From 998327540111c7be25502f4e65f9453f92af958f Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Wed, 3 Jan 2024 16:00:57 -0800 Subject: [PATCH 001/748] Auto-save cluster file in XFEL GUI Also bump sleep time to 15s for the uc plot Co-authored-by: Nicholas Sauter --- xfel/ui/components/xfel_gui_init.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/xfel/ui/components/xfel_gui_init.py b/xfel/ui/components/xfel_gui_init.py index 108c706594..92dbc18265 100644 --- a/xfel/ui/components/xfel_gui_init.py +++ b/xfel/ui/components/xfel_gui_init.py @@ -846,12 +846,25 @@ def run(self): plots = dbscan_plot_manager(params) plots.wrap_3D_features(fig = figure, embedded = True) figure.canvas.draw_idle() + cluster_dir = os.path.join(self.parent.params.output_folder, "cluster") + if not os.path.isdir(cluster_dir): + os.makedirs(cluster_dir) + cluster_file = os.path.join(cluster_dir,"cluster_%s.pickle"%(plots.FV.sample_name.strip().replace(" ", "_"))) + print("Writing cluster to", cluster_file) + import pickle + with open(cluster_file,"wb") as FF: + pickle.dump( + dict(populations=plots.pop, + features=plots.FV.features_, + info=plots.FV.output_info, + sample=plots.FV.sample_name),FF + ) else: print("Unsupported crystal system", cs) self.post_refresh() self.parent.run_window.unitcell_light.change_status('on') - time.sleep(5) + time.sleep(15) except Exception as e: print(e) self.parent.run_window.unitcell_light.change_status('alert') From 157c12a0466b715053ad7d7b200756753dc11703 Mon Sep 17 00:00:00 2001 From: Pavel Date: Fri, 5 Jan 2024 13:10:29 -0800 Subject: [PATCH 002/748] Do not try to extract fmodel is no reflection data is found. --- iotbx/data_manager/common.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/iotbx/data_manager/common.py b/iotbx/data_manager/common.py index 0f637a10d5..e12a31f676 100644 --- a/iotbx/data_manager/common.py +++ b/iotbx/data_manager/common.py @@ -193,6 +193,8 @@ def get_fmodel(self, array_type = array_type, crystal_symmetry = crystal_symmetry, ignore_intensities_if_amplitudes_present = True) + if rfs is None: + raise Sorry("No reflection data provided.") # Resolve symmetry issues (in-place) self._resolve_symmetry_conflicts( params = crystal_symmetry_phil, @@ -222,13 +224,16 @@ def get_fmodel(self, # XXX Temporary hack/work-around (REMOVE later) end # XXX # Get reflection data + dpg = None + if(model.crystal_symmetry() is not None): + dpg = model.crystal_symmetry().space_group().build_derived_point_group() data = extract_xtal_data.run( keep_going = not tmp_p.r_free_flags.required, extract_r_free_flags = not tmp_p.r_free_flags.ignore_r_free_flags, reflection_file_server = rfs, parameters = tmp_p, experimental_phases_params = experimental_phases_params, - working_point_group = model.crystal_symmetry().space_group().build_derived_point_group(), + working_point_group = dpg, free_r_flags_scope = free_r_flags_scope, remark_r_free_flags_md5_hexdigest = model.get_header_r_free_flags_md5_hexdigest()).result() # From 66949ba22c5dee1a7ca55e6f404defa50073b872 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 8 Jan 2024 10:24:32 -0800 Subject: [PATCH 003/748] Fixing typo. --- cctbx/command_line/precession_view.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cctbx/command_line/precession_view.py b/cctbx/command_line/precession_view.py index 650ee4ae16..d9ac8cfdf4 100644 --- a/cctbx/command_line/precession_view.py +++ b/cctbx/command_line/precession_view.py @@ -98,12 +98,12 @@ def run(args, out=sys.stdout, silent=True): scene = cctbx.miller.display.scene( miller_array=selected_array, settings=params) - postcript = False + postscript = False if (params.output_file is not None): if (params.output_file.endswith("eps")): if (params.format == "png"): raise Sorry("Postscript format requested, but output file ends in .png!") - postcript = True + postscript = True elif (not params.output_file.endswith("png")): raise Sorry("Output file extension must be .eps or .png.") else : From 432483d0bc40012e789a634193ae43aa3cdbef10 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 8 Jan 2024 10:32:24 -0800 Subject: [PATCH 004/748] Exposing silent option. --- cctbx/command_line/precession_view.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cctbx/command_line/precession_view.py b/cctbx/command_line/precession_view.py index d9ac8cfdf4..334bf1e36c 100644 --- a/cctbx/command_line/precession_view.py +++ b/cctbx/command_line/precession_view.py @@ -24,11 +24,13 @@ .type = int height = 800 .type = int +silent = True + .type = bool format = *Auto png eps .type = choice """, process_includes=True) -def run(args, out=sys.stdout, silent=True): +def run(args, out=sys.stdout): if (len(args) == 0): params_out = StringIO() master_phil.show(out=params_out, prefix=" ") @@ -133,7 +135,7 @@ def run(args, out=sys.stdout, silent=True): canvas = open(params.output_file, "w") render.paint(canvas) canvas.close() - elif (not silent): + elif (not params.silent): render = render_pil( w=params.width*8, h=params.height*8, @@ -144,7 +146,7 @@ def run(args, out=sys.stdout, silent=True): render.render(canvas) im2 = im.resize((params.width, params.height), Image.ANTIALIAS) im2.save(params.output_file) - if (not silent): + if (not params.silent): print("Wrote %s" % params.output_file, file=out) else : return scene, params From 064ef4027952af9549f3451d4df3c6914ab6bd5a Mon Sep 17 00:00:00 2001 From: Felix Wittwer <40206209+Trzs@users.noreply.github.com> Date: Mon, 8 Jan 2024 11:00:48 -0800 Subject: [PATCH 005/748] Merge changes made for Frontier (#934) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Big merge to bring all changes made for Frontier back to the main branch. **WARNING: This merge requires Kokkos 4.0 or later!** - switch to Kokkos 4.0 - bring nxmx_writer to nanoBragg - reduce memory footprint of hopper and stage2 - optimizations for nanoBragg and diffBragg stage 2 **Changes for Kokkos 4.0** - moved mathematical functions (`exp`, `sin`, ...) and `HIPSpace` from `Kokkos::experimental` to `Kokkos` namespace - Kokkos is now build with C++17 standard - Switch from UVM to manual memory management - InitArguments is deprecated, using InitializationSettings now **Changes for nxmx_writer** - Add nxmx_writer capability to nanoBragg - Uses dxtbx's general purpose nxmx_writer - Need to set values for material and thickness for NXmx - Hook up some missing pipes for ImageSetData and FormatBraggInMemory so they can work with imageset.get_spectrum - Add example test to tst_gauss_argchk.py - Work in progress writing simulations to NeXuS **Other Changes** - change `use_cuda` to `use_gpu` - added transfer function for boolean vector to kokkos view - micro optimizations change division to multiplication with reciprocal - collect individual refinement flags into one bit-mask - collect gradients in kokkos_manager struct - port rotated axis for diffuse scattering to diffbragg_kokkos - update unit tests to check that curve fit goes through origin - change panel vectors to use kokkos_vec3 instead of double[3] - in nanoBragg_kokkos, precalculate crystal_orientation in separate function - Fix hopper_utils.py to not keep full background after ROIs are created - Always use timestamps in diffBragg/mpi_logger - adds 3-fold Flatt support to diffBragg - better timers for device code - fixes to command line, notably integrate OOM error - better management of host-dev copies - use stride when spectrum_from_imageset=True --------- Co-authored-by: Felix Wittwer Co-authored-by: Aaron Brewster Co-authored-by: Nicholas K Sauter Co-authored-by: Vidya Ganapati Co-authored-by: Billy K. Poon Co-authored-by: Daniel Tchoń Co-authored-by: Michael Wall Co-authored-by: dermen --- .azure-pipelines/xfel/download-source.yml | 2 + .azure-pipelines/xfel/unix-conda-build.yml | 1 + kokkostbx/Legacy/kokkos_matrix.h | 2 +- kokkostbx/Legacy/kokkos_matrix3.h | 2 +- kokkostbx/Legacy/kokkos_vector.h | 6 +- kokkostbx/Legacy/kokkos_vector3.h | 6 +- kokkostbx/SConscript | 12 +- kokkostbx/kokkos_types.h | 11 +- kokkostbx/kokkos_utils.cpp | 16 + kokkostbx/kokkos_utils.h | 10 +- kokkostbx/kokkos_vector.h | 11 +- kokkostbx/kokkos_vector3.h | 34 +- libtbx/auto_build/bootstrap.py | 8 +- simtbx/command_line/complete_an_F.py | 48 + simtbx/command_line/estimate_Ncells_Eta.py | 111 + simtbx/command_line/hopper.py | 107 +- simtbx/command_line/hopper_ensemble.py | 26 +- simtbx/command_line/hopper_process.py | 2 +- simtbx/command_line/integrate.py | 415 ++- simtbx/command_line/make_input_file.py | 39 +- simtbx/command_line/spectra.py | 99 + simtbx/command_line/stage_two.py | 20 +- simtbx/command_line/update_stage1_phil.py | 82 + simtbx/diffBragg/ensemble_refine_launcher.py | 271 +- simtbx/diffBragg/hopper_ensemble_utils.py | 57 +- simtbx/diffBragg/hopper_io.py | 78 +- simtbx/diffBragg/hopper_utils.py | 429 ++- simtbx/diffBragg/mpi_logger.py | 8 +- simtbx/diffBragg/phil.py | 125 +- simtbx/diffBragg/prep_stage2_input.py | 58 +- simtbx/diffBragg/refiners/base_refiner.py | 2 + .../diffBragg/refiners/stage_two_refiner.py | 145 +- simtbx/diffBragg/src/diffBragg.cpp | 152 +- simtbx/diffBragg/src/diffBragg.h | 17 +- simtbx/diffBragg/src/diffBraggCUDA.cu | 6 + simtbx/diffBragg/src/diffBraggKOKKOS.cpp | 307 +- simtbx/diffBragg/src/diffBraggKOKKOS.h | 9 +- simtbx/diffBragg/src/diffBragg_cpu_kernel.cpp | 5 + simtbx/diffBragg/src/diffBragg_ext.cpp | 66 +- simtbx/diffBragg/src/diffBragg_gpu_kernel.cu | 2 +- .../diffBragg/src/diffBragg_kokkos_kernel.cpp | 3283 +++++++++++------ .../diffBragg/src/diffBragg_kokkos_kernel.h | 193 +- simtbx/diffBragg/src/diffBragg_refine_flag.h | 67 + simtbx/diffBragg/src/diffuse_util.h | 21 +- simtbx/diffBragg/src/diffuse_util_kokkos.h | 339 +- simtbx/diffBragg/src/util.h | 99 +- simtbx/diffBragg/src/util_kokkos.h | 69 +- simtbx/diffBragg/stage_two_utils.py | 65 +- .../tests/tst_diffBragg_Fcell_deriv.py | 1 + .../tst_diffBragg_detdist_derivatives.py | 4 + .../tests/tst_diffBragg_diffuse_properties.py | 1 + .../tests/tst_diffBragg_eta_derivs.py | 4 +- .../tests/tst_diffBragg_hopper_refine.py | 11 + .../tests/tst_diffBragg_hopper_refine_Fhkl.py | 11 + .../tst_diffBragg_lambda_coefficients.py | 1 + .../tst_diffBragg_ncells_offdiag_property.py | 2 + .../tests/tst_diffBragg_ncells_property.py | 2 + ...t_diffBragg_ncells_property_anisotropic.py | 2 + .../tests/tst_diffBragg_panelXY_derivs.py | 1 + .../diffBragg/tests/tst_diffBragg_rotXYZ.py | 2 +- .../tests/tst_diffBragg_rotXYZ_deriv.py | 4 +- .../tests/tst_diffBragg_unitcell_property.py | 22 +- simtbx/diffBragg/utils.py | 131 +- simtbx/gpu/simulation.cu | 20 +- simtbx/gpu/simulation.h | 3 +- simtbx/kokkos/SConscript | 1 - simtbx/kokkos/detector.cpp | 66 +- simtbx/kokkos/detector.h | 24 +- simtbx/kokkos/kernel_math.h | 13 + simtbx/kokkos/kokkos_instance.cpp | 8 +- simtbx/kokkos/simulation.cpp | 37 +- simtbx/kokkos/simulation.h | 7 + simtbx/kokkos/simulation_kernels.h | 231 +- simtbx/modeling/forward_models.py | 49 +- simtbx/nanoBragg/__init__.py | 129 +- simtbx/nanoBragg/anisotropic_mosaicity.py | 4 +- simtbx/nanoBragg/nanoBragg.cpp | 3 + simtbx/nanoBragg/nanoBragg.h | 1 + simtbx/nanoBragg/nanoBragg_ext.cpp | 5 + simtbx/nanoBragg/sim_data.py | 10 +- simtbx/nanoBragg/tst_gauss_argchk.py | 1 + simtbx/run_tests.py | 1 + .../application/errors/error_modifier_ev11.py | 2 +- 83 files changed, 5405 insertions(+), 2352 deletions(-) create mode 100644 simtbx/command_line/complete_an_F.py create mode 100644 simtbx/command_line/estimate_Ncells_Eta.py create mode 100644 simtbx/command_line/spectra.py create mode 100644 simtbx/command_line/update_stage1_phil.py create mode 100644 simtbx/diffBragg/src/diffBragg_refine_flag.h diff --git a/.azure-pipelines/xfel/download-source.yml b/.azure-pipelines/xfel/download-source.yml index b59af39774..7c2b32d412 100644 --- a/.azure-pipelines/xfel/download-source.yml +++ b/.azure-pipelines/xfel/download-source.yml @@ -61,7 +61,9 @@ jobs: # preserve permissions and delete extra files - script: | cd $(Pipeline.Workspace) + mv modules/kokkos/.git modules/kokkos/.git.tmp rm -fr modules/*/.git/* + mv modules/kokkos/.git.tmp modules/kokkos/.git rm -fr modules/*/.svn/* rm -fr modules/*.tar tar -cf modules.tar modules diff --git a/.azure-pipelines/xfel/unix-conda-build.yml b/.azure-pipelines/xfel/unix-conda-build.yml index 3766d91335..bece4d695b 100644 --- a/.azure-pipelines/xfel/unix-conda-build.yml +++ b/.azure-pipelines/xfel/unix-conda-build.yml @@ -95,6 +95,7 @@ steps: libtbx.configure lunus make fi + rm -fr modules/kokkos/.git/* displayName: Configure and Build # test diff --git a/kokkostbx/Legacy/kokkos_matrix.h b/kokkostbx/Legacy/kokkos_matrix.h index 140d69e01d..4a7f07077a 100644 --- a/kokkostbx/Legacy/kokkos_matrix.h +++ b/kokkostbx/Legacy/kokkos_matrix.h @@ -156,7 +156,7 @@ namespace kokkostbx { } KOKKOS_INLINE_FUNCTION NumType length() const { - return ::Kokkos::Experimental::sqrt(length_sqr()); + return ::Kokkos::sqrt(length_sqr()); } KOKKOS_INLINE_FUNCTION NumType dot(const matrix& v) const { diff --git a/kokkostbx/Legacy/kokkos_matrix3.h b/kokkostbx/Legacy/kokkos_matrix3.h index 96105beb3a..561f6b36b8 100644 --- a/kokkostbx/Legacy/kokkos_matrix3.h +++ b/kokkostbx/Legacy/kokkos_matrix3.h @@ -147,7 +147,7 @@ namespace kokkostbx { } KOKKOS_INLINE_FUNCTION NumType length() const { - return ::Kokkos::Experimental::sqrt(length_sqr()); + return ::Kokkos::sqrt(length_sqr()); } KOKKOS_INLINE_FUNCTION NumType dot(const matrix3& v) const { diff --git a/kokkostbx/Legacy/kokkos_vector.h b/kokkostbx/Legacy/kokkos_vector.h index 76beaaa245..f34de4586e 100644 --- a/kokkostbx/Legacy/kokkos_vector.h +++ b/kokkostbx/Legacy/kokkos_vector.h @@ -215,7 +215,7 @@ namespace kokkostbx { } KOKKOS_INLINE_FUNCTION NumType length() const { - return ::Kokkos::Experimental::sqrt(length_sqr()); + return ::Kokkos::sqrt(length_sqr()); } KOKKOS_INLINE_FUNCTION NumType dot(const vector3& v) const { @@ -248,8 +248,8 @@ namespace kokkostbx { // rotate a point about a unit vector3 axis KOKKOS_INLINE_FUNCTION vector3 rotate_around_axis(const vector3& axis, NumType angle) const { - NumType sinphi = ::Kokkos::Experimental::sin(angle); - NumType cosphi = ::Kokkos::Experimental::cos(angle); + NumType sinphi = ::Kokkos::sin(angle); + NumType cosphi = ::Kokkos::cos(angle); NumType dot_factor = axis.dot(*this) * (1.0-cosphi); vector3 vector_rot = axis.cross(*this) * sinphi; diff --git a/kokkostbx/Legacy/kokkos_vector3.h b/kokkostbx/Legacy/kokkos_vector3.h index 802a3c8e26..39a316a9dc 100644 --- a/kokkostbx/Legacy/kokkos_vector3.h +++ b/kokkostbx/Legacy/kokkos_vector3.h @@ -144,7 +144,7 @@ namespace kokkostbx { } KOKKOS_INLINE_FUNCTION NumType length() const { - return ::Kokkos::Experimental::sqrt(length_sqr()); + return ::Kokkos::sqrt(length_sqr()); } KOKKOS_INLINE_FUNCTION NumType dot(const vector3& v) const { @@ -177,8 +177,8 @@ namespace kokkostbx { // rotate a point about a unit vector3 axis KOKKOS_INLINE_FUNCTION vector3 rotate_around_axis(const vector3& axis, NumType angle) const { - NumType sinphi = ::Kokkos::Experimental::sin(angle); - NumType cosphi = ::Kokkos::Experimental::cos(angle); + NumType sinphi = ::Kokkos::sin(angle); + NumType cosphi = ::Kokkos::cos(angle); NumType dot_factor = axis.dot(*this) * (1.0-cosphi); vector3 vector_rot = axis.cross(*this) * sinphi; diff --git a/kokkostbx/SConscript b/kokkostbx/SConscript index 61212f0261..19e522c6f8 100644 --- a/kokkostbx/SConscript +++ b/kokkostbx/SConscript @@ -22,7 +22,7 @@ if env_etc.enable_kokkos: if os.getenv('KOKKOS_ARCH') is None: os.environ['KOKKOS_ARCH'] = "HSW" if use_cuda and os.getenv('KOKKOS_CUDA_OPTIONS') is None: - os.environ['KOKKOS_CUDA_OPTIONS'] = "enable_lambda,force_uvm" + os.environ['KOKKOS_CUDA_OPTIONS'] = "enable_lambda" os.environ['CXXFLAGS'] = '-O3 -fPIC -DCUDAREAL=double' library_flags = "-Llib" @@ -37,10 +37,6 @@ if env_etc.enable_kokkos: linked_libraries += " -lcudart -lcuda" os.environ['LDLIBS'] = linked_libraries - cxx_standard = '14' - if use_sycl: - cxx_standard = '17' - original_cxx = None kokkos_lib = 'libkokkos.a' kokkos_cxxflags = None @@ -119,7 +115,7 @@ if env_etc.enable_kokkos: returncode = subprocess.call([ 'cmake', os.environ['KOKKOS_PATH'], - '-DCMAKE_CXX_STANDARD={}'.format(cxx_standard), + '-DCMAKE_CXX_STANDARD={}'.format('17'), '-DCMAKE_INSTALL_PREFIX={}'.format(libtbx.env.under_build('.')), '-DCMAKE_INSTALL_LIBDIR=lib', '-DBUILD_SHARED_LIBS={}'.format(OnOff[True]), @@ -138,9 +134,9 @@ if env_etc.enable_kokkos: '-DKokkos_ENABLE_SERIAL=ON', '-DKokkos_ENABLE_OPENMP={}'.format(OnOff[use_openmp]), '-DKokkos_ENABLE_CUDA={}'.format(OnOff[use_cuda]), - '-DKokkos_ENABLE_CUDA_UVM={}'.format(OnOff[use_cuda]), '-DKokkos_ENABLE_HIP={}'.format(OnOff[use_hip]), - '-DKokkos_ENABLE_SYCL={}'.format(OnOff[use_sycl]) + '-DKokkos_ENABLE_SYCL={}'.format(OnOff[use_sycl]), + '-DKokkos_ENABLE_IMPL_MDSPAN=ON' ], cwd=kokkos_build_dir) diff --git a/kokkostbx/kokkos_types.h b/kokkostbx/kokkos_types.h index 619fa20568..3ea314437c 100644 --- a/kokkostbx/kokkos_types.h +++ b/kokkostbx/kokkos_types.h @@ -3,10 +3,10 @@ #include #ifdef KOKKOS_ENABLE_CUDA - #define MemSpace Kokkos::CudaUVMSpace + #define MemSpace Kokkos::CudaSpace #endif #ifdef KOKKOS_ENABLE_HIP - #define MemSpace Kokkos::Experimental::HIPSpace + #define MemSpace Kokkos::HIPSpace #endif #ifdef KOKKOS_ENABLE_OPENMPTARGET #define MemSpace Kokkos::OpenMPTargetSpace @@ -19,8 +19,11 @@ using ExecSpace = MemSpace::execution_space; using range_policy = Kokkos::RangePolicy; -template -using view_1d_t = Kokkos::View; +template using view_1d_t = Kokkos::View; +template using view_4d_t = Kokkos::View; +template using view_5d_t = Kokkos::View; +template using view_6d_t = Kokkos::View; +template using view_6d6_t = Kokkos::View; using vector_bool_t = view_1d_t; using vector_double_t = view_1d_t; diff --git a/kokkostbx/kokkos_utils.cpp b/kokkostbx/kokkos_utils.cpp index ee46cc35d5..02bb35994b 100644 --- a/kokkostbx/kokkos_utils.cpp +++ b/kokkostbx/kokkos_utils.cpp @@ -18,4 +18,20 @@ void transfer_double2kokkos(vector_cudareal_t& dst, const double* src, const siz } } +void transfer_vector2kokkos(view_1d_t& dst, const std::vector& src) { + if (true) { + // printf("== Transfer %s from %p\n", dst.label().c_str(), (void*) dst.data()); + // printf(" - size src|dst: %d|%d\n", src.size(), dst.span() ); + } + if (dst.span() < src.size()) { + resize(dst, src.size()); + // printf(" - size changed, new size: %d\n", dst.span() ); + } + auto host_view = Kokkos::create_mirror_view(dst); + for (int i = 0; i < src.size(); ++i) { + host_view(i) = src[i]; + } + Kokkos::deep_copy(dst, host_view); +} + } // namespace kokkostbx diff --git a/kokkostbx/kokkos_utils.h b/kokkostbx/kokkos_utils.h index e82a776ebc..4b0105ab0b 100644 --- a/kokkostbx/kokkos_utils.h +++ b/kokkostbx/kokkos_utils.h @@ -78,6 +78,8 @@ void transfer_kokkos2shared(af::shared& dst, const view_1d_t& src) { transfer_kokkos2X(dst, src); } +void transfer_vector2kokkos(view_1d_t& dst, const std::vector& src); + template void transfer_vector2kokkos(view_1d_t& dst, const std::vector& src) { if (true) { @@ -88,11 +90,9 @@ void transfer_vector2kokkos(view_1d_t& dst, const std::vector& src) { resize(dst, src.size()); // printf(" - size changed, new size: %d\n", dst.span() ); } - auto host_view = Kokkos::create_mirror_view(dst); - for (int i = 0; i < src.size(); ++i) { - host_view(i) = src[i]; - } - Kokkos::deep_copy(dst, host_view); + auto host_view = Kokkos::View(src.data(), src.size()); + auto dst_subview = Kokkos::subview(dst, std::pair(0, src.size())); + Kokkos::deep_copy(dst_subview, host_view); } template diff --git a/kokkostbx/kokkos_vector.h b/kokkostbx/kokkos_vector.h index e31d905bb6..5bda8e86d7 100644 --- a/kokkostbx/kokkos_vector.h +++ b/kokkostbx/kokkos_vector.h @@ -207,8 +207,9 @@ struct vector_base { } KOKKOS_FUNCTION void operator/=(const NumType& v) { + const NumType v_r = 1 / v; for (size_t i = 0; i < size; ++i) { - data[i] /= v; + data[i] *= v_r; } } @@ -261,14 +262,15 @@ struct vector_base { KOKKOS_FUNCTION NumType length() const { // return sqrt_func(length_sqr()); - return ::Kokkos::Experimental::sqrt(length_sqr()); + return ::Kokkos::sqrt(length_sqr()); } KOKKOS_FUNCTION void normalize() { NumType l = length(); if (l > 0) { + NumType l_r = 1 / l; for (size_t i = 0; i < size; ++i) { - data[i] /= l; + data[i] *= l_r; } } } @@ -277,8 +279,9 @@ struct vector_base { NumType l = length(); Derived unit_vector{}; if (l > 0) { + NumType l_r = 1 / l; for (size_t i = 0; i < size; ++i) { - unit_vector[i] = data[i] / l; + unit_vector[i] = data[i] * l_r; } } return unit_vector; diff --git a/kokkostbx/kokkos_vector3.h b/kokkostbx/kokkos_vector3.h index 98d46ee7dc..058540eb07 100644 --- a/kokkostbx/kokkos_vector3.h +++ b/kokkostbx/kokkos_vector3.h @@ -10,8 +10,8 @@ // #ifdef KOKKOS_CORE_HPP // template KOKKOS_FUNCTION T sin_func(T x) { return -// ::Kokkos::Experimental::sin(x); } template KOKKOS_FUNCTION T cos_func(T x) { -// return ::Kokkos::Experimental::cos(x); } +// ::Kokkos::sin(x); } template KOKKOS_FUNCTION T cos_func(T x) { +// return ::Kokkos::cos(x); } // #else // #include // template KOKKOS_FUNCTION T sin_func(T x) { return sin(x); } @@ -27,26 +27,26 @@ struct vector3 : public vector { using vector_base = kokkostbx::vector; vector3() = default; - KOKKOS_FUNCTION vector3(NumType val) : vector_base(val){}; - KOKKOS_FUNCTION vector3(NumType arr[]) : vector_base(arr){}; - KOKKOS_FUNCTION vector3(const vector_base& vec) : vector_base(vec){}; + KOKKOS_INLINE_FUNCTION vector3(NumType val) : vector_base(val){}; + KOKKOS_INLINE_FUNCTION vector3(NumType arr[]) : vector_base(arr){}; + KOKKOS_INLINE_FUNCTION vector3(const vector_base& vec) : vector_base(vec){}; - KOKKOS_FUNCTION vector3(NumType x, NumType y, NumType z) : vector_base() { + KOKKOS_INLINE_FUNCTION vector3(NumType x, NumType y, NumType z) : vector_base() { vector_base::data[0] = x; vector_base::data[1] = y; vector_base::data[2] = z; } // decided against using properties, as this would increase the size of the class - KOKKOS_FUNCTION NumType& x_val() { return vector_base::data[0]; } - KOKKOS_FUNCTION NumType& y_val() { return vector_base::data[1]; } - KOKKOS_FUNCTION NumType& z_val() { return vector_base::data[2]; } + KOKKOS_INLINE_FUNCTION NumType& x_val() { return vector_base::data[0]; } + KOKKOS_INLINE_FUNCTION NumType& y_val() { return vector_base::data[1]; } + KOKKOS_INLINE_FUNCTION NumType& z_val() { return vector_base::data[2]; } - KOKKOS_FUNCTION NumType x_val() const { return vector_base::data[0]; } - KOKKOS_FUNCTION NumType y_val() const { return vector_base::data[1]; } - KOKKOS_FUNCTION NumType z_val() const { return vector_base::data[2]; } + KOKKOS_INLINE_FUNCTION NumType x_val() const { return vector_base::data[0]; } + KOKKOS_INLINE_FUNCTION NumType y_val() const { return vector_base::data[1]; } + KOKKOS_INLINE_FUNCTION NumType z_val() const { return vector_base::data[2]; } - KOKKOS_FUNCTION vector3 cross(const vector3& v) const { + KOKKOS_INLINE_FUNCTION vector3 cross(const vector3& v) const { vector3 cross_vector{}; cross_vector.x_val() = y_val() * v.z_val() - z_val() * v.y_val(); cross_vector.y_val() = z_val() * v.x_val() - x_val() * v.z_val(); @@ -56,14 +56,14 @@ struct vector3 : public vector { } // rotate a point around a unit vector3 axis - KOKKOS_FUNCTION vector3 rotate_around_axis(const vector3& axis, NumType angle) + KOKKOS_INLINE_FUNCTION vector3 rotate_around_axis(const vector3& axis, NumType angle) const { // NumType sinphi = sin_func(angle); // NumType cosphi = cos_func(angle); - NumType sinphi = ::Kokkos::Experimental::sin(angle); - NumType cosphi = ::Kokkos::Experimental::cos(angle); + const NumType sinphi = ::Kokkos::sin(angle); + const NumType cosphi = ::Kokkos::cos(angle); - NumType dot_factor = axis.dot(*this) * (1.0 - cosphi); + const NumType dot_factor = axis.dot(*this) * (1.0 - cosphi); vector3 vector_rot = axis.cross(*this) * sinphi; vector_rot += axis * dot_factor; diff --git a/libtbx/auto_build/bootstrap.py b/libtbx/auto_build/bootstrap.py index 5fbfca691d..fc9ce3f3cc 100644 --- a/libtbx/auto_build/bootstrap.py +++ b/libtbx/auto_build/bootstrap.py @@ -1006,17 +1006,17 @@ class xia2_module(SourceModule): class kokkos_module(SourceModule): module = 'kokkos' - anonymous = ['git', '-b 3.7.01', + anonymous = ['git', '-b 4.2.00', 'git@github.com:kokkos/kokkos.git', 'https://github.com/kokkos/kokkos.git', - 'https://github.com/kokkos/kokkos/archive/refs/tags/3.7.01.zip'] + 'https://github.com/kokkos/kokkos/archive/refs/tags/4.2.00.zip'] class kokkos_kernels_module(SourceModule): module = 'kokkos-kernels' - anonymous = ['git', '-b 3.7.01', + anonymous = ['git', '-b 4.2.00', 'git@github.com:kokkos/kokkos-kernels.git', 'https://github.com/kokkos/kokkos-kernels.git', - 'https://github.com/kokkos/kokkos-kernels/archive/refs/tags/3.7.01.zip'] + 'https://github.com/kokkos/kokkos-kernels/archive/refs/tags/4.2.00.zip'] # Duke repositories class probe_module(SourceModule): diff --git a/simtbx/command_line/complete_an_F.py b/simtbx/command_line/complete_an_F.py new file mode 100644 index 0000000000..1bf34dad3e --- /dev/null +++ b/simtbx/command_line/complete_an_F.py @@ -0,0 +1,48 @@ +from __future__ import division, print_function +from argparse import ArgumentParser +parser = ArgumentParser() +parser.add_argument("mtzin", help="input mtz file", type=str) +parser.add_argument("mtzout", help="output mtz file", type=str) +args = parser.parse_args() + +# LIBTBX_SET_DISPATCHER_NAME diffBragg.completeF + +import numpy as np +from iotbx.reflection_file_reader import any_reflection_file +from dials.array_family import flex +from scipy.interpolate import interp1d +from cctbx import miller + +F = any_reflection_file(args.mtzin).as_miller_arrays()[0] +F = F.as_amplitude_array() +if not F.is_xray_amplitude_array(): + F = F.set_observation_type_xray_amplitude() + +print("Bin-ID Res-range Completeness #ASU-indices") +F.show_completeness() +d_max,d_min = F.resolution_range() +print("d_min, d_max (Angstrom): ", d_min, d_max) +mset_full = F.build_miller_set(False, d_min=d_min) +mset_full_d = {h: d for h,d in zip(mset_full.d_spacings().indices(), mset_full.d_spacings().data())} +Fmap = {h:val for h,val in zip(F.indices(), F.data())} +xvals = np.array(F.d_spacings().data()) +yvals = np.array(F.data()) +fill_vals = yvals[np.argmin(xvals)], yvals[np.argmax(xvals)] +I = interp1d(xvals, yvals, fill_value=fill_vals, bounds_error=False) +data = [] +for h in mset_full.indices(): + if h not in Fmap: + d_h = mset_full_d[h] + amp = I(d_h) + else: + amp = Fmap[h] + data.append(amp) + +complete_amps = flex.double(data) +complete_inds = mset_full.indices() +ma = miller.array(mset_full, complete_amps) +if not ma.is_xray_amplitude_array(): + ma = ma.set_observation_type_xray_amplitude() +ma = ma.as_anomalous_array() +assert ma.anomalous_flag() +ma.as_mtz_dataset(column_root_label="F").mtz_object().write(args.mtzout) diff --git a/simtbx/command_line/estimate_Ncells_Eta.py b/simtbx/command_line/estimate_Ncells_Eta.py new file mode 100644 index 0000000000..d6ba9476a4 --- /dev/null +++ b/simtbx/command_line/estimate_Ncells_Eta.py @@ -0,0 +1,111 @@ +from __future__ import division +from argparse import ArgumentParser +parser = ArgumentParser() +parser.add_argument("dirname", help="still process output folder", type=str) +parser.add_argument("--updatePhil", default=None, help="name of an exisiting stage 1 phil file to update (just the init.Ncells portion)", type=str) +parser.add_argument("--expSuffix", help="extension of refined experiments", type=str, default="_refined.expt") +parser.add_argument("--thresh", type=float, default=7, help="MAD score for outliers (default=7 standard deviation above the median)") +parser.add_argument("--useMean", action="store_true", help="set Eta and Nabc using the mean (default is median)") +parser.add_argument("--NabcMax", type=float, default=70, help="If estaimated Nabc is above this value, it will set to this value") +parser.add_argument("--NabcMin", type=float, default=5, help="If estaimated Nabc is BELOW this value, it will be set to this value") +parser.add_argument("--EtaMax", type=float, default=0.5, help="If estimated Eta is above this range, it will be set to this value") +parser.add_argument("--EtaMin", type=float, default=1e-3, help="If estimated Eta is BELOW this range, it will be set to this value") + +#parser.add_argument("--njobs", type=int, default=5, help="number of jobs (only runs on single node, no MPI)") +parser.add_argument("--plot", action="store_true", help="show a histogram at the end") +args = parser.parse_args() +# LIBTBX_SET_DISPATCHER_NAME diffBragg.estimate_Ncells_Eta +from mpi4py import MPI +COMM = MPI.COMM_WORLD +#from joblib import Parallel, delayed +import json +import numpy as np +from cctbx import uctbx +from scitbx.matrix import sqr +import os +import glob +from dxtbx.model import ExperimentList + +glob_s = os.path.join(args.dirname, "*%s" % args.expSuffix) +fnames = glob.glob(glob_s) + +#def main(jid): +all_Ns = [] +all_mos_spreads = [] +for i, f in enumerate(fnames): + if i % COMM.size != COMM.rank: + continue + print(f) + #Cs = ExperimentList.from_file(f, False).crystals() + Cs = json.load(open(f, 'r'))['crystal'] + dom_sizes = np.array([C['ML_domain_size_ang'] for C in Cs]) + mos_spreads = [2*C['ML_half_mosaicity_deg'] for C in Cs] + uc_vols = [] + for C in Cs: + a = C['real_space_a'] + b = C['real_space_b'] + c = C['real_space_c'] + uc = uctbx.unit_cell(orthogonalization_matrix=sqr(a + b + c).transpose()) + uc_vols.append(uc.volume()) + + Ns = dom_sizes / np.power(uc_vols, 1 / 3.) + all_Ns += list(Ns) + all_mos_spreads += list(mos_spreads) +# return all_Ns, all_mos_spreads + +all_Ns = COMM.reduce(all_Ns) +all_mos_spreads = COMM.reduce(all_mos_spreads) +#results = Parallel(n_jobs=args.njobs)(delayed(main)(j) for j in range(args.njobs)) +#all_Ns = [] +#all_mos_spreads = [] +#for N,mos in results: +# all_Ns += N +# all_mos_spreads += mos + +if COMM.rank==0: + import pandas + import pylab as plt + from simtbx.diffBragg import utils + all_Ns = np.array(all_Ns) + all_mos_spreads = np.array(all_mos_spreads) + bad_Ns = utils.is_outlier(all_Ns, args.thresh) + bad_mos_spreads = utils.is_outlier(all_mos_spreads, args.thresh) + is_bad = np.logical_or(bad_Ns, bad_mos_spreads) + print("Removing %d outlier estiamtes" % is_bad.sum()) + all_Ns = all_Ns[~is_bad] + all_mos_spreads = all_mos_spreads[~is_bad] + + df = pandas.DataFrame({"Ncells": all_Ns, "mos_spread_deg": all_mos_spreads}) + print(df.Ncells.describe()) + print(df.mos_spread_deg.describe()) + if args.useMean: + mean_N = df.Ncells.mean() + mean_mos = df.mos_spread_deg.mean() + else: + mean_N = df.Ncells.median() + mean_mos = df.mos_spread_deg.median() + print("mean Ncells=%f" % mean_N) + print("mean mos_spread=%f (deg.)" % mean_mos) + + if mean_mos > args.EtaMax or mean_mos < args.EtaMin: + temp = mean_mos + mean_mos = args.EtaMax if mean_mos > args.EtaMax else args.EtaMin + print("Estimated Eta=%f, setting it to %f" % (temp, mean_mos)) + if mean_N > args.NabcMax or mean_N < args.NabcMin: + temp = mean_N + mean_N = args.NabcMax if mean_N > args.NabcMax else args.NabcMin + print("Estimated N=%f, setting it to %f" %(temp, mean_N)) + + phil = """\ninit {{ + Nabc = [{n},{n},{n}] + eta_abc = [{m},{m},{m}] + }}\n""".format(n=round(mean_N,4), m=mean_mos) + + if args.updatePhil is not None: + with open(args.updatePhil, "r+") as o: + s = o.read() + s += phil + o.write(s) + if args.plot: + df.hist(bins=100, log=True) + plt.show() diff --git a/simtbx/command_line/hopper.py b/simtbx/command_line/hopper.py index cfd0e8ac75..32f8216d90 100644 --- a/simtbx/command_line/hopper.py +++ b/simtbx/command_line/hopper.py @@ -96,6 +96,7 @@ def run(self): assert os.path.exists(self.params.exp_ref_spec_file) input_lines = None best_models = None + pd_dir = os.path.join(self.params.outdir, "pandas") if COMM.rank == 0: input_lines = open(self.params.exp_ref_spec_file, "r").readlines() if self.params.skip is not None: @@ -113,6 +114,10 @@ def run(self): if self.params.gathers_dir is None: raise ValueError("Need to provide a file dir path in order to dump_gathers") utils.safe_makedirs(self.params.gathers_dir) + + utils.safe_makedirs(pd_dir) + + COMM.barrier() input_lines = COMM.bcast(input_lines) best_models = COMM.bcast(best_models) @@ -127,53 +132,63 @@ def run(self): exp_gatheredRef_spec = [] # optional list of expt, refls, spectra trefs = [] - for i_exp, line in enumerate(input_lines): - if i_exp == self.params.max_process: + this_rank_dfs = [] # dataframes storing the modeling results for each shot + for i_shot, line in enumerate(input_lines): + if i_shot == self.params.max_process: break - if i_exp % COMM.size != COMM.rank: + if i_shot % COMM.size != COMM.rank: continue - logging.info("COMM.rank %d on shot %d / %d" % (COMM.rank, i_exp + 1, len(input_lines))) + logging.info("COMM.rank %d on shot %d / %d" % (COMM.rank, i_shot + 1, len(input_lines))) line_fields = line.strip().split() - assert len(line_fields) in [2, 3] - if len(line_fields) == 2: - exp, ref = line_fields - spec = None - else: - exp, ref, spec = line_fields + num_fields = len(line_fields) + assert num_fields in [2, 3, 4] + exp, ref = line_fields[:2] + spec = None + exp_idx = 0 + if num_fields==3: + try: + exp_idx = int(line_fields[2]) + except ValueError: + spec = line_fields[2] + exp_idx = 0 + elif num_fields==4: + assert os.path.isfile(line_fields[2]) + spec = line_fields[2] + exp_idx = int(line_fields[3]) if self.params.ignore_existing: basename = os.path.splitext(os.path.basename(exp))[0] exists = False - for ii in [i_exp, 0]: - opt_exp = "%s_%s_%d.expt" % (self.params.tag, basename, ii) + for ii in [i_shot, 0]: + opt_exp = "%s_%s_%d_%d.expt" % (self.params.tag, basename, exp_idx, ii) opt_refl = opt_exp.replace(".expt", ".refl") if opt_exp in exp_names_already and opt_refl in refl_names_already: exists = True break if exists: - print("Found existing!! %d" % i_exp) + print("Found existing!! %d" % i_shot) continue best = None if best_models is not None: - best = best_models.query("exp_name=='%s'" % exp) - if len(best) == 0: - best = best_models.query("opt_exp_name=='%s'" % exp) + best = best_models.query("exp_name=='%s'" % exp).query("exp_idx==%d" % exp_idx) if len(best) != 1: raise ValueError("Should be 1 entry for exp %s in best pickle %s" % (exp, self.params.best_pickle)) self.params.simulator.spectrum.filename = spec Modeler = hopper_utils.DataModeler(self.params) Modeler.exper_name = exp + Modeler.exper_idx = exp_idx Modeler.refl_name = ref Modeler.rank = COMM.rank - Modeler.i_exp = i_exp + Modeler.i_shot = i_shot if self.params.load_data_from_refls: gathered = Modeler.GatherFromReflectionTable(exp, ref, sg_symbol=self.params.space_group) else: gathered = Modeler.GatherFromExperiment(exp, ref, remove_duplicate_hkl=self.params.remove_duplicate_hkl, - sg_symbol=self.params.space_group) + sg_symbol=self.params.space_group, + exp_idx=exp_idx) if not gathered: logging.warning("No refls in %s; CONTINUE; COMM.rank=%d" % (ref, COMM.rank)) continue @@ -213,20 +228,24 @@ def run(self): # best pickle is not supported yet for multiple crystals # also, if number of crystals is >1 , then the params.number_of_xtals flag will be overridden exp_list = ExperimentListFactory.from_json_file(exp, False) - xtals = exp_list.crystals() - if len(xtals) > 1: + xtals = exp_list.crystals() # TODO: fix as this is broken now that we allow multi image experiments + if self.params.consider_multicrystal_shots and len(xtals) > 1: assert best is None, "cannot pass best pickle if expt list has more than one crystal" assert self.params.number_of_xtals==1, "if expt list has more than one xtal, leave number_of_xtals as the default" self.params.number_of_xtals = len(xtals) MAIN_LOGGER.debug("Found %d xtals with unit cells:" %len(xtals)) for xtal in xtals: MAIN_LOGGER.debug("%.4f %.4f %.4f %.4f %.4f %.4f" % xtal.get_unit_cell().parameters()) + if self.params.record_device_timings and COMM.rank >0: + self.params.record_device_timings = False # only record for rank 0 otherwise there's too much output SIM = hopper_utils.get_simulator_for_data_modelers(Modeler) Modeler.set_parameters_for_experiment(best) - Modeler.Umatrices = [xtal.get_U() for xtal in xtals] - # TODO, move this to SimulatorFromExperiment + Modeler.Umatrices = [Modeler.E.crystal.get_U()] + + # TODO: move this to SimulatorFromExperiment + # TODO: fix multi crystal shot mode if best is not None and "other_spotscales" in list(best) and "other_Umats" in list(best): - Modeler.Umatrices[0] = self.E.get_U() + Modeler.Umatrices[0] = Modeler.E.get_U() assert len(xtals) == len(best.other_spotscales.values[0])+1 for i_xtal in range(1, len(xtals),1): scale_xt = best.other_spotscales.values[0][i_xtal] @@ -250,22 +269,31 @@ def run(self): nparam += SIM.Num_ASU*SIM.num_Fhkl_channels x0 = [1] * nparam tref = time.time() - MAIN_LOGGER.info("Beginning refinement of shot %d / %d" % (i_exp+1, len(input_lines))) + MAIN_LOGGER.info("Beginning refinement of shot %d / %d" % (i_shot+1, len(input_lines))) try: - x = Modeler.Minimize(x0, SIM, i_exp=i_exp) + x = Modeler.Minimize(x0, SIM, i_shot=i_shot) + for i_rep in range(self.params.filter_after_refinement.max_attempts): + final_sigz = Modeler.target.all_sigZ[-1] + niter = len(Modeler.target.all_sigZ) + too_few_iter = niter < self.params.filter_after_refinement.min_prev_niter + too_high_sigz = final_sigz > self.params.filter_after_refinement.max_prev_sigz + if too_few_iter or too_high_sigz: + Modeler.filter_pixels(self.params.filter_after_refinement.threshold) + x = Modeler.Minimize(x0, SIM, i_shot=i_shot) + except StopIteration: x = Modeler.target.x0 tref = time.time()-tref sigz = niter = None try: niter = len(Modeler.target.all_hop_id) - sigz = np.mean(Modeler.target.all_sigZ) + sigz = Modeler.target.all_sigZ[-1] except Exception: pass trefs.append(tref) print_s = "Finished refinement of shot %d / %d in %.4f sec. (rank mean t/im=%.4f sec.)" \ - % (i_exp+1, len(input_lines), tref, np.mean(trefs)) + % (i_shot+1, len(input_lines), tref, np.mean(trefs)) if sigz is not None and niter is not None: print_s += " Ran %d iterations. Final sigmaZ = %.1f," % (niter, sigz) if COMM.rank==0: @@ -275,11 +303,18 @@ def run(self): if self.params.profile: SIM.D.show_timings(COMM.rank) - Modeler.save_up(x,SIM, rank=COMM.rank, i_exp=i_exp) + dbg = self.params.debug_mode + shot_df = Modeler.save_up(x, SIM, rank=COMM.rank, i_shot=i_shot, + save_fhkl_data=dbg, save_refl=dbg, save_modeler_file=dbg, + save_sim_info=dbg, save_pandas=dbg, save_traces=dbg, save_expt=dbg) + this_rank_dfs.append(shot_df) if Modeler.params.refiner.debug_pixel_panelfastslow is not None: # TODO separate diffBragg logger utils.show_diffBragg_state(SIM.D, Modeler.params.refiner.debug_pixel_panelfastslow) + # TODO verify this works: + if SIM.D.record_timings: + SIM.D.show_timings(COMM.rank) Modeler.clean_up(SIM) del SIM.D # TODO: is this necessary ? @@ -294,6 +329,21 @@ def run(self): o.write("%s %s\n" % (e,r)) o.close() + if this_rank_dfs: + this_rank_dfs = pandas.concat(this_rank_dfs).reset_index(drop=True) + df_name = os.path.join(pd_dir, "hopper_results_rank%d.pkl" % COMM.rank) + this_rank_dfs.to_pickle(df_name) + + #MAIN_LOGGER.info("MPI-Gathering data frames across ranks") + #all_rank_dfs = COMM.gather(this_rank_dfs) + #if COMM.rank==0: + # all_rank_dfs = pandas.concat(all_rank_dfs) + # all_rank_dfs.reset_index(inplace=True, drop=True) + # all_df_name = os.path.join(self.params.outdir, "hopper_results.pkl") + # all_rank_dfs.to_pickle(all_df_name) + + + if __name__ == '__main__': from dials.util import show_mail_on_error @@ -311,6 +361,7 @@ def run(self): print("Install line_profiler in order to use logging: libtbx.python -m pip install line_profiler") with DeviceWrapper(script.dev) as _: + #with np.errstate(all='raise'): RUN() if lp is not None: diff --git a/simtbx/command_line/hopper_ensemble.py b/simtbx/command_line/hopper_ensemble.py index ca578a9214..49e0d2e449 100644 --- a/simtbx/command_line/hopper_ensemble.py +++ b/simtbx/command_line/hopper_ensemble.py @@ -7,7 +7,7 @@ parser.add_argument("input", type=str, help="combined pandas pickle") parser.add_argument("phil", type=str, help="user phil file used to run hopper (see simtbx/diffBragg/phil.py)") parser.add_argument("--outdir", type=str, default=None, help="output folder") -parser.add_argument("--exp", type=str, default="opt_exp_name", help="column name for input expeirments (default is opt_exp_name)") +parser.add_argument("--exp", type=str, default="exp_name", help="column name for input expeirments (default is opt_exp_name)") parser.add_argument("--refl", type=str, default="stage2_refls", help="column name for refls (default is stage2_refls)") parser.add_argument("--cmdlinePhil", nargs="+", default=None, type=str, help="command line phil params") parser.add_argument("--cell", nargs=6, type=float, default=None, help="unit cell to use when writing MTZ files. If not provided, average will be used") @@ -25,7 +25,7 @@ from simtbx.diffBragg.hopper_ensemble_utils import load_inputs from libtbx.mpi4py import MPI - +from simtbx.diffBragg.device import DeviceWrapper COMM= MPI.COMM_WORLD LOGGER = logging.getLogger("diffBragg.main") @@ -66,6 +66,8 @@ def write_commandline(params): if args.outdir is not None: params.outdir = args.outdir params.tag = args.saveTag + if params.record_device_timings and COMM.rank > 0: + params.record_device_timings = False # only record for rank 0 otherwise there's too much output # end of phil stuff ======== write_commandline(params) @@ -79,8 +81,8 @@ def write_commandline(params): if params.skip is not None: df = df.iloc[params.skip:] - if params.first_n is not None: - df = df.iloc[:params.first_n] + if params.max_process is not None: + df = df.iloc[:params.max_process] df.reset_index(inplace=True, drop=True) gather_dir=None @@ -91,16 +93,24 @@ def write_commandline(params): if not os.path.exists(gather_dir): os.makedirs(gather_dir) + for col in [args.exp, args.refl]: + if col not in list(df): + raise KeyError("Col %s is missing from dataframe" % col) + modelers = load_inputs(df, params, exper_key=args.exp, refls_key=args.refl, gather_dir=gather_dir) # note, we only go beyond this point if perImport flag was not passed modelers.cell_for_mtz = args.cell modelers.max_sigma = args.maxSigma modelers.outdir = args.outdir if args.outdir is not None else modelers.params.outdir modelers.save_freq = args.saveFreq + modelers.prep_for_refinement() - modelers.save_modeler_params = args.saveAll - # do all sanity checks up front before minimization - modelers.Minimize(save=True) + with DeviceWrapper(modelers.SIM.D.device_Id) as _: + modelers.alloc_max_pix_per_shot() + modelers.save_modeler_params = args.saveAll + + # do all sanity checks up front before minimization + modelers.Minimize(save=True) - LOGGER.debug("Done!") + LOGGER.debug("Done!") diff --git a/simtbx/command_line/hopper_process.py b/simtbx/command_line/hopper_process.py index f04d136b72..f170c89018 100644 --- a/simtbx/command_line/hopper_process.py +++ b/simtbx/command_line/hopper_process.py @@ -256,7 +256,7 @@ def integrate(self, experiments, indexed): ) if self.params.dispatch.coset: - from dials.algorithms.integration.sublattice_helper import integrate_coset + from xfel.util.sublattice_helper import integrate_coset integrate_coset(self, experiments, indexed) diff --git a/simtbx/command_line/integrate.py b/simtbx/command_line/integrate.py index c23e6011e9..e1d0cdd3c1 100644 --- a/simtbx/command_line/integrate.py +++ b/simtbx/command_line/integrate.py @@ -10,17 +10,29 @@ parser.add_argument("outdir", type=str, help="path to output refls") parser.add_argument("--cmdlinePhil", nargs="+", default=None, type=str, help="command line phil params") +parser.add_argument("--dialsInteg", action="store_true", help="Integrate new shoeboxes using dials and write *integrated.expt files") parser.add_argument("--numdev", type=int, default=1, help="number of GPUs (default=1)") parser.add_argument("--pklTag", type=str, help="optional suffix for globbing for pandas pickles (default .pkl)", default=".pkl") parser.add_argument("--loud", action="store_true", help="show lots of screen output") parser.add_argument("--hopInputName", default="preds_for_hopper", type=str, help="write exp_ref_spec file and best_pickle pointing to the preditction models, such that one can run predicted rois through simtbx.diffBragg.hopper (e.g. to fit per-roi scale factors)") parser.add_argument("--filterDupes", action="store_true", help="filter refls with same HKL") +parser.add_argument("--keepShoeboxes", action="store_true", help="Optionally keep shoeboxes present in the prediction refl tables (can lead to OOM errors)") +parser.add_argument("--scanWeakFracs", action="store_true", help="optionally stores a variety of inputs for stage2 based filtering different fractions of weak reflections") args = parser.parse_args() from mpi4py import MPI COMM = MPI.COMM_WORLD +import logging +if not args.loud: + logging.disable(logging.CRITICAL) +else: + if COMM.rank==0: + logger = logging.getLogger("diffBragg.main") + logger.setLevel(logging.DEBUG) + + def printR(*args, **kwargs): print("RANK %d" % COMM.rank, *args, **kwargs) def print0(*args, **kwargs): @@ -28,22 +40,40 @@ def print0(*args, **kwargs): print(*args, **kwargs) import numpy as np -from simtbx.diffBragg import utils +import json +from simtbx.diffBragg import hopper_utils, utils from simtbx.modeling import predictions from simtbx.diffBragg.hopper_utils import downsamp_spec_from_params import glob import pandas import os -import shutil from dials.algorithms.integration.stills_significance_filter import SignificanceFilter from dials.algorithms.indexing.stills_indexer import calc_2D_rmsd_and_displacements -import logging import sys -if not args.loud: - logging.disable(logging.CRITICAL) -else: - logging.basicConfig(level=logging.DEBUG) + +def filter_weak_reflections(refls, weak_fraction): + """ + :param pred: reflection table created by this script + :param weak_fraction: number from 0-1 (if 0, only strong spots are saved) + :return: new reflection table with weak reflections filtered according to weak_fraction + """ + new_refls = None + for idx in set(refls['id']): + pred = refls.select(refls['id']==idx) + weaks = pred.select(pred['is_weak']) + nweak = len(weaks) + weaks_sorted = np.argsort(weaks["scatter"])[::-1] + num_keep = int(nweak * weak_fraction) + weak_refl_inds_keep = set(np.array(weaks["refl_idx"])[weaks_sorted[:num_keep]]) + weak_sel = flex.bool([i in weak_refl_inds_keep for i in pred['refl_idx']]) + keeps = np.logical_or(pred['is_strong'], weak_sel) + pred = pred.select(flex.bool(keeps)) + if new_refls is None: + new_refls = deepcopy(pred) + else: + new_refls.extend(pred) + return new_refls # Note: these imports and following 3 methods will eventually be in CCTBX/simtbx/diffBragg/utils @@ -61,6 +91,7 @@ def print0(*args, **kwargs): from copy import deepcopy from collections import Counter +from simtbx.diffBragg.device import DeviceWrapper def filter_refls(R): vec3_dbl_keys = 'xyzcal.px', 'xyzcal.mm', 'xyzobs.px.value', 'xyzobs.px.value', 'rlp', 's1' @@ -338,148 +369,248 @@ def refls_from_sims(panel_imgs, detector, beam, thresh=0, filter=None, panel_ids os.makedirs(args.outdir) COMM.barrier() + #rank_outdir = os.path.join( args.outdir, "rank%d" % COMM.rank) + #if not os.path.exists(rank_outdir): + # os.makedirs(rank_outdir) + params = utils.get_extracted_params_from_phil_sources(args.predPhil, args.cmdlinePhil) - if os.path.isfile(args.inputGlob): - df_all = pandas.read_pickle(args.inputGlob) - df_all.reset_index(inplace=True, drop=True) - def df_iter(): - for i_f in range(len(df_all)): - if i_f % COMM.size != COMM.rank: - continue - df_i = df_all.iloc[i_f:i_f+1].copy().reset_index(drop=True) - yield i_f, df_i - Nf = len(df_all) - else: - if os.path.isdir(args.inputGlob): - glob_s = os.path.join(args.inputGlob, "pandas/rank*/*.pkl") - fnames = glob.glob(glob_s) + + # inputGlob can be a glob in strings, a single pandas file, or a hopper output folder + if os.path.isfile(args.inputGlob) or os.path.isdir(args.inputGlob): + if os.path.isfile(args.inputGlob): + fnames = [args.inputGlob] else: - fnames = glob.glob(args.inputGlob) - def df_iter(): - for i_f,f in enumerate(fnames): - if i_f % COMM.size != COMM.rank: - continue - df = pandas.read_pickle(f) - yield i_f, df - Nf = len(fnames) + dirname = args.inputGlob + fnames = glob.glob( os.path.join(dirname, "pandas/hopper_results_rank*.pkl")) + else: + fnames = glob.glob(args.inputGlob) + + if not fnames: + raise OSError("Found no filenames to load!") + Nf = 0 + shots_per_df = [] + print0("getting total number of shots") + for i_f, f in enumerate(fnames): + if i_f % COMM.size != COMM.rank: + continue + n = len(pandas.read_pickle(f)) + shots_per_df += [(f, str(x)) for x in range(n)] # note we cast to string because of mpi reduce + Nf += n + + shots_per_df = COMM.bcast(COMM.reduce( shots_per_df)) + Nf = COMM.bcast(COMM.reduce(Nf)) + print0("total num shots is %d" % Nf) + df_rows_per_rank = np.array_split(shots_per_df, COMM.size)[COMM.rank] + + print0("getting dataframe handles") + df_handles = {} + dfs = [] + if df_rows_per_rank.size: + dfs, _ = zip(*df_rows_per_rank) + for f in set(dfs): + df_handles[f] = pandas.read_pickle(f).reset_index(drop=True) + + def df_iter(): + for i_df, (df_name, row_idx) in enumerate(df_rows_per_rank): + row_idx = int(row_idx) + printR("Opening shot %d / %d" % (i_df+1, len(df_rows_per_rank))) + df = df_handles[df_name].iloc[row_idx: row_idx+1].copy() + yield i_df, df if params.predictions.verbose: params.predictions.verbose = COMM.rank==0 dev = COMM.rank % args.numdev - print0("Found %d input files" % Nf) - - all_dfs = [] - all_pred_names = [] - exp_ref_spec_lines = [] - for i_f, df in df_iter(): - printR("Shot %d / %d" % (i_f+1, Nf), flush=True) - - expt_name = df.opt_exp_name.values[0] - tag = os.path.splitext(os.path.basename(expt_name))[0] - new_expt_name = "%s/%s_%d_predicted.expt" % (args.outdir,tag, i_f) - new_expt_name = os.path.abspath(new_expt_name) - df["opt_exp_name"] = new_expt_name - - shutil.copyfile(expt_name, new_expt_name) - - data_exptList = ExperimentList.from_file(expt_name) - data_expt = data_exptList[0] - - try: - spectrum_override = None - if params.spectrum_from_imageset: - spectrum_override = downsamp_spec_from_params(params, data_expt) - pred = predictions.get_predicted_from_pandas( - df, params, strong=None, device_Id=dev, spectrum_override=spectrum_override) - if args.filterDupes: - pred = filter_refls(pred) - except ValueError: - os.remove(new_expt_name) - continue - - data = utils.image_data_from_expt(data_expt) - Rstrong = refls_from_sims(data, data_expt.detector, data_expt.beam, phil_file=args.procPhil ) - Rstrong['id'] = flex.int(len(Rstrong), 0) - num_panels = len(data_expt.detector) - if num_panels > 1: - assert params.predictions.label_weak_col == "rlp" - - Rstrong.centroid_px_to_mm(data_exptList) - Rstrong.map_centroids_to_reciprocal_space(data_exptList) - predictions.label_weak_predictions(pred, Rstrong, q_cutoff=params.predictions.qcut, col=params.predictions.label_weak_col ) - - pred['is_strong'] = flex.bool(np.logical_not(pred['is_weak'])) - strong_sel = np.logical_not(pred['is_weak']) - - pred["refl_idx"] = flex.int(np.arange(len(pred))) - weaks = pred.select(pred['is_weak']) - weaks_sorted = np.argsort(weaks["scatter"])[::-1] - nweak = len(weaks) - num_keep = int(nweak*params.predictions.weak_fraction) - weak_refl_inds_keep = set(np.array(weaks["refl_idx"])[weaks_sorted[:num_keep]]) - - weak_sel = flex.bool([i in weak_refl_inds_keep for i in pred['refl_idx']]) - keeps = np.logical_or( pred['is_strong'], weak_sel) - #printR("Sum keeps=%d; num_strong=%d, num_kept_weak=%d" % (sum(keeps), sum(strong_sel), sum(weak_sel))) - pred = pred.select(flex.bool(keeps)) - nstrong = np.sum(strong_sel) - printR("Will save %d refls (%d strong, %d weak)" % (len(pred), np.sum(strong_sel), np.sum(weak_sel))) - pred_file = os.path.abspath("%s/%s_%d_predicted.refl" % ( args.outdir, tag, i_f)) - pred.as_file(pred_file) - - Rindexed = Rstrong.select(Rstrong['indexed']) - if len(Rindexed)==0: - print("No strong indexed refls for shot %s" % new_expt_name) - continue + EXPT_DIRS = os.path.join(args.outdir, "expts_and_refls") + if COMM.rank==0: + utils.safe_makedirs(EXPT_DIRS) - utils.refls_to_hkl(Rindexed, data_expt.detector, data_expt.beam, data_expt.crystal, update_table=True) - try: - int_expt, int_refl = integrate(args.procPhil, data_exptList, Rindexed, pred) - int_expt_name = "%s/%s_%d_integrated.expt" % ( args.outdir,tag, i_f) - int_expt.as_file(int_expt_name) - int_refl['bbox'] = int_refl['shoebox'].bounding_boxes() - int_refl_name = int_expt_name.replace(".expt", ".refl") - int_refl.as_file(int_refl_name) - except RuntimeError as err: - print("Integration failed for %s because: '%s'" % (pred_file, str(err))) - - all_dfs.append(df) - all_pred_names.append(pred_file) - spec_name = df.spectrum_filename.values[0] - if spec_name is None: - spec_name = "" - exp_ref_spec_lines.append("%s %s %s\n" % (new_expt_name, pred_file, spec_name)) - - if all_dfs: - all_dfs = pandas.concat(all_dfs) - all_dfs["predicted_refls"] = all_pred_names - all_dfs["predictions"] = all_pred_names - else: - all_dfs = None + if args.scanWeakFracs and params.predictions.weak_fraction != 1: + print("WARNING: overriding weak_fracion because of scanWeakFracs") + params.predictions.weak_fraction=1 - all_dfs = COMM.gather(all_dfs) - exp_ref_spec_lines = COMM.reduce(exp_ref_spec_lines) - print0("\nReflections written to folder %s.\n" % args.outdir) - if COMM.rank==0: - hopper_input_name = os.path.abspath(os.path.join(args.outdir , "%s.txt" % args.hopInputName)) - o = open(hopper_input_name, "w") - for l in exp_ref_spec_lines: - o.write(l) - o.close() - all_dfs = [df for df in all_dfs if df is not None] - if not all_dfs: - raise ValueError("No dataframes to concat: prediction/integration failed for all shots..") - - all_dfs = pandas.concat([df for df in all_dfs if df is not None]) - all_dfs.reset_index(inplace=True, drop=True) - best_pkl_name = os.path.abspath(os.path.join(args.outdir , "%s.pkl" % args.hopInputName)) - all_dfs.to_pickle(best_pkl_name) - print("Wrote %s (best_pickle option for simtbx.diffBragg.hopper) and %s (exp_ref_spec option for simtbx.diffBragg.hopper). Use them to run the predictions through hopper. Use the centroid=cal option to specify the predictions" % (best_pkl_name, hopper_input_name)) - - with open(args.outdir +".exectution.txt", "w") as o: - o.write("integrate was run from folder: %s\n" % os.getcwd()) - o.write("The command line input was:\n") - o.write(" ".join(sys.argv)) - #TODO: write the diff phils here: + print0("Found %d input files" % Nf) + with DeviceWrapper(dev) as _: + all_dfs = [] + all_pred_names = [] + exp_ref_spec_lines = [] + all_rank_pred = None + all_rank_expt = None + + rank_shot_count = 0 + rank_pred_file = os.path.join(EXPT_DIRS, "rank%d_preds.refl" % COMM.rank) + rank_pred_file = os.path.abspath(rank_pred_file) + rank_expt_file = rank_pred_file.replace(".refl", ".expt") + for i_f, df in df_iter(): + + expt_name = df.exp_name.values[0] + expt_idx = df.exp_idx.values[0] + tag = os.path.splitext(os.path.basename(expt_name))[0] + + data_expt = hopper_utils.DataModeler.exper_json_single_file(expt_name, expt_idx) + data_exptList = ExperimentList() + data_exptList.append(data_expt) + + try: + spectrum_override = None + if params.spectrum_from_imageset: + spectrum_override = downsamp_spec_from_params(params, data_expt) + pred = predictions.get_predicted_from_pandas( + df, params, strong=None, device_Id=dev, spectrum_override=spectrum_override) + if args.filterDupes: + pred = filter_refls(pred) + except ValueError: + #os.remove(new_expt_name) + continue + + data = utils.image_data_from_expt(data_expt) + Rstrong = refls_from_sims(data, data_expt.detector, data_expt.beam, phil_file=args.procPhil ) + Rstrong['id'] = flex.int(len(Rstrong), 0) + num_panels = len(data_expt.detector) + if num_panels > 1: + assert params.predictions.label_weak_col == "rlp" + + Rstrong.centroid_px_to_mm(data_exptList) + Rstrong.map_centroids_to_reciprocal_space(data_exptList) + predictions.label_weak_predictions(pred, Rstrong, q_cutoff=params.predictions.qcut, col=params.predictions.label_weak_col ) + + pred['is_strong'] = flex.bool(np.logical_not(pred['is_weak'])) + strong_sel = np.logical_not(pred['is_weak']) + + pred["refl_idx"] = flex.int(np.arange(len(pred))) + + #weaks = pred.select(pred['is_weak']) + #weaks_sorted = np.argsort(weaks["scatter"])[::-1] + #nweak = len(weaks) + #num_keep = int(nweak*params.predictions.weak_fraction) + #weak_refl_inds_keep = set(np.array(weaks["refl_idx"])[weaks_sorted[:num_keep]]) + #weak_sel = flex.bool([i in weak_refl_inds_keep for i in pred['refl_idx']]) + #keeps = np.logical_or( pred['is_strong'], weak_sel) + #printR("Sum keeps=%d; num_strong=%d, num_kept_weak=%d" % (sum(keeps), sum(strong_sel), sum(weak_sel))) + #pred = pred.select(flex.bool(keeps)) + pred = filter_weak_reflections(pred, weak_fraction=params.predictions.weak_fraction) + + nstrong = np.sum(strong_sel) + printR("Will save %d refls (%d strong, %d weak)" % (len(pred), np.sum(pred["is_strong"]), np.sum(pred["is_weak"]))) + pred['id'] = flex.int(len(pred), rank_shot_count) + if 'shoebox' in list(pred) and not args.keepShoeboxes: + del pred['shoebox'] + if all_rank_pred is None: + all_rank_pred = deepcopy(pred) + else: + all_rank_pred.extend(pred) + + # Note, the simple append causes memory leak: + #all_rank_expt.append(data_expt) + if all_rank_expt is None: + all_rank_expt = deepcopy(data_exptList.to_dict()) + else: + Edict = data_exptList.to_dict() + for exp_key in 'beam', 'detector', 'crystal', 'imageset': + Edict['experiment'][0][exp_key] = rank_shot_count + for exp_key in 'experiment', 'beam', 'detector', 'crystal', 'imageset': + assert len( Edict[exp_key])==1 + all_rank_expt[exp_key] .append(Edict[exp_key][0]) + + Rindexed = Rstrong.select(Rstrong['indexed']) + if len(Rindexed)==0: + print("No strong indexed refls for shot %s" % expt_name) + continue + + utils.refls_to_hkl(Rindexed, data_expt.detector, data_expt.beam, data_expt.crystal, update_table=True) + if args.dialsInteg: + # TODO: save these files as multi-shot experiment/refls + try: + int_expt, int_refl = integrate(args.procPhil, data_exptList, Rindexed, pred) + int_expt_name = "%s/%s_%d_integrated.expt" % (rank_outdir, tag, i_f) + int_expt.as_file(int_expt_name) + int_refl['bbox'] = int_refl['shoebox'].bounding_boxes() + int_refl_name = int_expt_name.replace(".expt", ".refl") + int_refl.as_file(int_refl_name) + except RuntimeError: + print("Integration failed" ) + + df['old_exp_name'] = expt_name + df['old_exp_idx'] = expt_idx + df['exp_name'] = rank_expt_file + df['exp_idx'] = rank_shot_count + + df['predictions'] = rank_pred_file + df['predicted_refs'] = rank_pred_file + df['num_pred'] = len(pred) + + all_dfs.append(df) + rank_shot_count += 1 + + spec_name = df.spectrum_filename.values[0] + if spec_name is None: + spec_name = "" + exp_ref_spec_lines.append("%s %s %s %d\n" % (rank_expt_file, rank_pred_file, spec_name, rank_shot_count)) + + all_rank_pred.as_file(rank_pred_file) + # NOTE: all_rank_expt is a dictionary to avoid weird OOM, so we write a simple json + #all_rank_expt.as_file(rank_expt_file) + with open(rank_expt_file, "w") as file_O: + json.dump(all_rank_expt, file_O) + print0("Done with predictions, combining dataframes") + if all_dfs: + all_dfs = pandas.concat(all_dfs) + else: + all_dfs = None + + if args.scanWeakFracs and all_dfs is not None: + assert len(all_dfs.predictions.unique()) == 1 + pred_file = all_dfs.predictions.values[0] + n_total_weak = np.sum(all_rank_pred['is_weak']) + n_total = len(all_rank_pred) + weak_fracs = [.11,.22,.33,.44,.55,.66,.77,.88] + labels = [] + for i_frac, weak_frac in enumerate(weak_fracs): + filt_refls = filter_weak_reflections(all_rank_pred, weak_frac) + label="%dperc"%(weak_frac*100,) + labels.append(label) + new_pred_file = os.path.splitext(pred_file)[0]+"_%s.refl" % label + all_dfs['predictions_%s' % label] = new_pred_file + all_dfs['predicted_refs_%s' %label] = new_pred_file + num_preds = [] + for exp_id in all_dfs.exp_idx.values: + n = np.sum(filt_refls['id'] == int(exp_id)) + num_preds.append(n) + all_dfs['num_pred_%s' %label] = num_preds + filt_refls.as_file(new_pred_file) + printR("Saved %d/%d refls (%d strong, %d/%d weak) to %s" + % (len(filt_refls), n_total, np.sum(filt_refls["is_strong"]), np.sum(filt_refls["is_weak"]), n_total_weak, new_pred_file)) + # note this sanity check below requires that weaK_fracs be sorted + if sorted(weak_fracs) == weak_fracs: + # then as weak frac increases, there should be an increasing number of predictions + num_preds_per_frac = [all_dfs["num_pred_%s" % lab].sum() for lab in labels] + assert num_preds_per_frac == sorted(num_preds_per_frac) + + print0("MPI gather all_dfs") + all_dfs = COMM.gather(all_dfs) + print0("MPI reduce lines") + exp_ref_spec_lines = COMM.reduce(exp_ref_spec_lines) + if COMM.rank==0: + hopper_input_name = os.path.abspath(os.path.join(args.outdir , "%s.txt" % args.hopInputName)) + o = open(hopper_input_name, "w") + for l in exp_ref_spec_lines: + o.write(l) + o.close() + all_dfs = [df for df in all_dfs if df is not None] + if not all_dfs: + raise ValueError("No dataframes to concat: prediction/integration failed for all shots..") + + print("Concat frames") + all_dfs = pandas.concat([df for df in all_dfs if df is not None]) + all_dfs.reset_index(inplace=True, drop=True) + best_pkl_name = os.path.abspath(os.path.join(args.outdir , "%s.pkl" % args.hopInputName)) + all_dfs.to_pickle(best_pkl_name) + print("Wrote %s (best_pickle option for simtbx.diffBragg.hopper) and %s (exp_ref_spec option for simtbx.diffBragg.hopper). Use them to run the predictions through hopper (use phil centroid=cal) or simtbx.diffBragg.stage_two." % (best_pkl_name, hopper_input_name)) + + cmd_log_file = os.path.join(args.outdir, "cmdline_execution.txt") + with open(cmd_log_file, "w") as o: + o.write("integrate was run from folder: %s\n" % os.getcwd()) + o.write("The command line input was:\n") + o.write(" ".join(sys.argv) + "\n") + #TODO: write the diff phils here: diff --git a/simtbx/command_line/make_input_file.py b/simtbx/command_line/make_input_file.py index b63b9c4ac5..3229cd1b53 100644 --- a/simtbx/command_line/make_input_file.py +++ b/simtbx/command_line/make_input_file.py @@ -11,6 +11,7 @@ "split files will be written in same folders as their sources") parser.add_argument("--exptSuffix", type=str, default="refined.expt", help="find experiments with this suffix") parser.add_argument("--reflSuffix", type=str, default="indexed.refl", help="find reflection files with this suffix") +parser.add_argument("--write", action="store_true") args = parser.parse_args() @@ -25,10 +26,11 @@ from simtbx.diffBragg import hopper_io import hashlib + from libtbx.mpi4py import MPI COMM = MPI.COMM_WORLD -if COMM.rank==0: +if COMM.rank==0 and args.write: if args.splitDir is not None and not os.path.exists(args.splitDir): os.makedirs(args.splitDir) @@ -48,7 +50,7 @@ def get_idx_path(El): return idx, path -def split_stills_expts(expt_f, refl_f, split_dir): +def split_stills_expts(expt_f, refl_f, split_dir, write=False): El = ExperimentList.from_file(expt_f, False) R = flex.reflection_table.from_file(refl_f) expt_names = [] @@ -65,15 +67,16 @@ def split_stills_expts(expt_f, refl_f, split_dir): seen_isets[iset_id] += 1 tag = "%s-%d" % (os.path.basename(os.path.splitext(path)[0]), idx) new_expt_name = os.path.splitext(expt_f)[0] + "_%s_xtal%d.expt" % (tag, seen_isets[iset_id]) - if split_dir is not None: + if write and split_dir is not None: unique_tag = "shot_%s" % hash_name(new_expt_name) + ".expt" new_expt_name = os.path.join(split_dir, unique_tag) new_refl_name = new_expt_name.replace(".expt", ".refl") refls = R.select(R['id'] == i_expt) refls.reset_ids() - one_exp_El.as_file(new_expt_name) - refls.as_file(new_refl_name) + if write: + one_exp_El.as_file(new_expt_name) + refls.as_file(new_refl_name) expt_names.append(new_expt_name) refl_names.append(new_refl_name) orig_expt_names.append((apath(new_expt_name), (apath(expt_f), i_expt))) @@ -119,12 +122,20 @@ def split_stills_expts(expt_f, refl_f, split_dir): if COMM.rank==0: - print("Saving the input file for diffBragg") - hopper_io.save_expt_refl_file(args.filename, exp_names, ref_names, check_exists=True) - print("Saved %s" % args.filename) - - jname = args.filename + ".json" - jdat = {"expt": dict(orig_exp_names), "refl": dict(orig_ref_names)} - with open(jname, "w") as fp: - json.dump(jdat, fp, indent=1) - print("Wrote json %s, which maps the hashnames to the original expt files" % jname) + if args.write: + print("Saving the input file for diffBragg") + hopper_io.save_expt_refl_file(args.filename, exp_names, ref_names, check_exists=True) + print("Saved %s" % args.filename) + jname = args.filename + ".json" + jdat = {"expt": dict(orig_exp_names), "refl": dict(orig_ref_names)} + with open(jname, "w") as fp: + json.dump(jdat, fp, indent=1) + print("Wrote json %s, which maps the hashnames to the original expt files" % jname) + else: + _, exp_and_idx = zip(*orig_exp_names) + _, ref_and_idx = zip(*orig_ref_names) + exp, exp_idx = zip(*exp_and_idx) + ref, ref_idx = zip(*ref_and_idx) + assert exp_idx == ref_idx + hopper_io.save_expt_refl_file(args.filename, exp, ref, check_exists=True, + indices=exp_idx) diff --git a/simtbx/command_line/spectra.py b/simtbx/command_line/spectra.py new file mode 100644 index 0000000000..0ccfa78791 --- /dev/null +++ b/simtbx/command_line/spectra.py @@ -0,0 +1,99 @@ +from __future__ import division + +# LIBTBX_SET_DISPATCHER_NAME diffBragg.spectra + +#TODO: add text entry boxes for other spectrum filter params, position entry boxes sensibly + +from simtbx.diffBragg import hopper_utils +from pylab import * +import dxtbx +from simtbx.diffBragg.phil import philz, hopper_phil +from libtbx.phil import parse +from matplotlib.widgets import TextBox + +from argparse import ArgumentParser +parser = ArgumentParser() +parser.add_argument("image_file", type=str, help="path to a diffBragg modeler file (output from hopper, see the imgs folder in the outdir)") +parser.add_argument("--filt_freq", default=0.07, type=float) +parser.add_argument("--filt_order", default=3, type=float) +parser.add_argument("--tail", default=50, type=int) +parser.add_argument("--delta_en", default=0.5, type=float) +parser.add_argument("--skip", action="store_true") +args = parser.parse_args() + +FIG,ax0 = subplots(nrows=1,ncols=1) +FIG.set_size_inches((5,3)) + +class P: + + def __init__(self, params, imgset, ax0, FIG): + self.params = params + self.imgset = imgset + self.ax0 = ax0 + self.FIG= FIG + + def entry(self, text): + delta_en = float(text) + self.params.downsamp_spec.delta_en = delta_en + print(delta_en) + self.update_plot(self.imgset) + + def update_plot(self, i_img): + raw_spec = self.imgset.get_spectrum(i_img) + raw_en = raw_spec.get_energies_eV() + raw_wt = raw_spec.get_weights() + + spec = hopper_utils.downsamp_spec_from_params(self.params, imgset=self.imgset, i_img=i_img) + en, wt = map(np.array, zip(*spec)) + en = hopper_utils.utils.ENERGY_CONV / en + + self.ax0.clear() + self.ax0.plot( raw_en, raw_wt, lw=2, label="raw spec (%d chan)" % len(raw_en)) + self.ax0.plot( en, wt, '--', lw=1, label="filt spec (%d chan)" % len(en)) + self.FIG.suptitle("image %d" % (i_img, ), fontsize=14) + self.ax0.set_xlabel("Energy (eV)", fontsize=12) + self.ax0.tick_params(labelsize=11) + self.ax0.legend(prop={"size":11}, loc="upper right") + draw() + + +def press(event): + if event.key == 'right': + FIG.loop_counter += 1 + elif event.key=="left": + FIG.loop_counter = FIG.loop_counter -1 + FIG.loop_counter = max(FIG.loop_counter,0) + FIG.loop_counter = min(FIG.loop_counter, FIG.nspots-1) + + if event.key=="escape": + FIG.loop_counter = FIG.nspots + +FIG.loop_counter = 0 +loader = dxtbx.load(args.image_file) +imgset = loader.get_imageset(loader.get_image_file()) +FIG.nspots = len(imgset) +FIG.canvas.mpl_connect('key_press_event', press) + +phil_scope = parse(philz + hopper_phil) +params = phil_scope.fetch(sources=[phil_scope]).extract() + +params.downsamp_spec.filt_freq = args.filt_freq +params.downsamp_spec.filt_order = args.filt_order +params.downsamp_spec.tail = args.tail +params.downsamp_spec.delta_en = args.delta_en +params.downsamp_spec.skip = args.skip + +Pinst = P(params, imgset, ax0, FIG) +axbox = plt.axes([0.25, 0.75, 0.1, 0.075]) +text_box = TextBox(axbox, 'delta_en', initial="%.2f" % args.delta_en) +text_box.on_submit(Pinst.entry) + +while FIG.loop_counter < len(imgset): + i_img = FIG.loop_counter + + Pinst.update_plot(i_img) + + waitforbuttonpress() + i_img += 1 + +plt.close() diff --git a/simtbx/command_line/stage_two.py b/simtbx/command_line/stage_two.py index bb72c9a541..0787a9867f 100644 --- a/simtbx/command_line/stage_two.py +++ b/simtbx/command_line/stage_two.py @@ -3,13 +3,13 @@ # LIBTBX_SET_DISPATCHER_NAME simtbx.diffBragg.stage_two from libtbx.mpi4py import MPI -from simtbx.kokkos import gpu_instance -kokkos_run = gpu_instance(deviceId = 0) from simtbx.command_line.hopper import hopper_phil import time import logging from simtbx.diffBragg import mpi_logger +from simtbx.diffBragg.device import DeviceWrapper + COMM = MPI.COMM_WORLD if COMM.rank > 0: @@ -28,10 +28,13 @@ pandas_table = None .type = str .help = path to an input pandas table (usually output by simtbx.diffBragg.predictions) -prep_time = 60 +refls_key = predictions + .type = str + .help = name of the predicted refls column in the pandas table input +max_sigz = 10. .type = float - .help = Time spent optimizing order of input dataframe to better divide shots across ranks - .help = Unit is seconds, 1-2 minutes of prep might save a lot of time during refinement! + .help = Maximum allowed value ot sigz in the input pandas table (dataframe) + .help = (high sigz above 10 usually indicates failed stage 1 refinement) """ philz = script_phil + philz + hopper_phil @@ -85,6 +88,7 @@ def run(self): if LineProfiler is not None and script.params.profile: lp = LineProfiler() lp.add_function(ensemble_refine_launcher.RefineLauncher.launch_refiner) + lp.add_function(ensemble_refine_launcher.RefineLauncher.load_inputs) lp.add_function(stage_two_refiner.StageTwoRefiner._compute_functional_and_gradients) lp.add_function(stage_two_refiner.StageTwoRefiner._run_diffBragg_current) lp.add_function(stage_two_refiner.StageTwoRefiner._update_Fcell) @@ -108,7 +112,9 @@ def run(self): else: mpi_logger.setup_logging_from_params(script.params) - RUN() + dev = COMM.rank % script.params.refiner.num_devices + with DeviceWrapper(dev) as _: + RUN() if lp is not None: stats = lp.get_stats() @@ -116,4 +122,4 @@ def run(self): hopper_utils.print_profile(stats, ["launch_refiner", "_compute_functional_and_gradients", "_run_diffBragg_current", "_update_Fcell", "_scale_pixel_data", "_Fcell_derivatives", "_mpi_aggregation", - "GatherFromExperiment", "_setup"]) + "GatherFromExperiment", "_setup", "load_inputs"]) diff --git a/simtbx/command_line/update_stage1_phil.py b/simtbx/command_line/update_stage1_phil.py new file mode 100644 index 0000000000..869d1fe32f --- /dev/null +++ b/simtbx/command_line/update_stage1_phil.py @@ -0,0 +1,82 @@ + +from __future__ import division +from argparse import ArgumentParser +parser = ArgumentParser() +parser.add_argument("dirname", help="stage1 output folder with pandas and diff.phil", type=str) +parser.add_argument("newPhil", default=None, help="new stage 1 phil file", type=str) +parser.add_argument("--setGlim", action="store_true", help="Use unrestrained stage1 to set bounds on G") +#parser.add_argument("--njobs", type=int, default=5, help="number of jobs (only runs on single node, no MPI)") +#parser.add_argument("--plot", action="store_true", help="show a histogram at the end") +args = parser.parse_args() + +# LIBTBX_SET_DISPATCHER_NAME diffBragg.update_stage1_phil + +import os +import pandas +import numpy as np +import glob + +glob_s = os.path.join(args.dirname, "pandas/*pkl") +fnames = glob.glob(glob_s) + +# read in the pandas pickles +df1 = pandas.concat( [pandas.read_pickle(f) for f in fnames]).reset_index(drop=True) + +# unit cell phil +a,b,c,al,be,ga = df1[['a', 'b', 'c', 'al', 'be', 'ga']].median() + +# Ncells abc and Nvol +na, nb, nc = np.vstack(df1.ncells).T +nvol = na*nb*nc +nvol = np.median(na*nb*nc) +na, nb, nc = map(np.median, (na, nb, nc)) + +# eta +ea, eb, ec = map( np.median, np.vstack(df1.eta_abc).T) + +# spot scale (G) +Gmed = df1.spot_scales.median() +Gmin = df1.spot_scales.min()/100 +Gmax = df1.spot_scales.max()*100 + +update_phil = """ +init {{ + G = {G} + Nabc = [{na},{nb},{nc}] + eta_abc = [{ea},{eb},{ec}] +}} +centers {{ + Nvol = {nvol} + ucell_a = {a} + ucell_b = {b} + ucell_c = {c} + ucell_alpha = {al} + ucell_beta = {be} + ucell_gamma = {ga} +}} +betas {{ + Nvol = 1e-2 + ucell_a = 1e-7 + ucell_b = 1e-7 + ucell_c = 1e-7 + ucell_alpha = 1e-7 + ucell_beta = 1e-7 + ucell_gamma = 1e-7 +}} +use_restraints = True +""".format(G=Gmed,na=na, nb=nb, nc=nb, ea=ea, eb=eb, ec=ec,a=a,b=b,c=c,al=al,be=be,ga=ga, nvol=nvol) + +Gmin_Gmax=""" +mins.G={Gmin} +maxs.G={Gmax}\n""".format(Gmin=Gmin, Gmax=Gmax) + +if args.setGlim: + update_phil += Gmin_Gmax + +diff_phil_name = os.path.join(args.dirname, "diff.phil") +assert os.path.exists(diff_phil_name) +diff_phil = open(diff_phil_name, "r").read() +with open(args.newPhil, "w") as o: + o.write(diff_phil + "\n"+ update_phil) + +print("Done. added \n%s\n to the %s and saved to %s" % (update_phil, diff_phil_name, args.newPhil) ) diff --git a/simtbx/diffBragg/ensemble_refine_launcher.py b/simtbx/diffBragg/ensemble_refine_launcher.py index bb43493782..e84f5c3e9b 100644 --- a/simtbx/diffBragg/ensemble_refine_launcher.py +++ b/simtbx/diffBragg/ensemble_refine_launcher.py @@ -1,5 +1,7 @@ from __future__ import absolute_import, division, print_function from simtbx.diffBragg.stage_two_utils import PAR_from_params +from collections import Counter +from itertools import chain import os import sys from libtbx.mpi4py import MPI @@ -11,11 +13,10 @@ except ImportError: print("Pandas is required. Install using 'libtbx.python -m pip install pandas'") exit() -from xfel.merging.application.utils.memory_usage import get_memory_usage from simtbx.diffBragg.refiners.stage_two_refiner import StageTwoRefiner from simtbx.diffBragg import utils from simtbx.diffBragg import hopper_utils -from dxtbx.model.experiment_list import ExperimentListFactory +from dxtbx.model.experiment_list import ExperimentList, ExperimentListFactory from simtbx.diffBragg.prep_stage2_input import prep_dataframe from cctbx import miller, crystal import logging @@ -28,11 +29,20 @@ def global_refiner_from_parameters(params): # TODO read on each rank, or read and broadcast ? LOGGER.info("EVENT: read input pickle") pandas_table = pandas.read_pickle(params.pandas_table) + if params.max_sigz is not None and "sigz" in list(pandas_table): + Nframe = len(pandas_table) + pandas_table = pandas_table.query("sigz < %f" % params.max_sigz) + pandas_table.reset_index(drop=True, inplace=True) + LOGGER.info("Removed %d / %d dataframes due to max_sigz=%.2f filter" + % (Nframe - len(pandas_table), Nframe, params.max_sigz)) + if params.max_process > 0: + pandas_table = pandas_table.iloc[:params.max_process] LOGGER.info("EVENT: BEGIN prep dataframe") - if params.prep_time > 0: - work_distribution = prep_dataframe(pandas_table) + if "exp_idx" not in list(pandas_table): + pandas_table["exp_idx"] = 0 + work_distribution = prep_dataframe(pandas_table, res_ranges_string=params.refiner.res_ranges) LOGGER.info("EVENT: DONE prep dataframe") - return launcher.launch_refiner(pandas_table, work_distribution=work_distribution) + return launcher.launch_refiner(pandas_table, work_distribution=work_distribution, refls_key=params.refls_key) class RefineLauncher: @@ -63,7 +73,7 @@ def check_parameter_integrity(params): raise ValueError("Cannot refine because params.refiner.max_calls is empty") if os.environ.get("DIFFBRAGG_CUDA") is not None: - params.refiner.use_cuda = True + params.refiner.use_gpu = True return params @@ -115,8 +125,8 @@ def _check_experiment_integrity(expt): if not hasattr(expt, model): raise ValueError("No %s in experiment, exiting. " % model) - def launch_refiner(self, pandas_table, miller_data=None, work_distribution=None): - self.load_inputs(pandas_table, miller_data=miller_data, work_distribution=work_distribution) + def launch_refiner(self, pandas_table, miller_data=None, work_distribution=None, refls_key="predictions"): + self.load_inputs(pandas_table, miller_data=miller_data, work_distribution=work_distribution, refls_key=refls_key) LOGGER.info("EVENT: launch refiner") self._launch() return self.RUC @@ -128,7 +138,7 @@ def load_inputs(self, pandas_table, miller_data=None, work_distribution=None, re the pandas table is expected to have been written by diffBragg.hopper or diffBragg.hopper_process . See method save_to_pandas in simtbx/command_line/hopper.py For example, if the outputdir of diffBragg.hopper was set to `all_shots`, then - there should be a golder all_shots/pandas created which contains all of the per-shot pandas + there should be a folder all_shots/pandas created which contains all of the per-shot pandas dataframes. They should be concatenated as follows, forming a suitable argument for this method >> import glob,pandas >> fnames = glob.glob("all_shots/pandas/rank*/*pkl") @@ -145,6 +155,8 @@ def load_inputs(self, pandas_table, miller_data=None, work_distribution=None, re """ COMM.Barrier() num_exp = len(pandas_table) + if "exp_idx" not in list(pandas_table): + pandas_table["exp_idx"] = 0 first_exper_file = pandas_table.exp_name.values[0] detector = ExperimentListFactory.from_json_file(first_exper_file, check_format=False)[0].detector if detector is None and self.params.refiner.reference_geom is None: @@ -169,51 +181,58 @@ def load_inputs(self, pandas_table, miller_data=None, work_distribution=None, re shot_idx = 0 # each rank keeps index of the shots local to it rank_panel_groups_refined = set() exper_names = pandas_table.exp_name - assert len(exper_names) == len(set(exper_names)) + exper_ids = pandas_table.exp_idx.values + shot_ids = list(zip(exper_names, exper_ids)) + assert len(shot_ids) == len(set(shot_ids)) # TODO assert all exper are single-file, probably way before this point if work_distribution is None: worklist = range(COMM.rank, len(exper_names), COMM.size) else: worklist = work_distribution[COMM.rank] LOGGER.info("EVENT: begin loading inputs") - for i_exp in worklist: - exper_name = exper_names[i_exp] + + # load the Fhkl model once here to check which hkl are missing (and filter from the refls below) + first_exper = ExperimentList.from_file(exper_names[0], check_format=False)[0] + Fhkl_model = utils.load_Fhkl_model_from_params_and_expt(self.params, first_exper) + self.symbol = Fhkl_model.space_group().info().type().lookup_symbol() + if self.params.refiner.force_symbol is not None: + self.symbol = self.params.refiner.force_symbol + LOGGER.info("Will use space group symbol %s" % self.symbol) + Fhkl_model_p1 = Fhkl_model.expand_to_p1().generate_bijvoet_mates() + Fhkl_model_p1_indices = set(Fhkl_model_p1.indices()) + + for i_work, i_df in enumerate(worklist): + exper_name = exper_names[i_df] + exper_id = int(exper_ids[i_df]) LOGGER.info("EVENT: BEGIN loading experiment list") - expt_list = ExperimentListFactory.from_json_file(exper_name, check_format=self.params.refiner.check_expt_format) + # TODO: test that the diffBragg_benchmarks is not broken + expt = hopper_utils.DataModeler.exper_json_single_file(exper_name, exper_id) + expt_list = ExperimentList() + expt_list.append(expt) LOGGER.info("EVENT: DONE loading experiment list") - if len(expt_list) != 1: - print("Input experiments need to have length 1, %s does not" % exper_name) - expt = expt_list[0] expt.detector = detector # in case of supplied ref geom self._check_experiment_integrity(expt) - exper_dataframe = pandas_table.query("exp_name=='%s'" % exper_name) + exper_dataframe = pandas_table.query("exp_name=='%s'" % exper_name).query("exp_idx==%d" % exper_id) refl_name = exper_dataframe[refls_key].values[0] refls = flex.reflection_table.from_file(refl_name) - # FIXME need to remove (0,0,0) bboxes + refls = refls.select(refls['id'] == exper_id) try: - good_sel = flex.bool([h != (0, 0, 0) for h in list(refls["miller_index"])]) - refls = refls.select(good_sel) + miller_inds = list(refls["miller_index"]) + is_not_000 = [h != (0, 0, 0) for h in miller_inds] + is_in_Fhkl_model = [h in Fhkl_model_p1_indices for h in miller_inds] + LOGGER.debug("Only refining %d/%d refls whose HKL are in structure factor model" % ( + np.sum(is_in_Fhkl_model), len(refls))) + refl_sel = flex.bool(np.logical_and(is_not_000, is_in_Fhkl_model)) + refls = refls.select(refl_sel) except KeyError: pass - #UcellMan = utils.manager_from_crystal(expt.crystal) opt_uc_param = exper_dataframe[["a","b","c","al","be","ga"]].values[0] UcellMan = utils.manager_from_params(opt_uc_param) - if self.symbol is None: - if self.params.refiner.force_symbol is not None: - self.symbol = self.params.refiner.force_symbol - else: - self.symbol = expt.crystal.get_space_group().type().lookup_symbol() - LOGGER.info("Set space group symbol: %s" % self.symbol) - else: - if self.params.refiner.force_symbol is None: - if expt.crystal.get_space_group().type().lookup_symbol() != self.symbol: - raise ValueError("Crystals should all have the same space group symmetry") - if shot_idx == 0: # each rank initializes a simulator only once if self.params.simulator.init_scale != 1: print("WARNING: For stage_two , it is assumed that total scale is stored in the pandas dataframe") @@ -226,31 +245,16 @@ def load_inputs(self, pandas_table, miller_data=None, work_distribution=None, re self.Fref = utils.open_mtz(self.params.refiner.stage_two.Fref_mtzname, self.params.refiner.stage_two.Fref_mtzcol) - if "miller_index" in list(refls.keys()): - is_allowed = flex.bool(len(refls), True) - allowed_hkls = set(self.SIM.crystal.miller_array.indices()) - uc = self.SIM.crystal.dxtbx_crystal.get_unit_cell().parameters() - symb = self.SIM.crystal.space_group_info.type().lookup_symbol() - sym = crystal.symmetry(uc, symb) - mset = miller.set(sym, refls['miller_index'],True) - op = mset.change_of_basis_op_to_primitive_setting() - mset_p = mset.change_basis(op) - refl_hkls_p1 = mset_p.indices() - - for i_ref in range(len(refls)): - hkl_p1 = refl_hkls_p1[i_ref] - if hkl_p1 not in allowed_hkls: - is_allowed[i_ref] = False - refls = refls.select(is_allowed) - LOGGER.info("EVENT: LOADING ROI DATA") shot_modeler = hopper_utils.DataModeler(self.params) shot_modeler.exper_name = exper_name + shot_modeler.exper_idx = exper_id shot_modeler.refl_name = refl_name shot_modeler.rank = COMM.rank if self.params.refiner.load_data_from_refl: gathered = shot_modeler.GatherFromReflectionTable(expt, refls, sg_symbol=self.symbol) else: + # Note: no need to pass exper_id here because expt and refls have already been sliced out gathered = shot_modeler.GatherFromExperiment(expt, refls, sg_symbol=self.symbol) if not gathered: raise IOError("Failed to gather data from experiment %s", exper_name) @@ -279,7 +283,6 @@ def load_inputs(self, pandas_table, miller_data=None, work_distribution=None, re assert np.allclose(new_Modeler.roi_id, all_roi_id) LOGGER.info("Gathered file approved!") - self.Hi[shot_idx] = shot_modeler.Hi self.Hi_asu[shot_idx] = shot_modeler.Hi_asu @@ -322,19 +325,21 @@ def load_inputs(self, pandas_table, miller_data=None, work_distribution=None, re shot_modeler.originZ_init = exper_dataframe.detz_shift_mm.values[0]*1e-3 else: shot_modeler.originZ_init = 0 + # TODO: is there a reason these 3 attribs are set once more after being set above? shot_modeler.exper_name = exper_name + shot_modeler.exper_idx = exper_id shot_modeler.refl_name = refl_name shot_panel_groups_refined = self.determine_refined_panel_groups(shot_modeler.pids) rank_panel_groups_refined = rank_panel_groups_refined.union(set(shot_panel_groups_refined)) shot_idx += 1 - if COMM.rank == 0: - self._mem_usage() - print("Finished loading image %d / %d" % (i_exp+1, len(exper_names)), flush=True) + LOGGER.info(utils.memory_report('Process memory usage')) + LOGGER.info("Finished loading image %d / %d (%d / %d)" + % (i_df+1, len(exper_names), i_work+1, len(worklist))) #, flush=True) shot_modeler.PAR = PAR_from_params(self.params, expt, best=exper_dataframe) - self.Modelers[i_exp] = shot_modeler + self.Modelers[i_df] = shot_modeler # TODO: verify that i_df as a key is ok everywhere LOGGER.info("DONE LOADING DATA; ENTER BARRIER") COMM.Barrier() @@ -349,16 +354,18 @@ def load_inputs(self, pandas_table, miller_data=None, work_distribution=None, re for set_of_panels in all_refined_groups: panel_groups_refined = panel_groups_refined.union(set_of_panels) self.panel_groups_refined = list(COMM.bcast(panel_groups_refined)) + LOGGER.info(utils.memory_report('Mem after panel groups')) LOGGER.info("EVENT: Gathering global HKL information") try: self._gather_Hi_information() - except TypeError: + except TypeError: # TODO: should we siltently fail here ? pass LOGGER.info("EVENT: FINISHED gather global HKL information") if self.params.roi.cache_dir_only: print("Done creating cache directory and cache_dir_only=True, so goodbye.") sys.exit() + LOGGER.info(utils.memory_report('Mem after gather Hi info')) # in case of GPU LOGGER.info("BEGIN DETERMINE MAX PIX") @@ -369,15 +376,10 @@ def load_inputs(self, pandas_table, miller_data=None, work_distribution=None, re n = max(n) self.NPIX_TO_ALLOC = COMM.bcast(n) LOGGER.info("DONE DETERMINE MAX PIX") + LOGGER.info(utils.memory_report('Mem after determine max num pix')) self.DEVICE_ID = COMM.rank % self.params.refiner.num_devices - self._mem_usage() - - def _mem_usage(self): - memMB = get_memory_usage() - import socket - host = socket.gethostname() - print("Rank 0 reporting memory usage: %f GB on Rank 0 node %s" % (memMB / 1e3, host)) + LOGGER.info(utils.memory_report('Mem after load_inputs')) def determine_refined_panel_groups(self, pids): refined_groups = [] @@ -394,8 +396,8 @@ def _determine_per_rank_max_num_pix(self): x1, x2, y1, y2 = map(np.array, zip(*modeler.rois)) npix = np.sum((x2-x1)*(y2-y1)) max_npix = max(npix, max_npix) - print("Rank %d, shot %d has %d pixels" % (COMM.rank, i_shot+1, npix)) - print("Rank %d, max pix to be modeled: %d" % (COMM.rank, max_npix)) + #print("Rank %d, shot %d has %d pixels" % (COMM.rank, i_shot+1, npix)) + LOGGER.info("Rank %d, max pix to be modeled: %d" % (COMM.rank, max_npix)) return max_npix def _try_loading_spectrum_filelist(self): @@ -407,50 +409,37 @@ def _try_loading_spectrum_filelist(self): return file_list def _gather_Hi_information(self): - nshots_on_this_rank = len(self.Hi) # aggregate all miller indices - self.Hi_all_ranks, self.Hi_asu_all_ranks = [], [] - # TODO assert list types are stored in Hi and Hi_asu - for i_shot in self.Hi: #range(nshots_on_this_rank): - self.Hi_all_ranks += self.Hi[i_shot] - self.Hi_asu_all_ranks += self.Hi_asu[i_shot] - self.Hi_all_ranks = COMM.reduce(self.Hi_all_ranks) - self.Hi_all_ranks = COMM.bcast(self.Hi_all_ranks) - self.Hi_asu_all_ranks = COMM.reduce(self.Hi_asu_all_ranks) - self.Hi_asu_all_ranks = COMM.bcast(self.Hi_asu_all_ranks) + self.hiasu = HiAsu(self) - marr_unique_h = self._get_unique_Hi() + # TODO Restore this diagnostics step within the scope of `HiAsu` class + # Hi_asu_all_ranks used to be a list of all Hi_asu from all ranks, + # (None of ranks > 0) but was removed when moving to new `HiAsu` class. + # marr_unique_h = self._get_unique_Hi(Hi_asu_all_ranks) - # this will map the measured miller indices to their index in the LBFGS parameter array self.x - self.idx_from_asu = {h: i for i, h in enumerate(set(self.Hi_asu_all_ranks))} - # we will need the inverse map during refinement to update the miller array in diffBragg, so we cache it here - self.asu_from_idx = {i: h for i, h in enumerate(set(self.Hi_asu_all_ranks))} + # TODO: I think this code does absolutely nothing, but might be useful (it was used for B-factor modeling, and maybe more..) + # fres = marr_unique_h.d_spacings() + # self.res_from_asu = {h: res for h, res in zip(fres.indices(), fres.data())} + # TODO: End of code I think does absolutely nothing - self.num_hkl_global = len(self.idx_from_asu) + def get_first_modeller_symmetry(self): + uc = next(iter(self.Modelers.values())).ucell_man + params = uc.a, uc.b, uc.c, uc.al * 180 / np.pi, uc.be * 180 / np.pi, uc.ga * 180 / np.pi + if self.params.refiner.force_unit_cell is not None: + params = self.params.refiner.force_unit_cell + return crystal.symmetry(unit_cell=params, space_group_symbol=self.symbol) - fres = marr_unique_h.d_spacings() - self.res_from_asu = {h: res for h, res in zip(fres.indices(), fres.data())} - - def _get_unique_Hi(self): - COMM.barrier() + def _get_unique_Hi(self, Hi_asu_all_ranks): if COMM.rank == 0: - from cctbx.crystal import symmetry - from cctbx import miller from cctbx.array_family import flex as cctbx_flex - ii = list(self.Modelers.keys())[0] - uc = self.Modelers[ii].ucell_man - params = uc.a, uc.b, uc.c, uc.al * 180 / np.pi, uc.be * 180 / np.pi, uc.ga * 180 / np.pi - if self.params.refiner.force_unit_cell is not None: - params = self.params.refiner.force_unit_cell - symm = symmetry(unit_cell=params, space_group_symbol=self.symbol) - hi_asu_flex = cctbx_flex.miller_index(self.Hi_asu_all_ranks) + symm = self.get_first_modeller_symmetry() + hi_asu_flex = cctbx_flex.miller_index(Hi_asu_all_ranks) mset = miller.set(symm, hi_asu_flex, anomalous_flag=True) marr = miller.array(mset) binner = marr.setup_binner(d_max=self.params.refiner.stage_two.d_max, d_min=self.params.refiner.stage_two.d_min, n_bins=self.params.refiner.stage_two.n_bin) - from collections import Counter print("Average multiplicities:") print("<><><><><><><><><><><><>") for i_bin in range(self.params.refiner.stage_two.n_bin - 1): @@ -462,15 +451,15 @@ def _get_unique_Hi(self): print("\t %d refls with multi %d" % (sum(multi_in_bin == ii), ii)) print("Overall completeness\n<><><><><><><><>") - symm = symmetry(unit_cell=params, space_group_symbol=self.symbol) - hi_flex_unique = cctbx_flex.miller_index(list(set(self.Hi_asu_all_ranks))) + unique_Hi_asu = set(Hi_asu_all_ranks) + hi_flex_unique = cctbx_flex.miller_index(list(unique_Hi_asu)) mset = miller.set(symm, hi_flex_unique, anomalous_flag=True) self.binner = mset.setup_binner(d_min=self.params.refiner.stage_two.d_min, d_max=self.params.refiner.stage_two.d_max, n_bins=self.params.refiner.stage_two.n_bin) mset.completeness(use_binning=True).show() marr_unique_h = miller.array(mset) - print("Rank %d: total miller vars=%d" % (COMM.rank, len(set(self.Hi_asu_all_ranks)))) + print("Rank %d: total miller vars=%d" % (COMM.rank, len(unique_Hi_asu))) else: marr_unique_h = None @@ -486,6 +475,7 @@ def _launch(self): x_init = None nmacro = self.params.refiner.num_macro_cycles n_trials = len(self.params.refiner.max_calls) + for i_trial in range(n_trials*nmacro): self.RUC = StageTwoRefiner(self.Modelers, self.symbol, self.params) @@ -511,8 +501,7 @@ def _launch(self): self.RUC.log_fcells = True self.RUC.request_diag_once = False self.RUC.trad_conv = True - self.RUC.idx_from_asu = self.idx_from_asu - self.RUC.asu_from_idx = self.asu_from_idx + self.RUC.hiasu = self.hiasu self.RUC.S = self.SIM self.RUC.restart_file = self.params.refiner.io.restart_file @@ -527,7 +516,9 @@ def _launch(self): self.RUC.S.update_nanoBragg_instance('verbose', self.params.refiner.verbose) LOGGER.info("_launch run setup") + LOGGER.info(utils.memory_report('Mem usage before _setup')) self.RUC.run(setup_only=True) + LOGGER.info(utils.memory_report('Mem usage after _setup')) LOGGER.info("_launch done run setup") # for debug purposes: #if not self.params.refiner.quiet: @@ -552,9 +543,10 @@ def _launch(self): # more_sel_flags[i_shot] = [flag1 and flag2 for flag1,flag2 in zip(sel_flags, res_flags)] # self.RUC.selection_flags = more_sel_flags - LOGGER.info("_launcher runno setup") + LOGGER.info("_launcher running optimization") + self.RUC.run(setup=False) - LOGGER.info("_launcher done runno setup") + LOGGER.info("_launcher done running optimization") if self.RUC.hit_break_to_use_curvatures: self.RUC.fix_params_with_negative_curvature = False self.RUC.num_positive_curvatures = 0 @@ -576,8 +568,81 @@ def _launch(self): if self.params.profile: self.RUC.S.D.show_timings(self.RUC.rank) - if os.environ.get("DIFFBRAGG_USE_CUDA") is not None: + if os.environ.get("DIFFBRAGG_USE_CUDA") is not None or os.environ.get("DIFFBRAGG_USE_KOKKOS") is not None: self.RUC.S.D.gpu_free() def will_refine(self, param): return param is not None and any(param) + + +class HiAsu(object): + """ + Object which stores possible & present Miller Indices, their counts, + counters, maps between them and their integer indexes etc. + + Within `HiAsu`, the following notation is used for parameter names: + * no trailing `_`: global parameter - total or the same for all ranks. + * with trailing `_`: local parameter – value is unique for each rank. + Example: `counts_` would be specific to rank, but `counts` would be global. + """ + def __init__(self, refine_launcher): + self.rl = refine_launcher + self.possible = self.get_possible() + self.possible_len = len(self.possible) + self.possible_counts = self.get_counts() + self.present_len = len(list(self.present_zip)) + self.from_idx, self.to_idx = self._get_dicts() + + def get_possible(self): + if COMM.rank == 0: + sym = self.rl.get_first_modeller_symmetry() + res_ranges_str = self.rl.params.refiner.res_ranges + if res_ranges_str: + res_ranges = utils.parse_reso_string(res_ranges_str) + d_min = min([d_min for d_min, _ in res_ranges]) + else: + expt = next(iter(self.rl.Modelers.values())).E + det, s0 = expt.detector, expt.beam.get_s0() + d_min = min([p.get_max_resolution_at_corners(s0) for p in det]) + d_min *= 0.8 # accommodate variations in uc or det across expts + mset_full = sym.build_miller_set(anomalous_flag=True, d_min=d_min) + possible = list(mset_full.indices()) + else: + possible = None + return COMM.bcast(possible, root=0) + + def get_counts(self): + hi_asu_ = chain.from_iterable(self.rl.Hi_asu.values()) + hi_asu_counter_ = Counter(hi_asu_) + hi_asu_possible_counts_ = [hi_asu_counter_[k] for k in self.possible] + hi_asu_possible_counts_ = np.array(hi_asu_possible_counts_, dtype=np.uint16) + hi_asu_possible_counts = np.zeros_like(hi_asu_possible_counts_, dtype=np.uint16) + COMM.Allreduce(hi_asu_possible_counts_, hi_asu_possible_counts, op=MPI.SUM) + return hi_asu_possible_counts + + @property + def present(self): + return (p for p, c in self.present_zip) + + @property + def present_counts(self): + return (c for p, c in self.present_zip) + + @property + def present_counter(self): + return Counter({p: c for p, c in self.present_zip}) + + @property + def present_idx_counter(self): + return Counter({self.to_idx[p]: c for p, c in self.present_zip}) + + @property + def present_zip(self): + return ((p, c) for p, c in zip(self.possible, self.possible_counts) if c) + + def _get_dicts(self): + """from_idx maps miller indices to index in LBFGS par. array self.x; + to_ids is an inverse map during refinement to update diffBragg m.arr""" + from_idx = {i: h for i, h in enumerate(self.present)} + to_idx = {h: i for i, h in enumerate(self.present)} + return from_idx, to_idx diff --git a/simtbx/diffBragg/hopper_ensemble_utils.py b/simtbx/diffBragg/hopper_ensemble_utils.py index 0eba59a7c3..f15f608d10 100644 --- a/simtbx/diffBragg/hopper_ensemble_utils.py +++ b/simtbx/diffBragg/hopper_ensemble_utils.py @@ -15,7 +15,6 @@ from cctbx import miller, crystal, sgtbx from dials.array_family import flex from dxtbx.model import ExperimentList -from xfel.merging.application.utils.memory_usage import get_memory_usage COMM = MPI.COMM_WORLD @@ -80,9 +79,12 @@ def __call__(self, x, *args, **kwargs): min_info = "it=%d | t/it=%.4fs | F=%10.7g | sigZ=%10.7g" \ % (self.niter,self.ave_t_per_iter, f, ave_zscore_sig) if COMM.rank==0: - print(min_info, flush=True) + #print(min_info, flush=True) + MAIN_LOGGER.info(min_info) if modelers.save_freq is not None and self.niter % modelers.save_freq == 0: modelers.save_up(self.x0, ref_iter=self.niter) + if modelers.SIM.D.record_timings: + modelers.SIM.D.show_timings() return f @@ -106,12 +108,13 @@ def target_func(x, modelers): g_fhkl = np.zeros(num_fhkl_params) zscore_sigs = [] fcell_params = x[-num_fhkl_params:] - for i_shot in modelers: + for ii, i_shot in enumerate(modelers): shot_modeler = modelers[i_shot] shot_x_slice = modelers.x_slices[i_shot] per_shot_params = x[shot_x_slice] x_for_shot = np.hstack((per_shot_params, fcell_params)) - model_bragg, Jac = hopper_utils.model(x_for_shot, shot_modeler, modelers.SIM, compute_grad=True, update_spectrum=True) + model_bragg, Jac = hopper_utils.model(x_for_shot, shot_modeler, modelers.SIM, compute_grad=True, update_spectrum=True, + update_Fhkl_scales=ii==0) model_pix = model_bragg + shot_modeler.all_background @@ -367,6 +370,8 @@ def prep_for_refinement(self): self._set_mtz_data() self.set_device_id() + + def alloc_max_pix_per_shot(self): self._mpi_set_allocation_volume() def _get_fhkl_vary_flags(self): @@ -387,10 +392,13 @@ def _get_fhkl_vary_flags(self): all_nominal_hkl = set() for mod in self.data_modelers.values(): all_nominal_hkl = all_nominal_hkl.union(mod.hi_asu_perpix) + #TODO : is this memory intensive? all_nominal_hkl = COMM.gather(all_nominal_hkl) if COMM.rank == 0: + # TODO: all_nominal_hkl is P1, asu_map_int is non-P1 all_nominal_hkl = set(all_nominal_hkl[0]).union(*all_nominal_hkl[1:]) - asu_inds_to_vary = [self.SIM.asu_map_int[h] for h in all_nominal_hkl] + all_nominal_hkl_sym = utils.map_hkl_list(all_nominal_hkl, True, self.SIM.crystal.symbol) + asu_inds_to_vary = [self.SIM.asu_map_int[h] for h in all_nominal_hkl_sym] else: asu_inds_to_vary = None asu_inds_to_vary = set(COMM.bcast(asu_inds_to_vary)) @@ -564,13 +572,6 @@ def save_up(self, x, ref_iter=None): mod.params.tag = temp -def mem_usage(rank): - if COMM.rank == rank: - memMB = get_memory_usage() - host = socket.gethostname() - MAIN_LOGGER.info("Rank %d reporting memory usage: %f GB on Rank 0 node %s" % (COMM.rank, memMB / 1e3, host)) - - def get_gather_name(exper_name, gather_dir): gathered_name = os.path.splitext(os.path.basename(exper_name))[0] gathered_name += "_withData.refl" @@ -579,9 +580,10 @@ def get_gather_name(exper_name, gather_dir): def load_inputs(pandas_table, params, exper_key="exp_name", refls_key='predictions', - gather_dir=None): + gather_dir=None, exper_idx_key="exp_idx"): - work_distribution = prep_dataframe(pandas_table, refls_key) + work_distribution = prep_dataframe(pandas_table, refls_key, + res_ranges_string=params.refiner.res_ranges) COMM.barrier() num_exp = len(pandas_table) first_exper_file = pandas_table[exper_key].values[0] @@ -600,7 +602,9 @@ def load_inputs(pandas_table, params, exper_key="exp_name", refls_key='predictio % (COMM.size, num_exp, num_exp)) exper_names = pandas_table[exper_key] - assert len(exper_names) == len(set(exper_names)) + exper_ids = pandas_table[exper_idx_key] + name_ids = list(zip(exper_names, exper_ids)) + assert len(name_ids) == len(set(name_ids)) worklist = work_distribution[COMM.rank] MAIN_LOGGER.info("EVENT: begin loading inputs") @@ -609,20 +613,22 @@ def load_inputs(pandas_table, params, exper_key="exp_name", refls_key='predictio Fhkl_model = Fhkl_model.expand_to_p1().generate_bijvoet_mates() Fhkl_model_indices = set(Fhkl_model.indices()) shot_modelers = hopper_ensemble_utils.DataModelers() - for ii, i_exp in enumerate(worklist): - exper_name = exper_names[i_exp] + for ii, i_df in enumerate(worklist): + exper_name = exper_names[i_df] + exper_id = int(exper_ids[i_df]) MAIN_LOGGER.info("EVENT: BEGIN loading experiment list") - expt_list = ExperimentList.from_file(exper_name, check_format=params.refiner.check_expt_format) + check_format = not params.refiner.load_data_from_refl + expt = hopper_utils.DataModeler.exper_json_single_file(exper_name, exper_id, check_format) + expt_list = ExperimentList() + expt_list.append(expt) MAIN_LOGGER.info("EVENT: DONE loading experiment list") - if len(expt_list) != 1: - MAIN_LOGGER.critical("Input experiments need to have length 1, %s does not" % exper_name) - expt = expt_list[0] expt.detector = detector # in case of supplied ref geom - exper_dataframe = pandas_table.query("%s=='%s'" % (exper_key, exper_name)) + exper_dataframe = pandas_table.query("%s=='%s'" % (exper_key, exper_name)).query("%s==%d" % (exper_idx_key, exper_id)) refl_name = exper_dataframe[refls_key].values[0] refls = flex.reflection_table.from_file(refl_name) + refls = refls.select(refls['id'] == exper_id) miller_inds = list( refls['miller_index']) is_not_000 = [h != (0, 0, 0) for h in miller_inds] @@ -632,7 +638,7 @@ def load_inputs(pandas_table, params, exper_key="exp_name", refls_key='predictio refls = refls.select(refl_sel) exp_cry_sym = expt.crystal.get_space_group().type().lookup_symbol() - if exp_cry_sym.replace(" ", "") != params.space_group: + if params.space_group is not None and exp_cry_sym.replace(" ", "") != params.space_group: gr = sgtbx.space_group_info(params.space_group).group() expt.crystal.set_space_group(gr) #raise ValueError("Crystals should all have the same space group symmetry") @@ -640,6 +646,7 @@ def load_inputs(pandas_table, params, exper_key="exp_name", refls_key='predictio MAIN_LOGGER.info("EVENT: LOADING ROI DATA") shot_modeler = hopper_utils.DataModeler(params) shot_modeler.exper_name = exper_name + shot_modeler.exper_idx = exper_id shot_modeler.refl_name = refl_name shot_modeler.rank = COMM.rank if params.refiner.load_data_from_refl: @@ -678,13 +685,13 @@ def load_inputs(pandas_table, params, exper_key="exp_name", refls_key='predictio continue shot_modeler.set_parameters_for_experiment(best=exper_dataframe) - shot_modeler.set_spectrum() + shot_modeler.set_spectrum(spectra_file=exper_dataframe.spectrum_filename.values[0]) MAIN_LOGGER.info("Will simulate %d energy channels" % len(shot_modeler.nanoBragg_beam_spectrum)) # verify this shot_modeler.Umatrices = [shot_modeler.E.crystal.get_U()] - mem_usage(0) + MAIN_LOGGER.info(utils.memory_report('Rank 0 reporting memory usage')) if COMM.rank==0: print("Finished loading image %d / %d" % (ii + 1, len(worklist)), flush=True) diff --git a/simtbx/diffBragg/hopper_io.py b/simtbx/diffBragg/hopper_io.py index da9316e37e..5285c68de1 100644 --- a/simtbx/diffBragg/hopper_io.py +++ b/simtbx/diffBragg/hopper_io.py @@ -9,7 +9,7 @@ import numpy as np -def save_expt_refl_file(filename, expts, refls, specs=None, check_exists=False): +def save_expt_refl_file(filename, expts, refls, specs=None, check_exists=False, indices=None): """ Save an input file for bg_and_probOri (the EMC initializer script) expt and refl names will be given absolute paths @@ -18,12 +18,15 @@ def save_expt_refl_file(filename, expts, refls, specs=None, check_exists=False): :param refls: list of reflection tables :param specs: optional list of spectrum .lam files :param check_exists: ensure files actually exist + :param indices: experiment indices if multiple images per experiment :return: """ if specs is None: specs = [None]*len(expts) + if indices is None: + indices = [None] *len(indices) with open(filename, "w") as o: - for expt, refl, spec in zip(expts, refls, specs): + for expt, refl, spec, idx in zip(expts, refls, specs, indices): expt = os.path.abspath(expt) refl = os.path.abspath(refl) if spec is not None: @@ -33,10 +36,15 @@ def save_expt_refl_file(filename, expts, refls, specs=None, check_exists=False): assert os.path.exists(refl) if spec is not None: assert os.path.exists(spec) - if spec is not None: - o.write("%s %s %s\n" % (expt, refl, spec)) + if spec is None: + spec = "" + else: + spec = " %s" %spec + if idx is None: + idx = "" else: - o.write("%s %s\n" % (expt, refl)) + idx = " %d" % idx + o.write("%s %s%s%s\n" % (expt, refl, spec, idx)) def make_rank_outdir(root, subfolder, rank=0): @@ -59,11 +67,31 @@ def diffBragg_Umat(rotX, rotY, rotZ, U): return U -def save_to_pandas(x, Mod, SIM, orig_exp_name, params, expt, rank_exp_idx, stg1_refls, stg1_img_path, - rank=0): +def save_to_pandas(x, Mod, SIM, orig_exp_name, params, expt, rank_exp_idx, stg1_refls, stg1_img_path=None, + rank=0, write_expt=True, write_pandas=True, exp_idx=0): + """ + + :param x: the optiized parameters used by hopper (output of Minimize) + :param Mod: the instance of the hopper_utils.DataModeler that was used by hopper + :param SIM: the instance of nanoBragg/sim_data.SimData that was used by hopper + :param orig_exp_name: the name of the experiment list that was input to hopper + :param params: the diffBragg hopper parameters + :param expt: the data modeler experiment + :param rank_exp_idx: order this shot was processed by this MPI rank #TODO rename this + :param stg1_refls: path to the refls that were input to hopper + :param stg1_img_path: leave as None, no longer used + :param rank: MPI rank + :param write_expt: whether to write the single shot experiment + :param write_pandas: whether to write the single shot dataframe + :param exp_idx: the index of the experiment within the experiment list (orig_exp_name) + :return: the single shot dataframe + """ LOGGER = logging.getLogger("refine") - rank_exper_outdir = make_rank_outdir(params.outdir, "expers",rank) - rank_pandas_outdir = make_rank_outdir(params.outdir, "pandas",rank) + opt_exp_path = None + basename = os.path.splitext(os.path.basename(orig_exp_name))[0] + if write_expt: + rank_exper_outdir = make_rank_outdir(params.outdir, "expers",rank) + opt_exp_path = os.path.join(rank_exper_outdir, "%s_%s_%d.expt" % (params.tag, basename, rank_exp_idx)) scale, rotX, rotY, rotZ, Na, Nb, Nc, Nd, Ne, Nf,\ diff_gam_a, diff_gam_b, diff_gam_c, diff_sig_a, \ @@ -109,9 +137,6 @@ def save_to_pandas(x, Mod, SIM, orig_exp_name, params, expt, rank_exp_idx, stg1_ rotY_xt = par['rotY'] rotZ_xt = par['rotZ'] U_xt = diffBragg_Umat(rotX_xt, rotY_xt, rotZ_xt, SIM.Umatrices[i_xtal]) - #cryst_temp = deepcopy(new_cryst) - #cryst_temp.set_U(U_xt) - #Amat_xt = cryst_temp.get_A() other_Umats.append(U_xt) other_spotscales.append(scale_xt) @@ -128,9 +153,6 @@ def save_to_pandas(x, Mod, SIM, orig_exp_name, params, expt, rank_exp_idx, stg1_ lam_coefs.append([val]) lam_coefs = tuple(lam_coefs) - basename = os.path.splitext(os.path.basename(orig_exp_name))[0] - opt_exp_path = os.path.join(rank_exper_outdir, "%s_%s_%d.expt" % (params.tag, basename, rank_exp_idx)) - pandas_path = os.path.join(rank_pandas_outdir, "%s_%s_%d.pkl" % (params.tag, basename, rank_exp_idx)) new_expt = Experiment() new_expt.crystal = new_cryst new_expt.detector = expt.detector @@ -140,8 +162,9 @@ def save_to_pandas(x, Mod, SIM, orig_exp_name, params, expt, rank_exp_idx, stg1_ # expt.detector = refiner.get_optimized_detector() new_exp_list = ExperimentList() new_exp_list.append(new_expt) - new_exp_list.as_file(opt_exp_path) - LOGGER.debug("saved opt_exp %s with wavelength %f" % (opt_exp_path, expt.beam.get_wavelength())) + if write_expt: + new_exp_list.as_file(opt_exp_path) + LOGGER.debug("saved opt_exp %s with wavelength %f" % (opt_exp_path, expt.beam.get_wavelength())) _,flux_vals = zip(*SIM.beam.spectrum) df = single_expt_pandas(xtal_scale=scale, Amat=Amat, @@ -166,14 +189,21 @@ def save_to_pandas(x, Mod, SIM, orig_exp_name, params, expt, rank_exp_idx, stg1_ opt_det=params.opt_det, stg1_refls=stg1_refls, stg1_img_path=stg1_img_path, ncells_init=Nabc_init, spot_scales_init=scale_init, - other_Umats = other_Umats, other_spotscales = other_spotscales) + other_Umats = other_Umats, other_spotscales = other_spotscales, + num_mosaicity_samples=params.simulator.crystal.num_mosaicity_samples) + + df['exp_idx'] = exp_idx + if hasattr(Mod, "sigz"): df['sigz'] = [Mod.sigz] if hasattr(Mod, "niter"): df['niter'] = [Mod.niter] df['phi_deg'] = SIM.D.phi_deg df['osc_deg'] = SIM.D.osc_deg - df.to_pickle(pandas_path) + if write_pandas: + rank_pandas_outdir = make_rank_outdir(params.outdir, "pandas",rank) + pandas_path = os.path.join(rank_pandas_outdir, "%s_%s_%d.pkl" % (params.tag, basename, rank_exp_idx)) + df.to_pickle(pandas_path) return df @@ -183,7 +213,7 @@ def single_expt_pandas(xtal_scale, Amat, ncells_abc, ncells_def, eta_abc, spec_file, spec_stride,flux, beamsize_mm, orig_exp_name, opt_exp_name, spec_from_imageset, oversample, opt_det, stg1_refls, stg1_img_path, ncells_init=None, spot_scales_init = None, - other_Umats=None, other_spotscales=None): + other_Umats=None, other_spotscales=None, num_mosaicity_samples=None): """ :param xtal_scale: @@ -212,6 +242,7 @@ def single_expt_pandas(xtal_scale, Amat, ncells_abc, ncells_def, eta_abc, :param opt_det: :param stg1_refls: :param stg1_img_path: + :num_mosaicity_samples: :return: """ if other_Umats is None: @@ -253,11 +284,16 @@ def single_expt_pandas(xtal_scale, Amat, ncells_abc, ncells_def, eta_abc, df["other_spotscales"] = [tuple(other_spotscales)] if other_Umats: df["other_Umats"] = [tuple(map(tuple, other_Umats))] + if num_mosaicity_samples is not None: + df['num_mosaicity_samples'] = num_mosaicity_samples df["total_flux"] = flux df["beamsize_mm"] = beamsize_mm df["exp_name"] = os.path.abspath(orig_exp_name) - df["opt_exp_name"] = os.path.abspath(opt_exp_name) + + if opt_exp_name is not None: + opt_exp_name = os.path.abspath(opt_exp_name) + df["opt_exp_name"] = opt_exp_name df["spectrum_from_imageset"] = spec_from_imageset df["oversample"] = oversample if opt_det is not None: diff --git a/simtbx/diffBragg/hopper_utils.py b/simtbx/diffBragg/hopper_utils.py index 1b29754898..5acd3ced80 100644 --- a/simtbx/diffBragg/hopper_utils.py +++ b/simtbx/diffBragg/hopper_utils.py @@ -1,6 +1,7 @@ from __future__ import absolute_import, division, print_function import time import os +import json from dials.algorithms.shoebox import MaskCode from copy import deepcopy from dials.model.data import Shoebox @@ -14,7 +15,10 @@ from scipy.ndimage import binary_dilation from dxtbx.model.experiment_list import ExperimentListFactory from dxtbx.model import Spectrum -from serialtbx.detector.jungfrau import get_pedestalRMS_from_jungfrau +try: # TODO keep backwards compatibility until we close the nxmx_writer_experimental branch + from serialtbx.detector.jungfrau import get_pedestalRMS_from_jungfrau +except ModuleNotFoundError: + from xfel.util.jungfrau import get_pedestalRMS_from_jungfrau from simtbx.nanoBragg.utils import downsample_spectrum from dials.array_family import flex from simtbx.diffBragg import utils @@ -137,6 +141,8 @@ def __init__(self, params): self.all_freq = None # flag for the h,k,l frequency of the observed pixel self.best_model = None # best model value at each pixel self.best_model_includes_background = False # whether the best model includes the background scattering estimate + self.all_nominal_hkl_p1 = None # nominal p1 hkl at each pixel + self.all_nominal_hkl = None # nominal hkl at each pixel self.all_data =None # data at each pixel (photon units) self.all_sigma_rdout = None # this is either a float or an array. if the phil param use_perpixel_dark_rms=True, then these are different per pixel, per shot self.all_gain = None # gain value per pixel (used during diffBragg/refiners/stage_two_refiner) @@ -146,6 +152,7 @@ def __init__(self, params): self.all_fast =None # fast-scan coordinate per pixel self.all_slow =None # slow-scan coordinate per pixel self.all_pid = None # panel id per pixel + self.all_zscore = None # the estimated z-score values for each pixel, updated each iteration in the Target class self.rois=None # region of interest (per spot) self.pids=None # panel id (per spot) self.tilt_abc=None # background plane constants (per spot), a,b are fast,slow scan components, c is offset @@ -158,6 +165,7 @@ def __init__(self, params): self.exper_name = None # optional name specifying where dxtbx.model.Experiment was loaded from self.refl_name = None # optional name specifying where dials.array_family.flex.reflection_table refls were loaded from self.spec_name = None # optional name specifying spectrum file(.lam) + self.exper_idx = 0 # optional number specifying the index of the experiment in the experiment list self.rank = 0 # in case DataModelers are part of an MPI program, have a rank attribute for record keeping self.Hi = None # miller index (P1) @@ -171,6 +179,49 @@ def __init__(self, params): "Hi", "Hi_asu", "roi_id", "params", "all_pid", "all_fast", "all_slow", "best_model_includes_background", "all_q_perpix", "all_sigma_rdout"] + def filter_pixels(self, thresh): + assert self.roi_id is not None + assert self.all_trusted is not None + assert self.all_zscore is not None + + if not hasattr(self, 'roi_id_slices') or self.roi_id_slices is None: + self.set_slices('roi_id') + + ntrust = self.all_trusted.sum() + + sigz_per_shoebox = [] + for roi_id in self.roi_id_unique: + slcs = self.roi_id_slices[roi_id] + Zs = [] + for slc in slcs: + trusted = self.all_trusted[slc] + Zs += list(self.all_zscore[slc][trusted]) + if not Zs: + sigz = np.nan + else: + sigz = np.std(Zs) + sigz_per_shoebox.append(sigz) + if np.all(np.isnan(sigz_per_shoebox)): + MAIN_LOGGER.debug("All shoeboxes are nan, nothing to filter") + return + med_sigz = np.median([sigz for sigz in sigz_per_shoebox if not np.isnan(sigz)]) + sigz_per_shoebox = np.nan_to_num(sigz_per_shoebox, nan=med_sigz) + shoebox_is_bad = utils.is_outlier(sigz_per_shoebox, thresh) + nbad_pix = 0 + for i_roi, roi_id in enumerate(self.roi_id_unique): + if shoebox_is_bad[i_roi]: + for slc in self.roi_id_slices[roi_id]: + nbad_pix += slc.stop - slc.start + self.all_trusted[slc] = False + + #inds = np.arange(len(self.all_trusted)) + #Zs = self.all_zscore[self.all_trusted] + #bad = utils.is_outlier(Zs, thresh=thresh) + #inds_trusted = inds[self.all_trusted] + #self.all_trusted[inds_trusted[bad]] = False + MAIN_LOGGER.debug("Added %d pixels from %d shoeboxes to the untrusted list (%d / %d trusted pixels remain)" + % (nbad_pix, shoebox_is_bad.sum(), self.all_trusted.sum(), len(self.all_trusted))) + def set_spectrum(self, spectra_file=None, spectra_stride=None, total_flux=None): # note , the following 3 settings will only be used if spectrum_from_imageset is False and gause_spec is False @@ -211,11 +262,11 @@ def at_minimum(self, x, f, accept): #self.target.minima.append((f,self.target.x0,accept)) self.target.lowest_x = x try: - # TODO get SIM and i_exp in here so we can save_up each new global minima! + # TODO get SIM and i_shot in here so we can save_up each new global minima! if f < self.target.lowest_f: self.target.lowest_f = f MAIN_LOGGER.info("New minimum found!") - self.save_up(self.target.x0, SIM, self.rank, i_exp=i_exp) + self.save_up(self.target.x0, SIM, self.rank, i_shot=i_shot) except NameError: pass @@ -275,9 +326,48 @@ def sigma_rdout(self): def clean_up(self, SIM): free_SIM_mem(SIM) - def set_experiment(self, exp, load_imageset=True): + @staticmethod + def exper_json_single_file(exp_file, i_exp=0, check_format=True): + """ + load a single experiment from an exp_file + If working with large combined experiment files, we only want to load + one image at a time on each MPI rank, otherwise at least one rank would need to + load the entire file into memory. + :param exp_file: experiment list file + :param i_exp: experiment id + :param check_format: bool, verifies the format class of the experiment, set to False if loading data from refls + :return: + """ + exper_json = json.load(open(exp_file)) + nexper = len(exper_json["experiment"]) + assert 0 <= i_exp < nexper + + this_exper = exper_json["experiment"][i_exp] + + new_json = {'__id__': "ExperimentList", "experiment": [deepcopy(this_exper)]} + + for model in ['beam', 'detector', 'crystal', 'imageset', 'profile', 'scan', 'goniometer', 'scaling_model']: + if model in this_exper: + model_index = this_exper[model] + new_json[model] = [exper_json[model][model_index]] + new_json["experiment"][0][model] = 0 + else: + new_json[model] = [] + explist = ExperimentListFactory.from_dict(new_json, check_format=check_format) + assert len(explist) == 1 + return explist[0] + + def set_experiment(self, exp, load_imageset=True, exp_idx=0): + """ + :param exp: experiment or filename + :param load_imageset: whether to load the imageset (usually True) + :param exp_idx: index corresponding to experiment in experiment list + """ if isinstance(exp, str): - self.E = ExperimentListFactory.from_json_file(exp, load_imageset)[0] + if not load_imageset: + self.E = ExperimentListFactory.from_json_file(exp, False)[exp_idx] + else: + self.E = self.exper_json_single_file(exp, exp_idx) else: self.E = exp if self.params.opt_det is not None: @@ -290,9 +380,15 @@ def set_experiment(self, exp, load_imageset=True): self.E.beam = opt_beam_E.beam MAIN_LOGGER.info("Set the optimal beam from %s" % self.params.opt_beam) - def load_refls(self, ref): + def load_refls(self, ref, exp_idx=0): + """ + :param ref: reflection table or filename + :param exp_idx: index corresponding to experiment in experiment list + """ if isinstance(ref, str): refls = flex.reflection_table.from_file(ref) + # TODO: is this the proper way to select the id ? + refls = refls.select(refls['id']==exp_idx) else: # assert is a reflection table. .. refls = ref @@ -311,6 +407,7 @@ def is_duplicate_hkl(self, refls): return is_duplicate def GatherFromReflectionTable(self, exp, ref, sg_symbol=None): + self.set_experiment(exp, load_imageset=False) self.refls = self.load_refls(ref) nref = len(self.refls) @@ -360,7 +457,8 @@ def GatherFromReflectionTable(self, exp, ref, sg_symbol=None): else: sb_trust = np.logical_or(mask==fg_code, mask==bg_code) - below_zero = sb_bkgrnd <= 0 + # below_zero = sb_bkgrnd <= 0 + below_zero = sb_bkgrnd < 0 if np.any(below_zero): nbelow = np.sum(below_zero) ntot = sb_bkgrnd.size @@ -390,10 +488,19 @@ def GatherFromReflectionTable(self, exp, ref, sg_symbol=None): self.data_to_one_dim(img_data, is_trusted, background) return True - def GatherFromExperiment(self, exp, ref, remove_duplicate_hkl=True, sg_symbol=None): - self.set_experiment(exp, load_imageset=True) + def GatherFromExperiment(self, exp, ref, remove_duplicate_hkl=True, sg_symbol=None, exp_idx=0): + """ + + :param exp: experiment list filename , or experiment object + :param ref: reflection table filename, or reflection table instance + :param remove_duplicate_hkl: search for miller index duplicates and remove + :param sg_symbol: space group lookup symbol P43212 + :param exp_idx: index of the experiment in the experiment list + :return: + """ + self.set_experiment(exp, load_imageset=True, exp_idx=exp_idx) - refls = self.load_refls(ref) + refls = self.load_refls(ref, exp_idx=exp_idx) if len(refls)==0: MAIN_LOGGER.warning("no refls loaded!") return False @@ -471,6 +578,9 @@ def GatherFromExperiment(self, exp, ref, remove_duplicate_hkl=True, sg_symbol=No self.tilt_abc = [abc for i_roi, abc in enumerate(self.tilt_abc) if self.selection_flags[i_roi]] self.pids = [pid for i_roi, pid in enumerate(self.pids) if self.selection_flags[i_roi]] self.tilt_cov = [cov for i_roi, cov in enumerate(self.tilt_cov) if self.selection_flags[i_roi]] + self.Hi =[hi for i_roi, hi in enumerate(self.Hi) if self.selection_flags[i_roi]] + self.Hi_asu =[hi_asu for i_roi, hi_asu in enumerate(self.Hi_asu) if self.selection_flags[i_roi]] + if not self.no_rlp_info: self.Q = [np.linalg.norm(refls[i_roi]["rlp"]) for i_roi in range(len(refls)) if self.selection_flags[i_roi]] @@ -560,8 +670,10 @@ def data_to_one_dim(self, img_data, is_trusted, background): if not self.no_rlp_info: all_q_perpix += [self.Q[i_roi]]*npix if self.Hi is not None: - self.all_nominal_hkl += [tuple(self.Hi[self.refls_idx[i_roi]])]*npix - self.hi_asu_perpix += [self.Hi_asu[self.refls_idx[i_roi]]] * npix + self.all_nominal_hkl += [tuple(self.Hi[i_roi])]*npix + self.hi_asu_perpix += [self.Hi_asu[i_roi]] * npix + #self.all_nominal_hkl += [tuple(self.Hi[i_roi])]*npix + #self.hi_asu_perpix += [self.Hi_asu[i_roi]] * npix if self.params.roi.mask_outside_trusted_range: MAIN_LOGGER.debug("Found %d pixels outside of trusted range" % numOutOfRange) @@ -640,37 +752,32 @@ def dump_gathered_to_refl(self, output_name, do_xyobs_sanity_check=False): shoeboxes.append(sb) R['shoebox'] = flex.shoebox(shoeboxes) + R['id'] = flex.int(len(R), 0) R.as_file(output_name) def set_parameters_for_experiment(self, best=None): + if self.params.symmetrize_Flatt and not self.params.fix.eta_abc: + if not self.params.simulator.crystal.has_isotropic_mosaicity: + raise NotImplementedError("if fix.eta_abc=False and symmetrize_Flatt=True, then eta must be isotropic. Set simulator.crystal.has_isotropic_mosaicity=True") ParameterTypes = {"ranged": RangedParameter, "positive": PositiveParameter} ParameterType = RangedParameter # most params currently only this type + if self.params.centers.Nvol is not None: + assert self.params.betas.Nvol is not None + if best is not None: # set the crystal Umat (rotational displacement) and Bmat (unit cell) # Umatrix # NOTE: just set the best Amatrix here - if self.params.apply_best_crystal_model: - xax = col((-1, 0, 0)) - yax = col((0, -1, 0)) - zax = col((0, 0, -1)) - rotX, rotY, rotZ = best[["rotX", "rotY", "rotZ"]].values[0] - RX = xax.axis_and_angle_as_r3_rotation_matrix(rotX, deg=False) - RY = yax.axis_and_angle_as_r3_rotation_matrix(rotY, deg=False) - RZ = zax.axis_and_angle_as_r3_rotation_matrix(rotZ, deg=False) - M = RX * RY * RZ - U = M * sqr(self.E.crystal.get_U()) - self.E.crystal.set_U(U) - - # Bmatrix: - ucparam = best[["a","b","c","al","be","ga"]].values[0] - ucman = utils.manager_from_params(ucparam) - self.E.crystal.set_B(ucman.B_recipspace) + #C = deepcopy(self.E.crystal) + #crystal = self.E.crystal + #self.E.crystal = crystal ## TODO , currently need this anyway ucparam = best[["a","b","c","al","be","ga"]].values[0] ucman = utils.manager_from_params(ucparam) self.E.crystal.set_B(ucman.B_recipspace) + self.E.crystal.set_A(best.Amats.values[0]) # mosaic block self.params.init.Nabc = tuple(best.ncells.values[0]) @@ -693,9 +800,6 @@ def set_parameters_for_experiment(self, best=None): maxs = self.params.maxs centers = self.params.centers betas = self.params.betas - if not self.params.use_restraints or self.params.fix.ucell: - centers.ucell = [1,1,1,1,1,1] - betas.ucell = [1,1,1,1,1,1] fix = self.params.fix types = self.params.types P = Parameters() @@ -707,7 +811,8 @@ def set_parameters_for_experiment(self, best=None): p = ParameterType(init=0, sigma=sigma.RotXYZ[ii], minval=mins.RotXYZ[ii], maxval=maxs.RotXYZ[ii], fix=fix.RotXYZ, name="RotXYZ%d_xtal%d" % (ii,i_xtal), - center=centers.RotXYZ[ii], beta=betas.RotXYZ) + center=0 if betas.RotXYZ is not None else None, + beta=betas.RotXYZ) P.add(p) p = ParameterTypes[types.G](init=init.G + init.G*0.01*i_xtal, sigma=sigma.G, @@ -746,33 +851,38 @@ def set_parameters_for_experiment(self, best=None): p = ParameterTypes[types.Nabc](init=init.Nabc[ii], sigma=sigma.Nabc[ii], minval=mins.Nabc[ii], maxval=maxs.Nabc[ii], fix=fix_Nabc[ii], name="Nabc%d" % (ii,), - center=centers.Nabc[ii], beta=betas.Nabc[ii]) + center=centers.Nabc[ii] if centers.Nabc is not None else None, + beta=betas.Nabc[ii] if betas.Nabc is not None else None) P.add(p) p = ParameterType(init=init.Ndef[ii], sigma=sigma.Ndef[ii], minval=mins.Ndef[ii], maxval=maxs.Ndef[ii], fix=fix.Ndef, name="Ndef%d" % (ii,), - center=centers.Ndef[ii], beta=betas.Ndef[ii]) + center=centers.Ndef[ii] if centers.Ndef is not None else None, + beta=betas.Ndef[ii] if betas.Ndef is not None else None) P.add(p) # diffuse gamma and sigma p = ParameterTypes[types.diffuse_gamma](init=init.diffuse_gamma[ii], sigma=sigma.diffuse_gamma[ii], minval=mins.diffuse_gamma[ii], maxval=maxs.diffuse_gamma[ii], fix=fix_difgam[ii], name="diffuse_gamma%d" % (ii,), - center=centers.diffuse_gamma[ii], beta=betas.diffuse_gamma[ii]) + center=centers.diffuse_gamma[ii] if centers.diffuse_gamma is not None else None, + beta=betas.diffuse_gamma[ii] if betas.diffuse_gamma is not None else None) P.add(p) p = ParameterTypes[types.diffuse_sigma](init=init.diffuse_sigma[ii], sigma=sigma.diffuse_sigma[ii], minval=mins.diffuse_sigma[ii], maxval=maxs.diffuse_sigma[ii], fix=fix_difsig[ii], name="diffuse_sigma%d" % (ii,), - center=centers.diffuse_sigma[ii], beta=betas.diffuse_sigma[ii]) + center=centers.diffuse_sigma[ii] if centers.diffuse_sigma is not None else None, + beta=betas.diffuse_sigma[ii] if betas.diffuse_sigma is not None else None) P.add(p) # mosaic spread (mosaicity) p = ParameterType(init=init.eta_abc[ii], sigma=sigma.eta_abc[ii], minval=mins.eta_abc[ii], maxval=maxs.eta_abc[ii], fix=fix_eta[ii], name="eta_abc%d" % (ii,), - center=centers.eta_abc[ii], beta=betas.eta_abc[ii]) + center=centers.eta_abc[ii] if centers.eta_abc is not None else None, + beta=betas.eta_abc[ii] if betas.eta_abc is not None else None) P.add(p) ucell_man = utils.manager_from_crystal(self.E.crystal) @@ -781,40 +891,29 @@ def set_parameters_for_experiment(self, best=None): if "Ang" in name: minval = val - ucell_vary_perc * val maxval = val + ucell_vary_perc * val - if centers.ucell is not None: - cent = centers.ucell[i_uc] - beta = betas.ucell[i_uc] + if name == 'a_Ang': + cent = centers.ucell_a + beta = betas.ucell_a + elif name== 'b_Ang': + cent = centers.ucell_b + beta = betas.ucell_b else: - if name == 'a_Ang': - cent = centers.ucell_a - beta = betas.ucell_a - elif name== 'b_Ang': - cent = centers.ucell_b - beta = betas.ucell_b - else: - cent = centers.ucell_c - beta = betas.ucell_c - assert cent is not None, "Set the center restraints properly!" - assert beta is not None + cent = centers.ucell_c + beta = betas.ucell_c else: val_in_deg = val * 180 / np.pi minval = (val_in_deg - self.params.ucell_ang_abs) * np.pi / 180. maxval = (val_in_deg + self.params.ucell_ang_abs) * np.pi / 180. - if centers.ucell is not None: - cent = centers.ucell[i_uc]*np.pi / 180. - beta = betas.ucell[i_uc] + if name=='alpha_rad': + cent = centers.ucell_alpha + beta = betas.ucell_alpha + elif name=='beta_rad': + cent = centers.ucell_beta + beta = betas.ucell_beta else: - if name=='alpha_rad': - cent = centers.ucell_alpha - beta = betas.ucell_alpha - elif name=='beta_rad': - cent = centers.ucell_beta - beta = betas.ucell_beta - else: - cent = centers.ucell_gamma - beta = betas.ucell_gamma - assert cent is not None - assert beta is not None + cent = centers.ucell_gamma + beta = betas.ucell_gamma + if cent is not None: cent = cent*np.pi / 180. p = ParameterType(init=val, sigma=sigma.ucell[i_uc], @@ -860,11 +959,13 @@ def set_parameters_for_experiment(self, best=None): # two parameters for optimizing the spectrum p = RangedParameter(init=self.params.init.spec[0], sigma=self.params.sigmas.spec[0], minval=mins.spec[0], maxval=maxs.spec[0], fix=fix.spec, - name="lambda_offset", center=centers.spec[0], beta=betas.spec[0]) + name="lambda_offset", center=centers.spec[0] if centers.spec is not None else None, + beta=betas.spec[0] if betas.spec is not None else None) P.add(p) p = RangedParameter(init=self.params.init.spec[1], sigma=self.params.sigmas.spec[1], minval=mins.spec[1], maxval=maxs.spec[1], fix=fix.spec, - name="lambda_scale", center=centers.spec[1], beta=betas.spec[1]) + name="lambda_scale", center=centers.spec[1] if centers.spec is not None else None, + beta=betas.spec[1] if betas.spec is not None else None) P.add(p) # iterating over this dict is time-consuming when refinine Fhkl, so we split up the names here: @@ -872,6 +973,11 @@ def set_parameters_for_experiment(self, best=None): self.scale_roi_names = [name for name in P if name.startswith("scale_roi")] self.P = P + for name in self.P: + p = self.P[name] + if (p.beta is not None and p.center is None) or (p.center is not None and p.beta is None): + raise RuntimeError("To use restraints, must specify both center and beta for param %s" % name) + def get_data_model_pairs(self, reorder=False): if self.best_model is None: raise ValueError("cannot get the best model, there is no best_model attribute") @@ -923,7 +1029,7 @@ def get_data_model_pairs(self, reorder=False): return ret_subimgs - def Minimize(self, x0, SIM, i_exp=0): + def Minimize(self, x0, SIM, i_shot=0): self.target = target = TargetFunc(SIM=SIM, niter_per_J=self.params.niter_per_J, profile=self.params.profile) # set up the refinement flags @@ -957,7 +1063,7 @@ def Minimize(self, x0, SIM, i_exp=0): assert self.params.hopper_save_freq is None at_min = self.at_minimum - callback_kwargs = {"SIM":SIM, "i_exp": i_exp, "save_freq": self.params.hopper_save_freq} + callback_kwargs = {"SIM":SIM, "i_shot": i_shot, "save_freq": self.params.hopper_save_freq} callback = lambda x: self.callback(x, callback_kwargs) target.terminate_after_n_converged_iterations = self.params.terminate_after_n_converged_iter target.percent_change_of_converged = self.params.converged_param_percent_change @@ -1035,13 +1141,13 @@ def Minimize(self, x0, SIM, i_exp=0): def callback(self, x, kwargs): save_freq = kwargs["save_freq"] - i_exp = kwargs["i_exp"] + i_shot = kwargs["i_shot"] SIM = kwargs["SIM"] target = self.target if save_freq is not None and target.iteration % save_freq==0 and target.iteration> 0: xall = target.x0.copy() xall[target.vary] = x - self.save_up(xall, SIM, rank=self.rank, i_exp=i_exp) + self.save_up(xall, SIM, rank=self.rank, i_shot=i_shot) return rescaled_vals = np.zeros_like(xall) @@ -1094,30 +1200,34 @@ def callback(self, x, kwargs): # at this point prev_iter_vals are the converged parameters! raise StopIteration() # Refinement has reached convergence! - def save_up(self, x, SIM, rank=0, i_exp=0, + def save_up(self, x, SIM, rank=0, i_shot=0, save_fhkl_data=True, save_modeler_file=True, save_refl=True, - save_sim_info=True): + save_sim_info=True, + save_traces=True, + save_pandas=True, save_expt=True): """ - :param x: - :param SIM: - :param rank: - :param i_exp: - :param save_fhkl_data: - :param save_modeler_file: - :param save_refl: - :param save_sim_info: - :return: + :param x: l-bfgs refinement parameters (reparameterized, e.g. unbounded) + :param SIM: sim_data.SimData instance + :param rank: MPI rank Id + :param i_shot: shot index for this rank (assuming each rank processes more than one shot, this should increment) + :param save_fhkl_data: whether to write mtz files + :param save_modeler_file: whether to write the DataModeler .npy file (a pickle file) + :param save_refl: whether to write a reflection table for this shot with updated xyzcal.px from diffBragg models + :param save_sim_info: whether to write a text file showing the diffBragg state + :param save_traces: whether to write a text file showing the refinement target functional and sigmaZ per iter + :param save_pandas: whether to write a single-shot pandas dataframe containing optimized diffBragg params + :param save_expt: whether to save a single-shot experiment file for this shot with optimized crystal model + :return: returns the single shot pandas dataframe (whether or not it was written) """ - # TODO optionally create directories assert self.exper_name is not None assert self.refl_name is not None Modeler = self LOGGER = logging.getLogger("refine") Modeler.best_model, _ = model(x, Modeler, SIM, compute_grad=False) Modeler.best_model_includes_background = False - LOGGER.info("Optimized values for i_exp %d:" % i_exp) + LOGGER.info("Optimized values for i_shot %d:" % i_shot) basename = os.path.splitext(os.path.basename(self.exper_name))[0] @@ -1170,26 +1280,30 @@ def save_up(self, x, SIM, rank=0, i_exp=0, scale_facs.append(scale_fac) scale_vars.append(scale_var) is_nominal_hkl.append(asu in all_nominal_hkl) - scale_fname = os.path.join(fhkl_scale_dir, "%s_%s_%d_channel%d_scale.npz"\ - % (Modeler.params.tag, basename, i_exp, i_chan)) + scale_fname = os.path.join(fhkl_scale_dir, "%s_%s_%d_%d_channel%d_scale.npz"\ + % (Modeler.params.tag, basename, i_shot, self.exper_idx, i_chan)) np.savez(scale_fname, asu_hkl=asu_hkls, scale_fac=scale_facs, scale_var=scale_vars, is_nominal_hkl=is_nominal_hkl) # TODO: pretty formatting ? if Modeler.target is not None: - rank_trace_outdir = hopper_io.make_rank_outdir(Modeler.params.outdir, "traces", rank) - trace_path = os.path.join(rank_trace_outdir, "%s_%s_%d_traces.txt" % (Modeler.params.tag, basename, i_exp)) # hop number, gradient descent index (resets with each new hop), target functional trace0, trace1, trace2 = Modeler.target.all_hop_id, Modeler.target.all_f, Modeler.target.all_sigZ - trace_data = np.array([trace0, trace1, trace2]).T - np.savetxt(trace_path, trace_data, fmt="%s") + + if save_traces: + rank_trace_outdir = hopper_io.make_rank_outdir(Modeler.params.outdir, "traces", rank) + trace_path = os.path.join(rank_trace_outdir, "%s_%s_%d_%d_traces.txt" + % (Modeler.params.tag, basename, i_shot, self.exper_idx)) + np.savetxt(trace_path, trace_data, fmt="%s") Modeler.niter = len(trace0) Modeler.sigz = trace2[-1] - hopper_io.save_to_pandas(x, Modeler, SIM, self.exper_name, Modeler.params, Modeler.E, i_exp, self.refl_name, None, rank) + shot_df = hopper_io.save_to_pandas(x, Modeler, SIM, self.exper_name, Modeler.params, Modeler.E, i_shot, + self.refl_name, None, rank, write_expt=save_expt, write_pandas=save_pandas, + exp_idx=self.exper_idx) if isinstance(Modeler.all_sigma_rdout, np.ndarray): data_subimg, model_subimg, trusted_subimg, bragg_subimg, sigma_rdout_subimg = Modeler.get_data_model_pairs() @@ -1208,7 +1322,8 @@ def save_up(self, x, SIM, rank=0, i_exp=0, if save_refl: rank_refls_outdir = hopper_io.make_rank_outdir(Modeler.params.outdir, "refls", rank) - new_refls_file = os.path.join(rank_refls_outdir, "%s_%s_%d.refl" % (Modeler.params.tag, basename, i_exp)) + new_refls_file = os.path.join(rank_refls_outdir, "%s_%s_%d_%d.refl" + % (Modeler.params.tag, basename, i_shot, self.exper_idx)) new_refls = deepcopy(Modeler.refls) has_xyzcal = 'xyzcal.px' in list(new_refls.keys()) if has_xyzcal: @@ -1268,19 +1383,24 @@ def save_up(self, x, SIM, rank=0, i_exp=0, if save_modeler_file: rank_imgs_outdir = hopper_io.make_rank_outdir(Modeler.params.outdir, "imgs", rank) modeler_file = os.path.join(rank_imgs_outdir, - "%s_%s_%d_modeler.npy" % (Modeler.params.tag, basename, i_exp)) + "%s_%s_%d_%d_modeler.npy" + % (Modeler.params.tag, basename, i_shot, self.exper_idx)) np.save(modeler_file, Modeler) if save_sim_info: spectrum_file = os.path.join(rank_imgs_outdir, - "%s_%s_%d_spectra.lam" % (Modeler.params.tag, basename, i_exp)) + "%s_%s_%d_%d_spectra.lam" + % (Modeler.params.tag, basename, i_shot, self.exper_idx)) rank_SIMlog_outdir = hopper_io.make_rank_outdir(Modeler.params.outdir, "simulator_state", rank) - SIMlog_path = os.path.join(rank_SIMlog_outdir, "%s_%s_%d.txt" % (Modeler.params.tag, basename, i_exp)) + SIMlog_path = os.path.join(rank_SIMlog_outdir, "%s_%s_%d_%d.txt" + % (Modeler.params.tag, basename, i_shot, self.exper_idx)) write_SIM_logs(SIM, log=SIMlog_path, lam=spectrum_file) if Modeler.params.refiner.debug_pixel_panelfastslow is not None: # TODO separate diffBragg logger utils.show_diffBragg_state(SIM.D, Modeler.params.refiner.debug_pixel_panelfastslow) + return shot_df + def convolve_model_with_psf(model_pix, J, mod, SIM, PSF=None, psf_args=None, roi_id_slices=None, roi_id_unique=None): @@ -1339,7 +1459,24 @@ def convolve_model_with_psf(model_pix, J, mod, SIM, PSF=None, psf_args=None, return model_pix, J -def model(x, Mod, SIM, compute_grad=True, dont_rescale_gradient=False, update_spectrum=False): +def model(x, Mod, SIM, compute_grad=True, dont_rescale_gradient=False, update_spectrum=False, + update_Fhkl_scales=True): + + if Mod.params.logging.parameters: + val_s = "" + for p in Mod.P.values(): + if p.name.startswith("Fhkl_"): + continue + if p.refine: + xval = x[p.xpos] + val = p.get_val(xval) + name = p.name + if name == "detz_shift": + val = val * 1e3 + name = p.name + "_mm" + val_s += "%s=%.3f, " % (name, val) + MAIN_LOGGER.debug(val_s) + pfs = Mod.pan_fast_slow @@ -1351,7 +1488,7 @@ def model(x, Mod, SIM, compute_grad=True, dont_rescale_gradient=False, update_s if Mod.Fhkl_channel_ids is not None: SIM.D.update_Fhkl_channels(Mod.Fhkl_channel_ids) - if SIM.refining_Fhkl: # once per iteration + if SIM.refining_Fhkl and update_Fhkl_scales: # once per iteration nscales = SIM.Num_ASU*SIM.num_Fhkl_channels current_Fhkl_xvals = x[-nscales:] SIM.Fhkl_scales = SIM.Fhkl_scales_init * np.exp( Mod.params.sigmas.Fhkl *(current_Fhkl_xvals-1)) @@ -1436,6 +1573,7 @@ def model(x, Mod, SIM, compute_grad=True, dont_rescale_gradient=False, update_s J = np.zeros((nparam-SIM.Num_ASU*SIM.num_Fhkl_channels, npix)) # gradients model_pix = None + #TODO check roiScales mode and if its broken, git rid of it! model_pix_noRoi = None # extract the scale factors per ROI, these might correspond to structure factor intensity scale factors, and quite possibly might result in overfits! @@ -1462,6 +1600,16 @@ def model(x, Mod, SIM, compute_grad=True, dont_rescale_gradient=False, update_s SIM.D.set_value(ROTY_ID, rotY) SIM.D.set_value(ROTZ_ID, rotZ) + if Mod.params.symmetrize_Flatt: + RXYZU = hopper_io.diffBragg_Umat(rotX, rotY, rotZ, SIM.D.Umatrix) + Cryst = deepcopy(SIM.crystal.dxtbx_crystal) + A = RXYZU * Mod.ucell_man.B_realspace + A_recip = A.inverse().transpose() + Cryst.set_A(A_recip) + symbol = SIM.crystal.space_group_info.type().lookup_symbol() + SIM.D.set_mosaic_blocks_sym(Cryst, symbol , Mod.params.simulator.crystal.num_mosaicity_samples, + refining_eta=not Mod.params.fix.eta_abc) + G = Mod.P["G_xtal%d" % i_xtal] scale = G.get_val(x[G.xpos]) @@ -1663,7 +1811,15 @@ def __call__(self, x, *args, **kwargs): self.all_x.append(self.x0) mod, SIM, compute_grad = args - f, g, modelpix, J, sigZ, debug_s = target_func(self.x0, update_terms, mod, SIM, compute_grad) + f, g, modelpix, J, sigZ, debug_s, zscore_perpix = target_func(self.x0, update_terms, mod, SIM, compute_grad, + return_all_zscores=True) + mod.all_zscore = zscore_perpix + + # filter during refinement? + if mod.params.filter_during_refinement.enable and self.iteration > 0: + if self.iteration % mod.params.filter_during_refinement.after_n == 0: + mod.filter_pixels(thresh=mod.params.filter_during_refinement.threshold) + self.t_per_iter.append(time.time()) if len(self.t_per_iter) > 2: @@ -1683,7 +1839,7 @@ def __call__(self, x, *args, **kwargs): return f -def target_func(x, udpate_terms, mod, SIM, compute_grad=True): +def target_func(x, udpate_terms, mod, SIM, compute_grad=True, return_all_zscores=False): pfs = mod.pan_fast_slow data = mod.all_data sigma_rdout = mod.all_sigma_rdout @@ -1757,15 +1913,17 @@ def target_func(x, udpate_terms, mod, SIM, compute_grad=True): fLogLike = fLogLike[trusted].sum() # negative log Likelihood target # width of z-score should decrease as refinement proceeds - zscore_sigma = np.std( (resid / np.sqrt(V))[trusted]) + zscore_per = resid/np.sqrt(V) + zscore_sigma = np.std(zscore_per[trusted]) restraint_terms = {} if params.use_restraints: # scale factor restraint for name in mod.non_fhkl_params: p = mod.P[name] - val = p.get_restraint_val(x[p.xpos]) - restraint_terms[name] = val + if p.beta is not None: + val = p.get_restraint_val(x[p.xpos]) + restraint_terms[name] = val if params.centers.Nvol is not None: na,nb,nc = SIM.D.Ncells_abc_aniso @@ -1833,14 +1991,16 @@ def target_func(x, udpate_terms, mod, SIM, compute_grad=True): # update gradients according to restraints for name in mod.non_fhkl_params: p = mod.P[name] - g[p.xpos] += p.get_restraint_deriv(x[p.xpos]) + if p.beta is not None: + g[p.xpos] += p.get_restraint_deriv(x[p.xpos]) - if not params.fix.perRoiScale: + if not params.fix.perRoiScale: # deprecated ? for name in mod.scale_roi_names: p = mod.P[name] - g[p.xpos] += p.get_restraint_deriv(x[p.xpos]) + if p.beta is not None: + g[p.xpos] += p.get_restraint_deriv(x[p.xpos]) - if params.centers.Nvol is not None: + if params.betas.Nvol is not None: Nmat_inv = np.linalg.inv(Nmat) dVol_dN_vals = [] for i_N in range(6): @@ -1900,7 +2060,11 @@ def target_func(x, udpate_terms, mod, SIM, compute_grad=True): debug_s = "F=%10.7g sigZ=%10.7g (Fracs of F: %s), |g|=%10.7g" \ % (f, zscore_sigma, restraint_debug_s, gnorm) - return f, g, model_bragg, Jac, zscore_sigma, debug_s + + return_data = f, g, model_bragg, Jac, zscore_sigma, debug_s + if return_all_zscores: + return_data += (zscore_per,) + return return_data def refine(exp, ref, params, spec=None, gpu_device=None, return_modeler=False, best=None, free_mem=True): @@ -2117,13 +2281,30 @@ def generate_gauss_spec(central_en=9500, fwhm=10, res=1, nchan=20, total_flux=1e else: return ens, wt +def downsamp_spec_from_params(params, expt=None, imgset=None, i_img=0): + """ + + :param params: hopper phil params extracted + :param expt: a dxtbx experiment (optional) + :param imgset: an dxtbx imageset (optional) + :param i_img: index of the image in the imageset (only matters if imgset is not None) + :return: dxtbx spectrum with parameters applied + """ + if expt is not None: + dxtbx_spec = expt.imageset.get_spectrum(0) + starting_wave = expt.beam.get_wavelength() + else: + assert imgset is not None + dxtbx_spec = imgset.get_spectrum(i_img) + starting_wave = imgset.get_beam(i_img).get_wavelength() -def downsamp_spec_from_params(params, expt): - dxtbx_spec = expt.imageset.get_spectrum(0) spec_en = dxtbx_spec.get_energies_eV() spec_wt = dxtbx_spec.get_weights() if params.downsamp_spec.skip: spec_wave = utils.ENERGY_CONV / spec_en.as_numpy_array() + stride=params.simulator.spectrum.stride + spec_wave = spec_wave[::stride] + spec_wt = spec_wt[::stride] spectrum = list(zip(spec_wave, spec_wt)) else: spec_en = dxtbx_spec.get_energies_eV() @@ -2149,11 +2330,12 @@ def downsamp_spec_from_params(params, expt): downsamp_wave = utils.ENERGY_CONV / downsamp_en spectrum = list(zip(downsamp_wave, downsamp_wt)) # the nanoBragg beam has an xray_beams property that is used internally in diffBragg - starting_wave = expt.beam.get_wavelength() waves, specs = map(np.array, zip(*spectrum)) ave_wave = sum(waves*specs) / sum(specs) - expt.beam.set_wavelength(ave_wave) - MAIN_LOGGER.debug("Shifting wavelength from %f to %f" % (starting_wave, ave_wave)) + MAIN_LOGGER.debug("Starting wavelength=%f. Spectrum ave wavelength=%f" % (starting_wave, ave_wave)) + if expt is not None: + expt.beam.set_wavelength(ave_wave) + MAIN_LOGGER.debug("Shifting expt wavelength from %f to %f" % (starting_wave, ave_wave)) MAIN_LOGGER.debug("USING %d ENERGY CHANNELS" % len(spectrum)) return spectrum @@ -2165,6 +2347,9 @@ def downsamp_spec(SIM, params, expt, return_and_dont_set=False): spec_wt = SIM.dxtbx_spec.get_weights() if params.downsamp_spec.skip: spec_wave = utils.ENERGY_CONV / spec_en.as_numpy_array() + stride = params.simulator.spectrum.stride + spec_wave = spec_wave[::stride] + spec_wt = spec_wt[::stride] SIM.beam.spectrum = list(zip(spec_wave, spec_wt)) else: spec_en = SIM.dxtbx_spec.get_energies_eV() @@ -2195,6 +2380,7 @@ def downsamp_spec(SIM, params, expt, return_and_dont_set=False): ave_wave = sum(waves*specs) / sum(specs) expt.beam.set_wavelength(ave_wave) MAIN_LOGGER.debug("Shifting wavelength from %f to %f" % (starting_wave, ave_wave)) + MAIN_LOGGER.debug("Using %d energy channels" % len(SIM.beam.spectrum)) if return_and_dont_set: return SIM.beam.spectrum else: @@ -2234,12 +2420,12 @@ def set_gauss_spec(SIM=None, params=None, E=None): def sanity_test_input_lines(input_lines): for line in input_lines: - line_fields = line.strip().split() - if len(line_fields) not in [2, 3]: + line_items = line.strip().split() + if len(line_items) not in [2, 3, 4]: raise IOError("Input line %s is not formatted properly" % line) - for fname in line_fields: - if not os.path.exists(fname): - raise FileNotFoundError("File %s does not exist" % fname) + for item in line_items: + if os.path.isfile(item) and not os.path.exists(item): + raise FileNotFoundError("File %s does not exist" % item) def full_img_pfs(img_sh): @@ -2304,10 +2490,19 @@ def get_simulator_for_data_modelers(data_modeler): if self.params.diffuse_stencil_size > 0: SIM.D.stencil_size = self.params.diffuse_stencil_size MAIN_LOGGER.debug("Set diffuse stencil size: %d" % SIM.D.stencil_size) + if self.params.diffuse_orientation == 1: + ori = (1,0,0,0,1,0,0,0,1) + else: + a = 1/np.sqrt(2) + ori = a, a, 0.0, a, a, 0.0, 0.0, 0.0, 1.0 + SIM.D.set_rotate_principal_axes(ori) SIM.D.gamma_miller_units = self.params.gamma_miller_units SIM.isotropic_diffuse_gamma = self.params.isotropic.diffuse_gamma SIM.isotropic_diffuse_sigma = self.params.isotropic.diffuse_sigma + if self.params.record_device_timings: + SIM.D.record_timings = True + # TODO: use data_modeler.set_spectrum instead if self.params.spectrum_from_imageset: downsamp_spec(SIM, self.params, self.E) elif self.params.gen_gauss_spec: diff --git a/simtbx/diffBragg/mpi_logger.py b/simtbx/diffBragg/mpi_logger.py index 8900ea8d54..c81cffd4d9 100644 --- a/simtbx/diffBragg/mpi_logger.py +++ b/simtbx/diffBragg/mpi_logger.py @@ -20,7 +20,7 @@ LEVELS = {"low": logging.WARNING, "normal": logging.INFO, "high": logging.DEBUG} DETAILED_FORMAT = 'RANK%d:%s | ' % (COMM.rank, HOST) + '%(asctime)s | %(filename)s:%(funcName)s >> %(message)s' -SIMPLE_FORMAT = "RANK%04d "%(COMM.rank)+"%(message)s" +SIMPLE_FORMAT = "RANK%04d "%(COMM.rank)+"| %(asctime)s | %(message)s" from simtbx.diffBragg import utils @@ -61,14 +61,16 @@ def setup_logging_from_params(params): utils.safe_makedirs(params.outdir) COMM.barrier() main_level = LEVELS[params.logging.logfiles_level] + logfile_name = params.logging.log_hostname*(HOST+"-") + params.logging.logname main_logger = _make_logger("diffBragg.main", - os.path.join(params.outdir, HOST+"-"+params.logging.logname), + os.path.join(params.outdir, logfile_name), level=main_level, overwrite=params.logging.overwrite, formatter=logging.Formatter(DETAILED_FORMAT)) + profile_name = params.logging.log_hostname*(HOST+"-") + params.profile_name _make_logger("diffBragg.profile", - os.path.join(params.outdir, HOST+"-"+params.profile_name), + os.path.join(params.outdir, profile_name), level=logging.INFO, overwrite=params.logging.overwrite, formatter=logging.Formatter(SIMPLE_FORMAT)) diff --git a/simtbx/diffBragg/phil.py b/simtbx/diffBragg/phil.py index 806780f47c..b6558f77fb 100644 --- a/simtbx/diffBragg/phil.py +++ b/simtbx/diffBragg/phil.py @@ -6,6 +6,53 @@ #''' hopper_phil = """ + +filter_during_refinement { + enable = False + .type = bool + .help = if True, filtering will occur each N iterations, controlled by parameter after_n + after_n = 50 + .type = int + .help = refiner will pause and check for outliers every after_n iterations + threshold = 20 + .type = float + .help = outliers are detected by looking at the distribution of per shoebox sigmaZ + .help = and then using a median absolute deviation filter. Lower values of threshold will flag more pixels as outliers +} + +filter_after_refinement { + enable = False + .type = bool + .help = if True, filter, then rerun refinement if certain conditions are met (e.g. too few refinement iterations) + max_attempts = 2 + .type = int + .help = how many additional times to run hopper + min_prev_niter = 50 + .type = int + .help = only repeat if the previous refinement was fewer than this many iterations + max_prev_sigz = 10 + .type = float + .help = only repeat if the previous refinement had sigma Z more than this + threshold = 20 + .type = float + .help = outliers are detected by looking at the distribution of per shoebox sigmaZ + .help = and then using a median absolute deviation filter. Lower values of threshold will flag more pixels as outliers +} + +symmetrize_Flatt = False + .type = bool + .help = If True, add 3-fold symmetric mosaic blocks to the calculation of F_latt +record_device_timings = False + .type = bool + .help = Record the execution times of diffBragg host-dev copies and kernel executions + .help = the results will be printed to the terminal +consider_multicrystal_shots = False + .type = bool + .help = If True, and if there are multiple crystals in the experiment list, + .help = then try to model all crystals for a given shot. +debug_mode = False + .type = bool + .help = If True, many output files are written to explore the diffBragg models in great detail nominal_Fhkl_only = True .type = bool .help = if refining Fhkls, only refine the ones that are assigned to a reflection table... @@ -121,12 +168,6 @@ .help = final resolution of downsampled spectrum in eV .expert_level=0 } -apply_best_crystal_model = False - .type = bool - .help = depending on what experiments in the exper refl file, one may want - .help = to apply the optimal crystal transformations (this parameter only matters - .help = if params.best_pickle is not None) - .expert_level=10 filter_unpredicted_refls_in_output = True .type = bool .help = filter reflections in the output refl table for which there was no model bragg peak @@ -192,41 +233,41 @@ ucell_gamma = None .type = float .help = restraint variance for unit cell gamma angle - Nvol = 1e8 + Nvol = None .type = float .help = tightness of the Nabc volume contraint - detz_shift = 1e8 + detz_shift = None .type = float .help = restraint variance for detector shift target - ucell = [1e8,1e8,1e8,1e8,1e8,1e8] + ucell = None .type = floats .help = DEPRECATED: use e.g. betas.ucell_a instead .help = variances for unit cell constants in order determined by unit cell manager class (see diffBragg/refiners/crystal_systems) - RotXYZ = 1e8 + RotXYZ = None .type = float .help = restraint factor for the rotXYZ restraint - Nabc = [1e8,1e8,1e8] + Nabc = None .type = floats(size=3) .help = restraint factor for the ncells abc - Ndef = [1e8,1e8,1e8] + Ndef = None .type = floats(size=3) .help = restraint factor for the ncells def - diffuse_sigma = 1e8,1e8,1e8 + diffuse_sigma = None .type = floats(size=3) .help = restraint factor for diffuse sigma - diffuse_gamma = 1e8,1e8,1e8 + diffuse_gamma = None .type = floats(size=3) .help = restraint factor for diffuse gamma - G = 1e8 + G = None .type = float .help = restraint factor for the scale G - B = 1e8 + B = None .type = float .help = restraint factor for Bfactor - eta_abc = [1e8,1e8,1e8] + eta_abc = None .type = floats(size=3) .help = restrain factor for mosaic spread angles - spec = [1e8,1e8] + spec = None .type = floats(size=2) .help = restraint factor for spectrum coefs Fhkl = None @@ -276,38 +317,34 @@ Nvol = None .type = float .help = if provided, constrain the product Na*Nb*Nc to this value - detz_shift = 0 + detz_shift = None .type = float .help = restraint target for detector shift along z-direction - ucell = [63.66, 28.87, 35.86, 1.8425] - .type = floats - .help = DEPRECATED: use e.g. betas.ucell_a instead - .help = centers for unit cell constants in order determined by unit cell manager class (see diffBragg/refiners/crystal_systems) - RotXYZ = [0,0,0] + RotXYZ = None .type = floats(size=3) .help = restraint target for Umat rotations - Nabc = [100,100,100] + Nabc = None .type = floats(size=3) .help = restraint target for Nabc - Ndef = [0,0,0] + Ndef = None .type = floats(size=3) .help = restraint target for Ndef - diffuse_sigma = [1,1,1] + diffuse_sigma = None .type = floats(size=3) .help = restraint target for diffuse sigma - diffuse_gamma = [1,1,1] + diffuse_gamma = None .type = floats(size=3) .help = restraint target for diffuse gamma - G = 100 + G = None .type = float .help = restraint target for scale G - B = 0 + B = None .type = float .help = restraint target for Bfactor - eta_abc = [0,0,0] + eta_abc = None .type = floats(size=3) .help = restraint target for mosaic spread angles in degrees - spec = [0,1] + spec = None .type = floats(size=2) .help = restraint target for specturm correction (0 + 1*Lambda ) } @@ -402,9 +439,9 @@ diffuse_gamma = [1,1,1] .type = floats(size=3) .help = sensitivity for diffuse gamma - RotXYZ = [1,1,1] + RotXYZ = [1e-3,1e-3,1e-3] .type = floats(size=3) - .help = sensitivity for RotXYZ + .help = sensitivity for RotXYZ in radians G = 1 .type = float .help = sensitivity for scale factor @@ -451,7 +488,7 @@ .help = init for diffuse gamma RotXYZ = [0,0,0] .type = floats(size=3) - .help = init for RotXYZ + .help = init for RotXYZ in radians G = 1 .type = float .help = init for scale factor @@ -482,9 +519,9 @@ diffuse_gamma = [0,0,0] .type = floats(size=3) .help = min for diffuse gamma - RotXYZ = [-1,-1,-1] + RotXYZ = [-3.1415926, -3.1415926, -3.1415926] .type = floats(size=3) - .help = min for rotXYZ in degrees + .help = min for rotXYZ in radians G = 0 .type = float .help = min for scale G @@ -520,12 +557,12 @@ diffuse_sigma = [20,20,20] .type = floats(size=3) .help = max diffuse sigma - diffuse_gamma = [1000,1000,1000] + diffuse_gamma = [10000,10000,10000] .type = floats(size=3) .help = max for diffuse gamma - RotXYZ = [1,1,1] + RotXYZ = [3.1415926, 3.1415926, 3.1415926] .type = floats(size=3) - .help = max for rotXYZ in degrees + .help = max for rotXYZ in radians G = 1e12 .type = float .help = max for scale G @@ -582,7 +619,7 @@ ucell = False .type = bool .help = fix the unit cell during refinement - detz_shift = False + detz_shift = True .type = bool .help = fix the detector distance shift during refinement } @@ -611,6 +648,9 @@ .type = int .help = Increase to add accuracy to diffuse scattering models, at the expense of longer computations .help = Best to increment by values of 1 when testing +diffuse_orientation = 1 + .type = int + .help = orient the diffuse scattering features. 0 is along (a-b, a+b, c), 1 is along (a,b,c) symmetrize_diffuse = True .type = bool .help = use the laue group rotation operators to symmetrize diffuse signals @@ -718,6 +758,9 @@ .type = str .help = if logfiles=True, then write the log to this file, stored in the folder specified by outdir .help = if None, then defaults to main_stage1.log for hopper, main_pred.log for prediction, main_stage2.log for stage_two + log_hostname = True + .type = bool + .help = prefix logfiles with host name } profile = False .type = bool diff --git a/simtbx/diffBragg/prep_stage2_input.py b/simtbx/diffBragg/prep_stage2_input.py index 205128234f..2c08657a5c 100644 --- a/simtbx/diffBragg/prep_stage2_input.py +++ b/simtbx/diffBragg/prep_stage2_input.py @@ -4,6 +4,7 @@ import numpy as np from dials.array_family import flex from libtbx.mpi4py import MPI +from simtbx.diffBragg import utils COMM = MPI.COMM_WORLD import logging @@ -27,20 +28,59 @@ def get_equal_partition(weights, partitions): load[lightest] += weights[idx] return distribution -def prep_dataframe(df, refls_key="predictions"): +def prep_dataframe(df, refls_key="predictions", res_ranges_string=None): + """ + + :param df: input pandas dataframe for stage2 + :param refls_key: column in df containing the reflection filenames + :param res_ranges_string: optional res_ranges_string phil param (params.refiner.res_ranges) + :return: + """ # TODO make sure all pred files exist + + res_ranges = None + if res_ranges_string is not None: + res_ranges = utils.parse_reso_string(res_ranges_string) + + if refls_key not in list(df): + raise KeyError("Dataframe has no key %s" % refls_key) nshots = len(df) - refls_names = df[refls_key] + df.reset_index(drop=True, inplace=True) + df['index'] = df.index.values + refl_info = df[["index", refls_key, "exp_idx"]].values + + # sort and split such that each rank will read many refls from same file + sorted_names_and_ids = sorted( + refl_info, + key=lambda x: x[1]) # sort by name + df_idx, refl_names, expt_ids = np.array_split(sorted_names_and_ids, COMM.size)[COMM.rank].T + refls_per_shot = [] if COMM.rank==0: LOGGER.info("Loading nrefls per shot") - for i_shot, name in enumerate(refls_names): - if i_shot % COMM.size != COMM.rank: - continue - R = flex.reflection_table.from_file(name) - if len(R)==0: - LOGGER.critical("Reflection %s has 0 reflections !" % (name, len(R))) - refls_per_shot.append((i_shot, len(R))) + + prev_name = "" # keep track of the most recently read refl table file + Rall = None + for (i_shot, name, expt_id) in zip(df_idx, refl_names, expt_ids): + if Rall is None or name != prev_name: + Rall = flex.reflection_table.from_file(name) + prev_name = name + + R = Rall.select(Rall['id'] == int(expt_id)) + if res_ranges is not None: + num_ref = 0 + if 'rlp' not in set(R.keys()): + raise KeyError("Cannot filter res ranges if rlp column not in refl tables") + d = 1. / np.linalg.norm(R["rlp"], axis=1) # resolution per refl + for d_fine, d_coarse in res_ranges: + d_sel = np.logical_and(d >= d_fine, d < d_coarse) + num_ref += d_sel.sum() + else: + num_ref = len(R) + + if num_ref==0: + LOGGER.critical("Reflection %s id=%d has 0 reflections !" % (name, expt_id, num_ref)) + refls_per_shot.append((i_shot, num_ref)) refls_per_shot = COMM.reduce(refls_per_shot, root=0) work_distribution = None diff --git a/simtbx/diffBragg/refiners/base_refiner.py b/simtbx/diffBragg/refiners/base_refiner.py index c74cd44436..f5179e95fa 100644 --- a/simtbx/diffBragg/refiners/base_refiner.py +++ b/simtbx/diffBragg/refiners/base_refiner.py @@ -210,12 +210,14 @@ def run(self, setup=True, setup_only=False): else: try: self.diag_mode = None + self.minimizer = scitbx.lbfgs.run( target_evaluator=self, core_params=self._core_param, exception_handling_params=self._handler, termination_params=self._terminator, gradient_only=self.gradient_only) + except BreakToUseCurvatures: self.hit_break_to_use_curvatures = True pass diff --git a/simtbx/diffBragg/refiners/stage_two_refiner.py b/simtbx/diffBragg/refiners/stage_two_refiner.py index b877c40f70..3e7beb41fa 100644 --- a/simtbx/diffBragg/refiners/stage_two_refiner.py +++ b/simtbx/diffBragg/refiners/stage_two_refiner.py @@ -11,6 +11,8 @@ import warnings import signal import logging +from copy import deepcopy +from simtbx.diffBragg import hopper_io LOGGER = logging.getLogger("diffBragg.main") warnings.filterwarnings("ignore") @@ -53,7 +55,6 @@ class Bcolors: from simtbx.diffBragg.refiners import BreakBecauseSignal, BreakToUseCurvatures from dials.array_family import flex from simtbx.diffBragg.refiners import BaseRefiner -from collections import Counter from cctbx import miller, sgtbx from simtbx.diffBragg.refiners.parameters import RangedParameter @@ -74,11 +75,10 @@ def __init__(self, shot_modelers, sgsymbol, params): self.save_model_freq = self.params.refiner.stage_two.save_model_freq self.use_nominal_h = self.params.refiner.stage_two.use_nominal_hkl - self.saveZ_freq = self.params.refiner.stage_two.save_Z_freq # save Z-score data every N iterations + self.saveZ_freq = self.params.refiner.stage_two.save_Z_freq # save Z-score data every N function calls self.break_signal = None # check for this signal during refinement, and break refinement if signal is received (see python signal module) TODO: make work with MPI self.save_model = False # whether to save the model - self.idx_from_asu = {} # maps global fcell index to asu hkl - self.asu_from_idx = {} # maps asu hkl to global fcell index + self.hiasu = None # stores Hi_asu, counts, maps to and from fcell indices self.rescale_params = True # whether to rescale parameters during refinement # TODO this will always be true, so remove the ability to disable self.request_diag_once = False # LBFGS refiner property self.min_multiplicity = self.params.refiner.stage_two.min_multiplicity @@ -91,6 +91,7 @@ def __init__(self, shot_modelers, sgsymbol, params): self.use_curvatures_threshold = 7 # how many positive curvature iterations required before breaking, after which simulation can be restart with use_curvatures=True self.verbose = True # whether to print during iterations self.iterations = 0 # iteration counter , used internally + self.target_eval_count = 0 # target function evaluation counter, used internally self.shot_ids = None # for global refinement , self.log2pi = np.log(np.pi*2) @@ -151,7 +152,7 @@ def n(self): @property def n_global_fcell(self): - return len(self.idx_from_asu) + return self.hiasu.present_len @property def image_shape(self): @@ -190,16 +191,20 @@ def make_output_dir(self): self.Zdir = os.path.join(self.output_dir, "Z") self.model_dir = os.path.join(self.output_dir, "model") for dirname in (self.Zdir, self.model_dir): - if self.I_AM_ROOT and not os.path.exists(dirname): + if self.params.debug_mode and self.I_AM_ROOT and not os.path.exists(dirname): os.makedirs(dirname) COMM.barrier() def _setup(self): # Here we go! https://youtu.be/7VvkXA6xpqI + if not self.params.debug_mode: + LOGGER.info("Disabling saveZ and save_model because debug_mode=False") + self.saveZ_freq = None + self.save_model_freq = None LOGGER.info("Setup begins!") - if self.refine_Fcell and not self.asu_from_idx: + if self.refine_Fcell and not self.hiasu.from_idx: raise ValueError("Need to supply a non empty asu from idx map") - if self.refine_Fcell and not self.idx_from_asu: # # TODO just derive from its inverse + if self.refine_Fcell and not self.hiasu.to_idx: raise ValueError("Need to supply a non empty idx from asu map") self.make_output_dir() @@ -240,18 +245,12 @@ def _setup(self): self._setup_ncells_refinement_parameters() self._track_num_times_pixel_was_modeled() - self.hkl_totals = [] - if self.refine_Fcell: - for i_shot in self.shot_ids: - for i_h, h in enumerate(self.Modelers[i_shot].Hi_asu): - self.hkl_totals.append(self.idx_from_asu[h]) - self.hkl_totals = self._MPI_reduce_broadcast(self.hkl_totals) - + self._setup_nominal_hkl_p1() self._MPI_setup_global_params() self._MPI_sync_fcell_parameters() # reduce then broadcast fcell LOGGER.info("--combining parameters across ranks") - self._MPI_sync_hkl_freq() + self._MPI_sync_hkl_freq() # FIXME does this do absolutely anything? if self.x_init is not None: LOGGER.info("Initializing with provided x_init array") @@ -270,7 +269,7 @@ def _setup(self): for sid in self.shot_ids: Modeler = self.Modelers[sid] - Modeler.all_fcell_global_idx = np.array([self.idx_from_asu[h] for h in Modeler.hi_asu_perpix]) + Modeler.all_fcell_global_idx = np.array([self.hiasu.to_idx[h] for h in Modeler.hi_asu_perpix]) Modeler.unique_i_fcell = set(Modeler.all_fcell_global_idx) Modeler.i_fcell_slices = self._get_i_fcell_slices(Modeler) self.Modelers[sid] = Modeler # TODO: VERIFY IF THIS IS NECESSARY ? @@ -349,7 +348,7 @@ def _make_p1_equiv_mapping(self): self.num_equivs_for_i_fcell = {} self.update_indices = [] for i_fcell in range(self.n_global_fcell): - hkl_asu = self.asu_from_idx[i_fcell] + hkl_asu = self.hiasu.from_idx[i_fcell] equivs = [i.h() for i in miller.sym_equiv_indices(self.space_group, hkl_asu).indices()] self.num_equivs_for_i_fcell[i_fcell] = len(equivs) @@ -360,27 +359,45 @@ def _MPI_setup_global_params(self): if self.I_AM_ROOT: LOGGER.info("--2 Setting up global parameters") if self.output_dir is not None: - np.save(os.path.join(self.output_dir, "f_asu_map"), self.asu_from_idx) + np.save(os.path.join(self.output_dir, "f_asu_map"), self.hiasu.from_idx) self._setup_fcell_params() + def _setup_nominal_hkl_p1(self): + Omatrix = np.reshape(self.S.crystal.Omatrix.elems, [3, 3]) + for i_shot in self.Modelers: + MOD = self.Modelers[i_shot] + nom_h = MOD.all_nominal_hkl + nom_h_p1 = np.dot(nom_h, Omatrix).astype(np.int32) + nom_h_p1 = list(map(tuple, nom_h_p1)) + self.Modelers[i_shot].all_nominal_hkl_p1 = nom_h_p1 + def _setup_fcell_params(self): if self.refine_Fcell: LOGGER.info("----loading fcell data") # this is the number of observations of hkl (accessed like a dictionary via global_fcell_index) LOGGER.info("---- -- counting hkl totes") LOGGER.info("compute HKL multiplicity") - self.hkl_frequency = Counter(self.hkl_totals) + self.hkl_frequency = self.hiasu.present_idx_counter LOGGER.info("save HKL multiplicity") np.save(os.path.join(self.output_dir, "f_asu_multi"), self.hkl_frequency) LOGGER.info("Done ") LOGGER.info("local refiner symbol=%s ; nanoBragg crystal symbol: %s" % (self.symbol, self.S.crystal.symbol)) - ma = self.S.crystal.miller_array_high_symmetry.map_to_asu() + self.fcell_init_from_i_fcell = [] + ma = self.S.crystal.miller_array LOGGER.info("make an Fhkl map") ma_map = {h: d for h,d in zip(ma.indices(), ma.data())} - LOGGER.info("make fcell_init") - self.fcell_init_from_i_fcell = np.array([ma_map[self.asu_from_idx[i_fcell]] for i_fcell in range(self.n_global_fcell)]) + Omatrix = np.reshape(self.S.crystal.Omatrix.elems,[3,3]) + + # TODO: Vectorize + for i_fcell in range(self.n_global_fcell): + asu_hkl = self.hiasu.from_idx[i_fcell] # high symmetry + P1_hkl = tuple(np.dot(Omatrix, asu_hkl).astype(int)) + fcell_val = ma_map[P1_hkl] + self.fcell_init_from_i_fcell.append(fcell_val) + self.fcell_init_from_i_fcell = np.array(self.fcell_init_from_i_fcell) + self.fcell_sigmas_from_i_fcell = self.params.sigmas.Fhkl LOGGER.info("DONE make fcell_init") @@ -436,7 +453,9 @@ def _get_ncells_abc(self, i_shot): return vals def _get_eta(self, i_shot): - pass + # NOTE: refinement of eta not supported in this script + vals = [self.Modelers[i_shot].PAR.eta[i_eta].init for i_eta in range(3)] + return vals def _get_spot_scale(self, i_shot): xval = self.x[self.spot_scale_xpos[i_shot]] @@ -465,8 +484,8 @@ def _run_diffBragg_current(self): LOGGER.info("run diffBragg for shot %d" % self._i_shot) pfs = self.Modelers[self._i_shot].pan_fast_slow if self.use_nominal_h: - nom_h = self.Modelers[self._i_shot].all_nominal_hkl - self.D.add_diffBragg_spots(pfs, nom_h) + nom_h_p1 = self.Modelers[self._i_shot].all_nominal_hkl_p1 + self.D.add_diffBragg_spots(pfs, nom_h_p1) else: self.D.add_diffBragg_spots(pfs) LOGGER.info("finished diffBragg for shot %d" % self._i_shot) @@ -506,7 +525,30 @@ def _update_spectra_coefficients(self): pass def _update_eta(self): - pass + + if self.S.umat_maker is not None: + eta_vals = self._get_eta(self._i_shot) + + if not self.D.has_anisotropic_mosaic_spread: + assert self.S.Umats_method == 2 + assert len(set(eta_vals))==1 + eta_vals = eta_vals[0] + + LOGGER.info("eta=%f" % eta_vals) + self.S.update_umats_for_refinement(eta_vals) + + def _symmetrize_Flatt(self): + if self.params.symmetrize_Flatt: + # NOTE: RotXYZ refinement disabled for this script, so offsets always 0,0,0 + RXYZU = hopper_io.diffBragg_Umat(0,0,0,self.D.Umatrix) + Cryst = deepcopy(self.S.crystal.dxtbx_crystal) + B_realspace = self.get_refined_Bmatrix(self._i_shot, recip=False) + A = RXYZU * B_realspace + A_recip = A.inverse().transpose() + Cryst.set_A(A_recip) + symbol = self.S.crystal.space_group_info.type().lookup_symbol() + self.D.set_mosaic_blocks_sym(Cryst, symbol , self.params.simulator.crystal.num_mosaicity_samples, + refining_eta=False) # NOTE:no eta refinement in this stage 2 script (possible in ens.hopper) def _set_background_plane(self): self.tilt_plane = self.Modelers[self._i_shot].all_background[self.roi_sel] @@ -626,11 +668,11 @@ def compute_functional_and_gradients(self): t = time.time() out = self._compute_functional_and_gradients() t = time.time()-t - LOGGER.info("TOok %.4f sec to compute functional and grad" % t) + LOGGER.info("Took %.4f sec to compute functional and grad" % t) return out def _compute_functional_and_gradients(self): - LOGGER.info(Bcolors.OKBLUE+"BEGIN FUNC GRAD ; iteration %d" % self.iterations+Bcolors.ENDC) + LOGGER.info(Bcolors.OKBLUE+"BEGIN FUNC GRAD ; Eval %d" % self.target_eval_count+Bcolors.ENDC) #if self.verbose: # self._print_iteration_header() @@ -654,15 +696,15 @@ def _compute_functional_and_gradients(self): LOGGER.info("Iterate over %d shots" % len(self.shot_ids)) self._shot_Zscores = [] - save_model = self.save_model_freq is not None and self.iterations % self.save_model_freq == 0 + save_model = self.save_model_freq is not None and self.target_eval_count % self.save_model_freq == 0 if save_model: - self._save_model_dir = os.path.join(self.model_dir, "iter%d" % self.iterations) + self._save_model_dir = os.path.join(self.model_dir, "eval%d" % self.target_eval_count) - if COMM.rank == 0 and not os.path.exists(self._save_model_dir): + if self.params.debug_mode and COMM.rank == 0 and not os.path.exists(self._save_model_dir): os.makedirs(self._save_model_dir) COMM.barrier() - if self.iterations % self.params.refiner.save_gain_freq == 0: + if self.target_eval_count % self.params.refiner.save_gain_freq == 0: self._save_optimized_gain_map() self.all_sigZ = [] @@ -684,6 +726,7 @@ def _compute_functional_and_gradients(self): self._update_ncells_def() self._update_rotXYZ() self._update_eta() # mosaic spread + self._symmetrize_Flatt() self._update_dxtbx_detector() self._update_sausages() @@ -702,7 +745,7 @@ def _compute_functional_and_gradients(self): self._derivative_convenience_factors() - if self.iterations % self.saveZ_freq == 0: + if self.saveZ_freq is not None and self.target_eval_count % self.saveZ_freq == 0: MOD = self.Modelers[self._i_shot] self._spot_Zscores = [] for i_fcell in MOD.unique_i_fcell: @@ -772,7 +815,7 @@ def _compute_functional_and_gradients(self): tsave = time.time()-tsave LOGGER.info("Time to dump param and Zscore data: %.4f" % tsave) - self.iterations += 1 + self.target_eval_count += 1 self.f_vals.append(self.target_functional) if self.calc_curvatures and not self.use_curvatures: @@ -782,21 +825,24 @@ def _compute_functional_and_gradients(self): LOGGER.info("DONE WITH FUNC GRAD") return self._f, self._g + def callback_after_step(self, minimizer): + self.iterations = minimizer.iter() + def _save_model(self, model_info): LOGGER.info("SAVING MODEL FOR SHOT %d" % self._i_shot) df = pandas.DataFrame(model_info) df["shot_id"] = self._i_shot outdir = self._save_model_dir - outname = os.path.join(outdir, "rank%d_shot%d_ITER%d.pkl" % (COMM.rank, self._i_shot, self.iterations)) + outname = os.path.join(outdir, "rank%d_shot%d_EVAL%d_ITER%d.pkl" % (COMM.rank, self._i_shot, self.target_eval_count, self.iterations)) df.to_pickle(outname) def _save_Zscore_data(self): - if not self.iterations % self.saveZ_freq == 0: + if self.saveZ_freq is None or not self.target_eval_count % self.saveZ_freq == 0: return outdir = os.path.join(self.Zdir, "rank%d_Zscore" % self.rank) if not os.path.exists(outdir): os.makedirs(outdir) - fname = os.path.join(outdir, "sigZ_iter%d_rank%d" % (self.iterations, self.rank)) + fname = os.path.join(outdir, "sigZ_eval%d_iter%d_rank%d" % (self.target_eval_count, self.iterations, self.rank)) np.save(fname, np.array(self._shot_Zscores, object)) def _sanity_check_grad(self): @@ -827,6 +873,7 @@ def _Fcell_derivatives(self): if not self.refine_Fcell: return MOD = self.Modelers[self._i_shot] + dumps = [] for i_fcell in MOD.unique_i_fcell: multi = self.hkl_frequency[i_fcell] @@ -836,6 +883,7 @@ def _Fcell_derivatives(self): xpos = self.fcell_xstart + i_fcell Famp = self._fcell_at_i_fcell[i_fcell] sig = 1 + for slc in MOD.i_fcell_slices[i_fcell]: self.fcell_dI_dtheta = self.fcell_deriv[slc] @@ -852,7 +900,9 @@ def _Fcell_derivatives(self): trust = MOD.all_trusted[slc] # NOTE : no need to normalize Fhkl gradients by the overlap rate - they should arise from different HKLs #freq = MOD.all_freq[slc] # pixel frequency (1 is no overlaps) - self.grad[xpos] += (g_accum[trust].sum())*.5 + dump = (g_accum[trust].sum())*.5 + self.grad[xpos] += dump + dumps.append(dump) if self.calc_curvatures: raise NotImplementedError("No curvature for Fcell refinement") @@ -985,11 +1035,11 @@ def _print_iteration_header(self): if self.use_curvatures: LOGGER.info( - "%s%s%s%s\nTrial%d (%s): Compute functional and gradients Iter %d %s(Using Curvatures)%s\n%s%s%s%s" - % (Bcolors.HEADER, border,border,border, self.trial_id + 1, refine_str, self.iterations + 1, Bcolors.OKGREEN, Bcolors.HEADER, border,border,border, Bcolors.ENDC)) + "%s%s%s%s\nTrial%d (%s): Compute functional and gradients eval %d %s(Using Curvatures)%s\n%s%s%s%s" + % (Bcolors.HEADER, border,border,border, self.trial_id + 1, refine_str, self.target_eval_count + 1, Bcolors.OKGREEN, Bcolors.HEADER, border,border,border, Bcolors.ENDC)) else: - LOGGER.info("%s%s%s%s\n, Trial%d (%s): Compute functional and gradients Iter %d PosCurva %d\n%s%s%s%s" - % (Bcolors.HEADER, border, border, border, self.trial_id + 1, refine_str, self.iterations + 1, self.num_positive_curvatures, border, border,border, Bcolors.ENDC)) + LOGGER.info("%s%s%s%s\n, Trial%d (%s): Compute functional and gradients eval %d PosCurva %d\n%s%s%s%s" + % (Bcolors.HEADER, border, border, border, self.trial_id + 1, refine_str, self.target_eval_count + 1, self.num_positive_curvatures, border, border,border, Bcolors.ENDC)) def _save_optimized_gain_map(self): if not self.params.refiner.refine_gain_map: @@ -1006,7 +1056,7 @@ def _save_optimized_gain_map(self): def _MPI_save_state_of_refiner(self): if self.I_AM_ROOT and self.output_dir is not None and self.refine_Fcell: - outf = os.path.join(self.output_dir, "_fcell_trial%d_iter%d" % (self.trial_id, self.iterations)) + outf = os.path.join(self.output_dir, "_fcell_trial%d_eval%d_iter%d" % (self.trial_id, self.target_eval_count, self.iterations)) np.savez(outf, fvals=self._fcell_at_i_fcell) def _target_accumulate(self): @@ -1071,8 +1121,11 @@ def _evaluate_log_averageI_plus_sigma_readout(self): self.log_v = np.log(v) self.log_v[v <= 0] = 0 # but will I ever negative_model ? - def get_refined_Bmatrix(self, i_shot): - return self.Modelers[i_shot].PAR.ucell_man.B_recipspace + def get_refined_Bmatrix(self, i_shot, recip=False): + if recip: + return self.Modelers[i_shot].PAR.ucell_man.B_recipspace + else: + return self.Modelers[i_shot].PAR.ucell_man.B_realspace def curvatures(self): return self.curv diff --git a/simtbx/diffBragg/src/diffBragg.cpp b/simtbx/diffBragg/src/diffBragg.cpp index 8d2915db35..f07b7e99c2 100644 --- a/simtbx/diffBragg/src/diffBragg.cpp +++ b/simtbx/diffBragg/src/diffBragg.cpp @@ -537,6 +537,7 @@ void diffBragg::update_dxtbx_geoms( double panel_rot_angS, double panel_offsetX, double panel_offsetY, double panel_offsetZ, bool force){ + db_cu_flags.update_detector = true; int old_verbose = verbose; verbose = 0; @@ -714,12 +715,18 @@ void diffBragg::update_dxtbx_geoms( SCITBX_ASSERT(close_distance > 0); verbose = old_verbose; set_close_distances(); + db_cu_flags.update_panel_deriv_vecs=true; + db_cu_flags.update_detector=true; } void diffBragg::shift_originZ(const dxtbx::model::Detector& detector, double shiftZ){ - for (int pid=0; pid< detector.size(); pid++) - db_det.pix0_vectors[pid*3 + 2] = detector[pid].get_origin()[2]/1000.0 + shiftZ; - set_close_distances(); + if (shiftZ != prev_shiftZ){ + for (int pid=0; pid< detector.size(); pid++) + db_det.pix0_vectors[pid*3 + 2] = detector[pid].get_origin()[2]/1000.0 + shiftZ; + set_close_distances(); + db_cu_flags.update_detector=true; + prev_shiftZ = shiftZ; + } } void diffBragg::init_raw_pixels_roi(){ @@ -749,7 +756,7 @@ void diffBragg::initialize_managers(){ pan_orig = boost::dynamic_pointer_cast(panels[1+i_pan_orig]); if (pan_orig->refine_me){ pan_orig->initialize(Npix_total, compute_curvatures); - update_detector_on_device=true; + db_cu_flags.update_detector=true; } } @@ -757,7 +764,8 @@ void diffBragg::initialize_managers(){ fcell_managers[0]->initialize(Npix_total, compute_curvatures); //fcell_managers[1]->initialize(Npix_total, compute_curvatures); //fcell_managers[2]->initialize(Npix_total, compute_curvatures); - update_Fhkl_on_device = true; + db_cu_flags.update_Fhkl = true; + db_cu_flags.update_Fhkl_scales = true; } for (int i_eta=0; i_eta<3; i_eta++){ @@ -785,7 +793,7 @@ void diffBragg::initialize_managers(){ pan_rot = boost::dynamic_pointer_cast(panels[manager_idx]); if (pan_rot->refine_me){ update_panel_deriv_vecs_on_device=true; - update_detector_on_device=true; + db_cu_flags.update_detector=true; pan_rot->initialize(Npix_total, compute_curvatures); } } @@ -797,6 +805,20 @@ void diffBragg::initialize_managers(){ } +af::shared +diffBragg::get_mosaic_blocks_prime() { + af::shared result; + int num_blocks = mosaic_domains; + // TODO if refining aniso eta, then num_blocks for the primes is 3*mosaic_domains, address this case + for(mos_tic=0;mos_tic 0){ @@ -1000,12 +1022,13 @@ void diffBragg::refine(int refine_id){ boost::shared_ptr pan_orig = boost::dynamic_pointer_cast(panels[1]); pan_orig->refine_me=true; pan_orig->initialize(Npix_total, compute_curvatures); - update_detector_on_device=true; + db_cu_flags.update_detector=true; } else if(refine_id==11){ fcell_managers[0]->refine_me=true; fcell_managers[0]->initialize(Npix_total, compute_curvatures); - update_Fhkl_on_device = true; + db_cu_flags.update_Fhkl = true; + db_cu_flags.update_Fhkl_scales = true; } else if (refine_id==12 || refine_id==13){ @@ -1020,7 +1043,7 @@ void diffBragg::refine(int refine_id){ pan_rot->refine_me=true; rotate_fs_ss_vecs_3D(0,0,0); pan_rot->initialize(Npix_total, compute_curvatures); - update_detector_on_device = true; + db_cu_flags.update_detector = true; update_panel_deriv_vecs_on_device = true; } @@ -1028,21 +1051,21 @@ void diffBragg::refine(int refine_id){ boost::shared_ptr pan_orig = boost::dynamic_pointer_cast(panels[2]); pan_orig->refine_me=true; pan_orig->initialize(Npix_total, compute_curvatures); - update_detector_on_device = true; + db_cu_flags.update_detector = true; } else if (refine_id==16){ boost::shared_ptr pan_orig = boost::dynamic_pointer_cast(panels[3]); pan_orig->refine_me=true; pan_orig->initialize(Npix_total, compute_curvatures); - update_detector_on_device = true; + db_cu_flags.update_detector = true; } else if (refine_id==17){ boost::shared_ptr pan_rot = boost::dynamic_pointer_cast(panels[4]); pan_rot->refine_me=true; rotate_fs_ss_vecs_3D(0,0,0); pan_rot->initialize(Npix_total, compute_curvatures); - update_detector_on_device = true; + db_cu_flags.update_detector = true; update_panel_deriv_vecs_on_device = true; } else if (refine_id==18){ @@ -1050,7 +1073,7 @@ void diffBragg::refine(int refine_id){ pan_rot->refine_me=true; rotate_fs_ss_vecs_3D(0,0,0); pan_rot->initialize(Npix_total, compute_curvatures); - update_detector_on_device = true; + db_cu_flags.update_detector = true; update_panel_deriv_vecs_on_device = true; } else if (refine_id==19){ @@ -1131,6 +1154,7 @@ void diffBragg::update_Fhkl_channels(np::ndarray& channels){ if (verbose) printf("source=%d channel_id=%d\n", i, channel_id); } + db_cu_flags.update_Fhkl_channels=true; } boost::python::list diffBragg::get_Fhkl_channels(){ @@ -1198,6 +1222,7 @@ void diffBragg::quick_Fcell_update(boost::python::tuple const& value){ } //update_linear_Fhkl(); if(verbose) printf("done with quick update of Fhkl:\n"); + db_cu_flags.update_Fhkl=true; } @@ -1797,6 +1822,7 @@ void diffBragg::update_Fhkl_scale_factors(np::ndarray& scale_factors, int num_Fh bool init_scales=first_deriv_imgs.Fhkl_scale.empty(); db_flags.Fhkl_have_scale_factors = true; db_cryst.num_Fhkl_channels=num_Fhkl_channels; + db_cu_flags.update_Fhkl_scales=true; double* scale_ptr = reinterpret_cast(scale_factors.get_data()); for(int i_chan=0; i_chan< num_Fhkl_channels; i_chan++){ @@ -1843,41 +1869,55 @@ void diffBragg::add_diffBragg_spots(const af::shared& panels_fasts_slows int pan_rot_ids[3] = {0,4,5}; int pan_orig_ids[3] = {1,2,3}; - db_flags.refine_panel_rot.resize(3, false); - db_flags.refine_panel_origin.resize(3,false); - db_flags.refine_lambda.resize(2,false); - db_flags.refine_Bmat.resize(6,false); - db_flags.refine_Umat.resize(3,false); - db_flags.refine_Ncells.resize(3,false); + if (db_flags.refine_panel_rot.empty()){ // if one is empty, they're all empty + db_flags.refine_panel_rot.resize(3, false); + db_flags.refine_panel_origin.resize(3,false); + db_flags.refine_lambda.resize(2,false); + db_flags.refine_Bmat.resize(6,false); + db_flags.refine_Umat.resize(3,false); + db_flags.refine_Ncells.resize(3,false); + db_cu_flags.update_refine_flags=true; + } for(int i_pan=0;i_pan < 3; i_pan++){ int i_pan_rot = pan_rot_ids[i_pan]; int i_pan_orig = pan_orig_ids[i_pan]; - if (panels[i_pan_rot]->refine_me) - db_flags.refine_panel_rot[i_pan] = true; - if (panels[i_pan_orig]-> refine_me) - db_flags.refine_panel_origin[i_pan] = true; + if (panels[i_pan_rot]->refine_me != db_flags.refine_panel_rot[i_pan]){ + db_flags.refine_panel_rot[i_pan] = panels[i_pan_rot]->refine_me; + db_cu_flags.update_refine_flags=true; + } + if (panels[i_pan_orig]-> refine_me != db_flags.refine_panel_origin[i_pan_orig]){ + db_flags.refine_panel_origin[i_pan] = panels[i_pan_orig]->refine_me; + db_cu_flags.update_refine_flags=true; + } } for (int i_uc = 0; i_uc < 6; i_uc++){ - if (ucell_managers[i_uc]->refine_me) - db_flags.refine_Bmat[i_uc] = true; + if (ucell_managers[i_uc]->refine_me != db_flags.refine_Bmat[i_uc]){ + db_flags.refine_Bmat[i_uc] = ucell_managers[i_uc]->refine_me; + db_cu_flags.update_refine_flags=true; + } } for (int i_rot =0; i_rot< 3; i_rot ++){ - if (rot_managers[i_rot]->refine_me) - db_flags.refine_Umat[i_rot] = true; + if (rot_managers[i_rot]->refine_me != db_flags.refine_Umat[i_rot]){ + db_flags.refine_Umat[i_rot] = rot_managers[i_rot]->refine_me; + db_cu_flags.update_refine_flags=true; + } } for (int i_lam=0; i_lam< 2; i_lam++){ - if (lambda_managers[i_lam]->refine_me) - db_flags.refine_lambda[i_lam] = true; + if (lambda_managers[i_lam]->refine_me != db_flags.refine_lambda[i_lam]){ + db_flags.refine_lambda[i_lam] = lambda_managers[i_lam]->refine_me; + db_cu_flags.update_refine_flags=true; + } } - if (Ncells_managers[0]->refine_me){ - db_flags.refine_Ncells[0] = true; - if (! isotropic_ncells){ - db_flags.refine_Ncells[1] = true; - db_flags.refine_Ncells[2] = true; + for (int i_nc=0; i_nc<3; i_nc++){ + if (isotropic_ncells && i_nc >0) + continue; + if (Ncells_managers[i_nc]->refine_me != db_flags.refine_Ncells[i_nc]){ + db_flags.refine_Ncells[i_nc] = Ncells_managers[i_nc]->refine_me; + db_cu_flags.update_refine_flags=true; } } @@ -2026,7 +2066,7 @@ void diffBragg::add_diffBragg_spots(const af::shared& panels_fasts_slows //fudge = 1.1013986013; // from manuscript computation gettimeofday(&t1,0 ); - if ((! use_cuda && getenv("DIFFBRAGG_USE_CUDA")==NULL && getenv("DIFFBRAGG_USE_KOKKOS")==NULL ) || force_cpu){ + if ((! use_gpu && getenv("DIFFBRAGG_USE_CUDA")==NULL && getenv("DIFFBRAGG_USE_KOKKOS")==NULL ) || force_cpu){ diffBragg_sum_over_steps( Npix_to_model, panels_fasts_slows_vec, image, @@ -2044,16 +2084,18 @@ void diffBragg::add_diffBragg_spots(const af::shared& panels_fasts_slows db_cu_flags.device_Id = device_Id; db_cu_flags.update_step_positions = update_step_positions_on_device; db_cu_flags.update_panels_fasts_slows = update_panels_fasts_slows_on_device; - db_cu_flags.update_sources = update_sources_on_device; db_cu_flags.update_umats = update_umats_on_device; db_cu_flags.update_dB_mats = update_dB_matrices_on_device; db_cu_flags.update_rotmats = update_rotmats_on_device; - db_cu_flags.update_Fhkl = update_Fhkl_on_device; - db_cu_flags.update_detector = update_detector_on_device; - db_cu_flags.update_refine_flags = update_refine_flags_on_device; + //db_cu_flags.update_Fhkl = update_Fhkl_on_device; db_cu_flags.update_panel_deriv_vecs = update_panel_deriv_vecs_on_device; db_cu_flags.Npix_to_allocate = Npix_to_allocate; + bool use_cuda = false; +#ifdef DIFFBRAGG_HAVE_CUDA + use_cuda = use_gpu; +#endif + if (use_cuda || getenv("DIFFBRAGG_USE_CUDA")!=NULL){ #ifdef DIFFBRAGG_HAVE_CUDA diffBragg_sum_over_steps_cuda( @@ -2076,7 +2118,7 @@ void diffBragg::add_diffBragg_spots(const af::shared& panels_fasts_slows SCITBX_ASSERT(DIFFBRAGG_USE_CUDA_flag_unsupported); #endif } - else { + else if (use_gpu || getenv("DIFFBRAGG_USE_KOKKOS")!=NULL){ #ifdef DIFFBRAGG_HAVE_KOKKOS if (!diffBragg_runner) { diffBragg_runner = std::make_shared(); @@ -2097,10 +2139,10 @@ void diffBragg::add_diffBragg_spots(const af::shared& panels_fasts_slows if (verbose) printf("Ran the Kokkos kernel\n"); #else - bool DIFFBRAGG_USE_KOKKOS_flag_unsupported=false; - SCITBX_ASSERT(DIFFBRAGG_USE_KOKKOS_flag_unsupported); + bool DIFFBRAGG_USE_KOKKOS_flag_unsupported=false; + SCITBX_ASSERT(DIFFBRAGG_USE_KOKKOS_flag_unsupported); #endif - } + } last_kernel_on_GPU=true; #else bool DIFFBRAGG_USE_KOKKOS_and_DIFFBRAGG_USE_CUDA_flags_unsupported=false; @@ -2116,7 +2158,7 @@ void diffBragg::add_diffBragg_spots(const af::shared& panels_fasts_slows printf("Nsteps=%d\noversample=%d\ndet_thick_steps=%d\nsources=%d\nphisteps=%d\nmosaic_domains=%d\n", db_steps.Nsteps,oversample,detector_thicksteps,sources,phisteps,mosaic_domains); printf("DIFFBRAGG isotropic Ncells=%d\n", isotropic_ncells); - if(use_cuda || getenv("DIFFBRAGG_USE_CUDA")!= NULL) + if(use_gpu || getenv("DIFFBRAGG_USE_CUDA")!= NULL || getenv("DIFFBRAGG_USE_KOKKOS")!= NULL) printf("TIME TO RUN DIFFBRAGG -GPU- (%llu iterations): %3.10f ms \n",n_total_iter, time); else printf("TIME TO RUN DIFFBRAGG -CPU- (%llu iterations): %3.10f ms \n",n_total_iter, time); @@ -2383,10 +2425,24 @@ void diffBragg::show_timing_stats(int MPI_RANK){ //}, boost_adaptbx::python::str printf("RANK%d TIMINGS: add_diffBragg_spots pre kernel wrapper: %10.3f\n", MPI_RANK, TIMERS.add_spots_pre ); printf("RANK%d TIMINGS: add_diffBragg_spots post kernel wrapper: %10.3f\n", MPI_RANK , TIMERS.add_spots_post); printf("RANK%d TIMINGS: add_diffBragg_spots kernel wrapper: %10.3f\n", MPI_RANK, TIMERS.add_spots_kernel_wrapper ); - printf("RANK%d TIMINGS: add_diffBragg_spots CUDA alloc: %10.3f\n", MPI_RANK, TIMERS.cuda_alloc ); - printf("RANK%d TIMINGS: add_diffBragg_spots CUDA copy host to dev: %10.3f\n", MPI_RANK, TIMERS.cuda_copy_to_dev ); - printf("RANK%d TIMINGS: add_diffBragg_spots CUDA copy dev to host: %10.3f\n", MPI_RANK, TIMERS.cuda_copy_from_dev ); - printf("RANK%d TIMINGS: add_diffBragg_spots CUDA kernel: %10.3f\n", MPI_RANK, TIMERS.cuda_kernel ); + printf("RANK%d TIMINGS: add_diffBragg_spots device alloc: %10.3f\n", MPI_RANK, TIMERS.cuda_alloc ); + printf("RANK%d TIMINGS: add_diffBragg_spots copy host-to-dev: %10.3f\n", MPI_RANK, TIMERS.cuda_copy_to_dev ); + + printf("RANK%d TIMINGS: host-to-dev Fhkl scales: %10.3f\n", MPI_RANK, TIMERS.copy_Fhkl_scale ); + printf("RANK%d TIMINGS: host-to-dev sources: %10.3f\n", MPI_RANK, TIMERS.copy_sources ); + printf("RANK%d TIMINGS: host-to-dev umats: %10.3f\n", MPI_RANK, TIMERS.copy_umats ); + printf("RANK%d TIMINGS: host-to-dev amats: %10.3f\n", MPI_RANK, TIMERS.copy_amats ); + printf("RANK%d TIMINGS: host-to-dev bmats: %10.3f\n", MPI_RANK, TIMERS.copy_bmats ); + printf("RANK%d TIMINGS: host-to-dev rotmats: %10.3f\n", MPI_RANK, TIMERS.copy_rotmats ); + printf("RANK%d TIMINGS: host-to-dev det: %10.3f\n", MPI_RANK, TIMERS.copy_det ); + printf("RANK%d TIMINGS: host-to-dev nomhkl: %10.3f\n", MPI_RANK, TIMERS.copy_nomhkl ); + printf("RANK%d TIMINGS: host-to-dev flags: %10.3f\n", MPI_RANK, TIMERS.copy_flags ); + printf("RANK%d TIMINGS: host-to-dev fhkl: %10.3f\n", MPI_RANK, TIMERS.copy_fhkl ); + printf("RANK%d TIMINGS: host-to-dev detderiv: %10.3f\n", MPI_RANK, TIMERS.copy_detderiv ); + printf("RANK%d TIMINGS: host-to-dev pfs: %10.3f\n", MPI_RANK, TIMERS.copy_pfs ); + + printf("RANK%d TIMINGS: add_diffBragg_spots copy dev-to-host: %10.3f\n", MPI_RANK, TIMERS.cuda_copy_from_dev ); + printf("RANK%d TIMINGS: add_diffBragg_spots device kernel: %10.3f\n", MPI_RANK, TIMERS.cuda_kernel ); printf("RANK%d TIMINGS: Total kernel calls=%d\n", MPI_RANK, TIMERS.timings ); } else printf("RANK%d No timing has occured since instantiation of diffBragg\n", MPI_RANK); diff --git a/simtbx/diffBragg/src/diffBragg.h b/simtbx/diffBragg/src/diffBragg.h index 36ee6c0afb..aa4983792f 100644 --- a/simtbx/diffBragg/src/diffBragg.h +++ b/simtbx/diffBragg/src/diffBragg.h @@ -139,6 +139,8 @@ class diffBragg: public nanoBragg{ ~diffBragg(){}; + af::shared get_mosaic_blocks_prime(); + /// pixels double* floatimage_roi; af::flex_double raw_pixels_roi; @@ -164,12 +166,21 @@ class diffBragg: public nanoBragg{ #ifdef DIFFBRAGG_HAVE_KOKKOS // diffBragg_cudaPointers cuda_pointers; - void kokkos_free() { diffBragg_runner.reset(); } + inline void kokkos_free() { diffBragg_runner.reset(); } // allocate when needed to avoid problems with kokkos initialization when cuda/kokkos isn't used std::shared_ptr diffBragg_runner{}; // diffBraggKOKKOS diffBragg_runner; #endif + inline void gpu_free(){ +#ifdef DIFFBRAGG_HAVE_CUDA + cuda_free(); +#endif +#ifdef DIFFBRAGG_HAVE_KOKKOS + kokkos_free(); +#endif + } + // methods void update_xray_beams(scitbx::af::versa > const& value); void initialize_managers(); @@ -299,6 +310,7 @@ class diffBragg: public nanoBragg{ double Nd, Ne, Nf; bool refine_Ncells_def; bool no_Nabc_scale; // if true, then absorb the Nabc scale into an overall scale factor + double prev_shiftZ=0; // keep track of when detector Z was shifted (helps determine when to set the update_detector flag for GPU devices Eigen::Matrix3d NABC; bool use_lambda_coefficients; @@ -311,12 +323,11 @@ class diffBragg: public nanoBragg{ bool update_rotmats_on_device=false; bool update_umats_on_device=false; bool update_panels_fasts_slows_on_device=false; - bool update_sources_on_device=false; bool update_Fhkl_on_device=false; bool update_refine_flags_on_device=false; bool update_step_positions_on_device=false; bool update_panel_deriv_vecs_on_device=false; - bool use_cuda=false; + bool use_gpu=false; bool force_cpu=false; int Npix_to_allocate=-1; // got GPU allocation, -1 is auto mode diff --git a/simtbx/diffBragg/src/diffBraggCUDA.cu b/simtbx/diffBragg/src/diffBraggCUDA.cu index 6b0cddd2ff..b318a189e5 100644 --- a/simtbx/diffBragg/src/diffBraggCUDA.cu +++ b/simtbx/diffBragg/src/diffBraggCUDA.cu @@ -444,6 +444,12 @@ void diffBragg_sum_over_steps_cuda( if (db_cryst.fpfdp.size() == 0){ // note cannot use atom data if fpfdp is 0, make this cleaner num_atoms=0; } + + if (db_flags.use_diffuse) { + if (db_cryst.laue_group_num < 1 || db_cryst.laue_group_num >14 ){ + throw std::string("Laue group number not in range 1-14"); + } + } //int sm_size = number_of_sources*5*sizeof(CUDAREAL); //gpu_sum_over_steps<<>>( bool aniso_eta = db_cryst.UMATS_RXYZ.size() != db_cryst.UMATS_RXYZ_prime.size(); diff --git a/simtbx/diffBragg/src/diffBraggKOKKOS.cpp b/simtbx/diffBragg/src/diffBraggKOKKOS.cpp index f49508ed39..fb88a6f066 100644 --- a/simtbx/diffBragg/src/diffBraggKOKKOS.cpp +++ b/simtbx/diffBragg/src/diffBraggKOKKOS.cpp @@ -4,6 +4,45 @@ #include "diffBraggKOKKOS.h" #include "diffBragg_kokkos_kernel.h" +#define PRINTOUT(flag, function, ...) \ + if (flag) { \ + function(__VA_ARGS__); \ + } else { \ + function(__VA_ARGS__); \ + } \ + +uint32_t combine_refinement_flags(flags& db_flags) { + uint32_t refine_flag = 0; + refine_flag |= db_flags.refine_diffuse * REFINE_DIFFUSE; + refine_flag |= db_flags.refine_fcell * REFINE_FCELL; + refine_flag |= db_flags.refine_eta * REFINE_ETA; + refine_flag |= db_flags.refine_Umat[0] * REFINE_UMAT1; + refine_flag |= db_flags.refine_Umat[1] * REFINE_UMAT2; + refine_flag |= db_flags.refine_Umat[2] * REFINE_UMAT3; + refine_flag |= db_flags.refine_Ncells_def * REFINE_NCELLS_DEF; + refine_flag |= db_flags.refine_Ncells[0] * REFINE_NCELLS1; + refine_flag |= db_flags.refine_Ncells[1] * REFINE_NCELLS2; + refine_flag |= db_flags.refine_Ncells[2] * REFINE_NCELLS3; + refine_flag |= db_flags.refine_panel_rot[0] * REFINE_PANEL_ROT1; + refine_flag |= db_flags.refine_panel_rot[1] * REFINE_PANEL_ROT2; + refine_flag |= db_flags.refine_panel_rot[2] * REFINE_PANEL_ROT3; + refine_flag |= db_flags.refine_panel_origin[0] * REFINE_PANEL_ORIGIN1; + refine_flag |= db_flags.refine_panel_origin[1] * REFINE_PANEL_ORIGIN2; + refine_flag |= db_flags.refine_panel_origin[2] * REFINE_PANEL_ORIGIN3; + refine_flag |= db_flags.refine_lambda[0] * REFINE_LAMBDA1; + refine_flag |= db_flags.refine_lambda[1] * REFINE_LAMBDA2; + refine_flag |= db_flags.refine_Bmat[0] * REFINE_BMAT1; + refine_flag |= db_flags.refine_Bmat[1] * REFINE_BMAT2; + refine_flag |= db_flags.refine_Bmat[2] * REFINE_BMAT3; + refine_flag |= db_flags.refine_Bmat[3] * REFINE_BMAT4; + refine_flag |= db_flags.refine_Bmat[4] * REFINE_BMAT5; + refine_flag |= db_flags.refine_Bmat[5] * REFINE_BMAT6; + refine_flag |= db_flags.refine_fp_fdp * REFINE_FP_FDP; + refine_flag |= db_flags.refine_Icell * REFINE_ICELL; + + return refine_flag; +} + void diffBraggKOKKOS::diffBragg_sum_over_steps_kokkos( int Npix_to_model, std::vector& panels_fasts_slows, @@ -20,7 +59,7 @@ void diffBraggKOKKOS::diffBragg_sum_over_steps_kokkos( timer_variables& TIMERS) { if (db_cryst.phi0 != 0 || db_cryst.phisteps > 1) { printf( - "PHI (goniometer position) not supported in GPU code: phi0=%f phisteps=%d, phistep=%d\n", + "PHI (goniometer position) not supported in GPU code: phi0=%f phisteps=%d, phistep=%f\n", db_cryst.phi0, db_cryst.phisteps, db_cryst.phistep); exit(-1); } @@ -33,7 +72,7 @@ void diffBraggKOKKOS::diffBragg_sum_over_steps_kokkos( Kokkos::Tools::popRegion(); double time; - struct timeval t1, t2; //, t3 ,t4; + struct timeval t1, t; // t1 times larger blocks of code, and t is used to time shorter blocks of code gettimeofday(&t1, 0); // determine if we need to allocate pixels, and how many. @@ -201,18 +240,19 @@ void diffBraggKOKKOS::diffBragg_sum_over_steps_kokkos( resize(m_panels_fasts_slows, db_cu_flags.Npix_to_allocate * 3); + m_refine_flag = combine_refinement_flags(db_flags); + if (m_refine_flag) { + resize(m_manager_dI, db_cu_flags.Npix_to_allocate); + resize(m_manager_dI2, db_cu_flags.Npix_to_allocate); + } + m_npix_allocated = db_cu_flags.Npix_to_allocate; Kokkos::Tools::popRegion(); } // END of allocation bool ALLOC = !m_device_is_allocated; // shortcut variable - gettimeofday(&t2, 0); - time = (1000000.0 * (t2.tv_sec - t1.tv_sec) + t2.tv_usec - t1.tv_usec) / 1000.0; - if (TIMERS.recording) - TIMERS.cuda_alloc += time; - if (db_flags.verbose > 1) - printf("TIME SPENT ALLOCATING (TOTAL): %3.10f ms \n", time); + easy_time(TIMERS.cuda_alloc, t1, TIMERS.recording); //, db_flags.verbose > 1); // ALLOC = false; // BEGIN COPYING DATA @@ -221,33 +261,36 @@ void diffBraggKOKKOS::diffBragg_sum_over_steps_kokkos( // END step position if (db_flags.Fhkl_gradient_mode){ - transfer(m_data_residual, d_image.residual, Npix_to_model); - transfer(m_data_variance, d_image.variance, Npix_to_model); - transfer(m_data_trusted, d_image.trusted, Npix_to_model); - transfer(m_data_freq, d_image.freq, Npix_to_model); + kokkostbx::transfer_vector2kokkos(m_data_residual, d_image.residual); + kokkostbx::transfer_vector2kokkos(m_data_variance, d_image.variance); + kokkostbx::transfer_vector2kokkos(m_data_trusted, d_image.trusted); + kokkostbx::transfer_vector2kokkos(m_data_freq, d_image.freq); } if (db_flags.Fhkl_have_scale_factors && ALLOC){ - transfer(m_FhklLinear_ASUid, db_cryst.FhklLinear_ASUid); + kokkostbx::transfer_vector2kokkos(m_FhklLinear_ASUid, db_cryst.FhklLinear_ASUid); } + Kokkos::Tools::pushRegion("BEGIN Fhkl have scale factors"); + gettimeofday(&t, 0); if (db_flags.Fhkl_have_scale_factors){ - //SCITBX_ASSERT(db_beam.number_of_sources == db_beam.Fhkl_channels.size()); - transfer(m_Fhkl_channels, db_beam.Fhkl_channels); - transfer(m_Fhkl_scale, d_image.Fhkl_scale); + if (db_cu_flags.update_Fhkl_scales || ALLOC){ + kokkostbx::transfer_vector2kokkos(m_Fhkl_scale, d_image.Fhkl_scale); + db_cu_flags.update_Fhkl_scales = false; + } + if (db_cu_flags.update_Fhkl_channels || ALLOC){ + kokkostbx::transfer_vector2kokkos(m_Fhkl_channels, db_beam.Fhkl_channels); + db_cu_flags.update_Fhkl_channels = false; + } ::Kokkos::deep_copy(m_Fhkl_scale_deriv, 0); - - // for (int i=0; i < d_image.Fhkl_scale.size(); i++){ - // cp.Fhkl_scale[i] = d_image.Fhkl_scale[i]; - // if (db_flags.Fhkl_gradient_mode){ - // cp.Fhkl_scale_deriv[i] = 0; - // } - // } } + Kokkos::Tools::popRegion(); + easy_time(TIMERS.copy_Fhkl_scale, t, TIMERS.recording); //, db_flags.verbose > 1); // BEGIN sources Kokkos::Tools::pushRegion("BEGIN sources"); - if (db_cu_flags.update_sources || ALLOC || FORCE_COPY) { + gettimeofday(&t, 0); + if (db_cu_flags.update_sources || ALLOC) { int source_count = local_beam.number_of_sources; kokkostbx::transfer_double2kokkos(m_source_X, local_beam.source_X, source_count); kokkostbx::transfer_double2kokkos(m_source_Y, local_beam.source_Y, source_count); @@ -268,12 +311,15 @@ void diffBraggKOKKOS::diffBragg_sum_over_steps_kokkos( Kokkos::fence(); if (db_flags.verbose > 1) printf("H2D sources\n"); + db_cu_flags.update_sources = false; } + easy_time(TIMERS.copy_sources, t, TIMERS.recording); //, db_flags.verbose > 1); Kokkos::Tools::popRegion(); // END sources // UMATS + gettimeofday(&t, 0); Kokkos::Tools::pushRegion("UMATS"); if (db_cu_flags.update_umats || ALLOC || FORCE_COPY) { transfer_KOKKOS_MAT3(m_UMATS, db_cryst.UMATS); @@ -285,18 +331,24 @@ void diffBraggKOKKOS::diffBragg_sum_over_steps_kokkos( printf("H2D Done copying Umats\n"); } Kokkos::Tools::popRegion(); + easy_time(TIMERS.copy_umats, t, TIMERS.recording); //, db_flags.verbose > 1); // END UMATS + gettimeofday(&t, 0); if (db_cu_flags.update_umats || ALLOC || FORCE_COPY) { auto Amat_init = db_cryst.eig_U*db_cryst.eig_B*1e10*(db_cryst.eig_O.transpose()); + auto host_AMATS = Kokkos::create_mirror_view(m_AMATS); for (int i=0; i 1) printf("H2D Done copying Amats\n"); } + easy_time(TIMERS.copy_amats, t, TIMERS.recording); // BMATS + gettimeofday(&t, 0); Kokkos::Tools::pushRegion("BMATS"); if (db_cu_flags.update_dB_mats || ALLOC || FORCE_COPY) { transfer_KOKKOS_MAT3(m_dB_Mats, db_cryst.dB_Mats); @@ -305,9 +357,11 @@ void diffBraggKOKKOS::diffBragg_sum_over_steps_kokkos( printf("H2D Done copying dB_Mats\n"); } Kokkos::Tools::popRegion(); + easy_time(TIMERS.copy_bmats, t, TIMERS.recording); // END BMATS // ROT MATS + gettimeofday(&t, 0); Kokkos::Tools::pushRegion("ROT MATS"); if (db_cu_flags.update_rotmats || ALLOC || FORCE_COPY) { transfer_KOKKOS_MAT3(m_RotMats, db_cryst.RotMats); @@ -317,11 +371,13 @@ void diffBraggKOKKOS::diffBragg_sum_over_steps_kokkos( printf("H2D Done copying rotmats\n"); } Kokkos::Tools::popRegion(); + easy_time(TIMERS.copy_rotmats, t, TIMERS.recording); // END ROT MATS // DETECTOR VECTORS + gettimeofday(&t, 0); Kokkos::Tools::pushRegion("DETECTOR VECTORS"); - if (db_cu_flags.update_detector || ALLOC || FORCE_COPY) { + if (db_cu_flags.update_detector || ALLOC) { kokkostbx::transfer_vector2kokkos(m_fdet_vectors, local_det.fdet_vectors); kokkostbx::transfer_vector2kokkos(m_sdet_vectors, local_det.sdet_vectors); kokkostbx::transfer_vector2kokkos(m_odet_vectors, local_det.odet_vectors); @@ -329,25 +385,30 @@ void diffBraggKOKKOS::diffBragg_sum_over_steps_kokkos( kokkostbx::transfer_vector2kokkos(m_close_distances, local_det.close_distances); if (db_flags.verbose > 1) printf("H2D Done copying detector vectors\n"); + db_cu_flags.update_detector = false; } Kokkos::Tools::popRegion(); + easy_time(TIMERS.copy_det, t, TIMERS.recording); // END DETECTOR VECTORS + gettimeofday(&t, 0); if (ALLOC || FORCE_COPY) { - transfer(m_nominal_hkl, db_cryst.nominal_hkl); - transfer(m_atom_data, db_cryst.atom_data); + kokkostbx::transfer_vector2kokkos(m_nominal_hkl, db_cryst.nominal_hkl); + kokkostbx::transfer_vector2kokkos(m_atom_data, db_cryst.atom_data); if (db_flags.verbose > 1) printf("H2D Done copying atom data\n"); - transfer(m_fpfdp, db_cryst.fpfdp); - transfer(m_fpfdp_derivs, db_cryst.fpfdp_derivs); + kokkostbx::transfer_vector2kokkos(m_fpfdp, db_cryst.fpfdp); + kokkostbx::transfer_vector2kokkos(m_fpfdp_derivs, db_cryst.fpfdp_derivs); if (db_flags.verbose > 1) printf("H2D Done copying fprime and fdblprime\n"); } + easy_time(TIMERS.copy_nomhkl, t, TIMERS.recording); - // BEGIN REFINEMENT FLAGS - Kokkos::Tools::pushRegion("BEGIN REFINMENT FLAGS"); - if (db_cu_flags.update_refine_flags || ALLOC || FORCE_COPY) { + // BEGIN UPDATE REFINEMENT + gettimeofday(&t, 0); + Kokkos::Tools::pushRegion("BEGIN UPDATE REFINMENT"); + if (db_cu_flags.update_refine_flags || ALLOC) { kokkostbx::transfer_vector2kokkos(m_refine_Umat, db_flags.refine_Umat); kokkostbx::transfer_vector2kokkos(m_refine_Ncells, db_flags.refine_Ncells); kokkostbx::transfer_vector2kokkos(m_refine_panel_origin, db_flags.refine_panel_origin); @@ -356,35 +417,44 @@ void diffBraggKOKKOS::diffBragg_sum_over_steps_kokkos( kokkostbx::transfer_vector2kokkos(m_refine_Bmat, db_flags.refine_Bmat); if (db_flags.verbose > 1) printf("H2D Done copying refinement flags\n"); + db_cu_flags.update_refine_flags=false; } Kokkos::Tools::popRegion(); - // END REFINEMENT FLAGS + easy_time(TIMERS.copy_flags, t, TIMERS.recording); + // END UPDATE REFINEMENT // BEGIN Fhkl + gettimeofday(&t, 0); Kokkos::Tools::pushRegion("Begin Fhkl"); - if (db_cu_flags.update_Fhkl || ALLOC || FORCE_COPY) { - transfer(m_Fhkl, db_cryst.FhklLinear); + if (db_cu_flags.update_Fhkl || ALLOC) { + kokkostbx::transfer_vector2kokkos(m_Fhkl, db_cryst.FhklLinear); if (db_flags.complex_miller) { - transfer(m_Fhkl2, db_cryst.Fhkl2Linear); + kokkostbx::transfer_vector2kokkos(m_Fhkl2, db_cryst.Fhkl2Linear); } if (db_flags.verbose > 1) printf("H2D Done copying step Fhkl\n"); + db_cu_flags.update_Fhkl = false; } Kokkos::Tools::popRegion(); + easy_time(TIMERS.copy_fhkl, t, TIMERS.recording); // END Fhkl // BEGIN panel derivative vecs + gettimeofday(&t, 0); Kokkos::Tools::pushRegion("BEGIN panel derivative vecs"); - if (db_cu_flags.update_panel_deriv_vecs || ALLOC || FORCE_COPY) { + if (db_cu_flags.update_panel_deriv_vecs || ALLOC) { kokkostbx::transfer_vector2kokkos(m_dF_vecs, local_det.dF_vecs); kokkostbx::transfer_vector2kokkos(m_dS_vecs, local_det.dS_vecs); if (db_flags.verbose > 1) printf("H2D Done copying step panel derivative vectors\n"); + db_cu_flags.update_panel_deriv_vecs=false; } Kokkos::Tools::popRegion(); + easy_time(TIMERS.copy_detderiv, t, TIMERS.recording); // END panel derivative vecs // BEGIN panels fasts slows + gettimeofday(&t, 0); Kokkos::Tools::pushRegion("BEGIN panels fasts slows"); if (db_cu_flags.update_panels_fasts_slows || ALLOC || FORCE_COPY) { kokkostbx::transfer_vector2kokkos(m_panels_fasts_slows, panels_fasts_slows); @@ -392,14 +462,10 @@ void diffBraggKOKKOS::diffBragg_sum_over_steps_kokkos( printf("H2D Done copying panels_fasts_slows\n"); } Kokkos::Tools::popRegion(); + easy_time(TIMERS.copy_pfs, t, TIMERS.recording); // END panels fasts slows - gettimeofday(&t2, 0); - time = (1000000.0 * (t2.tv_sec - t1.tv_sec) + t2.tv_usec - t1.tv_usec) / 1000.0; - if (TIMERS.recording) - TIMERS.cuda_copy_to_dev += time; - if (db_flags.verbose > 1) - printf("TIME SPENT COPYING DATA HOST->DEV: %3.10f ms \n", time); + easy_time(TIMERS.cuda_copy_to_dev, t1, TIMERS.recording); m_device_is_allocated = true; ::Kokkos::fence("after copy to device"); @@ -412,61 +478,105 @@ void diffBraggKOKKOS::diffBragg_sum_over_steps_kokkos( if (db_cryst.fpfdp.size() == 0) { num_atoms = 0; } - // int sm_size = number_of_sources*5*sizeof(CUDAREAL); - // gpu_sum_over_steps<<>>( + bool aniso_eta = db_cryst.UMATS_RXYZ.size() != db_cryst.UMATS_RXYZ_prime.size(); bool use_nominal_hkl = !db_cryst.nominal_hkl.empty(); - kokkos_sum_over_steps( - Npix_to_model, m_panels_fasts_slows, m_floatimage, m_wavelenimage, m_d_Umat_images, - m_d2_Umat_images, m_d_Bmat_images, m_d2_Bmat_images, m_d_Ncells_images, m_d2_Ncells_images, - m_d_fcell_images, m_d2_fcell_images, m_d_eta_images, m_d2_eta_images, m_d_lambda_images, - m_d2_lambda_images, m_d_panel_rot_images, m_d2_panel_rot_images, m_d_panel_orig_images, - m_d2_panel_orig_images, m_d_fp_fdp_images, db_steps.Nsteps, db_flags.printout_fpixel, - db_flags.printout_spixel, db_flags.printout, db_cryst.default_F, local_det.oversample, - db_flags.oversample_omega, local_det.subpixel_size, local_det.pixel_size, - local_det.detector_thickstep, local_det.detector_thick, m_close_distances, - local_det.detector_attnlen, local_det.detector_thicksteps, local_beam.number_of_sources, - db_cryst.phisteps, db_cryst.UMATS.size(), db_flags.use_lambda_coefficients, - local_beam.lambda0, local_beam.lambda1, to_mat3(db_cryst.eig_U), to_mat3(db_cryst.eig_O), - to_mat3(db_cryst.eig_B), to_mat3(db_cryst.RXYZ), m_dF_vecs, m_dS_vecs, m_UMATS_RXYZ, m_UMATS_RXYZ_prime, - m_UMATS_RXYZ_dbl_prime, m_RotMats, m_dRotMats, m_d2RotMats, m_UMATS, m_dB_Mats, m_dB2_Mats, - m_AMATS, m_source_X, m_source_Y, m_source_Z, m_source_lambda, m_source_I, - local_beam.kahn_factor, db_cryst.Na, db_cryst.Nb, db_cryst.Nc, db_cryst.Nd, - db_cryst.Ne, db_cryst.Nf, db_cryst.phi0, db_cryst.phistep, - to_vec3(db_cryst.spindle_vec), local_beam.polarization_axis, db_cryst.h_range, - db_cryst.k_range, db_cryst.l_range, db_cryst.h_max, db_cryst.h_min, - db_cryst.k_max, db_cryst.k_min, db_cryst.l_max, db_cryst.l_min, - db_cryst.dmin, db_cryst.fudge, db_flags.complex_miller, db_flags.verbose, - db_flags.only_save_omega_kahn, db_flags.isotropic_ncells, db_flags.compute_curvatures, - m_Fhkl, m_Fhkl2, m_refine_Bmat, m_refine_Ncells, db_flags.refine_Ncells_def, - m_refine_panel_origin, m_refine_panel_rot, db_flags.refine_fcell, m_refine_lambda, - db_flags.refine_eta, m_refine_Umat, m_fdet_vectors, m_sdet_vectors, m_odet_vectors, - m_pix0_vectors, db_flags.nopolar, db_flags.point_pixel, local_beam.fluence, - db_cryst.r_e_sqr, db_cryst.spot_scale, Npanels, aniso_eta, db_flags.no_Nabc_scale, - m_fpfdp, m_fpfdp_derivs, m_atom_data, num_atoms, db_flags.refine_fp_fdp, m_nominal_hkl, - use_nominal_hkl, to_mat3(db_cryst.anisoU), to_mat3(db_cryst.anisoG), to_mat3(db_cryst.rotate_principal_axes), - db_flags.use_diffuse, m_d_diffuse_gamma_images, m_d_diffuse_sigma_images, db_flags.refine_diffuse, - db_flags.gamma_miller_units, db_flags.refine_Icell, db_flags.wavelength_img, - db_cryst.laue_group_num, db_cryst.stencil_size, db_flags.Fhkl_gradient_mode, - db_flags.Fhkl_errors_mode, db_flags.using_trusted_mask, db_beam.Fhkl_channels.empty(), - db_flags.Fhkl_have_scale_factors, db_cryst.Num_ASU, - m_data_residual, m_data_variance, - m_data_freq, m_data_trusted, - m_FhklLinear_ASUid, - m_Fhkl_channels, - m_Fhkl_scale, m_Fhkl_scale_deriv - ); + if ((db_flags.printout==false) && + (db_flags.complex_miller==false) && + (db_flags.compute_curvatures==false) && + (m_refine_flag==REFINE_FCELL) && + (db_flags.use_diffuse==false) && + (db_flags.wavelength_img==false) && + (db_flags.Fhkl_gradient_mode==false) && + (db_flags.Fhkl_errors_mode==false) && + (db_flags.using_trusted_mask==false) && + (db_beam.Fhkl_channels.empty()==true) && + (db_flags.Fhkl_have_scale_factors)==false) { + kokkos_sum_over_steps( + Npix_to_model, m_panels_fasts_slows, m_floatimage, m_wavelenimage, m_d_Umat_images, + m_d2_Umat_images, m_d_Bmat_images, m_d2_Bmat_images, m_d_Ncells_images, m_d2_Ncells_images, + m_d_fcell_images, m_d2_fcell_images, m_d_eta_images, m_d2_eta_images, m_d_lambda_images, + m_d2_lambda_images, m_d_panel_rot_images, m_d2_panel_rot_images, m_d_panel_orig_images, + m_d2_panel_orig_images, m_d_fp_fdp_images, m_manager_dI, m_manager_dI2, db_steps.Nsteps, + db_flags.printout_fpixel, db_flags.printout_spixel, /*db_flags.printout,*/ db_cryst.default_F, + local_det.oversample, db_flags.oversample_omega, local_det.subpixel_size, local_det.pixel_size, + local_det.detector_thickstep, local_det.detector_thick, m_close_distances, + local_det.detector_attnlen, local_det.detector_thicksteps, local_beam.number_of_sources, + db_cryst.phisteps, (int) db_cryst.UMATS.size(), db_flags.use_lambda_coefficients, + local_beam.lambda0, local_beam.lambda1, to_mat3(db_cryst.eig_U), to_mat3(db_cryst.eig_O), + to_mat3(db_cryst.eig_B), to_mat3(db_cryst.RXYZ), m_dF_vecs, m_dS_vecs, m_UMATS_RXYZ, m_UMATS_RXYZ_prime, + m_UMATS_RXYZ_dbl_prime, m_RotMats, m_dRotMats, m_d2RotMats, m_UMATS, m_dB_Mats, m_dB2_Mats, + m_AMATS, m_source_X, m_source_Y, m_source_Z, m_source_lambda, m_source_I, + local_beam.kahn_factor, db_cryst.Na, db_cryst.Nb, db_cryst.Nc, db_cryst.Nd, + db_cryst.Ne, db_cryst.Nf, db_cryst.phi0, db_cryst.phistep, + to_vec3(db_cryst.spindle_vec), local_beam.polarization_axis, db_cryst.h_range, + db_cryst.k_range, db_cryst.l_range, db_cryst.h_max, db_cryst.h_min, + db_cryst.k_max, db_cryst.k_min, db_cryst.l_max, db_cryst.l_min, + db_cryst.dmin, db_cryst.fudge, /*db_flags.complex_miller,*/ db_flags.verbose, + db_flags.only_save_omega_kahn, db_flags.isotropic_ncells, /*db_flags.compute_curvatures,*/ + m_Fhkl, m_Fhkl2, /*m_refine_flag,*/ + m_fdet_vectors, m_sdet_vectors, m_odet_vectors, + m_pix0_vectors, db_flags.nopolar, db_flags.point_pixel, local_beam.fluence, + db_cryst.r_e_sqr, db_cryst.spot_scale, Npanels, aniso_eta, db_flags.no_Nabc_scale, + m_fpfdp, m_fpfdp_derivs, m_atom_data, num_atoms, m_nominal_hkl, + use_nominal_hkl, to_mat3(db_cryst.anisoU), to_mat3(db_cryst.anisoG), to_mat3(db_cryst.rotate_principal_axes), + /*db_flags.use_diffuse,*/ m_d_diffuse_gamma_images, m_d_diffuse_sigma_images, + db_flags.gamma_miller_units, /*db_flags.wavelength_img,*/ + db_cryst.laue_group_num, db_cryst.stencil_size, /*db_flags.Fhkl_gradient_mode,*/ + /*db_flags.Fhkl_errors_mode,*/ /*db_flags.using_trusted_mask,*/ /*db_beam.Fhkl_channels.empty(),*/ + /*db_flags.Fhkl_have_scale_factors,*/ db_cryst.Num_ASU, + m_data_residual, m_data_variance, + m_data_freq, m_data_trusted, + m_FhklLinear_ASUid, + m_Fhkl_channels, + m_Fhkl_scale, m_Fhkl_scale_deriv); + } else { + kokkos_sum_over_steps( + Npix_to_model, m_panels_fasts_slows, m_floatimage, m_wavelenimage, m_d_Umat_images, + m_d2_Umat_images, m_d_Bmat_images, m_d2_Bmat_images, m_d_Ncells_images, m_d2_Ncells_images, + m_d_fcell_images, m_d2_fcell_images, m_d_eta_images, m_d2_eta_images, m_d_lambda_images, + m_d2_lambda_images, m_d_panel_rot_images, m_d2_panel_rot_images, m_d_panel_orig_images, + m_d2_panel_orig_images, m_d_fp_fdp_images, m_manager_dI, m_manager_dI2, db_steps.Nsteps, + db_flags.printout_fpixel, db_flags.printout_spixel, db_flags.printout, db_cryst.default_F, + local_det.oversample, db_flags.oversample_omega, local_det.subpixel_size, local_det.pixel_size, + local_det.detector_thickstep, local_det.detector_thick, m_close_distances, + local_det.detector_attnlen, local_det.detector_thicksteps, local_beam.number_of_sources, + db_cryst.phisteps, db_cryst.UMATS.size(), db_flags.use_lambda_coefficients, + local_beam.lambda0, local_beam.lambda1, to_mat3(db_cryst.eig_U), to_mat3(db_cryst.eig_O), + to_mat3(db_cryst.eig_B), to_mat3(db_cryst.RXYZ), m_dF_vecs, m_dS_vecs, m_UMATS_RXYZ, m_UMATS_RXYZ_prime, + m_UMATS_RXYZ_dbl_prime, m_RotMats, m_dRotMats, m_d2RotMats, m_UMATS, m_dB_Mats, m_dB2_Mats, + m_AMATS, m_source_X, m_source_Y, m_source_Z, m_source_lambda, m_source_I, + local_beam.kahn_factor, db_cryst.Na, db_cryst.Nb, db_cryst.Nc, db_cryst.Nd, + db_cryst.Ne, db_cryst.Nf, db_cryst.phi0, db_cryst.phistep, + to_vec3(db_cryst.spindle_vec), local_beam.polarization_axis, db_cryst.h_range, + db_cryst.k_range, db_cryst.l_range, db_cryst.h_max, db_cryst.h_min, + db_cryst.k_max, db_cryst.k_min, db_cryst.l_max, db_cryst.l_min, + db_cryst.dmin, db_cryst.fudge, db_flags.complex_miller, db_flags.verbose, + db_flags.only_save_omega_kahn, db_flags.isotropic_ncells, db_flags.compute_curvatures, + m_Fhkl, m_Fhkl2, m_refine_flag, + m_fdet_vectors, m_sdet_vectors, m_odet_vectors, + m_pix0_vectors, db_flags.nopolar, db_flags.point_pixel, local_beam.fluence, + db_cryst.r_e_sqr, db_cryst.spot_scale, Npanels, aniso_eta, db_flags.no_Nabc_scale, + m_fpfdp, m_fpfdp_derivs, m_atom_data, num_atoms, m_nominal_hkl, + use_nominal_hkl, to_mat3(db_cryst.anisoU), to_mat3(db_cryst.anisoG), to_mat3(db_cryst.rotate_principal_axes), + db_flags.use_diffuse, m_d_diffuse_gamma_images, m_d_diffuse_sigma_images, + db_flags.gamma_miller_units, db_flags.wavelength_img, + db_cryst.laue_group_num, db_cryst.stencil_size, db_flags.Fhkl_gradient_mode, + db_flags.Fhkl_errors_mode, db_flags.using_trusted_mask, db_beam.Fhkl_channels.empty(), + db_flags.Fhkl_have_scale_factors, db_cryst.Num_ASU, + m_data_residual, m_data_variance, + m_data_freq, m_data_trusted, + m_FhklLinear_ASUid, + m_Fhkl_channels, + m_Fhkl_scale, m_Fhkl_scale_deriv + ); + } ::Kokkos::fence("after kernel call"); if (db_flags.verbose > 1) printf("KERNEL_COMPLETE gpu_sum_over_steps\n"); - gettimeofday(&t2, 0); - time = (1000000.0 * (t2.tv_sec - t1.tv_sec) + t2.tv_usec - t1.tv_usec) / 1000.0; - if (TIMERS.recording) - TIMERS.cuda_kernel += time; - if (db_flags.verbose > 1) - printf("TIME SPENT(KERNEL): %3.10f ms \n", time); + easy_time(TIMERS.cuda_kernel, t1, TIMERS.recording); gettimeofday(&t1, 0); // COPY BACK FROM DEVICE @@ -482,12 +592,10 @@ void diffBraggKOKKOS::diffBragg_sum_over_steps_kokkos( } if (db_flags.Fhkl_gradient_mode){ if (db_flags.Fhkl_errors_mode){ - for (int i=0; i < d_image.Fhkl_hessian.size(); i++) - d_image.Fhkl_hessian[i]= m_Fhkl_scale_deriv(i); + kokkostbx::transfer_kokkos2vector(d_image.Fhkl_hessian, m_Fhkl_scale_deriv); } else{ - for (int i=0; i < d_image.Fhkl_scale_deriv.size(); i++) - d_image.Fhkl_scale_deriv[i]= m_Fhkl_scale_deriv(i); + kokkostbx::transfer_kokkos2vector(d_image.Fhkl_scale_deriv, m_Fhkl_scale_deriv); } } if (std::count(db_flags.refine_Umat.begin(), db_flags.refine_Umat.end(), true) > 0) { @@ -526,12 +634,7 @@ void diffBraggKOKKOS::diffBragg_sum_over_steps_kokkos( } Kokkos::Tools::popRegion(); - gettimeofday(&t2, 0); - time = (1000000.0 * (t2.tv_sec - t1.tv_sec) + t2.tv_usec - t1.tv_usec) / 1000.0; - if (TIMERS.recording) - TIMERS.cuda_copy_from_dev += time; - if (db_flags.verbose > 1) - printf("TIME SPENT COPYING BACK : %3.10f ms \n", time); + easy_time(TIMERS.cuda_copy_from_dev, t1, TIMERS.recording); ::Kokkos::fence("After copy to host"); Kokkos::Tools::popRegion(); diff --git a/simtbx/diffBragg/src/diffBraggKOKKOS.h b/simtbx/diffBragg/src/diffBraggKOKKOS.h index cc074b938a..3aa07ae27b 100644 --- a/simtbx/diffBragg/src/diffBraggKOKKOS.h +++ b/simtbx/diffBragg/src/diffBraggKOKKOS.h @@ -9,9 +9,11 @@ #include "kokkostbx/kokkos_utils.h" #include "simtbx/diffBragg/src/util.h" #include "simtbx/diffBragg/src/util_kokkos.h" +#include "simtbx/diffBragg/src/diffBragg_refine_flag.h" using vector_vec3_t = view_1d_t; using vector_mat3_t = view_1d_t; +using vector_manager_t = view_1d_t; #define INTEGER_VIEW(varname) vector_int_t varname = vector_int_t(#varname, 0) #define CUDAREAL_VIEW(varname) vector_cudareal_t varname = vector_cudareal_t(#varname, 0) @@ -101,6 +103,7 @@ class diffBraggKOKKOS { MATRIX3_VIEW(m_sausages_U); CUDAREAL_VIEW(m_sausages_scale); + uint32_t m_refine_flag = 0; vector_bool_t m_refine_Bmat = vector_bool_t("m_refine_Bmat", 6); vector_bool_t m_refine_Umat = vector_bool_t("m_refine_Umat", 3); vector_bool_t m_refine_Ncells = vector_bool_t("m_refine_Ncells", 3); @@ -108,6 +111,9 @@ class diffBraggKOKKOS { vector_bool_t m_refine_panel_rot = vector_bool_t("m_refine_panel_rot", 3); vector_bool_t m_refine_lambda = vector_bool_t("m_refine_lambda", 2); + vector_manager_t m_manager_dI = vector_manager_t("m_manager_dI", 0); + vector_manager_t m_manager_dI2 = vector_manager_t("m_manager_dI2", 0); + bool m_Fhkl_gradient_mode; bool m_using_trusted_mask; bool m_Fhkl_channels_empty; @@ -119,12 +125,13 @@ class diffBraggKOKKOS { INTEGER_VIEW(m_data_freq); // length is number of modeled pixels vector_bool_t m_data_trusted = vector_bool_t("m_data_trusted", 0); // length is number of modeled pixels INTEGER_VIEW(m_FhklLinear_ASUid); // length is number of ASU in FhklLinear - CUDAREAL_VIEW(m_Fhkl_channels); + INTEGER_VIEW(m_Fhkl_channels); // Fhkl_scale is dynamically copied each iteration // Fhkl_scale_deriv is set to 0 each iteration CUDAREAL_VIEW(m_Fhkl_scale); // length is (number of ASUin FhklLinear) *times* (number of Fhkl channels) CUDAREAL_VIEW(m_Fhkl_scale_deriv); // length is (number of ASUin FhklLinear) *times* (number of Fhkl channels) + public: void diffBragg_sum_over_steps_kokkos( int Npix_to_model, diff --git a/simtbx/diffBragg/src/diffBragg_cpu_kernel.cpp b/simtbx/diffBragg/src/diffBragg_cpu_kernel.cpp index decf9f9145..22dd70275a 100644 --- a/simtbx/diffBragg/src/diffBragg_cpu_kernel.cpp +++ b/simtbx/diffBragg/src/diffBragg_cpu_kernel.cpp @@ -311,6 +311,10 @@ void diffBragg_sum_over_steps( anisoG_local = db_cryst.anisoG; anisoU_local = db_cryst.anisoU; + if (laue_group_num < 1 || laue_group_num >14 ){ + throw std::string("Laue group number not in range 1-14"); + } + num_laue_mats = gen_laue_mats(laue_group_num, laue_mats, db_cryst.rotate_principal_axes); for (int i_gam=0; i_gam<3; i_gam++){ dG_dgam[i_gam] << 0,0,0,0,0,0,0,0,0; @@ -913,6 +917,7 @@ void diffBragg_sum_over_steps( int nom_l=l0; //int f_cell_idx = 1; if (use_nominal_hkl){ + nom_h = db_cryst.nominal_hkl[i_pix*3]; nom_k = db_cryst.nominal_hkl[i_pix*3+1]; nom_l = db_cryst.nominal_hkl[i_pix*3+2]; diff --git a/simtbx/diffBragg/src/diffBragg_ext.cpp b/simtbx/diffBragg/src/diffBragg_ext.cpp index 7d2ba180f1..997a6bea6d 100644 --- a/simtbx/diffBragg/src/diffBragg_ext.cpp +++ b/simtbx/diffBragg/src/diffBragg_ext.cpp @@ -23,6 +23,43 @@ namespace boost_python { namespace { return indices; } + static void set_beams(simtbx::nanoBragg::diffBragg& diffBragg, scitbx::af::versa > const& value) { + if(diffBragg.verbose>3) printf(" about to initialize sources\n"); + diffBragg.pythony_beams = value; + if(diffBragg.verbose>3) printf(" done\n"); + diffBragg.db_cu_flags.update_sources=true; + /* re-initialize source table from pythony array */ + diffBragg.init_sources(); + } + // TODO: point to the get_beams defined in simtbx/nanoBragg/nanoBragg_ext.cpp if possible.. + ///* table of sources, as dxtbx "beam"s */ + static scitbx::af::versa > get_beams(simtbx::nanoBragg::diffBragg& diffBragg) { + int i; + /* allocate new flex array */ +// scitbx::af::versa > diffBragg_pythony_beams; + diffBragg.pythony_beams = scitbx::af::versa >(); + /* make sure it is big enough to hold all sources */ + diffBragg.pythony_beams.resize(diffBragg.sources); + + /* polarization normal seems to be B vector */ + scitbx::vec3 Evector = scitbx::vec3(diffBragg.polar_vector[1],diffBragg.polar_vector[2],diffBragg.polar_vector[3]); + scitbx::vec3 Pvector = scitbx::vec3(diffBragg.beam_vector[1],diffBragg.beam_vector[2],diffBragg.beam_vector[3]); + scitbx::vec3 Bvector = Pvector.cross(Evector).normalize(); + + /* copy internal storage into the flex array */ + for(i=0;i(diffBragg.source_X[i],diffBragg.source_Y[i],diffBragg.source_Z[i])); + diffBragg.pythony_beams[i].set_wavelength(diffBragg.source_lambda[i]*1e10); + diffBragg.pythony_beams[i].set_flux(diffBragg.source_I[i]); + // how is this a fraction when it can be negative? (Kahn et al. 1982) + diffBragg.pythony_beams[i].set_polarization_fraction(diffBragg.polarization); + diffBragg.pythony_beams[i].set_polarization_normal(Bvector); + } + /* pass this back to python */ + return diffBragg.pythony_beams; + } + + void set_dspace_bins(simtbx::nanoBragg::diffBragg& diffBragg, boost::python::list bins){ diffBragg.db_cryst.dspace_bins.clear(); for (int i=0; i< boost::python::len(bins); i++ ){ @@ -155,7 +192,7 @@ namespace boost_python { namespace { values = boost::python::make_tuple(0,0); return values; } - //TODO override the set_sources function (or xray_beams) property in nanoBragg in order + //TODO override the set_sources function (or xray_beams) property in nanoBragg // to set the fpfdp accordingly (if Fhkl2 is set) static void set_atom_data(simtbx::nanoBragg::diffBragg & diffBragg, boost::python::tuple const& atom_XYZBO){ @@ -418,6 +455,7 @@ namespace boost_python { namespace { static void set_Fhkl_tuple(simtbx::nanoBragg::diffBragg& diffBragg, boost::python::tuple const& value) { //TODO nanoBragg set as well ? + diffBragg.db_cu_flags.update_Fhkl=true; diffBragg.pythony_indices = extract(value[0]); diffBragg.pythony_amplitudes = extract >(value[1]); diffBragg.init_Fhkl(); @@ -432,7 +470,7 @@ namespace boost_python { namespace { diffBragg.linearize_Fhkl(true); } - static boost::python::tuple get_Fhkl_tuple(simtbx::nanoBragg::diffBragg diffBragg) { + static boost::python::tuple get_Fhkl_tuple(nanoBragg::diffBragg diffBragg) { int h,k,l; double temp; int hkls = diffBragg.h_range*diffBragg.k_range*diffBragg.l_range; @@ -471,9 +509,8 @@ namespace boost_python { namespace { } void initialize_kokkos(int dev){ - Kokkos::InitArguments kokkos_init; - kokkos_init.device_id = dev; - Kokkos::initialize(kokkos_init); + Kokkos::initialize(Kokkos::InitializationSettings() + .set_device_id(dev)); } #endif @@ -628,12 +665,14 @@ namespace boost_python { namespace { .def("show_heavy_atom_data", &simtbx::nanoBragg::diffBragg::show_heavy_atom_data) + .def("gpu_free",&simtbx::nanoBragg::diffBragg::gpu_free) + #ifdef DIFFBRAGG_HAVE_CUDA .def("gpu_free",&simtbx::nanoBragg::diffBragg::cuda_free) #endif #ifdef DIFFBRAGG_HAVE_KOKKOS - .def("kokkos_gpu_free",&simtbx::nanoBragg::diffBragg::kokkos_free) + .def("kokkos_free",&simtbx::nanoBragg::diffBragg::kokkos_free) #endif .def("set_mosaic_blocks_prime", @@ -789,9 +828,9 @@ namespace boost_python { namespace { "coefficients for source_lambda refinement: `lambda = coef0 + coef1*source` where `source` is the source index") // CUDA PROPERTIES - .add_property("use_cuda", - make_getter(&simtbx::nanoBragg::diffBragg::use_cuda,rbv()), - make_setter(&simtbx::nanoBragg::diffBragg::use_cuda,dcp()), + .add_property("use_gpu", + make_getter(&simtbx::nanoBragg::diffBragg::use_gpu,rbv()), + make_setter(&simtbx::nanoBragg::diffBragg::use_gpu,dcp()), "use GPU acceleration") .add_property("record_time", @@ -886,6 +925,15 @@ namespace boost_python { namespace { &simtbx::nanoBragg::diffBragg::set_Friedel_mate_inds, "Two arguments; each lists of the same length, pointing to the positive and negative mates in a Friedel pair, respectively") + .def("get_mosaic_blocks_prime", + &simtbx::nanoBragg::diffBragg::get_mosaic_blocks_prime, + "return the deriv of the matrices U that define the mosaic block distribution w.r.t eta") + + .add_property("xray_beams", + make_function(&get_beams,rbv()), + make_function(&set_beams,dcp()), + "list of dxtbx::Beam objects corresponding to each zero-divergence and monochromatic x-ray point source in the numerical simulation ") + ; // end of diffBragg extention } // end of diffBragg_init_module diff --git a/simtbx/diffBragg/src/diffBragg_gpu_kernel.cu b/simtbx/diffBragg/src/diffBragg_gpu_kernel.cu index 9c382a5c60..6bf8b801e4 100644 --- a/simtbx/diffBragg/src/diffBragg_gpu_kernel.cu +++ b/simtbx/diffBragg/src/diffBragg_gpu_kernel.cu @@ -465,7 +465,7 @@ void gpu_sum_over_steps( CUDAREAL _F_cell = s_default_F; CUDAREAL _F_cell2 = 0; - int i_hklasu=0; + int i_hklasu=0; if ( (_h0<=s_h_max) && (_h0>=s_h_min) && (_k0<=s_k_max) && (_k0>=s_k_min) && (_l0<=s_l_max) && (_l0>=s_l_min) ) { int Fhkl_linear_index = (_h0-s_h_min) * s_k_range * s_l_range + (_k0-s_k_min) * s_l_range + (_l0-s_l_min); diff --git a/simtbx/diffBragg/src/diffBragg_kokkos_kernel.cpp b/simtbx/diffBragg/src/diffBragg_kokkos_kernel.cpp index 69750ad9be..5b1acf243f 100644 --- a/simtbx/diffBragg/src/diffBragg_kokkos_kernel.cpp +++ b/simtbx/diffBragg/src/diffBragg_kokkos_kernel.cpp @@ -2,11 +2,6 @@ #include "diffBraggKOKKOS.h" #include -// using ::Kokkos::Experimental::exp; -// using ::Kokkos::Experimental::sin; -// using ::Kokkos::Experimental::cos; -// using ::Kokkos::Experimental::sqrt; - void kokkos_sum_over_steps( int Npix_to_model, vector_uint_t panels_fasts_slows, @@ -29,6 +24,8 @@ void kokkos_sum_over_steps( vector_cudareal_t d_panel_orig_images, vector_cudareal_t d2_panel_orig_images, vector_cudareal_t d_fp_fdp_images, + vector_manager_t manager_dI, + vector_manager_t manager_dI2, const int Nsteps, int printout_fpixel, int printout_spixel, @@ -99,15 +96,16 @@ void kokkos_sum_over_steps( bool compute_curvatures, const vector_cudareal_t FhklLinear, const vector_cudareal_t Fhkl2Linear, - vector_bool_t refine_Bmat, - vector_bool_t refine_Ncells, - bool refine_Ncells_def, - vector_bool_t refine_panel_origin, - vector_bool_t refine_panel_rot, - bool refine_fcell, - vector_bool_t refine_lambda, - bool refine_eta, - vector_bool_t refine_Umat, + const uint32_t refine_flag, + // vector_bool_t refine_Bmat, + // vector_bool_t refine_Ncells, + // bool refine_Ncells_def, + // vector_bool_t refine_panel_origin, + // vector_bool_t refine_panel_rot, + // bool refine_fcell, + // vector_bool_t refine_lambda, + // bool refine_eta, + // vector_bool_t refine_Umat, const vector_cudareal_t fdet_vectors, const vector_cudareal_t sdet_vectors, const vector_cudareal_t odet_vectors, @@ -124,7 +122,7 @@ void kokkos_sum_over_steps( const vector_cudareal_t fpfdp_derivs, const vector_cudareal_t atom_data, int num_atoms, - bool refine_fp_fdp, + // bool refine_fp_fdp, const vector_int_t nominal_hkl, bool use_nominal_hkl, KOKKOS_MAT3 anisoU, @@ -133,9 +131,9 @@ void kokkos_sum_over_steps( bool use_diffuse, vector_cudareal_t d_diffuse_gamma_images, vector_cudareal_t d_diffuse_sigma_images, - bool refine_diffuse, + // bool refine_diffuse, bool gamma_miller_units, - bool refine_Icell, + // bool refine_Icell, bool save_wavelenimage, int laue_group_num, int stencil_size, @@ -150,91 +148,10 @@ void kokkos_sum_over_steps( const vector_int_t data_freq, const vector_bool_t data_trusted, const vector_int_t FhklLinear_ASUid, - const vector_cudareal_t Fhkl_channels, + const vector_int_t Fhkl_channels, const vector_cudareal_t Fhkl_scale, vector_cudareal_t Fhkl_scale_deriv) { // BEGIN GPU kernel - // int tid = blockIdx.x * blockDim.x + threadIdx.x; - // int thread_stride = blockDim.x * gridDim.x; - // __shared__ bool s_Fhkl_channels_empty; - // __shared__ bool s_Fhkl_have_scale_factors; - // __shared__ bool s_Fhkl_gradient_mode; - // __shared__ bool s_Fhkl_errors_mode; - // __shared__ int s_Num_ASU; - // __shared__ bool s_refine_Icell; - // __shared__ bool s_use_diffuse; - // __shared__ bool s_use_nominal_hkl; - // __shared__ bool s_refine_fp_fdp; - // __shared__ bool s_complex_miller; - // __shared__ int s_num_atoms; - // __shared__ bool s_aniso_eta; - // __shared__ bool s_no_Nabc_scale; - // __shared__ bool s_compute_curvatures; - // __shared__ KOKKOS_MAT3 s_Ot; - // __shared__ bool s_refine_diffuse; - // __shared__ bool s_gamma_miller_units; - // __shared__ KOKKOS_MAT3 _NABC; - // __shared__ KOKKOS_MAT3 s_dN; - // __shared__ CUDAREAL C; - // __shared__ CUDAREAL two_C; - // __shared__ KOKKOS_MAT3 Bmat_realspace; - // __shared__ KOKKOS_MAT3 Amat_init; - //__shared__ CUDAREAL s_Na; - //__shared__ CUDAREAL s_Nb; - //__shared__ CUDAREAL s_Nc; - // __shared__ CUDAREAL s_NaNbNc_squared; // unused? - // __shared__ int s_h_max, s_k_max, s_l_max, s_h_min, s_k_min, s_l_min, s_k_range, s_l_range; - // __shared__ int s_sources, s_mosaic_domains; - // __shared__ CUDAREAL s_detector_attnlen, s_lambda0, s_lambda1; - // __shared__ bool s_printout; - // __shared__ KOKKOS_VEC3 s_polarization_axis; - - // __shared__ bool s_refine_Umat[3]; - // __shared__ bool s_refine_panel_origin[3]; - // __shared__ bool s_refine_panel_rot[3]; - // __shared__ bool s_refine_Ncells[3]; - // __shared__ bool s_refine_eta; - // __shared__ bool s_refine_Ncells_def; - // __shared__ bool s_refine_fcell; - // __shared__ bool s_refine_Bmat[6]; - // __shared__ bool s_refine_lambda[2]; - // __shared__ double s_NABC_det, s_NABC_det_sq; - // extern __shared__ CUDAREAL det_vecs[]; - //__shared__ int det_stride; - - // TODO can we get speed gains by dividing up the following definitions over more threads ? - // if (threadIdx.x == 0) { - // for (int i = 0; i < 3; i++) { - // s_refine_Ncells[i] = refine_Ncells[i]; - // s_refine_Umat[i] = refine_Umat[i]; - // s_refine_panel_origin[i] = refine_panel_origin[i]; - // s_refine_panel_rot[i] = refine_panel_rot[i]; - // } - // s_Fhkl_channels_empty = Fhkl_channels_empty; - // s_Fhkl_have_scale_factors = Fhkl_have_scale_factors; - // s_Fhkl_gradient_mode = Fhkl_gradient_mode; - // s_Fhkl_errors_mode = Fhkl_errors_mode; - // s_Num_ASU = Num_ASU; - // s_refine_Icell = refine_Icell; - // s_use_nominal_hkl = use_nominal_hkl; - // s_aniso_eta = aniso_eta; - // s_no_Nabc_scale = no_Nabc_scale; - // s_complex_miller = complex_miller; - // s_refine_lambda[0] = refine_lambda[0]; - // s_refine_lambda[1] = refine_lambda[1]; - // for (int i = 0; i < 6; i++) { - // s_refine_Bmat[i] = refine_Bmat[i]; - // } - // s_use_diffuse = use_diffuse; - // s_num_atoms = num_atoms; - // s_refine_fcell = refine_fcell; - // s_refine_eta = refine_eta; - // s_refine_Ncells_def = refine_Ncells_def; - // s_compute_curvatures = compute_curvatures; - // s_refine_fp_fdp = refine_fp_fdp; - // s_refine_diffuse = refine_diffuse; - // s_gamma_miller_units = gamma_miller_units; - const KOKKOS_MAT3 Bmat_realspace = eig_B * 1e10; const KOKKOS_MAT3 eig_Otranspose = eig_O.transpose(); const KOKKOS_MAT3 Amat_init = eig_U * Bmat_realspace * eig_Otranspose; @@ -245,1027 +162,2325 @@ void kokkos_sum_over_steps( const CUDAREAL C = 2 / 0.63 * fudge; const CUDAREAL two_C = 2 * C; KOKKOS_MAT3 anisoG_local; + CUDAREAL anisoG_determ = 0; KOKKOS_MAT3 anisoU_local; - KOKKOS_MAT3 laue_mats[24]; - KOKKOS_MAT3 dG_dgam[3]; + vector_mat3_t laue_mats = vector_mat3_t("laue_mats", 24); + vector_vec3_t dG_dgam = vector_vec3_t("dG_dgam", 3); + vector_cudareal_t dG_trace = vector_cudareal_t("dG_trace", 3); int num_laue_mats = 0; int dhh = 0, dkk = 0, dll = 0; - KOKKOS_VEC3 Hmin, Hmax, dHH, Hrange; - // s_Na = Na; - // s_Nb = Nb; - // s_Nc = Nc; - // s_NaNbNc_squared = (Na * Nb * Nc); - // s_NaNbNc_squared *= s_NaNbNc_squared; - // s_h_max = h_max; - // s_k_max = k_max; - // s_l_max = l_max; - // s_h_min = h_min; - // s_k_min = k_min; - // s_l_min = l_min; - // s_h_range = h_range; - // s_k_range = k_range; - // s_l_range = l_range; - - // s_oversample = oversample; - // s_detector_thicksteps = detector_thicksteps; - // s_sources = sources; - // s_mosaic_domains = mosaic_domains; - // s_detector_thickstep = detector_thickstep; - // s_detector_attnlen = detector_attnlen; - // s_subpixel_size = subpixel_size; - // s_pixel_size = pixel_size; - // s_detector_thick = _detector_thick; - // s_lambda0 = lambda0; - // s_lambda1 = lambda1; - // s_oversample_omega = _oversample_omega; - // s_printout = printout; - // s_printout_fpixel = printout_fpixel; - // s_printout_spixel = printout_spixel; - // s_default_F = default_F; - // s_verbose = verbose; - // s_polarization_axis = polarization_axis; - // s_kahn_factor = kahn_factor; - // s_nopolar = nopolar; - // sX0 = source_X[0]; - // sY0 = source_Y[0]; - // sZ0 = source_Z[0]; - // s_Nsteps = Nsteps; - - // } + + Kokkos::View UMATS_prime("UMATS_prime", mosaic_domains); + Kokkos::View UMATS_dbl_prime("UMATS_dbl_prime", mosaic_domains); + Kokkos::View BMATS_prime("BMATS_prime", mosaic_domains); + Kokkos::View BMATS_dbl_prime("BMATS_dbl_prime", mosaic_domains); + + Kokkos::parallel_for("prepare_UMATS", mosaic_domains, KOKKOS_LAMBDA(const int& _mos_tic) { + const KOKKOS_MAT3 UBOt = Amat_init; + UMATS_prime(_mos_tic, 0) = _NABC * (UMATS(_mos_tic) * dRotMats(0) * RotMats(1) * RotMats(2) * UBOt).transpose(); + UMATS_prime(_mos_tic, 1) = _NABC * (UMATS(_mos_tic) * RotMats(0) * dRotMats(1) * RotMats(2) * UBOt).transpose(); + UMATS_prime(_mos_tic, 2) = _NABC * (UMATS(_mos_tic) * RotMats(0) * RotMats(1) * dRotMats(2) * UBOt).transpose(); + + UMATS_dbl_prime(_mos_tic, 0) = _NABC * (UMATS(_mos_tic) * d2RotMats(0) * RotMats(1) * RotMats(2) * UBOt).transpose(); + UMATS_dbl_prime(_mos_tic, 1) = _NABC * (UMATS(_mos_tic) * RotMats(0) * d2RotMats(1) * RotMats(2) * UBOt).transpose(); + UMATS_dbl_prime(_mos_tic, 2) = _NABC * (UMATS(_mos_tic) * RotMats(0) * RotMats(1) * d2RotMats(2) * UBOt).transpose(); + + for (int i_uc=0; i_uc<6; i_uc++) { + BMATS_prime(_mos_tic, i_uc) = _NABC * (UMATS_RXYZ(_mos_tic) * eig_U * dB_mats(i_uc) * eig_O.transpose()).transpose(); + BMATS_dbl_prime(_mos_tic, i_uc) = _NABC * (UMATS_RXYZ(_mos_tic) * eig_U * dB2_mats(i_uc) * eig_O.transpose()).transpose(); + } + }); if (use_diffuse){ anisoG_local = anisoG; anisoU_local = anisoU; - num_laue_mats = gen_laue_mats(laue_group_num, laue_mats, rotate_principal_axes); - - for (int i_gam=0; i_gam<3; i_gam++){ - dG_dgam[i_gam] << 0,0,0,0,0,0,0,0,0; - dG_dgam[i_gam](i_gam, i_gam) = 1; + if (laue_group_num < 1 || laue_group_num >14 ){ + throw std::string("Laue group number not in range 1-14"); } + if (gamma_miller_units){ anisoG_local = anisoG_local * Bmat_realspace; + } + Kokkos::parallel_reduce("prepare diffuse mats", 1, KOKKOS_LAMBDA (const int& i, int& num_laue_mats_temp){ + num_laue_mats_temp = gen_laue_mats(laue_group_num, laue_mats, rotate_principal_axes); + // KOKKOS_MAT3 rotate_principal_axes; + // rotate_principal_axes << 0.70710678, -0.70710678, 0., 0.70710678, 0.70710678, 0., 0., 0., 1.; + + for ( int iL = 0; iL < num_laue_mats_temp; iL++ ){ + laue_mats(iL) = Ainv * laue_mats(iL); + } + // printf("Bmat ="); + // for (int i=0; i<9; ++i) { + // printf(" %g", Bmat_realspace[i]); + // } + // printf("\n"); + const KOKKOS_MAT3 Ginv = anisoG_local.inverse(); + // printf("Ginv ="); + // for (int i=0; i<9; ++i) { + // printf(" %g", Ginv[i]); + // } + // printf("\n"); + const KOKKOS_MAT3 dG = Bmat_realspace * Ginv; + // printf("dG ="); + // for (int i=0; i<9; ++i) { + // printf(" %g", dG[i]); + // } + // printf("\n"); for (int i_gam=0; i_gam<3; i_gam++){ - dG_dgam[i_gam] = dG_dgam[i_gam] * Bmat_realspace; + if (gamma_miller_units) { + dG_dgam(i_gam) = KOKKOS_VEC3(Bmat_realspace(i_gam, 0), Bmat_realspace(i_gam, 1), Bmat_realspace(i_gam, 2)); + } else { + dG_dgam(i_gam)[i_gam] = 1; + } + KOKKOS_MAT3 temp_dgam; + temp_dgam(i_gam, 0) = dG_dgam(i_gam)[0]; + temp_dgam(i_gam, 1) = dG_dgam(i_gam)[1]; + temp_dgam(i_gam, 2) = dG_dgam(i_gam)[2]; + dG_trace(i_gam) = (Ginv*temp_dgam).trace(); + // printf("TRACE %g\n", dG_trace(i_gam)); + // printf("dgam ="); + // for (int i=0; i<9; ++i) { + // printf(" %g", temp_dgam[i]); + // } + // printf("\n"); + + // dG(i_gam, i_gam); } - } + }, num_laue_mats); + anisoG_determ = anisoG_local.determinant(); dhh = dkk = dll = stencil_size; // Limits of stencil for diffuse calc } - Hmin << h_min, k_min, l_min; - Hmax << h_max, k_max, l_max; - dHH << dhh, dkk, dll; - Hrange << h_range, k_range, l_range; + const KOKKOS_VEC3 dHH (dhh, dkk, dll); const CUDAREAL overall_scale = r_e_sqr * spot_scale * fluence / Nsteps; + const CUDAREAL detector_attnlen_r = (detector_attnlen>0) ? 1 / detector_attnlen : 0; + Kokkos::parallel_for( "sum_over_steps", Npix_to_model, KOKKOS_LAMBDA(const int& pixIdx) { - // __syncthreads(); - // for (int pixIdx=tid; pixIdx < Npix_to_model; pixIdx+= thread_stride){ - if (using_trusted_mask) { - if (!data_trusted(pixIdx)) - return; - } - int _pid = panels_fasts_slows(pixIdx * 3); - int _fpixel = panels_fasts_slows(pixIdx * 3 + 1); - int _spixel = panels_fasts_slows(pixIdx * 3 + 2); - - CUDAREAL Fhkl_deriv_coef=0; - CUDAREAL Fhkl_hessian_coef=0; - if (Fhkl_gradient_mode) { - CUDAREAL u = data_residual(pixIdx); - CUDAREAL one_by_v = 1/data_variance(pixIdx); - CUDAREAL Gterm = 1 - 2*u - u*u*one_by_v; - Fhkl_deriv_coef = 0.5 * Gterm*one_by_v / data_freq(pixIdx); - if (Fhkl_errors_mode) { - Fhkl_hessian_coef = -0.5*one_by_v*(one_by_v*Gterm - 2 - 2*u*one_by_v -u*u*one_by_v*one_by_v)/data_freq(pixIdx); - } + if (using_trusted_mask) { + if (!data_trusted(pixIdx)) + return; + } + const int _pid = panels_fasts_slows(pixIdx * 3); + const int _fpixel = panels_fasts_slows(pixIdx * 3 + 1); + const int _spixel = panels_fasts_slows(pixIdx * 3 + 2); + + CUDAREAL Fhkl_deriv_coef=0; + CUDAREAL Fhkl_hessian_coef=0; + if (Fhkl_gradient_mode) { + CUDAREAL u = data_residual(pixIdx); + CUDAREAL one_by_v = 1/data_variance(pixIdx); + CUDAREAL Gterm = 1 - 2*u - u*u*one_by_v; + Fhkl_deriv_coef = 0.5 * Gterm*one_by_v / data_freq(pixIdx); + if (Fhkl_errors_mode) { + Fhkl_hessian_coef = -0.5*one_by_v*(one_by_v*Gterm - 2 - 2*u*one_by_v -u*u*one_by_v*one_by_v)/data_freq(pixIdx); } + } - // int fcell_idx=1; - int nom_h = 0, nom_k = 0, nom_l = 0; - if (use_nominal_hkl) { - nom_h = nominal_hkl(pixIdx * 3); - nom_k = nominal_hkl(pixIdx * 3 + 1); - nom_l = nominal_hkl(pixIdx * 3 + 2); - } - CUDAREAL close_distance = close_distances(_pid); - - // reset photon count for this pixel - double _I = 0; - double Ilambda = 0; - - // reset derivative photon counts for the various parameters - double rot_manager_dI[3] = {0, 0, 0}; - double rot_manager_dI2[3] = {0, 0, 0}; - double ucell_manager_dI[6] = {0, 0, 0, 0, 0, 0}; - double ucell_manager_dI2[6] = {0, 0, 0, 0, 0, 0}; - double Ncells_manager_dI[6] = {0, 0, 0, 0, 0, 0}; - double Ncells_manager_dI2[6] = {0, 0, 0, 0, 0, 0}; - double pan_orig_manager_dI[3] = {0, 0, 0}; - double pan_orig_manager_dI2[3] = {0, 0, 0}; - double pan_rot_manager_dI[3] = {0, 0, 0}; - double pan_rot_manager_dI2[3] = {0, 0, 0}; - double fcell_manager_dI = 0; - double fcell_manager_dI2 = 0; - double eta_manager_dI[3] = {0, 0, 0}; - double eta_manager_dI2[3] = {0, 0, 0}; - double lambda_manager_dI[2] = {0, 0}; - double lambda_manager_dI2[2] = {0, 0}; - double fp_fdp_manager_dI[2] = {0, 0}; - double dI_diffuse[6] = {0, 0, 0, 0, 0, 0}; - - for (int _subS = 0; _subS < oversample; ++_subS) { - for (int _subF = 0; _subF < oversample; ++_subF) { - // absolute mm position on detector (relative to its origin) - CUDAREAL _Fdet = - subpixel_size * (_fpixel * oversample + _subF) + subpixel_size / 2.0; - CUDAREAL _Sdet = - subpixel_size * (_spixel * oversample + _subS) + subpixel_size / 2.0; - - // assume "distance" is to the front of the detector sensor layer - int pid_x = _pid * 3; - int pid_y = _pid * 3 + 1; - int pid_z = _pid * 3 + 2; - - CUDAREAL fx = fdet_vectors(pid_x); - CUDAREAL fy = fdet_vectors(pid_y); - CUDAREAL fz = fdet_vectors(pid_z); - CUDAREAL sx = sdet_vectors(pid_x); - CUDAREAL sy = sdet_vectors(pid_y); - CUDAREAL sz = sdet_vectors(pid_z); - CUDAREAL ox = odet_vectors(pid_x); - CUDAREAL oy = odet_vectors(pid_y); - CUDAREAL oz = odet_vectors(pid_z); - CUDAREAL px = pix0_vectors(pid_x); - CUDAREAL py = pix0_vectors(pid_y); - CUDAREAL pz = pix0_vectors(pid_z); - - KOKKOS_VEC3 _o_vec(ox, oy, oz); - - for (int _thick_tic = 0; _thick_tic < detector_thicksteps; ++_thick_tic) { - CUDAREAL _Odet = _thick_tic * detector_thickstep; - - CUDAREAL pixposX = _Fdet * fx + _Sdet * sx + _Odet * ox + px; - CUDAREAL pixposY = _Fdet * fy + _Sdet * sy + _Odet * oy + py; - CUDAREAL pixposZ = _Fdet * fz + _Sdet * sz + _Odet * oz + pz; - KOKKOS_VEC3 _pixel_pos(pixposX, pixposY, pixposZ); - - CUDAREAL _airpath = _pixel_pos.length(); - KOKKOS_VEC3 _diffracted = _pixel_pos.get_unit_vector(); - - // solid angle subtended by a pixel: (pix/airpath)^2*cos(2theta) - CUDAREAL _omega_pixel = pixel_size * pixel_size / _airpath / _airpath * - close_distance / _airpath; - - // option to turn off obliquity effect, inverse-square-law only - if (point_pixel) - _omega_pixel = 1.0 / _airpath / _airpath; - - // now calculate detector thickness effects - CUDAREAL _capture_fraction = 1; - - if (detector_thick > 0.0 && detector_attnlen > 0.0) { - // inverse of effective thickness increase - CUDAREAL _parallax = _diffracted.dot(_o_vec); - _capture_fraction = ::Kokkos::Experimental::exp( - -_thick_tic * detector_thickstep / - detector_attnlen / _parallax) - - ::Kokkos::Experimental::exp( - -(_thick_tic + 1) * detector_thickstep / - detector_attnlen / _parallax); + // int fcell_idx=1; + int nom_h = 0, nom_k = 0, nom_l = 0; + if (use_nominal_hkl) { + nom_h = nominal_hkl(pixIdx * 3); + nom_k = nominal_hkl(pixIdx * 3 + 1); + nom_l = nominal_hkl(pixIdx * 3 + 2); + } + CUDAREAL close_distance = close_distances(_pid); + + // reset photon count for this pixel + double _I = 0; + double Ilambda = 0; + + kokkos_manager dI, dI2; + dI.reset(); + dI2.reset(); + + for (int _subS = 0; _subS < oversample; ++_subS) { + for (int _subF = 0; _subF < oversample; ++_subF) { + // absolute mm position on detector (relative to its origin) + CUDAREAL _Fdet = + subpixel_size * (_fpixel * oversample + _subF) + subpixel_size / 2.0; + CUDAREAL _Sdet = + subpixel_size * (_spixel * oversample + _subS) + subpixel_size / 2.0; + + // assume "distance" is to the front of the detector sensor layer + int pid_x = _pid * 3; + int pid_y = _pid * 3 + 1; + int pid_z = _pid * 3 + 2; + + + CUDAREAL fx = fdet_vectors(pid_x); + CUDAREAL fy = fdet_vectors(pid_y); + CUDAREAL fz = fdet_vectors(pid_z); + CUDAREAL sx = sdet_vectors(pid_x); + CUDAREAL sy = sdet_vectors(pid_y); + CUDAREAL sz = sdet_vectors(pid_z); + CUDAREAL ox = odet_vectors(pid_x); + CUDAREAL oy = odet_vectors(pid_y); + CUDAREAL oz = odet_vectors(pid_z); + CUDAREAL px = pix0_vectors(pid_x); + CUDAREAL py = pix0_vectors(pid_y); + CUDAREAL pz = pix0_vectors(pid_z); + KOKKOS_VEC3 _o_vec(ox, oy, oz); + + for (int _thick_tic = 0; _thick_tic < detector_thicksteps; ++_thick_tic) { + + CUDAREAL _Odet = _thick_tic * detector_thickstep; + + CUDAREAL pixposX = _Fdet * fx + _Sdet * sx + _Odet * ox + px; + CUDAREAL pixposY = _Fdet * fy + _Sdet * sy + _Odet * oy + py; + CUDAREAL pixposZ = _Fdet * fz + _Sdet * sz + _Odet * oz + pz; + KOKKOS_VEC3 _pixel_pos(pixposX, pixposY, pixposZ); + + CUDAREAL _airpath_r = 1 / _pixel_pos.length(); + KOKKOS_VEC3 _diffracted = _pixel_pos.get_unit_vector(); + + const CUDAREAL close_distance = close_distances(_pid); + + // solid angle subtended by a pixel: (pix/airpath)^2*cos(2theta) + CUDAREAL _omega_pixel = pixel_size * pixel_size * _airpath_r * _airpath_r * + close_distance * _airpath_r; + + // option to turn off obliquity effect, inverse-square-law only + if (point_pixel) + _omega_pixel = _airpath_r * _airpath_r; + + // now calculate detector thickness effects + CUDAREAL _capture_fraction = 1; + + CUDAREAL previous_layer = 1.0; + if (detector_thick > 0.0 && detector_attnlen_r > 0.0) { + // inverse of effective thickness increase + KOKKOS_VEC3 _o_vec(ox, oy, oz); + CUDAREAL _parallax = _diffracted.dot(_o_vec); + CUDAREAL current_layer = ::Kokkos::exp( + -(_thick_tic + 1) * detector_thickstep * + detector_attnlen_r / _parallax); + _capture_fraction = previous_layer - current_layer; + previous_layer = current_layer; + } + + for (int _source = 0; _source < sources; ++_source) { + + KOKKOS_VEC3 _incident( + -source_X(_source), -source_Y(_source), -source_Z(_source)); + CUDAREAL _lambda = source_lambda(_source); + CUDAREAL sI = source_I(_source); + CUDAREAL lambda_ang = _lambda * 1e10; + if (use_lambda_coefficients) { + lambda_ang = lambda0 + lambda1 * lambda_ang; + _lambda = lambda_ang * 1e-10; } - CUDAREAL cap_frac_times_omega = _capture_fraction * _omega_pixel; - - for (int _source = 0; _source < sources; ++_source) { - KOKKOS_VEC3 _incident( - -source_X(_source), -source_Y(_source), -source_Z(_source)); - CUDAREAL _lambda = source_lambda(_source); - CUDAREAL sI = source_I(_source); - CUDAREAL lambda_ang = _lambda * 1e10; - if (use_lambda_coefficients) { - lambda_ang = lambda0 + lambda1 * lambda_ang; - _lambda = lambda_ang * 1e-10; - } - // polarization - CUDAREAL polar_for_Fhkl_grad=1; - if (!nopolar && Fhkl_gradient_mode){ - //polar_for_Fhkl_grad = diffBragg_gpu_kernel_polarization(_incident, _diffracted, - // s_polarization_axis, s_kahn_factor); - // component of diffracted unit vector along incident beam unit vector - CUDAREAL cos2theta = _incident.dot(_diffracted); - CUDAREAL cos2theta_sqr = cos2theta*cos2theta; - CUDAREAL sin2theta_sqr = 1-cos2theta_sqr; - - CUDAREAL _psi=0; - if(kahn_factor != 0.0){ - // cross product to get "vertical" axis that is orthogonal to the cannonical "polarization" - KOKKOS_VEC3 B_in = polarization_axis.cross(_incident); - // cross product with incident beam to get E-vector direction - KOKKOS_VEC3 E_in = _incident.cross(B_in); - // get components of diffracted ray projected onto the E-B plane - CUDAREAL _kEi = _diffracted.dot(E_in); - CUDAREAL _kBi = _diffracted.dot(B_in); - // compute the angle of the diffracted ray projected onto the incident E-B plane - _psi = -atan2(_kBi,_kEi); + // polarization + CUDAREAL polar_for_Fhkl_grad=1; + if (!nopolar && Fhkl_gradient_mode){ + + // component of diffracted unit vector along incident beam unit vector + CUDAREAL cos2theta = _incident.dot(_diffracted); + CUDAREAL cos2theta_sqr = cos2theta*cos2theta; + CUDAREAL sin2theta_sqr = 1-cos2theta_sqr; + + CUDAREAL cos2psi=0; + if(kahn_factor != 0.0){ + // cross product to get "vertical" axis that is orthogonal to the cannonical "polarization" + KOKKOS_VEC3 B_in = polarization_axis.cross(_incident); + // cross product with incident beam to get E-vector direction + KOKKOS_VEC3 E_in = _incident.cross(B_in); + // get components of diffracted ray projected onto the E-B plane + CUDAREAL _kEi = _diffracted.dot(E_in); + CUDAREAL _kBi = _diffracted.dot(B_in); + // compute the angle of the diffracted ray projected onto the incident E-B plane + // calculate cos(2 * atan2(_kBi, _kEi)) + if (_kEi!=0) { + CUDAREAL ratio = _kBi / _kEi; + cos2psi = (1 - ratio*ratio) / (1 + ratio*ratio); + } else { + cos2psi = -1; } - // correction for polarized incident beam - polar_for_Fhkl_grad = 0.5*(1.0 + cos2theta_sqr - kahn_factor*cos(2*_psi)*sin2theta_sqr); + } + // correction for polarized incident beam + polar_for_Fhkl_grad = 0.5*(1.0 + cos2theta_sqr - kahn_factor*cos2psi*sin2theta_sqr); + } + KOKKOS_VEC3 _scattering = (_diffracted - _incident) / _lambda; + + KOKKOS_VEC3 q_vec = _scattering * 1e-10; + + // TODO rename + CUDAREAL texture_scale = _capture_fraction * _omega_pixel * sI; + + for (int _mos_tic = 0; _mos_tic < mosaic_domains; ++_mos_tic) { + const KOKKOS_MAT3 UBO = Amatrices(_mos_tic); + + KOKKOS_VEC3 H_vec = UBO * q_vec; + CUDAREAL _h = H_vec[0]; + CUDAREAL _k = H_vec[1]; + CUDAREAL _l = H_vec[2]; + + int _h0 = ceil(_h - 0.5); + int _k0 = ceil(_k - 0.5); + int _l0 = ceil(_l - 0.5); + + KOKKOS_VEC3 H0(_h0, _k0, _l0); + + KOKKOS_VEC3 delta_H = H_vec - H0; + KOKKOS_VEC3 V = _NABC * delta_H; + CUDAREAL _hrad_sqr = V.length_sqr(); + CUDAREAL exparg = _hrad_sqr * C / 2; + CUDAREAL I0 = 0; + + if (exparg < 35) + if (no_Nabc_scale) + I0 = ::Kokkos::exp(-2 * exparg); + else + I0 = (NABC_det_sq) * + ::Kokkos::exp(-2 * exparg); + + // are we doing diffuse scattering + CUDAREAL step_diffuse_param[6] = {0, 0, 0, 0, 0, 0}; + if (use_diffuse) { + calc_diffuse_at_hkl(H_vec,H0,dHH,h_min,k_min,l_min,h_max,k_max,l_max,h_range,k_range,l_range,Ainv,FhklLinear,num_laue_mats,laue_mats,anisoG_local,dG_trace,anisoG_determ,anisoU_local,dG_dgam,(refine_flag & REFINE_DIFFUSE)>0,&I0,step_diffuse_param); + } // end s_use_diffuse outer + + CUDAREAL _F_cell = default_F; + CUDAREAL _F_cell2 = 0; + int i_hklasu=0; + + if ((_h0 <= h_max) && (_h0 >= h_min) && + (_k0 <= k_max) && (_k0 >= k_min) && + (_l0 <= l_max) && (_l0 >= l_min)) { + int Fhkl_linear_index = (_h0 - h_min) * k_range * l_range + + (_k0 - k_min) * l_range + (_l0 - l_min); + //_F_cell = __ldg(&FhklLinear[Fhkl_linear_index]); + _F_cell = FhklLinear(Fhkl_linear_index); + // if (complex_miller) _F_cell2 = + // __ldg(&Fhkl2Linear[Fhkl_linear_index]); + if (complex_miller) + _F_cell2 = Fhkl2Linear(Fhkl_linear_index); + if (Fhkl_have_scale_factors) + i_hklasu = FhklLinear_ASUid(Fhkl_linear_index); } - KOKKOS_VEC3 _scattering = (_diffracted - _incident) / _lambda; - - KOKKOS_VEC3 q_vec(_scattering[0], _scattering[1], _scattering[2]); - q_vec *= 1e-10; - - // TODO rename - CUDAREAL texture_scale = 1; - texture_scale *= cap_frac_times_omega; - texture_scale *= sI; + CUDAREAL c_deriv_Fcell = 0; + CUDAREAL d_deriv_Fcell = 0; + if (complex_miller) { + CUDAREAL c_deriv_Fcell_real = 0; + CUDAREAL c_deriv_Fcell_imag = 0; + CUDAREAL d_deriv_Fcell_real = 0; + CUDAREAL d_deriv_Fcell_imag = 0; + if (num_atoms > 0) { + CUDAREAL S_2 = (q_vec[0] * q_vec[0] + + q_vec[1] * q_vec[1] + + q_vec[2] * q_vec[2]); + + // fp is always followed by the fdp value + CUDAREAL val_fp = fpfdp(2 * _source); + CUDAREAL val_fdp = fpfdp(2 * _source + 1); + + CUDAREAL c_deriv_prime = 0; + CUDAREAL c_deriv_dblprime = 0; + CUDAREAL d_deriv_prime = 0; + CUDAREAL d_deriv_dblprime = 0; + if (refine_flag & REFINE_FP_FDP) { + // currently only supports two parameter model + int d_idx = 2 * _source; + c_deriv_prime = fpfdp_derivs(d_idx); + c_deriv_dblprime = fpfdp_derivs(d_idx + 1); + d_deriv_prime = fpfdp_derivs(d_idx + 2 * sources); + d_deriv_dblprime = + fpfdp_derivs(d_idx + 1 + 2 * sources); + } - for (int _mos_tic = 0; _mos_tic < mosaic_domains; ++_mos_tic) { - int amat_idx = _mos_tic; - KOKKOS_MAT3 UBO = Amatrices(amat_idx); + for (int i_atom = 0; i_atom < num_atoms; i_atom++) { + // fractional atomic coordinates + CUDAREAL atom_x = atom_data(i_atom * 5); + CUDAREAL atom_y = atom_data(i_atom * 5 + 1); + CUDAREAL atom_z = atom_data(i_atom * 5 + 2); + CUDAREAL B = atom_data(i_atom * 5 + 3); // B factor + B = ::Kokkos::exp( + -B * S_2 / 4.0); // TODO: speed me up? + CUDAREAL occ = atom_data(i_atom * 5 + 4); // occupancy + CUDAREAL r_dot_h = + _h0 * atom_x + _k0 * atom_y + _l0 * atom_z; + CUDAREAL phase = 2 * M_PI * r_dot_h; + CUDAREAL s_rdoth = ::Kokkos::sin(phase); + CUDAREAL c_rdoth = ::Kokkos::cos(phase); + CUDAREAL Bocc = B * occ; + CUDAREAL BC = B * c_rdoth; + CUDAREAL BS = B * s_rdoth; + CUDAREAL real_part = BC * val_fp - BS * val_fdp; + CUDAREAL imag_part = BS * val_fp + BC * val_fdp; + _F_cell += real_part; + _F_cell2 += imag_part; + if (refine_flag & REFINE_FP_FDP) { + c_deriv_Fcell_real += + BC * c_deriv_prime - BS * c_deriv_dblprime; + c_deriv_Fcell_imag += + BS * c_deriv_prime + BC * c_deriv_dblprime; + + d_deriv_Fcell_real += + BC * d_deriv_prime - BS * d_deriv_dblprime; + d_deriv_Fcell_imag += + BS * d_deriv_prime + BC * d_deriv_dblprime; + } + } + } + CUDAREAL Freal = _F_cell; + CUDAREAL Fimag = _F_cell2; + _F_cell = + ::Kokkos::sqrt(Freal * Freal + Fimag * Fimag); + if (refine_flag & REFINE_FP_FDP) { + c_deriv_Fcell = + Freal * c_deriv_Fcell_real + Fimag * c_deriv_Fcell_imag; + d_deriv_Fcell = + Freal * d_deriv_Fcell_real + Fimag * d_deriv_Fcell_imag; + } + } + if (!oversample_omega && ! Fhkl_gradient_mode) + _omega_pixel = 1; + + CUDAREAL _I_cell = _F_cell; + if (!(refine_flag & REFINE_ICELL)) + _I_cell *= _F_cell; + CUDAREAL hkl=1; + int Fhkl_channel=0; + if (! Fhkl_channels_empty) + Fhkl_channel = Fhkl_channels(_source); + if (Fhkl_have_scale_factors) + hkl = Fhkl_scale(i_hklasu + Fhkl_channel*Num_ASU); + if (Fhkl_gradient_mode){ + CUDAREAL Fhkl_deriv_scale = overall_scale*polar_for_Fhkl_grad; + CUDAREAL I_noFcell=texture_scale*I0; + CUDAREAL dfhkl = I_noFcell*_I_cell * Fhkl_deriv_scale; + CUDAREAL grad_incr = dfhkl*Fhkl_deriv_coef; + int fhkl_grad_idx=i_hklasu + Fhkl_channel*Num_ASU; + + if (Fhkl_errors_mode){ + // here we hi-kack the Fhkl_scale_deriv array, if computing errors, in order to store the hessian terms + // if we are getting the hessian terms, we no longer need the gradients (e.g. by this point we are done refininig) + CUDAREAL hessian_incr = Fhkl_hessian_coef*dfhkl*dfhkl; + ::Kokkos::atomic_add(&Fhkl_scale_deriv(fhkl_grad_idx), hessian_incr); + } + else{ + ::Kokkos::atomic_add(&Fhkl_scale_deriv(fhkl_grad_idx), grad_incr); + } + continue; + } - KOKKOS_VEC3 H_vec = UBO * q_vec; - CUDAREAL _h = H_vec[0]; - CUDAREAL _k = H_vec[1]; - CUDAREAL _l = H_vec[2]; + CUDAREAL _I_total = hkl*_I_cell *I0; + CUDAREAL Iincrement = _I_total * texture_scale; + _I += Iincrement; + if (save_wavelenimage) + Ilambda += Iincrement * lambda_ang; + + if (refine_flag & REFINE_DIFFUSE) { + CUDAREAL step_scale = texture_scale * _F_cell * _F_cell; + for (int i_diff = 0; i_diff < 6; i_diff++) { + dI.diffuse[i_diff] += + step_scale * step_diffuse_param[i_diff]; + } + } - int _h0 = ceil(_h - 0.5); - int _k0 = ceil(_k - 0.5); - int _l0 = ceil(_l - 0.5); + //************************************************* + // START REFINEMENT - KOKKOS_VEC3 H0(_h0, _k0, _l0); + if (refine_flag & REFINE_FP_FDP) { + CUDAREAL I_noFcell = texture_scale * I0; + dI.fp_fdp[0] += 2 * I_noFcell * (c_deriv_Fcell); + dI.fp_fdp[1] += 2 * I_noFcell * (d_deriv_Fcell); + } - KOKKOS_VEC3 delta_H = H_vec - H0; - KOKKOS_VEC3 V = _NABC * delta_H; - CUDAREAL _hrad_sqr = V.dot(V); - CUDAREAL exparg = _hrad_sqr * C / 2; - CUDAREAL I0 = 0; + if (verbose > 3) + printf( + "hkl= %f %f %f hkl1= %d %d %d Fcell=%f\n", _h, _k, _l, + _h0, _k0, _l0, _F_cell); - if (exparg < 35) - if (no_Nabc_scale) - I0 = ::Kokkos::Experimental::exp(-2 * exparg); - else - I0 = (NABC_det_sq) * - ::Kokkos::Experimental::exp(-2 * exparg); - - // are we doing diffuse scattering - CUDAREAL step_diffuse_param[6] = {0, 0, 0, 0, 0, 0}; - if (use_diffuse) { - calc_diffuse_at_hkl(H_vec,H0,dHH,Hmin,Hmax,Hrange,Ainv,FhklLinear,num_laue_mats,laue_mats,anisoG_local,anisoU_local,dG_dgam,refine_diffuse,&I0,step_diffuse_param); - } // end s_use_diffuse outer - - CUDAREAL _F_cell = default_F; - CUDAREAL _F_cell2 = 0; - int i_hklasu=0; - - if ((_h0 <= h_max) && (_h0 >= h_min) && (_k0 <= k_max) && - (_k0 >= k_min) && (_l0 <= l_max) && (_l0 >= l_min)) { - int Fhkl_linear_index = (_h0 - h_min) * k_range * l_range + - (_k0 - k_min) * l_range + (_l0 - l_min); - //_F_cell = __ldg(&FhklLinear[Fhkl_linear_index]); - _F_cell = FhklLinear(Fhkl_linear_index); - // if (complex_miller) _F_cell2 = - // __ldg(&Fhkl2Linear[Fhkl_linear_index]); - if (complex_miller) - _F_cell2 = Fhkl2Linear(Fhkl_linear_index); - if (Fhkl_have_scale_factors) - i_hklasu = FhklLinear_ASUid(Fhkl_linear_index); + KOKKOS_MAT3 UBOt; + if (refine_flag & (REFINE_UMAT | REFINE_ETA)) { + UBOt = Amat_init; + } + if (refine_flag & REFINE_UMAT1) { + const KOKKOS_VEC3 dV = UMATS_prime(_mos_tic, 0) * q_vec; + const CUDAREAL V_dot_dV = V.dot(dV); + const CUDAREAL value = -two_C * V_dot_dV * Iincrement; + CUDAREAL value2 = 0; + if (compute_curvatures) { + const CUDAREAL dV_dot_dV = dV.length_sqr(); + const CUDAREAL dV2_dot_V = V.dot(UMATS_dbl_prime(_mos_tic, 0)*q_vec); + value2 = two_C * (two_C * V_dot_dV * V_dot_dV - dV2_dot_V - dV_dot_dV) * Iincrement; } - - CUDAREAL c_deriv_Fcell = 0; - CUDAREAL d_deriv_Fcell = 0; - if (complex_miller) { - CUDAREAL c_deriv_Fcell_real = 0; - CUDAREAL c_deriv_Fcell_imag = 0; - CUDAREAL d_deriv_Fcell_real = 0; - CUDAREAL d_deriv_Fcell_imag = 0; - if (num_atoms > 0) { - CUDAREAL S_2 = 1.e-20 * (_scattering[0] * _scattering[0] + - _scattering[1] * _scattering[1] + - _scattering[2] * _scattering[2]); - - // fp is always followed by the fdp value - CUDAREAL val_fp = fpfdp(2 * _source); - CUDAREAL val_fdp = fpfdp(2 * _source + 1); - - CUDAREAL c_deriv_prime = 0; - CUDAREAL c_deriv_dblprime = 0; - CUDAREAL d_deriv_prime = 0; - CUDAREAL d_deriv_dblprime = 0; - if (refine_fp_fdp) { - // currently only supports two parameter model - int d_idx = 2 * _source; - c_deriv_prime = fpfdp_derivs(d_idx); - c_deriv_dblprime = fpfdp_derivs(d_idx + 1); - d_deriv_prime = fpfdp_derivs(d_idx + 2 * sources); - d_deriv_dblprime = - fpfdp_derivs(d_idx + 1 + 2 * sources); - } - - for (int i_atom = 0; i_atom < num_atoms; i_atom++) { - // fractional atomic coordinates - CUDAREAL atom_x = atom_data(i_atom * 5); - CUDAREAL atom_y = atom_data(i_atom * 5 + 1); - CUDAREAL atom_z = atom_data(i_atom * 5 + 2); - CUDAREAL B = atom_data(i_atom * 5 + 3); // B factor - B = ::Kokkos::Experimental::exp( - -B * S_2 / 4.0); // TODO: speed me up? - CUDAREAL occ = atom_data(i_atom * 5 + 4); // occupancy - CUDAREAL r_dot_h = - _h0 * atom_x + _k0 * atom_y + _l0 * atom_z; - CUDAREAL phase = 2 * M_PI * r_dot_h; - CUDAREAL s_rdoth = ::Kokkos::Experimental::sin(phase); - CUDAREAL c_rdoth = ::Kokkos::Experimental::cos(phase); - CUDAREAL Bocc = B * occ; - CUDAREAL BC = B * c_rdoth; - CUDAREAL BS = B * s_rdoth; - CUDAREAL real_part = BC * val_fp - BS * val_fdp; - CUDAREAL imag_part = BS * val_fp + BC * val_fdp; - _F_cell += real_part; - _F_cell2 += imag_part; - if (refine_fp_fdp) { - c_deriv_Fcell_real += - BC * c_deriv_prime - BS * c_deriv_dblprime; - c_deriv_Fcell_imag += - BS * c_deriv_prime + BC * c_deriv_dblprime; - - d_deriv_Fcell_real += - BC * d_deriv_prime - BS * d_deriv_dblprime; - d_deriv_Fcell_imag += - BS * d_deriv_prime + BC * d_deriv_dblprime; - } - } - } - CUDAREAL Freal = _F_cell; - CUDAREAL Fimag = _F_cell2; - _F_cell = - ::Kokkos::Experimental::sqrt(Freal * Freal + Fimag * Fimag); - if (refine_fp_fdp) { - c_deriv_Fcell = - Freal * c_deriv_Fcell_real + Fimag * c_deriv_Fcell_imag; - d_deriv_Fcell = - Freal * d_deriv_Fcell_real + Fimag * d_deriv_Fcell_imag; + dI.rot[0] += value; + dI2.rot[0] += value2; + } + if (refine_flag & REFINE_UMAT2) { + KOKKOS_VEC3 dV = UMATS_prime(_mos_tic, 1) * q_vec; + CUDAREAL V_dot_dV = V.dot(dV); + CUDAREAL value = -two_C * V_dot_dV * Iincrement; + + CUDAREAL value2 = 0; + if (compute_curvatures) { + const CUDAREAL dV_dot_dV = dV.length_sqr(); + CUDAREAL dV2_dot_V = V.dot(UMATS_dbl_prime(_mos_tic, 1)*q_vec); + value2 = two_C * (two_C * V_dot_dV * V_dot_dV - dV2_dot_V - dV_dot_dV) * Iincrement; + } + dI.rot[1] += value; + dI2.rot[1] += value2; + } + if (refine_flag & REFINE_UMAT3) { + KOKKOS_VEC3 dV = UMATS_prime(_mos_tic, 2) * q_vec; + CUDAREAL V_dot_dV = V.dot(dV); + CUDAREAL value = -two_C * V_dot_dV * Iincrement; + + CUDAREAL value2 = 0; + if (compute_curvatures) { + const CUDAREAL dV_dot_dV = dV.length_sqr(); + CUDAREAL dV2_dot_V = V.dot(UMATS_dbl_prime(_mos_tic, 2)*q_vec); + value2 = two_C * (two_C * V_dot_dV * V_dot_dV - dV2_dot_V - dV_dot_dV) * Iincrement; + } + dI.rot[2] += value; + dI2.rot[2] += value2; + } + // Checkpoint for unit cell derivatives + for (int i_uc = 0; i_uc < 6; i_uc++) { + if (refine_flag & (REFINE_BMAT1 << i_uc)) { + KOKKOS_VEC3 dV = BMATS_prime(_mos_tic, i_uc) * q_vec; + CUDAREAL V_dot_dV = V.dot(dV); + CUDAREAL value = -two_C * V_dot_dV * Iincrement; + CUDAREAL value2 = 0; + if (compute_curvatures) { + const CUDAREAL dV_dot_dV = dV.length_sqr(); + CUDAREAL dV2_dot_V = V.dot(BMATS_dbl_prime(_mos_tic, i_uc)*q_vec); + value2 = two_C * (two_C * V_dot_dV * V_dot_dV - dV2_dot_V - dV_dot_dV) * Iincrement; } + dI.ucell[i_uc] += value; + dI2.ucell[i_uc] += value2; } - if (!oversample_omega && ! Fhkl_gradient_mode) - _omega_pixel = 1; - - CUDAREAL _I_cell = _F_cell; - if (!refine_Icell) - _I_cell *= _F_cell; - CUDAREAL hkl=1; - int Fhkl_channel=0; - if (! Fhkl_channels_empty) - Fhkl_channel = Fhkl_channels(_source); - if (Fhkl_have_scale_factors) - hkl = Fhkl_scale(i_hklasu + Fhkl_channel*Num_ASU); - if (Fhkl_gradient_mode){ - CUDAREAL Fhkl_deriv_scale = overall_scale*polar_for_Fhkl_grad; - CUDAREAL I_noFcell=texture_scale*I0; - CUDAREAL dfhkl = I_noFcell*_I_cell * Fhkl_deriv_scale; - CUDAREAL grad_incr = dfhkl*Fhkl_deriv_coef; - int fhkl_grad_idx=i_hklasu + Fhkl_channel*Num_ASU; - - if (Fhkl_errors_mode){ - // here we hi-kack the Fhkl_scale_deriv array, if computing errors, in order to store the hessian terms - // if we are getting the hessian terms, we no longer need the gradients (e.g. by this point we are done refininig) - CUDAREAL hessian_incr = Fhkl_hessian_coef*dfhkl*dfhkl; - ::Kokkos::atomic_add(&Fhkl_scale_deriv(fhkl_grad_idx), hessian_incr); + } // end ucell deriv + + // Checkpoint for Ncells manager + if (refine_flag & REFINE_NCELLS1) { + int num_ncell_deriv = 1; + if (!isotropic_ncells) + num_ncell_deriv = 3; + for (int i_nc = 0; i_nc < num_ncell_deriv; i_nc++) { + KOKKOS_MAT3 dN; + dN(i_nc, i_nc) = 1; + if (num_ncell_deriv == 1) { + dN(0, 0) = 1; + dN(1, 1) = 1; + dN(2, 2) = 1; } - else{ - ::Kokkos::atomic_add(&Fhkl_scale_deriv(fhkl_grad_idx), grad_incr); + CUDAREAL N_i = _NABC(i_nc, i_nc); + KOKKOS_VEC3 dV_dN = dN.dot(delta_H); + // TODO speedops: precompute these, store shared var + // _NABC.inverse + CUDAREAL determ_deriv = (_NABC.inverse().dot(dN)).trace(); + CUDAREAL deriv_coef = determ_deriv - C * (dV_dN.dot(V)); + CUDAREAL value = 2 * Iincrement * deriv_coef; + CUDAREAL value2 = 0; + if (compute_curvatures) { + value2 = (-1 / N_i / N_i - C * (dV_dN.dot(dV_dN))) * 2 * + Iincrement; + value2 += deriv_coef * 2 * value; } - continue; + dI.Ncells[i_nc] += value; + dI2.Ncells[i_nc] += value2; } - - CUDAREAL _I_total = hkl*_I_cell *I0; - CUDAREAL Iincrement = _I_total * texture_scale; - _I += Iincrement; - if (save_wavelenimage) - Ilambda += Iincrement * lambda_ang; - - if (refine_diffuse) { - CUDAREAL step_scale = texture_scale * _F_cell * _F_cell; - for (int i_diff = 0; i_diff < 6; i_diff++) { - dI_diffuse[i_diff] += - step_scale * step_diffuse_param[i_diff]; + } // end Ncells manager deriv + + if (refine_flag & REFINE_NCELLS_DEF) { + for (int i_nc = 3; i_nc < 6; i_nc++) { + KOKKOS_MAT3 dN; + if (i_nc == 3) + dN = KOKKOS_MAT3{0, 1, 0, 1, 0, 0, 0, 0, 0}; + else if (i_nc == 4) + dN = KOKKOS_MAT3{0, 0, 0, 0, 0, 1, 0, 1, 0}; + else + dN = KOKKOS_MAT3{0, 0, 1, 0, 0, 0, 1, 0, 0}; + KOKKOS_VEC3 dV_dN = dN.dot(delta_H); + // TODO speedops: precompute these + CUDAREAL determ_deriv = (_NABC.inverse().dot(dN)).trace(); + CUDAREAL deriv_coef = determ_deriv - C * (dV_dN.dot(V)); + CUDAREAL value = 2 * Iincrement * deriv_coef; + dI.Ncells[i_nc] += value; + CUDAREAL value2 = 0; + if (compute_curvatures) { + value2 = deriv_coef * value; + value2 += -2 * C * Iincrement * (dV_dN.dot(dV_dN)); + dI2.Ncells[i_nc] += value2; } } + } - if (refine_fp_fdp) { - CUDAREAL I_noFcell = texture_scale * I0; - fp_fdp_manager_dI[0] += 2 * I_noFcell * (c_deriv_Fcell); - fp_fdp_manager_dI[1] += 2 * I_noFcell * (d_deriv_Fcell); - } + // Checkpoint for Origin manager + for (int i_pan_orig = 0; i_pan_orig < 3; i_pan_orig++) { + if (refine_flag & (REFINE_PANEL_ORIGIN1 << i_pan_orig)) { + CUDAREAL per_k = _airpath_r; + CUDAREAL per_k3 = pow(per_k, 3.); + CUDAREAL per_k5 = pow(per_k, 5.); + + KOKKOS_MAT3 M = -two_C * (_NABC.dot(UBO)) / lambda_ang; + KOKKOS_VEC3 dk; + if (i_pan_orig == 0) + dk = KOKKOS_VEC3{0, 0, 1}; + else if (i_pan_orig == 1) + dk = KOKKOS_VEC3{1, 0, 0}; + else + dk = KOKKOS_VEC3{0, 1, 0}; + + CUDAREAL G = dk.dot(_pixel_pos); + CUDAREAL pix2 = subpixel_size * subpixel_size; + KOKKOS_VEC3 dk_hat = -per_k3 * G * _pixel_pos + per_k * dk; + CUDAREAL coef = (M.dot(dk_hat)).dot(V); + CUDAREAL coef2 = + -3 * pix2 * per_k5 * G * (_o_vec.dot(_pixel_pos)); + coef2 += pix2 * per_k3 * (_o_vec.dot(dk)); + CUDAREAL value = + coef * Iincrement + coef2 * Iincrement / _omega_pixel; + + dI.pan_orig[i_pan_orig] += value; + dI2.pan_orig[i_pan_orig] += 0; + + } // end origin manager deriv + } - if (verbose > 3) - printf( - "hkl= %f %f %f hkl1= %d %d %d Fcell=%f\n", _h, _k, _l, - _h0, _k0, _l0, _F_cell); + for (int i_pan_rot = 0; i_pan_rot < 3; i_pan_rot++) { + if (refine_flag & (REFINE_PANEL_ROT1 << i_pan_rot)) { + CUDAREAL per_k = _airpath_r; + CUDAREAL per_k3 = pow(per_k, 3.); + CUDAREAL per_k5 = pow(per_k, 5.); + KOKKOS_MAT3 M = -two_C * (_NABC.dot(UBO)) / lambda_ang; + KOKKOS_VEC3 dk = _Fdet * (dF_vecs(_pid * 3 + i_pan_rot)) + + _Sdet * (dS_vecs(_pid * 3 + i_pan_rot)); + CUDAREAL G = dk.dot(_pixel_pos); + CUDAREAL pix2 = subpixel_size * subpixel_size; + KOKKOS_VEC3 dk_hat = -per_k3 * G * _pixel_pos + per_k * dk; + CUDAREAL coef = (M.dot(dk_hat)).dot(V); + CUDAREAL coef2 = + -3 * pix2 * per_k5 * G * (_o_vec.dot(_pixel_pos)); + coef2 += pix2 * per_k3 * (_o_vec.dot(dk)); + CUDAREAL value = + coef * Iincrement + coef2 * Iincrement / _omega_pixel; + + dI.pan_rot[i_pan_rot] += value; + dI2.pan_rot[i_pan_rot] += 0; + } + } - KOKKOS_MAT3 UBOt; - if (refine_Umat(0) || refine_Umat(1) || refine_Umat(2) || - refine_eta) { - UBOt = Amat_init; + // checkpoint for Fcell manager + if (refine_flag & REFINE_FCELL) { + CUDAREAL value; + if (refine_flag & REFINE_ICELL) + value = I0 * texture_scale; + else + value = 2 * I0 * _F_cell * + texture_scale; // Iincrement/_F_cell ; + CUDAREAL value2 = 0; + if (compute_curvatures) { + // NOTE if _Fcell >0 + value2 = 2 * I0 * texture_scale; } - if (refine_Umat(0)) { - KOKKOS_MAT3 RyRzUBOt = RotMats(1) * RotMats(2) * UBOt; - KOKKOS_VEC3 delta_H_prime = - (UMATS(_mos_tic) * dRotMats(0) * RyRzUBOt) - .transpose() - .dot(q_vec); - CUDAREAL V_dot_dV = V.dot(_NABC.dot(delta_H_prime)); - CUDAREAL value = -two_C * V_dot_dV * Iincrement; - CUDAREAL value2 = 0; - if (compute_curvatures) { - KOKKOS_VEC3 delta_H_dbl_prime = - (UMATS(_mos_tic).dot(d2RotMats(0).dot(RyRzUBOt))) - .transpose() - .dot(q_vec); - CUDAREAL dV_dot_dV = (_NABC.dot(delta_H_prime)) - .dot(_NABC.dot(delta_H_prime)); - CUDAREAL dV2_dot_V = - (_NABC.dot(delta_H)).dot(_NABC.dot(delta_H_dbl_prime)); - value2 = - two_C * - (two_C * V_dot_dV * V_dot_dV - dV2_dot_V - dV_dot_dV) * - Iincrement; + // if (fcell_idx >=0 && fcell_idx <=2){ + if (use_nominal_hkl) { + if (_h0 == nom_h && _k0 == nom_k && _l0 == nom_l) { + dI.fcell += value; + dI2.fcell += value2; } - rot_manager_dI[0] += value; - rot_manager_dI2[0] += value2; + } else { + dI.fcell += value; + dI2.fcell += value2; } - if (refine_Umat(1)) { - KOKKOS_MAT3 UmosRx = UMATS(_mos_tic).dot(RotMats(0)); - KOKKOS_MAT3 RzUBOt = RotMats(2).dot(UBOt); - KOKKOS_VEC3 delta_H_prime = (UmosRx.dot(dRotMats(1).dot(RzUBOt))) - .transpose() - .dot(q_vec); - CUDAREAL V_dot_dV = V.dot(_NABC.dot(delta_H_prime)); - CUDAREAL value = -two_C * V_dot_dV * Iincrement; - - CUDAREAL value2 = 0; + } // end of fcell man deriv + + // checkpoint for eta manager + if (refine_flag & REFINE_ETA) { + for (int i_eta = 0; i_eta < 3; i_eta++) { + if (i_eta > 0 && !aniso_eta) + continue; + int mtic2 = _mos_tic + i_eta * mosaic_domains; + KOKKOS_VEC3 DeltaH_deriv = (UMATS_RXYZ_prime(mtic2).dot(UBOt)) + .transpose() + .dot(q_vec); + // vector V is _Nabc*Delta_H + KOKKOS_VEC3 dV = _NABC.dot(DeltaH_deriv); + CUDAREAL V_dot_dV = V.dot(dV); + CUDAREAL Iprime = -two_C * (V_dot_dV)*Iincrement; + dI.eta[i_eta] += Iprime; + CUDAREAL Idbl_prime = 0; if (compute_curvatures) { - KOKKOS_VEC3 delta_H_dbl_prime = - (UmosRx.dot(d2RotMats(1).dot(RzUBOt))) + KOKKOS_VEC3 DeltaH_second_deriv = + (UMATS_RXYZ_dbl_prime(mtic2).dot(UBOt)) .transpose() .dot(q_vec); - CUDAREAL dV_dot_dV = (_NABC.dot(delta_H_prime)) - .dot(_NABC.dot(delta_H_prime)); - CUDAREAL dV2_dot_V = - (_NABC.dot(delta_H)).dot(_NABC.dot(delta_H_dbl_prime)); - value2 = - two_C * - (two_C * V_dot_dV * V_dot_dV - dV2_dot_V - dV_dot_dV) * - Iincrement; + KOKKOS_VEC3 dV2 = _NABC.dot(DeltaH_second_deriv); + Idbl_prime = + -two_C * (dV.dot(dV) + V.dot(dV2)) * Iincrement; + Idbl_prime += -two_C * (V_dot_dV)*Iprime; } - rot_manager_dI[1] += value; - rot_manager_dI2[1] += value2; + dI2.eta[i_eta] += Idbl_prime; } - if (refine_Umat(2)) { - KOKKOS_MAT3 UmosRxRy = UMATS(_mos_tic).dot(RotMats(0).dot(RotMats(1))); - KOKKOS_VEC3 delta_H_prime = (UmosRxRy.dot(dRotMats(2).dot(UBOt))) - .transpose() - .dot(q_vec); - CUDAREAL V_dot_dV = V.dot(_NABC.dot(delta_H_prime)); - CUDAREAL value = -two_C * V_dot_dV * Iincrement; - + } // end of eta man deriv + + // checkpoint for lambda manager + for (int i_lam = 0; i_lam < 2; i_lam++) { + if (refine_flag & (REFINE_LAMBDA << i_lam)) { + CUDAREAL NH_dot_V = (_NABC.dot(H_vec)).dot(V); + CUDAREAL dg_dlambda; + if (i_lam == 0) + dg_dlambda = 1; + else // i_lam==1 + dg_dlambda = lambda_ang; + CUDAREAL coef = + NH_dot_V * two_C * (dg_dlambda) / lambda_ang; + CUDAREAL value = coef * Iincrement; CUDAREAL value2 = 0; - if (compute_curvatures) { - KOKKOS_VEC3 delta_H_dbl_prime = - (UmosRxRy.dot(d2RotMats(2).dot(UBOt))) - .transpose() - .dot(q_vec); - CUDAREAL dV_dot_dV = (_NABC.dot(delta_H_prime)) - .dot(_NABC.dot(delta_H_prime)); - CUDAREAL dV2_dot_V = - (_NABC.dot(delta_H)).dot(_NABC.dot(delta_H_dbl_prime)); - value2 = - two_C * - (two_C * V_dot_dV * V_dot_dV - dV2_dot_V - dV_dot_dV) * - Iincrement; - } - rot_manager_dI[2] += value; - rot_manager_dI2[2] += value2; + dI.lambda[i_lam] += value; + dI2.lambda[i_lam] += value2; } - // Checkpoint for unit cell derivatives - // KOKKOS_MAT3 Ot = eig_O.transpose(); - KOKKOS_MAT3 UmosRxRyRzU; - KOKKOS_VEC3 delta_H_prime; - for (int i_uc = 0; i_uc < 6; i_uc++) { - if (refine_Bmat(i_uc)) { - UmosRxRyRzU = UMATS_RXYZ(_mos_tic).dot(eig_U); - delta_H_prime = - (UmosRxRyRzU.dot(dB_mats(i_uc).dot(eig_Otranspose))) - .transpose() - .dot(q_vec); - CUDAREAL V_dot_dV = V.dot(_NABC.dot(delta_H_prime)); - CUDAREAL value = -two_C * V_dot_dV * Iincrement; - CUDAREAL value2 = 0; - if (compute_curvatures) { - KOKKOS_VEC3 delta_H_dbl_prime = - (UmosRxRyRzU.dot( - dB2_mats(i_uc).dot(eig_Otranspose))) - .transpose() - .dot(q_vec); - CUDAREAL dV_dot_dV = (_NABC.dot(delta_H_prime)) - .dot(_NABC.dot(delta_H_prime)); - CUDAREAL dV2_dot_V = - (_NABC.dot(delta_H)) - .dot(_NABC.dot(delta_H_dbl_prime)); - value2 = two_C * - (two_C * V_dot_dV * V_dot_dV - dV2_dot_V - - dV_dot_dV) * - Iincrement; - } - ucell_manager_dI[i_uc] += value; - ucell_manager_dI2[i_uc] += value2; + } + // end of lambda deriv + if (printout) { + if (_subS == 0 && _subF == 0 && _thick_tic == 0 && + _source == 0 && _mos_tic == 0) { + if ((_fpixel == printout_fpixel && + _spixel == printout_spixel) || + printout_fpixel < 0) { + printf("%4d %4d : lambda = %g\n", _fpixel, _spixel, _lambda); + printf( + "at %g %g %g\n", _pixel_pos[0], _pixel_pos[1], + _pixel_pos[2]); + printf("Fdet= %g; Sdet= %g ; Odet= %g\n", _Fdet, _Sdet, _Odet); + printf( + "PIX0: %f %f %f\n", pix0_vectors(pid_x), + pix0_vectors(pid_y), pix0_vectors(pid_z)); + printf( + "F: %f %f %f\n", fdet_vectors(pid_x), + fdet_vectors(pid_y), fdet_vectors(pid_z)); + printf( + "S: %f %f %f\n", sdet_vectors(pid_x), + sdet_vectors(pid_y), sdet_vectors(pid_z)); + printf( + "O: %f %f %f\n", odet_vectors(pid_x), + odet_vectors(pid_y), odet_vectors(pid_z)); + printf("pid_x=%d, pid_y=%d; pid_z=%d\n", pid_x, pid_y, pid_z); + printf( + "QVECTOR: %f %f %f\n", q_vec[0], q_vec[1], q_vec[2]); + printf("omega %15.10g\n", _omega_pixel); + printf( + "Incident: %g %g %g\n", + _incident[0], _incident[1], _incident[2]); + + KOKKOS_MAT3 UU = UMATS_RXYZ(_mos_tic); + printf( + "UMAT_RXYZ :\n%f %f %f\n%f %f %f\n%f %f %f\n", + UU(0, 0), UU(0, 1), UU(0, 2), UU(1, 0), UU(1, 1), + UU(1, 2), UU(2, 0), UU(2, 1), UU(2, 2)); + UU = Bmat_realspace; + printf( + "Bmat_realspace :\n%f %f %f\n%f %f %f\n%f %f %f\n", + UU(0, 0), UU(0, 1), UU(0, 2), UU(1, 0), UU(1, 1), + UU(1, 2), UU(2, 0), UU(2, 1), UU(2, 2)); + UU = UBO; + printf( + "UBO :\n%f %f %f\n%f %f %f\n%f %f %f\n", + UU(0, 0), UU(0, 1), UU(0, 2), UU(1, 0), UU(1, 1), + UU(1, 2), UU(2, 0), UU(2, 1), UU(2, 2)); + + UU = UBOt; + printf( + "UBOt :\n%f %f %f\n%f %f %f\n%f %f %f\n", + UU(0, 0), UU(0, 1), UU(0, 2), UU(1, 0), UU(1, 1), + UU(1, 2), UU(2, 0), UU(2, 1), UU(2, 2)); + + // UU = UmosRxRyRzU; + // printf( + // "UmosRxRyRzU :\n%f %f %f\n%f %f %f\n%f %f %f\n", + // UU(0, 0), UU(0, 1), UU(0, 2), UU(1, 0), UU(1, 1), + // UU(1, 2), UU(2, 0), UU(2, 1), UU(2, 2)); + // KOKKOS_VEC3 AA = delta_H_prime; + // printf( + // "delta_H_prime :\n%f %f %f\n", AA[0], AA[1], + // AA[2]); + printf("Iincrement: %f\n", Iincrement); + printf( + "hkl= %f %f %f hkl0= %d %d %d\n", _h, _k, _l, _h0, + _k0, _l0); + printf( + " F_cell=%g F_cell2=%g I_latt=%g I = %g\n", + _F_cell, _F_cell2, I0, _I); + printf("I/steps %15.10g\n", _I / Nsteps); + // printf("Ilatt diffuse %15.10g\n", I_latt_diffuse); + printf("default_F= %f\n", default_F); + if (complex_miller) + printf("COMPLEX MILLER!\n"); + if (no_Nabc_scale) + printf("No Nabc scale!\n"); } - } // end ucell deriv - - // Checkpoint for Ncells manager - if (refine_Ncells(0)) { - int num_ncell_deriv = 1; - if (!isotropic_ncells) - num_ncell_deriv = 3; - for (int i_nc = 0; i_nc < num_ncell_deriv; i_nc++) { - KOKKOS_MAT3 dN; - dN(i_nc, i_nc) = 1; - if (num_ncell_deriv == 1) { - dN(0, 0) = 1; - dN(1, 1) = 1; - dN(2, 2) = 1; - } - CUDAREAL N_i = _NABC(i_nc, i_nc); - KOKKOS_VEC3 dV_dN = dN.dot(delta_H); - // TODO speedops: precompute these, store shared var - // _NABC.inverse - CUDAREAL determ_deriv = (_NABC.inverse().dot(dN)).trace(); - CUDAREAL deriv_coef = determ_deriv - C * (dV_dN.dot(V)); - CUDAREAL value = 2 * Iincrement * deriv_coef; - CUDAREAL value2 = 0; - if (compute_curvatures) { - dN(i_nc, i_nc) = 0; // TODO check maths - value2 = (-1 / N_i / N_i - C * (dV_dN.dot(dV_dN))) * 2 * - Iincrement; - value2 += deriv_coef * 2 * value; - } - Ncells_manager_dI[i_nc] += value; - Ncells_manager_dI2[i_nc] += value2; + } + } // end of printout if + + } // end of mos_tic loop + } // end of source loop + } // end of thick step loop + } // end of fpos loop + } // end of spos loop + floatimage(pixIdx) = _I; + if (save_wavelenimage) + wavelenimage(pixIdx) = Ilambda / _I; + + if (refine_flag) { + manager_dI(pixIdx) = dI; + manager_dI2(pixIdx) = dI2; + } + }); // end pixIdx loop + + if (Fhkl_gradient_mode) + return; + + Kokkos::parallel_for( + "deriv_image_increment", Npix_to_model, KOKKOS_LAMBDA(const int& pixIdx) { + + int _pid = panels_fasts_slows(pixIdx * 3); + int _fpixel = panels_fasts_slows(pixIdx * 3 + 1); + int _spixel = panels_fasts_slows(pixIdx * 3 + 2); + + CUDAREAL _Fdet_ave = pixel_size * _fpixel + pixel_size / 2.0; + CUDAREAL _Sdet_ave = pixel_size * _spixel + pixel_size / 2.0; + CUDAREAL _Odet_ave = 0; // Odet; + // TODO maybe make this more general for thick detectors? + + KOKKOS_VEC3 _pixel_pos_ave(0, 0, 0); + int pid_x = _pid * 3; + int pid_y = _pid * 3 + 1; + int pid_z = _pid * 3 + 2; + + CUDAREAL fx = fdet_vectors(pid_x); + CUDAREAL fy = fdet_vectors(pid_y); + CUDAREAL fz = fdet_vectors(pid_z); + + CUDAREAL sx = sdet_vectors(pid_x); + CUDAREAL sy = sdet_vectors(pid_y); + CUDAREAL sz = sdet_vectors(pid_z); + + CUDAREAL ox = odet_vectors(pid_x); + CUDAREAL oy = odet_vectors(pid_y); + CUDAREAL oz = odet_vectors(pid_z); + + CUDAREAL px = pix0_vectors(pid_x); + CUDAREAL py = pix0_vectors(pid_y); + CUDAREAL pz = pix0_vectors(pid_z); + + _pixel_pos_ave[0] = _Fdet_ave * fx + _Sdet_ave * sx + _Odet_ave * ox + px; + _pixel_pos_ave[1] = _Fdet_ave * fy + _Sdet_ave * sy + _Odet_ave * oy + py; + _pixel_pos_ave[2] = _Fdet_ave * fz + _Sdet_ave * sz + _Odet_ave * oz + pz; + + CUDAREAL close_distance = close_distances(_pid); + + CUDAREAL _airpath_ave_r = 1 / _pixel_pos_ave.length(); + KOKKOS_VEC3 _diffracted_ave = _pixel_pos_ave.get_unit_vector(); + CUDAREAL _omega_pixel_ave = pixel_size * pixel_size * _airpath_ave_r * _airpath_ave_r * + close_distance * _airpath_ave_r; + + CUDAREAL _polar = 1; + if (!nopolar) { + KOKKOS_VEC3 _incident(-source_X(0), -source_Y(0), -source_Z(0)); + _incident.normalize(); + // component of diffracted unit vector along _incident beam unit vector + CUDAREAL cos2theta = _incident.dot(_diffracted_ave); + CUDAREAL cos2theta_sqr = cos2theta * cos2theta; + CUDAREAL sin2theta_sqr = 1 - cos2theta_sqr; + + CUDAREAL cos2psi = 0; + if (kahn_factor != 0.0) { + // cross product to get "vertical" axis that is orthogonal to the cannonical + // "polarization" + KOKKOS_VEC3 B_in = polarization_axis.cross(_incident); + // cross product with _incident beam to get E-vector direction + KOKKOS_VEC3 E_in = _incident.cross(B_in); + // get components of diffracted ray projected onto the E-B plane + CUDAREAL _kEi = _diffracted_ave.dot(E_in); + CUDAREAL _kBi = _diffracted_ave.dot(B_in); + // compute the angle of the diffracted ray projected onto the incident E-B plane + // calculate cos(2 * atan2(_kBi, _kEi)) + if (_kEi!=0) { + CUDAREAL ratio = _kBi / _kEi; + cos2psi = (1 - ratio*ratio) / (1 + ratio*ratio); + } else { + cos2psi = -1; + } + } + // correction for polarized _incident beam + _polar = 0.5 * (1.0 + cos2theta_sqr - kahn_factor * cos2psi * sin2theta_sqr); + } + + CUDAREAL _om = 1; + if (!oversample_omega) + _om = _omega_pixel_ave; + // final scale term to being everything to photon number units + CUDAREAL _scale_term = _polar * _om * overall_scale; + floatimage(pixIdx) *= _scale_term; + + auto& dI = manager_dI(pixIdx); + auto& dI2 = manager_dI2(pixIdx); + + // udpate the rotation derivative images* + for (int i_rot = 0; i_rot < 3; i_rot++) { + if (refine_flag & (REFINE_UMAT1 << i_rot)) { + CUDAREAL value = _scale_term * dI.rot[i_rot]; + CUDAREAL value2 = _scale_term * dI2.rot[i_rot]; + int idx = i_rot * Npix_to_model + pixIdx; + d_Umat_images(idx) = value; + d2_Umat_images(idx) = value2; + } + } // end rot deriv image increment + + // update the ucell derivative images + for (int i_uc = 0; i_uc < 6; i_uc++) { + if (refine_flag & (REFINE_BMAT1 << i_uc)) { + CUDAREAL value = _scale_term * dI.ucell[i_uc]; + CUDAREAL value2 = _scale_term * dI2.ucell[i_uc]; + int idx = i_uc * Npix_to_model + pixIdx; + d_Bmat_images(idx) = value; + d2_Bmat_images(idx) = value2; + } + } // end ucell deriv image increment + + // update the Ncells derivative image + if (refine_flag & REFINE_NCELLS1) { + CUDAREAL value = _scale_term * dI.Ncells[0]; + CUDAREAL value2 = _scale_term * dI2.Ncells[0]; + int idx = pixIdx; + d_Ncells_images(idx) = value; + d2_Ncells_images(idx) = value2; + + if (!isotropic_ncells) { + value = _scale_term * dI.Ncells[1]; + value2 = _scale_term * dI2.Ncells[1]; + idx = Npix_to_model + pixIdx; + d_Ncells_images(idx) = value; + d2_Ncells_images(idx) = value2; + + value = _scale_term * dI.Ncells[2]; + value2 = _scale_term * dI2.Ncells[2]; + idx = Npix_to_model * 2 + pixIdx; + d_Ncells_images(idx) = value; + d2_Ncells_images(idx) = value2; + } + } // end Ncells deriv image increment + if (refine_flag & REFINE_NCELLS_DEF) { + for (int i_nc = 3; i_nc < 6; i_nc++) { + CUDAREAL value = _scale_term * dI.Ncells[i_nc]; + CUDAREAL value2 = _scale_term * dI2.Ncells[i_nc]; + int idx = i_nc * Npix_to_model + pixIdx; + d_Ncells_images(idx) = value; + d2_Ncells_images(idx) = value2; + } + } + + // update Fcell derivative image + if (refine_flag & REFINE_FCELL) { + CUDAREAL value = _scale_term * dI.fcell; + CUDAREAL value2 = _scale_term * dI2.fcell; + d_fcell_images(pixIdx) = value; + d2_fcell_images(pixIdx) = value2; + } // end Fcell deriv image increment + + if (refine_flag & REFINE_FP_FDP) { + // c derivative + CUDAREAL value = _scale_term * dI.fp_fdp[0]; + d_fp_fdp_images(pixIdx) = value; + // d derivative + value = _scale_term * dI.fp_fdp[1]; + d_fp_fdp_images(Npix_to_model + pixIdx) = value; + } + if (refine_flag & REFINE_DIFFUSE) { + for (int i_gam = 0; i_gam < 3; i_gam++) { + CUDAREAL val = dI.diffuse[i_gam] * _scale_term; + int img_idx = Npix_to_model * i_gam + pixIdx; + d_diffuse_gamma_images(img_idx) = val; + } + for (int i_sig = 0; i_sig < 3; i_sig++) { + CUDAREAL val = dI.diffuse[i_sig + 3] * _scale_term; + int img_idx = Npix_to_model * i_sig + pixIdx; + d_diffuse_sigma_images(img_idx) = val; + } + } + + // update eta derivative image + if (refine_flag & REFINE_ETA) { + for (int i_eta = 0; i_eta < 3; i_eta++) { + if (i_eta > 0 && !aniso_eta) + continue; + int idx = pixIdx + Npix_to_model * i_eta; + CUDAREAL value = _scale_term * dI.eta[i_eta]; + CUDAREAL value2 = _scale_term * dI2.eta[i_eta]; + d_eta_images(idx) = value; + d2_eta_images(idx) = value2; + } + } // end eta deriv image increment + + // update the lambda derivative images + for (int i_lam = 0; i_lam < 2; i_lam++) { + if (refine_flag & (REFINE_LAMBDA1 << i_lam)) { + CUDAREAL value = _scale_term * dI.lambda[i_lam]; + CUDAREAL value2 = _scale_term * dI2.lambda[i_lam]; + int idx = i_lam * Npix_to_model + pixIdx; + d_lambda_images(idx) = value; + // d2_lambda_images(idx) = value2; + } + } // end lambda deriv image increment + + for (int i_pan_rot = 0; i_pan_rot < 3; i_pan_rot++) { + if (refine_flag & (REFINE_PANEL_ROT1 << i_pan_rot)) { + CUDAREAL value = _scale_term * dI.pan_rot[i_pan_rot]; + CUDAREAL value2 = _scale_term * dI2.pan_rot[i_pan_rot]; + int idx = i_pan_rot * Npix_to_model + pixIdx; + d_panel_rot_images(idx) = value; + // d2_panel_rot_images(idx) = value2; + } + } // end panel rot deriv image increment + + for (int i_pan_orig = 0; i_pan_orig < 3; i_pan_orig++) { + if (refine_flag & (REFINE_PANEL_ORIGIN1 << i_pan_orig)) { + CUDAREAL value = _scale_term * dI.pan_orig[i_pan_orig]; + CUDAREAL value2 = _scale_term * dI2.pan_orig[i_pan_orig]; + int idx = i_pan_orig * Npix_to_model + pixIdx; + d_panel_orig_images(idx) = value; + // d2_panel_orig_images(idx) = value2; + } + } // end panel orig deriv image increment + }); // end pixIdx loop + +} // END of GPU kernel + +////////////////////////////////////////////////////////////////////////////////// + +template < + bool printout, + bool complex_miller, + bool compute_curvatures, + uint32_t refine_flag, + bool use_diffuse, + bool save_wavelenimage, + bool Fhkl_gradient_mode, + bool Fhkl_errors_mode, + bool using_trusted_mask, + bool Fhkl_channels_empty, + bool Fhkl_have_scale_factors> +void kokkos_sum_over_steps( + int Npix_to_model, + vector_uint_t panels_fasts_slows, + vector_cudareal_t floatimage, + vector_cudareal_t wavelenimage, + vector_cudareal_t d_Umat_images, + vector_cudareal_t d2_Umat_images, + vector_cudareal_t d_Bmat_images, + vector_cudareal_t d2_Bmat_images, + vector_cudareal_t d_Ncells_images, + vector_cudareal_t d2_Ncells_images, + vector_cudareal_t d_fcell_images, + vector_cudareal_t d2_fcell_images, + vector_cudareal_t d_eta_images, + vector_cudareal_t d2_eta_images, + vector_cudareal_t d_lambda_images, + vector_cudareal_t d2_lambda_images, + vector_cudareal_t d_panel_rot_images, + vector_cudareal_t d2_panel_rot_images, + vector_cudareal_t d_panel_orig_images, + vector_cudareal_t d2_panel_orig_images, + vector_cudareal_t d_fp_fdp_images, + vector_manager_t manager_dI, + vector_manager_t manager_dI2, + const int Nsteps, + int printout_fpixel, + int printout_spixel, + /*bool printout,*/ + CUDAREAL default_F, + int oversample, + bool oversample_omega, + CUDAREAL subpixel_size, + CUDAREAL pixel_size, + CUDAREAL detector_thickstep, + CUDAREAL detector_thick, + const vector_cudareal_t close_distances, + CUDAREAL detector_attnlen, + int detector_thicksteps, + int sources, + int phisteps, + int mosaic_domains, + bool use_lambda_coefficients, + CUDAREAL lambda0, + CUDAREAL lambda1, + KOKKOS_MAT3 eig_U, + KOKKOS_MAT3 eig_O, + KOKKOS_MAT3 eig_B, + KOKKOS_MAT3 RXYZ, + vector_vec3_t dF_vecs, + vector_vec3_t dS_vecs, + const vector_mat3_t UMATS_RXYZ, + vector_mat3_t UMATS_RXYZ_prime, + vector_mat3_t UMATS_RXYZ_dbl_prime, + vector_mat3_t RotMats, + vector_mat3_t dRotMats, + vector_mat3_t d2RotMats, + vector_mat3_t UMATS, + vector_mat3_t dB_mats, + vector_mat3_t dB2_mats, + vector_mat3_t Amatrices, + const vector_cudareal_t source_X, + const vector_cudareal_t source_Y, + const vector_cudareal_t source_Z, + const vector_cudareal_t source_lambda, + const vector_cudareal_t source_I, + CUDAREAL kahn_factor, + CUDAREAL Na, + CUDAREAL Nb, + CUDAREAL Nc, + CUDAREAL Nd, + CUDAREAL Ne, + CUDAREAL Nf, + CUDAREAL phi0, + CUDAREAL phistep, + KOKKOS_VEC3 spindle_vec, + KOKKOS_VEC3 polarization_axis, + int h_range, + int k_range, + int l_range, + int h_max, + int h_min, + int k_max, + int k_min, + int l_max, + int l_min, + CUDAREAL dmin, + CUDAREAL fudge, + /*bool complex_miller,*/ + int verbose, + bool only_save_omega_kahn, + bool isotropic_ncells, + /*bool compute_curvatures,*/ + const vector_cudareal_t FhklLinear, + const vector_cudareal_t Fhkl2Linear, + /*const uint32_t refine_flag,*/ + // vector_bool_t refine_Bmat, + // vector_bool_t refine_Ncells, + // bool refine_Ncells_def, + // vector_bool_t refine_panel_origin, + // vector_bool_t refine_panel_rot, + // bool refine_fcell, + // vector_bool_t refine_lambda, + // bool refine_eta, + // vector_bool_t refine_Umat, + const vector_cudareal_t fdet_vectors, + const vector_cudareal_t sdet_vectors, + const vector_cudareal_t odet_vectors, + const vector_cudareal_t pix0_vectors, + bool nopolar, + bool point_pixel, + CUDAREAL fluence, + CUDAREAL r_e_sqr, + CUDAREAL spot_scale, + int Npanels, + bool aniso_eta, + bool no_Nabc_scale, + const vector_cudareal_t fpfdp, + const vector_cudareal_t fpfdp_derivs, + const vector_cudareal_t atom_data, + int num_atoms, + // bool refine_fp_fdp, + const vector_int_t nominal_hkl, + bool use_nominal_hkl, + KOKKOS_MAT3 anisoU, + KOKKOS_MAT3 anisoG, + KOKKOS_MAT3 rotate_principal_axes, + /*bool use_diffuse,*/ + vector_cudareal_t d_diffuse_gamma_images, + vector_cudareal_t d_diffuse_sigma_images, + // bool refine_diffuse, + bool gamma_miller_units, + // bool refine_Icell, + /*bool save_wavelenimage,*/ + int laue_group_num, + int stencil_size, + /*bool Fhkl_gradient_mode,*/ + /*bool Fhkl_errors_mode,*/ + /*bool using_trusted_mask,*/ + /*bool Fhkl_channels_empty,*/ + /*bool Fhkl_have_scale_factors,*/ + int Num_ASU, + const vector_cudareal_t data_residual, + const vector_cudareal_t data_variance, + const vector_int_t data_freq, + const vector_bool_t data_trusted, + const vector_int_t FhklLinear_ASUid, + const vector_int_t Fhkl_channels, + const vector_cudareal_t Fhkl_scale, + vector_cudareal_t Fhkl_scale_deriv) { // BEGIN GPU kernel + + const KOKKOS_MAT3 Bmat_realspace = eig_B * 1e10; + const KOKKOS_MAT3 eig_Otranspose = eig_O.transpose(); + const KOKKOS_MAT3 Amat_init = eig_U * Bmat_realspace * eig_Otranspose; + const KOKKOS_MAT3 Ainv = eig_U*(Bmat_realspace.transpose().inverse())* (eig_O.inverse()); + const KOKKOS_MAT3 _NABC {Na, Nd, Nf, Nd, Nb, Ne, Nf, Ne, Nc}; + const double NABC_det = _NABC.determinant(); // TODO is this slow ? + const double NABC_det_sq = NABC_det * NABC_det; + const CUDAREAL C = 2 / 0.63 * fudge; + const CUDAREAL two_C = 2 * C; + KOKKOS_MAT3 anisoG_local; + CUDAREAL anisoG_determ = 0; + KOKKOS_MAT3 anisoU_local; + vector_mat3_t laue_mats = vector_mat3_t("laue_mats", 24); + vector_vec3_t dG_dgam = vector_vec3_t("dG_dgam", 3); + vector_cudareal_t dG_trace = vector_cudareal_t("dG_trace", 3); + int num_laue_mats = 0; + int dhh = 0, dkk = 0, dll = 0; + + Kokkos::View UMATS_prime("UMATS_prime", mosaic_domains); + Kokkos::View UMATS_dbl_prime("UMATS_dbl_prime", mosaic_domains); + Kokkos::View BMATS_prime("BMATS_prime", mosaic_domains); + Kokkos::View BMATS_dbl_prime("BMATS_dbl_prime", mosaic_domains); + + Kokkos::parallel_for("prepare_UMATS", mosaic_domains, KOKKOS_LAMBDA(const int& _mos_tic) { + const KOKKOS_MAT3 UBOt = Amat_init; + UMATS_prime(_mos_tic, 0) = _NABC * (UMATS(_mos_tic) * dRotMats(0) * RotMats(1) * RotMats(2) * UBOt).transpose(); + UMATS_prime(_mos_tic, 1) = _NABC * (UMATS(_mos_tic) * RotMats(0) * dRotMats(1) * RotMats(2) * UBOt).transpose(); + UMATS_prime(_mos_tic, 2) = _NABC * (UMATS(_mos_tic) * RotMats(0) * RotMats(1) * dRotMats(2) * UBOt).transpose(); + + UMATS_dbl_prime(_mos_tic, 0) = _NABC * (UMATS(_mos_tic) * d2RotMats(0) * RotMats(1) * RotMats(2) * UBOt).transpose(); + UMATS_dbl_prime(_mos_tic, 1) = _NABC * (UMATS(_mos_tic) * RotMats(0) * d2RotMats(1) * RotMats(2) * UBOt).transpose(); + UMATS_dbl_prime(_mos_tic, 2) = _NABC * (UMATS(_mos_tic) * RotMats(0) * RotMats(1) * d2RotMats(2) * UBOt).transpose(); + + for (int i_uc=0; i_uc<6; i_uc++) { + BMATS_prime(_mos_tic, i_uc) = _NABC * (UMATS_RXYZ(_mos_tic) * eig_U * dB_mats(i_uc) * eig_O.transpose()).transpose(); + BMATS_dbl_prime(_mos_tic, i_uc) = _NABC * (UMATS_RXYZ(_mos_tic) * eig_U * dB2_mats(i_uc) * eig_O.transpose()).transpose(); + } + }); + + if (use_diffuse){ + anisoG_local = anisoG; + anisoU_local = anisoU; + + if (laue_group_num < 1 || laue_group_num >14 ){ + throw std::string("Laue group number not in range 1-14"); + } + + if (gamma_miller_units){ + anisoG_local = anisoG_local * Bmat_realspace; + } + Kokkos::parallel_reduce("prepare diffuse mats", 1, KOKKOS_LAMBDA (const int& i, int& num_laue_mats_temp){ + num_laue_mats_temp = gen_laue_mats(laue_group_num, laue_mats, rotate_principal_axes); + // KOKKOS_MAT3 rotate_principal_axes; + // rotate_principal_axes << 0.70710678, -0.70710678, 0., 0.70710678, 0.70710678, 0., 0., 0., 1.; + + for ( int iL = 0; iL < num_laue_mats_temp; iL++ ){ + laue_mats(iL) = Ainv * laue_mats(iL) * rotate_principal_axes; + } + // printf("Bmat ="); + // for (int i=0; i<9; ++i) { + // printf(" %g", Bmat_realspace[i]); + // } + // printf("\n"); + const KOKKOS_MAT3 Ginv = anisoG_local.inverse(); + // printf("Ginv ="); + // for (int i=0; i<9; ++i) { + // printf(" %g", Ginv[i]); + // } + // printf("\n"); + const KOKKOS_MAT3 dG = Bmat_realspace * Ginv; + // printf("dG ="); + // for (int i=0; i<9; ++i) { + // printf(" %g", dG[i]); + // } + // printf("\n"); + for (int i_gam=0; i_gam<3; i_gam++){ + if (gamma_miller_units) { + dG_dgam(i_gam) = KOKKOS_VEC3(Bmat_realspace(i_gam, 0), Bmat_realspace(i_gam, 1), Bmat_realspace(i_gam, 2)); + } else { + dG_dgam(i_gam)[i_gam] = 1; + } + KOKKOS_MAT3 temp_dgam; + temp_dgam(i_gam, 0) = dG_dgam(i_gam)[0]; + temp_dgam(i_gam, 1) = dG_dgam(i_gam)[1]; + temp_dgam(i_gam, 2) = dG_dgam(i_gam)[2]; + dG_trace(i_gam) = (Ginv*temp_dgam).trace(); + // printf("TRACE %g\n", dG_trace(i_gam)); + // printf("dgam ="); + // for (int i=0; i<9; ++i) { + // printf(" %g", temp_dgam[i]); + // } + // printf("\n"); + + // dG(i_gam, i_gam); + } + }, num_laue_mats); + anisoG_determ = anisoG_local.determinant(); + dhh = dkk = dll = stencil_size; // Limits of stencil for diffuse calc + } + const KOKKOS_VEC3 dHH (dhh, dkk, dll); + + const CUDAREAL overall_scale = r_e_sqr * spot_scale * fluence / Nsteps; + + const CUDAREAL detector_attnlen_r = (detector_attnlen>0) ? 1 / detector_attnlen : 0; + + Kokkos::parallel_for( + "sum_over_steps", Npix_to_model, KOKKOS_LAMBDA(const int& pixIdx) { + + if (using_trusted_mask) { + if (!data_trusted(pixIdx)) + return; + } + const int _pid = panels_fasts_slows(pixIdx * 3); + const int _fpixel = panels_fasts_slows(pixIdx * 3 + 1); + const int _spixel = panels_fasts_slows(pixIdx * 3 + 2); + + CUDAREAL Fhkl_deriv_coef=0; + CUDAREAL Fhkl_hessian_coef=0; + if (Fhkl_gradient_mode) { + CUDAREAL u = data_residual(pixIdx); + CUDAREAL one_by_v = 1/data_variance(pixIdx); + CUDAREAL Gterm = 1 - 2*u - u*u*one_by_v; + Fhkl_deriv_coef = 0.5 * Gterm*one_by_v / data_freq(pixIdx); + if (Fhkl_errors_mode) { + Fhkl_hessian_coef = -0.5*one_by_v*(one_by_v*Gterm - 2 - 2*u*one_by_v -u*u*one_by_v*one_by_v)/data_freq(pixIdx); + } + } + + // int fcell_idx=1; + int nom_h = 0, nom_k = 0, nom_l = 0; + if (use_nominal_hkl) { + nom_h = nominal_hkl(pixIdx * 3); + nom_k = nominal_hkl(pixIdx * 3 + 1); + nom_l = nominal_hkl(pixIdx * 3 + 2); + } + CUDAREAL close_distance = close_distances(_pid); + + // reset photon count for this pixel + double _I = 0; + double Ilambda = 0; + + kokkos_manager dI, dI2; + dI.reset(); + dI2.reset(); + + for (int _subS = 0; _subS < oversample; ++_subS) { + for (int _subF = 0; _subF < oversample; ++_subF) { + // absolute mm position on detector (relative to its origin) + CUDAREAL _Fdet = + subpixel_size * (_fpixel * oversample + _subF) + subpixel_size / 2.0; + CUDAREAL _Sdet = + subpixel_size * (_spixel * oversample + _subS) + subpixel_size / 2.0; + + // assume "distance" is to the front of the detector sensor layer + int pid_x = _pid * 3; + int pid_y = _pid * 3 + 1; + int pid_z = _pid * 3 + 2; + + + CUDAREAL fx = fdet_vectors(pid_x); + CUDAREAL fy = fdet_vectors(pid_y); + CUDAREAL fz = fdet_vectors(pid_z); + CUDAREAL sx = sdet_vectors(pid_x); + CUDAREAL sy = sdet_vectors(pid_y); + CUDAREAL sz = sdet_vectors(pid_z); + CUDAREAL ox = odet_vectors(pid_x); + CUDAREAL oy = odet_vectors(pid_y); + CUDAREAL oz = odet_vectors(pid_z); + CUDAREAL px = pix0_vectors(pid_x); + CUDAREAL py = pix0_vectors(pid_y); + CUDAREAL pz = pix0_vectors(pid_z); + KOKKOS_VEC3 _o_vec(ox, oy, oz); + + for (int _thick_tic = 0; _thick_tic < detector_thicksteps; ++_thick_tic) { + + CUDAREAL _Odet = _thick_tic * detector_thickstep; + + CUDAREAL pixposX = _Fdet * fx + _Sdet * sx + _Odet * ox + px; + CUDAREAL pixposY = _Fdet * fy + _Sdet * sy + _Odet * oy + py; + CUDAREAL pixposZ = _Fdet * fz + _Sdet * sz + _Odet * oz + pz; + KOKKOS_VEC3 _pixel_pos(pixposX, pixposY, pixposZ); + + CUDAREAL _airpath_r = 1 / _pixel_pos.length(); + KOKKOS_VEC3 _diffracted = _pixel_pos.get_unit_vector(); + + const CUDAREAL close_distance = close_distances(_pid); + + // solid angle subtended by a pixel: (pix/airpath)^2*cos(2theta) + CUDAREAL _omega_pixel = pixel_size * pixel_size * _airpath_r * _airpath_r * + close_distance * _airpath_r; + + // option to turn off obliquity effect, inverse-square-law only + if (point_pixel) + _omega_pixel = _airpath_r * _airpath_r; + + // now calculate detector thickness effects + CUDAREAL _capture_fraction = 1; + + CUDAREAL previous_layer = 1.0; + if (detector_thick > 0.0 && detector_attnlen_r > 0.0) { + // inverse of effective thickness increase + KOKKOS_VEC3 _o_vec(ox, oy, oz); + CUDAREAL _parallax = _diffracted.dot(_o_vec); + CUDAREAL current_layer = ::Kokkos::exp( + -(_thick_tic + 1) * detector_thickstep * + detector_attnlen_r / _parallax); + _capture_fraction = previous_layer - current_layer; + previous_layer = current_layer; + } + + for (int _source = 0; _source < sources; ++_source) { + + KOKKOS_VEC3 _incident( + -source_X(_source), -source_Y(_source), -source_Z(_source)); + CUDAREAL _lambda = source_lambda(_source); + CUDAREAL sI = source_I(_source); + CUDAREAL lambda_ang = _lambda * 1e10; + if (use_lambda_coefficients) { + lambda_ang = lambda0 + lambda1 * lambda_ang; + _lambda = lambda_ang * 1e-10; + } + + // polarization + CUDAREAL polar_for_Fhkl_grad=1; + if (!nopolar && Fhkl_gradient_mode){ + + // component of diffracted unit vector along incident beam unit vector + CUDAREAL cos2theta = _incident.dot(_diffracted); + CUDAREAL cos2theta_sqr = cos2theta*cos2theta; + CUDAREAL sin2theta_sqr = 1-cos2theta_sqr; + + CUDAREAL cos2psi=1; + if(kahn_factor != 0.0){ + // cross product to get "vertical" axis that is orthogonal to the cannonical "polarization" + KOKKOS_VEC3 B_in = polarization_axis.cross(_incident); + // cross product with incident beam to get E-vector direction + KOKKOS_VEC3 E_in = _incident.cross(B_in); + // get components of diffracted ray projected onto the E-B plane + CUDAREAL _kEi = _diffracted.dot(E_in); + CUDAREAL _kBi = _diffracted.dot(B_in); + // compute the angle of the diffracted ray projected onto the incident E-B plane + // calculate cos(2 * atan2(_kBi, _kEi)) + if (_kEi!=0) { + CUDAREAL ratio = _kBi / _kEi; + cos2psi = (1 - ratio*ratio) / (1 + ratio*ratio); + } else { + cos2psi = -1; + } + } + // correction for polarized incident beam + polar_for_Fhkl_grad = 0.5*(1.0 + cos2theta_sqr - kahn_factor*cos2psi*sin2theta_sqr); + } + KOKKOS_VEC3 _scattering = (_diffracted - _incident) / _lambda; + + KOKKOS_VEC3 q_vec = _scattering * 1e-10; + + // TODO rename + CUDAREAL texture_scale = _capture_fraction * _omega_pixel * sI; + + for (int _mos_tic = 0; _mos_tic < mosaic_domains; ++_mos_tic) { + const KOKKOS_MAT3 UBO = Amatrices(_mos_tic); + + KOKKOS_VEC3 H_vec = UBO * q_vec; + CUDAREAL _h = H_vec[0]; + CUDAREAL _k = H_vec[1]; + CUDAREAL _l = H_vec[2]; + + int _h0 = ceil(_h - 0.5); + int _k0 = ceil(_k - 0.5); + int _l0 = ceil(_l - 0.5); + + KOKKOS_VEC3 H0(_h0, _k0, _l0); + + KOKKOS_VEC3 delta_H = H_vec - H0; + KOKKOS_VEC3 V = _NABC * delta_H; + CUDAREAL _hrad_sqr = V.length_sqr(); + CUDAREAL exparg = _hrad_sqr * C / 2; + CUDAREAL I0 = 0; + + if (exparg < 35) + if (no_Nabc_scale) + I0 = ::Kokkos::exp(-2 * exparg); + else + I0 = (NABC_det_sq) * + ::Kokkos::exp(-2 * exparg); + + // are we doing diffuse scattering + CUDAREAL step_diffuse_param[6] = {0, 0, 0, 0, 0, 0}; + if (use_diffuse) { + calc_diffuse_at_hkl(H_vec,H0,dHH,h_min,k_min,l_min,h_max,k_max,l_max,h_range,k_range,l_range,Ainv,FhklLinear,num_laue_mats,laue_mats,anisoG_local,dG_trace,anisoG_determ,anisoU_local,dG_dgam,(refine_flag & REFINE_DIFFUSE)>0,&I0,step_diffuse_param); + } // end s_use_diffuse outer + + CUDAREAL _F_cell = default_F; + CUDAREAL _F_cell2 = 0; + int i_hklasu=0; + + if ((_h0 <= h_max) && (_h0 >= h_min) && + (_k0 <= k_max) && (_k0 >= k_min) && + (_l0 <= l_max) && (_l0 >= l_min)) { + int Fhkl_linear_index = (_h0 - h_min) * k_range * l_range + + (_k0 - k_min) * l_range + (_l0 - l_min); + //_F_cell = __ldg(&FhklLinear[Fhkl_linear_index]); + _F_cell = FhklLinear(Fhkl_linear_index); + // if (complex_miller) _F_cell2 = + // __ldg(&Fhkl2Linear[Fhkl_linear_index]); + if (complex_miller) + _F_cell2 = Fhkl2Linear(Fhkl_linear_index); + if (Fhkl_have_scale_factors) + i_hklasu = FhklLinear_ASUid(Fhkl_linear_index); + } + + CUDAREAL c_deriv_Fcell = 0; + CUDAREAL d_deriv_Fcell = 0; + if (complex_miller) { + CUDAREAL c_deriv_Fcell_real = 0; + CUDAREAL c_deriv_Fcell_imag = 0; + CUDAREAL d_deriv_Fcell_real = 0; + CUDAREAL d_deriv_Fcell_imag = 0; + if (num_atoms > 0) { + CUDAREAL S_2 = (q_vec[0] * q_vec[0] + + q_vec[1] * q_vec[1] + + q_vec[2] * q_vec[2]); + + // fp is always followed by the fdp value + CUDAREAL val_fp = fpfdp(2 * _source); + CUDAREAL val_fdp = fpfdp(2 * _source + 1); + + CUDAREAL c_deriv_prime = 0; + CUDAREAL c_deriv_dblprime = 0; + CUDAREAL d_deriv_prime = 0; + CUDAREAL d_deriv_dblprime = 0; + if (refine_flag & REFINE_FP_FDP) { + // currently only supports two parameter model + int d_idx = 2 * _source; + c_deriv_prime = fpfdp_derivs(d_idx); + c_deriv_dblprime = fpfdp_derivs(d_idx + 1); + d_deriv_prime = fpfdp_derivs(d_idx + 2 * sources); + d_deriv_dblprime = + fpfdp_derivs(d_idx + 1 + 2 * sources); } - } // end Ncells manager deriv - - if (refine_Ncells_def) { - for (int i_nc = 3; i_nc < 6; i_nc++) { - KOKKOS_MAT3 dN; - if (i_nc == 3) - dN = KOKKOS_MAT3{0, 1, 0, 1, 0, 0, 0, 0, 0}; - else if (i_nc == 4) - dN = KOKKOS_MAT3{0, 0, 0, 0, 0, 1, 0, 1, 0}; - else - dN = KOKKOS_MAT3{0, 0, 1, 0, 0, 0, 1, 0, 0}; - KOKKOS_VEC3 dV_dN = dN.dot(delta_H); - // TODO speedops: precompute these - CUDAREAL determ_deriv = (_NABC.inverse().dot(dN)).trace(); - CUDAREAL deriv_coef = determ_deriv - C * (dV_dN.dot(V)); - CUDAREAL value = 2 * Iincrement * deriv_coef; - Ncells_manager_dI[i_nc] += value; - CUDAREAL value2 = 0; - if (compute_curvatures) { - value2 = deriv_coef * value; - value2 += -2 * C * Iincrement * (dV_dN.dot(dV_dN)); - Ncells_manager_dI2[i_nc] += value2; + + for (int i_atom = 0; i_atom < num_atoms; i_atom++) { + // fractional atomic coordinates + CUDAREAL atom_x = atom_data(i_atom * 5); + CUDAREAL atom_y = atom_data(i_atom * 5 + 1); + CUDAREAL atom_z = atom_data(i_atom * 5 + 2); + CUDAREAL B = atom_data(i_atom * 5 + 3); // B factor + B = ::Kokkos::exp( + -B * S_2 / 4.0); // TODO: speed me up? + CUDAREAL occ = atom_data(i_atom * 5 + 4); // occupancy + CUDAREAL r_dot_h = + _h0 * atom_x + _k0 * atom_y + _l0 * atom_z; + CUDAREAL phase = 2 * M_PI * r_dot_h; + CUDAREAL s_rdoth = ::Kokkos::sin(phase); + CUDAREAL c_rdoth = ::Kokkos::cos(phase); + CUDAREAL Bocc = B * occ; + CUDAREAL BC = B * c_rdoth; + CUDAREAL BS = B * s_rdoth; + CUDAREAL real_part = BC * val_fp - BS * val_fdp; + CUDAREAL imag_part = BS * val_fp + BC * val_fdp; + _F_cell += real_part; + _F_cell2 += imag_part; + if (refine_flag & REFINE_FP_FDP) { + c_deriv_Fcell_real += + BC * c_deriv_prime - BS * c_deriv_dblprime; + c_deriv_Fcell_imag += + BS * c_deriv_prime + BC * c_deriv_dblprime; + + d_deriv_Fcell_real += + BC * d_deriv_prime - BS * d_deriv_dblprime; + d_deriv_Fcell_imag += + BS * d_deriv_prime + BC * d_deriv_dblprime; } } } + CUDAREAL Freal = _F_cell; + CUDAREAL Fimag = _F_cell2; + _F_cell = + ::Kokkos::sqrt(Freal * Freal + Fimag * Fimag); + if (refine_flag & REFINE_FP_FDP) { + c_deriv_Fcell = + Freal * c_deriv_Fcell_real + Fimag * c_deriv_Fcell_imag; + d_deriv_Fcell = + Freal * d_deriv_Fcell_real + Fimag * d_deriv_Fcell_imag; + } + } + if (!oversample_omega && ! Fhkl_gradient_mode) + _omega_pixel = 1; + + CUDAREAL _I_cell = _F_cell; + if (!(refine_flag & REFINE_ICELL)) + _I_cell *= _F_cell; + CUDAREAL hkl=1; + int Fhkl_channel=0; + if (! Fhkl_channels_empty) + Fhkl_channel = Fhkl_channels(_source); + if (Fhkl_have_scale_factors) + hkl = Fhkl_scale(i_hklasu + Fhkl_channel*Num_ASU); + if (Fhkl_gradient_mode){ + CUDAREAL Fhkl_deriv_scale = overall_scale*polar_for_Fhkl_grad; + CUDAREAL I_noFcell=texture_scale*I0; + CUDAREAL dfhkl = I_noFcell*_I_cell * Fhkl_deriv_scale; + CUDAREAL grad_incr = dfhkl*Fhkl_deriv_coef; + int fhkl_grad_idx=i_hklasu + Fhkl_channel*Num_ASU; + + if (Fhkl_errors_mode){ + // here we hi-kack the Fhkl_scale_deriv array, if computing errors, in order to store the hessian terms + // if we are getting the hessian terms, we no longer need the gradients (e.g. by this point we are done refininig) + CUDAREAL hessian_incr = Fhkl_hessian_coef*dfhkl*dfhkl; + ::Kokkos::atomic_add(&Fhkl_scale_deriv(fhkl_grad_idx), hessian_incr); + } + else{ + ::Kokkos::atomic_add(&Fhkl_scale_deriv(fhkl_grad_idx), grad_incr); + } + continue; + } - // Checkpoint for Origin manager - for (int i_pan_orig = 0; i_pan_orig < 3; i_pan_orig++) { - if (refine_panel_origin(i_pan_orig)) { - CUDAREAL per_k = 1 / _airpath; - CUDAREAL per_k3 = pow(per_k, 3.); - CUDAREAL per_k5 = pow(per_k, 5.); - CUDAREAL lambda_ang = _lambda * 1e10; - - KOKKOS_MAT3 M = -two_C * (_NABC.dot(UBO)) / lambda_ang; - KOKKOS_VEC3 dk; - if (i_pan_orig == 0) - dk = KOKKOS_VEC3{0, 0, 1}; - else if (i_pan_orig == 1) - dk = KOKKOS_VEC3{1, 0, 0}; - else - dk = KOKKOS_VEC3{0, 1, 0}; - - CUDAREAL G = dk.dot(_pixel_pos); - CUDAREAL pix2 = subpixel_size * subpixel_size; - KOKKOS_VEC3 dk_hat = -per_k3 * G * _pixel_pos + per_k * dk; - CUDAREAL coef = (M.dot(dk_hat)).dot(V); - CUDAREAL coef2 = - -3 * pix2 * per_k5 * G * (_o_vec.dot(_pixel_pos)); - coef2 += pix2 * per_k3 * (_o_vec.dot(dk)); - CUDAREAL value = - coef * Iincrement + coef2 * Iincrement / _omega_pixel; - - pan_orig_manager_dI[i_pan_orig] += value; - pan_orig_manager_dI2[i_pan_orig] += 0; - - } // end origin manager deriv + CUDAREAL _I_total = hkl*_I_cell *I0; + CUDAREAL Iincrement = _I_total * texture_scale; + _I += Iincrement; + if (save_wavelenimage) + Ilambda += Iincrement * lambda_ang; + + if (refine_flag & REFINE_DIFFUSE) { + CUDAREAL step_scale = texture_scale * _F_cell * _F_cell; + for (int i_diff = 0; i_diff < 6; i_diff++) { + dI.diffuse[i_diff] += + step_scale * step_diffuse_param[i_diff]; } + } + + //************************************************* + // START REFINEMENT - for (int i_pan_rot = 0; i_pan_rot < 3; i_pan_rot++) { - if (refine_panel_rot(i_pan_rot)) { - CUDAREAL per_k = 1 / _airpath; - CUDAREAL per_k3 = pow(per_k, 3.); - CUDAREAL per_k5 = pow(per_k, 5.); - CUDAREAL lambda_ang = _lambda * 1e10; - KOKKOS_MAT3 M = -two_C * (_NABC.dot(UBO)) / lambda_ang; - KOKKOS_VEC3 dk = _Fdet * (dF_vecs(_pid * 3 + i_pan_rot)) + - _Sdet * (dS_vecs(_pid * 3 + i_pan_rot)); - CUDAREAL G = dk.dot(_pixel_pos); - CUDAREAL pix2 = subpixel_size * subpixel_size; - KOKKOS_VEC3 dk_hat = -per_k3 * G * _pixel_pos + per_k * dk; - CUDAREAL coef = (M.dot(dk_hat)).dot(V); - CUDAREAL coef2 = - -3 * pix2 * per_k5 * G * (_o_vec.dot(_pixel_pos)); - coef2 += pix2 * per_k3 * (_o_vec.dot(dk)); - CUDAREAL value = - coef * Iincrement + coef2 * Iincrement / _omega_pixel; - - pan_rot_manager_dI[i_pan_rot] += value; - pan_rot_manager_dI2[i_pan_rot] += 0; + if (refine_flag & REFINE_FP_FDP) { + CUDAREAL I_noFcell = texture_scale * I0; + dI.fp_fdp[0] += 2 * I_noFcell * (c_deriv_Fcell); + dI.fp_fdp[1] += 2 * I_noFcell * (d_deriv_Fcell); + } + + if (verbose > 3) + printf( + "hkl= %f %f %f hkl1= %d %d %d Fcell=%f\n", _h, _k, _l, + _h0, _k0, _l0, _F_cell); + + KOKKOS_MAT3 UBOt; + if (refine_flag & (REFINE_UMAT | REFINE_ETA)) { + UBOt = Amat_init; + } + if (refine_flag & REFINE_UMAT1) { + const KOKKOS_VEC3 dV = UMATS_prime(_mos_tic, 0) * q_vec; + const CUDAREAL V_dot_dV = V.dot(dV); + const CUDAREAL value = -two_C * V_dot_dV * Iincrement; + CUDAREAL value2 = 0; + if (compute_curvatures) { + const CUDAREAL dV_dot_dV = dV.length_sqr(); + const CUDAREAL dV2_dot_V = V.dot(UMATS_dbl_prime(_mos_tic, 0)*q_vec); + value2 = two_C * (two_C * V_dot_dV * V_dot_dV - dV2_dot_V - dV_dot_dV) * Iincrement; + } + dI.rot[0] += value; + dI2.rot[0] += value2; + } + if (refine_flag & REFINE_UMAT2) { + KOKKOS_VEC3 dV = UMATS_prime(_mos_tic, 1) * q_vec; + CUDAREAL V_dot_dV = V.dot(dV); + CUDAREAL value = -two_C * V_dot_dV * Iincrement; + + CUDAREAL value2 = 0; + if (compute_curvatures) { + const CUDAREAL dV_dot_dV = dV.length_sqr(); + CUDAREAL dV2_dot_V = V.dot(UMATS_dbl_prime(_mos_tic, 1)*q_vec); + value2 = two_C * (two_C * V_dot_dV * V_dot_dV - dV2_dot_V - dV_dot_dV) * Iincrement; + } + dI.rot[1] += value; + dI2.rot[1] += value2; + } + if (refine_flag & REFINE_UMAT3) { + KOKKOS_VEC3 dV = UMATS_prime(_mos_tic, 2) * q_vec; + CUDAREAL V_dot_dV = V.dot(dV); + CUDAREAL value = -two_C * V_dot_dV * Iincrement; + + CUDAREAL value2 = 0; + if (compute_curvatures) { + const CUDAREAL dV_dot_dV = dV.length_sqr(); + CUDAREAL dV2_dot_V = V.dot(UMATS_dbl_prime(_mos_tic, 2)*q_vec); + value2 = two_C * (two_C * V_dot_dV * V_dot_dV - dV2_dot_V - dV_dot_dV) * Iincrement; + } + dI.rot[2] += value; + dI2.rot[2] += value2; + } + // Checkpoint for unit cell derivatives + for (int i_uc = 0; i_uc < 6; i_uc++) { + if (refine_flag & (REFINE_BMAT1 << i_uc)) { + KOKKOS_VEC3 dV = BMATS_prime(_mos_tic, i_uc) * q_vec; + CUDAREAL V_dot_dV = V.dot(dV); + CUDAREAL value = -two_C * V_dot_dV * Iincrement; + CUDAREAL value2 = 0; + if (compute_curvatures) { + const CUDAREAL dV_dot_dV = dV.length_sqr(); + CUDAREAL dV2_dot_V = V.dot(BMATS_dbl_prime(_mos_tic, i_uc)*q_vec); + value2 = two_C * (two_C * V_dot_dV * V_dot_dV - dV2_dot_V - dV_dot_dV) * Iincrement; } + dI.ucell[i_uc] += value; + dI2.ucell[i_uc] += value2; } - - // checkpoint for Fcell manager - if (refine_fcell) { - CUDAREAL value; - if (refine_Icell) - value = I0 * texture_scale; - else - value = 2 * I0 * _F_cell * - texture_scale; // Iincrement/_F_cell ; + } // end ucell deriv + + // Checkpoint for Ncells manager + if (refine_flag & REFINE_NCELLS1) { + int num_ncell_deriv = 1; + if (!isotropic_ncells) + num_ncell_deriv = 3; + for (int i_nc = 0; i_nc < num_ncell_deriv; i_nc++) { + KOKKOS_MAT3 dN; + dN(i_nc, i_nc) = 1; + if (num_ncell_deriv == 1) { + dN(0, 0) = 1; + dN(1, 1) = 1; + dN(2, 2) = 1; + } + CUDAREAL N_i = _NABC(i_nc, i_nc); + KOKKOS_VEC3 dV_dN = dN.dot(delta_H); + // TODO speedops: precompute these, store shared var + // _NABC.inverse + CUDAREAL determ_deriv = (_NABC.inverse().dot(dN)).trace(); + CUDAREAL deriv_coef = determ_deriv - C * (dV_dN.dot(V)); + CUDAREAL value = 2 * Iincrement * deriv_coef; CUDAREAL value2 = 0; if (compute_curvatures) { - // NOTE if _Fcell >0 - value2 = 2 * I0 * texture_scale; + value2 = (-1 / N_i / N_i - C * (dV_dN.dot(dV_dN))) * 2 * + Iincrement; + value2 += deriv_coef * 2 * value; } - // if (fcell_idx >=0 && fcell_idx <=2){ - if (use_nominal_hkl) { - if (_h0 == nom_h && _k0 == nom_k && _l0 == nom_l) { - fcell_manager_dI += value; - fcell_manager_dI2 += value2; - } - } else { - fcell_manager_dI += value; - fcell_manager_dI2 += value2; + dI.Ncells[i_nc] += value; + dI2.Ncells[i_nc] += value2; + } + } // end Ncells manager deriv + + if (refine_flag & REFINE_NCELLS_DEF) { + for (int i_nc = 3; i_nc < 6; i_nc++) { + KOKKOS_MAT3 dN; + if (i_nc == 3) + dN = KOKKOS_MAT3{0, 1, 0, 1, 0, 0, 0, 0, 0}; + else if (i_nc == 4) + dN = KOKKOS_MAT3{0, 0, 0, 0, 0, 1, 0, 1, 0}; + else + dN = KOKKOS_MAT3{0, 0, 1, 0, 0, 0, 1, 0, 0}; + KOKKOS_VEC3 dV_dN = dN.dot(delta_H); + // TODO speedops: precompute these + CUDAREAL determ_deriv = (_NABC.inverse().dot(dN)).trace(); + CUDAREAL deriv_coef = determ_deriv - C * (dV_dN.dot(V)); + CUDAREAL value = 2 * Iincrement * deriv_coef; + dI.Ncells[i_nc] += value; + CUDAREAL value2 = 0; + if (compute_curvatures) { + value2 = deriv_coef * value; + value2 += -2 * C * Iincrement * (dV_dN.dot(dV_dN)); + dI2.Ncells[i_nc] += value2; } - } // end of fcell man deriv - - // checkpoint for eta manager - if (refine_eta) { - for (int i_eta = 0; i_eta < 3; i_eta++) { - if (i_eta > 0 && !aniso_eta) - continue; - int mtic2 = _mos_tic + i_eta * mosaic_domains; - KOKKOS_VEC3 DeltaH_deriv = (UMATS_RXYZ_prime(mtic2).dot(UBOt)) - .transpose() - .dot(q_vec); - // vector V is _Nabc*Delta_H - KOKKOS_VEC3 dV = _NABC.dot(DeltaH_deriv); - CUDAREAL V_dot_dV = V.dot(dV); - CUDAREAL Iprime = -two_C * (V_dot_dV)*Iincrement; - eta_manager_dI[i_eta] += Iprime; - CUDAREAL Idbl_prime = 0; - if (compute_curvatures) { - KOKKOS_VEC3 DeltaH_second_deriv = - (UMATS_RXYZ_dbl_prime(mtic2).dot(UBOt)) - .transpose() - .dot(q_vec); - KOKKOS_VEC3 dV2 = _NABC.dot(DeltaH_second_deriv); - Idbl_prime = - -two_C * (dV.dot(dV) + V.dot(dV2)) * Iincrement; - Idbl_prime += -two_C * (V_dot_dV)*Iprime; - } - eta_manager_dI2[i_eta] += Idbl_prime; + } + } + + // Checkpoint for Origin manager + for (int i_pan_orig = 0; i_pan_orig < 3; i_pan_orig++) { + if (refine_flag & (REFINE_PANEL_ORIGIN1 << i_pan_orig)) { + CUDAREAL per_k = _airpath_r; + CUDAREAL per_k3 = pow(per_k, 3.); + CUDAREAL per_k5 = pow(per_k, 5.); + + KOKKOS_MAT3 M = -two_C * (_NABC.dot(UBO)) / lambda_ang; + KOKKOS_VEC3 dk; + if (i_pan_orig == 0) + dk = KOKKOS_VEC3{0, 0, 1}; + else if (i_pan_orig == 1) + dk = KOKKOS_VEC3{1, 0, 0}; + else + dk = KOKKOS_VEC3{0, 1, 0}; + + CUDAREAL G = dk.dot(_pixel_pos); + CUDAREAL pix2 = subpixel_size * subpixel_size; + KOKKOS_VEC3 dk_hat = -per_k3 * G * _pixel_pos + per_k * dk; + CUDAREAL coef = (M.dot(dk_hat)).dot(V); + CUDAREAL coef2 = + -3 * pix2 * per_k5 * G * (_o_vec.dot(_pixel_pos)); + coef2 += pix2 * per_k3 * (_o_vec.dot(dk)); + CUDAREAL value = + coef * Iincrement + coef2 * Iincrement / _omega_pixel; + + dI.pan_orig[i_pan_orig] += value; + dI2.pan_orig[i_pan_orig] += 0; + + } // end origin manager deriv + } + + for (int i_pan_rot = 0; i_pan_rot < 3; i_pan_rot++) { + if (refine_flag & (REFINE_PANEL_ROT1 << i_pan_rot)) { + CUDAREAL per_k = _airpath_r; + CUDAREAL per_k3 = pow(per_k, 3.); + CUDAREAL per_k5 = pow(per_k, 5.); + KOKKOS_MAT3 M = -two_C * (_NABC.dot(UBO)) / lambda_ang; + KOKKOS_VEC3 dk = _Fdet * (dF_vecs(_pid * 3 + i_pan_rot)) + + _Sdet * (dS_vecs(_pid * 3 + i_pan_rot)); + CUDAREAL G = dk.dot(_pixel_pos); + CUDAREAL pix2 = subpixel_size * subpixel_size; + KOKKOS_VEC3 dk_hat = -per_k3 * G * _pixel_pos + per_k * dk; + CUDAREAL coef = (M.dot(dk_hat)).dot(V); + CUDAREAL coef2 = + -3 * pix2 * per_k5 * G * (_o_vec.dot(_pixel_pos)); + coef2 += pix2 * per_k3 * (_o_vec.dot(dk)); + CUDAREAL value = + coef * Iincrement + coef2 * Iincrement / _omega_pixel; + + dI.pan_rot[i_pan_rot] += value; + dI2.pan_rot[i_pan_rot] += 0; + } + } + + // checkpoint for Fcell manager + if (refine_flag & REFINE_FCELL) { + CUDAREAL value; + if (refine_flag & REFINE_ICELL) + value = I0 * texture_scale; + else + value = 2 * I0 * _F_cell * + texture_scale; // Iincrement/_F_cell ; + CUDAREAL value2 = 0; + if (compute_curvatures) { + // NOTE if _Fcell >0 + value2 = 2 * I0 * texture_scale; + } + // if (fcell_idx >=0 && fcell_idx <=2){ + if (use_nominal_hkl) { + if (_h0 == nom_h && _k0 == nom_k && _l0 == nom_l) { + dI.fcell += value; + dI2.fcell += value2; } - } // end of eta man deriv - - // checkpoint for lambda manager - for (int i_lam = 0; i_lam < 2; i_lam++) { - if (refine_lambda(i_lam)) { - CUDAREAL lambda_ang = _lambda * 1e10; - CUDAREAL NH_dot_V = (_NABC.dot(H_vec)).dot(V); - CUDAREAL dg_dlambda; - if (i_lam == 0) - dg_dlambda = 1; - else // i_lam==1 - dg_dlambda = lambda_ang; - CUDAREAL coef = - NH_dot_V * two_C * (dg_dlambda) / lambda_ang; - CUDAREAL value = coef * Iincrement; - CUDAREAL value2 = 0; - lambda_manager_dI[i_lam] += value; - lambda_manager_dI2[i_lam] += value2; + } else { + dI.fcell += value; + dI2.fcell += value2; + } + } // end of fcell man deriv + + // checkpoint for eta manager + if (refine_flag & REFINE_ETA) { + for (int i_eta = 0; i_eta < 3; i_eta++) { + if (i_eta > 0 && !aniso_eta) + continue; + int mtic2 = _mos_tic + i_eta * mosaic_domains; + KOKKOS_VEC3 DeltaH_deriv = (UMATS_RXYZ_prime(mtic2).dot(UBOt)) + .transpose() + .dot(q_vec); + // vector V is _Nabc*Delta_H + KOKKOS_VEC3 dV = _NABC.dot(DeltaH_deriv); + CUDAREAL V_dot_dV = V.dot(dV); + CUDAREAL Iprime = -two_C * (V_dot_dV)*Iincrement; + dI.eta[i_eta] += Iprime; + CUDAREAL Idbl_prime = 0; + if (compute_curvatures) { + KOKKOS_VEC3 DeltaH_second_deriv = + (UMATS_RXYZ_dbl_prime(mtic2).dot(UBOt)) + .transpose() + .dot(q_vec); + KOKKOS_VEC3 dV2 = _NABC.dot(DeltaH_second_deriv); + Idbl_prime = + -two_C * (dV.dot(dV) + V.dot(dV2)) * Iincrement; + Idbl_prime += -two_C * (V_dot_dV)*Iprime; } + dI2.eta[i_eta] += Idbl_prime; } - // end of lambda deriv - if (printout) { - if (_subS == 0 && _subF == 0 && _thick_tic == 0 && - _source == 0 && _mos_tic == 0) { - if ((_fpixel == printout_fpixel && - _spixel == printout_spixel) || - printout_fpixel < 0) { - printf( - "%4d %4d : lambda = %g\n", _fpixel, _spixel, - _lambda); - printf( - "at %g %g %g\n", _pixel_pos[0], _pixel_pos[1], - _pixel_pos[2]); - printf( - "Fdet= %g; Sdet= %g ; Odet= %g\n", _Fdet, _Sdet, - _Odet); - printf( - "PIX0: %f %f %f\n", pix0_vectors(pid_x), - pix0_vectors(pid_y), pix0_vectors(pid_z)); - printf( - "F: %f %f %f\n", fdet_vectors(pid_x), - fdet_vectors(pid_y), fdet_vectors(pid_z)); - printf( - "S: %f %f %f\n", sdet_vectors(pid_x), - sdet_vectors(pid_y), sdet_vectors(pid_z)); - printf( - "O: %f %f %f\n", odet_vectors(pid_x), - odet_vectors(pid_y), odet_vectors(pid_z)); - printf( - "pid_x=%d, pid_y=%d; pid_z=%d\n", pid_x, pid_y, - pid_z); - - printf( - "QVECTOR: %f %f %f\n", q_vec[0], q_vec[1], - q_vec[2]); - KOKKOS_MAT3 UU = UMATS_RXYZ(_mos_tic); - printf( - "UMAT_RXYZ :\n%f %f %f\n%f %f %f\n%f %f %f\n", - UU(0, 0), UU(0, 1), UU(0, 2), UU(1, 0), UU(1, 1), - UU(1, 2), UU(2, 0), UU(2, 1), UU(2, 2)); - UU = Bmat_realspace; - printf( - "Bmat_realspace :\n%f %f %f\n%f %f %f\n%f %f %f\n", - UU(0, 0), UU(0, 1), UU(0, 2), UU(1, 0), UU(1, 1), - UU(1, 2), UU(2, 0), UU(2, 1), UU(2, 2)); - UU = UBO; - printf( - "UBO :\n%f %f %f\n%f %f %f\n%f %f %f\n", - UU(0, 0), UU(0, 1), UU(0, 2), UU(1, 0), UU(1, 1), - UU(1, 2), UU(2, 0), UU(2, 1), UU(2, 2)); - - UU = UBOt; - printf( - "UBOt :\n%f %f %f\n%f %f %f\n%f %f %f\n", - UU(0, 0), UU(0, 1), UU(0, 2), UU(1, 0), UU(1, 1), - UU(1, 2), UU(2, 0), UU(2, 1), UU(2, 2)); - - UU = UmosRxRyRzU; - printf( - "UmosRxRyRzU :\n%f %f %f\n%f %f %f\n%f %f %f\n", - UU(0, 0), UU(0, 1), UU(0, 2), UU(1, 0), UU(1, 1), - UU(1, 2), UU(2, 0), UU(2, 1), UU(2, 2)); - KOKKOS_VEC3 AA = delta_H_prime; - printf( - "delta_H_prime :\n%f %f %f\n", AA[0], AA[1], - AA[2]); - printf("Iincrement: %f\n", Iincrement); - printf( - "hkl= %f %f %f hkl0= %d %d %d\n", _h, _k, _l, _h0, - _k0, _l0); - printf( - " F_cell=%g F_cell2=%g I_latt=%g I = %g\n", - _F_cell, _F_cell2, I0, _I); - printf("I/steps %15.10g\n", _I / Nsteps); - // printf("Ilatt diffuse %15.10g\n", I_latt_diffuse); - printf("omega %15.10g\n", _omega_pixel); - printf("default_F= %f\n", default_F); - printf( - "Incident[0]=%g, Incident[1]=%g, Incident[2]=%g\n", - _incident[0], _incident[1], _incident[2]); - if (complex_miller) - printf("COMPLEX MILLER!\n"); - if (no_Nabc_scale) - printf("No Nabc scale!\n"); - } + } // end of eta man deriv + + // checkpoint for lambda manager + for (int i_lam = 0; i_lam < 2; i_lam++) { + if (refine_flag & (REFINE_LAMBDA << i_lam)) { + CUDAREAL NH_dot_V = (_NABC.dot(H_vec)).dot(V); + CUDAREAL dg_dlambda; + if (i_lam == 0) + dg_dlambda = 1; + else // i_lam==1 + dg_dlambda = lambda_ang; + CUDAREAL coef = + NH_dot_V * two_C * (dg_dlambda) / lambda_ang; + CUDAREAL value = coef * Iincrement; + CUDAREAL value2 = 0; + dI.lambda[i_lam] += value; + dI2.lambda[i_lam] += value2; + } + } + // end of lambda deriv + if (printout) { + if (_subS == 0 && _subF == 0 && _thick_tic == 0 && + _source == 0 && _mos_tic == 0) { + if ((_fpixel == printout_fpixel && + _spixel == printout_spixel) || + printout_fpixel < 0) { + printf("%4d %4d : lambda = %g\n", _fpixel, _spixel, _lambda); + printf( + "at %g %g %g\n", _pixel_pos[0], _pixel_pos[1], + _pixel_pos[2]); + printf("Fdet= %g; Sdet= %g ; Odet= %g\n", _Fdet, _Sdet, _Odet); + printf( + "PIX0: %f %f %f\n", pix0_vectors(pid_x), + pix0_vectors(pid_y), pix0_vectors(pid_z)); + printf( + "F: %f %f %f\n", fdet_vectors(pid_x), + fdet_vectors(pid_y), fdet_vectors(pid_z)); + printf( + "S: %f %f %f\n", sdet_vectors(pid_x), + sdet_vectors(pid_y), sdet_vectors(pid_z)); + printf( + "O: %f %f %f\n", odet_vectors(pid_x), + odet_vectors(pid_y), odet_vectors(pid_z)); + printf("pid_x=%d, pid_y=%d; pid_z=%d\n", pid_x, pid_y, pid_z); + printf( + "QVECTOR: %f %f %f\n", q_vec[0], q_vec[1], q_vec[2]); + printf("omega %15.10g\n", _omega_pixel); + printf( + "Incident: %g %g %g\n", + _incident[0], _incident[1], _incident[2]); + + KOKKOS_MAT3 UU = UMATS_RXYZ(_mos_tic); + printf( + "UMAT_RXYZ :\n%f %f %f\n%f %f %f\n%f %f %f\n", + UU(0, 0), UU(0, 1), UU(0, 2), UU(1, 0), UU(1, 1), + UU(1, 2), UU(2, 0), UU(2, 1), UU(2, 2)); + UU = Bmat_realspace; + printf( + "Bmat_realspace :\n%f %f %f\n%f %f %f\n%f %f %f\n", + UU(0, 0), UU(0, 1), UU(0, 2), UU(1, 0), UU(1, 1), + UU(1, 2), UU(2, 0), UU(2, 1), UU(2, 2)); + UU = UBO; + printf( + "UBO :\n%f %f %f\n%f %f %f\n%f %f %f\n", + UU(0, 0), UU(0, 1), UU(0, 2), UU(1, 0), UU(1, 1), + UU(1, 2), UU(2, 0), UU(2, 1), UU(2, 2)); + + UU = UBOt; + printf( + "UBOt :\n%f %f %f\n%f %f %f\n%f %f %f\n", + UU(0, 0), UU(0, 1), UU(0, 2), UU(1, 0), UU(1, 1), + UU(1, 2), UU(2, 0), UU(2, 1), UU(2, 2)); + + // UU = UmosRxRyRzU; + // printf( + // "UmosRxRyRzU :\n%f %f %f\n%f %f %f\n%f %f %f\n", + // UU(0, 0), UU(0, 1), UU(0, 2), UU(1, 0), UU(1, 1), + // UU(1, 2), UU(2, 0), UU(2, 1), UU(2, 2)); + // KOKKOS_VEC3 AA = delta_H_prime; + // printf( + // "delta_H_prime :\n%f %f %f\n", AA[0], AA[1], + // AA[2]); + printf("Iincrement: %f\n", Iincrement); + printf( + "hkl= %f %f %f hkl0= %d %d %d\n", _h, _k, _l, _h0, + _k0, _l0); + printf( + " F_cell=%g F_cell2=%g I_latt=%g I = %g\n", + _F_cell, _F_cell2, I0, _I); + printf("I/steps %15.10g\n", _I / Nsteps); + // printf("Ilatt diffuse %15.10g\n", I_latt_diffuse); + printf("default_F= %f\n", default_F); + if (complex_miller) + printf("COMPLEX MILLER!\n"); + if (no_Nabc_scale) + printf("No Nabc scale!\n"); } } + } // end of printout if + + } // end of mos_tic loop + } // end of source loop + } // end of thick step loop + } // end of fpos loop + } // end of spos loop + floatimage(pixIdx) = _I; + if (save_wavelenimage) + wavelenimage(pixIdx) = Ilambda / _I; + + if (refine_flag) { + manager_dI(pixIdx) = dI; + manager_dI2(pixIdx) = dI2; + } + }); // end pixIdx loop - } // end of mos_tic loop - } // end of source loop - } // end of thick step loop - } // end of fpos loop - } // end of spos loop - if (Fhkl_gradient_mode) - return; + if (Fhkl_gradient_mode) + return; - CUDAREAL _Fdet_ave = pixel_size * _fpixel + pixel_size / 2.0; - CUDAREAL _Sdet_ave = pixel_size * _spixel + pixel_size / 2.0; - CUDAREAL _Odet_ave = 0; // Odet; - // TODO maybe make this more general for thick detectors? - - KOKKOS_VEC3 _pixel_pos_ave(0, 0, 0); - int pid_x = _pid * 3; - int pid_y = _pid * 3 + 1; - int pid_z = _pid * 3 + 2; - - CUDAREAL fx = fdet_vectors(pid_x); - CUDAREAL fy = fdet_vectors(pid_y); - CUDAREAL fz = fdet_vectors(pid_z); - - CUDAREAL sx = sdet_vectors(pid_x); - CUDAREAL sy = sdet_vectors(pid_y); - CUDAREAL sz = sdet_vectors(pid_z); - - CUDAREAL ox = odet_vectors(pid_x); - CUDAREAL oy = odet_vectors(pid_y); - CUDAREAL oz = odet_vectors(pid_z); - - CUDAREAL px = pix0_vectors(pid_x); - CUDAREAL py = pix0_vectors(pid_y); - CUDAREAL pz = pix0_vectors(pid_z); - - _pixel_pos_ave[0] = _Fdet_ave * fx + _Sdet_ave * sx + _Odet_ave * ox + px; - _pixel_pos_ave[1] = _Fdet_ave * fy + _Sdet_ave * sy + _Odet_ave * oy + py; - _pixel_pos_ave[2] = _Fdet_ave * fz + _Sdet_ave * sz + _Odet_ave * oz + pz; - - CUDAREAL _airpath_ave = _pixel_pos_ave.length(); - KOKKOS_VEC3 _diffracted_ave = _pixel_pos_ave.get_unit_vector(); - CUDAREAL _omega_pixel_ave = pixel_size * pixel_size / _airpath_ave / _airpath_ave * - close_distance / _airpath_ave; - - CUDAREAL _polar = 1; - if (!nopolar) { - KOKKOS_VEC3 _incident(-source_X(0), -source_Y(0), -source_Z(0)); - _incident.normalize(); - // component of diffracted unit vector along _incident beam unit vector - CUDAREAL cos2theta = _incident.dot(_diffracted_ave); - CUDAREAL cos2theta_sqr = cos2theta * cos2theta; - CUDAREAL sin2theta_sqr = 1 - cos2theta_sqr; - - CUDAREAL _psi = 0; - if (kahn_factor != 0.0) { - // cross product to get "vertical" axis that is orthogonal to the cannonical - // "polarization" - KOKKOS_VEC3 B_in = polarization_axis.cross(_incident); - // cross product with _incident beam to get E-vector direction - KOKKOS_VEC3 E_in = _incident.cross(B_in); - // get components of diffracted ray projected onto the E-B plane - CUDAREAL _kEi = _diffracted_ave.dot(E_in); - CUDAREAL _kBi = _diffracted_ave.dot(B_in); - // compute the angle of the diffracted ray projected onto the incident E-B plane - _psi = -atan2(_kBi, _kEi); + Kokkos::parallel_for( + "deriv_image_increment", Npix_to_model, KOKKOS_LAMBDA(const int& pixIdx) { + + int _pid = panels_fasts_slows(pixIdx * 3); + int _fpixel = panels_fasts_slows(pixIdx * 3 + 1); + int _spixel = panels_fasts_slows(pixIdx * 3 + 2); + + CUDAREAL _Fdet_ave = pixel_size * _fpixel + pixel_size / 2.0; + CUDAREAL _Sdet_ave = pixel_size * _spixel + pixel_size / 2.0; + CUDAREAL _Odet_ave = 0; // Odet; + // TODO maybe make this more general for thick detectors? + + KOKKOS_VEC3 _pixel_pos_ave(0, 0, 0); + int pid_x = _pid * 3; + int pid_y = _pid * 3 + 1; + int pid_z = _pid * 3 + 2; + + CUDAREAL fx = fdet_vectors(pid_x); + CUDAREAL fy = fdet_vectors(pid_y); + CUDAREAL fz = fdet_vectors(pid_z); + + CUDAREAL sx = sdet_vectors(pid_x); + CUDAREAL sy = sdet_vectors(pid_y); + CUDAREAL sz = sdet_vectors(pid_z); + + CUDAREAL ox = odet_vectors(pid_x); + CUDAREAL oy = odet_vectors(pid_y); + CUDAREAL oz = odet_vectors(pid_z); + + CUDAREAL px = pix0_vectors(pid_x); + CUDAREAL py = pix0_vectors(pid_y); + CUDAREAL pz = pix0_vectors(pid_z); + + _pixel_pos_ave[0] = _Fdet_ave * fx + _Sdet_ave * sx + _Odet_ave * ox + px; + _pixel_pos_ave[1] = _Fdet_ave * fy + _Sdet_ave * sy + _Odet_ave * oy + py; + _pixel_pos_ave[2] = _Fdet_ave * fz + _Sdet_ave * sz + _Odet_ave * oz + pz; + + CUDAREAL close_distance = close_distances(_pid); + + CUDAREAL _airpath_ave_r = 1 / _pixel_pos_ave.length(); + KOKKOS_VEC3 _diffracted_ave = _pixel_pos_ave.get_unit_vector(); + CUDAREAL _omega_pixel_ave = pixel_size * pixel_size * _airpath_ave_r * _airpath_ave_r * + close_distance * _airpath_ave_r; + + CUDAREAL _polar = 1; + if (!nopolar) { + KOKKOS_VEC3 _incident(-source_X(0), -source_Y(0), -source_Z(0)); + _incident.normalize(); + // component of diffracted unit vector along _incident beam unit vector + CUDAREAL cos2theta = _incident.dot(_diffracted_ave); + CUDAREAL cos2theta_sqr = cos2theta * cos2theta; + CUDAREAL sin2theta_sqr = 1 - cos2theta_sqr; + + CUDAREAL cos2psi = 0; + if (kahn_factor != 0.0) { + // cross product to get "vertical" axis that is orthogonal to the cannonical + // "polarization" + KOKKOS_VEC3 B_in = polarization_axis.cross(_incident); + // cross product with _incident beam to get E-vector direction + KOKKOS_VEC3 E_in = _incident.cross(B_in); + // get components of diffracted ray projected onto the E-B plane + CUDAREAL _kEi = _diffracted_ave.dot(E_in); + CUDAREAL _kBi = _diffracted_ave.dot(B_in); + // compute the angle of the diffracted ray projected onto the incident E-B plane + // calculate cos(2 * atan2(_kBi, _kEi)) + if (_kEi!=0) { + CUDAREAL ratio = _kBi / _kEi; + cos2psi = (1 - ratio*ratio) / (1 + ratio*ratio); + } else { + cos2psi = -1; } - // correction for polarized _incident beam - _polar = - 0.5 * (1.0 + cos2theta_sqr - - kahn_factor * ::Kokkos::Experimental::cos(2 * _psi) * sin2theta_sqr); } + // correction for polarized _incident beam + _polar = 0.5 * (1.0 + cos2theta_sqr - kahn_factor * cos2psi * sin2theta_sqr); + } - CUDAREAL _om = 1; - if (!oversample_omega) - _om = _omega_pixel_ave; - // final scale term to being everything to photon number units - CUDAREAL _scale_term = _polar * _om * overall_scale; - floatimage(pixIdx) = _scale_term * _I; - if (save_wavelenimage) - wavelenimage(pixIdx) = Ilambda / _I; - - // udpate the rotation derivative images* - for (int i_rot = 0; i_rot < 3; i_rot++) { - if (refine_Umat(i_rot)) { - CUDAREAL value = _scale_term * rot_manager_dI[i_rot]; - CUDAREAL value2 = _scale_term * rot_manager_dI2[i_rot]; - int idx = i_rot * Npix_to_model + pixIdx; - d_Umat_images(idx) = value; - d2_Umat_images(idx) = value2; - } - } // end rot deriv image increment - - // update the ucell derivative images - for (int i_uc = 0; i_uc < 6; i_uc++) { - if (refine_Bmat(i_uc)) { - CUDAREAL value = _scale_term * ucell_manager_dI[i_uc]; - CUDAREAL value2 = _scale_term * ucell_manager_dI2[i_uc]; - int idx = i_uc * Npix_to_model + pixIdx; - d_Bmat_images(idx) = value; - d2_Bmat_images(idx) = value2; - } - } // end ucell deriv image increment - - // update the Ncells derivative image - if (refine_Ncells(0)) { - CUDAREAL value = _scale_term * Ncells_manager_dI[0]; - CUDAREAL value2 = _scale_term * Ncells_manager_dI2[0]; - int idx = pixIdx; + CUDAREAL _om = 1; + if (!oversample_omega) + _om = _omega_pixel_ave; + // final scale term to being everything to photon number units + CUDAREAL _scale_term = _polar * _om * overall_scale; + floatimage(pixIdx) *= _scale_term; + + auto& dI = manager_dI(pixIdx); + auto& dI2 = manager_dI2(pixIdx); + + // udpate the rotation derivative images* + for (int i_rot = 0; i_rot < 3; i_rot++) { + if (refine_flag & (REFINE_UMAT1 << i_rot)) { + CUDAREAL value = _scale_term * dI.rot[i_rot]; + CUDAREAL value2 = _scale_term * dI2.rot[i_rot]; + int idx = i_rot * Npix_to_model + pixIdx; + d_Umat_images(idx) = value; + d2_Umat_images(idx) = value2; + } + } // end rot deriv image increment + + // update the ucell derivative images + for (int i_uc = 0; i_uc < 6; i_uc++) { + if (refine_flag & (REFINE_BMAT1 << i_uc)) { + CUDAREAL value = _scale_term * dI.ucell[i_uc]; + CUDAREAL value2 = _scale_term * dI2.ucell[i_uc]; + int idx = i_uc * Npix_to_model + pixIdx; + d_Bmat_images(idx) = value; + d2_Bmat_images(idx) = value2; + } + } // end ucell deriv image increment + + // update the Ncells derivative image + if (refine_flag & REFINE_NCELLS1) { + CUDAREAL value = _scale_term * dI.Ncells[0]; + CUDAREAL value2 = _scale_term * dI2.Ncells[0]; + int idx = pixIdx; + d_Ncells_images(idx) = value; + d2_Ncells_images(idx) = value2; + + if (!isotropic_ncells) { + value = _scale_term * dI.Ncells[1]; + value2 = _scale_term * dI2.Ncells[1]; + idx = Npix_to_model + pixIdx; d_Ncells_images(idx) = value; d2_Ncells_images(idx) = value2; - if (!isotropic_ncells) { - value = _scale_term * Ncells_manager_dI[1]; - value2 = _scale_term * Ncells_manager_dI2[1]; - idx = Npix_to_model + pixIdx; - d_Ncells_images(idx) = value; - d2_Ncells_images(idx) = value2; - - value = _scale_term * Ncells_manager_dI[2]; - value2 = _scale_term * Ncells_manager_dI2[2]; - idx = Npix_to_model * 2 + pixIdx; - d_Ncells_images(idx) = value; - d2_Ncells_images(idx) = value2; - } - } // end Ncells deriv image increment - if (refine_Ncells_def) { - for (int i_nc = 3; i_nc < 6; i_nc++) { - CUDAREAL value = _scale_term * Ncells_manager_dI[i_nc]; - CUDAREAL value2 = _scale_term * Ncells_manager_dI2[i_nc]; - int idx = i_nc * Npix_to_model + pixIdx; - d_Ncells_images(idx) = value; - d2_Ncells_images(idx) = value2; - } + value = _scale_term * dI.Ncells[2]; + value2 = _scale_term * dI2.Ncells[2]; + idx = Npix_to_model * 2 + pixIdx; + d_Ncells_images(idx) = value; + d2_Ncells_images(idx) = value2; + } + } // end Ncells deriv image increment + if (refine_flag & REFINE_NCELLS_DEF) { + for (int i_nc = 3; i_nc < 6; i_nc++) { + CUDAREAL value = _scale_term * dI.Ncells[i_nc]; + CUDAREAL value2 = _scale_term * dI2.Ncells[i_nc]; + int idx = i_nc * Npix_to_model + pixIdx; + d_Ncells_images(idx) = value; + d2_Ncells_images(idx) = value2; } + } - // update Fcell derivative image - if (refine_fcell) { - CUDAREAL value = _scale_term * fcell_manager_dI; - CUDAREAL value2 = _scale_term * fcell_manager_dI2; - d_fcell_images(pixIdx) = value; - d2_fcell_images(pixIdx) = value2; - } // end Fcell deriv image increment - - if (refine_fp_fdp) { - // c derivative - CUDAREAL value = _scale_term * fp_fdp_manager_dI[0]; - d_fp_fdp_images(pixIdx) = value; - // d derivative - value = _scale_term * fp_fdp_manager_dI[1]; - d_fp_fdp_images(Npix_to_model + pixIdx) = value; + // update Fcell derivative image + if (refine_flag & REFINE_FCELL) { + CUDAREAL value = _scale_term * dI.fcell; + CUDAREAL value2 = _scale_term * dI2.fcell; + d_fcell_images(pixIdx) = value; + d2_fcell_images(pixIdx) = value2; + } // end Fcell deriv image increment + + if (refine_flag & REFINE_FP_FDP) { + // c derivative + CUDAREAL value = _scale_term * dI.fp_fdp[0]; + d_fp_fdp_images(pixIdx) = value; + // d derivative + value = _scale_term * dI.fp_fdp[1]; + d_fp_fdp_images(Npix_to_model + pixIdx) = value; + } + if (refine_flag & REFINE_DIFFUSE) { + for (int i_gam = 0; i_gam < 3; i_gam++) { + CUDAREAL val = dI.diffuse[i_gam] * _scale_term; + int img_idx = Npix_to_model * i_gam + pixIdx; + d_diffuse_gamma_images(img_idx) = val; } - if (refine_diffuse) { - for (int i_gam = 0; i_gam < 3; i_gam++) { - CUDAREAL val = dI_diffuse[i_gam] * _scale_term; - int img_idx = Npix_to_model * i_gam + pixIdx; - d_diffuse_gamma_images(img_idx) = val; - } - for (int i_sig = 0; i_sig < 3; i_sig++) { - CUDAREAL val = dI_diffuse[i_sig + 3] * _scale_term; - int img_idx = Npix_to_model * i_sig + pixIdx; - d_diffuse_sigma_images(img_idx) = val; - } + for (int i_sig = 0; i_sig < 3; i_sig++) { + CUDAREAL val = dI.diffuse[i_sig + 3] * _scale_term; + int img_idx = Npix_to_model * i_sig + pixIdx; + d_diffuse_sigma_images(img_idx) = val; } + } - // update eta derivative image - if (refine_eta) { - for (int i_eta = 0; i_eta < 3; i_eta++) { - if (i_eta > 0 && !aniso_eta) - continue; - int idx = pixIdx + Npix_to_model * i_eta; - CUDAREAL value = _scale_term * eta_manager_dI[i_eta]; - CUDAREAL value2 = _scale_term * eta_manager_dI2[i_eta]; - d_eta_images(idx) = value; - d2_eta_images(idx) = value2; - } - } // end eta deriv image increment - - // update the lambda derivative images - for (int i_lam = 0; i_lam < 2; i_lam++) { - if (refine_lambda(i_lam)) { - CUDAREAL value = _scale_term * lambda_manager_dI[i_lam]; - CUDAREAL value2 = _scale_term * lambda_manager_dI2[i_lam]; - int idx = i_lam * Npix_to_model + pixIdx; - d_lambda_images(idx) = value; - // d2_lambda_images(idx) = value2; - } - } // end lambda deriv image increment - - for (int i_pan_rot = 0; i_pan_rot < 3; i_pan_rot++) { - if (refine_panel_rot(i_pan_rot)) { - CUDAREAL value = _scale_term * pan_rot_manager_dI[i_pan_rot]; - CUDAREAL value2 = _scale_term * pan_rot_manager_dI2[i_pan_rot]; - int idx = i_pan_rot * Npix_to_model + pixIdx; - d_panel_rot_images(idx) = value; - // d2_panel_rot_images(idx) = value2; - } - } // end panel rot deriv image increment - - for (int i_pan_orig = 0; i_pan_orig < 3; i_pan_orig++) { - if (refine_panel_origin(i_pan_orig)) { - CUDAREAL value = _scale_term * pan_orig_manager_dI[i_pan_orig]; - CUDAREAL value2 = _scale_term * pan_orig_manager_dI2[i_pan_orig]; - int idx = i_pan_orig * Npix_to_model + pixIdx; - d_panel_orig_images(idx) = value; - // d2_panel_orig_images(idx) = value2; - } - } // end panel orig deriv image increment - }); // end pixIdx loop + // update eta derivative image + if (refine_flag & REFINE_ETA) { + for (int i_eta = 0; i_eta < 3; i_eta++) { + if (i_eta > 0 && !aniso_eta) + continue; + int idx = pixIdx + Npix_to_model * i_eta; + CUDAREAL value = _scale_term * dI.eta[i_eta]; + CUDAREAL value2 = _scale_term * dI2.eta[i_eta]; + d_eta_images(idx) = value; + d2_eta_images(idx) = value2; + } + } // end eta deriv image increment + + // update the lambda derivative images + for (int i_lam = 0; i_lam < 2; i_lam++) { + if (refine_flag & (REFINE_LAMBDA1 << i_lam)) { + CUDAREAL value = _scale_term * dI.lambda[i_lam]; + CUDAREAL value2 = _scale_term * dI2.lambda[i_lam]; + int idx = i_lam * Npix_to_model + pixIdx; + d_lambda_images(idx) = value; + // d2_lambda_images(idx) = value2; + } + } // end lambda deriv image increment + + for (int i_pan_rot = 0; i_pan_rot < 3; i_pan_rot++) { + if (refine_flag & (REFINE_PANEL_ROT1 << i_pan_rot)) { + CUDAREAL value = _scale_term * dI.pan_rot[i_pan_rot]; + CUDAREAL value2 = _scale_term * dI2.pan_rot[i_pan_rot]; + int idx = i_pan_rot * Npix_to_model + pixIdx; + d_panel_rot_images(idx) = value; + // d2_panel_rot_images(idx) = value2; + } + } // end panel rot deriv image increment + + for (int i_pan_orig = 0; i_pan_orig < 3; i_pan_orig++) { + if (refine_flag & (REFINE_PANEL_ORIGIN1 << i_pan_orig)) { + CUDAREAL value = _scale_term * dI.pan_orig[i_pan_orig]; + CUDAREAL value2 = _scale_term * dI2.pan_orig[i_pan_orig]; + int idx = i_pan_orig * Npix_to_model + pixIdx; + d_panel_orig_images(idx) = value; + // d2_panel_orig_images(idx) = value2; + } + } // end panel orig deriv image increment + }); // end pixIdx loop } // END of GPU kernel + +template void +kokkos_sum_over_steps< + false, // printout, + false, // complex_miller, + false, // compute_curvatures, + REFINE_FCELL, // refine_flag, + false, // use_diffuse, + false, // save_wavelenimage + false, // Fhkl_gradient_mode, + false, // Fhkl_errors_mode, + false, // using_trusted_mask, + true, // Fhkl_channels_empty, + false> // Fhkl_have_scale_factors + ( + int Npix_to_model, + vector_uint_t panels_fasts_slows, + vector_cudareal_t floatimage, + vector_cudareal_t wavelenimage, + vector_cudareal_t d_Umat_images, + vector_cudareal_t d2_Umat_images, + vector_cudareal_t d_Bmat_images, + vector_cudareal_t d2_Bmat_images, + vector_cudareal_t d_Ncells_images, + vector_cudareal_t d2_Ncells_images, + vector_cudareal_t d_fcell_images, + vector_cudareal_t d2_fcell_images, + vector_cudareal_t d_eta_images, + vector_cudareal_t d2_eta_images, + vector_cudareal_t d_lambda_images, + vector_cudareal_t d2_lambda_images, + vector_cudareal_t d_panel_rot_images, + vector_cudareal_t d2_panel_rot_images, + vector_cudareal_t d_panel_orig_images, + vector_cudareal_t d2_panel_orig_images, + vector_cudareal_t d_fp_fdp_images, + vector_manager_t manager_dI, + vector_manager_t manager_dI2, + const int Nsteps, + int printout_fpixel, + int printout_spixel, + /*bool printout,*/ + CUDAREAL default_F, + int oversample, + bool oversample_omega, + CUDAREAL subpixel_size, + CUDAREAL pixel_size, + CUDAREAL detector_thickstep, + CUDAREAL detector_thick, + const vector_cudareal_t close_distances, + CUDAREAL detector_attnlen, + int detector_thicksteps, + int sources, + int phisteps, + int mosaic_domains, + bool use_lambda_coefficients, + CUDAREAL lambda0, + CUDAREAL lambda1, + KOKKOS_MAT3 eig_U, + KOKKOS_MAT3 eig_O, + KOKKOS_MAT3 eig_B, + KOKKOS_MAT3 RXYZ, + vector_vec3_t dF_vecs, + vector_vec3_t dS_vecs, + const vector_mat3_t UMATS_RXYZ, + vector_mat3_t UMATS_RXYZ_prime, + vector_mat3_t UMATS_RXYZ_dbl_prime, + vector_mat3_t RotMats, + vector_mat3_t dRotMats, + vector_mat3_t d2RotMats, + vector_mat3_t UMATS, + vector_mat3_t dB_mats, + vector_mat3_t dB2_mats, + vector_mat3_t Amatrices, + const vector_cudareal_t source_X, + const vector_cudareal_t source_Y, + const vector_cudareal_t source_Z, + const vector_cudareal_t source_lambda, + const vector_cudareal_t source_I, + CUDAREAL kahn_factor, + CUDAREAL Na, + CUDAREAL Nb, + CUDAREAL Nc, + CUDAREAL Nd, + CUDAREAL Ne, + CUDAREAL Nf, + CUDAREAL phi0, + CUDAREAL phistep, + KOKKOS_VEC3 spindle_vec, + KOKKOS_VEC3 polarization_axis, + int h_range, + int k_range, + int l_range, + int h_max, + int h_min, + int k_max, + int k_min, + int l_max, + int l_min, + CUDAREAL dmin, + CUDAREAL fudge, + /*bool complex_miller,*/ + int verbose, + bool only_save_omega_kahn, + bool isotropic_ncells, + /*bool compute_curvatures,*/ + const vector_cudareal_t FhklLinear, + const vector_cudareal_t Fhkl2Linear, + /*const uint32_t refine_flag,*/ + // vector_bool_t refine_Bmat, + // vector_bool_t refine_Ncells, + // bool refine_Ncells_def, + // vector_bool_t refine_panel_origin, + // vector_bool_t refine_panel_rot, + // bool refine_fcell, + // vector_bool_t refine_lambda, + // bool refine_eta, + // vector_bool_t refine_Umat, + const vector_cudareal_t fdet_vectors, + const vector_cudareal_t sdet_vectors, + const vector_cudareal_t odet_vectors, + const vector_cudareal_t pix0_vectors, + bool nopolar, + bool point_pixel, + CUDAREAL fluence, + CUDAREAL r_e_sqr, + CUDAREAL spot_scale, + int Npanels, + bool aniso_eta, + bool no_Nabc_scale, + const vector_cudareal_t fpfdp, + const vector_cudareal_t fpfdp_derivs, + const vector_cudareal_t atom_data, + int num_atoms, + // bool refine_fp_fdp, + const vector_int_t nominal_hkl, + bool use_nominal_hkl, + KOKKOS_MAT3 anisoU, + KOKKOS_MAT3 anisoG, + KOKKOS_MAT3 rotate_principal_axes, + /*bool use_diffuse,*/ + vector_cudareal_t d_diffuse_gamma_images, + vector_cudareal_t d_diffuse_sigma_images, + // bool refine_diffuse, + bool gamma_miller_units, + // bool refine_Icell, + /*bool save_wavelenimage,*/ + int laue_group_num, + int stencil_size, + /*bool Fhkl_gradient_mode,*/ + /*bool Fhkl_errors_mode,*/ + /*bool using_trusted_mask,*/ + /*bool Fhkl_channels_empty,*/ + /*bool Fhkl_have_scale_factors,*/ + int Num_ASU, + const vector_cudareal_t data_residual, + const vector_cudareal_t data_variance, + const vector_int_t data_freq, + const vector_bool_t data_trusted, + const vector_int_t FhklLinear_ASUid, + const vector_int_t Fhkl_channels, + const vector_cudareal_t Fhkl_scale, + vector_cudareal_t Fhkl_scale_deriv); diff --git a/simtbx/diffBragg/src/diffBragg_kokkos_kernel.h b/simtbx/diffBragg/src/diffBragg_kokkos_kernel.h index 3c4a117693..3586183087 100644 --- a/simtbx/diffBragg/src/diffBragg_kokkos_kernel.h +++ b/simtbx/diffBragg/src/diffBragg_kokkos_kernel.h @@ -26,6 +26,8 @@ void kokkos_sum_over_steps( vector_cudareal_t d_panel_orig_images, vector_cudareal_t d2_panel_orig_images, vector_cudareal_t d_fp_fdp_images, + vector_manager_t manager_dI, + vector_manager_t manager_dI2, const int Nsteps, int printout_fpixel, int printout_spixel, @@ -96,15 +98,16 @@ void kokkos_sum_over_steps( bool compute_curvatures, const vector_cudareal_t FhklLinear, const vector_cudareal_t Fhkl2Linear, - vector_bool_t refine_Bmat, - vector_bool_t refine_Ncells, - bool refine_Ncells_def, - vector_bool_t refine_panel_origin, - vector_bool_t refine_panel_rot, - bool refine_fcell, - vector_bool_t refine_lambda, - bool refine_eta, - vector_bool_t refine_Umat, + const uint32_t refine_flag, + // vector_bool_t refine_Bmat, + // vector_bool_t refine_Ncells, + // bool refine_Ncells_def, + // vector_bool_t refine_panel_origin, + // vector_bool_t refine_panel_rot, + // bool refine_fcell, + // vector_bool_t refine_lambda, + // bool refine_eta, + // vector_bool_t refine_Umat, const vector_cudareal_t fdet_vectors, const vector_cudareal_t sdet_vectors, const vector_cudareal_t odet_vectors, @@ -121,7 +124,7 @@ void kokkos_sum_over_steps( const vector_cudareal_t fpfdp_derivs, const vector_cudareal_t atom_data, int num_atoms, - bool refine_fp_fdp, + // bool refine_fp_fdp, const vector_int_t nominal_hkl, bool use_nominal_hkl, KOKKOS_MAT3 anisoU, @@ -130,9 +133,9 @@ void kokkos_sum_over_steps( bool use_diffuse, vector_cudareal_t d_diffuse_gamma_images, vector_cudareal_t d_diffuse_sigma_images, - bool refine_diffuse, + // bool refine_diffuse, bool gamma_miller_units, - bool refine_Icell, + // bool refine_Icell, bool save_wavelenimage, int laue_group_num, int stencil_size, bool Fhkl_gradient_mode, @@ -146,10 +149,170 @@ void kokkos_sum_over_steps( const vector_int_t data_freq, const vector_bool_t data_trusted, const vector_int_t FhklLinear_ASUid, - const vector_cudareal_t Fhkl_channels, + const vector_int_t Fhkl_channels, const vector_cudareal_t Fhkl_scale, vector_cudareal_t Fhkl_scale_deriv - ); - +); +template < + bool printout, + bool complex_miller, + bool compute_curvatures, + uint32_t refine_fcell, + bool use_diffuse, + bool save_wavelenimage, + bool Fhkl_gradient_mode, + bool Fhkl_errors_mode, + bool using_trusted_mask, + bool Fhkl_channels_empty, + bool Fhkl_have_scale_factors> +void kokkos_sum_over_steps( + int Npix_to_model, + vector_uint_t panels_fasts_slows, + vector_cudareal_t floatimage, + vector_cudareal_t wavelenimage, + vector_cudareal_t d_Umat_images, + vector_cudareal_t d2_Umat_images, + vector_cudareal_t d_Bmat_images, + vector_cudareal_t d2_Bmat_images, + vector_cudareal_t d_Ncells_images, + vector_cudareal_t d2_Ncells_images, + vector_cudareal_t d_fcell_images, + vector_cudareal_t d2_fcell_images, + vector_cudareal_t d_eta_images, + vector_cudareal_t d2_eta_images, + vector_cudareal_t d_lambda_images, + vector_cudareal_t d2_lambda_images, + vector_cudareal_t d_panel_rot_images, + vector_cudareal_t d2_panel_rot_images, + vector_cudareal_t d_panel_orig_images, + vector_cudareal_t d2_panel_orig_images, + vector_cudareal_t d_fp_fdp_images, + vector_manager_t manager_dI, + vector_manager_t manager_dI2, + const int Nsteps, + int printout_fpixel, + int printout_spixel, + /*bool printout,*/ + CUDAREAL default_F, + int oversample, + bool oversample_omega, + CUDAREAL subpixel_size, + CUDAREAL pixel_size, + CUDAREAL detector_thickstep, + CUDAREAL detector_thick, + const vector_cudareal_t close_distances, + CUDAREAL detector_attnlen, + int detector_thicksteps, + int sources, + int phisteps, + int mosaic_domains, + bool use_lambda_coefficients, + CUDAREAL lambda0, + CUDAREAL lambda1, + KOKKOS_MAT3 eig_U, + KOKKOS_MAT3 eig_O, + KOKKOS_MAT3 eig_B, + KOKKOS_MAT3 RXYZ, + vector_vec3_t dF_vecs, + vector_vec3_t dS_vecs, + const vector_mat3_t UMATS_RXYZ, + vector_mat3_t UMATS_RXYZ_prime, + vector_mat3_t UMATS_RXYZ_dbl_prime, + vector_mat3_t RotMats, + vector_mat3_t dRotMats, + vector_mat3_t d2RotMats, + vector_mat3_t UMATS, + vector_mat3_t dB_mats, + vector_mat3_t dB2_mats, + vector_mat3_t Amatrices, + const vector_cudareal_t source_X, + const vector_cudareal_t source_Y, + const vector_cudareal_t source_Z, + const vector_cudareal_t source_lambda, + const vector_cudareal_t source_I, + CUDAREAL kahn_factor, + CUDAREAL Na, + CUDAREAL Nb, + CUDAREAL Nc, + CUDAREAL Nd, + CUDAREAL Ne, + CUDAREAL Nf, + CUDAREAL phi0, + CUDAREAL phistep, + KOKKOS_VEC3 spindle_vec, + KOKKOS_VEC3 polarization_axis, + int h_range, + int k_range, + int l_range, + int h_max, + int h_min, + int k_max, + int k_min, + int l_max, + int l_min, + CUDAREAL dmin, + CUDAREAL fudge, + /*bool complex_miller,*/ + int verbose, + bool only_save_omega_kahn, + bool isotropic_ncells, + /*bool compute_curvatures,*/ + const vector_cudareal_t FhklLinear, + const vector_cudareal_t Fhkl2Linear, + /*const uint32_t refine_flag,*/ + // vector_bool_t refine_Bmat, + // vector_bool_t refine_Ncells, + // bool refine_Ncells_def, + // vector_bool_t refine_panel_origin, + // vector_bool_t refine_panel_rot, + // bool refine_fcell, + // vector_bool_t refine_lambda, + // bool refine_eta, + // vector_bool_t refine_Umat, + const vector_cudareal_t fdet_vectors, + const vector_cudareal_t sdet_vectors, + const vector_cudareal_t odet_vectors, + const vector_cudareal_t pix0_vectors, + bool nopolar, + bool point_pixel, + CUDAREAL fluence, + CUDAREAL r_e_sqr, + CUDAREAL spot_scale, + int Npanels, + bool aniso_eta, + bool no_Nabc_scale, + const vector_cudareal_t fpfdp, + const vector_cudareal_t fpfdp_derivs, + const vector_cudareal_t atom_data, + int num_atoms, + // bool refine_fp_fdp, + const vector_int_t nominal_hkl, + bool use_nominal_hkl, + KOKKOS_MAT3 anisoU, + KOKKOS_MAT3 anisoG, + KOKKOS_MAT3 rotate_principal_axes, + /*bool use_diffuse,*/ + vector_cudareal_t d_diffuse_gamma_images, + vector_cudareal_t d_diffuse_sigma_images, + // bool refine_diffuse, + bool gamma_miller_units, + // bool refine_Icell, + /*bool save_wavelenimage,*/ + int laue_group_num, int stencil_size, + /*bool Fhkl_gradient_mode,*/ + /*bool Fhkl_errors_mode,*/ + /*bool using_trusted_mask,*/ + /*bool Fhkl_channels_empty,*/ + /*bool Fhkl_have_scale_factors,*/ + int Num_ASU, + const vector_cudareal_t data_residual, + const vector_cudareal_t data_variance, + const vector_int_t data_freq, + const vector_bool_t data_trusted, + const vector_int_t FhklLinear_ASUid, + const vector_int_t Fhkl_channels, + const vector_cudareal_t Fhkl_scale, + vector_cudareal_t Fhkl_scale_deriv +); #endif diff --git a/simtbx/diffBragg/src/diffBragg_refine_flag.h b/simtbx/diffBragg/src/diffBragg_refine_flag.h new file mode 100644 index 0000000000..64b250ebf5 --- /dev/null +++ b/simtbx/diffBragg/src/diffBragg_refine_flag.h @@ -0,0 +1,67 @@ +#ifndef SIMTBX_DIFFBRAGG_REFINE_FLAG +#define SIMTBX_DIFFBRAGG_REFINE_FLAG +/* +enum refine_id { + ROTX_ID = (1u << 0), + ROTY_ID = (1u << 1), + ROTZ_ID = (1u << 2), + UCELL_A_ID = (1u << 3), + UCELL_B_ID = (1u << 4), + UCELL_C_ID = (1u << 5), + UCELL_ALPHA_ID = (1u << 6), + UCELL_BETA_ID = (1u << 7), + UCELL_GAMMA_ID = (1u << 8), + NCELLS_ID = (1u << 9), + PANELZ_ID = (1u << 10), + FCELL_ID = (1u << 11), + LAMBDA_OFFSET_ID = (1u << 12), + LAMBDA_SCALE_ID = (1u << 13), + PANEL_ROTO_ID = (1u << 14), + PANELX_ID = (1u << 15), + PANELY_ID = (1u << 16), + PANEL_ROTF_ID = (1u << 17), + PANEL_ROTS_ID = (1u << 18), + ETA_ID = (1u << 19), + NCELLS_OFFDIAG_ID = (1u << 21), + F_PRIME_F_DPRIME_ID = (1u << 22), + DIFFUSE_ID = (1u << 23), +}; +*/ + +enum refine_flag : uint32_t { + REFINE_DIFFUSE = (1u << 0), + REFINE_FP_FDP = (1u << 1), + REFINE_UMAT1 = (1u << 2), + REFINE_UMAT2 = (1u << 3), + REFINE_UMAT3 = (1u << 4), + REFINE_BMAT1 = (1u << 5), + REFINE_BMAT2 = (1u << 6), + REFINE_BMAT3 = (1u << 7), + REFINE_BMAT4 = (1u << 8), + REFINE_BMAT5 = (1u << 9), + REFINE_BMAT6 = (1u << 10), + REFINE_NCELLS1 = (1u << 11), + REFINE_NCELLS2 = (1u << 12), + REFINE_NCELLS3 = (1u << 13), + REFINE_NCELLS_DEF = (1u << 14), + REFINE_PANEL_ORIGIN1 = (1u << 15), + REFINE_PANEL_ORIGIN2 = (1u << 16), + REFINE_PANEL_ORIGIN3 = (1u << 17), + REFINE_PANEL_ROT1 = (1u << 18), + REFINE_PANEL_ROT2 = (1u << 19), + REFINE_PANEL_ROT3 = (1u << 20), + REFINE_FCELL = (1u << 21), + REFINE_ETA = (1u << 22), + REFINE_LAMBDA1 = (1u << 23), + REFINE_LAMBDA2 = (1u << 24), + REFINE_ICELL = (1u << 25) +}; + +constexpr unsigned int REFINE_BMAT = REFINE_BMAT1 | REFINE_BMAT2 | REFINE_BMAT3 | REFINE_BMAT4 | REFINE_BMAT5 | REFINE_BMAT6; +constexpr unsigned int REFINE_UMAT = REFINE_UMAT1 | REFINE_UMAT2 | REFINE_UMAT3; +constexpr unsigned int REFINE_NCELLS = REFINE_NCELLS1 | REFINE_NCELLS2 | REFINE_NCELLS3; +constexpr unsigned int REFINE_PANEL_ORIGIN = REFINE_PANEL_ORIGIN1 | REFINE_PANEL_ORIGIN2 | REFINE_PANEL_ORIGIN3; +constexpr unsigned int REFINE_PANEL_ROT = REFINE_PANEL_ROT1 | REFINE_PANEL_ROT2 | REFINE_PANEL_ROT3; +constexpr unsigned int REFINE_LAMBDA = REFINE_LAMBDA1 | REFINE_LAMBDA2; + +#endif diff --git a/simtbx/diffBragg/src/diffuse_util.h b/simtbx/diffBragg/src/diffuse_util.h index 881a4902a9..d556f885d9 100644 --- a/simtbx/diffBragg/src/diffuse_util.h +++ b/simtbx/diffBragg/src/diffuse_util.h @@ -3,21 +3,22 @@ #include -#define CUDA_COMPILE (defined(DIFFBRAGG_HAVE_CUDA) && defined(__CUDACC__)) +#if defined(DIFFBRAGG_HAVE_CUDA) && defined(__CUDACC__) +#define CUDA_COMPILE +#endif #define REAL double -#if CUDA_COMPILE +#ifdef CUDA_COMPILE __device__ __host__ #endif -#if CUDA_COMPILE || not defined(DIFFBRAGG_HAVE_CUDA) + +#if defined(CUDA_COMPILE) || not defined(DIFFBRAGG_HAVE_CUDA) int gen_laue_mats(int laue_group_num, MAT3 *lmats, MAT3 rpa) { - if (laue_group_num < 1 || laue_group_num >14 ){ - printf("Laue group number not in range 1-14; exiting\n"); - exit(1); - } + assert(laue_group_num>0); + assert(laue_group_num<15); - int num_mats; + int num_mats = 0; const double one_over_root2 = 1./sqrt(2.); @@ -561,10 +562,10 @@ int gen_laue_mats(int laue_group_num, MAT3 *lmats, MAT3 rpa) { int gen_laue_mats(int laue_group_num, MAT3 *lmats, MAT3 rpa); #endif -#if CUDA_COMPILE +#ifdef CUDA_COMPILE __device__ __host__ #endif -#if CUDA_COMPILE || not defined(DIFFBRAGG_HAVE_CUDA) +#if defined(CUDA_COMPILE) || not defined(DIFFBRAGG_HAVE_CUDA) void calc_diffuse_at_hkl(VEC3 H_vec, VEC3 H0, VEC3 dHH, VEC3 Hmin, VEC3 Hmax, VEC3 Hrange, MAT3 Ainv, const REAL *FhklLinear, int num_laue_mats, MAT3 *laue_mats, MAT3 anisoG_local, MAT3 anisoU_local, MAT3 *dG_dgam, bool refine_diffuse, REAL *I0, REAL *step_diffuse_param){ REAL four_mpi_sq = 4.*M_PI*M_PI; // loop over laue matrices diff --git a/simtbx/diffBragg/src/diffuse_util_kokkos.h b/simtbx/diffBragg/src/diffuse_util_kokkos.h index 33edd23b94..397db20f73 100644 --- a/simtbx/diffBragg/src/diffuse_util_kokkos.h +++ b/simtbx/diffBragg/src/diffuse_util_kokkos.h @@ -3,14 +3,12 @@ #include -KOKKOS_FUNCTION -int gen_laue_mats(int laue_group_num, KOKKOS_MAT3 *lmats, KOKKOS_MAT3 rpa) { +KOKKOS_INLINE_FUNCTION +int gen_laue_mats(int laue_group_num, vector_mat3_t lmats, KOKKOS_MAT3 rpa) { - if (laue_group_num < 1 || laue_group_num >14 ){ - printf("Laue group number not in range 1-14; exiting\n"); - exit(1); - } - int num_mats; + assert(laue_group_num>0); + assert(laue_group_num<15); + int num_mats = 0; const double one_over_root2 = 1./sqrt(2.); @@ -18,7 +16,7 @@ int gen_laue_mats(int laue_group_num, KOKKOS_MAT3 *lmats, KOKKOS_MAT3 rpa) { // P -1 // x,y,z - lmats[0] << 1, 0, 0, + lmats(0) << 1, 0, 0, 0, 1, 0, 0, 0, 1; @@ -28,12 +26,12 @@ int gen_laue_mats(int laue_group_num, KOKKOS_MAT3 *lmats, KOKKOS_MAT3 rpa) { // P 1 1 2/m // x,y,z - lmats[0] << 1, 0, 0, + lmats(0) << 1, 0, 0, 0, 1, 0, 0, 0, 1; // -x,-y,z - lmats[1] << -1, 0, 0, + lmats(1) << -1, 0, 0, 0,-1, 0, 0, 0, 1; @@ -43,12 +41,12 @@ int gen_laue_mats(int laue_group_num, KOKKOS_MAT3 *lmats, KOKKOS_MAT3 rpa) { // P 1 2/m 1 // x,y,z - lmats[0] << 1, 0, 0, + lmats(0) << 1, 0, 0, 0, 1, 0, 0, 0, 1; // -x,y,-z - lmats[1] << -1, 0, 0, + lmats(1) << -1, 0, 0, 0, 1, 0, 0, 0,-1; @@ -58,12 +56,12 @@ int gen_laue_mats(int laue_group_num, KOKKOS_MAT3 *lmats, KOKKOS_MAT3 rpa) { // P 2/m 1 1 // x,y,z - lmats[0] << 1, 0, 0, + lmats(0) << 1, 0, 0, 0, 1, 0, 0, 0, 1; // x,-y,-z - lmats[1] << 1, 0, 0, + lmats(1) << 1, 0, 0, 0,-1, 0, 0, 0,-1; @@ -73,22 +71,22 @@ int gen_laue_mats(int laue_group_num, KOKKOS_MAT3 *lmats, KOKKOS_MAT3 rpa) { // P m m m // x,y,z - lmats[0] << 1, 0, 0, + lmats(0) << 1, 0, 0, 0, 1, 0, 0, 0, 1; // x,-y,-z - lmats[1] << 1, 0, 0, + lmats(1) << 1, 0, 0, 0,-1, 0, 0, 0,-1; // -x,y,-z - lmats[2] << -1, 0, 0, + lmats(2) << -1, 0, 0, 0, 1, 0, 0, 0,-1; // -x,-y,z - lmats[3] << -1, 0, 0, + lmats(3) << -1, 0, 0, 0,-1, 0, 0, 0, 1; @@ -98,22 +96,22 @@ int gen_laue_mats(int laue_group_num, KOKKOS_MAT3 *lmats, KOKKOS_MAT3 rpa) { // P 4/m // x,y,z - lmats[0] << 1, 0, 0, + lmats(0) << 1, 0, 0, 0, 1, 0, 0, 0, 1; // -y,x,z - lmats[1] << 0,-1, 0, + lmats(1) << 0,-1, 0, 1, 0, 0, 0, 0, 1; // y,-x,z - lmats[2] << 0, 1, 0, + lmats(2) << 0, 1, 0, -1, 0, 0, 0, 0, 1; // -x,-y,z - lmats[3] << -1, 0, 0, + lmats(3) << -1, 0, 0, 0,-1, 0, 0, 0, 1; @@ -123,42 +121,42 @@ int gen_laue_mats(int laue_group_num, KOKKOS_MAT3 *lmats, KOKKOS_MAT3 rpa) { // P 4/m m m // x,y,z - lmats[0] << 1, 0, 0, + lmats(0) << 1, 0, 0, 0, 1, 0, 0, 0, 1; // -y,x,z - lmats[1] << 0,-1, 0, + lmats(1) << 0,-1, 0, 1, 0, 0, 0, 0, 1; // y,-x,z - lmats[2] << 0, 1, 0, + lmats(2) << 0, 1, 0, -1, 0, 0, 0, 0, 1; // x,-y,-z - lmats[3] << 1, 0, 0, + lmats(3) << 1, 0, 0, 0,-1, 0, 0, 0,-1; // -x,y,-z - lmats[4] << -1, 0, 0, + lmats(4) << -1, 0, 0, 0, 1, 0, 0, 0,-1; // -x,-y,z - lmats[5] << -1, 0, 0, + lmats(5) << -1, 0, 0, 0,-1, 0, 0, 0, 1; // y,x,-z - lmats[6] << 0, 1, 0, + lmats(6) << 0, 1, 0, 1, 0, 0, 0, 0,-1; // -y,-x,-z - lmats[7] << 0,-1, 0, + lmats(7) << 0,-1, 0, -1, 0, 0, 0, 0,-1; @@ -168,17 +166,17 @@ int gen_laue_mats(int laue_group_num, KOKKOS_MAT3 *lmats, KOKKOS_MAT3 rpa) { // P -3 // x,y,z - lmats[0] << 1, 0, 0, + lmats(0) << 1, 0, 0, 0, 1, 0, 0, 0, 1; // -y,x-y,z - lmats[1] << 0,-1, 0, + lmats(1) << 0,-1, 0, one_over_root2,-one_over_root2, 0, 0, 0, 1; // -x+y,-x,z - lmats[2] << -one_over_root2, one_over_root2, 0, + lmats(2) << -one_over_root2, one_over_root2, 0, -1, 0, 0, 0, 0, 1; @@ -188,32 +186,32 @@ int gen_laue_mats(int laue_group_num, KOKKOS_MAT3 *lmats, KOKKOS_MAT3 rpa) { // P -3 m 1 // x,y,z - lmats[0] << 1, 0, 0, + lmats(0) << 1, 0, 0, 0, 1, 0, 0, 0, 1; // -y,x-y,z - lmats[1] << 0,-1, 0, + lmats(1) << 0,-1, 0, one_over_root2,-one_over_root2, 0, 0, 0, 1; // -x+y,-x,z - lmats[2] << -one_over_root2, one_over_root2, 0, + lmats(2) << -one_over_root2, one_over_root2, 0, -1, 0, 0, 0, 0, 1; // x-y,-y,-z - lmats[3] << one_over_root2,-one_over_root2, 0, + lmats(3) << one_over_root2,-one_over_root2, 0, 0,-1, 0, 0, 0,-1; // -x,-x+y,-z - lmats[4] << -1, 0, 0, + lmats(4) << -1, 0, 0, -one_over_root2, one_over_root2, 0, 0, 0,-1; // y,x,-z - lmats[5] << 0, 1, 0, + lmats(5) << 0, 1, 0, 1, 0, 0, 0, 0,-1; @@ -223,32 +221,32 @@ int gen_laue_mats(int laue_group_num, KOKKOS_MAT3 *lmats, KOKKOS_MAT3 rpa) { // P -3 1 m // x,y,z - lmats[0] << 1, 0, 0, + lmats(0) << 1, 0, 0, 0, 1, 0, 0, 0, 1; // -y,x-y,z - lmats[1] << 0,-1, 0, + lmats(1) << 0,-1, 0, one_over_root2,-one_over_root2, 0, 0, 0, 1; // -x+y,-x,z - lmats[2] << -one_over_root2, one_over_root2, 0, + lmats(2) << -one_over_root2, one_over_root2, 0, -1, 0, 0, 0, 0, 1; // -y,-x,-z - lmats[3] << 0,-1, 0, + lmats(3) << 0,-1, 0, -1, 0, 0, 0, 0,-1; // -x+y,y,-z - lmats[4] << -one_over_root2, one_over_root2, 0, + lmats(4) << -one_over_root2, one_over_root2, 0, 0, 1, 0, 0, 0,-1; // x,x-y,-z - lmats[5] << 1, 0, 0, + lmats(5) << 1, 0, 0, one_over_root2,-one_over_root2, 0, 0, 0,-1; @@ -258,32 +256,32 @@ int gen_laue_mats(int laue_group_num, KOKKOS_MAT3 *lmats, KOKKOS_MAT3 rpa) { // P 6/m // x,y,z - lmats[0] << 1, 0, 0, + lmats(0) << 1, 0, 0, 0, 1, 0, 0, 0, 1; // x-y,x,z - lmats[1] << one_over_root2,-one_over_root2, 0, + lmats(1) << one_over_root2,-one_over_root2, 0, 1, 0, 0, 0, 0, 1; // y,-x+y,z - lmats[2] << 0, 1, 0, + lmats(2) << 0, 1, 0, -one_over_root2, one_over_root2, 0, 0, 0, 1; // -y,x-y,z - lmats[3] << 0,-1, 0, + lmats(3) << 0,-1, 0, one_over_root2,-one_over_root2, 0, 0, 0, 1; // -x+y,-x,z - lmats[4] << -one_over_root2, one_over_root2, 0, + lmats(4) << -one_over_root2, one_over_root2, 0, -1, 0, 0, 0, 0, 1; // -x,-y,z - lmats[5] << -1, 0, 0, + lmats(5) << -1, 0, 0, 0,-1, 0, 0, 0, 1; @@ -293,62 +291,62 @@ int gen_laue_mats(int laue_group_num, KOKKOS_MAT3 *lmats, KOKKOS_MAT3 rpa) { // P 6/m m m // x,y,z - lmats[0] << 1, 0, 0, + lmats(0) << 1, 0, 0, 0, 1, 0, 0, 0, 1; // x-y,x,z - lmats[1] << one_over_root2,-one_over_root2, 0, + lmats(1) << one_over_root2,-one_over_root2, 0, 1, 0, 0, 0, 0, 1; // y,-x+y,z - lmats[2] << 0, 1, 0, + lmats(2) << 0, 1, 0, -one_over_root2, one_over_root2, 0, 0, 0, 1; // -y,x-y,z - lmats[3] << 0,-1, 0, + lmats(3) << 0,-1, 0, one_over_root2,-one_over_root2, 0, 0, 0, 1; // -x+y,-x,z - lmats[4] << -one_over_root2, one_over_root2, 0, + lmats(4) << -one_over_root2, one_over_root2, 0, -1, 0, 0, 0, 0, 1; // x-y,-y,-z - lmats[5] << one_over_root2,-one_over_root2, 0, + lmats(5) << one_over_root2,-one_over_root2, 0, 0,-1, 0, 0, 0,-1; // -x,-x+y,-z - lmats[6] << -1, 0, 0, + lmats(6) << -1, 0, 0, -one_over_root2, one_over_root2, 0, 0, 0,-1; // -x,-y,z - lmats[7] << -1, 0, 0, + lmats(7) << -1, 0, 0, 0,-1, 0, 0, 0, 1; // y,x,-z - lmats[8] << 0, 1, 0, + lmats(8) << 0, 1, 0, 1, 0, 0, 0, 0,-1; // -y,-x,-z - lmats[9] << 0,-1, 0, + lmats(9) << 0,-1, 0, -1, 0, 0, 0, 0,-1; // -x+y,y,-z - lmats[10] << -one_over_root2, one_over_root2, 0, + lmats(10) << -one_over_root2, one_over_root2, 0, 0, 1, 0, 0, 0,-1; // x,x-y,-z - lmats[11] << 1, 0, 0, + lmats(11) << 1, 0, 0, one_over_root2,-one_over_root2, 0, 0, 0,-1; @@ -358,62 +356,62 @@ int gen_laue_mats(int laue_group_num, KOKKOS_MAT3 *lmats, KOKKOS_MAT3 rpa) { // P m -3 // x,y,z - lmats[0] << 1, 0, 0, + lmats(0) << 1, 0, 0, 0, 1, 0, 0, 0, 1; // z,x,y - lmats[1] << 0, 0, 1, + lmats(1) << 0, 0, 1, 1, 0, 0, 0, 1, 0; // y,z,x - lmats[2] << 0, 1, 0, + lmats(2) << 0, 1, 0, 0, 0, 1, 1, 0, 0; // -y,-z,x - lmats[3] << 0,-1, 0, + lmats(3) << 0,-1, 0, 0, 0,-1, 1, 0, 0; // z,-x,-y - lmats[4] << 0, 0, 1, + lmats(4) << 0, 0, 1, -1, 0, 0, 0,-1, 0; // -y,z,-x - lmats[5] << 0,-1, 0, + lmats(5) << 0,-1, 0, 0, 0, 1, -1, 0, 0; // -z,-x,y - lmats[6] << 0, 0,-1, + lmats(6) << 0, 0,-1, -1, 0, 0, 0, 1, 0; // -z,x,-y - lmats[7] << 0, 0,-1, + lmats(7) << 0, 0,-1, 1, 0, 0, 0,-1, 0; // y,-z,-x - lmats[8] << 0, 1, 0, + lmats(8) << 0, 1, 0, 0, 0,-1, -1, 0, 0; // x,-y,-z - lmats[9] << 1, 0, 0, + lmats(9) << 1, 0, 0, 0,-1, 0, 0, 0,-1; // -x,y,-z - lmats[10] << -1, 0, 0, + lmats(10) << -1, 0, 0, 0, 1, 0, 0, 0,-1; // -x,-y,z - lmats[11] << -1, 0, 0, + lmats(11) << -1, 0, 0, 0,-1, 0, 0, 0, 1; @@ -423,122 +421,122 @@ int gen_laue_mats(int laue_group_num, KOKKOS_MAT3 *lmats, KOKKOS_MAT3 rpa) { // P m -3 m // x,y,z - lmats[0] << 1, 0, 0, + lmats(0) << 1, 0, 0, 0, 1, 0, 0, 0, 1; // x,-z,y - lmats[1] << 1, 0, 0, + lmats(1) << 1, 0, 0, 0, 0,-1, 0, 1, 0; // x,z,-y - lmats[2] << 1, 0, 0, + lmats(2) << 1, 0, 0, 0, 0, 1, 0,-1, 0; // z,y,-x - lmats[3] << 0, 0, 1, + lmats(3) << 0, 0, 1, 0, 1, 0, -1, 0, 0; // -z,y,x - lmats[4] << 0, 0,-1, + lmats(4) << 0, 0,-1, 0, 1, 0, 1, 0, 0; // -y,x,z - lmats[5] << 0,-1, 0, + lmats(5) << 0,-1, 0, 1, 0, 0, 0, 0, 1; // y,-x,z - lmats[6] << 0, 1, 0, + lmats(6) << 0, 1, 0, -1, 0, 0, 0, 0, 1; // z,x,y - lmats[7] << 0, 0, 1, + lmats(7) << 0, 0, 1, 1, 0, 0, 0, 1, 0; // y,z,x - lmats[8] << 0, 1, 0, + lmats(8) << 0, 1, 0, 0, 0, 1, 1, 0, 0; // -y,-z,x - lmats[9] << 0,-1, 0, + lmats(9) << 0,-1, 0, 0, 0,-1, 1, 0, 0; // z,-x,-y - lmats[10] << 0, 0, 1, + lmats(10) << 0, 0, 1, -1, 0, 0, 0,-1, 0; // -y,z,-x - lmats[11] << 0,-1, 0, + lmats(11) << 0,-1, 0, 0, 0, 1, -1, 0, 0; // -z,-x,y - lmats[12] << 0, 0,-1, + lmats(12) << 0, 0,-1, -1, 0, 0, 0, 1, 0; // -z,x,-y - lmats[13] << 0, 0,-1, + lmats(13) << 0, 0,-1, 1, 0, 0, 0,-1, 0; // y,-z,-x - lmats[14] << 0, 1, 0, + lmats(14) << 0, 1, 0, 0, 0,-1, -1, 0, 0; // x,-y,-z - lmats[15] << 1, 0, 0, + lmats(15) << 1, 0, 0, 0,-1, 0, 0, 0,-1; // -x,y,-z - lmats[16] << -1, 0, 0, + lmats(16) << -1, 0, 0, 0, 1, 0, 0, 0,-1; // -x,-y,z - lmats[17] << -1, 0, 0, + lmats(17) << -1, 0, 0, 0,-1, 0, 0, 0, 1; // y,x,-z - lmats[18] << 0, 1, 0, + lmats(18) << 0, 1, 0, 1, 0, 0, 0, 0,-1; // -y,-x,-z - lmats[19] << 0,-1, 0, + lmats(19) << 0,-1, 0, -1, 0, 0, 0, 0,-1; // z,-y,x - lmats[20] << 0, 0, 1, + lmats(20) << 0, 0, 1, 0,-1, 0, 1, 0, 0; // -z,-y,-x - lmats[21] << 0, 0,-1, + lmats(21) << 0, 0,-1, 0,-1, 0, -1, 0, 0; // -x,z,y - lmats[22] << -1, 0, 0, + lmats(22) << -1, 0, 0, 0, 0, 1, 0, 1, 0; // -x,-z,-y - lmats[23] << -1, 0, 0, + lmats(23) << -1, 0, 0, 0, 0,-1, 0,-1, 0; @@ -546,87 +544,78 @@ int gen_laue_mats(int laue_group_num, KOKKOS_MAT3 *lmats, KOKKOS_MAT3 rpa) { } for (int i_mat=0; i_mat < num_mats; i_mat ++){ - lmats[i_mat] = lmats[i_mat] * rpa; + lmats(i_mat) = lmats(i_mat) * rpa; } return num_mats; }; KOKKOS_FUNCTION -void calc_diffuse_at_hkl(KOKKOS_VEC3 H_vec, KOKKOS_VEC3 H0, KOKKOS_VEC3 dHH, KOKKOS_VEC3 Hmin, KOKKOS_VEC3 Hmax, KOKKOS_VEC3 Hrange, KOKKOS_MAT3 Ainv, const vector_cudareal_t FhklLinear, int num_laue_mats, const KOKKOS_MAT3 *laue_mats, KOKKOS_MAT3 anisoG_local, KOKKOS_MAT3 anisoU_local, const KOKKOS_MAT3 *dG_dgam, bool refine_diffuse, CUDAREAL *I0, CUDAREAL *step_diffuse_param){ - CUDAREAL four_mpi_sq = 4.*M_PI*M_PI; - // loop over laue matrices - int num_stencil_points = (2*dHH[0] + 1) * (2*dHH[1] + 1) * (2*dHH[2] + 1); - bool h_bounded= (H0[0]+dHH[0]<=Hmax[0]) && (H0[0]-dHH[0]>=Hmin[0]) ; - bool k_bounded= (H0[1]+dHH[1]<=Hmax[1]) && (H0[1]-dHH[1]>=Hmin[1]) ; - bool l_bounded= (H0[2]+dHH[2]<=Hmax[2]) && (H0[2]-dHH[2]>=Hmin[2]) ; - if (h_bounded && k_bounded && l_bounded) { - int Fhkl_linear_index_0 = (H0[0]-Hmin[0]) * Hrange[1] * Hrange[2] - + (H0[1]-Hmin[1]) * Hrange[2] + (H0[2]-Hmin[2]); - CUDAREAL _F_cell_0 = FhklLinear(Fhkl_linear_index_0); - KOKKOS_MAT3 Ginv = anisoG_local.inverse(); - CUDAREAL anisoG_determ = anisoG_local.determinant(); - for (int hh=-dHH[0]; hh <= dHH[0]; hh++){ - for (int kk=-dHH[1]; kk <= dHH[1]; kk++){ - for (int ll=-dHH[2]; ll <= dHH[2]; ll++){ - CUDAREAL ID_this = 0; - CUDAREAL step_diffuse_param_this[6] = {0,0,0,0,0,0}; - int Fhkl_linear_index_this = (H0[0]+hh-Hmin[0]) * Hrange[1] * Hrange[2] - + (H0[1]+kk-Hmin[1]) * Hrange[2] + (H0[2]+ll-Hmin[2]); - CUDAREAL _F_cell_this = FhklLinear(Fhkl_linear_index_this); - CUDAREAL _this_diffuse_scale; - if (_F_cell_0 != 0.0) - _this_diffuse_scale = _F_cell_this/_F_cell_0; - else - _this_diffuse_scale = 1.0; - - _this_diffuse_scale *= _this_diffuse_scale/(CUDAREAL)num_laue_mats/ - (CUDAREAL)num_stencil_points; - // Use (a-b, a+b, c) as the principal axes of the diffuse model - // TODO: Add an option to select (a, b, c) as the principal axes - - for ( int iL = 0; iL < num_laue_mats; iL++ ){ - KOKKOS_VEC3 Q0 =Ainv*laue_mats[iL]*H0; - CUDAREAL exparg = four_mpi_sq*Q0.dot(anisoU_local*Q0); - CUDAREAL dwf = exp(-exparg); - KOKKOS_VEC3 H0_offset(H0[0]+hh, H0[1]+kk, H0[2]+ll); - KOKKOS_VEC3 delta_H_offset = H_vec - H0_offset; - KOKKOS_VEC3 delta_Q = Ainv*laue_mats[iL]*delta_H_offset; - KOKKOS_VEC3 anisoG_q = anisoG_local*delta_Q; - - CUDAREAL V_dot_V = anisoG_q.dot(anisoG_q); - CUDAREAL gamma_portion_denom = (1.+ V_dot_V* four_mpi_sq); - gamma_portion_denom *= gamma_portion_denom; - CUDAREAL gamma_portion = 8.*M_PI*anisoG_determ / - gamma_portion_denom; - CUDAREAL this_I_latt_diffuse = dwf*exparg*gamma_portion; - - ID_this += this_I_latt_diffuse; - if (refine_diffuse){ // add the contributions to diffuse scattering gradients here - for (int i_gam=0; i_gam<3; i_gam++){ - KOKKOS_VEC3 dV = dG_dgam[i_gam]*delta_Q; - CUDAREAL V_dot_dV = anisoG_q.dot(dV); - CUDAREAL deriv = (Ginv*dG_dgam[i_gam]).trace() - 4.*four_mpi_sq*V_dot_dV/(1+four_mpi_sq*V_dot_V); - step_diffuse_param_this[i_gam] += gamma_portion*deriv*dwf*exparg; - } - KOKKOS_MAT3 dU_dsigma; - // dU_dsigma << 0,0,0,0,0,0,0,0,0; - for (int i_sig = 0;i_sig<3; i_sig++){ - dU_dsigma(i_sig, i_sig) = 2.*sqrt(anisoU_local(i_sig,i_sig)); - CUDAREAL dexparg = four_mpi_sq*Q0.dot(dU_dsigma*Q0); - dU_dsigma(i_sig, i_sig) = 0.; - step_diffuse_param_this[i_sig+3] += gamma_portion*dwf*dexparg*(1. - exparg); - } - } - } // end loop over iL (laue group mats) - // Update the lattice interference term here to include diffuse scattering (F_latt squared) - *I0 += ID_this * _this_diffuse_scale; - - for (int idp=0; idp < 6; idp++) - step_diffuse_param[idp] += step_diffuse_param_this[idp]*_this_diffuse_scale; - } // end ll loop - } // end kk loop - } // end hh loop - } // end if bounded +void calc_diffuse_at_hkl(KOKKOS_VEC3 H_vec, KOKKOS_VEC3 H0, KOKKOS_VEC3 dHH, int h_min, int k_min, int l_min, int h_max, int k_max, int l_max, int h_range, int k_range, int l_range, KOKKOS_MAT3 Ainv, const vector_cudareal_t FhklLinear, int num_laue_mats, const vector_mat3_t laue_mats, KOKKOS_MAT3 anisoG_local, vector_cudareal_t dG_trace, CUDAREAL anisoG_determ, KOKKOS_MAT3 anisoU_local, const vector_vec3_t dG_dgam, bool refine_diffuse, CUDAREAL *I0, CUDAREAL *step_diffuse_param){ + constexpr CUDAREAL four_mpi_sq = 4.*M_PI*M_PI; + // loop over laue matrices + int num_stencil_points = (2*dHH[0] + 1) * (2*dHH[1] + 1) * (2*dHH[2] + 1); + bool h_bounded= (H0[0]+dHH[0]<=h_max) && (H0[0]-dHH[0]>=h_min) ; + bool k_bounded= (H0[1]+dHH[1]<=k_max) && (H0[1]-dHH[1]>=k_min) ; + bool l_bounded= (H0[2]+dHH[2]<=l_max) && (H0[2]-dHH[2]>=l_min) ; + if (h_bounded && k_bounded && l_bounded) { + int Fhkl_linear_index_0 = (H0[0]-h_min) * k_range * l_range + (H0[1]-k_min) * l_range + (H0[2]-l_min); + const CUDAREAL _F_cell_0 = FhklLinear(Fhkl_linear_index_0); + for (int hh=-dHH[0]; hh <= dHH[0]; hh++){ + for (int kk=-dHH[1]; kk <= dHH[1]; kk++){ + for (int ll=-dHH[2]; ll <= dHH[2]; ll++){ + CUDAREAL ID_this = 0; + CUDAREAL step_diffuse_param_this[6] = {0,0,0,0,0,0}; + const int Fhkl_linear_index_this = hh * k_range * l_range + kk * l_range + ll + Fhkl_linear_index_0; + const CUDAREAL _F_cell_this = FhklLinear(Fhkl_linear_index_this); + CUDAREAL _this_diffuse_scale; + if (_F_cell_0 != 0.0) + _this_diffuse_scale = _F_cell_this/_F_cell_0; + else + _this_diffuse_scale = 1.0; + + _this_diffuse_scale *= _this_diffuse_scale/(CUDAREAL)num_laue_mats/(CUDAREAL)num_stencil_points; + + const KOKKOS_VEC3 H0_offset(H0[0]+hh, H0[1]+kk, H0[2]+ll); + const KOKKOS_VEC3 delta_H_offset = H_vec - H0_offset; + + for ( int iL = 0; iL < num_laue_mats; iL++ ){ + const KOKKOS_VEC3 Q0 = laue_mats(iL)*H0; + const CUDAREAL exparg = four_mpi_sq*Q0.dot(anisoU_local*Q0); + const CUDAREAL dwf = exp(-exparg); + const KOKKOS_VEC3 delta_Q = laue_mats(iL)*delta_H_offset; + const KOKKOS_VEC3 anisoG_q = anisoG_local*delta_Q; + + const CUDAREAL V_dot_V = anisoG_q.length_sqr(); + const CUDAREAL gamma_portion_denom = 1 / (1.+ V_dot_V* four_mpi_sq); + const CUDAREAL gamma_portion = 8.*M_PI*anisoG_determ * gamma_portion_denom * gamma_portion_denom; + const CUDAREAL this_I_latt_diffuse = dwf*exparg*gamma_portion; + + ID_this += this_I_latt_diffuse; + if (refine_diffuse){ // add the contributions to diffuse scattering gradients here + for (int i_gam=0; i_gam<3; i_gam++){ + const CUDAREAL dV = dG_dgam(i_gam).dot(delta_Q); + const CUDAREAL V_dot_dV = anisoG_q[i_gam] * dV; + const CUDAREAL deriv = dG_trace(i_gam) - 4.*four_mpi_sq*V_dot_dV*gamma_portion_denom; + step_diffuse_param_this[i_gam] += gamma_portion*deriv*dwf*exparg; + } + for (int i_sig = 0;i_sig<3; i_sig++){ + const CUDAREAL dexparg = 2 * four_mpi_sq * sqrt(anisoU_local(i_sig,i_sig)) * Q0[i_sig] * Q0[i_sig]; + step_diffuse_param_this[i_sig+3] += gamma_portion*dwf*dexparg*(1. - exparg); + } + } + } // end loop over iL (laue group mats) + // Update the lattice interference term here to include diffuse scattering (F_latt squared) + *I0 += ID_this * _this_diffuse_scale; + + if (refine_diffuse) { + for (int idp=0; idp < 6; idp++) { + step_diffuse_param[idp] += step_diffuse_param_this[idp]*_this_diffuse_scale; + } + } + } // end ll loop + } // end kk loop + } // end hh loop + } // end if bounded } #endif diff --git a/simtbx/diffBragg/src/util.h b/simtbx/diffBragg/src/util.h index 3cf9360e55..ec197c1dc9 100644 --- a/simtbx/diffBragg/src/util.h +++ b/simtbx/diffBragg/src/util.h @@ -8,6 +8,7 @@ #include #include #include +#include #ifndef CUDAREAL #define CUDAREAL double @@ -19,14 +20,35 @@ typedef Eigen::Matrix MAT3; typedef std::vector > eigMat3_vec; typedef std::vector > eigVec3_vec; +inline void easy_time(double& timer, struct timeval& t, bool recording){ + double before_sec = t.tv_sec; + double before_usec = t.tv_usec; + gettimeofday(&t, 0); + double time = (1000000.0 * (t.tv_sec - before_sec) + t.tv_usec - before_usec) / 1000.0; + if (recording) + timer += time; +} + struct timer_variables{ - CUDAREAL add_spots_pre=0; // times the initializations for add spots kernel - CUDAREAL add_spots_post=0; // times the copies that occur after add spots kernel - CUDAREAL add_spots_kernel_wrapper=0; // times the add spots kernel overall, either CPU or GPU - CUDAREAL cuda_alloc=0; // times the allocation of the device - CUDAREAL cuda_copy_to_dev=0; // times the copying from host to device - CUDAREAL cuda_copy_from_dev=0; // times the copying back from device to host - CUDAREAL cuda_kernel=0; // times the GPU kernel + double add_spots_pre=0; // times the initializations for add spots kernel + double add_spots_post=0; // times the copies that occur after add spots kernel + double add_spots_kernel_wrapper=0; // times the add spots kernel overall, either CPU or GPU + double cuda_alloc=0; // times the allocation of the device + double cuda_copy_to_dev=0; // times the copying from host to device + double cuda_copy_from_dev=0; // times the copying back from device to host + double cuda_kernel=0; // times the GPU kernel + double copy_sources=0; + double copy_Fhkl_scale=0; + double copy_umats=0; + double copy_amats=0; + double copy_bmats=0; + double copy_rotmats=0; + double copy_det=0; + double copy_nomhkl=0; + double copy_flags=0; + double copy_fhkl=0; + double copy_detderiv=0; + double copy_pfs=0; int timings=0; // how many times these variables were incremented bool recording=true; }; @@ -72,16 +94,18 @@ struct cuda_flags{ int Npix_to_allocate; // how much space to allocate for simulating forward model and gradients // these following flags indicate whether to update quantities on the GPU device prior to running the kernel // ( of course they are all set prior to running the kernel for the first time) - bool update_step_positions; // step arrays - bool update_panels_fasts_slows; // pixels to simulatoe (panel id, fast scan, slow scan) - bool update_sources; // beam sources - bool update_umats; // umatrices for mosaic blocks - bool update_dB_mats; // derivative of the orthogonalization matrix (for unit cell derivatives) - bool update_rotmats; // rotation matrices (for Umat derivatives) - bool update_Fhkl; // structure factors - bool update_detector; // detector vectors (origin, slow-axis, fast-axis, orth-axis) - bool update_refine_flags; // refinement flags (in case one is iteratively freezing parameters) - bool update_panel_deriv_vecs; // if one is refining the detector vectors) + bool update_step_positions = false; // step arrays + bool update_panels_fasts_slows = false; // pixels to simulatoe (panel id, fast scan, slow scan) + bool update_sources = false; // beam sources + bool update_umats = false; // umatrices for mosaic blocks + bool update_dB_mats = false; // derivative of the orthogonalization matrix (for unit cell derivatives) + bool update_rotmats = false; // rotation matrices (for Umat derivatives) + bool update_Fhkl = false; // structure factors + bool update_Fhkl_scales = false; // structure factors + bool update_Fhkl_channels = false; // structure factors + bool update_detector = false; // detector vectors (origin, slow-axis, fast-axis, orth-axis) + bool update_refine_flags = false; // refinement flags (in case one is iteratively freezing parameters) + bool update_panel_deriv_vecs = false; // if one is refining the detector vectors) }; struct flags{ @@ -91,30 +115,30 @@ struct flags{ bool using_trusted_mask=false; bool Fhkl_gradient_mode=false; bool wavelength_img=false; - bool track_Fhkl; // for CPU kernel only, track the HKLS evaluated in the inner most loop - bool printout; // whether to printout debug info for a pixel - bool nopolar; // disable polarization effects - bool point_pixel; // approximate solid angle effects - bool only_save_omega_kahn; // only save the polarization and solid angle corrections (deprecated) - bool compute_curvatures; // whether to compute the curvatures in addition to gradients - bool isotropic_ncells; // one mosaic domain parameter - bool complex_miller; // is the miller array complex (such thet Fhkl_linear and Fhkl2_linear are both defined) - bool no_Nabc_scale; // no Nabc prefactor - bool refine_diffuse; // flag for computing diffuse gradients + bool track_Fhkl = false; // for CPU kernel only, track the HKLS evaluated in the inner most loop + bool printout = false; // whether to printout debug info for a pixel + bool nopolar = false; // disable polarization effects + bool point_pixel = false; // approximate solid angle effects + bool only_save_omega_kahn = false; // only save the polarization and solid angle corrections (deprecated) + bool compute_curvatures = false; // whether to compute the curvatures in addition to gradients + bool isotropic_ncells = false; // one mosaic domain parameter + bool complex_miller = false; // is the miller array complex (such thet Fhkl_linear and Fhkl2_linear are both defined) + bool no_Nabc_scale = false; // no Nabc prefactor + bool refine_diffuse = false; // flag for computing diffuse gradients std::vector refine_Bmat; // Bmatrix std::vector refine_Ncells; // mosaic domain size - bool refine_Ncells_def; // mosaic domain size off diag + bool refine_Ncells_def = false; // mosaic domain size off diag std::vector refine_panel_origin; // panel shift std::vector refine_panel_rot; // detector panel rotation - bool refine_fcell; // structure factor + bool refine_fcell = false; // structure factor std::vector refine_lambda; // spectrum affine correction - bool refine_eta; // mosaic spread + bool refine_eta = false; // mosaic spread std::vector refine_Umat; // missetting angle umatrix - bool refine_fp_fdp; // fprime and fbl prime - bool use_lambda_coefficients; // affine correction lam0 , lam1 - bool oversample_omega; // omega is computed separately for each sub-pixel - int printout_fpixel, printout_spixel; // debug printout pixel (fast scan, slow scan) // TODO add panel id - int verbose; // nanoBragg verbosity flag + bool refine_fp_fdp = false; // fprime and fbl prime + bool use_lambda_coefficients = false; // affine correction lam0 , lam1 + bool oversample_omega = false; // omega is computed separately for each sub-pixel + int printout_fpixel = 0, printout_spixel = 0; // debug printout pixel (fast scan, slow scan) // TODO add panel id + int verbose = 0; // nanoBragg verbosity flag bool use_diffuse = false; // model diffuse bool only_diffuse = false; // model diffuse scattering (experimental) bool refine_Icell = false; // option to refine the structure factor intensity directly (F_cell^2) @@ -203,7 +227,10 @@ struct beam{ struct detector{ std::vector > dF_vecs; // derivative of the panel fast direction std::vector > dS_vecs; // derivative of the panel slow direction - CUDAREAL detector_thickstep, detector_thicksteps, detector_thick, detector_attnlen; + CUDAREAL detector_thickstep; + int detector_thicksteps; + CUDAREAL detector_thick; + CUDAREAL detector_attnlen; std::vector close_distances; // offsets to the detector origins (Z direction) int oversample; // determines the pixel subsampling rate CUDAREAL subpixel_size, pixel_size; diff --git a/simtbx/diffBragg/src/util_kokkos.h b/simtbx/diffBragg/src/util_kokkos.h index f74a6d35be..7f0a8da0df 100644 --- a/simtbx/diffBragg/src/util_kokkos.h +++ b/simtbx/diffBragg/src/util_kokkos.h @@ -23,29 +23,37 @@ inline KOKKOS_VEC3 to_vec3(const Eigen::Vector3d& v) { inline KOKKOS_MAT3 to_mat3(const Eigen::Matrix3d& m) { // Eigen matrix is column-major! - return KOKKOS_MAT3(m(0, 0), m(0, 1), m(0, 2), m(1, 0), m(1, 1), m(1, 2), m(2, 0), m(2, 1), m(2, 2)); + return KOKKOS_MAT3(m(0, 0), m(0, 1), m(0, 2), + m(1, 0), m(1, 1), m(1, 2), + m(2, 0), m(2, 1), m(2, 2)); } template -inline void transfer(T& target, U& source, int size=-1) { - const int length = size>=0 ? size : source.size(); +inline void transfer(T& dst, U& src, int size=-1) { + const int length = size>=0 ? size : src.size(); for (int i=0; i -inline void transfer_KOKKOS_VEC3(T& target, U& source) { - for (int i=0; i -inline void transfer_KOKKOS_MAT3(T& target, U& source) { - for (int i=0; i dF_vecs; // derivative of the panel fast direction std::vector dS_vecs; // derivative of the panel slow direction - CUDAREAL detector_thickstep, detector_thicksteps, detector_thick, detector_attnlen; + CUDAREAL detector_thickstep; + int detector_thicksteps; + CUDAREAL detector_thick; + CUDAREAL detector_attnlen; std::vector close_distances; // offsets to the detector origins (Z direction) int oversample; // determines the pixel subsampling rate CUDAREAL subpixel_size, pixel_size; @@ -268,4 +279,34 @@ struct kokkos_detector { }; +struct kokkos_manager { + KOKKOS_VEC3 rot; + double ucell[6] = {0, 0, 0, 0, 0, 0}; + double Ncells[6] = {0, 0, 0, 0, 0, 0}; + KOKKOS_VEC3 pan_orig; + KOKKOS_VEC3 pan_rot; + double fcell = 0; + KOKKOS_VEC3 eta; + double lambda[2] = {0, 0}; + double fp_fdp[2] = {0, 0}; + double diffuse[6] = {0, 0, 0, 0, 0, 0}; + + KOKKOS_INLINE_FUNCTION void reset() { + for (int i=0; i<6; ++i) { + ucell[i] = 0; + Ncells[i] = 0; + diffuse[i] = 0; + } + for (int i=0; i<2; ++i) { + lambda[i] = 0; + fp_fdp[i] = 0; + } + rot.zero(); + pan_orig.zero(); + pan_rot.zero(); + eta.zero(); + fcell = 0; + } +}; + #endif diff --git a/simtbx/diffBragg/stage_two_utils.py b/simtbx/diffBragg/stage_two_utils.py index bc7df9f761..a73c8ac30c 100644 --- a/simtbx/diffBragg/stage_two_utils.py +++ b/simtbx/diffBragg/stage_two_utils.py @@ -113,11 +113,8 @@ def PAR_from_params(params, experiment, best=None): PAR.Ndef = [None]*3 PAR.eta = [None]*3 PAR.RotXYZ_params = [None]*3 - - if not params.use_restraints or params.fix.ucell: - # dummie values: - params.centers.ucell = [1, 1, 1, 1, 1, 1] - params.betas.ucell = [1,1,1,1,1,1] + PAR.diffuse_sigma = [None]*3 + PAR.diffuse_gamma = [None]*3 eta_min = params.mins.eta_abc init_eta = params.init.eta_abc if best is None else best.eta_abc.values[0] @@ -126,28 +123,46 @@ def PAR_from_params(params, experiment, best=None): if not params.simulator.crystal.num_mosaicity_samples == 1: raise ValueError("if all eta_abc are 0,0,0, num_mosaicity_samples should be 1") + # TODO allow setting diffuse gamma/sigma from stage 1 (e.g. from the `best` dataframe) + init_diffuse_sigma = params.init.diffuse_sigma + init_diffuse_gamma = params.init.diffuse_gamma + for i in range(3): initN = params.init.Nabc[i] if best is None else best.ncells.values[0][i] PAR.Nabc[i] = ParameterType(init=initN, minval=params.mins.Nabc[i], maxval=params.maxs.Nabc[i], fix=params.fix.Nabc, sigma=params.sigmas.Nabc[i], - center=params.centers.Nabc[i], beta=params.betas.Nabc[i]) + center=params.centers.Nabc[i] if params.centers.Nabc is not None else None, + beta=params.betas.Nabc[i] if params.betas.Nabc is not None else None) initN = params.init.Ndef[i] if best is None else best.ncells_def.values[0][i] PAR.Ndef[i] = ParameterType(init=initN, minval=params.mins.Ndef[i], maxval=params.maxs.Ndef[i], fix=params.fix.Ndef, sigma=params.sigmas.Ndef[i], - center=params.centers.Ndef[i], beta=params.betas.Ndef[i]) + center=params.centers.Ndef[i] if params.centers.Ndef is not None else None, + beta=params.betas.Ndef[i] if params.betas.Ndef is not None else None) PAR.RotXYZ_params[i] = ParameterType(init=0, minval=params.mins.RotXYZ[i], maxval=params.maxs.RotXYZ[i], fix=params.fix.RotXYZ, sigma=params.sigmas.RotXYZ[i], - center=0, beta=params.betas.RotXYZ) + center=0 if params.betas.RotXYZ is not None else None, beta=params.betas.RotXYZ) PAR.eta[i] = ParameterType(init=init_eta[i], minval=eta_min[i], maxval=params.maxs.eta_abc[i], fix=params.fix.eta_abc, sigma=params.sigmas.eta_abc[i], - center=params.betas.eta_abc[i], beta=params.betas.eta_abc[i]) + center=params.betas.eta_abc[i] if params.centers.eta_abc is not None else None, + beta=params.betas.eta_abc[i] if params.betas.eta_abc is not None else None) # TODO: diffuse scattering terms + PAR.diffuse_sigma[i] = ParameterType(init=init_diffuse_sigma[i], minval=params.mins.diffuse_sigma[i], + maxval=params.maxs.diffuse_sigma[i], fix=params.fix.diffuse_sigma, + sigma=params.sigmas.diffuse_sigma[i], + center=params.centers.diffuse_sigma[i] if params.centers.diffuse_sigma is not None else None, + beta=params.betas.diffuse_sigma[i] if params.betas.diffuse_sigma is not None else None) + + PAR.diffuse_gamma[i] = ParameterType(init=init_diffuse_gamma[i], minval=params.mins.diffuse_gamma[i], + maxval=params.maxs.diffuse_gamma[i], fix=params.fix.diffuse_gamma, + sigma=params.sigmas.diffuse_gamma[i], + center=params.centers.diffuse_gamma[i] if params.centers.diffuse_gamma is not None else None, + beta=params.betas.diffuse_gamma[i] if params.betas.diffuse_gamma is not None else None) # unit cell parameters ucell_man = utils.manager_from_crystal(experiment.crystal) # Note ucell man contains the best parameters (if best is not None) @@ -157,12 +172,34 @@ def PAR_from_params(params, experiment, best=None): if "Ang" in name: minval = val - ucell_vary_perc * val maxval = val + ucell_vary_perc * val + if name == 'a_Ang': + cent = params.centers.ucell_a + beta = params.betas.ucell_a + elif name == 'b_Ang': + cent = params.centers.ucell_b + beta = params.betas.ucell_b + else: + cent = params.centers.ucell_c + beta = params.betas.ucell_c else: val_in_deg = val * 180 / np.pi minval = (val_in_deg - params.ucell_ang_abs) * np.pi / 180. maxval = (val_in_deg + params.ucell_ang_abs) * np.pi / 180. + if name == 'alpha_rad': + cent = params.centers.ucell_alpha + beta = params.betas.ucell_alpha + elif name == 'beta_rad': + cent = params.centers.ucell_beta + beta = params.betas.ucell_beta + else: + cent = params.centers.ucell_gamma + beta = params.betas.ucell_gamma + assert cent is not None + assert beta is not None + cent = cent * np.pi / 180. + p = ParameterType(init=val, minval=minval, maxval=maxval, fix=params.fix.ucell, sigma=params.sigmas.ucell[i_uc], - center=params.centers.ucell[i_uc], beta=params.betas.ucell[i_uc]) + center=cent, beta=beta) PAR.ucell.append(p) PAR.ucell_man = ucell_man @@ -173,7 +210,7 @@ def PAR_from_params(params, experiment, best=None): center=params.centers.detz_shift, beta=params.betas.detz_shift) PAR.B = ParameterType(init=params.init.B, sigma=params.sigmas.B, minval=params.mins.B, maxval=params.maxs.B, fix=True, - center=0, beta=1e8) + center=params.centers.B, beta=params.betas.B) lam0, lam1 = params.init.spec if best is not None: @@ -181,8 +218,8 @@ def PAR_from_params(params, experiment, best=None): PAR.spec_coef = [] for i_p, init_val in enumerate((lam0, lam1)): p = ParameterType(init=init_val, sigma=params.sigmas.spec[i_p], - center=params.centers.spec[i_p], - beta=params.betas.spec[i_p], + center=params.centers.spec[i_p] if params.centers.spec is not None else None, + beta=params.betas.spec[i_p] if params.betas.spec is not None else None, fix=params.fix.spec, minval=params.mins.spec[i_p], maxval=params.maxs.spec[i_p]) PAR.spec_coef.append(p) @@ -203,3 +240,5 @@ def __init__(self): self.detz_shift = None self.paneRot = None self.PanXYZ = None + self.diffuse_sigma = None + self.diffuse_gamma = None diff --git a/simtbx/diffBragg/tests/tst_diffBragg_Fcell_deriv.py b/simtbx/diffBragg/tests/tst_diffBragg_Fcell_deriv.py index a24b0bee4a..45e0b6ae98 100644 --- a/simtbx/diffBragg/tests/tst_diffBragg_Fcell_deriv.py +++ b/simtbx/diffBragg/tests/tst_diffBragg_Fcell_deriv.py @@ -152,6 +152,7 @@ assert l.rvalue > .9999 # this is definitely a line! assert l.slope > 0 assert l.pvalue < 1e-6 + assert l.intercept < 0.1*l.slope # line should go through origin print("Error versus parameter shift fits a line with slope=%2.7g and Correleation Coef=%2.7g" % (l.slope, l.rvalue)) print("OK!") for name in find_diffBragg_instances(globals()): del globals()[name] diff --git a/simtbx/diffBragg/tests/tst_diffBragg_detdist_derivatives.py b/simtbx/diffBragg/tests/tst_diffBragg_detdist_derivatives.py index 55f30ef84f..7c14318a5d 100644 --- a/simtbx/diffBragg/tests/tst_diffBragg_detdist_derivatives.py +++ b/simtbx/diffBragg/tests/tst_diffBragg_detdist_derivatives.py @@ -372,6 +372,8 @@ assert l.rvalue > .99 assert l.slope > 0 assert l.pvalue < 1e-6 + assert l.intercept < 0.1*l.slope + if args.curvatures: if args.plotlines: @@ -387,5 +389,7 @@ assert l.rvalue > .99 assert l.slope > 0 assert l.pvalue < 1e-6 + assert l.intercept < 0.1*l.slope + print("OK!") for name in find_diffBragg_instances(globals()): del globals()[name] diff --git a/simtbx/diffBragg/tests/tst_diffBragg_diffuse_properties.py b/simtbx/diffBragg/tests/tst_diffBragg_diffuse_properties.py index ca64bc1e98..c09f28597f 100644 --- a/simtbx/diffBragg/tests/tst_diffBragg_diffuse_properties.py +++ b/simtbx/diffBragg/tests/tst_diffBragg_diffuse_properties.py @@ -122,6 +122,7 @@ assert l.rvalue > .9999 # this is definitely a line! assert l.slope > 0 assert l.pvalue < 1e-6 + assert l.intercept < 0.1*l.slope # line should go through origin det_sh = 1024, 1024 print("OK") diff --git a/simtbx/diffBragg/tests/tst_diffBragg_eta_derivs.py b/simtbx/diffBragg/tests/tst_diffBragg_eta_derivs.py index ab3a3c5dd8..d1c0c79819 100644 --- a/simtbx/diffBragg/tests/tst_diffBragg_eta_derivs.py +++ b/simtbx/diffBragg/tests/tst_diffBragg_eta_derivs.py @@ -99,7 +99,7 @@ SIM.add_air = True SIM.add_water = True SIM.include_noise = True - SIM.D.use_cuda = args.kokkos + SIM.D.use_gpu = args.kokkos SIM.D.compute_curvatures = args.curvatures SIM.D.add_diffBragg_spots() @@ -196,10 +196,12 @@ assert l.rvalue > .99, "%f" % l.rvalue assert l.slope > 0, "%f" % l.slope assert l.pvalue < 1e-6, "%f" % l.pvalue + assert l.intercept < 0.1*l.slope, "%f" % l.intercept if args.curvatures: l = linregress(all_shifts2, all_errors2) assert l.rvalue > .9999 # this is definitely a line! assert l.slope > 0 assert l.pvalue < 1e-6 + assert l.intercept < 0.1*l.slope # line should go through origin print("OK") for name in find_diffBragg_instances(globals()): del globals()[name] diff --git a/simtbx/diffBragg/tests/tst_diffBragg_hopper_refine.py b/simtbx/diffBragg/tests/tst_diffBragg_hopper_refine.py index 1609175af1..8c4e0f12ea 100644 --- a/simtbx/diffBragg/tests/tst_diffBragg_hopper_refine.py +++ b/simtbx/diffBragg/tests/tst_diffBragg_hopper_refine.py @@ -194,6 +194,13 @@ P.fix.detz_shift = True P.ftol=1e-15 + if args.perturb == ["detz_shift"]: + P.fix.detz_shift = False + P.fix.ucell=True + P.fix.Nabc=True + P.fix.G=True + P.fix.RotXYZ=True + E.detector = SIM.detector E.beam = SIM.D.beam E.imageset = make_imageset([img], E.beam, E.detector) @@ -219,6 +226,7 @@ P.simulator.structure_factors.mtz_name = mtz_name P.simulator.structure_factors.mtz_column = "F(+),F(-)" P.niter = 0 + P.sigmas.RotXYZ = [1,1,1] P.logging.parameters=True P.niter_per_J = 1 P.method="L-BFGS-B" @@ -268,7 +276,10 @@ # TODO open the pandas output file and optimized expt in outdir and verify the optimized parameters are similar to ground exit() + P.record_device_timings = True Eopt,_, Mod, SIM_used_by_hopper, x = hopper_utils.refine(E, refls, P, spec=spec, return_modeler=True) + if SIM_used_by_hopper.D.record_timings: + SIM_used_by_hopper.D.show_timings(MPI_RANK=0) G, rotX,rotY, rotZ, Na,Nb,Nc,_,_,_,_,_,_,_,_,_,a,b,c,al,be,ga,detz_shift = hopper_utils.get_param_from_x(x, Mod) eta_abc_opt = hopper_utils.get_mosaicity_from_x(x, Mod, SIM_used_by_hopper) diff --git a/simtbx/diffBragg/tests/tst_diffBragg_hopper_refine_Fhkl.py b/simtbx/diffBragg/tests/tst_diffBragg_hopper_refine_Fhkl.py index 5846564feb..5be8e6b274 100644 --- a/simtbx/diffBragg/tests/tst_diffBragg_hopper_refine_Fhkl.py +++ b/simtbx/diffBragg/tests/tst_diffBragg_hopper_refine_Fhkl.py @@ -129,6 +129,7 @@ SIM.D.raw_pixels *= 0 P = phil_scope.extract() + P.debug_mode=True E = Experiment() P.init.G = SIM.D.spot_scale @@ -215,7 +216,9 @@ P.outdir="_temp_fhkl_refine" if args.maxiter is not None: P.lbfgs_maxiter = args.maxiter + P.record_device_timings = True Eopt,_, Mod,SIM_from_hopper, x = hopper_utils.refine(E, refls, P, return_modeler=True, free_mem=False) + SIM_from_hopper.D.show_timings(0) logging.disable() print("\nResults\n<><><><><><>") @@ -331,10 +334,18 @@ def compute_r_factor_with_gt(corrections): df[refl_col] = [input_refl] P.refiner.load_data_from_refl = True P.refiner.check_expt_format = False + + #from simtbx.diffBragg import mpi_logger + #P.logging.rank0_level="high" + #mpi_logger.setup_logging_from_params(P) modelers = load_inputs(df, P, exper_key="opt_exp_name", refls_key=refl_col) modelers.outdir=P.outdir modelers.prep_for_refinement() + print("Minimizing using hopper_ensemble_utils...") modelers.Minimize(save=True) + if modelers.SIM.D.record_timings: + modelers.SIM.D.show_timings(MPI_RANK=0) + print("Done!") from iotbx.reflection_file_reader import any_reflection_file opt_F = any_reflection_file("_temp_fhkl_refine/optimized_channel0.mtz").as_miller_arrays()[0] diff --git a/simtbx/diffBragg/tests/tst_diffBragg_lambda_coefficients.py b/simtbx/diffBragg/tests/tst_diffBragg_lambda_coefficients.py index 386f6cd212..da7557b3b4 100644 --- a/simtbx/diffBragg/tests/tst_diffBragg_lambda_coefficients.py +++ b/simtbx/diffBragg/tests/tst_diffBragg_lambda_coefficients.py @@ -155,6 +155,7 @@ assert l.rvalue > .9999 # this is definitely a line! assert l.slope > 0 assert l.pvalue < 1e-6 + assert l.intercept < 0.1*l.slope # line should go through origin print("OK!") for name in find_diffBragg_instances(globals()): del globals()[name] diff --git a/simtbx/diffBragg/tests/tst_diffBragg_ncells_offdiag_property.py b/simtbx/diffBragg/tests/tst_diffBragg_ncells_offdiag_property.py index 9bf3dfd801..4084080cf6 100644 --- a/simtbx/diffBragg/tests/tst_diffBragg_ncells_offdiag_property.py +++ b/simtbx/diffBragg/tests/tst_diffBragg_ncells_offdiag_property.py @@ -136,11 +136,13 @@ assert l.rvalue > .999 # this is definitely a line! assert l.slope > 0 assert l.pvalue < 1e-5 + assert l.intercept < 0.1*l.slope # line should go through origin if args.curvatures: l = linregress(shifts2, all_error2) assert l.rvalue > .999 # this is definitely a line! assert l.slope > 0 assert l.pvalue < 1e-5 + assert l.intercept < 0.1*l.slope # line should go through origin print("OK!") for name in find_diffBragg_instances(globals()): del globals()[name] diff --git a/simtbx/diffBragg/tests/tst_diffBragg_ncells_property.py b/simtbx/diffBragg/tests/tst_diffBragg_ncells_property.py index 70e3d28eb7..c3310fb5ca 100644 --- a/simtbx/diffBragg/tests/tst_diffBragg_ncells_property.py +++ b/simtbx/diffBragg/tests/tst_diffBragg_ncells_property.py @@ -128,11 +128,13 @@ assert l.rvalue > .9999, l # this is definitely a line! assert l.slope > 0 assert l.pvalue < 1e-6 + assert l.intercept < 0.1*l.slope # line should go through origin if args.curvatures: l = linregress(shifts2, all_error2) assert l.rvalue > .9999 # this is definitely a line! assert l.slope > 0 assert l.pvalue < 1e-6 + assert l.intercept < 0.1*l.slope # line should go through origin print("OK!") for name in find_diffBragg_instances(globals()): del globals()[name] diff --git a/simtbx/diffBragg/tests/tst_diffBragg_ncells_property_anisotropic.py b/simtbx/diffBragg/tests/tst_diffBragg_ncells_property_anisotropic.py index 8c9dee4013..42a2011ecf 100644 --- a/simtbx/diffBragg/tests/tst_diffBragg_ncells_property_anisotropic.py +++ b/simtbx/diffBragg/tests/tst_diffBragg_ncells_property_anisotropic.py @@ -137,11 +137,13 @@ assert l.rvalue > .9999 # this is definitely a line! assert l.slope > 0 assert l.pvalue < 1e-6 + assert l.intercept < 0.1*l.slope # line should go through origin if args.curvatures: l = linregress(shifts2, all_error2) assert l.rvalue > .9999 # this is definitely a line! assert l.slope > 0 assert l.pvalue < 1e-6 + assert l.intercept < 0.1*l.slope # line should go through origin print("OK!") for name in find_diffBragg_instances(globals()): del globals()[name] diff --git a/simtbx/diffBragg/tests/tst_diffBragg_panelXY_derivs.py b/simtbx/diffBragg/tests/tst_diffBragg_panelXY_derivs.py index 2578fa7136..f542ed9372 100644 --- a/simtbx/diffBragg/tests/tst_diffBragg_panelXY_derivs.py +++ b/simtbx/diffBragg/tests/tst_diffBragg_panelXY_derivs.py @@ -121,6 +121,7 @@ assert l.rvalue > .99 assert l.slope > 0 assert l.pvalue < 1e-6 + assert l.intercept < 0.1*l.slope # line should go through origin print("OK!") for name in find_diffBragg_instances(globals()): del globals()[name] diff --git a/simtbx/diffBragg/tests/tst_diffBragg_rotXYZ.py b/simtbx/diffBragg/tests/tst_diffBragg_rotXYZ.py index 730f8f9db9..2e93bc87e1 100644 --- a/simtbx/diffBragg/tests/tst_diffBragg_rotXYZ.py +++ b/simtbx/diffBragg/tests/tst_diffBragg_rotXYZ.py @@ -24,7 +24,7 @@ def main(): print (angles_XYZ*180 / np.pi) D = get_diffBragg_instance() - D.use_cuda = args.kokkos + D.use_gpu = args.kokkos rotX, rotY, rotZ = 0, 1, 2 D.refine(rotX) # rotX diff --git a/simtbx/diffBragg/tests/tst_diffBragg_rotXYZ_deriv.py b/simtbx/diffBragg/tests/tst_diffBragg_rotXYZ_deriv.py index 0bd0b89f9f..d8009ed6fa 100644 --- a/simtbx/diffBragg/tests/tst_diffBragg_rotXYZ_deriv.py +++ b/simtbx/diffBragg/tests/tst_diffBragg_rotXYZ_deriv.py @@ -59,7 +59,7 @@ D.refine(rot_idx) D.initialize_managers() D.set_value(rot_idx, 0) - D.use_cuda = args.kokkos + D.use_gpu = args.kokkos #D.printout_pixel_fastslow = 786, 567 D.add_diffBragg_spots() img0 = D.raw_pixels_roi.as_numpy_array() @@ -157,11 +157,13 @@ assert l.rvalue > .9999, "%2.7g" % l.rvalue assert l.slope > 0, "%2.7g" % l.slope assert l.pvalue < 1e-6, "%2.7g" % l.pvalue + assert l.intercept < 0.1*l.slope, "%2.7g" % l.intercept if args.curvatures: l = stats.linregress(delta_h2, error_vals2) assert l.rvalue > .9999, "2nd deriv rvalue %2.7g" % l.rvalue assert l.slope > 0, "2nd deriv slope %2.7g" % l.slope assert l.pvalue < 1e-6, "2nd deriv pvalue %2.7g" % l.pvalue + assert l.intercept < 0.1*l.slope, "2nd deriv pvalue %2.7g" % l.intercept if args.kokkos: D.gpu_free() print("OK!") diff --git a/simtbx/diffBragg/tests/tst_diffBragg_unitcell_property.py b/simtbx/diffBragg/tests/tst_diffBragg_unitcell_property.py index d138a671db..90ef89420d 100644 --- a/simtbx/diffBragg/tests/tst_diffBragg_unitcell_property.py +++ b/simtbx/diffBragg/tests/tst_diffBragg_unitcell_property.py @@ -1,12 +1,10 @@ from __future__ import division -##from simtbx.kokkos import gpu_instance -#kokkos_run = gpu_instance(deviceId = 0) from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument("--plot", action='store_true') parser.add_argument("--crystalsystem", default='tetragonal', - choices=["monoclinic", "tetragonal"]) + choices=["monoclinic", "tetragonal", "hexagonal"]) parser.add_argument("--curvatures", action='store_true') parser.add_argument("--kokkos", action="store_true") args = parser.parse_args() @@ -38,6 +36,9 @@ if args.crystalsystem=="tetragonal": ucell = (55, 55, 77, 90, 90, 90) symbol = "P43212" + elif args.crystalsystem=="hexagonal": + ucell = (55, 55, 77, 90, 90, 120) + symbol = "P6522" else: # args.crystalsystem == "monoclinic" ucell = (70, 60, 50, 90.0, 110, 90.0) symbol = "C121" @@ -76,6 +77,7 @@ # and our dxtbx crystal created above D = SIM.D D.progress_meter = True + D.compute_curvatures = args.curvatures # STEP6: # initialize the derivative managers for the unit cell parameters @@ -178,26 +180,26 @@ cc_vals2.append(r2) if args.plot: plt.subplot(121) - plt.imshow(finite_deriv) + plt.imshow(finite_deriv.reshape((img_sh))) plt.title("finite diff") plt.subplot(122) - plt.imshow(analy_deriv) + plt.imshow(analy_deriv.reshape((img_sh))) plt.title("analytical") plt.draw() plt.suptitle("Shift %d / %d" % (i_shift+1, len(shifts))) - plt.pause(0.8) + plt.pause(1.2) if args.curvatures: plt.subplot(121) - plt.imshow(finite_second_deriv) + plt.imshow(finite_second_deriv.reshape((img_sh))) plt.title("finite second diff") plt.subplot(122) - plt.imshow(second_derivs[i_param]) + plt.imshow(second_derivs[i_param].reshape((img_sh))) plt.title("analytical") plt.draw() plt.suptitle("Shift %d / %d" % (i_shift + 1, len(shifts))) - plt.pause(0.8) + plt.pause(1.2) l = linregress(h_vals, error) @@ -205,6 +207,7 @@ assert l.rvalue > .99 assert l.slope > 0 assert l.pvalue < 1e-6 + assert l.intercept < 0.1*l.slope if args.curvatures: l2 = linregress(np.array(h_vals)**2, error2) @@ -212,6 +215,7 @@ assert l2.rvalue > .99 assert l2.slope > 0 assert l2.pvalue < 1e-6 + assert l2.intercept < 0.1*l2.slope if args.plot: plt.close() diff --git a/simtbx/diffBragg/utils.py b/simtbx/diffBragg/utils.py index 3692633de0..28e7857820 100644 --- a/simtbx/diffBragg/utils.py +++ b/simtbx/diffBragg/utils.py @@ -1,5 +1,6 @@ from __future__ import absolute_import, division, print_function import os +import socket import sys import re from io import StringIO @@ -29,6 +30,8 @@ from cctbx.eltbx import henke from simtbx.diffBragg import psf from dials.algorithms.shoebox import MaskCode +from xfel.merging.application.utils.memory_usage import get_memory_usage + import logging MAIN_LOGGER = logging.getLogger("diffBragg.main") @@ -81,14 +84,22 @@ def label_background_pixels(roi_img, thresh=3.5, iterations=1, only_high=True): while iterations > 0: if background_pixels is None: outliers = is_outlier(img1, thresh) - m = np.median(img1[~outliers]) + inlier_vals = img1[~outliers] + if inlier_vals.size: + m = np.median(inlier_vals) + else: + m = np.nan if only_high: outliers = np.logical_and(outliers, img1 > m) background_pixels = ~outliers else: where_bg = np.where(background_pixels)[0] outliers = is_outlier(img1[background_pixels], thresh) - m = np.median(img1[background_pixels][~outliers]) + inlier_vals = img1[background_pixels][~outliers] + if inlier_vals.size: + m = np.median(inlier_vals) + else: + m = np.nan if only_high: outliers = np.logical_and(outliers, img1[background_pixels] > m) background_pixels[where_bg[outliers]] = False @@ -101,10 +112,16 @@ def is_outlier(points, thresh=3.5): """http://stackoverflow.com/a/22357811/2077270""" if len(points.shape) == 1: points = points[:, None] - median = np.median(points, axis=0) + if points.size: + median = np.median(points, axis=0) + else: + median = np.nan diff = np.sum((points - median) ** 2, axis=-1) diff = np.sqrt(diff) - med_abs_deviation = np.median(diff) + if diff.size: + med_abs_deviation = np.median(diff) + else: + med_abs_deviation = np.nan if med_abs_deviation == 0: return np.zeros(points.shape[0], bool) @@ -452,13 +469,13 @@ def get_roi_background_and_selection_flags(refls, imgs, shoebox_sz=10, reject_ed selection_flags = [] num_roi_negative_bg = 0 num_roi_nan_bg = 0 - background = np.ones(imgs.shape)*-1 + background = np.full_like(imgs, -1, dtype=float) i_roi = 0 while i_roi < len(rois): roi = rois[i_roi] i1, i2, j1, j2 = roi is_selected = True - MAIN_LOGGER.debug("Reflection %d bounded by x1=%d,x2=%d,y1=%d,y2=%d" % (i_roi, i1,i2,j1,j2)) + refl_bbox_str = "Reflection %d bounded by x1=%d,x2=%d,y1=%d,y2=%d" % (i_roi, i1,i2,j1,j2) if is_on_edge[i_roi] and reject_edge_reflections: MAIN_LOGGER.debug("Reflection %d is on edge" % i_roi) is_selected = False @@ -474,6 +491,14 @@ def get_roi_background_and_selection_flags(refls, imgs, shoebox_sz=10, reject_ed MAIN_LOGGER.debug("reflection %d has too many (%d) hot pixels (%d allowed)!" % (i_roi, num_hotpix, min_trusted_pix_per_roi)) is_selected = False + # Before padding and fitting, test for overlaps and shrink if needed + is_overlapping = not np.all(background[pid, j1:j2, i1:i2] == -1) + if not allow_overlaps and is_overlapping: + MAIN_LOGGER.debug("region of interest already accounted for roi size= %d %d" % (i2-i1, j2-j1)) + rois[i_roi] = (i1 + 1, i2, j1 + 1, j2) if (i1 + i2) % 2 \ + else (i1, i2 - 1, j1, j2 - 1) # shrink alternately from corners + continue + dimY, dimX = imgs[pid].shape j1_nopad = j1 i1_nopad = i1 @@ -487,6 +512,10 @@ def get_roi_background_and_selection_flags(refls, imgs, shoebox_sz=10, reject_ed shoebox = imgs[pid, j1:j2, i1:i2] + if shoebox.size < 4: + MAIN_LOGGER.debug("reflection %d has negative background" % i_roi) + is_selected = False + if not isinstance(sigma_rdout, float) and not isinstance(sigma_rdout, int): shoebox_sigma_readout = sigma_rdout[pid, j1:j2, i1:i2] else: @@ -495,13 +524,19 @@ def get_roi_background_and_selection_flags(refls, imgs, shoebox_sz=10, reject_ed if background_mask is not None: is_background = background_mask[pid, j1:j2, i1:i2] else: - is_background = label_background_pixels(shoebox,thresh=bg_thresh, iterations=2, only_high=only_high) + if shoebox.shape== (0,0): + is_background = shoebox.copy().astype(bool) + else: + is_background = label_background_pixels(shoebox,thresh=bg_thresh, iterations=2, only_high=only_high) Ycoords, Xcoords = np.indices((j2-j1, i2-i1)) if use_robust_estimation: bg_pixels = shoebox[is_background] - bg_signal = np.median(bg_pixels) + if not bg_pixels.size: + bg_signal = np.nan + else: + bg_signal = np.median(bg_pixels) if bg_signal < 0: num_roi_negative_bg += 1 if set_negative_bg_to_zero: @@ -509,6 +544,8 @@ def get_roi_background_and_selection_flags(refls, imgs, shoebox_sz=10, reject_ed elif skip_roi_with_negative_bg: MAIN_LOGGER.debug("reflection %d has negative background" % i_roi) is_selected = False + elif np.isnan(bg_signal): + is_selected = False tilt_a, tilt_b, tilt_c = 0, 0, bg_signal covariance = None @@ -524,7 +561,7 @@ def get_roi_background_and_selection_flags(refls, imgs, shoebox_sz=10, reject_ed MAIN_LOGGER.debug("tilt fit failed for reflection %d, probably too few pixels" % i_roi) tilt_plane = np.zeros_like(Xcoords) else: - MAIN_LOGGER.debug("successfully fit tilt plane") + #MAIN_LOGGER.debug("successfully fit tilt plane") (tilt_a, tilt_b, tilt_c), covariance = fit_results tilt_plane = tilt_a * Xcoords + tilt_b * Ycoords + tilt_c if np.any(np.isnan(tilt_plane)) and is_selected: @@ -536,14 +573,6 @@ def get_roi_background_and_selection_flags(refls, imgs, shoebox_sz=10, reject_ed MAIN_LOGGER.debug("reflection %d has tilt plane that dips below 0" % i_roi) is_selected = False - is_overlapping = not np.all(background[pid, j1_nopad:j2_nopad, i1_nopad:i2_nopad] == -1) - - if not allow_overlaps and is_overlapping: - # NOTE : move away from this option, it potentially moves the pixel centroid outside of the ROI (in very rare instances) - MAIN_LOGGER.debug("region of interest already accounted for roi size= %d %d" % (i2_nopad-i1_nopad, j2_nopad-j1_nopad)) - rois[i_roi] = i1_nopad+1,i2_nopad,j1_nopad+1,j2_nopad - continue - # unpadded ROI dimension roi_dimY = j2_nopad-j1_nopad roi_dimX = i2_nopad-i1_nopad @@ -561,6 +590,8 @@ def get_roi_background_and_selection_flags(refls, imgs, shoebox_sz=10, reject_ed kept_rois.append(roi) panel_ids.append(pid) selection_flags.append(is_selected) + if not is_selected: + MAIN_LOGGER.debug("--> %s was not selected for above reasons" % refl_bbox_str) i_roi += 1 MAIN_LOGGER.debug("Number of skipped ROI with negative BGs: %d / %d" % (num_roi_negative_bg, len(rois))) @@ -650,7 +681,7 @@ def fit_plane_equation_to_background_pixels(shoebox_img, fit_sel, sigma_rdout=3, # vector of residuals r = rho_bg - np.dot(A, (t1, t2, t3)) Nbg = len(rho_bg) - with np.errstate(invalid='ignore'): + with np.errstate(divide='ignore', invalid='ignore'): r_fact = np.dot(r.T, np.dot(W, r)) / (Nbg - 3) # 3 parameters fit var_covar = AWA_inv * r_fact # TODO: check for correlations in the off diagonal elems @@ -705,6 +736,7 @@ def image_data_from_expt(expt, as_double=True): raise ValueError("imageset should have only 1 shot. This expt has imageset with %d shots" % len(iset)) try: flex_data = iset.get_raw_data(0) + except Exception as err: assert str(type(err)) == "", "something weird going on with imageset data" flex_data = iset.get_raw_data() @@ -748,6 +780,9 @@ def simulator_for_refinement(expt, params): else: MAIN_LOGGER.info("Will not use mosaic models, as simulator.crystal.num_mosaicity_samples=1") + if not params.fix.eta_abc: + assert SIM.D.mosaic_domains > 1 + if not params.fix.diffuse_gamma or not params.fix.diffuse_sigma: assert params.use_diffuse_models SIM.D.use_diffuse = params.use_diffuse_models @@ -1385,15 +1420,20 @@ def refls_to_hkl(refls, detector, beam, crystal, return np.vstack(HKL).T, np.vstack(HKLi).T -def get_panels_fasts_slows(expt, pids, rois): +def get_panels_fasts_slows(expt, pids, rois, img_sh=None): """ :param expt: dxtbx experiment :param pids: panel ids :param rois: regions of interest + :param img_sh: 3-tuple Npan, Nslow, Nfast :return: """ - npan = len(expt.detector) - nfast, nslow = expt.detector[0].get_image_size() + if expt is not None: + npan = len(expt.detector) + nfast, nslow = expt.detector[0].get_image_size() + else: + assert img_sh is not None + npan, nslow, nfast = img_sh MASK = np.zeros((npan, nslow, nfast), bool) ROI_ID = np.zeros((npan, nslow, nfast), 'uint16') #ROI_ID = NP_ONES((npan, nslow, nfast), 'uint16') * mx @@ -1727,3 +1767,52 @@ def find_diffBragg_instances(globe_objs): if "simtbx_diffBragg_ext.diffBragg" in str(obj): inst_names.append(name) return inst_names + + +def memory_report(prefix='Memory usage'): + """Return a string documenting memory usage; to be used with LOGGER.info""" + memory_usage_in_gb = get_memory_usage() / 1024. + host = socket.gethostname() + return "%s: %f GB on node %s" % (prefix, memory_usage_in_gb, host) + + +def smooth(x, beta=10.0, window_size=11): + """ + https://glowingpython.blogspot.com/2012/02/convolution-with-numpy.html + + Apply a Kaiser window smoothing convolution. + + Parameters + ---------- + x : ndarray, float + The array to smooth. + + Optional Parameters + ------------------- + beta : float + Parameter controlling the strength of the smoothing -- bigger beta + results in a smoother function. + window_size : int + The size of the Kaiser window to apply, i.e. the number of neighboring + points used in the smoothing. + + Returns + ------- + smoothed : ndarray, float + A smoothed version of `x`. + """ + + # make sure the window size is odd + if window_size % 2 == 0: + window_size += 1 + + # apply the smoothing function + s = np.r_[x[window_size - 1:0:-1], x, x[-1:-window_size:-1]] + w = np.kaiser(window_size, beta) + y = np.convolve(w / w.sum(), s, mode='valid') + + # remove the extra array length convolve adds + b = int((window_size - 1) / 2) + smoothed = y[b:len(y) - b] + + return smoothed diff --git a/simtbx/gpu/simulation.cu b/simtbx/gpu/simulation.cu index af29f670e7..24b2274cb5 100644 --- a/simtbx/gpu/simulation.cu +++ b/simtbx/gpu/simulation.cu @@ -92,7 +92,8 @@ namespace af = scitbx::af; simtbx::gpu::gpu_detector & gdt, double const& weight ){ - cudaSafeCall(cudaSetDevice(SIM.device_Id)); + SCITBX_ASSERT(SIM.device_Id == stash_device_Id); + cudaSafeCall(cudaSetDevice(stash_device_Id)); // transfer source_I, source_lambda // the int arguments are for sizes of the arrays @@ -107,7 +108,7 @@ namespace af = scitbx::af; cu_current_channel_Fhkl = gec.d_channel_Fhkl[ichannel]; cudaDeviceProp deviceProps = { 0 }; - cudaSafeCall(cudaGetDeviceProperties(&deviceProps, SIM.device_Id)); + cudaSafeCall(cudaGetDeviceProperties(&deviceProps, stash_device_Id)); int smCount = deviceProps.multiProcessorCount; dim3 threadsPerBlock(THREADS_PER_BLOCK_X, THREADS_PER_BLOCK_Y); dim3 numBlocks(smCount * 8, 1); @@ -185,7 +186,8 @@ namespace af = scitbx::af; simtbx::gpu::gpu_detector & gdt, af::shared const active_pixel_list ){ - cudaSafeCall(cudaSetDevice(SIM.device_Id)); + SCITBX_ASSERT(SIM.device_Id == stash_device_Id); + cudaSafeCall(cudaSetDevice(stash_device_Id)); gdt.set_active_pixels_on_GPU(active_pixel_list); @@ -198,7 +200,7 @@ namespace af = scitbx::af; cu_current_channel_Fhkl = gec.d_channel_Fhkl[ichannel]; cudaDeviceProp deviceProps = { 0 }; - cudaSafeCall(cudaGetDeviceProperties(&deviceProps, SIM.device_Id)); + cudaSafeCall(cudaGetDeviceProperties(&deviceProps, stash_device_Id)); int smCount = deviceProps.multiProcessorCount; dim3 threadsPerBlock(THREADS_PER_BLOCK_X, THREADS_PER_BLOCK_Y); dim3 numBlocks(smCount * 8, 1); @@ -249,7 +251,8 @@ namespace af = scitbx::af; void exascale_api::add_background(simtbx::gpu::gpu_detector & gdt, int const& override_source){ - cudaSafeCall(cudaSetDevice(SIM.device_Id)); + SCITBX_ASSERT(SIM.device_Id == stash_device_Id); + cudaSafeCall(cudaSetDevice(stash_device_Id)); // transfer source_I, source_lambda // the int arguments are for sizes of the arrays @@ -265,7 +268,7 @@ namespace af = scitbx::af; cudaSafeCall(cudaMemcpyVectorDoubleToDevice(cu_Fbg_of, SIM.Fbg_of, SIM.stols)); cudaDeviceProp deviceProps = { 0 }; - cudaSafeCall(cudaGetDeviceProperties(&deviceProps, SIM.device_Id)); + cudaSafeCall(cudaGetDeviceProperties(&deviceProps, stash_device_Id)); int smCount = deviceProps.multiProcessorCount; dim3 threadsPerBlock(THREADS_PER_BLOCK_X, THREADS_PER_BLOCK_Y); dim3 numBlocks(smCount * 8, 1); @@ -314,7 +317,8 @@ namespace af = scitbx::af; void exascale_api::allocate(){ - cudaSafeCall(cudaSetDevice(SIM.device_Id)); + SCITBX_ASSERT(SIM.device_Id == stash_device_Id); + cudaSafeCall(cudaSetDevice(stash_device_Id)); /* water_size not defined in class, CLI argument, defaults to 0 */ double water_size = 0.0; @@ -386,7 +390,7 @@ namespace af = scitbx::af; }; exascale_api::~exascale_api(){ - cudaSafeCall(cudaSetDevice(SIM.device_Id)); + cudaSafeCall(cudaSetDevice(stash_device_Id)); cudaSafeCall(cudaFree(cu_beam_vector)); cudaSafeCall(cudaFree(cu_spindle_vector)); diff --git a/simtbx/gpu/simulation.h b/simtbx/gpu/simulation.h index 8cf384f862..b518196494 100644 --- a/simtbx/gpu/simulation.h +++ b/simtbx/gpu/simulation.h @@ -14,7 +14,7 @@ namespace af = scitbx::af; struct exascale_api { inline exascale_api(const simtbx::nanoBragg::nanoBragg& nB): - SIM(nB){ + SIM(nB),stash_device_Id(nB.device_Id){ } void show(); @@ -38,6 +38,7 @@ struct exascale_api { ~exascale_api(); const simtbx::nanoBragg::nanoBragg& SIM; + const int stash_device_Id; // must remain the same after initialization CUDAREAL * cu_current_channel_Fhkl; CUDAREAL cu_subpixel_size; diff --git a/simtbx/kokkos/SConscript b/simtbx/kokkos/SConscript index e9bcae54b6..2407718563 100644 --- a/simtbx/kokkos/SConscript +++ b/simtbx/kokkos/SConscript @@ -1,5 +1,4 @@ import os -import subprocess from shutil import copy, which import libtbx.load_env diff --git a/simtbx/kokkos/detector.cpp b/simtbx/kokkos/detector.cpp index 85715e3077..0c310551ca 100644 --- a/simtbx/kokkos/detector.cpp +++ b/simtbx/kokkos/detector.cpp @@ -16,50 +16,46 @@ using Kokkos::deep_copy; using Kokkos::create_mirror_view; using Kokkos::parallel_for; +auto get_kokkos_vec3 = [](auto&& src) { return vec3(src[0], src[1], src[2]); }; + namespace simtbx { namespace Kokkos { packed_metrology::packed_metrology(dxtbx::model::Detector const & arg_detector, dxtbx::model::Beam const & arg_beam) { for (std::size_t panel_id = 0; panel_id < arg_detector.size(); panel_id++){ - // helper code arising from the nanoBragg constructor, with user_beam=True - typedef scitbx::vec3 vec3; + // helper code arising from the nanoBragg constructor, with user_beam=True // DETECTOR properties // typically: 1 0 0 - vec3 fdet_vector = arg_detector[panel_id].get_fast_axis(); - fdet_vector = fdet_vector.normalize(); + vec3 fdet_vector = get_kokkos_vec3(arg_detector[panel_id].get_fast_axis()); + fdet_vector.normalize(); // typically: 0 -1 0 - vec3 sdet_vector = arg_detector[panel_id].get_slow_axis(); - sdet_vector = sdet_vector.normalize(); + vec3 sdet_vector = get_kokkos_vec3(arg_detector[panel_id].get_slow_axis()); + sdet_vector.normalize(); // set orthogonal vector to the detector pixel array vec3 odet_vector = fdet_vector.cross(sdet_vector); - odet_vector = odet_vector.normalize(); + odet_vector.normalize(); // dxtbx origin is location of outer corner of the first pixel - vec3 pix0_vector = arg_detector[panel_id].get_origin()/1000.0; + vec3 pix0_vector = get_kokkos_vec3(arg_detector[panel_id].get_origin()/1000.0); // what is the point of closest approach between sample and detector? - double close_distance = pix0_vector * odet_vector; + double close_distance = pix0_vector.dot(odet_vector); if (close_distance < 0){ bool verbose = false; if(verbose)printf("WARNING: dxtbx model is lefthanded. Inverting odet_vector.\n"); odet_vector = -1. * odet_vector; - close_distance = -1*close_distance; + close_distance = -1 * close_distance; } - sdet.push_back(sdet_vector.length()); - fdet.push_back(fdet_vector.length()); - odet.push_back(odet_vector.length()); - pix0.push_back(0.); - for (std::size_t idx_vec = 0; idx_vec < 3; idx_vec++){ - sdet.push_back(sdet_vector[idx_vec]); - fdet.push_back(fdet_vector[idx_vec]); - odet.push_back(odet_vector[idx_vec]); - pix0.push_back(pix0_vector[idx_vec]); - } + sdet.push_back(sdet_vector); + fdet.push_back(fdet_vector); + odet.push_back(odet_vector); + pix0.push_back(pix0_vector); + // set beam centre scitbx::vec2 dials_bc=arg_detector[panel_id].get_beam_centre(arg_beam.get_s0()); dists.push_back(close_distance); @@ -69,28 +65,28 @@ namespace simtbx { namespace Kokkos { }; packed_metrology::packed_metrology(const simtbx::nanoBragg::nanoBragg& nB){ - for (std::size_t idx_vec = 0; idx_vec < 4; idx_vec++){ - sdet.push_back(nB.sdet_vector[idx_vec]); - fdet.push_back(nB.fdet_vector[idx_vec]); - odet.push_back(nB.odet_vector[idx_vec]); - pix0.push_back(nB.pix0_vector[idx_vec]); - } - dists.push_back(nB.close_distance); - Xbeam.push_back(nB.Xbeam); - Ybeam.push_back(nB.Ybeam); + // Careful, 4-vectors! [length, x, y, z] + auto get_kokkos_vec3 = [](auto& src) { return vec3(src[1], src[2], src[3]); }; + sdet.push_back( get_kokkos_vec3(nB.sdet_vector) ); + fdet.push_back( get_kokkos_vec3(nB.fdet_vector) ); + odet.push_back( get_kokkos_vec3(nB.odet_vector) ); + pix0.push_back( get_kokkos_vec3(nB.pix0_vector) ); + dists.push_back(nB.close_distance); + Xbeam.push_back(nB.Xbeam); + Ybeam.push_back(nB.Ybeam); } void packed_metrology::show() const { for (std::size_t idx_p = 0; idx_p < Xbeam.size(); idx_p++){ printf(" Panel %3ld\n",idx_p); - printf(" Panel %3ld sdet %9.6f %9.6f %9.6f %9.6f fdet %9.6f %9.6f %9.6f %9.6f\n", - idx_p,sdet[4*idx_p+0],sdet[4*idx_p+1],sdet[4*idx_p+2],sdet[4*idx_p+3], - fdet[4*idx_p+0],fdet[4*idx_p+1],fdet[4*idx_p+2],fdet[4*idx_p+3] + printf(" Panel %3ld sdet %9.6f %9.6f %9.6f fdet %9.6f %9.6f %9.6f\n", + idx_p,sdet[idx_p][0],sdet[idx_p][1],sdet[idx_p][2], + fdet[idx_p][0],fdet[idx_p][1],fdet[idx_p][2] ); - printf(" Panel %3ld odet %9.6f %9.6f %9.6f %9.6f pix0 %9.6f %9.6f %9.6f %9.6f\n", - idx_p,odet[4*idx_p+0],odet[4*idx_p+1],odet[4*idx_p+2],odet[4*idx_p+3], - pix0[4*idx_p+0],pix0[4*idx_p+1],pix0[4*idx_p+2],pix0[4*idx_p+3] + printf(" Panel %3ld odet %9.6f %9.6f %9.6f pix0 %9.6f %9.6f %9.6f\n", + idx_p,odet[idx_p][0],odet[idx_p][1],odet[idx_p][2], + pix0[idx_p][0],pix0[idx_p][1],pix0[idx_p][2] ); printf(" Panel %3ld beam %11.8f %11.8f\n",idx_p,Xbeam[idx_p],Ybeam[idx_p]); } diff --git a/simtbx/kokkos/detector.h b/simtbx/kokkos/detector.h index ced5c4b87d..03e3913e17 100644 --- a/simtbx/kokkos/detector.h +++ b/simtbx/kokkos/detector.h @@ -7,7 +7,7 @@ // 3) the associated simulated data, in process of being accumulated by kernel calls // 4) mask data // 5) possibly other metadata - +#include #include "scitbx/array_family/shared.h" #include "scitbx/array_family/flex_types.h" @@ -15,8 +15,12 @@ #include "dxtbx/model/beam.h" #include "simtbx/nanoBragg/nanoBragg.h" #include "kokkostbx/kokkos_types.h" +#include "kokkostbx/kokkos_vector3.h" +#include "kokkostbx/kokkos_matrix3.h" + +using vec3 = kokkostbx::vector3; +using mat3 = kokkostbx::matrix3; -#include namespace simtbx { namespace Kokkos { @@ -27,10 +31,10 @@ struct packed_metrology{ packed_metrology(dxtbx::model::Detector const &,dxtbx::model::Beam const &); packed_metrology(const simtbx::nanoBragg::nanoBragg& nB); void show() const; - af::sharedsdet; - af::sharedfdet; - af::sharedodet; - af::sharedpix0; + af::sharedsdet; + af::sharedfdet; + af::sharedodet; + af::sharedpix0; af::shareddists; af::sharedXbeam; af::sharedYbeam; @@ -83,10 +87,10 @@ struct kokkos_detector{ vector_float_t m_floatimage = vector_float_t("m_floatimage", 0); // all-panel packed GPU representation of the multi-panel metrology - vector_cudareal_t m_sdet_vector = vector_cudareal_t("m_sdet_vector", 0); - vector_cudareal_t m_fdet_vector = vector_cudareal_t("m_fdet_vector", 0); - vector_cudareal_t m_odet_vector = vector_cudareal_t("m_odet_vector", 0); - vector_cudareal_t m_pix0_vector = vector_cudareal_t("m_pix0_vector", 0); + view_1d_t m_sdet_vector = view_1d_t("m_sdet_vector", 0); + view_1d_t m_fdet_vector = view_1d_t("m_fdet_vector", 0); + view_1d_t m_odet_vector = view_1d_t("m_odet_vector", 0); + view_1d_t m_pix0_vector = view_1d_t("m_pix0_vector", 0); vector_cudareal_t m_distance = vector_cudareal_t("m_distance", 0); vector_cudareal_t m_Xbeam = vector_cudareal_t("m_Xbeam", 0); vector_cudareal_t m_Ybeam = vector_cudareal_t("m_Ybeam", 0); diff --git a/simtbx/kokkos/kernel_math.h b/simtbx/kokkos/kernel_math.h index b140ec91d9..f55e38013e 100644 --- a/simtbx/kokkos/kernel_math.h +++ b/simtbx/kokkos/kernel_math.h @@ -24,6 +24,7 @@ KOKKOS_INLINE_FUNCTION static void cross_product(CUDAREAL *x, CUDAREAL *y, CUDAR /* rotate a 3-vector about a unit vector axis */ KOKKOS_INLINE_FUNCTION static CUDAREAL *rotate_axis(const vector_cudareal_t v, CUDAREAL * newv, const vector_cudareal_t axis, const CUDAREAL phi); KOKKOS_INLINE_FUNCTION static CUDAREAL *rotate_axis(const CUDAREAL * v, CUDAREAL * newv, const vector_cudareal_t axis, const CUDAREAL phi); +KOKKOS_INLINE_FUNCTION static vector3 rotate_axis(const vector3& v, vector3& newv, const vector3& axis, const CUDAREAL phi); /* rotate a 3-vector using a 9-element unitary matrix */ KOKKOS_INLINE_FUNCTION static void rotate_umat(CUDAREAL * v, CUDAREAL *newv, const CUDAREAL * __restrict__ umat); // measure magnitude of vector and put it in 0th element @@ -201,6 +202,18 @@ KOKKOS_INLINE_FUNCTION CUDAREAL *rotate_axis(const CUDAREAL * v, CUDAREAL * newv return newv; } +/* rotate a point about a unit vector axis */ +KOKKOS_INLINE_FUNCTION vector3 rotate_axis(const vector3& v, vector3& newv, const vector3& axis, const CUDAREAL phi) { + + const CUDAREAL sinphi = sin(phi); + const CUDAREAL cosphi = cos(phi); + const CUDAREAL dot = axis.dot(v) * (1.0 - cosphi); + + newv = axis * dot + v * cosphi + axis.cross(v) * sinphi; + + return newv; +} + /* rotate a vector using a 9-element unitary matrix */ KOKKOS_INLINE_FUNCTION void rotate_umat(CUDAREAL * v, CUDAREAL *newv, const CUDAREAL * __restrict__ umat) { diff --git a/simtbx/kokkos/kokkos_instance.cpp b/simtbx/kokkos/kokkos_instance.cpp index 2624459b8e..d0b467501d 100644 --- a/simtbx/kokkos/kokkos_instance.cpp +++ b/simtbx/kokkos/kokkos_instance.cpp @@ -1,6 +1,6 @@ #include "simtbx/kokkos/kokkos_instance.h" -using Kokkos::InitArguments; +using Kokkos::InitializationSettings; using Kokkos::initialize; using Kokkos::finalize; @@ -15,11 +15,9 @@ namespace Kokkos { } kokkos_instance::kokkos_instance(int const& t_deviceID) { - InitArguments kokkos_init; - kokkos_init.device_id = t_deviceID; - if (!m_isInitialized) { - initialize(kokkos_init); + initialize(InitializationSettings() + .set_device_id(t_deviceID)); m_isInitialized = true; m_isFinalized = false; diff --git a/simtbx/kokkos/simulation.cpp b/simtbx/kokkos/simulation.cpp index dc3d5f9aa4..23f960ff08 100644 --- a/simtbx/kokkos/simulation.cpp +++ b/simtbx/kokkos/simulation.cpp @@ -100,8 +100,6 @@ namespace Kokkos { simtbx::Kokkos::kokkos_detector & kdt, double const& weight ){ - // cudaSafeCall(cudaSetDevice(SIM.device_Id)); - // transfer source_I, source_lambda // the int arguments are for sizes of the arrays int source_count = SIM.sources; @@ -110,18 +108,15 @@ namespace Kokkos { for (std::size_t iwt = 0; iwt < source_count; iwt++){wptr[iwt] = weight*(SIM.source_I[iwt]);} kokkostbx::transfer_double2kokkos(m_source_I, wptr, source_count); kokkostbx::transfer_double2kokkos(m_source_lambda, SIM.source_lambda, source_count); - // cudaSafeCall(cudaMemcpyVectorDoubleToDevice(cu_source_I, SIM.source_I, SIM.sources)); - // cudaSafeCall(cudaMemcpyVectorDoubleToDevice(cu_source_lambda, SIM.source_lambda, SIM.sources)); + + ::Kokkos::resize(m_crystal_orientation, SIM.phisteps, SIM.mosaic_domains, 3); + calc_CrystalOrientations( + SIM.phi0, SIM.phistep, SIM.phisteps, m_spindle_vector, m_a0, m_b0, m_c0, SIM.mosaic_spread, + SIM.mosaic_domains, m_mosaic_umats, m_crystal_orientation); // magic happens here(?): take pointer from singleton, temporarily use it for add Bragg iteration: vector_cudareal_t current_channel_Fhkl = kec.d_channel_Fhkl[ichannel]; - // cudaDeviceProp deviceProps = { 0 }; - // cudaSafeCall(cudaGetDeviceProperties(&deviceProps, SIM.device_Id)); - // int smCount = deviceProps.multiProcessorCount; - // dim3 threadsPerBlock(THREADS_PER_BLOCK_X, THREADS_PER_BLOCK_Y); - // dim3 numBlocks(smCount * 8, 1); - std::size_t panel_size = kdt.m_slow_dim_size * kdt.m_fast_dim_size; // the for loop around panels. Offsets given. @@ -132,16 +127,14 @@ namespace Kokkos { SIM.roi_xmax, SIM.roi_ymin, SIM.roi_ymax, SIM.oversample, SIM.point_pixel, SIM.pixel_size, m_subpixel_size, m_steps, SIM.detector_thickstep, SIM.detector_thicksteps, SIM.detector_thick, SIM.detector_attnlen, - extract_subview(kdt.m_sdet_vector, panel_id, m_vector_length), - extract_subview(kdt.m_fdet_vector, panel_id, m_vector_length), - extract_subview(kdt.m_odet_vector, panel_id, m_vector_length), - extract_subview(kdt.m_pix0_vector, panel_id, m_vector_length), + extract_subview(kdt.m_sdet_vector, panel_id, 1), + extract_subview(kdt.m_fdet_vector, panel_id, 1), + extract_subview(kdt.m_odet_vector, panel_id, 1), + extract_subview(kdt.m_pix0_vector, panel_id, 1), SIM.curved_detector, kdt.metrology.dists[panel_id], kdt.metrology.dists[panel_id], m_beam_vector, kdt.metrology.Xbeam[panel_id], kdt.metrology.Ybeam[panel_id], - SIM.dmin, SIM.phi0, SIM.phistep, SIM.phisteps, m_spindle_vector, - SIM.sources, m_source_X, m_source_Y, m_source_Z, - m_source_I, m_source_lambda, m_a0, m_b0, - m_c0, SIM.xtal_shape, SIM.mosaic_spread, SIM.mosaic_domains, m_mosaic_umats, + SIM.dmin, SIM.phisteps, SIM.sources, m_source_X, m_source_Y, m_source_Z, + m_source_I, m_source_lambda, SIM.xtal_shape, SIM.mosaic_domains, m_crystal_orientation, SIM.Na, SIM.Nb, SIM.Nc, SIM.V_cell, m_water_size, m_water_F, m_water_MW, simtbx::nanoBragg::r_e_sqr, SIM.fluence, simtbx::nanoBragg::Avogadro, SIM.spot_scale, SIM.integral_form, SIM.default_F, @@ -380,10 +373,10 @@ namespace Kokkos { SIM.oversample, override_source, SIM.pixel_size, kdt.m_slow_dim_size, kdt.m_fast_dim_size, SIM.detector_thicksteps, SIM.detector_thickstep, SIM.detector_attnlen, - extract_subview(kdt.m_sdet_vector, panel_id, m_vector_length), - extract_subview(kdt.m_fdet_vector, panel_id, m_vector_length), - extract_subview(kdt.m_odet_vector, panel_id, m_vector_length), - extract_subview(kdt.m_pix0_vector, panel_id, m_vector_length), + extract_subview(kdt.m_sdet_vector, panel_id, 1), + extract_subview(kdt.m_fdet_vector, panel_id, 1), + extract_subview(kdt.m_odet_vector, panel_id, 1), + extract_subview(kdt.m_pix0_vector, panel_id, 1), kdt.metrology.dists[panel_id], SIM.point_pixel, SIM.detector_thick, m_source_X, m_source_Y, m_source_Z, m_source_lambda, m_source_I, diff --git a/simtbx/kokkos/simulation.h b/simtbx/kokkos/simulation.h index 23f8cc0ddb..f1fc1c68ca 100644 --- a/simtbx/kokkos/simulation.h +++ b/simtbx/kokkos/simulation.h @@ -7,6 +7,12 @@ #include "simtbx/kokkos/structure_factors.h" #include "simtbx/kokkos/detector.h" #include "kokkostbx/kokkos_types.h" +#include "kokkostbx/kokkos_vector3.h" +#include "kokkostbx/kokkos_matrix3.h" + +using vec3 = kokkostbx::vector3; +using mat3 = kokkostbx::matrix3; +using crystal_orientation_t = Kokkos::View; // [phisteps, domains, 3] namespace simtbx { namespace Kokkos { @@ -62,6 +68,7 @@ struct exascale_api { vector_cudareal_t m_source_I = vector_cudareal_t("m_source_I", 0); vector_cudareal_t m_source_lambda = vector_cudareal_t("m_source_lambda", 0); vector_cudareal_t m_mosaic_umats = vector_cudareal_t("m_mosaic_umats", 0); + crystal_orientation_t m_crystal_orientation = crystal_orientation_t("m_crystal_orientation", 0, 0, 3); CUDAREAL m_water_size = 0; CUDAREAL m_water_F = 0; CUDAREAL m_water_MW = 0; diff --git a/simtbx/kokkos/simulation_kernels.h b/simtbx/kokkos/simulation_kernels.h index 84c4152423..eb368a95db 100644 --- a/simtbx/kokkos/simulation_kernels.h +++ b/simtbx/kokkos/simulation_kernels.h @@ -16,25 +16,72 @@ using simtbx::nanoBragg::GAUSS; using simtbx::nanoBragg::GAUSS_ARGCHK; using simtbx::nanoBragg::TOPHAT; +void calc_CrystalOrientations(CUDAREAL phi0, + CUDAREAL phistep, + int phisteps, + const vector_cudareal_t spindle_vector, + const vector_cudareal_t a0, + const vector_cudareal_t b0, + const vector_cudareal_t c0, + CUDAREAL mosaic_spread, + int mosaic_domains, + const vector_cudareal_t mosaic_umats, + crystal_orientation_t crystal_orientation) { + + Kokkos::parallel_for("calc_CrystalOrientation", phisteps, KOKKOS_LAMBDA(const int& phi_tic) { + // sweep over phi angles + CUDAREAL phi = phistep * phi_tic + phi0; + + vec3 spindle_vector_tmp {spindle_vector(1), spindle_vector(2), spindle_vector(3)}; + vec3 a0_tmp {a0(1), a0(2), a0(3)}; + vec3 b0_tmp {b0(1), b0(2), b0(3)}; + vec3 c0_tmp {c0(1), c0(2), c0(3)}; + + // rotate about spindle if necessary + vec3 ap = a0_tmp.rotate_around_axis(spindle_vector_tmp, phi); + vec3 bp = b0_tmp.rotate_around_axis(spindle_vector_tmp, phi); + vec3 cp = c0_tmp.rotate_around_axis(spindle_vector_tmp, phi); + + // enumerate mosaic domains + for (int mos_tic = 0; mos_tic < mosaic_domains; ++mos_tic) { + // apply mosaic rotation after phi rotation + vec3 a, b, c; + + if (mosaic_spread > 0.0) { + mat3 umat; + for (int i=0; i<9; ++i) { + umat[i] = mosaic_umats(mos_tic * 9 + i); + } + a = umat.dot(ap); + b = umat.dot(bp); + c = umat.dot(cp); + } else { + a = ap; + b = bp; + c = cp; + } + crystal_orientation(phi_tic, mos_tic, 0) = a; + crystal_orientation(phi_tic, mos_tic, 1) = b; + crystal_orientation(phi_tic, mos_tic, 2) = c; + } + }); +} + void kokkosSpotsKernel(int spixels, int fpixels, int roi_xmin, int roi_xmax, int roi_ymin, int roi_ymax, int oversample, int point_pixel, CUDAREAL pixel_size, CUDAREAL subpixel_size, int steps, CUDAREAL detector_thickstep, int detector_thicksteps, CUDAREAL detector_thick, CUDAREAL detector_mu, - const vector_cudareal_t sdet_vector, const vector_cudareal_t fdet_vector, - const vector_cudareal_t odet_vector, const vector_cudareal_t pix0_vector, + const view_1d_t sdet_vector, const view_1d_t fdet_vector, + const view_1d_t odet_vector, const view_1d_t pix0_vector, int curved_detector, CUDAREAL distance, CUDAREAL close_distance, const vector_cudareal_t beam_vector, - CUDAREAL Xbeam, CUDAREAL Ybeam, CUDAREAL dmin, CUDAREAL phi0, CUDAREAL phistep, - int phisteps, const vector_cudareal_t spindle_vector, int sources, + CUDAREAL Xbeam, CUDAREAL Ybeam, CUDAREAL dmin, int phisteps, int sources, const vector_cudareal_t source_X, const vector_cudareal_t source_Y, const vector_cudareal_t source_Z, const vector_cudareal_t source_I, const vector_cudareal_t source_lambda, - const vector_cudareal_t a0, const vector_cudareal_t b0, - const vector_cudareal_t c0, shapetype xtal_shape, CUDAREAL mosaic_spread, - int mosaic_domains, const vector_cudareal_t mosaic_umats, - CUDAREAL Na, CUDAREAL Nb, - CUDAREAL Nc, CUDAREAL V_cell, + shapetype xtal_shape, int mosaic_domains, crystal_orientation_t crystal_orientation, + CUDAREAL Na, CUDAREAL Nb, CUDAREAL Nc, CUDAREAL V_cell, CUDAREAL water_size, CUDAREAL water_F, CUDAREAL water_MW, CUDAREAL r_e_sqr, CUDAREAL fluence, CUDAREAL Avogadro, CUDAREAL spot_scale, int integral_form, CUDAREAL default_F, @@ -57,23 +104,17 @@ void kokkosSpotsKernel(int spixels, int fpixels, int roi_xmin, int roi_xmax, const int total_pixels = spixels * fpixels; - // add background from something amorphous - CUDAREAL F_bg = water_F; - CUDAREAL I_bg = F_bg * F_bg * r_e_sqr * fluence * water_size * water_size * water_size * 1e6 * Avogadro / water_MW; + const CUDAREAL distance_r = 1 / distance; + const CUDAREAL dmin_r = (dmin > 0.0) ? 1/dmin : 0.0; - Kokkos::parallel_for("kokkosSpotsKernel", total_pixels, KOKKOS_LAMBDA(const int& pixIdx) { + // add background from something amorphous, precalculate scaling + const CUDAREAL F_bg = water_F; + const CUDAREAL I_bg = F_bg * F_bg * r_e_sqr * fluence * water_size * water_size * water_size * 1e6 * Avogadro / water_MW; + const CUDAREAL I_factor = r_e_sqr * spot_scale * fluence / steps; - vec3 sdet_tmp {sdet_vector(1), sdet_vector(2), sdet_vector(3)}; - vec3 fdet_tmp {fdet_vector(1), fdet_vector(2), fdet_vector(3)}; - vec3 odet_tmp {odet_vector(1), odet_vector(2), odet_vector(3)}; - vec3 pix0_tmp {pix0_vector(1), pix0_vector(2), pix0_vector(3)}; + Kokkos::parallel_for("kokkosSpotsKernel", total_pixels, KOKKOS_LAMBDA(const int& pixIdx) { vec3 beam_vector_tmp {beam_vector(1), beam_vector(2), beam_vector(3)}; - vec3 spindle_vector_tmp {spindle_vector(1), spindle_vector(2), spindle_vector(3)}; - - vec3 a0_tmp {a0(1), a0(2), a0(3)}; - vec3 b0_tmp {b0(1), b0(2), b0(3)}; - vec3 c0_tmp {c0(1), c0(2), c0(3)}; vec3 polar_vector_tmp {polar_vector(1), polar_vector(2), polar_vector(3)}; @@ -127,38 +168,35 @@ void kokkosSpotsKernel(int spixels, int fpixels, int roi_xmin, int roi_xmax, // pixel_Y = Sdet-Ybeam; // pixel_Z = Fdet-Xbeam; vec3 pixel_pos; - pixel_pos += Fdet * fdet_tmp; - pixel_pos += Sdet * sdet_tmp; - pixel_pos += Odet * odet_tmp; - pixel_pos += pix0_tmp; - - CUDAREAL pixel_pos_tmp[] = {0, pixel_pos[0], pixel_pos[1], pixel_pos[2]}; + pixel_pos += Fdet * fdet_vector(0); + pixel_pos += Sdet * sdet_vector(0); + pixel_pos += Odet * odet_vector(0); + pixel_pos += pix0_vector(0); if (curved_detector) { // construct detector pixel that is always "distance" from the sample vec3 dbvector = distance * vec3{beam_vector(1), beam_vector(2), beam_vector(3)}; // treat detector pixel coordinates as radians - vec3 newvector = dbvector.rotate_around_axis(sdet_tmp, pixel_pos.y_val() / distance ); - pixel_pos = newvector.rotate_around_axis(fdet_tmp, pixel_pos.z_val() / distance ); + vec3 newvector = dbvector.rotate_around_axis(sdet_vector(0), pixel_pos.y_val() * distance_r ); + pixel_pos = newvector.rotate_around_axis(fdet_vector(0), pixel_pos.z_val() * distance_r ); } // construct the diffracted-beam unit vector to this sub-pixel - CUDAREAL airpath = pixel_pos.length(); + CUDAREAL airpath_r = 1 / pixel_pos.length(); vec3 diffracted = pixel_pos.get_unit_vector(); // solid angle subtended by a pixel: (pix/airpath)^2*cos(2theta) - CUDAREAL omega_pixel = pixel_size * pixel_size / airpath / airpath * close_distance / airpath; + CUDAREAL omega_pixel = pixel_size * pixel_size * airpath_r * airpath_r * close_distance * airpath_r; // option to turn off obliquity effect, inverse-square-law only if (point_pixel) { - omega_pixel = 1.0 / airpath / airpath; + omega_pixel = airpath_r * airpath_r; } // now calculate detector thickness effects CUDAREAL capture_fraction = 1.0; if (detector_thick > 0.0 && detector_mu> 0.0) { // inverse of effective thickness increase - vec3 odet{odet_vector(1), odet_vector(2), odet_vector(3)}; - CUDAREAL parallax = odet.dot(diffracted); + CUDAREAL parallax = odet_vector(0).dot(diffracted); capture_fraction = exp(-thick_tic * detector_thickstep / detector_mu / parallax) - exp(-(thick_tic + 1) * detector_thickstep / detector_mu / parallax); } @@ -182,7 +220,8 @@ void kokkosSpotsKernel(int spixels, int fpixels, int roi_xmin, int roi_xmax, // rough cut to speed things up when we aren't using whole detector if (dmin > 0.0 && stol > 0.0) { - if (dmin > 0.5 / stol) { + // use reciprocal of (dmin > 0.5 / stol) + if (dmin_r <= 2 * stol) { continue; } } @@ -197,34 +236,12 @@ void kokkosSpotsKernel(int spixels, int fpixels, int roi_xmin, int roi_xmax, // sweep over phi angles for (int phi_tic = 0; phi_tic < phisteps; ++phi_tic) { - CUDAREAL phi = phistep * phi_tic + phi0; - - // rotate about spindle if necessary - vec3 ap = a0_tmp.rotate_around_axis(spindle_vector_tmp, phi); - vec3 bp = b0_tmp.rotate_around_axis(spindle_vector_tmp, phi); - vec3 cp = c0_tmp.rotate_around_axis(spindle_vector_tmp, phi); - // enumerate mosaic domains for (int mos_tic = 0; mos_tic < mosaic_domains; ++mos_tic) { // apply mosaic rotation after phi rotation - // CUDAREAL a[4]; - // CUDAREAL b[4]; - // CUDAREAL c[4]; - vec3 a, b, c; - - if (mosaic_spread > 0.0) { - mat3 umat; - for (int i=0; i<9; ++i) { - umat[i] = mosaic_umats(mos_tic * 9 + i); - } - a = umat.dot(ap); - b = umat.dot(bp); - c = umat.dot(cp); - } else { - a = ap; - b = bp; - c = cp; - } + auto a = crystal_orientation(phi_tic, mos_tic, 0); + auto b = crystal_orientation(phi_tic, mos_tic, 1); + auto c = crystal_orientation(phi_tic, mos_tic, 2); // construct fractional Miller indicies CUDAREAL h = a.dot(scattering); @@ -257,7 +274,10 @@ void kokkosSpotsKernel(int spixels, int fpixels, int roi_xmin, int roi_xmax, } } else { // handy radius in reciprocal space, squared - hrad_sqr = (h - h0) * (h - h0) * Na * Na + (k - k0) * (k - k0) * Nb * Nb + (l - l0) * (l - l0) * Nc * Nc; + const CUDAREAL hrad = (h - h0) * Na; + const CUDAREAL krad = (k - k0) * Nb; + const CUDAREAL lrad = (l - l0) * Nc; + hrad_sqr = hrad * hrad + krad * krad + lrad * lrad; } if (xtal_shape == ROUND) { // use sinc3 for elliptical xtal shape, @@ -304,19 +324,13 @@ void kokkosSpotsKernel(int spixels, int fpixels, int roi_xmin, int roi_xmax, // convert amplitudes into intensity (photons per steradian) I += F_cell * F_cell * F_latt * F_latt * source_fraction * capture_fraction * omega_pixel; omega_sub_reduction += omega_pixel; - } - // end of mosaic loop - } - // end of phi loop - } - // end of source loop - } - // end of detector thickness loop - } - // end of sub-pixel y loop - } - // end of sub-pixel x loop - const double photons = I_bg + (r_e_sqr * spot_scale * fluence * polar * I) / steps; + } // end of mosaic loop + } // end of phi loop + } // end of source loop + } // end of detector thickness loop + } // end of sub-pixel y loop + } // end of sub-pixel x loop + const double photons = I_bg + I_factor * polar * I; floatimage( pixIdx ) = photons; omega_reduction( pixIdx ) = omega_sub_reduction; // shared contention max_I_x_reduction( pixIdx ) = max_I_x_sub_reduction; @@ -330,8 +344,8 @@ void debranch_maskall_Kernel(int npanels, int spixels, int fpixels, int total_pi CUDAREAL pixel_size, CUDAREAL subpixel_size, int steps, CUDAREAL detector_thickstep, int detector_thicksteps, CUDAREAL detector_thick, CUDAREAL detector_mu, const int vec_len, - const vector_cudareal_t sdet_vector, const vector_cudareal_t fdet_vector, - const vector_cudareal_t odet_vector, const vector_cudareal_t pix0_vector, + const view_1d_t sdet_vector, const view_1d_t fdet_vector, + const view_1d_t odet_vector, const view_1d_t pix0_vector, const vector_cudareal_t distance, const vector_cudareal_t close_distance, const vector_cudareal_t beam_vector, const vector_cudareal_t Xbeam, const vector_cudareal_t Ybeam, // not even used, after all the work @@ -419,19 +433,18 @@ void debranch_maskall_Kernel(int npanels, int spixels, int fpixels, int total_pi // pixel_Z = Fdet-Xbeam; //CUDAREAL * pixel_pos = tmpVector1; CUDAREAL pixel_pos[4]; - int iVL = vec_len * i_panel; - pixel_pos[1] = Fdet * fdet_vector(iVL+1) - + Sdet * sdet_vector(iVL+1) - + Odet * odet_vector(iVL+1) - + pix0_vector(iVL+1); // X - pixel_pos[2] = Fdet * fdet_vector(iVL+2) - + Sdet * sdet_vector(iVL+2) - + Odet * odet_vector(iVL+2) - + pix0_vector(iVL+2); // Y - pixel_pos[3] = Fdet * fdet_vector(iVL+3) - + Sdet * sdet_vector(iVL+3) - + Odet * odet_vector(iVL+3) - + pix0_vector(iVL+3); // Z + pixel_pos[1] = Fdet * fdet_vector(i_panel)[0] + + Sdet * sdet_vector(i_panel)[0] + + Odet * odet_vector(i_panel)[0] + + pix0_vector(i_panel)[0]; // X + pixel_pos[2] = Fdet * fdet_vector(i_panel)[1] + + Sdet * sdet_vector(i_panel)[1] + + Odet * odet_vector(i_panel)[1] + + pix0_vector(i_panel)[1]; // Y + pixel_pos[3] = Fdet * fdet_vector(i_panel)[2] + + Sdet * sdet_vector(i_panel)[2] + + Odet * odet_vector(i_panel)[2] + + pix0_vector(i_panel)[2]; // Z // construct the diffracted-beam unit vector to this sub-pixel //CUDAREAL * diffracted = tmpVector2; @@ -450,9 +463,9 @@ void debranch_maskall_Kernel(int npanels, int spixels, int fpixels, int total_pi if (detector_thick > 0.0 && detector_mu> 0.0) { // inverse of effective thickness increase CUDAREAL odet[4]; - odet[1] = odet_vector(iVL+1); - odet[2] = odet_vector(iVL+2); - odet[3] = odet_vector(iVL+3); + odet[1] = odet_vector(i_panel)[0]; + odet[2] = odet_vector(i_panel)[1]; + odet[3] = odet_vector(i_panel)[2]; CUDAREAL parallax = dot_product(odet, diffracted); capture_fraction = exp(-thick_tic * detector_thickstep / detector_mu / parallax) - exp(-(thick_tic + 1) * detector_thickstep / detector_mu / parallax); @@ -615,8 +628,8 @@ void add_array( view_1d_t lhs, const view_1d_t rhs ) { void add_background_kokkos_kernel(int sources, int nanoBragg_oversample, int override_source, CUDAREAL pixel_size, int spixels, int fpixels, int detector_thicksteps, CUDAREAL detector_thickstep, CUDAREAL detector_attnlen, - const vector_cudareal_t sdet_vector, const vector_cudareal_t fdet_vector, - const vector_cudareal_t odet_vector, const vector_cudareal_t pix0_vector, + const view_1d_t sdet_vector, const view_1d_t fdet_vector, + const view_1d_t odet_vector, const view_1d_t pix0_vector, CUDAREAL close_distance, int point_pixel, CUDAREAL detector_thick, const vector_cudareal_t source_X, const vector_cudareal_t source_Y, const vector_cudareal_t source_Z, @@ -653,11 +666,6 @@ void add_background_kokkos_kernel(int sources, int nanoBragg_oversample, int ove // const int stride = fstride * sstride; Kokkos::parallel_for("add_background", total_pixels, KOKKOS_LAMBDA(const int& pixIdx) { - vec3 sdet_tmp {sdet_vector(1), sdet_vector(2), sdet_vector(3)}; - vec3 fdet_tmp {fdet_vector(1), fdet_vector(2), fdet_vector(3)}; - vec3 odet_tmp {odet_vector(1), odet_vector(2), odet_vector(3)}; - vec3 pix0_tmp {pix0_vector(1), pix0_vector(2), pix0_vector(3)}; - vec3 polar_vector_tmp {polar_vector(1), polar_vector(2), polar_vector(3)}; const int fpixel = pixIdx % fpixels; @@ -675,19 +683,11 @@ void add_background_kokkos_kernel(int sources, int nanoBragg_oversample, int ove for(int thick_tic=0; thick_tic 0.0){ // inverse of effective thickness increase // CUDAREAL parallax = diffracted[1] * odet_vector(1) + diffracted[2] * odet_vector(2) + diffracted[3] * odet_vector(3); - CUDAREAL parallax = diffracted.dot(odet_tmp); + CUDAREAL parallax = diffracted.dot(odet_vector(0)); capture_fraction = exp(-thick_tic*detector_thickstep/detector_attnlen/parallax) -exp(-(thick_tic+1)*detector_thickstep/detector_attnlen/parallax); } @@ -710,26 +710,15 @@ void add_background_kokkos_kernel(int sources, int nanoBragg_oversample, int ove for(int source=source_start; source 0 : value of the multiplicative factor + intfile_scale = 1 (default): do not apply a factor + intfile_scale = 0 : compute a reasonable scale factor to set max pixel to 55000; given by get_intfile_scale() + cbf_int: boolean flag, write the cbf using 32-bit int precision + """ + temp = self.cbf_int + self.cbf_int = cbf_int + + if intfile_scale != 1.0: + cache_pixels = self.raw_pixels + if intfile_scale > 0: self.raw_pixels = self.raw_pixels * intfile_scale + else: self.raw_pixels = self.raw_pixels * self.get_intfile_scale() + # print("switch to scaled") + + if toggle_conventions: + # switch to DIALS convention before writing CBF + CURRENT_CONV = self.beamcenter_convention + self.beamcenter_convention=DIALS + + imgset = self.imageset + writer = cbf_writer.FullCBFWriter(imageset=imgset) + cbf = writer.get_cbf_handle(index=0, header_only=True) + data = imgset.get_raw_data(0) + writer.add_data_to_cbf(cbf, data=data) + writer.write_cbf(cbf_filename, cbf=cbf) + + if toggle_conventions: + self.beamcenter_convention=CURRENT_CONV + + if intfile_scale != 1.0: + self.raw_pixels = cache_pixels + # print("switch back to cached") + + self.cbf_int = temp + + def to_nexus_nxmx(self, nxmx_filename, toggle_conventions=False, intfile_scale=1.0): + """write a NeXus NXmx-format image file to disk from the raw pixel array intfile_scale: multiplicative factor applied to raw pixels before output intfile_scale > 0 : value of the multiplicative factor intfile_scale = 1 (default): do not apply a factor @@ -285,8 +354,18 @@ def to_cbf(self, cbf_filename, toggle_conventions=False, intfile_scale=1.0): CURRENT_CONV = self.beamcenter_convention self.beamcenter_convention=DIALS - writer = cbf_writer.FullCBFWriter(imageset=self.imageset) - writer.write_cbf(cbf_filename, index=0) + params = nxmx_writer.phil_scope.fetch(parse(""" + output_file=%s + nexus_details { + instrument_name=nanoBragg + source_name=nanoBragg + start_time=NA + end_time_estimated=NA + sample_name=nanoBragg + } + """%nxmx_filename)).extract() + writer = nxmx_writer.NXmxWriter(params) + writer(imageset=self.imageset) if toggle_conventions: self.beamcenter_convention=CURRENT_CONV @@ -295,6 +374,22 @@ def to_cbf(self, cbf_filename, toggle_conventions=False, intfile_scale=1.0): self.raw_pixels = cache_pixels # print("switch back to cached") +def nexus_factory(nxmx_filename): + params = nxmx_writer.phil_scope.fetch(parse(""" + output_file=%s + nexus_details { + instrument_name=nanoBragg + source_name=nanoBragg + start_time=NA + end_time_estimated=NA + sample_name=nanoBragg + } + dtype=int32 + """%nxmx_filename)).extract() + writer = nxmx_writer.NXmxWriter(params) + return writer + + def make_imageset(data, beam, detector): format_class = FormatBraggInMemoryMultiPanel(data) reader = MemReaderNamedPath("virtual_Bragg_path", [format_class]) @@ -332,7 +427,7 @@ def get_mask(self, goniometer=None): """dummie place holder for mask, consider using internal nanoBragg mask""" return self.mask -class FormatBraggInMemory: +class FormatBraggInMemory(Format): def __init__(self, raw_pixels): self.raw_pixels = raw_pixels @@ -358,6 +453,10 @@ def get_mask(self, goniometer=None): """dummie place holder for mask, consider using internal nanoBragg mask""" return self.mask, + @classmethod + def get_instance(Class, filename, **kwargs): + return Class(raw_pixels = kwargs.pop('raw_pixels'), **kwargs) + #def paths(self): # return ["InMemoryBraggPath"] # TODO: CBFLib complains if no datablock path provided which comes from path diff --git a/simtbx/nanoBragg/anisotropic_mosaicity.py b/simtbx/nanoBragg/anisotropic_mosaicity.py index edf3d20643..3934117b47 100644 --- a/simtbx/nanoBragg/anisotropic_mosaicity.py +++ b/simtbx/nanoBragg/anisotropic_mosaicity.py @@ -72,8 +72,8 @@ def _compute(rot_ax, ang_idx, eta_eff, Cvec, derivs=None, second_derivs=None): dU_d_theta = rot_ax.axis_and_angle_as_r3_derivative_wrt_angle(rot_sign*rot_ang, deg=False) # 1st deriv d2U_d_theta2 = rot_ax.axis_and_angle_as_r3_derivative_wrt_angle(rot_sign*rot_ang, deg=False, second_order=True) # second deriv for d, d2 in zip(d_theta_d_eta, dsquared_theta_d_eta_squared): - dU_d_eta = rot_sign*dU_d_theta*d - d2U_d_eta2 = d2U_d_theta2*(d**2) + dU_d_theta*d2 + dU_d_eta = dU_d_theta*(rot_sign*d) + d2U_d_eta2 = d2U_d_theta2*(d**2) + dU_d_theta*(rot_sign*d2) Uprimes.append(dU_d_eta) Udblprimes.append(d2U_d_eta2) diff --git a/simtbx/nanoBragg/nanoBragg.cpp b/simtbx/nanoBragg/nanoBragg.cpp index 2c4948c4d9..14ba8b26b8 100644 --- a/simtbx/nanoBragg/nanoBragg.cpp +++ b/simtbx/nanoBragg/nanoBragg.cpp @@ -216,6 +216,9 @@ nanoBragg::init_defaults() exit(9); }; + /* write cbf files in int precision? */ + cbf_int = false; + /* optional file stuff, to be removed eventually? */ matfilename = NULL; hklfilename = NULL; diff --git a/simtbx/nanoBragg/nanoBragg.h b/simtbx/nanoBragg/nanoBragg.h index 00963071c5..bd1c1a5cc6 100644 --- a/simtbx/nanoBragg/nanoBragg.h +++ b/simtbx/nanoBragg/nanoBragg.h @@ -366,6 +366,7 @@ class nanoBragg { af::flex_double raw_pixels; unsigned short int *intimage; unsigned char *pgmimage; + bool cbf_int; // if saving the cbf file raw pixels will be converted to int // char *byte_order; // = get_byte_order(); /* optional input image to extract background? */ // SMVinfo imginfile; diff --git a/simtbx/nanoBragg/nanoBragg_ext.cpp b/simtbx/nanoBragg/nanoBragg_ext.cpp index 197170d696..269c11634f 100644 --- a/simtbx/nanoBragg/nanoBragg_ext.cpp +++ b/simtbx/nanoBragg/nanoBragg_ext.cpp @@ -1915,6 +1915,11 @@ printf("DEBUG: pythony_stolFbg[1]=(%g,%g)\n",nanoBragg.pythony_stolFbg[1][0],nan make_setter(&nanoBragg::raw_pixels,dcp()), "2D flex array representing floating-point pixel values, this is expected photons before you call add_noise(), which converts it into detector pixel values, or ADU") + .add_property("cbf_int", + make_getter(&nanoBragg::cbf_int,rbv()), + make_setter(&nanoBragg::cbf_int,dcp()), + "Write the cbf file using to_cbf with int32 precision") + /* print to screen a summary of all initialized parameters */ .def("show_params",&nanoBragg::show_params, "print out all simulation parameters, just like the standalone program") diff --git a/simtbx/nanoBragg/sim_data.py b/simtbx/nanoBragg/sim_data.py index ac7d5cc56b..f40c2581da 100644 --- a/simtbx/nanoBragg/sim_data.py +++ b/simtbx/nanoBragg/sim_data.py @@ -360,6 +360,8 @@ def get_detector_corner_res(self): def update_Fhkl_tuple(self): if self.crystal.miller_array is not None: + if np.all(self.crystal.miller_array.data().as_numpy_array()==0): + raise ValueError("Seems all miller indices are 0") d_max, _ = self.crystal.miller_array.resolution_range() d_min = self.get_detector_corner_res() ma_on_detector = self.crystal.miller_array.resolution_filter(d_min=d_min, d_max=d_max) @@ -470,8 +472,12 @@ def _init_diffBragg_umats(self): if self.crystal.anisotropic_mos_spread_deg is not None: if tuple(self.crystal.anisotropic_mos_spread_deg) == (0,0,0) and self.crystal.n_mos_domains != 1: raise ValueError("If more than 1 mosaic domain are passed, must set a positive value for anisotropic_mos_spread") - self.D.has_anisotropic_mosaic_spread = True - mosaicity = self.crystal.anisotropic_mos_spread_deg + if len(set(self.crystal.anisotropic_mos_spread_deg))==1: + self.D.has_anisotropic_mosaic_spread = False + mosaicity = self.crystal.anisotropic_mos_spread_deg[0] + else: + self.D.has_anisotropic_mosaic_spread = True + mosaicity = self.crystal.anisotropic_mos_spread_deg else: self.D.has_anisotropic_mosaic_spread = False mosaicity = self.crystal.mos_spread_deg diff --git a/simtbx/nanoBragg/tst_gauss_argchk.py b/simtbx/nanoBragg/tst_gauss_argchk.py index 87368ac24f..91ba3043ff 100644 --- a/simtbx/nanoBragg/tst_gauss_argchk.py +++ b/simtbx/nanoBragg/tst_gauss_argchk.py @@ -231,6 +231,7 @@ def simple_monochromatic_case(bragg_engine, BEAM, DETECTOR, CRYSTAL, SF_model, a SIM.to_smv_format(fileout="test_full_001.img", intfile_scale=output_scale) assert approx_equal(SIM.raw_pixels, SIM2.raw_pixels) SIM.to_cbf("test_full_001.cbf", intfile_scale=output_scale) + SIM.to_nexus_nxmx("test_full_001.h5", intfile_scale=output_scale) if runmode=="GPU": bragg_engine = nanoBragg.add_nanoBragg_spots_cuda diff --git a/simtbx/run_tests.py b/simtbx/run_tests.py index e333d6ca87..7add96ae7c 100644 --- a/simtbx/run_tests.py +++ b/simtbx/run_tests.py @@ -33,6 +33,7 @@ ["$D/diffBragg/tests/tst_diffBragg_ncells_property_anisotropic.py", "--idx 1"], ["$D/diffBragg/tests/tst_diffBragg_ncells_property_anisotropic.py", "--idx 2"], ["$D/diffBragg/tests/tst_diffBragg_unitcell_property.py", "--crystalsystem tetragonal" ], + ["$D/diffBragg/tests/tst_diffBragg_unitcell_property.py", "--crystalsystem hexagonal" ], ["$D/diffBragg/tests/tst_diffBragg_unitcell_property.py", "--crystalsystem monoclinic" ], ["$D/diffBragg/tests/tst_diffBragg_lambda_coefficients.py", "--idx 0"], ["$D/diffBragg/tests/tst_diffBragg_lambda_coefficients.py", "--idx 1"], diff --git a/xfel/merging/application/errors/error_modifier_ev11.py b/xfel/merging/application/errors/error_modifier_ev11.py index 004c9539d8..cf72dbb1c6 100644 --- a/xfel/merging/application/errors/error_modifier_ev11.py +++ b/xfel/merging/application/errors/error_modifier_ev11.py @@ -325,7 +325,7 @@ def calculate_initial_ev11_parameters(self): # Calculate initial EV11 parameters self.sfac = 1/slope self.sadd = offset - self.sb = math.sqrt(self.sadd) + self.sb = math.sqrt(self.sadd) if self.sadd > 0 else 0 ''' if True: From 281d0bae2847f4fedeee25a55832bce383e89afb Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 9 Jan 2024 09:57:53 -0800 Subject: [PATCH 006/748] Take expected failures from outside (phenix_regression). --- libtbx/command_line/run_tests_parallel.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libtbx/command_line/run_tests_parallel.py b/libtbx/command_line/run_tests_parallel.py index bbf16551eb..1d32a0779e 100755 --- a/libtbx/command_line/run_tests_parallel.py +++ b/libtbx/command_line/run_tests_parallel.py @@ -44,7 +44,8 @@ def run(args, python_keyword_text="", max_tests=None, start_test=None, - tests_to_skip=None): + tests_to_skip=None, + expected_failures_from_phenix_regression=[]): if (len(args) == 0): raise Usage("""libtbx.run_tests_parallel [module=NAME] [directory=path]""") @@ -111,6 +112,12 @@ def run(args, expected_unstable_list.extend(unstable_tests) parallel_list.extend(parallel_tests) + # add expected failures from phenix regression + for ef in expected_failures_from_phenix_regression: + for t in all_tests: + if t.find(ef) > -1: + expected_failure_list.append(t) + # remove any specified tests: if tests_to_skip: new_tests=[] From c4574522a352d2d414c4de09b3231d30a395f1b9 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 9 Jan 2024 12:19:28 -0800 Subject: [PATCH 007/748] Better ADP weight selection for low-res --- mmtbx/refinement/adp_refinement.py | 47 +++++++++++++++++------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/mmtbx/refinement/adp_refinement.py b/mmtbx/refinement/adp_refinement.py index 692b43f24d..eb01a152a9 100644 --- a/mmtbx/refinement/adp_refinement.py +++ b/mmtbx/refinement/adp_refinement.py @@ -273,26 +273,32 @@ def __init__( (not all_params.target_weights.force_optimize_weights)) : optimize_adp_weight = False # initialize with defaults... - if(target_weights is not None): - import mmtbx.refinement.weights_params - wcp = mmtbx.refinement.weights_params.tw_customizations_params.extract() - for w_s_c in wcp.weight_selection_criteria: - if(d_min >= w_s_c.d_min and d_min < w_s_c.d_max): - r_free_range_width = w_s_c.r_free_range_width - r_free_r_work_gap = w_s_c.r_free_minus_r_work - mean_diff_b_iso_bonded_fraction = w_s_c.mean_diff_b_iso_bonded_fraction - min_diff_b_iso_bonded = w_s_c.min_diff_b_iso_bonded - break - # ...then customize - wsc = all_params.target_weights.weight_selection_criteria - if(wsc.r_free_minus_r_work is not None): - r_free_r_work_gap = wsc.r_free_minus_r_work - if(wsc.r_free_range_width is not None): - r_free_range_width = wsc.r_free_range_width - if(wsc.mean_diff_b_iso_bonded_fraction is not None): - mean_diff_b_iso_bonded_fraction = wsc.mean_diff_b_iso_bonded_fraction - if(wsc.min_diff_b_iso_bonded is not None): - min_diff_b_iso_bonded = wsc.min_diff_b_iso_bonded + if(self.fmodels.fmodel_xray().f_obs().d_min()<3): # This logic is only good for high_res + if(target_weights is not None): + import mmtbx.refinement.weights_params + wcp = mmtbx.refinement.weights_params.tw_customizations_params.extract() + for w_s_c in wcp.weight_selection_criteria: + if(d_min >= w_s_c.d_min and d_min < w_s_c.d_max): + r_free_range_width = w_s_c.r_free_range_width + r_free_r_work_gap = w_s_c.r_free_minus_r_work + mean_diff_b_iso_bonded_fraction = w_s_c.mean_diff_b_iso_bonded_fraction + min_diff_b_iso_bonded = w_s_c.min_diff_b_iso_bonded + break + # ...then customize + wsc = all_params.target_weights.weight_selection_criteria + if(wsc.r_free_minus_r_work is not None): + r_free_r_work_gap = wsc.r_free_minus_r_work + if(wsc.r_free_range_width is not None): + r_free_range_width = wsc.r_free_range_width + if(wsc.mean_diff_b_iso_bonded_fraction is not None): + mean_diff_b_iso_bonded_fraction = wsc.mean_diff_b_iso_bonded_fraction + if(wsc.min_diff_b_iso_bonded is not None): + min_diff_b_iso_bonded = wsc.min_diff_b_iso_bonded + else: # Worse than 3A: better yet ad hoc criteria. + r_free_r_work_gap = 6 + r_free_range_width = 1.5 + mean_diff_b_iso_bonded_fraction = 0.2 + min_diff_b_iso_bonded = 20 # print_statistics.make_sub_header(text="Individual ADP refinement", out = log) assert fmodels.fmodel_xray().xray_structure is model.get_xray_structure() @@ -319,6 +325,7 @@ def __init__( self.target_weights.adp_weights_result.wx_scale if(optimize_adp_weight): wx_scale = [0.03,0.125,0.5,1.,1.5,2.,2.5,3.,3.5,4.,4.5,5.] + trial_weights = list( flex.double(wx_scale)*self.target_weights.adp_weights_result.wx ) self.wx_scale = 1 else: From 788fbf58074173a57343a57c26e230f2c2d378ad Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 9 Jan 2024 13:15:04 -0800 Subject: [PATCH 008/748] Take external list of unstable tests. --- libtbx/command_line/run_tests_parallel.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libtbx/command_line/run_tests_parallel.py b/libtbx/command_line/run_tests_parallel.py index 1d32a0779e..9ac52df989 100755 --- a/libtbx/command_line/run_tests_parallel.py +++ b/libtbx/command_line/run_tests_parallel.py @@ -45,7 +45,8 @@ def run(args, max_tests=None, start_test=None, tests_to_skip=None, - expected_failures_from_phenix_regression=[]): + expected_failures_from_phenix_regression=[], + unstables_from_phenix_regression = []): if (len(args) == 0): raise Usage("""libtbx.run_tests_parallel [module=NAME] [directory=path]""") @@ -118,6 +119,12 @@ def run(args, if t.find(ef) > -1: expected_failure_list.append(t) + # add unstables from phenix regression + for u in unstables_from_phenix_regression: + for t in all_tests: + if t.find(u) > -1: + expected_unstable_list.append(t) + # remove any specified tests: if tests_to_skip: new_tests=[] From 44ef0d39894f16db44353541f55271c20fef9e48 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 9 Jan 2024 16:59:17 -0800 Subject: [PATCH 009/748] Bug fix: show correct hint to help define labels --- iotbx/extract_xtal_data.py | 7 ++++--- iotbx/reflection_file_utils.py | 7 ++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/iotbx/extract_xtal_data.py b/iotbx/extract_xtal_data.py index 2df31a7659..0ac2e8372c 100644 --- a/iotbx/extract_xtal_data.py +++ b/iotbx/extract_xtal_data.py @@ -289,7 +289,7 @@ def __init__(self, prefer_anomalous = None, force_non_anomalous = False, allow_mismatch_flags = False, - free_r_flags_scope = 'xray_data', + free_r_flags_scope = 'miller_array.labels.name', ): adopt_init_args(self, locals()) # Buffers for error and log messages. @@ -494,7 +494,8 @@ def _extract_data(self): file_name = self.parameters.file_name, labels = self.parameters.labels, ignore_all_zeros = self.parameters.ignore_all_zeros, - parameter_scope = "", + parameter_name = "", + parameter_scope = "miller_array.labels.name", prefer_anomalous = self.prefer_anomalous) self.parameters.file_name = data.info().source self.parameters.labels = [data.info().label_string()] @@ -524,7 +525,7 @@ def _extract_flags(self, data_description = "R-free flags"): if(self.parameters.r_free_flags.generate is not None): if(not self.keep_going): self.err.append(explain_how_to_generate_array_of_r_free_flags( - scope = "%s.r_free_flags.generate" %(self.free_r_flags_scope))) + scope = "xray_data.r_free_flags.generate")) self.err.append("Please try again.") return None r_free_flags, test_flag_value = None, None diff --git a/iotbx/reflection_file_utils.py b/iotbx/reflection_file_utils.py index ebf7fdea8d..7729a92c18 100644 --- a/iotbx/reflection_file_utils.py +++ b/iotbx/reflection_file_utils.py @@ -693,8 +693,13 @@ def get_xray_data(self, new_miller_arrays.append(ma) new_data_scores.append(ds) # + parameter_name = parameter_name.strip() + if(len(parameter_name)==0): + parameter_name_ = parameter_scope + else: + parameter_name_ = parameter_scope+"."+parameter_name i = select_array( - parameter_name=parameter_scope+"."+parameter_name, + parameter_name=parameter_name_, labels=labels, miller_arrays=new_miller_arrays, data_scores=new_data_scores, From ad1a1ff980883c0d8e9f1bf5d4dd82db1c2f5479 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 9 Jan 2024 19:19:23 -0800 Subject: [PATCH 010/748] Fix broken REMAR 3 formatting --- mmtbx/f_model/f_model_info.py | 1 + mmtbx/model/statistics.py | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/mmtbx/f_model/f_model_info.py b/mmtbx/f_model/f_model_info.py index dde99d83b6..5acf9f2183 100644 --- a/mmtbx/f_model/f_model_info.py +++ b/mmtbx/f_model/f_model_info.py @@ -314,6 +314,7 @@ def show_remark_3(self, out = None): print(pr, file=out) print(pr+"STRUCTURE FACTORS CALCULATION ALGORITHM : %-s"%\ self.sf_algorithm.upper(), file=out) + print(pr, file=out) print(pr+"B VALUES.", file=out) print(pr+" FROM WILSON PLOT (A**2) : %s" %\ format_value("%-8.2f", self.wilson_b), file=out) diff --git a/mmtbx/model/statistics.py b/mmtbx/model/statistics.py index 46279fd8ee..1a3631e72d 100644 --- a/mmtbx/model/statistics.py +++ b/mmtbx/model/statistics.py @@ -328,7 +328,7 @@ def fmt2(f1): a,b,c,d,p,n = res.angle, res.bond, res.chirality, res.dihedral, \ res.planarity, res.nonbonded az, bz = res.angle_z, res.bond_z - result = """%s + result = """ %sGeometry Restraints Library: %s %sDeviations from Ideal Values - rmsd, rmsZ for bonds and angles. %s Bond : %s @@ -337,7 +337,7 @@ def fmt2(f1): %s Planarity : %s %s Dihedral : %s %s Min Nonbonded Distance : %s -%s"""%(prefix.strip(), +%s"""%(#prefix.strip(), prefix, self.restraints_source, prefix, @@ -386,11 +386,12 @@ def fmt2(f1): %s"""%prefix result += res.rama_z.as_string(prefix=prefix) # + result+="\n%s"%prefix if p.protein_planes_max_dev: - result += "\n\n%sMax deviation from planes:"%prefix + result += "\n%sMax deviation from planes:"%prefix result += "\n%s Type MaxDev MeanDev LineInFile"%prefix for pp in p.protein_planes_max_dev: - result += "\n %s %s %s %s %s"%( + result += "\n%s %s %s %s %s"%( prefix, format_value("%s", pp.resname), format_value("%7.3f", pp.max_dev), @@ -400,7 +401,7 @@ def fmt2(f1): result += "\n\n%sMax deviation from planes (no H):"%prefix result += "\n%s Type MaxDev MeanDev LineInFile"%prefix for pp in p.protein_planes_max_dev_noH: - result += "\n %s %s %s %s %s"%( + result += "\n%s %s %s %s %s"%( prefix, format_value("%s", pp.resname), format_value("%7.3f", pp.max_dev), @@ -566,6 +567,7 @@ def format_str(v): v.min, v.max, v.mean, rms, v.n_iso, v.n_aniso) r = self.result() pad=" "*14 + print(prefix, "Individual atomic B", file=log) print(prefix, pad, "min max mean iso aniso", file=log) if(r.overall is not None): print(prefix, " Overall: ", format_str(r.overall), file=log) @@ -646,18 +648,16 @@ def show_remark_3(self, out = None): print(prefix+"X-RAY DATA.", file=out) print(prefix, file=out) self.data_x.show_remark_3(out = out) - print(prefix, file=out, end='') if(self.data_n is not None): print(prefix+"NEUTRON DATA.", file=out) print(prefix, file=out) self.data_n.show_remark_3(out = out) print(prefix, file=out, end='') - if(self.geometry is not None): - self.geometry.show(log=out, prefix=prefix) - print(prefix, file=out) if self.adp is not None: self.adp.show(log=out, prefix=prefix) - print(prefix, file=out) + print(prefix, file=out, end='') + if(self.geometry is not None): + self.geometry.show(log=out, prefix=prefix) for info_pdb_str in [self.model.tls_groups_as_pdb(), self.model.anomalous_scatterer_groups_as_pdb(), self.model.cartesian_NCS_as_pdb(), From 60927fc6567d4cfa49b9cc72468a14d13494db29 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 9 Jan 2024 19:27:25 -0800 Subject: [PATCH 011/748] REMARK 3 bug fix: Print actual grid step used (not an UNused step factor!) --- mmtbx/f_model/f_model_info.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mmtbx/f_model/f_model_info.py b/mmtbx/f_model/f_model_info.py index 5acf9f2183..aae49a8b72 100644 --- a/mmtbx/f_model/f_model_info.py +++ b/mmtbx/f_model/f_model_info.py @@ -136,7 +136,7 @@ def __init__(self, matches.n_singles() self.mask_solvent_radius = mp.solvent_radius self.mask_shrink_radius = mp.shrink_truncation_radius - self.mask_grid_step_factor = mp.grid_step_factor + self.mask_grid_step = mp.step self.ml_phase_error = flex.mean(fmodel.phase_errors()) self.ml_coordinate_error = fmodel.model_error_ml() self.d_max, self.d_min = fmodel.f_obs().resolution_range() @@ -299,7 +299,7 @@ def show_remark_3(self, out = None): print(pr+" METHOD USED : FLAT BULK SOLVENT MODEL", file=out) print(pr+" SOLVENT RADIUS : %s"%format_value("%-8.2f", self.mask_solvent_radius), file=out) print(pr+" SHRINKAGE RADIUS : %s"%format_value("%-8.2f", self.mask_shrink_radius), file=out) - print(pr+" GRID STEP FACTOR : %s"%format_value("%-8.2f", self.mask_grid_step_factor), file=out) + print(pr+" GRID STEP : %s"%format_value("%-8.2f", self.mask_grid_step), file=out) print(pr, file=out) if(self.twin_fraction is not None): print(pr+"TWINNING INFORMATION.", file=out) From 37c66983362ec042a91752c200ae4eede607ae28 Mon Sep 17 00:00:00 2001 From: chrissciwilliams Date: Wed, 10 Jan 2024 10:32:02 -0500 Subject: [PATCH 012/748] undowser advice text updates --- mmtbx/validation/undowser.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mmtbx/validation/undowser.py b/mmtbx/validation/undowser.py index 6a5d925783..581656f07a 100644 --- a/mmtbx/validation/undowser.py +++ b/mmtbx/validation/undowser.py @@ -80,11 +80,11 @@ class undowserlyze(validation):

Clash with polar - HOH that clashes with polar groups may actually be a coordinated ion.
-Clash with nonpolar - HOH that clashes with nonpolar groups may be a missing or displaced atom*. +Clash with nonpolar - HOH that clashes with nonpolar groups may be a missing or displaced atom*. Or it may be the first atom of an unmodeled alternate.
Clash with both polar and nonpolar - HOH that clashes with both polar and non-polar groups is unlikely to be an ion. If clashes are severe, a displaced atom is likely. If clashes and map are weak, the HOH may be entirely removable.
-Clash with water - HOH-HOH clashes may be real waters that need to be modeled as alternates of compatible occupancy. Or they may indicate missing or displaced atoms. +Clash with water - HOH-HOH clashes may be real waters that need to be modeled as alternates of compatible occupancy. Or they may be in the density of a sidechain alternate or a larger ligand.
Clash with altloc - HOH clashes involving one or more alternate conformations may be resolved by renaming some of the alternates.

@@ -96,7 +96,7 @@ class undowserlyze(validation):
Missing atoms have been entirely replaced by HOH. Removed atoms may be restored by modeling alternate conformations (especially sidechains), modeling ligands, or continuing a macromolecular mainchain.

-These categories are general suggestions. Check your electron density; trust your intuition and experience. +These categories are general suggestions. Check your electron density; trust your intuition and experience. Prisant 2020 Prot Sci 29:315 (https://doi.org/10.1002/pro.3786) illustrates 10 examples of clashing HOH cases.


From 2f4ceaaff4e071c0be13953dd207b1b6c182e64d Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Wed, 10 Jan 2024 10:49:14 -0800 Subject: [PATCH 013/748] Add missing serialtbx __init__ files Fixes #952 --- serialtbx/__init__.py | 0 serialtbx/detector/legacy_metrology/__init__.py | 0 serialtbx/mono_simulation/__init__.py | 0 serialtbx/util/__init__.py | 0 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 serialtbx/__init__.py create mode 100644 serialtbx/detector/legacy_metrology/__init__.py create mode 100644 serialtbx/mono_simulation/__init__.py create mode 100644 serialtbx/util/__init__.py diff --git a/serialtbx/__init__.py b/serialtbx/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/serialtbx/detector/legacy_metrology/__init__.py b/serialtbx/detector/legacy_metrology/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/serialtbx/mono_simulation/__init__.py b/serialtbx/mono_simulation/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/serialtbx/util/__init__.py b/serialtbx/util/__init__.py new file mode 100644 index 0000000000..e69de29bb2 From b959a753e132d10fed0f0e4c6d447c63d38862fa Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 11 Jan 2024 09:14:24 -0800 Subject: [PATCH 014/748] updated the parent and AA types --- iotbx/pdb/modified_aa_names.h | 16 ++++++++++++++-- iotbx/pdb/modified_aa_names.py | 15 +++++++++++++-- iotbx/pdb/modified_rna_dna_names.h | 10 +++++++++- iotbx/pdb/modified_rna_dna_names.py | 10 +++++++++- 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/iotbx/pdb/modified_aa_names.h b/iotbx/pdb/modified_aa_names.h index 4aa7e004c9..b60c99a137 100644 --- a/iotbx/pdb/modified_aa_names.h +++ b/iotbx/pdb/modified_aa_names.h @@ -5,7 +5,7 @@ This file is generated by the following procedure: phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Wed Sep 27 09:55:15 2023 +The date of file generation: Thu Jan 11 09:02:01 2024 */ #include @@ -632,7 +632,6 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "ERL", "EYS", "F0G", - "F2Y", "F3G", "F3M", "F3T", @@ -650,6 +649,9 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "FPR", "FRD", "FTO", + "FXC", + "FXF", + "FXL", "FYI", "FYQ", "G85", @@ -964,6 +966,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "THO", "TIF", "TIG", + "TJI", "TKL", "TPH", "TPN", @@ -1012,6 +1015,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "VLT", "VME", "VMS", + "VNW", "VOL", "VPF", "VSC", @@ -1024,6 +1028,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "X5H", "X6E", "X9A", + "XC0", "XCP", "XDD", "XDJ", @@ -1116,6 +1121,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "FB5", "FB6", "FLA", + "H7V", "HAC", "HIX", "HQA", @@ -1382,6 +1388,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "TNB", "TQZ", "TSY", + "UJR", "V44", "VI3", "XCN", @@ -1459,6 +1466,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "MSA", "NLY", "NMC", + "OZ3", "PGY", "PRV", "SAR", @@ -1733,6 +1741,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "F2F", "FC0", "FCL", + "FX9", "H14", "HOX", "HP9", @@ -1826,6 +1835,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "RT0", "TPJ", "TPK", + "V3C", "VH0", "XPR", "YPR", @@ -1921,6 +1931,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "TNR", "UDS", "UF0", + "W4T", // parent is SFE "0E5", // parent is THR "26B", "28X", @@ -2034,6 +2045,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "DPQ", "E9C", "ESB", + "F2Y", "F7Q", "FLT", "FTY", diff --git a/iotbx/pdb/modified_aa_names.py b/iotbx/pdb/modified_aa_names.py index 3ef5a4e2ea..2cbc1d2137 100644 --- a/iotbx/pdb/modified_aa_names.py +++ b/iotbx/pdb/modified_aa_names.py @@ -7,7 +7,7 @@ phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Wed Sep 27 09:55:15 2023 +The date of file generation: Thu Jan 11 09:02:01 2024 """ from __future__ import absolute_import, division, print_function @@ -630,7 +630,6 @@ "ERL" : "?", "EYS" : "?", "F0G" : "?", - "F2Y" : "?", "F3G" : "?", "F3M" : "?", "F3T" : "?", @@ -648,6 +647,9 @@ "FPR" : "?", "FRD" : "?", "FTO" : "?", + "FXC" : "?", + "FXF" : "?", + "FXL" : "?", "FYI" : "?", "FYQ" : "?", "G85" : "?", @@ -962,6 +964,7 @@ "THO" : "?", "TIF" : "?", "TIG" : "?", + "TJI" : "?", "TKL" : "?", "TPH" : "?", "TPN" : "?", @@ -1010,6 +1013,7 @@ "VLT" : "?", "VME" : "?", "VMS" : "?", + "VNW" : "?", "VOL" : "?", "VPF" : "?", "VSC" : "?", @@ -1022,6 +1026,7 @@ "X5H" : "?", "X6E" : "?", "X9A" : "?", + "XC0" : "?", "XCP" : "?", "XDD" : "?", "XDJ" : "?", @@ -1113,6 +1118,7 @@ "FB5" : "A", "FB6" : "A", "FLA" : "A", + "H7V" : "A", "HAC" : "A", "HIX" : "A", "HQA" : "A", @@ -1379,6 +1385,7 @@ "TNB" : "C", "TQZ" : "C", "TSY" : "C", + "UJR" : "C", "V44" : "C", "VI3" : "C", "XCN" : "C", @@ -1454,6 +1461,7 @@ "MSA" : "G", "NLY" : "G", "NMC" : "G", + "OZ3" : "G", "PGY" : "G", "PRV" : "G", "SAR" : "G", @@ -1727,6 +1735,7 @@ "F2F" : "F", "FC0" : "F", "FCL" : "F", + "FX9" : "F", "H14" : "F", "HOX" : "F", "HP9" : "F", @@ -1820,6 +1829,7 @@ "RT0" : "P", "TPJ" : "P", "TPK" : "P", + "V3C" : "P", "VH0" : "P", "XPR" : "P", "YPR" : "P", @@ -2028,6 +2038,7 @@ "DPQ" : "Y", "E9C" : "Y", "ESB" : "Y", + "F2Y" : "Y", "F7Q" : "Y", "FLT" : "Y", "FTY" : "Y", diff --git a/iotbx/pdb/modified_rna_dna_names.h b/iotbx/pdb/modified_rna_dna_names.h index 0b75d2b766..aa340dc74d 100644 --- a/iotbx/pdb/modified_rna_dna_names.h +++ b/iotbx/pdb/modified_rna_dna_names.h @@ -5,7 +5,7 @@ This file is generated by the following procedure: phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Wed Sep 27 09:55:16 2023 +The date of file generation: Thu Jan 11 09:02:01 2024 */ #include @@ -96,6 +96,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "TYU", "U4M", "U5M", + "U6F", "UDP", "UFB", "UOA", @@ -104,6 +105,8 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "UY1", "UY4", "UZL", + "X0F", + "X0O", "XE6", "XEC", "XNY", @@ -491,8 +494,11 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "6PO", "7BG", "7GU", + "7S8", "8AG", + "8EB", "8FG", + "8H2", "8MG", "8OG", "8PY", @@ -726,11 +732,13 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "TG", "TPG", "VC7", + "VSN", "XTS", "YG", "YYG", "ZGU", "RT", // parent is T + "WUH", // parent is TTD "125", // parent is U "126", "127", diff --git a/iotbx/pdb/modified_rna_dna_names.py b/iotbx/pdb/modified_rna_dna_names.py index e72d47fd3a..8bf24fdf71 100644 --- a/iotbx/pdb/modified_rna_dna_names.py +++ b/iotbx/pdb/modified_rna_dna_names.py @@ -7,7 +7,7 @@ phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Wed Sep 27 09:55:16 2023 +The date of file generation: Thu Jan 11 09:02:01 2024 """ from __future__ import absolute_import, division, print_function @@ -94,6 +94,7 @@ "TYU" : "?", "U4M" : "?", "U5M" : "?", + "U6F" : "?", "UDP" : "?", "UFB" : "?", "UOA" : "?", @@ -102,6 +103,8 @@ "UY1" : "?", "UY4" : "?", "UZL" : "?", + "X0F" : "?", + "X0O" : "?", "XE6" : "?", "XEC" : "?", "XNY" : "?", @@ -489,8 +492,11 @@ "6PO" : "DG", "7BG" : "DG", "7GU" : "DG", + "7S8" : "DG", "8AG" : "DG", + "8EB" : "DG", "8FG" : "DG", + "8H2" : "DG", "8MG" : "DG", "8OG" : "DG", "8PY" : "DG", @@ -724,11 +730,13 @@ "TG" : "G", "TPG" : "G", "VC7" : "G", + "VSN" : "G", "XTS" : "G", "YG" : "G", "YYG" : "G", "ZGU" : "G", "RT" : "T", + "WUH" : "TTD", "125" : "U", "126" : "U", "127" : "U", From 1c22358bdc55ec231bfb76ca28ec3b06301ff891 Mon Sep 17 00:00:00 2001 From: Iris Young Date: Fri, 12 Jan 2024 12:40:12 -0500 Subject: [PATCH 015/748] move set dispatcher name to trigger building executable --- simtbx/command_line/estimate_Ncells_Eta.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/simtbx/command_line/estimate_Ncells_Eta.py b/simtbx/command_line/estimate_Ncells_Eta.py index d6ba9476a4..816b56c582 100644 --- a/simtbx/command_line/estimate_Ncells_Eta.py +++ b/simtbx/command_line/estimate_Ncells_Eta.py @@ -1,4 +1,7 @@ from __future__ import division + +# LIBTBX_SET_DISPATCHER_NAME diffBragg.estimate_Ncells_Eta + from argparse import ArgumentParser parser = ArgumentParser() parser.add_argument("dirname", help="still process output folder", type=str) @@ -14,7 +17,6 @@ #parser.add_argument("--njobs", type=int, default=5, help="number of jobs (only runs on single node, no MPI)") parser.add_argument("--plot", action="store_true", help="show a histogram at the end") args = parser.parse_args() -# LIBTBX_SET_DISPATCHER_NAME diffBragg.estimate_Ncells_Eta from mpi4py import MPI COMM = MPI.COMM_WORLD #from joblib import Parallel, delayed From 463a9c53be7f10b70e9c6c98ac513bfabf9d31ed Mon Sep 17 00:00:00 2001 From: nksauter Date: Sat, 13 Jan 2024 12:02:15 -0800 Subject: [PATCH 016/748] Streamline the two exascale simulation kernels. (#954) * Streamline the two exascale simulation kernels. Debranch kernel now a) uses vec3 rather than Holton-vec4; b) marshals all mos-tics and phi-tics into one list of crystal orientations; c) aligns exact order of operations (*,/) with kokkosSpotsKernel. * cosmetic changes * cosmetic changes --- simtbx/kokkos/simulation.cpp | 90 ++++++++----- simtbx/kokkos/simulation_kernels.h | 197 +++++++++++------------------ 2 files changed, 128 insertions(+), 159 deletions(-) diff --git a/simtbx/kokkos/simulation.cpp b/simtbx/kokkos/simulation.cpp index 23f960ff08..3770383e61 100644 --- a/simtbx/kokkos/simulation.cpp +++ b/simtbx/kokkos/simulation.cpp @@ -123,22 +123,28 @@ namespace Kokkos { for (std::size_t panel_id = 0; panel_id < kdt.m_panel_count; panel_id++){ // loop thru panels and increment the array ptrs kokkosSpotsKernel( - kdt.m_slow_dim_size, kdt.m_fast_dim_size, SIM.roi_xmin, - SIM.roi_xmax, SIM.roi_ymin, SIM.roi_ymax, SIM.oversample, SIM.point_pixel, - SIM.pixel_size, m_subpixel_size, m_steps, SIM.detector_thickstep, SIM.detector_thicksteps, - SIM.detector_thick, SIM.detector_attnlen, + kdt.m_slow_dim_size, kdt.m_fast_dim_size, SIM.roi_xmin, SIM.roi_xmax, + SIM.roi_ymin, SIM.roi_ymax, SIM.oversample, SIM.point_pixel, + SIM.pixel_size, m_subpixel_size, m_steps, SIM.detector_thickstep, + SIM.detector_thicksteps, SIM.detector_thick, SIM.detector_attnlen, extract_subview(kdt.m_sdet_vector, panel_id, 1), extract_subview(kdt.m_fdet_vector, panel_id, 1), extract_subview(kdt.m_odet_vector, panel_id, 1), extract_subview(kdt.m_pix0_vector, panel_id, 1), - SIM.curved_detector, kdt.metrology.dists[panel_id], kdt.metrology.dists[panel_id], m_beam_vector, - kdt.metrology.Xbeam[panel_id], kdt.metrology.Ybeam[panel_id], - SIM.dmin, SIM.phisteps, SIM.sources, m_source_X, m_source_Y, m_source_Z, - m_source_I, m_source_lambda, SIM.xtal_shape, SIM.mosaic_domains, m_crystal_orientation, + SIM.curved_detector, kdt.metrology.dists[panel_id], kdt.metrology.dists[panel_id], + m_beam_vector, + SIM.dmin, SIM.phisteps, SIM.sources, + m_source_X, m_source_Y, m_source_Z, + m_source_I, m_source_lambda, + SIM.xtal_shape, + SIM.mosaic_domains, m_crystal_orientation, SIM.Na, SIM.Nb, SIM.Nc, SIM.V_cell, - m_water_size, m_water_F, m_water_MW, simtbx::nanoBragg::r_e_sqr, SIM.fluence, - simtbx::nanoBragg::Avogadro, SIM.spot_scale, SIM.integral_form, SIM.default_F, - SIM.interpolate, current_channel_Fhkl, kec.m_FhklParams, SIM.nopolar, + m_water_size, m_water_F, m_water_MW, simtbx::nanoBragg::r_e_sqr, + SIM.fluence, simtbx::nanoBragg::Avogadro, SIM.spot_scale, SIM.integral_form, + SIM.default_F, + current_channel_Fhkl, + kec.m_FhklParams, + SIM.nopolar, m_polar_vector, SIM.polarization, SIM.fudge, // &(kdt.m_maskimage[panel_size * panel_id]), nullptr, @@ -195,6 +201,11 @@ namespace Kokkos { // cudaSafeCall(cudaMemcpyVectorDoubleToDevice(m_source_I, SIM.source_I, SIM.sources)); // cudaSafeCall(cudaMemcpyVectorDoubleToDevice(m_source_lambda, SIM.source_lambda, SIM.sources)); + ::Kokkos::resize(m_crystal_orientation, SIM.phisteps, SIM.mosaic_domains, 3); + calc_CrystalOrientations( + SIM.phi0, SIM.phistep, SIM.phisteps, m_spindle_vector, m_a0, m_b0, m_c0, SIM.mosaic_spread, + SIM.mosaic_domains, m_mosaic_umats, m_crystal_orientation); + // magic happens here: take pointer from singleton, temporarily use it for add Bragg iteration: vector_cudareal_t current_channel_Fhkl = kec.d_channel_Fhkl[ichannel]; @@ -210,23 +221,25 @@ namespace Kokkos { kdt.m_panel_count, kdt.m_slow_dim_size, kdt.m_fast_dim_size, active_pixel_list.size(), SIM.oversample, SIM.point_pixel, SIM.pixel_size, m_subpixel_size, m_steps, - SIM.detector_thickstep, SIM.detector_thicksteps, - SIM.detector_thick, SIM.detector_attnlen, - m_vector_length, + SIM.detector_thickstep, SIM.detector_thicksteps, SIM.detector_thick, SIM.detector_attnlen, kdt.m_sdet_vector, kdt.m_fdet_vector, kdt.m_odet_vector, kdt.m_pix0_vector, - kdt.m_distance, kdt.m_distance, m_beam_vector, - kdt.m_Xbeam, kdt.m_Ybeam, - SIM.dmin, SIM.phi0, SIM.phistep, SIM.phisteps, m_spindle_vector, - SIM.sources, m_source_X, m_source_Y, m_source_Z, - m_source_I, m_source_lambda, m_a0, m_b0, - m_c0, SIM.xtal_shape, SIM.mosaic_domains, m_mosaic_umats, + kdt.m_distance, + m_beam_vector, + SIM.dmin, SIM.phisteps, SIM.sources, + m_source_X, m_source_Y, + m_source_Z, + m_source_I, m_source_lambda, + SIM.mosaic_domains, m_crystal_orientation, SIM.Na, SIM.Nb, SIM.Nc, SIM.V_cell, - m_water_size, m_water_F, m_water_MW, simtbx::nanoBragg::r_e_sqr, SIM.fluence, - simtbx::nanoBragg::Avogadro, SIM.spot_scale, SIM.integral_form, SIM.default_F, - current_channel_Fhkl, kec.m_FhklParams, SIM.nopolar, + m_water_size, m_water_F, m_water_MW, simtbx::nanoBragg::r_e_sqr, + SIM.fluence, simtbx::nanoBragg::Avogadro, SIM.spot_scale, SIM.integral_form, + SIM.default_F, + current_channel_Fhkl, + kec.m_FhklParams, + SIM.nopolar, m_polar_vector, SIM.polarization, SIM.fudge, kdt.m_active_pixel_list, // return arrays: @@ -268,6 +281,11 @@ namespace Kokkos { // SIM.source_X[ictr], SIM.source_Y[ictr], SIM.source_Z[ictr], // SIM.source_I[ictr], SIM.source_lambda[ictr]); + ::Kokkos::resize(m_crystal_orientation, SIM.phisteps, SIM.mosaic_domains, 3); + calc_CrystalOrientations( + SIM.phi0, SIM.phistep, SIM.phisteps, m_spindle_vector, m_a0, m_b0, m_c0, SIM.mosaic_spread, + SIM.mosaic_domains, m_mosaic_umats, m_crystal_orientation); + // magic happens here: take pointer from singleton, temporarily use it for add Bragg iteration: vector_cudareal_t current_channel_Fhkl = kec.d_channel_Fhkl[ichannels[ictr]]; @@ -287,23 +305,25 @@ namespace Kokkos { kdt.m_panel_count, kdt.m_slow_dim_size, kdt.m_fast_dim_size, active_pixel_list.size(), SIM.oversample, SIM.point_pixel, SIM.pixel_size, m_subpixel_size, m_steps, - SIM.detector_thickstep, SIM.detector_thicksteps, - SIM.detector_thick, SIM.detector_attnlen, - m_vector_length, + SIM.detector_thickstep, SIM.detector_thicksteps, SIM.detector_thick, SIM.detector_attnlen, kdt.m_sdet_vector, kdt.m_fdet_vector, kdt.m_odet_vector, kdt.m_pix0_vector, - kdt.m_distance, kdt.m_distance, m_beam_vector, - kdt.m_Xbeam, kdt.m_Ybeam, - SIM.dmin, SIM.phi0, SIM.phistep, SIM.phisteps, m_spindle_vector, - 1, c_source_X, c_source_Y, c_source_Z, - c_source_I, c_source_lambda, m_a0, m_b0, - m_c0, SIM.xtal_shape, SIM.mosaic_domains, m_mosaic_umats, + kdt.m_distance, + m_beam_vector, + SIM.dmin, SIM.phisteps, 1, + c_source_X, c_source_Y, + c_source_Z, + c_source_I, c_source_lambda, + SIM.mosaic_domains, m_crystal_orientation, SIM.Na, SIM.Nb, SIM.Nc, SIM.V_cell, - m_water_size, m_water_F, m_water_MW, simtbx::nanoBragg::r_e_sqr, SIM.fluence, - simtbx::nanoBragg::Avogadro, SIM.spot_scale, SIM.integral_form, SIM.default_F, - current_channel_Fhkl, kec.m_FhklParams, SIM.nopolar, + m_water_size, m_water_F, m_water_MW, simtbx::nanoBragg::r_e_sqr, + SIM.fluence, simtbx::nanoBragg::Avogadro, SIM.spot_scale, SIM.integral_form, + SIM.default_F, + current_channel_Fhkl, + kec.m_FhklParams, + SIM.nopolar, m_polar_vector, SIM.polarization, SIM.fudge, kdt.m_active_pixel_list, // return arrays: diff --git a/simtbx/kokkos/simulation_kernels.h b/simtbx/kokkos/simulation_kernels.h index eb368a95db..6058b58ccf 100644 --- a/simtbx/kokkos/simulation_kernels.h +++ b/simtbx/kokkos/simulation_kernels.h @@ -75,21 +75,24 @@ void kokkosSpotsKernel(int spixels, int fpixels, int roi_xmin, int roi_xmax, const view_1d_t sdet_vector, const view_1d_t fdet_vector, const view_1d_t odet_vector, const view_1d_t pix0_vector, int curved_detector, CUDAREAL distance, CUDAREAL close_distance, - const vector_cudareal_t beam_vector, - CUDAREAL Xbeam, CUDAREAL Ybeam, CUDAREAL dmin, int phisteps, int sources, + const vector_cudareal_t beam_vector, + CUDAREAL dmin, int phisteps, int sources, const vector_cudareal_t source_X, const vector_cudareal_t source_Y, const vector_cudareal_t source_Z, const vector_cudareal_t source_I, const vector_cudareal_t source_lambda, - shapetype xtal_shape, int mosaic_domains, crystal_orientation_t crystal_orientation, + shapetype xtal_shape, + int mosaic_domains, crystal_orientation_t crystal_orientation, CUDAREAL Na, CUDAREAL Nb, CUDAREAL Nc, CUDAREAL V_cell, CUDAREAL water_size, CUDAREAL water_F, CUDAREAL water_MW, CUDAREAL r_e_sqr, CUDAREAL fluence, CUDAREAL Avogadro, CUDAREAL spot_scale, int integral_form, CUDAREAL default_F, - int interpolate, const vector_cudareal_t Fhkl, - const hklParams FhklParams, int nopolar, + const vector_cudareal_t Fhkl, + const hklParams FhklParams, + int nopolar, const vector_cudareal_t polar_vector, CUDAREAL polarization, CUDAREAL fudge, - const vector_ushort_t * maskimage, vector_float_t floatimage /*out*/, - vector_float_t omega_reduction /*out*/, vector_float_t max_I_x_reduction/*out*/, + const vector_ushort_t * maskimage, + vector_float_t floatimage /*out*/, + vector_float_t omega_reduction /*out*/, vector_float_t max_I_x_reduction /*out*/, vector_float_t max_I_y_reduction /*out*/, vector_bool_t rangemap) { const int s_h_min = FhklParams.h_min; @@ -114,8 +117,6 @@ void kokkosSpotsKernel(int spixels, int fpixels, int roi_xmin, int roi_xmax, Kokkos::parallel_for("kokkosSpotsKernel", total_pixels, KOKKOS_LAMBDA(const int& pixIdx) { - vec3 beam_vector_tmp {beam_vector(1), beam_vector(2), beam_vector(3)}; - vec3 polar_vector_tmp {polar_vector(1), polar_vector(2), polar_vector(3)}; const int fpixel = pixIdx % fpixels; @@ -255,6 +256,7 @@ void kokkosSpotsKernel(int spixels, int fpixels, int roi_xmin, int roi_xmax, // structure factor of the lattice (paralelpiped crystal) // F_latt = sin(M_PI*s_Na*h)*sin(M_PI*s_Nb*k)*sin(M_PI*s_Nc*l)/sin(M_PI*h)/sin(M_PI*k)/sin(M_PI*l); + CUDAREAL F_latt = 1.0; // Shape transform for the crystal. CUDAREAL hrad_sqr = 0.0; @@ -343,53 +345,55 @@ void debranch_maskall_Kernel(int npanels, int spixels, int fpixels, int total_pi int oversample, int point_pixel, CUDAREAL pixel_size, CUDAREAL subpixel_size, int steps, CUDAREAL detector_thickstep, int detector_thicksteps, CUDAREAL detector_thick, CUDAREAL detector_mu, - const int vec_len, const view_1d_t sdet_vector, const view_1d_t fdet_vector, const view_1d_t odet_vector, const view_1d_t pix0_vector, - const vector_cudareal_t distance, const vector_cudareal_t close_distance, + const vector_cudareal_t close_distance, const vector_cudareal_t beam_vector, - const vector_cudareal_t Xbeam, const vector_cudareal_t Ybeam, // not even used, after all the work - CUDAREAL dmin, CUDAREAL phi0, CUDAREAL phistep, int phisteps, - const vector_cudareal_t spindle_vector, int sources, + CUDAREAL dmin, int phisteps, int sources, const vector_cudareal_t source_X, const vector_cudareal_t source_Y, const vector_cudareal_t source_Z, const vector_cudareal_t source_I, const vector_cudareal_t source_lambda, - const vector_cudareal_t a0, const vector_cudareal_t b0, - const vector_cudareal_t c0, shapetype xtal_shape, - int mosaic_domains, const vector_cudareal_t mosaic_umats, - CUDAREAL Na, CUDAREAL Nb, CUDAREAL Nc, CUDAREAL V_cell, CUDAREAL water_size, CUDAREAL water_F, CUDAREAL water_MW, - CUDAREAL r_e_sqr, CUDAREAL fluence, - CUDAREAL Avogadro, CUDAREAL spot_scale, int integral_form, CUDAREAL default_F, - const vector_cudareal_t Fhkl, const hklParams FhklParams, - int nopolar, const vector_cudareal_t polar_vector, - CUDAREAL polarization, CUDAREAL fudge, + int mosaic_domains, crystal_orientation_t crystal_orientation, + CUDAREAL Na, CUDAREAL Nb, CUDAREAL Nc, CUDAREAL V_cell, + CUDAREAL water_size, CUDAREAL water_F, CUDAREAL water_MW, CUDAREAL r_e_sqr, + CUDAREAL fluence, CUDAREAL Avogadro, CUDAREAL spot_scale, int integral_form, + CUDAREAL default_F, + const vector_cudareal_t Fhkl, + const hklParams FhklParams, + int nopolar, + const vector_cudareal_t polar_vector, CUDAREAL polarization, CUDAREAL fudge, const vector_size_t pixel_lookup, - vector_float_t floatimage /*out*/, vector_float_t omega_reduction/*out*/, - vector_float_t max_I_x_reduction/*out*/, vector_float_t max_I_y_reduction /*out*/, vector_bool_t rangemap) { + vector_float_t floatimage /*out*/, + vector_float_t omega_reduction /*out*/, vector_float_t max_I_x_reduction /*out*/, + vector_float_t max_I_y_reduction /*out*/, vector_bool_t rangemap) { - const int s_h_min = FhklParams.h_min; - const int s_k_min = FhklParams.k_min; - const int s_l_min = FhklParams.l_min; - const int s_h_range = FhklParams.h_range; - const int s_k_range = FhklParams.k_range; - const int s_l_range = FhklParams.l_range; - const int s_h_max = s_h_min + s_h_range - 1; - const int s_k_max = s_k_min + s_k_range - 1; - const int s_l_max = s_l_min + s_l_range - 1; + const int s_h_min = FhklParams.h_min; + const int s_k_min = FhklParams.k_min; + const int s_l_min = FhklParams.l_min; + const int s_h_range = FhklParams.h_range; + const int s_k_range = FhklParams.k_range; + const int s_l_range = FhklParams.l_range; + const int s_h_max = s_h_min + s_h_range - 1; + const int s_k_max = s_k_min + s_k_range - 1; + const int s_l_max = s_l_min + s_l_range - 1; // Implementation notes. This kernel is aggressively debranched, therefore the assumptions are: // 1) mosaicity non-zero positive // 2) xtal shape is "Gauss" i.e. 3D spheroid. // 3) No bounds check for access to the structure factor array. // 4) No check for Flatt=0. + const CUDAREAL dmin_r = (dmin > 0.0) ? 1/dmin : 0.0; - - // add background from something amorphous - CUDAREAL F_bg = water_F; - CUDAREAL I_bg = F_bg * F_bg * r_e_sqr * fluence * water_size * water_size * water_size * 1e6 * Avogadro / water_MW; + // add background from something amorphous, precalculate scaling + const CUDAREAL F_bg = water_F; + const CUDAREAL I_bg = F_bg * F_bg * r_e_sqr * fluence * water_size * water_size * water_size * 1e6 * Avogadro / water_MW; + const CUDAREAL I_factor = r_e_sqr * spot_scale * fluence / steps; Kokkos::parallel_for("debranch_maskall", total_pixels, KOKKOS_LAMBDA(const int& pixIdx) { + + vec3 polar_vector_tmp {polar_vector(1), polar_vector(2), polar_vector(3)}; + // position in pixel array const int j = pixel_lookup(pixIdx);//pixIdx: index into pixel subset; j: index into the data. const int i_panel = j / (fpixels*spixels); // the panel number @@ -431,42 +435,28 @@ void debranch_maskall_Kernel(int npanels, int spixels, int fpixels, int total_pi // pixel_X = distance; // pixel_Y = Sdet-Ybeam; // pixel_Z = Fdet-Xbeam; - //CUDAREAL * pixel_pos = tmpVector1; - CUDAREAL pixel_pos[4]; - pixel_pos[1] = Fdet * fdet_vector(i_panel)[0] - + Sdet * sdet_vector(i_panel)[0] - + Odet * odet_vector(i_panel)[0] - + pix0_vector(i_panel)[0]; // X - pixel_pos[2] = Fdet * fdet_vector(i_panel)[1] - + Sdet * sdet_vector(i_panel)[1] - + Odet * odet_vector(i_panel)[1] - + pix0_vector(i_panel)[1]; // Y - pixel_pos[3] = Fdet * fdet_vector(i_panel)[2] - + Sdet * sdet_vector(i_panel)[2] - + Odet * odet_vector(i_panel)[2] - + pix0_vector(i_panel)[2]; // Z + vec3 pixel_pos; + pixel_pos += Fdet * fdet_vector(i_panel); + pixel_pos += Sdet * sdet_vector(i_panel); + pixel_pos += Odet * odet_vector(i_panel); + pixel_pos += pix0_vector(i_panel); // construct the diffracted-beam unit vector to this sub-pixel - //CUDAREAL * diffracted = tmpVector2; - CUDAREAL diffracted[4]; - CUDAREAL airpath = unitize(pixel_pos, diffracted); + CUDAREAL airpath_r = 1 / pixel_pos.length(); + vec3 diffracted = pixel_pos.get_unit_vector(); // solid angle subtended by a pixel: (pix/airpath)^2*cos(2theta) - CUDAREAL omega_pixel = pixel_size * pixel_size / airpath / airpath * close_distance(i_panel) / airpath; + CUDAREAL omega_pixel = pixel_size * pixel_size * airpath_r * airpath_r * close_distance(i_panel) * airpath_r; // option to turn off obliquity effect, inverse-square-law only if (point_pixel) { - omega_pixel = 1.0 / airpath / airpath; + omega_pixel = airpath_r * airpath_r; } // now calculate detector thickness effects CUDAREAL capture_fraction = 1.0; if (detector_thick > 0.0 && detector_mu> 0.0) { // inverse of effective thickness increase - CUDAREAL odet[4]; - odet[1] = odet_vector(i_panel)[0]; - odet[2] = odet_vector(i_panel)[1]; - odet[3] = odet_vector(i_panel)[2]; - CUDAREAL parallax = dot_product(odet, diffracted); + CUDAREAL parallax = odet_vector(i_panel).dot(diffracted); capture_fraction = exp(-thick_tic * detector_thickstep / detector_mu / parallax) - exp(-(thick_tic + 1) * detector_thickstep / detector_mu / parallax); } @@ -476,32 +466,22 @@ void debranch_maskall_Kernel(int npanels, int spixels, int fpixels, int total_pi for (source = 0; source < sources; ++source) { // retrieve stuff from cache - CUDAREAL incident[4]; - incident[1] = -source_X(source); - incident[2] = -source_Y(source); - incident[3] = -source_Z(source); + vec3 incident = {-source_X(source), -source_Y(source), -source_Z(source)}; CUDAREAL lambda = source_lambda(source); CUDAREAL source_fraction = source_I(source); // construct the incident beam unit vector while recovering source distance // TODO[Giles]: Optimization! We can unitize the source vectors before passing them in. - unitize(incident, incident); + incident.normalize(); // construct the scattering vector for this pixel - CUDAREAL scattering[4]; - scattering[1] = (diffracted[1] - incident[1]) / lambda; - scattering[2] = (diffracted[2] - incident[2]) / lambda; - scattering[3] = (diffracted[3] - incident[3]) / lambda; - - #ifdef __CUDA_ARCH__ - CUDAREAL stol = 0.5 * norm3d(scattering[1], scattering[2], scattering[3]); - #else - CUDAREAL stol = 0.5 * sqrt(scattering[1]*scattering[1] + scattering[2]*scattering[2] + scattering[3]*scattering[3]); - #endif + vec3 scattering = (diffracted - incident) / lambda; + CUDAREAL stol = 0.5 * scattering.length(); // rough cut to speed things up when we aren't using whole detector if (dmin > 0.0 && stol > 0.0) { - if (dmin > 0.5 / stol) { + // use reciprocal of (dmin > 0.5 / stol) + if (dmin_r <= 2 * stol) { continue; } } @@ -509,50 +489,24 @@ void debranch_maskall_Kernel(int npanels, int spixels, int fpixels, int total_pi // polarization factor if (!nopolar) { // need to compute polarization factor - polar = polarization_factor(polarization, incident, diffracted, polar_vector); + polar = polarization_factor(polarization, incident, diffracted, polar_vector_tmp); } else { polar = 1.0; } // sweep over phi angles for (int phi_tic = 0; phi_tic < phisteps; ++phi_tic) { - CUDAREAL phi = phistep * phi_tic + phi0; - - CUDAREAL ap[4]; - CUDAREAL bp[4]; - CUDAREAL cp[4]; - - // rotate about spindle if necessary - rotate_axis(a0, ap, spindle_vector, phi); - rotate_axis(b0, bp, spindle_vector, phi); - rotate_axis(c0, cp, spindle_vector, phi); - // enumerate mosaic domains for (int mos_tic = 0; mos_tic < mosaic_domains; ++mos_tic) { // apply mosaic rotation after phi rotation - CUDAREAL a[4]; - CUDAREAL b[4]; - CUDAREAL c[4]; - - CUDAREAL umat[] = {mosaic_umats(mos_tic * 9 + 0), - mosaic_umats(mos_tic * 9 + 1), - mosaic_umats(mos_tic * 9 + 2), - mosaic_umats(mos_tic * 9 + 3), - mosaic_umats(mos_tic * 9 + 4), - mosaic_umats(mos_tic * 9 + 5), - mosaic_umats(mos_tic * 9 + 6), - mosaic_umats(mos_tic * 9 + 7), - mosaic_umats(mos_tic * 9 + 8)}; - - rotate_umat(ap, a, umat); - rotate_umat(bp, b, umat); - rotate_umat(cp, c, umat); + auto a = crystal_orientation(phi_tic, mos_tic, 0); + auto b = crystal_orientation(phi_tic, mos_tic, 1); + auto c = crystal_orientation(phi_tic, mos_tic, 2); // construct fractional Miller indicies - - CUDAREAL h = dot_product(a, scattering); - CUDAREAL k = dot_product(b, scattering); - CUDAREAL l = dot_product(c, scattering); + CUDAREAL h = a.dot(scattering); + CUDAREAL k = b.dot(scattering); + CUDAREAL l = c.dot(scattering); // round off to nearest whole index int h0 = ceil(h - 0.5); @@ -564,6 +518,7 @@ void debranch_maskall_Kernel(int npanels, int spixels, int fpixels, int total_pi CUDAREAL F_latt = 1.0; // Shape transform for the crystal. CUDAREAL hrad_sqr = 0.0; + // handy radius in reciprocal space, squared hrad_sqr = (h - h0) * (h - h0) * Na * Na + (k - k0) * (k - k0) * Nb * Nb + (l - l0) * (l - l0) * Nc * Nc; // fudge the radius so that volume and FWHM are similar to square_xtal spots @@ -592,19 +547,13 @@ void debranch_maskall_Kernel(int npanels, int spixels, int fpixels, int total_pi // convert amplitudes into intensity (photons per steradian) I += F_cell * F_cell * F_latt * F_latt * source_fraction * capture_fraction * omega_pixel; omega_sub_reduction += omega_pixel; - } - // end of mosaic loop - } - // end of phi loop - } - // end of source loop - } - // end of detector thickness loop - } - // end of sub-pixel y loop - } - // end of sub-pixel x loop - const double photons = I_bg + (r_e_sqr * spot_scale * fluence * polar * I) / steps; + } // end of mosaic loop + } // end of phi loop + } // end of source loop + } // end of detector thickness loop + } // end of sub-pixel y loop + } // end of sub-pixel x loop + const double photons = I_bg + I_factor * polar * I; floatimage( j ) = photons; omega_reduction( j ) = omega_sub_reduction; // shared contention max_I_x_reduction( j ) = max_I_x_sub_reduction; From 2882f6d3641152f2447307974337881f12fb340e Mon Sep 17 00:00:00 2001 From: terwill Date: Mon, 15 Jan 2024 10:26:11 -0700 Subject: [PATCH 017/748] Catch pdb_hierarchy that does not fit in pdb format and write with mmcif --- mmtbx/geometry_restraints/torsion_restraints/utils.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mmtbx/geometry_restraints/torsion_restraints/utils.py b/mmtbx/geometry_restraints/torsion_restraints/utils.py index bd39eb3d60..45278c9333 100644 --- a/mmtbx/geometry_restraints/torsion_restraints/utils.py +++ b/mmtbx/geometry_restraints/torsion_restraints/utils.py @@ -106,7 +106,10 @@ def get_complete_dihedral_proxies( if ener_lib is None: ener_lib = server.ener_lib() if pdb_hierarchy is not None: - raw_records = pdb_hierarchy.as_pdb_string() + if pdb_hierarchy.fits_in_pdb_format(): + raw_records = pdb_hierarchy.as_pdb_string() + else: + raw_records = pdb_hierarchy.as_mmcif_string() if raw_records is not None: if (isinstance(raw_records, str)): raw_records = flex.split_lines(raw_records) From 25a9002d4e4d773ef7355e243a27d4acd7c3fc01 Mon Sep 17 00:00:00 2001 From: dermen Date: Fri, 12 Jan 2024 09:08:03 -0800 Subject: [PATCH 018/748] adds option to store average wavelength per pixel --- simtbx/diffBragg/src/diffBragg.cpp | 22 ++++++++++-- simtbx/diffBragg/src/diffBragg.h | 1 + simtbx/diffBragg/src/diffBraggCUDA.cu | 4 +-- simtbx/diffBragg/src/diffBraggKOKKOS.cpp | 2 +- simtbx/diffBragg/src/diffBragg_cpu_kernel.cpp | 18 +++++++--- simtbx/diffBragg/src/diffBragg_ext.cpp | 4 +++ simtbx/diffBragg/src/diffBragg_gpu_kernel.cu | 36 +++++++++++++------ .../diffBragg/src/diffBragg_kokkos_kernel.cpp | 17 +++++++-- simtbx/modeling/forward_models.py | 3 +- 9 files changed, 82 insertions(+), 25 deletions(-) diff --git a/simtbx/diffBragg/src/diffBragg.cpp b/simtbx/diffBragg/src/diffBragg.cpp index f07b7e99c2..a42cc5b960 100644 --- a/simtbx/diffBragg/src/diffBragg.cpp +++ b/simtbx/diffBragg/src/diffBragg.cpp @@ -2006,7 +2006,7 @@ void diffBragg::add_diffBragg_spots(const af::shared& panels_fasts_slows image_type image(Npix_to_model,0.0); if(db_flags.wavelength_img){ // TODO: `wavelength` is not a first derivative image, change membership in the future - first_deriv_imgs.wavelength.resize(Npix_to_model,0); + first_deriv_imgs.wavelength.resize(4*Npix_to_model,0); // store average wavelength and h,k,l } if (std::count(db_flags.refine_Umat.begin(), db_flags.refine_Umat.end(), true) > 0){ first_deriv_imgs.Umat.resize(Npix_to_model*3, 0); @@ -2451,13 +2451,29 @@ void diffBragg::show_timing_stats(int MPI_RANK){ //}, boost_adaptbx::python::str } af::flex_double diffBragg::ave_wavelength_img(){ - int Npix = first_deriv_imgs.wavelength.size(); + int Npix = first_deriv_imgs.wavelength.size()/4; af::flex_double wavelen_pixels = af::flex_double(Npix); for (int i=0; i 0 ); SCITBX_ASSERT(db_cryst.dspace_bins.size()>0); diff --git a/simtbx/diffBragg/src/diffBragg.h b/simtbx/diffBragg/src/diffBragg.h index aa4983792f..c26d0d019e 100644 --- a/simtbx/diffBragg/src/diffBragg.h +++ b/simtbx/diffBragg/src/diffBragg.h @@ -145,6 +145,7 @@ class diffBragg: public nanoBragg{ double* floatimage_roi; af::flex_double raw_pixels_roi; af::flex_double ave_wavelength_img(); + boost::python::tuple ave_hkl_img(); int Npix_total, Npix_to_model; void diffBragg_list_steps(step_arrays& db_steps); diff --git a/simtbx/diffBragg/src/diffBraggCUDA.cu b/simtbx/diffBragg/src/diffBraggCUDA.cu index b318a189e5..9c58687f40 100644 --- a/simtbx/diffBragg/src/diffBraggCUDA.cu +++ b/simtbx/diffBragg/src/diffBraggCUDA.cu @@ -187,7 +187,7 @@ void diffBragg_sum_over_steps_cuda( //gettimeofday(&t3, 0)); gpuErr(cudaMallocManaged(&cp.cu_floatimage, db_cu_flags.Npix_to_allocate*sizeof(CUDAREAL) )); if (db_flags.wavelength_img){ - gpuErr(cudaMallocManaged(&cp.cu_wavelenimage, db_cu_flags.Npix_to_allocate*sizeof(CUDAREAL) )); + gpuErr(cudaMallocManaged(&cp.cu_wavelenimage, 4*db_cu_flags.Npix_to_allocate*sizeof(CUDAREAL) )); } if (db_flags.refine_diffuse){ gpuErr(cudaMallocManaged(&cp.cu_d_diffuse_gamma_images, db_cu_flags.Npix_to_allocate*3*sizeof(CUDAREAL))); @@ -535,7 +535,7 @@ void diffBragg_sum_over_steps_cuda( floatimage[i] = cp.cu_floatimage[i]; } if(db_flags.wavelength_img){ - for (int i=0; i< Npix_to_model; i++){ + for (int i=0; i< 4*Npix_to_model; i++){ d_image.wavelength[i] = cp.cu_wavelenimage[i]; } } diff --git a/simtbx/diffBragg/src/diffBraggKOKKOS.cpp b/simtbx/diffBragg/src/diffBraggKOKKOS.cpp index fb88a6f066..273088f765 100644 --- a/simtbx/diffBragg/src/diffBraggKOKKOS.cpp +++ b/simtbx/diffBragg/src/diffBraggKOKKOS.cpp @@ -189,7 +189,7 @@ void diffBraggKOKKOS::diffBragg_sum_over_steps_kokkos( resize(m_floatimage, db_cu_flags.Npix_to_allocate); if (db_flags.wavelength_img) { - resize(m_wavelenimage, db_cu_flags.Npix_to_allocate); + resize(m_wavelenimage, 4*db_cu_flags.Npix_to_allocate); } if (db_flags.refine_diffuse) { resize(m_d_diffuse_gamma_images, db_cu_flags.Npix_to_allocate * 3); diff --git a/simtbx/diffBragg/src/diffBragg_cpu_kernel.cpp b/simtbx/diffBragg/src/diffBragg_cpu_kernel.cpp index 22dd70275a..94cd9fa501 100644 --- a/simtbx/diffBragg/src/diffBragg_cpu_kernel.cpp +++ b/simtbx/diffBragg/src/diffBragg_cpu_kernel.cpp @@ -373,6 +373,9 @@ void diffBragg_sum_over_steps( // reset photon count for this pixel double I=0; double Ilambda = 0; + double Imiller_h =0; + double Imiller_k =0; + double Imiller_l =0; double II_max = -1; double max_stats[11] = {0,0,0,0,0, 0,0,0,0,0,0}; @@ -722,9 +725,12 @@ void diffBragg_sum_over_steps( double Iincrement = s_hkl*I_cell*I_noFcell; I += Iincrement; - if(db_flags.wavelength_img) + if(db_flags.wavelength_img){ Ilambda += Iincrement*lambda_ang; - + Imiller_h += Iincrement * h ; + Imiller_k += Iincrement * k; + Imiller_l += Iincrement * l; + } if (db_flags.refine_diffuse){ double step_scale = count_scale*I_cell; for (int i_gam=0; i_gam <3; i_gam++){ @@ -1094,8 +1100,12 @@ void diffBragg_sum_over_steps( floatimage[i_pix] = scale_term*I; - if (db_flags.wavelength_img) - d_image.wavelength[i_pix] = Ilambda / I; + if (db_flags.wavelength_img){ + d_image.wavelength[i_pix*4] = Ilambda / I; + d_image.wavelength[i_pix*4+1] = Imiller_h / I; + d_image.wavelength[i_pix*4+2] = Imiller_k / I; + d_image.wavelength[i_pix*4+3] = Imiller_l / I; + } } if (db_flags.refine_diffuse){ for (int i_diff=0; i_diff < 6; i_diff++){ diff --git a/simtbx/diffBragg/src/diffBragg_ext.cpp b/simtbx/diffBragg/src/diffBragg_ext.cpp index 997a6bea6d..47d500ca77 100644 --- a/simtbx/diffBragg/src/diffBragg_ext.cpp +++ b/simtbx/diffBragg/src/diffBragg_ext.cpp @@ -921,6 +921,10 @@ namespace boost_python { namespace { &simtbx::nanoBragg::diffBragg::ave_wavelength_img, "return flex array containing average wavelen per pixel") + .def("ave_hkl_image", + &simtbx::nanoBragg::diffBragg::ave_hkl_img, + "return 3-tuple of flex arrays each containing average h,k,l per pixel, respectively") + .def("_set_Friedel_mate_inds", &simtbx::nanoBragg::diffBragg::set_Friedel_mate_inds, "Two arguments; each lists of the same length, pointing to the positive and negative mates in a Friedel pair, respectively") diff --git a/simtbx/diffBragg/src/diffBragg_gpu_kernel.cu b/simtbx/diffBragg/src/diffBragg_gpu_kernel.cu index 6bf8b801e4..f74319f810 100644 --- a/simtbx/diffBragg/src/diffBragg_gpu_kernel.cu +++ b/simtbx/diffBragg/src/diffBragg_gpu_kernel.cu @@ -294,6 +294,9 @@ void gpu_sum_over_steps( // reset photon count for this pixel double _I=0; double Ilambda=0; + double Imiller_h=0; + double Imiller_k=0; + double Imiller_l=0; // reset derivative photon counts for the various parameters double rot_manager_dI[3] = {0,0,0}; @@ -576,8 +579,12 @@ void gpu_sum_over_steps( CUDAREAL _I_total = s_hkl*_I_cell *I0; CUDAREAL Iincrement = _I_total*texture_scale; _I += Iincrement; - if (save_wavelenimage) + if (save_wavelenimage){ Ilambda += Iincrement*lambda_ang; + Imiller_h += Iincrement*_h; + Imiller_k += Iincrement*_k; + Imiller_l += Iincrement*_l; + } if (s_refine_diffuse){ CUDAREAL step_scale = texture_scale*_F_cell*_F_cell; @@ -845,16 +852,16 @@ void gpu_sum_over_steps( if( s_printout){ if( _subS==0 && _subF==0 && _thick_tic==0 && _source==0 && _mos_tic==0 ){ if((_fpixel==s_printout_fpixel && _spixel==s_printout_spixel) || s_printout_fpixel < 0){ - printf("%4d %4d : lambda = %g\n", _fpixel,_spixel, _lambda); + printf("%4d %4d : lambda = %10.9g\n", _fpixel,_spixel, _lambda); printf("at %g %g %g\n", _pixel_pos[0],_pixel_pos[1],_pixel_pos[2]); - printf("Fdet= %g; Sdet= %g ; Odet= %g\n", _Fdet, _Sdet, _Odet); - printf("PIX0: %f %f %f\n" , pix0_vectors[pid_x], pix0_vectors[pid_y], pix0_vectors[pid_z]); - printf("F: %f %f %f\n" , fdet_vectors[pid_x], fdet_vectors[pid_y], fdet_vectors[pid_z]); - printf("S: %f %f %f\n" , sdet_vectors[pid_x], sdet_vectors[pid_y], sdet_vectors[pid_z]); - printf("O: %f %f %f\n" , odet_vectors[pid_x], odet_vectors[pid_y], odet_vectors[pid_z]); + printf("Fdet= %10.7g; Sdet= %10.7g ; Odet= %10.7g\n", _Fdet, _Sdet, _Odet); + printf("PIX0: %10.5g %10.5g %10.5g\n" , pix0_vectors[pid_x], pix0_vectors[pid_y], pix0_vectors[pid_z]); + printf("F: %10.5g %10.5g %10.5g\n" , fdet_vectors[pid_x], fdet_vectors[pid_y], fdet_vectors[pid_z]); + printf("S: %10.5g %10.5g %10.5g\n" , sdet_vectors[pid_x], sdet_vectors[pid_y], sdet_vectors[pid_z]); + printf("O: %10.5g %10.5g %10.5g\n" , odet_vectors[pid_x], odet_vectors[pid_y], odet_vectors[pid_z]); printf("pid_x=%d, pid_y=%d; pid_z=%d\n", pid_x, pid_y, pid_z); - printf("QVECTOR: %f %f %f\n" , q_vec[0], q_vec[1], q_vec[2]); + printf("QVECTOR: %10.5g %10.5g %10.5g\n" , q_vec[0], q_vec[1], q_vec[2]); MAT3 UU = UMATS_RXYZ[_mos_tic]; printf("UMAT_RXYZ :\n%f %f %f\n%f %f %f\n%f %f %f\n", UU(0,0), UU(0,1), UU(0,2), @@ -892,7 +899,10 @@ void gpu_sum_over_steps( //printf("Ilatt diffuse %15.10g\n", I_latt_diffuse); printf("omega %15.10g\n", _omega_pixel); printf("default_F= %f\n", s_default_F); - printf("Incident[0]=%g, Incident[1]=%g, Incident[2]=%g\n", _incident[0], _incident[1], _incident[2]); + printf("Incident[0]=%15.10g, Incident[1]=%15.10g, Incident[2]=%15.10g\n", _incident[0], _incident[1], _incident[2]); + printf("Diffracted[0]=%15.10g, Diffracted[1]=%15.10g, Diffracted[2]=%15.10g\n", _diffracted[0], _diffracted[1], _diffracted[2]); + printf("Scattering[0]=%15.10g, Scattering[1]=%15.10g, Scattering[2]=%15.10g\n", _scattering[0], _scattering[1], _scattering[2]); + printf("sourceI=%10.7g\n", sI); if (s_complex_miller)printf("COMPLEX MILLER!\n"); if (s_no_Nabc_scale)printf("No Nabc scale!\n"); } @@ -971,8 +981,12 @@ void gpu_sum_over_steps( // final scale term to being everything to photon number units CUDAREAL _scale_term = _polar*_om * s_overall_scale; floatimage[i_pix] = _scale_term*_I; - if (save_wavelenimage) - wavelenimage[i_pix] = Ilambda / _I; + if (save_wavelenimage){ + wavelenimage[i_pix*4] = Ilambda / _I; + wavelenimage[i_pix*4+1] = Imiller_h / _I; + wavelenimage[i_pix*4+2] = Imiller_k / _I; + wavelenimage[i_pix*4+3] = Imiller_l / _I; + } // udpate the rotation derivative images* for (int i_rot =0 ; i_rot < 3 ; i_rot++){ diff --git a/simtbx/diffBragg/src/diffBragg_kokkos_kernel.cpp b/simtbx/diffBragg/src/diffBragg_kokkos_kernel.cpp index 5b1acf243f..f6bfe0b119 100644 --- a/simtbx/diffBragg/src/diffBragg_kokkos_kernel.cpp +++ b/simtbx/diffBragg/src/diffBragg_kokkos_kernel.cpp @@ -292,6 +292,9 @@ void kokkos_sum_over_steps( // reset photon count for this pixel double _I = 0; double Ilambda = 0; + double Imiller_h = 0; + double Imiller_k = 0; + double Imiller_l = 0; kokkos_manager dI, dI2; dI.reset(); @@ -572,8 +575,12 @@ void kokkos_sum_over_steps( CUDAREAL _I_total = hkl*_I_cell *I0; CUDAREAL Iincrement = _I_total * texture_scale; _I += Iincrement; - if (save_wavelenimage) + if (save_wavelenimage){ Ilambda += Iincrement * lambda_ang; + Imiller_h += Iincrement*_h; + Imiller_k += Iincrement*_k; + Imiller_l += Iincrement*_k; + } if (refine_flag & REFINE_DIFFUSE) { CUDAREAL step_scale = texture_scale * _F_cell * _F_cell; @@ -927,8 +934,12 @@ void kokkos_sum_over_steps( } // end of fpos loop } // end of spos loop floatimage(pixIdx) = _I; - if (save_wavelenimage) - wavelenimage(pixIdx) = Ilambda / _I; + if (save_wavelenimage){ + wavelenimage(pixIdx*4) = Ilambda / _I; + wavelenimage(pixIdx*4+1) = Imiller_h / _I; + wavelenimage(pixIdx*4+2) = Imiller_k / _I; + wavelenimage(pixIdx*4+3) = Imiller_l / _I; + } if (refine_flag) { manager_dI(pixIdx) = dI; diff --git a/simtbx/modeling/forward_models.py b/simtbx/modeling/forward_models.py index b6538c9400..dd305aa7ec 100644 --- a/simtbx/modeling/forward_models.py +++ b/simtbx/modeling/forward_models.py @@ -315,6 +315,7 @@ def diffBragg_forward(CRYSTAL, DETECTOR, BEAM, Famp, energies, fluxes, data = S.D.raw_pixels_roi.as_numpy_array().reshape(img_shape) if perpixel_wavelen: wavelen_data = S.D.ave_wavelength_image().as_numpy_array().reshape(img_shape) + hdata,kdata,ldata = map(lambda x:x.as_numpy_array().reshape(img_shape), S.D.ave_hkl_image()) t = time.time() - t if show_timings: @@ -332,7 +333,7 @@ def diffBragg_forward(CRYSTAL, DETECTOR, BEAM, Famp, energies, fluxes, if S.D.gpu_free is not None: S.D.gpu_free() if perpixel_wavelen: - return data, wavelen_data + return data, wavelen_data, hdata, kdata, ldata else: return data From fd9972b27855a953da68ce2262091bde3bae78a5 Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Wed, 17 Jan 2024 09:19:53 -0800 Subject: [PATCH 019/748] XFEL CI: add retries to conda steps --- .azure-pipelines/xfel/unix-conda-build.yml | 1 + .azure-pipelines/xfel/unix-psana-build.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.azure-pipelines/xfel/unix-conda-build.yml b/.azure-pipelines/xfel/unix-conda-build.yml index bece4d695b..9e40551341 100644 --- a/.azure-pipelines/xfel/unix-conda-build.yml +++ b/.azure-pipelines/xfel/unix-conda-build.yml @@ -58,6 +58,7 @@ steps: conda install -y -c conda-forge --no-deps -n $(PYTHON_VERSION) junit-xml conda install -y -c conda-forge cmake pandas distro -n $(PYTHON_VERSION) displayName: Create conda environment + retryCountOnTaskFailure: 3 - script: | set -xe diff --git a/.azure-pipelines/xfel/unix-psana-build.yml b/.azure-pipelines/xfel/unix-psana-build.yml index 3238deacaa..25ab5d8361 100644 --- a/.azure-pipelines/xfel/unix-psana-build.yml +++ b/.azure-pipelines/xfel/unix-psana-build.yml @@ -53,6 +53,7 @@ steps: mamba install -y -c conda-forge --no-deps -n psana_env junit-xml mamba install -y -c conda-forge cmake pandas distro -n psana_env displayName: Create conda environment + retryCountOnTaskFailure: 3 # build - script: | From 6d03ec588237e397c85fc0a1027ce381926b1ecd Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 17 Jan 2024 10:03:57 -0800 Subject: [PATCH 020/748] use str instead of basestring --- cctbx/eltbx/read_custom_scattering_dict.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cctbx/eltbx/read_custom_scattering_dict.py b/cctbx/eltbx/read_custom_scattering_dict.py index 9b2a4e9f2b..c7102cc20e 100644 --- a/cctbx/eltbx/read_custom_scattering_dict.py +++ b/cctbx/eltbx/read_custom_scattering_dict.py @@ -27,9 +27,9 @@ def run(filename, log = None): el = fields[0] parameters = fields[1:] # Make sure the first field is a string - assert(isinstance(el, basestring)) + # assert(isinstance(el, basestring)) # Python 3 - # assert (isinstance(el, str)) + assert (isinstance(el, str)) # How many gaussians? n_gauss = (len(parameters))//2 From a190167c35f2dc59aaee317b19d5412172e2afa5 Mon Sep 17 00:00:00 2001 From: cschlick Date: Wed, 17 Jan 2024 11:09:23 -0800 Subject: [PATCH 021/748] Initial commit of qscore implementation --- cctbx/maptbx/qscore | 1 + 1 file changed, 1 insertion(+) create mode 160000 cctbx/maptbx/qscore diff --git a/cctbx/maptbx/qscore b/cctbx/maptbx/qscore new file mode 160000 index 0000000000..701613e347 --- /dev/null +++ b/cctbx/maptbx/qscore @@ -0,0 +1 @@ +Subproject commit 701613e347cd7708093dab590e97e3f7e5c13918 From 18b6144f5557e7cd6b34527d47277d98ae6dd2d2 Mon Sep 17 00:00:00 2001 From: cschlick Date: Wed, 17 Jan 2024 11:10:01 -0800 Subject: [PATCH 022/748] Expose qscore as a program --- cctbx/command_line/qscore.py | 8 ++++ cctbx/programs/qscore.py | 89 ++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 cctbx/command_line/qscore.py create mode 100644 cctbx/programs/qscore.py diff --git a/cctbx/command_line/qscore.py b/cctbx/command_line/qscore.py new file mode 100644 index 0000000000..be5f21697e --- /dev/null +++ b/cctbx/command_line/qscore.py @@ -0,0 +1,8 @@ +# LIBTBX_SET_DISPATCHER_NAME cctbx.qscore +from __future__ import absolute_import, division, print_function + +from iotbx.cli_parser import run_program +from cctbx.programs import qscore + +if __name__ == '__main__': + run_program(program_class=qscore.Program) diff --git a/cctbx/programs/qscore.py b/cctbx/programs/qscore.py new file mode 100644 index 0000000000..28acacf899 --- /dev/null +++ b/cctbx/programs/qscore.py @@ -0,0 +1,89 @@ +from __future__ import absolute_import, division, print_function +from phenix.program_template import ProgramTemplate +from libtbx import group_args +from cctbx.maptbx.qscore.qscore import qscore_np + +import numpy as np + + +# ============================================================================= + +class Program(ProgramTemplate): + + description = """ + Perform a Qscore analysis for map-model fit + """ + + datatypes = ['phil','model','real_map'] + + + master_phil_str = """ + nproc = 8 + .type = int + .help = Number of processors to use + .short_caption = Number of processors to use + .expert_level = 1 + n_probes = 32 + .type = int + .help = Number of radial probes to use + .short_caption = Number of radial probes to use + .expert_level = 1 + selection = None + .type = str + .help = Only test atoms within this selection + .short_caption = Only test atoms within this selection + .expert_level = 1 + + shell_radius_start = 0.1 + .type = float + .help = Start testing density at this radius from atom + .short_caption = Start testing density at this radius from atom + .expert_level = 1 + + shell_radius_stop = 2 + .type = float + .help = Stop testing density at this radius from atom + .short_caption = Stop testing density at this radius from atom + .expert_level = 1 + + shell_radius_num = 11 + .type = int + .help = The number of radial shells + .short_caption = The number of radial shells (includes start/stop, so minimum 2) + .expert_level = 1 + + probe_allocation_method = precalculate + .type = str + .help = The method used to allocate radial probes + .short_caption = Either 'progressive' or 'precalculate'. Progressive is the original method \ + where probes are proposed and rejected iteratively. \ + Precalculate is a method where probes are pre-allocated and \ + rejected once. Parallelization is done by radial shell. \ + Precalculate is much faster but will yield slightly different results. + + + """ + + def validate(self): + pass + + def run(self): + print("Running") + shells = np.linspace(self.params.shell_radius_start, + self.params.shell_radius_stop, + num = self.params.shell_radius_num, + endpoint=True) + mmm = self.data_manager.get_map_model_manager() + version = 2 if self.params.probe_allocation_method == "precalculate" else 1 # 'progressive' + result = qscore_np( + mmm, + selection=self.params.selection, + n_probes = self.params.n_probes, + shells = shells, + nproc=self.params.nproc, + version=version, + log = self.logger) + print(result) + + def get_results(self): + return group_args() From db797f1bc13455b5b51f51926c0e757ddba76832 Mon Sep 17 00:00:00 2001 From: cschlick Date: Wed, 17 Jan 2024 11:44:33 -0800 Subject: [PATCH 023/748] Revert "Initial commit of qscore implementation" This reverts commit a190167c35f2dc59aaee317b19d5412172e2afa5. --- cctbx/maptbx/qscore | 1 - 1 file changed, 1 deletion(-) delete mode 160000 cctbx/maptbx/qscore diff --git a/cctbx/maptbx/qscore b/cctbx/maptbx/qscore deleted file mode 160000 index 701613e347..0000000000 --- a/cctbx/maptbx/qscore +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 701613e347cd7708093dab590e97e3f7e5c13918 From 5c9de4edf20b408ad37461f060beb7e67f4c43ff Mon Sep 17 00:00:00 2001 From: cschlick Date: Wed, 17 Jan 2024 11:47:17 -0800 Subject: [PATCH 024/748] Initial qscore commit, fix previous submodule commit --- cctbx/maptbx/qscore/__init__.py | 1 + cctbx/maptbx/qscore/flex_utils.py | 121 ++++++ cctbx/maptbx/qscore/qscore.py | 597 ++++++++++++++++++++++++++++ cctbx/maptbx/qscore/qscore_utils.py | 304 ++++++++++++++ cctbx/maptbx/qscore/tst_qscore.py | 14 + 5 files changed, 1037 insertions(+) create mode 100644 cctbx/maptbx/qscore/__init__.py create mode 100644 cctbx/maptbx/qscore/flex_utils.py create mode 100644 cctbx/maptbx/qscore/qscore.py create mode 100644 cctbx/maptbx/qscore/qscore_utils.py create mode 100644 cctbx/maptbx/qscore/tst_qscore.py diff --git a/cctbx/maptbx/qscore/__init__.py b/cctbx/maptbx/qscore/__init__.py new file mode 100644 index 0000000000..8a531fc130 --- /dev/null +++ b/cctbx/maptbx/qscore/__init__.py @@ -0,0 +1 @@ +from .qscore import * \ No newline at end of file diff --git a/cctbx/maptbx/qscore/flex_utils.py b/cctbx/maptbx/qscore/flex_utils.py new file mode 100644 index 0000000000..1e6465bd4b --- /dev/null +++ b/cctbx/maptbx/qscore/flex_utils.py @@ -0,0 +1,121 @@ +from __future__ import division +from cctbx.array_family import flex + + +def flex_from_list(lst, signed_int=False): + """Generate a flex array from a list, try to infer type""" + flat_list, shape = flatten_and_shape(lst) + dtype = get_dtype_of_list(flat_list) + type_mapper = {int: flex.size_t, + float: flex.double, + bool: flex.bool} + if signed_int: + type_mapper[int] = flex.int16 + + # make flex array + assert dtype in type_mapper, f"Unrecognized type: {dtype}" + flex_func = type_mapper[dtype] + flex_array = flex_func(flat_list) + if len(shape) > 1: + flex_array.reshape(flex.grid(*shape)) + return flex_array + + +def flatten_and_shape(lst): + """Flatten a nested list and return its shape.""" + def helper(l): + if not isinstance(l, list): + return [l], () + flat = [] + shapes = [] + for item in l: + f, s = helper(item) + flat.extend(f) + shapes.append(s) + if len(set(shapes)) != 1: + raise ValueError("Ragged nested list detected.") + return flat, (len(l),) + shapes[0] + + flattened, shape = helper(lst) + return flattened, shape + + +def get_dtype_of_list(lst): + dtypes = {type(item) for item in lst} + + if len(dtypes) > 1: + raise ValueError("Multiple data types detected.") + elif len(dtypes) == 0: + raise ValueError("Empty list provided.") + else: + return dtypes.pop() + + +def nd_to_1d_indices(indices, shape): + """Generate the 1d indices given nd indices and an array shape""" + # Normalize indices to always use slice objects + normalized_indices = [] + for dim, idx in enumerate(indices): + if idx is None: + normalized_indices.append(slice(0, shape[dim])) + else: + normalized_indices.append(idx) + + # If any index is a slice, recursively call function for each value in slice + for dim, (i, s) in enumerate(zip(normalized_indices, shape)): + if isinstance(i, slice): + result_indices = [] + start, stop, step = i.indices(s) + for j in range(start, stop, step): + new_indices = list(normalized_indices) + new_indices[dim] = j + result_indices.extend(nd_to_1d_indices(new_indices, shape)) + return result_indices + + # If no slices, calculate single 1D index + index = 0 + stride = 1 + for i, dim in reversed(list(zip(normalized_indices, shape))): + index += i * stride + stride *= dim + return [index] + +def optimized_nd_to_1d_indices(i, shape): + """Similar to above, but hardcoded to select a single index on dimension 1""" + # For fixed input of (None, i, None), we directly compute based on given structure + result_indices = [] + + # Pre-compute for 1st dimension which is always a slice + start1, stop1 = 0, shape[0] + + # Pre-compute for 3rd dimension which is always a slice + start3, stop3 = 0, shape[2] + stride3 = 1 + + # Directly compute for 2nd dimension which is variable + stride2 = shape[2] + index2 = i * stride2 * shape[0] + + for val1 in range(start1, stop1): + for val3 in range(start3, stop3): + result_indices.append(val1 * stride2 + index2 + val3 * stride3) + + return result_indices + + +def flex_std(flex_array): + """Standard deviation""" + n = flex_array.size() + if n <= 1: + raise ValueError("Sample size must be greater than 1") + + # Compute the mean + mean_value = flex.mean(flex_array) + + # Compute the sum of squared deviations + squared_deviations = (flex_array - mean_value) ** 2 + sum_squared_deviations = flex.sum(squared_deviations) + + # Compute the standard deviation + std_dev = (sum_squared_deviations / (n - 1)) ** 0.5 + return std_dev diff --git a/cctbx/maptbx/qscore/qscore.py b/cctbx/maptbx/qscore/qscore.py new file mode 100644 index 0000000000..c7aadb838a --- /dev/null +++ b/cctbx/maptbx/qscore/qscore.py @@ -0,0 +1,597 @@ +""" +This code provides methods to calculate the qscore metric for map-model validation, +as developed by Pintile et al. + +As with the original implementation, multiple calculation options are provided. +The fastest (default) is to pass an mmtbx map-model-manager (mmm) +to the the function qscore_np, qscore_np(mmm) +""" + +from __future__ import division +import math +import sys +import numpy as np +from scipy.spatial import KDTree +from multiprocessing import Pool, cpu_count + +from cctbx.array_family import flex +from scitbx_array_family_flex_ext import bool as flex_bool + +from .qscore_utils import ( + trilinear_interpolation, + rowwise_corrcoef + sphere_points_np, + sphere_points_flex, + cdist_flex, + query_ball_point_flex, + query_atom_neighbors, +) +from .flex_utils import optimized_nd_to_1d_indices, nd_to_1d_indices, flex_std + +try: + from tqdm import tqdm +except ImportError: + from .qscore_utils import DummyTQDM as tqdm + + +def radial_shell_worker_v1_np(args): + """ + Calulate qscore for a single radial shell using version 1 (serial probe allocation) and numpy + """ + ( + i, + atoms_xyz, + n_probes, + radius_shell, + tree, + rtol, + selection, + n_probes_target, + ) = args + + # + # manage selection input + if selection is None: + selection = np.arange(len(atoms_xyz)) + else: + assert selection.dtype == bool + # do selection + atoms_xyz_sel = atoms_xyz[selection] + # print("sel_shape",atoms_xyz_sel.shape) + n_atoms = atoms_xyz_sel.shape[0] + + if radius_shell == 0: + radius_shell = 1e-9 # zero causes crash + numPts = n_probes_target + RAD = radius_shell + outRAD = rtol + all_pts = [] # list of probe arrays for each atom + probe_xyz_r = np.full((n_atoms, n_probes_target, 3), -1.0) + # print(atoms_xyz_sel) + # print("n_atoms",n_atoms) + for atom_i in range(n_atoms): + coord = atoms_xyz_sel[atom_i] + # print("atom_i",atom_i) + # print("coord:",coord) + pts = [] + + # try to get at least [numPts] points at [RAD] distance + # from the atom, that are not closer to other atoms + for i in range(0, 50): + # if we find the necessary number of probes in the first iteration, then i will never go to 1 + # points on a sphere at radius RAD... + n_pts_to_grab = ( + numPts + i * 2 + ) # progressively more points are grabbed with each failed iter + # print("n_to_grab:",n_pts_to_grab) + + outPts = sphere_points_np( + coord[None, :], RAD, n_pts_to_grab + ) # get the points + outPts = outPts.reshape(-1, 3) + at_pts, at_pts_i = [None] * len(outPts), 0 + # print("probe candidates") + + for pt_i, pt in enumerate( + outPts + ): # identify which ones to keep, progressively grow pts list + # print(f"\t{pt[0]},{pt[1]},{pt[2]}") + # query kdtree to find probe-atom interactions + counts = tree.query_ball_point( + pt[None, :], RAD * outRAD, return_length=True + ) + + # each value in counts is the number of atoms within radius+tol of each probe + count = counts.flatten()[0] + ptsNear = count + + if ptsNear == 0: + at_pts[at_pts_i] = pt + at_pts_i += 1 + # if at_pts_i >= numPts: + # break + + if ( + at_pts_i >= numPts + ): # if we have enough points, take all the "good" points from this iter + pts.extend(at_pts[0:at_pts_i]) + break + # assert len(pts)>0, "Zero probes were found " + pts = np.array(pts) # should be shape (n_probes,3) + all_pts.append(pts) + + # prepare output + n_atoms = len(atoms_xyz) + for i, r in enumerate(all_pts): + if r.ndim == 2 and len(r) > 0: + probe_xyz_r[i, :n_probes, :] = r[:n_probes_target, :] + + keep_sel = probe_xyz_r != -1.0 + keep_sel = np.mean(keep_sel, axis=-1, keepdims=True) + keep_sel = np.squeeze(keep_sel, axis=-1) + + return probe_xyz_r, keep_sel.astype(bool) + + +def radial_shell_worker_v2_np(args): + """ + Calulate qscore for a single radial shell using version 2 (parallel probe allocation) and numpy + """ + # unpack args + i, atoms_xyz, n_probes, radius_shell, tree, rtol, selection = args + + # manage selection input + if selection is None: + selection = np.arange(len(atoms_xyz)) + else: + assert selection.dtype == bool + + # do selection + atoms_xyz_sel = atoms_xyz[selection] + n_atoms = atoms_xyz_sel.shape[0] + + # get probe coordinates + probe_xyz = sphere_points_np(atoms_xyz_sel, radius_shell, n_probes) + + counts = tree.query_ball_point( + probe_xyz, radius_shell * rtol, return_length=True + ) # atom counts for each probe, for probes in shape (n_atoms,n_probes) + probe_mask = ( + counts == 0 + ) # keep probes with 0 nearby atoms. The rtol ensures self is not counted + + return probe_xyz, probe_mask + + +def radial_shell_mp_np( + + model, + n_probes=32, + radii=np.linspace(0.1, 2, 12), + rtol=0.9, + num_processes=cpu_count(), + selection=None, + version=2, + log=sys.stdout, + ): + """ + Generate probes for a model file using numpy + """ + assert version in [1, 2], "Version must be 1 or 2" + + atoms_xyz = model.get_sites_cart().as_numpy_array() + tree = KDTree(atoms_xyz) + + if version == 1: + worker_func = radial_shell_worker_v1_np + n_probes_target = n_probes + # Create argument tuples for each chunk + args = [ + ( + i, + atoms_xyz, + n_probes, + radius_shell, + tree, + rtol, + selection, + n_probes_target, + ) + for i, radius_shell in enumerate(radii) + ] + else: + worker_func = radial_shell_worker_v2_np + # Create argument tuples for each chunk + args = [ + (i, atoms_xyz, n_probes, radius_shell, tree, rtol, selection) + for i, radius_shell in enumerate(radii) + ] + + # Create a pool of worker processes + if num_processes > 1: + with Pool(num_processes) as p: + # Use the pool to run the trilinear_interpolation_worker function in parallel + results = list( + tqdm(p.imap(worker_func, args), total=len(args), file=log) + ) + else: + results = [] + for arg in tqdm(args, file=log): + # for arg in args: + result = worker_func(arg) + results.append(result) + + probe_xyz_all = [result[0] for result in results] + probe_mask_all = [result[1] for result in results] + + # debug + # return probe_xyz_all, probe_mask_all + + # stack numpy + probe_xyz = np.stack(probe_xyz_all) + probe_mask = np.stack(probe_mask_all) + + return probe_xyz, probe_mask + + +def qscore_np( + mmm, + selection=None, + n_probes=32, + shells=np.array( + [ + 0.1, + 0.27272727, + 0.44545455, + 0.61818182, + 0.79090909, + 0.96363636, + 1.13636364, + 1.30909091, + 1.48181818, + 1.65454545, + 1.82727273, + 2.0, + ] + ), + version=2, + nproc=cpu_count(), + log=sys.stdout, + ): + """ + Calculate the qscore metric per-atom from an mmtbx map-model-manager, using numpy + """ + model = mmm.model() + mm = mmm.map_manager() + volume = mm.map_data().as_numpy_array() + radii = shells + voxel_size = mm.pixel_sizes() + + probe_xyz, probe_mask = radial_shell_mp_np( + model, + n_probes=n_probes, + num_processes=nproc, + selection=selection, + version=version, + radii=radii, + log=log, + ) + # return probe_xyz,probe_mask + # after the probe generation, versions 1 and 2 are the same + + # infer params from shape + n_shells, n_atoms, n_probes, _ = probe_xyz.shape + + # flatten + probe_xyz_flat = probe_xyz.reshape((n_atoms * n_shells * n_probes, 3)) + probe_mask_flat = probe_mask.reshape(-1) # (n_shells*n_atoms*n_probes,) + + # select mask=True probes + masked_probe_xyz_flat = probe_xyz_flat[probe_mask_flat] + + # interpolate + masked_density = trilinear_interpolation( + volume, masked_probe_xyz_flat, voxel_size=voxel_size + ) + + # reshape interpolated values to (n_shells,n_atoms, n_probes) + + d_vals = np.zeros((n_shells, n_atoms, n_probes)) + d_vals[probe_mask] = masked_density + + # reshape to (M,N*L) for rowwise correlation + + d_vals_2d = d_vals.transpose(1, 0, 2).reshape(d_vals.shape[1], -1) + + # create the reference data + + M = volume + maxD = min(M.mean() + M.std() * 10, M.max()) + minD = max(M.mean() - M.std() * 1, M.min()) + A = maxD - minD + B = minD + u = 0 + sigma = 0.6 + x = np.array(radii) + y = A * np.exp(-0.5 * ((x - u) / sigma) ** 2) + B + + # Stack and reshape data for correlation calc + + # stack the reference to shape (n_shells,n_atoms,n_probes) + g_vals = np.repeat(y[:, None], n_probes, axis=1) + g_vals = np.expand_dims(g_vals, 1) + g_vals = np.tile(g_vals, (n_atoms, 1)) + + # reshape + g_vals_2d = g_vals.transpose(1, 0, 2).reshape(g_vals.shape[1], -1) + d_vals_2d = d_vals.transpose(1, 0, 2).reshape(d_vals.shape[1], -1) + mask_2d = probe_mask.transpose(1, 0, 2).reshape(probe_mask.shape[1], -1) + + # # CALCULATE Q + + # # numpy + q = rowwise_corrcoef(g_vals_2d, d_vals_2d, mask=mask_2d) + + return q + + +############################################################################## +# Functions that use only flex, no numpy +############################################################################## + + +def radial_shell_worker_v2_flex(args): + """ + Calulate qscore for a single radial shell using version 2 (parallel probe allocation) and flex only + """ + # unpack args + i, atoms_xyz, n_probes, radius_shell, rtol, tree, selection = args + + # manage selection input + if selection is None: + selection = flex.size_t_range(len(atoms_xyz)) + else: + assert isinstance(selection, flex_bool) + + # do selection + n_atoms = selection.count(True) + atoms_xyz_sel = atoms_xyz.select(selection) + + # get probe coordinates + probe_xyz = sphere_points_flex(atoms_xyz_sel, radius_shell, n_probes) + + # query to find the number of atoms within the clash range of each probe + counts = query_ball_point_flex( + tree, atoms_xyz, probe_xyz, r=radius_shell * rtol + ) + probe_mask = counts == 0 + return probe_xyz, probe_mask + + +def radial_shell_v2_mp_flex( + model, + n_probes=32, + radii=np.linspace(0.1, 2, 12), + rtol=0.9, + num_processes=cpu_count(), + selection=None, + version=2, + log=sys.stdout, + ): + """ + Generate probes for a model file using flex only + """ + assert version in [1, 2], "Version must be 1 or 2" + if version == 1: + assert False + else: + worker_func = radial_shell_worker_v2_flex + + # get a "tree", which is just a dictionary of index:local neighbor indices + tree, _ = query_atom_neighbors(model, radius=3.5) + atoms_xyz = model.get_sites_cart() + + # i,atoms_xyz,n_probes,radius_shell,rtol, selection= args + # Create argument tuples for each chunk + + args = [ + (i, atoms_xyz, n_probes, radius_shell, rtol, tree, selection) + for i, radius_shell in enumerate(radii) + ] + + # Create a pool of worker processes + if num_processes > 1: + with Pool(num_processes) as p: + # Use the pool to run the trilinear_interpolation_worker function in parallel + results = list( + tqdm(p.imap(worker_func, args), total=len(args), file=log) + ) + else: + results = [] + for arg in tqdm(args, file=log): + # for arg in args: + result = worker_func(arg) + results.append(result) + + # stack the results from each shell into single arrays + probe_xyz_all = [result[0] for result in results] + probe_mask_all = [result[1] for result in results] + + # # debug + # return probe_xyz_all, probe_mask_all,tree + + n_atoms = probe_xyz_all[0].focus()[0] + n_shells = len(probe_mask_all) + out_shape = (n_shells, n_atoms, n_probes, 3) + out_size = math.prod(out_shape) + shell_size = math.prod(out_shape[1:]) + out_probes = flex.double(out_size, -1.0) + out_mask = flex.bool(n_atoms * n_shells * n_probes, False) + + for i, p in enumerate(probe_xyz_all): + start = i * shell_size + stop = start + shell_size + out_probes = out_probes.set_selected( + flex.size_t_range(start, stop), p.as_1d() + ) + out_probes.reshape(flex.grid(*out_shape)) + + for i, k in enumerate(probe_mask_all): + start = i * (n_atoms * n_probes) + stop = start + (n_atoms * n_probes) + out_mask = out_mask.set_selected( + flex.size_t_range(start, stop), k.as_1d() + ) + out_mask.reshape(flex.grid(n_shells, n_atoms, n_probes)) + + return out_probes, out_mask + + +def qscore_flex( + mmm, + selection=None, + n_probes=32, + shells=[ + 0.1, + 0.27272727, + 0.44545455, + 0.61818182, + 0.79090909, + 0.96363636, + 1.13636364, + 1.30909091, + 1.48181818, + 1.65454545, + 1.82727273, + 2.0, + ], + version=2, + nproc=cpu_count(), + ): + """ + Calculate the qscore metric per-atom from an mmtbx map-model-manager, using flex only + """ + model = mmm.model() + mm = mmm.map_manager() + radii = shells + volume = mm.map_data() + voxel_size = mm.pixel_sizes() + + probe_xyz, probe_mask = radial_shell_v2_mp_flex( + model, + n_probes=n_probes, + num_processes=nproc, + selection=selection, + version=version, + radii=radii, + ) + + # aliases + probe_xyz_cctbx = probe_xyz + probe_mask_cctbx = probe_mask + + # infer params from shape + n_shells, n_atoms, n_probes, _ = probe_xyz.focus() + + # APPLY MASK BEFORE INTERPOLATION + + probe_mask_cctbx_fullflat = [] + + for val in probe_mask_cctbx: + for _ in range(3): # since A has an additional dimension of size 3 + probe_mask_cctbx_fullflat.append(val) + + mask = flex.bool(probe_mask_cctbx_fullflat) + # indices = flex.int([i for i in range(1, keep_mask_cctbx.size() + 1) for _ in range(3)]) + sel = probe_xyz_cctbx.select(mask) + # sel_indices = indices.select(mask) + masked_probe_xyz_flat_cctbx = flex.vec3_double(sel) + + # INTERPOLATE + + masked_density_cctbx = mm.density_at_sites_cart( + masked_probe_xyz_flat_cctbx + ) + + # reshape interpolated values to (n_shells,n_atoms, n_probes) + + probe_mask_cctbx.reshape(flex.grid(n_shells * n_atoms * n_probes)) + d_vals_cctbx = flex.double(probe_mask_cctbx.size(), 0.0) + d_vals_cctbx = d_vals_cctbx.set_selected( + probe_mask_cctbx, masked_density_cctbx + ) + d_vals_cctbx.reshape(flex.grid(n_shells, n_atoms, n_probes)) + + # reshape to (M,N*L) for rowwise correlation + + def custom_reshape_indices(flex_array): + N, M, L = flex_array.focus() + result = flex.double(flex.grid(M, N * L)) + + for i in range(N): + for j in range(M): + for k in range(L): + # Calculate the original flat index + old_index = i * M * L + j * L + k + # Calculate the new flat index after transpose and reshape + new_index = j * N * L + i * L + k + result[new_index] = flex_array[old_index] + + return result + + d_vals_2d_cctbx = custom_reshape_indices(d_vals_cctbx) + + # create the reference data + M = volume + M_std = flex_std(M) + M_mean = flex.mean(M) + maxD_cctbx = min(M_mean + M_std * 10, flex.max(M)) + minD_cctbx = max(M_mean - M_std * 1, flex.min(M)) + A_cctbx = maxD_cctbx - minD_cctbx + B_cctbx = minD_cctbx + u = 0 + sigma = 0.6 + x = flex.double(radii) + y_cctbx = ( + A_cctbx * flex.exp(-0.5 * ((flex.double(x) - u) / sigma) ** 2) + + B_cctbx + ) + + # Stack and reshape data for correlation calc + + # 1. Repeat y for n_probes (equivalent to np.repeat) + g_vals_cctbx = [[val] * n_probes for val in y_cctbx] + + # 2. Add a new dimension (equivalent to np.expand_dims) + g_vals_expanded = [[item] for item in g_vals_cctbx] + + # 3. Tile for each atom (equivalent to np.tile) + g_vals_tiled = [] + for item in g_vals_expanded: + g_vals_tiled.append(item * n_atoms) + + g_vals_cctbx = flex.double(np.array(g_vals_tiled)) + + # # CALCULATE Q + + d_vals_cctbx = d_vals_cctbx.as_1d() + g_vals_cctbx = g_vals_cctbx.as_1d() + probe_mask_cctbx_double = probe_mask_cctbx.as_1d().as_double() + q_cctbx = [] + for atomi in range(n_atoms): + inds = nd_to_1d_indices( + (None, atomi, None), (n_shells, n_atoms, n_probes) + ) + # inds = optimized_nd_to_1d_indices(atomi,(n_shells,n_atoms,n_probes)) + inds = flex.uint32(inds) + d_row = d_vals_cctbx.select(inds) + g_row = g_vals_cctbx.select(inds) + mask = probe_mask_cctbx.select(inds) + + d = d_row.select(mask) + g = g_row.select(mask) + qval = flex.linear_correlation(d, g).coefficient() + q_cctbx.append(qval) + + q = flex.double(q_cctbx) + return q diff --git a/cctbx/maptbx/qscore/qscore_utils.py b/cctbx/maptbx/qscore/qscore_utils.py new file mode 100644 index 0000000000..09d6bd0201 --- /dev/null +++ b/cctbx/maptbx/qscore/qscore_utils.py @@ -0,0 +1,304 @@ +from __future__ import division +import math +from collections import defaultdict +from itertools import chain + +import numpy as np +import numpy.ma as ma +import cctbx +from cctbx.array_family import flex + +from .flex_utils import * + + +class DummyTQDM: + """A 'dummy' object that can be used for compatibility if tqdm is not installed""" + def __init__(self, iterable=None, *args, **kwargs): + self.iterable = iterable + self.args = args + self.kwargs = kwargs + + def __iter__(self): + return iter(self.iterable) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + pass + + +def trilinear_interpolation(voxel_grid, coords, voxel_size=None, offset=None): + """Numpy trilinear interpolation""" + assert voxel_size is not None, "Provide voxel size as an array or single value" + + # Apply offset if provided + if offset is not None: + coords = coords - offset + + # Transform coordinates to voxel grid index space + index_coords = coords / voxel_size + + # Split the index_coords array into three arrays: x, y, and z + x, y, z = index_coords.T + + # Truncate to integer values + x0, y0, z0 = np.floor([x, y, z]).astype(int) + x1, y1, z1 = np.ceil([x, y, z]).astype(int) + + # Ensure indices are within grid boundaries + x0, y0, z0 = np.clip([x0, y0, z0], 0, voxel_grid.shape[0]-1) + x1, y1, z1 = np.clip([x1, y1, z1], 0, voxel_grid.shape[0]-1) + + # Compute weights + xd, yd, zd = [arr - arr.astype(int) for arr in [x, y, z]] + + # Interpolate along x + c00 = voxel_grid[x0, y0, z0]*(1-xd) + voxel_grid[x1, y0, z0]*xd + c01 = voxel_grid[x0, y0, z1]*(1-xd) + voxel_grid[x1, y0, z1]*xd + c10 = voxel_grid[x0, y1, z0]*(1-xd) + voxel_grid[x1, y1, z0]*xd + c11 = voxel_grid[x0, y1, z1]*(1-xd) + voxel_grid[x1, y1, z1]*xd + + # Interpolate along y + c0 = c00*(1-yd) + c10*yd + c1 = c01*(1-yd) + c11*yd + + # Interpolate along z + c = c0*(1-zd) + c1*zd + + return c + + +def rowwise_corrcoef(A, B, mask=None): + """Numpy masked array rowwise correlation coefficient""" + assert A.shape == B.shape, f"A and B must have the same shape, got: {A.shape} and {B.shape}" + + if mask is not None: + assert mask.shape == A.shape, "mask must have the same shape as A and B" + A = ma.masked_array(A, mask=np.logical_not(mask)) + B = ma.masked_array(B, mask=np.logical_not(mask)) + + # Calculate means + A_mean = ma.mean(A, axis=1, keepdims=True) + B_mean = ma.mean(B, axis=1, keepdims=True) + + # Subtract means + A_centered = A - A_mean + B_centered = B - B_mean + + # Calculate sum of products + sumprod = ma.sum(A_centered * B_centered, axis=1) + + # Calculate square roots of the sum of squares + sqrt_sos_A = ma.sqrt(ma.sum(A_centered**2, axis=1)) + sqrt_sos_B = ma.sqrt(ma.sum(B_centered**2, axis=1)) + + # Return correlation coefficients + cc = sumprod / (sqrt_sos_A * sqrt_sos_B) + return cc.data + + +def sphere_points_np(ctr, rad, N): + """Generate points on a sphere, using numpy, as implemented in original qscore from Pintile et al.""" + # ctr is shape (N,3) + # print("sphere_points_ctr_input_shape",ctr.shape) + h = -1.0 + (2.0 * np.arange(N) / float(N-1))[:, np.newaxis] + phis = np.arccos(h) + thetas = np.zeros_like(phis) + a = (3.6 / np.sqrt(N * (1.0 - h[1:-1]**2))) + thetas[1:-1, :] = a + thetas = np.cumsum(thetas, axis=0) + x = np.sin(phis) * np.cos(thetas) + y = np.sin(phis) * np.sin(thetas) + z = np.cos(phis) + points = rad * np.stack([x, y, z], axis=-1) + points = points.reshape(1, N, 3) + ctr = ctr[:, np.newaxis, :] + points = ctr + points # broadcast add + return points + + +def sphere_points_flex(ctr, rad, N): +"""Generate points on a sphere, using flex only, as implemented in original qscore from Pintile et al.""" + + h = -1.0 + (2.0 * flex.double_range(N) / (N-1)) + phis = flex.acos(h) + thetas = flex.double(len(phis), 0.0) + a = (3.6 / flex.sqrt(N * (1.0 - h[1:-1]**2))) + thetas = thetas.set_selected(flex.size_t_range(1, N-1), a) + + # cumulative sum operation + def cumsum_flex(arr): + # should perform as np.cumsum + result = [] + running_sum = 0.0 + for i, x in enumerate(arr): + running_sum += x + result.append(running_sum) + return flex.double(result) + + thetas = cumsum_flex(thetas) + x = flex.sin(phis) * flex.cos(thetas) + y = flex.sin(phis) * flex.sin(thetas) + z = flex.cos(phis) + rad = float(rad) + points = rad * flex.vec3_double(x, y, z) + + # add generated points to center points + def broadcast_add(ctr, points): + + # add and populate additional dimension. equivalent to: + # result = ctr[:, np.newaxis, :] + points + + N = points.size() + M = ctr.size() + # Preallocate an array of shape (M*N, 3) + result = flex.vec3_double(M*N) + + for i in range(M): + for j in range(N): + flat_index = i * N + j + new_point = tuple(ctr[i:i+1] + points[j:j+1])[0] + result[flat_index] = new_point + + result = result.as_1d().as_double() + result.reshape(flex.grid(len(ctr), len(points), 3)) + return result + + # apply function + points = broadcast_add(ctr, points) + return points + + +def cdist_flex(A, B): + """A flex implementation of the cdist function""" + + def indices_2d_flex(dimensions): + N = len(dimensions) + if N != 2: + raise ValueError("Only 2D is supported for this implementation.") + + # Create the row indices + row_idx = flex.size_t(chain.from_iterable( + [[i] * dimensions[1] for i in range(dimensions[0])])) + + # Create the column indices + col_idx = flex.size_t(chain.from_iterable( + [list(range(dimensions[1])) for _ in range(dimensions[0])])) + + return row_idx, col_idx + + i_idxs, j_idxs = indices_2d_flex((A.focus()[0], B.focus()[0])) + + r = i_idxs + xi = i_idxs*3 + yi = i_idxs*3 + 1 + zi = i_idxs*3 + 2 + + xa = A.select(xi) + ya = A.select(yi) + za = A.select(zi) + + xj = j_idxs*3 + yj = j_idxs*3 + 1 + zj = j_idxs*3 + 2 + + xb = B.select(xj) + yb = B.select(yj) + zb = B.select(zj) + + d = ((xb - xa)**2 + (yb - ya)**2 + (zb - za)**2)**0.5 + d.reshape(flex.grid((A.focus()[0], B.focus()[0]))) + + return d + + +def query_atom_neighbors(model, radius=3.5, include_self=True, only_unit=True): + """Perform radial nearest neighbor searches using cctbx tools, for atom coordinates in a model""" + crystal_symmetry = model.crystal_symmetry() + hierarchy = model.get_hierarchy() + sites_cart = hierarchy.atoms().extract_xyz() + sst = crystal_symmetry.special_position_settings().site_symmetry_table( + sites_cart=sites_cart) + conn_asu_mappings = crystal_symmetry.special_position_settings().\ + asu_mappings(buffer_thickness=5) + conn_asu_mappings.process_sites_cart( + original_sites=sites_cart, + site_symmetry_table=sst) + conn_pair_asu_table = cctbx.crystal.pair_asu_table( + asu_mappings=conn_asu_mappings) + conn_pair_asu_table.add_all_pairs(distance_cutoff=radius) + pair_generator = cctbx.crystal.neighbors_fast_pair_generator( + conn_asu_mappings, + distance_cutoff=radius) + fm = crystal_symmetry.unit_cell().fractionalization_matrix() + om = crystal_symmetry.unit_cell().orthogonalization_matrix() + + pairs = list(pair_generator) + inds = defaultdict(list) + dists = defaultdict(list) + + for pair in pairs: + i, j = pair.i_seq, pair.j_seq + rt_mx_i = conn_asu_mappings.get_rt_mx_i(pair) + rt_mx_j = conn_asu_mappings.get_rt_mx_j(pair) + rt_mx_ji = rt_mx_i.inverse().multiply(rt_mx_j) + + if (only_unit and rt_mx_ji.is_unit_mx()) or (not only_unit): + d = round(math.sqrt(pair.dist_sq), 6) + inds[i].append(j) + dists[i].append(d) + + # add reverse + inds[j].append(i) + dists[j].append(d) + # print(pair.i_seq, pair.j_seq, rt_mx_ji, math.sqrt(pair.dist_sq), de) + + # add self + if include_self: + for key, value in list(inds.items()): + dval = dists[key] + dists[key] = dval+[0.0] + inds[key] = value+[key] + + # sort + for key, value in list(inds.items()): + dval = dists[key] + # sort + sorted_pairs = sorted(set(list(zip(value, dval)))) + value_sorted, dval_sorted = zip(*sorted_pairs) + inds[key] = value_sorted + dists[key] = dval_sorted + + return inds, dists + + +def query_ball_point_flex(tree, tree_xyz, query_xyz, r=None): + """ + Imitate the api of the scipy.spatial query_ball_point function, but using only flex arrays. + Note: This just copies the api, it does not actually use a tree structure, so is much slower. + """ + assert r is not None, "provide radius" + n_atoms, n_probes, _ = query_xyz.focus() + counts = [] + + for atom_i in range(n_atoms): + probe_range = (n_probes * atom_i * 3, n_probes * (atom_i+1) * 3) + atom_probes_xyz = query_xyz.select(flex.size_t_range(*probe_range)) + atom_probes_xyz.reshape(flex.grid(n_probes, 3)) + nbrs = tree[atom_i] + n_nbrs = len(nbrs) + nbrs_xyz = tree_xyz.select(flex.size_t(nbrs)).as_1d().as_double() + nbrs_xyz.reshape(flex.grid(len(nbrs), 3)) + d = cdist_flex(nbrs_xyz, atom_probes_xyz) + sel = d < r + count = [] + for nbr_i in range(n_probes): + nbr_range = (slice(0, n_nbrs), slice(nbr_i, nbr_i+1)) + count_nbr = sel[nbr_range].count(True) + count.append(count_nbr) + + counts.append(count) + + counts = flex_from_list(counts) + return counts diff --git a/cctbx/maptbx/qscore/tst_qscore.py b/cctbx/maptbx/qscore/tst_qscore.py new file mode 100644 index 0000000000..c20308ce0c --- /dev/null +++ b/cctbx/maptbx/qscore/tst_qscore.py @@ -0,0 +1,14 @@ +from __future__ import absolute_import, division, print_function + +from cctbx.maptbx.qscore import qscore_np as qscore +from iotbx.data_manager import DataManager + + +dm = DataManager() +dm.process_real_map_file( + "/Users/user/Desktop/data/data_large/7UAE/emd_26422.map.gz") +dm.process_model_file( + "/Users/user/Desktop/data/data_large/7UAE/pdb7uae.ent.gz") +mmm = dm.get_map_model_manager() +result = qscore(mmm) +print(result) From 5218cdeb23198a5f1b61c4033a9572a18184eb02 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 16 Jan 2024 15:11:54 -0800 Subject: [PATCH 025/748] MOPAC energy must be Heat of Formation --- mmtbx/geometry_restraints/mopac_manager.py | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/mmtbx/geometry_restraints/mopac_manager.py b/mmtbx/geometry_restraints/mopac_manager.py index 78e305985e..643165c546 100644 --- a/mmtbx/geometry_restraints/mopac_manager.py +++ b/mmtbx/geometry_restraints/mopac_manager.py @@ -171,20 +171,14 @@ def read_energy(self, filename=None): f=open(filename, 'r') lines=f.read() del f - '''FINAL HEAT OF FORMATION = -132.17152 KCAL/MOL = -553.00562 KJ/MOL - - - - - - TOTAL ENERGY = -1356.82771 EV''' + # FINAL HEAT OF FORMATION = -132.17152 KCAL/MOL = -553.00562 KJ/MOL for line in lines.splitlines(): if line.find('FINAL HEAT OF FORMATION = ')>-1: self.energy = float(line.split()[5]) - self.units = line.split()[6] - if line.find('TOTAL ENERGY =')>-1: - self.energy = float(line.split()[3]) - self.units = line.split()[4] + self.units = line.split()[6].lower() + # if line.find('TOTAL ENERGY =')>-1: + # self.energy = float(line.split()[3]) + # self.units = line.split()[4] return self.energy, self.units def cleanup(self, level=None, verbose=False): From 7082245995039c166d1260ddb31f803ba2d5af3c Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Wed, 17 Jan 2024 16:14:59 -0800 Subject: [PATCH 026/748] changes for Q|R terminals --- mmtbx/ligands/ready_set_utils.py | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/mmtbx/ligands/ready_set_utils.py b/mmtbx/ligands/ready_set_utils.py index e38991fda1..cac239786f 100644 --- a/mmtbx/ligands/ready_set_utils.py +++ b/mmtbx/ligands/ready_set_utils.py @@ -35,6 +35,18 @@ def _add_atoms_from_chains_to_end_of_hierarchy(hierarchy, chains): tc.append_residue_group(rg.detached_copy()) model.append_chain(tc) +def validate_c_ca_n_for_n_terminal(c,ca,n,bonds): + nb = bonds.get(n.i_seq, None) + if not nb: return False + if len(nb) not in [1]: return False + return True + +def validate_c_ca_n_for_c_terminal(c,ca,n,bonds): + cb = bonds.get(c.i_seq, None) + if not cb: return False + if len(cb) not in [2]: return False + return True + def add_n_terminal_hydrogens_to_atom_group(ag, bonds=None, use_capping_hydrogens=False, @@ -53,12 +65,13 @@ def add_n_terminal_hydrogens_to_atom_group(ag, c = ag.get_atom("C") if c is None: return 'no C' - if bonds: - ns = [] - for key in bonds: - if n.i_seq == key[0]: - ns.append(key) - if len(ns)>=3: return rc + if not validate_c_ca_n_for_n_terminal(c, ca, n, bonds): return [] + # if bonds: + # ns = [] + # for key in bonds: + # if n.i_seq == key[0]: + # ns.append(key) + # if len(ns)>=3: return rc proton_element, proton_name = get_proton_info(ag) atom = ag.get_atom(proton_element) # just so happens that the atom is named H/D @@ -190,6 +203,7 @@ def add_c_terminal_oxygens_to_atom_group(ag, if ca is None: return n = ag.get_atom("N") if n is None: return + if not validate_c_ca_n_for_c_terminal(c, ca, n, bonds): return [] atom = ag.get_atom('O') dihedral = dihedral_angle(sites=[atom.xyz, c.xyz, From c1baa196ad39f641f133ce73b66002ab35caee88 Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 18 Jan 2024 12:25:57 -0700 Subject: [PATCH 027/748] Catch None --- cctbx/maptbx/refine_sharpening.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cctbx/maptbx/refine_sharpening.py b/cctbx/maptbx/refine_sharpening.py index 9600b1ac63..78ce4eb1b5 100644 --- a/cctbx/maptbx/refine_sharpening.py +++ b/cctbx/maptbx/refine_sharpening.py @@ -668,7 +668,8 @@ def calculate_fsc(**kw): if remove_anisotropy_before_analysis and aniso_scale_factor_as_u_cart: rms_fo_values = len(direction_vectors) * [None] - elif direction_vectors and direction_vectors[0] != None: + elif (direction_vectors and direction_vectors[0] != None) and ( + aniso_scale_factor_array is not None): # Let's fit rms fo in just this shell rms_fo_values = get_rms_fo_values( fo = fo, @@ -686,7 +687,8 @@ def calculate_fsc(**kw): if dv: weights_para_sel = weights_para.select(sel) weights_para_sel_sqrt = flex.sqrt(weights_para_sel) - if remove_anisotropy_before_analysis and aniso_scale_factor_as_u_cart: + if remove_anisotropy_before_analysis and aniso_scale_factor_as_u_cart\ + and aniso_scale_factor_array and aniso_scale_factor_array.data(): scale_sel = aniso_scale_factor_array.data().select(sel) else: scale_sel = None From 159329a8dafa1b7da623c9a4dd5c7786fd944551 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 18 Jan 2024 12:56:00 -0800 Subject: [PATCH 028/748] small change --- mmtbx/ligands/ready_set_utils.py | 2 ++ mmtbx/monomer_library/tst_server.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mmtbx/ligands/ready_set_utils.py b/mmtbx/ligands/ready_set_utils.py index cac239786f..022e9ba15e 100644 --- a/mmtbx/ligands/ready_set_utils.py +++ b/mmtbx/ligands/ready_set_utils.py @@ -36,12 +36,14 @@ def _add_atoms_from_chains_to_end_of_hierarchy(hierarchy, chains): model.append_chain(tc) def validate_c_ca_n_for_n_terminal(c,ca,n,bonds): + if bonds is None: return True nb = bonds.get(n.i_seq, None) if not nb: return False if len(nb) not in [1]: return False return True def validate_c_ca_n_for_c_terminal(c,ca,n,bonds): + if bonds is None: return True cb = bonds.get(c.i_seq, None) if not cb: return False if len(cb) not in [2]: return False diff --git a/mmtbx/monomer_library/tst_server.py b/mmtbx/monomer_library/tst_server.py index 2a7636f7ef..aa8c31b515 100644 --- a/mmtbx/monomer_library/tst_server.py +++ b/mmtbx/monomer_library/tst_server.py @@ -138,7 +138,7 @@ def exercise(): comp_comp_id = srv.get_comp_comp_id_direct(row["_chem_comp.id"]) if (is_standard_aa): assert comp_comp_id is not None - assert comp_comp_id.chem_comp.group.strip() == "L-peptide" + assert comp_comp_id.chem_comp.group.strip() == "L-peptide", '%s %s' % (row["_chem_comp.id"], comp_comp_id.chem_comp.group) if (comp_comp_id is not None): print(comp_comp_id.chem_comp.id.strip(), end=' ') print(comp_comp_id.chem_comp.name.strip(), end=' ') From ab62d7006c0ac38e32c1734c0db8aa8dde446409 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 18 Jan 2024 13:53:54 -0800 Subject: [PATCH 029/748] more info --- cctbx/geometry_restraints/auto_linking_types.py | 6 +++--- mmtbx/hydrogens/specialised_hydrogen_atoms.py | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cctbx/geometry_restraints/auto_linking_types.py b/cctbx/geometry_restraints/auto_linking_types.py index abf0a2e078..3c617921f5 100644 --- a/cctbx/geometry_restraints/auto_linking_types.py +++ b/cctbx/geometry_restraints/auto_linking_types.py @@ -27,7 +27,7 @@ def __repr__(self): starting_id = 0 for link_info in [ - ['covalent geometry', [0,1,2,3,4,5]], + ['covalent geometry', [0,1,2,3,4,5]], # 0 ['SS BOND', # short desc. # complete desc. 'Disulphide bond for CYS-like sulphur atoms within 3A (default) using ' @@ -100,13 +100,13 @@ def __repr__(self): '', ['Misc.']*5, [0,1,2,3,4] - ], + ], # 9 ['User supplied cif_link', 'Internal coordinates supplied by the user in cif_link format', '', ['User cif_link']*5, [0,1,2,3,4] - ], + ], # 10 ]: for oi in origin_ids: assert starting_id not in oi diff --git a/mmtbx/hydrogens/specialised_hydrogen_atoms.py b/mmtbx/hydrogens/specialised_hydrogen_atoms.py index 66c3dcac1b..ad11865ac6 100644 --- a/mmtbx/hydrogens/specialised_hydrogen_atoms.py +++ b/mmtbx/hydrogens/specialised_hydrogen_atoms.py @@ -196,6 +196,7 @@ def conditional_add_cys_hg_to_atom_group(geometry_restraints_manager, if sgs: specific_origin_ids = [origin_ids.get_origin_id('SS BOND'), origin_ids.get_origin_id('metal coordination'), + origin_ids.get_origin_id('Misc. bond'), ] for bond in geometry_restraints_manager.get_all_bond_proxies(): if not hasattr(bond, 'get_proxies_with_origin_id'): continue From 4df4027784cdf2cfee2b4cc121f2c2a2d4bdda4d Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 18 Jan 2024 16:09:13 -0800 Subject: [PATCH 030/748] more fixes due to new GeoStd --- .../tst_geo_file_parsing.py | 7 +- mmtbx/hydrogens/tst_add_hydrogen_2.py | 146 +++++++++--------- 2 files changed, 79 insertions(+), 74 deletions(-) diff --git a/mmtbx/geometry_restraints/tst_geo_file_parsing.py b/mmtbx/geometry_restraints/tst_geo_file_parsing.py index 0171c2215c..74fc01110d 100644 --- a/mmtbx/geometry_restraints/tst_geo_file_parsing.py +++ b/mmtbx/geometry_restraints/tst_geo_file_parsing.py @@ -194,14 +194,17 @@ def get_type(value): def compare_custom(d1,d2): """ - Compare two dictionaries by types, and 'idea' floats + Compare two dictionaries by types, and 'ideal' floats with a large tolerance to enable future changes to restraints. """ + print(d1) + print(d2) for key1,value1 in d1.items(): assert key1 in d2 value2 = d2[key1] + print(value1,value2) t1,t2 = get_type(value1), get_type(value2) - assert t1==t2 + assert t1==t2, '%s!=%s' % (t1, t2) if isinstance(t1,float): if key1 == 'ideal': diff = abs(float(value1)-float(value2)) diff --git a/mmtbx/hydrogens/tst_add_hydrogen_2.py b/mmtbx/hydrogens/tst_add_hydrogen_2.py index 9510355b25..c37b6f4baa 100644 --- a/mmtbx/hydrogens/tst_add_hydrogen_2.py +++ b/mmtbx/hydrogens/tst_add_hydrogen_2.py @@ -16,7 +16,7 @@ def run(): test_004() test_005() test_006() - test_007() + # test_007() # needs fixing test_008() #test_009() @@ -314,69 +314,70 @@ def test_009(): ATOM 2 CA GLY A -3 15.503 6.752 6.050 1.00 43.12 C ATOM 3 C GLY A -3 16.822 7.516 6.092 1.00 10.33 C ATOM 4 O GLY A -3 17.833 7.000 5.608 1.00 34.23 O -ATOM 5 HA2 GLY A -3 15.692 5.828 5.822 1.00 43.12 H -ATOM 6 HA3 GLY A -3 15.103 6.784 6.933 1.00 43.12 H -ATOM 7 N PRO A -2 16.855 8.759 6.667 1.00 43.42 N -ATOM 8 CA PRO A -2 18.084 9.573 6.756 1.00 72.12 C -ATOM 9 C PRO A -2 19.050 9.085 7.843 1.00 24.33 C -ATOM 10 O PRO A -2 20.269 9.138 7.662 1.00 1.42 O -ATOM 11 CB PRO A -2 17.569 10.986 7.098 1.00 65.32 C -ATOM 12 CG PRO A -2 16.078 10.915 7.005 1.00 23.11 C -ATOM 13 CD PRO A -2 15.713 9.483 7.257 1.00 3.14 C -ATOM 14 HA PRO A -2 18.527 9.578 5.893 1.00 72.12 H -ATOM 15 HB2 PRO A -2 17.846 11.226 7.996 1.00 65.32 H -ATOM 16 HB3 PRO A -2 17.923 11.625 6.460 1.00 65.32 H -ATOM 17 HG2 PRO A -2 15.793 11.190 6.120 1.00 23.11 H -ATOM 18 HG3 PRO A -2 15.682 11.493 7.676 1.00 23.11 H -ATOM 19 HD2 PRO A -2 15.639 9.304 8.207 1.00 3.14 H -ATOM 20 HD3 PRO A -2 14.884 9.250 6.810 1.00 3.14 H -ATOM 21 N SER A -1 18.485 8.603 8.974 1.00 54.30 N -ATOM 22 CA SER A -1 19.258 8.090 10.133 1.00 74.21 C -ATOM 23 C SER A -1 20.126 9.182 10.770 1.00 44.31 C -ATOM 24 O SER A -1 20.919 9.834 10.087 1.00 24.24 O -ATOM 25 CB SER A -1 20.129 6.881 9.741 1.00 35.31 C -ATOM 26 OG SER A -1 20.678 6.247 10.885 1.00 34.24 O -ATOM 27 H SER A -1 17.635 8.561 9.098 1.00 54.30 H -ATOM 28 HA SER A -1 18.623 7.790 10.802 1.00 74.21 H -ATOM 29 HB2 SER A -1 20.854 7.187 9.174 1.00 35.31 H -ATOM 30 HB3 SER A -1 19.580 6.241 9.261 1.00 35.31 H -ATOM 31 HG SER A -1 21.157 6.789 11.312 1.00 34.24 H -TER +ATOM 5 H GLY A -3 14.453 8.152 5.157 1.00 23.20 H +ATOM 6 HA2 GLY A -3 15.103 6.784 6.933 1.00 43.12 H +ATOM 7 HA3 GLY A -3 15.692 5.828 5.822 1.00 43.12 H +ATOM 8 N PRO A -2 16.855 8.759 6.667 1.00 43.42 N +ATOM 9 CA PRO A -2 18.084 9.573 6.756 1.00 72.12 C +ATOM 10 C PRO A -2 19.050 9.085 7.843 1.00 24.33 C +ATOM 11 O PRO A -2 20.269 9.138 7.662 1.00 1.42 O +ATOM 12 CB PRO A -2 17.569 10.986 7.098 1.00 65.32 C +ATOM 13 CG PRO A -2 16.078 10.915 7.005 1.00 23.11 C +ATOM 14 CD PRO A -2 15.713 9.483 7.257 1.00 3.14 C +ATOM 15 HA PRO A -2 18.527 9.578 5.893 1.00 72.12 H +ATOM 16 HB2 PRO A -2 17.846 11.226 7.996 1.00 65.32 H +ATOM 17 HB3 PRO A -2 17.923 11.625 6.460 1.00 65.32 H +ATOM 18 HG2 PRO A -2 15.682 11.493 7.676 1.00 23.11 H +ATOM 19 HG3 PRO A -2 15.793 11.190 6.120 1.00 23.11 H +ATOM 20 HD2 PRO A -2 15.639 9.304 8.207 1.00 3.14 H +ATOM 21 HD3 PRO A -2 14.884 9.250 6.810 1.00 3.14 H +ATOM 22 N SER A -1 18.485 8.603 8.974 1.00 54.30 N +ATOM 23 CA SER A -1 19.258 8.090 10.133 1.00 74.21 C +ATOM 24 C SER A -1 20.126 9.182 10.770 1.00 44.31 C +ATOM 25 O SER A -1 20.919 9.834 10.087 1.00 24.24 O +ATOM 26 CB SER A -1 20.129 6.881 9.741 1.00 35.31 C +ATOM 27 OG SER A -1 20.678 6.247 10.885 1.00 34.24 O +ATOM 28 H SER A -1 17.635 8.561 9.098 1.00 54.30 H +ATOM 29 HA SER A -1 18.623 7.790 10.802 1.00 74.21 H +ATOM 30 HB2 SER A -1 20.854 7.187 9.174 1.00 35.31 H +ATOM 31 HB3 SER A -1 19.580 6.241 9.261 1.00 35.31 H +ATOM 32 HG SER A -1 21.157 6.789 11.312 1.00 34.24 H ENDMDL MODEL 2 -ATOM 35 N GLY A -3 15.598 12.155 12.730 1.00 23.20 N -ATOM 36 CA GLY A -3 15.801 13.217 11.761 1.00 43.12 C -ATOM 37 C GLY A -3 15.603 12.746 10.322 1.00 10.33 C -ATOM 38 O GLY A -3 14.940 11.727 10.105 1.00 34.23 O -ATOM 39 HA3 GLY A -3 15.172 13.934 11.936 1.00 43.12 H -ATOM 40 HA2 GLY A -3 16.704 13.561 11.848 1.00 43.12 H -ATOM 41 N PRO A -2 16.164 13.467 9.301 1.00 43.42 N -ATOM 42 CA PRO A -2 16.028 13.090 7.880 1.00 72.12 C -ATOM 43 C PRO A -2 16.904 11.891 7.491 1.00 24.33 C -ATOM 44 O PRO A -2 16.479 11.039 6.705 1.00 1.42 O -ATOM 45 CB PRO A -2 16.479 14.351 7.114 1.00 65.32 C -ATOM 46 CG PRO A -2 16.651 15.418 8.147 1.00 23.11 C -ATOM 47 CD PRO A -2 16.953 14.708 9.432 1.00 3.14 C -ATOM 48 HA PRO A -2 15.094 12.906 7.692 1.00 72.12 H -ATOM 49 HB2 PRO A -2 17.317 14.174 6.659 1.00 65.32 H -ATOM 50 HB3 PRO A -2 15.799 14.602 6.470 1.00 65.32 H -ATOM 51 HG3 PRO A -2 15.832 15.932 8.224 1.00 23.11 H -ATOM 52 HG2 PRO A -2 17.386 15.999 7.896 1.00 23.11 H -ATOM 53 HD2 PRO A -2 17.900 14.513 9.508 1.00 3.14 H -ATOM 54 HD3 PRO A -2 16.659 15.229 10.196 1.00 3.14 H -ATOM 55 N SER A -1 18.123 11.839 8.047 1.00 54.30 N -ATOM 56 CA SER A -1 19.064 10.752 7.768 1.00 74.21 C -ATOM 57 C SER A -1 19.650 10.188 9.066 1.00 44.31 C -ATOM 58 O SER A -1 19.683 8.969 9.256 1.00 24.24 O -ATOM 59 CB SER A -1 20.187 11.243 6.843 1.00 35.31 C -ATOM 60 OG SER A -1 20.983 10.164 6.382 1.00 34.24 O -ATOM 61 H SER A -1 18.429 12.428 8.594 1.00 54.30 H -ATOM 62 HA SER A -1 18.597 10.032 7.316 1.00 74.21 H -ATOM 63 HB2 SER A -1 20.750 11.861 7.334 1.00 35.31 H -ATOM 64 HB3 SER A -1 19.791 11.690 6.079 1.00 35.31 H -ATOM 65 HG SER A -1 21.333 9.767 7.034 1.00 34.24 H -TER +ATOM 1 N GLY A -3 15.598 12.155 12.730 1.00 23.20 N +ATOM 2 CA GLY A -3 15.801 13.217 11.761 1.00 43.12 C +ATOM 3 C GLY A -3 15.603 12.746 10.322 1.00 10.33 C +ATOM 4 O GLY A -3 14.940 11.727 10.105 1.00 34.23 O +ATOM 5 H GLY A -3 14.858 11.727 12.631 1.00 23.20 H +ATOM 6 HA2 GLY A -3 16.704 13.561 11.848 1.00 43.12 H +ATOM 7 HA3 GLY A -3 15.172 13.934 11.936 1.00 43.12 H +ATOM 8 N PRO A -2 16.164 13.467 9.301 1.00 43.42 N +ATOM 9 CA PRO A -2 16.028 13.090 7.880 1.00 72.12 C +ATOM 10 C PRO A -2 16.904 11.891 7.491 1.00 24.33 C +ATOM 11 O PRO A -2 16.479 11.039 6.705 1.00 1.42 O +ATOM 12 CB PRO A -2 16.479 14.351 7.114 1.00 65.32 C +ATOM 13 CG PRO A -2 16.651 15.418 8.147 1.00 23.11 C +ATOM 14 CD PRO A -2 16.953 14.708 9.432 1.00 3.14 C +ATOM 15 HA PRO A -2 15.094 12.906 7.692 1.00 72.12 H +ATOM 16 HB2 PRO A -2 17.317 14.174 6.659 1.00 65.32 H +ATOM 17 HB3 PRO A -2 15.799 14.602 6.470 1.00 65.32 H +ATOM 18 HG2 PRO A -2 17.386 15.999 7.896 1.00 23.11 H +ATOM 19 HG3 PRO A -2 15.832 15.932 8.224 1.00 23.11 H +ATOM 20 HD2 PRO A -2 17.900 14.513 9.508 1.00 3.14 H +ATOM 21 HD3 PRO A -2 16.659 15.229 10.196 1.00 3.14 H +ATOM 22 N SER A -1 18.123 11.839 8.047 1.00 54.30 N +ATOM 23 CA SER A -1 19.064 10.752 7.768 1.00 74.21 C +ATOM 24 C SER A -1 19.650 10.188 9.066 1.00 44.31 C +ATOM 25 O SER A -1 19.683 8.969 9.256 1.00 24.24 O +ATOM 26 CB SER A -1 20.187 11.243 6.843 1.00 35.31 C +ATOM 27 OG SER A -1 20.983 10.164 6.382 1.00 34.24 O +ATOM 28 H SER A -1 18.429 12.428 8.594 1.00 54.30 H +ATOM 29 HA SER A -1 18.597 10.032 7.316 1.00 74.21 H +ATOM 30 HB2 SER A -1 20.750 11.861 7.334 1.00 35.31 H +ATOM 31 HB3 SER A -1 19.791 11.690 6.079 1.00 35.31 H +ATOM 32 HG SER A -1 21.333 9.767 7.034 1.00 34.24 H ENDMDL +END """ pdb_str_003 = """ @@ -408,8 +409,8 @@ def test_009(): ATOM 24 HO2* U A 2 5.578 9.841 9.360 1.00 38.55 H ATOM 25 H1* U A 2 6.256 10.694 7.724 1.00 36.22 H ATOM 26 H5 U A 2 9.576 14.307 6.377 1.00 33.80 H -ATOM 27 H5*2 U A 2 5.515 14.540 10.895 1.00 37.02 H -ATOM 28 H5*1 U A 2 5.082 14.734 9.388 1.00 37.02 H +ATOM 27 H5*1 U A 2 5.082 14.734 9.388 1.00 37.02 H +ATOM 28 H5*2 U A 2 5.515 14.540 10.895 1.00 37.02 H ATOM 29 H3 U A 2 10.157 10.489 5.626 1.00 33.13 H ATOM 30 H6 U A 2 7.829 13.711 7.657 1.00 33.46 H HETATM 31 P UMS A 3 8.115 12.049 12.757 1.00 35.65 P @@ -433,15 +434,16 @@ def test_009(): HETATM 49 C6 UMS A 3 10.817 10.354 9.743 1.00 34.62 C HETATM 50 CA' UMS A 3 11.776 5.000 13.480 1.00 46.26 C HETATM 51 SE2' UMS A 3 10.815 5.400 11.905 1.00 48.17 Se -HETATM 53 H3* UMS A 3 11.022 9.152 12.279 1.00 40.33 H -HETATM 54 H3 UMS A 3 13.140 9.648 7.179 1.00 33.98 H -HETATM 55 H1* UMS A 3 10.387 7.156 9.525 1.00 38.75 H -HETATM 56 H6 UMS A 3 10.252 10.527 10.462 1.00 34.62 H -HETATM 57 H4* UMS A 3 8.782 7.553 12.369 1.00 39.11 H -HETATM 58 H5*2 UMS A 3 7.481 9.448 12.109 1.00 36.88 H -HETATM 59 H5 UMS A 3 11.056 12.270 9.246 1.00 33.90 H -HETATM 60 H5* UMS A 3 8.158 9.276 13.531 1.00 36.88 H -HETATM 64 H2* UMS A 3 12.022 6.833 11.440 1.00 40.93 H +HETATM 52 H5* UMS A 3 8.158 9.276 13.531 1.00 36.88 H +HETATM 53 H4* UMS A 3 8.782 7.553 12.369 1.00 39.11 H +HETATM 54 H3* UMS A 3 11.022 9.152 12.279 1.00 40.33 H +HETATM 55 HO3* UMS A 3 10.593 8.589 14.362 1.00 40.80 H +HETATM 56 H2* UMS A 3 12.022 6.833 11.440 1.00 40.93 H +HETATM 57 H1* UMS A 3 10.387 7.156 9.525 1.00 38.75 H +HETATM 58 H5 UMS A 3 11.056 12.270 9.246 1.00 33.90 H +HETATM 59 H5*2 UMS A 3 7.481 9.448 12.109 1.00 36.88 H +HETATM 60 H3 UMS A 3 13.140 9.648 7.179 1.00 33.98 H +HETATM 61 H6 UMS A 3 10.252 10.527 10.462 1.00 34.62 H """ pdb_str_004 = ''' From 89a68e4ec7e7aae7f879e53ed20c3b4f245d97c3 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 18 Jan 2024 16:14:42 -0800 Subject: [PATCH 031/748] LLP restraints updated to include H1Z --- mmtbx/conformation_dependent_library/tst_pH_mechanism.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mmtbx/conformation_dependent_library/tst_pH_mechanism.py b/mmtbx/conformation_dependent_library/tst_pH_mechanism.py index 350cc12288..0c1b9035e8 100644 --- a/mmtbx/conformation_dependent_library/tst_pH_mechanism.py +++ b/mmtbx/conformation_dependent_library/tst_pH_mechanism.py @@ -144,5 +144,5 @@ def run2(): del sys.argv[1:] rc = run1() assert rc.return_code==0 - rc = run2() - assert rc.return_code==0 + # rc = run2() + # assert rc.return_code==0 From 695d1fe5f52f3a613eb3447ed82438426e91e72f Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Thu, 18 Jan 2024 16:20:45 -0800 Subject: [PATCH 032/748] Move matplotlib import Avoids occasional test failure as it's building the font cache --- xfel/command_line/filter_experiments_by_rmsd.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/xfel/command_line/filter_experiments_by_rmsd.py b/xfel/command_line/filter_experiments_by_rmsd.py index 082f97cdfc..c71cec57c0 100644 --- a/xfel/command_line/filter_experiments_by_rmsd.py +++ b/xfel/command_line/filter_experiments_by_rmsd.py @@ -21,11 +21,6 @@ import libtbx.load_env import math -try: - from matplotlib import pyplot as plt -except ImportError: # Can happen on non-GUI nodes - pass - help_message = ''' Filter a set of experiments and reflections from a multi-experiment job by overall RMSD using Tukey's rule of thumb. I.E, for each experiment, determine the RMSD of the @@ -120,6 +115,7 @@ def run_with_preparsed(experiments, reflections, params): print(len(subset), "experiments with > 0 reflections") if params.show_plots: + from matplotlib import pyplot as plt h = flex.histogram(subset, n_slots=40) fig = plt.figure() ax = fig.add_subplot('111') From 0eba8fedeb07aa3b0a0f5c299c9547335fb6e109 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Fri, 19 Jan 2024 09:05:59 -0800 Subject: [PATCH 033/748] updated dihedrals for lone H --- mmtbx/monomer_library/tst_geo_reduce_for_tardy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/monomer_library/tst_geo_reduce_for_tardy.py b/mmtbx/monomer_library/tst_geo_reduce_for_tardy.py index 727049878d..02c133ced6 100644 --- a/mmtbx/monomer_library/tst_geo_reduce_for_tardy.py +++ b/mmtbx/monomer_library/tst_geo_reduce_for_tardy.py @@ -61,7 +61,7 @@ def run(args): ("1yjp_box.pdb", (59,0), (22, 15)), # ("disulfides_box.pdb", (198,3), (65, 28)), origin ID move some restraints # ("disulfides_box.pdb", (198,3), (56, 25)), added torsions for H atoms - ("disulfides_box.pdb", (198,3), (70, 37)), + ("disulfides_box.pdb", (198,3), (74, 41)), ]: exercise_geo_reduce_for_tardy( mon_lib_srv=mon_lib_srv, From 44b32e67955652a283ee2f7b1c4981ce0a8f2152 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 19 Jan 2024 11:27:25 -0800 Subject: [PATCH 034/748] Fix test after geostd updates --- mmtbx/hydrogens/tst_add_hydrogen_2.py | 41 ++++++++++++++++----------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/mmtbx/hydrogens/tst_add_hydrogen_2.py b/mmtbx/hydrogens/tst_add_hydrogen_2.py index c37b6f4baa..f9e7672d1c 100644 --- a/mmtbx/hydrogens/tst_add_hydrogen_2.py +++ b/mmtbx/hydrogens/tst_add_hydrogen_2.py @@ -16,7 +16,7 @@ def run(): test_004() test_005() test_006() - # test_007() # needs fixing + test_007() # needs fixing test_008() #test_009() @@ -54,12 +54,18 @@ def compare_models(pdb_str, model_h_added = reduce_add_h_obj.get_model() hd_sel_h_added = model_h_added.get_hd_selection() - f = open("m_initial.pdb","w") - f.write(model_initial.model_as_pdb()) - f.close() - f = open("m_added.pdb","w") - f.write(model_h_added.model_as_pdb()) - f.close() + #f = open("m_initial.pdb","w") + #f.write(model_initial.model_as_pdb()) + #f.close() + #f = open("m_initial.cif","w") + #f.write(model_initial.model_as_mmcif()) + #f.close() + #f = open("m_added.pdb","w") + #f.write(model_h_added.model_as_pdb()) + #f.close() + #f = open("m_added.cif","w") + #f.write(model_h_added.model_as_mmcif()) + #f.close() ph_h_added = model_h_added.get_hierarchy() assert ph_initial.is_similar_hierarchy(other=ph_h_added) @@ -579,16 +585,17 @@ def test_009(): ATOM 595 C CA . GLY A 1 75 ? 41.845 36.550 32.686 0.25 36.07 ? 75 GLY A CA 1 ATOM 596 C C . GLY A 1 75 ? 41.251 37.941 32.588 0.25 36.16 ? 75 GLY A C 1 ATOM 597 O O . GLY A 1 75 ? 41.102 38.523 31.500 0.25 36.26 ? 75 GLY A O 1 -ATOM 598 H HA2 . GLY A 1 75 ? 42.768 36.603 32.393 0.25 36.07 ? 75 GLY A HA3 1 -ATOM 599 H HA3 . GLY A 1 75 ? 41.823 36.286 33.619 0.25 36.07 ? 75 GLY A HA2 1 -ATOM 600 N N . GLY A 1 76 ? 40.946 38.472 33.757 0.25 36.05 ? 76 GLY A N 1 -ATOM 601 C CA . GLY A 1 76 ? 40.373 39.813 33.944 0.25 36.19 ? 76 GLY A CA 1 -ATOM 602 C C . GLY A 1 76 ? 40.031 39.992 35.432 0.25 36.20 ? 76 GLY A C 1 -ATOM 603 O O . GLY A 1 76 ? 38.933 40.525 35.687 0.25 36.13 ? 76 GLY A O 1 -ATOM 604 O OXT . GLY A 1 76 ? 40.862 39.575 36.251 0.25 36.27 ? 76 GLY A OXT 1 -ATOM 605 H H . GLY A 1 76 ? 41.063 38.062 34.504 0.25 36.05 ? 76 GLY A H 1 -ATOM 606 H HA3 . GLY A 1 76 ? 39.566 39.910 33.413 0.25 36.19 ? 76 GLY A HA3 1 -ATOM 607 H HA2 . GLY A 1 76 ? 41.011 40.491 33.675 0.25 36.19 ? 76 GLY A HA2 1 +ATOM 598 H H . GLY A 1 75 ? 40.314 35.502 32.022 0.25 36.31 ? 75 GLY A H 1 +ATOM 599 H HA2 . GLY A 1 75 ? 42.768 36.603 32.393 0.25 36.07 ? 75 GLY A HA3 1 +ATOM 600 H HA3 . GLY A 1 75 ? 41.823 36.286 33.619 0.25 36.07 ? 75 GLY A HA2 1 +ATOM 601 N N . GLY A 1 76 ? 40.946 38.472 33.757 0.25 36.05 ? 76 GLY A N 1 +ATOM 602 C CA . GLY A 1 76 ? 40.373 39.813 33.944 0.25 36.19 ? 76 GLY A CA 1 +ATOM 603 C C . GLY A 1 76 ? 40.031 39.992 35.432 0.25 36.20 ? 76 GLY A C 1 +ATOM 604 O O . GLY A 1 76 ? 38.933 40.525 35.687 0.25 36.13 ? 76 GLY A O 1 +ATOM 605 O OXT . GLY A 1 76 ? 40.862 39.575 36.251 0.25 36.27 ? 76 GLY A OXT 1 +ATOM 606 H H . GLY A 1 76 ? 41.063 38.062 34.504 0.25 36.05 ? 76 GLY A H 1 +ATOM 607 H HA3 . GLY A 1 76 ? 39.566 39.910 33.413 0.25 36.19 ? 76 GLY A HA3 1 +ATOM 608 H HA2 . GLY A 1 76 ? 41.011 40.491 33.675 0.25 36.19 ? 76 GLY A HA2 1 HETATM 611 O O . HOH B 2 . ? 45.747 30.081 19.708 1.00 12.43 ? 77 HOH A O 1 ''' From 36b07d73fe0ab3951b69f7d785bb9d644bcdeb2d Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Fri, 19 Jan 2024 12:42:51 -0800 Subject: [PATCH 035/748] conda: clean up installation script - Consolidate some code - Add case for phaser_voyager [skip ci] --- .../auto_build/conda_build/install_build.py | 69 +++++++------------ 1 file changed, 26 insertions(+), 43 deletions(-) diff --git a/libtbx/auto_build/conda_build/install_build.py b/libtbx/auto_build/conda_build/install_build.py index 7771c07aae..44f0abf90e 100644 --- a/libtbx/auto_build/conda_build/install_build.py +++ b/libtbx/auto_build/conda_build/install_build.py @@ -36,13 +36,18 @@ def copy_cmd(src, dst, link): ------- Nothing """ - if link: - os.symlink(src, dst) + if os.path.exists(dst): + print(' {dst} already exists'.format(dst=dst)) else: - if os.path.isdir(src): - copytree(src, dst, ignore=ignore_patterns('.git*', '.svn*')) + print(' source: ' + src) + print(' destination: ' + dst) + if link: + os.symlink(src, dst) else: - copy(src, dst) + if os.path.isdir(src): + copytree(src, dst, ignore=ignore_patterns('.git*', '.svn*')) + else: + copy(src, dst) # ============================================================================= def remove_cmd(src): @@ -143,12 +148,7 @@ def loop_copy(src_path, dst_path, name, filenames): print(' {src} does not exist'.format(src=src)) continue dst = os.path.join(dst_path, src_file) - if os.path.exists(dst): - print(' {dst} already exists'.format(dst=dst)) - else: - print(' source: ' + src) - print(' destination: ' + dst) - copy_cmd(src, dst, link) + copy_cmd(src, dst, link) print('Done') print() # --------------------------------------------------------------------------- @@ -262,28 +262,20 @@ def copy_modules(env, sp_dir=None, link=False): if module == 'boost' and src.endswith('boost'): continue # copy subdirectories for some modules - elif module == 'phenix': - for subdir in ['phenix', 'wxGUI2']: - src = abs(dist_path / subdir) + elif module in ['phenix', 'phaser_voyager']: + if module == 'phenix': + src_root = dist_path + subdirs = ['phenix', 'wxGUI2'] + elif module == 'phaser_voyager': + src_root = dist_path / 'src' + subdirs = ['New_Voyager', 'Voyager'] + for subdir in subdirs: + src = abs(src_root / subdir) dst = os.path.join(sp_dir, subdir) - if os.path.exists(dst): - print(' {dst} already exists'.format(dst=dst)) - continue - if os.path.isdir(src): - print(' source: ' + src) - print(' destination: ' + dst) - copy_cmd(src, dst, link) - else: - print(' Nothing done') - continue + copy_cmd(src, dst, link) # phenix/wxGUI2 is also an expected path (fix upstream) if subdir == 'wxGUI2': dst = os.path.join(sp_dir, 'phenix', subdir) - print(' source: ' + src) - print(' destination: ' + dst) - if os.path.exists(dst): - print(' {dst} already exists'.format(dst=dst)) - continue copy_cmd(src, dst, link) continue elif module in ['elbow', 'phaser', 'phasertng', 'PyQuante']: @@ -292,26 +284,14 @@ def copy_modules(env, sp_dir=None, link=False): for m in ['yacc.py', 'resources']: src = abs(dist_path / m) dst = os.path.join(sp_dir, m) - print(' source: ' + src) - print(' destination: ' + dst) copy_cmd(src, dst, link) src = abs(dist_path / module) dst = os.path.join(sp_dir, os.path.basename(src)) - if os.path.exists(dst): - print(' {dst} already exists'.format(dst=dst)) - continue - if os.path.isdir(src): - print(' source: ' + src) - print(' destination: ' + dst) - copy_cmd(src, dst, link) - else: - print(' Nothing done') + copy_cmd(src, dst, link) if module == 'tntbx': for f in ['__init__.py', 'eigensystem.py']: src = abs(dist_path / module / f) dst = os.path.join(sp_dir, module, f) - print(' source: ' + src) - print(' destination: ' + dst) copy_cmd(src, dst, link) except KeyError: print(dist_path) @@ -463,7 +443,10 @@ def remove_modules(env, sp_dir=None): for module_name, extra_stuff in [ ('elbow', 'yacc.py'), ('elbow', 'resources'), - ('phenix', 'wxGUI2')]: + ('phenix', 'wxGUI2'), + ('phaser_voyager', 'New_Voyager'), + ('phaser_voyager', 'Voyager'), + ]: if module == module_name: src = os.path.join(sp_dir, extra_stuff) if os.path.exists(src): From 1a6ca9f6e15c2f56bc52e58d3a9455d7e026edbd Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Fri, 19 Jan 2024 12:50:52 -0800 Subject: [PATCH 036/748] conda: fix path in Windows installers - Update PATH in dispatchers - When moving dispatchers to a new location, make sure that LIBTBX_PREFIX is the original location [skip ci] --- libtbx/auto_build/conda_build/create_custom_bin.py | 10 ++++++++++ libtbx/env_config.py | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/libtbx/auto_build/conda_build/create_custom_bin.py b/libtbx/auto_build/conda_build/create_custom_bin.py index 28a480677d..7440cd2fc8 100644 --- a/libtbx/auto_build/conda_build/create_custom_bin.py +++ b/libtbx/auto_build/conda_build/create_custom_bin.py @@ -58,6 +58,16 @@ def copy_bin(prefix, custom_bin, packages=[]): if sys.platform == 'win32': print(f'Copying {prefix/bin_file} to {new_prefix/bin_name}') copy(prefix/bin_file, new_prefix/bin_name) + if (new_prefix/bin_name).suffix == '.bat': + print(f'Fixing LIBTBX_PREFIX in {new_prefix/bin_name}') + with open(new_prefix/bin_name, 'r') as f: + lines = f.readlines() + with open(new_prefix/bin_name, 'w') as f: + for line in lines: + line = line.strip() + if 'dp0' in line: # make path relative to original location + line += '\\..\\Library\\bin' + f.write(line) else: print(f'Linking {prefix/bin_file} to {new_prefix/bin_name}') os.symlink(prefix/bin_file, new_prefix/bin_name) diff --git a/libtbx/env_config.py b/libtbx/env_config.py index 4b2693cac1..f620483ae1 100644 --- a/libtbx/env_config.py +++ b/libtbx/env_config.py @@ -1209,7 +1209,7 @@ def write_conda_dispatcher(self, source_file, target_file, print(r'@for %%F in ("%LIBTBX_PREFIX%") do @set LIBTBX_PREFIX=%%~dpF', file=f) print('@set LIBTBX_PREFIX=%LIBTBX_PREFIX:~0,-1%', file=f) print('@set LIBTBX_DISPATCHER_NAME=%~nx0', file=f) - print('@set PATH=%LIBTBX_PREFIX%\\..;%LIBTBX_PREFIX%\\mingw-w64\\bin;%LIBTBX_PREFIX%\\bin;%LIBTBX_PREFIX%\\..\\Scripts;%PATH%', file=f) + print('@set PATH=%LIBTBX_PREFIX%\\..;%LIBTBX_PREFIX%\\..\\mingw-w64\\bin;%LIBTBX_PREFIX%\\..\\bin;%LIBTBX_PREFIX%\\..\\..\\Scripts;%PATH%', file=f) def write_dispatcher_include(where): for line in self.dispatcher_include(where=where): if (line.startswith("@")): From 7cfb1b7d1d06d57097714817a2e279b7efa187b4 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 19 Jan 2024 13:09:56 -0800 Subject: [PATCH 037/748] Remove comment --- mmtbx/hydrogens/tst_add_hydrogen_2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/hydrogens/tst_add_hydrogen_2.py b/mmtbx/hydrogens/tst_add_hydrogen_2.py index f9e7672d1c..71d7aae39e 100644 --- a/mmtbx/hydrogens/tst_add_hydrogen_2.py +++ b/mmtbx/hydrogens/tst_add_hydrogen_2.py @@ -16,7 +16,7 @@ def run(): test_004() test_005() test_006() - test_007() # needs fixing + test_007() test_008() #test_009() From 8ac8b60a8612a8ae226039afa6aa3b92bfad44a1 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 19 Jan 2024 15:40:46 -0800 Subject: [PATCH 038/748] Add possibility of using custom scattering factors to phenix.fmodel --- mmtbx/command_line/fmodel.py | 7 +++++++ mmtbx/utils/__init__.py | 24 +++++++++++++++++++++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/mmtbx/command_line/fmodel.py b/mmtbx/command_line/fmodel.py index a655e9e35c..fcaf2c46a7 100644 --- a/mmtbx/command_line/fmodel.py +++ b/mmtbx/command_line/fmodel.py @@ -145,6 +145,9 @@ n_gaussian is the standard set of X-ray scattering factors. .expert_level=1 .style = noauto +custom_scattering_factors = None + .type = path + .help = Use custom scattering factors and replaces default values entirely pdb_file = None .type = path .multiple = True @@ -397,6 +400,9 @@ def run(args, log = sys.stdout): else: ofn = ofn + "_et_al" + extension if([miller_array, params.high_resolution].count(None)==2): raise Sorry("Input data file or high_resolution has to be provided.") + use_custom_scattering_dictionary = False + if params.custom_scattering_factors: + use_custom_scattering_dictionary = True mmtbx.utils.fmodel_from_xray_structure( xray_structure = xray_structure, f_obs = miller_array, @@ -404,6 +410,7 @@ def run(args, log = sys.stdout): params = params, twin_law = params.twin_law, twin_fraction = params.twin_fraction, + use_custom_scattering_dictionary = use_custom_scattering_dictionary, out = log).write_to_file(file_name = ofn, obs_type=params.output.obs_type) print("Output file name:", ofn, file=log) diff --git a/mmtbx/utils/__init__.py b/mmtbx/utils/__init__.py index 758fadb14a..30664f3848 100644 --- a/mmtbx/utils/__init__.py +++ b/mmtbx/utils/__init__.py @@ -1255,7 +1255,8 @@ def __init__(self, xray_structure, twin_fraction = None, target = "ml", out = None, - merge_r_free_flags = None): + merge_r_free_flags = None, + use_custom_scattering_dictionary = False): if(out is None): out = sys.stdout self.add_sigmas = add_sigmas if(params is None): @@ -1266,12 +1267,24 @@ def __init__(self, xray_structure, r_free_flags_fraction = params.r_free_flags_fraction else: r_free_flags_fraction = 0.1 + + new_scattering_dictionary = None + if use_custom_scattering_dictionary: + from cctbx.eltbx import read_custom_scattering_dict + new_scattering_dictionary = read_custom_scattering_dict.run( + filename = params.custom_scattering_factors, log = out) + if(f_obs is None): hr = None try: hr = params.high_resolution except Exception: self.Sorry_high_resolution_is_not_defined() if(params.scattering_table == "neutron"): - xray_structure.switch_to_neutron_scattering_dictionary() + if(new_scattering_dictionary): + xray_structure.scattering_type_registry( + custom_dict = new_scattering_dictionary) + xray_structure.scattering_type_registry().show(out = out) + else: + xray_structure.switch_to_neutron_scattering_dictionary() else: xray_structure.scattering_type_registry( table = params.scattering_table, d_min = hr) @@ -1303,7 +1316,12 @@ def __init__(self, xray_structure, except Exception: lr = None f_obs = f_obs.resolution_filter(d_max = lr, d_min = hr) if(params.scattering_table == "neutron"): - xray_structure.switch_to_neutron_scattering_dictionary() + if(new_scattering_dictionary): + xray_structure.scattering_type_registry( + custom_dict = new_scattering_dictionary) + xray_structure.scattering_type_registry().show(out = out) + else: + xray_structure.switch_to_neutron_scattering_dictionary() else: xray_structure.scattering_type_registry( table = params.scattering_table, d_min = f_obs.d_min()) From 7e737f41cd12bd3ae294dd78aff70b3630d73f8b Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Fri, 19 Jan 2024 19:11:15 -0800 Subject: [PATCH 039/748] iotbx: remove print when checking a3m files --- iotbx/bioinformatics/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/iotbx/bioinformatics/__init__.py b/iotbx/bioinformatics/__init__.py index 62ba792cb7..5a851fedf8 100644 --- a/iotbx/bioinformatics/__init__.py +++ b/iotbx/bioinformatics/__init__.py @@ -1888,7 +1888,6 @@ def ok_a3m_sequence(s, n = None, base_sequence = None): elif c >="a" and c <= "z": n_lower += 1 else: - print(c) n_other += 1 if n_other > 0: From 4386c4c5b1cfe51b987bb686154c1aec2e286255 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Sat, 20 Jan 2024 04:23:22 -0800 Subject: [PATCH 040/748] conda: ignore missing directories/files when creating installer [skip ci] --- libtbx/auto_build/conda_build/install_build.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libtbx/auto_build/conda_build/install_build.py b/libtbx/auto_build/conda_build/install_build.py index 44f0abf90e..f41071c9fe 100644 --- a/libtbx/auto_build/conda_build/install_build.py +++ b/libtbx/auto_build/conda_build/install_build.py @@ -36,7 +36,9 @@ def copy_cmd(src, dst, link): ------- Nothing """ - if os.path.exists(dst): + if not os.path.exists(src): + print(' {src} does not exist, skipping'.format(dst=dst)) + elif os.path.exists(dst): print(' {dst} already exists'.format(dst=dst)) else: print(' source: ' + src) From e17c100410564758e9cf33ed8f01ed67b7daac8d Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Sat, 20 Jan 2024 04:26:08 -0800 Subject: [PATCH 041/748] Fix typo [skip ci] --- libtbx/auto_build/conda_build/install_build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libtbx/auto_build/conda_build/install_build.py b/libtbx/auto_build/conda_build/install_build.py index f41071c9fe..4c47eddb08 100644 --- a/libtbx/auto_build/conda_build/install_build.py +++ b/libtbx/auto_build/conda_build/install_build.py @@ -37,7 +37,7 @@ def copy_cmd(src, dst, link): Nothing """ if not os.path.exists(src): - print(' {src} does not exist, skipping'.format(dst=dst)) + print(' {src} does not exist, skipping'.format(src=src)) elif os.path.exists(dst): print(' {dst} already exists'.format(dst=dst)) else: From 14fa41634b66d02e94f903967b5963b85fa7e632 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sat, 20 Jan 2024 13:56:49 -0800 Subject: [PATCH 042/748] Catch None --- cctbx/miller/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cctbx/miller/__init__.py b/cctbx/miller/__init__.py index 3ab88ffac9..c48ad9b73d 100644 --- a/cctbx/miller/__init__.py +++ b/cctbx/miller/__init__.py @@ -2324,7 +2324,8 @@ def regularize(self): result = self.deep_copy() info = result.info() result = result.eliminate_sys_absent() - info = info.customized_copy(systematic_absences_eliminated = True) + if info is not None: + info = info.customized_copy(systematic_absences_eliminated = True) if(not result.is_unique_set_under_symmetry()): merged = result.merge_equivalents() result = merged.array() From e990b5907a14982369753c42d1d090ad1e6c0d62 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Mon, 22 Jan 2024 17:08:57 -0800 Subject: [PATCH 043/748] test for HYP in AA chain --- mmtbx/hydrogens/tst_add_hydrogen_2.py | 64 +++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/mmtbx/hydrogens/tst_add_hydrogen_2.py b/mmtbx/hydrogens/tst_add_hydrogen_2.py index 71d7aae39e..7e7b6fb3af 100644 --- a/mmtbx/hydrogens/tst_add_hydrogen_2.py +++ b/mmtbx/hydrogens/tst_add_hydrogen_2.py @@ -19,6 +19,7 @@ def run(): test_007() test_008() #test_009() + test_010() # ------------------------------------------------------------------------------ @@ -179,6 +180,14 @@ def test_009(): # ------------------------------------------------------------------------------ +def test_010(): + ''' + 7JX4: ACE linked to GLY1 Goal: H1,2,3 on ACE and no H to HYP. + ''' + compare_models(pdb_str = pdb_str_010) + +# ------------------------------------------------------------------------------ + pdb_str_000 = """ REMARK This will crash if CDL is set to FALSE CRYST1 72.240 72.010 86.990 90.00 90.00 90.00 P 21 21 21 @@ -684,6 +693,61 @@ def test_009(): HETATM 45 H32 SIN A 0 12.173 13.820 5.265 1.00 22.69 H ''' +pdb_str_010 = ''' +REMARK 7JX4: ACE linked at GLY 1 and HYP (PRO-like) +CRYST1 72.365 24.756 25.357 90.00 98.72 90.00 C 1 2 1 +HETATM 1 C ACE A 0 38.724 1.027 10.647 1.00 35.12 C +HETATM 2 O ACE A 0 39.785 1.620 10.713 1.00 31.48 O +HETATM 3 CH3 ACE A 0 37.707 1.320 9.557 1.00 37.70 C +HETATM 4 H1 ACE A 0 37.394 2.362 9.563 1.00 37.70 H +HETATM 5 H2 ACE A 0 36.807 0.718 9.668 1.00 37.70 H +HETATM 6 H3 ACE A 0 38.104 1.115 8.565 1.00 37.70 H +ATOM 7 N GLY A 1 38.359 0.034 11.445 1.00 26.83 N +ATOM 8 CA GLY A 1 39.087 -0.442 12.689 1.00 24.95 C +ATOM 9 C GLY A 1 40.351 0.366 12.956 1.00 20.49 C +ATOM 10 O GLY A 1 40.732 1.220 12.165 1.00 21.71 O +ATOM 11 H GLY A 1 37.650 -0.432 11.306 1.00 26.83 H +ATOM 12 HA2 GLY A 1 38.501 -0.358 13.457 1.00 24.95 H +ATOM 13 HA3 GLY A 1 39.335 -1.374 12.581 1.00 24.95 H +ATOM 14 N PRO A 2 41.104 0.126 14.061 1.00 20.40 N +ATOM 15 CA PRO A 2 42.349 0.839 14.257 1.00 19.14 C +ATOM 16 C PRO A 2 43.339 0.479 13.161 1.00 15.63 C +ATOM 17 O PRO A 2 43.259 -0.533 12.439 1.00 14.90 O +ATOM 18 CB PRO A 2 42.883 0.369 15.625 1.00 23.56 C +ATOM 19 CG PRO A 2 42.199 -0.976 15.820 1.00 27.80 C +ATOM 20 CD PRO A 2 40.839 -0.836 15.147 1.00 24.02 C +ATOM 21 HA PRO A 2 42.194 1.795 14.310 1.00 19.14 H +ATOM 22 HB2 PRO A 2 43.848 0.274 15.596 1.00 23.56 H +ATOM 23 HB3 PRO A 2 42.632 0.998 16.320 1.00 23.56 H +ATOM 24 HG2 PRO A 2 42.722 -1.676 15.399 1.00 27.80 H +ATOM 25 HG3 PRO A 2 42.099 -1.160 16.767 1.00 27.80 H +ATOM 26 HD2 PRO A 2 40.180 -0.486 15.767 1.00 24.02 H +ATOM 27 HD3 PRO A 2 40.540 -1.687 14.791 1.00 24.02 H +HETATM 28 N HYP A 3 44.381 1.316 13.052 1.00 14.81 N +HETATM 29 CA HYP A 3 45.534 1.014 12.227 1.00 13.64 C +HETATM 30 C HYP A 3 46.092 -0.340 12.609 1.00 11.90 C +HETATM 31 O HYP A 3 46.074 -0.816 13.778 1.00 13.30 O +HETATM 32 CB HYP A 3 46.514 2.141 12.599 1.00 15.74 C +HETATM 33 CG HYP A 3 45.629 3.294 13.029 1.00 18.10 C +HETATM 34 CD HYP A 3 44.531 2.590 13.781 1.00 18.00 C +HETATM 35 OD1 HYP A 3 45.026 3.949 11.913 1.00 18.20 O +HETATM 37 HA HYP A 3 45.349 1.056 11.276 1.00 13.64 H +HETATM 38 HB2 HYP A 3 47.111 1.889 13.321 1.00 15.74 H +HETATM 39 HB3 HYP A 3 47.072 2.408 11.852 1.00 15.74 H +HETATM 40 HG HYP A 3 46.135 3.928 13.562 1.00 18.10 H +HETATM 41 HD1 HYP A 3 44.639 3.368 11.428 1.00 18.20 H +HETATM 42 HD22 HYP A 3 44.765 2.430 14.709 1.00 18.00 H +HETATM 43 HD23 HYP A 3 43.700 3.091 13.773 1.00 18.00 H +ATOM 44 N GLY A 4 46.667 -0.918 11.580 1.00 10.55 N +ATOM 45 CA GLY A 4 47.460 -2.080 11.829 1.00 10.24 C +ATOM 46 C GLY A 4 48.729 -1.736 12.583 1.00 9.86 C +ATOM 47 O GLY A 4 49.036 -0.544 12.829 1.00 11.39 O +ATOM 48 OXT GLY A 4 49.480 -2.633 12.966 1.00 9.86 O +ATOM 49 H GLY A 4 46.611 -0.661 10.761 1.00 10.55 H +ATOM 50 HA2 GLY A 4 46.949 -2.714 12.356 1.00 10.24 H +ATOM 51 HA3 GLY A 4 47.703 -2.493 10.986 1.00 10.24 H +''' + if (__name__ == "__main__"): t0 = time.time() run() From 5725151adbe1df61b4e95784a0ff83791c4096b1 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Mon, 22 Jan 2024 17:12:55 -0800 Subject: [PATCH 044/748] some helper functions for Q|R --- mmtbx/ligands/hierarchy_utils.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/mmtbx/ligands/hierarchy_utils.py b/mmtbx/ligands/hierarchy_utils.py index 89e999cef0..1df21622d0 100644 --- a/mmtbx/ligands/hierarchy_utils.py +++ b/mmtbx/ligands/hierarchy_utils.py @@ -101,6 +101,38 @@ def attempt_to_squash_alt_loc(hierarchy): rg.remove_atom_group(ags[1]) return squash_hierarchy +def get_bonds_as_dict(geometry_restraints_manager): + bonds={} + for bond in geometry_restraints_manager.get_all_bond_proxies(): + if not hasattr(bond, 'get_proxies_with_origin_id'): continue + for p in bond.get_proxies_with_origin_id(): + tmp=bonds.setdefault(p.i_seqs[0], []) + tmp.append(p.i_seqs[1]) + tmp=bonds.setdefault(p.i_seqs[1], []) + tmp.append(p.i_seqs[0]) + return bonds + +def get_valences(element, charge): + valence = { + 'C' : 4, + 'N' : 3, + 'O' : 2, + } + rc = valence.get(element) + rc += charge + return [rc] + +def simple_valence_check(ph, geometry_restraints_manager): + bonds = get_bonds_as_dict(geometry_restraints_manager) + for atom in ph.atoms(): + if atom.element_is_hydrogen(): continue + if atom.parent().resname in ['HOH']: continue + print(atom.quote()) + print(bonds[atom.i_seq]) + number_of_bonds = len(bonds.get(atom.i_seq, None)) + if number_of_bonds not in get_valences(atom.element, atom.charge_as_int()): + assert 0 + def main(filename): from iotbx import pdb pdb_inp=pdb.input(filename) From bf7f23e446a060d07f371623a0e12d23756d6c72 Mon Sep 17 00:00:00 2001 From: dermen Date: Tue, 16 Jan 2024 18:45:55 -0800 Subject: [PATCH 045/748] properly set divergences using nanoBragg xray beams --- simtbx/command_line/stage_two.py | 8 +++ simtbx/diffBragg/attr_list.py | 3 +- simtbx/modeling/forward_models.py | 5 +- simtbx/nanoBragg/nanoBragg_beam.py | 108 +++++++++++++++++++++++++---- 4 files changed, 106 insertions(+), 18 deletions(-) diff --git a/simtbx/command_line/stage_two.py b/simtbx/command_line/stage_two.py index 0787a9867f..7df821b6f9 100644 --- a/simtbx/command_line/stage_two.py +++ b/simtbx/command_line/stage_two.py @@ -6,6 +6,7 @@ from simtbx.command_line.hopper import hopper_phil import time import logging +import os from simtbx.diffBragg import mpi_logger from simtbx.diffBragg.device import DeviceWrapper @@ -57,6 +58,13 @@ def __init__(self): check_format=False, epilog=help_message) self.params, _ = self.parser.parse_args(show_diff_phil=COMM.rank==0) + outdir = self.params.refiner.io.output_dir + if outdir is not None: + if not os.path.exists(outdir): + os.makedirs(outdir) + diff_phil_outname = os.path.join(outdir, "diff.phil") + with open(diff_phil_outname, "w") as o: + o.write(self.parser.diff_phil.as_str()) self.params = COMM.bcast(self.params) def run(self): diff --git a/simtbx/diffBragg/attr_list.py b/simtbx/diffBragg/attr_list.py index b4f93b9450..f961528cd0 100644 --- a/simtbx/diffBragg/attr_list.py +++ b/simtbx/diffBragg/attr_list.py @@ -68,7 +68,8 @@ # properties of nanoBragg_beam.NBbeam instances NB_BEAM_ATTRS = [ - 'divergence', + 'divergence_mrad', + 'divsteps', 'polarization_fraction', 'size_mm', 'number_of_sources', diff --git a/simtbx/modeling/forward_models.py b/simtbx/modeling/forward_models.py index dd305aa7ec..16abe1cfab 100644 --- a/simtbx/modeling/forward_models.py +++ b/simtbx/modeling/forward_models.py @@ -244,14 +244,15 @@ def diffBragg_forward(CRYSTAL, DETECTOR, BEAM, Famp, energies, fluxes, nopolar=False, diffuse_params=None, cuda=False, show_timings=False,perpixel_wavelen=False, det_thicksteps=None, eta_abc=None, Ncells_def=None, - num_phi_steps=1, delta_phi=None, div_mrad=0): + num_phi_steps=1, delta_phi=None, div_mrad=0, divsteps=0): if cuda: os.environ["DIFFBRAGG_USE_CUDA"] = "1" CRYSTAL, Famp = nanoBragg_utils.ensure_p1(CRYSTAL, Famp) nbBeam = NBbeam() - nbBeam.divergence = div_mrad / 1e3 * 180 / np.pi + nbBeam.divergence_mrad = div_mrad # / 1e3 * 180 / np.pi + nbBeam.divsteps = divsteps nbBeam.size_mm = beamsize_mm nbBeam.unit_s0 = BEAM.get_unit_s0() wavelengths = utils.ENERGY_CONV / np.array(energies) diff --git a/simtbx/nanoBragg/nanoBragg_beam.py b/simtbx/nanoBragg/nanoBragg_beam.py index 1e177a6dab..fae1e8a189 100644 --- a/simtbx/nanoBragg/nanoBragg_beam.py +++ b/simtbx/nanoBragg/nanoBragg_beam.py @@ -4,17 +4,52 @@ from __future__ import print_function, division from dxtbx.model.beam import BeamFactory from dxtbx_model_ext import flex_Beam +import numpy as np +from copy import deepcopy + + +def rotate_axis(v, axis, phi): + sinphi = np.sin(phi); + cosphi = np.cos(phi); + dot = np.dot(axis,v)*(1-cosphi) + #dot = (axis[0]*v[0]+axis[1]*v[1]+axis[2]*v[2])*(1.0-cosphi); + new_x = axis[0]*dot+v[0]*cosphi+(-axis[2]*v[1]+axis[1]*v[2])*sinphi; + new_y = axis[1]*dot+v[1]*cosphi+(+axis[2]*v[0]-axis[0]*v[2])*sinphi; + new_z = axis[2]*dot+v[2]*cosphi+(-axis[1]*v[0]+axis[0]*v[1])*sinphi; + return new_x, new_y, new_z class NBbeam(object): def __init__(self): self.spectrum = [(1.8, 1e12)] # angstroms, photons per pulse - self.unit_s0 = 1, 0, 0 - self.polarization_fraction = 1 - self.divergence = 0 - self.size_mm = 0.001 + self.unit_s0 = 1, 0, 0 # forward beam direction + self.polarization_fraction = 1 # defines horizontal and vertical polarization fraction + self.divergence_mrad = 0 # set the divergence cone angle + self.divsteps = 0 # number of divergence steps, will be squared (one per horizontal, vertical directions) + self.size_mm = 0.001 # beam spot size self._undo_nanoBragg_norm_by_nbeams = True # we undo it by default + self.prev_xray_beams = None # used to cache most recent xray_beams property for efficiency + self.num_div_angles_within_cone = 0 # used to count how manydivergence angles we sample within the cone of divergence + + @property + def divsteps(self): + return self._divsteps + + @divsteps.setter + def divsteps(self, val): + if val > 0: + assert val % 2 == 0, "divsteps must be even" + self._divsteps = val + + @property + def divergences(self): + divrange = self.divergence_mrad/1000. + if self.divsteps==0: + return [(0,0)] + else: + all_divs = np.arange(0, divrange+1e-7, divrange / self.divsteps) - divrange / 2 + return [(hdiv, vdiv) for vdiv in all_divs for hdiv in all_divs] @property def size_mm(self): @@ -60,40 +95,83 @@ def polarization_fraction(self, val): @property def xray_beams(self): self._xray_beams = flex_Beam() + + divs = self.divergences + + wavelen = self.spectrum[0][0] + nominal_beam = BeamFactory.simple(wavelen * 1e-10) + nominal_beam.set_unit_s0(self.unit_s0) + nominal_beam.set_polarization_fraction(self.polarization_fraction) + beam_vector = nominal_beam.get_sample_to_source_direction() + beam_vector /= np.linalg.norm(beam_vector) + vert_vector = nominal_beam.get_polarization_normal() + polar_vector = np.cross(beam_vector, vert_vector) + polar_vector /= np.linalg.norm(polar_vector) + + self.num_div_angles_within_cone = 0 + beams = [] + for hdiv, vdiv in divs: + vec_xyz = rotate_axis(-beam_vector, polar_vector, vdiv) + unit_s0 = rotate_axis(vec_xyz, vert_vector, hdiv) + div_ang = np.arccos(np.dot(unit_s0, -beam_vector)) + if hdiv == 0 and vdiv == 0: + assert div_ang == 0 + assert np.allclose(unit_s0, nominal_beam.get_unit_s0()) + if div_ang > 1.1*(self.divergence_mrad / 1000. / 2.): + continue + self.num_div_angles_within_cone += 1 + for wavelen, flux in self.spectrum: + beam = deepcopy(nominal_beam) + beam.set_wavelength(wavelen*1e-10) + beam.set_flux(flux) + beam.set_polarization_fraction(self.polarization_fraction) + beam.set_unit_s0(unit_s0) + beam.set_divergence(div_ang) + beams.append(beam) + + # set normalization norm = 1 if self._undo_nanoBragg_norm_by_nbeams: - norm = float(len(self.spectrum)) - - for wavelen, flux in self.spectrum: - beam = BeamFactory.simple(wavelen * 1e-10) - beam.set_flux(flux / norm) - beam.set_unit_s0(self.unit_s0) - beam.set_polarization_fraction(self.polarization_fraction) - beam.set_divergence(self.divergence) + norm = len(beams) + for beam in beams: + beam.set_flux(beam.get_flux()/norm) self._xray_beams.append(beam) + self.prev_xray_beams = self._xray_beams return self._xray_beams @property def nanoBragg_constructor_beam(self): - """dumb necessity FIXME please""" + """dumb necessity for instantiating nanoBragg.""" + if self.prev_xray_beams is None: + self.prev_xray_beams = self.xray_beams - beam = BeamFactory.from_dict(self.xray_beams[0].to_dict()) + beam = BeamFactory.from_dict(self.prev_xray_beams[0].to_dict()) # set the nominal beam to have the average wavelength and the total flux num = 0 den = 0 flux = 0 - for b in self.xray_beams: + u0 = [] + div = 0 + count = 0 + for b in self.prev_xray_beams: wave = b.get_wavelength() wt = b.get_flux() num += wave * wt den += wt flux += b.get_flux() + div += b.get_divergence() + u0.append( b.get_unit_s0()) + count += 1 + u0 = np.mean(u0, 0) ave_wave = num / den + div = div / count + beam.set_divergence(div) beam.set_wavelength(ave_wave * 1e10) beam.set_flux(flux) + beam.set_unit_s0(u0) return beam @property From a0f643f21c7dd4eb66f1261747189ba99fe4eaa7 Mon Sep 17 00:00:00 2001 From: Derek Mendez Date: Wed, 17 Jan 2024 14:44:05 -0800 Subject: [PATCH 046/748] remove semis --- simtbx/nanoBragg/nanoBragg_beam.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/simtbx/nanoBragg/nanoBragg_beam.py b/simtbx/nanoBragg/nanoBragg_beam.py index fae1e8a189..df52223baa 100644 --- a/simtbx/nanoBragg/nanoBragg_beam.py +++ b/simtbx/nanoBragg/nanoBragg_beam.py @@ -9,13 +9,12 @@ def rotate_axis(v, axis, phi): - sinphi = np.sin(phi); - cosphi = np.cos(phi); + sinphi = np.sin(phi) + cosphi = np.cos(phi) dot = np.dot(axis,v)*(1-cosphi) - #dot = (axis[0]*v[0]+axis[1]*v[1]+axis[2]*v[2])*(1.0-cosphi); - new_x = axis[0]*dot+v[0]*cosphi+(-axis[2]*v[1]+axis[1]*v[2])*sinphi; - new_y = axis[1]*dot+v[1]*cosphi+(+axis[2]*v[0]-axis[0]*v[2])*sinphi; - new_z = axis[2]*dot+v[2]*cosphi+(-axis[1]*v[0]+axis[0]*v[1])*sinphi; + new_x = axis[0]*dot+v[0]*cosphi+(-axis[2]*v[1]+axis[1]*v[2])*sinphi + new_y = axis[1]*dot+v[1]*cosphi+(+axis[2]*v[0]-axis[0]*v[2])*sinphi + new_z = axis[2]*dot+v[2]*cosphi+(-axis[1]*v[0]+axis[0]*v[1])*sinphi return new_x, new_y, new_z From 09572171782f9b125f4bdefe9e02cc8277ef0554 Mon Sep 17 00:00:00 2001 From: dermen Date: Thu, 18 Jan 2024 19:55:49 -0800 Subject: [PATCH 047/748] faster rotate method --- simtbx/nanoBragg/nanoBragg_beam.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/simtbx/nanoBragg/nanoBragg_beam.py b/simtbx/nanoBragg/nanoBragg_beam.py index df52223baa..a589fe52c4 100644 --- a/simtbx/nanoBragg/nanoBragg_beam.py +++ b/simtbx/nanoBragg/nanoBragg_beam.py @@ -6,16 +6,17 @@ from dxtbx_model_ext import flex_Beam import numpy as np from copy import deepcopy +from mmtbx_reduce_ext import RotatePointDegreesAroundAxisDir def rotate_axis(v, axis, phi): - sinphi = np.sin(phi) - cosphi = np.cos(phi) - dot = np.dot(axis,v)*(1-cosphi) - new_x = axis[0]*dot+v[0]*cosphi+(-axis[2]*v[1]+axis[1]*v[2])*sinphi - new_y = axis[1]*dot+v[1]*cosphi+(+axis[2]*v[0]-axis[0]*v[2])*sinphi - new_z = axis[2]*dot+v[2]*cosphi+(-axis[1]*v[0]+axis[0]*v[1])*sinphi - return new_x, new_y, new_z + """ + :param v: vector to rotate + :param axis: axis of rotation + :param phi: angle in radians + """ + new_v = RotatePointDegreesAroundAxisDir((0,0,0), axis, v, phi*180/np.pi) + return new_v class NBbeam(object): From d3ae52180de594e95aa92c5b75473479c1c7dc57 Mon Sep 17 00:00:00 2001 From: cschlick Date: Wed, 17 Jan 2024 14:07:28 -0800 Subject: [PATCH 048/748] qscore: add first test, fix some formatting --- .azure-pipelines/py2_syntax_exceptions.txt | 3 ++ cctbx/maptbx/qscore/qscore.py | 2 +- cctbx/maptbx/qscore/qscore_utils.py | 2 +- cctbx/maptbx/qscore/tst_qscore.py | 57 ++++++++++++++++++---- cctbx/programs/qscore.py | 4 +- 5 files changed, 54 insertions(+), 14 deletions(-) diff --git a/.azure-pipelines/py2_syntax_exceptions.txt b/.azure-pipelines/py2_syntax_exceptions.txt index c934a7adfb..0dbb2d8f1d 100644 --- a/.azure-pipelines/py2_syntax_exceptions.txt +++ b/.azure-pipelines/py2_syntax_exceptions.txt @@ -13,3 +13,6 @@ xfel/ui/db/job.py xfel/command_line/cxi_mpi_submit.py xfel/command_line/fee_calibration.py xfel/util/drift.py +cctbx/maptbx/qscore/flex_utils.py +cctbx/maptbx/qscore/qscore_utils.py +cctbx/maptbx/qscore/tst_qscore.py diff --git a/cctbx/maptbx/qscore/qscore.py b/cctbx/maptbx/qscore/qscore.py index c7aadb838a..6322bba37c 100644 --- a/cctbx/maptbx/qscore/qscore.py +++ b/cctbx/maptbx/qscore/qscore.py @@ -19,7 +19,7 @@ from .qscore_utils import ( trilinear_interpolation, - rowwise_corrcoef + rowwise_corrcoef, sphere_points_np, sphere_points_flex, cdist_flex, diff --git a/cctbx/maptbx/qscore/qscore_utils.py b/cctbx/maptbx/qscore/qscore_utils.py index 09d6bd0201..2cd76b5f1e 100644 --- a/cctbx/maptbx/qscore/qscore_utils.py +++ b/cctbx/maptbx/qscore/qscore_utils.py @@ -119,7 +119,7 @@ def sphere_points_np(ctr, rad, N): def sphere_points_flex(ctr, rad, N): -"""Generate points on a sphere, using flex only, as implemented in original qscore from Pintile et al.""" + """Generate points on a sphere, using flex only, as implemented in original qscore from Pintile et al.""" h = -1.0 + (2.0 * flex.double_range(N) / (N-1)) phis = flex.acos(h) diff --git a/cctbx/maptbx/qscore/tst_qscore.py b/cctbx/maptbx/qscore/tst_qscore.py index c20308ce0c..f86719f74e 100644 --- a/cctbx/maptbx/qscore/tst_qscore.py +++ b/cctbx/maptbx/qscore/tst_qscore.py @@ -1,14 +1,51 @@ from __future__ import absolute_import, division, print_function - -from cctbx.maptbx.qscore import qscore_np as qscore +import os +from cctbx.array_family import flex +from iotbx.cli_parser import run_program +import libtbx +from libtbx.utils import null_out +from libtbx.test_utils import approx_equal from iotbx.data_manager import DataManager +from cctbx.programs import qscore + + + + +expected_results = { + +} +# make flex arrays +expected_results = {key:flex.double(val) for key,val in list(expected_results.items())} + +def exercise(test_name): + pdb_file = libtbx.env.find_in_repositories( + relative_path=f"phenix_regression/real_space_refine/data/tst_{test_name}.pdb", + test=os.path.isfile) + + map_file = libtbx.env.find_in_repositories( + relative_path=f"phenix_regression/real_space_refine/data/tst_{test_name}.ccp4", + test=os.path.isfile) + + result = run_program( + program_class=qscore.Program, + args = [pdb_file,map_file,"probe_allocation_method=progressive"], + logger=null_out(), + ) + + try: + expected_result = expected_results[test_name] + assert approx_equal(expected_result, result.qscore,eps=1.e-2) + except: + for val in result.qscore: + print(str(val)+",") + raise -dm = DataManager() -dm.process_real_map_file( - "/Users/user/Desktop/data/data_large/7UAE/emd_26422.map.gz") -dm.process_model_file( - "/Users/user/Desktop/data/data_large/7UAE/pdb7uae.ent.gz") -mmm = dm.get_map_model_manager() -result = qscore(mmm) -print(result) +if (__name__ == "__main__"): + """ + Test random files to verify basic functionality remains unchanged + Data from phenix_regression/real_space_refine/data + """ + for test_name in [17,42,48]: + exercise(test_name) + print("OK") diff --git a/cctbx/programs/qscore.py b/cctbx/programs/qscore.py index 28acacf899..8975e57357 100644 --- a/cctbx/programs/qscore.py +++ b/cctbx/programs/qscore.py @@ -83,7 +83,7 @@ def run(self): nproc=self.params.nproc, version=version, log = self.logger) - print(result) + self.result = group_args(qscore=result) def get_results(self): - return group_args() + return self.result From d28fd4b604a490198e013531e84cad733ccacd55 Mon Sep 17 00:00:00 2001 From: cschlick Date: Wed, 17 Jan 2024 14:18:25 -0800 Subject: [PATCH 049/748] Include test data --- cctbx/maptbx/qscore/tst_qscore.py | 685 +++++++++++++++++++++++++++++- 1 file changed, 684 insertions(+), 1 deletion(-) diff --git a/cctbx/maptbx/qscore/tst_qscore.py b/cctbx/maptbx/qscore/tst_qscore.py index f86719f74e..78a5dd3e8e 100644 --- a/cctbx/maptbx/qscore/tst_qscore.py +++ b/cctbx/maptbx/qscore/tst_qscore.py @@ -12,7 +12,690 @@ expected_results = { - + 17:[ + 0.3421921625599796, +0.23059586409823973, +0.5270018776968665, +0.29184116446707, +0.2973812006489643, +0.07600997821758661, +0.33045716863866426, +0.03962350210737266, +0.45794512843877005, +0.35465168874249403, +0.23226261428093095, +0.26433144001016096, +0.41278635270991104, +0.6186540306246111, +0.3770973684892207, +0.1254397336440012, +0.5285370113101394, +0.2223610365635392, +0.24309534172227623, +0.30352501019319705, +0.2752690339591535, +0.4899237828881729, +0.47240975385758843, +0.22025163500887476, +0.5397425995575168, +0.26138971843050957, +0.1846157694745772, +0.45832140303149244, +0.3199925993370375, +0.35148314291468097, +0.30805876853197545, +0.2348747178532036, +0.40538545573721857, +0.35931982891529424, +0.06674246110537026, +0.08865944371905632, +0.46383366221789635, +0.2414768194261802, +0.48285460422290516, +0.347877304598477, +0.29203014359638124, +0.1947260717344384, +0.3991802715787289, +0.15842934668592273, +0.280357208712987, +0.021717502283329426, +0.4062439964555134, +0.3865031622747038, +0.29816347111472813, +0.45863553488308767, +0.3973819008836693, +0.531306284812025, +0.07867336339275807, +0.25396729661621414, +0.5707587513791409, +0.2600181342944659, +0.21478114239293503, +0.18550113903271073, +0.2997586158550855, +0.44065895599883254, +0.5339912733146549, +0.5059403589930165, +0.399563388207582, +0.31353965867608585, +0.40706293922680536, +0.40852998551402225, +0.37818395249405246, +0.34189236056721284, +0.520108250944137, +0.29432165478083183, +0.34554241140959957, +0.3809737558101816, +0.33047852491034596, +0.12000723357018166, +0.28516860178263526, +0.1304167083889345, +0.3702251144186975, +0.1306375003350293, +0.2525755342807049, +0.305846980315952, +0.36304984160901194, +0.26842234134086995, +0.31851634422367264, +0.11418522944583082, +0.6152548226050001, +0.4291161298297077, +0.10135045960919627, +0.43097837719824467, +0.3569904356893862, +0.3807958467081636, +0.048417434326699954, +0.15985263511257164, +0.5031089728058448, +0.33412590730425046, +0.2440388804247266, +0.22092929565192077, +0.34998096643341287, +0.5328979368545581, +0.4266904867364755, +0.26936514659137617, +0.3358724276862323, +0.14700048638497365, +0.3466519839231303, +0.3589201427103675, +0.3032979999041832, +0.46538655038051413, +0.3466157906620784, +0.24854267539811445, +0.4673383636231253, +0.49684501909476203, +0.14656288530085, +0.2060356161083599, +0.37147775553927004, +0.10325116448725478, +0.3298831493141937, +0.06128012250142477, +0.31965867165876083, +0.20571755422175803, +0.24666581378509295, +0.30188192740566117, +0.44059320534165436, +0.12535259204451776, +0.5391480678714957, +0.3146649234896872, +0.2984529944378834, +0.47059387025463373, +0.33688498405806233, +0.45724566460236, +-0.0847094806977648, +0.45241765479611734, +0.6024926988514311, +0.39043112440534494, +0.29212336908130637, +0.23521496698092792, +0.3331502225292009, +0.4710973854203711, +0.3930399946681371, +0.22618357696966504, +0.36777652710753406, +0.0687204125428958, +0.21794240968140147, +0.4585816225505588, +0.3189379047384071, +0.39631545999706735, +0.33782657195371435, +0.23053542900402393, +0.44634381476198975, +0.378636545735303, +0.0540847735219687, +0.15763453359404314, +0.3720433946019659, +0.2243999801330215, +0.3919840059559488, +0.24155293236144296, +0.5501860352383139, +0.31499601370777963, +0.3898073419940384, +0.25243082713588016, +0.4264068645720301, +0.06425344489908891, +0.44199112723007916, +0.36807522242257723, +0.29785713399865804, +0.412183321562423, +0.33525906932911176, +0.43397598115931846, +-0.010103891048515189, +0.2861456512828132, +0.5159897032252302, +0.3698059640541782, +0.28655590366719214, +0.25513393415337626, +0.2645690349170997, +0.5774885444935143, +0.5722935335150611, +0.12402945863077025, +0.3996273866908372, +0.24242658053677701, +0.32847927480603223, +0.4094780969465886, +0.4156053867514524, +0.17966699996528257, +0.40722902738054584, +0.12689775003918397, +0.371164181132422, +0.3767642054751001, +0.13130550470731653, +0.2581368857773402, +0.4295248268094051, +0.1594754057037172, +0.4822546259691846, +0.26862708250268674, +0.2053994164606709, +0.3314561119080312, +0.3901557321280329, +0.10356267623652139, +0.4893119933324595, +0.06970010217164949, +0.4341832340257733, +0.24300158997333163, +0.40342983455052717, +0.4875152102559497, +0.3611438908961756, +0.43315692556809254, +0.13005314649579647, +0.2789621268926412, +0.5797695620511155, +0.16073844912362031, +0.3189555777730557, +0.25307250722381414, +0.3337698438034294, +0.42692690233657604, +0.39577778624593446, +0.09985873598652467, +0.4519414307186756, +0.2722216910938107, +0.372440061007927, +0.372938237995561, +0.3373188155569413, +0.3077586817882031, +0.3268356422133767, +0.2637935136435236, +0.5124761116179708, +0.45120271947016605, +0.04645127186504295, +0.12464514753785585, +0.4076631108219313, +0.14149061521974549, +0.48019853552270136, +0.3302360313272201, +0.19387184572104918, +0.1276839312082207, +0.16838227799666874, +0.15212252134889084, +0.3938618155397946, +0.007238091652426953, +0.47956784581125006, +0.3628745036188133, +0.15933311523276858, +0.3450436068676078, +0.44003803751547854, +0.4790697870967329, +-0.20012992747200145, +0.22038229028354375, +0.4977640896498761, +0.20051572280775803, +0.37450575803439906, +0.24129734365789224, +0.30395715749502616, +0.5091826977961296, +0.43975091833718905, +0.234910477914851, +0.3763909822880909, +0.12134224515408576, +0.1469207447824904, +0.361680966789992, +0.3224493281226169, +0.1786168704708826, +0.3792230579360604, +0.15281162374642446, +0.42911335989536653, +0.31476367357186996, +0.07673757804961866, +0.10689006194487724, +0.4348292707713999, +0.18393677778574968, + ], + 42:[ + 0.04374859159228914, + 0.7014683292236671, + 0.702452905364866, + 0.7021948503391319, + 0.6321784075459557, + 0.49343050019989493, + 0.2387960398985455, + 0.16175122257257904, + 0.5951430522174325, + 0.7298902031066814, + 0.5532188675136824, + 0.7163124107885536, + 0.20712423014887388, + 0.25430831361146483, + 0.6549198534001504, + 0.7354481865202372, + 0.6662233425951913, + 0.7791061242902525, + 0.702971884514788, + 0.7701247147434058, + 0.7604352888270121, + 0.43373125301322574, + 0.592195693113768, + 0.6364893889382377, + 0.5338124993715777, + 0.8629489169692224, + 0.8309699855651322, + 0.8259201064688118, + 0.6416438069201235, + 0.47825154553942534, + 0.4550092060659318, + 0.7141126193559746, + 0.361378093066521, + 0.5170106846191803, + 0.5707500631718254, + 0.2992092767633682, + 0.5245848435807441, + 0.5457993561949297, + 0.43804435104199724, + 0.6965206562313486, + 0.8337428248309631, + 0.5605077031654175, + 0.6540968584763245, + 0.5637569078486285, + 0.5425493265063142, + 0.7905467036720909, + 0.8127777974919012, + 0.16915735889528427, + 0.8851526077212654, + 0.7229453458130224, + 0.6297422798191332, + 0.5501958845022322, + 0.36465666366132, + 0.31652279968342384, + 0.3922520165718135, + 0.644278729536953, + 0.5976556071675406, + 0.4209522494216284, + 0.8009479990116065, + 0.6466622101616207, + 0.5943185266914189, + 0.6137118595285456, + 0.5007963438613854, + 0.8392920445753075, + 0.720763302874267, + 0.8557279503911867, + 0.666713487421232, + 0.8063221960473734, + 0.8505047278069652, + 0.8497427761241569, + 0.803346479118527, + 0.8499754939112326, + 0.31486843957067545, + 0.5200046832164775, + 0.37186717909606204, + 0.6257089207620644, + 0.5829209564081711, + 0.4418711637191809, + 0.8382691191598867, + 0.3985977869183781, + 0.6716185017722498, + 0.4282676780478786, + 0.4769409624386573, + 0.5910446920430065, + 0.8944305471390882, + 0.8928567384381616, + 0.7827931482685355, + 0.6583803668742215, + 0.5991078586481865, + 0.08023769884309902, + 0.6681897301421666, + 0.37209308303777267, + 0.6415923372742239, + 0.4426268000273496, + 0.8688990816217295, + 0.8070367895141034, + 0.8720127649194883, + 0.8203465022935613, + 0.8338592104583938, + 0.6990620518701595, + 0.2149555598988231, + 0.7567926316813701, + 0.8575551185788508, + 0.6933730350449754, + 0.9161219623118465, + 0.732624707051576, + 0.7555994039397524, + 0.5442291068799832, + 0.4627745063207215, + 0.7993664076349526, + 0.5256150479791528, + 0.6760701859645473, + 0.1302511186971115, + 0.7937133262639481, + 0.5220560401977098, + 0.28486982673453465, + 0.8325957396927982, + 0.8513773917569079, + 0.7475582394501862, + 0.8048612849474618, + 0.8214530862558614, + 0.8265812540190871, + 0.7242004339085576, + 0.8846853466892513, + 0.819423901100646, + 0.8313477848815514, + 0.5755446895056169, + 0.2546135793925592, + 0.5574703129705603, + 0.7300843901002169, + 0.5305151067732694, + 0.37122485649150677, + 0.8986747212742561, + 0.8380225816078332, + 0.7614209371152203, + 0.8960858704306193, + 0.7226287919159747, + 0.37728834622953006, + 0.21982393465181072, + 0.5455923669432795, + 0.6875281916354992, + 0.6560338112643748, + 0.7666954073180295, + 0.5964728319202803, + 0.8241982508051366, + 0.7981306054065668, + 0.8648202347360532, + 0.6202773580633816, + 0.40183146013098137, + 0.863659879304468, + 0.7328936642623606, + 0.43331966960473806, + 0.41051665674688637, + 0.3732321485324986, + 0.35704325729788094, + 0.33229209164428214, + 0.6168027054172801, + 0.6693757063241048, + 0.7826022797198974, + 0.5377086752347333, + 0.6730535064545592 + ], + 48: [ + 0.5968541254772408, +0.5888149798397792, +0.315582500635734, +0.687079314914942, +-0.10788849213050972, +0.16254718641158727, +0.32455597581368123, +0.5302638476888132, +0.403992922141881, +0.6100358301708605, +0.5771768770057722, +0.2792661235629232, +0.2575949934159178, +0.6043836583958772, +0.7708730081576577, +0.6242504407090721, +0.13591271842406735, +0.18614841272819024, +-0.2628077298805197, +0.22025502165116118, +0.7091768516167763, +0.40239405704252396, +0.09949923664253973, +-0.054100560826983536, +0.21038809613088602, +0.007996193327384046, +0.6357088374844898, +0.258324242452466, +0.6917422678350181, +0.6857337642645633, +0.13084883287439783, +0.11834600629053386, +0.11256061932813789, +-0.32197959142088056, +0.1964277228764244, +0.5263412467056378, +0.47750577744670736, +0.6273411730359443, +0.5644985300402862, +-0.04914315380458464, +0.50787821609155, +0.6796080766675747, +0.49186053449280276, +0.7509837193151416, +0.4890882429801768, +0.10679031788648738, +0.40916823804687474, +0.788255742665104, +0.6570069433758265, +-0.19528178901870677, +-0.39998361609636585, +-0.5779325051441814, +0.6451869255926912, +0.5718358631709289, +0.3271255576435047, +0.5473709345665331, +0.6434335071057217, +0.4524362607690744, +0.6898807824065822, +0.7072495487992003, +0.6194096112060017, +-0.16830340496094134, +-0.4170271322831438, +-0.4642359202007596, +-0.4178461988711234, +0.6073341350813557, +0.5855734753991133, +0.8564952874666714, +0.6839532113518676, +0.5000213127939919, +-0.08326968807387838, +0.3570602870558649, +0.7018663463617603, +0.711969366411144, +0.44508111920540083, +0.5473132202073291, +0.4655274120927994, +0.7078374526458721, +0.17372169440403212, +-0.2522585714614016, +0.4648877781222761, +0.7597726350278259, +0.6707870646835342, +0.6573007782788086, +0.5198339575453219, +-0.0006526550069698477, +0.6072461380958942, +0.4214311340917669, +0.7173940904184968, +0.35733529642917017, +0.5589328732056613, +0.612336593479406, +0.6507700208799166, +0.25559454694029293, +0.44820830149665475, +0.7185191357007285, +0.5060258719916453, +0.5497397450602441, +0.5622895985717057, +0.5011199096743087, +0.1708925623515588, +-0.22131743662693917, +0.24501870130290582, +0.5196556754058135, +0.6172331426177281, +0.7029724816347478, +-0.025298909940450143, +0.36765131991932465, +0.2627628940499585, +0.6321682268748771, +-0.0500688433871909, +0.5763335415597144, +0.008612564030688004, +0.4472234144081752, +0.5929092758866635, +0.6843005300904107, +0.6651767633174818, +0.26333429778606227, +0.6414457509892533, +0.14438088419608539, +-0.21222131040832543, +0.10109932103828434, +0.34494471024693685, +0.5990874755868693, +0.7035932607975525, +0.4857858052204092, +0.4281832690795328, +0.2891807006509428, +0.22222323149421325, +0.203906427947274, +0.04671623310290915, +0.44848477802023157, +0.44684211728874007, +0.5645615585513909, +0.6342758281949152, +0.7489086658409955, +0.589070738843178, +0.41800198826016766, +0.4961210628234994, +-0.12984928751527708, +0.39110688153345324, +0.4928519249525499, +0.45581559545936545, +0.21425438653612414, +0.407549256302758, +-0.15035212940105575, +0.07036429249131188, +0.6488945090989772, +0.4946267386677905, +0.6382812819654359, +0.23775216404460772, +0.3055450860933104, +-0.16833165794875501, +-0.19048152061339418, +0.5553859609305851, +0.5406222276872222, +0.6415299499364683, +0.5487751251087766, +-0.09145281911606847, +0.28984243303281065, +0.009656212224640586, +0.1494707876965392, +0.11035761336516262, +0.5228293409179153, +0.22983894819798084, +0.4718316173428129, +0.44675298345251324, +0.6110538799666169, +0.40431875240561327, +0.46617059636437935, +0.45627276687090956, +-0.117947116698063, +0.4116000349271482, +0.5765557749775085, +0.2544777230831843, +0.4723904664490961, +0.024926912888517457, +0.5621786040077159, +0.6353312649614798, +-0.11651261586048801, +0.5633206031940512, +0.38602830801407023, +0.3703387686372386, +0.3144119800821697, +0.6892262947019678, +0.3760829781443364, +0.07418780367285109, +-0.19462135663672434, +0.4108928059365392, +0.29895474397513155, +0.6352052484435172, +0.2737730076758392, +0.1744028531150664, +0.10210585799412926, +0.3275183577296833, +-0.30303731977501597, +-0.24431571115581802, +0.7950029444847503, +0.3796560948926144, +0.5818371159456599, +0.4491548136066217, +-0.04931907230118858, +0.37017358917348503, +0.023401235075432583, +-0.09782988358799102, +0.63977831753492, +0.4321582398644358, +0.25078377961765774, +0.3469515045045513, +0.40989287767077875, +0.4376901052054188, +0.09475319685420992, +0.05742918560522124, +-0.46513487300102824, +-0.11594752857285522, +0.12854571044295462, +0.36297737921070805, +0.7694305255605903, +0.6152924317603523, +0.41393102341071225, +0.5477717598392893, +-0.2402803578626161, +0.4923987790733689, +0.24427080665726864, +0.5527035011741326, +0.520481852292403, +0.2545693380532749, +0.2943667973934887, +0.13894357009748437, +0.7620957496844697, +0.6147574799490112, +0.7580367523339745, +0.5457950033094567, +0.7178761945864589, +0.6757214005391818, +0.4788983409036063, +-0.0303463202660314, +0.6900029820032803, +0.5025196729969039, +0.602699059074302, +0.6107175777294718, +0.6514091338122153, +0.2821497089278383, +0.24515795566596624, +0.548841907952178, +0.5182059748859397, +0.788365623661261, +0.5841782769142585, +0.31236692438409164, +0.45591686200983655, +0.6797742941938839, + ] } # make flex arrays expected_results = {key:flex.double(val) for key,val in list(expected_results.items())} From 35d1174ae9cc700c44ac86fbece730bef8a40811 Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 23 Jan 2024 10:09:52 -0800 Subject: [PATCH 050/748] Major refactor to condense to a single file --- cctbx/maptbx/{qscore => }/qscore.py | 449 ++++++++++++++++- cctbx/maptbx/qscore/__init__.py | 1 - cctbx/maptbx/qscore/flex_utils.py | 121 ----- cctbx/maptbx/qscore/qscore_utils.py | 304 ------------ cctbx/maptbx/qscore/tst_qscore.py | 734 ---------------------------- cctbx/maptbx/tst_qscore.py | 320 ++++++++++++ cctbx/programs/qscore.py | 10 +- 7 files changed, 764 insertions(+), 1175 deletions(-) rename cctbx/maptbx/{qscore => }/qscore.py (55%) delete mode 100644 cctbx/maptbx/qscore/__init__.py delete mode 100644 cctbx/maptbx/qscore/flex_utils.py delete mode 100644 cctbx/maptbx/qscore/qscore_utils.py delete mode 100644 cctbx/maptbx/qscore/tst_qscore.py create mode 100644 cctbx/maptbx/tst_qscore.py diff --git a/cctbx/maptbx/qscore/qscore.py b/cctbx/maptbx/qscore.py similarity index 55% rename from cctbx/maptbx/qscore/qscore.py rename to cctbx/maptbx/qscore.py index 6322bba37c..861a11c1e1 100644 --- a/cctbx/maptbx/qscore/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -10,23 +10,29 @@ from __future__ import division import math import sys +from collections import defaultdict +from multiprocessing import Pool, cpu_count +from itertools import chain + import numpy as np +import numpy.ma as ma + from scipy.spatial import KDTree -from multiprocessing import Pool, cpu_count +import cctbx from cctbx.array_family import flex from scitbx_array_family_flex_ext import bool as flex_bool -from .qscore_utils import ( - trilinear_interpolation, - rowwise_corrcoef, - sphere_points_np, - sphere_points_flex, - cdist_flex, - query_ball_point_flex, - query_atom_neighbors, -) -from .flex_utils import optimized_nd_to_1d_indices, nd_to_1d_indices, flex_std +# from .qscore_utils import ( +# trilinear_interpolation, +# rowwise_corrcoef, +# sphere_points_np, +# sphere_points_flex, +# cdist_flex, +# query_ball_point_flex, +# query_atom_neighbors, +# ) +# from .flex_utils import optimized_nd_to_1d_indices, nd_to_1d_indices, flex_std try: from tqdm import tqdm @@ -34,6 +40,7 @@ from .qscore_utils import DummyTQDM as tqdm + def radial_shell_worker_v1_np(args): """ Calulate qscore for a single radial shell using version 1 (serial probe allocation) and numpy @@ -233,7 +240,17 @@ def radial_shell_mp_np( return probe_xyz, probe_mask - +def ndarray_to_nested_list(arr): + """ + Convert a NumPy array of arbitrary dimensions into a nested list. + :param arr: A NumPy array. + :return: A nested list representing the array. + """ + if arr.ndim == 1: + return arr.tolist() + return [ndarray_to_nested_list(sub_arr) for sub_arr in arr] + +# Example usage def qscore_np( mmm, selection=None, @@ -276,7 +293,7 @@ def qscore_np( radii=radii, log=log, ) - # return probe_xyz,probe_mask + # after the probe generation, versions 1 and 2 are the same # infer params from shape @@ -332,6 +349,21 @@ def qscore_np( # # numpy q = rowwise_corrcoef(g_vals_2d, d_vals_2d, mask=mask_2d) + + # # Log + # import os + + # print("FINISHING...") + # print(os.getcwd()) + # print("saving atoms xyz: atom_xyz_np.npy") + # np.save("atoms_xyz_np.npy",model.get_sites_cart().as_numpy_array()) + # print("saving probe xyz: probe_xyz_np.npy") + # np.save("probe_xyz_np.npy",probe_xyz) + # print("saving probe mask: probe_mask_np.npy") + # np.save("probe_mask_np.npy",probe_mask) + # print("saving qscore: qscore_np.npy") + # np.save("qscore_np.npy",q) + return q @@ -595,3 +627,394 @@ def custom_reshape_indices(flex_array): q = flex.double(q_cctbx) return q + + + + +### qscore utils + + + +class DummyTQDM: + """A 'dummy' object that can be used for compatibility if tqdm is not installed""" + def __init__(self, iterable=None, *args, **kwargs): + self.iterable = iterable + self.args = args + self.kwargs = kwargs + + def __iter__(self): + return iter(self.iterable) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + pass + + +def trilinear_interpolation(voxel_grid, coords, voxel_size=None, offset=None): + """Numpy trilinear interpolation""" + assert voxel_size is not None, "Provide voxel size as an array or single value" + + # Apply offset if provided + if offset is not None: + coords = coords - offset + + # Transform coordinates to voxel grid index space + index_coords = coords / voxel_size + + # Split the index_coords array into three arrays: x, y, and z + x, y, z = index_coords.T + + # Truncate to integer values + x0, y0, z0 = np.floor([x, y, z]).astype(int) + x1, y1, z1 = np.ceil([x, y, z]).astype(int) + + # Ensure indices are within grid boundaries + x0, y0, z0 = np.clip([x0, y0, z0], 0, voxel_grid.shape[0]-1) + x1, y1, z1 = np.clip([x1, y1, z1], 0, voxel_grid.shape[0]-1) + + # Compute weights + xd, yd, zd = [arr - arr.astype(int) for arr in [x, y, z]] + + # Interpolate along x + c00 = voxel_grid[x0, y0, z0]*(1-xd) + voxel_grid[x1, y0, z0]*xd + c01 = voxel_grid[x0, y0, z1]*(1-xd) + voxel_grid[x1, y0, z1]*xd + c10 = voxel_grid[x0, y1, z0]*(1-xd) + voxel_grid[x1, y1, z0]*xd + c11 = voxel_grid[x0, y1, z1]*(1-xd) + voxel_grid[x1, y1, z1]*xd + + # Interpolate along y + c0 = c00*(1-yd) + c10*yd + c1 = c01*(1-yd) + c11*yd + + # Interpolate along z + c = c0*(1-zd) + c1*zd + + return c + + +def rowwise_corrcoef(A, B, mask=None): + """Numpy masked array rowwise correlation coefficient""" + assert A.shape == B.shape, f"A and B must have the same shape, got: {A.shape} and {B.shape}" + + if mask is not None: + assert mask.shape == A.shape, "mask must have the same shape as A and B" + A = ma.masked_array(A, mask=np.logical_not(mask)) + B = ma.masked_array(B, mask=np.logical_not(mask)) + + # Calculate means + A_mean = ma.mean(A, axis=1, keepdims=True) + B_mean = ma.mean(B, axis=1, keepdims=True) + + # Subtract means + A_centered = A - A_mean + B_centered = B - B_mean + + # Calculate sum of products + sumprod = ma.sum(A_centered * B_centered, axis=1) + + # Calculate square roots of the sum of squares + sqrt_sos_A = ma.sqrt(ma.sum(A_centered**2, axis=1)) + sqrt_sos_B = ma.sqrt(ma.sum(B_centered**2, axis=1)) + + # Return correlation coefficients + cc = sumprod / (sqrt_sos_A * sqrt_sos_B) + return cc.data + +def sphere_points_np(ctr, rad, N, mode='SpherePts'): + """ + Points on a sphere given centers, radius, number N + + TODO: Mode is confusing, it is not clear why there is a difference. + mode='SpherePts' an attempt to literally copy the SpherePts function from mapq + mode='original' a version that gives the same results as the QscorePt3 function from mapq + """ + h = -1.0 + (2.0 * np.arange(N) / float(N-1)) + phis = np.arccos(h) + + if mode == 'original': + thetas = np.zeros(N) + a = (3.6 / np.sqrt(N * (1.0 - h[1:-1]**2))) + thetas[1:-1] = a + thetas = np.cumsum(thetas) + elif mode == 'SpherePts': + thetas = np.zeros(N) + for k in range(1, N): + if k == 1 or k == N - 1: + thetas[k] = 0 + else: + thetas[k] = (thetas[k-1] + 3.6 / np.sqrt(N * (1 - h[k]**2))) % (2 * np.pi) + thetas = thetas.cumsum() + + x = np.sin(phis) * np.cos(thetas) + y = np.sin(phis) * np.sin(thetas) + z = np.cos(phis) + + points = rad * np.stack([x, y, z], axis=-1) + + # Adjusting for multiple centers + if ctr.ndim == 1: + # Single center case + points = points + ctr + else: + # Multiple centers case + points = points.reshape(-1, 1, 3) + ctr.reshape(1, -1, 3) + + + return points + + +def cdist_flex(A, B): + """A flex implementation of the cdist function""" + + def indices_2d_flex(dimensions): + N = len(dimensions) + if N != 2: + raise ValueError("Only 2D is supported for this implementation.") + + # Create the row indices + row_idx = flex.size_t(chain.from_iterable( + [[i] * dimensions[1] for i in range(dimensions[0])])) + + # Create the column indices + col_idx = flex.size_t(chain.from_iterable( + [list(range(dimensions[1])) for _ in range(dimensions[0])])) + + return row_idx, col_idx + + i_idxs, j_idxs = indices_2d_flex((A.focus()[0], B.focus()[0])) + + r = i_idxs + xi = i_idxs*3 + yi = i_idxs*3 + 1 + zi = i_idxs*3 + 2 + + xa = A.select(xi) + ya = A.select(yi) + za = A.select(zi) + + xj = j_idxs*3 + yj = j_idxs*3 + 1 + zj = j_idxs*3 + 2 + + xb = B.select(xj) + yb = B.select(yj) + zb = B.select(zj) + + d = ((xb - xa)**2 + (yb - ya)**2 + (zb - za)**2)**0.5 + d.reshape(flex.grid((A.focus()[0], B.focus()[0]))) + + return d + + +def query_atom_neighbors(model, radius=3.5, include_self=True, only_unit=True): + """Perform radial nearest neighbor searches using cctbx tools, for atom coordinates in a model""" + crystal_symmetry = model.crystal_symmetry() + hierarchy = model.get_hierarchy() + sites_cart = hierarchy.atoms().extract_xyz() + sst = crystal_symmetry.special_position_settings().site_symmetry_table( + sites_cart=sites_cart) + conn_asu_mappings = crystal_symmetry.special_position_settings().\ + asu_mappings(buffer_thickness=5) + conn_asu_mappings.process_sites_cart( + original_sites=sites_cart, + site_symmetry_table=sst) + conn_pair_asu_table = cctbx.crystal.pair_asu_table( + asu_mappings=conn_asu_mappings) + conn_pair_asu_table.add_all_pairs(distance_cutoff=radius) + pair_generator = cctbx.crystal.neighbors_fast_pair_generator( + conn_asu_mappings, + distance_cutoff=radius) + fm = crystal_symmetry.unit_cell().fractionalization_matrix() + om = crystal_symmetry.unit_cell().orthogonalization_matrix() + + pairs = list(pair_generator) + inds = defaultdict(list) + dists = defaultdict(list) + + for pair in pairs: + i, j = pair.i_seq, pair.j_seq + rt_mx_i = conn_asu_mappings.get_rt_mx_i(pair) + rt_mx_j = conn_asu_mappings.get_rt_mx_j(pair) + rt_mx_ji = rt_mx_i.inverse().multiply(rt_mx_j) + + if (only_unit and rt_mx_ji.is_unit_mx()) or (not only_unit): + d = round(math.sqrt(pair.dist_sq), 6) + inds[i].append(j) + dists[i].append(d) + + # add reverse + inds[j].append(i) + dists[j].append(d) + # print(pair.i_seq, pair.j_seq, rt_mx_ji, math.sqrt(pair.dist_sq), de) + + # add self + if include_self: + for key, value in list(inds.items()): + dval = dists[key] + dists[key] = dval+[0.0] + inds[key] = value+[key] + + # sort + for key, value in list(inds.items()): + dval = dists[key] + # sort + sorted_pairs = sorted(set(list(zip(value, dval)))) + value_sorted, dval_sorted = zip(*sorted_pairs) + inds[key] = value_sorted + dists[key] = dval_sorted + + return inds, dists + + +def query_ball_point_flex(tree, tree_xyz, query_xyz, r=None): + """ + Imitate the api of the scipy.spatial query_ball_point function, but using only flex arrays. + Note: This just copies the api, it does not actually use a tree structure, so is much slower. + """ + assert r is not None, "provide radius" + n_atoms, n_probes, _ = query_xyz.focus() + counts = [] + + for atom_i in range(n_atoms): + probe_range = (n_probes * atom_i * 3, n_probes * (atom_i+1) * 3) + atom_probes_xyz = query_xyz.select(flex.size_t_range(*probe_range)) + atom_probes_xyz.reshape(flex.grid(n_probes, 3)) + nbrs = tree[atom_i] + n_nbrs = len(nbrs) + nbrs_xyz = tree_xyz.select(flex.size_t(nbrs)).as_1d().as_double() + nbrs_xyz.reshape(flex.grid(len(nbrs), 3)) + d = cdist_flex(nbrs_xyz, atom_probes_xyz) + sel = d < r + count = [] + for nbr_i in range(n_probes): + nbr_range = (slice(0, n_nbrs), slice(nbr_i, nbr_i+1)) + count_nbr = sel[nbr_range].count(True) + count.append(count_nbr) + + counts.append(count) + + counts = flex_from_list(counts) + return counts + + +### flex utils + + +def flex_from_list(lst, signed_int=False): + """Generate a flex array from a list, try to infer type""" + flat_list, shape = flatten_and_shape(lst) + dtype = get_dtype_of_list(flat_list) + type_mapper = {int: flex.size_t, + float: flex.double, + bool: flex.bool} + if signed_int: + type_mapper[int] = flex.int16 + + # make flex array + assert dtype in type_mapper, f"Unrecognized type: {dtype}" + flex_func = type_mapper[dtype] + flex_array = flex_func(flat_list) + if len(shape) > 1: + flex_array.reshape(flex.grid(*shape)) + return flex_array + + +def flatten_and_shape(lst): + """Flatten a nested list and return its shape.""" + def helper(l): + if not isinstance(l, list): + return [l], () + flat = [] + shapes = [] + for item in l: + f, s = helper(item) + flat.extend(f) + shapes.append(s) + if len(set(shapes)) != 1: + raise ValueError("Ragged nested list detected.") + return flat, (len(l),) + shapes[0] + + flattened, shape = helper(lst) + return flattened, shape + + +def get_dtype_of_list(lst): + dtypes = {type(item) for item in lst} + + if len(dtypes) > 1: + raise ValueError("Multiple data types detected.") + elif len(dtypes) == 0: + raise ValueError("Empty list provided.") + else: + return dtypes.pop() + + +def nd_to_1d_indices(indices, shape): + """Generate the 1d indices given nd indices and an array shape""" + # Normalize indices to always use slice objects + normalized_indices = [] + for dim, idx in enumerate(indices): + if idx is None: + normalized_indices.append(slice(0, shape[dim])) + else: + normalized_indices.append(idx) + + # If any index is a slice, recursively call function for each value in slice + for dim, (i, s) in enumerate(zip(normalized_indices, shape)): + if isinstance(i, slice): + result_indices = [] + start, stop, step = i.indices(s) + for j in range(start, stop, step): + new_indices = list(normalized_indices) + new_indices[dim] = j + result_indices.extend(nd_to_1d_indices(new_indices, shape)) + return result_indices + + # If no slices, calculate single 1D index + index = 0 + stride = 1 + for i, dim in reversed(list(zip(normalized_indices, shape))): + index += i * stride + stride *= dim + return [index] + +def optimized_nd_to_1d_indices(i, shape): + """Similar to above, but hardcoded to select a single index on dimension 1""" + # For fixed input of (None, i, None), we directly compute based on given structure + result_indices = [] + + # Pre-compute for 1st dimension which is always a slice + start1, stop1 = 0, shape[0] + + # Pre-compute for 3rd dimension which is always a slice + start3, stop3 = 0, shape[2] + stride3 = 1 + + # Directly compute for 2nd dimension which is variable + stride2 = shape[2] + index2 = i * stride2 * shape[0] + + for val1 in range(start1, stop1): + for val3 in range(start3, stop3): + result_indices.append(val1 * stride2 + index2 + val3 * stride3) + + return result_indices + + +def flex_std(flex_array): + """Standard deviation""" + n = flex_array.size() + if n <= 1: + raise ValueError("Sample size must be greater than 1") + + # Compute the mean + mean_value = flex.mean(flex_array) + + # Compute the sum of squared deviations + squared_deviations = (flex_array - mean_value) ** 2 + sum_squared_deviations = flex.sum(squared_deviations) + + # Compute the standard deviation + std_dev = (sum_squared_deviations / (n - 1)) ** 0.5 + return std_dev diff --git a/cctbx/maptbx/qscore/__init__.py b/cctbx/maptbx/qscore/__init__.py deleted file mode 100644 index 8a531fc130..0000000000 --- a/cctbx/maptbx/qscore/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .qscore import * \ No newline at end of file diff --git a/cctbx/maptbx/qscore/flex_utils.py b/cctbx/maptbx/qscore/flex_utils.py deleted file mode 100644 index 1e6465bd4b..0000000000 --- a/cctbx/maptbx/qscore/flex_utils.py +++ /dev/null @@ -1,121 +0,0 @@ -from __future__ import division -from cctbx.array_family import flex - - -def flex_from_list(lst, signed_int=False): - """Generate a flex array from a list, try to infer type""" - flat_list, shape = flatten_and_shape(lst) - dtype = get_dtype_of_list(flat_list) - type_mapper = {int: flex.size_t, - float: flex.double, - bool: flex.bool} - if signed_int: - type_mapper[int] = flex.int16 - - # make flex array - assert dtype in type_mapper, f"Unrecognized type: {dtype}" - flex_func = type_mapper[dtype] - flex_array = flex_func(flat_list) - if len(shape) > 1: - flex_array.reshape(flex.grid(*shape)) - return flex_array - - -def flatten_and_shape(lst): - """Flatten a nested list and return its shape.""" - def helper(l): - if not isinstance(l, list): - return [l], () - flat = [] - shapes = [] - for item in l: - f, s = helper(item) - flat.extend(f) - shapes.append(s) - if len(set(shapes)) != 1: - raise ValueError("Ragged nested list detected.") - return flat, (len(l),) + shapes[0] - - flattened, shape = helper(lst) - return flattened, shape - - -def get_dtype_of_list(lst): - dtypes = {type(item) for item in lst} - - if len(dtypes) > 1: - raise ValueError("Multiple data types detected.") - elif len(dtypes) == 0: - raise ValueError("Empty list provided.") - else: - return dtypes.pop() - - -def nd_to_1d_indices(indices, shape): - """Generate the 1d indices given nd indices and an array shape""" - # Normalize indices to always use slice objects - normalized_indices = [] - for dim, idx in enumerate(indices): - if idx is None: - normalized_indices.append(slice(0, shape[dim])) - else: - normalized_indices.append(idx) - - # If any index is a slice, recursively call function for each value in slice - for dim, (i, s) in enumerate(zip(normalized_indices, shape)): - if isinstance(i, slice): - result_indices = [] - start, stop, step = i.indices(s) - for j in range(start, stop, step): - new_indices = list(normalized_indices) - new_indices[dim] = j - result_indices.extend(nd_to_1d_indices(new_indices, shape)) - return result_indices - - # If no slices, calculate single 1D index - index = 0 - stride = 1 - for i, dim in reversed(list(zip(normalized_indices, shape))): - index += i * stride - stride *= dim - return [index] - -def optimized_nd_to_1d_indices(i, shape): - """Similar to above, but hardcoded to select a single index on dimension 1""" - # For fixed input of (None, i, None), we directly compute based on given structure - result_indices = [] - - # Pre-compute for 1st dimension which is always a slice - start1, stop1 = 0, shape[0] - - # Pre-compute for 3rd dimension which is always a slice - start3, stop3 = 0, shape[2] - stride3 = 1 - - # Directly compute for 2nd dimension which is variable - stride2 = shape[2] - index2 = i * stride2 * shape[0] - - for val1 in range(start1, stop1): - for val3 in range(start3, stop3): - result_indices.append(val1 * stride2 + index2 + val3 * stride3) - - return result_indices - - -def flex_std(flex_array): - """Standard deviation""" - n = flex_array.size() - if n <= 1: - raise ValueError("Sample size must be greater than 1") - - # Compute the mean - mean_value = flex.mean(flex_array) - - # Compute the sum of squared deviations - squared_deviations = (flex_array - mean_value) ** 2 - sum_squared_deviations = flex.sum(squared_deviations) - - # Compute the standard deviation - std_dev = (sum_squared_deviations / (n - 1)) ** 0.5 - return std_dev diff --git a/cctbx/maptbx/qscore/qscore_utils.py b/cctbx/maptbx/qscore/qscore_utils.py deleted file mode 100644 index 2cd76b5f1e..0000000000 --- a/cctbx/maptbx/qscore/qscore_utils.py +++ /dev/null @@ -1,304 +0,0 @@ -from __future__ import division -import math -from collections import defaultdict -from itertools import chain - -import numpy as np -import numpy.ma as ma -import cctbx -from cctbx.array_family import flex - -from .flex_utils import * - - -class DummyTQDM: - """A 'dummy' object that can be used for compatibility if tqdm is not installed""" - def __init__(self, iterable=None, *args, **kwargs): - self.iterable = iterable - self.args = args - self.kwargs = kwargs - - def __iter__(self): - return iter(self.iterable) - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, traceback): - pass - - -def trilinear_interpolation(voxel_grid, coords, voxel_size=None, offset=None): - """Numpy trilinear interpolation""" - assert voxel_size is not None, "Provide voxel size as an array or single value" - - # Apply offset if provided - if offset is not None: - coords = coords - offset - - # Transform coordinates to voxel grid index space - index_coords = coords / voxel_size - - # Split the index_coords array into three arrays: x, y, and z - x, y, z = index_coords.T - - # Truncate to integer values - x0, y0, z0 = np.floor([x, y, z]).astype(int) - x1, y1, z1 = np.ceil([x, y, z]).astype(int) - - # Ensure indices are within grid boundaries - x0, y0, z0 = np.clip([x0, y0, z0], 0, voxel_grid.shape[0]-1) - x1, y1, z1 = np.clip([x1, y1, z1], 0, voxel_grid.shape[0]-1) - - # Compute weights - xd, yd, zd = [arr - arr.astype(int) for arr in [x, y, z]] - - # Interpolate along x - c00 = voxel_grid[x0, y0, z0]*(1-xd) + voxel_grid[x1, y0, z0]*xd - c01 = voxel_grid[x0, y0, z1]*(1-xd) + voxel_grid[x1, y0, z1]*xd - c10 = voxel_grid[x0, y1, z0]*(1-xd) + voxel_grid[x1, y1, z0]*xd - c11 = voxel_grid[x0, y1, z1]*(1-xd) + voxel_grid[x1, y1, z1]*xd - - # Interpolate along y - c0 = c00*(1-yd) + c10*yd - c1 = c01*(1-yd) + c11*yd - - # Interpolate along z - c = c0*(1-zd) + c1*zd - - return c - - -def rowwise_corrcoef(A, B, mask=None): - """Numpy masked array rowwise correlation coefficient""" - assert A.shape == B.shape, f"A and B must have the same shape, got: {A.shape} and {B.shape}" - - if mask is not None: - assert mask.shape == A.shape, "mask must have the same shape as A and B" - A = ma.masked_array(A, mask=np.logical_not(mask)) - B = ma.masked_array(B, mask=np.logical_not(mask)) - - # Calculate means - A_mean = ma.mean(A, axis=1, keepdims=True) - B_mean = ma.mean(B, axis=1, keepdims=True) - - # Subtract means - A_centered = A - A_mean - B_centered = B - B_mean - - # Calculate sum of products - sumprod = ma.sum(A_centered * B_centered, axis=1) - - # Calculate square roots of the sum of squares - sqrt_sos_A = ma.sqrt(ma.sum(A_centered**2, axis=1)) - sqrt_sos_B = ma.sqrt(ma.sum(B_centered**2, axis=1)) - - # Return correlation coefficients - cc = sumprod / (sqrt_sos_A * sqrt_sos_B) - return cc.data - - -def sphere_points_np(ctr, rad, N): - """Generate points on a sphere, using numpy, as implemented in original qscore from Pintile et al.""" - # ctr is shape (N,3) - # print("sphere_points_ctr_input_shape",ctr.shape) - h = -1.0 + (2.0 * np.arange(N) / float(N-1))[:, np.newaxis] - phis = np.arccos(h) - thetas = np.zeros_like(phis) - a = (3.6 / np.sqrt(N * (1.0 - h[1:-1]**2))) - thetas[1:-1, :] = a - thetas = np.cumsum(thetas, axis=0) - x = np.sin(phis) * np.cos(thetas) - y = np.sin(phis) * np.sin(thetas) - z = np.cos(phis) - points = rad * np.stack([x, y, z], axis=-1) - points = points.reshape(1, N, 3) - ctr = ctr[:, np.newaxis, :] - points = ctr + points # broadcast add - return points - - -def sphere_points_flex(ctr, rad, N): - """Generate points on a sphere, using flex only, as implemented in original qscore from Pintile et al.""" - - h = -1.0 + (2.0 * flex.double_range(N) / (N-1)) - phis = flex.acos(h) - thetas = flex.double(len(phis), 0.0) - a = (3.6 / flex.sqrt(N * (1.0 - h[1:-1]**2))) - thetas = thetas.set_selected(flex.size_t_range(1, N-1), a) - - # cumulative sum operation - def cumsum_flex(arr): - # should perform as np.cumsum - result = [] - running_sum = 0.0 - for i, x in enumerate(arr): - running_sum += x - result.append(running_sum) - return flex.double(result) - - thetas = cumsum_flex(thetas) - x = flex.sin(phis) * flex.cos(thetas) - y = flex.sin(phis) * flex.sin(thetas) - z = flex.cos(phis) - rad = float(rad) - points = rad * flex.vec3_double(x, y, z) - - # add generated points to center points - def broadcast_add(ctr, points): - - # add and populate additional dimension. equivalent to: - # result = ctr[:, np.newaxis, :] + points - - N = points.size() - M = ctr.size() - # Preallocate an array of shape (M*N, 3) - result = flex.vec3_double(M*N) - - for i in range(M): - for j in range(N): - flat_index = i * N + j - new_point = tuple(ctr[i:i+1] + points[j:j+1])[0] - result[flat_index] = new_point - - result = result.as_1d().as_double() - result.reshape(flex.grid(len(ctr), len(points), 3)) - return result - - # apply function - points = broadcast_add(ctr, points) - return points - - -def cdist_flex(A, B): - """A flex implementation of the cdist function""" - - def indices_2d_flex(dimensions): - N = len(dimensions) - if N != 2: - raise ValueError("Only 2D is supported for this implementation.") - - # Create the row indices - row_idx = flex.size_t(chain.from_iterable( - [[i] * dimensions[1] for i in range(dimensions[0])])) - - # Create the column indices - col_idx = flex.size_t(chain.from_iterable( - [list(range(dimensions[1])) for _ in range(dimensions[0])])) - - return row_idx, col_idx - - i_idxs, j_idxs = indices_2d_flex((A.focus()[0], B.focus()[0])) - - r = i_idxs - xi = i_idxs*3 - yi = i_idxs*3 + 1 - zi = i_idxs*3 + 2 - - xa = A.select(xi) - ya = A.select(yi) - za = A.select(zi) - - xj = j_idxs*3 - yj = j_idxs*3 + 1 - zj = j_idxs*3 + 2 - - xb = B.select(xj) - yb = B.select(yj) - zb = B.select(zj) - - d = ((xb - xa)**2 + (yb - ya)**2 + (zb - za)**2)**0.5 - d.reshape(flex.grid((A.focus()[0], B.focus()[0]))) - - return d - - -def query_atom_neighbors(model, radius=3.5, include_self=True, only_unit=True): - """Perform radial nearest neighbor searches using cctbx tools, for atom coordinates in a model""" - crystal_symmetry = model.crystal_symmetry() - hierarchy = model.get_hierarchy() - sites_cart = hierarchy.atoms().extract_xyz() - sst = crystal_symmetry.special_position_settings().site_symmetry_table( - sites_cart=sites_cart) - conn_asu_mappings = crystal_symmetry.special_position_settings().\ - asu_mappings(buffer_thickness=5) - conn_asu_mappings.process_sites_cart( - original_sites=sites_cart, - site_symmetry_table=sst) - conn_pair_asu_table = cctbx.crystal.pair_asu_table( - asu_mappings=conn_asu_mappings) - conn_pair_asu_table.add_all_pairs(distance_cutoff=radius) - pair_generator = cctbx.crystal.neighbors_fast_pair_generator( - conn_asu_mappings, - distance_cutoff=radius) - fm = crystal_symmetry.unit_cell().fractionalization_matrix() - om = crystal_symmetry.unit_cell().orthogonalization_matrix() - - pairs = list(pair_generator) - inds = defaultdict(list) - dists = defaultdict(list) - - for pair in pairs: - i, j = pair.i_seq, pair.j_seq - rt_mx_i = conn_asu_mappings.get_rt_mx_i(pair) - rt_mx_j = conn_asu_mappings.get_rt_mx_j(pair) - rt_mx_ji = rt_mx_i.inverse().multiply(rt_mx_j) - - if (only_unit and rt_mx_ji.is_unit_mx()) or (not only_unit): - d = round(math.sqrt(pair.dist_sq), 6) - inds[i].append(j) - dists[i].append(d) - - # add reverse - inds[j].append(i) - dists[j].append(d) - # print(pair.i_seq, pair.j_seq, rt_mx_ji, math.sqrt(pair.dist_sq), de) - - # add self - if include_self: - for key, value in list(inds.items()): - dval = dists[key] - dists[key] = dval+[0.0] - inds[key] = value+[key] - - # sort - for key, value in list(inds.items()): - dval = dists[key] - # sort - sorted_pairs = sorted(set(list(zip(value, dval)))) - value_sorted, dval_sorted = zip(*sorted_pairs) - inds[key] = value_sorted - dists[key] = dval_sorted - - return inds, dists - - -def query_ball_point_flex(tree, tree_xyz, query_xyz, r=None): - """ - Imitate the api of the scipy.spatial query_ball_point function, but using only flex arrays. - Note: This just copies the api, it does not actually use a tree structure, so is much slower. - """ - assert r is not None, "provide radius" - n_atoms, n_probes, _ = query_xyz.focus() - counts = [] - - for atom_i in range(n_atoms): - probe_range = (n_probes * atom_i * 3, n_probes * (atom_i+1) * 3) - atom_probes_xyz = query_xyz.select(flex.size_t_range(*probe_range)) - atom_probes_xyz.reshape(flex.grid(n_probes, 3)) - nbrs = tree[atom_i] - n_nbrs = len(nbrs) - nbrs_xyz = tree_xyz.select(flex.size_t(nbrs)).as_1d().as_double() - nbrs_xyz.reshape(flex.grid(len(nbrs), 3)) - d = cdist_flex(nbrs_xyz, atom_probes_xyz) - sel = d < r - count = [] - for nbr_i in range(n_probes): - nbr_range = (slice(0, n_nbrs), slice(nbr_i, nbr_i+1)) - count_nbr = sel[nbr_range].count(True) - count.append(count_nbr) - - counts.append(count) - - counts = flex_from_list(counts) - return counts diff --git a/cctbx/maptbx/qscore/tst_qscore.py b/cctbx/maptbx/qscore/tst_qscore.py deleted file mode 100644 index 78a5dd3e8e..0000000000 --- a/cctbx/maptbx/qscore/tst_qscore.py +++ /dev/null @@ -1,734 +0,0 @@ -from __future__ import absolute_import, division, print_function -import os -from cctbx.array_family import flex -from iotbx.cli_parser import run_program -import libtbx -from libtbx.utils import null_out -from libtbx.test_utils import approx_equal -from iotbx.data_manager import DataManager -from cctbx.programs import qscore - - - - -expected_results = { - 17:[ - 0.3421921625599796, -0.23059586409823973, -0.5270018776968665, -0.29184116446707, -0.2973812006489643, -0.07600997821758661, -0.33045716863866426, -0.03962350210737266, -0.45794512843877005, -0.35465168874249403, -0.23226261428093095, -0.26433144001016096, -0.41278635270991104, -0.6186540306246111, -0.3770973684892207, -0.1254397336440012, -0.5285370113101394, -0.2223610365635392, -0.24309534172227623, -0.30352501019319705, -0.2752690339591535, -0.4899237828881729, -0.47240975385758843, -0.22025163500887476, -0.5397425995575168, -0.26138971843050957, -0.1846157694745772, -0.45832140303149244, -0.3199925993370375, -0.35148314291468097, -0.30805876853197545, -0.2348747178532036, -0.40538545573721857, -0.35931982891529424, -0.06674246110537026, -0.08865944371905632, -0.46383366221789635, -0.2414768194261802, -0.48285460422290516, -0.347877304598477, -0.29203014359638124, -0.1947260717344384, -0.3991802715787289, -0.15842934668592273, -0.280357208712987, -0.021717502283329426, -0.4062439964555134, -0.3865031622747038, -0.29816347111472813, -0.45863553488308767, -0.3973819008836693, -0.531306284812025, -0.07867336339275807, -0.25396729661621414, -0.5707587513791409, -0.2600181342944659, -0.21478114239293503, -0.18550113903271073, -0.2997586158550855, -0.44065895599883254, -0.5339912733146549, -0.5059403589930165, -0.399563388207582, -0.31353965867608585, -0.40706293922680536, -0.40852998551402225, -0.37818395249405246, -0.34189236056721284, -0.520108250944137, -0.29432165478083183, -0.34554241140959957, -0.3809737558101816, -0.33047852491034596, -0.12000723357018166, -0.28516860178263526, -0.1304167083889345, -0.3702251144186975, -0.1306375003350293, -0.2525755342807049, -0.305846980315952, -0.36304984160901194, -0.26842234134086995, -0.31851634422367264, -0.11418522944583082, -0.6152548226050001, -0.4291161298297077, -0.10135045960919627, -0.43097837719824467, -0.3569904356893862, -0.3807958467081636, -0.048417434326699954, -0.15985263511257164, -0.5031089728058448, -0.33412590730425046, -0.2440388804247266, -0.22092929565192077, -0.34998096643341287, -0.5328979368545581, -0.4266904867364755, -0.26936514659137617, -0.3358724276862323, -0.14700048638497365, -0.3466519839231303, -0.3589201427103675, -0.3032979999041832, -0.46538655038051413, -0.3466157906620784, -0.24854267539811445, -0.4673383636231253, -0.49684501909476203, -0.14656288530085, -0.2060356161083599, -0.37147775553927004, -0.10325116448725478, -0.3298831493141937, -0.06128012250142477, -0.31965867165876083, -0.20571755422175803, -0.24666581378509295, -0.30188192740566117, -0.44059320534165436, -0.12535259204451776, -0.5391480678714957, -0.3146649234896872, -0.2984529944378834, -0.47059387025463373, -0.33688498405806233, -0.45724566460236, --0.0847094806977648, -0.45241765479611734, -0.6024926988514311, -0.39043112440534494, -0.29212336908130637, -0.23521496698092792, -0.3331502225292009, -0.4710973854203711, -0.3930399946681371, -0.22618357696966504, -0.36777652710753406, -0.0687204125428958, -0.21794240968140147, -0.4585816225505588, -0.3189379047384071, -0.39631545999706735, -0.33782657195371435, -0.23053542900402393, -0.44634381476198975, -0.378636545735303, -0.0540847735219687, -0.15763453359404314, -0.3720433946019659, -0.2243999801330215, -0.3919840059559488, -0.24155293236144296, -0.5501860352383139, -0.31499601370777963, -0.3898073419940384, -0.25243082713588016, -0.4264068645720301, -0.06425344489908891, -0.44199112723007916, -0.36807522242257723, -0.29785713399865804, -0.412183321562423, -0.33525906932911176, -0.43397598115931846, --0.010103891048515189, -0.2861456512828132, -0.5159897032252302, -0.3698059640541782, -0.28655590366719214, -0.25513393415337626, -0.2645690349170997, -0.5774885444935143, -0.5722935335150611, -0.12402945863077025, -0.3996273866908372, -0.24242658053677701, -0.32847927480603223, -0.4094780969465886, -0.4156053867514524, -0.17966699996528257, -0.40722902738054584, -0.12689775003918397, -0.371164181132422, -0.3767642054751001, -0.13130550470731653, -0.2581368857773402, -0.4295248268094051, -0.1594754057037172, -0.4822546259691846, -0.26862708250268674, -0.2053994164606709, -0.3314561119080312, -0.3901557321280329, -0.10356267623652139, -0.4893119933324595, -0.06970010217164949, -0.4341832340257733, -0.24300158997333163, -0.40342983455052717, -0.4875152102559497, -0.3611438908961756, -0.43315692556809254, -0.13005314649579647, -0.2789621268926412, -0.5797695620511155, -0.16073844912362031, -0.3189555777730557, -0.25307250722381414, -0.3337698438034294, -0.42692690233657604, -0.39577778624593446, -0.09985873598652467, -0.4519414307186756, -0.2722216910938107, -0.372440061007927, -0.372938237995561, -0.3373188155569413, -0.3077586817882031, -0.3268356422133767, -0.2637935136435236, -0.5124761116179708, -0.45120271947016605, -0.04645127186504295, -0.12464514753785585, -0.4076631108219313, -0.14149061521974549, -0.48019853552270136, -0.3302360313272201, -0.19387184572104918, -0.1276839312082207, -0.16838227799666874, -0.15212252134889084, -0.3938618155397946, -0.007238091652426953, -0.47956784581125006, -0.3628745036188133, -0.15933311523276858, -0.3450436068676078, -0.44003803751547854, -0.4790697870967329, --0.20012992747200145, -0.22038229028354375, -0.4977640896498761, -0.20051572280775803, -0.37450575803439906, -0.24129734365789224, -0.30395715749502616, -0.5091826977961296, -0.43975091833718905, -0.234910477914851, -0.3763909822880909, -0.12134224515408576, -0.1469207447824904, -0.361680966789992, -0.3224493281226169, -0.1786168704708826, -0.3792230579360604, -0.15281162374642446, -0.42911335989536653, -0.31476367357186996, -0.07673757804961866, -0.10689006194487724, -0.4348292707713999, -0.18393677778574968, - ], - 42:[ - 0.04374859159228914, - 0.7014683292236671, - 0.702452905364866, - 0.7021948503391319, - 0.6321784075459557, - 0.49343050019989493, - 0.2387960398985455, - 0.16175122257257904, - 0.5951430522174325, - 0.7298902031066814, - 0.5532188675136824, - 0.7163124107885536, - 0.20712423014887388, - 0.25430831361146483, - 0.6549198534001504, - 0.7354481865202372, - 0.6662233425951913, - 0.7791061242902525, - 0.702971884514788, - 0.7701247147434058, - 0.7604352888270121, - 0.43373125301322574, - 0.592195693113768, - 0.6364893889382377, - 0.5338124993715777, - 0.8629489169692224, - 0.8309699855651322, - 0.8259201064688118, - 0.6416438069201235, - 0.47825154553942534, - 0.4550092060659318, - 0.7141126193559746, - 0.361378093066521, - 0.5170106846191803, - 0.5707500631718254, - 0.2992092767633682, - 0.5245848435807441, - 0.5457993561949297, - 0.43804435104199724, - 0.6965206562313486, - 0.8337428248309631, - 0.5605077031654175, - 0.6540968584763245, - 0.5637569078486285, - 0.5425493265063142, - 0.7905467036720909, - 0.8127777974919012, - 0.16915735889528427, - 0.8851526077212654, - 0.7229453458130224, - 0.6297422798191332, - 0.5501958845022322, - 0.36465666366132, - 0.31652279968342384, - 0.3922520165718135, - 0.644278729536953, - 0.5976556071675406, - 0.4209522494216284, - 0.8009479990116065, - 0.6466622101616207, - 0.5943185266914189, - 0.6137118595285456, - 0.5007963438613854, - 0.8392920445753075, - 0.720763302874267, - 0.8557279503911867, - 0.666713487421232, - 0.8063221960473734, - 0.8505047278069652, - 0.8497427761241569, - 0.803346479118527, - 0.8499754939112326, - 0.31486843957067545, - 0.5200046832164775, - 0.37186717909606204, - 0.6257089207620644, - 0.5829209564081711, - 0.4418711637191809, - 0.8382691191598867, - 0.3985977869183781, - 0.6716185017722498, - 0.4282676780478786, - 0.4769409624386573, - 0.5910446920430065, - 0.8944305471390882, - 0.8928567384381616, - 0.7827931482685355, - 0.6583803668742215, - 0.5991078586481865, - 0.08023769884309902, - 0.6681897301421666, - 0.37209308303777267, - 0.6415923372742239, - 0.4426268000273496, - 0.8688990816217295, - 0.8070367895141034, - 0.8720127649194883, - 0.8203465022935613, - 0.8338592104583938, - 0.6990620518701595, - 0.2149555598988231, - 0.7567926316813701, - 0.8575551185788508, - 0.6933730350449754, - 0.9161219623118465, - 0.732624707051576, - 0.7555994039397524, - 0.5442291068799832, - 0.4627745063207215, - 0.7993664076349526, - 0.5256150479791528, - 0.6760701859645473, - 0.1302511186971115, - 0.7937133262639481, - 0.5220560401977098, - 0.28486982673453465, - 0.8325957396927982, - 0.8513773917569079, - 0.7475582394501862, - 0.8048612849474618, - 0.8214530862558614, - 0.8265812540190871, - 0.7242004339085576, - 0.8846853466892513, - 0.819423901100646, - 0.8313477848815514, - 0.5755446895056169, - 0.2546135793925592, - 0.5574703129705603, - 0.7300843901002169, - 0.5305151067732694, - 0.37122485649150677, - 0.8986747212742561, - 0.8380225816078332, - 0.7614209371152203, - 0.8960858704306193, - 0.7226287919159747, - 0.37728834622953006, - 0.21982393465181072, - 0.5455923669432795, - 0.6875281916354992, - 0.6560338112643748, - 0.7666954073180295, - 0.5964728319202803, - 0.8241982508051366, - 0.7981306054065668, - 0.8648202347360532, - 0.6202773580633816, - 0.40183146013098137, - 0.863659879304468, - 0.7328936642623606, - 0.43331966960473806, - 0.41051665674688637, - 0.3732321485324986, - 0.35704325729788094, - 0.33229209164428214, - 0.6168027054172801, - 0.6693757063241048, - 0.7826022797198974, - 0.5377086752347333, - 0.6730535064545592 - ], - 48: [ - 0.5968541254772408, -0.5888149798397792, -0.315582500635734, -0.687079314914942, --0.10788849213050972, -0.16254718641158727, -0.32455597581368123, -0.5302638476888132, -0.403992922141881, -0.6100358301708605, -0.5771768770057722, -0.2792661235629232, -0.2575949934159178, -0.6043836583958772, -0.7708730081576577, -0.6242504407090721, -0.13591271842406735, -0.18614841272819024, --0.2628077298805197, -0.22025502165116118, -0.7091768516167763, -0.40239405704252396, -0.09949923664253973, --0.054100560826983536, -0.21038809613088602, -0.007996193327384046, -0.6357088374844898, -0.258324242452466, -0.6917422678350181, -0.6857337642645633, -0.13084883287439783, -0.11834600629053386, -0.11256061932813789, --0.32197959142088056, -0.1964277228764244, -0.5263412467056378, -0.47750577744670736, -0.6273411730359443, -0.5644985300402862, --0.04914315380458464, -0.50787821609155, -0.6796080766675747, -0.49186053449280276, -0.7509837193151416, -0.4890882429801768, -0.10679031788648738, -0.40916823804687474, -0.788255742665104, -0.6570069433758265, --0.19528178901870677, --0.39998361609636585, --0.5779325051441814, -0.6451869255926912, -0.5718358631709289, -0.3271255576435047, -0.5473709345665331, -0.6434335071057217, -0.4524362607690744, -0.6898807824065822, -0.7072495487992003, -0.6194096112060017, --0.16830340496094134, --0.4170271322831438, --0.4642359202007596, --0.4178461988711234, -0.6073341350813557, -0.5855734753991133, -0.8564952874666714, -0.6839532113518676, -0.5000213127939919, --0.08326968807387838, -0.3570602870558649, -0.7018663463617603, -0.711969366411144, -0.44508111920540083, -0.5473132202073291, -0.4655274120927994, -0.7078374526458721, -0.17372169440403212, --0.2522585714614016, -0.4648877781222761, -0.7597726350278259, -0.6707870646835342, -0.6573007782788086, -0.5198339575453219, --0.0006526550069698477, -0.6072461380958942, -0.4214311340917669, -0.7173940904184968, -0.35733529642917017, -0.5589328732056613, -0.612336593479406, -0.6507700208799166, -0.25559454694029293, -0.44820830149665475, -0.7185191357007285, -0.5060258719916453, -0.5497397450602441, -0.5622895985717057, -0.5011199096743087, -0.1708925623515588, --0.22131743662693917, -0.24501870130290582, -0.5196556754058135, -0.6172331426177281, -0.7029724816347478, --0.025298909940450143, -0.36765131991932465, -0.2627628940499585, -0.6321682268748771, --0.0500688433871909, -0.5763335415597144, -0.008612564030688004, -0.4472234144081752, -0.5929092758866635, -0.6843005300904107, -0.6651767633174818, -0.26333429778606227, -0.6414457509892533, -0.14438088419608539, --0.21222131040832543, -0.10109932103828434, -0.34494471024693685, -0.5990874755868693, -0.7035932607975525, -0.4857858052204092, -0.4281832690795328, -0.2891807006509428, -0.22222323149421325, -0.203906427947274, -0.04671623310290915, -0.44848477802023157, -0.44684211728874007, -0.5645615585513909, -0.6342758281949152, -0.7489086658409955, -0.589070738843178, -0.41800198826016766, -0.4961210628234994, --0.12984928751527708, -0.39110688153345324, -0.4928519249525499, -0.45581559545936545, -0.21425438653612414, -0.407549256302758, --0.15035212940105575, -0.07036429249131188, -0.6488945090989772, -0.4946267386677905, -0.6382812819654359, -0.23775216404460772, -0.3055450860933104, --0.16833165794875501, --0.19048152061339418, -0.5553859609305851, -0.5406222276872222, -0.6415299499364683, -0.5487751251087766, --0.09145281911606847, -0.28984243303281065, -0.009656212224640586, -0.1494707876965392, -0.11035761336516262, -0.5228293409179153, -0.22983894819798084, -0.4718316173428129, -0.44675298345251324, -0.6110538799666169, -0.40431875240561327, -0.46617059636437935, -0.45627276687090956, --0.117947116698063, -0.4116000349271482, -0.5765557749775085, -0.2544777230831843, -0.4723904664490961, -0.024926912888517457, -0.5621786040077159, -0.6353312649614798, --0.11651261586048801, -0.5633206031940512, -0.38602830801407023, -0.3703387686372386, -0.3144119800821697, -0.6892262947019678, -0.3760829781443364, -0.07418780367285109, --0.19462135663672434, -0.4108928059365392, -0.29895474397513155, -0.6352052484435172, -0.2737730076758392, -0.1744028531150664, -0.10210585799412926, -0.3275183577296833, --0.30303731977501597, --0.24431571115581802, -0.7950029444847503, -0.3796560948926144, -0.5818371159456599, -0.4491548136066217, --0.04931907230118858, -0.37017358917348503, -0.023401235075432583, --0.09782988358799102, -0.63977831753492, -0.4321582398644358, -0.25078377961765774, -0.3469515045045513, -0.40989287767077875, -0.4376901052054188, -0.09475319685420992, -0.05742918560522124, --0.46513487300102824, --0.11594752857285522, -0.12854571044295462, -0.36297737921070805, -0.7694305255605903, -0.6152924317603523, -0.41393102341071225, -0.5477717598392893, --0.2402803578626161, -0.4923987790733689, -0.24427080665726864, -0.5527035011741326, -0.520481852292403, -0.2545693380532749, -0.2943667973934887, -0.13894357009748437, -0.7620957496844697, -0.6147574799490112, -0.7580367523339745, -0.5457950033094567, -0.7178761945864589, -0.6757214005391818, -0.4788983409036063, --0.0303463202660314, -0.6900029820032803, -0.5025196729969039, -0.602699059074302, -0.6107175777294718, -0.6514091338122153, -0.2821497089278383, -0.24515795566596624, -0.548841907952178, -0.5182059748859397, -0.788365623661261, -0.5841782769142585, -0.31236692438409164, -0.45591686200983655, -0.6797742941938839, - ] -} -# make flex arrays -expected_results = {key:flex.double(val) for key,val in list(expected_results.items())} - -def exercise(test_name): - pdb_file = libtbx.env.find_in_repositories( - relative_path=f"phenix_regression/real_space_refine/data/tst_{test_name}.pdb", - test=os.path.isfile) - - map_file = libtbx.env.find_in_repositories( - relative_path=f"phenix_regression/real_space_refine/data/tst_{test_name}.ccp4", - test=os.path.isfile) - - result = run_program( - program_class=qscore.Program, - args = [pdb_file,map_file,"probe_allocation_method=progressive"], - logger=null_out(), - ) - - - try: - expected_result = expected_results[test_name] - assert approx_equal(expected_result, result.qscore,eps=1.e-2) - except: - for val in result.qscore: - print(str(val)+",") - raise - -if (__name__ == "__main__"): - """ - Test random files to verify basic functionality remains unchanged - Data from phenix_regression/real_space_refine/data - """ - for test_name in [17,42,48]: - exercise(test_name) - print("OK") diff --git a/cctbx/maptbx/tst_qscore.py b/cctbx/maptbx/tst_qscore.py new file mode 100644 index 0000000000..f5027348d0 --- /dev/null +++ b/cctbx/maptbx/tst_qscore.py @@ -0,0 +1,320 @@ +from __future__ import absolute_import, division, print_function +import os +from cctbx.array_family import flex +from iotbx.cli_parser import run_program +import libtbx +from libtbx.utils import null_out +from libtbx.test_utils import approx_equal +from cctbx.programs import qscore + + + + +expected_results = { + 17:[ + 0.35535516324938227, +0.24550687752861167, +0.42717508108780494, +0.2630431196992697, +0.2512972739404068, +0.0748338849699907, +0.3951188616344501, +0.017261865581353543, +0.47942130214316503, +0.2927000401754054, +0.08603369430277283, +0.30219565421918, +0.39417849168365854, +0.6189297826154754, +0.36598113428758416, +0.07821030825399476, +0.5275589560551526, +0.19580632885270882, +0.27077417168391377, +0.31471829887209857, +0.3158786931123718, +0.5096481626657788, +0.4609767956764144, +0.28235509392736674, +0.4709590709747482, +0.2939374853294539, +0.10241906482206845, +0.4015066315039059, +0.35209047260985793, +0.35059709887741874, +0.3265106583648, +0.2806311093313803, +0.37458818716858017, +0.385126780724512, +0.06154713873358951, +0.10991564773911004, +0.49364138455921214, +0.2544807372533646, +0.5054205573973468, +0.2637558217581824, +0.3140624661999957, +0.2365647784766615, +0.28262674351648415, +0.1969617894777505, +0.3197038813888359, +0.004434119579554559, +0.49852526974799255, +0.4284389897113832, +0.32266761533489585, +0.5064439221443267, +0.4922792436039985, +0.6303751667061026, +0.1542182251535256, +0.17137072347023904, +0.5974219741230471, +0.3533762354980602, +0.27000081206540955, +0.2007048933666327, +0.30627931992625224, +0.4333678839790156, +0.5452464031846214, +0.39074700178563093, +0.44160485208870487, +0.3012758760420372, +0.3250739032545345, +0.43362607699544053, +0.3625137062692818, +0.3737674696637951, +0.42857066342176636, +0.35808570562399467, +0.22410204647321708, +0.3767186160303378, +0.28651652046017084, +-0.049724839252815733, +0.19356789252833098, +0.09094302118136462, +0.42016933552912894, +0.13060556101358295, +0.22990514778100643, +0.24778269855730797, +0.3321627503379433, +0.2793544145496639, +0.36436645199153783, +0.1990021248328906, +0.5972764932446221, +0.38459252021474777, +0.15376046116368622, +0.4350468866909971, +0.34446835591022873, +0.36878927260006605, +0.05794444507950947, +0.1368028652112549, +0.47365762715495435, +0.40950604509893035, +0.21697233895086965, +0.24302703044362328, +0.3419794880192022, +0.5585194498374837, +0.459308252423094, +0.3230117486740559, +0.3148210060317072, +0.13707459657834334, +0.35686464668359086, +0.3070311263154991, +0.3055250982319954, +0.5000373760197506, +0.2828409443923543, +0.22088517997784513, +0.34473673110006714, +0.39401167930098646, +0.1409604644258536, +0.17904487505641237, +0.41512532606270575, +0.051477839079248605, +0.430233223946139, +0.10701871986502859, +0.3554414516983775, +0.15227178169975683, +0.20902369264131399, +0.27523031292228356, +0.5014761466259059, +0.07273646238705293, +0.5228074093643269, +0.28213307002470817, +0.32834396845308833, +0.4546359850826332, +0.2640898256601553, +0.4042889388009938, +-0.058819305685534916, +0.3320355211739059, +0.5368734032575433, +0.38723919567921916, +0.27920683488494874, +0.21293610438730504, +0.28101278857543577, +0.5005434542705948, +0.3471817144906104, +0.21127407819640626, +0.32067511222833683, +0.11079335636572182, +0.17036780464871323, +0.41955675987187646, +0.3905657146499568, +0.3401149986039323, +0.36035223718270976, +0.23917228790998196, +0.36381317879482006, +0.39077694083716824, +0.03118681161607613, +0.04641661292929102, +0.3724988531432701, +0.2643036127826901, +0.30537188074803256, +0.16202886247768936, +0.43568155630265554, +0.3084634599307411, +0.387489124753754, +0.2666390040428182, +0.46279277413454706, +0.02002279771517451, +0.4827489588800846, +0.445680062618974, +0.14784923408302839, +0.4184692111286882, +0.3933408944964084, +0.4550840595198136, +-0.06497059743774909, +0.20326928453476295, +0.5410683745517895, +0.3934791271999539, +0.24834218260971685, +0.2284335972515956, +0.2749252359472737, +0.5811000263463834, +0.5886279113579868, +0.10014876331174488, +0.3558056816456358, +0.23931433448674996, +0.28193700267688226, +0.30923904707665817, +0.3937787470567507, +0.16583160065281066, +0.41937141588607457, +0.11413599799171258, +0.3671212694643467, +0.31069640919716385, +0.05525220154724908, +0.247288738983681, +0.39689271509298957, +0.20134818886327846, +0.5060624692935539, +0.23340144114502143, +0.1047045872234278, +0.26762911598483546, +0.39263746442670566, +0.12692533917487203, +0.3980087754375635, +0.03756336993253084, +0.46101152409796214, +0.42446162573971874, +0.3643343019533042, +0.5130778316649313, +0.3063184055501381, +0.47635554117162227, +0.2022659217974044, +0.2554080063069391, +0.5501695893864158, +0.2846628653680698, +0.3242176784889862, +0.24811871246412262, +0.3255252546682871, +0.5453376573614725, +0.41301426891418463, +0.07307555071072433, +0.4536301022017574, +0.24638397492302436, +0.19814077792624293, +0.3602238859424958, +0.3170086525644145, +0.2972960450133945, +0.4145260546137287, +0.2661909058919775, +0.49307051785060885, +0.42049092767916485, +0.010562206055517411, +0.05167120683170355, +0.48650651743605644, +0.07522293396734439, +0.4990564081521944, +0.3334757193364281, +0.14185320419595457, +0.12828315708419813, +0.11089188858896354, +0.14452747870340907, +0.3699940929152232, +-0.041235846823679784, +0.513812878496174, +0.3694188603001491, +0.28901185662505796, +0.3803523709807769, +0.3765605158390536, +0.4527272022777316, +-0.08048732044100083, +0.18539904739806815, +0.5232189411542995, +0.3022522764188308, +0.35572393347262615, +0.27116261764046895, +0.3626082715676051, +0.5619703843998924, +0.4944482273684381, +0.16248076555523522, +0.3206340194265775, +0.14751443872046044, +0.09595366681825422, +0.40639326593721653, +0.31519352252160526, +0.2403981456993558, +0.36692833148492576, +0.15957380970815432, +0.49190636939034976, +0.3189327704420888, +0.10792266773848919, +0.04212798503994418, +0.39647128156913286, +0.19546149360621035 + ], + 42:[ + + ] +} +# make flex arrays +expected_results = {key:flex.double(val) for key,val in list(expected_results.items())} + +def exercise(test_name): + pdb_file = libtbx.env.find_in_repositories( + relative_path=f"phenix_regression/real_space_refine/data/tst_{test_name}.pdb", + test=os.path.isfile) + + map_file = libtbx.env.find_in_repositories( + relative_path=f"phenix_regression/real_space_refine/data/tst_{test_name}.ccp4", + test=os.path.isfile) + + result = run_program( + program_class=qscore.Program, + args = [pdb_file,map_file,"probe_allocation_method=progressive shell_radius_num=5 nproc=1 n_probes=8"], + logger=null_out(), + ) + + + try: + expected_result = expected_results[test_name] + assert approx_equal(expected_result, result.qscore,eps=1.e-2) + except: + for val in result.qscore: + print(str(val)+",") + raise + +if (__name__ == "__main__"): + """ + Test random files to verify basic functionality remains unchanged + Data from phenix_regression/real_space_refine/data + """ + for test_name in [17]:#[17,42,48]: + exercise(test_name) + print("OK") diff --git a/cctbx/programs/qscore.py b/cctbx/programs/qscore.py index 8975e57357..8c0345f51d 100644 --- a/cctbx/programs/qscore.py +++ b/cctbx/programs/qscore.py @@ -1,7 +1,7 @@ from __future__ import absolute_import, division, print_function from phenix.program_template import ProgramTemplate from libtbx import group_args -from cctbx.maptbx.qscore.qscore import qscore_np +from cctbx.maptbx.qscore import qscore_np import numpy as np @@ -46,7 +46,7 @@ class Program(ProgramTemplate): .short_caption = Stop testing density at this radius from atom .expert_level = 1 - shell_radius_num = 11 + shell_radius_num = 20 .type = int .help = The number of radial shells .short_caption = The number of radial shells (includes start/stop, so minimum 2) @@ -75,6 +75,8 @@ def run(self): endpoint=True) mmm = self.data_manager.get_map_model_manager() version = 2 if self.params.probe_allocation_method == "precalculate" else 1 # 'progressive' + + # TODO: move param unpacking to the library function result = qscore_np( mmm, selection=self.params.selection, @@ -83,7 +85,11 @@ def run(self): nproc=self.params.nproc, version=version, log = self.logger) + print("Result:") + for val in result: + print(str(val)+",") self.result = group_args(qscore=result) + def get_results(self): return self.result From e4529f2bdef5e28a1da252bd8bb7a1640cc1d8a3 Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 23 Jan 2024 10:35:42 -0800 Subject: [PATCH 051/748] Fix indentation --- cctbx/maptbx/qscore.py | 82 +++++++++++++++++++------------------- cctbx/maptbx/tst_qscore.py | 6 +-- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index 861a11c1e1..60d91a7857 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -1,8 +1,8 @@ """ This code provides methods to calculate the qscore metric for map-model validation, -as developed by Pintile et al. +as developed by Pintile et al. -As with the original implementation, multiple calculation options are provided. +As with the original implementation, multiple calculation options are provided. The fastest (default) is to pass an mmtbx map-model-manager (mmm) to the the function qscore_np, qscore_np(mmm) """ @@ -171,7 +171,7 @@ def radial_shell_worker_v2_np(args): def radial_shell_mp_np( - + model, n_probes=32, radii=np.linspace(0.1, 2, 12), @@ -363,7 +363,7 @@ def qscore_np( # np.save("probe_mask_np.npy",probe_mask) # print("saving qscore: qscore_np.npy") # np.save("qscore_np.npy",q) - + return q @@ -722,46 +722,46 @@ def rowwise_corrcoef(A, B, mask=None): return cc.data def sphere_points_np(ctr, rad, N, mode='SpherePts'): - """ - Points on a sphere given centers, radius, number N + """ + Points on a sphere given centers, radius, number N - TODO: Mode is confusing, it is not clear why there is a difference. - mode='SpherePts' an attempt to literally copy the SpherePts function from mapq - mode='original' a version that gives the same results as the QscorePt3 function from mapq - """ - h = -1.0 + (2.0 * np.arange(N) / float(N-1)) - phis = np.arccos(h) - - if mode == 'original': - thetas = np.zeros(N) - a = (3.6 / np.sqrt(N * (1.0 - h[1:-1]**2))) - thetas[1:-1] = a - thetas = np.cumsum(thetas) - elif mode == 'SpherePts': - thetas = np.zeros(N) - for k in range(1, N): - if k == 1 or k == N - 1: - thetas[k] = 0 - else: - thetas[k] = (thetas[k-1] + 3.6 / np.sqrt(N * (1 - h[k]**2))) % (2 * np.pi) - thetas = thetas.cumsum() - - x = np.sin(phis) * np.cos(thetas) - y = np.sin(phis) * np.sin(thetas) - z = np.cos(phis) - - points = rad * np.stack([x, y, z], axis=-1) - - # Adjusting for multiple centers - if ctr.ndim == 1: - # Single center case - points = points + ctr - else: - # Multiple centers case - points = points.reshape(-1, 1, 3) + ctr.reshape(1, -1, 3) + TODO: Mode is confusing, it is not clear why there is a difference. + mode='SpherePts' an attempt to literally copy the SpherePts function from mapq + mode='original' a version that gives the same results as the QscorePt3 function from mapq + """ + h = -1.0 + (2.0 * np.arange(N) / float(N-1)) + phis = np.arccos(h) + + if mode == 'original': + thetas = np.zeros(N) + a = (3.6 / np.sqrt(N * (1.0 - h[1:-1]**2))) + thetas[1:-1] = a + thetas = np.cumsum(thetas) + elif mode == 'SpherePts': + thetas = np.zeros(N)ß + for k in range(1, N): + if k == 1 or k == N - 1: + thetas[k] = 0 + else: + thetas[k] = (thetas[k-1] + 3.6 / np.sqrt(N * (1 - h[k]**2))) % (2 * np.pi) + thetas = thetas.cumsum() + + x = np.sin(phis) * np.cos(thetas) + y = np.sin(phis) * np.sin(thetas) + z = np.cos(phis) + + points = rad * np.stack([x, y, z], axis=-1) + + # Adjusting for multiple centers + if ctr.ndim == 1: + # Single center case + points = points + ctr + else: + # Multiple centers case + points = points.reshape(-1, 1, 3) + ctr.reshape(1, -1, 3) - return points + return points def cdist_flex(A, B): diff --git a/cctbx/maptbx/tst_qscore.py b/cctbx/maptbx/tst_qscore.py index f5027348d0..a2ba507a58 100644 --- a/cctbx/maptbx/tst_qscore.py +++ b/cctbx/maptbx/tst_qscore.py @@ -280,7 +280,7 @@ 0.19546149360621035 ], 42:[ - + ] } # make flex arrays @@ -301,11 +301,11 @@ def exercise(test_name): logger=null_out(), ) - + try: expected_result = expected_results[test_name] assert approx_equal(expected_result, result.qscore,eps=1.e-2) - except: + except Exception: for val in result.qscore: print(str(val)+",") raise From d2e6656424e0a1772a20e6819e84fdd8b3275c01 Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 23 Jan 2024 10:55:25 -0800 Subject: [PATCH 052/748] typo --- cctbx/maptbx/qscore.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index 60d91a7857..ea7e83c580 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -738,7 +738,7 @@ def sphere_points_np(ctr, rad, N, mode='SpherePts'): thetas[1:-1] = a thetas = np.cumsum(thetas) elif mode == 'SpherePts': - thetas = np.zeros(N)ß + thetas = np.zeros(N) for k in range(1, N): if k == 1 or k == N - 1: thetas[k] = 0 @@ -760,7 +760,6 @@ def sphere_points_np(ctr, rad, N, mode='SpherePts'): # Multiple centers case points = points.reshape(-1, 1, 3) + ctr.reshape(1, -1, 3) - return points From fcd97c7bcdec310bd2ec6eb4becf3da49768ed2b Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 23 Jan 2024 11:35:26 -0800 Subject: [PATCH 053/748] Update syntax exceptions file list --- .azure-pipelines/py2_syntax_exceptions.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.azure-pipelines/py2_syntax_exceptions.txt b/.azure-pipelines/py2_syntax_exceptions.txt index 0dbb2d8f1d..fe6be8c43c 100644 --- a/.azure-pipelines/py2_syntax_exceptions.txt +++ b/.azure-pipelines/py2_syntax_exceptions.txt @@ -13,6 +13,5 @@ xfel/ui/db/job.py xfel/command_line/cxi_mpi_submit.py xfel/command_line/fee_calibration.py xfel/util/drift.py -cctbx/maptbx/qscore/flex_utils.py -cctbx/maptbx/qscore/qscore_utils.py -cctbx/maptbx/qscore/tst_qscore.py +cctbx/maptbx/qscore.py +cctbx/maptbx/tst_qscore.py From 9f865f8de9d3fb3691d55334392115dac23d93a1 Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 23 Jan 2024 11:38:12 -0800 Subject: [PATCH 054/748] Remove whitespace --- cctbx/maptbx/qscore.py | 1532 ++++++++++++++++++------------------ cctbx/maptbx/tst_qscore.py | 597 +++++++------- 2 files changed, 1066 insertions(+), 1063 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index ea7e83c580..27c9c22067 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -35,139 +35,138 @@ # from .flex_utils import optimized_nd_to_1d_indices, nd_to_1d_indices, flex_std try: - from tqdm import tqdm + from tqdm import tqdm except ImportError: - from .qscore_utils import DummyTQDM as tqdm - + from .qscore_utils import DummyTQDM as tqdm def radial_shell_worker_v1_np(args): - """ - Calulate qscore for a single radial shell using version 1 (serial probe allocation) and numpy - """ - ( - i, - atoms_xyz, - n_probes, - radius_shell, - tree, - rtol, - selection, - n_probes_target, - ) = args - - # - # manage selection input - if selection is None: - selection = np.arange(len(atoms_xyz)) - else: - assert selection.dtype == bool - # do selection - atoms_xyz_sel = atoms_xyz[selection] - # print("sel_shape",atoms_xyz_sel.shape) - n_atoms = atoms_xyz_sel.shape[0] - - if radius_shell == 0: - radius_shell = 1e-9 # zero causes crash - numPts = n_probes_target - RAD = radius_shell - outRAD = rtol - all_pts = [] # list of probe arrays for each atom - probe_xyz_r = np.full((n_atoms, n_probes_target, 3), -1.0) - # print(atoms_xyz_sel) - # print("n_atoms",n_atoms) - for atom_i in range(n_atoms): - coord = atoms_xyz_sel[atom_i] - # print("atom_i",atom_i) - # print("coord:",coord) - pts = [] - - # try to get at least [numPts] points at [RAD] distance - # from the atom, that are not closer to other atoms - for i in range(0, 50): - # if we find the necessary number of probes in the first iteration, then i will never go to 1 - # points on a sphere at radius RAD... - n_pts_to_grab = ( - numPts + i * 2 - ) # progressively more points are grabbed with each failed iter - # print("n_to_grab:",n_pts_to_grab) - - outPts = sphere_points_np( - coord[None, :], RAD, n_pts_to_grab - ) # get the points - outPts = outPts.reshape(-1, 3) - at_pts, at_pts_i = [None] * len(outPts), 0 - # print("probe candidates") - - for pt_i, pt in enumerate( - outPts - ): # identify which ones to keep, progressively grow pts list - # print(f"\t{pt[0]},{pt[1]},{pt[2]}") - # query kdtree to find probe-atom interactions - counts = tree.query_ball_point( - pt[None, :], RAD * outRAD, return_length=True - ) - - # each value in counts is the number of atoms within radius+tol of each probe - count = counts.flatten()[0] - ptsNear = count - - if ptsNear == 0: - at_pts[at_pts_i] = pt - at_pts_i += 1 - # if at_pts_i >= numPts: - # break - - if ( - at_pts_i >= numPts - ): # if we have enough points, take all the "good" points from this iter - pts.extend(at_pts[0:at_pts_i]) - break - # assert len(pts)>0, "Zero probes were found " - pts = np.array(pts) # should be shape (n_probes,3) - all_pts.append(pts) - - # prepare output - n_atoms = len(atoms_xyz) - for i, r in enumerate(all_pts): - if r.ndim == 2 and len(r) > 0: - probe_xyz_r[i, :n_probes, :] = r[:n_probes_target, :] - - keep_sel = probe_xyz_r != -1.0 - keep_sel = np.mean(keep_sel, axis=-1, keepdims=True) - keep_sel = np.squeeze(keep_sel, axis=-1) - - return probe_xyz_r, keep_sel.astype(bool) + """ + Calulate qscore for a single radial shell using version 1 (serial probe allocation) and numpy + """ + ( + i, + atoms_xyz, + n_probes, + radius_shell, + tree, + rtol, + selection, + n_probes_target, + ) = args + + # + # manage selection input + if selection is None: + selection = np.arange(len(atoms_xyz)) + else: + assert selection.dtype == bool + # do selection + atoms_xyz_sel = atoms_xyz[selection] + # print("sel_shape",atoms_xyz_sel.shape) + n_atoms = atoms_xyz_sel.shape[0] + + if radius_shell == 0: + radius_shell = 1e-9 # zero causes crash + numPts = n_probes_target + RAD = radius_shell + outRAD = rtol + all_pts = [] # list of probe arrays for each atom + probe_xyz_r = np.full((n_atoms, n_probes_target, 3), -1.0) + # print(atoms_xyz_sel) + # print("n_atoms",n_atoms) + for atom_i in range(n_atoms): + coord = atoms_xyz_sel[atom_i] + # print("atom_i",atom_i) + # print("coord:",coord) + pts = [] + + # try to get at least [numPts] points at [RAD] distance + # from the atom, that are not closer to other atoms + for i in range(0, 50): + # if we find the necessary number of probes in the first iteration, then i will never go to 1 + # points on a sphere at radius RAD... + n_pts_to_grab = ( + numPts + i * 2 + ) # progressively more points are grabbed with each failed iter + # print("n_to_grab:",n_pts_to_grab) + + outPts = sphere_points_np( + coord[None, :], RAD, n_pts_to_grab + ) # get the points + outPts = outPts.reshape(-1, 3) + at_pts, at_pts_i = [None] * len(outPts), 0 + # print("probe candidates") + + for pt_i, pt in enumerate( + outPts + ): # identify which ones to keep, progressively grow pts list + # print(f"\t{pt[0]},{pt[1]},{pt[2]}") + # query kdtree to find probe-atom interactions + counts = tree.query_ball_point( + pt[None, :], RAD * outRAD, return_length=True + ) + + # each value in counts is the number of atoms within radius+tol of each probe + count = counts.flatten()[0] + ptsNear = count + + if ptsNear == 0: + at_pts[at_pts_i] = pt + at_pts_i += 1 + # if at_pts_i >= numPts: + # break + + if ( + at_pts_i >= numPts + ): # if we have enough points, take all the "good" points from this iter + pts.extend(at_pts[0:at_pts_i]) + break + # assert len(pts)>0, "Zero probes were found " + pts = np.array(pts) # should be shape (n_probes,3) + all_pts.append(pts) + + # prepare output + n_atoms = len(atoms_xyz) + for i, r in enumerate(all_pts): + if r.ndim == 2 and len(r) > 0: + probe_xyz_r[i, :n_probes, :] = r[:n_probes_target, :] + + keep_sel = probe_xyz_r != -1.0 + keep_sel = np.mean(keep_sel, axis=-1, keepdims=True) + keep_sel = np.squeeze(keep_sel, axis=-1) + + return probe_xyz_r, keep_sel.astype(bool) def radial_shell_worker_v2_np(args): - """ - Calulate qscore for a single radial shell using version 2 (parallel probe allocation) and numpy - """ - # unpack args - i, atoms_xyz, n_probes, radius_shell, tree, rtol, selection = args + """ + Calulate qscore for a single radial shell using version 2 (parallel probe allocation) and numpy + """ + # unpack args + i, atoms_xyz, n_probes, radius_shell, tree, rtol, selection = args - # manage selection input - if selection is None: - selection = np.arange(len(atoms_xyz)) - else: - assert selection.dtype == bool + # manage selection input + if selection is None: + selection = np.arange(len(atoms_xyz)) + else: + assert selection.dtype == bool - # do selection - atoms_xyz_sel = atoms_xyz[selection] - n_atoms = atoms_xyz_sel.shape[0] + # do selection + atoms_xyz_sel = atoms_xyz[selection] + n_atoms = atoms_xyz_sel.shape[0] - # get probe coordinates - probe_xyz = sphere_points_np(atoms_xyz_sel, radius_shell, n_probes) + # get probe coordinates + probe_xyz = sphere_points_np(atoms_xyz_sel, radius_shell, n_probes) - counts = tree.query_ball_point( - probe_xyz, radius_shell * rtol, return_length=True - ) # atom counts for each probe, for probes in shape (n_atoms,n_probes) - probe_mask = ( - counts == 0 - ) # keep probes with 0 nearby atoms. The rtol ensures self is not counted + counts = tree.query_ball_point( + probe_xyz, radius_shell * rtol, return_length=True + ) # atom counts for each probe, for probes in shape (n_atoms,n_probes) + probe_mask = ( + counts == 0 + ) # keep probes with 0 nearby atoms. The rtol ensures self is not counted - return probe_xyz, probe_mask + return probe_xyz, probe_mask def radial_shell_mp_np( @@ -180,65 +179,66 @@ def radial_shell_mp_np( selection=None, version=2, log=sys.stdout, - ): - """ - Generate probes for a model file using numpy - """ - assert version in [1, 2], "Version must be 1 or 2" - - atoms_xyz = model.get_sites_cart().as_numpy_array() - tree = KDTree(atoms_xyz) - - if version == 1: - worker_func = radial_shell_worker_v1_np - n_probes_target = n_probes - # Create argument tuples for each chunk - args = [ - ( - i, - atoms_xyz, - n_probes, - radius_shell, - tree, - rtol, - selection, - n_probes_target, - ) - for i, radius_shell in enumerate(radii) - ] - else: - worker_func = radial_shell_worker_v2_np - # Create argument tuples for each chunk - args = [ - (i, atoms_xyz, n_probes, radius_shell, tree, rtol, selection) - for i, radius_shell in enumerate(radii) - ] +): + """ + Generate probes for a model file using numpy + """ + assert version in [1, 2], "Version must be 1 or 2" + + atoms_xyz = model.get_sites_cart().as_numpy_array() + tree = KDTree(atoms_xyz) + + if version == 1: + worker_func = radial_shell_worker_v1_np + n_probes_target = n_probes + # Create argument tuples for each chunk + args = [ + ( + i, + atoms_xyz, + n_probes, + radius_shell, + tree, + rtol, + selection, + n_probes_target, + ) + for i, radius_shell in enumerate(radii) + ] + else: + worker_func = radial_shell_worker_v2_np + # Create argument tuples for each chunk + args = [ + (i, atoms_xyz, n_probes, radius_shell, tree, rtol, selection) + for i, radius_shell in enumerate(radii) + ] - # Create a pool of worker processes - if num_processes > 1: - with Pool(num_processes) as p: - # Use the pool to run the trilinear_interpolation_worker function in parallel - results = list( - tqdm(p.imap(worker_func, args), total=len(args), file=log) - ) - else: - results = [] - for arg in tqdm(args, file=log): - # for arg in args: - result = worker_func(arg) - results.append(result) + # Create a pool of worker processes + if num_processes > 1: + with Pool(num_processes) as p: + # Use the pool to run the trilinear_interpolation_worker function in parallel + results = list( + tqdm(p.imap(worker_func, args), total=len(args), file=log) + ) + else: + results = [] + for arg in tqdm(args, file=log): + # for arg in args: + result = worker_func(arg) + results.append(result) + + probe_xyz_all = [result[0] for result in results] + probe_mask_all = [result[1] for result in results] - probe_xyz_all = [result[0] for result in results] - probe_mask_all = [result[1] for result in results] + # debug + # return probe_xyz_all, probe_mask_all - # debug - # return probe_xyz_all, probe_mask_all + # stack numpy + probe_xyz = np.stack(probe_xyz_all) + probe_mask = np.stack(probe_mask_all) - # stack numpy - probe_xyz = np.stack(probe_xyz_all) - probe_mask = np.stack(probe_mask_all) + return probe_xyz, probe_mask - return probe_xyz, probe_mask def ndarray_to_nested_list(arr): """ @@ -251,6 +251,8 @@ def ndarray_to_nested_list(arr): return [ndarray_to_nested_list(sub_arr) for sub_arr in arr] # Example usage + + def qscore_np( mmm, selection=None, @@ -274,97 +276,96 @@ def qscore_np( version=2, nproc=cpu_count(), log=sys.stdout, - ): - """ - Calculate the qscore metric per-atom from an mmtbx map-model-manager, using numpy - """ - model = mmm.model() - mm = mmm.map_manager() - volume = mm.map_data().as_numpy_array() - radii = shells - voxel_size = mm.pixel_sizes() - - probe_xyz, probe_mask = radial_shell_mp_np( - model, - n_probes=n_probes, - num_processes=nproc, - selection=selection, - version=version, - radii=radii, - log=log, - ) - - # after the probe generation, versions 1 and 2 are the same +): + """ + Calculate the qscore metric per-atom from an mmtbx map-model-manager, using numpy + """ + model = mmm.model() + mm = mmm.map_manager() + volume = mm.map_data().as_numpy_array() + radii = shells + voxel_size = mm.pixel_sizes() + + probe_xyz, probe_mask = radial_shell_mp_np( + model, + n_probes=n_probes, + num_processes=nproc, + selection=selection, + version=version, + radii=radii, + log=log, + ) - # infer params from shape - n_shells, n_atoms, n_probes, _ = probe_xyz.shape + # after the probe generation, versions 1 and 2 are the same - # flatten - probe_xyz_flat = probe_xyz.reshape((n_atoms * n_shells * n_probes, 3)) - probe_mask_flat = probe_mask.reshape(-1) # (n_shells*n_atoms*n_probes,) + # infer params from shape + n_shells, n_atoms, n_probes, _ = probe_xyz.shape - # select mask=True probes - masked_probe_xyz_flat = probe_xyz_flat[probe_mask_flat] + # flatten + probe_xyz_flat = probe_xyz.reshape((n_atoms * n_shells * n_probes, 3)) + probe_mask_flat = probe_mask.reshape(-1) # (n_shells*n_atoms*n_probes,) - # interpolate - masked_density = trilinear_interpolation( - volume, masked_probe_xyz_flat, voxel_size=voxel_size - ) + # select mask=True probes + masked_probe_xyz_flat = probe_xyz_flat[probe_mask_flat] - # reshape interpolated values to (n_shells,n_atoms, n_probes) + # interpolate + masked_density = trilinear_interpolation( + volume, masked_probe_xyz_flat, voxel_size=voxel_size + ) - d_vals = np.zeros((n_shells, n_atoms, n_probes)) - d_vals[probe_mask] = masked_density + # reshape interpolated values to (n_shells,n_atoms, n_probes) - # reshape to (M,N*L) for rowwise correlation + d_vals = np.zeros((n_shells, n_atoms, n_probes)) + d_vals[probe_mask] = masked_density - d_vals_2d = d_vals.transpose(1, 0, 2).reshape(d_vals.shape[1], -1) + # reshape to (M,N*L) for rowwise correlation - # create the reference data + d_vals_2d = d_vals.transpose(1, 0, 2).reshape(d_vals.shape[1], -1) - M = volume - maxD = min(M.mean() + M.std() * 10, M.max()) - minD = max(M.mean() - M.std() * 1, M.min()) - A = maxD - minD - B = minD - u = 0 - sigma = 0.6 - x = np.array(radii) - y = A * np.exp(-0.5 * ((x - u) / sigma) ** 2) + B + # create the reference data - # Stack and reshape data for correlation calc + M = volume + maxD = min(M.mean() + M.std() * 10, M.max()) + minD = max(M.mean() - M.std() * 1, M.min()) + A = maxD - minD + B = minD + u = 0 + sigma = 0.6 + x = np.array(radii) + y = A * np.exp(-0.5 * ((x - u) / sigma) ** 2) + B - # stack the reference to shape (n_shells,n_atoms,n_probes) - g_vals = np.repeat(y[:, None], n_probes, axis=1) - g_vals = np.expand_dims(g_vals, 1) - g_vals = np.tile(g_vals, (n_atoms, 1)) + # Stack and reshape data for correlation calc - # reshape - g_vals_2d = g_vals.transpose(1, 0, 2).reshape(g_vals.shape[1], -1) - d_vals_2d = d_vals.transpose(1, 0, 2).reshape(d_vals.shape[1], -1) - mask_2d = probe_mask.transpose(1, 0, 2).reshape(probe_mask.shape[1], -1) + # stack the reference to shape (n_shells,n_atoms,n_probes) + g_vals = np.repeat(y[:, None], n_probes, axis=1) + g_vals = np.expand_dims(g_vals, 1) + g_vals = np.tile(g_vals, (n_atoms, 1)) - # # CALCULATE Q + # reshape + g_vals_2d = g_vals.transpose(1, 0, 2).reshape(g_vals.shape[1], -1) + d_vals_2d = d_vals.transpose(1, 0, 2).reshape(d_vals.shape[1], -1) + mask_2d = probe_mask.transpose(1, 0, 2).reshape(probe_mask.shape[1], -1) - # # numpy - q = rowwise_corrcoef(g_vals_2d, d_vals_2d, mask=mask_2d) + # # CALCULATE Q + # # numpy + q = rowwise_corrcoef(g_vals_2d, d_vals_2d, mask=mask_2d) - # # Log - # import os + # # Log + # import os - # print("FINISHING...") - # print(os.getcwd()) - # print("saving atoms xyz: atom_xyz_np.npy") - # np.save("atoms_xyz_np.npy",model.get_sites_cart().as_numpy_array()) - # print("saving probe xyz: probe_xyz_np.npy") - # np.save("probe_xyz_np.npy",probe_xyz) - # print("saving probe mask: probe_mask_np.npy") - # np.save("probe_mask_np.npy",probe_mask) - # print("saving qscore: qscore_np.npy") - # np.save("qscore_np.npy",q) + # print("FINISHING...") + # print(os.getcwd()) + # print("saving atoms xyz: atom_xyz_np.npy") + # np.save("atoms_xyz_np.npy",model.get_sites_cart().as_numpy_array()) + # print("saving probe xyz: probe_xyz_np.npy") + # np.save("probe_xyz_np.npy",probe_xyz) + # print("saving probe mask: probe_mask_np.npy") + # np.save("probe_mask_np.npy",probe_mask) + # print("saving qscore: qscore_np.npy") + # np.save("qscore_np.npy",q) - return q + return q ############################################################################## @@ -373,31 +374,31 @@ def qscore_np( def radial_shell_worker_v2_flex(args): - """ - Calulate qscore for a single radial shell using version 2 (parallel probe allocation) and flex only - """ - # unpack args - i, atoms_xyz, n_probes, radius_shell, rtol, tree, selection = args + """ + Calulate qscore for a single radial shell using version 2 (parallel probe allocation) and flex only + """ + # unpack args + i, atoms_xyz, n_probes, radius_shell, rtol, tree, selection = args - # manage selection input - if selection is None: - selection = flex.size_t_range(len(atoms_xyz)) - else: - assert isinstance(selection, flex_bool) + # manage selection input + if selection is None: + selection = flex.size_t_range(len(atoms_xyz)) + else: + assert isinstance(selection, flex_bool) - # do selection - n_atoms = selection.count(True) - atoms_xyz_sel = atoms_xyz.select(selection) + # do selection + n_atoms = selection.count(True) + atoms_xyz_sel = atoms_xyz.select(selection) - # get probe coordinates - probe_xyz = sphere_points_flex(atoms_xyz_sel, radius_shell, n_probes) + # get probe coordinates + probe_xyz = sphere_points_flex(atoms_xyz_sel, radius_shell, n_probes) - # query to find the number of atoms within the clash range of each probe - counts = query_ball_point_flex( - tree, atoms_xyz, probe_xyz, r=radius_shell * rtol - ) - probe_mask = counts == 0 - return probe_xyz, probe_mask + # query to find the number of atoms within the clash range of each probe + counts = query_ball_point_flex( + tree, atoms_xyz, probe_xyz, r=radius_shell * rtol + ) + probe_mask = counts == 0 + return probe_xyz, probe_mask def radial_shell_v2_mp_flex( @@ -409,74 +410,74 @@ def radial_shell_v2_mp_flex( selection=None, version=2, log=sys.stdout, - ): - """ - Generate probes for a model file using flex only - """ - assert version in [1, 2], "Version must be 1 or 2" - if version == 1: - assert False - else: - worker_func = radial_shell_worker_v2_flex - - # get a "tree", which is just a dictionary of index:local neighbor indices - tree, _ = query_atom_neighbors(model, radius=3.5) - atoms_xyz = model.get_sites_cart() - - # i,atoms_xyz,n_probes,radius_shell,rtol, selection= args - # Create argument tuples for each chunk - - args = [ - (i, atoms_xyz, n_probes, radius_shell, rtol, tree, selection) - for i, radius_shell in enumerate(radii) - ] - - # Create a pool of worker processes - if num_processes > 1: - with Pool(num_processes) as p: - # Use the pool to run the trilinear_interpolation_worker function in parallel - results = list( - tqdm(p.imap(worker_func, args), total=len(args), file=log) - ) - else: - results = [] - for arg in tqdm(args, file=log): - # for arg in args: - result = worker_func(arg) - results.append(result) - - # stack the results from each shell into single arrays - probe_xyz_all = [result[0] for result in results] - probe_mask_all = [result[1] for result in results] - - # # debug - # return probe_xyz_all, probe_mask_all,tree - - n_atoms = probe_xyz_all[0].focus()[0] - n_shells = len(probe_mask_all) - out_shape = (n_shells, n_atoms, n_probes, 3) - out_size = math.prod(out_shape) - shell_size = math.prod(out_shape[1:]) - out_probes = flex.double(out_size, -1.0) - out_mask = flex.bool(n_atoms * n_shells * n_probes, False) - - for i, p in enumerate(probe_xyz_all): - start = i * shell_size - stop = start + shell_size - out_probes = out_probes.set_selected( - flex.size_t_range(start, stop), p.as_1d() - ) - out_probes.reshape(flex.grid(*out_shape)) +): + """ + Generate probes for a model file using flex only + """ + assert version in [1, 2], "Version must be 1 or 2" + if version == 1: + assert False + else: + worker_func = radial_shell_worker_v2_flex - for i, k in enumerate(probe_mask_all): - start = i * (n_atoms * n_probes) - stop = start + (n_atoms * n_probes) - out_mask = out_mask.set_selected( - flex.size_t_range(start, stop), k.as_1d() - ) - out_mask.reshape(flex.grid(n_shells, n_atoms, n_probes)) + # get a "tree", which is just a dictionary of index:local neighbor indices + tree, _ = query_atom_neighbors(model, radius=3.5) + atoms_xyz = model.get_sites_cart() - return out_probes, out_mask + # i,atoms_xyz,n_probes,radius_shell,rtol, selection= args + # Create argument tuples for each chunk + + args = [ + (i, atoms_xyz, n_probes, radius_shell, rtol, tree, selection) + for i, radius_shell in enumerate(radii) + ] + + # Create a pool of worker processes + if num_processes > 1: + with Pool(num_processes) as p: + # Use the pool to run the trilinear_interpolation_worker function in parallel + results = list( + tqdm(p.imap(worker_func, args), total=len(args), file=log) + ) + else: + results = [] + for arg in tqdm(args, file=log): + # for arg in args: + result = worker_func(arg) + results.append(result) + + # stack the results from each shell into single arrays + probe_xyz_all = [result[0] for result in results] + probe_mask_all = [result[1] for result in results] + + # # debug + # return probe_xyz_all, probe_mask_all,tree + + n_atoms = probe_xyz_all[0].focus()[0] + n_shells = len(probe_mask_all) + out_shape = (n_shells, n_atoms, n_probes, 3) + out_size = math.prod(out_shape) + shell_size = math.prod(out_shape[1:]) + out_probes = flex.double(out_size, -1.0) + out_mask = flex.bool(n_atoms * n_shells * n_probes, False) + + for i, p in enumerate(probe_xyz_all): + start = i * shell_size + stop = start + shell_size + out_probes = out_probes.set_selected( + flex.size_t_range(start, stop), p.as_1d() + ) + out_probes.reshape(flex.grid(*out_shape)) + + for i, k in enumerate(probe_mask_all): + start = i * (n_atoms * n_probes) + stop = start + (n_atoms * n_probes) + out_mask = out_mask.set_selected( + flex.size_t_range(start, stop), k.as_1d() + ) + out_mask.reshape(flex.grid(n_shells, n_atoms, n_probes)) + + return out_probes, out_mask def qscore_flex( @@ -499,521 +500,522 @@ def qscore_flex( ], version=2, nproc=cpu_count(), - ): - """ - Calculate the qscore metric per-atom from an mmtbx map-model-manager, using flex only - """ - model = mmm.model() - mm = mmm.map_manager() - radii = shells - volume = mm.map_data() - voxel_size = mm.pixel_sizes() - - probe_xyz, probe_mask = radial_shell_v2_mp_flex( - model, - n_probes=n_probes, - num_processes=nproc, - selection=selection, - version=version, - radii=radii, - ) - - # aliases - probe_xyz_cctbx = probe_xyz - probe_mask_cctbx = probe_mask - - # infer params from shape - n_shells, n_atoms, n_probes, _ = probe_xyz.focus() - - # APPLY MASK BEFORE INTERPOLATION - - probe_mask_cctbx_fullflat = [] - - for val in probe_mask_cctbx: - for _ in range(3): # since A has an additional dimension of size 3 - probe_mask_cctbx_fullflat.append(val) - - mask = flex.bool(probe_mask_cctbx_fullflat) - # indices = flex.int([i for i in range(1, keep_mask_cctbx.size() + 1) for _ in range(3)]) - sel = probe_xyz_cctbx.select(mask) - # sel_indices = indices.select(mask) - masked_probe_xyz_flat_cctbx = flex.vec3_double(sel) - - # INTERPOLATE - - masked_density_cctbx = mm.density_at_sites_cart( - masked_probe_xyz_flat_cctbx - ) - - # reshape interpolated values to (n_shells,n_atoms, n_probes) - - probe_mask_cctbx.reshape(flex.grid(n_shells * n_atoms * n_probes)) - d_vals_cctbx = flex.double(probe_mask_cctbx.size(), 0.0) - d_vals_cctbx = d_vals_cctbx.set_selected( - probe_mask_cctbx, masked_density_cctbx - ) - d_vals_cctbx.reshape(flex.grid(n_shells, n_atoms, n_probes)) - - # reshape to (M,N*L) for rowwise correlation - - def custom_reshape_indices(flex_array): - N, M, L = flex_array.focus() - result = flex.double(flex.grid(M, N * L)) - - for i in range(N): - for j in range(M): - for k in range(L): - # Calculate the original flat index - old_index = i * M * L + j * L + k - # Calculate the new flat index after transpose and reshape - new_index = j * N * L + i * L + k - result[new_index] = flex_array[old_index] - - return result - - d_vals_2d_cctbx = custom_reshape_indices(d_vals_cctbx) - - # create the reference data - M = volume - M_std = flex_std(M) - M_mean = flex.mean(M) - maxD_cctbx = min(M_mean + M_std * 10, flex.max(M)) - minD_cctbx = max(M_mean - M_std * 1, flex.min(M)) - A_cctbx = maxD_cctbx - minD_cctbx - B_cctbx = minD_cctbx - u = 0 - sigma = 0.6 - x = flex.double(radii) - y_cctbx = ( - A_cctbx * flex.exp(-0.5 * ((flex.double(x) - u) / sigma) ** 2) - + B_cctbx - ) - - # Stack and reshape data for correlation calc - - # 1. Repeat y for n_probes (equivalent to np.repeat) - g_vals_cctbx = [[val] * n_probes for val in y_cctbx] - - # 2. Add a new dimension (equivalent to np.expand_dims) - g_vals_expanded = [[item] for item in g_vals_cctbx] - - # 3. Tile for each atom (equivalent to np.tile) - g_vals_tiled = [] - for item in g_vals_expanded: - g_vals_tiled.append(item * n_atoms) - - g_vals_cctbx = flex.double(np.array(g_vals_tiled)) - - # # CALCULATE Q - - d_vals_cctbx = d_vals_cctbx.as_1d() - g_vals_cctbx = g_vals_cctbx.as_1d() - probe_mask_cctbx_double = probe_mask_cctbx.as_1d().as_double() - q_cctbx = [] - for atomi in range(n_atoms): - inds = nd_to_1d_indices( - (None, atomi, None), (n_shells, n_atoms, n_probes) +): + """ + Calculate the qscore metric per-atom from an mmtbx map-model-manager, using flex only + """ + model = mmm.model() + mm = mmm.map_manager() + radii = shells + volume = mm.map_data() + voxel_size = mm.pixel_sizes() + + probe_xyz, probe_mask = radial_shell_v2_mp_flex( + model, + n_probes=n_probes, + num_processes=nproc, + selection=selection, + version=version, + radii=radii, + ) + + # aliases + probe_xyz_cctbx = probe_xyz + probe_mask_cctbx = probe_mask + + # infer params from shape + n_shells, n_atoms, n_probes, _ = probe_xyz.focus() + + # APPLY MASK BEFORE INTERPOLATION + + probe_mask_cctbx_fullflat = [] + + for val in probe_mask_cctbx: + for _ in range(3): # since A has an additional dimension of size 3 + probe_mask_cctbx_fullflat.append(val) + + mask = flex.bool(probe_mask_cctbx_fullflat) + # indices = flex.int([i for i in range(1, keep_mask_cctbx.size() + 1) for _ in range(3)]) + sel = probe_xyz_cctbx.select(mask) + # sel_indices = indices.select(mask) + masked_probe_xyz_flat_cctbx = flex.vec3_double(sel) + + # INTERPOLATE + + masked_density_cctbx = mm.density_at_sites_cart( + masked_probe_xyz_flat_cctbx + ) + + # reshape interpolated values to (n_shells,n_atoms, n_probes) + + probe_mask_cctbx.reshape(flex.grid(n_shells * n_atoms * n_probes)) + d_vals_cctbx = flex.double(probe_mask_cctbx.size(), 0.0) + d_vals_cctbx = d_vals_cctbx.set_selected( + probe_mask_cctbx, masked_density_cctbx + ) + d_vals_cctbx.reshape(flex.grid(n_shells, n_atoms, n_probes)) + + # reshape to (M,N*L) for rowwise correlation + + def custom_reshape_indices(flex_array): + N, M, L = flex_array.focus() + result = flex.double(flex.grid(M, N * L)) + + for i in range(N): + for j in range(M): + for k in range(L): + # Calculate the original flat index + old_index = i * M * L + j * L + k + # Calculate the new flat index after transpose and reshape + new_index = j * N * L + i * L + k + result[new_index] = flex_array[old_index] + + return result + + d_vals_2d_cctbx = custom_reshape_indices(d_vals_cctbx) + + # create the reference data + M = volume + M_std = flex_std(M) + M_mean = flex.mean(M) + maxD_cctbx = min(M_mean + M_std * 10, flex.max(M)) + minD_cctbx = max(M_mean - M_std * 1, flex.min(M)) + A_cctbx = maxD_cctbx - minD_cctbx + B_cctbx = minD_cctbx + u = 0 + sigma = 0.6 + x = flex.double(radii) + y_cctbx = ( + A_cctbx * flex.exp(-0.5 * ((flex.double(x) - u) / sigma) ** 2) + + B_cctbx ) - # inds = optimized_nd_to_1d_indices(atomi,(n_shells,n_atoms,n_probes)) - inds = flex.uint32(inds) - d_row = d_vals_cctbx.select(inds) - g_row = g_vals_cctbx.select(inds) - mask = probe_mask_cctbx.select(inds) - d = d_row.select(mask) - g = g_row.select(mask) - qval = flex.linear_correlation(d, g).coefficient() - q_cctbx.append(qval) + # Stack and reshape data for correlation calc - q = flex.double(q_cctbx) - return q + # 1. Repeat y for n_probes (equivalent to np.repeat) + g_vals_cctbx = [[val] * n_probes for val in y_cctbx] + # 2. Add a new dimension (equivalent to np.expand_dims) + g_vals_expanded = [[item] for item in g_vals_cctbx] + # 3. Tile for each atom (equivalent to np.tile) + g_vals_tiled = [] + for item in g_vals_expanded: + g_vals_tiled.append(item * n_atoms) + g_vals_cctbx = flex.double(np.array(g_vals_tiled)) -### qscore utils + # # CALCULATE Q + d_vals_cctbx = d_vals_cctbx.as_1d() + g_vals_cctbx = g_vals_cctbx.as_1d() + probe_mask_cctbx_double = probe_mask_cctbx.as_1d().as_double() + q_cctbx = [] + for atomi in range(n_atoms): + inds = nd_to_1d_indices( + (None, atomi, None), (n_shells, n_atoms, n_probes) + ) + # inds = optimized_nd_to_1d_indices(atomi,(n_shells,n_atoms,n_probes)) + inds = flex.uint32(inds) + d_row = d_vals_cctbx.select(inds) + g_row = g_vals_cctbx.select(inds) + mask = probe_mask_cctbx.select(inds) + + d = d_row.select(mask) + g = g_row.select(mask) + qval = flex.linear_correlation(d, g).coefficient() + q_cctbx.append(qval) + + q = flex.double(q_cctbx) + return q + + +# qscore utils class DummyTQDM: - """A 'dummy' object that can be used for compatibility if tqdm is not installed""" - def __init__(self, iterable=None, *args, **kwargs): - self.iterable = iterable - self.args = args - self.kwargs = kwargs + """A 'dummy' object that can be used for compatibility if tqdm is not installed""" + + def __init__(self, iterable=None, *args, **kwargs): + self.iterable = iterable + self.args = args + self.kwargs = kwargs - def __iter__(self): - return iter(self.iterable) + def __iter__(self): + return iter(self.iterable) - def __enter__(self): - return self + def __enter__(self): + return self - def __exit__(self, exc_type, exc_value, traceback): - pass + def __exit__(self, exc_type, exc_value, traceback): + pass def trilinear_interpolation(voxel_grid, coords, voxel_size=None, offset=None): - """Numpy trilinear interpolation""" - assert voxel_size is not None, "Provide voxel size as an array or single value" + """Numpy trilinear interpolation""" + assert voxel_size is not None, "Provide voxel size as an array or single value" - # Apply offset if provided - if offset is not None: - coords = coords - offset + # Apply offset if provided + if offset is not None: + coords = coords - offset - # Transform coordinates to voxel grid index space - index_coords = coords / voxel_size + # Transform coordinates to voxel grid index space + index_coords = coords / voxel_size - # Split the index_coords array into three arrays: x, y, and z - x, y, z = index_coords.T + # Split the index_coords array into three arrays: x, y, and z + x, y, z = index_coords.T - # Truncate to integer values - x0, y0, z0 = np.floor([x, y, z]).astype(int) - x1, y1, z1 = np.ceil([x, y, z]).astype(int) + # Truncate to integer values + x0, y0, z0 = np.floor([x, y, z]).astype(int) + x1, y1, z1 = np.ceil([x, y, z]).astype(int) - # Ensure indices are within grid boundaries - x0, y0, z0 = np.clip([x0, y0, z0], 0, voxel_grid.shape[0]-1) - x1, y1, z1 = np.clip([x1, y1, z1], 0, voxel_grid.shape[0]-1) + # Ensure indices are within grid boundaries + x0, y0, z0 = np.clip([x0, y0, z0], 0, voxel_grid.shape[0]-1) + x1, y1, z1 = np.clip([x1, y1, z1], 0, voxel_grid.shape[0]-1) - # Compute weights - xd, yd, zd = [arr - arr.astype(int) for arr in [x, y, z]] + # Compute weights + xd, yd, zd = [arr - arr.astype(int) for arr in [x, y, z]] - # Interpolate along x - c00 = voxel_grid[x0, y0, z0]*(1-xd) + voxel_grid[x1, y0, z0]*xd - c01 = voxel_grid[x0, y0, z1]*(1-xd) + voxel_grid[x1, y0, z1]*xd - c10 = voxel_grid[x0, y1, z0]*(1-xd) + voxel_grid[x1, y1, z0]*xd - c11 = voxel_grid[x0, y1, z1]*(1-xd) + voxel_grid[x1, y1, z1]*xd + # Interpolate along x + c00 = voxel_grid[x0, y0, z0]*(1-xd) + voxel_grid[x1, y0, z0]*xd + c01 = voxel_grid[x0, y0, z1]*(1-xd) + voxel_grid[x1, y0, z1]*xd + c10 = voxel_grid[x0, y1, z0]*(1-xd) + voxel_grid[x1, y1, z0]*xd + c11 = voxel_grid[x0, y1, z1]*(1-xd) + voxel_grid[x1, y1, z1]*xd - # Interpolate along y - c0 = c00*(1-yd) + c10*yd - c1 = c01*(1-yd) + c11*yd + # Interpolate along y + c0 = c00*(1-yd) + c10*yd + c1 = c01*(1-yd) + c11*yd - # Interpolate along z - c = c0*(1-zd) + c1*zd + # Interpolate along z + c = c0*(1-zd) + c1*zd - return c + return c def rowwise_corrcoef(A, B, mask=None): - """Numpy masked array rowwise correlation coefficient""" - assert A.shape == B.shape, f"A and B must have the same shape, got: {A.shape} and {B.shape}" + """Numpy masked array rowwise correlation coefficient""" + assert A.shape == B.shape, f"A and B must have the same shape, got: {A.shape} and {B.shape}" - if mask is not None: - assert mask.shape == A.shape, "mask must have the same shape as A and B" - A = ma.masked_array(A, mask=np.logical_not(mask)) - B = ma.masked_array(B, mask=np.logical_not(mask)) + if mask is not None: + assert mask.shape == A.shape, "mask must have the same shape as A and B" + A = ma.masked_array(A, mask=np.logical_not(mask)) + B = ma.masked_array(B, mask=np.logical_not(mask)) - # Calculate means - A_mean = ma.mean(A, axis=1, keepdims=True) - B_mean = ma.mean(B, axis=1, keepdims=True) + # Calculate means + A_mean = ma.mean(A, axis=1, keepdims=True) + B_mean = ma.mean(B, axis=1, keepdims=True) - # Subtract means - A_centered = A - A_mean - B_centered = B - B_mean + # Subtract means + A_centered = A - A_mean + B_centered = B - B_mean - # Calculate sum of products - sumprod = ma.sum(A_centered * B_centered, axis=1) + # Calculate sum of products + sumprod = ma.sum(A_centered * B_centered, axis=1) - # Calculate square roots of the sum of squares - sqrt_sos_A = ma.sqrt(ma.sum(A_centered**2, axis=1)) - sqrt_sos_B = ma.sqrt(ma.sum(B_centered**2, axis=1)) + # Calculate square roots of the sum of squares + sqrt_sos_A = ma.sqrt(ma.sum(A_centered**2, axis=1)) + sqrt_sos_B = ma.sqrt(ma.sum(B_centered**2, axis=1)) + + # Return correlation coefficients + cc = sumprod / (sqrt_sos_A * sqrt_sos_B) + return cc.data - # Return correlation coefficients - cc = sumprod / (sqrt_sos_A * sqrt_sos_B) - return cc.data def sphere_points_np(ctr, rad, N, mode='SpherePts'): - """ - Points on a sphere given centers, radius, number N - - TODO: Mode is confusing, it is not clear why there is a difference. - mode='SpherePts' an attempt to literally copy the SpherePts function from mapq - mode='original' a version that gives the same results as the QscorePt3 function from mapq - """ - h = -1.0 + (2.0 * np.arange(N) / float(N-1)) - phis = np.arccos(h) - - if mode == 'original': - thetas = np.zeros(N) - a = (3.6 / np.sqrt(N * (1.0 - h[1:-1]**2))) - thetas[1:-1] = a - thetas = np.cumsum(thetas) - elif mode == 'SpherePts': - thetas = np.zeros(N) - for k in range(1, N): - if k == 1 or k == N - 1: - thetas[k] = 0 - else: - thetas[k] = (thetas[k-1] + 3.6 / np.sqrt(N * (1 - h[k]**2))) % (2 * np.pi) - thetas = thetas.cumsum() - - x = np.sin(phis) * np.cos(thetas) - y = np.sin(phis) * np.sin(thetas) - z = np.cos(phis) - - points = rad * np.stack([x, y, z], axis=-1) - - # Adjusting for multiple centers - if ctr.ndim == 1: - # Single center case - points = points + ctr - else: - # Multiple centers case - points = points.reshape(-1, 1, 3) + ctr.reshape(1, -1, 3) - - return points + """ + Points on a sphere given centers, radius, number N + + TODO: Mode is confusing, it is not clear why there is a difference. + mode='SpherePts' an attempt to literally copy the SpherePts function from mapq + mode='original' a version that gives the same results as the QscorePt3 function from mapq + """ + h = -1.0 + (2.0 * np.arange(N) / float(N-1)) + phis = np.arccos(h) + + if mode == 'original': + thetas = np.zeros(N) + a = (3.6 / np.sqrt(N * (1.0 - h[1:-1]**2))) + thetas[1:-1] = a + thetas = np.cumsum(thetas) + elif mode == 'SpherePts': + thetas = np.zeros(N) + for k in range(1, N): + if k == 1 or k == N - 1: + thetas[k] = 0 + else: + thetas[k] = (thetas[k-1] + 3.6 / + np.sqrt(N * (1 - h[k]**2))) % (2 * np.pi) + thetas = thetas.cumsum() + + x = np.sin(phis) * np.cos(thetas) + y = np.sin(phis) * np.sin(thetas) + z = np.cos(phis) + + points = rad * np.stack([x, y, z], axis=-1) + + # Adjusting for multiple centers + if ctr.ndim == 1: + # Single center case + points = points + ctr + else: + # Multiple centers case + points = points.reshape(-1, 1, 3) + ctr.reshape(1, -1, 3) + + return points def cdist_flex(A, B): - """A flex implementation of the cdist function""" + """A flex implementation of the cdist function""" - def indices_2d_flex(dimensions): - N = len(dimensions) - if N != 2: - raise ValueError("Only 2D is supported for this implementation.") + def indices_2d_flex(dimensions): + N = len(dimensions) + if N != 2: + raise ValueError("Only 2D is supported for this implementation.") - # Create the row indices - row_idx = flex.size_t(chain.from_iterable( - [[i] * dimensions[1] for i in range(dimensions[0])])) + # Create the row indices + row_idx = flex.size_t(chain.from_iterable( + [[i] * dimensions[1] for i in range(dimensions[0])])) - # Create the column indices - col_idx = flex.size_t(chain.from_iterable( - [list(range(dimensions[1])) for _ in range(dimensions[0])])) + # Create the column indices + col_idx = flex.size_t(chain.from_iterable( + [list(range(dimensions[1])) for _ in range(dimensions[0])])) - return row_idx, col_idx + return row_idx, col_idx - i_idxs, j_idxs = indices_2d_flex((A.focus()[0], B.focus()[0])) + i_idxs, j_idxs = indices_2d_flex((A.focus()[0], B.focus()[0])) - r = i_idxs - xi = i_idxs*3 - yi = i_idxs*3 + 1 - zi = i_idxs*3 + 2 + r = i_idxs + xi = i_idxs*3 + yi = i_idxs*3 + 1 + zi = i_idxs*3 + 2 - xa = A.select(xi) - ya = A.select(yi) - za = A.select(zi) + xa = A.select(xi) + ya = A.select(yi) + za = A.select(zi) - xj = j_idxs*3 - yj = j_idxs*3 + 1 - zj = j_idxs*3 + 2 + xj = j_idxs*3 + yj = j_idxs*3 + 1 + zj = j_idxs*3 + 2 - xb = B.select(xj) - yb = B.select(yj) - zb = B.select(zj) + xb = B.select(xj) + yb = B.select(yj) + zb = B.select(zj) - d = ((xb - xa)**2 + (yb - ya)**2 + (zb - za)**2)**0.5 - d.reshape(flex.grid((A.focus()[0], B.focus()[0]))) + d = ((xb - xa)**2 + (yb - ya)**2 + (zb - za)**2)**0.5 + d.reshape(flex.grid((A.focus()[0], B.focus()[0]))) - return d + return d def query_atom_neighbors(model, radius=3.5, include_self=True, only_unit=True): - """Perform radial nearest neighbor searches using cctbx tools, for atom coordinates in a model""" - crystal_symmetry = model.crystal_symmetry() - hierarchy = model.get_hierarchy() - sites_cart = hierarchy.atoms().extract_xyz() - sst = crystal_symmetry.special_position_settings().site_symmetry_table( - sites_cart=sites_cart) - conn_asu_mappings = crystal_symmetry.special_position_settings().\ - asu_mappings(buffer_thickness=5) - conn_asu_mappings.process_sites_cart( - original_sites=sites_cart, - site_symmetry_table=sst) - conn_pair_asu_table = cctbx.crystal.pair_asu_table( - asu_mappings=conn_asu_mappings) - conn_pair_asu_table.add_all_pairs(distance_cutoff=radius) - pair_generator = cctbx.crystal.neighbors_fast_pair_generator( - conn_asu_mappings, - distance_cutoff=radius) - fm = crystal_symmetry.unit_cell().fractionalization_matrix() - om = crystal_symmetry.unit_cell().orthogonalization_matrix() - - pairs = list(pair_generator) - inds = defaultdict(list) - dists = defaultdict(list) - - for pair in pairs: - i, j = pair.i_seq, pair.j_seq - rt_mx_i = conn_asu_mappings.get_rt_mx_i(pair) - rt_mx_j = conn_asu_mappings.get_rt_mx_j(pair) - rt_mx_ji = rt_mx_i.inverse().multiply(rt_mx_j) - - if (only_unit and rt_mx_ji.is_unit_mx()) or (not only_unit): - d = round(math.sqrt(pair.dist_sq), 6) - inds[i].append(j) - dists[i].append(d) - - # add reverse - inds[j].append(i) - dists[j].append(d) - # print(pair.i_seq, pair.j_seq, rt_mx_ji, math.sqrt(pair.dist_sq), de) - - # add self - if include_self: - for key, value in list(inds.items()): - dval = dists[key] - dists[key] = dval+[0.0] - inds[key] = value+[key] + """Perform radial nearest neighbor searches using cctbx tools, for atom coordinates in a model""" + crystal_symmetry = model.crystal_symmetry() + hierarchy = model.get_hierarchy() + sites_cart = hierarchy.atoms().extract_xyz() + sst = crystal_symmetry.special_position_settings().site_symmetry_table( + sites_cart=sites_cart) + conn_asu_mappings = crystal_symmetry.special_position_settings().\ + asu_mappings(buffer_thickness=5) + conn_asu_mappings.process_sites_cart( + original_sites=sites_cart, + site_symmetry_table=sst) + conn_pair_asu_table = cctbx.crystal.pair_asu_table( + asu_mappings=conn_asu_mappings) + conn_pair_asu_table.add_all_pairs(distance_cutoff=radius) + pair_generator = cctbx.crystal.neighbors_fast_pair_generator( + conn_asu_mappings, + distance_cutoff=radius) + fm = crystal_symmetry.unit_cell().fractionalization_matrix() + om = crystal_symmetry.unit_cell().orthogonalization_matrix() + + pairs = list(pair_generator) + inds = defaultdict(list) + dists = defaultdict(list) + + for pair in pairs: + i, j = pair.i_seq, pair.j_seq + rt_mx_i = conn_asu_mappings.get_rt_mx_i(pair) + rt_mx_j = conn_asu_mappings.get_rt_mx_j(pair) + rt_mx_ji = rt_mx_i.inverse().multiply(rt_mx_j) + + if (only_unit and rt_mx_ji.is_unit_mx()) or (not only_unit): + d = round(math.sqrt(pair.dist_sq), 6) + inds[i].append(j) + dists[i].append(d) + + # add reverse + inds[j].append(i) + dists[j].append(d) + # print(pair.i_seq, pair.j_seq, rt_mx_ji, math.sqrt(pair.dist_sq), de) + + # add self + if include_self: + for key, value in list(inds.items()): + dval = dists[key] + dists[key] = dval+[0.0] + inds[key] = value+[key] - # sort - for key, value in list(inds.items()): - dval = dists[key] # sort - sorted_pairs = sorted(set(list(zip(value, dval)))) - value_sorted, dval_sorted = zip(*sorted_pairs) - inds[key] = value_sorted - dists[key] = dval_sorted + for key, value in list(inds.items()): + dval = dists[key] + # sort + sorted_pairs = sorted(set(list(zip(value, dval)))) + value_sorted, dval_sorted = zip(*sorted_pairs) + inds[key] = value_sorted + dists[key] = dval_sorted - return inds, dists + return inds, dists def query_ball_point_flex(tree, tree_xyz, query_xyz, r=None): - """ - Imitate the api of the scipy.spatial query_ball_point function, but using only flex arrays. - Note: This just copies the api, it does not actually use a tree structure, so is much slower. - """ - assert r is not None, "provide radius" - n_atoms, n_probes, _ = query_xyz.focus() - counts = [] - - for atom_i in range(n_atoms): - probe_range = (n_probes * atom_i * 3, n_probes * (atom_i+1) * 3) - atom_probes_xyz = query_xyz.select(flex.size_t_range(*probe_range)) - atom_probes_xyz.reshape(flex.grid(n_probes, 3)) - nbrs = tree[atom_i] - n_nbrs = len(nbrs) - nbrs_xyz = tree_xyz.select(flex.size_t(nbrs)).as_1d().as_double() - nbrs_xyz.reshape(flex.grid(len(nbrs), 3)) - d = cdist_flex(nbrs_xyz, atom_probes_xyz) - sel = d < r - count = [] - for nbr_i in range(n_probes): - nbr_range = (slice(0, n_nbrs), slice(nbr_i, nbr_i+1)) - count_nbr = sel[nbr_range].count(True) - count.append(count_nbr) - - counts.append(count) - - counts = flex_from_list(counts) - return counts - - -### flex utils + """ + Imitate the api of the scipy.spatial query_ball_point function, but using only flex arrays. + Note: This just copies the api, it does not actually use a tree structure, so is much slower. + """ + assert r is not None, "provide radius" + n_atoms, n_probes, _ = query_xyz.focus() + counts = [] + + for atom_i in range(n_atoms): + probe_range = (n_probes * atom_i * 3, n_probes * (atom_i+1) * 3) + atom_probes_xyz = query_xyz.select(flex.size_t_range(*probe_range)) + atom_probes_xyz.reshape(flex.grid(n_probes, 3)) + nbrs = tree[atom_i] + n_nbrs = len(nbrs) + nbrs_xyz = tree_xyz.select(flex.size_t(nbrs)).as_1d().as_double() + nbrs_xyz.reshape(flex.grid(len(nbrs), 3)) + d = cdist_flex(nbrs_xyz, atom_probes_xyz) + sel = d < r + count = [] + for nbr_i in range(n_probes): + nbr_range = (slice(0, n_nbrs), slice(nbr_i, nbr_i+1)) + count_nbr = sel[nbr_range].count(True) + count.append(count_nbr) + + counts.append(count) + + counts = flex_from_list(counts) + return counts + + +# flex utils def flex_from_list(lst, signed_int=False): - """Generate a flex array from a list, try to infer type""" - flat_list, shape = flatten_and_shape(lst) - dtype = get_dtype_of_list(flat_list) - type_mapper = {int: flex.size_t, - float: flex.double, - bool: flex.bool} - if signed_int: - type_mapper[int] = flex.int16 - - # make flex array - assert dtype in type_mapper, f"Unrecognized type: {dtype}" - flex_func = type_mapper[dtype] - flex_array = flex_func(flat_list) - if len(shape) > 1: - flex_array.reshape(flex.grid(*shape)) - return flex_array + """Generate a flex array from a list, try to infer type""" + flat_list, shape = flatten_and_shape(lst) + dtype = get_dtype_of_list(flat_list) + type_mapper = {int: flex.size_t, + float: flex.double, + bool: flex.bool} + if signed_int: + type_mapper[int] = flex.int16 + + # make flex array + assert dtype in type_mapper, f"Unrecognized type: {dtype}" + flex_func = type_mapper[dtype] + flex_array = flex_func(flat_list) + if len(shape) > 1: + flex_array.reshape(flex.grid(*shape)) + return flex_array def flatten_and_shape(lst): - """Flatten a nested list and return its shape.""" - def helper(l): - if not isinstance(l, list): - return [l], () - flat = [] - shapes = [] - for item in l: - f, s = helper(item) - flat.extend(f) - shapes.append(s) - if len(set(shapes)) != 1: - raise ValueError("Ragged nested list detected.") - return flat, (len(l),) + shapes[0] - - flattened, shape = helper(lst) - return flattened, shape + """Flatten a nested list and return its shape.""" + def helper(l): + if not isinstance(l, list): + return [l], () + flat = [] + shapes = [] + for item in l: + f, s = helper(item) + flat.extend(f) + shapes.append(s) + if len(set(shapes)) != 1: + raise ValueError("Ragged nested list detected.") + return flat, (len(l),) + shapes[0] + + flattened, shape = helper(lst) + return flattened, shape def get_dtype_of_list(lst): - dtypes = {type(item) for item in lst} + dtypes = {type(item) for item in lst} - if len(dtypes) > 1: - raise ValueError("Multiple data types detected.") - elif len(dtypes) == 0: - raise ValueError("Empty list provided.") - else: - return dtypes.pop() + if len(dtypes) > 1: + raise ValueError("Multiple data types detected.") + elif len(dtypes) == 0: + raise ValueError("Empty list provided.") + else: + return dtypes.pop() def nd_to_1d_indices(indices, shape): - """Generate the 1d indices given nd indices and an array shape""" - # Normalize indices to always use slice objects - normalized_indices = [] - for dim, idx in enumerate(indices): - if idx is None: - normalized_indices.append(slice(0, shape[dim])) - else: - normalized_indices.append(idx) - - # If any index is a slice, recursively call function for each value in slice - for dim, (i, s) in enumerate(zip(normalized_indices, shape)): - if isinstance(i, slice): - result_indices = [] - start, stop, step = i.indices(s) - for j in range(start, stop, step): - new_indices = list(normalized_indices) - new_indices[dim] = j - result_indices.extend(nd_to_1d_indices(new_indices, shape)) - return result_indices - - # If no slices, calculate single 1D index - index = 0 - stride = 1 - for i, dim in reversed(list(zip(normalized_indices, shape))): - index += i * stride - stride *= dim - return [index] + """Generate the 1d indices given nd indices and an array shape""" + # Normalize indices to always use slice objects + normalized_indices = [] + for dim, idx in enumerate(indices): + if idx is None: + normalized_indices.append(slice(0, shape[dim])) + else: + normalized_indices.append(idx) + + # If any index is a slice, recursively call function for each value in slice + for dim, (i, s) in enumerate(zip(normalized_indices, shape)): + if isinstance(i, slice): + result_indices = [] + start, stop, step = i.indices(s) + for j in range(start, stop, step): + new_indices = list(normalized_indices) + new_indices[dim] = j + result_indices.extend(nd_to_1d_indices(new_indices, shape)) + return result_indices + + # If no slices, calculate single 1D index + index = 0 + stride = 1 + for i, dim in reversed(list(zip(normalized_indices, shape))): + index += i * stride + stride *= dim + return [index] + def optimized_nd_to_1d_indices(i, shape): - """Similar to above, but hardcoded to select a single index on dimension 1""" - # For fixed input of (None, i, None), we directly compute based on given structure - result_indices = [] + """Similar to above, but hardcoded to select a single index on dimension 1""" + # For fixed input of (None, i, None), we directly compute based on given structure + result_indices = [] - # Pre-compute for 1st dimension which is always a slice - start1, stop1 = 0, shape[0] + # Pre-compute for 1st dimension which is always a slice + start1, stop1 = 0, shape[0] - # Pre-compute for 3rd dimension which is always a slice - start3, stop3 = 0, shape[2] - stride3 = 1 + # Pre-compute for 3rd dimension which is always a slice + start3, stop3 = 0, shape[2] + stride3 = 1 - # Directly compute for 2nd dimension which is variable - stride2 = shape[2] - index2 = i * stride2 * shape[0] + # Directly compute for 2nd dimension which is variable + stride2 = shape[2] + index2 = i * stride2 * shape[0] - for val1 in range(start1, stop1): - for val3 in range(start3, stop3): - result_indices.append(val1 * stride2 + index2 + val3 * stride3) + for val1 in range(start1, stop1): + for val3 in range(start3, stop3): + result_indices.append(val1 * stride2 + index2 + val3 * stride3) - return result_indices + return result_indices def flex_std(flex_array): - """Standard deviation""" - n = flex_array.size() - if n <= 1: - raise ValueError("Sample size must be greater than 1") + """Standard deviation""" + n = flex_array.size() + if n <= 1: + raise ValueError("Sample size must be greater than 1") - # Compute the mean - mean_value = flex.mean(flex_array) + # Compute the mean + mean_value = flex.mean(flex_array) - # Compute the sum of squared deviations - squared_deviations = (flex_array - mean_value) ** 2 - sum_squared_deviations = flex.sum(squared_deviations) + # Compute the sum of squared deviations + squared_deviations = (flex_array - mean_value) ** 2 + sum_squared_deviations = flex.sum(squared_deviations) - # Compute the standard deviation - std_dev = (sum_squared_deviations / (n - 1)) ** 0.5 - return std_dev + # Compute the standard deviation + std_dev = (sum_squared_deviations / (n - 1)) ** 0.5 + return std_dev diff --git a/cctbx/maptbx/tst_qscore.py b/cctbx/maptbx/tst_qscore.py index a2ba507a58..0f93a8b9f2 100644 --- a/cctbx/maptbx/tst_qscore.py +++ b/cctbx/maptbx/tst_qscore.py @@ -8,313 +8,314 @@ from cctbx.programs import qscore - - expected_results = { - 17:[ - 0.35535516324938227, -0.24550687752861167, -0.42717508108780494, -0.2630431196992697, -0.2512972739404068, -0.0748338849699907, -0.3951188616344501, -0.017261865581353543, -0.47942130214316503, -0.2927000401754054, -0.08603369430277283, -0.30219565421918, -0.39417849168365854, -0.6189297826154754, -0.36598113428758416, -0.07821030825399476, -0.5275589560551526, -0.19580632885270882, -0.27077417168391377, -0.31471829887209857, -0.3158786931123718, -0.5096481626657788, -0.4609767956764144, -0.28235509392736674, -0.4709590709747482, -0.2939374853294539, -0.10241906482206845, -0.4015066315039059, -0.35209047260985793, -0.35059709887741874, -0.3265106583648, -0.2806311093313803, -0.37458818716858017, -0.385126780724512, -0.06154713873358951, -0.10991564773911004, -0.49364138455921214, -0.2544807372533646, -0.5054205573973468, -0.2637558217581824, -0.3140624661999957, -0.2365647784766615, -0.28262674351648415, -0.1969617894777505, -0.3197038813888359, -0.004434119579554559, -0.49852526974799255, -0.4284389897113832, -0.32266761533489585, -0.5064439221443267, -0.4922792436039985, -0.6303751667061026, -0.1542182251535256, -0.17137072347023904, -0.5974219741230471, -0.3533762354980602, -0.27000081206540955, -0.2007048933666327, -0.30627931992625224, -0.4333678839790156, -0.5452464031846214, -0.39074700178563093, -0.44160485208870487, -0.3012758760420372, -0.3250739032545345, -0.43362607699544053, -0.3625137062692818, -0.3737674696637951, -0.42857066342176636, -0.35808570562399467, -0.22410204647321708, -0.3767186160303378, -0.28651652046017084, --0.049724839252815733, -0.19356789252833098, -0.09094302118136462, -0.42016933552912894, -0.13060556101358295, -0.22990514778100643, -0.24778269855730797, -0.3321627503379433, -0.2793544145496639, -0.36436645199153783, -0.1990021248328906, -0.5972764932446221, -0.38459252021474777, -0.15376046116368622, -0.4350468866909971, -0.34446835591022873, -0.36878927260006605, -0.05794444507950947, -0.1368028652112549, -0.47365762715495435, -0.40950604509893035, -0.21697233895086965, -0.24302703044362328, -0.3419794880192022, -0.5585194498374837, -0.459308252423094, -0.3230117486740559, -0.3148210060317072, -0.13707459657834334, -0.35686464668359086, -0.3070311263154991, -0.3055250982319954, -0.5000373760197506, -0.2828409443923543, -0.22088517997784513, -0.34473673110006714, -0.39401167930098646, -0.1409604644258536, -0.17904487505641237, -0.41512532606270575, -0.051477839079248605, -0.430233223946139, -0.10701871986502859, -0.3554414516983775, -0.15227178169975683, -0.20902369264131399, -0.27523031292228356, -0.5014761466259059, -0.07273646238705293, -0.5228074093643269, -0.28213307002470817, -0.32834396845308833, -0.4546359850826332, -0.2640898256601553, -0.4042889388009938, --0.058819305685534916, -0.3320355211739059, -0.5368734032575433, -0.38723919567921916, -0.27920683488494874, -0.21293610438730504, -0.28101278857543577, -0.5005434542705948, -0.3471817144906104, -0.21127407819640626, -0.32067511222833683, -0.11079335636572182, -0.17036780464871323, -0.41955675987187646, -0.3905657146499568, -0.3401149986039323, -0.36035223718270976, -0.23917228790998196, -0.36381317879482006, -0.39077694083716824, -0.03118681161607613, -0.04641661292929102, -0.3724988531432701, -0.2643036127826901, -0.30537188074803256, -0.16202886247768936, -0.43568155630265554, -0.3084634599307411, -0.387489124753754, -0.2666390040428182, -0.46279277413454706, -0.02002279771517451, -0.4827489588800846, -0.445680062618974, -0.14784923408302839, -0.4184692111286882, -0.3933408944964084, -0.4550840595198136, --0.06497059743774909, -0.20326928453476295, -0.5410683745517895, -0.3934791271999539, -0.24834218260971685, -0.2284335972515956, -0.2749252359472737, -0.5811000263463834, -0.5886279113579868, -0.10014876331174488, -0.3558056816456358, -0.23931433448674996, -0.28193700267688226, -0.30923904707665817, -0.3937787470567507, -0.16583160065281066, -0.41937141588607457, -0.11413599799171258, -0.3671212694643467, -0.31069640919716385, -0.05525220154724908, -0.247288738983681, -0.39689271509298957, -0.20134818886327846, -0.5060624692935539, -0.23340144114502143, -0.1047045872234278, -0.26762911598483546, -0.39263746442670566, -0.12692533917487203, -0.3980087754375635, -0.03756336993253084, -0.46101152409796214, -0.42446162573971874, -0.3643343019533042, -0.5130778316649313, -0.3063184055501381, -0.47635554117162227, -0.2022659217974044, -0.2554080063069391, -0.5501695893864158, -0.2846628653680698, -0.3242176784889862, -0.24811871246412262, -0.3255252546682871, -0.5453376573614725, -0.41301426891418463, -0.07307555071072433, -0.4536301022017574, -0.24638397492302436, -0.19814077792624293, -0.3602238859424958, -0.3170086525644145, -0.2972960450133945, -0.4145260546137287, -0.2661909058919775, -0.49307051785060885, -0.42049092767916485, -0.010562206055517411, -0.05167120683170355, -0.48650651743605644, -0.07522293396734439, -0.4990564081521944, -0.3334757193364281, -0.14185320419595457, -0.12828315708419813, -0.11089188858896354, -0.14452747870340907, -0.3699940929152232, --0.041235846823679784, -0.513812878496174, -0.3694188603001491, -0.28901185662505796, -0.3803523709807769, -0.3765605158390536, -0.4527272022777316, --0.08048732044100083, -0.18539904739806815, -0.5232189411542995, -0.3022522764188308, -0.35572393347262615, -0.27116261764046895, -0.3626082715676051, -0.5619703843998924, -0.4944482273684381, -0.16248076555523522, -0.3206340194265775, -0.14751443872046044, -0.09595366681825422, -0.40639326593721653, -0.31519352252160526, -0.2403981456993558, -0.36692833148492576, -0.15957380970815432, -0.49190636939034976, -0.3189327704420888, -0.10792266773848919, -0.04212798503994418, -0.39647128156913286, -0.19546149360621035 - ], - 42:[ + 17: [ + 0.35535516324938227, + 0.24550687752861167, + 0.42717508108780494, + 0.2630431196992697, + 0.2512972739404068, + 0.0748338849699907, + 0.3951188616344501, + 0.017261865581353543, + 0.47942130214316503, + 0.2927000401754054, + 0.08603369430277283, + 0.30219565421918, + 0.39417849168365854, + 0.6189297826154754, + 0.36598113428758416, + 0.07821030825399476, + 0.5275589560551526, + 0.19580632885270882, + 0.27077417168391377, + 0.31471829887209857, + 0.3158786931123718, + 0.5096481626657788, + 0.4609767956764144, + 0.28235509392736674, + 0.4709590709747482, + 0.2939374853294539, + 0.10241906482206845, + 0.4015066315039059, + 0.35209047260985793, + 0.35059709887741874, + 0.3265106583648, + 0.2806311093313803, + 0.37458818716858017, + 0.385126780724512, + 0.06154713873358951, + 0.10991564773911004, + 0.49364138455921214, + 0.2544807372533646, + 0.5054205573973468, + 0.2637558217581824, + 0.3140624661999957, + 0.2365647784766615, + 0.28262674351648415, + 0.1969617894777505, + 0.3197038813888359, + 0.004434119579554559, + 0.49852526974799255, + 0.4284389897113832, + 0.32266761533489585, + 0.5064439221443267, + 0.4922792436039985, + 0.6303751667061026, + 0.1542182251535256, + 0.17137072347023904, + 0.5974219741230471, + 0.3533762354980602, + 0.27000081206540955, + 0.2007048933666327, + 0.30627931992625224, + 0.4333678839790156, + 0.5452464031846214, + 0.39074700178563093, + 0.44160485208870487, + 0.3012758760420372, + 0.3250739032545345, + 0.43362607699544053, + 0.3625137062692818, + 0.3737674696637951, + 0.42857066342176636, + 0.35808570562399467, + 0.22410204647321708, + 0.3767186160303378, + 0.28651652046017084, + -0.049724839252815733, + 0.19356789252833098, + 0.09094302118136462, + 0.42016933552912894, + 0.13060556101358295, + 0.22990514778100643, + 0.24778269855730797, + 0.3321627503379433, + 0.2793544145496639, + 0.36436645199153783, + 0.1990021248328906, + 0.5972764932446221, + 0.38459252021474777, + 0.15376046116368622, + 0.4350468866909971, + 0.34446835591022873, + 0.36878927260006605, + 0.05794444507950947, + 0.1368028652112549, + 0.47365762715495435, + 0.40950604509893035, + 0.21697233895086965, + 0.24302703044362328, + 0.3419794880192022, + 0.5585194498374837, + 0.459308252423094, + 0.3230117486740559, + 0.3148210060317072, + 0.13707459657834334, + 0.35686464668359086, + 0.3070311263154991, + 0.3055250982319954, + 0.5000373760197506, + 0.2828409443923543, + 0.22088517997784513, + 0.34473673110006714, + 0.39401167930098646, + 0.1409604644258536, + 0.17904487505641237, + 0.41512532606270575, + 0.051477839079248605, + 0.430233223946139, + 0.10701871986502859, + 0.3554414516983775, + 0.15227178169975683, + 0.20902369264131399, + 0.27523031292228356, + 0.5014761466259059, + 0.07273646238705293, + 0.5228074093643269, + 0.28213307002470817, + 0.32834396845308833, + 0.4546359850826332, + 0.2640898256601553, + 0.4042889388009938, + -0.058819305685534916, + 0.3320355211739059, + 0.5368734032575433, + 0.38723919567921916, + 0.27920683488494874, + 0.21293610438730504, + 0.28101278857543577, + 0.5005434542705948, + 0.3471817144906104, + 0.21127407819640626, + 0.32067511222833683, + 0.11079335636572182, + 0.17036780464871323, + 0.41955675987187646, + 0.3905657146499568, + 0.3401149986039323, + 0.36035223718270976, + 0.23917228790998196, + 0.36381317879482006, + 0.39077694083716824, + 0.03118681161607613, + 0.04641661292929102, + 0.3724988531432701, + 0.2643036127826901, + 0.30537188074803256, + 0.16202886247768936, + 0.43568155630265554, + 0.3084634599307411, + 0.387489124753754, + 0.2666390040428182, + 0.46279277413454706, + 0.02002279771517451, + 0.4827489588800846, + 0.445680062618974, + 0.14784923408302839, + 0.4184692111286882, + 0.3933408944964084, + 0.4550840595198136, + -0.06497059743774909, + 0.20326928453476295, + 0.5410683745517895, + 0.3934791271999539, + 0.24834218260971685, + 0.2284335972515956, + 0.2749252359472737, + 0.5811000263463834, + 0.5886279113579868, + 0.10014876331174488, + 0.3558056816456358, + 0.23931433448674996, + 0.28193700267688226, + 0.30923904707665817, + 0.3937787470567507, + 0.16583160065281066, + 0.41937141588607457, + 0.11413599799171258, + 0.3671212694643467, + 0.31069640919716385, + 0.05525220154724908, + 0.247288738983681, + 0.39689271509298957, + 0.20134818886327846, + 0.5060624692935539, + 0.23340144114502143, + 0.1047045872234278, + 0.26762911598483546, + 0.39263746442670566, + 0.12692533917487203, + 0.3980087754375635, + 0.03756336993253084, + 0.46101152409796214, + 0.42446162573971874, + 0.3643343019533042, + 0.5130778316649313, + 0.3063184055501381, + 0.47635554117162227, + 0.2022659217974044, + 0.2554080063069391, + 0.5501695893864158, + 0.2846628653680698, + 0.3242176784889862, + 0.24811871246412262, + 0.3255252546682871, + 0.5453376573614725, + 0.41301426891418463, + 0.07307555071072433, + 0.4536301022017574, + 0.24638397492302436, + 0.19814077792624293, + 0.3602238859424958, + 0.3170086525644145, + 0.2972960450133945, + 0.4145260546137287, + 0.2661909058919775, + 0.49307051785060885, + 0.42049092767916485, + 0.010562206055517411, + 0.05167120683170355, + 0.48650651743605644, + 0.07522293396734439, + 0.4990564081521944, + 0.3334757193364281, + 0.14185320419595457, + 0.12828315708419813, + 0.11089188858896354, + 0.14452747870340907, + 0.3699940929152232, + -0.041235846823679784, + 0.513812878496174, + 0.3694188603001491, + 0.28901185662505796, + 0.3803523709807769, + 0.3765605158390536, + 0.4527272022777316, + -0.08048732044100083, + 0.18539904739806815, + 0.5232189411542995, + 0.3022522764188308, + 0.35572393347262615, + 0.27116261764046895, + 0.3626082715676051, + 0.5619703843998924, + 0.4944482273684381, + 0.16248076555523522, + 0.3206340194265775, + 0.14751443872046044, + 0.09595366681825422, + 0.40639326593721653, + 0.31519352252160526, + 0.2403981456993558, + 0.36692833148492576, + 0.15957380970815432, + 0.49190636939034976, + 0.3189327704420888, + 0.10792266773848919, + 0.04212798503994418, + 0.39647128156913286, + 0.19546149360621035 + ], + 42: [ - ] + ] } # make flex arrays -expected_results = {key:flex.double(val) for key,val in list(expected_results.items())} +expected_results = {key: flex.double(val) + for key, val in list(expected_results.items())} + def exercise(test_name): - pdb_file = libtbx.env.find_in_repositories( - relative_path=f"phenix_regression/real_space_refine/data/tst_{test_name}.pdb", - test=os.path.isfile) + pdb_file = libtbx.env.find_in_repositories( + relative_path=f"phenix_regression/real_space_refine/data/tst_{test_name}.pdb", + test=os.path.isfile) - map_file = libtbx.env.find_in_repositories( - relative_path=f"phenix_regression/real_space_refine/data/tst_{test_name}.ccp4", - test=os.path.isfile) + map_file = libtbx.env.find_in_repositories( + relative_path=f"phenix_regression/real_space_refine/data/tst_{test_name}.ccp4", + test=os.path.isfile) - result = run_program( - program_class=qscore.Program, - args = [pdb_file,map_file,"probe_allocation_method=progressive shell_radius_num=5 nproc=1 n_probes=8"], - logger=null_out(), - ) + result = run_program( + program_class=qscore.Program, + args=[pdb_file, map_file, + "probe_allocation_method=progressive shell_radius_num=5 nproc=1 n_probes=8"], + logger=null_out(), + ) + try: + expected_result = expected_results[test_name] + assert approx_equal(expected_result, result.qscore, eps=1.e-2) + except Exception: + for val in result.qscore: + print(str(val)+",") + raise - try: - expected_result = expected_results[test_name] - assert approx_equal(expected_result, result.qscore,eps=1.e-2) - except Exception: - for val in result.qscore: - print(str(val)+",") - raise if (__name__ == "__main__"): - """ - Test random files to verify basic functionality remains unchanged - Data from phenix_regression/real_space_refine/data - """ - for test_name in [17]:#[17,42,48]: - exercise(test_name) - print("OK") + """ + Test random files to verify basic functionality remains unchanged + Data from phenix_regression/real_space_refine/data + """ + for test_name in [17]: # [17,42,48]: + exercise(test_name) + print("OK") From 60c6515008d905a1d8ce7a7ed649be98fb1f2482 Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 23 Jan 2024 12:58:38 -0800 Subject: [PATCH 055/748] clean clutter --- cctbx/programs/qscore.py | 68 +++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/cctbx/programs/qscore.py b/cctbx/programs/qscore.py index 8c0345f51d..e6b81e6a77 100644 --- a/cctbx/programs/qscore.py +++ b/cctbx/programs/qscore.py @@ -10,14 +10,13 @@ class Program(ProgramTemplate): - description = """ + description = """ Perform a Qscore analysis for map-model fit """ - datatypes = ['phil','model','real_map'] + datatypes = ['phil', 'model', 'real_map'] - - master_phil_str = """ + master_phil_str = """ nproc = 8 .type = int .help = Number of processors to use @@ -39,7 +38,7 @@ class Program(ProgramTemplate): .help = Start testing density at this radius from atom .short_caption = Start testing density at this radius from atom .expert_level = 1 - + shell_radius_stop = 2 .type = float .help = Stop testing density at this radius from atom @@ -60,36 +59,35 @@ class Program(ProgramTemplate): Precalculate is a method where probes are pre-allocated and \ rejected once. Parallelization is done by radial shell. \ Precalculate is much faster but will yield slightly different results. - + """ - def validate(self): - pass - - def run(self): - print("Running") - shells = np.linspace(self.params.shell_radius_start, - self.params.shell_radius_stop, - num = self.params.shell_radius_num, - endpoint=True) - mmm = self.data_manager.get_map_model_manager() - version = 2 if self.params.probe_allocation_method == "precalculate" else 1 # 'progressive' - - # TODO: move param unpacking to the library function - result = qscore_np( - mmm, - selection=self.params.selection, - n_probes = self.params.n_probes, - shells = shells, - nproc=self.params.nproc, - version=version, - log = self.logger) - print("Result:") - for val in result: - print(str(val)+",") - self.result = group_args(qscore=result) - - - def get_results(self): - return self.result + def validate(self): + pass + + def run(self): + print("Running") + shells = np.linspace(self.params.shell_radius_start, + self.params.shell_radius_stop, + num=self.params.shell_radius_num, + endpoint=True) + mmm = self.data_manager.get_map_model_manager() + version = 2 if self.params.probe_allocation_method == "precalculate" else 1 # 'progressive' + + # TODO: move param unpacking to the library function + result = qscore_np( + mmm, + selection=self.params.selection, + n_probes=self.params.n_probes, + shells=shells, + nproc=self.params.nproc, + version=version, + log=self.logger) + print("Result:") + for val in result: + print(str(val)+",") + self.result = group_args(qscore=result) + + def get_results(self): + return self.result From 4cec80d5f1e3fb91b1cc3f1ff243df1eb074b7fa Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 23 Jan 2024 16:42:42 -0800 Subject: [PATCH 056/748] added mmtbx.electrons to programs --- mmtbx/command_line/electrons.py | 7 +++++++ mmtbx/ligands/electrons.py | 3 ++- mmtbx/ligands/hierarchy_utils.py | 8 ++++---- 3 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 mmtbx/command_line/electrons.py diff --git a/mmtbx/command_line/electrons.py b/mmtbx/command_line/electrons.py new file mode 100644 index 0000000000..8f9c98c87d --- /dev/null +++ b/mmtbx/command_line/electrons.py @@ -0,0 +1,7 @@ +# LIBTBX_SET_DISPATCHER_NAME mmtbx.electrons +from __future__ import absolute_import, division, print_function + +from iotbx.cli_parser import run_program +from mmtbx.ligands import electrons + +run_program(electrons.Program) diff --git a/mmtbx/ligands/electrons.py b/mmtbx/ligands/electrons.py index 96e3ccd66e..ac53851ffd 100644 --- a/mmtbx/ligands/electrons.py +++ b/mmtbx/ligands/electrons.py @@ -918,7 +918,7 @@ def report(self, ignore_water=False, show_detailed=False): return report from libtbx.program_template import ProgramTemplate -#from libtbx.utils import null_out +from libtbx.utils import null_out from libtbx import group_args master_phil_str = ''' @@ -956,6 +956,7 @@ def validate(self): def run(self): model = self.data_manager.get_model() + model.set_log(null_out()) model.process(make_restraints=True) if self.params.input.selection: new_model = model.selection(self.params.input.selection) diff --git a/mmtbx/ligands/hierarchy_utils.py b/mmtbx/ligands/hierarchy_utils.py index 1df21622d0..4d98d99d8e 100644 --- a/mmtbx/ligands/hierarchy_utils.py +++ b/mmtbx/ligands/hierarchy_utils.py @@ -114,22 +114,22 @@ def get_bonds_as_dict(geometry_restraints_manager): def get_valences(element, charge): valence = { - 'C' : 4, + # 'C' : 4, 'N' : 3, 'O' : 2, } rc = valence.get(element) + if rc is None: return [] rc += charge return [rc] def simple_valence_check(ph, geometry_restraints_manager): - bonds = get_bonds_as_dict(geometry_restraints_manager) + bonds = get_bonds_as_dict(geometry_restraints_manager.geometry) for atom in ph.atoms(): if atom.element_is_hydrogen(): continue if atom.parent().resname in ['HOH']: continue - print(atom.quote()) - print(bonds[atom.i_seq]) number_of_bonds = len(bonds.get(atom.i_seq, None)) + # if number_of_bonds is None: continue if number_of_bonds not in get_valences(atom.element, atom.charge_as_int()): assert 0 From dcdba59cbecd8a9d6f26c2413f3dc29d813588ec Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 23 Jan 2024 16:44:49 -0800 Subject: [PATCH 057/748] add H to water --- mmtbx/hydrogens/reduce_hydrogen.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index 468a015107..c86badf5bd 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -328,6 +328,9 @@ def run(self): # restraint_objects = ro, # log = null_out()) + if not self.exclude_water: + self.model.add_hydrogens(1., occupancy=0.) + self.n_H_final = self.model.get_hd_selection().count(True) # ------------------------------------------------------------------------------ From 40f6d64cb578b8711153958dfd507bb1e5f14f88 Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 23 Jan 2024 23:28:57 -0800 Subject: [PATCH 058/748] Major update to .geo parsing to expand compatibility to additional restraints. Also fixes a failing test --- .azure-pipelines/py2_syntax_exceptions.txt | 2 + mmtbx/geometry_restraints/geo_file_parsing.py | 279 +++++++------ .../tst_geo_file_parsing.py | 384 ++++++++++++------ 3 files changed, 418 insertions(+), 247 deletions(-) diff --git a/.azure-pipelines/py2_syntax_exceptions.txt b/.azure-pipelines/py2_syntax_exceptions.txt index fe6be8c43c..ed005d33d1 100644 --- a/.azure-pipelines/py2_syntax_exceptions.txt +++ b/.azure-pipelines/py2_syntax_exceptions.txt @@ -15,3 +15,5 @@ xfel/command_line/fee_calibration.py xfel/util/drift.py cctbx/maptbx/qscore.py cctbx/maptbx/tst_qscore.py +mmtbx/geometry_restraints/geo_file_parsing.py +mmtbx/geometry_restraints/tst_geo_file_parsing.py diff --git a/mmtbx/geometry_restraints/geo_file_parsing.py b/mmtbx/geometry_restraints/geo_file_parsing.py index 755e1c74ee..20c8876863 100644 --- a/mmtbx/geometry_restraints/geo_file_parsing.py +++ b/mmtbx/geometry_restraints/geo_file_parsing.py @@ -1,67 +1,184 @@ """ Parse a '.geo' text file to structured restraint data. """ -from __future__ import division import re import pandas as pd import numpy as np - - - +def tryfloat(value): + try: + return float(value) + except: + return value +class BondRestraint: + restraint_label = 'bond' + @classmethod + def from_geo_lines(cls,lines,settings): + # start make restraint + n_atoms = settings["n_atoms"] + restraint_key = cls.restraint_label + key_index = n_atoms + value_index = n_atoms+1 + atom_indices = ["i","j","k","l","m","n"] + atoms_i_seqs = [int(re.search(r'\d+', lines[i]).group()) for i in range(0,n_atoms)] + keys = [e for e in lines[key_index].split()] + values = [tryfloat(e) for e in lines[value_index].split()] + d = {"restraint_type":restraint_key} + for i, i_seq in enumerate(atoms_i_seqs): + k = "{}_seq".format(atom_indices[i]) + v = i_seq + d[k] = v + d.update({key:value for key,value in zip(keys,values)}) + return cls(d) + def __init__(self, data_dict): + self.data_dict = data_dict +class AngleRestraint(BondRestraint): + restraint_label = 'angle' +class DihedralRestraint(BondRestraint): + restraint_label = 'dihedral' +class NonBondedRestraint(BondRestraint): + restraint_label = 'nonbonded' +class ChiralityRestraint(BondRestraint): + restraint_label = 'chirality' +class CBetaRestraint(BondRestraint): + restraint_label = 'c-beta' restraint_settings = { - "nonbonded":{ # name of restraint - "header_label":"Nonbonded interactions", # search string - "n_atoms":2, # n_atoms to look for - "cif_key":"_phenix_restraint_nonbonded" # key for restraint in result - }, - "angle":{ - "header_label":"Bond angle restraints", - "n_atoms":3, - "cif_key":"_phenix_restraint_angle" - }, - "bond":{ - "header_label":"Bond restraints", - "n_atoms":2, - "cif_key":"_phenix_restraint_bond" - }, - "dihedral":{ - "header_label":"Dihedral angle restraints", - "n_atoms":4, - "cif_key":"_phenix_restraint_dihedral" - }, - + "nonbonded":{ # name of restraint + "header_label":"Nonbonded interactions", # search string + "n_atoms":2, # n_atoms to look for + "cif_key":"_phenix_restraint_nonbonded", # key for restraint in result + "restraint_class":NonBondedRestraint, + }, + "angle":{ + "header_label":"Bond angle restraints", + "n_atoms":3, + "cif_key":"_phenix_restraint_angle", + "restraint_class":AngleRestraint, + }, + "bond":{ + "header_label":"Bond restraints", + "n_atoms":2, + "cif_key":"_phenix_restraint_bond", + "restraint_class":BondRestraint, + }, + "dihedral":{ + "header_label":"Dihedral angle restraints", + "n_atoms":4, + "cif_key":"_phenix_restraint_dihedral", + "restraint_class":DihedralRestraint, + }, + "chirality":{ + "header_label":"Chirality restraints", + "n_atoms":4, + "cif_key":"_phenix_restraint_chirality", + "restraint_class":ChiralityRestraint, + }, + "c-beta":{ + "header_label":"C-Beta improper torsion angle restraints", + "n_atoms":4, + "cif_key":"_phenix_restraint_c-beta", + "restraint_class":CBetaRestraint, + }, + # "plane":{ + # "header_label":"Planarity restraints", + # "n_atoms":None, + # "cif_key":"_phenix_restraint_planarity", + # "restraint_class":PlanarityRestraint, + # }, } - +def split_into_sections(lines): + """ + Split a .geo file lines into sub-sections of lines for each restraint type + """ + sections = {} + current_section = None + for idx,line in enumerate(lines): + line = line.strip() + if not line: + continue + # Check if the line is a section header + if ':' in line and any(keyword in line for keyword in ['restraints', 'interactions']): + current_section = line + sections[current_section] = [] + elif current_section is not None: + # if 'plane' in line: + # sections[current_section].append(lines[idx-1]) + sections[current_section].append(line) + # Rename labels + output = {} + for section_label,section_value in sections.items(): + for setting_label, setting_value in restraint_settings.items(): + search_term = setting_value["header_label"] + if search_term in section_label: + output[setting_label] = section_value + return output + +def extract_restraint_objs_from_group(group, + settings, + restraint_key=None): + """ + Given a 'group' of lines for a given restraint, extract the data to a restraint instance + """ + n_atoms = settings["n_atoms"] + restraints = [] + restraint_lines = [] + if restraint_key == "c-beta": + new_entry_indicator = 'dihedral' + else: + new_entry_indicator = restraint_key + restraint_label = restraint_key + for idx,line in enumerate(group): + # Check if the line is the start of a new entry within the restraint + if new_entry_indicator in line: + if restraint_lines: + # If there are already lines collected for a previous entry, save them + restraints.append(restraint_lines) + restraint_lines = [line] + else: + # This is the first entry in the restraint + if restraint_key == "plane": + if idx>1: + restraint_lines.append(group[idx-1]) + restraint_lines.append(line) + elif restraint_lines: + # Continue adding lines to the current entry + restraint_lines.append(line) + # Add the last set of lines if not empty + if restraint_lines: + restraints.append(restraint_lines) + s = set([len(r) for r in restraints]) + if restraint_key != "plane": + assert len(s)==1, "Failed .geo parsing\n"+"\n".join(restraint_lines) + assert next(iter(s))==n_atoms+2, "Failed .geo parsing"+"\n".join(restraints) + restraint_objs = [] + for restraint_lines in restraints: + settings = restraint_settings[restraint_label] + if "restraint_class" in settings: + restraint_class = restraint_settings[restraint_label]["restraint_class"] + restraint_instance = restraint_class.from_geo_lines(restraint_lines,settings) + restraint_objs.append(restraint_instance) + return restraint_objs def parse_geo_file(filename,return_format='dict'): """ Args: filename (str): the .geo filename return_format (str): One of 'dict', 'df' (pd.DataFrame), or 'json' - Returns: restraint_dicts (dict): nested dictionary with final data in column format """ with open(filename,"r") as fh: lines = fh.readlines() - groups = geo_lines_to_groups(lines) restraint_dicts_all = {} - for restraint_key,settings in restraint_settings.items(): - header_label = settings["header_label"] - n_atoms = settings["n_atoms"] - restraint_dicts = extract_restraint_dicts_from_groups(groups, - restraint_key=restraint_key, - header_label=header_label, - n_atoms=n_atoms) - reframed_dict = pd.DataFrame.from_records(restraint_dicts).to_dict("list") - restraint_dicts_all[restraint_key] = reframed_dict - for key,value in list(restraint_dicts_all.items()): - cif_key = restraint_settings[key]["cif_key"] - restraint_dicts_all[cif_key] = restraint_dicts_all.pop(key) - + restraint_sections = split_into_sections(lines) + for restraint_label,setting_dict in restraint_settings.items(): + if restraint_label in restraint_sections: + group = restraint_sections[restraint_label] + restraint_objs = extract_restraint_objs_from_group(group, + setting_dict, + restraint_key=restraint_label) + restraint_dicts_all[restraint_label] = [obj.data_dict for obj in restraint_objs] # convert dicts to dataframes and fill nan with None dfs = {key:pd.DataFrame(value).replace({np.nan: None}) for key,value in restraint_dicts_all.items()} - if return_format == "df": return dfs elif return_format == "dict": @@ -70,81 +187,3 @@ def parse_geo_file(filename,return_format='dict'): elif return_format == "json": # same format as dict, but as json string return {key:df.to_json(orient='records') for key,df in dfs.items()} - - - - - -def geo_lines_to_groups(lines): - """ - Parse raw text lines into 'groups' of lines for each restraint type - """ - - # group by newline into restraints groups (bonds, angles, etc) - groups = [] - group_open = False - group_lines = [] - for line in lines: - if line == "\n": - if group_open == False: # first group - group_open = True - else: # close open group - groups.append(group_lines) - group_lines = [] - elif group_open: - group_lines.append(line) - return groups - -def extract_restraint_dicts_from_groups(groups, - restraint_key=None, - header_label=None, - n_atoms=None, - ignore_sym=True): - """ - Given a 'group' of lines for a given restraint, extract the data to a dictionary - - ignore_sym (bool): Whether to include restraints that cross symetry boundary - - TODO: This only works up to dihedral. Need to implement restraints with uncertain n_atoms - """ - assert [restraint_key,header_label,n_atoms].count(None)==0, "provide each parameter" - # split groups into nonbonded restraints - group = [group for group in groups if header_label in group[0]][0] - - restraints = [] - restraint_open = False - restraint_lines = [] - for line in group: - if restraint_key in line and header_label not in line: - if restraint_open == False: - restraint_open = True - else: - restraints.append(restraint_lines) - restraint_lines = [] - if restraint_open: - restraint_lines.append(line) - - s = set([len(r) for r in restraints]) - assert len(s)==1, "Failed .geo parsing" - assert next(iter(s))==n_atoms+2, "Failed .geo parsing" - key_index = n_atoms - value_index = n_atoms+1 - - restraint_dicts = [] - atom_indices = ["i","j","k","l","m","n"] - for restraint in restraints: - if "sym.op." in restraint[key_index] and ignore_sym: - continue - atoms_i_seqs = [int(re.search(r'\d+', restraint[i]).group()) for i in range(0,n_atoms)] - - keys = [e for e in restraint[key_index].split()] - values = [float(e) for e in restraint[value_index].split()] - d = {"restraint_type":restraint_key} - for i, i_seq in enumerate(atoms_i_seqs): - k = "{}_seq".format(atom_indices[i]) - v = i_seq - d[k] = v - d.update({key:value for key,value in zip(keys,values)}) - - restraint_dicts.append(d) - return restraint_dicts diff --git a/mmtbx/geometry_restraints/tst_geo_file_parsing.py b/mmtbx/geometry_restraints/tst_geo_file_parsing.py index 74fc01110d..752b9f19f1 100644 --- a/mmtbx/geometry_restraints/tst_geo_file_parsing.py +++ b/mmtbx/geometry_restraints/tst_geo_file_parsing.py @@ -12,173 +12,306 @@ """ Test that parsing a geo file yields previous results """ +sample_geo_text = """ +# Geometry restraints + +Bond restraints: 2 +bond 38 + 39 + ideal model delta sigma weight residual + 1.522 1.553 -0.030 1.18e-02 7.18e+03 6.53e+00 +bond 37 + 38 + ideal model delta sigma weight residual + 1.460 1.485 -0.025 1.17e-02 7.31e+03 4.40e+00 + +Bond angle restraints: 2 +Sorted by residual: +angle 23 + 24 + 25 + ideal model delta sigma weight residual + 108.90 113.48 -4.58 1.63e+00 3.76e-01 7.90e+00 +angle 37 + 38 + 39 + ideal model delta sigma weight residual + 108.02 111.93 -3.91 1.78e+00 3.16e-01 4.84e+00 + + +Dihedral angle restraints: 2 + sinusoidal: 1 + harmonic: 1 +Sorted by residual: +dihedral 24 + 25 + 37 + 38 + ideal model delta harmonic sigma weight residual + 180.00 166.21 13.79 0 5.00e+00 4.00e-02 7.60e+00 +dihedral 58 + 59 + 60 + 61 + ideal model delta sinusoidal sigma weight residual + 0.00 -72.39 72.39 2 3.00e+01 1.11e-03 4.85e+00 + + +C-Beta improper torsion angle restraints: 2 +Sorted by residual: +dihedral 37 + 39 + 38 + 41 + ideal model delta harmonic sigma weight residual + 122.80 126.95 -4.15 0 2.50e+00 1.60e-01 2.75e+00 +dihedral 56 + 54 + 55 + 58 + ideal model delta harmonic sigma weight residual + -122.60 -126.01 3.41 0 2.50e+00 1.60e-01 1.86e+00 + + +Chirality restraints: 2 +Sorted by residual: +chirality 55 + 54 + 56 + 58 + both_signs ideal model delta sigma weight residual + False 2.51 2.39 0.12 2.00e-01 2.50e+01 3.48e-01 +chirality 72 + 71 + 73 + 75 + both_signs ideal model delta sigma weight residual + False 2.51 2.62 -0.11 2.00e-01 2.50e+01 2.86e-01 + +Planarity restraints: 2 +Sorted by residual: + delta sigma weight rms_deltas residual +plane 89 0.007 2.00e-02 2.50e+03 1.43e-02 6.15e+00 + 90 0.029 2.00e-02 2.50e+03 + 91 -0.003 2.00e-02 2.50e+03 + 92 0.001 2.00e-02 2.50e+03 + 93 0.003 2.00e-02 2.50e+03 + 94 -0.001 2.00e-02 2.50e+03 + 95 -0.013 2.00e-02 2.50e+03 + 96 -0.001 2.00e-02 2.50e+03 + 102 -0.029 2.00e-02 2.50e+03 + 103 -0.016 2.00e-02 2.50e+03 + 104 0.017 2.00e-02 2.50e+03 + 105 0.005 2.00e-02 2.50e+03 + delta sigma weight rms_deltas residual +plane 13 -0.003 2.00e-02 2.50e+03 1.55e-02 3.62e+00 + 14 -0.022 2.00e-02 2.50e+03 + 15 0.019 2.00e-02 2.50e+03 + 16 -0.002 2.00e-02 2.50e+03 + 19 -0.012 2.00e-02 2.50e+03 + 20 0.020 2.00e-02 2.50e+03 + + +Nonbonded interactions: 3 +Sorted by model distance: +nonbonded 106 + 110 + model vdw sym.op. + 1.719 1.850 -x+1,y-1/2,-z+1 +nonbonded 29 + 34 + model vdw sym.op. + 1.859 1.850 x,y+1,z + +nonbonded 33 + 61 + model vdw + 1.876 1.850 + +""" + test_data_json = """ { - "_phenix_restraint_nonbonded": [ + "nonbonded": [ { "restraint_type": "nonbonded", - "i_seq": 0, - "j_seq": 3, - "model": 2.665, - "vdw": 2.496 + "i_seq": 106, + "j_seq": 110, + "model": 1.719, + "vdw": 1.85, + "sym.op.": "-x+1,y-1/2,-z+1" }, { "restraint_type": "nonbonded", - "i_seq": 19, - "j_seq": 36, - "model": 2.726, - "vdw": 2.52 + "i_seq": 29, + "j_seq": 34, + "model": 1.859, + "vdw": 1.85, + "sym.op.": "x,y+1,z" }, { "restraint_type": "nonbonded", - "i_seq": 41, - "j_seq": 42, - "model": 2.803, - "vdw": 2.752 + "i_seq": 33, + "j_seq": 61, + "model": 1.876, + "vdw": 1.85, + "sym.op.": null } ], - "_phenix_restraint_angle": [ + "angle": [ { "restraint_type": "angle", - "i_seq": 12, - "j_seq": 13, - "k_seq": 14, + "i_seq": 23, + "j_seq": 24, + "k_seq": 25, "ideal": 108.9, - "model": 113.46, - "delta": -4.56, + "model": 113.48, + "delta": -4.58, "sigma": 1.63, "weight": 0.376, - "residual": 7.83 - }, - { - "restraint_type": "angle", - "i_seq": 21, - "j_seq": 22, - "k_seq": 23, - "ideal": 120.33, - "model": 122.26, - "delta": -1.93, - "sigma": 1.08, - "weight": 0.857, - "residual": 3.18 + "residual": 7.9 }, { "restraint_type": "angle", - "i_seq": 29, - "j_seq": 30, - "k_seq": 31, - "ideal": 108.9, - "model": 111.01, - "delta": -2.11, - "sigma": 1.63, - "weight": 0.376, - "residual": 1.68 + "i_seq": 37, + "j_seq": 38, + "k_seq": 39, + "ideal": 108.02, + "model": 111.93, + "delta": -3.91, + "sigma": 1.78, + "weight": 0.316, + "residual": 4.84 } ], - "_phenix_restraint_bond": [ - { - "restraint_type": "bond", - "i_seq": 0, - "j_seq": 1, - "ideal": 1.451, - "model": 1.507, - "delta": -0.056, - "sigma": 0.016, - "weight": 3910.0, - "residual": 12.1 - }, + "bond": [ { "restraint_type": "bond", - "i_seq": 5, - "j_seq": 6, - "ideal": 1.524, - "model": 1.498, - "delta": 0.026, - "sigma": 0.0126, - "weight": 6300.0, - "residual": 4.15 + "i_seq": 38, + "j_seq": 39, + "ideal": 1.522, + "model": 1.553, + "delta": -0.03, + "sigma": 0.0118, + "weight": 7180.0, + "residual": 6.53 }, { "restraint_type": "bond", - "i_seq": 35, - "j_seq": 37, - "ideal": 1.328, - "model": 1.348, - "delta": -0.02, - "sigma": 0.021, - "weight": 2270.0, - "residual": 0.875 + "i_seq": 37, + "j_seq": 38, + "ideal": 1.46, + "model": 1.485, + "delta": -0.025, + "sigma": 0.0117, + "weight": 7310.0, + "residual": 4.4 } ], - "_phenix_restraint_dihedral": [ + "dihedral": [ { "restraint_type": "dihedral", - "i_seq": 13, - "j_seq": 14, - "k_seq": 20, - "l_seq": 21, + "i_seq": 24, + "j_seq": 25, + "k_seq": 37, + "l_seq": 38, "ideal": 180.0, - "model": 166.19, - "delta": 13.81, + "model": 166.21, + "delta": 13.79, "harmonic": 0.0, "sigma": 5.0, "weight": 0.04, - "residual": 7.63, + "residual": 7.6, "sinusoidal": null }, { "restraint_type": "dihedral", - "i_seq": 1, - "j_seq": 2, - "k_seq": 4, - "l_seq": 5, - "ideal": 180.0, - "model": 171.51, - "delta": 8.49, + "i_seq": 58, + "j_seq": 59, + "k_seq": 60, + "l_seq": 61, + "ideal": 0.0, + "model": -72.39, + "delta": 72.39, + "harmonic": null, + "sigma": 30.0, + "weight": 0.00111, + "residual": 4.85, + "sinusoidal": 2.0 + } + ], + "chirality": [ + { + "restraint_type": "chirality", + "i_seq": 55, + "j_seq": 54, + "k_seq": 56, + "l_seq": 58, + "both_signs": "False", + "ideal": 2.51, + "model": 2.39, + "delta": 0.12, + "sigma": 0.2, + "weight": 25.0, + "residual": 0.348 + }, + { + "restraint_type": "chirality", + "i_seq": 72, + "j_seq": 71, + "k_seq": 73, + "l_seq": 75, + "both_signs": "False", + "ideal": 2.51, + "model": 2.62, + "delta": -0.11, + "sigma": 0.2, + "weight": 25.0, + "residual": 0.286 + } + ], + "c-beta": [ + { + "restraint_type": "c-beta", + "i_seq": 37, + "j_seq": 39, + "k_seq": 38, + "l_seq": 41, + "ideal": 122.8, + "model": 126.95, + "delta": -4.15, "harmonic": 0.0, - "sigma": 5.0, - "weight": 0.04, - "residual": 2.88, - "sinusoidal": null + "sigma": 2.5, + "weight": 0.16, + "residual": 2.75 }, { - "restraint_type": "dihedral", - "i_seq": 20, - "j_seq": 21, - "k_seq": 24, - "l_seq": 25, - "ideal": -180.0, - "model": -164.64, - "delta": -15.36, - "harmonic": null, - "sigma": 15.0, - "weight": 0.00444, - "residual": 1.45, - "sinusoidal": 3.0 + "restraint_type": "c-beta", + "i_seq": 56, + "j_seq": 54, + "k_seq": 55, + "l_seq": 58, + "ideal": -122.6, + "model": -126.01, + "delta": 3.41, + "harmonic": 0.0, + "sigma": 2.5, + "weight": 0.16, + "residual": 1.86 } ] } + """ test_data = json.loads(test_data_json) # load file -pdb_file = libtbx.env.find_in_repositories( - relative_path="phenix_regression/pdb/1yjp_h.pdb", - test=os.path.isfile) - -dm = DataManager() -dm.process_model_file(pdb_file) -model = dm.get_model() - -# write geo -model.add_crystal_symmetry_if_necessary() -model.process(make_restraints=True) -grm = model.get_restraints_manager().geometry -grm.write_geo_file(model.get_sites_cart(),file_name="test.geo") +with open("tst_geo_parsing.geo","w") as fh: + fh.write(sample_geo_text) # read back in -geo_dict = parse_geo_file("test.geo",return_format='dict') +geo_dict = parse_geo_file("tst_geo_parsing.geo",return_format='dict') # define comparison functions @@ -197,30 +330,27 @@ def compare_custom(d1,d2): Compare two dictionaries by types, and 'ideal' floats with a large tolerance to enable future changes to restraints. """ - print(d1) - print(d2) + #print(d1) + #print(d2) for key1,value1 in d1.items(): assert key1 in d2 value2 = d2[key1] - print(value1,value2) + #print(value1,value2) t1,t2 = get_type(value1), get_type(value2) assert t1==t2, '%s!=%s' % (t1, t2) - if isinstance(t1,float): - if key1 == 'ideal': - diff = abs(float(value1)-float(value2)) - assert diff < 5, "difference in expected and generated restraint out of range" # 5 ok? + assert str(value1)==str(value2), "Invalid comparisons: "+str(value1)+" and "+str(value2) return True + # test def test(): for key,d_list in geo_dict.items(): - spot_indices = [0,3,11] - for idx,i in enumerate(spot_indices): - d = d_list[i] - d_ref = test_data[key][idx] + for j,d in enumerate(d_list): + d_ref = test_data[key][j] same = compare_custom(d,d_ref) print(same) - if __name__ == '__main__': test() + print("Finished") + From 03bf7e24790850ff0f14d74e14321f1efd64bb3a Mon Sep 17 00:00:00 2001 From: cschlick Date: Wed, 24 Jan 2024 01:07:34 -0800 Subject: [PATCH 059/748] Clean clutter --- mmtbx/geometry_restraints/geo_file_parsing.py | 6 ++---- mmtbx/geometry_restraints/tst_geo_file_parsing.py | 5 ----- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/mmtbx/geometry_restraints/geo_file_parsing.py b/mmtbx/geometry_restraints/geo_file_parsing.py index 20c8876863..83d4acdbdb 100644 --- a/mmtbx/geometry_restraints/geo_file_parsing.py +++ b/mmtbx/geometry_restraints/geo_file_parsing.py @@ -1,13 +1,11 @@ -""" -Parse a '.geo' text file to structured restraint data. -""" +from __future__ import division, print_function import re import pandas as pd import numpy as np def tryfloat(value): try: return float(value) - except: + except Exception: return value class BondRestraint: restraint_label = 'bond' diff --git a/mmtbx/geometry_restraints/tst_geo_file_parsing.py b/mmtbx/geometry_restraints/tst_geo_file_parsing.py index 752b9f19f1..a559070a4f 100644 --- a/mmtbx/geometry_restraints/tst_geo_file_parsing.py +++ b/mmtbx/geometry_restraints/tst_geo_file_parsing.py @@ -1,11 +1,6 @@ from __future__ import division, print_function -import os import json - -import libtbx.load_env -from iotbx.data_manager import DataManager - from geo_file_parsing import parse_geo_file From 0c22b185dc3ab3ab7077a751af26cf1f75030c4f Mon Sep 17 00:00:00 2001 From: cschlick Date: Wed, 24 Jan 2024 11:04:48 -0800 Subject: [PATCH 060/748] Updates to qscore code --- cctbx/maptbx/qscore.py | 163 ++++++++++++++++++++++++++++----------- cctbx/programs/qscore.py | 82 ++++---------------- 2 files changed, 137 insertions(+), 108 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index 27c9c22067..bf6c83773e 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -23,21 +23,90 @@ from cctbx.array_family import flex from scitbx_array_family_flex_ext import bool as flex_bool -# from .qscore_utils import ( -# trilinear_interpolation, -# rowwise_corrcoef, -# sphere_points_np, -# sphere_points_flex, -# cdist_flex, -# query_ball_point_flex, -# query_atom_neighbors, -# ) -# from .flex_utils import optimized_nd_to_1d_indices, nd_to_1d_indices, flex_std +class DummyTQDM: + """A 'dummy' object that can be used for compatibility if tqdm is not installed""" + + def __init__(self, iterable=None, *args, **kwargs): + self.iterable = iterable + self.args = args + self.kwargs = kwargs + + def __iter__(self): + return iter(self.iterable) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + pass try: - from tqdm import tqdm + from tqdm import tqdm except ImportError: - from .qscore_utils import DummyTQDM as tqdm + tqdm = DummyTQDM + + +master_phil_str = """ + qscore + { + + nproc = 16 + .type = int + .help = Number of processors to use + .short_caption = Number of processors to use + .expert_level = 1 + n_probes = 8 + .type = int + .help = Number of radial probes to use + .short_caption = Number of radial probes to use + .expert_level = 1 + selection = None + .type = str + .help = Only test atoms within this selection + .short_caption = Only test atoms within this selection + .expert_level = 1 + + shell_radius_start = 0.1 + .type = float + .help = Start testing density at this radius from atom + .short_caption = Start testing density at this radius from atom + .expert_level = 1 + + shell_radius_stop = 2 + .type = float + .help = Stop testing density at this radius from atom + .short_caption = Stop testing density at this radius from atom + .expert_level = 1 + + shell_radius_num = 20 + .type = int + .help = The number of radial shells + .short_caption = The number of radial shells (includes start/stop, so minimum 2) + .expert_level = 1 + + probe_allocation_method = precalculate + .type = str + .help = The method used to allocate radial probes + .short_caption = Either 'progressive' or 'precalculate'. Progressive is the original method \ + where probes are proposed and rejected iteratively. \ + Precalculate is a method where probes are pre-allocated and \ + rejected once. Parallelization is done by radial shell. \ + Precalculate is much faster but will yield slightly different results. + + progress = False + .type = bool + .help = Report progress + .short_caption = Report progress bar + .expert_level = 1 + + debug = False + .type = bool + .help = Return much more debug information + .short_caption = Returns a dictionary with additional debug information + .expert_level = 1 + } + + """ def radial_shell_worker_v1_np(args): @@ -150,7 +219,8 @@ def radial_shell_worker_v2_np(args): if selection is None: selection = np.arange(len(atoms_xyz)) else: - assert selection.dtype == bool + #assert selection.dtype == bool + pass # do selection atoms_xyz_sel = atoms_xyz[selection] @@ -165,7 +235,6 @@ def radial_shell_worker_v2_np(args): probe_mask = ( counts == 0 ) # keep probes with 0 nearby atoms. The rtol ensures self is not counted - return probe_xyz, probe_mask @@ -178,13 +247,15 @@ def radial_shell_mp_np( num_processes=cpu_count(), selection=None, version=2, + progress=True, log=sys.stdout, ): """ Generate probes for a model file using numpy """ assert version in [1, 2], "Version must be 1 or 2" - + if not progress: + tqdm = DummyTQDM atoms_xyz = model.get_sites_cart().as_numpy_array() tree = KDTree(atoms_xyz) @@ -230,13 +301,11 @@ def radial_shell_mp_np( probe_xyz_all = [result[0] for result in results] probe_mask_all = [result[1] for result in results] - # debug - # return probe_xyz_all, probe_mask_all - # stack numpy probe_xyz = np.stack(probe_xyz_all) probe_mask = np.stack(probe_mask_all) - + probe_xyz = np.transpose(probe_xyz, (0, 2, 1, 3)) # Reorder to shape (n_shells,n_atoms,n_probes,3) + probe_mask = np.swapaxes(probe_mask, 1, 2) return probe_xyz, probe_mask @@ -250,9 +319,6 @@ def ndarray_to_nested_list(arr): return arr.tolist() return [ndarray_to_nested_list(sub_arr) for sub_arr in arr] -# Example usage - - def qscore_np( mmm, selection=None, @@ -275,7 +341,9 @@ def qscore_np( ), version=2, nproc=cpu_count(), + progress=True, log=sys.stdout, + debug = False ): """ Calculate the qscore metric per-atom from an mmtbx map-model-manager, using numpy @@ -293,6 +361,7 @@ def qscore_np( selection=selection, version=version, radii=radii, + progress=progress, log=log, ) @@ -364,10 +433,37 @@ def qscore_np( # np.save("probe_mask_np.npy",probe_mask) # print("saving qscore: qscore_np.npy") # np.save("qscore_np.npy",q) - + if debug: + result = { + "q":q, + "probe_xyz":probe_xyz, + "probe_mask":probe_mask, + } + return result return q - +def run_qscore(mmm,params,log=sys.stdout,return_type='flex'): + """ + The primary function to interact with this file. + """ + shells = np.linspace(params.shell_radius_start, + params.shell_radius_stop, + num=params.shell_radius_num, + endpoint=True) + version = 2 if "precalculate" in params.probe_allocation_method else 1 # "progressive" + result = qscore_np(mmm, + selection=params.selection, + n_probes = params.n_probes, + shells = shells, + version=version, + nproc=params.nproc, + progress=params.progress, + log=log, + debug=params.debug + ) + if return_type == "flex" and not params.debug: + result = flex.double(result) + return result ############################################################################## # Functions that use only flex, no numpy ############################################################################## @@ -632,25 +728,6 @@ def custom_reshape_indices(flex_array): # qscore utils - -class DummyTQDM: - """A 'dummy' object that can be used for compatibility if tqdm is not installed""" - - def __init__(self, iterable=None, *args, **kwargs): - self.iterable = iterable - self.args = args - self.kwargs = kwargs - - def __iter__(self): - return iter(self.iterable) - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, traceback): - pass - - def trilinear_interpolation(voxel_grid, coords, voxel_size=None, offset=None): """Numpy trilinear interpolation""" assert voxel_size is not None, "Provide voxel size as an array or single value" diff --git a/cctbx/programs/qscore.py b/cctbx/programs/qscore.py index e6b81e6a77..fa52f13b82 100644 --- a/cctbx/programs/qscore.py +++ b/cctbx/programs/qscore.py @@ -1,11 +1,10 @@ from __future__ import absolute_import, division, print_function -from phenix.program_template import ProgramTemplate +from libtbx.program_template import ProgramTemplate from libtbx import group_args -from cctbx.maptbx.qscore import qscore_np +from cctbx.maptbx import qscore import numpy as np - # ============================================================================= class Program(ProgramTemplate): @@ -17,77 +16,30 @@ class Program(ProgramTemplate): datatypes = ['phil', 'model', 'real_map'] master_phil_str = """ - nproc = 8 - .type = int - .help = Number of processors to use - .short_caption = Number of processors to use - .expert_level = 1 - n_probes = 32 - .type = int - .help = Number of radial probes to use - .short_caption = Number of radial probes to use - .expert_level = 1 - selection = None - .type = str - .help = Only test atoms within this selection - .short_caption = Only test atoms within this selection - .expert_level = 1 - - shell_radius_start = 0.1 - .type = float - .help = Start testing density at this radius from atom - .short_caption = Start testing density at this radius from atom - .expert_level = 1 - - shell_radius_stop = 2 - .type = float - .help = Stop testing density at this radius from atom - .short_caption = Stop testing density at this radius from atom - .expert_level = 1 - - shell_radius_num = 20 - .type = int - .help = The number of radial shells - .short_caption = The number of radial shells (includes start/stop, so minimum 2) - .expert_level = 1 - - probe_allocation_method = precalculate - .type = str - .help = The method used to allocate radial probes - .short_caption = Either 'progressive' or 'precalculate'. Progressive is the original method \ - where probes are proposed and rejected iteratively. \ - Precalculate is a method where probes are pre-allocated and \ - rejected once. Parallelization is done by radial shell. \ - Precalculate is much faster but will yield slightly different results. - - - """ + include scope cctbx.maptbx.qscore.master_phil_str + """ def validate(self): pass def run(self): print("Running") - shells = np.linspace(self.params.shell_radius_start, - self.params.shell_radius_stop, - num=self.params.shell_radius_num, - endpoint=True) mmm = self.data_manager.get_map_model_manager() - version = 2 if self.params.probe_allocation_method == "precalculate" else 1 # 'progressive' - - # TODO: move param unpacking to the library function - result = qscore_np( + if self.params.qscore.selection != None: + selection = np.where(mmm.model().selection(self.params.qscore.selection).as_numpy_array())[0] + if len(selection)==0: + print("Finished... nothing selected") + self.result = group_args() + return + self.params.qscore.selection = selection + qscore_per_atom= qscore.run_qscore( mmm, - selection=self.params.selection, - n_probes=self.params.n_probes, - shells=shells, - nproc=self.params.nproc, - version=version, + self.params.qscore, log=self.logger) - print("Result:") - for val in result: - print(str(val)+",") - self.result = group_args(qscore=result) + + print("Finished") + self.result = group_args(qscore_per_atom=qscore_per_atom) + def get_results(self): return self.result From f0f0a0b6bb823e9e2bd5a18d43fe684996a061fe Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 24 Jan 2024 13:38:19 -0800 Subject: [PATCH 061/748] iotbx: update hierachy pickling - Attributes added to the hierarchy class in Python will require additional changes to the pickling code --- iotbx/pdb/hierarchy.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index b84f5985dc..60cf9620a2 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -376,7 +376,17 @@ class _(): >>> hierarchy = iotbx.pdb.hierarchy.root() """ + __getstate_manages_dict__ = True + def __getstate__(self): + # check that the only possible attributes that are set are + # _lai_lookup + # _label_seq_id_dict + # these are not pickled and are not restored when unpickling + # if more attributes are added to the hierarchy class in Python, + # the pickling code needs to be updated. + assert len(set(self.__dict__.keys()) - set(['_lai_lookup', '_label_seq_id_dict'])) == 0, \ + set(['_lai_lookup', '_label_seq_id_dict']) - set(self.__dict__.keys()) version = 2 pdb_string = StringIO() if self.fits_in_pdb_format(): From 6bc2a01e70ee5c05eb96482fbe1cfa0644b452c0 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 24 Jan 2024 14:07:05 -0800 Subject: [PATCH 062/748] iotbx: add another test for hierachy pickling --- iotbx/pdb/hierarchy.py | 4 ++-- iotbx/pdb/tst_hierarchy.py | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index 60cf9620a2..5e74b6915d 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -385,8 +385,8 @@ def __getstate__(self): # these are not pickled and are not restored when unpickling # if more attributes are added to the hierarchy class in Python, # the pickling code needs to be updated. - assert len(set(self.__dict__.keys()) - set(['_lai_lookup', '_label_seq_id_dict'])) == 0, \ - set(['_lai_lookup', '_label_seq_id_dict']) - set(self.__dict__.keys()) + attribute_check = set(self.__dict__.keys()) - set(['_lai_lookup', '_label_seq_id_dict']) + assert len(attribute_check) == 0, attribute_check version = 2 pdb_string = StringIO() if self.fits_in_pdb_format(): diff --git a/iotbx/pdb/tst_hierarchy.py b/iotbx/pdb/tst_hierarchy.py index b1df62fd4f..f87d26b3e7 100644 --- a/iotbx/pdb/tst_hierarchy.py +++ b/iotbx/pdb/tst_hierarchy.py @@ -5706,6 +5706,43 @@ def exercise_residue_pickling(): assert not show_diff(l.root().as_pdb_string(), eps) rp = l +def exercise_attribute_pickling(): + pdb_inp = pdb.input(source_info=None, lines="""\ +MODEL 1 +ATOM 1 N MET A 1 6.215 22.789 24.067 1.00 0.00 N +ATOM 2 CA MET A 1 6.963 22.789 22.822 1.00 0.00 C +BREAK +HETATM 3 C MET A 2 7.478 21.387 22.491 1.00 0.00 C +ATOM 4 O MET A 2 8.406 20.895 23.132 1.00 0.00 O +ENDMDL +MODEL 3 +HETATM 9 2H3 MPR B 5 16.388 0.289 6.613 1.00 0.08 +SIGATM 9 2H3 MPR B 5 0.155 0.175 0.155 0.00 0.05 +ANISOU 9 2H3 MPR B 5 848 848 848 0 0 0 +SIGUIJ 9 2H3 MPR B 5 510 510 510 0 0 0 +TER +ATOM 10 N CYSCH 6 14.270 2.464 3.364 1.00 0.07 +SIGATM 10 N CYSCH 6 0.012 0.012 0.011 0.00 0.00 +ANISOU 10 N CYSCH 6 788 626 677 -344 621 -232 +SIGUIJ 10 N CYSCH 6 3 13 4 11 6 13 +TER +ENDMDL +""") + hierarchy = pdb_inp.construct_hierarchy() + s = pickle.dumps(hierarchy, 1) + + hierarchy.as_mmcif_string() + expected_attributes = ['_lai_lookup', '_label_seq_id_dict'] + for attribute in hierarchy.__dict__.keys(): + assert attribute in expected_attributes, attribute + s = pickle.dumps(hierarchy, 1) + + setattr(hierarchy, 'not_a_valid_attribute', None) + try: + s = pickle.dumps(hierarchy, 1) + except AssertionError as a: + assert 'not_a_valid_attribute' in str(a) + def exercise_hierarchy_input(): pdb_obj = pdb.hierarchy.input(pdb_string=pdb_2izq_220) i_atoms = pdb_obj.input.atoms() @@ -7282,6 +7319,7 @@ def exercise(args): exercise_root_altloc_indices() exercise_root_pickling() exercise_residue_pickling() + exercise_attribute_pickling() exercise_hierarchy_input() exercise_other() exercise_equality_and_hashing() From 4fcff33d819d0be6353b88f59da42f54fdd7679c Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 24 Jan 2024 14:43:37 -0800 Subject: [PATCH 063/748] CI: add syntax checks for Python 3.11 and 3.12 [skip ci] --- .azure-pipelines/syntax.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.azure-pipelines/syntax.yml b/.azure-pipelines/syntax.yml index 9e7a0a6e83..7bc06d474c 100644 --- a/.azure-pipelines/syntax.yml +++ b/.azure-pipelines/syntax.yml @@ -18,6 +18,10 @@ jobs: PYTHON_VERSION: 3.9 python3.10: PYTHON_VERSION: 3.10 + python3.11: + PYTHON_VERSION: 3.11 + python3.12: + PYTHON_VERSION: 3.12 steps: From eec9caaf15afd4e55d7e28fd3a452ac1468cf661 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Wed, 24 Jan 2024 15:13:40 -0800 Subject: [PATCH 064/748] Cleanup caches before outputting mmCIF --- iotbx/pdb/hierarchy.py | 9 +++++++++ mmtbx/model/model.py | 1 + 2 files changed, 10 insertions(+) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index 5e74b6915d..5d1273bff4 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -1176,6 +1176,14 @@ def get_label_seq_id(self, atom_group): self._label_seq_id_dict[ag.memory_id()] = label_seq_id_str return self._label_seq_id_dict[atom_group.memory_id()] + def clear_label_asym_id_lookups(self): + """ Make sure we have fresh lookups in case the hierarchy was modified since + they were calculated.""" + if hasattr(self, '_lai_lookup'): + del self._lai_lookup + if hasattr(self, '_label_seq_id_dict'): + del self._label_seq_id_dict + def as_cif_block(self, crystal_symmetry=None, coordinate_precision=5, @@ -1186,6 +1194,7 @@ def as_cif_block(self, if crystal_symmetry is None: crystal_symmetry = crystal.symmetry() cs_cif_block = crystal_symmetry.as_cif_block(format="mmcif") + self.clear_label_asym_id_lookups() h_cif_block = iotbx.cif.model.block() coord_fmt_str = "%%.%if" %coordinate_precision diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index 08b89673f4..854e4bd2e3 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -1552,6 +1552,7 @@ def _figure_out_hierarchy_to_output(self, do_not_shift_back): hierarchy_to_output = hierarchy_to_output.deep_copy() if (self._shift_cart is not None) and (not do_not_shift_back): self._shift_back(hierarchy_to_output) + hierarchy_to_output.clear_label_asym_id_lookups() return hierarchy_to_output def can_be_output_as_pdb(self): From fba87ef54e37ac686b489110c5041f8aa3656a21 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 25 Jan 2024 18:04:28 -0800 Subject: [PATCH 065/748] Add step of pre-filting the original P1 mask: remove regions that are large negative blobs of Fo-Fc --- mmtbx/bulk_solvent/mosaic.py | 37 ++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/mmtbx/bulk_solvent/mosaic.py b/mmtbx/bulk_solvent/mosaic.py index 74ddc9ab6c..02ebc451a9 100644 --- a/mmtbx/bulk_solvent/mosaic.py +++ b/mmtbx/bulk_solvent/mosaic.py @@ -622,7 +622,9 @@ def __init__(self, volume_cutoff=50, wrapping=True, force_symmetry=True, - log=None): + log=None, + modifier=None + ): """ Split 0/1 traditional bulk-solvent mask into a series of isolated masks covering the whole unit cell in P1. @@ -640,13 +642,44 @@ def __init__(self, n_real = self.crystal_gridding.n_real(), in_asu = False).mask_data maptbx.unpad_in_place(map=self.mask_p1) + # + # TO-DO: instead of excluding, add them as mosaic regions, may be? + # + tmp = flex.double(flex.grid(self.mask_p1.all()), 1) + if(modifier is not None): + modifier = modifier * self.mask_p1 + sel = modifier < -2.0 # XXX Depending on this, results can vary a lot + modifier = modifier.set_selected(sel, 1) + modifier = modifier.set_selected(~sel, 0) + co = maptbx.connectivity( + map_data = modifier, + threshold = 0.01, + preprocess_against_shallow = False, + wrapping = wrapping) + if(force_symmetry and xray_structure.space_group().type().number() != 1): + co.merge_symmetry_related_regions( + space_group = xray_structure.space_group()) + conn = co.result().as_double() + z = zip(co.regions(),range(0,co.regions().size())) + sorted_by_volume = sorted(z, key=lambda x: x[0], reverse=True) + for i_seq, p in enumerate(sorted_by_volume): + v, i = p + if(i==0): continue + # Skip small volume regions + volume = v*self.step**3 + tmp = tmp.set_selected(conn==i, 0) + if(volume_cutoff is not None and volume < volume_cutoff): + break + modifier = tmp + # + # # Solvent fraction self.solvent_content=100.*(self.mask_p1!=0).count(True)/self.mask_p1.size() if(log is not None): print("Solvent content: %7.3f"%self.solvent_content, file=log) # Connectivity co = maptbx.connectivity( - map_data = self.mask_p1, + map_data = self.mask_p1 * modifier, #!!!!!!!!!!!!!!!!!!! threshold = 0.01, preprocess_against_shallow = False, # XXX WHY False? wrapping = wrapping) From da8a430bbedc33279a91cb8f692265dce78bfb2b Mon Sep 17 00:00:00 2001 From: terwill Date: Fri, 26 Jan 2024 15:45:02 -0800 Subject: [PATCH 066/748] Add tool to find instances of pdb-specific coding --- libtbx/find_pdb_mmcif_problems.py | 224 ++++++++++++++++++++++++++++++ libtbx/utils.py | 68 +++++++++ 2 files changed, 292 insertions(+) create mode 100644 libtbx/find_pdb_mmcif_problems.py diff --git a/libtbx/find_pdb_mmcif_problems.py b/libtbx/find_pdb_mmcif_problems.py new file mode 100644 index 0000000000..45078ee3fe --- /dev/null +++ b/libtbx/find_pdb_mmcif_problems.py @@ -0,0 +1,224 @@ +from __future__ import absolute_import, division, print_function +import os, sys +from libtbx import group_args + +from libtbx.utils import display_context + + +''' Tool to find instances in code where PDB formatting is assumed and + should be made general to include PDB or mmcif formatting +''' + +# ============================================================================= +def find_pdb_mmcif_problems(path, n_context = 5): + + # Run recursively if a directory is supplied + if os.path.isdir(path): + print("Working recursively on the path '%s'" %(path)) + all_problems = [] + for fn in os.listdir(path): + if fn.startswith("."): continue + full_fn = os.path.join(path, fn) + if os.path.isdir(full_fn) or full_fn.endswith('.py'): + all_problems += find_pdb_mmcif_problems(full_fn, + n_context = n_context) + return all_problems + + if not os.path.isfile(path): + print("The path %s is not a file" %path) + return [] + if (not path.endswith('.py')): + print("The file %s is not a python file" %path) + return [] + + # Run on one file + all_problems = [] + text = open(path).read() + for problem in ( + pdb_write_statements, + pdb_format_interpretation, + raw_records, + pdb_file_name, + ): + all_problems += problem(text, header = path, n_context = n_context) + + return all_problems + +def run(args, n_context = 5): + if len(args) < 1: + print("phenix.python find_pdb_mmcif_problems.py ") + return + path = args[0] + if not os.path.exists(path): + print("The path '%s' does not exist?" %path) + return [] + + if len(args) > 1: + n_context = int(args[1]) + all_problems = find_pdb_mmcif_problems(path, n_context = n_context) + + # Summarize results + + all_headers = get_all_unique(all_problems, key = 'header') + all_categories = get_all_unique(all_problems, key = 'category') + all_search_words = get_all_unique(all_problems, key = 'search_word') + + print("All unique categories: ",all_categories) + print("All unique headers: ",all_headers) + print("All unique search words: ",all_search_words) + + print("\nAll problems:") + for header in all_headers: + print("\n"+70*"=") + print("FILE NAME: %s" %(header)) + print(70*"=") + problem_list = select_problems(all_problems, key = 'header', + value = header, n_context = n_context) + for p in problem_list: + display_problem(p) + + print("\nSummary of problems by file:") + for header in all_headers: + problem_list = select_problems(all_problems, key = 'header', + value = header, n_context = n_context) + total_problems = 0 + from six.moves import StringIO + f = StringIO() + for sw in all_search_words: + search_words = [sw] + p_list = select_problems(problem_list, key = 'search_word', + value = sw, n_context = 0) + if p_list: + for p in p_list: + if p.required_word and (not p.required_word in search_words): + search_words.append(p.required_word) + print(" TEXT FOUND: %s NUMBER OF TIMES: %s" %( + search_words, len(p_list)), file = f) + total_problems += len(p_list) + print("\n%s: %s problems" %(header,total_problems)) + print(f.getvalue()) + + print("\nSummary of problems by code:\n") + total_problems = 0 + for sw in all_search_words: + search_words = [sw] + p_list = select_problems(all_problems, key = 'search_word', + value = sw, n_context = 0) + if p_list: + for p in p_list: + if p.required_word and (not p.required_word in search_words): + search_words.append(p.required_word) + print(" TEXT FOUND: %s NUMBER OF TIMES: %s" %( + search_words, len(p_list))) + total_problems += len(p_list) + + print("\nTotal problems found in %s: %s" %(path,total_problems)) + + +def display_problem(p, out = sys.stdout): + print(70*"-", file = out) + sw = [p.search_word, p.required_word] + if None in sw: sw.remove(None) + print("Search words: %s \nExcluded words: %s\n" %( + sw, p.excluded_words, + ), file = out) + print("%s Line: %s" %(p.category, p.line_number), file = out) + print(p.text_block, file = out) + print(70*"-", file = out) + +def select_problems(all_problems, key = 'header', value = None, + n_context = 5): + new_problems = [] + for p in all_problems: + if getattr(p,key,None) == value: + new_problems.append(p) + new_problems = sorted(new_problems, key = lambda p: p.line_number) + sieved_problems = [] + last_line_number = None + for p in new_problems: + if (last_line_number is None) or ( + p.line_number >= last_line_number + n_context - 1): + sieved_problems.append(p) + last_line_number = p.line_number + return sieved_problems + +def get_all_unique(all_problems, key = 'header'): + all_unique = [] + for p in all_problems: + x = getattr(p,key,None) + if (x is not None) and not x in all_unique: + all_unique.append(x) + return all_unique + +def pdb_write_statements(text, header = None, n_context = 5): + all_problems = [] + for search_word in [".model_as_pdb(", ".as_pdb_string(", + ".write_model_file("]: + all_problems += display_context(header = header, text = text, + n_context = n_context, search_word = search_word,quiet = True, + category = 'pdb_write_statements') + return all_problems + +def pdb_format_interpretation(text, header = None, n_context = 5): + all_problems = [] + for search_word in ['.open(']: + for required_word in ['.pdb','pdb_file','model_file']: + all_problems += display_context(header = header, text = text, + n_context = n_context, + search_word = search_word, + required_word=required_word, + excluded_words=['transfer_ext','forward_compatible','iotbx.pdb'], + quiet = True, + category = 'pdb_format_interpretation') + all_problems += display_context(header = header, text = text, + n_context = n_context, + search_word = ".splitlines(", + required_word=" in ", + excluded_words=["cmds.","iotbx.pdb"], # if this is present, it is ok + quiet = True, + category = 'pdb_format_interpretation') + for search_word in ['HETATM','ATOM','TER','BREAK',' CA ',' N ']: + for required_word in ['startswith','find(']: + all_problems += display_context(header = header, text = text, + n_context = n_context, + search_word = search_word, + required_word=required_word, + quiet = True, + category = 'pdb_format_interpretation') + return all_problems + +def raw_records(text, header = None, n_context = 5): + all_problems = [] + for search_word in ['raw_records=','lines=','raw_records =','lines =']: + for required_word in ['.pdb','open(']: + all_problems += display_context(header = header, text = text, + n_context = n_context, + search_word = search_word, + required_word=required_word, + excluded_words=['pdb.input','iotbx.pdb','input.pdb'], + quiet = True, + category = 'pdb_format_interpretation') + return all_problems + +def pdb_file_name(text, header = None, n_context = 5): + all_problems = [] + for search_word in ['file_name',' fn ',' fn=','filename']: + for required_word in ['.pdb']: + all_problems += display_context(header = header, text = text, + n_context = n_context, + search_word = search_word, + required_word=required_word, + excluded_words = ['.pdb_or_mmcif_string_info', + 'pdb.input','iotbx.pdb','.cif','input.pdb'], + quiet = True, + category = 'pdb_format_interpretation') + return all_problems + + +# ============================================================================= +if __name__ == '__main__': + import sys + run(sys.argv[1:]) + +# ============================================================================= +# end diff --git a/libtbx/utils.py b/libtbx/utils.py index bf72fe5c6c..bd126cd60c 100644 --- a/libtbx/utils.py +++ b/libtbx/utils.py @@ -2525,6 +2525,74 @@ def check_git_lfs_pointer_is_loaded(path): """%path) return not test +def display_context(text, header = 'Supplied text', n_context = 5, + search_word = None, required_word= None, + excluded_words = None, category = None, + quiet = None, + always_excluded_words = ['DEBUG', 'PDB OK']): + ''' Search lines in text for search_word and select blocks of size + n_context on either side. If context_word appears, mark that line + + params: text: block of text + params: n_context: number of lines on either side of search word to keep + params: search_word: word to find + params: required_word: another word to find (must have both in block + if required_word is set) + params: excluded_words: if any are present in text_block, skip it + params: category: category to pass on in group_args + params: header: header (title or name of file) to pass on in group_args + params: always_excluded_words: add to excluded words + ''' + + text_block_list = [] + from libtbx import group_args + lines = text.splitlines() + if not quiet: + print("\n"+79*"=") + print( + "Searching %s with Search word: %s Required word: %s Excluded word: %s" %( + header, search_word, required_word, excluded_words)) + print("\n"+79*"=") + + + if not excluded_words: excluded_words = [] + for i in range(len(lines)): + if lines[i].find(search_word)>-1: + text_block = "" + first_line_number = max(0,i-n_context) + last_line_number = min(len(lines), i+n_context+1) + for ll in lines[first_line_number: last_line_number]: + if ll.find(search_word)> -1: + text_block += " ** %s\n" %(ll) + else: + text_block += " %s\n" %(ll) + skip = False + for x in excluded_words + always_excluded_words: + if text_block.find(x) > -1: + skip = True + if skip: + continue + if required_word and (text_block.find(required_word) < 0): + continue + + if not quiet: + print("\n%s at line %s. Search word: %s Required word: %s" %( + header, first_line_number+1, search_word, required_word)) + print(text_block) + info = group_args(group_args_type = 'text block', + category = category, + header = header, + search_word = search_word, + required_word = required_word, + excluded_words = excluded_words, + always_excluded_words = always_excluded_words, + text_block = text_block, + line_number = i+1, + ) + text_block_list.append(info) + return text_block_list + + class timer: ''' Context manager for timing blocks of code From 5b906ebe4d16b709c5d2ba755382b1db43a21e2e Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Thu, 25 Jan 2024 14:47:46 -0800 Subject: [PATCH 067/748] Fix new SyntaxWarnings from Python 3.12 --- .../command_line/find_reticular_twin_laws.py | 2 +- gltbx/util.py | 2 +- iotbx/command_line/explore_metric_symmetry.py | 4 +- iotbx/logfiles.py | 8 ++-- iotbx/pdb/utils.py | 4 +- .../ncs/tst_ncs_groups_preprocessing.py | 2 +- libtbx/auto_build/bootstrap.py | 4 +- libtbx/auto_build/install_base_packages.py | 2 +- libtbx/fastentrypoints.py | 4 +- libtbx/file_clutter.py | 6 +-- .../processing/polling.py | 2 +- mmtbx/command_line/show_r_factors_by_shell.py | 2 +- mmtbx/pdb_distances.py | 40 +++++++++---------- prime/postrefine/mod_gui_frames.py | 2 +- scitbx/math/fliege_mayer_900_ylm.py | 2 +- wxtbx/info_panels.py | 4 +- wxtbx/phil_controls/choice.py | 2 +- xfel/command_line/cxi_stream_to_pickle.py | 16 ++++---- xfel/command_line/detector_residuals.py | 16 ++++---- xfel/command_line/experiment_residuals.py | 2 +- xfel/cxi/cspad_ana/mod_filter.py | 4 +- xfel/cxi/cxi_cc.py | 2 +- .../intensity_resolution_statistics_cxi.py | 2 +- xfel/metrology/flatfile.py | 8 ++-- xfel/ui/components/xfel_gui_plotter.py | 6 +-- xfel/ui/db/merging_log_scraper.py | 4 +- 26 files changed, 76 insertions(+), 76 deletions(-) diff --git a/cctbx/command_line/find_reticular_twin_laws.py b/cctbx/command_line/find_reticular_twin_laws.py index 40798b1c05..2c5ee3f253 100644 --- a/cctbx/command_line/find_reticular_twin_laws.py +++ b/cctbx/command_line/find_reticular_twin_laws.py @@ -39,7 +39,7 @@ def run(args, command_name="phenix.find_reticular_twin_laws"): Reticular twin laws are grouped by their associated sublattice. - The matrix M acting on the input (base) lattice is listed, as well as the metric R value (\%) + The matrix M acting on the input (base) lattice is listed, as well as the metric R value (%) between the symmetrized sublattice and the unsymmetrized sublattice. reticular twin laws of twin index 1, are 'normal' twin laws diff --git a/gltbx/util.py b/gltbx/util.py index fbad71ba9c..e86ec44784 100644 --- a/gltbx/util.py +++ b/gltbx/util.py @@ -58,7 +58,7 @@ def __init__(self): import re self.__dict__ = self._shared_state if not self._shared_state: - vers_pat = re.compile("^((\d+)\.(\d+))(?:\.(\d+))?(?: (.*))?$") + vers_pat = re.compile(r"^((\d+)\.(\d+))(?:\.(\d+))?(?: (.*))?$") m = vers_pat.search(gl.glGetString(gl.GL_VERSION)) self.__dict__.update(dict(zip( ["principal", "major_number", "minor_number", "release_number", diff --git a/iotbx/command_line/explore_metric_symmetry.py b/iotbx/command_line/explore_metric_symmetry.py index 26a918ee9c..ab55600d67 100644 --- a/iotbx/command_line/explore_metric_symmetry.py +++ b/iotbx/command_line/explore_metric_symmetry.py @@ -336,9 +336,9 @@ def run(args, command_name="phenix.explore_metric_symmetry"): print("===================================================================", file=log) print("Niggli cell is expanded using matrix:", file=log) print(file=log) - print(" /%4i %4i %4i \ "%(mat[0][0],mat[0][1],mat[0][2]), file=log) + print(r" /%4i %4i %4i \ "%(mat[0][0],mat[0][1],mat[0][2]), file=log) print(" M = |%4i %4i %4i | "%(mat[1][0],mat[1][1],mat[1][2]), file=log) - print(" \%4i %4i %4i / "%(mat[2][0],mat[2][1],mat[2][2]), file=log) + print(r" \%4i %4i %4i / "%(mat[2][0],mat[2][1],mat[2][2]), file=log) print(file=log) print("Change of basis operator to reference setting:", file=log) print(" ", cb_op.as_xyz(), file=log) diff --git a/iotbx/logfiles.py b/iotbx/logfiles.py index e08eb118e8..0c96edc788 100644 --- a/iotbx/logfiles.py +++ b/iotbx/logfiles.py @@ -1,7 +1,7 @@ from __future__ import absolute_import, division, print_function -import cStringIO import sys, os, re +from six.moves import cStringIO as StringIO from six.moves import zip def check_bin_format(bin): @@ -16,7 +16,7 @@ def float_or_none(n): def percent_to_float(value): assert value.endswith("%") - return float(re.sub("\%$", "", value)) + return float(re.sub(r"\%$", "", value)) class experiment_info(object): def extract_all_stats(self): @@ -174,7 +174,7 @@ def format(obj, attr, fs="%.4f"): wavelength = getattr(i, "wavelength", None) synchrotron = "NULL" if (wavelength is not None): - out = cStringIO.StringIO() + out = StringIO() if (not approx_equal(wavelength, 1.5418, eps=0.01, out=out) and not approx_equal(wavelength, 0.7107, eps=0.01, out=out)): synchrotron = "Y" @@ -471,7 +471,7 @@ def parse_xscale(lines): elif (fields[0] == "total"): overall = fields break - elif re.match("^\d", line): + elif re.match(r"^\d", line): bins.append(fields) j += 1 assert (len(bins) > 0) and (len(overall) == len(bins[0])) diff --git a/iotbx/pdb/utils.py b/iotbx/pdb/utils.py index b8a055ee30..f058814513 100644 --- a/iotbx/pdb/utils.py +++ b/iotbx/pdb/utils.py @@ -4,7 +4,7 @@ from six.moves import range class generate_n_char_string: - """ Iterator to generate strings of length n_chars, using upper-case, + r""" Iterator to generate strings of length n_chars, using upper-case, lower-case and numbers as desired. Allows specialty sets of characters as well @@ -42,7 +42,7 @@ def __init__(self, n_chars = 1, all_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" all_chars_lc = all_chars.lower() all_numbers = '0123456789' - special_characters = """[]_,.;:"&<>()\/\{}'`~!@#$%*|+-""" + special_characters = r"""[]_,.;:"&<>()/\{}'`~!@#$%*|+-""" self._tilde = """~""" self._all_everything = "" diff --git a/iotbx/regression/ncs/tst_ncs_groups_preprocessing.py b/iotbx/regression/ncs/tst_ncs_groups_preprocessing.py index 17d05c5846..d5ecdbe842 100644 --- a/iotbx/regression/ncs/tst_ncs_groups_preprocessing.py +++ b/iotbx/regression/ncs/tst_ncs_groups_preprocessing.py @@ -406,7 +406,7 @@ def tearDown(self): ''' -test_ncs_spec = '''\ +test_ncs_spec = r'''\ Summary of NCS information Fri Jun 13 13:18:12 2014 diff --git a/libtbx/auto_build/bootstrap.py b/libtbx/auto_build/bootstrap.py index fc9ce3f3cc..aceb8bac3b 100644 --- a/libtbx/auto_build/bootstrap.py +++ b/libtbx/auto_build/bootstrap.py @@ -452,9 +452,9 @@ def set_git_repository_config_to_rebase(config): else: branch = False remote, rebase = False, False - if re.match('remote\s*=', line.strip()): + if re.match(r'remote\s*=', line.strip()): remote = True - if re.match('rebase\s*=', line.strip()): + if re.match(r'rebase\s*=', line.strip()): rebase = True if branch and remote and not rebase: insertions.insert(0, (n + 1, branch)) diff --git a/libtbx/auto_build/install_base_packages.py b/libtbx/auto_build/install_base_packages.py index 9b4aad928d..c11960aa40 100644 --- a/libtbx/auto_build/install_base_packages.py +++ b/libtbx/auto_build/install_base_packages.py @@ -837,7 +837,7 @@ def build_python(self): configure_args += ["--prefix", self.base_dir] if (self.options.python_shared): configure_args.append("--enable-shared") - configure_args.append("LDFLAGS=-Wl,-rpath=\$$ORIGIN/../lib") + configure_args.append("LDFLAGS=-Wl,-rpath=$ORIGIN/../lib") # patch Modules/Setup.dist to find custom OpenSSL targets = ['#SSL=/usr/local/ssl', diff --git a/libtbx/fastentrypoints.py b/libtbx/fastentrypoints.py index 545ff0ad34..20e95f8c71 100644 --- a/libtbx/fastentrypoints.py +++ b/libtbx/fastentrypoints.py @@ -40,7 +40,7 @@ ''' from setuptools.command import easy_install import re -TEMPLATE = '''\ +TEMPLATE = r'''\ # -*- coding: utf-8 -*- # EASY-INSTALL-ENTRY-SCRIPT: '{3}','{4}','{5}' __requires__ = '{3}' @@ -89,7 +89,7 @@ def main(): import shutil import sys dests = sys.argv[1:] or ['.'] - filename = re.sub('\.pyc$', '.py', __file__) + filename = re.sub(r'\.pyc$', '.py', __file__) for dst in dests: shutil.copy(filename, dst) diff --git a/libtbx/file_clutter.py b/libtbx/file_clutter.py index 81b744bc6c..dd93cd7499 100644 --- a/libtbx/file_clutter.py +++ b/libtbx/file_clutter.py @@ -9,11 +9,11 @@ class file_clutter(object): from_future_pat = re.compile( '^ from [ ]+ __future__ ', re.VERBOSE) from_future_import_division_pat = re.compile( - '^ from [ ]+ __future__ [ ]+ import [ \w,]+ division', re.VERBOSE) + r'^ from [ ]+ __future__ [ ]+ import [ \w,]+ division', re.VERBOSE) from_future_import_absolute_import_pat = re.compile( - '^ from [ ]+ __future__ [ ]+ import [ \w,]+ absolute_import', re.VERBOSE) + r'^ from [ ]+ __future__ [ ]+ import [ \w,]+ absolute_import', re.VERBOSE) from_future_import_print_function_pat = re.compile( - '^ from [ ]+ __future__ [ ]+ import [ \w,]+ print_function', re.VERBOSE) + r'^ from [ ]+ __future__ [ ]+ import [ \w,]+ print_function', re.VERBOSE) def __init__(self, path, find_unused_imports=False, find_bad_indentation=True, flag_absolute_import=False, diff --git a/libtbx/queuing_system_utils/processing/polling.py b/libtbx/queuing_system_utils/processing/polling.py index a5802a6421..412afa43d6 100644 --- a/libtbx/queuing_system_utils/processing/polling.py +++ b/libtbx/queuing_system_utils/processing/polling.py @@ -279,7 +279,7 @@ def sge_xml_evaluate(out, running, completed): CONDOR_XML_OUTPUT_REGEX = util.get_lazy_initialized_regex( - pattern = "^.*?(?=<\?xml)", + pattern = r"^.*?(?=<\?xml)", flags = [ "DOTALL" ], ) diff --git a/mmtbx/command_line/show_r_factors_by_shell.py b/mmtbx/command_line/show_r_factors_by_shell.py index 7ed54231b8..9f5da75efa 100644 --- a/mmtbx/command_line/show_r_factors_by_shell.py +++ b/mmtbx/command_line/show_r_factors_by_shell.py @@ -103,7 +103,7 @@ def run(args, out=sys.stdout): f_calc = f_obs = r_free_flags = None for array in mtz_in.file_server.miller_arrays : labels = array.info().labels - first_label_non_anom = re.sub("\(.*", "", labels[0]) + first_label_non_anom = re.sub(r"\(.*", "", labels[0]) if ((labels[0] == params.f_obs_label) or (first_label_non_anom == params.f_obs_label)): f_obs = array diff --git a/mmtbx/pdb_distances.py b/mmtbx/pdb_distances.py index 2c5c67f4fe..b5fa3bb2eb 100644 --- a/mmtbx/pdb_distances.py +++ b/mmtbx/pdb_distances.py @@ -774,9 +774,9 @@ def CONVERT(list): # print "resid", resid, "list", list while count <= len(resid): if list[resid_count] != []: - m=re.search('\d+', list[resid_count]) + m=re.search(r'\d+', list[resid_count]) resid[resid_count] = m.group() - n=re.search('\w', list[resid_count + 1]) + n=re.search(r'\w', list[resid_count + 1]) resid[resid_count + 1] = n.group() count = count + 2 resid_count = resid_count + 2 @@ -813,14 +813,14 @@ def PYMOL_OUTPUT(list, h, pdb_file_main, From, file): if file[k] != []: for a in range (1, 3): if From == 'basepairs': - m=re.search('\d+', list[2 * a]) + m=re.search(r'\d+', list[2 * a]) resid = m.group() RESID = str(resid) line = [["color " + color + ", /" + pdb_file_main + "/*/*/" + RESID + '\n',"hide sticks, /" + pdb_file_main + "/*/*/" + RESID + '\n'],["color " + color + ", /" + pdb_file_main + "/*/*/" + RESID + '\n', "show sticks, /" + pdb_file_main + "/*/*/" + RESID + '\n']] for l in range (len(line[k])): file[k].write(line[k][l]) else: - m=re.search('\d+', list[2 * a]) + m=re.search(r'\d+', list[2 * a]) resid = m.group() RESID = str(resid) line = "color " + color + ", /" + pdb_file_main + "/*/*/" + RESID + '\n' @@ -1188,10 +1188,10 @@ def loop(MASTER_Basepairs_summary, control, loop_control, CUTOFF, positions): MH_yes = 'n' #Three-bond-basepairs for which only two bonds have been identified are prevented from entering the rest of the loop lines until MAX_CUTOFF_str[0:3] == CUTOFF_str[0:3] if len(MASTER_Basepairs_summary[i]) > 0: if ('no' in MASTER_Basepairs_summary[i][j]) and ('yes' not in MASTER_Basepairs_summary[i][j]) and MH_yes == 'y': - m=re.search('\d+', MASTER_Basepairs_summary[i][j][2]) + m=re.search(r'\d+', MASTER_Basepairs_summary[i][j][2]) search1 = m.group() SEARCH1 = to_int(search1) #convert string to integers - m=re.search('\d+', MASTER_Basepairs_summary[i][j][4]) + m=re.search(r'\d+', MASTER_Basepairs_summary[i][j][4]) search2 = m.group() SEARCH2 = to_int(search2) #convert string to integers list = [MASTER_Basepairs_summary[i][j][2], MASTER_Basepairs_summary[i][j][3], MASTER_Basepairs_summary[i][j][4], MASTER_Basepairs_summary[i][j][5]] @@ -1496,13 +1496,13 @@ def program(First_List, MASTER_Basepairs_summary, CUTOFF, pdb_file_main, control #Detection of lines carrying consecutive bases. These should be not allowed to enter the assignment section, as they can give rise to FALSE basepairs resid = [[],[]] atom = [[],[],[]] - m=re.search('\d+', MASTER_Basepairs[i][j][0]) + m=re.search(r'\d+', MASTER_Basepairs[i][j][0]) resid[0] = int(m.group()) - m=re.search('\d+', MASTER_Basepairs[i][j][3]) + m=re.search(r'\d+', MASTER_Basepairs[i][j][3]) resid[1] = int(m.group()) - m=re.search('\S+', MASTER_Basepairs[i][j][2]) + m=re.search(r'\S+', MASTER_Basepairs[i][j][2]) atom[0] = str(m.group()) - m=re.search('\S+', MASTER_Basepairs[i][j][5]) + m=re.search(r'\S+', MASTER_Basepairs[i][j][5]) atom[1] = str(m.group()) atom[2] = MASTER_Basepairs[i][j][6] if (resid[1] - resid[0] > 1) or (resid[1] - resid[0] < -1): @@ -1820,9 +1820,9 @@ def HELICITY(LIST, a0, a1, a2, a3, where_from): match_position = [] for r in range (len(LIST)): for s in range (len(LIST[r])): - m=re.search('\d+', LIST[r][s][2]) + m=re.search(r'\d+', LIST[r][s][2]) match1 = m.group() - m=re.search('\d+', LIST[r][s][4]) + m=re.search(r'\d+', LIST[r][s][4]) match2 = m.group() # print "LIST[r][s]", LIST[r][s], "\n match1", match1, "match2", match2, "a0", a0, "a1", a1, "a2", a2, "a3", a3 if (('Loop' in where_from) and ('REMOVED' not in LIST[r][s]) and ('yes' in LIST[r][s]) and ((match1 in a0) and (match2 in a1) or (match2 in a0) and (match1 in a1))): @@ -1876,7 +1876,7 @@ def HELICITY(LIST, a0, a1, a2, a3, where_from): import os dir = os.getcwd() import re -ma=re.compile('\/+') +ma=re.compile(r'\/+') iterator = ma.finditer(dir) aaa=[] for match in iterator: @@ -1985,10 +1985,10 @@ def HELICITY(LIST, a0, a1, a2, a3, where_from): #Called below def CONTINUITY_HELICITY_CRITERION(MASTER_Basepairs_summary_line, MASTER_Basepairs_summary, CUTOFF): - m=re.search('\d+', MASTER_Basepairs_summary_line[2]) + m=re.search(r'\d+', MASTER_Basepairs_summary_line[2]) search1 = m.group() SEARCH1 = to_int(search1) #convert string to integers - m=re.search('\d+', MASTER_Basepairs_summary_line[4]) + m=re.search(r'\d+', MASTER_Basepairs_summary_line[4]) search2 = m.group() SEARCH2 = to_int(search2) #convert string to integers list = [MASTER_Basepairs_summary_line[2], MASTER_Basepairs_summary_line[3], MASTER_Basepairs_summary_line[4], MASTER_Basepairs_summary_line[5]] @@ -2315,13 +2315,13 @@ def DECISSION(LIST1, LIST2, A0, A1, A2, A3, A4, A5, A6, A7, removed, undetermine if 'yes' in MASTER_Basepairs_summary[i][j]: if yes_count == 0: #Initializing 'min' and 'max' count = 1 - m=re.search('\d+', MASTER_Basepairs_summary[i][j][2]) + m=re.search(r'\d+', MASTER_Basepairs_summary[i][j][2]) search1 = m.group() compare_to = to_int(search1) max = [compare_to, i, j] yes_count = 1 else: - m=re.search('\d+', MASTER_Basepairs_summary[i][j][2]) + m=re.search(r'\d+', MASTER_Basepairs_summary[i][j][2]) search1 = m.group() transient = to_int(search1) if transient >= max[0]: @@ -2889,7 +2889,7 @@ def DIFF_CALC(ARR1, ARR2, LIST1, LIST2): geometry_counter_real = 0 #Will count only non-FALSE, non-UNDETERMINED basepairs within 'new_list_end[b]' with 'MASTER_Basepairs_schemes[c]' geometry #TRUE BASEPAIRS for b in range (len(new_list_end)): - m=re.search('\S+', new_list_end[b][0]) + m=re.search(r'\S+', new_list_end[b][0]) scheme = str(m.group()) if MASTER_Basepairs_schemes[c] == scheme: geometry_counter = geometry_counter + 1 @@ -2976,9 +2976,9 @@ def DIFF_CALC(ARR1, ARR2, LIST1, LIST2): processed_control.append(control[i][j]) for u in range (len(processed_control)): #To format the 2 strings for the current basepair, resid and resid #, into residresid # if u%2 == 0: - search = '\d+' + search = r'\d+' else: - search = '\w+' + search = r'\w+' formatted = SEARCH(processed_control[u], search) list.append(formatted) for v in range (len(list)/2): diff --git a/prime/postrefine/mod_gui_frames.py b/prime/postrefine/mod_gui_frames.py index ca2b092eb2..f22aef9dd4 100644 --- a/prime/postrefine/mod_gui_frames.py +++ b/prime/postrefine/mod_gui_frames.py @@ -747,7 +747,7 @@ def draw_axes(self): self.bcomp_axes.set_xticklabels([]) self.bmult_axes.yaxis.get_major_ticks()[0].label1.set_visible(False) self.bmult_axes.yaxis.get_major_ticks()[-1].label1.set_visible(False) - self.bmult_axes.set_xlabel("Resolution ($\AA$)") + self.bmult_axes.set_xlabel(r"Resolution ($\AA$)") self.bmult_axes.set_ylabel("# of Obs") def draw_plots(self, info, total_cycles): diff --git a/scitbx/math/fliege_mayer_900_ylm.py b/scitbx/math/fliege_mayer_900_ylm.py index 8c93b6f191..3a9706bf25 100644 --- a/scitbx/math/fliege_mayer_900_ylm.py +++ b/scitbx/math/fliege_mayer_900_ylm.py @@ -1,4 +1,4 @@ -""" +r""" Listed below are weights needed to computed the following integral diff --git a/wxtbx/info_panels.py b/wxtbx/info_panels.py index 974e914b73..3f1445d232 100644 --- a/wxtbx/info_panels.py +++ b/wxtbx/info_panels.py @@ -205,7 +205,7 @@ def set_file(self, file_name): str_value = to_str(value) alert = False if (str_value.endswith("***")): - str_value = re.sub("\s*\*\*\*", "", str_value) + str_value = re.sub(r"\s*\*\*\*", "", str_value) alert = True txt2 = wx.StaticText(self.info_panel, -1, str_value) font2 = txt2.GetFont() @@ -415,7 +415,7 @@ def set_map_coeffs(self, array): str_value = to_str(value) alert = False if (str_value.endswith("***")): - str_value = re.sub("\s*\*\*\*", "", str_value) + str_value = re.sub(r"\s*\*\*\*", "", str_value) alert = True txt2 = wx.StaticText(self.info_panel, -1, str_value) font2 = txt2.GetFont() diff --git a/wxtbx/phil_controls/choice.py b/wxtbx/phil_controls/choice.py index b44ddb792b..30049a20a5 100644 --- a/wxtbx/phil_controls/choice.py +++ b/wxtbx/phil_controls/choice.py @@ -15,7 +15,7 @@ def SetChoices(self, choices, captions=None, allow_none=True): is_selected = [ ("*" in choice) for choice in choices ] if (True in is_selected): selection = is_selected.index(True) - choices = [ re.sub("\*", "", choice) for choice in choices ] + choices = [ re.sub(r"\*", "", choice) for choice in choices ] if (captions is None): captions = list(choices) # XXX force copy if (len(captions) != len(choices)): diff --git a/xfel/command_line/cxi_stream_to_pickle.py b/xfel/command_line/cxi_stream_to_pickle.py index ad5a8d7709..e655afc7de 100644 --- a/xfel/command_line/cxi_stream_to_pickle.py +++ b/xfel/command_line/cxi_stream_to_pickle.py @@ -20,8 +20,8 @@ EV_PER_A = 12398.4187 # Regular expressions, set up so one can use groups to extract the data -re_energy = re.compile("photon_energy_eV\s=\s([0-9]+\.[0-9]+)") -re_uc = re.compile("""Cell\sparameters\s +re_energy = re.compile(r"photon_energy_eV\s=\s([0-9]+\.[0-9]+)") +re_uc = re.compile(r"""Cell\sparameters\s ([0-9]+\.[0-9]+)\s # a ([0-9]+\.[0-9]+)\s # b ([0-9]+\.[0-9]+)\snm,\s # c @@ -30,7 +30,7 @@ ([0-9]+\.[0-9]+) # gamma""", re.X) # groups 1-7: h,k,l,I,sig(i),peak, background,fs,ss -re_miller = re.compile("""\s*(-?[0-9]{1,3}) +re_miller = re.compile(r"""\s*(-?[0-9]{1,3}) \s*(-?[0-9]{1,3}) \s*(-?[0-9]{1,3}) #h,k,l \s*(-?[0-9]+\.[0-9]+) @@ -38,17 +38,17 @@ ([\s*-?[0-9]+\.[0-9]+){2} #Peak, background \s*([0-9]+\.[0-9]+) \s*([0-9]+\.[0-9]+) #fs, ssi""", re.X) -re_lattice_type = re.compile("lattice_type\s=\s([a-zA-Z]+)") -re_centering = re.compile("centering\s=\s([A-Z])") +re_lattice_type = re.compile(r"lattice_type\s=\s([a-zA-Z]+)") +re_centering = re.compile(r"centering\s=\s([A-Z])") # note the setting lattice is in nm^-1 -re_Astar = re.compile("""astar\s=\s*(-?\+?[0-9]+\.[0-9]+) +re_Astar = re.compile(r"""astar\s=\s*(-?\+?[0-9]+\.[0-9]+) \s*(-?\+?[0-9]+\.[0-9]+) \s*(-?\+?[0-9]+\.[0-9]+)""", re.X) -re_Bstar = re.compile("""bstar\s=\s*(-?\+?[0-9]+\.[0-9]+) +re_Bstar = re.compile(r"""bstar\s=\s*(-?\+?[0-9]+\.[0-9]+) \s*(-?\+?[0-9]+\.[0-9]+) \s*(-?\+?[0-9]+\.[0-9]+)""", re.X) -re_Cstar = re.compile("""cstar\s=\s*(-?\+?[0-9]+\.[0-9]+) +re_Cstar = re.compile(r"""cstar\s=\s*(-?\+?[0-9]+\.[0-9]+) \s*(-?\+?[0-9]+\.[0-9]+) \s*(-?\+?[0-9]+\.[0-9]+)""", re.X) diff --git a/xfel/command_line/detector_residuals.py b/xfel/command_line/detector_residuals.py index e192ccdc5f..6ed6152aee 100644 --- a/xfel/command_line/detector_residuals.py +++ b/xfel/command_line/detector_residuals.py @@ -1121,9 +1121,9 @@ def plot_all(self): ["XY", "radial", "transverse"]): fig = plt.figure() plt.hist2d(angle.as_numpy_array(), reflections[column_name].as_numpy_array() * 1000, bins=180, norm=LogNorm()) - plt.title("2d histogram of $\Delta$ %s vs azimuthal angle"%caption) + plt.title(r"2d histogram of $\Delta$ %s vs azimuthal angle"%caption) plt.xlabel("Azimuthal angle (deg)") - plt.ylabel("$\Delta$ %s ($\mu$m)"%caption) + plt.ylabel(r"$\Delta$ %s ($\mu$m)"%caption) plt.colorbar() if params.plots.intensity_vs_radials_2dhist and 'intensity.sum.value' in reflections: @@ -1263,9 +1263,9 @@ def plot_all(self): if expt_id == 0: fig = plt.figure() plt.scatter(two_thetas, offset) - plt.title(u"%d: Ewald offset ($\AA^{-1}$) vs $2\\theta$ on %d spots"%(expt_id, len(two_thetas))) - plt.xlabel(u"$2\\theta (\circ)$") - plt.ylabel(u"Ewald offset ($\AA^{-1}$)") + plt.title(r"%d: Ewald offset ($\AA^{-1}$) vs $2\theta$ on %d spots"%(expt_id, len(two_thetas))) + plt.xlabel(r"$2\theta (\circ)$") + plt.ylabel(r"Ewald offset ($\AA^{-1}$)") array = refls.as_miller_array(experiments[expt_id]) binner = array.setup_binner(d_min=2.0, n_bins=n_bins) @@ -1291,9 +1291,9 @@ def plot_all(self): print (bin_id, binner.bin_d_range(bin_number), sel.count(True), x[-1], y[-1]) plt.plot(x, y, '-') plt.legend(legend) - plt.title(u"Binned $I/\sigma_I$ vs. Ewald offset") - plt.xlabel(u"Ewald offset ($\AA^{-1}$)") - plt.ylabel(u"Median $I/\sigma_I$") + plt.title(r"Binned $I/\sigma_I$ vs. Ewald offset") + plt.xlabel(r"Ewald offset ($\AA^{-1}$)") + plt.ylabel(r"Median $I/\sigma_I$") plt.figure() plt.title('Ewald offsets vs. two theta') diff --git a/xfel/command_line/experiment_residuals.py b/xfel/command_line/experiment_residuals.py index 0256cd70ac..157e39a0d2 100644 --- a/xfel/command_line/experiment_residuals.py +++ b/xfel/command_line/experiment_residuals.py @@ -200,7 +200,7 @@ def run(self): cbar = plt.colorbar(scat, shrink=params.cbarshrink) - cbar.ax.set_title("$\Delta \psi$") + cbar.ax.set_title(r"$\Delta \psi$") ax.set_aspect("equal") ax.set_facecolor(params.axcol) title = "prediction offsets (arrow points to prediction)" diff --git a/xfel/cxi/cspad_ana/mod_filter.py b/xfel/cxi/cspad_ana/mod_filter.py index c18b788c62..6c5a46417d 100644 --- a/xfel/cxi/cspad_ana/mod_filter.py +++ b/xfel/cxi/cspad_ana/mod_filter.py @@ -49,8 +49,8 @@ def __init__( self.negate = cspad_tbx.getOptBool(negate) if (timestamps_path is not None): - p_old = re.compile("\d{4}-\d{2}-\d{2}T\d{2}:\d{2}Z\d{2}\.\d{3}") - p_new = re.compile("\d{17}") + p_old = re.compile(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}Z\d{2}\.\d{3}") + p_new = re.compile(r"\d{17}") f = open(timestamps_path, "r") self.timestamps_list = [] for line in f.readlines(): diff --git a/xfel/cxi/cxi_cc.py b/xfel/cxi/cxi_cc.py index 3067fa5212..234a25cef2 100644 --- a/xfel/cxi/cxi_cc.py +++ b/xfel/cxi/cxi_cc.py @@ -129,7 +129,7 @@ def split_sigma_test(self, other, scale, use_binning=False, show_plot=False): def r1_factor(self, other, scale_factor=None, assume_index_matching=False, use_binning=False): - """Get the R1 factor according to this formula + r"""Get the R1 factor according to this formula .. math:: R1 = \dfrac{\sum{||F| - k|F'||}}{\sum{|F|}} diff --git a/xfel/merging/application/statistics/intensity_resolution_statistics_cxi.py b/xfel/merging/application/statistics/intensity_resolution_statistics_cxi.py index b0aaed160d..72eb7673ba 100644 --- a/xfel/merging/application/statistics/intensity_resolution_statistics_cxi.py +++ b/xfel/merging/application/statistics/intensity_resolution_statistics_cxi.py @@ -347,7 +347,7 @@ def split_sigma_test(self, this, other, scale, use_binning=False, show_plot=Fals def r1_factor(self, this, other, scale_factor=None, assume_index_matching=False, use_binning=False): - """Get the R1 factor according to this formula + r"""Get the R1 factor according to this formula .. math:: R1 = \dfrac{\sum{||F| - k|F'||}}{\sum{|F|}} diff --git a/xfel/metrology/flatfile.py b/xfel/metrology/flatfile.py index 9508eb9ad5..ea035d40c9 100644 --- a/xfel/metrology/flatfile.py +++ b/xfel/metrology/flatfile.py @@ -1019,13 +1019,13 @@ def parse_metrology(path, detector = 'CxiDs1', plot = True, do_diffs = True, old # Continuation lines (i.e. backslash preceding a newline) are not # permitted. pattern_blank = \ - re.compile('^\s*(#.*)?$') + re.compile(r'^\s*(#.*)?$') pattern_quadrant = \ - re.compile('^\s*[Qq][Uu][Aa][Dd]\s+\d+\s*(#.*)?$') + re.compile(r'^\s*[Qq][Uu][Aa][Dd]\s+\d+\s*(#.*)?$') pattern_sensor = \ - re.compile('^\s*[Ss][Ee][Nn][Ss][Oo][Rr]\s+[Xx]\s+[Yy]\s+[Zz]\s*(#.*)?$') + re.compile(r'^\s*[Ss][Ee][Nn][Ss][Oo][Rr]\s+[Xx]\s+[Yy]\s+[Zz]\s*(#.*)?$') pattern_sxyz = \ - re.compile('^\s*\d+\s+[+-]?\d+\s+[+-]?\d+\s+[+-]?\d+\s*(#.*)?$') + re.compile(r'^\s*\d+\s+[+-]?\d+\s+[+-]?\d+\s+[+-]?\d+\s*(#.*)?$') # Parse the file into dict of dict of four-tuples, indexed by # quadrant indices and sensor indices, respectively. diff --git a/xfel/ui/components/xfel_gui_plotter.py b/xfel/ui/components/xfel_gui_plotter.py index 73fbc44298..1ce1faf915 100644 --- a/xfel/ui/components/xfel_gui_plotter.py +++ b/xfel/ui/components/xfel_gui_plotter.py @@ -390,11 +390,11 @@ def plot_uc_3Dplot(self, info, iqr_ratio = 1.5): b = b.select(accepted) c = c.select(accepted) - AA = "a-edge (%.2f +/- %.2f $\AA$)" % (flex.mean(a), + AA = r"a-edge (%.2f +/- %.2f $\AA$)" % (flex.mean(a), flex.mean_and_variance(a).unweighted_sample_standard_deviation()) - BB = "b-edge (%.2f +/- %.2f $\AA$)" % (flex.mean(b), + BB = r"b-edge (%.2f +/- %.2f $\AA$)" % (flex.mean(b), flex.mean_and_variance(b).unweighted_sample_standard_deviation()) - CC = "c-edge (%.2f +/- %.2f $\AA$)" % (flex.mean(c), + CC = r"c-edge (%.2f +/- %.2f $\AA$)" % (flex.mean(c), flex.mean_and_variance(c).unweighted_sample_standard_deviation()) diff --git a/xfel/ui/db/merging_log_scraper.py b/xfel/ui/db/merging_log_scraper.py index d18c62b15e..bdd3d47ea7 100644 --- a/xfel/ui/db/merging_log_scraper.py +++ b/xfel/ui/db/merging_log_scraper.py @@ -103,7 +103,7 @@ def resolution(x, pos): return "%.1f"%(1/math.sqrt(x)) formatter = FuncFormatter(resolution) ax1.xaxis.set_major_formatter(formatter) - ax1.set_xlabel(u'Resolution ${\AA}$') + ax1.set_xlabel(r'Resolution ${\AA}$') ax1.set_ylabel('%') ax2.set_ylabel('Multiplicity') handles, labels = ax1.get_legend_handles_labels() @@ -186,7 +186,7 @@ def plot_many_results(self, all_results, title, xsize=30, ysize=10, interactive ax2.set_xlabel("N images") ax1a.set_ylabel("Overall CC1/2 (%)") ax1b.set_ylabel("Overall multiplicity") - ax2.set_ylabel(u"Resolution ($\AA$") + ax2.set_ylabel(r"Resolution ($\AA$") ax1a.set_title(title) def resolution(y, pos): From a5eb5fc79251bfd01ffe2b396c1cf29565661201 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Fri, 26 Jan 2024 20:15:14 -0800 Subject: [PATCH 068/748] CI: Bump Xcode 15.0.1 to 15.2 [skip ci] --- .azure-pipelines/full-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.azure-pipelines/full-build.yml b/.azure-pipelines/full-build.yml index 70e1e34408..7378480452 100644 --- a/.azure-pipelines/full-build.yml +++ b/.azure-pipelines/full-build.yml @@ -63,6 +63,6 @@ jobs: - template: ./conda-osx.yml parameters: vmImage: [13] - xcode_version: [15, 0, 1] + xcode_version: [15, 2] modules: ${{ parameters.modules }} template: ./unix-conda-build.yml From a511a6cb4ab2dde0fa3528c54d315fd5edcf9f7b Mon Sep 17 00:00:00 2001 From: terwill Date: Sat, 27 Jan 2024 10:18:49 -0700 Subject: [PATCH 069/748] Add methods for finding code that may not deal with mmcif/pdb properly --- .../command_line/find_pdb_mmcif_problems.py | 387 ++++++++++++++++++ libtbx/find_pdb_mmcif_problems.py | 224 ---------- libtbx/utils.py | 32 +- 3 files changed, 408 insertions(+), 235 deletions(-) create mode 100644 libtbx/command_line/find_pdb_mmcif_problems.py delete mode 100644 libtbx/find_pdb_mmcif_problems.py diff --git a/libtbx/command_line/find_pdb_mmcif_problems.py b/libtbx/command_line/find_pdb_mmcif_problems.py new file mode 100644 index 0000000000..3fad22b8b2 --- /dev/null +++ b/libtbx/command_line/find_pdb_mmcif_problems.py @@ -0,0 +1,387 @@ +from __future__ import absolute_import, division, print_function +import os, sys +from libtbx import group_args + +from libtbx.utils import display_context + + +''' Tool to find instances in code where PDB formatting is assumed and + should be made general to include PDB or mmcif formatting +''' + +# ============================================================================= +def find_pdb_mmcif_problems(path, n_context = 7, overall_exclude = None, + mark_files = None, unmark_files = None): + + # Run on all paths supplied in file if a .list file is supplied + if os.path.isfile(path) and path.endswith(".list"): + print("Working on all paths listed in '%s'" %(path)) + all_problems = [] + total_files = 0 + for full_fn in open(path).readlines(): + full_fn = full_fn.strip() + print("Working on '%s'" %(full_fn)) + if os.path.isdir(full_fn) or full_fn.endswith('.py'): + problems, number_of_files_examined = find_pdb_mmcif_problems(full_fn, + n_context = n_context, overall_exclude = overall_exclude, + mark_files = mark_files, unmark_files = unmark_files) + all_problems += problems + total_files += number_of_files_examined + return all_problems, total_files + + # Run recursively if a directory is supplied + if os.path.isdir(path): + print("Working recursively on the path '%s'" %(path)) + all_problems = [] + total_files = 0 + for fn in os.listdir(path): + if fn.startswith("."): continue + if fn.startswith("tst_"): continue + full_fn = os.path.join(path, fn) + if os.path.isdir(full_fn) or full_fn.endswith('.py'): + problems, number_of_files_examined = find_pdb_mmcif_problems(full_fn, + n_context = n_context, overall_exclude = overall_exclude, + mark_files = mark_files, unmark_files = unmark_files) + all_problems += problems + total_files += number_of_files_examined + return all_problems, total_files + + # Normal run here on one file in path + + if not os.path.isfile(path): + print("The path %s is not a file" %path) + return [],0 + if (not path.endswith('.py')): + print("The file %s is not a python file" %path) + return [], 0 + if (os.path.split(path)[-1].startswith('tst_')): + print("The file %s is a test file" %path) + return [], 0 + + # Run on one file + all_problems = [] + text = open(path).read() + for problem in ( + write_model_file_without_assignment, + pdb_write_statements, + pdb_format_interpretation, + raw_records, + pdb_file_name, + ): + all_problems += problem(text, file_name = path, n_context = n_context, + overall_exclude = overall_exclude) + + if mark_files: # mark all problems in the files themselves + mark_problems_in_file(text,path, all_problems, n_context = n_context) + if unmark_files: # unmark all problems in the files + unmark_problems_in_file(text,path) + + return all_problems, 1 + +def unmark_problems_in_file(text,path): + if text.find(" # XXX CHECK PDB:") < 0: + return # nothing to do + + lines = text.splitlines() + for i in range(len(lines)): + line = lines[i] + index = line.find(" # XXX CHECK PDB:") + if index > -1: + lines[i] = line[:index] + f = open(path,'w') + print("\n".join(lines), file = f) + f.close() + print("Removed CHECK PDB text from %s" %(path)) + + +def mark_problems_in_file(text, path, all_problems, + n_context = 5): + if not all_problems: + return # nothing to do + lines = text.splitlines() + for p in all_problems: + sw = [p.search_word, p.required_word] + if None in sw: sw.remove(None) + line = lines[p.line_number-1].rstrip() + next_ending = None + for w in sw: + if line.find(w): + next_ending = w + break + if (not next_ending): + next_ending = " ".join(sw) + new_text = " # XXX CHECK PDB: %s" %(next_ending) + for i in range(p.line_number, p.line_number + n_context): + line = lines[i] + if (not line.endswith("\\")) and (not line.find("XXX CHECK PDB") > -1): + line = line.rstrip() + blanks = max(0, 80 - len(line) - len(new_text)) + if blanks > 0: + new_text = blanks *" " + new_text + line += new_text + lines[i] = line + break + f = open(path,'w') + print("\n".join(lines), file = f) + f.close() + print("Marked problems with CHECK PDB text in %s" %(path)) + +def run(args, n_context = 7, overall_exclude = None): + if len(args) < 1: + print("phenix.python find_pdb_mmcif_problems.py ") + return + + mark_files = False + unmark_files = False + if 'mark_files' in args: + args.remove('mark_files') + mark_files = True + if 'unmark_files' in args: + args.remove('unmark_files') + unmark_files = True + + path = args[0] + if not os.path.exists(path): + print("The path '%s' does not exist?" %path) + return [] + + if not overall_exclude: + overall_exclude = ['get_refine_file_stem', + 'DEBUG', # debugging code + 'PDB OK', # marked as ok + 'PDB REQUIRED', # marked as ok + 'must be PDB', # marked as ok + 'MUST BE PDB', # marked as ok + 'XXX OK', # marked as ok + 'XXX ok', # marked as ok + 'set_model_ext_and_target_output_format', # function to set the extension + 'forward_compatible', # using pdb deliberately + 'transfer_ext', # function to set the extension + 'get_cif_or_pdb_file_if_present', # function to set the extension + '.pdb_or_mmcif_string_info', # function to set the extension + 'mmcif', # the author has considered cif + '.cif', # the author has considered cif + 'write_model(', # the write_model function is cif-aware + '.type = ', # This is in parameters + ] + + if len(args) > 1: + n_context = int(args[1]) + print("Set n_context to ",n_context) + all_problems, total_files = find_pdb_mmcif_problems( + path, n_context = n_context, overall_exclude = overall_exclude, + mark_files = mark_files, unmark_files = unmark_files) + + # Summarize results + + all_file_names = get_all_unique(all_problems, key = 'file_name') + all_categories = get_all_unique(all_problems, key = 'category') + all_search_words = get_all_unique(all_problems, key = 'search_word') + + print("All unique categories: ",all_categories) + print("All unique file_names: ",all_file_names) + print("All unique search words: ",all_search_words) + + print("\nAll problems:") + for file_name in all_file_names: + print("\n"+70*"=") + print("FILE NAME: %s" %(file_name)) + print(70*"=") + problem_list = select_problems(all_problems, key = 'file_name', + value = file_name, n_context = n_context) + for p in problem_list: + display_problem(p) + + print("\nSummary of problems by file:") + for file_name in all_file_names: + problem_list = select_problems(all_problems, key = 'file_name', + value = file_name, n_context = n_context) + total_problems = 0 + from six.moves import StringIO + f = StringIO() + for sw in all_search_words: + search_words = [sw] + p_list = select_problems(problem_list, key = 'search_word', + value = sw, n_context = 0) + if p_list: + for p in p_list: + if p.required_word and (not p.required_word in search_words): + search_words.append(p.required_word) + print(" TEXT FOUND: %s NUMBER OF TIMES: %s" %( + search_words, len(p_list)), file = f) + total_problems += len(p_list) + print("\n%s: %s problems" %(file_name,total_problems)) + print(f.getvalue()) + total_files_with_problems = len(all_file_names) + print("\nTotal files with problems: %s (of %s)" %( + total_files_with_problems, total_files)) + + print("\nSummary of problems by code:\n") + total_problems = 0 + for sw in all_search_words: + search_words = [sw] + p_list = select_problems(all_problems, key = 'search_word', + value = sw, n_context = 0) + if p_list: + for p in p_list: + if p.required_word and (not p.required_word in search_words): + search_words.append(p.required_word) + print(" TEXT FOUND: %s NUMBER OF TIMES: %s" %( + search_words, len(p_list))) + total_problems += len(p_list) + + print("\nTotal problems found in %s: %s" %(path,total_problems)) + + +def display_problem(p, out = sys.stdout): + print("%s Line: %s\n" %(p.file_name,p.line_number)+ 70*"-", file = out) + sw = [p.search_word, p.required_word] + if None in sw: sw.remove(None) + next_ending = None + for line in p.text_block.splitlines(): + line = line.rstrip() + if line.startswith(" **"): + for w in sw: + if line.find(w): + next_ending = w + break + if (not next_ending): + next_ending = " ".join(sw) + if next_ending and (not line.endswith("\\")): + line = line.rstrip() + new_text = " # XXX CHECK PDB: %s" %(next_ending) + blanks = max(0, 80 - len(line) - len(new_text)) + if blanks > 0: + new_text = blanks *" " + new_text + line += new_text + next_ending = None + print(line, file = out) + print(70*"-", file = out) + +def select_problems(all_problems, key = 'file_name', value = None, + n_context = 7): + new_problems = [] + for p in all_problems: + if getattr(p,key,None) == value: + new_problems.append(p) + new_problems = sorted(new_problems, key = lambda p: p.line_number) + sieved_problems = [] + last_line_number = None + for p in new_problems: + if (last_line_number is None) or ( + p.line_number >= last_line_number + n_context - 1): + sieved_problems.append(p) + last_line_number = p.line_number + return sieved_problems + +def get_all_unique(all_problems, key = 'file_name'): + all_unique = [] + for p in all_problems: + x = getattr(p,key,None) + if (x is not None) and not x in all_unique: + all_unique.append(x) + return all_unique + +def write_model_file_without_assignment(text, file_name = None, n_context = 7, + overall_exclude = None): + all_problems = [] + for search_word in [ "dm.write_model_file(", + "data_manager.write_model_file(", ]: + all_problems += display_context(file_name = file_name, text = text, + n_context = n_context, search_word = search_word,quiet = True, + excluded_words = [ + '=dm.write_model_file', + '= dm.write_model_file', + '=data_manager.write_model_file', + '= data_manager.write_model_file', + '=self.dm.write_model_file', + '= self.dm.write_model_file', + '=self.data_manager.write_model_file', + '= self.data_manager.write_model_file', + ] + overall_exclude, + category = 'write_model_file_without_assignment') + return all_problems + +def pdb_write_statements(text, file_name = None, n_context = 7, + overall_exclude = None): + all_problems = [] + for search_word in [".model_as_pdb(", ".as_pdb_string(", + ".write_pdb_file("]: + all_problems += display_context(file_name = file_name, text = text, + n_context = n_context, search_word = search_word,quiet = True, + excluded_words = overall_exclude, + category = 'pdb_write_statements') + return all_problems + +def pdb_format_interpretation(text, file_name = None, n_context = 7, + overall_exclude = None): + all_problems = [] + for search_word in ['.open(']: + for required_word in ['.pdb"',".pdb'",'pdb_file','model_file']: + all_problems += display_context(file_name = file_name, text = text, + n_context = n_context, + search_word = search_word, + required_word=required_word, + excluded_words= overall_exclude, + quiet = True, + category = 'pdb_format_interpretation') + all_problems += display_context(file_name = file_name, text = text, + n_context = n_context, + search_word = ".splitlines(", + required_word="pdb", + excluded_words=["cmds.","iotbx.pdb", + 'pdb_interpretation.process', + 'traceback','phil_string',] + overall_exclude, + quiet = True, + category = 'pdb_format_interpretation') + for search_word in ['HETATM','ATOM','TER','BREAK',' CA ',' N ']: + for required_word in ['startswith','find(','re.search(']: + all_problems += display_context(file_name = file_name, text = text, + n_context = n_context, + search_word = search_word, + required_word=required_word, + quiet = True, + category = 'pdb_format_interpretation') + return all_problems + +def raw_records(text, file_name = None, n_context = 7, overall_exclude = None): + all_problems = [] + for search_word in ['raw_records=','raw_records =']: + for required_word in ['pdb']: + all_problems += display_context(file_name = file_name, text = text, + n_context = n_context, + search_word = search_word, + required_word=required_word, + excluded_words=['pdb.input','iotbx.pdb','input.pdb', + '.pdb_or_mmcif_string_info','get_cif_or_pdb_file_if_present' + 'pdb_interpretation.process'] + + overall_exclude, + quiet = True, + category = 'raw_records') + return all_problems + +def pdb_file_name(text, file_name = None, + n_context = 7, overall_exclude = None): + all_problems = [] + for search_word in ['file_name',' fn=',' fn = ','filename']: + for required_word in ['.pdb"',".pdb'"]: + all_problems += display_context(file_name = file_name, text = text, + n_context = n_context, + search_word = search_word, + required_word=required_word, + excluded_words = ['.pdb_or_mmcif_string_info', + 'get_cif_or_pdb_file_if_present','write_model', + 'pdb.input','iotbx.pdb','.cif','input.pdb', + 'map_file_name','restraint_file',] + overall_exclude, + quiet = True, + category = 'pdb_file_name') + return all_problems + + +# ============================================================================= +if __name__ == '__main__': + import sys + run(sys.argv[1:]) + +# ============================================================================= +# end diff --git a/libtbx/find_pdb_mmcif_problems.py b/libtbx/find_pdb_mmcif_problems.py deleted file mode 100644 index 45078ee3fe..0000000000 --- a/libtbx/find_pdb_mmcif_problems.py +++ /dev/null @@ -1,224 +0,0 @@ -from __future__ import absolute_import, division, print_function -import os, sys -from libtbx import group_args - -from libtbx.utils import display_context - - -''' Tool to find instances in code where PDB formatting is assumed and - should be made general to include PDB or mmcif formatting -''' - -# ============================================================================= -def find_pdb_mmcif_problems(path, n_context = 5): - - # Run recursively if a directory is supplied - if os.path.isdir(path): - print("Working recursively on the path '%s'" %(path)) - all_problems = [] - for fn in os.listdir(path): - if fn.startswith("."): continue - full_fn = os.path.join(path, fn) - if os.path.isdir(full_fn) or full_fn.endswith('.py'): - all_problems += find_pdb_mmcif_problems(full_fn, - n_context = n_context) - return all_problems - - if not os.path.isfile(path): - print("The path %s is not a file" %path) - return [] - if (not path.endswith('.py')): - print("The file %s is not a python file" %path) - return [] - - # Run on one file - all_problems = [] - text = open(path).read() - for problem in ( - pdb_write_statements, - pdb_format_interpretation, - raw_records, - pdb_file_name, - ): - all_problems += problem(text, header = path, n_context = n_context) - - return all_problems - -def run(args, n_context = 5): - if len(args) < 1: - print("phenix.python find_pdb_mmcif_problems.py ") - return - path = args[0] - if not os.path.exists(path): - print("The path '%s' does not exist?" %path) - return [] - - if len(args) > 1: - n_context = int(args[1]) - all_problems = find_pdb_mmcif_problems(path, n_context = n_context) - - # Summarize results - - all_headers = get_all_unique(all_problems, key = 'header') - all_categories = get_all_unique(all_problems, key = 'category') - all_search_words = get_all_unique(all_problems, key = 'search_word') - - print("All unique categories: ",all_categories) - print("All unique headers: ",all_headers) - print("All unique search words: ",all_search_words) - - print("\nAll problems:") - for header in all_headers: - print("\n"+70*"=") - print("FILE NAME: %s" %(header)) - print(70*"=") - problem_list = select_problems(all_problems, key = 'header', - value = header, n_context = n_context) - for p in problem_list: - display_problem(p) - - print("\nSummary of problems by file:") - for header in all_headers: - problem_list = select_problems(all_problems, key = 'header', - value = header, n_context = n_context) - total_problems = 0 - from six.moves import StringIO - f = StringIO() - for sw in all_search_words: - search_words = [sw] - p_list = select_problems(problem_list, key = 'search_word', - value = sw, n_context = 0) - if p_list: - for p in p_list: - if p.required_word and (not p.required_word in search_words): - search_words.append(p.required_word) - print(" TEXT FOUND: %s NUMBER OF TIMES: %s" %( - search_words, len(p_list)), file = f) - total_problems += len(p_list) - print("\n%s: %s problems" %(header,total_problems)) - print(f.getvalue()) - - print("\nSummary of problems by code:\n") - total_problems = 0 - for sw in all_search_words: - search_words = [sw] - p_list = select_problems(all_problems, key = 'search_word', - value = sw, n_context = 0) - if p_list: - for p in p_list: - if p.required_word and (not p.required_word in search_words): - search_words.append(p.required_word) - print(" TEXT FOUND: %s NUMBER OF TIMES: %s" %( - search_words, len(p_list))) - total_problems += len(p_list) - - print("\nTotal problems found in %s: %s" %(path,total_problems)) - - -def display_problem(p, out = sys.stdout): - print(70*"-", file = out) - sw = [p.search_word, p.required_word] - if None in sw: sw.remove(None) - print("Search words: %s \nExcluded words: %s\n" %( - sw, p.excluded_words, - ), file = out) - print("%s Line: %s" %(p.category, p.line_number), file = out) - print(p.text_block, file = out) - print(70*"-", file = out) - -def select_problems(all_problems, key = 'header', value = None, - n_context = 5): - new_problems = [] - for p in all_problems: - if getattr(p,key,None) == value: - new_problems.append(p) - new_problems = sorted(new_problems, key = lambda p: p.line_number) - sieved_problems = [] - last_line_number = None - for p in new_problems: - if (last_line_number is None) or ( - p.line_number >= last_line_number + n_context - 1): - sieved_problems.append(p) - last_line_number = p.line_number - return sieved_problems - -def get_all_unique(all_problems, key = 'header'): - all_unique = [] - for p in all_problems: - x = getattr(p,key,None) - if (x is not None) and not x in all_unique: - all_unique.append(x) - return all_unique - -def pdb_write_statements(text, header = None, n_context = 5): - all_problems = [] - for search_word in [".model_as_pdb(", ".as_pdb_string(", - ".write_model_file("]: - all_problems += display_context(header = header, text = text, - n_context = n_context, search_word = search_word,quiet = True, - category = 'pdb_write_statements') - return all_problems - -def pdb_format_interpretation(text, header = None, n_context = 5): - all_problems = [] - for search_word in ['.open(']: - for required_word in ['.pdb','pdb_file','model_file']: - all_problems += display_context(header = header, text = text, - n_context = n_context, - search_word = search_word, - required_word=required_word, - excluded_words=['transfer_ext','forward_compatible','iotbx.pdb'], - quiet = True, - category = 'pdb_format_interpretation') - all_problems += display_context(header = header, text = text, - n_context = n_context, - search_word = ".splitlines(", - required_word=" in ", - excluded_words=["cmds.","iotbx.pdb"], # if this is present, it is ok - quiet = True, - category = 'pdb_format_interpretation') - for search_word in ['HETATM','ATOM','TER','BREAK',' CA ',' N ']: - for required_word in ['startswith','find(']: - all_problems += display_context(header = header, text = text, - n_context = n_context, - search_word = search_word, - required_word=required_word, - quiet = True, - category = 'pdb_format_interpretation') - return all_problems - -def raw_records(text, header = None, n_context = 5): - all_problems = [] - for search_word in ['raw_records=','lines=','raw_records =','lines =']: - for required_word in ['.pdb','open(']: - all_problems += display_context(header = header, text = text, - n_context = n_context, - search_word = search_word, - required_word=required_word, - excluded_words=['pdb.input','iotbx.pdb','input.pdb'], - quiet = True, - category = 'pdb_format_interpretation') - return all_problems - -def pdb_file_name(text, header = None, n_context = 5): - all_problems = [] - for search_word in ['file_name',' fn ',' fn=','filename']: - for required_word in ['.pdb']: - all_problems += display_context(header = header, text = text, - n_context = n_context, - search_word = search_word, - required_word=required_word, - excluded_words = ['.pdb_or_mmcif_string_info', - 'pdb.input','iotbx.pdb','.cif','input.pdb'], - quiet = True, - category = 'pdb_format_interpretation') - return all_problems - - -# ============================================================================= -if __name__ == '__main__': - import sys - run(sys.argv[1:]) - -# ============================================================================= -# end diff --git a/libtbx/utils.py b/libtbx/utils.py index bd126cd60c..69184e274b 100644 --- a/libtbx/utils.py +++ b/libtbx/utils.py @@ -2525,11 +2525,11 @@ def check_git_lfs_pointer_is_loaded(path): """%path) return not test -def display_context(text, header = 'Supplied text', n_context = 5, - search_word = None, required_word= None, +def display_context(text, file_name = 'file name', n_context = 5, + search_word = None, required_word= None, excluded_words = None, category = None, quiet = None, - always_excluded_words = ['DEBUG', 'PDB OK']): + always_excluded_words = None): ''' Search lines in text for search_word and select blocks of size n_context on either side. If context_word appears, mark that line @@ -2540,7 +2540,7 @@ def display_context(text, header = 'Supplied text', n_context = 5, if required_word is set) params: excluded_words: if any are present in text_block, skip it params: category: category to pass on in group_args - params: header: header (title or name of file) to pass on in group_args + params: file_name: file_name (title or name of file) to pass on in group_args params: always_excluded_words: add to excluded words ''' @@ -2551,13 +2551,21 @@ def display_context(text, header = 'Supplied text', n_context = 5, print("\n"+79*"=") print( "Searching %s with Search word: %s Required word: %s Excluded word: %s" %( - header, search_word, required_word, excluded_words)) + file_name, search_word, required_word, excluded_words)) print("\n"+79*"=") if not excluded_words: excluded_words = [] + if not always_excluded_words: always_excluded_words = [] + max_working_lines = 2*n_context + working_lines = [] for i in range(len(lines)): - if lines[i].find(search_word)>-1: + working_lines.append(lines[i]) + if len(working_lines) > max_working_lines: + working_lines = working_lines[1:] + working_lines_text = "\n".join(working_lines) + if lines[i].find(search_word)>-1 and ( + not lines[i].strip().startswith("#")): text_block = "" first_line_number = max(0,i-n_context) last_line_number = min(len(lines), i+n_context+1) @@ -2570,18 +2578,20 @@ def display_context(text, header = 'Supplied text', n_context = 5, for x in excluded_words + always_excluded_words: if text_block.find(x) > -1: skip = True + if working_lines_text.find(x) > -1: # allow backwards further + skip = True if skip: - continue + continue if required_word and (text_block.find(required_word) < 0): continue if not quiet: print("\n%s at line %s. Search word: %s Required word: %s" %( - header, first_line_number+1, search_word, required_word)) + file_name, first_line_number+1, search_word, required_word)) print(text_block) info = group_args(group_args_type = 'text block', category = category, - header = header, + file_name = file_name, search_word = search_word, required_word = required_word, excluded_words = excluded_words, @@ -2589,9 +2599,9 @@ def display_context(text, header = 'Supplied text', n_context = 5, text_block = text_block, line_number = i+1, ) - text_block_list.append(info) + text_block_list.append(info) return text_block_list - + class timer: ''' From c0dbcfa9d38d15464eba300da968dfb4ac728577 Mon Sep 17 00:00:00 2001 From: terwill Date: Sat, 27 Jan 2024 09:46:44 -0800 Subject: [PATCH 070/748] Update find_pdb_mmcif_problems.py --- libtbx/command_line/find_pdb_mmcif_problems.py | 1 + 1 file changed, 1 insertion(+) diff --git a/libtbx/command_line/find_pdb_mmcif_problems.py b/libtbx/command_line/find_pdb_mmcif_problems.py index 3fad22b8b2..c28672751c 100644 --- a/libtbx/command_line/find_pdb_mmcif_problems.py +++ b/libtbx/command_line/find_pdb_mmcif_problems.py @@ -162,6 +162,7 @@ def run(args, n_context = 7, overall_exclude = None): 'mmcif', # the author has considered cif '.cif', # the author has considered cif 'write_model(', # the write_model function is cif-aware + 'write_output_file(', # the write_output_file function is cif-aware '.type = ', # This is in parameters ] From 51608ceb400f8e1b4043087fd287ebd999d147ca Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Sat, 27 Jan 2024 09:47:37 -0800 Subject: [PATCH 071/748] Refactoring phenix.fmodel part1: code and tests (a bit more work needed in next round to clean up output scope) --- cctbx/development/create_models_or_maps.py | 2 +- mmtbx/command_line/fmodel.py | 944 +++++++++--------- mmtbx/refinement/tst_occupancy_selections.py | 5 +- mmtbx/refinement/tst_rigid_body.py | 2 +- .../tst_select_best_starting_model.py | 3 +- mmtbx/regression/make_fake_anomalous_data.py | 5 +- .../model_idealization/tst_with_mtz.py | 3 +- mmtbx/regression/tst_fmodel_misc.py | 21 +- mmtbx/regression/tst_ligand_ncs.py | 5 +- mmtbx/utils/__init__.py | 3 +- 10 files changed, 503 insertions(+), 490 deletions(-) diff --git a/cctbx/development/create_models_or_maps.py b/cctbx/development/create_models_or_maps.py index e16fce8245..859a859f08 100644 --- a/cctbx/development/create_models_or_maps.py +++ b/cctbx/development/create_models_or_maps.py @@ -260,7 +260,7 @@ def generate_map_coefficients( # get map coefficients from mmtbx.utils import fmodel_from_xray_structure import iotbx.phil - from mmtbx.command_line.fmodel import master_phil + from mmtbx.programs.fmodel import master_phil fmodel_params=master_phil.extract() if f_obs_array: diff --git a/mmtbx/command_line/fmodel.py b/mmtbx/command_line/fmodel.py index fcaf2c46a7..9876a19df4 100644 --- a/mmtbx/command_line/fmodel.py +++ b/mmtbx/command_line/fmodel.py @@ -1,469 +1,479 @@ -from __future__ import absolute_import, division, print_function # LIBTBX_SET_DISPATCHER_NAME phenix.fmodel +from __future__ import absolute_import, division, print_function -import sys, os -import mmtbx.utils -import iotbx.phil -import iotbx.pdb -from scitbx.array_family import flex -from libtbx import runtime_utils -from libtbx.utils import Sorry -import random - -legend = """ -phenix.fmodel: a tool to compute structure factors, Fmodel: - - Fmodel = scale * exp(AnisoScale) * (Fcalc + k_sol * exp(-b_sol*s^2/4) * Fmask) - - where: - - - Fmodel - total model structure factor (complex value) - - AnisoScale = -ht*A(-1)*b_cart*A(-1)th/4 - - h - column vector with Miller indices - - A - orthogonalization matrix - - b_cart - anisotropic scale matrix - - t and (-1) denotes transposition and inversion operations - - scale - overall scale factor - - Fcalc - structure factors calculated from atomic model - - k_sol and b_sol - Flat Bulk solvent model parameters - - Fmask - structure factors calculated from bulk solvent mask - -Usage examples: - - 1) phenix.fmodel model.pdb high_resolution=1.5 - - will result in a file containing complete set of Fmodel = Fcalc computed - from atomic model up to 1.5A resolution. - - 2) phenix.fmodel model.pdb scale=2 k_sol=0.35 b_sol=50 b_cart="1 2 3 0 4 7" high_res=1.5 low_res=10 - - will result in a file containing complete set of Fmodel computed using the - above formula in resolution range 1.5-20.0A. - - 3) phenix.fmodel model.pdb high_resolution=1.5 algorithm=direct - - is similar to "1)" but the Fcalc are computed using direct summation algorithm. - - 4) phenix.fmodel model.pdb high_res=1.5 format=cns label=FOBS type=real r_free=0.1 - - will result in CNS formatted file containing complete set of amplitudes of - Fmodel = Fcalc computed up to 1.5A resolution, labelled as FOBS, and free-R - flags with 10% of test reflections. This is a typical command to simulate Fobs. - - 5) phenix.fmodel model.pdb high_res=1.5 scattering_table=neutron - - will result in a file containing complete set of Fmodel = Fcalc computed - from atomic model up to 1.5A resolution using neutron scattering table. - - 6) phenix.fmodel model.pdb parameters.txt - - will result in a structure factor file, where Fmodel were computed using - parameters defined in parameters.txt file. The parameters.txt file can - contain all or any subset of parameters listed below. Note, that each { - must have a matching one }. - - 7) phenix.fmodel model.pdb reflection_data.mtz - - will result in a file containing a set of Fmodel = Fcalc that will match - the set of Miller indices of the data in reflection_data.mtz file. - - 8) phenix.fmodel model.pdb reflection_data.mtz data_column_label="FOBS,SIGMA" - - similar to "7)", where the specific data array is selected. - - 9) phenix.fmodel model.pdb reflection_data.mtz twin_law="l,-k,h" twin_fraction=0.3 - - generates twin data set (real type) with given twin law and fraction. - -See below for complete list of available parameters. -""" - -fmodel_from_xray_structure_params_str = """\ -fmodel - .short_caption = F(model) options - .expert_level = 1 - .style = auto_align box -{ - k_sol = 0.0 - .type = float - .help = Bulk solvent k_sol values - .short_caption=Bulk solvent K_sol value - b_sol = 0.0 - .type = float - .help = Bulk solvent b_sol values - .short_caption=Bulk solvent B_sol value - b_cart = 0 0 0 0 0 0 - .type = floats(6) - .help = Anisotropic scale matrix - .input_size = 200 - .short_caption = Anisotropic scale matrix - scale = 1.0 - .type = float - .help = Overall scale factor -} -structure_factors_accuracy - .short_caption = Structure factors accuracy - .style = auto_align box -{ - include scope mmtbx.f_model.sf_and_grads_accuracy_master_params -} -mask - .short_caption = Bulk solvent mask - .style = auto_align box -{ - include scope mmtbx.masks.mask_master_params -} -""" -fmodel_from_xray_structure_params = iotbx.phil.parse( - fmodel_from_xray_structure_params_str, process_includes=True) - -fmodel_from_xray_structure_master_params_str = """\ -high_resolution = None - .type = float - .expert_level=1 - .style = noauto bold -low_resolution = None - .type = float - .expert_level=1 - .style = noauto -r_free_flags_fraction = None - .type = float - .expert_level=1 - .style = noauto -add_sigmas = False - .type = bool - .expert_level=1 - .help = Adds calculated Sigma(F) column to output file. - .style = noauto -add_random_error_to_amplitudes_percent = None - .type = float - .short_caption = Add random error (percent) - .style = noauto -scattering_table = wk1995 it1992 *n_gaussian neutron electron - .type = choice - .help = Choices of scattering table for structure factors calculations. \ - n_gaussian is the standard set of X-ray scattering factors. - .expert_level=1 - .style = noauto -custom_scattering_factors = None - .type = path - .help = Use custom scattering factors and replaces default values entirely -pdb_file = None - .type = path - .multiple = True - .optional = True - .short_caption = Model file - .style = bold noauto file_type:pdb input_file OnChange:update_output_file_name -reference_file = None - .type = path - .short_caption = Reference set - .help = Reflections file containing Miller indices (h,k,l) to use in output \ - file. - .style = noauto input_file file_type:mtz OnChange:update_reference_column_labels -data_column_label = None - .type = str - .short_caption = Reference file label - .style = noauto renderer:draw_any_label_widget -%s -random_seed=None - .type = int - .help = Random seed - .expert_level=2 -twin_law = None - .type = str - .help = Optional twin law if we want to generate a twinned dataset - .input_size = 120 - .style = noauto -twin_fraction = None - .type = float - .help = Twin fraction, ignored if twin_law is not specified - .style = noauto -wavelength = None - .type = float - .input_size = 80 - .help = Wavelength, sets all atoms to anomalous - .style = noauto -generate_fake_p1_symmetry = False - .type = bool - .short_caption = Generate fake symmetry if necessary - .help = Allows use of PDB files without CRYST1 records as input. The \ - crystal symmetry will be assumed to be a P1 box. -output - .short_caption = Reflection output - .expert_level=0 - .style = noauto -{ - format = *mtz cns - .type = choice - .short_caption = File format - label = FMODEL - .type = str - .short_caption = Data label - .input_size = 100 - type = real *complex - .type = choice - .short_caption = Output data type - .help = Numeric type of output data. 'real' is amplitudes only, \ - 'complex' is complete structure factors as complex numbers. - .expert_level=1 - .style = bold - obs_type = *amplitudes intensities - .type = choice - .help = Experimental observation type to output. Certain restrictions \ - apply if intensities are selected. - .expert_level = 2 - file_name = None - .type = path - .short_caption = Output file - .style = bold noauto new_file - include scope libtbx.phil.interface.tracking_params -} -anomalous_scatterers - .short_caption = Anomalous sites - .style = menu_item noauto -{ - group - .optional = True - .multiple = True - .short_caption = Anomalous scatterer group - .style = auto_align - { - selection = None - .type = atom_selection - .short_caption = Atom selection - .input_size = 400 - f_prime = 0 - .type = float - .short_caption = f' - f_double_prime = 0 - .type = float - .short_caption = f'' - } -} -"""%fmodel_from_xray_structure_params_str - -fmodel_from_xray_structure_master_params = iotbx.phil.parse( - fmodel_from_xray_structure_master_params_str, process_includes=True) -master_phil = fmodel_from_xray_structure_master_params # XXX for phenix docs - -def set_fp_fdp_for_anomalous_scatterers(pdb_hierarchy, xray_structure, - anomalous_scatterer_groups): - scatterers = xray_structure.scatterers() - for group in anomalous_scatterer_groups: - iselection = pdb_hierarchy.atom_selection_cache().selection( - string = group.selection).iselection() - if(iselection.size() == 0): - raise Sorry( - "Empty selection: selection string '%s' does not select any atom."% - group.selection) - for i_seq in iselection: - scatterers[i_seq].fp = group.f_prime - scatterers[i_seq].fdp = group.f_double_prime - -def run(args, log = sys.stdout): - print(legend, file=log) - # XXX: pre-processing for GUI; duplicates some of mmtbx.utils - sources = [] - for arg in args : - if os.path.isfile(arg): - try : - file_phil = iotbx.phil.parse(file_name=arg) - except KeyboardInterrupt : - raise - except RuntimeError : - pass - else : - if len(file_phil.objects) != 0 : - sources.append(file_phil) - if len(sources) > 0 : - cmdline_phil = fmodel_from_xray_structure_master_params.fetch( - sources=sources) - params = cmdline_phil.extract() - if len(params.pdb_file) > 0 : - args.extend(params.pdb_file) - if params.reference_file is not None : - args.append(params.reference_file) - # end of preprocessing - processed_args = mmtbx.utils.process_command_line_args(args = args, log = log, - master_params = fmodel_from_xray_structure_master_params) - pdb_combined = iotbx.pdb.combine_unique_pdb_files( - file_names = processed_args.pdb_file_names) - pdb_combined.report_non_unique(out = log) - print("-"*79, file=log) - print("\nParameters to compute Fmodel::\n", file=log) - processed_args.params.show(out = log, prefix=" ") - params = processed_args.params.extract() - if(params.random_seed is not None): - random.seed(params.random_seed) - flex.set_random_seed(params.random_seed) - pdb_file_names = processed_args.pdb_file_names - if len(pdb_file_names) == 0 : - pdb_file_names = params.pdb_file # for GUI - pdb_combined = iotbx.pdb.combine_unique_pdb_files(file_names=pdb_file_names) - pdb_combined.report_non_unique(out = log) - if(len(pdb_combined.unique_file_names) == 0): - raise Sorry("Model file is not provided.") - print("-"*79, file=log) - print("\nInput model file(s):", " ".join(processed_args.pdb_file_names), file=log) - pdb_inp = iotbx.pdb.input(source_info = None, - lines = flex.std_string(pdb_combined.raw_records)) - # select miller array to use as a set of miller indices for f_model - miller_array = None - if(len(processed_args.reflection_files) > 1): - raise Sorry("Multiple reflection files found at input.") - # FIXME this does not pick up the reference_file parameter! in fact, it - # appears to be ignored completely when run on the command line. - if(len(processed_args.reflection_files) == 1): - print("-"*79, file=log) - print("Input reflection data:", \ - " ".join(processed_args.reflection_file_names), file=log) - if([params.high_resolution, params.low_resolution].count(None) != 2): - raise Sorry("high_resolution and low_resolution must be undefined "+ - "if reflection data file is given.") - miller_arrays = processed_args.reflection_files[0].as_miller_arrays() - data_sizes = flex.int([ma.data().size() for ma in miller_arrays]) - if(data_sizes.all_eq(data_sizes[0])): miller_array = miller_arrays[0] - else: - all_labels = [] - for ma in miller_arrays: - if(params.data_column_label is not None and - ma.info().label_string() == params.data_column_label): - miller_array = ma - break - all_labels.append(",".join(ma.info().labels)) - if(miller_array is None): - raise Sorry("Multiple data available in input reflection file:\n%s\n%s"%( - "\n".join(all_labels),"Please select one using 'data_column_label=' keyword.")) - else: - miller_array.show_comprehensive_summary(f = log, prefix=" ") - if(miller_array is not None): - miller_array = miller_array.map_to_asu().customized_copy( - data = flex.double(miller_array.data().size(), 1)) - # - cryst1 = pdb_inp.crystal_symmetry_from_cryst1() - if(cryst1 is None and miller_array is not None): - cryst1 = miller_array.crystal_symmetry() - if (cryst1 is not None) and (params.generate_fake_p1_symmetry): - raise Sorry("The input reference data already define crystal symmetry; "+ - "you may not use this in combination with the option "+ - "generate_fake_p1_symmetry=True.") - if (not params.generate_fake_p1_symmetry): - if(cryst1 is None): - raise Sorry( - "CRYST1 record in input PDB file is incomplete or missing. "+ - "If you want the program to generate P1 symmetry automatically, set "+ - "generate_fake_p1_symmetry=True.") - else: - if([cryst1.unit_cell(), cryst1.space_group_info()].count(None) != 0): - raise Sorry( - "CRYST1 record in input PDB file is incomplete or missing. "+ - "If you want the program to generate P1 symmetry automatically, "+ - "set generate_fake_p1_symmetry=True.") - pdb_hierarchy = pdb_inp.construct_hierarchy() - # need to preserve the order in the hierarchy in case we have to perform an - # atom selection later - xray_structure = pdb_hierarchy.extract_xray_structure( - crystal_symmetry = cryst1) - if (cryst1 is None): - cryst1 = xray_structure.crystal_symmetry() - if (miller_array is not None): - if (miller_array.crystal_symmetry() is None): - miller_array = miller_array.customized_copy(crystal_symmetry=cryst1) - xray_structure.show_summary(f = log, prefix=" ") - if(len(params.anomalous_scatterers.group) != 0): - pdb_atoms = pdb_hierarchy.atoms() - pdb_atoms.reset_i_seq() - set_fp_fdp_for_anomalous_scatterers( - pdb_hierarchy = pdb_hierarchy, - xray_structure = xray_structure, - anomalous_scatterer_groups = params.anomalous_scatterers.group) - elif (params.wavelength is not None): - if (params.scattering_table == "neutron"): - raise Sorry("Wavelength parameter not supported when the neutron "+ - "scattering table is used.") - print("Setting inelastic form factors for wavelength = %g" % \ - params.wavelength, file=log) - xray_structure.set_inelastic_form_factors( - photon=params.wavelength, - table="sasaki") - # - validate_params_command_line(params) - # - print("-"*79, file=log) - print("Computing model structure factors, Fmodel:", file=log) - if(params.output.format == "cns"): extension = ".hkl" - elif(params.output.format == "mtz"): extension = ".mtz" - ofn = params.output.file_name - if(ofn is None): - ofn = os.path.basename(processed_args.pdb_file_names[0]) - if(len(processed_args.pdb_file_names)==1): ofn = ofn + extension - else: ofn = ofn + "_et_al" + extension - if([miller_array, params.high_resolution].count(None)==2): - raise Sorry("Input data file or high_resolution has to be provided.") - use_custom_scattering_dictionary = False - if params.custom_scattering_factors: - use_custom_scattering_dictionary = True - mmtbx.utils.fmodel_from_xray_structure( - xray_structure = xray_structure, - f_obs = miller_array, - add_sigmas = params.add_sigmas, - params = params, - twin_law = params.twin_law, - twin_fraction = params.twin_fraction, - use_custom_scattering_dictionary = use_custom_scattering_dictionary, - out = log).write_to_file(file_name = ofn, - obs_type=params.output.obs_type) - print("Output file name:", ofn, file=log) - print("All done.", file=log) - print("-"*79, file=log) - return ofn - -class launcher(runtime_utils.target_with_save_result): - def run(self): - return run(args=list(self.args), log=sys.stdout) - -def validate_params(params, callback=None): - if len(params.pdb_file) == 0 : - raise Sorry("You must provide at least one model file to use for "+ - "F(model) calculations.") - if (params.high_resolution is None): - if (params.reference_file is None): - raise Sorry("Please specify a high-resolution cutoff.") - elif (params.reference_file is not None): - if (params.data_column_label is None): - raise Sorry("Please select a column label to use in the reference "+ - "data file.") - elif ([params.high_resolution, params.low_resolution].count(None) != 2): - raise Sorry("High resolution and low resolution must be undefined "+ - "if reflection data file is given.") - if (params.output.file_name is None): - raise Sorry("Please specify an output file.") - validate_params_command_line(params) - -def validate_params_command_line(params): - if (params.output.type == "complex") and (params.add_sigmas): - raise Sorry("Sigma values only supported when the output type is 'real'.") - if ( params.low_resolution is not None - and params.high_resolution is not None): - if params.low_resolution < params.high_resolution : - raise Sorry("Low-resolution cutoff must be larger than the high-"+ - "resolution cutoff.") - if (params.output.obs_type == "intensities"): - if (params.output.type == "complex"): - raise Sorry("Output type must be 'real' when intensities specified "+ - "for obs_type.") - if (not params.output.label.upper().startswith("I")): - raise Sorry("Output label must start with 'I' (any case) when "+ - "intensities specified for obs_type (was: %s)." % params.output.label) - if (params.output.format != "mtz"): - raise Sorry("Output format must be 'mtz' when intensities specified.") - return True - -def finish_job(result): - output_files = [] - if (result is not None) and (os.path.isfile(result)): - output_files.append((os.path.abspath(result), "MTZ file")) - return (output_files, []) - -if (__name__ == "__main__"): - run(args=sys.argv[1:]) +from iotbx.cli_parser import run_program +from mmtbx.programs import fmodel + +if __name__ == '__main__': + run_program(program_class=fmodel.Program) + +#from __future__ import absolute_import, division, print_function +## LIBTBX_SET_DISPATCHER_NAME phenix.fmodel +# +#import sys, os +#import mmtbx.utils +#import iotbx.phil +#import iotbx.pdb +#from scitbx.array_family import flex +#from libtbx import runtime_utils +#from libtbx.utils import Sorry +#import random +# +#legend = """ +#phenix.fmodel: a tool to compute structure factors, Fmodel: +# +# Fmodel = scale * exp(AnisoScale) * (Fcalc + k_sol * exp(-b_sol*s^2/4) * Fmask) +# +# where: +# +# - Fmodel - total model structure factor (complex value) +# - AnisoScale = -ht*A(-1)*b_cart*A(-1)th/4 +# - h - column vector with Miller indices +# - A - orthogonalization matrix +# - b_cart - anisotropic scale matrix +# - t and (-1) denotes transposition and inversion operations +# - scale - overall scale factor +# - Fcalc - structure factors calculated from atomic model +# - k_sol and b_sol - Flat Bulk solvent model parameters +# - Fmask - structure factors calculated from bulk solvent mask +# +#Usage examples: +# +# 1) phenix.fmodel model.pdb high_resolution=1.5 +# +# will result in a file containing complete set of Fmodel = Fcalc computed +# from atomic model up to 1.5A resolution. +# +# 2) phenix.fmodel model.pdb scale=2 k_sol=0.35 b_sol=50 b_cart="1 2 3 0 4 7" high_res=1.5 low_res=10 +# +# will result in a file containing complete set of Fmodel computed using the +# above formula in resolution range 1.5-20.0A. +# +# 3) phenix.fmodel model.pdb high_resolution=1.5 algorithm=direct +# +# is similar to "1)" but the Fcalc are computed using direct summation algorithm. +# +# 4) phenix.fmodel model.pdb high_res=1.5 format=cns label=FOBS type=real r_free=0.1 +# +# will result in CNS formatted file containing complete set of amplitudes of +# Fmodel = Fcalc computed up to 1.5A resolution, labelled as FOBS, and free-R +# flags with 10% of test reflections. This is a typical command to simulate Fobs. +# +# 5) phenix.fmodel model.pdb high_res=1.5 scattering_table=neutron +# +# will result in a file containing complete set of Fmodel = Fcalc computed +# from atomic model up to 1.5A resolution using neutron scattering table. +# +# 6) phenix.fmodel model.pdb parameters.txt +# +# will result in a structure factor file, where Fmodel were computed using +# parameters defined in parameters.txt file. The parameters.txt file can +# contain all or any subset of parameters listed below. Note, that each { +# must have a matching one }. +# +# 7) phenix.fmodel model.pdb reflection_data.mtz +# +# will result in a file containing a set of Fmodel = Fcalc that will match +# the set of Miller indices of the data in reflection_data.mtz file. +# +# 8) phenix.fmodel model.pdb reflection_data.mtz data_column_label="FOBS,SIGMA" +# +# similar to "7)", where the specific data array is selected. +# +# 9) phenix.fmodel model.pdb reflection_data.mtz twin_law="l,-k,h" twin_fraction=0.3 +# +# generates twin data set (real type) with given twin law and fraction. +# +#See below for complete list of available parameters. +#""" +# +#fmodel_from_xray_structure_params_str = """\ +#fmodel +# .short_caption = F(model) options +# .expert_level = 1 +# .style = auto_align box +#{ +# k_sol = 0.0 +# .type = float +# .help = Bulk solvent k_sol values +# .short_caption=Bulk solvent K_sol value +# b_sol = 0.0 +# .type = float +# .help = Bulk solvent b_sol values +# .short_caption=Bulk solvent B_sol value +# b_cart = 0 0 0 0 0 0 +# .type = floats(6) +# .help = Anisotropic scale matrix +# .input_size = 200 +# .short_caption = Anisotropic scale matrix +# scale = 1.0 +# .type = float +# .help = Overall scale factor +#} +#structure_factors_accuracy +# .short_caption = Structure factors accuracy +# .style = auto_align box +#{ +# include scope mmtbx.f_model.sf_and_grads_accuracy_master_params +#} +#mask +# .short_caption = Bulk solvent mask +# .style = auto_align box +#{ +# include scope mmtbx.masks.mask_master_params +#} +#""" +#fmodel_from_xray_structure_params = iotbx.phil.parse( +# fmodel_from_xray_structure_params_str, process_includes=True) +# +#fmodel_from_xray_structure_master_params_str = """\ +#high_resolution = None +# .type = float +# .expert_level=1 +# .style = noauto bold +#low_resolution = None +# .type = float +# .expert_level=1 +# .style = noauto +#r_free_flags_fraction = None +# .type = float +# .expert_level=1 +# .style = noauto +#add_sigmas = False +# .type = bool +# .expert_level=1 +# .help = Adds calculated Sigma(F) column to output file. +# .style = noauto +#add_random_error_to_amplitudes_percent = None +# .type = float +# .short_caption = Add random error (percent) +# .style = noauto +#scattering_table = wk1995 it1992 *n_gaussian neutron electron +# .type = choice +# .help = Choices of scattering table for structure factors calculations. \ +# n_gaussian is the standard set of X-ray scattering factors. +# .expert_level=1 +# .style = noauto +#custom_scattering_factors = None +# .type = path +# .help = Use custom scattering factors and replaces default values entirely +#pdb_file = None +# .type = path +# .multiple = True +# .optional = True +# .short_caption = Model file +# .style = bold noauto file_type:pdb input_file OnChange:update_output_file_name +#reference_file = None +# .type = path +# .short_caption = Reference set +# .help = Reflections file containing Miller indices (h,k,l) to use in output \ +# file. +# .style = noauto input_file file_type:mtz OnChange:update_reference_column_labels +#data_column_label = None +# .type = str +# .short_caption = Reference file label +# .style = noauto renderer:draw_any_label_widget +#%s +#random_seed=None +# .type = int +# .help = Random seed +# .expert_level=2 +#twin_law = None +# .type = str +# .help = Optional twin law if we want to generate a twinned dataset +# .input_size = 120 +# .style = noauto +#twin_fraction = None +# .type = float +# .help = Twin fraction, ignored if twin_law is not specified +# .style = noauto +#wavelength = None +# .type = float +# .input_size = 80 +# .help = Wavelength, sets all atoms to anomalous +# .style = noauto +#generate_fake_p1_symmetry = False +# .type = bool +# .short_caption = Generate fake symmetry if necessary +# .help = Allows use of PDB files without CRYST1 records as input. The \ +# crystal symmetry will be assumed to be a P1 box. +#output +# .short_caption = Reflection output +# .expert_level=0 +# .style = noauto +#{ +# format = *mtz cns +# .type = choice +# .short_caption = File format +# label = FMODEL +# .type = str +# .short_caption = Data label +# .input_size = 100 +# type = real *complex +# .type = choice +# .short_caption = Output data type +# .help = Numeric type of output data. 'real' is amplitudes only, \ +# 'complex' is complete structure factors as complex numbers. +# .expert_level=1 +# .style = bold +# obs_type = *amplitudes intensities +# .type = choice +# .help = Experimental observation type to output. Certain restrictions \ +# apply if intensities are selected. +# .expert_level = 2 +# file_name = None +# .type = path +# .short_caption = Output file +# .style = bold noauto new_file +# include scope libtbx.phil.interface.tracking_params +#} +#anomalous_scatterers +# .short_caption = Anomalous sites +# .style = menu_item noauto +#{ +# group +# .optional = True +# .multiple = True +# .short_caption = Anomalous scatterer group +# .style = auto_align +# { +# selection = None +# .type = atom_selection +# .short_caption = Atom selection +# .input_size = 400 +# f_prime = 0 +# .type = float +# .short_caption = f' +# f_double_prime = 0 +# .type = float +# .short_caption = f'' +# } +#} +#"""%fmodel_from_xray_structure_params_str +# +#fmodel_from_xray_structure_master_params = iotbx.phil.parse( +# fmodel_from_xray_structure_master_params_str, process_includes=True) +#master_phil = fmodel_from_xray_structure_master_params # XXX for phenix docs +# +#def set_fp_fdp_for_anomalous_scatterers(pdb_hierarchy, xray_structure, +# anomalous_scatterer_groups): +# scatterers = xray_structure.scatterers() +# for group in anomalous_scatterer_groups: +# iselection = pdb_hierarchy.atom_selection_cache().selection( +# string = group.selection).iselection() +# if(iselection.size() == 0): +# raise Sorry( +# "Empty selection: selection string '%s' does not select any atom."% +# group.selection) +# for i_seq in iselection: +# scatterers[i_seq].fp = group.f_prime +# scatterers[i_seq].fdp = group.f_double_prime +# +#def run(args, log = sys.stdout): +# print(legend, file=log) +# # XXX: pre-processing for GUI; duplicates some of mmtbx.utils +# sources = [] +# for arg in args : +# if os.path.isfile(arg): +# try : +# file_phil = iotbx.phil.parse(file_name=arg) +# except KeyboardInterrupt : +# raise +# except RuntimeError : +# pass +# else : +# if len(file_phil.objects) != 0 : +# sources.append(file_phil) +# if len(sources) > 0 : +# cmdline_phil = fmodel_from_xray_structure_master_params.fetch( +# sources=sources) +# params = cmdline_phil.extract() +# if len(params.pdb_file) > 0 : +# args.extend(params.pdb_file) +# if params.reference_file is not None : +# args.append(params.reference_file) +# # end of preprocessing +# processed_args = mmtbx.utils.process_command_line_args(args = args, log = log, +# master_params = fmodel_from_xray_structure_master_params) +# pdb_combined = iotbx.pdb.combine_unique_pdb_files( +# file_names = processed_args.pdb_file_names) +# pdb_combined.report_non_unique(out = log) +# print("-"*79, file=log) +# print("\nParameters to compute Fmodel::\n", file=log) +# processed_args.params.show(out = log, prefix=" ") +# params = processed_args.params.extract() +# if(params.random_seed is not None): +# random.seed(params.random_seed) +# flex.set_random_seed(params.random_seed) +# pdb_file_names = processed_args.pdb_file_names +# if len(pdb_file_names) == 0 : +# pdb_file_names = params.pdb_file # for GUI +# pdb_combined = iotbx.pdb.combine_unique_pdb_files(file_names=pdb_file_names) +# pdb_combined.report_non_unique(out = log) +# if(len(pdb_combined.unique_file_names) == 0): +# raise Sorry("Model file is not provided.") +# print("-"*79, file=log) +# print("\nInput model file(s):", " ".join(processed_args.pdb_file_names), file=log) +# pdb_inp = iotbx.pdb.input(source_info = None, +# lines = flex.std_string(pdb_combined.raw_records)) +# # select miller array to use as a set of miller indices for f_model +# miller_array = None +# if(len(processed_args.reflection_files) > 1): +# raise Sorry("Multiple reflection files found at input.") +# # FIXME this does not pick up the reference_file parameter! in fact, it +# # appears to be ignored completely when run on the command line. +# if(len(processed_args.reflection_files) == 1): +# print("-"*79, file=log) +# print("Input reflection data:", \ +# " ".join(processed_args.reflection_file_names), file=log) +# if([params.high_resolution, params.low_resolution].count(None) != 2): +# raise Sorry("high_resolution and low_resolution must be undefined "+ +# "if reflection data file is given.") +# miller_arrays = processed_args.reflection_files[0].as_miller_arrays() +# data_sizes = flex.int([ma.data().size() for ma in miller_arrays]) +# if(data_sizes.all_eq(data_sizes[0])): miller_array = miller_arrays[0] +# else: +# all_labels = [] +# for ma in miller_arrays: +# if(params.data_column_label is not None and +# ma.info().label_string() == params.data_column_label): +# miller_array = ma +# break +# all_labels.append(",".join(ma.info().labels)) +# if(miller_array is None): +# raise Sorry("Multiple data available in input reflection file:\n%s\n%s"%( +# "\n".join(all_labels),"Please select one using 'data_column_label=' keyword.")) +# else: +# miller_array.show_comprehensive_summary(f = log, prefix=" ") +# if(miller_array is not None): +# miller_array = miller_array.map_to_asu().customized_copy( +# data = flex.double(miller_array.data().size(), 1)) +# # +# cryst1 = pdb_inp.crystal_symmetry_from_cryst1() +# if(cryst1 is None and miller_array is not None): +# cryst1 = miller_array.crystal_symmetry() +# if (cryst1 is not None) and (params.generate_fake_p1_symmetry): +# raise Sorry("The input reference data already define crystal symmetry; "+ +# "you may not use this in combination with the option "+ +# "generate_fake_p1_symmetry=True.") +# if (not params.generate_fake_p1_symmetry): +# if(cryst1 is None): +# raise Sorry( +# "CRYST1 record in input PDB file is incomplete or missing. "+ +# "If you want the program to generate P1 symmetry automatically, set "+ +# "generate_fake_p1_symmetry=True.") +# else: +# if([cryst1.unit_cell(), cryst1.space_group_info()].count(None) != 0): +# raise Sorry( +# "CRYST1 record in input PDB file is incomplete or missing. "+ +# "If you want the program to generate P1 symmetry automatically, "+ +# "set generate_fake_p1_symmetry=True.") +# pdb_hierarchy = pdb_inp.construct_hierarchy() +# # need to preserve the order in the hierarchy in case we have to perform an +# # atom selection later +# xray_structure = pdb_hierarchy.extract_xray_structure( +# crystal_symmetry = cryst1) +# if (cryst1 is None): +# cryst1 = xray_structure.crystal_symmetry() +# if (miller_array is not None): +# if (miller_array.crystal_symmetry() is None): +# miller_array = miller_array.customized_copy(crystal_symmetry=cryst1) +# xray_structure.show_summary(f = log, prefix=" ") +# if(len(params.anomalous_scatterers.group) != 0): +# pdb_atoms = pdb_hierarchy.atoms() +# pdb_atoms.reset_i_seq() +# set_fp_fdp_for_anomalous_scatterers( +# pdb_hierarchy = pdb_hierarchy, +# xray_structure = xray_structure, +# anomalous_scatterer_groups = params.anomalous_scatterers.group) +# elif (params.wavelength is not None): +# if (params.scattering_table == "neutron"): +# raise Sorry("Wavelength parameter not supported when the neutron "+ +# "scattering table is used.") +# print("Setting inelastic form factors for wavelength = %g" % \ +# params.wavelength, file=log) +# xray_structure.set_inelastic_form_factors( +# photon=params.wavelength, +# table="sasaki") +# # +# validate_params_command_line(params) +# # +# print("-"*79, file=log) +# print("Computing model structure factors, Fmodel:", file=log) +# if(params.output.format == "cns"): extension = ".hkl" +# elif(params.output.format == "mtz"): extension = ".mtz" +# ofn = params.output.file_name +# if(ofn is None): +# ofn = os.path.basename(processed_args.pdb_file_names[0]) +# if(len(processed_args.pdb_file_names)==1): ofn = ofn + extension +# else: ofn = ofn + "_et_al" + extension +# if([miller_array, params.high_resolution].count(None)==2): +# raise Sorry("Input data file or high_resolution has to be provided.") +# use_custom_scattering_dictionary = False +# if params.custom_scattering_factors: +# use_custom_scattering_dictionary = True +# mmtbx.utils.fmodel_from_xray_structure( +# xray_structure = xray_structure, +# f_obs = miller_array, +# add_sigmas = params.add_sigmas, +# params = params, +# twin_law = params.twin_law, +# twin_fraction = params.twin_fraction, +# use_custom_scattering_dictionary = use_custom_scattering_dictionary, +# out = log).write_to_file(file_name = ofn, +# obs_type=params.output.obs_type) +# print("Output file name:", ofn, file=log) +# print("All done.", file=log) +# print("-"*79, file=log) +# return ofn +# +#class launcher(runtime_utils.target_with_save_result): +# def run(self): +# return run(args=list(self.args), log=sys.stdout) +# +#def validate_params(params, callback=None): +# if len(params.pdb_file) == 0 : +# raise Sorry("You must provide at least one model file to use for "+ +# "F(model) calculations.") +# if (params.high_resolution is None): +# if (params.reference_file is None): +# raise Sorry("Please specify a high-resolution cutoff.") +# elif (params.reference_file is not None): +# if (params.data_column_label is None): +# raise Sorry("Please select a column label to use in the reference "+ +# "data file.") +# elif ([params.high_resolution, params.low_resolution].count(None) != 2): +# raise Sorry("High resolution and low resolution must be undefined "+ +# "if reflection data file is given.") +# if (params.output.file_name is None): +# raise Sorry("Please specify an output file.") +# validate_params_command_line(params) +# +#def validate_params_command_line(params): +# if (params.output.type == "complex") and (params.add_sigmas): +# raise Sorry("Sigma values only supported when the output type is 'real'.") +# if ( params.low_resolution is not None +# and params.high_resolution is not None): +# if params.low_resolution < params.high_resolution : +# raise Sorry("Low-resolution cutoff must be larger than the high-"+ +# "resolution cutoff.") +# if (params.output.obs_type == "intensities"): +# if (params.output.type == "complex"): +# raise Sorry("Output type must be 'real' when intensities specified "+ +# "for obs_type.") +# if (not params.output.label.upper().startswith("I")): +# raise Sorry("Output label must start with 'I' (any case) when "+ +# "intensities specified for obs_type (was: %s)." % params.output.label) +# if (params.output.format != "mtz"): +# raise Sorry("Output format must be 'mtz' when intensities specified.") +# return True +# +#def finish_job(result): +# output_files = [] +# if (result is not None) and (os.path.isfile(result)): +# output_files.append((os.path.abspath(result), "MTZ file")) +# return (output_files, []) +# +#if (__name__ == "__main__"): +# run(args=sys.argv[1:]) +# diff --git a/mmtbx/refinement/tst_occupancy_selections.py b/mmtbx/refinement/tst_occupancy_selections.py index 26958356c7..96a2d60475 100644 --- a/mmtbx/refinement/tst_occupancy_selections.py +++ b/mmtbx/refinement/tst_occupancy_selections.py @@ -1,7 +1,8 @@ from __future__ import absolute_import, division, print_function from mmtbx.monomer_library import pdb_interpretation from mmtbx.refinement.occupancies import occupancy_selections -from mmtbx.command_line import fmodel +from iotbx.cli_parser import run_program +from mmtbx.programs import fmodel import mmtbx.model import iotbx.pdb import iotbx.phil @@ -1223,7 +1224,7 @@ def prepare_correlated_occupancy_inputs( "random_seed=12345", "output.file_name=%s.mtz" % prefix, ] - fmodel.run(args=args, log=null_out()) + run_program(program_class=fmodel.Program, args=args, logger=null_out()) pdb_file = iotbx.pdb.input(pdb_in) hierarchy = pdb_file.construct_hierarchy() xrs = pdb_file.xray_structure_simple() diff --git a/mmtbx/refinement/tst_rigid_body.py b/mmtbx/refinement/tst_rigid_body.py index dd14cac5ad..55a983f74a 100644 --- a/mmtbx/refinement/tst_rigid_body.py +++ b/mmtbx/refinement/tst_rigid_body.py @@ -185,7 +185,7 @@ def get_fmodel_from_pdb(pdb_file_name, pdb_file = libtbx.env.find_in_repositories( relative_path="phenix_regression/pdb/%s"%pdb_file_name,test=os.path.isfile) xray_structure = iotbx.pdb.input(file_name =pdb_file).xray_structure_simple() - params = mmtbx.command_line.fmodel.fmodel_from_xray_structure_master_params.extract() + params = mmtbx.programs.fmodel.master_phil.extract() assert params.high_resolution is None assert params.scattering_table == 'n_gaussian' assert params.structure_factors_accuracy.algorithm == 'fft' diff --git a/mmtbx/refinement/tst_select_best_starting_model.py b/mmtbx/refinement/tst_select_best_starting_model.py index 5d756e82c1..d68686af1b 100644 --- a/mmtbx/refinement/tst_select_best_starting_model.py +++ b/mmtbx/refinement/tst_select_best_starting_model.py @@ -92,7 +92,6 @@ def exercise_main(): params = """ high_resolution = 1.75 add_sigmas = True - pdb_file = tst_start_model_base.pdb output { label = F type = *real complex @@ -102,7 +101,7 @@ def exercise_main(): with open("tst_start_model_fmodel.eff", "w") as f: f.write(params) assert (easy_run.fully_buffered( - "phenix.fmodel tst_start_model_fmodel.eff" + "phenix.fmodel tst_start_model_base.pdb tst_start_model_fmodel.eff" ).raise_if_errors().return_code == 0) mtz_in = file_reader.any_file("tst_start_model_base.mtz") f_obs = mtz_in.file_server.miller_arrays[0] diff --git a/mmtbx/regression/make_fake_anomalous_data.py b/mmtbx/regression/make_fake_anomalous_data.py index 5c1dc6b4d5..eb96d3d90b 100644 --- a/mmtbx/regression/make_fake_anomalous_data.py +++ b/mmtbx/regression/make_fake_anomalous_data.py @@ -180,13 +180,12 @@ def generate_mtz_file(file_base, d_min, anomalous_scatterers=None, high_resolution = %g r_free_flags_fraction = 0.1 add_sigmas = True - pdb_file = %s.pdb wavelength = %s output { label = F type = *real complex file_name = %s.mtz - }\n""" % (d_min, file_base, wavelength, file_base) + }\n""" % (d_min, wavelength, file_base) if anomalous_scatterers is not None: params += "anomalous_scatterers {\n" for group in anomalous_scatterers : @@ -199,7 +198,7 @@ def generate_mtz_file(file_base, d_min, anomalous_scatterers=None, eff_file = file_base + "_fmodel.eff" with open(eff_file, "w") as f: f.write(params) - assert (easy_run.fully_buffered("phenix.fmodel %s" % eff_file, + assert (easy_run.fully_buffered("phenix.fmodel %s.pdb %s" % (file_base, eff_file), ).raise_if_errors().return_code == 0) return mtz_file diff --git a/mmtbx/regression/model_idealization/tst_with_mtz.py b/mmtbx/regression/model_idealization/tst_with_mtz.py index 7be89b1778..4e361cce3b 100644 --- a/mmtbx/regression/model_idealization/tst_with_mtz.py +++ b/mmtbx/regression/model_idealization/tst_with_mtz.py @@ -20,8 +20,7 @@ def exercise_01(prefix="tst_mi_mtz_01"): pdb_h = pdb_inp.construct_hierarchy() xrs = pdb_h.extract_xray_structure(crystal_symmetry=pdb_inp.crystal_symmetry()) - params = mmtbx.command_line.fmodel.\ - fmodel_from_xray_structure_master_params.extract() + params = mmtbx.programs.fmodel.master_phil.extract() params.high_resolution = 3 params.low_resolution = 20 params.output.label="FOBS" diff --git a/mmtbx/regression/tst_fmodel_misc.py b/mmtbx/regression/tst_fmodel_misc.py index 9149e514dd..f70dabdbc9 100644 --- a/mmtbx/regression/tst_fmodel_misc.py +++ b/mmtbx/regression/tst_fmodel_misc.py @@ -1,8 +1,10 @@ from __future__ import absolute_import, division, print_function from mmtbx.regression import make_fake_anomalous_data -from mmtbx.command_line import fmodel +#from mmtbx.command_line import fmodel +from mmtbx.programs import fmodel from iotbx import file_reader +from iotbx.cli_parser import run_program from cctbx import miller from scitbx.array_family import flex from libtbx.test_utils import approx_equal, Exception_expected @@ -26,7 +28,8 @@ def exercise(): "output.file_name=tst_fmodel_anomalous.mtz", "r_free_flags_fraction=0.1", ] - fmodel.run(args=args, log=null_out()) + #fmodel.run(args=args, log=null_out()) + run_program(program_class=fmodel.Program, args=args, logger=null_out()) assert os.path.isfile("tst_fmodel_anomalous.mtz") mtz_in = file_reader.any_file("tst_fmodel_anomalous.mtz") array = mtz_in.file_server.miller_arrays[0] @@ -55,18 +58,22 @@ def exercise_intensity_output(): "r_free_flags_fraction=0.1", ] args2 = args + ["label=Imodel"] - fmodel.run(args=args2, log=null_out()) + #fmodel.run(args=args2, log=null_out()) + run_program(program_class=fmodel.Program, args=args2) assert os.path.isfile("tst_fmodel_intensity.mtz") mtz_in = file_reader.any_file("tst_fmodel_intensity.mtz") assert mtz_in.file_server.miller_arrays[0].is_xray_intensity_array() try : - fmodel.run(args=args, log=null_out()) + #fmodel.run(args=args, log=null_out()) + run_program(program_class=fmodel.Program, args=args) except Sorry : pass else : raise Exception_expected try : - fmodel.run(args=args+["format=cns"], log=null_out()) + #fmodel.run(args=args+["format=cns"], log=null_out()) + run_program(program_class=fmodel.Program, args=args+["format=cns"], + logger=null_out()) except Sorry : pass else : @@ -110,7 +117,6 @@ def exercise_selection_consistency(): f.write(pdb_str) with open("tst_fmodel_misc.eff", "w") as f: f.write("""\ -pdb_file = tst_fmodel_misc.pdb high_resolution = 1.0 output.file_name = tst_fmodel_misc.mtz generate_fake_p1_symmetry = True @@ -122,7 +128,8 @@ def exercise_selection_consistency(): } } """) - fmodel.run(args=["tst_fmodel_misc.eff"], log=null_out()) + #fmodel.run(args=["tst_fmodel_misc.eff"], log=null_out()) + run_program(program_class=fmodel.Program, args=["tst_fmodel_misc.pdb","tst_fmodel_misc.eff"], logger=null_out()) mtz_in = file_reader.any_file("tst_fmodel_misc.mtz") f_model = mtz_in.file_server.miller_arrays[0] dano = abs(f_model).anomalous_differences() diff --git a/mmtbx/regression/tst_ligand_ncs.py b/mmtbx/regression/tst_ligand_ncs.py index 26f8dff6b5..05c6168fb5 100644 --- a/mmtbx/regression/tst_ligand_ncs.py +++ b/mmtbx/regression/tst_ligand_ncs.py @@ -160,18 +160,17 @@ def make_inputs(prefix="tst_ligand_ncs"): high_resolution = 1.75 r_free_flags_fraction = 0.1 add_sigmas = True - pdb_file = %s random_seed = 12345 output { label = F type = *real complex file_name = %s } - """ % (pdb_in, mtz_in) + """ % mtz_in with open("%s_fmodel.eff" % prefix, "w") as f: f.write(params) assert (easy_run.fully_buffered( - "phenix.fmodel %s_fmodel.eff" % prefix + "phenix.fmodel %s %s_fmodel.eff" % (pdb_in, prefix) ).raise_if_errors().return_code == 0) return pdb_in, mtz_in diff --git a/mmtbx/utils/__init__.py b/mmtbx/utils/__init__.py index 30664f3848..6db471f6e1 100644 --- a/mmtbx/utils/__init__.py +++ b/mmtbx/utils/__init__.py @@ -1260,8 +1260,7 @@ def __init__(self, xray_structure, if(out is None): out = sys.stdout self.add_sigmas = add_sigmas if(params is None): - params = mmtbx.command_line.fmodel.\ - fmodel_from_xray_structure_master_params.extract() + params = mmtbx.programs.fmodel.master_phil.extract() if(r_free_flags_fraction is None): if(params.r_free_flags_fraction is not None): r_free_flags_fraction = params.r_free_flags_fraction From 132c03938dae873aa1dbb61db1957e58e172745d Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Sat, 27 Jan 2024 09:48:13 -0800 Subject: [PATCH 072/748] Refactoring phenix.fmodel part1: code in mmtbx/programs --- mmtbx/programs/fmodel.py | 456 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 456 insertions(+) create mode 100644 mmtbx/programs/fmodel.py diff --git a/mmtbx/programs/fmodel.py b/mmtbx/programs/fmodel.py new file mode 100644 index 0000000000..e7f2940fcb --- /dev/null +++ b/mmtbx/programs/fmodel.py @@ -0,0 +1,456 @@ +from __future__ import absolute_import, division, print_function +from six.moves import zip +try: + from phenix.program_template import ProgramTemplate +except ImportError: + from libtbx.program_template import ProgramTemplate +import os +from libtbx.utils import null_out, Sorry +import mmtbx.maps.polder +from iotbx import crystal_symmetry_from_any +import mmtbx.utils +from iotbx import mrcfile +from libtbx import group_args +from cctbx.array_family import flex +from iotbx import extract_xtal_data +import sys, os +import mmtbx.utils +import iotbx.phil +import iotbx.pdb +from scitbx.array_family import flex +from libtbx import runtime_utils +from libtbx.utils import Sorry +import random + +fmodel_from_xray_structure_params_str = """\ +fmodel + .short_caption = F(model) options + .expert_level = 1 + .style = auto_align box +{ + k_sol = 0.0 + .type = float + .help = Bulk solvent k_sol values + .short_caption=Bulk solvent K_sol value + b_sol = 0.0 + .type = float + .help = Bulk solvent b_sol values + .short_caption=Bulk solvent B_sol value + b_cart = 0 0 0 0 0 0 + .type = floats(6) + .help = Anisotropic scale matrix + .input_size = 200 + .short_caption = Anisotropic scale matrix + scale = 1.0 + .type = float + .help = Overall scale factor +} +structure_factors_accuracy + .short_caption = Structure factors accuracy + .style = auto_align box +{ + include scope mmtbx.f_model.sf_and_grads_accuracy_master_params +} +mask + .short_caption = Bulk solvent mask + .style = auto_align box +{ + include scope mmtbx.masks.mask_master_params +} +""" + + +master_phil_str = ''' +include scope libtbx.phil.interface.tracking_params +high_resolution = None + .type = float + .expert_level=1 + .style = noauto bold +low_resolution = None + .type = float + .expert_level=1 + .style = noauto +r_free_flags_fraction = None + .type = float + .expert_level=1 + .style = noauto +add_sigmas = False + .type = bool + .expert_level=1 + .help = Adds calculated Sigma(F) column to output file. + .style = noauto +add_random_error_to_amplitudes_percent = None + .type = float + .short_caption = Add random error (percent) + .style = noauto +scattering_table = wk1995 it1992 *n_gaussian neutron electron + .type = choice + .help = Choices of scattering table for structure factors calculations. \ + n_gaussian is the standard set of X-ray scattering factors. + .expert_level=1 + .style = noauto +custom_scattering_factors = None + .type = path + .help = Use custom scattering factors and replaces default values entirely +%s +random_seed=None + .type = int + .help = Random seed + .expert_level=2 +twin_law = None + .type = str + .help = Optional twin law if we want to generate a twinned dataset + .input_size = 120 + .style = noauto +twin_fraction = None + .type = float + .help = Twin fraction, ignored if twin_law is not specified + .style = noauto +wavelength = None + .type = float + .input_size = 80 + .help = Wavelength, sets all atoms to anomalous + .style = noauto +generate_fake_p1_symmetry = False + .type = bool + .short_caption = Generate fake symmetry if necessary + .help = Allows use of PDB files without CRYST1 records as input. The \ + crystal symmetry will be assumed to be a P1 box. +output + .short_caption = Reflection output + .expert_level=0 + .style = noauto +{ + format = *mtz cns + .type = choice + .short_caption = File format + label = FMODEL + .type = str + .short_caption = Data label + .input_size = 100 + type = real *complex + .type = choice + .short_caption = Output data type + .help = Numeric type of output data. 'real' is amplitudes only, \ + 'complex' is complete structure factors as complex numbers. + .expert_level=1 + .style = bold + obs_type = *amplitudes intensities + .type = choice + .help = Experimental observation type to output. Certain restrictions \ + apply if intensities are selected. + .expert_level = 2 + file_name = None + .type = path + .short_caption = Output file + .style = bold noauto new_file + include scope libtbx.phil.interface.tracking_params +} +anomalous_scatterers + .short_caption = Anomalous sites + .style = menu_item noauto +{ + group + .optional = True + .multiple = True + .short_caption = Anomalous scatterer group + .style = auto_align + { + selection = None + .type = atom_selection + .short_caption = Atom selection + .input_size = 400 + f_prime = 0 + .type = float + .short_caption = f' + f_double_prime = 0 + .type = float + .short_caption = f'' + } +} +'''%fmodel_from_xray_structure_params_str + +fmodel_from_xray_structure_params = iotbx.phil.parse( + fmodel_from_xray_structure_params_str, process_includes=True) + +#master_phil = fmodel_from_xray_structure_master_params # XXX for phenix docs + +master_phil = iotbx.phil.parse(master_phil_str, process_includes = True) + +#pdb_file = None +# .type = path +# .multiple = True +# .optional = True +# .short_caption = Model file +# .style = bold noauto file_type:pdb input_file OnChange:update_output_file_name +#reference_file = None +# .type = path +# .short_caption = Reference set +# .help = Reflections file containing Miller indices (h,k,l) to use in output \ +# file. +# .style = noauto input_file file_type:mtz OnChange:update_reference_column_labels +#data_column_label = None +# .type = str +# .short_caption = Reference file label +# .style = noauto renderer:draw_any_label_widget + +def set_fp_fdp_for_anomalous_scatterers(pdb_hierarchy, xray_structure, + anomalous_scatterer_groups): + scatterers = xray_structure.scatterers() + for group in anomalous_scatterer_groups: + iselection = pdb_hierarchy.atom_selection_cache().selection( + string = group.selection).iselection() + if(iselection.size() == 0): + raise Sorry( + "Empty selection: selection string '%s' does not select any atom."% + group.selection) + for i_seq in iselection: + scatterers[i_seq].fp = group.f_prime + scatterers[i_seq].fdp = group.f_double_prime + +# ============================================================================= + +class Program(ProgramTemplate): + + description = ''' +phenix.fmodel: a tool to compute structure factors, Fmodel: + + Fmodel = scale * exp(AnisoScale) * (Fcalc + k_sol * exp(-b_sol*s^2/4) * Fmask) + + where: + + - Fmodel - total model structure factor (complex value) + - AnisoScale = -ht*A(-1)*b_cart*A(-1)th/4 + - h - column vector with Miller indices + - A - orthogonalization matrix + - b_cart - anisotropic scale matrix + - t and (-1) denotes transposition and inversion operations + - scale - overall scale factor + - Fcalc - structure factors calculated from atomic model + - k_sol and b_sol - Flat Bulk solvent model parameters + - Fmask - structure factors calculated from bulk solvent mask + +Usage examples: + + 1) phenix.fmodel model.pdb high_resolution=1.5 + + will result in a file containing complete set of Fmodel = Fcalc computed + from atomic model up to 1.5A resolution. + + 2) phenix.fmodel model.pdb scale=2 k_sol=0.35 b_sol=50 b_cart="1 2 3 0 4 7" high_res=1.5 low_res=10 + + will result in a file containing complete set of Fmodel computed using the + above formula in resolution range 1.5-20.0A. + + 3) phenix.fmodel model.pdb high_resolution=1.5 algorithm=direct + + is similar to "1)" but the Fcalc are computed using direct summation algorithm. + + 4) phenix.fmodel model.pdb high_res=1.5 format=cns label=FOBS type=real r_free=0.1 + + will result in CNS formatted file containing complete set of amplitudes of + Fmodel = Fcalc computed up to 1.5A resolution, labelled as FOBS, and free-R + flags with 10% of test reflections. This is a typical command to simulate Fobs. + + 5) phenix.fmodel model.pdb high_res=1.5 scattering_table=neutron + + will result in a file containing complete set of Fmodel = Fcalc computed + from atomic model up to 1.5A resolution using neutron scattering table. + + 6) phenix.fmodel model.pdb parameters.txt + + will result in a structure factor file, where Fmodel were computed using + parameters defined in parameters.txt file. The parameters.txt file can + contain all or any subset of parameters listed below. Note, that each { + must have a matching one }. + + 7) phenix.fmodel model.pdb reflection_data.mtz + + will result in a file containing a set of Fmodel = Fcalc that will match + the set of Miller indices of the data in reflection_data.mtz file. + + 8) phenix.fmodel model.pdb reflection_data.mtz data_column_label="FOBS,SIGMA" + + similar to "7)", where the specific data array is selected. + + 9) phenix.fmodel model.pdb reflection_data.mtz twin_law="l,-k,h" twin_fraction=0.3 + + generates twin data set (real type) with given twin law and fraction. + +See below for complete list of available parameters. +''' + + datatypes = ['model', 'phil', 'miller_array'] + + master_phil_str = master_phil_str + known_article_ids = ['phenix.polder'] + + # --------------------------------------------------------------------------- + + def validate(self): + print('Validating inputs:\n', file=self.logger) + self.data_manager.has_models( + raise_sorry = True, + expected_n = 1, + exact_count = True) + if len(self.data_manager.get_miller_array_names()) > 1: + raise Sorry('Please supply at most one reflection file.') + if self.data_manager.has_miller_arrays(): + if([self.params.high_resolution, self.params.low_resolution].count(None) != 2): + raise Sorry("high_resolution and low_resolution must be undefined "+ + "if reflection data file is given.") + if len(self.data_manager.get_miller_array_user_selected_labels()) > 1: + raise Sorry('Supply not more than one label name.') + else: + if (self.params.high_resolution is None): + raise Sorry("Input data file or high_resolution has to be provided.") + + if (self.params.output.type == "complex") and (self.params.add_sigmas): + raise Sorry("Sigma values only supported when the output type is 'real'.") + if (self.params.low_resolution is not None + and self.params.high_resolution is not None): + if self.params.low_resolution < self.params.high_resolution : + raise Sorry("Low-resolution cutoff must be larger than the high-"+ + "resolution cutoff.") + if (self.params.output.obs_type == "intensities"): + if (self.params.output.type == "complex"): + raise Sorry("Output type must be 'real' when intensities specified "+ + "for obs_type.") + if (not self.params.output.label.upper().startswith("I")): + raise Sorry("Output label must start with 'I' (any case) when "+ + "intensities specified for obs_type (was: %s)." % self.params.output.label) + if (self.params.output.format != "mtz"): + raise Sorry("Output format must be 'mtz' when intensities specified.") + if (self.params.wavelength is not None): + if (self.params.scattering_table == "neutron"): + raise Sorry("Wavelength parameter not supported when the neutron "+ + "scattering table is used.") + + +#def validate_params(params, callback=None): +# if len(params.pdb_file) == 0 : +# raise Sorry("You must provide at least one model file to use for "+ +# "F(model) calculations.") +# if (params.high_resolution is None): +# if (params.reference_file is None): +# raise Sorry("Please specify a high-resolution cutoff.") +# elif (params.reference_file is not None): +# if (params.data_column_label is None): +# raise Sorry("Please select a column label to use in the reference "+ +# "data file.") +# elif ([params.high_resolution, params.low_resolution].count(None) != 2): +# raise Sorry("High resolution and low resolution must be undefined "+ +# "if reflection data file is given.") +# if (params.output.file_name is None): +# raise Sorry("Please specify an output file.") +# validate_params_command_line(params) + + + # --------------------------------------------------------------------------- + + def run(self): + + print('Parameters to compute Fmodel:', file=self.logger) + # TODO print processed non defaults from phil + + print('Using model file:', self.data_manager.get_default_model_name(), + file=self.logger) + + mo = self.data_manager.get_model() + cs = mo.crystal_symmetry() + + miller_array = None + if self.data_manager.has_miller_arrays(): + print('Using reflection file:', + self.data_manager.get_default_miller_array_name(), + file=self.logger) + user_selected_labels = self.data_manager.get_miller_array_user_selected_labels() + if not user_selected_labels: user_selected_labels = None + miller_arrays = self.data_manager.get_miller_arrays( + labels=user_selected_labels) + data_sizes = flex.int([ma.data().size() for ma in miller_arrays]) + if(data_sizes.all_eq(data_sizes[0])): miller_array = miller_arrays[0] + else: + raise Sorry('Reflection file contains arrays of different lengths. \ + Please select one using "labels.name=" keyword.') + miller_array = miller_arrays[0] + assert(miller_array is not None) + miller_array.show_comprehensive_summary(f = self.logger, prefix=" ") + miller_array = miller_array.map_to_asu().customized_copy( + data = flex.double(miller_array.data().size(), 1)) + cs_from_ma = miller_array.crystal_symmetry() + if (self.params.generate_fake_p1_symmetry and cs_from_ma is not None): + raise Sorry("The reflection data already define crystal symmetry; "+ + "you may not use this in combination with the option "+ + "generate_fake_p1_symmetry=True.") + if cs is None: + cs = cs_from_ma + + if not self.params.generate_fake_p1_symmetry: + msg = '''Symmetry information in model file is incomplete or missing. +If you want the program to generate P1 symmetry automatically, set +generate_fake_p1_symmetry=True.''' + if not cs: raise Sorry(msg) + elif cs.is_incomplete(): raise Sorry(msg) + else: + print('\nGenerating fake P1 symmetry', file=self.logger) + + pdb_hierarchy = mo.get_hierarchy() + # need to preserve the order in the hierarchy in case we have to perform an + # atom selection later + # if cs is None, this will create a fake box, not sure how to get the same + # box via model obj directly + xray_structure = pdb_hierarchy.extract_xray_structure(crystal_symmetry = cs) + if (cs is None): cs = xray_structure.crystal_symmetry() + print('\nCrystal symmetry used: ', file=self.logger) + cs.show_summary() + + if (miller_array is not None): + if (miller_array.crystal_symmetry() is None): + miller_array = miller_array.customized_copy(crystal_symmetry=cs) + xray_structure.show_summary(f = self.logger, prefix=' ') + if(len(self.params.anomalous_scatterers.group) != 0): + pdb_atoms = pdb_hierarchy.atoms() + pdb_atoms.reset_i_seq() + set_fp_fdp_for_anomalous_scatterers( + pdb_hierarchy = pdb_hierarchy, + xray_structure = xray_structure, + anomalous_scatterer_groups = self.params.anomalous_scatterers.group) + elif (self.params.wavelength is not None): + print("Setting inelastic form factors for wavelength = %g" % \ + self.params.wavelength, file=self.logger) + xray_structure.set_inelastic_form_factors( + photon=self.params.wavelength, + table="sasaki") + + if(self.params.random_seed is not None): + random.seed(self.params.random_seed) + flex.set_random_seed(self.params.random_seed) + + print("-"*79, file=self.logger) + print("Computing model structure factors, Fmodel:", file=self.logger) + if(self.params.output.format == "cns"): extension = ".hkl" + elif(self.params.output.format == "mtz"): extension = ".mtz" + ofn = self.params.output.file_name + if(ofn is None): + ofn = os.path.basename(self.data_manager.get_default_model_name()) + ofn = ofn + extension + + use_custom_scattering_dictionary = False + if self.params.custom_scattering_factors: + use_custom_scattering_dictionary = True + mmtbx.utils.fmodel_from_xray_structure( + xray_structure = xray_structure, + f_obs = miller_array, + add_sigmas = self.params.add_sigmas, + params = self.params, + twin_law = self.params.twin_law, + twin_fraction = self.params.twin_fraction, + use_custom_scattering_dictionary = use_custom_scattering_dictionary, + out = self.logger).write_to_file(file_name = ofn, + obs_type=self.params.output.obs_type) + print("Output file name:", ofn, file=self.logger) + print("All done.", file=self.logger) + print("-"*79, file=self.logger) + return ofn + From 1119ec35341d38cbd68ec9709f537686f7957d35 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Sat, 27 Jan 2024 10:19:19 -0800 Subject: [PATCH 073/748] Refactoring phenix.fmodel part1: cleanup unused imports. --- mmtbx/programs/fmodel.py | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/mmtbx/programs/fmodel.py b/mmtbx/programs/fmodel.py index e7f2940fcb..4888c8e052 100644 --- a/mmtbx/programs/fmodel.py +++ b/mmtbx/programs/fmodel.py @@ -1,26 +1,15 @@ from __future__ import absolute_import, division, print_function -from six.moves import zip try: from phenix.program_template import ProgramTemplate except ImportError: from libtbx.program_template import ProgramTemplate import os -from libtbx.utils import null_out, Sorry -import mmtbx.maps.polder -from iotbx import crystal_symmetry_from_any -import mmtbx.utils -from iotbx import mrcfile -from libtbx import group_args -from cctbx.array_family import flex -from iotbx import extract_xtal_data -import sys, os import mmtbx.utils import iotbx.phil import iotbx.pdb -from scitbx.array_family import flex -from libtbx import runtime_utils -from libtbx.utils import Sorry import random +from libtbx.utils import Sorry +from cctbx.array_family import flex fmodel_from_xray_structure_params_str = """\ fmodel @@ -59,7 +48,6 @@ } """ - master_phil_str = ''' include scope libtbx.phil.interface.tracking_params high_resolution = None @@ -173,8 +161,6 @@ fmodel_from_xray_structure_params = iotbx.phil.parse( fmodel_from_xray_structure_params_str, process_includes=True) -#master_phil = fmodel_from_xray_structure_master_params # XXX for phenix docs - master_phil = iotbx.phil.parse(master_phil_str, process_includes = True) #pdb_file = None @@ -283,7 +269,6 @@ class Program(ProgramTemplate): datatypes = ['model', 'phil', 'miller_array'] master_phil_str = master_phil_str - known_article_ids = ['phenix.polder'] # --------------------------------------------------------------------------- @@ -326,7 +311,7 @@ def validate(self): raise Sorry("Wavelength parameter not supported when the neutron "+ "scattering table is used.") - +# For GUI #def validate_params(params, callback=None): # if len(params.pdb_file) == 0 : # raise Sorry("You must provide at least one model file to use for "+ @@ -453,4 +438,3 @@ def run(self): print("All done.", file=self.logger) print("-"*79, file=self.logger) return ofn - From 640db5a71ea219caac44596a2ac5610522f663da Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Sat, 27 Jan 2024 10:37:01 -0800 Subject: [PATCH 074/748] Refactoring phenix.fmodel part1: now a previously commented test works. Reactivating it. --- mmtbx/regression/tst_fmodel_no_cryst1.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/mmtbx/regression/tst_fmodel_no_cryst1.py b/mmtbx/regression/tst_fmodel_no_cryst1.py index f8b7946fa6..6096df9559 100644 --- a/mmtbx/regression/tst_fmodel_no_cryst1.py +++ b/mmtbx/regression/tst_fmodel_no_cryst1.py @@ -1,6 +1,8 @@ - from __future__ import absolute_import, division, print_function from libtbx import easy_run +from mmtbx.programs import fmodel +from iotbx.cli_parser import run_program +from libtbx.utils import null_out, Sorry import os def exercise(): @@ -31,11 +33,14 @@ def exercise(): from iotbx import crystal_symmetry_from_any symm = crystal_symmetry_from_any.extract_from("tmp_fmodel_fake_p1.mtz") assert (str(symm.space_group_info()) == "P 1") - # FIXME this should fail but doesn't due to a bug in the program - #args.append("reference_file=tmp_fmodel_fake_p1.mtz") - #args.append("data_column_label=FMODEL,PHIFMODEL") - #result = easy_run.fully_buffered(args).raise_if_errors() - #print result.return_code + args.append("tmp_fmodel_fake_p1.mtz") + args.append("labels.name=FMODEL,PHIFMODEL") + try : + run_program(program_class=fmodel.Program, args=args, logger=null_out()) + except Sorry : + pass + else : + raise Exception_expected print("OK") if (__name__ == "__main__"): From 39b0aa19e6c91db58ddbb86285be92bbda0b4189 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Sat, 27 Jan 2024 10:39:09 -0800 Subject: [PATCH 075/748] Refactoring phenix.fmodel part1: more cleanup --- mmtbx/regression/tst_fmodel_misc.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/mmtbx/regression/tst_fmodel_misc.py b/mmtbx/regression/tst_fmodel_misc.py index f70dabdbc9..db38879017 100644 --- a/mmtbx/regression/tst_fmodel_misc.py +++ b/mmtbx/regression/tst_fmodel_misc.py @@ -1,10 +1,9 @@ from __future__ import absolute_import, division, print_function from mmtbx.regression import make_fake_anomalous_data -#from mmtbx.command_line import fmodel from mmtbx.programs import fmodel -from iotbx import file_reader from iotbx.cli_parser import run_program +from iotbx import file_reader from cctbx import miller from scitbx.array_family import flex from libtbx.test_utils import approx_equal, Exception_expected @@ -28,7 +27,6 @@ def exercise(): "output.file_name=tst_fmodel_anomalous.mtz", "r_free_flags_fraction=0.1", ] - #fmodel.run(args=args, log=null_out()) run_program(program_class=fmodel.Program, args=args, logger=null_out()) assert os.path.isfile("tst_fmodel_anomalous.mtz") mtz_in = file_reader.any_file("tst_fmodel_anomalous.mtz") @@ -58,20 +56,17 @@ def exercise_intensity_output(): "r_free_flags_fraction=0.1", ] args2 = args + ["label=Imodel"] - #fmodel.run(args=args2, log=null_out()) run_program(program_class=fmodel.Program, args=args2) assert os.path.isfile("tst_fmodel_intensity.mtz") mtz_in = file_reader.any_file("tst_fmodel_intensity.mtz") assert mtz_in.file_server.miller_arrays[0].is_xray_intensity_array() try : - #fmodel.run(args=args, log=null_out()) run_program(program_class=fmodel.Program, args=args) except Sorry : pass else : raise Exception_expected try : - #fmodel.run(args=args+["format=cns"], log=null_out()) run_program(program_class=fmodel.Program, args=args+["format=cns"], logger=null_out()) except Sorry : @@ -128,7 +123,6 @@ def exercise_selection_consistency(): } } """) - #fmodel.run(args=["tst_fmodel_misc.eff"], log=null_out()) run_program(program_class=fmodel.Program, args=["tst_fmodel_misc.pdb","tst_fmodel_misc.eff"], logger=null_out()) mtz_in = file_reader.any_file("tst_fmodel_misc.mtz") f_model = mtz_in.file_server.miller_arrays[0] From 82a3678137d62a2a1c33df0e99a45222801ec632 Mon Sep 17 00:00:00 2001 From: terwill Date: Sat, 27 Jan 2024 12:12:35 -0700 Subject: [PATCH 076/748] Print out problem category --- libtbx/command_line/find_pdb_mmcif_problems.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libtbx/command_line/find_pdb_mmcif_problems.py b/libtbx/command_line/find_pdb_mmcif_problems.py index c28672751c..b09e6f9d07 100644 --- a/libtbx/command_line/find_pdb_mmcif_problems.py +++ b/libtbx/command_line/find_pdb_mmcif_problems.py @@ -235,7 +235,8 @@ def run(args, n_context = 7, overall_exclude = None): def display_problem(p, out = sys.stdout): - print("%s Line: %s\n" %(p.file_name,p.line_number)+ 70*"-", file = out) + print("%s Line: %s :: %s\n" %( + p.file_name,p.line_number,p.category)+ 70*"-", file = out) sw = [p.search_word, p.required_word] if None in sw: sw.remove(None) next_ending = None From cd93a5fb7810dc232915397da1170cb1f1ffc157 Mon Sep 17 00:00:00 2001 From: terwill Date: Sat, 27 Jan 2024 12:42:12 -0800 Subject: [PATCH 077/748] Write output of pdbtools to mmcif if it does not fit in pdb format --- mmtbx/programs/pdbtools.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/mmtbx/programs/pdbtools.py b/mmtbx/programs/pdbtools.py index 5b2c278239..05934ae68d 100644 --- a/mmtbx/programs/pdbtools.py +++ b/mmtbx/programs/pdbtools.py @@ -68,8 +68,13 @@ def run(self): # Write output model file input_file_name_base = os.path.basename( self.data_manager.get_default_model_name())[:-4] - if( self.model.input_model_format_cif()): extension = ".cif" + if( self.model.input_model_format_cif()) or ( + not self.model.can_be_output_as_pdb()): + extension = ".cif" elif(self.model.input_model_format_pdb()): extension = ".pdb" + else: + assert self.model.input_model_format_pdb() or \ + self.model.input_model_format_cif() if(self.params.output.prefix is not None): output_file_name = self.params.output.prefix if(self.params.output.suffix is not None): @@ -81,9 +86,10 @@ def run(self): prefix=output_file_name, suffix=None, serial=Auto) - print('Writing output model', file=self.logger) + print('Writing output model to %s' %ofn, file=self.logger) output_cs=True if(cs is None): output_cs = False + self.data_manager.write_model_file(self.model.model_as_str( output_cs=output_cs), ofn) self.result = ofn From a1949b07a31cc9ab3cf7cc455b9b542e5f37b3ea Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Sat, 27 Jan 2024 15:32:58 -0800 Subject: [PATCH 078/748] More phenix.fmodel updates - clean clutter --- libtbx/command_line/find_pdb_mmcif_problems.py | 1 - mmtbx/command_line/simulate_low_res_data.py | 6 +++--- mmtbx/refinement/tst_rigid_body.py | 1 - mmtbx/regression/model_idealization/tst_with_mtz.py | 2 +- mmtbx/utils/__init__.py | 1 + simtbx/diffBragg/utils.py | 6 +++--- simtbx/nanoBragg/tst_gauss_argchk.py | 4 ++-- xfel/cxi/command_line/einsle.py | 4 ++-- xfel/cxi/display_powder_arcs.py | 4 ++-- xfel/merging/application/model/crystal_model.py | 5 ++--- xfel/merging/general_fcalc.py | 6 +++--- 11 files changed, 19 insertions(+), 21 deletions(-) diff --git a/libtbx/command_line/find_pdb_mmcif_problems.py b/libtbx/command_line/find_pdb_mmcif_problems.py index b09e6f9d07..41b11747d0 100644 --- a/libtbx/command_line/find_pdb_mmcif_problems.py +++ b/libtbx/command_line/find_pdb_mmcif_problems.py @@ -1,6 +1,5 @@ from __future__ import absolute_import, division, print_function import os, sys -from libtbx import group_args from libtbx.utils import display_context diff --git a/mmtbx/command_line/simulate_low_res_data.py b/mmtbx/command_line/simulate_low_res_data.py index bc6d86334f..d739a35853 100644 --- a/mmtbx/command_line/simulate_low_res_data.py +++ b/mmtbx/command_line/simulate_low_res_data.py @@ -141,7 +141,7 @@ fake_data_from_fmodel .help = Options for generating model-based reflections using phenix.fmodel. { - include scope mmtbx.command_line.fmodel.fmodel_from_xray_structure_params + include scope mmtbx.programs.fmodel.fmodel_from_xray_structure_params } } """, process_includes=True) @@ -386,9 +386,9 @@ def from_pdb(self): pdb_hierarchy.atoms().set_adps_from_scatterers( scatterers=xray_structure.scatterers(), unit_cell=xray_structure.unit_cell()) - import mmtbx.command_line.fmodel + import mmtbx.programs.fmodel from mmtbx import utils - fmodel_params = mmtbx.command_line.fmodel.fmodel_from_xray_structure_master_params.extract() + fmodel_params = mmtbx.programs.fmodel.master_phil.extract() fmodel_params.high_resolution = params.d_min fake_data = params.fake_data_from_fmodel fmodel_params.fmodel = fake_data.fmodel diff --git a/mmtbx/refinement/tst_rigid_body.py b/mmtbx/refinement/tst_rigid_body.py index 55a983f74a..731a1dc56c 100644 --- a/mmtbx/refinement/tst_rigid_body.py +++ b/mmtbx/refinement/tst_rigid_body.py @@ -12,7 +12,6 @@ import mmtbx.utils import iotbx.pdb from scitbx import matrix -import mmtbx.command_line.fmodel import scitbx.rigid_body from six.moves import range diff --git a/mmtbx/regression/model_idealization/tst_with_mtz.py b/mmtbx/regression/model_idealization/tst_with_mtz.py index 4e361cce3b..a79d482e52 100644 --- a/mmtbx/regression/model_idealization/tst_with_mtz.py +++ b/mmtbx/regression/model_idealization/tst_with_mtz.py @@ -6,7 +6,7 @@ import iotbx from mmtbx.utils import fmodel_from_xray_structure from mmtbx.secondary_structure.build.tst_2 import tst_01_start_lines -import mmtbx.command_line.fmodel +import mmtbx.programs.fmodel def exercise_01(prefix="tst_mi_mtz_01"): """ diff --git a/mmtbx/utils/__init__.py b/mmtbx/utils/__init__.py index 6db471f6e1..5fe47c7016 100644 --- a/mmtbx/utils/__init__.py +++ b/mmtbx/utils/__init__.py @@ -45,6 +45,7 @@ import mmtbx.tls.tools from mmtbx.scaling import outlier_rejection import mmtbx.command_line.fmodel +import mmtbx.programs.fmodel import libtbx.callbacks # import dependency from libtbx.math_utils import ifloor, iceil from cctbx import maptbx diff --git a/simtbx/diffBragg/utils.py b/simtbx/diffBragg/utils.py index 28e7857820..d8c439e26d 100644 --- a/simtbx/diffBragg/utils.py +++ b/simtbx/diffBragg/utils.py @@ -25,7 +25,7 @@ import libtbx from libtbx.phil import parse from dials.array_family import flex as dials_flex -import mmtbx.command_line.fmodel +import mmtbx.programs.fmodel import mmtbx.utils from cctbx.eltbx import henke from simtbx.diffBragg import psf @@ -930,7 +930,7 @@ def get_complex_fcalc_from_pdb( dmax=None, k_sol=0.435, b_sol=46, show_pdb_summary=False): """ - produce a structure factor from PDB coords, see mmtbx/command_line/fmodel.py for formulation + produce a structure factor from PDB coords, see mmtbx/programs/fmodel.py for formulation k_sol, b_sol form the solvent component of the Fcalc: Fprotein + k_sol*exp(-b_sol*s^2/4) (I think) """ import iotbx.pdb @@ -943,7 +943,7 @@ def get_complex_fcalc_from_pdb( expected_henke = henke.table(sc.element_symbol()).at_angstrom(wavelength) sc.fp = expected_henke.fp() sc.fdp = expected_henke.fdp() - phil2 = mmtbx.command_line.fmodel.fmodel_from_xray_structure_master_params + phil2 = mmtbx.programs.fmodel.master_phil params2 = phil2.extract() params2.high_resolution = dmin params2.low_resolution = dmax diff --git a/simtbx/nanoBragg/tst_gauss_argchk.py b/simtbx/nanoBragg/tst_gauss_argchk.py index 91ba3043ff..c87f7e4ee3 100644 --- a/simtbx/nanoBragg/tst_gauss_argchk.py +++ b/simtbx/nanoBragg/tst_gauss_argchk.py @@ -155,8 +155,8 @@ def get_amplitudes(self, at_angstrom): sc.fp = expected_henke.fp() sc.fdp = expected_henke.fdp() - import mmtbx.command_line.fmodel - phil2 = mmtbx.command_line.fmodel.fmodel_from_xray_structure_master_params + import mmtbx.programs.fmodel + phil2 = mmtbx.programs.fmodel.master_phil params2 = phil2.extract() params2.high_resolution = 1.6 params2.fmodel.k_sol = 0.35 diff --git a/xfel/cxi/command_line/einsle.py b/xfel/cxi/command_line/einsle.py index bd80a72c6b..4f15811522 100644 --- a/xfel/cxi/command_line/einsle.py +++ b/xfel/cxi/command_line/einsle.py @@ -5,7 +5,7 @@ import iotbx.pdb import string from scitbx.array_family import flex -import mmtbx.command_line.fmodel +import mmtbx.programs.fmodel import mmtbx.f_model """Fit the anomalous scattering parameters f' and f", given the pdb model (for phases) and the @@ -24,7 +24,7 @@ def __init__(self,file_name, d_min, algorithm = "direct", use_solvent=False, plo self.pdb_inp = iotbx.pdb.input(file_name) self.xray_structure = self.pdb_inp.xray_structure_simple() self.xray_structure.show_summary() - phil2 = mmtbx.command_line.fmodel.fmodel_from_xray_structure_master_params + phil2 = mmtbx.programs.fmodel.master_phil params2 = phil2.extract() # adjust the cutoff of the generated intensities to assure that # statistics will be reported to the desired high-resolution limit diff --git a/xfel/cxi/display_powder_arcs.py b/xfel/cxi/display_powder_arcs.py index 6ff26ce8fd..75ad4c1052 100644 --- a/xfel/cxi/display_powder_arcs.py +++ b/xfel/cxi/display_powder_arcs.py @@ -1,7 +1,7 @@ from __future__ import absolute_import, division, print_function from six.moves import range import math -import mmtbx.command_line.fmodel +import mmtbx.programs.fmodel import mmtbx.utils import iotbx.pdb.fetch from iotbx import pdb @@ -24,7 +24,7 @@ def get_mmtbx_icalc(code,d_min, anomalous_flag = False): xray_structure = pdb_input.xray_structure_simple() - phil2 = mmtbx.command_line.fmodel.fmodel_from_xray_structure_master_params + phil2 = mmtbx.programs.fmodel.master_phil params2 = phil2.extract() # adjust the cutoff of the generated intensities to assure that # statistics will be reported to the desired high-resolution limit diff --git a/xfel/merging/application/model/crystal_model.py b/xfel/merging/application/model/crystal_model.py index 44918ac304..6f758f06f2 100644 --- a/xfel/merging/application/model/crystal_model.py +++ b/xfel/merging/application/model/crystal_model.py @@ -1,8 +1,7 @@ from __future__ import absolute_import, division, print_function from xfel.merging.application.worker import worker -import mmtbx.command_line.fmodel +import mmtbx.programs.fmodel import mmtbx.utils -import libtbx.phil.command_line from cctbx import miller from cctbx.crystal import symmetry import iotbx.pdb @@ -125,7 +124,7 @@ def create_model_from_structure_file(self, model_file_path): self.params.scaling.unit_cell = unit_cell # prepare phil parameters to generate model intensities - phil2 = mmtbx.command_line.fmodel.fmodel_from_xray_structure_master_params + phil2 = mmtbx.programs.fmodel.master_phil params2 = phil2.extract() ''' diff --git a/xfel/merging/general_fcalc.py b/xfel/merging/general_fcalc.py index bbccb0e4a6..fea96564ac 100644 --- a/xfel/merging/general_fcalc.py +++ b/xfel/merging/general_fcalc.py @@ -1,5 +1,5 @@ from __future__ import absolute_import, division, print_function -import mmtbx.command_line.fmodel +import mmtbx.programs.fmodel import mmtbx.utils import iotbx.pdb import libtbx.phil.command_line @@ -27,7 +27,7 @@ def run (params) : pdb_in = iotbx.pdb.input(params.model) xray_structure = pdb_in.xray_structure_simple() xray_structure.show_summary() - phil2 = mmtbx.command_line.fmodel.fmodel_from_xray_structure_master_params + phil2 = mmtbx.programs.fmodel.master_phil params2 = phil2.extract() # adjust the cutoff of the generated intensities to assure that # statistics will be reported to the desired high-resolution limit @@ -93,7 +93,7 @@ def random_structure (params) : elements=elements, min_distance=1.2) xs.show_summary() - phil2 = mmtbx.command_line.fmodel.fmodel_from_xray_structure_master_params + phil2 = mmtbx.programs.fmodel.master_phil params2 = phil2.extract() # adjust the cutoff of the generated intensities to assure that # statistics will be reported to the desired high-resolution limit From e41a6e1357f4e29e4bf0103ebb2239b736ea6e8b Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Mon, 29 Jan 2024 12:21:31 -0800 Subject: [PATCH 079/748] Cleanup --- mmtbx/programs/fmodel.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/mmtbx/programs/fmodel.py b/mmtbx/programs/fmodel.py index 4888c8e052..8c6394424c 100644 --- a/mmtbx/programs/fmodel.py +++ b/mmtbx/programs/fmodel.py @@ -163,22 +163,6 @@ master_phil = iotbx.phil.parse(master_phil_str, process_includes = True) -#pdb_file = None -# .type = path -# .multiple = True -# .optional = True -# .short_caption = Model file -# .style = bold noauto file_type:pdb input_file OnChange:update_output_file_name -#reference_file = None -# .type = path -# .short_caption = Reference set -# .help = Reflections file containing Miller indices (h,k,l) to use in output \ -# file. -# .style = noauto input_file file_type:mtz OnChange:update_reference_column_labels -#data_column_label = None -# .type = str -# .short_caption = Reference file label -# .style = noauto renderer:draw_any_label_widget def set_fp_fdp_for_anomalous_scatterers(pdb_hierarchy, xray_structure, anomalous_scatterer_groups): From 1113bdf7f58145eaab9311b3db4d17d85e513441 Mon Sep 17 00:00:00 2001 From: terwill Date: Mon, 29 Jan 2024 12:35:10 -0800 Subject: [PATCH 080/748] Update to ignore words that are part of another word --- libtbx/command_line/find_pdb_mmcif_problems.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libtbx/command_line/find_pdb_mmcif_problems.py b/libtbx/command_line/find_pdb_mmcif_problems.py index 41b11747d0..ff1bf6865a 100644 --- a/libtbx/command_line/find_pdb_mmcif_problems.py +++ b/libtbx/command_line/find_pdb_mmcif_problems.py @@ -1,6 +1,7 @@ from __future__ import absolute_import, division, print_function import os, sys + from libtbx.utils import display_context @@ -306,7 +307,7 @@ def write_model_file_without_assignment(text, file_name = None, n_context = 7, def pdb_write_statements(text, file_name = None, n_context = 7, overall_exclude = None): all_problems = [] - for search_word in [".model_as_pdb(", ".as_pdb_string(", + for search_word in [".model_as_pdb(", ".as_pdb_string(", # PDB OK ".write_pdb_file("]: all_problems += display_context(file_name = file_name, text = text, n_context = n_context, search_word = search_word,quiet = True, @@ -318,7 +319,7 @@ def pdb_format_interpretation(text, file_name = None, n_context = 7, overall_exclude = None): all_problems = [] for search_word in ['.open(']: - for required_word in ['.pdb"',".pdb'",'pdb_file','model_file']: + for required_word in ['.pdb"',".pdb'",'pdb_file','model_file']: # PDB OK all_problems += display_context(file_name = file_name, text = text, n_context = n_context, search_word = search_word, @@ -335,12 +336,14 @@ def pdb_format_interpretation(text, file_name = None, n_context = 7, 'traceback','phil_string',] + overall_exclude, quiet = True, category = 'pdb_format_interpretation') - for search_word in ['HETATM','ATOM','TER','BREAK',' CA ',' N ']: + for search_word in ['HETATM','"ATOM',"'ATOM",'"TER',"'TER", + '"BREAK',"'BREAK",' CA ',' N ']: # PDB OK for required_word in ['startswith','find(','re.search(']: all_problems += display_context(file_name = file_name, text = text, n_context = n_context, search_word = search_word, required_word=required_word, + excluded_words = ['group_PDB'] + overall_exclude, quiet = True, category = 'pdb_format_interpretation') return all_problems From 41b8da0725ecc9386ec68c194efd4162234269c7 Mon Sep 17 00:00:00 2001 From: Felix Wittwer Date: Mon, 29 Jan 2024 12:54:25 -0800 Subject: [PATCH 081/748] diffBragg: set gpu device only in one place --- simtbx/command_line/stage_two.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/simtbx/command_line/stage_two.py b/simtbx/command_line/stage_two.py index 7df821b6f9..7b2ebaf300 100644 --- a/simtbx/command_line/stage_two.py +++ b/simtbx/command_line/stage_two.py @@ -75,7 +75,6 @@ def run(self): raise ValueError("Pandas table input required") refine_starttime = time.time() - self.params.simulator.device_id = COMM.rank % self.params.refiner.num_devices refiner = ensemble_refine_launcher.global_refiner_from_parameters(self.params) print("Time to refine experiment: %f" % (time.time()- refine_starttime)) @@ -120,8 +119,8 @@ def run(self): else: mpi_logger.setup_logging_from_params(script.params) - dev = COMM.rank % script.params.refiner.num_devices - with DeviceWrapper(dev) as _: + script.params.simulator.device_id = COMM.rank % script.params.refiner.num_devices + with DeviceWrapper(script.params.simulator.device_id) as _: RUN() if lp is not None: From 7a4a9a24002039c62444c12c7262d6a366c93370 Mon Sep 17 00:00:00 2001 From: Felix Wittwer Date: Mon, 29 Jan 2024 12:56:01 -0800 Subject: [PATCH 082/748] clean clutter --- simtbx/command_line/stage_two.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simtbx/command_line/stage_two.py b/simtbx/command_line/stage_two.py index 7b2ebaf300..a58f76e3f9 100644 --- a/simtbx/command_line/stage_two.py +++ b/simtbx/command_line/stage_two.py @@ -119,7 +119,7 @@ def run(self): else: mpi_logger.setup_logging_from_params(script.params) - script.params.simulator.device_id = COMM.rank % script.params.refiner.num_devices + script.params.simulator.device_id = COMM.rank % script.params.refiner.num_devices with DeviceWrapper(script.params.simulator.device_id) as _: RUN() From 7435a7279b44531f443e562fe3f0a9a59126c3d9 Mon Sep 17 00:00:00 2001 From: cschlick Date: Mon, 29 Jan 2024 13:07:12 -0800 Subject: [PATCH 083/748] Major updates to qscore. Extensive testing added. Still a work in progress. --- cctbx/maptbx/qscore.py | 828 +++++++++++++++++---------------- cctbx/maptbx/tst_qscore.py | 931 +++++++++++++++++++++++++------------ cctbx/programs/qscore.py | 68 ++- 3 files changed, 1122 insertions(+), 705 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index bf6c83773e..dd04df81a4 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -2,14 +2,15 @@ This code provides methods to calculate the qscore metric for map-model validation, as developed by Pintile et al. -As with the original implementation, multiple calculation options are provided. -The fastest (default) is to pass an mmtbx map-model-manager (mmm) -to the the function qscore_np, qscore_np(mmm) +Two main modes are provided. + 1. progressive: Allocates probes progressively, and should give identical results to mapq + 2. precalculate: Allocates probes once and rejects. Should give analogous results and is faster. """ from __future__ import division import math import sys +from libtbx.utils import null_out from collections import defaultdict from multiprocessing import Pool, cpu_count from itertools import chain @@ -24,28 +25,6 @@ from scitbx_array_family_flex_ext import bool as flex_bool -class DummyTQDM: - """A 'dummy' object that can be used for compatibility if tqdm is not installed""" - - def __init__(self, iterable=None, *args, **kwargs): - self.iterable = iterable - self.args = args - self.kwargs = kwargs - - def __iter__(self): - return iter(self.iterable) - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, traceback): - pass -try: - from tqdm import tqdm -except ImportError: - tqdm = DummyTQDM - - master_phil_str = """ qscore { @@ -55,11 +34,21 @@ def __exit__(self, exc_type, exc_value, traceback): .help = Number of processors to use .short_caption = Number of processors to use .expert_level = 1 - n_probes = 8 + n_probes_target = 8 .type = int .help = Number of radial probes to use .short_caption = Number of radial probes to use .expert_level = 1 + n_probes_max = 16 + .type = int + .help = Max number of radial probes to use + .short_caption = Number of radial probes to use + .expert_level = 1 + n_probes_min = 4 + .type = int + .help = Min number of radial probes to use + .short_caption = Number of radial probes to use + .expert_level = 1 selection = None .type = str .help = Only test atoms within this selection @@ -84,6 +73,15 @@ def __exit__(self, exc_type, exc_value, traceback): .short_caption = The number of radial shells (includes start/stop, so minimum 2) .expert_level = 1 + shells = None + .type = float + .multiple = True + .help = Explicitly provide radial shells + + rtol = 0.9 + .type = float + .help = Mapq rtol value, the "real" shell radii are r*rtol + probe_allocation_method = precalculate .type = str .help = The method used to allocate radial probes @@ -108,364 +106,450 @@ def __exit__(self, exc_type, exc_value, traceback): """ +def get_probe_mask(atom_tree,probes_xyz,r=None,expected=None,log=null_out(),debug=False): + """ + atoms_xyz shape (n_atoms,3) + probes_xyz shape (n_atoms,n_probes,3) -def radial_shell_worker_v1_np(args): - """ - Calulate qscore for a single radial shell using version 1 (serial probe allocation) and numpy - """ - ( - i, - atoms_xyz, - n_probes, - radius_shell, - tree, - rtol, - selection, - n_probes_target, - ) = args - - # - # manage selection input - if selection is None: - selection = np.arange(len(atoms_xyz)) - else: - assert selection.dtype == bool - # do selection - atoms_xyz_sel = atoms_xyz[selection] - # print("sel_shape",atoms_xyz_sel.shape) - n_atoms = atoms_xyz_sel.shape[0] - - if radius_shell == 0: - radius_shell = 1e-9 # zero causes crash - numPts = n_probes_target - RAD = radius_shell - outRAD = rtol - all_pts = [] # list of probe arrays for each atom - probe_xyz_r = np.full((n_atoms, n_probes_target, 3), -1.0) - # print(atoms_xyz_sel) - # print("n_atoms",n_atoms) - for atom_i in range(n_atoms): - coord = atoms_xyz_sel[atom_i] - # print("atom_i",atom_i) - # print("coord:",coord) - pts = [] - - # try to get at least [numPts] points at [RAD] distance - # from the atom, that are not closer to other atoms - for i in range(0, 50): - # if we find the necessary number of probes in the first iteration, then i will never go to 1 - # points on a sphere at radius RAD... - n_pts_to_grab = ( - numPts + i * 2 - ) # progressively more points are grabbed with each failed iter - # print("n_to_grab:",n_pts_to_grab) - - outPts = sphere_points_np( - coord[None, :], RAD, n_pts_to_grab - ) # get the points - outPts = outPts.reshape(-1, 3) - at_pts, at_pts_i = [None] * len(outPts), 0 - # print("probe candidates") - - for pt_i, pt in enumerate( - outPts - ): # identify which ones to keep, progressively grow pts list - # print(f"\t{pt[0]},{pt[1]},{pt[2]}") - # query kdtree to find probe-atom interactions - counts = tree.query_ball_point( - pt[None, :], RAD * outRAD, return_length=True - ) - - # each value in counts is the number of atoms within radius+tol of each probe - count = counts.flatten()[0] - ptsNear = count - - if ptsNear == 0: - at_pts[at_pts_i] = pt - at_pts_i += 1 - # if at_pts_i >= numPts: - # break - - if ( - at_pts_i >= numPts - ): # if we have enough points, take all the "good" points from this iter - pts.extend(at_pts[0:at_pts_i]) - break - # assert len(pts)>0, "Zero probes were found " - pts = np.array(pts) # should be shape (n_probes,3) - all_pts.append(pts) - - # prepare output - n_atoms = len(atoms_xyz) - for i, r in enumerate(all_pts): - if r.ndim == 2 and len(r) > 0: - probe_xyz_r[i, :n_probes, :] = r[:n_probes_target, :] - - keep_sel = probe_xyz_r != -1.0 - keep_sel = np.mean(keep_sel, axis=-1, keepdims=True) - keep_sel = np.squeeze(keep_sel, axis=-1) - - return probe_xyz_r, keep_sel.astype(bool) - - -def radial_shell_worker_v2_np(args): - """ - Calulate qscore for a single radial shell using version 2 (parallel probe allocation) and numpy - """ - # unpack args - i, atoms_xyz, n_probes, radius_shell, tree, rtol, selection = args + If expected is None, infer atom indices from probes_xyz + Else expected should be a single value, or have shape (n_atoms,n_probes) - # manage selection input - if selection is None: - selection = np.arange(len(atoms_xyz)) - else: - #assert selection.dtype == bool - pass + """ - # do selection - atoms_xyz_sel = atoms_xyz[selection] - n_atoms = atoms_xyz_sel.shape[0] + assert r is not None, "Provide a radius" + assert probes_xyz.ndim ==3 and probes_xyz.shape[-1] == 3, "Provide probes_xyz as shape: (n_atoms,n_probes,3)" + n_atoms_probe,n_probes,_ = probes_xyz.shape + dim = probes_xyz.shape[-1] # 3 for cartesian coords - # get probe coordinates - probe_xyz = sphere_points_np(atoms_xyz_sel, radius_shell, n_probes) - - counts = tree.query_ball_point( - probe_xyz, radius_shell * rtol, return_length=True - ) # atom counts for each probe, for probes in shape (n_atoms,n_probes) - probe_mask = ( - counts == 0 - ) # keep probes with 0 nearby atoms. The rtol ensures self is not counted - return probe_xyz, probe_mask + # reshaped_probes shape (n_atoms*n_probes,3) + reshaped_probes = probes_xyz.reshape(-1, 3) + atom_indices = np.tile(np.arange(n_atoms_probe), (probes_xyz.shape[1], 1)).T -def radial_shell_mp_np( + if not expected: + atom_indices = np.tile(np.arange(n_atoms_probe), (probes_xyz.shape[1], 1)).T + else: + atom_indices = np.full(probes_xyz.shape,expected) - model, - n_probes=32, - radii=np.linspace(0.1, 2, 12), - rtol=0.9, - num_processes=cpu_count(), - selection=None, - version=2, - progress=True, - log=sys.stdout, -): - """ - Generate probes for a model file using numpy - """ - assert version in [1, 2], "Version must be 1 or 2" - if not progress: - tqdm = DummyTQDM - atoms_xyz = model.get_sites_cart().as_numpy_array() - tree = KDTree(atoms_xyz) + associated_indices = atom_indices.reshape(-1) - if version == 1: - worker_func = radial_shell_worker_v1_np - n_probes_target = n_probes - # Create argument tuples for each chunk - args = [ - ( - i, - atoms_xyz, - n_probes, - radius_shell, - tree, - rtol, - selection, - n_probes_target, - ) - for i, radius_shell in enumerate(radii) - ] - else: - worker_func = radial_shell_worker_v2_np - # Create argument tuples for each chunk - args = [ - (i, atoms_xyz, n_probes, radius_shell, tree, rtol, selection) - for i, radius_shell in enumerate(radii) - ] - # Create a pool of worker processes - if num_processes > 1: - with Pool(num_processes) as p: - # Use the pool to run the trilinear_interpolation_worker function in parallel - results = list( - tqdm(p.imap(worker_func, args), total=len(args), file=log) - ) - else: - results = [] - for arg in tqdm(args, file=log): - # for arg in args: - result = worker_func(arg) - results.append(result) + # query + # Check if any other tree points are within r of each query point + query_points = reshaped_probes + other_points_within_r = [] + for i, (query_point,idx) in enumerate(zip(query_points,associated_indices)): - probe_xyz_all = [result[0] for result in results] - probe_mask_all = [result[1] for result in results] + indices_within_r = atom_tree.query_ball_point(query_point, r) - # stack numpy - probe_xyz = np.stack(probe_xyz_all) - probe_mask = np.stack(probe_mask_all) - probe_xyz = np.transpose(probe_xyz, (0, 2, 1, 3)) # Reorder to shape (n_shells,n_atoms,n_probes,3) - probe_mask = np.swapaxes(probe_mask, 1, 2) - return probe_xyz, probe_mask + # Exclude the associated point + associated_index = associated_indices[i] + other_indices = [] + for idx in indices_within_r: + if idx != associated_index: + other_indices.append(idx) + if len(indices_within_r)==0: + other_indices.append(-1) -def ndarray_to_nested_list(arr): - """ - Convert a NumPy array of arbitrary dimensions into a nested list. - :param arr: A NumPy array. - :return: A nested list representing the array. - """ - if arr.ndim == 1: - return arr.tolist() - return [ndarray_to_nested_list(sub_arr) for sub_arr in arr] + print(other_indices,file=log) -def qscore_np( - mmm, - selection=None, - n_probes=32, - shells=np.array( - [ - 0.1, - 0.27272727, - 0.44545455, - 0.61818182, - 0.79090909, - 0.96363636, - 1.13636364, - 1.30909091, - 1.48181818, - 1.65454545, - 1.82727273, - 2.0, - ] - ), - version=2, - nproc=cpu_count(), - progress=True, - log=sys.stdout, - debug = False -): - """ - Calculate the qscore metric per-atom from an mmtbx map-model-manager, using numpy - """ - model = mmm.model() - mm = mmm.map_manager() - volume = mm.map_data().as_numpy_array() - radii = shells - voxel_size = mm.pixel_sizes() + other_points_within_r.append(other_indices) - probe_xyz, probe_mask = radial_shell_mp_np( - model, - n_probes=n_probes, - num_processes=nproc, - selection=selection, - version=version, - radii=radii, - progress=progress, - log=log, - ) + # true are points that don't get rejected + num_nbrs_other = np.array([len(inds) for i,inds in enumerate(other_points_within_r)]) + print(num_nbrs_other,file=log) + num_nbrs_other = num_nbrs_other.reshape((n_atoms_probe,n_probes)) + mask = num_nbrs_other==0 - # after the probe generation, versions 1 and 2 are the same + return mask - # infer params from shape - n_shells, n_atoms, n_probes, _ = probe_xyz.shape +# Generating probes +def generate_probes_np(atoms_xyz, rad, n_probes): + """ + atoms_xyz: np array of shape (n_atoms,3) + rad: the radius at which to place the probes + N: the number of probes per atom - # flatten - probe_xyz_flat = probe_xyz.reshape((n_atoms * n_shells * n_probes, 3)) - probe_mask_flat = probe_mask.reshape(-1) # (n_shells*n_atoms*n_probes,) + Returns: + probes (np.ndarray): shape (n_atoms,n_probes,3) + """ + assert atoms_xyz.ndim == 2 and atoms_xyz.shape[-1]==3, "Provide coordinates in shape (n_atoms,3)" + N = n_probes + h = -1.0 + (2.0 * np.arange(N) / float(N-1)) + phis = np.arccos(h) - # select mask=True probes - masked_probe_xyz_flat = probe_xyz_flat[probe_mask_flat] + thetas = np.zeros(N) + a = (3.6 / np.sqrt(N * (1.0 - h[1:-1]**2))) + thetas[1:-1] = a + thetas = np.cumsum(thetas) - # interpolate - masked_density = trilinear_interpolation( - volume, masked_probe_xyz_flat, voxel_size=voxel_size - ) - # reshape interpolated values to (n_shells,n_atoms, n_probes) + x = np.sin(phis) * np.cos(thetas) + y = np.sin(phis) * np.sin(thetas) + z = np.cos(phis) - d_vals = np.zeros((n_shells, n_atoms, n_probes)) - d_vals[probe_mask] = masked_density + probes = rad * np.stack([x, y, z], axis=-1) - # reshape to (M,N*L) for rowwise correlation + # Adjusting location of generated points relative to point ctr + probes = probes.reshape(-1, 1, 3) + atoms_xyz.reshape(1, -1, 3) - d_vals_2d = d_vals.transpose(1, 0, 2).reshape(d_vals.shape[1], -1) + # reshape (n_atoms,n_probes,3) + probes = probes.swapaxes(0,1) + return probes - # create the reference data +def SpherePtsVectorized ( ctr, rad, N ) : + """ + Function for generating points on a sphere. For testing, it retains the original + mapq pattern + """ + thetas, phis = [], [] + from math import acos, sin, cos, sqrt, pi + for k in range ( 1, N+1 ) : + h = -1.0 + ( 2.0*float(k-1)/float(N-1) ) + phis.append ( acos(h) ) + thetas.append ( 0 if k == 1 or k == N else + (thetas[k-2] + 3.6/sqrt(N*(1.0-h**2.0))) % (2*pi) ) + + pts = [None] * N + for i, theta, phi in zip ( range(N), thetas, phis ): + v = np.array([ sin(phi)*cos(theta), sin(phi)*sin(theta), cos(phi)]) + + pt = ctr + v * rad + pts[i] = pt + pts = np.array(pts) + pts = pts.swapaxes(0,1) + return pts + +def _shell_probes_progressive_wrapper(kwargs): + """ + A wrapper function to pass kwargs for 'shell_probes_progressive' + to multiprocessing pool. + """ + return shell_probes_progressive(**kwargs) + +def shell_probes_progressive( atoms_xyz=None, # A numpy array of shape (N,3) + atoms_tree=None, # An atom_xyz scipy kdtree + selection=None, # An atom selection + n_probes_target=8,# The desired number of probes per shell + n_probes_max=16, # The maximum number of probes allowed + n_probes_min=4, + RAD=1.5, # The nominal radius of this shell + rtol=0.9, # Multiplied with RAD to get actual radius + log = null_out(), + ): + """ + Generate probes progressively for a single shell (radius) + """ - M = volume - maxD = min(M.mean() + M.std() * 10, M.max()) - minD = max(M.mean() - M.std() * 1, M.min()) - A = maxD - minD - B = minD - u = 0 - sigma = 0.6 - x = np.array(radii) - y = A * np.exp(-0.5 * ((x - u) / sigma) ** 2) + B + # Do input validation + if not atoms_tree: + assert atoms_tree is None, "If not providing an atom tree, provide a 2d atom coordinate array to build tree" + atoms_tree = KDTree(atoms_xyz) - # Stack and reshape data for correlation calc + # Manage log + if log is None: + log = null_out() - # stack the reference to shape (n_shells,n_atoms,n_probes) - g_vals = np.repeat(y[:, None], n_probes, axis=1) - g_vals = np.expand_dims(g_vals, 1) - g_vals = np.tile(g_vals, (n_atoms, 1)) + # manage selection input + if selection is None: + selection = np.arange(atoms_xyz.shape[0]) + else: + selection = np.array(selection) + assert selection.dtype in [int,bool] - # reshape - g_vals_2d = g_vals.transpose(1, 0, 2).reshape(g_vals.shape[1], -1) - d_vals_2d = d_vals.transpose(1, 0, 2).reshape(d_vals.shape[1], -1) - mask_2d = probe_mask.transpose(1, 0, 2).reshape(probe_mask.shape[1], -1) + # do selection + atoms_xyz_sel = atoms_xyz[selection] + n_atoms = atoms_xyz_sel.shape[0] - # # CALCULATE Q + all_pts = [] # list of probe arrays for each atom + for atom_i in range(n_atoms): + coord = atoms_xyz_sel[atom_i:atom_i+1] + outRAD = RAD * rtol - # # numpy - q = rowwise_corrcoef(g_vals_2d, d_vals_2d, mask=mask_2d) - - # # Log - # import os - - # print("FINISHING...") - # print(os.getcwd()) - # print("saving atoms xyz: atom_xyz_np.npy") - # np.save("atoms_xyz_np.npy",model.get_sites_cart().as_numpy_array()) - # print("saving probe xyz: probe_xyz_np.npy") - # np.save("probe_xyz_np.npy",probe_xyz) - # print("saving probe mask: probe_mask_np.npy") - # np.save("probe_mask_np.npy",probe_mask) - # print("saving qscore: qscore_np.npy") - # np.save("qscore_np.npy",q) - if debug: - result = { - "q":q, - "probe_xyz":probe_xyz, - "probe_mask":probe_mask, - } - return result - return q -def run_qscore(mmm,params,log=sys.stdout,return_type='flex'): + print(coord,file=log) + pts = [] + i_log = [] + # try to get at least numPts] points at [RAD] distance + # from the atom, that are not closer to other atoms + N_i = 50 + for i in range(0, N_i): + rejections = 0 + + # if we find the necessary number of probes in the first iteration, then i will never go to 1 + # points on a sphere at radius RAD... + n_pts_to_grab = (n_probes_target + i * 2) # progressively more points are grabbed with each failed iter + #print(f"Grabbing {n_pts_to_grab} probes at RAD {RAD} using generate_probes_np()",file=log) + + outPts = generate_probes_np(coord, RAD, n_pts_to_grab) # get the points in shape (n_atoms,n_pts_to_grab,3) + + # initialize points to keep + at_pts, at_pts_i = [None] * outPts.shape[1], 0 + + # mask for outPts, are they are closest to the expected atom + # mask shape (n_atoms,n_pts_to_grab) + # NOTE: n_atoms != len(outPts) + + # will get mask of shape (n_atoms,n_probes) + mask = get_probe_mask(atoms_tree,outPts,r=outRAD,expected=atom_i,log=log) + + + for pt_i, pt in enumerate(outPts[0]): # identify which ones to keep, progressively grow pts list + keep = mask[0,pt_i] # only one atom TODO: vectorize atoms + if keep: + at_pts[at_pts_i] = pt + at_pts_i += 1 + else: + #print("REJECTING...",pt,file=log) + rejections+=1 + pass + + # check if we have enough points to break the search loop + if ( at_pts_i >= n_probes_target): + pts.extend(at_pts[0:at_pts_i]) + pts = pts + [np.array([np.nan,np.nan,np.nan])]*(n_probes_max-len(pts)) + #print(pts) + break + + i_log.append(i) + if i>=N_i: + assert False, "Too many iterations to get probes" + if i>0: + print("Going another round..",file=log) + # End sampling iteration + + + #Finish working on a single atom + + pts = np.array(pts) + if pts.shape == (0,): # all probes clashed + pts = np.full((n_probes_max,3),np.nan) + else: + assert pts.shape == (n_probes_max,3), ( + f"Generated points shape:{pts.shape}, expected: {(n_probes_max,3)}, try increasing n_probes_max" + ) + #iterations_shell.append(i+1) + all_pts.append(pts) + + # Finish the shell function + probes_xyz = np.array(all_pts) + assert probes_xyz.shape == (n_atoms,n_probes_max,3),( + f"probes not allocated correctly, probes_xyz.shape: {probes_xyz.shape}, expected: {(n_atoms,n_probes_max,3)}" + ) + probe_mask = ~(np.isnan(probes_xyz))[:,:,0] + + return probes_xyz, probe_mask + +def _shell_probes_precalculate_wrapper(kwargs): + """ + A wrapper function to pass kwargs for 'shell_probes_progressive' + to multiprocessing pool. + """ + return shell_probes_precalculate(**kwargs) + +def shell_probes_precalculate(atoms_xyz=None, # A numpy array of shape (N,3) + atoms_tree=None, # An atom_xyz scipy kdtree + selection=None, # An atom selection + n_probes_target=8,# The desired number of probes per shell + n_probes_max=16, # The maximum number of probes allowed + n_probes_min=4, # The min number of probes allowed without error + RAD=1.5, # The nominal radius of this shell + rtol=0.9, # Multiplied with RAD to get actual radius + log = null_out(), + strict = False, + ): + """ + Generate probes by precalculating for a single shell (radius) + """ + + # Do input validation + if not atoms_tree: + assert atoms_tree is None, "If not providing an atom tree, provide a 2d atom coordinate array to build tree" + atoms_tree = KDTree(atoms_xyz) + + # Manage log + if log is None: + log = null_out() + + # manage selection input + if selection is None: + selection = np.arange(atoms_xyz.shape[0]) + else: + assert selection.dtype == bool + + # do selection + atoms_xyz_sel = atoms_xyz[selection] + + # get probe coordinates + probe_xyz = generate_probes_np(atoms_xyz_sel, RAD, n_probes_max) + n_atoms, n_probes, _ = probe_xyz.shape + probe_xyz_flat = probe_xyz.reshape(-1,3) + + outRAD = RAD*rtol + dists, atom_indices = atoms_tree.query(probe_xyz_flat, k=2) + dists = dists.reshape((n_atoms,n_probes,2)) + atom_indices = atom_indices.reshape((n_atoms,n_probes,2)) + row_indices = np.arange(n_atoms)[:, np.newaxis] + expected_atom_mask = atom_indices[:,:,0]==row_indices # whether each probe's nearest atom is the one expected + within_r_mask = dists[:,:,1]= n_probes_min, f"Some atoms have less than {n_probes_min} probes ({len(problematic_probes)}). Consider raising n_probes_max" + return probe_xyz, probe_mask + + +def get_probes( + atoms_xyz=None, + atoms_tree = None, + params=None, + worker_func=None, + log=None): """ - The primary function to interact with this file. + Generate probes for atom coordinates. """ - shells = np.linspace(params.shell_radius_start, - params.shell_radius_stop, - num=params.shell_radius_num, - endpoint=True) - version = 2 if "precalculate" in params.probe_allocation_method else 1 # "progressive" - result = qscore_np(mmm, - selection=params.selection, - n_probes = params.n_probes, - shells = shells, - version=version, - nproc=params.nproc, - progress=params.progress, - log=log, - debug=params.debug - ) - if return_type == "flex" and not params.debug: - result = flex.double(result) - return result + + if atoms_tree is None: + atoms_tree = KDTree(atoms_xyz) + + kwargs_list = [ + { + 'atoms_xyz':atoms_xyz, + 'atoms_tree':atoms_tree, + 'selection':params.selection, + 'n_probes_target':params.n_probes_target, + 'n_probes_max':params.n_probes_max, + 'n_probes_min':params.n_probes_min, + 'RAD':RAD, + 'rtol':params.rtol, + } for RAD in params.shells] + + # Create a pool of worker processes + if params.nproc > 1: + with Pool(params.nproc) as pool: + results = pool.starmap(worker_func, [(kwargs,) for kwargs in kwargs_list]) + else: + results = [] + for kwargs in kwargs_list: + result = worker_func(kwargs) + results.append(result) + + probe_xyz_all = [result[0] for result in results] + probe_mask_all = [result[1] for result in results] + + # # stack numpy + probe_xyz = np.stack(probe_xyz_all) + probe_mask = np.stack(probe_mask_all) + return probe_xyz, probe_mask + + +def calc_qscore(mmm,params,log=null_out(),debug=False): + """ + Calculate qscore from map model manager + """ + model = mmm.model() + mm = mmm.map_manager() + + + # Get atoms + atom_xyz = model.get_sites_cart().as_numpy_array() + + # Get probes and probe mask (probes to reject) + if params.probe_allocation_method == "progressive": + worker_func=_shell_probes_progressive_wrapper + else: + worker_func=_shell_probes_precalculate_wrapper + + probe_xyz,probe_mask = get_probes( + atoms_xyz=atom_xyz, + atoms_tree = None, + params=params, + worker_func=worker_func, + log = log, + ) + + n_shells, n_atoms, n_probes, _ = probe_xyz.shape + + # flatten + probe_xyz_flat = probe_xyz.reshape((n_atoms * n_shells * n_probes, 3)) + probe_mask_flat = probe_mask.reshape(-1) # (n_shells*n_atoms*n_probes,) + + # apply the mask to get only the xyz for selected probes + masked_probe_xyz_flat = probe_xyz_flat[probe_mask_flat] + + # interpolate + volume = mm.map_data().as_numpy_array() + voxel_size = mm.pixel_sizes() + masked_density = trilinear_interpolation(volume, masked_probe_xyz_flat, voxel_size=voxel_size) + + d_vals = np.full((n_shells, n_atoms, n_probes),np.nan) + d_vals[probe_mask] = masked_density + + # g vals + # create the reference data + radii = params.shells + M = volume + maxD = min(M.mean() + M.std() * 10, M.max()) + minD = max(M.mean() - M.std() * 1, M.min()) + A = maxD - minD + B = minD + u = 0 + sigma = 0.6 + x = np.array(radii) + y = A * np.exp(-0.5 * ((x - u) / sigma) ** 2) + B + + # Stack and reshape data for correlation calc + + # stack the reference to shape (n_shells,n_atoms,n_probes) + g_vals = np.repeat(y[:, None], n_probes, axis=1) + g_vals = np.expand_dims(g_vals, 1) + g_vals = np.tile(g_vals, (n_atoms, 1)) + + # set masked area to nan + g_vals[~probe_mask] = np.nan + + # reshape + g_vals_2d = g_vals.transpose(1, 0, 2).reshape(g_vals.shape[1], -1) + d_vals_2d = d_vals.transpose(1, 0, 2).reshape(d_vals.shape[1], -1) + mask_2d = probe_mask.transpose(1, 0, 2).reshape(probe_mask.shape[1], -1) + + # CALCULATE Q + q = rowwise_corrcoef(g_vals_2d, d_vals_2d, mask=mask_2d) + + # Output + if debug or params.debug: + # Collect debug data + result = { + "atom_xyz":atom_xyz, + "probe_xyz":probe_xyz, + "probe_mask":probe_mask, + "d_vals":d_vals, + "g_vals":g_vals, + "qscore_per_atom":q, + } + else: + result = { + "qscore_per_atom":q, + } + return result + + + +def ndarray_to_nested_list(arr): + """ + Convert a NumPy array of arbitrary dimensions into a nested list. + :param arr: A NumPy array. + :return: A nested list representing the array. + """ + if arr.ndim == 1: + return arr.tolist() + return [ndarray_to_nested_list(sub_arr) for sub_arr in arr] + ############################################################################## -# Functions that use only flex, no numpy +# Code below here requires refactoring ############################################################################## @@ -797,50 +881,6 @@ def rowwise_corrcoef(A, B, mask=None): cc = sumprod / (sqrt_sos_A * sqrt_sos_B) return cc.data - -def sphere_points_np(ctr, rad, N, mode='SpherePts'): - """ - Points on a sphere given centers, radius, number N - - TODO: Mode is confusing, it is not clear why there is a difference. - mode='SpherePts' an attempt to literally copy the SpherePts function from mapq - mode='original' a version that gives the same results as the QscorePt3 function from mapq - """ - h = -1.0 + (2.0 * np.arange(N) / float(N-1)) - phis = np.arccos(h) - - if mode == 'original': - thetas = np.zeros(N) - a = (3.6 / np.sqrt(N * (1.0 - h[1:-1]**2))) - thetas[1:-1] = a - thetas = np.cumsum(thetas) - elif mode == 'SpherePts': - thetas = np.zeros(N) - for k in range(1, N): - if k == 1 or k == N - 1: - thetas[k] = 0 - else: - thetas[k] = (thetas[k-1] + 3.6 / - np.sqrt(N * (1 - h[k]**2))) % (2 * np.pi) - thetas = thetas.cumsum() - - x = np.sin(phis) * np.cos(thetas) - y = np.sin(phis) * np.sin(thetas) - z = np.cos(phis) - - points = rad * np.stack([x, y, z], axis=-1) - - # Adjusting for multiple centers - if ctr.ndim == 1: - # Single center case - points = points + ctr - else: - # Multiple centers case - points = points.reshape(-1, 1, 3) + ctr.reshape(1, -1, 3) - - return points - - def cdist_flex(A, B): """A flex implementation of the cdist function""" @@ -976,8 +1016,6 @@ def query_ball_point_flex(tree, tree_xyz, query_xyz, r=None): # flex utils - - def flex_from_list(lst, signed_int=False): """Generate a flex array from a list, try to infer type""" flat_list, shape = flatten_and_shape(lst) diff --git a/cctbx/maptbx/tst_qscore.py b/cctbx/maptbx/tst_qscore.py index 0f93a8b9f2..215c671206 100644 --- a/cctbx/maptbx/tst_qscore.py +++ b/cctbx/maptbx/tst_qscore.py @@ -1,321 +1,640 @@ from __future__ import absolute_import, division, print_function import os +import copy +import subprocess +import shutil +from pathlib import Path +import json +import argparse + +from iotbx.data_manager import DataManager from cctbx.array_family import flex -from iotbx.cli_parser import run_program import libtbx +from libtbx import group_args from libtbx.utils import null_out -from libtbx.test_utils import approx_equal -from cctbx.programs import qscore - - -expected_results = { - 17: [ - 0.35535516324938227, - 0.24550687752861167, - 0.42717508108780494, - 0.2630431196992697, - 0.2512972739404068, - 0.0748338849699907, - 0.3951188616344501, - 0.017261865581353543, - 0.47942130214316503, - 0.2927000401754054, - 0.08603369430277283, - 0.30219565421918, - 0.39417849168365854, - 0.6189297826154754, - 0.36598113428758416, - 0.07821030825399476, - 0.5275589560551526, - 0.19580632885270882, - 0.27077417168391377, - 0.31471829887209857, - 0.3158786931123718, - 0.5096481626657788, - 0.4609767956764144, - 0.28235509392736674, - 0.4709590709747482, - 0.2939374853294539, - 0.10241906482206845, - 0.4015066315039059, - 0.35209047260985793, - 0.35059709887741874, - 0.3265106583648, - 0.2806311093313803, - 0.37458818716858017, - 0.385126780724512, - 0.06154713873358951, - 0.10991564773911004, - 0.49364138455921214, - 0.2544807372533646, - 0.5054205573973468, - 0.2637558217581824, - 0.3140624661999957, - 0.2365647784766615, - 0.28262674351648415, - 0.1969617894777505, - 0.3197038813888359, - 0.004434119579554559, - 0.49852526974799255, - 0.4284389897113832, - 0.32266761533489585, - 0.5064439221443267, - 0.4922792436039985, - 0.6303751667061026, - 0.1542182251535256, - 0.17137072347023904, - 0.5974219741230471, - 0.3533762354980602, - 0.27000081206540955, - 0.2007048933666327, - 0.30627931992625224, - 0.4333678839790156, - 0.5452464031846214, - 0.39074700178563093, - 0.44160485208870487, - 0.3012758760420372, - 0.3250739032545345, - 0.43362607699544053, - 0.3625137062692818, - 0.3737674696637951, - 0.42857066342176636, - 0.35808570562399467, - 0.22410204647321708, - 0.3767186160303378, - 0.28651652046017084, - -0.049724839252815733, - 0.19356789252833098, - 0.09094302118136462, - 0.42016933552912894, - 0.13060556101358295, - 0.22990514778100643, - 0.24778269855730797, - 0.3321627503379433, - 0.2793544145496639, - 0.36436645199153783, - 0.1990021248328906, - 0.5972764932446221, - 0.38459252021474777, - 0.15376046116368622, - 0.4350468866909971, - 0.34446835591022873, - 0.36878927260006605, - 0.05794444507950947, - 0.1368028652112549, - 0.47365762715495435, - 0.40950604509893035, - 0.21697233895086965, - 0.24302703044362328, - 0.3419794880192022, - 0.5585194498374837, - 0.459308252423094, - 0.3230117486740559, - 0.3148210060317072, - 0.13707459657834334, - 0.35686464668359086, - 0.3070311263154991, - 0.3055250982319954, - 0.5000373760197506, - 0.2828409443923543, - 0.22088517997784513, - 0.34473673110006714, - 0.39401167930098646, - 0.1409604644258536, - 0.17904487505641237, - 0.41512532606270575, - 0.051477839079248605, - 0.430233223946139, - 0.10701871986502859, - 0.3554414516983775, - 0.15227178169975683, - 0.20902369264131399, - 0.27523031292228356, - 0.5014761466259059, - 0.07273646238705293, - 0.5228074093643269, - 0.28213307002470817, - 0.32834396845308833, - 0.4546359850826332, - 0.2640898256601553, - 0.4042889388009938, - -0.058819305685534916, - 0.3320355211739059, - 0.5368734032575433, - 0.38723919567921916, - 0.27920683488494874, - 0.21293610438730504, - 0.28101278857543577, - 0.5005434542705948, - 0.3471817144906104, - 0.21127407819640626, - 0.32067511222833683, - 0.11079335636572182, - 0.17036780464871323, - 0.41955675987187646, - 0.3905657146499568, - 0.3401149986039323, - 0.36035223718270976, - 0.23917228790998196, - 0.36381317879482006, - 0.39077694083716824, - 0.03118681161607613, - 0.04641661292929102, - 0.3724988531432701, - 0.2643036127826901, - 0.30537188074803256, - 0.16202886247768936, - 0.43568155630265554, - 0.3084634599307411, - 0.387489124753754, - 0.2666390040428182, - 0.46279277413454706, - 0.02002279771517451, - 0.4827489588800846, - 0.445680062618974, - 0.14784923408302839, - 0.4184692111286882, - 0.3933408944964084, - 0.4550840595198136, - -0.06497059743774909, - 0.20326928453476295, - 0.5410683745517895, - 0.3934791271999539, - 0.24834218260971685, - 0.2284335972515956, - 0.2749252359472737, - 0.5811000263463834, - 0.5886279113579868, - 0.10014876331174488, - 0.3558056816456358, - 0.23931433448674996, - 0.28193700267688226, - 0.30923904707665817, - 0.3937787470567507, - 0.16583160065281066, - 0.41937141588607457, - 0.11413599799171258, - 0.3671212694643467, - 0.31069640919716385, - 0.05525220154724908, - 0.247288738983681, - 0.39689271509298957, - 0.20134818886327846, - 0.5060624692935539, - 0.23340144114502143, - 0.1047045872234278, - 0.26762911598483546, - 0.39263746442670566, - 0.12692533917487203, - 0.3980087754375635, - 0.03756336993253084, - 0.46101152409796214, - 0.42446162573971874, - 0.3643343019533042, - 0.5130778316649313, - 0.3063184055501381, - 0.47635554117162227, - 0.2022659217974044, - 0.2554080063069391, - 0.5501695893864158, - 0.2846628653680698, - 0.3242176784889862, - 0.24811871246412262, - 0.3255252546682871, - 0.5453376573614725, - 0.41301426891418463, - 0.07307555071072433, - 0.4536301022017574, - 0.24638397492302436, - 0.19814077792624293, - 0.3602238859424958, - 0.3170086525644145, - 0.2972960450133945, - 0.4145260546137287, - 0.2661909058919775, - 0.49307051785060885, - 0.42049092767916485, - 0.010562206055517411, - 0.05167120683170355, - 0.48650651743605644, - 0.07522293396734439, - 0.4990564081521944, - 0.3334757193364281, - 0.14185320419595457, - 0.12828315708419813, - 0.11089188858896354, - 0.14452747870340907, - 0.3699940929152232, - -0.041235846823679784, - 0.513812878496174, - 0.3694188603001491, - 0.28901185662505796, - 0.3803523709807769, - 0.3765605158390536, - 0.4527272022777316, - -0.08048732044100083, - 0.18539904739806815, - 0.5232189411542995, - 0.3022522764188308, - 0.35572393347262615, - 0.27116261764046895, - 0.3626082715676051, - 0.5619703843998924, - 0.4944482273684381, - 0.16248076555523522, - 0.3206340194265775, - 0.14751443872046044, - 0.09595366681825422, - 0.40639326593721653, - 0.31519352252160526, - 0.2403981456993558, - 0.36692833148492576, - 0.15957380970815432, - 0.49190636939034976, - 0.3189327704420888, - 0.10792266773848919, - 0.04212798503994418, - 0.39647128156913286, - 0.19546149360621035 - ], - 42: [ - - ] -} -# make flex arrays -expected_results = {key: flex.double(val) - for key, val in list(expected_results.items())} +from iotbx.cli_parser import run_program +import numpy as np +from scipy.spatial import KDTree + + + +from cctbx.maptbx.qscore import ( + generate_probes_np, + SpherePtsVectorized, + get_probe_mask, + get_probes, + shell_probes_progressive, + shell_probes_precalculate, + _shell_probes_progressive_wrapper, + _shell_probes_precalculate_wrapper +) +from cctbx.programs.qscore import Program as QscoreProgram + + + + +def isclose_or_nan(a, b, atol=1e-3): + # perform isclose comparison, treating nans as equal + return np.isclose(a, b, atol=atol) | (np.isnan(a) & np.isnan(b)) + +def test_probe_generation(): + # test the primary points generation function against expected data + atoms_xyz = np.array([[ 5.276, 12.488, 16.069], + [ 5.649, 13.947, 16.076]]) + + probes_expected = np.array([[ + [ 5.276 , 12.488 , 15.969 ], + [ 5.2588, 12.5558, 15.9976], + [ 5.186 , 12.4803, 16.0261], + [ 5.2564, 12.391 , 16.0547], + [ 5.3636, 12.442 , 16.0833], + [ 5.3304, 12.5601, 16.1119], + [ 5.2115, 12.5151, 16.1404], + [ 5.276 , 12.488 , 16.169 ]], + + [[ 5.649 , 13.947 , 15.976 ], + [ 5.6318, 14.0148, 16.0046], + [ 5.559 , 13.9393, 16.0331], + [ 5.6294, 13.85 , 16.0617], + [ 5.7366, 13.901 , 16.0903], + [ 5.7034, 14.0191, 16.1189], + [ 5.5845, 13.9741, 16.1474], + [ 5.649 , 13.947 , 16.176 ]]]) + + probes_xyz = generate_probes_np(atoms_xyz,0.1,8) + assert np.all(np.isclose(probes_xyz,probes_expected,atol=1e-3)) + + + # test that our points generator functions don't diverge on + # a large amount of points + points = np.random.random((1000,3)) + rads = np.linspace(0,2.0,20) + Ns = [2] + # test point by point + for point in points: + for rad in rads: + for N in Ns: + mapq_values = SpherePtsVectorized(point[None,:],rad,N) + cctbx_values = generate_probes_np(point[None,:],rad,N) + assert np.all(np.isclose(mapq_values,cctbx_values,atol=1e-3)) + + # test vectorized over points + for rad in rads: + for N in Ns: + mapq_values = SpherePtsVectorized(points,rad,N) + cctbx_values = generate_probes_np(points,rad,N) + assert np.all(np.isclose(mapq_values,cctbx_values,atol=1e-3)) + + +def test_probe_masking(): + # test the progressive probe masking function against test data + atoms_xyz = np.array([ + [0,0,-1], + [0,0,1], + ]) + + # probes_xyz shape (2,4,3), (n_atoms,n_probes,3) + probes_xyz = np.array([ + [[0,0,-2], + [0,0,-0.5], + [0,0,0], + [0,0,0.5]], + + [[0,0,-2], + [0,0,-0.5], + [0,0,0], + [0,0,0.5]]]) + + atom_tree = KDTree(atoms_xyz) + + calculated_result = get_probe_mask(atom_tree,probes_xyz,r=1.4) + manual_result = np.array([[ True, True, False, False], + [False, False, False, True]]) + + + assert np.all(calculated_result==manual_result) + +def test_shell_probes(probe_allocation_method="progressive"): + # Test full progressive probe generation for a single shell + atoms_xyz = np.array([[ 5.276, 12.488, 16.069], + [ 5.649, 13.947, 16.076]]) + if probe_allocation_method=="progressive": + shell_func = shell_probes_progressive + expected_probes = np.array([[[ 5.276 , 12.488 , 14.569 ], + [ 5.0515, 13.4037, 14.9023], + [ 4.0297, 12.4397, 15.2357], + [ 4.825 , 11.1476, 15.569 ], + [ 6.3669, 11.4721, 15.9023], + [ 4.0466, 12.6981, 16.9023], + [ 5.343 , 11.5476, 17.2357], + [ 5.276 , 12.488 , 17.569 ], + [ np.nan, np.nan, np.nan], + [ np.nan, np.nan, np.nan]], -def exercise(test_name): - pdb_file = libtbx.env.find_in_repositories( - relative_path=f"phenix_regression/real_space_refine/data/tst_{test_name}.pdb", - test=os.path.isfile) + [[ 5.649 , 13.947 , 14.576 ], + [ 5.4245, 14.8627, 14.9093], + [ 4.4027, 13.8987, 15.2427], + [ 6.7399, 12.9311, 15.9093], + [ 7.0245, 14.5216, 16.2427], + [ 5.6032, 15.3605, 16.576 ], + [ 4.4196, 14.1571, 16.9093], + [ 5.716 , 13.0066, 17.2427], + [ 5.649 , 13.947 , 17.576 ], + [ np.nan, np.nan, np.nan]]]) - map_file = libtbx.env.find_in_repositories( - relative_path=f"phenix_regression/real_space_refine/data/tst_{test_name}.ccp4", - test=os.path.isfile) + elif probe_allocation_method == "precalculate": + shell_func = shell_probes_precalculate + expected_probes = np.array( - result = run_program( - program_class=qscore.Program, - args=[pdb_file, map_file, - "probe_allocation_method=progressive shell_radius_num=5 nproc=1 n_probes=8"], - logger=null_out(), + [[[5.2760, 12.4880, 14.5690], + [5.0515, 13.4037, 14.9023], + [4.0297, 12.4397, 15.2357], + [4.8250, 11.1476, 15.5690], + [6.3669, 11.4721, 15.9023], + [6.6515, 13.0626, 16.2357], + [5.2302, 13.9015, 16.5690], + [4.0466, 12.6981, 16.9023], + [5.3430, 11.5476, 17.2357], + [5.2760, 12.4880, 17.5690]], + + [[5.6490, 13.9470, 14.5760], + [5.4245, 14.8627, 14.9093], + [4.4027, 13.8987, 15.2427], + [5.1980, 12.6066, 15.5760], + [6.7399, 12.9311, 15.9093], + [7.0245, 14.5216, 16.2427], + [5.6032, 15.3605, 16.5760], + [4.4196, 14.1571, 16.9093], + [5.7160, 13.0066, 17.2427], + [5.6490, 13.9470, 17.5760]]]) + + probes_xyz, _ = shell_func(atoms_xyz=atoms_xyz, + atoms_tree = None, + selection=None, + n_probes_target=8, + n_probes_max=10, + RAD=1.5, + rtol=0.9, + log = null_out()) + + if probe_allocation_method == "precalculate": + print(probes_xyz) + assert np.all(isclose_or_nan(probes_xyz,expected_probes,atol=1e-3)) + +def test_get_probes(probe_allocation_method="progressive"): + # Test the full progressive probe generation for multiple shells + + atoms_xyz = np.array([[ 5.276, 12.488, 16.069], + [ 5.649, 13.947, 16.076]]) + + params = group_args( + selection=None, + shells = np.array([0.0,0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1., 1.1, 1.2, 1.3, + 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. ]), + n_probes_target=8, + n_probes_max=16, + n_probes_min=4, + rtol=0.9, + nproc=1, + probe_allocation_method=probe_allocation_method, + log = null_out() ) - try: - expected_result = expected_results[test_name] - assert approx_equal(expected_result, result.qscore, eps=1.e-2) - except Exception: - for val in result.qscore: - print(str(val)+",") - raise + if probe_allocation_method == "progressive": + worker_func = _shell_probes_progressive_wrapper + sum_expected = 12343.8878 + elif probe_allocation_method == "precalculate": + worker_func = _shell_probes_precalculate_wrapper + sum_expected = 23337.6710 + probes_xyz,probe_mask = get_probes(atoms_xyz=atoms_xyz, + params=params, + worker_func=worker_func, + log = null_out()) -if (__name__ == "__main__"): + + sum_calc = probes_xyz[~np.isnan(np.around(probes_xyz,3))].sum() + + + print(probe_allocation_method,sum_calc) + assert np.all(np.isclose(sum_calc,sum_expected)), ( + "The sum of generated probes do not match previous values obtained from mapq. Debug probe generation." + ) + + +################################ +# Tests with real data +################################ + +def prepare_test_data(templates): + """ + Prepare folders with data files for each test + """ + + for i,template in enumerate(templates): + test_dir_name = template["data"]["name"] + + is_fragment = False + if template["data"]["fragment_iselection"] not in [None,[]]: + i_sel = template["data"]["fragment_iselection"] + is_fragment = True + test_dir = Path(test_dir_name) + + # make test directory and copy data + test_dir.mkdir(exist_ok=True) + templates[i]["data"]["test_dir"] = str(test_dir.absolute()) + model_path_base = Path(template["data"]["model_file_base"]) + map_path_base = Path(template["data"]["map_file_base"]) + model_path = test_dir / Path(f"model.pdb") + map_path = test_dir / Path(f"map.ccp4") + shutil.copyfile(model_path_base,model_path) + shutil.copyfile(map_path_base,map_path) + + # possibly make fragment files + if is_fragment: + dm = DataManager() + dm.process_model_file(str(model_path)) + model = dm.get_model() + sel = np.full(model.get_number_of_atoms(),False) + sel[i_sel] = True + model_sel = model.select(flex.bool(sel)) + dm.write_model_file(model_sel.model_as_pdb(),str(model_path),overwrite=True) + + # record in template the data in test directory + templates[i]["data"]["model_file"] = str(model_path) + templates[i]["data"]["map_file"] = str(map_path) + + return templates + +def run_test_template_mapq(template, + mapq_location=None, + mapq_debug_data_filename="debug_data_mapq.json"): + """ + Run mapq via Chimera on the command line. Load debug results + NOTE: The debug results rely on a modified version of mapq. The releaseed version does not write + all the intermediate data. + """ + assert mapq_location is not None + mapq_location = Path(mapq_location) + model_path = Path(template["data"]["model_file"]) + map_path = Path(template["data"]["map_file"]) + test_dir = Path(template["data"]["test_dir"]) + + # run program + mapq_executable = mapq_location / Path("mapq_cmd.py") + chimera_path = mapq_location / Path("../../../../../Chimera.app") + mapq_command = f"python {mapq_executable.absolute()} {chimera_path.absolute()} map={map_path.absolute()} pdb={model_path.absolute()} bfactor=1.0" + # q is stored in bfactor column of pdb, with: bfactor = f * (1.0-Qscore). The scale factor f is provided with the 'bfactor' arg + # Bfactor 'f' should not affect q result + print(f"Running mapq with command:") + print(mapq_command) + print("\n\n") + subprocess.run(mapq_command.split()) + debug_data = load_mapq_debug_data(test_dir) + return debug_data + + + +def load_mapq_debug_data(test_dir): """ - Test random files to verify basic functionality remains unchanged - Data from phenix_regression/real_space_refine/data + Load the mapq intermediate results. Looks for a file 'debug_data_mapq.json' in + the test directory. """ - for test_name in [17]: # [17,42,48]: - exercise(test_name) - print("OK") + + # anticipate output data file path + data_file = Path(test_dir,Path("debug_data_mapq.json")).absolute() + # load debug data + with open(data_file,"r") as fh: + debug_data = json.load(fh) + def _is_ragged(a): + # don't force arrays for ragged data + if isinstance(a, list): + # Check if all elements are lists and have the same length + if all(isinstance(i, list) for i in a): + length = len(a[0]) + return any(len(i) != length for i in a) + else: + # It's a list, but not a list of lists + return False + else: + # Not a list, so it's not a ragged array in the typical sense + return False + + debug_data = {key:np.array(value) if not _is_ragged(value) else value for key,value in debug_data.items()} + return debug_data + + +def run_test_template_cctbx(template): + """ + Run a test using the progressive method added to cctbx + """ + + + params = group_args( + selection=None, + shells = template["params"]["shells"], + n_probes_target=template["params"]["n_probes_target"], + n_probes_max=template["params"]["n_probes_max"], + n_probes_min=template["params"]["n_probes_min"], + rtol=template["params"]["rtol"], + nproc=template["params"]["nproc"], + probe_allocation_method = template["params"]["probe_allocation_method"], + log = null_out(), + ) + model_filename = template["data"]["model_file"] + map_filename = template["data"]["map_file"] + + param_args = [f"{key}={getattr(params,key)}" for key in params.keys() if key not in ["shells","log"]] + for shell in params.shells: + param_args.append(f"shells={shell}") + args = [model_filename,map_filename, "debug=True"] + param_args + print(args) + result = run_program(program_class=QscoreProgram,args=args) + result = {key:getattr(result,key) for key in result.keys()} # group_args to dict + return result + +def run_template(template,mapq_location=None): + print("Template") + print(json.dumps(template,indent=2)) + + # get data + debug_data = run_test_template_cctbx(template) + probe_xyz = debug_data["probe_xyz"] + probe_mask = debug_data["probe_mask"] + d_vals = debug_data["d_vals"] + g_vals = debug_data["g_vals"] + qscore_per_atom = debug_data["qscore_per_atom"] + + # Record sums + template["results"]["probe_sum"] = probe_xyz[~np.isnan(probe_xyz)].sum() + template["results"]["q_sum"] = qscore_per_atom.sum() + + if template["results"]["probe_sum_expected"] is not None: + assert np.isclose(template["results"]["probe_sum"],template["results"]["probe_sum_expected"],atol=1e-2) + if template["results"]["q_sum_expected"]: + assert np.isclose(template["results"]["q_sum"],template["results"]["q_sum_expected"],atol=1e-2) + + # Record all data + template["results"]["cctbx"] = debug_data + + # run mapq, check results with progressive + if mapq_location is not None: + if template["params"]["probe_allocation_method"] == "progressive": + debug_data_mapq = run_test_template_mapq(template,mapq_location = mapq_location) + + probe_xyz_mapq = debug_data_mapq["probe_xyz"] + probe_mask_mapq = debug_data_mapq["probe_mask"] + d_vals_mapq = debug_data_mapq["d_vals"] + g_vals_mapq = debug_data_mapq["g_vals"] + qscore_per_atom_mapq = debug_data_mapq["qscore_per_atom"] + + # Check probes + assert np.all(isclose_or_nan(probe_xyz,probe_xyz_mapq)) + assert np.all(isclose_or_nan(probe_mask,probe_mask_mapq)) + + # Check d and g + assert np.all(isclose_or_nan(d_vals,d_vals_mapq)) + assert np.all(isclose_or_nan(g_vals,g_vals_mapq)) + + # Check q + assert np.all(isclose_or_nan(qscore_per_atom,qscore_per_atom_mapq)) + + # Check q from actual pdb output file + test_dir = Path(template["data"]["test_dir"]) + model_path = Path(template["data"]["model_file"]) + map_path = Path(template["data"]["map_file"]) + dm = DataManager() + mapq_output_file = Path(test_dir, f"{model_path.stem}.pdb__Q__{map_path.stem}.ccp4.pdb") + _ = dm.process_model_file(str(mapq_output_file)) + model = dm.get_model() + pseudo_b = model.get_b_iso().as_numpy_array() + q_test = pseudo_b + # Round heavily to match bfactor + q_calc = np.around(qscore_per_atom,decimals=2) + assert set(q_test)==set(q_calc) + + # record sums + template["results"]["probe_sum"] = probe_xyz_mapq[~np.isnan(probe_xyz)].sum() + template["results"]["q_sum"] = qscore_per_atom_mapq.sum() + template["results"]["mapq"] = debug_data_mapq + return template + + +# a template to store configuration for a single test +test_template ={ + + "data":{ + "name":None, + "model_file":None, + "model_file_base":None, + "map_file":None, + "map_file_base":None, + "test_dir":None, + "fragment_iselection":None, # actually reduce the file + }, + "results":{ + "probe_sum":None, + "q_sum":None, + "probe_sum_expected":None, + "q_sum_expected":None, + }, + "params":{ + "selection":None, # Just calculate q score for a sub-selection + "iselection":None, + "shells": [0.0,0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1., 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. ], + "n_probes_target":8, + "n_probes_max":16, + "n_probes_min":4, + "nproc":4, + "probe_allocation_method":"progressive", + "rtol":0.9, + } +} + +if (__name__ == "__main__"): + parser = argparse.ArgumentParser(description="Run qscore tests") + + # Figure out if using mapq + parser.add_argument('--mapq_location', + type=str, + help='Compare to mapq results. Example: /Users/user/Desktop/Chimera.app/Contents/Resources/share/mapq') + args = parser.parse_args() + mapq_location = args.mapq_location + if mapq_location is None: + mapq = False + else: + mapq = True + + + # Start tests... + + #1. test probe generation + test_probe_generation() + + #2. test probe masking (for progressive) + test_probe_masking() + + #3. test single shell probe generation + test_shell_probes(probe_allocation_method="progressive") + test_shell_probes(probe_allocation_method="precalculate") + + #4. test multi-shell probe generation + test_get_probes(probe_allocation_method="progressive") + test_get_probes(probe_allocation_method="precalculate") + + + #5. test some real files + templates = [] + + + def get_base_map_model(test_name): + # model + pdb_file_repo = libtbx.env.find_in_repositories( + relative_path=f"phenix_regression/real_space_refine/data/tst_{test_name}.pdb", + test=os.path.isfile) + + # map + map_file_repo = libtbx.env.find_in_repositories( + relative_path=f"phenix_regression/real_space_refine/data/tst_{test_name}.ccp4", + test=os.path.isfile) + return pdb_file_repo,map_file_repo + + # Do some small fragments (progressive) + base_model_name, base_map_name = get_base_map_model(17) + test_name = Path(base_model_name).stem + + # 1 atom fragment + test = copy.deepcopy(test_template) + test["data"]["name"] = f"{test_name}_0" + test["data"]["model_file_base"] = base_model_name + test["data"]["map_file_base"] = base_map_name + test["data"]["fragment_iselection"] = [0] + templates.append(test) + + # 2 atom fragment + test = copy.deepcopy(test_template) + test["data"]["name"] = f"{test_name}_0-1" + test["data"]["model_file_base"] = base_model_name + test["data"]["map_file_base"] = base_map_name + test["data"]["fragment_iselection"] = [0,1] + templates.append(test) + + # 3 atom fragment + test = copy.deepcopy(test_template) + test["data"]["name"] = f"{test_name}_0-2" + test["data"]["model_file_base"] = base_model_name + test["data"]["map_file_base"] = base_map_name + test["data"]["fragment_iselection"] = [0,1,2] + templates.append(test) + + # 4 atom fragment + test = copy.deepcopy(test_template) + test["data"]["name"] = f"{test_name}_0-3" + test["data"]["model_file_base"] = base_model_name + test["data"]["map_file_base"] = base_map_name + test["data"]["fragment_iselection"] = [0,1,2,3] + templates.append(test) + + # full molecules + + # 17 + # progressive + base_model_name, base_map_name = get_base_map_model(17) + test_name = Path(base_model_name).stem + test = copy.deepcopy(test_template) + test["data"]["name"] = test_name+"_progressive" + test["data"]["model_file_base"] = base_model_name + test["data"]["map_file_base"] = base_map_name + test["params"]["probe_allocation_method"] = "progressive" + test["results"]["q_sum_expected"] = 85.74585520218474 + test["results"]["probe_sum_expected"] = 7033351.9964000005 + templates.append(test) + + # precalculate + test = copy.deepcopy(test_template) + test["data"]["name"] = test_name+"_precalc" + test["data"]["model_file_base"] = base_model_name + test["data"]["map_file_base"] = base_map_name + test["params"]["n_probes_max"] = 128 + test["params"]["probe_allocation_method"] = "precalculate" + test["results"]["q_sum_expected"] = 87.87610388144196 + test["results"]["probe_sum_expected"] = 108903540.12935309 + templates.append(test) + + # 42 + # progressive + base_model_name, base_map_name = get_base_map_model(42) + test_name = Path(base_model_name).stem + test = copy.deepcopy(test_template) + test["data"]["name"] = test_name+"_progressive" + test["data"]["model_file_base"] = base_model_name + test["data"]["map_file_base"] = base_map_name + test["results"]["q_sum_expected"] = 65.18062030153557 + test["results"]["probe_sum_expected"] = 479151.29789999995 + templates.append(test) + + # precalculate + test = copy.deepcopy(test_template) + test["data"]["name"] = test_name+"_precalc" + test["data"]["model_file_base"] = base_model_name + test["data"]["map_file_base"] = base_map_name + test["params"]["n_probes_max"] = 128 + test["params"]["probe_allocation_method"] = "precalculate" + test["results"]["q_sum_expected"] = 65.98930853051141 + test["results"]["probe_sum_expected"] = 7393520.8060661685 + templates.append(test) + + # 48 + # progressive + base_model_name, base_map_name = get_base_map_model(48) + test_name = Path(base_model_name).stem + test = copy.deepcopy(test_template) + test["data"]["name"] = test_name+"_progressive" + test["data"]["model_file_base"] = base_model_name + test["data"]["map_file_base"] = base_map_name + test["results"]["q_sum_expected"] = 74.57025665508365 + test["results"]["probe_sum_expected"] = 904759.264 + templates.append(test) + + # precalculate + test = copy.deepcopy(test_template) + test["data"]["name"] = test_name+"_precalc" + test["data"]["model_file_base"] = base_model_name + test["data"]["map_file_base"] = base_map_name + test["params"]["n_probes_max"] = 128 + test["params"]["probe_allocation_method"] = "precalculate" + test["results"]["q_sum_expected"] = 75.99978032145603 + test["results"]["probe_sum_expected"] = 13979341.58057615 + templates.append(test) + + # prepare files + templates = prepare_test_data(templates) + + # run templates + templates = [run_template(template,mapq_location=mapq_location) for template in templates] + + + # Compare progressive and precalculate + for template in templates: + name = template["data"]["name"] + for other_template in templates: + other_name = other_template["data"]["name"] + + if "progressive" in name: + if name.strip("progressive") == other_name.strip("precalc"): + debug_data_cctbx = template["results"]["cctbx"] + debug_data_cctbx_mp = other_template["results"]["cctbx"] + probe_xyz = debug_data_cctbx["probe_xyz"] + probe_xyz_mp = debug_data_cctbx_mp["probe_xyz"] + qscore_per_atom = debug_data_cctbx["qscore_per_atom"] + qscore_per_atom_mp = debug_data_cctbx_mp["qscore_per_atom"] + + rmsd = np.sqrt(np.mean((qscore_per_atom-qscore_per_atom_mp) ** 2)) + cc = np.corrcoef(qscore_per_atom, qscore_per_atom_mp)[0][1] + print(template["data"]["name"],"rmsd",rmsd) + print(template["data"]["name"],"CC",cc) + assert rmsd<0.1, rmsd + assert cc>0.9, cc + + print("OK") diff --git a/cctbx/programs/qscore.py b/cctbx/programs/qscore.py index fa52f13b82..a8af6f5956 100644 --- a/cctbx/programs/qscore.py +++ b/cctbx/programs/qscore.py @@ -1,8 +1,11 @@ from __future__ import absolute_import, division, print_function from libtbx.program_template import ProgramTemplate from libtbx import group_args +from iotbx.pdb import input as pdb_input +from mmtbx.model import manager as model_manager +from iotbx.map_manager import map_manager +from iotbx.map_model_manager import map_model_manager from cctbx.maptbx import qscore - import numpy as np # ============================================================================= @@ -24,6 +27,8 @@ def validate(self): def run(self): print("Running") + + # do selection mmm = self.data_manager.get_map_model_manager() if self.params.qscore.selection != None: selection = np.where(mmm.model().selection(self.params.qscore.selection).as_numpy_array())[0] @@ -32,14 +37,69 @@ def run(self): self.result = group_args() return self.params.qscore.selection = selection - qscore_per_atom= qscore.run_qscore( + + # calculate shells + + if len(self.params.qscore.shells) ==0 : + start = self.params.qscore.shell_radius_start + stop = self.params.qscore.shell_radius_stop + num = self.params.qscore.shell_radius_num + shells = list(np.linspace( + start, + stop, + num, + endpoint=True)) + for shell in shells: + self.params.qscore.shells.append(shell) + + + # unsort model, make new mmm + model = self._unsort_model(mmm.model()) + # ignore hydrogens + model = model.select(model.selection("not element H")) + + # make mmm + mmm.set_model(model,overwrite=True) + + + # run qscore + qscore_result= qscore.calc_qscore( mmm, self.params.qscore, log=self.logger) - print("Finished") - self.result = group_args(qscore_per_atom=qscore_per_atom) + + self.result = group_args(**qscore_result) + def get_results(self): return self.result + + + def _unsort_model(self,model): + + # A very hacky way to get a model with atoms unsorted. Only works for pdb + # TODO: Need to add sort kwarg to data_manager.process_model_file somehow + model_input = model.get_model_input() + if 'cif' not in str(model_input.__class__): + h = pdb_input(source_info=None,lines=model_input.as_pdb_string()).construct_hierarchy(sort_atoms=False) + atom_name_list = [s.strip() for s in h.atoms().extract_name()] + scatterer_list = [s.strip() for s in h.atoms().extract_element()] + + model = model_manager.from_sites_cart(h.atoms().extract_xyz(), + crystal_symmetry=model.crystal_symmetry(), + atom_name_list = atom_name_list, + scatterer_list=scatterer_list + ) + return model + + @staticmethod + def _mmm_from_model_and_map(model,map): + map_data = map.map_data() + mm = map_manager(map_data=map_data, + unit_cell_grid=map_data.accessor().all(), + unit_cell_crystal_symmetry=model.unit_cell_crystal_symmetry(), + wrapping=False) + mmm = map_model_manager(model=model,map_manager=mm) + return mmm From 7e118e9b1ea40190b3ea55f070ecd41dcc4496e7 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Sun, 10 Dec 2023 13:51:33 -0800 Subject: [PATCH 084/748] boost: switch deprecated boost/timer.hpp to boost/timer/timer.hpp - Change header from boost/timer.hpp to boost/timer/timer.hpp - Change boost::timer to boost::timer::auto_cpu_timer - Handle switch to nanoseconds - Build Boost timer library if needed --- boost_adaptbx/SConscript | 38 ++++++++++++++++--- .../tests/python_streambuf_test_ext.cpp | 18 ++++----- cbflib_adaptbx/detectors/cbf_adaptor.h | 1 - cctbx/math/SConscript | 1 + cctbx/math/time_trigonometry.cpp | 10 ++--- scitbx/lbfgsb/boost_python/SConscript | 1 + scitbx/lbfgsb/dev/SConscript | 2 +- scitbx/lbfgsb/raw.h | 6 +-- spotfinder/core_toolbox/libdistl.cpp | 2 +- 9 files changed, 54 insertions(+), 25 deletions(-) diff --git a/boost_adaptbx/SConscript b/boost_adaptbx/SConscript index 02670e92ff..4ad2aef819 100644 --- a/boost_adaptbx/SConscript +++ b/boost_adaptbx/SConscript @@ -227,6 +227,7 @@ e.g. with "yum install python-dev" or "apt-get install python-dev". env.SharedLibrary( target="#lib/boost_tuple_ext", source="tuple_ext.cpp") + env.Append(LIBS=['boost_timer']) env.SharedLibrary( target="#lib/boost_adaptbx_python_streambuf_test_ext", source="tests/python_streambuf_test_ext.cpp") @@ -356,7 +357,7 @@ e.g. with "yum install python-dev" or "apt-get install python-dev". source=boost_system_src) #Boost.Chrono? - if boost_thread_uses_winthreads: + if os.path.isdir(os.path.join(env_etc.boost_dist, 'boost', 'chrono')): env_boost_chrono = env_boost_thread_and_co.Clone() simple_darwin_shlinkcom(env_etc, env, 'chrono') boost_chrono_src = [ @@ -365,10 +366,37 @@ e.g. with "yum install python-dev" or "apt-get install python-dev". os.path.join(env_etc.boost_dist, 'libs', 'chrono', 'src', '*.cpp'))] # For Windows (c.f. point 2 above) env_boost_chrono.Append(CPPDEFINES={'BOOST_CHRONO_DYN_LINK':1}) - env_boost_chrono.StaticLibrary( - target='#lib/boost_chrono', - source=boost_chrono_src, - LIBS=['boost_system']) + if boost_thread_uses_winthreads: + env_boost_chrono.StaticLibrary( + target='#lib/boost_chrono', + source=boost_chrono_src, + LIBS=['boost_system']) + else: + env_boost_chrono.SharedLibrary( + target='#lib/boost_chrono', + source=boost_chrono_src, + LIBS=['boost_system']) + + #Boost.Timer? + if os.path.isdir(os.path.join(env_etc.boost_dist, 'boost', 'timer')): + env_boost_timer = env_boost_thread_and_co.Clone() + simple_darwin_shlinkcom(env_etc, env, 'timer') + boost_timer_src = [ + '#' + os.path.relpath(p, os.path.dirname(env_etc.boost_dist)) + for p in glob.glob( + os.path.join(env_etc.boost_dist, 'libs', 'timer', 'src', '*.cpp'))] + # For Windows (c.f. point 2 above) + env_boost_timer.Append(CPPDEFINES={'BOOST_TIMER_DYN_LINK':1}) + if boost_thread_uses_winthreads: + env_boost_timer.StaticLibrary( + target='#lib/boost_timer', + source=boost_timer_src, + LIBS=['boost_chrono']) + else: + env_boost_timer.SharedLibrary( + target='#lib/boost_timer', + source=boost_timer_src, + LIBS=['boost_chrono']) # Build a Python extension using Boost.Thread so as to test it works. # This also constitutes a nice real-life example of diff --git a/boost_adaptbx/tests/python_streambuf_test_ext.cpp b/boost_adaptbx/tests/python_streambuf_test_ext.cpp index dc4c493e29..dfbfdaaecb 100644 --- a/boost_adaptbx/tests/python_streambuf_test_ext.cpp +++ b/boost_adaptbx/tests/python_streambuf_test_ext.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include namespace boost_adaptbx { namespace python { namespace { @@ -104,14 +104,14 @@ namespace boost_adaptbx { namespace python { namespace { } void time_read(char const *path, streambuf& input) { - boost::timer t; + boost::timer::auto_cpu_timer t; streambuf::istream is(input); work_for_time_read(is); - double py_t = t.elapsed(); + double py_t = t.elapsed().wall; std::ifstream std_is(path); - t.restart(); + t.start(); work_for_time_read(std_is); - double py_cpp = t.elapsed(); + double py_cpp = t.elapsed().wall; std::cout << "- Reading -\nPython adaptor: " << py_t; std::cout << "\nPure C++: " << py_cpp; if (py_t > py_cpp) { @@ -121,14 +121,14 @@ namespace boost_adaptbx { namespace python { namespace { } void time_write(char const *path, streambuf& output) { - boost::timer t; + boost::timer::auto_cpu_timer t; streambuf::ostream os(output); work_for_time_write(os); - double py_t = t.elapsed(); + double py_t = t.elapsed().wall; std::ofstream std_os(path); - t.restart(); + t.start(); work_for_time_write(std_os); - double py_cpp = t.elapsed(); + double py_cpp = t.elapsed().wall; std::cout << "- Writing -\nPython adaptor: " << py_t; std::cout << "\nPure C++: " << py_cpp; if (py_t > py_cpp) { diff --git a/cbflib_adaptbx/detectors/cbf_adaptor.h b/cbflib_adaptbx/detectors/cbf_adaptor.h index d3eb28ca0b..8916cc3b4f 100644 --- a/cbflib_adaptbx/detectors/cbf_adaptor.h +++ b/cbflib_adaptbx/detectors/cbf_adaptor.h @@ -16,7 +16,6 @@ #define cbf_failnez(x) { int err; err = (x); if (err) { \ std::cout<<"error code "< namespace iotbx { namespace detectors { diff --git a/cctbx/math/SConscript b/cctbx/math/SConscript index f8ebf573c6..b8de9b2e4d 100644 --- a/cctbx/math/SConscript +++ b/cctbx/math/SConscript @@ -3,6 +3,7 @@ env = env_base.Clone( CXXFLAGS=env_etc.cxxflags_base, ) env.Prepend(LIBS=["cctbx"]) +env.Append(LIBS='boost_timer') env.Append(LIBS=env_etc.libm) env_etc.include_registry.append( env=env, diff --git a/cctbx/math/time_trigonometry.cpp b/cctbx/math/time_trigonometry.cpp index aa992455ec..67b92d4dd5 100644 --- a/cctbx/math/time_trigonometry.cpp +++ b/cctbx/math/time_trigonometry.cpp @@ -1,23 +1,23 @@ #include #include -#include +#include int main() { unsigned const n = 1024, p = 1024; cctbx::math::cos_sin_table table(n); cctbx::math::cos_sin_exact exact; std::complex sum = 0; - boost::timer t; + boost::timer::auto_cpu_timer t; for (unsigned i=0; i #include #include -#include +#include #include @@ -168,8 +168,8 @@ namespace raw { void timer(FloatType& ttime) { - static boost::timer timer_; - ttime = static_cast(timer_.elapsed()); + static boost::timer::auto_cpu_timer timer_; + ttime = 1.0e-9 * static_cast(timer_.elapsed().wall); } //! Emulation of write statement with implicit loop. diff --git a/spotfinder/core_toolbox/libdistl.cpp b/spotfinder/core_toolbox/libdistl.cpp index f34910c65a..d94cf66e3e 100644 --- a/spotfinder/core_toolbox/libdistl.cpp +++ b/spotfinder/core_toolbox/libdistl.cpp @@ -55,7 +55,7 @@ */ #include -//#include +//#include //#include #include // to implement std::stack fix for stack overflow, see search_border_spot From 67e1bb7d10657d2e016857e035fa4331a90656ca Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 31 Jan 2024 09:24:33 -0800 Subject: [PATCH 085/748] boost: switch auto_cpu_timer to cpu_timer for lbfgsb to avoid extra output line --- scitbx/lbfgsb/raw.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scitbx/lbfgsb/raw.h b/scitbx/lbfgsb/raw.h index 62a33800ba..8d0ee52a5f 100644 --- a/scitbx/lbfgsb/raw.h +++ b/scitbx/lbfgsb/raw.h @@ -168,7 +168,7 @@ namespace raw { void timer(FloatType& ttime) { - static boost::timer::auto_cpu_timer timer_; + static boost::timer::cpu_timer timer_; ttime = 1.0e-9 * static_cast(timer_.elapsed().wall); } From 7b67e41a4c52814d02f6cd051b3abbd5fea0dec0 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 31 Jan 2024 11:47:26 -0800 Subject: [PATCH 086/748] Update CHANGELOG.rst for 2024.1 release [skip ci] --- CHANGELOG.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index dd25a5e7c1..b592fa75a6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,11 @@ +2024.1 +====== + +* Added checks to see if a model can be outupt in the PDB format +* Added custom scattering factors support to fmodel +* Reogranize fmodel PHIL +* Fixed boost::timer deprecation + 2023.12 ======= From 1ea7f1d2e688f7d50bce31590dab3214ded585eb Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 31 Jan 2024 12:26:58 -0800 Subject: [PATCH 087/748] CI: exclude releases/* for XFEL CI branch [skip ci] --- .azure-pipelines/xfel/azure-pipelines-xfel-branch.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.azure-pipelines/xfel/azure-pipelines-xfel-branch.yml b/.azure-pipelines/xfel/azure-pipelines-xfel-branch.yml index 55a26f453e..5ae1fd7251 100644 --- a/.azure-pipelines/xfel/azure-pipelines-xfel-branch.yml +++ b/.azure-pipelines/xfel/azure-pipelines-xfel-branch.yml @@ -11,6 +11,7 @@ trigger: exclude: - master - main + - releases/* resources: pipelines: From 1d4cd23e04788eb36fcbbb1744e1daa0b1b862e2 Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 1 Feb 2024 05:49:13 -0800 Subject: [PATCH 088/748] Adding functionality for use of mmCIF/PDB formatted files and removal of PDB-specific code. See modules/cctbx_project/iotbx/command_line/pdb_cif_conversion.py or type phenix.pdb_cif_conversion for summary. --- cctbx/maptbx/auto_sharpen.py | 3 +- cctbx/maptbx/segment_and_split_map.py | 68 +- cctbx/maptbx/tst_get_percentile_cutoffs.py | 5 +- iotbx/cli_parser.py | 24 +- iotbx/command_line/pdb_cif_conversion.py | 677 +++ iotbx/data_manager/model.py | 46 +- iotbx/map_model_manager.py | 36 +- iotbx/pdb/__init__.py | 7 +- .../forward_compatible_pdb_cif_conversion.py | 369 +- iotbx/pdb/hierarchy.py | 360 +- iotbx/pdb/mmcif.py | 14 +- iotbx/pdb/pdb_v3_cif_conversion.py | 257 +- iotbx/pdb/secondary_structure.py | 93 +- iotbx/pdb/tst_hierarchy.py | 165 +- iotbx/pdb/tst_utils.py | 35 + iotbx/pdb/utils.py | 528 +- .../regression/data/non_zero_origin_model.cif | 141 + .../data/non_zero_origin_model_split.cif | 143 + .../data/non_zero_origin_ncs_model.cif | 1272 +++++ .../tst_hierarchy_forward_compatible_pdb.py | 130 +- iotbx/regression/tst_hierarchy_pdb_v3.py | 88 +- ...in_shift_and_unit_cell_crystal_symmetry.py | 29 +- ...hift_and_unit_cell_crystal_symmetry_cif.py | 47 + iotbx/regression/tst_map_model_manager_cif.py | 298 ++ ...ap_model_manager_model_sharpening_5_cif.py | 75 + iotbx/run_tests.py | 5 +- libtbx/command_line/remove_unused_imports.py | 130 + libtbx/program_template.py | 27 + libtbx/python_code_parsing.py | 2 +- libtbx/test_utils/__init__.py | 17 + libtbx/tst_utils.py | 23 + mmtbx/building/merge_models.py | 35 +- mmtbx/building/minimize_chain.py | 15 +- mmtbx/command_line/map_box.py | 7 +- mmtbx/command_line/sort_hetatms.py | 56 +- mmtbx/masks/tst_masks.py | 1 + mmtbx/model/model.py | 55 +- mmtbx/process_predicted_model.py | 6 +- mmtbx/programs/process_predicted_model.py | 20 +- .../real_space/explode_and_refine.py | 2 +- mmtbx/regression/pdbs/AF_json_v3.cif | 2690 ++++++++++ .../pdbs/fibronectin_af_ca_1358_1537.cif | 228 + mmtbx/regression/pdbs/pae_model.cif | 2307 +++++++++ mmtbx/regression/pdbs/pae_model.pdb | 4588 ++++++++--------- mmtbx/regression/pdbs/test1.cif | 2307 +++++++++ mmtbx/regression/tst_chain_comparison_cif.py | 856 +++ mmtbx/regression/tst_domains_from_pae_cif.py | 157 + mmtbx/regression/tst_find_ss_structure.py | 25 +- mmtbx/regression/tst_find_ss_structure_cif.py | 3986 ++++++++++++++ mmtbx/regression/tst_minimize_chain.py | 2 +- mmtbx/regression/tst_minimize_chain_cif.py | 679 +++ mmtbx/regression/tst_pdbtools.py | 1 + .../tst_process_predicted_model_cif.py | 299 ++ .../regression/tst_regularize_from_pdb_cif.py | 100 + mmtbx/run_tests.py | 6 + mmtbx/secondary_structure/find_ss_from_ca.py | 236 +- .../regularize_from_pdb.py | 19 +- mmtbx/validation/chain_comparison.py | 20 +- mmtbx/validation/clashscore.py | 18 + 59 files changed, 20886 insertions(+), 2949 deletions(-) create mode 100644 iotbx/command_line/pdb_cif_conversion.py create mode 100644 iotbx/regression/data/non_zero_origin_model.cif create mode 100644 iotbx/regression/data/non_zero_origin_model_split.cif create mode 100644 iotbx/regression/data/non_zero_origin_ncs_model.cif create mode 100644 iotbx/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry_cif.py create mode 100644 iotbx/regression/tst_map_model_manager_cif.py create mode 100644 iotbx/regression/tst_map_model_manager_model_sharpening_5_cif.py create mode 100644 libtbx/command_line/remove_unused_imports.py create mode 100644 mmtbx/regression/pdbs/AF_json_v3.cif create mode 100644 mmtbx/regression/pdbs/fibronectin_af_ca_1358_1537.cif create mode 100644 mmtbx/regression/pdbs/pae_model.cif create mode 100644 mmtbx/regression/pdbs/test1.cif create mode 100644 mmtbx/regression/tst_chain_comparison_cif.py create mode 100644 mmtbx/regression/tst_domains_from_pae_cif.py create mode 100644 mmtbx/regression/tst_find_ss_structure_cif.py create mode 100644 mmtbx/regression/tst_minimize_chain_cif.py create mode 100644 mmtbx/regression/tst_process_predicted_model_cif.py create mode 100644 mmtbx/regression/tst_regularize_from_pdb_cif.py diff --git a/cctbx/maptbx/auto_sharpen.py b/cctbx/maptbx/auto_sharpen.py index dd7117a973..be2c01cd5e 100644 --- a/cctbx/maptbx/auto_sharpen.py +++ b/cctbx/maptbx/auto_sharpen.py @@ -914,7 +914,8 @@ def get_map_and_model(params=None, model_file=params.input_files.pdb_file if not os.path.isfile(model_file): raise Sorry("Missing the model file: %s" %(model_file)) - pdb_inp=iotbx.pdb.input(file_name=model_file) + from iotbx.pdb.utils import get_pdb_input + pdb_inp = get_pdb_input(file_name = model_file) if pdb_inp: # XXX added 2019-05-05 if origin_frac != (0,0,0): print("Shifting model by %s" %(str(origin_frac)), file=out) diff --git a/cctbx/maptbx/segment_and_split_map.py b/cctbx/maptbx/segment_and_split_map.py index 6da6fe6065..30055e5309 100644 --- a/cctbx/maptbx/segment_and_split_map.py +++ b/cctbx/maptbx/segment_and_split_map.py @@ -1,7 +1,6 @@ from __future__ import absolute_import, division, print_function from operator import itemgetter import iotbx.phil -import iotbx.pdb import iotbx.mrcfile from cctbx import crystal from cctbx import maptbx @@ -2609,8 +2608,8 @@ def write_ccp4_map(crystal_symmetry, file_name, map_data, def set_up_xrs(crystal_symmetry = None): # dummy xrs to write out atoms lines = ["ATOM 92 SG CYS A 10 8.470 28.863 18.423 1.00 22.05 S"] # just a random line to set up x-ray structure - from cctbx.array_family import flex - pdb_inp = iotbx.pdb.input(source_info = "", lines = lines) + from iotbx.pdb.utils import get_pdb_input + pdb_inp = get_pdb_input(lines = lines) xrs = pdb_inp.xray_structure_simple(crystal_symmetry = crystal_symmetry) scatterers = flex.xray_scatterer() return xrs, scatterers @@ -2637,10 +2636,11 @@ def write_atoms(tracking_data = None, sites = None, file_name = None, return text -def write_xrs(xrs = None, scatterers = None, file_name = "atoms.pdb", out = sys.stdout): +def write_xrs( + xrs = None, scatterers = None, file_name = "atoms.pdb", out = sys.stdout): from cctbx import xray xrs = xray.structure(xrs, scatterers = scatterers) - text = xrs.as_pdb_file() + text = xrs.as_pdb_file() # PDB OK just writing out some atoms if file_name: f = open(file_name, 'w') print(text, file = f) @@ -4734,7 +4734,7 @@ def get_bounds_for_au_box(params, # write out closest_sites to match original position coordinate_offset = -1*matrix.col(box.shift_cart) - write_atoms(file_name = 'one_au.pdb', + write_atoms(file_name = 'one_au.pdb', # PDB OK just writing out atoms crystal_symmetry = box_crystal_symmetry, sites = closest_sites+coordinate_offset) unique_closest_sites = closest_sites.deep_copy() @@ -5034,8 +5034,8 @@ def get_params(args, map_data = None, crystal_symmetry = None, if params.input_files.pdb_file: print("\nInput PDB file to be used to identify region to work with: %s\n" %( params.input_files.pdb_file), file = out) - pdb_inp = iotbx.pdb.input(file_name = params.input_files.pdb_file) - pdb_hierarchy = pdb_inp.construct_hierarchy() + from iotbx.pdb.utils import get_pdb_hierarchy + pdb_hierarchy = get_pdb_hierarchy(file_name = params.input_files.pdb_file) pdb_atoms = pdb_hierarchy.atoms() pdb_atoms.reset_i_seq() tracking_data.set_input_pdb_info(file_name = params.input_files.pdb_file, @@ -5643,7 +5643,8 @@ def get_ncs(params = None, tracking_data = None, file_name = None, from mmtbx.ncs.ncs import ncs ncs_object = ncs() try: # see if we can read biomtr records - pdb_inp = iotbx.pdb.input(file_name = file_name) + from iotbx.pdb.utils import get_pdb_input + pdb_inp = get_pdb_input(file_name = file_name) ncs_object.ncs_from_pdb_input_BIOMT(pdb_inp = pdb_inp, log = out) except Exception as e: # try as regular ncs object ncs_object.read_ncs(file_name = file_name, log = out) @@ -7730,11 +7731,12 @@ def write_region_maps(params, else: text = "_r" base_file = 'map%s_%d.ccp4' %(text, id) - base_pdb_file = 'atoms%s_%d.pdb' %(text, id) + base_pdb_file = 'atoms%s_%d.pdb' %(text, id) # PDB OK just atoms if tracking_data.params.output_files.output_directory: if not os.path.isdir(tracking_data.params.output_files.output_directory): os.mkdir(tracking_data.params.output_files.output_directory) - file_name = os.path.join(tracking_data.params.output_files.output_directory, base_file) + file_name = os.path.join( + tracking_data.params.output_files.output_directory, base_file) pdb_file_name = os.path.join( tracking_data.params.output_files.output_directory, base_pdb_file) else: @@ -8441,11 +8443,13 @@ def apply_origin_shift(origin_shift = None, if shifted_pdb_file and pdb_hierarchy: - import iotbx.pdb + info = pdb_hierarchy.pdb_or_mmcif_string_info( + target_filename = shifted_pdb_file, + crystal_symmetry = tracking_data.crystal_symmetry) + shifted_pdb_file = info.file_name + f = open(shifted_pdb_file, 'w') - print(iotbx.pdb.format_cryst1_record( - crystal_symmetry = tracking_data.crystal_symmetry), file = f) - print(pdb_hierarchy.as_pdb_string(), file = f) + print(info.pdb_string, file = f) f.close() print("Wrote shifted pdb file to %s" %( shifted_pdb_file), file = out) @@ -8467,8 +8471,8 @@ def apply_origin_shift(origin_shift = None, is_helical_symmetry = tracking_data.input_ncs_info.is_helical_symmetry) tracking_data.shifted_ncs_info.show_summary(out = out) - return shifted_ncs_object, pdb_hierarchy, target_hierarchy, tracking_data, \ - sharpening_target_pdb_inp + return shifted_pdb_file, shifted_ncs_object, pdb_hierarchy, \ + target_hierarchy, tracking_data, sharpening_target_pdb_inp def restore_pdb(params, tracking_data = None, out = sys.stdout): if not params.output_files.restored_pdb: @@ -8481,19 +8485,23 @@ def restore_pdb(params, tracking_data = None, out = sys.stdout): origin_shift = (-os[0], -os[1], -os[2]) print("Origin shift will be: %.1f %.1f %.1f "%(origin_shift), file = out) - import iotbx.pdb - pdb_inp = iotbx.pdb.input(file_name = params.input_files.pdb_to_restore) - pdb_hierarchy = pdb_inp.construct_hierarchy() + from iotbx.pdb.utils import get_pdb_hierarchy + pdb_hierarchy = get_pdb_hierarchy( + file_name = params.input_files.pdb_to_restore) + pdb_hierarchy = apply_shift_to_pdb_hierarchy( origin_shift = origin_shift, crystal_symmetry = tracking_data.crystal_symmetry, pdb_hierarchy = pdb_hierarchy, out = out) + info = pdb_hierarchy.pdb_or_mmcif_string_info( + crystal_symmetry = tracking_data.crystal_symmetry, + target_filename = params.output_files.restored_pdb) + tracking_data.crystal_symmetry = info.file_name + f = open(params.output_files.restored_pdb, 'w') - print(iotbx.pdb.format_cryst1_record( - crystal_symmetry = tracking_data.crystal_symmetry), file = f) - print(pdb_hierarchy.as_pdb_string(), file = f) + print(info.pdb_string, file = f) f.close() print("Wrote restored pdb file to %s" %( params.output_files.restored_pdb), file = out) @@ -10072,11 +10080,11 @@ def get_target_boxes(si = None, ncs_obj = None, map = None, sharpening_centers_file = os.path.join( si.output_directory, "sharpening_centers.pdb") - write_atoms(file_name = sharpening_centers_file, + write_atoms(file_name = sharpening_centers_file, # PDB OK crystal_symmetry = si.crystal_symmetry, sites = centers_cart) ncs_sharpening_centers_file = os.path.join( si.output_directory, "ncs_sharpening_centers.pdb") - write_atoms(file_name = ncs_sharpening_centers_file, + write_atoms(file_name = ncs_sharpening_centers_file, # PDB OK crystal_symmetry = si.crystal_symmetry, sites = all_cart) print("\nSharpening centers (matching shifted_map_file).\n\n "+\ @@ -11769,9 +11777,9 @@ def run(args, if target_model: target_hierarchy = target_model.get_hierarchy() elif params.input_files.target_ncs_au_file: # read in target - import iotbx.pdb - target_hierarchy = iotbx.pdb.input( - file_name = params.input_files.target_ncs_au_file).construct_hierarchy() + from iotbx.pdb.utils import get_pdb_hierarchy + pdb_hierarchy = get_pdb_hierarchy( + file_name = params.input_files.target_ncs_au_file) print("\nShifting model based on origin shift (if any)", file = out) print("Coordinate shift is (%7.2f, %7.2f, %7.2f)" %( @@ -11797,7 +11805,7 @@ def run(args, params.output_files.shifted_pdb_file) else: shifted_pdb_file = None - ncs_obj, pdb_hierarchy, target_hierarchy, \ + shifted_pdb_file, ncs_obj, pdb_hierarchy, target_hierarchy, \ tracking_data, sharpening_target_pdb_inp = apply_origin_shift( shifted_map_file = shifted_map_file, shifted_pdb_file = shifted_pdb_file, @@ -11810,6 +11818,8 @@ def run(args, tracking_data = tracking_data, sharpening_target_pdb_inp = sharpening_target_pdb_inp, out = out) + if shifted_pdb_file: + params.output_files.shifted_pdb_file = os.path.split(shifted_pdb_file)[-1] if target_hierarchy: target_xyz = target_hierarchy.atoms().extract_xyz() diff --git a/cctbx/maptbx/tst_get_percentile_cutoffs.py b/cctbx/maptbx/tst_get_percentile_cutoffs.py index 8f2e61c9a4..bc3f8aa273 100644 --- a/cctbx/maptbx/tst_get_percentile_cutoffs.py +++ b/cctbx/maptbx/tst_get_percentile_cutoffs.py @@ -1,7 +1,6 @@ from __future__ import absolute_import, division, print_function from cctbx.array_family import flex from libtbx.test_utils import approx_equal -import iotbx.pdb import time from cctbx import maptbx @@ -74,7 +73,9 @@ def percentile_cutoffs_inefficient( return cutoffp, cutoffm def exercise(): - xrs = iotbx.pdb.input(source_info=None, lines=pdb_str).xray_structure_simple() + from iotbx.pdb.utils import get_pdb_input + pdb_inp = get_pdb_input(text = pdb_str) + xrs = pdb_inp.xray_structure_simple() fc = xrs.structure_factors(d_min=1.5).f_calc() fft_map = fc.fft_map(resolution_factor=0.1) fft_map.apply_sigma_scaling() diff --git a/iotbx/cli_parser.py b/iotbx/cli_parser.py index 6ee182e8de..2ed53ed126 100644 --- a/iotbx/cli_parser.py +++ b/iotbx/cli_parser.py @@ -275,6 +275,12 @@ def add_default_options(self): '--dry-run', '--dry_run', action='store_true', help='performs basic validation the input arguments, but does not run the program' ) + # --get-parser + # proceeds until the validate step + self.add_argument( + '--get-parser', '--get_parser', action='store_true', + help='sets up the parameters only' + ) # --citations will use the default format # --citations= will use the specified format @@ -873,7 +879,6 @@ def run_program(program_class=None, parser_class=CCTBXParser, custom_process_arg if args is None: args = sys.argv[1:] - # start profiling pr = None if '--profile' in args: @@ -907,6 +912,8 @@ def run_program(program_class=None, parser_class=CCTBXParser, custom_process_arg unused_phil_raises_sorry=unused_phil_raises_sorry, logger=logger) namespace = parser.parse_args(args) + if namespace.get_parser: + return parser # start program if namespace.dry_run: @@ -968,4 +975,19 @@ def run_program(program_class=None, parser_class=CCTBXParser, custom_process_arg return result # ============================================================================= +def get_program_params(run): + """Tool to get parameters object for a program that runs with + the program template. + params: run: the program template object + returns: parameters for this program as set up by the program template + Get the run something like this way: + from phenix.programs import map_to_model as run + """ + + from iotbx.cli_parser import run_program + parser=run_program(program_class=run.Program,args=['--get_parser'], + logger=sys.stdout) + return parser.working_phil.extract() + + # end diff --git a/iotbx/command_line/pdb_cif_conversion.py b/iotbx/command_line/pdb_cif_conversion.py new file mode 100644 index 0000000000..fef7317696 --- /dev/null +++ b/iotbx/command_line/pdb_cif_conversion.py @@ -0,0 +1,677 @@ +from __future__ import absolute_import, division, print_function +# LIBTBX_SET_DISPATCHER_NAME phenix.pdb_cif_conversion + +info_string = ''' + +=========================================================================== +=========================================================================== +CCTBX methods, tools, and strategies for conversion of PDB-format +based methods to mmCIF/PDB compatible methods +2024-01-30 TT +=========================================================================== +=========================================================================== + SECTIONS: + + SUMMARY OF RECOMMENDED PROCEDURES + GOALS + RECOMMENDED OVERALL APPROACHES + DETAILED SUGGESTIONS FOR MAKING CODE CIF-COMPLIANT + USING THE PROGRAM TEMPLATE TO HANDLE PDB/MMCIF INPUT/OUTPUT + TOOLS AVAILABLE IF YOU CANNOT USE THE PROGRAM TEMPLATE + REWRITING CODE USING PDB-FORMATTED TEXT + TOOLS AVAILABLE TO FIND CODE THAT NEEDS TO BE MADE CIF-COMPATIBLE + CREATING CIF TESTS TO CHECK CODE WITH MODELS THAT CANNOT FIT IN PDB FORMAT + USING FORWARD-COMPATIBLE PDB FORMAT FOR CODE REQUIRING PDB-FORMATTED TEXT + DETAILS OF METHODS ADDED FOR WORKING WITH PDB/CIF + +=========================================================================== +=========================================================================== + +SUMMARY OF RECOMMENDED PROCEDURES + +I. USE THE PROGRAM TEMPLATE +II. TOOLS ARE AVAILABLE IF YOU CANNOT USE THE PROGRAM TEMPLATE +III. IF CODE USES PDB-FORMATTED TEXT IT SHOULD BE REWRITTEN +IV. TOOLS ARE AVAILABLE TO FIND CODE THAT NEEDS TO BE MADE CIF-COMPATIBLE +V. CREATE CIF TESTS TO CHECK CODE WITH MODELS THAT CANNOT FIT IN PDB FORMAT +VI. USE FORWARD-COMPATIBLE PDB FORMAT FOR CODE REQUIRING PDB-FORMATTED TEXT + +=========================================================================== +=========================================================================== + +GOALS: + +I. Read, write and work with models in mmCIF or PDB format interchangeably if + models fit in PDB format, otherwise read and write only in mmCIF. In + exceptional circumstances, allow read/write of forward-compatible PDB files + representing models that do not fit in PDB format. + +II. Use the cctbx hierarchy and model objects to contain and work with + all models + +III. Write mmCIF or PDB-formatted files with the rules: + a. Write as PDB with extension '.pdb' if output model fits in PDB format and, + 1. User specifies PDB format, or, + 2. User does not specify format and either there is no input model or it is + PDB format + b. Write as mmCIF, with extension '.cif', if + 1. Output model does not fit in PDB format, or + 2. User specifies mmCIF, or + 3. Input model is mmCIF and User does not specify which to use +=========================================================================== +=========================================================================== + + RECOMMENDED OVERALL APPROACHES + (DETAILS IN THE SECTION "DETAILED SUGGESTIONS FOR MAKING CODE CIF-COMPLIANT") + +I. USE THE PROGRAM TEMPLATE + +Use the Program Template and its data_manager to carry out all read/write +and parsing of model files. If you do this then all mmCIF/PDB handling is +taken care of for you, except only that you need to capture the actual +file names written by the data_manager. + +II. TOOLS ARE AVAILABLE IF YOU CANNOT USE THE PROGRAM TEMPLATE + +For existing code that cannot use the Program Template or that +reads and writes files outside of the Program Template: + + a. Try to pass the data_manager from the Program Template and use + it to read/write files in your programs. Then once again you only + need to capture the actual file names written by the data_manager. + + b. If you cannot use the data_manager, use the pdb_or_mmcif_string_info + method of the model manager or the hierarchy to write your files. + This method allows setting the preferred output format and capturing + the name of the actual file that is written. + + Normally you should keep track of the actual file name that is written + and then use that later when you read the file back in. If you do + not use this approach, you can use the get_cif_or_pdb_file_if_present + tool from iotbx.pdb.utils with your guess of the file name, and it will + return the name of the file with that name if present, or the name of a + present file with the opposite extension if it is present instead, + or blank if neither is present. + + You can use the get_pdb_info tool from iotbx.pdb.utils or the + iotbx.pdb.input method to read in either mmCIF or PDB formatted files. + +III. IF CODE USES PDB-FORMATTED TEXT IT SHOULD BE REWRITTEN + +If code parses PDB-formatted text, generally it should be rewritten +to use the methods in the hierarchy class. + + a. For example, code that edits formatted strings representing a PDB file + to remove HETATM records can be replaced with the method + remove_hetero() of the hierarchy class. + + b. All code that accumulates lines from multiple PDB files and then interprets + the new lines should be replaced by reading each PDB file and merging + the resulting hierarchies or models. This can be done for model files + with the simple_combine or add_hierarchies methods available in + iotbx.pdb.utils, or simple custom code can be written to add chains + from one hierarchy onto another hierarchy. + + +IV. TOOLS ARE AVAILABLE TO FIND CODE THAT NEEDS TO BE MADE CIF-COMPATIBLE + You can find possibly-problematic code using the tool + libtbx.find_pdb_mmcif_problems and specifying a file or directory to check + +V. CREATE CIF TESTS TO CHECK CODE WITH MODELS THAT CANNOT FIT IN PDB FORMAT + For any code that uses pdb/cif files or that uses the hierarchy object + should be tested with models that do not fit in PDB format. It is + recommended that each standard test using models should be duplicated + and run with non-PDB-compliant models. The tool + convert_pdb_to_cif_for_pdb_str can be used to edit strings in place in + tests so that identical starting strings can be used in the original and + non-PDB-compliant tests. + +VI. USING FORWARD-COMPATIBLE PDB FORMAT FOR CODE REQUIRING PDB-FORMATTED TEXT +If you have code or 3rd party code that requires PDB-formatted text you can +convert any hierarchy into a forward-compatible hierarchy that can be +formatted in PDB format (hybrid-36 PDB format). This conversion (currently) +amounts to replacing chainIDs that are longer than 2 characters with +2-character IDs, and residue names that are 5 characters long with +3-character residue names. A table of conversions is kept that allows +reversion of the hierarchy to its original form. + +a. This procedure is only partially supported and is not encouraged for + anything except cases that cannot be managed without PDB formatting. + +b. When this is done, it should be carried out either one-way (conversion + to forward-compatible PDB and never converted back), or else the + conversion should be carried out, the operation with the converted file + done, and the result converted back, all in one small block. + +c. Note that conversion may be very complicated if the chain IDs or the + residue names are needed in whatever operation is done with the + converted file. This is one of the reasons this approach is not + recommended except where required. Tools are supplied to convert + any text-based parameters are used with the converted file, but they + are not general and not always simple to use. + +=========================================================================== +=========================================================================== + + DETAILED SUGGESTIONS FOR MAKING CODE CIF-COMPLIANT + +--------------------------------------------------------------------------- +--------------------------------------------------------------------------- +I. USING THE PROGRAM TEMPLATE TO HANDLE PDB/MMCIF INPUT/OUTPUT + +A. Use the Program Template and use data_manager for + all model read/write. If you do this there is only one thing + you need to do: capture the actual file name written by + the data_manager. + + The program template automatically adds the scope + 'output.target_output_format' to your parameters, allowing + a user to set the output format. If it is not set, the program + template sets it to the format of the default incoming model if + present, otherwise to 'pdb'. + + def run(self): + ... + self.final_file_name = self.data_manager.write_model_file( + model, self.params.output.file_name) + print("Final model written to '%s'" %self.final_file_name) + + def get_results(self): + return group_args( + output_file_name = self.final_file_name, + ...) + +--------------------------------------------------------------------------- +--------------------------------------------------------------------------- + +II. TOOLS AVAILABLE IF YOU CANNOT USE THE PROGRAM TEMPLATE + +If you do not use the Program template, you will need to keep track +of the target output format and write your files with a pdb/cif-aware +method. + +1. Add target_output_format to your "output" or "output_files" scope: + + target_output_format = *None pdb mmcif + .type = choice + .help = Desired output format (if possible). Choices are None (\ + try to use input format), pdb, mmcif. If output model\ + does not fit in pdb format, mmcif will be used. \ + Default is pdb. + .short_caption = Desired output format + +2. After you set up your parameters, set the target_output_format: + + from iotbx.pdb.utils import set_target_output_format_in_params + set_target_output_format_in_params(params) + +3. When you write model files, supply the target output format and + capture the actual file name written: + +a. If you have a data manager and a model object: + + file_name = self.data_manager.write_model_file( + model, self.params.output.file_name) + print("Model written to '%s'" %file_name) + +b. If have only a hierarchy and crystal_symmetry and params: + + info = ph.pdb_or_mmcif_string_info( + target_format = params.output_files.target_output_format, + target_filename = params.output.file_name, + write_file = True, + crystal_symmetry=crystal_symmetry) + file_name = info.file_name + print("Model written to '%s'" %file_name) + +c. When you read pdb/mmcif files, if you do not know the ending .pdb or + .mmcif, use the function get_cif_or_pdb_file_if_present: + + from iotbx.pdb.utils import get_cif_or_pdb_file_if_present + fn = get_cif_or_pdb_file_if_present(fn) + +--------------------------------------------------------------------------- +--------------------------------------------------------------------------- +III. REWRITING CODE USING PDB-FORMATTED TEXT + +A. You will want to remove all instances of the following methods. None of these +are mmcif-compliant: + + model.model_as_pdb() + ph.as_pdb_string() + ph.write_pdb_file() + +Suggested replacements: + + 1. If your code uses model.model_as_pdb(): + + file_name = 'mypdb.pdb' + str = model.model_as_pdb() + f = open(file_name,'w') + print(str, file = f) + f.close() + print("Wrote model to '%s'" %file_name) + + Use instead model.pdb_or_mmcif_string_info(): + + file_name = 'mypdb.pdb' + info = model.pdb_or_mmcif_string_info( + target_format = params.output_files.target_output_format, + target_filename = file_name, + write_file = True) + file_name = info.file_name + print("Wrote model to '%s'" %file_name) + + 2. If your code uses ph.as_pdb_string() and you need the string: + + file_name = 'mypdb.pdb' + str = ph.as_pdb_string() + print("Doing something with a string %s" %str) + + Use instead model.pdb_or_mmcif_string_info() which will give you a PDB or + mmcif string as appropriate: + + info = model.pdb_or_mmcif_string_info( + target_format = params.output_files.target_output_format) + str = info.pdb_string + print("Doing something with a string %s" %str) + + 3. If your code uses ph.as_pdb_string() or ph.write_pdb_file() and you are + writing the string to a file like this: + + file_name = 'mypdb.pdb' + str = ph.as_pdb_string(crystal_symmetry = crystal_symmetry) + f = open(file_name,'w') + print(str, file = f) + f.close() + print("Wrote model to '%s'" %file_name) + + or like this: + + file_name = 'mypdb.pdb' + str = ph.write_model_file(file_name) + print("Wrote model to '%s'" %file_name) + + Use instead pdb_or_mmcif_string_info: + + file_name = 'mypdb.pdb' + info = ph.pdb_or_mmcif_string_info( + target_format = params.output_files.target_output_format, + target_filename = file_name, + write_file = True) + file_name = info.file_name + print("Wrote model to '%s'" %file_name) + +B. You will want to rewrite all code that interprets model text line-by-line. + + If your code looks like this: + + for line in open(model_file).readlines(): + do_something_based_on_a_line_in_file(line) + + You will want instead to read in the model to get a hierarchy, then + use hierarchy methods to change or interpret the hierarchy. + +C. If your code catenates model text like this: + + new_file_name = 'combined.pdb' + raw_records = list(open(model_file).splitlines()) + raw_records += list(open(other_model_file).splitlines()) + f = open(new_file_name,'w') + print(raw_records, file = f) + f.close() + print("Wrote combined model lines to '%s'" %new_file_name) + + You will want to rewrite it to read in the models and then merge them: + + new_file_name = 'combined.pdb' + m1 = dm.get_model_file(model_file) + m2 = dm.get_model_file(other_model_file) + from iotbx.pdb.utils import simple_combine + m1 = simple_combine(model_list = [m1,m2]) # NOTE: changes m1 in place + new_file_name = dm.write_model_file(m1, new_file_name) # capture actual name + print("Wrote combined model lines to '%s'" %new_file_name) + + Note: you can also merge hierarchies directly with the add_hierarchies method + in iotbx.pdb.utils + +D. If your code names intermediate files with the extension '.pdb': + + new_file_name = 'model.pdb' + f = open(new_file_name,'w') + print(model.model_as_pdb(), file = f) + f.close() + print("Wrote intermediate model lines to '%s'" %new_file_name) + + Use the data_manager or pdb_or_mmcif_string_info to write the file, and + capture the actual file name so that you can use it when you read the + contents of the file back in. + + new_file_name = 'model.pdb' + new_file_name = dm.write_model_file(model, new_file_name) + print("Wrote intermediate model lines to '%s'" %new_file_name) + + +--------------------------------------------------------------------------- +--------------------------------------------------------------------------- +V. TOOLS AVAILABLE TO FIND CODE THAT NEEDS TO BE MADE CIF-COMPATIBLE + +A. You can use the libtbx.find_pdb_mmcif_problems to help identify code + that needs to be modified to make it cif-compatible. + + You can say: + + libtbx.find_pdb_mmcif_problems phenix/phenix/command_line + + and it (recursively) will go through all files/directories in command_line + and look for problems + + Or you can work on just one file: + + libtbx.find_pdb_mmcif_problems phase_and_build.py + + ==================================================================== + ==>> Here is a **SUPER-HELPFUL HINT** to make the editing easy: <<== + ==================================================================== + +B. Run libtbx.find_pdb_mmcif_problems with the argument "mark_lines": + + 1. Run it like this: + + libtbx.find_pdb_mmcif_problems phase_and_build.py mark_lines + + This will edit phase_and_build.py, placing text like: + " # XXX CHECK PDB: .pdb'" + at the end of possibly-problematic lines + + 2. Then you just edit this file (phase_and_build.py) + a. find all the places where "CHECK PDB" shows up + b. fix the problems + c. mark non-problems with the text " # PDB OK", add explanation if you want + + 3. Then clean up by running: + + libtbx.find_pdb_mmcif_problems phase_and_build.py unmark_lines + + which will remove all the " # XXX CHECK PDB" text + + 4. Finally, run: + + libtbx.find_pdb_mmcif_problems phase_and_build.py + + again to make sure you got it all. + +C. You can run libtbx.find_pdb_mmcif_problems with a file containing a list + of files: + + 1. Put list of your files/directories and put them in files.list: + files.list: + phenix/phenix/programs/myfile.py + phenix/phenix/mydir + 2. Mark/unmark all likely PDB problems in your files + libtbx.find_pdb_mmcif_problems files.list mark_lines + libtbx.find_pdb_mmcif_problems files.list unmark_lines + +--------------------------------------------------------------------------- +--------------------------------------------------------------------------- +V. CREATING CIF TESTS TO CHECK CODE WITH MODELS THAT CANNOT FIT IN PDB FORMAT + + You will want to create a cif-only version of all your tests that use + models. The purpose of this is to test all the code that handles + chain IDs and residue names. + +A. Simple conversion of tests to mmCIF if your test uses PDB strings. + If your test has PDB strings like: pdb_str_1 = """pdb-text""" at the + top of the file, before any function definitions, you can convert + the test to mmCIF by placing two lines below all the pdb_str_xxx + definitions: + + from libtbx.test_utils import convert_pdb_to_cif_for_pdb_str + convert_pdb_to_cif_for_pdb_str(locals()) + + This will make all your PDB strings into mmCIF strings with long + chain IDS. You can choose how to edit your chain ids if you want: + + convert_pdb_to_cif_for_pdb_str(locals(), chain_addition="ZXLONG") + + You might also want to rename some of your residue names + + You can also do this for strings that have some other name: + + my_string="""text""" + convert_pdb_to_cif_for_pdb_str(locals(), key_str = 'my_string') + + Now your test should run just as it did before except that the + chain IDs (and optionally HETATM residue names) may be different. + +B. If your test uses models in PDB files, you may simply want to + make copies of all your models, converting your PDB files into + mmCIF and edit the chain IDs: + + You can do this with pdbtools: + + phenix.pdbtools x.pdb output.file_name=x.cif old_id=A new_id=AXZLONG + + to make them longer than 2 characters. If you want, edit + the HETATM records to change the residue names too. + + Then make a new test tst_xxxx_cif.py that uses these PDB files. + Note: make sure you rename any restraints file to xxx_restraints.cif + so you don't overwrite xxx.cif with the new cif-formatted version + of xxx.pdb + +--------------------------------------------------------------------------- +--------------------------------------------------------------------------- +VI. USING FORWARD-COMPATIBLE PDB FORMAT FOR CODE REQUIRING PDB-FORMATTED TEXT + + The hierarchy class has tools to convert a hierarchy that cannot fit into + PDB format into one that can and to keep track of the conversion so that + it can be reversed. + + The main tools are: + + 1. Convert a hierarchy to one that fits in PDB format, saving conversion + information + fc_ph = ph.as_forward_compatible_hierarchy() + + 2. Get the conversion information: + conversion_info = fc_ph.conversion_info() + + 3. Convert back using saved conversion info : + original_ph = fc_ph.forward_compatible_hierarchy_as_standard() + + 4. Convert one-way to PDB format compatible string: + str = ph.as_forward_compatible_string() + + 5. Identify whether hierarchy has been converted: + is_fc = ph.is_forward_compatible_hierarchy() + + 6. Use saved conversion_info to edit text containing words matching + chain IDs or residue names, making new text match the chain IDs and + residue names used in the forward_compatible hierarchy: + new_text = ph.convert_multi_word_text_to_forward_compatible(text) + + These methods are described in detail in the hierarchy.py code. +--------------------------------------------------------------------------- +--------------------------------------------------------------------------- + DETAILS OF METHODS ADDED FOR WORKING WITH PDB/CIF + + MODULE: iotbx/cli_parser.py + +Method to return the parameters as set up by the data_manager: + +def get_program_params(run) + + MODULE: iotbx/data_manager/model.py + +Method to set the desired output format for model files, based on user +specification and the format of the default input model file: + + def set_target_output_format(self, target_output_format): + +Modified write_model_file method to check whether output model fits in PDB +format and to write as mmCIF it does not, or if the user specified cif as the +output format. + + def write_model_file(self, model_str, filename=Auto, extension=Auto, + + + MODULE: iotbx/pdb/hierarchy.py: + +Methods for converting hierarchy to forward-compatible (fits in PDB format, + see above): + + def is_forward_compatible_hierarchy(self): + def conversion_info(self): + def convert_multi_word_text_to_forward_compatible(self, text): + def as_forward_compatible_hierarchy(self, conversion_info = None): + def forward_compatible_hierarchy_as_standard(self, conversion_info = None): + def as_forward_compatible_string(self, **kw): + +Method for writing as PDB or mmCIF string, using supplied target_format if +possible, optionally writing as file, returning group_args object with +text string, file_name written, and is_mmcif marker: + + def pdb_or_mmcif_string_info(self, + +NOTE: This method and the corresponding method in model.py use +default of segid_as_auth_segid = True, different from the default in +model_as_mmcif() in model.py and as_mmcif_string() in hierarchy.py +The default of segid_as_auth_segid = True causes any text in the SEGID +field read from a PDB-formatted file to be written to the auth_segid field +in the mmCIF output, and the chain ID from the PDB file is used as +the actual chain ID in the mmCIF output. + +Methods supplied so that code elsewhere does not need to parse PDB formatted +strings to remove HETATM, TER, and BREAK records and to sort chains in order +of chain ID: + + def remove_hetero(self): + def contains_hetero(self): + def contains_break_records(self): + def remove_ter_or_break(self): + def sort_chains_by_id(self): + + MODULE: mmtbx/model/model.py: + +Method matching one of the same name in hierarchy.py, +for writing as PDB or mmCIF string, using supplied target_format if +possible, optionally writing as file, returning group_args object with +text string, file_name written, and is_mmcif marker: + + def pdb_or_mmcif_string_info(self, + +NOTE: This method and the corresponding method in hierarchy.py use +default of segid_as_auth_segid = True, different from the default in +model_as_mmcif() in model.py and as_mmcif_string() in hierarchy.py. +The default of segid_as_auth_segid = True causes any text in the SEGID +field read from a PDB-formatted file to be written to the auth_segid field +in the mmCIF output, and the chain ID from the PDB file is used as +the actual chain ID in the mmCIF output. + + MODULE: iotbx/pdb/utils.py: + +Methods to set the target_output_format parameter in the scope output/output_files: + +def set_target_output_format_in_params(params, +def get_input_model_file_name_from_params(params): +def target_output_format_in_params(params): +def get_target_output_format_from_file_name(file_name, +def move_down_scope_to_input_files(params, levels = 3): + +Method to find file named with 'pdb' or 'cif' when given one or the other. +Returns the file supplied if present, otherwise the other file if it is present, +otherwise empty string. Can find files with the pdb/cif followed by an +underscore such as myfile.pdb_1. Only looks for pdb/cif in the extension: + +def get_cif_or_pdb_file_if_present(file_name): + +Methods to merge hierarchies: + +def add_hierarchies(ph_list, create_new_chain_ids_if_necessary = True): +def add_hierarchy(s1_ph, s2_ph, create_new_chain_ids_if_necessary = True): +def catenate_segment_onto_chain(model_chain, s2, gap = 1, +def get_chain(s1_ph, chain_id = None): + +Methods to merge and edit models: + +def add_model(s1, s2, create_new_chain_ids_if_necessary = True): +def catenate_segments(s1, s2, gap = 1, +def catenate_segment_onto_chain(model_chain, s2, gap = 1, +def simple_combine(model_list, + +Method to get hierarchy and pdb_input objects from text files. These differ +from iotbx.pdb.input() and construct_hierarchy() by allowing empty text +for both mmCIF and PDB input, and in packaging a hierarchy, pdb_input, and +crystal_symmetry in a single group_args object that is returned + +Normal use: pdb_info = get_pdb_info(file_name = file_name) + +def get_pdb_info(text = None, file_name = None, lines = None, + +Shortcuts to get just hierarchy or pdb_input: + +def get_pdb_hierarchy(text=None, file_name = None, +def get_pdb_input(text = None, file_name = None, lines = None, + +Helper methods for reading pdb_input text and getting hierarchy + +def lines_are_really_text(lines): +def get_lines(text = None, file_name = None, lines = None): +def type_of_pdb_input(pdb_inp): +def try_to_get_hierarchy(pdb_inp): + +Methods to guess elements in atoms object from a hierarchy: + +def check_for_missing_elements(atoms, file_name = None): +def guess_chemical_elements(atoms, check_pseudo = False, +def check_for_incorrect_spacings(atoms): + +Method checking for atom names starting with "Z" (used as pseudo-atoms) + +def check_for_pseudo_atoms(atoms): + + + MODULE: iotbx/pdb/forward_compatible_pdb_cif_conversion.py + +This module has low-level methods for conversion of hierarchies to a PDB-compatible +form, for reading and writing these hierarchies, and for converting them +back to the original form. + +Normally the methods in the hierarchy class should be used, rather +than using these low-level methods directly. + +The methods available are: + + def __init__(self, hierarchy = None, + def is_initialized(self): + def conversion_required(self): + def conversion_as_remark_hetnam_string(self): + def convert_hierarchy_to_forward_compatible_pdb_representation(self, + def convert_hierarchy_to_full_representation(self, hierarchy): + def set_conversion_tables_from_remark_hetnam_records( + def _set_up_conversion_table(self, key, hierarchy, unique_values_dict = None): + def _unique_chain_ids_from_hierarchy(self, hierarchy): + def _unique_resnames_from_hierarchy(self, hierarchy): + def _get_any_forward_compatible_pdb_representation(self, + def _get_forward_compatible_pdb_representation(self, ids, max_chars, + def _get_new_unique_id(self, id, max_chars, exclude_list, + def _get_new_id(self, n_chars, exclude_list, end_with_tilde = None, + def _choose_allowed_ids(self, unique_values, max_chars): + def _is_allowed(self, u, max_chars): + def _get_conversion_table_info(self, key): + def get_full_text_from_forward_compatible_pdb_text(self, key = None, + def convert_multi_word_text_to_forward_compatible(self, + def get_forward_compatible_pdb_text_from_full_text(self, + + +=========================================================================== +=========================================================================== + +''' + +def run(): + print(info_string) + +if (__name__ == "__main__"): + run() diff --git a/iotbx/data_manager/model.py b/iotbx/data_manager/model.py index 150aca98b5..e47a712e13 100644 --- a/iotbx/data_manager/model.py +++ b/iotbx/data_manager/model.py @@ -106,6 +106,13 @@ def _is_valid_model_type(self, model_type): valid = valid and (mt in self._possible_model_types) return valid + def set_target_output_format(self, target_output_format): + if target_output_format == 'mmcif': target_output_format='cif' + if not target_output_format in ['cif','pdb']: + raise Sorry("Target output format (%s) not recognized, options are" %( + target_output_format) + "pdb or cif") + self._target_output_format = target_output_format + def set_default_model_type(self, model_type): if not self._is_valid_model_type(model_type): raise Sorry('Unrecognized model type, "%s," possible choices are %s.' % @@ -271,7 +278,7 @@ def get_default_output_model_filename(self, extension=Auto): return filename def write_model_file(self, model_str, filename=Auto, extension=Auto, - format=Auto, overwrite=Auto): + format=Auto, overwrite=Auto, append_ext = True): ''' Function for writing a model to file @@ -287,11 +294,14 @@ def write_model_file(self, model_str, filename=Auto, extension=Auto, and params.output.serial extension: str or Auto The extension to be added. If set to Auto, defaults to .cif - format: pdb or cif or Auto. If set to Auto, defaults to format of - original file. + format: pdb or cif (mmcif treated as cif) or Auto. If set to + Auto, defaults to format of original file. + If self._target_output_format is not None, + always write to this format if possible overwrite: bool or Auto Overwrite filename if it exists. If set to Auto, the overwrite state of the DataManager is used. + append_ext: bool. If True append extension if necessary Returns ------- @@ -301,20 +311,40 @@ def write_model_file(self, model_str, filename=Auto, extension=Auto, extension to cif by default. This function may alter the extension based on the desired format. ''' + target_output_format = getattr(self,'_target_output_format',None) + if target_output_format and (format in [Auto, None]): + # Take format from self._target_output_format + format = target_output_format + + if format == 'mmcif': format = 'cif' # mmcif and cif are synonyms here + if isinstance(model_str, mmtbx.model.manager): + if format == 'cif' or ( format is Auto and model_str.input_model_format_cif()): extension = '.cif' model_str = model_str.model_as_mmcif() else: - extension = '.pdb' - model_str = model_str.model_as_pdb() + if model_str.get_hierarchy().fits_in_pdb_format(): + extension = '.pdb' + model_str = model_str.model_as_pdb() + else: # XXX Catch case where it does not fit in PDB format + extension = '.cif' + model_str = model_str.model_as_mmcif() if filename is Auto: filename = self.get_default_output_model_filename(extension=extension) - elif extension is not Auto and (not filename.endswith(extension)): - filename += extension - return self._write_text(ModelDataManager.datatype, model_str, + elif (extension is not Auto) and (not filename.endswith(extension)) and ( + append_ext): + if filename.endswith(".pdb") or filename.endswith(".cif"): + fn,ext = os.path.splitext(filename) + filename = fn + extension # replace extension + else: + filename += extension + if model_str: + return self._write_text(ModelDataManager.datatype, model_str, filename=filename, overwrite=overwrite) + else: + return '' # ============================================================================= # end diff --git a/iotbx/map_model_manager.py b/iotbx/map_model_manager.py index a1d8291890..6735e299ae 100644 --- a/iotbx/map_model_manager.py +++ b/iotbx/map_model_manager.py @@ -1012,6 +1012,8 @@ def write_model(self, file_name, model_id = None, model = None, + data_manager = None, + format = None, ): if not model: @@ -1024,10 +1026,12 @@ def write_model(self, self._print ("Need file name to write model") else: # Write out model - - f = open(file_name, 'w') - print(model.model_as_pdb(), file = f) - f.close() + if not data_manager: + from iotbx.data_manager import DataManager + data_manager = DataManager() + data_manager.set_overwrite(True) + file_name = data_manager.write_model_file(model, + file_name, format = format) self._print("Wrote model with %s residues to %s" %( model.get_hierarchy().overall_counts().n_residues, file_name)) @@ -2269,10 +2273,10 @@ def _split_up_map_and_model(self, for mmm in box_info.mmm_list: i += 1 print("Writing files for model and map: %s " %(i), file=self.log) - model_file = "model_%s.pdb" %(i) + model_file = "model_%s.pdb" %(i) # PDB OK map_file = "map_%s.ccp4" %(i) - dm.write_model_file(mmm.model(), model_file) - dm.write_real_map_file(mmm.map_manager(), map_file) + model_file = dm.write_model_file(mmm.model(), model_file) + map_file = dm.write_real_map_file(mmm.map_manager(), map_file) return box_info # Methods for masking maps ( creating masks and applying masks to maps) @@ -4071,7 +4075,7 @@ def find_k_sol_b_sol(self, [0.15,0], [0.15,5], ] - from cctbx.development.create_models_or_maps import generate_model, \ + from cctbx.development.create_models_or_maps import \ generate_map_coefficients target_map_coeffs = self.get_map_manager_by_id( @@ -8117,7 +8121,7 @@ def remove_origin_shift_and_unit_cell_crystal_symmetry(self): Typical use: box_mmm = mmm.extract_all_maps_around_model() box_mmm.remove_origin_shift_and_unit_cell_crystal_symmetry() - data_manager.write_model_file(box_mmm.model(), model_file) + model_file = data_manager.write_model_file(box_mmm.model(), model_file) data_manager.write_real_map_file(box_mmm.map_manager(), map_file) Now model_file and map_file have no origin shift and the model CRYST1 matches the crystal_symmetry and map_file unit_cell_crystal_symmetry of @@ -8753,17 +8757,19 @@ def write_map(self, file_name = None): self._map_manager.write_map(file_name = file_name) def write_model(self, - file_name = None): + file_name = None, data_manager = None, format = None): if not self._model: self._print ("No model to write out") elif not file_name: self._print ("Need file name to write model") else: # Write out model - - f = open(file_name, 'w') - print(self._model.model_as_pdb(), file = f) - f.close() + if not data_manager: + from iotbx.data_manager import DataManager + data_manager = DataManager() + data_manager.set_overwrite(True) + file_name = data_manager.write_model_file(self._model, file_name, + format = format) self._print("Wrote model with %s residues to %s" %( self._model.get_hierarchy().overall_counts().n_residues, file_name)) @@ -9516,7 +9522,6 @@ def set_nearby_empty_values( Set values within radii of xyz_list points to value if not already set ''' - from cctbx.maptbx import grid_indices_around_sites gias = maptbx.grid_indices_around_sites( unit_cell=map_manager.crystal_symmetry().unit_cell(), fft_n_real=map_manager.map_data().all(), @@ -9547,7 +9552,6 @@ def get_split_maps_and_models( masked_value = masked_value, ''' - from iotbx.map_model_manager import map_model_manager as MapModelManager if hasattr(box_info,'tlso_group_info') and box_info.tlso_group_info: # cannot pickle tlso values box_info.tlso_group_info.tlso_list = None diff --git a/iotbx/pdb/__init__.py b/iotbx/pdb/__init__.py index 895cabe4ba..69a7de9ad3 100644 --- a/iotbx/pdb/__init__.py +++ b/iotbx/pdb/__init__.py @@ -568,13 +568,15 @@ def __init__(self, file_names): self.md5_registry = {} self.unique_file_names = [] self.raw_records = [] + self.raw_text_block_list = [] for file_name in file_names: if (file_name in self.file_name_registry): self.file_name_registry[file_name] += 1 else: self.file_name_registry[file_name] = 1 with smart_open.for_reading(file_name=file_name) as f: - r = [s.expandtabs().rstrip() for s in f.read().splitlines()] + text = f.read() + r = [s.expandtabs().rstrip() for s in text.splitlines()] m = hashlib_md5() m.update(to_bytes("\n".join(r), codec='utf8')) m = m.hexdigest() @@ -585,6 +587,7 @@ def __init__(self, file_names): self.md5_registry[m] = [file_name] self.unique_file_names.append(file_name) self.raw_records.extend(r) + self.raw_text_block_list.append(text) def report_non_unique(self, out=None, prefix=""): if (out is None): out = sys.stdout @@ -1353,7 +1356,7 @@ def extract_tls_params(self, hierarchy): chain_ids = chain_ids) def extract_f_model_core_constants(self): - import iotbx.pdb.remark_3_interpretation + remark_3_records = self.extract_remark_iii_records(3) return remark_3_interpretation.extract_f_model_core_constants(remark_3_records) diff --git a/iotbx/pdb/forward_compatible_pdb_cif_conversion.py b/iotbx/pdb/forward_compatible_pdb_cif_conversion.py index 998e6f043b..7725540dd1 100644 --- a/iotbx/pdb/forward_compatible_pdb_cif_conversion.py +++ b/iotbx/pdb/forward_compatible_pdb_cif_conversion.py @@ -35,52 +35,78 @@ C. Get conversion info from any hierarchy (ph): - from iotbx.pdb.forward_compatible_pdb_cif_conversion import forward_compatible_pdb_cif_conversion + from iotbx.pdb.forward_compatible_pdb_cif_conversion \ + import forward_compatible_pdb_cif_conversion conversion_info = forward_compatible_pdb_cif_conversion(hierarchy = ph) -D. Get conversion info from unique chain_ids and residue names ( +D. convert any hierarchy to a forward_compatible one (changes chain.id and + residue names: + from iotbx.pdb.forward_compatible_pdb_cif_conversion \ + import forward_compatible_pdb_cif_conversion + conversion_info = forward_compatible_pdb_cif_conversion(hierarchy = ph) + conversion_info.convert_hierarchy_to_forward_compatible_pdb_representation(ph) + +E. Convert forward compatible pdb back (done in place) + conversion_info.convert_hierarchy_to_full_representation(ph) + +F. TODO: Convert any hierarchy to forward compatible (method of hierarchy): + ph.convert_to_forward_compatible_pdb() # saves conversion info as attribute + # Optionally supply conversion_info + # now ph._conversion_info is set + +E. Get conversion info from unique chain_ids and residue names ( unique_values_dict): - from iotbx.pdb.forward_compatible_pdb_cif_conversion import forward_compatible_pdb_cif_conversion + from iotbx.pdb.forward_compatible_pdb_cif_conversion \ + import forward_compatible_pdb_cif_conversion conversion_info = forward_compatible_pdb_cif_conversion( unique_values_dict = unique_values_dict) -D. Get conversion info as REMARK and RESNAM string +F. Get conversion info as REMARK and RESNAM string - from iotbx.pdb.forward_compatible_pdb_cif_conversion import forward_compatible_pdb_cif_conversion - remark_hetnam_string = forward_compatible_pdb_cif_conversion(ph).conversion_as_remark_hetnam_string() + from iotbx.pdb.forward_compatible_pdb_cif_conversion \ + import forward_compatible_pdb_cif_conversion + remark_hetnam_string = \ + forward_compatible_pdb_cif_conversion(ph).conversion_as_remark_hetnam_string() -E. Convert a forward_compatible_pdb compatible hierarchy to a full hierarchy with - conversion information in conversion_info. This approach can be +E. Convert a forward_compatible_pdb compatible hierarchy to a full hierarchy + with conversion information in conversion_info. This approach can be used to (1) save conversion information from a hierarchy, - (2) write a forward_compatible_pdb file, (3) do something with the forward_compatible_pdb file that loses - the header information, (4) read back the forward_compatible_pdb file that does not have - REMARK records, and (5) restore the original structure in the new - hierarchy. - - from iotbx.pdb.forward_compatible_pdb_cif_conversion import forward_compatible_pdb_cif_conversion - from iotbx.pdb.forward_compatible_pdb_cif_conversion import hierarchy_as_forward_compatible_pdb_string - from iotbx.pdb.forward_compatible_pdb_cif_conversion import pdb_or_mmcif_string_as_hierarchy + (2) write a forward_compatible_pdb file, (3) do something with the + forward_compatible_pdb file that loses + the header information, (4) read back the forward_compatible_pdb file that + does not have REMARK records, and (5) restore the original structure in + the new hierarchy. + + from iotbx.pdb.forward_compatible_pdb_cif_conversion \ + import forward_compatible_pdb_cif_conversion + from iotbx.pdb.forward_compatible_pdb_cif_conversion \ + import hierarchy_as_forward_compatible_pdb_string + from iotbx.pdb.forward_compatible_pdb_cif_conversion \ + import pdb_or_mmcif_string_as_hierarchy # Get conversion information conversion_info = forward_compatible_pdb_cif_conversion(ph) # Get a forward_compatible_pdb string with no remarks - forward_compatible_pdb_string = hierarchy_as_forward_compatible_pdb_string(ph) - forward_compatible_pdb_string_no_remarks = remove_remarks(forward_compatible_pdb_string) + forward_compatible_pdb_string = hierarchy_as_forward_compatible_pdb_string(ph) + forward_compatible_pdb_string_no_remarks = remove_remarks( + forward_compatible_pdb_string) # convert back to hierarchy (this can be a new pdb string obtained # after manipulations of the model but with residue names and chain id # values matching the forward_compatible_pdb_string) - ph = pdb_or_mmcif_string_as_hierarchy(forward_compatible_pdb_string_no_remarks).hierarchy + ph = pdb_or_mmcif_string_as_hierarchy( + forward_compatible_pdb_string_no_remarks).hierarchy # Apply the conversions to obtain a full representation in ph conversion_info.convert_hierarchy_to_full_representation(ph) ''' -def hierarchy_as_forward_compatible_pdb_string(ph, conversion_info = None, *args, **kw): - '''Convert a hierarchy into a forward_compatible_pdb compatible string, with any - conversion information written as REMARK records +def hierarchy_as_forward_compatible_pdb_string(ph, + conversion_info = None, *args, **kw): + '''Convert a hierarchy into a forward_compatible_pdb compatible string, + with any conversion information written as REMARK records parameters: ph: hierarchy object @@ -98,27 +124,31 @@ def hierarchy_as_forward_compatible_pdb_string(ph, conversion_info = None, *args return ph.as_pdb_string(*args, **kw) else: ph_forward_compatible_pdb = ph.deep_copy() - conversion_info.convert_hierarchy_to_forward_compatible_pdb_representation(ph_forward_compatible_pdb) + conversion_info.convert_hierarchy_to_forward_compatible_pdb_representation( + ph_forward_compatible_pdb) remark_hetnam_string = conversion_info.conversion_as_remark_hetnam_string() - forward_compatible_pdb_string = ph_forward_compatible_pdb.as_pdb_string(*args, **kw) + forward_compatible_pdb_string = ph_forward_compatible_pdb.as_pdb_string( + *args, **kw) full_string = remark_hetnam_string + forward_compatible_pdb_string return full_string def pdb_or_mmcif_string_as_hierarchy(pdb_or_mmcif_string, conversion_info = None): - '''Convert an mmcif string or a forward_compatible_pdb compatible string into a - hierarchy object, using any conversion information written as + '''Convert an mmcif string or a forward_compatible_pdb compatible string + into a hierarchy object, using any conversion information written as REMARK records in the forward_compatible_pdb string, or using any supplied conversion information. parameters: - pdb_or_mmcif_string: mmcif string or a forward_compatible_pdb compatible string - conversion_info: optional forward_compatible_pdb_cif_conversion object to apply + pdb_or_mmcif_string: mmcif string or a forward_compatible_pdb compatible + string conversion_info: optional forward_compatible_pdb_cif_conversion + object to apply returns: group_args (hierarchy, pdb_inp, crystal_symmetry, conversion_info) ''' import iotbx.pdb - from iotbx.pdb.forward_compatible_pdb_cif_conversion import forward_compatible_pdb_cif_conversion + from iotbx.pdb.forward_compatible_pdb_cif_conversion \ + import forward_compatible_pdb_cif_conversion inp = iotbx.pdb.input(lines=pdb_or_mmcif_string, source_info=None) remark_hetnam_string = "\n".join(inp.remark_section()) hetnam_string = "\n".join(inp.heterogen_section()) @@ -142,24 +172,43 @@ def pdb_or_mmcif_string_as_hierarchy(pdb_or_mmcif_string, conversion_info = conversion_info) # Determine if this is already in full format - if forward_compatible_pdb_cif_conversion(ph).conversion_required(): # already set + if forward_compatible_pdb_cif_conversion(ph).conversion_required(): + # already set assert not conversion_info.conversion_required(), \ - "Cannot apply forward_compatible_pdb conversions to a hierarchy that is not forward_compatible_pdb" - elif conversion_info.conversion_required(): # convert it + "Cannot apply forward_compatible_pdb conversions to a "+\ + "hierarchy that is not forward_compatible_pdb" + else: conversion_info.convert_hierarchy_to_full_representation(ph) - else: # nothing to convert - pass return result +def get_unique_values_dict(hierarchy_list): + # Get all the unique chain_id and resname values in all hierarchies + + chain_id_list = [] + resname_list = [] + for hierarchy in hierarchy_list: + for model in hierarchy.models(): + for chain in model.chains(): + if not chain.id in chain_id_list: + chain_id_list.append(chain.id) + for residue_group in chain.residue_groups(): + for atom_group in residue_group.atom_groups(): + if not atom_group.resname in resname_list: + resname_list.append(atom_group.resname) + unique_values_dict = { + 'chain_id': chain_id_list, + 'resname': resname_list} + return unique_values_dict + class forward_compatible_pdb_cif_conversion: - ''' Class to generate and save forward_compatible_pdb representation of 5-character - residue names and n-character chain IDs. Used to convert between - forward_compatible_pdb and mmcif formatting. + ''' Class to generate and save forward_compatible_pdb representation + of 5-character residue names and n-character chain IDs. Used to convert + between forward_compatible_pdb and mmcif formatting. NOTE 1: marked as self._is_initialized when values are available - NOTE 2: hierarchy object that has been converted to forward_compatible_pdb compatible - will be marked with the attribute - self._is_forward_compatible_pdb_representation=True + NOTE 2: hierarchy object that has been converted to + forward_compatible_pdb compatible will be marked with the attribute + self._conversion_info, the conversion used. To modify these tables to add another field to check: @@ -167,19 +216,20 @@ class forward_compatible_pdb_cif_conversion: 2. Add new methods like "def _unique_chain_ids_from_hierarchy" 3. Use these new methods in "def _set_up_conversion_table" 4. Add code at "Modify hierarchy here to convert to forward_compatible_pdb" - 5. Add code at "Modify hierarchy here to convert from forward_compatible_pdb" - 6. Add code to regression test at iotbx/regression/tst_hierarchy_forward_compatible_pdb.py + 5. Add at "Modify hierarchy here to convert from forward_compatible_pdb" + 6. Add to regression test at + iotbx/regression/tst_hierarchy_forward_compatible_pdb.py ''' def __init__(self, hierarchy = None, unique_values_dict = None, residue_conversion_as_remark = True, residue_conversion_as_hetnam = True, - end_residue_names_with_tilde_if_possible = True, + end_residue_names_with_tilde_if_possible = False, ): ''' Identify all unique chain_ids and residue names that are not compatible - with forward_compatible_pdb. Generate dictionary relating original names and - compatible names and for going backwards. + with forward_compatible_pdb. Generate dictionary relating original + names and compatible names and for going backwards. parameters: iotbx.pdb.hierarchy object (required unless unique_values_dict is supplied) @@ -196,7 +246,8 @@ def __init__(self, hierarchy = None, ''' - # Fields in hierarchy that are limited in number of characters in forward_compatible_pdb + # Fields in hierarchy that are limited in number of characters + # in forward_compatible_pdb self._keys = ['chain_id', 'resname'] self._max_chars_dict = {'chain_id':2, 'resname':3} self._end_with_tilde_dict = {'chain_id':False, 'resname':True} @@ -244,7 +295,8 @@ def is_initialized(self): def conversion_required(self): - '''Public method to return True if conversion for forward_compatible_pdb is necessary + '''Public method to return True if conversion for forward_compatible_pdb + is necessary parameters: None returns: True if conversion is necessary ''' @@ -265,7 +317,7 @@ def conversion_as_remark_hetnam_string(self): from six.moves import cStringIO as StringIO f = StringIO() print( - "REMARK 987 PDB_V3_CONVERSION CONVERSIONS MADE FOR PDB_V3 COMPATIBILITY", + "REMARK 987 PDB_V3_CONVERSION CONVERSIONS MADE FOR PDB_V3 COMPATIBILITY", file = f) # Set up conversion info that goes in REMARK records @@ -306,12 +358,12 @@ def conversion_as_remark_hetnam_string(self): for full_text, forward_compatible_pdb_text in zip( info.full_representation_list, info.forward_compatible_pdb_representation_list, - ): + ): # any text for 55 chars print("%6s %2s %3s %55s%10s" %( "HETNAM".ljust(6), "".ljust(2), # continuation chars forward_compatible_pdb_text.ljust(3), # 3-char version - "PDB_V3_CONVERSION (FULL NAME IN COLS 71-80)".ljust(55), # any text for 55 chars + "PDB_V3_CONVERSION (FULL NAME IN COLS 71-80)".ljust(55), full_text.ljust(10)), # full version file = f) print(file = f) @@ -320,47 +372,49 @@ def conversion_as_remark_hetnam_string(self): return f.getvalue() - def convert_hierarchy_to_forward_compatible_pdb_representation(self, hierarchy): + def convert_hierarchy_to_forward_compatible_pdb_representation(self, + hierarchy): - '''Public method to convert a hierarchy in place to forward_compatible_pdb compatible - hierarchy using information in self._conversion_table_info_dict + '''Public method to convert a hierarchy in place to + forward_compatible_pdb compatible hierarchy using information + in self._conversion_table_info_dict parameters: hierarchy (modified in place) output: None + Hierarchy is marked with attribute _conversion_info ''' assert self.is_initialized(), "Need to initialize" assert hierarchy is not None, "Need hierarchy for conversion" - if hasattr(hierarchy, '_is_forward_compatible_pdb_representation') and ( - hierarchy._is_forward_compatible_pdb_representation): + if hierarchy.is_forward_compatible_hierarchy(): return # nothing to do because it was already converted - if not self.conversion_required(): - return # nothing to do because no conversion is necessary - - # Modify hierarchy here to convert to forward_compatible_pdb - - for model in hierarchy.models(): - for chain in model.chains(): - new_id = self.get_forward_compatible_pdb_text_from_full_text( - key = 'chain_id', - full_text = chain.id) - if new_id and new_id != chain.id: - chain.id = new_id # Modify chain ID here - - for residue_group in chain.residue_groups(): - for atom_group in residue_group.atom_groups(): - new_resname = self.get_forward_compatible_pdb_text_from_full_text('resname', - atom_group.resname) - if new_resname and (new_resname != atom_group.resname): - atom_group.resname = new_resname # Modify residue name here - - hierarchy._is_forward_compatible_pdb_representation = True + if self.conversion_required(): + + # Modify hierarchy here to convert to forward_compatible_pdb + for model in hierarchy.models(): + for chain in model.chains(): + new_id = self.get_forward_compatible_pdb_text_from_full_text( + key = 'chain_id', + full_text = chain.id) + if new_id and new_id != chain.id: + chain.id = new_id # Modify chain ID here + + for residue_group in chain.residue_groups(): + for atom_group in residue_group.atom_groups(): + new_resname = self.get_forward_compatible_pdb_text_from_full_text( + 'resname', + atom_group.resname) + if new_resname and (new_resname != atom_group.resname): + atom_group.resname = new_resname # Modify residue name here + # Mark it + hierarchy._conversion_info = self def convert_hierarchy_to_full_representation(self, hierarchy): - '''Public method to convert a hierarchy in place from forward_compatible_pdb compatible - hierarchy using information in self._conversion_table_info_dict + '''Public method to convert a hierarchy in place from + forward_compatible_pdb compatible hierarchy back to original + hierarchy using information in self._conversion_table_info_dict parameters: hierarchy (modified in place) output: None @@ -368,32 +422,28 @@ def convert_hierarchy_to_full_representation(self, hierarchy): assert hierarchy is not None, "Need hierarchy for conversion" assert self.is_initialized(), "Need to initialize" - if hasattr(hierarchy, '_is_forward_compatible_pdb_representation') and ( - hierarchy._is_forward_compatible_pdb_representation): - return # nothing to do because it was already converted - if not self.conversion_required(): - return # nothing to do because no conversion is necessary + if self.conversion_required(): + # Modify hierarchy here to convert from forward_compatible_pdb - # Modify hierarchy here to convert from forward_compatible_pdb + for model in hierarchy.models(): + for chain in model.chains(): + new_id = self.get_full_text_from_forward_compatible_pdb_text( + key = 'chain_id', + forward_compatible_pdb_text = chain.id) + if new_id and new_id != chain.id: + chain.id = new_id # Modify chain_id here - for model in hierarchy.models(): - for chain in model.chains(): - new_id = self.get_full_text_from_forward_compatible_pdb_text( - key = 'chain_id', - forward_compatible_pdb_text = chain.id) - if new_id and new_id != chain.id: - chain.id = new_id # Modify chain_id here - - for residue_group in chain.residue_groups(): - for atom_group in residue_group.atom_groups(): - new_resname = self.get_full_text_from_forward_compatible_pdb_text( - key = 'resname', - forward_compatible_pdb_text = atom_group.resname) - if new_resname and (new_resname != atom_group.resname): - atom_group.resname = new_resname # Modify residue name here + for residue_group in chain.residue_groups(): + for atom_group in residue_group.atom_groups(): + new_resname = self.get_full_text_from_forward_compatible_pdb_text( + key = 'resname', + forward_compatible_pdb_text = atom_group.resname) + if new_resname and (new_resname != atom_group.resname): + atom_group.resname = new_resname # Modify residue name here - hierarchy._is_forward_compatible_pdb_representation = False + if hasattr(hierarchy,'_conversion_info'): + delattr(hierarchy,'_conversion_info') def set_conversion_tables_from_remark_hetnam_records( self, remark_hetnam_records, add_to_existing = False): @@ -429,7 +479,8 @@ def set_conversion_tables_from_remark_hetnam_records( for line in remark_hetnam_records: if not line: continue spl = line.split() - if (spl[0] == "REMARK") and (spl[1] == "987") and (spl[2] == "PDB_V3_CONVERSION"): + if (spl[0] == "REMARK") and (spl[1] == "987") and \ + (spl[2] == "PDB_V3_CONVERSION"): if len(spl) != 7: continue key = spl[3].lower()[:-1] # take off ":" if not key in self._remark_keys: continue @@ -447,7 +498,8 @@ def set_conversion_tables_from_remark_hetnam_records( if not full in full_representation_list_dict[key]: full_representation_list_dict[key].append(full) - forward_compatible_pdb_representation_list_dict[key].append(forward_compatible_pdb) + forward_compatible_pdb_representation_list_dict[key].append( + forward_compatible_pdb) # there was something needing conversion self._conversion_required = True @@ -463,7 +515,8 @@ def set_conversion_tables_from_remark_hetnam_records( self._conversion_table_info_dict[key] = group_args( group_args_type = 'conversion tables for %s' %(key), full_representation_list = full_representation_list_dict[key], - forward_compatible_pdb_representation_list = forward_compatible_pdb_representation_list_dict[key]) + forward_compatible_pdb_representation_list = \ + forward_compatible_pdb_representation_list_dict[key]) def _set_up_conversion_table(self, key, hierarchy, unique_values_dict = None): @@ -488,20 +541,24 @@ def _set_up_conversion_table(self, key, hierarchy, unique_values_dict = None): unique_values, max_chars = max_chars) - forward_compatible_pdb_representation_list = self._get_any_forward_compatible_pdb_representation( + forward_compatible_pdb_representation_list = \ + self._get_any_forward_compatible_pdb_representation( ids_needing_conversion, max_chars, exclude_list = allowed_ids, end_with_tilde = end_with_tilde) if ids_needing_conversion: - assert len(ids_needing_conversion) == len(forward_compatible_pdb_representation_list) + assert len(ids_needing_conversion) == len( + forward_compatible_pdb_representation_list) from libtbx import group_args self._conversion_table_info_dict[key] = group_args( group_args_type = 'conversion tables for %s' %(key), full_representation_list = ids_needing_conversion, - forward_compatible_pdb_representation_list = forward_compatible_pdb_representation_list) + forward_compatible_pdb_representation_list = \ + forward_compatible_pdb_representation_list) - if forward_compatible_pdb_representation_list: # there was something needing conversion + if forward_compatible_pdb_representation_list: + # there was something needing conversion self._conversion_required = True def _unique_chain_ids_from_hierarchy(self, hierarchy): @@ -532,10 +589,12 @@ def _unique_resnames_from_hierarchy(self, hierarchy): resnames.append(atom_group.resname) return resnames - def _get_any_forward_compatible_pdb_representation(self, ids_needing_conversion, + def _get_any_forward_compatible_pdb_representation(self, + ids_needing_conversion, max_chars, exclude_list = None, end_with_tilde = None): - '''Private method to try a few ways to generate unique forward_compatible_pdb + '''Private method to try a few ways to generate unique + forward_compatible_pdb representations for a set of strings. Order to try: 1. take first max_chars of each. 2. if end_with_tilde, then generate max_chars-1 of numbers plus tilde, @@ -546,7 +605,8 @@ def _get_any_forward_compatible_pdb_representation(self, ids_needing_conversion, exclude_list: list of strings not to use as output end_with_tilde: try to end strings with a tilde ("~") returns: - forward_compatible_pdb_representation_list: list of converted strings, same order and + forward_compatible_pdb_representation_list: + list of converted strings, same order and length as ids_needing_conversion ''' @@ -554,7 +614,8 @@ def _get_any_forward_compatible_pdb_representation(self, ids_needing_conversion, return [] # ok with nothing in it # Try just taking first n_chars of strings...ok if they are all unique - forward_compatible_pdb_representation_list = self._get_forward_compatible_pdb_representation( + forward_compatible_pdb_representation_list = \ + self._get_forward_compatible_pdb_representation( ids_needing_conversion, max_chars, exclude_list = exclude_list, take_first_n_chars = True) if forward_compatible_pdb_representation_list: @@ -562,7 +623,8 @@ def _get_any_forward_compatible_pdb_representation(self, ids_needing_conversion, # Generate unique strings for all the ids needing conversion, preventing # duplications of existing ids - forward_compatible_pdb_representation_list = self._get_forward_compatible_pdb_representation( + forward_compatible_pdb_representation_list = \ + self._get_forward_compatible_pdb_representation( ids_needing_conversion, max_chars, exclude_list = exclude_list, end_with_tilde = end_with_tilde) if forward_compatible_pdb_representation_list: @@ -570,13 +632,15 @@ def _get_any_forward_compatible_pdb_representation(self, ids_needing_conversion, # Failed to get forward_compatible_pdb representation... from libtbx.utils import Sorry - raise Sorry("Unable to generate forward_compatible_pdb representation of %s" %(key)) + raise Sorry( + "Unable to generate forward_compatible_pdb representation of %s" %(key)) def _get_forward_compatible_pdb_representation(self, ids, max_chars, exclude_list = None, take_first_n_chars = False, - end_with_tilde = False): + end_with_tilde = None): - '''Private method to try and get forward_compatible_pdb representation of ids that fit in + '''Private method to try and get forward_compatible_pdb representation + of ids that fit in max_chars and do not duplicate anything in exclude_list parameters: ids: strings to convert @@ -698,52 +762,97 @@ def _get_conversion_table_info(self, key): else: return self._conversion_table_info_dict[key] - def get_full_text_from_forward_compatible_pdb_text(self, key = None, forward_compatible_pdb_text = None): - '''Public method to return full text from forward_compatible_pdb_text based on - conversion table + def get_full_text_from_forward_compatible_pdb_text(self, key = None, + forward_compatible_pdb_text = None): + '''Public method to return full text from forward_compatible_pdb_text + based on conversion table. Applies to one word. parameters: key: field to convert (e.g., chain_id, resname) - forward_compatible_pdb_text: text to convert from forward_compatible_pdb to full text + forward_compatible_pdb_text: text to convert from + forward_compatible_pdb to full text ''' - assert key is not None assert forward_compatible_pdb_text is not None + if key is None: + full_text = forward_compatible_pdb_text + for key in list(self._conversion_table_info_dict.keys()): + full_text = self.get_full_text_from_forward_compatible_pdb_text( + key = key, forward_compatible_pdb_text = full_text) + return full_text + conversion_table_info = self._get_conversion_table_info(key) if conversion_table_info and ( - forward_compatible_pdb_text in conversion_table_info.forward_compatible_pdb_representation_list): - index = conversion_table_info.forward_compatible_pdb_representation_list.index( - forward_compatible_pdb_text) + forward_compatible_pdb_text in + conversion_table_info.forward_compatible_pdb_representation_list): + index = \ + conversion_table_info.forward_compatible_pdb_representation_list.index( + forward_compatible_pdb_text) full_text = conversion_table_info.full_representation_list[index] else: full_text = forward_compatible_pdb_text return full_text - def get_forward_compatible_pdb_text_from_full_text(self, key = None, full_text = None): - '''Public method to return forward_compatible_pdb text from full text based on - conversion table + def convert_multi_word_text_to_forward_compatible(self, + key = None, text = None): + ''' Public method to take a block of text and convert all the words that + are in the dictionary for key to forward_compatible_pdb. Note: + cannot be reversed. Spacing in lines is not maintained. + Suitable for converting restraint (mmcif) files). + ''' + if key is None: # do all keys + for key in list(self._conversion_table_info_dict.keys()): + text = self.convert_multi_word_text_to_forward_compatible( + key, text = text) + return text + + if not key in list(self._conversion_table_info_dict.keys()): + return text # do nothing + + info = self._conversion_table_info_dict[key] + if info: + for full_text, forward_compatible_pdb_text in zip( + info.full_representation_list, + info.forward_compatible_pdb_representation_list, + ): + text = text.replace(full_text,forward_compatible_pdb_text) + return text + + def get_forward_compatible_pdb_text_from_full_text(self, + key = None, full_text = None, require_allowed = True): + '''Public method to return forward_compatible_pdb text from + full text (full text is original text, just one word) + based on conversion table parameters: key: field to convert (e.g., chain_id, resname) full_text: text to convert to forward_compatible_pdb ''' - assert key is not None assert full_text is not None + if key is None: # run all of them + for key in list(self._conversion_table_info_dict.keys()): + full_text = self.get_forward_compatible_pdb_text_from_full_text( + key, full_text = full_text) + return full_text + conversion_table_info = self._get_conversion_table_info(key) if conversion_table_info and ( full_text in conversion_table_info.full_representation_list): index = conversion_table_info.full_representation_list.index( full_text) - forward_compatible_pdb_text = conversion_table_info.forward_compatible_pdb_representation_list[index] + forward_compatible_pdb_text = \ + conversion_table_info.forward_compatible_pdb_representation_list[index] else: forward_compatible_pdb_text = full_text - # Make sure that the resulting text is allowed in forward_compatible_pdb - assert self._is_allowed(forward_compatible_pdb_text, self._max_chars_dict[key]) + if require_allowed: + # Make sure that the resulting text is allowed in forward_compatible_pdb + assert self._is_allowed( + forward_compatible_pdb_text, self._max_chars_dict[key]) return forward_compatible_pdb_text diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index 5d1273bff4..e33c95d327 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -643,6 +643,178 @@ def as_str(self, level_id_exception=level_id_exception) return out.getvalue() + def is_forward_compatible_hierarchy(self): + """ Determine if this is a forward_compatible hierarchy""" + if hasattr(self,'_conversion_info'): + return True + else: + return False + + def conversion_info(self): + """ Get the conversion info for this forward_compatible hierarchy""" + assert self.is_forward_compatible_hierarchy(),\ + "Only a forward_compatible hierarchy has conversion info" + return self._conversion_info + + def convert_multi_word_text_to_forward_compatible(self, text): + """ Use conversion info to convert words in a text string to + forward-compatible equivalents + :params text: text to convert + :returns modified text + """ + c = self.conversion_info() + return c.convert_multi_word_text_to_forward_compatible(text = text) + + def as_forward_compatible_hierarchy(self, conversion_info = None): + """ Convert a standard hierarchy to a forward_compatible_hierarchy + + :params conversion_info + + :returns pdb_hierarchy with chain ID and residue names converted to + strings compatible with PDB formatting. Returned hierarchy is + a deep_copy and contains the attribute _conversion_info with the + conversion_info used + + Typical use: running a method with cmd_text (text commands) and supplying + a hierarchy (or string from it). Convert the hierarchy and the + cmd_text, run the method, convert the results back: + + # Convert the hierarchy to forward compatible + ph_fc = ph.as_forward_compatible_hierarchy() + + # Convert any commands. Can be done one word at a time also + cmd_text_fc = ph_fc.convert_multi_word_text_to_forward_compatible(cmd_text) + + # Run the method with converted hierarchy and commands + result = do_something(ph = ph_fc, command_text = cmd_text_fc) + + # Convert back any resulting hierarchy + new_ph = result.ph.forward_compatible_hierarchy_as_standard( + conversion_info = ph_fc.conversion_info()) + + # Convert back any words in the results that referred to converted + # items. Keys are chain_id and resname + new_result_items = [] + for result_item,key in zip(results.text_words, results.text_keys): + new_result_item = ph_fc.conversion_info().\ + get_full_text_from_forward_compatible_pdb_text(key = key, + forward_compatible_pdb_text = result_item) + new_result_items.append(new_result_item) + + """ + assert not self.is_forward_compatible_hierarchy(), \ + "Cannot make a hierarchy forward compatible twice" + if not conversion_info: + from iotbx.pdb.forward_compatible_pdb_cif_conversion \ + import forward_compatible_pdb_cif_conversion + conversion_info = forward_compatible_pdb_cif_conversion(hierarchy = self) + ph = self.deep_copy() # do not alter original + conversion_info.convert_hierarchy_to_forward_compatible_pdb_representation( + ph) + return ph + + def forward_compatible_hierarchy_as_standard(self, conversion_info = None): + """ Convert a forward_compatible_hierarchy to a standard one. + Inverse of as_forward_compatible_hierarchy. Restores chain IDs and + residue names using conversion_info object + + :params: conversion_info: optional conversion_info object specifying + conversion to be applied + + :returns pdb_hierarchy with original (standard) chain ID and residue names + + """ + + assert self.is_forward_compatible_hierarchy() or \ + (conversion_info is not None), \ + "Only a forward_compatible_hierarchy or a "+\ + "hierarchy and conversion_info can be converted back to standard" + if not conversion_info: + conversion_info = self.conversion_info() + ph = self.deep_copy() # do not alter original + conversion_info.convert_hierarchy_to_full_representation(ph) + return ph + + def as_forward_compatible_string(self, **kw): + """ Create a forward_compatible PDB string from a hierarchy and + throw away the conversion information. + + One-way conversion useful for creating a file that is in PDB format. + + :params **kw: any params suitable for as_pdb_string() + :returns text string + """ + + from iotbx.pdb.forward_compatible_pdb_cif_conversion \ + import hierarchy_as_forward_compatible_pdb_string + return hierarchy_as_forward_compatible_pdb_string(self, **kw) + + def pdb_or_mmcif_string_info(self, + target_format = None, target_filename = None, + data_manager = None, + overwrite = True, + segid_as_auth_segid = True, write_file = False, + remark_section = None, + **kw): + """ + Method to allow shifting from general writing as pdb to + writing as mmcif, with the change in two places (here and model.py) + Use default of segid_as_auth_segid=True here (different than + as_mmcif_string()) + :param target_format: desired output format, pdb or mmcif + :param target_filename: desired output file name, to be modified to + match the output format + :param data_manager: data_manager to write files + :param overwrite: parameter to set overwrite=True in data_manager if True + :param segid_as_auth_segid: use the segid in hierarchy as the auth_segid + in mmcif output + :param write_file: Write the string to the target file + :param remark_section: if supplied and format is pdb, add this text + :param **kw: any keywords suitable for as_pdb_string() + and as_mmcif_string() + + :returns group_args object with attributes + pdb_string, file_name (the actual file name used) and is_mmcif + """ + + if target_format in ['None',None]: # set the default format here + target_format = 'pdb' + assert target_format in ['pdb','mmcif'] + + if target_format == 'pdb': + if self.fits_in_pdb_format(): + pdb_str = self.as_pdb_string(**kw) + is_mmcif = False + if remark_section: + pdb_str = "%s\n%s" %(remark_section, pdb_str) + else: + pdb_str = self.as_mmcif_string( + segid_as_auth_segid = segid_as_auth_segid, **kw) + is_mmcif = True + else: + pdb_str = self.as_mmcif_string( + segid_as_auth_segid = segid_as_auth_segid, **kw) + is_mmcif = True + if target_filename: + import os + path,ext = os.path.splitext(target_filename) + if is_mmcif: + ext = ".cif" + else: + ext = ".pdb" + target_filename = "%s%s" %(path,ext) + if target_filename and write_file: + if not data_manager: + from iotbx.data_manager import DataManager + data_manager = DataManager() + target_filename = data_manager.write_model_file(pdb_str, target_filename, + overwrite = overwrite) + + return group_args(group_args_type = 'pdb_string and filename', + pdb_string = pdb_str, + file_name = target_filename, + is_mmcif = is_mmcif) + def as_pdb_string(self, crystal_symmetry=None, cryst1_z=None, @@ -654,7 +826,8 @@ def as_pdb_string(self, sigatm=True, anisou=True, siguij=True, - output_break_records=True, # TODO deprecate + output_break_records=True, # TODO deprecate XXX no, this is still needed + force_write = False, cstringio=None, return_cstringio=Auto): """ @@ -668,9 +841,10 @@ def as_pdb_string(self, :param anisou: write ANISOU records for anisotropic atoms :param sigatm: write SIGATM records if applicable :param siguij: write SIGUIJ records if applicable + :param force_write: write even if it does not fit in pdb format :returns: Python str """ - if not self.fits_in_pdb_format(): + if (not self.fits_in_pdb_format()) and (not force_write): return "" if (cstringio is None): cstringio = StringIO() @@ -708,7 +882,8 @@ def as_pdb_string(self, # need in this tranformation. # Currently used exclusively in Tom's code. - def as_pdb_input(self, crystal_symmetry=None): + def as_pdb_input(self, crystal_symmetry=None, + segid_as_auth_segid = True): """ Generate corresponding pdb.input object. """ @@ -719,7 +894,9 @@ def as_pdb_input(self, crystal_symmetry=None): source_info="pdb_hierarchy", lines=flex.split_lines(h_str)) else: - h_str = self.as_mmcif_string(crystal_symmetry=crystal_symmetry) + h_str = self.deep_copy().as_mmcif_string( + segid_as_auth_segid=segid_as_auth_segid, + crystal_symmetry=crystal_symmetry) # deep_copy needed to preserve parents inp = iotbx.pdb.mmcif.cif_input( source_info="pdb_hierarchy", lines=flex.split_lines(h_str)) @@ -1105,6 +1282,7 @@ def get_label_asym_id(self, residue_group): # fill self._lai_lookup for the whole hierarchy number_label_asym_id = 0 label_asym_ids = all_label_asym_ids() + for model in self.models(): for chain in model.chains(): previous = None @@ -1190,7 +1368,9 @@ def as_cif_block(self, occupancy_precision=3, b_iso_precision=5, u_aniso_precision=5, - segid_as_auth_segid=False): + segid_as_auth_segid=False, + output_break_records=False): + if crystal_symmetry is None: crystal_symmetry = crystal.symmetry() cs_cif_block = crystal_symmetry.as_cif_block(format="mmcif") @@ -1229,6 +1409,12 @@ def as_cif_block(self, ] if segid_as_auth_segid: atom_site_header.append('_atom_site.auth_segid',) + if output_break_records: + # Determine if there are any break records here to write out + if not self.contains_break_records(): + output_break_records = False # no point + if output_break_records: # set up _atom_site.auth_break + atom_site_header.append('_atom_site.auth_break',) atom_site_loop = iotbx.cif.model.loop(header=tuple(atom_site_header)) @@ -1276,6 +1462,9 @@ def as_cif_block(self, atom_site_pdbx_PDB_model_num = atom_site_loop['_atom_site.pdbx_PDB_model_num'] if segid_as_auth_segid: atom_site_auth_segid = atom_site_loop['_atom_site.auth_segid'] + if output_break_records: + atom_site_auth_break = atom_site_loop['_atom_site.auth_break'] + atom_site_anisotrop_id = aniso_loop['_atom_site_anisotrop.id'] atom_site_anisotrop_pdbx_auth_atom_id = \ aniso_loop['_atom_site_anisotrop.pdbx_auth_atom_id'] @@ -1313,11 +1502,14 @@ def as_cif_block(self, chain_ids = all_chain_ids() for model in self.models(): model_id = model.id + is_first_in_chain = True if model_id == '': model_id = '1' for chain in model.chains(): auth_asym_id = self.get_auth_asym_id(chain, segid_as_auth_segid = segid_as_auth_segid) for residue_group in chain.residue_groups(): + is_first_after_break = not ( + is_first_in_chain or residue_group.link_to_previous) label_asym_id = self.get_label_asym_id(residue_group) seq_id = self.get_auth_seq_id(residue_group) icode = residue_group.icode @@ -1326,6 +1518,7 @@ def as_cif_block(self, comp_id = atom_group.resname.strip() entity_id = '?' # XXX how do we determine this? for atom in atom_group.atoms(): + group_pdb = "ATOM" if atom.hetero: group_pdb = "HETATM" x, y, z = [coord_fmt_str %i for i in atom.xyz] @@ -1372,6 +1565,8 @@ def as_cif_block(self, atom_site_pdbx_PDB_model_num.append(model_id.strip()) if segid_as_auth_segid: atom_site_auth_segid.append(atom.segid) + if output_break_records: + atom_site_auth_break.append("1" if is_first_after_break else "0") if atom.uij_is_defined(): u11, u22, u33, u12, u13, u23 = [ @@ -1390,6 +1585,9 @@ def as_cif_block(self, atom_site_anisotrop_U12.append(u12) atom_site_anisotrop_U13.append(u13) atom_site_anisotrop_U23.append(u23) + is_first_in_chain = False + is_first_after_break = False + # end of atom loop for key in ('_atom_site.phenix_scat_dispersion_real', '_atom_site.phenix_scat_dispersion_imag'): @@ -1409,16 +1607,72 @@ def as_cif_block(self, # return h_cif_block + def remove_hetero(self): + for model in self.models(): + for chain in model.chains(): + for residue_group in chain.residue_groups(): + for atom_group in residue_group.atom_groups(): + have_het = False + for atom in atom_group.atoms(): + if atom.hetero: + have_het = True + break + if have_het: + residue_group.remove_atom_group(atom_group) + # clean up + need_fixing = True + while need_fixing: + need_fixing = False + for model in self.models(): + if len(list(model.chains())) == 0: + self.remove_model(model) + need_fixing = True + for chain in model.chains(): + if len(list(chain.residue_groups())) == 0: + model.remove_chain(chain) + need_fixing = True + for residue_group in chain.residue_groups(): + if len(list(residue_group.atom_groups())) == 0: + chain.remove_residue_group(residue_group) + need_fixing = True + for atom_group in residue_group.atom_groups(): + if len(list(atom_group.atoms())) == 0: + residue_group.remove_atom_group(atom_group) + need_fixing = True + + def contains_hetero(self): + for model in self.models(): + for chain in model.chains(): + for residue_group in chain.residue_groups(): + for atom_group in residue_group.atom_groups(): + for atom in atom_group.atoms(): + if atom.hetero: + return True + return False + + def contains_break_records(self): + for model in self.models(): + for chain in model.chains(): + is_first_in_chain = True + for rg in chain.residue_groups(): + is_first_after_break = not (is_first_in_chain or rg.link_to_previous) + if is_first_after_break: + return True + is_first_in_chain = False + return False + def as_mmcif_string(self, crystal_symmetry=None, data_block_name=None, - segid_as_auth_segid=False): + segid_as_auth_segid=False, + output_break_records=False): cif_object = iotbx.cif.model.cif() if data_block_name is None: data_block_name = "phenix" cif_object[data_block_name] = self.as_cif_block( crystal_symmetry=crystal_symmetry, - segid_as_auth_segid = segid_as_auth_segid) + segid_as_auth_segid = segid_as_auth_segid, + output_break_records = output_break_records) f = StringIO() cif_object.show(out = f) return f.getvalue() @@ -1427,13 +1681,15 @@ def write_mmcif_file(self, file_name, crystal_symmetry=None, data_block_name=None, - segid_as_auth_segid=False): + segid_as_auth_segid=False, + output_break_records=False): cif_object = iotbx.cif.model.cif() if data_block_name is None: data_block_name = "phenix" cif_object[data_block_name] = self.as_cif_block( crystal_symmetry=crystal_symmetry, - segid_as_auth_segid = segid_as_auth_segid) + segid_as_auth_segid = segid_as_auth_segid, + output_break_records = output_break_records) with open(file_name, "w") as f: print(cif_object, file=f) @@ -1474,6 +1730,90 @@ def get_conformer_indices(self): conformer_indices.set_selected(altloc_indices[altloc], i+p) return conformer_indices + def sort_chains_by_id(self): + chain_ids = self.chain_ids() + if len(chain_ids) < 2: + return # nothing to do + + unique_chain_ids = [] + have_dups = False + for chain_id in chain_ids: + if chain_id in unique_chain_ids: + have_dups = True + else: + unique_chain_ids.append(chain_id) + if not have_dups: + return # nothing to do + + import iotbx.pdb.hierarchy + new_ph = iotbx.pdb.hierarchy.root() + for m0 in self.models(): + detached_chain_dict = {} + m1 = iotbx.pdb.hierarchy.model() + m1.id = m0.id + new_ph.append_model(m1) + for c0 in m0.chains(): + if not c0.id in list(detached_chain_dict.keys()): + detached_chain_dict[c0.id] = [] + detached_chain_dict[c0.id].append(c0.detached_copy()) + for chain_id in unique_chain_ids: + for c in detached_chain_dict[chain_id]: + m1.append_chain(c) + + # Now clear out the original and attach new models to the original hierarchy + for m0 in self.models(): + for c0 in m0.chains(): + m0.remove_chain(chain = c0) + + for m0, m1 in zip(self.models(), new_ph.models()): + for c1 in m1.chains(): + m0.append_chain(c1.detached_copy()) + + # and reset i_seq + atoms = self.atoms() + atoms.reset_i_seq() + + def remove_ter_or_break(self): + import iotbx.pdb.hierarchy + new_ph = iotbx.pdb.hierarchy.root() + # Sort by chain ID first + self.sort_chains_by_id() + for m0 in self.models(): + m1 = iotbx.pdb.hierarchy.model() + m1.id = m0.id + new_ph.append_model(m1) + last_chain = None + for c0 in m0.chains(): + if (not last_chain) or (last_chain and c0.id != last_chain.id) : + new_chain = True + first = True + c1 = c0.detached_copy() + m1.append_chain(c1) + last_chain = c0 + else: + for residue_group in c0.residue_groups(): + c1.append_residue_group(residue_group.detached_copy()) + for m1 in new_ph.models(): + for c1 in m1.chains(): + first = True + for residue_group in c1.residue_groups(): + if not first: + residue_group.link_to_previous = True + first = False + + # Now clear out the original and attach new models to the original hierarchy + for m0 in self.models(): + for c0 in m0.chains(): + m0.remove_chain(chain = c0) + + for m0, m1 in zip(self.models(), new_ph.models()): + for c1 in m1.chains(): + m0.append_chain(c1.detached_copy()) + + # and reset i_seq + atoms = self.atoms() + atoms.reset_i_seq() + def remove_incomplete_main_chain_protein(self, required_atom_names=['CA','N','C','O']): # Remove each residue_group that does not contain CA N C O of protein @@ -2117,7 +2457,7 @@ def de_deuterate(self): """ atoms = self.atoms() # Get exchanged sites - from mmtbx import utils + hd_group_selections = self.exchangeable_hd_selections() hd_site_d_iseqs, hd_site_h_iseqs = [], [] for gsel in hd_group_selections: diff --git a/iotbx/pdb/mmcif.py b/iotbx/pdb/mmcif.py index b857f1c09e..3d78b04086 100644 --- a/iotbx/pdb/mmcif.py +++ b/iotbx/pdb/mmcif.py @@ -44,6 +44,7 @@ def __init__(self, cif_block): label_asym_id = self._wrap_loop_if_needed(cif_block, "_atom_site.label_asym_id") # chain id auth_asym_id = self._wrap_loop_if_needed(cif_block, "_atom_site.auth_asym_id") auth_segid = self._wrap_loop_if_needed(cif_block, "_atom_site.auth_segid") + auth_break = self._wrap_loop_if_needed(cif_block, "_atom_site.auth_break") if label_asym_id is None: label_asym_id = auth_asym_id if auth_asym_id is None: auth_asym_id = label_asym_id comp_id = self._wrap_loop_if_needed(cif_block, "_atom_site.auth_comp_id") @@ -129,6 +130,7 @@ def __init__(self, cif_block): i_atom > 0 and is_aa_or_rna_dna(comp_id[i_atom-1])) ): # insert chain breaks chain = hierarchy.chain(id=current_auth_asym_id) + is_first_in_chain = None model.append_chain(chain) else: assert current_auth_asym_id == last_auth_asym_id @@ -155,6 +157,10 @@ def __init__(self, cif_block): resseq=resseq, icode=current_ins_code) chain.append_residue_group(residue_group) + if is_first_in_chain is None: + is_first_in_chain = True + else: + is_first_in_chain = False atom_groups = OrderedDict() # reset atom_groups cache # atom_group(s) # defined by resname and altloc id @@ -192,6 +198,9 @@ def __init__(self, cif_block): atom.set_segid(auth_segid[i_atom][:4]+(4-len(auth_segid[i_atom]))*" ") else: atom.set_segid(" ") + if auth_break and (not is_first_in_chain) and auth_break[i_atom] == "1": + # insert break before this residue + residue_group.link_to_previous = False if group_PDB is not None and group_PDB[i_atom] == "HETATM": atom.hetero = True if formal_charge is not None: @@ -378,6 +387,8 @@ def file_type(self): return "mmcif" def construct_hierarchy(self, set_atom_i_seq=True, sort_atoms=True): + if self.hierarchy is not None: + return self.hierarchy self.builder = pdb_hierarchy_builder(self.cif_block) self.hierarchy = self.builder.hierarchy if sort_atoms: @@ -499,7 +510,8 @@ def get_program_name(self): return software_name elif software_classification is not None: i = flex.first_index(software_classification, 'refinement') - if i is not None and i >= 0 and software_name is not None and i < len(software_name): + if (i is not None) and (i >= 0) and (software_name is not None) and ( + i < len(software_name)): return software_name[i] def resolution(self): diff --git a/iotbx/pdb/pdb_v3_cif_conversion.py b/iotbx/pdb/pdb_v3_cif_conversion.py index 9238cc304e..998e6f043b 100644 --- a/iotbx/pdb/pdb_v3_cif_conversion.py +++ b/iotbx/pdb/pdb_v3_cif_conversion.py @@ -1,16 +1,16 @@ from __future__ import absolute_import, division, print_function ''' -pdb_v3_cif_conversion.py +forward_compatible_pdb_cif_conversion.py -Methods to convert between a hierarchy object and a pdb_v3 compatible string. +Methods to convert between a hierarchy object and a forward_compatible_pdb compatible string. Rationale: Hierarchy object and mmcif representations can contain chain ID values with n-characters and residue names with 3 or 5 characters. PDB format only allows 2 chars for chain ID and 3 for residue names. -Approach: Convert all non-pdb_v3-compliant chain ID and residue names +Approach: Convert all non-forward_compatible_pdb-compliant chain ID and residue names to suitable number of characters and save the conversion information as a conversion_info object and as RESNAM records (for residue names) and REMARK records (for chain ID) in PDB string representations of @@ -18,104 +18,107 @@ Examples of typical uses: -A. Write a pdb_v3 compatible string with conversion information in REMARK +A. Write a forward_compatible_pdb compatible string with conversion information in REMARK and RESNAM records from any hierarchy (ph): NOTE: any kw and args for as_pdb_string() can be supplied - from iotbx.pdb.pdb_v3_cif_conversion import hierarchy_as_pdb_v3_string - pdb_v3_string = hierarchy_as_pdb_v3_string(ph) + from iotbx.pdb.forward_compatible_pdb_cif_conversion import hierarchy_as_forward_compatible_pdb_string + forward_compatible_pdb_string = hierarchy_as_forward_compatible_pdb_string(ph) -B. Read a pdb_v3 compatible string (pdb_v3_string) with conversion +B. Read a forward_compatible_pdb compatible string (forward_compatible_pdb_string) with conversion information in REMARK/RESNAM records and convert to a hierarchy ( inverse of A). NOTE: same function will read any mmcif string as well. - from iotbx.pdb.pdb_v3_cif_conversion import pdb_or_mmcif_string_as_hierarchy - ph = pdb_or_mmcif_string_as_hierarchy(pdb_v3_string).hierarchy + from iotbx.pdb.forward_compatible_pdb_cif_conversion import pdb_or_mmcif_string_as_hierarchy + ph = pdb_or_mmcif_string_as_hierarchy(forward_compatible_pdb_string).hierarchy C. Get conversion info from any hierarchy (ph): - from iotbx.pdb.pdb_v3_cif_conversion import pdb_v3_cif_conversion - conversion_info = pdb_v3_cif_conversion(hierarchy = ph) + from iotbx.pdb.forward_compatible_pdb_cif_conversion import forward_compatible_pdb_cif_conversion + conversion_info = forward_compatible_pdb_cif_conversion(hierarchy = ph) D. Get conversion info from unique chain_ids and residue names ( unique_values_dict): - from iotbx.pdb.pdb_v3_cif_conversion import pdb_v3_cif_conversion - conversion_info = pdb_v3_cif_conversion( + from iotbx.pdb.forward_compatible_pdb_cif_conversion import forward_compatible_pdb_cif_conversion + conversion_info = forward_compatible_pdb_cif_conversion( unique_values_dict = unique_values_dict) D. Get conversion info as REMARK and RESNAM string - from iotbx.pdb.pdb_v3_cif_conversion import pdb_v3_cif_conversion - remark_hetnam_string = pdb_v3_cif_conversion(ph).conversion_as_remark_hetnam_string() + from iotbx.pdb.forward_compatible_pdb_cif_conversion import forward_compatible_pdb_cif_conversion + remark_hetnam_string = forward_compatible_pdb_cif_conversion(ph).conversion_as_remark_hetnam_string() -E. Convert a pdb_v3 compatible hierarchy to a full hierarchy with +E. Convert a forward_compatible_pdb compatible hierarchy to a full hierarchy with conversion information in conversion_info. This approach can be used to (1) save conversion information from a hierarchy, - (2) write a pdb_v3 file, (3) do something with the pdb_v3 file that loses - the header information, (4) read back the pdb_v3 file that does not have + (2) write a forward_compatible_pdb file, (3) do something with the forward_compatible_pdb file that loses + the header information, (4) read back the forward_compatible_pdb file that does not have REMARK records, and (5) restore the original structure in the new hierarchy. - from iotbx.pdb.pdb_v3_cif_conversion import pdb_v3_cif_conversion - from iotbx.pdb.pdb_v3_cif_conversion import hierarchy_as_pdb_v3_string - from iotbx.pdb.pdb_v3_cif_conversion import pdb_or_mmcif_string_as_hierarchy + from iotbx.pdb.forward_compatible_pdb_cif_conversion import forward_compatible_pdb_cif_conversion + from iotbx.pdb.forward_compatible_pdb_cif_conversion import hierarchy_as_forward_compatible_pdb_string + from iotbx.pdb.forward_compatible_pdb_cif_conversion import pdb_or_mmcif_string_as_hierarchy # Get conversion information - conversion_info = pdb_v3_cif_conversion(ph) + conversion_info = forward_compatible_pdb_cif_conversion(ph) - # Get a pdb_v3 string with no remarks - pdb_v3_string = hierarchy_as_pdb_v3_string(ph) - pdb_v3_string_no_remarks = remove_remarks(pdb_v3_string) + # Get a forward_compatible_pdb string with no remarks + forward_compatible_pdb_string = hierarchy_as_forward_compatible_pdb_string(ph) + forward_compatible_pdb_string_no_remarks = remove_remarks(forward_compatible_pdb_string) # convert back to hierarchy (this can be a new pdb string obtained # after manipulations of the model but with residue names and chain id - # values matching the pdb_v3_string) - ph = pdb_or_mmcif_string_as_hierarchy(pdb_v3_string_no_remarks).hierarchy + # values matching the forward_compatible_pdb_string) + ph = pdb_or_mmcif_string_as_hierarchy(forward_compatible_pdb_string_no_remarks).hierarchy # Apply the conversions to obtain a full representation in ph conversion_info.convert_hierarchy_to_full_representation(ph) ''' -def hierarchy_as_pdb_v3_string(ph, *args, **kw): - '''Convert a hierarchy into a pdb_v3 compatible string, with any +def hierarchy_as_forward_compatible_pdb_string(ph, conversion_info = None, *args, **kw): + '''Convert a hierarchy into a forward_compatible_pdb compatible string, with any conversion information written as REMARK records parameters: ph: hierarchy object + conversion_info: optional conversion_info object specifying conversion args, kw: any args and kw suitable for the hierarchy method ph.as_pdb_string() returns: string ''' - conversion_info = pdb_v3_cif_conversion(hierarchy = ph) + if not conversion_info: + conversion_info = forward_compatible_pdb_cif_conversion(hierarchy = ph) + if (not conversion_info.conversion_required()): return ph.as_pdb_string(*args, **kw) else: - ph_pdb_v3 = ph.deep_copy() - conversion_info.convert_hierarchy_to_pdb_v3_representation(ph_pdb_v3) + ph_forward_compatible_pdb = ph.deep_copy() + conversion_info.convert_hierarchy_to_forward_compatible_pdb_representation(ph_forward_compatible_pdb) remark_hetnam_string = conversion_info.conversion_as_remark_hetnam_string() - pdb_v3_string = ph_pdb_v3.as_pdb_string(*args, **kw) - full_string = remark_hetnam_string + pdb_v3_string + forward_compatible_pdb_string = ph_forward_compatible_pdb.as_pdb_string(*args, **kw) + full_string = remark_hetnam_string + forward_compatible_pdb_string return full_string def pdb_or_mmcif_string_as_hierarchy(pdb_or_mmcif_string, conversion_info = None): - '''Convert an mmcif string or a pdb_v3 compatible string into a + '''Convert an mmcif string or a forward_compatible_pdb compatible string into a hierarchy object, using any conversion information written as - REMARK records in the pdb_v3 string, or using any supplied + REMARK records in the forward_compatible_pdb string, or using any supplied conversion information. parameters: - pdb_or_mmcif_string: mmcif string or a pdb_v3 compatible string - conversion_info: optional pdb_v3_cif_conversion object to apply + pdb_or_mmcif_string: mmcif string or a forward_compatible_pdb compatible string + conversion_info: optional forward_compatible_pdb_cif_conversion object to apply - returns: group_args (hierarchy, crystal_symmetry) + returns: group_args (hierarchy, pdb_inp, crystal_symmetry, conversion_info) ''' import iotbx.pdb - from iotbx.pdb.pdb_v3_cif_conversion import pdb_v3_cif_conversion + from iotbx.pdb.forward_compatible_pdb_cif_conversion import forward_compatible_pdb_cif_conversion inp = iotbx.pdb.input(lines=pdb_or_mmcif_string, source_info=None) remark_hetnam_string = "\n".join(inp.remark_section()) hetnam_string = "\n".join(inp.heterogen_section()) @@ -123,7 +126,7 @@ def pdb_or_mmcif_string_as_hierarchy(pdb_or_mmcif_string, crystal_symmetry = inp.crystal_symmetry() if (not conversion_info): - conversion_info = pdb_v3_cif_conversion() + conversion_info = forward_compatible_pdb_cif_conversion() conversion_info.set_conversion_tables_from_remark_hetnam_records( remark_hetnam_records = remark_hetnam_string.splitlines()) assert conversion_info.is_initialized() @@ -134,36 +137,38 @@ def pdb_or_mmcif_string_as_hierarchy(pdb_or_mmcif_string, result = group_args( group_args_type = 'hierarchy and crystal_symmetry from text string', hierarchy = ph, - crystal_symmetry = crystal_symmetry) + pdb_inp = inp, + crystal_symmetry = crystal_symmetry, + conversion_info = conversion_info) # Determine if this is already in full format - if pdb_v3_cif_conversion(ph).conversion_required(): # already set + if forward_compatible_pdb_cif_conversion(ph).conversion_required(): # already set assert not conversion_info.conversion_required(), \ - "Cannot apply pdb_v3 conversions to a hierarchy that is not pdb_v3" + "Cannot apply forward_compatible_pdb conversions to a hierarchy that is not forward_compatible_pdb" elif conversion_info.conversion_required(): # convert it conversion_info.convert_hierarchy_to_full_representation(ph) else: # nothing to convert pass return result -class pdb_v3_cif_conversion: - ''' Class to generate and save pdb_v3 representation of 5-character +class forward_compatible_pdb_cif_conversion: + ''' Class to generate and save forward_compatible_pdb representation of 5-character residue names and n-character chain IDs. Used to convert between - pdb_v3 and mmcif formatting. + forward_compatible_pdb and mmcif formatting. NOTE 1: marked as self._is_initialized when values are available - NOTE 2: hierarchy object that has been converted to pdb_v3 compatible + NOTE 2: hierarchy object that has been converted to forward_compatible_pdb compatible will be marked with the attribute - self._is_pdb_v3_representation=True + self._is_forward_compatible_pdb_representation=True To modify these tables to add another field to check: 1. Add new field to self._keys and self._max_chars_dict 2. Add new methods like "def _unique_chain_ids_from_hierarchy" 3. Use these new methods in "def _set_up_conversion_table" - 4. Add code at "Modify hierarchy here to convert to pdb_v3" - 5. Add code at "Modify hierarchy here to convert from pdb_v3" - 6. Add code to regression test at iotbx/regression/tst_hierarchy_pdb_v3.py + 4. Add code at "Modify hierarchy here to convert to forward_compatible_pdb" + 5. Add code at "Modify hierarchy here to convert from forward_compatible_pdb" + 6. Add code to regression test at iotbx/regression/tst_hierarchy_forward_compatible_pdb.py ''' def __init__(self, hierarchy = None, @@ -173,7 +178,7 @@ def __init__(self, hierarchy = None, end_residue_names_with_tilde_if_possible = True, ): ''' Identify all unique chain_ids and residue names that are not compatible - with pdb_v3. Generate dictionary relating original names and + with forward_compatible_pdb. Generate dictionary relating original names and compatible names and for going backwards. parameters: iotbx.pdb.hierarchy object (required unless unique_values_dict @@ -191,7 +196,7 @@ def __init__(self, hierarchy = None, ''' - # Fields in hierarchy that are limited in number of characters in pdb_v3 + # Fields in hierarchy that are limited in number of characters in forward_compatible_pdb self._keys = ['chain_id', 'resname'] self._max_chars_dict = {'chain_id':2, 'resname':3} self._end_with_tilde_dict = {'chain_id':False, 'resname':True} @@ -239,7 +244,7 @@ def is_initialized(self): def conversion_required(self): - '''Public method to return True if conversion for pdb_v3 is necessary + '''Public method to return True if conversion for forward_compatible_pdb is necessary parameters: None returns: True if conversion is necessary ''' @@ -267,15 +272,15 @@ def conversion_as_remark_hetnam_string(self): for key in self._remark_keys: info = self._conversion_table_info_dict[key] if info: - for full_text, pdb_v3_text in zip( + for full_text, forward_compatible_pdb_text in zip( info.full_representation_list, - info.pdb_v3_representation_list, + info.forward_compatible_pdb_representation_list, ): print( "REMARK 987 PDB_V3_CONVERSION %s: %s PDB_V3_TEXT: %s" %( key.upper(), full_text, - pdb_v3_text), + forward_compatible_pdb_text), file = f) print(file = f) @@ -298,14 +303,14 @@ def conversion_as_remark_hetnam_string(self): for key in self._hetnam_keys: info = self._conversion_table_info_dict[key] if info: - for full_text, pdb_v3_text in zip( + for full_text, forward_compatible_pdb_text in zip( info.full_representation_list, - info.pdb_v3_representation_list, + info.forward_compatible_pdb_representation_list, ): print("%6s %2s %3s %55s%10s" %( "HETNAM".ljust(6), "".ljust(2), # continuation chars - pdb_v3_text.ljust(3), # 3-char version + forward_compatible_pdb_text.ljust(3), # 3-char version "PDB_V3_CONVERSION (FULL NAME IN COLS 71-80)".ljust(55), # any text for 55 chars full_text.ljust(10)), # full version file = f) @@ -315,9 +320,9 @@ def conversion_as_remark_hetnam_string(self): return f.getvalue() - def convert_hierarchy_to_pdb_v3_representation(self, hierarchy): + def convert_hierarchy_to_forward_compatible_pdb_representation(self, hierarchy): - '''Public method to convert a hierarchy in place to pdb_v3 compatible + '''Public method to convert a hierarchy in place to forward_compatible_pdb compatible hierarchy using information in self._conversion_table_info_dict parameters: hierarchy (modified in place) output: None @@ -327,18 +332,18 @@ def convert_hierarchy_to_pdb_v3_representation(self, hierarchy): assert self.is_initialized(), "Need to initialize" assert hierarchy is not None, "Need hierarchy for conversion" - if hasattr(hierarchy, '_is_pdb_v3_representation') and ( - hierarchy._is_pdb_v3_representation): + if hasattr(hierarchy, '_is_forward_compatible_pdb_representation') and ( + hierarchy._is_forward_compatible_pdb_representation): return # nothing to do because it was already converted if not self.conversion_required(): return # nothing to do because no conversion is necessary - # Modify hierarchy here to convert to pdb_v3 + # Modify hierarchy here to convert to forward_compatible_pdb for model in hierarchy.models(): for chain in model.chains(): - new_id = self.get_pdb_v3_text_from_full_text( + new_id = self.get_forward_compatible_pdb_text_from_full_text( key = 'chain_id', full_text = chain.id) if new_id and new_id != chain.id: @@ -346,15 +351,15 @@ def convert_hierarchy_to_pdb_v3_representation(self, hierarchy): for residue_group in chain.residue_groups(): for atom_group in residue_group.atom_groups(): - new_resname = self.get_pdb_v3_text_from_full_text('resname', + new_resname = self.get_forward_compatible_pdb_text_from_full_text('resname', atom_group.resname) if new_resname and (new_resname != atom_group.resname): atom_group.resname = new_resname # Modify residue name here - hierarchy._is_pdb_v3_representation = True + hierarchy._is_forward_compatible_pdb_representation = True def convert_hierarchy_to_full_representation(self, hierarchy): - '''Public method to convert a hierarchy in place from pdb_v3 compatible + '''Public method to convert a hierarchy in place from forward_compatible_pdb compatible hierarchy using information in self._conversion_table_info_dict parameters: hierarchy (modified in place) output: None @@ -363,32 +368,32 @@ def convert_hierarchy_to_full_representation(self, hierarchy): assert hierarchy is not None, "Need hierarchy for conversion" assert self.is_initialized(), "Need to initialize" - if hasattr(hierarchy, '_is_pdb_v3_representation') and ( - hierarchy._is_pdb_v3_representation): + if hasattr(hierarchy, '_is_forward_compatible_pdb_representation') and ( + hierarchy._is_forward_compatible_pdb_representation): return # nothing to do because it was already converted if not self.conversion_required(): return # nothing to do because no conversion is necessary - # Modify hierarchy here to convert from pdb_v3 + # Modify hierarchy here to convert from forward_compatible_pdb for model in hierarchy.models(): for chain in model.chains(): - new_id = self.get_full_text_from_pdb_v3_text( + new_id = self.get_full_text_from_forward_compatible_pdb_text( key = 'chain_id', - pdb_v3_text = chain.id) + forward_compatible_pdb_text = chain.id) if new_id and new_id != chain.id: chain.id = new_id # Modify chain_id here for residue_group in chain.residue_groups(): for atom_group in residue_group.atom_groups(): - new_resname = self.get_full_text_from_pdb_v3_text( + new_resname = self.get_full_text_from_forward_compatible_pdb_text( key = 'resname', - pdb_v3_text = atom_group.resname) + forward_compatible_pdb_text = atom_group.resname) if new_resname and (new_resname != atom_group.resname): atom_group.resname = new_resname # Modify residue name here - hierarchy._is_pdb_v3_representation = False + hierarchy._is_forward_compatible_pdb_representation = False def set_conversion_tables_from_remark_hetnam_records( self, remark_hetnam_records, add_to_existing = False): @@ -414,11 +419,11 @@ def set_conversion_tables_from_remark_hetnam_records( pass # keep existing dicts else: # usual...initialize full_representation_list_dict = {} - pdb_v3_representation_list_dict = {} + forward_compatible_pdb_representation_list_dict = {} for key in self._keys: full_representation_list_dict[key] = [] - pdb_v3_representation_list_dict[key] = [] + forward_compatible_pdb_representation_list_dict[key] = [] self._is_initialized = True for line in remark_hetnam_records: @@ -429,20 +434,20 @@ def set_conversion_tables_from_remark_hetnam_records( key = spl[3].lower()[:-1] # take off ":" if not key in self._remark_keys: continue full = spl[4] - pdb_v3 = spl[6] + forward_compatible_pdb = spl[6] elif self._residue_conversion_as_hetnam and (spl[0] == "HETNAM"): key = "resname" if not key in self._hetnam_keys: continue - pdb_v3 = line[11:14].strip() + forward_compatible_pdb = line[11:14].strip() full = line[69:80].strip() - if not pdb_v3: continue + if not forward_compatible_pdb: continue if not full: continue else: continue if not full in full_representation_list_dict[key]: full_representation_list_dict[key].append(full) - pdb_v3_representation_list_dict[key].append(pdb_v3) + forward_compatible_pdb_representation_list_dict[key].append(forward_compatible_pdb) # there was something needing conversion self._conversion_required = True @@ -458,7 +463,7 @@ def set_conversion_tables_from_remark_hetnam_records( self._conversion_table_info_dict[key] = group_args( group_args_type = 'conversion tables for %s' %(key), full_representation_list = full_representation_list_dict[key], - pdb_v3_representation_list = pdb_v3_representation_list_dict[key]) + forward_compatible_pdb_representation_list = forward_compatible_pdb_representation_list_dict[key]) def _set_up_conversion_table(self, key, hierarchy, unique_values_dict = None): @@ -483,20 +488,20 @@ def _set_up_conversion_table(self, key, hierarchy, unique_values_dict = None): unique_values, max_chars = max_chars) - pdb_v3_representation_list = self._get_any_pdb_v3_representation( + forward_compatible_pdb_representation_list = self._get_any_forward_compatible_pdb_representation( ids_needing_conversion, max_chars, exclude_list = allowed_ids, end_with_tilde = end_with_tilde) if ids_needing_conversion: - assert len(ids_needing_conversion) == len(pdb_v3_representation_list) + assert len(ids_needing_conversion) == len(forward_compatible_pdb_representation_list) from libtbx import group_args self._conversion_table_info_dict[key] = group_args( group_args_type = 'conversion tables for %s' %(key), full_representation_list = ids_needing_conversion, - pdb_v3_representation_list = pdb_v3_representation_list) + forward_compatible_pdb_representation_list = forward_compatible_pdb_representation_list) - if pdb_v3_representation_list: # there was something needing conversion + if forward_compatible_pdb_representation_list: # there was something needing conversion self._conversion_required = True def _unique_chain_ids_from_hierarchy(self, hierarchy): @@ -527,10 +532,10 @@ def _unique_resnames_from_hierarchy(self, hierarchy): resnames.append(atom_group.resname) return resnames - def _get_any_pdb_v3_representation(self, ids_needing_conversion, + def _get_any_forward_compatible_pdb_representation(self, ids_needing_conversion, max_chars, exclude_list = None, end_with_tilde = None): - '''Private method to try a few ways to generate unique pdb_v3 + '''Private method to try a few ways to generate unique forward_compatible_pdb representations for a set of strings. Order to try: 1. take first max_chars of each. 2. if end_with_tilde, then generate max_chars-1 of numbers plus tilde, @@ -541,7 +546,7 @@ def _get_any_pdb_v3_representation(self, ids_needing_conversion, exclude_list: list of strings not to use as output end_with_tilde: try to end strings with a tilde ("~") returns: - pdb_v3_representation_list: list of converted strings, same order and + forward_compatible_pdb_representation_list: list of converted strings, same order and length as ids_needing_conversion ''' @@ -549,29 +554,29 @@ def _get_any_pdb_v3_representation(self, ids_needing_conversion, return [] # ok with nothing in it # Try just taking first n_chars of strings...ok if they are all unique - pdb_v3_representation_list = self._get_pdb_v3_representation( + forward_compatible_pdb_representation_list = self._get_forward_compatible_pdb_representation( ids_needing_conversion, max_chars, exclude_list = exclude_list, take_first_n_chars = True) - if pdb_v3_representation_list: - return pdb_v3_representation_list + if forward_compatible_pdb_representation_list: + return forward_compatible_pdb_representation_list # Generate unique strings for all the ids needing conversion, preventing # duplications of existing ids - pdb_v3_representation_list = self._get_pdb_v3_representation( + forward_compatible_pdb_representation_list = self._get_forward_compatible_pdb_representation( ids_needing_conversion, max_chars, exclude_list = exclude_list, end_with_tilde = end_with_tilde) - if pdb_v3_representation_list: - return pdb_v3_representation_list + if forward_compatible_pdb_representation_list: + return forward_compatible_pdb_representation_list - # Failed to get pdb_v3 representation... + # Failed to get forward_compatible_pdb representation... from libtbx.utils import Sorry - raise Sorry("Unable to generate pdb_v3 representation of %s" %(key)) + raise Sorry("Unable to generate forward_compatible_pdb representation of %s" %(key)) - def _get_pdb_v3_representation(self, ids, max_chars, + def _get_forward_compatible_pdb_representation(self, ids, max_chars, exclude_list = None, take_first_n_chars = False, end_with_tilde = False): - '''Private method to try and get pdb_v3 representation of ids that fit in + '''Private method to try and get forward_compatible_pdb representation of ids that fit in max_chars and do not duplicate anything in exclude_list parameters: ids: strings to convert @@ -585,20 +590,20 @@ def _get_pdb_v3_representation(self, ids, max_chars, otherwise, None ''' - pdb_v3_representation_list = [] + forward_compatible_pdb_representation_list = [] for id in ids: if take_first_n_chars: # Just take the first n_chars new_id = id[:max_chars] - if new_id in exclude_list + pdb_v3_representation_list: + if new_id in exclude_list + forward_compatible_pdb_representation_list: return None # cannot do it this way else: # generate a new id new_id = self._get_new_unique_id(id, max_chars, - exclude_list + pdb_v3_representation_list, + exclude_list + forward_compatible_pdb_representation_list, end_with_tilde = end_with_tilde) if not new_id: return None # could not do this - pdb_v3_representation_list.append(new_id) - return pdb_v3_representation_list + forward_compatible_pdb_representation_list.append(new_id) + return forward_compatible_pdb_representation_list def _get_new_unique_id(self, id, max_chars, exclude_list, end_with_tilde): @@ -660,7 +665,7 @@ def _get_new_id(self, n_chars, exclude_list, end_with_tilde = None, def _choose_allowed_ids(self, unique_values, max_chars): ''' Private method to separate unique_values into those that are and - are not compatible with pdb_v3 (i.e., have max_chars or fewer) + are not compatible with forward_compatible_pdb (i.e., have max_chars or fewer) ''' allowed = [] not_allowed = [] @@ -673,7 +678,7 @@ def _choose_allowed_ids(self, unique_values, max_chars): def _is_allowed(self, u, max_chars): ''' Private method to identify whether the string u is or is not - compatible with pdb_v3 (i.e., has max_chars or fewer) + compatible with forward_compatible_pdb (i.e., has max_chars or fewer) ''' if len(u) <= max_chars: return True @@ -688,40 +693,42 @@ def _get_conversion_table_info(self, key): if not key in self._keys: return None + elif (not self._conversion_required): + return None else: return self._conversion_table_info_dict[key] - def get_full_text_from_pdb_v3_text(self, key = None, pdb_v3_text = None): - '''Public method to return full text from pdb_v3_text based on + def get_full_text_from_forward_compatible_pdb_text(self, key = None, forward_compatible_pdb_text = None): + '''Public method to return full text from forward_compatible_pdb_text based on conversion table parameters: key: field to convert (e.g., chain_id, resname) - pdb_v3_text: text to convert from pdb_v3 to full text + forward_compatible_pdb_text: text to convert from forward_compatible_pdb to full text ''' assert key is not None - assert pdb_v3_text is not None + assert forward_compatible_pdb_text is not None conversion_table_info = self._get_conversion_table_info(key) if conversion_table_info and ( - pdb_v3_text in conversion_table_info.pdb_v3_representation_list): - index = conversion_table_info.pdb_v3_representation_list.index( - pdb_v3_text) + forward_compatible_pdb_text in conversion_table_info.forward_compatible_pdb_representation_list): + index = conversion_table_info.forward_compatible_pdb_representation_list.index( + forward_compatible_pdb_text) full_text = conversion_table_info.full_representation_list[index] else: - full_text = pdb_v3_text + full_text = forward_compatible_pdb_text return full_text - def get_pdb_v3_text_from_full_text(self, key = None, full_text = None): - '''Public method to return pdb_v3 text from full text based on + def get_forward_compatible_pdb_text_from_full_text(self, key = None, full_text = None): + '''Public method to return forward_compatible_pdb text from full text based on conversion table parameters: key: field to convert (e.g., chain_id, resname) - full_text: text to convert to pdb_v3 + full_text: text to convert to forward_compatible_pdb ''' assert key is not None @@ -732,11 +739,11 @@ def get_pdb_v3_text_from_full_text(self, key = None, full_text = None): full_text in conversion_table_info.full_representation_list): index = conversion_table_info.full_representation_list.index( full_text) - pdb_v3_text = conversion_table_info.pdb_v3_representation_list[index] + forward_compatible_pdb_text = conversion_table_info.forward_compatible_pdb_representation_list[index] else: - pdb_v3_text = full_text + forward_compatible_pdb_text = full_text - # Make sure that the resulting text is allowed in pdb_v3 - assert self._is_allowed(pdb_v3_text, self._max_chars_dict[key]) + # Make sure that the resulting text is allowed in forward_compatible_pdb + assert self._is_allowed(forward_compatible_pdb_text, self._max_chars_dict[key]) - return pdb_v3_text + return forward_compatible_pdb_text diff --git a/iotbx/pdb/secondary_structure.py b/iotbx/pdb/secondary_structure.py index 59386f3ea4..99ea08a6ac 100644 --- a/iotbx/pdb/secondary_structure.py +++ b/iotbx/pdb/secondary_structure.py @@ -48,7 +48,7 @@ # from libtbx.utils import Sorry -import libtbx.phil + from libtbx import adopt_init_args import sys from iotbx.pdb.hybrid_36 import hy36encode, hy36decode @@ -358,8 +358,11 @@ class structure_base(object): def as_pdb_str(self): return None + def as_pdb_or_mmcif_str(self): + return None + def __str__(self): - return self.as_pdb_str() + return self.as_pdb_or_mmcif_str() @staticmethod def convert_resseq(resseq): @@ -516,7 +519,7 @@ def count_h_bonds(self,hierarchy=None, from mmtbx.secondary_structure.find_ss_from_ca import \ find_secondary_structure fss=find_secondary_structure(hierarchy=ph, - user_annotation_text=self.as_pdb_str(), + user_annotation_text=self.as_pdb_or_mmcif_str(), force_secondary_structure_input=True, combine_annotations=False, ss_by_chain=ss_by_chain, @@ -595,6 +598,7 @@ def overlaps_with(self,other=None,hierarchy=None): return False + class annotation(structure_base): def __init__(self, helices=None, sheets=None): assert (not None in [helices, sheets]) @@ -1194,6 +1198,30 @@ def as_cif_loops(self): loops.append(struct_sheet_hbond_loop) return loops + def as_mmcif_str(self, data_block_name=None): + cif_object = iotbx.cif.model.cif() + if data_block_name is None: + data_block_name = "phenix" + cif_object[data_block_name] = self.as_cif_block() + from six.moves import cStringIO as StringIO + f = StringIO() + cif_object.show(out = f) + return f.getvalue() + + def as_cif_block(self): + cif_block = iotbx.cif.model.block() + ss_cif_loops = self.as_cif_loops() + for loop in ss_cif_loops: + cif_block.add_loop(loop) + return cif_block + + def fits_in_pdb_format(self): + for helix in self.helices : + if (not helix.fits_in_pdb_format()): return False + for sheet in self.sheets : + if (not sheet.fits_in_pdb_format()): return False + return True + def as_pdb_str(self): records = [] for helix in self.helices : @@ -1202,6 +1230,13 @@ def as_pdb_str(self): records.append(sheet.as_pdb_str()) return "\n".join(records) + def as_pdb_or_mmcif_str(self, target_format = 'pdb'): + # Return str in target format if possible, otherwise in mmcif + if target_format == 'pdb' and self.fits_in_pdb_format(): + return self.as_pdb_str() + else: + return self.as_mmcif_str() + def as_restraint_groups(self, log=sys.stdout, prefix_scope="", add_segid=None): phil_strs = [] @@ -1744,7 +1779,7 @@ def is_same_as(self,other=None): def sort_strings(h): sorted=[] for x in h: - sorted.append(x.as_pdb_str(set_id_zero=True)) + sorted.append(x.as_pdb_str(set_id_zero=True, force_format = True)) sorted.sort() return sorted @@ -2072,7 +2107,30 @@ def as_cif_dict(self): result['pdbx_PDB_helix_length'] = self.length return result - def as_pdb_str(self, set_id_zero=False): + def as_pdb_or_mmcif_str(self, target_format = 'pdb'): + # Return str in target format if possible, otherwise in mmcif + if target_format == 'pdb' and self.fits_in_pdb_format(): + return self.as_pdb_str() + else: + return self.as_mmcif_str() + + def fits_in_pdb_format(self): + if len(self.start_resname.strip()) > 3: return False + if len(self.end_resname.strip()) > 3: return False + if len(self.start_chain_id.strip()) > 2: return False + if len(self.end_chain_id.strip()) > 2: return False + return True + + def as_mmcif_str(self): + ann = annotation(helices = [self], sheets = []) + text = ann.as_mmcif_str() + return text + + def as_pdb_str(self, set_id_zero=False, force_format = False): + if (not force_format) and (not self.fits_in_pdb_format()): + raise AssertionError( + "Helix does not fit in PDB format. "+ + "Please fix code to use as_pdb_or_mmcif_str instead of as_pdb_str") def h_class_to_pdb_int(h_class): h_class_int = self.helix_class_to_int(h_class) if h_class_int == 0: @@ -2766,7 +2824,30 @@ def get_n_defined_hbonds(self): return len(self.hbond_list) return 0 - def as_pdb_str(self, strand_id=None, set_id_zero=False): + def as_pdb_or_mmcif_str(self, target_format = 'pdb'): + # Return str in target format if possible, otherwise in mmcif + if target_format == 'pdb' and self.fits_in_pdb_format(): + return self.as_pdb_str() + else: + return self.as_mmcif_str() + + def fits_in_pdb_format(self): + for strand in self.strands: + if len(strand.start_resname.strip()) > 3: return False + if len(strand.end_resname.strip()) > 3: return False + if len(strand.start_chain_id.strip()) > 2: return False + if len(strand.end_chain_id.strip()) > 2: return False + return True + + def as_mmcif_str(self): + ann = annotation(helices = [], sheets = [self]) + text = ann.as_mmcif_str() + return text + + def as_pdb_str(self, strand_id=None, set_id_zero=False, force_format = False): + if (not force_format) and (not self.fits_in_pdb_format()): + raise AssertionError("Sheet does not fit in PDB format"+ + "Please fix code to use as_pdb_or_mmcif_str instead of as_pdb_str") assert len(self.strands) == len(self.registrations) lines = [] for strand, reg in zip(self.strands, self.registrations): diff --git a/iotbx/pdb/tst_hierarchy.py b/iotbx/pdb/tst_hierarchy.py index f87d26b3e7..6ea1aa1784 100644 --- a/iotbx/pdb/tst_hierarchy.py +++ b/iotbx/pdb/tst_hierarchy.py @@ -5706,43 +5706,6 @@ def exercise_residue_pickling(): assert not show_diff(l.root().as_pdb_string(), eps) rp = l -def exercise_attribute_pickling(): - pdb_inp = pdb.input(source_info=None, lines="""\ -MODEL 1 -ATOM 1 N MET A 1 6.215 22.789 24.067 1.00 0.00 N -ATOM 2 CA MET A 1 6.963 22.789 22.822 1.00 0.00 C -BREAK -HETATM 3 C MET A 2 7.478 21.387 22.491 1.00 0.00 C -ATOM 4 O MET A 2 8.406 20.895 23.132 1.00 0.00 O -ENDMDL -MODEL 3 -HETATM 9 2H3 MPR B 5 16.388 0.289 6.613 1.00 0.08 -SIGATM 9 2H3 MPR B 5 0.155 0.175 0.155 0.00 0.05 -ANISOU 9 2H3 MPR B 5 848 848 848 0 0 0 -SIGUIJ 9 2H3 MPR B 5 510 510 510 0 0 0 -TER -ATOM 10 N CYSCH 6 14.270 2.464 3.364 1.00 0.07 -SIGATM 10 N CYSCH 6 0.012 0.012 0.011 0.00 0.00 -ANISOU 10 N CYSCH 6 788 626 677 -344 621 -232 -SIGUIJ 10 N CYSCH 6 3 13 4 11 6 13 -TER -ENDMDL -""") - hierarchy = pdb_inp.construct_hierarchy() - s = pickle.dumps(hierarchy, 1) - - hierarchy.as_mmcif_string() - expected_attributes = ['_lai_lookup', '_label_seq_id_dict'] - for attribute in hierarchy.__dict__.keys(): - assert attribute in expected_attributes, attribute - s = pickle.dumps(hierarchy, 1) - - setattr(hierarchy, 'not_a_valid_attribute', None) - try: - s = pickle.dumps(hierarchy, 1) - except AssertionError as a: - assert 'not_a_valid_attribute' in str(a) - def exercise_hierarchy_input(): pdb_obj = pdb.hierarchy.input(pdb_string=pdb_2izq_220) i_atoms = pdb_obj.input.atoms() @@ -7225,6 +7188,129 @@ def exercise_occupancy_counts(): assert (approx_equal(oc.greater_than_1_fraction, 2*100/30, eps=eps)) assert (approx_equal(oc.alt_conf_frac, 100/3, eps=eps)) +def exercise_remove_ter_or_break(): + pdb_inp_lines = flex.split_lines("""\ +ATOM 1 CA ASP A 1 47.975 -63.194 59.946 1.00 33.86 C +ATOM 5 CA VAL A 2 44.978 -63.576 62.233 1.00 29.81 C +TER +ATOM 8 N GLN B 3 44.585 -65.878 62.864 1.00 25.93 N +ATOM 9 CA GLN B 3 44.166 -67.262 62.686 1.00 24.46 C +ATOM 10 C GLN B 3 42.730 -67.505 63.153 1.00 23.33 C +ATOM 11 O GLN B 3 42.389 -67.234 64.302 1.00 20.10 O +BREAK +ATOM 12 N MET B 4 41.894 -68.026 62.256 1.00 24.27 N +ATOM 13 CA MET B 4 40.497 -68.318 62.576 1.00 22.89 C +ATOM 14 C MET B 4 40.326 -69.824 62.795 1.00 21.48 C +ATOM 15 O MET B 4 40.633 -70.625 61.911 1.00 23.73 O +TER +ATOM 12 N MET B 5 41.894 -68.026 62.256 1.00 24.27 N +ATOM 13 CA MET B 5 40.497 -68.318 62.576 1.00 22.89 C +ATOM 14 C MET B 5 40.326 -69.824 62.795 1.00 21.48 C +ATOM 15 O MET B 5 40.633 -70.625 61.911 1.00 23.73 O +""") + h = pdb.input(source_info=None, lines=pdb_inp_lines).construct_hierarchy() + assert h.as_pdb_string().split().count("TER")==3 + assert h.as_pdb_string().split().count("BREAK")==1 + h.remove_ter_or_break() + assert h.as_pdb_string().split().count("TER")==2 + assert h.as_pdb_string().split().count("BREAK")==0 + +def exercise_forward_compatibility(): + pdb_inp_lines = flex.split_lines("""\ +ATOM 1 CA ASP A 1 47.975 -63.194 59.946 1.00 33.86 C +ATOM 5 CA VAL A 2 44.978 -63.576 62.233 1.00 29.81 C +ATOM 12 N MET B 4 41.894 -68.026 62.256 1.00 24.27 N +ATOM 13 CA MET B 4 40.497 -68.318 62.576 1.00 22.89 C +ATOM 14 C MET B 4 40.326 -69.824 62.795 1.00 21.48 C +ATOM 15 O MET B 4 40.633 -70.625 61.911 1.00 23.73 O +""") + h = pdb.input(source_info=None, lines=pdb_inp_lines).construct_hierarchy() + from libtbx import easy_pickle + easy_pickle.dump('test.pkl',h) + new_h = easy_pickle.load('test.pkl') + assert new_h.as_mmcif_string() == h.as_mmcif_string() + + assert h.as_pdb_string().split().count("ATOM")==6 + assert h.apply_atom_selection("resname MET").overall_counts().n_residues == 1 + assert h.apply_atom_selection("resname METXL").overall_counts().n_residues == 0 + assert h.apply_atom_selection("chain A").overall_counts().n_residues == 2 + assert h.apply_atom_selection("chain AXZLONG").overall_counts().n_residues == 0 + assert h.fits_in_pdb_format() + assert not h.is_forward_compatible_hierarchy() + + # Make pdb incompatible + for model in h.models(): + for chain in model.chains(): + chain.id = "%sXZLONG" %(chain.id) + for rg in chain.residue_groups(): + for ag in rg.atom_groups(): + ag.resname = "%sXL" %(ag.resname) + assert h.as_pdb_string().split().count("ATOM")==0 + assert h.apply_atom_selection("resname MET").overall_counts().n_residues == 0 + assert h.apply_atom_selection("resname METXL").overall_counts().n_residues == 1 + assert h.apply_atom_selection("chain A").overall_counts().n_residues == 0 + assert h.apply_atom_selection("chain AXZLONG").overall_counts().n_residues == 2 + assert not h.fits_in_pdb_format() + assert not h.is_forward_compatible_hierarchy() + + easy_pickle.dump('test.pkl',h) + new_h = easy_pickle.load('test.pkl') + assert new_h.as_mmcif_string() == h.as_mmcif_string() + + # Convert to forward_compatible PDB + ph_fc = h.as_forward_compatible_hierarchy() + + assert ph_fc.as_pdb_string().split().count("ATOM")==6 + assert ph_fc.apply_atom_selection("resname MET").overall_counts().n_residues == 1 + assert ph_fc.apply_atom_selection("resname METXL").overall_counts().n_residues == 0 + assert ph_fc.apply_atom_selection("chain AX").overall_counts().n_residues == 2 + assert ph_fc.apply_atom_selection("chain AXZLONG").overall_counts().n_residues == 0 + assert ph_fc.fits_in_pdb_format() + assert ph_fc.is_forward_compatible_hierarchy() + + # Convert some text from original to matching forward compatible + text = "Text with AXZLONG and METXL" + text_fc = ph_fc.convert_multi_word_text_to_forward_compatible(text) + assert text_fc == "Text with AX and MET" + + try: + easy_pickle.dump('test.pkl',ph_fc) + assert 0, "Forward compatible should not be pickleable" + except Exception as e: + pass # expected + + # Convert the hierarchy back + h_copy = ph_fc.forward_compatible_hierarchy_as_standard() + assert h_copy.is_similar_hierarchy(h) + assert h_copy.as_pdb_string() == h.as_pdb_string() + assert not h.is_forward_compatible_hierarchy() + easy_pickle.dump('test.pkl',h_copy) + new_h_copy= easy_pickle.load('test.pkl') + assert new_h_copy.as_mmcif_string() == h_copy.as_mmcif_string() + +def exercise_contains_hetero(): + pdb_inp_lines = flex.split_lines("""\ +ATOM 1 CA ASP A 1 47.975 -63.194 59.946 1.00 33.86 C +ATOM 5 CA VAL A 2 44.978 -63.576 62.233 1.00 29.81 C +HETATM 8 N GLN B 3 44.585 -65.878 62.864 1.00 25.93 N +HETATM 9 CA GLN B 3 44.166 -67.262 62.686 1.00 24.46 C +HETATM 10 C GLN B 3 42.730 -67.505 63.153 1.00 23.33 C +HETATM 11 O GLN B 3 42.389 -67.234 64.302 1.00 20.10 O +ATOM 12 N MET B 4 41.894 -68.026 62.256 1.00 24.27 N +ATOM 13 CA MET B 4 40.497 -68.318 62.576 1.00 22.89 C +ATOM 14 C MET B 4 40.326 -69.824 62.795 1.00 21.48 C +ATOM 15 O MET B 4 40.633 -70.625 61.911 1.00 23.73 O +""") + h = pdb.input(source_info=None, lines=pdb_inp_lines).construct_hierarchy() + assert h.as_pdb_string().split().count("HETATM")==4 + assert h.as_pdb_string().split().count("ATOM")==6 + assert h.contains_hetero() + h.remove_hetero() + assert h.as_pdb_string().split().count("HETATM")==0 + assert h.as_pdb_string().split().count("ATOM")==6 + assert not h.contains_hetero() + + def exercise_fits_in_pdb_format(): pdb_inp_lines = flex.split_lines("""\ ATOM 1 CA ASP A 1 47.975 -63.194 59.946 1.00 33.86 C @@ -7319,7 +7405,6 @@ def exercise(args): exercise_root_altloc_indices() exercise_root_pickling() exercise_residue_pickling() - exercise_attribute_pickling() exercise_hierarchy_input() exercise_other() exercise_equality_and_hashing() @@ -7331,8 +7416,12 @@ def exercise(args): exercise_is_ca_only() exercise_occupancy_counts() exercise_fits_in_pdb_format() + exercise_remove_ter_or_break() + exercise_contains_hetero() + exercise_forward_compatibility() if (not forever): break print(format_cpu_times()) if (__name__ == "__main__"): exercise(sys.argv[1:]) + print("OK") diff --git a/iotbx/pdb/tst_utils.py b/iotbx/pdb/tst_utils.py index f12fb3c078..37a04c0dfe 100644 --- a/iotbx/pdb/tst_utils.py +++ b/iotbx/pdb/tst_utils.py @@ -1,12 +1,47 @@ from __future__ import absolute_import, division, print_function import iotbx.pdb.utils +pdb_str_to_be_cif=""" +CRYST1 40.339 36.116 46.266 90.00 90.00 90.00 P 1 +ATOM 1 CA ASP AXYB2 34.633 18.762 20.254 1.00 22.59 C +ATOM 2 CA LYS AXYB3 36.047 17.704 23.610 1.00 19.79 C +ATOM 3 CA ILE AXYB4 35.551 19.482 26.886 1.00 19.33 C +ATOM 4 CA AHIS AXYB5 38.649 21.223 28.218 0.50 19.79 C +ATOM 5 CA BHIS AXYB6 38.583 21.270 28.209 0.50 20.43 C +ATOM 6 CA GLY A 138 38.261 15.285 27.690 1.00 6.80 C +ATOM 7 CA ALA A 139 34.607 14.241 27.428 1.00 4.76 C +ATOM 8 CA ALEU A 140 33.091 14.490 23.937 0.50 5.08 C +ATOM 9 CA BLEU A 140 33.072 14.565 23.972 0.50 5.41 C +ATOM 10 CA ASN A 141 30.271 17.061 23.474 1.00 5.65 C +""" + +as_pdb = pdb_str_to_be_cif +# Convert pdb_str_hybrid_residues to mmcif: +from libtbx.test_utils import convert_pdb_to_cif_for_pdb_str +convert_pdb_to_cif_for_pdb_str(locals(), chain_addition="ZXLONG") +as_cif = pdb_str_to_be_cif # now it is cif + def exercise_all_chain_ids(): ids = iotbx.pdb.utils.all_chain_ids() assert len(ids)==3906 assert len(set(ids))==3906 +def exercise_get_pdb_info(): + from iotbx.pdb.utils import get_pdb_info + pdb_info_from_pdb = get_pdb_info(as_pdb) + pdb_info_from_cif = get_pdb_info(as_cif) + assert not pdb_info_from_pdb.hierarchy.is_similar_hierarchy( + pdb_info_from_cif.hierarchy) + for model in pdb_info_from_cif.hierarchy.models(): + for chain in model.chains(): + chain.id = chain.id.replace("ZXLONG","") # make it short again + assert pdb_info_from_pdb.hierarchy.is_similar_hierarchy( + pdb_info_from_cif.hierarchy) + assert pdb_info_from_pdb.crystal_symmetry.is_similar_symmetry( + pdb_info_from_cif.crystal_symmetry) + def run(): + exercise_get_pdb_info() exercise_all_chain_ids() print("OK") diff --git a/iotbx/pdb/utils.py b/iotbx/pdb/utils.py index f058814513..0513adca40 100644 --- a/iotbx/pdb/utils.py +++ b/iotbx/pdb/utils.py @@ -2,9 +2,10 @@ import string from itertools import product from six.moves import range +import sys class generate_n_char_string: - r""" Iterator to generate strings of length n_chars, using upper-case, + """ Iterator to generate strings of length n_chars, using upper-case, lower-case and numbers as desired. Allows specialty sets of characters as well @@ -42,7 +43,7 @@ def __init__(self, n_chars = 1, all_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" all_chars_lc = all_chars.lower() all_numbers = '0123456789' - special_characters = r"""[]_,.;:"&<>()/\{}'`~!@#$%*|+-""" + special_characters = """[]_,.;:"&<>()\/\{}'`~!@#$%*|+-""" self._tilde = """~""" self._all_everything = "" @@ -129,6 +130,529 @@ def all_label_asym_ids(maximum_length=4): rc += ["".join(p) for p in char_upper] return rc +def get_input_model_file_name_from_params(params): + if not params: + return "" + + input_scopes = [None, 'input_files','map_model','input'] + input_file_types = ['pdb_in','model','input_model','fixed_model', + 'moving_model','fixed_pdb','moving_pdb','search_model'] + file_name = "" + for s in input_scopes: + for x in input_file_types: + if file_name: break + if s is None: + file_name = getattr(params,x,None) + elif hasattr(params,s): + ss = getattr(params,s) + file_name = getattr(ss,x,None) + if type(file_name) in [type([1,2,3]),type((1,2,3))]: + if file_name: + file_name = file_name[0] + else: + file_name = '' + return file_name + +def target_output_format_in_params(params): + for x in ['output_files','output']: + if params and hasattr(params,x) and \ + hasattr(getattr(params,x),'target_output_format'): + target_output_format = getattr(getattr(params,x),'target_output_format') + if target_output_format in [None,'','None']: + target_output_format = None + return target_output_format + else: + return None + +def get_target_output_format_from_file_name(file_name, + default = None): + if file_name: + import os + path, ext = os.path.splitext(file_name) + if ext == '.pdb': + target_output_format = 'pdb' + elif ext == '.cif': + target_output_format = 'mmcif' + else: + target_output_format = default + else: + target_output_format = default + return target_output_format + +def move_down_scope_to_input_files(params, levels = 3): + target_scopes = ['input_files','output','output_files','map_model',] + if levels < 0: + return None + for t in target_scopes: + if hasattr(params, t): + return params + for x in dir(params): + if x.startswith("_"): continue + new_p = move_down_scope_to_input_files(getattr(params, x), + levels = levels - 1) + if new_p: + return new_p + return None + +def set_target_output_format_in_params(params, + file_name = None, default = 'pdb', target_output_format = None, + out = sys.stdout, quiet = True): + params = move_down_scope_to_input_files(params) + # Do we have it set already: + target_output_format = target_output_format_in_params(params) + if not target_output_format: + if not file_name: + file_name = get_input_model_file_name_from_params(params) + target_output_format = get_target_output_format_from_file_name( + file_name, default = default) + + # set value in params.output_files.target_output_format + if hasattr(params,'output_files') and \ + hasattr(params.output_files,'target_output_format'): + params.output_files.target_output_format = target_output_format + elif hasattr(params,'output') and \ + hasattr(params.output,'target_output_format'): + params.output.target_output_format = target_output_format + + # print result + if not quiet: + print("Target output format will be: %s" %(target_output_format), + file = out) + + # Return value + return target_output_format + +def catenate_segment_onto_chain(model_chain, s2, gap = 1, + keep_numbers = False, insertion_chain = None): + ''' catenate residues from s2 onto model_chain''' + from iotbx.pdb import resseq_encode + if not model_chain: + return + if not insertion_chain: + s2_as_ph = s2.get_hierarchy() + if not s2_as_ph.overall_counts().n_residues > 0: + return + insertion_chain = s2.get_hierarchy().models()[0].chains()[0] + new_segid = model_chain.residue_groups( + )[0].atom_groups()[0].atoms()[0].segid + highest_resseq = None + if len(model_chain.residue_groups()) > 0: + highest_resseq = model_chain.residue_groups()[0].resseq_as_int() + for rg in model_chain.residue_groups(): + rg_resseq = rg.resseq_as_int() + highest_resseq=max(highest_resseq,rg_resseq) + resseq_as_int = highest_resseq + (gap - 1) + for rg in insertion_chain.residue_groups(): + resseq_as_int += 1 + rg_copy = rg.detached_copy() + if (not keep_numbers): + rg_copy.resseq = resseq_encode(resseq_as_int) + model_chain.append_residue_group( + residue_group = rg_copy) + rg_copy.link_to_previous = True # Required + for ag in rg_copy.atom_groups(): + for atom in ag.atoms(): + awl = atom.fetch_labels() + atom.segid = new_segid + +def add_hierarchies(ph_list, create_new_chain_ids_if_necessary = True): + new_ph_list = [] + for ph in ph_list: + if ph: + new_ph_list.append(ph) + if not new_ph_list: + return None + ph = ph_list[0] + for i in range(1, len(ph_list)): + ph = add_hierarchy(ph, ph_list[i], create_new_chain_ids_if_necessary = + create_new_chain_ids_if_necessary) + return ph + + +def add_hierarchy(s1_ph, s2_ph, create_new_chain_ids_if_necessary = True): + ''' Add chains from hierarchy s2_ph to existing hierarchy s1_ph''' + if not s1_ph: + return s2_ph + s1_ph = s1_ph.deep_copy() + if not s2_ph: + return s1_ph + existing_chain_ids = s1_ph.chain_ids() + for model_mm_2 in s2_ph.models()[:1]: + for chain in model_mm_2.chains(): + if chain.id in existing_chain_ids: # duplicate chains in add_model + if not create_new_chain_ids_if_necessary: + # append to existing chain + existing_chain = get_chain(s1_ph, chain_id = chain.id) + catenate_segment_onto_chain(existing_chain, None, gap = 1, + keep_numbers = True, insertion_chain= chain.detached_copy()) + continue + else: + chain.id = get_new_chain_id(existing_chain_ids) + new_chain = chain.detached_copy() + existing_chain_ids.append(chain.id) + for model_mm in s1_ph.models()[:1]: + model_mm.append_chain(new_chain) + return s1_ph + +def get_chain(s1_ph, chain_id = None): + for model in s1_ph.models(): + for chain in model.chains(): + if chain.id == chain_id: + return chain + +def lines_are_really_text(lines): + if lines and type(lines) in (type('abc'), type(b'abc')): + return True + else: + return False + +def get_lines(text = None, file_name = None, lines = None): + import os + if lines and lines_are_really_text(lines): + text = lines + elif lines: + text = "\n".join(lines) + elif file_name and os.path.isfile(file_name): + text = open(file_name).read() + if not text: + text = "" + # Python 3 read fix + # ======================================================================= + if sys.version_info.major == 3 and type(text) == type(b'abc'): + text = text.decode("utf-8") + # ======================================================================= + from cctbx.array_family import flex + return flex.split_lines(text) + +def check_for_missing_elements(atoms, file_name = None): + elements = atoms.extract_element().strip() + if (not elements.all_ne("")): + n_missing = elements.count("") + missing_list = [] + for atom in list(atoms): + if not atom.element.strip(): + missing_list.append(atom.format_atom_record()) + + raise AssertionError( + "Uninterpretable elements for %d atoms%s. \n" %(n_missing, + "" if not file_name else " in '%s'" %(file_name))+ + "Up to 10 listed below: \n%s" % ("\n".join(missing_list[:10]))) + +def get_pdb_info(text = None, file_name = None, lines = None, + check_pseudo = False, return_pdb_hierarchy = False, + return_group_args = False, + allow_incorrect_spacing = False): + ''' Get a pdb_input object from pdb or mmcif file, construct a + hierarchy, check the hierarchy for missing elements and fill them + in if from pdb. Return group_args object with + hierarchy, pdb_input, and crystal_symmetry. + + If text has no atoms, returns empty hierarchy (Note: iotbx.pdb.input + returns an empty hierarchy in this case if supplied with PDB input + and raises an exception if supplied with mmCIF input without atoms). + + This method is preferred over get_pdb_input and get_pdb_hierarchy + as a method for robust reading of pdb/mmcif files because it + generates the hierarchy only once. If you run get_pdb_input and then + construct the hierarchy it is generated twice. + ''' + return get_pdb_input(text = text, file_name = file_name, + lines = lines, check_pseudo = check_pseudo, + allow_incorrect_spacing = allow_incorrect_spacing, + return_group_args = True) + +def get_pdb_hierarchy(text=None, file_name = None, + lines = None, check_pseudo = None, + allow_incorrect_spacing = False): + ''' Get pdb_input object and construct hierarchy. Normally use instead + info = get_pdb_info and then take info.hierarchy so that you have + the pdb_input object and crystal_symmetry available as well + ''' + return get_pdb_input(text = text, file_name = file_name, lines = lines, + check_pseudo = check_pseudo, return_pdb_hierarchy = True, + allow_incorrect_spacing = allow_incorrect_spacing) + + +def get_pdb_input(text = None, file_name = None, lines = None, + check_pseudo = False, return_pdb_hierarchy = False, + return_group_args = False, + allow_incorrect_spacing = False): + + ''' Get a pdb_input object from pdb or mmcif file, construct a + hierarchy, check the hierarchy for missing elements and fill them + in if from pdb. Return hierarchy, pdb_input, or + group_args object with hierarchy, pdb_input, and crystal_symmetry. + + Normally use instead the info = get_pdb_info method and then + you have hierarchy, pdb_input and crystal_symmetry all available + + ''' + lines = get_lines(text = text, file_name = file_name, lines = lines) + + # Get input object as pdb_inp + import iotbx.pdb + pdb_inp = iotbx.pdb.input(source_info=None,lines=lines) + + # Guess elements if PDB is source input and elements are missing. + # This is can only be done with PDB files + # because mmcif files lose the positional information + # in atom names, so CA cannot be distinguished from Ca (calcium) without + # element information in an mmCIF file. + + if type_of_pdb_input(pdb_inp) == 'pdb': # Guess elements if missing for PDB + ph = try_to_get_hierarchy(pdb_inp) + atoms = ph.atoms() + guess_chemical_elements(atoms, check_pseudo = check_pseudo, + allow_incorrect_spacing = allow_incorrect_spacing) + check_for_missing_elements(ph.atoms()) + else: + # Make sure we have an element for each atom + # try to construct and save empty ph if fails + ph = try_to_get_hierarchy(pdb_inp) + check_for_missing_elements(ph.atoms()) + + # Return what is requested + if return_group_args: + from libtbx import group_args + return group_args(group_args_type = 'hierarchy and pdb_input', + hierarchy = ph, + pdb_inp = pdb_inp, + crystal_symmetry = pdb_inp.crystal_symmetry()) + + elif return_pdb_hierarchy: + return ph + else: + return pdb_inp + +def guess_chemical_elements(atoms, check_pseudo = False, + allow_incorrect_spacing = None): + # Standard set of chemical elements based on atom names (and leading spaces) + for at in atoms: + at.name = at.name.upper() + atoms.set_chemical_element_simple_if_necessary() + + # Check to see if all have an element now + elements = atoms.extract_element().strip() + if elements.all_ne(""): # all done + return + + # Check for incorrect spacings (atom name has space before it but should + # not or opposite) + if allow_incorrect_spacing: + check_for_incorrect_spacings(atoms) + + # Check for pseudo-atoms (ZU ZC etc that represent groups of atoms) + if check_pseudo: + check_for_pseudo_atoms(atoms) + +def check_for_incorrect_spacings(atoms): + elements = atoms.extract_element().strip() + sel = (elements == "") + atoms_sel = atoms.select(sel) + for at in atoms_sel: + if at.name.startswith(" "): + at.name = at.name[1:] + else: + at.name = " "+at.name[:3] + atoms.set_chemical_element_simple_if_necessary() + +def check_for_pseudo_atoms(atoms): + # Check for special case where PDB input contains pseudo-atoms ZC ZU etc + + # Do we already have all the elements + elements = atoms.extract_element().strip() + if elements.all_ne(""): # all done + return + + # Are there any pseudo-atoms + atom_names = atoms.extract_name().strip() + all_text = "".join(list(atom_names)) + if all_text.find("Z") < 0: # no pseudo-atoms + return + + # contains some pseudo-atoms ZC ZU etc. Get their elements if necessary + for atom in atoms: + if atom.element.replace(" ","") == '': + # Missing element not fixed by set_chemical_element_simple_if_necessary + # take first non-Z, non-blank character + for c in atom.name.replace("Z","").replace(" ",""): + if c.isalpha(): + atom.element=c + break + +def type_of_pdb_input(pdb_inp): + format_type = None + if not pdb_inp: + return format_type + else: + s = str(type(pdb_inp)) + if s.find("cif") > 0: + format_type = "mmcif" + elif s.find("pdb") > 0: + format_type = "pdb" + return format_type + +def try_to_get_hierarchy(pdb_inp): + try: + return pdb_inp.construct_hierarchy() + except Exception as e: # nothing there + if str(e).find("something is not present") > -1: # was empty hierarchy + # NOTE this text is in modules/cctbx_project/iotbx/pdb/mmcif.py + # If it changes, change it here too. + from iotbx.pdb import hierarchy + ph = hierarchy.root() + return ph + else: # Stop and ask developers to check code + ph_text = "\n".join(lines) + text = """The above hierarchy could not be read. If it is just empty, + please ask developers to check that the + text "something is not present" is used in + modules/cctbx_project/iotbx/pdb/mmcif.py as part of the assertion that + atoms are present. Modify this text to match the assertion if + necessary""" + raise Sorry(ph_text+"\n"+text+"\n"+str(e)) +def add_model(s1, s2, create_new_chain_ids_if_necessary = True): + ''' add chains from s2 to existing s1''' + if not s1: + s2.reset_after_changing_hierarchy() + return s2 + s1.add_crystal_symmetry_if_necessary() + s1 = s1.deep_copy() + if not s2: + s1.reset_after_changing_hierarchy() + return s1 + s1_ph = s1.get_hierarchy() # working hierarchy + existing_chain_ids = [] + from mmtbx.secondary_structure.find_ss_from_ca import get_new_chain_id + for model_mm1 in s1_ph.models()[:1]: + for chain in model_mm1.chains(): + if not chain.id.strip(): + chain.id = get_new_chain_id(existing_chain_ids) + existing_chain_ids = s1_ph.chain_ids() + for model_mm_2 in s2.get_hierarchy().models()[:1]: + for chain in model_mm_2.chains(): + if not chain.id.strip(): + chain.id = get_new_chain_id(existing_chain_ids) + + if chain.id in existing_chain_ids: # duplicate chains in add_model + if not create_new_chain_ids_if_necessary: + # append to existing chain + from iotbx.pdb.utils import get_chain + from iotbx.pdb.utils import catenate_segment_onto_chain + existing_chain = get_chain(s1_ph, chain_id = chain.id) + catenate_segment_onto_chain(existing_chain, None, gap = 1, + keep_numbers = True, insertion_chain= chain.detached_copy()) + continue + else: + chain.id = get_new_chain_id(existing_chain_ids) + new_chain = chain.detached_copy() + existing_chain_ids.append(chain.id) + for model_mm in s1_ph.models()[:1]: + model_mm.append_chain(new_chain) + s1.reset_after_changing_hierarchy() + if hasattr(s1,'info') and s1.info().get('numbering_dict') and \ + hasattr(s2,'info') and s2.info().get('numbering_dict'): + s1.info().numbering_dict.add_from_other(s2.info().numbering_dict) # XXX fixed... never should have worked before + return s1 + +def catenate_segments(s1, s2, gap = 1, + keep_numbers = False): + ''' + catenate two models and renumber starting with first residue of s1 + if gap is set, start s2 gap residue numbers higher than the end of s1 + if keep_numbers is set, just keep all the residue numbers + ''' + s1 = s1.deep_copy() + s1 = s1.apply_selection_string("not (name OXT)") # get rid of these + s1_ph = s1.get_hierarchy() # working hierarchy + for model_mm in s1_ph.models()[:1]: + for model_chain in model_mm.chains()[:1]: + from iotbx.pdb.utils import catenate_segment_onto_chain + catenate_segment_onto_chain( + model_chain, + s2, + gap = gap, + keep_numbers = keep_numbers) + s1.reset_after_changing_hierarchy() + return s1 +def catenate_segment_onto_chain(model_chain, s2, gap = 1, + keep_numbers = False, insertion_chain = None): + ''' catenate residues from s2 onto model_chain''' + from iotbx.pdb import resseq_encode + if not model_chain: + return + if not insertion_chain: + s2_as_ph = s2.get_hierarchy() + if not s2_as_ph.overall_counts().n_residues > 0: + return + insertion_chain = s2.get_hierarchy().models()[0].chains()[0] + new_segid = model_chain.residue_groups( + )[0].atom_groups()[0].atoms()[0].segid + highest_resseq = None + if len(model_chain.residue_groups()) > 0: + highest_resseq = model_chain.residue_groups()[0].resseq_as_int() + for rg in model_chain.residue_groups(): + rg_resseq = rg.resseq_as_int() + highest_resseq=max(highest_resseq,rg_resseq) + resseq_as_int = highest_resseq + (gap - 1) + for rg in insertion_chain.residue_groups(): + resseq_as_int += 1 + rg_copy = rg.detached_copy() + if (not keep_numbers): + rg_copy.resseq = resseq_encode(resseq_as_int) + model_chain.append_residue_group( + residue_group = rg_copy) + rg_copy.link_to_previous = True # Required + for ag in rg_copy.atom_groups(): + for atom in ag.atoms(): + awl = atom.fetch_labels() + atom.segid = new_segid + +def simple_combine(model_list, + create_new_chain_ids_if_necessary = True): + ''' Method to combine the chains in a set of models to create a new + model with all the chains. + param: model_list: list of model objects + param: create_new_chain_ids_if_necessary: If True (default), if a + model has a duplicate chain ID, create a new one and rename it + returns: first model in model_list with all chains from all models. + NOTE: first model in model_list is modified by this method. Make + a deep_copy before hand if you want to keep it. + ''' + + model = None + for m in model_list: + if not model: + model = m + else: + model = add_model(model, m, + create_new_chain_ids_if_necessary = create_new_chain_ids_if_necessary) + return model + +def get_cif_or_pdb_file_if_present(file_name): + ''' Identify whether a file with the name file_name or with + alternate extensions replacing pdb/cif is present. + If file_name is present, return file_name. + If not, and alternative is present, return alternative file name + Otherwise return empty string + ''' + + import os + if file_name and os.path.isfile(file_name): # if it is present, take it + return file_name + # Otherwise, look for pdb or cif versions of this file + p,e = os.path.splitext(file_name) + e_pdb = e.replace("cif","pdb") + e_cif = e.replace("pdb","cif") + pdb_file = "%s%s" %(p,e_pdb) + cif_file = "%s%s" %(p,e_cif) + if os.path.isfile(pdb_file): + return pdb_file + elif os.path.isfile(cif_file): + return cif_file + else: + return "" # return empty string so os.path.isfile(return_value) works + if __name__ == '__main__': import time l=0 diff --git a/iotbx/regression/data/non_zero_origin_model.cif b/iotbx/regression/data/non_zero_origin_model.cif new file mode 100644 index 0000000000..3decedad64 --- /dev/null +++ b/iotbx/regression/data/non_zero_origin_model.cif @@ -0,0 +1,141 @@ +data_default +_cell.length_a 149.407 +_cell.length_b 144.615 +_cell.length_c 147.488 +_cell.angle_alpha 90.000 +_cell.angle_beta 90.000 +_cell.angle_gamma 90.000 +_cell.volume 3186698.485 +_space_group.crystal_system triclinic +_space_group.IT_number 1 +_space_group.name_H-M_alt 'P 1' +_space_group.name_Hall ' P 1' +_symmetry.space_group_name_H-M 'P 1' +_symmetry.space_group_name_Hall ' P 1' +_symmetry.Int_Tables_number 1 +loop_ + _space_group_symop.id + _space_group_symop.operation_xyz + 1 x,y,z + +loop_ + _struct_asym.id + A + +loop_ + _chem_comp.id + ALA + ARG + GLN + ILE + LEU + MET + TYR + +loop_ + _atom_site.group_PDB + _atom_site.id + _atom_site.label_atom_id + _atom_site.label_alt_id + _atom_site.label_comp_id + _atom_site.auth_asym_id + _atom_site.auth_seq_id + _atom_site.pdbx_PDB_ins_code + _atom_site.Cartn_x + _atom_site.Cartn_y + _atom_site.Cartn_z + _atom_site.occupancy + _atom_site.B_iso_or_equiv + _atom_site.type_symbol + _atom_site.pdbx_formal_charge + _atom_site.label_asym_id + _atom_site.label_entity_id + _atom_site.label_seq_id + _atom_site.pdbx_PDB_model_num + ATOM 1 N . LEU B 219 ? 89.17900 82.87800 82.08600 1.000 30.00000 N ? A ? 1 1 + ATOM 2 CA . LEU B 219 ? 87.73200 83.02800 81.94200 1.000 30.00000 C ? A ? 1 1 + ATOM 3 C . LEU B 219 ? 87.07400 83.47900 83.24000 1.000 30.00000 C ? A ? 1 1 + ATOM 4 O . LEU B 219 ? 86.12500 84.26500 83.21300 1.000 30.00000 O ? A ? 1 1 + ATOM 5 CB . LEU B 219 ? 87.10700 81.72100 81.44400 1.000 30.00000 C ? A ? 1 1 + ATOM 6 CG . LEU B 219 ? 85.59700 81.75200 81.15400 1.000 30.00000 C ? A ? 1 1 + ATOM 7 CD1 . LEU B 219 ? 85.27000 81.08500 79.82200 1.000 30.00000 C ? A ? 1 1 + ATOM 8 CD2 . LEU B 219 ? 84.79500 81.11600 82.28400 1.000 30.00000 C ? A ? 1 1 + ATOM 9 N . ARG B 220 ? 87.58100 82.98000 84.36600 1.000 30.00000 N ? A ? 2 1 + ATOM 10 CA . ARG B 220 ? 87.08400 83.36100 85.68200 1.000 30.00000 C ? A ? 2 1 + ATOM 11 C . ARG B 220 ? 87.30600 84.83900 85.92900 1.000 30.00000 C ? A ? 2 1 + ATOM 12 O . ARG B 220 ? 86.41800 85.51000 86.47200 1.000 30.00000 O ? A ? 2 1 + ATOM 13 CB . ARG B 220 ? 87.76800 82.54400 86.78500 1.000 30.00000 C ? A ? 2 1 + ATOM 14 CG . ARG B 220 ? 87.36400 81.07900 86.82700 1.000 30.00000 C ? A ? 2 1 + ATOM 15 CD . ARG B 220 ? 86.02400 80.87900 87.52000 1.000 30.00000 C ? A ? 2 1 + ATOM 16 NE . ARG B 220 ? 85.64800 79.46500 87.59100 1.000 30.00000 N ? A ? 2 1 + ATOM 17 CZ . ARG B 220 ? 86.14900 78.56700 88.44500 1.000 30.00000 C ? A ? 2 1 + ATOM 18 NH1 . ARG B 220 ? 87.08000 78.90100 89.34200 1.000 30.00000 N ? A ? 2 1 + ATOM 19 NH2 . ARG B 220 ? 85.71500 77.30800 88.40000 1.000 30.00000 N ? A ? 2 1 + ATOM 20 N . LEU B 221 ? 88.49500 85.31400 85.54700 1.000 30.00000 N ? A ? 3 1 + ATOM 21 CA . LEU B 221 ? 88.88200 86.71000 85.73400 1.000 30.00000 C ? A ? 3 1 + ATOM 22 C . LEU B 221 ? 87.89500 87.63100 85.03700 1.000 30.00000 C ? A ? 3 1 + ATOM 23 O . LEU B 221 ? 87.44200 88.63300 85.61800 1.000 30.00000 O ? A ? 3 1 + ATOM 24 CB . LEU B 221 ? 90.28100 86.98600 85.17600 1.000 30.00000 C ? A ? 3 1 + ATOM 25 CG . LEU B 221 ? 90.87200 88.38000 85.41700 1.000 30.00000 C ? A ? 3 1 + ATOM 26 CD1 . LEU B 221 ? 91.20600 88.58500 86.88700 1.000 30.00000 C ? A ? 3 1 + ATOM 27 CD2 . LEU B 221 ? 92.11400 88.58000 84.56700 1.000 30.00000 C ? A ? 3 1 + ATOM 28 N . GLN B 222 ? 87.58200 87.26400 83.79700 1.000 30.00000 N ? A ? 4 1 + ATOM 29 CA . GLN B 222 ? 86.64600 88.03100 82.96200 1.000 30.00000 C ? A ? 4 1 + ATOM 30 C . GLN B 222 ? 85.29400 88.13300 83.64700 1.000 30.00000 C ? A ? 4 1 + ATOM 31 O . GLN B 222 ? 84.69700 89.21800 83.71200 1.000 30.00000 O ? A ? 4 1 + ATOM 32 CB . GLN B 222 ? 86.47000 87.38900 81.58400 1.000 30.00000 C ? A ? 4 1 + ATOM 33 CG . GLN B 222 ? 85.62700 88.20100 80.61100 1.000 30.00000 C ? A ? 4 1 + ATOM 34 CD . GLN B 222 ? 85.41800 87.48600 79.28900 1.000 30.00000 C ? A ? 4 1 + ATOM 35 OE1 . GLN B 222 ? 86.32900 86.84500 78.76200 1.000 30.00000 O ? A ? 4 1 + ATOM 36 NE2 . GLN B 222 ? 84.21000 87.59300 78.74400 1.000 30.00000 N ? A ? 4 1 + ATOM 37 N . GLN B 223 ? 84.84600 86.98400 84.15000 1.000 30.00000 N ? A ? 5 1 + ATOM 38 CA . GLN B 223 ? 83.56000 86.87400 84.85000 1.000 30.00000 C ? A ? 5 1 + ATOM 39 C . GLN B 223 ? 83.53000 87.82100 86.04100 1.000 30.00000 C ? A ? 5 1 + ATOM 40 O . GLN B 223 ? 82.54700 88.55700 86.25400 1.000 30.00000 O ? A ? 5 1 + ATOM 41 CB . GLN B 223 ? 83.32000 85.45500 85.38600 1.000 30.00000 C ? A ? 5 1 + ATOM 42 CG . GLN B 223 ? 82.84000 84.42600 84.38000 1.000 30.00000 C ? A ? 5 1 + ATOM 43 CD . GLN B 223 ? 82.51500 83.09900 85.04400 1.000 30.00000 C ? A ? 5 1 + ATOM 44 OE1 . GLN B 223 ? 83.12200 82.07300 84.73800 1.000 30.00000 O ? A ? 5 1 + ATOM 45 NE2 . GLN B 223 ? 81.56200 83.11700 85.97200 1.000 30.00000 N ? A ? 5 1 + ATOM 46 N . ALA B 224 ? 84.62100 87.77600 86.79700 1.000 30.00000 N ? A ? 6 1 + ATOM 47 CA . ALA B 224 ? 84.79300 88.60100 87.99700 1.000 30.00000 C ? A ? 6 1 + ATOM 48 C . ALA B 224 ? 84.67000 90.07800 87.63700 1.000 30.00000 C ? A ? 6 1 + ATOM 49 O . ALA B 224 ? 83.96500 90.84700 88.31200 1.000 30.00000 O ? A ? 6 1 + ATOM 50 CB . ALA B 224 ? 86.14000 88.33200 88.65800 1.000 30.00000 C ? A ? 6 1 + ATOM 51 N . TYR B 225 ? 85.36900 90.43600 86.56600 1.000 30.00000 N ? A ? 7 1 + ATOM 52 CA . TYR B 225 ? 85.38600 91.81200 86.06000 1.000 30.00000 C ? A ? 7 1 + ATOM 53 C . TYR B 225 ? 83.98200 92.26900 85.71700 1.000 30.00000 C ? A ? 7 1 + ATOM 54 O . TYR B 225 ? 83.56800 93.37900 86.09000 1.000 30.00000 O ? A ? 7 1 + ATOM 55 CB . TYR B 225 ? 86.38000 92.04600 84.92200 1.000 30.00000 C ? A ? 7 1 + ATOM 56 CG . TYR B 225 ? 87.59900 92.65800 85.50300 1.000 30.00000 C ? A ? 7 1 + ATOM 57 CD1 . TYR B 225 ? 87.60100 94.00300 85.84600 1.000 30.00000 C ? A ? 7 1 + ATOM 58 CD2 . TYR B 225 ? 88.71300 91.88600 85.81600 1.000 30.00000 C ? A ? 7 1 + ATOM 59 CE1 . TYR B 225 ? 88.70100 94.58100 86.44000 1.000 30.00000 C ? A ? 7 1 + ATOM 60 CE2 . TYR B 225 ? 89.82900 92.45700 86.40400 1.000 30.00000 C ? A ? 7 1 + ATOM 61 CZ . TYR B 225 ? 89.81500 93.80400 86.71400 1.000 30.00000 C ? A ? 7 1 + ATOM 62 OH . TYR B 225 ? 90.90000 94.38300 87.30700 1.000 30.00000 O ? A ? 7 1 + ATOM 63 N . LEU B 226 ? 83.27200 91.38900 85.02300 1.000 30.00000 N ? A ? 8 1 + ATOM 64 CA . LEU B 226 ? 81.89100 91.64000 84.59200 1.000 30.00000 C ? A ? 8 1 + ATOM 65 C . LEU B 226 ? 81.01500 91.92100 85.80300 1.000 30.00000 C ? A ? 8 1 + ATOM 66 O . LEU B 226 ? 80.22600 92.89200 85.80900 1.000 30.00000 O ? A ? 8 1 + ATOM 67 CB . LEU B 226 ? 81.29000 90.46300 83.80500 1.000 30.00000 C ? A ? 8 1 + ATOM 68 CG . LEU B 226 ? 81.22400 90.62000 82.28600 1.000 30.00000 C ? A ? 8 1 + ATOM 69 CD1 . LEU B 226 ? 82.61700 90.56600 81.68700 1.000 30.00000 C ? A ? 8 1 + ATOM 70 CD2 . LEU B 226 ? 80.34600 89.54000 81.66700 1.000 30.00000 C ? A ? 8 1 + ATOM 71 N . ILE B 227 ? 81.17900 91.05700 86.80800 1.000 30.00000 N ? A ? 9 1 + ATOM 72 CA . ILE B 227 ? 80.39300 91.16300 88.04500 1.000 30.00000 C ? A ? 9 1 + ATOM 73 C . ILE B 227 ? 80.65500 92.50600 88.71300 1.000 30.00000 C ? A ? 9 1 + ATOM 74 O . ILE B 227 ? 79.70300 93.17800 89.14900 1.000 30.00000 O ? A ? 9 1 + ATOM 75 CB . ILE B 227 ? 80.37100 89.95200 89.02300 1.000 30.00000 C ? A ? 9 1 + ATOM 76 CG1 . ILE B 227 ? 81.71900 89.66700 89.66200 1.000 30.00000 C ? A ? 9 1 + ATOM 77 CG2 . ILE B 227 ? 79.81000 88.71800 88.33200 1.000 30.00000 C ? A ? 9 1 + ATOM 78 CD1 . ILE B 227 ? 81.62900 88.81000 90.90400 1.000 30.00000 C ? A ? 9 1 + ATOM 79 N . MET B 228 ? 81.93000 92.87400 88.76100 1.000 30.00000 N ? A ? 10 1 + ATOM 80 CA . MET B 228 ? 82.36600 94.13800 89.36100 1.000 30.00000 C ? A ? 10 1 + ATOM 81 C . MET B 228 ? 81.69400 95.31000 88.66000 1.000 30.00000 C ? A ? 10 1 + ATOM 82 O . MET B 228 ? 81.17500 96.23100 89.31600 1.000 30.00000 O ? A ? 10 1 + ATOM 83 CB . MET B 228 ? 83.89500 94.29300 89.33900 1.000 30.00000 C ? A ? 10 1 + ATOM 84 CG . MET B 228 ? 84.66300 93.42600 90.33500 1.000 30.00000 C ? A ? 10 1 + ATOM 85 SD . MET B 228 ? 84.21400 93.61900 92.07900 1.000 30.00000 S ? A ? 10 1 + ATOM 86 CE . MET B 228 ? 84.36300 95.39000 92.34200 1.000 30.00000 C ? A ? 10 1 + diff --git a/iotbx/regression/data/non_zero_origin_model_split.cif b/iotbx/regression/data/non_zero_origin_model_split.cif new file mode 100644 index 0000000000..018b4eb77d --- /dev/null +++ b/iotbx/regression/data/non_zero_origin_model_split.cif @@ -0,0 +1,143 @@ +data_default +_cell.length_a 149.407 +_cell.length_b 144.615 +_cell.length_c 147.488 +_cell.angle_alpha 90.000 +_cell.angle_beta 90.000 +_cell.angle_gamma 90.000 +_cell.volume 3186698.485 +_space_group.crystal_system triclinic +_space_group.IT_number 1 +_space_group.name_H-M_alt 'P 1' +_space_group.name_Hall ' P 1' +_symmetry.space_group_name_H-M 'P 1' +_symmetry.space_group_name_Hall ' P 1' +_symmetry.Int_Tables_number 1 +loop_ + _space_group_symop.id + _space_group_symop.operation_xyz + 1 x,y,z + +loop_ + _struct_asym.id + A + B + C + +loop_ + _chem_comp.id + ALA + ARG + GLN + ILE + LEU + MET + TYR + +loop_ + _atom_site.group_PDB + _atom_site.id + _atom_site.label_atom_id + _atom_site.label_alt_id + _atom_site.label_comp_id + _atom_site.auth_asym_id + _atom_site.auth_seq_id + _atom_site.pdbx_PDB_ins_code + _atom_site.Cartn_x + _atom_site.Cartn_y + _atom_site.Cartn_z + _atom_site.occupancy + _atom_site.B_iso_or_equiv + _atom_site.type_symbol + _atom_site.pdbx_formal_charge + _atom_site.label_asym_id + _atom_site.label_entity_id + _atom_site.label_seq_id + _atom_site.pdbx_PDB_model_num + ATOM 1 N . LEU B 219 ? 89.17900 82.87800 82.08600 1.000 30.00000 N ? A ? 1 1 + ATOM 2 CA . LEU B 219 ? 87.73200 83.02800 81.94200 1.000 30.00000 C ? A ? 1 1 + ATOM 3 C . LEU B 219 ? 87.07400 83.47900 83.24000 1.000 30.00000 C ? A ? 1 1 + ATOM 4 O . LEU B 219 ? 86.12500 84.26500 83.21300 1.000 30.00000 O ? A ? 1 1 + ATOM 5 CB . LEU B 219 ? 87.10700 81.72100 81.44400 1.000 30.00000 C ? A ? 1 1 + ATOM 6 CG . LEU B 219 ? 85.59700 81.75200 81.15400 1.000 30.00000 C ? A ? 1 1 + ATOM 7 CD1 . LEU B 219 ? 85.27000 81.08500 79.82200 1.000 30.00000 C ? A ? 1 1 + ATOM 8 CD2 . LEU B 219 ? 84.79500 81.11600 82.28400 1.000 30.00000 C ? A ? 1 1 + ATOM 9 N . ARG B 220 ? 87.58100 82.98000 84.36600 1.000 30.00000 N ? A ? 2 1 + ATOM 10 CA . ARG B 220 ? 87.08400 83.36100 85.68200 1.000 30.00000 C ? A ? 2 1 + ATOM 11 C . ARG B 220 ? 87.30600 84.83900 85.92900 1.000 30.00000 C ? A ? 2 1 + ATOM 12 O . ARG B 220 ? 86.41800 85.51000 86.47200 1.000 30.00000 O ? A ? 2 1 + ATOM 13 CB . ARG B 220 ? 87.76800 82.54400 86.78500 1.000 30.00000 C ? A ? 2 1 + ATOM 14 CG . ARG B 220 ? 87.36400 81.07900 86.82700 1.000 30.00000 C ? A ? 2 1 + ATOM 15 CD . ARG B 220 ? 86.02400 80.87900 87.52000 1.000 30.00000 C ? A ? 2 1 + ATOM 16 NE . ARG B 220 ? 85.64800 79.46500 87.59100 1.000 30.00000 N ? A ? 2 1 + ATOM 17 CZ . ARG B 220 ? 86.14900 78.56700 88.44500 1.000 30.00000 C ? A ? 2 1 + ATOM 18 NH1 . ARG B 220 ? 87.08000 78.90100 89.34200 1.000 30.00000 N ? A ? 2 1 + ATOM 19 NH2 . ARG B 220 ? 85.71500 77.30800 88.40000 1.000 30.00000 N ? A ? 2 1 + ATOM 20 N . LEU C 221 ? 88.49500 85.31400 85.54700 1.000 30.00000 N ? B ? 1 1 + ATOM 21 CA . LEU C 221 ? 88.88200 86.71000 85.73400 1.000 30.00000 C ? B ? 1 1 + ATOM 22 C . LEU C 221 ? 87.89500 87.63100 85.03700 1.000 30.00000 C ? B ? 1 1 + ATOM 23 O . LEU C 221 ? 87.44200 88.63300 85.61800 1.000 30.00000 O ? B ? 1 1 + ATOM 24 CB . LEU C 221 ? 90.28100 86.98600 85.17600 1.000 30.00000 C ? B ? 1 1 + ATOM 25 CG . LEU C 221 ? 90.87200 88.38000 85.41700 1.000 30.00000 C ? B ? 1 1 + ATOM 26 CD1 . LEU C 221 ? 91.20600 88.58500 86.88700 1.000 30.00000 C ? B ? 1 1 + ATOM 27 CD2 . LEU C 221 ? 92.11400 88.58000 84.56700 1.000 30.00000 C ? B ? 1 1 + ATOM 28 N . GLN C 222 ? 87.58200 87.26400 83.79700 1.000 30.00000 N ? B ? 2 1 + ATOM 29 CA . GLN C 222 ? 86.64600 88.03100 82.96200 1.000 30.00000 C ? B ? 2 1 + ATOM 30 C . GLN C 222 ? 85.29400 88.13300 83.64700 1.000 30.00000 C ? B ? 2 1 + ATOM 31 O . GLN C 222 ? 84.69700 89.21800 83.71200 1.000 30.00000 O ? B ? 2 1 + ATOM 32 CB . GLN C 222 ? 86.47000 87.38900 81.58400 1.000 30.00000 C ? B ? 2 1 + ATOM 33 CG . GLN C 222 ? 85.62700 88.20100 80.61100 1.000 30.00000 C ? B ? 2 1 + ATOM 34 CD . GLN C 222 ? 85.41800 87.48600 79.28900 1.000 30.00000 C ? B ? 2 1 + ATOM 35 OE1 . GLN C 222 ? 86.32900 86.84500 78.76200 1.000 30.00000 O ? B ? 2 1 + ATOM 36 NE2 . GLN C 222 ? 84.21000 87.59300 78.74400 1.000 30.00000 N ? B ? 2 1 + ATOM 37 N . GLN D 223 ? 84.84600 86.98400 84.15000 1.000 30.00000 N ? C ? 1 1 + ATOM 38 CA . GLN D 223 ? 83.56000 86.87400 84.85000 1.000 30.00000 C ? C ? 1 1 + ATOM 39 C . GLN D 223 ? 83.53000 87.82100 86.04100 1.000 30.00000 C ? C ? 1 1 + ATOM 40 O . GLN D 223 ? 82.54700 88.55700 86.25400 1.000 30.00000 O ? C ? 1 1 + ATOM 41 CB . GLN D 223 ? 83.32000 85.45500 85.38600 1.000 30.00000 C ? C ? 1 1 + ATOM 42 CG . GLN D 223 ? 82.84000 84.42600 84.38000 1.000 30.00000 C ? C ? 1 1 + ATOM 43 CD . GLN D 223 ? 82.51500 83.09900 85.04400 1.000 30.00000 C ? C ? 1 1 + ATOM 44 OE1 . GLN D 223 ? 83.12200 82.07300 84.73800 1.000 30.00000 O ? C ? 1 1 + ATOM 45 NE2 . GLN D 223 ? 81.56200 83.11700 85.97200 1.000 30.00000 N ? C ? 1 1 + ATOM 46 N . ALA D 224 ? 84.62100 87.77600 86.79700 1.000 30.00000 N ? C ? 2 1 + ATOM 47 CA . ALA D 224 ? 84.79300 88.60100 87.99700 1.000 30.00000 C ? C ? 2 1 + ATOM 48 C . ALA D 224 ? 84.67000 90.07800 87.63700 1.000 30.00000 C ? C ? 2 1 + ATOM 49 O . ALA D 224 ? 83.96500 90.84700 88.31200 1.000 30.00000 O ? C ? 2 1 + ATOM 50 CB . ALA D 224 ? 86.14000 88.33200 88.65800 1.000 30.00000 C ? C ? 2 1 + ATOM 51 N . TYR D 225 ? 85.36900 90.43600 86.56600 1.000 30.00000 N ? C ? 3 1 + ATOM 52 CA . TYR D 225 ? 85.38600 91.81200 86.06000 1.000 30.00000 C ? C ? 3 1 + ATOM 53 C . TYR D 225 ? 83.98200 92.26900 85.71700 1.000 30.00000 C ? C ? 3 1 + ATOM 54 O . TYR D 225 ? 83.56800 93.37900 86.09000 1.000 30.00000 O ? C ? 3 1 + ATOM 55 CB . TYR D 225 ? 86.38000 92.04600 84.92200 1.000 30.00000 C ? C ? 3 1 + ATOM 56 CG . TYR D 225 ? 87.59900 92.65800 85.50300 1.000 30.00000 C ? C ? 3 1 + ATOM 57 CD1 . TYR D 225 ? 87.60100 94.00300 85.84600 1.000 30.00000 C ? C ? 3 1 + ATOM 58 CD2 . TYR D 225 ? 88.71300 91.88600 85.81600 1.000 30.00000 C ? C ? 3 1 + ATOM 59 CE1 . TYR D 225 ? 88.70100 94.58100 86.44000 1.000 30.00000 C ? C ? 3 1 + ATOM 60 CE2 . TYR D 225 ? 89.82900 92.45700 86.40400 1.000 30.00000 C ? C ? 3 1 + ATOM 61 CZ . TYR D 225 ? 89.81500 93.80400 86.71400 1.000 30.00000 C ? C ? 3 1 + ATOM 62 OH . TYR D 225 ? 90.90000 94.38300 87.30700 1.000 30.00000 O ? C ? 3 1 + ATOM 63 N . LEU D 226 ? 83.27200 91.38900 85.02300 1.000 30.00000 N ? C ? 4 1 + ATOM 64 CA . LEU D 226 ? 81.89100 91.64000 84.59200 1.000 30.00000 C ? C ? 4 1 + ATOM 65 C . LEU D 226 ? 81.01500 91.92100 85.80300 1.000 30.00000 C ? C ? 4 1 + ATOM 66 O . LEU D 226 ? 80.22600 92.89200 85.80900 1.000 30.00000 O ? C ? 4 1 + ATOM 67 CB . LEU D 226 ? 81.29000 90.46300 83.80500 1.000 30.00000 C ? C ? 4 1 + ATOM 68 CG . LEU D 226 ? 81.22400 90.62000 82.28600 1.000 30.00000 C ? C ? 4 1 + ATOM 69 CD1 . LEU D 226 ? 82.61700 90.56600 81.68700 1.000 30.00000 C ? C ? 4 1 + ATOM 70 CD2 . LEU D 226 ? 80.34600 89.54000 81.66700 1.000 30.00000 C ? C ? 4 1 + ATOM 71 N . ILE D 227 ? 81.17900 91.05700 86.80800 1.000 30.00000 N ? C ? 5 1 + ATOM 72 CA . ILE D 227 ? 80.39300 91.16300 88.04500 1.000 30.00000 C ? C ? 5 1 + ATOM 73 C . ILE D 227 ? 80.65500 92.50600 88.71300 1.000 30.00000 C ? C ? 5 1 + ATOM 74 O . ILE D 227 ? 79.70300 93.17800 89.14900 1.000 30.00000 O ? C ? 5 1 + ATOM 75 CB . ILE D 227 ? 80.37100 89.95200 89.02300 1.000 30.00000 C ? C ? 5 1 + ATOM 76 CG1 . ILE D 227 ? 81.71900 89.66700 89.66200 1.000 30.00000 C ? C ? 5 1 + ATOM 77 CG2 . ILE D 227 ? 79.81000 88.71800 88.33200 1.000 30.00000 C ? C ? 5 1 + ATOM 78 CD1 . ILE D 227 ? 81.62900 88.81000 90.90400 1.000 30.00000 C ? C ? 5 1 + ATOM 79 N . MET D 228 ? 81.93000 92.87400 88.76100 1.000 30.00000 N ? C ? 6 1 + ATOM 80 CA . MET D 228 ? 82.36600 94.13800 89.36100 1.000 30.00000 C ? C ? 6 1 + ATOM 81 C . MET D 228 ? 81.69400 95.31000 88.66000 1.000 30.00000 C ? C ? 6 1 + ATOM 82 O . MET D 228 ? 81.17500 96.23100 89.31600 1.000 30.00000 O ? C ? 6 1 + ATOM 83 CB . MET D 228 ? 83.89500 94.29300 89.33900 1.000 30.00000 C ? C ? 6 1 + ATOM 84 CG . MET D 228 ? 84.66300 93.42600 90.33500 1.000 30.00000 C ? C ? 6 1 + ATOM 85 SD . MET D 228 ? 84.21400 93.61900 92.07900 1.000 30.00000 S ? C ? 6 1 + ATOM 86 CE . MET D 228 ? 84.36300 95.39000 92.34200 1.000 30.00000 C ? C ? 6 1 + diff --git a/iotbx/regression/data/non_zero_origin_ncs_model.cif b/iotbx/regression/data/non_zero_origin_ncs_model.cif new file mode 100644 index 0000000000..590821c205 --- /dev/null +++ b/iotbx/regression/data/non_zero_origin_ncs_model.cif @@ -0,0 +1,1272 @@ +data_default +_cell.length_a 149.407 +_cell.length_b 144.615 +_cell.length_c 147.488 +_cell.angle_alpha 90.000 +_cell.angle_beta 90.000 +_cell.angle_gamma 90.000 +_cell.volume 3186698.485 +_space_group.crystal_system triclinic +_space_group.IT_number 1 +_space_group.name_H-M_alt 'P 1' +_space_group.name_Hall ' P 1' +_symmetry.space_group_name_H-M 'P 1' +_symmetry.space_group_name_Hall ' P 1' +_symmetry.Int_Tables_number 1 +loop_ + _space_group_symop.id + _space_group_symop.operation_xyz + 1 x,y,z + +loop_ + _struct_asym.id + A + B + C + D + E + F + G + H + I + J + K + L + M + N + +loop_ + _chem_comp.id + ALA + ARG + GLN + ILE + LEU + MET + TYR + +loop_ + _atom_site.group_PDB + _atom_site.id + _atom_site.label_atom_id + _atom_site.label_alt_id + _atom_site.label_comp_id + _atom_site.auth_asym_id + _atom_site.auth_seq_id + _atom_site.pdbx_PDB_ins_code + _atom_site.Cartn_x + _atom_site.Cartn_y + _atom_site.Cartn_z + _atom_site.occupancy + _atom_site.B_iso_or_equiv + _atom_site.type_symbol + _atom_site.pdbx_formal_charge + _atom_site.label_asym_id + _atom_site.label_entity_id + _atom_site.label_seq_id + _atom_site.pdbx_PDB_model_num + ATOM 1 N . LEU B 219 ? -53.84400 -42.50400 -65.40200 1.000 30.00000 N ? A ? 1 1 + ATOM 2 CA . LEU B 219 ? -53.66800 -43.94800 -65.54600 1.000 30.00000 C ? A ? 1 1 + ATOM 3 C . LEU B 219 ? -53.96200 -44.69000 -64.24800 1.000 30.00000 C ? A ? 1 1 + ATOM 4 O . LEU B 219 ? -54.51700 -45.79000 -64.27500 1.000 30.00000 O ? A ? 1 1 + ATOM 5 CB . LEU B 219 ? -52.25500 -44.26700 -66.04400 1.000 30.00000 C ? A ? 1 1 + ATOM 6 CG . LEU B 219 ? -51.94900 -45.74600 -66.33400 1.000 30.00000 C ? A ? 1 1 + ATOM 7 CD1 . LEU B 219 ? -51.22600 -45.91600 -67.66600 1.000 30.00000 C ? A ? 1 1 + ATOM 8 CD2 . LEU B 219 ? -51.15100 -46.38600 -65.20400 1.000 30.00000 C ? A ? 1 1 + ATOM 9 N . ARG B 220 ? -53.58800 -44.08500 -63.12200 1.000 30.00000 N ? A ? 2 1 + ATOM 10 CA . ARG B 220 ? -53.84900 -44.65400 -61.80600 1.000 30.00000 C ? A ? 2 1 + ATOM 11 C . ARG B 220 ? -55.33900 -44.76600 -61.55900 1.000 30.00000 C ? A ? 2 1 + ATOM 12 O . ARG B 220 ? -55.79600 -45.78100 -61.01600 1.000 30.00000 O ? A ? 2 1 + ATOM 13 CB . ARG B 220 ? -53.20500 -43.80500 -60.70300 1.000 30.00000 C ? A ? 2 1 + ATOM 14 CG . ARG B 220 ? -51.68600 -43.87300 -60.66100 1.000 30.00000 C ? A ? 2 1 + ATOM 15 CD . ARG B 220 ? -51.19300 -45.13500 -59.96800 1.000 30.00000 C ? A ? 2 1 + ATOM 16 NE . ARG B 220 ? -49.73100 -45.18700 -59.89700 1.000 30.00000 N ? A ? 2 1 + ATOM 17 CZ . ARG B 220 ? -48.96700 -44.49900 -59.04300 1.000 30.00000 C ? A ? 2 1 + ATOM 18 NH1 . ARG B 220 ? -49.50000 -43.66600 -58.14600 1.000 30.00000 N ? A ? 2 1 + ATOM 19 NH2 . ARG B 220 ? -47.64300 -44.64200 -59.08800 1.000 30.00000 N ? A ? 2 1 + ATOM 20 N . LEU B 221 ? -56.06700 -43.71300 -61.94100 1.000 30.00000 N ? A ? 3 1 + ATOM 21 CA . LEU B 221 ? -57.51400 -43.64600 -61.75400 1.000 30.00000 C ? A ? 3 1 + ATOM 22 C . LEU B 221 ? -58.19200 -44.81300 -62.45100 1.000 30.00000 C ? A ? 3 1 + ATOM 23 O . LEU B 221 ? -59.06800 -45.47800 -61.87000 1.000 30.00000 O ? A ? 3 1 + ATOM 24 CB . LEU B 221 ? -58.09400 -42.34400 -62.31200 1.000 30.00000 C ? A ? 3 1 + ATOM 25 CG . LEU B 221 ? -59.58500 -42.07800 -62.07100 1.000 30.00000 C ? A ? 3 1 + ATOM 26 CD1 . LEU B 221 ? -59.85900 -41.79800 -60.60100 1.000 30.00000 C ? A ? 3 1 + ATOM 27 CD2 . LEU B 221 ? -60.05600 -40.91100 -62.92100 1.000 30.00000 C ? A ? 3 1 + ATOM 28 N . GLN B 222 ? -57.76500 -45.03700 -63.69100 1.000 30.00000 N ? A ? 4 1 + ATOM 29 CA . GLN B 222 ? -58.30400 -46.12000 -64.52600 1.000 30.00000 C ? A ? 4 1 + ATOM 30 C . GLN B 222 ? -58.10300 -47.46100 -63.84100 1.000 30.00000 C ? A ? 4 1 + ATOM 31 O . GLN B 222 ? -59.02800 -48.28400 -63.77600 1.000 30.00000 O ? A ? 4 1 + ATOM 32 CB . GLN B 222 ? -57.63900 -46.14900 -65.90400 1.000 30.00000 C ? A ? 4 1 + ATOM 33 CG . GLN B 222 ? -58.24300 -47.15100 -66.87700 1.000 30.00000 C ? A ? 4 1 + ATOM 34 CD . GLN B 222 ? -57.50000 -47.19600 -68.19900 1.000 30.00000 C ? A ? 4 1 + ATOM 35 OE1 . GLN B 222 ? -57.07700 -46.16500 -68.72600 1.000 30.00000 O ? A ? 4 1 + ATOM 36 NE2 . GLN B 222 ? -57.33500 -48.39700 -68.74400 1.000 30.00000 N ? A ? 4 1 + ATOM 37 N . GLN B 223 ? -56.88300 -47.64200 -63.33800 1.000 30.00000 N ? A ? 5 1 + ATOM 38 CA . GLN B 223 ? -56.49000 -48.87100 -62.63800 1.000 30.00000 C ? A ? 5 1 + ATOM 39 C . GLN B 223 ? -57.40600 -49.11100 -61.44700 1.000 30.00000 C ? A ? 5 1 + ATOM 40 O . GLN B 223 ? -57.90500 -50.23300 -61.23400 1.000 30.00000 O ? A ? 5 1 + ATOM 41 CB . GLN B 223 ? -55.05300 -48.78900 -62.10200 1.000 30.00000 C ? A ? 5 1 + ATOM 42 CG . GLN B 223 ? -53.94300 -49.02800 -63.10800 1.000 30.00000 C ? A ? 5 1 + ATOM 43 CD . GLN B 223 ? -52.57700 -49.05000 -62.44400 1.000 30.00000 C ? A ? 5 1 + ATOM 44 OE1 . GLN B 223 ? -51.71200 -48.23000 -62.75000 1.000 30.00000 O ? A ? 5 1 + ATOM 45 NE2 . GLN B 223 ? -52.38200 -49.98300 -61.51600 1.000 30.00000 N ? A ? 5 1 + ATOM 46 N . ALA B 224 ? -57.60500 -48.03700 -60.69100 1.000 30.00000 N ? A ? 6 1 + ATOM 47 CA . ALA B 224 ? -58.44800 -48.05300 -59.49100 1.000 30.00000 C ? A ? 6 1 + ATOM 48 C . ALA B 224 ? -59.86000 -48.50200 -59.85100 1.000 30.00000 C ? A ? 6 1 + ATOM 49 O . ALA B 224 ? -60.45300 -49.36000 -59.17600 1.000 30.00000 O ? A ? 6 1 + ATOM 50 CB . ALA B 224 ? -58.48500 -46.68000 -58.83000 1.000 30.00000 C ? A ? 6 1 + ATOM 51 N . TYR B 225 ? -60.36500 -47.90000 -60.92200 1.000 30.00000 N ? A ? 7 1 + ATOM 52 CA . TYR B 225 ? -61.71000 -48.19000 -61.42800 1.000 30.00000 C ? A ? 7 1 + ATOM 53 C . TYR B 225 ? -61.84300 -49.66000 -61.77100 1.000 30.00000 C ? A ? 7 1 + ATOM 54 O . TYR B 225 ? -62.83300 -50.31100 -61.39800 1.000 30.00000 O ? A ? 7 1 + ATOM 55 CB . TYR B 225 ? -62.15900 -47.27300 -62.56600 1.000 30.00000 C ? A ? 7 1 + ATOM 56 CG . TYR B 225 ? -63.02700 -46.22000 -61.98500 1.000 30.00000 C ? A ? 7 1 + ATOM 57 CD1 . TYR B 225 ? -64.33900 -46.51800 -61.64200 1.000 30.00000 C ? A ? 7 1 + ATOM 58 CD2 . TYR B 225 ? -62.52200 -44.96300 -61.67200 1.000 30.00000 C ? A ? 7 1 + ATOM 59 CE1 . TYR B 225 ? -65.14700 -45.57400 -61.04800 1.000 30.00000 C ? A ? 7 1 + ATOM 60 CE2 . TYR B 225 ? -63.32700 -44.00200 -61.08400 1.000 30.00000 C ? A ? 7 1 + ATOM 61 CZ . TYR B 225 ? -64.63700 -44.31500 -60.77400 1.000 30.00000 C ? A ? 7 1 + ATOM 62 OH . TYR B 225 ? -65.44300 -43.38600 -60.18100 1.000 30.00000 O ? A ? 7 1 + ATOM 63 N . LEU B 226 ? -60.82700 -50.15700 -62.46500 1.000 30.00000 N ? A ? 8 1 + ATOM 64 CA . LEU B 226 ? -60.76500 -51.55900 -62.89600 1.000 30.00000 C ? A ? 8 1 + ATOM 65 C . LEU B 226 ? -60.84400 -52.47500 -61.68500 1.000 30.00000 C ? A ? 8 1 + ATOM 66 O . LEU B 226 ? -61.61500 -53.46000 -61.67900 1.000 30.00000 O ? A ? 8 1 + ATOM 67 CB . LEU B 226 ? -59.48300 -51.88300 -63.68300 1.000 30.00000 C ? A ? 8 1 + ATOM 68 CG . LEU B 226 ? -59.62200 -51.98200 -65.20200 1.000 30.00000 C ? A ? 8 1 + ATOM 69 CD1 . LEU B 226 ? -59.87900 -50.61200 -65.80100 1.000 30.00000 C ? A ? 8 1 + ATOM 70 CD2 . LEU B 226 ? -58.37400 -52.59800 -65.82100 1.000 30.00000 C ? A ? 8 1 + ATOM 71 N . ILE B 227 ? -60.03800 -52.12300 -60.68000 1.000 30.00000 N ? A ? 9 1 + ATOM 72 CA . ILE B 227 ? -59.96600 -52.91300 -59.44300 1.000 30.00000 C ? A ? 9 1 + ATOM 73 C . ILE B 227 ? -61.33400 -52.95600 -58.77500 1.000 30.00000 C ? A ? 9 1 + ATOM 74 O . ILE B 227 ? -61.77700 -54.03400 -58.33900 1.000 30.00000 O ? A ? 9 1 + ATOM 75 CB . ILE B 227 ? -58.78100 -52.66500 -58.46500 1.000 30.00000 C ? A ? 9 1 + ATOM 76 CG1 . ILE B 227 ? -58.80300 -51.28700 -57.82600 1.000 30.00000 C ? A ? 9 1 + ATOM 77 CG2 . ILE B 227 ? -57.45300 -52.93700 -59.15600 1.000 30.00000 C ? A ? 9 1 + ATOM 78 CD1 . ILE B 227 ? -57.94700 -51.18400 -56.58400 1.000 30.00000 C ? A ? 9 1 + ATOM 79 N . MET B 228 ? -61.97600 -51.79500 -58.72700 1.000 30.00000 N ? A ? 10 1 + ATOM 80 CA . MET B 228 ? -63.30600 -51.65100 -58.12700 1.000 30.00000 C ? A ? 10 1 + ATOM 81 C . MET B 228 ? -64.29900 -52.56700 -58.82800 1.000 30.00000 C ? A ? 10 1 + ATOM 82 O . MET B 228 ? -65.08100 -53.27800 -58.17200 1.000 30.00000 O ? A ? 10 1 + ATOM 83 CB . MET B 228 ? -63.79700 -50.19500 -58.14900 1.000 30.00000 C ? A ? 10 1 + ATOM 84 CG . MET B 228 ? -63.12300 -49.25400 -57.15300 1.000 30.00000 C ? A ? 10 1 + ATOM 85 SD . MET B 228 ? -63.21100 -49.73400 -55.40900 1.000 30.00000 S ? A ? 10 1 + ATOM 86 CE . MET B 228 ? -64.97100 -49.98300 -55.14600 1.000 30.00000 C ? A ? 10 1 + ATOM 87 N . LEU A 219 ? 11.24200 -72.65300 -65.40200 1.000 30.00000 N ? B ? 1 1 + ATOM 88 CA . LEU A 219 ? 12.48000 -73.41600 -65.54600 1.000 30.00000 C ? B ? 1 1 + ATOM 89 C . LEU A 219 ? 12.87800 -74.10800 -64.24800 1.000 30.00000 C ? B ? 1 1 + ATOM 90 O . LEU A 219 ? 13.39200 -75.22800 -64.27500 1.000 30.00000 O ? B ? 1 1 + ATOM 91 CB . LEU A 219 ? 13.61100 -72.51000 -66.04400 1.000 30.00000 C ? B ? 1 1 + ATOM 92 CG . LEU A 219 ? 14.95800 -73.19300 -66.33400 1.000 30.00000 C ? B ? 1 1 + ATOM 93 CD1 . LEU A 219 ? 15.54200 -72.73400 -67.66600 1.000 30.00000 C ? B ? 1 1 + ATOM 94 CD2 . LEU A 219 ? 15.95600 -72.96800 -65.20400 1.000 30.00000 C ? B ? 1 1 + ATOM 95 N . ARG A 220 ? 12.63700 -73.43800 -63.12200 1.000 30.00000 N ? B ? 2 1 + ATOM 96 CA . ARG A 220 ? 12.92000 -73.99700 -61.80600 1.000 30.00000 C ? B ? 2 1 + ATOM 97 C . ARG A 220 ? 12.07800 -75.23200 -61.55900 1.000 30.00000 C ? B ? 2 1 + ATOM 98 O . ARG A 220 ? 12.58700 -76.22200 -61.01600 1.000 30.00000 O ? B ? 2 1 + ATOM 99 CB . ARG A 220 ? 12.65800 -72.96400 -60.70300 1.000 30.00000 C ? B ? 2 1 + ATOM 100 CG . ARG A 220 ? 13.65800 -71.82000 -60.66100 1.000 30.00000 C ? B ? 2 1 + ATOM 101 CD . ARG A 220 ? 14.95200 -72.22100 -59.96800 1.000 30.00000 C ? B ? 2 1 + ATOM 102 NE . ARG A 220 ? 15.90400 -71.11000 -59.89700 1.000 30.00000 N ? B ? 2 1 + ATOM 103 CZ . ARG A 220 ? 15.84200 -70.08400 -59.04300 1.000 30.00000 C ? B ? 2 1 + ATOM 104 NH1 . ARG A 220 ? 14.85900 -69.98100 -58.14600 1.000 30.00000 N ? B ? 2 1 + ATOM 105 NH2 . ARG A 220 ? 16.78000 -69.13800 -59.08800 1.000 30.00000 N ? B ? 2 1 + ATOM 106 N . LEU A 221 ? 10.80100 -75.14400 -61.94100 1.000 30.00000 N ? B ? 3 1 + ATOM 107 CA . LEU A 221 ? 9.84700 -76.23400 -61.75400 1.000 30.00000 C ? B ? 3 1 + ATOM 108 C . LEU A 221 ? 10.33600 -77.49200 -62.45100 1.000 30.00000 C ? B ? 3 1 + ATOM 109 O . LEU A 221 ? 10.31000 -78.59100 -61.87000 1.000 30.00000 O ? B ? 3 1 + ATOM 110 CB . LEU A 221 ? 8.46700 -75.87600 -62.31200 1.000 30.00000 C ? B ? 3 1 + ATOM 111 CG . LEU A 221 ? 7.32900 -76.87500 -62.07100 1.000 30.00000 C ? B ? 3 1 + ATOM 112 CD1 . LEU A 221 ? 6.93900 -76.91500 -60.60100 1.000 30.00000 C ? B ? 3 1 + ATOM 113 CD2 . LEU A 221 ? 6.12300 -76.51600 -62.92100 1.000 30.00000 C ? B ? 3 1 + ATOM 114 N . GLN A 222 ? 10.77800 -77.29700 -63.69100 1.000 30.00000 N ? B ? 4 1 + ATOM 115 CA . GLN A 222 ? 11.28800 -78.39500 -64.52600 1.000 30.00000 C ? B ? 4 1 + ATOM 116 C . GLN A 222 ? 12.46200 -79.07300 -63.84100 1.000 30.00000 C ? B ? 4 1 + ATOM 117 O . GLN A 222 ? 12.52900 -80.31000 -63.77600 1.000 30.00000 O ? B ? 4 1 + ATOM 118 CB . GLN A 222 ? 11.72500 -77.89200 -65.90400 1.000 30.00000 C ? B ? 4 1 + ATOM 119 CG . GLN A 222 ? 12.13200 -78.99000 -66.87700 1.000 30.00000 C ? B ? 4 1 + ATOM 120 CD . GLN A 222 ? 12.63100 -78.43600 -68.19900 1.000 30.00000 C ? B ? 4 1 + ATOM 121 OE1 . GLN A 222 ? 12.08800 -77.46400 -68.72600 1.000 30.00000 O ? B ? 4 1 + ATOM 122 NE2 . GLN A 222 ? 13.67300 -79.05700 -68.74400 1.000 30.00000 N ? B ? 4 1 + ATOM 123 N . GLN A 223 ? 13.36400 -78.23200 -63.33800 1.000 30.00000 N ? B ? 5 1 + ATOM 124 CA . GLN A 223 ? 14.57000 -78.69100 -62.63800 1.000 30.00000 C ? B ? 5 1 + ATOM 125 C . GLN A 223 ? 14.18600 -79.55700 -61.44700 1.000 30.00000 C ? B ? 5 1 + ATOM 126 O . GLN A 223 ? 14.75300 -80.64700 -61.23400 1.000 30.00000 O ? B ? 5 1 + ATOM 127 CB . GLN A 223 ? 15.40200 -77.51700 -62.10200 1.000 30.00000 C ? B ? 5 1 + ATOM 128 CG . GLN A 223 ? 16.28100 -76.79800 -63.10800 1.000 30.00000 C ? B ? 5 1 + ATOM 129 CD . GLN A 223 ? 17.15000 -75.74400 -62.44400 1.000 30.00000 C ? B ? 5 1 + ATOM 130 OE1 . GLN A 223 ? 17.04800 -74.55600 -62.75000 1.000 30.00000 O ? B ? 5 1 + ATOM 131 NE2 . GLN A 223 ? 18.00100 -76.17300 -61.51600 1.000 30.00000 N ? B ? 5 1 + ATOM 132 N . ALA A 224 ? 13.22300 -79.04300 -60.69100 1.000 30.00000 N ? B ? 6 1 + ATOM 133 CA . ALA A 224 ? 12.71000 -79.71200 -59.49100 1.000 30.00000 C ? B ? 6 1 + ATOM 134 C . ALA A 224 ? 12.18000 -81.09600 -59.85100 1.000 30.00000 C ? B ? 6 1 + ATOM 135 O . ALA A 224 ? 12.48200 -82.09500 -59.17600 1.000 30.00000 O ? B ? 6 1 + ATOM 136 CB . ALA A 224 ? 11.61300 -78.88500 -58.83000 1.000 30.00000 C ? B ? 6 1 + ATOM 137 N . TYR A 225 ? 11.39500 -81.11500 -60.92200 1.000 30.00000 N ? B ? 7 1 + ATOM 138 CA . TYR A 225 ? 10.78300 -82.34800 -61.42800 1.000 30.00000 C ? B ? 7 1 + ATOM 139 C . TYR A 225 ? 11.84900 -83.36900 -61.77100 1.000 30.00000 C ? B ? 7 1 + ATOM 140 O . TYR A 225 ? 11.74100 -84.54800 -61.39800 1.000 30.00000 O ? B ? 7 1 + ATOM 141 CB . TYR A 225 ? 9.78600 -82.12700 -62.56600 1.000 30.00000 C ? B ? 7 1 + ATOM 142 CG . TYR A 225 ? 8.42200 -82.15000 -61.98500 1.000 30.00000 C ? B ? 7 1 + ATOM 143 CD1 . TYR A 225 ? 7.83600 -83.36100 -61.64200 1.000 30.00000 C ? B ? 7 1 + ATOM 144 CD2 . TYR A 225 ? 7.75300 -80.97100 -61.67200 1.000 30.00000 C ? B ? 7 1 + ATOM 145 CE1 . TYR A 225 ? 6.59400 -83.40400 -61.04800 1.000 30.00000 C ? B ? 7 1 + ATOM 146 CE2 . TYR A 225 ? 6.50000 -81.00100 -61.08400 1.000 30.00000 C ? B ? 7 1 + ATOM 147 CZ . TYR A 225 ? 5.92800 -82.22100 -60.77400 1.000 30.00000 C ? B ? 7 1 + ATOM 148 OH . TYR A 225 ? 4.69900 -82.27100 -60.18100 1.000 30.00000 O ? B ? 7 1 + ATOM 149 N . LEU A 226 ? 12.87100 -82.88400 -62.46500 1.000 30.00000 N ? B ? 8 1 + ATOM 150 CA . LEU A 226 ? 14.00600 -83.70900 -62.89600 1.000 30.00000 C ? B ? 8 1 + ATOM 151 C . LEU A 226 ? 14.67300 -84.34300 -61.68500 1.000 30.00000 C ? B ? 8 1 + ATOM 152 O . LEU A 226 ? 14.96300 -85.56000 -61.67900 1.000 30.00000 O ? B ? 8 1 + ATOM 153 CB . LEU A 226 ? 15.05800 -82.91000 -63.68300 1.000 30.00000 C ? B ? 8 1 + ATOM 154 CG . LEU A 226 ? 15.05000 -83.08000 -65.20200 1.000 30.00000 C ? B ? 8 1 + ATOM 155 CD1 . LEU A 226 ? 13.81800 -82.42700 -65.80100 1.000 30.00000 C ? B ? 8 1 + ATOM 156 CD2 . LEU A 226 ? 16.30900 -82.48800 -65.82100 1.000 30.00000 C ? B ? 8 1 + ATOM 157 N . ILE A 227 ? 14.90000 -83.49300 -60.68000 1.000 30.00000 N ? B ? 9 1 + ATOM 158 CA . ILE A 227 ? 15.56300 -83.93000 -59.44300 1.000 30.00000 C ? B ? 9 1 + ATOM 159 C . ILE A 227 ? 14.74400 -85.02600 -58.77500 1.000 30.00000 C ? B ? 9 1 + ATOM 160 O . ILE A 227 ? 15.31000 -86.04400 -58.33900 1.000 30.00000 O ? B ? 9 1 + ATOM 161 CB . ILE A 227 ? 16.10800 -82.84800 -58.46500 1.000 30.00000 C ? B ? 9 1 + ATOM 162 CG1 . ILE A 227 ? 15.01700 -82.00600 -57.82600 1.000 30.00000 C ? B ? 9 1 + ATOM 163 CG2 . ILE A 227 ? 17.14900 -81.98000 -59.15600 1.000 30.00000 C ? B ? 9 1 + ATOM 164 CD1 . ILE A 227 ? 15.47000 -81.27300 -56.58400 1.000 30.00000 C ? B ? 9 1 + ATOM 165 N . MET A 228 ? 13.43500 -84.80400 -58.72700 1.000 30.00000 N ? B ? 10 1 + ATOM 166 CA . MET A 228 ? 12.49400 -85.75400 -58.12700 1.000 30.00000 C ? B ? 10 1 + ATOM 167 C . MET A 228 ? 12.59100 -87.10100 -58.82800 1.000 30.00000 C ? B ? 10 1 + ATOM 168 O . MET A 228 ? 12.65900 -88.15600 -58.17200 1.000 30.00000 O ? B ? 10 1 + ATOM 169 CB . MET A 228 ? 11.04900 -85.23000 -58.14900 1.000 30.00000 C ? B ? 10 1 + ATOM 170 CG . MET A 228 ? 10.73400 -84.11600 -57.15300 1.000 30.00000 C ? B ? 10 1 + ATOM 171 SD . MET A 228 ? 11.05400 -84.48400 -55.40900 1.000 30.00000 S ? B ? 10 1 + ATOM 172 CE . MET A 228 ? 10.15200 -86.01500 -55.14600 1.000 30.00000 C ? B ? 10 1 + ATOM 173 N . LEU C 219 ? 75.39600 -40.56200 -65.40200 1.000 30.00000 N ? C ? 1 1 + ATOM 174 CA . LEU C 219 ? 76.76500 -40.06900 -65.54600 1.000 30.00000 C ? C ? 1 1 + ATOM 175 C . LEU C 219 ? 77.55400 -40.19000 -64.24800 1.000 30.00000 C ? C ? 1 1 + ATOM 176 O . LEU C 219 ? 78.75000 -40.48600 -64.27500 1.000 30.00000 O ? C ? 1 1 + ATOM 177 CB . LEU C 219 ? 76.76100 -38.62000 -66.04400 1.000 30.00000 C ? C ? 1 1 + ATOM 178 CG . LEU C 219 ? 78.13500 -37.99300 -66.33400 1.000 30.00000 C ? C ? 1 1 + ATOM 179 CD1 . LEU C 219 ? 78.14000 -37.25000 -67.66600 1.000 30.00000 C ? C ? 1 1 + ATOM 180 CD2 . LEU C 219 ? 78.58200 -37.07200 -65.20400 1.000 30.00000 C ? C ? 1 1 + ATOM 181 N . ARG C 220 ? 76.88000 -39.96000 -63.12200 1.000 30.00000 N ? C ? 2 1 + ATOM 182 CA . ARG C 220 ? 77.49300 -40.08800 -61.80600 1.000 30.00000 C ? C ? 2 1 + ATOM 183 C . ARG C 220 ? 77.93500 -41.51600 -61.55900 1.000 30.00000 C ? C ? 2 1 + ATOM 184 O . ARG C 220 ? 79.02600 -41.73500 -61.01600 1.000 30.00000 O ? C ? 2 1 + ATOM 185 CB . ARG C 220 ? 76.52300 -39.64900 -60.70300 1.000 30.00000 C ? C ? 2 1 + ATOM 186 CG . ARG C 220 ? 76.25100 -38.15300 -60.66100 1.000 30.00000 C ? C ? 2 1 + ATOM 187 CD . ARG C 220 ? 77.37200 -37.39200 -59.96800 1.000 30.00000 C ? C ? 2 1 + ATOM 188 NE . ARG C 220 ? 77.09700 -35.95500 -59.89700 1.000 30.00000 N ? C ? 2 1 + ATOM 189 CZ . ARG C 220 ? 76.25600 -35.36300 -59.04300 1.000 30.00000 C ? C ? 2 1 + ATOM 190 NH1 . ARG C 220 ? 75.56200 -36.06800 -58.14600 1.000 30.00000 N ? C ? 2 1 + ATOM 191 NH2 . ARG C 220 ? 76.10100 -34.04000 -59.08800 1.000 30.00000 N ? C ? 2 1 + ATOM 192 N . LEU C 221 ? 77.06900 -42.46000 -61.94100 1.000 30.00000 N ? C ? 3 1 + ATOM 193 CA . LEU C 221 ? 77.32600 -43.88600 -61.75400 1.000 30.00000 C ? C ? 3 1 + ATOM 194 C . LEU C 221 ? 78.61500 -44.28700 -62.45100 1.000 30.00000 C ? C ? 3 1 + ATOM 195 O . LEU C 221 ? 79.45800 -44.99300 -61.87000 1.000 30.00000 O ? C ? 3 1 + ATOM 196 CB . LEU C 221 ? 76.18600 -44.74100 -62.31200 1.000 30.00000 C ? C ? 3 1 + ATOM 197 CG . LEU C 221 ? 76.25800 -46.25400 -62.07100 1.000 30.00000 C ? C ? 3 1 + ATOM 198 CD1 . LEU C 221 ? 76.04600 -46.58300 -60.60100 1.000 30.00000 C ? C ? 3 1 + ATOM 199 CD2 . LEU C 221 ? 75.22600 -46.97300 -62.92100 1.000 30.00000 C ? C ? 3 1 + ATOM 200 N . GLN C 222 ? 78.73800 -43.82100 -63.69100 1.000 30.00000 N ? C ? 4 1 + ATOM 201 CA . GLN C 222 ? 79.91400 -44.10600 -64.52600 1.000 30.00000 C ? C ? 4 1 + ATOM 202 C . GLN C 222 ? 81.17600 -43.61100 -63.84100 1.000 30.00000 C ? C ? 4 1 + ATOM 203 O . GLN C 222 ? 82.18500 -44.32900 -63.77600 1.000 30.00000 O ? C ? 4 1 + ATOM 204 CB . GLN C 222 ? 79.79400 -43.45100 -65.90400 1.000 30.00000 C ? C ? 4 1 + ATOM 205 CG . GLN C 222 ? 80.90600 -43.81700 -66.87700 1.000 30.00000 C ? C ? 4 1 + ATOM 206 CD . GLN C 222 ? 80.78400 -43.08200 -68.19900 1.000 30.00000 C ? C ? 4 1 + ATOM 207 OE1 . GLN C 222 ? 79.68500 -42.90000 -68.72600 1.000 30.00000 O ? C ? 4 1 + ATOM 208 NE2 . GLN C 222 ? 81.91900 -42.65400 -68.74400 1.000 30.00000 N ? C ? 4 1 + ATOM 209 N . GLN C 223 ? 81.08200 -42.38100 -63.33800 1.000 30.00000 N ? C ? 5 1 + ATOM 210 CA . GLN C 223 ? 82.19300 -41.72400 -62.63800 1.000 30.00000 C ? C ? 5 1 + ATOM 211 C . GLN C 223 ? 82.63000 -42.56400 -61.44700 1.000 30.00000 C ? C ? 5 1 + ATOM 212 O . GLN C 223 ? 83.83500 -42.80100 -61.23400 1.000 30.00000 O ? C ? 5 1 + ATOM 213 CB . GLN C 223 ? 81.79300 -40.34200 -62.10200 1.000 30.00000 C ? C ? 5 1 + ATOM 214 CG . GLN C 223 ? 81.77900 -39.20600 -63.10800 1.000 30.00000 C ? C ? 5 1 + ATOM 215 CD . GLN C 223 ? 81.49600 -37.87000 -62.44400 1.000 30.00000 C ? C ? 5 1 + ATOM 216 OE1 . GLN C 223 ? 80.50400 -37.20900 -62.75000 1.000 30.00000 O ? C ? 5 1 + ATOM 217 NE2 . GLN C 223 ? 82.36300 -37.47200 -61.51600 1.000 30.00000 N ? C ? 5 1 + ATOM 218 N . ALA C 224 ? 81.62800 -42.99700 -60.69100 1.000 30.00000 N ? C ? 6 1 + ATOM 219 CA . ALA C 224 ? 81.83100 -43.81500 -59.49100 1.000 30.00000 C ? C ? 6 1 + ATOM 220 C . ALA C 224 ? 82.58300 -45.09300 -59.85100 1.000 30.00000 C ? C ? 6 1 + ATOM 221 O . ALA C 224 ? 83.55100 -45.48000 -59.17600 1.000 30.00000 O ? C ? 6 1 + ATOM 222 CB . ALA C 224 ? 80.50100 -44.15700 -58.83000 1.000 30.00000 C ? C ? 6 1 + ATOM 223 N . TYR C 225 ? 82.10800 -45.71800 -60.92200 1.000 30.00000 N ? C ? 7 1 + ATOM 224 CA . TYR C 225 ? 82.69000 -46.96600 -61.42800 1.000 30.00000 C ? C ? 7 1 + ATOM 225 C . TYR C 225 ? 84.15300 -46.76800 -61.77100 1.000 30.00000 C ? C ? 7 1 + ATOM 226 O . TYR C 225 ? 85.00800 -47.58900 -61.39800 1.000 30.00000 O ? C ? 7 1 + ATOM 227 CB . TYR C 225 ? 81.89600 -47.60800 -62.56600 1.000 30.00000 C ? C ? 7 1 + ATOM 228 CG . TYR C 225 ? 81.06300 -48.68800 -61.98500 1.000 30.00000 C ? C ? 7 1 + ATOM 229 CD1 . TYR C 225 ? 81.64500 -49.90100 -61.64200 1.000 30.00000 C ? C ? 7 1 + ATOM 230 CD2 . TYR C 225 ? 79.72400 -48.47600 -61.67200 1.000 30.00000 C ? C ? 7 1 + ATOM 231 CE1 . TYR C 225 ? 80.90400 -50.89900 -61.04800 1.000 30.00000 C ? C ? 7 1 + ATOM 232 CE2 . TYR C 225 ? 78.96700 -49.47400 -61.08400 1.000 30.00000 C ? C ? 7 1 + ATOM 233 CZ . TYR C 225 ? 79.56400 -50.68200 -60.77400 1.000 30.00000 C ? C ? 7 1 + ATOM 234 OH . TYR C 225 ? 78.83700 -51.67400 -60.18100 1.000 30.00000 O ? C ? 7 1 + ATOM 235 N . LEU C 226 ? 84.41100 -45.66700 -62.46500 1.000 30.00000 N ? C ? 8 1 + ATOM 236 CA . LEU C 226 ? 85.76400 -45.29400 -62.89600 1.000 30.00000 C ? C ? 8 1 + ATOM 237 C . LEU C 226 ? 86.67500 -45.16700 -61.68500 1.000 30.00000 C ? C ? 8 1 + ATOM 238 O . LEU C 226 ? 87.80700 -45.70000 -61.67900 1.000 30.00000 O ? C ? 8 1 + ATOM 239 CB . LEU C 226 ? 85.79500 -43.97300 -63.68300 1.000 30.00000 C ? C ? 8 1 + ATOM 240 CG . LEU C 226 ? 85.92200 -44.08600 -65.20200 1.000 30.00000 C ? C ? 8 1 + ATOM 241 CD1 . LEU C 226 ? 84.64400 -44.64200 -65.80100 1.000 30.00000 C ? C ? 8 1 + ATOM 242 CD2 . LEU C 226 ? 86.24500 -42.73200 -65.82100 1.000 30.00000 C ? C ? 8 1 + ATOM 243 N . ILE C 227 ? 86.15300 -44.46000 -60.68000 1.000 30.00000 N ? C ? 9 1 + ATOM 244 CA . ILE C 227 ? 86.90700 -44.21500 -59.44300 1.000 30.00000 C ? C ? 9 1 + ATOM 245 C . ILE C 227 ? 87.25300 -45.53800 -58.77500 1.000 30.00000 C ? C ? 9 1 + ATOM 246 O . ILE C 227 ? 88.40300 -45.73100 -58.33900 1.000 30.00000 O ? C ? 9 1 + ATOM 247 CB . ILE C 227 ? 86.40100 -43.11400 -58.46500 1.000 30.00000 C ? C ? 9 1 + ATOM 248 CG1 . ILE C 227 ? 85.06300 -43.44200 -57.82600 1.000 30.00000 C ? C ? 9 1 + ATOM 249 CG2 . ILE C 227 ? 86.37100 -41.75900 -59.15600 1.000 30.00000 C ? C ? 9 1 + ATOM 250 CD1 . ILE C 227 ? 84.77200 -42.63100 -56.58400 1.000 30.00000 C ? C ? 9 1 + ATOM 251 N . MET C 228 ? 86.26400 -46.42300 -58.72700 1.000 30.00000 N ? C ? 10 1 + ATOM 252 CA . MET C 228 ? 86.42000 -47.75100 -58.12700 1.000 30.00000 C ? C ? 10 1 + ATOM 253 C . MET C 228 ? 87.53400 -48.51500 -58.82800 1.000 30.00000 C ? C ? 10 1 + ATOM 254 O . MET C 228 ? 88.40100 -49.12000 -58.17200 1.000 30.00000 O ? C ? 10 1 + ATOM 255 CB . MET C 228 ? 85.11000 -48.55400 -58.14900 1.000 30.00000 C ? C ? 10 1 + ATOM 256 CG . MET C 228 ? 84.04100 -48.10600 -57.15300 1.000 30.00000 C ? C ? 10 1 + ATOM 257 SD . MET C 228 ? 84.53000 -48.08500 -55.40900 1.000 30.00000 S ? C ? 10 1 + ATOM 258 CE . MET C 228 ? 85.16400 -49.74500 -55.14600 1.000 30.00000 C ? C ? 10 1 + ATOM 259 N . LEU D 219 ? 90.29900 29.60200 -65.40200 1.000 30.00000 N ? D ? 1 1 + ATOM 260 CA . LEU D 219 ? 90.76700 30.97900 -65.54600 1.000 30.00000 C ? D ? 1 1 + ATOM 261 C . LEU D 219 ? 91.35300 31.52000 -64.24800 1.000 30.00000 C ? D ? 1 1 + ATOM 262 O . LEU D 219 ? 92.33100 32.27000 -64.27500 1.000 30.00000 O ? D ? 1 1 + ATOM 263 CB . LEU D 219 ? 89.63200 31.87900 -66.04400 1.000 30.00000 C ? D ? 1 1 + ATOM 264 CG . LEU D 219 ? 89.99800 33.34400 -66.33400 1.000 30.00000 C ? D ? 1 1 + ATOM 265 CD1 . LEU D 219 ? 89.42100 33.81200 -67.66600 1.000 30.00000 C ? D ? 1 1 + ATOM 266 CD2 . LEU D 219 ? 89.55700 34.26800 -65.20400 1.000 30.00000 C ? D ? 1 1 + ATOM 267 N . ARG D 220 ? 90.75400 31.13700 -63.12200 1.000 30.00000 N ? D ? 2 1 + ATOM 268 CA . ARG D 220 ? 91.23600 31.53700 -61.80600 1.000 30.00000 C ? D ? 2 1 + ATOM 269 C . ARG D 220 ? 92.62700 30.99100 -61.55900 1.000 30.00000 C ? D ? 2 1 + ATOM 270 O . ARG D 220 ? 93.47900 31.70800 -61.01600 1.000 30.00000 O ? D ? 2 1 + ATOM 271 CB . ARG D 220 ? 90.28700 31.05200 -60.70300 1.000 30.00000 C ? D ? 2 1 + ATOM 272 CG . ARG D 220 ? 88.94900 31.77200 -60.66100 1.000 30.00000 C ? D ? 2 1 + ATOM 273 CD . ARG D 220 ? 89.05200 33.12200 -59.96800 1.000 30.00000 C ? D ? 2 1 + ATOM 274 NE . ARG D 220 ? 87.75800 33.80400 -59.89700 1.000 30.00000 N ? D ? 2 1 + ATOM 275 CZ . ARG D 220 ? 86.77100 33.51500 -59.04300 1.000 30.00000 C ? D ? 2 1 + ATOM 276 NH1 . ARG D 220 ? 86.88900 32.53300 -58.14600 1.000 30.00000 N ? D ? 2 1 + ATOM 277 NH2 . ARG D 220 ? 85.64000 34.21800 -59.08800 1.000 30.00000 N ? D ? 2 1 + ATOM 278 N . LEU D 221 ? 92.82600 29.72700 -61.94100 1.000 30.00000 N ? D ? 3 1 + ATOM 279 CA . LEU D 221 ? 94.10100 29.03900 -61.75400 1.000 30.00000 C ? D ? 3 1 + ATOM 280 C . LEU D 221 ? 95.21800 29.79600 -62.45100 1.000 30.00000 C ? D ? 3 1 + ATOM 281 O . LEU D 221 ? 96.29600 30.01500 -61.87000 1.000 30.00000 O ? D ? 3 1 + ATOM 282 CB . LEU D 221 ? 94.05900 27.61300 -62.31200 1.000 30.00000 C ? D ? 3 1 + ATOM 283 CG . LEU D 221 ? 95.28600 26.72700 -62.07100 1.000 30.00000 C ? D ? 3 1 + ATOM 284 CD1 . LEU D 221 ? 95.41100 26.35600 -60.60100 1.000 30.00000 C ? D ? 3 1 + ATOM 285 CD2 . LEU D 221 ? 95.20500 25.47200 -62.92100 1.000 30.00000 C ? D ? 3 1 + ATOM 286 N . GLN D 222 ? 94.93000 30.18300 -63.69100 1.000 30.00000 N ? D ? 4 1 + ATOM 287 CA . GLN D 222 ? 95.88600 30.92500 -64.52600 1.000 30.00000 C ? D ? 4 1 + ATOM 288 C . GLN D 222 ? 96.28600 32.22000 -63.84100 1.000 30.00000 C ? D ? 4 1 + ATOM 289 O . GLN D 222 ? 97.47700 32.56000 -63.77600 1.000 30.00000 O ? D ? 4 1 + ATOM 290 CB . GLN D 222 ? 95.29900 31.23900 -65.90400 1.000 30.00000 C ? D ? 4 1 + ATOM 291 CG . GLN D 222 ? 96.27900 31.88000 -66.87700 1.000 30.00000 C ? D ? 4 1 + ATOM 292 CD . GLN D 222 ? 95.62800 32.24300 -68.19900 1.000 30.00000 C ? D ? 4 1 + ATOM 293 OE1 . GLN D 222 ? 94.80000 31.49700 -68.72600 1.000 30.00000 O ? D ? 4 1 + ATOM 294 NE2 . GLN D 222 ? 96.00100 33.39700 -68.74400 1.000 30.00000 N ? D ? 4 1 + ATOM 295 N . GLN D 223 ? 95.26600 32.91200 -63.33800 1.000 30.00000 N ? D ? 5 1 + ATOM 296 CA . GLN D 223 ? 95.44500 34.19000 -62.63800 1.000 30.00000 C ? D ? 5 1 + ATOM 297 C . GLN D 223 ? 96.37500 34.00900 -61.44700 1.000 30.00000 C ? D ? 5 1 + ATOM 298 O . GLN D 223 ? 97.31100 34.80300 -61.23400 1.000 30.00000 O ? D ? 5 1 + ATOM 299 CB . GLN D 223 ? 94.11500 34.74000 -62.10200 1.000 30.00000 C ? D ? 5 1 + ATOM 300 CG . GLN D 223 ? 93.21900 35.43700 -63.10800 1.000 30.00000 C ? D ? 5 1 + ATOM 301 CD . GLN D 223 ? 91.99700 36.04900 -62.44400 1.000 30.00000 C ? D ? 5 1 + ATOM 302 OE1 . GLN D 223 ? 90.86200 35.68600 -62.75000 1.000 30.00000 O ? D ? 5 1 + ATOM 303 NE2 . GLN D 223 ? 92.22700 36.97400 -61.51600 1.000 30.00000 N ? D ? 5 1 + ATOM 304 N . ALA D 224 ? 96.08800 32.95500 -60.69100 1.000 30.00000 N ? D ? 6 1 + ATOM 305 CA . ALA D 224 ? 96.85400 32.60400 -59.49100 1.000 30.00000 C ? D ? 6 1 + ATOM 306 C . ALA D 224 ? 98.32100 32.39500 -59.85100 1.000 30.00000 C ? D ? 6 1 + ATOM 307 O . ALA D 224 ? 99.22800 32.91100 -59.17600 1.000 30.00000 O ? D ? 6 1 + ATOM 308 CB . ALA D 224 ? 96.29200 31.35100 -58.83000 1.000 30.00000 C ? D ? 6 1 + ATOM 309 N . TYR D 225 ? 98.51500 31.63400 -60.92200 1.000 30.00000 N ? D ? 7 1 + ATOM 310 CA . TYR D 225 ? 99.85200 31.31100 -61.42800 1.000 30.00000 C ? D ? 7 1 + ATOM 311 C . TYR D 225 ? 100.61000 32.57800 -61.77100 1.000 30.00000 C ? D ? 7 1 + ATOM 312 O . TYR D 225 ? 101.78500 32.73500 -61.39800 1.000 30.00000 O ? D ? 7 1 + ATOM 313 CB . TYR D 225 ? 99.85900 30.29000 -62.56600 1.000 30.00000 C ? D ? 7 1 + ATOM 314 CG . TYR D 225 ? 100.18500 28.96600 -61.98500 1.000 30.00000 C ? D ? 7 1 + ATOM 315 CD1 . TYR D 225 ? 101.49500 28.66500 -61.64200 1.000 30.00000 C ? D ? 7 1 + ATOM 316 CD2 . TYR D 225 ? 99.18400 28.05200 -61.67200 1.000 30.00000 C ? D ? 7 1 + ATOM 317 CE1 . TYR D 225 ? 101.81400 27.46400 -61.04800 1.000 30.00000 C ? D ? 7 1 + ATOM 318 CE2 . TYR D 225 ? 99.49300 26.83700 -61.08400 1.000 30.00000 C ? D ? 7 1 + ATOM 319 CZ . TYR D 225 ? 100.80900 26.55100 -60.77400 1.000 30.00000 C ? D ? 7 1 + ATOM 320 OH . TYR D 225 ? 101.13200 25.36400 -60.18100 1.000 30.00000 O ? D ? 7 1 + ATOM 321 N . LEU D 226 ? 99.91000 33.46600 -62.46500 1.000 30.00000 N ? D ? 8 1 + ATOM 322 CA . LEU D 226 ? 100.46200 34.75700 -62.89600 1.000 30.00000 C ? D ? 8 1 + ATOM 323 C . LEU D 226 ? 100.93100 35.54800 -61.68500 1.000 30.00000 C ? D ? 8 1 + ATOM 324 O . LEU D 226 ? 102.05300 36.10100 -61.67900 1.000 30.00000 O ? D ? 8 1 + ATOM 325 CB . LEU D 226 ? 99.44900 35.60500 -63.68300 1.000 30.00000 C ? D ? 8 1 + ATOM 326 CG . LEU D 226 ? 99.61700 35.63400 -65.20200 1.000 30.00000 C ? D ? 8 1 + ATOM 327 CD1 . LEU D 226 ? 99.25400 34.28800 -65.80100 1.000 30.00000 C ? D ? 8 1 + ATOM 328 CD2 . LEU D 226 ? 98.75900 36.73000 -65.82100 1.000 30.00000 C ? D ? 8 1 + ATOM 329 N . ILE D 227 ? 100.05300 35.58100 -60.68000 1.000 30.00000 N ? D ? 9 1 + ATOM 330 CA . ILE D 227 ? 100.33100 36.32300 -59.44300 1.000 30.00000 C ? D ? 9 1 + ATOM 331 C . ILE D 227 ? 101.58200 35.76900 -58.77500 1.000 30.00000 C ? D ? 9 1 + ATOM 332 O . ILE D 227 ? 102.44900 36.54800 -58.33900 1.000 30.00000 O ? D ? 9 1 + ATOM 333 CB . ILE D 227 ? 99.15500 36.61400 -58.46500 1.000 30.00000 C ? D ? 9 1 + ATOM 334 CG1 . ILE D 227 ? 98.57700 35.36400 -57.82600 1.000 30.00000 C ? D ? 9 1 + ATOM 335 CG2 . ILE D 227 ? 98.07700 37.43600 -59.15600 1.000 30.00000 C ? D ? 9 1 + ATOM 336 CD1 . ILE D 227 ? 97.76200 35.64200 -56.58400 1.000 30.00000 C ? D ? 9 1 + ATOM 337 N . MET D 228 ? 101.65700 34.44400 -58.72700 1.000 30.00000 N ? D ? 10 1 + ATOM 338 CA . MET D 228 ? 102.79200 33.73800 -58.12700 1.000 30.00000 C ? D ? 10 1 + ATOM 339 C . MET D 228 ? 104.08400 34.13200 -58.82800 1.000 30.00000 C ? D ? 10 1 + ATOM 340 O . MET D 228 ? 105.09700 34.43300 -58.17200 1.000 30.00000 O ? D ? 10 1 + ATOM 341 CB . MET D 228 ? 102.60300 32.21300 -58.14900 1.000 30.00000 C ? D ? 10 1 + ATOM 342 CG . MET D 228 ? 101.58700 31.65700 -57.15300 1.000 30.00000 C ? D ? 10 1 + ATOM 343 SD . MET D 228 ? 101.87500 32.05200 -55.40900 1.000 30.00000 S ? D ? 10 1 + ATOM 344 CE . MET D 228 ? 103.56800 31.51300 -55.14600 1.000 30.00000 C ? D ? 10 1 + ATOM 345 N . LEU E 219 ? 44.73900 85.00200 -65.40200 1.000 30.00000 N ? E ? 1 1 + ATOM 346 CA . LEU E 219 ? 43.95400 86.22700 -65.54600 1.000 30.00000 C ? E ? 1 1 + ATOM 347 C . LEU E 219 ? 43.89700 87.02200 -64.24800 1.000 30.00000 C ? E ? 1 1 + ATOM 348 O . LEU E 219 ? 43.91900 88.25400 -64.27500 1.000 30.00000 O ? E ? 1 1 + ATOM 349 CB . LEU E 219 ? 42.54300 85.90100 -66.04400 1.000 30.00000 C ? E ? 1 1 + ATOM 350 CG . LEU E 219 ? 41.62600 87.10000 -66.33400 1.000 30.00000 C ? E ? 1 1 + ATOM 351 CD1 . LEU E 219 ? 40.90000 86.94000 -67.66600 1.000 30.00000 C ? E ? 1 1 + ATOM 352 CD2 . LEU E 219 ? 40.62800 87.33100 -65.20400 1.000 30.00000 C ? E ? 1 1 + ATOM 353 N . ARG E 220 ? 43.82300 86.31500 -63.12200 1.000 30.00000 N ? E ? 2 1 + ATOM 354 CA . ARG E 220 ? 43.81100 86.94100 -61.80600 1.000 30.00000 C ? E ? 2 1 + ATOM 355 C . ARG E 220 ? 45.10500 87.68900 -61.55900 1.000 30.00000 C ? E ? 2 1 + ATOM 356 O . ARG E 220 ? 45.07500 88.80200 -61.01600 1.000 30.00000 O ? E ? 2 1 + ATOM 357 CB . ARG E 220 ? 43.59800 85.89700 -60.70300 1.000 30.00000 C ? E ? 2 1 + ATOM 358 CG . ARG E 220 ? 42.20100 85.29900 -60.66100 1.000 30.00000 C ? E ? 2 1 + ATOM 359 CD . ARG E 220 ? 41.20900 86.22200 -59.96800 1.000 30.00000 C ? E ? 2 1 + ATOM 360 NE . ARG E 220 ? 39.87000 85.63500 -59.89700 1.000 30.00000 N ? E ? 2 1 + ATOM 361 CZ . ARG E 220 ? 39.48000 84.68300 -59.04300 1.000 30.00000 C ? E ? 2 1 + ATOM 362 NH1 . ARG E 220 ? 40.32100 84.16400 -58.14600 1.000 30.00000 N ? E ? 2 1 + ATOM 363 NH2 . ARG E 220 ? 38.22500 84.23800 -59.08800 1.000 30.00000 N ? E ? 2 1 + ATOM 364 N . LEU E 221 ? 46.21700 87.05600 -61.94100 1.000 30.00000 N ? E ? 3 1 + ATOM 365 CA . LEU E 221 ? 47.55000 87.62300 -61.75400 1.000 30.00000 C ? E ? 3 1 + ATOM 366 C . LEU E 221 ? 47.65400 88.96900 -62.45100 1.000 30.00000 C ? E ? 3 1 + ATOM 367 O . LEU E 221 ? 48.15500 89.94800 -61.87000 1.000 30.00000 O ? E ? 3 1 + ATOM 368 CB . LEU E 221 ? 48.63800 86.70200 -62.31200 1.000 30.00000 C ? E ? 3 1 + ATOM 369 CG . LEU E 221 ? 50.09600 87.10900 -62.07100 1.000 30.00000 C ? E ? 3 1 + ATOM 370 CD1 . LEU E 221 ? 50.46400 86.97500 -60.60100 1.000 30.00000 C ? E ? 3 1 + ATOM 371 CD2 . LEU E 221 ? 51.02700 86.26200 -62.92100 1.000 30.00000 C ? E ? 3 1 + ATOM 372 N . GLN E 222 ? 47.17200 88.98500 -63.69100 1.000 30.00000 N ? E ? 4 1 + ATOM 373 CA . GLN E 222 ? 47.18900 90.19500 -64.52600 1.000 30.00000 C ? E ? 4 1 + ATOM 374 C . GLN E 222 ? 46.42500 91.31600 -63.84100 1.000 30.00000 C ? E ? 4 1 + ATOM 375 O . GLN E 222 ? 46.90100 92.45900 -63.77600 1.000 30.00000 O ? E ? 4 1 + ATOM 376 CB . GLN E 222 ? 46.57700 89.93200 -65.90400 1.000 30.00000 C ? E ? 4 1 + ATOM 377 CG . GLN E 222 ? 46.68600 91.09800 -66.87700 1.000 30.00000 C ? E ? 4 1 + ATOM 378 CD . GLN E 222 ? 45.99700 90.81500 -68.19900 1.000 30.00000 C ? E ? 4 1 + ATOM 379 OE1 . GLN E 222 ? 46.06400 89.70300 -68.72600 1.000 30.00000 O ? E ? 4 1 + ATOM 380 NE2 . GLN E 222 ? 45.32700 91.82600 -68.74400 1.000 30.00000 N ? E ? 4 1 + ATOM 381 N . GLN E 223 ? 45.24800 90.94900 -63.33800 1.000 30.00000 N ? E ? 5 1 + ATOM 382 CA . GLN E 223 ? 44.36000 91.88600 -62.63800 1.000 30.00000 C ? E ? 5 1 + ATOM 383 C . GLN E 223 ? 45.08200 92.50000 -61.44700 1.000 30.00000 C ? E ? 5 1 + ATOM 384 O . GLN E 223 ? 45.04400 93.72700 -61.23400 1.000 30.00000 O ? E ? 5 1 + ATOM 385 CB . GLN E 223 ? 43.10100 91.18900 -62.10200 1.000 30.00000 C ? E ? 5 1 + ATOM 386 CG . GLN E 223 ? 41.99700 90.92300 -63.10800 1.000 30.00000 C ? E ? 5 1 + ATOM 387 CD . GLN E 223 ? 40.75700 90.35000 -62.44400 1.000 30.00000 C ? E ? 5 1 + ATOM 388 OE1 . GLN E 223 ? 40.33400 89.23600 -62.75000 1.000 30.00000 O ? E ? 5 1 + ATOM 389 NE2 . GLN E 223 ? 40.17700 91.10600 -61.51600 1.000 30.00000 N ? E ? 5 1 + ATOM 390 N . ALA E 224 ? 45.72700 91.61900 -60.69100 1.000 30.00000 N ? E ? 6 1 + ATOM 391 CA . ALA E 224 ? 46.47900 91.99900 -59.49100 1.000 30.00000 C ? E ? 6 1 + ATOM 392 C . ALA E 224 ? 47.55700 93.01600 -59.85100 1.000 30.00000 C ? E ? 6 1 + ATOM 393 O . ALA E 224 ? 47.71900 94.04700 -59.17600 1.000 30.00000 O ? E ? 6 1 + ATOM 394 CB . ALA E 224 ? 47.10800 90.77800 -58.83000 1.000 30.00000 C ? E ? 6 1 + ATOM 395 N . TYR E 225 ? 48.27300 92.69300 -60.92200 1.000 30.00000 N ? E ? 7 1 + ATOM 396 CA . TYR E 225 ? 49.35900 93.53700 -61.42800 1.000 30.00000 C ? E ? 7 1 + ATOM 397 C . TYR E 225 ? 48.84100 94.92000 -61.77100 1.000 30.00000 C ? E ? 7 1 + ATOM 398 O . TYR E 225 ? 49.45100 95.93500 -61.39800 1.000 30.00000 O ? E ? 7 1 + ATOM 399 CB . TYR E 225 ? 50.16200 92.90600 -62.56600 1.000 30.00000 C ? E ? 7 1 + ATOM 400 CG . TYR E 225 ? 51.40000 92.33500 -61.98500 1.000 30.00000 C ? E ? 7 1 + ATOM 401 CD1 . TYR E 225 ? 52.45300 93.17200 -61.64200 1.000 30.00000 C ? E ? 7 1 + ATOM 402 CD2 . TYR E 225 ? 51.49100 90.98200 -61.67200 1.000 30.00000 C ? E ? 7 1 + ATOM 403 CE1 . TYR E 225 ? 53.59000 92.67200 -61.04800 1.000 30.00000 C ? E ? 7 1 + ATOM 404 CE2 . TYR E 225 ? 52.63300 90.46600 -61.08400 1.000 30.00000 C ? E ? 7 1 + ATOM 405 CZ . TYR E 225 ? 53.67700 91.31700 -60.77400 1.000 30.00000 C ? E ? 7 1 + ATOM 406 OH . TYR E 225 ? 54.80700 90.82900 -60.18100 1.000 30.00000 O ? E ? 7 1 + ATOM 407 N . LEU E 226 ? 47.71000 94.92600 -62.46500 1.000 30.00000 N ? E ? 8 1 + ATOM 408 CA . LEU E 226 ? 47.04600 96.16200 -62.89600 1.000 30.00000 C ? E ? 8 1 + ATOM 409 C . LEU E 226 ? 46.71900 97.02200 -61.68500 1.000 30.00000 C ? E ? 8 1 + ATOM 410 O . LEU E 226 ? 46.98600 98.24500 -61.67900 1.000 30.00000 O ? E ? 8 1 + ATOM 411 CB . LEU E 226 ? 45.75100 95.89800 -63.68300 1.000 30.00000 C ? E ? 8 1 + ATOM 412 CG . LEU E 226 ? 45.83200 96.04800 -65.20200 1.000 30.00000 C ? E ? 8 1 + ATOM 413 CD1 . LEU E 226 ? 46.65900 94.92500 -65.80100 1.000 30.00000 C ? E ? 8 1 + ATOM 414 CD2 . LEU E 226 ? 44.44100 96.06100 -65.82100 1.000 30.00000 C ? E ? 8 1 + ATOM 415 N . ILE E 227 ? 46.14600 96.35600 -60.68000 1.000 30.00000 N ? E ? 9 1 + ATOM 416 CA . ILE E 227 ? 45.73900 97.03600 -59.44300 1.000 30.00000 C ? E ? 9 1 + ATOM 417 C . ILE E 227 ? 46.95200 97.66900 -58.77500 1.000 30.00000 C ? E ? 9 1 + ATOM 418 O . ILE E 227 ? 46.88400 98.83200 -58.33900 1.000 30.00000 O ? E ? 9 1 + ATOM 419 CB . ILE E 227 ? 44.77800 96.29800 -58.46500 1.000 30.00000 C ? E ? 9 1 + ATOM 420 CG1 . ILE E 227 ? 45.39600 95.06700 -57.82600 1.000 30.00000 C ? E ? 9 1 + ATOM 421 CG2 . ILE E 227 ? 43.46400 95.96800 -59.15600 1.000 30.00000 C ? E ? 9 1 + ATOM 422 CD1 . ILE E 227 ? 44.67000 94.60300 -56.58400 1.000 30.00000 C ? E ? 9 1 + ATOM 423 N . MET E 228 ? 48.03500 96.90100 -58.72700 1.000 30.00000 N ? E ? 10 1 + ATOM 424 CA . MET E 228 ? 49.29500 97.34800 -58.12700 1.000 30.00000 C ? E ? 10 1 + ATOM 425 C . MET E 228 ? 49.79200 98.60400 -58.82800 1.000 30.00000 C ? E ? 10 1 + ATOM 426 O . MET E 228 ? 50.18800 99.58400 -58.17200 1.000 30.00000 O ? E ? 10 1 + ATOM 427 CB . MET E 228 ? 50.36900 96.25000 -58.14900 1.000 30.00000 C ? E ? 10 1 + ATOM 428 CG . MET E 228 ? 50.17000 95.10900 -57.15300 1.000 30.00000 C ? E ? 10 1 + ATOM 429 SD . MET E 228 ? 50.04100 95.58000 -55.40900 1.000 30.00000 S ? E ? 10 1 + ATOM 430 CE . MET E 228 ? 51.51800 96.56800 -55.14600 1.000 30.00000 C ? E ? 10 1 + ATOM 431 N . LEU F 219 ? -26.98300 83.92900 -65.40200 1.000 30.00000 N ? F ? 1 1 + ATOM 432 CA . LEU F 219 ? -28.43000 84.07900 -65.54600 1.000 30.00000 C ? F ? 1 1 + ATOM 433 C . LEU F 219 ? -29.08800 84.53000 -64.24800 1.000 30.00000 C ? F ? 1 1 + ATOM 434 O . LEU F 219 ? -30.03700 85.31600 -64.27500 1.000 30.00000 O ? F ? 1 1 + ATOM 435 CB . LEU F 219 ? -29.05500 82.77200 -66.04400 1.000 30.00000 C ? F ? 1 1 + ATOM 436 CG . LEU F 219 ? -30.56500 82.80300 -66.33400 1.000 30.00000 C ? F ? 1 1 + ATOM 437 CD1 . LEU F 219 ? -30.89200 82.13600 -67.66600 1.000 30.00000 C ? F ? 1 1 + ATOM 438 CD2 . LEU F 219 ? -31.36700 82.16700 -65.20400 1.000 30.00000 C ? F ? 1 1 + ATOM 439 N . ARG F 220 ? -28.58100 84.03100 -63.12200 1.000 30.00000 N ? F ? 2 1 + ATOM 440 CA . ARG F 220 ? -29.07800 84.41200 -61.80600 1.000 30.00000 C ? F ? 2 1 + ATOM 441 C . ARG F 220 ? -28.85600 85.89000 -61.55900 1.000 30.00000 C ? F ? 2 1 + ATOM 442 O . ARG F 220 ? -29.74400 86.56100 -61.01600 1.000 30.00000 O ? F ? 2 1 + ATOM 443 CB . ARG F 220 ? -28.39400 83.59500 -60.70300 1.000 30.00000 C ? F ? 2 1 + ATOM 444 CG . ARG F 220 ? -28.79800 82.13000 -60.66100 1.000 30.00000 C ? F ? 2 1 + ATOM 445 CD . ARG F 220 ? -30.13800 81.93000 -59.96800 1.000 30.00000 C ? F ? 2 1 + ATOM 446 NE . ARG F 220 ? -30.51400 80.51600 -59.89700 1.000 30.00000 N ? F ? 2 1 + ATOM 447 CZ . ARG F 220 ? -30.01300 79.61800 -59.04300 1.000 30.00000 C ? F ? 2 1 + ATOM 448 NH1 . ARG F 220 ? -29.08200 79.95200 -58.14600 1.000 30.00000 N ? F ? 2 1 + ATOM 449 NH2 . ARG F 220 ? -30.44700 78.35900 -59.08800 1.000 30.00000 N ? F ? 2 1 + ATOM 450 N . LEU F 221 ? -27.66700 86.36500 -61.94100 1.000 30.00000 N ? F ? 3 1 + ATOM 451 CA . LEU F 221 ? -27.28000 87.76100 -61.75400 1.000 30.00000 C ? F ? 3 1 + ATOM 452 C . LEU F 221 ? -28.26700 88.68200 -62.45100 1.000 30.00000 C ? F ? 3 1 + ATOM 453 O . LEU F 221 ? -28.72000 89.68400 -61.87000 1.000 30.00000 O ? F ? 3 1 + ATOM 454 CB . LEU F 221 ? -25.88100 88.03700 -62.31200 1.000 30.00000 C ? F ? 3 1 + ATOM 455 CG . LEU F 221 ? -25.29000 89.43100 -62.07100 1.000 30.00000 C ? F ? 3 1 + ATOM 456 CD1 . LEU F 221 ? -24.95600 89.63600 -60.60100 1.000 30.00000 C ? F ? 3 1 + ATOM 457 CD2 . LEU F 221 ? -24.04800 89.63100 -62.92100 1.000 30.00000 C ? F ? 3 1 + ATOM 458 N . GLN F 222 ? -28.58000 88.31500 -63.69100 1.000 30.00000 N ? F ? 4 1 + ATOM 459 CA . GLN F 222 ? -29.51600 89.08200 -64.52600 1.000 30.00000 C ? F ? 4 1 + ATOM 460 C . GLN F 222 ? -30.86800 89.18400 -63.84100 1.000 30.00000 C ? F ? 4 1 + ATOM 461 O . GLN F 222 ? -31.46500 90.26900 -63.77600 1.000 30.00000 O ? F ? 4 1 + ATOM 462 CB . GLN F 222 ? -29.69200 88.44000 -65.90400 1.000 30.00000 C ? F ? 4 1 + ATOM 463 CG . GLN F 222 ? -30.53500 89.25200 -66.87700 1.000 30.00000 C ? F ? 4 1 + ATOM 464 CD . GLN F 222 ? -30.74400 88.53700 -68.19900 1.000 30.00000 C ? F ? 4 1 + ATOM 465 OE1 . GLN F 222 ? -29.83300 87.89600 -68.72600 1.000 30.00000 O ? F ? 4 1 + ATOM 466 NE2 . GLN F 222 ? -31.95200 88.64400 -68.74400 1.000 30.00000 N ? F ? 4 1 + ATOM 467 N . GLN F 223 ? -31.31600 88.03500 -63.33800 1.000 30.00000 N ? F ? 5 1 + ATOM 468 CA . GLN F 223 ? -32.60200 87.92500 -62.63800 1.000 30.00000 C ? F ? 5 1 + ATOM 469 C . GLN F 223 ? -32.63200 88.87200 -61.44700 1.000 30.00000 C ? F ? 5 1 + ATOM 470 O . GLN F 223 ? -33.61500 89.60800 -61.23400 1.000 30.00000 O ? F ? 5 1 + ATOM 471 CB . GLN F 223 ? -32.84200 86.50600 -62.10200 1.000 30.00000 C ? F ? 5 1 + ATOM 472 CG . GLN F 223 ? -33.32200 85.47700 -63.10800 1.000 30.00000 C ? F ? 5 1 + ATOM 473 CD . GLN F 223 ? -33.64700 84.15000 -62.44400 1.000 30.00000 C ? F ? 5 1 + ATOM 474 OE1 . GLN F 223 ? -33.04000 83.12400 -62.75000 1.000 30.00000 O ? F ? 5 1 + ATOM 475 NE2 . GLN F 223 ? -34.60000 84.16800 -61.51600 1.000 30.00000 N ? F ? 5 1 + ATOM 476 N . ALA F 224 ? -31.54100 88.82700 -60.69100 1.000 30.00000 N ? F ? 6 1 + ATOM 477 CA . ALA F 224 ? -31.36900 89.65200 -59.49100 1.000 30.00000 C ? F ? 6 1 + ATOM 478 C . ALA F 224 ? -31.49200 91.12900 -59.85100 1.000 30.00000 C ? F ? 6 1 + ATOM 479 O . ALA F 224 ? -32.19700 91.89800 -59.17600 1.000 30.00000 O ? F ? 6 1 + ATOM 480 CB . ALA F 224 ? -30.02200 89.38300 -58.83000 1.000 30.00000 C ? F ? 6 1 + ATOM 481 N . TYR F 225 ? -30.79300 91.48700 -60.92200 1.000 30.00000 N ? F ? 7 1 + ATOM 482 CA . TYR F 225 ? -30.77600 92.86300 -61.42800 1.000 30.00000 C ? F ? 7 1 + ATOM 483 C . TYR F 225 ? -32.18000 93.32000 -61.77100 1.000 30.00000 C ? F ? 7 1 + ATOM 484 O . TYR F 225 ? -32.59400 94.43000 -61.39800 1.000 30.00000 O ? F ? 7 1 + ATOM 485 CB . TYR F 225 ? -29.78200 93.09700 -62.56600 1.000 30.00000 C ? F ? 7 1 + ATOM 486 CG . TYR F 225 ? -28.56300 93.70900 -61.98500 1.000 30.00000 C ? F ? 7 1 + ATOM 487 CD1 . TYR F 225 ? -28.56100 95.05400 -61.64200 1.000 30.00000 C ? F ? 7 1 + ATOM 488 CD2 . TYR F 225 ? -27.44900 92.93700 -61.67200 1.000 30.00000 C ? F ? 7 1 + ATOM 489 CE1 . TYR F 225 ? -27.46100 95.63200 -61.04800 1.000 30.00000 C ? F ? 7 1 + ATOM 490 CE2 . TYR F 225 ? -26.33300 93.50800 -61.08400 1.000 30.00000 C ? F ? 7 1 + ATOM 491 CZ . TYR F 225 ? -26.34700 94.85500 -60.77400 1.000 30.00000 C ? F ? 7 1 + ATOM 492 OH . TYR F 225 ? -25.26200 95.43400 -60.18100 1.000 30.00000 O ? F ? 7 1 + ATOM 493 N . LEU F 226 ? -32.89000 92.44000 -62.46500 1.000 30.00000 N ? F ? 8 1 + ATOM 494 CA . LEU F 226 ? -34.27100 92.69100 -62.89600 1.000 30.00000 C ? F ? 8 1 + ATOM 495 C . LEU F 226 ? -35.14700 92.97200 -61.68500 1.000 30.00000 C ? F ? 8 1 + ATOM 496 O . LEU F 226 ? -35.93600 93.94300 -61.67900 1.000 30.00000 O ? F ? 8 1 + ATOM 497 CB . LEU F 226 ? -34.87200 91.51400 -63.68300 1.000 30.00000 C ? F ? 8 1 + ATOM 498 CG . LEU F 226 ? -34.93800 91.67100 -65.20200 1.000 30.00000 C ? F ? 8 1 + ATOM 499 CD1 . LEU F 226 ? -33.54500 91.61700 -65.80100 1.000 30.00000 C ? F ? 8 1 + ATOM 500 CD2 . LEU F 226 ? -35.81600 90.59100 -65.82100 1.000 30.00000 C ? F ? 8 1 + ATOM 501 N . ILE F 227 ? -34.98300 92.10800 -60.68000 1.000 30.00000 N ? F ? 9 1 + ATOM 502 CA . ILE F 227 ? -35.76900 92.21400 -59.44300 1.000 30.00000 C ? F ? 9 1 + ATOM 503 C . ILE F 227 ? -35.50700 93.55700 -58.77500 1.000 30.00000 C ? F ? 9 1 + ATOM 504 O . ILE F 227 ? -36.45900 94.22900 -58.33900 1.000 30.00000 O ? F ? 9 1 + ATOM 505 CB . ILE F 227 ? -35.79100 91.00300 -58.46500 1.000 30.00000 C ? F ? 9 1 + ATOM 506 CG1 . ILE F 227 ? -34.44300 90.71800 -57.82600 1.000 30.00000 C ? F ? 9 1 + ATOM 507 CG2 . ILE F 227 ? -36.35200 89.76900 -59.15600 1.000 30.00000 C ? F ? 9 1 + ATOM 508 CD1 . ILE F 227 ? -34.53300 89.86100 -56.58400 1.000 30.00000 C ? F ? 9 1 + ATOM 509 N . MET F 228 ? -34.23200 93.92500 -58.72700 1.000 30.00000 N ? F ? 10 1 + ATOM 510 CA . MET F 228 ? -33.79600 95.18900 -58.12700 1.000 30.00000 C ? F ? 10 1 + ATOM 511 C . MET F 228 ? -34.46800 96.36100 -58.82800 1.000 30.00000 C ? F ? 10 1 + ATOM 512 O . MET F 228 ? -34.98700 97.28200 -58.17200 1.000 30.00000 O ? F ? 10 1 + ATOM 513 CB . MET F 228 ? -32.26700 95.34400 -58.14900 1.000 30.00000 C ? F ? 10 1 + ATOM 514 CG . MET F 228 ? -31.49900 94.47700 -57.15300 1.000 30.00000 C ? F ? 10 1 + ATOM 515 SD . MET F 228 ? -31.94800 94.67000 -55.40900 1.000 30.00000 S ? F ? 10 1 + ATOM 516 CE . MET F 228 ? -31.79900 96.44100 -55.14600 1.000 30.00000 C ? F ? 10 1 + ATOM 517 N . LEU G 219 ? -70.85700 27.17800 -65.40200 1.000 30.00000 N ? G ? 1 1 + ATOM 518 CA . LEU G 219 ? -71.87700 26.14100 -65.54600 1.000 30.00000 C ? G ? 1 1 + ATOM 519 C . LEU G 219 ? -72.64000 25.90700 -64.24800 1.000 30.00000 C ? G ? 1 1 + ATOM 520 O . LEU G 219 ? -73.84600 25.65600 -64.27500 1.000 30.00000 O ? G ? 1 1 + ATOM 521 CB . LEU G 219 ? -71.24500 24.83700 -66.04400 1.000 30.00000 C ? G ? 1 1 + ATOM 522 CG . LEU G 219 ? -72.21000 23.67600 -66.33400 1.000 30.00000 C ? G ? 1 1 + ATOM 523 CD1 . LEU G 219 ? -71.89300 23.00400 -67.66600 1.000 30.00000 C ? G ? 1 1 + ATOM 524 CD2 . LEU G 219 ? -72.21300 22.65200 -65.20400 1.000 30.00000 C ? G ? 1 1 + ATOM 525 N . ARG G 220 ? -71.93400 25.99300 -63.12200 1.000 30.00000 N ? G ? 2 1 + ATOM 526 CA . ARG G 220 ? -72.54100 25.84200 -61.80600 1.000 30.00000 C ? G ? 2 1 + ATOM 527 C . ARG G 220 ? -73.55800 26.93700 -61.55900 1.000 30.00000 C ? G ? 2 1 + ATOM 528 O . ARG G 220 ? -74.63700 26.66100 -61.01600 1.000 30.00000 O ? G ? 2 1 + ATOM 529 CB . ARG G 220 ? -71.47600 25.86700 -60.70300 1.000 30.00000 C ? G ? 2 1 + ATOM 530 CG . ARG G 220 ? -70.58300 24.63800 -60.66100 1.000 30.00000 C ? G ? 2 1 + ATOM 531 CD . ARG G 220 ? -71.26200 23.46500 -59.96800 1.000 30.00000 C ? G ? 2 1 + ATOM 532 NE . ARG G 220 ? -70.39100 22.29000 -59.89700 1.000 30.00000 N ? G ? 2 1 + ATOM 533 CZ . ARG G 220 ? -69.37600 22.12200 -59.04300 1.000 30.00000 C ? G ? 2 1 + ATOM 534 NH1 . ARG G 220 ? -69.05700 23.05800 -58.14600 1.000 30.00000 N ? G ? 2 1 + ATOM 535 NH2 . ARG G 220 ? -68.66200 20.99700 -59.08800 1.000 30.00000 N ? G ? 2 1 + ATOM 536 N . LEU G 221 ? -73.18800 28.16200 -61.94100 1.000 30.00000 N ? G ? 3 1 + ATOM 537 CA . LEU G 221 ? -74.03900 29.33500 -61.75400 1.000 30.00000 C ? G ? 3 1 + ATOM 538 C . LEU G 221 ? -75.37400 29.13800 -62.45100 1.000 30.00000 C ? G ? 3 1 + ATOM 539 O . LEU G 221 ? -76.44000 29.40900 -61.87000 1.000 30.00000 O ? G ? 3 1 + ATOM 540 CB . LEU G 221 ? -73.38200 30.60100 -62.31200 1.000 30.00000 C ? G ? 3 1 + ATOM 541 CG . LEU G 221 ? -74.10400 31.93200 -62.07100 1.000 30.00000 C ? G ? 3 1 + ATOM 542 CD1 . LEU G 221 ? -74.05600 32.32100 -60.60100 1.000 30.00000 C ? G ? 3 1 + ATOM 543 CD2 . LEU G 221 ? -73.48600 33.02800 -62.92100 1.000 30.00000 C ? G ? 3 1 + ATOM 544 N . GLN G 222 ? -75.28200 28.66400 -63.69100 1.000 30.00000 N ? G ? 4 1 + ATOM 545 CA . GLN G 222 ? -76.46500 28.41100 -64.52600 1.000 30.00000 C ? G ? 4 1 + ATOM 546 C . GLN G 222 ? -77.38800 27.41700 -63.84100 1.000 30.00000 C ? G ? 4 1 + ATOM 547 O . GLN G 222 ? -78.60900 27.62700 -63.77600 1.000 30.00000 O ? G ? 4 1 + ATOM 548 CB . GLN G 222 ? -76.07300 27.87300 -65.90400 1.000 30.00000 C ? G ? 4 1 + ATOM 549 CG . GLN G 222 ? -77.23400 27.72000 -66.87700 1.000 30.00000 C ? G ? 4 1 + ATOM 550 CD . GLN G 222 ? -76.80500 27.11100 -68.19900 1.000 30.00000 C ? G ? 4 1 + ATOM 551 OE1 . GLN G 222 ? -75.73600 27.42400 -68.72600 1.000 30.00000 O ? G ? 4 1 + ATOM 552 NE2 . GLN G 222 ? -77.64200 26.23300 -68.74400 1.000 30.00000 N ? G ? 4 1 + ATOM 553 N . GLN G 223 ? -76.76900 26.35100 -63.33800 1.000 30.00000 N ? G ? 5 1 + ATOM 554 CA . GLN G 223 ? -77.48500 25.27700 -62.63800 1.000 30.00000 C ? G ? 5 1 + ATOM 555 C . GLN G 223 ? -78.24400 25.84400 -61.44700 1.000 30.00000 C ? G ? 5 1 + ATOM 556 O . GLN G 223 ? -79.43200 25.53400 -61.23400 1.000 30.00000 O ? G ? 5 1 + ATOM 557 CB . GLN G 223 ? -76.52500 24.20400 -62.10200 1.000 30.00000 C ? G ? 5 1 + ATOM 558 CG . GLN G 223 ? -76.02000 23.18800 -63.10800 1.000 30.00000 C ? G ? 5 1 + ATOM 559 CD . GLN G 223 ? -75.18500 22.10600 -62.44400 1.000 30.00000 C ? G ? 5 1 + ATOM 560 OE1 . GLN G 223 ? -74.00400 21.94100 -62.75000 1.000 30.00000 O ? G ? 5 1 + ATOM 561 NE2 . GLN G 223 ? -75.79300 21.37200 -61.51600 1.000 30.00000 N ? G ? 5 1 + ATOM 562 N . ALA G 224 ? -77.52900 26.66900 -60.69100 1.000 30.00000 N ? G ? 6 1 + ATOM 563 CA . ALA G 224 ? -78.06600 27.31700 -59.49100 1.000 30.00000 C ? G ? 6 1 + ATOM 564 C . ALA G 224 ? -79.29800 28.14200 -59.85100 1.000 30.00000 C ? G ? 6 1 + ATOM 565 O . ALA G 224 ? -80.33900 28.07000 -59.17600 1.000 30.00000 O ? G ? 6 1 + ATOM 566 CB . ALA G 224 ? -77.01600 28.20300 -58.83000 1.000 30.00000 C ? G ? 6 1 + ATOM 567 N . TYR G 225 ? -79.14200 28.91200 -60.92200 1.000 30.00000 N ? G ? 7 1 + ATOM 568 CA . TYR G 225 ? -80.20700 29.78300 -61.42800 1.000 30.00000 C ? G ? 7 1 + ATOM 569 C . TYR G 225 ? -81.44000 28.97000 -61.77100 1.000 30.00000 C ? G ? 7 1 + ATOM 570 O . TYR G 225 ? -82.56600 29.33900 -61.39800 1.000 30.00000 O ? G ? 7 1 + ATOM 571 CB . TYR G 225 ? -79.77000 30.70600 -62.56600 1.000 30.00000 C ? G ? 7 1 + ATOM 572 CG . TYR G 225 ? -79.48900 32.04100 -61.98500 1.000 30.00000 C ? G ? 7 1 + ATOM 573 CD1 . TYR G 225 ? -80.53900 32.88100 -61.64200 1.000 30.00000 C ? G ? 7 1 + ATOM 574 CD2 . TYR G 225 ? -78.19100 32.43000 -61.67200 1.000 30.00000 C ? G ? 7 1 + ATOM 575 CE1 . TYR G 225 ? -80.30500 34.10100 -61.04800 1.000 30.00000 C ? G ? 7 1 + ATOM 576 CE2 . TYR G 225 ? -77.94100 33.65900 -61.08400 1.000 30.00000 C ? G ? 7 1 + ATOM 577 CZ . TYR G 225 ? -79.00300 34.48800 -60.77400 1.000 30.00000 C ? G ? 7 1 + ATOM 578 OH . TYR G 225 ? -78.77900 35.69700 -60.18100 1.000 30.00000 O ? G ? 7 1 + ATOM 579 N . LEU G 226 ? -81.19400 27.86700 -62.46500 1.000 30.00000 N ? G ? 8 1 + ATOM 580 CA . LEU G 226 ? -82.25200 26.94300 -62.89600 1.000 30.00000 C ? G ? 8 1 + ATOM 581 C . LEU G 226 ? -83.01800 26.43400 -61.68500 1.000 30.00000 C ? G ? 8 1 + ATOM 582 O . LEU G 226 ? -84.26900 26.42200 -61.67900 1.000 30.00000 O ? G ? 8 1 + ATOM 583 CB . LEU G 226 ? -81.70600 25.74000 -63.68300 1.000 30.00000 C ? G ? 8 1 + ATOM 584 CG . LEU G 226 ? -81.87000 25.78600 -65.20200 1.000 30.00000 C ? G ? 8 1 + ATOM 585 CD1 . LEU G 226 ? -80.95900 26.84100 -65.80100 1.000 30.00000 C ? G ? 8 1 + ATOM 586 CD2 . LEU G 226 ? -81.57300 24.42600 -65.82100 1.000 30.00000 C ? G ? 8 1 + ATOM 587 N . ILE G 227 ? -82.24000 26.02300 -60.68000 1.000 30.00000 N ? G ? 9 1 + ATOM 588 CA . ILE G 227 ? -82.81300 25.47500 -59.44300 1.000 30.00000 C ? G ? 9 1 + ATOM 589 C . ILE G 227 ? -83.69900 26.51700 -58.77500 1.000 30.00000 C ? G ? 9 1 + ATOM 590 O . ILE G 227 ? -84.81800 26.19200 -58.33900 1.000 30.00000 O ? G ? 9 1 + ATOM 591 CB . ILE G 227 ? -81.88000 24.70300 -58.46500 1.000 30.00000 C ? G ? 9 1 + ATOM 592 CG1 . ILE G 227 ? -80.81600 25.57900 -57.82600 1.000 30.00000 C ? G ? 9 1 + ATOM 593 CG2 . ILE G 227 ? -81.26500 23.49500 -59.15600 1.000 30.00000 C ? G ? 9 1 + ATOM 594 CD1 . ILE G 227 ? -80.20200 24.97400 -56.58400 1.000 30.00000 C ? G ? 9 1 + ATOM 595 N . MET G 228 ? -83.19200 27.74300 -58.72700 1.000 30.00000 N ? G ? 10 1 + ATOM 596 CA . MET G 228 ? -83.90900 28.87200 -58.12700 1.000 30.00000 C ? G ? 10 1 + ATOM 597 C . MET G 228 ? -85.24400 29.07700 -58.82800 1.000 30.00000 C ? G ? 10 1 + ATOM 598 O . MET G 228 ? -86.28800 29.24600 -58.17200 1.000 30.00000 O ? G ? 10 1 + ATOM 599 CB . MET G 228 ? -83.07600 30.16400 -58.14900 1.000 30.00000 C ? G ? 10 1 + ATOM 600 CG . MET G 228 ? -81.92000 30.22400 -57.15300 1.000 30.00000 C ? G ? 10 1 + ATOM 601 SD . MET G 228 ? -82.35100 29.99300 -55.40900 1.000 30.00000 S ? G ? 10 1 + ATOM 602 CE . MET G 228 ? -83.64200 31.21400 -55.14600 1.000 30.00000 C ? G ? 10 1 + ATOM 603 N . LEU H 219 ? 73.84400 -42.50400 85.40200 1.000 30.00000 N ? H ? 1 1 + ATOM 604 CA . LEU H 219 ? 73.66800 -43.94800 85.54600 1.000 30.00000 C ? H ? 1 1 + ATOM 605 C . LEU H 219 ? 73.96200 -44.69000 84.24800 1.000 30.00000 C ? H ? 1 1 + ATOM 606 O . LEU H 219 ? 74.51700 -45.79000 84.27500 1.000 30.00000 O ? H ? 1 1 + ATOM 607 CB . LEU H 219 ? 72.25500 -44.26700 86.04400 1.000 30.00000 C ? H ? 1 1 + ATOM 608 CG . LEU H 219 ? 71.94900 -45.74600 86.33400 1.000 30.00000 C ? H ? 1 1 + ATOM 609 CD1 . LEU H 219 ? 71.22600 -45.91600 87.66600 1.000 30.00000 C ? H ? 1 1 + ATOM 610 CD2 . LEU H 219 ? 71.15100 -46.38600 85.20400 1.000 30.00000 C ? H ? 1 1 + ATOM 611 N . ARG H 220 ? 73.58800 -44.08500 83.12200 1.000 30.00000 N ? H ? 2 1 + ATOM 612 CA . ARG H 220 ? 73.84900 -44.65400 81.80600 1.000 30.00000 C ? H ? 2 1 + ATOM 613 C . ARG H 220 ? 75.33900 -44.76600 81.55900 1.000 30.00000 C ? H ? 2 1 + ATOM 614 O . ARG H 220 ? 75.79600 -45.78100 81.01600 1.000 30.00000 O ? H ? 2 1 + ATOM 615 CB . ARG H 220 ? 73.20500 -43.80500 80.70300 1.000 30.00000 C ? H ? 2 1 + ATOM 616 CG . ARG H 220 ? 71.68600 -43.87300 80.66100 1.000 30.00000 C ? H ? 2 1 + ATOM 617 CD . ARG H 220 ? 71.19300 -45.13500 79.96800 1.000 30.00000 C ? H ? 2 1 + ATOM 618 NE . ARG H 220 ? 69.73100 -45.18700 79.89700 1.000 30.00000 N ? H ? 2 1 + ATOM 619 CZ . ARG H 220 ? 68.96700 -44.49900 79.04300 1.000 30.00000 C ? H ? 2 1 + ATOM 620 NH1 . ARG H 220 ? 69.50000 -43.66600 78.14600 1.000 30.00000 N ? H ? 2 1 + ATOM 621 NH2 . ARG H 220 ? 67.64300 -44.64200 79.08800 1.000 30.00000 N ? H ? 2 1 + ATOM 622 N . LEU H 221 ? 76.06700 -43.71300 81.94100 1.000 30.00000 N ? H ? 3 1 + ATOM 623 CA . LEU H 221 ? 77.51400 -43.64600 81.75400 1.000 30.00000 C ? H ? 3 1 + ATOM 624 C . LEU H 221 ? 78.19200 -44.81300 82.45100 1.000 30.00000 C ? H ? 3 1 + ATOM 625 O . LEU H 221 ? 79.06800 -45.47800 81.87000 1.000 30.00000 O ? H ? 3 1 + ATOM 626 CB . LEU H 221 ? 78.09400 -42.34400 82.31200 1.000 30.00000 C ? H ? 3 1 + ATOM 627 CG . LEU H 221 ? 79.58500 -42.07800 82.07100 1.000 30.00000 C ? H ? 3 1 + ATOM 628 CD1 . LEU H 221 ? 79.85900 -41.79800 80.60100 1.000 30.00000 C ? H ? 3 1 + ATOM 629 CD2 . LEU H 221 ? 80.05600 -40.91100 82.92100 1.000 30.00000 C ? H ? 3 1 + ATOM 630 N . GLN H 222 ? 77.76500 -45.03700 83.69100 1.000 30.00000 N ? H ? 4 1 + ATOM 631 CA . GLN H 222 ? 78.30400 -46.12000 84.52600 1.000 30.00000 C ? H ? 4 1 + ATOM 632 C . GLN H 222 ? 78.10300 -47.46100 83.84100 1.000 30.00000 C ? H ? 4 1 + ATOM 633 O . GLN H 222 ? 79.02800 -48.28400 83.77600 1.000 30.00000 O ? H ? 4 1 + ATOM 634 CB . GLN H 222 ? 77.63900 -46.14900 85.90400 1.000 30.00000 C ? H ? 4 1 + ATOM 635 CG . GLN H 222 ? 78.24300 -47.15100 86.87700 1.000 30.00000 C ? H ? 4 1 + ATOM 636 CD . GLN H 222 ? 77.50000 -47.19600 88.19900 1.000 30.00000 C ? H ? 4 1 + ATOM 637 OE1 . GLN H 222 ? 77.07700 -46.16500 88.72600 1.000 30.00000 O ? H ? 4 1 + ATOM 638 NE2 . GLN H 222 ? 77.33500 -48.39700 88.74400 1.000 30.00000 N ? H ? 4 1 + ATOM 639 N . GLN H 223 ? 76.88300 -47.64200 83.33800 1.000 30.00000 N ? H ? 5 1 + ATOM 640 CA . GLN H 223 ? 76.49000 -48.87100 82.63800 1.000 30.00000 C ? H ? 5 1 + ATOM 641 C . GLN H 223 ? 77.40600 -49.11100 81.44700 1.000 30.00000 C ? H ? 5 1 + ATOM 642 O . GLN H 223 ? 77.90500 -50.23300 81.23400 1.000 30.00000 O ? H ? 5 1 + ATOM 643 CB . GLN H 223 ? 75.05300 -48.78900 82.10200 1.000 30.00000 C ? H ? 5 1 + ATOM 644 CG . GLN H 223 ? 73.94300 -49.02800 83.10800 1.000 30.00000 C ? H ? 5 1 + ATOM 645 CD . GLN H 223 ? 72.57700 -49.05000 82.44400 1.000 30.00000 C ? H ? 5 1 + ATOM 646 OE1 . GLN H 223 ? 71.71200 -48.23000 82.75000 1.000 30.00000 O ? H ? 5 1 + ATOM 647 NE2 . GLN H 223 ? 72.38200 -49.98300 81.51600 1.000 30.00000 N ? H ? 5 1 + ATOM 648 N . ALA H 224 ? 77.60500 -48.03700 80.69100 1.000 30.00000 N ? H ? 6 1 + ATOM 649 CA . ALA H 224 ? 78.44800 -48.05300 79.49100 1.000 30.00000 C ? H ? 6 1 + ATOM 650 C . ALA H 224 ? 79.86000 -48.50200 79.85100 1.000 30.00000 C ? H ? 6 1 + ATOM 651 O . ALA H 224 ? 80.45300 -49.36000 79.17600 1.000 30.00000 O ? H ? 6 1 + ATOM 652 CB . ALA H 224 ? 78.48500 -46.68000 78.83000 1.000 30.00000 C ? H ? 6 1 + ATOM 653 N . TYR H 225 ? 80.36500 -47.90000 80.92200 1.000 30.00000 N ? H ? 7 1 + ATOM 654 CA . TYR H 225 ? 81.71000 -48.19000 81.42800 1.000 30.00000 C ? H ? 7 1 + ATOM 655 C . TYR H 225 ? 81.84300 -49.66000 81.77100 1.000 30.00000 C ? H ? 7 1 + ATOM 656 O . TYR H 225 ? 82.83300 -50.31100 81.39800 1.000 30.00000 O ? H ? 7 1 + ATOM 657 CB . TYR H 225 ? 82.15900 -47.27300 82.56600 1.000 30.00000 C ? H ? 7 1 + ATOM 658 CG . TYR H 225 ? 83.02700 -46.22000 81.98500 1.000 30.00000 C ? H ? 7 1 + ATOM 659 CD1 . TYR H 225 ? 84.33900 -46.51800 81.64200 1.000 30.00000 C ? H ? 7 1 + ATOM 660 CD2 . TYR H 225 ? 82.52200 -44.96300 81.67200 1.000 30.00000 C ? H ? 7 1 + ATOM 661 CE1 . TYR H 225 ? 85.14700 -45.57400 81.04800 1.000 30.00000 C ? H ? 7 1 + ATOM 662 CE2 . TYR H 225 ? 83.32700 -44.00200 81.08400 1.000 30.00000 C ? H ? 7 1 + ATOM 663 CZ . TYR H 225 ? 84.63700 -44.31500 80.77400 1.000 30.00000 C ? H ? 7 1 + ATOM 664 OH . TYR H 225 ? 85.44300 -43.38600 80.18100 1.000 30.00000 O ? H ? 7 1 + ATOM 665 N . LEU H 226 ? 80.82700 -50.15700 82.46500 1.000 30.00000 N ? H ? 8 1 + ATOM 666 CA . LEU H 226 ? 80.76500 -51.55900 82.89600 1.000 30.00000 C ? H ? 8 1 + ATOM 667 C . LEU H 226 ? 80.84400 -52.47500 81.68500 1.000 30.00000 C ? H ? 8 1 + ATOM 668 O . LEU H 226 ? 81.61500 -53.46000 81.67900 1.000 30.00000 O ? H ? 8 1 + ATOM 669 CB . LEU H 226 ? 79.48300 -51.88300 83.68300 1.000 30.00000 C ? H ? 8 1 + ATOM 670 CG . LEU H 226 ? 79.62200 -51.98200 85.20200 1.000 30.00000 C ? H ? 8 1 + ATOM 671 CD1 . LEU H 226 ? 79.87900 -50.61200 85.80100 1.000 30.00000 C ? H ? 8 1 + ATOM 672 CD2 . LEU H 226 ? 78.37400 -52.59800 85.82100 1.000 30.00000 C ? H ? 8 1 + ATOM 673 N . ILE H 227 ? 80.03800 -52.12300 80.68000 1.000 30.00000 N ? H ? 9 1 + ATOM 674 CA . ILE H 227 ? 79.96600 -52.91300 79.44300 1.000 30.00000 C ? H ? 9 1 + ATOM 675 C . ILE H 227 ? 81.33400 -52.95600 78.77500 1.000 30.00000 C ? H ? 9 1 + ATOM 676 O . ILE H 227 ? 81.77700 -54.03400 78.33900 1.000 30.00000 O ? H ? 9 1 + ATOM 677 CB . ILE H 227 ? 78.78100 -52.66500 78.46500 1.000 30.00000 C ? H ? 9 1 + ATOM 678 CG1 . ILE H 227 ? 78.80300 -51.28700 77.82600 1.000 30.00000 C ? H ? 9 1 + ATOM 679 CG2 . ILE H 227 ? 77.45300 -52.93700 79.15600 1.000 30.00000 C ? H ? 9 1 + ATOM 680 CD1 . ILE H 227 ? 77.94700 -51.18400 76.58400 1.000 30.00000 C ? H ? 9 1 + ATOM 681 N . MET H 228 ? 81.97600 -51.79500 78.72700 1.000 30.00000 N ? H ? 10 1 + ATOM 682 CA . MET H 228 ? 83.30600 -51.65100 78.12700 1.000 30.00000 C ? H ? 10 1 + ATOM 683 C . MET H 228 ? 84.29900 -52.56700 78.82800 1.000 30.00000 C ? H ? 10 1 + ATOM 684 O . MET H 228 ? 85.08100 -53.27800 78.17200 1.000 30.00000 O ? H ? 10 1 + ATOM 685 CB . MET H 228 ? 83.79700 -50.19500 78.14900 1.000 30.00000 C ? H ? 10 1 + ATOM 686 CG . MET H 228 ? 83.12300 -49.25400 77.15300 1.000 30.00000 C ? H ? 10 1 + ATOM 687 SD . MET H 228 ? 83.21100 -49.73400 75.40900 1.000 30.00000 S ? H ? 10 1 + ATOM 688 CE . MET H 228 ? 84.97100 -49.98300 75.14600 1.000 30.00000 C ? H ? 10 1 + ATOM 689 N . LEU I 219 ? 8.75900 -72.65200 85.40200 1.000 30.00000 N ? I ? 1 1 + ATOM 690 CA . LEU I 219 ? 7.52000 -73.41500 85.54600 1.000 30.00000 C ? I ? 1 1 + ATOM 691 C . LEU I 219 ? 7.12300 -74.10700 84.24800 1.000 30.00000 C ? I ? 1 1 + ATOM 692 O . LEU I 219 ? 6.60900 -75.22700 84.27500 1.000 30.00000 O ? I ? 1 1 + ATOM 693 CB . LEU I 219 ? 6.39000 -72.50900 86.04400 1.000 30.00000 C ? I ? 1 1 + ATOM 694 CG . LEU I 219 ? 5.04300 -73.19200 86.33400 1.000 30.00000 C ? I ? 1 1 + ATOM 695 CD1 . LEU I 219 ? 4.45900 -72.73300 87.66600 1.000 30.00000 C ? I ? 1 1 + ATOM 696 CD2 . LEU I 219 ? 4.04500 -72.96700 85.20400 1.000 30.00000 C ? I ? 1 1 + ATOM 697 N . ARG I 220 ? 7.36300 -73.43700 83.12200 1.000 30.00000 N ? I ? 2 1 + ATOM 698 CA . ARG I 220 ? 7.08100 -73.99600 81.80600 1.000 30.00000 C ? I ? 2 1 + ATOM 699 C . ARG I 220 ? 7.92200 -75.23200 81.55900 1.000 30.00000 C ? I ? 2 1 + ATOM 700 O . ARG I 220 ? 7.41300 -76.22100 81.01600 1.000 30.00000 O ? I ? 2 1 + ATOM 701 CB . ARG I 220 ? 7.34300 -72.96300 80.70300 1.000 30.00000 C ? I ? 2 1 + ATOM 702 CG . ARG I 220 ? 6.34300 -71.81900 80.66100 1.000 30.00000 C ? I ? 2 1 + ATOM 703 CD . ARG I 220 ? 5.04900 -72.22000 79.96800 1.000 30.00000 C ? I ? 2 1 + ATOM 704 NE . ARG I 220 ? 4.09700 -71.10900 79.89700 1.000 30.00000 N ? I ? 2 1 + ATOM 705 CZ . ARG I 220 ? 4.15800 -70.08300 79.04300 1.000 30.00000 C ? I ? 2 1 + ATOM 706 NH1 . ARG I 220 ? 5.14200 -69.98000 78.14600 1.000 30.00000 N ? I ? 2 1 + ATOM 707 NH2 . ARG I 220 ? 3.22100 -69.13700 79.08800 1.000 30.00000 N ? I ? 2 1 + ATOM 708 N . LEU I 221 ? 9.20000 -75.14400 81.94100 1.000 30.00000 N ? I ? 3 1 + ATOM 709 CA . LEU I 221 ? 10.15400 -76.23300 81.75400 1.000 30.00000 C ? I ? 3 1 + ATOM 710 C . LEU I 221 ? 9.66400 -77.49100 82.45100 1.000 30.00000 C ? I ? 3 1 + ATOM 711 O . LEU I 221 ? 9.69100 -78.59100 81.87000 1.000 30.00000 O ? I ? 3 1 + ATOM 712 CB . LEU I 221 ? 11.53400 -75.87500 82.31200 1.000 30.00000 C ? I ? 3 1 + ATOM 713 CG . LEU I 221 ? 12.67200 -76.87400 82.07100 1.000 30.00000 C ? I ? 3 1 + ATOM 714 CD1 . LEU I 221 ? 13.06100 -76.91400 80.60100 1.000 30.00000 C ? I ? 3 1 + ATOM 715 CD2 . LEU I 221 ? 13.87700 -76.51600 82.92100 1.000 30.00000 C ? I ? 3 1 + ATOM 716 N . GLN I 222 ? 9.22300 -77.29700 83.69100 1.000 30.00000 N ? I ? 4 1 + ATOM 717 CA . GLN I 222 ? 8.71300 -78.39400 84.52600 1.000 30.00000 C ? I ? 4 1 + ATOM 718 C . GLN I 222 ? 7.53900 -79.07200 83.84100 1.000 30.00000 C ? I ? 4 1 + ATOM 719 O . GLN I 222 ? 7.47200 -80.30900 83.77600 1.000 30.00000 O ? I ? 4 1 + ATOM 720 CB . GLN I 222 ? 8.27600 -77.89200 85.90400 1.000 30.00000 C ? I ? 4 1 + ATOM 721 CG . GLN I 222 ? 7.86800 -78.98900 86.87700 1.000 30.00000 C ? I ? 4 1 + ATOM 722 CD . GLN I 222 ? 7.37000 -78.43600 88.19900 1.000 30.00000 C ? I ? 4 1 + ATOM 723 OE1 . GLN I 222 ? 7.91300 -77.46300 88.72600 1.000 30.00000 O ? I ? 4 1 + ATOM 724 NE2 . GLN I 222 ? 6.32800 -79.05600 88.74400 1.000 30.00000 N ? I ? 4 1 + ATOM 725 N . GLN I 223 ? 6.63700 -78.23200 83.33800 1.000 30.00000 N ? I ? 5 1 + ATOM 726 CA . GLN I 223 ? 5.43000 -78.69000 82.63800 1.000 30.00000 C ? I ? 5 1 + ATOM 727 C . GLN I 223 ? 5.81400 -79.55700 81.44700 1.000 30.00000 C ? I ? 5 1 + ATOM 728 O . GLN I 223 ? 5.24800 -80.64600 81.23400 1.000 30.00000 O ? I ? 5 1 + ATOM 729 CB . GLN I 223 ? 4.59800 -77.51600 82.10200 1.000 30.00000 C ? I ? 5 1 + ATOM 730 CG . GLN I 223 ? 3.72000 -76.79700 83.10800 1.000 30.00000 C ? I ? 5 1 + ATOM 731 CD . GLN I 223 ? 2.85100 -75.74300 82.44400 1.000 30.00000 C ? I ? 5 1 + ATOM 732 OE1 . GLN I 223 ? 2.95300 -74.55500 82.75000 1.000 30.00000 O ? I ? 5 1 + ATOM 733 NE2 . GLN I 223 ? 2.00000 -76.17300 81.51600 1.000 30.00000 N ? I ? 5 1 + ATOM 734 N . ALA I 224 ? 6.77800 -79.04300 80.69100 1.000 30.00000 N ? I ? 6 1 + ATOM 735 CA . ALA I 224 ? 7.29100 -79.71100 79.49100 1.000 30.00000 C ? I ? 6 1 + ATOM 736 C . ALA I 224 ? 7.82100 -81.09500 79.85100 1.000 30.00000 C ? I ? 6 1 + ATOM 737 O . ALA I 224 ? 7.51900 -82.09400 79.17600 1.000 30.00000 O ? I ? 6 1 + ATOM 738 CB . ALA I 224 ? 8.38700 -78.88400 78.83000 1.000 30.00000 C ? I ? 6 1 + ATOM 739 N . TYR I 225 ? 8.60600 -81.11500 80.92200 1.000 30.00000 N ? I ? 7 1 + ATOM 740 CA . TYR I 225 ? 9.21800 -82.34700 81.42800 1.000 30.00000 C ? I ? 7 1 + ATOM 741 C . TYR I 225 ? 8.15200 -83.36800 81.77100 1.000 30.00000 C ? I ? 7 1 + ATOM 742 O . TYR I 225 ? 8.26000 -84.54800 81.39800 1.000 30.00000 O ? I ? 7 1 + ATOM 743 CB . TYR I 225 ? 10.21500 -82.12600 82.56600 1.000 30.00000 C ? I ? 7 1 + ATOM 744 CG . TYR I 225 ? 11.57900 -82.14900 81.98500 1.000 30.00000 C ? I ? 7 1 + ATOM 745 CD1 . TYR I 225 ? 12.16500 -83.36000 81.64200 1.000 30.00000 C ? I ? 7 1 + ATOM 746 CD2 . TYR I 225 ? 12.24800 -80.97000 81.67200 1.000 30.00000 C ? I ? 7 1 + ATOM 747 CE1 . TYR I 225 ? 13.40600 -83.40300 81.04800 1.000 30.00000 C ? I ? 7 1 + ATOM 748 CE2 . TYR I 225 ? 13.50100 -81.00000 81.08400 1.000 30.00000 C ? I ? 7 1 + ATOM 749 CZ . TYR I 225 ? 14.07300 -82.22000 80.77400 1.000 30.00000 C ? I ? 7 1 + ATOM 750 OH . TYR I 225 ? 15.30200 -82.27100 80.18100 1.000 30.00000 O ? I ? 7 1 + ATOM 751 N . LEU I 226 ? 7.13000 -82.88300 82.46500 1.000 30.00000 N ? I ? 8 1 + ATOM 752 CA . LEU I 226 ? 5.99500 -83.70800 82.89600 1.000 30.00000 C ? I ? 8 1 + ATOM 753 C . LEU I 226 ? 5.32800 -84.34200 81.68500 1.000 30.00000 C ? I ? 8 1 + ATOM 754 O . LEU I 226 ? 5.03800 -85.55900 81.67900 1.000 30.00000 O ? I ? 8 1 + ATOM 755 CB . LEU I 226 ? 4.94300 -82.90900 83.68300 1.000 30.00000 C ? I ? 8 1 + ATOM 756 CG . LEU I 226 ? 4.95100 -83.07900 85.20200 1.000 30.00000 C ? I ? 8 1 + ATOM 757 CD1 . LEU I 226 ? 6.18300 -82.42600 85.80100 1.000 30.00000 C ? I ? 8 1 + ATOM 758 CD2 . LEU I 226 ? 3.69200 -82.48700 85.82100 1.000 30.00000 C ? I ? 8 1 + ATOM 759 N . ILE I 227 ? 5.10000 -83.49200 80.68000 1.000 30.00000 N ? I ? 9 1 + ATOM 760 CA . ILE I 227 ? 4.43800 -83.92900 79.44300 1.000 30.00000 C ? I ? 9 1 + ATOM 761 C . ILE I 227 ? 5.25700 -85.02500 78.77500 1.000 30.00000 C ? I ? 9 1 + ATOM 762 O . ILE I 227 ? 4.69100 -86.04400 78.33900 1.000 30.00000 O ? I ? 9 1 + ATOM 763 CB . ILE I 227 ? 3.89300 -82.84700 78.46500 1.000 30.00000 C ? I ? 9 1 + ATOM 764 CG1 . ILE I 227 ? 4.98400 -82.00600 77.82600 1.000 30.00000 C ? I ? 9 1 + ATOM 765 CG2 . ILE I 227 ? 2.85200 -81.97900 79.15600 1.000 30.00000 C ? I ? 9 1 + ATOM 766 CD1 . ILE I 227 ? 4.53100 -81.27300 76.58400 1.000 30.00000 C ? I ? 9 1 + ATOM 767 N . MET I 228 ? 6.56500 -84.80300 78.72700 1.000 30.00000 N ? I ? 10 1 + ATOM 768 CA . MET I 228 ? 7.50700 -85.75300 78.12700 1.000 30.00000 C ? I ? 10 1 + ATOM 769 C . MET I 228 ? 7.41000 -87.10000 78.82800 1.000 30.00000 C ? I ? 10 1 + ATOM 770 O . MET I 228 ? 7.34200 -88.15500 78.17200 1.000 30.00000 O ? I ? 10 1 + ATOM 771 CB . MET I 228 ? 8.95100 -85.22900 78.14900 1.000 30.00000 C ? I ? 10 1 + ATOM 772 CG . MET I 228 ? 9.26700 -84.11500 77.15300 1.000 30.00000 C ? I ? 10 1 + ATOM 773 SD . MET I 228 ? 8.94600 -84.48300 75.40900 1.000 30.00000 S ? I ? 10 1 + ATOM 774 CE . MET I 228 ? 9.84900 -86.01400 75.14600 1.000 30.00000 C ? I ? 10 1 + ATOM 775 N . LEU J 219 ? -55.39500 -40.56200 85.40200 1.000 30.00000 N ? J ? 1 1 + ATOM 776 CA . LEU J 219 ? -56.76400 -40.06900 85.54600 1.000 30.00000 C ? J ? 1 1 + ATOM 777 C . LEU J 219 ? -57.55200 -40.19000 84.24800 1.000 30.00000 C ? J ? 1 1 + ATOM 778 O . LEU J 219 ? -58.74900 -40.48600 84.27500 1.000 30.00000 O ? J ? 1 1 + ATOM 779 CB . LEU J 219 ? -56.76000 -38.62000 86.04400 1.000 30.00000 C ? J ? 1 1 + ATOM 780 CG . LEU J 219 ? -58.13400 -37.99300 86.33400 1.000 30.00000 C ? J ? 1 1 + ATOM 781 CD1 . LEU J 219 ? -58.13900 -37.25000 87.66600 1.000 30.00000 C ? J ? 1 1 + ATOM 782 CD2 . LEU J 219 ? -58.58100 -37.07200 85.20400 1.000 30.00000 C ? J ? 1 1 + ATOM 783 N . ARG J 220 ? -56.87900 -39.96000 83.12200 1.000 30.00000 N ? J ? 2 1 + ATOM 784 CA . ARG J 220 ? -57.49200 -40.08800 81.80600 1.000 30.00000 C ? J ? 2 1 + ATOM 785 C . ARG J 220 ? -57.93300 -41.51600 81.55900 1.000 30.00000 C ? J ? 2 1 + ATOM 786 O . ARG J 220 ? -59.02500 -41.73500 81.01600 1.000 30.00000 O ? J ? 2 1 + ATOM 787 CB . ARG J 220 ? -56.52200 -39.64800 80.70300 1.000 30.00000 C ? J ? 2 1 + ATOM 788 CG . ARG J 220 ? -56.25000 -38.15300 80.66100 1.000 30.00000 C ? J ? 2 1 + ATOM 789 CD . ARG J 220 ? -57.37000 -37.39200 79.96800 1.000 30.00000 C ? J ? 2 1 + ATOM 790 NE . ARG J 220 ? -57.09600 -35.95500 79.89700 1.000 30.00000 N ? J ? 2 1 + ATOM 791 CZ . ARG J 220 ? -56.25500 -35.36300 79.04300 1.000 30.00000 C ? J ? 2 1 + ATOM 792 NH1 . ARG J 220 ? -55.56100 -36.06800 78.14600 1.000 30.00000 N ? J ? 2 1 + ATOM 793 NH2 . ARG J 220 ? -56.10000 -34.04000 79.08800 1.000 30.00000 N ? J ? 2 1 + ATOM 794 N . LEU J 221 ? -57.06800 -42.46000 81.94100 1.000 30.00000 N ? J ? 3 1 + ATOM 795 CA . LEU J 221 ? -57.32500 -43.88500 81.75400 1.000 30.00000 C ? J ? 3 1 + ATOM 796 C . LEU J 221 ? -58.61400 -44.28700 82.45100 1.000 30.00000 C ? J ? 3 1 + ATOM 797 O . LEU J 221 ? -59.45700 -44.99300 81.87000 1.000 30.00000 O ? J ? 3 1 + ATOM 798 CB . LEU J 221 ? -56.18500 -44.74100 82.31200 1.000 30.00000 C ? J ? 3 1 + ATOM 799 CG . LEU J 221 ? -56.25700 -46.25300 82.07100 1.000 30.00000 C ? J ? 3 1 + ATOM 800 CD1 . LEU J 221 ? -56.04500 -46.58300 80.60100 1.000 30.00000 C ? J ? 3 1 + ATOM 801 CD2 . LEU J 221 ? -55.22500 -46.97200 82.92100 1.000 30.00000 C ? J ? 3 1 + ATOM 802 N . GLN J 222 ? -58.73700 -43.82000 83.69100 1.000 30.00000 N ? J ? 4 1 + ATOM 803 CA . GLN J 222 ? -59.91300 -44.10500 84.52600 1.000 30.00000 C ? J ? 4 1 + ATOM 804 C . GLN J 222 ? -61.17500 -43.61100 83.84100 1.000 30.00000 C ? J ? 4 1 + ATOM 805 O . GLN J 222 ? -62.18400 -44.32900 83.77600 1.000 30.00000 O ? J ? 4 1 + ATOM 806 CB . GLN J 222 ? -59.79300 -43.45100 85.90400 1.000 30.00000 C ? J ? 4 1 + ATOM 807 CG . GLN J 222 ? -60.90500 -43.81600 86.87700 1.000 30.00000 C ? J ? 4 1 + ATOM 808 CD . GLN J 222 ? -60.78300 -43.08200 88.19900 1.000 30.00000 C ? J ? 4 1 + ATOM 809 OE1 . GLN J 222 ? -59.68400 -42.89900 88.72600 1.000 30.00000 O ? J ? 4 1 + ATOM 810 NE2 . GLN J 222 ? -61.91800 -42.65400 88.74400 1.000 30.00000 N ? J ? 4 1 + ATOM 811 N . GLN J 223 ? -61.08100 -42.38100 83.33800 1.000 30.00000 N ? J ? 5 1 + ATOM 812 CA . GLN J 223 ? -62.19100 -41.72400 82.63800 1.000 30.00000 C ? J ? 5 1 + ATOM 813 C . GLN J 223 ? -62.62900 -42.56400 81.44700 1.000 30.00000 C ? J ? 5 1 + ATOM 814 O . GLN J 223 ? -63.83400 -42.80100 81.23400 1.000 30.00000 O ? J ? 5 1 + ATOM 815 CB . GLN J 223 ? -61.79200 -40.34100 82.10200 1.000 30.00000 C ? J ? 5 1 + ATOM 816 CG . GLN J 223 ? -61.77800 -39.20600 83.10800 1.000 30.00000 C ? J ? 5 1 + ATOM 817 CD . GLN J 223 ? -61.49500 -37.86900 82.44400 1.000 30.00000 C ? J ? 5 1 + ATOM 818 OE1 . GLN J 223 ? -60.50300 -37.20800 82.75000 1.000 30.00000 O ? J ? 5 1 + ATOM 819 NE2 . GLN J 223 ? -62.36200 -37.47200 81.51600 1.000 30.00000 N ? J ? 5 1 + ATOM 820 N . ALA J 224 ? -61.62700 -42.99700 80.69100 1.000 30.00000 N ? J ? 6 1 + ATOM 821 CA . ALA J 224 ? -61.83000 -43.81500 79.49100 1.000 30.00000 C ? J ? 6 1 + ATOM 822 C . ALA J 224 ? -62.58100 -45.09200 79.85100 1.000 30.00000 C ? J ? 6 1 + ATOM 823 O . ALA J 224 ? -63.55000 -45.47900 79.17600 1.000 30.00000 O ? J ? 6 1 + ATOM 824 CB . ALA J 224 ? -60.50000 -44.15700 78.83000 1.000 30.00000 C ? J ? 6 1 + ATOM 825 N . TYR J 225 ? -62.10700 -45.71800 80.92200 1.000 30.00000 N ? J ? 7 1 + ATOM 826 CA . TYR J 225 ? -62.68900 -46.96500 81.42800 1.000 30.00000 C ? J ? 7 1 + ATOM 827 C . TYR J 225 ? -64.15200 -46.76800 81.77100 1.000 30.00000 C ? J ? 7 1 + ATOM 828 O . TYR J 225 ? -65.00700 -47.58800 81.39800 1.000 30.00000 O ? J ? 7 1 + ATOM 829 CB . TYR J 225 ? -61.89500 -47.60700 82.56600 1.000 30.00000 C ? J ? 7 1 + ATOM 830 CG . TYR J 225 ? -61.06200 -48.68800 81.98500 1.000 30.00000 C ? J ? 7 1 + ATOM 831 CD1 . TYR J 225 ? -61.64400 -49.90000 81.64200 1.000 30.00000 C ? J ? 7 1 + ATOM 832 CD2 . TYR J 225 ? -59.72300 -48.47500 81.67200 1.000 30.00000 C ? J ? 7 1 + ATOM 833 CE1 . TYR J 225 ? -60.90300 -50.89800 81.04800 1.000 30.00000 C ? J ? 7 1 + ATOM 834 CE2 . TYR J 225 ? -58.96500 -49.47400 81.08400 1.000 30.00000 C ? J ? 7 1 + ATOM 835 CZ . TYR J 225 ? -59.56200 -50.68200 80.77400 1.000 30.00000 C ? J ? 7 1 + ATOM 836 OH . TYR J 225 ? -58.83600 -51.67400 80.18100 1.000 30.00000 O ? J ? 7 1 + ATOM 837 N . LEU J 226 ? -64.41000 -45.66700 82.46500 1.000 30.00000 N ? J ? 8 1 + ATOM 838 CA . LEU J 226 ? -65.76300 -45.29400 82.89600 1.000 30.00000 C ? J ? 8 1 + ATOM 839 C . LEU J 226 ? -66.67400 -45.16700 81.68500 1.000 30.00000 C ? J ? 8 1 + ATOM 840 O . LEU J 226 ? -67.80600 -45.70000 81.67900 1.000 30.00000 O ? J ? 8 1 + ATOM 841 CB . LEU J 226 ? -65.79400 -43.97300 83.68300 1.000 30.00000 C ? J ? 8 1 + ATOM 842 CG . LEU J 226 ? -65.92100 -44.08600 85.20200 1.000 30.00000 C ? J ? 8 1 + ATOM 843 CD1 . LEU J 226 ? -64.64300 -44.64100 85.80100 1.000 30.00000 C ? J ? 8 1 + ATOM 844 CD2 . LEU J 226 ? -66.24400 -42.73200 85.82100 1.000 30.00000 C ? J ? 8 1 + ATOM 845 N . ILE J 227 ? -66.15200 -44.46000 80.68000 1.000 30.00000 N ? J ? 9 1 + ATOM 846 CA . ILE J 227 ? -66.90600 -44.21400 79.44300 1.000 30.00000 C ? J ? 9 1 + ATOM 847 C . ILE J 227 ? -67.25200 -45.53800 78.77500 1.000 30.00000 C ? J ? 9 1 + ATOM 848 O . ILE J 227 ? -68.40200 -45.73000 78.33900 1.000 30.00000 O ? J ? 9 1 + ATOM 849 CB . ILE J 227 ? -66.40000 -43.11400 78.46500 1.000 30.00000 C ? J ? 9 1 + ATOM 850 CG1 . ILE J 227 ? -65.06200 -43.44200 77.82600 1.000 30.00000 C ? J ? 9 1 + ATOM 851 CG2 . ILE J 227 ? -66.37000 -41.75800 79.15600 1.000 30.00000 C ? J ? 9 1 + ATOM 852 CD1 . ILE J 227 ? -64.77100 -42.63100 76.58400 1.000 30.00000 C ? J ? 9 1 + ATOM 853 N . MET J 228 ? -66.26300 -46.42300 78.72700 1.000 30.00000 N ? J ? 10 1 + ATOM 854 CA . MET J 228 ? -66.41900 -47.75100 78.12700 1.000 30.00000 C ? J ? 10 1 + ATOM 855 C . MET J 228 ? -67.53300 -48.51500 78.82800 1.000 30.00000 C ? J ? 10 1 + ATOM 856 O . MET J 228 ? -68.40000 -49.12000 78.17200 1.000 30.00000 O ? J ? 10 1 + ATOM 857 CB . MET J 228 ? -65.10800 -48.55400 78.14900 1.000 30.00000 C ? J ? 10 1 + ATOM 858 CG . MET J 228 ? -64.04000 -48.10600 77.15300 1.000 30.00000 C ? J ? 10 1 + ATOM 859 SD . MET J 228 ? -64.52900 -48.08500 75.40900 1.000 30.00000 S ? J ? 10 1 + ATOM 860 CE . MET J 228 ? -65.16300 -49.74500 75.14600 1.000 30.00000 C ? J ? 10 1 + ATOM 861 N . LEU K 219 ? -70.30100 29.60200 85.40200 1.000 30.00000 N ? K ? 1 1 + ATOM 862 CA . LEU K 219 ? -70.76900 30.98000 85.54600 1.000 30.00000 C ? K ? 1 1 + ATOM 863 C . LEU K 219 ? -71.35500 31.52100 84.24800 1.000 30.00000 C ? K ? 1 1 + ATOM 864 O . LEU K 219 ? -72.33300 32.27100 84.27500 1.000 30.00000 O ? K ? 1 1 + ATOM 865 CB . LEU K 219 ? -69.63400 31.88000 86.04400 1.000 30.00000 C ? K ? 1 1 + ATOM 866 CG . LEU K 219 ? -70.00000 33.34500 86.33400 1.000 30.00000 C ? K ? 1 1 + ATOM 867 CD1 . LEU K 219 ? -69.42300 33.81200 87.66600 1.000 30.00000 C ? K ? 1 1 + ATOM 868 CD2 . LEU K 219 ? -69.55900 34.26800 85.20400 1.000 30.00000 C ? K ? 1 1 + ATOM 869 N . ARG K 220 ? -70.75600 31.13800 83.12200 1.000 30.00000 N ? K ? 2 1 + ATOM 870 CA . ARG K 220 ? -71.23800 31.53700 81.80600 1.000 30.00000 C ? K ? 2 1 + ATOM 871 C . ARG K 220 ? -72.62900 30.99200 81.55900 1.000 30.00000 C ? K ? 2 1 + ATOM 872 O . ARG K 220 ? -73.48100 31.70800 81.01600 1.000 30.00000 O ? K ? 2 1 + ATOM 873 CB . ARG K 220 ? -70.28900 31.05200 80.70300 1.000 30.00000 C ? K ? 2 1 + ATOM 874 CG . ARG K 220 ? -68.95100 31.77200 80.66100 1.000 30.00000 C ? K ? 2 1 + ATOM 875 CD . ARG K 220 ? -69.05400 33.12300 79.96800 1.000 30.00000 C ? K ? 2 1 + ATOM 876 NE . ARG K 220 ? -67.75900 33.80400 79.89700 1.000 30.00000 N ? K ? 2 1 + ATOM 877 CZ . ARG K 220 ? -66.77300 33.51600 79.04300 1.000 30.00000 C ? K ? 2 1 + ATOM 878 NH1 . ARG K 220 ? -66.89100 32.53400 78.14600 1.000 30.00000 N ? K ? 2 1 + ATOM 879 NH2 . ARG K 220 ? -65.64200 34.21900 79.08800 1.000 30.00000 N ? K ? 2 1 + ATOM 880 N . LEU K 221 ? -72.82800 29.72700 81.94100 1.000 30.00000 N ? K ? 3 1 + ATOM 881 CA . LEU K 221 ? -74.10300 29.03900 81.75400 1.000 30.00000 C ? K ? 3 1 + ATOM 882 C . LEU K 221 ? -75.22000 29.79700 82.45100 1.000 30.00000 C ? K ? 3 1 + ATOM 883 O . LEU K 221 ? -76.29800 30.01500 81.87000 1.000 30.00000 O ? K ? 3 1 + ATOM 884 CB . LEU K 221 ? -74.06000 27.61400 82.31200 1.000 30.00000 C ? K ? 3 1 + ATOM 885 CG . LEU K 221 ? -75.28800 26.72800 82.07100 1.000 30.00000 C ? K ? 3 1 + ATOM 886 CD1 . LEU K 221 ? -75.41300 26.35600 80.60100 1.000 30.00000 C ? K ? 3 1 + ATOM 887 CD2 . LEU K 221 ? -75.20700 25.47200 82.92100 1.000 30.00000 C ? K ? 3 1 + ATOM 888 N . GLN K 222 ? -74.93200 30.18300 83.69100 1.000 30.00000 N ? K ? 4 1 + ATOM 889 CA . GLN K 222 ? -75.88800 30.92500 84.52600 1.000 30.00000 C ? K ? 4 1 + ATOM 890 C . GLN K 222 ? -76.28800 32.22000 83.84100 1.000 30.00000 C ? K ? 4 1 + ATOM 891 O . GLN K 222 ? -77.47900 32.56100 83.77600 1.000 30.00000 O ? K ? 4 1 + ATOM 892 CB . GLN K 222 ? -75.30100 31.24000 85.90400 1.000 30.00000 C ? K ? 4 1 + ATOM 893 CG . GLN K 222 ? -76.28100 31.88100 86.87700 1.000 30.00000 C ? K ? 4 1 + ATOM 894 CD . GLN K 222 ? -75.63000 32.24400 88.19900 1.000 30.00000 C ? K ? 4 1 + ATOM 895 OE1 . GLN K 222 ? -74.80200 31.49800 88.72600 1.000 30.00000 O ? K ? 4 1 + ATOM 896 NE2 . GLN K 222 ? -76.00300 33.39700 88.74400 1.000 30.00000 N ? K ? 4 1 + ATOM 897 N . GLN K 223 ? -75.26800 32.91300 83.33800 1.000 30.00000 N ? K ? 5 1 + ATOM 898 CA . GLN K 223 ? -75.44700 34.19100 82.63800 1.000 30.00000 C ? K ? 5 1 + ATOM 899 C . GLN K 223 ? -76.37700 34.01000 81.44700 1.000 30.00000 C ? K ? 5 1 + ATOM 900 O . GLN K 223 ? -77.31300 34.80400 81.23400 1.000 30.00000 O ? K ? 5 1 + ATOM 901 CB . GLN K 223 ? -74.11700 34.74100 82.10200 1.000 30.00000 C ? K ? 5 1 + ATOM 902 CG . GLN K 223 ? -73.22100 35.43800 83.10800 1.000 30.00000 C ? K ? 5 1 + ATOM 903 CD . GLN K 223 ? -71.99900 36.05000 82.44400 1.000 30.00000 C ? K ? 5 1 + ATOM 904 OE1 . GLN K 223 ? -70.86400 35.68600 82.75000 1.000 30.00000 O ? K ? 5 1 + ATOM 905 NE2 . GLN K 223 ? -72.22900 36.97500 81.51600 1.000 30.00000 N ? K ? 5 1 + ATOM 906 N . ALA K 224 ? -76.09000 32.95600 80.69100 1.000 30.00000 N ? K ? 6 1 + ATOM 907 CA . ALA K 224 ? -76.85600 32.60500 79.49100 1.000 30.00000 C ? K ? 6 1 + ATOM 908 C . ALA K 224 ? -78.32300 32.39600 79.85100 1.000 30.00000 C ? K ? 6 1 + ATOM 909 O . ALA K 224 ? -79.23000 32.91200 79.17600 1.000 30.00000 O ? K ? 6 1 + ATOM 910 CB . ALA K 224 ? -76.29400 31.35100 78.83000 1.000 30.00000 C ? K ? 6 1 + ATOM 911 N . TYR K 225 ? -78.51700 31.63500 80.92200 1.000 30.00000 N ? K ? 7 1 + ATOM 912 CA . TYR K 225 ? -79.85400 31.31200 81.42800 1.000 30.00000 C ? K ? 7 1 + ATOM 913 C . TYR K 225 ? -80.61200 32.57900 81.77100 1.000 30.00000 C ? K ? 7 1 + ATOM 914 O . TYR K 225 ? -81.78700 32.73600 81.39800 1.000 30.00000 O ? K ? 7 1 + ATOM 915 CB . TYR K 225 ? -79.86100 30.29100 82.56600 1.000 30.00000 C ? K ? 7 1 + ATOM 916 CG . TYR K 225 ? -80.18700 28.96600 81.98500 1.000 30.00000 C ? K ? 7 1 + ATOM 917 CD1 . TYR K 225 ? -81.49700 28.66500 81.64200 1.000 30.00000 C ? K ? 7 1 + ATOM 918 CD2 . TYR K 225 ? -79.18600 28.05200 81.67200 1.000 30.00000 C ? K ? 7 1 + ATOM 919 CE1 . TYR K 225 ? -81.81600 27.46400 81.04800 1.000 30.00000 C ? K ? 7 1 + ATOM 920 CE2 . TYR K 225 ? -79.49500 26.83700 81.08400 1.000 30.00000 C ? K ? 7 1 + ATOM 921 CZ . TYR K 225 ? -80.81100 26.55100 80.77400 1.000 30.00000 C ? K ? 7 1 + ATOM 922 OH . TYR K 225 ? -81.13400 25.36500 80.18100 1.000 30.00000 O ? K ? 7 1 + ATOM 923 N . LEU K 226 ? -79.91200 33.46700 82.46500 1.000 30.00000 N ? K ? 8 1 + ATOM 924 CA . LEU K 226 ? -80.46400 34.75700 82.89600 1.000 30.00000 C ? K ? 8 1 + ATOM 925 C . LEU K 226 ? -80.93300 35.54900 81.68500 1.000 30.00000 C ? K ? 8 1 + ATOM 926 O . LEU K 226 ? -82.05500 36.10200 81.67900 1.000 30.00000 O ? K ? 8 1 + ATOM 927 CB . LEU K 226 ? -79.45100 35.60500 83.68300 1.000 30.00000 C ? K ? 8 1 + ATOM 928 CG . LEU K 226 ? -79.61800 35.63500 85.20200 1.000 30.00000 C ? K ? 8 1 + ATOM 929 CD1 . LEU K 226 ? -79.25600 34.28900 85.80100 1.000 30.00000 C ? K ? 8 1 + ATOM 930 CD2 . LEU K 226 ? -78.76100 36.73100 85.82100 1.000 30.00000 C ? K ? 8 1 + ATOM 931 N . ILE K 227 ? -80.05500 35.58100 80.68000 1.000 30.00000 N ? K ? 9 1 + ATOM 932 CA . ILE K 227 ? -80.33300 36.32400 79.44300 1.000 30.00000 C ? K ? 9 1 + ATOM 933 C . ILE K 227 ? -81.58400 35.77000 78.77500 1.000 30.00000 C ? K ? 9 1 + ATOM 934 O . ILE K 227 ? -82.45100 36.54800 78.33900 1.000 30.00000 O ? K ? 9 1 + ATOM 935 CB . ILE K 227 ? -79.15700 36.61500 78.46500 1.000 30.00000 C ? K ? 9 1 + ATOM 936 CG1 . ILE K 227 ? -78.57900 35.36400 77.82600 1.000 30.00000 C ? K ? 9 1 + ATOM 937 CG2 . ILE K 227 ? -78.07900 37.43600 79.15600 1.000 30.00000 C ? K ? 9 1 + ATOM 938 CD1 . ILE K 227 ? -77.76400 35.64300 76.58400 1.000 30.00000 C ? K ? 9 1 + ATOM 939 N . MET K 228 ? -81.65900 34.44500 78.72700 1.000 30.00000 N ? K ? 10 1 + ATOM 940 CA . MET K 228 ? -82.79400 33.73900 78.12700 1.000 30.00000 C ? K ? 10 1 + ATOM 941 C . MET K 228 ? -84.08600 34.13300 78.82800 1.000 30.00000 C ? K ? 10 1 + ATOM 942 O . MET K 228 ? -85.09900 34.43400 78.17200 1.000 30.00000 O ? K ? 10 1 + ATOM 943 CB . MET K 228 ? -82.60500 32.21400 78.14900 1.000 30.00000 C ? K ? 10 1 + ATOM 944 CG . MET K 228 ? -81.58900 31.65800 77.15300 1.000 30.00000 C ? K ? 10 1 + ATOM 945 SD . MET K 228 ? -81.87700 32.05300 75.40900 1.000 30.00000 S ? K ? 10 1 + ATOM 946 CE . MET K 228 ? -83.57000 31.51300 75.14600 1.000 30.00000 C ? K ? 10 1 + ATOM 947 N . LEU L 219 ? -24.74100 85.00300 85.40200 1.000 30.00000 N ? L ? 1 1 + ATOM 948 CA . LEU L 219 ? -23.95600 86.22800 85.54600 1.000 30.00000 C ? L ? 1 1 + ATOM 949 C . LEU L 219 ? -23.89800 87.02400 84.24800 1.000 30.00000 C ? L ? 1 1 + ATOM 950 O . LEU L 219 ? -23.92100 88.25500 84.27500 1.000 30.00000 O ? L ? 1 1 + ATOM 951 CB . LEU L 219 ? -22.54400 85.90200 86.04400 1.000 30.00000 C ? L ? 1 1 + ATOM 952 CG . LEU L 219 ? -21.62700 87.10200 86.33400 1.000 30.00000 C ? L ? 1 1 + ATOM 953 CD1 . LEU L 219 ? -20.90200 86.94100 87.66600 1.000 30.00000 C ? L ? 1 1 + ATOM 954 CD2 . LEU L 219 ? -20.63000 87.33200 85.20400 1.000 30.00000 C ? L ? 1 1 + ATOM 955 N . ARG L 220 ? -23.82400 86.31600 83.12200 1.000 30.00000 N ? L ? 2 1 + ATOM 956 CA . ARG L 220 ? -23.81200 86.94200 81.80600 1.000 30.00000 C ? L ? 2 1 + ATOM 957 C . ARG L 220 ? -25.10600 87.69000 81.55900 1.000 30.00000 C ? L ? 2 1 + ATOM 958 O . ARG L 220 ? -25.07700 88.80300 81.01600 1.000 30.00000 O ? L ? 2 1 + ATOM 959 CB . ARG L 220 ? -23.60000 85.89800 80.70300 1.000 30.00000 C ? L ? 2 1 + ATOM 960 CG . ARG L 220 ? -22.20300 85.30100 80.66100 1.000 30.00000 C ? L ? 2 1 + ATOM 961 CD . ARG L 220 ? -21.21100 86.22300 79.96800 1.000 30.00000 C ? L ? 2 1 + ATOM 962 NE . ARG L 220 ? -19.87100 85.63600 79.89700 1.000 30.00000 N ? L ? 2 1 + ATOM 963 CZ . ARG L 220 ? -19.48100 84.68400 79.04300 1.000 30.00000 C ? L ? 2 1 + ATOM 964 NH1 . ARG L 220 ? -20.32300 84.16500 78.14600 1.000 30.00000 N ? L ? 2 1 + ATOM 965 NH2 . ARG L 220 ? -18.22700 84.23900 79.08800 1.000 30.00000 N ? L ? 2 1 + ATOM 966 N . LEU L 221 ? -26.21900 87.05700 81.94100 1.000 30.00000 N ? L ? 3 1 + ATOM 967 CA . LEU L 221 ? -27.55100 87.62400 81.75400 1.000 30.00000 C ? L ? 3 1 + ATOM 968 C . LEU L 221 ? -27.65600 88.97000 82.45100 1.000 30.00000 C ? L ? 3 1 + ATOM 969 O . LEU L 221 ? -28.15700 89.94900 81.87000 1.000 30.00000 O ? L ? 3 1 + ATOM 970 CB . LEU L 221 ? -28.63900 86.70300 82.31200 1.000 30.00000 C ? L ? 3 1 + ATOM 971 CG . LEU L 221 ? -30.09800 87.11000 82.07100 1.000 30.00000 C ? L ? 3 1 + ATOM 972 CD1 . LEU L 221 ? -30.46600 86.97600 80.60100 1.000 30.00000 C ? L ? 3 1 + ATOM 973 CD2 . LEU L 221 ? -31.02800 86.26400 82.92100 1.000 30.00000 C ? L ? 3 1 + ATOM 974 N . GLN L 222 ? -27.17400 88.98600 83.69100 1.000 30.00000 N ? L ? 4 1 + ATOM 975 CA . GLN L 222 ? -27.19000 90.19600 84.52600 1.000 30.00000 C ? L ? 4 1 + ATOM 976 C . GLN L 222 ? -26.42700 91.31700 83.84100 1.000 30.00000 C ? L ? 4 1 + ATOM 977 O . GLN L 222 ? -26.90300 92.46000 83.77600 1.000 30.00000 O ? L ? 4 1 + ATOM 978 CB . GLN L 222 ? -26.57800 89.93300 85.90400 1.000 30.00000 C ? L ? 4 1 + ATOM 979 CG . GLN L 222 ? -26.68800 91.09900 86.87700 1.000 30.00000 C ? L ? 4 1 + ATOM 980 CD . GLN L 222 ? -25.99800 90.81600 88.19900 1.000 30.00000 C ? L ? 4 1 + ATOM 981 OE1 . GLN L 222 ? -26.06500 89.70400 88.72600 1.000 30.00000 O ? L ? 4 1 + ATOM 982 NE2 . GLN L 222 ? -25.32900 91.82700 88.74400 1.000 30.00000 N ? L ? 4 1 + ATOM 983 N . GLN L 223 ? -25.24900 90.95100 83.33800 1.000 30.00000 N ? L ? 5 1 + ATOM 984 CA . GLN L 223 ? -24.36200 91.88700 82.63800 1.000 30.00000 C ? L ? 5 1 + ATOM 985 C . GLN L 223 ? -25.08300 92.50100 81.44700 1.000 30.00000 C ? L ? 5 1 + ATOM 986 O . GLN L 223 ? -25.04600 93.72900 81.23400 1.000 30.00000 O ? L ? 5 1 + ATOM 987 CB . GLN L 223 ? -23.10300 91.19000 82.10200 1.000 30.00000 C ? L ? 5 1 + ATOM 988 CG . GLN L 223 ? -21.99900 90.92400 83.10800 1.000 30.00000 C ? L ? 5 1 + ATOM 989 CD . GLN L 223 ? -20.75900 90.35100 82.44400 1.000 30.00000 C ? L ? 5 1 + ATOM 990 OE1 . GLN L 223 ? -20.33500 89.23700 82.75000 1.000 30.00000 O ? L ? 5 1 + ATOM 991 NE2 . GLN L 223 ? -20.17900 91.10700 81.51600 1.000 30.00000 N ? L ? 5 1 + ATOM 992 N . ALA L 224 ? -25.72800 91.62000 80.69100 1.000 30.00000 N ? L ? 6 1 + ATOM 993 CA . ALA L 224 ? -26.48000 92.00000 79.49100 1.000 30.00000 C ? L ? 6 1 + ATOM 994 C . ALA L 224 ? -27.55800 93.01700 79.85100 1.000 30.00000 C ? L ? 6 1 + ATOM 995 O . ALA L 224 ? -27.72000 94.04800 79.17600 1.000 30.00000 O ? L ? 6 1 + ATOM 996 CB . ALA L 224 ? -27.11000 90.77900 78.83000 1.000 30.00000 C ? L ? 6 1 + ATOM 997 N . TYR L 225 ? -28.27400 92.69400 80.92200 1.000 30.00000 N ? L ? 7 1 + ATOM 998 CA . TYR L 225 ? -29.36000 93.53800 81.42800 1.000 30.00000 C ? L ? 7 1 + ATOM 999 C . TYR L 225 ? -28.84200 94.92100 81.77100 1.000 30.00000 C ? L ? 7 1 + ATOM 1000 O . TYR L 225 ? -29.45200 95.93700 81.39800 1.000 30.00000 O ? L ? 7 1 + ATOM 1001 CB . TYR L 225 ? -30.16300 92.90700 82.56600 1.000 30.00000 C ? L ? 7 1 + ATOM 1002 CG . TYR L 225 ? -31.40200 92.33600 81.98500 1.000 30.00000 C ? L ? 7 1 + ATOM 1003 CD1 . TYR L 225 ? -32.45400 93.17300 81.64200 1.000 30.00000 C ? L ? 7 1 + ATOM 1004 CD2 . TYR L 225 ? -31.49300 90.98300 81.67200 1.000 30.00000 C ? L ? 7 1 + ATOM 1005 CE1 . TYR L 225 ? -33.59200 92.67300 81.04800 1.000 30.00000 C ? L ? 7 1 + ATOM 1006 CE2 . TYR L 225 ? -32.63500 90.46700 81.08400 1.000 30.00000 C ? L ? 7 1 + ATOM 1007 CZ . TYR L 225 ? -33.67900 91.31800 80.77400 1.000 30.00000 C ? L ? 7 1 + ATOM 1008 OH . TYR L 225 ? -34.80800 90.83000 80.18100 1.000 30.00000 O ? L ? 7 1 + ATOM 1009 N . LEU L 226 ? -27.71200 94.92700 82.46500 1.000 30.00000 N ? L ? 8 1 + ATOM 1010 CA . LEU L 226 ? -27.04700 96.16300 82.89600 1.000 30.00000 C ? L ? 8 1 + ATOM 1011 C . LEU L 226 ? -26.72100 97.02300 81.68500 1.000 30.00000 C ? L ? 8 1 + ATOM 1012 O . LEU L 226 ? -26.98800 98.24600 81.67900 1.000 30.00000 O ? L ? 8 1 + ATOM 1013 CB . LEU L 226 ? -25.75200 95.90000 83.68300 1.000 30.00000 C ? L ? 8 1 + ATOM 1014 CG . LEU L 226 ? -25.83400 96.04900 85.20200 1.000 30.00000 C ? L ? 8 1 + ATOM 1015 CD1 . LEU L 226 ? -26.66000 94.92600 85.80100 1.000 30.00000 C ? L ? 8 1 + ATOM 1016 CD2 . LEU L 226 ? -24.44200 96.06200 85.82100 1.000 30.00000 C ? L ? 8 1 + ATOM 1017 N . ILE L 227 ? -26.14700 96.35700 80.68000 1.000 30.00000 N ? L ? 9 1 + ATOM 1018 CA . ILE L 227 ? -25.74000 97.03700 79.44300 1.000 30.00000 C ? L ? 9 1 + ATOM 1019 C . ILE L 227 ? -26.95400 97.67000 78.77500 1.000 30.00000 C ? L ? 9 1 + ATOM 1020 O . ILE L 227 ? -26.88500 98.83300 78.33900 1.000 30.00000 O ? L ? 9 1 + ATOM 1021 CB . ILE L 227 ? -24.78000 96.29900 78.46500 1.000 30.00000 C ? L ? 9 1 + ATOM 1022 CG1 . ILE L 227 ? -25.39700 95.06800 77.82600 1.000 30.00000 C ? L ? 9 1 + ATOM 1023 CG2 . ILE L 227 ? -23.46500 95.96900 79.15600 1.000 30.00000 C ? L ? 9 1 + ATOM 1024 CD1 . ILE L 227 ? -24.67100 94.60400 76.58400 1.000 30.00000 C ? L ? 9 1 + ATOM 1025 N . MET L 228 ? -28.03600 96.90200 78.72700 1.000 30.00000 N ? L ? 10 1 + ATOM 1026 CA . MET L 228 ? -29.29600 97.34900 78.12700 1.000 30.00000 C ? L ? 10 1 + ATOM 1027 C . MET L 228 ? -29.79300 98.60500 78.82800 1.000 30.00000 C ? L ? 10 1 + ATOM 1028 O . MET L 228 ? -30.19000 99.58500 78.17200 1.000 30.00000 O ? L ? 10 1 + ATOM 1029 CB . MET L 228 ? -30.37100 96.25100 78.14900 1.000 30.00000 C ? L ? 10 1 + ATOM 1030 CG . MET L 228 ? -30.17200 95.11000 77.15300 1.000 30.00000 C ? L ? 10 1 + ATOM 1031 SD . MET L 228 ? -30.04300 95.58100 75.40900 1.000 30.00000 S ? L ? 10 1 + ATOM 1032 CE . MET L 228 ? -31.52000 96.56900 75.14600 1.000 30.00000 C ? L ? 10 1 + ATOM 1033 N . LEU M 219 ? 46.98500 83.92900 85.40200 1.000 30.00000 N ? M ? 1 1 + ATOM 1034 CA . LEU M 219 ? 48.43200 84.07900 85.54600 1.000 30.00000 C ? M ? 1 1 + ATOM 1035 C . LEU M 219 ? 49.09000 84.53000 84.24800 1.000 30.00000 C ? M ? 1 1 + ATOM 1036 O . LEU M 219 ? 50.03900 85.31600 84.27500 1.000 30.00000 O ? M ? 1 1 + ATOM 1037 CB . LEU M 219 ? 49.05700 82.77200 86.04400 1.000 30.00000 C ? M ? 1 1 + ATOM 1038 CG . LEU M 219 ? 50.56700 82.80300 86.33400 1.000 30.00000 C ? M ? 1 1 + ATOM 1039 CD1 . LEU M 219 ? 50.89400 82.13600 87.66600 1.000 30.00000 C ? M ? 1 1 + ATOM 1040 CD2 . LEU M 219 ? 51.36900 82.16700 85.20400 1.000 30.00000 C ? M ? 1 1 + ATOM 1041 N . ARG M 220 ? 48.58300 84.03100 83.12200 1.000 30.00000 N ? M ? 2 1 + ATOM 1042 CA . ARG M 220 ? 49.08000 84.41200 81.80600 1.000 30.00000 C ? M ? 2 1 + ATOM 1043 C . ARG M 220 ? 48.85800 85.89000 81.55900 1.000 30.00000 C ? M ? 2 1 + ATOM 1044 O . ARG M 220 ? 49.74600 86.56100 81.01600 1.000 30.00000 O ? M ? 2 1 + ATOM 1045 CB . ARG M 220 ? 48.39600 83.59500 80.70300 1.000 30.00000 C ? M ? 2 1 + ATOM 1046 CG . ARG M 220 ? 48.80000 82.13000 80.66100 1.000 30.00000 C ? M ? 2 1 + ATOM 1047 CD . ARG M 220 ? 50.14000 81.93000 79.96800 1.000 30.00000 C ? M ? 2 1 + ATOM 1048 NE . ARG M 220 ? 50.51600 80.51600 79.89700 1.000 30.00000 N ? M ? 2 1 + ATOM 1049 CZ . ARG M 220 ? 50.01500 79.61800 79.04300 1.000 30.00000 C ? M ? 2 1 + ATOM 1050 NH1 . ARG M 220 ? 49.08400 79.95200 78.14600 1.000 30.00000 N ? M ? 2 1 + ATOM 1051 NH2 . ARG M 220 ? 50.44900 78.35900 79.08800 1.000 30.00000 N ? M ? 2 1 + ATOM 1052 N . LEU M 221 ? 47.66900 86.36500 81.94100 1.000 30.00000 N ? M ? 3 1 + ATOM 1053 CA . LEU M 221 ? 47.28200 87.76100 81.75400 1.000 30.00000 C ? M ? 3 1 + ATOM 1054 C . LEU M 221 ? 48.26900 88.68200 82.45100 1.000 30.00000 C ? M ? 3 1 + ATOM 1055 O . LEU M 221 ? 48.72200 89.68400 81.87000 1.000 30.00000 O ? M ? 3 1 + ATOM 1056 CB . LEU M 221 ? 45.88300 88.03700 82.31200 1.000 30.00000 C ? M ? 3 1 + ATOM 1057 CG . LEU M 221 ? 45.29200 89.43100 82.07100 1.000 30.00000 C ? M ? 3 1 + ATOM 1058 CD1 . LEU M 221 ? 44.95800 89.63600 80.60100 1.000 30.00000 C ? M ? 3 1 + ATOM 1059 CD2 . LEU M 221 ? 44.05000 89.63100 82.92100 1.000 30.00000 C ? M ? 3 1 + ATOM 1060 N . GLN M 222 ? 48.58200 88.31500 83.69100 1.000 30.00000 N ? M ? 4 1 + ATOM 1061 CA . GLN M 222 ? 49.51800 89.08200 84.52600 1.000 30.00000 C ? M ? 4 1 + ATOM 1062 C . GLN M 222 ? 50.87000 89.18400 83.84100 1.000 30.00000 C ? M ? 4 1 + ATOM 1063 O . GLN M 222 ? 51.46700 90.26900 83.77600 1.000 30.00000 O ? M ? 4 1 + ATOM 1064 CB . GLN M 222 ? 49.69400 88.44000 85.90400 1.000 30.00000 C ? M ? 4 1 + ATOM 1065 CG . GLN M 222 ? 50.53700 89.25200 86.87700 1.000 30.00000 C ? M ? 4 1 + ATOM 1066 CD . GLN M 222 ? 50.74600 88.53700 88.19900 1.000 30.00000 C ? M ? 4 1 + ATOM 1067 OE1 . GLN M 222 ? 49.83500 87.89600 88.72600 1.000 30.00000 O ? M ? 4 1 + ATOM 1068 NE2 . GLN M 222 ? 51.95400 88.64400 88.74400 1.000 30.00000 N ? M ? 4 1 + ATOM 1069 N . GLN M 223 ? 51.31800 88.03500 83.33800 1.000 30.00000 N ? M ? 5 1 + ATOM 1070 CA . GLN M 223 ? 52.60400 87.92500 82.63800 1.000 30.00000 C ? M ? 5 1 + ATOM 1071 C . GLN M 223 ? 52.63400 88.87200 81.44700 1.000 30.00000 C ? M ? 5 1 + ATOM 1072 O . GLN M 223 ? 53.61700 89.60800 81.23400 1.000 30.00000 O ? M ? 5 1 + ATOM 1073 CB . GLN M 223 ? 52.84400 86.50600 82.10200 1.000 30.00000 C ? M ? 5 1 + ATOM 1074 CG . GLN M 223 ? 53.32400 85.47700 83.10800 1.000 30.00000 C ? M ? 5 1 + ATOM 1075 CD . GLN M 223 ? 53.64900 84.15000 82.44400 1.000 30.00000 C ? M ? 5 1 + ATOM 1076 OE1 . GLN M 223 ? 53.04200 83.12400 82.75000 1.000 30.00000 O ? M ? 5 1 + ATOM 1077 NE2 . GLN M 223 ? 54.60200 84.16800 81.51600 1.000 30.00000 N ? M ? 5 1 + ATOM 1078 N . ALA M 224 ? 51.54300 88.82700 80.69100 1.000 30.00000 N ? M ? 6 1 + ATOM 1079 CA . ALA M 224 ? 51.37100 89.65200 79.49100 1.000 30.00000 C ? M ? 6 1 + ATOM 1080 C . ALA M 224 ? 51.49400 91.12900 79.85100 1.000 30.00000 C ? M ? 6 1 + ATOM 1081 O . ALA M 224 ? 52.19900 91.89800 79.17600 1.000 30.00000 O ? M ? 6 1 + ATOM 1082 CB . ALA M 224 ? 50.02400 89.38300 78.83000 1.000 30.00000 C ? M ? 6 1 + ATOM 1083 N . TYR M 225 ? 50.79500 91.48700 80.92200 1.000 30.00000 N ? M ? 7 1 + ATOM 1084 CA . TYR M 225 ? 50.77800 92.86300 81.42800 1.000 30.00000 C ? M ? 7 1 + ATOM 1085 C . TYR M 225 ? 52.18200 93.32000 81.77100 1.000 30.00000 C ? M ? 7 1 + ATOM 1086 O . TYR M 225 ? 52.59600 94.43000 81.39800 1.000 30.00000 O ? M ? 7 1 + ATOM 1087 CB . TYR M 225 ? 49.78400 93.09700 82.56600 1.000 30.00000 C ? M ? 7 1 + ATOM 1088 CG . TYR M 225 ? 48.56500 93.70900 81.98500 1.000 30.00000 C ? M ? 7 1 + ATOM 1089 CD1 . TYR M 225 ? 48.56300 95.05400 81.64200 1.000 30.00000 C ? M ? 7 1 + ATOM 1090 CD2 . TYR M 225 ? 47.45100 92.93700 81.67200 1.000 30.00000 C ? M ? 7 1 + ATOM 1091 CE1 . TYR M 225 ? 47.46300 95.63200 81.04800 1.000 30.00000 C ? M ? 7 1 + ATOM 1092 CE2 . TYR M 225 ? 46.33500 93.50800 81.08400 1.000 30.00000 C ? M ? 7 1 + ATOM 1093 CZ . TYR M 225 ? 46.34900 94.85500 80.77400 1.000 30.00000 C ? M ? 7 1 + ATOM 1094 OH . TYR M 225 ? 45.26400 95.43400 80.18100 1.000 30.00000 O ? M ? 7 1 + ATOM 1095 N . LEU M 226 ? 52.89200 92.44000 82.46500 1.000 30.00000 N ? M ? 8 1 + ATOM 1096 CA . LEU M 226 ? 54.27300 92.69100 82.89600 1.000 30.00000 C ? M ? 8 1 + ATOM 1097 C . LEU M 226 ? 55.14900 92.97200 81.68500 1.000 30.00000 C ? M ? 8 1 + ATOM 1098 O . LEU M 226 ? 55.93800 93.94300 81.67900 1.000 30.00000 O ? M ? 8 1 + ATOM 1099 CB . LEU M 226 ? 54.87400 91.51400 83.68300 1.000 30.00000 C ? M ? 8 1 + ATOM 1100 CG . LEU M 226 ? 54.94000 91.67100 85.20200 1.000 30.00000 C ? M ? 8 1 + ATOM 1101 CD1 . LEU M 226 ? 53.54700 91.61700 85.80100 1.000 30.00000 C ? M ? 8 1 + ATOM 1102 CD2 . LEU M 226 ? 55.81800 90.59100 85.82100 1.000 30.00000 C ? M ? 8 1 + ATOM 1103 N . ILE M 227 ? 54.98500 92.10800 80.68000 1.000 30.00000 N ? M ? 9 1 + ATOM 1104 CA . ILE M 227 ? 55.77100 92.21400 79.44300 1.000 30.00000 C ? M ? 9 1 + ATOM 1105 C . ILE M 227 ? 55.50900 93.55700 78.77500 1.000 30.00000 C ? M ? 9 1 + ATOM 1106 O . ILE M 227 ? 56.46100 94.22900 78.33900 1.000 30.00000 O ? M ? 9 1 + ATOM 1107 CB . ILE M 227 ? 55.79300 91.00300 78.46500 1.000 30.00000 C ? M ? 9 1 + ATOM 1108 CG1 . ILE M 227 ? 54.44500 90.71800 77.82600 1.000 30.00000 C ? M ? 9 1 + ATOM 1109 CG2 . ILE M 227 ? 56.35400 89.76900 79.15600 1.000 30.00000 C ? M ? 9 1 + ATOM 1110 CD1 . ILE M 227 ? 54.53500 89.86100 76.58400 1.000 30.00000 C ? M ? 9 1 + ATOM 1111 N . MET M 228 ? 54.23400 93.92500 78.72700 1.000 30.00000 N ? M ? 10 1 + ATOM 1112 CA . MET M 228 ? 53.79800 95.18900 78.12700 1.000 30.00000 C ? M ? 10 1 + ATOM 1113 C . MET M 228 ? 54.47000 96.36100 78.82800 1.000 30.00000 C ? M ? 10 1 + ATOM 1114 O . MET M 228 ? 54.98900 97.28200 78.17200 1.000 30.00000 O ? M ? 10 1 + ATOM 1115 CB . MET M 228 ? 52.26900 95.34400 78.14900 1.000 30.00000 C ? M ? 10 1 + ATOM 1116 CG . MET M 228 ? 51.50100 94.47700 77.15300 1.000 30.00000 C ? M ? 10 1 + ATOM 1117 SD . MET M 228 ? 51.95000 94.67000 75.40900 1.000 30.00000 S ? M ? 10 1 + ATOM 1118 CE . MET M 228 ? 51.80100 96.44100 75.14600 1.000 30.00000 C ? M ? 10 1 + ATOM 1119 N . LEU N 219 ? 90.85800 27.17700 85.40300 1.000 30.00000 N ? N ? 1 1 + ATOM 1120 CA . LEU N 219 ? 91.87700 26.14000 85.54700 1.000 30.00000 C ? N ? 1 1 + ATOM 1121 C . LEU N 219 ? 92.64000 25.90600 84.24900 1.000 30.00000 C ? N ? 1 1 + ATOM 1122 O . LEU N 219 ? 93.84600 25.65400 84.27500 1.000 30.00000 O ? N ? 1 1 + ATOM 1123 CB . LEU N 219 ? 91.24500 24.83600 86.04400 1.000 30.00000 C ? N ? 1 1 + ATOM 1124 CG . LEU N 219 ? 92.21100 23.67500 86.33400 1.000 30.00000 C ? N ? 1 1 + ATOM 1125 CD1 . LEU N 219 ? 91.89300 23.00300 87.66600 1.000 30.00000 C ? N ? 1 1 + ATOM 1126 CD2 . LEU N 219 ? 92.21300 22.65100 85.20400 1.000 30.00000 C ? N ? 1 1 + ATOM 1127 N . ARG N 220 ? 91.93400 25.99200 83.12300 1.000 30.00000 N ? N ? 2 1 + ATOM 1128 CA . ARG N 220 ? 92.54100 25.84100 81.80600 1.000 30.00000 C ? N ? 2 1 + ATOM 1129 C . ARG N 220 ? 93.55900 26.93600 81.56000 1.000 30.00000 C ? N ? 2 1 + ATOM 1130 O . ARG N 220 ? 94.63700 26.66000 81.01700 1.000 30.00000 O ? N ? 2 1 + ATOM 1131 CB . ARG N 220 ? 91.47600 25.86600 80.70400 1.000 30.00000 C ? N ? 2 1 + ATOM 1132 CG . ARG N 220 ? 90.58300 24.63700 80.66200 1.000 30.00000 C ? N ? 2 1 + ATOM 1133 CD . ARG N 220 ? 91.26200 23.46400 79.96900 1.000 30.00000 C ? N ? 2 1 + ATOM 1134 NE . ARG N 220 ? 90.39100 22.28900 79.89800 1.000 30.00000 N ? N ? 2 1 + ATOM 1135 CZ . ARG N 220 ? 89.37600 22.12100 79.04400 1.000 30.00000 C ? N ? 2 1 + ATOM 1136 NH1 . ARG N 220 ? 89.05700 23.05700 78.14700 1.000 30.00000 N ? N ? 2 1 + ATOM 1137 NH2 . ARG N 220 ? 88.66300 20.99600 79.08800 1.000 30.00000 N ? N ? 2 1 + ATOM 1138 N . LEU N 221 ? 93.18900 28.16100 81.94100 1.000 30.00000 N ? N ? 3 1 + ATOM 1139 CA . LEU N 221 ? 94.03900 29.33400 81.75500 1.000 30.00000 C ? N ? 3 1 + ATOM 1140 C . LEU N 221 ? 95.37400 29.13700 82.45100 1.000 30.00000 C ? N ? 3 1 + ATOM 1141 O . LEU N 221 ? 96.44000 29.40700 81.87000 1.000 30.00000 O ? N ? 3 1 + ATOM 1142 CB . LEU N 221 ? 93.38200 30.60000 82.31200 1.000 30.00000 C ? N ? 3 1 + ATOM 1143 CG . LEU N 221 ? 94.10400 31.93100 82.07200 1.000 30.00000 C ? N ? 3 1 + ATOM 1144 CD1 . LEU N 221 ? 94.05600 32.32000 80.60200 1.000 30.00000 C ? N ? 3 1 + ATOM 1145 CD2 . LEU N 221 ? 93.48600 33.02700 82.92200 1.000 30.00000 C ? N ? 3 1 + ATOM 1146 N . GLN N 222 ? 95.28200 28.66300 83.69200 1.000 30.00000 N ? N ? 4 1 + ATOM 1147 CA . GLN N 222 ? 96.46600 28.41000 84.52600 1.000 30.00000 C ? N ? 4 1 + ATOM 1148 C . GLN N 222 ? 97.38800 27.41600 83.84100 1.000 30.00000 C ? N ? 4 1 + ATOM 1149 O . GLN N 222 ? 98.60900 27.62600 83.77600 1.000 30.00000 O ? N ? 4 1 + ATOM 1150 CB . GLN N 222 ? 96.07300 27.87200 85.90400 1.000 30.00000 C ? N ? 4 1 + ATOM 1151 CG . GLN N 222 ? 97.23400 27.71900 86.87700 1.000 30.00000 C ? N ? 4 1 + ATOM 1152 CD . GLN N 222 ? 96.80500 27.11000 88.20000 1.000 30.00000 C ? N ? 4 1 + ATOM 1153 OE1 . GLN N 222 ? 95.73600 27.42200 88.72700 1.000 30.00000 O ? N ? 4 1 + ATOM 1154 NE2 . GLN N 222 ? 97.64200 26.23200 88.74500 1.000 30.00000 N ? N ? 4 1 + ATOM 1155 N . GLN N 223 ? 96.76900 26.35000 83.33900 1.000 30.00000 N ? N ? 5 1 + ATOM 1156 CA . GLN N 223 ? 97.48500 25.27600 82.63900 1.000 30.00000 C ? N ? 5 1 + ATOM 1157 C . GLN N 223 ? 98.24400 25.84300 81.44800 1.000 30.00000 C ? N ? 5 1 + ATOM 1158 O . GLN N 223 ? 99.43200 25.53300 81.23400 1.000 30.00000 O ? N ? 5 1 + ATOM 1159 CB . GLN N 223 ? 96.52500 24.20300 82.10300 1.000 30.00000 C ? N ? 5 1 + ATOM 1160 CG . GLN N 223 ? 96.02000 23.18600 83.10900 1.000 30.00000 C ? N ? 5 1 + ATOM 1161 CD . GLN N 223 ? 95.18500 22.10500 82.44500 1.000 30.00000 C ? N ? 5 1 + ATOM 1162 OE1 . GLN N 223 ? 94.00500 21.94000 82.75100 1.000 30.00000 O ? N ? 5 1 + ATOM 1163 NE2 . GLN N 223 ? 95.79300 21.37100 81.51700 1.000 30.00000 N ? N ? 5 1 + ATOM 1164 N . ALA N 224 ? 97.52900 26.66800 80.69100 1.000 30.00000 N ? N ? 6 1 + ATOM 1165 CA . ALA N 224 ? 98.06700 27.31600 79.49200 1.000 30.00000 C ? N ? 6 1 + ATOM 1166 C . ALA N 224 ? 99.29800 28.14100 79.85100 1.000 30.00000 C ? N ? 6 1 + ATOM 1167 O . ALA N 224 ? 100.33900 28.06900 79.17700 1.000 30.00000 O ? N ? 6 1 + ATOM 1168 CB . ALA N 224 ? 97.01600 28.20200 78.83100 1.000 30.00000 C ? N ? 6 1 + ATOM 1169 N . TYR N 225 ? 99.14200 28.91100 80.92200 1.000 30.00000 N ? N ? 7 1 + ATOM 1170 CA . TYR N 225 ? 100.20700 29.78200 81.42800 1.000 30.00000 C ? N ? 7 1 + ATOM 1171 C . TYR N 225 ? 101.44000 28.96900 81.77200 1.000 30.00000 C ? N ? 7 1 + ATOM 1172 O . TYR N 225 ? 102.56600 29.33800 81.39800 1.000 30.00000 O ? N ? 7 1 + ATOM 1173 CB . TYR N 225 ? 99.77100 30.70500 82.56600 1.000 30.00000 C ? N ? 7 1 + ATOM 1174 CG . TYR N 225 ? 99.48900 32.04000 81.98600 1.000 30.00000 C ? N ? 7 1 + ATOM 1175 CD1 . TYR N 225 ? 100.53900 32.88000 81.64200 1.000 30.00000 C ? N ? 7 1 + ATOM 1176 CD2 . TYR N 225 ? 98.19100 32.42900 81.67300 1.000 30.00000 C ? N ? 7 1 + ATOM 1177 CE1 . TYR N 225 ? 100.30500 34.10000 81.04900 1.000 30.00000 C ? N ? 7 1 + ATOM 1178 CE2 . TYR N 225 ? 97.94100 33.65800 81.08500 1.000 30.00000 C ? N ? 7 1 + ATOM 1179 CZ . TYR N 225 ? 99.00300 34.48700 80.77500 1.000 30.00000 C ? N ? 7 1 + ATOM 1180 OH . TYR N 225 ? 98.78000 35.69600 80.18100 1.000 30.00000 O ? N ? 7 1 + ATOM 1181 N . LEU N 226 ? 101.19500 27.86500 82.46600 1.000 30.00000 N ? N ? 8 1 + ATOM 1182 CA . LEU N 226 ? 102.25200 26.94200 82.89700 1.000 30.00000 C ? N ? 8 1 + ATOM 1183 C . LEU N 226 ? 103.01800 26.43300 81.68600 1.000 30.00000 C ? N ? 8 1 + ATOM 1184 O . LEU N 226 ? 104.26900 26.42100 81.68000 1.000 30.00000 O ? N ? 8 1 + ATOM 1185 CB . LEU N 226 ? 101.70600 25.73900 83.68300 1.000 30.00000 C ? N ? 8 1 + ATOM 1186 CG . LEU N 226 ? 101.87000 25.78500 85.20300 1.000 30.00000 C ? N ? 8 1 + ATOM 1187 CD1 . LEU N 226 ? 100.96000 26.84000 85.80200 1.000 30.00000 C ? N ? 8 1 + ATOM 1188 CD2 . LEU N 226 ? 101.57300 24.42500 85.82200 1.000 30.00000 C ? N ? 8 1 + ATOM 1189 N . ILE N 227 ? 102.24000 26.02200 80.68000 1.000 30.00000 N ? N ? 9 1 + ATOM 1190 CA . ILE N 227 ? 102.81300 25.47400 79.44400 1.000 30.00000 C ? N ? 9 1 + ATOM 1191 C . ILE N 227 ? 103.70000 26.51600 78.77600 1.000 30.00000 C ? N ? 9 1 + ATOM 1192 O . ILE N 227 ? 104.81800 26.19000 78.34000 1.000 30.00000 O ? N ? 9 1 + ATOM 1193 CB . ILE N 227 ? 101.88000 24.70100 78.46600 1.000 30.00000 C ? N ? 9 1 + ATOM 1194 CG1 . ILE N 227 ? 100.81700 25.57800 77.82700 1.000 30.00000 C ? N ? 9 1 + ATOM 1195 CG2 . ILE N 227 ? 101.26500 23.49300 79.15700 1.000 30.00000 C ? N ? 9 1 + ATOM 1196 CD1 . ILE N 227 ? 100.20300 24.97300 76.58500 1.000 30.00000 C ? N ? 9 1 + ATOM 1197 N . MET N 228 ? 103.19200 27.74200 78.72800 1.000 30.00000 N ? N ? 10 1 + ATOM 1198 CA . MET N 228 ? 103.90900 28.87100 78.12700 1.000 30.00000 C ? N ? 10 1 + ATOM 1199 C . MET N 228 ? 105.24400 29.07600 78.82900 1.000 30.00000 C ? N ? 10 1 + ATOM 1200 O . MET N 228 ? 106.28800 29.24500 78.17200 1.000 30.00000 O ? N ? 10 1 + ATOM 1201 CB . MET N 228 ? 103.07700 30.16300 78.14900 1.000 30.00000 C ? N ? 10 1 + ATOM 1202 CG . MET N 228 ? 101.92000 30.22300 77.15400 1.000 30.00000 C ? N ? 10 1 + ATOM 1203 SD . MET N 228 ? 102.35100 29.99200 75.41000 1.000 30.00000 S ? N ? 10 1 + ATOM 1204 CE . MET N 228 ? 103.64200 31.21300 75.14700 1.000 30.00000 C ? N ? 10 1 + diff --git a/iotbx/regression/tst_hierarchy_forward_compatible_pdb.py b/iotbx/regression/tst_hierarchy_forward_compatible_pdb.py index bc6c046570..6234a9c41c 100644 --- a/iotbx/regression/tst_hierarchy_forward_compatible_pdb.py +++ b/iotbx/regression/tst_hierarchy_forward_compatible_pdb.py @@ -110,6 +110,68 @@ ATOM 1 CA . GLYG ABCDEFG 1 ? 12.47000 12.95700 8.06900 1.000 30.00000 C ? A ? 1 1 ATOM 2 CA . GLYHABCD DEFGHIL 1 ? 12.47000 12.95700 8.06900 1.000 30.00000 C ? B ? 1 1 ''' +mmcif_str_3 = ''' +data_XXXX +# +loop_ +_atom_site.group_PDB +_atom_site.id +_atom_site.type_symbol +_atom_site.label_atom_id +_atom_site.label_alt_id +_atom_site.label_comp_id +_atom_site.label_asym_id +_atom_site.label_entity_id +_atom_site.label_seq_id +_atom_site.pdbx_PDB_ins_code +_atom_site.Cartn_x +_atom_site.Cartn_y +_atom_site.Cartn_z +_atom_site.occupancy +_atom_site.B_iso_or_equiv +_atom_site.pdbx_formal_charge +_atom_site.auth_seq_id +_atom_site.auth_comp_id +_atom_site.auth_asym_id +_atom_site.auth_atom_id +_atom_site.pdbx_PDB_model_num +ATOM 2141 C CA . LYS A 1 261 ? -0.169 -9.988 41.173 1.00 43.86 ? 261 LYS A C 1 +ATOM 2142 C CA . LYS A 1 262 ? 0.687 -9.011 41.991 1.00 41.94 ? 262 LYS A C 1 +ATOM 2143 C CA . LYS A 1 263 ? 1.044 -7.920 41.556 1.00 39.32 ? 263 LYS A C 1 +ATOM 2144 C CA . LYS A 1 264 ? -0.260 -11.336 41.902 1.00 46.47 ? 264 LYS A C 1 +''' +mmcif_str_4 = '''data_default +loop_ + _struct_asym.id + A + +loop_ + _chem_comp.id + GLY + +loop_ + _atom_site.group_PDB + _atom_site.id + _atom_site.label_atom_id + _atom_site.label_alt_id + _atom_site.label_comp_id + _atom_site.auth_asym_id + _atom_site.auth_seq_id + _atom_site.pdbx_PDB_ins_code + _atom_site.Cartn_x + _atom_site.Cartn_y + _atom_site.Cartn_z + _atom_site.occupancy + _atom_site.B_iso_or_equiv + _atom_site.type_symbol + _atom_site.pdbx_formal_charge + _atom_site.label_asym_id + _atom_site.label_entity_id + _atom_site.label_seq_id + _atom_site.pdbx_PDB_model_num + ATOM 1 CA . GLY A 1 ? 12.47000 12.95700 8.06900 1.000 30.00000 C ? A ? 1 1 + ATOM 2 CA . GLY A 2 ? 12.47000 12.95700 8.06900 1.000 30.00000 C ? A ? 1 1 +''' def test1(): """ @@ -267,9 +329,10 @@ def test6(): print("Testing use of ph.as_mmcif_string(segid_as_auth_segid=True)") # Get a hierarchy - from iotbx.pdb.forward_compatible_pdb_cif_conversion import pdb_or_mmcif_string_as_hierarchy - ph = pdb_or_mmcif_string_as_hierarchy(mmcif_str_1).hierarchy - # Add segid to the hierarchy + from iotbx.pdb.forward_compatible_pdb_cif_conversion \ + import pdb_or_mmcif_string_as_hierarchy + ph = pdb_or_mmcif_string_as_hierarchy(mmcif_str_4).hierarchy + # Add segid to the hierarchy and set chain ID and resnames i = 0 for model in ph.models(): for chain in model.chains(): @@ -277,9 +340,62 @@ def test6(): for atom_group in residue_group.atom_groups(): for atom in atom_group.atoms(): atom.set_segid('UNK') - # assert ph.as_pdb_string().find("UNK")>-1 - assert ph.as_mmcif_string().find("UNK") == -1 - assert ph.as_mmcif_string(segid_as_auth_segid=True).find("UNK") > -1 + ph_as_string = ph.as_pdb_string() + ph_as_mmcif_string_auth_segid = ph.as_mmcif_string(segid_as_auth_segid=True) + ph_as_mmcif_string_no_auth_segid = ph.as_mmcif_string( + segid_as_auth_segid=False) + new_ph_auth_segid = pdb_or_mmcif_string_as_hierarchy( + ph_as_mmcif_string_auth_segid).hierarchy + new_ph_no_auth_segid = pdb_or_mmcif_string_as_hierarchy( + ph_as_mmcif_string_no_auth_segid).hierarchy + new_ph_auth_segid_as_string = new_ph_auth_segid.as_pdb_string( + force_write=True) + new_ph_no_auth_segid_as_string = new_ph_no_auth_segid.as_pdb_string( + force_write=True) + + #print("ph_as_string\n",ph_as_string) + #print("ph_as_mmcif_string_auth_segid\n",ph_as_mmcif_string_auth_segid) + #print("ph_as_mmcif_string_no_auth_segid\n",ph_as_mmcif_string_no_auth_segid) + #print("new_ph_auth_segid_as_string\n",new_ph_auth_segid_as_string) + #print("new_ph_no_auth_segid_as_string\n",new_ph_no_auth_segid_as_string) + assert ph_as_string.find(" UNK C")>-1 + assert ph_as_mmcif_string_auth_segid.find("1 1 UNK") > -1 + assert ph_as_mmcif_string_no_auth_segid.find("0 1 UNK") < 0 + assert ph_as_mmcif_string_no_auth_segid.find(" UNK ") > -1 + assert ph_as_string == new_ph_auth_segid_as_string + +def test7(): + """ + Test get_unique_values_dict + """ + print("Testing get_unique_values_dict") + inp = iotbx.pdb.input(lines=mmcif_str_1.split("\n"), source_info=None) + ph = inp.construct_hierarchy() + from iotbx.pdb.forward_compatible_pdb_cif_conversion import \ + get_unique_values_dict + unique_values_dict = get_unique_values_dict([ph]) + assert unique_values_dict == { + 'chain_id': ['ABCDEFG', 'DEFGHIL'], 'resname': ['GLYG', 'GLYHABCD']} + +def test8(): + print("Testing use of ph.as_mmcif_string(output_break_string=True)") + + # Get a hierarchy + from iotbx.pdb.forward_compatible_pdb_cif_conversion import pdb_or_mmcif_string_as_hierarchy + ph = pdb_or_mmcif_string_as_hierarchy(mmcif_str_3).hierarchy + # Add segid to the hierarchy + i = 0 + for model in ph.models(): + for chain in model.chains(): + for residue_group in chain.residue_groups(): + i+= 1 + if i == 2: + residue_group.link_to_previous = False + ph1 = pdb_or_mmcif_string_as_hierarchy(ph.as_mmcif_string()).hierarchy + assert ph1.as_pdb_string().find("BREAK") == -1 + ph2 = pdb_or_mmcif_string_as_hierarchy( + ph.as_mmcif_string(output_break_records=True)).hierarchy + assert ph2.as_pdb_string().find("BREAK") > -1 def remove_remarks_hetnam(text): new_text_list = [] @@ -297,4 +413,6 @@ def remove_remarks_hetnam(text): test4() test5() test6() + test7() + test8() print("OK. Time: %8.3f"%(time.time()-t0)) diff --git a/iotbx/regression/tst_hierarchy_pdb_v3.py b/iotbx/regression/tst_hierarchy_pdb_v3.py index 86aa8bef90..bc6c046570 100644 --- a/iotbx/regression/tst_hierarchy_pdb_v3.py +++ b/iotbx/regression/tst_hierarchy_pdb_v3.py @@ -118,8 +118,8 @@ def test1(): inp = iotbx.pdb.input(lines=mmcif_str.split("\n"), source_info=None) ph = inp.construct_hierarchy() - from iotbx.pdb.pdb_v3_cif_conversion import pdb_v3_cif_conversion - conversion_info = pdb_v3_cif_conversion(hierarchy = ph) + from iotbx.pdb.forward_compatible_pdb_cif_conversion import forward_compatible_pdb_cif_conversion + conversion_info = forward_compatible_pdb_cif_conversion(hierarchy = ph) print(conversion_info.conversion_as_remark_hetnam_string()) def test2(): @@ -129,8 +129,8 @@ def test2(): inp = iotbx.pdb.input(lines=mmcif_str_1.split("\n"), source_info=None) ph = inp.construct_hierarchy() - from iotbx.pdb.pdb_v3_cif_conversion import pdb_v3_cif_conversion - conversion_info = pdb_v3_cif_conversion(hierarchy = ph) + from iotbx.pdb.forward_compatible_pdb_cif_conversion import forward_compatible_pdb_cif_conversion + conversion_info = forward_compatible_pdb_cif_conversion(hierarchy = ph) print(conversion_info.conversion_as_remark_hetnam_string()) def test3(): @@ -141,12 +141,12 @@ def test3(): inp = iotbx.pdb.input(lines=mmcif_str_1.split("\n"), source_info=None) ph = inp.construct_hierarchy() - from iotbx.pdb.pdb_v3_cif_conversion import pdb_v3_cif_conversion - conversion_info = pdb_v3_cif_conversion(hierarchy = ph, + from iotbx.pdb.forward_compatible_pdb_cif_conversion import forward_compatible_pdb_cif_conversion + conversion_info = forward_compatible_pdb_cif_conversion(hierarchy = ph, residue_conversion_as_remark = True) remark_hetnam_string = conversion_info.conversion_as_remark_hetnam_string() - new_conversion_info = pdb_v3_cif_conversion() + new_conversion_info = forward_compatible_pdb_cif_conversion() new_conversion_info.set_conversion_tables_from_remark_hetnam_records( remark_hetnam_records = remark_hetnam_string.splitlines()) new_remark_hetnam_string = new_conversion_info.conversion_as_remark_hetnam_string() @@ -161,15 +161,15 @@ def test3a(): inp = iotbx.pdb.input(lines=mmcif_str_1.split("\n"), source_info=None) ph = inp.construct_hierarchy() - from iotbx.pdb.pdb_v3_cif_conversion import pdb_v3_cif_conversion - conversion_info = pdb_v3_cif_conversion(hierarchy = ph, + from iotbx.pdb.forward_compatible_pdb_cif_conversion import forward_compatible_pdb_cif_conversion + conversion_info = forward_compatible_pdb_cif_conversion(hierarchy = ph, residue_conversion_as_remark = False, residue_conversion_as_hetnam = True, ) remark_hetnam_string = conversion_info.conversion_as_remark_hetnam_string() print("OLD\n",remark_hetnam_string) - new_conversion_info = pdb_v3_cif_conversion( + new_conversion_info = forward_compatible_pdb_cif_conversion( residue_conversion_as_remark = False, residue_conversion_as_hetnam = True, ) @@ -188,14 +188,14 @@ def test4(): inp = iotbx.pdb.input(lines=mmcif_str_1.split("\n"), source_info=None) ph = inp.construct_hierarchy() - from iotbx.pdb.pdb_v3_cif_conversion import pdb_v3_cif_conversion - conversion_info = pdb_v3_cif_conversion(hierarchy = ph) + from iotbx.pdb.forward_compatible_pdb_cif_conversion import forward_compatible_pdb_cif_conversion + conversion_info = forward_compatible_pdb_cif_conversion(hierarchy = ph) remark_hetnam_string = conversion_info.conversion_as_remark_hetnam_string() - # convert to pdb_v3 - conversion_info.convert_hierarchy_to_pdb_v3_representation(ph) + # convert to forward_compatible_pdb + conversion_info.convert_hierarchy_to_forward_compatible_pdb_representation(ph) new_string = ph.as_pdb_string() - print("NEW STRING (pdb_v3)\n%s" %(new_string)) + print("NEW STRING (forward_compatible_pdb)\n%s" %(new_string)) new_inp = iotbx.pdb.input(lines=(remark_hetnam_string + new_string).split("\n"), source_info=None, ) @@ -203,8 +203,8 @@ def test4(): new_ph = new_inp.construct_hierarchy() print("New ph as string:\n",new_ph.as_pdb_string()) - from iotbx.pdb.pdb_v3_cif_conversion import pdb_v3_cif_conversion - new_conversion_info = pdb_v3_cif_conversion() + from iotbx.pdb.forward_compatible_pdb_cif_conversion import forward_compatible_pdb_cif_conversion + new_conversion_info = forward_compatible_pdb_cif_conversion() new_conversion_info.set_conversion_tables_from_remark_hetnam_records( remark_hetnam_records = new_remark_hetnam_string.splitlines()) updated_remark_hetnam_string = new_conversion_info.conversion_as_remark_hetnam_string() @@ -214,50 +214,50 @@ def test4(): def test5(): """ - Test standard uses of pdb_v3 to hierarchy conversions + Test standard uses of forward_compatible_pdb to hierarchy conversions """ - print("\nTest 5, standard uses of pdb_v3 to hierarchy conversions") + print("\nTest 5, standard uses of forward_compatible_pdb to hierarchy conversions") - # Get a hierarchy that is not pdb_v3 compatible - from iotbx.pdb.pdb_v3_cif_conversion import pdb_or_mmcif_string_as_hierarchy + # Get a hierarchy that is not forward_compatible_pdb compatible + from iotbx.pdb.forward_compatible_pdb_cif_conversion import pdb_or_mmcif_string_as_hierarchy ph = pdb_or_mmcif_string_as_hierarchy(mmcif_str_1).hierarchy - # Write a pdb_v3 compatible string with conversion information in REMARKs - from iotbx.pdb.pdb_v3_cif_conversion import hierarchy_as_pdb_v3_string - pdb_v3_string = hierarchy_as_pdb_v3_string(ph) - print("Hierarchy as pdb_v3 string with REMARKS:\n%s" %(pdb_v3_string)) + # Write a forward_compatible_pdb compatible string with conversion information in REMARKs + from iotbx.pdb.forward_compatible_pdb_cif_conversion import hierarchy_as_forward_compatible_pdb_string + forward_compatible_pdb_string = hierarchy_as_forward_compatible_pdb_string(ph) + print("Hierarchy as forward_compatible_pdb string with REMARKS:\n%s" %(forward_compatible_pdb_string)) - # convert pdb_v3_string to a hierarchy - from iotbx.pdb.pdb_v3_cif_conversion import pdb_or_mmcif_string_as_hierarchy - new_ph = pdb_or_mmcif_string_as_hierarchy(pdb_v3_string).hierarchy - new_pdb_v3_string = hierarchy_as_pdb_v3_string(new_ph) - print("Hierarchy after writing/reading as pdb_v3 string with REMARKS:\n%s" %(new_pdb_v3_string)) - assert pdb_v3_string == new_pdb_v3_string + # convert forward_compatible_pdb_string to a hierarchy + from iotbx.pdb.forward_compatible_pdb_cif_conversion import pdb_or_mmcif_string_as_hierarchy + new_ph = pdb_or_mmcif_string_as_hierarchy(forward_compatible_pdb_string).hierarchy + new_forward_compatible_pdb_string = hierarchy_as_forward_compatible_pdb_string(new_ph) + print("Hierarchy after writing/reading as forward_compatible_pdb string with REMARKS:\n%s" %(new_forward_compatible_pdb_string)) + assert forward_compatible_pdb_string == new_forward_compatible_pdb_string - # strip off REMARKS from pdb_v3_string, read in and apply conversions - from iotbx.pdb.pdb_v3_cif_conversion import pdb_v3_cif_conversion - conversion_info = pdb_v3_cif_conversion(ph) - pdb_v3_string_no_remarks = remove_remarks_hetnam(pdb_v3_string) - print("pdb_v3_string with no remarks:\n%s\n" %(pdb_v3_string_no_remarks)) + # strip off REMARKS from forward_compatible_pdb_string, read in and apply conversions + from iotbx.pdb.forward_compatible_pdb_cif_conversion import forward_compatible_pdb_cif_conversion + conversion_info = forward_compatible_pdb_cif_conversion(ph) + forward_compatible_pdb_string_no_remarks = remove_remarks_hetnam(forward_compatible_pdb_string) + print("forward_compatible_pdb_string with no remarks:\n%s\n" %(forward_compatible_pdb_string_no_remarks)) - updated_ph = pdb_or_mmcif_string_as_hierarchy(pdb_v3_string_no_remarks).hierarchy + updated_ph = pdb_or_mmcif_string_as_hierarchy(forward_compatible_pdb_string_no_remarks).hierarchy # Apply the conversions to obtain a full representation in updated_ph conversion_info.convert_hierarchy_to_full_representation(updated_ph) - # Get updated pdb_v3 string - updated_pdb_v3_string = hierarchy_as_pdb_v3_string(updated_ph) - print("Hierarchy after writing/reading as pdb_v3 string without REMARKS and restoring conversion:\n%s" %(updated_pdb_v3_string)) - assert updated_pdb_v3_string == pdb_v3_string + # Get updated forward_compatible_pdb string + updated_forward_compatible_pdb_string = hierarchy_as_forward_compatible_pdb_string(updated_ph) + print("Hierarchy after writing/reading as forward_compatible_pdb string without REMARKS and restoring conversion:\n%s" %(updated_forward_compatible_pdb_string)) + assert updated_forward_compatible_pdb_string == forward_compatible_pdb_string # Initialize conversion_info with unique_values_dict - conversion_info = pdb_v3_cif_conversion(ph) + conversion_info = forward_compatible_pdb_cif_conversion(ph) unique_values_dict = {} unique_values_dict['chain_id'] = \ conversion_info._unique_chain_ids_from_hierarchy(ph) unique_values_dict['resname'] = \ conversion_info._unique_resnames_from_hierarchy(ph) - new_conversion_info = pdb_v3_cif_conversion( + new_conversion_info = forward_compatible_pdb_cif_conversion( unique_values_dict = unique_values_dict) print("\nConversion info using unique_values_dict:") print(conversion_info.conversion_as_remark_hetnam_string()) @@ -267,7 +267,7 @@ def test6(): print("Testing use of ph.as_mmcif_string(segid_as_auth_segid=True)") # Get a hierarchy - from iotbx.pdb.pdb_v3_cif_conversion import pdb_or_mmcif_string_as_hierarchy + from iotbx.pdb.forward_compatible_pdb_cif_conversion import pdb_or_mmcif_string_as_hierarchy ph = pdb_or_mmcif_string_as_hierarchy(mmcif_str_1).hierarchy # Add segid to the hierarchy i = 0 diff --git a/iotbx/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry.py b/iotbx/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry.py index 859df3f610..0485fdfd0d 100644 --- a/iotbx/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry.py +++ b/iotbx/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry.py @@ -2,24 +2,19 @@ from iotbx.data_manager import DataManager import libtbx.load_env import os -from libtbx import easy_run + def exercise(): - if not libtbx.env.has_module("phenix_regression"): - print("phenix_regression not configured, skipping.") - return - fn="phenix_regression/mmtbx/extract_box_around_model_and_map/tst8.pdb" - pdb_file_name = libtbx.env.find_in_repositories( - relative_path=fn, - test=os.path.isfile) - prefix = "extract_box_around_model_and_map_tst8" - cmd = "phenix.model_map %s output_file_name_prefix=%s grid_step=1" - easy_run.call(cmd%(pdb_file_name,prefix)) - # + data_dir = os.path.dirname(os.path.abspath(__file__)) + data_ccp4 = os.path.join(data_dir, 'data', + 'non_zero_origin_map.ccp4') + data_model = os.path.join(data_dir, 'data', + 'non_zero_origin_model.pdb') + dm = DataManager() mmm = dm.get_map_model_manager( - model_file = pdb_file_name, - map_files = "%s.ccp4"%prefix) + model_file = data_model, + map_files = data_ccp4) box_mmm = mmm.extract_all_maps_around_model() @@ -28,18 +23,18 @@ def exercise(): assert not box_mmm.crystal_symmetry().is_similar_symmetry( mmm.crystal_symmetry()) assert box_mmm.unit_cell_crystal_symmetry().is_similar_symmetry( - mmm.crystal_symmetry()) + mmm.unit_cell_crystal_symmetry()) box_mmm.remove_origin_shift_and_unit_cell_crystal_symmetry() assert box_mmm.crystal_symmetry().is_similar_symmetry(box_cs) assert box_mmm.unit_cell_crystal_symmetry().is_similar_symmetry(box_cs) assert not box_mmm.unit_cell_crystal_symmetry().is_similar_symmetry( mmm.crystal_symmetry()) - box_mmm.write_model("model.pdb") + file_name = box_mmm.write_model("model.cif", format ='cif') box_mmm.write_map("map.ccp4") new_mmm = dm.get_map_model_manager( - model_file = "model.pdb", + model_file = file_name, map_files = "map.ccp4") assert new_mmm.crystal_symmetry().is_similar_symmetry(box_cs) diff --git a/iotbx/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry_cif.py b/iotbx/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry_cif.py new file mode 100644 index 0000000000..8b2348f730 --- /dev/null +++ b/iotbx/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry_cif.py @@ -0,0 +1,47 @@ +from __future__ import absolute_import, division, print_function +from iotbx.data_manager import DataManager +import libtbx.load_env +import os + +def exercise(): + data_dir = os.path.dirname(os.path.abspath(__file__)) + data_ccp4 = os.path.join(data_dir, 'data', + 'non_zero_origin_map.ccp4') + data_model = os.path.join(data_dir, 'data', + 'non_zero_origin_model.cif') + # + dm = DataManager() + mmm = dm.get_map_model_manager( + model_file = data_model, + map_files = data_ccp4) + + box_mmm = mmm.extract_all_maps_around_model() + + box_cs = box_mmm.crystal_symmetry() + + assert not box_mmm.crystal_symmetry().is_similar_symmetry( + mmm.crystal_symmetry()) + assert box_mmm.unit_cell_crystal_symmetry().is_similar_symmetry( + mmm.unit_cell_crystal_symmetry()) + + box_mmm.remove_origin_shift_and_unit_cell_crystal_symmetry() + assert box_mmm.crystal_symmetry().is_similar_symmetry(box_cs) + assert box_mmm.unit_cell_crystal_symmetry().is_similar_symmetry(box_cs) + assert not box_mmm.unit_cell_crystal_symmetry().is_similar_symmetry( + mmm.crystal_symmetry()) + file_name = box_mmm.write_model("model.cif", format ='cif') + box_mmm.write_map("map.ccp4") + + new_mmm = dm.get_map_model_manager( + model_file = file_name, + map_files = "map.ccp4") + + assert new_mmm.crystal_symmetry().is_similar_symmetry(box_cs) + assert new_mmm.unit_cell_crystal_symmetry().is_similar_symmetry(box_cs) + +if (__name__ == "__main__"): + import time + t0 = time.time() + exercise() + print("Time: %6.4f"%(time.time()-t0)) + print("OK") diff --git a/iotbx/regression/tst_map_model_manager_cif.py b/iotbx/regression/tst_map_model_manager_cif.py new file mode 100644 index 0000000000..c2a265553f --- /dev/null +++ b/iotbx/regression/tst_map_model_manager_cif.py @@ -0,0 +1,298 @@ +from __future__ import absolute_import, division, print_function +import os +import libtbx.load_env +from iotbx.data_manager import DataManager +from iotbx.map_model_manager import match_map_model_ncs, map_model_manager +from iotbx.phil import parse +from libtbx.program_template import ProgramTemplate +from libtbx.test_utils import approx_equal +from libtbx.utils import Sorry +from libtbx.test_utils import show_diff + +def test_01(): + + # Source data + + data_dir = os.path.dirname(os.path.abspath(__file__)) + data_ccp4 = os.path.join(data_dir, 'data', + 'non_zero_origin_map.ccp4') + data_pdb = os.path.join(data_dir, 'data', + 'non_zero_origin_model.cif') + data_ncs_spec = os.path.join(data_dir, 'data', + 'non_zero_origin_ncs_spec.ncs_spec') + + # DataManager + + dm = DataManager(['ncs_spec','model', 'real_map', 'phil']) + dm.set_overwrite(True) + + # Read in map and model and ncs + + map_file=data_ccp4 + dm.process_real_map_file(map_file) + mm = dm.get_real_map(map_file) + + model_file=data_pdb + dm.process_model_file(model_file) + model = dm.get_model(model_file) + + ncs_file=data_ncs_spec + dm.process_ncs_spec_file(ncs_file) + ncs = dm.get_ncs_spec(ncs_file) + + ncs_dc = ncs.deep_copy() + + mmmn = match_map_model_ncs() + mmmn.add_map_manager(mm) + mmmn.add_model(model) + mmmn.add_ncs_object(ncs) + + # Save it + mmmn_dc=mmmn.deep_copy() + + # Test creating mmm from model: + mmm_from_model = model.as_map_model_manager(create_model_map = False) + mmm_from_model = model.as_map_model_manager(create_model_map = True, + resolution = 5) + assert mmm_from_model.map_manager() is not None + + # Make sure we can add an ncs object that is either shifted or not + mmmn_dcdc=mmmn.deep_copy() + new_mmmn = match_map_model_ncs() + new_mmmn.add_map_manager(mmmn_dcdc.map_manager()) + new_mmmn.add_model(mmmn_dcdc.model()) + new_mmmn.add_ncs_object(mmmn_dcdc.ncs_object()) + assert new_mmmn.ncs_object().shift_cart() == new_mmmn.map_manager().shift_cart() + + mmmn_dcdc=mmmn.deep_copy() + new_mmmn = match_map_model_ncs() + new_mmmn.add_map_manager(mmmn_dcdc.map_manager()) + new_mmmn.add_model(mmmn_dcdc.model()) + new_mmmn.add_ncs_object(ncs_dc) + assert new_mmmn.ncs_object().shift_cart() == new_mmmn.map_manager().shift_cart() + + + original_ncs=mmmn.ncs_object() + assert approx_equal((24.0528, 11.5833, 20.0004), + tuple(original_ncs.ncs_groups()[0].translations_orth()[-1]), + eps=0.1) + + assert tuple(mmmn._map_manager.origin_shift_grid_units) == (0,0,0) + + # Shift origin to (0,0,0) + mmmn=mmmn_dc.deep_copy() # fresh version of match_map_model_ncs + mmmn.shift_origin() + new_ncs=mmmn.ncs_object() + assert tuple(mmmn._map_manager.origin_shift_grid_units) == (100,100,100) + + mmmn.write_model('s.pdb') + mmmn.write_map('s.mrc') + + shifted_ncs=mmmn.ncs_object() + assert approx_equal((-153.758, -74.044, -127.487), + tuple(shifted_ncs.ncs_groups()[0].translations_orth()[-1]),eps=0.1) + + + # Shift a model and shift it back + + mmmn=mmmn_dc.deep_copy() # fresh version of match_map_model_ncs + model=mmmn.model() + shifted_model=mmmn.shift_model_to_match_working_map(model=model) + model_in_original_position=mmmn.shift_model_to_match_original_map( + model=shifted_model) + assert (approx_equal(model.get_sites_cart(), # not a copy + shifted_model.get_sites_cart())) + assert approx_equal(model.get_sites_cart(), + model_in_original_position.get_sites_cart()) + + # test data_manager map_model_manager + generated_mmm = dm.get_map_model_manager() + print(generated_mmm) + assert(isinstance(generated_mmm,map_model_manager)) + + + # Generate a map and model + + import sys + mmm=map_model_manager(log=sys.stdout) + mmm.generate_map() + model=mmm.model() + mm=mmm.map_manager() + assert approx_equal( + model.get_sites_cart()[0], (14.476, 10.57, 8.34) ,eps=0.01) + assert approx_equal(mm.map_data()[10,10,10],-0.0506,eps=0.001) + # Save it + mmm_dc=mmm.deep_copy() + + # Create model from sites + mmm_sites = mmm_dc.deep_copy() + from scitbx.array_family import flex + sites_cart = flex.vec3_double() + sites_cart.append((3,4,5)) + mmm_sites.model_from_sites_cart(sites_cart = sites_cart, + model_id = 'new_model') + assert mmm_sites.get_model_by_id('new_model').get_sites_cart()[0] == (3,4,5) + ph_sites = mmm_sites.get_model_by_id('new_model').get_hierarchy() + text_sites = mmm_sites.get_model_by_id('new_model').model_as_pdb() + + # Create model from hierarchy + mmm_sites = mmm_dc.deep_copy() + mmm_sites.model_from_hierarchy(hierarchy = ph_sites, + model_id = 'new_model') + assert mmm_sites.get_model_by_id('new_model').get_sites_cart()[0] == (3,4,5) + + # Create model from text + mmm_sites = mmm_dc.deep_copy() + mmm_sites.model_from_text(text = text_sites, + model_id = 'new_model') + assert mmm_sites.get_model_by_id('new_model').get_sites_cart()[0] == (3,4,5) + + + + # Set crystal_symmetry and unit_cell_crystal_symmetry and shift_cart + # Box and shift the map_model_manager so we have new coordinate system + mmm_sites.box_all_maps_around_model_and_shift_origin(box_cushion=4.5) + new_model = mmm_sites.get_model_by_id('new_model') + assert approx_equal((3., 4., 5.0), + mmm_sites.get_model_by_id('new_model').get_sites_cart()[0]) + + # arbitrarily set unit_cell crystal symmetry of model to + # match crystal_symmetry. First have to set shift_cart to None + new_model.set_shift_cart(shift_cart = None) + new_model.set_unit_cell_crystal_symmetry_and_shift_cart() + assert new_model.crystal_symmetry() != mmm_sites.crystal_symmetry() + + # now set crystal symmetries and shift cart of model to match the manager + mmm_sites.set_model_symmetries_and_shift_cart_to_match_map(new_model) + assert new_model.crystal_symmetry().is_similar_symmetry( + mmm_sites.crystal_symmetry()) + assert new_model.unit_cell_crystal_symmetry().is_similar_symmetry( + mmm_sites.unit_cell_crystal_symmetry()) + assert new_model.shift_cart() == mmm_sites.shift_cart() + + # Import hierarchy into a model and set symmetries and shift to match + mmm_sites.model_from_hierarchy( + hierarchy = mmm_sites.model().get_hierarchy(), + model_id='model_from_hierarchy') + assert not show_diff(mmm_sites.get_model_by_id('model_from_hierarchy').model_as_pdb(), + mmm_sites.get_model_by_id('model').model_as_pdb()) + + + # Check on wrapping + assert not mm.wrapping() # this one should not wrap because it is zero at edges + + # Make a new one with no buffer so it is not zero at edges + mmm=map_model_manager() + mmm.generate_map(box_cushion=0) + mm=mmm.map_manager() + # check its compatibility with wrapping + assert mm.is_consistent_with_wrapping() + mmm.show_summary() + + # now box it + sel=mmm.model().selection("resseq 221:221") + new_model=mmm.model().deep_copy().select(sel) + new_mmm=map_model_manager(model=new_model,map_manager=mm.deep_copy()) + new_mmm.box_all_maps_around_model_and_shift_origin() + new_mm=new_mmm.map_manager() + + assert not new_mm.wrapping() + assert not new_mm.is_consistent_with_wrapping() + + # now box it with selection + new_mmm_1=map_model_manager( + model=mmm.model().deep_copy(),map_manager=mm.deep_copy()) + new_mmm_1.box_all_maps_around_model_and_shift_origin( + selection_string="resseq 221:221") + new_mm_1=new_mmm_1.map_manager() + + assert not new_mm_1.wrapping() + assert not new_mm_1.is_consistent_with_wrapping() + assert new_mm_1.map_data().all()== new_mm.map_data().all() + + # create map_model_manager with just half-maps + mm1=mm.deep_copy() + mm2=mm.deep_copy() + map_data=mm2.map_data() + map_data+=1. + new_mmm=map_model_manager(model=mmm.model().deep_copy(), + map_manager_1=mm1, + map_manager_2=mm2) + assert new_mmm._map_dict.get('map_manager') is None # should not be any yet + assert approx_equal(new_mmm.map_manager().map_data()[232], + mm.deep_copy().map_data()[232]+0.5) + assert new_mmm._map_dict.get('map_manager') is not None # now should be there + + # generate map data from a model + mm1=mm.deep_copy() + mm2=mm.deep_copy() + new_mmm=map_model_manager(model=mmm.model().deep_copy(), map_manager=mm1) + mmm.generate_map(model=mmm.model()) + mm=mmm.map_manager() + mmm.show_summary() + + # check get_map_model_manager function + dm = DataManager(['model']) + assert not hasattr(dm, 'get_map_model_manager') + dm = DataManager(['real_map']) + assert not hasattr(dm, 'get_map_model_manager') + dm = DataManager(['sequence']) + assert not hasattr(dm, 'get_map_model_manager') + dm = DataManager(['model', 'real_map']) + assert hasattr(dm, 'get_map_model_manager') + + # usage + dm.get_map_model_manager(model_file=data_pdb, map_files=data_ccp4) + dm.get_map_model_manager(model_file=data_pdb, map_files=[data_ccp4]) + dm.get_map_model_manager(model_file=data_pdb, map_files=[data_ccp4, data_ccp4, data_ccp4]) + dm.get_map_model_manager(model_file=data_pdb, map_files=data_ccp4, ignore_symmetry_conflicts=True) + + # errors + try: + dm.get_map_model_manager(model_file=data_pdb, map_files=data_ccp4, from_phil=True) + except Sorry as e: + assert 'from_phil is set to True' in str(e) + try: + dm.get_map_model_manager(model_file=data_pdb, map_files=data_ccp4, abc=123) + except TypeError as e: + assert 'unexpected keyword argument' in str(e) + try: + dm.get_map_model_manager(model_file=data_pdb, map_files=[data_ccp4, data_ccp4]) + except Sorry as e: + assert '1 full map and 2 half maps' in str(e) + + # PHIL + class test_program(ProgramTemplate): + master_phil_str = ''' +include scope iotbx.map_model_manager.map_model_phil_str +''' + working_phil_str = ''' + map_model { + full_map = %s + half_map = %s + half_map = s.mrc + model = %s + } +''' % (data_ccp4, data_ccp4, data_pdb) + + master_phil = parse(test_program.master_phil_str, process_includes=True) + working_phil = master_phil.fetch(parse(working_phil_str)) + tp = test_program(dm, working_phil.extract()) + + try: + dm.get_map_model_manager(from_phil=True) + except Exception as e: + assert 'ignore_symmetry_conflicts' in str(e) + try: + dm.get_map_model_manager(from_phil=True, ignore_symmetry_conflicts=True) + except AssertionError: + pass + +# ---------------------------------------------------------------------------- + +if (__name__ == '__main__'): + if libtbx.env.find_in_repositories(relative_path='chem_data') is not None: + test_01() + else: + print('Skip test_01, chem_data not available') + print ("OK") diff --git a/iotbx/regression/tst_map_model_manager_model_sharpening_5_cif.py b/iotbx/regression/tst_map_model_manager_model_sharpening_5_cif.py new file mode 100644 index 0000000000..959e86322b --- /dev/null +++ b/iotbx/regression/tst_map_model_manager_model_sharpening_5_cif.py @@ -0,0 +1,75 @@ +from __future__ import absolute_import, division, print_function +import os, sys +import libtbx.load_env +from iotbx.data_manager import DataManager +from iotbx.map_model_manager import map_model_manager + +def test_01(method = 'model_sharpen', + expected_results=None): + + # Source data + + data_dir = os.path.dirname(os.path.abspath(__file__)) + data_ccp4 = os.path.join(data_dir, 'data', + 'non_zero_origin_map.ccp4') + data_pdb = os.path.join(data_dir, 'data', + 'non_zero_origin_model.cif') + data_ncs_spec = os.path.join(data_dir, 'data', + 'non_zero_origin_ncs_spec.ncs_spec') + + # Read in data + + dm = DataManager(['ncs_spec','model', 'real_map', 'phil']) + dm.set_overwrite(True) + + map_file=data_ccp4 + dm.process_real_map_file(map_file) + mm = dm.get_real_map(map_file) + + model_file=data_pdb + dm.process_model_file(model_file) + model = dm.get_model(model_file) + + ncs_file=data_ncs_spec + dm.process_ncs_spec_file(ncs_file) + ncs = dm.get_ncs_spec(ncs_file) + + mmm=map_model_manager( + model = model, + map_manager_1 = mm.deep_copy(), + map_manager_2 = mm.deep_copy(), + ncs_object = ncs, + wrapping = False) + mmm.add_map_manager_by_id( + map_id='external_map',map_manager=mmm.map_manager().deep_copy()) + mmm.set_resolution(3) + mmm.set_log(sys.stdout) + + dc = mmm.deep_copy() + + sharpen_method = getattr(mmm,method) + + # sharpen by method (can be model_sharpen, half_map_sharpen or + # external_sharpen) + + sharpen_method(anisotropic_sharpen = False, n_bins=10) + assert mmm.map_model_cc() > 0.9 + sharpen_method(anisotropic_sharpen = False, n_bins=10, + local_sharpen = True) + assert mmm.map_model_cc() > 0.9 + sharpen_method(anisotropic_sharpen = True, n_bins=10) + assert mmm.map_model_cc() > 0.9 + sharpen_method(anisotropic_sharpen = True, n_bins=10, + local_sharpen = True, n_boxes = 1) + assert mmm.map_model_cc() > 0.9 + + +# ---------------------------------------------------------------------------- + +if (__name__ == '__main__'): + if libtbx.env.find_in_repositories(relative_path='chem_data') is not None: + test_01(method = 'model_sharpen') + else: + print('Skip test_01, chem_data not available') + print ("OK") + diff --git a/iotbx/run_tests.py b/iotbx/run_tests.py index 47e771f9fd..43dbb473ce 100644 --- a/iotbx/run_tests.py +++ b/iotbx/run_tests.py @@ -98,7 +98,10 @@ "$D/regression/tst_bioinformatics.py", "$D/regression/tst_box_around_molecule.py", "$D/regression/tst_mmcif_segids.py", - "$D/regression/tst_hierarchy_pdb_v3.py", + "$D/regression/tst_hierarchy_forward_compatible_pdb.py", + "$D/regression/tst_map_model_manager_cif.py", + "$D/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry_cif.py", + "$D/regression/tst_map_model_manager_model_sharpening_5_cif.py", "$D/regression/tst_mmcif_multimodel.py", "$D/regression/tst_add_conformations.py", "$D/regression/tst_symmetry.py", diff --git a/libtbx/command_line/remove_unused_imports.py b/libtbx/command_line/remove_unused_imports.py new file mode 100644 index 0000000000..36e53c5d5b --- /dev/null +++ b/libtbx/command_line/remove_unused_imports.py @@ -0,0 +1,130 @@ +from __future__ import division +from __future__ import print_function + +from libtbx import group_args + +def run(args): + if len(args) != 1: + print("phenix.python remove_unused_args ") + return + file_name = args[0] + + instruction_list = get_instruction_list(file_name) + for file_instructions in instruction_list: + edit_one_file(file_instructions) + +def edit_one_file(file_instructions): + file_name = file_instructions.file_name + lines = [] + for l in open(file_name).readlines(): + lines.append(l.rstrip()) + ok = True + did_something = False + for instruction in file_instructions.instructions: + word = instruction.key + i = instruction.line_number - 1 + spl = get_split_text(lines[i]) + if not spl: + ok = False + continue + if spl[-1] == "\\": + ok = False + continue + if not word in spl: + ok = False + continue + info = remove_word(lines[i], word) + if info.removed: + lines[i] = info.new_line + did_something = True + new_text = "\n".join(lines) + if did_something: + f = open(file_name,'w') + f.write(new_text + "\n") + f.close() + if ok: + print("Edited %s" %(file_name)) + else: + print("Edited %s with errors" %(file_name)) + elif ok: + print("Nothing done with %s" %(file_name)) + else: + print("Errors in working with %s" %(file_name)) + +def remove_word(line, word): + ''' from x import word, other_word + import word, other_word + from word import word + ''' + info = group_args(group_args_type = 'remove_word info', + word = word, + line = line, + new_line = line, + removed = None,) + spl = get_split_text(line) + if not word in spl: + return info + spl = remove_word_after_key(spl, word, key = 'as') + spl = remove_word_after_key(spl, word, key = 'import') + starting = get_blanks_at_start(line) + new_line = starting + " ".join(spl) + new_line = new_line.replace(", ,",",").replace("import ,", "import").replace("as,", "as") + if new_line.endswith(","): + new_line = new_line[:-1].rstrip() + if new_line.endswith("as") or new_line.endswith("import"): # nothing left + info.new_line = "" + info.removed = True + return info + info.new_line = new_line + info.removed = True + return info + +def remove_word_after_key(spl, word, key = None): + new_spl = [] + found_key = (key is None) + for w in spl: + if w == key: + found_key = True + if (not found_key) or (w != word): + new_spl.append(w) + else: + pass # skip word after key is found + return new_spl + +def get_blanks_at_start(line): + starting = "" + for a in line: + if a == " ": + starting += a + else: + return starting + return starting +def get_split_text(line): + return line.strip().replace(","," , ").split() + +def get_instruction_list(file_name): + all_instructions = [] + for line in open(file_name).readlines(): + if line.startswith("In file"): + line = line.replace(":","") + fn = line.split()[-1] + file_instructions=group_args(group_args_type = 'instructions', + file_name = fn, + instructions= [], + ) + all_instructions.append(file_instructions) + elif line.find("imported at line") > -1: + spl = line.split() + key = spl[0] + line_number = int(spl[-1]) + single_import = group_args(group_args_type = 'single import', + key = key, + line_number = line_number, + ) + file_instructions.instructions.append(single_import) + return all_instructions + + +if __name__ == "__main__": + import sys + run(sys.argv[1:]) diff --git a/libtbx/program_template.py b/libtbx/program_template.py index 75bd16aca0..24183ffd79 100644 --- a/libtbx/program_template.py +++ b/libtbx/program_template.py @@ -129,6 +129,14 @@ class ProgramTemplate(object): serial_format = "%03d" .type = str .help = Format for serial number + target_output_format = *None pdb mmcif + .type = choice + .help = Desired output format (if possible). Choices are None (\ + try to use input format), pdb, mmcif. If output model\ + does not fit in pdb format, mmcif will be used. \ + Default is pdb. + .short_caption = Desired output format + overwrite = False .type = bool .help = Overwrite files when set to True @@ -207,6 +215,7 @@ def __init__(self, data_manager, params, master_phil=None, logger=None): if self.data_manager is not None: self.data_manager.set_default_output_filename( self.get_default_output_filename()) + self.set_target_output_format() try: self.data_manager.set_overwrite(self.params.output.overwrite) except AttributeError: @@ -386,6 +395,24 @@ def get_full_phil_str(self, diff=False): ''' return self.get_data_phil_str(diff=diff) + self.get_program_phil_str(diff=diff) + # --------------------------------------------------------------------------- + def set_target_output_format(self): + """ Try to set the desired output format if not set by user (pdb or mmcif) + """ + assert self.data_manager is not None + if not hasattr(self.data_manager,'set_target_output_format'): + return # No models in this data_manager + + from iotbx.pdb.utils import set_target_output_format_in_params + if hasattr(self.data_manager, 'get_default_model_name'): + file_name = self.data_manager.get_default_model_name() + else: + file_name = None + target_output_format = set_target_output_format_in_params(self.params, + file_name = file_name, + out = self.logger) + self.data_manager.set_target_output_format(target_output_format) + # --------------------------------------------------------------------------- def get_default_output_filename(self, prefix=Auto, suffix=Auto, serial=Auto, filename=Auto): diff --git a/libtbx/python_code_parsing.py b/libtbx/python_code_parsing.py index e195c335de..7b6c021603 100644 --- a/libtbx/python_code_parsing.py +++ b/libtbx/python_code_parsing.py @@ -47,7 +47,7 @@ def __init__(self, python_source_code=None, python_source_filename=None, ignore_imports_flagged_by_comments=()): assert (python_source_code, python_source_filename).count(None) == 1 if python_source_code is None: - python_source_code = file(python_source_filename).read() + python_source_code = open(python_source_filename).read() super(unused_imports, self).__init__() self.comment_flags = ignore_imports_flagged_by_comments self.python_source_line = python_source_code.splitlines() diff --git a/libtbx/test_utils/__init__.py b/libtbx/test_utils/__init__.py index e7c0c08509..98b6e6ad25 100644 --- a/libtbx/test_utils/__init__.py +++ b/libtbx/test_utils/__init__.py @@ -848,5 +848,22 @@ def exercise(): assert precision_approx_equal(0.799999,0.800004,precision=18)==False print("OK") +def convert_pdb_to_cif_for_pdb_str(locals, chain_addition = "ZXLONG", key_str="pdb_str"): + # Converts all the strings that start with "pdb_str" from PDB to mmcif + # format, adding chain_addition to chain names + keys = list(locals.keys()) + for key in keys: + if (not key.startswith(key_str)) or (type(locals[key]) != type("abc")): + continue + from iotbx.pdb.utils import get_pdb_input + pdb_inp = get_pdb_input(locals[key]) + ph = pdb_inp.construct_hierarchy() + if ph.overall_counts().n_residues < 1: + continue + for model in ph.models(): + for chain in model.chains(): + chain.id = "%s%s" %(chain.id,chain_addition) + new_string = ph.as_mmcif_string(crystal_symmetry = pdb_inp.crystal_symmetry()) + locals[key] = new_string if (__name__ == "__main__"): exercise() diff --git a/libtbx/tst_utils.py b/libtbx/tst_utils.py index 44b1308994..a251615df8 100644 --- a/libtbx/tst_utils.py +++ b/libtbx/tst_utils.py @@ -400,6 +400,28 @@ def exercise_round2(): def exercise_guess_total_memory(): assert(utils.guess_total_memory() > 0) +def exercise_display_context(): + text = """ + line with word1 + another line + another line with word2 + another line with word1 + line with word3 +""" + from libtbx.utils import display_context + text_block_list = display_context(text = text, + n_context = 1, search_word = 'word1', quiet = True) + assert [text_block_list[0].text_block] == [ ' \n ** line with word1\n another line\n'] + + text_block_list = display_context(text = text, + n_context = 1, search_word = 'word2', quiet = True) + assert [text_block_list[0].text_block] == [ ' another line\n ** another line with word2\n another line with word1\n'] + + text_block_list = display_context(text = text, + n_context = 1, search_word = 'word2', required_word ='word1', quiet = True) + assert [text_block_list[0].text_block] == [ ' another line\n ** another line with word2\n another line with word1\n'] + + def run(args): assert len(args) == 0 if '--exercise-retrieve-unless-exists' in args: @@ -432,6 +454,7 @@ def run(args): exercise_dir_utils() exercise_group_args() exercise_round2() + exercise_display_context() print(utils.format_cpu_times()) if (__name__ == "__main__"): diff --git a/mmtbx/building/merge_models.py b/mmtbx/building/merge_models.py index 0b8e81b2ed..5e5c0d1f5a 100644 --- a/mmtbx/building/merge_models.py +++ b/mmtbx/building/merge_models.py @@ -552,15 +552,6 @@ def smooth_cc_values(cc_dict=None, return smoothed_cc_dict -def remove_ter(text): # remove blank lines and TER records - new_lines=[] - for line in flex.split_lines(text): - if not line.replace(" ",""): continue - if line.startswith("TER"): continue - new_lines.append(line) - return "\n".join(new_lines) - - # NOTE: Match defaults here and in params at top of file # : copy from defaults if params is not None below # : See explanations of parameters in params at top of file @@ -695,6 +686,7 @@ def run( # Save composite model, chain by chain composite_model_stream=StringIO() + sel_ph_list = [] for chain_id_and_resseq in chain_id_and_resseq_list: f=StringIO() @@ -721,7 +713,7 @@ def run( verbose=verbose,out=out) # figure out all the places where crossover can occur. - # FIXME: order of keys changes in py2/3 vthis could be bad + # FIXME: order of keys changes in py2/3 vthis could be bad. No all are same. n_residues=cc_dict[list(cc_dict.keys())[0]].size() crossover_dict=get_crossover_dict( @@ -811,7 +803,6 @@ def run( # Note residue values. We are going to pick each residue from one of # the models - for model in ph.models(): for chain in model.chains(): if chain.id != chain_id: continue @@ -820,27 +811,29 @@ def run( residue_list.append(rg.resseq) residue_list.sort() assert len(best_model.source_list)==len(residue_list) - + from mmtbx.secondary_structure.find_ss_from_ca import remove_ter_or_break for i in range(len(residue_list)): atom_selection=get_atom_selection(model_id=best_model.source_list[i], resseq_sel=residue_list[i]) asc=ph.atom_selection_cache() sel=asc.selection(string = atom_selection) sel_hierarchy=ph.select(sel) - print(remove_ter(sel_hierarchy.as_pdb_string()), file=composite_model_stream) - - # All done, make a new pdb_hierarchy - pdb_string=composite_model_stream.getvalue() - pdb_inp=iotbx.pdb.input(source_info=None, lines = pdb_string) - pdb_hierarchy=pdb_inp.construct_hierarchy() + sel_hierarchy = remove_ter_or_break(sel_hierarchy) + sel_ph_list.append(sel_hierarchy) + from iotbx.pdb.utils import add_hierarchies + pdb_hierarchy = remove_ter_or_break(add_hierarchies(sel_ph_list, + create_new_chain_ids_if_necessary = False)) + print(pdb_hierarchy.as_pdb_string()) if pdb_out: - f=open(pdb_out,'w') - print(pdb_hierarchy.as_pdb_string(crystal_symmetry=crystal_symmetry), file=f) + info = pdb_hierarchy.pdb_or_mmcif_string_info(target_filename = pdb_out, + crystal_symmetry = crystal_symmetry) + f=open(info.file_name,'w') + print(info.pdb_string, file = f) print("Final model is in: %s\n" %(f.name)) f.close() - return pdb_hierarchy + return pdb_hierarchy, pdb_out if (__name__ == "__main__"): args=sys.argv[1:] diff --git a/mmtbx/building/minimize_chain.py b/mmtbx/building/minimize_chain.py index a55b6e6b4e..11f74df011 100644 --- a/mmtbx/building/minimize_chain.py +++ b/mmtbx/building/minimize_chain.py @@ -214,18 +214,15 @@ def get_pdb_inp( pdb_string=open(pdb_in).read() else: raise Sorry("Need an input PDB file") - pdb_inp=iotbx.pdb.input(source_info=None, lines = pdb_string) + from iotbx.pdb.utils import get_pdb_input + pdb_inp=get_pdb_input(pdb_string) cryst1_line=iotbx.pdb.format_cryst1_record( crystal_symmetry=crystal_symmetry) - if not pdb_inp.crystal_symmetry(): # get it - from six.moves import cStringIO as StringIO - f=StringIO() - print(cryst1_line, file=f) - print(pdb_string, file=f) - pdb_string=f.getvalue() - pdb_inp=iotbx.pdb.input(source_info=None, lines = pdb_string) if pdb_string is None: - pdb_string=pdb_inp.as_pdb_string() + ph = pdb_inp.construct_hierarchy() + info = ph.pdb_or_mmcif_string_info( + crystal_symmetry = crystal_symmetry) + pdb_string = info.pdb_string return pdb_inp,cryst1_line,pdb_string def run_one_cycle( diff --git a/mmtbx/command_line/map_box.py b/mmtbx/command_line/map_box.py index 23e42b3b1b..d2bc3284c0 100644 --- a/mmtbx/command_line/map_box.py +++ b/mmtbx/command_line/map_box.py @@ -1123,7 +1123,7 @@ def run(args, gridding = params.output_unit_cell_grid) if mam.map_manager().ncs_object(): # mam.map_manager().ncs_object().display_all() - from scitbx.array_family import flex + mam.map_manager().ncs_object().set_shift_cart( mam.map_manager().shift_cart()) @@ -1215,9 +1215,10 @@ def run(args, if(params.output_file_name_prefix is None): filename = "%s_box"%output_prefix else: filename = "%s"%params.output_file_name_prefix - dm.write_model_file(model, filename = filename, extension = ".pdb") + full_filename = dm.write_model_file( + model, filename = filename, extension = ".pdb") print("Writing boxed PDB with box unit cell to %s" %( - "%s.pdb" %filename), file = log) + "%s" %filename), file = log) # Write NCS file if NCS if ncs_object and ncs_object.max_operators()>0: diff --git a/mmtbx/command_line/sort_hetatms.py b/mmtbx/command_line/sort_hetatms.py index 6ad1364cae..726bd7df0b 100644 --- a/mmtbx/command_line/sort_hetatms.py +++ b/mmtbx/command_line/sort_hetatms.py @@ -398,30 +398,38 @@ def run(args, out=sys.stdout, sorting_params=None): if (params.output_file is None): params.output_file = os.path.splitext( os.path.basename(params.file_name))[0] + "_sorted.pdb" - f = open(params.output_file, "w") - if (params.preserve_remarks): - remarks = pdb_in.remark_section() - if (len(remarks) > 0): - f.write("\n".join(remarks)) - f.write("\n") - pdb_str = result.pdb_hierarchy.as_pdb_string(crystal_symmetry=final_symm) - if (params.remove_hetatm_ter_records): - n_hetatm = n_atom = 0 - for line in pdb_str.splitlines(): - if (line[0:3] == "TER"): - if (n_atom != 0): - f.write("%s\n" % line) - n_atom = n_hetatm = 0 - continue - elif (line.startswith("HETATM")): - n_hetatm += 1 - elif (line.startswith("ATOM")): - n_atom += 1 - f.write("%s\n" % line) - else : - f.write(pdb_str) - f.write("END") - f.close() + if (not result.pdb_hierarchy.fits_in_pdb_format()): + info = result.pdb_hierarchy.pdb_or_mmcif_string_info( + target_filename = params.output_file, + write_file = True) + params.output_file = info.file_name + + else: # standard pdb file + f = open(params.output_file, "w") + if (params.preserve_remarks): + remarks = pdb_in.remark_section() + if (len(remarks) > 0): + f.write("\n".join(remarks)) + f.write("\n") + pdb_str = result.pdb_hierarchy.as_pdb_string(crystal_symmetry=final_symm) + if (params.remove_hetatm_ter_records): + n_hetatm = n_atom = 0 + for line in pdb_str.splitlines(): + if (line[0:3] == "TER"): + if (n_atom != 0): + f.write("%s\n" % line) + n_atom = n_hetatm = 0 + continue + elif (line.startswith("HETATM")): + n_hetatm += 1 + elif (line.startswith("ATOM")): + n_atom += 1 + f.write("%s\n" % line) + else : + f.write(pdb_str) + f.write("END") + f.close() + print("Wrote %s" % params.output_file, file=out) out.flush() return sort_hetatms_result( diff --git a/mmtbx/masks/tst_masks.py b/mmtbx/masks/tst_masks.py index 487f3a82c9..4f5befb901 100644 --- a/mmtbx/masks/tst_masks.py +++ b/mmtbx/masks/tst_masks.py @@ -366,6 +366,7 @@ def run(): exercise_4() debug_utils.parse_options_loop_space_groups(sys.argv[1:], run_call_back, symbols_to_stdout=True, symbols_to_stderr=False) + print("OK") if (__name__ == "__main__"): run() diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index 854e4bd2e3..058bd1f89b 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -24,7 +24,7 @@ from cctbx.array_family import flex from cctbx import xray from cctbx import adptbx -from cctbx import geometry_restraints + from cctbx import adp_restraints from cctbx import crystal from cctbx import uctbx @@ -37,8 +37,8 @@ from mmtbx.geometry_restraints.torsion_restraints.utils import check_for_internal_chain_ter_records import mmtbx.tls.tools as tls_tools from mmtbx import ias -from mmtbx import utils -from mmtbx import ncs + + from mmtbx.ncs.ncs_utils import apply_transforms from mmtbx.command_line import find_tls_groups from mmtbx.monomer_library.pdb_interpretation import grand_master_phil_str @@ -1683,6 +1683,55 @@ def can_be_unique_with_biomt(self): return False return True + def pdb_or_mmcif_string_info(self, + target_filename = None, target_format = None, + segid_as_auth_segid = True, + write_file = False, + data_manager = None, + overwrite = True, + remark_section = None, + **kw): + # Method to allow shifting from general writing as pdb + # to writing as mmcif, with the change in two places (here and hierarchy.py) + # Note default of segid_as_auth_segid = True, different from + # as_mmcif_string() + + if target_format in ['None',None]: # set the default format here + target_format = 'pdb' + assert target_format in ['pdb','mmcif'] + + if target_format == 'pdb': + if self.get_hierarchy().fits_in_pdb_format(): + pdb_str = self.model_as_pdb(**kw) + is_mmcif = False + if remark_section: + pdb_str = "%s\n%s" %(remark_section, pdb_str) + else: + pdb_str = self.model_as_mmcif( + segid_as_auth_segid = segid_as_auth_segid,**kw) + is_mmcif = True + else: + pdb_str = self.model_as_mmcif(segid_as_auth_segid = segid_as_auth_segid,**kw) + is_mmcif = True + if target_filename: + import os + path,ext = os.path.splitext(target_filename) + if is_mmcif: + ext = ".cif" + else: + ext = ".pdb" + target_filename = "%s%s" %(path,ext) + if write_file and target_filename: + if not data_manager: + from iotbx.data_manager import DataManager + data_manager = DataManager() + target_filename = data_manager.write_model_file(pdb_str, target_filename, + overwrite = overwrite) + return group_args(group_args_type = 'pdb_string and filename', + pdb_string = pdb_str, + file_name = target_filename, + is_mmcif = is_mmcif) + def model_as_mmcif(self, cif_block_name = "default", output_cs = True, diff --git a/mmtbx/process_predicted_model.py b/mmtbx/process_predicted_model.py index 727174c72d..430aa08e1b 100644 --- a/mmtbx/process_predicted_model.py +++ b/mmtbx/process_predicted_model.py @@ -425,7 +425,7 @@ def process_predicted_model( # Apply this selection to full hierarchy asc1 = ph.atom_selection_cache() sel = asc1.selection(selection_string_2) - working_ph = ph.select(sel) + working_ph = ph.select(sel).deep_copy() # XXX for double selection if p.minimum_sequential_residues: # # Remove any very short segments @@ -440,7 +440,7 @@ def process_predicted_model( sel2 = asc1.selection(selection_to_remove) sel = ~ (~sel | sel2) - new_ph = ph.select(sel) + new_ph = ph.select(sel).deep_copy() n_after = new_ph.overall_counts().n_residues print("Total of %s of %s residues kept after B-factor filtering" %( n_after, n_before), file = log) @@ -472,7 +472,7 @@ def process_predicted_model( ) if not keep_all: - removed_ph = ph.select(~sel) + removed_ph = ph.select(~sel).deep_copy() from mmtbx.secondary_structure.find_ss_from_ca import model_info, \ split_model remainder_sequence_str = "" diff --git a/mmtbx/programs/process_predicted_model.py b/mmtbx/programs/process_predicted_model.py index 33e3b1578c..f9e3cd5b14 100644 --- a/mmtbx/programs/process_predicted_model.py +++ b/mmtbx/programs/process_predicted_model.py @@ -67,6 +67,14 @@ class Program(ProgramTemplate): } output_files { + target_output_format = *None pdb mmcif + .type = choice + .help = Desired output format (if possible). Choices are None (\ + try to use input format), pdb, mmcif. If output model\ + does not fit in pdb format, mmcif will be used. \ + Default is pdb. + .short_caption = Desired output format + processed_model_prefix = None .type = str .help = Output file with processed models will begin with this prefix.\ @@ -132,6 +140,9 @@ def run(self): # self.get_data_inputs() # get any file-based information + from iotbx.pdb.utils import set_target_output_format_in_params + set_target_output_format_in_params(self.params) + # self.print_params() self.starting_model = self.model self.model_list = [] @@ -189,7 +200,10 @@ def run(self): mm_to_split = mm # original (multi-char chain IDs) - self.data_manager.write_model_file(mm, self.processed_model_file_name) + + self.processed_model_file_name = self.data_manager.write_model_file( + mm, self.processed_model_file_name, + format=self.params.output_files.target_output_format) final_residues = mm.get_hierarchy().overall_counts().n_residues print("Final residues: %s\n" %(final_residues), file = self.logger) @@ -217,7 +231,9 @@ def run(self): continue mm = limit_output_b(m, maximum_output_b = self.params.output_files.maximum_output_b) - self.data_manager.write_model_file(mm,fn) + fn = self.data_manager.write_model_file(mm,fn, + format=self.params.output_files.target_output_format) + self.processed_model_file_name_list.append(fn) diff --git a/mmtbx/refinement/real_space/explode_and_refine.py b/mmtbx/refinement/real_space/explode_and_refine.py index 534983ca86..955b308a73 100644 --- a/mmtbx/refinement/real_space/explode_and_refine.py +++ b/mmtbx/refinement/real_space/explode_and_refine.py @@ -384,7 +384,7 @@ def merge_models(self, pdb_hierarchy): # if("merge_models" in self.score_method): from mmtbx.building.merge_models import run as merge_models - pdb_hierarchy_merged = merge_models( + pdb_hierarchy_merged, pdb_out = merge_models( map_data = self.map_data, resolution = self.resolution, pdb_hierarchy = pdb_hierarchy, diff --git a/mmtbx/regression/pdbs/AF_json_v3.cif b/mmtbx/regression/pdbs/AF_json_v3.cif new file mode 100644 index 0000000000..697364f7ed --- /dev/null +++ b/mmtbx/regression/pdbs/AF_json_v3.cif @@ -0,0 +1,2690 @@ +data_default +loop_ + _struct_asym.id + A + +loop_ + _chem_comp.id + ALA + ARG + ASN + ASP + CYS + GLN + GLU + GLY + HIS + ILE + LEU + LYS + MET + PHE + PRO + SER + THR + TRP + TYR + VAL + +loop_ + _atom_site.group_PDB + _atom_site.id + _atom_site.label_atom_id + _atom_site.label_alt_id + _atom_site.label_comp_id + _atom_site.auth_asym_id + _atom_site.auth_seq_id + _atom_site.pdbx_PDB_ins_code + _atom_site.Cartn_x + _atom_site.Cartn_y + _atom_site.Cartn_z + _atom_site.occupancy + _atom_site.B_iso_or_equiv + _atom_site.type_symbol + _atom_site.pdbx_formal_charge + _atom_site.label_asym_id + _atom_site.label_entity_id + _atom_site.label_seq_id + _atom_site.pdbx_PDB_model_num + ATOM 1 N . MET A 1 ? -57.09000 22.02700 35.85800 1.000 32.25000 N ? A ? 1 1 + ATOM 2 CA . MET A 1 ? -57.19900 21.78500 34.40300 1.000 32.25000 C ? A ? 1 1 + ATOM 3 C . MET A 1 ? -55.90700 22.22700 33.74800 1.000 32.25000 C ? A ? 1 1 + ATOM 4 O . MET A 1 ? -55.50900 23.34300 34.03100 1.000 32.25000 O ? A ? 1 1 + ATOM 5 CB . MET A 1 ? -58.34700 22.58300 33.75900 1.000 32.25000 C ? A ? 1 1 + ATOM 6 CG . MET A 1 ? -59.72600 21.95900 33.96300 1.000 32.25000 C ? A ? 1 1 + ATOM 7 SD . MET A 1 ? -61.02400 22.90600 33.13300 1.000 32.25000 S ? A ? 1 1 + ATOM 8 CE . MET A 1 ? -62.50000 22.08700 33.79600 1.000 32.25000 C ? A ? 1 1 + ATOM 9 N . ARG A 2 ? -55.35300 21.35000 32.89400 1.000 31.97000 N ? A ? 2 1 + ATOM 10 CA . ARG A 2 ? -54.36700 21.57800 31.81300 1.000 31.97000 C ? A ? 2 1 + ATOM 11 C . ARG A 2 ? -53.05500 22.26900 32.22900 1.000 31.97000 C ? A ? 2 1 + ATOM 12 O . ARG A 2 ? -53.06000 23.38800 32.70000 1.000 31.97000 O ? A ? 2 1 + ATOM 13 CB . ARG A 2 ? -55.05500 22.30900 30.64600 1.000 31.97000 C ? A ? 2 1 + ATOM 14 CG . ARG A 2 ? -56.15800 21.45500 29.99700 1.000 31.97000 C ? A ? 2 1 + ATOM 15 CD . ARG A 2 ? -56.84300 22.20500 28.85000 1.000 31.97000 C ? A ? 2 1 + ATOM 16 NE . ARG A 2 ? -57.89800 21.37900 28.22200 1.000 31.97000 N ? A ? 2 1 + ATOM 17 CZ . ARG A 2 ? -58.16700 21.28500 26.92900 1.000 31.97000 C ? A ? 2 1 + ATOM 18 NH1 . ARG A 2 ? -57.51400 21.96400 26.02900 1.000 31.97000 N ? A ? 2 1 + ATOM 19 NH2 . ARG A 2 ? -59.11200 20.49300 26.50900 1.000 31.97000 N ? A ? 2 1 + ATOM 20 N . GLY A 3 ? -51.89100 21.64600 32.10000 1.000 33.69000 N ? A ? 3 1 + ATOM 21 CA . GLY A 3 ? -51.45900 20.76800 31.01500 1.000 33.69000 C ? A ? 3 1 + ATOM 22 C . GLY A 3 ? -50.39300 21.52400 30.23100 1.000 33.69000 C ? A ? 3 1 + ATOM 23 O . GLY A 3 ? -50.70600 22.50700 29.57400 1.000 33.69000 O ? A ? 3 1 + ATOM 24 N . GLY A 4 ? -49.15000 21.07900 30.35300 1.000 27.70000 N ? A ? 4 1 + ATOM 25 CA . GLY A 4 ? -47.99300 21.60900 29.64400 1.000 27.70000 C ? A ? 4 1 + ATOM 26 C . GLY A 4 ? -46.88900 20.58500 29.80700 1.000 27.70000 C ? A ? 4 1 + ATOM 27 O . GLY A 4 ? -46.19800 20.58000 30.82300 1.000 27.70000 O ? A ? 4 1 + ATOM 28 N . ALA A 5 ? -46.87100 19.63000 28.88100 1.000 33.88000 N ? A ? 5 1 + ATOM 29 CA . ALA A 5 ? -45.92100 18.53900 28.82700 1.000 33.88000 C ? A ? 5 1 + ATOM 30 C . ALA A 5 ? -44.50100 19.10200 28.91500 1.000 33.88000 C ? A ? 5 1 + ATOM 31 O . ALA A 5 ? -44.10500 19.93300 28.10100 1.000 33.88000 O ? A ? 5 1 + ATOM 32 CB . ALA A 5 ? -46.16100 17.78300 27.51300 1.000 33.88000 C ? A ? 5 1 + ATOM 33 N . LYS A 6 ? -43.74600 18.64200 29.91500 1.000 35.59000 N ? A ? 6 1 + ATOM 34 CA . LYS A 6 ? -42.29700 18.56900 29.78100 1.000 35.59000 C ? A ? 6 1 + ATOM 35 C . LYS A 6 ? -42.08200 17.62000 28.61300 1.000 35.59000 C ? A ? 6 1 + ATOM 36 O . LYS A 6 ? -42.36100 16.43300 28.76100 1.000 35.59000 O ? A ? 6 1 + ATOM 37 CB . LYS A 6 ? -41.66300 18.02800 31.07000 1.000 35.59000 C ? A ? 6 1 + ATOM 38 CG . LYS A 6 ? -41.69500 19.05900 32.20600 1.000 35.59000 C ? A ? 6 1 + ATOM 39 CD . LYS A 6 ? -41.04900 18.47000 33.46400 1.000 35.59000 C ? A ? 6 1 + ATOM 40 CE . LYS A 6 ? -40.97000 19.53200 34.56400 1.000 35.59000 C ? A ? 6 1 + ATOM 41 NZ . LYS A 6 ? -40.29000 18.99600 35.76900 1.000 35.59000 N ? A ? 6 1 + ATOM 42 N . GLU A 7 ? -41.75300 18.18000 27.45500 1.000 35.94000 N ? A ? 7 1 + ATOM 43 CA . GLU A 7 ? -41.28100 17.42300 26.30700 1.000 35.94000 C ? A ? 7 1 + ATOM 44 C . GLU A 7 ? -40.15000 16.53500 26.80500 1.000 35.94000 C ? A ? 7 1 + ATOM 45 O . GLU A 7 ? -39.07800 16.98700 27.20300 1.000 35.94000 O ? A ? 7 1 + ATOM 46 CB . GLU A 7 ? -40.84500 18.36200 25.17000 1.000 35.94000 C ? A ? 7 1 + ATOM 47 CG . GLU A 7 ? -42.04900 18.68700 24.27000 1.000 35.94000 C ? A ? 7 1 + ATOM 48 CD . GLU A 7 ? -41.78800 19.80400 23.24800 1.000 35.94000 C ? A ? 7 1 + ATOM 49 OE1 . GLU A 7 ? -42.39500 19.73000 22.15400 1.000 35.94000 O ? A ? 7 1 + ATOM 50 OE2 . GLU A 7 ? -41.08800 20.77700 23.60700 1.000 35.94000 O ? A ? 7 1 + ATOM 51 N . GLU A 8 ? -40.49400 15.25600 26.90000 1.000 34.78000 N ? A ? 8 1 + ATOM 52 CA . GLU A 8 ? -39.57600 14.14700 26.90000 1.000 34.78000 C ? A ? 8 1 + ATOM 53 C . GLU A 8 ? -38.62700 14.36300 25.71200 1.000 34.78000 C ? A ? 8 1 + ATOM 54 O . GLU A 8 ? -38.94800 13.98900 24.58600 1.000 34.78000 O ? A ? 8 1 + ATOM 55 CB . GLU A 8 ? -40.39500 12.84100 26.72200 1.000 34.78000 C ? A ? 8 1 + ATOM 56 CG . GLU A 8 ? -41.34900 12.47400 27.87500 1.000 34.78000 C ? A ? 8 1 + ATOM 57 CD . GLU A 8 ? -42.19200 11.19600 27.62600 1.000 34.78000 C ? A ? 8 1 + ATOM 58 OE1 . GLU A 8 ? -42.66400 10.61400 28.62900 1.000 34.78000 O ? A ? 8 1 + ATOM 59 OE2 . GLU A 8 ? -42.38700 10.76000 26.46000 1.000 34.78000 O ? A ? 8 1 + ATOM 60 N . GLU A 9 ? -37.43900 14.92500 25.94800 1.000 34.62000 N ? A ? 9 1 + ATOM 61 CA . GLU A 9 ? -36.24400 14.52300 25.20300 1.000 34.62000 C ? A ? 9 1 + ATOM 62 C . GLU A 9 ? -36.00900 13.04700 25.54200 1.000 34.62000 C ? A ? 9 1 + ATOM 63 O . GLU A 9 ? -35.15800 12.66000 26.34200 1.000 34.62000 O ? A ? 9 1 + ATOM 64 CB . GLU A 9 ? -35.02000 15.40900 25.51300 1.000 34.62000 C ? A ? 9 1 + ATOM 65 CG . GLU A 9 ? -34.92500 16.62800 24.58000 1.000 34.62000 C ? A ? 9 1 + ATOM 66 CD . GLU A 9 ? -33.69200 17.50900 24.86300 1.000 34.62000 C ? A ? 9 1 + ATOM 67 OE1 . GLU A 9 ? -33.24300 18.20000 23.91900 1.000 34.62000 O ? A ? 9 1 + ATOM 68 OE2 . GLU A 9 ? -33.23200 17.53300 26.02900 1.000 34.62000 O ? A ? 9 1 + ATOM 69 N . LYS A 10 ? -36.86100 12.19800 24.96100 1.000 33.03000 N ? A ? 10 1 + ATOM 70 CA . LYS A 10 ? -36.54300 10.81700 24.67000 1.000 33.03000 C ? A ? 10 1 + ATOM 71 C . LYS A 10 ? -35.38000 10.88400 23.69500 1.000 33.03000 C ? A ? 10 1 + ATOM 72 O . LYS A 10 ? -35.55500 10.86700 22.48100 1.000 33.03000 O ? A ? 10 1 + ATOM 73 CB . LYS A 10 ? -37.76600 10.10100 24.07300 1.000 33.03000 C ? A ? 10 1 + ATOM 74 CG . LYS A 10 ? -38.58900 9.36400 25.13000 1.000 33.03000 C ? A ? 10 1 + ATOM 75 CD . LYS A 10 ? -39.88300 8.85800 24.49200 1.000 33.03000 C ? A ? 10 1 + ATOM 76 CE . LYS A 10 ? -40.68600 8.06400 25.52000 1.000 33.03000 C ? A ? 10 1 + ATOM 77 NZ . LYS A 10 ? -42.12500 8.14300 25.20200 1.000 33.03000 N ? A ? 10 1 + ATOM 78 N . GLU A 11 ? -34.17900 10.93300 24.25400 1.000 37.56000 N ? A ? 11 1 + ATOM 79 CA . GLU A 11 ? -33.10800 10.10100 23.74300 1.000 37.56000 C ? A ? 11 1 + ATOM 80 C . GLU A 11 ? -33.69300 8.68200 23.62700 1.000 37.56000 C ? A ? 11 1 + ATOM 81 O . GLU A 11 ? -33.62900 7.87900 24.55800 1.000 37.56000 O ? A ? 11 1 + ATOM 82 CB . GLU A 11 ? -31.90100 10.12400 24.70200 1.000 37.56000 C ? A ? 11 1 + ATOM 83 CG . GLU A 11 ? -31.03700 11.39500 24.66900 1.000 37.56000 C ? A ? 11 1 + ATOM 84 CD . GLU A 11 ? -29.76200 11.25800 25.53400 1.000 37.56000 C ? A ? 11 1 + ATOM 85 OE1 . GLU A 11 ? -28.75900 11.94400 25.22700 1.000 37.56000 O ? A ? 11 1 + ATOM 86 OE2 . GLU A 11 ? -29.76100 10.44500 26.49100 1.000 37.56000 O ? A ? 11 1 + ATOM 87 N . GLU A 12 ? -34.31800 8.36600 22.48900 1.000 37.25000 N ? A ? 12 1 + ATOM 88 CA . GLU A 12 ? -34.45800 6.99500 22.00700 1.000 37.25000 C ? A ? 12 1 + ATOM 89 C . GLU A 12 ? -33.04100 6.50300 21.68400 1.000 37.25000 C ? A ? 12 1 + ATOM 90 O . GLU A 12 ? -32.65900 6.24200 20.54600 1.000 37.25000 O ? A ? 12 1 + ATOM 91 CB . GLU A 12 ? -35.43800 6.88800 20.81700 1.000 37.25000 C ? A ? 12 1 + ATOM 92 CG . GLU A 12 ? -36.90900 6.82200 21.26400 1.000 37.25000 C ? A ? 12 1 + ATOM 93 CD . GLU A 12 ? -37.91600 6.67000 20.10600 1.000 37.25000 C ? A ? 12 1 + ATOM 94 OE1 . GLU A 12 ? -39.09600 6.37800 20.42000 1.000 37.25000 O ? A ? 12 1 + ATOM 95 OE2 . GLU A 12 ? -37.52700 6.85300 18.93100 1.000 37.25000 O ? A ? 12 1 + ATOM 96 N . LEU A 13 ? -32.22100 6.38400 22.73400 1.000 35.50000 N ? A ? 13 1 + ATOM 97 CA . LEU A 13 ? -31.18300 5.38700 22.79800 1.000 35.50000 C ? A ? 13 1 + ATOM 98 C . LEU A 13 ? -31.92600 4.10300 22.48500 1.000 35.50000 C ? A ? 13 1 + ATOM 99 O . LEU A 13 ? -32.73800 3.64200 23.28700 1.000 35.50000 O ? A ? 13 1 + ATOM 100 CB . LEU A 13 ? -30.57600 5.34000 24.21600 1.000 35.50000 C ? A ? 13 1 + ATOM 101 CG . LEU A 13 ? -29.72700 6.56800 24.58000 1.000 35.50000 C ? A ? 13 1 + ATOM 102 CD1 . LEU A 13 ? -29.50700 6.62200 26.09200 1.000 35.50000 C ? A ? 13 1 + ATOM 103 CD2 . LEU A 13 ? -28.36200 6.54300 23.88900 1.000 35.50000 C ? A ? 13 1 + ATOM 104 N . LEU A 14 ? -31.68700 3.56400 21.29700 1.000 41.12000 N ? A ? 14 1 + ATOM 105 CA . LEU A 14 ? -31.94500 2.17300 20.99700 1.000 41.12000 C ? A ? 14 1 + ATOM 106 C . LEU A 14 ? -31.22900 1.36500 22.09100 1.000 41.12000 C ? A ? 14 1 + ATOM 107 O . LEU A 14 ? -30.07000 0.98200 21.94300 1.000 41.12000 O ? A ? 14 1 + ATOM 108 CB . LEU A 14 ? -31.41900 1.88700 19.57500 1.000 41.12000 C ? A ? 14 1 + ATOM 109 CG . LEU A 14 ? -32.29900 2.45100 18.44300 1.000 41.12000 C ? A ? 14 1 + ATOM 110 CD1 . LEU A 14 ? -31.49600 2.51000 17.14200 1.000 41.12000 C ? A ? 14 1 + ATOM 111 CD2 . LEU A 14 ? -33.52800 1.57100 18.20000 1.000 41.12000 C ? A ? 14 1 + ATOM 112 N . GLN A 15 ? -31.90700 1.14900 23.22300 1.000 48.41000 N ? A ? 15 1 + ATOM 113 CA . GLN A 15 ? -31.63100 0.09600 24.18600 1.000 48.41000 C ? A ? 15 1 + ATOM 114 C . GLN A 15 ? -32.02500 -1.18800 23.47300 1.000 48.41000 C ? A ? 15 1 + ATOM 115 O . GLN A 15 ? -33.01500 -1.84000 23.78500 1.000 48.41000 O ? A ? 15 1 + ATOM 116 CB . GLN A 15 ? -32.41700 0.28400 25.49800 1.000 48.41000 C ? A ? 15 1 + ATOM 117 CG . GLN A 15 ? -31.95300 1.47400 26.34900 1.000 48.41000 C ? A ? 15 1 + ATOM 118 CD . GLN A 15 ? -32.67100 1.54600 27.69800 1.000 48.41000 C ? A ? 15 1 + ATOM 119 OE1 . GLN A 15 ? -33.43300 0.69000 28.10700 1.000 48.41000 O ? A ? 15 1 + ATOM 120 NE2 . GLN A 15 ? -32.44900 2.58600 28.47000 1.000 48.41000 N ? A ? 15 1 + ATOM 121 N . LEU A 16 ? -31.28400 -1.50600 22.41600 1.000 53.53000 N ? A ? 16 1 + ATOM 122 CA . LEU A 16 ? -31.26200 -2.85200 21.91900 1.000 53.53000 C ? A ? 16 1 + ATOM 123 C . LEU A 16 ? -30.70900 -3.64400 23.10600 1.000 53.53000 C ? A ? 16 1 + ATOM 124 O . LEU A 16 ? -29.55800 -3.45600 23.50200 1.000 53.53000 O ? A ? 16 1 + ATOM 125 CB . LEU A 16 ? -30.39700 -2.90600 20.64800 1.000 53.53000 C ? A ? 16 1 + ATOM 126 CG . LEU A 16 ? -31.00500 -2.22900 19.41100 1.000 53.53000 C ? A ? 16 1 + ATOM 127 CD1 . LEU A 16 ? -29.91000 -1.85400 18.40900 1.000 53.53000 C ? A ? 16 1 + ATOM 128 CD2 . LEU A 16 ? -31.99500 -3.16000 18.71100 1.000 53.53000 C ? A ? 16 1 + ATOM 129 N . GLU A 17 ? -31.54900 -4.46600 23.72800 1.000 61.28000 N ? A ? 17 1 + ATOM 130 CA . GLU A 17 ? -31.12200 -5.51900 24.64900 1.000 61.28000 C ? A ? 17 1 + ATOM 131 C . GLU A 17 ? -30.35100 -6.56000 23.82400 1.000 61.28000 C ? A ? 17 1 + ATOM 132 O . GLU A 17 ? -30.81500 -7.67000 23.57400 1.000 61.28000 O ? A ? 17 1 + ATOM 133 CB . GLU A 17 ? -32.32800 -6.12700 25.38500 1.000 61.28000 C ? A ? 17 1 + ATOM 134 CG . GLU A 17 ? -32.96400 -5.17500 26.41100 1.000 61.28000 C ? A ? 17 1 + ATOM 135 CD . GLU A 17 ? -34.14500 -5.81300 27.16800 1.000 61.28000 C ? A ? 17 1 + ATOM 136 OE1 . GLU A 17 ? -34.52800 -5.25000 28.21900 1.000 61.28000 O ? A ? 17 1 + ATOM 137 OE2 . GLU A 17 ? -34.66000 -6.86000 26.71000 1.000 61.28000 O ? A ? 17 1 + ATOM 138 N . ILE A 18 ? -29.19700 -6.14900 23.29300 1.000 69.00000 N ? A ? 18 1 + ATOM 139 CA . ILE A 18 ? -28.33500 -6.96100 22.44900 1.000 69.00000 C ? A ? 18 1 + ATOM 140 C . ILE A 18 ? -27.72400 -8.02600 23.36100 1.000 69.00000 C ? A ? 18 1 + ATOM 141 O . ILE A 18 ? -27.06500 -7.67600 24.34600 1.000 69.00000 O ? A ? 18 1 + ATOM 142 CB . ILE A 18 ? -27.25100 -6.11100 21.74800 1.000 69.00000 C ? A ? 18 1 + ATOM 143 CG1 . ILE A 18 ? -27.87500 -5.03700 20.84700 1.000 69.00000 C ? A ? 18 1 + ATOM 144 CG2 . ILE A 18 ? -26.31700 -6.98200 20.90100 1.000 69.00000 C ? A ? 18 1 + ATOM 145 CD1 . ILE A 18 ? -26.89700 -4.15000 20.06500 1.000 69.00000 C ? A ? 18 1 + ATOM 146 N . PRO A 19 ? -27.91400 -9.31900 23.05400 1.000 75.00000 N ? A ? 19 1 + ATOM 147 CA . PRO A 19 ? -27.25600 -10.39000 23.78400 1.000 75.00000 C ? A ? 19 1 + ATOM 148 C . PRO A 19 ? -25.73600 -10.18000 23.85200 1.000 75.00000 C ? A ? 19 1 + ATOM 149 O . PRO A 19 ? -25.07400 -9.95200 22.83900 1.000 75.00000 O ? A ? 19 1 + ATOM 150 CB . PRO A 19 ? -27.63900 -11.66600 23.03400 1.000 75.00000 C ? A ? 19 1 + ATOM 151 CG . PRO A 19 ? -28.98700 -11.33500 22.40300 1.000 75.00000 C ? A ? 19 1 + ATOM 152 CD . PRO A 19 ? -28.85800 -9.85300 22.08100 1.000 75.00000 C ? A ? 19 1 + ATOM 153 N . CYS A 20 ? -25.15900 -10.28400 25.05000 1.000 76.06000 N ? A ? 20 1 + ATOM 154 CA . CYS A 20 ? -23.72900 -10.03900 25.27100 1.000 76.06000 C ? A ? 20 1 + ATOM 155 C . CYS A 20 ? -22.80600 -11.07500 24.60600 1.000 76.06000 C ? A ? 20 1 + ATOM 156 O . CYS A 20 ? -21.61100 -10.82400 24.47300 1.000 76.06000 O ? A ? 20 1 + ATOM 157 CB . CYS A 20 ? -23.46700 -9.94600 26.78100 1.000 76.06000 C ? A ? 20 1 + ATOM 158 SG . CYS A 20 ? -24.02200 -11.45800 27.63400 1.000 76.06000 S ? A ? 20 1 + ATOM 159 N . ASN A 21 ? -23.35800 -12.21200 24.16700 1.000 84.56000 N ? A ? 21 1 + ATOM 160 CA . ASN A 21 ? -22.65600 -13.29500 23.47900 1.000 84.56000 C ? A ? 21 1 + ATOM 161 C . ASN A 21 ? -22.49700 -13.07400 21.96400 1.000 84.56000 C ? A ? 21 1 + ATOM 162 O . ASN A 21 ? -22.03000 -13.97200 21.26700 1.000 84.56000 O ? A ? 21 1 + ATOM 163 CB . ASN A 21 ? -23.35800 -14.63200 23.78300 1.000 84.56000 C ? A ? 21 1 + ATOM 164 CG . ASN A 21 ? -24.73700 -14.74700 23.15600 1.000 84.56000 C ? A ? 21 1 + ATOM 165 OD1 . ASN A 21 ? -25.45400 -13.78200 22.96900 1.000 84.56000 O ? A ? 21 1 + ATOM 166 ND2 . ASN A 21 ? -25.18300 -15.93900 22.84500 1.000 84.56000 N ? A ? 21 1 + ATOM 167 N . ILE A 22 ? -22.91100 -11.92100 21.43700 1.000 87.94000 N ? A ? 22 1 + ATOM 168 CA . ILE A 22 ? -22.77500 -11.61800 20.01400 1.000 87.94000 C ? A ? 22 1 + ATOM 169 C . ILE A 22 ? -21.31700 -11.29900 19.67800 1.000 87.94000 C ? A ? 22 1 + ATOM 170 O . ILE A 22 ? -20.72100 -10.39600 20.25800 1.000 87.94000 O ? A ? 22 1 + ATOM 171 CB . ILE A 22 ? -23.76100 -10.50600 19.60700 1.000 87.94000 C ? A ? 22 1 + ATOM 172 CG1 . ILE A 22 ? -25.18400 -11.10200 19.61700 1.000 87.94000 C ? A ? 22 1 + ATOM 173 CG2 . ILE A 22 ? -23.44200 -9.99000 18.19500 1.000 87.94000 C ? A ? 22 1 + ATOM 174 CD1 . ILE A 22 ? -26.30500 -10.07300 19.55700 1.000 87.94000 C ? A ? 22 1 + ATOM 175 N . GLU A 23 ? -20.77300 -12.02400 18.70100 1.000 93.19000 N ? A ? 23 1 + ATOM 176 CA . GLU A 23 ? -19.39600 -11.86100 18.20900 1.000 93.19000 C ? A ? 23 1 + ATOM 177 C . GLU A 23 ? -19.29600 -10.94800 16.97900 1.000 93.19000 C ? A ? 23 1 + ATOM 178 O . GLU A 23 ? -18.25900 -10.32500 16.74500 1.000 93.19000 O ? A ? 23 1 + ATOM 179 CB . GLU A 23 ? -18.79700 -13.23600 17.88900 1.000 93.19000 C ? A ? 23 1 + ATOM 180 CG . GLU A 23 ? -18.70500 -14.14800 19.12400 1.000 93.19000 C ? A ? 23 1 + ATOM 181 CD . GLU A 23 ? -18.05800 -15.51100 18.82800 1.000 93.19000 C ? A ? 23 1 + ATOM 182 OE1 . GLU A 23 ? -17.89900 -16.28900 19.79700 1.000 93.19000 O ? A ? 23 1 + ATOM 183 OE2 . GLU A 23 ? -17.73700 -15.78700 17.64900 1.000 93.19000 O ? A ? 23 1 + ATOM 184 N . TYR A 24 ? -20.39000 -10.81500 16.22400 1.000 93.75000 N ? A ? 24 1 + ATOM 185 CA . TYR A 24 ? -20.47200 -10.01600 15.00500 1.000 93.75000 C ? A ? 24 1 + ATOM 186 C . TYR A 24 ? -21.70900 -9.11700 15.01300 1.000 93.75000 C ? A ? 24 1 + ATOM 187 O . TYR A 24 ? -22.83400 -9.59900 15.15500 1.000 93.75000 O ? A ? 24 1 + ATOM 188 CB . TYR A 24 ? -20.48300 -10.94600 13.78500 1.000 93.75000 C ? A ? 24 1 + ATOM 189 CG . TYR A 24 ? -20.64500 -10.22200 12.46000 1.000 93.75000 C ? A ? 24 1 + ATOM 190 CD1 . TYR A 24 ? -21.93000 -9.98500 11.93300 1.000 93.75000 C ? A ? 24 1 + ATOM 191 CD2 . TYR A 24 ? -19.51000 -9.78900 11.75200 1.000 93.75000 C ? A ? 24 1 + ATOM 192 CE1 . TYR A 24 ? -22.07400 -9.32900 10.69600 1.000 93.75000 C ? A ? 24 1 + ATOM 193 CE2 . TYR A 24 ? -19.64900 -9.11500 10.52400 1.000 93.75000 C ? A ? 24 1 + ATOM 194 CZ . TYR A 24 ? -20.93400 -8.89500 9.98700 1.000 93.75000 C ? A ? 24 1 + ATOM 195 OH . TYR A 24 ? -21.08300 -8.30200 8.77500 1.000 93.75000 O ? A ? 24 1 + ATOM 196 N . VAL A 25 ? -21.51000 -7.81900 14.79500 1.000 92.25000 N ? A ? 25 1 + ATOM 197 CA . VAL A 25 ? -22.58700 -6.84000 14.61800 1.000 92.25000 C ? A ? 25 1 + ATOM 198 C . VAL A 25 ? -22.35900 -6.08300 13.32300 1.000 92.25000 C ? A ? 25 1 + ATOM 199 O . VAL A 25 ? -21.27600 -5.55500 13.08200 1.000 92.25000 O ? A ? 25 1 + ATOM 200 CB . VAL A 25 ? -22.69900 -5.88100 15.82100 1.000 92.25000 C ? A ? 25 1 + ATOM 201 CG1 . VAL A 25 ? -23.64500 -4.70400 15.55400 1.000 92.25000 C ? A ? 25 1 + ATOM 202 CG2 . VAL A 25 ? -23.26100 -6.60700 17.04300 1.000 92.25000 C ? A ? 25 1 + ATOM 203 N . ARG A 26 ? -23.41600 -5.97000 12.52000 1.000 94.38000 N ? A ? 26 1 + ATOM 204 CA . ARG A 26 ? -23.46700 -5.08500 11.36000 1.000 94.38000 C ? A ? 26 1 + ATOM 205 C . ARG A 26 ? -24.59500 -4.08000 11.54000 1.000 94.38000 C ? A ? 26 1 + ATOM 206 O . ARG A 26 ? -25.75200 -4.46800 11.67800 1.000 94.38000 O ? A ? 26 1 + ATOM 207 CB . ARG A 26 ? -23.59300 -5.92500 10.08600 1.000 94.38000 C ? A ? 26 1 + ATOM 208 CG . ARG A 26 ? -23.64900 -5.05300 8.82700 1.000 94.38000 C ? A ? 26 1 + ATOM 209 CD . ARG A 26 ? -23.63400 -5.94200 7.58300 1.000 94.38000 C ? A ? 26 1 + ATOM 210 NE . ARG A 26 ? -23.80100 -5.13400 6.36200 1.000 94.38000 N ? A ? 26 1 + ATOM 211 CZ . ARG A 26 ? -22.90900 -4.96300 5.40200 1.000 94.38000 C ? A ? 26 1 + ATOM 212 NH1 . ARG A 26 ? -21.71500 -5.46700 5.41800 1.000 94.38000 N ? A ? 26 1 + ATOM 213 NH2 . ARG A 26 ? -23.21700 -4.24600 4.35900 1.000 94.38000 N ? A ? 26 1 + ATOM 214 N . ILE A 27 ? -24.25000 -2.80000 11.51500 1.000 92.56000 N ? A ? 27 1 + ATOM 215 CA . ILE A 27 ? -25.17600 -1.67100 11.56500 1.000 92.56000 C ? A ? 27 1 + ATOM 216 C . ILE A 27 ? -25.22400 -1.08000 10.16000 1.000 92.56000 C ? A ? 27 1 + ATOM 217 O . ILE A 27 ? -24.22500 -0.55800 9.67900 1.000 92.56000 O ? A ? 27 1 + ATOM 218 CB . ILE A 27 ? -24.73100 -0.63500 12.62100 1.000 92.56000 C ? A ? 27 1 + ATOM 219 CG1 . ILE A 27 ? -24.46900 -1.29700 13.99300 1.000 92.56000 C ? A ? 27 1 + ATOM 220 CG2 . ILE A 27 ? -25.81500 0.44800 12.73000 1.000 92.56000 C ? A ? 27 1 + ATOM 221 CD1 . ILE A 27 ? -23.97700 -0.32600 15.06900 1.000 92.56000 C ? A ? 27 1 + ATOM 222 N . GLY A 28 ? -26.35300 -1.22600 9.47300 1.000 94.44000 N ? A ? 28 1 + ATOM 223 CA . GLY A 28 ? -26.51200 -0.84000 8.07100 1.000 94.44000 C ? A ? 28 1 + ATOM 224 C . GLY A 28 ? -27.65700 0.14500 7.88300 1.000 94.44000 C ? A ? 28 1 + ATOM 225 O . GLY A 28 ? -28.69700 -0.01600 8.51800 1.000 94.44000 O ? A ? 28 1 + ATOM 226 N . ASP A 29 ? -27.47700 1.14100 7.01700 1.000 93.62000 N ? A ? 29 1 + ATOM 227 CA . ASP A 29 ? -28.54000 2.03500 6.53100 1.000 93.62000 C ? A ? 29 1 + ATOM 228 C . ASP A 29 ? -29.29700 2.79200 7.65200 1.000 93.62000 C ? A ? 29 1 + ATOM 229 O . ASP A 29 ? -30.45000 3.20500 7.49500 1.000 93.62000 O ? A ? 29 1 + ATOM 230 CB . ASP A 29 ? -29.43800 1.28400 5.52600 1.000 93.62000 C ? A ? 29 1 + ATOM 231 CG . ASP A 29 ? -28.65500 0.80200 4.29400 1.000 93.62000 C ? A ? 29 1 + ATOM 232 OD1 . ASP A 29 ? -28.25700 1.66200 3.47500 1.000 93.62000 O ? A ? 29 1 + ATOM 233 OD2 . ASP A 29 ? -28.43400 -0.42300 4.15200 1.000 93.62000 O ? A ? 29 1 + ATOM 234 N . CYS A 30 ? -28.64700 3.00900 8.80300 1.000 90.62000 N ? A ? 30 1 + ATOM 235 CA . CYS A 30 ? -29.24400 3.65500 9.97300 1.000 90.62000 C ? A ? 30 1 + ATOM 236 C . CYS A 30 ? -29.20100 5.18800 9.86000 1.000 90.62000 C ? A ? 30 1 + ATOM 237 O . CYS A 30 ? -28.21900 5.83800 10.21700 1.000 90.62000 O ? A ? 30 1 + ATOM 238 CB . CYS A 30 ? -28.56200 3.14500 11.24800 1.000 90.62000 C ? A ? 30 1 + ATOM 239 SG . CYS A 30 ? -28.98400 1.40000 11.50700 1.000 90.62000 S ? A ? 30 1 + ATOM 240 N . GLN A 31 ? -30.31600 5.77600 9.42100 1.000 90.94000 N ? A ? 31 1 + ATOM 241 CA . GLN A 31 ? -30.46300 7.22100 9.17600 1.000 90.94000 C ? A ? 31 1 + ATOM 242 C . GLN A 31 ? -30.41700 8.09200 10.44300 1.000 90.94000 C ? A ? 31 1 + ATOM 243 O . GLN A 31 ? -30.22100 9.30100 10.35500 1.000 90.94000 O ? A ? 31 1 + ATOM 244 CB . GLN A 31 ? -31.79300 7.46600 8.44000 1.000 90.94000 C ? A ? 31 1 + ATOM 245 CG . GLN A 31 ? -31.92000 6.69100 7.11800 1.000 90.94000 C ? A ? 31 1 + ATOM 246 CD . GLN A 31 ? -30.77300 6.99700 6.16500 1.000 90.94000 C ? A ? 31 1 + ATOM 247 OE1 . GLN A 31 ? -30.46600 8.14300 5.89700 1.000 90.94000 O ? A ? 31 1 + ATOM 248 NE2 . GLN A 31 ? -30.08600 5.99600 5.65900 1.000 90.94000 N ? A ? 31 1 + ATOM 249 N . GLY A 32 ? -30.62600 7.49500 11.61900 1.000 88.12000 N ? A ? 32 1 + ATOM 250 CA . GLY A 32 ? -30.60200 8.17500 12.91800 1.000 88.12000 C ? A ? 32 1 + ATOM 251 C . GLY A 32 ? -29.32300 7.95600 13.72800 1.000 88.12000 C ? A ? 32 1 + ATOM 252 O . GLY A 32 ? -29.21500 8.50100 14.82100 1.000 88.12000 O ? A ? 32 1 + ATOM 253 N . LEU A 33 ? -28.37400 7.14300 13.24400 1.000 88.94000 N ? A ? 33 1 + ATOM 254 CA . LEU A 33 ? -27.18600 6.79400 14.02400 1.000 88.94000 C ? A ? 33 1 + ATOM 255 C . LEU A 33 ? -26.19000 7.95400 14.02400 1.000 88.94000 C ? A ? 33 1 + ATOM 256 O . LEU A 33 ? -25.39300 8.08800 13.10300 1.000 88.94000 O ? A ? 33 1 + ATOM 257 CB . LEU A 33 ? -26.55100 5.49900 13.48800 1.000 88.94000 C ? A ? 33 1 + ATOM 258 CG . LEU A 33 ? -25.35700 5.02600 14.34600 1.000 88.94000 C ? A ? 33 1 + ATOM 259 CD1 . LEU A 33 ? -25.83100 4.38200 15.65100 1.000 88.94000 C ? A ? 33 1 + ATOM 260 CD2 . LEU A 33 ? -24.53100 4.01100 13.56300 1.000 88.94000 C ? A ? 33 1 + ATOM 261 N . GLU A 34 ? -26.22600 8.76300 15.07500 1.000 86.25000 N ? A ? 34 1 + ATOM 262 CA . GLU A 34 ? -25.27400 9.86200 15.27400 1.000 86.25000 C ? A ? 34 1 + ATOM 263 C . GLU A 34 ? -24.00300 9.40100 15.99500 1.000 86.25000 C ? A ? 34 1 + ATOM 264 O . GLU A 34 ? -22.90400 9.86500 15.68800 1.000 86.25000 O ? A ? 34 1 + ATOM 265 CB . GLU A 34 ? -25.98200 11.00600 16.01600 1.000 86.25000 C ? A ? 34 1 + ATOM 266 CG . GLU A 34 ? -26.97000 11.70700 15.06600 1.000 86.25000 C ? A ? 34 1 + ATOM 267 CD . GLU A 34 ? -27.86300 12.76700 15.71900 1.000 86.25000 C ? A ? 34 1 + ATOM 268 OE1 . GLU A 34 ? -28.90000 13.09000 15.07500 1.000 86.25000 O ? A ? 34 1 + ATOM 269 OE2 . GLU A 34 ? -27.49300 13.25500 16.80900 1.000 86.25000 O ? A ? 34 1 + ATOM 270 N . ARG A 35 ? -24.14600 8.46100 16.94100 1.000 83.06000 N ? A ? 35 1 + ATOM 271 CA . ARG A 35 ? -23.07100 7.87300 17.75500 1.000 83.06000 C ? A ? 35 1 + ATOM 272 C . ARG A 35 ? -23.43400 6.44400 18.16000 1.000 83.06000 C ? A ? 35 1 + ATOM 273 O . ARG A 35 ? -24.61100 6.11100 18.28100 1.000 83.06000 O ? A ? 35 1 + ATOM 274 CB . ARG A 35 ? -22.84500 8.72900 19.01800 1.000 83.06000 C ? A ? 35 1 + ATOM 275 CG . ARG A 35 ? -22.29600 10.12800 18.69700 1.000 83.06000 C ? A ? 35 1 + ATOM 276 CD . ARG A 35 ? -22.05000 10.95200 19.96000 1.000 83.06000 C ? A ? 35 1 + ATOM 277 NE . ARG A 35 ? -21.26700 12.16000 19.64000 1.000 83.06000 N ? A ? 35 1 + ATOM 278 CZ . ARG A 35 ? -21.13600 13.24700 20.37400 1.000 83.06000 C ? A ? 35 1 + ATOM 279 NH1 . ARG A 35 ? -21.82200 13.41800 21.47100 1.000 83.06000 N ? A ? 35 1 + ATOM 280 NH2 . ARG A 35 ? -20.29200 14.17400 20.02500 1.000 83.06000 N ? A ? 35 1 + ATOM 281 N . LEU A 36 ? -22.43200 5.61000 18.43900 1.000 82.69000 N ? A ? 36 1 + ATOM 282 CA . LEU A 36 ? -22.66500 4.33600 19.13000 1.000 82.69000 C ? A ? 36 1 + ATOM 283 C . LEU A 36 ? -23.10400 4.59100 20.57900 1.000 82.69000 C ? A ? 36 1 + ATOM 284 O . LEU A 36 ? -22.54500 5.44900 21.26000 1.000 82.69000 O ? A ? 36 1 + ATOM 285 CB . LEU A 36 ? -21.41100 3.44800 19.08500 1.000 82.69000 C ? A ? 36 1 + ATOM 286 CG . LEU A 36 ? -21.02900 2.91400 17.69500 1.000 82.69000 C ? A ? 36 1 + ATOM 287 CD1 . LEU A 36 ? -19.76200 2.06900 17.83100 1.000 82.69000 C ? A ? 36 1 + ATOM 288 CD2 . LEU A 36 ? -22.11600 2.04100 17.06600 1.000 82.69000 C ? A ? 36 1 + ATOM 289 N . SER A 37 ? -24.09100 3.83400 21.05900 1.000 77.19000 N ? A ? 37 1 + ATOM 290 CA . SER A 37 ? -24.52900 3.89400 22.45900 1.000 77.19000 C ? A ? 37 1 + ATOM 291 C . SER A 37 ? -23.44500 3.34700 23.38800 1.000 77.19000 C ? A ? 37 1 + ATOM 292 O . SER A 37 ? -22.79700 2.35700 23.06100 1.000 77.19000 O ? A ? 37 1 + ATOM 293 CB . SER A 37 ? -25.83300 3.10400 22.63300 1.000 77.19000 C ? A ? 37 1 + ATOM 294 OG . SER A 37 ? -26.24800 3.07400 23.99100 1.000 77.19000 O ? A ? 37 1 + ATOM 295 N . LYS A 38 ? -23.30800 3.90800 24.59600 1.000 72.88000 N ? A ? 38 1 + ATOM 296 CA . LYS A 38 ? -22.39000 3.39400 25.63400 1.000 72.88000 C ? A ? 38 1 + ATOM 297 C . LYS A 38 ? -22.64300 1.92700 25.99400 1.000 72.88000 C ? A ? 38 1 + ATOM 298 O . LYS A 38 ? -21.74500 1.23300 26.45400 1.000 72.88000 O ? A ? 38 1 + ATOM 299 CB . LYS A 38 ? -22.50500 4.24700 26.90400 1.000 72.88000 C ? A ? 38 1 + ATOM 300 CG . LYS A 38 ? -21.93200 5.65200 26.69700 1.000 72.88000 C ? A ? 38 1 + ATOM 301 CD . LYS A 38 ? -22.00500 6.45400 27.99700 1.000 72.88000 C ? A ? 38 1 + ATOM 302 CE . LYS A 38 ? -21.37100 7.82600 27.75800 1.000 72.88000 C ? A ? 38 1 + ATOM 303 NZ . LYS A 38 ? -21.34900 8.62900 29.00300 1.000 72.88000 N ? A ? 38 1 + ATOM 304 N . THR A 39 ? -23.86100 1.43700 25.76500 1.000 72.00000 N ? A ? 39 1 + ATOM 305 CA . THR A 39 ? -24.22000 0.02600 25.97600 1.000 72.00000 C ? A ? 39 1 + ATOM 306 C . THR A 39 ? -23.45300 -0.93600 25.06200 1.000 72.00000 C ? A ? 39 1 + ATOM 307 O . THR A 39 ? -23.27700 -2.09000 25.44400 1.000 72.00000 O ? A ? 39 1 + ATOM 308 CB . THR A 39 ? -25.72600 -0.19700 25.79800 1.000 72.00000 C ? A ? 39 1 + ATOM 309 OG1 . THR A 39 ? -26.12900 0.24100 24.52300 1.000 72.00000 O ? A ? 39 1 + ATOM 310 CG2 . THR A 39 ? -26.55100 0.56400 26.83700 1.000 72.00000 C ? A ? 39 1 + ATOM 311 N . PHE A 40 ? -22.90900 -0.47600 23.92400 1.000 76.00000 N ? A ? 40 1 + ATOM 312 CA . PHE A 40 ? -22.04300 -1.29000 23.05700 1.000 76.00000 C ? A ? 40 1 + ATOM 313 C . PHE A 40 ? -20.76900 -1.75800 23.76000 1.000 76.00000 C ? A ? 40 1 + ATOM 314 O . PHE A 40 ? -20.25200 -2.82600 23.43800 1.000 76.00000 O ? A ? 40 1 + ATOM 315 CB . PHE A 40 ? -21.66200 -0.52000 21.78500 1.000 76.00000 C ? A ? 40 1 + ATOM 316 CG . PHE A 40 ? -22.59900 -0.77300 20.62800 1.000 76.00000 C ? A ? 40 1 + ATOM 317 CD1 . PHE A 40 ? -22.17600 -1.59900 19.57000 1.000 76.00000 C ? A ? 40 1 + ATOM 318 CD2 . PHE A 40 ? -23.89800 -0.23500 20.62300 1.000 76.00000 C ? A ? 40 1 + ATOM 319 CE1 . PHE A 40 ? -23.05200 -1.89400 18.51400 1.000 76.00000 C ? A ? 40 1 + ATOM 320 CE2 . PHE A 40 ? -24.77700 -0.53100 19.56500 1.000 76.00000 C ? A ? 40 1 + ATOM 321 CZ . PHE A 40 ? -24.35500 -1.36600 18.51500 1.000 76.00000 C ? A ? 40 1 + ATOM 322 N . HIS A 41 ? -20.29700 -1.01600 24.76500 1.000 75.44000 N ? A ? 41 1 + ATOM 323 CA . HIS A 41 ? -19.16700 -1.43900 25.58400 1.000 75.44000 C ? A ? 41 1 + ATOM 324 C . HIS A 41 ? -19.44400 -2.75100 26.34500 1.000 75.44000 C ? A ? 41 1 + ATOM 325 O . HIS A 41 ? -18.52000 -3.50900 26.63300 1.000 75.44000 O ? A ? 41 1 + ATOM 326 CB . HIS A 41 ? -18.81600 -0.30200 26.54500 1.000 75.44000 C ? A ? 41 1 + ATOM 327 CG . HIS A 41 ? -17.49300 -0.52900 27.21900 1.000 75.44000 C ? A ? 41 1 + ATOM 328 ND1 . HIS A 41 ? -16.25900 -0.30600 26.65600 1.000 75.44000 N ? A ? 41 1 + ATOM 329 CD2 . HIS A 41 ? -17.28400 -1.04500 28.47000 1.000 75.44000 C ? A ? 41 1 + ATOM 330 CE1 . HIS A 41 ? -15.32900 -0.65400 27.55800 1.000 75.44000 C ? A ? 41 1 + ATOM 331 NE2 . HIS A 41 ? -15.90200 -1.12200 28.68000 1.000 75.44000 N ? A ? 41 1 + ATOM 332 N . ASN A 42 ? -20.71700 -3.06300 26.62000 1.000 77.00000 N ? A ? 42 1 + ATOM 333 CA . ASN A 42 ? -21.12600 -4.27600 27.33500 1.000 77.00000 C ? A ? 42 1 + ATOM 334 C . ASN A 42 ? -21.14300 -5.53200 26.44800 1.000 77.00000 C ? A ? 42 1 + ATOM 335 O . ASN A 42 ? -21.38600 -6.63000 26.95300 1.000 77.00000 O ? A ? 42 1 + ATOM 336 CB . ASN A 42 ? -22.50300 -4.05700 27.98400 1.000 77.00000 C ? A ? 42 1 + ATOM 337 CG . ASN A 42 ? -22.53300 -2.94400 29.01000 1.000 77.00000 C ? A ? 42 1 + ATOM 338 OD1 . ASN A 42 ? -21.53600 -2.52800 29.57400 1.000 77.00000 O ? A ? 42 1 + ATOM 339 ND2 . ASN A 42 ? -23.70300 -2.43900 29.32100 1.000 77.00000 N ? A ? 42 1 + ATOM 340 N . LEU A 43 ? -20.89500 -5.39700 25.14100 1.000 82.25000 N ? A ? 43 1 + ATOM 341 CA . LEU A 43 ? -20.82000 -6.52300 24.21100 1.000 82.25000 C ? A ? 43 1 + ATOM 342 C . LEU A 43 ? -19.46200 -7.21400 24.33900 1.000 82.25000 C ? A ? 43 1 + ATOM 343 O . LEU A 43 ? -18.58700 -7.10300 23.48400 1.000 82.25000 O ? A ? 43 1 + ATOM 344 CB . LEU A 43 ? -21.13300 -6.06000 22.78100 1.000 82.25000 C ? A ? 43 1 + ATOM 345 CG . LEU A 43 ? -22.49400 -5.37200 22.61500 1.000 82.25000 C ? A ? 43 1 + ATOM 346 CD1 . LEU A 43 ? -22.68300 -4.95700 21.15700 1.000 82.25000 C ? A ? 43 1 + ATOM 347 CD2 . LEU A 43 ? -23.64000 -6.29200 23.02400 1.000 82.25000 C ? A ? 43 1 + ATOM 348 N . THR A 44 ? -19.27800 -7.91900 25.45100 1.000 84.75000 N ? A ? 44 1 + ATOM 349 CA . THR A 44 ? -17.99800 -8.51700 25.83900 1.000 84.75000 C ? A ? 44 1 + ATOM 350 C . THR A 44 ? -17.54000 -9.64100 24.91300 1.000 84.75000 C ? A ? 44 1 + ATOM 351 O . THR A 44 ? -16.34900 -9.93800 24.89500 1.000 84.75000 O ? A ? 44 1 + ATOM 352 CB . THR A 44 ? -18.04500 -9.02800 27.28300 1.000 84.75000 C ? A ? 44 1 + ATOM 353 OG1 . THR A 44 ? -19.13600 -9.90100 27.45800 1.000 84.75000 O ? A ? 44 1 + ATOM 354 CG2 . THR A 44 ? -18.20900 -7.89000 28.29200 1.000 84.75000 C ? A ? 44 1 + ATOM 355 N . CYS A 45 ? -18.41400 -10.23000 24.09500 1.000 88.88000 N ? A ? 45 1 + ATOM 356 CA . CYS A 45 ? -18.01900 -11.19500 23.06600 1.000 88.88000 C ? A ? 45 1 + ATOM 357 C . CYS A 45 ? -17.76700 -10.57000 21.68400 1.000 88.88000 C ? A ? 45 1 + ATOM 358 O . CYS A 45 ? -17.28900 -11.28000 20.80500 1.000 88.88000 O ? A ? 45 1 + ATOM 359 CB . CYS A 45 ? -19.06000 -12.31700 23.00800 1.000 88.88000 C ? A ? 45 1 + ATOM 360 SG . CYS A 45 ? -19.03600 -13.24900 24.57300 1.000 88.88000 S ? A ? 45 1 + ATOM 361 N . LEU A 46 ? -18.04000 -9.27500 21.47400 1.000 90.50000 N ? A ? 46 1 + ATOM 362 CA . LEU A 46 ? -18.00200 -8.67800 20.13700 1.000 90.50000 C ? A ? 46 1 + ATOM 363 C . LEU A 46 ? -16.57300 -8.55100 19.60800 1.000 90.50000 C ? A ? 46 1 + ATOM 364 O . LEU A 46 ? -15.80000 -7.71900 20.07600 1.000 90.50000 O ? A ? 46 1 + ATOM 365 CB . LEU A 46 ? -18.72700 -7.31900 20.13100 1.000 90.50000 C ? A ? 46 1 + ATOM 366 CG . LEU A 46 ? -18.98900 -6.77600 18.71100 1.000 90.50000 C ? A ? 46 1 + ATOM 367 CD1 . LEU A 46 ? -20.08600 -7.58600 18.04300 1.000 90.50000 C ? A ? 46 1 + ATOM 368 CD2 . LEU A 46 ? -19.48900 -5.32900 18.71800 1.000 90.50000 C ? A ? 46 1 + ATOM 369 N . THR A 47 ? -16.24000 -9.31900 18.57300 1.000 93.62000 N ? A ? 47 1 + ATOM 370 CA . THR A 47 ? -14.93100 -9.26300 17.90900 1.000 93.62000 C ? A ? 47 1 + ATOM 371 C . THR A 47 ? -14.97200 -8.49500 16.59500 1.000 93.62000 C ? A ? 47 1 + ATOM 372 O . THR A 47 ? -13.94400 -7.95400 16.18400 1.000 93.62000 O ? A ? 47 1 + ATOM 373 CB . THR A 47 ? -14.36600 -10.66400 17.66100 1.000 93.62000 C ? A ? 47 1 + ATOM 374 OG1 . THR A 47 ? -15.22400 -11.44100 16.86400 1.000 93.62000 O ? A ? 47 1 + ATOM 375 CG2 . THR A 47 ? -14.14200 -11.41600 18.97200 1.000 93.62000 C ? A ? 47 1 + ATOM 376 N . ASN A 48 ? -16.13800 -8.41100 15.95300 1.000 95.94000 N ? A ? 48 1 + ATOM 377 CA . ASN A 48 ? -16.30500 -7.82500 14.62900 1.000 95.94000 C ? A ? 48 1 + ATOM 378 C . ASN A 48 ? -17.47800 -6.83900 14.61300 1.000 95.94000 C ? A ? 48 1 + ATOM 379 O . ASN A 48 ? -18.61100 -7.19700 14.93100 1.000 95.94000 O ? A ? 48 1 + ATOM 380 CB . ASN A 48 ? -16.50400 -8.96100 13.61700 1.000 95.94000 C ? A ? 48 1 + ATOM 381 CG . ASN A 48 ? -15.25100 -9.78700 13.40700 1.000 95.94000 C ? A ? 48 1 + ATOM 382 OD1 . ASN A 48 ? -14.81200 -10.54100 14.26100 1.000 95.94000 O ? A ? 48 1 + ATOM 383 ND2 . ASN A 48 ? -14.61300 -9.66200 12.26600 1.000 95.94000 N ? A ? 48 1 + ATOM 384 N . LEU A 49 ? -17.20500 -5.60500 14.19700 1.000 93.50000 N ? A ? 49 1 + ATOM 385 CA . LEU A 49 ? -18.20800 -4.56100 14.02700 1.000 93.50000 C ? A ? 49 1 + ATOM 386 C . LEU A 49 ? -18.10700 -3.98500 12.61600 1.000 93.50000 C ? A ? 49 1 + ATOM 387 O . LEU A 49 ? -17.03200 -3.59500 12.16500 1.000 93.50000 O ? A ? 49 1 + ATOM 388 CB . LEU A 49 ? -18.03700 -3.50200 15.13000 1.000 93.50000 C ? A ? 49 1 + ATOM 389 CG . LEU A 49 ? -18.98600 -2.29100 15.03700 1.000 93.50000 C ? A ? 49 1 + ATOM 390 CD1 . LEU A 49 ? -20.46400 -2.67900 15.10300 1.000 93.50000 C ? A ? 49 1 + ATOM 391 CD2 . LEU A 49 ? -18.71200 -1.34400 16.20700 1.000 93.50000 C ? A ? 49 1 + ATOM 392 N . GLU A 50 ? -19.23900 -3.90800 11.93400 1.000 96.25000 N ? A ? 50 1 + ATOM 393 CA . GLU A 50 ? -19.36900 -3.22900 10.65200 1.000 96.25000 C ? A ? 50 1 + ATOM 394 C . GLU A 50 ? -20.40500 -2.11500 10.76200 1.000 96.25000 C ? A ? 50 1 + ATOM 395 O . GLU A 50 ? -21.51500 -2.34000 11.24300 1.000 96.25000 O ? A ? 50 1 + ATOM 396 CB . GLU A 50 ? -19.75300 -4.21200 9.54600 1.000 96.25000 C ? A ? 50 1 + ATOM 397 CG . GLU A 50 ? -18.70400 -5.31000 9.31700 1.000 96.25000 C ? A ? 50 1 + ATOM 398 CD . GLU A 50 ? -19.06300 -6.20300 8.12700 1.000 96.25000 C ? A ? 50 1 + ATOM 399 OE1 . GLU A 50 ? -18.45600 -7.28500 7.99000 1.000 96.25000 O ? A ? 50 1 + ATOM 400 OE2 . GLU A 50 ? -20.03100 -5.89400 7.39600 1.000 96.25000 O ? A ? 50 1 + ATOM 401 N . ILE A 51 ? -20.05900 -0.92100 10.29300 1.000 95.25000 N ? A ? 51 1 + ATOM 402 CA . ILE A 51 ? -20.97200 0.21800 10.20400 1.000 95.25000 C ? A ? 51 1 + ATOM 403 C . ILE A 51 ? -21.03600 0.64200 8.74300 1.000 95.25000 C ? A ? 51 1 + ATOM 404 O . ILE A 51 ? -20.02700 1.00800 8.15200 1.000 95.25000 O ? A ? 51 1 + ATOM 405 CB . ILE A 51 ? -20.54000 1.37200 11.12600 1.000 95.25000 C ? A ? 51 1 + ATOM 406 CG1 . ILE A 51 ? -20.35600 0.89700 12.58700 1.000 95.25000 C ? A ? 51 1 + ATOM 407 CG2 . ILE A 51 ? -21.61100 2.46900 11.03600 1.000 95.25000 C ? A ? 51 1 + ATOM 408 CD1 . ILE A 51 ? -19.85700 1.98900 13.54000 1.000 95.25000 C ? A ? 51 1 + ATOM 409 N . VAL A 52 ? -22.21700 0.56500 8.14300 1.000 97.44000 N ? A ? 52 1 + ATOM 410 CA . VAL A 52 ? -22.40900 0.73400 6.70500 1.000 97.44000 C ? A ? 52 1 + ATOM 411 C . VAL A 52 ? -23.53100 1.73000 6.45500 1.000 97.44000 C ? A ? 52 1 + ATOM 412 O . VAL A 52 ? -24.61500 1.58600 7.01800 1.000 97.44000 O ? A ? 52 1 + ATOM 413 CB . VAL A 52 ? -22.66700 -0.62400 6.02200 1.000 97.44000 C ? A ? 52 1 + ATOM 414 CG1 . VAL A 52 ? -22.75700 -0.46100 4.50000 1.000 97.44000 C ? A ? 52 1 + ATOM 415 CG2 . VAL A 52 ? -21.55700 -1.63500 6.35400 1.000 97.44000 C ? A ? 52 1 + ATOM 416 N . LYS A 53 ? -23.30300 2.72900 5.59700 1.000 96.00000 N ? A ? 53 1 + ATOM 417 CA . LYS A 53 ? -24.33900 3.67700 5.14500 1.000 96.00000 C ? A ? 53 1 + ATOM 418 C . LYS A 53 ? -25.10000 4.34800 6.29500 1.000 96.00000 C ? A ? 53 1 + ATOM 419 O . LYS A 53 ? -26.32600 4.41400 6.29900 1.000 96.00000 O ? A ? 53 1 + ATOM 420 CB . LYS A 53 ? -25.27000 2.99200 4.13700 1.000 96.00000 C ? A ? 53 1 + ATOM 421 CG . LYS A 53 ? -24.54500 2.60000 2.84600 1.000 96.00000 C ? A ? 53 1 + ATOM 422 CD . LYS A 53 ? -25.53800 1.84800 1.96600 1.000 96.00000 C ? A ? 53 1 + ATOM 423 CE . LYS A 53 ? -24.89500 1.45200 0.64300 1.000 96.00000 C ? A ? 53 1 + ATOM 424 NZ . LYS A 53 ? -25.92800 0.84700 -0.22300 1.000 96.00000 N ? A ? 53 1 + ATOM 425 N . CYS A 54 ? -24.37300 4.82200 7.30300 1.000 95.31000 N ? A ? 54 1 + ATOM 426 CA . CYS A 54 ? -24.94000 5.57700 8.42300 1.000 95.31000 C ? A ? 54 1 + ATOM 427 C . CYS A 54 ? -24.59400 7.06500 8.24600 1.000 95.31000 C ? A ? 54 1 + ATOM 428 O . CYS A 54 ? -23.52600 7.48400 8.69400 1.000 95.31000 O ? A ? 54 1 + ATOM 429 CB . CYS A 54 ? -24.43300 4.98800 9.74500 1.000 95.31000 C ? A ? 54 1 + ATOM 430 SG . CYS A 54 ? -25.04300 3.28500 9.92600 1.000 95.31000 S ? A ? 54 1 + ATOM 431 N . PRO A 55 ? -25.44200 7.86400 7.56900 1.000 92.38000 N ? A ? 55 1 + ATOM 432 CA . PRO A 55 ? -25.07000 9.20500 7.12400 1.000 92.38000 C ? A ? 55 1 + ATOM 433 C . PRO A 55 ? -25.00000 10.22000 8.25900 1.000 92.38000 C ? A ? 55 1 + ATOM 434 O . PRO A 55 ? -24.38100 11.25300 8.08300 1.000 92.38000 O ? A ? 55 1 + ATOM 435 CB . PRO A 55 ? -26.12900 9.60800 6.09500 1.000 92.38000 C ? A ? 55 1 + ATOM 436 CG . PRO A 55 ? -27.36000 8.83000 6.54400 1.000 92.38000 C ? A ? 55 1 + ATOM 437 CD . PRO A 55 ? -26.76200 7.52200 7.05500 1.000 92.38000 C ? A ? 55 1 + ATOM 438 N . LYS A 56 ? -25.60700 9.96800 9.42100 1.000 93.12000 N ? A ? 56 1 + ATOM 439 CA . LYS A 56 ? -25.52600 10.87900 10.57200 1.000 93.12000 C ? A ? 56 1 + ATOM 440 C . LYS A 56 ? -24.33600 10.62100 11.49700 1.000 93.12000 C ? A ? 56 1 + ATOM 441 O . LYS A 56 ? -24.12900 11.39700 12.42500 1.000 93.12000 O ? A ? 56 1 + ATOM 442 CB . LYS A 56 ? -26.83400 10.83500 11.35500 1.000 93.12000 C ? A ? 56 1 + ATOM 443 CG . LYS A 56 ? -27.96500 11.59600 10.65800 1.000 93.12000 C ? A ? 56 1 + ATOM 444 CD . LYS A 56 ? -29.03100 11.83900 11.72600 1.000 93.12000 C ? A ? 56 1 + ATOM 445 CE . LYS A 56 ? -30.28900 12.51600 11.20100 1.000 93.12000 C ? A ? 56 1 + ATOM 446 NZ . LYS A 56 ? -31.13700 12.84100 12.37400 1.000 93.12000 N ? A ? 56 1 + ATOM 447 N . LEU A 57 ? -23.57100 9.55500 11.27000 1.000 92.06000 N ? A ? 57 1 + ATOM 448 CA . LEU A 57 ? -22.46000 9.19900 12.14300 1.000 92.06000 C ? A ? 57 1 + ATOM 449 C . LEU A 57 ? -21.32000 10.19700 11.94300 1.000 92.06000 C ? A ? 57 1 + ATOM 450 O . LEU A 57 ? -20.74000 10.23100 10.86400 1.000 92.06000 O ? A ? 57 1 + ATOM 451 CB . LEU A 57 ? -22.01800 7.75800 11.83800 1.000 92.06000 C ? A ? 57 1 + ATOM 452 CG . LEU A 57 ? -20.83900 7.30100 12.71400 1.000 92.06000 C ? A ? 57 1 + ATOM 453 CD1 . LEU A 57 ? -21.23000 7.19900 14.18800 1.000 92.06000 C ? A ? 57 1 + ATOM 454 CD2 . LEU A 57 ? -20.37400 5.92200 12.27000 1.000 92.06000 C ? A ? 57 1 + ATOM 455 N . VAL A 58 ? -20.98900 10.96900 12.97900 1.000 90.25000 N ? A ? 58 1 + ATOM 456 CA . VAL A 58 ? -19.93900 12.00500 12.90200 1.000 90.25000 C ? A ? 58 1 + ATOM 457 C . VAL A 58 ? -18.60000 11.51000 13.44500 1.000 90.25000 C ? A ? 58 1 + ATOM 458 O . VAL A 58 ? -17.54400 11.80800 12.88700 1.000 90.25000 O ? A ? 58 1 + ATOM 459 CB . VAL A 58 ? -20.37800 13.29200 13.62500 1.000 90.25000 C ? A ? 58 1 + ATOM 460 CG1 . VAL A 58 ? -19.31300 14.39200 13.53200 1.000 90.25000 C ? A ? 58 1 + ATOM 461 CG2 . VAL A 58 ? -21.67400 13.85000 13.02600 1.000 90.25000 C ? A ? 58 1 + ATOM 462 N . SER A 59 ? -18.63400 10.74500 14.53300 1.000 87.69000 N ? A ? 59 1 + ATOM 463 CA . SER A 59 ? -17.44700 10.20200 15.18600 1.000 87.69000 C ? A ? 59 1 + ATOM 464 C . SER A 59 ? -17.76700 8.92700 15.96000 1.000 87.69000 C ? A ? 59 1 + ATOM 465 O . SER A 59 ? -18.91600 8.68100 16.34600 1.000 87.69000 O ? A ? 59 1 + ATOM 466 CB . SER A 59 ? -16.80600 11.24900 16.11700 1.000 87.69000 C ? A ? 59 1 + ATOM 467 OG . SER A 59 ? -17.69700 11.64400 17.15500 1.000 87.69000 O ? A ? 59 1 + ATOM 468 N . LEU A 60 ? -16.74300 8.11400 16.22500 1.000 84.44000 N ? A ? 60 1 + ATOM 469 CA . LEU A 60 ? -16.79800 7.11300 17.28700 1.000 84.44000 C ? A ? 60 1 + ATOM 470 C . LEU A 60 ? -16.04900 7.63900 18.51300 1.000 84.44000 C ? A ? 60 1 + ATOM 471 O . LEU A 60 ? -15.12100 8.43900 18.41600 1.000 84.44000 O ? A ? 60 1 + ATOM 472 CB . LEU A 60 ? -16.30800 5.73100 16.80800 1.000 84.44000 C ? A ? 60 1 + ATOM 473 CG . LEU A 60 ? -17.02400 5.22000 15.54400 1.000 84.44000 C ? A ? 60 1 + ATOM 474 CD1 . LEU A 60 ? -16.37200 3.94300 15.03200 1.000 84.44000 C ? A ? 60 1 + ATOM 475 CD2 . LEU A 60 ? -18.47500 4.87200 15.85700 1.000 84.44000 C ? A ? 60 1 + ATOM 476 N . SER A 61 ? -16.47000 7.18000 19.68600 1.000 76.62000 N ? A ? 61 1 + ATOM 477 CA . SER A 61 ? -15.76500 7.43400 20.93900 1.000 76.62000 C ? A ? 61 1 + ATOM 478 C . SER A 61 ? -15.14600 6.13400 21.42400 1.000 76.62000 C ? A ? 61 1 + ATOM 479 O . SER A 61 ? -15.75800 5.06800 21.30100 1.000 76.62000 O ? A ? 61 1 + ATOM 480 CB . SER A 61 ? -16.71100 8.02800 21.97900 1.000 76.62000 C ? A ? 61 1 + ATOM 481 OG . SER A 61 ? -16.00900 8.33500 23.16300 1.000 76.62000 O ? A ? 61 1 + ATOM 482 N . THR A 62 ? -13.94700 6.22700 21.99300 1.000 69.50000 N ? A ? 62 1 + ATOM 483 CA . THR A 62 ? -13.23800 5.09700 22.60300 1.000 69.50000 C ? A ? 62 1 + ATOM 484 C . THR A 62 ? -14.06400 4.41600 23.69500 1.000 69.50000 C ? A ? 62 1 + ATOM 485 O . THR A 62 ? -14.05800 3.19000 23.78100 1.000 69.50000 O ? A ? 62 1 + ATOM 486 CB . THR A 62 ? -11.88800 5.56800 23.17400 1.000 69.50000 C ? A ? 62 1 + ATOM 487 OG1 . THR A 62 ? -12.00500 6.82100 23.80600 1.000 69.50000 O ? A ? 62 1 + ATOM 488 CG2 . THR A 62 ? -10.85500 5.76200 22.06900 1.000 69.50000 C ? A ? 62 1 + ATOM 489 N . ASP A 63 ? -14.86200 5.18100 24.44300 1.000 68.19000 N ? A ? 63 1 + ATOM 490 CA . ASP A 63 ? -15.76000 4.66400 25.48400 1.000 68.19000 C ? A ? 63 1 + ATOM 491 C . ASP A 63 ? -16.90900 3.80300 24.93000 1.000 68.19000 C ? A ? 63 1 + ATOM 492 O . ASP A 63 ? -17.50500 3.01100 25.65900 1.000 68.19000 O ? A ? 63 1 + ATOM 493 CB . ASP A 63 ? -16.35800 5.84600 26.26600 1.000 68.19000 C ? A ? 63 1 + ATOM 494 CG . ASP A 63 ? -15.34700 6.63100 27.11100 1.000 68.19000 C ? A ? 63 1 + ATOM 495 OD1 . ASP A 63 ? -14.31200 6.04800 27.50200 1.000 68.19000 O ? A ? 63 1 + ATOM 496 OD2 . ASP A 63 ? -15.66600 7.80500 27.41800 1.000 68.19000 O ? A ? 63 1 + ATOM 497 N . ASN A 64 ? -17.23300 3.94200 23.64200 1.000 72.75000 N ? A ? 64 1 + ATOM 498 CA . ASN A 64 ? -18.37300 3.26300 23.02500 1.000 72.75000 C ? A ? 64 1 + ATOM 499 C . ASN A 64 ? -17.97500 1.97900 22.28600 1.000 72.75000 C ? A ? 64 1 + ATOM 500 O . ASN A 64 ? -18.85100 1.25400 21.81300 1.000 72.75000 O ? A ? 64 1 + ATOM 501 CB . ASN A 64 ? -19.10700 4.24500 22.10100 1.000 72.75000 C ? A ? 64 1 + ATOM 502 CG . ASN A 64 ? -19.64100 5.48000 22.80200 1.000 72.75000 C ? A ? 64 1 + ATOM 503 OD1 . ASN A 64 ? -19.84900 5.54400 24.00200 1.000 72.75000 O ? A ? 64 1 + ATOM 504 ND2 . ASN A 64 ? -19.92300 6.51900 22.05600 1.000 72.75000 N ? A ? 64 1 + ATOM 505 N . LEU A 65 ? -16.67600 1.69300 22.15800 1.000 81.44000 N ? A ? 65 1 + ATOM 506 CA . LEU A 65 ? -16.20200 0.47200 21.51700 1.000 81.44000 C ? A ? 65 1 + ATOM 507 C . LEU A 65 ? -16.07900 -0.66300 22.55000 1.000 81.44000 C ? A ? 65 1 + ATOM 508 O . LEU A 65 ? -15.55000 -0.44500 23.64600 1.000 81.44000 O ? A ? 65 1 + ATOM 509 CB . LEU A 65 ? -14.88700 0.73200 20.76200 1.000 81.44000 C ? A ? 65 1 + ATOM 510 CG . LEU A 65 ? -15.03400 1.66900 19.54600 1.000 81.44000 C ? A ? 65 1 + ATOM 511 CD1 . LEU A 65 ? -13.65600 1.93800 18.94000 1.000 81.44000 C ? A ? 65 1 + ATOM 512 CD2 . LEU A 65 ? -15.91600 1.07700 18.44100 1.000 81.44000 C ? A ? 65 1 + ATOM 513 N . PRO A 66 ? -16.53900 -1.88400 22.22200 1.000 83.25000 N ? A ? 66 1 + ATOM 514 CA . PRO A 66 ? -16.33500 -3.03200 23.09000 1.000 83.25000 C ? A ? 66 1 + ATOM 515 C . PRO A 66 ? -14.84100 -3.36200 23.22900 1.000 83.25000 C ? A ? 66 1 + ATOM 516 O . PRO A 66 ? -14.09800 -3.31400 22.24300 1.000 83.25000 O ? A ? 66 1 + ATOM 517 CB . PRO A 66 ? -17.13400 -4.19900 22.51300 1.000 83.25000 C ? A ? 66 1 + ATOM 518 CG . PRO A 66 ? -17.70900 -3.69700 21.19400 1.000 83.25000 C ? A ? 66 1 + ATOM 519 CD . PRO A 66 ? -17.32200 -2.23000 21.05000 1.000 83.25000 C ? A ? 66 1 + ATOM 520 N . PRO A 67 ? -14.38100 -3.74500 24.43300 1.000 82.38000 N ? A ? 67 1 + ATOM 521 CA . PRO A 67 ? -12.96300 -3.99100 24.69400 1.000 82.38000 C ? A ? 67 1 + ATOM 522 C . PRO A 67 ? -12.41600 -5.21100 23.93800 1.000 82.38000 C ? A ? 67 1 + ATOM 523 O . PRO A 67 ? -11.21400 -5.30700 23.70700 1.000 82.38000 O ? A ? 67 1 + ATOM 524 CB . PRO A 67 ? -12.87300 -4.16900 26.21400 1.000 82.38000 C ? A ? 67 1 + ATOM 525 CG . PRO A 67 ? -14.26000 -4.68200 26.60900 1.000 82.38000 C ? A ? 67 1 + ATOM 526 CD . PRO A 67 ? -15.18100 -3.96300 25.63000 1.000 82.38000 C ? A ? 67 1 + ATOM 527 N . THR A 68 ? -13.27900 -6.14400 23.53200 1.000 89.00000 N ? A ? 68 1 + ATOM 528 CA . THR A 68 ? -12.90300 -7.36300 22.80300 1.000 89.00000 C ? A ? 68 1 + ATOM 529 C . THR A 68 ? -12.86400 -7.20200 21.28700 1.000 89.00000 C ? A ? 68 1 + ATOM 530 O . THR A 68 ? -12.45000 -8.13500 20.59200 1.000 89.00000 O ? A ? 68 1 + ATOM 531 CB . THR A 68 ? -13.80300 -8.53300 23.20900 1.000 89.00000 C ? A ? 68 1 + ATOM 532 OG1 . THR A 68 ? -15.14900 -8.13900 23.17300 1.000 89.00000 O ? A ? 68 1 + ATOM 533 CG2 . THR A 68 ? -13.48500 -8.94700 24.64800 1.000 89.00000 C ? A ? 68 1 + ATOM 534 N . LEU A 69 ? -13.21300 -6.01600 20.77600 1.000 90.94000 N ? A ? 69 1 + ATOM 535 CA . LEU A 69 ? -13.29500 -5.74400 19.34900 1.000 90.94000 C ? A ? 69 1 + ATOM 536 C . LEU A 69 ? -11.92700 -5.89800 18.67500 1.000 90.94000 C ? A ? 69 1 + ATOM 537 O . LEU A 69 ? -10.96100 -5.23600 19.04700 1.000 90.94000 O ? A ? 69 1 + ATOM 538 CB . LEU A 69 ? -13.89200 -4.34000 19.14400 1.000 90.94000 C ? A ? 69 1 + ATOM 539 CG . LEU A 69 ? -14.24400 -4.03300 17.68000 1.000 90.94000 C ? A ? 69 1 + ATOM 540 CD1 . LEU A 69 ? -15.44800 -4.84700 17.21500 1.000 90.94000 C ? A ? 69 1 + ATOM 541 CD2 . LEU A 69 ? -14.59800 -2.55600 17.52200 1.000 90.94000 C ? A ? 69 1 + ATOM 542 N . ARG A 70 ? -11.85900 -6.75400 17.65000 1.000 94.69000 N ? A ? 70 1 + ATOM 543 CA . ARG A 70 ? -10.64500 -7.05500 16.87200 1.000 94.69000 C ? A ? 70 1 + ATOM 544 C . ARG A 70 ? -10.68800 -6.47300 15.47200 1.000 94.69000 C ? A ? 70 1 + ATOM 545 O . ARG A 70 ? -9.64000 -6.14400 14.91700 1.000 94.69000 O ? A ? 70 1 + ATOM 546 CB . ARG A 70 ? -10.45300 -8.57000 16.75600 1.000 94.69000 C ? A ? 70 1 + ATOM 547 CG . ARG A 70 ? -10.26200 -9.23800 18.11600 1.000 94.69000 C ? A ? 70 1 + ATOM 548 CD . ARG A 70 ? -9.91500 -10.71600 17.91700 1.000 94.69000 C ? A ? 70 1 + ATOM 549 NE . ARG A 70 ? -9.69200 -11.38700 19.20800 1.000 94.69000 N ? A ? 70 1 + ATOM 550 CZ . ARG A 70 ? -8.60600 -11.30700 19.95300 1.000 94.69000 C ? A ? 70 1 + ATOM 551 NH1 . ARG A 70 ? -7.55300 -10.63600 19.57500 1.000 94.69000 N ? A ? 70 1 + ATOM 552 NH2 . ARG A 70 ? -8.56400 -11.89600 21.11300 1.000 94.69000 N ? A ? 70 1 + ATOM 553 N . THR A 71 ? -11.87100 -6.36000 14.88400 1.000 96.44000 N ? A ? 71 1 + ATOM 554 CA . THR A 71 ? -12.05100 -5.87800 13.51600 1.000 96.44000 C ? A ? 71 1 + ATOM 555 C . THR A 71 ? -13.18100 -4.86800 13.46000 1.000 96.44000 C ? A ? 71 1 + ATOM 556 O . THR A 71 ? -14.28700 -5.14500 13.92000 1.000 96.44000 O ? A ? 71 1 + ATOM 557 CB . THR A 71 ? -12.31400 -7.04400 12.55900 1.000 96.44000 C ? A ? 71 1 + ATOM 558 OG1 . THR A 71 ? -11.24100 -7.95800 12.63200 1.000 96.44000 O ? A ? 71 1 + ATOM 559 CG2 . THR A 71 ? -12.42600 -6.59800 11.10200 1.000 96.44000 C ? A ? 71 1 + ATOM 560 N . LEU A 72 ? -12.89300 -3.71400 12.86700 1.000 95.38000 N ? A ? 72 1 + ATOM 561 CA . LEU A 72 ? -13.86400 -2.66300 12.61100 1.000 95.38000 C ? A ? 72 1 + ATOM 562 C . LEU A 72 ? -13.81700 -2.26900 11.13600 1.000 95.38000 C ? A ? 72 1 + ATOM 563 O . LEU A 72 ? -12.75300 -1.91500 10.62900 1.000 95.38000 O ? A ? 72 1 + ATOM 564 CB . LEU A 72 ? -13.57500 -1.48200 13.54400 1.000 95.38000 C ? A ? 72 1 + ATOM 565 CG . LEU A 72 ? -14.51800 -0.28400 13.34800 1.000 95.38000 C ? A ? 72 1 + ATOM 566 CD1 . LEU A 72 ? -15.99600 -0.61400 13.53900 1.000 95.38000 C ? A ? 72 1 + ATOM 567 CD2 . LEU A 72 ? -14.16400 0.76600 14.38600 1.000 95.38000 C ? A ? 72 1 + ATOM 568 N . CYS A 73 ? -14.96800 -2.31700 10.47300 1.000 97.25000 N ? A ? 73 1 + ATOM 569 CA . CYS A 73 ? -15.15500 -1.80400 9.12000 1.000 97.25000 C ? A ? 73 1 + ATOM 570 C . CYS A 73 ? -16.18800 -0.67200 9.14800 1.000 97.25000 C ? A ? 73 1 + ATOM 571 O . CYS A 73 ? -17.27300 -0.84100 9.70600 1.000 97.25000 O ? A ? 73 1 + ATOM 572 CB . CYS A 73 ? -15.57900 -2.94900 8.19600 1.000 97.25000 C ? A ? 73 1 + ATOM 573 SG . CYS A 73 ? -15.77200 -2.37800 6.48100 1.000 97.25000 S ? A ? 73 1 + ATOM 574 N . ILE A 74 ? -15.86300 0.47000 8.54800 1.000 96.88000 N ? A ? 74 1 + ATOM 575 CA . ILE A 74 ? -16.79700 1.57700 8.33700 1.000 96.88000 C ? A ? 74 1 + ATOM 576 C . ILE A 74 ? -16.87700 1.85000 6.83600 1.000 96.88000 C ? A ? 74 1 + ATOM 577 O . ILE A 74 ? -15.85300 2.09000 6.20400 1.000 96.88000 O ? A ? 74 1 + ATOM 578 CB . ILE A 74 ? -16.41300 2.83600 9.14300 1.000 96.88000 C ? A ? 74 1 + ATOM 579 CG1 . ILE A 74 ? -16.15900 2.51600 10.63600 1.000 96.88000 C ? A ? 74 1 + ATOM 580 CG2 . ILE A 74 ? -17.55000 3.85900 8.98400 1.000 96.88000 C ? A ? 74 1 + ATOM 581 CD1 . ILE A 74 ? -15.65500 3.71200 11.45200 1.000 96.88000 C ? A ? 74 1 + ATOM 582 N . LEU A 75 ? -18.07300 1.79600 6.25700 1.000 97.88000 N ? A ? 75 1 + ATOM 583 CA . LEU A 75 ? -18.29000 1.90000 4.81400 1.000 97.88000 C ? A ? 75 1 + ATOM 584 C . LEU A 75 ? -19.39600 2.91000 4.49900 1.000 97.88000 C ? A ? 75 1 + ATOM 585 O . LEU A 75 ? -20.51800 2.78300 4.99000 1.000 97.88000 O ? A ? 75 1 + ATOM 586 CB . LEU A 75 ? -18.59300 0.49600 4.26000 1.000 97.88000 C ? A ? 75 1 + ATOM 587 CG . LEU A 75 ? -19.00100 0.44700 2.77600 1.000 97.88000 C ? A ? 75 1 + ATOM 588 CD1 . LEU A 75 ? -17.89000 0.88100 1.82200 1.000 97.88000 C ? A ? 75 1 + ATOM 589 CD2 . LEU A 75 ? -19.39500 -0.98200 2.39900 1.000 97.88000 C ? A ? 75 1 + ATOM 590 N . SER A 76 ? -19.10000 3.86700 3.62400 1.000 97.25000 N ? A ? 76 1 + ATOM 591 CA . SER A 76 ? -20.06600 4.83500 3.09100 1.000 97.25000 C ? A ? 76 1 + ATOM 592 C . SER A 76 ? -20.78300 5.64500 4.19300 1.000 97.25000 C ? A ? 76 1 + ATOM 593 O . SER A 76 ? -21.99500 5.85100 4.14400 1.000 97.25000 O ? A ? 76 1 + ATOM 594 CB . SER A 76 ? -21.03600 4.17800 2.09000 1.000 97.25000 C ? A ? 76 1 + ATOM 595 OG . SER A 76 ? -20.44600 3.19200 1.24800 1.000 97.25000 O ? A ? 76 1 + ATOM 596 N . CYS A 77 ? -20.05600 6.06700 5.23600 1.000 96.25000 N ? A ? 77 1 + ATOM 597 CA . CYS A 77 ? -20.55600 6.97300 6.28100 1.000 96.25000 C ? A ? 77 1 + ATOM 598 C . CYS A 77 ? -20.16900 8.41900 5.94500 1.000 96.25000 C ? A ? 77 1 + ATOM 599 O . CYS A 77 ? -19.10600 8.89500 6.33600 1.000 96.25000 O ? A ? 77 1 + ATOM 600 CB . CYS A 77 ? -20.03100 6.53700 7.65600 1.000 96.25000 C ? A ? 77 1 + ATOM 601 SG . CYS A 77 ? -20.97700 5.11300 8.25700 1.000 96.25000 S ? A ? 77 1 + ATOM 602 N . GLU A 78 ? -21.03400 9.10500 5.19800 1.000 93.06000 N ? A ? 78 1 + ATOM 603 CA . GLU A 78 ? -20.71300 10.37000 4.51800 1.000 93.06000 C ? A ? 78 1 + ATOM 604 C . GLU A 78 ? -20.32300 11.52400 5.45500 1.000 93.06000 C ? A ? 78 1 + ATOM 605 O . GLU A 78 ? -19.40600 12.26300 5.11600 1.000 93.06000 O ? A ? 78 1 + ATOM 606 CB . GLU A 78 ? -21.90200 10.77700 3.63300 1.000 93.06000 C ? A ? 78 1 + ATOM 607 CG . GLU A 78 ? -22.13600 9.78300 2.47800 1.000 93.06000 C ? A ? 78 1 + ATOM 608 CD . GLU A 78 ? -23.41000 10.07500 1.66200 1.000 93.06000 C ? A ? 78 1 + ATOM 609 OE1 . GLU A 78 ? -23.73800 9.23100 0.79600 1.000 93.06000 O ? A ? 78 1 + ATOM 610 OE2 . GLU A 78 ? -24.10400 11.07400 1.96200 1.000 93.06000 O ? A ? 78 1 + ATOM 611 N . ASN A 79 ? -20.94000 11.65100 6.64000 1.000 95.19000 N ? A ? 79 1 + ATOM 612 CA . ASN A 79 ? -20.62300 12.71400 7.61200 1.000 95.19000 C ? A ? 79 1 + ATOM 613 C . ASN A 79 ? -19.59300 12.30800 8.68100 1.000 95.19000 C ? A ? 79 1 + ATOM 614 O . ASN A 79 ? -19.39000 13.05800 9.63600 1.000 95.19000 O ? A ? 79 1 + ATOM 615 CB . ASN A 79 ? -21.90500 13.26400 8.26000 1.000 95.19000 C ? A ? 79 1 + ATOM 616 CG . ASN A 79 ? -22.79800 14.01200 7.28700 1.000 95.19000 C ? A ? 79 1 + ATOM 617 OD1 . ASN A 79 ? -22.36300 14.80800 6.48000 1.000 95.19000 O ? A ? 79 1 + ATOM 618 ND2 . ASN A 79 ? -24.09100 13.82800 7.33800 1.000 95.19000 N ? A ? 79 1 + ATOM 619 N . LEU A 80 ? -18.94600 11.14300 8.55300 1.000 94.19000 N ? A ? 80 1 + ATOM 620 CA . LEU A 80 ? -17.92600 10.71800 9.51100 1.000 94.19000 C ? A ? 80 1 + ATOM 621 C . LEU A 80 ? -16.70900 11.63100 9.37700 1.000 94.19000 C ? A ? 80 1 + ATOM 622 O . LEU A 80 ? -15.91900 11.45400 8.45900 1.000 94.19000 O ? A ? 80 1 + ATOM 623 CB . LEU A 80 ? -17.56200 9.24400 9.26700 1.000 94.19000 C ? A ? 80 1 + ATOM 624 CG . LEU A 80 ? -16.50400 8.70700 10.25200 1.000 94.19000 C ? A ? 80 1 + ATOM 625 CD1 . LEU A 80 ? -17.11900 8.39000 11.61500 1.000 94.19000 C ? A ? 80 1 + ATOM 626 CD2 . LEU A 80 ? -15.90200 7.41900 9.69400 1.000 94.19000 C ? A ? 80 1 + ATOM 627 N . GLU A 81 ? -16.53100 12.57200 10.30000 1.000 92.75000 N ? A ? 81 1 + ATOM 628 CA . GLU A 81 ? -15.41000 13.51400 10.27600 1.000 92.75000 C ? A ? 81 1 + ATOM 629 C . GLU A 81 ? -14.14300 12.93600 10.90900 1.000 92.75000 C ? A ? 81 1 + ATOM 630 O . GLU A 81 ? -13.02500 13.28600 10.51700 1.000 92.75000 O ? A ? 81 1 + ATOM 631 CB . GLU A 81 ? -15.78600 14.82600 10.97700 1.000 92.75000 C ? A ? 81 1 + ATOM 632 CG . GLU A 81 ? -16.85500 15.61500 10.20300 1.000 92.75000 C ? A ? 81 1 + ATOM 633 CD . GLU A 81 ? -16.91800 17.09500 10.61300 1.000 92.75000 C ? A ? 81 1 + ATOM 634 OE1 . GLU A 81 ? -18.02400 17.67100 10.63100 1.000 92.75000 O ? A ? 81 1 + ATOM 635 OE2 . GLU A 81 ? -15.83500 17.71500 10.78900 1.000 92.75000 O ? A ? 81 1 + ATOM 636 N . CYS A 82 ? -14.30300 12.04400 11.89000 1.000 89.06000 N ? A ? 82 1 + ATOM 637 CA . CYS A 82 ? -13.18700 11.40500 12.57200 1.000 89.06000 C ? A ? 82 1 + ATOM 638 C . CYS A 82 ? -13.52300 9.98800 13.02500 1.000 89.06000 C ? A ? 82 1 + ATOM 639 O . CYS A 82 ? -14.63600 9.73200 13.47400 1.000 89.06000 O ? A ? 82 1 + ATOM 640 CB . CYS A 82 ? -12.76900 12.28700 13.74800 1.000 89.06000 C ? A ? 82 1 + ATOM 641 SG . CYS A 82 ? -11.22800 11.67600 14.48900 1.000 89.06000 S ? A ? 82 1 + ATOM 642 N . PHE A 83 ? -12.55500 9.06900 12.96700 1.000 84.38000 N ? A ? 83 1 + ATOM 643 CA . PHE A 83 ? -12.75200 7.73800 13.54100 1.000 84.38000 C ? A ? 83 1 + ATOM 644 C . PHE A 83 ? -12.84800 7.79900 15.07500 1.000 84.38000 C ? A ? 83 1 + ATOM 645 O . PHE A 83 ? -13.86900 7.37300 15.60300 1.000 84.38000 O ? A ? 83 1 + ATOM 646 CB . PHE A 83 ? -11.72300 6.73100 12.99800 1.000 84.38000 C ? A ? 83 1 + ATOM 647 CG . PHE A 83 ? -11.57300 5.46500 13.81800 1.000 84.38000 C ? A ? 83 1 + ATOM 648 CD1 . PHE A 83 ? -10.32300 5.07500 14.33800 1.000 84.38000 C ? A ? 83 1 + ATOM 649 CD2 . PHE A 83 ? -12.71200 4.70400 14.11300 1.000 84.38000 C ? A ? 83 1 + ATOM 650 CE1 . PHE A 83 ? -10.22000 3.93000 15.15200 1.000 84.38000 C ? A ? 83 1 + ATOM 651 CE2 . PHE A 83 ? -12.61600 3.60100 14.97600 1.000 84.38000 C ? A ? 83 1 + ATOM 652 CZ . PHE A 83 ? -11.37100 3.19600 15.47900 1.000 84.38000 C ? A ? 83 1 + ATOM 653 N . LEU A 84 ? -11.86400 8.36300 15.78700 1.000 80.19000 N ? A ? 84 1 + ATOM 654 CA . LEU A 84 ? -11.88900 8.48500 17.25300 1.000 80.19000 C ? A ? 84 1 + ATOM 655 C . LEU A 84 ? -11.84700 9.94000 17.73100 1.000 80.19000 C ? A ? 84 1 + ATOM 656 O . LEU A 84 ? -10.86900 10.67100 17.53000 1.000 80.19000 O ? A ? 84 1 + ATOM 657 CB . LEU A 84 ? -10.76200 7.65700 17.89100 1.000 80.19000 C ? A ? 84 1 + ATOM 658 CG . LEU A 84 ? -10.93500 6.14000 17.71700 1.000 80.19000 C ? A ? 84 1 + ATOM 659 CD1 . LEU A 84 ? -9.68000 5.42200 18.21500 1.000 80.19000 C ? A ? 84 1 + ATOM 660 CD2 . LEU A 84 ? -12.15300 5.56600 18.44500 1.000 80.19000 C ? A ? 84 1 + ATOM 661 N . GLU A 85 ? -12.91100 10.33600 18.42400 1.000 72.69000 N ? A ? 85 1 + ATOM 662 CA . GLU A 85 ? -12.98600 11.57600 19.18600 1.000 72.69000 C ? A ? 85 1 + ATOM 663 C . GLU A 85 ? -12.48200 11.33400 20.61700 1.000 72.69000 C ? A ? 85 1 + ATOM 664 O . GLU A 85 ? -13.19400 10.79200 21.46400 1.000 72.69000 O ? A ? 85 1 + ATOM 665 CB . GLU A 85 ? -14.42300 12.12100 19.11900 1.000 72.69000 C ? A ? 85 1 + ATOM 666 CG . GLU A 85 ? -14.54600 13.55600 19.65300 1.000 72.69000 C ? A ? 85 1 + ATOM 667 CD . GLU A 85 ? -15.96300 14.14500 19.49000 1.000 72.69000 C ? A ? 85 1 + ATOM 668 OE1 . GLU A 85 ? -16.11100 15.36100 19.74200 1.000 72.69000 O ? A ? 85 1 + ATOM 669 OE2 . GLU A 85 ? -16.91500 13.39700 19.14600 1.000 72.69000 O ? A ? 85 1 + ATOM 670 N . ASP A 86 ? -11.24000 11.74600 20.88100 1.000 64.75000 N ? A ? 86 1 + ATOM 671 CA . ASP A 86 ? -10.64400 11.72600 22.21600 1.000 64.75000 C ? A ? 86 1 + ATOM 672 C . ASP A 86 ? -10.58500 13.14900 22.77900 1.000 64.75000 C ? A ? 86 1 + ATOM 673 O . ASP A 86 ? -10.16800 14.09000 22.09800 1.000 64.75000 O ? A ? 86 1 + ATOM 674 CB . ASP A 86 ? -9.23600 11.11900 22.18800 1.000 64.75000 C ? A ? 86 1 + ATOM 675 CG . ASP A 86 ? -9.18100 9.64700 21.76600 1.000 64.75000 C ? A ? 86 1 + ATOM 676 OD1 . ASP A 86 ? -10.09100 8.87600 22.15400 1.000 64.75000 O ? A ? 86 1 + ATOM 677 OD2 . ASP A 86 ? -8.17500 9.31400 21.09000 1.000 64.75000 O ? A ? 86 1 + ATOM 678 N . LYS A 87 ? -10.94200 13.31100 24.05600 1.000 58.28000 N ? A ? 87 1 + ATOM 679 CA . LYS A 87 ? -10.59200 14.52700 24.79700 1.000 58.28000 C ? A ? 87 1 + ATOM 680 C . LYS A 87 ? -9.07900 14.52200 25.02700 1.000 58.28000 C ? A ? 87 1 + ATOM 681 O . LYS A 87 ? -8.51800 13.49500 25.41300 1.000 58.28000 O ? A ? 87 1 + ATOM 682 CB . LYS A 87 ? -11.39300 14.62700 26.10500 1.000 58.28000 C ? A ? 87 1 + ATOM 683 CG . LYS A 87 ? -12.89000 14.83900 25.82200 1.000 58.28000 C ? A ? 87 1 + ATOM 684 CD . LYS A 87 ? -13.68900 15.01700 27.11700 1.000 58.28000 C ? A ? 87 1 + ATOM 685 CE . LYS A 87 ? -15.16500 15.23800 26.76700 1.000 58.28000 C ? A ? 87 1 + ATOM 686 NZ . LYS A 87 ? -15.99300 15.40200 27.98500 1.000 58.28000 N ? A ? 87 1 + ATOM 687 N . GLU A 88 ? -8.42500 15.65500 24.77400 1.000 46.88000 N ? A ? 88 1 + ATOM 688 CA . GLU A 88 ? -6.98500 15.83400 24.99900 1.000 46.88000 C ? A ? 88 1 + ATOM 689 C . GLU A 88 ? -6.57300 15.26300 26.37700 1.000 46.88000 C ? A ? 88 1 + ATOM 690 O . GLU A 88 ? -7.24700 15.51800 27.37400 1.000 46.88000 O ? A ? 88 1 + ATOM 691 CB . GLU A 88 ? -6.61600 17.33000 24.88900 1.000 46.88000 C ? A ? 88 1 + ATOM 692 CG . GLU A 88 ? -6.85200 17.93200 23.48800 1.000 46.88000 C ? A ? 88 1 + ATOM 693 CD . GLU A 88 ? -6.36200 19.38900 23.35800 1.000 46.88000 C ? A ? 88 1 + ATOM 694 OE1 . GLU A 88 ? -6.03700 19.79100 22.21600 1.000 46.88000 O ? A ? 88 1 + ATOM 695 OE2 . GLU A 88 ? -6.29900 20.08800 24.39500 1.000 46.88000 O ? A ? 88 1 + ATOM 696 N . ASN A 89 ? -5.47700 14.49100 26.42500 1.000 43.38000 N ? A ? 89 1 + ATOM 697 CA . ASN A 89 ? -4.90000 13.77900 27.59000 1.000 43.38000 C ? A ? 89 1 + ATOM 698 C . ASN A 89 ? -5.42800 12.38700 27.97500 1.000 43.38000 C ? A ? 89 1 + ATOM 699 O . ASN A 89 ? -4.94700 11.83300 28.96800 1.000 43.38000 O ? A ? 89 1 + ATOM 700 CB . ASN A 89 ? -4.75300 14.68400 28.83200 1.000 43.38000 C ? A ? 89 1 + ATOM 701 CG . ASN A 89 ? -3.74500 15.78500 28.64800 1.000 43.38000 C ? A ? 89 1 + ATOM 702 OD1 . ASN A 89 ? -2.75500 15.65300 27.95000 1.000 43.38000 O ? A ? 89 1 + ATOM 703 ND2 . ASN A 89 ? -3.93300 16.89300 29.31900 1.000 43.38000 N ? A ? 89 1 + ATOM 704 N . ILE A 90 ? -6.30700 11.74600 27.20600 1.000 47.25000 N ? A ? 90 1 + ATOM 705 CA . ILE A 90 ? -6.54400 10.31100 27.41200 1.000 47.25000 C ? A ? 90 1 + ATOM 706 C . ILE A 90 ? -5.47200 9.55100 26.62900 1.000 47.25000 C ? A ? 90 1 + ATOM 707 O . ILE A 90 ? -5.52100 9.45500 25.40500 1.000 47.25000 O ? A ? 90 1 + ATOM 708 CB . ILE A 90 ? -8.00500 9.90900 27.12100 1.000 47.25000 C ? A ? 90 1 + ATOM 709 CG1 . ILE A 90 ? -8.95200 10.78400 27.98200 1.000 47.25000 C ? A ? 90 1 + ATOM 710 CG2 . ILE A 90 ? -8.20900 8.41600 27.44600 1.000 47.25000 C ? A ? 90 1 + ATOM 711 CD1 . ILE A 90 ? -10.44400 10.53900 27.74000 1.000 47.25000 C ? A ? 90 1 + ATOM 712 N . ASN A 91 ? -4.45600 9.04600 27.34100 1.000 45.00000 N ? A ? 91 1 + ATOM 713 CA . ASN A 91 ? -3.62600 7.95600 26.82900 1.000 45.00000 C ? A ? 91 1 + ATOM 714 C . ASN A 91 ? -4.58900 6.91900 26.26200 1.000 45.00000 C ? A ? 91 1 + ATOM 715 O . ASN A 91 ? -5.43500 6.46000 27.03100 1.000 45.00000 O ? A ? 91 1 + ATOM 716 CB . ASN A 91 ? -2.81100 7.31500 27.97600 1.000 45.00000 C ? A ? 91 1 + ATOM 717 CG . ASN A 91 ? -1.43600 7.91100 28.18300 1.000 45.00000 C ? A ? 91 1 + ATOM 718 OD1 . ASN A 91 ? -0.87200 8.58200 27.33500 1.000 45.00000 O ? A ? 91 1 + ATOM 719 ND2 . ASN A 91 ? -0.82400 7.64400 29.31400 1.000 45.00000 N ? A ? 91 1 + ATOM 720 N . PHE A 92 ? -4.47200 6.59300 24.96500 1.000 49.47000 N ? A ? 92 1 + ATOM 721 CA . PHE A 92 ? -5.17700 5.46600 24.35400 1.000 49.47000 C ? A ? 92 1 + ATOM 722 C . PHE A 92 ? -5.27100 4.37900 25.40200 1.000 49.47000 C ? A ? 92 1 + ATOM 723 O . PHE A 92 ? -4.23400 3.92800 25.90200 1.000 49.47000 O ? A ? 92 1 + ATOM 724 CB . PHE A 92 ? -4.39800 4.91600 23.14800 1.000 49.47000 C ? A ? 92 1 + ATOM 725 CG . PHE A 92 ? -4.83700 5.52100 21.84000 1.000 49.47000 C ? A ? 92 1 + ATOM 726 CD1 . PHE A 92 ? -5.84200 4.89000 21.08400 1.000 49.47000 C ? A ? 92 1 + ATOM 727 CD2 . PHE A 92 ? -4.30000 6.74700 21.41600 1.000 49.47000 C ? A ? 92 1 + ATOM 728 CE1 . PHE A 92 ? -6.30700 5.48100 19.89900 1.000 49.47000 C ? A ? 92 1 + ATOM 729 CE2 . PHE A 92 ? -4.79000 7.34600 20.24500 1.000 49.47000 C ? A ? 92 1 + ATOM 730 CZ . PHE A 92 ? -5.78700 6.71500 19.48700 1.000 49.47000 C ? A ? 92 1 + ATOM 731 N . SER A 93 ? -6.49400 4.05000 25.81800 1.000 50.53000 N ? A ? 93 1 + ATOM 732 CA . SER A 93 ? -6.66100 2.99800 26.79300 1.000 50.53000 C ? A ? 93 1 + ATOM 733 C . SER A 93 ? -5.95100 1.79800 26.18700 1.000 50.53000 C ? A ? 93 1 + ATOM 734 O . SER A 93 ? -6.23200 1.35100 25.07300 1.000 50.53000 O ? A ? 93 1 + ATOM 735 CB . SER A 93 ? -8.13600 2.76400 27.12700 1.000 50.53000 C ? A ? 93 1 + ATOM 736 OG . SER A 93 ? -8.90000 2.58600 25.95200 1.000 50.53000 O ? A ? 93 1 + ATOM 737 N . SER A 94 ? -4.94400 1.31600 26.89900 1.000 50.47000 N ? A ? 94 1 + ATOM 738 CA . SER A 94 ? -4.11600 0.16000 26.56700 1.000 50.47000 C ? A ? 94 1 + ATOM 739 C . SER A 94 ? -4.93500 -1.14300 26.46900 1.000 50.47000 C ? A ? 94 1 + ATOM 740 O . SER A 94 ? -4.38300 -2.23900 26.49100 1.000 50.47000 O ? A ? 94 1 + ATOM 741 CB . SER A 94 ? -3.00200 0.08700 27.62400 1.000 50.47000 C ? A ? 94 1 + ATOM 742 OG . SER A 94 ? -3.48500 0.44900 28.91500 1.000 50.47000 O ? A ? 94 1 + ATOM 743 N . THR A 95 ? -6.25900 -1.01900 26.36900 1.000 54.34000 N ? A ? 95 1 + ATOM 744 CA . THR A 95 ? -7.29900 -2.03000 26.44400 1.000 54.34000 C ? A ? 95 1 + ATOM 745 C . THR A 95 ? -7.92900 -2.33800 25.08900 1.000 54.34000 C ? A ? 95 1 + ATOM 746 O . THR A 95 ? -8.55500 -3.38500 24.96900 1.000 54.34000 O ? A ? 95 1 + ATOM 747 CB . THR A 95 ? -8.40900 -1.55900 27.39800 1.000 54.34000 C ? A ? 95 1 + ATOM 748 OG1 . THR A 95 ? -9.02700 -0.40000 26.89200 1.000 54.34000 O ? A ? 95 1 + ATOM 749 CG2 . THR A 95 ? -7.88600 -1.19500 28.79000 1.000 54.34000 C ? A ? 95 1 + ATOM 750 N . SER A 96 ? -7.77500 -1.48400 24.06500 1.000 74.44000 N ? A ? 96 1 + ATOM 751 CA . SER A 96 ? -8.30700 -1.80200 22.73400 1.000 74.44000 C ? A ? 96 1 + ATOM 752 C . SER A 96 ? -7.54600 -2.98100 22.12200 1.000 74.44000 C ? A ? 96 1 + ATOM 753 O . SER A 96 ? -6.33900 -2.90100 21.87300 1.000 74.44000 O ? A ? 96 1 + ATOM 754 CB . SER A 96 ? -8.27400 -0.59200 21.79700 1.000 74.44000 C ? A ? 96 1 + ATOM 755 OG . SER A 96 ? -8.89800 -0.92900 20.57000 1.000 74.44000 O ? A ? 96 1 + ATOM 756 N . LEU A 97 ? -8.26900 -4.07200 21.85600 1.000 87.69000 N ? A ? 97 1 + ATOM 757 CA . LEU A 97 ? -7.76400 -5.25200 21.15000 1.000 87.69000 C ? A ? 97 1 + ATOM 758 C . LEU A 97 ? -7.90700 -5.13700 19.62500 1.000 87.69000 C ? A ? 97 1 + ATOM 759 O . LEU A 97 ? -7.79300 -6.14500 18.92000 1.000 87.69000 O ? A ? 97 1 + ATOM 760 CB . LEU A 97 ? -8.44300 -6.52400 21.69400 1.000 87.69000 C ? A ? 97 1 + ATOM 761 CG . LEU A 97 ? -8.25900 -6.79100 23.19900 1.000 87.69000 C ? A ? 97 1 + ATOM 762 CD1 . LEU A 97 ? -8.85500 -8.15600 23.54500 1.000 87.69000 C ? A ? 97 1 + ATOM 763 CD2 . LEU A 97 ? -6.79500 -6.82700 23.63100 1.000 87.69000 C ? A ? 97 1 + ATOM 764 N . LEU A 98 ? -8.16800 -3.92900 19.11100 1.000 91.00000 N ? A ? 98 1 + ATOM 765 CA . LEU A 98 ? -8.42300 -3.70500 17.69600 1.000 91.00000 C ? A ? 98 1 + ATOM 766 C . LEU A 98 ? -7.16900 -4.02800 16.88200 1.000 91.00000 C ? A ? 98 1 + ATOM 767 O . LEU A 98 ? -6.12200 -3.41100 17.05500 1.000 91.00000 O ? A ? 98 1 + ATOM 768 CB . LEU A 98 ? -8.92100 -2.26700 17.47300 1.000 91.00000 C ? A ? 98 1 + ATOM 769 CG . LEU A 98 ? -9.40600 -2.00100 16.03600 1.000 91.00000 C ? A ? 98 1 + ATOM 770 CD1 . LEU A 98 ? -10.70900 -2.73700 15.72500 1.000 91.00000 C ? A ? 98 1 + ATOM 771 CD2 . LEU A 98 ? -9.66500 -0.50900 15.83800 1.000 91.00000 C ? A ? 98 1 + ATOM 772 N . GLN A 99 ? -7.29700 -4.99700 15.98000 1.000 95.31000 N ? A ? 99 1 + ATOM 773 CA . GLN A 99 ? -6.21900 -5.51600 15.13900 1.000 95.31000 C ? A ? 99 1 + ATOM 774 C . GLN A 99 ? -6.36700 -5.09400 13.67900 1.000 95.31000 C ? A ? 99 1 + ATOM 775 O . GLN A 99 ? -5.35800 -4.93400 12.99800 1.000 95.31000 O ? A ? 99 1 + ATOM 776 CB . GLN A 99 ? -6.19700 -7.04700 15.24300 1.000 95.31000 C ? A ? 99 1 + ATOM 777 CG . GLN A 99 ? -5.62500 -7.49400 16.59100 1.000 95.31000 C ? A ? 99 1 + ATOM 778 CD . GLN A 99 ? -5.72500 -8.99100 16.83900 1.000 95.31000 C ? A ? 99 1 + ATOM 779 OE1 . GLN A 99 ? -6.27400 -9.77800 16.08800 1.000 95.31000 O ? A ? 99 1 + ATOM 780 NE2 . GLN A 99 ? -5.16900 -9.46500 17.93200 1.000 95.31000 N ? A ? 99 1 + ATOM 781 N . SER A 100 ? -7.59100 -4.89100 13.19600 1.000 97.25000 N ? A ? 100 1 + ATOM 782 CA . SER A 100 ? -7.85900 -4.48200 11.81700 1.000 97.25000 C ? A ? 100 1 + ATOM 783 C . SER A 100 ? -8.87700 -3.35100 11.78700 1.000 97.25000 C ? A ? 100 1 + ATOM 784 O . SER A 100 ? -9.98800 -3.51000 12.29400 1.000 97.25000 O ? A ? 100 1 + ATOM 785 CB . SER A 100 ? -8.35000 -5.68400 11.00700 1.000 97.25000 C ? A ? 100 1 + ATOM 786 OG . SER A 100 ? -8.45700 -5.36100 9.63400 1.000 97.25000 O ? A ? 100 1 + ATOM 787 N . LEU A 101 ? -8.50200 -2.23700 11.16400 1.000 96.19000 N ? A ? 101 1 + ATOM 788 CA . LEU A 101 ? -9.37400 -1.09800 10.90600 1.000 96.19000 C ? A ? 101 1 + ATOM 789 C . LEU A 101 ? -9.46200 -0.88200 9.40100 1.000 96.19000 C ? A ? 101 1 + ATOM 790 O . LEU A 101 ? -8.44100 -0.72900 8.73100 1.000 96.19000 O ? A ? 101 1 + ATOM 791 CB . LEU A 101 ? -8.84000 0.15000 11.62800 1.000 96.19000 C ? A ? 101 1 + ATOM 792 CG . LEU A 101 ? -9.66400 1.42800 11.37100 1.000 96.19000 C ? A ? 101 1 + ATOM 793 CD1 . LEU A 101 ? -11.10700 1.30300 11.86500 1.000 96.19000 C ? A ? 101 1 + ATOM 794 CD2 . LEU A 101 ? -9.01200 2.59700 12.10600 1.000 96.19000 C ? A ? 101 1 + ATOM 795 N . GLU A 102 ? -10.68600 -0.85000 8.89800 1.000 98.00000 N ? A ? 102 1 + ATOM 796 CA . GLU A 102 ? -10.98300 -0.56400 7.50700 1.000 98.00000 C ? A ? 102 1 + ATOM 797 C . GLU A 102 ? -12.01100 0.56500 7.42400 1.000 98.00000 C ? A ? 102 1 + ATOM 798 O . GLU A 102 ? -13.07900 0.47500 8.02600 1.000 98.00000 O ? A ? 102 1 + ATOM 799 CB . GLU A 102 ? -11.46300 -1.85300 6.84000 1.000 98.00000 C ? A ? 102 1 + ATOM 800 CG . GLU A 102 ? -11.62300 -1.65100 5.34000 1.000 98.00000 C ? A ? 102 1 + ATOM 801 CD . GLU A 102 ? -12.11600 -2.93400 4.68800 1.000 98.00000 C ? A ? 102 1 + ATOM 802 OE1 . GLU A 102 ? -13.24300 -2.91300 4.16900 1.000 98.00000 O ? A ? 102 1 + ATOM 803 OE2 . GLU A 102 ? -11.34000 -3.89400 4.51200 1.000 98.00000 O ? A ? 102 1 + ATOM 804 N . ILE A 103 ? -11.70000 1.63100 6.69100 1.000 97.81000 N ? A ? 103 1 + ATOM 805 CA . ILE A 103 ? -12.62700 2.74000 6.44700 1.000 97.81000 C ? A ? 103 1 + ATOM 806 C . ILE A 103 ? -12.70300 2.98600 4.94600 1.000 97.81000 C ? A ? 103 1 + ATOM 807 O . ILE A 103 ? -11.67800 3.16300 4.29000 1.000 97.81000 O ? A ? 103 1 + ATOM 808 CB . ILE A 103 ? -12.24600 4.00400 7.24200 1.000 97.81000 C ? A ? 103 1 + ATOM 809 CG1 . ILE A 103 ? -12.17900 3.70200 8.75800 1.000 97.81000 C ? A ? 103 1 + ATOM 810 CG2 . ILE A 103 ? -13.30000 5.09100 6.96700 1.000 97.81000 C ? A ? 103 1 + ATOM 811 CD1 . ILE A 103 ? -11.59400 4.85300 9.57100 1.000 97.81000 C ? A ? 103 1 + ATOM 812 N . ARG A 104 ? -13.91100 2.96400 4.38600 1.000 98.06000 N ? A ? 104 1 + ATOM 813 CA . ARG A 104 ? -14.15200 3.05800 2.94600 1.000 98.06000 C ? A ? 104 1 + ATOM 814 C . ARG A 104 ? -15.23400 4.08100 2.64100 1.000 98.06000 C ? A ? 104 1 + ATOM 815 O . ARG A 104 ? -16.28000 4.06300 3.28000 1.000 98.06000 O ? A ? 104 1 + ATOM 816 CB . ARG A 104 ? -14.53900 1.69000 2.37900 1.000 98.06000 C ? A ? 104 1 + ATOM 817 CG . ARG A 104 ? -13.47300 0.61200 2.59300 1.000 98.06000 C ? A ? 104 1 + ATOM 818 CD . ARG A 104 ? -13.70200 -0.56500 1.64200 1.000 98.06000 C ? A ? 104 1 + ATOM 819 NE . ARG A 104 ? -12.70000 -1.62300 1.84900 1.000 98.06000 N ? A ? 104 1 + ATOM 820 CZ . ARG A 104 ? -12.70600 -2.82900 1.31300 1.000 98.06000 C ? A ? 104 1 + ATOM 821 NH1 . ARG A 104 ? -13.51500 -3.12600 0.33500 1.000 98.06000 N ? A ? 104 1 + ATOM 822 NH2 . ARG A 104 ? -11.91700 -3.77200 1.74500 1.000 98.06000 N ? A ? 104 1 + ATOM 823 N . GLU A 105 ? -15.01600 4.90500 1.62200 1.000 97.62000 N ? A ? 105 1 + ATOM 824 CA . GLU A 105 ? -16.04300 5.80600 1.07100 1.000 97.62000 C ? A ? 105 1 + ATOM 825 C . GLU A 105 ? -16.64300 6.77200 2.11900 1.000 97.62000 C ? A ? 105 1 + ATOM 826 O . GLU A 105 ? -17.81800 7.12100 2.06000 1.000 97.62000 O ? A ? 105 1 + ATOM 827 CB . GLU A 105 ? -17.11500 4.99500 0.31300 1.000 97.62000 C ? A ? 105 1 + ATOM 828 CG . GLU A 105 ? -16.55600 4.13600 -0.83600 1.000 97.62000 C ? A ? 105 1 + ATOM 829 CD . GLU A 105 ? -17.61700 3.22000 -1.47100 1.000 97.62000 C ? A ? 105 1 + ATOM 830 OE1 . GLU A 105 ? -17.20500 2.36200 -2.28800 1.000 97.62000 O ? A ? 105 1 + ATOM 831 OE2 . GLU A 105 ? -18.81300 3.33000 -1.10600 1.000 97.62000 O ? A ? 105 1 + ATOM 832 N . CYS A 106 ? -15.85400 7.19900 3.11100 1.000 97.00000 N ? A ? 106 1 + ATOM 833 CA . CYS A 106 ? -16.27100 8.20300 4.09500 1.000 97.00000 C ? A ? 106 1 + ATOM 834 C . CYS A 106 ? -15.79100 9.58600 3.64200 1.000 97.00000 C ? A ? 106 1 + ATOM 835 O . CYS A 106 ? -14.64400 9.96600 3.88300 1.000 97.00000 O ? A ? 106 1 + ATOM 836 CB . CYS A 106 ? -15.74700 7.82800 5.48700 1.000 97.00000 C ? A ? 106 1 + ATOM 837 SG . CYS A 106 ? -16.51400 6.28000 6.05300 1.000 97.00000 S ? A ? 106 1 + ATOM 838 N . GLU A 107 ? -16.65700 10.32400 2.94400 1.000 95.50000 N ? A ? 107 1 + ATOM 839 CA . GLU A 107 ? -16.27000 11.54900 2.23500 1.000 95.50000 C ? A ? 107 1 + ATOM 840 C . GLU A 107 ? -15.85000 12.70200 3.15300 1.000 95.50000 C ? A ? 107 1 + ATOM 841 O . GLU A 107 ? -14.91600 13.41700 2.80400 1.000 95.50000 O ? A ? 107 1 + ATOM 842 CB . GLU A 107 ? -17.37800 11.99800 1.27200 1.000 95.50000 C ? A ? 107 1 + ATOM 843 CG . GLU A 107 ? -17.64500 10.95400 0.17200 1.000 95.50000 C ? A ? 107 1 + ATOM 844 CD . GLU A 107 ? -18.49300 11.49400 -0.99500 1.000 95.50000 C ? A ? 107 1 + ATOM 845 OE1 . GLU A 107 ? -18.53400 10.79700 -2.03600 1.000 95.50000 O ? A ? 107 1 + ATOM 846 OE2 . GLU A 107 ? -19.03200 12.61800 -0.88300 1.000 95.50000 O ? A ? 107 1 + ATOM 847 N . ALA A 108 ? -16.46200 12.85200 4.33500 1.000 96.50000 N ? A ? 108 1 + ATOM 848 CA . ALA A 108 ? -16.11100 13.90400 5.29400 1.000 96.50000 C ? A ? 108 1 + ATOM 849 C . ALA A 108 ? -14.93100 13.56200 6.22400 1.000 96.50000 C ? A ? 108 1 + ATOM 850 O . ALA A 108 ? -14.57400 14.39000 7.06500 1.000 96.50000 O ? A ? 108 1 + ATOM 851 CB . ALA A 108 ? -17.36000 14.27800 6.10000 1.000 96.50000 C ? A ? 108 1 + ATOM 852 N . LEU A 109 ? -14.32400 12.37200 6.10900 1.000 96.12000 N ? A ? 109 1 + ATOM 853 CA . LEU A 109 ? -13.30200 11.90500 7.05000 1.000 96.12000 C ? A ? 109 1 + ATOM 854 C . LEU A 109 ? -12.03400 12.74400 6.93700 1.000 96.12000 C ? A ? 109 1 + ATOM 855 O . LEU A 109 ? -11.30800 12.61500 5.96100 1.000 96.12000 O ? A ? 109 1 + ATOM 856 CB . LEU A 109 ? -13.01700 10.41400 6.80000 1.000 96.12000 C ? A ? 109 1 + ATOM 857 CG . LEU A 109 ? -11.98400 9.80900 7.77100 1.000 96.12000 C ? A ? 109 1 + ATOM 858 CD1 . LEU A 109 ? -12.56500 9.60100 9.16900 1.000 96.12000 C ? A ? 109 1 + ATOM 859 CD2 . LEU A 109 ? -11.51400 8.46500 7.21800 1.000 96.12000 C ? A ? 109 1 + ATOM 860 N . LYS A 110 ? -11.72400 13.53200 7.97000 1.000 93.56000 N ? A ? 110 1 + ATOM 861 CA . LYS A 110 ? -10.53500 14.40200 8.02900 1.000 93.56000 C ? A ? 110 1 + ATOM 862 C . LYS A 110 ? -9.36500 13.75900 8.77100 1.000 93.56000 C ? A ? 110 1 + ATOM 863 O . LYS A 110 ? -8.20800 14.00600 8.42700 1.000 93.56000 O ? A ? 110 1 + ATOM 864 CB . LYS A 110 ? -10.91600 15.73200 8.69300 1.000 93.56000 C ? A ? 110 1 + ATOM 865 CG . LYS A 110 ? -11.87600 16.56600 7.83300 1.000 93.56000 C ? A ? 110 1 + ATOM 866 CD . LYS A 110 ? -12.46800 17.71500 8.65600 1.000 93.56000 C ? A ? 110 1 + ATOM 867 CE . LYS A 110 ? -13.61600 18.37100 7.88400 1.000 93.56000 C ? A ? 110 1 + ATOM 868 NZ . LYS A 110 ? -14.49800 19.13700 8.80200 1.000 93.56000 N ? A ? 110 1 + ATOM 869 N . SER A 111 ? -9.64500 12.94300 9.78900 1.000 90.88000 N ? A ? 111 1 + ATOM 870 CA . SER A 111 ? -8.63000 12.32400 10.65300 1.000 90.88000 C ? A ? 111 1 + ATOM 871 C . SER A 111 ? -9.07100 10.95400 11.17200 1.000 90.88000 C ? A ? 111 1 + ATOM 872 O . SER A 111 ? -10.26200 10.71200 11.33800 1.000 90.88000 O ? A ? 111 1 + ATOM 873 CB . SER A 111 ? -8.33700 13.25400 11.83400 1.000 90.88000 C ? A ? 111 1 + ATOM 874 OG . SER A 111 ? -7.27500 12.74600 12.62300 1.000 90.88000 O ? A ? 111 1 + ATOM 875 N . LEU A 112 ? -8.13500 10.04900 11.48100 1.000 87.94000 N ? A ? 112 1 + ATOM 876 CA . LEU A 112 ? -8.49000 8.81200 12.19900 1.000 87.94000 C ? A ? 112 1 + ATOM 877 C . LEU A 112 ? -8.51900 8.98900 13.71700 1.000 87.94000 C ? A ? 112 1 + ATOM 878 O . LEU A 112 ? -9.28200 8.32200 14.41000 1.000 87.94000 O ? A ? 112 1 + ATOM 879 CB . LEU A 112 ? -7.55400 7.65300 11.84700 1.000 87.94000 C ? A ? 112 1 + ATOM 880 CG . LEU A 112 ? -7.46900 7.31500 10.35700 1.000 87.94000 C ? A ? 112 1 + ATOM 881 CD1 . LEU A 112 ? -6.58700 6.08200 10.20100 1.000 87.94000 C ? A ? 112 1 + ATOM 882 CD2 . LEU A 112 ? -8.84800 7.00600 9.79200 1.000 87.94000 C ? A ? 112 1 + ATOM 883 N . ALA A 113 ? -7.67800 9.86600 14.24700 1.000 79.75000 N ? A ? 113 1 + ATOM 884 CA . ALA A 113 ? -7.60900 10.12400 15.67400 1.000 79.75000 C ? A ? 113 1 + ATOM 885 C . ALA A 113 ? -7.18300 11.56900 15.89600 1.000 79.75000 C ? A ? 113 1 + ATOM 886 O . ALA A 113 ? -6.07200 11.96600 15.52900 1.000 79.75000 O ? A ? 113 1 + ATOM 887 CB . ALA A 113 ? -6.62200 9.13700 16.30900 1.000 79.75000 C ? A ? 113 1 + ATOM 888 N . TRP A 114 ? -8.04200 12.36600 16.53100 1.000 73.25000 N ? A ? 114 1 + ATOM 889 CA . TRP A 114 ? -7.68800 13.74800 16.87200 1.000 73.25000 C ? A ? 114 1 + ATOM 890 C . TRP A 114 ? -6.56400 13.82600 17.91200 1.000 73.25000 C ? A ? 114 1 + ATOM 891 O . TRP A 114 ? -5.74300 14.74200 17.85600 1.000 73.25000 O ? A ? 114 1 + ATOM 892 CB . TRP A 114 ? -8.93100 14.51600 17.32200 1.000 73.25000 C ? A ? 114 1 + ATOM 893 CG . TRP A 114 ? -9.90400 14.82500 16.22500 1.000 73.25000 C ? A ? 114 1 + ATOM 894 CD1 . TRP A 114 ? -11.22900 14.56000 16.25300 1.000 73.25000 C ? A ? 114 1 + ATOM 895 CD2 . TRP A 114 ? -9.65900 15.50800 14.95300 1.000 73.25000 C ? A ? 114 1 + ATOM 896 NE1 . TRP A 114 ? -11.81500 15.01600 15.09000 1.000 73.25000 N ? A ? 114 1 + ATOM 897 CE2 . TRP A 114 ? -10.89100 15.57700 14.23700 1.000 73.25000 C ? A ? 114 1 + ATOM 898 CE3 . TRP A 114 ? -8.52700 16.09400 14.33800 1.000 73.25000 C ? A ? 114 1 + ATOM 899 CZ2 . TRP A 114 ? -10.99100 16.15100 12.96200 1.000 73.25000 C ? A ? 114 1 + ATOM 900 CZ3 . TRP A 114 ? -8.61900 16.68500 13.06200 1.000 73.25000 C ? A ? 114 1 + ATOM 901 CH2 . TRP A 114 ? -9.84400 16.70600 12.37100 1.000 73.25000 C ? A ? 114 1 + ATOM 902 N . SER A 115 ? -6.45500 12.81600 18.78300 1.000 71.06000 N ? A ? 115 1 + ATOM 903 CA . SER A 115 ? -5.32600 12.62200 19.70500 1.000 71.06000 C ? A ? 115 1 + ATOM 904 C . SER A 115 ? -3.98900 12.40400 18.98500 1.000 71.06000 C ? A ? 115 1 + ATOM 905 O . SER A 115 ? -2.92500 12.63800 19.55800 1.000 71.06000 O ? A ? 115 1 + ATOM 906 CB . SER A 115 ? -5.62600 11.42900 20.62200 1.000 71.06000 C ? A ? 115 1 + ATOM 907 OG . SER A 115 ? -5.97400 10.29400 19.85400 1.000 71.06000 O ? A ? 115 1 + ATOM 908 N . GLY A 116 ? -4.02400 12.00800 17.70800 1.000 75.62000 N ? A ? 116 1 + ATOM 909 CA . GLY A 116 ? -2.85200 11.90500 16.84900 1.000 75.62000 C ? A ? 116 1 + ATOM 910 C . GLY A 116 ? -2.03000 10.62900 17.01700 1.000 75.62000 C ? A ? 116 1 + ATOM 911 O . GLY A 116 ? -0.91200 10.61300 16.50600 1.000 75.62000 O ? A ? 116 1 + ATOM 912 N . LYS A 117 ? -2.55600 9.58700 17.67700 1.000 81.31000 N ? A ? 117 1 + ATOM 913 CA . LYS A 117 ? -1.93600 8.25000 17.76400 1.000 81.31000 C ? A ? 117 1 + ATOM 914 C . LYS A 117 ? -2.88400 7.17200 17.22400 1.000 81.31000 C ? A ? 117 1 + ATOM 915 O . LYS A 117 ? -4.08500 7.39800 17.12100 1.000 81.31000 O ? A ? 117 1 + ATOM 916 CB . LYS A 117 ? -1.48300 7.92800 19.20000 1.000 81.31000 C ? A ? 117 1 + ATOM 917 CG . LYS A 117 ? -0.55100 8.96200 19.84800 1.000 81.31000 C ? A ? 117 1 + ATOM 918 CD . LYS A 117 ? -0.24800 8.53100 21.29000 1.000 81.31000 C ? A ? 117 1 + ATOM 919 CE . LYS A 117 ? 0.78800 9.45200 21.94400 1.000 81.31000 C ? A ? 117 1 + ATOM 920 NZ . LYS A 117 ? 1.17600 8.94400 23.28800 1.000 81.31000 N ? A ? 117 1 + ATOM 921 N . LEU A 118 ? -2.34600 6.00800 16.86300 1.000 84.38000 N ? A ? 118 1 + ATOM 922 CA . LEU A 118 ? -3.13000 4.84900 16.41600 1.000 84.38000 C ? A ? 118 1 + ATOM 923 C . LEU A 118 ? -3.37200 3.86000 17.57500 1.000 84.38000 C ? A ? 118 1 + ATOM 924 O . LEU A 118 ? -2.56400 3.81400 18.50600 1.000 84.38000 O ? A ? 118 1 + ATOM 925 CB . LEU A 118 ? -2.41500 4.16200 15.23600 1.000 84.38000 C ? A ? 118 1 + ATOM 926 CG . LEU A 118 ? -2.33800 5.00500 13.94800 1.000 84.38000 C ? A ? 118 1 + ATOM 927 CD1 . LEU A 118 ? -1.48800 4.27100 12.91000 1.000 84.38000 C ? A ? 118 1 + ATOM 928 CD2 . LEU A 118 ? -3.71600 5.26800 13.33200 1.000 84.38000 C ? A ? 118 1 + ATOM 929 N . PRO A 119 ? -4.42100 3.01300 17.51100 1.000 85.25000 N ? A ? 119 1 + ATOM 930 CA . PRO A 119 ? -4.64700 1.95900 18.50100 1.000 85.25000 C ? A ? 119 1 + ATOM 931 C . PRO A 119 ? -3.43300 1.03000 18.63700 1.000 85.25000 C ? A ? 119 1 + ATOM 932 O . PRO A 119 ? -2.87200 0.58700 17.63700 1.000 85.25000 O ? A ? 119 1 + ATOM 933 CB . PRO A 119 ? -5.89500 1.19800 18.03500 1.000 85.25000 C ? A ? 119 1 + ATOM 934 CG . PRO A 119 ? -6.62100 2.20200 17.13900 1.000 85.25000 C ? A ? 119 1 + ATOM 935 CD . PRO A 119 ? -5.49300 3.02700 16.52600 1.000 85.25000 C ? A ? 119 1 + ATOM 936 N . VAL A 120 ? -3.03600 0.70100 19.87000 1.000 86.06000 N ? A ? 120 1 + ATOM 937 CA . VAL A 120 ? -1.74700 0.04300 20.18300 1.000 86.06000 C ? A ? 120 1 + ATOM 938 C . VAL A 120 ? -1.60300 -1.35500 19.56200 1.000 86.06000 C ? A ? 120 1 + ATOM 939 O . VAL A 120 ? -0.50300 -1.74600 19.16900 1.000 86.06000 O ? A ? 120 1 + ATOM 940 CB . VAL A 120 ? -1.55000 -0.02000 21.71500 1.000 86.06000 C ? A ? 120 1 + ATOM 941 CG1 . VAL A 120 ? -0.21100 -0.64900 22.11800 1.000 86.06000 C ? A ? 120 1 + ATOM 942 CG2 . VAL A 120 ? -1.60900 1.38200 22.33900 1.000 86.06000 C ? A ? 120 1 + ATOM 943 N . GLN A 121 ? -2.70400 -2.10600 19.44300 1.000 90.00000 N ? A ? 121 1 + ATOM 944 CA . GLN A 121 ? -2.71200 -3.47000 18.89100 1.000 90.00000 C ? A ? 121 1 + ATOM 945 C . GLN A 121 ? -3.01900 -3.53800 17.39000 1.000 90.00000 C ? A ? 121 1 + ATOM 946 O . GLN A 121 ? -3.08400 -4.64000 16.83500 1.000 90.00000 O ? A ? 121 1 + ATOM 947 CB . GLN A 121 ? -3.67600 -4.36500 19.68300 1.000 90.00000 C ? A ? 121 1 + ATOM 948 CG . GLN A 121 ? -3.26900 -4.48100 21.15700 1.000 90.00000 C ? A ? 121 1 + ATOM 949 CD . GLN A 121 ? -3.91400 -5.66300 21.86900 1.000 90.00000 C ? A ? 121 1 + ATOM 950 OE1 . GLN A 121 ? -4.51500 -6.55700 21.28700 1.000 90.00000 O ? A ? 121 1 + ATOM 951 NE2 . GLN A 121 ? -3.75800 -5.74900 23.17100 1.000 90.00000 N ? A ? 121 1 + ATOM 952 N . LEU A 122 ? -3.19200 -2.38800 16.72600 1.000 92.00000 N ? A ? 122 1 + ATOM 953 CA . LEU A 122 ? -3.57700 -2.35200 15.32000 1.000 92.00000 C ? A ? 122 1 + ATOM 954 C . LEU A 122 ? -2.47200 -2.96600 14.46100 1.000 92.00000 C ? A ? 122 1 + ATOM 955 O . LEU A 122 ? -1.33200 -2.50700 14.50100 1.000 92.00000 O ? A ? 122 1 + ATOM 956 CB . LEU A 122 ? -3.91500 -0.91000 14.89900 1.000 92.00000 C ? A ? 122 1 + ATOM 957 CG . LEU A 122 ? -4.63100 -0.81400 13.54500 1.000 92.00000 C ? A ? 122 1 + ATOM 958 CD1 . LEU A 122 ? -6.06700 -1.32200 13.64800 1.000 92.00000 C ? A ? 122 1 + ATOM 959 CD2 . LEU A 122 ? -4.68700 0.64200 13.08700 1.000 92.00000 C ? A ? 122 1 + ATOM 960 N . LYS A 123 ? -2.83000 -3.99300 13.69000 1.000 96.56000 N ? A ? 123 1 + ATOM 961 CA . LYS A 123 ? -1.96600 -4.70200 12.74000 1.000 96.56000 C ? A ? 123 1 + ATOM 962 C . LYS A 123 ? -2.21400 -4.26400 11.30400 1.000 96.56000 C ? A ? 123 1 + ATOM 963 O . LYS A 123 ? -1.27200 -4.16000 10.52800 1.000 96.56000 O ? A ? 123 1 + ATOM 964 CB . LYS A 123 ? -2.19900 -6.21000 12.83000 1.000 96.56000 C ? A ? 123 1 + ATOM 965 CG . LYS A 123 ? -1.86700 -6.78800 14.20600 1.000 96.56000 C ? A ? 123 1 + ATOM 966 CD . LYS A 123 ? -2.04200 -8.29900 14.11500 1.000 96.56000 C ? A ? 123 1 + ATOM 967 CE . LYS A 123 ? -1.52000 -8.97500 15.37500 1.000 96.56000 C ? A ? 123 1 + ATOM 968 NZ . LYS A 123 ? -1.23700 -10.38800 15.04900 1.000 96.56000 N ? A ? 123 1 + ATOM 969 N . LYS A 124 ? -3.46900 -3.99400 10.95000 1.000 97.62000 N ? A ? 124 1 + ATOM 970 CA . LYS A 124 ? -3.87300 -3.62900 9.59300 1.000 97.62000 C ? A ? 124 1 + ATOM 971 C . LYS A 124 ? -4.68300 -2.34000 9.60200 1.000 97.62000 C ? A ? 124 1 + ATOM 972 O . LYS A 124 ? -5.65200 -2.23200 10.35500 1.000 97.62000 O ? A ? 124 1 + ATOM 973 CB . LYS A 124 ? -4.64500 -4.80400 8.98100 1.000 97.62000 C ? A ? 124 1 + ATOM 974 CG . LYS A 124 ? -4.90500 -4.57700 7.49000 1.000 97.62000 C ? A ? 124 1 + ATOM 975 CD . LYS A 124 ? -5.67600 -5.75400 6.88800 1.000 97.62000 C ? A ? 124 1 + ATOM 976 CE . LYS A 124 ? -5.78100 -5.50000 5.38400 1.000 97.62000 C ? A ? 124 1 + ATOM 977 NZ . LYS A 124 ? -7.11900 -5.82400 4.84600 1.000 97.62000 N ? A ? 124 1 + ATOM 978 N . LEU A 125 ? -4.28000 -1.39500 8.76100 1.000 96.88000 N ? A ? 125 1 + ATOM 979 CA . LEU A 125 ? -4.97200 -0.13200 8.55100 1.000 96.88000 C ? A ? 125 1 + ATOM 980 C . LEU A 125 ? -5.23600 0.08100 7.06300 1.000 96.88000 C ? A ? 125 1 + ATOM 981 O . LEU A 125 ? -4.30400 0.35600 6.31000 1.000 96.88000 O ? A ? 125 1 + ATOM 982 CB . LEU A 125 ? -4.12200 1.00600 9.13800 1.000 96.88000 C ? A ? 125 1 + ATOM 983 CG . LEU A 125 ? -4.72600 2.40200 8.90200 1.000 96.88000 C ? A ? 125 1 + ATOM 984 CD1 . LEU A 125 ? -6.13300 2.52500 9.48600 1.000 96.88000 C ? A ? 125 1 + ATOM 985 CD2 . LEU A 125 ? -3.82600 3.45000 9.55700 1.000 96.88000 C ? A ? 125 1 + ATOM 986 N . ASP A 126 ? -6.50500 0.02600 6.67900 1.000 98.06000 N ? A ? 126 1 + ATOM 987 CA . ASP A 126 ? -6.95700 0.25500 5.31300 1.000 98.06000 C ? A ? 126 1 + ATOM 988 C . ASP A 126 ? -7.88400 1.48100 5.28000 1.000 98.06000 C ? A ? 126 1 + ATOM 989 O . ASP A 126 ? -8.93700 1.48000 5.91600 1.000 98.06000 O ? A ? 126 1 + ATOM 990 CB . ASP A 126 ? -7.67000 -1.00700 4.80200 1.000 98.06000 C ? A ? 126 1 + ATOM 991 CG . ASP A 126 ? -6.77100 -2.21400 4.50200 1.000 98.06000 C ? A ? 126 1 + ATOM 992 OD1 . ASP A 126 ? -5.52700 -2.13100 4.58000 1.000 98.06000 O ? A ? 126 1 + ATOM 993 OD2 . ASP A 126 ? -7.33600 -3.28200 4.17000 1.000 98.06000 O ? A ? 126 1 + ATOM 994 N . VAL A 127 ? -7.51900 2.52500 4.53000 1.000 98.00000 N ? A ? 127 1 + ATOM 995 CA . VAL A 127 ? -8.39800 3.67800 4.26600 1.000 98.00000 C ? A ? 127 1 + ATOM 996 C . VAL A 127 ? -8.56200 3.87300 2.76300 1.000 98.00000 C ? A ? 127 1 + ATOM 997 O . VAL A 127 ? -7.59100 4.13100 2.05300 1.000 98.00000 O ? A ? 127 1 + ATOM 998 CB . VAL A 127 ? -7.93000 4.97500 4.94800 1.000 98.00000 C ? A ? 127 1 + ATOM 999 CG1 . VAL A 127 ? -9.02400 6.03700 4.79700 1.000 98.00000 C ? A ? 127 1 + ATOM 1000 CG2 . VAL A 127 ? -7.64300 4.78300 6.44300 1.000 98.00000 C ? A ? 127 1 + ATOM 1001 N . LEU A 128 ? -9.78700 3.71600 2.26300 1.000 98.12000 N ? A ? 128 1 + ATOM 1002 CA . LEU A 128 ? -10.10000 3.73500 0.83700 1.000 98.12000 C ? A ? 128 1 + ATOM 1003 C . LEU A 128 ? -11.15500 4.80000 0.53000 1.000 98.12000 C ? A ? 128 1 + ATOM 1004 O . LEU A 128 ? -12.14600 4.93100 1.23800 1.000 98.12000 O ? A ? 128 1 + ATOM 1005 CB . LEU A 128 ? -10.57700 2.35700 0.34200 1.000 98.12000 C ? A ? 128 1 + ATOM 1006 CG . LEU A 128 ? -9.58800 1.17600 0.44300 1.000 98.12000 C ? A ? 128 1 + ATOM 1007 CD1 . LEU A 128 ? -9.35800 0.63300 1.85300 1.000 98.12000 C ? A ? 128 1 + ATOM 1008 CD2 . LEU A 128 ? -10.13600 0.00600 -0.37700 1.000 98.12000 C ? A ? 128 1 + ATOM 1009 N . LEU A 129 ? -10.97200 5.52700 -0.56600 1.000 97.81000 N ? A ? 129 1 + ATOM 1010 CA . LEU A 129 ? -11.91200 6.50300 -1.11100 1.000 97.81000 C ? A ? 129 1 + ATOM 1011 C . LEU A 129 ? -12.39600 7.52100 -0.05800 1.000 97.81000 C ? A ? 129 1 + ATOM 1012 O . LEU A 129 ? -13.57400 7.84700 -0.00100 1.000 97.81000 O ? A ? 129 1 + ATOM 1013 CB . LEU A 129 ? -13.04300 5.75400 -1.84900 1.000 97.81000 C ? A ? 129 1 + ATOM 1014 CG . LEU A 129 ? -12.57200 4.77600 -2.94600 1.000 97.81000 C ? A ? 129 1 + ATOM 1015 CD1 . LEU A 129 ? -13.76400 4.01000 -3.51300 1.000 97.81000 C ? A ? 129 1 + ATOM 1016 CD2 . LEU A 129 ? -11.86600 5.49400 -4.10000 1.000 97.81000 C ? A ? 129 1 + ATOM 1017 N . CYS A 130 ? -11.48100 8.00900 0.78800 1.000 97.69000 N ? A ? 130 1 + ATOM 1018 CA . CYS A 130 ? -11.73600 9.05700 1.78500 1.000 97.69000 C ? A ? 130 1 + ATOM 1019 C . CYS A 130 ? -10.99400 10.34300 1.36400 1.000 97.69000 C ? A ? 130 1 + ATOM 1020 O . CYS A 130 ? -9.86600 10.57800 1.81200 1.000 97.69000 O ? A ? 130 1 + ATOM 1021 CB . CYS A 130 ? -11.31200 8.55700 3.17300 1.000 97.69000 C ? A ? 130 1 + ATOM 1022 SG . CYS A 130 ? -12.30000 7.11100 3.66400 1.000 97.69000 S ? A ? 130 1 + ATOM 1023 N . PRO A 131 ? -11.55200 11.14500 0.43600 1.000 96.38000 N ? A ? 131 1 + ATOM 1024 CA . PRO A 131 ? -10.82700 12.23000 -0.22600 1.000 96.38000 C ? A ? 131 1 + ATOM 1025 C . PRO A 131 ? -10.40200 13.36200 0.71600 1.000 96.38000 C ? A ? 131 1 + ATOM 1026 O . PRO A 131 ? -9.32800 13.92500 0.49900 1.000 96.38000 O ? A ? 131 1 + ATOM 1027 CB . PRO A 131 ? -11.76300 12.73200 -1.33200 1.000 96.38000 C ? A ? 131 1 + ATOM 1028 CG . PRO A 131 ? -13.15500 12.34600 -0.83000 1.000 96.38000 C ? A ? 131 1 + ATOM 1029 CD . PRO A 131 ? -12.88800 11.02100 -0.12700 1.000 96.38000 C ? A ? 131 1 + ATOM 1030 N . GLU A 132 ? -11.18300 13.65100 1.76100 1.000 96.88000 N ? A ? 132 1 + ATOM 1031 CA . GLU A 132 ? -10.90800 14.71900 2.73300 1.000 96.88000 C ? A ? 132 1 + ATOM 1032 C . GLU A 132 ? -9.89800 14.33100 3.82500 1.000 96.88000 C ? A ? 132 1 + ATOM 1033 O . GLU A 132 ? -9.52300 15.17700 4.63600 1.000 96.88000 O ? A ? 132 1 + ATOM 1034 CB . GLU A 132 ? -12.22400 15.23100 3.34800 1.000 96.88000 C ? A ? 132 1 + ATOM 1035 CG . GLU A 132 ? -13.12400 15.95500 2.32600 1.000 96.88000 C ? A ? 132 1 + ATOM 1036 CD . GLU A 132 ? -12.44000 17.18100 1.69900 1.000 96.88000 C ? A ? 132 1 + ATOM 1037 OE1 . GLU A 132 ? -12.52400 17.35300 0.46100 1.000 96.88000 O ? A ? 132 1 + ATOM 1038 OE2 . GLU A 132 ? -11.74800 17.91900 2.43800 1.000 96.88000 O ? A ? 132 1 + ATOM 1039 N . LEU A 133 ? -9.39800 13.08700 3.83500 1.000 95.88000 N ? A ? 133 1 + ATOM 1040 CA . LEU A 133 ? -8.48400 12.61700 4.87600 1.000 95.88000 C ? A ? 133 1 + ATOM 1041 C . LEU A 133 ? -7.16900 13.39300 4.82100 1.000 95.88000 C ? A ? 133 1 + ATOM 1042 O . LEU A 133 ? -6.37400 13.20800 3.90200 1.000 95.88000 O ? A ? 133 1 + ATOM 1043 CB . LEU A 133 ? -8.27100 11.09800 4.73600 1.000 95.88000 C ? A ? 133 1 + ATOM 1044 CG . LEU A 133 ? -7.31400 10.52000 5.79900 1.000 95.88000 C ? A ? 133 1 + ATOM 1045 CD1 . LEU A 133 ? -7.92700 10.52300 7.20000 1.000 95.88000 C ? A ? 133 1 + ATOM 1046 CD2 . LEU A 133 ? -6.89300 9.08800 5.45900 1.000 95.88000 C ? A ? 133 1 + ATOM 1047 N . GLU A 134 ? -6.89800 14.21000 5.83600 1.000 92.56000 N ? A ? 134 1 + ATOM 1048 CA . GLU A 134 ? -5.68700 15.03000 5.91100 1.000 92.56000 C ? A ? 134 1 + ATOM 1049 C . GLU A 134 ? -4.54000 14.30600 6.62800 1.000 92.56000 C ? A ? 134 1 + ATOM 1050 O . GLU A 134 ? -3.36400 14.49900 6.29100 1.000 92.56000 O ? A ? 134 1 + ATOM 1051 CB . GLU A 134 ? -5.98500 16.35300 6.63000 1.000 92.56000 C ? A ? 134 1 + ATOM 1052 CG . GLU A 134 ? -7.09800 17.19100 5.97700 1.000 92.56000 C ? A ? 134 1 + ATOM 1053 CD . GLU A 134 ? -7.16300 18.61900 6.54300 1.000 92.56000 C ? A ? 134 1 + ATOM 1054 OE1 . GLU A 134 ? -7.70900 19.50200 5.84600 1.000 92.56000 O ? A ? 134 1 + ATOM 1055 OE2 . GLU A 134 ? -6.57200 18.86700 7.62200 1.000 92.56000 O ? A ? 134 1 + ATOM 1056 N . CYS A 135 ? -4.87000 13.47300 7.62300 1.000 87.94000 N ? A ? 135 1 + ATOM 1057 CA . CYS A 135 ? -3.90400 12.83400 8.51500 1.000 87.94000 C ? A ? 135 1 + ATOM 1058 C . CYS A 135 ? -4.41400 11.48400 9.04800 1.000 87.94000 C ? A ? 135 1 + ATOM 1059 O . CYS A 135 ? -5.54100 11.38800 9.52500 1.000 87.94000 O ? A ? 135 1 + ATOM 1060 CB . CYS A 135 ? -3.65200 13.81100 9.67200 1.000 87.94000 C ? A ? 135 1 + ATOM 1061 SG . CYS A 135 ? -2.26300 13.25300 10.69600 1.000 87.94000 S ? A ? 135 1 + ATOM 1062 N . LEU A 136 ? -3.56800 10.44600 9.03800 1.000 89.81000 N ? A ? 136 1 + ATOM 1063 CA . LEU A 136 ? -3.86600 9.19500 9.75500 1.000 89.81000 C ? A ? 136 1 + ATOM 1064 C . LEU A 136 ? -3.64600 9.36000 11.26300 1.000 89.81000 C ? A ? 136 1 + ATOM 1065 O . LEU A 136 ? -4.49500 9.01400 12.07200 1.000 89.81000 O ? A ? 136 1 + ATOM 1066 CB . LEU A 136 ? -2.98900 8.04100 9.23300 1.000 89.81000 C ? A ? 136 1 + ATOM 1067 CG . LEU A 136 ? -3.17600 7.66300 7.75900 1.000 89.81000 C ? A ? 136 1 + ATOM 1068 CD1 . LEU A 136 ? -2.16700 6.56400 7.42100 1.000 89.81000 C ? A ? 136 1 + ATOM 1069 CD2 . LEU A 136 ? -4.58100 7.15900 7.44900 1.000 89.81000 C ? A ? 136 1 + ATOM 1070 N . ALA A 137 ? -2.47600 9.87500 11.62600 1.000 87.06000 N ? A ? 137 1 + ATOM 1071 CA . ALA A 137 ? -2.02800 10.14300 12.98400 1.000 87.06000 C ? A ? 137 1 + ATOM 1072 C . ALA A 137 ? -0.80200 11.06500 12.90000 1.000 87.06000 C ? A ? 137 1 + ATOM 1073 O . ALA A 137 ? -0.08200 11.04900 11.89600 1.000 87.06000 O ? A ? 137 1 + ATOM 1074 CB . ALA A 137 ? -1.68600 8.81100 13.66600 1.000 87.06000 C ? A ? 137 1 + ATOM 1075 N . ARG A 138 ? -0.53700 11.86000 13.94300 1.000 84.38000 N ? A ? 138 1 + ATOM 1076 CA . ARG A 138 ? 0.67300 12.70100 14.00900 1.000 84.38000 C ? A ? 138 1 + ATOM 1077 C . ARG A 138 ? 1.92100 11.82300 14.12600 1.000 84.38000 C ? A ? 138 1 + ATOM 1078 O . ARG A 138 ? 2.90400 12.03100 13.41500 1.000 84.38000 O ? A ? 138 1 + ATOM 1079 CB . ARG A 138 ? 0.58700 13.68500 15.18900 1.000 84.38000 C ? A ? 138 1 + ATOM 1080 CG . ARG A 138 ? -0.48900 14.76800 15.00200 1.000 84.38000 C ? A ? 138 1 + ATOM 1081 CD . ARG A 138 ? -0.49300 15.72400 16.20400 1.000 84.38000 C ? A ? 138 1 + ATOM 1082 NE . ARG A 138 ? -1.53100 16.76900 16.07900 1.000 84.38000 N ? A ? 138 1 + ATOM 1083 CZ . ARG A 138 ? -1.95200 17.57400 17.04300 1.000 84.38000 C ? A ? 138 1 + ATOM 1084 NH1 . ARG A 138 ? -1.43500 17.55500 18.24000 1.000 84.38000 N ? A ? 138 1 + ATOM 1085 NH2 . ARG A 138 ? -2.92000 18.41900 16.82800 1.000 84.38000 N ? A ? 138 1 + ATOM 1086 N . GLU A 139 ? 1.84500 10.80600 14.97600 1.000 85.56000 N ? A ? 139 1 + ATOM 1087 CA . GLU A 139 ? 2.87800 9.79700 15.18600 1.000 85.56000 C ? A ? 139 1 + ATOM 1088 C . GLU A 139 ? 2.24600 8.41400 15.38100 1.000 85.56000 C ? A ? 139 1 + ATOM 1089 O . GLU A 139 ? 1.07800 8.28900 15.74300 1.000 85.56000 O ? A ? 139 1 + ATOM 1090 CB . GLU A 139 ? 3.78000 10.18700 16.37300 1.000 85.56000 C ? A ? 139 1 + ATOM 1091 CG . GLU A 139 ? 3.02500 10.34600 17.70800 1.000 85.56000 C ? A ? 139 1 + ATOM 1092 CD . GLU A 139 ? 3.94100 10.63000 18.90900 1.000 85.56000 C ? A ? 139 1 + ATOM 1093 OE1 . GLU A 139 ? 3.40400 10.60800 20.04300 1.000 85.56000 O ? A ? 139 1 + ATOM 1094 OE2 . GLU A 139 ? 5.16200 10.82200 18.70200 1.000 85.56000 O ? A ? 139 1 + ATOM 1095 N . ILE A 140 ? 3.02400 7.35600 15.16000 1.000 85.00000 N ? A ? 140 1 + ATOM 1096 CA . ILE A 140 ? 2.59700 5.97600 15.44400 1.000 85.00000 C ? A ? 140 1 + ATOM 1097 C . ILE A 140 ? 2.32900 5.75600 16.94600 1.000 85.00000 C ? A ? 140 1 + ATOM 1098 O . ILE A 140 ? 1.50800 4.91400 17.31400 1.000 85.00000 O ? A ? 140 1 + ATOM 1099 CB . ILE A 140 ? 3.66200 5.01600 14.86300 1.000 85.00000 C ? A ? 140 1 + ATOM 1100 CG1 . ILE A 140 ? 3.70700 5.05100 13.31600 1.000 85.00000 C ? A ? 140 1 + ATOM 1101 CG2 . ILE A 140 ? 3.49200 3.57000 15.32800 1.000 85.00000 C ? A ? 140 1 + ATOM 1102 CD1 . ILE A 140 ? 2.39500 4.66700 12.60800 1.000 85.00000 C ? A ? 140 1 + ATOM 1103 N . GLY A 141 ? 2.96600 6.54900 17.81400 1.000 82.94000 N ? A ? 141 1 + ATOM 1104 CA . GLY A 141 ? 2.82400 6.44500 19.26400 1.000 82.94000 C ? A ? 141 1 + ATOM 1105 C . GLY A 141 ? 3.37000 5.11500 19.78500 1.000 82.94000 C ? A ? 141 1 + ATOM 1106 O . GLY A 141 ? 4.47600 4.71300 19.42600 1.000 82.94000 O ? A ? 141 1 + ATOM 1107 N . ASP A 142 ? 2.58000 4.43300 20.61500 1.000 83.62000 N ? A ? 142 1 + ATOM 1108 CA . ASP A 142 ? 2.95100 3.16600 21.26200 1.000 83.62000 C ? A ? 142 1 + ATOM 1109 C . ASP A 142 ? 2.62000 1.92600 20.41100 1.000 83.62000 C ? A ? 142 1 + ATOM 1110 O . ASP A 142 ? 2.87700 0.79100 20.82400 1.000 83.62000 O ? A ? 142 1 + ATOM 1111 CB . ASP A 142 ? 2.28300 3.09900 22.64400 1.000 83.62000 C ? A ? 142 1 + ATOM 1112 CG . ASP A 142 ? 2.65400 4.31000 23.50500 1.000 83.62000 C ? A ? 142 1 + ATOM 1113 OD1 . ASP A 142 ? 3.86500 4.51500 23.73000 1.000 83.62000 O ? A ? 142 1 + ATOM 1114 OD2 . ASP A 142 ? 1.73000 5.07600 23.87000 1.000 83.62000 O ? A ? 142 1 + ATOM 1115 N . ASN A 143 ? 2.04200 2.10800 19.21600 1.000 84.50000 N ? A ? 143 1 + ATOM 1116 CA . ASN A 143 ? 1.77600 0.98800 18.32400 1.000 84.50000 C ? A ? 143 1 + ATOM 1117 C . ASN A 143 ? 3.09900 0.39500 17.81000 1.000 84.50000 C ? A ? 143 1 + ATOM 1118 O . ASN A 143 ? 3.85800 1.02600 17.08200 1.000 84.50000 O ? A ? 143 1 + ATOM 1119 CB . ASN A 143 ? 0.81200 1.40200 17.20100 1.000 84.50000 C ? A ? 143 1 + ATOM 1120 CG . ASN A 143 ? 0.49500 0.22700 16.28600 1.000 84.50000 C ? A ? 143 1 + ATOM 1121 OD1 . ASN A 143 ? 1.35700 -0.49700 15.81700 1.000 84.50000 O ? A ? 143 1 + ATOM 1122 ND2 . ASN A 143 ? -0.74700 -0.06400 16.03000 1.000 84.50000 N ? A ? 143 1 + ATOM 1123 N . THR A 144 ? 3.33900 -0.86500 18.16400 1.000 85.62000 N ? A ? 144 1 + ATOM 1124 CA . THR A 144 ? 4.46400 -1.68100 17.67200 1.000 85.62000 C ? A ? 144 1 + ATOM 1125 C . THR A 144 ? 3.99000 -2.90400 16.88200 1.000 85.62000 C ? A ? 144 1 + ATOM 1126 O . THR A 144 ? 4.78800 -3.75300 16.48200 1.000 85.62000 O ? A ? 144 1 + ATOM 1127 CB . THR A 144 ? 5.36100 -2.11200 18.84100 1.000 85.62000 C ? A ? 144 1 + ATOM 1128 OG1 . THR A 144 ? 4.58800 -2.74500 19.83800 1.000 85.62000 O ? A ? 144 1 + ATOM 1129 CG2 . THR A 144 ? 6.05500 -0.92400 19.50400 1.000 85.62000 C ? A ? 144 1 + ATOM 1130 N . CYS A 145 ? 2.67500 -3.01900 16.67500 1.000 91.88000 N ? A ? 145 1 + ATOM 1131 CA . CYS A 145 ? 2.02600 -4.18100 16.07900 1.000 91.88000 C ? A ? 145 1 + ATOM 1132 C . CYS A 145 ? 1.66800 -3.99900 14.60400 1.000 91.88000 C ? A ? 145 1 + ATOM 1133 O . CYS A 145 ? 1.31700 -4.99300 13.97700 1.000 91.88000 O ? A ? 145 1 + ATOM 1134 CB . CYS A 145 ? 0.79100 -4.55500 16.90900 1.000 91.88000 C ? A ? 145 1 + ATOM 1135 SG . CYS A 145 ? 1.31100 -5.25300 18.50600 1.000 91.88000 S ? A ? 145 1 + ATOM 1136 N . LEU A 146 ? 1.74500 -2.78200 14.05900 1.000 94.25000 N ? A ? 146 1 + ATOM 1137 CA . LEU A 146 ? 1.30500 -2.48600 12.70000 1.000 94.25000 C ? A ? 146 1 + ATOM 1138 C . LEU A 146 ? 2.14500 -3.24700 11.66400 1.000 94.25000 C ? A ? 146 1 + ATOM 1139 O . LEU A 146 ? 3.36500 -3.10800 11.59600 1.000 94.25000 O ? A ? 146 1 + ATOM 1140 CB . LEU A 146 ? 1.29800 -0.96300 12.49700 1.000 94.25000 C ? A ? 146 1 + ATOM 1141 CG . LEU A 146 ? 0.46000 -0.45100 11.31500 1.000 94.25000 C ? A ? 146 1 + ATOM 1142 CD1 . LEU A 146 ? -1.04100 -0.66900 11.52000 1.000 94.25000 C ? A ? 146 1 + ATOM 1143 CD2 . LEU A 146 ? 0.67700 1.05700 11.20400 1.000 94.25000 C ? A ? 146 1 + ATOM 1144 N . GLU A 147 ? 1.45700 -4.05600 10.86500 1.000 96.75000 N ? A ? 147 1 + ATOM 1145 CA . GLU A 147 ? 1.98700 -4.94900 9.83400 1.000 96.75000 C ? A ? 147 1 + ATOM 1146 C . GLU A 147 ? 1.67400 -4.42200 8.42300 1.000 96.75000 C ? A ? 147 1 + ATOM 1147 O . GLU A 147 ? 2.46100 -4.62500 7.49700 1.000 96.75000 O ? A ? 147 1 + ATOM 1148 CB . GLU A 147 ? 1.39200 -6.36200 10.02800 1.000 96.75000 C ? A ? 147 1 + ATOM 1149 CG . GLU A 147 ? 1.93700 -7.12200 11.25800 1.000 96.75000 C ? A ? 147 1 + ATOM 1150 CD . GLU A 147 ? 1.08100 -8.33600 11.69100 1.000 96.75000 C ? A ? 147 1 + ATOM 1151 OE1 . GLU A 147 ? 1.16900 -8.76100 12.87600 1.000 96.75000 O ? A ? 147 1 + ATOM 1152 OE2 . GLU A 147 ? 0.30700 -8.86000 10.86100 1.000 96.75000 O ? A ? 147 1 + ATOM 1153 N . SER A 148 ? 0.55200 -3.71400 8.24600 1.000 97.44000 N ? A ? 148 1 + ATOM 1154 CA . SER A 148 ? 0.09000 -3.24900 6.93700 1.000 97.44000 C ? A ? 148 1 + ATOM 1155 C . SER A 148 ? -0.61300 -1.89100 6.99700 1.000 97.44000 C ? A ? 148 1 + ATOM 1156 O . SER A 148 ? -1.47500 -1.66500 7.84800 1.000 97.44000 O ? A ? 148 1 + ATOM 1157 CB . SER A 148 ? -0.82900 -4.31600 6.33500 1.000 97.44000 C ? A ? 148 1 + ATOM 1158 OG . SER A 148 ? -1.30700 -3.95700 5.05300 1.000 97.44000 O ? A ? 148 1 + ATOM 1159 N . ILE A 149 ? -0.25600 -1.01100 6.05600 1.000 96.06000 N ? A ? 149 1 + ATOM 1160 CA . ILE A 149 ? -0.93700 0.26100 5.78400 1.000 96.06000 C ? A ? 149 1 + ATOM 1161 C . ILE A 149 ? -1.34800 0.28400 4.31100 1.000 96.06000 C ? A ? 149 1 + ATOM 1162 O . ILE A 149 ? -0.49300 0.15500 3.43300 1.000 96.06000 O ? A ? 149 1 + ATOM 1163 CB . ILE A 149 ? -0.03500 1.47200 6.12000 1.000 96.06000 C ? A ? 149 1 + ATOM 1164 CG1 . ILE A 149 ? 0.39600 1.45500 7.60300 1.000 96.06000 C ? A ? 149 1 + ATOM 1165 CG2 . ILE A 149 ? -0.76300 2.79500 5.79400 1.000 96.06000 C ? A ? 149 1 + ATOM 1166 CD1 . ILE A 149 ? 1.45300 2.51500 7.94300 1.000 96.06000 C ? A ? 149 1 + ATOM 1167 N . SER A 150 ? -2.63300 0.49400 4.04200 1.000 97.69000 N ? A ? 150 1 + ATOM 1168 CA . SER A 150 ? -3.17600 0.67600 2.69900 1.000 97.69000 C ? A ? 150 1 + ATOM 1169 C . SER A 150 ? -3.97500 1.97200 2.61400 1.000 97.69000 C ? A ? 150 1 + ATOM 1170 O . SER A 150 ? -4.90800 2.18100 3.38700 1.000 97.69000 O ? A ? 150 1 + ATOM 1171 CB . SER A 150 ? -4.05200 -0.51000 2.31200 1.000 97.69000 C ? A ? 150 1 + ATOM 1172 OG . SER A 150 ? -4.33500 -0.45800 0.92700 1.000 97.69000 O ? A ? 150 1 + ATOM 1173 N . LEU A 151 ? -3.61900 2.84000 1.67000 1.000 97.38000 N ? A ? 151 1 + ATOM 1174 CA . LEU A 151 ? -4.34200 4.06900 1.36000 1.000 97.38000 C ? A ? 151 1 + ATOM 1175 C . LEU A 151 ? -4.71400 4.09100 -0.11400 1.000 97.38000 C ? A ? 151 1 + ATOM 1176 O . LEU A 151 ? -3.83600 3.96300 -0.96700 1.000 97.38000 O ? A ? 151 1 + ATOM 1177 CB . LEU A 151 ? -3.50300 5.30600 1.70200 1.000 97.38000 C ? A ? 151 1 + ATOM 1178 CG . LEU A 151 ? -3.05200 5.40200 3.16400 1.000 97.38000 C ? A ? 151 1 + ATOM 1179 CD1 . LEU A 151 ? -2.21500 6.67100 3.29100 1.000 97.38000 C ? A ? 151 1 + ATOM 1180 CD2 . LEU A 151 ? -4.22900 5.48700 4.13100 1.000 97.38000 C ? A ? 151 1 + ATOM 1181 N . TRP A 152 ? -5.99100 4.30800 -0.41300 1.000 97.25000 N ? A ? 152 1 + ATOM 1182 CA . TRP A 152 ? -6.47100 4.43300 -1.78500 1.000 97.25000 C ? A ? 152 1 + ATOM 1183 C . TRP A 152 ? -7.39600 5.63900 -1.92600 1.000 97.25000 C ? A ? 152 1 + ATOM 1184 O . TRP A 152 ? -8.37800 5.73400 -1.20800 1.000 97.25000 O ? A ? 152 1 + ATOM 1185 CB . TRP A 152 ? -7.15000 3.13200 -2.21800 1.000 97.25000 C ? A ? 152 1 + ATOM 1186 CG . TRP A 152 ? -7.61400 3.05000 -3.64300 1.000 97.25000 C ? A ? 152 1 + ATOM 1187 CD1 . TRP A 152 ? -7.37800 3.93600 -4.64100 1.000 97.25000 C ? A ? 152 1 + ATOM 1188 CD2 . TRP A 152 ? -8.37800 1.97300 -4.26200 1.000 97.25000 C ? A ? 152 1 + ATOM 1189 NE1 . TRP A 152 ? -8.00500 3.52600 -5.79500 1.000 97.25000 N ? A ? 152 1 + ATOM 1190 CE2 . TRP A 152 ? -8.62800 2.31300 -5.62400 1.000 97.25000 C ? A ? 152 1 + ATOM 1191 CE3 . TRP A 152 ? -8.85900 0.72600 -3.81300 1.000 97.25000 C ? A ? 152 1 + ATOM 1192 CZ2 . TRP A 152 ? -9.34900 1.48000 -6.48900 1.000 97.25000 C ? A ? 152 1 + ATOM 1193 CZ3 . TRP A 152 ? -9.58600 -0.12100 -4.67000 1.000 97.25000 C ? A ? 152 1 + ATOM 1194 CH2 . TRP A 152 ? -9.83700 0.25600 -6.00200 1.000 97.25000 C ? A ? 152 1 + ATOM 1195 N . GLY A 153 ? -7.12300 6.56200 -2.84800 1.000 96.38000 N ? A ? 153 1 + ATOM 1196 CA . GLY A 153 ? -8.02900 7.66900 -3.16500 1.000 96.38000 C ? A ? 153 1 + ATOM 1197 C . GLY A 153 ? -8.12800 8.71600 -2.05100 1.000 96.38000 C ? A ? 153 1 + ATOM 1198 O . GLY A 153 ? -9.09300 9.47800 -2.00500 1.000 96.38000 O ? A ? 153 1 + ATOM 1199 N . CYS A 154 ? -7.15000 8.75600 -1.14200 1.000 96.56000 N ? A ? 154 1 + ATOM 1200 CA . CYS A 154 ? -7.06200 9.74900 -0.07300 1.000 96.56000 C ? A ? 154 1 + ATOM 1201 C . CYS A 154 ? -6.40300 11.01500 -0.63100 1.000 96.56000 C ? A ? 154 1 + ATOM 1202 O . CYS A 154 ? -5.18000 11.15500 -0.63100 1.000 96.56000 O ? A ? 154 1 + ATOM 1203 CB . CYS A 154 ? -6.29800 9.16100 1.12200 1.000 96.56000 C ? A ? 154 1 + ATOM 1204 SG . CYS A 154 ? -7.15300 7.68200 1.74000 1.000 96.56000 S ? A ? 154 1 + ATOM 1205 N . ARG A 155 ? -7.20400 11.93200 -1.17800 1.000 94.50000 N ? A ? 155 1 + ATOM 1206 CA . ARG A 155 ? -6.68700 13.04900 -1.98100 1.000 94.50000 C ? A ? 155 1 + ATOM 1207 C . ARG A 155 ? -6.05000 14.16200 -1.16300 1.000 94.50000 C ? A ? 155 1 + ATOM 1208 O . ARG A 155 ? -5.09900 14.75900 -1.66000 1.000 94.50000 O ? A ? 155 1 + ATOM 1209 CB . ARG A 155 ? -7.77500 13.58900 -2.91200 1.000 94.50000 C ? A ? 155 1 + ATOM 1210 CG . ARG A 155 ? -8.13000 12.54900 -3.98100 1.000 94.50000 C ? A ? 155 1 + ATOM 1211 CD . ARG A 155 ? -9.16900 13.12500 -4.94000 1.000 94.50000 C ? A ? 155 1 + ATOM 1212 NE . ARG A 155 ? -9.50600 12.14500 -5.98200 1.000 94.50000 N ? A ? 155 1 + ATOM 1213 CZ . ARG A 155 ? -10.52800 12.21200 -6.80900 1.000 94.50000 C ? A ? 155 1 + ATOM 1214 NH1 . ARG A 155 ? -11.34200 13.23500 -6.82600 1.000 94.50000 N ? A ? 155 1 + ATOM 1215 NH2 . ARG A 155 ? -10.74100 11.22800 -7.63200 1.000 94.50000 N ? A ? 155 1 + ATOM 1216 N . ASN A 156 ? -6.50600 14.41900 0.06100 1.000 95.88000 N ? A ? 156 1 + ATOM 1217 CA . ASN A 156 ? -5.98700 15.49700 0.91100 1.000 95.88000 C ? A ? 156 1 + ATOM 1218 C . ASN A 156 ? -4.85000 15.06900 1.84900 1.000 95.88000 C ? A ? 156 1 + ATOM 1219 O . ASN A 156 ? -4.24700 15.93300 2.49400 1.000 95.88000 O ? A ? 156 1 + ATOM 1220 CB . ASN A 156 ? -7.16200 16.18700 1.63300 1.000 95.88000 C ? A ? 156 1 + ATOM 1221 CG . ASN A 156 ? -8.00400 17.03500 0.68700 1.000 95.88000 C ? A ? 156 1 + ATOM 1222 OD1 . ASN A 156 ? -7.61300 17.30200 -0.44600 1.000 95.88000 O ? A ? 156 1 + ATOM 1223 ND2 . ASN A 156 ? -9.13900 17.52000 1.13100 1.000 95.88000 N ? A ? 156 1 + ATOM 1224 N . ILE A 157 ? -4.48100 13.78100 1.87900 1.000 93.88000 N ? A ? 157 1 + ATOM 1225 CA . ILE A 157 ? -3.43300 13.30800 2.78500 1.000 93.88000 C ? A ? 157 1 + ATOM 1226 C . ILE A 157 ? -2.07400 13.84000 2.34400 1.000 93.88000 C ? A ? 157 1 + ATOM 1227 O . ILE A 157 ? -1.66400 13.69100 1.19200 1.000 93.88000 O ? A ? 157 1 + ATOM 1228 CB . ILE A 157 ? -3.44300 11.77800 2.98100 1.000 93.88000 C ? A ? 157 1 + ATOM 1229 CG1 . ILE A 157 ? -2.54500 11.44300 4.19300 1.000 93.88000 C ? A ? 157 1 + ATOM 1230 CG2 . ILE A 157 ? -2.97500 11.00800 1.73300 1.000 93.88000 C ? A ? 157 1 + ATOM 1231 CD1 . ILE A 157 ? -2.68000 10.00500 4.68000 1.000 93.88000 C ? A ? 157 1 + ATOM 1232 N . LYS A 158 ? -1.35400 14.46700 3.27600 1.000 90.25000 N ? A ? 158 1 + ATOM 1233 CA . LYS A 158 ? -0.05500 15.10100 2.98600 1.000 90.25000 C ? A ? 158 1 + ATOM 1234 C . LYS A 158 ? 1.12800 14.28300 3.47700 1.000 90.25000 C ? A ? 158 1 + ATOM 1235 O . LYS A 158 ? 2.19100 14.32500 2.85000 1.000 90.25000 O ? A ? 158 1 + ATOM 1236 CB . LYS A 158 ? -0.03300 16.52200 3.56300 1.000 90.25000 C ? A ? 158 1 + ATOM 1237 CG . LYS A 158 ? -1.01500 17.43000 2.80900 1.000 90.25000 C ? A ? 158 1 + ATOM 1238 CD . LYS A 158 ? -1.16200 18.79700 3.48300 1.000 90.25000 C ? A ? 158 1 + ATOM 1239 CE . LYS A 158 ? -2.29200 19.56300 2.78400 1.000 90.25000 C ? A ? 158 1 + ATOM 1240 NZ . LYS A 158 ? -2.76100 20.72300 3.58200 1.000 90.25000 N ? A ? 158 1 + ATOM 1241 N . HIS A 159 ? 0.95500 13.54300 4.57200 1.000 87.75000 N ? A ? 159 1 + ATOM 1242 CA . HIS A 159 ? 2.02500 12.82000 5.25500 1.000 87.75000 C ? A ? 159 1 + ATOM 1243 C . HIS A 159 ? 1.52400 11.49700 5.84200 1.000 87.75000 C ? A ? 159 1 + ATOM 1244 O . HIS A 159 ? 0.38200 11.39700 6.28500 1.000 87.75000 O ? A ? 159 1 + ATOM 1245 CB . HIS A 159 ? 2.61900 13.70900 6.36300 1.000 87.75000 C ? A ? 159 1 + ATOM 1246 CG . HIS A 159 ? 3.09500 15.05700 5.87200 1.000 87.75000 C ? A ? 159 1 + ATOM 1247 ND1 . HIS A 159 ? 4.01500 15.27200 4.87100 1.000 87.75000 N ? A ? 159 1 + ATOM 1248 CD2 . HIS A 159 ? 2.58500 16.28000 6.22000 1.000 87.75000 C ? A ? 159 1 + ATOM 1249 CE1 . HIS A 159 ? 4.04100 16.58800 4.60700 1.000 87.75000 C ? A ? 159 1 + ATOM 1250 NE2 . HIS A 159 ? 3.20100 17.24700 5.41500 1.000 87.75000 N ? A ? 159 1 + ATOM 1251 N . LEU A 160 ? 2.41000 10.50100 5.88000 1.000 89.56000 N ? A ? 160 1 + ATOM 1252 CA . LEU A 160 ? 2.24700 9.33600 6.74700 1.000 89.56000 C ? A ? 160 1 + ATOM 1253 C . LEU A 160 ? 2.68600 9.68500 8.18600 1.000 89.56000 C ? A ? 160 1 + ATOM 1254 O . LEU A 160 ? 3.45600 10.63700 8.35800 1.000 89.56000 O ? A ? 160 1 + ATOM 1255 CB . LEU A 160 ? 3.04800 8.15200 6.17600 1.000 89.56000 C ? A ? 160 1 + ATOM 1256 CG . LEU A 160 ? 2.52800 7.59900 4.83700 1.000 89.56000 C ? A ? 160 1 + ATOM 1257 CD1 . LEU A 160 ? 3.44700 6.48100 4.34800 1.000 89.56000 C ? A ? 160 1 + ATOM 1258 CD2 . LEU A 160 ? 1.11500 7.02700 4.95500 1.000 89.56000 C ? A ? 160 1 + ATOM 1259 N . PRO A 161 ? 2.23800 8.93100 9.21000 1.000 87.69000 N ? A ? 161 1 + ATOM 1260 CA . PRO A 161 ? 2.60900 9.18400 10.60100 1.000 87.69000 C ? A ? 161 1 + ATOM 1261 C . PRO A 161 ? 4.12500 9.18000 10.82600 1.000 87.69000 C ? A ? 161 1 + ATOM 1262 O . PRO A 161 ? 4.86100 8.40500 10.20800 1.000 87.69000 O ? A ? 161 1 + ATOM 1263 CB . PRO A 161 ? 1.93500 8.07900 11.41900 1.000 87.69000 C ? A ? 161 1 + ATOM 1264 CG . PRO A 161 ? 0.74600 7.66800 10.55800 1.000 87.69000 C ? A ? 161 1 + ATOM 1265 CD . PRO A 161 ? 1.27700 7.84000 9.13800 1.000 87.69000 C ? A ? 161 1 + ATOM 1266 N . GLN A 162 ? 4.60600 10.01700 11.74800 1.000 86.12000 N ? A ? 162 1 + ATOM 1267 CA . GLN A 162 ? 6.00400 9.96100 12.18200 1.000 86.12000 C ? A ? 162 1 + ATOM 1268 C . GLN A 162 ? 6.29100 8.67300 12.97100 1.000 86.12000 C ? A ? 162 1 + ATOM 1269 O . GLN A 162 ? 5.42400 8.15700 13.67700 1.000 86.12000 O ? A ? 162 1 + ATOM 1270 CB . GLN A 162 ? 6.36800 11.20200 13.00800 1.000 86.12000 C ? A ? 162 1 + ATOM 1271 CG . GLN A 162 ? 6.30800 12.49400 12.17600 1.000 86.12000 C ? A ? 162 1 + ATOM 1272 CD . GLN A 162 ? 6.82000 13.71200 12.93800 1.000 86.12000 C ? A ? 162 1 + ATOM 1273 OE1 . GLN A 162 ? 7.14700 13.68400 14.10800 1.000 86.12000 O ? A ? 162 1 + ATOM 1274 NE2 . GLN A 162 ? 6.93800 14.85000 12.29000 1.000 86.12000 N ? A ? 162 1 + ATOM 1275 N . GLY A 163 ? 7.52500 8.16700 12.87800 1.000 85.31000 N ? A ? 163 1 + ATOM 1276 CA . GLY A 163 ? 7.95800 6.97100 13.60700 1.000 85.31000 C ? A ? 163 1 + ATOM 1277 C . GLY A 163 ? 7.66200 5.63800 12.91400 1.000 85.31000 C ? A ? 163 1 + ATOM 1278 O . GLY A 163 ? 7.71100 4.60700 13.57800 1.000 85.31000 O ? A ? 163 1 + ATOM 1279 N . LEU A 164 ? 7.36200 5.62300 11.60700 1.000 86.94000 N ? A ? 164 1 + ATOM 1280 CA . LEU A 164 ? 7.19200 4.37300 10.84300 1.000 86.94000 C ? A ? 164 1 + ATOM 1281 C . LEU A 164 ? 8.44300 3.47600 10.87600 1.000 86.94000 C ? A ? 164 1 + ATOM 1282 O . LEU A 164 ? 8.32400 2.25900 10.81700 1.000 86.94000 O ? A ? 164 1 + ATOM 1283 CB . LEU A 164 ? 6.80200 4.68900 9.38200 1.000 86.94000 C ? A ? 164 1 + ATOM 1284 CG . LEU A 164 ? 5.33400 5.10900 9.17800 1.000 86.94000 C ? A ? 164 1 + ATOM 1285 CD1 . LEU A 164 ? 5.05400 5.46500 7.71800 1.000 86.94000 C ? A ? 164 1 + ATOM 1286 CD2 . LEU A 164 ? 4.34800 4.00600 9.53400 1.000 86.94000 C ? A ? 164 1 + ATOM 1287 N . ASP A 165 ? 9.62700 4.06100 11.03600 1.000 82.50000 N ? A ? 165 1 + ATOM 1288 CA . ASP A 165 ? 10.90700 3.37100 11.23400 1.000 82.50000 C ? A ? 165 1 + ATOM 1289 C . ASP A 165 ? 11.00100 2.58300 12.54600 1.000 82.50000 C ? A ? 165 1 + ATOM 1290 O . ASP A 165 ? 11.81500 1.67000 12.66200 1.000 82.50000 O ? A ? 165 1 + ATOM 1291 CB . ASP A 165 ? 12.03300 4.40500 11.13100 1.000 82.50000 C ? A ? 165 1 + ATOM 1292 CG . ASP A 165 ? 11.94500 5.54800 12.15700 1.000 82.50000 C ? A ? 165 1 + ATOM 1293 OD1 . ASP A 165 ? 10.85200 6.15800 12.27500 1.000 82.50000 O ? A ? 165 1 + ATOM 1294 OD2 . ASP A 165 ? 12.97800 5.84600 12.79000 1.000 82.50000 O ? A ? 165 1 + ATOM 1295 N . LYS A 166 ? 10.13500 2.88600 13.51800 1.000 84.88000 N ? A ? 166 1 + ATOM 1296 CA . LYS A 166 ? 10.03600 2.14600 14.78200 1.000 84.88000 C ? A ? 166 1 + ATOM 1297 C . LYS A 166 ? 9.19300 0.87300 14.65600 1.000 84.88000 C ? A ? 166 1 + ATOM 1298 O . LYS A 166 ? 9.19000 0.05200 15.57400 1.000 84.88000 O ? A ? 166 1 + ATOM 1299 CB . LYS A 166 ? 9.48300 3.06500 15.88200 1.000 84.88000 C ? A ? 166 1 + ATOM 1300 CG . LYS A 166 ? 10.30900 4.34900 16.06800 1.000 84.88000 C ? A ? 166 1 + ATOM 1301 CD . LYS A 166 ? 9.67500 5.22000 17.15700 1.000 84.88000 C ? A ? 166 1 + ATOM 1302 CE . LYS A 166 ? 10.47600 6.51300 17.34100 1.000 84.88000 C ? A ? 166 1 + ATOM 1303 NZ . LYS A 166 ? 9.81500 7.40700 18.32700 1.000 84.88000 N ? A ? 166 1 + ATOM 1304 N . LEU A 167 ? 8.47500 0.69000 13.54500 1.000 87.62000 N ? A ? 167 1 + ATOM 1305 CA . LEU A 167 ? 7.61200 -0.46800 13.32600 1.000 87.62000 C ? A ? 167 1 + ATOM 1306 C . LEU A 167 ? 8.41600 -1.66500 12.81600 1.000 87.62000 C ? A ? 167 1 + ATOM 1307 O . LEU A 167 ? 8.57200 -1.88100 11.61600 1.000 87.62000 O ? A ? 167 1 + ATOM 1308 CB . LEU A 167 ? 6.47800 -0.11500 12.35900 1.000 87.62000 C ? A ? 167 1 + ATOM 1309 CG . LEU A 167 ? 5.46200 0.90200 12.89400 1.000 87.62000 C ? A ? 167 1 + ATOM 1310 CD1 . LEU A 167 ? 4.52700 1.27000 11.75300 1.000 87.62000 C ? A ? 167 1 + ATOM 1311 CD2 . LEU A 167 ? 4.64800 0.29700 14.03800 1.000 87.62000 C ? A ? 167 1 + ATOM 1312 N . SER A 168 ? 8.86100 -2.51000 13.74100 1.000 87.56000 N ? A ? 168 1 + ATOM 1313 CA . SER A 168 ? 9.58700 -3.74800 13.42600 1.000 87.56000 C ? A ? 168 1 + ATOM 1314 C . SER A 168 ? 8.73300 -4.83300 12.75700 1.000 87.56000 C ? A ? 168 1 + ATOM 1315 O . SER A 168 ? 9.26100 -5.85800 12.34000 1.000 87.56000 O ? A ? 168 1 + ATOM 1316 CB . SER A 168 ? 10.22400 -4.30000 14.70000 1.000 87.56000 C ? A ? 168 1 + ATOM 1317 OG . SER A 168 ? 9.23000 -4.56300 15.67800 1.000 87.56000 O ? A ? 168 1 + ATOM 1318 N . ARG A 169 ? 7.41400 -4.64300 12.65400 1.000 93.12000 N ? A ? 169 1 + ATOM 1319 CA . ARG A 169 ? 6.49000 -5.61000 12.03800 1.000 93.12000 C ? A ? 169 1 + ATOM 1320 C . ARG A 169 ? 5.89900 -5.14700 10.71600 1.000 93.12000 C ? A ? 169 1 + ATOM 1321 O . ARG A 169 ? 5.22700 -5.94600 10.07200 1.000 93.12000 O ? A ? 169 1 + ATOM 1322 CB . ARG A 169 ? 5.38000 -5.97300 13.02900 1.000 93.12000 C ? A ? 169 1 + ATOM 1323 CG . ARG A 169 ? 5.95300 -6.68400 14.25700 1.000 93.12000 C ? A ? 169 1 + ATOM 1324 CD . ARG A 169 ? 4.79800 -7.14700 15.13800 1.000 93.12000 C ? A ? 169 1 + ATOM 1325 NE . ARG A 169 ? 5.29200 -7.84000 16.33900 1.000 93.12000 N ? A ? 169 1 + ATOM 1326 CZ . ARG A 169 ? 4.54700 -8.20900 17.36100 1.000 93.12000 C ? A ? 169 1 + ATOM 1327 NH1 . ARG A 169 ? 3.25600 -8.03300 17.35800 1.000 93.12000 N ? A ? 169 1 + ATOM 1328 NH2 . ARG A 169 ? 5.09100 -8.75700 18.41000 1.000 93.12000 N ? A ? 169 1 + ATOM 1329 N . LEU A 170 ? 6.15600 -3.90500 10.30300 1.000 94.44000 N ? A ? 170 1 + ATOM 1330 CA . LEU A 170 ? 5.56000 -3.33900 9.09900 1.000 94.44000 C ? A ? 170 1 + ATOM 1331 C . LEU A 170 ? 6.11400 -4.04400 7.85900 1.000 94.44000 C ? A ? 170 1 + ATOM 1332 O . LEU A 170 ? 7.28600 -3.89500 7.51700 1.000 94.44000 O ? A ? 170 1 + ATOM 1333 CB . LEU A 170 ? 5.79300 -1.82200 9.07900 1.000 94.44000 C ? A ? 170 1 + ATOM 1334 CG . LEU A 170 ? 5.06500 -1.09000 7.93800 1.000 94.44000 C ? A ? 170 1 + ATOM 1335 CD1 . LEU A 170 ? 3.54400 -1.12100 8.10400 1.000 94.44000 C ? A ? 170 1 + ATOM 1336 CD2 . LEU A 170 ? 5.49900 0.37200 7.93600 1.000 94.44000 C ? A ? 170 1 + ATOM 1337 N . GLN A 171 ? 5.25100 -4.80800 7.19700 1.000 96.44000 N ? A ? 171 1 + ATOM 1338 CA . GLN A 171 ? 5.57800 -5.61900 6.02900 1.000 96.44000 C ? A ? 171 1 + ATOM 1339 C . GLN A 171 ? 5.01400 -5.01700 4.74800 1.000 96.44000 C ? A ? 171 1 + ATOM 1340 O . GLN A 171 ? 5.66800 -5.11100 3.71000 1.000 96.44000 O ? A ? 171 1 + ATOM 1341 CB . GLN A 171 ? 5.05300 -7.04600 6.23400 1.000 96.44000 C ? A ? 171 1 + ATOM 1342 CG . GLN A 171 ? 5.91300 -7.81100 7.24800 1.000 96.44000 C ? A ? 171 1 + ATOM 1343 CD . GLN A 171 ? 5.29100 -9.13300 7.67400 1.000 96.44000 C ? A ? 171 1 + ATOM 1344 OE1 . GLN A 171 ? 4.61100 -9.82100 6.93800 1.000 96.44000 O ? A ? 171 1 + ATOM 1345 NE2 . GLN A 171 ? 5.51000 -9.55600 8.89800 1.000 96.44000 N ? A ? 171 1 + ATOM 1346 N . HIS A 172 ? 3.83600 -4.38700 4.80200 1.000 97.25000 N ? A ? 172 1 + ATOM 1347 CA . HIS A 172 ? 3.12400 -3.93100 3.60800 1.000 97.25000 C ? A ? 172 1 + ATOM 1348 C . HIS A 172 ? 2.78100 -2.43800 3.67200 1.000 97.25000 C ? A ? 172 1 + ATOM 1349 O . HIS A 172 ? 2.11600 -1.98100 4.60300 1.000 97.25000 O ? A ? 172 1 + ATOM 1350 CB . HIS A 172 ? 1.84900 -4.76500 3.41100 1.000 97.25000 C ? A ? 172 1 + ATOM 1351 CG . HIS A 172 ? 2.01800 -6.26600 3.33500 1.000 97.25000 C ? A ? 172 1 + ATOM 1352 ND1 . HIS A 172 ? 1.00100 -7.17900 3.48400 1.000 97.25000 N ? A ? 172 1 + ATOM 1353 CD2 . HIS A 172 ? 3.15000 -6.99000 3.06900 1.000 97.25000 C ? A ? 172 1 + ATOM 1354 CE1 . HIS A 172 ? 1.51400 -8.41100 3.33500 1.000 97.25000 C ? A ? 172 1 + ATOM 1355 NE2 . HIS A 172 ? 2.82300 -8.34300 3.07600 1.000 97.25000 N ? A ? 172 1 + ATOM 1356 N . ILE A 173 ? 3.17000 -1.69500 2.63700 1.000 95.19000 N ? A ? 173 1 + ATOM 1357 CA . ILE A 173 ? 2.70600 -0.32700 2.38700 1.000 95.19000 C ? A ? 173 1 + ATOM 1358 C . ILE A 173 ? 2.12000 -0.27500 0.97600 1.000 95.19000 C ? A ? 173 1 + ATOM 1359 O . ILE A 173 ? 2.83600 -0.47400 -0.00700 1.000 95.19000 O ? A ? 173 1 + ATOM 1360 CB . ILE A 173 ? 3.83900 0.70300 2.59200 1.000 95.19000 C ? A ? 173 1 + ATOM 1361 CG1 . ILE A 173 ? 4.29900 0.74300 4.06800 1.000 95.19000 C ? A ? 173 1 + ATOM 1362 CG2 . ILE A 173 ? 3.38000 2.10700 2.14600 1.000 95.19000 C ? A ? 173 1 + ATOM 1363 CD1 . ILE A 173 ? 5.56200 1.59200 4.27800 1.000 95.19000 C ? A ? 173 1 + ATOM 1364 N . CYS A 174 ? 0.83000 0.03200 0.88200 1.000 95.94000 N ? A ? 174 1 + ATOM 1365 CA . CYS A 174 ? 0.11400 0.19900 -0.37600 1.000 95.94000 C ? A ? 174 1 + ATOM 1366 C . CYS A 174 ? -0.46200 1.61500 -0.45000 1.000 95.94000 C ? A ? 174 1 + ATOM 1367 O . CYS A 174 ? -1.22600 2.02500 0.41500 1.000 95.94000 O ? A ? 174 1 + ATOM 1368 CB . CYS A 174 ? -0.98000 -0.87200 -0.48600 1.000 95.94000 C ? A ? 174 1 + ATOM 1369 SG . CYS A 174 ? -0.24700 -2.53700 -0.49800 1.000 95.94000 S ? A ? 174 1 + ATOM 1370 N . LEU A 175 ? -0.08700 2.37500 -1.47300 1.000 94.50000 N ? A ? 175 1 + ATOM 1371 CA . LEU A 175 ? -0.52300 3.75100 -1.69300 1.000 94.50000 C ? A ? 175 1 + ATOM 1372 C . LEU A 175 ? -1.03800 3.87100 -3.12500 1.000 94.50000 C ? A ? 175 1 + ATOM 1373 O . LEU A 175 ? -0.28000 3.63300 -4.06300 1.000 94.50000 O ? A ? 175 1 + ATOM 1374 CB . LEU A 175 ? 0.65800 4.71300 -1.45300 1.000 94.50000 C ? A ? 175 1 + ATOM 1375 CG . LEU A 175 ? 1.31000 4.62800 -0.06300 1.000 94.50000 C ? A ? 175 1 + ATOM 1376 CD1 . LEU A 175 ? 2.54700 5.52500 -0.03200 1.000 94.50000 C ? A ? 175 1 + ATOM 1377 CD2 . LEU A 175 ? 0.37200 5.07800 1.05200 1.000 94.50000 C ? A ? 175 1 + ATOM 1378 N . TRP A 176 ? -2.29500 4.26000 -3.30200 1.000 93.94000 N ? A ? 176 1 + ATOM 1379 CA . TRP A 176 ? -2.92400 4.42100 -4.61100 1.000 93.94000 C ? A ? 176 1 + ATOM 1380 C . TRP A 176 ? -3.69500 5.74400 -4.67000 1.000 93.94000 C ? A ? 176 1 + ATOM 1381 O . TRP A 176 ? -4.55500 5.98600 -3.83500 1.000 93.94000 O ? A ? 176 1 + ATOM 1382 CB . TRP A 176 ? -3.82000 3.20500 -4.89400 1.000 93.94000 C ? A ? 176 1 + ATOM 1383 CG . TRP A 176 ? -4.33200 3.06800 -6.30100 1.000 93.94000 C ? A ? 176 1 + ATOM 1384 CD1 . TRP A 176 ? -4.84100 4.05300 -7.07100 1.000 93.94000 C ? A ? 176 1 + ATOM 1385 CD2 . TRP A 176 ? -4.49400 1.85700 -7.09800 1.000 93.94000 C ? A ? 176 1 + ATOM 1386 NE1 . TRP A 176 ? -5.20600 3.57600 -8.30500 1.000 93.94000 N ? A ? 176 1 + ATOM 1387 CE2 . TRP A 176 ? -5.07100 2.21400 -8.35600 1.000 93.94000 C ? A ? 176 1 + ATOM 1388 CE3 . TRP A 176 ? -4.26300 0.48600 -6.86700 1.000 93.94000 C ? A ? 176 1 + ATOM 1389 CZ2 . TRP A 176 ? -5.41600 1.26900 -9.32800 1.000 93.94000 C ? A ? 176 1 + ATOM 1390 CZ3 . TRP A 176 ? -4.62100 -0.47700 -7.82900 1.000 93.94000 C ? A ? 176 1 + ATOM 1391 CH2 . TRP A 176 ? -5.20900 -0.09000 -9.04800 1.000 93.94000 C ? A ? 176 1 + ATOM 1392 N . ASP A 177 ? -3.46000 6.57900 -5.68600 1.000 92.81000 N ? A ? 177 1 + ATOM 1393 CA . ASP A 177 ? -4.22600 7.82100 -5.92800 1.000 92.81000 C ? A ? 177 1 + ATOM 1394 C . ASP A 177 ? -4.25500 8.72900 -4.68500 1.000 92.81000 C ? A ? 177 1 + ATOM 1395 O . ASP A 177 ? -5.30100 9.19600 -4.23400 1.000 92.81000 O ? A ? 177 1 + ATOM 1396 CB . ASP A 177 ? -5.61500 7.53100 -6.55000 1.000 92.81000 C ? A ? 177 1 + ATOM 1397 CG . ASP A 177 ? -6.37000 8.78600 -7.01000 1.000 92.81000 C ? A ? 177 1 + ATOM 1398 OD1 . ASP A 177 ? -5.69300 9.70900 -7.51700 1.000 92.81000 O ? A ? 177 1 + ATOM 1399 OD2 . ASP A 177 ? -7.62400 8.80100 -6.93600 1.000 92.81000 O ? A ? 177 1 + ATOM 1400 N . CYS A 178 ? -3.06900 8.96200 -4.11400 1.000 93.12000 N ? A ? 178 1 + ATOM 1401 CA . CYS A 178 ? -2.83700 9.93200 -3.04100 1.000 93.12000 C ? A ? 178 1 + ATOM 1402 C . CYS A 178 ? -2.01400 11.11700 -3.59400 1.000 93.12000 C ? A ? 178 1 + ATOM 1403 O . CYS A 178 ? -0.82500 11.25200 -3.28000 1.000 93.12000 O ? A ? 178 1 + ATOM 1404 CB . CYS A 178 ? -2.17200 9.24500 -1.83700 1.000 93.12000 C ? A ? 178 1 + ATOM 1405 SG . CYS A 178 ? -3.22500 7.91900 -1.17400 1.000 93.12000 S ? A ? 178 1 + ATOM 1406 N . PRO A 179 ? -2.59700 11.98300 -4.44900 1.000 90.12000 N ? A ? 179 1 + ATOM 1407 CA . PRO A 179 ? -1.85500 12.98500 -5.21800 1.000 90.12000 C ? A ? 179 1 + ATOM 1408 C . PRO A 179 ? -1.14500 14.04800 -4.37400 1.000 90.12000 C ? A ? 179 1 + ATOM 1409 O . PRO A 179 ? -0.11800 14.58000 -4.80200 1.000 90.12000 O ? A ? 179 1 + ATOM 1410 CB . PRO A 179 ? -2.88200 13.61000 -6.17100 1.000 90.12000 C ? A ? 179 1 + ATOM 1411 CG . PRO A 179 ? -4.22000 13.36700 -5.47400 1.000 90.12000 C ? A ? 179 1 + ATOM 1412 CD . PRO A 179 ? -3.99300 11.99400 -4.85600 1.000 90.12000 C ? A ? 179 1 + ATOM 1413 N . ASN A 180 ? -1.65400 14.35500 -3.17700 1.000 91.50000 N ? A ? 180 1 + ATOM 1414 CA . ASN A 180 ? -1.05900 15.35600 -2.29100 1.000 91.50000 C ? A ? 180 1 + ATOM 1415 C . ASN A 180 ? -0.04300 14.79600 -1.29000 1.000 91.50000 C ? A ? 180 1 + ATOM 1416 O . ASN A 180 ? 0.59600 15.59700 -0.60200 1.000 91.50000 O ? A ? 180 1 + ATOM 1417 CB . ASN A 180 ? -2.16300 16.16800 -1.60300 1.000 91.50000 C ? A ? 180 1 + ATOM 1418 CG . ASN A 180 ? -2.83500 17.11800 -2.57400 1.000 91.50000 C ? A ? 180 1 + ATOM 1419 OD1 . ASN A 180 ? -2.16200 17.86300 -3.27400 1.000 91.50000 O ? A ? 180 1 + ATOM 1420 ND2 . ASN A 180 ? -4.14200 17.15500 -2.62500 1.000 91.50000 N ? A ? 180 1 + ATOM 1421 N . LEU A 181 ? 0.16300 13.47600 -1.24400 1.000 90.62000 N ? A ? 181 1 + ATOM 1422 CA . LEU A 181 ? 1.10600 12.84800 -0.32300 1.000 90.62000 C ? A ? 181 1 + ATOM 1423 C . LEU A 181 ? 2.53400 13.25400 -0.70600 1.000 90.62000 C ? A ? 181 1 + ATOM 1424 O . LEU A 181 ? 3.04900 12.85700 -1.74600 1.000 90.62000 O ? A ? 181 1 + ATOM 1425 CB . LEU A 181 ? 0.86800 11.32900 -0.33300 1.000 90.62000 C ? A ? 181 1 + ATOM 1426 CG . LEU A 181 ? 1.72100 10.54000 0.67400 1.000 90.62000 C ? A ? 181 1 + ATOM 1427 CD1 . LEU A 181 ? 1.45000 10.92300 2.12500 1.000 90.62000 C ? A ? 181 1 + ATOM 1428 CD2 . LEU A 181 ? 1.43800 9.04900 0.53000 1.000 90.62000 C ? A ? 181 1 + ATOM 1429 N . VAL A 182 ? 3.16600 14.10100 0.10800 1.000 83.31000 N ? A ? 182 1 + ATOM 1430 CA . VAL A 182 ? 4.36500 14.85000 -0.30900 1.000 83.31000 C ? A ? 182 1 + ATOM 1431 C . VAL A 182 ? 5.62400 13.99000 -0.30400 1.000 83.31000 C ? A ? 182 1 + ATOM 1432 O . VAL A 182 ? 6.50100 14.18200 -1.13500 1.000 83.31000 O ? A ? 182 1 + ATOM 1433 CB . VAL A 182 ? 4.56600 16.10300 0.56800 1.000 83.31000 C ? A ? 182 1 + ATOM 1434 CG1 . VAL A 182 ? 5.80100 16.91900 0.15900 1.000 83.31000 C ? A ? 182 1 + ATOM 1435 CG2 . VAL A 182 ? 3.35600 17.04100 0.48400 1.000 83.31000 C ? A ? 182 1 + ATOM 1436 N . ARG A 183 ? 5.75200 13.07500 0.65600 1.000 78.00000 N ? A ? 183 1 + ATOM 1437 CA . ARG A 183 ? 6.95900 12.26300 0.83500 1.000 78.00000 C ? A ? 183 1 + ATOM 1438 C . ARG A 183 ? 6.65100 10.99000 1.60300 1.000 78.00000 C ? A ? 183 1 + ATOM 1439 O . ARG A 183 ? 5.76200 10.98300 2.45700 1.000 78.00000 O ? A ? 183 1 + ATOM 1440 CB . ARG A 183 ? 8.07200 13.07700 1.52800 1.000 78.00000 C ? A ? 183 1 + ATOM 1441 CG . ARG A 183 ? 7.66900 13.69300 2.88000 1.000 78.00000 C ? A ? 183 1 + ATOM 1442 CD . ARG A 183 ? 8.84100 14.48400 3.47100 1.000 78.00000 C ? A ? 183 1 + ATOM 1443 NE . ARG A 183 ? 8.43600 15.24600 4.67200 1.000 78.00000 N ? A ? 183 1 + ATOM 1444 CZ . ARG A 183 ? 9.18300 15.49000 5.73700 1.000 78.00000 C ? A ? 183 1 + ATOM 1445 NH1 . ARG A 183 ? 10.39500 15.02400 5.85800 1.000 78.00000 N ? A ? 183 1 + ATOM 1446 NH2 . ARG A 183 ? 8.71200 16.22200 6.70800 1.000 78.00000 N ? A ? 183 1 + ATOM 1447 N . LEU A 184 ? 7.43000 9.95200 1.32400 1.000 79.56000 N ? A ? 184 1 + ATOM 1448 CA . LEU A 184 ? 7.56600 8.82000 2.23300 1.000 79.56000 C ? A ? 184 1 + ATOM 1449 C . LEU A 184 ? 8.43500 9.21600 3.43600 1.000 79.56000 C ? A ? 184 1 + ATOM 1450 O . LEU A 184 ? 9.11400 10.24900 3.39700 1.000 79.56000 O ? A ? 184 1 + ATOM 1451 CB . LEU A 184 ? 8.14600 7.62000 1.46400 1.000 79.56000 C ? A ? 184 1 + ATOM 1452 CG . LEU A 184 ? 7.07500 6.94200 0.60400 1.000 79.56000 C ? A ? 184 1 + ATOM 1453 CD1 . LEU A 184 ? 7.71900 6.04200 -0.43900 1.000 79.56000 C ? A ? 184 1 + ATOM 1454 CD2 . LEU A 184 ? 6.06000 6.12500 1.39400 1.000 79.56000 C ? A ? 184 1 + ATOM 1455 N . PRO A 185 ? 8.41400 8.42200 4.51900 1.000 75.38000 N ? A ? 185 1 + ATOM 1456 CA . PRO A 185 ? 9.31200 8.62500 5.64400 1.000 75.38000 C ? A ? 185 1 + ATOM 1457 C . PRO A 185 ? 10.76400 8.67000 5.18100 1.000 75.38000 C ? A ? 185 1 + ATOM 1458 O . PRO A 185 ? 11.19900 7.84800 4.38000 1.000 75.38000 O ? A ? 185 1 + ATOM 1459 CB . PRO A 185 ? 9.07600 7.45000 6.59500 1.000 75.38000 C ? A ? 185 1 + ATOM 1460 CG . PRO A 185 ? 7.64900 7.04300 6.26300 1.000 75.38000 C ? A ? 185 1 + ATOM 1461 CD . PRO A 185 ? 7.54400 7.28700 4.76600 1.000 75.38000 C ? A ? 185 1 + ATOM 1462 N . GLU A 186 ? 11.54100 9.59800 5.73200 1.000 73.69000 N ? A ? 186 1 + ATOM 1463 CA . GLU A 186 ? 12.96800 9.72900 5.41400 1.000 73.69000 C ? A ? 186 1 + ATOM 1464 C . GLU A 186 ? 13.77600 8.46200 5.71200 1.000 73.69000 C ? A ? 186 1 + ATOM 1465 O . GLU A 186 ? 14.79000 8.20500 5.06300 1.000 73.69000 O ? A ? 186 1 + ATOM 1466 CB . GLU A 186 ? 13.53200 10.89400 6.22700 1.000 73.69000 C ? A ? 186 1 + ATOM 1467 CG . GLU A 186 ? 13.13400 12.22000 5.57100 1.000 73.69000 C ? A ? 186 1 + ATOM 1468 CD . GLU A 186 ? 13.86800 13.41100 6.18000 1.000 73.69000 C ? A ? 186 1 + ATOM 1469 OE1 . GLU A 186 ? 13.22100 14.48100 6.26100 1.000 73.69000 O ? A ? 186 1 + ATOM 1470 OE2 . GLU A 186 ? 15.07500 13.24700 6.46100 1.000 73.69000 O ? A ? 186 1 + ATOM 1471 N . ALA A 187 ? 13.29000 7.67500 6.66700 1.000 73.94000 N ? A ? 187 1 + ATOM 1472 CA . ALA A 187 ? 13.82200 6.39100 7.08000 1.000 73.94000 C ? A ? 187 1 + ATOM 1473 C . ALA A 187 ? 13.21100 5.20200 6.30600 1.000 73.94000 C ? A ? 187 1 + ATOM 1474 O . ALA A 187 ? 13.33100 4.06900 6.76100 1.000 73.94000 O ? A ? 187 1 + ATOM 1475 CB . ALA A 187 ? 13.63000 6.31100 8.59600 1.000 73.94000 C ? A ? 187 1 + ATOM 1476 N . LEU A 188 ? 12.57800 5.41700 5.14100 1.000 81.38000 N ? A ? 188 1 + ATOM 1477 CA . LEU A 188 ? 12.05700 4.33700 4.28900 1.000 81.38000 C ? A ? 188 1 + ATOM 1478 C . LEU A 188 ? 13.10000 3.22900 4.03000 1.000 81.38000 C ? A ? 188 1 + ATOM 1479 O . LEU A 188 ? 12.74600 2.06900 4.22000 1.000 81.38000 O ? A ? 188 1 + ATOM 1480 CB . LEU A 188 ? 11.49000 4.91300 2.97200 1.000 81.38000 C ? A ? 188 1 + ATOM 1481 CG . LEU A 188 ? 10.83000 3.86400 2.05400 1.000 81.38000 C ? A ? 188 1 + ATOM 1482 CD1 . LEU A 188 ? 9.38900 3.60200 2.48800 1.000 81.38000 C ? A ? 188 1 + ATOM 1483 CD2 . LEU A 188 ? 10.82900 4.36000 0.61000 1.000 81.38000 C ? A ? 188 1 + ATOM 1484 N . PRO A 189 ? 14.37700 3.51800 3.69100 1.000 80.94000 N ? A ? 189 1 + ATOM 1485 CA . PRO A 189 ? 15.38400 2.46400 3.51600 1.000 80.94000 C ? A ? 189 1 + ATOM 1486 C . PRO A 189 ? 15.66100 1.63800 4.78600 1.000 80.94000 C ? A ? 189 1 + ATOM 1487 O . PRO A 189 ? 16.14200 0.51100 4.68800 1.000 80.94000 O ? A ? 189 1 + ATOM 1488 CB . PRO A 189 ? 16.65800 3.17700 3.05100 1.000 80.94000 C ? A ? 189 1 + ATOM 1489 CG . PRO A 189 ? 16.15900 4.49500 2.47200 1.000 80.94000 C ? A ? 189 1 + ATOM 1490 CD . PRO A 189 ? 14.96100 4.81300 3.35700 1.000 80.94000 C ? A ? 189 1 + ATOM 1491 N . ASN A 190 ? 15.33300 2.17400 5.96800 1.000 82.69000 N ? A ? 190 1 + ATOM 1492 CA . ASN A 190 ? 15.52700 1.52400 7.26600 1.000 82.69000 C ? A ? 190 1 + ATOM 1493 C . ASN A 190 ? 14.34500 0.62000 7.65800 1.000 82.69000 C ? A ? 190 1 + ATOM 1494 O . ASN A 190 ? 14.37800 -0.00900 8.71400 1.000 82.69000 O ? A ? 190 1 + ATOM 1495 CB . ASN A 190 ? 15.79700 2.57800 8.35700 1.000 82.69000 C ? A ? 190 1 + ATOM 1496 CG . ASN A 190 ? 16.97400 3.49600 8.08600 1.000 82.69000 C ? A ? 190 1 + ATOM 1497 OD1 . ASN A 190 ? 17.81800 3.27800 7.23400 1.000 82.69000 O ? A ? 190 1 + ATOM 1498 ND2 . ASN A 190 ? 17.07000 4.58200 8.81700 1.000 82.69000 N ? A ? 190 1 + ATOM 1499 N . LEU A 191 ? 13.29700 0.52100 6.83100 1.000 87.00000 N ? A ? 191 1 + ATOM 1500 CA . LEU A 191 ? 12.18900 -0.40900 7.05600 1.000 87.00000 C ? A ? 191 1 + ATOM 1501 C . LEU A 191 ? 12.60800 -1.83800 6.69200 1.000 87.00000 C ? A ? 191 1 + ATOM 1502 O . LEU A 191 ? 12.17200 -2.40800 5.69500 1.000 87.00000 O ? A ? 191 1 + ATOM 1503 CB . LEU A 191 ? 10.92500 0.04300 6.30600 1.000 87.00000 C ? A ? 191 1 + ATOM 1504 CG . LEU A 191 ? 10.39300 1.43200 6.68200 1.000 87.00000 C ? A ? 191 1 + ATOM 1505 CD1 . LEU A 191 ? 9.10500 1.69600 5.90600 1.000 87.00000 C ? A ? 191 1 + ATOM 1506 CD2 . LEU A 191 ? 10.07500 1.54800 8.16700 1.000 87.00000 C ? A ? 191 1 + ATOM 1507 N . HIS A 192 ? 13.47300 -2.42800 7.51500 1.000 85.12000 N ? A ? 192 1 + ATOM 1508 CA . HIS A 192 ? 14.09200 -3.72800 7.25400 1.000 85.12000 C ? A ? 192 1 + ATOM 1509 C . HIS A 192 ? 13.09400 -4.89300 7.18200 1.000 85.12000 C ? A ? 192 1 + ATOM 1510 O . HIS A 192 ? 13.43700 -5.94800 6.66500 1.000 85.12000 O ? A ? 192 1 + ATOM 1511 CB . HIS A 192 ? 15.15100 -4.00000 8.32900 1.000 85.12000 C ? A ? 192 1 + ATOM 1512 CG . HIS A 192 ? 16.22200 -2.94000 8.39700 1.000 85.12000 C ? A ? 192 1 + ATOM 1513 ND1 . HIS A 192 ? 17.04400 -2.54600 7.36500 1.000 85.12000 N ? A ? 192 1 + ATOM 1514 CD2 . HIS A 192 ? 16.53800 -2.16500 9.48100 1.000 85.12000 C ? A ? 192 1 + ATOM 1515 CE1 . HIS A 192 ? 17.83400 -1.56000 7.81800 1.000 85.12000 C ? A ? 192 1 + ATOM 1516 NE2 . HIS A 192 ? 17.57000 -1.30000 9.10500 1.000 85.12000 N ? A ? 192 1 + ATOM 1517 N . HIS A 193 ? 11.86800 -4.73400 7.67200 1.000 91.50000 N ? A ? 193 1 + ATOM 1518 CA . HIS A 193 ? 10.83700 -5.77200 7.60100 1.000 91.50000 C ? A ? 193 1 + ATOM 1519 C . HIS A 193 ? 9.85000 -5.57500 6.44700 1.000 91.50000 C ? A ? 193 1 + ATOM 1520 O . HIS A 193 ? 9.00600 -6.44400 6.23100 1.000 91.50000 O ? A ? 193 1 + ATOM 1521 CB . HIS A 193 ? 10.15600 -5.88400 8.96500 1.000 91.50000 C ? A ? 193 1 + ATOM 1522 CG . HIS A 193 ? 11.12100 -6.38600 10.00900 1.000 91.50000 C ? A ? 193 1 + ATOM 1523 ND1 . HIS A 193 ? 11.47200 -7.69900 10.21500 1.000 91.50000 N ? A ? 193 1 + ATOM 1524 CD2 . HIS A 193 ? 11.83500 -5.63200 10.90100 1.000 91.50000 C ? A ? 193 1 + ATOM 1525 CE1 . HIS A 193 ? 12.36100 -7.73600 11.22100 1.000 91.50000 C ? A ? 193 1 + ATOM 1526 NE2 . HIS A 193 ? 12.62200 -6.49900 11.66900 1.000 91.50000 N ? A ? 193 1 + ATOM 1527 N . LEU A 194 ? 9.97100 -4.48100 5.68600 1.000 94.06000 N ? A ? 194 1 + ATOM 1528 CA . LEU A 194 ? 9.07500 -4.19700 4.57400 1.000 94.06000 C ? A ? 194 1 + ATOM 1529 C . LEU A 194 ? 9.32800 -5.18100 3.42700 1.000 94.06000 C ? A ? 194 1 + ATOM 1530 O . LEU A 194 ? 10.43400 -5.26200 2.89400 1.000 94.06000 O ? A ? 194 1 + ATOM 1531 CB . LEU A 194 ? 9.22600 -2.72900 4.13800 1.000 94.06000 C ? A ? 194 1 + ATOM 1532 CG . LEU A 194 ? 8.06000 -2.23900 3.26200 1.000 94.06000 C ? A ? 194 1 + ATOM 1533 CD1 . LEU A 194 ? 6.80300 -1.98700 4.09300 1.000 94.06000 C ? A ? 194 1 + ATOM 1534 CD2 . LEU A 194 ? 8.40100 -0.91100 2.58600 1.000 94.06000 C ? A ? 194 1 + ATOM 1535 N . GLN A 195 ? 8.28000 -5.90600 3.04700 1.000 96.12000 N ? A ? 195 1 + ATOM 1536 CA . GLN A 195 ? 8.28300 -6.91200 1.98400 1.000 96.12000 C ? A ? 195 1 + ATOM 1537 C . GLN A 195 ? 7.54800 -6.41900 0.73700 1.000 96.12000 C ? A ? 195 1 + ATOM 1538 O . GLN A 195 ? 7.97200 -6.71000 -0.38000 1.000 96.12000 O ? A ? 195 1 + ATOM 1539 CB . GLN A 195 ? 7.61200 -8.19100 2.50100 1.000 96.12000 C ? A ? 195 1 + ATOM 1540 CG . GLN A 195 ? 8.42500 -8.86700 3.61300 1.000 96.12000 C ? A ? 195 1 + ATOM 1541 CD . GLN A 195 ? 7.77700 -10.14700 4.12100 1.000 96.12000 C ? A ? 195 1 + ATOM 1542 OE1 . GLN A 195 ? 6.71000 -10.56600 3.71300 1.000 96.12000 O ? A ? 195 1 + ATOM 1543 NE2 . GLN A 195 ? 8.41300 -10.84500 5.03400 1.000 96.12000 N ? A ? 195 1 + ATOM 1544 N . VAL A 196 ? 6.47000 -5.65300 0.91900 1.000 97.12000 N ? A ? 196 1 + ATOM 1545 CA . VAL A 196 ? 5.61200 -5.17900 -0.17000 1.000 97.12000 C ? A ? 196 1 + ATOM 1546 C . VAL A 196 ? 5.52200 -3.66000 -0.13300 1.000 97.12000 C ? A ? 196 1 + ATOM 1547 O . VAL A 196 ? 5.09000 -3.07800 0.86500 1.000 97.12000 O ? A ? 196 1 + ATOM 1548 CB . VAL A 196 ? 4.21400 -5.82200 -0.11000 1.000 97.12000 C ? A ? 196 1 + ATOM 1549 CG1 . VAL A 196 ? 3.34100 -5.36700 -1.28500 1.000 97.12000 C ? A ? 196 1 + ATOM 1550 CG2 . VAL A 196 ? 4.29000 -7.35600 -0.13300 1.000 97.12000 C ? A ? 196 1 + ATOM 1551 N . LEU A 197 ? 5.89000 -3.02800 -1.24700 1.000 94.31000 N ? A ? 197 1 + ATOM 1552 CA . LEU A 197 ? 5.72200 -1.59500 -1.46300 1.000 94.31000 C ? A ? 197 1 + ATOM 1553 C . LEU A 197 ? 5.01500 -1.34500 -2.79800 1.000 94.31000 C ? A ? 197 1 + ATOM 1554 O . LEU A 197 ? 5.56700 -1.61300 -3.86600 1.000 94.31000 O ? A ? 197 1 + ATOM 1555 CB . LEU A 197 ? 7.09500 -0.90900 -1.37400 1.000 94.31000 C ? A ? 197 1 + ATOM 1556 CG . LEU A 197 ? 7.04900 0.61900 -1.56100 1.000 94.31000 C ? A ? 197 1 + ATOM 1557 CD1 . LEU A 197 ? 6.21200 1.31200 -0.48100 1.000 94.31000 C ? A ? 197 1 + ATOM 1558 CD2 . LEU A 197 ? 8.47200 1.17200 -1.49700 1.000 94.31000 C ? A ? 197 1 + ATOM 1559 N . ILE A 198 ? 3.80000 -0.80400 -2.72500 1.000 93.44000 N ? A ? 198 1 + ATOM 1560 CA . ILE A 198 ? 2.99100 -0.42400 -3.88600 1.000 93.44000 C ? A ? 198 1 + ATOM 1561 C . ILE A 198 ? 2.72900 1.08100 -3.82000 1.000 93.44000 C ? A ? 198 1 + ATOM 1562 O . ILE A 198 ? 2.22000 1.57400 -2.81700 1.000 93.44000 O ? A ? 198 1 + ATOM 1563 CB . ILE A 198 ? 1.69000 -1.25600 -3.96600 1.000 93.44000 C ? A ? 198 1 + ATOM 1564 CG1 . ILE A 198 ? 2.02200 -2.76700 -4.01700 1.000 93.44000 C ? A ? 198 1 + ATOM 1565 CG2 . ILE A 198 ? 0.84900 -0.81200 -5.17900 1.000 93.44000 C ? A ? 198 1 + ATOM 1566 CD1 . ILE A 198 ? 0.80400 -3.69200 -4.10900 1.000 93.44000 C ? A ? 198 1 + ATOM 1567 N . ILE A 199 ? 3.08900 1.81800 -4.87300 1.000 90.75000 N ? A ? 199 1 + ATOM 1568 CA . ILE A 199 ? 2.91000 3.27500 -4.96400 1.000 90.75000 C ? A ? 199 1 + ATOM 1569 C . ILE A 199 ? 2.39300 3.63500 -6.35200 1.000 90.75000 C ? A ? 199 1 + ATOM 1570 O . ILE A 199 ? 3.17800 3.74800 -7.29700 1.000 90.75000 O ? A ? 199 1 + ATOM 1571 CB . ILE A 199 ? 4.22500 4.03300 -4.68300 1.000 90.75000 C ? A ? 199 1 + ATOM 1572 CG1 . ILE A 199 ? 4.86200 3.64500 -3.33400 1.000 90.75000 C ? A ? 199 1 + ATOM 1573 CG2 . ILE A 199 ? 3.95700 5.55400 -4.73000 1.000 90.75000 C ? A ? 199 1 + ATOM 1574 CD1 . ILE A 199 ? 6.28500 4.18700 -3.20800 1.000 90.75000 C ? A ? 199 1 + ATOM 1575 N . TRP A 200 ? 1.08400 3.82300 -6.49000 1.000 90.06000 N ? A ? 200 1 + ATOM 1576 CA . TRP A 200 ? 0.43200 4.14000 -7.75900 1.000 90.06000 C ? A ? 200 1 + ATOM 1577 C . TRP A 200 ? -0.25000 5.50300 -7.70900 1.000 90.06000 C ? A ? 200 1 + ATOM 1578 O . TRP A 200 ? -0.89100 5.84300 -6.71900 1.000 90.06000 O ? A ? 200 1 + ATOM 1579 CB . TRP A 200 ? -0.55400 3.03000 -8.14800 1.000 90.06000 C ? A ? 200 1 + ATOM 1580 CG . TRP A 200 ? 0.02400 1.69800 -8.53900 1.000 90.06000 C ? A ? 200 1 + ATOM 1581 CD1 . TRP A 200 ? 1.30200 1.27600 -8.38900 1.000 90.06000 C ? A ? 200 1 + ATOM 1582 CD2 . TRP A 200 ? -0.65900 0.58200 -9.19400 1.000 90.06000 C ? A ? 200 1 + ATOM 1583 NE1 . TRP A 200 ? 1.43800 0.00200 -8.86400 1.000 90.06000 N ? A ? 200 1 + ATOM 1584 CE2 . TRP A 200 ? 0.26700 -0.48600 -9.36300 1.000 90.06000 C ? A ? 200 1 + ATOM 1585 CE3 . TRP A 200 ? -1.95900 0.35900 -9.68500 1.000 90.06000 C ? A ? 200 1 + ATOM 1586 CZ2 . TRP A 200 ? -0.06600 -1.71600 -9.94100 1.000 90.06000 C ? A ? 200 1 + ATOM 1587 CZ3 . TRP A 200 ? -2.30900 -0.86700 -10.28900 1.000 90.06000 C ? A ? 200 1 + ATOM 1588 CH2 . TRP A 200 ? -1.37400 -1.90900 -10.40300 1.000 90.06000 C ? A ? 200 1 + ATOM 1589 N . ALA A 201 ? -0.12600 6.29800 -8.77500 1.000 87.31000 N ? A ? 201 1 + ATOM 1590 CA . ALA A 201 ? -0.75300 7.62200 -8.86900 1.000 87.31000 C ? A ? 201 1 + ATOM 1591 C . ALA A 201 ? -0.45300 8.55200 -7.66100 1.000 87.31000 C ? A ? 201 1 + ATOM 1592 O . ALA A 201 ? -1.30200 9.32200 -7.21800 1.000 87.31000 O ? A ? 201 1 + ATOM 1593 CB . ALA A 201 ? -2.24500 7.44800 -9.20100 1.000 87.31000 C ? A ? 201 1 + ATOM 1594 N . CYS A 202 ? 0.78200 8.50300 -7.14100 1.000 87.25000 N ? A ? 202 1 + ATOM 1595 CA . CYS A 202 ? 1.27600 9.33600 -6.03100 1.000 87.25000 C ? A ? 202 1 + ATOM 1596 C . CYS A 202 ? 2.44600 10.24300 -6.48900 1.000 87.25000 C ? A ? 202 1 + ATOM 1597 O . CYS A 202 ? 3.58300 10.04900 -6.05100 1.000 87.25000 O ? A ? 202 1 + ATOM 1598 CB . CYS A 202 ? 1.67200 8.42900 -4.85600 1.000 87.25000 C ? A ? 202 1 + ATOM 1599 SG . CYS A 202 ? 0.21500 7.60600 -4.15500 1.000 87.25000 S ? A ? 202 1 + ATOM 1600 N . PRO A 203 ? 2.20300 11.23900 -7.36700 1.000 80.75000 N ? A ? 203 1 + ATOM 1601 CA . PRO A 203 ? 3.23700 12.02400 -8.05700 1.000 80.75000 C ? A ? 203 1 + ATOM 1602 C . PRO A 203 ? 4.22400 12.77100 -7.15000 1.000 80.75000 C ? A ? 203 1 + ATOM 1603 O . PRO A 203 ? 5.35000 13.03700 -7.56200 1.000 80.75000 O ? A ? 203 1 + ATOM 1604 CB . PRO A 203 ? 2.45700 13.04400 -8.90600 1.000 80.75000 C ? A ? 203 1 + ATOM 1605 CG . PRO A 203 ? 1.07900 13.11500 -8.25100 1.000 80.75000 C ? A ? 203 1 + ATOM 1606 CD . PRO A 203 ? 0.89100 11.67000 -7.81600 1.000 80.75000 C ? A ? 203 1 + ATOM 1607 N . ARG A 204 ? 3.81500 13.17100 -5.93700 1.000 80.62000 N ? A ? 204 1 + ATOM 1608 CA . ARG A 204 ? 4.65800 13.99200 -5.04700 1.000 80.62000 C ? A ? 204 1 + ATOM 1609 C . ARG A 204 ? 5.60400 13.14600 -4.19300 1.000 80.62000 C ? A ? 204 1 + ATOM 1610 O . ARG A 204 ? 6.74100 13.55900 -3.98300 1.000 80.62000 O ? A ? 204 1 + ATOM 1611 CB . ARG A 204 ? 3.78800 14.93000 -4.19800 1.000 80.62000 C ? A ? 204 1 + ATOM 1612 CG . ARG A 204 ? 2.93300 15.89100 -5.03400 1.000 80.62000 C ? A ? 204 1 + ATOM 1613 CD . ARG A 204 ? 2.07400 16.79000 -4.13400 1.000 80.62000 C ? A ? 204 1 + ATOM 1614 NE . ARG A 204 ? 2.74900 18.06200 -3.80900 1.000 80.62000 N ? A ? 204 1 + ATOM 1615 CZ . ARG A 204 ? 2.23900 19.03200 -3.07300 1.000 80.62000 C ? A ? 204 1 + ATOM 1616 NH1 . ARG A 204 ? 1.11200 18.89800 -2.43400 1.000 80.62000 N ? A ? 204 1 + ATOM 1617 NH2 . ARG A 204 ? 2.85800 20.17400 -2.97600 1.000 80.62000 N ? A ? 204 1 + ATOM 1618 N . VAL A 205 ? 5.17500 11.94400 -3.79100 1.000 78.25000 N ? A ? 205 1 + ATOM 1619 CA . VAL A 205 ? 5.96200 10.98900 -2.98900 1.000 78.25000 C ? A ? 205 1 + ATOM 1620 C . VAL A 205 ? 7.30600 10.66300 -3.63300 1.000 78.25000 C ? A ? 205 1 + ATOM 1621 O . VAL A 205 ? 8.31900 10.51800 -2.94800 1.000 78.25000 O ? A ? 205 1 + ATOM 1622 CB . VAL A 205 ? 5.17500 9.67100 -2.80700 1.000 78.25000 C ? A ? 205 1 + ATOM 1623 CG1 . VAL A 205 ? 6.05800 8.53700 -2.29000 1.000 78.25000 C ? A ? 205 1 + ATOM 1624 CG2 . VAL A 205 ? 4.02700 9.85600 -1.82300 1.000 78.25000 C ? A ? 205 1 + ATOM 1625 N . GLN A 206 ? 7.32300 10.51700 -4.95000 1.000 65.75000 N ? A ? 206 1 + ATOM 1626 CA . GLN A 206 ? 8.40800 9.84300 -5.65800 1.000 65.75000 C ? A ? 206 1 + ATOM 1627 C . GLN A 206 ? 9.71900 10.65100 -5.67300 1.000 65.75000 C ? A ? 206 1 + ATOM 1628 O . GLN A 206 ? 10.79400 10.05200 -5.69100 1.000 65.75000 O ? A ? 206 1 + ATOM 1629 CB . GLN A 206 ? 7.87300 9.45800 -7.04300 1.000 65.75000 C ? A ? 206 1 + ATOM 1630 CG . GLN A 206 ? 6.82800 8.32200 -6.91000 1.000 65.75000 C ? A ? 206 1 + ATOM 1631 CD . GLN A 206 ? 5.88000 8.19100 -8.09500 1.000 65.75000 C ? A ? 206 1 + ATOM 1632 OE1 . GLN A 206 ? 5.73800 9.07700 -8.91100 1.000 65.75000 O ? A ? 206 1 + ATOM 1633 NE2 . GLN A 206 ? 5.12500 7.11300 -8.16800 1.000 65.75000 N ? A ? 206 1 + ATOM 1634 N . ASN A 207 ? 9.65900 11.97700 -5.47500 1.000 64.25000 N ? A ? 207 1 + ATOM 1635 CA . ASN A 207 ? 10.84200 12.82900 -5.25800 1.000 64.25000 C ? A ? 207 1 + ATOM 1636 C . ASN A 207 ? 11.64400 12.45000 -3.99700 1.000 64.25000 C ? A ? 207 1 + ATOM 1637 O . ASN A 207 ? 12.80900 12.81700 -3.87600 1.000 64.25000 O ? A ? 207 1 + ATOM 1638 CB . ASN A 207 ? 10.38800 14.29700 -5.14900 1.000 64.25000 C ? A ? 207 1 + ATOM 1639 CG . ASN A 207 ? 9.87600 14.88100 -6.45000 1.000 64.25000 C ? A ? 207 1 + ATOM 1640 OD1 . ASN A 207 ? 10.15200 14.41900 -7.53900 1.000 64.25000 O ? A ? 207 1 + ATOM 1641 ND2 . ASN A 207 ? 9.11300 15.94500 -6.38000 1.000 64.25000 N ? A ? 207 1 + ATOM 1642 N . SER A 208 ? 11.02700 11.73900 -3.04600 1.000 65.06000 N ? A ? 208 1 + ATOM 1643 CA . SER A 208 ? 11.67900 11.32000 -1.79700 1.000 65.06000 C ? A ? 208 1 + ATOM 1644 C . SER A 208 ? 12.40700 9.97400 -1.88300 1.000 65.06000 C ? A ? 208 1 + ATOM 1645 O . SER A 208 ? 13.20700 9.67500 -0.99900 1.000 65.06000 O ? A ? 208 1 + ATOM 1646 CB . SER A 208 ? 10.68100 11.34600 -0.63100 1.000 65.06000 C ? A ? 208 1 + ATOM 1647 OG . SER A 208 ? 9.65700 10.37100 -0.72900 1.000 65.06000 O ? A ? 208 1 + ATOM 1648 N . ILE A 209 ? 12.16100 9.17800 -2.93400 1.000 69.88000 N ? A ? 209 1 + ATOM 1649 CA . ILE A 209 ? 12.76800 7.84700 -3.09800 1.000 69.88000 C ? A ? 209 1 + ATOM 1650 C . ILE A 209 ? 14.21700 7.97900 -3.59300 1.000 69.88000 C ? A ? 209 1 + ATOM 1651 O . ILE A 209 ? 15.11100 7.42800 -2.95700 1.000 69.88000 O ? A ? 209 1 + ATOM 1652 CB . ILE A 209 ? 11.88500 6.95400 -4.00100 1.000 69.88000 C ? A ? 209 1 + ATOM 1653 CG1 . ILE A 209 ? 10.48500 6.74900 -3.36800 1.000 69.88000 C ? A ? 209 1 + ATOM 1654 CG2 . ILE A 209 ? 12.55600 5.59200 -4.24600 1.000 69.88000 C ? A ? 209 1 + ATOM 1655 CD1 . ILE A 209 ? 9.47600 6.03700 -4.27800 1.000 69.88000 C ? A ? 209 1 + ATOM 1656 N . GLY A 210 ? 14.43600 8.75700 -4.66600 1.000 63.94000 N ? A ? 210 1 + ATOM 1657 CA . GLY A 210 ? 15.73500 9.21700 -5.20500 1.000 63.94000 C ? A ? 210 1 + ATOM 1658 C . GLY A 210 ? 16.99000 8.39400 -4.85700 1.000 63.94000 C ? A ? 210 1 + ATOM 1659 O . GLY A 210 ? 16.99700 7.16600 -4.95000 1.000 63.94000 O ? A ? 210 1 + ATOM 1660 N . GLU A 211 ? 18.05800 9.08600 -4.43700 1.000 57.47000 N ? A ? 211 1 + ATOM 1661 CA . GLU A 211 ? 19.36000 8.50200 -4.05400 1.000 57.47000 C ? A ? 211 1 + ATOM 1662 C . GLU A 211 ? 19.28300 7.54000 -2.85100 1.000 57.47000 C ? A ? 211 1 + ATOM 1663 O . GLU A 211 ? 20.17500 6.71100 -2.65000 1.000 57.47000 O ? A ? 211 1 + ATOM 1664 CB . GLU A 211 ? 20.34100 9.63400 -3.68500 1.000 57.47000 C ? A ? 211 1 + ATOM 1665 CG . GLU A 211 ? 20.69700 10.58300 -4.84300 1.000 57.47000 C ? A ? 211 1 + ATOM 1666 CD . GLU A 211 ? 21.71700 11.66600 -4.43200 1.000 57.47000 C ? A ? 211 1 + ATOM 1667 OE1 . GLU A 211 ? 22.29200 12.30300 -5.34200 1.000 57.47000 O ? A ? 211 1 + ATOM 1668 OE2 . GLU A 211 ? 21.90600 11.87000 -3.20900 1.000 57.47000 O ? A ? 211 1 + ATOM 1669 N . ARG A 212 ? 18.21900 7.63300 -2.03900 1.000 70.56000 N ? A ? 212 1 + ATOM 1670 CA . ARG A 212 ? 18.05000 6.84200 -0.80800 1.000 70.56000 C ? A ? 212 1 + ATOM 1671 C . ARG A 212 ? 17.72800 5.37500 -1.10700 1.000 70.56000 C ? A ? 212 1 + ATOM 1672 O . ARG A 212 ? 18.11200 4.50000 -0.33400 1.000 70.56000 O ? A ? 212 1 + ATOM 1673 CB . ARG A 212 ? 16.97000 7.47700 0.08600 1.000 70.56000 C ? A ? 212 1 + ATOM 1674 CG . ARG A 212 ? 17.32200 8.90300 0.54300 1.000 70.56000 C ? A ? 212 1 + ATOM 1675 CD . ARG A 212 ? 16.29300 9.41600 1.56200 1.000 70.56000 C ? A ? 212 1 + ATOM 1676 NE . ARG A 212 ? 16.53200 10.83500 1.91000 1.000 70.56000 N ? A ? 212 1 + ATOM 1677 CZ . ARG A 212 ? 16.41500 11.40200 3.10200 1.000 70.56000 C ? A ? 212 1 + ATOM 1678 NH1 . ARG A 212 ? 16.13400 10.74200 4.18700 1.000 70.56000 N ? A ? 212 1 + ATOM 1679 NH2 . ARG A 212 ? 16.56600 12.68800 3.25300 1.000 70.56000 N ? A ? 212 1 + ATOM 1680 N . GLY A 213 ? 17.07500 5.10600 -2.23800 1.000 78.00000 N ? A ? 213 1 + ATOM 1681 CA . GLY A 213 ? 16.69700 3.76200 -2.66500 1.000 78.00000 C ? A ? 213 1 + ATOM 1682 C . GLY A 213 ? 15.58600 3.13700 -1.81400 1.000 78.00000 C ? A ? 213 1 + ATOM 1683 O . GLY A 213 ? 14.82600 3.82300 -1.13100 1.000 78.00000 O ? A ? 213 1 + ATOM 1684 N . PHE A 214 ? 15.48400 1.81000 -1.88100 1.000 86.88000 N ? A ? 214 1 + ATOM 1685 CA . PHE A 214 ? 14.44200 1.01900 -1.22200 1.000 86.88000 C ? A ? 214 1 + ATOM 1686 C . PHE A 214 ? 15.01300 0.09400 -0.13500 1.000 86.88000 C ? A ? 214 1 + ATOM 1687 O . PHE A 214 ? 16.20000 -0.24100 -0.19500 1.000 86.88000 O ? A ? 214 1 + ATOM 1688 CB . PHE A 214 ? 13.71300 0.18300 -2.27600 1.000 86.88000 C ? A ? 214 1 + ATOM 1689 CG . PHE A 214 ? 13.00700 0.97400 -3.34400 1.000 86.88000 C ? A ? 214 1 + ATOM 1690 CD1 . PHE A 214 ? 11.78700 1.61000 -3.05500 1.000 86.88000 C ? A ? 214 1 + ATOM 1691 CD2 . PHE A 214 ? 13.56800 1.06400 -4.62800 1.000 86.88000 C ? A ? 214 1 + ATOM 1692 CE1 . PHE A 214 ? 11.13700 2.35700 -4.04900 1.000 86.88000 C ? A ? 214 1 + ATOM 1693 CE2 . PHE A 214 ? 12.90900 1.79800 -5.62100 1.000 86.88000 C ? A ? 214 1 + ATOM 1694 CZ . PHE A 214 ? 11.71100 2.46200 -5.32900 1.000 86.88000 C ? A ? 214 1 + ATOM 1695 N . PRO A 215 ? 14.18000 -0.38000 0.81400 1.000 87.44000 N ? A ? 215 1 + ATOM 1696 CA . PRO A 215 ? 14.57500 -1.44600 1.73000 1.000 87.44000 C ? A ? 215 1 + ATOM 1697 C . PRO A 215 ? 14.99000 -2.71700 0.97800 1.000 87.44000 C ? A ? 215 1 + ATOM 1698 O . PRO A 215 ? 14.32400 -3.14400 0.03800 1.000 87.44000 O ? A ? 215 1 + ATOM 1699 CB . PRO A 215 ? 13.37800 -1.73100 2.63900 1.000 87.44000 C ? A ? 215 1 + ATOM 1700 CG . PRO A 215 ? 12.32000 -0.69000 2.29200 1.000 87.44000 C ? A ? 215 1 + ATOM 1701 CD . PRO A 215 ? 12.80400 0.03700 1.04300 1.000 87.44000 C ? A ? 215 1 + ATOM 1702 N . THR A 216 ? 16.06500 -3.36700 1.42300 1.000 87.50000 N ? A ? 216 1 + ATOM 1703 CA . THR A 216 ? 16.66100 -4.52700 0.73300 1.000 87.50000 C ? A ? 216 1 + ATOM 1704 C . THR A 216 ? 15.83800 -5.81300 0.82500 1.000 87.50000 C ? A ? 216 1 + ATOM 1705 O . THR A 216 ? 16.03600 -6.70900 0.00800 1.000 87.50000 O ? A ? 216 1 + ATOM 1706 CB . THR A 216 ? 18.07000 -4.80700 1.27100 1.000 87.50000 C ? A ? 216 1 + ATOM 1707 OG1 . THR A 216 ? 18.03100 -4.94100 2.67800 1.000 87.50000 O ? A ? 216 1 + ATOM 1708 CG2 . THR A 216 ? 19.03400 -3.66700 0.93700 1.000 87.50000 C ? A ? 216 1 + ATOM 1709 N . ASN A 217 ? 14.92400 -5.90800 1.79500 1.000 91.50000 N ? A ? 217 1 + ATOM 1710 CA . ASN A 217 ? 14.10800 -7.10000 2.05800 1.000 91.50000 C ? A ? 217 1 + ATOM 1711 C . ASN A 217 ? 12.78100 -7.12400 1.28100 1.000 91.50000 C ? A ? 217 1 + ATOM 1712 O . ASN A 217 ? 11.96600 -8.02300 1.49100 1.000 91.50000 O ? A ? 217 1 + ATOM 1713 CB . ASN A 217 ? 13.93000 -7.25800 3.58000 1.000 91.50000 C ? A ? 217 1 + ATOM 1714 CG . ASN A 217 ? 15.21700 -7.66400 4.28200 1.000 91.50000 C ? A ? 217 1 + ATOM 1715 OD1 . ASN A 217 ? 16.21600 -8.02900 3.68700 1.000 91.50000 O ? A ? 217 1 + ATOM 1716 ND2 . ASN A 217 ? 15.26600 -7.60400 5.58500 1.000 91.50000 N ? A ? 217 1 + ATOM 1717 N . LEU A 218 ? 12.57700 -6.16800 0.36800 1.000 94.50000 N ? A ? 218 1 + ATOM 1718 CA . LEU A 218 ? 11.41700 -6.15700 -0.51400 1.000 94.50000 C ? A ? 218 1 + ATOM 1719 C . LEU A 218 ? 11.38200 -7.41100 -1.39000 1.000 94.50000 C ? A ? 218 1 + ATOM 1720 O . LEU A 218 ? 12.34100 -7.72200 -2.09700 1.000 94.50000 O ? A ? 218 1 + ATOM 1721 CB . LEU A 218 ? 11.42700 -4.90500 -1.40100 1.000 94.50000 C ? A ? 218 1 + ATOM 1722 CG . LEU A 218 ? 11.03600 -3.60200 -0.68600 1.000 94.50000 C ? A ? 218 1 + ATOM 1723 CD1 . LEU A 218 ? 11.18000 -2.46700 -1.69400 1.000 94.50000 C ? A ? 218 1 + ATOM 1724 CD2 . LEU A 218 ? 9.58600 -3.60500 -0.20300 1.000 94.50000 C ? A ? 218 1 + ATOM 1725 N . THR A 219 ? 10.23300 -8.07800 -1.38300 1.000 96.88000 N ? A ? 219 1 + ATOM 1726 CA . THR A 219 ? 9.88900 -9.17800 -2.28700 1.000 96.88000 C ? A ? 219 1 + ATOM 1727 C . THR A 219 ? 9.01000 -8.69200 -3.43400 1.000 96.88000 C ? A ? 219 1 + ATOM 1728 O . THR A 219 ? 9.11300 -9.20700 -4.54500 1.000 96.88000 O ? A ? 219 1 + ATOM 1729 CB . THR A 219 ? 9.18600 -10.31000 -1.52900 1.000 96.88000 C ? A ? 219 1 + ATOM 1730 OG1 . THR A 219 ? 7.99600 -9.84000 -0.93800 1.000 96.88000 O ? A ? 219 1 + ATOM 1731 CG2 . THR A 219 ? 10.05500 -10.88000 -0.40800 1.000 96.88000 C ? A ? 219 1 + ATOM 1732 N . SER A 220 ? 8.20800 -7.64800 -3.20600 1.000 97.44000 N ? A ? 220 1 + ATOM 1733 CA . SER A 220 ? 7.32300 -7.05900 -4.20600 1.000 97.44000 C ? A ? 220 1 + ATOM 1734 C . SER A 220 ? 7.43300 -5.53800 -4.22600 1.000 97.44000 C ? A ? 220 1 + ATOM 1735 O . SER A 220 ? 7.23000 -4.86600 -3.21100 1.000 97.44000 O ? A ? 220 1 + ATOM 1736 CB . SER A 220 ? 5.88900 -7.50000 -3.92700 1.000 97.44000 C ? A ? 220 1 + ATOM 1737 OG . SER A 220 ? 5.02600 -7.03100 -4.94000 1.000 97.44000 O ? A ? 220 1 + ATOM 1738 N . LEU A 221 ? 7.74100 -4.99600 -5.40300 1.000 94.25000 N ? A ? 221 1 + ATOM 1739 CA . LEU A 221 ? 7.82000 -3.56300 -5.65700 1.000 94.25000 C ? A ? 221 1 + ATOM 1740 C . LEU A 221 ? 6.95700 -3.21400 -6.86400 1.000 94.25000 C ? A ? 221 1 + ATOM 1741 O . LEU A 221 ? 7.17400 -3.71700 -7.96500 1.000 94.25000 O ? A ? 221 1 + ATOM 1742 CB . LEU A 221 ? 9.29000 -3.16200 -5.86400 1.000 94.25000 C ? A ? 221 1 + ATOM 1743 CG . LEU A 221 ? 9.50600 -1.65600 -6.09100 1.000 94.25000 C ? A ? 221 1 + ATOM 1744 CD1 . LEU A 221 ? 9.01000 -0.84000 -4.89700 1.000 94.25000 C ? A ? 221 1 + ATOM 1745 CD2 . LEU A 221 ? 10.99600 -1.37800 -6.28600 1.000 94.25000 C ? A ? 221 1 + ATOM 1746 N . SER A 222 ? 5.99700 -2.31800 -6.67400 1.000 92.62000 N ? A ? 222 1 + ATOM 1747 CA . SER A 222 ? 5.14500 -1.84200 -7.75600 1.000 92.62000 C ? A ? 222 1 + ATOM 1748 C . SER A 222 ? 5.03900 -0.33100 -7.72000 1.000 92.62000 C ? A ? 222 1 + ATOM 1749 O . SER A 222 ? 4.56500 0.24200 -6.74000 1.000 92.62000 O ? A ? 222 1 + ATOM 1750 CB . SER A 222 ? 3.77400 -2.48600 -7.64600 1.000 92.62000 C ? A ? 222 1 + ATOM 1751 OG . SER A 222 ? 3.04500 -2.22400 -8.81900 1.000 92.62000 O ? A ? 222 1 + ATOM 1752 N . ILE A 223 ? 5.49000 0.32500 -8.78400 1.000 87.12000 N ? A ? 223 1 + ATOM 1753 CA . ILE A 223 ? 5.50500 1.78100 -8.86100 1.000 87.12000 C ? A ? 223 1 + ATOM 1754 C . ILE A 223 ? 4.89400 2.23100 -10.18400 1.000 87.12000 C ? A ? 223 1 + ATOM 1755 O . ILE A 223 ? 5.36900 1.87100 -11.26400 1.000 87.12000 O ? A ? 223 1 + ATOM 1756 CB . ILE A 223 ? 6.92200 2.34900 -8.61900 1.000 87.12000 C ? A ? 223 1 + ATOM 1757 CG1 . ILE A 223 ? 7.47300 1.86900 -7.25800 1.000 87.12000 C ? A ? 223 1 + ATOM 1758 CG2 . ILE A 223 ? 6.82800 3.88400 -8.63700 1.000 87.12000 C ? A ? 223 1 + ATOM 1759 CD1 . ILE A 223 ? 8.90300 2.30700 -6.97200 1.000 87.12000 C ? A ? 223 1 + ATOM 1760 N . ASP A 224 ? 3.86200 3.06700 -10.07900 1.000 82.62000 N ? A ? 224 1 + ATOM 1761 CA . ASP A 224 ? 3.31300 3.82700 -11.19700 1.000 82.62000 C ? A ? 224 1 + ATOM 1762 C . ASP A 224 ? 3.68200 5.30000 -11.03300 1.000 82.62000 C ? A ? 224 1 + ATOM 1763 O . ASP A 224 ? 3.24200 5.97300 -10.09300 1.000 82.62000 O ? A ? 224 1 + ATOM 1764 CB . ASP A 224 ? 1.80400 3.58100 -11.33900 1.000 82.62000 C ? A ? 224 1 + ATOM 1765 CG . ASP A 224 ? 1.21300 4.14000 -12.63200 1.000 82.62000 C ? A ? 224 1 + ATOM 1766 OD1 . ASP A 224 ? 1.90400 4.89500 -13.35000 1.000 82.62000 O ? A ? 224 1 + ATOM 1767 OD2 . ASP A 224 ? 0.07900 3.74000 -12.96600 1.000 82.62000 O ? A ? 224 1 + ATOM 1768 N . ASP A 225 ? 4.57000 5.76700 -11.90900 1.000 63.81000 N ? A ? 225 1 + ATOM 1769 CA . ASP A 225 ? 5.28800 7.02000 -11.73800 1.000 63.81000 C ? A ? 225 1 + ATOM 1770 C . ASP A 225 ? 5.08100 7.96200 -12.93800 1.000 63.81000 C ? A ? 225 1 + ATOM 1771 O . ASP A 225 ? 5.55100 7.71100 -14.05800 1.000 63.81000 O ? A ? 225 1 + ATOM 1772 CB . ASP A 225 ? 6.74700 6.70300 -11.46500 1.000 63.81000 C ? A ? 225 1 + ATOM 1773 CG . ASP A 225 ? 7.63000 7.90700 -11.10700 1.000 63.81000 C ? A ? 225 1 + ATOM 1774 OD1 . ASP A 225 ? 7.26800 9.03600 -11.48000 1.000 63.81000 O ? A ? 225 1 + ATOM 1775 OD2 . ASP A 225 ? 8.72500 7.69400 -10.54500 1.000 63.81000 O ? A ? 225 1 + ATOM 1776 N . PRO A 226 ? 4.39900 9.09400 -12.70300 1.000 56.66000 N ? A ? 226 1 + ATOM 1777 CA . PRO A 226 ? 4.22900 10.15000 -13.68200 1.000 56.66000 C ? A ? 226 1 + ATOM 1778 C . PRO A 226 ? 5.43900 11.10500 -13.83600 1.000 56.66000 C ? A ? 226 1 + ATOM 1779 O . PRO A 226 ? 5.26400 12.12300 -14.49000 1.000 56.66000 O ? A ? 226 1 + ATOM 1780 CB . PRO A 226 ? 2.93800 10.86200 -13.25700 1.000 56.66000 C ? A ? 226 1 + ATOM 1781 CG . PRO A 226 ? 2.94400 10.71200 -11.74600 1.000 56.66000 C ? A ? 226 1 + ATOM 1782 CD . PRO A 226 ? 3.55400 9.33900 -11.54200 1.000 56.66000 C ? A ? 226 1 + ATOM 1783 N . ASN A 227 ? 6.64000 10.84000 -13.31300 1.000 58.66000 N ? A ? 227 1 + ATOM 1784 CA . ASN A 227 ? 7.86500 11.66300 -13.44000 1.000 58.66000 C ? A ? 227 1 + ATOM 1785 C . ASN A 227 ? 9.20500 10.86200 -13.39400 1.000 58.66000 C ? A ? 227 1 + ATOM 1786 O . ASN A 227 ? 10.27500 11.43300 -13.18000 1.000 58.66000 O ? A ? 227 1 + ATOM 1787 CB . ASN A 227 ? 7.83400 12.76500 -12.36100 1.000 58.66000 C ? A ? 227 1 + ATOM 1788 CG . ASN A 227 ? 6.87900 13.90100 -12.67700 1.000 58.66000 C ? A ? 227 1 + ATOM 1789 OD1 . ASN A 227 ? 6.78200 14.40500 -13.78300 1.000 58.66000 O ? A ? 227 1 + ATOM 1790 ND2 . ASN A 227 ? 6.17500 14.39800 -11.68700 1.000 58.66000 N ? A ? 227 1 + ATOM 1791 N . ILE A 228 ? 9.18700 9.55000 -13.65100 1.000 61.81000 N ? A ? 228 1 + ATOM 1792 CA . ILE A 228 ? 10.27400 8.58400 -13.36200 1.000 61.81000 C ? A ? 228 1 + ATOM 1793 C . ILE A 228 ? 11.60400 8.72800 -14.13200 1.000 61.81000 C ? A ? 228 1 + ATOM 1794 O . ILE A 228 ? 12.50500 7.90400 -13.95100 1.000 61.81000 O ? A ? 228 1 + ATOM 1795 CB . ILE A 228 ? 9.68300 7.17100 -13.56300 1.000 61.81000 C ? A ? 228 1 + ATOM 1796 CG1 . ILE A 228 ? 10.37000 6.08600 -12.72400 1.000 61.81000 C ? A ? 228 1 + ATOM 1797 CG2 . ILE A 228 ? 9.61000 6.74900 -15.03800 1.000 61.81000 C ? A ? 228 1 + ATOM 1798 CD1 . ILE A 228 ? 9.40800 4.94300 -12.34100 1.000 61.81000 C ? A ? 228 1 + ATOM 1799 N . SER A 229 ? 11.75100 9.70700 -15.03400 1.000 58.00000 N ? A ? 229 1 + ATOM 1800 CA . SER A 229 ? 12.75800 9.64400 -16.11100 1.000 58.00000 C ? A ? 229 1 + ATOM 1801 C . SER A 229 ? 14.21200 9.56400 -15.62900 1.000 58.00000 C ? A ? 229 1 + ATOM 1802 O . SER A 229 ? 15.01900 8.90500 -16.28400 1.000 58.00000 O ? A ? 229 1 + ATOM 1803 CB . SER A 229 ? 12.58900 10.78600 -17.12400 1.000 58.00000 C ? A ? 229 1 + ATOM 1804 OG . SER A 229 ? 12.94600 12.04200 -16.58500 1.000 58.00000 O ? A ? 229 1 + ATOM 1805 N . LYS A 230 ? 14.53300 10.16400 -14.47400 1.000 59.12000 N ? A ? 230 1 + ATOM 1806 CA . LYS A 230 ? 15.85900 10.06700 -13.83100 1.000 59.12000 C ? A ? 230 1 + ATOM 1807 C . LYS A 230 ? 15.88100 9.14200 -12.61000 1.000 59.12000 C ? A ? 230 1 + ATOM 1808 O . LYS A 230 ? 16.84000 8.40000 -12.43400 1.000 59.12000 O ? A ? 230 1 + ATOM 1809 CB . LYS A 230 ? 16.38100 11.46700 -13.48100 1.000 59.12000 C ? A ? 230 1 + ATOM 1810 CG . LYS A 230 ? 16.66200 12.29600 -14.74400 1.000 59.12000 C ? A ? 230 1 + ATOM 1811 CD . LYS A 230 ? 17.28600 13.64300 -14.37000 1.000 59.12000 C ? A ? 230 1 + ATOM 1812 CE . LYS A 230 ? 17.54900 14.45900 -15.63800 1.000 59.12000 C ? A ? 230 1 + ATOM 1813 NZ . LYS A 230 ? 18.17000 15.76200 -15.30000 1.000 59.12000 N ? A ? 230 1 + ATOM 1814 N . ALA A 231 ? 14.81000 9.11900 -11.81600 1.000 62.19000 N ? A ? 231 1 + ATOM 1815 CA . ALA A 231 ? 14.79100 8.43400 -10.52300 1.000 62.19000 C ? A ? 231 1 + ATOM 1816 C . ALA A 231 ? 14.93400 6.90400 -10.63300 1.000 62.19000 C ? A ? 231 1 + ATOM 1817 O . ALA A 231 ? 15.69700 6.31500 -9.87100 1.000 62.19000 O ? A ? 231 1 + ATOM 1818 CB . ALA A 231 ? 13.50800 8.83600 -9.78700 1.000 62.19000 C ? A ? 231 1 + ATOM 1819 N . VAL A 232 ? 14.29400 6.25300 -11.62000 1.000 65.38000 N ? A ? 232 1 + ATOM 1820 CA . VAL A 232 ? 14.42900 4.78800 -11.81400 1.000 65.38000 C ? A ? 232 1 + ATOM 1821 C . VAL A 232 ? 15.87000 4.34100 -11.98200 1.000 65.38000 C ? A ? 232 1 + ATOM 1822 O . VAL A 232 ? 16.23800 3.24200 -11.56200 1.000 65.38000 O ? A ? 232 1 + ATOM 1823 CB . VAL A 232 ? 13.59500 4.29800 -13.01800 1.000 65.38000 C ? A ? 232 1 + ATOM 1824 CG1 . VAL A 232 ? 14.17200 3.19400 -13.91200 1.000 65.38000 C ? A ? 232 1 + ATOM 1825 CG2 . VAL A 232 ? 12.35300 3.64900 -12.45600 1.000 65.38000 C ? A ? 232 1 + ATOM 1826 N . MET A 233 ? 16.68100 5.19800 -12.59300 1.000 63.69000 N ? A ? 233 1 + ATOM 1827 CA . MET A 233 ? 18.07500 4.91200 -12.89400 1.000 63.69000 C ? A ? 233 1 + ATOM 1828 C . MET A 233 ? 18.95100 4.96100 -11.63200 1.000 63.69000 C ? A ? 233 1 + ATOM 1829 O . MET A 233 ? 19.98500 4.30000 -11.58700 1.000 63.69000 O ? A ? 233 1 + ATOM 1830 CB . MET A 233 ? 18.55900 5.89800 -13.96900 1.000 63.69000 C ? A ? 233 1 + ATOM 1831 CG . MET A 233 ? 17.67600 5.89800 -15.23400 1.000 63.69000 C ? A ? 233 1 + ATOM 1832 SD . MET A 233 ? 17.58400 4.32100 -16.13600 1.000 63.69000 S ? A ? 233 1 + ATOM 1833 CE . MET A 233 ? 19.25000 4.33000 -16.83200 1.000 63.69000 C ? A ? 233 1 + ATOM 1834 N . GLU A 234 ? 18.51300 5.67900 -10.59400 1.000 69.19000 N ? A ? 234 1 + ATOM 1835 CA . GLU A 234 ? 19.24900 5.92400 -9.34500 1.000 69.19000 C ? A ? 234 1 + ATOM 1836 C . GLU A 234 ? 18.81500 5.00400 -8.19000 1.000 69.19000 C ? A ? 234 1 + ATOM 1837 O . GLU A 234 ? 19.51900 4.88000 -7.18900 1.000 69.19000 O ? A ? 234 1 + ATOM 1838 CB . GLU A 234 ? 19.08100 7.40200 -8.95800 1.000 69.19000 C ? A ? 234 1 + ATOM 1839 CG . GLU A 234 ? 19.78700 8.33900 -9.95600 1.000 69.19000 C ? A ? 234 1 + ATOM 1840 CD . GLU A 234 ? 19.47100 9.82700 -9.73100 1.000 69.19000 C ? A ? 234 1 + ATOM 1841 OE1 . GLU A 234 ? 19.98600 10.64100 -10.53500 1.000 69.19000 O ? A ? 234 1 + ATOM 1842 OE2 . GLU A 234 ? 18.67000 10.14200 -8.82000 1.000 69.19000 O ? A ? 234 1 + ATOM 1843 N . TRP A 235 ? 17.70100 4.27700 -8.32700 1.000 77.12000 N ? A ? 235 1 + ATOM 1844 CA . TRP A 235 ? 17.15800 3.43800 -7.24800 1.000 77.12000 C ? A ? 235 1 + ATOM 1845 C . TRP A 235 ? 18.06600 2.28000 -6.81400 1.000 77.12000 C ? A ? 235 1 + ATOM 1846 O . TRP A 235 ? 17.92900 1.74600 -5.70800 1.000 77.12000 O ? A ? 235 1 + ATOM 1847 CB . TRP A 235 ? 15.79300 2.90700 -7.69100 1.000 77.12000 C ? A ? 235 1 + ATOM 1848 CG . TRP A 235 ? 14.69800 3.92600 -7.78300 1.000 77.12000 C ? A ? 235 1 + ATOM 1849 CD1 . TRP A 235 ? 14.72100 5.17800 -7.26500 1.000 77.12000 C ? A ? 235 1 + ATOM 1850 CD2 . TRP A 235 ? 13.38100 3.78200 -8.39700 1.000 77.12000 C ? A ? 235 1 + ATOM 1851 NE1 . TRP A 235 ? 13.53000 5.81700 -7.53500 1.000 77.12000 N ? A ? 235 1 + ATOM 1852 CE2 . TRP A 235 ? 12.65900 4.99800 -8.21300 1.000 77.12000 C ? A ? 235 1 + ATOM 1853 CE3 . TRP A 235 ? 12.71600 2.73300 -9.07100 1.000 77.12000 C ? A ? 235 1 + ATOM 1854 CZ2 . TRP A 235 ? 11.34900 5.17200 -8.67100 1.000 77.12000 C ? A ? 235 1 + ATOM 1855 CZ3 . TRP A 235 ? 11.38400 2.88000 -9.49600 1.000 77.12000 C ? A ? 235 1 + ATOM 1856 CH2 . TRP A 235 ? 10.70700 4.09700 -9.30200 1.000 77.12000 C ? A ? 235 1 + ATOM 1857 N . GLY A 236 ? 19.00900 1.87000 -7.66400 1.000 78.75000 N ? A ? 236 1 + ATOM 1858 CA . GLY A 236 ? 19.91000 0.76100 -7.36200 1.000 78.75000 C ? A ? 236 1 + ATOM 1859 C . GLY A 236 ? 19.15500 -0.55000 -7.11500 1.000 78.75000 C ? A ? 236 1 + ATOM 1860 O . GLY A 236 ? 19.46100 -1.25700 -6.15700 1.000 78.75000 O ? A ? 236 1 + ATOM 1861 N . LEU A 237 ? 18.17700 -0.86800 -7.97700 1.000 84.50000 N ? A ? 237 1 + ATOM 1862 CA . LEU A 237 ? 17.31500 -2.06000 -7.87300 1.000 84.50000 C ? A ? 237 1 + ATOM 1863 C . LEU A 237 ? 18.09700 -3.37800 -7.76900 1.000 84.50000 C ? A ? 237 1 + ATOM 1864 O . LEU A 237 ? 17.62400 -4.32600 -7.15600 1.000 84.50000 O ? A ? 237 1 + ATOM 1865 CB . LEU A 237 ? 16.38000 -2.13700 -9.09500 1.000 84.50000 C ? A ? 237 1 + ATOM 1866 CG . LEU A 237 ? 15.34900 -1.00200 -9.22500 1.000 84.50000 C ? A ? 237 1 + ATOM 1867 CD1 . LEU A 237 ? 14.51800 -1.22700 -10.48600 1.000 84.50000 C ? A ? 237 1 + ATOM 1868 CD2 . LEU A 237 ? 14.39000 -0.95200 -8.03600 1.000 84.50000 C ? A ? 237 1 + ATOM 1869 N . HIS A 238 ? 19.31500 -3.43400 -8.31000 1.000 82.19000 N ? A ? 238 1 + ATOM 1870 CA . HIS A 238 ? 20.22400 -4.57600 -8.17900 1.000 82.19000 C ? A ? 238 1 + ATOM 1871 C . HIS A 238 ? 20.54600 -4.96200 -6.72300 1.000 82.19000 C ? A ? 238 1 + ATOM 1872 O . HIS A 238 ? 20.96300 -6.09100 -6.48000 1.000 82.19000 O ? A ? 238 1 + ATOM 1873 CB . HIS A 238 ? 21.52500 -4.26000 -8.93200 1.000 82.19000 C ? A ? 238 1 + ATOM 1874 CG . HIS A 238 ? 22.29400 -3.08700 -8.37300 1.000 82.19000 C ? A ? 238 1 + ATOM 1875 ND1 . HIS A 238 ? 22.13000 -1.76100 -8.71100 1.000 82.19000 N ? A ? 238 1 + ATOM 1876 CD2 . HIS A 238 ? 23.28800 -3.14100 -7.43300 1.000 82.19000 C ? A ? 238 1 + ATOM 1877 CE1 . HIS A 238 ? 23.00200 -1.03600 -7.98900 1.000 82.19000 C ? A ? 238 1 + ATOM 1878 NE2 . HIS A 238 ? 23.72600 -1.83600 -7.19500 1.000 82.19000 N ? A ? 238 1 + ATOM 1879 N . ARG A 239 ? 20.36500 -4.04600 -5.75800 1.000 84.81000 N ? A ? 239 1 + ATOM 1880 CA . ARG A 239 ? 20.54500 -4.30400 -4.31800 1.000 84.81000 C ? A ? 239 1 + ATOM 1881 C . ARG A 239 ? 19.38000 -5.08600 -3.70000 1.000 84.81000 C ? A ? 239 1 + ATOM 1882 O . ARG A 239 ? 19.51700 -5.59600 -2.59400 1.000 84.81000 O ? A ? 239 1 + ATOM 1883 CB . ARG A 239 ? 20.74600 -2.97300 -3.57000 1.000 84.81000 C ? A ? 239 1 + ATOM 1884 CG . ARG A 239 ? 21.99300 -2.20800 -4.04300 1.000 84.81000 C ? A ? 239 1 + ATOM 1885 CD . ARG A 239 ? 22.19600 -0.88600 -3.29200 1.000 84.81000 C ? A ? 239 1 + ATOM 1886 NE . ARG A 239 ? 21.17600 0.12200 -3.65500 1.000 84.81000 N ? A ? 239 1 + ATOM 1887 CZ . ARG A 239 ? 21.29500 1.43900 -3.57700 1.000 84.81000 C ? A ? 239 1 + ATOM 1888 NH1 . ARG A 239 ? 22.38700 2.01400 -3.15300 1.000 84.81000 N ? A ? 239 1 + ATOM 1889 NH2 . ARG A 239 ? 20.31900 2.22200 -3.94500 1.000 84.81000 N ? A ? 239 1 + ATOM 1890 N . LEU A 240 ? 18.24600 -5.17900 -4.39400 1.000 89.44000 N ? A ? 240 1 + ATOM 1891 CA . LEU A 240 ? 17.02700 -5.82900 -3.91300 1.000 89.44000 C ? A ? 240 1 + ATOM 1892 C . LEU A 240 ? 17.06700 -7.32700 -4.23500 1.000 89.44000 C ? A ? 240 1 + ATOM 1893 O . LEU A 240 ? 16.34700 -7.82100 -5.09600 1.000 89.44000 O ? A ? 240 1 + ATOM 1894 CB . LEU A 240 ? 15.78700 -5.11300 -4.48500 1.000 89.44000 C ? A ? 240 1 + ATOM 1895 CG . LEU A 240 ? 15.76900 -3.58500 -4.32000 1.000 89.44000 C ? A ? 240 1 + ATOM 1896 CD1 . LEU A 240 ? 14.47300 -3.02100 -4.89900 1.000 89.44000 C ? A ? 240 1 + ATOM 1897 CD2 . LEU A 240 ? 15.88400 -3.17900 -2.85700 1.000 89.44000 C ? A ? 240 1 + ATOM 1898 N . THR A 241 ? 17.95900 -8.05500 -3.56600 1.000 88.94000 N ? A ? 241 1 + ATOM 1899 CA . THR A 241 ? 18.25800 -9.46900 -3.85800 1.000 88.94000 C ? A ? 241 1 + ATOM 1900 C . THR A 241 ? 17.12900 -10.44300 -3.52100 1.000 88.94000 C ? A ? 241 1 + ATOM 1901 O . THR A 241 ? 17.20900 -11.60700 -3.90000 1.000 88.94000 O ? A ? 241 1 + ATOM 1902 CB . THR A 241 ? 19.51700 -9.91500 -3.10400 1.000 88.94000 C ? A ? 241 1 + ATOM 1903 OG1 . THR A 241 ? 19.38000 -9.66500 -1.72200 1.000 88.94000 O ? A ? 241 1 + ATOM 1904 CG2 . THR A 241 ? 20.75700 -9.15500 -3.57600 1.000 88.94000 C ? A ? 241 1 + ATOM 1905 N . PHE A 242 ? 16.10800 -9.99300 -2.79000 1.000 93.19000 N ? A ? 242 1 + ATOM 1906 CA . PHE A 242 ? 14.90800 -10.77100 -2.47200 1.000 93.19000 C ? A ? 242 1 + ATOM 1907 C . PHE A 242 ? 13.71800 -10.42700 -3.37300 1.000 93.19000 C ? A ? 242 1 + ATOM 1908 O . PHE A 242 ? 12.66400 -11.04800 -3.24600 1.000 93.19000 O ? A ? 242 1 + ATOM 1909 CB . PHE A 242 ? 14.56700 -10.58200 -0.98800 1.000 93.19000 C ? A ? 242 1 + ATOM 1910 CG . PHE A 242 ? 15.63500 -11.12100 -0.05700 1.000 93.19000 C ? A ? 242 1 + ATOM 1911 CD1 . PHE A 242 ? 15.79300 -12.51100 0.09800 1.000 93.19000 C ? A ? 242 1 + ATOM 1912 CD2 . PHE A 242 ? 16.48000 -10.24100 0.64300 1.000 93.19000 C ? A ? 242 1 + ATOM 1913 CE1 . PHE A 242 ? 16.78800 -13.01900 0.95100 1.000 93.19000 C ? A ? 242 1 + ATOM 1914 CE2 . PHE A 242 ? 17.47100 -10.74700 1.50100 1.000 93.19000 C ? A ? 242 1 + ATOM 1915 CZ . PHE A 242 ? 17.62700 -12.13600 1.65400 1.000 93.19000 C ? A ? 242 1 + ATOM 1916 N . LEU A 243 ? 13.87500 -9.46500 -4.28800 1.000 95.12000 N ? A ? 243 1 + ATOM 1917 CA . LEU A 243 ? 12.78200 -8.96200 -5.10700 1.000 95.12000 C ? A ? 243 1 + ATOM 1918 C . LEU A 243 ? 12.37800 -10.00600 -6.14600 1.000 95.12000 C ? A ? 243 1 + ATOM 1919 O . LEU A 243 ? 13.16900 -10.33500 -7.03200 1.000 95.12000 O ? A ? 243 1 + ATOM 1920 CB . LEU A 243 ? 13.21000 -7.63400 -5.74800 1.000 95.12000 C ? A ? 243 1 + ATOM 1921 CG . LEU A 243 ? 12.04800 -6.86000 -6.38200 1.000 95.12000 C ? A ? 243 1 + ATOM 1922 CD1 . LEU A 243 ? 11.14400 -6.25200 -5.31300 1.000 95.12000 C ? A ? 243 1 + ATOM 1923 CD2 . LEU A 243 ? 12.59200 -5.70700 -7.22500 1.000 95.12000 C ? A ? 243 1 + ATOM 1924 N . THR A 244 ? 11.15300 -10.50900 -6.04300 1.000 96.88000 N ? A ? 244 1 + ATOM 1925 CA . THR A 244 ? 10.58300 -11.49900 -6.96400 1.000 96.88000 C ? A ? 244 1 + ATOM 1926 C . THR A 244 ? 9.60500 -10.86300 -7.94000 1.000 96.88000 C ? A ? 244 1 + ATOM 1927 O . THR A 244 ? 9.55200 -11.28700 -9.09200 1.000 96.88000 O ? A ? 244 1 + ATOM 1928 CB . THR A 244 ? 9.88100 -12.63000 -6.20600 1.000 96.88000 C ? A ? 244 1 + ATOM 1929 OG1 . THR A 244 ? 8.85000 -12.12600 -5.38900 1.000 96.88000 O ? A ? 244 1 + ATOM 1930 CG2 . THR A 244 ? 10.84200 -13.40000 -5.30300 1.000 96.88000 C ? A ? 244 1 + ATOM 1931 N . TYR A 245 ? 8.89100 -9.81900 -7.51300 1.000 97.12000 N ? A ? 245 1 + ATOM 1932 CA . TYR A 245 ? 7.94400 -9.07700 -8.33600 1.000 97.12000 C ? A ? 245 1 + ATOM 1933 C . TYR A 245 ? 8.37800 -7.61900 -8.49300 1.000 97.12000 C ? A ? 245 1 + ATOM 1934 O . TYR A 245 ? 8.58200 -6.90800 -7.50500 1.000 97.12000 O ? A ? 245 1 + ATOM 1935 CB . TYR A 245 ? 6.54400 -9.18700 -7.72700 1.000 97.12000 C ? A ? 245 1 + ATOM 1936 CG . TYR A 245 ? 5.49200 -8.40500 -8.48900 1.000 97.12000 C ? A ? 245 1 + ATOM 1937 CD1 . TYR A 245 ? 5.22500 -7.06300 -8.15400 1.000 97.12000 C ? A ? 245 1 + ATOM 1938 CD2 . TYR A 245 ? 4.79100 -9.01500 -9.54600 1.000 97.12000 C ? A ? 245 1 + ATOM 1939 CE1 . TYR A 245 ? 4.24400 -6.34500 -8.86000 1.000 97.12000 C ? A ? 245 1 + ATOM 1940 CE2 . TYR A 245 ? 3.82000 -8.29400 -10.26400 1.000 97.12000 C ? A ? 245 1 + ATOM 1941 CZ . TYR A 245 ? 3.53700 -6.95800 -9.91200 1.000 97.12000 C ? A ? 245 1 + ATOM 1942 OH . TYR A 245 ? 2.58000 -6.26400 -10.58200 1.000 97.12000 O ? A ? 245 1 + ATOM 1943 N . LEU A 246 ? 8.47200 -7.16300 -9.74200 1.000 93.88000 N ? A ? 246 1 + ATOM 1944 CA . LEU A 246 ? 8.71100 -5.76400 -10.07600 1.000 93.88000 C ? A ? 246 1 + ATOM 1945 C . LEU A 246 ? 7.72000 -5.28400 -11.13200 1.000 93.88000 C ? A ? 246 1 + ATOM 1946 O . LEU A 246 ? 7.68100 -5.79800 -12.25000 1.000 93.88000 O ? A ? 246 1 + ATOM 1947 CB . LEU A 246 ? 10.16900 -5.58500 -10.51700 1.000 93.88000 C ? A ? 246 1 + ATOM 1948 CG . LEU A 246 ? 10.54800 -4.15400 -10.93800 1.000 93.88000 C ? A ? 246 1 + ATOM 1949 CD1 . LEU A 246 ? 10.37600 -3.13600 -9.80800 1.000 93.88000 C ? A ? 246 1 + ATOM 1950 CD2 . LEU A 246 ? 12.01500 -4.15000 -11.36600 1.000 93.88000 C ? A ? 246 1 + ATOM 1951 N . HIS A 247 ? 6.97500 -4.23500 -10.80900 1.000 92.50000 N ? A ? 247 1 + ATOM 1952 CA . HIS A 247 ? 6.15800 -3.50000 -11.76700 1.000 92.50000 C ? A ? 247 1 + ATOM 1953 C . HIS A 247 ? 6.60000 -2.04100 -11.82900 1.000 92.50000 C ? A ? 247 1 + ATOM 1954 O . HIS A 247 ? 6.72300 -1.37400 -10.80200 1.000 92.50000 O ? A ? 247 1 + ATOM 1955 CB . HIS A 247 ? 4.68100 -3.69100 -11.43100 1.000 92.50000 C ? A ? 247 1 + ATOM 1956 CG . HIS A 247 ? 3.74600 -2.78600 -12.19100 1.000 92.50000 C ? A ? 247 1 + ATOM 1957 ND1 . HIS A 247 ? 3.54600 -1.43900 -11.91400 1.000 92.50000 N ? A ? 247 1 + ATOM 1958 CD2 . HIS A 247 ? 2.83300 -3.17400 -13.12400 1.000 92.50000 C ? A ? 247 1 + ATOM 1959 CE1 . HIS A 247 ? 2.52800 -1.03800 -12.68500 1.000 92.50000 C ? A ? 247 1 + ATOM 1960 NE2 . HIS A 247 ? 2.08100 -2.06000 -13.43600 1.000 92.50000 N ? A ? 247 1 + ATOM 1961 N . ILE A 248 ? 6.86500 -1.57200 -13.04800 1.000 87.56000 N ? A ? 248 1 + ATOM 1962 CA . ILE A 248 ? 7.24700 -0.19100 -13.33900 1.000 87.56000 C ? A ? 248 1 + ATOM 1963 C . ILE A 248 ? 6.36700 0.32300 -14.47700 1.000 87.56000 C ? A ? 248 1 + ATOM 1964 O . ILE A 248 ? 6.42700 -0.17900 -15.60400 1.000 87.56000 O ? A ? 248 1 + ATOM 1965 CB . ILE A 248 ? 8.75300 -0.07800 -13.67800 1.000 87.56000 C ? A ? 248 1 + ATOM 1966 CG1 . ILE A 248 ? 9.63400 -0.54700 -12.49600 1.000 87.56000 C ? A ? 248 1 + ATOM 1967 CG2 . ILE A 248 ? 9.09200 1.38700 -14.02400 1.000 87.56000 C ? A ? 248 1 + ATOM 1968 CD1 . ILE A 248 ? 11.11800 -0.71800 -12.83700 1.000 87.56000 C ? A ? 248 1 + ATOM 1969 N . ASN A 249 ? 5.59400 1.36800 -14.20300 1.000 85.44000 N ? A ? 249 1 + ATOM 1970 CA . ASN A 249 ? 4.86700 2.12600 -15.21500 1.000 85.44000 C ? A ? 249 1 + ATOM 1971 C . ASN A 249 ? 5.57200 3.47400 -15.45600 1.000 85.44000 C ? A ? 249 1 + ATOM 1972 O . ASN A 249 ? 5.78200 4.25900 -14.53500 1.000 85.44000 O ? A ? 249 1 + ATOM 1973 CB . ASN A 249 ? 3.39100 2.17400 -14.79700 1.000 85.44000 C ? A ? 249 1 + ATOM 1974 CG . ASN A 249 ? 2.50200 3.09700 -15.60400 1.000 85.44000 C ? A ? 249 1 + ATOM 1975 OD1 . ASN A 249 ? 2.91900 3.96200 -16.35700 1.000 85.44000 O ? A ? 249 1 + ATOM 1976 ND2 . ASN A 249 ? 1.21000 2.92600 -15.49300 1.000 85.44000 N ? A ? 249 1 + ATOM 1977 N . GLY A 250 ? 5.98100 3.69900 -16.70900 1.000 77.06000 N ? A ? 250 1 + ATOM 1978 CA . GLY A 250 ? 6.77100 4.84200 -17.16600 1.000 77.06000 C ? A ? 250 1 + ATOM 1979 C . GLY A 250 ? 5.98600 5.85400 -17.99600 1.000 77.06000 C ? A ? 250 1 + ATOM 1980 O . GLY A 250 ? 6.56100 6.44400 -18.91500 1.000 77.06000 O ? A ? 250 1 + ATOM 1981 N . SER A 251 ? 4.69600 6.04800 -17.69700 1.000 74.19000 N ? A ? 251 1 + ATOM 1982 CA . SER A 251 ? 3.75300 6.89600 -18.45000 1.000 74.19000 C ? A ? 251 1 + ATOM 1983 C . SER A 251 ? 4.26300 8.30400 -18.79100 1.000 74.19000 C ? A ? 251 1 + ATOM 1984 O . SER A 251 ? 3.88600 8.85700 -19.82800 1.000 74.19000 O ? A ? 251 1 + ATOM 1985 CB . SER A 251 ? 2.41800 6.97300 -17.69900 1.000 74.19000 C ? A ? 251 1 + ATOM 1986 OG . SER A 251 ? 2.59600 7.50700 -16.40300 1.000 74.19000 O ? A ? 251 1 + ATOM 1987 N . ASN A 252 ? 5.17400 8.86600 -17.99900 1.000 65.56000 N ? A ? 252 1 + ATOM 1988 CA . ASN A 252 ? 5.78400 10.18000 -18.23500 1.000 65.56000 C ? A ? 252 1 + ATOM 1989 C . ASN A 252 ? 7.32400 10.14600 -18.28000 1.000 65.56000 C ? A ? 252 1 + ATOM 1990 O . ASN A 252 ? 7.98300 11.17500 -18.15700 1.000 65.56000 O ? A ? 252 1 + ATOM 1991 CB . ASN A 252 ? 5.24600 11.11600 -17.16800 1.000 65.56000 C ? A ? 252 1 + ATOM 1992 CG . ASN A 252 ? 3.77600 11.47800 -17.30800 1.000 65.56000 C ? A ? 252 1 + ATOM 1993 OD1 . ASN A 252 ? 3.17000 11.39100 -18.37000 1.000 65.56000 O ? A ? 252 1 + ATOM 1994 ND2 . ASN A 252 ? 3.16700 11.94900 -16.25200 1.000 65.56000 N ? A ? 252 1 + ATOM 1995 N . CYS A 253 ? 7.92100 8.97600 -18.52100 1.000 67.94000 N ? A ? 253 1 + ATOM 1996 CA . CYS A 253 ? 9.33900 8.86900 -18.84600 1.000 67.94000 C ? A ? 253 1 + ATOM 1997 C . CYS A 253 ? 9.58800 9.38900 -20.27500 1.000 67.94000 C ? A ? 253 1 + ATOM 1998 O . CYS A 253 ? 9.42600 8.65600 -21.25800 1.000 67.94000 O ? A ? 253 1 + ATOM 1999 CB . CYS A 253 ? 9.77700 7.41300 -18.65800 1.000 67.94000 C ? A ? 253 1 + ATOM 2000 SG . CYS A 253 ? 11.58200 7.31100 -18.80600 1.000 67.94000 S ? A ? 253 1 + ATOM 2001 N . THR A 254 ? 9.94100 10.67100 -20.41300 1.000 66.94000 N ? A ? 254 1 + ATOM 2002 CA . THR A 254 ? 10.17200 11.30300 -21.72500 1.000 66.94000 C ? A ? 254 1 + ATOM 2003 C . THR A 254 ? 11.61000 11.19300 -22.21600 1.000 66.94000 C ? A ? 254 1 + ATOM 2004 O . THR A 254 ? 11.83200 11.22800 -23.42600 1.000 66.94000 O ? A ? 254 1 + ATOM 2005 CB . THR A 254 ? 9.74700 12.77700 -21.73300 1.000 66.94000 C ? A ? 254 1 + ATOM 2006 OG1 . THR A 254 ? 10.32800 13.48000 -20.66200 1.000 66.94000 O ? A ? 254 1 + ATOM 2007 CG2 . THR A 254 ? 8.22400 12.88800 -21.59700 1.000 66.94000 C ? A ? 254 1 + ATOM 2008 N . ASP A 255 ? 12.57600 11.00800 -21.32100 1.000 67.12000 N ? A ? 255 1 + ATOM 2009 CA . ASP A 255 ? 13.98900 11.23400 -21.65800 1.000 67.12000 C ? A ? 255 1 + ATOM 2010 C . ASP A 255 ? 14.73000 9.94400 -22.05100 1.000 67.12000 C ? A ? 255 1 + ATOM 2011 O . ASP A 255 ? 15.75700 9.98600 -22.72800 1.000 67.12000 O ? A ? 255 1 + ATOM 2012 CB . ASP A 255 ? 14.67000 11.97200 -20.49400 1.000 67.12000 C ? A ? 255 1 + ATOM 2013 CG . ASP A 255 ? 13.88900 13.21200 -20.03100 1.000 67.12000 C ? A ? 255 1 + ATOM 2014 OD1 . ASP A 255 ? 13.19500 13.82800 -20.87600 1.000 67.12000 O ? A ? 255 1 + ATOM 2015 OD2 . ASP A 255 ? 13.91100 13.46200 -18.80500 1.000 67.12000 O ? A ? 255 1 + ATOM 2016 N . ALA A 256 ? 14.19500 8.77400 -21.68600 1.000 65.69000 N ? A ? 256 1 + ATOM 2017 CA . ALA A 256 ? 14.86700 7.49600 -21.89900 1.000 65.69000 C ? A ? 256 1 + ATOM 2018 C . ALA A 256 ? 14.55000 6.88100 -23.27600 1.000 65.69000 C ? A ? 256 1 + ATOM 2019 O . ALA A 256 ? 13.43500 6.43200 -23.55100 1.000 65.69000 O ? A ? 256 1 + ATOM 2020 CB . ALA A 256 ? 14.52600 6.55400 -20.74000 1.000 65.69000 C ? A ? 256 1 + ATOM 2021 N . ALA A 257 ? 15.56500 6.78200 -24.14300 1.000 65.69000 N ? A ? 257 1 + ATOM 2022 CA . ALA A 257 ? 15.47500 6.05800 -25.41800 1.000 65.69000 C ? A ? 257 1 + ATOM 2023 C . ALA A 257 ? 15.55200 4.52500 -25.25200 1.000 65.69000 C ? A ? 257 1 + ATOM 2024 O . ALA A 257 ? 15.14700 3.77400 -26.14700 1.000 65.69000 O ? A ? 257 1 + ATOM 2025 CB . ALA A 257 ? 16.58300 6.57200 -26.34500 1.000 65.69000 C ? A ? 257 1 + ATOM 2026 N . SER A 258 ? 16.05800 4.05400 -24.11200 1.000 62.44000 N ? A ? 258 1 + ATOM 2027 CA . SER A 258 ? 16.11800 2.64500 -23.73000 1.000 62.44000 C ? A ? 258 1 + ATOM 2028 C . SER A 258 ? 15.81900 2.47800 -22.24900 1.000 62.44000 C ? A ? 258 1 + ATOM 2029 O . SER A 258 ? 16.33400 3.24200 -21.43700 1.000 62.44000 O ? A ? 258 1 + ATOM 2030 CB . SER A 258 ? 17.49500 2.04200 -24.02700 1.000 62.44000 C ? A ? 258 1 + ATOM 2031 OG . SER A 258 ? 18.52700 2.76700 -23.38700 1.000 62.44000 O ? A ? 258 1 + ATOM 2032 N . PHE A 259 ? 15.06100 1.44500 -21.90000 1.000 69.44000 N ? A ? 259 1 + ATOM 2033 CA . PHE A 259 ? 14.96400 0.99100 -20.51400 1.000 69.44000 C ? A ? 259 1 + ATOM 2034 C . PHE A 259 ? 16.29100 0.30800 -20.13500 1.000 69.44000 C ? A ? 259 1 + ATOM 2035 O . PHE A 259 ? 16.81000 -0.45000 -20.96100 1.000 69.44000 O ? A ? 259 1 + ATOM 2036 CB . PHE A 259 ? 13.75700 0.05700 -20.41200 1.000 69.44000 C ? A ? 259 1 + ATOM 2037 CG . PHE A 259 ? 13.36900 -0.33300 -19.00600 1.000 69.44000 C ? A ? 259 1 + ATOM 2038 CD1 . PHE A 259 ? 13.84500 -1.53700 -18.45800 1.000 69.44000 C ? A ? 259 1 + ATOM 2039 CD2 . PHE A 259 ? 12.52200 0.49700 -18.24800 1.000 69.44000 C ? A ? 259 1 + ATOM 2040 CE1 . PHE A 259 ? 13.47000 -1.91700 -17.15900 1.000 69.44000 C ? A ? 259 1 + ATOM 2041 CE2 . PHE A 259 ? 12.15700 0.12000 -16.94400 1.000 69.44000 C ? A ? 259 1 + ATOM 2042 CZ . PHE A 259 ? 12.62700 -1.08800 -16.40500 1.000 69.44000 C ? A ? 259 1 + ATOM 2043 N . SER A 260 ? 16.83600 0.62100 -18.94800 1.000 62.25000 N ? A ? 260 1 + ATOM 2044 CA . SER A 260 ? 18.17000 0.21900 -18.44200 1.000 62.25000 C ? A ? 260 1 + ATOM 2045 C . SER A 260 ? 19.37800 0.65700 -19.30000 1.000 62.25000 C ? A ? 260 1 + ATOM 2046 O . SER A 260 ? 20.13600 -0.14900 -19.83200 1.000 62.25000 O ? A ? 260 1 + ATOM 2047 CB . SER A 260 ? 18.20400 -1.25300 -18.00000 1.000 62.25000 C ? A ? 260 1 + ATOM 2048 OG . SER A 260 ? 17.79100 -2.17500 -18.99300 1.000 62.25000 O ? A ? 260 1 + ATOM 2049 N . GLN A 261 ? 19.57100 1.97200 -19.44100 1.000 59.06000 N ? A ? 261 1 + ATOM 2050 CA . GLN A 261 ? 20.65800 2.60200 -20.21200 1.000 59.06000 C ? A ? 261 1 + ATOM 2051 C . GLN A 261 ? 22.06400 2.06600 -19.85200 1.000 59.06000 C ? A ? 261 1 + ATOM 2052 O . GLN A 261 ? 22.44200 1.99600 -18.68200 1.000 59.06000 O ? A ? 261 1 + ATOM 2053 CB . GLN A 261 ? 20.55400 4.12700 -20.01100 1.000 59.06000 C ? A ? 261 1 + ATOM 2054 CG . GLN A 261 ? 20.84300 4.97500 -21.25900 1.000 59.06000 C ? A ? 261 1 + ATOM 2055 CD . GLN A 261 ? 20.40500 6.42800 -21.05800 1.000 59.06000 C ? A ? 261 1 + ATOM 2056 OE1 . GLN A 261 ? 20.14800 6.88900 -19.96300 1.000 59.06000 O ? A ? 261 1 + ATOM 2057 NE2 . GLN A 261 ? 20.25600 7.20400 -22.10700 1.000 59.06000 N ? A ? 261 1 + ATOM 2058 N . GLU A 262 ? 22.84300 1.70000 -20.87700 1.000 52.94000 N ? A ? 262 1 + ATOM 2059 CA . GLU A 262 ? 24.16400 1.05600 -20.74900 1.000 52.94000 C ? A ? 262 1 + ATOM 2060 C . GLU A 262 ? 25.21700 1.95500 -20.07200 1.000 52.94000 C ? A ? 262 1 + ATOM 2061 O . GLU A 262 ? 26.09600 1.44300 -19.38600 1.000 52.94000 O ? A ? 262 1 + ATOM 2062 CB . GLU A 262 ? 24.65000 0.61200 -22.14800 1.000 52.94000 C ? A ? 262 1 + ATOM 2063 CG . GLU A 262 ? 23.82300 -0.55400 -22.73400 1.000 52.94000 C ? A ? 262 1 + ATOM 2064 CD . GLU A 262 ? 24.08500 -0.82300 -24.23200 1.000 52.94000 C ? A ? 262 1 + ATOM 2065 OE1 . GLU A 262 ? 23.14600 -1.31600 -24.91100 1.000 52.94000 O ? A ? 262 1 + ATOM 2066 OE2 . GLU A 262 ? 25.16900 -0.46400 -24.73200 1.000 52.94000 O ? A ? 262 1 + ATOM 2067 N . GLU A 263 ? 25.08600 3.27900 -20.19900 1.000 48.91000 N ? A ? 263 1 + ATOM 2068 CA . GLU A 263 ? 26.02500 4.27800 -19.65800 1.000 48.91000 C ? A ? 263 1 + ATOM 2069 C . GLU A 263 ? 25.95800 4.43000 -18.12500 1.000 48.91000 C ? A ? 263 1 + ATOM 2070 O . GLU A 263 ? 26.91500 4.90500 -17.52100 1.000 48.91000 O ? A ? 263 1 + ATOM 2071 CB . GLU A 263 ? 25.75500 5.63000 -20.35000 1.000 48.91000 C ? A ? 263 1 + ATOM 2072 CG . GLU A 263 ? 26.13200 5.60900 -21.84600 1.000 48.91000 C ? A ? 263 1 + ATOM 2073 CD . GLU A 263 ? 25.74400 6.88500 -22.61600 1.000 48.91000 C ? A ? 263 1 + ATOM 2074 OE1 . GLU A 263 ? 26.07300 6.94200 -23.82300 1.000 48.91000 O ? A ? 263 1 + ATOM 2075 OE2 . GLU A 263 ? 25.04700 7.74900 -22.03900 1.000 48.91000 O ? A ? 263 1 + ATOM 2076 N . ILE A 264 ? 24.85900 4.00400 -17.48300 1.000 51.03000 N ? A ? 264 1 + ATOM 2077 CA . ILE A 264 ? 24.58800 4.22400 -16.04300 1.000 51.03000 C ? A ? 264 1 + ATOM 2078 C . ILE A 264 ? 24.54300 2.89200 -15.25900 1.000 51.03000 C ? A ? 264 1 + ATOM 2079 O . ILE A 264 ? 24.47400 2.86800 -14.03400 1.000 51.03000 O ? A ? 264 1 + ATOM 2080 CB . ILE A 264 ? 23.32500 5.11700 -15.87200 1.000 51.03000 C ? A ? 264 1 + ATOM 2081 CG1 . ILE A 264 ? 23.46500 6.43500 -16.68200 1.000 51.03000 C ? A ? 264 1 + ATOM 2082 CG2 . ILE A 264 ? 23.04100 5.46000 -14.39400 1.000 51.03000 C ? A ? 264 1 + ATOM 2083 CD1 . ILE A 264 ? 22.19500 7.29300 -16.74600 1.000 51.03000 C ? A ? 264 1 + ATOM 2084 N . GLY A 265 ? 24.62600 1.74300 -15.94300 1.000 54.34000 N ? A ? 265 1 + ATOM 2085 CA . GLY A 265 ? 24.78800 0.44100 -15.28500 1.000 54.34000 C ? A ? 265 1 + ATOM 2086 C . GLY A 265 ? 23.57900 -0.04100 -14.47100 1.000 54.34000 C ? A ? 265 1 + ATOM 2087 O . GLY A 265 ? 23.74700 -0.87900 -13.58200 1.000 54.34000 O ? A ? 265 1 + ATOM 2088 N . MET A 266 ? 22.36200 0.44100 -14.76200 1.000 69.94000 N ? A ? 266 1 + ATOM 2089 CA . MET A 266 ? 21.14000 -0.03500 -14.10300 1.000 69.94000 C ? A ? 266 1 + ATOM 2090 C . MET A 266 ? 20.92400 -1.53000 -14.39600 1.000 69.94000 C ? A ? 266 1 + ATOM 2091 O . MET A 266 ? 20.57000 -1.91700 -15.51100 1.000 69.94000 O ? A ? 266 1 + ATOM 2092 CB . MET A 266 ? 19.92400 0.79900 -14.54100 1.000 69.94000 C ? A ? 266 1 + ATOM 2093 CG . MET A 266 ? 18.65400 0.41200 -13.76700 1.000 69.94000 C ? A ? 266 1 + ATOM 2094 SD . MET A 266 ? 17.11900 0.83900 -14.62600 1.000 69.94000 S ? A ? 266 1 + ATOM 2095 CE . MET A 266 ? 15.93400 0.04500 -13.51100 1.000 69.94000 C ? A ? 266 1 + ATOM 2096 N . LYS A 267 ? 21.11800 -2.36800 -13.37400 1.000 78.75000 N ? A ? 267 1 + ATOM 2097 CA . LYS A 267 ? 20.87800 -3.81600 -13.41700 1.000 78.75000 C ? A ? 267 1 + ATOM 2098 C . LYS A 267 ? 19.62400 -4.17600 -12.63000 1.000 78.75000 C ? A ? 267 1 + ATOM 2099 O . LYS A 267 ? 19.38600 -3.62900 -11.55100 1.000 78.75000 O ? A ? 267 1 + ATOM 2100 CB . LYS A 267 ? 22.10700 -4.58300 -12.91000 1.000 78.75000 C ? A ? 267 1 + ATOM 2101 CG . LYS A 267 ? 23.29100 -4.45500 -13.87700 1.000 78.75000 C ? A ? 267 1 + ATOM 2102 CD . LYS A 267 ? 24.51700 -5.19700 -13.33800 1.000 78.75000 C ? A ? 267 1 + ATOM 2103 CE . LYS A 267 ? 25.69500 -4.97000 -14.29000 1.000 78.75000 C ? A ? 267 1 + ATOM 2104 NZ . LYS A 267 ? 26.91100 -5.68500 -13.83200 1.000 78.75000 N ? A ? 267 1 + ATOM 2105 N . LEU A 268 ? 18.84100 -5.09800 -13.17800 1.000 86.12000 N ? A ? 268 1 + ATOM 2106 CA . LEU A 268 ? 17.71300 -5.70500 -12.48400 1.000 86.12000 C ? A ? 268 1 + ATOM 2107 C . LEU A 268 ? 18.20900 -6.82500 -11.54500 1.000 86.12000 C ? A ? 268 1 + ATOM 2108 O . LEU A 268 ? 19.23300 -7.45000 -11.83900 1.000 86.12000 O ? A ? 268 1 + ATOM 2109 CB . LEU A 268 ? 16.71600 -6.21600 -13.53300 1.000 86.12000 C ? A ? 268 1 + ATOM 2110 CG . LEU A 268 ? 16.00900 -5.11300 -14.34100 1.000 86.12000 C ? A ? 268 1 + ATOM 2111 CD1 . LEU A 268 ? 15.23200 -5.73900 -15.49700 1.000 86.12000 C ? A ? 268 1 + ATOM 2112 CD2 . LEU A 268 ? 15.02900 -4.31900 -13.47600 1.000 86.12000 C ? A ? 268 1 + ATOM 2113 N . PRO A 269 ? 17.53000 -7.07500 -10.41100 1.000 88.19000 N ? A ? 269 1 + ATOM 2114 CA . PRO A 269 ? 17.93600 -8.12400 -9.48400 1.000 88.19000 C ? A ? 269 1 + ATOM 2115 C . PRO A 269 ? 17.70800 -9.53300 -10.07500 1.000 88.19000 C ? A ? 269 1 + ATOM 2116 O . PRO A 269 ? 16.66600 -9.78300 -10.68100 1.000 88.19000 O ? A ? 269 1 + ATOM 2117 CB . PRO A 269 ? 17.15600 -7.87500 -8.19200 1.000 88.19000 C ? A ? 269 1 + ATOM 2118 CG . PRO A 269 ? 15.97000 -7.00300 -8.59700 1.000 88.19000 C ? A ? 269 1 + ATOM 2119 CD . PRO A 269 ? 16.41200 -6.30800 -9.88300 1.000 88.19000 C ? A ? 269 1 + ATOM 2120 N . PRO A 270 ? 18.65000 -10.48100 -9.88900 1.000 88.00000 N ? A ? 270 1 + ATOM 2121 CA . PRO A 270 ? 18.57400 -11.82800 -10.47800 1.000 88.00000 C ? A ? 270 1 + ATOM 2122 C . PRO A 270 ? 17.48900 -12.72300 -9.85200 1.000 88.00000 C ? A ? 270 1 + ATOM 2123 O . PRO A 270 ? 17.15600 -13.77600 -10.39800 1.000 88.00000 O ? A ? 270 1 + ATOM 2124 CB . PRO A 270 ? 19.97300 -12.42000 -10.27400 1.000 88.00000 C ? A ? 270 1 + ATOM 2125 CG . PRO A 270 ? 20.46600 -11.73500 -9.00000 1.000 88.00000 C ? A ? 270 1 + ATOM 2126 CD . PRO A 270 ? 19.88400 -10.33000 -9.12800 1.000 88.00000 C ? A ? 270 1 + ATOM 2127 N . SER A 271 ? 16.94100 -12.31100 -8.70800 1.000 92.69000 N ? A ? 271 1 + ATOM 2128 CA . SER A 271 ? 15.83400 -12.96200 -8.00100 1.000 92.69000 C ? A ? 271 1 + ATOM 2129 C . SER A 271 ? 14.46900 -12.75800 -8.66100 1.000 92.69000 C ? A ? 271 1 + ATOM 2130 O . SER A 271 ? 13.52000 -13.43000 -8.26600 1.000 92.69000 O ? A ? 271 1 + ATOM 2131 CB . SER A 271 ? 15.78400 -12.41200 -6.57300 1.000 92.69000 C ? A ? 271 1 + ATOM 2132 OG . SER A 271 ? 15.72300 -10.99700 -6.60500 1.000 92.69000 O ? A ? 271 1 + ATOM 2133 N . LEU A 272 ? 14.35200 -11.84800 -9.63900 1.000 94.31000 N ? A ? 272 1 + ATOM 2134 CA . LEU A 272 ? 13.07000 -11.53600 -10.27100 1.000 94.31000 C ? A ? 272 1 + ATOM 2135 C . LEU A 272 ? 12.46600 -12.76200 -10.94700 1.000 94.31000 C ? A ? 272 1 + ATOM 2136 O . LEU A 272 ? 13.11400 -13.40900 -11.76700 1.000 94.31000 O ? A ? 272 1 + ATOM 2137 CB . LEU A 272 ? 13.20600 -10.41000 -11.30600 1.000 94.31000 C ? A ? 272 1 + ATOM 2138 CG . LEU A 272 ? 13.34700 -9.01600 -10.69400 1.000 94.31000 C ? A ? 272 1 + ATOM 2139 CD1 . LEU A 272 ? 13.60500 -8.00800 -11.81300 1.000 94.31000 C ? A ? 272 1 + ATOM 2140 CD2 . LEU A 272 ? 12.09700 -8.56300 -9.94000 1.000 94.31000 C ? A ? 272 1 + ATOM 2141 N . ILE A 273 ? 11.20000 -13.00700 -10.63100 1.000 96.19000 N ? A ? 273 1 + ATOM 2142 CA . ILE A 273 ? 10.34600 -14.03900 -11.22100 1.000 96.19000 C ? A ? 273 1 + ATOM 2143 C . ILE A 273 ? 9.35700 -13.37800 -12.18200 1.000 96.19000 C ? A ? 273 1 + ATOM 2144 O . ILE A 273 ? 9.17500 -13.85400 -13.30400 1.000 96.19000 O ? A ? 273 1 + ATOM 2145 CB . ILE A 273 ? 9.62100 -14.82700 -10.10600 1.000 96.19000 C ? A ? 273 1 + ATOM 2146 CG1 . ILE A 273 ? 10.64400 -15.44100 -9.11800 1.000 96.19000 C ? A ? 273 1 + ATOM 2147 CG2 . ILE A 273 ? 8.74100 -15.92500 -10.72800 1.000 96.19000 C ? A ? 273 1 + ATOM 2148 CD1 . ILE A 273 ? 10.02900 -16.23700 -7.96100 1.000 96.19000 C ? A ? 273 1 + ATOM 2149 N . ASP A 274 ? 8.80400 -12.23600 -11.77300 1.000 96.56000 N ? A ? 274 1 + ATOM 2150 CA . ASP A 274 ? 7.76000 -11.50700 -12.47900 1.000 96.56000 C ? A ? 274 1 + ATOM 2151 C . ASP A 274 ? 8.18500 -10.05600 -12.71100 1.000 96.56000 C ? A ? 274 1 + ATOM 2152 O . ASP A 274 ? 8.47100 -9.30300 -11.77500 1.000 96.56000 O ? A ? 274 1 + ATOM 2153 CB . ASP A 274 ? 6.46600 -11.56700 -11.66300 1.000 96.56000 C ? A ? 274 1 + ATOM 2154 CG . ASP A 274 ? 5.90700 -12.98600 -11.57400 1.000 96.56000 C ? A ? 274 1 + ATOM 2155 OD1 . ASP A 274 ? 5.12100 -13.34500 -12.47900 1.000 96.56000 O ? A ? 274 1 + ATOM 2156 OD2 . ASP A 274 ? 6.26800 -13.68700 -10.60400 1.000 96.56000 O ? A ? 274 1 + ATOM 2157 N . LEU A 275 ? 8.20500 -9.64900 -13.98100 1.000 93.81000 N ? A ? 275 1 + ATOM 2158 CA . LEU A 275 ? 8.54900 -8.29300 -14.39100 1.000 93.81000 C ? A ? 275 1 + ATOM 2159 C . LEU A 275 ? 7.45100 -7.70900 -15.27300 1.000 93.81000 C ? A ? 275 1 + ATOM 2160 O . LEU A 275 ? 7.16200 -8.22200 -16.35200 1.000 93.81000 O ? A ? 275 1 + ATOM 2161 CB . LEU A 275 ? 9.91500 -8.31600 -15.08600 1.000 93.81000 C ? A ? 275 1 + ATOM 2162 CG . LEU A 275 ? 10.40100 -6.96000 -15.62100 1.000 93.81000 C ? A ? 275 1 + ATOM 2163 CD1 . LEU A 275 ? 10.47800 -5.87200 -14.55000 1.000 93.81000 C ? A ? 275 1 + ATOM 2164 CD2 . LEU A 275 ? 11.80500 -7.16700 -16.18700 1.000 93.81000 C ? A ? 275 1 + ATOM 2165 N . THR A 276 ? 6.88200 -6.59000 -14.83900 1.000 93.06000 N ? A ? 276 1 + ATOM 2166 CA . THR A 276 ? 5.92400 -5.81100 -15.62200 1.000 93.06000 C ? A ? 276 1 + ATOM 2167 C . THR A 276 ? 6.48600 -4.43000 -15.94000 1.000 93.06000 C ? A ? 276 1 + ATOM 2168 O . THR A 276 ? 6.85800 -3.67800 -15.04300 1.000 93.06000 O ? A ? 276 1 + ATOM 2169 CB . THR A 276 ? 4.57800 -5.71000 -14.90800 1.000 93.06000 C ? A ? 276 1 + ATOM 2170 OG1 . THR A 276 ? 4.04800 -6.98600 -14.65100 1.000 93.06000 O ? A ? 276 1 + ATOM 2171 CG2 . THR A 276 ? 3.56700 -4.97600 -15.78200 1.000 93.06000 C ? A ? 276 1 + ATOM 2172 N . ILE A 277 ? 6.52600 -4.08000 -17.22500 1.000 88.50000 N ? A ? 277 1 + ATOM 2173 CA . ILE A 277 ? 7.02700 -2.79600 -17.72700 1.000 88.50000 C ? A ? 277 1 + ATOM 2174 C . ILE A 277 ? 5.94700 -2.16900 -18.61100 1.000 88.50000 C ? A ? 277 1 + ATOM 2175 O . ILE A 277 ? 5.58600 -2.72000 -19.65000 1.000 88.50000 O ? A ? 277 1 + ATOM 2176 CB . ILE A 277 ? 8.36600 -2.99400 -18.47300 1.000 88.50000 C ? A ? 277 1 + ATOM 2177 CG1 . ILE A 277 ? 9.43600 -3.59000 -17.52900 1.000 88.50000 C ? A ? 277 1 + ATOM 2178 CG2 . ILE A 277 ? 8.88200 -1.66600 -19.05300 1.000 88.50000 C ? A ? 277 1 + ATOM 2179 CD1 . ILE A 277 ? 10.75400 -3.93700 -18.22800 1.000 88.50000 C ? A ? 277 1 + ATOM 2180 N . GLY A 278 ? 5.42500 -1.01400 -18.21000 1.000 88.88000 N ? A ? 278 1 + ATOM 2181 CA . GLY A 278 ? 4.27100 -0.38800 -18.85600 1.000 88.88000 C ? A ? 278 1 + ATOM 2182 C . GLY A 278 ? 4.49100 1.06100 -19.27600 1.000 88.88000 C ? A ? 278 1 + ATOM 2183 O . GLY A 278 ? 5.26300 1.78200 -18.65300 1.000 88.88000 O ? A ? 278 1 + ATOM 2184 N . ASN A 279 ? 3.75200 1.50800 -20.29100 1.000 86.75000 N ? A ? 279 1 + ATOM 2185 CA . ASN A 279 ? 3.50800 2.91100 -20.64100 1.000 86.75000 C ? A ? 279 1 + ATOM 2186 C . ASN A 279 ? 4.74700 3.76800 -20.97200 1.000 86.75000 C ? A ? 279 1 + ATOM 2187 O . ASN A 279 ? 4.70300 4.99300 -20.87100 1.000 86.75000 O ? A ? 279 1 + ATOM 2188 CB . ASN A 279 ? 2.57800 3.52600 -19.59200 1.000 86.75000 C ? A ? 279 1 + ATOM 2189 CG . ASN A 279 ? 1.22800 2.84100 -19.51500 1.000 86.75000 C ? A ? 279 1 + ATOM 2190 OD1 . ASN A 279 ? 0.68500 2.37100 -20.49900 1.000 86.75000 O ? A ? 279 1 + ATOM 2191 ND2 . ASN A 279 ? 0.62800 2.78700 -18.35600 1.000 86.75000 N ? A ? 279 1 + ATOM 2192 N . PHE A 280 ? 5.85900 3.17500 -21.41300 1.000 84.69000 N ? A ? 280 1 + ATOM 2193 CA . PHE A 280 ? 7.04000 3.94700 -21.81100 1.000 84.69000 C ? A ? 280 1 + ATOM 2194 C . PHE A 280 ? 6.87200 4.57600 -23.20400 1.000 84.69000 C ? A ? 280 1 + ATOM 2195 O . PHE A 280 ? 7.09300 3.93500 -24.23500 1.000 84.69000 O ? A ? 280 1 + ATOM 2196 CB . PHE A 280 ? 8.30500 3.09000 -21.73400 1.000 84.69000 C ? A ? 280 1 + ATOM 2197 CG . PHE A 280 ? 8.79200 2.84500 -20.32400 1.000 84.69000 C ? A ? 280 1 + ATOM 2198 CD1 . PHE A 280 ? 9.74000 3.71200 -19.74500 1.000 84.69000 C ? A ? 280 1 + ATOM 2199 CD2 . PHE A 280 ? 8.26200 1.78600 -19.56900 1.000 84.69000 C ? A ? 280 1 + ATOM 2200 CE1 . PHE A 280 ? 10.16200 3.51100 -18.42000 1.000 84.69000 C ? A ? 280 1 + ATOM 2201 CE2 . PHE A 280 ? 8.65600 1.61000 -18.23100 1.000 84.69000 C ? A ? 280 1 + ATOM 2202 CZ . PHE A 280 ? 9.61300 2.46600 -17.66300 1.000 84.69000 C ? A ? 280 1 + ATOM 2203 N . LYS A 281 ? 6.56300 5.87800 -23.24400 1.000 82.56000 N ? A ? 281 1 + ATOM 2204 CA . LYS A 281 ? 6.28300 6.62700 -24.48800 1.000 82.56000 C ? A ? 281 1 + ATOM 2205 C . LYS A 281 ? 7.46700 6.70200 -25.46400 1.000 82.56000 C ? A ? 281 1 + ATOM 2206 O . LYS A 281 ? 7.25600 6.73400 -26.67900 1.000 82.56000 O ? A ? 281 1 + ATOM 2207 CB . LYS A 281 ? 5.79600 8.04300 -24.12600 1.000 82.56000 C ? A ? 281 1 + ATOM 2208 CG . LYS A 281 ? 4.39700 8.04100 -23.48400 1.000 82.56000 C ? A ? 281 1 + ATOM 2209 CD . LYS A 281 ? 3.98200 9.45100 -23.03600 1.000 82.56000 C ? A ? 281 1 + ATOM 2210 CE . LYS A 281 ? 2.56300 9.43100 -22.44200 1.000 82.56000 C ? A ? 281 1 + ATOM 2211 NZ . LYS A 281 ? 2.34800 10.53100 -21.46400 1.000 82.56000 N ? A ? 281 1 + ATOM 2212 N . ASN A 282 ? 8.70400 6.75100 -24.95600 1.000 82.94000 N ? A ? 282 1 + ATOM 2213 CA . ASN A 282 ? 9.90400 7.00400 -25.76800 1.000 82.94000 C ? A ? 282 1 + ATOM 2214 C . ASN A 282 ? 10.90800 5.84700 -25.85800 1.000 82.94000 C ? A ? 282 1 + ATOM 2215 O . ASN A 282 ? 11.81200 5.90300 -26.70000 1.000 82.94000 O ? A ? 282 1 + ATOM 2216 CB . ASN A 282 ? 10.53600 8.33800 -25.33000 1.000 82.94000 C ? A ? 282 1 + ATOM 2217 CG . ASN A 282 ? 9.74400 9.53400 -25.83400 1.000 82.94000 C ? A ? 282 1 + ATOM 2218 OD1 . ASN A 282 ? 9.11000 9.50600 -26.88400 1.000 82.94000 O ? A ? 282 1 + ATOM 2219 ND2 . ASN A 282 ? 9.79000 10.64600 -25.15500 1.000 82.94000 N ? A ? 282 1 + ATOM 2220 N . VAL A 283 ? 10.71700 4.77700 -25.08000 1.000 81.44000 N ? A ? 283 1 + ATOM 2221 CA . VAL A 283 ? 11.61400 3.61600 -25.08700 1.000 81.44000 C ? A ? 283 1 + ATOM 2222 C . VAL A 283 ? 11.51600 2.88000 -26.42200 1.000 81.44000 C ? A ? 283 1 + ATOM 2223 O . VAL A 283 ? 10.45000 2.43500 -26.84400 1.000 81.44000 O ? A ? 283 1 + ATOM 2224 CB . VAL A 283 ? 11.33900 2.68600 -23.89200 1.000 81.44000 C ? A ? 283 1 + ATOM 2225 CG1 . VAL A 283 ? 12.08400 1.35000 -23.99400 1.000 81.44000 C ? A ? 283 1 + ATOM 2226 CG2 . VAL A 283 ? 11.80600 3.37000 -22.60000 1.000 81.44000 C ? A ? 283 1 + ATOM 2227 N . ARG A 284 ? 12.66300 2.74200 -27.09500 1.000 83.19000 N ? A ? 284 1 + ATOM 2228 CA . ARG A 284 ? 12.79400 2.04900 -28.38700 1.000 83.19000 C ? A ? 284 1 + ATOM 2229 C . ARG A 284 ? 13.31400 0.62700 -28.24800 1.000 83.19000 C ? A ? 284 1 + ATOM 2230 O . ARG A 284 ? 13.02500 -0.21200 -29.09700 1.000 83.19000 O ? A ? 284 1 + ATOM 2231 CB . ARG A 284 ? 13.70900 2.84500 -29.32300 1.000 83.19000 C ? A ? 284 1 + ATOM 2232 CG . ARG A 284 ? 13.18200 4.25300 -29.62200 1.000 83.19000 C ? A ? 284 1 + ATOM 2233 CD . ARG A 284 ? 14.15300 4.96900 -30.56600 1.000 83.19000 C ? A ? 284 1 + ATOM 2234 NE . ARG A 284 ? 13.74000 6.36200 -30.81400 1.000 83.19000 N ? A ? 284 1 + ATOM 2235 CZ . ARG A 284 ? 14.35200 7.23100 -31.60100 1.000 83.19000 C ? A ? 284 1 + ATOM 2236 NH1 . ARG A 284 ? 15.42900 6.92500 -32.27000 1.000 83.19000 N ? A ? 284 1 + ATOM 2237 NH2 . ARG A 284 ? 13.89800 8.44400 -31.72600 1.000 83.19000 N ? A ? 284 1 + ATOM 2238 N . LYS A 285 ? 14.10100 0.36400 -27.20900 1.000 82.38000 N ? A ? 285 1 + ATOM 2239 CA . LYS A 285 ? 14.69600 -0.94300 -26.92200 1.000 82.38000 C ? A ? 285 1 + ATOM 2240 C . LYS A 285 ? 14.78200 -1.16900 -25.41700 1.000 82.38000 C ? A ? 285 1 + ATOM 2241 O . LYS A 285 ? 14.97200 -0.22000 -24.65900 1.000 82.38000 O ? A ? 285 1 + ATOM 2242 CB . LYS A 285 ? 16.07800 -1.08000 -27.60700 1.000 82.38000 C ? A ? 285 1 + ATOM 2243 CG . LYS A 285 ? 17.14700 -0.06600 -27.14000 1.000 82.38000 C ? A ? 285 1 + ATOM 2244 CD . LYS A 285 ? 18.54900 -0.35800 -27.71600 1.000 82.38000 C ? A ? 285 1 + ATOM 2245 CE . LYS A 285 ? 19.60000 0.62000 -27.14200 1.000 82.38000 C ? A ? 285 1 + ATOM 2246 NZ . LYS A 285 ? 21.01600 0.16600 -27.31800 1.000 82.38000 N ? A ? 285 1 + ATOM 2247 N . LEU A 286 ? 14.70600 -2.42600 -25.00800 1.000 78.88000 N ? A ? 286 1 + ATOM 2248 CA . LEU A 286 ? 15.18600 -2.85900 -23.69900 1.000 78.88000 C ? A ? 286 1 + ATOM 2249 C . LEU A 286 ? 16.68600 -3.16600 -23.81900 1.000 78.88000 C ? A ? 286 1 + ATOM 2250 O . LEU A 286 ? 17.09500 -3.83200 -24.77300 1.000 78.88000 O ? A ? 286 1 + ATOM 2251 CB . LEU A 286 ? 14.37500 -4.08400 -23.25300 1.000 78.88000 C ? A ? 286 1 + ATOM 2252 CG . LEU A 286 ? 12.84800 -3.87400 -23.14100 1.000 78.88000 C ? A ? 286 1 + ATOM 2253 CD1 . LEU A 286 ? 12.18100 -5.15200 -22.63500 1.000 78.88000 C ? A ? 286 1 + ATOM 2254 CD2 . LEU A 286 ? 12.48000 -2.72600 -22.20500 1.000 78.88000 C ? A ? 286 1 + ATOM 2255 N . SER A 287 ? 17.51100 -2.64500 -22.91100 1.000 75.75000 N ? A ? 287 1 + ATOM 2256 CA . SER A 287 ? 18.95700 -2.89100 -22.92600 1.000 75.75000 C ? A ? 287 1 + ATOM 2257 C . SER A 287 ? 19.28300 -4.34100 -22.58700 1.000 75.75000 C ? A ? 287 1 + ATOM 2258 O . SER A 287 ? 18.71700 -4.91600 -21.66100 1.000 75.75000 O ? A ? 287 1 + ATOM 2259 CB . SER A 287 ? 19.62400 -1.97400 -21.91700 1.000 75.75000 C ? A ? 287 1 + ATOM 2260 OG . SER A 287 ? 20.99400 -2.25800 -21.72800 1.000 75.75000 O ? A ? 287 1 + ATOM 2261 N . SER A 288 ? 20.23700 -4.93300 -23.30300 1.000 74.62000 N ? A ? 288 1 + ATOM 2262 CA . SER A 288 ? 20.73500 -6.27500 -22.99400 1.000 74.62000 C ? A ? 288 1 + ATOM 2263 C . SER A 288 ? 21.41400 -6.32600 -21.62200 1.000 74.62000 C ? A ? 288 1 + ATOM 2264 O . SER A 288 ? 21.22800 -7.28300 -20.87700 1.000 74.62000 O ? A ? 288 1 + ATOM 2265 CB . SER A 288 ? 21.68800 -6.73500 -24.10600 1.000 74.62000 C ? A ? 288 1 + ATOM 2266 OG . SER A 288 ? 22.57400 -5.70300 -24.49800 1.000 74.62000 O ? A ? 288 1 + ATOM 2267 N . ASN A 289 ? 22.14300 -5.28000 -21.23200 1.000 72.81000 N ? A ? 289 1 + ATOM 2268 CA . ASN A 289 ? 22.93200 -5.29800 -19.99700 1.000 72.81000 C ? A ? 289 1 + ATOM 2269 C . ASN A 289 ? 22.06200 -5.29600 -18.73200 1.000 72.81000 C ? A ? 289 1 + ATOM 2270 O . ASN A 289 ? 22.43600 -5.90800 -17.73600 1.000 72.81000 O ? A ? 289 1 + ATOM 2271 CB . ASN A 289 ? 23.91400 -4.11400 -20.01200 1.000 72.81000 C ? A ? 289 1 + ATOM 2272 CG . ASN A 289 ? 25.02400 -4.27300 -21.03600 1.000 72.81000 C ? A ? 289 1 + ATOM 2273 OD1 . ASN A 289 ? 25.11000 -5.24800 -21.76500 1.000 72.81000 O ? A ? 289 1 + ATOM 2274 ND2 . ASN A 289 ? 25.90100 -3.30300 -21.14100 1.000 72.81000 N ? A ? 289 1 + ATOM 2275 N . GLY A 290 ? 20.89200 -4.64800 -18.76500 1.000 74.00000 N ? A ? 290 1 + ATOM 2276 CA . GLY A 290 ? 19.99400 -4.60100 -17.60800 1.000 74.00000 C ? A ? 290 1 + ATOM 2277 C . GLY A 290 ? 19.22900 -5.90200 -17.35200 1.000 74.00000 C ? A ? 290 1 + ATOM 2278 O . GLY A 290 ? 18.79600 -6.13000 -16.22800 1.000 74.00000 O ? A ? 290 1 + ATOM 2279 N . PHE A 291 ? 19.09000 -6.74700 -18.37800 1.000 80.00000 N ? A ? 291 1 + ATOM 2280 CA . PHE A 291 ? 18.43000 -8.05900 -18.31500 1.000 80.00000 C ? A ? 291 1 + ATOM 2281 C . PHE A 291 ? 19.43800 -9.21700 -18.24600 1.000 80.00000 C ? A ? 291 1 + ATOM 2282 O . PHE A 291 ? 19.05100 -10.38400 -18.21400 1.000 80.00000 O ? A ? 291 1 + ATOM 2283 CB . PHE A 291 ? 17.47600 -8.21300 -19.51100 1.000 80.00000 C ? A ? 291 1 + ATOM 2284 CG . PHE A 291 ? 16.23700 -7.33600 -19.44900 1.000 80.00000 C ? A ? 291 1 + ATOM 2285 CD1 . PHE A 291 ? 14.98100 -7.89600 -19.15100 1.000 80.00000 C ? A ? 291 1 + ATOM 2286 CD2 . PHE A 291 ? 16.33000 -5.95600 -19.69800 1.000 80.00000 C ? A ? 291 1 + ATOM 2287 CE1 . PHE A 291 ? 13.83600 -7.08300 -19.10700 1.000 80.00000 C ? A ? 291 1 + ATOM 2288 CE2 . PHE A 291 ? 15.19000 -5.14100 -19.65100 1.000 80.00000 C ? A ? 291 1 + ATOM 2289 CZ . PHE A 291 ? 13.94000 -5.70400 -19.35000 1.000 80.00000 C ? A ? 291 1 + ATOM 2290 N . GLN A 292 ? 20.73800 -8.91100 -18.23600 1.000 73.88000 N ? A ? 292 1 + ATOM 2291 CA . GLN A 292 ? 21.78100 -9.91400 -18.08800 1.000 73.88000 C ? A ? 292 1 + ATOM 2292 C . GLN A 292 ? 21.67100 -10.56200 -16.69800 1.000 73.88000 C ? A ? 292 1 + ATOM 2293 O . GLN A 292 ? 21.59400 -9.86100 -15.69200 1.000 73.88000 O ? A ? 292 1 + ATOM 2294 CB . GLN A 292 ? 23.14600 -9.25300 -18.34200 1.000 73.88000 C ? A ? 292 1 + ATOM 2295 CG . GLN A 292 ? 24.27000 -10.28600 -18.50500 1.000 73.88000 C ? A ? 292 1 + ATOM 2296 CD . GLN A 292 ? 25.62500 -9.66100 -18.82700 1.000 73.88000 C ? A ? 292 1 + ATOM 2297 OE1 . GLN A 292 ? 25.82800 -8.45800 -18.81800 1.000 73.88000 O ? A ? 292 1 + ATOM 2298 NE2 . GLN A 292 ? 26.62500 -10.46600 -19.10700 1.000 73.88000 N ? A ? 292 1 + ATOM 2299 N . ASN A 293 ? 21.70600 -11.89700 -16.64800 1.000 76.88000 N ? A ? 293 1 + ATOM 2300 CA . ASN A 293 ? 21.61500 -12.72000 -15.43000 1.000 76.88000 C ? A ? 293 1 + ATOM 2301 C . ASN A 293 ? 20.22500 -12.81300 -14.77200 1.000 76.88000 C ? A ? 293 1 + ATOM 2302 O . ASN A 293 ? 20.13100 -13.24200 -13.62300 1.000 76.88000 O ? A ? 293 1 + ATOM 2303 CB . ASN A 293 ? 22.72000 -12.35400 -14.41800 1.000 76.88000 C ? A ? 293 1 + ATOM 2304 CG . ASN A 293 ? 24.10000 -12.24400 -15.02800 1.000 76.88000 C ? A ? 293 1 + ATOM 2305 OD1 . ASN A 293 ? 24.48800 -12.97700 -15.92100 1.000 76.88000 O ? A ? 293 1 + ATOM 2306 ND2 . ASN A 293 ? 24.89700 -11.30900 -14.57100 1.000 76.88000 N ? A ? 293 1 + ATOM 2307 N . LEU A 294 ? 19.13900 -12.49300 -15.48500 1.000 85.94000 N ? A ? 294 1 + ATOM 2308 CA . LEU A 294 ? 17.77100 -12.78100 -15.03100 1.000 85.94000 C ? A ? 294 1 + ATOM 2309 C . LEU A 294 ? 17.41700 -14.26600 -15.21700 1.000 85.94000 C ? A ? 294 1 + ATOM 2310 O . LEU A 294 ? 16.52100 -14.63200 -15.97500 1.000 85.94000 O ? A ? 294 1 + ATOM 2311 CB . LEU A 294 ? 16.77500 -11.83800 -15.72200 1.000 85.94000 C ? A ? 294 1 + ATOM 2312 CG . LEU A 294 ? 16.95000 -10.35200 -15.37700 1.000 85.94000 C ? A ? 294 1 + ATOM 2313 CD1 . LEU A 294 ? 15.81000 -9.57100 -16.02400 1.000 85.94000 C ? A ? 294 1 + ATOM 2314 CD2 . LEU A 294 ? 16.92600 -10.08700 -13.87300 1.000 85.94000 C ? A ? 294 1 + ATOM 2315 N . THR A 295 ? 18.15100 -15.14200 -14.53000 1.000 87.62000 N ? A ? 295 1 + ATOM 2316 CA . THR A 295 ? 17.99300 -16.60100 -14.63200 1.000 87.62000 C ? A ? 295 1 + ATOM 2317 C . THR A 295 ? 16.70700 -17.11100 -13.99600 1.000 87.62000 C ? A ? 295 1 + ATOM 2318 O . THR A 295 ? 16.30200 -18.22800 -14.29300 1.000 87.62000 O ? A ? 295 1 + ATOM 2319 CB . THR A 295 ? 19.17500 -17.33700 -13.98800 1.000 87.62000 C ? A ? 295 1 + ATOM 2320 OG1 . THR A 295 ? 19.35700 -16.91400 -12.65500 1.000 87.62000 O ? A ? 295 1 + ATOM 2321 CG2 . THR A 295 ? 20.48200 -17.05700 -14.73100 1.000 87.62000 C ? A ? 295 1 + ATOM 2322 N . SER A 296 ? 16.07000 -16.32400 -13.13200 1.000 93.25000 N ? A ? 296 1 + ATOM 2323 CA . SER A 296 ? 14.85000 -16.71900 -12.41400 1.000 93.25000 C ? A ? 296 1 + ATOM 2324 C . SER A 296 ? 13.57100 -16.19100 -13.06500 1.000 93.25000 C ? A ? 296 1 + ATOM 2325 O . SER A 296 ? 12.48600 -16.58600 -12.64600 1.000 93.25000 O ? A ? 296 1 + ATOM 2326 CB . SER A 296 ? 14.91900 -16.25500 -10.95400 1.000 93.25000 C ? A ? 296 1 + ATOM 2327 OG . SER A 296 ? 16.19600 -16.52600 -10.40100 1.000 93.25000 O ? A ? 296 1 + ATOM 2328 N . LEU A 297 ? 13.68200 -15.32200 -14.08100 1.000 94.44000 N ? A ? 297 1 + ATOM 2329 CA . LEU A 297 ? 12.53700 -14.62000 -14.65600 1.000 94.44000 C ? A ? 297 1 + ATOM 2330 C . LEU A 297 ? 11.65700 -15.58800 -15.44800 1.000 94.44000 C ? A ? 297 1 + ATOM 2331 O . LEU A 297 ? 12.09100 -16.13500 -16.46100 1.000 94.44000 O ? A ? 297 1 + ATOM 2332 CB . LEU A 297 ? 13.02200 -13.43600 -15.51400 1.000 94.44000 C ? A ? 297 1 + ATOM 2333 CG . LEU A 297 ? 11.87200 -12.51600 -15.96600 1.000 94.44000 C ? A ? 297 1 + ATOM 2334 CD1 . LEU A 297 ? 11.40700 -11.61500 -14.82400 1.000 94.44000 C ? A ? 297 1 + ATOM 2335 CD2 . LEU A 297 ? 12.31500 -11.60900 -17.11600 1.000 94.44000 C ? A ? 297 1 + ATOM 2336 N . GLN A 298 ? 10.41900 -15.76100 -14.99100 1.000 95.62000 N ? A ? 298 1 + ATOM 2337 CA . GLN A 298 ? 9.42300 -16.65400 -15.58200 1.000 95.62000 C ? A ? 298 1 + ATOM 2338 C . GLN A 298 ? 8.37300 -15.88300 -16.38100 1.000 95.62000 C ? A ? 298 1 + ATOM 2339 O . GLN A 298 ? 7.94500 -16.36600 -17.43100 1.000 95.62000 O ? A ? 298 1 + ATOM 2340 CB . GLN A 298 ? 8.74600 -17.47300 -14.47600 1.000 95.62000 C ? A ? 298 1 + ATOM 2341 CG . GLN A 298 ? 9.72600 -18.44100 -13.80200 1.000 95.62000 C ? A ? 298 1 + ATOM 2342 CD . GLN A 298 ? 9.09400 -19.22300 -12.66000 1.000 95.62000 C ? A ? 298 1 + ATOM 2343 OE1 . GLN A 298 ? 7.92800 -19.57600 -12.66600 1.000 95.62000 O ? A ? 298 1 + ATOM 2344 NE2 . GLN A 298 ? 9.85300 -19.55500 -11.63900 1.000 95.62000 N ? A ? 298 1 + ATOM 2345 N . SER A 299 ? 8.00400 -14.68300 -15.92500 1.000 96.06000 N ? A ? 299 1 + ATOM 2346 CA . SER A 299 ? 6.95600 -13.85900 -16.52700 1.000 96.06000 C ? A ? 299 1 + ATOM 2347 C . SER A 299 ? 7.46700 -12.46500 -16.88700 1.000 96.06000 C ? A ? 299 1 + ATOM 2348 O . SER A 299 ? 8.02700 -11.75100 -16.05100 1.000 96.06000 O ? A ? 299 1 + ATOM 2349 CB . SER A 299 ? 5.77900 -13.76000 -15.56300 1.000 96.06000 C ? A ? 299 1 + ATOM 2350 OG . SER A 299 ? 4.69400 -13.08800 -16.16900 1.000 96.06000 O ? A ? 299 1 + ATOM 2351 N . LEU A 300 ? 7.25500 -12.06700 -18.14300 1.000 93.25000 N ? A ? 300 1 + ATOM 2352 CA . LEU A 300 ? 7.51900 -10.71800 -18.63900 1.000 93.25000 C ? A ? 300 1 + ATOM 2353 C . LEU A 300 ? 6.25100 -10.14500 -19.27400 1.000 93.25000 C ? A ? 300 1 + ATOM 2354 O . LEU A 300 ? 5.78100 -10.63100 -20.30400 1.000 93.25000 O ? A ? 300 1 + ATOM 2355 CB . LEU A 300 ? 8.71800 -10.73700 -19.60600 1.000 93.25000 C ? A ? 300 1 + ATOM 2356 CG . LEU A 300 ? 9.06200 -9.37100 -20.23200 1.000 93.25000 C ? A ? 300 1 + ATOM 2357 CD1 . LEU A 300 ? 9.38400 -8.29800 -19.19000 1.000 93.25000 C ? A ? 300 1 + ATOM 2358 CD2 . LEU A 300 ? 10.28800 -9.51100 -21.13900 1.000 93.25000 C ? A ? 300 1 + ATOM 2359 N . VAL A 301 ? 5.73100 -9.07300 -18.68300 1.000 93.00000 N ? A ? 301 1 + ATOM 2360 CA . VAL A 301 ? 4.58100 -8.32700 -19.19600 1.000 93.00000 C ? A ? 301 1 + ATOM 2361 C . VAL A 301 ? 5.04200 -6.96100 -19.68300 1.000 93.00000 C ? A ? 301 1 + ATOM 2362 O . VAL A 301 ? 5.68200 -6.20400 -18.95300 1.000 93.00000 O ? A ? 301 1 + ATOM 2363 CB . VAL A 301 ? 3.45900 -8.21400 -18.15000 1.000 93.00000 C ? A ? 301 1 + ATOM 2364 CG1 . VAL A 301 ? 2.24100 -7.47700 -18.72500 1.000 93.00000 C ? A ? 301 1 + ATOM 2365 CG2 . VAL A 301 ? 2.99600 -9.59800 -17.67700 1.000 93.00000 C ? A ? 301 1 + ATOM 2366 N . MET A 302 ? 4.69600 -6.63000 -20.92300 1.000 90.88000 N ? A ? 302 1 + ATOM 2367 CA . MET A 302 ? 4.96800 -5.33300 -21.52500 1.000 90.88000 C ? A ? 302 1 + ATOM 2368 C . MET A 302 ? 3.70100 -4.70700 -22.08400 1.000 90.88000 C ? A ? 302 1 + ATOM 2369 O . MET A 302 ? 2.96100 -5.35700 -22.82300 1.000 90.88000 O ? A ? 302 1 + ATOM 2370 CB . MET A 302 ? 6.02000 -5.44100 -22.62400 1.000 90.88000 C ? A ? 302 1 + ATOM 2371 CG . MET A 302 ? 7.38000 -5.88700 -22.08300 1.000 90.88000 C ? A ? 302 1 + ATOM 2372 SD . MET A 302 ? 8.72200 -5.66700 -23.27900 1.000 90.88000 S ? A ? 302 1 + ATOM 2373 CE . MET A 302 ? 8.84200 -3.86000 -23.21100 1.000 90.88000 C ? A ? 302 1 + ATOM 2374 N . TYR A 303 ? 3.47600 -3.42900 -21.79200 1.000 91.75000 N ? A ? 303 1 + ATOM 2375 CA . TYR A 303 ? 2.33200 -2.73000 -22.36400 1.000 91.75000 C ? A ? 303 1 + ATOM 2376 C . TYR A 303 ? 2.52800 -1.24600 -22.61100 1.000 91.75000 C ? A ? 303 1 + ATOM 2377 O . TYR A 303 ? 3.38800 -0.62300 -21.99900 1.000 91.75000 O ? A ? 303 1 + ATOM 2378 CB . TYR A 303 ? 1.09400 -2.97200 -21.52100 1.000 91.75000 C ? A ? 303 1 + ATOM 2379 CG . TYR A 303 ? 1.09400 -2.40800 -20.12000 1.000 91.75000 C ? A ? 303 1 + ATOM 2380 CD1 . TYR A 303 ? 1.68900 -3.13200 -19.07100 1.000 91.75000 C ? A ? 303 1 + ATOM 2381 CD2 . TYR A 303 ? 0.46900 -1.17200 -19.86300 1.000 91.75000 C ? A ? 303 1 + ATOM 2382 CE1 . TYR A 303 ? 1.69900 -2.59700 -17.77200 1.000 91.75000 C ? A ? 303 1 + ATOM 2383 CE2 . TYR A 303 ? 0.46200 -0.65300 -18.55700 1.000 91.75000 C ? A ? 303 1 + ATOM 2384 CZ . TYR A 303 ? 1.10000 -1.34900 -17.51500 1.000 91.75000 C ? A ? 303 1 + ATOM 2385 OH . TYR A 303 ? 1.19500 -0.79700 -16.27900 1.000 91.75000 O ? A ? 303 1 + ATOM 2386 N . GLY A 304 ? 1.73300 -0.66800 -23.51400 1.000 89.94000 N ? A ? 304 1 + ATOM 2387 CA . GLY A 304 ? 1.68400 0.78100 -23.73400 1.000 89.94000 C ? A ? 304 1 + ATOM 2388 C . GLY A 304 ? 3.02400 1.38800 -24.16000 1.000 89.94000 C ? A ? 304 1 + ATOM 2389 O . GLY A 304 ? 3.35700 2.50500 -23.76900 1.000 89.94000 O ? A ? 304 1 + ATOM 2390 N . CYS A 305 ? 3.84700 0.65100 -24.91300 1.000 89.69000 N ? A ? 305 1 + ATOM 2391 CA . CYS A 305 ? 5.17900 1.09400 -25.34100 1.000 89.69000 C ? A ? 305 1 + ATOM 2392 C . CYS A 305 ? 5.19800 1.35700 -26.86000 1.000 89.69000 C ? A ? 305 1 + ATOM 2393 O . CYS A 305 ? 5.66800 0.51700 -27.63500 1.000 89.69000 O ? A ? 305 1 + ATOM 2394 CB . CYS A 305 ? 6.24200 0.08200 -24.89500 1.000 89.69000 C ? A ? 305 1 + ATOM 2395 SG . CYS A 305 ? 6.31800 -0.01500 -23.08400 1.000 89.69000 S ? A ? 305 1 + ATOM 2396 N . PRO A 306 ? 4.72200 2.52800 -27.33000 1.000 88.94000 N ? A ? 306 1 + ATOM 2397 CA . PRO A 306 ? 4.43900 2.76300 -28.74500 1.000 88.94000 C ? A ? 306 1 + ATOM 2398 C . PRO A 306 ? 5.67200 2.78800 -29.65000 1.000 88.94000 C ? A ? 306 1 + ATOM 2399 O . PRO A 306 ? 5.55300 2.53700 -30.84400 1.000 88.94000 O ? A ? 306 1 + ATOM 2400 CB . PRO A 306 ? 3.66800 4.08600 -28.79400 1.000 88.94000 C ? A ? 306 1 + ATOM 2401 CG . PRO A 306 ? 4.12100 4.81200 -27.52900 1.000 88.94000 C ? A ? 306 1 + ATOM 2402 CD . PRO A 306 ? 4.26600 3.66200 -26.53900 1.000 88.94000 C ? A ? 306 1 + ATOM 2403 N . LYS A 307 ? 6.86300 3.09000 -29.11900 1.000 88.94000 N ? A ? 307 1 + ATOM 2404 CA . LYS A 307 ? 8.10700 3.18300 -29.90900 1.000 88.94000 C ? A ? 307 1 + ATOM 2405 C . LYS A 307 ? 9.00600 1.95200 -29.79400 1.000 88.94000 C ? A ? 307 1 + ATOM 2406 O . LYS A 307 ? 10.08200 1.95100 -30.39700 1.000 88.94000 O ? A ? 307 1 + ATOM 2407 CB . LYS A 307 ? 8.85400 4.48400 -29.57400 1.000 88.94000 C ? A ? 307 1 + ATOM 2408 CG . LYS A 307 ? 8.03300 5.71700 -29.97900 1.000 88.94000 C ? A ? 307 1 + ATOM 2409 CD . LYS A 307 ? 8.84200 7.00700 -29.81400 1.000 88.94000 C ? A ? 307 1 + ATOM 2410 CE . LYS A 307 ? 7.91400 8.21000 -30.02100 1.000 88.94000 C ? A ? 307 1 + ATOM 2411 NZ . LYS A 307 ? 8.53100 9.48300 -29.57500 1.000 88.94000 N ? A ? 307 1 + ATOM 2412 N . LEU A 308 ? 8.58700 0.92600 -29.05200 1.000 88.56000 N ? A ? 308 1 + ATOM 2413 CA . LEU A 308 ? 9.38700 -0.26500 -28.79500 1.000 88.56000 C ? A ? 308 1 + ATOM 2414 C . LEU A 308 ? 9.57800 -1.08300 -30.07900 1.000 88.56000 C ? A ? 308 1 + ATOM 2415 O . LEU A 308 ? 8.61900 -1.55100 -30.68500 1.000 88.56000 O ? A ? 308 1 + ATOM 2416 CB . LEU A 308 ? 8.70600 -1.08400 -27.69200 1.000 88.56000 C ? A ? 308 1 + ATOM 2417 CG . LEU A 308 ? 9.52200 -2.30400 -27.23800 1.000 88.56000 C ? A ? 308 1 + ATOM 2418 CD1 . LEU A 308 ? 10.73700 -1.90100 -26.39600 1.000 88.56000 C ? A ? 308 1 + ATOM 2419 CD2 . LEU A 308 ? 8.61700 -3.21400 -26.42200 1.000 88.56000 C ? A ? 308 1 + ATOM 2420 N . LYS A 309 ? 10.83600 -1.26800 -30.48500 1.000 86.88000 N ? A ? 309 1 + ATOM 2421 CA . LYS A 309 ? 11.22700 -1.99600 -31.70100 1.000 86.88000 C ? A ? 309 1 + ATOM 2422 C . LYS A 309 ? 11.75800 -3.39600 -31.42300 1.000 86.88000 C ? A ? 309 1 + ATOM 2423 O . LYS A 309 ? 11.73400 -4.23900 -32.31200 1.000 86.88000 O ? A ? 309 1 + ATOM 2424 CB . LYS A 309 ? 12.29800 -1.20000 -32.46000 1.000 86.88000 C ? A ? 309 1 + ATOM 2425 CG . LYS A 309 ? 11.79000 0.16100 -32.94600 1.000 86.88000 C ? A ? 309 1 + ATOM 2426 CD . LYS A 309 ? 12.84200 0.84100 -33.82600 1.000 86.88000 C ? A ? 309 1 + ATOM 2427 CE . LYS A 309 ? 12.28600 2.17200 -34.34000 1.000 86.88000 C ? A ? 309 1 + ATOM 2428 NZ . LYS A 309 ? 13.22200 2.81300 -35.30000 1.000 86.88000 N ? A ? 309 1 + ATOM 2429 N . SER A 310 ? 12.29600 -3.63500 -30.22900 1.000 84.25000 N ? A ? 310 1 + ATOM 2430 CA . SER A 310 ? 12.95100 -4.90000 -29.89800 1.000 84.25000 C ? A ? 310 1 + ATOM 2431 C . SER A 310 ? 12.94000 -5.19300 -28.40300 1.000 84.25000 C ? A ? 310 1 + ATOM 2432 O . SER A 310 ? 13.17800 -4.29500 -27.59300 1.000 84.25000 O ? A ? 310 1 + ATOM 2433 CB . SER A 310 ? 14.40600 -4.88600 -30.38300 1.000 84.25000 C ? A ? 310 1 + ATOM 2434 OG . SER A 310 ? 15.15400 -3.87200 -29.73700 1.000 84.25000 O ? A ? 310 1 + ATOM 2435 N . ILE A 311 ? 12.78800 -6.47500 -28.07600 1.000 84.06000 N ? A ? 311 1 + ATOM 2436 CA . ILE A 311 ? 12.93100 -7.04900 -26.73200 1.000 84.06000 C ? A ? 311 1 + ATOM 2437 C . ILE A 311 ? 14.23900 -7.86900 -26.61900 1.000 84.06000 C ? A ? 311 1 + ATOM 2438 O . ILE A 311 ? 14.85400 -8.17700 -27.66000 1.000 84.06000 O ? A ? 311 1 + ATOM 2439 CB . ILE A 311 ? 11.66400 -7.86700 -26.37800 1.000 84.06000 C ? A ? 311 1 + ATOM 2440 CG1 . ILE A 311 ? 11.45800 -9.06100 -27.33700 1.000 84.06000 C ? A ? 311 1 + ATOM 2441 CG2 . ILE A 311 ? 10.44000 -6.93400 -26.33900 1.000 84.06000 C ? A ? 311 1 + ATOM 2442 CD1 . ILE A 311 ? 10.32700 -9.99900 -26.90200 1.000 84.06000 C ? A ? 311 1 + ATOM 2443 N . PRO A 312 ? 14.68900 -8.22000 -25.39200 1.000 81.00000 N ? A ? 312 1 + ATOM 2444 CA . PRO A 312 ? 15.86500 -9.06100 -25.17500 1.000 81.00000 C ? A ? 312 1 + ATOM 2445 C . PRO A 312 ? 15.75300 -10.39300 -25.92600 1.000 81.00000 C ? A ? 312 1 + ATOM 2446 O . PRO A 312 ? 14.65700 -10.86900 -26.22900 1.000 81.00000 O ? A ? 312 1 + ATOM 2447 CB . PRO A 312 ? 15.98500 -9.25400 -23.65800 1.000 81.00000 C ? A ? 312 1 + ATOM 2448 CG . PRO A 312 ? 15.26200 -8.03400 -23.09200 1.000 81.00000 C ? A ? 312 1 + ATOM 2449 CD . PRO A 312 ? 14.13100 -7.85300 -24.09800 1.000 81.00000 C ? A ? 312 1 + ATOM 2450 N . ARG A 313 ? 16.89400 -10.97100 -26.31400 1.000 79.19000 N ? A ? 313 1 + ATOM 2451 CA . ARG A 313 ? 16.89400 -12.25100 -27.03600 1.000 79.19000 C ? A ? 313 1 + ATOM 2452 C . ARG A 313 ? 16.58900 -13.40900 -26.08500 1.000 79.19000 C ? A ? 313 1 + ATOM 2453 O . ARG A 313 ? 16.83900 -13.30300 -24.88800 1.000 79.19000 O ? A ? 313 1 + ATOM 2454 CB . ARG A 313 ? 18.21100 -12.49800 -27.77500 1.000 79.19000 C ? A ? 313 1 + ATOM 2455 CG . ARG A 313 ? 18.63400 -11.40900 -28.76200 1.000 79.19000 C ? A ? 313 1 + ATOM 2456 CD . ARG A 313 ? 19.89900 -11.87100 -29.49300 1.000 79.19000 C ? A ? 313 1 + ATOM 2457 NE . ARG A 313 ? 20.29600 -10.91900 -30.55100 1.000 79.19000 N ? A ? 313 1 + ATOM 2458 CZ . ARG A 313 ? 21.42000 -10.97300 -31.24400 1.000 79.19000 C ? A ? 313 1 + ATOM 2459 NH1 . ARG A 313 ? 22.31400 -11.89500 -31.02900 1.000 79.19000 N ? A ? 313 1 + ATOM 2460 NH2 . ARG A 313 ? 21.66700 -10.09500 -32.17600 1.000 79.19000 N ? A ? 313 1 + ATOM 2461 N . LYS A 314 ? 16.09200 -14.52200 -26.63100 1.000 76.81000 N ? A ? 314 1 + ATOM 2462 CA . LYS A 314 ? 15.72600 -15.71400 -25.85100 1.000 76.81000 C ? A ? 314 1 + ATOM 2463 C . LYS A 314 ? 16.90100 -16.24600 -25.02900 1.000 76.81000 C ? A ? 314 1 + ATOM 2464 O . LYS A 314 ? 16.70000 -16.65600 -23.89500 1.000 76.81000 O ? A ? 314 1 + ATOM 2465 CB . LYS A 314 ? 15.18300 -16.79200 -26.80200 1.000 76.81000 C ? A ? 314 1 + ATOM 2466 CG . LYS A 314 ? 14.69700 -18.03100 -26.03400 1.000 76.81000 C ? A ? 314 1 + ATOM 2467 CD . LYS A 314 ? 14.18400 -19.12000 -26.98000 1.000 76.81000 C ? A ? 314 1 + ATOM 2468 CE . LYS A 314 ? 13.79600 -20.34500 -26.14300 1.000 76.81000 C ? A ? 314 1 + ATOM 2469 NZ . LYS A 314 ? 13.35300 -21.47900 -26.99000 1.000 76.81000 N ? A ? 314 1 + ATOM 2470 N . GLU A 315 ? 18.12400 -16.18100 -25.55900 1.000 79.81000 N ? A ? 315 1 + ATOM 2471 CA . GLU A 315 ? 19.32200 -16.66200 -24.85500 1.000 79.81000 C ? A ? 315 1 + ATOM 2472 C . GLU A 315 ? 19.60500 -15.88000 -23.56100 1.000 79.81000 C ? A ? 315 1 + ATOM 2473 O . GLU A 315 ? 20.31900 -16.36500 -22.69100 1.000 79.81000 O ? A ? 315 1 + ATOM 2474 CB . GLU A 315 ? 20.56200 -16.59500 -25.76900 1.000 79.81000 C ? A ? 315 1 + ATOM 2475 CG . GLU A 315 ? 20.42400 -17.29500 -27.13700 1.000 79.81000 C ? A ? 315 1 + ATOM 2476 CD . GLU A 315 ? 19.66200 -16.47500 -28.19300 1.000 79.81000 C ? A ? 315 1 + ATOM 2477 OE1 . GLU A 315 ? 19.21800 -17.06200 -29.19900 1.000 79.81000 O ? A ? 315 1 + ATOM 2478 OE2 . GLU A 315 ? 19.46000 -15.25600 -27.97900 1.000 79.81000 O ? A ? 315 1 + ATOM 2479 N . MET A 316 ? 19.03800 -14.67800 -23.41900 1.000 77.44000 N ? A ? 316 1 + ATOM 2480 CA . MET A 316 ? 19.19000 -13.83100 -22.23500 1.000 77.44000 C ? A ? 316 1 + ATOM 2481 C . MET A 316 ? 18.15500 -14.11700 -21.14600 1.000 77.44000 C ? A ? 316 1 + ATOM 2482 O . MET A 316 ? 18.35000 -13.70700 -20.00600 1.000 77.44000 O ? A ? 316 1 + ATOM 2483 CB . MET A 316 ? 19.07700 -12.36100 -22.64200 1.000 77.44000 C ? A ? 316 1 + ATOM 2484 CG . MET A 316 ? 20.08300 -11.98500 -23.73700 1.000 77.44000 C ? A ? 316 1 + ATOM 2485 SD . MET A 316 ? 20.18800 -10.20800 -24.06000 1.000 77.44000 S ? A ? 316 1 + ATOM 2486 CE . MET A 316 ? 20.77000 -9.72500 -22.41400 1.000 77.44000 C ? A ? 316 1 + ATOM 2487 N . LEU A 317 ? 17.05900 -14.78900 -21.49900 1.000 84.00000 N ? A ? 317 1 + ATOM 2488 CA . LEU A 317 ? 15.90700 -15.04000 -20.63700 1.000 84.00000 C ? A ? 317 1 + ATOM 2489 C . LEU A 317 ? 15.62400 -16.55300 -20.60100 1.000 84.00000 C ? A ? 317 1 + ATOM 2490 O . LEU A 317 ? 14.60300 -17.00100 -21.12600 1.000 84.00000 O ? A ? 317 1 + ATOM 2491 CB . LEU A 317 ? 14.71400 -14.20600 -21.14800 1.000 84.00000 C ? A ? 317 1 + ATOM 2492 CG . LEU A 317 ? 14.92200 -12.68200 -21.16800 1.000 84.00000 C ? A ? 317 1 + ATOM 2493 CD1 . LEU A 317 ? 13.66600 -11.99800 -21.71100 1.000 84.00000 C ? A ? 317 1 + ATOM 2494 CD2 . LEU A 317 ? 15.20000 -12.11000 -19.77800 1.000 84.00000 C ? A ? 317 1 + ATOM 2495 N . PRO A 318 ? 16.54400 -17.36300 -20.03700 1.000 86.44000 N ? A ? 318 1 + ATOM 2496 CA . PRO A 318 ? 16.51800 -18.82000 -20.18200 1.000 86.44000 C ? A ? 318 1 + ATOM 2497 C . PRO A 318 ? 15.30100 -19.48600 -19.52500 1.000 86.44000 C ? A ? 318 1 + ATOM 2498 O . PRO A 318 ? 14.87200 -20.53900 -19.98900 1.000 86.44000 O ? A ? 318 1 + ATOM 2499 CB . PRO A 318 ? 17.83200 -19.30400 -19.55600 1.000 86.44000 C ? A ? 318 1 + ATOM 2500 CG . PRO A 318 ? 18.17200 -18.21600 -18.53700 1.000 86.44000 C ? A ? 318 1 + ATOM 2501 CD . PRO A 318 ? 17.69200 -16.95000 -19.23900 1.000 86.44000 C ? A ? 318 1 + ATOM 2502 N . SER A 319 ? 14.73800 -18.87100 -18.48200 1.000 92.38000 N ? A ? 319 1 + ATOM 2503 CA . SER A 319 ? 13.62300 -19.41700 -17.69200 1.000 92.38000 C ? A ? 319 1 + ATOM 2504 C . SER A 319 ? 12.25900 -18.82600 -18.05100 1.000 92.38000 C ? A ? 319 1 + ATOM 2505 O . SER A 319 ? 11.25800 -19.18300 -17.43100 1.000 92.38000 O ? A ? 319 1 + ATOM 2506 CB . SER A 319 ? 13.90800 -19.22300 -16.20300 1.000 92.38000 C ? A ? 319 1 + ATOM 2507 OG . SER A 319 ? 15.11900 -19.88200 -15.89200 1.000 92.38000 O ? A ? 319 1 + ATOM 2508 N . LEU A 320 ? 12.20200 -17.93400 -19.04700 1.000 92.50000 N ? A ? 320 1 + ATOM 2509 CA . LEU A 320 ? 10.97400 -17.23400 -19.40500 1.000 92.50000 C ? A ? 320 1 + ATOM 2510 C . LEU A 320 ? 9.96100 -18.21100 -20.01000 1.000 92.50000 C ? A ? 320 1 + ATOM 2511 O . LEU A 320 ? 10.18200 -18.76600 -21.08800 1.000 92.50000 O ? A ? 320 1 + ATOM 2512 CB . LEU A 320 ? 11.30700 -16.07300 -20.35300 1.000 92.50000 C ? A ? 320 1 + ATOM 2513 CG . LEU A 320 ? 10.12800 -15.10900 -20.56800 1.000 92.50000 C ? A ? 320 1 + ATOM 2514 CD1 . LEU A 320 ? 9.96800 -14.17300 -19.37200 1.000 92.50000 C ? A ? 320 1 + ATOM 2515 CD2 . LEU A 320 ? 10.36700 -14.24700 -21.80900 1.000 92.50000 C ? A ? 320 1 + ATOM 2516 N . SER A 321 ? 8.83700 -18.39100 -19.32000 1.000 93.00000 N ? A ? 321 1 + ATOM 2517 CA . SER A 321 ? 7.74000 -19.27200 -19.72600 1.000 93.00000 C ? A ? 321 1 + ATOM 2518 C . SER A 321 ? 6.50900 -18.49200 -20.18800 1.000 93.00000 C ? A ? 321 1 + ATOM 2519 O . SER A 321 ? 5.73300 -18.99900 -20.99700 1.000 93.00000 O ? A ? 321 1 + ATOM 2520 CB . SER A 321 ? 7.39500 -20.21000 -18.56600 1.000 93.00000 C ? A ? 321 1 + ATOM 2521 OG . SER A 321 ? 6.90800 -19.47300 -17.46100 1.000 93.00000 O ? A ? 321 1 + ATOM 2522 N . GLN A 322 ? 6.35300 -17.24700 -19.72700 1.000 93.38000 N ? A ? 322 1 + ATOM 2523 CA . GLN A 322 ? 5.24100 -16.36700 -20.06700 1.000 93.38000 C ? A ? 322 1 + ATOM 2524 C . GLN A 322 ? 5.75500 -15.02000 -20.58600 1.000 93.38000 C ? A ? 322 1 + ATOM 2525 O . GLN A 322 ? 6.52900 -14.32600 -19.92700 1.000 93.38000 O ? A ? 322 1 + ATOM 2526 CB . GLN A 322 ? 4.31700 -16.19400 -18.85200 1.000 93.38000 C ? A ? 322 1 + ATOM 2527 CG . GLN A 322 ? 3.70400 -17.53000 -18.39400 1.000 93.38000 C ? A ? 322 1 + ATOM 2528 CD . GLN A 322 ? 2.68300 -17.37000 -17.27500 1.000 93.38000 C ? A ? 322 1 + ATOM 2529 OE1 . GLN A 322 ? 2.30800 -16.28800 -16.86300 1.000 93.38000 O ? A ? 322 1 + ATOM 2530 NE2 . GLN A 322 ? 2.16300 -18.45600 -16.74600 1.000 93.38000 N ? A ? 322 1 + ATOM 2531 N . LEU A 323 ? 5.30700 -14.64500 -21.78500 1.000 92.25000 N ? A ? 323 1 + ATOM 2532 CA . LEU A 323 ? 5.57100 -13.34300 -22.38900 1.000 92.25000 C ? A ? 323 1 + ATOM 2533 C . LEU A 323 ? 4.25400 -12.75500 -22.87900 1.000 92.25000 C ? A ? 323 1 + ATOM 2534 O . LEU A 323 ? 3.64000 -13.29000 -23.80300 1.000 92.25000 O ? A ? 323 1 + ATOM 2535 CB . LEU A 323 ? 6.59100 -13.48100 -23.53200 1.000 92.25000 C ? A ? 323 1 + ATOM 2536 CG . LEU A 323 ? 6.85800 -12.16700 -24.29500 1.000 92.25000 C ? A ? 323 1 + ATOM 2537 CD1 . LEU A 323 ? 7.45600 -11.07800 -23.40400 1.000 92.25000 C ? A ? 323 1 + ATOM 2538 CD2 . LEU A 323 ? 7.83500 -12.43300 -25.44100 1.000 92.25000 C ? A ? 323 1 + ATOM 2539 N . THR A 324 ? 3.87000 -11.62400 -22.30000 1.000 92.56000 N ? A ? 324 1 + ATOM 2540 CA . THR A 324 ? 2.64500 -10.92300 -22.67200 1.000 92.56000 C ? A ? 324 1 + ATOM 2541 C . THR A 324 ? 2.98600 -9.52200 -23.15000 1.000 92.56000 C ? A ? 324 1 + ATOM 2542 O . THR A 324 ? 3.64300 -8.76400 -22.44200 1.000 92.56000 O ? A ? 324 1 + ATOM 2543 CB . THR A 324 ? 1.65100 -10.90400 -21.51200 1.000 92.56000 C ? A ? 324 1 + ATOM 2544 OG1 . THR A 324 ? 1.40300 -12.21200 -21.05600 1.000 92.56000 O ? A ? 324 1 + ATOM 2545 CG2 . THR A 324 ? 0.31700 -10.36700 -21.99200 1.000 92.56000 C ? A ? 324 1 + ATOM 2546 N . ILE A 325 ? 2.55300 -9.17800 -24.36400 1.000 91.31000 N ? A ? 325 1 + ATOM 2547 CA . ILE A 325 ? 2.79600 -7.86700 -24.97000 1.000 91.31000 C ? A ? 325 1 + ATOM 2548 C . ILE A 325 ? 1.48500 -7.34400 -25.55000 1.000 91.31000 C ? A ? 325 1 + ATOM 2549 O . ILE A 325 ? 0.89800 -7.99100 -26.41600 1.000 91.31000 O ? A ? 325 1 + ATOM 2550 CB . ILE A 325 ? 3.91100 -7.91500 -26.04100 1.000 91.31000 C ? A ? 325 1 + ATOM 2551 CG1 . ILE A 325 ? 5.19200 -8.58700 -25.49300 1.000 91.31000 C ? A ? 325 1 + ATOM 2552 CG2 . ILE A 325 ? 4.20000 -6.48400 -26.53700 1.000 91.31000 C ? A ? 325 1 + ATOM 2553 CD1 . ILE A 325 ? 6.36400 -8.63300 -26.47700 1.000 91.31000 C ? A ? 325 1 + ATOM 2554 N . TRP A 326 ? 1.05000 -6.16100 -25.12100 1.000 92.81000 N ? A ? 326 1 + ATOM 2555 CA . TRP A 326 ? -0.08800 -5.46400 -25.72500 1.000 92.81000 C ? A ? 326 1 + ATOM 2556 C . TRP A 326 ? 0.20800 -3.97300 -25.91000 1.000 92.81000 C ? A ? 326 1 + ATOM 2557 O . TRP A 326 ? 1.10200 -3.42200 -25.28000 1.000 92.81000 O ? A ? 326 1 + ATOM 2558 CB . TRP A 326 ? -1.37500 -5.74900 -24.93600 1.000 92.81000 C ? A ? 326 1 + ATOM 2559 CG . TRP A 326 ? -1.43300 -5.29300 -23.50900 1.000 92.81000 C ? A ? 326 1 + ATOM 2560 CD1 . TRP A 326 ? -1.59800 -4.01300 -23.10600 1.000 92.81000 C ? A ? 326 1 + ATOM 2561 CD2 . TRP A 326 ? -1.42000 -6.09000 -22.28100 1.000 92.81000 C ? A ? 326 1 + ATOM 2562 NE1 . TRP A 326 ? -1.67800 -3.96900 -21.72900 1.000 92.81000 N ? A ? 326 1 + ATOM 2563 CE2 . TRP A 326 ? -1.46500 -5.20300 -21.16600 1.000 92.81000 C ? A ? 326 1 + ATOM 2564 CE3 . TRP A 326 ? -1.42700 -7.46800 -21.98300 1.000 92.81000 C ? A ? 326 1 + ATOM 2565 CZ2 . TRP A 326 ? -1.36700 -5.63400 -19.83700 1.000 92.81000 C ? A ? 326 1 + ATOM 2566 CZ3 . TRP A 326 ? -1.41000 -7.91700 -20.64500 1.000 92.81000 C ? A ? 326 1 + ATOM 2567 CH2 . TRP A 326 ? -1.33000 -7.01000 -19.57700 1.000 92.81000 C ? A ? 326 1 + ATOM 2568 N . ASP A 327 ? -0.49700 -3.31400 -26.83000 1.000 91.31000 N ? A ? 327 1 + ATOM 2569 CA . ASP A 327 ? -0.31300 -1.88100 -27.11900 1.000 91.31000 C ? A ? 327 1 + ATOM 2570 C . ASP A 327 ? 1.16000 -1.46800 -27.39600 1.000 91.31000 C ? A ? 327 1 + ATOM 2571 O . ASP A 327 ? 1.69100 -0.48100 -26.88400 1.000 91.31000 O ? A ? 327 1 + ATOM 2572 CB . ASP A 327 ? -1.03500 -1.05500 -26.04100 1.000 91.31000 C ? A ? 327 1 + ATOM 2573 CG . ASP A 327 ? -1.23600 0.40300 -26.46000 1.000 91.31000 C ? A ? 327 1 + ATOM 2574 OD1 . ASP A 327 ? -1.32600 0.64300 -27.68700 1.000 91.31000 O ? A ? 327 1 + ATOM 2575 OD2 . ASP A 327 ? -1.30700 1.25000 -25.54600 1.000 91.31000 O ? A ? 327 1 + ATOM 2576 N . CYS A 328 ? 1.85800 -2.28500 -28.19700 1.000 90.44000 N ? A ? 328 1 + ATOM 2577 CA . CYS A 328 ? 3.23400 -2.05600 -28.66900 1.000 90.44000 C ? A ? 328 1 + ATOM 2578 C . CYS A 328 ? 3.29700 -2.11500 -30.21500 1.000 90.44000 C ? A ? 328 1 + ATOM 2579 O . CYS A 328 ? 3.88600 -3.04200 -30.77500 1.000 90.44000 O ? A ? 328 1 + ATOM 2580 CB . CYS A 328 ? 4.18900 -3.06500 -28.01100 1.000 90.44000 C ? A ? 328 1 + ATOM 2581 SG . CYS A 328 ? 4.23600 -2.84500 -26.20800 1.000 90.44000 S ? A ? 328 1 + ATOM 2582 N . PRO A 329 ? 2.67700 -1.15900 -30.93500 1.000 88.50000 N ? A ? 329 1 + ATOM 2583 CA . PRO A 329 ? 2.38800 -1.24900 -32.37400 1.000 88.50000 C ? A ? 329 1 + ATOM 2584 C . PRO A 329 ? 3.60300 -1.38700 -33.30500 1.000 88.50000 C ? A ? 329 1 + ATOM 2585 O . PRO A 329 ? 3.46300 -1.87800 -34.42200 1.000 88.50000 O ? A ? 329 1 + ATOM 2586 CB . PRO A 329 ? 1.60800 0.03600 -32.69700 1.000 88.50000 C ? A ? 329 1 + ATOM 2587 CG . PRO A 329 ? 1.97700 1.00000 -31.56700 1.000 88.50000 C ? A ? 329 1 + ATOM 2588 CD . PRO A 329 ? 2.06700 0.04100 -30.39000 1.000 88.50000 C ? A ? 329 1 + ATOM 2589 N . VAL A 330 ? 4.79200 -0.94000 -32.89000 1.000 89.06000 N ? A ? 330 1 + ATOM 2590 CA . VAL A 330 ? 6.00000 -0.93200 -33.74400 1.000 89.06000 C ? A ? 330 1 + ATOM 2591 C . VAL A 330 ? 6.85600 -2.19400 -33.55100 1.000 89.06000 C ? A ? 330 1 + ATOM 2592 O . VAL A 330 ? 7.82700 -2.40400 -34.28400 1.000 89.06000 O ? A ? 330 1 + ATOM 2593 CB . VAL A 330 ? 6.79200 0.38200 -33.55200 1.000 89.06000 C ? A ? 330 1 + ATOM 2594 CG1 . VAL A 330 ? 7.93100 0.57500 -34.56900 1.000 89.06000 C ? A ? 330 1 + ATOM 2595 CG2 . VAL A 330 ? 5.88400 1.60500 -33.75400 1.000 89.06000 C ? A ? 330 1 + ATOM 2596 N . LEU A 331 ? 6.49700 -3.06200 -32.59900 1.000 84.38000 N ? A ? 331 1 + ATOM 2597 CA . LEU A 331 ? 7.22000 -4.30000 -32.33900 1.000 84.38000 C ? A ? 331 1 + ATOM 2598 C . LEU A 331 ? 6.98000 -5.28400 -33.49000 1.000 84.38000 C ? A ? 331 1 + ATOM 2599 O . LEU A 331 ? 5.91800 -5.88900 -33.61300 1.000 84.38000 O ? A ? 331 1 + ATOM 2600 CB . LEU A 331 ? 6.79800 -4.86000 -30.96900 1.000 84.38000 C ? A ? 331 1 + ATOM 2601 CG . LEU A 331 ? 7.67500 -6.03500 -30.50200 1.000 84.38000 C ? A ? 331 1 + ATOM 2602 CD1 . LEU A 331 ? 9.09400 -5.58600 -30.13700 1.000 84.38000 C ? A ? 331 1 + ATOM 2603 CD2 . LEU A 331 ? 7.06700 -6.68100 -29.26400 1.000 84.38000 C ? A ? 331 1 + ATOM 2604 N . LYS A 332 ? 7.98200 -5.43800 -34.35700 1.000 69.94000 N ? A ? 332 1 + ATOM 2605 CA . LYS A 332 ? 7.93100 -6.39400 -35.46600 1.000 69.94000 C ? A ? 332 1 + ATOM 2606 C . LYS A 332 ? 8.32300 -7.78600 -34.97900 1.000 69.94000 C ? A ? 332 1 + ATOM 2607 O . LYS A 332 ? 9.22700 -7.92900 -34.15400 1.000 69.94000 O ? A ? 332 1 + ATOM 2608 CB . LYS A 332 ? 8.80400 -5.92500 -36.63700 1.000 69.94000 C ? A ? 332 1 + ATOM 2609 CG . LYS A 332 ? 8.28000 -4.61500 -37.24500 1.000 69.94000 C ? A ? 332 1 + ATOM 2610 CD . LYS A 332 ? 9.06700 -4.25500 -38.50800 1.000 69.94000 C ? A ? 332 1 + ATOM 2611 CE . LYS A 332 ? 8.51400 -2.96600 -39.12400 1.000 69.94000 C ? A ? 332 1 + ATOM 2612 NZ . LYS A 332 ? 9.15100 -2.69000 -40.43600 1.000 69.94000 N ? A ? 332 1 + ATOM 2613 N . LYS A 333 ? 7.67000 -8.81300 -35.52600 1.000 56.16000 N ? A ? 333 1 + ATOM 2614 CA . LYS A 333 ? 8.11000 -10.20500 -35.37900 1.000 56.16000 C ? A ? 333 1 + ATOM 2615 C . LYS A 333 ? 9.52800 -10.30400 -35.96200 1.000 56.16000 C ? A ? 333 1 + ATOM 2616 O . LYS A 333 ? 9.77000 -9.76000 -37.03500 1.000 56.16000 O ? A ? 333 1 + ATOM 2617 CB . LYS A 333 ? 7.09000 -11.12300 -36.08200 1.000 56.16000 C ? A ? 333 1 + ATOM 2618 CG . LYS A 333 ? 7.06500 -12.54800 -35.51000 1.000 56.16000 C ? A ? 333 1 + ATOM 2619 CD . LYS A 333 ? 5.93500 -13.36300 -36.16000 1.000 56.16000 C ? A ? 333 1 + ATOM 2620 CE . LYS A 333 ? 5.85300 -14.76400 -35.54000 1.000 56.16000 C ? A ? 333 1 + ATOM 2621 NZ . LYS A 333 ? 4.79900 -15.58500 -36.18800 1.000 56.16000 N ? A ? 333 1 + ATOM 2622 N . ARG A 334 ? 10.47500 -10.89700 -35.22600 1.000 56.28000 N ? A ? 334 1 + ATOM 2623 CA . ARG A 334 ? 11.79300 -11.22400 -35.79400 1.000 56.28000 C ? A ? 334 1 + ATOM 2624 C . ARG A 334 ? 11.57700 -12.34100 -36.81800 1.000 56.28000 C ? A ? 334 1 + ATOM 2625 O . ARG A 334 ? 10.92400 -13.32200 -36.46100 1.000 56.28000 O ? A ? 334 1 + ATOM 2626 CB . ARG A 334 ? 12.80200 -11.64200 -34.70600 1.000 56.28000 C ? A ? 334 1 + ATOM 2627 CG . ARG A 334 ? 13.44700 -10.44700 -33.98300 1.000 56.28000 C ? A ? 334 1 + ATOM 2628 CD . ARG A 334 ? 14.47300 -10.93000 -32.94100 1.000 56.28000 C ? A ? 334 1 + ATOM 2629 NE . ARG A 334 ? 15.19900 -9.80500 -32.30100 1.000 56.28000 N ? A ? 334 1 + ATOM 2630 CZ . ARG A 334 ? 15.54200 -9.70100 -31.02500 1.000 56.28000 C ? A ? 334 1 + ATOM 2631 NH1 . ARG A 334 ? 15.33000 -10.65200 -30.16300 1.000 56.28000 N ? A ? 334 1 + ATOM 2632 NH2 . ARG A 334 ? 16.08400 -8.61000 -30.56000 1.000 56.28000 N ? A ? 334 1 + ATOM 2633 N . ASP A 335 ? 12.05800 -12.12300 -38.04000 1.000 37.50000 N ? A ? 335 1 + ATOM 2634 CA . ASP A 335 ? 12.10200 -13.13100 -39.10800 1.000 37.50000 C ? A ? 335 1 + ATOM 2635 C . ASP A 335 ? 13.00300 -14.31200 -38.72900 1.000 37.50000 C ? A ? 335 1 + ATOM 2636 O . ASP A 335 ? 14.03900 -14.07000 -38.05400 1.000 37.50000 O ? A ? 335 1 + ATOM 2637 CB . ASP A 335 ? 12.54800 -12.48300 -40.44100 1.000 37.50000 C ? A ? 335 1 + ATOM 2638 CG . ASP A 335 ? 11.55600 -11.45900 -41.02900 1.000 37.50000 C ? A ? 335 1 + ATOM 2639 OD1 . ASP A 335 ? 10.33100 -11.72600 -41.03000 1.000 37.50000 O ? A ? 335 1 + ATOM 2640 OD2 . ASP A 335 ? 12.03000 -10.38000 -41.46600 1.000 37.50000 O ? A ? 335 1 + ATOM 2641 OXT . ASP A 335 ? 12.59100 -15.43800 -39.08300 1.000 37.50000 O ? A ? 335 1 + diff --git a/mmtbx/regression/pdbs/fibronectin_af_ca_1358_1537.cif b/mmtbx/regression/pdbs/fibronectin_af_ca_1358_1537.cif new file mode 100644 index 0000000000..f12765ad03 --- /dev/null +++ b/mmtbx/regression/pdbs/fibronectin_af_ca_1358_1537.cif @@ -0,0 +1,228 @@ +data_default +loop_ + _struct_asym.id + A + +loop_ + _chem_comp.id + ALA + ARG + ASN + ASP + GLN + GLU + GLY + HIS + ILE + LEU + LYS + MET + PHE + PRO + SER + THR + TRP + TYR + VAL + +loop_ + _atom_site.group_PDB + _atom_site.id + _atom_site.label_atom_id + _atom_site.label_alt_id + _atom_site.label_comp_id + _atom_site.auth_asym_id + _atom_site.auth_seq_id + _atom_site.pdbx_PDB_ins_code + _atom_site.Cartn_x + _atom_site.Cartn_y + _atom_site.Cartn_z + _atom_site.occupancy + _atom_site.B_iso_or_equiv + _atom_site.type_symbol + _atom_site.pdbx_formal_charge + _atom_site.label_asym_id + _atom_site.label_entity_id + _atom_site.label_seq_id + _atom_site.pdbx_PDB_model_num + ATOM 1 CA . VAL AZLONG 1358 ? 14.12100 -42.00400 -31.13500 1.000 76.98000 C ? A ? 1 1 + ATOM 2 CA . PRO AZLONG 1359 ? 14.29100 -45.43900 -29.18200 1.000 77.73000 C ? A ? 2 1 + ATOM 3 CA . PRO AZLONG 1360 ? 11.26100 -47.17900 -27.33800 1.000 80.13000 C ? A ? 3 1 + ATOM 4 CA . PRO AZLONG 1361 ? 10.80400 -48.85900 -23.79800 1.000 84.60000 C ? A ? 4 1 + ATOM 5 CA . THR AZLONG 1362 ? 10.26400 -52.47800 -22.45200 1.000 82.74000 C ? A ? 5 1 + ATOM 6 CA . ASP AZLONG 1363 ? 8.83400 -54.74900 -19.56000 1.000 83.24000 C ? A ? 6 1 + ATOM 7 CA . LEU AZLONG 1364 ? 5.48400 -53.11700 -18.40300 1.000 88.86000 C ? A ? 7 1 + ATOM 8 CA . ARG AZLONG 1365 ? 4.03900 -54.16300 -14.91800 1.000 88.12000 C ? A ? 8 1 + ATOM 9 CA . PHE AZLONG 1366 ? 1.47800 -53.11700 -12.18400 1.000 89.35000 C ? A ? 9 1 + ATOM 10 CA . THR AZLONG 1367 ? 1.52100 -52.87700 -8.28400 1.000 84.70000 C ? A ? 10 1 + ATOM 11 CA . ASN AZLONG 1368 ? -0.06900 -50.95400 -5.27400 1.000 76.34000 C ? A ? 11 1 + ATOM 12 CA . ILE AZLONG 1369 ? -3.72400 -51.09100 -6.47000 1.000 83.26000 C ? A ? 12 1 + ATOM 13 CA . GLY AZLONG 1370 ? -6.03000 -48.77500 -4.45400 1.000 78.00000 C ? A ? 13 1 + ATOM 14 CA . PRO AZLONG 1371 ? -9.58600 -47.58800 -5.41000 1.000 78.41000 C ? A ? 14 1 + ATOM 15 CA . ASP AZLONG 1372 ? -8.35800 -44.36100 -7.09400 1.000 81.42000 C ? A ? 15 1 + ATOM 16 CA . THR AZLONG 1373 ? -4.70500 -45.45300 -7.47300 1.000 85.06000 C ? A ? 16 1 + ATOM 17 CA . MET AZLONG 1374 ? -2.26300 -47.90500 -9.14000 1.000 88.30000 C ? A ? 17 1 + ATOM 18 CA . ARG AZLONG 1375 ? 1.57800 -48.07900 -9.53000 1.000 89.12000 C ? A ? 18 1 + ATOM 19 CA . VAL AZLONG 1376 ? 2.71300 -48.79700 -13.13200 1.000 90.33000 C ? A ? 19 1 + ATOM 20 CA . THR AZLONG 1377 ? 6.35800 -49.96600 -13.83000 1.000 88.44000 C ? A ? 20 1 + ATOM 21 CA . TRP AZLONG 1378 ? 8.61900 -50.44600 -16.97200 1.000 91.93000 C ? A ? 21 1 + ATOM 22 CA . ALA AZLONG 1379 ? 12.26000 -50.85100 -18.25200 1.000 83.16000 C ? A ? 22 1 + ATOM 23 CA . PRO AZLONG 1380 ? 14.01500 -47.94500 -20.16700 1.000 80.44000 C ? A ? 23 1 + ATOM 24 CA . PRO AZLONG 1381 ? 15.95900 -47.87900 -23.52800 1.000 76.90000 C ? A ? 24 1 + ATOM 25 CA . PRO AZLONG 1382 ? 19.76300 -48.55800 -23.41300 1.000 68.91000 C ? A ? 25 1 + ATOM 26 CA . SER AZLONG 1383 ? 21.28000 -45.60000 -25.37500 1.000 64.27000 C ? A ? 26 1 + ATOM 27 CA . ILE AZLONG 1384 ? 20.00500 -42.01300 -24.71700 1.000 66.98000 C ? A ? 27 1 + ATOM 28 CA . ASP AZLONG 1385 ? 19.19000 -39.28200 -22.10000 1.000 70.77000 C ? A ? 28 1 + ATOM 29 CA . LEU AZLONG 1386 ? 15.49200 -39.00800 -23.05200 1.000 75.16000 C ? A ? 29 1 + ATOM 30 CA . THR AZLONG 1387 ? 13.35000 -35.89200 -22.28900 1.000 77.09000 C ? A ? 30 1 + ATOM 31 CA . ASN AZLONG 1388 ? 10.09300 -37.84800 -21.70700 1.000 84.66000 C ? A ? 31 1 + ATOM 32 CA . PHE AZLONG 1389 ? 8.17200 -41.04200 -21.07300 1.000 88.48000 C ? A ? 32 1 + ATOM 33 CA . LEU AZLONG 1390 ? 4.62600 -40.33300 -22.20700 1.000 87.98000 C ? A ? 33 1 + ATOM 34 CA . VAL AZLONG 1391 ? 2.27500 -42.45100 -20.05900 1.000 90.30000 C ? A ? 34 1 + ATOM 35 CA . ARG AZLONG 1392 ? -1.08800 -42.46300 -21.90400 1.000 89.93000 C ? A ? 35 1 + ATOM 36 CA . TYR AZLONG 1393 ? -3.92000 -44.21900 -19.98300 1.000 91.76000 C ? A ? 36 1 + ATOM 37 CA . SER AZLONG 1394 ? -7.70600 -44.63100 -20.56100 1.000 86.31000 C ? A ? 37 1 + ATOM 38 CA . PRO AZLONG 1395 ? -10.64400 -46.74200 -19.19900 1.000 84.92000 C ? A ? 38 1 + ATOM 39 CA . VAL AZLONG 1396 ? -11.00900 -50.02300 -21.23100 1.000 81.01000 C ? A ? 39 1 + ATOM 40 CA . LYS AZLONG 1397 ? -14.68300 -49.03200 -21.88500 1.000 73.56000 C ? A ? 40 1 + ATOM 41 CA . ASN AZLONG 1398 ? -13.67800 -45.61800 -23.35100 1.000 73.93000 C ? A ? 41 1 + ATOM 42 CA . GLU AZLONG 1399 ? -10.20800 -46.03600 -24.98400 1.000 71.08000 C ? A ? 42 1 + ATOM 43 CA . GLU AZLONG 1400 ? -10.62700 -42.44500 -26.43400 1.000 74.18000 C ? A ? 43 1 + ATOM 44 CA . ASP AZLONG 1401 ? -10.60700 -40.94700 -22.84600 1.000 69.62000 C ? A ? 44 1 + ATOM 45 CA . VAL AZLONG 1402 ? -6.78500 -40.73000 -22.87300 1.000 76.67000 C ? A ? 45 1 + ATOM 46 CA . ALA AZLONG 1403 ? -5.24400 -39.05000 -19.86400 1.000 78.06000 C ? A ? 46 1 + ATOM 47 CA . GLU AZLONG 1404 ? -1.54800 -38.27000 -20.58900 1.000 84.39000 C ? A ? 47 1 + ATOM 48 CA . LEU AZLONG 1405 ? 1.30800 -38.01100 -18.04900 1.000 81.71000 C ? A ? 48 1 + ATOM 49 CA . SER AZLONG 1406 ? 4.74100 -36.56600 -18.96200 1.000 83.83000 C ? A ? 49 1 + ATOM 50 CA . ILE AZLONG 1407 ? 6.93500 -38.02900 -16.30200 1.000 82.33000 C ? A ? 50 1 + ATOM 51 CA . SER AZLONG 1408 ? 10.20100 -35.68800 -15.88600 1.000 77.12000 C ? A ? 51 1 + ATOM 52 CA . PRO AZLONG 1409 ? 13.81700 -37.38500 -15.45000 1.000 76.47000 C ? A ? 52 1 + ATOM 53 CA . SER AZLONG 1410 ? 13.65900 -40.74200 -13.11000 1.000 75.57000 C ? A ? 53 1 + ATOM 54 CA . ASP AZLONG 1411 ? 10.31400 -43.01100 -12.53800 1.000 79.37000 C ? A ? 54 1 + ATOM 55 CA . ASN AZLONG 1412 ? 10.75600 -46.44100 -14.01700 1.000 82.54000 C ? A ? 55 1 + ATOM 56 CA . ALA AZLONG 1413 ? 7.40800 -46.44600 -12.07200 1.000 86.19000 C ? A ? 56 1 + ATOM 57 CA . VAL AZLONG 1414 ? 4.46400 -43.90500 -11.93400 1.000 86.61000 C ? A ? 57 1 + ATOM 58 CA . VAL AZLONG 1415 ? 1.55400 -43.91800 -9.43700 1.000 86.91000 C ? A ? 58 1 + ATOM 59 CA . LEU AZLONG 1416 ? -1.59200 -43.19300 -11.47300 1.000 86.35000 C ? A ? 59 1 + ATOM 60 CA . THR AZLONG 1417 ? -4.09900 -41.26900 -9.23800 1.000 83.54000 C ? A ? 60 1 + ATOM 61 CA . ASN AZLONG 1418 ? -7.74700 -39.98200 -9.56300 1.000 77.65000 C ? A ? 61 1 + ATOM 62 CA . LEU AZLONG 1419 ? -8.82900 -43.31700 -11.14900 1.000 86.38000 C ? A ? 62 1 + ATOM 63 CA . LEU AZLONG 1420 ? -12.42200 -44.63500 -11.15300 1.000 82.01000 C ? A ? 63 1 + ATOM 64 CA . PRO AZLONG 1421 ? -13.00500 -47.29800 -8.40200 1.000 83.37000 C ? A ? 64 1 + ATOM 65 CA . GLY AZLONG 1422 ? -13.55400 -50.89800 -9.62600 1.000 81.41000 C ? A ? 65 1 + ATOM 66 CA . THR AZLONG 1423 ? -12.59300 -49.87100 -13.25000 1.000 84.57000 C ? A ? 66 1 + ATOM 67 CA . GLU AZLONG 1424 ? -10.21300 -51.50300 -15.81700 1.000 87.87000 C ? A ? 67 1 + ATOM 68 CA . TYR AZLONG 1425 ? -7.64100 -49.21900 -17.56600 1.000 88.93000 C ? A ? 68 1 + ATOM 69 CA . VAL AZLONG 1426 ? -5.30400 -49.42400 -20.58400 1.000 89.65000 C ? A ? 69 1 + ATOM 70 CA . VAL AZLONG 1427 ? -1.82000 -47.93200 -19.99200 1.000 89.79000 C ? A ? 70 1 + ATOM 71 CA . SER AZLONG 1428 ? 0.81000 -47.14500 -22.66500 1.000 90.77000 C ? A ? 71 1 + ATOM 72 CA . VAL AZLONG 1429 ? 4.38000 -45.69400 -22.55900 1.000 90.44000 C ? A ? 72 1 + ATOM 73 CA . SER AZLONG 1430 ? 6.31300 -43.91600 -25.40100 1.000 88.19000 C ? A ? 73 1 + ATOM 74 CA . SER AZLONG 1431 ? 9.88600 -42.61300 -24.96200 1.000 84.31000 C ? A ? 74 1 + ATOM 75 CA . VAL AZLONG 1432 ? 10.29800 -38.95200 -26.10800 1.000 81.00000 C ? A ? 75 1 + ATOM 76 CA . TYR AZLONG 1433 ? 13.44400 -36.94400 -27.03700 1.000 73.21000 C ? A ? 76 1 + ATOM 77 CA . GLU AZLONG 1434 ? 12.75400 -33.16400 -26.96900 1.000 67.20000 C ? A ? 77 1 + ATOM 78 CA . GLN AZLONG 1435 ? 9.32200 -33.37200 -28.77200 1.000 67.21000 C ? A ? 78 1 + ATOM 79 CA . HIS AZLONG 1436 ? 9.90200 -36.60100 -30.78800 1.000 70.74000 C ? A ? 79 1 + ATOM 80 CA . GLU AZLONG 1437 ? 7.88600 -39.71900 -29.77200 1.000 78.72000 C ? A ? 80 1 + ATOM 81 CA . SER AZLONG 1438 ? 9.17500 -43.30400 -30.09300 1.000 81.88000 C ? A ? 81 1 + ATOM 82 CA . THR AZLONG 1439 ? 6.80300 -46.32100 -30.49100 1.000 79.18000 C ? A ? 82 1 + ATOM 83 CA . PRO AZLONG 1440 ? 4.58200 -47.08300 -27.39600 1.000 85.50000 C ? A ? 83 1 + ATOM 84 CA . LEU AZLONG 1441 ? 4.68900 -50.12100 -25.03400 1.000 87.64000 C ? A ? 84 1 + ATOM 85 CA . ARG AZLONG 1442 ? 1.11900 -51.19900 -23.78900 1.000 87.72000 C ? A ? 85 1 + ATOM 86 CA . GLY AZLONG 1443 ? -0.75900 -53.08500 -20.94400 1.000 86.81000 C ? A ? 86 1 + ATOM 87 CA . ARG AZLONG 1444 ? -3.99800 -53.27600 -18.76700 1.000 90.31000 C ? A ? 87 1 + ATOM 88 CA . GLN AZLONG 1445 ? -5.04500 -53.30600 -15.02100 1.000 90.49000 C ? A ? 88 1 + ATOM 89 CA . LYS AZLONG 1446 ? -8.19400 -52.91800 -12.72000 1.000 86.21000 C ? A ? 89 1 + ATOM 90 CA . THR AZLONG 1447 ? -8.59800 -50.65900 -9.58400 1.000 84.89000 C ? A ? 90 1 + ATOM 91 CA . GLY AZLONG 1448 ? -9.94700 -51.63000 -6.09500 1.000 78.52000 C ? A ? 91 1 + ATOM 92 CA . LEU AZLONG 1449 ? -13.22500 -50.79500 -4.24800 1.000 82.01000 C ? A ? 92 1 + ATOM 93 CA . ASP AZLONG 1450 ? -13.62700 -47.59000 -2.19900 1.000 78.78000 C ? A ? 93 1 + ATOM 94 CA . SER AZLONG 1451 ? -15.22800 -47.43500 1.28000 1.000 81.92000 C ? A ? 94 1 + ATOM 95 CA . PRO AZLONG 1452 ? -18.55800 -45.94800 2.29700 1.000 83.13000 C ? A ? 95 1 + ATOM 96 CA . THR AZLONG 1453 ? -17.89900 -42.46100 3.83100 1.000 82.78000 C ? A ? 96 1 + ATOM 97 CA . GLY AZLONG 1454 ? -19.79200 -40.03100 6.17600 1.000 74.81000 C ? A ? 97 1 + ATOM 98 CA . ILE AZLONG 1455 ? -21.30200 -42.26000 8.93000 1.000 86.68000 C ? A ? 98 1 + ATOM 99 CA . ASP AZLONG 1456 ? -24.15100 -40.41600 10.72900 1.000 83.44000 C ? A ? 99 1 + ATOM 100 CA . PHE AZLONG 1457 ? -26.77800 -41.27800 13.43000 1.000 88.77000 C ? A ? 100 1 + ATOM 101 CA . SER AZLONG 1458 ? -30.45300 -40.08500 13.26600 1.000 77.93000 C ? A ? 101 1 + ATOM 102 CA . ASP AZLONG 1459 ? -33.84500 -41.33600 14.73000 1.000 78.33000 C ? A ? 102 1 + ATOM 103 CA . ILE AZLONG 1460 ? -32.15900 -41.66200 18.17000 1.000 80.81000 C ? A ? 103 1 + ATOM 104 CA . THR AZLONG 1461 ? -34.81700 -43.10400 20.54200 1.000 72.41000 C ? A ? 104 1 + ATOM 105 CA . ALA AZLONG 1462 ? -34.77500 -45.16800 23.75900 1.000 69.09000 C ? A ? 105 1 + ATOM 106 CA . ASN AZLONG 1463 ? -34.74700 -48.42000 21.62300 1.000 82.09000 C ? A ? 106 1 + ATOM 107 CA . SER AZLONG 1464 ? -33.56100 -47.52000 18.05500 1.000 84.42000 C ? A ? 107 1 + ATOM 108 CA . PHE AZLONG 1465 ? -31.31500 -45.25800 15.99800 1.000 88.73000 C ? A ? 108 1 + ATOM 109 CA . THR AZLONG 1466 ? -30.93900 -44.88900 12.18400 1.000 86.79000 C ? A ? 109 1 + ATOM 110 CA . VAL AZLONG 1467 ? -27.42300 -45.15500 10.72400 1.000 88.31000 C ? A ? 110 1 + ATOM 111 CA . HIS AZLONG 1468 ? -26.63500 -43.30300 7.45900 1.000 87.52000 C ? A ? 111 1 + ATOM 112 CA . TRP AZLONG 1469 ? -23.57000 -43.54500 5.16400 1.000 91.25000 C ? A ? 112 1 + ATOM 113 CA . ILE AZLONG 1470 ? -22.45200 -42.00500 1.83800 1.000 83.88000 C ? A ? 113 1 + ATOM 114 CA . ALA AZLONG 1471 ? -22.20400 -44.57300 -1.00200 1.000 81.79000 C ? A ? 114 1 + ATOM 115 CA . PRO AZLONG 1472 ? -18.81000 -45.58800 -2.55900 1.000 80.28000 C ? A ? 115 1 + ATOM 116 CA . ARG AZLONG 1473 ? -18.11000 -44.51600 -6.20500 1.000 80.88000 C ? A ? 116 1 + ATOM 117 CA . ALA AZLONG 1474 ? -17.41200 -48.17300 -7.14300 1.000 78.12000 C ? A ? 117 1 + ATOM 118 CA . THR AZLONG 1475 ? -20.26100 -50.26500 -8.55800 1.000 79.54000 C ? A ? 118 1 + ATOM 119 CA . ILE AZLONG 1476 ? -21.33800 -52.42900 -5.57000 1.000 83.28000 C ? A ? 119 1 + ATOM 120 CA . THR AZLONG 1477 ? -23.71300 -55.35400 -4.89000 1.000 83.14000 C ? A ? 120 1 + ATOM 121 CA . GLY AZLONG 1478 ? -24.58100 -54.20600 -1.30500 1.000 85.09000 C ? A ? 121 1 + ATOM 122 CA . TYR AZLONG 1479 ? -23.47800 -53.38500 2.27700 1.000 90.89000 C ? A ? 122 1 + ATOM 123 CA . ARG AZLONG 1480 ? -22.78700 -55.34400 5.50700 1.000 90.72000 C ? A ? 123 1 + ATOM 124 CA . ILE AZLONG 1481 ? -23.46300 -53.54500 8.82200 1.000 90.39000 C ? A ? 124 1 + ATOM 125 CA . ARG AZLONG 1482 ? -22.26800 -54.86900 12.24300 1.000 90.05000 C ? A ? 125 1 + ATOM 126 CA . HIS AZLONG 1483 ? -23.53700 -53.52800 15.60500 1.000 89.55000 C ? A ? 126 1 + ATOM 127 CA . HIS AZLONG 1484 ? -22.88400 -54.23600 19.34300 1.000 88.89000 C ? A ? 127 1 + ATOM 128 CA . PRO AZLONG 1485 ? -22.85500 -52.40400 22.74700 1.000 85.71000 C ? A ? 128 1 + ATOM 129 CA . GLU AZLONG 1486 ? -19.36700 -50.86900 23.39200 1.000 76.38000 C ? A ? 129 1 + ATOM 130 CA . HIS AZLONG 1487 ? -18.65600 -53.18000 26.39800 1.000 75.73000 C ? A ? 130 1 + ATOM 131 CA . PHE AZLONG 1488 ? -20.04200 -56.29600 24.51800 1.000 70.75000 C ? A ? 131 1 + ATOM 132 CA . SER AZLONG 1489 ? -17.73900 -59.38700 24.60700 1.000 63.88000 C ? A ? 132 1 + ATOM 133 CA . GLY AZLONG 1490 ? -19.89200 -61.33000 22.03800 1.000 71.80000 C ? A ? 133 1 + ATOM 134 CA . ARG AZLONG 1491 ? -20.29100 -61.72100 18.23800 1.000 76.55000 C ? A ? 134 1 + ATOM 135 CA . PRO AZLONG 1492 ? -21.78800 -58.42200 16.86000 1.000 76.69000 C ? A ? 135 1 + ATOM 136 CA . ARG AZLONG 1493 ? -25.23700 -58.51000 15.18800 1.000 83.99000 C ? A ? 136 1 + ATOM 137 CA . GLU AZLONG 1494 ? -24.72000 -58.52400 11.37000 1.000 85.36000 C ? A ? 137 1 + ATOM 138 CA . ASP AZLONG 1495 ? -27.27200 -56.93900 8.99400 1.000 84.26000 C ? A ? 138 1 + ATOM 139 CA . ARG AZLONG 1496 ? -27.19500 -56.98600 5.13700 1.000 87.36000 C ? A ? 139 1 + ATOM 140 CA . VAL AZLONG 1497 ? -28.40900 -54.01800 3.08400 1.000 84.53000 C ? A ? 140 1 + ATOM 141 CA . PRO AZLONG 1498 ? -28.88800 -53.78400 -0.75600 1.000 82.15000 C ? A ? 141 1 + ATOM 142 CA . HIS AZLONG 1499 ? -26.68800 -51.38100 -2.81100 1.000 79.72000 C ? A ? 142 1 + ATOM 143 CA . SER AZLONG 1500 ? -29.92000 -49.28500 -3.19600 1.000 77.71000 C ? A ? 143 1 + ATOM 144 CA . ARG AZLONG 1501 ? -29.87300 -48.32700 0.55900 1.000 80.46000 C ? A ? 144 1 + ATOM 145 CA . ASN AZLONG 1502 ? -27.50800 -45.79600 2.17000 1.000 84.83000 C ? A ? 145 1 + ATOM 146 CA . SER AZLONG 1503 ? -29.22100 -46.25100 5.61400 1.000 88.71000 C ? A ? 146 1 + ATOM 147 CA . ILE AZLONG 1504 ? -30.52600 -48.71800 8.27200 1.000 90.10000 C ? A ? 147 1 + ATOM 148 CA . THR AZLONG 1505 ? -32.71900 -48.27200 11.39100 1.000 89.40000 C ? A ? 148 1 + ATOM 149 CA . LEU AZLONG 1506 ? -31.09800 -50.43300 14.09000 1.000 88.79000 C ? A ? 149 1 + ATOM 150 CA . THR AZLONG 1507 ? -33.89300 -51.63100 16.44600 1.000 85.27000 C ? A ? 150 1 + ATOM 151 CA . ASN AZLONG 1508 ? -34.31500 -53.65300 19.68000 1.000 82.83000 C ? A ? 151 1 + ATOM 152 CA . LEU AZLONG 1509 ? -31.54100 -51.63900 21.37300 1.000 86.68000 C ? A ? 152 1 + ATOM 153 CA . THR AZLONG 1510 ? -31.50100 -51.04400 25.19900 1.000 79.52000 C ? A ? 153 1 + ATOM 154 CA . PRO AZLONG 1511 ? -32.25900 -47.51100 26.65200 1.000 74.75000 C ? A ? 154 1 + ATOM 155 CA . GLY AZLONG 1512 ? -29.28700 -45.40800 27.91200 1.000 73.53000 C ? A ? 155 1 + ATOM 156 CA . THR AZLONG 1513 ? -26.77000 -47.79200 26.17800 1.000 82.07000 C ? A ? 156 1 + ATOM 157 CA . GLU AZLONG 1514 ? -23.82500 -47.03500 23.83100 1.000 82.90000 C ? A ? 157 1 + ATOM 158 CA . TYR AZLONG 1515 ? -23.32000 -49.08600 20.60300 1.000 89.27000 C ? A ? 158 1 + ATOM 159 CA . VAL AZLONG 1516 ? -20.36900 -49.44200 18.16100 1.000 88.57000 C ? A ? 159 1 + ATOM 160 CA . VAL AZLONG 1517 ? -21.40500 -49.78100 14.46000 1.000 90.19000 C ? A ? 160 1 + ATOM 161 CA . SER AZLONG 1518 ? -19.23400 -50.81700 11.45500 1.000 89.60000 C ? A ? 161 1 + ATOM 162 CA . ILE AZLONG 1519 ? -20.09200 -50.82600 7.69700 1.000 90.88000 C ? A ? 162 1 + ATOM 163 CA . VAL AZLONG 1520 ? -18.49600 -52.60000 4.65800 1.000 89.50000 C ? A ? 163 1 + ATOM 164 CA . ALA AZLONG 1521 ? -19.35500 -52.33300 0.92500 1.000 87.20000 C ? A ? 164 1 + ATOM 165 CA . LEU AZLONG 1522 ? -19.31000 -55.48200 -1.28500 1.000 85.94000 C ? A ? 165 1 + ATOM 166 CA . ASN AZLONG 1523 ? -18.78500 -56.11400 -5.04100 1.000 80.47000 C ? A ? 166 1 + ATOM 167 CA . GLY AZLONG 1524 ? -19.66400 -59.85100 -5.36700 1.000 78.84000 C ? A ? 167 1 + ATOM 168 CA . ARG AZLONG 1525 ? -16.71400 -61.15400 -3.22900 1.000 80.48000 C ? A ? 168 1 + ATOM 169 CA . GLU AZLONG 1526 ? -14.47500 -58.03600 -3.05000 1.000 80.23000 C ? A ? 169 1 + ATOM 170 CA . GLU AZLONG 1527 ? -14.98000 -56.14400 0.28700 1.000 84.03000 C ? A ? 170 1 + ATOM 171 CA . SER AZLONG 1528 ? -14.14600 -52.45700 1.01400 1.000 82.56000 C ? A ? 171 1 + ATOM 172 CA . PRO AZLONG 1529 ? -12.25000 -51.16300 4.06800 1.000 79.92000 C ? A ? 172 1 + ATOM 173 CA . LEU AZLONG 1530 ? -14.44000 -50.55300 7.18200 1.000 85.24000 C ? A ? 173 1 + ATOM 174 CA . LEU AZLONG 1531 ? -16.40000 -47.38400 8.06300 1.000 87.32000 C ? A ? 174 1 + ATOM 175 CA . ILE AZLONG 1532 ? -16.95100 -47.22000 11.91800 1.000 87.00000 C ? A ? 175 1 + ATOM 176 CA . GLY AZLONG 1533 ? -18.92700 -45.04000 14.43900 1.000 83.90000 C ? A ? 176 1 + ATOM 177 CA . GLN AZLONG 1534 ? -20.49800 -44.96800 17.98000 1.000 88.33000 C ? A ? 177 1 + ATOM 178 CA . GLN AZLONG 1535 ? -24.02100 -43.97400 19.21700 1.000 87.34000 C ? A ? 178 1 + ATOM 179 CA . SER AZLONG 1536 ? -26.05500 -43.97000 22.49900 1.000 82.89000 C ? A ? 179 1 + ATOM 180 CA . THR AZLONG 1537 ? -29.82500 -44.57500 23.03400 1.000 79.47000 C ? A ? 180 1 + diff --git a/mmtbx/regression/pdbs/pae_model.cif b/mmtbx/regression/pdbs/pae_model.cif new file mode 100644 index 0000000000..07bb022ab2 --- /dev/null +++ b/mmtbx/regression/pdbs/pae_model.cif @@ -0,0 +1,2307 @@ +data_default +loop_ + _struct_asym.id + A + +loop_ + _chem_comp.id + ALA + ARG + ASN + ASP + CYS + GLN + GLU + GLY + HIS + ILE + LEU + LYS + MET + PHE + PRO + SER + THR + TRP + TYR + VAL + +loop_ + _atom_site.group_PDB + _atom_site.id + _atom_site.label_atom_id + _atom_site.label_alt_id + _atom_site.label_comp_id + _atom_site.auth_asym_id + _atom_site.auth_seq_id + _atom_site.pdbx_PDB_ins_code + _atom_site.Cartn_x + _atom_site.Cartn_y + _atom_site.Cartn_z + _atom_site.occupancy + _atom_site.B_iso_or_equiv + _atom_site.type_symbol + _atom_site.pdbx_formal_charge + _atom_site.label_asym_id + _atom_site.label_entity_id + _atom_site.label_seq_id + _atom_site.pdbx_PDB_model_num + ATOM 1 N . SER A 1 ? 2.97400 -27.45800 18.52400 1.000 72.44000 N ? A ? 1 0 + ATOM 2 CA . SER A 1 ? 3.37100 -28.05400 17.23900 1.000 72.44000 C ? A ? 1 0 + ATOM 3 C . SER A 1 ? 3.69400 -29.50800 17.47000 1.000 72.44000 C ? A ? 1 0 + ATOM 4 O . SER A 1 ? 4.31700 -29.81100 18.48100 1.000 72.44000 O ? A ? 1 0 + ATOM 5 CB . SER A 1 ? 4.57400 -27.32000 16.65500 1.000 72.44000 C ? A ? 1 0 + ATOM 6 OG . SER A 1 ? 4.28400 -25.93700 16.72100 1.000 72.44000 O ? A ? 1 0 + ATOM 7 N . TYR A 2 ? 3.23900 -30.38100 16.58400 1.000 79.50000 N ? A ? 2 0 + ATOM 8 CA . TYR A 2 ? 3.48500 -31.81600 16.61700 1.000 79.50000 C ? A ? 2 0 + ATOM 9 C . TYR A 2 ? 4.24800 -32.20100 15.35300 1.000 79.50000 C ? A ? 2 0 + ATOM 10 O . TYR A 2 ? 4.01300 -31.63100 14.28800 1.000 79.50000 O ? A ? 2 0 + ATOM 11 CB . TYR A 2 ? 2.15800 -32.57900 16.72700 1.000 79.50000 C ? A ? 2 0 + ATOM 12 CG . TYR A 2 ? 1.35500 -32.24100 17.96900 1.000 79.50000 C ? A ? 2 0 + ATOM 13 CD1 . TYR A 2 ? 1.58500 -32.94900 19.16300 1.000 79.50000 C ? A ? 2 0 + ATOM 14 CD2 . TYR A 2 ? 0.38500 -31.21800 17.93000 1.000 79.50000 C ? A ? 2 0 + ATOM 15 CE1 . TYR A 2 ? 0.84800 -32.64100 20.32200 1.000 79.50000 C ? A ? 2 0 + ATOM 16 CE2 . TYR A 2 ? -0.34400 -30.89700 19.09200 1.000 79.50000 C ? A ? 2 0 + ATOM 17 CZ . TYR A 2 ? -0.11800 -31.61200 20.28700 1.000 79.50000 C ? A ? 2 0 + ATOM 18 OH . TYR A 2 ? -0.83000 -31.30200 21.40000 1.000 79.50000 O ? A ? 2 0 + ATOM 19 N . SER A 3 ? 5.16400 -33.15200 15.48000 1.000 85.13000 N ? A ? 3 0 + ATOM 20 CA . SER A 3 ? 5.85200 -33.75600 14.34600 1.000 85.13000 C ? A ? 3 0 + ATOM 21 C . SER A 3 ? 5.25200 -35.14300 14.15100 1.000 85.13000 C ? A ? 3 0 + ATOM 22 O . SER A 3 ? 5.32600 -35.96600 15.06300 1.000 85.13000 O ? A ? 3 0 + ATOM 23 CB . SER A 3 ? 7.35300 -33.79500 14.63000 1.000 85.13000 C ? A ? 3 0 + ATOM 24 OG . SER A 3 ? 8.06100 -33.77900 13.42000 1.000 85.13000 O ? A ? 3 0 + ATOM 25 N . VAL A 4 ? 4.56900 -35.36300 13.02700 1.000 88.29000 N ? A ? 4 0 + ATOM 26 CA . VAL A 4 ? 3.86100 -36.61800 12.74200 1.000 88.29000 C ? A ? 4 0 + ATOM 27 C . VAL A 4 ? 4.67500 -37.42700 11.74500 1.000 88.29000 C ? A ? 4 0 + ATOM 28 O . VAL A 4 ? 5.02600 -36.93700 10.67000 1.000 88.29000 O ? A ? 4 0 + ATOM 29 CB . VAL A 4 ? 2.42300 -36.37300 12.24300 1.000 88.29000 C ? A ? 4 0 + ATOM 30 CG1 . VAL A 4 ? 1.68100 -37.69200 11.97700 1.000 88.29000 C ? A ? 4 0 + ATOM 31 CG2 . VAL A 4 ? 1.60600 -35.59600 13.28500 1.000 88.29000 C ? A ? 4 0 + ATOM 32 N . THR A 5 ? 4.95600 -38.67400 12.10400 1.000 91.73000 N ? A ? 5 0 + ATOM 33 CA . THR A 5 ? 5.56100 -39.68400 11.23800 1.000 91.73000 C ? A ? 5 0 + ATOM 34 C . THR A 5 ? 4.63900 -40.89400 11.16800 1.000 91.73000 C ? A ? 5 0 + ATOM 35 O . THR A 5 ? 3.86300 -41.15600 12.08700 1.000 91.73000 O ? A ? 5 0 + ATOM 36 CB . THR A 5 ? 6.95600 -40.10200 11.72700 1.000 91.73000 C ? A ? 5 0 + ATOM 37 OG1 . THR A 5 ? 6.91300 -40.51900 13.07100 1.000 91.73000 O ? A ? 5 0 + ATOM 38 CG2 . THR A 5 ? 7.96400 -38.95900 11.64700 1.000 91.73000 C ? A ? 5 0 + ATOM 39 N . VAL A 6 ? 4.69900 -41.62200 10.05600 1.000 91.60000 N ? A ? 6 0 + ATOM 40 CA . VAL A 6 ? 3.92700 -42.84900 9.85000 1.000 91.60000 C ? A ? 6 0 + ATOM 41 C . VAL A 6 ? 4.90000 -44.00500 9.66900 1.000 91.60000 C ? A ? 6 0 + ATOM 42 O . VAL A 6 ? 5.83000 -43.91700 8.86600 1.000 91.60000 O ? A ? 6 0 + ATOM 43 CB . VAL A 6 ? 2.95900 -42.70700 8.65900 1.000 91.60000 C ? A ? 6 0 + ATOM 44 CG1 . VAL A 6 ? 2.12300 -43.97800 8.45700 1.000 91.60000 C ? A ? 6 0 + ATOM 45 CG2 . VAL A 6 ? 1.98500 -41.53800 8.87100 1.000 91.60000 C ? A ? 6 0 + ATOM 46 N . THR A 7 ? 4.67900 -45.08800 10.40700 1.000 91.25000 N ? A ? 7 0 + ATOM 47 CA . THR A 7 ? 5.34800 -46.37900 10.22700 1.000 91.25000 C ? A ? 7 0 + ATOM 48 C . THR A 7 ? 4.32100 -47.40400 9.75900 1.000 91.25000 C ? A ? 7 0 + ATOM 49 O . THR A 7 ? 3.16200 -47.38800 10.17500 1.000 91.25000 O ? A ? 7 0 + ATOM 50 CB . THR A 7 ? 6.05200 -46.85300 11.51000 1.000 91.25000 C ? A ? 7 0 + ATOM 51 OG1 . THR A 7 ? 5.19600 -46.74600 12.62100 1.000 91.25000 O ? A ? 7 0 + ATOM 52 CG2 . THR A 7 ? 7.28900 -46.01300 11.81500 1.000 91.25000 C ? A ? 7 0 + ATOM 53 N . SER A 8 ? 4.72500 -48.28300 8.84600 1.000 88.71000 N ? A ? 8 0 + ATOM 54 CA . SER A 8 ? 3.90300 -49.42000 8.42500 1.000 88.71000 C ? A ? 8 0 + ATOM 55 C . SER A 8 ? 4.27800 -50.65400 9.24200 1.000 88.71000 C ? A ? 8 0 + ATOM 56 O . SER A 8 ? 5.45900 -50.87000 9.51900 1.000 88.71000 O ? A ? 8 0 + ATOM 57 CB . SER A 8 ? 4.01100 -49.64900 6.91500 1.000 88.71000 C ? A ? 8 0 + ATOM 58 OG . SER A 8 ? 5.32600 -49.97100 6.51400 1.000 88.71000 O ? A ? 8 0 + ATOM 59 N . LEU A 9 ? 3.27600 -51.44800 9.62600 1.000 91.87000 N ? A ? 9 0 + ATOM 60 CA . LEU A 9 ? 3.44300 -52.63400 10.46600 1.000 91.87000 C ? A ? 9 0 + ATOM 61 C . LEU A 9 ? 2.85000 -53.85900 9.76100 1.000 91.87000 C ? A ? 9 0 + ATOM 62 O . LEU A 9 ? 1.70300 -53.83200 9.30800 1.000 91.87000 O ? A ? 9 0 + ATOM 63 CB . LEU A 9 ? 2.82500 -52.33900 11.84900 1.000 91.87000 C ? A ? 9 0 + ATOM 64 CG . LEU A 9 ? 3.26400 -53.32300 12.95700 1.000 91.87000 C ? A ? 9 0 + ATOM 65 CD1 . LEU A 9 ? 3.60500 -52.56800 14.24100 1.000 91.87000 C ? A ? 9 0 + ATOM 66 CD2 . LEU A 9 ? 2.14700 -54.31100 13.29700 1.000 91.87000 C ? A ? 9 0 + ATOM 67 N . ARG A 10 ? 3.63600 -54.93500 9.64400 1.000 89.14000 N ? A ? 10 0 + ATOM 68 CA . ARG A 10 ? 3.18300 -56.23900 9.13100 1.000 89.14000 C ? A ? 10 0 + ATOM 69 C . ARG A 10 ? 3.75400 -57.34600 10.01500 1.000 89.14000 C ? A ? 10 0 + ATOM 70 O . ARG A 10 ? 4.94300 -57.64400 9.93200 1.000 89.14000 O ? A ? 10 0 + ATOM 71 CB . ARG A 10 ? 3.58200 -56.40200 7.64800 1.000 89.14000 C ? A ? 10 0 + ATOM 72 CG . ARG A 10 ? 3.14200 -57.76700 7.08400 1.000 89.14000 C ? A ? 10 0 + ATOM 73 CD . ARG A 10 ? 3.58600 -57.99500 5.63200 1.000 89.14000 C ? A ? 10 0 + ATOM 74 NE . ARG A 10 ? 2.66400 -57.39400 4.64800 1.000 89.14000 N ? A ? 10 0 + ATOM 75 CZ . ARG A 10 ? 2.74200 -57.52700 3.33500 1.000 89.14000 C ? A ? 10 0 + ATOM 76 NH1 . ARG A 10 ? 3.72800 -58.16600 2.76600 1.000 89.14000 N ? A ? 10 0 + ATOM 77 NH2 . ARG A 10 ? 1.82600 -57.01800 2.56000 1.000 89.14000 N ? A ? 10 0 + ATOM 78 N . GLY A 11 ? 2.89400 -57.98100 10.81100 1.000 88.64000 N ? A ? 11 0 + ATOM 79 CA . GLY A 11 ? 3.33400 -58.94000 11.82900 1.000 88.64000 C ? A ? 11 0 + ATOM 80 C . GLY A 11 ? 4.23200 -58.24400 12.85200 1.000 88.64000 C ? A ? 11 0 + ATOM 81 O . GLY A 11 ? 3.86600 -57.18100 13.34100 1.000 88.64000 O ? A ? 11 0 + ATOM 82 N . ASP A 12 ? 5.42000 -58.80000 13.08500 1.000 87.38000 N ? A ? 12 0 + ATOM 83 CA . ASP A 12 ? 6.42400 -58.25300 14.01100 1.000 87.38000 C ? A ? 12 0 + ATOM 84 C . ASP A 12 ? 7.45600 -57.32800 13.32800 1.000 87.38000 C ? A ? 12 0 + ATOM 85 O . ASP A 12 ? 8.46800 -56.96700 13.92600 1.000 87.38000 O ? A ? 12 0 + ATOM 86 CB . ASP A 12 ? 7.12000 -59.41200 14.74500 1.000 87.38000 C ? A ? 12 0 + ATOM 87 CG . ASP A 12 ? 6.14500 -60.33800 15.47700 1.000 87.38000 C ? A ? 12 0 + ATOM 88 OD1 . ASP A 12 ? 5.19100 -59.82400 16.10100 1.000 87.38000 O ? A ? 12 0 + ATOM 89 OD2 . ASP A 12 ? 6.34500 -61.56900 15.37000 1.000 87.38000 O ? A ? 12 0 + ATOM 90 N . CYS A 13 ? 7.25800 -56.96600 12.05400 1.000 86.80000 N ? A ? 13 0 + ATOM 91 CA . CYS A 13 ? 8.16700 -56.08300 11.32100 1.000 86.80000 C ? A ? 13 0 + ATOM 92 C . CYS A 13 ? 7.59900 -54.66200 11.19500 1.000 86.80000 C ? A ? 13 0 + ATOM 93 O . CYS A 13 ? 6.49000 -54.47300 10.68400 1.000 86.80000 O ? A ? 13 0 + ATOM 94 CB . CYS A 13 ? 8.48700 -56.68200 9.94300 1.000 86.80000 C ? A ? 13 0 + ATOM 95 SG . CYS A 13 ? 9.32400 -58.28700 10.10400 1.000 86.80000 S ? A ? 13 0 + ATOM 96 N . GLU A 14 ? 8.40500 -53.66800 11.57700 1.000 90.65000 N ? A ? 14 0 + ATOM 97 CA . GLU A 14 ? 8.13200 -52.23600 11.40600 1.000 90.65000 C ? A ? 14 0 + ATOM 98 C . GLU A 14 ? 9.01900 -51.63300 10.30700 1.000 90.65000 C ? A ? 14 0 + ATOM 99 O . GLU A 14 ? 10.20100 -51.96600 10.18700 1.000 90.65000 O ? A ? 14 0 + ATOM 100 CB . GLU A 14 ? 8.34400 -51.47300 12.72500 1.000 90.65000 C ? A ? 14 0 + ATOM 101 CG . GLU A 14 ? 7.41800 -51.96300 13.84700 1.000 90.65000 C ? A ? 14 0 + ATOM 102 CD . GLU A 14 ? 7.43400 -51.06200 15.09600 1.000 90.65000 C ? A ? 14 0 + ATOM 103 OE1 . GLU A 14 ? 6.54900 -51.26300 15.95700 1.000 90.65000 O ? A ? 14 0 + ATOM 104 OE2 . GLU A 14 ? 8.30200 -50.16200 15.17700 1.000 90.65000 O ? A ? 14 0 + ATOM 105 N . SER A 15 ? 8.46300 -50.73300 9.49200 1.000 89.93000 N ? A ? 15 0 + ATOM 106 CA . SER A 15 ? 9.25800 -49.94200 8.54600 1.000 89.93000 C ? A ? 15 0 + ATOM 107 C . SER A 15 ? 10.00200 -48.79900 9.23900 1.000 89.93000 C ? A ? 15 0 + ATOM 108 O . SER A 15 ? 9.63500 -48.36600 10.32800 1.000 89.93000 O ? A ? 15 0 + ATOM 109 CB . SER A 15 ? 8.39100 -49.40800 7.39900 1.000 89.93000 C ? A ? 15 0 + ATOM 110 OG . SER A 15 ? 7.50800 -48.37100 7.80500 1.000 89.93000 O ? A ? 15 0 + ATOM 111 N . GLN A 16 ? 10.98700 -48.21600 8.55000 1.000 89.52000 N ? A ? 16 0 + ATOM 112 CA . GLN A 16 ? 11.50600 -46.90600 8.94900 1.000 89.52000 C ? A ? 16 0 + ATOM 113 C . GLN A 16 ? 10.36900 -45.85900 8.95100 1.000 89.52000 C ? A ? 16 0 + ATOM 114 O . GLN A 16 ? 9.46800 -45.95300 8.10400 1.000 89.52000 O ? A ? 16 0 + ATOM 115 CB . GLN A 16 ? 12.65400 -46.47700 8.02100 1.000 89.52000 C ? A ? 16 0 + ATOM 116 CG . GLN A 16 ? 13.91100 -47.34600 8.20500 1.000 89.52000 C ? A ? 16 0 + ATOM 117 CD . GLN A 16 ? 14.52800 -47.22100 9.59800 1.000 89.52000 C ? A ? 16 0 + ATOM 118 OE1 . GLN A 16 ? 14.45100 -46.19900 10.25800 1.000 89.52000 O ? A ? 16 0 + ATOM 119 NE2 . GLN A 16 ? 15.16400 -48.25300 10.10500 1.000 89.52000 N ? A ? 16 0 + ATOM 120 N . PRO A 17 ? 10.38000 -44.88200 9.87700 1.000 90.04000 N ? A ? 17 0 + ATOM 121 CA . PRO A 17 ? 9.40900 -43.79300 9.88600 1.000 90.04000 C ? A ? 17 0 + ATOM 122 C . PRO A 17 ? 9.46100 -42.96400 8.59800 1.000 90.04000 C ? A ? 17 0 + ATOM 123 O . PRO A 17 ? 10.53200 -42.73800 8.03400 1.000 90.04000 O ? A ? 17 0 + ATOM 124 CB . PRO A 17 ? 9.74000 -42.94200 11.11800 1.000 90.04000 C ? A ? 17 0 + ATOM 125 CG . PRO A 17 ? 10.50800 -43.89800 12.02900 1.000 90.04000 C ? A ? 17 0 + ATOM 126 CD . PRO A 17 ? 11.24600 -44.79900 11.04500 1.000 90.04000 C ? A ? 17 0 + ATOM 127 N . SER A 18 ? 8.30400 -42.47400 8.14900 1.000 91.27000 N ? A ? 18 0 + ATOM 128 CA . SER A 18 ? 8.22600 -41.49900 7.05700 1.000 91.27000 C ? A ? 18 0 + ATOM 129 C . SER A 18 ? 8.98400 -40.20500 7.38300 1.000 91.27000 C ? A ? 18 0 + ATOM 130 O . SER A 18 ? 9.27800 -39.90700 8.54300 1.000 91.27000 O ? A ? 18 0 + ATOM 131 CB . SER A 18 ? 6.75600 -41.18400 6.73900 1.000 91.27000 C ? A ? 18 0 + ATOM 132 OG . SER A 18 ? 6.15300 -40.39900 7.75700 1.000 91.27000 O ? A ? 18 0 + ATOM 133 N . THR A 19 ? 9.21300 -39.36200 6.37100 1.000 90.71000 N ? A ? 19 0 + ATOM 134 CA . THR A 19 ? 9.60300 -37.96400 6.60700 1.000 90.71000 C ? A ? 19 0 + ATOM 135 C . THR A 19 ? 8.57700 -37.28900 7.51400 1.000 90.71000 C ? A ? 19 0 + ATOM 136 O . THR A 19 ? 7.37000 -37.42800 7.29800 1.000 90.71000 O ? A ? 19 0 + ATOM 137 CB . THR A 19 ? 9.71000 -37.16700 5.30200 1.000 90.71000 C ? A ? 19 0 + ATOM 138 OG1 . THR A 19 ? 8.54000 -37.33500 4.53400 1.000 90.71000 O ? A ? 19 0 + ATOM 139 CG2 . THR A 19 ? 10.89400 -37.63200 4.45600 1.000 90.71000 C ? A ? 19 0 + ATOM 140 N . ALA A 20 ? 9.05900 -36.57800 8.52900 1.000 88.71000 N ? A ? 20 0 + ATOM 141 CA . ALA A 20 ? 8.20500 -35.91800 9.49800 1.000 88.71000 C ? A ? 20 0 + ATOM 142 C . ALA A 20 ? 7.45100 -34.73900 8.87300 1.000 88.71000 C ? A ? 20 0 + ATOM 143 O . ALA A 20 ? 8.05100 -33.87400 8.23400 1.000 88.71000 O ? A ? 20 0 + ATOM 144 CB . ALA A 20 ? 9.07200 -35.48200 10.67500 1.000 88.71000 C ? A ? 20 0 + ATOM 145 N . VAL A 21 ? 6.13800 -34.68600 9.09700 1.000 86.44000 N ? A ? 21 0 + ATOM 146 CA . VAL A 21 ? 5.30400 -33.53700 8.73200 1.000 86.44000 C ? A ? 21 0 + ATOM 147 C . VAL A 21 ? 4.99600 -32.75100 10.00100 1.000 86.44000 C ? A ? 21 0 + ATOM 148 O . VAL A 21 ? 4.41800 -33.27800 10.95400 1.000 86.44000 O ? A ? 21 0 + ATOM 149 CB . VAL A 21 ? 4.03100 -33.96500 7.98000 1.000 86.44000 C ? A ? 21 0 + ATOM 150 CG1 . VAL A 21 ? 3.23000 -32.73500 7.52900 1.000 86.44000 C ? A ? 21 0 + ATOM 151 CG2 . VAL A 21 ? 4.37300 -34.78200 6.72600 1.000 86.44000 C ? A ? 21 0 + ATOM 152 N . ASN A 22 ? 5.39700 -31.48100 10.02600 1.000 83.81000 N ? A ? 22 0 + ATOM 153 CA . ASN A 22 ? 5.11800 -30.59200 11.14800 1.000 83.81000 C ? A ? 22 0 + ATOM 154 C . ASN A 22 ? 3.70400 -30.02400 11.01500 1.000 83.81000 C ? A ? 22 0 + ATOM 155 O . ASN A 22 ? 3.40600 -29.31000 10.06100 1.000 83.81000 O ? A ? 22 0 + ATOM 156 CB . ASN A 22 ? 6.18400 -29.48800 11.21800 1.000 83.81000 C ? A ? 22 0 + ATOM 157 CG . ASN A 22 ? 7.54800 -30.01200 11.63500 1.000 83.81000 C ? A ? 22 0 + ATOM 158 OD1 . ASN A 22 ? 7.68900 -31.00900 12.33100 1.000 83.81000 O ? A ? 22 0 + ATOM 159 ND2 . ASN A 22 ? 8.60100 -29.33200 11.24900 1.000 83.81000 N ? A ? 22 0 + ATOM 160 N . VAL A 23 ? 2.85200 -30.31600 11.99300 1.000 81.23000 N ? A ? 23 0 + ATOM 161 CA . VAL A 23 ? 1.47600 -29.81700 12.06800 1.000 81.23000 C ? A ? 23 0 + ATOM 162 C . VAL A 23 ? 1.26600 -29.03200 13.35500 1.000 81.23000 C ? A ? 23 0 + ATOM 163 O . VAL A 23 ? 1.81900 -29.34000 14.41600 1.000 81.23000 O ? A ? 23 0 + ATOM 164 CB . VAL A 23 ? 0.43200 -30.93900 11.90700 1.000 81.23000 C ? A ? 23 0 + ATOM 165 CG1 . VAL A 23 ? 0.42800 -31.48400 10.47600 1.000 81.23000 C ? A ? 23 0 + ATOM 166 CG2 . VAL A 23 ? 0.65300 -32.10500 12.87500 1.000 81.23000 C ? A ? 23 0 + ATOM 167 N . THR A 24 ? 0.43700 -28.00000 13.28500 1.000 81.30000 N ? A ? 24 0 + ATOM 168 CA . THR A 24 ? 0.07400 -27.18300 14.44500 1.000 81.30000 C ? A ? 24 0 + ATOM 169 C . THR A 24 ? -1.41300 -27.37000 14.71100 1.000 81.30000 C ? A ? 24 0 + ATOM 170 O . THR A 24 ? -2.20800 -27.36100 13.77600 1.000 81.30000 O ? A ? 24 0 + ATOM 171 CB . THR A 24 ? 0.44400 -25.70400 14.24400 1.000 81.30000 C ? A ? 24 0 + ATOM 172 OG1 . THR A 24 ? 1.65500 -25.57500 13.53200 1.000 81.30000 O ? A ? 24 0 + ATOM 173 CG2 . THR A 24 ? 0.69300 -25.01000 15.58400 1.000 81.30000 C ? A ? 24 0 + ATOM 174 N . SER A 25 ? -1.80200 -27.55900 15.97500 1.000 86.41000 N ? A ? 25 0 + ATOM 175 CA . SER A 25 ? -3.22000 -27.59800 16.35000 1.000 86.41000 C ? A ? 25 0 + ATOM 176 C . SER A 25 ? -3.89200 -26.25500 16.04900 1.000 86.41000 C ? A ? 25 0 + ATOM 177 O . SER A 25 ? -3.20700 -25.24200 15.88700 1.000 86.41000 O ? A ? 25 0 + ATOM 178 CB . SER A 25 ? -3.36900 -27.95700 17.83300 1.000 86.41000 C ? A ? 25 0 + ATOM 179 OG . SER A 25 ? -2.67900 -27.02200 18.64400 1.000 86.41000 O ? A ? 25 0 + ATOM 180 N . ALA A 26 ? -5.22600 -26.22900 16.01300 1.000 89.92000 N ? A ? 26 0 + ATOM 181 CA . ALA A 26 ? -5.96600 -24.97600 15.90500 1.000 89.92000 C ? A ? 26 0 + ATOM 182 C . ALA A 26 ? -5.55700 -23.98600 17.02100 1.000 89.92000 C ? A ? 26 0 + ATOM 183 O . ALA A 26 ? -5.22700 -24.42900 18.13100 1.000 89.92000 O ? A ? 26 0 + ATOM 184 CB . ALA A 26 ? -7.46900 -25.27100 15.92300 1.000 89.92000 C ? A ? 26 0 + ATOM 185 N . PRO A 27 ? -5.54900 -22.66900 16.74300 1.000 92.68000 N ? A ? 27 0 + ATOM 186 CA . PRO A 27 ? -5.32900 -21.65700 17.77000 1.000 92.68000 C ? A ? 27 0 + ATOM 187 C . PRO A 27 ? -6.37900 -21.73400 18.88200 1.000 92.68000 C ? A ? 27 0 + ATOM 188 O . PRO A 27 ? -7.49600 -22.21300 18.67000 1.000 92.68000 O ? A ? 27 0 + ATOM 189 CB . PRO A 27 ? -5.40500 -20.30800 17.04900 1.000 92.68000 C ? A ? 27 0 + ATOM 190 CG . PRO A 27 ? -5.11900 -20.65200 15.59200 1.000 92.68000 C ? A ? 27 0 + ATOM 191 CD . PRO A 27 ? -5.74300 -22.03400 15.44600 1.000 92.68000 C ? A ? 27 0 + ATOM 192 N . CYS A 28 ? -6.04400 -21.21700 20.06400 1.000 94.14000 N ? A ? 28 0 + ATOM 193 CA . CYS A 28 ? -7.04200 -20.99900 21.10800 1.000 94.14000 C ? A ? 28 0 + ATOM 194 C . CYS A 28 ? -8.09700 -19.97400 20.65900 1.000 94.14000 C ? A ? 28 0 + ATOM 195 O . CYS A 28 ? -7.82300 -19.10500 19.83200 1.000 94.14000 O ? A ? 28 0 + ATOM 196 CB . CYS A 28 ? -6.35200 -20.57000 22.40900 1.000 94.14000 C ? A ? 28 0 + ATOM 197 SG . CYS A 28 ? -5.36400 -21.94700 23.06800 1.000 94.14000 S ? A ? 28 0 + ATOM 198 N . VAL A 29 ? -9.29800 -20.07300 21.23100 1.000 94.81000 N ? A ? 29 0 + ATOM 199 CA . VAL A 29 ? -10.36600 -19.08900 21.02100 1.000 94.81000 C ? A ? 29 0 + ATOM 200 C . VAL A 29 ? -9.91000 -17.73200 21.59400 1.000 94.81000 C ? A ? 29 0 + ATOM 201 O . VAL A 29 ? -9.39800 -17.71800 22.71900 1.000 94.81000 O ? A ? 29 0 + ATOM 202 CB . VAL A 29 ? -11.68000 -19.57200 21.66500 1.000 94.81000 C ? A ? 29 0 + ATOM 203 CG1 . VAL A 29 ? -12.82200 -18.58500 21.44500 1.000 94.81000 C ? A ? 29 0 + ATOM 204 CG2 . VAL A 29 ? -12.12000 -20.91600 21.06300 1.000 94.81000 C ? A ? 29 0 + ATOM 205 N . PRO A 30 ? -10.03400 -16.61800 20.84500 1.000 93.95000 N ? A ? 30 0 + ATOM 206 CA . PRO A 30 ? -9.76100 -15.27100 21.35000 1.000 93.95000 C ? A ? 30 0 + ATOM 207 C . PRO A 30 ? -10.57700 -14.93000 22.60600 1.000 93.95000 C ? A ? 30 0 + ATOM 208 O . PRO A 30 ? -11.62500 -15.52200 22.85800 1.000 93.95000 O ? A ? 30 0 + ATOM 209 CB . PRO A 30 ? -10.08000 -14.31700 20.19300 1.000 93.95000 C ? A ? 30 0 + ATOM 210 CG . PRO A 30 ? -9.88500 -15.19300 18.95900 1.000 93.95000 C ? A ? 30 0 + ATOM 211 CD . PRO A 30 ? -10.36900 -16.56000 19.43000 1.000 93.95000 C ? A ? 30 0 + ATOM 212 N . GLN A 31 ? -10.06000 -14.00800 23.41900 1.000 93.67000 N ? A ? 31 0 + ATOM 213 CA . GLN A 31 ? -10.71600 -13.52500 24.63600 1.000 93.67000 C ? A ? 31 0 + ATOM 214 C . GLN A 31 ? -10.44700 -12.03000 24.83200 1.000 93.67000 C ? A ? 31 0 + ATOM 215 O . GLN A 31 ? -9.43200 -11.51000 24.36100 1.000 93.67000 O ? A ? 31 0 + ATOM 216 CB . GLN A 31 ? -10.20900 -14.29600 25.87300 1.000 93.67000 C ? A ? 31 0 + ATOM 217 CG . GLN A 31 ? -10.59000 -15.78300 25.87000 1.000 93.67000 C ? A ? 31 0 + ATOM 218 CD . GLN A 31 ? -10.23900 -16.49000 27.17600 1.000 93.67000 C ? A ? 31 0 + ATOM 219 OE1 . GLN A 31 ? -9.27800 -16.19100 27.86800 1.000 93.67000 O ? A ? 31 0 + ATOM 220 NE2 . GLN A 31 ? -11.01100 -17.47900 27.57200 1.000 93.67000 N ? A ? 31 0 + ATOM 221 N . GLY A 32 ? -11.31200 -11.36300 25.59800 1.000 91.63000 N ? A ? 32 0 + ATOM 222 CA . GLY A 32 ? -11.14700 -9.95200 25.95900 1.000 91.63000 C ? A ? 32 0 + ATOM 223 C . GLY A 32 ? -11.48000 -9.00600 24.80900 1.000 91.63000 C ? A ? 32 0 + ATOM 224 O . GLY A 32 ? -10.83200 -7.97400 24.66000 1.000 91.63000 O ? A ? 32 0 + ATOM 225 N . GLU A 33 ? -12.44400 -9.39100 23.97800 1.000 92.94000 N ? A ? 33 0 + ATOM 226 CA . GLU A 33 ? -12.88300 -8.63700 22.81800 1.000 92.94000 C ? A ? 33 0 + ATOM 227 C . GLU A 33 ? -13.59700 -7.35000 23.24200 1.000 92.94000 C ? A ? 33 0 + ATOM 228 O . GLU A 33 ? -14.56800 -7.37300 23.99900 1.000 92.94000 O ? A ? 33 0 + ATOM 229 CB . GLU A 33 ? -13.78500 -9.48700 21.90800 1.000 92.94000 C ? A ? 33 0 + ATOM 230 CG . GLU A 33 ? -13.15300 -10.80600 21.43600 1.000 92.94000 C ? A ? 33 0 + ATOM 231 CD . GLU A 33 ? -13.39000 -12.00700 22.37300 1.000 92.94000 C ? A ? 33 0 + ATOM 232 OE1 . GLU A 33 ? -13.34000 -13.14200 21.85900 1.000 92.94000 O ? A ? 33 0 + ATOM 233 OE2 . GLU A 33 ? -13.57900 -11.84500 23.60300 1.000 92.94000 O ? A ? 33 0 + ATOM 234 N . ALA A 34 ? -13.12600 -6.22000 22.72700 1.000 93.92000 N ? A ? 34 0 + ATOM 235 CA . ALA A 34 ? -13.75400 -4.92100 22.91100 1.000 93.92000 C ? A ? 34 0 + ATOM 236 C . ALA A 34 ? -13.77300 -4.16800 21.58100 1.000 93.92000 C ? A ? 34 0 + ATOM 237 O . ALA A 34 ? -12.87400 -4.32500 20.75900 1.000 93.92000 O ? A ? 34 0 + ATOM 238 CB . ALA A 34 ? -13.01100 -4.15200 24.00900 1.000 93.92000 C ? A ? 34 0 + ATOM 239 N . GLY A 35 ? -14.79600 -3.34400 21.36800 1.000 92.42000 N ? A ? 35 0 + ATOM 240 CA . GLY A 35 ? -14.92200 -2.51900 20.17100 1.000 92.42000 C ? A ? 35 0 + ATOM 241 C . GLY A 35 ? -15.10600 -1.05200 20.52600 1.000 92.42000 C ? A ? 35 0 + ATOM 242 O . GLY A 35 ? -15.85300 -0.72600 21.44800 1.000 92.42000 O ? A ? 35 0 + ATOM 243 N . ASN A 36 ? -14.44400 -0.17200 19.78200 1.000 91.54000 N ? A ? 36 0 + ATOM 244 CA . ASN A 36 ? -14.63300 1.26900 19.86100 1.000 91.54000 C ? A ? 36 0 + ATOM 245 C . ASN A 36 ? -15.07000 1.80000 18.49200 1.000 91.54000 C ? A ? 36 0 + ATOM 246 O . ASN A 36 ? -14.38400 1.57900 17.49400 1.000 91.54000 O ? A ? 36 0 + ATOM 247 CB . ASN A 36 ? -13.34400 1.92300 20.37900 1.000 91.54000 C ? A ? 36 0 + ATOM 248 CG . ASN A 36 ? -13.55900 3.37600 20.76300 1.000 91.54000 C ? A ? 36 0 + ATOM 249 OD1 . ASN A 36 ? -14.64600 3.92000 20.69100 1.000 91.54000 O ? A ? 36 0 + ATOM 250 ND2 . ASN A 36 ? -12.53400 4.04600 21.22800 1.000 91.54000 N ? A ? 36 0 + ATOM 251 N . LEU A 37 ? -16.22700 2.45900 18.45100 1.000 88.49000 N ? A ? 37 0 + ATOM 252 CA . LEU A 37 ? -16.79700 3.01600 17.22900 1.000 88.49000 C ? A ? 37 0 + ATOM 253 C . LEU A 37 ? -16.12800 4.35200 16.90600 1.000 88.49000 C ? A ? 37 0 + ATOM 254 O . LEU A 37 ? -16.25600 5.31400 17.66000 1.000 88.49000 O ? A ? 37 0 + ATOM 255 CB . LEU A 37 ? -18.32100 3.16200 17.40800 1.000 88.49000 C ? A ? 37 0 + ATOM 256 CG . LEU A 37 ? -19.05600 3.77000 16.19600 1.000 88.49000 C ? A ? 37 0 + ATOM 257 CD1 . LEU A 37 ? -19.03900 2.85400 14.97200 1.000 88.49000 C ? A ? 37 0 + ATOM 258 CD2 . LEU A 37 ? -20.52200 4.02500 16.55300 1.000 88.49000 C ? A ? 37 0 + ATOM 259 N . ASP A 38 ? -15.48800 4.42000 15.74700 1.000 85.73000 N ? A ? 38 0 + ATOM 260 CA . ASP A 38 ? -15.11100 5.67200 15.11700 1.000 85.73000 C ? A ? 38 0 + ATOM 261 C . ASP A 38 ? -16.31500 6.23600 14.35300 1.000 85.73000 C ? A ? 38 0 + ATOM 262 O . ASP A 38 ? -16.79800 5.68800 13.35700 1.000 85.73000 O ? A ? 38 0 + ATOM 263 CB . ASP A 38 ? -13.89000 5.46000 14.22500 1.000 85.73000 C ? A ? 38 0 + ATOM 264 CG . ASP A 38 ? -13.43800 6.75100 13.54200 1.000 85.73000 C ? A ? 38 0 + ATOM 265 OD1 . ASP A 38 ? -14.08200 7.81000 13.74800 1.000 85.73000 O ? A ? 38 0 + ATOM 266 OD2 . ASP A 38 ? -12.48500 6.63400 12.75000 1.000 85.73000 O ? A ? 38 0 + ATOM 267 N . CYS A 39 ? -16.82400 7.35100 14.86700 1.000 79.80000 N ? A ? 39 0 + ATOM 268 CA . CYS A 39 ? -18.00400 8.02100 14.34800 1.000 79.80000 C ? A ? 39 0 + ATOM 269 C . CYS A 39 ? -17.77900 8.66600 12.96700 1.000 79.80000 C ? A ? 39 0 + ATOM 270 O . CYS A 39 ? -18.76000 8.90200 12.25900 1.000 79.80000 O ? A ? 39 0 + ATOM 271 CB . CYS A 39 ? -18.40100 9.07800 15.38200 1.000 79.80000 C ? A ? 39 0 + ATOM 272 SG . CYS A 39 ? -17.27400 10.49800 15.36400 1.000 79.80000 S ? A ? 39 0 + ATOM 273 N . ILE A 40 ? -16.52500 8.97100 12.60000 1.000 73.17000 N ? A ? 40 0 + ATOM 274 CA . ILE A 40 ? -16.18100 9.69300 11.36800 1.000 73.17000 C ? A ? 40 0 + ATOM 275 C . ILE A 40 ? -16.24900 8.72400 10.19700 1.000 73.17000 C ? A ? 40 0 + ATOM 276 O . ILE A 40 ? -16.99400 8.92900 9.24000 1.000 73.17000 O ? A ? 40 0 + ATOM 277 CB . ILE A 40 ? -14.78000 10.35100 11.47100 1.000 73.17000 C ? A ? 40 0 + ATOM 278 CG1 . ILE A 40 ? -14.72600 11.32500 12.67000 1.000 73.17000 C ? A ? 40 0 + ATOM 279 CG2 . ILE A 40 ? -14.43200 11.07400 10.15400 1.000 73.17000 C ? A ? 40 0 + ATOM 280 CD1 . ILE A 40 ? -13.37100 12.01300 12.87500 1.000 73.17000 C ? A ? 40 0 + ATOM 281 N . THR A 41 ? -15.50600 7.63100 10.31400 1.000 80.58000 N ? A ? 41 0 + ATOM 282 CA . THR A 41 ? -15.36200 6.62500 9.26000 1.000 80.58000 C ? A ? 41 0 + ATOM 283 C . THR A 41 ? -16.46700 5.56100 9.28100 1.000 80.58000 C ? A ? 41 0 + ATOM 284 O . THR A 41 ? -16.52200 4.70800 8.39600 1.000 80.58000 O ? A ? 41 0 + ATOM 285 CB . THR A 41 ? -13.96800 5.99000 9.34500 1.000 80.58000 C ? A ? 41 0 + ATOM 286 OG1 . THR A 41 ? -13.78100 5.47000 10.64100 1.000 80.58000 O ? A ? 41 0 + ATOM 287 CG2 . THR A 41 ? -12.84000 6.98900 9.10200 1.000 80.58000 C ? A ? 41 0 + ATOM 288 N . ASN A 42 ? -17.35300 5.58100 10.29000 1.000 85.30000 N ? A ? 42 0 + ATOM 289 CA . ASN A 42 ? -18.22300 4.45100 10.65100 1.000 85.30000 C ? A ? 42 0 + ATOM 290 C . ASN A 42 ? -17.46000 3.13000 10.68200 1.000 85.30000 C ? A ? 42 0 + ATOM 291 O . ASN A 42 ? -17.91600 2.10900 10.15900 1.000 85.30000 O ? A ? 42 0 + ATOM 292 CB . ASN A 42 ? -19.45400 4.33100 9.74700 1.000 85.30000 C ? A ? 42 0 + ATOM 293 CG . ASN A 42 ? -20.52200 5.34000 9.99600 1.000 85.30000 C ? A ? 42 0 + ATOM 294 OD1 . ASN A 42 ? -20.49200 6.09000 10.95000 1.000 85.30000 O ? A ? 42 0 + ATOM 295 ND2 . ASN A 42 ? -21.56400 5.32500 9.20200 1.000 85.30000 N ? A ? 42 0 + ATOM 296 N . SER A 43 ? -16.27800 3.15900 11.27300 1.000 89.68000 N ? A ? 43 0 + ATOM 297 CA . SER A 43 ? -15.47100 1.97000 11.44900 1.000 89.68000 C ? A ? 43 0 + ATOM 298 C . SER A 43 ? -15.40300 1.61000 12.92400 1.000 89.68000 C ? A ? 43 0 + ATOM 299 O . SER A 43 ? -15.64100 2.44300 13.79700 1.000 89.68000 O ? A ? 43 0 + ATOM 300 CB . SER A 43 ? -14.12500 2.14300 10.75500 1.000 89.68000 C ? A ? 43 0 + ATOM 301 OG . SER A 43 ? -13.27600 3.03600 11.43800 1.000 89.68000 O ? A ? 43 0 + ATOM 302 N . VAL A 44 ? -15.17800 0.33800 13.22700 1.000 93.01000 N ? A ? 44 0 + ATOM 303 CA . VAL A 44 ? -15.02400 -0.11300 14.61000 1.000 93.01000 C ? A ? 44 0 + ATOM 304 C . VAL A 44 ? -13.63600 -0.69200 14.77100 1.000 93.01000 C ? A ? 44 0 + ATOM 305 O . VAL A 44 ? -13.30500 -1.71900 14.17500 1.000 93.01000 O ? A ? 44 0 + ATOM 306 CB . VAL A 44 ? -16.13100 -1.09000 15.03400 1.000 93.01000 C ? A ? 44 0 + ATOM 307 CG1 . VAL A 44 ? -15.85300 -1.73000 16.40100 1.000 93.01000 C ? A ? 44 0 + ATOM 308 CG2 . VAL A 44 ? -17.47400 -0.35800 15.16000 1.000 93.01000 C ? A ? 44 0 + ATOM 309 N . TRP A 45 ? -12.86400 -0.07200 15.65600 1.000 93.90000 N ? A ? 45 0 + ATOM 310 CA . TRP A 45 ? -11.62100 -0.63100 16.15000 1.000 93.90000 C ? A ? 45 0 + ATOM 311 C . TRP A 45 ? -11.93000 -1.72200 17.15800 1.000 93.90000 C ? A ? 45 0 + ATOM 312 O . TRP A 45 ? -12.39900 -1.44600 18.26200 1.000 93.90000 O ? A ? 45 0 + ATOM 313 CB . TRP A 45 ? -10.76200 0.47200 16.76000 1.000 93.90000 C ? A ? 45 0 + ATOM 314 CG . TRP A 45 ? -10.09400 1.31200 15.72800 1.000 93.90000 C ? A ? 45 0 + ATOM 315 CD1 . TRP A 45 ? -10.50400 2.52600 15.29700 1.000 93.90000 C ? A ? 45 0 + ATOM 316 CD2 . TRP A 45 ? -8.93200 0.96600 14.91900 1.000 93.90000 C ? A ? 45 0 + ATOM 317 NE1 . TRP A 45 ? -9.65600 2.97200 14.30200 1.000 93.90000 N ? A ? 45 0 + ATOM 318 CE2 . TRP A 45 ? -8.66000 2.05400 14.03800 1.000 93.90000 C ? A ? 45 0 + ATOM 319 CE3 . TRP A 45 ? -8.08900 -0.16800 14.83800 1.000 93.90000 C ? A ? 45 0 + ATOM 320 CZ2 . TRP A 45 ? -7.58300 2.03300 13.14100 1.000 93.90000 C ? A ? 45 0 + ATOM 321 CZ3 . TRP A 45 ? -7.00300 -0.19800 13.94100 1.000 93.90000 C ? A ? 45 0 + ATOM 322 CH2 . TRP A 45 ? -6.74500 0.90300 13.10100 1.000 93.90000 C ? A ? 45 0 + ATOM 323 N . VAL A 46 ? -11.66300 -2.96400 16.77100 1.000 95.79000 N ? A ? 46 0 + ATOM 324 CA . VAL A 46 ? -11.81500 -4.13300 17.63400 1.000 95.79000 C ? A ? 46 0 + ATOM 325 C . VAL A 46 ? -10.45400 -4.51000 18.20000 1.000 95.79000 C ? A ? 46 0 + ATOM 326 O . VAL A 46 ? -9.47300 -4.54800 17.46100 1.000 95.79000 O ? A ? 46 0 + ATOM 327 CB . VAL A 46 ? -12.49500 -5.29400 16.89000 1.000 95.79000 C ? A ? 46 0 + ATOM 328 CG1 . VAL A 46 ? -12.79400 -6.45700 17.84300 1.000 95.79000 C ? A ? 46 0 + ATOM 329 CG2 . VAL A 46 ? -13.82500 -4.83300 16.28000 1.000 95.79000 C ? A ? 46 0 + ATOM 330 N . THR A 47 ? -10.38800 -4.78000 19.49900 1.000 96.42000 N ? A ? 47 0 + ATOM 331 CA . THR A 47 ? -9.18700 -5.21400 20.22200 1.000 96.42000 C ? A ? 47 0 + ATOM 332 C . THR A 47 ? -9.45700 -6.52000 20.96200 1.000 96.42000 C ? A ? 47 0 + ATOM 333 O . THR A 47 ? -10.60000 -6.81600 21.30500 1.000 96.42000 O ? A ? 47 0 + ATOM 334 CB . THR A 47 ? -8.68900 -4.14000 21.20200 1.000 96.42000 C ? A ? 47 0 + ATOM 335 OG1 . THR A 47 ? -9.65200 -3.85100 22.18600 1.000 96.42000 O ? A ? 47 0 + ATOM 336 CG2 . THR A 47 ? -8.37300 -2.81400 20.51100 1.000 96.42000 C ? A ? 47 0 + ATOM 337 N . TRP A 48 ? -8.41900 -7.33000 21.17000 1.000 95.00000 N ? A ? 48 0 + ATOM 338 CA . TRP A 48 ? -8.50100 -8.61800 21.87100 1.000 95.00000 C ? A ? 48 0 + ATOM 339 C . TRP A 48 ? -7.15500 -8.99300 22.49900 1.000 95.00000 C ? A ? 48 0 + ATOM 340 O . TRP A 48 ? -6.11900 -8.38100 22.23100 1.000 95.00000 O ? A ? 48 0 + ATOM 341 CB . TRP A 48 ? -8.95000 -9.71700 20.89300 1.000 95.00000 C ? A ? 48 0 + ATOM 342 CG . TRP A 48 ? -8.11200 -9.83000 19.65800 1.000 95.00000 C ? A ? 48 0 + ATOM 343 CD1 . TRP A 48 ? -6.99800 -10.57900 19.49900 1.000 95.00000 C ? A ? 48 0 + ATOM 344 CD2 . TRP A 48 ? -8.30300 -9.13300 18.39700 1.000 95.00000 C ? A ? 48 0 + ATOM 345 NE1 . TRP A 48 ? -6.48000 -10.37600 18.23600 1.000 95.00000 N ? A ? 48 0 + ATOM 346 CE2 . TRP A 48 ? -7.24400 -9.49100 17.51800 1.000 95.00000 C ? A ? 48 0 + ATOM 347 CE3 . TRP A 48 ? -9.27000 -8.23200 17.91600 1.000 95.00000 C ? A ? 48 0 + ATOM 348 CZ2 . TRP A 48 ? -7.14800 -8.98500 16.22100 1.000 95.00000 C ? A ? 48 0 + ATOM 349 CZ3 . TRP A 48 ? -9.20600 -7.74100 16.60100 1.000 95.00000 C ? A ? 48 0 + ATOM 350 CH2 . TRP A 48 ? -8.16100 -8.14200 15.75400 1.000 95.00000 C ? A ? 48 0 + ATOM 351 N . LEU A 49 ? -7.15300 -10.03500 23.33100 1.000 95.28000 N ? A ? 49 0 + ATOM 352 CA . LEU A 49 ? -5.94000 -10.60400 23.91400 1.000 95.28000 C ? A ? 49 0 + ATOM 353 C . LEU A 49 ? -5.31400 -11.65600 22.99200 1.000 95.28000 C ? A ? 49 0 + ATOM 354 O . LEU A 49 ? -6.00400 -12.35800 22.25300 1.000 95.28000 O ? A ? 49 0 + ATOM 355 CB . LEU A 49 ? -6.25600 -11.18600 25.30000 1.000 95.28000 C ? A ? 49 0 + ATOM 356 CG . LEU A 49 ? -6.80800 -10.15700 26.30500 1.000 95.28000 C ? A ? 49 0 + ATOM 357 CD1 . LEU A 49 ? -7.19700 -10.87300 27.59800 1.000 95.28000 C ? A ? 49 0 + ATOM 358 CD2 . LEU A 49 ? -5.77600 -9.07600 26.64300 1.000 95.28000 C ? A ? 49 0 + ATOM 359 N . GLN A 50 ? -3.98800 -11.79800 23.06000 1.000 94.37000 N ? A ? 50 0 + ATOM 360 CA . GLN A 50 ? -3.25800 -12.76000 22.23700 1.000 94.37000 C ? A ? 50 0 + ATOM 361 C . GLN A 50 ? -3.69900 -14.20500 22.52600 1.000 94.37000 C ? A ? 50 0 + ATOM 362 O . GLN A 50 ? -3.44400 -14.75000 23.60000 1.000 94.37000 O ? A ? 50 0 + ATOM 363 CB . GLN A 50 ? -1.74500 -12.57400 22.43500 1.000 94.37000 C ? A ? 50 0 + ATOM 364 CG . GLN A 50 ? -0.93600 -13.43700 21.45100 1.000 94.37000 C ? A ? 50 0 + ATOM 365 CD . GLN A 50 ? 0.56500 -13.16400 21.50000 1.000 94.37000 C ? A ? 50 0 + ATOM 366 OE1 . GLN A 50 ? 1.10100 -12.54700 22.40300 1.000 94.37000 O ? A ? 50 0 + ATOM 367 NE2 . GLN A 50 ? 1.31400 -13.62200 20.52100 1.000 94.37000 N ? A ? 50 0 + ATOM 368 N . ALA A 51 ? -4.29900 -14.85500 21.53000 1.000 94.47000 N ? A ? 51 0 + ATOM 369 CA . ALA A 51 ? -4.63000 -16.26900 21.56200 1.000 94.47000 C ? A ? 51 0 + ATOM 370 C . ALA A 51 ? -3.38400 -17.13100 21.30600 1.000 94.47000 C ? A ? 51 0 + ATOM 371 O . ALA A 51 ? -2.60300 -16.90800 20.37400 1.000 94.47000 O ? A ? 51 0 + ATOM 372 CB . ALA A 51 ? -5.73700 -16.54700 20.54600 1.000 94.47000 C ? A ? 51 0 + ATOM 373 N . LYS A 52 ? -3.19700 -18.17200 22.12100 1.000 92.16000 N ? A ? 52 0 + ATOM 374 CA . LYS A 52 ? -2.06300 -19.09200 21.98500 1.000 92.16000 C ? A ? 52 0 + ATOM 375 C . LYS A 52 ? -2.14100 -19.84700 20.65200 1.000 92.16000 C ? A ? 52 0 + ATOM 376 O . LYS A 52 ? -3.13200 -20.51300 20.36000 1.000 92.16000 O ? A ? 52 0 + ATOM 377 CB . LYS A 52 ? -2.02700 -20.02300 23.20200 1.000 92.16000 C ? A ? 52 0 + ATOM 378 CG . LYS A 52 ? -0.76200 -20.89000 23.26300 1.000 92.16000 C ? A ? 52 0 + ATOM 379 CD . LYS A 52 ? -0.79800 -21.76200 24.52500 1.000 92.16000 C ? A ? 52 0 + ATOM 380 CE . LYS A 52 ? 0.47000 -22.61200 24.64200 1.000 92.16000 C ? A ? 52 0 + ATOM 381 NZ . LYS A 52 ? 0.45800 -23.42100 25.88800 1.000 92.16000 N ? A ? 52 0 + ATOM 382 N . GLY A 53 ? -1.06600 -19.77000 19.86900 1.000 90.79000 N ? A ? 53 0 + ATOM 383 CA . GLY A 53 ? -0.94400 -20.44800 18.57300 1.000 90.79000 C ? A ? 53 0 + ATOM 384 C . GLY A 53 ? -1.53600 -19.69100 17.38100 1.000 90.79000 C ? A ? 53 0 + ATOM 385 O . GLY A 53 ? -1.51300 -20.23600 16.27900 1.000 90.79000 O ? A ? 53 0 + ATOM 386 N . ALA A 54 ? -2.04500 -18.47100 17.57900 1.000 92.72000 N ? A ? 54 0 + ATOM 387 CA . ALA A 54 ? -2.51700 -17.60800 16.50100 1.000 92.72000 C ? A ? 54 0 + ATOM 388 C . ALA A 54 ? -1.34600 -16.89800 15.79800 1.000 92.72000 C ? A ? 54 0 + ATOM 389 O . ALA A 54 ? -0.43700 -16.39400 16.45800 1.000 92.72000 O ? A ? 54 0 + ATOM 390 CB . ALA A 54 ? -3.50100 -16.59800 17.09100 1.000 92.72000 C ? A ? 54 0 + ATOM 391 N . LEU A 55 ? -1.39200 -16.84600 14.46700 1.000 93.25000 N ? A ? 55 0 + ATOM 392 CA . LEU A 55 ? -0.49600 -16.04900 13.61900 1.000 93.25000 C ? A ? 55 0 + ATOM 393 C . LEU A 55 ? -1.19800 -14.80200 13.06700 1.000 93.25000 C ? A ? 55 0 + ATOM 394 O . LEU A 55 ? -0.55000 -13.79600 12.79400 1.000 93.25000 O ? A ? 55 0 + ATOM 395 CB . LEU A 55 ? 0.01600 -16.91300 12.45300 1.000 93.25000 C ? A ? 55 0 + ATOM 396 CG . LEU A 55 ? 0.84100 -18.14500 12.86000 1.000 93.25000 C ? A ? 55 0 + ATOM 397 CD1 . LEU A 55 ? 1.25700 -18.90700 11.60200 1.000 93.25000 C ? A ? 55 0 + ATOM 398 CD2 . LEU A 55 ? 2.10700 -17.77100 13.63200 1.000 93.25000 C ? A ? 55 0 + ATOM 399 N . SER A 56 ? -2.51700 -14.87300 12.90400 1.000 95.79000 N ? A ? 56 0 + ATOM 400 CA . SER A 56 ? -3.36300 -13.76700 12.46600 1.000 95.79000 C ? A ? 56 0 + ATOM 401 C . SER A 56 ? -4.77600 -13.91800 13.02700 1.000 95.79000 C ? A ? 56 0 + ATOM 402 O . SER A 56 ? -5.13100 -14.95200 13.60000 1.000 95.79000 O ? A ? 56 0 + ATOM 403 CB . SER A 56 ? -3.38400 -13.68300 10.93400 1.000 95.79000 C ? A ? 56 0 + ATOM 404 OG . SER A 56 ? -3.86900 -14.87900 10.35200 1.000 95.79000 O ? A ? 56 0 + ATOM 405 N . TYR A 57 ? -5.57600 -12.87000 12.88000 1.000 96.56000 N ? A ? 57 0 + ATOM 406 CA . TYR A 57 ? -6.96000 -12.80500 13.32500 1.000 96.56000 C ? A ? 57 0 + ATOM 407 C . TYR A 57 ? -7.84700 -12.26700 12.20600 1.000 96.56000 C ? A ? 57 0 + ATOM 408 O . TYR A 57 ? -7.41100 -11.45500 11.38700 1.000 96.56000 O ? A ? 57 0 + ATOM 409 CB . TYR A 57 ? -7.07200 -11.92100 14.56800 1.000 96.56000 C ? A ? 57 0 + ATOM 410 CG . TYR A 57 ? -6.25100 -12.40200 15.74800 1.000 96.56000 C ? A ? 57 0 + ATOM 411 CD1 . TYR A 57 ? -6.84000 -13.20300 16.74600 1.000 96.56000 C ? A ? 57 0 + ATOM 412 CD2 . TYR A 57 ? -4.89500 -12.03500 15.84700 1.000 96.56000 C ? A ? 57 0 + ATOM 413 CE1 . TYR A 57 ? -6.06800 -13.64800 17.83800 1.000 96.56000 C ? A ? 57 0 + ATOM 414 CE2 . TYR A 57 ? -4.11400 -12.50000 16.91600 1.000 96.56000 C ? A ? 57 0 + ATOM 415 CZ . TYR A 57 ? -4.70200 -13.30900 17.90900 1.000 96.56000 C ? A ? 57 0 + ATOM 416 OH . TYR A 57 ? -3.93200 -13.74100 18.93500 1.000 96.56000 O ? A ? 57 0 + ATOM 417 N . SER A 58 ? -9.10200 -12.70400 12.20300 1.000 96.21000 N ? A ? 58 0 + ATOM 418 CA . SER A 58 ? -10.16300 -12.19300 11.34100 1.000 96.21000 C ? A ? 58 0 + ATOM 419 C . SER A 58 ? -11.32700 -11.72700 12.20600 1.000 96.21000 C ? A ? 58 0 + ATOM 420 O . SER A 58 ? -11.73900 -12.43500 13.12800 1.000 96.21000 O ? A ? 58 0 + ATOM 421 CB . SER A 58 ? -10.60600 -13.27100 10.35300 1.000 96.21000 C ? A ? 58 0 + ATOM 422 OG . SER A 58 ? -11.59400 -12.76800 9.48200 1.000 96.21000 O ? A ? 58 0 + ATOM 423 N . VAL A 59 ? -11.83600 -10.53200 11.91700 1.000 96.83000 N ? A ? 59 0 + ATOM 424 CA . VAL A 59 ? -13.00400 -9.94900 12.57400 1.000 96.83000 C ? A ? 59 0 + ATOM 425 C . VAL A 59 ? -14.14000 -9.88000 11.56500 1.000 96.83000 C ? A ? 59 0 + ATOM 426 O . VAL A 59 ? -13.96200 -9.32800 10.48100 1.000 96.83000 O ? A ? 59 0 + ATOM 427 CB . VAL A 59 ? -12.71200 -8.55300 13.14700 1.000 96.83000 C ? A ? 59 0 + ATOM 428 CG1 . VAL A 59 ? -13.89400 -8.05100 13.98300 1.000 96.83000 C ? A ? 59 0 + ATOM 429 CG2 . VAL A 59 ? -11.46200 -8.53900 14.03400 1.000 96.83000 C ? A ? 59 0 + ATOM 430 N . LEU A 60 ? -15.30500 -10.40900 11.92800 1.000 96.31000 N ? A ? 60 0 + ATOM 431 CA . LEU A 60 ? -16.52300 -10.36200 11.12400 1.000 96.31000 C ? A ? 60 0 + ATOM 432 C . LEU A 60 ? -17.59600 -9.56200 11.86300 1.000 96.31000 C ? A ? 60 0 + ATOM 433 O . LEU A 60 ? -17.96600 -9.91600 12.97900 1.000 96.31000 O ? A ? 60 0 + ATOM 434 CB . LEU A 60 ? -16.97200 -11.80400 10.82700 1.000 96.31000 C ? A ? 60 0 + ATOM 435 CG . LEU A 60 ? -18.26200 -11.90200 9.99400 1.000 96.31000 C ? A ? 60 0 + ATOM 436 CD1 . LEU A 60 ? -18.07200 -11.38900 8.56600 1.000 96.31000 C ? A ? 60 0 + ATOM 437 CD2 . LEU A 60 ? -18.72600 -13.35800 9.92900 1.000 96.31000 C ? A ? 60 0 + ATOM 438 N . ALA A 61 ? -18.11200 -8.51600 11.22700 1.000 96.00000 N ? A ? 61 0 + ATOM 439 CA . ALA A 61 ? -19.25600 -7.74300 11.68600 1.000 96.00000 C ? A ? 61 0 + ATOM 440 C . ALA A 61 ? -20.49500 -8.14400 10.88000 1.000 96.00000 C ? A ? 61 0 + ATOM 441 O . ALA A 61 ? -20.52700 -7.98600 9.66000 1.000 96.00000 O ? A ? 61 0 + ATOM 442 CB . ALA A 61 ? -18.93000 -6.25500 11.55800 1.000 96.00000 C ? A ? 61 0 + ATOM 443 N . VAL A 62 ? -21.50800 -8.66600 11.56900 1.000 95.34000 N ? A ? 62 0 + ATOM 444 CA . VAL A 62 ? -22.75700 -9.14400 10.96700 1.000 95.34000 C ? A ? 62 0 + ATOM 445 C . VAL A 62 ? -23.89800 -8.20200 11.31700 1.000 95.34000 C ? A ? 62 0 + ATOM 446 O . VAL A 62 ? -24.15300 -7.94500 12.49500 1.000 95.34000 O ? A ? 62 0 + ATOM 447 CB . VAL A 62 ? -23.07800 -10.58900 11.39000 1.000 95.34000 C ? A ? 62 0 + ATOM 448 CG1 . VAL A 62 ? -24.34300 -11.12000 10.70300 1.000 95.34000 C ? A ? 62 0 + ATOM 449 CG2 . VAL A 62 ? -21.92300 -11.53600 11.03900 1.000 95.34000 C ? A ? 62 0 + ATOM 450 N . GLU A 63 ? -24.60000 -7.72100 10.29900 1.000 93.27000 N ? A ? 63 0 + ATOM 451 CA . GLU A 63 ? -25.77100 -6.85100 10.42800 1.000 93.27000 C ? A ? 63 0 + ATOM 452 C . GLU A 63 ? -27.03700 -7.61400 10.00900 1.000 93.27000 C ? A ? 63 0 + ATOM 453 O . GLU A 63 ? -26.98900 -8.52600 9.18200 1.000 93.27000 O ? A ? 63 0 + ATOM 454 CB . GLU A 63 ? -25.48800 -5.56000 9.65100 1.000 93.27000 C ? A ? 63 0 + ATOM 455 CG . GLU A 63 ? -26.51600 -4.42800 9.79900 1.000 93.27000 C ? A ? 63 0 + ATOM 456 CD . GLU A 63 ? -27.74800 -4.66200 8.93500 1.000 93.27000 C ? A ? 63 0 + ATOM 457 OE1 . GLU A 63 ? -28.86600 -4.43400 9.45100 1.000 93.27000 O ? A ? 63 0 + ATOM 458 OE2 . GLU A 63 ? -27.59300 -5.23100 7.83400 1.000 93.27000 O ? A ? 63 0 + ATOM 459 N . LYS A 64 ? -28.18400 -7.29400 10.62200 1.000 85.77000 N ? A ? 64 0 + ATOM 460 CA . LYS A 64 ? -29.42700 -8.06900 10.44700 1.000 85.77000 C ? A ? 64 0 + ATOM 461 C . LYS A 64 ? -29.96100 -8.06500 9.01000 1.000 85.77000 C ? A ? 64 0 + ATOM 462 O . LYS A 64 ? -30.61400 -9.02900 8.62200 1.000 85.77000 O ? A ? 64 0 + ATOM 463 CB . LYS A 64 ? -30.51700 -7.54900 11.39300 1.000 85.77000 C ? A ? 64 0 + ATOM 464 CG . LYS A 64 ? -30.26000 -7.91900 12.85900 1.000 85.77000 C ? A ? 64 0 + ATOM 465 CD . LYS A 64 ? -31.44500 -7.47100 13.72300 1.000 85.77000 C ? A ? 64 0 + ATOM 466 CE . LYS A 64 ? -31.21100 -7.85000 15.18700 1.000 85.77000 C ? A ? 64 0 + ATOM 467 NZ . LYS A 64 ? -32.31400 -7.36400 16.05200 1.000 85.77000 N ? A ? 64 0 + ATOM 468 N . GLN A 65 ? -29.72300 -7.00100 8.24900 1.000 82.48000 N ? A ? 65 0 + ATOM 469 CA . GLN A 65 ? -30.13500 -6.83000 6.85400 1.000 82.48000 C ? A ? 65 0 + ATOM 470 C . GLN A 65 ? -29.06200 -7.29500 5.85000 1.000 82.48000 C ? A ? 65 0 + ATOM 471 O . GLN A 65 ? -29.27800 -7.20200 4.64300 1.000 82.48000 O ? A ? 65 0 + ATOM 472 CB . GLN A 65 ? -30.56100 -5.37000 6.60100 1.000 82.48000 C ? A ? 65 0 + ATOM 473 CG . GLN A 65 ? -31.63900 -4.87500 7.57800 1.000 82.48000 C ? A ? 65 0 + ATOM 474 CD . GLN A 65 ? -32.04300 -3.42300 7.34400 1.000 82.48000 C ? A ? 65 0 + ATOM 475 OE1 . GLN A 65 ? -31.62700 -2.73700 6.42900 1.000 82.48000 O ? A ? 65 0 + ATOM 476 NE2 . GLN A 65 ? -32.92700 -2.88800 8.15800 1.000 82.48000 N ? A ? 65 0 + ATOM 477 N . GLY A 66 ? -27.94400 -7.85900 6.32200 1.000 86.08000 N ? A ? 66 0 + ATOM 478 CA . GLY A 66 ? -26.91200 -8.47800 5.48900 1.000 86.08000 C ? A ? 66 0 + ATOM 479 C . GLY A 66 ? -25.77100 -7.55000 5.07100 1.000 86.08000 C ? A ? 66 0 + ATOM 480 O . GLY A 66 ? -24.92400 -7.97100 4.28100 1.000 86.08000 O ? A ? 66 0 + ATOM 481 N . ALA A 67 ? -25.69900 -6.32500 5.60300 1.000 86.59000 N ? A ? 67 0 + ATOM 482 CA . ALA A 67 ? -24.60400 -5.38900 5.34100 1.000 86.59000 C ? A ? 67 0 + ATOM 483 C . ALA A 67 ? -23.32200 -5.76200 6.11400 1.000 86.59000 C ? A ? 67 0 + ATOM 484 O . ALA A 67 ? -22.80800 -4.98100 6.90700 1.000 86.59000 O ? A ? 67 0 + ATOM 485 CB . ALA A 67 ? -25.09600 -3.96300 5.62200 1.000 86.59000 C ? A ? 67 0 + ATOM 486 N . ASN A 68 ? -22.81500 -6.98000 5.92200 1.000 92.76000 N ? A ? 68 0 + ATOM 487 CA . ASN A 68 ? -21.67500 -7.49500 6.67700 1.000 92.76000 C ? A ? 68 0 + ATOM 488 C . ASN A 68 ? -20.36500 -6.81400 6.25900 1.000 92.76000 C ? A ? 68 0 + ATOM 489 O . ASN A 68 ? -20.14300 -6.53800 5.08100 1.000 92.76000 O ? A ? 68 0 + ATOM 490 CB . ASN A 68 ? -21.58500 -9.02100 6.52200 1.000 92.76000 C ? A ? 68 0 + ATOM 491 CG . ASN A 68 ? -22.80900 -9.75700 7.03300 1.000 92.76000 C ? A ? 68 0 + ATOM 492 OD1 . ASN A 68 ? -23.64800 -9.24700 7.75600 1.000 92.76000 O ? A ? 68 0 + ATOM 493 ND2 . ASN A 68 ? -22.95000 -11.01300 6.68200 1.000 92.76000 N ? A ? 68 0 + ATOM 494 N . SER A 69 ? -19.46400 -6.62600 7.21800 1.000 93.63000 N ? A ? 69 0 + ATOM 495 CA . SER A 69 ? -18.11000 -6.12100 6.97700 1.000 93.63000 C ? A ? 69 0 + ATOM 496 C . SER A 69 ? -17.08800 -6.97800 7.71500 1.000 93.63000 C ? A ? 69 0 + ATOM 497 O . SER A 69 ? -17.42700 -7.72100 8.63700 1.000 93.63000 O ? A ? 69 0 + ATOM 498 CB . SER A 69 ? -18.00500 -4.64300 7.35500 1.000 93.63000 C ? A ? 69 0 + ATOM 499 OG . SER A 69 ? -16.73400 -4.16300 6.96800 1.000 93.63000 O ? A ? 69 0 + ATOM 500 N . SER A 70 ? -15.82900 -6.92900 7.29600 1.000 95.92000 N ? A ? 70 0 + ATOM 501 CA . SER A 70 ? -14.77000 -7.70900 7.92900 1.000 95.92000 C ? A ? 70 0 + ATOM 502 C . SER A 70 ? -13.41800 -7.02400 7.82300 1.000 95.92000 C ? A ? 70 0 + ATOM 503 O . SER A 70 ? -13.20900 -6.15300 6.98100 1.000 95.92000 O ? A ? 70 0 + ATOM 504 CB . SER A 70 ? -14.71200 -9.12500 7.34100 1.000 95.92000 C ? A ? 70 0 + ATOM 505 OG . SER A 70 ? -14.35300 -9.09500 5.97400 1.000 95.92000 O ? A ? 70 0 + ATOM 506 N . CYS A 71 ? -12.49200 -7.43800 8.67800 1.000 95.74000 N ? A ? 71 0 + ATOM 507 CA . CYS A 71 ? -11.10000 -7.02700 8.59900 1.000 95.74000 C ? A ? 71 0 + ATOM 508 C . CYS A 71 ? -10.18700 -8.17700 9.05500 1.000 95.74000 C ? A ? 71 0 + ATOM 509 O . CYS A 71 ? -10.62700 -9.10600 9.73600 1.000 95.74000 O ? A ? 71 0 + ATOM 510 CB . CYS A 71 ? -10.93300 -5.72400 9.38800 1.000 95.74000 C ? A ? 71 0 + ATOM 511 SG . CYS A 71 ? -10.86200 -5.90400 11.17800 1.000 95.74000 S ? A ? 71 0 + ATOM 512 N . SER A 72 ? -8.92000 -8.15600 8.64100 1.000 95.46000 N ? A ? 72 0 + ATOM 513 CA . SER A 72 ? -7.92000 -9.15100 9.04600 1.000 95.46000 C ? A ? 72 0 + ATOM 514 C . SER A 72 ? -6.63500 -8.46100 9.48100 1.000 95.46000 C ? A ? 72 0 + ATOM 515 O . SER A 72 ? -6.21400 -7.49400 8.84900 1.000 95.46000 O ? A ? 72 0 + ATOM 516 CB . SER A 72 ? -7.62900 -10.14000 7.91500 1.000 95.46000 C ? A ? 72 0 + ATOM 517 OG . SER A 72 ? -8.79600 -10.87100 7.59300 1.000 95.46000 O ? A ? 72 0 + ATOM 518 N . ALA A 73 ? -6.00900 -8.96000 10.54500 1.000 94.81000 N ? A ? 73 0 + ATOM 519 CA . ALA A 73 ? -4.80600 -8.36300 11.11400 1.000 94.81000 C ? A ? 73 0 + ATOM 520 C . ALA A 73 ? -3.86200 -9.41700 11.70600 1.000 94.81000 C ? A ? 73 0 + ATOM 521 O . ALA A 73 ? -4.28800 -10.45600 12.20900 1.000 94.81000 O ? A ? 73 0 + ATOM 522 CB . ALA A 73 ? -5.22000 -7.33300 12.17000 1.000 94.81000 C ? A ? 73 0 + ATOM 523 N . THR A 74 ? -2.55900 -9.13900 11.66500 1.000 94.25000 N ? A ? 74 0 + ATOM 524 CA . THR A 74 ? -1.53200 -9.87700 12.42500 1.000 94.25000 C ? A ? 74 0 + ATOM 525 C . THR A 74 ? -1.28100 -9.25700 13.80300 1.000 94.25000 C ? A ? 74 0 + ATOM 526 O . THR A 74 ? -0.63600 -9.86800 14.65400 1.000 94.25000 O ? A ? 74 0 + ATOM 527 CB . THR A 74 ? -0.21600 -9.93600 11.64100 1.000 94.25000 C ? A ? 74 0 + ATOM 528 OG1 . THR A 74 ? 0.16300 -8.63400 11.25300 1.000 94.25000 O ? A ? 74 0 + ATOM 529 CG2 . THR A 74 ? -0.34900 -10.77000 10.36700 1.000 94.25000 C ? A ? 74 0 + ATOM 530 N . THR A 75 ? -1.80000 -8.05000 14.03300 1.000 94.54000 N ? A ? 75 0 + ATOM 531 CA . THR A 75 ? -1.79600 -7.33900 15.31300 1.000 94.54000 C ? A ? 75 0 + ATOM 532 C . THR A 75 ? -2.97700 -7.76900 16.19300 1.000 94.54000 C ? A ? 75 0 + ATOM 533 O . THR A 75 ? -3.81900 -8.57200 15.79600 1.000 94.54000 O ? A ? 75 0 + ATOM 534 CB . THR A 75 ? -1.80800 -5.81600 15.06800 1.000 94.54000 C ? A ? 75 0 + ATOM 535 OG1 . THR A 75 ? -2.87500 -5.47300 14.22100 1.000 94.54000 O ? A ? 75 0 + ATOM 536 CG2 . THR A 75 ? -0.52200 -5.35200 14.38000 1.000 94.54000 C ? A ? 75 0 + ATOM 537 N . LEU A 76 ? -3.03300 -7.24000 17.42000 1.000 95.39000 N ? A ? 76 0 + ATOM 538 CA . LEU A 76 ? -4.11000 -7.48700 18.39500 1.000 95.39000 C ? A ? 76 0 + ATOM 539 C . LEU A 76 ? -5.26900 -6.48100 18.29000 1.000 95.39000 C ? A ? 76 0 + ATOM 540 O . LEU A 76 ? -6.05100 -6.30700 19.22500 1.000 95.39000 O ? A ? 76 0 + ATOM 541 CB . LEU A 76 ? -3.51600 -7.51200 19.81200 1.000 95.39000 C ? A ? 76 0 + ATOM 542 CG . LEU A 76 ? -2.44100 -8.58300 20.04500 1.000 95.39000 C ? A ? 76 0 + ATOM 543 CD1 . LEU A 76 ? -1.94100 -8.48200 21.48600 1.000 95.39000 C ? A ? 76 0 + ATOM 544 CD2 . LEU A 76 ? -2.96500 -10.00000 19.80300 1.000 95.39000 C ? A ? 76 0 + ATOM 545 N . ASN A 77 ? -5.32900 -5.76300 17.17400 1.000 94.82000 N ? A ? 77 0 + ATOM 546 CA . ASN A 77 ? -6.37800 -4.81500 16.86600 1.000 94.82000 C ? A ? 77 0 + ATOM 547 C . ASN A 77 ? -6.67900 -4.84300 15.37100 1.000 94.82000 C ? A ? 77 0 + ATOM 548 O . ASN A 77 ? -5.82400 -5.20200 14.56200 1.000 94.82000 O ? A ? 77 0 + ATOM 549 CB . ASN A 77 ? -6.00000 -3.41600 17.38400 1.000 94.82000 C ? A ? 77 0 + ATOM 550 CG . ASN A 77 ? -4.72300 -2.82700 16.80200 1.000 94.82000 C ? A ? 77 0 + ATOM 551 OD1 . ASN A 77 ? -4.23800 -3.15600 15.73300 1.000 94.82000 O ? A ? 77 0 + ATOM 552 ND2 . ASN A 77 ? -4.09800 -1.92400 17.51800 1.000 94.82000 N ? A ? 77 0 + ATOM 553 N . CYS A 78 ? -7.90000 -4.48600 14.99900 1.000 94.63000 N ? A ? 78 0 + ATOM 554 CA . CYS A 78 ? -8.29000 -4.42100 13.60100 1.000 94.63000 C ? A ? 78 0 + ATOM 555 C . CYS A 78 ? -9.45400 -3.45900 13.42400 1.000 94.63000 C ? A ? 78 0 + ATOM 556 O . CYS A 78 ? -10.38100 -3.45000 14.23500 1.000 94.63000 O ? A ? 78 0 + ATOM 557 CB . CYS A 78 ? -8.61200 -5.84000 13.14700 1.000 94.63000 C ? A ? 78 0 + ATOM 558 SG . CYS A 78 ? -8.87800 -6.12200 11.40000 1.000 94.63000 S ? A ? 78 0 + ATOM 559 N . ASN A 79 ? -9.38100 -2.64200 12.37700 1.000 93.71000 N ? A ? 79 0 + ATOM 560 CA . ASN A 79 ? -10.43800 -1.70400 12.05400 1.000 93.71000 C ? A ? 79 0 + ATOM 561 C . ASN A 79 ? -11.41100 -2.33800 11.06400 1.000 93.71000 C ? A ? 79 0 + ATOM 562 O . ASN A 79 ? -11.00600 -2.66500 9.95000 1.000 93.71000 O ? A ? 79 0 + ATOM 563 CB . ASN A 79 ? -9.83900 -0.40600 11.49500 1.000 93.71000 C ? A ? 79 0 + ATOM 564 CG . ASN A 79 ? -10.89100 0.68000 11.48900 1.000 93.71000 C ? A ? 79 0 + ATOM 565 OD1 . ASN A 79 ? -11.88600 0.57500 12.18200 1.000 93.71000 O ? A ? 79 0 + ATOM 566 ND2 . ASN A 79 ? -10.73100 1.73000 10.72500 1.000 93.71000 N ? A ? 79 0 + ATOM 567 N . VAL A 80 ? -12.67100 -2.51400 11.45800 1.000 94.29000 N ? A ? 80 0 + ATOM 568 CA . VAL A 80 ? -13.73200 -2.99800 10.56800 1.000 94.29000 C ? A ? 80 0 + ATOM 569 C . VAL A 80 ? -14.37500 -1.79400 9.87400 1.000 94.29000 C ? A ? 80 0 + ATOM 570 O . VAL A 80 ? -15.07100 -1.03600 10.55100 1.000 94.29000 O ? A ? 80 0 + ATOM 571 CB . VAL A 80 ? -14.78900 -3.82200 11.32200 1.000 94.29000 C ? A ? 80 0 + ATOM 572 CG1 . VAL A 80 ? -15.79800 -4.38800 10.31600 1.000 94.29000 C ? A ? 80 0 + ATOM 573 CG2 . VAL A 80 ? -14.18200 -5.01100 12.07500 1.000 94.29000 C ? A ? 80 0 + ATOM 574 N . PRO A 81 ? -14.16500 -1.58700 8.56000 1.000 91.02000 N ? A ? 81 0 + ATOM 575 CA . PRO A 81 ? -14.60700 -0.37800 7.86900 1.000 91.02000 C ? A ? 81 0 + ATOM 576 C . PRO A 81 ? -16.05200 -0.47700 7.35600 1.000 91.02000 C ? A ? 81 0 + ATOM 577 O . PRO A 81 ? -16.63200 -1.56300 7.28900 1.000 91.02000 O ? A ? 81 0 + ATOM 578 CB . PRO A 81 ? -13.60300 -0.21900 6.72400 1.000 91.02000 C ? A ? 81 0 + ATOM 579 CG . PRO A 81 ? -13.32600 -1.66700 6.32000 1.000 91.02000 C ? A ? 81 0 + ATOM 580 CD . PRO A 81 ? -13.36900 -2.41200 7.65200 1.000 91.02000 C ? A ? 81 0 + ATOM 581 N . GLY A 82 ? -16.61000 0.65500 6.91600 1.000 84.64000 N ? A ? 82 0 + ATOM 582 CA . GLY A 82 ? -17.78800 0.68300 6.04100 1.000 84.64000 C ? A ? 82 0 + ATOM 583 C . GLY A 82 ? -19.11100 0.26900 6.69100 1.000 84.64000 C ? A ? 82 0 + ATOM 584 O . GLY A 82 ? -19.98200 -0.27200 6.00700 1.000 84.64000 O ? A ? 82 0 + ATOM 585 N . LEU A 83 ? -19.28700 0.49700 7.99700 1.000 89.54000 N ? A ? 83 0 + ATOM 586 CA . LEU A 83 ? -20.54300 0.17100 8.66900 1.000 89.54000 C ? A ? 83 0 + ATOM 587 C . LEU A 83 ? -21.64000 1.17600 8.28200 1.000 89.54000 C ? A ? 83 0 + ATOM 588 O . LEU A 83 ? -21.46900 2.39800 8.32300 1.000 89.54000 O ? A ? 83 0 + ATOM 589 CB . LEU A 83 ? -20.35800 0.06900 10.19200 1.000 89.54000 C ? A ? 83 0 + ATOM 590 CG . LEU A 83 ? -19.19000 -0.82400 10.65500 1.000 89.54000 C ? A ? 83 0 + ATOM 591 CD1 . LEU A 83 ? -19.13700 -0.80300 12.17900 1.000 89.54000 C ? A ? 83 0 + ATOM 592 CD2 . LEU A 83 ? -19.32900 -2.28000 10.21700 1.000 89.54000 C ? A ? 83 0 + ATOM 593 N . GLN A 84 ? -22.81000 0.65800 7.92800 1.000 85.82000 N ? A ? 84 0 + ATOM 594 CA . GLN A 84 ? -23.98300 1.47500 7.62100 1.000 85.82000 C ? A ? 84 0 + ATOM 595 C . GLN A 84 ? -24.52000 2.17100 8.87700 1.000 85.82000 C ? A ? 84 0 + ATOM 596 O . GLN A 84 ? -24.45900 1.63400 9.98600 1.000 85.82000 O ? A ? 84 0 + ATOM 597 CB . GLN A 84 ? -25.07600 0.63200 6.94300 1.000 85.82000 C ? A ? 84 0 + ATOM 598 CG . GLN A 84 ? -24.60500 -0.01300 5.62900 1.000 85.82000 C ? A ? 84 0 + ATOM 599 CD . GLN A 84 ? -24.17400 1.02100 4.59200 1.000 85.82000 C ? A ? 84 0 + ATOM 600 OE1 . GLN A 84 ? -24.81300 2.04300 4.39600 1.000 85.82000 O ? A ? 84 0 + ATOM 601 NE2 . GLN A 84 ? -23.06000 0.82200 3.92300 1.000 85.82000 N ? A ? 84 0 + ATOM 602 N . CYS A 85 ? -25.07600 3.36500 8.69300 1.000 83.02000 N ? A ? 85 0 + ATOM 603 CA . CYS A 85 ? -25.74500 4.12600 9.74400 1.000 83.02000 C ? A ? 85 0 + ATOM 604 C . CYS A 85 ? -27.02600 3.44500 10.24900 1.000 83.02000 C ? A ? 85 0 + ATOM 605 O . CYS A 85 ? -27.76100 2.84100 9.47400 1.000 83.02000 O ? A ? 85 0 + ATOM 606 CB . CYS A 85 ? -26.09400 5.49900 9.18100 1.000 83.02000 C ? A ? 85 0 + ATOM 607 SG . CYS A 85 ? -24.86600 6.77000 9.49000 1.000 83.02000 S ? A ? 85 0 + ATOM 608 N . GLY A 86 ? -27.32600 3.60800 11.54100 1.000 82.47000 N ? A ? 86 0 + ATOM 609 CA . GLY A 86 ? -28.54300 3.09900 12.18300 1.000 82.47000 C ? A ? 86 0 + ATOM 610 C . GLY A 86 ? -28.63600 1.57300 12.30700 1.000 82.47000 C ? A ? 86 0 + ATOM 611 O . GLY A 86 ? -29.69100 1.06100 12.67800 1.000 82.47000 O ? A ? 86 0 + ATOM 612 N . GLY A 87 ? -27.56100 0.84600 12.00000 1.000 86.39000 N ? A ? 87 0 + ATOM 613 CA . GLY A 87 ? -27.49600 -0.61100 12.06800 1.000 86.39000 C ? A ? 87 0 + ATOM 614 C . GLY A 87 ? -26.97200 -1.11100 13.41400 1.000 86.39000 C ? A ? 87 0 + ATOM 615 O . GLY A 87 ? -26.17300 -0.45200 14.08000 1.000 86.39000 O ? A ? 87 0 + ATOM 616 N . THR A 88 ? -27.39100 -2.31300 13.81000 1.000 92.11000 N ? A ? 88 0 + ATOM 617 CA . THR A 88 ? -26.80000 -3.03600 14.94600 1.000 92.11000 C ? A ? 88 0 + ATOM 618 C . THR A 88 ? -25.94300 -4.17400 14.41600 1.000 92.11000 C ? A ? 88 0 + ATOM 619 O . THR A 88 ? -26.46400 -5.11100 13.80900 1.000 92.11000 O ? A ? 88 0 + ATOM 620 CB . THR A 88 ? -27.86100 -3.57700 15.91300 1.000 92.11000 C ? A ? 88 0 + ATOM 621 OG1 . THR A 88 ? -28.73900 -2.55900 16.33400 1.000 92.11000 O ? A ? 88 0 + ATOM 622 CG2 . THR A 88 ? -27.23200 -4.17000 17.17500 1.000 92.11000 C ? A ? 88 0 + ATOM 623 N . TYR A 89 ? -24.64100 -4.09900 14.67800 1.000 93.89000 N ? A ? 89 0 + ATOM 624 CA . TYR A 89 ? -23.65000 -5.06700 14.22400 1.000 93.89000 C ? A ? 89 0 + ATOM 625 C . TYR A 89 ? -23.24100 -5.98600 15.36900 1.000 93.89000 C ? A ? 89 0 + ATOM 626 O . TYR A 89 ? -22.98300 -5.51900 16.47700 1.000 93.89000 O ? A ? 89 0 + ATOM 627 CB . TYR A 89 ? -22.43500 -4.33500 13.64900 1.000 93.89000 C ? A ? 89 0 + ATOM 628 CG . TYR A 89 ? -22.71600 -3.66500 12.32500 1.000 93.89000 C ? A ? 89 0 + ATOM 629 CD1 . TYR A 89 ? -22.31400 -4.28800 11.13100 1.000 93.89000 C ? A ? 89 0 + ATOM 630 CD2 . TYR A 89 ? -23.39500 -2.43000 12.28500 1.000 93.89000 C ? A ? 89 0 + ATOM 631 CE1 . TYR A 89 ? -22.58400 -3.67000 9.89900 1.000 93.89000 C ? A ? 89 0 + ATOM 632 CE2 . TYR A 89 ? -23.72400 -1.84600 11.04900 1.000 93.89000 C ? A ? 89 0 + ATOM 633 CZ . TYR A 89 ? -23.33100 -2.47900 9.85200 1.000 93.89000 C ? A ? 89 0 + ATOM 634 OH . TYR A 89 ? -23.70800 -1.95600 8.66200 1.000 93.89000 O ? A ? 89 0 + ATOM 635 N . THR A 90 ? -23.16200 -7.28600 15.09100 1.000 95.39000 N ? A ? 90 0 + ATOM 636 CA . THR A 90 ? -22.59400 -8.29200 15.99900 1.000 95.39000 C ? A ? 90 0 + ATOM 637 C . THR A 90 ? -21.20900 -8.68500 15.50200 1.000 95.39000 C ? A ? 90 0 + ATOM 638 O . THR A 90 ? -21.06700 -9.09500 14.35100 1.000 95.39000 O ? A ? 90 0 + ATOM 639 CB . THR A 90 ? -23.50200 -9.52500 16.11400 1.000 95.39000 C ? A ? 90 0 + ATOM 640 OG1 . THR A 90 ? -24.81600 -9.12300 16.44700 1.000 95.39000 O ? A ? 90 0 + ATOM 641 CG2 . THR A 90 ? -23.02800 -10.47800 17.20700 1.000 95.39000 C ? A ? 90 0 + ATOM 642 N . PHE A 91 ? -20.19500 -8.54500 16.35300 1.000 95.89000 N ? A ? 91 0 + ATOM 643 CA . PHE A 91 ? -18.79400 -8.77000 16.00200 1.000 95.89000 C ? A ? 91 0 + ATOM 644 C . PHE A 91 ? -18.31700 -10.14100 16.47500 1.000 95.89000 C ? A ? 91 0 + ATOM 645 O . PHE A 91 ? -18.61400 -10.54800 17.59600 1.000 95.89000 O ? A ? 91 0 + ATOM 646 CB . PHE A 91 ? -17.91900 -7.65400 16.58200 1.000 95.89000 C ? A ? 91 0 + ATOM 647 CG . PHE A 91 ? -18.17300 -6.30000 15.95300 1.000 95.89000 C ? A ? 91 0 + ATOM 648 CD1 . PHE A 91 ? -17.32500 -5.81300 14.94000 1.000 95.89000 C ? A ? 91 0 + ATOM 649 CD2 . PHE A 91 ? -19.28700 -5.54200 16.35500 1.000 95.89000 C ? A ? 91 0 + ATOM 650 CE1 . PHE A 91 ? -17.59900 -4.57900 14.32400 1.000 95.89000 C ? A ? 91 0 + ATOM 651 CE2 . PHE A 91 ? -19.58000 -4.33100 15.71200 1.000 95.89000 C ? A ? 91 0 + ATOM 652 CZ . PHE A 91 ? -18.74000 -3.84900 14.69500 1.000 95.89000 C ? A ? 91 0 + ATOM 653 N . TYR A 92 ? -17.53800 -10.81800 15.63600 1.000 95.78000 N ? A ? 92 0 + ATOM 654 CA . TYR A 92 ? -16.92800 -12.11700 15.90800 1.000 95.78000 C ? A ? 92 0 + ATOM 655 C . TYR A 92 ? -15.43500 -12.05800 15.60300 1.000 95.78000 C ? A ? 92 0 + ATOM 656 O . TYR A 92 ? -15.05700 -11.70000 14.49000 1.000 95.78000 O ? A ? 92 0 + ATOM 657 CB . TYR A 92 ? -17.59300 -13.18400 15.03100 1.000 95.78000 C ? A ? 92 0 + ATOM 658 CG . TYR A 92 ? -19.08200 -13.33600 15.25200 1.000 95.78000 C ? A ? 92 0 + ATOM 659 CD1 . TYR A 92 ? -19.55900 -14.12700 16.31400 1.000 95.78000 C ? A ? 92 0 + ATOM 660 CD2 . TYR A 92 ? -19.98500 -12.66400 14.40600 1.000 95.78000 C ? A ? 92 0 + ATOM 661 CE1 . TYR A 92 ? -20.94500 -14.25600 16.52500 1.000 95.78000 C ? A ? 92 0 + ATOM 662 CE2 . TYR A 92 ? -21.37000 -12.79100 14.61400 1.000 95.78000 C ? A ? 92 0 + ATOM 663 CZ . TYR A 92 ? -21.85100 -13.58800 15.67200 1.000 95.78000 C ? A ? 92 0 + ATOM 664 OH . TYR A 92 ? -23.18800 -13.70000 15.88100 1.000 95.78000 O ? A ? 92 0 + ATOM 665 N . VAL A 93 ? -14.58700 -12.44100 16.56000 1.000 96.54000 N ? A ? 93 0 + ATOM 666 CA . VAL A 93 ? -13.13000 -12.51500 16.37100 1.000 96.54000 C ? A ? 93 0 + ATOM 667 C . VAL A 93 ? -12.71300 -13.97700 16.27300 1.000 96.54000 C ? A ? 93 0 + ATOM 668 O . VAL A 93 ? -13.05000 -14.78200 17.13600 1.000 96.54000 O ? A ? 93 0 + ATOM 669 CB . VAL A 93 ? -12.36200 -11.78700 17.49100 1.000 96.54000 C ? A ? 93 0 + ATOM 670 CG1 . VAL A 93 ? -10.85700 -11.74100 17.18800 1.000 96.54000 C ? A ? 93 0 + ATOM 671 CG2 . VAL A 93 ? -12.84600 -10.33900 17.65600 1.000 96.54000 C ? A ? 93 0 + ATOM 672 N . THR A 94 ? -11.96800 -14.32500 15.22900 1.000 96.39000 N ? A ? 94 0 + ATOM 673 CA . THR A 94 ? -11.46100 -15.68200 14.99100 1.000 96.39000 C ? A ? 94 0 + ATOM 674 C . THR A 94 ? -9.94300 -15.64500 14.87400 1.000 96.39000 C ? A ? 94 0 + ATOM 675 O . THR A 94 ? -9.40300 -14.87600 14.08400 1.000 96.39000 O ? A ? 94 0 + ATOM 676 CB . THR A 94 ? -12.08900 -16.28100 13.72400 1.000 96.39000 C ? A ? 94 0 + ATOM 677 OG1 . THR A 94 ? -13.49400 -16.24400 13.82800 1.000 96.39000 O ? A ? 94 0 + ATOM 678 CG2 . THR A 94 ? -11.68800 -17.74000 13.52400 1.000 96.39000 C ? A ? 94 0 + ATOM 679 N . ALA A 95 ? -9.24000 -16.47900 15.64100 1.000 96.34000 N ? A ? 95 0 + ATOM 680 CA . ALA A 95 ? -7.79900 -16.68300 15.49600 1.000 96.34000 C ? A ? 95 0 + ATOM 681 C . ALA A 95 ? -7.48500 -17.70600 14.39400 1.000 96.34000 C ? A ? 95 0 + ATOM 682 O . ALA A 95 ? -8.13700 -18.75300 14.32000 1.000 96.34000 O ? A ? 95 0 + ATOM 683 CB . ALA A 95 ? -7.20700 -17.11800 16.83900 1.000 96.34000 C ? A ? 95 0 + ATOM 684 N . LEU A 96 ? -6.45100 -17.43200 13.59400 1.000 95.02000 N ? A ? 96 0 + ATOM 685 CA . LEU A 96 ? -5.97400 -18.26200 12.48800 1.000 95.02000 C ? A ? 96 0 + ATOM 686 C . LEU A 96 ? -4.48500 -18.59800 12.64400 1.000 95.02000 C ? A ? 96 0 + ATOM 687 O . LEU A 96 ? -3.69700 -17.82000 13.18500 1.000 95.02000 O ? A ? 96 0 + ATOM 688 CB . LEU A 96 ? -6.20900 -17.56600 11.13200 1.000 95.02000 C ? A ? 96 0 + ATOM 689 CG . LEU A 96 ? -7.67300 -17.18900 10.83400 1.000 95.02000 C ? A ? 96 0 + ATOM 690 CD1 . LEU A 96 ? -7.94200 -15.71800 11.14700 1.000 95.02000 C ? A ? 96 0 + ATOM 691 CD2 . LEU A 96 ? -8.00500 -17.41200 9.35900 1.000 95.02000 C ? A ? 96 0 + ATOM 692 N . ASN A 97 ? -4.08700 -19.76200 12.13600 1.000 91.28000 N ? A ? 97 0 + ATOM 693 CA . ASN A 97 ? -2.69200 -20.10300 11.86300 1.000 91.28000 C ? A ? 97 0 + ATOM 694 C . ASN A 97 ? -2.55000 -20.66200 10.43900 1.000 91.28000 C ? A ? 97 0 + ATOM 695 O . ASN A 97 ? -3.50200 -20.64200 9.66700 1.000 91.28000 O ? A ? 97 0 + ATOM 696 CB . ASN A 97 ? -2.16100 -21.02400 12.97600 1.000 91.28000 C ? A ? 97 0 + ATOM 697 CG . ASN A 97 ? -2.73200 -22.43200 13.00600 1.000 91.28000 C ? A ? 97 0 + ATOM 698 OD1 . ASN A 97 ? -3.19600 -22.98500 12.02800 1.000 91.28000 O ? A ? 97 0 + ATOM 699 ND2 . ASN A 97 ? -2.61700 -23.08200 14.13600 1.000 91.28000 N ? A ? 97 0 + ATOM 700 N . SER A 98 ? -1.37000 -21.16900 10.07900 1.000 87.92000 N ? A ? 98 0 + ATOM 701 CA . SER A 98 ? -1.09200 -21.67900 8.72800 1.000 87.92000 C ? A ? 98 0 + ATOM 702 C . SER A 98 ? -1.96800 -22.85800 8.28300 1.000 87.92000 C ? A ? 98 0 + ATOM 703 O . SER A 98 ? -1.95400 -23.19000 7.10300 1.000 87.92000 O ? A ? 98 0 + ATOM 704 CB . SER A 98 ? 0.37000 -22.12800 8.63800 1.000 87.92000 C ? A ? 98 0 + ATOM 705 OG . SER A 98 ? 1.24200 -21.12500 9.12700 1.000 87.92000 O ? A ? 98 0 + ATOM 706 N . PHE A 99 ? -2.68200 -23.51600 9.20200 1.000 85.05000 N ? A ? 99 0 + ATOM 707 CA . PHE A 99 ? -3.40100 -24.76500 8.93600 1.000 85.05000 C ? A ? 99 0 + ATOM 708 C . PHE A 99 ? -4.88400 -24.71500 9.31900 1.000 85.05000 C ? A ? 99 0 + ATOM 709 O . PHE A 99 ? -5.70900 -25.32700 8.64800 1.000 85.05000 O ? A ? 99 0 + ATOM 710 CB . PHE A 99 ? -2.70200 -25.90000 9.69900 1.000 85.05000 C ? A ? 99 0 + ATOM 711 CG . PHE A 99 ? -1.24300 -26.10100 9.33200 1.000 85.05000 C ? A ? 99 0 + ATOM 712 CD1 . PHE A 99 ? -0.90800 -26.72000 8.11400 1.000 85.05000 C ? A ? 99 0 + ATOM 713 CD2 . PHE A 99 ? -0.22100 -25.66600 10.19900 1.000 85.05000 C ? A ? 99 0 + ATOM 714 CE1 . PHE A 99 ? 0.44000 -26.91700 7.76900 1.000 85.05000 C ? A ? 99 0 + ATOM 715 CE2 . PHE A 99 ? 1.12900 -25.86300 9.85300 1.000 85.05000 C ? A ? 99 0 + ATOM 716 CZ . PHE A 99 ? 1.45800 -26.49300 8.64000 1.000 85.05000 C ? A ? 99 0 + ATOM 717 N . CYS A 100 ? -5.22700 -24.01600 10.40200 1.000 89.65000 N ? A ? 100 0 + ATOM 718 CA . CYS A 100 ? -6.52200 -24.11000 11.06400 1.000 89.65000 C ? A ? 100 0 + ATOM 719 C . CYS A 100 ? -7.00600 -22.74700 11.57800 1.000 89.65000 C ? A ? 100 0 + ATOM 720 O . CYS A 100 ? -6.21600 -21.86100 11.91600 1.000 89.65000 O ? A ? 100 0 + ATOM 721 CB . CYS A 100 ? -6.39900 -25.08500 12.24600 1.000 89.65000 C ? A ? 100 0 + ATOM 722 SG . CYS A 100 ? -6.10100 -26.79000 11.69500 1.000 89.65000 S ? A ? 100 0 + ATOM 723 N . GLN A 101 ? -8.32500 -22.64300 11.73800 1.000 93.66000 N ? A ? 101 0 + ATOM 724 CA . GLN A 101 ? -9.00200 -21.55400 12.43900 1.000 93.66000 C ? A ? 101 0 + ATOM 725 C . GLN A 101 ? -9.57700 -22.04500 13.77200 1.000 93.66000 C ? A ? 101 0 + ATOM 726 O . GLN A 101 ? -9.94100 -23.21400 13.91600 1.000 93.66000 O ? A ? 101 0 + ATOM 727 CB . GLN A 101 ? -10.06200 -20.91300 11.53100 1.000 93.66000 C ? A ? 101 0 + ATOM 728 CG . GLN A 101 ? -11.21700 -21.86000 11.15400 1.000 93.66000 C ? A ? 101 0 + ATOM 729 CD . GLN A 101 ? -12.17000 -21.25300 10.12700 1.000 93.66000 C ? A ? 101 0 + ATOM 730 OE1 . GLN A 101 ? -12.08400 -20.10200 9.74100 1.000 93.66000 O ? A ? 101 0 + ATOM 731 NE2 . GLN A 101 ? -13.11200 -22.01600 9.62100 1.000 93.66000 N ? A ? 101 0 + ATOM 732 N . SER A 102 ? -9.63200 -21.15100 14.75100 1.000 93.76000 N ? A ? 102 0 + ATOM 733 CA . SER A 102 ? -10.34300 -21.36800 16.01500 1.000 93.76000 C ? A ? 102 0 + ATOM 734 C . SER A 102 ? -11.86200 -21.24200 15.82900 1.000 93.76000 C ? A ? 102 0 + ATOM 735 O . SER A 102 ? -12.33700 -20.80000 14.78300 1.000 93.76000 O ? A ? 102 0 + ATOM 736 CB . SER A 102 ? -9.82600 -20.39300 17.07900 1.000 93.76000 C ? A ? 102 0 + ATOM 737 OG . SER A 102 ? -9.99700 -19.06400 16.64300 1.000 93.76000 O ? A ? 102 0 + ATOM 738 N . SER A 103 ? -12.63700 -21.62000 16.84900 1.000 94.15000 N ? A ? 103 0 + ATOM 739 CA . SER A 103 ? -14.03200 -21.16200 16.92900 1.000 94.15000 C ? A ? 103 0 + ATOM 740 C . SER A 103 ? -14.06000 -19.65100 17.20100 1.000 94.15000 C ? A ? 103 0 + ATOM 741 O . SER A 103 ? -13.13600 -19.15900 17.85700 1.000 94.15000 O ? A ? 103 0 + ATOM 742 CB . SER A 103 ? -14.80700 -21.88200 18.03500 1.000 94.15000 C ? A ? 103 0 + ATOM 743 OG . SER A 103 ? -14.86100 -23.27500 17.78300 1.000 94.15000 O ? A ? 103 0 + ATOM 744 N . PRO A 104 ? -15.09800 -18.91900 16.75500 1.000 92.86000 N ? A ? 104 0 + ATOM 745 CA . PRO A 104 ? -15.25500 -17.51200 17.09700 1.000 92.86000 C ? A ? 104 0 + ATOM 746 C . PRO A 104 ? -15.25400 -17.28500 18.61200 1.000 92.86000 C ? A ? 104 0 + ATOM 747 O . PRO A 104 ? -15.79800 -18.09300 19.36800 1.000 92.86000 O ? A ? 104 0 + ATOM 748 CB . PRO A 104 ? -16.57900 -17.07200 16.47000 1.000 92.86000 C ? A ? 104 0 + ATOM 749 CG . PRO A 104 ? -16.76100 -18.04800 15.31000 1.000 92.86000 C ? A ? 104 0 + ATOM 750 CD . PRO A 104 ? -16.16500 -19.34200 15.86100 1.000 92.86000 C ? A ? 104 0 + ATOM 751 N . GLY A 105 ? -14.63900 -16.18300 19.03000 1.000 91.17000 N ? A ? 105 0 + ATOM 752 CA . GLY A 105 ? -14.63100 -15.70800 20.40700 1.000 91.17000 C ? A ? 105 0 + ATOM 753 C . GLY A 105 ? -15.98700 -15.19800 20.89100 1.000 91.17000 C ? A ? 105 0 + ATOM 754 O . GLY A 105 ? -17.03100 -15.42700 20.27000 1.000 91.17000 O ? A ? 105 0 + ATOM 755 N . THR A 106 ? -15.98000 -14.49700 22.02300 1.000 92.18000 N ? A ? 106 0 + ATOM 756 CA . THR A 106 ? -17.22700 -13.96200 22.58700 1.000 92.18000 C ? A ? 106 0 + ATOM 757 C . THR A 106 ? -17.70400 -12.79300 21.73200 1.000 92.18000 C ? A ? 106 0 + ATOM 758 O . THR A 106 ? -16.96900 -11.83300 21.51200 1.000 92.18000 O ? A ? 106 0 + ATOM 759 CB . THR A 106 ? -17.08300 -13.54100 24.05300 1.000 92.18000 C ? A ? 106 0 + ATOM 760 OG1 . THR A 106 ? -16.57300 -14.62500 24.79900 1.000 92.18000 O ? A ? 106 0 + ATOM 761 CG2 . THR A 106 ? -18.43200 -13.17300 24.67600 1.000 92.18000 C ? A ? 106 0 + ATOM 762 N . SER A 107 ? -18.94200 -12.86100 21.24100 1.000 94.01000 N ? A ? 107 0 + ATOM 763 CA . SER A 107 ? -19.50300 -11.78400 20.42800 1.000 94.01000 C ? A ? 107 0 + ATOM 764 C . SER A 107 ? -19.92400 -10.58800 21.27300 1.000 94.01000 C ? A ? 107 0 + ATOM 765 O . SER A 107 ? -20.49200 -10.76100 22.35200 1.000 94.01000 O ? A ? 107 0 + ATOM 766 CB . SER A 107 ? -20.68900 -12.27400 19.59800 1.000 94.01000 C ? A ? 107 0 + ATOM 767 OG . SER A 107 ? -21.74500 -12.68900 20.44900 1.000 94.01000 O ? A ? 107 0 + ATOM 768 N . PHE A 108 ? -19.77300 -9.38500 20.73000 1.000 93.78000 N ? A ? 108 0 + ATOM 769 CA . PHE A 108 ? -20.32300 -8.15100 21.29100 1.000 93.78000 C ? A ? 108 0 + ATOM 770 C . PHE A 108 ? -21.08100 -7.37300 20.21000 1.000 93.78000 C ? A ? 108 0 + ATOM 771 O . PHE A 108 ? -20.91900 -7.63100 19.01400 1.000 93.78000 O ? A ? 108 0 + ATOM 772 CB . PHE A 108 ? -19.20100 -7.33200 21.94500 1.000 93.78000 C ? A ? 108 0 + ATOM 773 CG . PHE A 108 ? -18.14100 -6.86500 20.97100 1.000 93.78000 C ? A ? 108 0 + ATOM 774 CD1 . PHE A 108 ? -17.04200 -7.69300 20.67100 1.000 93.78000 C ? A ? 108 0 + ATOM 775 CD2 . PHE A 108 ? -18.28200 -5.62100 20.32800 1.000 93.78000 C ? A ? 108 0 + ATOM 776 CE1 . PHE A 108 ? -16.09600 -7.28100 19.71800 1.000 93.78000 C ? A ? 108 0 + ATOM 777 CE2 . PHE A 108 ? -17.33800 -5.21600 19.37200 1.000 93.78000 C ? A ? 108 0 + ATOM 778 CZ . PHE A 108 ? -16.24700 -6.04500 19.07100 1.000 93.78000 C ? A ? 108 0 + ATOM 779 N . GLN A 109 ? -21.93700 -6.43800 20.62500 1.000 94.22000 N ? A ? 109 0 + ATOM 780 CA . GLN A 109 ? -22.76500 -5.65000 19.71400 1.000 94.22000 C ? A ? 109 0 + ATOM 781 C . GLN A 109 ? -22.44700 -4.16300 19.80600 1.000 94.22000 C ? A ? 109 0 + ATOM 782 O . GLN A 109 ? -22.25700 -3.63200 20.89800 1.000 94.22000 O ? A ? 109 0 + ATOM 783 CB . GLN A 109 ? -24.26000 -5.91200 19.95100 1.000 94.22000 C ? A ? 109 0 + ATOM 784 CG . GLN A 109 ? -24.64000 -7.33200 19.51600 1.000 94.22000 C ? A ? 109 0 + ATOM 785 CD . GLN A 109 ? -26.13200 -7.62400 19.60800 1.000 94.22000 C ? A ? 109 0 + ATOM 786 OE1 . GLN A 109 ? -26.91600 -6.95300 20.26100 1.000 94.22000 O ? A ? 109 0 + ATOM 787 NE2 . GLN A 109 ? -26.58700 -8.65900 18.94000 1.000 94.22000 N ? A ? 109 0 + ATOM 788 N . ILE A 110 ? -22.43800 -3.49200 18.65400 1.000 91.74000 N ? A ? 110 0 + ATOM 789 CA . ILE A 110 ? -22.36100 -2.03200 18.55800 1.000 91.74000 C ? A ? 110 0 + ATOM 790 C . ILE A 110 ? -23.48900 -1.55600 17.65300 1.000 91.74000 C ? A ? 110 0 + ATOM 791 O . ILE A 110 ? -23.72000 -2.10200 16.57300 1.000 91.74000 O ? A ? 110 0 + ATOM 792 CB . ILE A 110 ? -20.97200 -1.55500 18.07900 1.000 91.74000 C ? A ? 110 0 + ATOM 793 CG1 . ILE A 110 ? -19.90900 -1.93500 19.13400 1.000 91.74000 C ? A ? 110 0 + ATOM 794 CG2 . ILE A 110 ? -20.95300 -0.04000 17.79300 1.000 91.74000 C ? A ? 110 0 + ATOM 795 CD1 . ILE A 110 ? -18.48200 -1.57400 18.73000 1.000 91.74000 C ? A ? 110 0 + ATOM 796 N . GLN A 111 ? -24.19300 -0.52500 18.10700 1.000 88.89000 N ? A ? 111 0 + ATOM 797 CA . GLN A 111 ? -25.19400 0.17200 17.31600 1.000 88.89000 C ? A ? 111 0 + ATOM 798 C . GLN A 111 ? -24.57700 1.44300 16.73400 1.000 88.89000 C ? A ? 111 0 + ATOM 799 O . GLN A 111 ? -24.06200 2.28100 17.47400 1.000 88.89000 O ? A ? 111 0 + ATOM 800 CB . GLN A 111 ? -26.41900 0.43900 18.19400 1.000 88.89000 C ? A ? 111 0 + ATOM 801 CG . GLN A 111 ? -27.55200 1.09800 17.39900 1.000 88.89000 C ? A ? 111 0 + ATOM 802 CD . GLN A 111 ? -28.81900 1.27600 18.22700 1.000 88.89000 C ? A ? 111 0 + ATOM 803 OE1 . GLN A 111 ? -29.03400 0.66000 19.25800 1.000 88.89000 O ? A ? 111 0 + ATOM 804 NE2 . GLN A 111 ? -29.72500 2.12000 17.79200 1.000 88.89000 N ? A ? 111 0 + ATOM 805 N . THR A 112 ? -24.63400 1.59000 15.41400 1.000 85.75000 N ? A ? 112 0 + ATOM 806 CA . THR A 112 ? -24.19700 2.81400 14.74300 1.000 85.75000 C ? A ? 112 0 + ATOM 807 C . THR A 112 ? -25.26800 3.89500 14.88400 1.000 85.75000 C ? A ? 112 0 + ATOM 808 O . THR A 112 ? -26.47100 3.61800 14.92700 1.000 85.75000 O ? A ? 112 0 + ATOM 809 CB . THR A 112 ? -23.82700 2.57300 13.27100 1.000 85.75000 C ? A ? 112 0 + ATOM 810 OG1 . THR A 112 ? -24.92500 2.08900 12.54600 1.000 85.75000 O ? A ? 112 0 + ATOM 811 CG2 . THR A 112 ? -22.70100 1.55200 13.11500 1.000 85.75000 C ? A ? 112 0 + ATOM 812 N . ALA A 113 ? -24.84200 5.15600 14.96500 1.000 79.65000 N ? A ? 113 0 + ATOM 813 CA . ALA A 113 ? -25.77700 6.27500 14.99500 1.000 79.65000 C ? A ? 113 0 + ATOM 814 C . ALA A 113 ? -26.59700 6.32800 13.68700 1.000 79.65000 C ? A ? 113 0 + ATOM 815 O . ALA A 113 ? -26.05500 6.02100 12.61900 1.000 79.65000 O ? A ? 113 0 + ATOM 816 CB . ALA A 113 ? -25.00600 7.57600 15.24400 1.000 79.65000 C ? A ? 113 0 + ATOM 817 N . PRO A 114 ? -27.88600 6.71000 13.73300 1.000 79.10000 N ? A ? 114 0 + ATOM 818 CA . PRO A 114 ? -28.65000 6.98400 12.52300 1.000 79.10000 C ? A ? 114 0 + ATOM 819 C . PRO A 114 ? -28.04700 8.18400 11.78000 1.000 79.10000 C ? A ? 114 0 + ATOM 820 O . PRO A 114 ? -27.64400 9.17000 12.39600 1.000 79.10000 O ? A ? 114 0 + ATOM 821 CB . PRO A 114 ? -30.08500 7.23900 12.99200 1.000 79.10000 C ? A ? 114 0 + ATOM 822 CG . PRO A 114 ? -29.90500 7.76600 14.41600 1.000 79.10000 C ? A ? 114 0 + ATOM 823 CD . PRO A 114 ? -28.66700 7.02500 14.91900 1.000 79.10000 C ? A ? 114 0 + ATOM 824 N . CYS A 115 ? -28.00000 8.09400 10.45400 1.000 77.65000 N ? A ? 115 0 + ATOM 825 CA . CYS A 115 ? -27.64100 9.20800 9.58400 1.000 77.65000 C ? A ? 115 0 + ATOM 826 C . CYS A 115 ? -28.89300 10.06000 9.34700 1.000 77.65000 C ? A ? 115 0 + ATOM 827 O . CYS A 115 ? -29.93400 9.51600 8.97900 1.000 77.65000 O ? A ? 115 0 + ATOM 828 CB . CYS A 115 ? -27.11300 8.66600 8.25200 1.000 77.65000 C ? A ? 115 0 + ATOM 829 SG . CYS A 115 ? -25.36900 8.17500 8.13000 1.000 77.65000 S ? A ? 115 0 + ATOM 830 N . SER A 116 ? -28.79800 11.37700 9.53700 1.000 74.95000 N ? A ? 116 0 + ATOM 831 CA . SER A 116 ? -29.92900 12.28900 9.29000 1.000 74.95000 C ? A ? 116 0 + ATOM 832 C . SER A 116 ? -29.87400 12.95900 7.91500 1.000 74.95000 C ? A ? 116 0 + ATOM 833 O . SER A 116 ? -30.90200 13.40900 7.41500 1.000 74.95000 O ? A ? 116 0 + ATOM 834 CB . SER A 116 ? -30.02200 13.37200 10.36500 1.000 74.95000 C ? A ? 116 0 + ATOM 835 OG . SER A 116 ? -30.02700 12.81900 11.66700 1.000 74.95000 O ? A ? 116 0 + ATOM 836 N . LEU A 117 ? -28.69000 13.05500 7.29800 1.000 78.26000 N ? A ? 117 0 + ATOM 837 CA . LEU A 117 ? -28.54100 13.59700 5.94500 1.000 78.26000 C ? A ? 117 0 + ATOM 838 C . LEU A 117 ? -28.59000 12.47600 4.90300 1.000 78.26000 C ? A ? 117 0 + ATOM 839 O . LEU A 117 ? -28.28200 11.31800 5.18800 1.000 78.26000 O ? A ? 117 0 + ATOM 840 CB . LEU A 117 ? -27.26200 14.44500 5.82200 1.000 78.26000 C ? A ? 117 0 + ATOM 841 CG . LEU A 117 ? -27.16200 15.63500 6.79200 1.000 78.26000 C ? A ? 117 0 + ATOM 842 CD1 . LEU A 117 ? -25.82000 16.34000 6.61500 1.000 78.26000 C ? A ? 117 0 + ATOM 843 CD2 . LEU A 117 ? -28.26800 16.66400 6.55200 1.000 78.26000 C ? A ? 117 0 + ATOM 844 N . THR A 118 ? -28.96400 12.83700 3.67800 1.000 78.01000 N ? A ? 118 0 + ATOM 845 CA . THR A 118 ? -28.93000 11.93900 2.52000 1.000 78.01000 C ? A ? 118 0 + ATOM 846 C . THR A 118 ? -27.49300 11.64700 2.08800 1.000 78.01000 C ? A ? 118 0 + ATOM 847 O . THR A 118 ? -26.54500 12.30400 2.52400 1.000 78.01000 O ? A ? 118 0 + ATOM 848 CB . THR A 118 ? -29.71800 12.54700 1.34900 1.000 78.01000 C ? A ? 118 0 + ATOM 849 OG1 . THR A 118 ? -29.25600 13.85400 1.09900 1.000 78.01000 O ? A ? 118 0 + ATOM 850 CG2 . THR A 118 ? -31.21300 12.62400 1.65300 1.000 78.01000 C ? A ? 118 0 + ATOM 851 N . SER A 119 ? -27.32700 10.66900 1.19700 1.000 81.36000 N ? A ? 119 0 + ATOM 852 CA . SER A 119 ? -26.04100 10.37200 0.56800 1.000 81.36000 C ? A ? 119 0 + ATOM 853 C . SER A 119 ? -25.43100 11.61300 -0.08800 1.000 81.36000 C ? A ? 119 0 + ATOM 854 O . SER A 119 ? -26.13200 12.43100 -0.68900 1.000 81.36000 O ? A ? 119 0 + ATOM 855 CB . SER A 119 ? -26.20300 9.26800 -0.47800 1.000 81.36000 C ? A ? 119 0 + ATOM 856 OG . SER A 119 ? -26.76800 8.12100 0.12900 1.000 81.36000 O ? A ? 119 0 + ATOM 857 N . ILE A 120 ? -24.11200 11.72400 0.03100 1.000 90.53000 N ? A ? 120 0 + ATOM 858 CA . ILE A 120 ? -23.30400 12.75600 -0.61500 1.000 90.53000 C ? A ? 120 0 + ATOM 859 C . ILE A 120 ? -22.66500 12.19400 -1.87900 1.000 90.53000 C ? A ? 120 0 + ATOM 860 O . ILE A 120 ? -22.56500 10.97900 -2.05500 1.000 90.53000 O ? A ? 120 0 + ATOM 861 CB . ILE A 120 ? -22.25900 13.34000 0.36300 1.000 90.53000 C ? A ? 120 0 + ATOM 862 CG1 . ILE A 120 ? -21.21300 12.29200 0.80700 1.000 90.53000 C ? A ? 120 0 + ATOM 863 CG2 . ILE A 120 ? -23.00400 13.93500 1.56500 1.000 90.53000 C ? A ? 120 0 + ATOM 864 CD1 . ILE A 120 ? -20.11600 12.86000 1.71400 1.000 90.53000 C ? A ? 120 0 + ATOM 865 N . THR A 121 ? -22.20400 13.08400 -2.74600 1.000 92.93000 N ? A ? 121 0 + ATOM 866 CA . THR A 121 ? -21.29800 12.72600 -3.83500 1.000 92.93000 C ? A ? 121 0 + ATOM 867 C . THR A 121 ? -20.03600 13.54900 -3.70700 1.000 92.93000 C ? A ? 121 0 + ATOM 868 O . THR A 121 ? -20.07000 14.68900 -3.24100 1.000 92.93000 O ? A ? 121 0 + ATOM 869 CB . THR A 121 ? -21.92700 12.89700 -5.22200 1.000 92.93000 C ? A ? 121 0 + ATOM 870 OG1 . THR A 121 ? -22.18700 14.24300 -5.50800 1.000 92.93000 O ? A ? 121 0 + ATOM 871 CG2 . THR A 121 ? -23.23900 12.13300 -5.38300 1.000 92.93000 C ? A ? 121 0 + ATOM 872 N . ALA A 122 ? -18.91100 12.97600 -4.10100 1.000 93.07000 N ? A ? 122 0 + ATOM 873 CA . ALA A 122 ? -17.66300 13.70100 -4.11400 1.000 93.07000 C ? A ? 122 0 + ATOM 874 C . ALA A 122 ? -16.83400 13.27000 -5.32200 1.000 93.07000 C ? A ? 122 0 + ATOM 875 O . ALA A 122 ? -16.83900 12.10000 -5.71000 1.000 93.07000 O ? A ? 122 0 + ATOM 876 CB . ALA A 122 ? -16.99900 13.52700 -2.74500 1.000 93.07000 C ? A ? 122 0 + ATOM 877 N . HIS A 123 ? -16.14200 14.23000 -5.92400 1.000 91.61000 N ? A ? 123 0 + ATOM 878 CA . HIS A 123 ? -15.30400 14.00200 -7.09300 1.000 91.61000 C ? A ? 123 0 + ATOM 879 C . HIS A 123 ? -14.01700 14.82100 -7.01000 1.000 91.61000 C ? A ? 123 0 + ATOM 880 O . HIS A 123 ? -13.96100 15.87600 -6.37200 1.000 91.61000 O ? A ? 123 0 + ATOM 881 CB . HIS A 123 ? -16.10100 14.28300 -8.37900 1.000 91.61000 C ? A ? 123 0 + ATOM 882 CG . HIS A 123 ? -16.56400 15.71000 -8.56900 1.000 91.61000 C ? A ? 123 0 + ATOM 883 ND1 . HIS A 123 ? -15.88400 16.85300 -8.22500 1.000 91.61000 N ? A ? 123 0 + ATOM 884 CD2 . HIS A 123 ? -17.70100 16.11500 -9.21500 1.000 91.61000 C ? A ? 123 0 + ATOM 885 CE1 . HIS A 123 ? -16.58000 17.91200 -8.66500 1.000 91.61000 C ? A ? 123 0 + ATOM 886 NE2 . HIS A 123 ? -17.71400 17.51200 -9.25400 1.000 91.61000 N ? A ? 123 0 + ATOM 887 N . THR A 124 ? -12.98400 14.35200 -7.69400 1.000 89.02000 N ? A ? 124 0 + ATOM 888 CA . THR A 124 ? -11.71000 15.05300 -7.82200 1.000 89.02000 C ? A ? 124 0 + ATOM 889 C . THR A 124 ? -11.15500 14.81000 -9.21600 1.000 89.02000 C ? A ? 124 0 + ATOM 890 O . THR A 124 ? -11.27300 13.70400 -9.74800 1.000 89.02000 O ? A ? 124 0 + ATOM 891 CB . THR A 124 ? -10.74000 14.61100 -6.71500 1.000 89.02000 C ? A ? 124 0 + ATOM 892 OG1 . THR A 124 ? -9.57500 15.39300 -6.73800 1.000 89.02000 O ? A ? 124 0 + ATOM 893 CG2 . THR A 124 ? -10.31000 13.14300 -6.78200 1.000 89.02000 C ? A ? 124 0 + ATOM 894 N . ASP A 125 ? -10.57000 15.84000 -9.81800 1.000 86.56000 N ? A ? 125 0 + ATOM 895 CA . ASP A 125 ? -9.78800 15.65700 -11.03400 1.000 86.56000 C ? A ? 125 0 + ATOM 896 C . ASP A 125 ? -8.45100 15.00800 -10.66900 1.000 86.56000 C ? A ? 125 0 + ATOM 897 O . ASP A 125 ? -7.85800 15.31900 -9.63800 1.000 86.56000 O ? A ? 125 0 + ATOM 898 CB . ASP A 125 ? -9.56400 16.98500 -11.76300 1.000 86.56000 C ? A ? 125 0 + ATOM 899 CG . ASP A 125 ? -10.86500 17.64200 -12.21600 1.000 86.56000 C ? A ? 125 0 + ATOM 900 OD1 . ASP A 125 ? -11.70900 16.91300 -12.78000 1.000 86.56000 O ? A ? 125 0 + ATOM 901 OD2 . ASP A 125 ? -10.97300 18.87100 -12.01300 1.000 86.56000 O ? A ? 125 0 + ATOM 902 N . CYS A 126 ? -7.92700 14.13900 -11.53100 1.000 84.95000 N ? A ? 126 0 + ATOM 903 CA . CYS A 126 ? -6.76800 13.29700 -11.21000 1.000 84.95000 C ? A ? 126 0 + ATOM 904 C . CYS A 126 ? -5.49500 14.06300 -10.79500 1.000 84.95000 C ? A ? 126 0 + ATOM 905 O . CYS A 126 ? -4.61700 13.49200 -10.15200 1.000 84.95000 O ? A ? 126 0 + ATOM 906 CB . CYS A 126 ? -6.47100 12.42300 -12.43000 1.000 84.95000 C ? A ? 126 0 + ATOM 907 SG . CYS A 126 ? -7.89300 11.48200 -13.04700 1.000 84.95000 S ? A ? 126 0 + ATOM 908 N . TYR A 127 ? -5.38500 15.34200 -11.15900 1.000 80.35000 N ? A ? 127 0 + ATOM 909 CA . TYR A 127 ? -4.24900 16.21300 -10.83200 1.000 80.35000 C ? A ? 127 0 + ATOM 910 C . TYR A 127 ? -4.62500 17.36900 -9.90300 1.000 80.35000 C ? A ? 127 0 + ATOM 911 O . TYR A 127 ? -3.80800 18.25600 -9.65900 1.000 80.35000 O ? A ? 127 0 + ATOM 912 CB . TYR A 127 ? -3.62500 16.73200 -12.13100 1.000 80.35000 C ? A ? 127 0 + ATOM 913 CG . TYR A 127 ? -3.32600 15.63700 -13.13100 1.000 80.35000 C ? A ? 127 0 + ATOM 914 CD1 . TYR A 127 ? -2.35200 14.66800 -12.83000 1.000 80.35000 C ? A ? 127 0 + ATOM 915 CD2 . TYR A 127 ? -4.06600 15.55200 -14.32700 1.000 80.35000 C ? A ? 127 0 + ATOM 916 CE1 . TYR A 127 ? -2.12700 13.60700 -13.72500 1.000 80.35000 C ? A ? 127 0 + ATOM 917 CE2 . TYR A 127 ? -3.82200 14.50200 -15.23200 1.000 80.35000 C ? A ? 127 0 + ATOM 918 CZ . TYR A 127 ? -2.85700 13.52400 -14.92600 1.000 80.35000 C ? A ? 127 0 + ATOM 919 OH . TYR A 127 ? -2.66100 12.47300 -15.76000 1.000 80.35000 O ? A ? 127 0 + ATOM 920 N . SER A 128 ? -5.86300 17.38700 -9.41400 1.000 85.29000 N ? A ? 128 0 + ATOM 921 CA . SER A 128 ? -6.34000 18.42200 -8.51400 1.000 85.29000 C ? A ? 128 0 + ATOM 922 C . SER A 128 ? -5.98300 18.07900 -7.07400 1.000 85.29000 C ? A ? 128 0 + ATOM 923 O . SER A 128 ? -6.10800 16.94400 -6.62300 1.000 85.29000 O ? A ? 128 0 + ATOM 924 CB . SER A 128 ? -7.84100 18.61500 -8.69500 1.000 85.29000 C ? A ? 128 0 + ATOM 925 OG . SER A 128 ? -8.28600 19.68200 -7.89100 1.000 85.29000 O ? A ? 128 0 + ATOM 926 N . SER A 129 ? -5.57100 19.09500 -6.32400 1.000 88.70000 N ? A ? 129 0 + ATOM 927 CA . SER A 129 ? -5.46100 19.04100 -4.86400 1.000 88.70000 C ? A ? 129 0 + ATOM 928 C . SER A 129 ? -6.79700 19.34800 -4.17300 1.000 88.70000 C ? A ? 129 0 + ATOM 929 O . SER A 129 ? -6.81900 19.61200 -2.96700 1.000 88.70000 O ? A ? 129 0 + ATOM 930 CB . SER A 129 ? -4.36400 20.00100 -4.40700 1.000 88.70000 C ? A ? 129 0 + ATOM 931 OG . SER A 129 ? -4.63000 21.29400 -4.92000 1.000 88.70000 O ? A ? 129 0 + ATOM 932 N . HIS A 130 ? -7.90000 19.34100 -4.92900 1.000 92.13000 N ? A ? 130 0 + ATOM 933 CA . HIS A 130 ? -9.24100 19.65900 -4.46300 1.000 92.13000 C ? A ? 130 0 + ATOM 934 C . HIS A 130 ? -10.17900 18.46200 -4.62700 1.000 92.13000 C ? A ? 130 0 + ATOM 935 O . HIS A 130 ? -10.19900 17.80900 -5.67400 1.000 92.13000 O ? A ? 130 0 + ATOM 936 CB . HIS A 130 ? -9.79500 20.89700 -5.18400 1.000 92.13000 C ? A ? 130 0 + ATOM 937 CG . HIS A 130 ? -8.91300 22.11400 -5.07500 1.000 92.13000 C ? A ? 130 0 + ATOM 938 ND1 . HIS A 130 ? -9.13600 23.18700 -4.24800 1.000 92.13000 N ? A ? 130 0 + ATOM 939 CD2 . HIS A 130 ? -7.76000 22.37400 -5.76900 1.000 92.13000 C ? A ? 130 0 + ATOM 940 CE1 . HIS A 130 ? -8.14000 24.06900 -4.43100 1.000 92.13000 C ? A ? 130 0 + ATOM 941 NE2 . HIS A 130 ? -7.26800 23.61400 -5.34200 1.000 92.13000 N ? A ? 130 0 + ATOM 942 N . ILE A 131 ? -10.98800 18.20800 -3.60200 1.000 94.16000 N ? A ? 131 0 + ATOM 943 CA . ILE A 131 ? -12.11900 17.28000 -3.66800 1.000 94.16000 C ? A ? 131 0 + ATOM 944 C . ILE A 131 ? -13.38800 18.10300 -3.47600 1.000 94.16000 C ? A ? 131 0 + ATOM 945 O . ILE A 131 ? -13.61600 18.64800 -2.39600 1.000 94.16000 O ? A ? 131 0 + ATOM 946 CB . ILE A 131 ? -12.00100 16.15400 -2.61800 1.000 94.16000 C ? A ? 131 0 + ATOM 947 CG1 . ILE A 131 ? -10.70900 15.32300 -2.78600 1.000 94.16000 C ? A ? 131 0 + ATOM 948 CG2 . ILE A 131 ? -13.23800 15.24300 -2.70500 1.000 94.16000 C ? A ? 131 0 + ATOM 949 CD1 . ILE A 131 ? -10.36300 14.48000 -1.55100 1.000 94.16000 C ? A ? 131 0 + ATOM 950 N . THR A 132 ? -14.21700 18.18000 -4.51000 1.000 94.98000 N ? A ? 132 0 + ATOM 951 CA . THR A 132 ? -15.51900 18.84200 -4.41500 1.000 94.98000 C ? A ? 132 0 + ATOM 952 C . THR A 132 ? -16.52600 17.84400 -3.88100 1.000 94.98000 C ? A ? 132 0 + ATOM 953 O . THR A 132 ? -16.78100 16.80400 -4.49100 1.000 94.98000 O ? A ? 132 0 + ATOM 954 CB . THR A 132 ? -15.99400 19.36400 -5.76200 1.000 94.98000 C ? A ? 132 0 + ATOM 955 OG1 . THR A 132 ? -15.02200 20.18700 -6.35200 1.000 94.98000 O ? A ? 132 0 + ATOM 956 CG2 . THR A 132 ? -17.31000 20.13900 -5.70100 1.000 94.98000 C ? A ? 132 0 + ATOM 957 N . VAL A 133 ? -17.10300 18.17400 -2.73500 1.000 94.54000 N ? A ? 133 0 + ATOM 958 CA . VAL A 133 ? -18.16100 17.41300 -2.08000 1.000 94.54000 C ? A ? 133 0 + ATOM 959 C . VAL A 133 ? -19.47800 18.13000 -2.33300 1.000 94.54000 C ? A ? 133 0 + ATOM 960 O . VAL A 133 ? -19.55000 19.35200 -2.20500 1.000 94.54000 O ? A ? 133 0 + ATOM 961 CB . VAL A 133 ? -17.87900 17.26900 -0.57400 1.000 94.54000 C ? A ? 133 0 + ATOM 962 CG1 . VAL A 133 ? -18.87500 16.30400 0.07700 1.000 94.54000 C ? A ? 133 0 + ATOM 963 CG2 . VAL A 133 ? -16.46200 16.74100 -0.31100 1.000 94.54000 C ? A ? 133 0 + ATOM 964 N . SER A 134 ? -20.52600 17.39000 -2.68000 1.000 93.66000 N ? A ? 134 0 + ATOM 965 CA . SER A 134 ? -21.86700 17.93000 -2.88800 1.000 93.66000 C ? A ? 134 0 + ATOM 966 C . SER A 134 ? -22.94700 17.05700 -2.25500 1.000 93.66000 C ? A ? 134 0 + ATOM 967 O . SER A 134 ? -22.81100 15.83600 -2.13800 1.000 93.66000 O ? A ? 134 0 + ATOM 968 CB . SER A 134 ? -22.13400 18.18400 -4.37200 1.000 93.66000 C ? A ? 134 0 + ATOM 969 OG . SER A 134 ? -22.28300 16.97900 -5.08400 1.000 93.66000 O ? A ? 134 0 + ATOM 970 N . TRP A 135 ? -24.02300 17.69900 -1.81100 1.000 89.24000 N ? A ? 135 0 + ATOM 971 CA . TRP A 135 ? -25.12700 17.07000 -1.08900 1.000 89.24000 C ? A ? 135 0 + ATOM 972 C . TRP A 135 ? -26.46200 17.72400 -1.44400 1.000 89.24000 C ? A ? 135 0 + ATOM 973 O . TRP A 135 ? -26.51200 18.82100 -1.99700 1.000 89.24000 O ? A ? 135 0 + ATOM 974 CB . TRP A 135 ? -24.85500 17.14800 0.41800 1.000 89.24000 C ? A ? 135 0 + ATOM 975 CG . TRP A 135 ? -24.64000 18.51900 0.97700 1.000 89.24000 C ? A ? 135 0 + ATOM 976 CD1 . TRP A 135 ? -25.58300 19.32900 1.51200 1.000 89.24000 C ? A ? 135 0 + ATOM 977 CD2 . TRP A 135 ? -23.37700 19.23800 1.09200 1.000 89.24000 C ? A ? 135 0 + ATOM 978 NE1 . TRP A 135 ? -24.99000 20.49800 1.95200 1.000 89.24000 N ? A ? 135 0 + ATOM 979 CE2 . TRP A 135 ? -23.63200 20.48800 1.72400 1.000 89.24000 C ? A ? 135 0 + ATOM 980 CE3 . TRP A 135 ? -22.04000 18.94900 0.74400 1.000 89.24000 C ? A ? 135 0 + ATOM 981 CZ2 . TRP A 135 ? -22.61000 21.39500 2.01400 1.000 89.24000 C ? A ? 135 0 + ATOM 982 CZ3 . TRP A 135 ? -20.99900 19.84100 1.06000 1.000 89.24000 C ? A ? 135 0 + ATOM 983 CH2 . TRP A 135 ? -21.28600 21.05300 1.71200 1.000 89.24000 C ? A ? 135 0 + ATOM 984 N . GLN A 136 ? -27.56700 17.05200 -1.12500 1.000 83.48000 N ? A ? 136 0 + ATOM 985 CA . GLN A 136 ? -28.90100 17.62500 -1.30000 1.000 83.48000 C ? A ? 136 0 + ATOM 986 C . GLN A 136 ? -29.24500 18.55700 -0.13200 1.000 83.48000 C ? A ? 136 0 + ATOM 987 O . GLN A 136 ? -28.94300 18.26700 1.02700 1.000 83.48000 O ? A ? 136 0 + ATOM 988 CB . GLN A 136 ? -29.94600 16.52100 -1.49900 1.000 83.48000 C ? A ? 136 0 + ATOM 989 CG . GLN A 136 ? -29.71500 15.77800 -2.82500 1.000 83.48000 C ? A ? 136 0 + ATOM 990 CD . GLN A 136 ? -30.81500 14.76800 -3.13600 1.000 83.48000 C ? A ? 136 0 + ATOM 991 OE1 . GLN A 136 ? -31.32600 14.06200 -2.28600 1.000 83.48000 O ? A ? 136 0 + ATOM 992 NE2 . GLN A 136 ? -31.22000 14.64000 -4.38000 1.000 83.48000 N ? A ? 136 0 + ATOM 993 N . LEU A 137 ? -29.86700 19.69800 -0.44200 1.000 73.64000 N ? A ? 137 0 + ATOM 994 CA . LEU A 137 ? -30.30100 20.65200 0.57300 1.000 73.64000 C ? A ? 137 0 + ATOM 995 C . LEU A 137 ? -31.55700 20.12600 1.27000 1.000 73.64000 C ? A ? 137 0 + ATOM 996 O . LEU A 137 ? -32.62100 20.08500 0.65500 1.000 73.64000 O ? A ? 137 0 + ATOM 997 CB . LEU A 137 ? -30.56800 22.02600 -0.07000 1.000 73.64000 C ? A ? 137 0 + ATOM 998 CG . LEU A 137 ? -30.64800 23.17300 0.95300 1.000 73.64000 C ? A ? 137 0 + ATOM 999 CD1 . LEU A 137 ? -29.28300 23.49600 1.56700 1.000 73.64000 C ? A ? 137 0 + ATOM 1000 CD2 . LEU A 137 ? -31.15500 24.43200 0.25000 1.000 73.64000 C ? A ? 137 0 + ATOM 1001 N . ASN A 138 ? -31.43900 19.78800 2.55200 1.000 65.93000 N ? A ? 138 0 + ATOM 1002 CA . ASN A 138 ? -32.59600 19.39100 3.35700 1.000 65.93000 C ? A ? 138 0 + ATOM 1003 C . ASN A 138 ? -33.19800 20.57200 4.12800 1.000 65.93000 C ? A ? 138 0 + ATOM 1004 O . ASN A 138 ? -34.40200 20.58200 4.35000 1.000 65.93000 O ? A ? 138 0 + ATOM 1005 CB . ASN A 138 ? -32.21400 18.20100 4.25200 1.000 65.93000 C ? A ? 138 0 + ATOM 1006 CG . ASN A 138 ? -31.98900 16.92100 3.45800 1.000 65.93000 C ? A ? 138 0 + ATOM 1007 OD1 . ASN A 138 ? -32.26000 16.81400 2.27500 1.000 65.93000 O ? A ? 138 0 + ATOM 1008 ND2 . ASN A 138 ? -31.50100 15.88100 4.09000 1.000 65.93000 N ? A ? 138 0 + ATOM 1009 N . ASP A 139 ? -32.39800 21.58800 4.47500 1.000 63.93000 N ? A ? 139 0 + ATOM 1010 CA . ASP A 139 ? -32.88400 22.77000 5.18900 1.000 63.93000 C ? A ? 139 0 + ATOM 1011 C . ASP A 139 ? -32.09600 24.03900 4.83600 1.000 63.93000 C ? A ? 139 0 + ATOM 1012 O . ASP A 139 ? -30.88400 24.01500 4.63000 1.000 63.93000 O ? A ? 139 0 + ATOM 1013 CB . ASP A 139 ? -32.87900 22.51500 6.71000 1.000 63.93000 C ? A ? 139 0 + ATOM 1014 CG . ASP A 139 ? -34.29300 22.45100 7.29500 1.000 63.93000 C ? A ? 139 0 + ATOM 1015 OD1 . ASP A 139 ? -35.15500 23.20900 6.78900 1.000 63.93000 O ? A ? 139 0 + ATOM 1016 OD2 . ASP A 139 ? -34.46900 21.71700 8.29100 1.000 63.93000 O ? A ? 139 0 + ATOM 1017 N . ARG A 140 ? -32.79400 25.17700 4.75100 1.000 56.49000 N ? A ? 140 0 + ATOM 1018 CA . ARG A 140 ? -32.27000 26.43100 4.16800 1.000 56.49000 C ? A ? 140 0 + ATOM 1019 C . ARG A 140 ? -31.43300 27.31500 5.10900 1.000 56.49000 C ? A ? 140 0 + ATOM 1020 O . ARG A 140 ? -31.23800 28.48400 4.79200 1.000 56.49000 O ? A ? 140 0 + ATOM 1021 CB . ARG A 140 ? -33.41000 27.20200 3.46200 1.000 56.49000 C ? A ? 140 0 + ATOM 1022 CG . ARG A 140 ? -33.62300 26.71200 2.02500 1.000 56.49000 C ? A ? 140 0 + ATOM 1023 CD . ARG A 140 ? -34.62100 27.61200 1.29000 1.000 56.49000 C ? A ? 140 0 + ATOM 1024 NE . ARG A 140 ? -34.78600 27.19700 -0.11600 1.000 56.49000 N ? A ? 140 0 + ATOM 1025 CZ . ARG A 140 ? -35.59800 27.74500 -1.00200 1.000 56.49000 C ? A ? 140 0 + ATOM 1026 NH1 . ARG A 140 ? -36.34700 28.77200 -0.70700 1.000 56.49000 N ? A ? 140 0 + ATOM 1027 NH2 . ARG A 140 ? -35.67400 27.26400 -2.21100 1.000 56.49000 N ? A ? 140 0 + ATOM 1028 N . SER A 141 ? -30.93200 26.82300 6.24600 1.000 57.16000 N ? A ? 141 0 + ATOM 1029 CA . SER A 141 ? -30.25200 27.70800 7.21700 1.000 57.16000 C ? A ? 141 0 + ATOM 1030 C . SER A 141 ? -29.14200 27.07500 8.07000 1.000 57.16000 C ? A ? 141 0 + ATOM 1031 O . SER A 141 ? -28.79500 27.62700 9.11700 1.000 57.16000 O ? A ? 141 0 + ATOM 1032 CB . SER A 141 ? -31.30500 28.39900 8.09500 1.000 57.16000 C ? A ? 141 0 + ATOM 1033 OG . SER A 141 ? -30.72800 29.49400 8.77500 1.000 57.16000 O ? A ? 141 0 + ATOM 1034 N . SER A 142 ? -28.55600 25.95400 7.65000 1.000 70.83000 N ? A ? 142 0 + ATOM 1035 CA . SER A 142 ? -27.48000 25.30100 8.41000 1.000 70.83000 C ? A ? 142 0 + ATOM 1036 C . SER A 142 ? -26.10800 25.53400 7.77500 1.000 70.83000 C ? A ? 142 0 + ATOM 1037 O . SER A 142 ? -25.95700 25.49300 6.55600 1.000 70.83000 O ? A ? 142 0 + ATOM 1038 CB . SER A 142 ? -27.78200 23.81400 8.59300 1.000 70.83000 C ? A ? 142 0 + ATOM 1039 OG . SER A 142 ? -28.99600 23.67100 9.31300 1.000 70.83000 O ? A ? 142 0 + ATOM 1040 N . LEU A 143 ? -25.09800 25.78000 8.61400 1.000 85.06000 N ? A ? 143 0 + ATOM 1041 CA . LEU A 143 ? -23.69800 25.70300 8.20600 1.000 85.06000 C ? A ? 143 0 + ATOM 1042 C . LEU A 143 ? -23.31800 24.22500 8.13000 1.000 85.06000 C ? A ? 143 0 + ATOM 1043 O . LEU A 143 ? -23.33900 23.53300 9.14500 1.000 85.06000 O ? A ? 143 0 + ATOM 1044 CB . LEU A 143 ? -22.82100 26.45900 9.22300 1.000 85.06000 C ? A ? 143 0 + ATOM 1045 CG . LEU A 143 ? -21.31800 26.44700 8.88000 1.000 85.06000 C ? A ? 143 0 + ATOM 1046 CD1 . LEU A 143 ? -21.02800 27.30700 7.64600 1.000 85.06000 C ? A ? 143 0 + ATOM 1047 CD2 . LEU A 143 ? -20.51200 26.99900 10.05700 1.000 85.06000 C ? A ? 143 0 + ATOM 1048 N . TYR A 144 ? -22.96000 23.75300 6.94300 1.000 87.21000 N ? A ? 144 0 + ATOM 1049 CA . TYR A 144 ? -22.46300 22.40000 6.75000 1.000 87.21000 C ? A ? 144 0 + ATOM 1050 C . TYR A 144 ? -20.94000 22.37600 6.83200 1.000 87.21000 C ? A ? 144 0 + ATOM 1051 O . TYR A 144 ? -20.25900 23.28300 6.34800 1.000 87.21000 O ? A ? 144 0 + ATOM 1052 CB . TYR A 144 ? -22.96700 21.83900 5.42300 1.000 87.21000 C ? A ? 144 0 + ATOM 1053 CG . TYR A 144 ? -24.47300 21.68300 5.36000 1.000 87.21000 C ? A ? 144 0 + ATOM 1054 CD1 . TYR A 144 ? -25.08400 20.58000 5.98600 1.000 87.21000 C ? A ? 144 0 + ATOM 1055 CD2 . TYR A 144 ? -25.26100 22.64500 4.69900 1.000 87.21000 C ? A ? 144 0 + ATOM 1056 CE1 . TYR A 144 ? -26.48400 20.43600 5.95400 1.000 87.21000 C ? A ? 144 0 + ATOM 1057 CE2 . TYR A 144 ? -26.66200 22.50200 4.66100 1.000 87.21000 C ? A ? 144 0 + ATOM 1058 CZ . TYR A 144 ? -27.27600 21.39800 5.28800 1.000 87.21000 C ? A ? 144 0 + ATOM 1059 OH . TYR A 144 ? -28.62800 21.26000 5.25300 1.000 87.21000 O ? A ? 144 0 + ATOM 1060 N . VAL A 145 ? -20.41600 21.31300 7.42700 1.000 90.33000 N ? A ? 145 0 + ATOM 1061 CA . VAL A 145 ? -18.99200 21.00600 7.51100 1.000 90.33000 C ? A ? 145 0 + ATOM 1062 C . VAL A 145 ? -18.76600 19.70600 6.75600 1.000 90.33000 C ? A ? 145 0 + ATOM 1063 O . VAL A 145 ? -19.29900 18.66600 7.13500 1.000 90.33000 O ? A ? 145 0 + ATOM 1064 CB . VAL A 145 ? -18.53800 20.90600 8.98000 1.000 90.33000 C ? A ? 145 0 + ATOM 1065 CG1 . VAL A 145 ? -17.03600 20.60600 9.07500 1.000 90.33000 C ? A ? 145 0 + ATOM 1066 CG2 . VAL A 145 ? -18.84100 22.20900 9.73700 1.000 90.33000 C ? A ? 145 0 + ATOM 1067 N . ALA A 146 ? -17.99500 19.76100 5.67400 1.000 92.07000 N ? A ? 146 0 + ATOM 1068 CA . ALA A 146 ? -17.48900 18.56900 5.01200 1.000 92.07000 C ? A ? 146 0 + ATOM 1069 C . ALA A 146 ? -16.12700 18.22500 5.61700 1.000 92.07000 C ? A ? 146 0 + ATOM 1070 O . ALA A 146 ? -15.27200 19.10200 5.76700 1.000 92.07000 O ? A ? 146 0 + ATOM 1071 CB . ALA A 146 ? -17.42200 18.79600 3.49900 1.000 92.07000 C ? A ? 146 0 + ATOM 1072 N . SER A 147 ? -15.91100 16.95600 5.95200 1.000 92.17000 N ? A ? 147 0 + ATOM 1073 CA . SER A 147 ? -14.62000 16.46700 6.42600 1.000 92.17000 C ? A ? 147 0 + ATOM 1074 C . SER A 147 ? -14.22100 15.19100 5.70800 1.000 92.17000 C ? A ? 147 0 + ATOM 1075 O . SER A 147 ? -15.05000 14.29400 5.56600 1.000 92.17000 O ? A ? 147 0 + ATOM 1076 CB . SER A 147 ? -14.60400 16.26700 7.94300 1.000 92.17000 C ? A ? 147 0 + ATOM 1077 OG . SER A 147 ? -15.50700 15.27300 8.37600 1.000 92.17000 O ? A ? 147 0 + ATOM 1078 N . ALA A 148 ? -12.95500 15.10500 5.31100 1.000 93.27000 N ? A ? 148 0 + ATOM 1079 CA . ALA A 148 ? -12.35400 13.89900 4.76000 1.000 93.27000 C ? A ? 148 0 + ATOM 1080 C . ALA A 148 ? -11.22200 13.41600 5.66000 1.000 93.27000 C ? A ? 148 0 + ATOM 1081 O . ALA A 148 ? -10.31900 14.19400 5.96800 1.000 93.27000 O ? A ? 148 0 + ATOM 1082 CB . ALA A 148 ? -11.85700 14.16700 3.34300 1.000 93.27000 C ? A ? 148 0 + ATOM 1083 N . GLU A 149 ? -11.26800 12.14800 6.05100 1.000 92.92000 N ? A ? 149 0 + ATOM 1084 CA . GLU A 149 ? -10.18800 11.46800 6.76200 1.000 92.92000 C ? A ? 149 0 + ATOM 1085 C . GLU A 149 ? -9.45700 10.52800 5.80600 1.000 92.92000 C ? A ? 149 0 + ATOM 1086 O . GLU A 149 ? -10.07800 9.69400 5.14800 1.000 92.92000 O ? A ? 149 0 + ATOM 1087 CB . GLU A 149 ? -10.74100 10.74100 7.99100 1.000 92.92000 C ? A ? 149 0 + ATOM 1088 CG . GLU A 149 ? -9.59900 10.10300 8.79900 1.000 92.92000 C ? A ? 149 0 + ATOM 1089 CD . GLU A 149 ? -10.04600 9.51800 10.14300 1.000 92.92000 C ? A ? 149 0 + ATOM 1090 OE1 . GLU A 149 ? -9.19900 8.82700 10.76000 1.000 92.92000 O ? A ? 149 0 + ATOM 1091 OE2 . GLU A 149 ? -11.18200 9.83700 10.56600 1.000 92.92000 O ? A ? 149 0 + ATOM 1092 N . GLY A 150 ? -8.14600 10.71400 5.67600 1.000 92.11000 N ? A ? 150 0 + ATOM 1093 CA . GLY A 150 ? -7.28300 9.86700 4.86900 1.000 92.11000 C ? A ? 150 0 + ATOM 1094 C . GLY A 150 ? -6.85700 8.60900 5.62000 1.000 92.11000 C ? A ? 150 0 + ATOM 1095 O . GLY A 150 ? -6.79600 8.58200 6.84500 1.000 92.11000 O ? A ? 150 0 + ATOM 1096 N . ASN A 151 ? -6.45300 7.58200 4.88000 1.000 89.70000 N ? A ? 151 0 + ATOM 1097 CA . ASN A 151 ? -5.82800 6.37400 5.42700 1.000 89.70000 C ? A ? 151 0 + ATOM 1098 C . ASN A 151 ? -4.51800 6.62100 6.20900 1.000 89.70000 C ? A ? 151 0 + ATOM 1099 O . ASN A 151 ? -4.06900 5.73300 6.92700 1.000 89.70000 O ? A ? 151 0 + ATOM 1100 CB . ASN A 151 ? -5.60300 5.37100 4.28000 1.000 89.70000 C ? A ? 151 0 + ATOM 1101 CG . ASN A 151 ? -4.67700 5.87100 3.17700 1.000 89.70000 C ? A ? 151 0 + ATOM 1102 OD1 . ASN A 151 ? -4.67900 7.01800 2.77200 1.000 89.70000 O ? A ? 151 0 + ATOM 1103 ND2 . ASN A 151 ? -3.89600 5.00900 2.57400 1.000 89.70000 N ? A ? 151 0 + ATOM 1104 N . ASP A 152 ? -3.90000 7.79700 6.07300 1.000 89.34000 N ? A ? 152 0 + ATOM 1105 CA . ASP A 152 ? -2.75600 8.25800 6.87300 1.000 89.34000 C ? A ? 152 0 + ATOM 1106 C . ASP A 152 ? -3.17000 9.05700 8.12700 1.000 89.34000 C ? A ? 152 0 + ATOM 1107 O . ASP A 152 ? -2.31200 9.62800 8.80100 1.000 89.34000 O ? A ? 152 0 + ATOM 1108 CB . ASP A 152 ? -1.80100 9.08000 5.98300 1.000 89.34000 C ? A ? 152 0 + ATOM 1109 CG . ASP A 152 ? -2.34000 10.47200 5.62000 1.000 89.34000 C ? A ? 152 0 + ATOM 1110 OD1 . ASP A 152 ? -3.57400 10.68200 5.71900 1.000 89.34000 O ? A ? 152 0 + ATOM 1111 OD2 . ASP A 152 ? -1.53900 11.33700 5.19500 1.000 89.34000 O ? A ? 152 0 + ATOM 1112 N . HIS A 153 ? -4.47300 9.12000 8.42300 1.000 87.28000 N ? A ? 153 0 + ATOM 1113 CA . HIS A 153 ? -5.09900 9.94600 9.46100 1.000 87.28000 C ? A ? 153 0 + ATOM 1114 C . HIS A 153 ? -5.01200 11.46300 9.22800 1.000 87.28000 C ? A ? 153 0 + ATOM 1115 O . HIS A 153 ? -5.27700 12.25400 10.13800 1.000 87.28000 O ? A ? 153 0 + ATOM 1116 CB . HIS A 153 ? -4.61600 9.52700 10.85700 1.000 87.28000 C ? A ? 153 0 + ATOM 1117 CG . HIS A 153 ? -4.70300 8.04500 11.09000 1.000 87.28000 C ? A ? 153 0 + ATOM 1118 ND1 . HIS A 153 ? -5.86700 7.32600 11.21600 1.000 87.28000 N ? A ? 153 0 + ATOM 1119 CD2 . HIS A 153 ? -3.66000 7.16300 11.17600 1.000 87.28000 C ? A ? 153 0 + ATOM 1120 CE1 . HIS A 153 ? -5.52800 6.03900 11.39300 1.000 87.28000 C ? A ? 153 0 + ATOM 1121 NE2 . HIS A 153 ? -4.19100 5.88600 11.39300 1.000 87.28000 N ? A ? 153 0 + ATOM 1122 N . SER A 154 ? -4.66000 11.90800 8.01800 1.000 91.44000 N ? A ? 154 0 + ATOM 1123 CA . SER A 154 ? -4.79300 13.31500 7.64100 1.000 91.44000 C ? A ? 154 0 + ATOM 1124 C . SER A 154 ? -6.26400 13.70200 7.53700 1.000 91.44000 C ? A ? 154 0 + ATOM 1125 O . SER A 154 ? -7.10400 12.92900 7.08300 1.000 91.44000 O ? A ? 154 0 + ATOM 1126 CB . SER A 154 ? -4.03600 13.66100 6.35400 1.000 91.44000 C ? A ? 154 0 + ATOM 1127 OG . SER A 154 ? -4.55900 13.01000 5.21700 1.000 91.44000 O ? A ? 154 0 + ATOM 1128 N . ILE A 155 ? -6.58200 14.92400 7.95800 1.000 91.47000 N ? A ? 155 0 + ATOM 1129 CA . ILE A 155 ? -7.95200 15.43100 7.96100 1.000 91.47000 C ? A ? 155 0 + ATOM 1130 C . ILE A 155 ? -8.01400 16.69400 7.11200 1.000 91.47000 C ? A ? 155 0 + ATOM 1131 O . ILE A 155 ? -7.30200 17.66300 7.37900 1.000 91.47000 O ? A ? 155 0 + ATOM 1132 CB . ILE A 155 ? -8.45300 15.65300 9.40100 1.000 91.47000 C ? A ? 155 0 + ATOM 1133 CG1 . ILE A 155 ? -8.41700 14.33200 10.20800 1.000 91.47000 C ? A ? 155 0 + ATOM 1134 CG2 . ILE A 155 ? -9.87800 16.23600 9.40300 1.000 91.47000 C ? A ? 155 0 + ATOM 1135 CD1 . ILE A 155 ? -8.87100 14.46500 11.66600 1.000 91.47000 C ? A ? 155 0 + ATOM 1136 N . LEU A 156 ? -8.91400 16.70100 6.13300 1.000 93.61000 N ? A ? 156 0 + ATOM 1137 CA . LEU A 156 ? -9.31000 17.89000 5.38400 1.000 93.61000 C ? A ? 156 0 + ATOM 1138 C . LEU A 156 ? -10.68900 18.33500 5.85500 1.000 93.61000 C ? A ? 156 0 + ATOM 1139 O . LEU A 156 ? -11.53800 17.50000 6.16900 1.000 93.61000 O ? A ? 156 0 + ATOM 1140 CB . LEU A 156 ? -9.29900 17.61100 3.87400 1.000 93.61000 C ? A ? 156 0 + ATOM 1141 CG . LEU A 156 ? -7.98800 17.00900 3.34300 1.000 93.61000 C ? A ? 156 0 + ATOM 1142 CD1 . LEU A 156 ? -8.12000 16.77900 1.84200 1.000 93.61000 C ? A ? 156 0 + ATOM 1143 CD2 . LEU A 156 ? -6.78000 17.91100 3.60100 1.000 93.61000 C ? A ? 156 0 + ATOM 1144 N . MET A 157 ? -10.92000 19.64300 5.91200 1.000 93.53000 N ? A ? 157 0 + ATOM 1145 CA . MET A 157 ? -12.21400 20.20100 6.29800 1.000 93.53000 C ? A ? 157 0 + ATOM 1146 C . MET A 157 ? -12.53300 21.42600 5.46000 1.000 93.53000 C ? A ? 157 0 + ATOM 1147 O . MET A 157 ? -11.64300 22.21200 5.13400 1.000 93.53000 O ? A ? 157 0 + ATOM 1148 CB . MET A 157 ? -12.25700 20.56900 7.78900 1.000 93.53000 C ? A ? 157 0 + ATOM 1149 CG . MET A 157 ? -12.02000 19.35700 8.69600 1.000 93.53000 C ? A ? 157 0 + ATOM 1150 SD . MET A 157 ? -12.17700 19.65100 10.48000 1.000 93.53000 S ? A ? 157 0 + ATOM 1151 CE . MET A 157 ? -10.88500 20.90400 10.71600 1.000 93.53000 C ? A ? 157 0 + ATOM 1152 N . CYS A 158 ? -13.80700 21.60400 5.14900 1.000 93.41000 N ? A ? 158 0 + ATOM 1153 CA . CYS A 158 ? -14.30300 22.82200 4.54000 1.000 93.41000 C ? A ? 158 0 + ATOM 1154 C . CYS A 158 ? -15.73300 23.08700 5.02300 1.000 93.41000 C ? A ? 158 0 + ATOM 1155 O . CYS A 158 ? -16.47600 22.15800 5.34800 1.000 93.41000 O ? A ? 158 0 + ATOM 1156 CB . CYS A 158 ? -14.14300 22.71600 3.01700 1.000 93.41000 C ? A ? 158 0 + ATOM 1157 SG . CYS A 158 ? -15.35200 21.67900 2.18300 1.000 93.41000 S ? A ? 158 0 + ATOM 1158 N . ASN A 159 ? -16.11300 24.36200 5.08300 1.000 91.84000 N ? A ? 159 0 + ATOM 1159 CA . ASN A 159 ? -17.42100 24.77900 5.57500 1.000 91.84000 C ? A ? 159 0 + ATOM 1160 C . ASN A 159 ? -18.18200 25.48700 4.45700 1.000 91.84000 C ? A ? 159 0 + ATOM 1161 O . ASN A 159 ? -17.60200 26.29100 3.72800 1.000 91.84000 O ? A ? 159 0 + ATOM 1162 CB . ASN A 159 ? -17.26500 25.68600 6.80500 1.000 91.84000 C ? A ? 159 0 + ATOM 1163 CG . ASN A 159 ? -16.57700 25.04000 7.99300 1.000 91.84000 C ? A ? 159 0 + ATOM 1164 OD1 . ASN A 159 ? -16.26500 23.86700 8.04200 1.000 91.84000 O ? A ? 159 0 + ATOM 1165 ND2 . ASN A 159 ? -16.30000 25.80600 9.02000 1.000 91.84000 N ? A ? 159 0 + ATOM 1166 N . SER A 160 ? -19.48100 25.22700 4.34800 1.000 89.68000 N ? A ? 160 0 + ATOM 1167 CA . SER A 160 ? -20.33100 25.85500 3.33900 1.000 89.68000 C ? A ? 160 0 + ATOM 1168 C . SER A 160 ? -21.76300 25.99500 3.83700 1.000 89.68000 C ? A ? 160 0 + ATOM 1169 O . SER A 160 ? -22.28700 25.13100 4.53400 1.000 89.68000 O ? A ? 160 0 + ATOM 1170 CB . SER A 160 ? -20.28100 25.03200 2.05100 1.000 89.68000 C ? A ? 160 0 + ATOM 1171 OG . SER A 160 ? -20.92500 25.69300 0.98200 1.000 89.68000 O ? A ? 160 0 + ATOM 1172 N . THR A 161 ? -22.41100 27.09800 3.47500 1.000 86.55000 N ? A ? 161 0 + ATOM 1173 CA . THR A 161 ? -23.86900 27.27500 3.60600 1.000 86.55000 C ? A ? 161 0 + ATOM 1174 C . THR A 161 ? -24.61200 26.86300 2.33200 1.000 86.55000 C ? A ? 161 0 + ATOM 1175 O . THR A 161 ? -25.84000 26.87200 2.29800 1.000 86.55000 O ? A ? 161 0 + ATOM 1176 CB . THR A 161 ? -24.20400 28.73200 3.94000 1.000 86.55000 C ? A ? 161 0 + ATOM 1177 OG1 . THR A 161 ? -23.62200 29.59300 2.98300 1.000 86.55000 O ? A ? 161 0 + ATOM 1178 CG2 . THR A 161 ? -23.66000 29.14500 5.30800 1.000 86.55000 C ? A ? 161 0 + ATOM 1179 N . SER A 162 ? -23.86800 26.52600 1.27500 1.000 87.03000 N ? A ? 162 0 + ATOM 1180 CA . SER A 162 ? -24.38700 26.01400 0.00900 1.000 87.03000 C ? A ? 162 0 + ATOM 1181 C . SER A 162 ? -24.50600 24.48200 0.04700 1.000 87.03000 C ? A ? 162 0 + ATOM 1182 O . SER A 162 ? -24.27700 23.84800 1.07400 1.000 87.03000 O ? A ? 162 0 + ATOM 1183 CB . SER A 162 ? -23.46700 26.49200 -1.12300 1.000 87.03000 C ? A ? 162 0 + ATOM 1184 OG . SER A 162 ? -24.08300 26.30300 -2.38200 1.000 87.03000 O ? A ? 162 0 + ATOM 1185 N . THR A 163 ? -24.84900 23.87500 -1.08700 1.000 89.21000 N ? A ? 163 0 + ATOM 1186 CA . THR A 163 ? -24.93800 22.41800 -1.30000 1.000 89.21000 C ? A ? 163 0 + ATOM 1187 C . THR A 163 ? -23.62800 21.77600 -1.75000 1.000 89.21000 C ? A ? 163 0 + ATOM 1188 O . THR A 163 ? -23.61700 20.61700 -2.16400 1.000 89.21000 O ? A ? 163 0 + ATOM 1189 CB . THR A 163 ? -26.02500 22.11000 -2.33500 1.000 89.21000 C ? A ? 163 0 + ATOM 1190 OG1 . THR A 163 ? -25.83700 22.88000 -3.50300 1.000 89.21000 O ? A ? 163 0 + ATOM 1191 CG2 . THR A 163 ? -27.40400 22.43800 -1.78200 1.000 89.21000 C ? A ? 163 0 + ATOM 1192 N . SER A 164 ? -22.53100 22.53100 -1.74900 1.000 92.97000 N ? A ? 164 0 + ATOM 1193 CA . SER A 164 ? -21.21800 22.04700 -2.16100 1.000 92.97000 C ? A ? 164 0 + ATOM 1194 C . SER A 164 ? -20.08900 22.73100 -1.40500 1.000 92.97000 C ? A ? 164 0 + ATOM 1195 O . SER A 164 ? -20.23800 23.85800 -0.91500 1.000 92.97000 O ? A ? 164 0 + ATOM 1196 CB . SER A 164 ? -21.01600 22.20600 -3.67200 1.000 92.97000 C ? A ? 164 0 + ATOM 1197 OG . SER A 164 ? -20.98700 23.57400 -4.04400 1.000 92.97000 O ? A ? 164 0 + ATOM 1198 N . CYS A 165 ? -18.95500 22.04000 -1.31300 1.000 93.31000 N ? A ? 165 0 + ATOM 1199 CA . CYS A 165 ? -17.76300 22.51900 -0.63600 1.000 93.31000 C ? A ? 165 0 + ATOM 1200 C . CYS A 165 ? -16.50400 21.83700 -1.17700 1.000 93.31000 C ? A ? 165 0 + ATOM 1201 O . CYS A 165 ? -16.50900 20.63000 -1.41500 1.000 93.31000 O ? A ? 165 0 + ATOM 1202 CB . CYS A 165 ? -17.96500 22.24800 0.85100 1.000 93.31000 C ? A ? 165 0 + ATOM 1203 SG . CYS A 165 ? -16.80600 23.04800 1.95200 1.000 93.31000 S ? A ? 165 0 + ATOM 1204 N . ASP A 166 ? -15.43200 22.60900 -1.34500 1.000 94.82000 N ? A ? 166 0 + ATOM 1205 CA . ASP A 166 ? -14.15200 22.10800 -1.83900 1.000 94.82000 C ? A ? 166 0 + ATOM 1206 C . ASP A 166 ? -13.19100 21.85700 -0.67700 1.000 94.82000 C ? A ? 166 0 + ATOM 1207 O . ASP A 166 ? -12.76500 22.77700 0.02600 1.000 94.82000 O ? A ? 166 0 + ATOM 1208 CB . ASP A 166 ? -13.54900 23.07500 -2.86600 1.000 94.82000 C ? A ? 166 0 + ATOM 1209 CG . ASP A 166 ? -14.39300 23.18200 -4.13700 1.000 94.82000 C ? A ? 166 0 + ATOM 1210 OD1 . ASP A 166 ? -14.91300 22.13600 -4.58800 1.000 94.82000 O ? A ? 166 0 + ATOM 1211 OD2 . ASP A 166 ? -14.50800 24.31400 -4.65100 1.000 94.82000 O ? A ? 166 0 + ATOM 1212 N . LEU A 167 ? -12.81900 20.59500 -0.48900 1.000 95.09000 N ? A ? 167 0 + ATOM 1213 CA . LEU A 167 ? -11.75300 20.19300 0.41600 1.000 95.09000 C ? A ? 167 0 + ATOM 1214 C . LEU A 167 ? -10.41200 20.45300 -0.26400 1.000 95.09000 C ? A ? 167 0 + ATOM 1215 O . LEU A 167 ? -10.12000 19.87000 -1.30600 1.000 95.09000 O ? A ? 167 0 + ATOM 1216 CB . LEU A 167 ? -11.90700 18.71000 0.75400 1.000 95.09000 C ? A ? 167 0 + ATOM 1217 CG . LEU A 167 ? -13.18200 18.36200 1.53600 1.000 95.09000 C ? A ? 167 0 + ATOM 1218 CD1 . LEU A 167 ? -13.34300 16.84900 1.51300 1.000 95.09000 C ? A ? 167 0 + ATOM 1219 CD2 . LEU A 167 ? -13.08000 18.81300 2.99100 1.000 95.09000 C ? A ? 167 0 + ATOM 1220 N . ILE A 168 ? -9.59900 21.32100 0.33000 1.000 94.20000 N ? A ? 168 0 + ATOM 1221 CA . ILE A 168 ? -8.31900 21.76400 -0.23000 1.000 94.20000 C ? A ? 168 0 + ATOM 1222 C . ILE A 168 ? -7.17400 21.00600 0.44200 1.000 94.20000 C ? A ? 168 0 + ATOM 1223 O . ILE A 168 ? -7.16300 20.85700 1.66100 1.000 94.20000 O ? A ? 168 0 + ATOM 1224 CB . ILE A 168 ? -8.15300 23.29500 -0.07500 1.000 94.20000 C ? A ? 168 0 + ATOM 1225 CG1 . ILE A 168 ? -9.38100 24.05500 -0.63300 1.000 94.20000 C ? A ? 168 0 + ATOM 1226 CG2 . ILE A 168 ? -6.85300 23.76000 -0.76500 1.000 94.20000 C ? A ? 168 0 + ATOM 1227 CD1 . ILE A 168 ? -9.34100 25.57500 -0.43900 1.000 94.20000 C ? A ? 168 0 + ATOM 1228 N . GLY A 169 ? -6.17900 20.58700 -0.34200 1.000 92.75000 N ? A ? 169 0 + ATOM 1229 CA . GLY A 169 ? -4.97900 19.91100 0.16100 1.000 92.75000 C ? A ? 169 0 + ATOM 1230 C . GLY A 169 ? -5.03500 18.38800 0.05500 1.000 92.75000 C ? A ? 169 0 + ATOM 1231 O . GLY A 169 ? -4.29200 17.70300 0.76000 1.000 92.75000 O ? A ? 169 0 + ATOM 1232 N . ALA A 170 ? -5.89200 17.86000 -0.82300 1.000 92.72000 N ? A ? 170 0 + ATOM 1233 CA . ALA A 170 ? -5.92500 16.44200 -1.14900 1.000 92.72000 C ? A ? 170 0 + ATOM 1234 C . ALA A 170 ? -4.57100 15.98600 -1.70400 1.000 92.72000 C ? A ? 170 0 + ATOM 1235 O . ALA A 170 ? -3.98100 16.63500 -2.57200 1.000 92.72000 O ? A ? 170 0 + ATOM 1236 CB . ALA A 170 ? -7.07700 16.17100 -2.11900 1.000 92.72000 C ? A ? 170 0 + ATOM 1237 N . ARG A 171 ? -4.06800 14.86900 -1.17400 1.000 91.52000 N ? A ? 171 0 + ATOM 1238 CA . ARG A 171 ? -2.79200 14.27300 -1.58500 1.000 91.52000 C ? A ? 171 0 + ATOM 1239 C . ARG A 171 ? -3.04000 13.12600 -2.56100 1.000 91.52000 C ? A ? 171 0 + ATOM 1240 O . ARG A 171 ? -4.08900 12.48200 -2.52500 1.000 91.52000 O ? A ? 171 0 + ATOM 1241 CB . ARG A 171 ? -1.98700 13.83000 -0.35300 1.000 91.52000 C ? A ? 171 0 + ATOM 1242 CG . ARG A 171 ? -1.69200 14.98900 0.60900 1.000 91.52000 C ? A ? 171 0 + ATOM 1243 CD . ARG A 171 ? -0.92700 14.48300 1.83300 1.000 91.52000 C ? A ? 171 0 + ATOM 1244 NE . ARG A 171 ? -0.64900 15.59500 2.76100 1.000 91.52000 N ? A ? 171 0 + ATOM 1245 CZ . ARG A 171 ? 0.42100 15.73700 3.52000 1.000 91.52000 C ? A ? 171 0 + ATOM 1246 NH1 . ARG A 171 ? 1.37800 14.85200 3.53600 1.000 91.52000 N ? A ? 171 0 + ATOM 1247 NH2 . ARG A 171 ? 0.54400 16.78100 4.29100 1.000 91.52000 N ? A ? 171 0 + ATOM 1248 N . CYS A 172 ? -2.06600 12.85300 -3.42300 1.000 92.05000 N ? A ? 172 0 + ATOM 1249 CA . CYS A 172 ? -2.07700 11.64700 -4.24800 1.000 92.05000 C ? A ? 172 0 + ATOM 1250 C . CYS A 172 ? -1.94000 10.39300 -3.37300 1.000 92.05000 C ? A ? 172 0 + ATOM 1251 O . CYS A 172 ? -1.41800 10.46100 -2.26100 1.000 92.05000 O ? A ? 172 0 + ATOM 1252 CB . CYS A 172 ? -0.95900 11.73600 -5.29600 1.000 92.05000 C ? A ? 172 0 + ATOM 1253 SG . CYS A 172 ? 0.73700 11.85200 -4.64200 1.000 92.05000 S ? A ? 172 0 + ATOM 1254 N . GLY A 173 ? -2.36000 9.23800 -3.88400 1.000 91.78000 N ? A ? 173 0 + ATOM 1255 CA . GLY A 173 ? -2.15300 7.96300 -3.19800 1.000 91.78000 C ? A ? 173 0 + ATOM 1256 C . GLY A 173 ? -3.04900 7.73900 -1.97600 1.000 91.78000 C ? A ? 173 0 + ATOM 1257 O . GLY A 173 ? -2.76200 6.84500 -1.18300 1.000 91.78000 O ? A ? 173 0 + ATOM 1258 N . MET A 174 ? -4.09600 8.54600 -1.80000 1.000 91.89000 N ? A ? 174 0 + ATOM 1259 CA . MET A 174 ? -4.91600 8.56300 -0.59100 1.000 91.89000 C ? A ? 174 0 + ATOM 1260 C . MET A 174 ? -6.24300 7.84900 -0.80100 1.000 91.89000 C ? A ? 174 0 + ATOM 1261 O . MET A 174 ? -6.87800 7.99600 -1.84700 1.000 91.89000 O ? A ? 174 0 + ATOM 1262 CB . MET A 174 ? -5.17000 10.00400 -0.13900 1.000 91.89000 C ? A ? 174 0 + ATOM 1263 CG . MET A 174 ? -3.88900 10.73000 0.27700 1.000 91.89000 C ? A ? 174 0 + ATOM 1264 SD . MET A 174 ? -2.86800 9.91800 1.52900 1.000 91.89000 S ? A ? 174 0 + ATOM 1265 CE . MET A 174 ? -4.02600 9.98500 2.91200 1.000 91.89000 C ? A ? 174 0 + ATOM 1266 N . HIS A 175 ? -6.68200 7.13400 0.23200 1.000 91.96000 N ? A ? 175 0 + ATOM 1267 CA . HIS A 175 ? -8.06300 6.68300 0.36800 1.000 91.96000 C ? A ? 175 0 + ATOM 1268 C . HIS A 175 ? -8.74200 7.57100 1.40800 1.000 91.96000 C ? A ? 175 0 + ATOM 1269 O . HIS A 175 ? -8.27900 7.61400 2.54700 1.000 91.96000 O ? A ? 175 0 + ATOM 1270 CB . HIS A 175 ? -8.09100 5.20500 0.76800 1.000 91.96000 C ? A ? 175 0 + ATOM 1271 CG . HIS A 175 ? -9.42400 4.56000 0.50000 1.000 91.96000 C ? A ? 175 0 + ATOM 1272 ND1 . HIS A 175 ? -10.56400 4.60300 1.27600 1.000 91.96000 N ? A ? 175 0 + ATOM 1273 CD2 . HIS A 175 ? -9.71100 3.78000 -0.58600 1.000 91.96000 C ? A ? 175 0 + ATOM 1274 CE1 . HIS A 175 ? -11.49400 3.84700 0.67100 1.000 91.96000 C ? A ? 175 0 + ATOM 1275 NE2 . HIS A 175 ? -11.02600 3.33500 -0.47800 1.000 91.96000 N ? A ? 175 0 + ATOM 1276 N . TYR A 176 ? -9.78000 8.30200 1.00700 1.000 91.90000 N ? A ? 176 0 + ATOM 1277 CA . TYR A 176 ? -10.49900 9.23500 1.86800 1.000 91.90000 C ? A ? 176 0 + ATOM 1278 C . TYR A 176 ? -11.89900 8.72100 2.18700 1.000 91.90000 C ? A ? 176 0 + ATOM 1279 O . TYR A 176 ? -12.65800 8.38500 1.27400 1.000 91.90000 O ? A ? 176 0 + ATOM 1280 CB . TYR A 176 ? -10.58200 10.63000 1.22800 1.000 91.90000 C ? A ? 176 0 + ATOM 1281 CG . TYR A 176 ? -9.29700 11.43600 1.27800 1.000 91.90000 C ? A ? 176 0 + ATOM 1282 CD1 . TYR A 176 ? -8.82200 11.91700 2.51200 1.000 91.90000 C ? A ? 176 0 + ATOM 1283 CD2 . TYR A 176 ? -8.59100 11.73100 0.09800 1.000 91.90000 C ? A ? 176 0 + ATOM 1284 CE1 . TYR A 176 ? -7.62500 12.65500 2.58200 1.000 91.90000 C ? A ? 176 0 + ATOM 1285 CE2 . TYR A 176 ? -7.40700 12.49400 0.15500 1.000 91.90000 C ? A ? 176 0 + ATOM 1286 CZ . TYR A 176 ? -6.91300 12.94400 1.39800 1.000 91.90000 C ? A ? 176 0 + ATOM 1287 OH . TYR A 176 ? -5.75200 13.65000 1.45900 1.000 91.90000 O ? A ? 176 0 + ATOM 1288 N . THR A 177 ? -12.25500 8.78300 3.46700 1.000 92.26000 N ? A ? 177 0 + ATOM 1289 CA . THR A 177 ? -13.63400 8.67700 3.94300 1.000 92.26000 C ? A ? 177 0 + ATOM 1290 C . THR A 177 ? -14.18600 10.07600 4.16500 1.000 92.26000 C ? A ? 177 0 + ATOM 1291 O . THR A 177 ? -13.65500 10.84100 4.97200 1.000 92.26000 O ? A ? 177 0 + ATOM 1292 CB . THR A 177 ? -13.72300 7.89300 5.25400 1.000 92.26000 C ? A ? 177 0 + ATOM 1293 OG1 . THR A 177 ? -13.15900 6.61600 5.11800 1.000 92.26000 O ? A ? 177 0 + ATOM 1294 CG2 . THR A 177 ? -15.18100 7.74900 5.69700 1.000 92.26000 C ? A ? 177 0 + ATOM 1295 N . ILE A 178 ? -15.24700 10.42700 3.44500 1.000 92.35000 N ? A ? 178 0 + ATOM 1296 CA . ILE A 178 ? -15.83500 11.76700 3.45000 1.000 92.35000 C ? A ? 178 0 + ATOM 1297 C . ILE A 178 ? -17.19900 11.72900 4.12800 1.000 92.35000 C ? A ? 178 0 + ATOM 1298 O . ILE A 178 ? -18.03900 10.89200 3.80400 1.000 92.35000 O ? A ? 178 0 + ATOM 1299 CB . ILE A 178 ? -15.91300 12.35000 2.02300 1.000 92.35000 C ? A ? 178 0 + ATOM 1300 CG1 . ILE A 178 ? -14.53500 12.25200 1.32900 1.000 92.35000 C ? A ? 178 0 + ATOM 1301 CG2 . ILE A 178 ? -16.41600 13.80900 2.06500 1.000 92.35000 C ? A ? 178 0 + ATOM 1302 CD1 . ILE A 178 ? -14.49600 12.80100 -0.09400 1.000 92.35000 C ? A ? 178 0 + ATOM 1303 N . ILE A 179 ? -17.44300 12.68100 5.02300 1.000 90.26000 N ? A ? 179 0 + ATOM 1304 CA . ILE A 179 ? -18.76100 12.93800 5.60800 1.000 90.26000 C ? A ? 179 0 + ATOM 1305 C . ILE A 179 ? -19.10300 14.42100 5.51300 1.000 90.26000 C ? A ? 179 0 + ATOM 1306 O . ILE A 179 ? -18.22200 15.28200 5.49000 1.000 90.26000 O ? A ? 179 0 + ATOM 1307 CB . ILE A 179 ? -18.86900 12.43400 7.06600 1.000 90.26000 C ? A ? 179 0 + ATOM 1308 CG1 . ILE A 179 ? -17.84300 13.10000 8.00600 1.000 90.26000 C ? A ? 179 0 + ATOM 1309 CG2 . ILE A 179 ? -18.77200 10.90200 7.10600 1.000 90.26000 C ? A ? 179 0 + ATOM 1310 CD1 . ILE A 179 ? -18.13400 12.87000 9.49300 1.000 90.26000 C ? A ? 179 0 + ATOM 1311 N . VAL A 180 ? -20.39900 14.71400 5.50200 1.000 89.75000 N ? A ? 180 0 + ATOM 1312 CA . VAL A 180 ? -20.93000 16.06500 5.69300 1.000 89.75000 C ? A ? 180 0 + ATOM 1313 C . VAL A 180 ? -21.77900 16.06800 6.95500 1.000 89.75000 C ? A ? 180 0 + ATOM 1314 O . VAL A 180 ? -22.61200 15.18200 7.13700 1.000 89.75000 O ? A ? 180 0 + ATOM 1315 CB . VAL A 180 ? -21.71800 16.53100 4.45800 1.000 89.75000 C ? A ? 180 0 + ATOM 1316 CG1 . VAL A 180 ? -22.34200 17.91700 4.66600 1.000 89.75000 C ? A ? 180 0 + ATOM 1317 CG2 . VAL A 180 ? -20.79900 16.61400 3.23200 1.000 89.75000 C ? A ? 180 0 + ATOM 1318 N . SER A 181 ? -21.58800 17.05800 7.82100 1.000 87.20000 N ? A ? 181 0 + ATOM 1319 CA . SER A 181 ? -22.38400 17.27500 9.03100 1.000 87.20000 C ? A ? 181 0 + ATOM 1320 C . SER A 181 ? -22.98000 18.68100 9.04900 1.000 87.20000 C ? A ? 181 0 + ATOM 1321 O . SER A 181 ? -22.35600 19.63900 8.60300 1.000 87.20000 O ? A ? 181 0 + ATOM 1322 CB . SER A 181 ? -21.55200 16.98600 10.29000 1.000 87.20000 C ? A ? 181 0 + ATOM 1323 OG . SER A 181 ? -20.37100 17.76300 10.33100 1.000 87.20000 O ? A ? 181 0 + ATOM 1324 N . ALA A 182 ? -24.19200 18.83300 9.58900 1.000 81.02000 N ? A ? 182 0 + ATOM 1325 CA . ALA A 182 ? -24.82500 20.14600 9.79800 1.000 81.02000 C ? A ? 182 0 + ATOM 1326 C . ALA A 182 ? -24.31200 20.88200 11.06100 1.000 81.02000 C ? A ? 182 0 + ATOM 1327 O . ALA A 182 ? -24.80700 21.94900 11.41600 1.000 81.02000 O ? A ? 182 0 + ATOM 1328 CB . ALA A 182 ? -26.34500 19.94500 9.82600 1.000 81.02000 C ? A ? 182 0 + ATOM 1329 N . SER A 183 ? -23.35400 20.27900 11.77000 1.000 73.04000 N ? A ? 183 0 + ATOM 1330 CA . SER A 183 ? -22.70300 20.77300 12.98600 1.000 73.04000 C ? A ? 183 0 + ATOM 1331 C . SER A 183 ? -21.19000 20.59800 12.84800 1.000 73.04000 C ? A ? 183 0 + ATOM 1332 O . SER A 183 ? -20.73600 19.71600 12.11800 1.000 73.04000 O ? A ? 183 0 + ATOM 1333 CB . SER A 183 ? -23.22400 19.98700 14.19700 1.000 73.04000 C ? A ? 183 0 + ATOM 1334 OG . SER A 183 ? -22.54200 20.35700 15.38200 1.000 73.04000 O ? A ? 183 0 + ATOM 1335 N . SER A 184 ? -20.39900 21.39300 13.57200 1.000 67.24000 N ? A ? 184 0 + ATOM 1336 CA . SER A 184 ? -18.94700 21.19100 13.68300 1.000 67.24000 C ? A ? 184 0 + ATOM 1337 C . SER A 184 ? -18.57100 19.89600 14.41200 1.000 67.24000 C ? A ? 184 0 + ATOM 1338 O . SER A 184 ? -17.42700 19.45200 14.31900 1.000 67.24000 O ? A ? 184 0 + ATOM 1339 CB . SER A 184 ? -18.30600 22.38300 14.39800 1.000 67.24000 C ? A ? 184 0 + ATOM 1340 OG . SER A 184 ? -18.93500 22.61200 15.64700 1.000 67.24000 O ? A ? 184 0 + ATOM 1341 N . ASP A 185 ? -19.52100 19.28100 15.12100 1.000 68.66000 N ? A ? 185 0 + ATOM 1342 CA . ASP A 185 ? -19.33700 17.97600 15.74500 1.000 68.66000 C ? A ? 185 0 + ATOM 1343 C . ASP A 185 ? -19.49800 16.84400 14.71500 1.000 68.66000 C ? A ? 185 0 + ATOM 1344 O . ASP A 185 ? -20.60900 16.50400 14.28600 1.000 68.66000 O ? A ? 185 0 + ATOM 1345 CB . ASP A 185 ? -20.28200 17.82700 16.94200 1.000 68.66000 C ? A ? 185 0 + ATOM 1346 CG . ASP A 185 ? -20.04300 16.52400 17.71400 1.000 68.66000 C ? A ? 185 0 + ATOM 1347 OD1 . ASP A 185 ? -19.11000 15.77100 17.34300 1.000 68.66000 O ? A ? 185 0 + ATOM 1348 OD2 . ASP A 185 ? -20.82700 16.28400 18.65300 1.000 68.66000 O ? A ? 185 0 + ATOM 1349 N . LYS A 186 ? -18.36100 16.24600 14.34400 1.000 66.46000 N ? A ? 186 0 + ATOM 1350 CA . LYS A 186 ? -18.25600 15.14200 13.37800 1.000 66.46000 C ? A ? 186 0 + ATOM 1351 C . LYS A 186 ? -18.97000 13.87000 13.83900 1.000 66.46000 C ? A ? 186 0 + ATOM 1352 O . LYS A 186 ? -19.40200 13.08600 13.00000 1.000 66.46000 O ? A ? 186 0 + ATOM 1353 CB . LYS A 186 ? -16.78100 14.81100 13.12400 1.000 66.46000 C ? A ? 186 0 + ATOM 1354 CG . LYS A 186 ? -15.97800 15.99000 12.56200 1.000 66.46000 C ? A ? 186 0 + ATOM 1355 CD . LYS A 186 ? -14.54200 15.53400 12.30400 1.000 66.46000 C ? A ? 186 0 + ATOM 1356 CE . LYS A 186 ? -13.71500 16.70800 11.78900 1.000 66.46000 C ? A ? 186 0 + ATOM 1357 NZ . LYS A 186 ? -12.32100 16.28200 11.55300 1.000 66.46000 N ? A ? 186 0 + ATOM 1358 N . CYS A 187 ? -19.12400 13.68100 15.15100 1.000 69.95000 N ? A ? 187 0 + ATOM 1359 CA . CYS A 187 ? -19.84400 12.54300 15.71900 1.000 69.95000 C ? A ? 187 0 + ATOM 1360 C . CYS A 187 ? -21.34700 12.80000 15.88800 1.000 69.95000 C ? A ? 187 0 + ATOM 1361 O . CYS A 187 ? -22.06000 11.93000 16.39300 1.000 69.95000 O ? A ? 187 0 + ATOM 1362 CB . CYS A 187 ? -19.22900 12.14600 17.06600 1.000 69.95000 C ? A ? 187 0 + ATOM 1363 SG . CYS A 187 ? -17.54100 11.49300 17.09600 1.000 69.95000 S ? A ? 187 0 + ATOM 1364 N . SER A 188 ? -21.85000 13.97200 15.48700 1.000 70.41000 N ? A ? 188 0 + ATOM 1365 CA . SER A 188 ? -23.27100 14.28100 15.62200 1.000 70.41000 C ? A ? 188 0 + ATOM 1366 C . SER A 188 ? -24.14300 13.33600 14.78700 1.000 70.41000 C ? A ? 188 0 + ATOM 1367 O . SER A 188 ? -23.75200 12.83100 13.73300 1.000 70.41000 O ? A ? 188 0 + ATOM 1368 CB . SER A 188 ? -23.56100 15.75400 15.31400 1.000 70.41000 C ? A ? 188 0 + ATOM 1369 OG . SER A 188 ? -23.32600 16.07900 13.96000 1.000 70.41000 O ? A ? 188 0 + ATOM 1370 N . SER A 189 ? -25.37800 13.11300 15.23700 1.000 66.77000 N ? A ? 189 0 + ATOM 1371 CA . SER A 189 ? -26.38300 12.35800 14.47300 1.000 66.77000 C ? A ? 189 0 + ATOM 1372 C . SER A 189 ? -26.81900 13.07800 13.18700 1.000 66.77000 C ? A ? 189 0 + ATOM 1373 O . SER A 189 ? -27.42500 12.47000 12.30200 1.000 66.77000 O ? A ? 189 0 + ATOM 1374 CB . SER A 189 ? -27.60000 12.09100 15.36100 1.000 66.77000 C ? A ? 189 0 + ATOM 1375 OG . SER A 189 ? -28.07300 13.30600 15.91900 1.000 66.77000 O ? A ? 189 0 + ATOM 1376 N . LEU A 190 ? -26.49700 14.36800 13.04600 1.000 74.68000 N ? A ? 190 0 + ATOM 1377 CA . LEU A 190 ? -26.85600 15.22500 11.91400 1.000 74.68000 C ? A ? 190 0 + ATOM 1378 C . LEU A 190 ? -25.82200 15.16300 10.77900 1.000 74.68000 C ? A ? 190 0 + ATOM 1379 O . LEU A 190 ? -25.37600 16.19800 10.27600 1.000 74.68000 O ? A ? 190 0 + ATOM 1380 CB . LEU A 190 ? -27.11100 16.65900 12.40600 1.000 74.68000 C ? A ? 190 0 + ATOM 1381 CG . LEU A 190 ? -28.28800 16.81700 13.38000 1.000 74.68000 C ? A ? 190 0 + ATOM 1382 CD1 . LEU A 190 ? -28.33100 18.27000 13.85200 1.000 74.68000 C ? A ? 190 0 + ATOM 1383 CD2 . LEU A 190 ? -29.63300 16.47700 12.73400 1.000 74.68000 C ? A ? 190 0 + ATOM 1384 N . ARG A 191 ? -25.43700 13.94800 10.38300 1.000 82.69000 N ? A ? 191 0 + ATOM 1385 CA . ARG A 191 ? -24.43600 13.69800 9.33800 1.000 82.69000 C ? A ? 191 0 + ATOM 1386 C . ARG A 191 ? -24.94400 12.80200 8.21400 1.000 82.69000 C ? A ? 191 0 + ATOM 1387 O . ARG A 191 ? -25.97600 12.13800 8.35100 1.000 82.69000 O ? A ? 191 0 + ATOM 1388 CB . ARG A 191 ? -23.13900 13.17000 9.96800 1.000 82.69000 C ? A ? 191 0 + ATOM 1389 CG . ARG A 191 ? -23.30900 11.75400 10.52100 1.000 82.69000 C ? A ? 191 0 + ATOM 1390 CD . ARG A 191 ? -22.03600 11.31400 11.23200 1.000 82.69000 C ? A ? 191 0 + ATOM 1391 NE . ARG A 191 ? -22.26900 10.00500 11.84100 1.000 82.69000 N ? A ? 191 0 + ATOM 1392 CZ . ARG A 191 ? -21.91600 8.83700 11.35500 1.000 82.69000 C ? A ? 191 0 + ATOM 1393 NH1 . ARG A 191 ? -21.25700 8.68400 10.24200 1.000 82.69000 N ? A ? 191 0 + ATOM 1394 NH2 . ARG A 191 ? -22.22900 7.77500 12.03200 1.000 82.69000 N ? A ? 191 0 + ATOM 1395 N . SER A 192 ? -24.20800 12.80900 7.10800 1.000 86.92000 N ? A ? 192 0 + ATOM 1396 CA . SER A 192 ? -24.40300 11.91100 5.97400 1.000 86.92000 C ? A ? 192 0 + ATOM 1397 C . SER A 192 ? -23.79300 10.53100 6.22700 1.000 86.92000 C ? A ? 192 0 + ATOM 1398 O . SER A 192 ? -22.90800 10.39300 7.07800 1.000 86.92000 O ? A ? 192 0 + ATOM 1399 CB . SER A 192 ? -23.78600 12.52400 4.71400 1.000 86.92000 C ? A ? 192 0 + ATOM 1400 OG . SER A 192 ? -22.36700 12.54100 4.77200 1.000 86.92000 O ? A ? 192 0 + ATOM 1401 N . PRO A 193 ? -24.19500 9.51200 5.44800 1.000 84.85000 N ? A ? 193 0 + ATOM 1402 CA . PRO A 193 ? -23.41200 8.29000 5.32500 1.000 84.85000 C ? A ? 193 0 + ATOM 1403 C . PRO A 193 ? -21.97800 8.61000 4.87100 1.000 84.85000 C ? A ? 193 0 + ATOM 1404 O . PRO A 193 ? -21.79400 9.58100 4.12300 1.000 84.85000 O ? A ? 193 0 + ATOM 1405 CB . PRO A 193 ? -24.16100 7.41300 4.31600 1.000 84.85000 C ? A ? 193 0 + ATOM 1406 CG . PRO A 193 ? -25.59300 7.95000 4.36000 1.000 84.85000 C ? A ? 193 0 + ATOM 1407 CD . PRO A 193 ? -25.39600 9.43800 4.63200 1.000 84.85000 C ? A ? 193 0 + ATOM 1408 N . PRO A 194 ? -20.97700 7.82700 5.31000 1.000 88.88000 N ? A ? 194 0 + ATOM 1409 CA . PRO A 194 ? -19.61200 7.95800 4.81900 1.000 88.88000 C ? A ? 194 0 + ATOM 1410 C . PRO A 194 ? -19.55200 7.64300 3.32400 1.000 88.88000 C ? A ? 194 0 + ATOM 1411 O . PRO A 194 ? -20.19100 6.70300 2.84400 1.000 88.88000 O ? A ? 194 0 + ATOM 1412 CB . PRO A 194 ? -18.76900 6.98900 5.65100 1.000 88.88000 C ? A ? 194 0 + ATOM 1413 CG . PRO A 194 ? -19.77700 5.90600 6.01900 1.000 88.88000 C ? A ? 194 0 + ATOM 1414 CD . PRO A 194 ? -21.07400 6.69000 6.21100 1.000 88.88000 C ? A ? 194 0 + ATOM 1415 N . PHE A 195 ? -18.78700 8.44500 2.59300 1.000 90.78000 N ? A ? 195 0 + ATOM 1416 CA . PHE A 195 ? -18.50500 8.25900 1.17700 1.000 90.78000 C ? A ? 195 0 + ATOM 1417 C . PHE A 195 ? -17.01800 7.97400 0.98900 1.000 90.78000 C ? A ? 195 0 + ATOM 1418 O . PHE A 195 ? -16.17400 8.80000 1.33300 1.000 90.78000 O ? A ? 195 0 + ATOM 1419 CB . PHE A 195 ? -18.95800 9.49500 0.39600 1.000 90.78000 C ? A ? 195 0 + ATOM 1420 CG . PHE A 195 ? -18.83200 9.34600 -1.10600 1.000 90.78000 C ? A ? 195 0 + ATOM 1421 CD1 . PHE A 195 ? -17.62000 9.65300 -1.75500 1.000 90.78000 C ? A ? 195 0 + ATOM 1422 CD2 . PHE A 195 ? -19.92700 8.88200 -1.85700 1.000 90.78000 C ? A ? 195 0 + ATOM 1423 CE1 . PHE A 195 ? -17.51100 9.49500 -3.14800 1.000 90.78000 C ? A ? 195 0 + ATOM 1424 CE2 . PHE A 195 ? -19.81400 8.72000 -3.24800 1.000 90.78000 C ? A ? 195 0 + ATOM 1425 CZ . PHE A 195 ? -18.60400 9.02500 -3.89400 1.000 90.78000 C ? A ? 195 0 + ATOM 1426 N . GLU A 196 ? -16.70700 6.81300 0.42300 1.000 90.83000 N ? A ? 196 0 + ATOM 1427 CA . GLU A 196 ? -15.33600 6.37800 0.16900 1.000 90.83000 C ? A ? 196 0 + ATOM 1428 C . GLU A 196 ? -14.87900 6.78200 -1.23200 1.000 90.83000 C ? A ? 196 0 + ATOM 1429 O . GLU A 196 ? -15.58700 6.56900 -2.22000 1.000 90.83000 O ? A ? 196 0 + ATOM 1430 CB . GLU A 196 ? -15.23000 4.85600 0.32800 1.000 90.83000 C ? A ? 196 0 + ATOM 1431 CG . GLU A 196 ? -15.54200 4.35500 1.74500 1.000 90.83000 C ? A ? 196 0 + ATOM 1432 CD . GLU A 196 ? -14.63400 4.97700 2.80800 1.000 90.83000 C ? A ? 196 0 + ATOM 1433 OE1 . GLU A 196 ? -15.17000 5.42300 3.84000 1.000 90.83000 O ? A ? 196 0 + ATOM 1434 OE2 . GLU A 196 ? -13.40400 5.02200 2.60400 1.000 90.83000 O ? A ? 196 0 + ATOM 1435 N . MET A 197 ? -13.66300 7.31300 -1.33500 1.000 90.26000 N ? A ? 197 0 + ATOM 1436 CA . MET A 197 ? -13.01300 7.56000 -2.61900 1.000 90.26000 C ? A ? 197 0 + ATOM 1437 C . MET A 197 ? -11.50000 7.39500 -2.54500 1.000 90.26000 C ? A ? 197 0 + ATOM 1438 O . MET A 197 ? -10.88700 7.52000 -1.49000 1.000 90.26000 O ? A ? 197 0 + ATOM 1439 CB . MET A 197 ? -13.36900 8.95200 -3.14900 1.000 90.26000 C ? A ? 197 0 + ATOM 1440 CG . MET A 197 ? -12.83600 10.09500 -2.27500 1.000 90.26000 C ? A ? 197 0 + ATOM 1441 SD . MET A 197 ? -12.77900 11.68400 -3.13200 1.000 90.26000 S ? A ? 197 0 + ATOM 1442 CE . MET A 197 ? -14.50400 11.77600 -3.60600 1.000 90.26000 C ? A ? 197 0 + ATOM 1443 N . SER A 198 ? -10.88100 7.17700 -3.70200 1.000 91.54000 N ? A ? 198 0 + ATOM 1444 CA . SER A 198 ? -9.42600 7.20000 -3.84900 1.000 91.54000 C ? A ? 198 0 + ATOM 1445 C . SER A 198 ? -8.99900 8.36100 -4.73600 1.000 91.54000 C ? A ? 198 0 + ATOM 1446 O . SER A 198 ? -9.62200 8.60800 -5.77000 1.000 91.54000 O ? A ? 198 0 + ATOM 1447 CB . SER A 198 ? -8.92300 5.88700 -4.44100 1.000 91.54000 C ? A ? 198 0 + ATOM 1448 OG . SER A 198 ? -9.23200 4.80500 -3.58700 1.000 91.54000 O ? A ? 198 0 + ATOM 1449 N . THR A 199 ? -7.91800 9.04300 -4.36400 1.000 91.35000 N ? A ? 199 0 + ATOM 1450 CA . THR A 199 ? -7.26100 10.00900 -5.25100 1.000 91.35000 C ? A ? 199 0 + ATOM 1451 C . THR A 199 ? -6.42600 9.29000 -6.31200 1.000 91.35000 C ? A ? 199 0 + ATOM 1452 O . THR A 199 ? -6.25400 8.06700 -6.28400 1.000 91.35000 O ? A ? 199 0 + ATOM 1453 CB . THR A 199 ? -6.42500 11.03500 -4.46800 1.000 91.35000 C ? A ? 199 0 + ATOM 1454 OG1 . THR A 199 ? -5.39000 10.43900 -3.72300 1.000 91.35000 O ? A ? 199 0 + ATOM 1455 CG2 . THR A 199 ? -7.29000 11.82400 -3.48900 1.000 91.35000 C ? A ? 199 0 + ATOM 1456 N . ALA A 200 ? -5.90100 10.03500 -7.28800 1.000 92.36000 N ? A ? 200 0 + ATOM 1457 CA . ALA A 200 ? -4.97000 9.46500 -8.25300 1.000 92.36000 C ? A ? 200 0 + ATOM 1458 C . ALA A 200 ? -3.71300 8.91800 -7.54500 1.000 92.36000 C ? A ? 200 0 + ATOM 1459 O . ALA A 200 ? -3.26000 9.51000 -6.55700 1.000 92.36000 O ? A ? 200 0 + ATOM 1460 CB . ALA A 200 ? -4.59600 10.52600 -9.28600 1.000 92.36000 C ? A ? 200 0 + ATOM 1461 N . PRO A 201 ? -3.10500 7.82700 -8.04300 1.000 94.47000 N ? A ? 201 0 + ATOM 1462 CA . PRO A 201 ? -1.85100 7.33000 -7.49700 1.000 94.47000 C ? A ? 201 0 + ATOM 1463 C . PRO A 201 ? -0.75300 8.39200 -7.53000 1.000 94.47000 C ? A ? 201 0 + ATOM 1464 O . PRO A 201 ? -0.68100 9.21100 -8.45000 1.000 94.47000 O ? A ? 201 0 + ATOM 1465 CB . PRO A 201 ? -1.45900 6.13900 -8.36700 1.000 94.47000 C ? A ? 201 0 + ATOM 1466 CG . PRO A 201 ? -2.78700 5.66800 -8.94600 1.000 94.47000 C ? A ? 201 0 + ATOM 1467 CD . PRO A 201 ? -3.55800 6.97200 -9.12800 1.000 94.47000 C ? A ? 201 0 + ATOM 1468 N . CYS A 202 ? 0.15500 8.34700 -6.55800 1.000 93.84000 N ? A ? 202 0 + ATOM 1469 CA . CYS A 202 ? 1.36400 9.15600 -6.63600 1.000 93.84000 C ? A ? 202 0 + ATOM 1470 C . CYS A 202 ? 2.28300 8.67300 -7.76100 1.000 93.84000 C ? A ? 202 0 + ATOM 1471 O . CYS A 202 ? 2.32500 7.48400 -8.09400 1.000 93.84000 O ? A ? 202 0 + ATOM 1472 CB . CYS A 202 ? 2.09500 9.17300 -5.29400 1.000 93.84000 C ? A ? 202 0 + ATOM 1473 SG . CYS A 202 ? 1.20400 9.98500 -3.94800 1.000 93.84000 S ? A ? 202 0 + ATOM 1474 N . VAL A 203 ? 3.05800 9.61200 -8.30600 1.000 94.50000 N ? A ? 203 0 + ATOM 1475 CA . VAL A 203 ? 4.10300 9.33600 -9.29700 1.000 94.50000 C ? A ? 203 0 + ATOM 1476 C . VAL A 203 ? 5.05700 8.27000 -8.74200 1.000 94.50000 C ? A ? 203 0 + ATOM 1477 O . VAL A 203 ? 5.60700 8.49400 -7.65800 1.000 94.50000 O ? A ? 203 0 + ATOM 1478 CB . VAL A 203 ? 4.89300 10.61600 -9.61800 1.000 94.50000 C ? A ? 203 0 + ATOM 1479 CG1 . VAL A 203 ? 5.95200 10.34500 -10.68300 1.000 94.50000 C ? A ? 203 0 + ATOM 1480 CG2 . VAL A 203 ? 3.97700 11.72600 -10.14300 1.000 94.50000 C ? A ? 203 0 + ATOM 1481 N . PRO A 204 ? 5.27700 7.14200 -9.44400 1.000 95.53000 N ? A ? 204 0 + ATOM 1482 CA . PRO A 204 ? 6.18900 6.10400 -8.97300 1.000 95.53000 C ? A ? 204 0 + ATOM 1483 C . PRO A 204 ? 7.60100 6.65000 -8.72900 1.000 95.53000 C ? A ? 204 0 + ATOM 1484 O . PRO A 204 ? 8.10200 7.47300 -9.49700 1.000 95.53000 O ? A ? 204 0 + ATOM 1485 CB . PRO A 204 ? 6.18700 5.01100 -10.04200 1.000 95.53000 C ? A ? 204 0 + ATOM 1486 CG . PRO A 204 ? 4.85200 5.21500 -10.75400 1.000 95.53000 C ? A ? 204 0 + ATOM 1487 CD . PRO A 204 ? 4.61800 6.72000 -10.67400 1.000 95.53000 C ? A ? 204 0 + ATOM 1488 N . GLN A 205 ? 8.23800 6.18100 -7.65600 1.000 94.67000 N ? A ? 205 0 + ATOM 1489 CA . GLN A 205 ? 9.56500 6.62400 -7.21200 1.000 94.67000 C ? A ? 205 0 + ATOM 1490 C . GLN A 205 ? 10.57100 5.46700 -7.22300 1.000 94.67000 C ? A ? 205 0 + ATOM 1491 O . GLN A 205 ? 10.18700 4.29700 -7.29600 1.000 94.67000 O ? A ? 205 0 + ATOM 1492 CB . GLN A 205 ? 9.47200 7.24700 -5.80500 1.000 94.67000 C ? A ? 205 0 + ATOM 1493 CG . GLN A 205 ? 8.54900 8.47200 -5.71600 1.000 94.67000 C ? A ? 205 0 + ATOM 1494 CD . GLN A 205 ? 8.97100 9.61500 -6.63400 1.000 94.67000 C ? A ? 205 0 + ATOM 1495 OE1 . GLN A 205 ? 10.12600 10.00100 -6.70200 1.000 94.67000 O ? A ? 205 0 + ATOM 1496 NE2 . GLN A 205 ? 8.05200 10.18400 -7.37900 1.000 94.67000 N ? A ? 205 0 + ATOM 1497 N . ASN A 206 ? 11.86100 5.79900 -7.09200 1.000 94.81000 N ? A ? 206 0 + ATOM 1498 CA . ASN A 206 ? 12.97400 4.84300 -7.01400 1.000 94.81000 C ? A ? 206 0 + ATOM 1499 C . ASN A 206 ? 12.98200 3.84400 -8.17900 1.000 94.81000 C ? A ? 206 0 + ATOM 1500 O . ASN A 206 ? 13.01200 2.63200 -7.96900 1.000 94.81000 O ? A ? 206 0 + ATOM 1501 CB . ASN A 206 ? 12.98500 4.15200 -5.64000 1.000 94.81000 C ? A ? 206 0 + ATOM 1502 CG . ASN A 206 ? 13.01000 5.12100 -4.48100 1.000 94.81000 C ? A ? 206 0 + ATOM 1503 OD1 . ASN A 206 ? 13.72000 6.11000 -4.48600 1.000 94.81000 O ? A ? 206 0 + ATOM 1504 ND2 . ASN A 206 ? 12.22500 4.88000 -3.45800 1.000 94.81000 N ? A ? 206 0 + ATOM 1505 N . VAL A 207 ? 12.90500 4.35800 -9.40800 1.000 95.64000 N ? A ? 207 0 + ATOM 1506 CA . VAL A 207 ? 12.98700 3.53000 -10.61300 1.000 95.64000 C ? A ? 207 0 + ATOM 1507 C . VAL A 207 ? 14.41700 3.00500 -10.75800 1.000 95.64000 C ? A ? 207 0 + ATOM 1508 O . VAL A 207 ? 15.35900 3.78100 -10.89900 1.000 95.64000 O ? A ? 207 0 + ATOM 1509 CB . VAL A 207 ? 12.53700 4.29700 -11.87000 1.000 95.64000 C ? A ? 207 0 + ATOM 1510 CG1 . VAL A 207 ? 12.57300 3.39600 -13.11200 1.000 95.64000 C ? A ? 207 0 + ATOM 1511 CG2 . VAL A 207 ? 11.10800 4.83900 -11.72400 1.000 95.64000 C ? A ? 207 0 + ATOM 1512 N . VAL A 208 ? 14.57000 1.68400 -10.72600 1.000 96.20000 N ? A ? 208 0 + ATOM 1513 CA . VAL A 208 ? 15.83600 0.96600 -10.90900 1.000 96.20000 C ? A ? 208 0 + ATOM 1514 C . VAL A 208 ? 15.75800 0.17100 -12.20400 1.000 96.20000 C ? A ? 208 0 + ATOM 1515 O . VAL A 208 ? 14.78700 -0.55600 -12.42400 1.000 96.20000 O ? A ? 208 0 + ATOM 1516 CB . VAL A 208 ? 16.13400 0.03800 -9.71700 1.000 96.20000 C ? A ? 208 0 + ATOM 1517 CG1 . VAL A 208 ? 17.46200 -0.70900 -9.90000 1.000 96.20000 C ? A ? 208 0 + ATOM 1518 CG2 . VAL A 208 ? 16.21000 0.81800 -8.40000 1.000 96.20000 C ? A ? 208 0 + ATOM 1519 N . LEU A 209 ? 16.78500 0.29900 -13.04400 1.000 95.76000 N ? A ? 209 0 + ATOM 1520 CA . LEU A 209 ? 16.87400 -0.34800 -14.35000 1.000 95.76000 C ? A ? 209 0 + ATOM 1521 C . LEU A 209 ? 18.06500 -1.30900 -14.36700 1.000 95.76000 C ? A ? 209 0 + ATOM 1522 O . LEU A 209 ? 19.20000 -0.89000 -14.14900 1.000 95.76000 O ? A ? 209 0 + ATOM 1523 CB . LEU A 209 ? 17.00800 0.71600 -15.45600 1.000 95.76000 C ? A ? 209 0 + ATOM 1524 CG . LEU A 209 ? 15.93500 1.82000 -15.44700 1.000 95.76000 C ? A ? 209 0 + ATOM 1525 CD1 . LEU A 209 ? 16.19300 2.79300 -16.58700 1.000 95.76000 C ? A ? 209 0 + ATOM 1526 CD2 . LEU A 209 ? 14.52600 1.26200 -15.63900 1.000 95.76000 C ? A ? 209 0 + ATOM 1527 N . ASN A 210 ? 17.80500 -2.58000 -14.66100 1.000 94.22000 N ? A ? 210 0 + ATOM 1528 CA . ASN A 210 ? 18.81400 -3.63000 -14.76700 1.000 94.22000 C ? A ? 210 0 + ATOM 1529 C . ASN A 210 ? 18.85700 -4.17200 -16.19700 1.000 94.22000 C ? A ? 210 0 + ATOM 1530 O . ASN A 210 ? 17.81500 -4.37000 -16.82100 1.000 94.22000 O ? A ? 210 0 + ATOM 1531 CB . ASN A 210 ? 18.49800 -4.74200 -13.75400 1.000 94.22000 C ? A ? 210 0 + ATOM 1532 CG . ASN A 210 ? 18.66200 -4.31300 -12.30600 1.000 94.22000 C ? A ? 210 0 + ATOM 1533 OD1 . ASN A 210 ? 19.31200 -3.34400 -11.96400 1.000 94.22000 O ? A ? 210 0 + ATOM 1534 ND2 . ASN A 210 ? 18.09000 -5.05100 -11.38500 1.000 94.22000 N ? A ? 210 0 + ATOM 1535 N . SER A 211 ? 20.05000 -4.45100 -16.71700 1.000 92.94000 N ? A ? 211 0 + ATOM 1536 CA . SER A 211 ? 20.20900 -5.06200 -18.03700 1.000 92.94000 C ? A ? 211 0 + ATOM 1537 C . SER A 211 ? 19.84600 -6.54900 -18.02300 1.000 92.94000 C ? A ? 211 0 + ATOM 1538 O . SER A 211 ? 20.15100 -7.27800 -17.08000 1.000 92.94000 O ? A ? 211 0 + ATOM 1539 CB . SER A 211 ? 21.63200 -4.84100 -18.56400 1.000 92.94000 C ? A ? 211 0 + ATOM 1540 OG . SER A 211 ? 22.59600 -5.24500 -17.60900 1.000 92.94000 O ? A ? 211 0 + ATOM 1541 N . MET A 212 ? 19.20200 -7.01300 -19.09600 1.000 91.28000 N ? A ? 212 0 + ATOM 1542 CA . MET A 212 ? 18.91400 -8.42700 -19.34400 1.000 91.28000 C ? A ? 212 0 + ATOM 1543 C . MET A 212 ? 19.64700 -8.87300 -20.60700 1.000 91.28000 C ? A ? 212 0 + ATOM 1544 O . MET A 212 ? 19.11300 -8.77500 -21.71500 1.000 91.28000 O ? A ? 212 0 + ATOM 1545 CB . MET A 212 ? 17.40700 -8.66500 -19.48400 1.000 91.28000 C ? A ? 212 0 + ATOM 1546 CG . MET A 212 ? 16.61400 -8.35100 -18.21400 1.000 91.28000 C ? A ? 212 0 + ATOM 1547 SD . MET A 212 ? 14.86600 -8.83200 -18.31400 1.000 91.28000 S ? A ? 212 0 + ATOM 1548 CE . MET A 212 ? 14.36800 -7.95600 -19.82200 1.000 91.28000 C ? A ? 212 0 + ATOM 1549 N . CYS A 213 ? 20.87400 -9.36300 -20.43600 1.000 84.27000 N ? A ? 213 0 + ATOM 1550 CA . CYS A 213 ? 21.75600 -9.73200 -21.54500 1.000 84.27000 C ? A ? 213 0 + ATOM 1551 C . CYS A 213 ? 21.15500 -10.81800 -22.45100 1.000 84.27000 C ? A ? 213 0 + ATOM 1552 O . CYS A 213 ? 21.28000 -10.72200 -23.66600 1.000 84.27000 O ? A ? 213 0 + ATOM 1553 CB . CYS A 213 ? 23.10800 -10.17800 -20.97400 1.000 84.27000 C ? A ? 213 0 + ATOM 1554 SG . CYS A 213 ? 23.86100 -8.82600 -20.01700 1.000 84.27000 S ? A ? 213 0 + ATOM 1555 N . ASP A 214 ? 20.43500 -11.79200 -21.88800 1.000 84.71000 N ? A ? 214 0 + ATOM 1556 CA . ASP A 214 ? 19.87700 -12.91700 -22.65600 1.000 84.71000 C ? A ? 214 0 + ATOM 1557 C . ASP A 214 ? 18.80500 -12.49500 -23.67500 1.000 84.71000 C ? A ? 214 0 + ATOM 1558 O . ASP A 214 ? 18.57800 -13.18300 -24.66700 1.000 84.71000 O ? A ? 214 0 + ATOM 1559 CB . ASP A 214 ? 19.26600 -13.94200 -21.68700 1.000 84.71000 C ? A ? 214 0 + ATOM 1560 CG . ASP A 214 ? 20.27400 -14.52100 -20.69200 1.000 84.71000 C ? A ? 214 0 + ATOM 1561 OD1 . ASP A 214 ? 21.46700 -14.62400 -21.05000 1.000 84.71000 O ? A ? 214 0 + ATOM 1562 OD2 . ASP A 214 ? 19.84100 -14.80600 -19.55500 1.000 84.71000 O ? A ? 214 0 + ATOM 1563 N . SER A 215 ? 18.13600 -11.36300 -23.43800 1.000 86.87000 N ? A ? 215 0 + ATOM 1564 CA . SER A 215 ? 17.03000 -10.86700 -24.27300 1.000 86.87000 C ? A ? 215 0 + ATOM 1565 C . SER A 215 ? 17.33300 -9.53800 -24.96700 1.000 86.87000 C ? A ? 215 0 + ATOM 1566 O . SER A 215 ? 16.43700 -8.95600 -25.58300 1.000 86.87000 O ? A ? 215 0 + ATOM 1567 CB . SER A 215 ? 15.73900 -10.78200 -23.45100 1.000 86.87000 C ? A ? 215 0 + ATOM 1568 OG . SER A 215 ? 15.88900 -9.88400 -22.36800 1.000 86.87000 O ? A ? 215 0 + ATOM 1569 N . ASN A 216 ? 18.57500 -9.04200 -24.85700 1.000 88.00000 N ? A ? 216 0 + ATOM 1570 CA . ASN A 216 ? 18.95900 -7.68400 -25.25900 1.000 88.00000 C ? A ? 216 0 + ATOM 1571 C . ASN A 216 ? 17.97200 -6.63300 -24.72000 1.000 88.00000 C ? A ? 216 0 + ATOM 1572 O . ASN A 216 ? 17.51600 -5.75300 -25.44400 1.000 88.00000 O ? A ? 216 0 + ATOM 1573 CB . ASN A 216 ? 19.15600 -7.62700 -26.78300 1.000 88.00000 C ? A ? 216 0 + ATOM 1574 CG . ASN A 216 ? 20.26100 -8.54900 -27.25100 1.000 88.00000 C ? A ? 216 0 + ATOM 1575 OD1 . ASN A 216 ? 21.29600 -8.69200 -26.62500 1.000 88.00000 O ? A ? 216 0 + ATOM 1576 ND2 . ASN A 216 ? 20.08900 -9.19900 -28.37700 1.000 88.00000 N ? A ? 216 0 + ATOM 1577 N . GLY A 217 ? 17.56900 -6.78700 -23.46000 1.000 92.79000 N ? A ? 217 0 + ATOM 1578 CA . GLY A 217 ? 16.48100 -6.02500 -22.86100 1.000 92.79000 C ? A ? 217 0 + ATOM 1579 C . GLY A 217 ? 16.86100 -5.34800 -21.55500 1.000 92.79000 C ? A ? 217 0 + ATOM 1580 O . GLY A 217 ? 18.01400 -5.37400 -21.11400 1.000 92.79000 O ? A ? 217 0 + ATOM 1581 N . MET A 218 ? 15.85200 -4.78900 -20.89500 1.000 94.65000 N ? A ? 218 0 + ATOM 1582 CA . MET A 218 ? 15.96000 -4.27600 -19.53400 1.000 94.65000 C ? A ? 218 0 + ATOM 1583 C . MET A 218 ? 14.81800 -4.76200 -18.64200 1.000 94.65000 C ? A ? 218 0 + ATOM 1584 O . MET A 218 ? 13.69000 -4.96900 -19.09100 1.000 94.65000 O ? A ? 218 0 + ATOM 1585 CB . MET A 218 ? 16.06400 -2.74700 -19.54000 1.000 94.65000 C ? A ? 218 0 + ATOM 1586 CG . MET A 218 ? 14.74200 -2.05200 -19.86100 1.000 94.65000 C ? A ? 218 0 + ATOM 1587 SD . MET A 218 ? 14.87600 -0.25500 -19.84100 1.000 94.65000 S ? A ? 218 0 + ATOM 1588 CE . MET A 218 ? 13.20600 0.09000 -20.41000 1.000 94.65000 C ? A ? 218 0 + ATOM 1589 N . MET A 219 ? 15.11400 -4.89900 -17.35600 1.000 95.36000 N ? A ? 219 0 + ATOM 1590 CA . MET A 219 ? 14.13700 -5.07600 -16.29400 1.000 95.36000 C ? A ? 219 0 + ATOM 1591 C . MET A 219 ? 14.08700 -3.79800 -15.46800 1.000 95.36000 C ? A ? 219 0 + ATOM 1592 O . MET A 219 ? 15.08800 -3.39000 -14.88200 1.000 95.36000 O ? A ? 219 0 + ATOM 1593 CB . MET A 219 ? 14.51300 -6.28700 -15.43600 1.000 95.36000 C ? A ? 219 0 + ATOM 1594 CG . MET A 219 ? 13.46700 -6.55200 -14.34800 1.000 95.36000 C ? A ? 219 0 + ATOM 1595 SD . MET A 219 ? 13.79300 -8.03000 -13.34900 1.000 95.36000 S ? A ? 219 0 + ATOM 1596 CE . MET A 219 ? 13.43100 -9.34000 -14.55200 1.000 95.36000 C ? A ? 219 0 + ATOM 1597 N . ALA A 220 ? 12.91400 -3.18700 -15.40500 1.000 96.83000 N ? A ? 220 0 + ATOM 1598 CA . ALA A 220 ? 12.65600 -2.04300 -14.55600 1.000 96.83000 C ? A ? 220 0 + ATOM 1599 C . ALA A 220 ? 11.90300 -2.47500 -13.29900 1.000 96.83000 C ? A ? 220 0 + ATOM 1600 O . ALA A 220 ? 11.01800 -3.33200 -13.35500 1.000 96.83000 O ? A ? 220 0 + ATOM 1601 CB . ALA A 220 ? 11.87300 -1.01800 -15.35900 1.000 96.83000 C ? A ? 220 0 + ATOM 1602 N . SER A 221 ? 12.23000 -1.85000 -12.17400 1.000 97.30000 N ? A ? 221 0 + ATOM 1603 CA . SER A 221 ? 11.52200 -2.00400 -10.90300 1.000 97.30000 C ? A ? 221 0 + ATOM 1604 C . SER A 221 ? 11.37600 -0.65400 -10.20900 1.000 97.30000 C ? A ? 221 0 + ATOM 1605 O . SER A 221 ? 12.17700 0.24600 -10.44700 1.000 97.30000 O ? A ? 221 0 + ATOM 1606 CB . SER A 221 ? 12.23200 -3.02700 -10.01500 1.000 97.30000 C ? A ? 221 0 + ATOM 1607 OG . SER A 221 ? 13.53700 -2.59800 -9.68500 1.000 97.30000 O ? A ? 221 0 + ATOM 1608 N . TRP A 222 ? 10.33700 -0.48300 -9.39600 1.000 96.10000 N ? A ? 222 0 + ATOM 1609 CA . TRP A 222 ? 10.02300 0.78900 -8.73400 1.000 96.10000 C ? A ? 222 0 + ATOM 1610 C . TRP A 222 ? 9.34200 0.56600 -7.38300 1.000 96.10000 C ? A ? 222 0 + ATOM 1611 O . TRP A 222 ? 8.81200 -0.50900 -7.09200 1.000 96.10000 O ? A ? 222 0 + ATOM 1612 CB . TRP A 222 ? 9.13800 1.64500 -9.65000 1.000 96.10000 C ? A ? 222 0 + ATOM 1613 CG . TRP A 222 ? 7.91600 0.94700 -10.16000 1.000 96.10000 C ? A ? 222 0 + ATOM 1614 CD1 . TRP A 222 ? 6.68900 0.95700 -9.59000 1.000 96.10000 C ? A ? 222 0 + ATOM 1615 CD2 . TRP A 222 ? 7.79800 0.11600 -11.35300 1.000 96.10000 C ? A ? 222 0 + ATOM 1616 NE1 . TRP A 222 ? 5.82700 0.17500 -10.33200 1.000 96.10000 N ? A ? 222 0 + ATOM 1617 CE2 . TRP A 222 ? 6.46000 -0.37300 -11.42300 1.000 96.10000 C ? A ? 222 0 + ATOM 1618 CE3 . TRP A 222 ? 8.67300 -0.23500 -12.40600 1.000 96.10000 C ? A ? 222 0 + ATOM 1619 CZ2 . TRP A 222 ? 6.01500 -1.18600 -12.46900 1.000 96.10000 C ? A ? 222 0 + ATOM 1620 CZ3 . TRP A 222 ? 8.22700 -1.03000 -13.47800 1.000 96.10000 C ? A ? 222 0 + ATOM 1621 CH2 . TRP A 222 ? 6.90000 -1.50000 -13.51000 1.000 96.10000 C ? A ? 222 0 + ATOM 1622 N . SER A 223 ? 9.32700 1.60300 -6.54600 1.000 95.88000 N ? A ? 223 0 + ATOM 1623 CA . SER A 223 ? 8.59100 1.56800 -5.27800 1.000 95.88000 C ? A ? 223 0 + ATOM 1624 C . SER A 223 ? 7.07100 1.56100 -5.51000 1.000 95.88000 C ? A ? 223 0 + ATOM 1625 O . SER A 223 ? 6.60300 2.23200 -6.43100 1.000 95.88000 O ? A ? 223 0 + ATOM 1626 CB . SER A 223 ? 8.97800 2.75300 -4.39800 1.000 95.88000 C ? A ? 223 0 + ATOM 1627 OG . SER A 223 ? 10.33800 2.61400 -4.03700 1.000 95.88000 O ? A ? 223 0 + ATOM 1628 N . PRO A 224 ? 6.28000 0.84000 -4.69300 1.000 93.58000 N ? A ? 224 0 + ATOM 1629 CA . PRO A 224 ? 4.82200 0.85700 -4.79800 1.000 93.58000 C ? A ? 224 0 + ATOM 1630 C . PRO A 224 ? 4.21700 2.24900 -4.63800 1.000 93.58000 C ? A ? 224 0 + ATOM 1631 O . PRO A 224 ? 4.50100 2.95100 -3.67000 1.000 93.58000 O ? A ? 224 0 + ATOM 1632 CB . PRO A 224 ? 4.30600 -0.12400 -3.73500 1.000 93.58000 C ? A ? 224 0 + ATOM 1633 CG . PRO A 224 ? 5.50600 -1.01100 -3.40200 1.000 93.58000 C ? A ? 224 0 + ATOM 1634 CD . PRO A 224 ? 6.71100 -0.11900 -3.68400 1.000 93.58000 C ? A ? 224 0 + ATOM 1635 N . SER A 225 ? 3.33200 2.61100 -5.56700 1.000 92.93000 N ? A ? 225 0 + ATOM 1636 CA . SER A 225 ? 2.43200 3.75200 -5.42700 1.000 92.93000 C ? A ? 225 0 + ATOM 1637 C . SER A 225 ? 1.14700 3.28900 -4.74400 1.000 92.93000 C ? A ? 225 0 + ATOM 1638 O . SER A 225 ? 0.48600 2.36600 -5.22200 1.000 92.93000 O ? A ? 225 0 + ATOM 1639 CB . SER A 225 ? 2.11100 4.37400 -6.79100 1.000 92.93000 C ? A ? 225 0 + ATOM 1640 OG . SER A 225 ? 3.25700 4.97600 -7.36200 1.000 92.93000 O ? A ? 225 0 + ATOM 1641 N . LEU A 226 ? 0.77400 3.93300 -3.63500 1.000 89.63000 N ? A ? 226 0 + ATOM 1642 CA . LEU A 226 ? -0.49900 3.66600 -2.96000 1.000 89.63000 C ? A ? 226 0 + ATOM 1643 C . LEU A 226 ? -1.67800 3.86900 -3.92400 1.000 89.63000 C ? A ? 226 0 + ATOM 1644 O . LEU A 226 ? -1.60200 4.69400 -4.83600 1.000 89.63000 O ? A ? 226 0 + ATOM 1645 CB . LEU A 226 ? -0.63900 4.55800 -1.71700 1.000 89.63000 C ? A ? 226 0 + ATOM 1646 CG . LEU A 226 ? 0.32500 4.22600 -0.56500 1.000 89.63000 C ? A ? 226 0 + ATOM 1647 CD1 . LEU A 226 ? 0.23400 5.30800 0.51000 1.000 89.63000 C ? A ? 226 0 + ATOM 1648 CD2 . LEU A 226 ? 0.00100 2.87400 0.07800 1.000 89.63000 C ? A ? 226 0 + ATOM 1649 N . VAL A 227 ? -2.73400 3.07400 -3.72400 1.000 90.07000 N ? A ? 227 0 + ATOM 1650 CA . VAL A 227 ? -3.95700 2.95500 -4.54500 1.000 90.07000 C ? A ? 227 0 + ATOM 1651 C . VAL A 227 ? -3.75900 2.58500 -6.02500 1.000 90.07000 C ? A ? 227 0 + ATOM 1652 O . VAL A 227 ? -4.74400 2.39400 -6.73200 1.000 90.07000 O ? A ? 227 0 + ATOM 1653 CB . VAL A 227 ? -4.93600 4.13900 -4.36100 1.000 90.07000 C ? A ? 227 0 + ATOM 1654 CG1 . VAL A 227 ? -5.16500 4.49600 -2.88600 1.000 90.07000 C ? A ? 227 0 + ATOM 1655 CG2 . VAL A 227 ? -4.55200 5.42000 -5.10300 1.000 90.07000 C ? A ? 227 0 + ATOM 1656 N . ALA A 228 ? -2.52500 2.43900 -6.52100 1.000 93.16000 N ? A ? 228 0 + ATOM 1657 CA . ALA A 228 ? -2.27300 2.03600 -7.90200 1.000 93.16000 C ? A ? 228 0 + ATOM 1658 C . ALA A 228 ? -2.71700 0.58700 -8.15400 1.000 93.16000 C ? A ? 228 0 + ATOM 1659 O . ALA A 228 ? -2.33300 -0.32500 -7.42500 1.000 93.16000 O ? A ? 228 0 + ATOM 1660 CB . ALA A 228 ? -0.78800 2.21400 -8.23000 1.000 93.16000 C ? A ? 228 0 + ATOM 1661 N . GLN A 229 ? -3.47700 0.37700 -9.22800 1.000 93.80000 N ? A ? 229 0 + ATOM 1662 CA . GLN A 229 ? -3.89900 -0.95000 -9.69000 1.000 93.80000 C ? A ? 229 0 + ATOM 1663 C . GLN A 229 ? -3.04200 -1.45300 -10.85600 1.000 93.80000 C ? A ? 229 0 + ATOM 1664 O . GLN A 229 ? -2.93600 -2.65500 -11.09400 1.000 93.80000 O ? A ? 229 0 + ATOM 1665 CB . GLN A 229 ? -5.35900 -0.87600 -10.14700 1.000 93.80000 C ? A ? 229 0 + ATOM 1666 CG . GLN A 229 ? -6.35700 -0.57400 -9.01800 1.000 93.80000 C ? A ? 229 0 + ATOM 1667 CD . GLN A 229 ? -7.78300 -0.46900 -9.55400 1.000 93.80000 C ? A ? 229 0 + ATOM 1668 OE1 . GLN A 229 ? -8.03300 -0.53100 -10.74700 1.000 93.80000 O ? A ? 229 0 + ATOM 1669 NE2 . GLN A 229 ? -8.77000 -0.27300 -8.71400 1.000 93.80000 N ? A ? 229 0 + ATOM 1670 N . SER A 230 ? -2.44900 -0.53100 -11.61500 1.000 96.03000 N ? A ? 230 0 + ATOM 1671 CA . SER A 230 ? -1.61200 -0.85200 -12.76500 1.000 96.03000 C ? A ? 230 0 + ATOM 1672 C . SER A 230 ? -0.55000 0.21500 -12.99300 1.000 96.03000 C ? A ? 230 0 + ATOM 1673 O . SER A 230 ? -0.68500 1.36000 -12.56000 1.000 96.03000 O ? A ? 230 0 + ATOM 1674 CB . SER A 230 ? -2.47500 -1.04000 -14.01800 1.000 96.03000 C ? A ? 230 0 + ATOM 1675 OG . SER A 230 ? -3.14600 0.15300 -14.37700 1.000 96.03000 O ? A ? 230 0 + ATOM 1676 N . TYR A 231 ? 0.50400 -0.17100 -13.69700 1.000 96.98000 N ? A ? 231 0 + ATOM 1677 CA . TYR A 231 ? 1.59600 0.69200 -14.10300 1.000 96.98000 C ? A ? 231 0 + ATOM 1678 C . TYR A 231 ? 1.81100 0.57900 -15.60900 1.000 96.98000 C ? A ? 231 0 + ATOM 1679 O . TYR A 231 ? 1.65200 -0.49900 -16.18900 1.000 96.98000 O ? A ? 231 0 + ATOM 1680 CB . TYR A 231 ? 2.87100 0.32500 -13.34200 1.000 96.98000 C ? A ? 231 0 + ATOM 1681 CG . TYR A 231 ? 2.76800 0.42800 -11.83100 1.000 96.98000 C ? A ? 231 0 + ATOM 1682 CD1 . TYR A 231 ? 3.12700 1.62100 -11.17300 1.000 96.98000 C ? A ? 231 0 + ATOM 1683 CD2 . TYR A 231 ? 2.31500 -0.67600 -11.08200 1.000 96.98000 C ? A ? 231 0 + ATOM 1684 CE1 . TYR A 231 ? 3.03100 1.70900 -9.76900 1.000 96.98000 C ? A ? 231 0 + ATOM 1685 CE2 . TYR A 231 ? 2.18700 -0.58100 -9.68400 1.000 96.98000 C ? A ? 231 0 + ATOM 1686 CZ . TYR A 231 ? 2.54300 0.61400 -9.02600 1.000 96.98000 C ? A ? 231 0 + ATOM 1687 OH . TYR A 231 ? 2.43200 0.70200 -7.67500 1.000 96.98000 O ? A ? 231 0 + ATOM 1688 N . LEU A 232 ? 2.20300 1.68700 -16.23300 1.000 96.86000 N ? A ? 232 0 + ATOM 1689 CA . LEU A 232 ? 2.61500 1.74000 -17.63200 1.000 96.86000 C ? A ? 232 0 + ATOM 1690 C . LEU A 232 ? 4.01500 2.33900 -17.70600 1.000 96.86000 C ? A ? 232 0 + ATOM 1691 O . LEU A 232 ? 4.20900 3.52500 -17.42500 1.000 96.86000 O ? A ? 232 0 + ATOM 1692 CB . LEU A 232 ? 1.58100 2.53600 -18.44500 1.000 96.86000 C ? A ? 232 0 + ATOM 1693 CG . LEU A 232 ? 1.97500 2.76500 -19.91700 1.000 96.86000 C ? A ? 232 0 + ATOM 1694 CD1 . LEU A 232 ? 1.92900 1.46800 -20.72400 1.000 96.86000 C ? A ? 232 0 + ATOM 1695 CD2 . LEU A 232 ? 1.00600 3.75500 -20.56100 1.000 96.86000 C ? A ? 232 0 + ATOM 1696 N . LEU A 233 ? 4.97300 1.50700 -18.09800 1.000 97.30000 N ? A ? 233 0 + ATOM 1697 CA . LEU A 233 ? 6.34200 1.90500 -18.38100 1.000 97.30000 C ? A ? 233 0 + ATOM 1698 C . LEU A 233 ? 6.47900 2.23100 -19.86600 1.000 97.30000 C ? A ? 233 0 + ATOM 1699 O . LEU A 233 ? 5.99400 1.47900 -20.70900 1.000 97.30000 O ? A ? 233 0 + ATOM 1700 CB . LEU A 233 ? 7.27400 0.78600 -17.90600 1.000 97.30000 C ? A ? 233 0 + ATOM 1701 CG . LEU A 233 ? 8.76300 1.14400 -18.05300 1.000 97.30000 C ? A ? 233 0 + ATOM 1702 CD1 . LEU A 233 ? 9.54600 0.46800 -16.94200 1.000 97.30000 C ? A ? 233 0 + ATOM 1703 CD2 . LEU A 233 ? 9.35000 0.65000 -19.37300 1.000 97.30000 C ? A ? 233 0 + ATOM 1704 N . THR A 234 ? 7.15000 3.33800 -20.17100 1.000 97.08000 N ? A ? 234 0 + ATOM 1705 CA . THR A 234 ? 7.45500 3.79200 -21.53200 1.000 97.08000 C ? A ? 234 0 + ATOM 1706 C . THR A 234 ? 8.95100 4.05000 -21.64600 1.000 97.08000 C ? A ? 234 0 + ATOM 1707 O . THR A 234 ? 9.50900 4.79300 -20.83800 1.000 97.08000 O ? A ? 234 0 + ATOM 1708 CB . THR A 234 ? 6.66800 5.06400 -21.87700 1.000 97.08000 C ? A ? 234 0 + ATOM 1709 OG1 . THR A 234 ? 5.29100 4.83000 -21.68400 1.000 97.08000 O ? A ? 234 0 + ATOM 1710 CG2 . THR A 234 ? 6.86400 5.50600 -23.32700 1.000 97.08000 C ? A ? 234 0 + ATOM 1711 N . ALA A 235 ? 9.58800 3.44200 -22.64100 1.000 96.74000 N ? A ? 235 0 + ATOM 1712 CA . ALA A 235 ? 10.98800 3.63400 -22.97900 1.000 96.74000 C ? A ? 235 0 + ATOM 1713 C . ALA A 235 ? 11.07700 4.18000 -24.40400 1.000 96.74000 C ? A ? 235 0 + ATOM 1714 O . ALA A 235 ? 10.59700 3.53700 -25.33300 1.000 96.74000 O ? A ? 235 0 + ATOM 1715 CB . ALA A 235 ? 11.71500 2.29600 -22.82300 1.000 96.74000 C ? A ? 235 0 + ATOM 1716 N . SER A 236 ? 11.67200 5.35600 -24.57200 1.000 96.76000 N ? A ? 236 0 + ATOM 1717 CA . SER A 236 ? 11.82700 6.00400 -25.87900 1.000 96.76000 C ? A ? 236 0 + ATOM 1718 C . SER A 236 ? 13.29200 6.28500 -26.16900 1.000 96.76000 C ? A ? 236 0 + ATOM 1719 O . SER A 236 ? 13.97900 6.82300 -25.29600 1.000 96.76000 O ? A ? 236 0 + ATOM 1720 CB . SER A 236 ? 11.03000 7.31000 -25.93000 1.000 96.76000 C ? A ? 236 0 + ATOM 1721 OG . SER A 236 ? 11.48000 8.19500 -24.91800 1.000 96.76000 O ? A ? 236 0 + ATOM 1722 N . SER A 237 ? 13.75500 5.98900 -27.37800 1.000 95.64000 N ? A ? 237 0 + ATOM 1723 CA . SER A 237 ? 15.11700 6.29000 -27.81300 1.000 95.64000 C ? A ? 237 0 + ATOM 1724 C . SER A 237 ? 15.16800 7.38700 -28.88300 1.000 95.64000 C ? A ? 237 0 + ATOM 1725 O . SER A 237 ? 14.16300 7.75300 -29.49200 1.000 95.64000 O ? A ? 237 0 + ATOM 1726 CB . SER A 237 ? 15.81500 5.01000 -28.25800 1.000 95.64000 C ? A ? 237 0 + ATOM 1727 OG . SER A 237 ? 17.18000 5.32300 -28.41200 1.000 95.64000 O ? A ? 237 0 + ATOM 1728 N . SER A 238 ? 16.35600 7.95900 -29.08700 1.000 93.34000 N ? A ? 238 0 + ATOM 1729 CA . SER A 238 ? 16.62200 9.01300 -30.07100 1.000 93.34000 C ? A ? 238 0 + ATOM 1730 C . SER A 238 ? 16.48700 8.55700 -31.52500 1.000 93.34000 C ? A ? 238 0 + ATOM 1731 O . SER A 238 ? 16.34700 9.40000 -32.40700 1.000 93.34000 O ? A ? 238 0 + ATOM 1732 CB . SER A 238 ? 18.03300 9.56900 -29.86100 1.000 93.34000 C ? A ? 238 0 + ATOM 1733 OG . SER A 238 ? 18.99800 8.54000 -29.70200 1.000 93.34000 O ? A ? 238 0 + ATOM 1734 N . ASP A 239 ? 16.53900 7.25100 -31.78300 1.000 92.94000 N ? A ? 239 0 + ATOM 1735 CA . ASP A 239 ? 16.32600 6.66400 -33.11000 1.000 92.94000 C ? A ? 239 0 + ATOM 1736 C . ASP A 239 ? 14.83600 6.55000 -33.49700 1.000 92.94000 C ? A ? 239 0 + ATOM 1737 O . ASP A 239 ? 14.51800 6.19100 -34.63000 1.000 92.94000 O ? A ? 239 0 + ATOM 1738 CB . ASP A 239 ? 17.04200 5.30600 -33.17800 1.000 92.94000 C ? A ? 239 0 + ATOM 1739 CG . ASP A 239 ? 16.41200 4.22300 -32.29600 1.000 92.94000 C ? A ? 239 0 + ATOM 1740 OD1 . ASP A 239 ? 15.51900 4.55800 -31.48700 1.000 92.94000 O ? A ? 239 0 + ATOM 1741 OD2 . ASP A 239 ? 16.83700 3.05800 -32.44500 1.000 92.94000 O ? A ? 239 0 + ATOM 1742 N . GLY A 240 ? 13.92900 6.89700 -32.57700 1.000 93.53000 N ? A ? 240 0 + ATOM 1743 CA . GLY A 240 ? 12.48100 6.83800 -32.75900 1.000 93.53000 C ? A ? 240 0 + ATOM 1744 C . GLY A 240 ? 11.82800 5.55900 -32.23400 1.000 93.53000 C ? A ? 240 0 + ATOM 1745 O . GLY A 240 ? 10.60300 5.45700 -32.31400 1.000 93.53000 O ? A ? 240 0 + ATOM 1746 N . ASP A 241 ? 12.59200 4.61100 -31.68000 1.000 94.68000 N ? A ? 241 0 + ATOM 1747 CA . ASP A 241 ? 12.01700 3.42000 -31.05900 1.000 94.68000 C ? A ? 241 0 + ATOM 1748 C . ASP A 241 ? 11.29000 3.77100 -29.75300 1.000 94.68000 C ? A ? 241 0 + ATOM 1749 O . ASP A 241 ? 11.80600 4.49800 -28.89500 1.000 94.68000 O ? A ? 241 0 + ATOM 1750 CB . ASP A 241 ? 13.08000 2.33100 -30.85800 1.000 94.68000 C ? A ? 241 0 + ATOM 1751 CG . ASP A 241 ? 12.43900 1.02800 -30.37500 1.000 94.68000 C ? A ? 241 0 + ATOM 1752 OD1 . ASP A 241 ? 11.34500 0.69300 -30.88500 1.000 94.68000 O ? A ? 241 0 + ATOM 1753 OD2 . ASP A 241 ? 13.00500 0.41600 -29.44000 1.000 94.68000 O ? A ? 241 0 + ATOM 1754 N . VAL A 242 ? 10.06500 3.26000 -29.60600 1.000 95.95000 N ? A ? 242 0 + ATOM 1755 CA . VAL A 242 ? 9.21400 3.48100 -28.43200 1.000 95.95000 C ? A ? 242 0 + ATOM 1756 C . VAL A 242 ? 8.58200 2.16600 -28.01500 1.000 95.95000 C ? A ? 242 0 + ATOM 1757 O . VAL A 242 ? 7.71300 1.61700 -28.69200 1.000 95.95000 O ? A ? 242 0 + ATOM 1758 CB . VAL A 242 ? 8.13300 4.55800 -28.65000 1.000 95.95000 C ? A ? 242 0 + ATOM 1759 CG1 . VAL A 242 ? 7.33400 4.79200 -27.35400 1.000 95.95000 C ? A ? 242 0 + ATOM 1760 CG2 . VAL A 242 ? 8.73400 5.90800 -29.05700 1.000 95.95000 C ? A ? 242 0 + ATOM 1761 N . LEU A 243 ? 8.97200 1.70100 -26.83500 1.000 95.53000 N ? A ? 243 0 + ATOM 1762 CA . LEU A 243 ? 8.50500 0.45800 -26.24700 1.000 95.53000 C ? A ? 243 0 + ATOM 1763 C . LEU A 243 ? 7.70300 0.75000 -24.98500 1.000 95.53000 C ? A ? 243 0 + ATOM 1764 O . LEU A 243 ? 8.04000 1.63100 -24.19100 1.000 95.53000 O ? A ? 243 0 + ATOM 1765 CB . LEU A 243 ? 9.71200 -0.44800 -25.98800 1.000 95.53000 C ? A ? 243 0 + ATOM 1766 CG . LEU A 243 ? 10.34600 -0.97800 -27.29000 1.000 95.53000 C ? A ? 243 0 + ATOM 1767 CD1 . LEU A 243 ? 11.76500 -1.42300 -26.99000 1.000 95.53000 C ? A ? 243 0 + ATOM 1768 CD2 . LEU A 243 ? 9.57000 -2.17000 -27.85000 1.000 95.53000 C ? A ? 243 0 + ATOM 1769 N . THR A 244 ? 6.63000 -0.01000 -24.78700 1.000 96.69000 N ? A ? 244 0 + ATOM 1770 CA . THR A 244 ? 5.77900 0.11800 -23.60200 1.000 96.69000 C ? A ? 244 0 + ATOM 1771 C . THR A 244 ? 5.49600 -1.23300 -22.98000 1.000 96.69000 C ? A ? 244 0 + ATOM 1772 O . THR A 244 ? 5.41500 -2.24800 -23.66900 1.000 96.69000 O ? A ? 244 0 + ATOM 1773 CB . THR A 244 ? 4.45900 0.85200 -23.87400 1.000 96.69000 C ? A ? 244 0 + ATOM 1774 OG1 . THR A 244 ? 3.66700 0.16800 -24.81500 1.000 96.69000 O ? A ? 244 0 + ATOM 1775 CG2 . THR A 244 ? 4.65400 2.27400 -24.38700 1.000 96.69000 C ? A ? 244 0 + ATOM 1776 N . CYS A 245 ? 5.33500 -1.25200 -21.66100 1.000 95.53000 N ? A ? 245 0 + ATOM 1777 CA . CYS A 245 ? 4.93400 -2.45200 -20.94400 1.000 95.53000 C ? A ? 245 0 + ATOM 1778 C . CYS A 245 ? 4.01700 -2.09900 -19.77600 1.000 95.53000 C ? A ? 245 0 + ATOM 1779 O . CYS A 245 ? 4.23900 -1.13900 -19.03300 1.000 95.53000 O ? A ? 245 0 + ATOM 1780 CB . CYS A 245 ? 6.17900 -3.25600 -20.57300 1.000 95.53000 C ? A ? 245 0 + ATOM 1781 SG . CYS A 245 ? 6.13900 -4.24100 -19.05900 1.000 95.53000 S ? A ? 245 0 + ATOM 1782 N . LYS A 246 ? 2.94000 -2.87800 -19.66200 1.000 96.04000 N ? A ? 246 0 + ATOM 1783 CA . LYS A 246 ? 1.92700 -2.75500 -18.61700 1.000 96.04000 C ? A ? 246 0 + ATOM 1784 C . LYS A 246 ? 2.15900 -3.82900 -17.57100 1.000 96.04000 C ? A ? 246 0 + ATOM 1785 O . LYS A 246 ? 2.36200 -4.98700 -17.92400 1.000 96.04000 O ? A ? 246 0 + ATOM 1786 CB . LYS A 246 ? 0.51400 -2.86400 -19.20600 1.000 96.04000 C ? A ? 246 0 + ATOM 1787 CG . LYS A 246 ? 0.15900 -1.63800 -20.05400 1.000 96.04000 C ? A ? 246 0 + ATOM 1788 CD . LYS A 246 ? -1.26700 -1.75000 -20.60400 1.000 96.04000 C ? A ? 246 0 + ATOM 1789 CE . LYS A 246 ? -1.59500 -0.50900 -21.44100 1.000 96.04000 C ? A ? 246 0 + ATOM 1790 NZ . LYS A 246 ? -2.98000 -0.55500 -21.97000 1.000 96.04000 N ? A ? 246 0 + ATOM 1791 N . SER A 247 ? 2.08200 -3.45200 -16.30200 1.000 95.41000 N ? A ? 247 0 + ATOM 1792 CA . SER A 247 ? 2.25200 -4.38200 -15.19000 1.000 95.41000 C ? A ? 247 0 + ATOM 1793 C . SER A 247 ? 1.28300 -4.07400 -14.05500 1.000 95.41000 C ? A ? 247 0 + ATOM 1794 O . SER A 247 ? 0.98200 -2.91300 -13.78600 1.000 95.41000 O ? A ? 247 0 + ATOM 1795 CB . SER A 247 ? 3.69600 -4.34000 -14.70000 1.000 95.41000 C ? A ? 247 0 + ATOM 1796 OG . SER A 247 ? 3.86800 -5.37800 -13.77200 1.000 95.41000 O ? A ? 247 0 + ATOM 1797 N . THR A 248 ? 0.78800 -5.11100 -13.38500 1.000 95.16000 N ? A ? 248 0 + ATOM 1798 CA . THR A 248 ? 0.04900 -4.99800 -12.11400 1.000 95.16000 C ? A ? 248 0 + ATOM 1799 C . THR A 248 ? 0.97300 -5.15200 -10.90500 1.000 95.16000 C ? A ? 248 0 + ATOM 1800 O . THR A 248 ? 0.53800 -4.99800 -9.76900 1.000 95.16000 O ? A ? 248 0 + ATOM 1801 CB . THR A 248 ? -1.07800 -6.03600 -12.04000 1.000 95.16000 C ? A ? 248 0 + ATOM 1802 OG1 . THR A 248 ? -0.54600 -7.33400 -12.19600 1.000 95.16000 O ? A ? 248 0 + ATOM 1803 CG2 . THR A 248 ? -2.11900 -5.82800 -13.14000 1.000 95.16000 C ? A ? 248 0 + ATOM 1804 N . THR A 249 ? 2.24700 -5.47300 -11.13900 1.000 94.79000 N ? A ? 249 0 + ATOM 1805 CA . THR A 249 ? 3.29700 -5.58600 -10.12600 1.000 94.79000 C ? A ? 249 0 + ATOM 1806 C . THR A 249 ? 4.27100 -4.41300 -10.23700 1.000 94.79000 C ? A ? 249 0 + ATOM 1807 O . THR A 249 ? 4.19300 -3.57300 -11.13000 1.000 94.79000 O ? A ? 249 0 + ATOM 1808 CB . THR A 249 ? 4.04200 -6.93200 -10.24500 1.000 94.79000 C ? A ? 249 0 + ATOM 1809 OG1 . THR A 249 ? 4.59500 -7.08400 -11.52900 1.000 94.79000 O ? A ? 249 0 + ATOM 1810 CG2 . THR A 249 ? 3.10600 -8.11900 -10.01400 1.000 94.79000 C ? A ? 249 0 + ATOM 1811 N . ASN A 250 ? 5.22300 -4.35700 -9.31100 1.000 95.13000 N ? A ? 250 0 + ATOM 1812 CA . ASN A 250 ? 6.23100 -3.30100 -9.18900 1.000 95.13000 C ? A ? 250 0 + ATOM 1813 C . ASN A 250 ? 7.44100 -3.46200 -10.11600 1.000 95.13000 C ? A ? 250 0 + ATOM 1814 O . ASN A 250 ? 8.51800 -2.92800 -9.84400 1.000 95.13000 O ? A ? 250 0 + ATOM 1815 CB . ASN A 250 ? 6.63800 -3.26600 -7.71700 1.000 95.13000 C ? A ? 250 0 + ATOM 1816 CG . ASN A 250 ? 5.47100 -2.78700 -6.90500 1.000 95.13000 C ? A ? 250 0 + ATOM 1817 OD1 . ASN A 250 ? 4.57200 -3.52500 -6.54500 1.000 95.13000 O ? A ? 250 0 + ATOM 1818 ND2 . ASN A 250 ? 5.41600 -1.50900 -6.68300 1.000 95.13000 N ? A ? 250 0 + ATOM 1819 N . ASN A 251 ? 7.29300 -4.26200 -11.16600 1.000 96.32000 N ? A ? 251 0 + ATOM 1820 CA . ASN A 251 ? 8.34300 -4.54800 -12.12200 1.000 96.32000 C ? A ? 251 0 + ATOM 1821 C . ASN A 251 ? 7.76600 -4.78600 -13.51500 1.000 96.32000 C ? A ? 251 0 + ATOM 1822 O . ASN A 251 ? 6.58700 -5.09800 -13.68700 1.000 96.32000 O ? A ? 251 0 + ATOM 1823 CB . ASN A 251 ? 9.20900 -5.71800 -11.61800 1.000 96.32000 C ? A ? 251 0 + ATOM 1824 CG . ASN A 251 ? 8.45900 -7.02300 -11.38500 1.000 96.32000 C ? A ? 251 0 + ATOM 1825 OD1 . ASN A 251 ? 7.35600 -7.26800 -11.84100 1.000 96.32000 O ? A ? 251 0 + ATOM 1826 ND2 . ASN A 251 ? 9.03300 -7.92400 -10.62700 1.000 96.32000 N ? A ? 251 0 + ATOM 1827 N . CYS A 252 ? 8.61100 -4.59900 -14.51900 1.000 96.24000 N ? A ? 252 0 + ATOM 1828 CA . CYS A 252 ? 8.26300 -4.78100 -15.91700 1.000 96.24000 C ? A ? 252 0 + ATOM 1829 C . CYS A 252 ? 9.53600 -5.03900 -16.72700 1.000 96.24000 C ? A ? 252 0 + ATOM 1830 O . CYS A 252 ? 10.58700 -4.45200 -16.46400 1.000 96.24000 O ? A ? 252 0 + ATOM 1831 CB . CYS A 252 ? 7.52500 -3.52400 -16.38100 1.000 96.24000 C ? A ? 252 0 + ATOM 1832 SG . CYS A 252 ? 7.58200 -3.19100 -18.13700 1.000 96.24000 S ? A ? 252 0 + ATOM 1833 N . THR A 253 ? 9.43800 -5.92200 -17.71400 1.000 95.25000 N ? A ? 253 0 + ATOM 1834 CA . THR A 253 ? 10.53500 -6.29300 -18.60600 1.000 95.25000 C ? A ? 253 0 + ATOM 1835 C . THR A 253 ? 10.25900 -5.79200 -20.01900 1.000 95.25000 C ? A ? 253 0 + ATOM 1836 O . THR A 253 ? 9.17900 -6.00400 -20.56500 1.000 95.25000 O ? A ? 253 0 + ATOM 1837 CB . THR A 253 ? 10.76000 -7.81100 -18.58700 1.000 95.25000 C ? A ? 253 0 + ATOM 1838 OG1 . THR A 253 ? 9.54900 -8.52000 -18.70700 1.000 95.25000 O ? A ? 253 0 + ATOM 1839 CG2 . THR A 253 ? 11.39100 -8.25100 -17.26700 1.000 95.25000 C ? A ? 253 0 + ATOM 1840 N . LEU A 254 ? 11.25100 -5.13400 -20.62000 1.000 94.89000 N ? A ? 254 0 + ATOM 1841 CA . LEU A 254 ? 11.23700 -4.72900 -22.02400 1.000 94.89000 C ? A ? 254 0 + ATOM 1842 C . LEU A 254 ? 12.36600 -5.45600 -22.76700 1.000 94.89000 C ? A ? 254 0 + ATOM 1843 O . LEU A 254 ? 13.53400 -5.12300 -22.55400 1.000 94.89000 O ? A ? 254 0 + ATOM 1844 CB . LEU A 254 ? 11.34900 -3.19900 -22.14900 1.000 94.89000 C ? A ? 254 0 + ATOM 1845 CG . LEU A 254 ? 10.04100 -2.43800 -21.85800 1.000 94.89000 C ? A ? 254 0 + ATOM 1846 CD1 . LEU A 254 ? 10.25400 -0.94800 -22.10700 1.000 94.89000 C ? A ? 254 0 + ATOM 1847 CD2 . LEU A 254 ? 8.89300 -2.87100 -22.77000 1.000 94.89000 C ? A ? 254 0 + ATOM 1848 N . PRO A 255 ? 12.05100 -6.47900 -23.57900 1.000 93.40000 N ? A ? 255 0 + ATOM 1849 CA . PRO A 255 ? 13.03600 -7.18300 -24.39600 1.000 93.40000 C ? A ? 255 0 + ATOM 1850 C . PRO A 255 ? 13.34200 -6.42600 -25.70000 1.000 93.40000 C ? A ? 255 0 + ATOM 1851 O . PRO A 255 ? 12.61600 -5.50300 -26.06500 1.000 93.40000 O ? A ? 255 0 + ATOM 1852 CB . PRO A 255 ? 12.39400 -8.54900 -24.64700 1.000 93.40000 C ? A ? 255 0 + ATOM 1853 CG . PRO A 255 ? 10.90600 -8.21300 -24.75900 1.000 93.40000 C ? A ? 255 0 + ATOM 1854 CD . PRO A 255 ? 10.72900 -7.07400 -23.75700 1.000 93.40000 C ? A ? 255 0 + ATOM 1855 N . HIS A 256 ? 14.37100 -6.87300 -26.42900 1.000 91.17000 N ? A ? 256 0 + ATOM 1856 CA . HIS A 256 ? 14.66700 -6.45100 -27.80800 1.000 91.17000 C ? A ? 256 0 + ATOM 1857 C . HIS A 256 ? 14.91900 -4.94600 -28.00400 1.000 91.17000 C ? A ? 256 0 + ATOM 1858 O . HIS A 256 ? 14.51400 -4.37500 -29.01300 1.000 91.17000 O ? A ? 256 0 + ATOM 1859 CB . HIS A 256 ? 13.60200 -6.99600 -28.77800 1.000 91.17000 C ? A ? 256 0 + ATOM 1860 CG . HIS A 256 ? 13.35300 -8.47300 -28.64600 1.000 91.17000 C ? A ? 256 0 + ATOM 1861 ND1 . HIS A 256 ? 14.27300 -9.47100 -28.86000 1.000 91.17000 N ? A ? 256 0 + ATOM 1862 CD2 . HIS A 256 ? 12.18200 -9.07300 -28.27400 1.000 91.17000 C ? A ? 256 0 + ATOM 1863 CE1 . HIS A 256 ? 13.67300 -10.64600 -28.61700 1.000 91.17000 C ? A ? 256 0 + ATOM 1864 NE2 . HIS A 256 ? 12.39600 -10.45600 -28.25000 1.000 91.17000 N ? A ? 256 0 + ATOM 1865 N . LEU A 257 ? 15.62300 -4.31400 -27.06600 1.000 94.11000 N ? A ? 257 0 + ATOM 1866 CA . LEU A 257 ? 16.08400 -2.93700 -27.22700 1.000 94.11000 C ? A ? 257 0 + ATOM 1867 C . LEU A 257 ? 17.15400 -2.86400 -28.32600 1.000 94.11000 C ? A ? 257 0 + ATOM 1868 O . LEU A 257 ? 18.01100 -3.74800 -28.43800 1.000 94.11000 O ? A ? 257 0 + ATOM 1869 CB . LEU A 257 ? 16.63200 -2.41000 -25.88700 1.000 94.11000 C ? A ? 257 0 + ATOM 1870 CG . LEU A 257 ? 15.61800 -2.38400 -24.72900 1.000 94.11000 C ? A ? 257 0 + ATOM 1871 CD1 . LEU A 257 ? 16.33500 -2.06500 -23.42000 1.000 94.11000 C ? A ? 257 0 + ATOM 1872 CD2 . LEU A 257 ? 14.55300 -1.31400 -24.92500 1.000 94.11000 C ? A ? 257 0 + ATOM 1873 N . HIS A 258 ? 17.13800 -1.79500 -29.12000 1.000 93.99000 N ? A ? 258 0 + ATOM 1874 CA . HIS A 258 ? 18.17000 -1.53800 -30.11800 1.000 93.99000 C ? A ? 258 0 + ATOM 1875 C . HIS A 258 ? 19.52900 -1.31700 -29.44800 1.000 93.99000 C ? A ? 258 0 + ATOM 1876 O . HIS A 258 ? 19.65300 -0.56800 -28.48200 1.000 93.99000 O ? A ? 258 0 + ATOM 1877 CB . HIS A 258 ? 17.78400 -0.33100 -30.97500 1.000 93.99000 C ? A ? 258 0 + ATOM 1878 CG . HIS A 258 ? 16.62200 -0.54800 -31.91100 1.000 93.99000 C ? A ? 258 0 + ATOM 1879 ND1 . HIS A 258 ? 16.01500 0.44600 -32.63500 1.000 93.99000 N ? A ? 258 0 + ATOM 1880 CD2 . HIS A 258 ? 15.98500 -1.71900 -32.23000 1.000 93.99000 C ? A ? 258 0 + ATOM 1881 CE1 . HIS A 258 ? 15.03800 -0.10500 -33.36800 1.000 93.99000 C ? A ? 258 0 + ATOM 1882 NE2 . HIS A 258 ? 15.00200 -1.43500 -33.18400 1.000 93.99000 N ? A ? 258 0 + ATOM 1883 N . CYS A 259 ? 20.56500 -1.96800 -29.97200 1.000 92.06000 N ? A ? 259 0 + ATOM 1884 CA . CYS A 259 ? 21.92600 -1.82900 -29.46800 1.000 92.06000 C ? A ? 259 0 + ATOM 1885 C . CYS A 259 ? 22.48900 -0.41800 -29.71300 1.000 92.06000 C ? A ? 259 0 + ATOM 1886 O . CYS A 259 ? 22.09000 0.28100 -30.64500 1.000 92.06000 O ? A ? 259 0 + ATOM 1887 CB . CYS A 259 ? 22.79300 -2.91700 -30.10900 1.000 92.06000 C ? A ? 259 0 + ATOM 1888 SG . CYS A 259 ? 22.86700 -2.86300 -31.92800 1.000 92.06000 S ? A ? 259 0 + ATOM 1889 N . GLY A 260 ? 23.44900 0.00300 -28.88900 1.000 91.36000 N ? A ? 260 0 + ATOM 1890 CA . GLY A 260 ? 24.13500 1.29300 -29.01400 1.000 91.36000 C ? A ? 260 0 + ATOM 1891 C . GLY A 260 ? 23.25500 2.52200 -28.76300 1.000 91.36000 C ? A ? 260 0 + ATOM 1892 O . GLY A 260 ? 23.72100 3.64400 -28.95100 1.000 91.36000 O ? A ? 260 0 + ATOM 1893 N . GLN A 261 ? 22.01100 2.32500 -28.33300 1.000 94.17000 N ? A ? 261 0 + ATOM 1894 CA . GLN A 261 ? 21.04300 3.37700 -28.06000 1.000 94.17000 C ? A ? 261 0 + ATOM 1895 C . GLN A 261 ? 20.94500 3.71900 -26.57100 1.000 94.17000 C ? A ? 261 0 + ATOM 1896 O . GLN A 261 ? 21.19900 2.88800 -25.68800 1.000 94.17000 O ? A ? 261 0 + ATOM 1897 CB . GLN A 261 ? 19.66800 2.96000 -28.59700 1.000 94.17000 C ? A ? 261 0 + ATOM 1898 CG . GLN A 261 ? 19.58000 2.80500 -30.12100 1.000 94.17000 C ? A ? 261 0 + ATOM 1899 CD . GLN A 261 ? 20.15900 3.97800 -30.90600 1.000 94.17000 C ? A ? 261 0 + ATOM 1900 OE1 . GLN A 261 ? 20.00400 5.14900 -30.58300 1.000 94.17000 O ? A ? 261 0 + ATOM 1901 NE2 . GLN A 261 ? 20.91200 3.70400 -31.94900 1.000 94.17000 N ? A ? 261 0 + ATOM 1902 N . VAL A 262 ? 20.51000 4.94900 -26.29900 1.000 95.71000 N ? A ? 262 0 + ATOM 1903 CA . VAL A 262 ? 20.08100 5.39500 -24.96900 1.000 95.71000 C ? A ? 262 0 + ATOM 1904 C . VAL A 262 ? 18.56100 5.48300 -24.96700 1.000 95.71000 C ? A ? 262 0 + ATOM 1905 O . VAL A 262 ? 17.97800 6.14300 -25.82700 1.000 95.71000 O ? A ? 262 0 + ATOM 1906 CB . VAL A 262 ? 20.73200 6.73200 -24.56900 1.000 95.71000 C ? A ? 262 0 + ATOM 1907 CG1 . VAL A 262 ? 20.38300 7.10100 -23.11900 1.000 95.71000 C ? A ? 262 0 + ATOM 1908 CG2 . VAL A 262 ? 22.26100 6.64600 -24.68300 1.000 95.71000 C ? A ? 262 0 + ATOM 1909 N . TYR A 263 ? 17.92300 4.80900 -24.01500 1.000 96.24000 N ? A ? 263 0 + ATOM 1910 CA . TYR A 263 ? 16.47800 4.86100 -23.81100 1.000 96.24000 C ? A ? 263 0 + ATOM 1911 C . TYR A 263 ? 16.15400 5.73700 -22.60400 1.000 96.24000 C ? A ? 263 0 + ATOM 1912 O . TYR A 263 ? 16.67400 5.51600 -21.51000 1.000 96.24000 O ? A ? 263 0 + ATOM 1913 CB . TYR A 263 ? 15.90200 3.44800 -23.64500 1.000 96.24000 C ? A ? 263 0 + ATOM 1914 CG . TYR A 263 ? 15.76600 2.67800 -24.94400 1.000 96.24000 C ? A ? 263 0 + ATOM 1915 CD1 . TYR A 263 ? 14.51400 2.58800 -25.58700 1.000 96.24000 C ? A ? 263 0 + ATOM 1916 CD2 . TYR A 263 ? 16.89200 2.05700 -25.51700 1.000 96.24000 C ? A ? 263 0 + ATOM 1917 CE1 . TYR A 263 ? 14.38100 1.85400 -26.78100 1.000 96.24000 C ? A ? 263 0 + ATOM 1918 CE2 . TYR A 263 ? 16.76000 1.32600 -26.71500 1.000 96.24000 C ? A ? 263 0 + ATOM 1919 CZ . TYR A 263 ? 15.50300 1.20900 -27.34100 1.000 96.24000 C ? A ? 263 0 + ATOM 1920 OH . TYR A 263 ? 15.38500 0.45100 -28.45900 1.000 96.24000 O ? A ? 263 0 + ATOM 1921 N . ASN A 264 ? 15.25300 6.69600 -22.79000 1.000 96.81000 N ? A ? 264 0 + ATOM 1922 CA . ASN A 264 ? 14.66600 7.47800 -21.71000 1.000 96.81000 C ? A ? 264 0 + ATOM 1923 C . ASN A 264 ? 13.45900 6.71300 -21.17500 1.000 96.81000 C ? A ? 264 0 + ATOM 1924 O . ASN A 264 ? 12.46800 6.53000 -21.88700 1.000 96.81000 O ? A ? 264 0 + ATOM 1925 CB . ASN A 264 ? 14.27300 8.86900 -22.22500 1.000 96.81000 C ? A ? 264 0 + ATOM 1926 CG . ASN A 264 ? 15.46300 9.68900 -22.68500 1.000 96.81000 C ? A ? 264 0 + ATOM 1927 OD1 . ASN A 264 ? 16.60800 9.45000 -22.35000 1.000 96.81000 O ? A ? 264 0 + ATOM 1928 ND2 . ASN A 264 ? 15.22700 10.69500 -23.49100 1.000 96.81000 N ? A ? 264 0 + ATOM 1929 N . VAL A 265 ? 13.55000 6.25200 -19.93100 1.000 96.86000 N ? A ? 265 0 + ATOM 1930 CA . VAL A 265 ? 12.52900 5.40800 -19.31100 1.000 96.86000 C ? A ? 265 0 + ATOM 1931 C . VAL A 265 ? 11.70800 6.22900 -18.33500 1.000 96.86000 C ? A ? 265 0 + ATOM 1932 O . VAL A 265 ? 12.25100 6.91100 -17.46800 1.000 96.86000 O ? A ? 265 0 + ATOM 1933 CB . VAL A 265 ? 13.14500 4.17400 -18.63700 1.000 96.86000 C ? A ? 265 0 + ATOM 1934 CG1 . VAL A 265 ? 12.04300 3.20200 -18.19800 1.000 96.86000 C ? A ? 265 0 + ATOM 1935 CG2 . VAL A 265 ? 14.08500 3.45200 -19.61000 1.000 96.86000 C ? A ? 265 0 + ATOM 1936 N . SER A 266 ? 10.38900 6.14800 -18.46100 1.000 97.12000 N ? A ? 266 0 + ATOM 1937 CA . SER A 266 ? 9.43600 6.78800 -17.55800 1.000 97.12000 C ? A ? 266 0 + ATOM 1938 C . SER A 266 ? 8.30500 5.83400 -17.21300 1.000 97.12000 C ? A ? 266 0 + ATOM 1939 O . SER A 266 ? 8.00300 4.90200 -17.96300 1.000 97.12000 O ? A ? 266 0 + ATOM 1940 CB . SER A 266 ? 8.89300 8.08100 -18.16900 1.000 97.12000 C ? A ? 266 0 + ATOM 1941 OG . SER A 266 ? 8.15400 7.81600 -19.34500 1.000 97.12000 O ? A ? 266 0 + ATOM 1942 N . ILE A 267 ? 7.67500 6.05600 -16.06400 1.000 96.80000 N ? A ? 267 0 + ATOM 1943 CA . ILE A 267 ? 6.57400 5.22100 -15.60300 1.000 96.80000 C ? A ? 267 0 + ATOM 1944 C . ILE A 267 ? 5.42400 6.05100 -15.04700 1.000 96.80000 C ? A ? 267 0 + ATOM 1945 O . ILE A 267 ? 5.62500 7.07600 -14.39800 1.000 96.80000 O ? A ? 267 0 + ATOM 1946 CB . ILE A 267 ? 7.09800 4.15600 -14.62700 1.000 96.80000 C ? A ? 267 0 + ATOM 1947 CG1 . ILE A 267 ? 5.97400 3.15700 -14.31800 1.000 96.80000 C ? A ? 267 0 + ATOM 1948 CG2 . ILE A 267 ? 7.72800 4.77100 -13.36800 1.000 96.80000 C ? A ? 267 0 + ATOM 1949 CD1 . ILE A 267 ? 6.51700 1.93500 -13.61000 1.000 96.80000 C ? A ? 267 0 + ATOM 1950 N . THR A 268 ? 4.20600 5.58400 -15.29800 1.000 96.43000 N ? A ? 268 0 + ATOM 1951 CA . THR A 268 ? 2.96600 6.13000 -14.73900 1.000 96.43000 C ? A ? 268 0 + ATOM 1952 C . THR A 268 ? 2.24200 5.05300 -13.93600 1.000 96.43000 C ? A ? 268 0 + ATOM 1953 O . THR A 268 ? 2.32200 3.86800 -14.26400 1.000 96.43000 O ? A ? 268 0 + ATOM 1954 CB . THR A 268 ? 2.05000 6.68300 -15.83900 1.000 96.43000 C ? A ? 268 0 + ATOM 1955 OG1 . THR A 268 ? 1.78800 5.69800 -16.80800 1.000 96.43000 O ? A ? 268 0 + ATOM 1956 CG2 . THR A 268 ? 2.65000 7.88100 -16.56900 1.000 96.43000 C ? A ? 268 0 + ATOM 1957 N . ALA A 269 ? 1.54000 5.45600 -12.87800 1.000 96.37000 N ? A ? 269 0 + ATOM 1958 CA . ALA A 269 ? 0.66300 4.59800 -12.08900 1.000 96.37000 C ? A ? 269 0 + ATOM 1959 C . ALA A 269 ? -0.79700 4.96700 -12.35800 1.000 96.37000 C ? A ? 269 0 + ATOM 1960 O . ALA A 269 ? -1.12800 6.14600 -12.43600 1.000 96.37000 O ? A ? 269 0 + ATOM 1961 CB . ALA A 269 ? 1.01400 4.75300 -10.60900 1.000 96.37000 C ? A ? 269 0 + ATOM 1962 N . SER A 270 ? -1.67700 3.97700 -12.48100 1.000 94.66000 N ? A ? 270 0 + ATOM 1963 CA . SER A 270 ? -3.09900 4.19600 -12.75400 1.000 94.66000 C ? A ? 270 0 + ATOM 1964 C . SER A 270 ? -3.99800 3.47400 -11.75400 1.000 94.66000 C ? A ? 270 0 + ATOM 1965 O . SER A 270 ? -3.71700 2.34700 -11.33700 1.000 94.66000 O ? A ? 270 0 + ATOM 1966 CB . SER A 270 ? -3.45600 3.81300 -14.19400 1.000 94.66000 C ? A ? 270 0 + ATOM 1967 OG . SER A 270 ? -2.68700 4.57100 -15.11200 1.000 94.66000 O ? A ? 270 0 + ATOM 1968 N . ASN A 271 ? -5.09300 4.13500 -11.38500 1.000 91.37000 N ? A ? 271 0 + ATOM 1969 CA . ASN A 271 ? -6.18800 3.59700 -10.58300 1.000 91.37000 C ? A ? 271 0 + ATOM 1970 C . ASN A 271 ? -7.51500 4.01700 -11.22300 1.000 91.37000 C ? A ? 271 0 + ATOM 1971 O . ASN A 271 ? -7.79400 5.21500 -11.32900 1.000 91.37000 O ? A ? 271 0 + ATOM 1972 CB . ASN A 271 ? -6.07200 4.12000 -9.14300 1.000 91.37000 C ? A ? 271 0 + ATOM 1973 CG . ASN A 271 ? -7.14200 3.56000 -8.22100 1.000 91.37000 C ? A ? 271 0 + ATOM 1974 OD1 . ASN A 271 ? -7.86800 2.63900 -8.55500 1.000 91.37000 O ? A ? 271 0 + ATOM 1975 ND2 . ASN A 271 ? -7.28800 4.11000 -7.04000 1.000 91.37000 N ? A ? 271 0 + ATOM 1976 N . ASN A 272 ? -8.32400 3.04500 -11.65100 1.000 84.72000 N ? A ? 272 0 + ATOM 1977 CA . ASN A 272 ? -9.56200 3.28100 -12.39600 1.000 84.72000 C ? A ? 272 0 + ATOM 1978 C . ASN A 272 ? -9.33200 4.22800 -13.59600 1.000 84.72000 C ? A ? 272 0 + ATOM 1979 O . ASN A 272 ? -8.58500 3.88900 -14.51200 1.000 84.72000 O ? A ? 272 0 + ATOM 1980 CB . ASN A 272 ? -10.66500 3.72600 -11.41000 1.000 84.72000 C ? A ? 272 0 + ATOM 1981 CG . ASN A 272 ? -10.92700 2.71500 -10.30800 1.000 84.72000 C ? A ? 272 0 + ATOM 1982 OD1 . ASN A 272 ? -10.88700 1.51100 -10.49600 1.000 84.72000 O ? A ? 272 0 + ATOM 1983 ND2 . ASN A 272 ? -11.23600 3.17500 -9.11900 1.000 84.72000 N ? A ? 272 0 + ATOM 1984 N . ASN A 273 ? -9.93500 5.42100 -13.57400 1.000 84.69000 N ? A ? 273 0 + ATOM 1985 CA . ASN A 273 ? -9.85000 6.41600 -14.64700 1.000 84.69000 C ? A ? 273 0 + ATOM 1986 C . ASN A 273 ? -8.75600 7.47500 -14.42800 1.000 84.69000 C ? A ? 273 0 + ATOM 1987 O . ASN A 273 ? -8.64400 8.39500 -15.23500 1.000 84.69000 O ? A ? 273 0 + ATOM 1988 CB . ASN A 273 ? -11.23300 7.06600 -14.83700 1.000 84.69000 C ? A ? 273 0 + ATOM 1989 CG . ASN A 273 ? -12.27800 6.12600 -15.40700 1.000 84.69000 C ? A ? 273 0 + ATOM 1990 OD1 . ASN A 273 ? -12.04200 4.97700 -15.73400 1.000 84.69000 O ? A ? 273 0 + ATOM 1991 ND2 . ASN A 273 ? -13.49500 6.59600 -15.54800 1.000 84.69000 N ? A ? 273 0 + ATOM 1992 N . CYS A 274 ? -7.96800 7.37600 -13.35300 1.000 90.30000 N ? A ? 274 0 + ATOM 1993 CA . CYS A 274 ? -6.92200 8.34400 -13.04700 1.000 90.30000 C ? A ? 274 0 + ATOM 1994 C . CYS A 274 ? -5.52000 7.77100 -13.21900 1.000 90.30000 C ? A ? 274 0 + ATOM 1995 O . CYS A 274 ? -5.19900 6.70500 -12.69200 1.000 90.30000 O ? A ? 274 0 + ATOM 1996 CB . CYS A 274 ? -7.12500 8.92300 -11.64400 1.000 90.30000 C ? A ? 274 0 + ATOM 1997 SG . CYS A 274 ? -8.40100 10.20200 -11.53700 1.000 90.30000 S ? A ? 274 0 + ATOM 1998 N . THR A 275 ? -4.66400 8.54100 -13.89100 1.000 92.72000 N ? A ? 275 0 + ATOM 1999 CA . THR A 275 ? -3.25600 8.21600 -14.13900 1.000 92.72000 C ? A ? 275 0 + ATOM 2000 C . THR A 275 ? -2.36500 9.30000 -13.54800 1.000 92.72000 C ? A ? 275 0 + ATOM 2001 O . THR A 275 ? -2.59200 10.48900 -13.76600 1.000 92.72000 O ? A ? 275 0 + ATOM 2002 CB . THR A 275 ? -2.99400 8.04200 -15.64300 1.000 92.72000 C ? A ? 275 0 + ATOM 2003 OG1 . THR A 275 ? -3.80900 7.01100 -16.14900 1.000 92.72000 O ? A ? 275 0 + ATOM 2004 CG2 . THR A 275 ? -1.55400 7.65600 -15.96700 1.000 92.72000 C ? A ? 275 0 + ATOM 2005 N . SER A 276 ? -1.33700 8.90000 -12.80400 1.000 93.75000 N ? A ? 276 0 + ATOM 2006 CA . SER A 276 ? -0.33800 9.81100 -12.25500 1.000 93.75000 C ? A ? 276 0 + ATOM 2007 C . SER A 276 ? 0.41600 10.53500 -13.37600 1.000 93.75000 C ? A ? 276 0 + ATOM 2008 O . SER A 276 ? 0.53400 10.00800 -14.48600 1.000 93.75000 O ? A ? 276 0 + ATOM 2009 CB . SER A 276 ? 0.65300 9.04600 -11.36200 1.000 93.75000 C ? A ? 276 0 + ATOM 2010 OG . SER A 276 ? 1.61100 8.31100 -12.11300 1.000 93.75000 O ? A ? 276 0 + ATOM 2011 N . PRO A 277 ? 1.03400 11.69300 -13.09700 1.000 93.06000 N ? A ? 277 0 + ATOM 2012 CA . PRO A 277 ? 2.09800 12.19700 -13.95600 1.000 93.06000 C ? A ? 277 0 + ATOM 2013 C . PRO A 277 ? 3.20400 11.14200 -14.13700 1.000 93.06000 C ? A ? 277 0 + ATOM 2014 O . PRO A 277 ? 3.34400 10.22000 -13.32100 1.000 93.06000 O ? A ? 277 0 + ATOM 2015 CB . PRO A 277 ? 2.60800 13.47300 -13.27700 1.000 93.06000 C ? A ? 277 0 + ATOM 2016 CG . PRO A 277 ? 1.44600 13.89400 -12.37400 1.000 93.06000 C ? A ? 277 0 + ATOM 2017 CD . PRO A 277 ? 0.83900 12.56000 -11.94700 1.000 93.06000 C ? A ? 277 0 + ATOM 2018 N . ALA A 278 ? 3.98400 11.26900 -15.20900 1.000 94.53000 N ? A ? 278 0 + ATOM 2019 CA . ALA A 278 ? 5.13100 10.40000 -15.44300 1.000 94.53000 C ? A ? 278 0 + ATOM 2020 C . ALA A 278 ? 6.23200 10.64600 -14.40000 1.000 94.53000 C ? A ? 278 0 + ATOM 2021 O . ALA A 278 ? 6.42800 11.77300 -13.93800 1.000 94.53000 O ? A ? 278 0 + ATOM 2022 CB . ALA A 278 ? 5.62900 10.60100 -16.87900 1.000 94.53000 C ? A ? 278 0 + ATOM 2023 N . SER A 279 ? 6.96000 9.58700 -14.04100 1.000 95.98000 N ? A ? 279 0 + ATOM 2024 CA . SER A 279 ? 8.16700 9.68700 -13.22000 1.000 95.98000 C ? A ? 279 0 + ATOM 2025 C . SER A 279 ? 9.22700 10.57000 -13.87600 1.000 95.98000 C ? A ? 279 0 + ATOM 2026 O . SER A 279 ? 9.20400 10.81300 -15.08600 1.000 95.98000 O ? A ? 279 0 + ATOM 2027 CB . SER A 279 ? 8.73600 8.29400 -12.92300 1.000 95.98000 C ? A ? 279 0 + ATOM 2028 OG . SER A 279 ? 9.32200 7.72900 -14.08600 1.000 95.98000 O ? A ? 279 0 + ATOM 2029 N . GLN A 280 ? 10.21800 10.98600 -13.08400 1.000 93.93000 N ? A ? 280 0 + ATOM 2030 CA . GLN A 280 ? 11.45900 11.49800 -13.65700 1.000 93.93000 C ? A ? 280 0 + ATOM 2031 C . GLN A 280 ? 12.03900 10.45800 -14.62200 1.000 93.93000 C ? A ? 280 0 + ATOM 2032 O . GLN A 280 ? 11.97000 9.25100 -14.35900 1.000 93.93000 O ? A ? 280 0 + ATOM 2033 CB . GLN A 280 ? 12.46800 11.85400 -12.55900 1.000 93.93000 C ? A ? 280 0 + ATOM 2034 CG . GLN A 280 ? 12.01300 13.08300 -11.75700 1.000 93.93000 C ? A ? 280 0 + ATOM 2035 CD . GLN A 280 ? 13.06300 13.56500 -10.76000 1.000 93.93000 C ? A ? 280 0 + ATOM 2036 OE1 . GLN A 280 ? 13.99200 12.87300 -10.38700 1.000 93.93000 O ? A ? 280 0 + ATOM 2037 NE2 . GLN A 280 ? 12.95500 14.78300 -10.27700 1.000 93.93000 N ? A ? 280 0 + ATOM 2038 N . GLN A 281 ? 12.55400 10.93600 -15.75400 1.000 94.79000 N ? A ? 281 0 + ATOM 2039 CA . GLN A 281 ? 13.15500 10.07000 -16.75800 1.000 94.79000 C ? A ? 281 0 + ATOM 2040 C . GLN A 281 ? 14.47600 9.51300 -16.22600 1.000 94.79000 C ? A ? 281 0 + ATOM 2041 O . GLN A 281 ? 15.30700 10.26100 -15.71000 1.000 94.79000 O ? A ? 281 0 + ATOM 2042 CB . GLN A 281 ? 13.35200 10.81900 -18.08300 1.000 94.79000 C ? A ? 281 0 + ATOM 2043 CG . GLN A 281 ? 12.01100 11.14100 -18.76200 1.000 94.79000 C ? A ? 281 0 + ATOM 2044 CD . GLN A 281 ? 12.16600 11.87100 -20.09400 1.000 94.79000 C ? A ? 281 0 + ATOM 2045 OE1 . GLN A 281 ? 13.24000 12.24600 -20.53100 1.000 94.79000 O ? A ? 281 0 + ATOM 2046 NE2 . GLN A 281 ? 11.08600 12.11100 -20.80300 1.000 94.79000 N ? A ? 281 0 + ATOM 2047 N . VAL A 282 ? 14.65800 8.20200 -16.36100 1.000 95.86000 N ? A ? 282 0 + ATOM 2048 CA . VAL A 282 ? 15.90800 7.50900 -16.04000 1.000 95.86000 C ? A ? 282 0 + ATOM 2049 C . VAL A 282 ? 16.49300 6.97100 -17.33700 1.000 95.86000 C ? A ? 282 0 + ATOM 2050 O . VAL A 282 ? 15.80300 6.29400 -18.10000 1.000 95.86000 O ? A ? 282 0 + ATOM 2051 CB . VAL A 282 ? 15.69700 6.39500 -14.99900 1.000 95.86000 C ? A ? 282 0 + ATOM 2052 CG1 . VAL A 282 ? 17.03300 5.75500 -14.59600 1.000 95.86000 C ? A ? 282 0 + ATOM 2053 CG2 . VAL A 282 ? 15.04100 6.93800 -13.72300 1.000 95.86000 C ? A ? 282 0 + ATOM 2054 N . ASN A 283 ? 17.76100 7.27800 -17.59300 1.000 96.09000 N ? A ? 283 0 + ATOM 2055 CA . ASN A 283 ? 18.42800 6.86200 -18.81900 1.000 96.09000 C ? A ? 283 0 + ATOM 2056 C . ASN A 283 ? 18.93300 5.42500 -18.68200 1.000 96.09000 C ? A ? 283 0 + ATOM 2057 O . ASN A 283 ? 19.63000 5.08800 -17.72400 1.000 96.09000 O ? A ? 283 0 + ATOM 2058 CB . ASN A 283 ? 19.56100 7.83800 -19.16800 1.000 96.09000 C ? A ? 283 0 + ATOM 2059 CG . ASN A 283 ? 19.07000 9.23700 -19.49900 1.000 96.09000 C ? A ? 283 0 + ATOM 2060 OD1 . ASN A 283 ? 17.89500 9.54700 -19.50600 1.000 96.09000 O ? A ? 283 0 + ATOM 2061 ND2 . ASN A 283 ? 19.97500 10.15100 -19.75100 1.000 96.09000 N ? A ? 283 0 + ATOM 2062 N . PHE A 284 ? 18.62300 4.59700 -19.67400 1.000 95.39000 N ? A ? 284 0 + ATOM 2063 CA . PHE A 284 ? 19.15300 3.25100 -19.81400 1.000 95.39000 C ? A ? 284 0 + ATOM 2064 C . PHE A 284 ? 20.06700 3.17300 -21.03100 1.000 95.39000 C ? A ? 284 0 + ATOM 2065 O . PHE A 284 ? 19.65100 3.45600 -22.15500 1.000 95.39000 O ? A ? 284 0 + ATOM 2066 CB . PHE A 284 ? 18.00700 2.24800 -19.91800 1.000 95.39000 C ? A ? 284 0 + ATOM 2067 CG . PHE A 284 ? 18.48600 0.81500 -19.96000 1.000 95.39000 C ? A ? 284 0 + ATOM 2068 CD1 . PHE A 284 ? 18.52900 0.12800 -21.18600 1.000 95.39000 C ? A ? 284 0 + ATOM 2069 CD2 . PHE A 284 ? 18.93600 0.18300 -18.78400 1.000 95.39000 C ? A ? 284 0 + ATOM 2070 CE1 . PHE A 284 ? 19.02100 -1.18600 -21.23600 1.000 95.39000 C ? A ? 284 0 + ATOM 2071 CE2 . PHE A 284 ? 19.42200 -1.13500 -18.83400 1.000 95.39000 C ? A ? 284 0 + ATOM 2072 CZ . PHE A 284 ? 19.46700 -1.81700 -20.06300 1.000 95.39000 C ? A ? 284 0 + ATOM 2073 N . HIS A 285 ? 21.31300 2.76900 -20.80600 1.000 93.79000 N ? A ? 285 0 + ATOM 2074 CA . HIS A 285 ? 22.28400 2.55300 -21.86900 1.000 93.79000 C ? A ? 285 0 + ATOM 2075 C . HIS A 285 ? 22.23900 1.09100 -22.29700 1.000 93.79000 C ? A ? 285 0 + ATOM 2076 O . HIS A 285 ? 22.50300 0.19300 -21.49500 1.000 93.79000 O ? A ? 285 0 + ATOM 2077 CB . HIS A 285 ? 23.67700 2.97500 -21.39200 1.000 93.79000 C ? A ? 285 0 + ATOM 2078 CG . HIS A 285 ? 23.78200 4.46000 -21.15600 1.000 93.79000 C ? A ? 285 0 + ATOM 2079 ND1 . HIS A 285 ? 24.24400 5.38500 -22.06100 1.000 93.79000 N ? A ? 285 0 + ATOM 2080 CD2 . HIS A 285 ? 23.40100 5.14800 -20.03400 1.000 93.79000 C ? A ? 285 0 + ATOM 2081 CE1 . HIS A 285 ? 24.14100 6.60100 -21.50200 1.000 93.79000 C ? A ? 285 0 + ATOM 2082 NE2 . HIS A 285 ? 23.63400 6.50900 -20.26400 1.000 93.79000 N ? A ? 285 0 + ATOM 2083 N . THR A 286 ? 21.90700 0.85600 -23.56200 1.000 92.25000 N ? A ? 286 0 + ATOM 2084 CA . THR A 286 ? 21.95800 -0.49100 -24.13300 1.000 92.25000 C ? A ? 286 0 + ATOM 2085 C . THR A 286 ? 23.39700 -0.92300 -24.38900 1.000 92.25000 C ? A ? 286 0 + ATOM 2086 O . THR A 286 ? 24.33500 -0.12100 -24.39000 1.000 92.25000 O ? A ? 286 0 + ATOM 2087 CB . THR A 286 ? 21.13200 -0.60600 -25.41600 1.000 92.25000 C ? A ? 286 0 + ATOM 2088 OG1 . THR A 286 ? 21.63900 0.28000 -26.37400 1.000 92.25000 O ? A ? 286 0 + ATOM 2089 CG2 . THR A 286 ? 19.66400 -0.29400 -25.14700 1.000 92.25000 C ? A ? 286 0 + ATOM 2090 N . VAL A 287 ? 23.58100 -2.22500 -24.60000 1.000 89.62000 N ? A ? 287 0 + ATOM 2091 CA . VAL A 287 ? 24.88200 -2.77600 -24.98100 1.000 89.62000 C ? A ? 287 0 + ATOM 2092 C . VAL A 287 ? 25.31600 -2.23700 -26.35200 1.000 89.62000 C ? A ? 287 0 + ATOM 2093 O . VAL A 287 ? 24.45700 -1.99300 -27.20300 1.000 89.62000 O ? A ? 287 0 + ATOM 2094 CB . VAL A 287 ? 24.87700 -4.31400 -24.96900 1.000 89.62000 C ? A ? 287 0 + ATOM 2095 CG1 . VAL A 287 ? 24.62400 -4.83100 -23.54700 1.000 89.62000 C ? A ? 287 0 + ATOM 2096 CG2 . VAL A 287 ? 23.83600 -4.93000 -25.91500 1.000 89.62000 C ? A ? 287 0 + ATOM 2097 N . PRO A 288 ? 26.62600 -2.06000 -26.60600 1.000 89.96000 N ? A ? 288 0 + ATOM 2098 CA . PRO A 288 ? 27.12200 -1.67500 -27.92400 1.000 89.96000 C ? A ? 288 0 + ATOM 2099 C . PRO A 288 ? 26.65500 -2.63700 -29.02100 1.000 89.96000 C ? A ? 288 0 + ATOM 2100 O . PRO A 288 ? 26.51000 -3.83800 -28.78800 1.000 89.96000 O ? A ? 288 0 + ATOM 2101 CB . PRO A 288 ? 28.64900 -1.66800 -27.81100 1.000 89.96000 C ? A ? 288 0 + ATOM 2102 CG . PRO A 288 ? 28.89300 -1.43700 -26.32100 1.000 89.96000 C ? A ? 288 0 + ATOM 2103 CD . PRO A 288 ? 27.72800 -2.17100 -25.66300 1.000 89.96000 C ? A ? 288 0 + ATOM 2104 N . CYS A 289 ? 26.45100 -2.11700 -30.23100 1.000 90.36000 N ? A ? 289 0 + ATOM 2105 CA . CYS A 289 ? 26.15100 -2.96200 -31.38100 1.000 90.36000 C ? A ? 289 0 + ATOM 2106 C . CYS A 289 ? 27.32300 -3.86900 -31.75000 1.000 90.36000 C ? A ? 289 0 + ATOM 2107 O . CYS A 289 ? 28.48800 -3.53100 -31.53100 1.000 90.36000 O ? A ? 289 0 + ATOM 2108 CB . CYS A 289 ? 25.72500 -2.10900 -32.57700 1.000 90.36000 C ? A ? 289 0 + ATOM 2109 SG . CYS A 289 ? 24.12000 -1.31200 -32.38200 1.000 90.36000 S ? A ? 289 0 + ATOM 2110 N . ALA A 290 ? 26.99700 -5.00900 -32.36200 1.000 88.26000 N ? A ? 290 0 + ATOM 2111 CA . ALA A 290 ? 27.99800 -5.84400 -33.00400 1.000 88.26000 C ? A ? 290 0 + ATOM 2112 C . ALA A 290 ? 28.74400 -5.01500 -34.07000 1.000 88.26000 C ? A ? 290 0 + ATOM 2113 O . ALA A 290 ? 28.08600 -4.30200 -34.83700 1.000 88.26000 O ? A ? 290 0 + ATOM 2114 CB . ALA A 290 ? 27.32400 -7.07800 -33.61100 1.000 88.26000 C ? A ? 290 0 + ATOM 2115 N . PRO A 291 ? 30.08500 -5.08600 -34.12800 1.000 89.12000 N ? A ? 291 0 + ATOM 2116 CA . PRO A 291 ? 30.85400 -4.37200 -35.13600 1.000 89.12000 C ? A ? 291 0 + ATOM 2117 C . PRO A 291 ? 30.38000 -4.72000 -36.55700 1.000 89.12000 C ? A ? 291 0 + ATOM 2118 O . PRO A 291 ? 30.23800 -5.90900 -36.86600 1.000 89.12000 O ? A ? 291 0 + ATOM 2119 CB . PRO A 291 ? 32.30300 -4.79000 -34.90800 1.000 89.12000 C ? A ? 291 0 + ATOM 2120 CG . PRO A 291 ? 32.35600 -5.20600 -33.44400 1.000 89.12000 C ? A ? 291 0 + ATOM 2121 CD . PRO A 291 ? 30.96800 -5.79000 -33.20900 1.000 89.12000 C ? A ? 291 0 + ATOM 2122 N . PRO A 292 ? 30.10100 -3.72800 -37.42100 1.000 89.18000 N ? A ? 292 0 + ATOM 2123 CA . PRO A 292 ? 29.67000 -3.99700 -38.78400 1.000 89.18000 C ? A ? 292 0 + ATOM 2124 C . PRO A 292 ? 30.83300 -4.54700 -39.62200 1.000 89.18000 C ? A ? 292 0 + ATOM 2125 O . PRO A 292 ? 31.99400 -4.29800 -39.33500 1.000 89.18000 O ? A ? 292 0 + ATOM 2126 CB . PRO A 292 ? 29.14300 -2.65800 -39.30700 1.000 89.18000 C ? A ? 292 0 + ATOM 2127 CG . PRO A 292 ? 29.99500 -1.63300 -38.55700 1.000 89.18000 C ? A ? 292 0 + ATOM 2128 CD . PRO A 292 ? 30.23200 -2.29300 -37.19800 1.000 89.18000 C ? A ? 292 0 + ATOM 2129 N . ASN A 293 ? 30.52200 -5.27700 -40.69600 1.000 89.26000 N ? A ? 293 0 + ATOM 2130 CA . ASN A 293 ? 31.47600 -5.60800 -41.76700 1.000 89.26000 C ? A ? 293 0 + ATOM 2131 C . ASN A 293 ? 32.83200 -6.18400 -41.31400 1.000 89.26000 C ? A ? 293 0 + ATOM 2132 O . ASN A 293 ? 33.86200 -5.85900 -41.90800 1.000 89.26000 O ? A ? 293 0 + ATOM 2133 CB . ASN A 293 ? 31.64000 -4.38200 -42.68000 1.000 89.26000 C ? A ? 293 0 + ATOM 2134 CG . ASN A 293 ? 30.33600 -3.93700 -43.29700 1.000 89.26000 C ? A ? 293 0 + ATOM 2135 OD1 . ASN A 293 ? 29.48200 -4.72900 -43.66000 1.000 89.26000 O ? A ? 293 0 + ATOM 2136 ND2 . ASN A 293 ? 30.13400 -2.64900 -43.42800 1.000 89.26000 N ? A ? 293 0 + ATOM 2137 N . LEU A 294 ? 32.83500 -7.06500 -40.30600 1.000 90.46000 N ? A ? 294 0 + ATOM 2138 CA . LEU A 294 ? 34.05400 -7.74100 -39.86900 1.000 90.46000 C ? A ? 294 0 + ATOM 2139 C . LEU A 294 ? 34.74100 -8.41900 -41.06400 1.000 90.46000 C ? A ? 294 0 + ATOM 2140 O . LEU A 294 ? 34.20500 -9.36000 -41.65400 1.000 90.46000 O ? A ? 294 0 + ATOM 2141 CB . LEU A 294 ? 33.73200 -8.75700 -38.76000 1.000 90.46000 C ? A ? 294 0 + ATOM 2142 CG . LEU A 294 ? 34.98100 -9.49400 -38.23200 1.000 90.46000 C ? A ? 294 0 + ATOM 2143 CD1 . LEU A 294 ? 35.93000 -8.55500 -37.48400 1.000 90.46000 C ? A ? 294 0 + ATOM 2144 CD2 . LEU A 294 ? 34.56600 -10.61600 -37.28100 1.000 90.46000 C ? A ? 294 0 + ATOM 2145 N . SER A 295 ? 35.94500 -7.96400 -41.39300 1.000 90.78000 N ? A ? 295 0 + ATOM 2146 CA . SER A 295 ? 36.77100 -8.54500 -42.44400 1.000 90.78000 C ? A ? 295 0 + ATOM 2147 C . SER A 295 ? 38.15200 -8.90600 -41.90800 1.000 90.78000 C ? A ? 295 0 + ATOM 2148 O . SER A 295 ? 38.71600 -8.22400 -41.04800 1.000 90.78000 O ? A ? 295 0 + ATOM 2149 CB . SER A 295 ? 36.81400 -7.64400 -43.68000 1.000 90.78000 C ? A ? 295 0 + ATOM 2150 OG . SER A 295 ? 37.69600 -6.56500 -43.51100 1.000 90.78000 O ? A ? 295 0 + ATOM 2151 N . VAL A 296 ? 38.68200 -10.02800 -42.39800 1.000 91.50000 N ? A ? 296 0 + ATOM 2152 CA . VAL A 296 ? 39.95300 -10.59900 -41.94900 1.000 91.50000 C ? A ? 296 0 + ATOM 2153 C . VAL A 296 ? 40.87700 -10.73900 -43.15100 1.000 91.50000 C ? A ? 296 0 + ATOM 2154 O . VAL A 296 ? 40.60000 -11.51200 -44.06600 1.000 91.50000 O ? A ? 296 0 + ATOM 2155 CB . VAL A 296 ? 39.74600 -11.95100 -41.23300 1.000 91.50000 C ? A ? 296 0 + ATOM 2156 CG1 . VAL A 296 ? 41.07200 -12.46300 -40.65400 1.000 91.50000 C ? A ? 296 0 + ATOM 2157 CG2 . VAL A 296 ? 38.73800 -11.84300 -40.07900 1.000 91.50000 C ? A ? 296 0 + ATOM 2158 N . ALA A 297 ? 41.98800 -10.00700 -43.13600 1.000 91.28000 N ? A ? 297 0 + ATOM 2159 CA . ALA A 297 ? 43.06000 -10.12100 -44.11600 1.000 91.28000 C ? A ? 297 0 + ATOM 2160 C . ALA A 297 ? 44.22100 -10.91600 -43.50600 1.000 91.28000 C ? A ? 297 0 + ATOM 2161 O . ALA A 297 ? 44.86600 -10.46800 -42.55800 1.000 91.28000 O ? A ? 297 0 + ATOM 2162 CB . ALA A 297 ? 43.46700 -8.71600 -44.57100 1.000 91.28000 C ? A ? 297 0 + ATOM 2163 N . VAL A 298 ? 44.47800 -12.11700 -44.02600 1.000 91.86000 N ? A ? 298 0 + ATOM 2164 CA . VAL A 298 ? 45.54200 -13.00000 -43.52700 1.000 91.86000 C ? A ? 298 0 + ATOM 2165 C . VAL A 298 ? 46.80700 -12.80900 -44.35800 1.000 91.86000 C ? A ? 298 0 + ATOM 2166 O . VAL A 298 ? 46.80200 -13.05500 -45.56200 1.000 91.86000 O ? A ? 298 0 + ATOM 2167 CB . VAL A 298 ? 45.10200 -14.47600 -43.51300 1.000 91.86000 C ? A ? 298 0 + ATOM 2168 CG1 . VAL A 298 ? 46.19700 -15.37100 -42.91500 1.000 91.86000 C ? A ? 298 0 + ATOM 2169 CG2 . VAL A 298 ? 43.82800 -14.66700 -42.67700 1.000 91.86000 C ? A ? 298 0 + ATOM 2170 N . GLN A 299 ? 47.90500 -12.43600 -43.70500 1.000 90.20000 N ? A ? 299 0 + ATOM 2171 CA . GLN A 299 ? 49.22300 -12.33000 -44.32100 1.000 90.20000 C ? A ? 299 0 + ATOM 2172 C . GLN A 299 ? 50.02900 -13.59800 -44.01900 1.000 90.20000 C ? A ? 299 0 + ATOM 2173 O . GLN A 299 ? 50.57300 -13.77700 -42.92500 1.000 90.20000 O ? A ? 299 0 + ATOM 2174 CB . GLN A 299 ? 49.91100 -11.04100 -43.84400 1.000 90.20000 C ? A ? 299 0 + ATOM 2175 CG . GLN A 299 ? 51.13300 -10.68100 -44.70800 1.000 90.20000 C ? A ? 299 0 + ATOM 2176 CD . GLN A 299 ? 50.76800 -10.23500 -46.12500 1.000 90.20000 C ? A ? 299 0 + ATOM 2177 OE1 . GLN A 299 ? 49.62200 -9.99800 -46.46600 1.000 90.20000 O ? A ? 299 0 + ATOM 2178 NE2 . GLN A 299 ? 51.72200 -10.12200 -47.02000 1.000 90.20000 N ? A ? 299 0 + ATOM 2179 N . CYS A 300 ? 50.09000 -14.50300 -45.00100 1.000 89.51000 N ? A ? 300 0 + ATOM 2180 CA . CYS A 300 ? 50.71500 -15.81900 -44.83700 1.000 89.51000 C ? A ? 300 0 + ATOM 2181 C . CYS A 300 ? 52.22700 -15.73000 -44.57300 1.000 89.51000 C ? A ? 300 0 + ATOM 2182 O . CYS A 300 ? 52.74700 -16.50300 -43.76800 1.000 89.51000 O ? A ? 300 0 + ATOM 2183 CB . CYS A 300 ? 50.41700 -16.68000 -46.07300 1.000 89.51000 C ? A ? 300 0 + ATOM 2184 SG . CYS A 300 ? 48.64200 -17.06800 -46.15600 1.000 89.51000 S ? A ? 300 0 + ATOM 2185 N . ASP A 301 ? 52.91300 -14.76100 -45.18600 1.000 90.56000 N ? A ? 301 0 + ATOM 2186 CA . ASP A 301 ? 54.37200 -14.61500 -45.08400 1.000 90.56000 C ? A ? 301 0 + ATOM 2187 C . ASP A 301 ? 54.82900 -14.25800 -43.66500 1.000 90.56000 C ? A ? 301 0 + ATOM 2188 O . ASP A 301 ? 55.81000 -14.79700 -43.15500 1.000 90.56000 O ? A ? 301 0 + ATOM 2189 CB . ASP A 301 ? 54.84900 -13.52700 -46.05700 1.000 90.56000 C ? A ? 301 0 + ATOM 2190 CG . ASP A 301 ? 54.47600 -13.81900 -47.51000 1.000 90.56000 C ? A ? 301 0 + ATOM 2191 OD1 . ASP A 301 ? 54.48200 -15.01100 -47.88700 1.000 90.56000 O ? A ? 301 0 + ATOM 2192 OD2 . ASP A 301 ? 54.13000 -12.83700 -48.20000 1.000 90.56000 O ? A ? 301 0 + ATOM 2193 N . THR A 302 ? 54.08800 -13.37000 -43.00000 1.000 91.35000 N ? A ? 302 0 + ATOM 2194 CA . THR A 302 ? 54.38400 -12.89800 -41.64000 1.000 91.35000 C ? A ? 302 0 + ATOM 2195 C . THR A 302 ? 53.66300 -13.70400 -40.56400 1.000 91.35000 C ? A ? 302 0 + ATOM 2196 O . THR A 302 ? 53.91100 -13.48700 -39.38000 1.000 91.35000 O ? A ? 302 0 + ATOM 2197 CB . THR A 302 ? 54.03300 -11.41200 -41.49700 1.000 91.35000 C ? A ? 302 0 + ATOM 2198 OG1 . THR A 302 ? 52.71100 -11.20600 -41.92800 1.000 91.35000 O ? A ? 302 0 + ATOM 2199 CG2 . THR A 302 ? 54.92500 -10.53400 -42.37500 1.000 91.35000 C ? A ? 302 0 + ATOM 2200 N . ARG A 303 ? 52.77800 -14.63500 -40.95200 1.000 88.38000 N ? A ? 303 0 + ATOM 2201 CA . ARG A 303 ? 51.87700 -15.37000 -40.04600 1.000 88.38000 C ? A ? 303 0 + ATOM 2202 C . ARG A 303 ? 51.03000 -14.43600 -39.17000 1.000 88.38000 C ? A ? 303 0 + ATOM 2203 O . ARG A 303 ? 50.78500 -14.72800 -38.00200 1.000 88.38000 O ? A ? 303 0 + ATOM 2204 CB . ARG A 303 ? 52.65600 -16.40000 -39.20800 1.000 88.38000 C ? A ? 303 0 + ATOM 2205 CG . ARG A 303 ? 53.48800 -17.37800 -40.04200 1.000 88.38000 C ? A ? 303 0 + ATOM 2206 CD . ARG A 303 ? 54.20900 -18.33100 -39.08700 1.000 88.38000 C ? A ? 303 0 + ATOM 2207 NE . ARG A 303 ? 55.01500 -19.31800 -39.82200 1.000 88.38000 N ? A ? 303 0 + ATOM 2208 CZ . ARG A 303 ? 55.71500 -20.30000 -39.28700 1.000 88.38000 C ? A ? 303 0 + ATOM 2209 NH1 . ARG A 303 ? 55.76700 -20.48200 -37.99500 1.000 88.38000 N ? A ? 303 0 + ATOM 2210 NH2 . ARG A 303 ? 56.37800 -21.12400 -40.04700 1.000 88.38000 N ? A ? 303 0 + ATOM 2211 N . THR A 304 ? 50.58300 -13.31100 -39.72600 1.000 93.03000 N ? A ? 304 0 + ATOM 2212 CA . THR A 304 ? 49.73500 -12.32800 -39.03200 1.000 93.03000 C ? A ? 304 0 + ATOM 2213 C . THR A 304 ? 48.37200 -12.21400 -39.70700 1.000 93.03000 C ? A ? 304 0 + ATOM 2214 O . THR A 304 ? 48.25500 -12.43200 -40.90900 1.000 93.03000 O ? A ? 304 0 + ATOM 2215 CB . THR A 304 ? 50.40200 -10.94600 -38.93800 1.000 93.03000 C ? A ? 304 0 + ATOM 2216 OG1 . THR A 304 ? 50.74400 -10.45000 -40.21200 1.000 93.03000 O ? A ? 304 0 + ATOM 2217 CG2 . THR A 304 ? 51.68500 -10.97300 -38.10900 1.000 93.03000 C ? A ? 304 0 + ATOM 2218 N . ALA A 305 ? 47.34300 -11.82600 -38.95600 1.000 91.49000 N ? A ? 305 0 + ATOM 2219 CA . ALA A 305 ? 46.03200 -11.48000 -39.50100 1.000 91.49000 C ? A ? 305 0 + ATOM 2220 C . ALA A 305 ? 45.65200 -10.05900 -39.07200 1.000 91.49000 C ? A ? 305 0 + ATOM 2221 O . ALA A 305 ? 45.80500 -9.70100 -37.90500 1.000 91.49000 O ? A ? 305 0 + ATOM 2222 CB . ALA A 305 ? 45.00000 -12.52300 -39.05700 1.000 91.49000 C ? A ? 305 0 + ATOM 2223 N . THR A 306 ? 45.15800 -9.26100 -40.01300 1.000 90.74000 N ? A ? 306 0 + ATOM 2224 CA . THR A 306 ? 44.62600 -7.92000 -39.76700 1.000 90.74000 C ? A ? 306 0 + ATOM 2225 C . THR A 306 ? 43.10700 -7.99500 -39.80500 1.000 90.74000 C ? A ? 306 0 + ATOM 2226 O . THR A 306 ? 42.52900 -8.43600 -40.79700 1.000 90.74000 O ? A ? 306 0 + ATOM 2227 CB . THR A 306 ? 45.15900 -6.91300 -40.79600 1.000 90.74000 C ? A ? 306 0 + ATOM 2228 OG1 . THR A 306 ? 46.56900 -6.94400 -40.81400 1.000 90.74000 O ? A ? 306 0 + ATOM 2229 CG2 . THR A 306 ? 44.75800 -5.47700 -40.46100 1.000 90.74000 C ? A ? 306 0 + ATOM 2230 N . LEU A 307 ? 42.46500 -7.58900 -38.71200 1.000 92.04000 N ? A ? 307 0 + ATOM 2231 CA . LEU A 307 ? 41.01300 -7.50700 -38.60100 1.000 92.04000 C ? A ? 307 0 + ATOM 2232 C . LEU A 307 ? 40.58500 -6.05100 -38.81900 1.000 92.04000 C ? A ? 307 0 + ATOM 2233 O . LEU A 307 ? 41.24900 -5.14200 -38.32300 1.000 92.04000 O ? A ? 307 0 + ATOM 2234 CB . LEU A 307 ? 40.54100 -8.04000 -37.23400 1.000 92.04000 C ? A ? 307 0 + ATOM 2235 CG . LEU A 307 ? 40.76800 -9.54600 -36.98600 1.000 92.04000 C ? A ? 307 0 + ATOM 2236 CD1 . LEU A 307 ? 42.17000 -9.86900 -36.45400 1.000 92.04000 C ? A ? 307 0 + ATOM 2237 CD2 . LEU A 307 ? 39.77700 -10.05400 -35.93800 1.000 92.04000 C ? A ? 307 0 + ATOM 2238 N . SER A 308 ? 39.48600 -5.83300 -39.53700 1.000 89.41000 N ? A ? 308 0 + ATOM 2239 CA . SER A 308 ? 38.83100 -4.52300 -39.64800 1.000 89.41000 C ? A ? 308 0 + ATOM 2240 C . SER A 308 ? 37.32100 -4.66700 -39.49900 1.000 89.41000 C ? A ? 308 0 + ATOM 2241 O . SER A 308 ? 36.76700 -5.70500 -39.86600 1.000 89.41000 O ? A ? 308 0 + ATOM 2242 CB . SER A 308 ? 39.21000 -3.81000 -40.94900 1.000 89.41000 C ? A ? 308 0 + ATOM 2243 OG . SER A 308 ? 38.79100 -4.52800 -42.08600 1.000 89.41000 O ? A ? 308 0 + ATOM 2244 N . TRP A 309 ? 36.69100 -3.65900 -38.90300 1.000 89.27000 N ? A ? 309 0 + ATOM 2245 CA . TRP A 309 ? 35.26100 -3.55800 -38.61800 1.000 89.27000 C ? A ? 309 0 + ATOM 2246 C . TRP A 309 ? 34.86900 -2.08300 -38.47900 1.000 89.27000 C ? A ? 309 0 + ATOM 2247 O . TRP A 309 ? 35.79200 -1.25800 -38.27100 1.000 89.27000 O ? A ? 309 0 + ATOM 2248 CB . TRP A 309 ? 34.93900 -4.33400 -37.33500 1.000 89.27000 C ? A ? 309 0 + ATOM 2249 CG . TRP A 309 ? 35.60000 -3.82400 -36.08600 1.000 89.27000 C ? A ? 309 0 + ATOM 2250 CD1 . TRP A 309 ? 35.16400 -2.78300 -35.34300 1.000 89.27000 C ? A ? 309 0 + ATOM 2251 CD2 . TRP A 309 ? 36.87100 -4.21900 -35.49000 1.000 89.27000 C ? A ? 309 0 + ATOM 2252 NE1 . TRP A 309 ? 36.01000 -2.57300 -34.27400 1.000 89.27000 N ? A ? 309 0 + ATOM 2253 CE2 . TRP A 309 ? 37.10100 -3.41100 -34.33500 1.000 89.27000 C ? A ? 309 0 + ATOM 2254 CE3 . TRP A 309 ? 37.88000 -5.14300 -35.83800 1.000 89.27000 C ? A ? 309 0 + ATOM 2255 CZ2 . TRP A 309 ? 38.25800 -3.52600 -33.55300 1.000 89.27000 C ? A ? 309 0 + ATOM 2256 CZ3 . TRP A 309 ? 39.05500 -5.25100 -35.06900 1.000 89.27000 C ? A ? 309 0 + ATOM 2257 CH2 . TRP A 309 ? 39.24400 -4.45200 -33.92800 1.000 89.27000 C ? A ? 309 0 + ATOM 2258 OXT . TRP A 309 ? 33.65700 -1.80300 -38.56700 1.000 89.27000 O ? A ? 309 0 + diff --git a/mmtbx/regression/pdbs/pae_model.pdb b/mmtbx/regression/pdbs/pae_model.pdb index 332ea54198..6b0bb65a14 100644 --- a/mmtbx/regression/pdbs/pae_model.pdb +++ b/mmtbx/regression/pdbs/pae_model.pdb @@ -1,2328 +1,2260 @@ -HEADER 01-JUL-21 -TITLE ALPHAFOLD V2.0 PREDICTION FOR FIBRONECTIN TYPE III DOMAIN-CONTAINING -TITLE 2 7B (A0A0J9YIY3) -COMPND MOL_ID: 1; -COMPND 2 MOLECULE: FIBRONECTIN TYPE III DOMAIN-CONTAINING 7B; -COMPND 3 CHAIN: A -SOURCE MOL_ID: 1; -SOURCE 2 ORGANISM_SCIENTIFIC: DANIO RERIO; -SOURCE 3 ORGANISM_TAXID: 7955 -REMARK 1 -REMARK 1 REFERENCE 1 -REMARK 1 AUTH JOHN JUMPER, RICHARD EVANS, ALEXANDER PRITZEL, TIM GREEN, -REMARK 1 AUTH 2 MICHAEL FIGURNOV, OLAF RONNEBERGER, KATHRYN TUNYASUVUNAKOOL, -REMARK 1 AUTH 3 RUSS BATES, AUGUSTIN ZIDEK, ANNA POTAPENKO, ALEX BRIDGLAND, -REMARK 1 AUTH 4 CLEMENS MEYER, SIMON A A KOHL, ANDREW J BALLARD, -REMARK 1 AUTH 5 ANDREW COWIE, BERNARDINO ROMERA-PAREDES, STANISLAV NIKOLOV, -REMARK 1 AUTH 6 RISHUB JAIN, JONAS ADLER, TREVOR BACK, STIG PETERSEN, -REMARK 1 AUTH 7 DAVID REIMAN, ELLEN CLANCY, MICHAL ZIELINSKI, -REMARK 1 AUTH 8 MARTIN STEINEGGER, MICHALINA PACHOLSKA, TAMAS BERGHAMMER, -REMARK 1 AUTH 9 DAVID SILVER, ORIOL VINYALS, ANDREW W SENIOR, -REMARK 1 AUTH10 KORAY KAVUKCUOGLU, PUSHMEET KOHLI, DEMIS HASSABIS -REMARK 1 TITL HIGHLY ACCURATE PROTEIN STRUCTURE PREDICTION WITH ALPHAFOLD -REMARK 1 REF NATURE 2021 -REMARK 1 -REMARK 1 DISCLAIMERS -REMARK 1 ALPHAFOLD DATA, COPYRIGHT (2021) DEEPMIND TECHNOLOGIES LIMITED. THE -REMARK 1 INFORMATION PROVIDED IS THEORETICAL MODELLING ONLY AND CAUTION SHOULD -REMARK 1 BE EXERCISED IN ITS USE. IT IS PROVIDED "AS-IS" WITHOUT ANY WARRANTY -REMARK 1 OF ANY KIND, WHETHER EXPRESSED OR IMPLIED. NO WARRANTY IS GIVEN THAT -REMARK 1 USE OF THE INFORMATION SHALL NOT INFRINGE THE RIGHTS OF ANY THIRD -REMARK 1 PARTY. THE INFORMATION IS NOT INTENDED TO BE A SUBSTITUTE FOR -REMARK 1 PROFESSIONAL MEDICAL ADVICE, DIAGNOSIS, OR TREATMENT, AND DOES NOT -REMARK 1 CONSTITUTE MEDICAL OR OTHER PROFESSIONAL ADVICE. IT IS AVAILABLE FOR -REMARK 1 ACADEMIC AND COMMERCIAL PURPOSES, UNDER CC-BY 4.0 LICENCE. -DBREF XXXX A 1 309 UNP A0A0J9YIY3 A0A0J9YIY3_DANRE 1 309 -SEQRES 1 A 309 SER TYR SER VAL THR VAL THR SER LEU ARG GLY ASP CYS -SEQRES 2 A 309 GLU SER GLN PRO SER THR ALA VAL ASN VAL THR SER ALA -SEQRES 3 A 309 PRO CYS VAL PRO GLN GLY GLU ALA GLY ASN LEU ASP CYS -SEQRES 4 A 309 ILE THR ASN SER VAL TRP VAL THR TRP LEU GLN ALA LYS -SEQRES 5 A 309 GLY ALA LEU SER TYR SER VAL LEU ALA VAL GLU LYS GLN -SEQRES 6 A 309 GLY ALA ASN SER SER CYS SER ALA THR THR LEU ASN CYS -SEQRES 7 A 309 ASN VAL PRO GLY LEU GLN CYS GLY GLY THR TYR THR PHE -SEQRES 8 A 309 TYR VAL THR ALA LEU ASN SER PHE CYS GLN SER SER PRO -SEQRES 9 A 309 GLY THR SER PHE GLN ILE GLN THR ALA PRO CYS SER LEU -SEQRES 10 A 309 THR SER ILE THR ALA HIS THR ASP CYS TYR SER SER HIS -SEQRES 11 A 309 ILE THR VAL SER TRP GLN LEU ASN ASP ARG SER SER LEU -SEQRES 12 A 309 TYR VAL ALA SER ALA GLU GLY ASN ASP HIS SER ILE LEU -SEQRES 13 A 309 MET CYS ASN SER THR SER THR SER CYS ASP LEU ILE GLY -SEQRES 14 A 309 ALA ARG CYS GLY MET HIS TYR THR ILE ILE VAL SER ALA -SEQRES 15 A 309 SER SER ASP LYS CYS SER SER LEU ARG SER PRO PRO PHE -SEQRES 16 A 309 GLU MET SER THR ALA PRO CYS VAL PRO GLN ASN VAL VAL -SEQRES 17 A 309 LEU ASN SER MET CYS ASP SER ASN GLY MET MET ALA SER -SEQRES 18 A 309 TRP SER PRO SER LEU VAL ALA GLN SER TYR LEU LEU THR -SEQRES 19 A 309 ALA SER SER SER ASP GLY ASP VAL LEU THR CYS LYS SER -SEQRES 20 A 309 THR THR ASN ASN CYS THR LEU PRO HIS LEU HIS CYS GLY -SEQRES 21 A 309 GLN VAL TYR ASN VAL SER ILE THR ALA SER ASN ASN ASN -SEQRES 22 A 309 CYS THR SER PRO ALA SER GLN GLN VAL ASN PHE HIS THR -SEQRES 23 A 309 VAL PRO CYS ALA PRO PRO ASN LEU SER VAL ALA VAL GLN -SEQRES 24 A 309 CYS ASP THR ARG THR ALA THR LEU SER TRP -CRYST1 1.000 1.000 1.000 90.00 90.00 90.00 P 1 -ORIGX1 1.000000 0.000000 0.000000 0.00000 -ORIGX2 0.000000 1.000000 0.000000 0.00000 -ORIGX3 0.000000 0.000000 1.000000 0.00000 -SCALE1 1.000000 0.000000 0.000000 0.00000 -SCALE2 0.000000 1.000000 0.000000 0.00000 -SCALE3 0.000000 0.000000 1.000000 0.00000 -MODEL 0 -ATOM 1 N SER A 1 2.974 -27.458 18.524 1.00 72.44 N -ATOM 2 CA SER A 1 3.371 -28.054 17.239 1.00 72.44 C -ATOM 3 C SER A 1 3.694 -29.508 17.470 1.00 72.44 C -ATOM 4 CB SER A 1 4.574 -27.320 16.655 1.00 72.44 C -ATOM 5 O SER A 1 4.317 -29.811 18.481 1.00 72.44 O -ATOM 6 OG SER A 1 4.284 -25.937 16.721 1.00 72.44 O -ATOM 7 N TYR A 2 3.239 -30.381 16.584 1.00 79.50 N -ATOM 8 CA TYR A 2 3.485 -31.816 16.617 1.00 79.50 C -ATOM 9 C TYR A 2 4.248 -32.201 15.353 1.00 79.50 C -ATOM 10 CB TYR A 2 2.158 -32.579 16.727 1.00 79.50 C -ATOM 11 O TYR A 2 4.013 -31.631 14.288 1.00 79.50 O -ATOM 12 CG TYR A 2 1.355 -32.241 17.969 1.00 79.50 C -ATOM 13 CD1 TYR A 2 1.585 -32.949 19.163 1.00 79.50 C -ATOM 14 CD2 TYR A 2 0.385 -31.218 17.930 1.00 79.50 C -ATOM 15 CE1 TYR A 2 0.848 -32.641 20.322 1.00 79.50 C -ATOM 16 CE2 TYR A 2 -0.344 -30.897 19.092 1.00 79.50 C -ATOM 17 OH TYR A 2 -0.830 -31.302 21.400 1.00 79.50 O -ATOM 18 CZ TYR A 2 -0.118 -31.612 20.287 1.00 79.50 C -ATOM 19 N SER A 3 5.164 -33.152 15.480 1.00 85.13 N -ATOM 20 CA SER A 3 5.852 -33.756 14.346 1.00 85.13 C -ATOM 21 C SER A 3 5.252 -35.143 14.151 1.00 85.13 C -ATOM 22 CB SER A 3 7.353 -33.795 14.630 1.00 85.13 C -ATOM 23 O SER A 3 5.326 -35.966 15.063 1.00 85.13 O -ATOM 24 OG SER A 3 8.061 -33.779 13.420 1.00 85.13 O -ATOM 25 N VAL A 4 4.569 -35.363 13.027 1.00 88.29 N -ATOM 26 CA VAL A 4 3.861 -36.618 12.742 1.00 88.29 C -ATOM 27 C VAL A 4 4.675 -37.427 11.745 1.00 88.29 C -ATOM 28 CB VAL A 4 2.423 -36.373 12.243 1.00 88.29 C -ATOM 29 O VAL A 4 5.026 -36.937 10.670 1.00 88.29 O -ATOM 30 CG1 VAL A 4 1.681 -37.692 11.977 1.00 88.29 C -ATOM 31 CG2 VAL A 4 1.606 -35.596 13.285 1.00 88.29 C -ATOM 32 N THR A 5 4.956 -38.674 12.104 1.00 91.73 N -ATOM 33 CA THR A 5 5.561 -39.684 11.238 1.00 91.73 C -ATOM 34 C THR A 5 4.639 -40.894 11.168 1.00 91.73 C -ATOM 35 CB THR A 5 6.956 -40.102 11.727 1.00 91.73 C -ATOM 36 O THR A 5 3.863 -41.156 12.087 1.00 91.73 O -ATOM 37 CG2 THR A 5 7.964 -38.959 11.647 1.00 91.73 C -ATOM 38 OG1 THR A 5 6.913 -40.519 13.071 1.00 91.73 O -ATOM 39 N VAL A 6 4.699 -41.622 10.056 1.00 91.60 N -ATOM 40 CA VAL A 6 3.927 -42.849 9.850 1.00 91.60 C -ATOM 41 C VAL A 6 4.900 -44.005 9.669 1.00 91.60 C -ATOM 42 CB VAL A 6 2.959 -42.707 8.659 1.00 91.60 C -ATOM 43 O VAL A 6 5.830 -43.917 8.866 1.00 91.60 O -ATOM 44 CG1 VAL A 6 2.123 -43.978 8.457 1.00 91.60 C -ATOM 45 CG2 VAL A 6 1.985 -41.538 8.871 1.00 91.60 C -ATOM 46 N THR A 7 4.679 -45.088 10.407 1.00 91.25 N -ATOM 47 CA THR A 7 5.348 -46.379 10.227 1.00 91.25 C -ATOM 48 C THR A 7 4.321 -47.404 9.759 1.00 91.25 C -ATOM 49 CB THR A 7 6.052 -46.853 11.510 1.00 91.25 C -ATOM 50 O THR A 7 3.162 -47.388 10.175 1.00 91.25 O -ATOM 51 CG2 THR A 7 7.289 -46.013 11.815 1.00 91.25 C -ATOM 52 OG1 THR A 7 5.196 -46.746 12.621 1.00 91.25 O -ATOM 53 N SER A 8 4.725 -48.283 8.846 1.00 88.71 N -ATOM 54 CA SER A 8 3.903 -49.420 8.425 1.00 88.71 C -ATOM 55 C SER A 8 4.278 -50.654 9.242 1.00 88.71 C -ATOM 56 CB SER A 8 4.011 -49.649 6.915 1.00 88.71 C -ATOM 57 O SER A 8 5.459 -50.870 9.519 1.00 88.71 O -ATOM 58 OG SER A 8 5.326 -49.971 6.514 1.00 88.71 O -ATOM 59 N LEU A 9 3.276 -51.448 9.626 1.00 91.87 N -ATOM 60 CA LEU A 9 3.443 -52.634 10.466 1.00 91.87 C -ATOM 61 C LEU A 9 2.850 -53.859 9.761 1.00 91.87 C -ATOM 62 CB LEU A 9 2.825 -52.339 11.849 1.00 91.87 C -ATOM 63 O LEU A 9 1.703 -53.832 9.308 1.00 91.87 O -ATOM 64 CG LEU A 9 3.264 -53.323 12.957 1.00 91.87 C -ATOM 65 CD1 LEU A 9 3.605 -52.568 14.241 1.00 91.87 C -ATOM 66 CD2 LEU A 9 2.147 -54.311 13.297 1.00 91.87 C -ATOM 67 N ARG A 10 3.636 -54.935 9.644 1.00 89.14 N -ATOM 68 CA ARG A 10 3.183 -56.239 9.131 1.00 89.14 C -ATOM 69 C ARG A 10 3.754 -57.346 10.015 1.00 89.14 C -ATOM 70 CB ARG A 10 3.582 -56.402 7.648 1.00 89.14 C -ATOM 71 O ARG A 10 4.943 -57.644 9.932 1.00 89.14 O -ATOM 72 CG ARG A 10 3.142 -57.767 7.084 1.00 89.14 C -ATOM 73 CD ARG A 10 3.586 -57.995 5.632 1.00 89.14 C -ATOM 74 NE ARG A 10 2.664 -57.394 4.648 1.00 89.14 N -ATOM 75 NH1 ARG A 10 3.728 -58.166 2.766 1.00 89.14 N -ATOM 76 NH2 ARG A 10 1.826 -57.018 2.560 1.00 89.14 N -ATOM 77 CZ ARG A 10 2.742 -57.527 3.335 1.00 89.14 C -ATOM 78 N GLY A 11 2.894 -57.981 10.811 1.00 88.64 N -ATOM 79 CA GLY A 11 3.334 -58.940 11.829 1.00 88.64 C -ATOM 80 C GLY A 11 4.232 -58.244 12.852 1.00 88.64 C -ATOM 81 O GLY A 11 3.866 -57.181 13.341 1.00 88.64 O -ATOM 82 N ASP A 12 5.420 -58.800 13.085 1.00 87.38 N -ATOM 83 CA ASP A 12 6.424 -58.253 14.011 1.00 87.38 C -ATOM 84 C ASP A 12 7.456 -57.328 13.328 1.00 87.38 C -ATOM 85 CB ASP A 12 7.120 -59.412 14.745 1.00 87.38 C -ATOM 86 O ASP A 12 8.468 -56.967 13.926 1.00 87.38 O -ATOM 87 CG ASP A 12 6.145 -60.338 15.477 1.00 87.38 C -ATOM 88 OD1 ASP A 12 5.191 -59.824 16.101 1.00 87.38 O -ATOM 89 OD2 ASP A 12 6.345 -61.569 15.370 1.00 87.38 O -ATOM 90 N CYS A 13 7.258 -56.966 12.054 1.00 86.80 N -ATOM 91 CA CYS A 13 8.167 -56.083 11.321 1.00 86.80 C -ATOM 92 C CYS A 13 7.599 -54.662 11.195 1.00 86.80 C -ATOM 93 CB CYS A 13 8.487 -56.682 9.943 1.00 86.80 C -ATOM 94 O CYS A 13 6.490 -54.473 10.684 1.00 86.80 O -ATOM 95 SG CYS A 13 9.324 -58.287 10.104 1.00 86.80 S -ATOM 96 N GLU A 14 8.405 -53.668 11.577 1.00 90.65 N -ATOM 97 CA GLU A 14 8.132 -52.236 11.406 1.00 90.65 C -ATOM 98 C GLU A 14 9.019 -51.633 10.307 1.00 90.65 C -ATOM 99 CB GLU A 14 8.344 -51.473 12.725 1.00 90.65 C -ATOM 100 O GLU A 14 10.201 -51.966 10.187 1.00 90.65 O -ATOM 101 CG GLU A 14 7.418 -51.963 13.847 1.00 90.65 C -ATOM 102 CD GLU A 14 7.434 -51.062 15.096 1.00 90.65 C -ATOM 103 OE1 GLU A 14 6.549 -51.263 15.957 1.00 90.65 O -ATOM 104 OE2 GLU A 14 8.302 -50.162 15.177 1.00 90.65 O -ATOM 105 N SER A 15 8.463 -50.733 9.492 1.00 89.93 N -ATOM 106 CA SER A 15 9.258 -49.942 8.546 1.00 89.93 C -ATOM 107 C SER A 15 10.002 -48.799 9.239 1.00 89.93 C -ATOM 108 CB SER A 15 8.391 -49.408 7.399 1.00 89.93 C -ATOM 109 O SER A 15 9.635 -48.366 10.328 1.00 89.93 O -ATOM 110 OG SER A 15 7.508 -48.371 7.805 1.00 89.93 O -ATOM 111 N GLN A 16 10.987 -48.216 8.550 1.00 89.52 N -ATOM 112 CA GLN A 16 11.506 -46.906 8.949 1.00 89.52 C -ATOM 113 C GLN A 16 10.369 -45.859 8.951 1.00 89.52 C -ATOM 114 CB GLN A 16 12.654 -46.477 8.021 1.00 89.52 C -ATOM 115 O GLN A 16 9.468 -45.953 8.104 1.00 89.52 O -ATOM 116 CG GLN A 16 13.911 -47.346 8.205 1.00 89.52 C -ATOM 117 CD GLN A 16 14.528 -47.221 9.598 1.00 89.52 C -ATOM 118 NE2 GLN A 16 15.164 -48.253 10.105 1.00 89.52 N -ATOM 119 OE1 GLN A 16 14.451 -46.199 10.258 1.00 89.52 O -ATOM 120 N PRO A 17 10.380 -44.882 9.877 1.00 90.04 N -ATOM 121 CA PRO A 17 9.409 -43.793 9.886 1.00 90.04 C -ATOM 122 C PRO A 17 9.461 -42.964 8.598 1.00 90.04 C -ATOM 123 CB PRO A 17 9.740 -42.942 11.118 1.00 90.04 C -ATOM 124 O PRO A 17 10.532 -42.738 8.034 1.00 90.04 O -ATOM 125 CG PRO A 17 10.508 -43.898 12.029 1.00 90.04 C -ATOM 126 CD PRO A 17 11.246 -44.799 11.045 1.00 90.04 C -ATOM 127 N SER A 18 8.304 -42.474 8.149 1.00 91.27 N -ATOM 128 CA SER A 18 8.226 -41.499 7.057 1.00 91.27 C -ATOM 129 C SER A 18 8.984 -40.205 7.383 1.00 91.27 C -ATOM 130 CB SER A 18 6.756 -41.184 6.739 1.00 91.27 C -ATOM 131 O SER A 18 9.278 -39.907 8.543 1.00 91.27 O -ATOM 132 OG SER A 18 6.153 -40.399 7.757 1.00 91.27 O -ATOM 133 N THR A 19 9.213 -39.362 6.371 1.00 90.71 N -ATOM 134 CA THR A 19 9.603 -37.964 6.607 1.00 90.71 C -ATOM 135 C THR A 19 8.577 -37.289 7.514 1.00 90.71 C -ATOM 136 CB THR A 19 9.710 -37.167 5.302 1.00 90.71 C -ATOM 137 O THR A 19 7.370 -37.428 7.298 1.00 90.71 O -ATOM 138 CG2 THR A 19 10.894 -37.632 4.456 1.00 90.71 C -ATOM 139 OG1 THR A 19 8.540 -37.335 4.534 1.00 90.71 O -ATOM 140 N ALA A 20 9.059 -36.578 8.529 1.00 88.71 N -ATOM 141 CA ALA A 20 8.205 -35.918 9.498 1.00 88.71 C -ATOM 142 C ALA A 20 7.451 -34.739 8.873 1.00 88.71 C -ATOM 143 CB ALA A 20 9.072 -35.482 10.675 1.00 88.71 C -ATOM 144 O ALA A 20 8.051 -33.874 8.234 1.00 88.71 O -ATOM 145 N VAL A 21 6.138 -34.686 9.097 1.00 86.44 N -ATOM 146 CA VAL A 21 5.304 -33.537 8.732 1.00 86.44 C -ATOM 147 C VAL A 21 4.996 -32.751 10.001 1.00 86.44 C -ATOM 148 CB VAL A 21 4.031 -33.965 7.980 1.00 86.44 C -ATOM 149 O VAL A 21 4.418 -33.278 10.954 1.00 86.44 O -ATOM 150 CG1 VAL A 21 3.230 -32.735 7.529 1.00 86.44 C -ATOM 151 CG2 VAL A 21 4.373 -34.782 6.726 1.00 86.44 C -ATOM 152 N ASN A 22 5.397 -31.481 10.026 1.00 83.81 N -ATOM 153 CA ASN A 22 5.118 -30.592 11.148 1.00 83.81 C -ATOM 154 C ASN A 22 3.704 -30.024 11.015 1.00 83.81 C -ATOM 155 CB ASN A 22 6.184 -29.488 11.218 1.00 83.81 C -ATOM 156 O ASN A 22 3.406 -29.310 10.061 1.00 83.81 O -ATOM 157 CG ASN A 22 7.548 -30.012 11.635 1.00 83.81 C -ATOM 158 ND2 ASN A 22 8.601 -29.332 11.249 1.00 83.81 N -ATOM 159 OD1 ASN A 22 7.689 -31.009 12.331 1.00 83.81 O -ATOM 160 N VAL A 23 2.852 -30.316 11.993 1.00 81.23 N -ATOM 161 CA VAL A 23 1.476 -29.817 12.068 1.00 81.23 C -ATOM 162 C VAL A 23 1.266 -29.032 13.355 1.00 81.23 C -ATOM 163 CB VAL A 23 0.432 -30.939 11.907 1.00 81.23 C -ATOM 164 O VAL A 23 1.819 -29.340 14.416 1.00 81.23 O -ATOM 165 CG1 VAL A 23 0.428 -31.484 10.476 1.00 81.23 C -ATOM 166 CG2 VAL A 23 0.653 -32.105 12.875 1.00 81.23 C -ATOM 167 N THR A 24 0.437 -28.000 13.285 1.00 81.30 N -ATOM 168 CA THR A 24 0.074 -27.183 14.445 1.00 81.30 C -ATOM 169 C THR A 24 -1.413 -27.370 14.711 1.00 81.30 C -ATOM 170 CB THR A 24 0.444 -25.704 14.244 1.00 81.30 C -ATOM 171 O THR A 24 -2.208 -27.361 13.776 1.00 81.30 O -ATOM 172 CG2 THR A 24 0.693 -25.010 15.584 1.00 81.30 C -ATOM 173 OG1 THR A 24 1.655 -25.575 13.532 1.00 81.30 O -ATOM 174 N SER A 25 -1.802 -27.559 15.975 1.00 86.41 N -ATOM 175 CA SER A 25 -3.220 -27.598 16.350 1.00 86.41 C -ATOM 176 C SER A 25 -3.892 -26.255 16.049 1.00 86.41 C -ATOM 177 CB SER A 25 -3.369 -27.957 17.833 1.00 86.41 C -ATOM 178 O SER A 25 -3.207 -25.242 15.887 1.00 86.41 O -ATOM 179 OG SER A 25 -2.679 -27.022 18.644 1.00 86.41 O -ATOM 180 N ALA A 26 -5.226 -26.229 16.013 1.00 89.92 N -ATOM 181 CA ALA A 26 -5.966 -24.976 15.905 1.00 89.92 C -ATOM 182 C ALA A 26 -5.557 -23.986 17.021 1.00 89.92 C -ATOM 183 CB ALA A 26 -7.469 -25.271 15.923 1.00 89.92 C -ATOM 184 O ALA A 26 -5.227 -24.429 18.131 1.00 89.92 O -ATOM 185 N PRO A 27 -5.549 -22.669 16.743 1.00 92.68 N -ATOM 186 CA PRO A 27 -5.329 -21.657 17.770 1.00 92.68 C -ATOM 187 C PRO A 27 -6.379 -21.734 18.882 1.00 92.68 C -ATOM 188 CB PRO A 27 -5.405 -20.308 17.049 1.00 92.68 C -ATOM 189 O PRO A 27 -7.496 -22.213 18.670 1.00 92.68 O -ATOM 190 CG PRO A 27 -5.119 -20.652 15.592 1.00 92.68 C -ATOM 191 CD PRO A 27 -5.743 -22.034 15.446 1.00 92.68 C -ATOM 192 N CYS A 28 -6.044 -21.217 20.064 1.00 94.14 N -ATOM 193 CA CYS A 28 -7.042 -20.999 21.108 1.00 94.14 C -ATOM 194 C CYS A 28 -8.097 -19.974 20.659 1.00 94.14 C -ATOM 195 CB CYS A 28 -6.352 -20.570 22.409 1.00 94.14 C -ATOM 196 O CYS A 28 -7.823 -19.105 19.832 1.00 94.14 O -ATOM 197 SG CYS A 28 -5.364 -21.947 23.068 1.00 94.14 S -ATOM 198 N VAL A 29 -9.298 -20.073 21.231 1.00 94.81 N -ATOM 199 CA VAL A 29 -10.366 -19.089 21.021 1.00 94.81 C -ATOM 200 C VAL A 29 -9.910 -17.732 21.594 1.00 94.81 C -ATOM 201 CB VAL A 29 -11.680 -19.572 21.665 1.00 94.81 C -ATOM 202 O VAL A 29 -9.398 -17.718 22.719 1.00 94.81 O -ATOM 203 CG1 VAL A 29 -12.822 -18.585 21.445 1.00 94.81 C -ATOM 204 CG2 VAL A 29 -12.120 -20.916 21.063 1.00 94.81 C -ATOM 205 N PRO A 30 -10.034 -16.618 20.845 1.00 93.95 N -ATOM 206 CA PRO A 30 -9.761 -15.271 21.350 1.00 93.95 C -ATOM 207 C PRO A 30 -10.577 -14.930 22.606 1.00 93.95 C -ATOM 208 CB PRO A 30 -10.080 -14.317 20.193 1.00 93.95 C -ATOM 209 O PRO A 30 -11.625 -15.522 22.858 1.00 93.95 O -ATOM 210 CG PRO A 30 -9.885 -15.193 18.959 1.00 93.95 C -ATOM 211 CD PRO A 30 -10.369 -16.560 19.430 1.00 93.95 C -ATOM 212 N GLN A 31 -10.060 -14.008 23.419 1.00 93.67 N -ATOM 213 CA GLN A 31 -10.716 -13.525 24.636 1.00 93.67 C -ATOM 214 C GLN A 31 -10.447 -12.030 24.832 1.00 93.67 C -ATOM 215 CB GLN A 31 -10.209 -14.296 25.873 1.00 93.67 C -ATOM 216 O GLN A 31 -9.432 -11.510 24.361 1.00 93.67 O -ATOM 217 CG GLN A 31 -10.590 -15.783 25.870 1.00 93.67 C -ATOM 218 CD GLN A 31 -10.239 -16.490 27.176 1.00 93.67 C -ATOM 219 NE2 GLN A 31 -11.011 -17.479 27.572 1.00 93.67 N -ATOM 220 OE1 GLN A 31 -9.278 -16.191 27.868 1.00 93.67 O -ATOM 221 N GLY A 32 -11.312 -11.363 25.598 1.00 91.63 N -ATOM 222 CA GLY A 32 -11.147 -9.952 25.959 1.00 91.63 C -ATOM 223 C GLY A 32 -11.480 -9.006 24.809 1.00 91.63 C -ATOM 224 O GLY A 32 -10.832 -7.974 24.660 1.00 91.63 O -ATOM 225 N GLU A 33 -12.444 -9.391 23.978 1.00 92.94 N -ATOM 226 CA GLU A 33 -12.883 -8.637 22.818 1.00 92.94 C -ATOM 227 C GLU A 33 -13.597 -7.350 23.242 1.00 92.94 C -ATOM 228 CB GLU A 33 -13.785 -9.487 21.908 1.00 92.94 C -ATOM 229 O GLU A 33 -14.568 -7.373 23.999 1.00 92.94 O -ATOM 230 CG GLU A 33 -13.153 -10.806 21.436 1.00 92.94 C -ATOM 231 CD GLU A 33 -13.390 -12.007 22.373 1.00 92.94 C -ATOM 232 OE1 GLU A 33 -13.340 -13.142 21.859 1.00 92.94 O -ATOM 233 OE2 GLU A 33 -13.579 -11.845 23.603 1.00 92.94 O -ATOM 234 N ALA A 34 -13.126 -6.220 22.727 1.00 93.92 N -ATOM 235 CA ALA A 34 -13.754 -4.921 22.911 1.00 93.92 C -ATOM 236 C ALA A 34 -13.773 -4.168 21.581 1.00 93.92 C -ATOM 237 CB ALA A 34 -13.011 -4.152 24.009 1.00 93.92 C -ATOM 238 O ALA A 34 -12.874 -4.325 20.759 1.00 93.92 O -ATOM 239 N GLY A 35 -14.796 -3.344 21.368 1.00 92.42 N -ATOM 240 CA GLY A 35 -14.922 -2.519 20.171 1.00 92.42 C -ATOM 241 C GLY A 35 -15.106 -1.052 20.526 1.00 92.42 C -ATOM 242 O GLY A 35 -15.853 -0.726 21.448 1.00 92.42 O -ATOM 243 N ASN A 36 -14.444 -0.172 19.782 1.00 91.54 N -ATOM 244 CA ASN A 36 -14.633 1.269 19.861 1.00 91.54 C -ATOM 245 C ASN A 36 -15.070 1.800 18.492 1.00 91.54 C -ATOM 246 CB ASN A 36 -13.344 1.923 20.379 1.00 91.54 C -ATOM 247 O ASN A 36 -14.384 1.579 17.494 1.00 91.54 O -ATOM 248 CG ASN A 36 -13.559 3.376 20.763 1.00 91.54 C -ATOM 249 ND2 ASN A 36 -12.534 4.046 21.228 1.00 91.54 N -ATOM 250 OD1 ASN A 36 -14.646 3.920 20.691 1.00 91.54 O -ATOM 251 N LEU A 37 -16.227 2.459 18.451 1.00 88.49 N -ATOM 252 CA LEU A 37 -16.797 3.016 17.229 1.00 88.49 C -ATOM 253 C LEU A 37 -16.128 4.352 16.906 1.00 88.49 C -ATOM 254 CB LEU A 37 -18.321 3.162 17.408 1.00 88.49 C -ATOM 255 O LEU A 37 -16.256 5.314 17.660 1.00 88.49 O -ATOM 256 CG LEU A 37 -19.056 3.770 16.196 1.00 88.49 C -ATOM 257 CD1 LEU A 37 -19.039 2.854 14.972 1.00 88.49 C -ATOM 258 CD2 LEU A 37 -20.522 4.025 16.553 1.00 88.49 C -ATOM 259 N ASP A 38 -15.488 4.420 15.747 1.00 85.73 N -ATOM 260 CA ASP A 38 -15.111 5.672 15.117 1.00 85.73 C -ATOM 261 C ASP A 38 -16.315 6.236 14.353 1.00 85.73 C -ATOM 262 CB ASP A 38 -13.890 5.460 14.225 1.00 85.73 C -ATOM 263 O ASP A 38 -16.798 5.688 13.357 1.00 85.73 O -ATOM 264 CG ASP A 38 -13.438 6.751 13.542 1.00 85.73 C -ATOM 265 OD1 ASP A 38 -14.082 7.810 13.748 1.00 85.73 O -ATOM 266 OD2 ASP A 38 -12.485 6.634 12.750 1.00 85.73 O -ATOM 267 N CYS A 39 -16.824 7.351 14.867 1.00 79.80 N -ATOM 268 CA CYS A 39 -18.004 8.021 14.348 1.00 79.80 C -ATOM 269 C CYS A 39 -17.779 8.666 12.967 1.00 79.80 C -ATOM 270 CB CYS A 39 -18.401 9.078 15.382 1.00 79.80 C -ATOM 271 O CYS A 39 -18.760 8.902 12.259 1.00 79.80 O -ATOM 272 SG CYS A 39 -17.274 10.498 15.364 1.00 79.80 S -ATOM 273 N ILE A 40 -16.525 8.971 12.600 1.00 73.17 N -ATOM 274 CA ILE A 40 -16.181 9.693 11.368 1.00 73.17 C -ATOM 275 C ILE A 40 -16.249 8.724 10.197 1.00 73.17 C -ATOM 276 CB ILE A 40 -14.780 10.351 11.471 1.00 73.17 C -ATOM 277 O ILE A 40 -16.994 8.929 9.240 1.00 73.17 O -ATOM 278 CG1 ILE A 40 -14.726 11.325 12.670 1.00 73.17 C -ATOM 279 CG2 ILE A 40 -14.432 11.074 10.154 1.00 73.17 C -ATOM 280 CD1 ILE A 40 -13.371 12.013 12.875 1.00 73.17 C -ATOM 281 N THR A 41 -15.506 7.631 10.314 1.00 80.58 N -ATOM 282 CA THR A 41 -15.362 6.625 9.260 1.00 80.58 C -ATOM 283 C THR A 41 -16.467 5.561 9.281 1.00 80.58 C -ATOM 284 CB THR A 41 -13.968 5.990 9.345 1.00 80.58 C -ATOM 285 O THR A 41 -16.522 4.708 8.396 1.00 80.58 O -ATOM 286 CG2 THR A 41 -12.840 6.989 9.102 1.00 80.58 C -ATOM 287 OG1 THR A 41 -13.781 5.470 10.641 1.00 80.58 O -ATOM 288 N ASN A 42 -17.353 5.581 10.290 1.00 85.30 N -ATOM 289 CA ASN A 42 -18.223 4.451 10.651 1.00 85.30 C -ATOM 290 C ASN A 42 -17.460 3.130 10.682 1.00 85.30 C -ATOM 291 CB ASN A 42 -19.454 4.331 9.747 1.00 85.30 C -ATOM 292 O ASN A 42 -17.916 2.109 10.159 1.00 85.30 O -ATOM 293 CG ASN A 42 -20.522 5.340 9.996 1.00 85.30 C -ATOM 294 ND2 ASN A 42 -21.564 5.325 9.202 1.00 85.30 N -ATOM 295 OD1 ASN A 42 -20.492 6.090 10.950 1.00 85.30 O -ATOM 296 N SER A 43 -16.278 3.159 11.273 1.00 89.68 N -ATOM 297 CA SER A 43 -15.471 1.970 11.449 1.00 89.68 C -ATOM 298 C SER A 43 -15.403 1.610 12.924 1.00 89.68 C -ATOM 299 CB SER A 43 -14.125 2.143 10.755 1.00 89.68 C -ATOM 300 O SER A 43 -15.641 2.443 13.797 1.00 89.68 O -ATOM 301 OG SER A 43 -13.276 3.036 11.438 1.00 89.68 O -ATOM 302 N VAL A 44 -15.178 0.338 13.227 1.00 93.01 N -ATOM 303 CA VAL A 44 -15.024 -0.113 14.610 1.00 93.01 C -ATOM 304 C VAL A 44 -13.636 -0.692 14.771 1.00 93.01 C -ATOM 305 CB VAL A 44 -16.131 -1.090 15.034 1.00 93.01 C -ATOM 306 O VAL A 44 -13.305 -1.719 14.175 1.00 93.01 O -ATOM 307 CG1 VAL A 44 -15.853 -1.730 16.401 1.00 93.01 C -ATOM 308 CG2 VAL A 44 -17.474 -0.358 15.160 1.00 93.01 C -ATOM 309 N TRP A 45 -12.864 -0.072 15.656 1.00 93.90 N -ATOM 310 CA TRP A 45 -11.621 -0.631 16.150 1.00 93.90 C -ATOM 311 C TRP A 45 -11.930 -1.722 17.158 1.00 93.90 C -ATOM 312 CB TRP A 45 -10.762 0.472 16.760 1.00 93.90 C -ATOM 313 O TRP A 45 -12.399 -1.446 18.262 1.00 93.90 O -ATOM 314 CG TRP A 45 -10.094 1.312 15.728 1.00 93.90 C -ATOM 315 CD1 TRP A 45 -10.504 2.526 15.297 1.00 93.90 C -ATOM 316 CD2 TRP A 45 -8.932 0.966 14.919 1.00 93.90 C -ATOM 317 CE2 TRP A 45 -8.660 2.054 14.038 1.00 93.90 C -ATOM 318 CE3 TRP A 45 -8.089 -0.168 14.838 1.00 93.90 C -ATOM 319 NE1 TRP A 45 -9.656 2.972 14.302 1.00 93.90 N -ATOM 320 CH2 TRP A 45 -6.745 0.903 13.101 1.00 93.90 C -ATOM 321 CZ2 TRP A 45 -7.583 2.033 13.141 1.00 93.90 C -ATOM 322 CZ3 TRP A 45 -7.003 -0.198 13.941 1.00 93.90 C -ATOM 323 N VAL A 46 -11.663 -2.964 16.771 1.00 95.79 N -ATOM 324 CA VAL A 46 -11.815 -4.133 17.634 1.00 95.79 C -ATOM 325 C VAL A 46 -10.454 -4.510 18.200 1.00 95.79 C -ATOM 326 CB VAL A 46 -12.495 -5.294 16.890 1.00 95.79 C -ATOM 327 O VAL A 46 -9.473 -4.548 17.461 1.00 95.79 O -ATOM 328 CG1 VAL A 46 -12.794 -6.457 17.843 1.00 95.79 C -ATOM 329 CG2 VAL A 46 -13.825 -4.833 16.280 1.00 95.79 C -ATOM 330 N THR A 47 -10.388 -4.780 19.499 1.00 96.42 N -ATOM 331 CA THR A 47 -9.187 -5.214 20.222 1.00 96.42 C -ATOM 332 C THR A 47 -9.457 -6.520 20.962 1.00 96.42 C -ATOM 333 CB THR A 47 -8.689 -4.140 21.202 1.00 96.42 C -ATOM 334 O THR A 47 -10.600 -6.816 21.305 1.00 96.42 O -ATOM 335 CG2 THR A 47 -8.373 -2.814 20.511 1.00 96.42 C -ATOM 336 OG1 THR A 47 -9.652 -3.851 22.186 1.00 96.42 O -ATOM 337 N TRP A 48 -8.419 -7.330 21.170 1.00 95.00 N -ATOM 338 CA TRP A 48 -8.501 -8.618 21.871 1.00 95.00 C -ATOM 339 C TRP A 48 -7.155 -8.993 22.499 1.00 95.00 C -ATOM 340 CB TRP A 48 -8.950 -9.717 20.893 1.00 95.00 C -ATOM 341 O TRP A 48 -6.119 -8.381 22.231 1.00 95.00 O -ATOM 342 CG TRP A 48 -8.112 -9.830 19.658 1.00 95.00 C -ATOM 343 CD1 TRP A 48 -6.998 -10.579 19.499 1.00 95.00 C -ATOM 344 CD2 TRP A 48 -8.303 -9.133 18.397 1.00 95.00 C -ATOM 345 CE2 TRP A 48 -7.244 -9.491 17.518 1.00 95.00 C -ATOM 346 CE3 TRP A 48 -9.270 -8.232 17.916 1.00 95.00 C -ATOM 347 NE1 TRP A 48 -6.480 -10.376 18.236 1.00 95.00 N -ATOM 348 CH2 TRP A 48 -8.161 -8.142 15.754 1.00 95.00 C -ATOM 349 CZ2 TRP A 48 -7.148 -8.985 16.221 1.00 95.00 C -ATOM 350 CZ3 TRP A 48 -9.206 -7.741 16.601 1.00 95.00 C -ATOM 351 N LEU A 49 -7.153 -10.035 23.331 1.00 95.28 N -ATOM 352 CA LEU A 49 -5.940 -10.604 23.914 1.00 95.28 C -ATOM 353 C LEU A 49 -5.314 -11.656 22.992 1.00 95.28 C -ATOM 354 CB LEU A 49 -6.256 -11.186 25.300 1.00 95.28 C -ATOM 355 O LEU A 49 -6.004 -12.358 22.253 1.00 95.28 O -ATOM 356 CG LEU A 49 -6.808 -10.157 26.305 1.00 95.28 C -ATOM 357 CD1 LEU A 49 -7.197 -10.873 27.598 1.00 95.28 C -ATOM 358 CD2 LEU A 49 -5.776 -9.076 26.643 1.00 95.28 C -ATOM 359 N GLN A 50 -3.988 -11.798 23.060 1.00 94.37 N -ATOM 360 CA GLN A 50 -3.258 -12.760 22.237 1.00 94.37 C -ATOM 361 C GLN A 50 -3.699 -14.205 22.526 1.00 94.37 C -ATOM 362 CB GLN A 50 -1.745 -12.574 22.435 1.00 94.37 C -ATOM 363 O GLN A 50 -3.444 -14.750 23.600 1.00 94.37 O -ATOM 364 CG GLN A 50 -0.936 -13.437 21.451 1.00 94.37 C -ATOM 365 CD GLN A 50 0.565 -13.164 21.500 1.00 94.37 C -ATOM 366 NE2 GLN A 50 1.314 -13.622 20.521 1.00 94.37 N -ATOM 367 OE1 GLN A 50 1.101 -12.547 22.403 1.00 94.37 O -ATOM 368 N ALA A 51 -4.299 -14.855 21.530 1.00 94.47 N -ATOM 369 CA ALA A 51 -4.630 -16.269 21.562 1.00 94.47 C -ATOM 370 C ALA A 51 -3.384 -17.131 21.306 1.00 94.47 C -ATOM 371 CB ALA A 51 -5.737 -16.547 20.546 1.00 94.47 C -ATOM 372 O ALA A 51 -2.603 -16.908 20.374 1.00 94.47 O -ATOM 373 N LYS A 52 -3.197 -18.172 22.121 1.00 92.16 N -ATOM 374 CA LYS A 52 -2.063 -19.092 21.985 1.00 92.16 C -ATOM 375 C LYS A 52 -2.141 -19.847 20.652 1.00 92.16 C -ATOM 376 CB LYS A 52 -2.027 -20.023 23.202 1.00 92.16 C -ATOM 377 O LYS A 52 -3.132 -20.513 20.360 1.00 92.16 O -ATOM 378 CG LYS A 52 -0.762 -20.890 23.263 1.00 92.16 C -ATOM 379 CD LYS A 52 -0.798 -21.762 24.525 1.00 92.16 C -ATOM 380 CE LYS A 52 0.470 -22.612 24.642 1.00 92.16 C -ATOM 381 NZ LYS A 52 0.458 -23.421 25.888 1.00 92.16 N -ATOM 382 N GLY A 53 -1.066 -19.770 19.869 1.00 90.79 N -ATOM 383 CA GLY A 53 -0.944 -20.448 18.573 1.00 90.79 C -ATOM 384 C GLY A 53 -1.536 -19.691 17.381 1.00 90.79 C -ATOM 385 O GLY A 53 -1.513 -20.236 16.279 1.00 90.79 O -ATOM 386 N ALA A 54 -2.045 -18.471 17.579 1.00 92.72 N -ATOM 387 CA ALA A 54 -2.517 -17.608 16.501 1.00 92.72 C -ATOM 388 C ALA A 54 -1.346 -16.898 15.798 1.00 92.72 C -ATOM 389 CB ALA A 54 -3.501 -16.598 17.091 1.00 92.72 C -ATOM 390 O ALA A 54 -0.437 -16.394 16.458 1.00 92.72 O -ATOM 391 N LEU A 55 -1.392 -16.846 14.467 1.00 93.25 N -ATOM 392 CA LEU A 55 -0.496 -16.049 13.619 1.00 93.25 C -ATOM 393 C LEU A 55 -1.198 -14.802 13.067 1.00 93.25 C -ATOM 394 CB LEU A 55 0.016 -16.913 12.453 1.00 93.25 C -ATOM 395 O LEU A 55 -0.550 -13.796 12.794 1.00 93.25 O -ATOM 396 CG LEU A 55 0.841 -18.145 12.860 1.00 93.25 C -ATOM 397 CD1 LEU A 55 1.257 -18.907 11.602 1.00 93.25 C -ATOM 398 CD2 LEU A 55 2.107 -17.771 13.632 1.00 93.25 C -ATOM 399 N SER A 56 -2.517 -14.873 12.904 1.00 95.79 N -ATOM 400 CA SER A 56 -3.363 -13.767 12.466 1.00 95.79 C -ATOM 401 C SER A 56 -4.776 -13.918 13.027 1.00 95.79 C -ATOM 402 CB SER A 56 -3.384 -13.683 10.934 1.00 95.79 C -ATOM 403 O SER A 56 -5.131 -14.952 13.600 1.00 95.79 O -ATOM 404 OG SER A 56 -3.869 -14.879 10.352 1.00 95.79 O -ATOM 405 N TYR A 57 -5.576 -12.870 12.880 1.00 96.56 N -ATOM 406 CA TYR A 57 -6.960 -12.805 13.325 1.00 96.56 C -ATOM 407 C TYR A 57 -7.847 -12.267 12.206 1.00 96.56 C -ATOM 408 CB TYR A 57 -7.072 -11.921 14.568 1.00 96.56 C -ATOM 409 O TYR A 57 -7.411 -11.455 11.387 1.00 96.56 O -ATOM 410 CG TYR A 57 -6.251 -12.402 15.748 1.00 96.56 C -ATOM 411 CD1 TYR A 57 -6.840 -13.203 16.746 1.00 96.56 C -ATOM 412 CD2 TYR A 57 -4.895 -12.035 15.847 1.00 96.56 C -ATOM 413 CE1 TYR A 57 -6.068 -13.648 17.838 1.00 96.56 C -ATOM 414 CE2 TYR A 57 -4.114 -12.500 16.916 1.00 96.56 C -ATOM 415 OH TYR A 57 -3.932 -13.741 18.935 1.00 96.56 O -ATOM 416 CZ TYR A 57 -4.702 -13.309 17.909 1.00 96.56 C -ATOM 417 N SER A 58 -9.102 -12.704 12.203 1.00 96.21 N -ATOM 418 CA SER A 58 -10.163 -12.193 11.341 1.00 96.21 C -ATOM 419 C SER A 58 -11.327 -11.727 12.206 1.00 96.21 C -ATOM 420 CB SER A 58 -10.606 -13.271 10.353 1.00 96.21 C -ATOM 421 O SER A 58 -11.739 -12.435 13.128 1.00 96.21 O -ATOM 422 OG SER A 58 -11.594 -12.768 9.482 1.00 96.21 O -ATOM 423 N VAL A 59 -11.836 -10.532 11.917 1.00 96.83 N -ATOM 424 CA VAL A 59 -13.004 -9.949 12.574 1.00 96.83 C -ATOM 425 C VAL A 59 -14.140 -9.880 11.565 1.00 96.83 C -ATOM 426 CB VAL A 59 -12.712 -8.553 13.147 1.00 96.83 C -ATOM 427 O VAL A 59 -13.962 -9.328 10.481 1.00 96.83 O -ATOM 428 CG1 VAL A 59 -13.894 -8.051 13.983 1.00 96.83 C -ATOM 429 CG2 VAL A 59 -11.462 -8.539 14.034 1.00 96.83 C -ATOM 430 N LEU A 60 -15.305 -10.409 11.928 1.00 96.31 N -ATOM 431 CA LEU A 60 -16.523 -10.362 11.124 1.00 96.31 C -ATOM 432 C LEU A 60 -17.596 -9.562 11.863 1.00 96.31 C -ATOM 433 CB LEU A 60 -16.972 -11.804 10.827 1.00 96.31 C -ATOM 434 O LEU A 60 -17.966 -9.916 12.979 1.00 96.31 O -ATOM 435 CG LEU A 60 -18.262 -11.902 9.994 1.00 96.31 C -ATOM 436 CD1 LEU A 60 -18.072 -11.389 8.566 1.00 96.31 C -ATOM 437 CD2 LEU A 60 -18.726 -13.358 9.929 1.00 96.31 C -ATOM 438 N ALA A 61 -18.112 -8.516 11.227 1.00 96.00 N -ATOM 439 CA ALA A 61 -19.256 -7.743 11.686 1.00 96.00 C -ATOM 440 C ALA A 61 -20.495 -8.144 10.880 1.00 96.00 C -ATOM 441 CB ALA A 61 -18.930 -6.255 11.558 1.00 96.00 C -ATOM 442 O ALA A 61 -20.527 -7.986 9.660 1.00 96.00 O -ATOM 443 N VAL A 62 -21.508 -8.666 11.569 1.00 95.34 N -ATOM 444 CA VAL A 62 -22.757 -9.144 10.967 1.00 95.34 C -ATOM 445 C VAL A 62 -23.898 -8.202 11.317 1.00 95.34 C -ATOM 446 CB VAL A 62 -23.078 -10.589 11.390 1.00 95.34 C -ATOM 447 O VAL A 62 -24.153 -7.945 12.495 1.00 95.34 O -ATOM 448 CG1 VAL A 62 -24.343 -11.120 10.703 1.00 95.34 C -ATOM 449 CG2 VAL A 62 -21.923 -11.536 11.039 1.00 95.34 C -ATOM 450 N GLU A 63 -24.600 -7.721 10.299 1.00 93.27 N -ATOM 451 CA GLU A 63 -25.771 -6.851 10.428 1.00 93.27 C -ATOM 452 C GLU A 63 -27.037 -7.614 10.009 1.00 93.27 C -ATOM 453 CB GLU A 63 -25.488 -5.560 9.651 1.00 93.27 C -ATOM 454 O GLU A 63 -26.989 -8.526 9.182 1.00 93.27 O -ATOM 455 CG GLU A 63 -26.516 -4.428 9.799 1.00 93.27 C -ATOM 456 CD GLU A 63 -27.748 -4.662 8.935 1.00 93.27 C -ATOM 457 OE1 GLU A 63 -28.866 -4.434 9.451 1.00 93.27 O -ATOM 458 OE2 GLU A 63 -27.593 -5.231 7.834 1.00 93.27 O -ATOM 459 N LYS A 64 -28.184 -7.294 10.622 1.00 85.77 N -ATOM 460 CA LYS A 64 -29.427 -8.069 10.447 1.00 85.77 C -ATOM 461 C LYS A 64 -29.961 -8.065 9.010 1.00 85.77 C -ATOM 462 CB LYS A 64 -30.517 -7.549 11.393 1.00 85.77 C -ATOM 463 O LYS A 64 -30.614 -9.029 8.622 1.00 85.77 O -ATOM 464 CG LYS A 64 -30.260 -7.919 12.859 1.00 85.77 C -ATOM 465 CD LYS A 64 -31.445 -7.471 13.723 1.00 85.77 C -ATOM 466 CE LYS A 64 -31.211 -7.850 15.187 1.00 85.77 C -ATOM 467 NZ LYS A 64 -32.314 -7.364 16.052 1.00 85.77 N -ATOM 468 N GLN A 65 -29.723 -7.001 8.249 1.00 82.48 N -ATOM 469 CA GLN A 65 -30.135 -6.830 6.854 1.00 82.48 C -ATOM 470 C GLN A 65 -29.062 -7.295 5.850 1.00 82.48 C -ATOM 471 CB GLN A 65 -30.561 -5.370 6.601 1.00 82.48 C -ATOM 472 O GLN A 65 -29.278 -7.202 4.643 1.00 82.48 O -ATOM 473 CG GLN A 65 -31.639 -4.875 7.578 1.00 82.48 C -ATOM 474 CD GLN A 65 -32.043 -3.423 7.344 1.00 82.48 C -ATOM 475 NE2 GLN A 65 -32.927 -2.888 8.158 1.00 82.48 N -ATOM 476 OE1 GLN A 65 -31.627 -2.737 6.429 1.00 82.48 O -ATOM 477 N GLY A 66 -27.944 -7.859 6.322 1.00 86.08 N -ATOM 478 CA GLY A 66 -26.912 -8.478 5.489 1.00 86.08 C -ATOM 479 C GLY A 66 -25.771 -7.550 5.071 1.00 86.08 C -ATOM 480 O GLY A 66 -24.924 -7.971 4.281 1.00 86.08 O -ATOM 481 N ALA A 67 -25.699 -6.325 5.603 1.00 86.59 N -ATOM 482 CA ALA A 67 -24.604 -5.389 5.341 1.00 86.59 C -ATOM 483 C ALA A 67 -23.322 -5.762 6.114 1.00 86.59 C -ATOM 484 CB ALA A 67 -25.096 -3.963 5.622 1.00 86.59 C -ATOM 485 O ALA A 67 -22.808 -4.981 6.907 1.00 86.59 O -ATOM 486 N ASN A 68 -22.815 -6.980 5.922 1.00 92.76 N -ATOM 487 CA ASN A 68 -21.675 -7.495 6.677 1.00 92.76 C -ATOM 488 C ASN A 68 -20.365 -6.814 6.259 1.00 92.76 C -ATOM 489 CB ASN A 68 -21.585 -9.021 6.522 1.00 92.76 C -ATOM 490 O ASN A 68 -20.143 -6.538 5.081 1.00 92.76 O -ATOM 491 CG ASN A 68 -22.809 -9.757 7.033 1.00 92.76 C -ATOM 492 ND2 ASN A 68 -22.950 -11.013 6.682 1.00 92.76 N -ATOM 493 OD1 ASN A 68 -23.648 -9.247 7.756 1.00 92.76 O -ATOM 494 N SER A 69 -19.464 -6.626 7.218 1.00 93.63 N -ATOM 495 CA SER A 69 -18.110 -6.121 6.977 1.00 93.63 C -ATOM 496 C SER A 69 -17.088 -6.978 7.715 1.00 93.63 C -ATOM 497 CB SER A 69 -18.005 -4.643 7.355 1.00 93.63 C -ATOM 498 O SER A 69 -17.427 -7.721 8.637 1.00 93.63 O -ATOM 499 OG SER A 69 -16.734 -4.163 6.968 1.00 93.63 O -ATOM 500 N SER A 70 -15.829 -6.929 7.296 1.00 95.92 N -ATOM 501 CA SER A 70 -14.770 -7.709 7.929 1.00 95.92 C -ATOM 502 C SER A 70 -13.418 -7.024 7.823 1.00 95.92 C -ATOM 503 CB SER A 70 -14.712 -9.125 7.341 1.00 95.92 C -ATOM 504 O SER A 70 -13.209 -6.153 6.981 1.00 95.92 O -ATOM 505 OG SER A 70 -14.353 -9.095 5.974 1.00 95.92 O -ATOM 506 N CYS A 71 -12.492 -7.438 8.678 1.00 95.74 N -ATOM 507 CA CYS A 71 -11.100 -7.027 8.599 1.00 95.74 C -ATOM 508 C CYS A 71 -10.187 -8.177 9.055 1.00 95.74 C -ATOM 509 CB CYS A 71 -10.933 -5.724 9.388 1.00 95.74 C -ATOM 510 O CYS A 71 -10.627 -9.106 9.736 1.00 95.74 O -ATOM 511 SG CYS A 71 -10.862 -5.904 11.178 1.00 95.74 S -ATOM 512 N SER A 72 -8.920 -8.156 8.641 1.00 95.46 N -ATOM 513 CA SER A 72 -7.920 -9.151 9.046 1.00 95.46 C -ATOM 514 C SER A 72 -6.635 -8.461 9.481 1.00 95.46 C -ATOM 515 CB SER A 72 -7.629 -10.140 7.915 1.00 95.46 C -ATOM 516 O SER A 72 -6.214 -7.494 8.849 1.00 95.46 O -ATOM 517 OG SER A 72 -8.796 -10.871 7.593 1.00 95.46 O -ATOM 518 N ALA A 73 -6.009 -8.960 10.545 1.00 94.81 N -ATOM 519 CA ALA A 73 -4.806 -8.363 11.114 1.00 94.81 C -ATOM 520 C ALA A 73 -3.862 -9.417 11.706 1.00 94.81 C -ATOM 521 CB ALA A 73 -5.220 -7.333 12.170 1.00 94.81 C -ATOM 522 O ALA A 73 -4.288 -10.456 12.209 1.00 94.81 O -ATOM 523 N THR A 74 -2.559 -9.139 11.665 1.00 94.25 N -ATOM 524 CA THR A 74 -1.532 -9.877 12.425 1.00 94.25 C -ATOM 525 C THR A 74 -1.281 -9.257 13.803 1.00 94.25 C -ATOM 526 CB THR A 74 -0.216 -9.936 11.641 1.00 94.25 C -ATOM 527 O THR A 74 -0.636 -9.868 14.654 1.00 94.25 O -ATOM 528 CG2 THR A 74 -0.349 -10.770 10.367 1.00 94.25 C -ATOM 529 OG1 THR A 74 0.163 -8.634 11.253 1.00 94.25 O -ATOM 530 N THR A 75 -1.800 -8.050 14.033 1.00 94.54 N -ATOM 531 CA THR A 75 -1.796 -7.339 15.313 1.00 94.54 C -ATOM 532 C THR A 75 -2.977 -7.769 16.193 1.00 94.54 C -ATOM 533 CB THR A 75 -1.808 -5.816 15.068 1.00 94.54 C -ATOM 534 O THR A 75 -3.819 -8.572 15.796 1.00 94.54 O -ATOM 535 CG2 THR A 75 -0.522 -5.352 14.380 1.00 94.54 C -ATOM 536 OG1 THR A 75 -2.875 -5.473 14.221 1.00 94.54 O -ATOM 537 N LEU A 76 -3.033 -7.240 17.420 1.00 95.39 N -ATOM 538 CA LEU A 76 -4.110 -7.487 18.395 1.00 95.39 C -ATOM 539 C LEU A 76 -5.269 -6.481 18.290 1.00 95.39 C -ATOM 540 CB LEU A 76 -3.516 -7.512 19.812 1.00 95.39 C -ATOM 541 O LEU A 76 -6.051 -6.307 19.225 1.00 95.39 O -ATOM 542 CG LEU A 76 -2.441 -8.583 20.045 1.00 95.39 C -ATOM 543 CD1 LEU A 76 -1.941 -8.482 21.486 1.00 95.39 C -ATOM 544 CD2 LEU A 76 -2.965 -10.000 19.803 1.00 95.39 C -ATOM 545 N ASN A 77 -5.329 -5.763 17.174 1.00 94.82 N -ATOM 546 CA ASN A 77 -6.378 -4.815 16.866 1.00 94.82 C -ATOM 547 C ASN A 77 -6.679 -4.843 15.371 1.00 94.82 C -ATOM 548 CB ASN A 77 -6.000 -3.416 17.384 1.00 94.82 C -ATOM 549 O ASN A 77 -5.824 -5.202 14.562 1.00 94.82 O -ATOM 550 CG ASN A 77 -4.723 -2.827 16.802 1.00 94.82 C -ATOM 551 ND2 ASN A 77 -4.098 -1.924 17.518 1.00 94.82 N -ATOM 552 OD1 ASN A 77 -4.238 -3.156 15.733 1.00 94.82 O -ATOM 553 N CYS A 78 -7.900 -4.486 14.999 1.00 94.63 N -ATOM 554 CA CYS A 78 -8.290 -4.421 13.601 1.00 94.63 C -ATOM 555 C CYS A 78 -9.454 -3.459 13.424 1.00 94.63 C -ATOM 556 CB CYS A 78 -8.612 -5.840 13.147 1.00 94.63 C -ATOM 557 O CYS A 78 -10.381 -3.450 14.235 1.00 94.63 O -ATOM 558 SG CYS A 78 -8.878 -6.122 11.400 1.00 94.63 S -ATOM 559 N ASN A 79 -9.381 -2.642 12.377 1.00 93.71 N -ATOM 560 CA ASN A 79 -10.438 -1.704 12.054 1.00 93.71 C -ATOM 561 C ASN A 79 -11.411 -2.338 11.064 1.00 93.71 C -ATOM 562 CB ASN A 79 -9.839 -0.406 11.495 1.00 93.71 C -ATOM 563 O ASN A 79 -11.006 -2.665 9.950 1.00 93.71 O -ATOM 564 CG ASN A 79 -10.891 0.680 11.489 1.00 93.71 C -ATOM 565 ND2 ASN A 79 -10.731 1.730 10.725 1.00 93.71 N -ATOM 566 OD1 ASN A 79 -11.886 0.575 12.182 1.00 93.71 O -ATOM 567 N VAL A 80 -12.671 -2.514 11.458 1.00 94.29 N -ATOM 568 CA VAL A 80 -13.732 -2.998 10.568 1.00 94.29 C -ATOM 569 C VAL A 80 -14.375 -1.794 9.874 1.00 94.29 C -ATOM 570 CB VAL A 80 -14.789 -3.822 11.322 1.00 94.29 C -ATOM 571 O VAL A 80 -15.071 -1.036 10.551 1.00 94.29 O -ATOM 572 CG1 VAL A 80 -15.798 -4.388 10.316 1.00 94.29 C -ATOM 573 CG2 VAL A 80 -14.182 -5.011 12.075 1.00 94.29 C -ATOM 574 N PRO A 81 -14.165 -1.587 8.560 1.00 91.02 N -ATOM 575 CA PRO A 81 -14.607 -0.378 7.869 1.00 91.02 C -ATOM 576 C PRO A 81 -16.052 -0.477 7.356 1.00 91.02 C -ATOM 577 CB PRO A 81 -13.603 -0.219 6.724 1.00 91.02 C -ATOM 578 O PRO A 81 -16.632 -1.563 7.289 1.00 91.02 O -ATOM 579 CG PRO A 81 -13.326 -1.667 6.320 1.00 91.02 C -ATOM 580 CD PRO A 81 -13.369 -2.412 7.652 1.00 91.02 C -ATOM 581 N GLY A 82 -16.610 0.655 6.916 1.00 84.64 N -ATOM 582 CA GLY A 82 -17.788 0.683 6.041 1.00 84.64 C -ATOM 583 C GLY A 82 -19.111 0.269 6.691 1.00 84.64 C -ATOM 584 O GLY A 82 -19.982 -0.272 6.007 1.00 84.64 O -ATOM 585 N LEU A 83 -19.287 0.497 7.997 1.00 89.54 N -ATOM 586 CA LEU A 83 -20.543 0.171 8.669 1.00 89.54 C -ATOM 587 C LEU A 83 -21.640 1.176 8.282 1.00 89.54 C -ATOM 588 CB LEU A 83 -20.358 0.069 10.192 1.00 89.54 C -ATOM 589 O LEU A 83 -21.469 2.398 8.323 1.00 89.54 O -ATOM 590 CG LEU A 83 -19.190 -0.824 10.655 1.00 89.54 C -ATOM 591 CD1 LEU A 83 -19.137 -0.803 12.179 1.00 89.54 C -ATOM 592 CD2 LEU A 83 -19.329 -2.280 10.217 1.00 89.54 C -ATOM 593 N GLN A 84 -22.810 0.658 7.928 1.00 85.82 N -ATOM 594 CA GLN A 84 -23.983 1.475 7.621 1.00 85.82 C -ATOM 595 C GLN A 84 -24.520 2.171 8.877 1.00 85.82 C -ATOM 596 CB GLN A 84 -25.076 0.632 6.943 1.00 85.82 C -ATOM 597 O GLN A 84 -24.459 1.634 9.986 1.00 85.82 O -ATOM 598 CG GLN A 84 -24.605 -0.013 5.629 1.00 85.82 C -ATOM 599 CD GLN A 84 -24.174 1.021 4.592 1.00 85.82 C -ATOM 600 NE2 GLN A 84 -23.060 0.822 3.923 1.00 85.82 N -ATOM 601 OE1 GLN A 84 -24.813 2.043 4.396 1.00 85.82 O -ATOM 602 N CYS A 85 -25.076 3.365 8.693 1.00 83.02 N -ATOM 603 CA CYS A 85 -25.745 4.126 9.744 1.00 83.02 C -ATOM 604 C CYS A 85 -27.026 3.445 10.249 1.00 83.02 C -ATOM 605 CB CYS A 85 -26.094 5.499 9.181 1.00 83.02 C -ATOM 606 O CYS A 85 -27.761 2.841 9.474 1.00 83.02 O -ATOM 607 SG CYS A 85 -24.866 6.770 9.490 1.00 83.02 S -ATOM 608 N GLY A 86 -27.326 3.608 11.541 1.00 82.47 N -ATOM 609 CA GLY A 86 -28.543 3.099 12.183 1.00 82.47 C -ATOM 610 C GLY A 86 -28.636 1.573 12.307 1.00 82.47 C -ATOM 611 O GLY A 86 -29.691 1.061 12.678 1.00 82.47 O -ATOM 612 N GLY A 87 -27.561 0.846 12.000 1.00 86.39 N -ATOM 613 CA GLY A 87 -27.496 -0.611 12.068 1.00 86.39 C -ATOM 614 C GLY A 87 -26.972 -1.111 13.414 1.00 86.39 C -ATOM 615 O GLY A 87 -26.173 -0.452 14.080 1.00 86.39 O -ATOM 616 N THR A 88 -27.391 -2.313 13.810 1.00 92.11 N -ATOM 617 CA THR A 88 -26.800 -3.036 14.946 1.00 92.11 C -ATOM 618 C THR A 88 -25.943 -4.174 14.416 1.00 92.11 C -ATOM 619 CB THR A 88 -27.861 -3.577 15.913 1.00 92.11 C -ATOM 620 O THR A 88 -26.464 -5.111 13.809 1.00 92.11 O -ATOM 621 CG2 THR A 88 -27.232 -4.170 17.175 1.00 92.11 C -ATOM 622 OG1 THR A 88 -28.739 -2.559 16.334 1.00 92.11 O -ATOM 623 N TYR A 89 -24.641 -4.099 14.678 1.00 93.89 N -ATOM 624 CA TYR A 89 -23.650 -5.067 14.224 1.00 93.89 C -ATOM 625 C TYR A 89 -23.241 -5.986 15.369 1.00 93.89 C -ATOM 626 CB TYR A 89 -22.435 -4.335 13.649 1.00 93.89 C -ATOM 627 O TYR A 89 -22.983 -5.519 16.477 1.00 93.89 O -ATOM 628 CG TYR A 89 -22.716 -3.665 12.325 1.00 93.89 C -ATOM 629 CD1 TYR A 89 -22.314 -4.288 11.131 1.00 93.89 C -ATOM 630 CD2 TYR A 89 -23.395 -2.430 12.285 1.00 93.89 C -ATOM 631 CE1 TYR A 89 -22.584 -3.670 9.899 1.00 93.89 C -ATOM 632 CE2 TYR A 89 -23.724 -1.846 11.049 1.00 93.89 C -ATOM 633 OH TYR A 89 -23.708 -1.956 8.662 1.00 93.89 O -ATOM 634 CZ TYR A 89 -23.331 -2.479 9.852 1.00 93.89 C -ATOM 635 N THR A 90 -23.162 -7.286 15.091 1.00 95.39 N -ATOM 636 CA THR A 90 -22.594 -8.292 15.999 1.00 95.39 C -ATOM 637 C THR A 90 -21.209 -8.685 15.502 1.00 95.39 C -ATOM 638 CB THR A 90 -23.502 -9.525 16.114 1.00 95.39 C -ATOM 639 O THR A 90 -21.067 -9.095 14.351 1.00 95.39 O -ATOM 640 CG2 THR A 90 -23.028 -10.478 17.207 1.00 95.39 C -ATOM 641 OG1 THR A 90 -24.816 -9.123 16.447 1.00 95.39 O -ATOM 642 N PHE A 91 -20.195 -8.545 16.353 1.00 95.89 N -ATOM 643 CA PHE A 91 -18.794 -8.770 16.002 1.00 95.89 C -ATOM 644 C PHE A 91 -18.317 -10.141 16.475 1.00 95.89 C -ATOM 645 CB PHE A 91 -17.919 -7.654 16.582 1.00 95.89 C -ATOM 646 O PHE A 91 -18.614 -10.548 17.596 1.00 95.89 O -ATOM 647 CG PHE A 91 -18.173 -6.300 15.953 1.00 95.89 C -ATOM 648 CD1 PHE A 91 -17.325 -5.813 14.940 1.00 95.89 C -ATOM 649 CD2 PHE A 91 -19.287 -5.542 16.355 1.00 95.89 C -ATOM 650 CE1 PHE A 91 -17.599 -4.579 14.324 1.00 95.89 C -ATOM 651 CE2 PHE A 91 -19.580 -4.331 15.712 1.00 95.89 C -ATOM 652 CZ PHE A 91 -18.740 -3.849 14.695 1.00 95.89 C -ATOM 653 N TYR A 92 -17.538 -10.818 15.636 1.00 95.78 N -ATOM 654 CA TYR A 92 -16.928 -12.117 15.908 1.00 95.78 C -ATOM 655 C TYR A 92 -15.435 -12.058 15.603 1.00 95.78 C -ATOM 656 CB TYR A 92 -17.593 -13.184 15.031 1.00 95.78 C -ATOM 657 O TYR A 92 -15.057 -11.700 14.490 1.00 95.78 O -ATOM 658 CG TYR A 92 -19.082 -13.336 15.252 1.00 95.78 C -ATOM 659 CD1 TYR A 92 -19.559 -14.127 16.314 1.00 95.78 C -ATOM 660 CD2 TYR A 92 -19.985 -12.664 14.406 1.00 95.78 C -ATOM 661 CE1 TYR A 92 -20.945 -14.256 16.525 1.00 95.78 C -ATOM 662 CE2 TYR A 92 -21.370 -12.791 14.614 1.00 95.78 C -ATOM 663 OH TYR A 92 -23.188 -13.700 15.881 1.00 95.78 O -ATOM 664 CZ TYR A 92 -21.851 -13.588 15.672 1.00 95.78 C -ATOM 665 N VAL A 93 -14.587 -12.441 16.560 1.00 96.54 N -ATOM 666 CA VAL A 93 -13.130 -12.515 16.371 1.00 96.54 C -ATOM 667 C VAL A 93 -12.713 -13.977 16.273 1.00 96.54 C -ATOM 668 CB VAL A 93 -12.362 -11.787 17.491 1.00 96.54 C -ATOM 669 O VAL A 93 -13.050 -14.782 17.136 1.00 96.54 O -ATOM 670 CG1 VAL A 93 -10.857 -11.741 17.188 1.00 96.54 C -ATOM 671 CG2 VAL A 93 -12.846 -10.339 17.656 1.00 96.54 C -ATOM 672 N THR A 94 -11.968 -14.325 15.229 1.00 96.39 N -ATOM 673 CA THR A 94 -11.461 -15.682 14.991 1.00 96.39 C -ATOM 674 C THR A 94 -9.943 -15.645 14.874 1.00 96.39 C -ATOM 675 CB THR A 94 -12.089 -16.281 13.724 1.00 96.39 C -ATOM 676 O THR A 94 -9.403 -14.876 14.084 1.00 96.39 O -ATOM 677 CG2 THR A 94 -11.688 -17.740 13.524 1.00 96.39 C -ATOM 678 OG1 THR A 94 -13.494 -16.244 13.828 1.00 96.39 O -ATOM 679 N ALA A 95 -9.240 -16.479 15.641 1.00 96.34 N -ATOM 680 CA ALA A 95 -7.799 -16.683 15.496 1.00 96.34 C -ATOM 681 C ALA A 95 -7.485 -17.706 14.394 1.00 96.34 C -ATOM 682 CB ALA A 95 -7.207 -17.118 16.839 1.00 96.34 C -ATOM 683 O ALA A 95 -8.137 -18.753 14.320 1.00 96.34 O -ATOM 684 N LEU A 96 -6.451 -17.432 13.594 1.00 95.02 N -ATOM 685 CA LEU A 96 -5.974 -18.262 12.488 1.00 95.02 C -ATOM 686 C LEU A 96 -4.485 -18.598 12.644 1.00 95.02 C -ATOM 687 CB LEU A 96 -6.209 -17.566 11.132 1.00 95.02 C -ATOM 688 O LEU A 96 -3.697 -17.820 13.185 1.00 95.02 O -ATOM 689 CG LEU A 96 -7.673 -17.189 10.834 1.00 95.02 C -ATOM 690 CD1 LEU A 96 -7.942 -15.718 11.147 1.00 95.02 C -ATOM 691 CD2 LEU A 96 -8.005 -17.412 9.359 1.00 95.02 C -ATOM 692 N ASN A 97 -4.087 -19.762 12.136 1.00 91.28 N -ATOM 693 CA ASN A 97 -2.692 -20.103 11.863 1.00 91.28 C -ATOM 694 C ASN A 97 -2.550 -20.662 10.439 1.00 91.28 C -ATOM 695 CB ASN A 97 -2.161 -21.024 12.976 1.00 91.28 C -ATOM 696 O ASN A 97 -3.502 -20.642 9.667 1.00 91.28 O -ATOM 697 CG ASN A 97 -2.732 -22.432 13.006 1.00 91.28 C -ATOM 698 ND2 ASN A 97 -2.617 -23.082 14.136 1.00 91.28 N -ATOM 699 OD1 ASN A 97 -3.196 -22.985 12.028 1.00 91.28 O -ATOM 700 N SER A 98 -1.370 -21.169 10.079 1.00 87.92 N -ATOM 701 CA SER A 98 -1.092 -21.679 8.728 1.00 87.92 C -ATOM 702 C SER A 98 -1.968 -22.858 8.283 1.00 87.92 C -ATOM 703 CB SER A 98 0.370 -22.128 8.638 1.00 87.92 C -ATOM 704 O SER A 98 -1.954 -23.190 7.103 1.00 87.92 O -ATOM 705 OG SER A 98 1.242 -21.125 9.127 1.00 87.92 O -ATOM 706 N PHE A 99 -2.682 -23.516 9.202 1.00 85.05 N -ATOM 707 CA PHE A 99 -3.401 -24.765 8.936 1.00 85.05 C -ATOM 708 C PHE A 99 -4.884 -24.715 9.319 1.00 85.05 C -ATOM 709 CB PHE A 99 -2.702 -25.900 9.699 1.00 85.05 C -ATOM 710 O PHE A 99 -5.709 -25.327 8.648 1.00 85.05 O -ATOM 711 CG PHE A 99 -1.243 -26.101 9.332 1.00 85.05 C -ATOM 712 CD1 PHE A 99 -0.908 -26.720 8.114 1.00 85.05 C -ATOM 713 CD2 PHE A 99 -0.221 -25.666 10.199 1.00 85.05 C -ATOM 714 CE1 PHE A 99 0.440 -26.917 7.769 1.00 85.05 C -ATOM 715 CE2 PHE A 99 1.129 -25.863 9.853 1.00 85.05 C -ATOM 716 CZ PHE A 99 1.458 -26.493 8.640 1.00 85.05 C -ATOM 717 N CYS A 100 -5.227 -24.016 10.402 1.00 89.65 N -ATOM 718 CA CYS A 100 -6.522 -24.110 11.064 1.00 89.65 C -ATOM 719 C CYS A 100 -7.006 -22.747 11.578 1.00 89.65 C -ATOM 720 CB CYS A 100 -6.399 -25.085 12.246 1.00 89.65 C -ATOM 721 O CYS A 100 -6.216 -21.861 11.916 1.00 89.65 O -ATOM 722 SG CYS A 100 -6.101 -26.790 11.695 1.00 89.65 S -ATOM 723 N GLN A 101 -8.325 -22.643 11.738 1.00 93.66 N -ATOM 724 CA GLN A 101 -9.002 -21.554 12.439 1.00 93.66 C -ATOM 725 C GLN A 101 -9.577 -22.045 13.772 1.00 93.66 C -ATOM 726 CB GLN A 101 -10.062 -20.913 11.531 1.00 93.66 C -ATOM 727 O GLN A 101 -9.941 -23.214 13.916 1.00 93.66 O -ATOM 728 CG GLN A 101 -11.217 -21.860 11.154 1.00 93.66 C -ATOM 729 CD GLN A 101 -12.170 -21.253 10.127 1.00 93.66 C -ATOM 730 NE2 GLN A 101 -13.112 -22.016 9.621 1.00 93.66 N -ATOM 731 OE1 GLN A 101 -12.084 -20.102 9.741 1.00 93.66 O -ATOM 732 N SER A 102 -9.632 -21.151 14.751 1.00 93.76 N -ATOM 733 CA SER A 102 -10.343 -21.368 16.015 1.00 93.76 C -ATOM 734 C SER A 102 -11.862 -21.242 15.829 1.00 93.76 C -ATOM 735 CB SER A 102 -9.826 -20.393 17.079 1.00 93.76 C -ATOM 736 O SER A 102 -12.337 -20.800 14.783 1.00 93.76 O -ATOM 737 OG SER A 102 -9.997 -19.064 16.643 1.00 93.76 O -ATOM 738 N SER A 103 -12.637 -21.620 16.849 1.00 94.15 N -ATOM 739 CA SER A 103 -14.032 -21.162 16.929 1.00 94.15 C -ATOM 740 C SER A 103 -14.060 -19.651 17.201 1.00 94.15 C -ATOM 741 CB SER A 103 -14.807 -21.882 18.035 1.00 94.15 C -ATOM 742 O SER A 103 -13.136 -19.159 17.857 1.00 94.15 O -ATOM 743 OG SER A 103 -14.861 -23.275 17.783 1.00 94.15 O -ATOM 744 N PRO A 104 -15.098 -18.919 16.755 1.00 92.86 N -ATOM 745 CA PRO A 104 -15.255 -17.512 17.097 1.00 92.86 C -ATOM 746 C PRO A 104 -15.254 -17.285 18.612 1.00 92.86 C -ATOM 747 CB PRO A 104 -16.579 -17.072 16.470 1.00 92.86 C -ATOM 748 O PRO A 104 -15.798 -18.093 19.368 1.00 92.86 O -ATOM 749 CG PRO A 104 -16.761 -18.048 15.310 1.00 92.86 C -ATOM 750 CD PRO A 104 -16.165 -19.342 15.861 1.00 92.86 C -ATOM 751 N GLY A 105 -14.639 -16.183 19.030 1.00 91.17 N -ATOM 752 CA GLY A 105 -14.631 -15.708 20.407 1.00 91.17 C -ATOM 753 C GLY A 105 -15.987 -15.198 20.891 1.00 91.17 C -ATOM 754 O GLY A 105 -17.031 -15.427 20.270 1.00 91.17 O -ATOM 755 N THR A 106 -15.980 -14.497 22.023 1.00 92.18 N -ATOM 756 CA THR A 106 -17.227 -13.962 22.587 1.00 92.18 C -ATOM 757 C THR A 106 -17.704 -12.793 21.732 1.00 92.18 C -ATOM 758 CB THR A 106 -17.083 -13.541 24.053 1.00 92.18 C -ATOM 759 O THR A 106 -16.969 -11.833 21.512 1.00 92.18 O -ATOM 760 CG2 THR A 106 -18.432 -13.173 24.676 1.00 92.18 C -ATOM 761 OG1 THR A 106 -16.573 -14.625 24.799 1.00 92.18 O -ATOM 762 N SER A 107 -18.942 -12.861 21.241 1.00 94.01 N -ATOM 763 CA SER A 107 -19.503 -11.784 20.428 1.00 94.01 C -ATOM 764 C SER A 107 -19.924 -10.588 21.273 1.00 94.01 C -ATOM 765 CB SER A 107 -20.689 -12.274 19.598 1.00 94.01 C -ATOM 766 O SER A 107 -20.492 -10.761 22.352 1.00 94.01 O -ATOM 767 OG SER A 107 -21.745 -12.689 20.449 1.00 94.01 O -ATOM 768 N PHE A 108 -19.773 -9.385 20.730 1.00 93.78 N -ATOM 769 CA PHE A 108 -20.323 -8.151 21.291 1.00 93.78 C -ATOM 770 C PHE A 108 -21.081 -7.373 20.210 1.00 93.78 C -ATOM 771 CB PHE A 108 -19.201 -7.332 21.945 1.00 93.78 C -ATOM 772 O PHE A 108 -20.919 -7.631 19.014 1.00 93.78 O -ATOM 773 CG PHE A 108 -18.141 -6.865 20.971 1.00 93.78 C -ATOM 774 CD1 PHE A 108 -17.042 -7.693 20.671 1.00 93.78 C -ATOM 775 CD2 PHE A 108 -18.282 -5.621 20.328 1.00 93.78 C -ATOM 776 CE1 PHE A 108 -16.096 -7.281 19.718 1.00 93.78 C -ATOM 777 CE2 PHE A 108 -17.338 -5.216 19.372 1.00 93.78 C -ATOM 778 CZ PHE A 108 -16.247 -6.045 19.071 1.00 93.78 C -ATOM 779 N GLN A 109 -21.937 -6.438 20.625 1.00 94.22 N -ATOM 780 CA GLN A 109 -22.765 -5.650 19.714 1.00 94.22 C -ATOM 781 C GLN A 109 -22.447 -4.163 19.806 1.00 94.22 C -ATOM 782 CB GLN A 109 -24.260 -5.912 19.951 1.00 94.22 C -ATOM 783 O GLN A 109 -22.257 -3.632 20.898 1.00 94.22 O -ATOM 784 CG GLN A 109 -24.640 -7.332 19.516 1.00 94.22 C -ATOM 785 CD GLN A 109 -26.132 -7.624 19.608 1.00 94.22 C -ATOM 786 NE2 GLN A 109 -26.587 -8.659 18.940 1.00 94.22 N -ATOM 787 OE1 GLN A 109 -26.916 -6.953 20.261 1.00 94.22 O -ATOM 788 N ILE A 110 -22.438 -3.492 18.654 1.00 91.74 N -ATOM 789 CA ILE A 110 -22.361 -2.032 18.558 1.00 91.74 C -ATOM 790 C ILE A 110 -23.489 -1.556 17.653 1.00 91.74 C -ATOM 791 CB ILE A 110 -20.972 -1.555 18.079 1.00 91.74 C -ATOM 792 O ILE A 110 -23.720 -2.102 16.573 1.00 91.74 O -ATOM 793 CG1 ILE A 110 -19.909 -1.935 19.134 1.00 91.74 C -ATOM 794 CG2 ILE A 110 -20.953 -0.040 17.793 1.00 91.74 C -ATOM 795 CD1 ILE A 110 -18.482 -1.574 18.730 1.00 91.74 C -ATOM 796 N GLN A 111 -24.193 -0.525 18.107 1.00 88.89 N -ATOM 797 CA GLN A 111 -25.194 0.172 17.316 1.00 88.89 C -ATOM 798 C GLN A 111 -24.577 1.443 16.734 1.00 88.89 C -ATOM 799 CB GLN A 111 -26.419 0.439 18.194 1.00 88.89 C -ATOM 800 O GLN A 111 -24.062 2.281 17.474 1.00 88.89 O -ATOM 801 CG GLN A 111 -27.552 1.098 17.399 1.00 88.89 C -ATOM 802 CD GLN A 111 -28.819 1.276 18.227 1.00 88.89 C -ATOM 803 NE2 GLN A 111 -29.725 2.120 17.792 1.00 88.89 N -ATOM 804 OE1 GLN A 111 -29.034 0.660 19.258 1.00 88.89 O -ATOM 805 N THR A 112 -24.634 1.590 15.414 1.00 85.75 N -ATOM 806 CA THR A 112 -24.197 2.814 14.743 1.00 85.75 C -ATOM 807 C THR A 112 -25.268 3.895 14.884 1.00 85.75 C -ATOM 808 CB THR A 112 -23.827 2.573 13.271 1.00 85.75 C -ATOM 809 O THR A 112 -26.471 3.618 14.927 1.00 85.75 O -ATOM 810 CG2 THR A 112 -22.701 1.552 13.115 1.00 85.75 C -ATOM 811 OG1 THR A 112 -24.925 2.089 12.546 1.00 85.75 O -ATOM 812 N ALA A 113 -24.842 5.156 14.965 1.00 79.65 N -ATOM 813 CA ALA A 113 -25.777 6.275 14.995 1.00 79.65 C -ATOM 814 C ALA A 113 -26.597 6.328 13.687 1.00 79.65 C -ATOM 815 CB ALA A 113 -25.006 7.576 15.244 1.00 79.65 C -ATOM 816 O ALA A 113 -26.055 6.021 12.619 1.00 79.65 O -ATOM 817 N PRO A 114 -27.886 6.710 13.733 1.00 79.10 N -ATOM 818 CA PRO A 114 -28.650 6.984 12.523 1.00 79.10 C -ATOM 819 C PRO A 114 -28.047 8.184 11.780 1.00 79.10 C -ATOM 820 CB PRO A 114 -30.085 7.239 12.992 1.00 79.10 C -ATOM 821 O PRO A 114 -27.644 9.170 12.396 1.00 79.10 O -ATOM 822 CG PRO A 114 -29.905 7.766 14.416 1.00 79.10 C -ATOM 823 CD PRO A 114 -28.667 7.025 14.919 1.00 79.10 C -ATOM 824 N CYS A 115 -28.000 8.094 10.454 1.00 77.65 N -ATOM 825 CA CYS A 115 -27.641 9.208 9.584 1.00 77.65 C -ATOM 826 C CYS A 115 -28.893 10.060 9.347 1.00 77.65 C -ATOM 827 CB CYS A 115 -27.113 8.666 8.252 1.00 77.65 C -ATOM 828 O CYS A 115 -29.934 9.516 8.979 1.00 77.65 O -ATOM 829 SG CYS A 115 -25.369 8.175 8.130 1.00 77.65 S -ATOM 830 N SER A 116 -28.798 11.377 9.537 1.00 74.95 N -ATOM 831 CA SER A 116 -29.929 12.289 9.290 1.00 74.95 C -ATOM 832 C SER A 116 -29.874 12.959 7.915 1.00 74.95 C -ATOM 833 CB SER A 116 -30.022 13.372 10.365 1.00 74.95 C -ATOM 834 O SER A 116 -30.902 13.409 7.415 1.00 74.95 O -ATOM 835 OG SER A 116 -30.027 12.819 11.667 1.00 74.95 O -ATOM 836 N LEU A 117 -28.690 13.055 7.298 1.00 78.26 N -ATOM 837 CA LEU A 117 -28.541 13.597 5.945 1.00 78.26 C -ATOM 838 C LEU A 117 -28.590 12.476 4.903 1.00 78.26 C -ATOM 839 CB LEU A 117 -27.262 14.445 5.822 1.00 78.26 C -ATOM 840 O LEU A 117 -28.282 11.318 5.188 1.00 78.26 O -ATOM 841 CG LEU A 117 -27.162 15.635 6.792 1.00 78.26 C -ATOM 842 CD1 LEU A 117 -25.820 16.340 6.615 1.00 78.26 C -ATOM 843 CD2 LEU A 117 -28.268 16.664 6.552 1.00 78.26 C -ATOM 844 N THR A 118 -28.964 12.837 3.678 1.00 78.01 N -ATOM 845 CA THR A 118 -28.930 11.939 2.520 1.00 78.01 C -ATOM 846 C THR A 118 -27.493 11.647 2.088 1.00 78.01 C -ATOM 847 CB THR A 118 -29.718 12.547 1.349 1.00 78.01 C -ATOM 848 O THR A 118 -26.545 12.304 2.524 1.00 78.01 O -ATOM 849 CG2 THR A 118 -31.213 12.624 1.653 1.00 78.01 C -ATOM 850 OG1 THR A 118 -29.256 13.854 1.099 1.00 78.01 O -ATOM 851 N SER A 119 -27.327 10.669 1.197 1.00 81.36 N -ATOM 852 CA SER A 119 -26.041 10.372 0.568 1.00 81.36 C -ATOM 853 C SER A 119 -25.431 11.613 -0.088 1.00 81.36 C -ATOM 854 CB SER A 119 -26.203 9.268 -0.478 1.00 81.36 C -ATOM 855 O SER A 119 -26.132 12.431 -0.689 1.00 81.36 O -ATOM 856 OG SER A 119 -26.768 8.121 0.129 1.00 81.36 O -ATOM 857 N ILE A 120 -24.112 11.724 0.031 1.00 90.53 N -ATOM 858 CA ILE A 120 -23.304 12.756 -0.615 1.00 90.53 C -ATOM 859 C ILE A 120 -22.665 12.194 -1.879 1.00 90.53 C -ATOM 860 CB ILE A 120 -22.259 13.340 0.363 1.00 90.53 C -ATOM 861 O ILE A 120 -22.565 10.979 -2.055 1.00 90.53 O -ATOM 862 CG1 ILE A 120 -21.213 12.292 0.807 1.00 90.53 C -ATOM 863 CG2 ILE A 120 -23.004 13.935 1.565 1.00 90.53 C -ATOM 864 CD1 ILE A 120 -20.116 12.860 1.714 1.00 90.53 C -ATOM 865 N THR A 121 -22.204 13.084 -2.746 1.00 92.93 N -ATOM 866 CA THR A 121 -21.298 12.726 -3.835 1.00 92.93 C -ATOM 867 C THR A 121 -20.036 13.549 -3.707 1.00 92.93 C -ATOM 868 CB THR A 121 -21.927 12.897 -5.222 1.00 92.93 C -ATOM 869 O THR A 121 -20.070 14.689 -3.241 1.00 92.93 O -ATOM 870 CG2 THR A 121 -23.239 12.133 -5.383 1.00 92.93 C -ATOM 871 OG1 THR A 121 -22.187 14.243 -5.508 1.00 92.93 O -ATOM 872 N ALA A 122 -18.911 12.976 -4.101 1.00 93.07 N -ATOM 873 CA ALA A 122 -17.663 13.701 -4.114 1.00 93.07 C -ATOM 874 C ALA A 122 -16.834 13.270 -5.322 1.00 93.07 C -ATOM 875 CB ALA A 122 -16.999 13.527 -2.745 1.00 93.07 C -ATOM 876 O ALA A 122 -16.839 12.100 -5.710 1.00 93.07 O -ATOM 877 N HIS A 123 -16.142 14.230 -5.924 1.00 91.61 N -ATOM 878 CA HIS A 123 -15.304 14.002 -7.093 1.00 91.61 C -ATOM 879 C HIS A 123 -14.017 14.821 -7.010 1.00 91.61 C -ATOM 880 CB HIS A 123 -16.101 14.283 -8.379 1.00 91.61 C -ATOM 881 O HIS A 123 -13.961 15.876 -6.372 1.00 91.61 O -ATOM 882 CG HIS A 123 -16.564 15.710 -8.569 1.00 91.61 C -ATOM 883 CD2 HIS A 123 -17.701 16.115 -9.215 1.00 91.61 C -ATOM 884 ND1 HIS A 123 -15.884 16.853 -8.225 1.00 91.61 N -ATOM 885 CE1 HIS A 123 -16.580 17.912 -8.665 1.00 91.61 C -ATOM 886 NE2 HIS A 123 -17.714 17.512 -9.254 1.00 91.61 N -ATOM 887 N THR A 124 -12.984 14.352 -7.694 1.00 89.02 N -ATOM 888 CA THR A 124 -11.710 15.053 -7.822 1.00 89.02 C -ATOM 889 C THR A 124 -11.155 14.810 -9.216 1.00 89.02 C -ATOM 890 CB THR A 124 -10.740 14.611 -6.715 1.00 89.02 C -ATOM 891 O THR A 124 -11.273 13.704 -9.748 1.00 89.02 O -ATOM 892 CG2 THR A 124 -10.310 13.143 -6.782 1.00 89.02 C -ATOM 893 OG1 THR A 124 -9.575 15.393 -6.738 1.00 89.02 O -ATOM 894 N ASP A 125 -10.570 15.840 -9.818 1.00 86.56 N -ATOM 895 CA ASP A 125 -9.788 15.657 -11.034 1.00 86.56 C -ATOM 896 C ASP A 125 -8.451 15.008 -10.669 1.00 86.56 C -ATOM 897 CB ASP A 125 -9.564 16.985 -11.763 1.00 86.56 C -ATOM 898 O ASP A 125 -7.858 15.319 -9.638 1.00 86.56 O -ATOM 899 CG ASP A 125 -10.865 17.642 -12.216 1.00 86.56 C -ATOM 900 OD1 ASP A 125 -11.709 16.913 -12.780 1.00 86.56 O -ATOM 901 OD2 ASP A 125 -10.973 18.871 -12.013 1.00 86.56 O -ATOM 902 N CYS A 126 -7.927 14.139 -11.531 1.00 84.95 N -ATOM 903 CA CYS A 126 -6.768 13.297 -11.210 1.00 84.95 C -ATOM 904 C CYS A 126 -5.495 14.063 -10.795 1.00 84.95 C -ATOM 905 CB CYS A 126 -6.471 12.423 -12.430 1.00 84.95 C -ATOM 906 O CYS A 126 -4.617 13.492 -10.152 1.00 84.95 O -ATOM 907 SG CYS A 126 -7.893 11.482 -13.047 1.00 84.95 S -ATOM 908 N TYR A 127 -5.385 15.342 -11.159 1.00 80.35 N -ATOM 909 CA TYR A 127 -4.249 16.213 -10.832 1.00 80.35 C -ATOM 910 C TYR A 127 -4.625 17.369 -9.903 1.00 80.35 C -ATOM 911 CB TYR A 127 -3.625 16.732 -12.131 1.00 80.35 C -ATOM 912 O TYR A 127 -3.808 18.256 -9.659 1.00 80.35 O -ATOM 913 CG TYR A 127 -3.326 15.637 -13.131 1.00 80.35 C -ATOM 914 CD1 TYR A 127 -2.352 14.668 -12.830 1.00 80.35 C -ATOM 915 CD2 TYR A 127 -4.066 15.552 -14.327 1.00 80.35 C -ATOM 916 CE1 TYR A 127 -2.127 13.607 -13.725 1.00 80.35 C -ATOM 917 CE2 TYR A 127 -3.822 14.502 -15.232 1.00 80.35 C -ATOM 918 OH TYR A 127 -2.661 12.473 -15.760 1.00 80.35 O -ATOM 919 CZ TYR A 127 -2.857 13.524 -14.926 1.00 80.35 C -ATOM 920 N SER A 128 -5.863 17.387 -9.414 1.00 85.29 N -ATOM 921 CA SER A 128 -6.340 18.422 -8.514 1.00 85.29 C -ATOM 922 C SER A 128 -5.983 18.079 -7.074 1.00 85.29 C -ATOM 923 CB SER A 128 -7.841 18.615 -8.695 1.00 85.29 C -ATOM 924 O SER A 128 -6.108 16.944 -6.623 1.00 85.29 O -ATOM 925 OG SER A 128 -8.286 19.682 -7.891 1.00 85.29 O -ATOM 926 N SER A 129 -5.571 19.095 -6.324 1.00 88.70 N -ATOM 927 CA SER A 129 -5.461 19.041 -4.864 1.00 88.70 C -ATOM 928 C SER A 129 -6.797 19.348 -4.173 1.00 88.70 C -ATOM 929 CB SER A 129 -4.364 20.001 -4.407 1.00 88.70 C -ATOM 930 O SER A 129 -6.819 19.612 -2.967 1.00 88.70 O -ATOM 931 OG SER A 129 -4.630 21.294 -4.920 1.00 88.70 O -ATOM 932 N HIS A 130 -7.900 19.341 -4.929 1.00 92.13 N -ATOM 933 CA HIS A 130 -9.241 19.659 -4.463 1.00 92.13 C -ATOM 934 C HIS A 130 -10.179 18.462 -4.627 1.00 92.13 C -ATOM 935 CB HIS A 130 -9.795 20.897 -5.184 1.00 92.13 C -ATOM 936 O HIS A 130 -10.199 17.809 -5.674 1.00 92.13 O -ATOM 937 CG HIS A 130 -8.913 22.114 -5.075 1.00 92.13 C -ATOM 938 CD2 HIS A 130 -7.760 22.374 -5.769 1.00 92.13 C -ATOM 939 ND1 HIS A 130 -9.136 23.187 -4.248 1.00 92.13 N -ATOM 940 CE1 HIS A 130 -8.140 24.069 -4.431 1.00 92.13 C -ATOM 941 NE2 HIS A 130 -7.268 23.614 -5.342 1.00 92.13 N -ATOM 942 N ILE A 131 -10.988 18.208 -3.602 1.00 94.16 N -ATOM 943 CA ILE A 131 -12.119 17.280 -3.668 1.00 94.16 C -ATOM 944 C ILE A 131 -13.388 18.103 -3.476 1.00 94.16 C -ATOM 945 CB ILE A 131 -12.001 16.154 -2.618 1.00 94.16 C -ATOM 946 O ILE A 131 -13.616 18.648 -2.396 1.00 94.16 O -ATOM 947 CG1 ILE A 131 -10.709 15.323 -2.786 1.00 94.16 C -ATOM 948 CG2 ILE A 131 -13.238 15.243 -2.705 1.00 94.16 C -ATOM 949 CD1 ILE A 131 -10.363 14.480 -1.551 1.00 94.16 C -ATOM 950 N THR A 132 -14.217 18.180 -4.510 1.00 94.98 N -ATOM 951 CA THR A 132 -15.519 18.842 -4.415 1.00 94.98 C -ATOM 952 C THR A 132 -16.526 17.844 -3.881 1.00 94.98 C -ATOM 953 CB THR A 132 -15.994 19.364 -5.762 1.00 94.98 C -ATOM 954 O THR A 132 -16.781 16.804 -4.491 1.00 94.98 O -ATOM 955 CG2 THR A 132 -17.310 20.139 -5.701 1.00 94.98 C -ATOM 956 OG1 THR A 132 -15.022 20.187 -6.352 1.00 94.98 O -ATOM 957 N VAL A 133 -17.103 18.174 -2.735 1.00 94.54 N -ATOM 958 CA VAL A 133 -18.161 17.413 -2.080 1.00 94.54 C -ATOM 959 C VAL A 133 -19.478 18.130 -2.333 1.00 94.54 C -ATOM 960 CB VAL A 133 -17.879 17.269 -0.574 1.00 94.54 C -ATOM 961 O VAL A 133 -19.550 19.352 -2.205 1.00 94.54 O -ATOM 962 CG1 VAL A 133 -18.875 16.304 0.077 1.00 94.54 C -ATOM 963 CG2 VAL A 133 -16.462 16.741 -0.311 1.00 94.54 C -ATOM 964 N SER A 134 -20.526 17.390 -2.680 1.00 93.66 N -ATOM 965 CA SER A 134 -21.867 17.930 -2.888 1.00 93.66 C -ATOM 966 C SER A 134 -22.947 17.057 -2.255 1.00 93.66 C -ATOM 967 CB SER A 134 -22.134 18.184 -4.372 1.00 93.66 C -ATOM 968 O SER A 134 -22.811 15.836 -2.138 1.00 93.66 O -ATOM 969 OG SER A 134 -22.283 16.979 -5.084 1.00 93.66 O -ATOM 970 N TRP A 135 -24.023 17.699 -1.811 1.00 89.24 N -ATOM 971 CA TRP A 135 -25.127 17.070 -1.089 1.00 89.24 C -ATOM 972 C TRP A 135 -26.462 17.724 -1.444 1.00 89.24 C -ATOM 973 CB TRP A 135 -24.855 17.148 0.418 1.00 89.24 C -ATOM 974 O TRP A 135 -26.512 18.821 -1.997 1.00 89.24 O -ATOM 975 CG TRP A 135 -24.640 18.519 0.977 1.00 89.24 C -ATOM 976 CD1 TRP A 135 -25.583 19.329 1.512 1.00 89.24 C -ATOM 977 CD2 TRP A 135 -23.377 19.238 1.092 1.00 89.24 C -ATOM 978 CE2 TRP A 135 -23.632 20.488 1.724 1.00 89.24 C -ATOM 979 CE3 TRP A 135 -22.040 18.949 0.744 1.00 89.24 C -ATOM 980 NE1 TRP A 135 -24.990 20.498 1.952 1.00 89.24 N -ATOM 981 CH2 TRP A 135 -21.286 21.053 1.712 1.00 89.24 C -ATOM 982 CZ2 TRP A 135 -22.610 21.395 2.014 1.00 89.24 C -ATOM 983 CZ3 TRP A 135 -20.999 19.841 1.060 1.00 89.24 C -ATOM 984 N GLN A 136 -27.567 17.052 -1.125 1.00 83.48 N -ATOM 985 CA GLN A 136 -28.901 17.625 -1.300 1.00 83.48 C -ATOM 986 C GLN A 136 -29.245 18.557 -0.132 1.00 83.48 C -ATOM 987 CB GLN A 136 -29.946 16.521 -1.499 1.00 83.48 C -ATOM 988 O GLN A 136 -28.943 18.267 1.027 1.00 83.48 O -ATOM 989 CG GLN A 136 -29.715 15.778 -2.825 1.00 83.48 C -ATOM 990 CD GLN A 136 -30.815 14.768 -3.136 1.00 83.48 C -ATOM 991 NE2 GLN A 136 -31.220 14.640 -4.380 1.00 83.48 N -ATOM 992 OE1 GLN A 136 -31.326 14.062 -2.286 1.00 83.48 O -ATOM 993 N LEU A 137 -29.867 19.698 -0.442 1.00 73.64 N -ATOM 994 CA LEU A 137 -30.301 20.652 0.573 1.00 73.64 C -ATOM 995 C LEU A 137 -31.557 20.126 1.270 1.00 73.64 C -ATOM 996 CB LEU A 137 -30.568 22.026 -0.070 1.00 73.64 C -ATOM 997 O LEU A 137 -32.621 20.085 0.655 1.00 73.64 O -ATOM 998 CG LEU A 137 -30.648 23.173 0.953 1.00 73.64 C -ATOM 999 CD1 LEU A 137 -29.283 23.496 1.567 1.00 73.64 C -ATOM 1000 CD2 LEU A 137 -31.155 24.432 0.250 1.00 73.64 C -ATOM 1001 N ASN A 138 -31.439 19.788 2.552 1.00 65.93 N -ATOM 1002 CA ASN A 138 -32.596 19.391 3.357 1.00 65.93 C -ATOM 1003 C ASN A 138 -33.198 20.572 4.128 1.00 65.93 C -ATOM 1004 CB ASN A 138 -32.214 18.201 4.252 1.00 65.93 C -ATOM 1005 O ASN A 138 -34.402 20.582 4.350 1.00 65.93 O -ATOM 1006 CG ASN A 138 -31.989 16.921 3.458 1.00 65.93 C -ATOM 1007 ND2 ASN A 138 -31.501 15.881 4.090 1.00 65.93 N -ATOM 1008 OD1 ASN A 138 -32.260 16.814 2.275 1.00 65.93 O -ATOM 1009 N ASP A 139 -32.398 21.588 4.475 1.00 63.93 N -ATOM 1010 CA ASP A 139 -32.884 22.770 5.189 1.00 63.93 C -ATOM 1011 C ASP A 139 -32.096 24.039 4.836 1.00 63.93 C -ATOM 1012 CB ASP A 139 -32.879 22.515 6.710 1.00 63.93 C -ATOM 1013 O ASP A 139 -30.884 24.015 4.630 1.00 63.93 O -ATOM 1014 CG ASP A 139 -34.293 22.451 7.295 1.00 63.93 C -ATOM 1015 OD1 ASP A 139 -35.155 23.209 6.789 1.00 63.93 O -ATOM 1016 OD2 ASP A 139 -34.469 21.717 8.291 1.00 63.93 O -ATOM 1017 N ARG A 140 -32.794 25.177 4.751 1.00 56.49 N -ATOM 1018 CA ARG A 140 -32.270 26.431 4.168 1.00 56.49 C -ATOM 1019 C ARG A 140 -31.433 27.315 5.109 1.00 56.49 C -ATOM 1020 CB ARG A 140 -33.410 27.202 3.462 1.00 56.49 C -ATOM 1021 O ARG A 140 -31.238 28.484 4.792 1.00 56.49 O -ATOM 1022 CG ARG A 140 -33.623 26.712 2.025 1.00 56.49 C -ATOM 1023 CD ARG A 140 -34.621 27.612 1.290 1.00 56.49 C -ATOM 1024 NE ARG A 140 -34.786 27.197 -0.116 1.00 56.49 N -ATOM 1025 NH1 ARG A 140 -36.347 28.772 -0.707 1.00 56.49 N -ATOM 1026 NH2 ARG A 140 -35.674 27.264 -2.211 1.00 56.49 N -ATOM 1027 CZ ARG A 140 -35.598 27.745 -1.002 1.00 56.49 C -ATOM 1028 N SER A 141 -30.932 26.823 6.246 1.00 57.16 N -ATOM 1029 CA SER A 141 -30.252 27.708 7.217 1.00 57.16 C -ATOM 1030 C SER A 141 -29.142 27.075 8.070 1.00 57.16 C -ATOM 1031 CB SER A 141 -31.305 28.399 8.095 1.00 57.16 C -ATOM 1032 O SER A 141 -28.795 27.627 9.117 1.00 57.16 O -ATOM 1033 OG SER A 141 -30.728 29.494 8.775 1.00 57.16 O -ATOM 1034 N SER A 142 -28.556 25.954 7.650 1.00 70.83 N -ATOM 1035 CA SER A 142 -27.480 25.301 8.410 1.00 70.83 C -ATOM 1036 C SER A 142 -26.108 25.534 7.775 1.00 70.83 C -ATOM 1037 CB SER A 142 -27.782 23.814 8.593 1.00 70.83 C -ATOM 1038 O SER A 142 -25.957 25.493 6.556 1.00 70.83 O -ATOM 1039 OG SER A 142 -28.996 23.671 9.313 1.00 70.83 O -ATOM 1040 N LEU A 143 -25.098 25.780 8.614 1.00 85.06 N -ATOM 1041 CA LEU A 143 -23.698 25.703 8.206 1.00 85.06 C -ATOM 1042 C LEU A 143 -23.318 24.225 8.130 1.00 85.06 C -ATOM 1043 CB LEU A 143 -22.821 26.459 9.223 1.00 85.06 C -ATOM 1044 O LEU A 143 -23.339 23.533 9.145 1.00 85.06 O -ATOM 1045 CG LEU A 143 -21.318 26.447 8.880 1.00 85.06 C -ATOM 1046 CD1 LEU A 143 -21.028 27.307 7.646 1.00 85.06 C -ATOM 1047 CD2 LEU A 143 -20.512 26.999 10.057 1.00 85.06 C -ATOM 1048 N TYR A 144 -22.960 23.753 6.943 1.00 87.21 N -ATOM 1049 CA TYR A 144 -22.463 22.400 6.750 1.00 87.21 C -ATOM 1050 C TYR A 144 -20.940 22.376 6.832 1.00 87.21 C -ATOM 1051 CB TYR A 144 -22.967 21.839 5.423 1.00 87.21 C -ATOM 1052 O TYR A 144 -20.259 23.283 6.348 1.00 87.21 O -ATOM 1053 CG TYR A 144 -24.473 21.683 5.360 1.00 87.21 C -ATOM 1054 CD1 TYR A 144 -25.084 20.580 5.986 1.00 87.21 C -ATOM 1055 CD2 TYR A 144 -25.261 22.645 4.699 1.00 87.21 C -ATOM 1056 CE1 TYR A 144 -26.484 20.436 5.954 1.00 87.21 C -ATOM 1057 CE2 TYR A 144 -26.662 22.502 4.661 1.00 87.21 C -ATOM 1058 OH TYR A 144 -28.628 21.260 5.253 1.00 87.21 O -ATOM 1059 CZ TYR A 144 -27.276 21.398 5.288 1.00 87.21 C -ATOM 1060 N VAL A 145 -20.416 21.313 7.427 1.00 90.33 N -ATOM 1061 CA VAL A 145 -18.992 21.006 7.511 1.00 90.33 C -ATOM 1062 C VAL A 145 -18.766 19.706 6.756 1.00 90.33 C -ATOM 1063 CB VAL A 145 -18.538 20.906 8.980 1.00 90.33 C -ATOM 1064 O VAL A 145 -19.299 18.666 7.135 1.00 90.33 O -ATOM 1065 CG1 VAL A 145 -17.036 20.606 9.075 1.00 90.33 C -ATOM 1066 CG2 VAL A 145 -18.841 22.209 9.737 1.00 90.33 C -ATOM 1067 N ALA A 146 -17.995 19.761 5.674 1.00 92.07 N -ATOM 1068 CA ALA A 146 -17.489 18.569 5.012 1.00 92.07 C -ATOM 1069 C ALA A 146 -16.127 18.225 5.617 1.00 92.07 C -ATOM 1070 CB ALA A 146 -17.422 18.796 3.499 1.00 92.07 C -ATOM 1071 O ALA A 146 -15.272 19.102 5.767 1.00 92.07 O -ATOM 1072 N SER A 147 -15.911 16.956 5.952 1.00 92.17 N -ATOM 1073 CA SER A 147 -14.620 16.467 6.426 1.00 92.17 C -ATOM 1074 C SER A 147 -14.221 15.191 5.708 1.00 92.17 C -ATOM 1075 CB SER A 147 -14.604 16.267 7.943 1.00 92.17 C -ATOM 1076 O SER A 147 -15.050 14.294 5.566 1.00 92.17 O -ATOM 1077 OG SER A 147 -15.507 15.273 8.376 1.00 92.17 O -ATOM 1078 N ALA A 148 -12.955 15.105 5.311 1.00 93.27 N -ATOM 1079 CA ALA A 148 -12.354 13.899 4.760 1.00 93.27 C -ATOM 1080 C ALA A 148 -11.222 13.416 5.660 1.00 93.27 C -ATOM 1081 CB ALA A 148 -11.857 14.167 3.343 1.00 93.27 C -ATOM 1082 O ALA A 148 -10.319 14.194 5.968 1.00 93.27 O -ATOM 1083 N GLU A 149 -11.268 12.148 6.051 1.00 92.92 N -ATOM 1084 CA GLU A 149 -10.188 11.468 6.762 1.00 92.92 C -ATOM 1085 C GLU A 149 -9.457 10.528 5.806 1.00 92.92 C -ATOM 1086 CB GLU A 149 -10.741 10.741 7.991 1.00 92.92 C -ATOM 1087 O GLU A 149 -10.078 9.694 5.148 1.00 92.92 O -ATOM 1088 CG GLU A 149 -9.599 10.103 8.799 1.00 92.92 C -ATOM 1089 CD GLU A 149 -10.046 9.518 10.143 1.00 92.92 C -ATOM 1090 OE1 GLU A 149 -9.199 8.827 10.760 1.00 92.92 O -ATOM 1091 OE2 GLU A 149 -11.182 9.837 10.566 1.00 92.92 O -ATOM 1092 N GLY A 150 -8.146 10.714 5.676 1.00 92.11 N -ATOM 1093 CA GLY A 150 -7.283 9.867 4.869 1.00 92.11 C -ATOM 1094 C GLY A 150 -6.857 8.609 5.620 1.00 92.11 C -ATOM 1095 O GLY A 150 -6.796 8.582 6.845 1.00 92.11 O -ATOM 1096 N ASN A 151 -6.453 7.582 4.880 1.00 89.70 N -ATOM 1097 CA ASN A 151 -5.828 6.374 5.427 1.00 89.70 C -ATOM 1098 C ASN A 151 -4.518 6.621 6.209 1.00 89.70 C -ATOM 1099 CB ASN A 151 -5.603 5.371 4.280 1.00 89.70 C -ATOM 1100 O ASN A 151 -4.069 5.733 6.927 1.00 89.70 O -ATOM 1101 CG ASN A 151 -4.677 5.871 3.177 1.00 89.70 C -ATOM 1102 ND2 ASN A 151 -3.896 5.009 2.574 1.00 89.70 N -ATOM 1103 OD1 ASN A 151 -4.679 7.018 2.772 1.00 89.70 O -ATOM 1104 N ASP A 152 -3.900 7.797 6.073 1.00 89.34 N -ATOM 1105 CA ASP A 152 -2.756 8.258 6.873 1.00 89.34 C -ATOM 1106 C ASP A 152 -3.170 9.057 8.127 1.00 89.34 C -ATOM 1107 CB ASP A 152 -1.801 9.080 5.983 1.00 89.34 C -ATOM 1108 O ASP A 152 -2.312 9.628 8.801 1.00 89.34 O -ATOM 1109 CG ASP A 152 -2.340 10.472 5.620 1.00 89.34 C -ATOM 1110 OD1 ASP A 152 -3.574 10.682 5.719 1.00 89.34 O -ATOM 1111 OD2 ASP A 152 -1.539 11.337 5.195 1.00 89.34 O -ATOM 1112 N HIS A 153 -4.473 9.120 8.423 1.00 87.28 N -ATOM 1113 CA HIS A 153 -5.099 9.946 9.461 1.00 87.28 C -ATOM 1114 C HIS A 153 -5.012 11.463 9.228 1.00 87.28 C -ATOM 1115 CB HIS A 153 -4.616 9.527 10.857 1.00 87.28 C -ATOM 1116 O HIS A 153 -5.277 12.254 10.138 1.00 87.28 O -ATOM 1117 CG HIS A 153 -4.703 8.045 11.090 1.00 87.28 C -ATOM 1118 CD2 HIS A 153 -3.660 7.163 11.176 1.00 87.28 C -ATOM 1119 ND1 HIS A 153 -5.867 7.326 11.216 1.00 87.28 N -ATOM 1120 CE1 HIS A 153 -5.528 6.039 11.393 1.00 87.28 C -ATOM 1121 NE2 HIS A 153 -4.191 5.886 11.393 1.00 87.28 N -ATOM 1122 N SER A 154 -4.660 11.908 8.018 1.00 91.44 N -ATOM 1123 CA SER A 154 -4.793 13.315 7.641 1.00 91.44 C -ATOM 1124 C SER A 154 -6.264 13.702 7.537 1.00 91.44 C -ATOM 1125 CB SER A 154 -4.036 13.661 6.354 1.00 91.44 C -ATOM 1126 O SER A 154 -7.104 12.929 7.083 1.00 91.44 O -ATOM 1127 OG SER A 154 -4.559 13.010 5.217 1.00 91.44 O -ATOM 1128 N ILE A 155 -6.582 14.924 7.958 1.00 91.47 N -ATOM 1129 CA ILE A 155 -7.952 15.431 7.961 1.00 91.47 C -ATOM 1130 C ILE A 155 -8.014 16.694 7.112 1.00 91.47 C -ATOM 1131 CB ILE A 155 -8.453 15.653 9.401 1.00 91.47 C -ATOM 1132 O ILE A 155 -7.302 17.663 7.379 1.00 91.47 O -ATOM 1133 CG1 ILE A 155 -8.417 14.332 10.208 1.00 91.47 C -ATOM 1134 CG2 ILE A 155 -9.878 16.236 9.403 1.00 91.47 C -ATOM 1135 CD1 ILE A 155 -8.871 14.465 11.666 1.00 91.47 C -ATOM 1136 N LEU A 156 -8.914 16.701 6.133 1.00 93.61 N -ATOM 1137 CA LEU A 156 -9.310 17.890 5.384 1.00 93.61 C -ATOM 1138 C LEU A 156 -10.689 18.335 5.855 1.00 93.61 C -ATOM 1139 CB LEU A 156 -9.299 17.611 3.874 1.00 93.61 C -ATOM 1140 O LEU A 156 -11.538 17.500 6.169 1.00 93.61 O -ATOM 1141 CG LEU A 156 -7.988 17.009 3.343 1.00 93.61 C -ATOM 1142 CD1 LEU A 156 -8.120 16.779 1.842 1.00 93.61 C -ATOM 1143 CD2 LEU A 156 -6.780 17.911 3.601 1.00 93.61 C -ATOM 1144 N MET A 157 -10.920 19.643 5.912 1.00 93.53 N -ATOM 1145 CA MET A 157 -12.214 20.201 6.298 1.00 93.53 C -ATOM 1146 C MET A 157 -12.533 21.426 5.460 1.00 93.53 C -ATOM 1147 CB MET A 157 -12.257 20.569 7.789 1.00 93.53 C -ATOM 1148 O MET A 157 -11.643 22.212 5.134 1.00 93.53 O -ATOM 1149 CG MET A 157 -12.020 19.357 8.696 1.00 93.53 C -ATOM 1150 SD MET A 157 -12.177 19.651 10.480 1.00 93.53 S -ATOM 1151 CE MET A 157 -10.885 20.904 10.716 1.00 93.53 C -ATOM 1152 N CYS A 158 -13.807 21.604 5.149 1.00 93.41 N -ATOM 1153 CA CYS A 158 -14.303 22.822 4.540 1.00 93.41 C -ATOM 1154 C CYS A 158 -15.733 23.087 5.023 1.00 93.41 C -ATOM 1155 CB CYS A 158 -14.143 22.716 3.017 1.00 93.41 C -ATOM 1156 O CYS A 158 -16.476 22.158 5.348 1.00 93.41 O -ATOM 1157 SG CYS A 158 -15.352 21.679 2.183 1.00 93.41 S -ATOM 1158 N ASN A 159 -16.113 24.362 5.083 1.00 91.84 N -ATOM 1159 CA ASN A 159 -17.421 24.779 5.575 1.00 91.84 C -ATOM 1160 C ASN A 159 -18.182 25.487 4.457 1.00 91.84 C -ATOM 1161 CB ASN A 159 -17.265 25.686 6.805 1.00 91.84 C -ATOM 1162 O ASN A 159 -17.602 26.291 3.728 1.00 91.84 O -ATOM 1163 CG ASN A 159 -16.577 25.040 7.993 1.00 91.84 C -ATOM 1164 ND2 ASN A 159 -16.300 25.806 9.020 1.00 91.84 N -ATOM 1165 OD1 ASN A 159 -16.265 23.867 8.042 1.00 91.84 O -ATOM 1166 N SER A 160 -19.481 25.227 4.348 1.00 89.68 N -ATOM 1167 CA SER A 160 -20.331 25.855 3.339 1.00 89.68 C -ATOM 1168 C SER A 160 -21.763 25.995 3.837 1.00 89.68 C -ATOM 1169 CB SER A 160 -20.281 25.032 2.051 1.00 89.68 C -ATOM 1170 O SER A 160 -22.287 25.131 4.534 1.00 89.68 O -ATOM 1171 OG SER A 160 -20.925 25.693 0.982 1.00 89.68 O -ATOM 1172 N THR A 161 -22.411 27.098 3.475 1.00 86.55 N -ATOM 1173 CA THR A 161 -23.869 27.275 3.606 1.00 86.55 C -ATOM 1174 C THR A 161 -24.612 26.863 2.332 1.00 86.55 C -ATOM 1175 CB THR A 161 -24.204 28.732 3.940 1.00 86.55 C -ATOM 1176 O THR A 161 -25.840 26.872 2.298 1.00 86.55 O -ATOM 1177 CG2 THR A 161 -23.660 29.145 5.308 1.00 86.55 C -ATOM 1178 OG1 THR A 161 -23.622 29.593 2.983 1.00 86.55 O -ATOM 1179 N SER A 162 -23.868 26.526 1.275 1.00 87.03 N -ATOM 1180 CA SER A 162 -24.387 26.014 0.009 1.00 87.03 C -ATOM 1181 C SER A 162 -24.506 24.482 0.047 1.00 87.03 C -ATOM 1182 CB SER A 162 -23.467 26.492 -1.123 1.00 87.03 C -ATOM 1183 O SER A 162 -24.277 23.848 1.074 1.00 87.03 O -ATOM 1184 OG SER A 162 -24.083 26.303 -2.382 1.00 87.03 O -ATOM 1185 N THR A 163 -24.849 23.875 -1.087 1.00 89.21 N -ATOM 1186 CA THR A 163 -24.938 22.418 -1.300 1.00 89.21 C -ATOM 1187 C THR A 163 -23.628 21.776 -1.750 1.00 89.21 C -ATOM 1188 CB THR A 163 -26.025 22.110 -2.335 1.00 89.21 C -ATOM 1189 O THR A 163 -23.617 20.617 -2.164 1.00 89.21 O -ATOM 1190 CG2 THR A 163 -27.404 22.438 -1.782 1.00 89.21 C -ATOM 1191 OG1 THR A 163 -25.837 22.880 -3.503 1.00 89.21 O -ATOM 1192 N SER A 164 -22.531 22.531 -1.749 1.00 92.97 N -ATOM 1193 CA SER A 164 -21.218 22.047 -2.161 1.00 92.97 C -ATOM 1194 C SER A 164 -20.089 22.731 -1.405 1.00 92.97 C -ATOM 1195 CB SER A 164 -21.016 22.206 -3.672 1.00 92.97 C -ATOM 1196 O SER A 164 -20.238 23.858 -0.915 1.00 92.97 O -ATOM 1197 OG SER A 164 -20.987 23.574 -4.044 1.00 92.97 O -ATOM 1198 N CYS A 165 -18.955 22.040 -1.313 1.00 93.31 N -ATOM 1199 CA CYS A 165 -17.763 22.519 -0.636 1.00 93.31 C -ATOM 1200 C CYS A 165 -16.504 21.837 -1.177 1.00 93.31 C -ATOM 1201 CB CYS A 165 -17.965 22.248 0.851 1.00 93.31 C -ATOM 1202 O CYS A 165 -16.509 20.630 -1.415 1.00 93.31 O -ATOM 1203 SG CYS A 165 -16.806 23.048 1.952 1.00 93.31 S -ATOM 1204 N ASP A 166 -15.432 22.609 -1.345 1.00 94.82 N -ATOM 1205 CA ASP A 166 -14.152 22.108 -1.839 1.00 94.82 C -ATOM 1206 C ASP A 166 -13.191 21.857 -0.677 1.00 94.82 C -ATOM 1207 CB ASP A 166 -13.549 23.075 -2.866 1.00 94.82 C -ATOM 1208 O ASP A 166 -12.765 22.777 0.026 1.00 94.82 O -ATOM 1209 CG ASP A 166 -14.393 23.182 -4.137 1.00 94.82 C -ATOM 1210 OD1 ASP A 166 -14.913 22.136 -4.588 1.00 94.82 O -ATOM 1211 OD2 ASP A 166 -14.508 24.314 -4.651 1.00 94.82 O -ATOM 1212 N LEU A 167 -12.819 20.595 -0.489 1.00 95.09 N -ATOM 1213 CA LEU A 167 -11.753 20.193 0.416 1.00 95.09 C -ATOM 1214 C LEU A 167 -10.412 20.453 -0.264 1.00 95.09 C -ATOM 1215 CB LEU A 167 -11.907 18.710 0.754 1.00 95.09 C -ATOM 1216 O LEU A 167 -10.120 19.870 -1.306 1.00 95.09 O -ATOM 1217 CG LEU A 167 -13.182 18.362 1.536 1.00 95.09 C -ATOM 1218 CD1 LEU A 167 -13.343 16.849 1.513 1.00 95.09 C -ATOM 1219 CD2 LEU A 167 -13.080 18.813 2.991 1.00 95.09 C -ATOM 1220 N ILE A 168 -9.599 21.321 0.330 1.00 94.20 N -ATOM 1221 CA ILE A 168 -8.319 21.764 -0.230 1.00 94.20 C -ATOM 1222 C ILE A 168 -7.174 21.006 0.442 1.00 94.20 C -ATOM 1223 CB ILE A 168 -8.153 23.295 -0.075 1.00 94.20 C -ATOM 1224 O ILE A 168 -7.163 20.857 1.661 1.00 94.20 O -ATOM 1225 CG1 ILE A 168 -9.381 24.055 -0.633 1.00 94.20 C -ATOM 1226 CG2 ILE A 168 -6.853 23.760 -0.765 1.00 94.20 C -ATOM 1227 CD1 ILE A 168 -9.341 25.575 -0.439 1.00 94.20 C -ATOM 1228 N GLY A 169 -6.179 20.587 -0.342 1.00 92.75 N -ATOM 1229 CA GLY A 169 -4.979 19.911 0.161 1.00 92.75 C -ATOM 1230 C GLY A 169 -5.035 18.388 0.055 1.00 92.75 C -ATOM 1231 O GLY A 169 -4.292 17.703 0.760 1.00 92.75 O -ATOM 1232 N ALA A 170 -5.892 17.860 -0.823 1.00 92.72 N -ATOM 1233 CA ALA A 170 -5.925 16.442 -1.149 1.00 92.72 C -ATOM 1234 C ALA A 170 -4.571 15.986 -1.704 1.00 92.72 C -ATOM 1235 CB ALA A 170 -7.077 16.171 -2.119 1.00 92.72 C -ATOM 1236 O ALA A 170 -3.981 16.635 -2.572 1.00 92.72 O -ATOM 1237 N ARG A 171 -4.068 14.869 -1.174 1.00 91.52 N -ATOM 1238 CA ARG A 171 -2.792 14.273 -1.585 1.00 91.52 C -ATOM 1239 C ARG A 171 -3.040 13.126 -2.561 1.00 91.52 C -ATOM 1240 CB ARG A 171 -1.987 13.830 -0.353 1.00 91.52 C -ATOM 1241 O ARG A 171 -4.089 12.482 -2.525 1.00 91.52 O -ATOM 1242 CG ARG A 171 -1.692 14.989 0.609 1.00 91.52 C -ATOM 1243 CD ARG A 171 -0.927 14.483 1.833 1.00 91.52 C -ATOM 1244 NE ARG A 171 -0.649 15.595 2.761 1.00 91.52 N -ATOM 1245 NH1 ARG A 171 1.378 14.852 3.536 1.00 91.52 N -ATOM 1246 NH2 ARG A 171 0.544 16.781 4.291 1.00 91.52 N -ATOM 1247 CZ ARG A 171 0.421 15.737 3.520 1.00 91.52 C -ATOM 1248 N CYS A 172 -2.066 12.853 -3.423 1.00 92.05 N -ATOM 1249 CA CYS A 172 -2.077 11.647 -4.248 1.00 92.05 C -ATOM 1250 C CYS A 172 -1.940 10.393 -3.373 1.00 92.05 C -ATOM 1251 CB CYS A 172 -0.959 11.736 -5.296 1.00 92.05 C -ATOM 1252 O CYS A 172 -1.418 10.461 -2.261 1.00 92.05 O -ATOM 1253 SG CYS A 172 0.737 11.852 -4.642 1.00 92.05 S -ATOM 1254 N GLY A 173 -2.360 9.238 -3.884 1.00 91.78 N -ATOM 1255 CA GLY A 173 -2.153 7.963 -3.198 1.00 91.78 C -ATOM 1256 C GLY A 173 -3.049 7.739 -1.976 1.00 91.78 C -ATOM 1257 O GLY A 173 -2.762 6.845 -1.183 1.00 91.78 O -ATOM 1258 N MET A 174 -4.096 8.546 -1.800 1.00 91.89 N -ATOM 1259 CA MET A 174 -4.916 8.563 -0.591 1.00 91.89 C -ATOM 1260 C MET A 174 -6.243 7.849 -0.801 1.00 91.89 C -ATOM 1261 CB MET A 174 -5.170 10.004 -0.139 1.00 91.89 C -ATOM 1262 O MET A 174 -6.878 7.996 -1.847 1.00 91.89 O -ATOM 1263 CG MET A 174 -3.889 10.730 0.277 1.00 91.89 C -ATOM 1264 SD MET A 174 -2.868 9.918 1.529 1.00 91.89 S -ATOM 1265 CE MET A 174 -4.026 9.985 2.912 1.00 91.89 C -ATOM 1266 N HIS A 175 -6.682 7.134 0.232 1.00 91.96 N -ATOM 1267 CA HIS A 175 -8.063 6.683 0.368 1.00 91.96 C -ATOM 1268 C HIS A 175 -8.742 7.571 1.408 1.00 91.96 C -ATOM 1269 CB HIS A 175 -8.091 5.205 0.768 1.00 91.96 C -ATOM 1270 O HIS A 175 -8.279 7.614 2.547 1.00 91.96 O -ATOM 1271 CG HIS A 175 -9.424 4.560 0.500 1.00 91.96 C -ATOM 1272 CD2 HIS A 175 -9.711 3.780 -0.586 1.00 91.96 C -ATOM 1273 ND1 HIS A 175 -10.564 4.603 1.276 1.00 91.96 N -ATOM 1274 CE1 HIS A 175 -11.494 3.847 0.671 1.00 91.96 C -ATOM 1275 NE2 HIS A 175 -11.026 3.335 -0.478 1.00 91.96 N -ATOM 1276 N TYR A 176 -9.780 8.302 1.007 1.00 91.90 N -ATOM 1277 CA TYR A 176 -10.499 9.235 1.868 1.00 91.90 C -ATOM 1278 C TYR A 176 -11.899 8.721 2.187 1.00 91.90 C -ATOM 1279 CB TYR A 176 -10.582 10.630 1.228 1.00 91.90 C -ATOM 1280 O TYR A 176 -12.658 8.385 1.274 1.00 91.90 O -ATOM 1281 CG TYR A 176 -9.297 11.436 1.278 1.00 91.90 C -ATOM 1282 CD1 TYR A 176 -8.822 11.917 2.512 1.00 91.90 C -ATOM 1283 CD2 TYR A 176 -8.591 11.731 0.098 1.00 91.90 C -ATOM 1284 CE1 TYR A 176 -7.625 12.655 2.582 1.00 91.90 C -ATOM 1285 CE2 TYR A 176 -7.407 12.494 0.155 1.00 91.90 C -ATOM 1286 OH TYR A 176 -5.752 13.650 1.459 1.00 91.90 O -ATOM 1287 CZ TYR A 176 -6.913 12.944 1.398 1.00 91.90 C -ATOM 1288 N THR A 177 -12.255 8.783 3.467 1.00 92.26 N -ATOM 1289 CA THR A 177 -13.634 8.677 3.943 1.00 92.26 C -ATOM 1290 C THR A 177 -14.186 10.076 4.165 1.00 92.26 C -ATOM 1291 CB THR A 177 -13.723 7.893 5.254 1.00 92.26 C -ATOM 1292 O THR A 177 -13.655 10.841 4.972 1.00 92.26 O -ATOM 1293 CG2 THR A 177 -15.181 7.749 5.697 1.00 92.26 C -ATOM 1294 OG1 THR A 177 -13.159 6.616 5.118 1.00 92.26 O -ATOM 1295 N ILE A 178 -15.247 10.427 3.445 1.00 92.35 N -ATOM 1296 CA ILE A 178 -15.835 11.767 3.450 1.00 92.35 C -ATOM 1297 C ILE A 178 -17.199 11.729 4.128 1.00 92.35 C -ATOM 1298 CB ILE A 178 -15.913 12.350 2.023 1.00 92.35 C -ATOM 1299 O ILE A 178 -18.039 10.892 3.804 1.00 92.35 O -ATOM 1300 CG1 ILE A 178 -14.535 12.252 1.329 1.00 92.35 C -ATOM 1301 CG2 ILE A 178 -16.416 13.809 2.065 1.00 92.35 C -ATOM 1302 CD1 ILE A 178 -14.496 12.801 -0.094 1.00 92.35 C -ATOM 1303 N ILE A 179 -17.443 12.681 5.023 1.00 90.26 N -ATOM 1304 CA ILE A 179 -18.761 12.938 5.608 1.00 90.26 C -ATOM 1305 C ILE A 179 -19.103 14.421 5.513 1.00 90.26 C -ATOM 1306 CB ILE A 179 -18.869 12.434 7.066 1.00 90.26 C -ATOM 1307 O ILE A 179 -18.222 15.282 5.490 1.00 90.26 O -ATOM 1308 CG1 ILE A 179 -17.843 13.100 8.006 1.00 90.26 C -ATOM 1309 CG2 ILE A 179 -18.772 10.902 7.106 1.00 90.26 C -ATOM 1310 CD1 ILE A 179 -18.134 12.870 9.493 1.00 90.26 C -ATOM 1311 N VAL A 180 -20.399 14.714 5.502 1.00 89.75 N -ATOM 1312 CA VAL A 180 -20.930 16.065 5.693 1.00 89.75 C -ATOM 1313 C VAL A 180 -21.779 16.068 6.955 1.00 89.75 C -ATOM 1314 CB VAL A 180 -21.718 16.531 4.458 1.00 89.75 C -ATOM 1315 O VAL A 180 -22.612 15.182 7.137 1.00 89.75 O -ATOM 1316 CG1 VAL A 180 -22.342 17.917 4.666 1.00 89.75 C -ATOM 1317 CG2 VAL A 180 -20.799 16.614 3.232 1.00 89.75 C -ATOM 1318 N SER A 181 -21.588 17.058 7.821 1.00 87.20 N -ATOM 1319 CA SER A 181 -22.384 17.275 9.031 1.00 87.20 C -ATOM 1320 C SER A 181 -22.980 18.681 9.049 1.00 87.20 C -ATOM 1321 CB SER A 181 -21.552 16.986 10.290 1.00 87.20 C -ATOM 1322 O SER A 181 -22.356 19.639 8.603 1.00 87.20 O -ATOM 1323 OG SER A 181 -20.371 17.763 10.331 1.00 87.20 O -ATOM 1324 N ALA A 182 -24.192 18.833 9.589 1.00 81.02 N -ATOM 1325 CA ALA A 182 -24.825 20.146 9.798 1.00 81.02 C -ATOM 1326 C ALA A 182 -24.312 20.882 11.061 1.00 81.02 C -ATOM 1327 CB ALA A 182 -26.345 19.945 9.826 1.00 81.02 C -ATOM 1328 O ALA A 182 -24.807 21.949 11.416 1.00 81.02 O -ATOM 1329 N SER A 183 -23.354 20.279 11.770 1.00 73.04 N -ATOM 1330 CA SER A 183 -22.703 20.773 12.986 1.00 73.04 C -ATOM 1331 C SER A 183 -21.190 20.598 12.848 1.00 73.04 C -ATOM 1332 CB SER A 183 -23.224 19.987 14.197 1.00 73.04 C -ATOM 1333 O SER A 183 -20.736 19.716 12.118 1.00 73.04 O -ATOM 1334 OG SER A 183 -22.542 20.357 15.382 1.00 73.04 O -ATOM 1335 N SER A 184 -20.399 21.393 13.572 1.00 67.24 N -ATOM 1336 CA SER A 184 -18.947 21.191 13.683 1.00 67.24 C -ATOM 1337 C SER A 184 -18.571 19.896 14.412 1.00 67.24 C -ATOM 1338 CB SER A 184 -18.306 22.383 14.398 1.00 67.24 C -ATOM 1339 O SER A 184 -17.427 19.452 14.319 1.00 67.24 O -ATOM 1340 OG SER A 184 -18.935 22.612 15.647 1.00 67.24 O -ATOM 1341 N ASP A 185 -19.521 19.281 15.121 1.00 68.66 N -ATOM 1342 CA ASP A 185 -19.337 17.976 15.745 1.00 68.66 C -ATOM 1343 C ASP A 185 -19.498 16.844 14.715 1.00 68.66 C -ATOM 1344 CB ASP A 185 -20.282 17.827 16.942 1.00 68.66 C -ATOM 1345 O ASP A 185 -20.609 16.504 14.286 1.00 68.66 O -ATOM 1346 CG ASP A 185 -20.043 16.524 17.714 1.00 68.66 C -ATOM 1347 OD1 ASP A 185 -19.110 15.771 17.343 1.00 68.66 O -ATOM 1348 OD2 ASP A 185 -20.827 16.284 18.653 1.00 68.66 O -ATOM 1349 N LYS A 186 -18.361 16.246 14.344 1.00 66.46 N -ATOM 1350 CA LYS A 186 -18.256 15.142 13.378 1.00 66.46 C -ATOM 1351 C LYS A 186 -18.970 13.870 13.839 1.00 66.46 C -ATOM 1352 CB LYS A 186 -16.781 14.811 13.124 1.00 66.46 C -ATOM 1353 O LYS A 186 -19.402 13.086 13.000 1.00 66.46 O -ATOM 1354 CG LYS A 186 -15.978 15.990 12.562 1.00 66.46 C -ATOM 1355 CD LYS A 186 -14.542 15.534 12.304 1.00 66.46 C -ATOM 1356 CE LYS A 186 -13.715 16.708 11.789 1.00 66.46 C -ATOM 1357 NZ LYS A 186 -12.321 16.282 11.553 1.00 66.46 N -ATOM 1358 N CYS A 187 -19.124 13.681 15.151 1.00 69.95 N -ATOM 1359 CA CYS A 187 -19.844 12.543 15.719 1.00 69.95 C -ATOM 1360 C CYS A 187 -21.347 12.800 15.888 1.00 69.95 C -ATOM 1361 CB CYS A 187 -19.229 12.146 17.066 1.00 69.95 C -ATOM 1362 O CYS A 187 -22.060 11.930 16.393 1.00 69.95 O -ATOM 1363 SG CYS A 187 -17.541 11.493 17.096 1.00 69.95 S -ATOM 1364 N SER A 188 -21.850 13.972 15.487 1.00 70.41 N -ATOM 1365 CA SER A 188 -23.271 14.281 15.622 1.00 70.41 C -ATOM 1366 C SER A 188 -24.143 13.336 14.787 1.00 70.41 C -ATOM 1367 CB SER A 188 -23.561 15.754 15.314 1.00 70.41 C -ATOM 1368 O SER A 188 -23.752 12.831 13.733 1.00 70.41 O -ATOM 1369 OG SER A 188 -23.326 16.079 13.960 1.00 70.41 O -ATOM 1370 N SER A 189 -25.378 13.113 15.237 1.00 66.77 N -ATOM 1371 CA SER A 189 -26.383 12.358 14.473 1.00 66.77 C -ATOM 1372 C SER A 189 -26.819 13.078 13.187 1.00 66.77 C -ATOM 1373 CB SER A 189 -27.600 12.091 15.361 1.00 66.77 C -ATOM 1374 O SER A 189 -27.425 12.470 12.302 1.00 66.77 O -ATOM 1375 OG SER A 189 -28.073 13.306 15.919 1.00 66.77 O -ATOM 1376 N LEU A 190 -26.497 14.368 13.046 1.00 74.68 N -ATOM 1377 CA LEU A 190 -26.856 15.225 11.914 1.00 74.68 C -ATOM 1378 C LEU A 190 -25.822 15.163 10.779 1.00 74.68 C -ATOM 1379 CB LEU A 190 -27.111 16.659 12.406 1.00 74.68 C -ATOM 1380 O LEU A 190 -25.376 16.198 10.276 1.00 74.68 O -ATOM 1381 CG LEU A 190 -28.288 16.817 13.380 1.00 74.68 C -ATOM 1382 CD1 LEU A 190 -28.331 18.270 13.852 1.00 74.68 C -ATOM 1383 CD2 LEU A 190 -29.633 16.477 12.734 1.00 74.68 C -ATOM 1384 N ARG A 191 -25.437 13.948 10.383 1.00 82.69 N -ATOM 1385 CA ARG A 191 -24.436 13.698 9.338 1.00 82.69 C -ATOM 1386 C ARG A 191 -24.944 12.802 8.214 1.00 82.69 C -ATOM 1387 CB ARG A 191 -23.139 13.170 9.968 1.00 82.69 C -ATOM 1388 O ARG A 191 -25.976 12.138 8.351 1.00 82.69 O -ATOM 1389 CG ARG A 191 -23.309 11.754 10.521 1.00 82.69 C -ATOM 1390 CD ARG A 191 -22.036 11.314 11.232 1.00 82.69 C -ATOM 1391 NE ARG A 191 -22.269 10.005 11.841 1.00 82.69 N -ATOM 1392 NH1 ARG A 191 -21.257 8.684 10.242 1.00 82.69 N -ATOM 1393 NH2 ARG A 191 -22.229 7.775 12.032 1.00 82.69 N -ATOM 1394 CZ ARG A 191 -21.916 8.837 11.355 1.00 82.69 C -ATOM 1395 N SER A 192 -24.208 12.809 7.108 1.00 86.92 N -ATOM 1396 CA SER A 192 -24.403 11.911 5.974 1.00 86.92 C -ATOM 1397 C SER A 192 -23.793 10.531 6.227 1.00 86.92 C -ATOM 1398 CB SER A 192 -23.786 12.524 4.714 1.00 86.92 C -ATOM 1399 O SER A 192 -22.908 10.393 7.078 1.00 86.92 O -ATOM 1400 OG SER A 192 -22.367 12.541 4.772 1.00 86.92 O -ATOM 1401 N PRO A 193 -24.195 9.512 5.448 1.00 84.85 N -ATOM 1402 CA PRO A 193 -23.412 8.290 5.325 1.00 84.85 C -ATOM 1403 C PRO A 193 -21.978 8.610 4.871 1.00 84.85 C -ATOM 1404 CB PRO A 193 -24.161 7.413 4.316 1.00 84.85 C -ATOM 1405 O PRO A 193 -21.794 9.581 4.123 1.00 84.85 O -ATOM 1406 CG PRO A 193 -25.593 7.950 4.360 1.00 84.85 C -ATOM 1407 CD PRO A 193 -25.396 9.438 4.632 1.00 84.85 C -ATOM 1408 N PRO A 194 -20.977 7.827 5.310 1.00 88.88 N -ATOM 1409 CA PRO A 194 -19.612 7.958 4.819 1.00 88.88 C -ATOM 1410 C PRO A 194 -19.552 7.643 3.324 1.00 88.88 C -ATOM 1411 CB PRO A 194 -18.769 6.989 5.651 1.00 88.88 C -ATOM 1412 O PRO A 194 -20.191 6.703 2.844 1.00 88.88 O -ATOM 1413 CG PRO A 194 -19.777 5.906 6.019 1.00 88.88 C -ATOM 1414 CD PRO A 194 -21.074 6.690 6.211 1.00 88.88 C -ATOM 1415 N PHE A 195 -18.787 8.445 2.593 1.00 90.78 N -ATOM 1416 CA PHE A 195 -18.505 8.259 1.177 1.00 90.78 C -ATOM 1417 C PHE A 195 -17.018 7.974 0.989 1.00 90.78 C -ATOM 1418 CB PHE A 195 -18.958 9.495 0.396 1.00 90.78 C -ATOM 1419 O PHE A 195 -16.174 8.800 1.333 1.00 90.78 O -ATOM 1420 CG PHE A 195 -18.832 9.346 -1.106 1.00 90.78 C -ATOM 1421 CD1 PHE A 195 -17.620 9.653 -1.755 1.00 90.78 C -ATOM 1422 CD2 PHE A 195 -19.927 8.882 -1.857 1.00 90.78 C -ATOM 1423 CE1 PHE A 195 -17.511 9.495 -3.148 1.00 90.78 C -ATOM 1424 CE2 PHE A 195 -19.814 8.720 -3.248 1.00 90.78 C -ATOM 1425 CZ PHE A 195 -18.604 9.025 -3.894 1.00 90.78 C -ATOM 1426 N GLU A 196 -16.707 6.813 0.423 1.00 90.83 N -ATOM 1427 CA GLU A 196 -15.336 6.378 0.169 1.00 90.83 C -ATOM 1428 C GLU A 196 -14.879 6.782 -1.232 1.00 90.83 C -ATOM 1429 CB GLU A 196 -15.230 4.856 0.328 1.00 90.83 C -ATOM 1430 O GLU A 196 -15.587 6.569 -2.220 1.00 90.83 O -ATOM 1431 CG GLU A 196 -15.542 4.355 1.745 1.00 90.83 C -ATOM 1432 CD GLU A 196 -14.634 4.977 2.808 1.00 90.83 C -ATOM 1433 OE1 GLU A 196 -15.170 5.423 3.840 1.00 90.83 O -ATOM 1434 OE2 GLU A 196 -13.404 5.022 2.604 1.00 90.83 O -ATOM 1435 N MET A 197 -13.663 7.313 -1.335 1.00 90.26 N -ATOM 1436 CA MET A 197 -13.013 7.560 -2.619 1.00 90.26 C -ATOM 1437 C MET A 197 -11.500 7.395 -2.545 1.00 90.26 C -ATOM 1438 CB MET A 197 -13.369 8.952 -3.149 1.00 90.26 C -ATOM 1439 O MET A 197 -10.887 7.520 -1.490 1.00 90.26 O -ATOM 1440 CG MET A 197 -12.836 10.095 -2.275 1.00 90.26 C -ATOM 1441 SD MET A 197 -12.779 11.684 -3.132 1.00 90.26 S -ATOM 1442 CE MET A 197 -14.504 11.776 -3.606 1.00 90.26 C -ATOM 1443 N SER A 198 -10.881 7.177 -3.702 1.00 91.54 N -ATOM 1444 CA SER A 198 -9.426 7.200 -3.849 1.00 91.54 C -ATOM 1445 C SER A 198 -8.999 8.361 -4.736 1.00 91.54 C -ATOM 1446 CB SER A 198 -8.923 5.887 -4.441 1.00 91.54 C -ATOM 1447 O SER A 198 -9.622 8.608 -5.770 1.00 91.54 O -ATOM 1448 OG SER A 198 -9.232 4.805 -3.587 1.00 91.54 O -ATOM 1449 N THR A 199 -7.918 9.043 -4.364 1.00 91.35 N -ATOM 1450 CA THR A 199 -7.261 10.009 -5.251 1.00 91.35 C -ATOM 1451 C THR A 199 -6.426 9.290 -6.312 1.00 91.35 C -ATOM 1452 CB THR A 199 -6.425 11.035 -4.468 1.00 91.35 C -ATOM 1453 O THR A 199 -6.254 8.067 -6.284 1.00 91.35 O -ATOM 1454 CG2 THR A 199 -7.290 11.824 -3.489 1.00 91.35 C -ATOM 1455 OG1 THR A 199 -5.390 10.439 -3.723 1.00 91.35 O -ATOM 1456 N ALA A 200 -5.901 10.035 -7.288 1.00 92.36 N -ATOM 1457 CA ALA A 200 -4.970 9.465 -8.253 1.00 92.36 C -ATOM 1458 C ALA A 200 -3.713 8.918 -7.545 1.00 92.36 C -ATOM 1459 CB ALA A 200 -4.596 10.526 -9.286 1.00 92.36 C -ATOM 1460 O ALA A 200 -3.260 9.510 -6.557 1.00 92.36 O -ATOM 1461 N PRO A 201 -3.105 7.827 -8.043 1.00 94.47 N -ATOM 1462 CA PRO A 201 -1.851 7.330 -7.497 1.00 94.47 C -ATOM 1463 C PRO A 201 -0.753 8.392 -7.530 1.00 94.47 C -ATOM 1464 CB PRO A 201 -1.459 6.139 -8.367 1.00 94.47 C -ATOM 1465 O PRO A 201 -0.681 9.211 -8.450 1.00 94.47 O -ATOM 1466 CG PRO A 201 -2.787 5.668 -8.946 1.00 94.47 C -ATOM 1467 CD PRO A 201 -3.558 6.972 -9.128 1.00 94.47 C -ATOM 1468 N CYS A 202 0.155 8.347 -6.558 1.00 93.84 N -ATOM 1469 CA CYS A 202 1.364 9.156 -6.636 1.00 93.84 C -ATOM 1470 C CYS A 202 2.283 8.673 -7.761 1.00 93.84 C -ATOM 1471 CB CYS A 202 2.095 9.173 -5.294 1.00 93.84 C -ATOM 1472 O CYS A 202 2.325 7.484 -8.094 1.00 93.84 O -ATOM 1473 SG CYS A 202 1.204 9.985 -3.948 1.00 93.84 S -ATOM 1474 N VAL A 203 3.058 9.612 -8.306 1.00 94.50 N -ATOM 1475 CA VAL A 203 4.103 9.336 -9.297 1.00 94.50 C -ATOM 1476 C VAL A 203 5.057 8.270 -8.742 1.00 94.50 C -ATOM 1477 CB VAL A 203 4.893 10.616 -9.618 1.00 94.50 C -ATOM 1478 O VAL A 203 5.607 8.494 -7.658 1.00 94.50 O -ATOM 1479 CG1 VAL A 203 5.952 10.345 -10.683 1.00 94.50 C -ATOM 1480 CG2 VAL A 203 3.977 11.726 -10.143 1.00 94.50 C -ATOM 1481 N PRO A 204 5.277 7.142 -9.444 1.00 95.53 N -ATOM 1482 CA PRO A 204 6.189 6.104 -8.973 1.00 95.53 C -ATOM 1483 C PRO A 204 7.601 6.650 -8.729 1.00 95.53 C -ATOM 1484 CB PRO A 204 6.187 5.011 -10.042 1.00 95.53 C -ATOM 1485 O PRO A 204 8.102 7.473 -9.497 1.00 95.53 O -ATOM 1486 CG PRO A 204 4.852 5.215 -10.754 1.00 95.53 C -ATOM 1487 CD PRO A 204 4.618 6.720 -10.674 1.00 95.53 C -ATOM 1488 N GLN A 205 8.238 6.181 -7.656 1.00 94.67 N -ATOM 1489 CA GLN A 205 9.565 6.624 -7.212 1.00 94.67 C -ATOM 1490 C GLN A 205 10.571 5.467 -7.223 1.00 94.67 C -ATOM 1491 CB GLN A 205 9.472 7.247 -5.805 1.00 94.67 C -ATOM 1492 O GLN A 205 10.187 4.297 -7.296 1.00 94.67 O -ATOM 1493 CG GLN A 205 8.549 8.472 -5.716 1.00 94.67 C -ATOM 1494 CD GLN A 205 8.971 9.615 -6.634 1.00 94.67 C -ATOM 1495 NE2 GLN A 205 8.052 10.184 -7.379 1.00 94.67 N -ATOM 1496 OE1 GLN A 205 10.126 10.001 -6.702 1.00 94.67 O -ATOM 1497 N ASN A 206 11.861 5.799 -7.092 1.00 94.81 N -ATOM 1498 CA ASN A 206 12.974 4.843 -7.014 1.00 94.81 C -ATOM 1499 C ASN A 206 12.982 3.844 -8.179 1.00 94.81 C -ATOM 1500 CB ASN A 206 12.985 4.152 -5.640 1.00 94.81 C -ATOM 1501 O ASN A 206 13.012 2.632 -7.969 1.00 94.81 O -ATOM 1502 CG ASN A 206 13.010 5.121 -4.481 1.00 94.81 C -ATOM 1503 ND2 ASN A 206 12.225 4.880 -3.458 1.00 94.81 N -ATOM 1504 OD1 ASN A 206 13.720 6.110 -4.486 1.00 94.81 O -ATOM 1505 N VAL A 207 12.905 4.358 -9.408 1.00 95.64 N -ATOM 1506 CA VAL A 207 12.987 3.530 -10.613 1.00 95.64 C -ATOM 1507 C VAL A 207 14.417 3.005 -10.758 1.00 95.64 C -ATOM 1508 CB VAL A 207 12.537 4.297 -11.870 1.00 95.64 C -ATOM 1509 O VAL A 207 15.359 3.781 -10.899 1.00 95.64 O -ATOM 1510 CG1 VAL A 207 12.573 3.396 -13.112 1.00 95.64 C -ATOM 1511 CG2 VAL A 207 11.108 4.839 -11.724 1.00 95.64 C -ATOM 1512 N VAL A 208 14.570 1.684 -10.726 1.00 96.20 N -ATOM 1513 CA VAL A 208 15.836 0.966 -10.909 1.00 96.20 C -ATOM 1514 C VAL A 208 15.758 0.171 -12.204 1.00 96.20 C -ATOM 1515 CB VAL A 208 16.134 0.038 -9.717 1.00 96.20 C -ATOM 1516 O VAL A 208 14.787 -0.556 -12.424 1.00 96.20 O -ATOM 1517 CG1 VAL A 208 17.462 -0.709 -9.900 1.00 96.20 C -ATOM 1518 CG2 VAL A 208 16.210 0.818 -8.400 1.00 96.20 C -ATOM 1519 N LEU A 209 16.785 0.299 -13.044 1.00 95.76 N -ATOM 1520 CA LEU A 209 16.874 -0.348 -14.350 1.00 95.76 C -ATOM 1521 C LEU A 209 18.065 -1.309 -14.367 1.00 95.76 C -ATOM 1522 CB LEU A 209 17.008 0.716 -15.456 1.00 95.76 C -ATOM 1523 O LEU A 209 19.200 -0.890 -14.149 1.00 95.76 O -ATOM 1524 CG LEU A 209 15.935 1.820 -15.447 1.00 95.76 C -ATOM 1525 CD1 LEU A 209 16.193 2.793 -16.587 1.00 95.76 C -ATOM 1526 CD2 LEU A 209 14.526 1.262 -15.639 1.00 95.76 C -ATOM 1527 N ASN A 210 17.805 -2.580 -14.661 1.00 94.22 N -ATOM 1528 CA ASN A 210 18.814 -3.630 -14.767 1.00 94.22 C -ATOM 1529 C ASN A 210 18.857 -4.172 -16.197 1.00 94.22 C -ATOM 1530 CB ASN A 210 18.498 -4.742 -13.754 1.00 94.22 C -ATOM 1531 O ASN A 210 17.815 -4.370 -16.821 1.00 94.22 O -ATOM 1532 CG ASN A 210 18.662 -4.313 -12.306 1.00 94.22 C -ATOM 1533 ND2 ASN A 210 18.090 -5.051 -11.385 1.00 94.22 N -ATOM 1534 OD1 ASN A 210 19.312 -3.344 -11.964 1.00 94.22 O -ATOM 1535 N SER A 211 20.050 -4.451 -16.717 1.00 92.94 N -ATOM 1536 CA SER A 211 20.209 -5.062 -18.037 1.00 92.94 C -ATOM 1537 C SER A 211 19.846 -6.549 -18.023 1.00 92.94 C -ATOM 1538 CB SER A 211 21.632 -4.841 -18.564 1.00 92.94 C -ATOM 1539 O SER A 211 20.151 -7.278 -17.080 1.00 92.94 O -ATOM 1540 OG SER A 211 22.596 -5.245 -17.609 1.00 92.94 O -ATOM 1541 N MET A 212 19.202 -7.013 -19.096 1.00 91.28 N -ATOM 1542 CA MET A 212 18.914 -8.427 -19.344 1.00 91.28 C -ATOM 1543 C MET A 212 19.647 -8.873 -20.607 1.00 91.28 C -ATOM 1544 CB MET A 212 17.407 -8.665 -19.484 1.00 91.28 C -ATOM 1545 O MET A 212 19.113 -8.775 -21.715 1.00 91.28 O -ATOM 1546 CG MET A 212 16.614 -8.351 -18.214 1.00 91.28 C -ATOM 1547 SD MET A 212 14.866 -8.832 -18.314 1.00 91.28 S -ATOM 1548 CE MET A 212 14.368 -7.956 -19.822 1.00 91.28 C -ATOM 1549 N CYS A 213 20.874 -9.363 -20.436 1.00 84.27 N -ATOM 1550 CA CYS A 213 21.756 -9.732 -21.545 1.00 84.27 C -ATOM 1551 C CYS A 213 21.155 -10.818 -22.451 1.00 84.27 C -ATOM 1552 CB CYS A 213 23.108 -10.178 -20.974 1.00 84.27 C -ATOM 1553 O CYS A 213 21.280 -10.722 -23.666 1.00 84.27 O -ATOM 1554 SG CYS A 213 23.861 -8.826 -20.017 1.00 84.27 S -ATOM 1555 N ASP A 214 20.435 -11.792 -21.888 1.00 84.71 N -ATOM 1556 CA ASP A 214 19.877 -12.917 -22.656 1.00 84.71 C -ATOM 1557 C ASP A 214 18.805 -12.495 -23.675 1.00 84.71 C -ATOM 1558 CB ASP A 214 19.266 -13.942 -21.687 1.00 84.71 C -ATOM 1559 O ASP A 214 18.578 -13.183 -24.667 1.00 84.71 O -ATOM 1560 CG ASP A 214 20.274 -14.521 -20.692 1.00 84.71 C -ATOM 1561 OD1 ASP A 214 21.467 -14.624 -21.050 1.00 84.71 O -ATOM 1562 OD2 ASP A 214 19.841 -14.806 -19.555 1.00 84.71 O -ATOM 1563 N SER A 215 18.136 -11.363 -23.438 1.00 86.87 N -ATOM 1564 CA SER A 215 17.030 -10.867 -24.273 1.00 86.87 C -ATOM 1565 C SER A 215 17.333 -9.538 -24.967 1.00 86.87 C -ATOM 1566 CB SER A 215 15.739 -10.782 -23.451 1.00 86.87 C -ATOM 1567 O SER A 215 16.437 -8.956 -25.583 1.00 86.87 O -ATOM 1568 OG SER A 215 15.889 -9.884 -22.368 1.00 86.87 O -ATOM 1569 N ASN A 216 18.575 -9.042 -24.857 1.00 88.00 N -ATOM 1570 CA ASN A 216 18.959 -7.684 -25.259 1.00 88.00 C -ATOM 1571 C ASN A 216 17.972 -6.633 -24.720 1.00 88.00 C -ATOM 1572 CB ASN A 216 19.156 -7.627 -26.783 1.00 88.00 C -ATOM 1573 O ASN A 216 17.516 -5.753 -25.444 1.00 88.00 O -ATOM 1574 CG ASN A 216 20.261 -8.549 -27.251 1.00 88.00 C -ATOM 1575 ND2 ASN A 216 20.089 -9.199 -28.377 1.00 88.00 N -ATOM 1576 OD1 ASN A 216 21.296 -8.692 -26.625 1.00 88.00 O -ATOM 1577 N GLY A 217 17.569 -6.787 -23.460 1.00 92.79 N -ATOM 1578 CA GLY A 217 16.481 -6.025 -22.861 1.00 92.79 C -ATOM 1579 C GLY A 217 16.861 -5.348 -21.555 1.00 92.79 C -ATOM 1580 O GLY A 217 18.014 -5.374 -21.114 1.00 92.79 O -ATOM 1581 N MET A 218 15.852 -4.789 -20.895 1.00 94.65 N -ATOM 1582 CA MET A 218 15.960 -4.276 -19.534 1.00 94.65 C -ATOM 1583 C MET A 218 14.818 -4.762 -18.642 1.00 94.65 C -ATOM 1584 CB MET A 218 16.064 -2.747 -19.540 1.00 94.65 C -ATOM 1585 O MET A 218 13.690 -4.969 -19.091 1.00 94.65 O -ATOM 1586 CG MET A 218 14.742 -2.052 -19.861 1.00 94.65 C -ATOM 1587 SD MET A 218 14.876 -0.255 -19.841 1.00 94.65 S -ATOM 1588 CE MET A 218 13.206 0.090 -20.410 1.00 94.65 C -ATOM 1589 N MET A 219 15.114 -4.899 -17.356 1.00 95.36 N -ATOM 1590 CA MET A 219 14.137 -5.076 -16.294 1.00 95.36 C -ATOM 1591 C MET A 219 14.087 -3.798 -15.468 1.00 95.36 C -ATOM 1592 CB MET A 219 14.513 -6.287 -15.436 1.00 95.36 C -ATOM 1593 O MET A 219 15.088 -3.390 -14.882 1.00 95.36 O -ATOM 1594 CG MET A 219 13.467 -6.552 -14.348 1.00 95.36 C -ATOM 1595 SD MET A 219 13.793 -8.030 -13.349 1.00 95.36 S -ATOM 1596 CE MET A 219 13.431 -9.340 -14.552 1.00 95.36 C -ATOM 1597 N ALA A 220 12.914 -3.187 -15.405 1.00 96.83 N -ATOM 1598 CA ALA A 220 12.656 -2.043 -14.556 1.00 96.83 C -ATOM 1599 C ALA A 220 11.903 -2.475 -13.299 1.00 96.83 C -ATOM 1600 CB ALA A 220 11.873 -1.018 -15.359 1.00 96.83 C -ATOM 1601 O ALA A 220 11.018 -3.332 -13.355 1.00 96.83 O -ATOM 1602 N SER A 221 12.230 -1.850 -12.174 1.00 97.30 N -ATOM 1603 CA SER A 221 11.522 -2.004 -10.903 1.00 97.30 C -ATOM 1604 C SER A 221 11.376 -0.654 -10.209 1.00 97.30 C -ATOM 1605 CB SER A 221 12.232 -3.027 -10.015 1.00 97.30 C -ATOM 1606 O SER A 221 12.177 0.246 -10.447 1.00 97.30 O -ATOM 1607 OG SER A 221 13.537 -2.598 -9.685 1.00 97.30 O -ATOM 1608 N TRP A 222 10.337 -0.483 -9.396 1.00 96.10 N -ATOM 1609 CA TRP A 222 10.023 0.789 -8.734 1.00 96.10 C -ATOM 1610 C TRP A 222 9.342 0.566 -7.383 1.00 96.10 C -ATOM 1611 CB TRP A 222 9.138 1.645 -9.650 1.00 96.10 C -ATOM 1612 O TRP A 222 8.812 -0.509 -7.092 1.00 96.10 O -ATOM 1613 CG TRP A 222 7.916 0.947 -10.160 1.00 96.10 C -ATOM 1614 CD1 TRP A 222 6.689 0.957 -9.590 1.00 96.10 C -ATOM 1615 CD2 TRP A 222 7.798 0.116 -11.353 1.00 96.10 C -ATOM 1616 CE2 TRP A 222 6.460 -0.373 -11.423 1.00 96.10 C -ATOM 1617 CE3 TRP A 222 8.673 -0.235 -12.406 1.00 96.10 C -ATOM 1618 NE1 TRP A 222 5.827 0.175 -10.332 1.00 96.10 N -ATOM 1619 CH2 TRP A 222 6.900 -1.500 -13.510 1.00 96.10 C -ATOM 1620 CZ2 TRP A 222 6.015 -1.186 -12.469 1.00 96.10 C -ATOM 1621 CZ3 TRP A 222 8.227 -1.030 -13.478 1.00 96.10 C -ATOM 1622 N SER A 223 9.327 1.603 -6.546 1.00 95.88 N -ATOM 1623 CA SER A 223 8.591 1.568 -5.278 1.00 95.88 C -ATOM 1624 C SER A 223 7.071 1.561 -5.510 1.00 95.88 C -ATOM 1625 CB SER A 223 8.978 2.753 -4.398 1.00 95.88 C -ATOM 1626 O SER A 223 6.603 2.232 -6.431 1.00 95.88 O -ATOM 1627 OG SER A 223 10.338 2.614 -4.037 1.00 95.88 O -ATOM 1628 N PRO A 224 6.280 0.840 -4.693 1.00 93.58 N -ATOM 1629 CA PRO A 224 4.822 0.857 -4.798 1.00 93.58 C -ATOM 1630 C PRO A 224 4.217 2.249 -4.638 1.00 93.58 C -ATOM 1631 CB PRO A 224 4.306 -0.124 -3.735 1.00 93.58 C -ATOM 1632 O PRO A 224 4.501 2.951 -3.670 1.00 93.58 O -ATOM 1633 CG PRO A 224 5.506 -1.011 -3.402 1.00 93.58 C -ATOM 1634 CD PRO A 224 6.711 -0.119 -3.684 1.00 93.58 C -ATOM 1635 N SER A 225 3.332 2.611 -5.567 1.00 92.93 N -ATOM 1636 CA SER A 225 2.432 3.752 -5.427 1.00 92.93 C -ATOM 1637 C SER A 225 1.147 3.289 -4.744 1.00 92.93 C -ATOM 1638 CB SER A 225 2.111 4.374 -6.791 1.00 92.93 C -ATOM 1639 O SER A 225 0.486 2.366 -5.222 1.00 92.93 O -ATOM 1640 OG SER A 225 3.257 4.976 -7.362 1.00 92.93 O -ATOM 1641 N LEU A 226 0.774 3.933 -3.635 1.00 89.63 N -ATOM 1642 CA LEU A 226 -0.499 3.666 -2.960 1.00 89.63 C -ATOM 1643 C LEU A 226 -1.678 3.869 -3.924 1.00 89.63 C -ATOM 1644 CB LEU A 226 -0.639 4.558 -1.717 1.00 89.63 C -ATOM 1645 O LEU A 226 -1.602 4.694 -4.836 1.00 89.63 O -ATOM 1646 CG LEU A 226 0.325 4.226 -0.565 1.00 89.63 C -ATOM 1647 CD1 LEU A 226 0.234 5.308 0.510 1.00 89.63 C -ATOM 1648 CD2 LEU A 226 0.001 2.874 0.078 1.00 89.63 C -ATOM 1649 N VAL A 227 -2.734 3.074 -3.724 1.00 90.07 N -ATOM 1650 CA VAL A 227 -3.957 2.955 -4.545 1.00 90.07 C -ATOM 1651 C VAL A 227 -3.759 2.585 -6.025 1.00 90.07 C -ATOM 1652 CB VAL A 227 -4.936 4.139 -4.361 1.00 90.07 C -ATOM 1653 O VAL A 227 -4.744 2.394 -6.732 1.00 90.07 O -ATOM 1654 CG1 VAL A 227 -5.165 4.496 -2.886 1.00 90.07 C -ATOM 1655 CG2 VAL A 227 -4.552 5.420 -5.103 1.00 90.07 C -ATOM 1656 N ALA A 228 -2.525 2.439 -6.521 1.00 93.16 N -ATOM 1657 CA ALA A 228 -2.273 2.036 -7.902 1.00 93.16 C -ATOM 1658 C ALA A 228 -2.717 0.587 -8.154 1.00 93.16 C -ATOM 1659 CB ALA A 228 -0.788 2.214 -8.230 1.00 93.16 C -ATOM 1660 O ALA A 228 -2.333 -0.325 -7.425 1.00 93.16 O -ATOM 1661 N GLN A 229 -3.477 0.377 -9.228 1.00 93.80 N -ATOM 1662 CA GLN A 229 -3.899 -0.950 -9.690 1.00 93.80 C -ATOM 1663 C GLN A 229 -3.042 -1.453 -10.856 1.00 93.80 C -ATOM 1664 CB GLN A 229 -5.359 -0.876 -10.147 1.00 93.80 C -ATOM 1665 O GLN A 229 -2.936 -2.655 -11.094 1.00 93.80 O -ATOM 1666 CG GLN A 229 -6.357 -0.574 -9.018 1.00 93.80 C -ATOM 1667 CD GLN A 229 -7.783 -0.469 -9.554 1.00 93.80 C -ATOM 1668 NE2 GLN A 229 -8.770 -0.273 -8.714 1.00 93.80 N -ATOM 1669 OE1 GLN A 229 -8.033 -0.531 -10.747 1.00 93.80 O -ATOM 1670 N SER A 230 -2.449 -0.531 -11.615 1.00 96.03 N -ATOM 1671 CA SER A 230 -1.612 -0.852 -12.765 1.00 96.03 C -ATOM 1672 C SER A 230 -0.550 0.215 -12.993 1.00 96.03 C -ATOM 1673 CB SER A 230 -2.475 -1.040 -14.018 1.00 96.03 C -ATOM 1674 O SER A 230 -0.685 1.360 -12.560 1.00 96.03 O -ATOM 1675 OG SER A 230 -3.146 0.153 -14.377 1.00 96.03 O -ATOM 1676 N TYR A 231 0.504 -0.171 -13.697 1.00 96.98 N -ATOM 1677 CA TYR A 231 1.596 0.692 -14.103 1.00 96.98 C -ATOM 1678 C TYR A 231 1.811 0.579 -15.609 1.00 96.98 C -ATOM 1679 CB TYR A 231 2.871 0.325 -13.342 1.00 96.98 C -ATOM 1680 O TYR A 231 1.652 -0.499 -16.189 1.00 96.98 O -ATOM 1681 CG TYR A 231 2.768 0.428 -11.831 1.00 96.98 C -ATOM 1682 CD1 TYR A 231 3.127 1.621 -11.173 1.00 96.98 C -ATOM 1683 CD2 TYR A 231 2.315 -0.676 -11.082 1.00 96.98 C -ATOM 1684 CE1 TYR A 231 3.031 1.709 -9.769 1.00 96.98 C -ATOM 1685 CE2 TYR A 231 2.187 -0.581 -9.684 1.00 96.98 C -ATOM 1686 OH TYR A 231 2.432 0.702 -7.675 1.00 96.98 O -ATOM 1687 CZ TYR A 231 2.543 0.614 -9.026 1.00 96.98 C -ATOM 1688 N LEU A 232 2.203 1.687 -16.233 1.00 96.86 N -ATOM 1689 CA LEU A 232 2.615 1.740 -17.632 1.00 96.86 C -ATOM 1690 C LEU A 232 4.015 2.339 -17.706 1.00 96.86 C -ATOM 1691 CB LEU A 232 1.581 2.536 -18.445 1.00 96.86 C -ATOM 1692 O LEU A 232 4.209 3.525 -17.425 1.00 96.86 O -ATOM 1693 CG LEU A 232 1.975 2.765 -19.917 1.00 96.86 C -ATOM 1694 CD1 LEU A 232 1.929 1.468 -20.724 1.00 96.86 C -ATOM 1695 CD2 LEU A 232 1.006 3.755 -20.561 1.00 96.86 C -ATOM 1696 N LEU A 233 4.973 1.507 -18.098 1.00 97.30 N -ATOM 1697 CA LEU A 233 6.342 1.905 -18.381 1.00 97.30 C -ATOM 1698 C LEU A 233 6.479 2.231 -19.866 1.00 97.30 C -ATOM 1699 CB LEU A 233 7.274 0.786 -17.906 1.00 97.30 C -ATOM 1700 O LEU A 233 5.994 1.479 -20.709 1.00 97.30 O -ATOM 1701 CG LEU A 233 8.763 1.144 -18.053 1.00 97.30 C -ATOM 1702 CD1 LEU A 233 9.546 0.468 -16.942 1.00 97.30 C -ATOM 1703 CD2 LEU A 233 9.350 0.650 -19.373 1.00 97.30 C -ATOM 1704 N THR A 234 7.150 3.338 -20.171 1.00 97.08 N -ATOM 1705 CA THR A 234 7.455 3.792 -21.532 1.00 97.08 C -ATOM 1706 C THR A 234 8.951 4.050 -21.646 1.00 97.08 C -ATOM 1707 CB THR A 234 6.668 5.064 -21.877 1.00 97.08 C -ATOM 1708 O THR A 234 9.509 4.793 -20.838 1.00 97.08 O -ATOM 1709 CG2 THR A 234 6.864 5.506 -23.327 1.00 97.08 C -ATOM 1710 OG1 THR A 234 5.291 4.830 -21.684 1.00 97.08 O -ATOM 1711 N ALA A 235 9.588 3.442 -22.641 1.00 96.74 N -ATOM 1712 CA ALA A 235 10.988 3.634 -22.979 1.00 96.74 C -ATOM 1713 C ALA A 235 11.077 4.180 -24.404 1.00 96.74 C -ATOM 1714 CB ALA A 235 11.715 2.296 -22.823 1.00 96.74 C -ATOM 1715 O ALA A 235 10.597 3.537 -25.333 1.00 96.74 O -ATOM 1716 N SER A 236 11.672 5.356 -24.572 1.00 96.76 N -ATOM 1717 CA SER A 236 11.827 6.004 -25.879 1.00 96.76 C -ATOM 1718 C SER A 236 13.292 6.285 -26.169 1.00 96.76 C -ATOM 1719 CB SER A 236 11.030 7.310 -25.930 1.00 96.76 C -ATOM 1720 O SER A 236 13.979 6.823 -25.296 1.00 96.76 O -ATOM 1721 OG SER A 236 11.480 8.195 -24.918 1.00 96.76 O -ATOM 1722 N SER A 237 13.755 5.989 -27.378 1.00 95.64 N -ATOM 1723 CA SER A 237 15.117 6.290 -27.813 1.00 95.64 C -ATOM 1724 C SER A 237 15.168 7.387 -28.883 1.00 95.64 C -ATOM 1725 CB SER A 237 15.815 5.010 -28.258 1.00 95.64 C -ATOM 1726 O SER A 237 14.163 7.753 -29.492 1.00 95.64 O -ATOM 1727 OG SER A 237 17.180 5.323 -28.412 1.00 95.64 O -ATOM 1728 N SER A 238 16.356 7.959 -29.087 1.00 93.34 N -ATOM 1729 CA SER A 238 16.622 9.013 -30.071 1.00 93.34 C -ATOM 1730 C SER A 238 16.487 8.557 -31.525 1.00 93.34 C -ATOM 1731 CB SER A 238 18.033 9.569 -29.861 1.00 93.34 C -ATOM 1732 O SER A 238 16.347 9.400 -32.407 1.00 93.34 O -ATOM 1733 OG SER A 238 18.998 8.540 -29.702 1.00 93.34 O -ATOM 1734 N ASP A 239 16.539 7.251 -31.783 1.00 92.94 N -ATOM 1735 CA ASP A 239 16.326 6.664 -33.110 1.00 92.94 C -ATOM 1736 C ASP A 239 14.836 6.550 -33.497 1.00 92.94 C -ATOM 1737 CB ASP A 239 17.042 5.306 -33.178 1.00 92.94 C -ATOM 1738 O ASP A 239 14.518 6.191 -34.630 1.00 92.94 O -ATOM 1739 CG ASP A 239 16.412 4.223 -32.296 1.00 92.94 C -ATOM 1740 OD1 ASP A 239 15.519 4.558 -31.487 1.00 92.94 O -ATOM 1741 OD2 ASP A 239 16.837 3.058 -32.445 1.00 92.94 O -ATOM 1742 N GLY A 240 13.929 6.897 -32.577 1.00 93.53 N -ATOM 1743 CA GLY A 240 12.481 6.838 -32.759 1.00 93.53 C -ATOM 1744 C GLY A 240 11.828 5.559 -32.234 1.00 93.53 C -ATOM 1745 O GLY A 240 10.603 5.457 -32.314 1.00 93.53 O -ATOM 1746 N ASP A 241 12.592 4.611 -31.680 1.00 94.68 N -ATOM 1747 CA ASP A 241 12.017 3.420 -31.059 1.00 94.68 C -ATOM 1748 C ASP A 241 11.290 3.771 -29.753 1.00 94.68 C -ATOM 1749 CB ASP A 241 13.080 2.331 -30.858 1.00 94.68 C -ATOM 1750 O ASP A 241 11.806 4.498 -28.895 1.00 94.68 O -ATOM 1751 CG ASP A 241 12.439 1.028 -30.375 1.00 94.68 C -ATOM 1752 OD1 ASP A 241 11.345 0.693 -30.885 1.00 94.68 O -ATOM 1753 OD2 ASP A 241 13.005 0.416 -29.440 1.00 94.68 O -ATOM 1754 N VAL A 242 10.065 3.260 -29.606 1.00 95.95 N -ATOM 1755 CA VAL A 242 9.214 3.481 -28.432 1.00 95.95 C -ATOM 1756 C VAL A 242 8.582 2.166 -28.015 1.00 95.95 C -ATOM 1757 CB VAL A 242 8.133 4.558 -28.650 1.00 95.95 C -ATOM 1758 O VAL A 242 7.713 1.617 -28.692 1.00 95.95 O -ATOM 1759 CG1 VAL A 242 7.334 4.792 -27.354 1.00 95.95 C -ATOM 1760 CG2 VAL A 242 8.734 5.908 -29.057 1.00 95.95 C -ATOM 1761 N LEU A 243 8.972 1.701 -26.835 1.00 95.53 N -ATOM 1762 CA LEU A 243 8.505 0.458 -26.247 1.00 95.53 C -ATOM 1763 C LEU A 243 7.703 0.750 -24.985 1.00 95.53 C -ATOM 1764 CB LEU A 243 9.712 -0.448 -25.988 1.00 95.53 C -ATOM 1765 O LEU A 243 8.040 1.631 -24.191 1.00 95.53 O -ATOM 1766 CG LEU A 243 10.346 -0.978 -27.290 1.00 95.53 C -ATOM 1767 CD1 LEU A 243 11.765 -1.423 -26.990 1.00 95.53 C -ATOM 1768 CD2 LEU A 243 9.570 -2.170 -27.850 1.00 95.53 C -ATOM 1769 N THR A 244 6.630 -0.010 -24.787 1.00 96.69 N -ATOM 1770 CA THR A 244 5.779 0.118 -23.602 1.00 96.69 C -ATOM 1771 C THR A 244 5.496 -1.233 -22.980 1.00 96.69 C -ATOM 1772 CB THR A 244 4.459 0.852 -23.874 1.00 96.69 C -ATOM 1773 O THR A 244 5.415 -2.248 -23.669 1.00 96.69 O -ATOM 1774 CG2 THR A 244 4.654 2.274 -24.387 1.00 96.69 C -ATOM 1775 OG1 THR A 244 3.667 0.168 -24.815 1.00 96.69 O -ATOM 1776 N CYS A 245 5.335 -1.252 -21.661 1.00 95.53 N -ATOM 1777 CA CYS A 245 4.934 -2.452 -20.944 1.00 95.53 C -ATOM 1778 C CYS A 245 4.017 -2.099 -19.776 1.00 95.53 C -ATOM 1779 CB CYS A 245 6.179 -3.256 -20.573 1.00 95.53 C -ATOM 1780 O CYS A 245 4.239 -1.139 -19.033 1.00 95.53 O -ATOM 1781 SG CYS A 245 6.139 -4.241 -19.059 1.00 95.53 S -ATOM 1782 N LYS A 246 2.940 -2.878 -19.662 1.00 96.04 N -ATOM 1783 CA LYS A 246 1.927 -2.755 -18.617 1.00 96.04 C -ATOM 1784 C LYS A 246 2.159 -3.829 -17.571 1.00 96.04 C -ATOM 1785 CB LYS A 246 0.514 -2.864 -19.206 1.00 96.04 C -ATOM 1786 O LYS A 246 2.362 -4.987 -17.924 1.00 96.04 O -ATOM 1787 CG LYS A 246 0.159 -1.638 -20.054 1.00 96.04 C -ATOM 1788 CD LYS A 246 -1.267 -1.750 -20.604 1.00 96.04 C -ATOM 1789 CE LYS A 246 -1.595 -0.509 -21.441 1.00 96.04 C -ATOM 1790 NZ LYS A 246 -2.980 -0.555 -21.970 1.00 96.04 N -ATOM 1791 N SER A 247 2.082 -3.452 -16.302 1.00 95.41 N -ATOM 1792 CA SER A 247 2.252 -4.382 -15.190 1.00 95.41 C -ATOM 1793 C SER A 247 1.283 -4.074 -14.055 1.00 95.41 C -ATOM 1794 CB SER A 247 3.696 -4.340 -14.700 1.00 95.41 C -ATOM 1795 O SER A 247 0.982 -2.913 -13.786 1.00 95.41 O -ATOM 1796 OG SER A 247 3.868 -5.378 -13.772 1.00 95.41 O -ATOM 1797 N THR A 248 0.788 -5.111 -13.385 1.00 95.16 N -ATOM 1798 CA THR A 248 0.049 -4.998 -12.114 1.00 95.16 C -ATOM 1799 C THR A 248 0.973 -5.152 -10.905 1.00 95.16 C -ATOM 1800 CB THR A 248 -1.078 -6.036 -12.040 1.00 95.16 C -ATOM 1801 O THR A 248 0.538 -4.998 -9.769 1.00 95.16 O -ATOM 1802 CG2 THR A 248 -2.119 -5.828 -13.140 1.00 95.16 C -ATOM 1803 OG1 THR A 248 -0.546 -7.334 -12.196 1.00 95.16 O -ATOM 1804 N THR A 249 2.247 -5.473 -11.139 1.00 94.79 N -ATOM 1805 CA THR A 249 3.297 -5.586 -10.126 1.00 94.79 C -ATOM 1806 C THR A 249 4.271 -4.413 -10.237 1.00 94.79 C -ATOM 1807 CB THR A 249 4.042 -6.932 -10.245 1.00 94.79 C -ATOM 1808 O THR A 249 4.193 -3.573 -11.130 1.00 94.79 O -ATOM 1809 CG2 THR A 249 3.106 -8.119 -10.014 1.00 94.79 C -ATOM 1810 OG1 THR A 249 4.595 -7.084 -11.529 1.00 94.79 O -ATOM 1811 N ASN A 250 5.223 -4.357 -9.311 1.00 95.13 N -ATOM 1812 CA ASN A 250 6.231 -3.301 -9.189 1.00 95.13 C -ATOM 1813 C ASN A 250 7.441 -3.462 -10.116 1.00 95.13 C -ATOM 1814 CB ASN A 250 6.638 -3.266 -7.717 1.00 95.13 C -ATOM 1815 O ASN A 250 8.518 -2.928 -9.844 1.00 95.13 O -ATOM 1816 CG ASN A 250 5.471 -2.787 -6.905 1.00 95.13 C -ATOM 1817 ND2 ASN A 250 5.416 -1.509 -6.683 1.00 95.13 N -ATOM 1818 OD1 ASN A 250 4.572 -3.525 -6.545 1.00 95.13 O -ATOM 1819 N ASN A 251 7.293 -4.262 -11.166 1.00 96.32 N -ATOM 1820 CA ASN A 251 8.343 -4.548 -12.122 1.00 96.32 C -ATOM 1821 C ASN A 251 7.766 -4.786 -13.515 1.00 96.32 C -ATOM 1822 CB ASN A 251 9.209 -5.718 -11.618 1.00 96.32 C -ATOM 1823 O ASN A 251 6.587 -5.098 -13.687 1.00 96.32 O -ATOM 1824 CG ASN A 251 8.459 -7.023 -11.385 1.00 96.32 C -ATOM 1825 ND2 ASN A 251 9.033 -7.924 -10.627 1.00 96.32 N -ATOM 1826 OD1 ASN A 251 7.356 -7.268 -11.841 1.00 96.32 O -ATOM 1827 N CYS A 252 8.611 -4.599 -14.519 1.00 96.24 N -ATOM 1828 CA CYS A 252 8.263 -4.781 -15.917 1.00 96.24 C -ATOM 1829 C CYS A 252 9.536 -5.039 -16.727 1.00 96.24 C -ATOM 1830 CB CYS A 252 7.525 -3.524 -16.381 1.00 96.24 C -ATOM 1831 O CYS A 252 10.587 -4.452 -16.464 1.00 96.24 O -ATOM 1832 SG CYS A 252 7.582 -3.191 -18.137 1.00 96.24 S -ATOM 1833 N THR A 253 9.438 -5.922 -17.714 1.00 95.25 N -ATOM 1834 CA THR A 253 10.535 -6.293 -18.606 1.00 95.25 C -ATOM 1835 C THR A 253 10.259 -5.792 -20.019 1.00 95.25 C -ATOM 1836 CB THR A 253 10.760 -7.811 -18.587 1.00 95.25 C -ATOM 1837 O THR A 253 9.179 -6.004 -20.565 1.00 95.25 O -ATOM 1838 CG2 THR A 253 11.391 -8.251 -17.267 1.00 95.25 C -ATOM 1839 OG1 THR A 253 9.549 -8.520 -18.707 1.00 95.25 O -ATOM 1840 N LEU A 254 11.251 -5.134 -20.620 1.00 94.89 N -ATOM 1841 CA LEU A 254 11.237 -4.729 -22.024 1.00 94.89 C -ATOM 1842 C LEU A 254 12.366 -5.456 -22.767 1.00 94.89 C -ATOM 1843 CB LEU A 254 11.349 -3.199 -22.149 1.00 94.89 C -ATOM 1844 O LEU A 254 13.534 -5.123 -22.554 1.00 94.89 O -ATOM 1845 CG LEU A 254 10.041 -2.438 -21.858 1.00 94.89 C -ATOM 1846 CD1 LEU A 254 10.254 -0.948 -22.107 1.00 94.89 C -ATOM 1847 CD2 LEU A 254 8.893 -2.871 -22.770 1.00 94.89 C -ATOM 1848 N PRO A 255 12.051 -6.479 -23.579 1.00 93.40 N -ATOM 1849 CA PRO A 255 13.036 -7.183 -24.396 1.00 93.40 C -ATOM 1850 C PRO A 255 13.342 -6.426 -25.700 1.00 93.40 C -ATOM 1851 CB PRO A 255 12.394 -8.549 -24.647 1.00 93.40 C -ATOM 1852 O PRO A 255 12.616 -5.503 -26.065 1.00 93.40 O -ATOM 1853 CG PRO A 255 10.906 -8.213 -24.759 1.00 93.40 C -ATOM 1854 CD PRO A 255 10.729 -7.074 -23.757 1.00 93.40 C -ATOM 1855 N HIS A 256 14.371 -6.873 -26.429 1.00 91.17 N -ATOM 1856 CA HIS A 256 14.667 -6.451 -27.808 1.00 91.17 C -ATOM 1857 C HIS A 256 14.919 -4.946 -28.004 1.00 91.17 C -ATOM 1858 CB HIS A 256 13.602 -6.996 -28.778 1.00 91.17 C -ATOM 1859 O HIS A 256 14.514 -4.375 -29.013 1.00 91.17 O -ATOM 1860 CG HIS A 256 13.353 -8.473 -28.646 1.00 91.17 C -ATOM 1861 CD2 HIS A 256 12.182 -9.073 -28.274 1.00 91.17 C -ATOM 1862 ND1 HIS A 256 14.273 -9.471 -28.860 1.00 91.17 N -ATOM 1863 CE1 HIS A 256 13.673 -10.646 -28.617 1.00 91.17 C -ATOM 1864 NE2 HIS A 256 12.396 -10.456 -28.250 1.00 91.17 N -ATOM 1865 N LEU A 257 15.623 -4.314 -27.066 1.00 94.11 N -ATOM 1866 CA LEU A 257 16.084 -2.937 -27.227 1.00 94.11 C -ATOM 1867 C LEU A 257 17.154 -2.864 -28.326 1.00 94.11 C -ATOM 1868 CB LEU A 257 16.632 -2.410 -25.887 1.00 94.11 C -ATOM 1869 O LEU A 257 18.011 -3.748 -28.438 1.00 94.11 O -ATOM 1870 CG LEU A 257 15.618 -2.384 -24.729 1.00 94.11 C -ATOM 1871 CD1 LEU A 257 16.335 -2.065 -23.420 1.00 94.11 C -ATOM 1872 CD2 LEU A 257 14.553 -1.314 -24.925 1.00 94.11 C -ATOM 1873 N HIS A 258 17.138 -1.795 -29.120 1.00 93.99 N -ATOM 1874 CA HIS A 258 18.170 -1.538 -30.118 1.00 93.99 C -ATOM 1875 C HIS A 258 19.529 -1.317 -29.448 1.00 93.99 C -ATOM 1876 CB HIS A 258 17.784 -0.331 -30.975 1.00 93.99 C -ATOM 1877 O HIS A 258 19.653 -0.568 -28.482 1.00 93.99 O -ATOM 1878 CG HIS A 258 16.622 -0.548 -31.911 1.00 93.99 C -ATOM 1879 CD2 HIS A 258 15.985 -1.719 -32.230 1.00 93.99 C -ATOM 1880 ND1 HIS A 258 16.015 0.446 -32.635 1.00 93.99 N -ATOM 1881 CE1 HIS A 258 15.038 -0.105 -33.368 1.00 93.99 C -ATOM 1882 NE2 HIS A 258 15.002 -1.435 -33.184 1.00 93.99 N -ATOM 1883 N CYS A 259 20.565 -1.968 -29.972 1.00 92.06 N -ATOM 1884 CA CYS A 259 21.926 -1.829 -29.468 1.00 92.06 C -ATOM 1885 C CYS A 259 22.489 -0.418 -29.713 1.00 92.06 C -ATOM 1886 CB CYS A 259 22.793 -2.917 -30.109 1.00 92.06 C -ATOM 1887 O CYS A 259 22.090 0.281 -30.645 1.00 92.06 O -ATOM 1888 SG CYS A 259 22.867 -2.863 -31.928 1.00 92.06 S -ATOM 1889 N GLY A 260 23.449 0.003 -28.889 1.00 91.36 N -ATOM 1890 CA GLY A 260 24.135 1.293 -29.014 1.00 91.36 C -ATOM 1891 C GLY A 260 23.255 2.522 -28.763 1.00 91.36 C -ATOM 1892 O GLY A 260 23.721 3.644 -28.951 1.00 91.36 O -ATOM 1893 N GLN A 261 22.011 2.325 -28.333 1.00 94.17 N -ATOM 1894 CA GLN A 261 21.043 3.377 -28.060 1.00 94.17 C -ATOM 1895 C GLN A 261 20.945 3.719 -26.571 1.00 94.17 C -ATOM 1896 CB GLN A 261 19.668 2.960 -28.597 1.00 94.17 C -ATOM 1897 O GLN A 261 21.199 2.888 -25.688 1.00 94.17 O -ATOM 1898 CG GLN A 261 19.580 2.805 -30.121 1.00 94.17 C -ATOM 1899 CD GLN A 261 20.159 3.978 -30.906 1.00 94.17 C -ATOM 1900 NE2 GLN A 261 20.912 3.704 -31.949 1.00 94.17 N -ATOM 1901 OE1 GLN A 261 20.004 5.149 -30.583 1.00 94.17 O -ATOM 1902 N VAL A 262 20.510 4.949 -26.299 1.00 95.71 N -ATOM 1903 CA VAL A 262 20.081 5.395 -24.969 1.00 95.71 C -ATOM 1904 C VAL A 262 18.561 5.483 -24.967 1.00 95.71 C -ATOM 1905 CB VAL A 262 20.732 6.732 -24.569 1.00 95.71 C -ATOM 1906 O VAL A 262 17.978 6.143 -25.827 1.00 95.71 O -ATOM 1907 CG1 VAL A 262 20.383 7.101 -23.119 1.00 95.71 C -ATOM 1908 CG2 VAL A 262 22.261 6.646 -24.683 1.00 95.71 C -ATOM 1909 N TYR A 263 17.923 4.809 -24.015 1.00 96.24 N -ATOM 1910 CA TYR A 263 16.478 4.861 -23.811 1.00 96.24 C -ATOM 1911 C TYR A 263 16.154 5.737 -22.604 1.00 96.24 C -ATOM 1912 CB TYR A 263 15.902 3.448 -23.645 1.00 96.24 C -ATOM 1913 O TYR A 263 16.674 5.516 -21.510 1.00 96.24 O -ATOM 1914 CG TYR A 263 15.766 2.678 -24.944 1.00 96.24 C -ATOM 1915 CD1 TYR A 263 14.514 2.588 -25.587 1.00 96.24 C -ATOM 1916 CD2 TYR A 263 16.892 2.057 -25.517 1.00 96.24 C -ATOM 1917 CE1 TYR A 263 14.381 1.854 -26.781 1.00 96.24 C -ATOM 1918 CE2 TYR A 263 16.760 1.326 -26.715 1.00 96.24 C -ATOM 1919 OH TYR A 263 15.385 0.451 -28.459 1.00 96.24 O -ATOM 1920 CZ TYR A 263 15.503 1.209 -27.341 1.00 96.24 C -ATOM 1921 N ASN A 264 15.253 6.696 -22.790 1.00 96.81 N -ATOM 1922 CA ASN A 264 14.666 7.478 -21.710 1.00 96.81 C -ATOM 1923 C ASN A 264 13.459 6.713 -21.175 1.00 96.81 C -ATOM 1924 CB ASN A 264 14.273 8.869 -22.225 1.00 96.81 C -ATOM 1925 O ASN A 264 12.468 6.530 -21.887 1.00 96.81 O -ATOM 1926 CG ASN A 264 15.463 9.689 -22.685 1.00 96.81 C -ATOM 1927 ND2 ASN A 264 15.227 10.695 -23.491 1.00 96.81 N -ATOM 1928 OD1 ASN A 264 16.608 9.450 -22.350 1.00 96.81 O -ATOM 1929 N VAL A 265 13.550 6.252 -19.931 1.00 96.86 N -ATOM 1930 CA VAL A 265 12.529 5.408 -19.311 1.00 96.86 C -ATOM 1931 C VAL A 265 11.708 6.229 -18.335 1.00 96.86 C -ATOM 1932 CB VAL A 265 13.145 4.174 -18.637 1.00 96.86 C -ATOM 1933 O VAL A 265 12.251 6.911 -17.468 1.00 96.86 O -ATOM 1934 CG1 VAL A 265 12.043 3.202 -18.198 1.00 96.86 C -ATOM 1935 CG2 VAL A 265 14.085 3.452 -19.610 1.00 96.86 C -ATOM 1936 N SER A 266 10.389 6.148 -18.461 1.00 97.12 N -ATOM 1937 CA SER A 266 9.436 6.788 -17.558 1.00 97.12 C -ATOM 1938 C SER A 266 8.305 5.834 -17.213 1.00 97.12 C -ATOM 1939 CB SER A 266 8.893 8.081 -18.169 1.00 97.12 C -ATOM 1940 O SER A 266 8.003 4.902 -17.963 1.00 97.12 O -ATOM 1941 OG SER A 266 8.154 7.816 -19.345 1.00 97.12 O -ATOM 1942 N ILE A 267 7.675 6.056 -16.064 1.00 96.80 N -ATOM 1943 CA ILE A 267 6.574 5.221 -15.603 1.00 96.80 C -ATOM 1944 C ILE A 267 5.424 6.051 -15.047 1.00 96.80 C -ATOM 1945 CB ILE A 267 7.098 4.156 -14.627 1.00 96.80 C -ATOM 1946 O ILE A 267 5.625 7.076 -14.398 1.00 96.80 O -ATOM 1947 CG1 ILE A 267 5.974 3.157 -14.318 1.00 96.80 C -ATOM 1948 CG2 ILE A 267 7.728 4.771 -13.368 1.00 96.80 C -ATOM 1949 CD1 ILE A 267 6.517 1.935 -13.610 1.00 96.80 C -ATOM 1950 N THR A 268 4.206 5.584 -15.298 1.00 96.43 N -ATOM 1951 CA THR A 268 2.966 6.130 -14.739 1.00 96.43 C -ATOM 1952 C THR A 268 2.242 5.053 -13.936 1.00 96.43 C -ATOM 1953 CB THR A 268 2.050 6.683 -15.839 1.00 96.43 C -ATOM 1954 O THR A 268 2.322 3.868 -14.264 1.00 96.43 O -ATOM 1955 CG2 THR A 268 2.650 7.881 -16.569 1.00 96.43 C -ATOM 1956 OG1 THR A 268 1.788 5.698 -16.808 1.00 96.43 O -ATOM 1957 N ALA A 269 1.540 5.456 -12.878 1.00 96.37 N -ATOM 1958 CA ALA A 269 0.663 4.598 -12.089 1.00 96.37 C -ATOM 1959 C ALA A 269 -0.797 4.967 -12.358 1.00 96.37 C -ATOM 1960 CB ALA A 269 1.014 4.753 -10.609 1.00 96.37 C -ATOM 1961 O ALA A 269 -1.128 6.146 -12.436 1.00 96.37 O -ATOM 1962 N SER A 270 -1.677 3.977 -12.481 1.00 94.66 N -ATOM 1963 CA SER A 270 -3.099 4.196 -12.754 1.00 94.66 C -ATOM 1964 C SER A 270 -3.998 3.474 -11.754 1.00 94.66 C -ATOM 1965 CB SER A 270 -3.456 3.813 -14.194 1.00 94.66 C -ATOM 1966 O SER A 270 -3.717 2.347 -11.337 1.00 94.66 O -ATOM 1967 OG SER A 270 -2.687 4.571 -15.112 1.00 94.66 O -ATOM 1968 N ASN A 271 -5.093 4.135 -11.385 1.00 91.37 N -ATOM 1969 CA ASN A 271 -6.188 3.597 -10.583 1.00 91.37 C -ATOM 1970 C ASN A 271 -7.515 4.017 -11.223 1.00 91.37 C -ATOM 1971 CB ASN A 271 -6.072 4.120 -9.143 1.00 91.37 C -ATOM 1972 O ASN A 271 -7.794 5.215 -11.329 1.00 91.37 O -ATOM 1973 CG ASN A 271 -7.142 3.560 -8.221 1.00 91.37 C -ATOM 1974 ND2 ASN A 271 -7.288 4.110 -7.040 1.00 91.37 N -ATOM 1975 OD1 ASN A 271 -7.868 2.639 -8.555 1.00 91.37 O -ATOM 1976 N ASN A 272 -8.324 3.045 -11.651 1.00 84.72 N -ATOM 1977 CA ASN A 272 -9.562 3.281 -12.396 1.00 84.72 C -ATOM 1978 C ASN A 272 -9.332 4.228 -13.596 1.00 84.72 C -ATOM 1979 CB ASN A 272 -10.665 3.726 -11.410 1.00 84.72 C -ATOM 1980 O ASN A 272 -8.585 3.889 -14.512 1.00 84.72 O -ATOM 1981 CG ASN A 272 -10.927 2.715 -10.308 1.00 84.72 C -ATOM 1982 ND2 ASN A 272 -11.236 3.175 -9.119 1.00 84.72 N -ATOM 1983 OD1 ASN A 272 -10.887 1.511 -10.496 1.00 84.72 O -ATOM 1984 N ASN A 273 -9.935 5.421 -13.574 1.00 84.69 N -ATOM 1985 CA ASN A 273 -9.850 6.416 -14.647 1.00 84.69 C -ATOM 1986 C ASN A 273 -8.756 7.475 -14.428 1.00 84.69 C -ATOM 1987 CB ASN A 273 -11.233 7.066 -14.837 1.00 84.69 C -ATOM 1988 O ASN A 273 -8.644 8.395 -15.235 1.00 84.69 O -ATOM 1989 CG ASN A 273 -12.278 6.126 -15.407 1.00 84.69 C -ATOM 1990 ND2 ASN A 273 -13.495 6.596 -15.548 1.00 84.69 N -ATOM 1991 OD1 ASN A 273 -12.042 4.977 -15.734 1.00 84.69 O -ATOM 1992 N CYS A 274 -7.968 7.376 -13.353 1.00 90.30 N -ATOM 1993 CA CYS A 274 -6.922 8.344 -13.047 1.00 90.30 C -ATOM 1994 C CYS A 274 -5.520 7.771 -13.219 1.00 90.30 C -ATOM 1995 CB CYS A 274 -7.125 8.923 -11.644 1.00 90.30 C -ATOM 1996 O CYS A 274 -5.199 6.705 -12.692 1.00 90.30 O -ATOM 1997 SG CYS A 274 -8.401 10.202 -11.537 1.00 90.30 S -ATOM 1998 N THR A 275 -4.664 8.541 -13.891 1.00 92.72 N -ATOM 1999 CA THR A 275 -3.256 8.216 -14.139 1.00 92.72 C -ATOM 2000 C THR A 275 -2.365 9.300 -13.548 1.00 92.72 C -ATOM 2001 CB THR A 275 -2.994 8.042 -15.643 1.00 92.72 C -ATOM 2002 O THR A 275 -2.592 10.489 -13.766 1.00 92.72 O -ATOM 2003 CG2 THR A 275 -1.554 7.656 -15.967 1.00 92.72 C -ATOM 2004 OG1 THR A 275 -3.809 7.011 -16.149 1.00 92.72 O -ATOM 2005 N SER A 276 -1.337 8.900 -12.804 1.00 93.75 N -ATOM 2006 CA SER A 276 -0.338 9.811 -12.255 1.00 93.75 C -ATOM 2007 C SER A 276 0.416 10.535 -13.376 1.00 93.75 C -ATOM 2008 CB SER A 276 0.653 9.046 -11.362 1.00 93.75 C -ATOM 2009 O SER A 276 0.534 10.008 -14.486 1.00 93.75 O -ATOM 2010 OG SER A 276 1.611 8.311 -12.113 1.00 93.75 O -ATOM 2011 N PRO A 277 1.034 11.693 -13.097 1.00 93.06 N -ATOM 2012 CA PRO A 277 2.098 12.197 -13.956 1.00 93.06 C -ATOM 2013 C PRO A 277 3.204 11.142 -14.137 1.00 93.06 C -ATOM 2014 CB PRO A 277 2.608 13.473 -13.277 1.00 93.06 C -ATOM 2015 O PRO A 277 3.344 10.220 -13.321 1.00 93.06 O -ATOM 2016 CG PRO A 277 1.446 13.894 -12.374 1.00 93.06 C -ATOM 2017 CD PRO A 277 0.839 12.560 -11.947 1.00 93.06 C -ATOM 2018 N ALA A 278 3.984 11.269 -15.209 1.00 94.53 N -ATOM 2019 CA ALA A 278 5.131 10.400 -15.443 1.00 94.53 C -ATOM 2020 C ALA A 278 6.232 10.646 -14.400 1.00 94.53 C -ATOM 2021 CB ALA A 278 5.629 10.601 -16.879 1.00 94.53 C -ATOM 2022 O ALA A 278 6.428 11.773 -13.938 1.00 94.53 O -ATOM 2023 N SER A 279 6.960 9.587 -14.041 1.00 95.98 N -ATOM 2024 CA SER A 279 8.167 9.687 -13.220 1.00 95.98 C -ATOM 2025 C SER A 279 9.227 10.570 -13.876 1.00 95.98 C -ATOM 2026 CB SER A 279 8.736 8.294 -12.923 1.00 95.98 C -ATOM 2027 O SER A 279 9.204 10.813 -15.086 1.00 95.98 O -ATOM 2028 OG SER A 279 9.322 7.729 -14.086 1.00 95.98 O -ATOM 2029 N GLN A 280 10.218 10.986 -13.084 1.00 93.93 N -ATOM 2030 CA GLN A 280 11.459 11.498 -13.657 1.00 93.93 C -ATOM 2031 C GLN A 280 12.039 10.458 -14.622 1.00 93.93 C -ATOM 2032 CB GLN A 280 12.468 11.854 -12.559 1.00 93.93 C -ATOM 2033 O GLN A 280 11.970 9.251 -14.359 1.00 93.93 O -ATOM 2034 CG GLN A 280 12.013 13.083 -11.757 1.00 93.93 C -ATOM 2035 CD GLN A 280 13.063 13.565 -10.760 1.00 93.93 C -ATOM 2036 NE2 GLN A 280 12.955 14.783 -10.277 1.00 93.93 N -ATOM 2037 OE1 GLN A 280 13.992 12.873 -10.387 1.00 93.93 O -ATOM 2038 N GLN A 281 12.554 10.936 -15.754 1.00 94.79 N -ATOM 2039 CA GLN A 281 13.155 10.070 -16.758 1.00 94.79 C -ATOM 2040 C GLN A 281 14.476 9.513 -16.226 1.00 94.79 C -ATOM 2041 CB GLN A 281 13.352 10.819 -18.083 1.00 94.79 C -ATOM 2042 O GLN A 281 15.307 10.261 -15.710 1.00 94.79 O -ATOM 2043 CG GLN A 281 12.011 11.141 -18.762 1.00 94.79 C -ATOM 2044 CD GLN A 281 12.166 11.871 -20.094 1.00 94.79 C -ATOM 2045 NE2 GLN A 281 11.086 12.111 -20.803 1.00 94.79 N -ATOM 2046 OE1 GLN A 281 13.240 12.246 -20.531 1.00 94.79 O -ATOM 2047 N VAL A 282 14.658 8.202 -16.361 1.00 95.86 N -ATOM 2048 CA VAL A 282 15.908 7.509 -16.040 1.00 95.86 C -ATOM 2049 C VAL A 282 16.493 6.971 -17.337 1.00 95.86 C -ATOM 2050 CB VAL A 282 15.697 6.395 -14.999 1.00 95.86 C -ATOM 2051 O VAL A 282 15.803 6.294 -18.100 1.00 95.86 O -ATOM 2052 CG1 VAL A 282 17.033 5.755 -14.596 1.00 95.86 C -ATOM 2053 CG2 VAL A 282 15.041 6.938 -13.723 1.00 95.86 C -ATOM 2054 N ASN A 283 17.761 7.278 -17.593 1.00 96.09 N -ATOM 2055 CA ASN A 283 18.428 6.862 -18.819 1.00 96.09 C -ATOM 2056 C ASN A 283 18.933 5.425 -18.682 1.00 96.09 C -ATOM 2057 CB ASN A 283 19.561 7.838 -19.168 1.00 96.09 C -ATOM 2058 O ASN A 283 19.630 5.088 -17.724 1.00 96.09 O -ATOM 2059 CG ASN A 283 19.070 9.237 -19.499 1.00 96.09 C -ATOM 2060 ND2 ASN A 283 19.975 10.151 -19.751 1.00 96.09 N -ATOM 2061 OD1 ASN A 283 17.895 9.547 -19.506 1.00 96.09 O -ATOM 2062 N PHE A 284 18.623 4.597 -19.674 1.00 95.39 N -ATOM 2063 CA PHE A 284 19.153 3.251 -19.814 1.00 95.39 C -ATOM 2064 C PHE A 284 20.067 3.173 -21.031 1.00 95.39 C -ATOM 2065 CB PHE A 284 18.007 2.248 -19.918 1.00 95.39 C -ATOM 2066 O PHE A 284 19.651 3.456 -22.155 1.00 95.39 O -ATOM 2067 CG PHE A 284 18.486 0.815 -19.960 1.00 95.39 C -ATOM 2068 CD1 PHE A 284 18.529 0.128 -21.186 1.00 95.39 C -ATOM 2069 CD2 PHE A 284 18.936 0.183 -18.784 1.00 95.39 C -ATOM 2070 CE1 PHE A 284 19.021 -1.186 -21.236 1.00 95.39 C -ATOM 2071 CE2 PHE A 284 19.422 -1.135 -18.834 1.00 95.39 C -ATOM 2072 CZ PHE A 284 19.467 -1.817 -20.063 1.00 95.39 C -ATOM 2073 N HIS A 285 21.313 2.769 -20.806 1.00 93.79 N -ATOM 2074 CA HIS A 285 22.284 2.553 -21.869 1.00 93.79 C -ATOM 2075 C HIS A 285 22.239 1.091 -22.297 1.00 93.79 C -ATOM 2076 CB HIS A 285 23.677 2.975 -21.392 1.00 93.79 C -ATOM 2077 O HIS A 285 22.503 0.193 -21.495 1.00 93.79 O -ATOM 2078 CG HIS A 285 23.782 4.460 -21.156 1.00 93.79 C -ATOM 2079 CD2 HIS A 285 23.401 5.148 -20.034 1.00 93.79 C -ATOM 2080 ND1 HIS A 285 24.244 5.385 -22.061 1.00 93.79 N -ATOM 2081 CE1 HIS A 285 24.141 6.601 -21.502 1.00 93.79 C -ATOM 2082 NE2 HIS A 285 23.634 6.509 -20.264 1.00 93.79 N -ATOM 2083 N THR A 286 21.907 0.856 -23.562 1.00 92.25 N -ATOM 2084 CA THR A 286 21.958 -0.491 -24.133 1.00 92.25 C -ATOM 2085 C THR A 286 23.397 -0.923 -24.389 1.00 92.25 C -ATOM 2086 CB THR A 286 21.132 -0.606 -25.416 1.00 92.25 C -ATOM 2087 O THR A 286 24.335 -0.121 -24.390 1.00 92.25 O -ATOM 2088 CG2 THR A 286 19.664 -0.294 -25.147 1.00 92.25 C -ATOM 2089 OG1 THR A 286 21.639 0.280 -26.374 1.00 92.25 O -ATOM 2090 N VAL A 287 23.581 -2.225 -24.600 1.00 89.62 N -ATOM 2091 CA VAL A 287 24.882 -2.776 -24.981 1.00 89.62 C -ATOM 2092 C VAL A 287 25.316 -2.237 -26.352 1.00 89.62 C -ATOM 2093 CB VAL A 287 24.877 -4.314 -24.969 1.00 89.62 C -ATOM 2094 O VAL A 287 24.457 -1.993 -27.203 1.00 89.62 O -ATOM 2095 CG1 VAL A 287 24.624 -4.831 -23.547 1.00 89.62 C -ATOM 2096 CG2 VAL A 287 23.836 -4.930 -25.915 1.00 89.62 C -ATOM 2097 N PRO A 288 26.626 -2.060 -26.606 1.00 89.96 N -ATOM 2098 CA PRO A 288 27.122 -1.675 -27.924 1.00 89.96 C -ATOM 2099 C PRO A 288 26.655 -2.637 -29.021 1.00 89.96 C -ATOM 2100 CB PRO A 288 28.649 -1.668 -27.811 1.00 89.96 C -ATOM 2101 O PRO A 288 26.510 -3.838 -28.788 1.00 89.96 O -ATOM 2102 CG PRO A 288 28.893 -1.437 -26.321 1.00 89.96 C -ATOM 2103 CD PRO A 288 27.728 -2.171 -25.663 1.00 89.96 C -ATOM 2104 N CYS A 289 26.451 -2.117 -30.231 1.00 90.36 N -ATOM 2105 CA CYS A 289 26.151 -2.962 -31.381 1.00 90.36 C -ATOM 2106 C CYS A 289 27.323 -3.869 -31.750 1.00 90.36 C -ATOM 2107 CB CYS A 289 25.725 -2.109 -32.577 1.00 90.36 C -ATOM 2108 O CYS A 289 28.488 -3.531 -31.531 1.00 90.36 O -ATOM 2109 SG CYS A 289 24.120 -1.312 -32.382 1.00 90.36 S -ATOM 2110 N ALA A 290 26.997 -5.009 -32.362 1.00 88.26 N -ATOM 2111 CA ALA A 290 27.998 -5.844 -33.004 1.00 88.26 C -ATOM 2112 C ALA A 290 28.744 -5.015 -34.070 1.00 88.26 C -ATOM 2113 CB ALA A 290 27.324 -7.078 -33.611 1.00 88.26 C -ATOM 2114 O ALA A 290 28.086 -4.302 -34.837 1.00 88.26 O -ATOM 2115 N PRO A 291 30.085 -5.086 -34.128 1.00 89.12 N -ATOM 2116 CA PRO A 291 30.854 -4.372 -35.136 1.00 89.12 C -ATOM 2117 C PRO A 291 30.380 -4.720 -36.557 1.00 89.12 C -ATOM 2118 CB PRO A 291 32.303 -4.790 -34.908 1.00 89.12 C -ATOM 2119 O PRO A 291 30.238 -5.909 -36.866 1.00 89.12 O -ATOM 2120 CG PRO A 291 32.356 -5.206 -33.444 1.00 89.12 C -ATOM 2121 CD PRO A 291 30.968 -5.790 -33.209 1.00 89.12 C -ATOM 2122 N PRO A 292 30.101 -3.728 -37.421 1.00 89.18 N -ATOM 2123 CA PRO A 292 29.670 -3.997 -38.784 1.00 89.18 C -ATOM 2124 C PRO A 292 30.833 -4.547 -39.622 1.00 89.18 C -ATOM 2125 CB PRO A 292 29.143 -2.658 -39.307 1.00 89.18 C -ATOM 2126 O PRO A 292 31.994 -4.298 -39.335 1.00 89.18 O -ATOM 2127 CG PRO A 292 29.995 -1.633 -38.557 1.00 89.18 C -ATOM 2128 CD PRO A 292 30.232 -2.293 -37.198 1.00 89.18 C -ATOM 2129 N ASN A 293 30.522 -5.277 -40.696 1.00 89.26 N -ATOM 2130 CA ASN A 293 31.476 -5.608 -41.767 1.00 89.26 C -ATOM 2131 C ASN A 293 32.832 -6.184 -41.314 1.00 89.26 C -ATOM 2132 CB ASN A 293 31.640 -4.382 -42.680 1.00 89.26 C -ATOM 2133 O ASN A 293 33.862 -5.859 -41.908 1.00 89.26 O -ATOM 2134 CG ASN A 293 30.336 -3.937 -43.297 1.00 89.26 C -ATOM 2135 ND2 ASN A 293 30.134 -2.649 -43.428 1.00 89.26 N -ATOM 2136 OD1 ASN A 293 29.482 -4.729 -43.660 1.00 89.26 O -ATOM 2137 N LEU A 294 32.835 -7.065 -40.306 1.00 90.46 N -ATOM 2138 CA LEU A 294 34.054 -7.741 -39.869 1.00 90.46 C -ATOM 2139 C LEU A 294 34.741 -8.419 -41.064 1.00 90.46 C -ATOM 2140 CB LEU A 294 33.732 -8.757 -38.760 1.00 90.46 C -ATOM 2141 O LEU A 294 34.205 -9.360 -41.654 1.00 90.46 O -ATOM 2142 CG LEU A 294 34.981 -9.494 -38.232 1.00 90.46 C -ATOM 2143 CD1 LEU A 294 35.930 -8.555 -37.484 1.00 90.46 C -ATOM 2144 CD2 LEU A 294 34.566 -10.616 -37.281 1.00 90.46 C -ATOM 2145 N SER A 295 35.945 -7.964 -41.393 1.00 90.78 N -ATOM 2146 CA SER A 295 36.771 -8.545 -42.444 1.00 90.78 C -ATOM 2147 C SER A 295 38.152 -8.906 -41.908 1.00 90.78 C -ATOM 2148 CB SER A 295 36.814 -7.644 -43.680 1.00 90.78 C -ATOM 2149 O SER A 295 38.716 -8.224 -41.048 1.00 90.78 O -ATOM 2150 OG SER A 295 37.696 -6.565 -43.511 1.00 90.78 O -ATOM 2151 N VAL A 296 38.682 -10.028 -42.398 1.00 91.50 N -ATOM 2152 CA VAL A 296 39.953 -10.599 -41.949 1.00 91.50 C -ATOM 2153 C VAL A 296 40.877 -10.739 -43.151 1.00 91.50 C -ATOM 2154 CB VAL A 296 39.746 -11.951 -41.233 1.00 91.50 C -ATOM 2155 O VAL A 296 40.600 -11.512 -44.066 1.00 91.50 O -ATOM 2156 CG1 VAL A 296 41.072 -12.463 -40.654 1.00 91.50 C -ATOM 2157 CG2 VAL A 296 38.738 -11.843 -40.079 1.00 91.50 C -ATOM 2158 N ALA A 297 41.988 -10.007 -43.136 1.00 91.28 N -ATOM 2159 CA ALA A 297 43.060 -10.121 -44.116 1.00 91.28 C -ATOM 2160 C ALA A 297 44.221 -10.916 -43.506 1.00 91.28 C -ATOM 2161 CB ALA A 297 43.467 -8.716 -44.571 1.00 91.28 C -ATOM 2162 O ALA A 297 44.866 -10.468 -42.558 1.00 91.28 O -ATOM 2163 N VAL A 298 44.478 -12.117 -44.026 1.00 91.86 N -ATOM 2164 CA VAL A 298 45.542 -13.000 -43.527 1.00 91.86 C -ATOM 2165 C VAL A 298 46.807 -12.809 -44.358 1.00 91.86 C -ATOM 2166 CB VAL A 298 45.102 -14.476 -43.513 1.00 91.86 C -ATOM 2167 O VAL A 298 46.802 -13.055 -45.562 1.00 91.86 O -ATOM 2168 CG1 VAL A 298 46.197 -15.371 -42.915 1.00 91.86 C -ATOM 2169 CG2 VAL A 298 43.828 -14.667 -42.677 1.00 91.86 C -ATOM 2170 N GLN A 299 47.905 -12.436 -43.705 1.00 90.20 N -ATOM 2171 CA GLN A 299 49.223 -12.330 -44.321 1.00 90.20 C -ATOM 2172 C GLN A 299 50.029 -13.598 -44.019 1.00 90.20 C -ATOM 2173 CB GLN A 299 49.911 -11.041 -43.844 1.00 90.20 C -ATOM 2174 O GLN A 299 50.573 -13.777 -42.925 1.00 90.20 O -ATOM 2175 CG GLN A 299 51.133 -10.681 -44.708 1.00 90.20 C -ATOM 2176 CD GLN A 299 50.768 -10.235 -46.125 1.00 90.20 C -ATOM 2177 NE2 GLN A 299 51.722 -10.122 -47.020 1.00 90.20 N -ATOM 2178 OE1 GLN A 299 49.622 -9.998 -46.466 1.00 90.20 O -ATOM 2179 N CYS A 300 50.090 -14.503 -45.001 1.00 89.51 N -ATOM 2180 CA CYS A 300 50.715 -15.819 -44.837 1.00 89.51 C -ATOM 2181 C CYS A 300 52.227 -15.730 -44.573 1.00 89.51 C -ATOM 2182 CB CYS A 300 50.417 -16.680 -46.073 1.00 89.51 C -ATOM 2183 O CYS A 300 52.747 -16.503 -43.768 1.00 89.51 O -ATOM 2184 SG CYS A 300 48.642 -17.068 -46.156 1.00 89.51 S -ATOM 2185 N ASP A 301 52.913 -14.761 -45.186 1.00 90.56 N -ATOM 2186 CA ASP A 301 54.372 -14.615 -45.084 1.00 90.56 C -ATOM 2187 C ASP A 301 54.829 -14.258 -43.665 1.00 90.56 C -ATOM 2188 CB ASP A 301 54.849 -13.527 -46.057 1.00 90.56 C -ATOM 2189 O ASP A 301 55.810 -14.797 -43.155 1.00 90.56 O -ATOM 2190 CG ASP A 301 54.476 -13.819 -47.510 1.00 90.56 C -ATOM 2191 OD1 ASP A 301 54.482 -15.011 -47.887 1.00 90.56 O -ATOM 2192 OD2 ASP A 301 54.130 -12.837 -48.200 1.00 90.56 O -ATOM 2193 N THR A 302 54.088 -13.370 -43.000 1.00 91.35 N -ATOM 2194 CA THR A 302 54.384 -12.898 -41.640 1.00 91.35 C -ATOM 2195 C THR A 302 53.663 -13.704 -40.564 1.00 91.35 C -ATOM 2196 CB THR A 302 54.033 -11.412 -41.497 1.00 91.35 C -ATOM 2197 O THR A 302 53.911 -13.487 -39.380 1.00 91.35 O -ATOM 2198 CG2 THR A 302 54.925 -10.534 -42.375 1.00 91.35 C -ATOM 2199 OG1 THR A 302 52.711 -11.206 -41.928 1.00 91.35 O -ATOM 2200 N ARG A 303 52.778 -14.635 -40.952 1.00 88.38 N -ATOM 2201 CA ARG A 303 51.877 -15.370 -40.046 1.00 88.38 C -ATOM 2202 C ARG A 303 51.030 -14.436 -39.170 1.00 88.38 C -ATOM 2203 CB ARG A 303 52.656 -16.400 -39.208 1.00 88.38 C -ATOM 2204 O ARG A 303 50.785 -14.728 -38.002 1.00 88.38 O -ATOM 2205 CG ARG A 303 53.488 -17.378 -40.042 1.00 88.38 C -ATOM 2206 CD ARG A 303 54.209 -18.331 -39.087 1.00 88.38 C -ATOM 2207 NE ARG A 303 55.015 -19.318 -39.822 1.00 88.38 N -ATOM 2208 NH1 ARG A 303 55.767 -20.482 -37.995 1.00 88.38 N -ATOM 2209 NH2 ARG A 303 56.378 -21.124 -40.047 1.00 88.38 N -ATOM 2210 CZ ARG A 303 55.715 -20.300 -39.287 1.00 88.38 C -ATOM 2211 N THR A 304 50.583 -13.311 -39.726 1.00 93.03 N -ATOM 2212 CA THR A 304 49.735 -12.328 -39.032 1.00 93.03 C -ATOM 2213 C THR A 304 48.372 -12.214 -39.707 1.00 93.03 C -ATOM 2214 CB THR A 304 50.402 -10.946 -38.938 1.00 93.03 C -ATOM 2215 O THR A 304 48.255 -12.432 -40.909 1.00 93.03 O -ATOM 2216 CG2 THR A 304 51.685 -10.973 -38.109 1.00 93.03 C -ATOM 2217 OG1 THR A 304 50.744 -10.450 -40.212 1.00 93.03 O -ATOM 2218 N ALA A 305 47.343 -11.826 -38.956 1.00 91.49 N -ATOM 2219 CA ALA A 305 46.032 -11.480 -39.501 1.00 91.49 C -ATOM 2220 C ALA A 305 45.652 -10.059 -39.072 1.00 91.49 C -ATOM 2221 CB ALA A 305 45.000 -12.523 -39.057 1.00 91.49 C -ATOM 2222 O ALA A 305 45.805 -9.701 -37.905 1.00 91.49 O -ATOM 2223 N THR A 306 45.158 -9.261 -40.013 1.00 90.74 N -ATOM 2224 CA THR A 306 44.626 -7.920 -39.767 1.00 90.74 C -ATOM 2225 C THR A 306 43.107 -7.995 -39.805 1.00 90.74 C -ATOM 2226 CB THR A 306 45.159 -6.913 -40.796 1.00 90.74 C -ATOM 2227 O THR A 306 42.529 -8.436 -40.797 1.00 90.74 O -ATOM 2228 CG2 THR A 306 44.758 -5.477 -40.461 1.00 90.74 C -ATOM 2229 OG1 THR A 306 46.569 -6.944 -40.814 1.00 90.74 O -ATOM 2230 N LEU A 307 42.465 -7.589 -38.712 1.00 92.04 N -ATOM 2231 CA LEU A 307 41.013 -7.507 -38.601 1.00 92.04 C -ATOM 2232 C LEU A 307 40.585 -6.051 -38.819 1.00 92.04 C -ATOM 2233 CB LEU A 307 40.541 -8.040 -37.234 1.00 92.04 C -ATOM 2234 O LEU A 307 41.249 -5.142 -38.323 1.00 92.04 O -ATOM 2235 CG LEU A 307 40.768 -9.546 -36.986 1.00 92.04 C -ATOM 2236 CD1 LEU A 307 42.170 -9.869 -36.454 1.00 92.04 C -ATOM 2237 CD2 LEU A 307 39.777 -10.054 -35.938 1.00 92.04 C -ATOM 2238 N SER A 308 39.486 -5.833 -39.537 1.00 89.41 N -ATOM 2239 CA SER A 308 38.831 -4.523 -39.648 1.00 89.41 C -ATOM 2240 C SER A 308 37.321 -4.667 -39.499 1.00 89.41 C -ATOM 2241 CB SER A 308 39.210 -3.810 -40.949 1.00 89.41 C -ATOM 2242 O SER A 308 36.767 -5.705 -39.866 1.00 89.41 O -ATOM 2243 OG SER A 308 38.791 -4.528 -42.086 1.00 89.41 O -ATOM 2244 N TRP A 309 36.691 -3.659 -38.903 1.00 89.27 N -ATOM 2245 CA TRP A 309 35.261 -3.558 -38.618 1.00 89.27 C -ATOM 2246 C TRP A 309 34.869 -2.083 -38.479 1.00 89.27 C -ATOM 2247 CB TRP A 309 34.939 -4.334 -37.335 1.00 89.27 C -ATOM 2248 O TRP A 309 35.792 -1.258 -38.271 1.00 89.27 O -ATOM 2249 CG TRP A 309 35.600 -3.824 -36.086 1.00 89.27 C -ATOM 2250 CD1 TRP A 309 35.164 -2.783 -35.343 1.00 89.27 C -ATOM 2251 CD2 TRP A 309 36.871 -4.219 -35.490 1.00 89.27 C -ATOM 2252 CE2 TRP A 309 37.101 -3.411 -34.335 1.00 89.27 C -ATOM 2253 CE3 TRP A 309 37.880 -5.143 -35.838 1.00 89.27 C -ATOM 2254 NE1 TRP A 309 36.010 -2.573 -34.274 1.00 89.27 N -ATOM 2255 CH2 TRP A 309 39.244 -4.452 -33.928 1.00 89.27 C -ATOM 2256 CZ2 TRP A 309 38.258 -3.526 -33.553 1.00 89.27 C -ATOM 2257 CZ3 TRP A 309 39.055 -5.251 -35.069 1.00 89.27 C -ATOM 2258 OXT TRP A 309 33.657 -1.803 -38.567 1.00 89.27 O -TER 2259 TRP A 309 -ENDMDL -END \ No newline at end of file +ATOM 1 N SER A 1 2.974 -27.458 18.524 1.00 72.44 N +ATOM 2 CA SER A 1 3.371 -28.054 17.239 1.00 72.44 C +ATOM 3 C SER A 1 3.694 -29.508 17.470 1.00 72.44 C +ATOM 4 O SER A 1 4.317 -29.811 18.481 1.00 72.44 O +ATOM 5 CB SER A 1 4.574 -27.320 16.655 1.00 72.44 C +ATOM 6 OG SER A 1 4.284 -25.937 16.721 1.00 72.44 O +ATOM 7 N TYR A 2 3.239 -30.381 16.584 1.00 79.50 N +ATOM 8 CA TYR A 2 3.485 -31.816 16.617 1.00 79.50 C +ATOM 9 C TYR A 2 4.248 -32.201 15.353 1.00 79.50 C +ATOM 10 O TYR A 2 4.013 -31.631 14.288 1.00 79.50 O +ATOM 11 CB TYR A 2 2.158 -32.579 16.727 1.00 79.50 C +ATOM 12 CG TYR A 2 1.355 -32.241 17.969 1.00 79.50 C +ATOM 13 CD1 TYR A 2 1.585 -32.949 19.163 1.00 79.50 C +ATOM 14 CD2 TYR A 2 0.385 -31.218 17.930 1.00 79.50 C +ATOM 15 CE1 TYR A 2 0.848 -32.641 20.322 1.00 79.50 C +ATOM 16 CE2 TYR A 2 -0.344 -30.897 19.092 1.00 79.50 C +ATOM 17 CZ TYR A 2 -0.118 -31.612 20.287 1.00 79.50 C +ATOM 18 OH TYR A 2 -0.830 -31.302 21.400 1.00 79.50 O +ATOM 19 N SER A 3 5.164 -33.152 15.480 1.00 85.13 N +ATOM 20 CA SER A 3 5.852 -33.756 14.346 1.00 85.13 C +ATOM 21 C SER A 3 5.252 -35.143 14.151 1.00 85.13 C +ATOM 22 O SER A 3 5.326 -35.966 15.063 1.00 85.13 O +ATOM 23 CB SER A 3 7.353 -33.795 14.630 1.00 85.13 C +ATOM 24 OG SER A 3 8.061 -33.779 13.420 1.00 85.13 O +ATOM 25 N VAL A 4 4.569 -35.363 13.027 1.00 88.29 N +ATOM 26 CA VAL A 4 3.861 -36.618 12.742 1.00 88.29 C +ATOM 27 C VAL A 4 4.675 -37.427 11.745 1.00 88.29 C +ATOM 28 O VAL A 4 5.026 -36.937 10.670 1.00 88.29 O +ATOM 29 CB VAL A 4 2.423 -36.373 12.243 1.00 88.29 C +ATOM 30 CG1 VAL A 4 1.681 -37.692 11.977 1.00 88.29 C +ATOM 31 CG2 VAL A 4 1.606 -35.596 13.285 1.00 88.29 C +ATOM 32 N THR A 5 4.956 -38.674 12.104 1.00 91.73 N +ATOM 33 CA THR A 5 5.561 -39.684 11.238 1.00 91.73 C +ATOM 34 C THR A 5 4.639 -40.894 11.168 1.00 91.73 C +ATOM 35 O THR A 5 3.863 -41.156 12.087 1.00 91.73 O +ATOM 36 CB THR A 5 6.956 -40.102 11.727 1.00 91.73 C +ATOM 37 OG1 THR A 5 6.913 -40.519 13.071 1.00 91.73 O +ATOM 38 CG2 THR A 5 7.964 -38.959 11.647 1.00 91.73 C +ATOM 39 N VAL A 6 4.699 -41.622 10.056 1.00 91.60 N +ATOM 40 CA VAL A 6 3.927 -42.849 9.850 1.00 91.60 C +ATOM 41 C VAL A 6 4.900 -44.005 9.669 1.00 91.60 C +ATOM 42 O VAL A 6 5.830 -43.917 8.866 1.00 91.60 O +ATOM 43 CB VAL A 6 2.959 -42.707 8.659 1.00 91.60 C +ATOM 44 CG1 VAL A 6 2.123 -43.978 8.457 1.00 91.60 C +ATOM 45 CG2 VAL A 6 1.985 -41.538 8.871 1.00 91.60 C +ATOM 46 N THR A 7 4.679 -45.088 10.407 1.00 91.25 N +ATOM 47 CA THR A 7 5.348 -46.379 10.227 1.00 91.25 C +ATOM 48 C THR A 7 4.321 -47.404 9.759 1.00 91.25 C +ATOM 49 O THR A 7 3.162 -47.388 10.175 1.00 91.25 O +ATOM 50 CB THR A 7 6.052 -46.853 11.510 1.00 91.25 C +ATOM 51 OG1 THR A 7 5.196 -46.746 12.621 1.00 91.25 O +ATOM 52 CG2 THR A 7 7.289 -46.013 11.815 1.00 91.25 C +ATOM 53 N SER A 8 4.725 -48.283 8.846 1.00 88.71 N +ATOM 54 CA SER A 8 3.903 -49.420 8.425 1.00 88.71 C +ATOM 55 C SER A 8 4.278 -50.654 9.242 1.00 88.71 C +ATOM 56 O SER A 8 5.459 -50.870 9.519 1.00 88.71 O +ATOM 57 CB SER A 8 4.011 -49.649 6.915 1.00 88.71 C +ATOM 58 OG SER A 8 5.326 -49.971 6.514 1.00 88.71 O +ATOM 59 N LEU A 9 3.276 -51.448 9.626 1.00 91.87 N +ATOM 60 CA LEU A 9 3.443 -52.634 10.466 1.00 91.87 C +ATOM 61 C LEU A 9 2.850 -53.859 9.761 1.00 91.87 C +ATOM 62 O LEU A 9 1.703 -53.832 9.308 1.00 91.87 O +ATOM 63 CB LEU A 9 2.825 -52.339 11.849 1.00 91.87 C +ATOM 64 CG LEU A 9 3.264 -53.323 12.957 1.00 91.87 C +ATOM 65 CD1 LEU A 9 3.605 -52.568 14.241 1.00 91.87 C +ATOM 66 CD2 LEU A 9 2.147 -54.311 13.297 1.00 91.87 C +ATOM 67 N ARG A 10 3.636 -54.935 9.644 1.00 89.14 N +ATOM 68 CA ARG A 10 3.183 -56.239 9.131 1.00 89.14 C +ATOM 69 C ARG A 10 3.754 -57.346 10.015 1.00 89.14 C +ATOM 70 O ARG A 10 4.943 -57.644 9.932 1.00 89.14 O +ATOM 71 CB ARG A 10 3.582 -56.402 7.648 1.00 89.14 C +ATOM 72 CG ARG A 10 3.142 -57.767 7.084 1.00 89.14 C +ATOM 73 CD ARG A 10 3.586 -57.995 5.632 1.00 89.14 C +ATOM 74 NE ARG A 10 2.664 -57.394 4.648 1.00 89.14 N +ATOM 75 CZ ARG A 10 2.742 -57.527 3.335 1.00 89.14 C +ATOM 76 NH1 ARG A 10 3.728 -58.166 2.766 1.00 89.14 N +ATOM 77 NH2 ARG A 10 1.826 -57.018 2.560 1.00 89.14 N +ATOM 78 N GLY A 11 2.894 -57.981 10.811 1.00 88.64 N +ATOM 79 CA GLY A 11 3.334 -58.940 11.829 1.00 88.64 C +ATOM 80 C GLY A 11 4.232 -58.244 12.852 1.00 88.64 C +ATOM 81 O GLY A 11 3.866 -57.181 13.341 1.00 88.64 O +ATOM 82 N ASP A 12 5.420 -58.800 13.085 1.00 87.38 N +ATOM 83 CA ASP A 12 6.424 -58.253 14.011 1.00 87.38 C +ATOM 84 C ASP A 12 7.456 -57.328 13.328 1.00 87.38 C +ATOM 85 O ASP A 12 8.468 -56.967 13.926 1.00 87.38 O +ATOM 86 CB ASP A 12 7.120 -59.412 14.745 1.00 87.38 C +ATOM 87 CG ASP A 12 6.145 -60.338 15.477 1.00 87.38 C +ATOM 88 OD1 ASP A 12 5.191 -59.824 16.101 1.00 87.38 O +ATOM 89 OD2 ASP A 12 6.345 -61.569 15.370 1.00 87.38 O +ATOM 90 N CYS A 13 7.258 -56.966 12.054 1.00 86.80 N +ATOM 91 CA CYS A 13 8.167 -56.083 11.321 1.00 86.80 C +ATOM 92 C CYS A 13 7.599 -54.662 11.195 1.00 86.80 C +ATOM 93 O CYS A 13 6.490 -54.473 10.684 1.00 86.80 O +ATOM 94 CB CYS A 13 8.487 -56.682 9.943 1.00 86.80 C +ATOM 95 SG CYS A 13 9.324 -58.287 10.104 1.00 86.80 S +ATOM 96 N GLU A 14 8.405 -53.668 11.577 1.00 90.65 N +ATOM 97 CA GLU A 14 8.132 -52.236 11.406 1.00 90.65 C +ATOM 98 C GLU A 14 9.019 -51.633 10.307 1.00 90.65 C +ATOM 99 O GLU A 14 10.201 -51.966 10.187 1.00 90.65 O +ATOM 100 CB GLU A 14 8.344 -51.473 12.725 1.00 90.65 C +ATOM 101 CG GLU A 14 7.418 -51.963 13.847 1.00 90.65 C +ATOM 102 CD GLU A 14 7.434 -51.062 15.096 1.00 90.65 C +ATOM 103 OE1 GLU A 14 6.549 -51.263 15.957 1.00 90.65 O +ATOM 104 OE2 GLU A 14 8.302 -50.162 15.177 1.00 90.65 O +ATOM 105 N SER A 15 8.463 -50.733 9.492 1.00 89.93 N +ATOM 106 CA SER A 15 9.258 -49.942 8.546 1.00 89.93 C +ATOM 107 C SER A 15 10.002 -48.799 9.239 1.00 89.93 C +ATOM 108 O SER A 15 9.635 -48.366 10.328 1.00 89.93 O +ATOM 109 CB SER A 15 8.391 -49.408 7.399 1.00 89.93 C +ATOM 110 OG SER A 15 7.508 -48.371 7.805 1.00 89.93 O +ATOM 111 N GLN A 16 10.987 -48.216 8.550 1.00 89.52 N +ATOM 112 CA GLN A 16 11.506 -46.906 8.949 1.00 89.52 C +ATOM 113 C GLN A 16 10.369 -45.859 8.951 1.00 89.52 C +ATOM 114 O GLN A 16 9.468 -45.953 8.104 1.00 89.52 O +ATOM 115 CB GLN A 16 12.654 -46.477 8.021 1.00 89.52 C +ATOM 116 CG GLN A 16 13.911 -47.346 8.205 1.00 89.52 C +ATOM 117 CD GLN A 16 14.528 -47.221 9.598 1.00 89.52 C +ATOM 118 OE1 GLN A 16 14.451 -46.199 10.258 1.00 89.52 O +ATOM 119 NE2 GLN A 16 15.164 -48.253 10.105 1.00 89.52 N +ATOM 120 N PRO A 17 10.380 -44.882 9.877 1.00 90.04 N +ATOM 121 CA PRO A 17 9.409 -43.793 9.886 1.00 90.04 C +ATOM 122 C PRO A 17 9.461 -42.964 8.598 1.00 90.04 C +ATOM 123 O PRO A 17 10.532 -42.738 8.034 1.00 90.04 O +ATOM 124 CB PRO A 17 9.740 -42.942 11.118 1.00 90.04 C +ATOM 125 CG PRO A 17 10.508 -43.898 12.029 1.00 90.04 C +ATOM 126 CD PRO A 17 11.246 -44.799 11.045 1.00 90.04 C +ATOM 127 N SER A 18 8.304 -42.474 8.149 1.00 91.27 N +ATOM 128 CA SER A 18 8.226 -41.499 7.057 1.00 91.27 C +ATOM 129 C SER A 18 8.984 -40.205 7.383 1.00 91.27 C +ATOM 130 O SER A 18 9.278 -39.907 8.543 1.00 91.27 O +ATOM 131 CB SER A 18 6.756 -41.184 6.739 1.00 91.27 C +ATOM 132 OG SER A 18 6.153 -40.399 7.757 1.00 91.27 O +ATOM 133 N THR A 19 9.213 -39.362 6.371 1.00 90.71 N +ATOM 134 CA THR A 19 9.603 -37.964 6.607 1.00 90.71 C +ATOM 135 C THR A 19 8.577 -37.289 7.514 1.00 90.71 C +ATOM 136 O THR A 19 7.370 -37.428 7.298 1.00 90.71 O +ATOM 137 CB THR A 19 9.710 -37.167 5.302 1.00 90.71 C +ATOM 138 OG1 THR A 19 8.540 -37.335 4.534 1.00 90.71 O +ATOM 139 CG2 THR A 19 10.894 -37.632 4.456 1.00 90.71 C +ATOM 140 N ALA A 20 9.059 -36.578 8.529 1.00 88.71 N +ATOM 141 CA ALA A 20 8.205 -35.918 9.498 1.00 88.71 C +ATOM 142 C ALA A 20 7.451 -34.739 8.873 1.00 88.71 C +ATOM 143 O ALA A 20 8.051 -33.874 8.234 1.00 88.71 O +ATOM 144 CB ALA A 20 9.072 -35.482 10.675 1.00 88.71 C +ATOM 145 N VAL A 21 6.138 -34.686 9.097 1.00 86.44 N +ATOM 146 CA VAL A 21 5.304 -33.537 8.732 1.00 86.44 C +ATOM 147 C VAL A 21 4.996 -32.751 10.001 1.00 86.44 C +ATOM 148 O VAL A 21 4.418 -33.278 10.954 1.00 86.44 O +ATOM 149 CB VAL A 21 4.031 -33.965 7.980 1.00 86.44 C +ATOM 150 CG1 VAL A 21 3.230 -32.735 7.529 1.00 86.44 C +ATOM 151 CG2 VAL A 21 4.373 -34.782 6.726 1.00 86.44 C +ATOM 152 N ASN A 22 5.397 -31.481 10.026 1.00 83.81 N +ATOM 153 CA ASN A 22 5.118 -30.592 11.148 1.00 83.81 C +ATOM 154 C ASN A 22 3.704 -30.024 11.015 1.00 83.81 C +ATOM 155 O ASN A 22 3.406 -29.310 10.061 1.00 83.81 O +ATOM 156 CB ASN A 22 6.184 -29.488 11.218 1.00 83.81 C +ATOM 157 CG ASN A 22 7.548 -30.012 11.635 1.00 83.81 C +ATOM 158 OD1 ASN A 22 7.689 -31.009 12.331 1.00 83.81 O +ATOM 159 ND2 ASN A 22 8.601 -29.332 11.249 1.00 83.81 N +ATOM 160 N VAL A 23 2.852 -30.316 11.993 1.00 81.23 N +ATOM 161 CA VAL A 23 1.476 -29.817 12.068 1.00 81.23 C +ATOM 162 C VAL A 23 1.266 -29.032 13.355 1.00 81.23 C +ATOM 163 O VAL A 23 1.819 -29.340 14.416 1.00 81.23 O +ATOM 164 CB VAL A 23 0.432 -30.939 11.907 1.00 81.23 C +ATOM 165 CG1 VAL A 23 0.428 -31.484 10.476 1.00 81.23 C +ATOM 166 CG2 VAL A 23 0.653 -32.105 12.875 1.00 81.23 C +ATOM 167 N THR A 24 0.437 -28.000 13.285 1.00 81.30 N +ATOM 168 CA THR A 24 0.074 -27.183 14.445 1.00 81.30 C +ATOM 169 C THR A 24 -1.413 -27.370 14.711 1.00 81.30 C +ATOM 170 O THR A 24 -2.208 -27.361 13.776 1.00 81.30 O +ATOM 171 CB THR A 24 0.444 -25.704 14.244 1.00 81.30 C +ATOM 172 OG1 THR A 24 1.655 -25.575 13.532 1.00 81.30 O +ATOM 173 CG2 THR A 24 0.693 -25.010 15.584 1.00 81.30 C +ATOM 174 N SER A 25 -1.802 -27.559 15.975 1.00 86.41 N +ATOM 175 CA SER A 25 -3.220 -27.598 16.350 1.00 86.41 C +ATOM 176 C SER A 25 -3.892 -26.255 16.049 1.00 86.41 C +ATOM 177 O SER A 25 -3.207 -25.242 15.887 1.00 86.41 O +ATOM 178 CB SER A 25 -3.369 -27.957 17.833 1.00 86.41 C +ATOM 179 OG SER A 25 -2.679 -27.022 18.644 1.00 86.41 O +ATOM 180 N ALA A 26 -5.226 -26.229 16.013 1.00 89.92 N +ATOM 181 CA ALA A 26 -5.966 -24.976 15.905 1.00 89.92 C +ATOM 182 C ALA A 26 -5.557 -23.986 17.021 1.00 89.92 C +ATOM 183 O ALA A 26 -5.227 -24.429 18.131 1.00 89.92 O +ATOM 184 CB ALA A 26 -7.469 -25.271 15.923 1.00 89.92 C +ATOM 185 N PRO A 27 -5.549 -22.669 16.743 1.00 92.68 N +ATOM 186 CA PRO A 27 -5.329 -21.657 17.770 1.00 92.68 C +ATOM 187 C PRO A 27 -6.379 -21.734 18.882 1.00 92.68 C +ATOM 188 O PRO A 27 -7.496 -22.213 18.670 1.00 92.68 O +ATOM 189 CB PRO A 27 -5.405 -20.308 17.049 1.00 92.68 C +ATOM 190 CG PRO A 27 -5.119 -20.652 15.592 1.00 92.68 C +ATOM 191 CD PRO A 27 -5.743 -22.034 15.446 1.00 92.68 C +ATOM 192 N CYS A 28 -6.044 -21.217 20.064 1.00 94.14 N +ATOM 193 CA CYS A 28 -7.042 -20.999 21.108 1.00 94.14 C +ATOM 194 C CYS A 28 -8.097 -19.974 20.659 1.00 94.14 C +ATOM 195 O CYS A 28 -7.823 -19.105 19.832 1.00 94.14 O +ATOM 196 CB CYS A 28 -6.352 -20.570 22.409 1.00 94.14 C +ATOM 197 SG CYS A 28 -5.364 -21.947 23.068 1.00 94.14 S +ATOM 198 N VAL A 29 -9.298 -20.073 21.231 1.00 94.81 N +ATOM 199 CA VAL A 29 -10.366 -19.089 21.021 1.00 94.81 C +ATOM 200 C VAL A 29 -9.910 -17.732 21.594 1.00 94.81 C +ATOM 201 O VAL A 29 -9.398 -17.718 22.719 1.00 94.81 O +ATOM 202 CB VAL A 29 -11.680 -19.572 21.665 1.00 94.81 C +ATOM 203 CG1 VAL A 29 -12.822 -18.585 21.445 1.00 94.81 C +ATOM 204 CG2 VAL A 29 -12.120 -20.916 21.063 1.00 94.81 C +ATOM 205 N PRO A 30 -10.034 -16.618 20.845 1.00 93.95 N +ATOM 206 CA PRO A 30 -9.761 -15.271 21.350 1.00 93.95 C +ATOM 207 C PRO A 30 -10.577 -14.930 22.606 1.00 93.95 C +ATOM 208 O PRO A 30 -11.625 -15.522 22.858 1.00 93.95 O +ATOM 209 CB PRO A 30 -10.080 -14.317 20.193 1.00 93.95 C +ATOM 210 CG PRO A 30 -9.885 -15.193 18.959 1.00 93.95 C +ATOM 211 CD PRO A 30 -10.369 -16.560 19.430 1.00 93.95 C +ATOM 212 N GLN A 31 -10.060 -14.008 23.419 1.00 93.67 N +ATOM 213 CA GLN A 31 -10.716 -13.525 24.636 1.00 93.67 C +ATOM 214 C GLN A 31 -10.447 -12.030 24.832 1.00 93.67 C +ATOM 215 O GLN A 31 -9.432 -11.510 24.361 1.00 93.67 O +ATOM 216 CB GLN A 31 -10.209 -14.296 25.873 1.00 93.67 C +ATOM 217 CG GLN A 31 -10.590 -15.783 25.870 1.00 93.67 C +ATOM 218 CD GLN A 31 -10.239 -16.490 27.176 1.00 93.67 C +ATOM 219 OE1 GLN A 31 -9.278 -16.191 27.868 1.00 93.67 O +ATOM 220 NE2 GLN A 31 -11.011 -17.479 27.572 1.00 93.67 N +ATOM 221 N GLY A 32 -11.312 -11.363 25.598 1.00 91.63 N +ATOM 222 CA GLY A 32 -11.147 -9.952 25.959 1.00 91.63 C +ATOM 223 C GLY A 32 -11.480 -9.006 24.809 1.00 91.63 C +ATOM 224 O GLY A 32 -10.832 -7.974 24.660 1.00 91.63 O +ATOM 225 N GLU A 33 -12.444 -9.391 23.978 1.00 92.94 N +ATOM 226 CA GLU A 33 -12.883 -8.637 22.818 1.00 92.94 C +ATOM 227 C GLU A 33 -13.597 -7.350 23.242 1.00 92.94 C +ATOM 228 O GLU A 33 -14.568 -7.373 23.999 1.00 92.94 O +ATOM 229 CB GLU A 33 -13.785 -9.487 21.908 1.00 92.94 C +ATOM 230 CG GLU A 33 -13.153 -10.806 21.436 1.00 92.94 C +ATOM 231 CD GLU A 33 -13.390 -12.007 22.373 1.00 92.94 C +ATOM 232 OE1 GLU A 33 -13.340 -13.142 21.859 1.00 92.94 O +ATOM 233 OE2 GLU A 33 -13.579 -11.845 23.603 1.00 92.94 O +ATOM 234 N ALA A 34 -13.126 -6.220 22.727 1.00 93.92 N +ATOM 235 CA ALA A 34 -13.754 -4.921 22.911 1.00 93.92 C +ATOM 236 C ALA A 34 -13.773 -4.168 21.581 1.00 93.92 C +ATOM 237 O ALA A 34 -12.874 -4.325 20.759 1.00 93.92 O +ATOM 238 CB ALA A 34 -13.011 -4.152 24.009 1.00 93.92 C +ATOM 239 N GLY A 35 -14.796 -3.344 21.368 1.00 92.42 N +ATOM 240 CA GLY A 35 -14.922 -2.519 20.171 1.00 92.42 C +ATOM 241 C GLY A 35 -15.106 -1.052 20.526 1.00 92.42 C +ATOM 242 O GLY A 35 -15.853 -0.726 21.448 1.00 92.42 O +ATOM 243 N ASN A 36 -14.444 -0.172 19.782 1.00 91.54 N +ATOM 244 CA ASN A 36 -14.633 1.269 19.861 1.00 91.54 C +ATOM 245 C ASN A 36 -15.070 1.800 18.492 1.00 91.54 C +ATOM 246 O ASN A 36 -14.384 1.579 17.494 1.00 91.54 O +ATOM 247 CB ASN A 36 -13.344 1.923 20.379 1.00 91.54 C +ATOM 248 CG ASN A 36 -13.559 3.376 20.763 1.00 91.54 C +ATOM 249 OD1 ASN A 36 -14.646 3.920 20.691 1.00 91.54 O +ATOM 250 ND2 ASN A 36 -12.534 4.046 21.228 1.00 91.54 N +ATOM 251 N LEU A 37 -16.227 2.459 18.451 1.00 88.49 N +ATOM 252 CA LEU A 37 -16.797 3.016 17.229 1.00 88.49 C +ATOM 253 C LEU A 37 -16.128 4.352 16.906 1.00 88.49 C +ATOM 254 O LEU A 37 -16.256 5.314 17.660 1.00 88.49 O +ATOM 255 CB LEU A 37 -18.321 3.162 17.408 1.00 88.49 C +ATOM 256 CG LEU A 37 -19.056 3.770 16.196 1.00 88.49 C +ATOM 257 CD1 LEU A 37 -19.039 2.854 14.972 1.00 88.49 C +ATOM 258 CD2 LEU A 37 -20.522 4.025 16.553 1.00 88.49 C +ATOM 259 N ASP A 38 -15.488 4.420 15.747 1.00 85.73 N +ATOM 260 CA ASP A 38 -15.111 5.672 15.117 1.00 85.73 C +ATOM 261 C ASP A 38 -16.315 6.236 14.353 1.00 85.73 C +ATOM 262 O ASP A 38 -16.798 5.688 13.357 1.00 85.73 O +ATOM 263 CB ASP A 38 -13.890 5.460 14.225 1.00 85.73 C +ATOM 264 CG ASP A 38 -13.438 6.751 13.542 1.00 85.73 C +ATOM 265 OD1 ASP A 38 -14.082 7.810 13.748 1.00 85.73 O +ATOM 266 OD2 ASP A 38 -12.485 6.634 12.750 1.00 85.73 O +ATOM 267 N CYS A 39 -16.824 7.351 14.867 1.00 79.80 N +ATOM 268 CA CYS A 39 -18.004 8.021 14.348 1.00 79.80 C +ATOM 269 C CYS A 39 -17.779 8.666 12.967 1.00 79.80 C +ATOM 270 O CYS A 39 -18.760 8.902 12.259 1.00 79.80 O +ATOM 271 CB CYS A 39 -18.401 9.078 15.382 1.00 79.80 C +ATOM 272 SG CYS A 39 -17.274 10.498 15.364 1.00 79.80 S +ATOM 273 N ILE A 40 -16.525 8.971 12.600 1.00 73.17 N +ATOM 274 CA ILE A 40 -16.181 9.693 11.368 1.00 73.17 C +ATOM 275 C ILE A 40 -16.249 8.724 10.197 1.00 73.17 C +ATOM 276 O ILE A 40 -16.994 8.929 9.240 1.00 73.17 O +ATOM 277 CB ILE A 40 -14.780 10.351 11.471 1.00 73.17 C +ATOM 278 CG1 ILE A 40 -14.726 11.325 12.670 1.00 73.17 C +ATOM 279 CG2 ILE A 40 -14.432 11.074 10.154 1.00 73.17 C +ATOM 280 CD1 ILE A 40 -13.371 12.013 12.875 1.00 73.17 C +ATOM 281 N THR A 41 -15.506 7.631 10.314 1.00 80.58 N +ATOM 282 CA THR A 41 -15.362 6.625 9.260 1.00 80.58 C +ATOM 283 C THR A 41 -16.467 5.561 9.281 1.00 80.58 C +ATOM 284 O THR A 41 -16.522 4.708 8.396 1.00 80.58 O +ATOM 285 CB THR A 41 -13.968 5.990 9.345 1.00 80.58 C +ATOM 286 OG1 THR A 41 -13.781 5.470 10.641 1.00 80.58 O +ATOM 287 CG2 THR A 41 -12.840 6.989 9.102 1.00 80.58 C +ATOM 288 N ASN A 42 -17.353 5.581 10.290 1.00 85.30 N +ATOM 289 CA ASN A 42 -18.223 4.451 10.651 1.00 85.30 C +ATOM 290 C ASN A 42 -17.460 3.130 10.682 1.00 85.30 C +ATOM 291 O ASN A 42 -17.916 2.109 10.159 1.00 85.30 O +ATOM 292 CB ASN A 42 -19.454 4.331 9.747 1.00 85.30 C +ATOM 293 CG ASN A 42 -20.522 5.340 9.996 1.00 85.30 C +ATOM 294 OD1 ASN A 42 -20.492 6.090 10.950 1.00 85.30 O +ATOM 295 ND2 ASN A 42 -21.564 5.325 9.202 1.00 85.30 N +ATOM 296 N SER A 43 -16.278 3.159 11.273 1.00 89.68 N +ATOM 297 CA SER A 43 -15.471 1.970 11.449 1.00 89.68 C +ATOM 298 C SER A 43 -15.403 1.610 12.924 1.00 89.68 C +ATOM 299 O SER A 43 -15.641 2.443 13.797 1.00 89.68 O +ATOM 300 CB SER A 43 -14.125 2.143 10.755 1.00 89.68 C +ATOM 301 OG SER A 43 -13.276 3.036 11.438 1.00 89.68 O +ATOM 302 N VAL A 44 -15.178 0.338 13.227 1.00 93.01 N +ATOM 303 CA VAL A 44 -15.024 -0.113 14.610 1.00 93.01 C +ATOM 304 C VAL A 44 -13.636 -0.692 14.771 1.00 93.01 C +ATOM 305 O VAL A 44 -13.305 -1.719 14.175 1.00 93.01 O +ATOM 306 CB VAL A 44 -16.131 -1.090 15.034 1.00 93.01 C +ATOM 307 CG1 VAL A 44 -15.853 -1.730 16.401 1.00 93.01 C +ATOM 308 CG2 VAL A 44 -17.474 -0.358 15.160 1.00 93.01 C +ATOM 309 N TRP A 45 -12.864 -0.072 15.656 1.00 93.90 N +ATOM 310 CA TRP A 45 -11.621 -0.631 16.150 1.00 93.90 C +ATOM 311 C TRP A 45 -11.930 -1.722 17.158 1.00 93.90 C +ATOM 312 O TRP A 45 -12.399 -1.446 18.262 1.00 93.90 O +ATOM 313 CB TRP A 45 -10.762 0.472 16.760 1.00 93.90 C +ATOM 314 CG TRP A 45 -10.094 1.312 15.728 1.00 93.90 C +ATOM 315 CD1 TRP A 45 -10.504 2.526 15.297 1.00 93.90 C +ATOM 316 CD2 TRP A 45 -8.932 0.966 14.919 1.00 93.90 C +ATOM 317 NE1 TRP A 45 -9.656 2.972 14.302 1.00 93.90 N +ATOM 318 CE2 TRP A 45 -8.660 2.054 14.038 1.00 93.90 C +ATOM 319 CE3 TRP A 45 -8.089 -0.168 14.838 1.00 93.90 C +ATOM 320 CZ2 TRP A 45 -7.583 2.033 13.141 1.00 93.90 C +ATOM 321 CZ3 TRP A 45 -7.003 -0.198 13.941 1.00 93.90 C +ATOM 322 CH2 TRP A 45 -6.745 0.903 13.101 1.00 93.90 C +ATOM 323 N VAL A 46 -11.663 -2.964 16.771 1.00 95.79 N +ATOM 324 CA VAL A 46 -11.815 -4.133 17.634 1.00 95.79 C +ATOM 325 C VAL A 46 -10.454 -4.510 18.200 1.00 95.79 C +ATOM 326 O VAL A 46 -9.473 -4.548 17.461 1.00 95.79 O +ATOM 327 CB VAL A 46 -12.495 -5.294 16.890 1.00 95.79 C +ATOM 328 CG1 VAL A 46 -12.794 -6.457 17.843 1.00 95.79 C +ATOM 329 CG2 VAL A 46 -13.825 -4.833 16.280 1.00 95.79 C +ATOM 330 N THR A 47 -10.388 -4.780 19.499 1.00 96.42 N +ATOM 331 CA THR A 47 -9.187 -5.214 20.222 1.00 96.42 C +ATOM 332 C THR A 47 -9.457 -6.520 20.962 1.00 96.42 C +ATOM 333 O THR A 47 -10.600 -6.816 21.305 1.00 96.42 O +ATOM 334 CB THR A 47 -8.689 -4.140 21.202 1.00 96.42 C +ATOM 335 OG1 THR A 47 -9.652 -3.851 22.186 1.00 96.42 O +ATOM 336 CG2 THR A 47 -8.373 -2.814 20.511 1.00 96.42 C +ATOM 337 N TRP A 48 -8.419 -7.330 21.170 1.00 95.00 N +ATOM 338 CA TRP A 48 -8.501 -8.618 21.871 1.00 95.00 C +ATOM 339 C TRP A 48 -7.155 -8.993 22.499 1.00 95.00 C +ATOM 340 O TRP A 48 -6.119 -8.381 22.231 1.00 95.00 O +ATOM 341 CB TRP A 48 -8.950 -9.717 20.893 1.00 95.00 C +ATOM 342 CG TRP A 48 -8.112 -9.830 19.658 1.00 95.00 C +ATOM 343 CD1 TRP A 48 -6.998 -10.579 19.499 1.00 95.00 C +ATOM 344 CD2 TRP A 48 -8.303 -9.133 18.397 1.00 95.00 C +ATOM 345 NE1 TRP A 48 -6.480 -10.376 18.236 1.00 95.00 N +ATOM 346 CE2 TRP A 48 -7.244 -9.491 17.518 1.00 95.00 C +ATOM 347 CE3 TRP A 48 -9.270 -8.232 17.916 1.00 95.00 C +ATOM 348 CZ2 TRP A 48 -7.148 -8.985 16.221 1.00 95.00 C +ATOM 349 CZ3 TRP A 48 -9.206 -7.741 16.601 1.00 95.00 C +ATOM 350 CH2 TRP A 48 -8.161 -8.142 15.754 1.00 95.00 C +ATOM 351 N LEU A 49 -7.153 -10.035 23.331 1.00 95.28 N +ATOM 352 CA LEU A 49 -5.940 -10.604 23.914 1.00 95.28 C +ATOM 353 C LEU A 49 -5.314 -11.656 22.992 1.00 95.28 C +ATOM 354 O LEU A 49 -6.004 -12.358 22.253 1.00 95.28 O +ATOM 355 CB LEU A 49 -6.256 -11.186 25.300 1.00 95.28 C +ATOM 356 CG LEU A 49 -6.808 -10.157 26.305 1.00 95.28 C +ATOM 357 CD1 LEU A 49 -7.197 -10.873 27.598 1.00 95.28 C +ATOM 358 CD2 LEU A 49 -5.776 -9.076 26.643 1.00 95.28 C +ATOM 359 N GLN A 50 -3.988 -11.798 23.060 1.00 94.37 N +ATOM 360 CA GLN A 50 -3.258 -12.760 22.237 1.00 94.37 C +ATOM 361 C GLN A 50 -3.699 -14.205 22.526 1.00 94.37 C +ATOM 362 O GLN A 50 -3.444 -14.750 23.600 1.00 94.37 O +ATOM 363 CB GLN A 50 -1.745 -12.574 22.435 1.00 94.37 C +ATOM 364 CG GLN A 50 -0.936 -13.437 21.451 1.00 94.37 C +ATOM 365 CD GLN A 50 0.565 -13.164 21.500 1.00 94.37 C +ATOM 366 OE1 GLN A 50 1.101 -12.547 22.403 1.00 94.37 O +ATOM 367 NE2 GLN A 50 1.314 -13.622 20.521 1.00 94.37 N +ATOM 368 N ALA A 51 -4.299 -14.855 21.530 1.00 94.47 N +ATOM 369 CA ALA A 51 -4.630 -16.269 21.562 1.00 94.47 C +ATOM 370 C ALA A 51 -3.384 -17.131 21.306 1.00 94.47 C +ATOM 371 O ALA A 51 -2.603 -16.908 20.374 1.00 94.47 O +ATOM 372 CB ALA A 51 -5.737 -16.547 20.546 1.00 94.47 C +ATOM 373 N LYS A 52 -3.197 -18.172 22.121 1.00 92.16 N +ATOM 374 CA LYS A 52 -2.063 -19.092 21.985 1.00 92.16 C +ATOM 375 C LYS A 52 -2.141 -19.847 20.652 1.00 92.16 C +ATOM 376 O LYS A 52 -3.132 -20.513 20.360 1.00 92.16 O +ATOM 377 CB LYS A 52 -2.027 -20.023 23.202 1.00 92.16 C +ATOM 378 CG LYS A 52 -0.762 -20.890 23.263 1.00 92.16 C +ATOM 379 CD LYS A 52 -0.798 -21.762 24.525 1.00 92.16 C +ATOM 380 CE LYS A 52 0.470 -22.612 24.642 1.00 92.16 C +ATOM 381 NZ LYS A 52 0.458 -23.421 25.888 1.00 92.16 N +ATOM 382 N GLY A 53 -1.066 -19.770 19.869 1.00 90.79 N +ATOM 383 CA GLY A 53 -0.944 -20.448 18.573 1.00 90.79 C +ATOM 384 C GLY A 53 -1.536 -19.691 17.381 1.00 90.79 C +ATOM 385 O GLY A 53 -1.513 -20.236 16.279 1.00 90.79 O +ATOM 386 N ALA A 54 -2.045 -18.471 17.579 1.00 92.72 N +ATOM 387 CA ALA A 54 -2.517 -17.608 16.501 1.00 92.72 C +ATOM 388 C ALA A 54 -1.346 -16.898 15.798 1.00 92.72 C +ATOM 389 O ALA A 54 -0.437 -16.394 16.458 1.00 92.72 O +ATOM 390 CB ALA A 54 -3.501 -16.598 17.091 1.00 92.72 C +ATOM 391 N LEU A 55 -1.392 -16.846 14.467 1.00 93.25 N +ATOM 392 CA LEU A 55 -0.496 -16.049 13.619 1.00 93.25 C +ATOM 393 C LEU A 55 -1.198 -14.802 13.067 1.00 93.25 C +ATOM 394 O LEU A 55 -0.550 -13.796 12.794 1.00 93.25 O +ATOM 395 CB LEU A 55 0.016 -16.913 12.453 1.00 93.25 C +ATOM 396 CG LEU A 55 0.841 -18.145 12.860 1.00 93.25 C +ATOM 397 CD1 LEU A 55 1.257 -18.907 11.602 1.00 93.25 C +ATOM 398 CD2 LEU A 55 2.107 -17.771 13.632 1.00 93.25 C +ATOM 399 N SER A 56 -2.517 -14.873 12.904 1.00 95.79 N +ATOM 400 CA SER A 56 -3.363 -13.767 12.466 1.00 95.79 C +ATOM 401 C SER A 56 -4.776 -13.918 13.027 1.00 95.79 C +ATOM 402 O SER A 56 -5.131 -14.952 13.600 1.00 95.79 O +ATOM 403 CB SER A 56 -3.384 -13.683 10.934 1.00 95.79 C +ATOM 404 OG SER A 56 -3.869 -14.879 10.352 1.00 95.79 O +ATOM 405 N TYR A 57 -5.576 -12.870 12.880 1.00 96.56 N +ATOM 406 CA TYR A 57 -6.960 -12.805 13.325 1.00 96.56 C +ATOM 407 C TYR A 57 -7.847 -12.267 12.206 1.00 96.56 C +ATOM 408 O TYR A 57 -7.411 -11.455 11.387 1.00 96.56 O +ATOM 409 CB TYR A 57 -7.072 -11.921 14.568 1.00 96.56 C +ATOM 410 CG TYR A 57 -6.251 -12.402 15.748 1.00 96.56 C +ATOM 411 CD1 TYR A 57 -6.840 -13.203 16.746 1.00 96.56 C +ATOM 412 CD2 TYR A 57 -4.895 -12.035 15.847 1.00 96.56 C +ATOM 413 CE1 TYR A 57 -6.068 -13.648 17.838 1.00 96.56 C +ATOM 414 CE2 TYR A 57 -4.114 -12.500 16.916 1.00 96.56 C +ATOM 415 CZ TYR A 57 -4.702 -13.309 17.909 1.00 96.56 C +ATOM 416 OH TYR A 57 -3.932 -13.741 18.935 1.00 96.56 O +ATOM 417 N SER A 58 -9.102 -12.704 12.203 1.00 96.21 N +ATOM 418 CA SER A 58 -10.163 -12.193 11.341 1.00 96.21 C +ATOM 419 C SER A 58 -11.327 -11.727 12.206 1.00 96.21 C +ATOM 420 O SER A 58 -11.739 -12.435 13.128 1.00 96.21 O +ATOM 421 CB SER A 58 -10.606 -13.271 10.353 1.00 96.21 C +ATOM 422 OG SER A 58 -11.594 -12.768 9.482 1.00 96.21 O +ATOM 423 N VAL A 59 -11.836 -10.532 11.917 1.00 96.83 N +ATOM 424 CA VAL A 59 -13.004 -9.949 12.574 1.00 96.83 C +ATOM 425 C VAL A 59 -14.140 -9.880 11.565 1.00 96.83 C +ATOM 426 O VAL A 59 -13.962 -9.328 10.481 1.00 96.83 O +ATOM 427 CB VAL A 59 -12.712 -8.553 13.147 1.00 96.83 C +ATOM 428 CG1 VAL A 59 -13.894 -8.051 13.983 1.00 96.83 C +ATOM 429 CG2 VAL A 59 -11.462 -8.539 14.034 1.00 96.83 C +ATOM 430 N LEU A 60 -15.305 -10.409 11.928 1.00 96.31 N +ATOM 431 CA LEU A 60 -16.523 -10.362 11.124 1.00 96.31 C +ATOM 432 C LEU A 60 -17.596 -9.562 11.863 1.00 96.31 C +ATOM 433 O LEU A 60 -17.966 -9.916 12.979 1.00 96.31 O +ATOM 434 CB LEU A 60 -16.972 -11.804 10.827 1.00 96.31 C +ATOM 435 CG LEU A 60 -18.262 -11.902 9.994 1.00 96.31 C +ATOM 436 CD1 LEU A 60 -18.072 -11.389 8.566 1.00 96.31 C +ATOM 437 CD2 LEU A 60 -18.726 -13.358 9.929 1.00 96.31 C +ATOM 438 N ALA A 61 -18.112 -8.516 11.227 1.00 96.00 N +ATOM 439 CA ALA A 61 -19.256 -7.743 11.686 1.00 96.00 C +ATOM 440 C ALA A 61 -20.495 -8.144 10.880 1.00 96.00 C +ATOM 441 O ALA A 61 -20.527 -7.986 9.660 1.00 96.00 O +ATOM 442 CB ALA A 61 -18.930 -6.255 11.558 1.00 96.00 C +ATOM 443 N VAL A 62 -21.508 -8.666 11.569 1.00 95.34 N +ATOM 444 CA VAL A 62 -22.757 -9.144 10.967 1.00 95.34 C +ATOM 445 C VAL A 62 -23.898 -8.202 11.317 1.00 95.34 C +ATOM 446 O VAL A 62 -24.153 -7.945 12.495 1.00 95.34 O +ATOM 447 CB VAL A 62 -23.078 -10.589 11.390 1.00 95.34 C +ATOM 448 CG1 VAL A 62 -24.343 -11.120 10.703 1.00 95.34 C +ATOM 449 CG2 VAL A 62 -21.923 -11.536 11.039 1.00 95.34 C +ATOM 450 N GLU A 63 -24.600 -7.721 10.299 1.00 93.27 N +ATOM 451 CA GLU A 63 -25.771 -6.851 10.428 1.00 93.27 C +ATOM 452 C GLU A 63 -27.037 -7.614 10.009 1.00 93.27 C +ATOM 453 O GLU A 63 -26.989 -8.526 9.182 1.00 93.27 O +ATOM 454 CB GLU A 63 -25.488 -5.560 9.651 1.00 93.27 C +ATOM 455 CG GLU A 63 -26.516 -4.428 9.799 1.00 93.27 C +ATOM 456 CD GLU A 63 -27.748 -4.662 8.935 1.00 93.27 C +ATOM 457 OE1 GLU A 63 -28.866 -4.434 9.451 1.00 93.27 O +ATOM 458 OE2 GLU A 63 -27.593 -5.231 7.834 1.00 93.27 O +ATOM 459 N LYS A 64 -28.184 -7.294 10.622 1.00 85.77 N +ATOM 460 CA LYS A 64 -29.427 -8.069 10.447 1.00 85.77 C +ATOM 461 C LYS A 64 -29.961 -8.065 9.010 1.00 85.77 C +ATOM 462 O LYS A 64 -30.614 -9.029 8.622 1.00 85.77 O +ATOM 463 CB LYS A 64 -30.517 -7.549 11.393 1.00 85.77 C +ATOM 464 CG LYS A 64 -30.260 -7.919 12.859 1.00 85.77 C +ATOM 465 CD LYS A 64 -31.445 -7.471 13.723 1.00 85.77 C +ATOM 466 CE LYS A 64 -31.211 -7.850 15.187 1.00 85.77 C +ATOM 467 NZ LYS A 64 -32.314 -7.364 16.052 1.00 85.77 N +ATOM 468 N GLN A 65 -29.723 -7.001 8.249 1.00 82.48 N +ATOM 469 CA GLN A 65 -30.135 -6.830 6.854 1.00 82.48 C +ATOM 470 C GLN A 65 -29.062 -7.295 5.850 1.00 82.48 C +ATOM 471 O GLN A 65 -29.278 -7.202 4.643 1.00 82.48 O +ATOM 472 CB GLN A 65 -30.561 -5.370 6.601 1.00 82.48 C +ATOM 473 CG GLN A 65 -31.639 -4.875 7.578 1.00 82.48 C +ATOM 474 CD GLN A 65 -32.043 -3.423 7.344 1.00 82.48 C +ATOM 475 OE1 GLN A 65 -31.627 -2.737 6.429 1.00 82.48 O +ATOM 476 NE2 GLN A 65 -32.927 -2.888 8.158 1.00 82.48 N +ATOM 477 N GLY A 66 -27.944 -7.859 6.322 1.00 86.08 N +ATOM 478 CA GLY A 66 -26.912 -8.478 5.489 1.00 86.08 C +ATOM 479 C GLY A 66 -25.771 -7.550 5.071 1.00 86.08 C +ATOM 480 O GLY A 66 -24.924 -7.971 4.281 1.00 86.08 O +ATOM 481 N ALA A 67 -25.699 -6.325 5.603 1.00 86.59 N +ATOM 482 CA ALA A 67 -24.604 -5.389 5.341 1.00 86.59 C +ATOM 483 C ALA A 67 -23.322 -5.762 6.114 1.00 86.59 C +ATOM 484 O ALA A 67 -22.808 -4.981 6.907 1.00 86.59 O +ATOM 485 CB ALA A 67 -25.096 -3.963 5.622 1.00 86.59 C +ATOM 486 N ASN A 68 -22.815 -6.980 5.922 1.00 92.76 N +ATOM 487 CA ASN A 68 -21.675 -7.495 6.677 1.00 92.76 C +ATOM 488 C ASN A 68 -20.365 -6.814 6.259 1.00 92.76 C +ATOM 489 O ASN A 68 -20.143 -6.538 5.081 1.00 92.76 O +ATOM 490 CB ASN A 68 -21.585 -9.021 6.522 1.00 92.76 C +ATOM 491 CG ASN A 68 -22.809 -9.757 7.033 1.00 92.76 C +ATOM 492 OD1 ASN A 68 -23.648 -9.247 7.756 1.00 92.76 O +ATOM 493 ND2 ASN A 68 -22.950 -11.013 6.682 1.00 92.76 N +ATOM 494 N SER A 69 -19.464 -6.626 7.218 1.00 93.63 N +ATOM 495 CA SER A 69 -18.110 -6.121 6.977 1.00 93.63 C +ATOM 496 C SER A 69 -17.088 -6.978 7.715 1.00 93.63 C +ATOM 497 O SER A 69 -17.427 -7.721 8.637 1.00 93.63 O +ATOM 498 CB SER A 69 -18.005 -4.643 7.355 1.00 93.63 C +ATOM 499 OG SER A 69 -16.734 -4.163 6.968 1.00 93.63 O +ATOM 500 N SER A 70 -15.829 -6.929 7.296 1.00 95.92 N +ATOM 501 CA SER A 70 -14.770 -7.709 7.929 1.00 95.92 C +ATOM 502 C SER A 70 -13.418 -7.024 7.823 1.00 95.92 C +ATOM 503 O SER A 70 -13.209 -6.153 6.981 1.00 95.92 O +ATOM 504 CB SER A 70 -14.712 -9.125 7.341 1.00 95.92 C +ATOM 505 OG SER A 70 -14.353 -9.095 5.974 1.00 95.92 O +ATOM 506 N CYS A 71 -12.492 -7.438 8.678 1.00 95.74 N +ATOM 507 CA CYS A 71 -11.100 -7.027 8.599 1.00 95.74 C +ATOM 508 C CYS A 71 -10.187 -8.177 9.055 1.00 95.74 C +ATOM 509 O CYS A 71 -10.627 -9.106 9.736 1.00 95.74 O +ATOM 510 CB CYS A 71 -10.933 -5.724 9.388 1.00 95.74 C +ATOM 511 SG CYS A 71 -10.862 -5.904 11.178 1.00 95.74 S +ATOM 512 N SER A 72 -8.920 -8.156 8.641 1.00 95.46 N +ATOM 513 CA SER A 72 -7.920 -9.151 9.046 1.00 95.46 C +ATOM 514 C SER A 72 -6.635 -8.461 9.481 1.00 95.46 C +ATOM 515 O SER A 72 -6.214 -7.494 8.849 1.00 95.46 O +ATOM 516 CB SER A 72 -7.629 -10.140 7.915 1.00 95.46 C +ATOM 517 OG SER A 72 -8.796 -10.871 7.593 1.00 95.46 O +ATOM 518 N ALA A 73 -6.009 -8.960 10.545 1.00 94.81 N +ATOM 519 CA ALA A 73 -4.806 -8.363 11.114 1.00 94.81 C +ATOM 520 C ALA A 73 -3.862 -9.417 11.706 1.00 94.81 C +ATOM 521 O ALA A 73 -4.288 -10.456 12.209 1.00 94.81 O +ATOM 522 CB ALA A 73 -5.220 -7.333 12.170 1.00 94.81 C +ATOM 523 N THR A 74 -2.559 -9.139 11.665 1.00 94.25 N +ATOM 524 CA THR A 74 -1.532 -9.877 12.425 1.00 94.25 C +ATOM 525 C THR A 74 -1.281 -9.257 13.803 1.00 94.25 C +ATOM 526 O THR A 74 -0.636 -9.868 14.654 1.00 94.25 O +ATOM 527 CB THR A 74 -0.216 -9.936 11.641 1.00 94.25 C +ATOM 528 OG1 THR A 74 0.163 -8.634 11.253 1.00 94.25 O +ATOM 529 CG2 THR A 74 -0.349 -10.770 10.367 1.00 94.25 C +ATOM 530 N THR A 75 -1.800 -8.050 14.033 1.00 94.54 N +ATOM 531 CA THR A 75 -1.796 -7.339 15.313 1.00 94.54 C +ATOM 532 C THR A 75 -2.977 -7.769 16.193 1.00 94.54 C +ATOM 533 O THR A 75 -3.819 -8.572 15.796 1.00 94.54 O +ATOM 534 CB THR A 75 -1.808 -5.816 15.068 1.00 94.54 C +ATOM 535 OG1 THR A 75 -2.875 -5.473 14.221 1.00 94.54 O +ATOM 536 CG2 THR A 75 -0.522 -5.352 14.380 1.00 94.54 C +ATOM 537 N LEU A 76 -3.033 -7.240 17.420 1.00 95.39 N +ATOM 538 CA LEU A 76 -4.110 -7.487 18.395 1.00 95.39 C +ATOM 539 C LEU A 76 -5.269 -6.481 18.290 1.00 95.39 C +ATOM 540 O LEU A 76 -6.051 -6.307 19.225 1.00 95.39 O +ATOM 541 CB LEU A 76 -3.516 -7.512 19.812 1.00 95.39 C +ATOM 542 CG LEU A 76 -2.441 -8.583 20.045 1.00 95.39 C +ATOM 543 CD1 LEU A 76 -1.941 -8.482 21.486 1.00 95.39 C +ATOM 544 CD2 LEU A 76 -2.965 -10.000 19.803 1.00 95.39 C +ATOM 545 N ASN A 77 -5.329 -5.763 17.174 1.00 94.82 N +ATOM 546 CA ASN A 77 -6.378 -4.815 16.866 1.00 94.82 C +ATOM 547 C ASN A 77 -6.679 -4.843 15.371 1.00 94.82 C +ATOM 548 O ASN A 77 -5.824 -5.202 14.562 1.00 94.82 O +ATOM 549 CB ASN A 77 -6.000 -3.416 17.384 1.00 94.82 C +ATOM 550 CG ASN A 77 -4.723 -2.827 16.802 1.00 94.82 C +ATOM 551 OD1 ASN A 77 -4.238 -3.156 15.733 1.00 94.82 O +ATOM 552 ND2 ASN A 77 -4.098 -1.924 17.518 1.00 94.82 N +ATOM 553 N CYS A 78 -7.900 -4.486 14.999 1.00 94.63 N +ATOM 554 CA CYS A 78 -8.290 -4.421 13.601 1.00 94.63 C +ATOM 555 C CYS A 78 -9.454 -3.459 13.424 1.00 94.63 C +ATOM 556 O CYS A 78 -10.381 -3.450 14.235 1.00 94.63 O +ATOM 557 CB CYS A 78 -8.612 -5.840 13.147 1.00 94.63 C +ATOM 558 SG CYS A 78 -8.878 -6.122 11.400 1.00 94.63 S +ATOM 559 N ASN A 79 -9.381 -2.642 12.377 1.00 93.71 N +ATOM 560 CA ASN A 79 -10.438 -1.704 12.054 1.00 93.71 C +ATOM 561 C ASN A 79 -11.411 -2.338 11.064 1.00 93.71 C +ATOM 562 O ASN A 79 -11.006 -2.665 9.950 1.00 93.71 O +ATOM 563 CB ASN A 79 -9.839 -0.406 11.495 1.00 93.71 C +ATOM 564 CG ASN A 79 -10.891 0.680 11.489 1.00 93.71 C +ATOM 565 OD1 ASN A 79 -11.886 0.575 12.182 1.00 93.71 O +ATOM 566 ND2 ASN A 79 -10.731 1.730 10.725 1.00 93.71 N +ATOM 567 N VAL A 80 -12.671 -2.514 11.458 1.00 94.29 N +ATOM 568 CA VAL A 80 -13.732 -2.998 10.568 1.00 94.29 C +ATOM 569 C VAL A 80 -14.375 -1.794 9.874 1.00 94.29 C +ATOM 570 O VAL A 80 -15.071 -1.036 10.551 1.00 94.29 O +ATOM 571 CB VAL A 80 -14.789 -3.822 11.322 1.00 94.29 C +ATOM 572 CG1 VAL A 80 -15.798 -4.388 10.316 1.00 94.29 C +ATOM 573 CG2 VAL A 80 -14.182 -5.011 12.075 1.00 94.29 C +ATOM 574 N PRO A 81 -14.165 -1.587 8.560 1.00 91.02 N +ATOM 575 CA PRO A 81 -14.607 -0.378 7.869 1.00 91.02 C +ATOM 576 C PRO A 81 -16.052 -0.477 7.356 1.00 91.02 C +ATOM 577 O PRO A 81 -16.632 -1.563 7.289 1.00 91.02 O +ATOM 578 CB PRO A 81 -13.603 -0.219 6.724 1.00 91.02 C +ATOM 579 CG PRO A 81 -13.326 -1.667 6.320 1.00 91.02 C +ATOM 580 CD PRO A 81 -13.369 -2.412 7.652 1.00 91.02 C +ATOM 581 N GLY A 82 -16.610 0.655 6.916 1.00 84.64 N +ATOM 582 CA GLY A 82 -17.788 0.683 6.041 1.00 84.64 C +ATOM 583 C GLY A 82 -19.111 0.269 6.691 1.00 84.64 C +ATOM 584 O GLY A 82 -19.982 -0.272 6.007 1.00 84.64 O +ATOM 585 N LEU A 83 -19.287 0.497 7.997 1.00 89.54 N +ATOM 586 CA LEU A 83 -20.543 0.171 8.669 1.00 89.54 C +ATOM 587 C LEU A 83 -21.640 1.176 8.282 1.00 89.54 C +ATOM 588 O LEU A 83 -21.469 2.398 8.323 1.00 89.54 O +ATOM 589 CB LEU A 83 -20.358 0.069 10.192 1.00 89.54 C +ATOM 590 CG LEU A 83 -19.190 -0.824 10.655 1.00 89.54 C +ATOM 591 CD1 LEU A 83 -19.137 -0.803 12.179 1.00 89.54 C +ATOM 592 CD2 LEU A 83 -19.329 -2.280 10.217 1.00 89.54 C +ATOM 593 N GLN A 84 -22.810 0.658 7.928 1.00 85.82 N +ATOM 594 CA GLN A 84 -23.983 1.475 7.621 1.00 85.82 C +ATOM 595 C GLN A 84 -24.520 2.171 8.877 1.00 85.82 C +ATOM 596 O GLN A 84 -24.459 1.634 9.986 1.00 85.82 O +ATOM 597 CB GLN A 84 -25.076 0.632 6.943 1.00 85.82 C +ATOM 598 CG GLN A 84 -24.605 -0.013 5.629 1.00 85.82 C +ATOM 599 CD GLN A 84 -24.174 1.021 4.592 1.00 85.82 C +ATOM 600 OE1 GLN A 84 -24.813 2.043 4.396 1.00 85.82 O +ATOM 601 NE2 GLN A 84 -23.060 0.822 3.923 1.00 85.82 N +ATOM 602 N CYS A 85 -25.076 3.365 8.693 1.00 83.02 N +ATOM 603 CA CYS A 85 -25.745 4.126 9.744 1.00 83.02 C +ATOM 604 C CYS A 85 -27.026 3.445 10.249 1.00 83.02 C +ATOM 605 O CYS A 85 -27.761 2.841 9.474 1.00 83.02 O +ATOM 606 CB CYS A 85 -26.094 5.499 9.181 1.00 83.02 C +ATOM 607 SG CYS A 85 -24.866 6.770 9.490 1.00 83.02 S +ATOM 608 N GLY A 86 -27.326 3.608 11.541 1.00 82.47 N +ATOM 609 CA GLY A 86 -28.543 3.099 12.183 1.00 82.47 C +ATOM 610 C GLY A 86 -28.636 1.573 12.307 1.00 82.47 C +ATOM 611 O GLY A 86 -29.691 1.061 12.678 1.00 82.47 O +ATOM 612 N GLY A 87 -27.561 0.846 12.000 1.00 86.39 N +ATOM 613 CA GLY A 87 -27.496 -0.611 12.068 1.00 86.39 C +ATOM 614 C GLY A 87 -26.972 -1.111 13.414 1.00 86.39 C +ATOM 615 O GLY A 87 -26.173 -0.452 14.080 1.00 86.39 O +ATOM 616 N THR A 88 -27.391 -2.313 13.810 1.00 92.11 N +ATOM 617 CA THR A 88 -26.800 -3.036 14.946 1.00 92.11 C +ATOM 618 C THR A 88 -25.943 -4.174 14.416 1.00 92.11 C +ATOM 619 O THR A 88 -26.464 -5.111 13.809 1.00 92.11 O +ATOM 620 CB THR A 88 -27.861 -3.577 15.913 1.00 92.11 C +ATOM 621 OG1 THR A 88 -28.739 -2.559 16.334 1.00 92.11 O +ATOM 622 CG2 THR A 88 -27.232 -4.170 17.175 1.00 92.11 C +ATOM 623 N TYR A 89 -24.641 -4.099 14.678 1.00 93.89 N +ATOM 624 CA TYR A 89 -23.650 -5.067 14.224 1.00 93.89 C +ATOM 625 C TYR A 89 -23.241 -5.986 15.369 1.00 93.89 C +ATOM 626 O TYR A 89 -22.983 -5.519 16.477 1.00 93.89 O +ATOM 627 CB TYR A 89 -22.435 -4.335 13.649 1.00 93.89 C +ATOM 628 CG TYR A 89 -22.716 -3.665 12.325 1.00 93.89 C +ATOM 629 CD1 TYR A 89 -22.314 -4.288 11.131 1.00 93.89 C +ATOM 630 CD2 TYR A 89 -23.395 -2.430 12.285 1.00 93.89 C +ATOM 631 CE1 TYR A 89 -22.584 -3.670 9.899 1.00 93.89 C +ATOM 632 CE2 TYR A 89 -23.724 -1.846 11.049 1.00 93.89 C +ATOM 633 CZ TYR A 89 -23.331 -2.479 9.852 1.00 93.89 C +ATOM 634 OH TYR A 89 -23.708 -1.956 8.662 1.00 93.89 O +ATOM 635 N THR A 90 -23.162 -7.286 15.091 1.00 95.39 N +ATOM 636 CA THR A 90 -22.594 -8.292 15.999 1.00 95.39 C +ATOM 637 C THR A 90 -21.209 -8.685 15.502 1.00 95.39 C +ATOM 638 O THR A 90 -21.067 -9.095 14.351 1.00 95.39 O +ATOM 639 CB THR A 90 -23.502 -9.525 16.114 1.00 95.39 C +ATOM 640 OG1 THR A 90 -24.816 -9.123 16.447 1.00 95.39 O +ATOM 641 CG2 THR A 90 -23.028 -10.478 17.207 1.00 95.39 C +ATOM 642 N PHE A 91 -20.195 -8.545 16.353 1.00 95.89 N +ATOM 643 CA PHE A 91 -18.794 -8.770 16.002 1.00 95.89 C +ATOM 644 C PHE A 91 -18.317 -10.141 16.475 1.00 95.89 C +ATOM 645 O PHE A 91 -18.614 -10.548 17.596 1.00 95.89 O +ATOM 646 CB PHE A 91 -17.919 -7.654 16.582 1.00 95.89 C +ATOM 647 CG PHE A 91 -18.173 -6.300 15.953 1.00 95.89 C +ATOM 648 CD1 PHE A 91 -17.325 -5.813 14.940 1.00 95.89 C +ATOM 649 CD2 PHE A 91 -19.287 -5.542 16.355 1.00 95.89 C +ATOM 650 CE1 PHE A 91 -17.599 -4.579 14.324 1.00 95.89 C +ATOM 651 CE2 PHE A 91 -19.580 -4.331 15.712 1.00 95.89 C +ATOM 652 CZ PHE A 91 -18.740 -3.849 14.695 1.00 95.89 C +ATOM 653 N TYR A 92 -17.538 -10.818 15.636 1.00 95.78 N +ATOM 654 CA TYR A 92 -16.928 -12.117 15.908 1.00 95.78 C +ATOM 655 C TYR A 92 -15.435 -12.058 15.603 1.00 95.78 C +ATOM 656 O TYR A 92 -15.057 -11.700 14.490 1.00 95.78 O +ATOM 657 CB TYR A 92 -17.593 -13.184 15.031 1.00 95.78 C +ATOM 658 CG TYR A 92 -19.082 -13.336 15.252 1.00 95.78 C +ATOM 659 CD1 TYR A 92 -19.559 -14.127 16.314 1.00 95.78 C +ATOM 660 CD2 TYR A 92 -19.985 -12.664 14.406 1.00 95.78 C +ATOM 661 CE1 TYR A 92 -20.945 -14.256 16.525 1.00 95.78 C +ATOM 662 CE2 TYR A 92 -21.370 -12.791 14.614 1.00 95.78 C +ATOM 663 CZ TYR A 92 -21.851 -13.588 15.672 1.00 95.78 C +ATOM 664 OH TYR A 92 -23.188 -13.700 15.881 1.00 95.78 O +ATOM 665 N VAL A 93 -14.587 -12.441 16.560 1.00 96.54 N +ATOM 666 CA VAL A 93 -13.130 -12.515 16.371 1.00 96.54 C +ATOM 667 C VAL A 93 -12.713 -13.977 16.273 1.00 96.54 C +ATOM 668 O VAL A 93 -13.050 -14.782 17.136 1.00 96.54 O +ATOM 669 CB VAL A 93 -12.362 -11.787 17.491 1.00 96.54 C +ATOM 670 CG1 VAL A 93 -10.857 -11.741 17.188 1.00 96.54 C +ATOM 671 CG2 VAL A 93 -12.846 -10.339 17.656 1.00 96.54 C +ATOM 672 N THR A 94 -11.968 -14.325 15.229 1.00 96.39 N +ATOM 673 CA THR A 94 -11.461 -15.682 14.991 1.00 96.39 C +ATOM 674 C THR A 94 -9.943 -15.645 14.874 1.00 96.39 C +ATOM 675 O THR A 94 -9.403 -14.876 14.084 1.00 96.39 O +ATOM 676 CB THR A 94 -12.089 -16.281 13.724 1.00 96.39 C +ATOM 677 OG1 THR A 94 -13.494 -16.244 13.828 1.00 96.39 O +ATOM 678 CG2 THR A 94 -11.688 -17.740 13.524 1.00 96.39 C +ATOM 679 N ALA A 95 -9.240 -16.479 15.641 1.00 96.34 N +ATOM 680 CA ALA A 95 -7.799 -16.683 15.496 1.00 96.34 C +ATOM 681 C ALA A 95 -7.485 -17.706 14.394 1.00 96.34 C +ATOM 682 O ALA A 95 -8.137 -18.753 14.320 1.00 96.34 O +ATOM 683 CB ALA A 95 -7.207 -17.118 16.839 1.00 96.34 C +ATOM 684 N LEU A 96 -6.451 -17.432 13.594 1.00 95.02 N +ATOM 685 CA LEU A 96 -5.974 -18.262 12.488 1.00 95.02 C +ATOM 686 C LEU A 96 -4.485 -18.598 12.644 1.00 95.02 C +ATOM 687 O LEU A 96 -3.697 -17.820 13.185 1.00 95.02 O +ATOM 688 CB LEU A 96 -6.209 -17.566 11.132 1.00 95.02 C +ATOM 689 CG LEU A 96 -7.673 -17.189 10.834 1.00 95.02 C +ATOM 690 CD1 LEU A 96 -7.942 -15.718 11.147 1.00 95.02 C +ATOM 691 CD2 LEU A 96 -8.005 -17.412 9.359 1.00 95.02 C +ATOM 692 N ASN A 97 -4.087 -19.762 12.136 1.00 91.28 N +ATOM 693 CA ASN A 97 -2.692 -20.103 11.863 1.00 91.28 C +ATOM 694 C ASN A 97 -2.550 -20.662 10.439 1.00 91.28 C +ATOM 695 O ASN A 97 -3.502 -20.642 9.667 1.00 91.28 O +ATOM 696 CB ASN A 97 -2.161 -21.024 12.976 1.00 91.28 C +ATOM 697 CG ASN A 97 -2.732 -22.432 13.006 1.00 91.28 C +ATOM 698 OD1 ASN A 97 -3.196 -22.985 12.028 1.00 91.28 O +ATOM 699 ND2 ASN A 97 -2.617 -23.082 14.136 1.00 91.28 N +ATOM 700 N SER A 98 -1.370 -21.169 10.079 1.00 87.92 N +ATOM 701 CA SER A 98 -1.092 -21.679 8.728 1.00 87.92 C +ATOM 702 C SER A 98 -1.968 -22.858 8.283 1.00 87.92 C +ATOM 703 O SER A 98 -1.954 -23.190 7.103 1.00 87.92 O +ATOM 704 CB SER A 98 0.370 -22.128 8.638 1.00 87.92 C +ATOM 705 OG SER A 98 1.242 -21.125 9.127 1.00 87.92 O +ATOM 706 N PHE A 99 -2.682 -23.516 9.202 1.00 85.05 N +ATOM 707 CA PHE A 99 -3.401 -24.765 8.936 1.00 85.05 C +ATOM 708 C PHE A 99 -4.884 -24.715 9.319 1.00 85.05 C +ATOM 709 O PHE A 99 -5.709 -25.327 8.648 1.00 85.05 O +ATOM 710 CB PHE A 99 -2.702 -25.900 9.699 1.00 85.05 C +ATOM 711 CG PHE A 99 -1.243 -26.101 9.332 1.00 85.05 C +ATOM 712 CD1 PHE A 99 -0.908 -26.720 8.114 1.00 85.05 C +ATOM 713 CD2 PHE A 99 -0.221 -25.666 10.199 1.00 85.05 C +ATOM 714 CE1 PHE A 99 0.440 -26.917 7.769 1.00 85.05 C +ATOM 715 CE2 PHE A 99 1.129 -25.863 9.853 1.00 85.05 C +ATOM 716 CZ PHE A 99 1.458 -26.493 8.640 1.00 85.05 C +ATOM 717 N CYS A 100 -5.227 -24.016 10.402 1.00 89.65 N +ATOM 718 CA CYS A 100 -6.522 -24.110 11.064 1.00 89.65 C +ATOM 719 C CYS A 100 -7.006 -22.747 11.578 1.00 89.65 C +ATOM 720 O CYS A 100 -6.216 -21.861 11.916 1.00 89.65 O +ATOM 721 CB CYS A 100 -6.399 -25.085 12.246 1.00 89.65 C +ATOM 722 SG CYS A 100 -6.101 -26.790 11.695 1.00 89.65 S +ATOM 723 N GLN A 101 -8.325 -22.643 11.738 1.00 93.66 N +ATOM 724 CA GLN A 101 -9.002 -21.554 12.439 1.00 93.66 C +ATOM 725 C GLN A 101 -9.577 -22.045 13.772 1.00 93.66 C +ATOM 726 O GLN A 101 -9.941 -23.214 13.916 1.00 93.66 O +ATOM 727 CB GLN A 101 -10.062 -20.913 11.531 1.00 93.66 C +ATOM 728 CG GLN A 101 -11.217 -21.860 11.154 1.00 93.66 C +ATOM 729 CD GLN A 101 -12.170 -21.253 10.127 1.00 93.66 C +ATOM 730 OE1 GLN A 101 -12.084 -20.102 9.741 1.00 93.66 O +ATOM 731 NE2 GLN A 101 -13.112 -22.016 9.621 1.00 93.66 N +ATOM 732 N SER A 102 -9.632 -21.151 14.751 1.00 93.76 N +ATOM 733 CA SER A 102 -10.343 -21.368 16.015 1.00 93.76 C +ATOM 734 C SER A 102 -11.862 -21.242 15.829 1.00 93.76 C +ATOM 735 O SER A 102 -12.337 -20.800 14.783 1.00 93.76 O +ATOM 736 CB SER A 102 -9.826 -20.393 17.079 1.00 93.76 C +ATOM 737 OG SER A 102 -9.997 -19.064 16.643 1.00 93.76 O +ATOM 738 N SER A 103 -12.637 -21.620 16.849 1.00 94.15 N +ATOM 739 CA SER A 103 -14.032 -21.162 16.929 1.00 94.15 C +ATOM 740 C SER A 103 -14.060 -19.651 17.201 1.00 94.15 C +ATOM 741 O SER A 103 -13.136 -19.159 17.857 1.00 94.15 O +ATOM 742 CB SER A 103 -14.807 -21.882 18.035 1.00 94.15 C +ATOM 743 OG SER A 103 -14.861 -23.275 17.783 1.00 94.15 O +ATOM 744 N PRO A 104 -15.098 -18.919 16.755 1.00 92.86 N +ATOM 745 CA PRO A 104 -15.255 -17.512 17.097 1.00 92.86 C +ATOM 746 C PRO A 104 -15.254 -17.285 18.612 1.00 92.86 C +ATOM 747 O PRO A 104 -15.798 -18.093 19.368 1.00 92.86 O +ATOM 748 CB PRO A 104 -16.579 -17.072 16.470 1.00 92.86 C +ATOM 749 CG PRO A 104 -16.761 -18.048 15.310 1.00 92.86 C +ATOM 750 CD PRO A 104 -16.165 -19.342 15.861 1.00 92.86 C +ATOM 751 N GLY A 105 -14.639 -16.183 19.030 1.00 91.17 N +ATOM 752 CA GLY A 105 -14.631 -15.708 20.407 1.00 91.17 C +ATOM 753 C GLY A 105 -15.987 -15.198 20.891 1.00 91.17 C +ATOM 754 O GLY A 105 -17.031 -15.427 20.270 1.00 91.17 O +ATOM 755 N THR A 106 -15.980 -14.497 22.023 1.00 92.18 N +ATOM 756 CA THR A 106 -17.227 -13.962 22.587 1.00 92.18 C +ATOM 757 C THR A 106 -17.704 -12.793 21.732 1.00 92.18 C +ATOM 758 O THR A 106 -16.969 -11.833 21.512 1.00 92.18 O +ATOM 759 CB THR A 106 -17.083 -13.541 24.053 1.00 92.18 C +ATOM 760 OG1 THR A 106 -16.573 -14.625 24.799 1.00 92.18 O +ATOM 761 CG2 THR A 106 -18.432 -13.173 24.676 1.00 92.18 C +ATOM 762 N SER A 107 -18.942 -12.861 21.241 1.00 94.01 N +ATOM 763 CA SER A 107 -19.503 -11.784 20.428 1.00 94.01 C +ATOM 764 C SER A 107 -19.924 -10.588 21.273 1.00 94.01 C +ATOM 765 O SER A 107 -20.492 -10.761 22.352 1.00 94.01 O +ATOM 766 CB SER A 107 -20.689 -12.274 19.598 1.00 94.01 C +ATOM 767 OG SER A 107 -21.745 -12.689 20.449 1.00 94.01 O +ATOM 768 N PHE A 108 -19.773 -9.385 20.730 1.00 93.78 N +ATOM 769 CA PHE A 108 -20.323 -8.151 21.291 1.00 93.78 C +ATOM 770 C PHE A 108 -21.081 -7.373 20.210 1.00 93.78 C +ATOM 771 O PHE A 108 -20.919 -7.631 19.014 1.00 93.78 O +ATOM 772 CB PHE A 108 -19.201 -7.332 21.945 1.00 93.78 C +ATOM 773 CG PHE A 108 -18.141 -6.865 20.971 1.00 93.78 C +ATOM 774 CD1 PHE A 108 -17.042 -7.693 20.671 1.00 93.78 C +ATOM 775 CD2 PHE A 108 -18.282 -5.621 20.328 1.00 93.78 C +ATOM 776 CE1 PHE A 108 -16.096 -7.281 19.718 1.00 93.78 C +ATOM 777 CE2 PHE A 108 -17.338 -5.216 19.372 1.00 93.78 C +ATOM 778 CZ PHE A 108 -16.247 -6.045 19.071 1.00 93.78 C +ATOM 779 N GLN A 109 -21.937 -6.438 20.625 1.00 94.22 N +ATOM 780 CA GLN A 109 -22.765 -5.650 19.714 1.00 94.22 C +ATOM 781 C GLN A 109 -22.447 -4.163 19.806 1.00 94.22 C +ATOM 782 O GLN A 109 -22.257 -3.632 20.898 1.00 94.22 O +ATOM 783 CB GLN A 109 -24.260 -5.912 19.951 1.00 94.22 C +ATOM 784 CG GLN A 109 -24.640 -7.332 19.516 1.00 94.22 C +ATOM 785 CD GLN A 109 -26.132 -7.624 19.608 1.00 94.22 C +ATOM 786 OE1 GLN A 109 -26.916 -6.953 20.261 1.00 94.22 O +ATOM 787 NE2 GLN A 109 -26.587 -8.659 18.940 1.00 94.22 N +ATOM 788 N ILE A 110 -22.438 -3.492 18.654 1.00 91.74 N +ATOM 789 CA ILE A 110 -22.361 -2.032 18.558 1.00 91.74 C +ATOM 790 C ILE A 110 -23.489 -1.556 17.653 1.00 91.74 C +ATOM 791 O ILE A 110 -23.720 -2.102 16.573 1.00 91.74 O +ATOM 792 CB ILE A 110 -20.972 -1.555 18.079 1.00 91.74 C +ATOM 793 CG1 ILE A 110 -19.909 -1.935 19.134 1.00 91.74 C +ATOM 794 CG2 ILE A 110 -20.953 -0.040 17.793 1.00 91.74 C +ATOM 795 CD1 ILE A 110 -18.482 -1.574 18.730 1.00 91.74 C +ATOM 796 N GLN A 111 -24.193 -0.525 18.107 1.00 88.89 N +ATOM 797 CA GLN A 111 -25.194 0.172 17.316 1.00 88.89 C +ATOM 798 C GLN A 111 -24.577 1.443 16.734 1.00 88.89 C +ATOM 799 O GLN A 111 -24.062 2.281 17.474 1.00 88.89 O +ATOM 800 CB GLN A 111 -26.419 0.439 18.194 1.00 88.89 C +ATOM 801 CG GLN A 111 -27.552 1.098 17.399 1.00 88.89 C +ATOM 802 CD GLN A 111 -28.819 1.276 18.227 1.00 88.89 C +ATOM 803 OE1 GLN A 111 -29.034 0.660 19.258 1.00 88.89 O +ATOM 804 NE2 GLN A 111 -29.725 2.120 17.792 1.00 88.89 N +ATOM 805 N THR A 112 -24.634 1.590 15.414 1.00 85.75 N +ATOM 806 CA THR A 112 -24.197 2.814 14.743 1.00 85.75 C +ATOM 807 C THR A 112 -25.268 3.895 14.884 1.00 85.75 C +ATOM 808 O THR A 112 -26.471 3.618 14.927 1.00 85.75 O +ATOM 809 CB THR A 112 -23.827 2.573 13.271 1.00 85.75 C +ATOM 810 OG1 THR A 112 -24.925 2.089 12.546 1.00 85.75 O +ATOM 811 CG2 THR A 112 -22.701 1.552 13.115 1.00 85.75 C +ATOM 812 N ALA A 113 -24.842 5.156 14.965 1.00 79.65 N +ATOM 813 CA ALA A 113 -25.777 6.275 14.995 1.00 79.65 C +ATOM 814 C ALA A 113 -26.597 6.328 13.687 1.00 79.65 C +ATOM 815 O ALA A 113 -26.055 6.021 12.619 1.00 79.65 O +ATOM 816 CB ALA A 113 -25.006 7.576 15.244 1.00 79.65 C +ATOM 817 N PRO A 114 -27.886 6.710 13.733 1.00 79.10 N +ATOM 818 CA PRO A 114 -28.650 6.984 12.523 1.00 79.10 C +ATOM 819 C PRO A 114 -28.047 8.184 11.780 1.00 79.10 C +ATOM 820 O PRO A 114 -27.644 9.170 12.396 1.00 79.10 O +ATOM 821 CB PRO A 114 -30.085 7.239 12.992 1.00 79.10 C +ATOM 822 CG PRO A 114 -29.905 7.766 14.416 1.00 79.10 C +ATOM 823 CD PRO A 114 -28.667 7.025 14.919 1.00 79.10 C +ATOM 824 N CYS A 115 -28.000 8.094 10.454 1.00 77.65 N +ATOM 825 CA CYS A 115 -27.641 9.208 9.584 1.00 77.65 C +ATOM 826 C CYS A 115 -28.893 10.060 9.347 1.00 77.65 C +ATOM 827 O CYS A 115 -29.934 9.516 8.979 1.00 77.65 O +ATOM 828 CB CYS A 115 -27.113 8.666 8.252 1.00 77.65 C +ATOM 829 SG CYS A 115 -25.369 8.175 8.130 1.00 77.65 S +ATOM 830 N SER A 116 -28.798 11.377 9.537 1.00 74.95 N +ATOM 831 CA SER A 116 -29.929 12.289 9.290 1.00 74.95 C +ATOM 832 C SER A 116 -29.874 12.959 7.915 1.00 74.95 C +ATOM 833 O SER A 116 -30.902 13.409 7.415 1.00 74.95 O +ATOM 834 CB SER A 116 -30.022 13.372 10.365 1.00 74.95 C +ATOM 835 OG SER A 116 -30.027 12.819 11.667 1.00 74.95 O +ATOM 836 N LEU A 117 -28.690 13.055 7.298 1.00 78.26 N +ATOM 837 CA LEU A 117 -28.541 13.597 5.945 1.00 78.26 C +ATOM 838 C LEU A 117 -28.590 12.476 4.903 1.00 78.26 C +ATOM 839 O LEU A 117 -28.282 11.318 5.188 1.00 78.26 O +ATOM 840 CB LEU A 117 -27.262 14.445 5.822 1.00 78.26 C +ATOM 841 CG LEU A 117 -27.162 15.635 6.792 1.00 78.26 C +ATOM 842 CD1 LEU A 117 -25.820 16.340 6.615 1.00 78.26 C +ATOM 843 CD2 LEU A 117 -28.268 16.664 6.552 1.00 78.26 C +ATOM 844 N THR A 118 -28.964 12.837 3.678 1.00 78.01 N +ATOM 845 CA THR A 118 -28.930 11.939 2.520 1.00 78.01 C +ATOM 846 C THR A 118 -27.493 11.647 2.088 1.00 78.01 C +ATOM 847 O THR A 118 -26.545 12.304 2.524 1.00 78.01 O +ATOM 848 CB THR A 118 -29.718 12.547 1.349 1.00 78.01 C +ATOM 849 OG1 THR A 118 -29.256 13.854 1.099 1.00 78.01 O +ATOM 850 CG2 THR A 118 -31.213 12.624 1.653 1.00 78.01 C +ATOM 851 N SER A 119 -27.327 10.669 1.197 1.00 81.36 N +ATOM 852 CA SER A 119 -26.041 10.372 0.568 1.00 81.36 C +ATOM 853 C SER A 119 -25.431 11.613 -0.088 1.00 81.36 C +ATOM 854 O SER A 119 -26.132 12.431 -0.689 1.00 81.36 O +ATOM 855 CB SER A 119 -26.203 9.268 -0.478 1.00 81.36 C +ATOM 856 OG SER A 119 -26.768 8.121 0.129 1.00 81.36 O +ATOM 857 N ILE A 120 -24.112 11.724 0.031 1.00 90.53 N +ATOM 858 CA ILE A 120 -23.304 12.756 -0.615 1.00 90.53 C +ATOM 859 C ILE A 120 -22.665 12.194 -1.879 1.00 90.53 C +ATOM 860 O ILE A 120 -22.565 10.979 -2.055 1.00 90.53 O +ATOM 861 CB ILE A 120 -22.259 13.340 0.363 1.00 90.53 C +ATOM 862 CG1 ILE A 120 -21.213 12.292 0.807 1.00 90.53 C +ATOM 863 CG2 ILE A 120 -23.004 13.935 1.565 1.00 90.53 C +ATOM 864 CD1 ILE A 120 -20.116 12.860 1.714 1.00 90.53 C +ATOM 865 N THR A 121 -22.204 13.084 -2.746 1.00 92.93 N +ATOM 866 CA THR A 121 -21.298 12.726 -3.835 1.00 92.93 C +ATOM 867 C THR A 121 -20.036 13.549 -3.707 1.00 92.93 C +ATOM 868 O THR A 121 -20.070 14.689 -3.241 1.00 92.93 O +ATOM 869 CB THR A 121 -21.927 12.897 -5.222 1.00 92.93 C +ATOM 870 OG1 THR A 121 -22.187 14.243 -5.508 1.00 92.93 O +ATOM 871 CG2 THR A 121 -23.239 12.133 -5.383 1.00 92.93 C +ATOM 872 N ALA A 122 -18.911 12.976 -4.101 1.00 93.07 N +ATOM 873 CA ALA A 122 -17.663 13.701 -4.114 1.00 93.07 C +ATOM 874 C ALA A 122 -16.834 13.270 -5.322 1.00 93.07 C +ATOM 875 O ALA A 122 -16.839 12.100 -5.710 1.00 93.07 O +ATOM 876 CB ALA A 122 -16.999 13.527 -2.745 1.00 93.07 C +ATOM 877 N HIS A 123 -16.142 14.230 -5.924 1.00 91.61 N +ATOM 878 CA HIS A 123 -15.304 14.002 -7.093 1.00 91.61 C +ATOM 879 C HIS A 123 -14.017 14.821 -7.010 1.00 91.61 C +ATOM 880 O HIS A 123 -13.961 15.876 -6.372 1.00 91.61 O +ATOM 881 CB HIS A 123 -16.101 14.283 -8.379 1.00 91.61 C +ATOM 882 CG HIS A 123 -16.564 15.710 -8.569 1.00 91.61 C +ATOM 883 ND1 HIS A 123 -15.884 16.853 -8.225 1.00 91.61 N +ATOM 884 CD2 HIS A 123 -17.701 16.115 -9.215 1.00 91.61 C +ATOM 885 CE1 HIS A 123 -16.580 17.912 -8.665 1.00 91.61 C +ATOM 886 NE2 HIS A 123 -17.714 17.512 -9.254 1.00 91.61 N +ATOM 887 N THR A 124 -12.984 14.352 -7.694 1.00 89.02 N +ATOM 888 CA THR A 124 -11.710 15.053 -7.822 1.00 89.02 C +ATOM 889 C THR A 124 -11.155 14.810 -9.216 1.00 89.02 C +ATOM 890 O THR A 124 -11.273 13.704 -9.748 1.00 89.02 O +ATOM 891 CB THR A 124 -10.740 14.611 -6.715 1.00 89.02 C +ATOM 892 OG1 THR A 124 -9.575 15.393 -6.738 1.00 89.02 O +ATOM 893 CG2 THR A 124 -10.310 13.143 -6.782 1.00 89.02 C +ATOM 894 N ASP A 125 -10.570 15.840 -9.818 1.00 86.56 N +ATOM 895 CA ASP A 125 -9.788 15.657 -11.034 1.00 86.56 C +ATOM 896 C ASP A 125 -8.451 15.008 -10.669 1.00 86.56 C +ATOM 897 O ASP A 125 -7.858 15.319 -9.638 1.00 86.56 O +ATOM 898 CB ASP A 125 -9.564 16.985 -11.763 1.00 86.56 C +ATOM 899 CG ASP A 125 -10.865 17.642 -12.216 1.00 86.56 C +ATOM 900 OD1 ASP A 125 -11.709 16.913 -12.780 1.00 86.56 O +ATOM 901 OD2 ASP A 125 -10.973 18.871 -12.013 1.00 86.56 O +ATOM 902 N CYS A 126 -7.927 14.139 -11.531 1.00 84.95 N +ATOM 903 CA CYS A 126 -6.768 13.297 -11.210 1.00 84.95 C +ATOM 904 C CYS A 126 -5.495 14.063 -10.795 1.00 84.95 C +ATOM 905 O CYS A 126 -4.617 13.492 -10.152 1.00 84.95 O +ATOM 906 CB CYS A 126 -6.471 12.423 -12.430 1.00 84.95 C +ATOM 907 SG CYS A 126 -7.893 11.482 -13.047 1.00 84.95 S +ATOM 908 N TYR A 127 -5.385 15.342 -11.159 1.00 80.35 N +ATOM 909 CA TYR A 127 -4.249 16.213 -10.832 1.00 80.35 C +ATOM 910 C TYR A 127 -4.625 17.369 -9.903 1.00 80.35 C +ATOM 911 O TYR A 127 -3.808 18.256 -9.659 1.00 80.35 O +ATOM 912 CB TYR A 127 -3.625 16.732 -12.131 1.00 80.35 C +ATOM 913 CG TYR A 127 -3.326 15.637 -13.131 1.00 80.35 C +ATOM 914 CD1 TYR A 127 -2.352 14.668 -12.830 1.00 80.35 C +ATOM 915 CD2 TYR A 127 -4.066 15.552 -14.327 1.00 80.35 C +ATOM 916 CE1 TYR A 127 -2.127 13.607 -13.725 1.00 80.35 C +ATOM 917 CE2 TYR A 127 -3.822 14.502 -15.232 1.00 80.35 C +ATOM 918 CZ TYR A 127 -2.857 13.524 -14.926 1.00 80.35 C +ATOM 919 OH TYR A 127 -2.661 12.473 -15.760 1.00 80.35 O +ATOM 920 N SER A 128 -5.863 17.387 -9.414 1.00 85.29 N +ATOM 921 CA SER A 128 -6.340 18.422 -8.514 1.00 85.29 C +ATOM 922 C SER A 128 -5.983 18.079 -7.074 1.00 85.29 C +ATOM 923 O SER A 128 -6.108 16.944 -6.623 1.00 85.29 O +ATOM 924 CB SER A 128 -7.841 18.615 -8.695 1.00 85.29 C +ATOM 925 OG SER A 128 -8.286 19.682 -7.891 1.00 85.29 O +ATOM 926 N SER A 129 -5.571 19.095 -6.324 1.00 88.70 N +ATOM 927 CA SER A 129 -5.461 19.041 -4.864 1.00 88.70 C +ATOM 928 C SER A 129 -6.797 19.348 -4.173 1.00 88.70 C +ATOM 929 O SER A 129 -6.819 19.612 -2.967 1.00 88.70 O +ATOM 930 CB SER A 129 -4.364 20.001 -4.407 1.00 88.70 C +ATOM 931 OG SER A 129 -4.630 21.294 -4.920 1.00 88.70 O +ATOM 932 N HIS A 130 -7.900 19.341 -4.929 1.00 92.13 N +ATOM 933 CA HIS A 130 -9.241 19.659 -4.463 1.00 92.13 C +ATOM 934 C HIS A 130 -10.179 18.462 -4.627 1.00 92.13 C +ATOM 935 O HIS A 130 -10.199 17.809 -5.674 1.00 92.13 O +ATOM 936 CB HIS A 130 -9.795 20.897 -5.184 1.00 92.13 C +ATOM 937 CG HIS A 130 -8.913 22.114 -5.075 1.00 92.13 C +ATOM 938 ND1 HIS A 130 -9.136 23.187 -4.248 1.00 92.13 N +ATOM 939 CD2 HIS A 130 -7.760 22.374 -5.769 1.00 92.13 C +ATOM 940 CE1 HIS A 130 -8.140 24.069 -4.431 1.00 92.13 C +ATOM 941 NE2 HIS A 130 -7.268 23.614 -5.342 1.00 92.13 N +ATOM 942 N ILE A 131 -10.988 18.208 -3.602 1.00 94.16 N +ATOM 943 CA ILE A 131 -12.119 17.280 -3.668 1.00 94.16 C +ATOM 944 C ILE A 131 -13.388 18.103 -3.476 1.00 94.16 C +ATOM 945 O ILE A 131 -13.616 18.648 -2.396 1.00 94.16 O +ATOM 946 CB ILE A 131 -12.001 16.154 -2.618 1.00 94.16 C +ATOM 947 CG1 ILE A 131 -10.709 15.323 -2.786 1.00 94.16 C +ATOM 948 CG2 ILE A 131 -13.238 15.243 -2.705 1.00 94.16 C +ATOM 949 CD1 ILE A 131 -10.363 14.480 -1.551 1.00 94.16 C +ATOM 950 N THR A 132 -14.217 18.180 -4.510 1.00 94.98 N +ATOM 951 CA THR A 132 -15.519 18.842 -4.415 1.00 94.98 C +ATOM 952 C THR A 132 -16.526 17.844 -3.881 1.00 94.98 C +ATOM 953 O THR A 132 -16.781 16.804 -4.491 1.00 94.98 O +ATOM 954 CB THR A 132 -15.994 19.364 -5.762 1.00 94.98 C +ATOM 955 OG1 THR A 132 -15.022 20.187 -6.352 1.00 94.98 O +ATOM 956 CG2 THR A 132 -17.310 20.139 -5.701 1.00 94.98 C +ATOM 957 N VAL A 133 -17.103 18.174 -2.735 1.00 94.54 N +ATOM 958 CA VAL A 133 -18.161 17.413 -2.080 1.00 94.54 C +ATOM 959 C VAL A 133 -19.478 18.130 -2.333 1.00 94.54 C +ATOM 960 O VAL A 133 -19.550 19.352 -2.205 1.00 94.54 O +ATOM 961 CB VAL A 133 -17.879 17.269 -0.574 1.00 94.54 C +ATOM 962 CG1 VAL A 133 -18.875 16.304 0.077 1.00 94.54 C +ATOM 963 CG2 VAL A 133 -16.462 16.741 -0.311 1.00 94.54 C +ATOM 964 N SER A 134 -20.526 17.390 -2.680 1.00 93.66 N +ATOM 965 CA SER A 134 -21.867 17.930 -2.888 1.00 93.66 C +ATOM 966 C SER A 134 -22.947 17.057 -2.255 1.00 93.66 C +ATOM 967 O SER A 134 -22.811 15.836 -2.138 1.00 93.66 O +ATOM 968 CB SER A 134 -22.134 18.184 -4.372 1.00 93.66 C +ATOM 969 OG SER A 134 -22.283 16.979 -5.084 1.00 93.66 O +ATOM 970 N TRP A 135 -24.023 17.699 -1.811 1.00 89.24 N +ATOM 971 CA TRP A 135 -25.127 17.070 -1.089 1.00 89.24 C +ATOM 972 C TRP A 135 -26.462 17.724 -1.444 1.00 89.24 C +ATOM 973 O TRP A 135 -26.512 18.821 -1.997 1.00 89.24 O +ATOM 974 CB TRP A 135 -24.855 17.148 0.418 1.00 89.24 C +ATOM 975 CG TRP A 135 -24.640 18.519 0.977 1.00 89.24 C +ATOM 976 CD1 TRP A 135 -25.583 19.329 1.512 1.00 89.24 C +ATOM 977 CD2 TRP A 135 -23.377 19.238 1.092 1.00 89.24 C +ATOM 978 NE1 TRP A 135 -24.990 20.498 1.952 1.00 89.24 N +ATOM 979 CE2 TRP A 135 -23.632 20.488 1.724 1.00 89.24 C +ATOM 980 CE3 TRP A 135 -22.040 18.949 0.744 1.00 89.24 C +ATOM 981 CZ2 TRP A 135 -22.610 21.395 2.014 1.00 89.24 C +ATOM 982 CZ3 TRP A 135 -20.999 19.841 1.060 1.00 89.24 C +ATOM 983 CH2 TRP A 135 -21.286 21.053 1.712 1.00 89.24 C +ATOM 984 N GLN A 136 -27.567 17.052 -1.125 1.00 83.48 N +ATOM 985 CA GLN A 136 -28.901 17.625 -1.300 1.00 83.48 C +ATOM 986 C GLN A 136 -29.245 18.557 -0.132 1.00 83.48 C +ATOM 987 O GLN A 136 -28.943 18.267 1.027 1.00 83.48 O +ATOM 988 CB GLN A 136 -29.946 16.521 -1.499 1.00 83.48 C +ATOM 989 CG GLN A 136 -29.715 15.778 -2.825 1.00 83.48 C +ATOM 990 CD GLN A 136 -30.815 14.768 -3.136 1.00 83.48 C +ATOM 991 OE1 GLN A 136 -31.326 14.062 -2.286 1.00 83.48 O +ATOM 992 NE2 GLN A 136 -31.220 14.640 -4.380 1.00 83.48 N +ATOM 993 N LEU A 137 -29.867 19.698 -0.442 1.00 73.64 N +ATOM 994 CA LEU A 137 -30.301 20.652 0.573 1.00 73.64 C +ATOM 995 C LEU A 137 -31.557 20.126 1.270 1.00 73.64 C +ATOM 996 O LEU A 137 -32.621 20.085 0.655 1.00 73.64 O +ATOM 997 CB LEU A 137 -30.568 22.026 -0.070 1.00 73.64 C +ATOM 998 CG LEU A 137 -30.648 23.173 0.953 1.00 73.64 C +ATOM 999 CD1 LEU A 137 -29.283 23.496 1.567 1.00 73.64 C +ATOM 1000 CD2 LEU A 137 -31.155 24.432 0.250 1.00 73.64 C +ATOM 1001 N ASN A 138 -31.439 19.788 2.552 1.00 65.93 N +ATOM 1002 CA ASN A 138 -32.596 19.391 3.357 1.00 65.93 C +ATOM 1003 C ASN A 138 -33.198 20.572 4.128 1.00 65.93 C +ATOM 1004 O ASN A 138 -34.402 20.582 4.350 1.00 65.93 O +ATOM 1005 CB ASN A 138 -32.214 18.201 4.252 1.00 65.93 C +ATOM 1006 CG ASN A 138 -31.989 16.921 3.458 1.00 65.93 C +ATOM 1007 OD1 ASN A 138 -32.260 16.814 2.275 1.00 65.93 O +ATOM 1008 ND2 ASN A 138 -31.501 15.881 4.090 1.00 65.93 N +ATOM 1009 N ASP A 139 -32.398 21.588 4.475 1.00 63.93 N +ATOM 1010 CA ASP A 139 -32.884 22.770 5.189 1.00 63.93 C +ATOM 1011 C ASP A 139 -32.096 24.039 4.836 1.00 63.93 C +ATOM 1012 O ASP A 139 -30.884 24.015 4.630 1.00 63.93 O +ATOM 1013 CB ASP A 139 -32.879 22.515 6.710 1.00 63.93 C +ATOM 1014 CG ASP A 139 -34.293 22.451 7.295 1.00 63.93 C +ATOM 1015 OD1 ASP A 139 -35.155 23.209 6.789 1.00 63.93 O +ATOM 1016 OD2 ASP A 139 -34.469 21.717 8.291 1.00 63.93 O +ATOM 1017 N ARG A 140 -32.794 25.177 4.751 1.00 56.49 N +ATOM 1018 CA ARG A 140 -32.270 26.431 4.168 1.00 56.49 C +ATOM 1019 C ARG A 140 -31.433 27.315 5.109 1.00 56.49 C +ATOM 1020 O ARG A 140 -31.238 28.484 4.792 1.00 56.49 O +ATOM 1021 CB ARG A 140 -33.410 27.202 3.462 1.00 56.49 C +ATOM 1022 CG ARG A 140 -33.623 26.712 2.025 1.00 56.49 C +ATOM 1023 CD ARG A 140 -34.621 27.612 1.290 1.00 56.49 C +ATOM 1024 NE ARG A 140 -34.786 27.197 -0.116 1.00 56.49 N +ATOM 1025 CZ ARG A 140 -35.598 27.745 -1.002 1.00 56.49 C +ATOM 1026 NH1 ARG A 140 -36.347 28.772 -0.707 1.00 56.49 N +ATOM 1027 NH2 ARG A 140 -35.674 27.264 -2.211 1.00 56.49 N +ATOM 1028 N SER A 141 -30.932 26.823 6.246 1.00 57.16 N +ATOM 1029 CA SER A 141 -30.252 27.708 7.217 1.00 57.16 C +ATOM 1030 C SER A 141 -29.142 27.075 8.070 1.00 57.16 C +ATOM 1031 O SER A 141 -28.795 27.627 9.117 1.00 57.16 O +ATOM 1032 CB SER A 141 -31.305 28.399 8.095 1.00 57.16 C +ATOM 1033 OG SER A 141 -30.728 29.494 8.775 1.00 57.16 O +ATOM 1034 N SER A 142 -28.556 25.954 7.650 1.00 70.83 N +ATOM 1035 CA SER A 142 -27.480 25.301 8.410 1.00 70.83 C +ATOM 1036 C SER A 142 -26.108 25.534 7.775 1.00 70.83 C +ATOM 1037 O SER A 142 -25.957 25.493 6.556 1.00 70.83 O +ATOM 1038 CB SER A 142 -27.782 23.814 8.593 1.00 70.83 C +ATOM 1039 OG SER A 142 -28.996 23.671 9.313 1.00 70.83 O +ATOM 1040 N LEU A 143 -25.098 25.780 8.614 1.00 85.06 N +ATOM 1041 CA LEU A 143 -23.698 25.703 8.206 1.00 85.06 C +ATOM 1042 C LEU A 143 -23.318 24.225 8.130 1.00 85.06 C +ATOM 1043 O LEU A 143 -23.339 23.533 9.145 1.00 85.06 O +ATOM 1044 CB LEU A 143 -22.821 26.459 9.223 1.00 85.06 C +ATOM 1045 CG LEU A 143 -21.318 26.447 8.880 1.00 85.06 C +ATOM 1046 CD1 LEU A 143 -21.028 27.307 7.646 1.00 85.06 C +ATOM 1047 CD2 LEU A 143 -20.512 26.999 10.057 1.00 85.06 C +ATOM 1048 N TYR A 144 -22.960 23.753 6.943 1.00 87.21 N +ATOM 1049 CA TYR A 144 -22.463 22.400 6.750 1.00 87.21 C +ATOM 1050 C TYR A 144 -20.940 22.376 6.832 1.00 87.21 C +ATOM 1051 O TYR A 144 -20.259 23.283 6.348 1.00 87.21 O +ATOM 1052 CB TYR A 144 -22.967 21.839 5.423 1.00 87.21 C +ATOM 1053 CG TYR A 144 -24.473 21.683 5.360 1.00 87.21 C +ATOM 1054 CD1 TYR A 144 -25.084 20.580 5.986 1.00 87.21 C +ATOM 1055 CD2 TYR A 144 -25.261 22.645 4.699 1.00 87.21 C +ATOM 1056 CE1 TYR A 144 -26.484 20.436 5.954 1.00 87.21 C +ATOM 1057 CE2 TYR A 144 -26.662 22.502 4.661 1.00 87.21 C +ATOM 1058 CZ TYR A 144 -27.276 21.398 5.288 1.00 87.21 C +ATOM 1059 OH TYR A 144 -28.628 21.260 5.253 1.00 87.21 O +ATOM 1060 N VAL A 145 -20.416 21.313 7.427 1.00 90.33 N +ATOM 1061 CA VAL A 145 -18.992 21.006 7.511 1.00 90.33 C +ATOM 1062 C VAL A 145 -18.766 19.706 6.756 1.00 90.33 C +ATOM 1063 O VAL A 145 -19.299 18.666 7.135 1.00 90.33 O +ATOM 1064 CB VAL A 145 -18.538 20.906 8.980 1.00 90.33 C +ATOM 1065 CG1 VAL A 145 -17.036 20.606 9.075 1.00 90.33 C +ATOM 1066 CG2 VAL A 145 -18.841 22.209 9.737 1.00 90.33 C +ATOM 1067 N ALA A 146 -17.995 19.761 5.674 1.00 92.07 N +ATOM 1068 CA ALA A 146 -17.489 18.569 5.012 1.00 92.07 C +ATOM 1069 C ALA A 146 -16.127 18.225 5.617 1.00 92.07 C +ATOM 1070 O ALA A 146 -15.272 19.102 5.767 1.00 92.07 O +ATOM 1071 CB ALA A 146 -17.422 18.796 3.499 1.00 92.07 C +ATOM 1072 N SER A 147 -15.911 16.956 5.952 1.00 92.17 N +ATOM 1073 CA SER A 147 -14.620 16.467 6.426 1.00 92.17 C +ATOM 1074 C SER A 147 -14.221 15.191 5.708 1.00 92.17 C +ATOM 1075 O SER A 147 -15.050 14.294 5.566 1.00 92.17 O +ATOM 1076 CB SER A 147 -14.604 16.267 7.943 1.00 92.17 C +ATOM 1077 OG SER A 147 -15.507 15.273 8.376 1.00 92.17 O +ATOM 1078 N ALA A 148 -12.955 15.105 5.311 1.00 93.27 N +ATOM 1079 CA ALA A 148 -12.354 13.899 4.760 1.00 93.27 C +ATOM 1080 C ALA A 148 -11.222 13.416 5.660 1.00 93.27 C +ATOM 1081 O ALA A 148 -10.319 14.194 5.968 1.00 93.27 O +ATOM 1082 CB ALA A 148 -11.857 14.167 3.343 1.00 93.27 C +ATOM 1083 N GLU A 149 -11.268 12.148 6.051 1.00 92.92 N +ATOM 1084 CA GLU A 149 -10.188 11.468 6.762 1.00 92.92 C +ATOM 1085 C GLU A 149 -9.457 10.528 5.806 1.00 92.92 C +ATOM 1086 O GLU A 149 -10.078 9.694 5.148 1.00 92.92 O +ATOM 1087 CB GLU A 149 -10.741 10.741 7.991 1.00 92.92 C +ATOM 1088 CG GLU A 149 -9.599 10.103 8.799 1.00 92.92 C +ATOM 1089 CD GLU A 149 -10.046 9.518 10.143 1.00 92.92 C +ATOM 1090 OE1 GLU A 149 -9.199 8.827 10.760 1.00 92.92 O +ATOM 1091 OE2 GLU A 149 -11.182 9.837 10.566 1.00 92.92 O +ATOM 1092 N GLY A 150 -8.146 10.714 5.676 1.00 92.11 N +ATOM 1093 CA GLY A 150 -7.283 9.867 4.869 1.00 92.11 C +ATOM 1094 C GLY A 150 -6.857 8.609 5.620 1.00 92.11 C +ATOM 1095 O GLY A 150 -6.796 8.582 6.845 1.00 92.11 O +ATOM 1096 N ASN A 151 -6.453 7.582 4.880 1.00 89.70 N +ATOM 1097 CA ASN A 151 -5.828 6.374 5.427 1.00 89.70 C +ATOM 1098 C ASN A 151 -4.518 6.621 6.209 1.00 89.70 C +ATOM 1099 O ASN A 151 -4.069 5.733 6.927 1.00 89.70 O +ATOM 1100 CB ASN A 151 -5.603 5.371 4.280 1.00 89.70 C +ATOM 1101 CG ASN A 151 -4.677 5.871 3.177 1.00 89.70 C +ATOM 1102 OD1 ASN A 151 -4.679 7.018 2.772 1.00 89.70 O +ATOM 1103 ND2 ASN A 151 -3.896 5.009 2.574 1.00 89.70 N +ATOM 1104 N ASP A 152 -3.900 7.797 6.073 1.00 89.34 N +ATOM 1105 CA ASP A 152 -2.756 8.258 6.873 1.00 89.34 C +ATOM 1106 C ASP A 152 -3.170 9.057 8.127 1.00 89.34 C +ATOM 1107 O ASP A 152 -2.312 9.628 8.801 1.00 89.34 O +ATOM 1108 CB ASP A 152 -1.801 9.080 5.983 1.00 89.34 C +ATOM 1109 CG ASP A 152 -2.340 10.472 5.620 1.00 89.34 C +ATOM 1110 OD1 ASP A 152 -3.574 10.682 5.719 1.00 89.34 O +ATOM 1111 OD2 ASP A 152 -1.539 11.337 5.195 1.00 89.34 O +ATOM 1112 N HIS A 153 -4.473 9.120 8.423 1.00 87.28 N +ATOM 1113 CA HIS A 153 -5.099 9.946 9.461 1.00 87.28 C +ATOM 1114 C HIS A 153 -5.012 11.463 9.228 1.00 87.28 C +ATOM 1115 O HIS A 153 -5.277 12.254 10.138 1.00 87.28 O +ATOM 1116 CB HIS A 153 -4.616 9.527 10.857 1.00 87.28 C +ATOM 1117 CG HIS A 153 -4.703 8.045 11.090 1.00 87.28 C +ATOM 1118 ND1 HIS A 153 -5.867 7.326 11.216 1.00 87.28 N +ATOM 1119 CD2 HIS A 153 -3.660 7.163 11.176 1.00 87.28 C +ATOM 1120 CE1 HIS A 153 -5.528 6.039 11.393 1.00 87.28 C +ATOM 1121 NE2 HIS A 153 -4.191 5.886 11.393 1.00 87.28 N +ATOM 1122 N SER A 154 -4.660 11.908 8.018 1.00 91.44 N +ATOM 1123 CA SER A 154 -4.793 13.315 7.641 1.00 91.44 C +ATOM 1124 C SER A 154 -6.264 13.702 7.537 1.00 91.44 C +ATOM 1125 O SER A 154 -7.104 12.929 7.083 1.00 91.44 O +ATOM 1126 CB SER A 154 -4.036 13.661 6.354 1.00 91.44 C +ATOM 1127 OG SER A 154 -4.559 13.010 5.217 1.00 91.44 O +ATOM 1128 N ILE A 155 -6.582 14.924 7.958 1.00 91.47 N +ATOM 1129 CA ILE A 155 -7.952 15.431 7.961 1.00 91.47 C +ATOM 1130 C ILE A 155 -8.014 16.694 7.112 1.00 91.47 C +ATOM 1131 O ILE A 155 -7.302 17.663 7.379 1.00 91.47 O +ATOM 1132 CB ILE A 155 -8.453 15.653 9.401 1.00 91.47 C +ATOM 1133 CG1 ILE A 155 -8.417 14.332 10.208 1.00 91.47 C +ATOM 1134 CG2 ILE A 155 -9.878 16.236 9.403 1.00 91.47 C +ATOM 1135 CD1 ILE A 155 -8.871 14.465 11.666 1.00 91.47 C +ATOM 1136 N LEU A 156 -8.914 16.701 6.133 1.00 93.61 N +ATOM 1137 CA LEU A 156 -9.310 17.890 5.384 1.00 93.61 C +ATOM 1138 C LEU A 156 -10.689 18.335 5.855 1.00 93.61 C +ATOM 1139 O LEU A 156 -11.538 17.500 6.169 1.00 93.61 O +ATOM 1140 CB LEU A 156 -9.299 17.611 3.874 1.00 93.61 C +ATOM 1141 CG LEU A 156 -7.988 17.009 3.343 1.00 93.61 C +ATOM 1142 CD1 LEU A 156 -8.120 16.779 1.842 1.00 93.61 C +ATOM 1143 CD2 LEU A 156 -6.780 17.911 3.601 1.00 93.61 C +ATOM 1144 N MET A 157 -10.920 19.643 5.912 1.00 93.53 N +ATOM 1145 CA MET A 157 -12.214 20.201 6.298 1.00 93.53 C +ATOM 1146 C MET A 157 -12.533 21.426 5.460 1.00 93.53 C +ATOM 1147 O MET A 157 -11.643 22.212 5.134 1.00 93.53 O +ATOM 1148 CB MET A 157 -12.257 20.569 7.789 1.00 93.53 C +ATOM 1149 CG MET A 157 -12.020 19.357 8.696 1.00 93.53 C +ATOM 1150 SD MET A 157 -12.177 19.651 10.480 1.00 93.53 S +ATOM 1151 CE MET A 157 -10.885 20.904 10.716 1.00 93.53 C +ATOM 1152 N CYS A 158 -13.807 21.604 5.149 1.00 93.41 N +ATOM 1153 CA CYS A 158 -14.303 22.822 4.540 1.00 93.41 C +ATOM 1154 C CYS A 158 -15.733 23.087 5.023 1.00 93.41 C +ATOM 1155 O CYS A 158 -16.476 22.158 5.348 1.00 93.41 O +ATOM 1156 CB CYS A 158 -14.143 22.716 3.017 1.00 93.41 C +ATOM 1157 SG CYS A 158 -15.352 21.679 2.183 1.00 93.41 S +ATOM 1158 N ASN A 159 -16.113 24.362 5.083 1.00 91.84 N +ATOM 1159 CA ASN A 159 -17.421 24.779 5.575 1.00 91.84 C +ATOM 1160 C ASN A 159 -18.182 25.487 4.457 1.00 91.84 C +ATOM 1161 O ASN A 159 -17.602 26.291 3.728 1.00 91.84 O +ATOM 1162 CB ASN A 159 -17.265 25.686 6.805 1.00 91.84 C +ATOM 1163 CG ASN A 159 -16.577 25.040 7.993 1.00 91.84 C +ATOM 1164 OD1 ASN A 159 -16.265 23.867 8.042 1.00 91.84 O +ATOM 1165 ND2 ASN A 159 -16.300 25.806 9.020 1.00 91.84 N +ATOM 1166 N SER A 160 -19.481 25.227 4.348 1.00 89.68 N +ATOM 1167 CA SER A 160 -20.331 25.855 3.339 1.00 89.68 C +ATOM 1168 C SER A 160 -21.763 25.995 3.837 1.00 89.68 C +ATOM 1169 O SER A 160 -22.287 25.131 4.534 1.00 89.68 O +ATOM 1170 CB SER A 160 -20.281 25.032 2.051 1.00 89.68 C +ATOM 1171 OG SER A 160 -20.925 25.693 0.982 1.00 89.68 O +ATOM 1172 N THR A 161 -22.411 27.098 3.475 1.00 86.55 N +ATOM 1173 CA THR A 161 -23.869 27.275 3.606 1.00 86.55 C +ATOM 1174 C THR A 161 -24.612 26.863 2.332 1.00 86.55 C +ATOM 1175 O THR A 161 -25.840 26.872 2.298 1.00 86.55 O +ATOM 1176 CB THR A 161 -24.204 28.732 3.940 1.00 86.55 C +ATOM 1177 OG1 THR A 161 -23.622 29.593 2.983 1.00 86.55 O +ATOM 1178 CG2 THR A 161 -23.660 29.145 5.308 1.00 86.55 C +ATOM 1179 N SER A 162 -23.868 26.526 1.275 1.00 87.03 N +ATOM 1180 CA SER A 162 -24.387 26.014 0.009 1.00 87.03 C +ATOM 1181 C SER A 162 -24.506 24.482 0.047 1.00 87.03 C +ATOM 1182 O SER A 162 -24.277 23.848 1.074 1.00 87.03 O +ATOM 1183 CB SER A 162 -23.467 26.492 -1.123 1.00 87.03 C +ATOM 1184 OG SER A 162 -24.083 26.303 -2.382 1.00 87.03 O +ATOM 1185 N THR A 163 -24.849 23.875 -1.087 1.00 89.21 N +ATOM 1186 CA THR A 163 -24.938 22.418 -1.300 1.00 89.21 C +ATOM 1187 C THR A 163 -23.628 21.776 -1.750 1.00 89.21 C +ATOM 1188 O THR A 163 -23.617 20.617 -2.164 1.00 89.21 O +ATOM 1189 CB THR A 163 -26.025 22.110 -2.335 1.00 89.21 C +ATOM 1190 OG1 THR A 163 -25.837 22.880 -3.503 1.00 89.21 O +ATOM 1191 CG2 THR A 163 -27.404 22.438 -1.782 1.00 89.21 C +ATOM 1192 N SER A 164 -22.531 22.531 -1.749 1.00 92.97 N +ATOM 1193 CA SER A 164 -21.218 22.047 -2.161 1.00 92.97 C +ATOM 1194 C SER A 164 -20.089 22.731 -1.405 1.00 92.97 C +ATOM 1195 O SER A 164 -20.238 23.858 -0.915 1.00 92.97 O +ATOM 1196 CB SER A 164 -21.016 22.206 -3.672 1.00 92.97 C +ATOM 1197 OG SER A 164 -20.987 23.574 -4.044 1.00 92.97 O +ATOM 1198 N CYS A 165 -18.955 22.040 -1.313 1.00 93.31 N +ATOM 1199 CA CYS A 165 -17.763 22.519 -0.636 1.00 93.31 C +ATOM 1200 C CYS A 165 -16.504 21.837 -1.177 1.00 93.31 C +ATOM 1201 O CYS A 165 -16.509 20.630 -1.415 1.00 93.31 O +ATOM 1202 CB CYS A 165 -17.965 22.248 0.851 1.00 93.31 C +ATOM 1203 SG CYS A 165 -16.806 23.048 1.952 1.00 93.31 S +ATOM 1204 N ASP A 166 -15.432 22.609 -1.345 1.00 94.82 N +ATOM 1205 CA ASP A 166 -14.152 22.108 -1.839 1.00 94.82 C +ATOM 1206 C ASP A 166 -13.191 21.857 -0.677 1.00 94.82 C +ATOM 1207 O ASP A 166 -12.765 22.777 0.026 1.00 94.82 O +ATOM 1208 CB ASP A 166 -13.549 23.075 -2.866 1.00 94.82 C +ATOM 1209 CG ASP A 166 -14.393 23.182 -4.137 1.00 94.82 C +ATOM 1210 OD1 ASP A 166 -14.913 22.136 -4.588 1.00 94.82 O +ATOM 1211 OD2 ASP A 166 -14.508 24.314 -4.651 1.00 94.82 O +ATOM 1212 N LEU A 167 -12.819 20.595 -0.489 1.00 95.09 N +ATOM 1213 CA LEU A 167 -11.753 20.193 0.416 1.00 95.09 C +ATOM 1214 C LEU A 167 -10.412 20.453 -0.264 1.00 95.09 C +ATOM 1215 O LEU A 167 -10.120 19.870 -1.306 1.00 95.09 O +ATOM 1216 CB LEU A 167 -11.907 18.710 0.754 1.00 95.09 C +ATOM 1217 CG LEU A 167 -13.182 18.362 1.536 1.00 95.09 C +ATOM 1218 CD1 LEU A 167 -13.343 16.849 1.513 1.00 95.09 C +ATOM 1219 CD2 LEU A 167 -13.080 18.813 2.991 1.00 95.09 C +ATOM 1220 N ILE A 168 -9.599 21.321 0.330 1.00 94.20 N +ATOM 1221 CA ILE A 168 -8.319 21.764 -0.230 1.00 94.20 C +ATOM 1222 C ILE A 168 -7.174 21.006 0.442 1.00 94.20 C +ATOM 1223 O ILE A 168 -7.163 20.857 1.661 1.00 94.20 O +ATOM 1224 CB ILE A 168 -8.153 23.295 -0.075 1.00 94.20 C +ATOM 1225 CG1 ILE A 168 -9.381 24.055 -0.633 1.00 94.20 C +ATOM 1226 CG2 ILE A 168 -6.853 23.760 -0.765 1.00 94.20 C +ATOM 1227 CD1 ILE A 168 -9.341 25.575 -0.439 1.00 94.20 C +ATOM 1228 N GLY A 169 -6.179 20.587 -0.342 1.00 92.75 N +ATOM 1229 CA GLY A 169 -4.979 19.911 0.161 1.00 92.75 C +ATOM 1230 C GLY A 169 -5.035 18.388 0.055 1.00 92.75 C +ATOM 1231 O GLY A 169 -4.292 17.703 0.760 1.00 92.75 O +ATOM 1232 N ALA A 170 -5.892 17.860 -0.823 1.00 92.72 N +ATOM 1233 CA ALA A 170 -5.925 16.442 -1.149 1.00 92.72 C +ATOM 1234 C ALA A 170 -4.571 15.986 -1.704 1.00 92.72 C +ATOM 1235 O ALA A 170 -3.981 16.635 -2.572 1.00 92.72 O +ATOM 1236 CB ALA A 170 -7.077 16.171 -2.119 1.00 92.72 C +ATOM 1237 N ARG A 171 -4.068 14.869 -1.174 1.00 91.52 N +ATOM 1238 CA ARG A 171 -2.792 14.273 -1.585 1.00 91.52 C +ATOM 1239 C ARG A 171 -3.040 13.126 -2.561 1.00 91.52 C +ATOM 1240 O ARG A 171 -4.089 12.482 -2.525 1.00 91.52 O +ATOM 1241 CB ARG A 171 -1.987 13.830 -0.353 1.00 91.52 C +ATOM 1242 CG ARG A 171 -1.692 14.989 0.609 1.00 91.52 C +ATOM 1243 CD ARG A 171 -0.927 14.483 1.833 1.00 91.52 C +ATOM 1244 NE ARG A 171 -0.649 15.595 2.761 1.00 91.52 N +ATOM 1245 CZ ARG A 171 0.421 15.737 3.520 1.00 91.52 C +ATOM 1246 NH1 ARG A 171 1.378 14.852 3.536 1.00 91.52 N +ATOM 1247 NH2 ARG A 171 0.544 16.781 4.291 1.00 91.52 N +ATOM 1248 N CYS A 172 -2.066 12.853 -3.423 1.00 92.05 N +ATOM 1249 CA CYS A 172 -2.077 11.647 -4.248 1.00 92.05 C +ATOM 1250 C CYS A 172 -1.940 10.393 -3.373 1.00 92.05 C +ATOM 1251 O CYS A 172 -1.418 10.461 -2.261 1.00 92.05 O +ATOM 1252 CB CYS A 172 -0.959 11.736 -5.296 1.00 92.05 C +ATOM 1253 SG CYS A 172 0.737 11.852 -4.642 1.00 92.05 S +ATOM 1254 N GLY A 173 -2.360 9.238 -3.884 1.00 91.78 N +ATOM 1255 CA GLY A 173 -2.153 7.963 -3.198 1.00 91.78 C +ATOM 1256 C GLY A 173 -3.049 7.739 -1.976 1.00 91.78 C +ATOM 1257 O GLY A 173 -2.762 6.845 -1.183 1.00 91.78 O +ATOM 1258 N MET A 174 -4.096 8.546 -1.800 1.00 91.89 N +ATOM 1259 CA MET A 174 -4.916 8.563 -0.591 1.00 91.89 C +ATOM 1260 C MET A 174 -6.243 7.849 -0.801 1.00 91.89 C +ATOM 1261 O MET A 174 -6.878 7.996 -1.847 1.00 91.89 O +ATOM 1262 CB MET A 174 -5.170 10.004 -0.139 1.00 91.89 C +ATOM 1263 CG MET A 174 -3.889 10.730 0.277 1.00 91.89 C +ATOM 1264 SD MET A 174 -2.868 9.918 1.529 1.00 91.89 S +ATOM 1265 CE MET A 174 -4.026 9.985 2.912 1.00 91.89 C +ATOM 1266 N HIS A 175 -6.682 7.134 0.232 1.00 91.96 N +ATOM 1267 CA HIS A 175 -8.063 6.683 0.368 1.00 91.96 C +ATOM 1268 C HIS A 175 -8.742 7.571 1.408 1.00 91.96 C +ATOM 1269 O HIS A 175 -8.279 7.614 2.547 1.00 91.96 O +ATOM 1270 CB HIS A 175 -8.091 5.205 0.768 1.00 91.96 C +ATOM 1271 CG HIS A 175 -9.424 4.560 0.500 1.00 91.96 C +ATOM 1272 ND1 HIS A 175 -10.564 4.603 1.276 1.00 91.96 N +ATOM 1273 CD2 HIS A 175 -9.711 3.780 -0.586 1.00 91.96 C +ATOM 1274 CE1 HIS A 175 -11.494 3.847 0.671 1.00 91.96 C +ATOM 1275 NE2 HIS A 175 -11.026 3.335 -0.478 1.00 91.96 N +ATOM 1276 N TYR A 176 -9.780 8.302 1.007 1.00 91.90 N +ATOM 1277 CA TYR A 176 -10.499 9.235 1.868 1.00 91.90 C +ATOM 1278 C TYR A 176 -11.899 8.721 2.187 1.00 91.90 C +ATOM 1279 O TYR A 176 -12.658 8.385 1.274 1.00 91.90 O +ATOM 1280 CB TYR A 176 -10.582 10.630 1.228 1.00 91.90 C +ATOM 1281 CG TYR A 176 -9.297 11.436 1.278 1.00 91.90 C +ATOM 1282 CD1 TYR A 176 -8.822 11.917 2.512 1.00 91.90 C +ATOM 1283 CD2 TYR A 176 -8.591 11.731 0.098 1.00 91.90 C +ATOM 1284 CE1 TYR A 176 -7.625 12.655 2.582 1.00 91.90 C +ATOM 1285 CE2 TYR A 176 -7.407 12.494 0.155 1.00 91.90 C +ATOM 1286 CZ TYR A 176 -6.913 12.944 1.398 1.00 91.90 C +ATOM 1287 OH TYR A 176 -5.752 13.650 1.459 1.00 91.90 O +ATOM 1288 N THR A 177 -12.255 8.783 3.467 1.00 92.26 N +ATOM 1289 CA THR A 177 -13.634 8.677 3.943 1.00 92.26 C +ATOM 1290 C THR A 177 -14.186 10.076 4.165 1.00 92.26 C +ATOM 1291 O THR A 177 -13.655 10.841 4.972 1.00 92.26 O +ATOM 1292 CB THR A 177 -13.723 7.893 5.254 1.00 92.26 C +ATOM 1293 OG1 THR A 177 -13.159 6.616 5.118 1.00 92.26 O +ATOM 1294 CG2 THR A 177 -15.181 7.749 5.697 1.00 92.26 C +ATOM 1295 N ILE A 178 -15.247 10.427 3.445 1.00 92.35 N +ATOM 1296 CA ILE A 178 -15.835 11.767 3.450 1.00 92.35 C +ATOM 1297 C ILE A 178 -17.199 11.729 4.128 1.00 92.35 C +ATOM 1298 O ILE A 178 -18.039 10.892 3.804 1.00 92.35 O +ATOM 1299 CB ILE A 178 -15.913 12.350 2.023 1.00 92.35 C +ATOM 1300 CG1 ILE A 178 -14.535 12.252 1.329 1.00 92.35 C +ATOM 1301 CG2 ILE A 178 -16.416 13.809 2.065 1.00 92.35 C +ATOM 1302 CD1 ILE A 178 -14.496 12.801 -0.094 1.00 92.35 C +ATOM 1303 N ILE A 179 -17.443 12.681 5.023 1.00 90.26 N +ATOM 1304 CA ILE A 179 -18.761 12.938 5.608 1.00 90.26 C +ATOM 1305 C ILE A 179 -19.103 14.421 5.513 1.00 90.26 C +ATOM 1306 O ILE A 179 -18.222 15.282 5.490 1.00 90.26 O +ATOM 1307 CB ILE A 179 -18.869 12.434 7.066 1.00 90.26 C +ATOM 1308 CG1 ILE A 179 -17.843 13.100 8.006 1.00 90.26 C +ATOM 1309 CG2 ILE A 179 -18.772 10.902 7.106 1.00 90.26 C +ATOM 1310 CD1 ILE A 179 -18.134 12.870 9.493 1.00 90.26 C +ATOM 1311 N VAL A 180 -20.399 14.714 5.502 1.00 89.75 N +ATOM 1312 CA VAL A 180 -20.930 16.065 5.693 1.00 89.75 C +ATOM 1313 C VAL A 180 -21.779 16.068 6.955 1.00 89.75 C +ATOM 1314 O VAL A 180 -22.612 15.182 7.137 1.00 89.75 O +ATOM 1315 CB VAL A 180 -21.718 16.531 4.458 1.00 89.75 C +ATOM 1316 CG1 VAL A 180 -22.342 17.917 4.666 1.00 89.75 C +ATOM 1317 CG2 VAL A 180 -20.799 16.614 3.232 1.00 89.75 C +ATOM 1318 N SER A 181 -21.588 17.058 7.821 1.00 87.20 N +ATOM 1319 CA SER A 181 -22.384 17.275 9.031 1.00 87.20 C +ATOM 1320 C SER A 181 -22.980 18.681 9.049 1.00 87.20 C +ATOM 1321 O SER A 181 -22.356 19.639 8.603 1.00 87.20 O +ATOM 1322 CB SER A 181 -21.552 16.986 10.290 1.00 87.20 C +ATOM 1323 OG SER A 181 -20.371 17.763 10.331 1.00 87.20 O +ATOM 1324 N ALA A 182 -24.192 18.833 9.589 1.00 81.02 N +ATOM 1325 CA ALA A 182 -24.825 20.146 9.798 1.00 81.02 C +ATOM 1326 C ALA A 182 -24.312 20.882 11.061 1.00 81.02 C +ATOM 1327 O ALA A 182 -24.807 21.949 11.416 1.00 81.02 O +ATOM 1328 CB ALA A 182 -26.345 19.945 9.826 1.00 81.02 C +ATOM 1329 N SER A 183 -23.354 20.279 11.770 1.00 73.04 N +ATOM 1330 CA SER A 183 -22.703 20.773 12.986 1.00 73.04 C +ATOM 1331 C SER A 183 -21.190 20.598 12.848 1.00 73.04 C +ATOM 1332 O SER A 183 -20.736 19.716 12.118 1.00 73.04 O +ATOM 1333 CB SER A 183 -23.224 19.987 14.197 1.00 73.04 C +ATOM 1334 OG SER A 183 -22.542 20.357 15.382 1.00 73.04 O +ATOM 1335 N SER A 184 -20.399 21.393 13.572 1.00 67.24 N +ATOM 1336 CA SER A 184 -18.947 21.191 13.683 1.00 67.24 C +ATOM 1337 C SER A 184 -18.571 19.896 14.412 1.00 67.24 C +ATOM 1338 O SER A 184 -17.427 19.452 14.319 1.00 67.24 O +ATOM 1339 CB SER A 184 -18.306 22.383 14.398 1.00 67.24 C +ATOM 1340 OG SER A 184 -18.935 22.612 15.647 1.00 67.24 O +ATOM 1341 N ASP A 185 -19.521 19.281 15.121 1.00 68.66 N +ATOM 1342 CA ASP A 185 -19.337 17.976 15.745 1.00 68.66 C +ATOM 1343 C ASP A 185 -19.498 16.844 14.715 1.00 68.66 C +ATOM 1344 O ASP A 185 -20.609 16.504 14.286 1.00 68.66 O +ATOM 1345 CB ASP A 185 -20.282 17.827 16.942 1.00 68.66 C +ATOM 1346 CG ASP A 185 -20.043 16.524 17.714 1.00 68.66 C +ATOM 1347 OD1 ASP A 185 -19.110 15.771 17.343 1.00 68.66 O +ATOM 1348 OD2 ASP A 185 -20.827 16.284 18.653 1.00 68.66 O +ATOM 1349 N LYS A 186 -18.361 16.246 14.344 1.00 66.46 N +ATOM 1350 CA LYS A 186 -18.256 15.142 13.378 1.00 66.46 C +ATOM 1351 C LYS A 186 -18.970 13.870 13.839 1.00 66.46 C +ATOM 1352 O LYS A 186 -19.402 13.086 13.000 1.00 66.46 O +ATOM 1353 CB LYS A 186 -16.781 14.811 13.124 1.00 66.46 C +ATOM 1354 CG LYS A 186 -15.978 15.990 12.562 1.00 66.46 C +ATOM 1355 CD LYS A 186 -14.542 15.534 12.304 1.00 66.46 C +ATOM 1356 CE LYS A 186 -13.715 16.708 11.789 1.00 66.46 C +ATOM 1357 NZ LYS A 186 -12.321 16.282 11.553 1.00 66.46 N +ATOM 1358 N CYS A 187 -19.124 13.681 15.151 1.00 69.95 N +ATOM 1359 CA CYS A 187 -19.844 12.543 15.719 1.00 69.95 C +ATOM 1360 C CYS A 187 -21.347 12.800 15.888 1.00 69.95 C +ATOM 1361 O CYS A 187 -22.060 11.930 16.393 1.00 69.95 O +ATOM 1362 CB CYS A 187 -19.229 12.146 17.066 1.00 69.95 C +ATOM 1363 SG CYS A 187 -17.541 11.493 17.096 1.00 69.95 S +ATOM 1364 N SER A 188 -21.850 13.972 15.487 1.00 70.41 N +ATOM 1365 CA SER A 188 -23.271 14.281 15.622 1.00 70.41 C +ATOM 1366 C SER A 188 -24.143 13.336 14.787 1.00 70.41 C +ATOM 1367 O SER A 188 -23.752 12.831 13.733 1.00 70.41 O +ATOM 1368 CB SER A 188 -23.561 15.754 15.314 1.00 70.41 C +ATOM 1369 OG SER A 188 -23.326 16.079 13.960 1.00 70.41 O +ATOM 1370 N SER A 189 -25.378 13.113 15.237 1.00 66.77 N +ATOM 1371 CA SER A 189 -26.383 12.358 14.473 1.00 66.77 C +ATOM 1372 C SER A 189 -26.819 13.078 13.187 1.00 66.77 C +ATOM 1373 O SER A 189 -27.425 12.470 12.302 1.00 66.77 O +ATOM 1374 CB SER A 189 -27.600 12.091 15.361 1.00 66.77 C +ATOM 1375 OG SER A 189 -28.073 13.306 15.919 1.00 66.77 O +ATOM 1376 N LEU A 190 -26.497 14.368 13.046 1.00 74.68 N +ATOM 1377 CA LEU A 190 -26.856 15.225 11.914 1.00 74.68 C +ATOM 1378 C LEU A 190 -25.822 15.163 10.779 1.00 74.68 C +ATOM 1379 O LEU A 190 -25.376 16.198 10.276 1.00 74.68 O +ATOM 1380 CB LEU A 190 -27.111 16.659 12.406 1.00 74.68 C +ATOM 1381 CG LEU A 190 -28.288 16.817 13.380 1.00 74.68 C +ATOM 1382 CD1 LEU A 190 -28.331 18.270 13.852 1.00 74.68 C +ATOM 1383 CD2 LEU A 190 -29.633 16.477 12.734 1.00 74.68 C +ATOM 1384 N ARG A 191 -25.437 13.948 10.383 1.00 82.69 N +ATOM 1385 CA ARG A 191 -24.436 13.698 9.338 1.00 82.69 C +ATOM 1386 C ARG A 191 -24.944 12.802 8.214 1.00 82.69 C +ATOM 1387 O ARG A 191 -25.976 12.138 8.351 1.00 82.69 O +ATOM 1388 CB ARG A 191 -23.139 13.170 9.968 1.00 82.69 C +ATOM 1389 CG ARG A 191 -23.309 11.754 10.521 1.00 82.69 C +ATOM 1390 CD ARG A 191 -22.036 11.314 11.232 1.00 82.69 C +ATOM 1391 NE ARG A 191 -22.269 10.005 11.841 1.00 82.69 N +ATOM 1392 CZ ARG A 191 -21.916 8.837 11.355 1.00 82.69 C +ATOM 1393 NH1 ARG A 191 -21.257 8.684 10.242 1.00 82.69 N +ATOM 1394 NH2 ARG A 191 -22.229 7.775 12.032 1.00 82.69 N +ATOM 1395 N SER A 192 -24.208 12.809 7.108 1.00 86.92 N +ATOM 1396 CA SER A 192 -24.403 11.911 5.974 1.00 86.92 C +ATOM 1397 C SER A 192 -23.793 10.531 6.227 1.00 86.92 C +ATOM 1398 O SER A 192 -22.908 10.393 7.078 1.00 86.92 O +ATOM 1399 CB SER A 192 -23.786 12.524 4.714 1.00 86.92 C +ATOM 1400 OG SER A 192 -22.367 12.541 4.772 1.00 86.92 O +ATOM 1401 N PRO A 193 -24.195 9.512 5.448 1.00 84.85 N +ATOM 1402 CA PRO A 193 -23.412 8.290 5.325 1.00 84.85 C +ATOM 1403 C PRO A 193 -21.978 8.610 4.871 1.00 84.85 C +ATOM 1404 O PRO A 193 -21.794 9.581 4.123 1.00 84.85 O +ATOM 1405 CB PRO A 193 -24.161 7.413 4.316 1.00 84.85 C +ATOM 1406 CG PRO A 193 -25.593 7.950 4.360 1.00 84.85 C +ATOM 1407 CD PRO A 193 -25.396 9.438 4.632 1.00 84.85 C +ATOM 1408 N PRO A 194 -20.977 7.827 5.310 1.00 88.88 N +ATOM 1409 CA PRO A 194 -19.612 7.958 4.819 1.00 88.88 C +ATOM 1410 C PRO A 194 -19.552 7.643 3.324 1.00 88.88 C +ATOM 1411 O PRO A 194 -20.191 6.703 2.844 1.00 88.88 O +ATOM 1412 CB PRO A 194 -18.769 6.989 5.651 1.00 88.88 C +ATOM 1413 CG PRO A 194 -19.777 5.906 6.019 1.00 88.88 C +ATOM 1414 CD PRO A 194 -21.074 6.690 6.211 1.00 88.88 C +ATOM 1415 N PHE A 195 -18.787 8.445 2.593 1.00 90.78 N +ATOM 1416 CA PHE A 195 -18.505 8.259 1.177 1.00 90.78 C +ATOM 1417 C PHE A 195 -17.018 7.974 0.989 1.00 90.78 C +ATOM 1418 O PHE A 195 -16.174 8.800 1.333 1.00 90.78 O +ATOM 1419 CB PHE A 195 -18.958 9.495 0.396 1.00 90.78 C +ATOM 1420 CG PHE A 195 -18.832 9.346 -1.106 1.00 90.78 C +ATOM 1421 CD1 PHE A 195 -17.620 9.653 -1.755 1.00 90.78 C +ATOM 1422 CD2 PHE A 195 -19.927 8.882 -1.857 1.00 90.78 C +ATOM 1423 CE1 PHE A 195 -17.511 9.495 -3.148 1.00 90.78 C +ATOM 1424 CE2 PHE A 195 -19.814 8.720 -3.248 1.00 90.78 C +ATOM 1425 CZ PHE A 195 -18.604 9.025 -3.894 1.00 90.78 C +ATOM 1426 N GLU A 196 -16.707 6.813 0.423 1.00 90.83 N +ATOM 1427 CA GLU A 196 -15.336 6.378 0.169 1.00 90.83 C +ATOM 1428 C GLU A 196 -14.879 6.782 -1.232 1.00 90.83 C +ATOM 1429 O GLU A 196 -15.587 6.569 -2.220 1.00 90.83 O +ATOM 1430 CB GLU A 196 -15.230 4.856 0.328 1.00 90.83 C +ATOM 1431 CG GLU A 196 -15.542 4.355 1.745 1.00 90.83 C +ATOM 1432 CD GLU A 196 -14.634 4.977 2.808 1.00 90.83 C +ATOM 1433 OE1 GLU A 196 -15.170 5.423 3.840 1.00 90.83 O +ATOM 1434 OE2 GLU A 196 -13.404 5.022 2.604 1.00 90.83 O +ATOM 1435 N MET A 197 -13.663 7.313 -1.335 1.00 90.26 N +ATOM 1436 CA MET A 197 -13.013 7.560 -2.619 1.00 90.26 C +ATOM 1437 C MET A 197 -11.500 7.395 -2.545 1.00 90.26 C +ATOM 1438 O MET A 197 -10.887 7.520 -1.490 1.00 90.26 O +ATOM 1439 CB MET A 197 -13.369 8.952 -3.149 1.00 90.26 C +ATOM 1440 CG MET A 197 -12.836 10.095 -2.275 1.00 90.26 C +ATOM 1441 SD MET A 197 -12.779 11.684 -3.132 1.00 90.26 S +ATOM 1442 CE MET A 197 -14.504 11.776 -3.606 1.00 90.26 C +ATOM 1443 N SER A 198 -10.881 7.177 -3.702 1.00 91.54 N +ATOM 1444 CA SER A 198 -9.426 7.200 -3.849 1.00 91.54 C +ATOM 1445 C SER A 198 -8.999 8.361 -4.736 1.00 91.54 C +ATOM 1446 O SER A 198 -9.622 8.608 -5.770 1.00 91.54 O +ATOM 1447 CB SER A 198 -8.923 5.887 -4.441 1.00 91.54 C +ATOM 1448 OG SER A 198 -9.232 4.805 -3.587 1.00 91.54 O +ATOM 1449 N THR A 199 -7.918 9.043 -4.364 1.00 91.35 N +ATOM 1450 CA THR A 199 -7.261 10.009 -5.251 1.00 91.35 C +ATOM 1451 C THR A 199 -6.426 9.290 -6.312 1.00 91.35 C +ATOM 1452 O THR A 199 -6.254 8.067 -6.284 1.00 91.35 O +ATOM 1453 CB THR A 199 -6.425 11.035 -4.468 1.00 91.35 C +ATOM 1454 OG1 THR A 199 -5.390 10.439 -3.723 1.00 91.35 O +ATOM 1455 CG2 THR A 199 -7.290 11.824 -3.489 1.00 91.35 C +ATOM 1456 N ALA A 200 -5.901 10.035 -7.288 1.00 92.36 N +ATOM 1457 CA ALA A 200 -4.970 9.465 -8.253 1.00 92.36 C +ATOM 1458 C ALA A 200 -3.713 8.918 -7.545 1.00 92.36 C +ATOM 1459 O ALA A 200 -3.260 9.510 -6.557 1.00 92.36 O +ATOM 1460 CB ALA A 200 -4.596 10.526 -9.286 1.00 92.36 C +ATOM 1461 N PRO A 201 -3.105 7.827 -8.043 1.00 94.47 N +ATOM 1462 CA PRO A 201 -1.851 7.330 -7.497 1.00 94.47 C +ATOM 1463 C PRO A 201 -0.753 8.392 -7.530 1.00 94.47 C +ATOM 1464 O PRO A 201 -0.681 9.211 -8.450 1.00 94.47 O +ATOM 1465 CB PRO A 201 -1.459 6.139 -8.367 1.00 94.47 C +ATOM 1466 CG PRO A 201 -2.787 5.668 -8.946 1.00 94.47 C +ATOM 1467 CD PRO A 201 -3.558 6.972 -9.128 1.00 94.47 C +ATOM 1468 N CYS A 202 0.155 8.347 -6.558 1.00 93.84 N +ATOM 1469 CA CYS A 202 1.364 9.156 -6.636 1.00 93.84 C +ATOM 1470 C CYS A 202 2.283 8.673 -7.761 1.00 93.84 C +ATOM 1471 O CYS A 202 2.325 7.484 -8.094 1.00 93.84 O +ATOM 1472 CB CYS A 202 2.095 9.173 -5.294 1.00 93.84 C +ATOM 1473 SG CYS A 202 1.204 9.985 -3.948 1.00 93.84 S +ATOM 1474 N VAL A 203 3.058 9.612 -8.306 1.00 94.50 N +ATOM 1475 CA VAL A 203 4.103 9.336 -9.297 1.00 94.50 C +ATOM 1476 C VAL A 203 5.057 8.270 -8.742 1.00 94.50 C +ATOM 1477 O VAL A 203 5.607 8.494 -7.658 1.00 94.50 O +ATOM 1478 CB VAL A 203 4.893 10.616 -9.618 1.00 94.50 C +ATOM 1479 CG1 VAL A 203 5.952 10.345 -10.683 1.00 94.50 C +ATOM 1480 CG2 VAL A 203 3.977 11.726 -10.143 1.00 94.50 C +ATOM 1481 N PRO A 204 5.277 7.142 -9.444 1.00 95.53 N +ATOM 1482 CA PRO A 204 6.189 6.104 -8.973 1.00 95.53 C +ATOM 1483 C PRO A 204 7.601 6.650 -8.729 1.00 95.53 C +ATOM 1484 O PRO A 204 8.102 7.473 -9.497 1.00 95.53 O +ATOM 1485 CB PRO A 204 6.187 5.011 -10.042 1.00 95.53 C +ATOM 1486 CG PRO A 204 4.852 5.215 -10.754 1.00 95.53 C +ATOM 1487 CD PRO A 204 4.618 6.720 -10.674 1.00 95.53 C +ATOM 1488 N GLN A 205 8.238 6.181 -7.656 1.00 94.67 N +ATOM 1489 CA GLN A 205 9.565 6.624 -7.212 1.00 94.67 C +ATOM 1490 C GLN A 205 10.571 5.467 -7.223 1.00 94.67 C +ATOM 1491 O GLN A 205 10.187 4.297 -7.296 1.00 94.67 O +ATOM 1492 CB GLN A 205 9.472 7.247 -5.805 1.00 94.67 C +ATOM 1493 CG GLN A 205 8.549 8.472 -5.716 1.00 94.67 C +ATOM 1494 CD GLN A 205 8.971 9.615 -6.634 1.00 94.67 C +ATOM 1495 OE1 GLN A 205 10.126 10.001 -6.702 1.00 94.67 O +ATOM 1496 NE2 GLN A 205 8.052 10.184 -7.379 1.00 94.67 N +ATOM 1497 N ASN A 206 11.861 5.799 -7.092 1.00 94.81 N +ATOM 1498 CA ASN A 206 12.974 4.843 -7.014 1.00 94.81 C +ATOM 1499 C ASN A 206 12.982 3.844 -8.179 1.00 94.81 C +ATOM 1500 O ASN A 206 13.012 2.632 -7.969 1.00 94.81 O +ATOM 1501 CB ASN A 206 12.985 4.152 -5.640 1.00 94.81 C +ATOM 1502 CG ASN A 206 13.010 5.121 -4.481 1.00 94.81 C +ATOM 1503 OD1 ASN A 206 13.720 6.110 -4.486 1.00 94.81 O +ATOM 1504 ND2 ASN A 206 12.225 4.880 -3.458 1.00 94.81 N +ATOM 1505 N VAL A 207 12.905 4.358 -9.408 1.00 95.64 N +ATOM 1506 CA VAL A 207 12.987 3.530 -10.613 1.00 95.64 C +ATOM 1507 C VAL A 207 14.417 3.005 -10.758 1.00 95.64 C +ATOM 1508 O VAL A 207 15.359 3.781 -10.899 1.00 95.64 O +ATOM 1509 CB VAL A 207 12.537 4.297 -11.870 1.00 95.64 C +ATOM 1510 CG1 VAL A 207 12.573 3.396 -13.112 1.00 95.64 C +ATOM 1511 CG2 VAL A 207 11.108 4.839 -11.724 1.00 95.64 C +ATOM 1512 N VAL A 208 14.570 1.684 -10.726 1.00 96.20 N +ATOM 1513 CA VAL A 208 15.836 0.966 -10.909 1.00 96.20 C +ATOM 1514 C VAL A 208 15.758 0.171 -12.204 1.00 96.20 C +ATOM 1515 O VAL A 208 14.787 -0.556 -12.424 1.00 96.20 O +ATOM 1516 CB VAL A 208 16.134 0.038 -9.717 1.00 96.20 C +ATOM 1517 CG1 VAL A 208 17.462 -0.709 -9.900 1.00 96.20 C +ATOM 1518 CG2 VAL A 208 16.210 0.818 -8.400 1.00 96.20 C +ATOM 1519 N LEU A 209 16.785 0.299 -13.044 1.00 95.76 N +ATOM 1520 CA LEU A 209 16.874 -0.348 -14.350 1.00 95.76 C +ATOM 1521 C LEU A 209 18.065 -1.309 -14.367 1.00 95.76 C +ATOM 1522 O LEU A 209 19.200 -0.890 -14.149 1.00 95.76 O +ATOM 1523 CB LEU A 209 17.008 0.716 -15.456 1.00 95.76 C +ATOM 1524 CG LEU A 209 15.935 1.820 -15.447 1.00 95.76 C +ATOM 1525 CD1 LEU A 209 16.193 2.793 -16.587 1.00 95.76 C +ATOM 1526 CD2 LEU A 209 14.526 1.262 -15.639 1.00 95.76 C +ATOM 1527 N ASN A 210 17.805 -2.580 -14.661 1.00 94.22 N +ATOM 1528 CA ASN A 210 18.814 -3.630 -14.767 1.00 94.22 C +ATOM 1529 C ASN A 210 18.857 -4.172 -16.197 1.00 94.22 C +ATOM 1530 O ASN A 210 17.815 -4.370 -16.821 1.00 94.22 O +ATOM 1531 CB ASN A 210 18.498 -4.742 -13.754 1.00 94.22 C +ATOM 1532 CG ASN A 210 18.662 -4.313 -12.306 1.00 94.22 C +ATOM 1533 OD1 ASN A 210 19.312 -3.344 -11.964 1.00 94.22 O +ATOM 1534 ND2 ASN A 210 18.090 -5.051 -11.385 1.00 94.22 N +ATOM 1535 N SER A 211 20.050 -4.451 -16.717 1.00 92.94 N +ATOM 1536 CA SER A 211 20.209 -5.062 -18.037 1.00 92.94 C +ATOM 1537 C SER A 211 19.846 -6.549 -18.023 1.00 92.94 C +ATOM 1538 O SER A 211 20.151 -7.278 -17.080 1.00 92.94 O +ATOM 1539 CB SER A 211 21.632 -4.841 -18.564 1.00 92.94 C +ATOM 1540 OG SER A 211 22.596 -5.245 -17.609 1.00 92.94 O +ATOM 1541 N MET A 212 19.202 -7.013 -19.096 1.00 91.28 N +ATOM 1542 CA MET A 212 18.914 -8.427 -19.344 1.00 91.28 C +ATOM 1543 C MET A 212 19.647 -8.873 -20.607 1.00 91.28 C +ATOM 1544 O MET A 212 19.113 -8.775 -21.715 1.00 91.28 O +ATOM 1545 CB MET A 212 17.407 -8.665 -19.484 1.00 91.28 C +ATOM 1546 CG MET A 212 16.614 -8.351 -18.214 1.00 91.28 C +ATOM 1547 SD MET A 212 14.866 -8.832 -18.314 1.00 91.28 S +ATOM 1548 CE MET A 212 14.368 -7.956 -19.822 1.00 91.28 C +ATOM 1549 N CYS A 213 20.874 -9.363 -20.436 1.00 84.27 N +ATOM 1550 CA CYS A 213 21.756 -9.732 -21.545 1.00 84.27 C +ATOM 1551 C CYS A 213 21.155 -10.818 -22.451 1.00 84.27 C +ATOM 1552 O CYS A 213 21.280 -10.722 -23.666 1.00 84.27 O +ATOM 1553 CB CYS A 213 23.108 -10.178 -20.974 1.00 84.27 C +ATOM 1554 SG CYS A 213 23.861 -8.826 -20.017 1.00 84.27 S +ATOM 1555 N ASP A 214 20.435 -11.792 -21.888 1.00 84.71 N +ATOM 1556 CA ASP A 214 19.877 -12.917 -22.656 1.00 84.71 C +ATOM 1557 C ASP A 214 18.805 -12.495 -23.675 1.00 84.71 C +ATOM 1558 O ASP A 214 18.578 -13.183 -24.667 1.00 84.71 O +ATOM 1559 CB ASP A 214 19.266 -13.942 -21.687 1.00 84.71 C +ATOM 1560 CG ASP A 214 20.274 -14.521 -20.692 1.00 84.71 C +ATOM 1561 OD1 ASP A 214 21.467 -14.624 -21.050 1.00 84.71 O +ATOM 1562 OD2 ASP A 214 19.841 -14.806 -19.555 1.00 84.71 O +ATOM 1563 N SER A 215 18.136 -11.363 -23.438 1.00 86.87 N +ATOM 1564 CA SER A 215 17.030 -10.867 -24.273 1.00 86.87 C +ATOM 1565 C SER A 215 17.333 -9.538 -24.967 1.00 86.87 C +ATOM 1566 O SER A 215 16.437 -8.956 -25.583 1.00 86.87 O +ATOM 1567 CB SER A 215 15.739 -10.782 -23.451 1.00 86.87 C +ATOM 1568 OG SER A 215 15.889 -9.884 -22.368 1.00 86.87 O +ATOM 1569 N ASN A 216 18.575 -9.042 -24.857 1.00 88.00 N +ATOM 1570 CA ASN A 216 18.959 -7.684 -25.259 1.00 88.00 C +ATOM 1571 C ASN A 216 17.972 -6.633 -24.720 1.00 88.00 C +ATOM 1572 O ASN A 216 17.516 -5.753 -25.444 1.00 88.00 O +ATOM 1573 CB ASN A 216 19.156 -7.627 -26.783 1.00 88.00 C +ATOM 1574 CG ASN A 216 20.261 -8.549 -27.251 1.00 88.00 C +ATOM 1575 OD1 ASN A 216 21.296 -8.692 -26.625 1.00 88.00 O +ATOM 1576 ND2 ASN A 216 20.089 -9.199 -28.377 1.00 88.00 N +ATOM 1577 N GLY A 217 17.569 -6.787 -23.460 1.00 92.79 N +ATOM 1578 CA GLY A 217 16.481 -6.025 -22.861 1.00 92.79 C +ATOM 1579 C GLY A 217 16.861 -5.348 -21.555 1.00 92.79 C +ATOM 1580 O GLY A 217 18.014 -5.374 -21.114 1.00 92.79 O +ATOM 1581 N MET A 218 15.852 -4.789 -20.895 1.00 94.65 N +ATOM 1582 CA MET A 218 15.960 -4.276 -19.534 1.00 94.65 C +ATOM 1583 C MET A 218 14.818 -4.762 -18.642 1.00 94.65 C +ATOM 1584 O MET A 218 13.690 -4.969 -19.091 1.00 94.65 O +ATOM 1585 CB MET A 218 16.064 -2.747 -19.540 1.00 94.65 C +ATOM 1586 CG MET A 218 14.742 -2.052 -19.861 1.00 94.65 C +ATOM 1587 SD MET A 218 14.876 -0.255 -19.841 1.00 94.65 S +ATOM 1588 CE MET A 218 13.206 0.090 -20.410 1.00 94.65 C +ATOM 1589 N MET A 219 15.114 -4.899 -17.356 1.00 95.36 N +ATOM 1590 CA MET A 219 14.137 -5.076 -16.294 1.00 95.36 C +ATOM 1591 C MET A 219 14.087 -3.798 -15.468 1.00 95.36 C +ATOM 1592 O MET A 219 15.088 -3.390 -14.882 1.00 95.36 O +ATOM 1593 CB MET A 219 14.513 -6.287 -15.436 1.00 95.36 C +ATOM 1594 CG MET A 219 13.467 -6.552 -14.348 1.00 95.36 C +ATOM 1595 SD MET A 219 13.793 -8.030 -13.349 1.00 95.36 S +ATOM 1596 CE MET A 219 13.431 -9.340 -14.552 1.00 95.36 C +ATOM 1597 N ALA A 220 12.914 -3.187 -15.405 1.00 96.83 N +ATOM 1598 CA ALA A 220 12.656 -2.043 -14.556 1.00 96.83 C +ATOM 1599 C ALA A 220 11.903 -2.475 -13.299 1.00 96.83 C +ATOM 1600 O ALA A 220 11.018 -3.332 -13.355 1.00 96.83 O +ATOM 1601 CB ALA A 220 11.873 -1.018 -15.359 1.00 96.83 C +ATOM 1602 N SER A 221 12.230 -1.850 -12.174 1.00 97.30 N +ATOM 1603 CA SER A 221 11.522 -2.004 -10.903 1.00 97.30 C +ATOM 1604 C SER A 221 11.376 -0.654 -10.209 1.00 97.30 C +ATOM 1605 O SER A 221 12.177 0.246 -10.447 1.00 97.30 O +ATOM 1606 CB SER A 221 12.232 -3.027 -10.015 1.00 97.30 C +ATOM 1607 OG SER A 221 13.537 -2.598 -9.685 1.00 97.30 O +ATOM 1608 N TRP A 222 10.337 -0.483 -9.396 1.00 96.10 N +ATOM 1609 CA TRP A 222 10.023 0.789 -8.734 1.00 96.10 C +ATOM 1610 C TRP A 222 9.342 0.566 -7.383 1.00 96.10 C +ATOM 1611 O TRP A 222 8.812 -0.509 -7.092 1.00 96.10 O +ATOM 1612 CB TRP A 222 9.138 1.645 -9.650 1.00 96.10 C +ATOM 1613 CG TRP A 222 7.916 0.947 -10.160 1.00 96.10 C +ATOM 1614 CD1 TRP A 222 6.689 0.957 -9.590 1.00 96.10 C +ATOM 1615 CD2 TRP A 222 7.798 0.116 -11.353 1.00 96.10 C +ATOM 1616 NE1 TRP A 222 5.827 0.175 -10.332 1.00 96.10 N +ATOM 1617 CE2 TRP A 222 6.460 -0.373 -11.423 1.00 96.10 C +ATOM 1618 CE3 TRP A 222 8.673 -0.235 -12.406 1.00 96.10 C +ATOM 1619 CZ2 TRP A 222 6.015 -1.186 -12.469 1.00 96.10 C +ATOM 1620 CZ3 TRP A 222 8.227 -1.030 -13.478 1.00 96.10 C +ATOM 1621 CH2 TRP A 222 6.900 -1.500 -13.510 1.00 96.10 C +ATOM 1622 N SER A 223 9.327 1.603 -6.546 1.00 95.88 N +ATOM 1623 CA SER A 223 8.591 1.568 -5.278 1.00 95.88 C +ATOM 1624 C SER A 223 7.071 1.561 -5.510 1.00 95.88 C +ATOM 1625 O SER A 223 6.603 2.232 -6.431 1.00 95.88 O +ATOM 1626 CB SER A 223 8.978 2.753 -4.398 1.00 95.88 C +ATOM 1627 OG SER A 223 10.338 2.614 -4.037 1.00 95.88 O +ATOM 1628 N PRO A 224 6.280 0.840 -4.693 1.00 93.58 N +ATOM 1629 CA PRO A 224 4.822 0.857 -4.798 1.00 93.58 C +ATOM 1630 C PRO A 224 4.217 2.249 -4.638 1.00 93.58 C +ATOM 1631 O PRO A 224 4.501 2.951 -3.670 1.00 93.58 O +ATOM 1632 CB PRO A 224 4.306 -0.124 -3.735 1.00 93.58 C +ATOM 1633 CG PRO A 224 5.506 -1.011 -3.402 1.00 93.58 C +ATOM 1634 CD PRO A 224 6.711 -0.119 -3.684 1.00 93.58 C +ATOM 1635 N SER A 225 3.332 2.611 -5.567 1.00 92.93 N +ATOM 1636 CA SER A 225 2.432 3.752 -5.427 1.00 92.93 C +ATOM 1637 C SER A 225 1.147 3.289 -4.744 1.00 92.93 C +ATOM 1638 O SER A 225 0.486 2.366 -5.222 1.00 92.93 O +ATOM 1639 CB SER A 225 2.111 4.374 -6.791 1.00 92.93 C +ATOM 1640 OG SER A 225 3.257 4.976 -7.362 1.00 92.93 O +ATOM 1641 N LEU A 226 0.774 3.933 -3.635 1.00 89.63 N +ATOM 1642 CA LEU A 226 -0.499 3.666 -2.960 1.00 89.63 C +ATOM 1643 C LEU A 226 -1.678 3.869 -3.924 1.00 89.63 C +ATOM 1644 O LEU A 226 -1.602 4.694 -4.836 1.00 89.63 O +ATOM 1645 CB LEU A 226 -0.639 4.558 -1.717 1.00 89.63 C +ATOM 1646 CG LEU A 226 0.325 4.226 -0.565 1.00 89.63 C +ATOM 1647 CD1 LEU A 226 0.234 5.308 0.510 1.00 89.63 C +ATOM 1648 CD2 LEU A 226 0.001 2.874 0.078 1.00 89.63 C +ATOM 1649 N VAL A 227 -2.734 3.074 -3.724 1.00 90.07 N +ATOM 1650 CA VAL A 227 -3.957 2.955 -4.545 1.00 90.07 C +ATOM 1651 C VAL A 227 -3.759 2.585 -6.025 1.00 90.07 C +ATOM 1652 O VAL A 227 -4.744 2.394 -6.732 1.00 90.07 O +ATOM 1653 CB VAL A 227 -4.936 4.139 -4.361 1.00 90.07 C +ATOM 1654 CG1 VAL A 227 -5.165 4.496 -2.886 1.00 90.07 C +ATOM 1655 CG2 VAL A 227 -4.552 5.420 -5.103 1.00 90.07 C +ATOM 1656 N ALA A 228 -2.525 2.439 -6.521 1.00 93.16 N +ATOM 1657 CA ALA A 228 -2.273 2.036 -7.902 1.00 93.16 C +ATOM 1658 C ALA A 228 -2.717 0.587 -8.154 1.00 93.16 C +ATOM 1659 O ALA A 228 -2.333 -0.325 -7.425 1.00 93.16 O +ATOM 1660 CB ALA A 228 -0.788 2.214 -8.230 1.00 93.16 C +ATOM 1661 N GLN A 229 -3.477 0.377 -9.228 1.00 93.80 N +ATOM 1662 CA GLN A 229 -3.899 -0.950 -9.690 1.00 93.80 C +ATOM 1663 C GLN A 229 -3.042 -1.453 -10.856 1.00 93.80 C +ATOM 1664 O GLN A 229 -2.936 -2.655 -11.094 1.00 93.80 O +ATOM 1665 CB GLN A 229 -5.359 -0.876 -10.147 1.00 93.80 C +ATOM 1666 CG GLN A 229 -6.357 -0.574 -9.018 1.00 93.80 C +ATOM 1667 CD GLN A 229 -7.783 -0.469 -9.554 1.00 93.80 C +ATOM 1668 OE1 GLN A 229 -8.033 -0.531 -10.747 1.00 93.80 O +ATOM 1669 NE2 GLN A 229 -8.770 -0.273 -8.714 1.00 93.80 N +ATOM 1670 N SER A 230 -2.449 -0.531 -11.615 1.00 96.03 N +ATOM 1671 CA SER A 230 -1.612 -0.852 -12.765 1.00 96.03 C +ATOM 1672 C SER A 230 -0.550 0.215 -12.993 1.00 96.03 C +ATOM 1673 O SER A 230 -0.685 1.360 -12.560 1.00 96.03 O +ATOM 1674 CB SER A 230 -2.475 -1.040 -14.018 1.00 96.03 C +ATOM 1675 OG SER A 230 -3.146 0.153 -14.377 1.00 96.03 O +ATOM 1676 N TYR A 231 0.504 -0.171 -13.697 1.00 96.98 N +ATOM 1677 CA TYR A 231 1.596 0.692 -14.103 1.00 96.98 C +ATOM 1678 C TYR A 231 1.811 0.579 -15.609 1.00 96.98 C +ATOM 1679 O TYR A 231 1.652 -0.499 -16.189 1.00 96.98 O +ATOM 1680 CB TYR A 231 2.871 0.325 -13.342 1.00 96.98 C +ATOM 1681 CG TYR A 231 2.768 0.428 -11.831 1.00 96.98 C +ATOM 1682 CD1 TYR A 231 3.127 1.621 -11.173 1.00 96.98 C +ATOM 1683 CD2 TYR A 231 2.315 -0.676 -11.082 1.00 96.98 C +ATOM 1684 CE1 TYR A 231 3.031 1.709 -9.769 1.00 96.98 C +ATOM 1685 CE2 TYR A 231 2.187 -0.581 -9.684 1.00 96.98 C +ATOM 1686 CZ TYR A 231 2.543 0.614 -9.026 1.00 96.98 C +ATOM 1687 OH TYR A 231 2.432 0.702 -7.675 1.00 96.98 O +ATOM 1688 N LEU A 232 2.203 1.687 -16.233 1.00 96.86 N +ATOM 1689 CA LEU A 232 2.615 1.740 -17.632 1.00 96.86 C +ATOM 1690 C LEU A 232 4.015 2.339 -17.706 1.00 96.86 C +ATOM 1691 O LEU A 232 4.209 3.525 -17.425 1.00 96.86 O +ATOM 1692 CB LEU A 232 1.581 2.536 -18.445 1.00 96.86 C +ATOM 1693 CG LEU A 232 1.975 2.765 -19.917 1.00 96.86 C +ATOM 1694 CD1 LEU A 232 1.929 1.468 -20.724 1.00 96.86 C +ATOM 1695 CD2 LEU A 232 1.006 3.755 -20.561 1.00 96.86 C +ATOM 1696 N LEU A 233 4.973 1.507 -18.098 1.00 97.30 N +ATOM 1697 CA LEU A 233 6.342 1.905 -18.381 1.00 97.30 C +ATOM 1698 C LEU A 233 6.479 2.231 -19.866 1.00 97.30 C +ATOM 1699 O LEU A 233 5.994 1.479 -20.709 1.00 97.30 O +ATOM 1700 CB LEU A 233 7.274 0.786 -17.906 1.00 97.30 C +ATOM 1701 CG LEU A 233 8.763 1.144 -18.053 1.00 97.30 C +ATOM 1702 CD1 LEU A 233 9.546 0.468 -16.942 1.00 97.30 C +ATOM 1703 CD2 LEU A 233 9.350 0.650 -19.373 1.00 97.30 C +ATOM 1704 N THR A 234 7.150 3.338 -20.171 1.00 97.08 N +ATOM 1705 CA THR A 234 7.455 3.792 -21.532 1.00 97.08 C +ATOM 1706 C THR A 234 8.951 4.050 -21.646 1.00 97.08 C +ATOM 1707 O THR A 234 9.509 4.793 -20.838 1.00 97.08 O +ATOM 1708 CB THR A 234 6.668 5.064 -21.877 1.00 97.08 C +ATOM 1709 OG1 THR A 234 5.291 4.830 -21.684 1.00 97.08 O +ATOM 1710 CG2 THR A 234 6.864 5.506 -23.327 1.00 97.08 C +ATOM 1711 N ALA A 235 9.588 3.442 -22.641 1.00 96.74 N +ATOM 1712 CA ALA A 235 10.988 3.634 -22.979 1.00 96.74 C +ATOM 1713 C ALA A 235 11.077 4.180 -24.404 1.00 96.74 C +ATOM 1714 O ALA A 235 10.597 3.537 -25.333 1.00 96.74 O +ATOM 1715 CB ALA A 235 11.715 2.296 -22.823 1.00 96.74 C +ATOM 1716 N SER A 236 11.672 5.356 -24.572 1.00 96.76 N +ATOM 1717 CA SER A 236 11.827 6.004 -25.879 1.00 96.76 C +ATOM 1718 C SER A 236 13.292 6.285 -26.169 1.00 96.76 C +ATOM 1719 O SER A 236 13.979 6.823 -25.296 1.00 96.76 O +ATOM 1720 CB SER A 236 11.030 7.310 -25.930 1.00 96.76 C +ATOM 1721 OG SER A 236 11.480 8.195 -24.918 1.00 96.76 O +ATOM 1722 N SER A 237 13.755 5.989 -27.378 1.00 95.64 N +ATOM 1723 CA SER A 237 15.117 6.290 -27.813 1.00 95.64 C +ATOM 1724 C SER A 237 15.168 7.387 -28.883 1.00 95.64 C +ATOM 1725 O SER A 237 14.163 7.753 -29.492 1.00 95.64 O +ATOM 1726 CB SER A 237 15.815 5.010 -28.258 1.00 95.64 C +ATOM 1727 OG SER A 237 17.180 5.323 -28.412 1.00 95.64 O +ATOM 1728 N SER A 238 16.356 7.959 -29.087 1.00 93.34 N +ATOM 1729 CA SER A 238 16.622 9.013 -30.071 1.00 93.34 C +ATOM 1730 C SER A 238 16.487 8.557 -31.525 1.00 93.34 C +ATOM 1731 O SER A 238 16.347 9.400 -32.407 1.00 93.34 O +ATOM 1732 CB SER A 238 18.033 9.569 -29.861 1.00 93.34 C +ATOM 1733 OG SER A 238 18.998 8.540 -29.702 1.00 93.34 O +ATOM 1734 N ASP A 239 16.539 7.251 -31.783 1.00 92.94 N +ATOM 1735 CA ASP A 239 16.326 6.664 -33.110 1.00 92.94 C +ATOM 1736 C ASP A 239 14.836 6.550 -33.497 1.00 92.94 C +ATOM 1737 O ASP A 239 14.518 6.191 -34.630 1.00 92.94 O +ATOM 1738 CB ASP A 239 17.042 5.306 -33.178 1.00 92.94 C +ATOM 1739 CG ASP A 239 16.412 4.223 -32.296 1.00 92.94 C +ATOM 1740 OD1 ASP A 239 15.519 4.558 -31.487 1.00 92.94 O +ATOM 1741 OD2 ASP A 239 16.837 3.058 -32.445 1.00 92.94 O +ATOM 1742 N GLY A 240 13.929 6.897 -32.577 1.00 93.53 N +ATOM 1743 CA GLY A 240 12.481 6.838 -32.759 1.00 93.53 C +ATOM 1744 C GLY A 240 11.828 5.559 -32.234 1.00 93.53 C +ATOM 1745 O GLY A 240 10.603 5.457 -32.314 1.00 93.53 O +ATOM 1746 N ASP A 241 12.592 4.611 -31.680 1.00 94.68 N +ATOM 1747 CA ASP A 241 12.017 3.420 -31.059 1.00 94.68 C +ATOM 1748 C ASP A 241 11.290 3.771 -29.753 1.00 94.68 C +ATOM 1749 O ASP A 241 11.806 4.498 -28.895 1.00 94.68 O +ATOM 1750 CB ASP A 241 13.080 2.331 -30.858 1.00 94.68 C +ATOM 1751 CG ASP A 241 12.439 1.028 -30.375 1.00 94.68 C +ATOM 1752 OD1 ASP A 241 11.345 0.693 -30.885 1.00 94.68 O +ATOM 1753 OD2 ASP A 241 13.005 0.416 -29.440 1.00 94.68 O +ATOM 1754 N VAL A 242 10.065 3.260 -29.606 1.00 95.95 N +ATOM 1755 CA VAL A 242 9.214 3.481 -28.432 1.00 95.95 C +ATOM 1756 C VAL A 242 8.582 2.166 -28.015 1.00 95.95 C +ATOM 1757 O VAL A 242 7.713 1.617 -28.692 1.00 95.95 O +ATOM 1758 CB VAL A 242 8.133 4.558 -28.650 1.00 95.95 C +ATOM 1759 CG1 VAL A 242 7.334 4.792 -27.354 1.00 95.95 C +ATOM 1760 CG2 VAL A 242 8.734 5.908 -29.057 1.00 95.95 C +ATOM 1761 N LEU A 243 8.972 1.701 -26.835 1.00 95.53 N +ATOM 1762 CA LEU A 243 8.505 0.458 -26.247 1.00 95.53 C +ATOM 1763 C LEU A 243 7.703 0.750 -24.985 1.00 95.53 C +ATOM 1764 O LEU A 243 8.040 1.631 -24.191 1.00 95.53 O +ATOM 1765 CB LEU A 243 9.712 -0.448 -25.988 1.00 95.53 C +ATOM 1766 CG LEU A 243 10.346 -0.978 -27.290 1.00 95.53 C +ATOM 1767 CD1 LEU A 243 11.765 -1.423 -26.990 1.00 95.53 C +ATOM 1768 CD2 LEU A 243 9.570 -2.170 -27.850 1.00 95.53 C +ATOM 1769 N THR A 244 6.630 -0.010 -24.787 1.00 96.69 N +ATOM 1770 CA THR A 244 5.779 0.118 -23.602 1.00 96.69 C +ATOM 1771 C THR A 244 5.496 -1.233 -22.980 1.00 96.69 C +ATOM 1772 O THR A 244 5.415 -2.248 -23.669 1.00 96.69 O +ATOM 1773 CB THR A 244 4.459 0.852 -23.874 1.00 96.69 C +ATOM 1774 OG1 THR A 244 3.667 0.168 -24.815 1.00 96.69 O +ATOM 1775 CG2 THR A 244 4.654 2.274 -24.387 1.00 96.69 C +ATOM 1776 N CYS A 245 5.335 -1.252 -21.661 1.00 95.53 N +ATOM 1777 CA CYS A 245 4.934 -2.452 -20.944 1.00 95.53 C +ATOM 1778 C CYS A 245 4.017 -2.099 -19.776 1.00 95.53 C +ATOM 1779 O CYS A 245 4.239 -1.139 -19.033 1.00 95.53 O +ATOM 1780 CB CYS A 245 6.179 -3.256 -20.573 1.00 95.53 C +ATOM 1781 SG CYS A 245 6.139 -4.241 -19.059 1.00 95.53 S +ATOM 1782 N LYS A 246 2.940 -2.878 -19.662 1.00 96.04 N +ATOM 1783 CA LYS A 246 1.927 -2.755 -18.617 1.00 96.04 C +ATOM 1784 C LYS A 246 2.159 -3.829 -17.571 1.00 96.04 C +ATOM 1785 O LYS A 246 2.362 -4.987 -17.924 1.00 96.04 O +ATOM 1786 CB LYS A 246 0.514 -2.864 -19.206 1.00 96.04 C +ATOM 1787 CG LYS A 246 0.159 -1.638 -20.054 1.00 96.04 C +ATOM 1788 CD LYS A 246 -1.267 -1.750 -20.604 1.00 96.04 C +ATOM 1789 CE LYS A 246 -1.595 -0.509 -21.441 1.00 96.04 C +ATOM 1790 NZ LYS A 246 -2.980 -0.555 -21.970 1.00 96.04 N +ATOM 1791 N SER A 247 2.082 -3.452 -16.302 1.00 95.41 N +ATOM 1792 CA SER A 247 2.252 -4.382 -15.190 1.00 95.41 C +ATOM 1793 C SER A 247 1.283 -4.074 -14.055 1.00 95.41 C +ATOM 1794 O SER A 247 0.982 -2.913 -13.786 1.00 95.41 O +ATOM 1795 CB SER A 247 3.696 -4.340 -14.700 1.00 95.41 C +ATOM 1796 OG SER A 247 3.868 -5.378 -13.772 1.00 95.41 O +ATOM 1797 N THR A 248 0.788 -5.111 -13.385 1.00 95.16 N +ATOM 1798 CA THR A 248 0.049 -4.998 -12.114 1.00 95.16 C +ATOM 1799 C THR A 248 0.973 -5.152 -10.905 1.00 95.16 C +ATOM 1800 O THR A 248 0.538 -4.998 -9.769 1.00 95.16 O +ATOM 1801 CB THR A 248 -1.078 -6.036 -12.040 1.00 95.16 C +ATOM 1802 OG1 THR A 248 -0.546 -7.334 -12.196 1.00 95.16 O +ATOM 1803 CG2 THR A 248 -2.119 -5.828 -13.140 1.00 95.16 C +ATOM 1804 N THR A 249 2.247 -5.473 -11.139 1.00 94.79 N +ATOM 1805 CA THR A 249 3.297 -5.586 -10.126 1.00 94.79 C +ATOM 1806 C THR A 249 4.271 -4.413 -10.237 1.00 94.79 C +ATOM 1807 O THR A 249 4.193 -3.573 -11.130 1.00 94.79 O +ATOM 1808 CB THR A 249 4.042 -6.932 -10.245 1.00 94.79 C +ATOM 1809 OG1 THR A 249 4.595 -7.084 -11.529 1.00 94.79 O +ATOM 1810 CG2 THR A 249 3.106 -8.119 -10.014 1.00 94.79 C +ATOM 1811 N ASN A 250 5.223 -4.357 -9.311 1.00 95.13 N +ATOM 1812 CA ASN A 250 6.231 -3.301 -9.189 1.00 95.13 C +ATOM 1813 C ASN A 250 7.441 -3.462 -10.116 1.00 95.13 C +ATOM 1814 O ASN A 250 8.518 -2.928 -9.844 1.00 95.13 O +ATOM 1815 CB ASN A 250 6.638 -3.266 -7.717 1.00 95.13 C +ATOM 1816 CG ASN A 250 5.471 -2.787 -6.905 1.00 95.13 C +ATOM 1817 OD1 ASN A 250 4.572 -3.525 -6.545 1.00 95.13 O +ATOM 1818 ND2 ASN A 250 5.416 -1.509 -6.683 1.00 95.13 N +ATOM 1819 N ASN A 251 7.293 -4.262 -11.166 1.00 96.32 N +ATOM 1820 CA ASN A 251 8.343 -4.548 -12.122 1.00 96.32 C +ATOM 1821 C ASN A 251 7.766 -4.786 -13.515 1.00 96.32 C +ATOM 1822 O ASN A 251 6.587 -5.098 -13.687 1.00 96.32 O +ATOM 1823 CB ASN A 251 9.209 -5.718 -11.618 1.00 96.32 C +ATOM 1824 CG ASN A 251 8.459 -7.023 -11.385 1.00 96.32 C +ATOM 1825 OD1 ASN A 251 7.356 -7.268 -11.841 1.00 96.32 O +ATOM 1826 ND2 ASN A 251 9.033 -7.924 -10.627 1.00 96.32 N +ATOM 1827 N CYS A 252 8.611 -4.599 -14.519 1.00 96.24 N +ATOM 1828 CA CYS A 252 8.263 -4.781 -15.917 1.00 96.24 C +ATOM 1829 C CYS A 252 9.536 -5.039 -16.727 1.00 96.24 C +ATOM 1830 O CYS A 252 10.587 -4.452 -16.464 1.00 96.24 O +ATOM 1831 CB CYS A 252 7.525 -3.524 -16.381 1.00 96.24 C +ATOM 1832 SG CYS A 252 7.582 -3.191 -18.137 1.00 96.24 S +ATOM 1833 N THR A 253 9.438 -5.922 -17.714 1.00 95.25 N +ATOM 1834 CA THR A 253 10.535 -6.293 -18.606 1.00 95.25 C +ATOM 1835 C THR A 253 10.259 -5.792 -20.019 1.00 95.25 C +ATOM 1836 O THR A 253 9.179 -6.004 -20.565 1.00 95.25 O +ATOM 1837 CB THR A 253 10.760 -7.811 -18.587 1.00 95.25 C +ATOM 1838 OG1 THR A 253 9.549 -8.520 -18.707 1.00 95.25 O +ATOM 1839 CG2 THR A 253 11.391 -8.251 -17.267 1.00 95.25 C +ATOM 1840 N LEU A 254 11.251 -5.134 -20.620 1.00 94.89 N +ATOM 1841 CA LEU A 254 11.237 -4.729 -22.024 1.00 94.89 C +ATOM 1842 C LEU A 254 12.366 -5.456 -22.767 1.00 94.89 C +ATOM 1843 O LEU A 254 13.534 -5.123 -22.554 1.00 94.89 O +ATOM 1844 CB LEU A 254 11.349 -3.199 -22.149 1.00 94.89 C +ATOM 1845 CG LEU A 254 10.041 -2.438 -21.858 1.00 94.89 C +ATOM 1846 CD1 LEU A 254 10.254 -0.948 -22.107 1.00 94.89 C +ATOM 1847 CD2 LEU A 254 8.893 -2.871 -22.770 1.00 94.89 C +ATOM 1848 N PRO A 255 12.051 -6.479 -23.579 1.00 93.40 N +ATOM 1849 CA PRO A 255 13.036 -7.183 -24.396 1.00 93.40 C +ATOM 1850 C PRO A 255 13.342 -6.426 -25.700 1.00 93.40 C +ATOM 1851 O PRO A 255 12.616 -5.503 -26.065 1.00 93.40 O +ATOM 1852 CB PRO A 255 12.394 -8.549 -24.647 1.00 93.40 C +ATOM 1853 CG PRO A 255 10.906 -8.213 -24.759 1.00 93.40 C +ATOM 1854 CD PRO A 255 10.729 -7.074 -23.757 1.00 93.40 C +ATOM 1855 N HIS A 256 14.371 -6.873 -26.429 1.00 91.17 N +ATOM 1856 CA HIS A 256 14.667 -6.451 -27.808 1.00 91.17 C +ATOM 1857 C HIS A 256 14.919 -4.946 -28.004 1.00 91.17 C +ATOM 1858 O HIS A 256 14.514 -4.375 -29.013 1.00 91.17 O +ATOM 1859 CB HIS A 256 13.602 -6.996 -28.778 1.00 91.17 C +ATOM 1860 CG HIS A 256 13.353 -8.473 -28.646 1.00 91.17 C +ATOM 1861 ND1 HIS A 256 14.273 -9.471 -28.860 1.00 91.17 N +ATOM 1862 CD2 HIS A 256 12.182 -9.073 -28.274 1.00 91.17 C +ATOM 1863 CE1 HIS A 256 13.673 -10.646 -28.617 1.00 91.17 C +ATOM 1864 NE2 HIS A 256 12.396 -10.456 -28.250 1.00 91.17 N +ATOM 1865 N LEU A 257 15.623 -4.314 -27.066 1.00 94.11 N +ATOM 1866 CA LEU A 257 16.084 -2.937 -27.227 1.00 94.11 C +ATOM 1867 C LEU A 257 17.154 -2.864 -28.326 1.00 94.11 C +ATOM 1868 O LEU A 257 18.011 -3.748 -28.438 1.00 94.11 O +ATOM 1869 CB LEU A 257 16.632 -2.410 -25.887 1.00 94.11 C +ATOM 1870 CG LEU A 257 15.618 -2.384 -24.729 1.00 94.11 C +ATOM 1871 CD1 LEU A 257 16.335 -2.065 -23.420 1.00 94.11 C +ATOM 1872 CD2 LEU A 257 14.553 -1.314 -24.925 1.00 94.11 C +ATOM 1873 N HIS A 258 17.138 -1.795 -29.120 1.00 93.99 N +ATOM 1874 CA HIS A 258 18.170 -1.538 -30.118 1.00 93.99 C +ATOM 1875 C HIS A 258 19.529 -1.317 -29.448 1.00 93.99 C +ATOM 1876 O HIS A 258 19.653 -0.568 -28.482 1.00 93.99 O +ATOM 1877 CB HIS A 258 17.784 -0.331 -30.975 1.00 93.99 C +ATOM 1878 CG HIS A 258 16.622 -0.548 -31.911 1.00 93.99 C +ATOM 1879 ND1 HIS A 258 16.015 0.446 -32.635 1.00 93.99 N +ATOM 1880 CD2 HIS A 258 15.985 -1.719 -32.230 1.00 93.99 C +ATOM 1881 CE1 HIS A 258 15.038 -0.105 -33.368 1.00 93.99 C +ATOM 1882 NE2 HIS A 258 15.002 -1.435 -33.184 1.00 93.99 N +ATOM 1883 N CYS A 259 20.565 -1.968 -29.972 1.00 92.06 N +ATOM 1884 CA CYS A 259 21.926 -1.829 -29.468 1.00 92.06 C +ATOM 1885 C CYS A 259 22.489 -0.418 -29.713 1.00 92.06 C +ATOM 1886 O CYS A 259 22.090 0.281 -30.645 1.00 92.06 O +ATOM 1887 CB CYS A 259 22.793 -2.917 -30.109 1.00 92.06 C +ATOM 1888 SG CYS A 259 22.867 -2.863 -31.928 1.00 92.06 S +ATOM 1889 N GLY A 260 23.449 0.003 -28.889 1.00 91.36 N +ATOM 1890 CA GLY A 260 24.135 1.293 -29.014 1.00 91.36 C +ATOM 1891 C GLY A 260 23.255 2.522 -28.763 1.00 91.36 C +ATOM 1892 O GLY A 260 23.721 3.644 -28.951 1.00 91.36 O +ATOM 1893 N GLN A 261 22.011 2.325 -28.333 1.00 94.17 N +ATOM 1894 CA GLN A 261 21.043 3.377 -28.060 1.00 94.17 C +ATOM 1895 C GLN A 261 20.945 3.719 -26.571 1.00 94.17 C +ATOM 1896 O GLN A 261 21.199 2.888 -25.688 1.00 94.17 O +ATOM 1897 CB GLN A 261 19.668 2.960 -28.597 1.00 94.17 C +ATOM 1898 CG GLN A 261 19.580 2.805 -30.121 1.00 94.17 C +ATOM 1899 CD GLN A 261 20.159 3.978 -30.906 1.00 94.17 C +ATOM 1900 OE1 GLN A 261 20.004 5.149 -30.583 1.00 94.17 O +ATOM 1901 NE2 GLN A 261 20.912 3.704 -31.949 1.00 94.17 N +ATOM 1902 N VAL A 262 20.510 4.949 -26.299 1.00 95.71 N +ATOM 1903 CA VAL A 262 20.081 5.395 -24.969 1.00 95.71 C +ATOM 1904 C VAL A 262 18.561 5.483 -24.967 1.00 95.71 C +ATOM 1905 O VAL A 262 17.978 6.143 -25.827 1.00 95.71 O +ATOM 1906 CB VAL A 262 20.732 6.732 -24.569 1.00 95.71 C +ATOM 1907 CG1 VAL A 262 20.383 7.101 -23.119 1.00 95.71 C +ATOM 1908 CG2 VAL A 262 22.261 6.646 -24.683 1.00 95.71 C +ATOM 1909 N TYR A 263 17.923 4.809 -24.015 1.00 96.24 N +ATOM 1910 CA TYR A 263 16.478 4.861 -23.811 1.00 96.24 C +ATOM 1911 C TYR A 263 16.154 5.737 -22.604 1.00 96.24 C +ATOM 1912 O TYR A 263 16.674 5.516 -21.510 1.00 96.24 O +ATOM 1913 CB TYR A 263 15.902 3.448 -23.645 1.00 96.24 C +ATOM 1914 CG TYR A 263 15.766 2.678 -24.944 1.00 96.24 C +ATOM 1915 CD1 TYR A 263 14.514 2.588 -25.587 1.00 96.24 C +ATOM 1916 CD2 TYR A 263 16.892 2.057 -25.517 1.00 96.24 C +ATOM 1917 CE1 TYR A 263 14.381 1.854 -26.781 1.00 96.24 C +ATOM 1918 CE2 TYR A 263 16.760 1.326 -26.715 1.00 96.24 C +ATOM 1919 CZ TYR A 263 15.503 1.209 -27.341 1.00 96.24 C +ATOM 1920 OH TYR A 263 15.385 0.451 -28.459 1.00 96.24 O +ATOM 1921 N ASN A 264 15.253 6.696 -22.790 1.00 96.81 N +ATOM 1922 CA ASN A 264 14.666 7.478 -21.710 1.00 96.81 C +ATOM 1923 C ASN A 264 13.459 6.713 -21.175 1.00 96.81 C +ATOM 1924 O ASN A 264 12.468 6.530 -21.887 1.00 96.81 O +ATOM 1925 CB ASN A 264 14.273 8.869 -22.225 1.00 96.81 C +ATOM 1926 CG ASN A 264 15.463 9.689 -22.685 1.00 96.81 C +ATOM 1927 OD1 ASN A 264 16.608 9.450 -22.350 1.00 96.81 O +ATOM 1928 ND2 ASN A 264 15.227 10.695 -23.491 1.00 96.81 N +ATOM 1929 N VAL A 265 13.550 6.252 -19.931 1.00 96.86 N +ATOM 1930 CA VAL A 265 12.529 5.408 -19.311 1.00 96.86 C +ATOM 1931 C VAL A 265 11.708 6.229 -18.335 1.00 96.86 C +ATOM 1932 O VAL A 265 12.251 6.911 -17.468 1.00 96.86 O +ATOM 1933 CB VAL A 265 13.145 4.174 -18.637 1.00 96.86 C +ATOM 1934 CG1 VAL A 265 12.043 3.202 -18.198 1.00 96.86 C +ATOM 1935 CG2 VAL A 265 14.085 3.452 -19.610 1.00 96.86 C +ATOM 1936 N SER A 266 10.389 6.148 -18.461 1.00 97.12 N +ATOM 1937 CA SER A 266 9.436 6.788 -17.558 1.00 97.12 C +ATOM 1938 C SER A 266 8.305 5.834 -17.213 1.00 97.12 C +ATOM 1939 O SER A 266 8.003 4.902 -17.963 1.00 97.12 O +ATOM 1940 CB SER A 266 8.893 8.081 -18.169 1.00 97.12 C +ATOM 1941 OG SER A 266 8.154 7.816 -19.345 1.00 97.12 O +ATOM 1942 N ILE A 267 7.675 6.056 -16.064 1.00 96.80 N +ATOM 1943 CA ILE A 267 6.574 5.221 -15.603 1.00 96.80 C +ATOM 1944 C ILE A 267 5.424 6.051 -15.047 1.00 96.80 C +ATOM 1945 O ILE A 267 5.625 7.076 -14.398 1.00 96.80 O +ATOM 1946 CB ILE A 267 7.098 4.156 -14.627 1.00 96.80 C +ATOM 1947 CG1 ILE A 267 5.974 3.157 -14.318 1.00 96.80 C +ATOM 1948 CG2 ILE A 267 7.728 4.771 -13.368 1.00 96.80 C +ATOM 1949 CD1 ILE A 267 6.517 1.935 -13.610 1.00 96.80 C +ATOM 1950 N THR A 268 4.206 5.584 -15.298 1.00 96.43 N +ATOM 1951 CA THR A 268 2.966 6.130 -14.739 1.00 96.43 C +ATOM 1952 C THR A 268 2.242 5.053 -13.936 1.00 96.43 C +ATOM 1953 O THR A 268 2.322 3.868 -14.264 1.00 96.43 O +ATOM 1954 CB THR A 268 2.050 6.683 -15.839 1.00 96.43 C +ATOM 1955 OG1 THR A 268 1.788 5.698 -16.808 1.00 96.43 O +ATOM 1956 CG2 THR A 268 2.650 7.881 -16.569 1.00 96.43 C +ATOM 1957 N ALA A 269 1.540 5.456 -12.878 1.00 96.37 N +ATOM 1958 CA ALA A 269 0.663 4.598 -12.089 1.00 96.37 C +ATOM 1959 C ALA A 269 -0.797 4.967 -12.358 1.00 96.37 C +ATOM 1960 O ALA A 269 -1.128 6.146 -12.436 1.00 96.37 O +ATOM 1961 CB ALA A 269 1.014 4.753 -10.609 1.00 96.37 C +ATOM 1962 N SER A 270 -1.677 3.977 -12.481 1.00 94.66 N +ATOM 1963 CA SER A 270 -3.099 4.196 -12.754 1.00 94.66 C +ATOM 1964 C SER A 270 -3.998 3.474 -11.754 1.00 94.66 C +ATOM 1965 O SER A 270 -3.717 2.347 -11.337 1.00 94.66 O +ATOM 1966 CB SER A 270 -3.456 3.813 -14.194 1.00 94.66 C +ATOM 1967 OG SER A 270 -2.687 4.571 -15.112 1.00 94.66 O +ATOM 1968 N ASN A 271 -5.093 4.135 -11.385 1.00 91.37 N +ATOM 1969 CA ASN A 271 -6.188 3.597 -10.583 1.00 91.37 C +ATOM 1970 C ASN A 271 -7.515 4.017 -11.223 1.00 91.37 C +ATOM 1971 O ASN A 271 -7.794 5.215 -11.329 1.00 91.37 O +ATOM 1972 CB ASN A 271 -6.072 4.120 -9.143 1.00 91.37 C +ATOM 1973 CG ASN A 271 -7.142 3.560 -8.221 1.00 91.37 C +ATOM 1974 OD1 ASN A 271 -7.868 2.639 -8.555 1.00 91.37 O +ATOM 1975 ND2 ASN A 271 -7.288 4.110 -7.040 1.00 91.37 N +ATOM 1976 N ASN A 272 -8.324 3.045 -11.651 1.00 84.72 N +ATOM 1977 CA ASN A 272 -9.562 3.281 -12.396 1.00 84.72 C +ATOM 1978 C ASN A 272 -9.332 4.228 -13.596 1.00 84.72 C +ATOM 1979 O ASN A 272 -8.585 3.889 -14.512 1.00 84.72 O +ATOM 1980 CB ASN A 272 -10.665 3.726 -11.410 1.00 84.72 C +ATOM 1981 CG ASN A 272 -10.927 2.715 -10.308 1.00 84.72 C +ATOM 1982 OD1 ASN A 272 -10.887 1.511 -10.496 1.00 84.72 O +ATOM 1983 ND2 ASN A 272 -11.236 3.175 -9.119 1.00 84.72 N +ATOM 1984 N ASN A 273 -9.935 5.421 -13.574 1.00 84.69 N +ATOM 1985 CA ASN A 273 -9.850 6.416 -14.647 1.00 84.69 C +ATOM 1986 C ASN A 273 -8.756 7.475 -14.428 1.00 84.69 C +ATOM 1987 O ASN A 273 -8.644 8.395 -15.235 1.00 84.69 O +ATOM 1988 CB ASN A 273 -11.233 7.066 -14.837 1.00 84.69 C +ATOM 1989 CG ASN A 273 -12.278 6.126 -15.407 1.00 84.69 C +ATOM 1990 OD1 ASN A 273 -12.042 4.977 -15.734 1.00 84.69 O +ATOM 1991 ND2 ASN A 273 -13.495 6.596 -15.548 1.00 84.69 N +ATOM 1992 N CYS A 274 -7.968 7.376 -13.353 1.00 90.30 N +ATOM 1993 CA CYS A 274 -6.922 8.344 -13.047 1.00 90.30 C +ATOM 1994 C CYS A 274 -5.520 7.771 -13.219 1.00 90.30 C +ATOM 1995 O CYS A 274 -5.199 6.705 -12.692 1.00 90.30 O +ATOM 1996 CB CYS A 274 -7.125 8.923 -11.644 1.00 90.30 C +ATOM 1997 SG CYS A 274 -8.401 10.202 -11.537 1.00 90.30 S +ATOM 1998 N THR A 275 -4.664 8.541 -13.891 1.00 92.72 N +ATOM 1999 CA THR A 275 -3.256 8.216 -14.139 1.00 92.72 C +ATOM 2000 C THR A 275 -2.365 9.300 -13.548 1.00 92.72 C +ATOM 2001 O THR A 275 -2.592 10.489 -13.766 1.00 92.72 O +ATOM 2002 CB THR A 275 -2.994 8.042 -15.643 1.00 92.72 C +ATOM 2003 OG1 THR A 275 -3.809 7.011 -16.149 1.00 92.72 O +ATOM 2004 CG2 THR A 275 -1.554 7.656 -15.967 1.00 92.72 C +ATOM 2005 N SER A 276 -1.337 8.900 -12.804 1.00 93.75 N +ATOM 2006 CA SER A 276 -0.338 9.811 -12.255 1.00 93.75 C +ATOM 2007 C SER A 276 0.416 10.535 -13.376 1.00 93.75 C +ATOM 2008 O SER A 276 0.534 10.008 -14.486 1.00 93.75 O +ATOM 2009 CB SER A 276 0.653 9.046 -11.362 1.00 93.75 C +ATOM 2010 OG SER A 276 1.611 8.311 -12.113 1.00 93.75 O +ATOM 2011 N PRO A 277 1.034 11.693 -13.097 1.00 93.06 N +ATOM 2012 CA PRO A 277 2.098 12.197 -13.956 1.00 93.06 C +ATOM 2013 C PRO A 277 3.204 11.142 -14.137 1.00 93.06 C +ATOM 2014 O PRO A 277 3.344 10.220 -13.321 1.00 93.06 O +ATOM 2015 CB PRO A 277 2.608 13.473 -13.277 1.00 93.06 C +ATOM 2016 CG PRO A 277 1.446 13.894 -12.374 1.00 93.06 C +ATOM 2017 CD PRO A 277 0.839 12.560 -11.947 1.00 93.06 C +ATOM 2018 N ALA A 278 3.984 11.269 -15.209 1.00 94.53 N +ATOM 2019 CA ALA A 278 5.131 10.400 -15.443 1.00 94.53 C +ATOM 2020 C ALA A 278 6.232 10.646 -14.400 1.00 94.53 C +ATOM 2021 O ALA A 278 6.428 11.773 -13.938 1.00 94.53 O +ATOM 2022 CB ALA A 278 5.629 10.601 -16.879 1.00 94.53 C +ATOM 2023 N SER A 279 6.960 9.587 -14.041 1.00 95.98 N +ATOM 2024 CA SER A 279 8.167 9.687 -13.220 1.00 95.98 C +ATOM 2025 C SER A 279 9.227 10.570 -13.876 1.00 95.98 C +ATOM 2026 O SER A 279 9.204 10.813 -15.086 1.00 95.98 O +ATOM 2027 CB SER A 279 8.736 8.294 -12.923 1.00 95.98 C +ATOM 2028 OG SER A 279 9.322 7.729 -14.086 1.00 95.98 O +ATOM 2029 N GLN A 280 10.218 10.986 -13.084 1.00 93.93 N +ATOM 2030 CA GLN A 280 11.459 11.498 -13.657 1.00 93.93 C +ATOM 2031 C GLN A 280 12.039 10.458 -14.622 1.00 93.93 C +ATOM 2032 O GLN A 280 11.970 9.251 -14.359 1.00 93.93 O +ATOM 2033 CB GLN A 280 12.468 11.854 -12.559 1.00 93.93 C +ATOM 2034 CG GLN A 280 12.013 13.083 -11.757 1.00 93.93 C +ATOM 2035 CD GLN A 280 13.063 13.565 -10.760 1.00 93.93 C +ATOM 2036 OE1 GLN A 280 13.992 12.873 -10.387 1.00 93.93 O +ATOM 2037 NE2 GLN A 280 12.955 14.783 -10.277 1.00 93.93 N +ATOM 2038 N GLN A 281 12.554 10.936 -15.754 1.00 94.79 N +ATOM 2039 CA GLN A 281 13.155 10.070 -16.758 1.00 94.79 C +ATOM 2040 C GLN A 281 14.476 9.513 -16.226 1.00 94.79 C +ATOM 2041 O GLN A 281 15.307 10.261 -15.710 1.00 94.79 O +ATOM 2042 CB GLN A 281 13.352 10.819 -18.083 1.00 94.79 C +ATOM 2043 CG GLN A 281 12.011 11.141 -18.762 1.00 94.79 C +ATOM 2044 CD GLN A 281 12.166 11.871 -20.094 1.00 94.79 C +ATOM 2045 OE1 GLN A 281 13.240 12.246 -20.531 1.00 94.79 O +ATOM 2046 NE2 GLN A 281 11.086 12.111 -20.803 1.00 94.79 N +ATOM 2047 N VAL A 282 14.658 8.202 -16.361 1.00 95.86 N +ATOM 2048 CA VAL A 282 15.908 7.509 -16.040 1.00 95.86 C +ATOM 2049 C VAL A 282 16.493 6.971 -17.337 1.00 95.86 C +ATOM 2050 O VAL A 282 15.803 6.294 -18.100 1.00 95.86 O +ATOM 2051 CB VAL A 282 15.697 6.395 -14.999 1.00 95.86 C +ATOM 2052 CG1 VAL A 282 17.033 5.755 -14.596 1.00 95.86 C +ATOM 2053 CG2 VAL A 282 15.041 6.938 -13.723 1.00 95.86 C +ATOM 2054 N ASN A 283 17.761 7.278 -17.593 1.00 96.09 N +ATOM 2055 CA ASN A 283 18.428 6.862 -18.819 1.00 96.09 C +ATOM 2056 C ASN A 283 18.933 5.425 -18.682 1.00 96.09 C +ATOM 2057 O ASN A 283 19.630 5.088 -17.724 1.00 96.09 O +ATOM 2058 CB ASN A 283 19.561 7.838 -19.168 1.00 96.09 C +ATOM 2059 CG ASN A 283 19.070 9.237 -19.499 1.00 96.09 C +ATOM 2060 OD1 ASN A 283 17.895 9.547 -19.506 1.00 96.09 O +ATOM 2061 ND2 ASN A 283 19.975 10.151 -19.751 1.00 96.09 N +ATOM 2062 N PHE A 284 18.623 4.597 -19.674 1.00 95.39 N +ATOM 2063 CA PHE A 284 19.153 3.251 -19.814 1.00 95.39 C +ATOM 2064 C PHE A 284 20.067 3.173 -21.031 1.00 95.39 C +ATOM 2065 O PHE A 284 19.651 3.456 -22.155 1.00 95.39 O +ATOM 2066 CB PHE A 284 18.007 2.248 -19.918 1.00 95.39 C +ATOM 2067 CG PHE A 284 18.486 0.815 -19.960 1.00 95.39 C +ATOM 2068 CD1 PHE A 284 18.529 0.128 -21.186 1.00 95.39 C +ATOM 2069 CD2 PHE A 284 18.936 0.183 -18.784 1.00 95.39 C +ATOM 2070 CE1 PHE A 284 19.021 -1.186 -21.236 1.00 95.39 C +ATOM 2071 CE2 PHE A 284 19.422 -1.135 -18.834 1.00 95.39 C +ATOM 2072 CZ PHE A 284 19.467 -1.817 -20.063 1.00 95.39 C +ATOM 2073 N HIS A 285 21.313 2.769 -20.806 1.00 93.79 N +ATOM 2074 CA HIS A 285 22.284 2.553 -21.869 1.00 93.79 C +ATOM 2075 C HIS A 285 22.239 1.091 -22.297 1.00 93.79 C +ATOM 2076 O HIS A 285 22.503 0.193 -21.495 1.00 93.79 O +ATOM 2077 CB HIS A 285 23.677 2.975 -21.392 1.00 93.79 C +ATOM 2078 CG HIS A 285 23.782 4.460 -21.156 1.00 93.79 C +ATOM 2079 ND1 HIS A 285 24.244 5.385 -22.061 1.00 93.79 N +ATOM 2080 CD2 HIS A 285 23.401 5.148 -20.034 1.00 93.79 C +ATOM 2081 CE1 HIS A 285 24.141 6.601 -21.502 1.00 93.79 C +ATOM 2082 NE2 HIS A 285 23.634 6.509 -20.264 1.00 93.79 N +ATOM 2083 N THR A 286 21.907 0.856 -23.562 1.00 92.25 N +ATOM 2084 CA THR A 286 21.958 -0.491 -24.133 1.00 92.25 C +ATOM 2085 C THR A 286 23.397 -0.923 -24.389 1.00 92.25 C +ATOM 2086 O THR A 286 24.335 -0.121 -24.390 1.00 92.25 O +ATOM 2087 CB THR A 286 21.132 -0.606 -25.416 1.00 92.25 C +ATOM 2088 OG1 THR A 286 21.639 0.280 -26.374 1.00 92.25 O +ATOM 2089 CG2 THR A 286 19.664 -0.294 -25.147 1.00 92.25 C +ATOM 2090 N VAL A 287 23.581 -2.225 -24.600 1.00 89.62 N +ATOM 2091 CA VAL A 287 24.882 -2.776 -24.981 1.00 89.62 C +ATOM 2092 C VAL A 287 25.316 -2.237 -26.352 1.00 89.62 C +ATOM 2093 O VAL A 287 24.457 -1.993 -27.203 1.00 89.62 O +ATOM 2094 CB VAL A 287 24.877 -4.314 -24.969 1.00 89.62 C +ATOM 2095 CG1 VAL A 287 24.624 -4.831 -23.547 1.00 89.62 C +ATOM 2096 CG2 VAL A 287 23.836 -4.930 -25.915 1.00 89.62 C +ATOM 2097 N PRO A 288 26.626 -2.060 -26.606 1.00 89.96 N +ATOM 2098 CA PRO A 288 27.122 -1.675 -27.924 1.00 89.96 C +ATOM 2099 C PRO A 288 26.655 -2.637 -29.021 1.00 89.96 C +ATOM 2100 O PRO A 288 26.510 -3.838 -28.788 1.00 89.96 O +ATOM 2101 CB PRO A 288 28.649 -1.668 -27.811 1.00 89.96 C +ATOM 2102 CG PRO A 288 28.893 -1.437 -26.321 1.00 89.96 C +ATOM 2103 CD PRO A 288 27.728 -2.171 -25.663 1.00 89.96 C +ATOM 2104 N CYS A 289 26.451 -2.117 -30.231 1.00 90.36 N +ATOM 2105 CA CYS A 289 26.151 -2.962 -31.381 1.00 90.36 C +ATOM 2106 C CYS A 289 27.323 -3.869 -31.750 1.00 90.36 C +ATOM 2107 O CYS A 289 28.488 -3.531 -31.531 1.00 90.36 O +ATOM 2108 CB CYS A 289 25.725 -2.109 -32.577 1.00 90.36 C +ATOM 2109 SG CYS A 289 24.120 -1.312 -32.382 1.00 90.36 S +ATOM 2110 N ALA A 290 26.997 -5.009 -32.362 1.00 88.26 N +ATOM 2111 CA ALA A 290 27.998 -5.844 -33.004 1.00 88.26 C +ATOM 2112 C ALA A 290 28.744 -5.015 -34.070 1.00 88.26 C +ATOM 2113 O ALA A 290 28.086 -4.302 -34.837 1.00 88.26 O +ATOM 2114 CB ALA A 290 27.324 -7.078 -33.611 1.00 88.26 C +ATOM 2115 N PRO A 291 30.085 -5.086 -34.128 1.00 89.12 N +ATOM 2116 CA PRO A 291 30.854 -4.372 -35.136 1.00 89.12 C +ATOM 2117 C PRO A 291 30.380 -4.720 -36.557 1.00 89.12 C +ATOM 2118 O PRO A 291 30.238 -5.909 -36.866 1.00 89.12 O +ATOM 2119 CB PRO A 291 32.303 -4.790 -34.908 1.00 89.12 C +ATOM 2120 CG PRO A 291 32.356 -5.206 -33.444 1.00 89.12 C +ATOM 2121 CD PRO A 291 30.968 -5.790 -33.209 1.00 89.12 C +ATOM 2122 N PRO A 292 30.101 -3.728 -37.421 1.00 89.18 N +ATOM 2123 CA PRO A 292 29.670 -3.997 -38.784 1.00 89.18 C +ATOM 2124 C PRO A 292 30.833 -4.547 -39.622 1.00 89.18 C +ATOM 2125 O PRO A 292 31.994 -4.298 -39.335 1.00 89.18 O +ATOM 2126 CB PRO A 292 29.143 -2.658 -39.307 1.00 89.18 C +ATOM 2127 CG PRO A 292 29.995 -1.633 -38.557 1.00 89.18 C +ATOM 2128 CD PRO A 292 30.232 -2.293 -37.198 1.00 89.18 C +ATOM 2129 N ASN A 293 30.522 -5.277 -40.696 1.00 89.26 N +ATOM 2130 CA ASN A 293 31.476 -5.608 -41.767 1.00 89.26 C +ATOM 2131 C ASN A 293 32.832 -6.184 -41.314 1.00 89.26 C +ATOM 2132 O ASN A 293 33.862 -5.859 -41.908 1.00 89.26 O +ATOM 2133 CB ASN A 293 31.640 -4.382 -42.680 1.00 89.26 C +ATOM 2134 CG ASN A 293 30.336 -3.937 -43.297 1.00 89.26 C +ATOM 2135 OD1 ASN A 293 29.482 -4.729 -43.660 1.00 89.26 O +ATOM 2136 ND2 ASN A 293 30.134 -2.649 -43.428 1.00 89.26 N +ATOM 2137 N LEU A 294 32.835 -7.065 -40.306 1.00 90.46 N +ATOM 2138 CA LEU A 294 34.054 -7.741 -39.869 1.00 90.46 C +ATOM 2139 C LEU A 294 34.741 -8.419 -41.064 1.00 90.46 C +ATOM 2140 O LEU A 294 34.205 -9.360 -41.654 1.00 90.46 O +ATOM 2141 CB LEU A 294 33.732 -8.757 -38.760 1.00 90.46 C +ATOM 2142 CG LEU A 294 34.981 -9.494 -38.232 1.00 90.46 C +ATOM 2143 CD1 LEU A 294 35.930 -8.555 -37.484 1.00 90.46 C +ATOM 2144 CD2 LEU A 294 34.566 -10.616 -37.281 1.00 90.46 C +ATOM 2145 N SER A 295 35.945 -7.964 -41.393 1.00 90.78 N +ATOM 2146 CA SER A 295 36.771 -8.545 -42.444 1.00 90.78 C +ATOM 2147 C SER A 295 38.152 -8.906 -41.908 1.00 90.78 C +ATOM 2148 O SER A 295 38.716 -8.224 -41.048 1.00 90.78 O +ATOM 2149 CB SER A 295 36.814 -7.644 -43.680 1.00 90.78 C +ATOM 2150 OG SER A 295 37.696 -6.565 -43.511 1.00 90.78 O +ATOM 2151 N VAL A 296 38.682 -10.028 -42.398 1.00 91.50 N +ATOM 2152 CA VAL A 296 39.953 -10.599 -41.949 1.00 91.50 C +ATOM 2153 C VAL A 296 40.877 -10.739 -43.151 1.00 91.50 C +ATOM 2154 O VAL A 296 40.600 -11.512 -44.066 1.00 91.50 O +ATOM 2155 CB VAL A 296 39.746 -11.951 -41.233 1.00 91.50 C +ATOM 2156 CG1 VAL A 296 41.072 -12.463 -40.654 1.00 91.50 C +ATOM 2157 CG2 VAL A 296 38.738 -11.843 -40.079 1.00 91.50 C +ATOM 2158 N ALA A 297 41.988 -10.007 -43.136 1.00 91.28 N +ATOM 2159 CA ALA A 297 43.060 -10.121 -44.116 1.00 91.28 C +ATOM 2160 C ALA A 297 44.221 -10.916 -43.506 1.00 91.28 C +ATOM 2161 O ALA A 297 44.866 -10.468 -42.558 1.00 91.28 O +ATOM 2162 CB ALA A 297 43.467 -8.716 -44.571 1.00 91.28 C +ATOM 2163 N VAL A 298 44.478 -12.117 -44.026 1.00 91.86 N +ATOM 2164 CA VAL A 298 45.542 -13.000 -43.527 1.00 91.86 C +ATOM 2165 C VAL A 298 46.807 -12.809 -44.358 1.00 91.86 C +ATOM 2166 O VAL A 298 46.802 -13.055 -45.562 1.00 91.86 O +ATOM 2167 CB VAL A 298 45.102 -14.476 -43.513 1.00 91.86 C +ATOM 2168 CG1 VAL A 298 46.197 -15.371 -42.915 1.00 91.86 C +ATOM 2169 CG2 VAL A 298 43.828 -14.667 -42.677 1.00 91.86 C +ATOM 2170 N GLN A 299 47.905 -12.436 -43.705 1.00 90.20 N +ATOM 2171 CA GLN A 299 49.223 -12.330 -44.321 1.00 90.20 C +ATOM 2172 C GLN A 299 50.029 -13.598 -44.019 1.00 90.20 C +ATOM 2173 O GLN A 299 50.573 -13.777 -42.925 1.00 90.20 O +ATOM 2174 CB GLN A 299 49.911 -11.041 -43.844 1.00 90.20 C +ATOM 2175 CG GLN A 299 51.133 -10.681 -44.708 1.00 90.20 C +ATOM 2176 CD GLN A 299 50.768 -10.235 -46.125 1.00 90.20 C +ATOM 2177 OE1 GLN A 299 49.622 -9.998 -46.466 1.00 90.20 O +ATOM 2178 NE2 GLN A 299 51.722 -10.122 -47.020 1.00 90.20 N +ATOM 2179 N CYS A 300 50.090 -14.503 -45.001 1.00 89.51 N +ATOM 2180 CA CYS A 300 50.715 -15.819 -44.837 1.00 89.51 C +ATOM 2181 C CYS A 300 52.227 -15.730 -44.573 1.00 89.51 C +ATOM 2182 O CYS A 300 52.747 -16.503 -43.768 1.00 89.51 O +ATOM 2183 CB CYS A 300 50.417 -16.680 -46.073 1.00 89.51 C +ATOM 2184 SG CYS A 300 48.642 -17.068 -46.156 1.00 89.51 S +ATOM 2185 N ASP A 301 52.913 -14.761 -45.186 1.00 90.56 N +ATOM 2186 CA ASP A 301 54.372 -14.615 -45.084 1.00 90.56 C +ATOM 2187 C ASP A 301 54.829 -14.258 -43.665 1.00 90.56 C +ATOM 2188 O ASP A 301 55.810 -14.797 -43.155 1.00 90.56 O +ATOM 2189 CB ASP A 301 54.849 -13.527 -46.057 1.00 90.56 C +ATOM 2190 CG ASP A 301 54.476 -13.819 -47.510 1.00 90.56 C +ATOM 2191 OD1 ASP A 301 54.482 -15.011 -47.887 1.00 90.56 O +ATOM 2192 OD2 ASP A 301 54.130 -12.837 -48.200 1.00 90.56 O +ATOM 2193 N THR A 302 54.088 -13.370 -43.000 1.00 91.35 N +ATOM 2194 CA THR A 302 54.384 -12.898 -41.640 1.00 91.35 C +ATOM 2195 C THR A 302 53.663 -13.704 -40.564 1.00 91.35 C +ATOM 2196 O THR A 302 53.911 -13.487 -39.380 1.00 91.35 O +ATOM 2197 CB THR A 302 54.033 -11.412 -41.497 1.00 91.35 C +ATOM 2198 OG1 THR A 302 52.711 -11.206 -41.928 1.00 91.35 O +ATOM 2199 CG2 THR A 302 54.925 -10.534 -42.375 1.00 91.35 C +ATOM 2200 N ARG A 303 52.778 -14.635 -40.952 1.00 88.38 N +ATOM 2201 CA ARG A 303 51.877 -15.370 -40.046 1.00 88.38 C +ATOM 2202 C ARG A 303 51.030 -14.436 -39.170 1.00 88.38 C +ATOM 2203 O ARG A 303 50.785 -14.728 -38.002 1.00 88.38 O +ATOM 2204 CB ARG A 303 52.656 -16.400 -39.208 1.00 88.38 C +ATOM 2205 CG ARG A 303 53.488 -17.378 -40.042 1.00 88.38 C +ATOM 2206 CD ARG A 303 54.209 -18.331 -39.087 1.00 88.38 C +ATOM 2207 NE ARG A 303 55.015 -19.318 -39.822 1.00 88.38 N +ATOM 2208 CZ ARG A 303 55.715 -20.300 -39.287 1.00 88.38 C +ATOM 2209 NH1 ARG A 303 55.767 -20.482 -37.995 1.00 88.38 N +ATOM 2210 NH2 ARG A 303 56.378 -21.124 -40.047 1.00 88.38 N +ATOM 2211 N THR A 304 50.583 -13.311 -39.726 1.00 93.03 N +ATOM 2212 CA THR A 304 49.735 -12.328 -39.032 1.00 93.03 C +ATOM 2213 C THR A 304 48.372 -12.214 -39.707 1.00 93.03 C +ATOM 2214 O THR A 304 48.255 -12.432 -40.909 1.00 93.03 O +ATOM 2215 CB THR A 304 50.402 -10.946 -38.938 1.00 93.03 C +ATOM 2216 OG1 THR A 304 50.744 -10.450 -40.212 1.00 93.03 O +ATOM 2217 CG2 THR A 304 51.685 -10.973 -38.109 1.00 93.03 C +ATOM 2218 N ALA A 305 47.343 -11.826 -38.956 1.00 91.49 N +ATOM 2219 CA ALA A 305 46.032 -11.480 -39.501 1.00 91.49 C +ATOM 2220 C ALA A 305 45.652 -10.059 -39.072 1.00 91.49 C +ATOM 2221 O ALA A 305 45.805 -9.701 -37.905 1.00 91.49 O +ATOM 2222 CB ALA A 305 45.000 -12.523 -39.057 1.00 91.49 C +ATOM 2223 N THR A 306 45.158 -9.261 -40.013 1.00 90.74 N +ATOM 2224 CA THR A 306 44.626 -7.920 -39.767 1.00 90.74 C +ATOM 2225 C THR A 306 43.107 -7.995 -39.805 1.00 90.74 C +ATOM 2226 O THR A 306 42.529 -8.436 -40.797 1.00 90.74 O +ATOM 2227 CB THR A 306 45.159 -6.913 -40.796 1.00 90.74 C +ATOM 2228 OG1 THR A 306 46.569 -6.944 -40.814 1.00 90.74 O +ATOM 2229 CG2 THR A 306 44.758 -5.477 -40.461 1.00 90.74 C +ATOM 2230 N LEU A 307 42.465 -7.589 -38.712 1.00 92.04 N +ATOM 2231 CA LEU A 307 41.013 -7.507 -38.601 1.00 92.04 C +ATOM 2232 C LEU A 307 40.585 -6.051 -38.819 1.00 92.04 C +ATOM 2233 O LEU A 307 41.249 -5.142 -38.323 1.00 92.04 O +ATOM 2234 CB LEU A 307 40.541 -8.040 -37.234 1.00 92.04 C +ATOM 2235 CG LEU A 307 40.768 -9.546 -36.986 1.00 92.04 C +ATOM 2236 CD1 LEU A 307 42.170 -9.869 -36.454 1.00 92.04 C +ATOM 2237 CD2 LEU A 307 39.777 -10.054 -35.938 1.00 92.04 C +ATOM 2238 N SER A 308 39.486 -5.833 -39.537 1.00 89.41 N +ATOM 2239 CA SER A 308 38.831 -4.523 -39.648 1.00 89.41 C +ATOM 2240 C SER A 308 37.321 -4.667 -39.499 1.00 89.41 C +ATOM 2241 O SER A 308 36.767 -5.705 -39.866 1.00 89.41 O +ATOM 2242 CB SER A 308 39.210 -3.810 -40.949 1.00 89.41 C +ATOM 2243 OG SER A 308 38.791 -4.528 -42.086 1.00 89.41 O +ATOM 2244 N TRP A 309 36.691 -3.659 -38.903 1.00 89.27 N +ATOM 2245 CA TRP A 309 35.261 -3.558 -38.618 1.00 89.27 C +ATOM 2246 C TRP A 309 34.869 -2.083 -38.479 1.00 89.27 C +ATOM 2247 O TRP A 309 35.792 -1.258 -38.271 1.00 89.27 O +ATOM 2248 CB TRP A 309 34.939 -4.334 -37.335 1.00 89.27 C +ATOM 2249 CG TRP A 309 35.600 -3.824 -36.086 1.00 89.27 C +ATOM 2250 CD1 TRP A 309 35.164 -2.783 -35.343 1.00 89.27 C +ATOM 2251 CD2 TRP A 309 36.871 -4.219 -35.490 1.00 89.27 C +ATOM 2252 NE1 TRP A 309 36.010 -2.573 -34.274 1.00 89.27 N +ATOM 2253 CE2 TRP A 309 37.101 -3.411 -34.335 1.00 89.27 C +ATOM 2254 CE3 TRP A 309 37.880 -5.143 -35.838 1.00 89.27 C +ATOM 2255 CZ2 TRP A 309 38.258 -3.526 -33.553 1.00 89.27 C +ATOM 2256 CZ3 TRP A 309 39.055 -5.251 -35.069 1.00 89.27 C +ATOM 2257 CH2 TRP A 309 39.244 -4.452 -33.928 1.00 89.27 C +ATOM 2258 OXT TRP A 309 33.657 -1.803 -38.567 1.00 89.27 O +TER +END diff --git a/mmtbx/regression/pdbs/test1.cif b/mmtbx/regression/pdbs/test1.cif new file mode 100644 index 0000000000..07bb022ab2 --- /dev/null +++ b/mmtbx/regression/pdbs/test1.cif @@ -0,0 +1,2307 @@ +data_default +loop_ + _struct_asym.id + A + +loop_ + _chem_comp.id + ALA + ARG + ASN + ASP + CYS + GLN + GLU + GLY + HIS + ILE + LEU + LYS + MET + PHE + PRO + SER + THR + TRP + TYR + VAL + +loop_ + _atom_site.group_PDB + _atom_site.id + _atom_site.label_atom_id + _atom_site.label_alt_id + _atom_site.label_comp_id + _atom_site.auth_asym_id + _atom_site.auth_seq_id + _atom_site.pdbx_PDB_ins_code + _atom_site.Cartn_x + _atom_site.Cartn_y + _atom_site.Cartn_z + _atom_site.occupancy + _atom_site.B_iso_or_equiv + _atom_site.type_symbol + _atom_site.pdbx_formal_charge + _atom_site.label_asym_id + _atom_site.label_entity_id + _atom_site.label_seq_id + _atom_site.pdbx_PDB_model_num + ATOM 1 N . SER A 1 ? 2.97400 -27.45800 18.52400 1.000 72.44000 N ? A ? 1 0 + ATOM 2 CA . SER A 1 ? 3.37100 -28.05400 17.23900 1.000 72.44000 C ? A ? 1 0 + ATOM 3 C . SER A 1 ? 3.69400 -29.50800 17.47000 1.000 72.44000 C ? A ? 1 0 + ATOM 4 O . SER A 1 ? 4.31700 -29.81100 18.48100 1.000 72.44000 O ? A ? 1 0 + ATOM 5 CB . SER A 1 ? 4.57400 -27.32000 16.65500 1.000 72.44000 C ? A ? 1 0 + ATOM 6 OG . SER A 1 ? 4.28400 -25.93700 16.72100 1.000 72.44000 O ? A ? 1 0 + ATOM 7 N . TYR A 2 ? 3.23900 -30.38100 16.58400 1.000 79.50000 N ? A ? 2 0 + ATOM 8 CA . TYR A 2 ? 3.48500 -31.81600 16.61700 1.000 79.50000 C ? A ? 2 0 + ATOM 9 C . TYR A 2 ? 4.24800 -32.20100 15.35300 1.000 79.50000 C ? A ? 2 0 + ATOM 10 O . TYR A 2 ? 4.01300 -31.63100 14.28800 1.000 79.50000 O ? A ? 2 0 + ATOM 11 CB . TYR A 2 ? 2.15800 -32.57900 16.72700 1.000 79.50000 C ? A ? 2 0 + ATOM 12 CG . TYR A 2 ? 1.35500 -32.24100 17.96900 1.000 79.50000 C ? A ? 2 0 + ATOM 13 CD1 . TYR A 2 ? 1.58500 -32.94900 19.16300 1.000 79.50000 C ? A ? 2 0 + ATOM 14 CD2 . TYR A 2 ? 0.38500 -31.21800 17.93000 1.000 79.50000 C ? A ? 2 0 + ATOM 15 CE1 . TYR A 2 ? 0.84800 -32.64100 20.32200 1.000 79.50000 C ? A ? 2 0 + ATOM 16 CE2 . TYR A 2 ? -0.34400 -30.89700 19.09200 1.000 79.50000 C ? A ? 2 0 + ATOM 17 CZ . TYR A 2 ? -0.11800 -31.61200 20.28700 1.000 79.50000 C ? A ? 2 0 + ATOM 18 OH . TYR A 2 ? -0.83000 -31.30200 21.40000 1.000 79.50000 O ? A ? 2 0 + ATOM 19 N . SER A 3 ? 5.16400 -33.15200 15.48000 1.000 85.13000 N ? A ? 3 0 + ATOM 20 CA . SER A 3 ? 5.85200 -33.75600 14.34600 1.000 85.13000 C ? A ? 3 0 + ATOM 21 C . SER A 3 ? 5.25200 -35.14300 14.15100 1.000 85.13000 C ? A ? 3 0 + ATOM 22 O . SER A 3 ? 5.32600 -35.96600 15.06300 1.000 85.13000 O ? A ? 3 0 + ATOM 23 CB . SER A 3 ? 7.35300 -33.79500 14.63000 1.000 85.13000 C ? A ? 3 0 + ATOM 24 OG . SER A 3 ? 8.06100 -33.77900 13.42000 1.000 85.13000 O ? A ? 3 0 + ATOM 25 N . VAL A 4 ? 4.56900 -35.36300 13.02700 1.000 88.29000 N ? A ? 4 0 + ATOM 26 CA . VAL A 4 ? 3.86100 -36.61800 12.74200 1.000 88.29000 C ? A ? 4 0 + ATOM 27 C . VAL A 4 ? 4.67500 -37.42700 11.74500 1.000 88.29000 C ? A ? 4 0 + ATOM 28 O . VAL A 4 ? 5.02600 -36.93700 10.67000 1.000 88.29000 O ? A ? 4 0 + ATOM 29 CB . VAL A 4 ? 2.42300 -36.37300 12.24300 1.000 88.29000 C ? A ? 4 0 + ATOM 30 CG1 . VAL A 4 ? 1.68100 -37.69200 11.97700 1.000 88.29000 C ? A ? 4 0 + ATOM 31 CG2 . VAL A 4 ? 1.60600 -35.59600 13.28500 1.000 88.29000 C ? A ? 4 0 + ATOM 32 N . THR A 5 ? 4.95600 -38.67400 12.10400 1.000 91.73000 N ? A ? 5 0 + ATOM 33 CA . THR A 5 ? 5.56100 -39.68400 11.23800 1.000 91.73000 C ? A ? 5 0 + ATOM 34 C . THR A 5 ? 4.63900 -40.89400 11.16800 1.000 91.73000 C ? A ? 5 0 + ATOM 35 O . THR A 5 ? 3.86300 -41.15600 12.08700 1.000 91.73000 O ? A ? 5 0 + ATOM 36 CB . THR A 5 ? 6.95600 -40.10200 11.72700 1.000 91.73000 C ? A ? 5 0 + ATOM 37 OG1 . THR A 5 ? 6.91300 -40.51900 13.07100 1.000 91.73000 O ? A ? 5 0 + ATOM 38 CG2 . THR A 5 ? 7.96400 -38.95900 11.64700 1.000 91.73000 C ? A ? 5 0 + ATOM 39 N . VAL A 6 ? 4.69900 -41.62200 10.05600 1.000 91.60000 N ? A ? 6 0 + ATOM 40 CA . VAL A 6 ? 3.92700 -42.84900 9.85000 1.000 91.60000 C ? A ? 6 0 + ATOM 41 C . VAL A 6 ? 4.90000 -44.00500 9.66900 1.000 91.60000 C ? A ? 6 0 + ATOM 42 O . VAL A 6 ? 5.83000 -43.91700 8.86600 1.000 91.60000 O ? A ? 6 0 + ATOM 43 CB . VAL A 6 ? 2.95900 -42.70700 8.65900 1.000 91.60000 C ? A ? 6 0 + ATOM 44 CG1 . VAL A 6 ? 2.12300 -43.97800 8.45700 1.000 91.60000 C ? A ? 6 0 + ATOM 45 CG2 . VAL A 6 ? 1.98500 -41.53800 8.87100 1.000 91.60000 C ? A ? 6 0 + ATOM 46 N . THR A 7 ? 4.67900 -45.08800 10.40700 1.000 91.25000 N ? A ? 7 0 + ATOM 47 CA . THR A 7 ? 5.34800 -46.37900 10.22700 1.000 91.25000 C ? A ? 7 0 + ATOM 48 C . THR A 7 ? 4.32100 -47.40400 9.75900 1.000 91.25000 C ? A ? 7 0 + ATOM 49 O . THR A 7 ? 3.16200 -47.38800 10.17500 1.000 91.25000 O ? A ? 7 0 + ATOM 50 CB . THR A 7 ? 6.05200 -46.85300 11.51000 1.000 91.25000 C ? A ? 7 0 + ATOM 51 OG1 . THR A 7 ? 5.19600 -46.74600 12.62100 1.000 91.25000 O ? A ? 7 0 + ATOM 52 CG2 . THR A 7 ? 7.28900 -46.01300 11.81500 1.000 91.25000 C ? A ? 7 0 + ATOM 53 N . SER A 8 ? 4.72500 -48.28300 8.84600 1.000 88.71000 N ? A ? 8 0 + ATOM 54 CA . SER A 8 ? 3.90300 -49.42000 8.42500 1.000 88.71000 C ? A ? 8 0 + ATOM 55 C . SER A 8 ? 4.27800 -50.65400 9.24200 1.000 88.71000 C ? A ? 8 0 + ATOM 56 O . SER A 8 ? 5.45900 -50.87000 9.51900 1.000 88.71000 O ? A ? 8 0 + ATOM 57 CB . SER A 8 ? 4.01100 -49.64900 6.91500 1.000 88.71000 C ? A ? 8 0 + ATOM 58 OG . SER A 8 ? 5.32600 -49.97100 6.51400 1.000 88.71000 O ? A ? 8 0 + ATOM 59 N . LEU A 9 ? 3.27600 -51.44800 9.62600 1.000 91.87000 N ? A ? 9 0 + ATOM 60 CA . LEU A 9 ? 3.44300 -52.63400 10.46600 1.000 91.87000 C ? A ? 9 0 + ATOM 61 C . LEU A 9 ? 2.85000 -53.85900 9.76100 1.000 91.87000 C ? A ? 9 0 + ATOM 62 O . LEU A 9 ? 1.70300 -53.83200 9.30800 1.000 91.87000 O ? A ? 9 0 + ATOM 63 CB . LEU A 9 ? 2.82500 -52.33900 11.84900 1.000 91.87000 C ? A ? 9 0 + ATOM 64 CG . LEU A 9 ? 3.26400 -53.32300 12.95700 1.000 91.87000 C ? A ? 9 0 + ATOM 65 CD1 . LEU A 9 ? 3.60500 -52.56800 14.24100 1.000 91.87000 C ? A ? 9 0 + ATOM 66 CD2 . LEU A 9 ? 2.14700 -54.31100 13.29700 1.000 91.87000 C ? A ? 9 0 + ATOM 67 N . ARG A 10 ? 3.63600 -54.93500 9.64400 1.000 89.14000 N ? A ? 10 0 + ATOM 68 CA . ARG A 10 ? 3.18300 -56.23900 9.13100 1.000 89.14000 C ? A ? 10 0 + ATOM 69 C . ARG A 10 ? 3.75400 -57.34600 10.01500 1.000 89.14000 C ? A ? 10 0 + ATOM 70 O . ARG A 10 ? 4.94300 -57.64400 9.93200 1.000 89.14000 O ? A ? 10 0 + ATOM 71 CB . ARG A 10 ? 3.58200 -56.40200 7.64800 1.000 89.14000 C ? A ? 10 0 + ATOM 72 CG . ARG A 10 ? 3.14200 -57.76700 7.08400 1.000 89.14000 C ? A ? 10 0 + ATOM 73 CD . ARG A 10 ? 3.58600 -57.99500 5.63200 1.000 89.14000 C ? A ? 10 0 + ATOM 74 NE . ARG A 10 ? 2.66400 -57.39400 4.64800 1.000 89.14000 N ? A ? 10 0 + ATOM 75 CZ . ARG A 10 ? 2.74200 -57.52700 3.33500 1.000 89.14000 C ? A ? 10 0 + ATOM 76 NH1 . ARG A 10 ? 3.72800 -58.16600 2.76600 1.000 89.14000 N ? A ? 10 0 + ATOM 77 NH2 . ARG A 10 ? 1.82600 -57.01800 2.56000 1.000 89.14000 N ? A ? 10 0 + ATOM 78 N . GLY A 11 ? 2.89400 -57.98100 10.81100 1.000 88.64000 N ? A ? 11 0 + ATOM 79 CA . GLY A 11 ? 3.33400 -58.94000 11.82900 1.000 88.64000 C ? A ? 11 0 + ATOM 80 C . GLY A 11 ? 4.23200 -58.24400 12.85200 1.000 88.64000 C ? A ? 11 0 + ATOM 81 O . GLY A 11 ? 3.86600 -57.18100 13.34100 1.000 88.64000 O ? A ? 11 0 + ATOM 82 N . ASP A 12 ? 5.42000 -58.80000 13.08500 1.000 87.38000 N ? A ? 12 0 + ATOM 83 CA . ASP A 12 ? 6.42400 -58.25300 14.01100 1.000 87.38000 C ? A ? 12 0 + ATOM 84 C . ASP A 12 ? 7.45600 -57.32800 13.32800 1.000 87.38000 C ? A ? 12 0 + ATOM 85 O . ASP A 12 ? 8.46800 -56.96700 13.92600 1.000 87.38000 O ? A ? 12 0 + ATOM 86 CB . ASP A 12 ? 7.12000 -59.41200 14.74500 1.000 87.38000 C ? A ? 12 0 + ATOM 87 CG . ASP A 12 ? 6.14500 -60.33800 15.47700 1.000 87.38000 C ? A ? 12 0 + ATOM 88 OD1 . ASP A 12 ? 5.19100 -59.82400 16.10100 1.000 87.38000 O ? A ? 12 0 + ATOM 89 OD2 . ASP A 12 ? 6.34500 -61.56900 15.37000 1.000 87.38000 O ? A ? 12 0 + ATOM 90 N . CYS A 13 ? 7.25800 -56.96600 12.05400 1.000 86.80000 N ? A ? 13 0 + ATOM 91 CA . CYS A 13 ? 8.16700 -56.08300 11.32100 1.000 86.80000 C ? A ? 13 0 + ATOM 92 C . CYS A 13 ? 7.59900 -54.66200 11.19500 1.000 86.80000 C ? A ? 13 0 + ATOM 93 O . CYS A 13 ? 6.49000 -54.47300 10.68400 1.000 86.80000 O ? A ? 13 0 + ATOM 94 CB . CYS A 13 ? 8.48700 -56.68200 9.94300 1.000 86.80000 C ? A ? 13 0 + ATOM 95 SG . CYS A 13 ? 9.32400 -58.28700 10.10400 1.000 86.80000 S ? A ? 13 0 + ATOM 96 N . GLU A 14 ? 8.40500 -53.66800 11.57700 1.000 90.65000 N ? A ? 14 0 + ATOM 97 CA . GLU A 14 ? 8.13200 -52.23600 11.40600 1.000 90.65000 C ? A ? 14 0 + ATOM 98 C . GLU A 14 ? 9.01900 -51.63300 10.30700 1.000 90.65000 C ? A ? 14 0 + ATOM 99 O . GLU A 14 ? 10.20100 -51.96600 10.18700 1.000 90.65000 O ? A ? 14 0 + ATOM 100 CB . GLU A 14 ? 8.34400 -51.47300 12.72500 1.000 90.65000 C ? A ? 14 0 + ATOM 101 CG . GLU A 14 ? 7.41800 -51.96300 13.84700 1.000 90.65000 C ? A ? 14 0 + ATOM 102 CD . GLU A 14 ? 7.43400 -51.06200 15.09600 1.000 90.65000 C ? A ? 14 0 + ATOM 103 OE1 . GLU A 14 ? 6.54900 -51.26300 15.95700 1.000 90.65000 O ? A ? 14 0 + ATOM 104 OE2 . GLU A 14 ? 8.30200 -50.16200 15.17700 1.000 90.65000 O ? A ? 14 0 + ATOM 105 N . SER A 15 ? 8.46300 -50.73300 9.49200 1.000 89.93000 N ? A ? 15 0 + ATOM 106 CA . SER A 15 ? 9.25800 -49.94200 8.54600 1.000 89.93000 C ? A ? 15 0 + ATOM 107 C . SER A 15 ? 10.00200 -48.79900 9.23900 1.000 89.93000 C ? A ? 15 0 + ATOM 108 O . SER A 15 ? 9.63500 -48.36600 10.32800 1.000 89.93000 O ? A ? 15 0 + ATOM 109 CB . SER A 15 ? 8.39100 -49.40800 7.39900 1.000 89.93000 C ? A ? 15 0 + ATOM 110 OG . SER A 15 ? 7.50800 -48.37100 7.80500 1.000 89.93000 O ? A ? 15 0 + ATOM 111 N . GLN A 16 ? 10.98700 -48.21600 8.55000 1.000 89.52000 N ? A ? 16 0 + ATOM 112 CA . GLN A 16 ? 11.50600 -46.90600 8.94900 1.000 89.52000 C ? A ? 16 0 + ATOM 113 C . GLN A 16 ? 10.36900 -45.85900 8.95100 1.000 89.52000 C ? A ? 16 0 + ATOM 114 O . GLN A 16 ? 9.46800 -45.95300 8.10400 1.000 89.52000 O ? A ? 16 0 + ATOM 115 CB . GLN A 16 ? 12.65400 -46.47700 8.02100 1.000 89.52000 C ? A ? 16 0 + ATOM 116 CG . GLN A 16 ? 13.91100 -47.34600 8.20500 1.000 89.52000 C ? A ? 16 0 + ATOM 117 CD . GLN A 16 ? 14.52800 -47.22100 9.59800 1.000 89.52000 C ? A ? 16 0 + ATOM 118 OE1 . GLN A 16 ? 14.45100 -46.19900 10.25800 1.000 89.52000 O ? A ? 16 0 + ATOM 119 NE2 . GLN A 16 ? 15.16400 -48.25300 10.10500 1.000 89.52000 N ? A ? 16 0 + ATOM 120 N . PRO A 17 ? 10.38000 -44.88200 9.87700 1.000 90.04000 N ? A ? 17 0 + ATOM 121 CA . PRO A 17 ? 9.40900 -43.79300 9.88600 1.000 90.04000 C ? A ? 17 0 + ATOM 122 C . PRO A 17 ? 9.46100 -42.96400 8.59800 1.000 90.04000 C ? A ? 17 0 + ATOM 123 O . PRO A 17 ? 10.53200 -42.73800 8.03400 1.000 90.04000 O ? A ? 17 0 + ATOM 124 CB . PRO A 17 ? 9.74000 -42.94200 11.11800 1.000 90.04000 C ? A ? 17 0 + ATOM 125 CG . PRO A 17 ? 10.50800 -43.89800 12.02900 1.000 90.04000 C ? A ? 17 0 + ATOM 126 CD . PRO A 17 ? 11.24600 -44.79900 11.04500 1.000 90.04000 C ? A ? 17 0 + ATOM 127 N . SER A 18 ? 8.30400 -42.47400 8.14900 1.000 91.27000 N ? A ? 18 0 + ATOM 128 CA . SER A 18 ? 8.22600 -41.49900 7.05700 1.000 91.27000 C ? A ? 18 0 + ATOM 129 C . SER A 18 ? 8.98400 -40.20500 7.38300 1.000 91.27000 C ? A ? 18 0 + ATOM 130 O . SER A 18 ? 9.27800 -39.90700 8.54300 1.000 91.27000 O ? A ? 18 0 + ATOM 131 CB . SER A 18 ? 6.75600 -41.18400 6.73900 1.000 91.27000 C ? A ? 18 0 + ATOM 132 OG . SER A 18 ? 6.15300 -40.39900 7.75700 1.000 91.27000 O ? A ? 18 0 + ATOM 133 N . THR A 19 ? 9.21300 -39.36200 6.37100 1.000 90.71000 N ? A ? 19 0 + ATOM 134 CA . THR A 19 ? 9.60300 -37.96400 6.60700 1.000 90.71000 C ? A ? 19 0 + ATOM 135 C . THR A 19 ? 8.57700 -37.28900 7.51400 1.000 90.71000 C ? A ? 19 0 + ATOM 136 O . THR A 19 ? 7.37000 -37.42800 7.29800 1.000 90.71000 O ? A ? 19 0 + ATOM 137 CB . THR A 19 ? 9.71000 -37.16700 5.30200 1.000 90.71000 C ? A ? 19 0 + ATOM 138 OG1 . THR A 19 ? 8.54000 -37.33500 4.53400 1.000 90.71000 O ? A ? 19 0 + ATOM 139 CG2 . THR A 19 ? 10.89400 -37.63200 4.45600 1.000 90.71000 C ? A ? 19 0 + ATOM 140 N . ALA A 20 ? 9.05900 -36.57800 8.52900 1.000 88.71000 N ? A ? 20 0 + ATOM 141 CA . ALA A 20 ? 8.20500 -35.91800 9.49800 1.000 88.71000 C ? A ? 20 0 + ATOM 142 C . ALA A 20 ? 7.45100 -34.73900 8.87300 1.000 88.71000 C ? A ? 20 0 + ATOM 143 O . ALA A 20 ? 8.05100 -33.87400 8.23400 1.000 88.71000 O ? A ? 20 0 + ATOM 144 CB . ALA A 20 ? 9.07200 -35.48200 10.67500 1.000 88.71000 C ? A ? 20 0 + ATOM 145 N . VAL A 21 ? 6.13800 -34.68600 9.09700 1.000 86.44000 N ? A ? 21 0 + ATOM 146 CA . VAL A 21 ? 5.30400 -33.53700 8.73200 1.000 86.44000 C ? A ? 21 0 + ATOM 147 C . VAL A 21 ? 4.99600 -32.75100 10.00100 1.000 86.44000 C ? A ? 21 0 + ATOM 148 O . VAL A 21 ? 4.41800 -33.27800 10.95400 1.000 86.44000 O ? A ? 21 0 + ATOM 149 CB . VAL A 21 ? 4.03100 -33.96500 7.98000 1.000 86.44000 C ? A ? 21 0 + ATOM 150 CG1 . VAL A 21 ? 3.23000 -32.73500 7.52900 1.000 86.44000 C ? A ? 21 0 + ATOM 151 CG2 . VAL A 21 ? 4.37300 -34.78200 6.72600 1.000 86.44000 C ? A ? 21 0 + ATOM 152 N . ASN A 22 ? 5.39700 -31.48100 10.02600 1.000 83.81000 N ? A ? 22 0 + ATOM 153 CA . ASN A 22 ? 5.11800 -30.59200 11.14800 1.000 83.81000 C ? A ? 22 0 + ATOM 154 C . ASN A 22 ? 3.70400 -30.02400 11.01500 1.000 83.81000 C ? A ? 22 0 + ATOM 155 O . ASN A 22 ? 3.40600 -29.31000 10.06100 1.000 83.81000 O ? A ? 22 0 + ATOM 156 CB . ASN A 22 ? 6.18400 -29.48800 11.21800 1.000 83.81000 C ? A ? 22 0 + ATOM 157 CG . ASN A 22 ? 7.54800 -30.01200 11.63500 1.000 83.81000 C ? A ? 22 0 + ATOM 158 OD1 . ASN A 22 ? 7.68900 -31.00900 12.33100 1.000 83.81000 O ? A ? 22 0 + ATOM 159 ND2 . ASN A 22 ? 8.60100 -29.33200 11.24900 1.000 83.81000 N ? A ? 22 0 + ATOM 160 N . VAL A 23 ? 2.85200 -30.31600 11.99300 1.000 81.23000 N ? A ? 23 0 + ATOM 161 CA . VAL A 23 ? 1.47600 -29.81700 12.06800 1.000 81.23000 C ? A ? 23 0 + ATOM 162 C . VAL A 23 ? 1.26600 -29.03200 13.35500 1.000 81.23000 C ? A ? 23 0 + ATOM 163 O . VAL A 23 ? 1.81900 -29.34000 14.41600 1.000 81.23000 O ? A ? 23 0 + ATOM 164 CB . VAL A 23 ? 0.43200 -30.93900 11.90700 1.000 81.23000 C ? A ? 23 0 + ATOM 165 CG1 . VAL A 23 ? 0.42800 -31.48400 10.47600 1.000 81.23000 C ? A ? 23 0 + ATOM 166 CG2 . VAL A 23 ? 0.65300 -32.10500 12.87500 1.000 81.23000 C ? A ? 23 0 + ATOM 167 N . THR A 24 ? 0.43700 -28.00000 13.28500 1.000 81.30000 N ? A ? 24 0 + ATOM 168 CA . THR A 24 ? 0.07400 -27.18300 14.44500 1.000 81.30000 C ? A ? 24 0 + ATOM 169 C . THR A 24 ? -1.41300 -27.37000 14.71100 1.000 81.30000 C ? A ? 24 0 + ATOM 170 O . THR A 24 ? -2.20800 -27.36100 13.77600 1.000 81.30000 O ? A ? 24 0 + ATOM 171 CB . THR A 24 ? 0.44400 -25.70400 14.24400 1.000 81.30000 C ? A ? 24 0 + ATOM 172 OG1 . THR A 24 ? 1.65500 -25.57500 13.53200 1.000 81.30000 O ? A ? 24 0 + ATOM 173 CG2 . THR A 24 ? 0.69300 -25.01000 15.58400 1.000 81.30000 C ? A ? 24 0 + ATOM 174 N . SER A 25 ? -1.80200 -27.55900 15.97500 1.000 86.41000 N ? A ? 25 0 + ATOM 175 CA . SER A 25 ? -3.22000 -27.59800 16.35000 1.000 86.41000 C ? A ? 25 0 + ATOM 176 C . SER A 25 ? -3.89200 -26.25500 16.04900 1.000 86.41000 C ? A ? 25 0 + ATOM 177 O . SER A 25 ? -3.20700 -25.24200 15.88700 1.000 86.41000 O ? A ? 25 0 + ATOM 178 CB . SER A 25 ? -3.36900 -27.95700 17.83300 1.000 86.41000 C ? A ? 25 0 + ATOM 179 OG . SER A 25 ? -2.67900 -27.02200 18.64400 1.000 86.41000 O ? A ? 25 0 + ATOM 180 N . ALA A 26 ? -5.22600 -26.22900 16.01300 1.000 89.92000 N ? A ? 26 0 + ATOM 181 CA . ALA A 26 ? -5.96600 -24.97600 15.90500 1.000 89.92000 C ? A ? 26 0 + ATOM 182 C . ALA A 26 ? -5.55700 -23.98600 17.02100 1.000 89.92000 C ? A ? 26 0 + ATOM 183 O . ALA A 26 ? -5.22700 -24.42900 18.13100 1.000 89.92000 O ? A ? 26 0 + ATOM 184 CB . ALA A 26 ? -7.46900 -25.27100 15.92300 1.000 89.92000 C ? A ? 26 0 + ATOM 185 N . PRO A 27 ? -5.54900 -22.66900 16.74300 1.000 92.68000 N ? A ? 27 0 + ATOM 186 CA . PRO A 27 ? -5.32900 -21.65700 17.77000 1.000 92.68000 C ? A ? 27 0 + ATOM 187 C . PRO A 27 ? -6.37900 -21.73400 18.88200 1.000 92.68000 C ? A ? 27 0 + ATOM 188 O . PRO A 27 ? -7.49600 -22.21300 18.67000 1.000 92.68000 O ? A ? 27 0 + ATOM 189 CB . PRO A 27 ? -5.40500 -20.30800 17.04900 1.000 92.68000 C ? A ? 27 0 + ATOM 190 CG . PRO A 27 ? -5.11900 -20.65200 15.59200 1.000 92.68000 C ? A ? 27 0 + ATOM 191 CD . PRO A 27 ? -5.74300 -22.03400 15.44600 1.000 92.68000 C ? A ? 27 0 + ATOM 192 N . CYS A 28 ? -6.04400 -21.21700 20.06400 1.000 94.14000 N ? A ? 28 0 + ATOM 193 CA . CYS A 28 ? -7.04200 -20.99900 21.10800 1.000 94.14000 C ? A ? 28 0 + ATOM 194 C . CYS A 28 ? -8.09700 -19.97400 20.65900 1.000 94.14000 C ? A ? 28 0 + ATOM 195 O . CYS A 28 ? -7.82300 -19.10500 19.83200 1.000 94.14000 O ? A ? 28 0 + ATOM 196 CB . CYS A 28 ? -6.35200 -20.57000 22.40900 1.000 94.14000 C ? A ? 28 0 + ATOM 197 SG . CYS A 28 ? -5.36400 -21.94700 23.06800 1.000 94.14000 S ? A ? 28 0 + ATOM 198 N . VAL A 29 ? -9.29800 -20.07300 21.23100 1.000 94.81000 N ? A ? 29 0 + ATOM 199 CA . VAL A 29 ? -10.36600 -19.08900 21.02100 1.000 94.81000 C ? A ? 29 0 + ATOM 200 C . VAL A 29 ? -9.91000 -17.73200 21.59400 1.000 94.81000 C ? A ? 29 0 + ATOM 201 O . VAL A 29 ? -9.39800 -17.71800 22.71900 1.000 94.81000 O ? A ? 29 0 + ATOM 202 CB . VAL A 29 ? -11.68000 -19.57200 21.66500 1.000 94.81000 C ? A ? 29 0 + ATOM 203 CG1 . VAL A 29 ? -12.82200 -18.58500 21.44500 1.000 94.81000 C ? A ? 29 0 + ATOM 204 CG2 . VAL A 29 ? -12.12000 -20.91600 21.06300 1.000 94.81000 C ? A ? 29 0 + ATOM 205 N . PRO A 30 ? -10.03400 -16.61800 20.84500 1.000 93.95000 N ? A ? 30 0 + ATOM 206 CA . PRO A 30 ? -9.76100 -15.27100 21.35000 1.000 93.95000 C ? A ? 30 0 + ATOM 207 C . PRO A 30 ? -10.57700 -14.93000 22.60600 1.000 93.95000 C ? A ? 30 0 + ATOM 208 O . PRO A 30 ? -11.62500 -15.52200 22.85800 1.000 93.95000 O ? A ? 30 0 + ATOM 209 CB . PRO A 30 ? -10.08000 -14.31700 20.19300 1.000 93.95000 C ? A ? 30 0 + ATOM 210 CG . PRO A 30 ? -9.88500 -15.19300 18.95900 1.000 93.95000 C ? A ? 30 0 + ATOM 211 CD . PRO A 30 ? -10.36900 -16.56000 19.43000 1.000 93.95000 C ? A ? 30 0 + ATOM 212 N . GLN A 31 ? -10.06000 -14.00800 23.41900 1.000 93.67000 N ? A ? 31 0 + ATOM 213 CA . GLN A 31 ? -10.71600 -13.52500 24.63600 1.000 93.67000 C ? A ? 31 0 + ATOM 214 C . GLN A 31 ? -10.44700 -12.03000 24.83200 1.000 93.67000 C ? A ? 31 0 + ATOM 215 O . GLN A 31 ? -9.43200 -11.51000 24.36100 1.000 93.67000 O ? A ? 31 0 + ATOM 216 CB . GLN A 31 ? -10.20900 -14.29600 25.87300 1.000 93.67000 C ? A ? 31 0 + ATOM 217 CG . GLN A 31 ? -10.59000 -15.78300 25.87000 1.000 93.67000 C ? A ? 31 0 + ATOM 218 CD . GLN A 31 ? -10.23900 -16.49000 27.17600 1.000 93.67000 C ? A ? 31 0 + ATOM 219 OE1 . GLN A 31 ? -9.27800 -16.19100 27.86800 1.000 93.67000 O ? A ? 31 0 + ATOM 220 NE2 . GLN A 31 ? -11.01100 -17.47900 27.57200 1.000 93.67000 N ? A ? 31 0 + ATOM 221 N . GLY A 32 ? -11.31200 -11.36300 25.59800 1.000 91.63000 N ? A ? 32 0 + ATOM 222 CA . GLY A 32 ? -11.14700 -9.95200 25.95900 1.000 91.63000 C ? A ? 32 0 + ATOM 223 C . GLY A 32 ? -11.48000 -9.00600 24.80900 1.000 91.63000 C ? A ? 32 0 + ATOM 224 O . GLY A 32 ? -10.83200 -7.97400 24.66000 1.000 91.63000 O ? A ? 32 0 + ATOM 225 N . GLU A 33 ? -12.44400 -9.39100 23.97800 1.000 92.94000 N ? A ? 33 0 + ATOM 226 CA . GLU A 33 ? -12.88300 -8.63700 22.81800 1.000 92.94000 C ? A ? 33 0 + ATOM 227 C . GLU A 33 ? -13.59700 -7.35000 23.24200 1.000 92.94000 C ? A ? 33 0 + ATOM 228 O . GLU A 33 ? -14.56800 -7.37300 23.99900 1.000 92.94000 O ? A ? 33 0 + ATOM 229 CB . GLU A 33 ? -13.78500 -9.48700 21.90800 1.000 92.94000 C ? A ? 33 0 + ATOM 230 CG . GLU A 33 ? -13.15300 -10.80600 21.43600 1.000 92.94000 C ? A ? 33 0 + ATOM 231 CD . GLU A 33 ? -13.39000 -12.00700 22.37300 1.000 92.94000 C ? A ? 33 0 + ATOM 232 OE1 . GLU A 33 ? -13.34000 -13.14200 21.85900 1.000 92.94000 O ? A ? 33 0 + ATOM 233 OE2 . GLU A 33 ? -13.57900 -11.84500 23.60300 1.000 92.94000 O ? A ? 33 0 + ATOM 234 N . ALA A 34 ? -13.12600 -6.22000 22.72700 1.000 93.92000 N ? A ? 34 0 + ATOM 235 CA . ALA A 34 ? -13.75400 -4.92100 22.91100 1.000 93.92000 C ? A ? 34 0 + ATOM 236 C . ALA A 34 ? -13.77300 -4.16800 21.58100 1.000 93.92000 C ? A ? 34 0 + ATOM 237 O . ALA A 34 ? -12.87400 -4.32500 20.75900 1.000 93.92000 O ? A ? 34 0 + ATOM 238 CB . ALA A 34 ? -13.01100 -4.15200 24.00900 1.000 93.92000 C ? A ? 34 0 + ATOM 239 N . GLY A 35 ? -14.79600 -3.34400 21.36800 1.000 92.42000 N ? A ? 35 0 + ATOM 240 CA . GLY A 35 ? -14.92200 -2.51900 20.17100 1.000 92.42000 C ? A ? 35 0 + ATOM 241 C . GLY A 35 ? -15.10600 -1.05200 20.52600 1.000 92.42000 C ? A ? 35 0 + ATOM 242 O . GLY A 35 ? -15.85300 -0.72600 21.44800 1.000 92.42000 O ? A ? 35 0 + ATOM 243 N . ASN A 36 ? -14.44400 -0.17200 19.78200 1.000 91.54000 N ? A ? 36 0 + ATOM 244 CA . ASN A 36 ? -14.63300 1.26900 19.86100 1.000 91.54000 C ? A ? 36 0 + ATOM 245 C . ASN A 36 ? -15.07000 1.80000 18.49200 1.000 91.54000 C ? A ? 36 0 + ATOM 246 O . ASN A 36 ? -14.38400 1.57900 17.49400 1.000 91.54000 O ? A ? 36 0 + ATOM 247 CB . ASN A 36 ? -13.34400 1.92300 20.37900 1.000 91.54000 C ? A ? 36 0 + ATOM 248 CG . ASN A 36 ? -13.55900 3.37600 20.76300 1.000 91.54000 C ? A ? 36 0 + ATOM 249 OD1 . ASN A 36 ? -14.64600 3.92000 20.69100 1.000 91.54000 O ? A ? 36 0 + ATOM 250 ND2 . ASN A 36 ? -12.53400 4.04600 21.22800 1.000 91.54000 N ? A ? 36 0 + ATOM 251 N . LEU A 37 ? -16.22700 2.45900 18.45100 1.000 88.49000 N ? A ? 37 0 + ATOM 252 CA . LEU A 37 ? -16.79700 3.01600 17.22900 1.000 88.49000 C ? A ? 37 0 + ATOM 253 C . LEU A 37 ? -16.12800 4.35200 16.90600 1.000 88.49000 C ? A ? 37 0 + ATOM 254 O . LEU A 37 ? -16.25600 5.31400 17.66000 1.000 88.49000 O ? A ? 37 0 + ATOM 255 CB . LEU A 37 ? -18.32100 3.16200 17.40800 1.000 88.49000 C ? A ? 37 0 + ATOM 256 CG . LEU A 37 ? -19.05600 3.77000 16.19600 1.000 88.49000 C ? A ? 37 0 + ATOM 257 CD1 . LEU A 37 ? -19.03900 2.85400 14.97200 1.000 88.49000 C ? A ? 37 0 + ATOM 258 CD2 . LEU A 37 ? -20.52200 4.02500 16.55300 1.000 88.49000 C ? A ? 37 0 + ATOM 259 N . ASP A 38 ? -15.48800 4.42000 15.74700 1.000 85.73000 N ? A ? 38 0 + ATOM 260 CA . ASP A 38 ? -15.11100 5.67200 15.11700 1.000 85.73000 C ? A ? 38 0 + ATOM 261 C . ASP A 38 ? -16.31500 6.23600 14.35300 1.000 85.73000 C ? A ? 38 0 + ATOM 262 O . ASP A 38 ? -16.79800 5.68800 13.35700 1.000 85.73000 O ? A ? 38 0 + ATOM 263 CB . ASP A 38 ? -13.89000 5.46000 14.22500 1.000 85.73000 C ? A ? 38 0 + ATOM 264 CG . ASP A 38 ? -13.43800 6.75100 13.54200 1.000 85.73000 C ? A ? 38 0 + ATOM 265 OD1 . ASP A 38 ? -14.08200 7.81000 13.74800 1.000 85.73000 O ? A ? 38 0 + ATOM 266 OD2 . ASP A 38 ? -12.48500 6.63400 12.75000 1.000 85.73000 O ? A ? 38 0 + ATOM 267 N . CYS A 39 ? -16.82400 7.35100 14.86700 1.000 79.80000 N ? A ? 39 0 + ATOM 268 CA . CYS A 39 ? -18.00400 8.02100 14.34800 1.000 79.80000 C ? A ? 39 0 + ATOM 269 C . CYS A 39 ? -17.77900 8.66600 12.96700 1.000 79.80000 C ? A ? 39 0 + ATOM 270 O . CYS A 39 ? -18.76000 8.90200 12.25900 1.000 79.80000 O ? A ? 39 0 + ATOM 271 CB . CYS A 39 ? -18.40100 9.07800 15.38200 1.000 79.80000 C ? A ? 39 0 + ATOM 272 SG . CYS A 39 ? -17.27400 10.49800 15.36400 1.000 79.80000 S ? A ? 39 0 + ATOM 273 N . ILE A 40 ? -16.52500 8.97100 12.60000 1.000 73.17000 N ? A ? 40 0 + ATOM 274 CA . ILE A 40 ? -16.18100 9.69300 11.36800 1.000 73.17000 C ? A ? 40 0 + ATOM 275 C . ILE A 40 ? -16.24900 8.72400 10.19700 1.000 73.17000 C ? A ? 40 0 + ATOM 276 O . ILE A 40 ? -16.99400 8.92900 9.24000 1.000 73.17000 O ? A ? 40 0 + ATOM 277 CB . ILE A 40 ? -14.78000 10.35100 11.47100 1.000 73.17000 C ? A ? 40 0 + ATOM 278 CG1 . ILE A 40 ? -14.72600 11.32500 12.67000 1.000 73.17000 C ? A ? 40 0 + ATOM 279 CG2 . ILE A 40 ? -14.43200 11.07400 10.15400 1.000 73.17000 C ? A ? 40 0 + ATOM 280 CD1 . ILE A 40 ? -13.37100 12.01300 12.87500 1.000 73.17000 C ? A ? 40 0 + ATOM 281 N . THR A 41 ? -15.50600 7.63100 10.31400 1.000 80.58000 N ? A ? 41 0 + ATOM 282 CA . THR A 41 ? -15.36200 6.62500 9.26000 1.000 80.58000 C ? A ? 41 0 + ATOM 283 C . THR A 41 ? -16.46700 5.56100 9.28100 1.000 80.58000 C ? A ? 41 0 + ATOM 284 O . THR A 41 ? -16.52200 4.70800 8.39600 1.000 80.58000 O ? A ? 41 0 + ATOM 285 CB . THR A 41 ? -13.96800 5.99000 9.34500 1.000 80.58000 C ? A ? 41 0 + ATOM 286 OG1 . THR A 41 ? -13.78100 5.47000 10.64100 1.000 80.58000 O ? A ? 41 0 + ATOM 287 CG2 . THR A 41 ? -12.84000 6.98900 9.10200 1.000 80.58000 C ? A ? 41 0 + ATOM 288 N . ASN A 42 ? -17.35300 5.58100 10.29000 1.000 85.30000 N ? A ? 42 0 + ATOM 289 CA . ASN A 42 ? -18.22300 4.45100 10.65100 1.000 85.30000 C ? A ? 42 0 + ATOM 290 C . ASN A 42 ? -17.46000 3.13000 10.68200 1.000 85.30000 C ? A ? 42 0 + ATOM 291 O . ASN A 42 ? -17.91600 2.10900 10.15900 1.000 85.30000 O ? A ? 42 0 + ATOM 292 CB . ASN A 42 ? -19.45400 4.33100 9.74700 1.000 85.30000 C ? A ? 42 0 + ATOM 293 CG . ASN A 42 ? -20.52200 5.34000 9.99600 1.000 85.30000 C ? A ? 42 0 + ATOM 294 OD1 . ASN A 42 ? -20.49200 6.09000 10.95000 1.000 85.30000 O ? A ? 42 0 + ATOM 295 ND2 . ASN A 42 ? -21.56400 5.32500 9.20200 1.000 85.30000 N ? A ? 42 0 + ATOM 296 N . SER A 43 ? -16.27800 3.15900 11.27300 1.000 89.68000 N ? A ? 43 0 + ATOM 297 CA . SER A 43 ? -15.47100 1.97000 11.44900 1.000 89.68000 C ? A ? 43 0 + ATOM 298 C . SER A 43 ? -15.40300 1.61000 12.92400 1.000 89.68000 C ? A ? 43 0 + ATOM 299 O . SER A 43 ? -15.64100 2.44300 13.79700 1.000 89.68000 O ? A ? 43 0 + ATOM 300 CB . SER A 43 ? -14.12500 2.14300 10.75500 1.000 89.68000 C ? A ? 43 0 + ATOM 301 OG . SER A 43 ? -13.27600 3.03600 11.43800 1.000 89.68000 O ? A ? 43 0 + ATOM 302 N . VAL A 44 ? -15.17800 0.33800 13.22700 1.000 93.01000 N ? A ? 44 0 + ATOM 303 CA . VAL A 44 ? -15.02400 -0.11300 14.61000 1.000 93.01000 C ? A ? 44 0 + ATOM 304 C . VAL A 44 ? -13.63600 -0.69200 14.77100 1.000 93.01000 C ? A ? 44 0 + ATOM 305 O . VAL A 44 ? -13.30500 -1.71900 14.17500 1.000 93.01000 O ? A ? 44 0 + ATOM 306 CB . VAL A 44 ? -16.13100 -1.09000 15.03400 1.000 93.01000 C ? A ? 44 0 + ATOM 307 CG1 . VAL A 44 ? -15.85300 -1.73000 16.40100 1.000 93.01000 C ? A ? 44 0 + ATOM 308 CG2 . VAL A 44 ? -17.47400 -0.35800 15.16000 1.000 93.01000 C ? A ? 44 0 + ATOM 309 N . TRP A 45 ? -12.86400 -0.07200 15.65600 1.000 93.90000 N ? A ? 45 0 + ATOM 310 CA . TRP A 45 ? -11.62100 -0.63100 16.15000 1.000 93.90000 C ? A ? 45 0 + ATOM 311 C . TRP A 45 ? -11.93000 -1.72200 17.15800 1.000 93.90000 C ? A ? 45 0 + ATOM 312 O . TRP A 45 ? -12.39900 -1.44600 18.26200 1.000 93.90000 O ? A ? 45 0 + ATOM 313 CB . TRP A 45 ? -10.76200 0.47200 16.76000 1.000 93.90000 C ? A ? 45 0 + ATOM 314 CG . TRP A 45 ? -10.09400 1.31200 15.72800 1.000 93.90000 C ? A ? 45 0 + ATOM 315 CD1 . TRP A 45 ? -10.50400 2.52600 15.29700 1.000 93.90000 C ? A ? 45 0 + ATOM 316 CD2 . TRP A 45 ? -8.93200 0.96600 14.91900 1.000 93.90000 C ? A ? 45 0 + ATOM 317 NE1 . TRP A 45 ? -9.65600 2.97200 14.30200 1.000 93.90000 N ? A ? 45 0 + ATOM 318 CE2 . TRP A 45 ? -8.66000 2.05400 14.03800 1.000 93.90000 C ? A ? 45 0 + ATOM 319 CE3 . TRP A 45 ? -8.08900 -0.16800 14.83800 1.000 93.90000 C ? A ? 45 0 + ATOM 320 CZ2 . TRP A 45 ? -7.58300 2.03300 13.14100 1.000 93.90000 C ? A ? 45 0 + ATOM 321 CZ3 . TRP A 45 ? -7.00300 -0.19800 13.94100 1.000 93.90000 C ? A ? 45 0 + ATOM 322 CH2 . TRP A 45 ? -6.74500 0.90300 13.10100 1.000 93.90000 C ? A ? 45 0 + ATOM 323 N . VAL A 46 ? -11.66300 -2.96400 16.77100 1.000 95.79000 N ? A ? 46 0 + ATOM 324 CA . VAL A 46 ? -11.81500 -4.13300 17.63400 1.000 95.79000 C ? A ? 46 0 + ATOM 325 C . VAL A 46 ? -10.45400 -4.51000 18.20000 1.000 95.79000 C ? A ? 46 0 + ATOM 326 O . VAL A 46 ? -9.47300 -4.54800 17.46100 1.000 95.79000 O ? A ? 46 0 + ATOM 327 CB . VAL A 46 ? -12.49500 -5.29400 16.89000 1.000 95.79000 C ? A ? 46 0 + ATOM 328 CG1 . VAL A 46 ? -12.79400 -6.45700 17.84300 1.000 95.79000 C ? A ? 46 0 + ATOM 329 CG2 . VAL A 46 ? -13.82500 -4.83300 16.28000 1.000 95.79000 C ? A ? 46 0 + ATOM 330 N . THR A 47 ? -10.38800 -4.78000 19.49900 1.000 96.42000 N ? A ? 47 0 + ATOM 331 CA . THR A 47 ? -9.18700 -5.21400 20.22200 1.000 96.42000 C ? A ? 47 0 + ATOM 332 C . THR A 47 ? -9.45700 -6.52000 20.96200 1.000 96.42000 C ? A ? 47 0 + ATOM 333 O . THR A 47 ? -10.60000 -6.81600 21.30500 1.000 96.42000 O ? A ? 47 0 + ATOM 334 CB . THR A 47 ? -8.68900 -4.14000 21.20200 1.000 96.42000 C ? A ? 47 0 + ATOM 335 OG1 . THR A 47 ? -9.65200 -3.85100 22.18600 1.000 96.42000 O ? A ? 47 0 + ATOM 336 CG2 . THR A 47 ? -8.37300 -2.81400 20.51100 1.000 96.42000 C ? A ? 47 0 + ATOM 337 N . TRP A 48 ? -8.41900 -7.33000 21.17000 1.000 95.00000 N ? A ? 48 0 + ATOM 338 CA . TRP A 48 ? -8.50100 -8.61800 21.87100 1.000 95.00000 C ? A ? 48 0 + ATOM 339 C . TRP A 48 ? -7.15500 -8.99300 22.49900 1.000 95.00000 C ? A ? 48 0 + ATOM 340 O . TRP A 48 ? -6.11900 -8.38100 22.23100 1.000 95.00000 O ? A ? 48 0 + ATOM 341 CB . TRP A 48 ? -8.95000 -9.71700 20.89300 1.000 95.00000 C ? A ? 48 0 + ATOM 342 CG . TRP A 48 ? -8.11200 -9.83000 19.65800 1.000 95.00000 C ? A ? 48 0 + ATOM 343 CD1 . TRP A 48 ? -6.99800 -10.57900 19.49900 1.000 95.00000 C ? A ? 48 0 + ATOM 344 CD2 . TRP A 48 ? -8.30300 -9.13300 18.39700 1.000 95.00000 C ? A ? 48 0 + ATOM 345 NE1 . TRP A 48 ? -6.48000 -10.37600 18.23600 1.000 95.00000 N ? A ? 48 0 + ATOM 346 CE2 . TRP A 48 ? -7.24400 -9.49100 17.51800 1.000 95.00000 C ? A ? 48 0 + ATOM 347 CE3 . TRP A 48 ? -9.27000 -8.23200 17.91600 1.000 95.00000 C ? A ? 48 0 + ATOM 348 CZ2 . TRP A 48 ? -7.14800 -8.98500 16.22100 1.000 95.00000 C ? A ? 48 0 + ATOM 349 CZ3 . TRP A 48 ? -9.20600 -7.74100 16.60100 1.000 95.00000 C ? A ? 48 0 + ATOM 350 CH2 . TRP A 48 ? -8.16100 -8.14200 15.75400 1.000 95.00000 C ? A ? 48 0 + ATOM 351 N . LEU A 49 ? -7.15300 -10.03500 23.33100 1.000 95.28000 N ? A ? 49 0 + ATOM 352 CA . LEU A 49 ? -5.94000 -10.60400 23.91400 1.000 95.28000 C ? A ? 49 0 + ATOM 353 C . LEU A 49 ? -5.31400 -11.65600 22.99200 1.000 95.28000 C ? A ? 49 0 + ATOM 354 O . LEU A 49 ? -6.00400 -12.35800 22.25300 1.000 95.28000 O ? A ? 49 0 + ATOM 355 CB . LEU A 49 ? -6.25600 -11.18600 25.30000 1.000 95.28000 C ? A ? 49 0 + ATOM 356 CG . LEU A 49 ? -6.80800 -10.15700 26.30500 1.000 95.28000 C ? A ? 49 0 + ATOM 357 CD1 . LEU A 49 ? -7.19700 -10.87300 27.59800 1.000 95.28000 C ? A ? 49 0 + ATOM 358 CD2 . LEU A 49 ? -5.77600 -9.07600 26.64300 1.000 95.28000 C ? A ? 49 0 + ATOM 359 N . GLN A 50 ? -3.98800 -11.79800 23.06000 1.000 94.37000 N ? A ? 50 0 + ATOM 360 CA . GLN A 50 ? -3.25800 -12.76000 22.23700 1.000 94.37000 C ? A ? 50 0 + ATOM 361 C . GLN A 50 ? -3.69900 -14.20500 22.52600 1.000 94.37000 C ? A ? 50 0 + ATOM 362 O . GLN A 50 ? -3.44400 -14.75000 23.60000 1.000 94.37000 O ? A ? 50 0 + ATOM 363 CB . GLN A 50 ? -1.74500 -12.57400 22.43500 1.000 94.37000 C ? A ? 50 0 + ATOM 364 CG . GLN A 50 ? -0.93600 -13.43700 21.45100 1.000 94.37000 C ? A ? 50 0 + ATOM 365 CD . GLN A 50 ? 0.56500 -13.16400 21.50000 1.000 94.37000 C ? A ? 50 0 + ATOM 366 OE1 . GLN A 50 ? 1.10100 -12.54700 22.40300 1.000 94.37000 O ? A ? 50 0 + ATOM 367 NE2 . GLN A 50 ? 1.31400 -13.62200 20.52100 1.000 94.37000 N ? A ? 50 0 + ATOM 368 N . ALA A 51 ? -4.29900 -14.85500 21.53000 1.000 94.47000 N ? A ? 51 0 + ATOM 369 CA . ALA A 51 ? -4.63000 -16.26900 21.56200 1.000 94.47000 C ? A ? 51 0 + ATOM 370 C . ALA A 51 ? -3.38400 -17.13100 21.30600 1.000 94.47000 C ? A ? 51 0 + ATOM 371 O . ALA A 51 ? -2.60300 -16.90800 20.37400 1.000 94.47000 O ? A ? 51 0 + ATOM 372 CB . ALA A 51 ? -5.73700 -16.54700 20.54600 1.000 94.47000 C ? A ? 51 0 + ATOM 373 N . LYS A 52 ? -3.19700 -18.17200 22.12100 1.000 92.16000 N ? A ? 52 0 + ATOM 374 CA . LYS A 52 ? -2.06300 -19.09200 21.98500 1.000 92.16000 C ? A ? 52 0 + ATOM 375 C . LYS A 52 ? -2.14100 -19.84700 20.65200 1.000 92.16000 C ? A ? 52 0 + ATOM 376 O . LYS A 52 ? -3.13200 -20.51300 20.36000 1.000 92.16000 O ? A ? 52 0 + ATOM 377 CB . LYS A 52 ? -2.02700 -20.02300 23.20200 1.000 92.16000 C ? A ? 52 0 + ATOM 378 CG . LYS A 52 ? -0.76200 -20.89000 23.26300 1.000 92.16000 C ? A ? 52 0 + ATOM 379 CD . LYS A 52 ? -0.79800 -21.76200 24.52500 1.000 92.16000 C ? A ? 52 0 + ATOM 380 CE . LYS A 52 ? 0.47000 -22.61200 24.64200 1.000 92.16000 C ? A ? 52 0 + ATOM 381 NZ . LYS A 52 ? 0.45800 -23.42100 25.88800 1.000 92.16000 N ? A ? 52 0 + ATOM 382 N . GLY A 53 ? -1.06600 -19.77000 19.86900 1.000 90.79000 N ? A ? 53 0 + ATOM 383 CA . GLY A 53 ? -0.94400 -20.44800 18.57300 1.000 90.79000 C ? A ? 53 0 + ATOM 384 C . GLY A 53 ? -1.53600 -19.69100 17.38100 1.000 90.79000 C ? A ? 53 0 + ATOM 385 O . GLY A 53 ? -1.51300 -20.23600 16.27900 1.000 90.79000 O ? A ? 53 0 + ATOM 386 N . ALA A 54 ? -2.04500 -18.47100 17.57900 1.000 92.72000 N ? A ? 54 0 + ATOM 387 CA . ALA A 54 ? -2.51700 -17.60800 16.50100 1.000 92.72000 C ? A ? 54 0 + ATOM 388 C . ALA A 54 ? -1.34600 -16.89800 15.79800 1.000 92.72000 C ? A ? 54 0 + ATOM 389 O . ALA A 54 ? -0.43700 -16.39400 16.45800 1.000 92.72000 O ? A ? 54 0 + ATOM 390 CB . ALA A 54 ? -3.50100 -16.59800 17.09100 1.000 92.72000 C ? A ? 54 0 + ATOM 391 N . LEU A 55 ? -1.39200 -16.84600 14.46700 1.000 93.25000 N ? A ? 55 0 + ATOM 392 CA . LEU A 55 ? -0.49600 -16.04900 13.61900 1.000 93.25000 C ? A ? 55 0 + ATOM 393 C . LEU A 55 ? -1.19800 -14.80200 13.06700 1.000 93.25000 C ? A ? 55 0 + ATOM 394 O . LEU A 55 ? -0.55000 -13.79600 12.79400 1.000 93.25000 O ? A ? 55 0 + ATOM 395 CB . LEU A 55 ? 0.01600 -16.91300 12.45300 1.000 93.25000 C ? A ? 55 0 + ATOM 396 CG . LEU A 55 ? 0.84100 -18.14500 12.86000 1.000 93.25000 C ? A ? 55 0 + ATOM 397 CD1 . LEU A 55 ? 1.25700 -18.90700 11.60200 1.000 93.25000 C ? A ? 55 0 + ATOM 398 CD2 . LEU A 55 ? 2.10700 -17.77100 13.63200 1.000 93.25000 C ? A ? 55 0 + ATOM 399 N . SER A 56 ? -2.51700 -14.87300 12.90400 1.000 95.79000 N ? A ? 56 0 + ATOM 400 CA . SER A 56 ? -3.36300 -13.76700 12.46600 1.000 95.79000 C ? A ? 56 0 + ATOM 401 C . SER A 56 ? -4.77600 -13.91800 13.02700 1.000 95.79000 C ? A ? 56 0 + ATOM 402 O . SER A 56 ? -5.13100 -14.95200 13.60000 1.000 95.79000 O ? A ? 56 0 + ATOM 403 CB . SER A 56 ? -3.38400 -13.68300 10.93400 1.000 95.79000 C ? A ? 56 0 + ATOM 404 OG . SER A 56 ? -3.86900 -14.87900 10.35200 1.000 95.79000 O ? A ? 56 0 + ATOM 405 N . TYR A 57 ? -5.57600 -12.87000 12.88000 1.000 96.56000 N ? A ? 57 0 + ATOM 406 CA . TYR A 57 ? -6.96000 -12.80500 13.32500 1.000 96.56000 C ? A ? 57 0 + ATOM 407 C . TYR A 57 ? -7.84700 -12.26700 12.20600 1.000 96.56000 C ? A ? 57 0 + ATOM 408 O . TYR A 57 ? -7.41100 -11.45500 11.38700 1.000 96.56000 O ? A ? 57 0 + ATOM 409 CB . TYR A 57 ? -7.07200 -11.92100 14.56800 1.000 96.56000 C ? A ? 57 0 + ATOM 410 CG . TYR A 57 ? -6.25100 -12.40200 15.74800 1.000 96.56000 C ? A ? 57 0 + ATOM 411 CD1 . TYR A 57 ? -6.84000 -13.20300 16.74600 1.000 96.56000 C ? A ? 57 0 + ATOM 412 CD2 . TYR A 57 ? -4.89500 -12.03500 15.84700 1.000 96.56000 C ? A ? 57 0 + ATOM 413 CE1 . TYR A 57 ? -6.06800 -13.64800 17.83800 1.000 96.56000 C ? A ? 57 0 + ATOM 414 CE2 . TYR A 57 ? -4.11400 -12.50000 16.91600 1.000 96.56000 C ? A ? 57 0 + ATOM 415 CZ . TYR A 57 ? -4.70200 -13.30900 17.90900 1.000 96.56000 C ? A ? 57 0 + ATOM 416 OH . TYR A 57 ? -3.93200 -13.74100 18.93500 1.000 96.56000 O ? A ? 57 0 + ATOM 417 N . SER A 58 ? -9.10200 -12.70400 12.20300 1.000 96.21000 N ? A ? 58 0 + ATOM 418 CA . SER A 58 ? -10.16300 -12.19300 11.34100 1.000 96.21000 C ? A ? 58 0 + ATOM 419 C . SER A 58 ? -11.32700 -11.72700 12.20600 1.000 96.21000 C ? A ? 58 0 + ATOM 420 O . SER A 58 ? -11.73900 -12.43500 13.12800 1.000 96.21000 O ? A ? 58 0 + ATOM 421 CB . SER A 58 ? -10.60600 -13.27100 10.35300 1.000 96.21000 C ? A ? 58 0 + ATOM 422 OG . SER A 58 ? -11.59400 -12.76800 9.48200 1.000 96.21000 O ? A ? 58 0 + ATOM 423 N . VAL A 59 ? -11.83600 -10.53200 11.91700 1.000 96.83000 N ? A ? 59 0 + ATOM 424 CA . VAL A 59 ? -13.00400 -9.94900 12.57400 1.000 96.83000 C ? A ? 59 0 + ATOM 425 C . VAL A 59 ? -14.14000 -9.88000 11.56500 1.000 96.83000 C ? A ? 59 0 + ATOM 426 O . VAL A 59 ? -13.96200 -9.32800 10.48100 1.000 96.83000 O ? A ? 59 0 + ATOM 427 CB . VAL A 59 ? -12.71200 -8.55300 13.14700 1.000 96.83000 C ? A ? 59 0 + ATOM 428 CG1 . VAL A 59 ? -13.89400 -8.05100 13.98300 1.000 96.83000 C ? A ? 59 0 + ATOM 429 CG2 . VAL A 59 ? -11.46200 -8.53900 14.03400 1.000 96.83000 C ? A ? 59 0 + ATOM 430 N . LEU A 60 ? -15.30500 -10.40900 11.92800 1.000 96.31000 N ? A ? 60 0 + ATOM 431 CA . LEU A 60 ? -16.52300 -10.36200 11.12400 1.000 96.31000 C ? A ? 60 0 + ATOM 432 C . LEU A 60 ? -17.59600 -9.56200 11.86300 1.000 96.31000 C ? A ? 60 0 + ATOM 433 O . LEU A 60 ? -17.96600 -9.91600 12.97900 1.000 96.31000 O ? A ? 60 0 + ATOM 434 CB . LEU A 60 ? -16.97200 -11.80400 10.82700 1.000 96.31000 C ? A ? 60 0 + ATOM 435 CG . LEU A 60 ? -18.26200 -11.90200 9.99400 1.000 96.31000 C ? A ? 60 0 + ATOM 436 CD1 . LEU A 60 ? -18.07200 -11.38900 8.56600 1.000 96.31000 C ? A ? 60 0 + ATOM 437 CD2 . LEU A 60 ? -18.72600 -13.35800 9.92900 1.000 96.31000 C ? A ? 60 0 + ATOM 438 N . ALA A 61 ? -18.11200 -8.51600 11.22700 1.000 96.00000 N ? A ? 61 0 + ATOM 439 CA . ALA A 61 ? -19.25600 -7.74300 11.68600 1.000 96.00000 C ? A ? 61 0 + ATOM 440 C . ALA A 61 ? -20.49500 -8.14400 10.88000 1.000 96.00000 C ? A ? 61 0 + ATOM 441 O . ALA A 61 ? -20.52700 -7.98600 9.66000 1.000 96.00000 O ? A ? 61 0 + ATOM 442 CB . ALA A 61 ? -18.93000 -6.25500 11.55800 1.000 96.00000 C ? A ? 61 0 + ATOM 443 N . VAL A 62 ? -21.50800 -8.66600 11.56900 1.000 95.34000 N ? A ? 62 0 + ATOM 444 CA . VAL A 62 ? -22.75700 -9.14400 10.96700 1.000 95.34000 C ? A ? 62 0 + ATOM 445 C . VAL A 62 ? -23.89800 -8.20200 11.31700 1.000 95.34000 C ? A ? 62 0 + ATOM 446 O . VAL A 62 ? -24.15300 -7.94500 12.49500 1.000 95.34000 O ? A ? 62 0 + ATOM 447 CB . VAL A 62 ? -23.07800 -10.58900 11.39000 1.000 95.34000 C ? A ? 62 0 + ATOM 448 CG1 . VAL A 62 ? -24.34300 -11.12000 10.70300 1.000 95.34000 C ? A ? 62 0 + ATOM 449 CG2 . VAL A 62 ? -21.92300 -11.53600 11.03900 1.000 95.34000 C ? A ? 62 0 + ATOM 450 N . GLU A 63 ? -24.60000 -7.72100 10.29900 1.000 93.27000 N ? A ? 63 0 + ATOM 451 CA . GLU A 63 ? -25.77100 -6.85100 10.42800 1.000 93.27000 C ? A ? 63 0 + ATOM 452 C . GLU A 63 ? -27.03700 -7.61400 10.00900 1.000 93.27000 C ? A ? 63 0 + ATOM 453 O . GLU A 63 ? -26.98900 -8.52600 9.18200 1.000 93.27000 O ? A ? 63 0 + ATOM 454 CB . GLU A 63 ? -25.48800 -5.56000 9.65100 1.000 93.27000 C ? A ? 63 0 + ATOM 455 CG . GLU A 63 ? -26.51600 -4.42800 9.79900 1.000 93.27000 C ? A ? 63 0 + ATOM 456 CD . GLU A 63 ? -27.74800 -4.66200 8.93500 1.000 93.27000 C ? A ? 63 0 + ATOM 457 OE1 . GLU A 63 ? -28.86600 -4.43400 9.45100 1.000 93.27000 O ? A ? 63 0 + ATOM 458 OE2 . GLU A 63 ? -27.59300 -5.23100 7.83400 1.000 93.27000 O ? A ? 63 0 + ATOM 459 N . LYS A 64 ? -28.18400 -7.29400 10.62200 1.000 85.77000 N ? A ? 64 0 + ATOM 460 CA . LYS A 64 ? -29.42700 -8.06900 10.44700 1.000 85.77000 C ? A ? 64 0 + ATOM 461 C . LYS A 64 ? -29.96100 -8.06500 9.01000 1.000 85.77000 C ? A ? 64 0 + ATOM 462 O . LYS A 64 ? -30.61400 -9.02900 8.62200 1.000 85.77000 O ? A ? 64 0 + ATOM 463 CB . LYS A 64 ? -30.51700 -7.54900 11.39300 1.000 85.77000 C ? A ? 64 0 + ATOM 464 CG . LYS A 64 ? -30.26000 -7.91900 12.85900 1.000 85.77000 C ? A ? 64 0 + ATOM 465 CD . LYS A 64 ? -31.44500 -7.47100 13.72300 1.000 85.77000 C ? A ? 64 0 + ATOM 466 CE . LYS A 64 ? -31.21100 -7.85000 15.18700 1.000 85.77000 C ? A ? 64 0 + ATOM 467 NZ . LYS A 64 ? -32.31400 -7.36400 16.05200 1.000 85.77000 N ? A ? 64 0 + ATOM 468 N . GLN A 65 ? -29.72300 -7.00100 8.24900 1.000 82.48000 N ? A ? 65 0 + ATOM 469 CA . GLN A 65 ? -30.13500 -6.83000 6.85400 1.000 82.48000 C ? A ? 65 0 + ATOM 470 C . GLN A 65 ? -29.06200 -7.29500 5.85000 1.000 82.48000 C ? A ? 65 0 + ATOM 471 O . GLN A 65 ? -29.27800 -7.20200 4.64300 1.000 82.48000 O ? A ? 65 0 + ATOM 472 CB . GLN A 65 ? -30.56100 -5.37000 6.60100 1.000 82.48000 C ? A ? 65 0 + ATOM 473 CG . GLN A 65 ? -31.63900 -4.87500 7.57800 1.000 82.48000 C ? A ? 65 0 + ATOM 474 CD . GLN A 65 ? -32.04300 -3.42300 7.34400 1.000 82.48000 C ? A ? 65 0 + ATOM 475 OE1 . GLN A 65 ? -31.62700 -2.73700 6.42900 1.000 82.48000 O ? A ? 65 0 + ATOM 476 NE2 . GLN A 65 ? -32.92700 -2.88800 8.15800 1.000 82.48000 N ? A ? 65 0 + ATOM 477 N . GLY A 66 ? -27.94400 -7.85900 6.32200 1.000 86.08000 N ? A ? 66 0 + ATOM 478 CA . GLY A 66 ? -26.91200 -8.47800 5.48900 1.000 86.08000 C ? A ? 66 0 + ATOM 479 C . GLY A 66 ? -25.77100 -7.55000 5.07100 1.000 86.08000 C ? A ? 66 0 + ATOM 480 O . GLY A 66 ? -24.92400 -7.97100 4.28100 1.000 86.08000 O ? A ? 66 0 + ATOM 481 N . ALA A 67 ? -25.69900 -6.32500 5.60300 1.000 86.59000 N ? A ? 67 0 + ATOM 482 CA . ALA A 67 ? -24.60400 -5.38900 5.34100 1.000 86.59000 C ? A ? 67 0 + ATOM 483 C . ALA A 67 ? -23.32200 -5.76200 6.11400 1.000 86.59000 C ? A ? 67 0 + ATOM 484 O . ALA A 67 ? -22.80800 -4.98100 6.90700 1.000 86.59000 O ? A ? 67 0 + ATOM 485 CB . ALA A 67 ? -25.09600 -3.96300 5.62200 1.000 86.59000 C ? A ? 67 0 + ATOM 486 N . ASN A 68 ? -22.81500 -6.98000 5.92200 1.000 92.76000 N ? A ? 68 0 + ATOM 487 CA . ASN A 68 ? -21.67500 -7.49500 6.67700 1.000 92.76000 C ? A ? 68 0 + ATOM 488 C . ASN A 68 ? -20.36500 -6.81400 6.25900 1.000 92.76000 C ? A ? 68 0 + ATOM 489 O . ASN A 68 ? -20.14300 -6.53800 5.08100 1.000 92.76000 O ? A ? 68 0 + ATOM 490 CB . ASN A 68 ? -21.58500 -9.02100 6.52200 1.000 92.76000 C ? A ? 68 0 + ATOM 491 CG . ASN A 68 ? -22.80900 -9.75700 7.03300 1.000 92.76000 C ? A ? 68 0 + ATOM 492 OD1 . ASN A 68 ? -23.64800 -9.24700 7.75600 1.000 92.76000 O ? A ? 68 0 + ATOM 493 ND2 . ASN A 68 ? -22.95000 -11.01300 6.68200 1.000 92.76000 N ? A ? 68 0 + ATOM 494 N . SER A 69 ? -19.46400 -6.62600 7.21800 1.000 93.63000 N ? A ? 69 0 + ATOM 495 CA . SER A 69 ? -18.11000 -6.12100 6.97700 1.000 93.63000 C ? A ? 69 0 + ATOM 496 C . SER A 69 ? -17.08800 -6.97800 7.71500 1.000 93.63000 C ? A ? 69 0 + ATOM 497 O . SER A 69 ? -17.42700 -7.72100 8.63700 1.000 93.63000 O ? A ? 69 0 + ATOM 498 CB . SER A 69 ? -18.00500 -4.64300 7.35500 1.000 93.63000 C ? A ? 69 0 + ATOM 499 OG . SER A 69 ? -16.73400 -4.16300 6.96800 1.000 93.63000 O ? A ? 69 0 + ATOM 500 N . SER A 70 ? -15.82900 -6.92900 7.29600 1.000 95.92000 N ? A ? 70 0 + ATOM 501 CA . SER A 70 ? -14.77000 -7.70900 7.92900 1.000 95.92000 C ? A ? 70 0 + ATOM 502 C . SER A 70 ? -13.41800 -7.02400 7.82300 1.000 95.92000 C ? A ? 70 0 + ATOM 503 O . SER A 70 ? -13.20900 -6.15300 6.98100 1.000 95.92000 O ? A ? 70 0 + ATOM 504 CB . SER A 70 ? -14.71200 -9.12500 7.34100 1.000 95.92000 C ? A ? 70 0 + ATOM 505 OG . SER A 70 ? -14.35300 -9.09500 5.97400 1.000 95.92000 O ? A ? 70 0 + ATOM 506 N . CYS A 71 ? -12.49200 -7.43800 8.67800 1.000 95.74000 N ? A ? 71 0 + ATOM 507 CA . CYS A 71 ? -11.10000 -7.02700 8.59900 1.000 95.74000 C ? A ? 71 0 + ATOM 508 C . CYS A 71 ? -10.18700 -8.17700 9.05500 1.000 95.74000 C ? A ? 71 0 + ATOM 509 O . CYS A 71 ? -10.62700 -9.10600 9.73600 1.000 95.74000 O ? A ? 71 0 + ATOM 510 CB . CYS A 71 ? -10.93300 -5.72400 9.38800 1.000 95.74000 C ? A ? 71 0 + ATOM 511 SG . CYS A 71 ? -10.86200 -5.90400 11.17800 1.000 95.74000 S ? A ? 71 0 + ATOM 512 N . SER A 72 ? -8.92000 -8.15600 8.64100 1.000 95.46000 N ? A ? 72 0 + ATOM 513 CA . SER A 72 ? -7.92000 -9.15100 9.04600 1.000 95.46000 C ? A ? 72 0 + ATOM 514 C . SER A 72 ? -6.63500 -8.46100 9.48100 1.000 95.46000 C ? A ? 72 0 + ATOM 515 O . SER A 72 ? -6.21400 -7.49400 8.84900 1.000 95.46000 O ? A ? 72 0 + ATOM 516 CB . SER A 72 ? -7.62900 -10.14000 7.91500 1.000 95.46000 C ? A ? 72 0 + ATOM 517 OG . SER A 72 ? -8.79600 -10.87100 7.59300 1.000 95.46000 O ? A ? 72 0 + ATOM 518 N . ALA A 73 ? -6.00900 -8.96000 10.54500 1.000 94.81000 N ? A ? 73 0 + ATOM 519 CA . ALA A 73 ? -4.80600 -8.36300 11.11400 1.000 94.81000 C ? A ? 73 0 + ATOM 520 C . ALA A 73 ? -3.86200 -9.41700 11.70600 1.000 94.81000 C ? A ? 73 0 + ATOM 521 O . ALA A 73 ? -4.28800 -10.45600 12.20900 1.000 94.81000 O ? A ? 73 0 + ATOM 522 CB . ALA A 73 ? -5.22000 -7.33300 12.17000 1.000 94.81000 C ? A ? 73 0 + ATOM 523 N . THR A 74 ? -2.55900 -9.13900 11.66500 1.000 94.25000 N ? A ? 74 0 + ATOM 524 CA . THR A 74 ? -1.53200 -9.87700 12.42500 1.000 94.25000 C ? A ? 74 0 + ATOM 525 C . THR A 74 ? -1.28100 -9.25700 13.80300 1.000 94.25000 C ? A ? 74 0 + ATOM 526 O . THR A 74 ? -0.63600 -9.86800 14.65400 1.000 94.25000 O ? A ? 74 0 + ATOM 527 CB . THR A 74 ? -0.21600 -9.93600 11.64100 1.000 94.25000 C ? A ? 74 0 + ATOM 528 OG1 . THR A 74 ? 0.16300 -8.63400 11.25300 1.000 94.25000 O ? A ? 74 0 + ATOM 529 CG2 . THR A 74 ? -0.34900 -10.77000 10.36700 1.000 94.25000 C ? A ? 74 0 + ATOM 530 N . THR A 75 ? -1.80000 -8.05000 14.03300 1.000 94.54000 N ? A ? 75 0 + ATOM 531 CA . THR A 75 ? -1.79600 -7.33900 15.31300 1.000 94.54000 C ? A ? 75 0 + ATOM 532 C . THR A 75 ? -2.97700 -7.76900 16.19300 1.000 94.54000 C ? A ? 75 0 + ATOM 533 O . THR A 75 ? -3.81900 -8.57200 15.79600 1.000 94.54000 O ? A ? 75 0 + ATOM 534 CB . THR A 75 ? -1.80800 -5.81600 15.06800 1.000 94.54000 C ? A ? 75 0 + ATOM 535 OG1 . THR A 75 ? -2.87500 -5.47300 14.22100 1.000 94.54000 O ? A ? 75 0 + ATOM 536 CG2 . THR A 75 ? -0.52200 -5.35200 14.38000 1.000 94.54000 C ? A ? 75 0 + ATOM 537 N . LEU A 76 ? -3.03300 -7.24000 17.42000 1.000 95.39000 N ? A ? 76 0 + ATOM 538 CA . LEU A 76 ? -4.11000 -7.48700 18.39500 1.000 95.39000 C ? A ? 76 0 + ATOM 539 C . LEU A 76 ? -5.26900 -6.48100 18.29000 1.000 95.39000 C ? A ? 76 0 + ATOM 540 O . LEU A 76 ? -6.05100 -6.30700 19.22500 1.000 95.39000 O ? A ? 76 0 + ATOM 541 CB . LEU A 76 ? -3.51600 -7.51200 19.81200 1.000 95.39000 C ? A ? 76 0 + ATOM 542 CG . LEU A 76 ? -2.44100 -8.58300 20.04500 1.000 95.39000 C ? A ? 76 0 + ATOM 543 CD1 . LEU A 76 ? -1.94100 -8.48200 21.48600 1.000 95.39000 C ? A ? 76 0 + ATOM 544 CD2 . LEU A 76 ? -2.96500 -10.00000 19.80300 1.000 95.39000 C ? A ? 76 0 + ATOM 545 N . ASN A 77 ? -5.32900 -5.76300 17.17400 1.000 94.82000 N ? A ? 77 0 + ATOM 546 CA . ASN A 77 ? -6.37800 -4.81500 16.86600 1.000 94.82000 C ? A ? 77 0 + ATOM 547 C . ASN A 77 ? -6.67900 -4.84300 15.37100 1.000 94.82000 C ? A ? 77 0 + ATOM 548 O . ASN A 77 ? -5.82400 -5.20200 14.56200 1.000 94.82000 O ? A ? 77 0 + ATOM 549 CB . ASN A 77 ? -6.00000 -3.41600 17.38400 1.000 94.82000 C ? A ? 77 0 + ATOM 550 CG . ASN A 77 ? -4.72300 -2.82700 16.80200 1.000 94.82000 C ? A ? 77 0 + ATOM 551 OD1 . ASN A 77 ? -4.23800 -3.15600 15.73300 1.000 94.82000 O ? A ? 77 0 + ATOM 552 ND2 . ASN A 77 ? -4.09800 -1.92400 17.51800 1.000 94.82000 N ? A ? 77 0 + ATOM 553 N . CYS A 78 ? -7.90000 -4.48600 14.99900 1.000 94.63000 N ? A ? 78 0 + ATOM 554 CA . CYS A 78 ? -8.29000 -4.42100 13.60100 1.000 94.63000 C ? A ? 78 0 + ATOM 555 C . CYS A 78 ? -9.45400 -3.45900 13.42400 1.000 94.63000 C ? A ? 78 0 + ATOM 556 O . CYS A 78 ? -10.38100 -3.45000 14.23500 1.000 94.63000 O ? A ? 78 0 + ATOM 557 CB . CYS A 78 ? -8.61200 -5.84000 13.14700 1.000 94.63000 C ? A ? 78 0 + ATOM 558 SG . CYS A 78 ? -8.87800 -6.12200 11.40000 1.000 94.63000 S ? A ? 78 0 + ATOM 559 N . ASN A 79 ? -9.38100 -2.64200 12.37700 1.000 93.71000 N ? A ? 79 0 + ATOM 560 CA . ASN A 79 ? -10.43800 -1.70400 12.05400 1.000 93.71000 C ? A ? 79 0 + ATOM 561 C . ASN A 79 ? -11.41100 -2.33800 11.06400 1.000 93.71000 C ? A ? 79 0 + ATOM 562 O . ASN A 79 ? -11.00600 -2.66500 9.95000 1.000 93.71000 O ? A ? 79 0 + ATOM 563 CB . ASN A 79 ? -9.83900 -0.40600 11.49500 1.000 93.71000 C ? A ? 79 0 + ATOM 564 CG . ASN A 79 ? -10.89100 0.68000 11.48900 1.000 93.71000 C ? A ? 79 0 + ATOM 565 OD1 . ASN A 79 ? -11.88600 0.57500 12.18200 1.000 93.71000 O ? A ? 79 0 + ATOM 566 ND2 . ASN A 79 ? -10.73100 1.73000 10.72500 1.000 93.71000 N ? A ? 79 0 + ATOM 567 N . VAL A 80 ? -12.67100 -2.51400 11.45800 1.000 94.29000 N ? A ? 80 0 + ATOM 568 CA . VAL A 80 ? -13.73200 -2.99800 10.56800 1.000 94.29000 C ? A ? 80 0 + ATOM 569 C . VAL A 80 ? -14.37500 -1.79400 9.87400 1.000 94.29000 C ? A ? 80 0 + ATOM 570 O . VAL A 80 ? -15.07100 -1.03600 10.55100 1.000 94.29000 O ? A ? 80 0 + ATOM 571 CB . VAL A 80 ? -14.78900 -3.82200 11.32200 1.000 94.29000 C ? A ? 80 0 + ATOM 572 CG1 . VAL A 80 ? -15.79800 -4.38800 10.31600 1.000 94.29000 C ? A ? 80 0 + ATOM 573 CG2 . VAL A 80 ? -14.18200 -5.01100 12.07500 1.000 94.29000 C ? A ? 80 0 + ATOM 574 N . PRO A 81 ? -14.16500 -1.58700 8.56000 1.000 91.02000 N ? A ? 81 0 + ATOM 575 CA . PRO A 81 ? -14.60700 -0.37800 7.86900 1.000 91.02000 C ? A ? 81 0 + ATOM 576 C . PRO A 81 ? -16.05200 -0.47700 7.35600 1.000 91.02000 C ? A ? 81 0 + ATOM 577 O . PRO A 81 ? -16.63200 -1.56300 7.28900 1.000 91.02000 O ? A ? 81 0 + ATOM 578 CB . PRO A 81 ? -13.60300 -0.21900 6.72400 1.000 91.02000 C ? A ? 81 0 + ATOM 579 CG . PRO A 81 ? -13.32600 -1.66700 6.32000 1.000 91.02000 C ? A ? 81 0 + ATOM 580 CD . PRO A 81 ? -13.36900 -2.41200 7.65200 1.000 91.02000 C ? A ? 81 0 + ATOM 581 N . GLY A 82 ? -16.61000 0.65500 6.91600 1.000 84.64000 N ? A ? 82 0 + ATOM 582 CA . GLY A 82 ? -17.78800 0.68300 6.04100 1.000 84.64000 C ? A ? 82 0 + ATOM 583 C . GLY A 82 ? -19.11100 0.26900 6.69100 1.000 84.64000 C ? A ? 82 0 + ATOM 584 O . GLY A 82 ? -19.98200 -0.27200 6.00700 1.000 84.64000 O ? A ? 82 0 + ATOM 585 N . LEU A 83 ? -19.28700 0.49700 7.99700 1.000 89.54000 N ? A ? 83 0 + ATOM 586 CA . LEU A 83 ? -20.54300 0.17100 8.66900 1.000 89.54000 C ? A ? 83 0 + ATOM 587 C . LEU A 83 ? -21.64000 1.17600 8.28200 1.000 89.54000 C ? A ? 83 0 + ATOM 588 O . LEU A 83 ? -21.46900 2.39800 8.32300 1.000 89.54000 O ? A ? 83 0 + ATOM 589 CB . LEU A 83 ? -20.35800 0.06900 10.19200 1.000 89.54000 C ? A ? 83 0 + ATOM 590 CG . LEU A 83 ? -19.19000 -0.82400 10.65500 1.000 89.54000 C ? A ? 83 0 + ATOM 591 CD1 . LEU A 83 ? -19.13700 -0.80300 12.17900 1.000 89.54000 C ? A ? 83 0 + ATOM 592 CD2 . LEU A 83 ? -19.32900 -2.28000 10.21700 1.000 89.54000 C ? A ? 83 0 + ATOM 593 N . GLN A 84 ? -22.81000 0.65800 7.92800 1.000 85.82000 N ? A ? 84 0 + ATOM 594 CA . GLN A 84 ? -23.98300 1.47500 7.62100 1.000 85.82000 C ? A ? 84 0 + ATOM 595 C . GLN A 84 ? -24.52000 2.17100 8.87700 1.000 85.82000 C ? A ? 84 0 + ATOM 596 O . GLN A 84 ? -24.45900 1.63400 9.98600 1.000 85.82000 O ? A ? 84 0 + ATOM 597 CB . GLN A 84 ? -25.07600 0.63200 6.94300 1.000 85.82000 C ? A ? 84 0 + ATOM 598 CG . GLN A 84 ? -24.60500 -0.01300 5.62900 1.000 85.82000 C ? A ? 84 0 + ATOM 599 CD . GLN A 84 ? -24.17400 1.02100 4.59200 1.000 85.82000 C ? A ? 84 0 + ATOM 600 OE1 . GLN A 84 ? -24.81300 2.04300 4.39600 1.000 85.82000 O ? A ? 84 0 + ATOM 601 NE2 . GLN A 84 ? -23.06000 0.82200 3.92300 1.000 85.82000 N ? A ? 84 0 + ATOM 602 N . CYS A 85 ? -25.07600 3.36500 8.69300 1.000 83.02000 N ? A ? 85 0 + ATOM 603 CA . CYS A 85 ? -25.74500 4.12600 9.74400 1.000 83.02000 C ? A ? 85 0 + ATOM 604 C . CYS A 85 ? -27.02600 3.44500 10.24900 1.000 83.02000 C ? A ? 85 0 + ATOM 605 O . CYS A 85 ? -27.76100 2.84100 9.47400 1.000 83.02000 O ? A ? 85 0 + ATOM 606 CB . CYS A 85 ? -26.09400 5.49900 9.18100 1.000 83.02000 C ? A ? 85 0 + ATOM 607 SG . CYS A 85 ? -24.86600 6.77000 9.49000 1.000 83.02000 S ? A ? 85 0 + ATOM 608 N . GLY A 86 ? -27.32600 3.60800 11.54100 1.000 82.47000 N ? A ? 86 0 + ATOM 609 CA . GLY A 86 ? -28.54300 3.09900 12.18300 1.000 82.47000 C ? A ? 86 0 + ATOM 610 C . GLY A 86 ? -28.63600 1.57300 12.30700 1.000 82.47000 C ? A ? 86 0 + ATOM 611 O . GLY A 86 ? -29.69100 1.06100 12.67800 1.000 82.47000 O ? A ? 86 0 + ATOM 612 N . GLY A 87 ? -27.56100 0.84600 12.00000 1.000 86.39000 N ? A ? 87 0 + ATOM 613 CA . GLY A 87 ? -27.49600 -0.61100 12.06800 1.000 86.39000 C ? A ? 87 0 + ATOM 614 C . GLY A 87 ? -26.97200 -1.11100 13.41400 1.000 86.39000 C ? A ? 87 0 + ATOM 615 O . GLY A 87 ? -26.17300 -0.45200 14.08000 1.000 86.39000 O ? A ? 87 0 + ATOM 616 N . THR A 88 ? -27.39100 -2.31300 13.81000 1.000 92.11000 N ? A ? 88 0 + ATOM 617 CA . THR A 88 ? -26.80000 -3.03600 14.94600 1.000 92.11000 C ? A ? 88 0 + ATOM 618 C . THR A 88 ? -25.94300 -4.17400 14.41600 1.000 92.11000 C ? A ? 88 0 + ATOM 619 O . THR A 88 ? -26.46400 -5.11100 13.80900 1.000 92.11000 O ? A ? 88 0 + ATOM 620 CB . THR A 88 ? -27.86100 -3.57700 15.91300 1.000 92.11000 C ? A ? 88 0 + ATOM 621 OG1 . THR A 88 ? -28.73900 -2.55900 16.33400 1.000 92.11000 O ? A ? 88 0 + ATOM 622 CG2 . THR A 88 ? -27.23200 -4.17000 17.17500 1.000 92.11000 C ? A ? 88 0 + ATOM 623 N . TYR A 89 ? -24.64100 -4.09900 14.67800 1.000 93.89000 N ? A ? 89 0 + ATOM 624 CA . TYR A 89 ? -23.65000 -5.06700 14.22400 1.000 93.89000 C ? A ? 89 0 + ATOM 625 C . TYR A 89 ? -23.24100 -5.98600 15.36900 1.000 93.89000 C ? A ? 89 0 + ATOM 626 O . TYR A 89 ? -22.98300 -5.51900 16.47700 1.000 93.89000 O ? A ? 89 0 + ATOM 627 CB . TYR A 89 ? -22.43500 -4.33500 13.64900 1.000 93.89000 C ? A ? 89 0 + ATOM 628 CG . TYR A 89 ? -22.71600 -3.66500 12.32500 1.000 93.89000 C ? A ? 89 0 + ATOM 629 CD1 . TYR A 89 ? -22.31400 -4.28800 11.13100 1.000 93.89000 C ? A ? 89 0 + ATOM 630 CD2 . TYR A 89 ? -23.39500 -2.43000 12.28500 1.000 93.89000 C ? A ? 89 0 + ATOM 631 CE1 . TYR A 89 ? -22.58400 -3.67000 9.89900 1.000 93.89000 C ? A ? 89 0 + ATOM 632 CE2 . TYR A 89 ? -23.72400 -1.84600 11.04900 1.000 93.89000 C ? A ? 89 0 + ATOM 633 CZ . TYR A 89 ? -23.33100 -2.47900 9.85200 1.000 93.89000 C ? A ? 89 0 + ATOM 634 OH . TYR A 89 ? -23.70800 -1.95600 8.66200 1.000 93.89000 O ? A ? 89 0 + ATOM 635 N . THR A 90 ? -23.16200 -7.28600 15.09100 1.000 95.39000 N ? A ? 90 0 + ATOM 636 CA . THR A 90 ? -22.59400 -8.29200 15.99900 1.000 95.39000 C ? A ? 90 0 + ATOM 637 C . THR A 90 ? -21.20900 -8.68500 15.50200 1.000 95.39000 C ? A ? 90 0 + ATOM 638 O . THR A 90 ? -21.06700 -9.09500 14.35100 1.000 95.39000 O ? A ? 90 0 + ATOM 639 CB . THR A 90 ? -23.50200 -9.52500 16.11400 1.000 95.39000 C ? A ? 90 0 + ATOM 640 OG1 . THR A 90 ? -24.81600 -9.12300 16.44700 1.000 95.39000 O ? A ? 90 0 + ATOM 641 CG2 . THR A 90 ? -23.02800 -10.47800 17.20700 1.000 95.39000 C ? A ? 90 0 + ATOM 642 N . PHE A 91 ? -20.19500 -8.54500 16.35300 1.000 95.89000 N ? A ? 91 0 + ATOM 643 CA . PHE A 91 ? -18.79400 -8.77000 16.00200 1.000 95.89000 C ? A ? 91 0 + ATOM 644 C . PHE A 91 ? -18.31700 -10.14100 16.47500 1.000 95.89000 C ? A ? 91 0 + ATOM 645 O . PHE A 91 ? -18.61400 -10.54800 17.59600 1.000 95.89000 O ? A ? 91 0 + ATOM 646 CB . PHE A 91 ? -17.91900 -7.65400 16.58200 1.000 95.89000 C ? A ? 91 0 + ATOM 647 CG . PHE A 91 ? -18.17300 -6.30000 15.95300 1.000 95.89000 C ? A ? 91 0 + ATOM 648 CD1 . PHE A 91 ? -17.32500 -5.81300 14.94000 1.000 95.89000 C ? A ? 91 0 + ATOM 649 CD2 . PHE A 91 ? -19.28700 -5.54200 16.35500 1.000 95.89000 C ? A ? 91 0 + ATOM 650 CE1 . PHE A 91 ? -17.59900 -4.57900 14.32400 1.000 95.89000 C ? A ? 91 0 + ATOM 651 CE2 . PHE A 91 ? -19.58000 -4.33100 15.71200 1.000 95.89000 C ? A ? 91 0 + ATOM 652 CZ . PHE A 91 ? -18.74000 -3.84900 14.69500 1.000 95.89000 C ? A ? 91 0 + ATOM 653 N . TYR A 92 ? -17.53800 -10.81800 15.63600 1.000 95.78000 N ? A ? 92 0 + ATOM 654 CA . TYR A 92 ? -16.92800 -12.11700 15.90800 1.000 95.78000 C ? A ? 92 0 + ATOM 655 C . TYR A 92 ? -15.43500 -12.05800 15.60300 1.000 95.78000 C ? A ? 92 0 + ATOM 656 O . TYR A 92 ? -15.05700 -11.70000 14.49000 1.000 95.78000 O ? A ? 92 0 + ATOM 657 CB . TYR A 92 ? -17.59300 -13.18400 15.03100 1.000 95.78000 C ? A ? 92 0 + ATOM 658 CG . TYR A 92 ? -19.08200 -13.33600 15.25200 1.000 95.78000 C ? A ? 92 0 + ATOM 659 CD1 . TYR A 92 ? -19.55900 -14.12700 16.31400 1.000 95.78000 C ? A ? 92 0 + ATOM 660 CD2 . TYR A 92 ? -19.98500 -12.66400 14.40600 1.000 95.78000 C ? A ? 92 0 + ATOM 661 CE1 . TYR A 92 ? -20.94500 -14.25600 16.52500 1.000 95.78000 C ? A ? 92 0 + ATOM 662 CE2 . TYR A 92 ? -21.37000 -12.79100 14.61400 1.000 95.78000 C ? A ? 92 0 + ATOM 663 CZ . TYR A 92 ? -21.85100 -13.58800 15.67200 1.000 95.78000 C ? A ? 92 0 + ATOM 664 OH . TYR A 92 ? -23.18800 -13.70000 15.88100 1.000 95.78000 O ? A ? 92 0 + ATOM 665 N . VAL A 93 ? -14.58700 -12.44100 16.56000 1.000 96.54000 N ? A ? 93 0 + ATOM 666 CA . VAL A 93 ? -13.13000 -12.51500 16.37100 1.000 96.54000 C ? A ? 93 0 + ATOM 667 C . VAL A 93 ? -12.71300 -13.97700 16.27300 1.000 96.54000 C ? A ? 93 0 + ATOM 668 O . VAL A 93 ? -13.05000 -14.78200 17.13600 1.000 96.54000 O ? A ? 93 0 + ATOM 669 CB . VAL A 93 ? -12.36200 -11.78700 17.49100 1.000 96.54000 C ? A ? 93 0 + ATOM 670 CG1 . VAL A 93 ? -10.85700 -11.74100 17.18800 1.000 96.54000 C ? A ? 93 0 + ATOM 671 CG2 . VAL A 93 ? -12.84600 -10.33900 17.65600 1.000 96.54000 C ? A ? 93 0 + ATOM 672 N . THR A 94 ? -11.96800 -14.32500 15.22900 1.000 96.39000 N ? A ? 94 0 + ATOM 673 CA . THR A 94 ? -11.46100 -15.68200 14.99100 1.000 96.39000 C ? A ? 94 0 + ATOM 674 C . THR A 94 ? -9.94300 -15.64500 14.87400 1.000 96.39000 C ? A ? 94 0 + ATOM 675 O . THR A 94 ? -9.40300 -14.87600 14.08400 1.000 96.39000 O ? A ? 94 0 + ATOM 676 CB . THR A 94 ? -12.08900 -16.28100 13.72400 1.000 96.39000 C ? A ? 94 0 + ATOM 677 OG1 . THR A 94 ? -13.49400 -16.24400 13.82800 1.000 96.39000 O ? A ? 94 0 + ATOM 678 CG2 . THR A 94 ? -11.68800 -17.74000 13.52400 1.000 96.39000 C ? A ? 94 0 + ATOM 679 N . ALA A 95 ? -9.24000 -16.47900 15.64100 1.000 96.34000 N ? A ? 95 0 + ATOM 680 CA . ALA A 95 ? -7.79900 -16.68300 15.49600 1.000 96.34000 C ? A ? 95 0 + ATOM 681 C . ALA A 95 ? -7.48500 -17.70600 14.39400 1.000 96.34000 C ? A ? 95 0 + ATOM 682 O . ALA A 95 ? -8.13700 -18.75300 14.32000 1.000 96.34000 O ? A ? 95 0 + ATOM 683 CB . ALA A 95 ? -7.20700 -17.11800 16.83900 1.000 96.34000 C ? A ? 95 0 + ATOM 684 N . LEU A 96 ? -6.45100 -17.43200 13.59400 1.000 95.02000 N ? A ? 96 0 + ATOM 685 CA . LEU A 96 ? -5.97400 -18.26200 12.48800 1.000 95.02000 C ? A ? 96 0 + ATOM 686 C . LEU A 96 ? -4.48500 -18.59800 12.64400 1.000 95.02000 C ? A ? 96 0 + ATOM 687 O . LEU A 96 ? -3.69700 -17.82000 13.18500 1.000 95.02000 O ? A ? 96 0 + ATOM 688 CB . LEU A 96 ? -6.20900 -17.56600 11.13200 1.000 95.02000 C ? A ? 96 0 + ATOM 689 CG . LEU A 96 ? -7.67300 -17.18900 10.83400 1.000 95.02000 C ? A ? 96 0 + ATOM 690 CD1 . LEU A 96 ? -7.94200 -15.71800 11.14700 1.000 95.02000 C ? A ? 96 0 + ATOM 691 CD2 . LEU A 96 ? -8.00500 -17.41200 9.35900 1.000 95.02000 C ? A ? 96 0 + ATOM 692 N . ASN A 97 ? -4.08700 -19.76200 12.13600 1.000 91.28000 N ? A ? 97 0 + ATOM 693 CA . ASN A 97 ? -2.69200 -20.10300 11.86300 1.000 91.28000 C ? A ? 97 0 + ATOM 694 C . ASN A 97 ? -2.55000 -20.66200 10.43900 1.000 91.28000 C ? A ? 97 0 + ATOM 695 O . ASN A 97 ? -3.50200 -20.64200 9.66700 1.000 91.28000 O ? A ? 97 0 + ATOM 696 CB . ASN A 97 ? -2.16100 -21.02400 12.97600 1.000 91.28000 C ? A ? 97 0 + ATOM 697 CG . ASN A 97 ? -2.73200 -22.43200 13.00600 1.000 91.28000 C ? A ? 97 0 + ATOM 698 OD1 . ASN A 97 ? -3.19600 -22.98500 12.02800 1.000 91.28000 O ? A ? 97 0 + ATOM 699 ND2 . ASN A 97 ? -2.61700 -23.08200 14.13600 1.000 91.28000 N ? A ? 97 0 + ATOM 700 N . SER A 98 ? -1.37000 -21.16900 10.07900 1.000 87.92000 N ? A ? 98 0 + ATOM 701 CA . SER A 98 ? -1.09200 -21.67900 8.72800 1.000 87.92000 C ? A ? 98 0 + ATOM 702 C . SER A 98 ? -1.96800 -22.85800 8.28300 1.000 87.92000 C ? A ? 98 0 + ATOM 703 O . SER A 98 ? -1.95400 -23.19000 7.10300 1.000 87.92000 O ? A ? 98 0 + ATOM 704 CB . SER A 98 ? 0.37000 -22.12800 8.63800 1.000 87.92000 C ? A ? 98 0 + ATOM 705 OG . SER A 98 ? 1.24200 -21.12500 9.12700 1.000 87.92000 O ? A ? 98 0 + ATOM 706 N . PHE A 99 ? -2.68200 -23.51600 9.20200 1.000 85.05000 N ? A ? 99 0 + ATOM 707 CA . PHE A 99 ? -3.40100 -24.76500 8.93600 1.000 85.05000 C ? A ? 99 0 + ATOM 708 C . PHE A 99 ? -4.88400 -24.71500 9.31900 1.000 85.05000 C ? A ? 99 0 + ATOM 709 O . PHE A 99 ? -5.70900 -25.32700 8.64800 1.000 85.05000 O ? A ? 99 0 + ATOM 710 CB . PHE A 99 ? -2.70200 -25.90000 9.69900 1.000 85.05000 C ? A ? 99 0 + ATOM 711 CG . PHE A 99 ? -1.24300 -26.10100 9.33200 1.000 85.05000 C ? A ? 99 0 + ATOM 712 CD1 . PHE A 99 ? -0.90800 -26.72000 8.11400 1.000 85.05000 C ? A ? 99 0 + ATOM 713 CD2 . PHE A 99 ? -0.22100 -25.66600 10.19900 1.000 85.05000 C ? A ? 99 0 + ATOM 714 CE1 . PHE A 99 ? 0.44000 -26.91700 7.76900 1.000 85.05000 C ? A ? 99 0 + ATOM 715 CE2 . PHE A 99 ? 1.12900 -25.86300 9.85300 1.000 85.05000 C ? A ? 99 0 + ATOM 716 CZ . PHE A 99 ? 1.45800 -26.49300 8.64000 1.000 85.05000 C ? A ? 99 0 + ATOM 717 N . CYS A 100 ? -5.22700 -24.01600 10.40200 1.000 89.65000 N ? A ? 100 0 + ATOM 718 CA . CYS A 100 ? -6.52200 -24.11000 11.06400 1.000 89.65000 C ? A ? 100 0 + ATOM 719 C . CYS A 100 ? -7.00600 -22.74700 11.57800 1.000 89.65000 C ? A ? 100 0 + ATOM 720 O . CYS A 100 ? -6.21600 -21.86100 11.91600 1.000 89.65000 O ? A ? 100 0 + ATOM 721 CB . CYS A 100 ? -6.39900 -25.08500 12.24600 1.000 89.65000 C ? A ? 100 0 + ATOM 722 SG . CYS A 100 ? -6.10100 -26.79000 11.69500 1.000 89.65000 S ? A ? 100 0 + ATOM 723 N . GLN A 101 ? -8.32500 -22.64300 11.73800 1.000 93.66000 N ? A ? 101 0 + ATOM 724 CA . GLN A 101 ? -9.00200 -21.55400 12.43900 1.000 93.66000 C ? A ? 101 0 + ATOM 725 C . GLN A 101 ? -9.57700 -22.04500 13.77200 1.000 93.66000 C ? A ? 101 0 + ATOM 726 O . GLN A 101 ? -9.94100 -23.21400 13.91600 1.000 93.66000 O ? A ? 101 0 + ATOM 727 CB . GLN A 101 ? -10.06200 -20.91300 11.53100 1.000 93.66000 C ? A ? 101 0 + ATOM 728 CG . GLN A 101 ? -11.21700 -21.86000 11.15400 1.000 93.66000 C ? A ? 101 0 + ATOM 729 CD . GLN A 101 ? -12.17000 -21.25300 10.12700 1.000 93.66000 C ? A ? 101 0 + ATOM 730 OE1 . GLN A 101 ? -12.08400 -20.10200 9.74100 1.000 93.66000 O ? A ? 101 0 + ATOM 731 NE2 . GLN A 101 ? -13.11200 -22.01600 9.62100 1.000 93.66000 N ? A ? 101 0 + ATOM 732 N . SER A 102 ? -9.63200 -21.15100 14.75100 1.000 93.76000 N ? A ? 102 0 + ATOM 733 CA . SER A 102 ? -10.34300 -21.36800 16.01500 1.000 93.76000 C ? A ? 102 0 + ATOM 734 C . SER A 102 ? -11.86200 -21.24200 15.82900 1.000 93.76000 C ? A ? 102 0 + ATOM 735 O . SER A 102 ? -12.33700 -20.80000 14.78300 1.000 93.76000 O ? A ? 102 0 + ATOM 736 CB . SER A 102 ? -9.82600 -20.39300 17.07900 1.000 93.76000 C ? A ? 102 0 + ATOM 737 OG . SER A 102 ? -9.99700 -19.06400 16.64300 1.000 93.76000 O ? A ? 102 0 + ATOM 738 N . SER A 103 ? -12.63700 -21.62000 16.84900 1.000 94.15000 N ? A ? 103 0 + ATOM 739 CA . SER A 103 ? -14.03200 -21.16200 16.92900 1.000 94.15000 C ? A ? 103 0 + ATOM 740 C . SER A 103 ? -14.06000 -19.65100 17.20100 1.000 94.15000 C ? A ? 103 0 + ATOM 741 O . SER A 103 ? -13.13600 -19.15900 17.85700 1.000 94.15000 O ? A ? 103 0 + ATOM 742 CB . SER A 103 ? -14.80700 -21.88200 18.03500 1.000 94.15000 C ? A ? 103 0 + ATOM 743 OG . SER A 103 ? -14.86100 -23.27500 17.78300 1.000 94.15000 O ? A ? 103 0 + ATOM 744 N . PRO A 104 ? -15.09800 -18.91900 16.75500 1.000 92.86000 N ? A ? 104 0 + ATOM 745 CA . PRO A 104 ? -15.25500 -17.51200 17.09700 1.000 92.86000 C ? A ? 104 0 + ATOM 746 C . PRO A 104 ? -15.25400 -17.28500 18.61200 1.000 92.86000 C ? A ? 104 0 + ATOM 747 O . PRO A 104 ? -15.79800 -18.09300 19.36800 1.000 92.86000 O ? A ? 104 0 + ATOM 748 CB . PRO A 104 ? -16.57900 -17.07200 16.47000 1.000 92.86000 C ? A ? 104 0 + ATOM 749 CG . PRO A 104 ? -16.76100 -18.04800 15.31000 1.000 92.86000 C ? A ? 104 0 + ATOM 750 CD . PRO A 104 ? -16.16500 -19.34200 15.86100 1.000 92.86000 C ? A ? 104 0 + ATOM 751 N . GLY A 105 ? -14.63900 -16.18300 19.03000 1.000 91.17000 N ? A ? 105 0 + ATOM 752 CA . GLY A 105 ? -14.63100 -15.70800 20.40700 1.000 91.17000 C ? A ? 105 0 + ATOM 753 C . GLY A 105 ? -15.98700 -15.19800 20.89100 1.000 91.17000 C ? A ? 105 0 + ATOM 754 O . GLY A 105 ? -17.03100 -15.42700 20.27000 1.000 91.17000 O ? A ? 105 0 + ATOM 755 N . THR A 106 ? -15.98000 -14.49700 22.02300 1.000 92.18000 N ? A ? 106 0 + ATOM 756 CA . THR A 106 ? -17.22700 -13.96200 22.58700 1.000 92.18000 C ? A ? 106 0 + ATOM 757 C . THR A 106 ? -17.70400 -12.79300 21.73200 1.000 92.18000 C ? A ? 106 0 + ATOM 758 O . THR A 106 ? -16.96900 -11.83300 21.51200 1.000 92.18000 O ? A ? 106 0 + ATOM 759 CB . THR A 106 ? -17.08300 -13.54100 24.05300 1.000 92.18000 C ? A ? 106 0 + ATOM 760 OG1 . THR A 106 ? -16.57300 -14.62500 24.79900 1.000 92.18000 O ? A ? 106 0 + ATOM 761 CG2 . THR A 106 ? -18.43200 -13.17300 24.67600 1.000 92.18000 C ? A ? 106 0 + ATOM 762 N . SER A 107 ? -18.94200 -12.86100 21.24100 1.000 94.01000 N ? A ? 107 0 + ATOM 763 CA . SER A 107 ? -19.50300 -11.78400 20.42800 1.000 94.01000 C ? A ? 107 0 + ATOM 764 C . SER A 107 ? -19.92400 -10.58800 21.27300 1.000 94.01000 C ? A ? 107 0 + ATOM 765 O . SER A 107 ? -20.49200 -10.76100 22.35200 1.000 94.01000 O ? A ? 107 0 + ATOM 766 CB . SER A 107 ? -20.68900 -12.27400 19.59800 1.000 94.01000 C ? A ? 107 0 + ATOM 767 OG . SER A 107 ? -21.74500 -12.68900 20.44900 1.000 94.01000 O ? A ? 107 0 + ATOM 768 N . PHE A 108 ? -19.77300 -9.38500 20.73000 1.000 93.78000 N ? A ? 108 0 + ATOM 769 CA . PHE A 108 ? -20.32300 -8.15100 21.29100 1.000 93.78000 C ? A ? 108 0 + ATOM 770 C . PHE A 108 ? -21.08100 -7.37300 20.21000 1.000 93.78000 C ? A ? 108 0 + ATOM 771 O . PHE A 108 ? -20.91900 -7.63100 19.01400 1.000 93.78000 O ? A ? 108 0 + ATOM 772 CB . PHE A 108 ? -19.20100 -7.33200 21.94500 1.000 93.78000 C ? A ? 108 0 + ATOM 773 CG . PHE A 108 ? -18.14100 -6.86500 20.97100 1.000 93.78000 C ? A ? 108 0 + ATOM 774 CD1 . PHE A 108 ? -17.04200 -7.69300 20.67100 1.000 93.78000 C ? A ? 108 0 + ATOM 775 CD2 . PHE A 108 ? -18.28200 -5.62100 20.32800 1.000 93.78000 C ? A ? 108 0 + ATOM 776 CE1 . PHE A 108 ? -16.09600 -7.28100 19.71800 1.000 93.78000 C ? A ? 108 0 + ATOM 777 CE2 . PHE A 108 ? -17.33800 -5.21600 19.37200 1.000 93.78000 C ? A ? 108 0 + ATOM 778 CZ . PHE A 108 ? -16.24700 -6.04500 19.07100 1.000 93.78000 C ? A ? 108 0 + ATOM 779 N . GLN A 109 ? -21.93700 -6.43800 20.62500 1.000 94.22000 N ? A ? 109 0 + ATOM 780 CA . GLN A 109 ? -22.76500 -5.65000 19.71400 1.000 94.22000 C ? A ? 109 0 + ATOM 781 C . GLN A 109 ? -22.44700 -4.16300 19.80600 1.000 94.22000 C ? A ? 109 0 + ATOM 782 O . GLN A 109 ? -22.25700 -3.63200 20.89800 1.000 94.22000 O ? A ? 109 0 + ATOM 783 CB . GLN A 109 ? -24.26000 -5.91200 19.95100 1.000 94.22000 C ? A ? 109 0 + ATOM 784 CG . GLN A 109 ? -24.64000 -7.33200 19.51600 1.000 94.22000 C ? A ? 109 0 + ATOM 785 CD . GLN A 109 ? -26.13200 -7.62400 19.60800 1.000 94.22000 C ? A ? 109 0 + ATOM 786 OE1 . GLN A 109 ? -26.91600 -6.95300 20.26100 1.000 94.22000 O ? A ? 109 0 + ATOM 787 NE2 . GLN A 109 ? -26.58700 -8.65900 18.94000 1.000 94.22000 N ? A ? 109 0 + ATOM 788 N . ILE A 110 ? -22.43800 -3.49200 18.65400 1.000 91.74000 N ? A ? 110 0 + ATOM 789 CA . ILE A 110 ? -22.36100 -2.03200 18.55800 1.000 91.74000 C ? A ? 110 0 + ATOM 790 C . ILE A 110 ? -23.48900 -1.55600 17.65300 1.000 91.74000 C ? A ? 110 0 + ATOM 791 O . ILE A 110 ? -23.72000 -2.10200 16.57300 1.000 91.74000 O ? A ? 110 0 + ATOM 792 CB . ILE A 110 ? -20.97200 -1.55500 18.07900 1.000 91.74000 C ? A ? 110 0 + ATOM 793 CG1 . ILE A 110 ? -19.90900 -1.93500 19.13400 1.000 91.74000 C ? A ? 110 0 + ATOM 794 CG2 . ILE A 110 ? -20.95300 -0.04000 17.79300 1.000 91.74000 C ? A ? 110 0 + ATOM 795 CD1 . ILE A 110 ? -18.48200 -1.57400 18.73000 1.000 91.74000 C ? A ? 110 0 + ATOM 796 N . GLN A 111 ? -24.19300 -0.52500 18.10700 1.000 88.89000 N ? A ? 111 0 + ATOM 797 CA . GLN A 111 ? -25.19400 0.17200 17.31600 1.000 88.89000 C ? A ? 111 0 + ATOM 798 C . GLN A 111 ? -24.57700 1.44300 16.73400 1.000 88.89000 C ? A ? 111 0 + ATOM 799 O . GLN A 111 ? -24.06200 2.28100 17.47400 1.000 88.89000 O ? A ? 111 0 + ATOM 800 CB . GLN A 111 ? -26.41900 0.43900 18.19400 1.000 88.89000 C ? A ? 111 0 + ATOM 801 CG . GLN A 111 ? -27.55200 1.09800 17.39900 1.000 88.89000 C ? A ? 111 0 + ATOM 802 CD . GLN A 111 ? -28.81900 1.27600 18.22700 1.000 88.89000 C ? A ? 111 0 + ATOM 803 OE1 . GLN A 111 ? -29.03400 0.66000 19.25800 1.000 88.89000 O ? A ? 111 0 + ATOM 804 NE2 . GLN A 111 ? -29.72500 2.12000 17.79200 1.000 88.89000 N ? A ? 111 0 + ATOM 805 N . THR A 112 ? -24.63400 1.59000 15.41400 1.000 85.75000 N ? A ? 112 0 + ATOM 806 CA . THR A 112 ? -24.19700 2.81400 14.74300 1.000 85.75000 C ? A ? 112 0 + ATOM 807 C . THR A 112 ? -25.26800 3.89500 14.88400 1.000 85.75000 C ? A ? 112 0 + ATOM 808 O . THR A 112 ? -26.47100 3.61800 14.92700 1.000 85.75000 O ? A ? 112 0 + ATOM 809 CB . THR A 112 ? -23.82700 2.57300 13.27100 1.000 85.75000 C ? A ? 112 0 + ATOM 810 OG1 . THR A 112 ? -24.92500 2.08900 12.54600 1.000 85.75000 O ? A ? 112 0 + ATOM 811 CG2 . THR A 112 ? -22.70100 1.55200 13.11500 1.000 85.75000 C ? A ? 112 0 + ATOM 812 N . ALA A 113 ? -24.84200 5.15600 14.96500 1.000 79.65000 N ? A ? 113 0 + ATOM 813 CA . ALA A 113 ? -25.77700 6.27500 14.99500 1.000 79.65000 C ? A ? 113 0 + ATOM 814 C . ALA A 113 ? -26.59700 6.32800 13.68700 1.000 79.65000 C ? A ? 113 0 + ATOM 815 O . ALA A 113 ? -26.05500 6.02100 12.61900 1.000 79.65000 O ? A ? 113 0 + ATOM 816 CB . ALA A 113 ? -25.00600 7.57600 15.24400 1.000 79.65000 C ? A ? 113 0 + ATOM 817 N . PRO A 114 ? -27.88600 6.71000 13.73300 1.000 79.10000 N ? A ? 114 0 + ATOM 818 CA . PRO A 114 ? -28.65000 6.98400 12.52300 1.000 79.10000 C ? A ? 114 0 + ATOM 819 C . PRO A 114 ? -28.04700 8.18400 11.78000 1.000 79.10000 C ? A ? 114 0 + ATOM 820 O . PRO A 114 ? -27.64400 9.17000 12.39600 1.000 79.10000 O ? A ? 114 0 + ATOM 821 CB . PRO A 114 ? -30.08500 7.23900 12.99200 1.000 79.10000 C ? A ? 114 0 + ATOM 822 CG . PRO A 114 ? -29.90500 7.76600 14.41600 1.000 79.10000 C ? A ? 114 0 + ATOM 823 CD . PRO A 114 ? -28.66700 7.02500 14.91900 1.000 79.10000 C ? A ? 114 0 + ATOM 824 N . CYS A 115 ? -28.00000 8.09400 10.45400 1.000 77.65000 N ? A ? 115 0 + ATOM 825 CA . CYS A 115 ? -27.64100 9.20800 9.58400 1.000 77.65000 C ? A ? 115 0 + ATOM 826 C . CYS A 115 ? -28.89300 10.06000 9.34700 1.000 77.65000 C ? A ? 115 0 + ATOM 827 O . CYS A 115 ? -29.93400 9.51600 8.97900 1.000 77.65000 O ? A ? 115 0 + ATOM 828 CB . CYS A 115 ? -27.11300 8.66600 8.25200 1.000 77.65000 C ? A ? 115 0 + ATOM 829 SG . CYS A 115 ? -25.36900 8.17500 8.13000 1.000 77.65000 S ? A ? 115 0 + ATOM 830 N . SER A 116 ? -28.79800 11.37700 9.53700 1.000 74.95000 N ? A ? 116 0 + ATOM 831 CA . SER A 116 ? -29.92900 12.28900 9.29000 1.000 74.95000 C ? A ? 116 0 + ATOM 832 C . SER A 116 ? -29.87400 12.95900 7.91500 1.000 74.95000 C ? A ? 116 0 + ATOM 833 O . SER A 116 ? -30.90200 13.40900 7.41500 1.000 74.95000 O ? A ? 116 0 + ATOM 834 CB . SER A 116 ? -30.02200 13.37200 10.36500 1.000 74.95000 C ? A ? 116 0 + ATOM 835 OG . SER A 116 ? -30.02700 12.81900 11.66700 1.000 74.95000 O ? A ? 116 0 + ATOM 836 N . LEU A 117 ? -28.69000 13.05500 7.29800 1.000 78.26000 N ? A ? 117 0 + ATOM 837 CA . LEU A 117 ? -28.54100 13.59700 5.94500 1.000 78.26000 C ? A ? 117 0 + ATOM 838 C . LEU A 117 ? -28.59000 12.47600 4.90300 1.000 78.26000 C ? A ? 117 0 + ATOM 839 O . LEU A 117 ? -28.28200 11.31800 5.18800 1.000 78.26000 O ? A ? 117 0 + ATOM 840 CB . LEU A 117 ? -27.26200 14.44500 5.82200 1.000 78.26000 C ? A ? 117 0 + ATOM 841 CG . LEU A 117 ? -27.16200 15.63500 6.79200 1.000 78.26000 C ? A ? 117 0 + ATOM 842 CD1 . LEU A 117 ? -25.82000 16.34000 6.61500 1.000 78.26000 C ? A ? 117 0 + ATOM 843 CD2 . LEU A 117 ? -28.26800 16.66400 6.55200 1.000 78.26000 C ? A ? 117 0 + ATOM 844 N . THR A 118 ? -28.96400 12.83700 3.67800 1.000 78.01000 N ? A ? 118 0 + ATOM 845 CA . THR A 118 ? -28.93000 11.93900 2.52000 1.000 78.01000 C ? A ? 118 0 + ATOM 846 C . THR A 118 ? -27.49300 11.64700 2.08800 1.000 78.01000 C ? A ? 118 0 + ATOM 847 O . THR A 118 ? -26.54500 12.30400 2.52400 1.000 78.01000 O ? A ? 118 0 + ATOM 848 CB . THR A 118 ? -29.71800 12.54700 1.34900 1.000 78.01000 C ? A ? 118 0 + ATOM 849 OG1 . THR A 118 ? -29.25600 13.85400 1.09900 1.000 78.01000 O ? A ? 118 0 + ATOM 850 CG2 . THR A 118 ? -31.21300 12.62400 1.65300 1.000 78.01000 C ? A ? 118 0 + ATOM 851 N . SER A 119 ? -27.32700 10.66900 1.19700 1.000 81.36000 N ? A ? 119 0 + ATOM 852 CA . SER A 119 ? -26.04100 10.37200 0.56800 1.000 81.36000 C ? A ? 119 0 + ATOM 853 C . SER A 119 ? -25.43100 11.61300 -0.08800 1.000 81.36000 C ? A ? 119 0 + ATOM 854 O . SER A 119 ? -26.13200 12.43100 -0.68900 1.000 81.36000 O ? A ? 119 0 + ATOM 855 CB . SER A 119 ? -26.20300 9.26800 -0.47800 1.000 81.36000 C ? A ? 119 0 + ATOM 856 OG . SER A 119 ? -26.76800 8.12100 0.12900 1.000 81.36000 O ? A ? 119 0 + ATOM 857 N . ILE A 120 ? -24.11200 11.72400 0.03100 1.000 90.53000 N ? A ? 120 0 + ATOM 858 CA . ILE A 120 ? -23.30400 12.75600 -0.61500 1.000 90.53000 C ? A ? 120 0 + ATOM 859 C . ILE A 120 ? -22.66500 12.19400 -1.87900 1.000 90.53000 C ? A ? 120 0 + ATOM 860 O . ILE A 120 ? -22.56500 10.97900 -2.05500 1.000 90.53000 O ? A ? 120 0 + ATOM 861 CB . ILE A 120 ? -22.25900 13.34000 0.36300 1.000 90.53000 C ? A ? 120 0 + ATOM 862 CG1 . ILE A 120 ? -21.21300 12.29200 0.80700 1.000 90.53000 C ? A ? 120 0 + ATOM 863 CG2 . ILE A 120 ? -23.00400 13.93500 1.56500 1.000 90.53000 C ? A ? 120 0 + ATOM 864 CD1 . ILE A 120 ? -20.11600 12.86000 1.71400 1.000 90.53000 C ? A ? 120 0 + ATOM 865 N . THR A 121 ? -22.20400 13.08400 -2.74600 1.000 92.93000 N ? A ? 121 0 + ATOM 866 CA . THR A 121 ? -21.29800 12.72600 -3.83500 1.000 92.93000 C ? A ? 121 0 + ATOM 867 C . THR A 121 ? -20.03600 13.54900 -3.70700 1.000 92.93000 C ? A ? 121 0 + ATOM 868 O . THR A 121 ? -20.07000 14.68900 -3.24100 1.000 92.93000 O ? A ? 121 0 + ATOM 869 CB . THR A 121 ? -21.92700 12.89700 -5.22200 1.000 92.93000 C ? A ? 121 0 + ATOM 870 OG1 . THR A 121 ? -22.18700 14.24300 -5.50800 1.000 92.93000 O ? A ? 121 0 + ATOM 871 CG2 . THR A 121 ? -23.23900 12.13300 -5.38300 1.000 92.93000 C ? A ? 121 0 + ATOM 872 N . ALA A 122 ? -18.91100 12.97600 -4.10100 1.000 93.07000 N ? A ? 122 0 + ATOM 873 CA . ALA A 122 ? -17.66300 13.70100 -4.11400 1.000 93.07000 C ? A ? 122 0 + ATOM 874 C . ALA A 122 ? -16.83400 13.27000 -5.32200 1.000 93.07000 C ? A ? 122 0 + ATOM 875 O . ALA A 122 ? -16.83900 12.10000 -5.71000 1.000 93.07000 O ? A ? 122 0 + ATOM 876 CB . ALA A 122 ? -16.99900 13.52700 -2.74500 1.000 93.07000 C ? A ? 122 0 + ATOM 877 N . HIS A 123 ? -16.14200 14.23000 -5.92400 1.000 91.61000 N ? A ? 123 0 + ATOM 878 CA . HIS A 123 ? -15.30400 14.00200 -7.09300 1.000 91.61000 C ? A ? 123 0 + ATOM 879 C . HIS A 123 ? -14.01700 14.82100 -7.01000 1.000 91.61000 C ? A ? 123 0 + ATOM 880 O . HIS A 123 ? -13.96100 15.87600 -6.37200 1.000 91.61000 O ? A ? 123 0 + ATOM 881 CB . HIS A 123 ? -16.10100 14.28300 -8.37900 1.000 91.61000 C ? A ? 123 0 + ATOM 882 CG . HIS A 123 ? -16.56400 15.71000 -8.56900 1.000 91.61000 C ? A ? 123 0 + ATOM 883 ND1 . HIS A 123 ? -15.88400 16.85300 -8.22500 1.000 91.61000 N ? A ? 123 0 + ATOM 884 CD2 . HIS A 123 ? -17.70100 16.11500 -9.21500 1.000 91.61000 C ? A ? 123 0 + ATOM 885 CE1 . HIS A 123 ? -16.58000 17.91200 -8.66500 1.000 91.61000 C ? A ? 123 0 + ATOM 886 NE2 . HIS A 123 ? -17.71400 17.51200 -9.25400 1.000 91.61000 N ? A ? 123 0 + ATOM 887 N . THR A 124 ? -12.98400 14.35200 -7.69400 1.000 89.02000 N ? A ? 124 0 + ATOM 888 CA . THR A 124 ? -11.71000 15.05300 -7.82200 1.000 89.02000 C ? A ? 124 0 + ATOM 889 C . THR A 124 ? -11.15500 14.81000 -9.21600 1.000 89.02000 C ? A ? 124 0 + ATOM 890 O . THR A 124 ? -11.27300 13.70400 -9.74800 1.000 89.02000 O ? A ? 124 0 + ATOM 891 CB . THR A 124 ? -10.74000 14.61100 -6.71500 1.000 89.02000 C ? A ? 124 0 + ATOM 892 OG1 . THR A 124 ? -9.57500 15.39300 -6.73800 1.000 89.02000 O ? A ? 124 0 + ATOM 893 CG2 . THR A 124 ? -10.31000 13.14300 -6.78200 1.000 89.02000 C ? A ? 124 0 + ATOM 894 N . ASP A 125 ? -10.57000 15.84000 -9.81800 1.000 86.56000 N ? A ? 125 0 + ATOM 895 CA . ASP A 125 ? -9.78800 15.65700 -11.03400 1.000 86.56000 C ? A ? 125 0 + ATOM 896 C . ASP A 125 ? -8.45100 15.00800 -10.66900 1.000 86.56000 C ? A ? 125 0 + ATOM 897 O . ASP A 125 ? -7.85800 15.31900 -9.63800 1.000 86.56000 O ? A ? 125 0 + ATOM 898 CB . ASP A 125 ? -9.56400 16.98500 -11.76300 1.000 86.56000 C ? A ? 125 0 + ATOM 899 CG . ASP A 125 ? -10.86500 17.64200 -12.21600 1.000 86.56000 C ? A ? 125 0 + ATOM 900 OD1 . ASP A 125 ? -11.70900 16.91300 -12.78000 1.000 86.56000 O ? A ? 125 0 + ATOM 901 OD2 . ASP A 125 ? -10.97300 18.87100 -12.01300 1.000 86.56000 O ? A ? 125 0 + ATOM 902 N . CYS A 126 ? -7.92700 14.13900 -11.53100 1.000 84.95000 N ? A ? 126 0 + ATOM 903 CA . CYS A 126 ? -6.76800 13.29700 -11.21000 1.000 84.95000 C ? A ? 126 0 + ATOM 904 C . CYS A 126 ? -5.49500 14.06300 -10.79500 1.000 84.95000 C ? A ? 126 0 + ATOM 905 O . CYS A 126 ? -4.61700 13.49200 -10.15200 1.000 84.95000 O ? A ? 126 0 + ATOM 906 CB . CYS A 126 ? -6.47100 12.42300 -12.43000 1.000 84.95000 C ? A ? 126 0 + ATOM 907 SG . CYS A 126 ? -7.89300 11.48200 -13.04700 1.000 84.95000 S ? A ? 126 0 + ATOM 908 N . TYR A 127 ? -5.38500 15.34200 -11.15900 1.000 80.35000 N ? A ? 127 0 + ATOM 909 CA . TYR A 127 ? -4.24900 16.21300 -10.83200 1.000 80.35000 C ? A ? 127 0 + ATOM 910 C . TYR A 127 ? -4.62500 17.36900 -9.90300 1.000 80.35000 C ? A ? 127 0 + ATOM 911 O . TYR A 127 ? -3.80800 18.25600 -9.65900 1.000 80.35000 O ? A ? 127 0 + ATOM 912 CB . TYR A 127 ? -3.62500 16.73200 -12.13100 1.000 80.35000 C ? A ? 127 0 + ATOM 913 CG . TYR A 127 ? -3.32600 15.63700 -13.13100 1.000 80.35000 C ? A ? 127 0 + ATOM 914 CD1 . TYR A 127 ? -2.35200 14.66800 -12.83000 1.000 80.35000 C ? A ? 127 0 + ATOM 915 CD2 . TYR A 127 ? -4.06600 15.55200 -14.32700 1.000 80.35000 C ? A ? 127 0 + ATOM 916 CE1 . TYR A 127 ? -2.12700 13.60700 -13.72500 1.000 80.35000 C ? A ? 127 0 + ATOM 917 CE2 . TYR A 127 ? -3.82200 14.50200 -15.23200 1.000 80.35000 C ? A ? 127 0 + ATOM 918 CZ . TYR A 127 ? -2.85700 13.52400 -14.92600 1.000 80.35000 C ? A ? 127 0 + ATOM 919 OH . TYR A 127 ? -2.66100 12.47300 -15.76000 1.000 80.35000 O ? A ? 127 0 + ATOM 920 N . SER A 128 ? -5.86300 17.38700 -9.41400 1.000 85.29000 N ? A ? 128 0 + ATOM 921 CA . SER A 128 ? -6.34000 18.42200 -8.51400 1.000 85.29000 C ? A ? 128 0 + ATOM 922 C . SER A 128 ? -5.98300 18.07900 -7.07400 1.000 85.29000 C ? A ? 128 0 + ATOM 923 O . SER A 128 ? -6.10800 16.94400 -6.62300 1.000 85.29000 O ? A ? 128 0 + ATOM 924 CB . SER A 128 ? -7.84100 18.61500 -8.69500 1.000 85.29000 C ? A ? 128 0 + ATOM 925 OG . SER A 128 ? -8.28600 19.68200 -7.89100 1.000 85.29000 O ? A ? 128 0 + ATOM 926 N . SER A 129 ? -5.57100 19.09500 -6.32400 1.000 88.70000 N ? A ? 129 0 + ATOM 927 CA . SER A 129 ? -5.46100 19.04100 -4.86400 1.000 88.70000 C ? A ? 129 0 + ATOM 928 C . SER A 129 ? -6.79700 19.34800 -4.17300 1.000 88.70000 C ? A ? 129 0 + ATOM 929 O . SER A 129 ? -6.81900 19.61200 -2.96700 1.000 88.70000 O ? A ? 129 0 + ATOM 930 CB . SER A 129 ? -4.36400 20.00100 -4.40700 1.000 88.70000 C ? A ? 129 0 + ATOM 931 OG . SER A 129 ? -4.63000 21.29400 -4.92000 1.000 88.70000 O ? A ? 129 0 + ATOM 932 N . HIS A 130 ? -7.90000 19.34100 -4.92900 1.000 92.13000 N ? A ? 130 0 + ATOM 933 CA . HIS A 130 ? -9.24100 19.65900 -4.46300 1.000 92.13000 C ? A ? 130 0 + ATOM 934 C . HIS A 130 ? -10.17900 18.46200 -4.62700 1.000 92.13000 C ? A ? 130 0 + ATOM 935 O . HIS A 130 ? -10.19900 17.80900 -5.67400 1.000 92.13000 O ? A ? 130 0 + ATOM 936 CB . HIS A 130 ? -9.79500 20.89700 -5.18400 1.000 92.13000 C ? A ? 130 0 + ATOM 937 CG . HIS A 130 ? -8.91300 22.11400 -5.07500 1.000 92.13000 C ? A ? 130 0 + ATOM 938 ND1 . HIS A 130 ? -9.13600 23.18700 -4.24800 1.000 92.13000 N ? A ? 130 0 + ATOM 939 CD2 . HIS A 130 ? -7.76000 22.37400 -5.76900 1.000 92.13000 C ? A ? 130 0 + ATOM 940 CE1 . HIS A 130 ? -8.14000 24.06900 -4.43100 1.000 92.13000 C ? A ? 130 0 + ATOM 941 NE2 . HIS A 130 ? -7.26800 23.61400 -5.34200 1.000 92.13000 N ? A ? 130 0 + ATOM 942 N . ILE A 131 ? -10.98800 18.20800 -3.60200 1.000 94.16000 N ? A ? 131 0 + ATOM 943 CA . ILE A 131 ? -12.11900 17.28000 -3.66800 1.000 94.16000 C ? A ? 131 0 + ATOM 944 C . ILE A 131 ? -13.38800 18.10300 -3.47600 1.000 94.16000 C ? A ? 131 0 + ATOM 945 O . ILE A 131 ? -13.61600 18.64800 -2.39600 1.000 94.16000 O ? A ? 131 0 + ATOM 946 CB . ILE A 131 ? -12.00100 16.15400 -2.61800 1.000 94.16000 C ? A ? 131 0 + ATOM 947 CG1 . ILE A 131 ? -10.70900 15.32300 -2.78600 1.000 94.16000 C ? A ? 131 0 + ATOM 948 CG2 . ILE A 131 ? -13.23800 15.24300 -2.70500 1.000 94.16000 C ? A ? 131 0 + ATOM 949 CD1 . ILE A 131 ? -10.36300 14.48000 -1.55100 1.000 94.16000 C ? A ? 131 0 + ATOM 950 N . THR A 132 ? -14.21700 18.18000 -4.51000 1.000 94.98000 N ? A ? 132 0 + ATOM 951 CA . THR A 132 ? -15.51900 18.84200 -4.41500 1.000 94.98000 C ? A ? 132 0 + ATOM 952 C . THR A 132 ? -16.52600 17.84400 -3.88100 1.000 94.98000 C ? A ? 132 0 + ATOM 953 O . THR A 132 ? -16.78100 16.80400 -4.49100 1.000 94.98000 O ? A ? 132 0 + ATOM 954 CB . THR A 132 ? -15.99400 19.36400 -5.76200 1.000 94.98000 C ? A ? 132 0 + ATOM 955 OG1 . THR A 132 ? -15.02200 20.18700 -6.35200 1.000 94.98000 O ? A ? 132 0 + ATOM 956 CG2 . THR A 132 ? -17.31000 20.13900 -5.70100 1.000 94.98000 C ? A ? 132 0 + ATOM 957 N . VAL A 133 ? -17.10300 18.17400 -2.73500 1.000 94.54000 N ? A ? 133 0 + ATOM 958 CA . VAL A 133 ? -18.16100 17.41300 -2.08000 1.000 94.54000 C ? A ? 133 0 + ATOM 959 C . VAL A 133 ? -19.47800 18.13000 -2.33300 1.000 94.54000 C ? A ? 133 0 + ATOM 960 O . VAL A 133 ? -19.55000 19.35200 -2.20500 1.000 94.54000 O ? A ? 133 0 + ATOM 961 CB . VAL A 133 ? -17.87900 17.26900 -0.57400 1.000 94.54000 C ? A ? 133 0 + ATOM 962 CG1 . VAL A 133 ? -18.87500 16.30400 0.07700 1.000 94.54000 C ? A ? 133 0 + ATOM 963 CG2 . VAL A 133 ? -16.46200 16.74100 -0.31100 1.000 94.54000 C ? A ? 133 0 + ATOM 964 N . SER A 134 ? -20.52600 17.39000 -2.68000 1.000 93.66000 N ? A ? 134 0 + ATOM 965 CA . SER A 134 ? -21.86700 17.93000 -2.88800 1.000 93.66000 C ? A ? 134 0 + ATOM 966 C . SER A 134 ? -22.94700 17.05700 -2.25500 1.000 93.66000 C ? A ? 134 0 + ATOM 967 O . SER A 134 ? -22.81100 15.83600 -2.13800 1.000 93.66000 O ? A ? 134 0 + ATOM 968 CB . SER A 134 ? -22.13400 18.18400 -4.37200 1.000 93.66000 C ? A ? 134 0 + ATOM 969 OG . SER A 134 ? -22.28300 16.97900 -5.08400 1.000 93.66000 O ? A ? 134 0 + ATOM 970 N . TRP A 135 ? -24.02300 17.69900 -1.81100 1.000 89.24000 N ? A ? 135 0 + ATOM 971 CA . TRP A 135 ? -25.12700 17.07000 -1.08900 1.000 89.24000 C ? A ? 135 0 + ATOM 972 C . TRP A 135 ? -26.46200 17.72400 -1.44400 1.000 89.24000 C ? A ? 135 0 + ATOM 973 O . TRP A 135 ? -26.51200 18.82100 -1.99700 1.000 89.24000 O ? A ? 135 0 + ATOM 974 CB . TRP A 135 ? -24.85500 17.14800 0.41800 1.000 89.24000 C ? A ? 135 0 + ATOM 975 CG . TRP A 135 ? -24.64000 18.51900 0.97700 1.000 89.24000 C ? A ? 135 0 + ATOM 976 CD1 . TRP A 135 ? -25.58300 19.32900 1.51200 1.000 89.24000 C ? A ? 135 0 + ATOM 977 CD2 . TRP A 135 ? -23.37700 19.23800 1.09200 1.000 89.24000 C ? A ? 135 0 + ATOM 978 NE1 . TRP A 135 ? -24.99000 20.49800 1.95200 1.000 89.24000 N ? A ? 135 0 + ATOM 979 CE2 . TRP A 135 ? -23.63200 20.48800 1.72400 1.000 89.24000 C ? A ? 135 0 + ATOM 980 CE3 . TRP A 135 ? -22.04000 18.94900 0.74400 1.000 89.24000 C ? A ? 135 0 + ATOM 981 CZ2 . TRP A 135 ? -22.61000 21.39500 2.01400 1.000 89.24000 C ? A ? 135 0 + ATOM 982 CZ3 . TRP A 135 ? -20.99900 19.84100 1.06000 1.000 89.24000 C ? A ? 135 0 + ATOM 983 CH2 . TRP A 135 ? -21.28600 21.05300 1.71200 1.000 89.24000 C ? A ? 135 0 + ATOM 984 N . GLN A 136 ? -27.56700 17.05200 -1.12500 1.000 83.48000 N ? A ? 136 0 + ATOM 985 CA . GLN A 136 ? -28.90100 17.62500 -1.30000 1.000 83.48000 C ? A ? 136 0 + ATOM 986 C . GLN A 136 ? -29.24500 18.55700 -0.13200 1.000 83.48000 C ? A ? 136 0 + ATOM 987 O . GLN A 136 ? -28.94300 18.26700 1.02700 1.000 83.48000 O ? A ? 136 0 + ATOM 988 CB . GLN A 136 ? -29.94600 16.52100 -1.49900 1.000 83.48000 C ? A ? 136 0 + ATOM 989 CG . GLN A 136 ? -29.71500 15.77800 -2.82500 1.000 83.48000 C ? A ? 136 0 + ATOM 990 CD . GLN A 136 ? -30.81500 14.76800 -3.13600 1.000 83.48000 C ? A ? 136 0 + ATOM 991 OE1 . GLN A 136 ? -31.32600 14.06200 -2.28600 1.000 83.48000 O ? A ? 136 0 + ATOM 992 NE2 . GLN A 136 ? -31.22000 14.64000 -4.38000 1.000 83.48000 N ? A ? 136 0 + ATOM 993 N . LEU A 137 ? -29.86700 19.69800 -0.44200 1.000 73.64000 N ? A ? 137 0 + ATOM 994 CA . LEU A 137 ? -30.30100 20.65200 0.57300 1.000 73.64000 C ? A ? 137 0 + ATOM 995 C . LEU A 137 ? -31.55700 20.12600 1.27000 1.000 73.64000 C ? A ? 137 0 + ATOM 996 O . LEU A 137 ? -32.62100 20.08500 0.65500 1.000 73.64000 O ? A ? 137 0 + ATOM 997 CB . LEU A 137 ? -30.56800 22.02600 -0.07000 1.000 73.64000 C ? A ? 137 0 + ATOM 998 CG . LEU A 137 ? -30.64800 23.17300 0.95300 1.000 73.64000 C ? A ? 137 0 + ATOM 999 CD1 . LEU A 137 ? -29.28300 23.49600 1.56700 1.000 73.64000 C ? A ? 137 0 + ATOM 1000 CD2 . LEU A 137 ? -31.15500 24.43200 0.25000 1.000 73.64000 C ? A ? 137 0 + ATOM 1001 N . ASN A 138 ? -31.43900 19.78800 2.55200 1.000 65.93000 N ? A ? 138 0 + ATOM 1002 CA . ASN A 138 ? -32.59600 19.39100 3.35700 1.000 65.93000 C ? A ? 138 0 + ATOM 1003 C . ASN A 138 ? -33.19800 20.57200 4.12800 1.000 65.93000 C ? A ? 138 0 + ATOM 1004 O . ASN A 138 ? -34.40200 20.58200 4.35000 1.000 65.93000 O ? A ? 138 0 + ATOM 1005 CB . ASN A 138 ? -32.21400 18.20100 4.25200 1.000 65.93000 C ? A ? 138 0 + ATOM 1006 CG . ASN A 138 ? -31.98900 16.92100 3.45800 1.000 65.93000 C ? A ? 138 0 + ATOM 1007 OD1 . ASN A 138 ? -32.26000 16.81400 2.27500 1.000 65.93000 O ? A ? 138 0 + ATOM 1008 ND2 . ASN A 138 ? -31.50100 15.88100 4.09000 1.000 65.93000 N ? A ? 138 0 + ATOM 1009 N . ASP A 139 ? -32.39800 21.58800 4.47500 1.000 63.93000 N ? A ? 139 0 + ATOM 1010 CA . ASP A 139 ? -32.88400 22.77000 5.18900 1.000 63.93000 C ? A ? 139 0 + ATOM 1011 C . ASP A 139 ? -32.09600 24.03900 4.83600 1.000 63.93000 C ? A ? 139 0 + ATOM 1012 O . ASP A 139 ? -30.88400 24.01500 4.63000 1.000 63.93000 O ? A ? 139 0 + ATOM 1013 CB . ASP A 139 ? -32.87900 22.51500 6.71000 1.000 63.93000 C ? A ? 139 0 + ATOM 1014 CG . ASP A 139 ? -34.29300 22.45100 7.29500 1.000 63.93000 C ? A ? 139 0 + ATOM 1015 OD1 . ASP A 139 ? -35.15500 23.20900 6.78900 1.000 63.93000 O ? A ? 139 0 + ATOM 1016 OD2 . ASP A 139 ? -34.46900 21.71700 8.29100 1.000 63.93000 O ? A ? 139 0 + ATOM 1017 N . ARG A 140 ? -32.79400 25.17700 4.75100 1.000 56.49000 N ? A ? 140 0 + ATOM 1018 CA . ARG A 140 ? -32.27000 26.43100 4.16800 1.000 56.49000 C ? A ? 140 0 + ATOM 1019 C . ARG A 140 ? -31.43300 27.31500 5.10900 1.000 56.49000 C ? A ? 140 0 + ATOM 1020 O . ARG A 140 ? -31.23800 28.48400 4.79200 1.000 56.49000 O ? A ? 140 0 + ATOM 1021 CB . ARG A 140 ? -33.41000 27.20200 3.46200 1.000 56.49000 C ? A ? 140 0 + ATOM 1022 CG . ARG A 140 ? -33.62300 26.71200 2.02500 1.000 56.49000 C ? A ? 140 0 + ATOM 1023 CD . ARG A 140 ? -34.62100 27.61200 1.29000 1.000 56.49000 C ? A ? 140 0 + ATOM 1024 NE . ARG A 140 ? -34.78600 27.19700 -0.11600 1.000 56.49000 N ? A ? 140 0 + ATOM 1025 CZ . ARG A 140 ? -35.59800 27.74500 -1.00200 1.000 56.49000 C ? A ? 140 0 + ATOM 1026 NH1 . ARG A 140 ? -36.34700 28.77200 -0.70700 1.000 56.49000 N ? A ? 140 0 + ATOM 1027 NH2 . ARG A 140 ? -35.67400 27.26400 -2.21100 1.000 56.49000 N ? A ? 140 0 + ATOM 1028 N . SER A 141 ? -30.93200 26.82300 6.24600 1.000 57.16000 N ? A ? 141 0 + ATOM 1029 CA . SER A 141 ? -30.25200 27.70800 7.21700 1.000 57.16000 C ? A ? 141 0 + ATOM 1030 C . SER A 141 ? -29.14200 27.07500 8.07000 1.000 57.16000 C ? A ? 141 0 + ATOM 1031 O . SER A 141 ? -28.79500 27.62700 9.11700 1.000 57.16000 O ? A ? 141 0 + ATOM 1032 CB . SER A 141 ? -31.30500 28.39900 8.09500 1.000 57.16000 C ? A ? 141 0 + ATOM 1033 OG . SER A 141 ? -30.72800 29.49400 8.77500 1.000 57.16000 O ? A ? 141 0 + ATOM 1034 N . SER A 142 ? -28.55600 25.95400 7.65000 1.000 70.83000 N ? A ? 142 0 + ATOM 1035 CA . SER A 142 ? -27.48000 25.30100 8.41000 1.000 70.83000 C ? A ? 142 0 + ATOM 1036 C . SER A 142 ? -26.10800 25.53400 7.77500 1.000 70.83000 C ? A ? 142 0 + ATOM 1037 O . SER A 142 ? -25.95700 25.49300 6.55600 1.000 70.83000 O ? A ? 142 0 + ATOM 1038 CB . SER A 142 ? -27.78200 23.81400 8.59300 1.000 70.83000 C ? A ? 142 0 + ATOM 1039 OG . SER A 142 ? -28.99600 23.67100 9.31300 1.000 70.83000 O ? A ? 142 0 + ATOM 1040 N . LEU A 143 ? -25.09800 25.78000 8.61400 1.000 85.06000 N ? A ? 143 0 + ATOM 1041 CA . LEU A 143 ? -23.69800 25.70300 8.20600 1.000 85.06000 C ? A ? 143 0 + ATOM 1042 C . LEU A 143 ? -23.31800 24.22500 8.13000 1.000 85.06000 C ? A ? 143 0 + ATOM 1043 O . LEU A 143 ? -23.33900 23.53300 9.14500 1.000 85.06000 O ? A ? 143 0 + ATOM 1044 CB . LEU A 143 ? -22.82100 26.45900 9.22300 1.000 85.06000 C ? A ? 143 0 + ATOM 1045 CG . LEU A 143 ? -21.31800 26.44700 8.88000 1.000 85.06000 C ? A ? 143 0 + ATOM 1046 CD1 . LEU A 143 ? -21.02800 27.30700 7.64600 1.000 85.06000 C ? A ? 143 0 + ATOM 1047 CD2 . LEU A 143 ? -20.51200 26.99900 10.05700 1.000 85.06000 C ? A ? 143 0 + ATOM 1048 N . TYR A 144 ? -22.96000 23.75300 6.94300 1.000 87.21000 N ? A ? 144 0 + ATOM 1049 CA . TYR A 144 ? -22.46300 22.40000 6.75000 1.000 87.21000 C ? A ? 144 0 + ATOM 1050 C . TYR A 144 ? -20.94000 22.37600 6.83200 1.000 87.21000 C ? A ? 144 0 + ATOM 1051 O . TYR A 144 ? -20.25900 23.28300 6.34800 1.000 87.21000 O ? A ? 144 0 + ATOM 1052 CB . TYR A 144 ? -22.96700 21.83900 5.42300 1.000 87.21000 C ? A ? 144 0 + ATOM 1053 CG . TYR A 144 ? -24.47300 21.68300 5.36000 1.000 87.21000 C ? A ? 144 0 + ATOM 1054 CD1 . TYR A 144 ? -25.08400 20.58000 5.98600 1.000 87.21000 C ? A ? 144 0 + ATOM 1055 CD2 . TYR A 144 ? -25.26100 22.64500 4.69900 1.000 87.21000 C ? A ? 144 0 + ATOM 1056 CE1 . TYR A 144 ? -26.48400 20.43600 5.95400 1.000 87.21000 C ? A ? 144 0 + ATOM 1057 CE2 . TYR A 144 ? -26.66200 22.50200 4.66100 1.000 87.21000 C ? A ? 144 0 + ATOM 1058 CZ . TYR A 144 ? -27.27600 21.39800 5.28800 1.000 87.21000 C ? A ? 144 0 + ATOM 1059 OH . TYR A 144 ? -28.62800 21.26000 5.25300 1.000 87.21000 O ? A ? 144 0 + ATOM 1060 N . VAL A 145 ? -20.41600 21.31300 7.42700 1.000 90.33000 N ? A ? 145 0 + ATOM 1061 CA . VAL A 145 ? -18.99200 21.00600 7.51100 1.000 90.33000 C ? A ? 145 0 + ATOM 1062 C . VAL A 145 ? -18.76600 19.70600 6.75600 1.000 90.33000 C ? A ? 145 0 + ATOM 1063 O . VAL A 145 ? -19.29900 18.66600 7.13500 1.000 90.33000 O ? A ? 145 0 + ATOM 1064 CB . VAL A 145 ? -18.53800 20.90600 8.98000 1.000 90.33000 C ? A ? 145 0 + ATOM 1065 CG1 . VAL A 145 ? -17.03600 20.60600 9.07500 1.000 90.33000 C ? A ? 145 0 + ATOM 1066 CG2 . VAL A 145 ? -18.84100 22.20900 9.73700 1.000 90.33000 C ? A ? 145 0 + ATOM 1067 N . ALA A 146 ? -17.99500 19.76100 5.67400 1.000 92.07000 N ? A ? 146 0 + ATOM 1068 CA . ALA A 146 ? -17.48900 18.56900 5.01200 1.000 92.07000 C ? A ? 146 0 + ATOM 1069 C . ALA A 146 ? -16.12700 18.22500 5.61700 1.000 92.07000 C ? A ? 146 0 + ATOM 1070 O . ALA A 146 ? -15.27200 19.10200 5.76700 1.000 92.07000 O ? A ? 146 0 + ATOM 1071 CB . ALA A 146 ? -17.42200 18.79600 3.49900 1.000 92.07000 C ? A ? 146 0 + ATOM 1072 N . SER A 147 ? -15.91100 16.95600 5.95200 1.000 92.17000 N ? A ? 147 0 + ATOM 1073 CA . SER A 147 ? -14.62000 16.46700 6.42600 1.000 92.17000 C ? A ? 147 0 + ATOM 1074 C . SER A 147 ? -14.22100 15.19100 5.70800 1.000 92.17000 C ? A ? 147 0 + ATOM 1075 O . SER A 147 ? -15.05000 14.29400 5.56600 1.000 92.17000 O ? A ? 147 0 + ATOM 1076 CB . SER A 147 ? -14.60400 16.26700 7.94300 1.000 92.17000 C ? A ? 147 0 + ATOM 1077 OG . SER A 147 ? -15.50700 15.27300 8.37600 1.000 92.17000 O ? A ? 147 0 + ATOM 1078 N . ALA A 148 ? -12.95500 15.10500 5.31100 1.000 93.27000 N ? A ? 148 0 + ATOM 1079 CA . ALA A 148 ? -12.35400 13.89900 4.76000 1.000 93.27000 C ? A ? 148 0 + ATOM 1080 C . ALA A 148 ? -11.22200 13.41600 5.66000 1.000 93.27000 C ? A ? 148 0 + ATOM 1081 O . ALA A 148 ? -10.31900 14.19400 5.96800 1.000 93.27000 O ? A ? 148 0 + ATOM 1082 CB . ALA A 148 ? -11.85700 14.16700 3.34300 1.000 93.27000 C ? A ? 148 0 + ATOM 1083 N . GLU A 149 ? -11.26800 12.14800 6.05100 1.000 92.92000 N ? A ? 149 0 + ATOM 1084 CA . GLU A 149 ? -10.18800 11.46800 6.76200 1.000 92.92000 C ? A ? 149 0 + ATOM 1085 C . GLU A 149 ? -9.45700 10.52800 5.80600 1.000 92.92000 C ? A ? 149 0 + ATOM 1086 O . GLU A 149 ? -10.07800 9.69400 5.14800 1.000 92.92000 O ? A ? 149 0 + ATOM 1087 CB . GLU A 149 ? -10.74100 10.74100 7.99100 1.000 92.92000 C ? A ? 149 0 + ATOM 1088 CG . GLU A 149 ? -9.59900 10.10300 8.79900 1.000 92.92000 C ? A ? 149 0 + ATOM 1089 CD . GLU A 149 ? -10.04600 9.51800 10.14300 1.000 92.92000 C ? A ? 149 0 + ATOM 1090 OE1 . GLU A 149 ? -9.19900 8.82700 10.76000 1.000 92.92000 O ? A ? 149 0 + ATOM 1091 OE2 . GLU A 149 ? -11.18200 9.83700 10.56600 1.000 92.92000 O ? A ? 149 0 + ATOM 1092 N . GLY A 150 ? -8.14600 10.71400 5.67600 1.000 92.11000 N ? A ? 150 0 + ATOM 1093 CA . GLY A 150 ? -7.28300 9.86700 4.86900 1.000 92.11000 C ? A ? 150 0 + ATOM 1094 C . GLY A 150 ? -6.85700 8.60900 5.62000 1.000 92.11000 C ? A ? 150 0 + ATOM 1095 O . GLY A 150 ? -6.79600 8.58200 6.84500 1.000 92.11000 O ? A ? 150 0 + ATOM 1096 N . ASN A 151 ? -6.45300 7.58200 4.88000 1.000 89.70000 N ? A ? 151 0 + ATOM 1097 CA . ASN A 151 ? -5.82800 6.37400 5.42700 1.000 89.70000 C ? A ? 151 0 + ATOM 1098 C . ASN A 151 ? -4.51800 6.62100 6.20900 1.000 89.70000 C ? A ? 151 0 + ATOM 1099 O . ASN A 151 ? -4.06900 5.73300 6.92700 1.000 89.70000 O ? A ? 151 0 + ATOM 1100 CB . ASN A 151 ? -5.60300 5.37100 4.28000 1.000 89.70000 C ? A ? 151 0 + ATOM 1101 CG . ASN A 151 ? -4.67700 5.87100 3.17700 1.000 89.70000 C ? A ? 151 0 + ATOM 1102 OD1 . ASN A 151 ? -4.67900 7.01800 2.77200 1.000 89.70000 O ? A ? 151 0 + ATOM 1103 ND2 . ASN A 151 ? -3.89600 5.00900 2.57400 1.000 89.70000 N ? A ? 151 0 + ATOM 1104 N . ASP A 152 ? -3.90000 7.79700 6.07300 1.000 89.34000 N ? A ? 152 0 + ATOM 1105 CA . ASP A 152 ? -2.75600 8.25800 6.87300 1.000 89.34000 C ? A ? 152 0 + ATOM 1106 C . ASP A 152 ? -3.17000 9.05700 8.12700 1.000 89.34000 C ? A ? 152 0 + ATOM 1107 O . ASP A 152 ? -2.31200 9.62800 8.80100 1.000 89.34000 O ? A ? 152 0 + ATOM 1108 CB . ASP A 152 ? -1.80100 9.08000 5.98300 1.000 89.34000 C ? A ? 152 0 + ATOM 1109 CG . ASP A 152 ? -2.34000 10.47200 5.62000 1.000 89.34000 C ? A ? 152 0 + ATOM 1110 OD1 . ASP A 152 ? -3.57400 10.68200 5.71900 1.000 89.34000 O ? A ? 152 0 + ATOM 1111 OD2 . ASP A 152 ? -1.53900 11.33700 5.19500 1.000 89.34000 O ? A ? 152 0 + ATOM 1112 N . HIS A 153 ? -4.47300 9.12000 8.42300 1.000 87.28000 N ? A ? 153 0 + ATOM 1113 CA . HIS A 153 ? -5.09900 9.94600 9.46100 1.000 87.28000 C ? A ? 153 0 + ATOM 1114 C . HIS A 153 ? -5.01200 11.46300 9.22800 1.000 87.28000 C ? A ? 153 0 + ATOM 1115 O . HIS A 153 ? -5.27700 12.25400 10.13800 1.000 87.28000 O ? A ? 153 0 + ATOM 1116 CB . HIS A 153 ? -4.61600 9.52700 10.85700 1.000 87.28000 C ? A ? 153 0 + ATOM 1117 CG . HIS A 153 ? -4.70300 8.04500 11.09000 1.000 87.28000 C ? A ? 153 0 + ATOM 1118 ND1 . HIS A 153 ? -5.86700 7.32600 11.21600 1.000 87.28000 N ? A ? 153 0 + ATOM 1119 CD2 . HIS A 153 ? -3.66000 7.16300 11.17600 1.000 87.28000 C ? A ? 153 0 + ATOM 1120 CE1 . HIS A 153 ? -5.52800 6.03900 11.39300 1.000 87.28000 C ? A ? 153 0 + ATOM 1121 NE2 . HIS A 153 ? -4.19100 5.88600 11.39300 1.000 87.28000 N ? A ? 153 0 + ATOM 1122 N . SER A 154 ? -4.66000 11.90800 8.01800 1.000 91.44000 N ? A ? 154 0 + ATOM 1123 CA . SER A 154 ? -4.79300 13.31500 7.64100 1.000 91.44000 C ? A ? 154 0 + ATOM 1124 C . SER A 154 ? -6.26400 13.70200 7.53700 1.000 91.44000 C ? A ? 154 0 + ATOM 1125 O . SER A 154 ? -7.10400 12.92900 7.08300 1.000 91.44000 O ? A ? 154 0 + ATOM 1126 CB . SER A 154 ? -4.03600 13.66100 6.35400 1.000 91.44000 C ? A ? 154 0 + ATOM 1127 OG . SER A 154 ? -4.55900 13.01000 5.21700 1.000 91.44000 O ? A ? 154 0 + ATOM 1128 N . ILE A 155 ? -6.58200 14.92400 7.95800 1.000 91.47000 N ? A ? 155 0 + ATOM 1129 CA . ILE A 155 ? -7.95200 15.43100 7.96100 1.000 91.47000 C ? A ? 155 0 + ATOM 1130 C . ILE A 155 ? -8.01400 16.69400 7.11200 1.000 91.47000 C ? A ? 155 0 + ATOM 1131 O . ILE A 155 ? -7.30200 17.66300 7.37900 1.000 91.47000 O ? A ? 155 0 + ATOM 1132 CB . ILE A 155 ? -8.45300 15.65300 9.40100 1.000 91.47000 C ? A ? 155 0 + ATOM 1133 CG1 . ILE A 155 ? -8.41700 14.33200 10.20800 1.000 91.47000 C ? A ? 155 0 + ATOM 1134 CG2 . ILE A 155 ? -9.87800 16.23600 9.40300 1.000 91.47000 C ? A ? 155 0 + ATOM 1135 CD1 . ILE A 155 ? -8.87100 14.46500 11.66600 1.000 91.47000 C ? A ? 155 0 + ATOM 1136 N . LEU A 156 ? -8.91400 16.70100 6.13300 1.000 93.61000 N ? A ? 156 0 + ATOM 1137 CA . LEU A 156 ? -9.31000 17.89000 5.38400 1.000 93.61000 C ? A ? 156 0 + ATOM 1138 C . LEU A 156 ? -10.68900 18.33500 5.85500 1.000 93.61000 C ? A ? 156 0 + ATOM 1139 O . LEU A 156 ? -11.53800 17.50000 6.16900 1.000 93.61000 O ? A ? 156 0 + ATOM 1140 CB . LEU A 156 ? -9.29900 17.61100 3.87400 1.000 93.61000 C ? A ? 156 0 + ATOM 1141 CG . LEU A 156 ? -7.98800 17.00900 3.34300 1.000 93.61000 C ? A ? 156 0 + ATOM 1142 CD1 . LEU A 156 ? -8.12000 16.77900 1.84200 1.000 93.61000 C ? A ? 156 0 + ATOM 1143 CD2 . LEU A 156 ? -6.78000 17.91100 3.60100 1.000 93.61000 C ? A ? 156 0 + ATOM 1144 N . MET A 157 ? -10.92000 19.64300 5.91200 1.000 93.53000 N ? A ? 157 0 + ATOM 1145 CA . MET A 157 ? -12.21400 20.20100 6.29800 1.000 93.53000 C ? A ? 157 0 + ATOM 1146 C . MET A 157 ? -12.53300 21.42600 5.46000 1.000 93.53000 C ? A ? 157 0 + ATOM 1147 O . MET A 157 ? -11.64300 22.21200 5.13400 1.000 93.53000 O ? A ? 157 0 + ATOM 1148 CB . MET A 157 ? -12.25700 20.56900 7.78900 1.000 93.53000 C ? A ? 157 0 + ATOM 1149 CG . MET A 157 ? -12.02000 19.35700 8.69600 1.000 93.53000 C ? A ? 157 0 + ATOM 1150 SD . MET A 157 ? -12.17700 19.65100 10.48000 1.000 93.53000 S ? A ? 157 0 + ATOM 1151 CE . MET A 157 ? -10.88500 20.90400 10.71600 1.000 93.53000 C ? A ? 157 0 + ATOM 1152 N . CYS A 158 ? -13.80700 21.60400 5.14900 1.000 93.41000 N ? A ? 158 0 + ATOM 1153 CA . CYS A 158 ? -14.30300 22.82200 4.54000 1.000 93.41000 C ? A ? 158 0 + ATOM 1154 C . CYS A 158 ? -15.73300 23.08700 5.02300 1.000 93.41000 C ? A ? 158 0 + ATOM 1155 O . CYS A 158 ? -16.47600 22.15800 5.34800 1.000 93.41000 O ? A ? 158 0 + ATOM 1156 CB . CYS A 158 ? -14.14300 22.71600 3.01700 1.000 93.41000 C ? A ? 158 0 + ATOM 1157 SG . CYS A 158 ? -15.35200 21.67900 2.18300 1.000 93.41000 S ? A ? 158 0 + ATOM 1158 N . ASN A 159 ? -16.11300 24.36200 5.08300 1.000 91.84000 N ? A ? 159 0 + ATOM 1159 CA . ASN A 159 ? -17.42100 24.77900 5.57500 1.000 91.84000 C ? A ? 159 0 + ATOM 1160 C . ASN A 159 ? -18.18200 25.48700 4.45700 1.000 91.84000 C ? A ? 159 0 + ATOM 1161 O . ASN A 159 ? -17.60200 26.29100 3.72800 1.000 91.84000 O ? A ? 159 0 + ATOM 1162 CB . ASN A 159 ? -17.26500 25.68600 6.80500 1.000 91.84000 C ? A ? 159 0 + ATOM 1163 CG . ASN A 159 ? -16.57700 25.04000 7.99300 1.000 91.84000 C ? A ? 159 0 + ATOM 1164 OD1 . ASN A 159 ? -16.26500 23.86700 8.04200 1.000 91.84000 O ? A ? 159 0 + ATOM 1165 ND2 . ASN A 159 ? -16.30000 25.80600 9.02000 1.000 91.84000 N ? A ? 159 0 + ATOM 1166 N . SER A 160 ? -19.48100 25.22700 4.34800 1.000 89.68000 N ? A ? 160 0 + ATOM 1167 CA . SER A 160 ? -20.33100 25.85500 3.33900 1.000 89.68000 C ? A ? 160 0 + ATOM 1168 C . SER A 160 ? -21.76300 25.99500 3.83700 1.000 89.68000 C ? A ? 160 0 + ATOM 1169 O . SER A 160 ? -22.28700 25.13100 4.53400 1.000 89.68000 O ? A ? 160 0 + ATOM 1170 CB . SER A 160 ? -20.28100 25.03200 2.05100 1.000 89.68000 C ? A ? 160 0 + ATOM 1171 OG . SER A 160 ? -20.92500 25.69300 0.98200 1.000 89.68000 O ? A ? 160 0 + ATOM 1172 N . THR A 161 ? -22.41100 27.09800 3.47500 1.000 86.55000 N ? A ? 161 0 + ATOM 1173 CA . THR A 161 ? -23.86900 27.27500 3.60600 1.000 86.55000 C ? A ? 161 0 + ATOM 1174 C . THR A 161 ? -24.61200 26.86300 2.33200 1.000 86.55000 C ? A ? 161 0 + ATOM 1175 O . THR A 161 ? -25.84000 26.87200 2.29800 1.000 86.55000 O ? A ? 161 0 + ATOM 1176 CB . THR A 161 ? -24.20400 28.73200 3.94000 1.000 86.55000 C ? A ? 161 0 + ATOM 1177 OG1 . THR A 161 ? -23.62200 29.59300 2.98300 1.000 86.55000 O ? A ? 161 0 + ATOM 1178 CG2 . THR A 161 ? -23.66000 29.14500 5.30800 1.000 86.55000 C ? A ? 161 0 + ATOM 1179 N . SER A 162 ? -23.86800 26.52600 1.27500 1.000 87.03000 N ? A ? 162 0 + ATOM 1180 CA . SER A 162 ? -24.38700 26.01400 0.00900 1.000 87.03000 C ? A ? 162 0 + ATOM 1181 C . SER A 162 ? -24.50600 24.48200 0.04700 1.000 87.03000 C ? A ? 162 0 + ATOM 1182 O . SER A 162 ? -24.27700 23.84800 1.07400 1.000 87.03000 O ? A ? 162 0 + ATOM 1183 CB . SER A 162 ? -23.46700 26.49200 -1.12300 1.000 87.03000 C ? A ? 162 0 + ATOM 1184 OG . SER A 162 ? -24.08300 26.30300 -2.38200 1.000 87.03000 O ? A ? 162 0 + ATOM 1185 N . THR A 163 ? -24.84900 23.87500 -1.08700 1.000 89.21000 N ? A ? 163 0 + ATOM 1186 CA . THR A 163 ? -24.93800 22.41800 -1.30000 1.000 89.21000 C ? A ? 163 0 + ATOM 1187 C . THR A 163 ? -23.62800 21.77600 -1.75000 1.000 89.21000 C ? A ? 163 0 + ATOM 1188 O . THR A 163 ? -23.61700 20.61700 -2.16400 1.000 89.21000 O ? A ? 163 0 + ATOM 1189 CB . THR A 163 ? -26.02500 22.11000 -2.33500 1.000 89.21000 C ? A ? 163 0 + ATOM 1190 OG1 . THR A 163 ? -25.83700 22.88000 -3.50300 1.000 89.21000 O ? A ? 163 0 + ATOM 1191 CG2 . THR A 163 ? -27.40400 22.43800 -1.78200 1.000 89.21000 C ? A ? 163 0 + ATOM 1192 N . SER A 164 ? -22.53100 22.53100 -1.74900 1.000 92.97000 N ? A ? 164 0 + ATOM 1193 CA . SER A 164 ? -21.21800 22.04700 -2.16100 1.000 92.97000 C ? A ? 164 0 + ATOM 1194 C . SER A 164 ? -20.08900 22.73100 -1.40500 1.000 92.97000 C ? A ? 164 0 + ATOM 1195 O . SER A 164 ? -20.23800 23.85800 -0.91500 1.000 92.97000 O ? A ? 164 0 + ATOM 1196 CB . SER A 164 ? -21.01600 22.20600 -3.67200 1.000 92.97000 C ? A ? 164 0 + ATOM 1197 OG . SER A 164 ? -20.98700 23.57400 -4.04400 1.000 92.97000 O ? A ? 164 0 + ATOM 1198 N . CYS A 165 ? -18.95500 22.04000 -1.31300 1.000 93.31000 N ? A ? 165 0 + ATOM 1199 CA . CYS A 165 ? -17.76300 22.51900 -0.63600 1.000 93.31000 C ? A ? 165 0 + ATOM 1200 C . CYS A 165 ? -16.50400 21.83700 -1.17700 1.000 93.31000 C ? A ? 165 0 + ATOM 1201 O . CYS A 165 ? -16.50900 20.63000 -1.41500 1.000 93.31000 O ? A ? 165 0 + ATOM 1202 CB . CYS A 165 ? -17.96500 22.24800 0.85100 1.000 93.31000 C ? A ? 165 0 + ATOM 1203 SG . CYS A 165 ? -16.80600 23.04800 1.95200 1.000 93.31000 S ? A ? 165 0 + ATOM 1204 N . ASP A 166 ? -15.43200 22.60900 -1.34500 1.000 94.82000 N ? A ? 166 0 + ATOM 1205 CA . ASP A 166 ? -14.15200 22.10800 -1.83900 1.000 94.82000 C ? A ? 166 0 + ATOM 1206 C . ASP A 166 ? -13.19100 21.85700 -0.67700 1.000 94.82000 C ? A ? 166 0 + ATOM 1207 O . ASP A 166 ? -12.76500 22.77700 0.02600 1.000 94.82000 O ? A ? 166 0 + ATOM 1208 CB . ASP A 166 ? -13.54900 23.07500 -2.86600 1.000 94.82000 C ? A ? 166 0 + ATOM 1209 CG . ASP A 166 ? -14.39300 23.18200 -4.13700 1.000 94.82000 C ? A ? 166 0 + ATOM 1210 OD1 . ASP A 166 ? -14.91300 22.13600 -4.58800 1.000 94.82000 O ? A ? 166 0 + ATOM 1211 OD2 . ASP A 166 ? -14.50800 24.31400 -4.65100 1.000 94.82000 O ? A ? 166 0 + ATOM 1212 N . LEU A 167 ? -12.81900 20.59500 -0.48900 1.000 95.09000 N ? A ? 167 0 + ATOM 1213 CA . LEU A 167 ? -11.75300 20.19300 0.41600 1.000 95.09000 C ? A ? 167 0 + ATOM 1214 C . LEU A 167 ? -10.41200 20.45300 -0.26400 1.000 95.09000 C ? A ? 167 0 + ATOM 1215 O . LEU A 167 ? -10.12000 19.87000 -1.30600 1.000 95.09000 O ? A ? 167 0 + ATOM 1216 CB . LEU A 167 ? -11.90700 18.71000 0.75400 1.000 95.09000 C ? A ? 167 0 + ATOM 1217 CG . LEU A 167 ? -13.18200 18.36200 1.53600 1.000 95.09000 C ? A ? 167 0 + ATOM 1218 CD1 . LEU A 167 ? -13.34300 16.84900 1.51300 1.000 95.09000 C ? A ? 167 0 + ATOM 1219 CD2 . LEU A 167 ? -13.08000 18.81300 2.99100 1.000 95.09000 C ? A ? 167 0 + ATOM 1220 N . ILE A 168 ? -9.59900 21.32100 0.33000 1.000 94.20000 N ? A ? 168 0 + ATOM 1221 CA . ILE A 168 ? -8.31900 21.76400 -0.23000 1.000 94.20000 C ? A ? 168 0 + ATOM 1222 C . ILE A 168 ? -7.17400 21.00600 0.44200 1.000 94.20000 C ? A ? 168 0 + ATOM 1223 O . ILE A 168 ? -7.16300 20.85700 1.66100 1.000 94.20000 O ? A ? 168 0 + ATOM 1224 CB . ILE A 168 ? -8.15300 23.29500 -0.07500 1.000 94.20000 C ? A ? 168 0 + ATOM 1225 CG1 . ILE A 168 ? -9.38100 24.05500 -0.63300 1.000 94.20000 C ? A ? 168 0 + ATOM 1226 CG2 . ILE A 168 ? -6.85300 23.76000 -0.76500 1.000 94.20000 C ? A ? 168 0 + ATOM 1227 CD1 . ILE A 168 ? -9.34100 25.57500 -0.43900 1.000 94.20000 C ? A ? 168 0 + ATOM 1228 N . GLY A 169 ? -6.17900 20.58700 -0.34200 1.000 92.75000 N ? A ? 169 0 + ATOM 1229 CA . GLY A 169 ? -4.97900 19.91100 0.16100 1.000 92.75000 C ? A ? 169 0 + ATOM 1230 C . GLY A 169 ? -5.03500 18.38800 0.05500 1.000 92.75000 C ? A ? 169 0 + ATOM 1231 O . GLY A 169 ? -4.29200 17.70300 0.76000 1.000 92.75000 O ? A ? 169 0 + ATOM 1232 N . ALA A 170 ? -5.89200 17.86000 -0.82300 1.000 92.72000 N ? A ? 170 0 + ATOM 1233 CA . ALA A 170 ? -5.92500 16.44200 -1.14900 1.000 92.72000 C ? A ? 170 0 + ATOM 1234 C . ALA A 170 ? -4.57100 15.98600 -1.70400 1.000 92.72000 C ? A ? 170 0 + ATOM 1235 O . ALA A 170 ? -3.98100 16.63500 -2.57200 1.000 92.72000 O ? A ? 170 0 + ATOM 1236 CB . ALA A 170 ? -7.07700 16.17100 -2.11900 1.000 92.72000 C ? A ? 170 0 + ATOM 1237 N . ARG A 171 ? -4.06800 14.86900 -1.17400 1.000 91.52000 N ? A ? 171 0 + ATOM 1238 CA . ARG A 171 ? -2.79200 14.27300 -1.58500 1.000 91.52000 C ? A ? 171 0 + ATOM 1239 C . ARG A 171 ? -3.04000 13.12600 -2.56100 1.000 91.52000 C ? A ? 171 0 + ATOM 1240 O . ARG A 171 ? -4.08900 12.48200 -2.52500 1.000 91.52000 O ? A ? 171 0 + ATOM 1241 CB . ARG A 171 ? -1.98700 13.83000 -0.35300 1.000 91.52000 C ? A ? 171 0 + ATOM 1242 CG . ARG A 171 ? -1.69200 14.98900 0.60900 1.000 91.52000 C ? A ? 171 0 + ATOM 1243 CD . ARG A 171 ? -0.92700 14.48300 1.83300 1.000 91.52000 C ? A ? 171 0 + ATOM 1244 NE . ARG A 171 ? -0.64900 15.59500 2.76100 1.000 91.52000 N ? A ? 171 0 + ATOM 1245 CZ . ARG A 171 ? 0.42100 15.73700 3.52000 1.000 91.52000 C ? A ? 171 0 + ATOM 1246 NH1 . ARG A 171 ? 1.37800 14.85200 3.53600 1.000 91.52000 N ? A ? 171 0 + ATOM 1247 NH2 . ARG A 171 ? 0.54400 16.78100 4.29100 1.000 91.52000 N ? A ? 171 0 + ATOM 1248 N . CYS A 172 ? -2.06600 12.85300 -3.42300 1.000 92.05000 N ? A ? 172 0 + ATOM 1249 CA . CYS A 172 ? -2.07700 11.64700 -4.24800 1.000 92.05000 C ? A ? 172 0 + ATOM 1250 C . CYS A 172 ? -1.94000 10.39300 -3.37300 1.000 92.05000 C ? A ? 172 0 + ATOM 1251 O . CYS A 172 ? -1.41800 10.46100 -2.26100 1.000 92.05000 O ? A ? 172 0 + ATOM 1252 CB . CYS A 172 ? -0.95900 11.73600 -5.29600 1.000 92.05000 C ? A ? 172 0 + ATOM 1253 SG . CYS A 172 ? 0.73700 11.85200 -4.64200 1.000 92.05000 S ? A ? 172 0 + ATOM 1254 N . GLY A 173 ? -2.36000 9.23800 -3.88400 1.000 91.78000 N ? A ? 173 0 + ATOM 1255 CA . GLY A 173 ? -2.15300 7.96300 -3.19800 1.000 91.78000 C ? A ? 173 0 + ATOM 1256 C . GLY A 173 ? -3.04900 7.73900 -1.97600 1.000 91.78000 C ? A ? 173 0 + ATOM 1257 O . GLY A 173 ? -2.76200 6.84500 -1.18300 1.000 91.78000 O ? A ? 173 0 + ATOM 1258 N . MET A 174 ? -4.09600 8.54600 -1.80000 1.000 91.89000 N ? A ? 174 0 + ATOM 1259 CA . MET A 174 ? -4.91600 8.56300 -0.59100 1.000 91.89000 C ? A ? 174 0 + ATOM 1260 C . MET A 174 ? -6.24300 7.84900 -0.80100 1.000 91.89000 C ? A ? 174 0 + ATOM 1261 O . MET A 174 ? -6.87800 7.99600 -1.84700 1.000 91.89000 O ? A ? 174 0 + ATOM 1262 CB . MET A 174 ? -5.17000 10.00400 -0.13900 1.000 91.89000 C ? A ? 174 0 + ATOM 1263 CG . MET A 174 ? -3.88900 10.73000 0.27700 1.000 91.89000 C ? A ? 174 0 + ATOM 1264 SD . MET A 174 ? -2.86800 9.91800 1.52900 1.000 91.89000 S ? A ? 174 0 + ATOM 1265 CE . MET A 174 ? -4.02600 9.98500 2.91200 1.000 91.89000 C ? A ? 174 0 + ATOM 1266 N . HIS A 175 ? -6.68200 7.13400 0.23200 1.000 91.96000 N ? A ? 175 0 + ATOM 1267 CA . HIS A 175 ? -8.06300 6.68300 0.36800 1.000 91.96000 C ? A ? 175 0 + ATOM 1268 C . HIS A 175 ? -8.74200 7.57100 1.40800 1.000 91.96000 C ? A ? 175 0 + ATOM 1269 O . HIS A 175 ? -8.27900 7.61400 2.54700 1.000 91.96000 O ? A ? 175 0 + ATOM 1270 CB . HIS A 175 ? -8.09100 5.20500 0.76800 1.000 91.96000 C ? A ? 175 0 + ATOM 1271 CG . HIS A 175 ? -9.42400 4.56000 0.50000 1.000 91.96000 C ? A ? 175 0 + ATOM 1272 ND1 . HIS A 175 ? -10.56400 4.60300 1.27600 1.000 91.96000 N ? A ? 175 0 + ATOM 1273 CD2 . HIS A 175 ? -9.71100 3.78000 -0.58600 1.000 91.96000 C ? A ? 175 0 + ATOM 1274 CE1 . HIS A 175 ? -11.49400 3.84700 0.67100 1.000 91.96000 C ? A ? 175 0 + ATOM 1275 NE2 . HIS A 175 ? -11.02600 3.33500 -0.47800 1.000 91.96000 N ? A ? 175 0 + ATOM 1276 N . TYR A 176 ? -9.78000 8.30200 1.00700 1.000 91.90000 N ? A ? 176 0 + ATOM 1277 CA . TYR A 176 ? -10.49900 9.23500 1.86800 1.000 91.90000 C ? A ? 176 0 + ATOM 1278 C . TYR A 176 ? -11.89900 8.72100 2.18700 1.000 91.90000 C ? A ? 176 0 + ATOM 1279 O . TYR A 176 ? -12.65800 8.38500 1.27400 1.000 91.90000 O ? A ? 176 0 + ATOM 1280 CB . TYR A 176 ? -10.58200 10.63000 1.22800 1.000 91.90000 C ? A ? 176 0 + ATOM 1281 CG . TYR A 176 ? -9.29700 11.43600 1.27800 1.000 91.90000 C ? A ? 176 0 + ATOM 1282 CD1 . TYR A 176 ? -8.82200 11.91700 2.51200 1.000 91.90000 C ? A ? 176 0 + ATOM 1283 CD2 . TYR A 176 ? -8.59100 11.73100 0.09800 1.000 91.90000 C ? A ? 176 0 + ATOM 1284 CE1 . TYR A 176 ? -7.62500 12.65500 2.58200 1.000 91.90000 C ? A ? 176 0 + ATOM 1285 CE2 . TYR A 176 ? -7.40700 12.49400 0.15500 1.000 91.90000 C ? A ? 176 0 + ATOM 1286 CZ . TYR A 176 ? -6.91300 12.94400 1.39800 1.000 91.90000 C ? A ? 176 0 + ATOM 1287 OH . TYR A 176 ? -5.75200 13.65000 1.45900 1.000 91.90000 O ? A ? 176 0 + ATOM 1288 N . THR A 177 ? -12.25500 8.78300 3.46700 1.000 92.26000 N ? A ? 177 0 + ATOM 1289 CA . THR A 177 ? -13.63400 8.67700 3.94300 1.000 92.26000 C ? A ? 177 0 + ATOM 1290 C . THR A 177 ? -14.18600 10.07600 4.16500 1.000 92.26000 C ? A ? 177 0 + ATOM 1291 O . THR A 177 ? -13.65500 10.84100 4.97200 1.000 92.26000 O ? A ? 177 0 + ATOM 1292 CB . THR A 177 ? -13.72300 7.89300 5.25400 1.000 92.26000 C ? A ? 177 0 + ATOM 1293 OG1 . THR A 177 ? -13.15900 6.61600 5.11800 1.000 92.26000 O ? A ? 177 0 + ATOM 1294 CG2 . THR A 177 ? -15.18100 7.74900 5.69700 1.000 92.26000 C ? A ? 177 0 + ATOM 1295 N . ILE A 178 ? -15.24700 10.42700 3.44500 1.000 92.35000 N ? A ? 178 0 + ATOM 1296 CA . ILE A 178 ? -15.83500 11.76700 3.45000 1.000 92.35000 C ? A ? 178 0 + ATOM 1297 C . ILE A 178 ? -17.19900 11.72900 4.12800 1.000 92.35000 C ? A ? 178 0 + ATOM 1298 O . ILE A 178 ? -18.03900 10.89200 3.80400 1.000 92.35000 O ? A ? 178 0 + ATOM 1299 CB . ILE A 178 ? -15.91300 12.35000 2.02300 1.000 92.35000 C ? A ? 178 0 + ATOM 1300 CG1 . ILE A 178 ? -14.53500 12.25200 1.32900 1.000 92.35000 C ? A ? 178 0 + ATOM 1301 CG2 . ILE A 178 ? -16.41600 13.80900 2.06500 1.000 92.35000 C ? A ? 178 0 + ATOM 1302 CD1 . ILE A 178 ? -14.49600 12.80100 -0.09400 1.000 92.35000 C ? A ? 178 0 + ATOM 1303 N . ILE A 179 ? -17.44300 12.68100 5.02300 1.000 90.26000 N ? A ? 179 0 + ATOM 1304 CA . ILE A 179 ? -18.76100 12.93800 5.60800 1.000 90.26000 C ? A ? 179 0 + ATOM 1305 C . ILE A 179 ? -19.10300 14.42100 5.51300 1.000 90.26000 C ? A ? 179 0 + ATOM 1306 O . ILE A 179 ? -18.22200 15.28200 5.49000 1.000 90.26000 O ? A ? 179 0 + ATOM 1307 CB . ILE A 179 ? -18.86900 12.43400 7.06600 1.000 90.26000 C ? A ? 179 0 + ATOM 1308 CG1 . ILE A 179 ? -17.84300 13.10000 8.00600 1.000 90.26000 C ? A ? 179 0 + ATOM 1309 CG2 . ILE A 179 ? -18.77200 10.90200 7.10600 1.000 90.26000 C ? A ? 179 0 + ATOM 1310 CD1 . ILE A 179 ? -18.13400 12.87000 9.49300 1.000 90.26000 C ? A ? 179 0 + ATOM 1311 N . VAL A 180 ? -20.39900 14.71400 5.50200 1.000 89.75000 N ? A ? 180 0 + ATOM 1312 CA . VAL A 180 ? -20.93000 16.06500 5.69300 1.000 89.75000 C ? A ? 180 0 + ATOM 1313 C . VAL A 180 ? -21.77900 16.06800 6.95500 1.000 89.75000 C ? A ? 180 0 + ATOM 1314 O . VAL A 180 ? -22.61200 15.18200 7.13700 1.000 89.75000 O ? A ? 180 0 + ATOM 1315 CB . VAL A 180 ? -21.71800 16.53100 4.45800 1.000 89.75000 C ? A ? 180 0 + ATOM 1316 CG1 . VAL A 180 ? -22.34200 17.91700 4.66600 1.000 89.75000 C ? A ? 180 0 + ATOM 1317 CG2 . VAL A 180 ? -20.79900 16.61400 3.23200 1.000 89.75000 C ? A ? 180 0 + ATOM 1318 N . SER A 181 ? -21.58800 17.05800 7.82100 1.000 87.20000 N ? A ? 181 0 + ATOM 1319 CA . SER A 181 ? -22.38400 17.27500 9.03100 1.000 87.20000 C ? A ? 181 0 + ATOM 1320 C . SER A 181 ? -22.98000 18.68100 9.04900 1.000 87.20000 C ? A ? 181 0 + ATOM 1321 O . SER A 181 ? -22.35600 19.63900 8.60300 1.000 87.20000 O ? A ? 181 0 + ATOM 1322 CB . SER A 181 ? -21.55200 16.98600 10.29000 1.000 87.20000 C ? A ? 181 0 + ATOM 1323 OG . SER A 181 ? -20.37100 17.76300 10.33100 1.000 87.20000 O ? A ? 181 0 + ATOM 1324 N . ALA A 182 ? -24.19200 18.83300 9.58900 1.000 81.02000 N ? A ? 182 0 + ATOM 1325 CA . ALA A 182 ? -24.82500 20.14600 9.79800 1.000 81.02000 C ? A ? 182 0 + ATOM 1326 C . ALA A 182 ? -24.31200 20.88200 11.06100 1.000 81.02000 C ? A ? 182 0 + ATOM 1327 O . ALA A 182 ? -24.80700 21.94900 11.41600 1.000 81.02000 O ? A ? 182 0 + ATOM 1328 CB . ALA A 182 ? -26.34500 19.94500 9.82600 1.000 81.02000 C ? A ? 182 0 + ATOM 1329 N . SER A 183 ? -23.35400 20.27900 11.77000 1.000 73.04000 N ? A ? 183 0 + ATOM 1330 CA . SER A 183 ? -22.70300 20.77300 12.98600 1.000 73.04000 C ? A ? 183 0 + ATOM 1331 C . SER A 183 ? -21.19000 20.59800 12.84800 1.000 73.04000 C ? A ? 183 0 + ATOM 1332 O . SER A 183 ? -20.73600 19.71600 12.11800 1.000 73.04000 O ? A ? 183 0 + ATOM 1333 CB . SER A 183 ? -23.22400 19.98700 14.19700 1.000 73.04000 C ? A ? 183 0 + ATOM 1334 OG . SER A 183 ? -22.54200 20.35700 15.38200 1.000 73.04000 O ? A ? 183 0 + ATOM 1335 N . SER A 184 ? -20.39900 21.39300 13.57200 1.000 67.24000 N ? A ? 184 0 + ATOM 1336 CA . SER A 184 ? -18.94700 21.19100 13.68300 1.000 67.24000 C ? A ? 184 0 + ATOM 1337 C . SER A 184 ? -18.57100 19.89600 14.41200 1.000 67.24000 C ? A ? 184 0 + ATOM 1338 O . SER A 184 ? -17.42700 19.45200 14.31900 1.000 67.24000 O ? A ? 184 0 + ATOM 1339 CB . SER A 184 ? -18.30600 22.38300 14.39800 1.000 67.24000 C ? A ? 184 0 + ATOM 1340 OG . SER A 184 ? -18.93500 22.61200 15.64700 1.000 67.24000 O ? A ? 184 0 + ATOM 1341 N . ASP A 185 ? -19.52100 19.28100 15.12100 1.000 68.66000 N ? A ? 185 0 + ATOM 1342 CA . ASP A 185 ? -19.33700 17.97600 15.74500 1.000 68.66000 C ? A ? 185 0 + ATOM 1343 C . ASP A 185 ? -19.49800 16.84400 14.71500 1.000 68.66000 C ? A ? 185 0 + ATOM 1344 O . ASP A 185 ? -20.60900 16.50400 14.28600 1.000 68.66000 O ? A ? 185 0 + ATOM 1345 CB . ASP A 185 ? -20.28200 17.82700 16.94200 1.000 68.66000 C ? A ? 185 0 + ATOM 1346 CG . ASP A 185 ? -20.04300 16.52400 17.71400 1.000 68.66000 C ? A ? 185 0 + ATOM 1347 OD1 . ASP A 185 ? -19.11000 15.77100 17.34300 1.000 68.66000 O ? A ? 185 0 + ATOM 1348 OD2 . ASP A 185 ? -20.82700 16.28400 18.65300 1.000 68.66000 O ? A ? 185 0 + ATOM 1349 N . LYS A 186 ? -18.36100 16.24600 14.34400 1.000 66.46000 N ? A ? 186 0 + ATOM 1350 CA . LYS A 186 ? -18.25600 15.14200 13.37800 1.000 66.46000 C ? A ? 186 0 + ATOM 1351 C . LYS A 186 ? -18.97000 13.87000 13.83900 1.000 66.46000 C ? A ? 186 0 + ATOM 1352 O . LYS A 186 ? -19.40200 13.08600 13.00000 1.000 66.46000 O ? A ? 186 0 + ATOM 1353 CB . LYS A 186 ? -16.78100 14.81100 13.12400 1.000 66.46000 C ? A ? 186 0 + ATOM 1354 CG . LYS A 186 ? -15.97800 15.99000 12.56200 1.000 66.46000 C ? A ? 186 0 + ATOM 1355 CD . LYS A 186 ? -14.54200 15.53400 12.30400 1.000 66.46000 C ? A ? 186 0 + ATOM 1356 CE . LYS A 186 ? -13.71500 16.70800 11.78900 1.000 66.46000 C ? A ? 186 0 + ATOM 1357 NZ . LYS A 186 ? -12.32100 16.28200 11.55300 1.000 66.46000 N ? A ? 186 0 + ATOM 1358 N . CYS A 187 ? -19.12400 13.68100 15.15100 1.000 69.95000 N ? A ? 187 0 + ATOM 1359 CA . CYS A 187 ? -19.84400 12.54300 15.71900 1.000 69.95000 C ? A ? 187 0 + ATOM 1360 C . CYS A 187 ? -21.34700 12.80000 15.88800 1.000 69.95000 C ? A ? 187 0 + ATOM 1361 O . CYS A 187 ? -22.06000 11.93000 16.39300 1.000 69.95000 O ? A ? 187 0 + ATOM 1362 CB . CYS A 187 ? -19.22900 12.14600 17.06600 1.000 69.95000 C ? A ? 187 0 + ATOM 1363 SG . CYS A 187 ? -17.54100 11.49300 17.09600 1.000 69.95000 S ? A ? 187 0 + ATOM 1364 N . SER A 188 ? -21.85000 13.97200 15.48700 1.000 70.41000 N ? A ? 188 0 + ATOM 1365 CA . SER A 188 ? -23.27100 14.28100 15.62200 1.000 70.41000 C ? A ? 188 0 + ATOM 1366 C . SER A 188 ? -24.14300 13.33600 14.78700 1.000 70.41000 C ? A ? 188 0 + ATOM 1367 O . SER A 188 ? -23.75200 12.83100 13.73300 1.000 70.41000 O ? A ? 188 0 + ATOM 1368 CB . SER A 188 ? -23.56100 15.75400 15.31400 1.000 70.41000 C ? A ? 188 0 + ATOM 1369 OG . SER A 188 ? -23.32600 16.07900 13.96000 1.000 70.41000 O ? A ? 188 0 + ATOM 1370 N . SER A 189 ? -25.37800 13.11300 15.23700 1.000 66.77000 N ? A ? 189 0 + ATOM 1371 CA . SER A 189 ? -26.38300 12.35800 14.47300 1.000 66.77000 C ? A ? 189 0 + ATOM 1372 C . SER A 189 ? -26.81900 13.07800 13.18700 1.000 66.77000 C ? A ? 189 0 + ATOM 1373 O . SER A 189 ? -27.42500 12.47000 12.30200 1.000 66.77000 O ? A ? 189 0 + ATOM 1374 CB . SER A 189 ? -27.60000 12.09100 15.36100 1.000 66.77000 C ? A ? 189 0 + ATOM 1375 OG . SER A 189 ? -28.07300 13.30600 15.91900 1.000 66.77000 O ? A ? 189 0 + ATOM 1376 N . LEU A 190 ? -26.49700 14.36800 13.04600 1.000 74.68000 N ? A ? 190 0 + ATOM 1377 CA . LEU A 190 ? -26.85600 15.22500 11.91400 1.000 74.68000 C ? A ? 190 0 + ATOM 1378 C . LEU A 190 ? -25.82200 15.16300 10.77900 1.000 74.68000 C ? A ? 190 0 + ATOM 1379 O . LEU A 190 ? -25.37600 16.19800 10.27600 1.000 74.68000 O ? A ? 190 0 + ATOM 1380 CB . LEU A 190 ? -27.11100 16.65900 12.40600 1.000 74.68000 C ? A ? 190 0 + ATOM 1381 CG . LEU A 190 ? -28.28800 16.81700 13.38000 1.000 74.68000 C ? A ? 190 0 + ATOM 1382 CD1 . LEU A 190 ? -28.33100 18.27000 13.85200 1.000 74.68000 C ? A ? 190 0 + ATOM 1383 CD2 . LEU A 190 ? -29.63300 16.47700 12.73400 1.000 74.68000 C ? A ? 190 0 + ATOM 1384 N . ARG A 191 ? -25.43700 13.94800 10.38300 1.000 82.69000 N ? A ? 191 0 + ATOM 1385 CA . ARG A 191 ? -24.43600 13.69800 9.33800 1.000 82.69000 C ? A ? 191 0 + ATOM 1386 C . ARG A 191 ? -24.94400 12.80200 8.21400 1.000 82.69000 C ? A ? 191 0 + ATOM 1387 O . ARG A 191 ? -25.97600 12.13800 8.35100 1.000 82.69000 O ? A ? 191 0 + ATOM 1388 CB . ARG A 191 ? -23.13900 13.17000 9.96800 1.000 82.69000 C ? A ? 191 0 + ATOM 1389 CG . ARG A 191 ? -23.30900 11.75400 10.52100 1.000 82.69000 C ? A ? 191 0 + ATOM 1390 CD . ARG A 191 ? -22.03600 11.31400 11.23200 1.000 82.69000 C ? A ? 191 0 + ATOM 1391 NE . ARG A 191 ? -22.26900 10.00500 11.84100 1.000 82.69000 N ? A ? 191 0 + ATOM 1392 CZ . ARG A 191 ? -21.91600 8.83700 11.35500 1.000 82.69000 C ? A ? 191 0 + ATOM 1393 NH1 . ARG A 191 ? -21.25700 8.68400 10.24200 1.000 82.69000 N ? A ? 191 0 + ATOM 1394 NH2 . ARG A 191 ? -22.22900 7.77500 12.03200 1.000 82.69000 N ? A ? 191 0 + ATOM 1395 N . SER A 192 ? -24.20800 12.80900 7.10800 1.000 86.92000 N ? A ? 192 0 + ATOM 1396 CA . SER A 192 ? -24.40300 11.91100 5.97400 1.000 86.92000 C ? A ? 192 0 + ATOM 1397 C . SER A 192 ? -23.79300 10.53100 6.22700 1.000 86.92000 C ? A ? 192 0 + ATOM 1398 O . SER A 192 ? -22.90800 10.39300 7.07800 1.000 86.92000 O ? A ? 192 0 + ATOM 1399 CB . SER A 192 ? -23.78600 12.52400 4.71400 1.000 86.92000 C ? A ? 192 0 + ATOM 1400 OG . SER A 192 ? -22.36700 12.54100 4.77200 1.000 86.92000 O ? A ? 192 0 + ATOM 1401 N . PRO A 193 ? -24.19500 9.51200 5.44800 1.000 84.85000 N ? A ? 193 0 + ATOM 1402 CA . PRO A 193 ? -23.41200 8.29000 5.32500 1.000 84.85000 C ? A ? 193 0 + ATOM 1403 C . PRO A 193 ? -21.97800 8.61000 4.87100 1.000 84.85000 C ? A ? 193 0 + ATOM 1404 O . PRO A 193 ? -21.79400 9.58100 4.12300 1.000 84.85000 O ? A ? 193 0 + ATOM 1405 CB . PRO A 193 ? -24.16100 7.41300 4.31600 1.000 84.85000 C ? A ? 193 0 + ATOM 1406 CG . PRO A 193 ? -25.59300 7.95000 4.36000 1.000 84.85000 C ? A ? 193 0 + ATOM 1407 CD . PRO A 193 ? -25.39600 9.43800 4.63200 1.000 84.85000 C ? A ? 193 0 + ATOM 1408 N . PRO A 194 ? -20.97700 7.82700 5.31000 1.000 88.88000 N ? A ? 194 0 + ATOM 1409 CA . PRO A 194 ? -19.61200 7.95800 4.81900 1.000 88.88000 C ? A ? 194 0 + ATOM 1410 C . PRO A 194 ? -19.55200 7.64300 3.32400 1.000 88.88000 C ? A ? 194 0 + ATOM 1411 O . PRO A 194 ? -20.19100 6.70300 2.84400 1.000 88.88000 O ? A ? 194 0 + ATOM 1412 CB . PRO A 194 ? -18.76900 6.98900 5.65100 1.000 88.88000 C ? A ? 194 0 + ATOM 1413 CG . PRO A 194 ? -19.77700 5.90600 6.01900 1.000 88.88000 C ? A ? 194 0 + ATOM 1414 CD . PRO A 194 ? -21.07400 6.69000 6.21100 1.000 88.88000 C ? A ? 194 0 + ATOM 1415 N . PHE A 195 ? -18.78700 8.44500 2.59300 1.000 90.78000 N ? A ? 195 0 + ATOM 1416 CA . PHE A 195 ? -18.50500 8.25900 1.17700 1.000 90.78000 C ? A ? 195 0 + ATOM 1417 C . PHE A 195 ? -17.01800 7.97400 0.98900 1.000 90.78000 C ? A ? 195 0 + ATOM 1418 O . PHE A 195 ? -16.17400 8.80000 1.33300 1.000 90.78000 O ? A ? 195 0 + ATOM 1419 CB . PHE A 195 ? -18.95800 9.49500 0.39600 1.000 90.78000 C ? A ? 195 0 + ATOM 1420 CG . PHE A 195 ? -18.83200 9.34600 -1.10600 1.000 90.78000 C ? A ? 195 0 + ATOM 1421 CD1 . PHE A 195 ? -17.62000 9.65300 -1.75500 1.000 90.78000 C ? A ? 195 0 + ATOM 1422 CD2 . PHE A 195 ? -19.92700 8.88200 -1.85700 1.000 90.78000 C ? A ? 195 0 + ATOM 1423 CE1 . PHE A 195 ? -17.51100 9.49500 -3.14800 1.000 90.78000 C ? A ? 195 0 + ATOM 1424 CE2 . PHE A 195 ? -19.81400 8.72000 -3.24800 1.000 90.78000 C ? A ? 195 0 + ATOM 1425 CZ . PHE A 195 ? -18.60400 9.02500 -3.89400 1.000 90.78000 C ? A ? 195 0 + ATOM 1426 N . GLU A 196 ? -16.70700 6.81300 0.42300 1.000 90.83000 N ? A ? 196 0 + ATOM 1427 CA . GLU A 196 ? -15.33600 6.37800 0.16900 1.000 90.83000 C ? A ? 196 0 + ATOM 1428 C . GLU A 196 ? -14.87900 6.78200 -1.23200 1.000 90.83000 C ? A ? 196 0 + ATOM 1429 O . GLU A 196 ? -15.58700 6.56900 -2.22000 1.000 90.83000 O ? A ? 196 0 + ATOM 1430 CB . GLU A 196 ? -15.23000 4.85600 0.32800 1.000 90.83000 C ? A ? 196 0 + ATOM 1431 CG . GLU A 196 ? -15.54200 4.35500 1.74500 1.000 90.83000 C ? A ? 196 0 + ATOM 1432 CD . GLU A 196 ? -14.63400 4.97700 2.80800 1.000 90.83000 C ? A ? 196 0 + ATOM 1433 OE1 . GLU A 196 ? -15.17000 5.42300 3.84000 1.000 90.83000 O ? A ? 196 0 + ATOM 1434 OE2 . GLU A 196 ? -13.40400 5.02200 2.60400 1.000 90.83000 O ? A ? 196 0 + ATOM 1435 N . MET A 197 ? -13.66300 7.31300 -1.33500 1.000 90.26000 N ? A ? 197 0 + ATOM 1436 CA . MET A 197 ? -13.01300 7.56000 -2.61900 1.000 90.26000 C ? A ? 197 0 + ATOM 1437 C . MET A 197 ? -11.50000 7.39500 -2.54500 1.000 90.26000 C ? A ? 197 0 + ATOM 1438 O . MET A 197 ? -10.88700 7.52000 -1.49000 1.000 90.26000 O ? A ? 197 0 + ATOM 1439 CB . MET A 197 ? -13.36900 8.95200 -3.14900 1.000 90.26000 C ? A ? 197 0 + ATOM 1440 CG . MET A 197 ? -12.83600 10.09500 -2.27500 1.000 90.26000 C ? A ? 197 0 + ATOM 1441 SD . MET A 197 ? -12.77900 11.68400 -3.13200 1.000 90.26000 S ? A ? 197 0 + ATOM 1442 CE . MET A 197 ? -14.50400 11.77600 -3.60600 1.000 90.26000 C ? A ? 197 0 + ATOM 1443 N . SER A 198 ? -10.88100 7.17700 -3.70200 1.000 91.54000 N ? A ? 198 0 + ATOM 1444 CA . SER A 198 ? -9.42600 7.20000 -3.84900 1.000 91.54000 C ? A ? 198 0 + ATOM 1445 C . SER A 198 ? -8.99900 8.36100 -4.73600 1.000 91.54000 C ? A ? 198 0 + ATOM 1446 O . SER A 198 ? -9.62200 8.60800 -5.77000 1.000 91.54000 O ? A ? 198 0 + ATOM 1447 CB . SER A 198 ? -8.92300 5.88700 -4.44100 1.000 91.54000 C ? A ? 198 0 + ATOM 1448 OG . SER A 198 ? -9.23200 4.80500 -3.58700 1.000 91.54000 O ? A ? 198 0 + ATOM 1449 N . THR A 199 ? -7.91800 9.04300 -4.36400 1.000 91.35000 N ? A ? 199 0 + ATOM 1450 CA . THR A 199 ? -7.26100 10.00900 -5.25100 1.000 91.35000 C ? A ? 199 0 + ATOM 1451 C . THR A 199 ? -6.42600 9.29000 -6.31200 1.000 91.35000 C ? A ? 199 0 + ATOM 1452 O . THR A 199 ? -6.25400 8.06700 -6.28400 1.000 91.35000 O ? A ? 199 0 + ATOM 1453 CB . THR A 199 ? -6.42500 11.03500 -4.46800 1.000 91.35000 C ? A ? 199 0 + ATOM 1454 OG1 . THR A 199 ? -5.39000 10.43900 -3.72300 1.000 91.35000 O ? A ? 199 0 + ATOM 1455 CG2 . THR A 199 ? -7.29000 11.82400 -3.48900 1.000 91.35000 C ? A ? 199 0 + ATOM 1456 N . ALA A 200 ? -5.90100 10.03500 -7.28800 1.000 92.36000 N ? A ? 200 0 + ATOM 1457 CA . ALA A 200 ? -4.97000 9.46500 -8.25300 1.000 92.36000 C ? A ? 200 0 + ATOM 1458 C . ALA A 200 ? -3.71300 8.91800 -7.54500 1.000 92.36000 C ? A ? 200 0 + ATOM 1459 O . ALA A 200 ? -3.26000 9.51000 -6.55700 1.000 92.36000 O ? A ? 200 0 + ATOM 1460 CB . ALA A 200 ? -4.59600 10.52600 -9.28600 1.000 92.36000 C ? A ? 200 0 + ATOM 1461 N . PRO A 201 ? -3.10500 7.82700 -8.04300 1.000 94.47000 N ? A ? 201 0 + ATOM 1462 CA . PRO A 201 ? -1.85100 7.33000 -7.49700 1.000 94.47000 C ? A ? 201 0 + ATOM 1463 C . PRO A 201 ? -0.75300 8.39200 -7.53000 1.000 94.47000 C ? A ? 201 0 + ATOM 1464 O . PRO A 201 ? -0.68100 9.21100 -8.45000 1.000 94.47000 O ? A ? 201 0 + ATOM 1465 CB . PRO A 201 ? -1.45900 6.13900 -8.36700 1.000 94.47000 C ? A ? 201 0 + ATOM 1466 CG . PRO A 201 ? -2.78700 5.66800 -8.94600 1.000 94.47000 C ? A ? 201 0 + ATOM 1467 CD . PRO A 201 ? -3.55800 6.97200 -9.12800 1.000 94.47000 C ? A ? 201 0 + ATOM 1468 N . CYS A 202 ? 0.15500 8.34700 -6.55800 1.000 93.84000 N ? A ? 202 0 + ATOM 1469 CA . CYS A 202 ? 1.36400 9.15600 -6.63600 1.000 93.84000 C ? A ? 202 0 + ATOM 1470 C . CYS A 202 ? 2.28300 8.67300 -7.76100 1.000 93.84000 C ? A ? 202 0 + ATOM 1471 O . CYS A 202 ? 2.32500 7.48400 -8.09400 1.000 93.84000 O ? A ? 202 0 + ATOM 1472 CB . CYS A 202 ? 2.09500 9.17300 -5.29400 1.000 93.84000 C ? A ? 202 0 + ATOM 1473 SG . CYS A 202 ? 1.20400 9.98500 -3.94800 1.000 93.84000 S ? A ? 202 0 + ATOM 1474 N . VAL A 203 ? 3.05800 9.61200 -8.30600 1.000 94.50000 N ? A ? 203 0 + ATOM 1475 CA . VAL A 203 ? 4.10300 9.33600 -9.29700 1.000 94.50000 C ? A ? 203 0 + ATOM 1476 C . VAL A 203 ? 5.05700 8.27000 -8.74200 1.000 94.50000 C ? A ? 203 0 + ATOM 1477 O . VAL A 203 ? 5.60700 8.49400 -7.65800 1.000 94.50000 O ? A ? 203 0 + ATOM 1478 CB . VAL A 203 ? 4.89300 10.61600 -9.61800 1.000 94.50000 C ? A ? 203 0 + ATOM 1479 CG1 . VAL A 203 ? 5.95200 10.34500 -10.68300 1.000 94.50000 C ? A ? 203 0 + ATOM 1480 CG2 . VAL A 203 ? 3.97700 11.72600 -10.14300 1.000 94.50000 C ? A ? 203 0 + ATOM 1481 N . PRO A 204 ? 5.27700 7.14200 -9.44400 1.000 95.53000 N ? A ? 204 0 + ATOM 1482 CA . PRO A 204 ? 6.18900 6.10400 -8.97300 1.000 95.53000 C ? A ? 204 0 + ATOM 1483 C . PRO A 204 ? 7.60100 6.65000 -8.72900 1.000 95.53000 C ? A ? 204 0 + ATOM 1484 O . PRO A 204 ? 8.10200 7.47300 -9.49700 1.000 95.53000 O ? A ? 204 0 + ATOM 1485 CB . PRO A 204 ? 6.18700 5.01100 -10.04200 1.000 95.53000 C ? A ? 204 0 + ATOM 1486 CG . PRO A 204 ? 4.85200 5.21500 -10.75400 1.000 95.53000 C ? A ? 204 0 + ATOM 1487 CD . PRO A 204 ? 4.61800 6.72000 -10.67400 1.000 95.53000 C ? A ? 204 0 + ATOM 1488 N . GLN A 205 ? 8.23800 6.18100 -7.65600 1.000 94.67000 N ? A ? 205 0 + ATOM 1489 CA . GLN A 205 ? 9.56500 6.62400 -7.21200 1.000 94.67000 C ? A ? 205 0 + ATOM 1490 C . GLN A 205 ? 10.57100 5.46700 -7.22300 1.000 94.67000 C ? A ? 205 0 + ATOM 1491 O . GLN A 205 ? 10.18700 4.29700 -7.29600 1.000 94.67000 O ? A ? 205 0 + ATOM 1492 CB . GLN A 205 ? 9.47200 7.24700 -5.80500 1.000 94.67000 C ? A ? 205 0 + ATOM 1493 CG . GLN A 205 ? 8.54900 8.47200 -5.71600 1.000 94.67000 C ? A ? 205 0 + ATOM 1494 CD . GLN A 205 ? 8.97100 9.61500 -6.63400 1.000 94.67000 C ? A ? 205 0 + ATOM 1495 OE1 . GLN A 205 ? 10.12600 10.00100 -6.70200 1.000 94.67000 O ? A ? 205 0 + ATOM 1496 NE2 . GLN A 205 ? 8.05200 10.18400 -7.37900 1.000 94.67000 N ? A ? 205 0 + ATOM 1497 N . ASN A 206 ? 11.86100 5.79900 -7.09200 1.000 94.81000 N ? A ? 206 0 + ATOM 1498 CA . ASN A 206 ? 12.97400 4.84300 -7.01400 1.000 94.81000 C ? A ? 206 0 + ATOM 1499 C . ASN A 206 ? 12.98200 3.84400 -8.17900 1.000 94.81000 C ? A ? 206 0 + ATOM 1500 O . ASN A 206 ? 13.01200 2.63200 -7.96900 1.000 94.81000 O ? A ? 206 0 + ATOM 1501 CB . ASN A 206 ? 12.98500 4.15200 -5.64000 1.000 94.81000 C ? A ? 206 0 + ATOM 1502 CG . ASN A 206 ? 13.01000 5.12100 -4.48100 1.000 94.81000 C ? A ? 206 0 + ATOM 1503 OD1 . ASN A 206 ? 13.72000 6.11000 -4.48600 1.000 94.81000 O ? A ? 206 0 + ATOM 1504 ND2 . ASN A 206 ? 12.22500 4.88000 -3.45800 1.000 94.81000 N ? A ? 206 0 + ATOM 1505 N . VAL A 207 ? 12.90500 4.35800 -9.40800 1.000 95.64000 N ? A ? 207 0 + ATOM 1506 CA . VAL A 207 ? 12.98700 3.53000 -10.61300 1.000 95.64000 C ? A ? 207 0 + ATOM 1507 C . VAL A 207 ? 14.41700 3.00500 -10.75800 1.000 95.64000 C ? A ? 207 0 + ATOM 1508 O . VAL A 207 ? 15.35900 3.78100 -10.89900 1.000 95.64000 O ? A ? 207 0 + ATOM 1509 CB . VAL A 207 ? 12.53700 4.29700 -11.87000 1.000 95.64000 C ? A ? 207 0 + ATOM 1510 CG1 . VAL A 207 ? 12.57300 3.39600 -13.11200 1.000 95.64000 C ? A ? 207 0 + ATOM 1511 CG2 . VAL A 207 ? 11.10800 4.83900 -11.72400 1.000 95.64000 C ? A ? 207 0 + ATOM 1512 N . VAL A 208 ? 14.57000 1.68400 -10.72600 1.000 96.20000 N ? A ? 208 0 + ATOM 1513 CA . VAL A 208 ? 15.83600 0.96600 -10.90900 1.000 96.20000 C ? A ? 208 0 + ATOM 1514 C . VAL A 208 ? 15.75800 0.17100 -12.20400 1.000 96.20000 C ? A ? 208 0 + ATOM 1515 O . VAL A 208 ? 14.78700 -0.55600 -12.42400 1.000 96.20000 O ? A ? 208 0 + ATOM 1516 CB . VAL A 208 ? 16.13400 0.03800 -9.71700 1.000 96.20000 C ? A ? 208 0 + ATOM 1517 CG1 . VAL A 208 ? 17.46200 -0.70900 -9.90000 1.000 96.20000 C ? A ? 208 0 + ATOM 1518 CG2 . VAL A 208 ? 16.21000 0.81800 -8.40000 1.000 96.20000 C ? A ? 208 0 + ATOM 1519 N . LEU A 209 ? 16.78500 0.29900 -13.04400 1.000 95.76000 N ? A ? 209 0 + ATOM 1520 CA . LEU A 209 ? 16.87400 -0.34800 -14.35000 1.000 95.76000 C ? A ? 209 0 + ATOM 1521 C . LEU A 209 ? 18.06500 -1.30900 -14.36700 1.000 95.76000 C ? A ? 209 0 + ATOM 1522 O . LEU A 209 ? 19.20000 -0.89000 -14.14900 1.000 95.76000 O ? A ? 209 0 + ATOM 1523 CB . LEU A 209 ? 17.00800 0.71600 -15.45600 1.000 95.76000 C ? A ? 209 0 + ATOM 1524 CG . LEU A 209 ? 15.93500 1.82000 -15.44700 1.000 95.76000 C ? A ? 209 0 + ATOM 1525 CD1 . LEU A 209 ? 16.19300 2.79300 -16.58700 1.000 95.76000 C ? A ? 209 0 + ATOM 1526 CD2 . LEU A 209 ? 14.52600 1.26200 -15.63900 1.000 95.76000 C ? A ? 209 0 + ATOM 1527 N . ASN A 210 ? 17.80500 -2.58000 -14.66100 1.000 94.22000 N ? A ? 210 0 + ATOM 1528 CA . ASN A 210 ? 18.81400 -3.63000 -14.76700 1.000 94.22000 C ? A ? 210 0 + ATOM 1529 C . ASN A 210 ? 18.85700 -4.17200 -16.19700 1.000 94.22000 C ? A ? 210 0 + ATOM 1530 O . ASN A 210 ? 17.81500 -4.37000 -16.82100 1.000 94.22000 O ? A ? 210 0 + ATOM 1531 CB . ASN A 210 ? 18.49800 -4.74200 -13.75400 1.000 94.22000 C ? A ? 210 0 + ATOM 1532 CG . ASN A 210 ? 18.66200 -4.31300 -12.30600 1.000 94.22000 C ? A ? 210 0 + ATOM 1533 OD1 . ASN A 210 ? 19.31200 -3.34400 -11.96400 1.000 94.22000 O ? A ? 210 0 + ATOM 1534 ND2 . ASN A 210 ? 18.09000 -5.05100 -11.38500 1.000 94.22000 N ? A ? 210 0 + ATOM 1535 N . SER A 211 ? 20.05000 -4.45100 -16.71700 1.000 92.94000 N ? A ? 211 0 + ATOM 1536 CA . SER A 211 ? 20.20900 -5.06200 -18.03700 1.000 92.94000 C ? A ? 211 0 + ATOM 1537 C . SER A 211 ? 19.84600 -6.54900 -18.02300 1.000 92.94000 C ? A ? 211 0 + ATOM 1538 O . SER A 211 ? 20.15100 -7.27800 -17.08000 1.000 92.94000 O ? A ? 211 0 + ATOM 1539 CB . SER A 211 ? 21.63200 -4.84100 -18.56400 1.000 92.94000 C ? A ? 211 0 + ATOM 1540 OG . SER A 211 ? 22.59600 -5.24500 -17.60900 1.000 92.94000 O ? A ? 211 0 + ATOM 1541 N . MET A 212 ? 19.20200 -7.01300 -19.09600 1.000 91.28000 N ? A ? 212 0 + ATOM 1542 CA . MET A 212 ? 18.91400 -8.42700 -19.34400 1.000 91.28000 C ? A ? 212 0 + ATOM 1543 C . MET A 212 ? 19.64700 -8.87300 -20.60700 1.000 91.28000 C ? A ? 212 0 + ATOM 1544 O . MET A 212 ? 19.11300 -8.77500 -21.71500 1.000 91.28000 O ? A ? 212 0 + ATOM 1545 CB . MET A 212 ? 17.40700 -8.66500 -19.48400 1.000 91.28000 C ? A ? 212 0 + ATOM 1546 CG . MET A 212 ? 16.61400 -8.35100 -18.21400 1.000 91.28000 C ? A ? 212 0 + ATOM 1547 SD . MET A 212 ? 14.86600 -8.83200 -18.31400 1.000 91.28000 S ? A ? 212 0 + ATOM 1548 CE . MET A 212 ? 14.36800 -7.95600 -19.82200 1.000 91.28000 C ? A ? 212 0 + ATOM 1549 N . CYS A 213 ? 20.87400 -9.36300 -20.43600 1.000 84.27000 N ? A ? 213 0 + ATOM 1550 CA . CYS A 213 ? 21.75600 -9.73200 -21.54500 1.000 84.27000 C ? A ? 213 0 + ATOM 1551 C . CYS A 213 ? 21.15500 -10.81800 -22.45100 1.000 84.27000 C ? A ? 213 0 + ATOM 1552 O . CYS A 213 ? 21.28000 -10.72200 -23.66600 1.000 84.27000 O ? A ? 213 0 + ATOM 1553 CB . CYS A 213 ? 23.10800 -10.17800 -20.97400 1.000 84.27000 C ? A ? 213 0 + ATOM 1554 SG . CYS A 213 ? 23.86100 -8.82600 -20.01700 1.000 84.27000 S ? A ? 213 0 + ATOM 1555 N . ASP A 214 ? 20.43500 -11.79200 -21.88800 1.000 84.71000 N ? A ? 214 0 + ATOM 1556 CA . ASP A 214 ? 19.87700 -12.91700 -22.65600 1.000 84.71000 C ? A ? 214 0 + ATOM 1557 C . ASP A 214 ? 18.80500 -12.49500 -23.67500 1.000 84.71000 C ? A ? 214 0 + ATOM 1558 O . ASP A 214 ? 18.57800 -13.18300 -24.66700 1.000 84.71000 O ? A ? 214 0 + ATOM 1559 CB . ASP A 214 ? 19.26600 -13.94200 -21.68700 1.000 84.71000 C ? A ? 214 0 + ATOM 1560 CG . ASP A 214 ? 20.27400 -14.52100 -20.69200 1.000 84.71000 C ? A ? 214 0 + ATOM 1561 OD1 . ASP A 214 ? 21.46700 -14.62400 -21.05000 1.000 84.71000 O ? A ? 214 0 + ATOM 1562 OD2 . ASP A 214 ? 19.84100 -14.80600 -19.55500 1.000 84.71000 O ? A ? 214 0 + ATOM 1563 N . SER A 215 ? 18.13600 -11.36300 -23.43800 1.000 86.87000 N ? A ? 215 0 + ATOM 1564 CA . SER A 215 ? 17.03000 -10.86700 -24.27300 1.000 86.87000 C ? A ? 215 0 + ATOM 1565 C . SER A 215 ? 17.33300 -9.53800 -24.96700 1.000 86.87000 C ? A ? 215 0 + ATOM 1566 O . SER A 215 ? 16.43700 -8.95600 -25.58300 1.000 86.87000 O ? A ? 215 0 + ATOM 1567 CB . SER A 215 ? 15.73900 -10.78200 -23.45100 1.000 86.87000 C ? A ? 215 0 + ATOM 1568 OG . SER A 215 ? 15.88900 -9.88400 -22.36800 1.000 86.87000 O ? A ? 215 0 + ATOM 1569 N . ASN A 216 ? 18.57500 -9.04200 -24.85700 1.000 88.00000 N ? A ? 216 0 + ATOM 1570 CA . ASN A 216 ? 18.95900 -7.68400 -25.25900 1.000 88.00000 C ? A ? 216 0 + ATOM 1571 C . ASN A 216 ? 17.97200 -6.63300 -24.72000 1.000 88.00000 C ? A ? 216 0 + ATOM 1572 O . ASN A 216 ? 17.51600 -5.75300 -25.44400 1.000 88.00000 O ? A ? 216 0 + ATOM 1573 CB . ASN A 216 ? 19.15600 -7.62700 -26.78300 1.000 88.00000 C ? A ? 216 0 + ATOM 1574 CG . ASN A 216 ? 20.26100 -8.54900 -27.25100 1.000 88.00000 C ? A ? 216 0 + ATOM 1575 OD1 . ASN A 216 ? 21.29600 -8.69200 -26.62500 1.000 88.00000 O ? A ? 216 0 + ATOM 1576 ND2 . ASN A 216 ? 20.08900 -9.19900 -28.37700 1.000 88.00000 N ? A ? 216 0 + ATOM 1577 N . GLY A 217 ? 17.56900 -6.78700 -23.46000 1.000 92.79000 N ? A ? 217 0 + ATOM 1578 CA . GLY A 217 ? 16.48100 -6.02500 -22.86100 1.000 92.79000 C ? A ? 217 0 + ATOM 1579 C . GLY A 217 ? 16.86100 -5.34800 -21.55500 1.000 92.79000 C ? A ? 217 0 + ATOM 1580 O . GLY A 217 ? 18.01400 -5.37400 -21.11400 1.000 92.79000 O ? A ? 217 0 + ATOM 1581 N . MET A 218 ? 15.85200 -4.78900 -20.89500 1.000 94.65000 N ? A ? 218 0 + ATOM 1582 CA . MET A 218 ? 15.96000 -4.27600 -19.53400 1.000 94.65000 C ? A ? 218 0 + ATOM 1583 C . MET A 218 ? 14.81800 -4.76200 -18.64200 1.000 94.65000 C ? A ? 218 0 + ATOM 1584 O . MET A 218 ? 13.69000 -4.96900 -19.09100 1.000 94.65000 O ? A ? 218 0 + ATOM 1585 CB . MET A 218 ? 16.06400 -2.74700 -19.54000 1.000 94.65000 C ? A ? 218 0 + ATOM 1586 CG . MET A 218 ? 14.74200 -2.05200 -19.86100 1.000 94.65000 C ? A ? 218 0 + ATOM 1587 SD . MET A 218 ? 14.87600 -0.25500 -19.84100 1.000 94.65000 S ? A ? 218 0 + ATOM 1588 CE . MET A 218 ? 13.20600 0.09000 -20.41000 1.000 94.65000 C ? A ? 218 0 + ATOM 1589 N . MET A 219 ? 15.11400 -4.89900 -17.35600 1.000 95.36000 N ? A ? 219 0 + ATOM 1590 CA . MET A 219 ? 14.13700 -5.07600 -16.29400 1.000 95.36000 C ? A ? 219 0 + ATOM 1591 C . MET A 219 ? 14.08700 -3.79800 -15.46800 1.000 95.36000 C ? A ? 219 0 + ATOM 1592 O . MET A 219 ? 15.08800 -3.39000 -14.88200 1.000 95.36000 O ? A ? 219 0 + ATOM 1593 CB . MET A 219 ? 14.51300 -6.28700 -15.43600 1.000 95.36000 C ? A ? 219 0 + ATOM 1594 CG . MET A 219 ? 13.46700 -6.55200 -14.34800 1.000 95.36000 C ? A ? 219 0 + ATOM 1595 SD . MET A 219 ? 13.79300 -8.03000 -13.34900 1.000 95.36000 S ? A ? 219 0 + ATOM 1596 CE . MET A 219 ? 13.43100 -9.34000 -14.55200 1.000 95.36000 C ? A ? 219 0 + ATOM 1597 N . ALA A 220 ? 12.91400 -3.18700 -15.40500 1.000 96.83000 N ? A ? 220 0 + ATOM 1598 CA . ALA A 220 ? 12.65600 -2.04300 -14.55600 1.000 96.83000 C ? A ? 220 0 + ATOM 1599 C . ALA A 220 ? 11.90300 -2.47500 -13.29900 1.000 96.83000 C ? A ? 220 0 + ATOM 1600 O . ALA A 220 ? 11.01800 -3.33200 -13.35500 1.000 96.83000 O ? A ? 220 0 + ATOM 1601 CB . ALA A 220 ? 11.87300 -1.01800 -15.35900 1.000 96.83000 C ? A ? 220 0 + ATOM 1602 N . SER A 221 ? 12.23000 -1.85000 -12.17400 1.000 97.30000 N ? A ? 221 0 + ATOM 1603 CA . SER A 221 ? 11.52200 -2.00400 -10.90300 1.000 97.30000 C ? A ? 221 0 + ATOM 1604 C . SER A 221 ? 11.37600 -0.65400 -10.20900 1.000 97.30000 C ? A ? 221 0 + ATOM 1605 O . SER A 221 ? 12.17700 0.24600 -10.44700 1.000 97.30000 O ? A ? 221 0 + ATOM 1606 CB . SER A 221 ? 12.23200 -3.02700 -10.01500 1.000 97.30000 C ? A ? 221 0 + ATOM 1607 OG . SER A 221 ? 13.53700 -2.59800 -9.68500 1.000 97.30000 O ? A ? 221 0 + ATOM 1608 N . TRP A 222 ? 10.33700 -0.48300 -9.39600 1.000 96.10000 N ? A ? 222 0 + ATOM 1609 CA . TRP A 222 ? 10.02300 0.78900 -8.73400 1.000 96.10000 C ? A ? 222 0 + ATOM 1610 C . TRP A 222 ? 9.34200 0.56600 -7.38300 1.000 96.10000 C ? A ? 222 0 + ATOM 1611 O . TRP A 222 ? 8.81200 -0.50900 -7.09200 1.000 96.10000 O ? A ? 222 0 + ATOM 1612 CB . TRP A 222 ? 9.13800 1.64500 -9.65000 1.000 96.10000 C ? A ? 222 0 + ATOM 1613 CG . TRP A 222 ? 7.91600 0.94700 -10.16000 1.000 96.10000 C ? A ? 222 0 + ATOM 1614 CD1 . TRP A 222 ? 6.68900 0.95700 -9.59000 1.000 96.10000 C ? A ? 222 0 + ATOM 1615 CD2 . TRP A 222 ? 7.79800 0.11600 -11.35300 1.000 96.10000 C ? A ? 222 0 + ATOM 1616 NE1 . TRP A 222 ? 5.82700 0.17500 -10.33200 1.000 96.10000 N ? A ? 222 0 + ATOM 1617 CE2 . TRP A 222 ? 6.46000 -0.37300 -11.42300 1.000 96.10000 C ? A ? 222 0 + ATOM 1618 CE3 . TRP A 222 ? 8.67300 -0.23500 -12.40600 1.000 96.10000 C ? A ? 222 0 + ATOM 1619 CZ2 . TRP A 222 ? 6.01500 -1.18600 -12.46900 1.000 96.10000 C ? A ? 222 0 + ATOM 1620 CZ3 . TRP A 222 ? 8.22700 -1.03000 -13.47800 1.000 96.10000 C ? A ? 222 0 + ATOM 1621 CH2 . TRP A 222 ? 6.90000 -1.50000 -13.51000 1.000 96.10000 C ? A ? 222 0 + ATOM 1622 N . SER A 223 ? 9.32700 1.60300 -6.54600 1.000 95.88000 N ? A ? 223 0 + ATOM 1623 CA . SER A 223 ? 8.59100 1.56800 -5.27800 1.000 95.88000 C ? A ? 223 0 + ATOM 1624 C . SER A 223 ? 7.07100 1.56100 -5.51000 1.000 95.88000 C ? A ? 223 0 + ATOM 1625 O . SER A 223 ? 6.60300 2.23200 -6.43100 1.000 95.88000 O ? A ? 223 0 + ATOM 1626 CB . SER A 223 ? 8.97800 2.75300 -4.39800 1.000 95.88000 C ? A ? 223 0 + ATOM 1627 OG . SER A 223 ? 10.33800 2.61400 -4.03700 1.000 95.88000 O ? A ? 223 0 + ATOM 1628 N . PRO A 224 ? 6.28000 0.84000 -4.69300 1.000 93.58000 N ? A ? 224 0 + ATOM 1629 CA . PRO A 224 ? 4.82200 0.85700 -4.79800 1.000 93.58000 C ? A ? 224 0 + ATOM 1630 C . PRO A 224 ? 4.21700 2.24900 -4.63800 1.000 93.58000 C ? A ? 224 0 + ATOM 1631 O . PRO A 224 ? 4.50100 2.95100 -3.67000 1.000 93.58000 O ? A ? 224 0 + ATOM 1632 CB . PRO A 224 ? 4.30600 -0.12400 -3.73500 1.000 93.58000 C ? A ? 224 0 + ATOM 1633 CG . PRO A 224 ? 5.50600 -1.01100 -3.40200 1.000 93.58000 C ? A ? 224 0 + ATOM 1634 CD . PRO A 224 ? 6.71100 -0.11900 -3.68400 1.000 93.58000 C ? A ? 224 0 + ATOM 1635 N . SER A 225 ? 3.33200 2.61100 -5.56700 1.000 92.93000 N ? A ? 225 0 + ATOM 1636 CA . SER A 225 ? 2.43200 3.75200 -5.42700 1.000 92.93000 C ? A ? 225 0 + ATOM 1637 C . SER A 225 ? 1.14700 3.28900 -4.74400 1.000 92.93000 C ? A ? 225 0 + ATOM 1638 O . SER A 225 ? 0.48600 2.36600 -5.22200 1.000 92.93000 O ? A ? 225 0 + ATOM 1639 CB . SER A 225 ? 2.11100 4.37400 -6.79100 1.000 92.93000 C ? A ? 225 0 + ATOM 1640 OG . SER A 225 ? 3.25700 4.97600 -7.36200 1.000 92.93000 O ? A ? 225 0 + ATOM 1641 N . LEU A 226 ? 0.77400 3.93300 -3.63500 1.000 89.63000 N ? A ? 226 0 + ATOM 1642 CA . LEU A 226 ? -0.49900 3.66600 -2.96000 1.000 89.63000 C ? A ? 226 0 + ATOM 1643 C . LEU A 226 ? -1.67800 3.86900 -3.92400 1.000 89.63000 C ? A ? 226 0 + ATOM 1644 O . LEU A 226 ? -1.60200 4.69400 -4.83600 1.000 89.63000 O ? A ? 226 0 + ATOM 1645 CB . LEU A 226 ? -0.63900 4.55800 -1.71700 1.000 89.63000 C ? A ? 226 0 + ATOM 1646 CG . LEU A 226 ? 0.32500 4.22600 -0.56500 1.000 89.63000 C ? A ? 226 0 + ATOM 1647 CD1 . LEU A 226 ? 0.23400 5.30800 0.51000 1.000 89.63000 C ? A ? 226 0 + ATOM 1648 CD2 . LEU A 226 ? 0.00100 2.87400 0.07800 1.000 89.63000 C ? A ? 226 0 + ATOM 1649 N . VAL A 227 ? -2.73400 3.07400 -3.72400 1.000 90.07000 N ? A ? 227 0 + ATOM 1650 CA . VAL A 227 ? -3.95700 2.95500 -4.54500 1.000 90.07000 C ? A ? 227 0 + ATOM 1651 C . VAL A 227 ? -3.75900 2.58500 -6.02500 1.000 90.07000 C ? A ? 227 0 + ATOM 1652 O . VAL A 227 ? -4.74400 2.39400 -6.73200 1.000 90.07000 O ? A ? 227 0 + ATOM 1653 CB . VAL A 227 ? -4.93600 4.13900 -4.36100 1.000 90.07000 C ? A ? 227 0 + ATOM 1654 CG1 . VAL A 227 ? -5.16500 4.49600 -2.88600 1.000 90.07000 C ? A ? 227 0 + ATOM 1655 CG2 . VAL A 227 ? -4.55200 5.42000 -5.10300 1.000 90.07000 C ? A ? 227 0 + ATOM 1656 N . ALA A 228 ? -2.52500 2.43900 -6.52100 1.000 93.16000 N ? A ? 228 0 + ATOM 1657 CA . ALA A 228 ? -2.27300 2.03600 -7.90200 1.000 93.16000 C ? A ? 228 0 + ATOM 1658 C . ALA A 228 ? -2.71700 0.58700 -8.15400 1.000 93.16000 C ? A ? 228 0 + ATOM 1659 O . ALA A 228 ? -2.33300 -0.32500 -7.42500 1.000 93.16000 O ? A ? 228 0 + ATOM 1660 CB . ALA A 228 ? -0.78800 2.21400 -8.23000 1.000 93.16000 C ? A ? 228 0 + ATOM 1661 N . GLN A 229 ? -3.47700 0.37700 -9.22800 1.000 93.80000 N ? A ? 229 0 + ATOM 1662 CA . GLN A 229 ? -3.89900 -0.95000 -9.69000 1.000 93.80000 C ? A ? 229 0 + ATOM 1663 C . GLN A 229 ? -3.04200 -1.45300 -10.85600 1.000 93.80000 C ? A ? 229 0 + ATOM 1664 O . GLN A 229 ? -2.93600 -2.65500 -11.09400 1.000 93.80000 O ? A ? 229 0 + ATOM 1665 CB . GLN A 229 ? -5.35900 -0.87600 -10.14700 1.000 93.80000 C ? A ? 229 0 + ATOM 1666 CG . GLN A 229 ? -6.35700 -0.57400 -9.01800 1.000 93.80000 C ? A ? 229 0 + ATOM 1667 CD . GLN A 229 ? -7.78300 -0.46900 -9.55400 1.000 93.80000 C ? A ? 229 0 + ATOM 1668 OE1 . GLN A 229 ? -8.03300 -0.53100 -10.74700 1.000 93.80000 O ? A ? 229 0 + ATOM 1669 NE2 . GLN A 229 ? -8.77000 -0.27300 -8.71400 1.000 93.80000 N ? A ? 229 0 + ATOM 1670 N . SER A 230 ? -2.44900 -0.53100 -11.61500 1.000 96.03000 N ? A ? 230 0 + ATOM 1671 CA . SER A 230 ? -1.61200 -0.85200 -12.76500 1.000 96.03000 C ? A ? 230 0 + ATOM 1672 C . SER A 230 ? -0.55000 0.21500 -12.99300 1.000 96.03000 C ? A ? 230 0 + ATOM 1673 O . SER A 230 ? -0.68500 1.36000 -12.56000 1.000 96.03000 O ? A ? 230 0 + ATOM 1674 CB . SER A 230 ? -2.47500 -1.04000 -14.01800 1.000 96.03000 C ? A ? 230 0 + ATOM 1675 OG . SER A 230 ? -3.14600 0.15300 -14.37700 1.000 96.03000 O ? A ? 230 0 + ATOM 1676 N . TYR A 231 ? 0.50400 -0.17100 -13.69700 1.000 96.98000 N ? A ? 231 0 + ATOM 1677 CA . TYR A 231 ? 1.59600 0.69200 -14.10300 1.000 96.98000 C ? A ? 231 0 + ATOM 1678 C . TYR A 231 ? 1.81100 0.57900 -15.60900 1.000 96.98000 C ? A ? 231 0 + ATOM 1679 O . TYR A 231 ? 1.65200 -0.49900 -16.18900 1.000 96.98000 O ? A ? 231 0 + ATOM 1680 CB . TYR A 231 ? 2.87100 0.32500 -13.34200 1.000 96.98000 C ? A ? 231 0 + ATOM 1681 CG . TYR A 231 ? 2.76800 0.42800 -11.83100 1.000 96.98000 C ? A ? 231 0 + ATOM 1682 CD1 . TYR A 231 ? 3.12700 1.62100 -11.17300 1.000 96.98000 C ? A ? 231 0 + ATOM 1683 CD2 . TYR A 231 ? 2.31500 -0.67600 -11.08200 1.000 96.98000 C ? A ? 231 0 + ATOM 1684 CE1 . TYR A 231 ? 3.03100 1.70900 -9.76900 1.000 96.98000 C ? A ? 231 0 + ATOM 1685 CE2 . TYR A 231 ? 2.18700 -0.58100 -9.68400 1.000 96.98000 C ? A ? 231 0 + ATOM 1686 CZ . TYR A 231 ? 2.54300 0.61400 -9.02600 1.000 96.98000 C ? A ? 231 0 + ATOM 1687 OH . TYR A 231 ? 2.43200 0.70200 -7.67500 1.000 96.98000 O ? A ? 231 0 + ATOM 1688 N . LEU A 232 ? 2.20300 1.68700 -16.23300 1.000 96.86000 N ? A ? 232 0 + ATOM 1689 CA . LEU A 232 ? 2.61500 1.74000 -17.63200 1.000 96.86000 C ? A ? 232 0 + ATOM 1690 C . LEU A 232 ? 4.01500 2.33900 -17.70600 1.000 96.86000 C ? A ? 232 0 + ATOM 1691 O . LEU A 232 ? 4.20900 3.52500 -17.42500 1.000 96.86000 O ? A ? 232 0 + ATOM 1692 CB . LEU A 232 ? 1.58100 2.53600 -18.44500 1.000 96.86000 C ? A ? 232 0 + ATOM 1693 CG . LEU A 232 ? 1.97500 2.76500 -19.91700 1.000 96.86000 C ? A ? 232 0 + ATOM 1694 CD1 . LEU A 232 ? 1.92900 1.46800 -20.72400 1.000 96.86000 C ? A ? 232 0 + ATOM 1695 CD2 . LEU A 232 ? 1.00600 3.75500 -20.56100 1.000 96.86000 C ? A ? 232 0 + ATOM 1696 N . LEU A 233 ? 4.97300 1.50700 -18.09800 1.000 97.30000 N ? A ? 233 0 + ATOM 1697 CA . LEU A 233 ? 6.34200 1.90500 -18.38100 1.000 97.30000 C ? A ? 233 0 + ATOM 1698 C . LEU A 233 ? 6.47900 2.23100 -19.86600 1.000 97.30000 C ? A ? 233 0 + ATOM 1699 O . LEU A 233 ? 5.99400 1.47900 -20.70900 1.000 97.30000 O ? A ? 233 0 + ATOM 1700 CB . LEU A 233 ? 7.27400 0.78600 -17.90600 1.000 97.30000 C ? A ? 233 0 + ATOM 1701 CG . LEU A 233 ? 8.76300 1.14400 -18.05300 1.000 97.30000 C ? A ? 233 0 + ATOM 1702 CD1 . LEU A 233 ? 9.54600 0.46800 -16.94200 1.000 97.30000 C ? A ? 233 0 + ATOM 1703 CD2 . LEU A 233 ? 9.35000 0.65000 -19.37300 1.000 97.30000 C ? A ? 233 0 + ATOM 1704 N . THR A 234 ? 7.15000 3.33800 -20.17100 1.000 97.08000 N ? A ? 234 0 + ATOM 1705 CA . THR A 234 ? 7.45500 3.79200 -21.53200 1.000 97.08000 C ? A ? 234 0 + ATOM 1706 C . THR A 234 ? 8.95100 4.05000 -21.64600 1.000 97.08000 C ? A ? 234 0 + ATOM 1707 O . THR A 234 ? 9.50900 4.79300 -20.83800 1.000 97.08000 O ? A ? 234 0 + ATOM 1708 CB . THR A 234 ? 6.66800 5.06400 -21.87700 1.000 97.08000 C ? A ? 234 0 + ATOM 1709 OG1 . THR A 234 ? 5.29100 4.83000 -21.68400 1.000 97.08000 O ? A ? 234 0 + ATOM 1710 CG2 . THR A 234 ? 6.86400 5.50600 -23.32700 1.000 97.08000 C ? A ? 234 0 + ATOM 1711 N . ALA A 235 ? 9.58800 3.44200 -22.64100 1.000 96.74000 N ? A ? 235 0 + ATOM 1712 CA . ALA A 235 ? 10.98800 3.63400 -22.97900 1.000 96.74000 C ? A ? 235 0 + ATOM 1713 C . ALA A 235 ? 11.07700 4.18000 -24.40400 1.000 96.74000 C ? A ? 235 0 + ATOM 1714 O . ALA A 235 ? 10.59700 3.53700 -25.33300 1.000 96.74000 O ? A ? 235 0 + ATOM 1715 CB . ALA A 235 ? 11.71500 2.29600 -22.82300 1.000 96.74000 C ? A ? 235 0 + ATOM 1716 N . SER A 236 ? 11.67200 5.35600 -24.57200 1.000 96.76000 N ? A ? 236 0 + ATOM 1717 CA . SER A 236 ? 11.82700 6.00400 -25.87900 1.000 96.76000 C ? A ? 236 0 + ATOM 1718 C . SER A 236 ? 13.29200 6.28500 -26.16900 1.000 96.76000 C ? A ? 236 0 + ATOM 1719 O . SER A 236 ? 13.97900 6.82300 -25.29600 1.000 96.76000 O ? A ? 236 0 + ATOM 1720 CB . SER A 236 ? 11.03000 7.31000 -25.93000 1.000 96.76000 C ? A ? 236 0 + ATOM 1721 OG . SER A 236 ? 11.48000 8.19500 -24.91800 1.000 96.76000 O ? A ? 236 0 + ATOM 1722 N . SER A 237 ? 13.75500 5.98900 -27.37800 1.000 95.64000 N ? A ? 237 0 + ATOM 1723 CA . SER A 237 ? 15.11700 6.29000 -27.81300 1.000 95.64000 C ? A ? 237 0 + ATOM 1724 C . SER A 237 ? 15.16800 7.38700 -28.88300 1.000 95.64000 C ? A ? 237 0 + ATOM 1725 O . SER A 237 ? 14.16300 7.75300 -29.49200 1.000 95.64000 O ? A ? 237 0 + ATOM 1726 CB . SER A 237 ? 15.81500 5.01000 -28.25800 1.000 95.64000 C ? A ? 237 0 + ATOM 1727 OG . SER A 237 ? 17.18000 5.32300 -28.41200 1.000 95.64000 O ? A ? 237 0 + ATOM 1728 N . SER A 238 ? 16.35600 7.95900 -29.08700 1.000 93.34000 N ? A ? 238 0 + ATOM 1729 CA . SER A 238 ? 16.62200 9.01300 -30.07100 1.000 93.34000 C ? A ? 238 0 + ATOM 1730 C . SER A 238 ? 16.48700 8.55700 -31.52500 1.000 93.34000 C ? A ? 238 0 + ATOM 1731 O . SER A 238 ? 16.34700 9.40000 -32.40700 1.000 93.34000 O ? A ? 238 0 + ATOM 1732 CB . SER A 238 ? 18.03300 9.56900 -29.86100 1.000 93.34000 C ? A ? 238 0 + ATOM 1733 OG . SER A 238 ? 18.99800 8.54000 -29.70200 1.000 93.34000 O ? A ? 238 0 + ATOM 1734 N . ASP A 239 ? 16.53900 7.25100 -31.78300 1.000 92.94000 N ? A ? 239 0 + ATOM 1735 CA . ASP A 239 ? 16.32600 6.66400 -33.11000 1.000 92.94000 C ? A ? 239 0 + ATOM 1736 C . ASP A 239 ? 14.83600 6.55000 -33.49700 1.000 92.94000 C ? A ? 239 0 + ATOM 1737 O . ASP A 239 ? 14.51800 6.19100 -34.63000 1.000 92.94000 O ? A ? 239 0 + ATOM 1738 CB . ASP A 239 ? 17.04200 5.30600 -33.17800 1.000 92.94000 C ? A ? 239 0 + ATOM 1739 CG . ASP A 239 ? 16.41200 4.22300 -32.29600 1.000 92.94000 C ? A ? 239 0 + ATOM 1740 OD1 . ASP A 239 ? 15.51900 4.55800 -31.48700 1.000 92.94000 O ? A ? 239 0 + ATOM 1741 OD2 . ASP A 239 ? 16.83700 3.05800 -32.44500 1.000 92.94000 O ? A ? 239 0 + ATOM 1742 N . GLY A 240 ? 13.92900 6.89700 -32.57700 1.000 93.53000 N ? A ? 240 0 + ATOM 1743 CA . GLY A 240 ? 12.48100 6.83800 -32.75900 1.000 93.53000 C ? A ? 240 0 + ATOM 1744 C . GLY A 240 ? 11.82800 5.55900 -32.23400 1.000 93.53000 C ? A ? 240 0 + ATOM 1745 O . GLY A 240 ? 10.60300 5.45700 -32.31400 1.000 93.53000 O ? A ? 240 0 + ATOM 1746 N . ASP A 241 ? 12.59200 4.61100 -31.68000 1.000 94.68000 N ? A ? 241 0 + ATOM 1747 CA . ASP A 241 ? 12.01700 3.42000 -31.05900 1.000 94.68000 C ? A ? 241 0 + ATOM 1748 C . ASP A 241 ? 11.29000 3.77100 -29.75300 1.000 94.68000 C ? A ? 241 0 + ATOM 1749 O . ASP A 241 ? 11.80600 4.49800 -28.89500 1.000 94.68000 O ? A ? 241 0 + ATOM 1750 CB . ASP A 241 ? 13.08000 2.33100 -30.85800 1.000 94.68000 C ? A ? 241 0 + ATOM 1751 CG . ASP A 241 ? 12.43900 1.02800 -30.37500 1.000 94.68000 C ? A ? 241 0 + ATOM 1752 OD1 . ASP A 241 ? 11.34500 0.69300 -30.88500 1.000 94.68000 O ? A ? 241 0 + ATOM 1753 OD2 . ASP A 241 ? 13.00500 0.41600 -29.44000 1.000 94.68000 O ? A ? 241 0 + ATOM 1754 N . VAL A 242 ? 10.06500 3.26000 -29.60600 1.000 95.95000 N ? A ? 242 0 + ATOM 1755 CA . VAL A 242 ? 9.21400 3.48100 -28.43200 1.000 95.95000 C ? A ? 242 0 + ATOM 1756 C . VAL A 242 ? 8.58200 2.16600 -28.01500 1.000 95.95000 C ? A ? 242 0 + ATOM 1757 O . VAL A 242 ? 7.71300 1.61700 -28.69200 1.000 95.95000 O ? A ? 242 0 + ATOM 1758 CB . VAL A 242 ? 8.13300 4.55800 -28.65000 1.000 95.95000 C ? A ? 242 0 + ATOM 1759 CG1 . VAL A 242 ? 7.33400 4.79200 -27.35400 1.000 95.95000 C ? A ? 242 0 + ATOM 1760 CG2 . VAL A 242 ? 8.73400 5.90800 -29.05700 1.000 95.95000 C ? A ? 242 0 + ATOM 1761 N . LEU A 243 ? 8.97200 1.70100 -26.83500 1.000 95.53000 N ? A ? 243 0 + ATOM 1762 CA . LEU A 243 ? 8.50500 0.45800 -26.24700 1.000 95.53000 C ? A ? 243 0 + ATOM 1763 C . LEU A 243 ? 7.70300 0.75000 -24.98500 1.000 95.53000 C ? A ? 243 0 + ATOM 1764 O . LEU A 243 ? 8.04000 1.63100 -24.19100 1.000 95.53000 O ? A ? 243 0 + ATOM 1765 CB . LEU A 243 ? 9.71200 -0.44800 -25.98800 1.000 95.53000 C ? A ? 243 0 + ATOM 1766 CG . LEU A 243 ? 10.34600 -0.97800 -27.29000 1.000 95.53000 C ? A ? 243 0 + ATOM 1767 CD1 . LEU A 243 ? 11.76500 -1.42300 -26.99000 1.000 95.53000 C ? A ? 243 0 + ATOM 1768 CD2 . LEU A 243 ? 9.57000 -2.17000 -27.85000 1.000 95.53000 C ? A ? 243 0 + ATOM 1769 N . THR A 244 ? 6.63000 -0.01000 -24.78700 1.000 96.69000 N ? A ? 244 0 + ATOM 1770 CA . THR A 244 ? 5.77900 0.11800 -23.60200 1.000 96.69000 C ? A ? 244 0 + ATOM 1771 C . THR A 244 ? 5.49600 -1.23300 -22.98000 1.000 96.69000 C ? A ? 244 0 + ATOM 1772 O . THR A 244 ? 5.41500 -2.24800 -23.66900 1.000 96.69000 O ? A ? 244 0 + ATOM 1773 CB . THR A 244 ? 4.45900 0.85200 -23.87400 1.000 96.69000 C ? A ? 244 0 + ATOM 1774 OG1 . THR A 244 ? 3.66700 0.16800 -24.81500 1.000 96.69000 O ? A ? 244 0 + ATOM 1775 CG2 . THR A 244 ? 4.65400 2.27400 -24.38700 1.000 96.69000 C ? A ? 244 0 + ATOM 1776 N . CYS A 245 ? 5.33500 -1.25200 -21.66100 1.000 95.53000 N ? A ? 245 0 + ATOM 1777 CA . CYS A 245 ? 4.93400 -2.45200 -20.94400 1.000 95.53000 C ? A ? 245 0 + ATOM 1778 C . CYS A 245 ? 4.01700 -2.09900 -19.77600 1.000 95.53000 C ? A ? 245 0 + ATOM 1779 O . CYS A 245 ? 4.23900 -1.13900 -19.03300 1.000 95.53000 O ? A ? 245 0 + ATOM 1780 CB . CYS A 245 ? 6.17900 -3.25600 -20.57300 1.000 95.53000 C ? A ? 245 0 + ATOM 1781 SG . CYS A 245 ? 6.13900 -4.24100 -19.05900 1.000 95.53000 S ? A ? 245 0 + ATOM 1782 N . LYS A 246 ? 2.94000 -2.87800 -19.66200 1.000 96.04000 N ? A ? 246 0 + ATOM 1783 CA . LYS A 246 ? 1.92700 -2.75500 -18.61700 1.000 96.04000 C ? A ? 246 0 + ATOM 1784 C . LYS A 246 ? 2.15900 -3.82900 -17.57100 1.000 96.04000 C ? A ? 246 0 + ATOM 1785 O . LYS A 246 ? 2.36200 -4.98700 -17.92400 1.000 96.04000 O ? A ? 246 0 + ATOM 1786 CB . LYS A 246 ? 0.51400 -2.86400 -19.20600 1.000 96.04000 C ? A ? 246 0 + ATOM 1787 CG . LYS A 246 ? 0.15900 -1.63800 -20.05400 1.000 96.04000 C ? A ? 246 0 + ATOM 1788 CD . LYS A 246 ? -1.26700 -1.75000 -20.60400 1.000 96.04000 C ? A ? 246 0 + ATOM 1789 CE . LYS A 246 ? -1.59500 -0.50900 -21.44100 1.000 96.04000 C ? A ? 246 0 + ATOM 1790 NZ . LYS A 246 ? -2.98000 -0.55500 -21.97000 1.000 96.04000 N ? A ? 246 0 + ATOM 1791 N . SER A 247 ? 2.08200 -3.45200 -16.30200 1.000 95.41000 N ? A ? 247 0 + ATOM 1792 CA . SER A 247 ? 2.25200 -4.38200 -15.19000 1.000 95.41000 C ? A ? 247 0 + ATOM 1793 C . SER A 247 ? 1.28300 -4.07400 -14.05500 1.000 95.41000 C ? A ? 247 0 + ATOM 1794 O . SER A 247 ? 0.98200 -2.91300 -13.78600 1.000 95.41000 O ? A ? 247 0 + ATOM 1795 CB . SER A 247 ? 3.69600 -4.34000 -14.70000 1.000 95.41000 C ? A ? 247 0 + ATOM 1796 OG . SER A 247 ? 3.86800 -5.37800 -13.77200 1.000 95.41000 O ? A ? 247 0 + ATOM 1797 N . THR A 248 ? 0.78800 -5.11100 -13.38500 1.000 95.16000 N ? A ? 248 0 + ATOM 1798 CA . THR A 248 ? 0.04900 -4.99800 -12.11400 1.000 95.16000 C ? A ? 248 0 + ATOM 1799 C . THR A 248 ? 0.97300 -5.15200 -10.90500 1.000 95.16000 C ? A ? 248 0 + ATOM 1800 O . THR A 248 ? 0.53800 -4.99800 -9.76900 1.000 95.16000 O ? A ? 248 0 + ATOM 1801 CB . THR A 248 ? -1.07800 -6.03600 -12.04000 1.000 95.16000 C ? A ? 248 0 + ATOM 1802 OG1 . THR A 248 ? -0.54600 -7.33400 -12.19600 1.000 95.16000 O ? A ? 248 0 + ATOM 1803 CG2 . THR A 248 ? -2.11900 -5.82800 -13.14000 1.000 95.16000 C ? A ? 248 0 + ATOM 1804 N . THR A 249 ? 2.24700 -5.47300 -11.13900 1.000 94.79000 N ? A ? 249 0 + ATOM 1805 CA . THR A 249 ? 3.29700 -5.58600 -10.12600 1.000 94.79000 C ? A ? 249 0 + ATOM 1806 C . THR A 249 ? 4.27100 -4.41300 -10.23700 1.000 94.79000 C ? A ? 249 0 + ATOM 1807 O . THR A 249 ? 4.19300 -3.57300 -11.13000 1.000 94.79000 O ? A ? 249 0 + ATOM 1808 CB . THR A 249 ? 4.04200 -6.93200 -10.24500 1.000 94.79000 C ? A ? 249 0 + ATOM 1809 OG1 . THR A 249 ? 4.59500 -7.08400 -11.52900 1.000 94.79000 O ? A ? 249 0 + ATOM 1810 CG2 . THR A 249 ? 3.10600 -8.11900 -10.01400 1.000 94.79000 C ? A ? 249 0 + ATOM 1811 N . ASN A 250 ? 5.22300 -4.35700 -9.31100 1.000 95.13000 N ? A ? 250 0 + ATOM 1812 CA . ASN A 250 ? 6.23100 -3.30100 -9.18900 1.000 95.13000 C ? A ? 250 0 + ATOM 1813 C . ASN A 250 ? 7.44100 -3.46200 -10.11600 1.000 95.13000 C ? A ? 250 0 + ATOM 1814 O . ASN A 250 ? 8.51800 -2.92800 -9.84400 1.000 95.13000 O ? A ? 250 0 + ATOM 1815 CB . ASN A 250 ? 6.63800 -3.26600 -7.71700 1.000 95.13000 C ? A ? 250 0 + ATOM 1816 CG . ASN A 250 ? 5.47100 -2.78700 -6.90500 1.000 95.13000 C ? A ? 250 0 + ATOM 1817 OD1 . ASN A 250 ? 4.57200 -3.52500 -6.54500 1.000 95.13000 O ? A ? 250 0 + ATOM 1818 ND2 . ASN A 250 ? 5.41600 -1.50900 -6.68300 1.000 95.13000 N ? A ? 250 0 + ATOM 1819 N . ASN A 251 ? 7.29300 -4.26200 -11.16600 1.000 96.32000 N ? A ? 251 0 + ATOM 1820 CA . ASN A 251 ? 8.34300 -4.54800 -12.12200 1.000 96.32000 C ? A ? 251 0 + ATOM 1821 C . ASN A 251 ? 7.76600 -4.78600 -13.51500 1.000 96.32000 C ? A ? 251 0 + ATOM 1822 O . ASN A 251 ? 6.58700 -5.09800 -13.68700 1.000 96.32000 O ? A ? 251 0 + ATOM 1823 CB . ASN A 251 ? 9.20900 -5.71800 -11.61800 1.000 96.32000 C ? A ? 251 0 + ATOM 1824 CG . ASN A 251 ? 8.45900 -7.02300 -11.38500 1.000 96.32000 C ? A ? 251 0 + ATOM 1825 OD1 . ASN A 251 ? 7.35600 -7.26800 -11.84100 1.000 96.32000 O ? A ? 251 0 + ATOM 1826 ND2 . ASN A 251 ? 9.03300 -7.92400 -10.62700 1.000 96.32000 N ? A ? 251 0 + ATOM 1827 N . CYS A 252 ? 8.61100 -4.59900 -14.51900 1.000 96.24000 N ? A ? 252 0 + ATOM 1828 CA . CYS A 252 ? 8.26300 -4.78100 -15.91700 1.000 96.24000 C ? A ? 252 0 + ATOM 1829 C . CYS A 252 ? 9.53600 -5.03900 -16.72700 1.000 96.24000 C ? A ? 252 0 + ATOM 1830 O . CYS A 252 ? 10.58700 -4.45200 -16.46400 1.000 96.24000 O ? A ? 252 0 + ATOM 1831 CB . CYS A 252 ? 7.52500 -3.52400 -16.38100 1.000 96.24000 C ? A ? 252 0 + ATOM 1832 SG . CYS A 252 ? 7.58200 -3.19100 -18.13700 1.000 96.24000 S ? A ? 252 0 + ATOM 1833 N . THR A 253 ? 9.43800 -5.92200 -17.71400 1.000 95.25000 N ? A ? 253 0 + ATOM 1834 CA . THR A 253 ? 10.53500 -6.29300 -18.60600 1.000 95.25000 C ? A ? 253 0 + ATOM 1835 C . THR A 253 ? 10.25900 -5.79200 -20.01900 1.000 95.25000 C ? A ? 253 0 + ATOM 1836 O . THR A 253 ? 9.17900 -6.00400 -20.56500 1.000 95.25000 O ? A ? 253 0 + ATOM 1837 CB . THR A 253 ? 10.76000 -7.81100 -18.58700 1.000 95.25000 C ? A ? 253 0 + ATOM 1838 OG1 . THR A 253 ? 9.54900 -8.52000 -18.70700 1.000 95.25000 O ? A ? 253 0 + ATOM 1839 CG2 . THR A 253 ? 11.39100 -8.25100 -17.26700 1.000 95.25000 C ? A ? 253 0 + ATOM 1840 N . LEU A 254 ? 11.25100 -5.13400 -20.62000 1.000 94.89000 N ? A ? 254 0 + ATOM 1841 CA . LEU A 254 ? 11.23700 -4.72900 -22.02400 1.000 94.89000 C ? A ? 254 0 + ATOM 1842 C . LEU A 254 ? 12.36600 -5.45600 -22.76700 1.000 94.89000 C ? A ? 254 0 + ATOM 1843 O . LEU A 254 ? 13.53400 -5.12300 -22.55400 1.000 94.89000 O ? A ? 254 0 + ATOM 1844 CB . LEU A 254 ? 11.34900 -3.19900 -22.14900 1.000 94.89000 C ? A ? 254 0 + ATOM 1845 CG . LEU A 254 ? 10.04100 -2.43800 -21.85800 1.000 94.89000 C ? A ? 254 0 + ATOM 1846 CD1 . LEU A 254 ? 10.25400 -0.94800 -22.10700 1.000 94.89000 C ? A ? 254 0 + ATOM 1847 CD2 . LEU A 254 ? 8.89300 -2.87100 -22.77000 1.000 94.89000 C ? A ? 254 0 + ATOM 1848 N . PRO A 255 ? 12.05100 -6.47900 -23.57900 1.000 93.40000 N ? A ? 255 0 + ATOM 1849 CA . PRO A 255 ? 13.03600 -7.18300 -24.39600 1.000 93.40000 C ? A ? 255 0 + ATOM 1850 C . PRO A 255 ? 13.34200 -6.42600 -25.70000 1.000 93.40000 C ? A ? 255 0 + ATOM 1851 O . PRO A 255 ? 12.61600 -5.50300 -26.06500 1.000 93.40000 O ? A ? 255 0 + ATOM 1852 CB . PRO A 255 ? 12.39400 -8.54900 -24.64700 1.000 93.40000 C ? A ? 255 0 + ATOM 1853 CG . PRO A 255 ? 10.90600 -8.21300 -24.75900 1.000 93.40000 C ? A ? 255 0 + ATOM 1854 CD . PRO A 255 ? 10.72900 -7.07400 -23.75700 1.000 93.40000 C ? A ? 255 0 + ATOM 1855 N . HIS A 256 ? 14.37100 -6.87300 -26.42900 1.000 91.17000 N ? A ? 256 0 + ATOM 1856 CA . HIS A 256 ? 14.66700 -6.45100 -27.80800 1.000 91.17000 C ? A ? 256 0 + ATOM 1857 C . HIS A 256 ? 14.91900 -4.94600 -28.00400 1.000 91.17000 C ? A ? 256 0 + ATOM 1858 O . HIS A 256 ? 14.51400 -4.37500 -29.01300 1.000 91.17000 O ? A ? 256 0 + ATOM 1859 CB . HIS A 256 ? 13.60200 -6.99600 -28.77800 1.000 91.17000 C ? A ? 256 0 + ATOM 1860 CG . HIS A 256 ? 13.35300 -8.47300 -28.64600 1.000 91.17000 C ? A ? 256 0 + ATOM 1861 ND1 . HIS A 256 ? 14.27300 -9.47100 -28.86000 1.000 91.17000 N ? A ? 256 0 + ATOM 1862 CD2 . HIS A 256 ? 12.18200 -9.07300 -28.27400 1.000 91.17000 C ? A ? 256 0 + ATOM 1863 CE1 . HIS A 256 ? 13.67300 -10.64600 -28.61700 1.000 91.17000 C ? A ? 256 0 + ATOM 1864 NE2 . HIS A 256 ? 12.39600 -10.45600 -28.25000 1.000 91.17000 N ? A ? 256 0 + ATOM 1865 N . LEU A 257 ? 15.62300 -4.31400 -27.06600 1.000 94.11000 N ? A ? 257 0 + ATOM 1866 CA . LEU A 257 ? 16.08400 -2.93700 -27.22700 1.000 94.11000 C ? A ? 257 0 + ATOM 1867 C . LEU A 257 ? 17.15400 -2.86400 -28.32600 1.000 94.11000 C ? A ? 257 0 + ATOM 1868 O . LEU A 257 ? 18.01100 -3.74800 -28.43800 1.000 94.11000 O ? A ? 257 0 + ATOM 1869 CB . LEU A 257 ? 16.63200 -2.41000 -25.88700 1.000 94.11000 C ? A ? 257 0 + ATOM 1870 CG . LEU A 257 ? 15.61800 -2.38400 -24.72900 1.000 94.11000 C ? A ? 257 0 + ATOM 1871 CD1 . LEU A 257 ? 16.33500 -2.06500 -23.42000 1.000 94.11000 C ? A ? 257 0 + ATOM 1872 CD2 . LEU A 257 ? 14.55300 -1.31400 -24.92500 1.000 94.11000 C ? A ? 257 0 + ATOM 1873 N . HIS A 258 ? 17.13800 -1.79500 -29.12000 1.000 93.99000 N ? A ? 258 0 + ATOM 1874 CA . HIS A 258 ? 18.17000 -1.53800 -30.11800 1.000 93.99000 C ? A ? 258 0 + ATOM 1875 C . HIS A 258 ? 19.52900 -1.31700 -29.44800 1.000 93.99000 C ? A ? 258 0 + ATOM 1876 O . HIS A 258 ? 19.65300 -0.56800 -28.48200 1.000 93.99000 O ? A ? 258 0 + ATOM 1877 CB . HIS A 258 ? 17.78400 -0.33100 -30.97500 1.000 93.99000 C ? A ? 258 0 + ATOM 1878 CG . HIS A 258 ? 16.62200 -0.54800 -31.91100 1.000 93.99000 C ? A ? 258 0 + ATOM 1879 ND1 . HIS A 258 ? 16.01500 0.44600 -32.63500 1.000 93.99000 N ? A ? 258 0 + ATOM 1880 CD2 . HIS A 258 ? 15.98500 -1.71900 -32.23000 1.000 93.99000 C ? A ? 258 0 + ATOM 1881 CE1 . HIS A 258 ? 15.03800 -0.10500 -33.36800 1.000 93.99000 C ? A ? 258 0 + ATOM 1882 NE2 . HIS A 258 ? 15.00200 -1.43500 -33.18400 1.000 93.99000 N ? A ? 258 0 + ATOM 1883 N . CYS A 259 ? 20.56500 -1.96800 -29.97200 1.000 92.06000 N ? A ? 259 0 + ATOM 1884 CA . CYS A 259 ? 21.92600 -1.82900 -29.46800 1.000 92.06000 C ? A ? 259 0 + ATOM 1885 C . CYS A 259 ? 22.48900 -0.41800 -29.71300 1.000 92.06000 C ? A ? 259 0 + ATOM 1886 O . CYS A 259 ? 22.09000 0.28100 -30.64500 1.000 92.06000 O ? A ? 259 0 + ATOM 1887 CB . CYS A 259 ? 22.79300 -2.91700 -30.10900 1.000 92.06000 C ? A ? 259 0 + ATOM 1888 SG . CYS A 259 ? 22.86700 -2.86300 -31.92800 1.000 92.06000 S ? A ? 259 0 + ATOM 1889 N . GLY A 260 ? 23.44900 0.00300 -28.88900 1.000 91.36000 N ? A ? 260 0 + ATOM 1890 CA . GLY A 260 ? 24.13500 1.29300 -29.01400 1.000 91.36000 C ? A ? 260 0 + ATOM 1891 C . GLY A 260 ? 23.25500 2.52200 -28.76300 1.000 91.36000 C ? A ? 260 0 + ATOM 1892 O . GLY A 260 ? 23.72100 3.64400 -28.95100 1.000 91.36000 O ? A ? 260 0 + ATOM 1893 N . GLN A 261 ? 22.01100 2.32500 -28.33300 1.000 94.17000 N ? A ? 261 0 + ATOM 1894 CA . GLN A 261 ? 21.04300 3.37700 -28.06000 1.000 94.17000 C ? A ? 261 0 + ATOM 1895 C . GLN A 261 ? 20.94500 3.71900 -26.57100 1.000 94.17000 C ? A ? 261 0 + ATOM 1896 O . GLN A 261 ? 21.19900 2.88800 -25.68800 1.000 94.17000 O ? A ? 261 0 + ATOM 1897 CB . GLN A 261 ? 19.66800 2.96000 -28.59700 1.000 94.17000 C ? A ? 261 0 + ATOM 1898 CG . GLN A 261 ? 19.58000 2.80500 -30.12100 1.000 94.17000 C ? A ? 261 0 + ATOM 1899 CD . GLN A 261 ? 20.15900 3.97800 -30.90600 1.000 94.17000 C ? A ? 261 0 + ATOM 1900 OE1 . GLN A 261 ? 20.00400 5.14900 -30.58300 1.000 94.17000 O ? A ? 261 0 + ATOM 1901 NE2 . GLN A 261 ? 20.91200 3.70400 -31.94900 1.000 94.17000 N ? A ? 261 0 + ATOM 1902 N . VAL A 262 ? 20.51000 4.94900 -26.29900 1.000 95.71000 N ? A ? 262 0 + ATOM 1903 CA . VAL A 262 ? 20.08100 5.39500 -24.96900 1.000 95.71000 C ? A ? 262 0 + ATOM 1904 C . VAL A 262 ? 18.56100 5.48300 -24.96700 1.000 95.71000 C ? A ? 262 0 + ATOM 1905 O . VAL A 262 ? 17.97800 6.14300 -25.82700 1.000 95.71000 O ? A ? 262 0 + ATOM 1906 CB . VAL A 262 ? 20.73200 6.73200 -24.56900 1.000 95.71000 C ? A ? 262 0 + ATOM 1907 CG1 . VAL A 262 ? 20.38300 7.10100 -23.11900 1.000 95.71000 C ? A ? 262 0 + ATOM 1908 CG2 . VAL A 262 ? 22.26100 6.64600 -24.68300 1.000 95.71000 C ? A ? 262 0 + ATOM 1909 N . TYR A 263 ? 17.92300 4.80900 -24.01500 1.000 96.24000 N ? A ? 263 0 + ATOM 1910 CA . TYR A 263 ? 16.47800 4.86100 -23.81100 1.000 96.24000 C ? A ? 263 0 + ATOM 1911 C . TYR A 263 ? 16.15400 5.73700 -22.60400 1.000 96.24000 C ? A ? 263 0 + ATOM 1912 O . TYR A 263 ? 16.67400 5.51600 -21.51000 1.000 96.24000 O ? A ? 263 0 + ATOM 1913 CB . TYR A 263 ? 15.90200 3.44800 -23.64500 1.000 96.24000 C ? A ? 263 0 + ATOM 1914 CG . TYR A 263 ? 15.76600 2.67800 -24.94400 1.000 96.24000 C ? A ? 263 0 + ATOM 1915 CD1 . TYR A 263 ? 14.51400 2.58800 -25.58700 1.000 96.24000 C ? A ? 263 0 + ATOM 1916 CD2 . TYR A 263 ? 16.89200 2.05700 -25.51700 1.000 96.24000 C ? A ? 263 0 + ATOM 1917 CE1 . TYR A 263 ? 14.38100 1.85400 -26.78100 1.000 96.24000 C ? A ? 263 0 + ATOM 1918 CE2 . TYR A 263 ? 16.76000 1.32600 -26.71500 1.000 96.24000 C ? A ? 263 0 + ATOM 1919 CZ . TYR A 263 ? 15.50300 1.20900 -27.34100 1.000 96.24000 C ? A ? 263 0 + ATOM 1920 OH . TYR A 263 ? 15.38500 0.45100 -28.45900 1.000 96.24000 O ? A ? 263 0 + ATOM 1921 N . ASN A 264 ? 15.25300 6.69600 -22.79000 1.000 96.81000 N ? A ? 264 0 + ATOM 1922 CA . ASN A 264 ? 14.66600 7.47800 -21.71000 1.000 96.81000 C ? A ? 264 0 + ATOM 1923 C . ASN A 264 ? 13.45900 6.71300 -21.17500 1.000 96.81000 C ? A ? 264 0 + ATOM 1924 O . ASN A 264 ? 12.46800 6.53000 -21.88700 1.000 96.81000 O ? A ? 264 0 + ATOM 1925 CB . ASN A 264 ? 14.27300 8.86900 -22.22500 1.000 96.81000 C ? A ? 264 0 + ATOM 1926 CG . ASN A 264 ? 15.46300 9.68900 -22.68500 1.000 96.81000 C ? A ? 264 0 + ATOM 1927 OD1 . ASN A 264 ? 16.60800 9.45000 -22.35000 1.000 96.81000 O ? A ? 264 0 + ATOM 1928 ND2 . ASN A 264 ? 15.22700 10.69500 -23.49100 1.000 96.81000 N ? A ? 264 0 + ATOM 1929 N . VAL A 265 ? 13.55000 6.25200 -19.93100 1.000 96.86000 N ? A ? 265 0 + ATOM 1930 CA . VAL A 265 ? 12.52900 5.40800 -19.31100 1.000 96.86000 C ? A ? 265 0 + ATOM 1931 C . VAL A 265 ? 11.70800 6.22900 -18.33500 1.000 96.86000 C ? A ? 265 0 + ATOM 1932 O . VAL A 265 ? 12.25100 6.91100 -17.46800 1.000 96.86000 O ? A ? 265 0 + ATOM 1933 CB . VAL A 265 ? 13.14500 4.17400 -18.63700 1.000 96.86000 C ? A ? 265 0 + ATOM 1934 CG1 . VAL A 265 ? 12.04300 3.20200 -18.19800 1.000 96.86000 C ? A ? 265 0 + ATOM 1935 CG2 . VAL A 265 ? 14.08500 3.45200 -19.61000 1.000 96.86000 C ? A ? 265 0 + ATOM 1936 N . SER A 266 ? 10.38900 6.14800 -18.46100 1.000 97.12000 N ? A ? 266 0 + ATOM 1937 CA . SER A 266 ? 9.43600 6.78800 -17.55800 1.000 97.12000 C ? A ? 266 0 + ATOM 1938 C . SER A 266 ? 8.30500 5.83400 -17.21300 1.000 97.12000 C ? A ? 266 0 + ATOM 1939 O . SER A 266 ? 8.00300 4.90200 -17.96300 1.000 97.12000 O ? A ? 266 0 + ATOM 1940 CB . SER A 266 ? 8.89300 8.08100 -18.16900 1.000 97.12000 C ? A ? 266 0 + ATOM 1941 OG . SER A 266 ? 8.15400 7.81600 -19.34500 1.000 97.12000 O ? A ? 266 0 + ATOM 1942 N . ILE A 267 ? 7.67500 6.05600 -16.06400 1.000 96.80000 N ? A ? 267 0 + ATOM 1943 CA . ILE A 267 ? 6.57400 5.22100 -15.60300 1.000 96.80000 C ? A ? 267 0 + ATOM 1944 C . ILE A 267 ? 5.42400 6.05100 -15.04700 1.000 96.80000 C ? A ? 267 0 + ATOM 1945 O . ILE A 267 ? 5.62500 7.07600 -14.39800 1.000 96.80000 O ? A ? 267 0 + ATOM 1946 CB . ILE A 267 ? 7.09800 4.15600 -14.62700 1.000 96.80000 C ? A ? 267 0 + ATOM 1947 CG1 . ILE A 267 ? 5.97400 3.15700 -14.31800 1.000 96.80000 C ? A ? 267 0 + ATOM 1948 CG2 . ILE A 267 ? 7.72800 4.77100 -13.36800 1.000 96.80000 C ? A ? 267 0 + ATOM 1949 CD1 . ILE A 267 ? 6.51700 1.93500 -13.61000 1.000 96.80000 C ? A ? 267 0 + ATOM 1950 N . THR A 268 ? 4.20600 5.58400 -15.29800 1.000 96.43000 N ? A ? 268 0 + ATOM 1951 CA . THR A 268 ? 2.96600 6.13000 -14.73900 1.000 96.43000 C ? A ? 268 0 + ATOM 1952 C . THR A 268 ? 2.24200 5.05300 -13.93600 1.000 96.43000 C ? A ? 268 0 + ATOM 1953 O . THR A 268 ? 2.32200 3.86800 -14.26400 1.000 96.43000 O ? A ? 268 0 + ATOM 1954 CB . THR A 268 ? 2.05000 6.68300 -15.83900 1.000 96.43000 C ? A ? 268 0 + ATOM 1955 OG1 . THR A 268 ? 1.78800 5.69800 -16.80800 1.000 96.43000 O ? A ? 268 0 + ATOM 1956 CG2 . THR A 268 ? 2.65000 7.88100 -16.56900 1.000 96.43000 C ? A ? 268 0 + ATOM 1957 N . ALA A 269 ? 1.54000 5.45600 -12.87800 1.000 96.37000 N ? A ? 269 0 + ATOM 1958 CA . ALA A 269 ? 0.66300 4.59800 -12.08900 1.000 96.37000 C ? A ? 269 0 + ATOM 1959 C . ALA A 269 ? -0.79700 4.96700 -12.35800 1.000 96.37000 C ? A ? 269 0 + ATOM 1960 O . ALA A 269 ? -1.12800 6.14600 -12.43600 1.000 96.37000 O ? A ? 269 0 + ATOM 1961 CB . ALA A 269 ? 1.01400 4.75300 -10.60900 1.000 96.37000 C ? A ? 269 0 + ATOM 1962 N . SER A 270 ? -1.67700 3.97700 -12.48100 1.000 94.66000 N ? A ? 270 0 + ATOM 1963 CA . SER A 270 ? -3.09900 4.19600 -12.75400 1.000 94.66000 C ? A ? 270 0 + ATOM 1964 C . SER A 270 ? -3.99800 3.47400 -11.75400 1.000 94.66000 C ? A ? 270 0 + ATOM 1965 O . SER A 270 ? -3.71700 2.34700 -11.33700 1.000 94.66000 O ? A ? 270 0 + ATOM 1966 CB . SER A 270 ? -3.45600 3.81300 -14.19400 1.000 94.66000 C ? A ? 270 0 + ATOM 1967 OG . SER A 270 ? -2.68700 4.57100 -15.11200 1.000 94.66000 O ? A ? 270 0 + ATOM 1968 N . ASN A 271 ? -5.09300 4.13500 -11.38500 1.000 91.37000 N ? A ? 271 0 + ATOM 1969 CA . ASN A 271 ? -6.18800 3.59700 -10.58300 1.000 91.37000 C ? A ? 271 0 + ATOM 1970 C . ASN A 271 ? -7.51500 4.01700 -11.22300 1.000 91.37000 C ? A ? 271 0 + ATOM 1971 O . ASN A 271 ? -7.79400 5.21500 -11.32900 1.000 91.37000 O ? A ? 271 0 + ATOM 1972 CB . ASN A 271 ? -6.07200 4.12000 -9.14300 1.000 91.37000 C ? A ? 271 0 + ATOM 1973 CG . ASN A 271 ? -7.14200 3.56000 -8.22100 1.000 91.37000 C ? A ? 271 0 + ATOM 1974 OD1 . ASN A 271 ? -7.86800 2.63900 -8.55500 1.000 91.37000 O ? A ? 271 0 + ATOM 1975 ND2 . ASN A 271 ? -7.28800 4.11000 -7.04000 1.000 91.37000 N ? A ? 271 0 + ATOM 1976 N . ASN A 272 ? -8.32400 3.04500 -11.65100 1.000 84.72000 N ? A ? 272 0 + ATOM 1977 CA . ASN A 272 ? -9.56200 3.28100 -12.39600 1.000 84.72000 C ? A ? 272 0 + ATOM 1978 C . ASN A 272 ? -9.33200 4.22800 -13.59600 1.000 84.72000 C ? A ? 272 0 + ATOM 1979 O . ASN A 272 ? -8.58500 3.88900 -14.51200 1.000 84.72000 O ? A ? 272 0 + ATOM 1980 CB . ASN A 272 ? -10.66500 3.72600 -11.41000 1.000 84.72000 C ? A ? 272 0 + ATOM 1981 CG . ASN A 272 ? -10.92700 2.71500 -10.30800 1.000 84.72000 C ? A ? 272 0 + ATOM 1982 OD1 . ASN A 272 ? -10.88700 1.51100 -10.49600 1.000 84.72000 O ? A ? 272 0 + ATOM 1983 ND2 . ASN A 272 ? -11.23600 3.17500 -9.11900 1.000 84.72000 N ? A ? 272 0 + ATOM 1984 N . ASN A 273 ? -9.93500 5.42100 -13.57400 1.000 84.69000 N ? A ? 273 0 + ATOM 1985 CA . ASN A 273 ? -9.85000 6.41600 -14.64700 1.000 84.69000 C ? A ? 273 0 + ATOM 1986 C . ASN A 273 ? -8.75600 7.47500 -14.42800 1.000 84.69000 C ? A ? 273 0 + ATOM 1987 O . ASN A 273 ? -8.64400 8.39500 -15.23500 1.000 84.69000 O ? A ? 273 0 + ATOM 1988 CB . ASN A 273 ? -11.23300 7.06600 -14.83700 1.000 84.69000 C ? A ? 273 0 + ATOM 1989 CG . ASN A 273 ? -12.27800 6.12600 -15.40700 1.000 84.69000 C ? A ? 273 0 + ATOM 1990 OD1 . ASN A 273 ? -12.04200 4.97700 -15.73400 1.000 84.69000 O ? A ? 273 0 + ATOM 1991 ND2 . ASN A 273 ? -13.49500 6.59600 -15.54800 1.000 84.69000 N ? A ? 273 0 + ATOM 1992 N . CYS A 274 ? -7.96800 7.37600 -13.35300 1.000 90.30000 N ? A ? 274 0 + ATOM 1993 CA . CYS A 274 ? -6.92200 8.34400 -13.04700 1.000 90.30000 C ? A ? 274 0 + ATOM 1994 C . CYS A 274 ? -5.52000 7.77100 -13.21900 1.000 90.30000 C ? A ? 274 0 + ATOM 1995 O . CYS A 274 ? -5.19900 6.70500 -12.69200 1.000 90.30000 O ? A ? 274 0 + ATOM 1996 CB . CYS A 274 ? -7.12500 8.92300 -11.64400 1.000 90.30000 C ? A ? 274 0 + ATOM 1997 SG . CYS A 274 ? -8.40100 10.20200 -11.53700 1.000 90.30000 S ? A ? 274 0 + ATOM 1998 N . THR A 275 ? -4.66400 8.54100 -13.89100 1.000 92.72000 N ? A ? 275 0 + ATOM 1999 CA . THR A 275 ? -3.25600 8.21600 -14.13900 1.000 92.72000 C ? A ? 275 0 + ATOM 2000 C . THR A 275 ? -2.36500 9.30000 -13.54800 1.000 92.72000 C ? A ? 275 0 + ATOM 2001 O . THR A 275 ? -2.59200 10.48900 -13.76600 1.000 92.72000 O ? A ? 275 0 + ATOM 2002 CB . THR A 275 ? -2.99400 8.04200 -15.64300 1.000 92.72000 C ? A ? 275 0 + ATOM 2003 OG1 . THR A 275 ? -3.80900 7.01100 -16.14900 1.000 92.72000 O ? A ? 275 0 + ATOM 2004 CG2 . THR A 275 ? -1.55400 7.65600 -15.96700 1.000 92.72000 C ? A ? 275 0 + ATOM 2005 N . SER A 276 ? -1.33700 8.90000 -12.80400 1.000 93.75000 N ? A ? 276 0 + ATOM 2006 CA . SER A 276 ? -0.33800 9.81100 -12.25500 1.000 93.75000 C ? A ? 276 0 + ATOM 2007 C . SER A 276 ? 0.41600 10.53500 -13.37600 1.000 93.75000 C ? A ? 276 0 + ATOM 2008 O . SER A 276 ? 0.53400 10.00800 -14.48600 1.000 93.75000 O ? A ? 276 0 + ATOM 2009 CB . SER A 276 ? 0.65300 9.04600 -11.36200 1.000 93.75000 C ? A ? 276 0 + ATOM 2010 OG . SER A 276 ? 1.61100 8.31100 -12.11300 1.000 93.75000 O ? A ? 276 0 + ATOM 2011 N . PRO A 277 ? 1.03400 11.69300 -13.09700 1.000 93.06000 N ? A ? 277 0 + ATOM 2012 CA . PRO A 277 ? 2.09800 12.19700 -13.95600 1.000 93.06000 C ? A ? 277 0 + ATOM 2013 C . PRO A 277 ? 3.20400 11.14200 -14.13700 1.000 93.06000 C ? A ? 277 0 + ATOM 2014 O . PRO A 277 ? 3.34400 10.22000 -13.32100 1.000 93.06000 O ? A ? 277 0 + ATOM 2015 CB . PRO A 277 ? 2.60800 13.47300 -13.27700 1.000 93.06000 C ? A ? 277 0 + ATOM 2016 CG . PRO A 277 ? 1.44600 13.89400 -12.37400 1.000 93.06000 C ? A ? 277 0 + ATOM 2017 CD . PRO A 277 ? 0.83900 12.56000 -11.94700 1.000 93.06000 C ? A ? 277 0 + ATOM 2018 N . ALA A 278 ? 3.98400 11.26900 -15.20900 1.000 94.53000 N ? A ? 278 0 + ATOM 2019 CA . ALA A 278 ? 5.13100 10.40000 -15.44300 1.000 94.53000 C ? A ? 278 0 + ATOM 2020 C . ALA A 278 ? 6.23200 10.64600 -14.40000 1.000 94.53000 C ? A ? 278 0 + ATOM 2021 O . ALA A 278 ? 6.42800 11.77300 -13.93800 1.000 94.53000 O ? A ? 278 0 + ATOM 2022 CB . ALA A 278 ? 5.62900 10.60100 -16.87900 1.000 94.53000 C ? A ? 278 0 + ATOM 2023 N . SER A 279 ? 6.96000 9.58700 -14.04100 1.000 95.98000 N ? A ? 279 0 + ATOM 2024 CA . SER A 279 ? 8.16700 9.68700 -13.22000 1.000 95.98000 C ? A ? 279 0 + ATOM 2025 C . SER A 279 ? 9.22700 10.57000 -13.87600 1.000 95.98000 C ? A ? 279 0 + ATOM 2026 O . SER A 279 ? 9.20400 10.81300 -15.08600 1.000 95.98000 O ? A ? 279 0 + ATOM 2027 CB . SER A 279 ? 8.73600 8.29400 -12.92300 1.000 95.98000 C ? A ? 279 0 + ATOM 2028 OG . SER A 279 ? 9.32200 7.72900 -14.08600 1.000 95.98000 O ? A ? 279 0 + ATOM 2029 N . GLN A 280 ? 10.21800 10.98600 -13.08400 1.000 93.93000 N ? A ? 280 0 + ATOM 2030 CA . GLN A 280 ? 11.45900 11.49800 -13.65700 1.000 93.93000 C ? A ? 280 0 + ATOM 2031 C . GLN A 280 ? 12.03900 10.45800 -14.62200 1.000 93.93000 C ? A ? 280 0 + ATOM 2032 O . GLN A 280 ? 11.97000 9.25100 -14.35900 1.000 93.93000 O ? A ? 280 0 + ATOM 2033 CB . GLN A 280 ? 12.46800 11.85400 -12.55900 1.000 93.93000 C ? A ? 280 0 + ATOM 2034 CG . GLN A 280 ? 12.01300 13.08300 -11.75700 1.000 93.93000 C ? A ? 280 0 + ATOM 2035 CD . GLN A 280 ? 13.06300 13.56500 -10.76000 1.000 93.93000 C ? A ? 280 0 + ATOM 2036 OE1 . GLN A 280 ? 13.99200 12.87300 -10.38700 1.000 93.93000 O ? A ? 280 0 + ATOM 2037 NE2 . GLN A 280 ? 12.95500 14.78300 -10.27700 1.000 93.93000 N ? A ? 280 0 + ATOM 2038 N . GLN A 281 ? 12.55400 10.93600 -15.75400 1.000 94.79000 N ? A ? 281 0 + ATOM 2039 CA . GLN A 281 ? 13.15500 10.07000 -16.75800 1.000 94.79000 C ? A ? 281 0 + ATOM 2040 C . GLN A 281 ? 14.47600 9.51300 -16.22600 1.000 94.79000 C ? A ? 281 0 + ATOM 2041 O . GLN A 281 ? 15.30700 10.26100 -15.71000 1.000 94.79000 O ? A ? 281 0 + ATOM 2042 CB . GLN A 281 ? 13.35200 10.81900 -18.08300 1.000 94.79000 C ? A ? 281 0 + ATOM 2043 CG . GLN A 281 ? 12.01100 11.14100 -18.76200 1.000 94.79000 C ? A ? 281 0 + ATOM 2044 CD . GLN A 281 ? 12.16600 11.87100 -20.09400 1.000 94.79000 C ? A ? 281 0 + ATOM 2045 OE1 . GLN A 281 ? 13.24000 12.24600 -20.53100 1.000 94.79000 O ? A ? 281 0 + ATOM 2046 NE2 . GLN A 281 ? 11.08600 12.11100 -20.80300 1.000 94.79000 N ? A ? 281 0 + ATOM 2047 N . VAL A 282 ? 14.65800 8.20200 -16.36100 1.000 95.86000 N ? A ? 282 0 + ATOM 2048 CA . VAL A 282 ? 15.90800 7.50900 -16.04000 1.000 95.86000 C ? A ? 282 0 + ATOM 2049 C . VAL A 282 ? 16.49300 6.97100 -17.33700 1.000 95.86000 C ? A ? 282 0 + ATOM 2050 O . VAL A 282 ? 15.80300 6.29400 -18.10000 1.000 95.86000 O ? A ? 282 0 + ATOM 2051 CB . VAL A 282 ? 15.69700 6.39500 -14.99900 1.000 95.86000 C ? A ? 282 0 + ATOM 2052 CG1 . VAL A 282 ? 17.03300 5.75500 -14.59600 1.000 95.86000 C ? A ? 282 0 + ATOM 2053 CG2 . VAL A 282 ? 15.04100 6.93800 -13.72300 1.000 95.86000 C ? A ? 282 0 + ATOM 2054 N . ASN A 283 ? 17.76100 7.27800 -17.59300 1.000 96.09000 N ? A ? 283 0 + ATOM 2055 CA . ASN A 283 ? 18.42800 6.86200 -18.81900 1.000 96.09000 C ? A ? 283 0 + ATOM 2056 C . ASN A 283 ? 18.93300 5.42500 -18.68200 1.000 96.09000 C ? A ? 283 0 + ATOM 2057 O . ASN A 283 ? 19.63000 5.08800 -17.72400 1.000 96.09000 O ? A ? 283 0 + ATOM 2058 CB . ASN A 283 ? 19.56100 7.83800 -19.16800 1.000 96.09000 C ? A ? 283 0 + ATOM 2059 CG . ASN A 283 ? 19.07000 9.23700 -19.49900 1.000 96.09000 C ? A ? 283 0 + ATOM 2060 OD1 . ASN A 283 ? 17.89500 9.54700 -19.50600 1.000 96.09000 O ? A ? 283 0 + ATOM 2061 ND2 . ASN A 283 ? 19.97500 10.15100 -19.75100 1.000 96.09000 N ? A ? 283 0 + ATOM 2062 N . PHE A 284 ? 18.62300 4.59700 -19.67400 1.000 95.39000 N ? A ? 284 0 + ATOM 2063 CA . PHE A 284 ? 19.15300 3.25100 -19.81400 1.000 95.39000 C ? A ? 284 0 + ATOM 2064 C . PHE A 284 ? 20.06700 3.17300 -21.03100 1.000 95.39000 C ? A ? 284 0 + ATOM 2065 O . PHE A 284 ? 19.65100 3.45600 -22.15500 1.000 95.39000 O ? A ? 284 0 + ATOM 2066 CB . PHE A 284 ? 18.00700 2.24800 -19.91800 1.000 95.39000 C ? A ? 284 0 + ATOM 2067 CG . PHE A 284 ? 18.48600 0.81500 -19.96000 1.000 95.39000 C ? A ? 284 0 + ATOM 2068 CD1 . PHE A 284 ? 18.52900 0.12800 -21.18600 1.000 95.39000 C ? A ? 284 0 + ATOM 2069 CD2 . PHE A 284 ? 18.93600 0.18300 -18.78400 1.000 95.39000 C ? A ? 284 0 + ATOM 2070 CE1 . PHE A 284 ? 19.02100 -1.18600 -21.23600 1.000 95.39000 C ? A ? 284 0 + ATOM 2071 CE2 . PHE A 284 ? 19.42200 -1.13500 -18.83400 1.000 95.39000 C ? A ? 284 0 + ATOM 2072 CZ . PHE A 284 ? 19.46700 -1.81700 -20.06300 1.000 95.39000 C ? A ? 284 0 + ATOM 2073 N . HIS A 285 ? 21.31300 2.76900 -20.80600 1.000 93.79000 N ? A ? 285 0 + ATOM 2074 CA . HIS A 285 ? 22.28400 2.55300 -21.86900 1.000 93.79000 C ? A ? 285 0 + ATOM 2075 C . HIS A 285 ? 22.23900 1.09100 -22.29700 1.000 93.79000 C ? A ? 285 0 + ATOM 2076 O . HIS A 285 ? 22.50300 0.19300 -21.49500 1.000 93.79000 O ? A ? 285 0 + ATOM 2077 CB . HIS A 285 ? 23.67700 2.97500 -21.39200 1.000 93.79000 C ? A ? 285 0 + ATOM 2078 CG . HIS A 285 ? 23.78200 4.46000 -21.15600 1.000 93.79000 C ? A ? 285 0 + ATOM 2079 ND1 . HIS A 285 ? 24.24400 5.38500 -22.06100 1.000 93.79000 N ? A ? 285 0 + ATOM 2080 CD2 . HIS A 285 ? 23.40100 5.14800 -20.03400 1.000 93.79000 C ? A ? 285 0 + ATOM 2081 CE1 . HIS A 285 ? 24.14100 6.60100 -21.50200 1.000 93.79000 C ? A ? 285 0 + ATOM 2082 NE2 . HIS A 285 ? 23.63400 6.50900 -20.26400 1.000 93.79000 N ? A ? 285 0 + ATOM 2083 N . THR A 286 ? 21.90700 0.85600 -23.56200 1.000 92.25000 N ? A ? 286 0 + ATOM 2084 CA . THR A 286 ? 21.95800 -0.49100 -24.13300 1.000 92.25000 C ? A ? 286 0 + ATOM 2085 C . THR A 286 ? 23.39700 -0.92300 -24.38900 1.000 92.25000 C ? A ? 286 0 + ATOM 2086 O . THR A 286 ? 24.33500 -0.12100 -24.39000 1.000 92.25000 O ? A ? 286 0 + ATOM 2087 CB . THR A 286 ? 21.13200 -0.60600 -25.41600 1.000 92.25000 C ? A ? 286 0 + ATOM 2088 OG1 . THR A 286 ? 21.63900 0.28000 -26.37400 1.000 92.25000 O ? A ? 286 0 + ATOM 2089 CG2 . THR A 286 ? 19.66400 -0.29400 -25.14700 1.000 92.25000 C ? A ? 286 0 + ATOM 2090 N . VAL A 287 ? 23.58100 -2.22500 -24.60000 1.000 89.62000 N ? A ? 287 0 + ATOM 2091 CA . VAL A 287 ? 24.88200 -2.77600 -24.98100 1.000 89.62000 C ? A ? 287 0 + ATOM 2092 C . VAL A 287 ? 25.31600 -2.23700 -26.35200 1.000 89.62000 C ? A ? 287 0 + ATOM 2093 O . VAL A 287 ? 24.45700 -1.99300 -27.20300 1.000 89.62000 O ? A ? 287 0 + ATOM 2094 CB . VAL A 287 ? 24.87700 -4.31400 -24.96900 1.000 89.62000 C ? A ? 287 0 + ATOM 2095 CG1 . VAL A 287 ? 24.62400 -4.83100 -23.54700 1.000 89.62000 C ? A ? 287 0 + ATOM 2096 CG2 . VAL A 287 ? 23.83600 -4.93000 -25.91500 1.000 89.62000 C ? A ? 287 0 + ATOM 2097 N . PRO A 288 ? 26.62600 -2.06000 -26.60600 1.000 89.96000 N ? A ? 288 0 + ATOM 2098 CA . PRO A 288 ? 27.12200 -1.67500 -27.92400 1.000 89.96000 C ? A ? 288 0 + ATOM 2099 C . PRO A 288 ? 26.65500 -2.63700 -29.02100 1.000 89.96000 C ? A ? 288 0 + ATOM 2100 O . PRO A 288 ? 26.51000 -3.83800 -28.78800 1.000 89.96000 O ? A ? 288 0 + ATOM 2101 CB . PRO A 288 ? 28.64900 -1.66800 -27.81100 1.000 89.96000 C ? A ? 288 0 + ATOM 2102 CG . PRO A 288 ? 28.89300 -1.43700 -26.32100 1.000 89.96000 C ? A ? 288 0 + ATOM 2103 CD . PRO A 288 ? 27.72800 -2.17100 -25.66300 1.000 89.96000 C ? A ? 288 0 + ATOM 2104 N . CYS A 289 ? 26.45100 -2.11700 -30.23100 1.000 90.36000 N ? A ? 289 0 + ATOM 2105 CA . CYS A 289 ? 26.15100 -2.96200 -31.38100 1.000 90.36000 C ? A ? 289 0 + ATOM 2106 C . CYS A 289 ? 27.32300 -3.86900 -31.75000 1.000 90.36000 C ? A ? 289 0 + ATOM 2107 O . CYS A 289 ? 28.48800 -3.53100 -31.53100 1.000 90.36000 O ? A ? 289 0 + ATOM 2108 CB . CYS A 289 ? 25.72500 -2.10900 -32.57700 1.000 90.36000 C ? A ? 289 0 + ATOM 2109 SG . CYS A 289 ? 24.12000 -1.31200 -32.38200 1.000 90.36000 S ? A ? 289 0 + ATOM 2110 N . ALA A 290 ? 26.99700 -5.00900 -32.36200 1.000 88.26000 N ? A ? 290 0 + ATOM 2111 CA . ALA A 290 ? 27.99800 -5.84400 -33.00400 1.000 88.26000 C ? A ? 290 0 + ATOM 2112 C . ALA A 290 ? 28.74400 -5.01500 -34.07000 1.000 88.26000 C ? A ? 290 0 + ATOM 2113 O . ALA A 290 ? 28.08600 -4.30200 -34.83700 1.000 88.26000 O ? A ? 290 0 + ATOM 2114 CB . ALA A 290 ? 27.32400 -7.07800 -33.61100 1.000 88.26000 C ? A ? 290 0 + ATOM 2115 N . PRO A 291 ? 30.08500 -5.08600 -34.12800 1.000 89.12000 N ? A ? 291 0 + ATOM 2116 CA . PRO A 291 ? 30.85400 -4.37200 -35.13600 1.000 89.12000 C ? A ? 291 0 + ATOM 2117 C . PRO A 291 ? 30.38000 -4.72000 -36.55700 1.000 89.12000 C ? A ? 291 0 + ATOM 2118 O . PRO A 291 ? 30.23800 -5.90900 -36.86600 1.000 89.12000 O ? A ? 291 0 + ATOM 2119 CB . PRO A 291 ? 32.30300 -4.79000 -34.90800 1.000 89.12000 C ? A ? 291 0 + ATOM 2120 CG . PRO A 291 ? 32.35600 -5.20600 -33.44400 1.000 89.12000 C ? A ? 291 0 + ATOM 2121 CD . PRO A 291 ? 30.96800 -5.79000 -33.20900 1.000 89.12000 C ? A ? 291 0 + ATOM 2122 N . PRO A 292 ? 30.10100 -3.72800 -37.42100 1.000 89.18000 N ? A ? 292 0 + ATOM 2123 CA . PRO A 292 ? 29.67000 -3.99700 -38.78400 1.000 89.18000 C ? A ? 292 0 + ATOM 2124 C . PRO A 292 ? 30.83300 -4.54700 -39.62200 1.000 89.18000 C ? A ? 292 0 + ATOM 2125 O . PRO A 292 ? 31.99400 -4.29800 -39.33500 1.000 89.18000 O ? A ? 292 0 + ATOM 2126 CB . PRO A 292 ? 29.14300 -2.65800 -39.30700 1.000 89.18000 C ? A ? 292 0 + ATOM 2127 CG . PRO A 292 ? 29.99500 -1.63300 -38.55700 1.000 89.18000 C ? A ? 292 0 + ATOM 2128 CD . PRO A 292 ? 30.23200 -2.29300 -37.19800 1.000 89.18000 C ? A ? 292 0 + ATOM 2129 N . ASN A 293 ? 30.52200 -5.27700 -40.69600 1.000 89.26000 N ? A ? 293 0 + ATOM 2130 CA . ASN A 293 ? 31.47600 -5.60800 -41.76700 1.000 89.26000 C ? A ? 293 0 + ATOM 2131 C . ASN A 293 ? 32.83200 -6.18400 -41.31400 1.000 89.26000 C ? A ? 293 0 + ATOM 2132 O . ASN A 293 ? 33.86200 -5.85900 -41.90800 1.000 89.26000 O ? A ? 293 0 + ATOM 2133 CB . ASN A 293 ? 31.64000 -4.38200 -42.68000 1.000 89.26000 C ? A ? 293 0 + ATOM 2134 CG . ASN A 293 ? 30.33600 -3.93700 -43.29700 1.000 89.26000 C ? A ? 293 0 + ATOM 2135 OD1 . ASN A 293 ? 29.48200 -4.72900 -43.66000 1.000 89.26000 O ? A ? 293 0 + ATOM 2136 ND2 . ASN A 293 ? 30.13400 -2.64900 -43.42800 1.000 89.26000 N ? A ? 293 0 + ATOM 2137 N . LEU A 294 ? 32.83500 -7.06500 -40.30600 1.000 90.46000 N ? A ? 294 0 + ATOM 2138 CA . LEU A 294 ? 34.05400 -7.74100 -39.86900 1.000 90.46000 C ? A ? 294 0 + ATOM 2139 C . LEU A 294 ? 34.74100 -8.41900 -41.06400 1.000 90.46000 C ? A ? 294 0 + ATOM 2140 O . LEU A 294 ? 34.20500 -9.36000 -41.65400 1.000 90.46000 O ? A ? 294 0 + ATOM 2141 CB . LEU A 294 ? 33.73200 -8.75700 -38.76000 1.000 90.46000 C ? A ? 294 0 + ATOM 2142 CG . LEU A 294 ? 34.98100 -9.49400 -38.23200 1.000 90.46000 C ? A ? 294 0 + ATOM 2143 CD1 . LEU A 294 ? 35.93000 -8.55500 -37.48400 1.000 90.46000 C ? A ? 294 0 + ATOM 2144 CD2 . LEU A 294 ? 34.56600 -10.61600 -37.28100 1.000 90.46000 C ? A ? 294 0 + ATOM 2145 N . SER A 295 ? 35.94500 -7.96400 -41.39300 1.000 90.78000 N ? A ? 295 0 + ATOM 2146 CA . SER A 295 ? 36.77100 -8.54500 -42.44400 1.000 90.78000 C ? A ? 295 0 + ATOM 2147 C . SER A 295 ? 38.15200 -8.90600 -41.90800 1.000 90.78000 C ? A ? 295 0 + ATOM 2148 O . SER A 295 ? 38.71600 -8.22400 -41.04800 1.000 90.78000 O ? A ? 295 0 + ATOM 2149 CB . SER A 295 ? 36.81400 -7.64400 -43.68000 1.000 90.78000 C ? A ? 295 0 + ATOM 2150 OG . SER A 295 ? 37.69600 -6.56500 -43.51100 1.000 90.78000 O ? A ? 295 0 + ATOM 2151 N . VAL A 296 ? 38.68200 -10.02800 -42.39800 1.000 91.50000 N ? A ? 296 0 + ATOM 2152 CA . VAL A 296 ? 39.95300 -10.59900 -41.94900 1.000 91.50000 C ? A ? 296 0 + ATOM 2153 C . VAL A 296 ? 40.87700 -10.73900 -43.15100 1.000 91.50000 C ? A ? 296 0 + ATOM 2154 O . VAL A 296 ? 40.60000 -11.51200 -44.06600 1.000 91.50000 O ? A ? 296 0 + ATOM 2155 CB . VAL A 296 ? 39.74600 -11.95100 -41.23300 1.000 91.50000 C ? A ? 296 0 + ATOM 2156 CG1 . VAL A 296 ? 41.07200 -12.46300 -40.65400 1.000 91.50000 C ? A ? 296 0 + ATOM 2157 CG2 . VAL A 296 ? 38.73800 -11.84300 -40.07900 1.000 91.50000 C ? A ? 296 0 + ATOM 2158 N . ALA A 297 ? 41.98800 -10.00700 -43.13600 1.000 91.28000 N ? A ? 297 0 + ATOM 2159 CA . ALA A 297 ? 43.06000 -10.12100 -44.11600 1.000 91.28000 C ? A ? 297 0 + ATOM 2160 C . ALA A 297 ? 44.22100 -10.91600 -43.50600 1.000 91.28000 C ? A ? 297 0 + ATOM 2161 O . ALA A 297 ? 44.86600 -10.46800 -42.55800 1.000 91.28000 O ? A ? 297 0 + ATOM 2162 CB . ALA A 297 ? 43.46700 -8.71600 -44.57100 1.000 91.28000 C ? A ? 297 0 + ATOM 2163 N . VAL A 298 ? 44.47800 -12.11700 -44.02600 1.000 91.86000 N ? A ? 298 0 + ATOM 2164 CA . VAL A 298 ? 45.54200 -13.00000 -43.52700 1.000 91.86000 C ? A ? 298 0 + ATOM 2165 C . VAL A 298 ? 46.80700 -12.80900 -44.35800 1.000 91.86000 C ? A ? 298 0 + ATOM 2166 O . VAL A 298 ? 46.80200 -13.05500 -45.56200 1.000 91.86000 O ? A ? 298 0 + ATOM 2167 CB . VAL A 298 ? 45.10200 -14.47600 -43.51300 1.000 91.86000 C ? A ? 298 0 + ATOM 2168 CG1 . VAL A 298 ? 46.19700 -15.37100 -42.91500 1.000 91.86000 C ? A ? 298 0 + ATOM 2169 CG2 . VAL A 298 ? 43.82800 -14.66700 -42.67700 1.000 91.86000 C ? A ? 298 0 + ATOM 2170 N . GLN A 299 ? 47.90500 -12.43600 -43.70500 1.000 90.20000 N ? A ? 299 0 + ATOM 2171 CA . GLN A 299 ? 49.22300 -12.33000 -44.32100 1.000 90.20000 C ? A ? 299 0 + ATOM 2172 C . GLN A 299 ? 50.02900 -13.59800 -44.01900 1.000 90.20000 C ? A ? 299 0 + ATOM 2173 O . GLN A 299 ? 50.57300 -13.77700 -42.92500 1.000 90.20000 O ? A ? 299 0 + ATOM 2174 CB . GLN A 299 ? 49.91100 -11.04100 -43.84400 1.000 90.20000 C ? A ? 299 0 + ATOM 2175 CG . GLN A 299 ? 51.13300 -10.68100 -44.70800 1.000 90.20000 C ? A ? 299 0 + ATOM 2176 CD . GLN A 299 ? 50.76800 -10.23500 -46.12500 1.000 90.20000 C ? A ? 299 0 + ATOM 2177 OE1 . GLN A 299 ? 49.62200 -9.99800 -46.46600 1.000 90.20000 O ? A ? 299 0 + ATOM 2178 NE2 . GLN A 299 ? 51.72200 -10.12200 -47.02000 1.000 90.20000 N ? A ? 299 0 + ATOM 2179 N . CYS A 300 ? 50.09000 -14.50300 -45.00100 1.000 89.51000 N ? A ? 300 0 + ATOM 2180 CA . CYS A 300 ? 50.71500 -15.81900 -44.83700 1.000 89.51000 C ? A ? 300 0 + ATOM 2181 C . CYS A 300 ? 52.22700 -15.73000 -44.57300 1.000 89.51000 C ? A ? 300 0 + ATOM 2182 O . CYS A 300 ? 52.74700 -16.50300 -43.76800 1.000 89.51000 O ? A ? 300 0 + ATOM 2183 CB . CYS A 300 ? 50.41700 -16.68000 -46.07300 1.000 89.51000 C ? A ? 300 0 + ATOM 2184 SG . CYS A 300 ? 48.64200 -17.06800 -46.15600 1.000 89.51000 S ? A ? 300 0 + ATOM 2185 N . ASP A 301 ? 52.91300 -14.76100 -45.18600 1.000 90.56000 N ? A ? 301 0 + ATOM 2186 CA . ASP A 301 ? 54.37200 -14.61500 -45.08400 1.000 90.56000 C ? A ? 301 0 + ATOM 2187 C . ASP A 301 ? 54.82900 -14.25800 -43.66500 1.000 90.56000 C ? A ? 301 0 + ATOM 2188 O . ASP A 301 ? 55.81000 -14.79700 -43.15500 1.000 90.56000 O ? A ? 301 0 + ATOM 2189 CB . ASP A 301 ? 54.84900 -13.52700 -46.05700 1.000 90.56000 C ? A ? 301 0 + ATOM 2190 CG . ASP A 301 ? 54.47600 -13.81900 -47.51000 1.000 90.56000 C ? A ? 301 0 + ATOM 2191 OD1 . ASP A 301 ? 54.48200 -15.01100 -47.88700 1.000 90.56000 O ? A ? 301 0 + ATOM 2192 OD2 . ASP A 301 ? 54.13000 -12.83700 -48.20000 1.000 90.56000 O ? A ? 301 0 + ATOM 2193 N . THR A 302 ? 54.08800 -13.37000 -43.00000 1.000 91.35000 N ? A ? 302 0 + ATOM 2194 CA . THR A 302 ? 54.38400 -12.89800 -41.64000 1.000 91.35000 C ? A ? 302 0 + ATOM 2195 C . THR A 302 ? 53.66300 -13.70400 -40.56400 1.000 91.35000 C ? A ? 302 0 + ATOM 2196 O . THR A 302 ? 53.91100 -13.48700 -39.38000 1.000 91.35000 O ? A ? 302 0 + ATOM 2197 CB . THR A 302 ? 54.03300 -11.41200 -41.49700 1.000 91.35000 C ? A ? 302 0 + ATOM 2198 OG1 . THR A 302 ? 52.71100 -11.20600 -41.92800 1.000 91.35000 O ? A ? 302 0 + ATOM 2199 CG2 . THR A 302 ? 54.92500 -10.53400 -42.37500 1.000 91.35000 C ? A ? 302 0 + ATOM 2200 N . ARG A 303 ? 52.77800 -14.63500 -40.95200 1.000 88.38000 N ? A ? 303 0 + ATOM 2201 CA . ARG A 303 ? 51.87700 -15.37000 -40.04600 1.000 88.38000 C ? A ? 303 0 + ATOM 2202 C . ARG A 303 ? 51.03000 -14.43600 -39.17000 1.000 88.38000 C ? A ? 303 0 + ATOM 2203 O . ARG A 303 ? 50.78500 -14.72800 -38.00200 1.000 88.38000 O ? A ? 303 0 + ATOM 2204 CB . ARG A 303 ? 52.65600 -16.40000 -39.20800 1.000 88.38000 C ? A ? 303 0 + ATOM 2205 CG . ARG A 303 ? 53.48800 -17.37800 -40.04200 1.000 88.38000 C ? A ? 303 0 + ATOM 2206 CD . ARG A 303 ? 54.20900 -18.33100 -39.08700 1.000 88.38000 C ? A ? 303 0 + ATOM 2207 NE . ARG A 303 ? 55.01500 -19.31800 -39.82200 1.000 88.38000 N ? A ? 303 0 + ATOM 2208 CZ . ARG A 303 ? 55.71500 -20.30000 -39.28700 1.000 88.38000 C ? A ? 303 0 + ATOM 2209 NH1 . ARG A 303 ? 55.76700 -20.48200 -37.99500 1.000 88.38000 N ? A ? 303 0 + ATOM 2210 NH2 . ARG A 303 ? 56.37800 -21.12400 -40.04700 1.000 88.38000 N ? A ? 303 0 + ATOM 2211 N . THR A 304 ? 50.58300 -13.31100 -39.72600 1.000 93.03000 N ? A ? 304 0 + ATOM 2212 CA . THR A 304 ? 49.73500 -12.32800 -39.03200 1.000 93.03000 C ? A ? 304 0 + ATOM 2213 C . THR A 304 ? 48.37200 -12.21400 -39.70700 1.000 93.03000 C ? A ? 304 0 + ATOM 2214 O . THR A 304 ? 48.25500 -12.43200 -40.90900 1.000 93.03000 O ? A ? 304 0 + ATOM 2215 CB . THR A 304 ? 50.40200 -10.94600 -38.93800 1.000 93.03000 C ? A ? 304 0 + ATOM 2216 OG1 . THR A 304 ? 50.74400 -10.45000 -40.21200 1.000 93.03000 O ? A ? 304 0 + ATOM 2217 CG2 . THR A 304 ? 51.68500 -10.97300 -38.10900 1.000 93.03000 C ? A ? 304 0 + ATOM 2218 N . ALA A 305 ? 47.34300 -11.82600 -38.95600 1.000 91.49000 N ? A ? 305 0 + ATOM 2219 CA . ALA A 305 ? 46.03200 -11.48000 -39.50100 1.000 91.49000 C ? A ? 305 0 + ATOM 2220 C . ALA A 305 ? 45.65200 -10.05900 -39.07200 1.000 91.49000 C ? A ? 305 0 + ATOM 2221 O . ALA A 305 ? 45.80500 -9.70100 -37.90500 1.000 91.49000 O ? A ? 305 0 + ATOM 2222 CB . ALA A 305 ? 45.00000 -12.52300 -39.05700 1.000 91.49000 C ? A ? 305 0 + ATOM 2223 N . THR A 306 ? 45.15800 -9.26100 -40.01300 1.000 90.74000 N ? A ? 306 0 + ATOM 2224 CA . THR A 306 ? 44.62600 -7.92000 -39.76700 1.000 90.74000 C ? A ? 306 0 + ATOM 2225 C . THR A 306 ? 43.10700 -7.99500 -39.80500 1.000 90.74000 C ? A ? 306 0 + ATOM 2226 O . THR A 306 ? 42.52900 -8.43600 -40.79700 1.000 90.74000 O ? A ? 306 0 + ATOM 2227 CB . THR A 306 ? 45.15900 -6.91300 -40.79600 1.000 90.74000 C ? A ? 306 0 + ATOM 2228 OG1 . THR A 306 ? 46.56900 -6.94400 -40.81400 1.000 90.74000 O ? A ? 306 0 + ATOM 2229 CG2 . THR A 306 ? 44.75800 -5.47700 -40.46100 1.000 90.74000 C ? A ? 306 0 + ATOM 2230 N . LEU A 307 ? 42.46500 -7.58900 -38.71200 1.000 92.04000 N ? A ? 307 0 + ATOM 2231 CA . LEU A 307 ? 41.01300 -7.50700 -38.60100 1.000 92.04000 C ? A ? 307 0 + ATOM 2232 C . LEU A 307 ? 40.58500 -6.05100 -38.81900 1.000 92.04000 C ? A ? 307 0 + ATOM 2233 O . LEU A 307 ? 41.24900 -5.14200 -38.32300 1.000 92.04000 O ? A ? 307 0 + ATOM 2234 CB . LEU A 307 ? 40.54100 -8.04000 -37.23400 1.000 92.04000 C ? A ? 307 0 + ATOM 2235 CG . LEU A 307 ? 40.76800 -9.54600 -36.98600 1.000 92.04000 C ? A ? 307 0 + ATOM 2236 CD1 . LEU A 307 ? 42.17000 -9.86900 -36.45400 1.000 92.04000 C ? A ? 307 0 + ATOM 2237 CD2 . LEU A 307 ? 39.77700 -10.05400 -35.93800 1.000 92.04000 C ? A ? 307 0 + ATOM 2238 N . SER A 308 ? 39.48600 -5.83300 -39.53700 1.000 89.41000 N ? A ? 308 0 + ATOM 2239 CA . SER A 308 ? 38.83100 -4.52300 -39.64800 1.000 89.41000 C ? A ? 308 0 + ATOM 2240 C . SER A 308 ? 37.32100 -4.66700 -39.49900 1.000 89.41000 C ? A ? 308 0 + ATOM 2241 O . SER A 308 ? 36.76700 -5.70500 -39.86600 1.000 89.41000 O ? A ? 308 0 + ATOM 2242 CB . SER A 308 ? 39.21000 -3.81000 -40.94900 1.000 89.41000 C ? A ? 308 0 + ATOM 2243 OG . SER A 308 ? 38.79100 -4.52800 -42.08600 1.000 89.41000 O ? A ? 308 0 + ATOM 2244 N . TRP A 309 ? 36.69100 -3.65900 -38.90300 1.000 89.27000 N ? A ? 309 0 + ATOM 2245 CA . TRP A 309 ? 35.26100 -3.55800 -38.61800 1.000 89.27000 C ? A ? 309 0 + ATOM 2246 C . TRP A 309 ? 34.86900 -2.08300 -38.47900 1.000 89.27000 C ? A ? 309 0 + ATOM 2247 O . TRP A 309 ? 35.79200 -1.25800 -38.27100 1.000 89.27000 O ? A ? 309 0 + ATOM 2248 CB . TRP A 309 ? 34.93900 -4.33400 -37.33500 1.000 89.27000 C ? A ? 309 0 + ATOM 2249 CG . TRP A 309 ? 35.60000 -3.82400 -36.08600 1.000 89.27000 C ? A ? 309 0 + ATOM 2250 CD1 . TRP A 309 ? 35.16400 -2.78300 -35.34300 1.000 89.27000 C ? A ? 309 0 + ATOM 2251 CD2 . TRP A 309 ? 36.87100 -4.21900 -35.49000 1.000 89.27000 C ? A ? 309 0 + ATOM 2252 NE1 . TRP A 309 ? 36.01000 -2.57300 -34.27400 1.000 89.27000 N ? A ? 309 0 + ATOM 2253 CE2 . TRP A 309 ? 37.10100 -3.41100 -34.33500 1.000 89.27000 C ? A ? 309 0 + ATOM 2254 CE3 . TRP A 309 ? 37.88000 -5.14300 -35.83800 1.000 89.27000 C ? A ? 309 0 + ATOM 2255 CZ2 . TRP A 309 ? 38.25800 -3.52600 -33.55300 1.000 89.27000 C ? A ? 309 0 + ATOM 2256 CZ3 . TRP A 309 ? 39.05500 -5.25100 -35.06900 1.000 89.27000 C ? A ? 309 0 + ATOM 2257 CH2 . TRP A 309 ? 39.24400 -4.45200 -33.92800 1.000 89.27000 C ? A ? 309 0 + ATOM 2258 OXT . TRP A 309 ? 33.65700 -1.80300 -38.56700 1.000 89.27000 O ? A ? 309 0 + diff --git a/mmtbx/regression/tst_chain_comparison_cif.py b/mmtbx/regression/tst_chain_comparison_cif.py new file mode 100644 index 0000000000..b599829254 --- /dev/null +++ b/mmtbx/regression/tst_chain_comparison_cif.py @@ -0,0 +1,856 @@ +from __future__ import absolute_import, division, print_function + +from six.moves import cStringIO as StringIO +from mmtbx.validation.chain_comparison import run + +def remove_blank(text): + return text.replace(" ","").replace("\n","") + +pdb_str_model=""" +CRYST1 113.949 113.949 32.474 90.00 90.00 90.00 I 4 +ATOM 9 CA LYS 4 109.976 18.221 44.266 1.00 48.61 P9 +ATOM 11 CA TRP 5 109.182 21.755 43.110 1.00 47.90 P9 +ATOM 25 CA VAL 6 110.823 23.654 40.250 1.00 46.89 P9 +ATOM 32 CA MET 7 108.936 26.802 39.218 1.00 45.06 P9 +ATOM 40 CA SER 8 105.419 28.211 39.036 1.00 41.81 P9 +ATOM 46 CA THR 9 103.906 27.616 35.600 1.00 37.71 P9 +ATOM 53 CA LYS 10 103.277 30.858 33.696 1.00 33.20 P9 +ATOM 62 CA TYR 11 100.215 31.269 31.467 1.00 29.03 P9 +ATOM 74 CA VAL 12 98.628 33.636 28.957 1.00 24.81 P9 +ATOM 81 CA GLU 13 95.372 33.451 27.024 1.00 21.62 P9 +ATOM 90 CA ALA 14 95.648 31.766 23.627 1.00 21.34 P9 +ATOM 95 CA GLY 15 94.222 34.881 22.004 1.00 22.33 P9 +ATOM 99 CA GLU 16 97.221 36.890 23.214 1.00 23.17 P9 +ATOM 108 CA LEU 17 99.807 34.753 21.414 1.00 23.42 P9 +ATOM 116 CA LYS 18 101.429 36.062 18.237 1.00 24.53 P9 +ATOM 125 CA GLU 19 103.948 34.832 15.691 1.00 24.34 P9 +ATOM 134 CA GLY 20 107.227 34.699 17.578 1.00 22.47 P9 +ATOM 138 CA SER 21 105.632 33.977 20.956 1.00 20.20 P9 +ATOM 144 CA TYR 22 106.668 30.890 22.912 1.00 19.09 P9 +ATOM 156 CA VAL 23 104.283 28.225 24.176 1.00 18.63 P9 +ATOM 163 CA VAL 24 104.403 24.711 25.602 1.00 16.73 P9 +ATOM 170 CA ILE 25 102.485 22.073 23.645 1.00 16.21 P9 +ATOM 178 CA ASP 26 102.424 18.531 25.042 1.00 17.02 P9 +ATOM 186 CA GLY 27 105.535 19.131 27.135 1.00 19.18 P9 +ATOM 190 CA GLU 28 107.647 20.739 24.398 1.00 18.42 P9 +ATOM 200 CA PRO 29 108.490 24.457 24.454 1.00 17.13 P9 +ATOM 206 CA CYS 30 107.738 25.793 20.958 1.00 18.27 P9 +ATOM 212 CA ARG 31 108.013 29.010 18.950 1.00 18.81 P9 +ATOM 223 CA VAL 32 104.720 30.074 17.348 1.00 18.68 P9 +ATOM 230 CA VAL 33 104.990 30.324 13.554 1.00 21.62 P9 +ATOM 237 CA GLU 34 101.337 30.903 12.676 1.00 22.97 P9 +ATOM 246 CA ILE 35 97.990 31.567 14.325 1.00 23.13 P9 +ATOM 254 CA GLU 36 94.516 31.390 12.807 1.00 22.64 P9 +ATOM 263 CA LYS 37 91.314 32.656 14.422 1.00 21.25 P9 +ATOM 272 CA SER 38 87.754 31.489 13.758 1.00 20.23 P9 +ATOM 278 CA LYS 39 84.259 31.708 15.215 1.00 22.33 P9 +ATOM 287 CA THR 40 81.571 29.194 14.236 1.00 25.52 P9 +ATOM 294 CA GLY 41 79.184 29.756 17.114 0.93 29.60 P9 +ATOM 298 CA LYS 42 76.787 32.652 16.597 0.89 32.20 P9 +ATOM 307 CA HIS 43 77.170 33.509 20.288 1.00 31.87 P9 +ATOM 317 CA GLY 44 80.141 31.264 20.999 0.65 28.63 P9 +ATOM 321 CA SER 45 83.784 31.911 21.813 1.00 23.69 P9 +ATOM 327 CA ALA 46 86.373 32.582 19.132 1.00 18.89 P9 +ATOM 332 CA LYS 47 88.902 29.776 18.670 1.00 17.38 P9 +ATOM 341 CA ALA 48 92.611 29.914 17.899 1.00 17.02 P9 +ATOM 346 CA ARG 49 94.612 27.386 15.893 1.00 17.11 P9 +ATOM 357 CA ILE 50 98.284 27.635 16.768 1.00 17.68 P9 +ATOM 365 CA VAL 51 101.124 26.174 14.718 1.00 17.34 P9 +ATOM 372 CA ALA 52 104.518 26.094 16.413 1.00 17.71 P9 +ATOM 377 CA VAL 53 107.935 24.470 16.254 1.00 17.54 P9 +ATOM 384 CA GLY 54 109.704 22.649 19.055 1.00 18.35 P9 +ATOM 388 CA VAL 55 112.688 24.550 20.407 1.00 19.01 P9 +ATOM 395 CA PHE 56 114.509 21.294 21.108 1.00 19.90 P9 +ATOM 406 CA ASP 57 113.198 18.603 18.749 1.00 21.17 P9 +ATOM 414 CA GLY 58 112.293 20.976 15.923 1.00 21.69 P9 +ATOM 418 CA GLY 59 108.988 19.187 15.479 1.00 21.62 P9 +ATOM 422 CA LYS 60 105.864 20.872 14.151 1.00 20.30 P9 +ATOM 431 CA ARG 61 103.024 20.971 16.667 1.00 18.60 P9 +ATOM 442 CA THR 62 99.517 22.398 16.607 1.00 17.44 P9 +ATOM 449 CA LEU 63 96.998 23.440 19.242 1.00 16.19 P9 +ATOM 457 CA SER 64 93.370 24.446 18.716 1.00 15.39 P9 +ATOM 463 CA LEU 65 91.433 25.924 21.644 1.00 14.67 P9 +ATOM 472 CA PRO 66 89.260 28.905 22.730 1.00 14.79 P9 +ATOM 478 CA VAL 67 90.940 32.325 22.634 1.00 15.74 P9 +ATOM 485 CA ASP 68 90.325 32.738 26.369 1.00 17.10 P9 +ATOM 493 CA ALA 69 91.793 29.371 27.372 1.00 16.26 P9 +ATOM 498 CA GLN 70 95.115 29.425 29.223 1.00 18.00 P9 +ATOM 507 CA VAL 71 98.237 28.190 27.463 1.00 19.41 P9 +ATOM 514 CA GLU 72 101.563 27.596 29.201 1.00 21.29 P9 +ATOM 523 CA VAL 73 104.492 29.822 28.262 1.00 21.83 P9 +ATOM 531 CA PRO 74 108.047 28.603 28.963 0.94 22.19 P9 +ATOM 537 CA ILE 75 110.436 30.660 31.072 1.00 23.67 P9 +ATOM 545 CA ILE 76 113.508 31.336 28.943 0.96 24.46 P9 +ATOM 553 CA GLU 77 116.735 32.457 30.611 1.00 24.69 P9 +ATOM 562 CA LYS 78 119.294 33.935 28.213 1.00 24.12 P9 +ATOM 571 CA PHE 79 123.013 34.160 28.959 1.00 21.39 P9 +ATOM 582 CA THR 80 126.479 34.196 27.404 1.00 19.30 P9 +ATOM 589 CA ALA 81 128.958 31.320 27.436 1.00 17.03 P9 +ATOM 594 CA GLN 82 132.421 30.668 25.993 1.00 15.83 P9 +ATOM 603 CA ILE 83 133.128 27.536 23.964 1.00 14.35 P9 +ATOM 611 CA LEU 84 135.770 25.349 25.639 1.00 14.01 P9 +ATOM 619 CA SER 85 135.720 22.442 23.163 1.00 14.77 P9 +ATOM 625 CA VAL 86 133.697 21.017 20.292 1.00 15.76 P9 +ATOM 632 CA SER 87 133.246 17.344 19.410 1.00 15.97 P9 +ATOM 638 CA GLY 88 130.905 15.871 16.836 1.00 16.65 P9 +ATOM 642 CA ASP 89 128.352 15.243 19.587 1.00 17.36 P9 +ATOM 650 CA VAL 90 128.894 17.746 22.389 1.00 16.73 P9 +ATOM 657 CA ILE 91 129.780 21.401 22.870 1.00 16.05 P9 +ATOM 665 CA GLN 92 131.584 22.059 26.178 1.00 16.32 P9 +ATOM 674 CA LEU 93 130.870 25.590 27.465 1.00 15.69 P9 +ATOM 682 CA MET 94 131.982 27.904 30.270 1.00 17.32 P9 +ATOM 690 CA ASP 95 129.006 29.830 31.697 1.00 19.94 P9 +ATOM 698 CA MET 96 130.333 33.412 31.817 1.00 22.68 P9 +ATOM 706 CA ARG 97 128.065 34.204 34.767 1.00 24.59 P9 +ATOM 717 CA ASP 98 129.544 31.755 37.283 0.96 24.84 P9 +ATOM 725 CA TYR 99 132.285 30.135 35.175 0.99 24.06 P9 +ATOM 737 CA LYS 100 130.841 26.625 35.550 1.00 22.14 P9 +ATOM 746 CA THR 101 131.149 24.064 32.761 1.00 20.84 P9 +ATOM 753 CA ILE 102 127.988 23.035 30.916 1.00 19.78 P9 +ATOM 761 CA GLU 103 127.678 20.418 28.177 1.00 19.97 P9 +ATOM 770 CA VAL 104 125.251 20.963 25.299 1.00 18.00 P9 +ATOM 778 CA PRO 105 124.362 18.242 22.754 1.00 18.24 P9 +ATOM 784 CA MET 106 125.166 19.138 19.128 1.00 18.91 P9 +ATOM 792 CA LYS 107 121.491 18.558 18.303 1.00 19.94 P9 +ATOM 801 CA TYR 108 120.616 21.558 20.496 1.00 20.72 P9 +ATOM 813 CA VAL 109 122.621 24.018 18.411 1.00 23.20 P9 +ATOM 820 CA GLU 110 120.751 26.260 15.961 1.00 28.03 P9 +ATOM 829 CA GLU 111 121.704 25.099 12.460 0.74 31.85 P9 +ATOM 838 CA GLU 112 122.954 28.554 11.512 1.00 33.44 P9 +ATOM 847 CA ALA 113 125.368 28.615 14.458 1.00 31.90 P9 +ATOM 852 CA LYS 114 126.911 25.180 13.906 0.92 31.27 P9 +ATOM 861 CA GLY 115 129.136 26.579 11.174 1.00 30.17 P9 +ATOM 865 CA ARG 116 130.956 29.004 13.463 1.00 27.89 P9 +ATOM 876 CA LEU 117 131.365 26.777 16.514 1.00 25.28 P9 +ATOM 884 CA ALA 118 134.998 27.063 17.578 1.00 23.01 P9 +ATOM 890 CA PRO 119 136.912 26.997 20.869 1.00 21.21 P9 +ATOM 896 CA GLY 120 137.158 30.500 22.308 1.00 21.69 P9 +ATOM 900 CA ALA 121 134.046 31.875 20.620 1.00 21.58 P9 +ATOM 905 CA GLU 122 131.240 33.298 22.745 1.00 22.41 P9 +ATOM 914 CA VAL 123 127.678 32.132 22.205 1.00 20.97 P9 +ATOM 921 CA GLU 124 124.171 33.150 23.219 1.00 20.32 P9 +ATOM 930 CA VAL 125 122.627 30.323 25.229 1.00 19.82 P9 +ATOM 937 CA TRP 126 119.012 29.745 26.239 1.00 21.08 P9 +ATOM 951 CA GLN 127 118.027 27.643 29.216 1.00 22.22 P9 +ATOM 960 CA ILE 128 114.538 26.200 29.585 1.00 22.80 P9 +ATOM 968 CA LEU 129 114.153 24.029 32.671 1.00 24.59 P9 +ATOM 976 CA ASP 130 117.058 21.551 32.616 0.99 24.90 P9 +ATOM 984 CA ARG 131 117.952 21.918 28.938 1.00 22.57 P9 +ATOM 995 CA TYR 132 120.128 24.357 27.016 1.00 21.18 P9 +ATOM 1007 CA LYS 133 120.153 25.537 23.432 1.00 21.22 P9 +ATOM 1016 CA ILE 134 122.957 27.373 21.662 1.00 20.82 P9 +ATOM 1024 CA ILE 135 121.298 30.133 19.637 1.00 24.27 P9 +ATOM 1032 CA ARG 136 124.175 31.872 17.866 1.00 28.80 P9 +ATOM 1043 CA VAL 137 127.877 32.680 17.955 1.00 32.92 P9 +ATOM 1050 CA LYS 138 128.895 35.931 19.718 1.00 36.89 P9 +ATOM 1059 CA GLY 139 126.242 36.878 22.264 0.67 38.21 P9 +""" + +pdb_str_query=""" +ATOM 2 CA HIS A 7 47.968 37.350 1.343 1.00 30.00 C +ATOM 12 CA ILE A 8 46.579 37.684 4.402 1.00 30.00 C +ATOM 20 CA LYS A 9 47.784 38.702 7.227 1.00 30.00 C +ATOM 29 CA LEU A 10 45.288 36.534 8.774 1.00 30.00 C +ATOM 37 CA MET A 11 43.852 36.569 12.293 1.00 30.00 C +ATOM 45 CA ASN A 12 42.415 33.671 14.884 1.00 30.00 C +ATOM 53 CA ALA U 31 39.285 33.668 16.254 1.00 30.00 UNK C +ATOM 58 CA CYS U 32 40.481 30.632 18.193 1.00 30.00 UNK C +ATOM 64 CA LYS U 33 38.694 27.705 19.208 1.00 30.00 UNK C +ATOM 73 CA GLY U 34 41.530 25.709 20.615 1.00 30.00 UNK C +ATOM 77 CA LEU U 35 42.598 23.279 18.933 1.00 30.00 UNK C +ATOM 85 CA GLY U 36 45.899 23.083 17.741 1.00 30.00 UNK C +ATOM 89 CA HIS U 37 47.964 25.323 17.214 1.00 30.00 UNK C +ATOM 99 CA TRP U 41 49.522 32.736 0.687 1.00 30.00 UNK C +ATOM 113 CA PRO U 42 46.846 33.404 2.158 1.00 30.00 UNK C +ATOM 120 CA GLY U 43 49.716 33.742 4.809 1.00 30.00 UNK C +ATOM 124 CA MET U 44 50.275 36.496 3.408 1.00 30.00 UNK C +ATOM 132 CA ARG U 51 66.471 31.618 0.165 1.00 30.00 UNK C +ATOM 143 CA THR U 52 62.673 32.286 0.000 1.00 30.00 UNK C +ATOM 150 CA TRP U 53 60.396 33.791 2.514 1.00 30.00 UNK C +ATOM 164 CA PRO U 54 56.975 33.518 4.059 1.00 30.00 UNK C +ATOM 171 CA GLY U 55 56.742 37.050 3.683 1.00 30.00 UNK C +ATOM 175 CA HIS U 56 58.241 37.385 0.677 1.00 30.00 UNK C +ATOM 185 CA GLY U 57 60.259 36.521 -2.061 1.00 30.00 UNK C +ATOM 189 CA TRP U 58 63.306 36.585 -0.658 1.00 30.00 UNK C +ATOM 203 CA HIS U 59 66.371 36.917 -1.353 1.00 30.00 UNK C +ATOM 213 CA ARG U 71 33.885 27.955 5.046 1.00 30.00 UNK C +ATOM 224 CA PRO U 72 34.112 31.066 3.070 1.00 30.00 UNK C +ATOM 231 CA GLY U 73 37.023 30.068 0.698 1.00 30.00 UNK C +ATOM 235 CA ASN U 74 40.330 31.142 0.443 1.00 30.00 UNK C +ATOM 243 CA GLY U 75 39.883 28.291 -1.998 1.00 30.00 UNK C +ATOM 247 CA ALA U 76 40.699 29.754 -4.736 1.00 30.00 UNK C +ATOM 252 CA TYR U 77 42.908 31.262 -3.328 1.00 30.00 UNK C +ATOM 264 CA GLY U 78 44.842 29.020 -1.084 1.00 30.00 UNK C +ATOM 268 CA ALA U 79 46.698 27.855 -3.383 1.00 30.00 UNK C +ATOM 273 CA VAL U 91 51.081 32.321 8.150 1.00 30.00 UNK C +ATOM 280 CA ARG U 92 51.757 33.221 11.457 1.00 30.00 UNK C +ATOM 291 CA TYR U 93 53.177 35.451 14.207 1.00 30.00 UNK C +ATOM 303 CA GLY U 94 55.930 33.240 16.341 1.00 30.00 UNK C +ATOM 307 CA LYS U 95 56.538 31.836 13.500 1.00 30.00 UNK C +ATOM 316 CA GLU U 96 53.605 29.086 13.128 1.00 30.00 UNK C +ATOM 325 CA TRP U 97 52.331 28.161 9.983 1.00 30.00 UNK C +ATOM 339 CA ASP U 98 49.378 26.104 9.729 1.00 30.00 UNK C +ATOM 347 CA GLU U 99 47.812 25.689 7.165 1.00 30.00 UNK C +ATOM 356 CA GLY U 111 34.962 41.965 -2.040 1.00 30.00 UNK C +ATOM 360 CA GLY U 112 34.552 41.382 1.896 1.00 30.00 UNK C +ATOM 364 CA PHE U 113 32.652 38.617 2.536 1.00 30.00 UNK C +ATOM 375 CA GLY U 114 33.035 35.430 1.690 1.00 30.00 UNK C +ATOM 379 CA LEU U 115 31.413 34.883 5.090 1.00 30.00 UNK C +ATOM 387 CA SER U 116 29.190 32.919 6.131 1.00 30.00 UNK C +ATOM 393 CA LEU U 117 25.231 33.701 6.955 1.00 30.00 UNK C +ATOM 401 CA PRO U 118 24.358 32.286 10.112 1.00 30.00 UNK C +ATOM 408 CA TYR U 119 26.935 34.425 10.677 1.00 30.00 UNK C +ATOM 420 CA GLY U 131 38.770 41.005 4.746 1.00 30.00 UNK C +ATOM 424 CA GLN U 132 39.116 39.652 2.001 1.00 30.00 UNK C +ATOM 433 CA TRP U 133 36.781 37.434 3.332 1.00 30.00 UNK C +ATOM 447 CA TYR U 134 37.051 34.918 6.022 1.00 30.00 UNK C +ATOM 459 CA ALA U 135 34.718 33.052 8.152 1.00 30.00 UNK C +ATOM 464 CA CYS U 136 35.953 32.045 10.889 1.00 30.00 UNK C +ATOM 470 CA GLY U 137 37.106 29.541 8.056 1.00 30.00 UNK C +ATOM 474 CA TYR U 138 39.250 29.269 5.412 1.00 30.00 UNK C +""" + +pdb_str_model1=""" +CRYST1 113.949 113.949 32.474 90.00 90.00 90.00 I 4 +ATOM 1 CA LYS A 4 109.976 18.221 44.266 1.00 48.61 P9 +ATOM 2 CA TRP A 5 109.182 21.755 43.110 1.00 47.90 P9 +ATOM 3 CA VAL A 6 110.823 23.654 40.250 1.00 46.89 P9 +ATOM 4 CA MET A 7 108.936 26.802 39.218 1.00 45.06 P9 +ATOM 5 CA SER A 8 105.419 28.211 39.036 1.00 41.81 P9 +ATOM 6 CA THR A 9 103.906 27.616 35.600 1.00 37.71 P9 +ATOM 7 CA LYS A 10 103.277 30.858 33.696 1.00 33.20 P9 +ATOM 8 CA TYR A 11 100.215 31.269 31.467 1.00 29.03 P9 +ATOM 9 CA VAL A 12 98.628 33.636 28.957 1.00 24.81 P9 +ATOM 10 CA GLU A 13 95.372 33.451 27.024 1.00 21.62 P9 +ATOM 11 CA ALA A 14 95.648 31.766 23.627 1.00 21.34 P9 +ATOM 12 CA GLY A 15 94.222 34.881 22.004 1.00 22.33 P9 +ATOM 13 CA GLU A 16 97.221 36.890 23.214 1.00 23.17 P9 +ATOM 14 CA LEU A 17 99.807 34.753 21.414 1.00 23.42 P9 +ATOM 15 CA LYS A 18 101.429 36.062 18.237 1.00 24.53 P9 +ATOM 16 CA GLU A 19 103.948 34.832 15.691 1.00 24.34 P9 +ATOM 17 CA GLY A 20 107.227 34.699 17.578 1.00 22.47 P9 +ATOM 18 CA SER A 21 105.632 33.977 20.956 1.00 20.20 P9 +ATOM 19 CA TYR A 22 106.668 30.890 22.912 1.00 19.09 P9 +ATOM 20 CA VAL A 23 104.283 28.225 24.176 1.00 18.63 P9 +ATOM 21 CA VAL A 24 104.403 24.711 25.602 1.00 16.73 P9 +ATOM 22 CA ILE A 25 102.485 22.073 23.645 1.00 16.21 P9 +ATOM 23 CA ASP A 26 102.424 18.531 25.042 1.00 17.02 P9 +ATOM 24 CA GLY A 27 105.535 19.131 27.135 1.00 19.18 P9 +ATOM 25 CA GLU A 28 107.647 20.739 24.398 1.00 18.42 P9 +ATOM 26 CA PRO A 29 108.490 24.457 24.454 1.00 17.13 P9 +ATOM 27 CA CYS A 30 107.738 25.793 20.958 1.00 18.27 P9 +ATOM 28 CA ARG A 31 108.013 29.010 18.950 1.00 18.81 P9 +ATOM 29 CA VAL A 32 104.720 30.074 17.348 1.00 18.68 P9 +ATOM 30 CA VAL A 33 104.990 30.324 13.554 1.00 21.62 P9 +ATOM 31 CA GLU A 34 101.337 30.903 12.676 1.00 22.97 P9 +ATOM 32 CA ILE A 35 97.990 31.567 14.325 1.00 23.13 P9 +ATOM 33 CA GLU A 36 94.516 31.390 12.807 1.00 22.64 P9 +ATOM 34 CA LYS A 37 91.314 32.656 14.422 1.00 21.25 P9 +ATOM 35 CA SER A 38 87.754 31.489 13.758 1.00 20.23 P9 +ATOM 36 CA LYS A 39 84.259 31.708 15.215 1.00 22.33 P9 +ATOM 37 CA THR A 40 81.571 29.194 14.236 1.00 25.52 P9 +ATOM 38 CA GLY A 41 79.184 29.756 17.114 0.93 29.60 P9 +ATOM 39 CA LYS A 42 76.787 32.652 16.597 0.89 32.20 P9 +ATOM 40 CA HIS A 43 77.170 33.509 20.288 1.00 31.87 P9 +ATOM 41 CA GLY A 44 80.141 31.264 20.999 0.65 28.63 P9 +ATOM 42 CA SER A 45 83.784 31.911 21.813 1.00 23.69 P9 +ATOM 43 CA ALA A 46 86.373 32.582 19.132 1.00 18.89 P9 +ATOM 44 CA LYS A 47 88.902 29.776 18.670 1.00 17.38 P9 +ATOM 45 CA ALA A 48 92.611 29.914 17.899 1.00 17.02 P9 +ATOM 46 CA ARG A 49 94.612 27.386 15.893 1.00 17.11 P9 +ATOM 47 CA ILE A 50 98.284 27.635 16.768 1.00 17.68 P9 +ATOM 48 CA VAL A 51 101.124 26.174 14.718 1.00 17.34 P9 +ATOM 49 CA ALA A 52 104.518 26.094 16.413 1.00 17.71 P9 +ATOM 50 CA VAL A 53 107.935 24.470 16.254 1.00 17.54 P9 +ATOM 51 CA GLY A 54 109.704 22.649 19.055 1.00 18.35 P9 +ATOM 52 CA VAL A 55 112.688 24.550 20.407 1.00 19.01 P9 +ATOM 53 CA PHE A 56 114.509 21.294 21.108 1.00 19.90 P9 +ATOM 54 CA ASP A 57 113.198 18.603 18.749 1.00 21.17 P9 +ATOM 55 CA GLY A 58 112.293 20.976 15.923 1.00 21.69 P9 +ATOM 56 CA GLY A 59 108.988 19.187 15.479 1.00 21.62 P9 +ATOM 57 CA LYS A 60 105.864 20.872 14.151 1.00 20.30 P9 +ATOM 58 CA ARG A 61 103.024 20.971 16.667 1.00 18.60 P9 +ATOM 59 CA THR A 62 99.517 22.398 16.607 1.00 17.44 P9 +ATOM 60 CA LEU A 63 96.998 23.440 19.242 1.00 16.19 P9 +ATOM 61 CA SER A 64 93.370 24.446 18.716 1.00 15.39 P9 +ATOM 62 CA LEU A 65 91.433 25.924 21.644 1.00 14.67 P9 +ATOM 63 CA PRO A 66 89.260 28.905 22.730 1.00 14.79 P9 +ATOM 64 CA VAL A 67 90.940 32.325 22.634 1.00 15.74 P9 +ATOM 65 CA ASP A 68 90.325 32.738 26.369 1.00 17.10 P9 +ATOM 66 CA ALA A 69 91.793 29.371 27.372 1.00 16.26 P9 +ATOM 67 CA GLN A 70 95.115 29.425 29.223 1.00 18.00 P9 +ATOM 68 CA VAL A 71 98.237 28.190 27.463 1.00 19.41 P9 +ATOM 69 CA GLU A 72 101.563 27.596 29.201 1.00 21.29 P9 +ATOM 70 CA VAL A 73 104.492 29.822 28.262 1.00 21.83 P9 +ATOM 71 CA PRO A 74 108.047 28.603 28.963 0.94 22.19 P9 +ATOM 72 CA ILE A 75 110.436 30.660 31.072 1.00 23.67 P9 +ATOM 73 CA ILE A 76 113.508 31.336 28.943 0.96 24.46 P9 +ATOM 74 CA GLU A 77 116.735 32.457 30.611 1.00 24.69 P9 +ATOM 75 CA LYS A 78 119.294 33.935 28.213 1.00 24.12 P9 +ATOM 76 CA PHE A 79 123.013 34.160 28.959 1.00 21.39 P9 +ATOM 77 CA THR A 80 126.479 34.196 27.404 1.00 19.30 P9 +ATOM 78 CA ALA A 81 128.958 31.320 27.436 1.00 17.03 P9 +ATOM 79 CA GLN A 82 132.421 30.668 25.993 1.00 15.83 P9 +ATOM 80 CA ILE A 83 133.128 27.536 23.964 1.00 14.35 P9 +ATOM 81 CA LEU A 84 135.770 25.349 25.639 1.00 14.01 P9 +ATOM 82 CA SER A 85 135.720 22.442 23.163 1.00 14.77 P9 +ATOM 83 CA VAL A 86 133.697 21.017 20.292 1.00 15.76 P9 +ATOM 84 CA SER A 87 133.246 17.344 19.410 1.00 15.97 P9 +ATOM 85 CA GLY A 88 130.905 15.871 16.836 1.00 16.65 P9 +ATOM 86 CA ASP A 89 128.352 15.243 19.587 1.00 17.36 P9 +ATOM 87 CA VAL A 90 128.894 17.746 22.389 1.00 16.73 P9 +ATOM 88 CA ILE A 91 129.780 21.401 22.870 1.00 16.05 P9 +ATOM 89 CA GLN A 92 131.584 22.059 26.178 1.00 16.32 P9 +ATOM 90 CA LEU A 93 130.870 25.590 27.465 1.00 15.69 P9 +ATOM 91 CA MET A 94 131.982 27.904 30.270 1.00 17.32 P9 +ATOM 92 CA ASP A 95 129.006 29.830 31.697 1.00 19.94 P9 +ATOM 93 CA MET A 96 130.333 33.412 31.817 1.00 22.68 P9 +ATOM 94 CA ARG A 97 128.065 34.204 34.767 1.00 24.59 P9 +ATOM 95 CA ASP A 98 129.544 31.755 37.283 0.96 24.84 P9 +ATOM 96 CA TYR A 99 132.285 30.135 35.175 0.99 24.06 P9 +ATOM 97 CA LYS A 100 130.841 26.625 35.550 1.00 22.14 P9 +ATOM 98 CA THR A 101 131.149 24.064 32.761 1.00 20.84 P9 +ATOM 99 CA ILE A 102 127.988 23.035 30.916 1.00 19.78 P9 +ATOM 100 CA GLU A 103 127.678 20.418 28.177 1.00 19.97 P9 +ATOM 101 CA VAL A 104 125.251 20.963 25.299 1.00 18.00 P9 +ATOM 102 CA PRO A 105 124.362 18.242 22.754 1.00 18.24 P9 +ATOM 103 CA MET A 106 125.166 19.138 19.128 1.00 18.91 P9 +ATOM 104 CA LYS A 107 121.491 18.558 18.303 1.00 19.94 P9 +ATOM 105 CA TYR A 108 120.616 21.558 20.496 1.00 20.72 P9 +ATOM 106 CA VAL A 109 122.621 24.018 18.411 1.00 23.20 P9 +ATOM 107 CA GLU A 110 120.751 26.260 15.961 1.00 28.03 P9 +ATOM 108 CA GLU A 111 121.704 25.099 12.460 0.74 31.85 P9 +ATOM 109 CA GLU A 112 122.954 28.554 11.512 1.00 33.44 P9 +ATOM 110 CA ALA A 113 125.368 28.615 14.458 1.00 31.90 P9 +ATOM 111 CA LYS A 114 126.911 25.180 13.906 0.92 31.27 P9 +ATOM 112 CA GLY A 115 129.136 26.579 11.174 1.00 30.17 P9 +ATOM 113 CA ARG A 116 130.956 29.004 13.463 1.00 27.89 P9 +ATOM 114 CA LEU A 117 131.365 26.777 16.514 1.00 25.28 P9 +ATOM 115 CA ALA A 118 134.998 27.063 17.578 1.00 23.01 P9 +ATOM 116 CA PRO A 119 136.912 26.997 20.869 1.00 21.21 P9 +ATOM 117 CA GLY A 120 137.158 30.500 22.308 1.00 21.69 P9 +ATOM 118 CA ALA A 121 134.046 31.875 20.620 1.00 21.58 P9 +ATOM 119 CA GLU A 122 131.240 33.298 22.745 1.00 22.41 P9 +ATOM 120 CA VAL A 123 127.678 32.132 22.205 1.00 20.97 P9 +ATOM 121 CA GLU A 124 124.171 33.150 23.219 1.00 20.32 P9 +ATOM 122 CA VAL A 125 122.627 30.323 25.229 1.00 19.82 P9 +ATOM 123 CA TRP A 126 119.012 29.745 26.239 1.00 21.08 P9 +ATOM 124 CA GLN A 127 118.027 27.643 29.216 1.00 22.22 P9 +ATOM 125 CA ILE A 128 114.538 26.200 29.585 1.00 22.80 P9 +ATOM 126 CA LEU A 129 114.153 24.029 32.671 1.00 24.59 P9 +ATOM 127 CA ASP A 130 117.058 21.551 32.616 0.99 24.90 P9 +ATOM 128 CA ARG A 131 117.952 21.918 28.938 1.00 22.57 P9 +ATOM 129 CA TYR A 132 120.128 24.357 27.016 1.00 21.18 P9 +ATOM 130 CA LYS A 133 120.153 25.537 23.432 1.00 21.22 P9 +ATOM 131 CA ILE A 134 122.957 27.373 21.662 1.00 20.82 P9 +ATOM 132 CA ILE A 135 121.298 30.133 19.637 1.00 24.27 P9 +ATOM 133 CA ARG A 136 124.175 31.872 17.866 1.00 28.80 P9 +ATOM 134 CA VAL A 137 127.877 32.680 17.955 1.00 32.92 P9 +ATOM 135 CA LYS A 138 128.895 35.931 19.718 1.00 36.89 P9 +ATOM 136 CA GLY A 139 126.242 36.878 22.264 0.67 38.21 P9 +ATOM 1 CA LYS B 4 514.976 423.221 449.266 1.00 48.61 P9 +ATOM 2 CA TRP B 5 514.182 426.755 448.110 1.00 47.90 P9 +ATOM 3 CA VAL B 6 515.823 428.654 445.250 1.00 46.89 P9 +ATOM 4 CA MET B 7 513.936 431.802 444.218 1.00 45.06 P9 +ATOM 5 CA SER B 8 510.419 433.211 444.036 1.00 41.81 P9 +ATOM 6 CA THR B 9 508.906 432.616 440.600 1.00 37.71 P9 +ATOM 7 CA LYS B 10 508.277 435.858 438.696 1.00 33.20 P9 +ATOM 8 CA TYR B 11 505.215 436.269 436.467 1.00 29.03 P9 +ATOM 9 CA VAL B 12 503.628 438.636 433.957 1.00 24.81 P9 +ATOM 10 CA GLU B 13 500.372 438.451 432.024 1.00 21.62 P9 +ATOM 11 CA ALA B 14 500.648 436.766 428.627 1.00 21.34 P9 +ATOM 12 CA GLY B 15 499.222 439.881 427.004 1.00 22.33 P9 +ATOM 13 CA GLU B 16 502.221 441.890 428.214 1.00 23.17 P9 +ATOM 14 CA LEU B 17 504.807 439.753 426.414 1.00 23.42 P9 +ATOM 15 CA LYS B 18 506.429 441.062 423.237 1.00 24.53 P9 +ATOM 16 CA GLU B 19 508.948 439.832 420.691 1.00 24.34 P9 +ATOM 17 CA GLY B 20 512.227 439.699 422.578 1.00 22.47 P9 +ATOM 18 CA SER B 21 510.632 438.977 425.956 1.00 20.20 P9 +ATOM 19 CA TYR B 22 511.668 435.890 427.912 1.00 19.09 P9 +ATOM 20 CA VAL B 23 509.283 433.225 429.176 1.00 18.63 P9 +ATOM 21 CA VAL B 24 509.403 429.711 430.602 1.00 16.73 P9 +ATOM 22 CA ILE B 25 507.485 427.073 428.645 1.00 16.21 P9 +ATOM 23 CA ASP B 26 507.424 423.531 430.042 1.00 17.02 P9 +ATOM 24 CA GLY B 27 510.535 424.131 432.135 1.00 19.18 P9 +ATOM 25 CA GLU B 28 512.647 425.739 429.398 1.00 18.42 P9 +ATOM 26 CA PRO B 29 513.490 429.457 429.454 1.00 17.13 P9 +ATOM 27 CA CYS B 30 512.738 430.793 425.958 1.00 18.27 P9 +ATOM 28 CA ARG B 31 513.013 434.010 423.950 1.00 18.81 P9 +ATOM 29 CA VAL B 32 509.720 435.074 422.348 1.00 18.68 P9 +ATOM 30 CA VAL B 33 509.990 435.324 418.554 1.00 21.62 P9 +ATOM 31 CA GLU B 34 506.337 435.903 417.676 1.00 22.97 P9 +ATOM 32 CA ILE B 35 502.990 436.567 419.325 1.00 23.13 P9 +ATOM 33 CA GLU B 36 499.516 436.390 417.807 1.00 22.64 P9 +ATOM 34 CA LYS B 37 496.314 437.656 419.422 1.00 21.25 P9 +ATOM 35 CA SER B 38 492.754 436.489 418.758 1.00 20.23 P9 +ATOM 36 CA LYS B 39 489.259 436.708 420.215 1.00 22.33 P9 +ATOM 37 CA THR B 40 486.571 434.194 419.236 1.00 25.52 P9 +ATOM 38 CA GLY B 41 484.184 434.756 422.114 0.93 29.60 P9 +ATOM 39 CA LYS B 42 481.787 437.652 421.597 0.89 32.20 P9 +ATOM 40 CA HIS B 43 482.170 438.509 425.288 1.00 31.87 P9 +ATOM 41 CA GLY B 44 485.141 436.264 425.999 0.65 28.63 P9 +ATOM 42 CA SER B 45 488.784 436.911 426.813 1.00 23.69 P9 +ATOM 43 CA ALA B 46 491.373 437.582 424.132 1.00 18.89 P9 +ATOM 44 CA LYS B 47 493.902 434.776 423.670 1.00 17.38 P9 +ATOM 45 CA ALA B 48 497.611 434.914 422.899 1.00 17.02 P9 +ATOM 46 CA ARG B 49 499.612 432.386 420.893 1.00 17.11 P9 +ATOM 47 CA ILE B 50 503.284 432.635 421.768 1.00 17.68 P9 +ATOM 48 CA VAL B 51 506.124 431.174 419.718 1.00 17.34 P9 +ATOM 49 CA ALA B 52 509.518 431.094 421.413 1.00 17.71 P9 +ATOM 50 CA VAL B 53 512.935 429.470 421.254 1.00 17.54 P9 +ATOM 51 CA GLY B 54 514.704 427.649 424.055 1.00 18.35 P9 +ATOM 52 CA VAL B 55 517.688 429.550 425.407 1.00 19.01 P9 +ATOM 53 CA PHE B 56 519.509 426.294 426.108 1.00 19.90 P9 +ATOM 54 CA ASP B 57 518.198 423.603 423.749 1.00 21.17 P9 +ATOM 55 CA GLY B 58 517.293 425.976 420.923 1.00 21.69 P9 +ATOM 56 CA GLY B 59 513.988 424.187 420.479 1.00 21.62 P9 +ATOM 57 CA LYS B 60 510.864 425.872 419.151 1.00 20.30 P9 +ATOM 58 CA ARG B 61 508.024 425.971 421.667 1.00 18.60 P9 +ATOM 59 CA THR B 62 504.517 427.398 421.607 1.00 17.44 P9 +ATOM 60 CA LEU B 63 501.998 428.440 424.242 1.00 16.19 P9 +ATOM 61 CA SER B 64 498.370 429.446 423.716 1.00 15.39 P9 +ATOM 62 CA LEU B 65 496.433 430.924 426.644 1.00 14.67 P9 +ATOM 63 CA PRO B 66 494.260 433.905 427.730 1.00 14.79 P9 +ATOM 64 CA VAL B 67 495.940 437.325 427.634 1.00 15.74 P9 +ATOM 65 CA ASP B 68 495.325 437.738 431.369 1.00 17.10 P9 +ATOM 66 CA ALA B 69 496.793 434.371 432.372 1.00 16.26 P9 +ATOM 67 CA GLN B 70 500.115 434.425 434.223 1.00 18.00 P9 +ATOM 68 CA VAL B 71 503.237 433.190 432.463 1.00 19.41 P9 +ATOM 69 CA GLU B 72 506.563 432.596 434.201 1.00 21.29 P9 +ATOM 70 CA VAL B 73 509.492 434.822 433.262 1.00 21.83 P9 +ATOM 71 CA PRO B 74 513.047 433.603 433.963 0.94 22.19 P9 +ATOM 72 CA ILE B 75 515.436 435.660 436.072 1.00 23.67 P9 +ATOM 73 CA ILE B 76 518.508 436.336 433.943 0.96 24.46 P9 +ATOM 74 CA GLU B 77 521.735 437.457 435.611 1.00 24.69 P9 +ATOM 75 CA LYS B 78 524.294 438.935 433.213 1.00 24.12 P9 +ATOM 76 CA PHE B 79 528.013 439.160 433.959 1.00 21.39 P9 +ATOM 77 CA THR B 80 531.479 439.196 432.404 1.00 19.30 P9 +ATOM 78 CA ALA B 81 533.958 436.320 432.436 1.00 17.03 P9 +ATOM 79 CA GLN B 82 537.421 435.668 430.993 1.00 15.83 P9 +ATOM 80 CA ILE B 83 538.128 432.536 428.964 1.00 14.35 P9 +ATOM 81 CA LEU B 84 540.770 430.349 430.639 1.00 14.01 P9 +ATOM 82 CA SER B 85 540.720 427.442 428.163 1.00 14.77 P9 +ATOM 83 CA VAL B 86 538.697 426.017 425.292 1.00 15.76 P9 +ATOM 84 CA SER B 87 538.246 422.344 424.410 1.00 15.97 P9 +ATOM 85 CA GLY B 88 535.905 420.871 421.836 1.00 16.65 P9 +ATOM 86 CA ASP B 89 533.352 420.243 424.587 1.00 17.36 P9 +ATOM 87 CA VAL B 90 533.894 422.746 427.389 1.00 16.73 P9 +ATOM 88 CA ILE B 91 534.780 426.401 427.870 1.00 16.05 P9 +ATOM 89 CA GLN B 92 536.584 427.059 431.178 1.00 16.32 P9 +ATOM 90 CA LEU B 93 535.870 430.590 432.465 1.00 15.69 P9 +ATOM 91 CA MET B 94 536.982 432.904 435.270 1.00 17.32 P9 +ATOM 92 CA ASP B 95 534.006 434.830 436.697 1.00 19.94 P9 +ATOM 93 CA MET B 96 535.333 438.412 436.817 1.00 22.68 P9 +ATOM 94 CA ARG B 97 533.065 439.204 439.767 1.00 24.59 P9 +ATOM 95 CA ASP B 98 534.544 436.755 442.283 0.96 24.84 P9 +ATOM 96 CA TYR B 99 537.285 435.135 440.175 0.99 24.06 P9 +ATOM 97 CA LYS B 100 535.841 431.625 440.550 1.00 22.14 P9 +ATOM 98 CA THR B 101 536.149 429.064 437.761 1.00 20.84 P9 +ATOM 99 CA ILE B 102 532.988 428.035 435.916 1.00 19.78 P9 +ATOM 100 CA GLU B 103 532.678 425.418 433.177 1.00 19.97 P9 +ATOM 101 CA VAL B 104 530.251 425.963 430.299 1.00 18.00 P9 +ATOM 102 CA PRO B 105 529.362 423.242 427.754 1.00 18.24 P9 +ATOM 103 CA MET B 106 530.166 424.138 424.128 1.00 18.91 P9 +ATOM 104 CA LYS B 107 526.491 423.558 423.303 1.00 19.94 P9 +ATOM 105 CA TYR B 108 525.616 426.558 425.496 1.00 20.72 P9 +ATOM 106 CA VAL B 109 527.621 429.018 423.411 1.00 23.20 P9 +ATOM 107 CA GLU B 110 525.751 431.260 420.961 1.00 28.03 P9 +ATOM 108 CA GLU B 111 526.704 430.099 417.460 0.74 31.85 P9 +ATOM 109 CA GLU B 112 527.954 433.554 416.512 1.00 33.44 P9 +ATOM 110 CA ALA B 113 530.368 433.615 419.458 1.00 31.90 P9 +ATOM 111 CA LYS B 114 531.911 430.180 418.906 0.92 31.27 P9 +ATOM 112 CA GLY B 115 534.136 431.579 416.174 1.00 30.17 P9 +ATOM 113 CA ARG B 116 535.956 434.004 418.463 1.00 27.89 P9 +ATOM 114 CA LEU B 117 536.365 431.777 421.514 1.00 25.28 P9 +ATOM 115 CA ALA B 118 539.998 432.063 422.578 1.00 23.01 P9 +ATOM 116 CA PRO B 119 541.912 431.997 425.869 1.00 21.21 P9 +ATOM 117 CA GLY B 120 542.158 435.500 427.308 1.00 21.69 P9 +ATOM 118 CA ALA B 121 539.046 436.875 425.620 1.00 21.58 P9 +ATOM 119 CA GLU B 122 536.240 438.298 427.745 1.00 22.41 P9 +ATOM 120 CA VAL B 123 532.678 437.132 427.205 1.00 20.97 P9 +ATOM 121 CA GLU B 124 529.171 438.150 428.219 1.00 20.32 P9 +ATOM 122 CA VAL B 125 527.627 435.323 430.229 1.00 19.82 P9 +ATOM 123 CA TRP B 126 524.012 434.745 431.239 1.00 21.08 P9 +ATOM 124 CA GLN B 127 523.027 432.643 434.216 1.00 22.22 P9 +ATOM 125 CA ILE B 128 519.538 431.200 434.585 1.00 22.80 P9 +ATOM 126 CA LEU B 129 519.153 429.029 437.671 1.00 24.59 P9 +ATOM 127 CA ASP B 130 522.058 426.551 437.616 0.99 24.90 P9 +ATOM 128 CA ARG B 131 522.952 426.918 433.938 1.00 22.57 P9 +ATOM 129 CA TYR B 132 525.128 429.357 432.016 1.00 21.18 P9 +ATOM 130 CA LYS B 133 525.153 430.537 428.432 1.00 21.22 P9 +ATOM 131 CA ILE B 134 527.957 432.373 426.662 1.00 20.82 P9 +ATOM 132 CA ILE B 135 526.298 435.133 424.637 1.00 24.27 P9 +ATOM 133 CA ARG B 136 529.175 436.872 422.866 1.00 28.80 P9 +ATOM 134 CA VAL B 137 532.877 437.680 422.955 1.00 32.92 P9 +ATOM 135 CA LYS B 138 533.895 440.931 424.718 1.00 36.89 P9 +ATOM 136 CA GLY B 139 531.242 441.878 427.264 0.67 38.21 P9 +""" + +pdb_str_target=""" +CRYST1 113.949 113.949 32.474 90.00 90.00 90.00 I 4 +ATOM 9 CA LYS U 4 109.976 18.221 44.266 1.00 48.61 P9 +ATOM 11 CA TRP U 5 109.182 21.755 43.110 1.00 47.90 P9 +ATOM 25 CA VAL U 6 110.823 23.654 40.250 1.00 46.89 P9 +ATOM 32 CA MET U 7 108.936 26.802 39.218 1.00 45.06 P9 +""" + +pdb_str_modela=""" +CRYST1 113.949 113.949 32.474 90.00 90.00 90.00 I 4 +ATOM 9 CA LYS A 4 109.976 18.221 44.266 1.00 48.61 P9 +ATOM 11 CA TRP A 5 109.182 21.755 43.110 1.00 47.90 P9 +ATOM 25 CA VAL A 6 110.823 23.654 40.250 1.00 46.89 P9 +ATOM 32 CA MET A 7 108.936 26.802 39.218 1.00 45.06 P9 +""" +pdb_str_modelb=""" +ATOM 40 CA SER B 8 205.419 28.211 39.036 1.00 41.81 P9 +ATOM 46 CA THR B 9 203.906 27.616 35.600 1.00 37.71 P9 +ATOM 53 CA LYS B 10 203.277 30.858 33.696 1.00 33.20 P9 +ATOM 62 CA TYR B 11 200.215 31.269 31.467 1.00 29.03 P9 +""" + +pdb_str_modelaa=""" +ATOM 9 CA LYS A 4 109.976 18.221 44.266 1.00 48.61 P9 +ATOM 11 CA TRP A 5 109.182 21.755 43.110 1.00 47.90 P9 +ATOM 25 CA VAL A 6 110.823 23.654 40.250 1.00 46.89 P9 +ATOM 32 CA MET A 7 108.936 26.802 39.218 1.00 45.06 P9 +ATOM 9 CA LYS C 14 209.976 18.221 44.266 1.00 48.61 P9 +ATOM 11 CA TRP C 15 209.182 21.755 43.110 1.00 47.90 P9 +ATOM 15 CA VAL C 16 210.823 23.654 40.250 1.00 46.89 P9 +ATOM 32 CA MET C 17 208.936 26.802 39.218 1.00 45.06 P9 +""" + +pdb_str_modelaab=""" +ATOM 9 CA LYS A 4 109.976 18.221 44.266 1.00 48.61 P9 +ATOM 11 CA TRP A 5 109.182 21.755 43.110 1.00 47.90 P9 +ATOM 25 CA VAL A 6 110.823 23.654 40.250 1.00 46.89 P9 +ATOM 32 CA MET A 7 108.936 26.802 39.218 1.00 45.06 P9 +ATOM 9 CA LYS C 14 209.976 18.221 44.266 1.00 48.61 P9 +ATOM 11 CA TRP C 15 209.182 21.755 43.110 1.00 47.90 P9 +ATOM 15 CA VAL C 16 210.823 23.654 40.250 1.00 46.89 P9 +ATOM 32 CA MET C 17 208.936 26.802 39.218 1.00 45.06 P9 +ATOM 40 CA SER B 8 205.419 28.211 39.036 1.00 41.81 P9 +ATOM 46 CA THR B 9 203.906 27.616 35.600 1.00 37.71 P9 +ATOM 53 CA LYS B 10 203.277 30.858 33.696 1.00 33.20 P9 +ATOM 62 CA TYR B 11 200.215 31.269 31.467 1.00 29.03 P9 +""" + +pdb_str_modelaabaab=""" +ATOM 9 CA LYS A 4 109.976 18.221 44.266 1.00 48.61 P9 +ATOM 11 CA TRP A 5 109.182 21.755 43.110 1.00 47.90 P9 +ATOM 25 CA VAL A 6 110.823 23.654 40.250 1.00 46.89 P9 +ATOM 32 CA MET A 7 108.936 26.802 39.218 1.00 45.06 P9 +ATOM 9 CA LYS C 14 209.976 18.221 44.266 1.00 48.61 P9 +ATOM 11 CA TRP C 15 209.182 21.755 43.110 1.00 47.90 P9 +ATOM 15 CA VAL C 16 210.823 23.654 40.250 1.00 46.89 P9 +ATOM 32 CA MET C 17 208.936 26.802 39.218 1.00 45.06 P9 +ATOM 40 CA SER B 8 205.419 28.211 39.036 1.00 41.81 P9 +ATOM 46 CA THR B 9 203.906 27.616 35.600 1.00 37.71 P9 +ATOM 53 CA LYS B 10 203.277 30.858 33.696 1.00 33.20 P9 +ATOM 62 CA TYR B 11 200.215 31.269 31.467 1.00 29.03 P9 +ATOM 9 CA LYS F 4 109.976 118.221 44.266 1.00 48.61 P9 +ATOM 11 CA TRP F 5 109.182 121.755 43.110 1.00 47.90 P9 +ATOM 25 CA VAL F 6 110.823 123.654 40.250 1.00 46.89 P9 +ATOM 32 CA MET F 7 108.936 126.802 39.218 1.00 45.06 P9 +ATOM 9 CA LYS H 14 209.976 118.221 44.266 1.00 48.61 P9 +ATOM 11 CA TRP H 15 209.182 121.755 43.110 1.00 47.90 P9 +ATOM 15 CA VAL H 16 210.823 123.654 40.250 1.00 46.89 P9 +ATOM 32 CA MET H 17 208.936 126.802 39.218 1.00 45.06 P9 +ATOM 40 CA SER G 8 205.419 128.211 39.036 1.00 41.81 P9 +ATOM 46 CA THR G 9 203.906 127.616 35.600 1.00 37.71 P9 +ATOM 53 CA LYS G 10 203.277 130.858 33.696 1.00 33.20 P9 +ATOM 62 CA TYR G 11 200.215 131.269 31.467 1.00 29.03 P9 +""" + +# Convert to mmcif: +chain_addition = "XZLONG" +from libtbx.test_utils import convert_pdb_to_cif_for_pdb_str +convert_pdb_to_cif_for_pdb_str(locals(),chain_addition=chain_addition) + +def tst_01(): + print("Comparing mixed model with target...") + import iotbx.pdb + from cctbx.array_family import flex + model_pdb_inp=iotbx.pdb.input(source_info='model', + lines=flex.split_lines(pdb_str_model)) + crystal_symmetry=model_pdb_inp.crystal_symmetry() + model_hierarchy=model_pdb_inp.construct_hierarchy() + query_hierarchy=iotbx.pdb.input(source_info='query', + lines=flex.split_lines(pdb_str_query)).construct_hierarchy() + + f=StringIO() + r=run(crystal_symmetry=crystal_symmetry, + chain_hierarchy=query_hierarchy,target_hierarchy=model_hierarchy,out=f) + expected_text=\ +"""SEQ SCORE is fraction (close and matching target sequence). +MEAN LENGTH is the mean length of contiguous segments in the match with target sequence. (Each gap/reverse of direction starts new segment). + + + + ----ALL RESIDUES--- CLOSE RESIDUES ONLY % + MODEL --CLOSE- --FAR-- FORWARD REVERSE MIXED FOUND CA SEQ + RMSD N N N N N SCORE SEQ MATCH(%) SCORE MEAN LENGTH FRAGMENTS BAD CONNECTIONS + + Unique_target 1.55 54 7 14 29 11 39.7 0.26 9.3 0.04 6.0 7 6""" + found_text="\n".join(f.getvalue().splitlines()[-10:]) + if remove_blank(found_text)!=remove_blank(expected_text): + print("Expected: \n%s \nFound: \n%s" %(expected_text,found_text)) + raise AssertionError("FAILED") + from libtbx.test_utils import approx_equal + print(r.get_values("forward")) + assert approx_equal(r.get_values("forward"),(1.6751069901864204, 14)) + print(r.get_values("reverse")) + assert approx_equal(r.get_values("reverse"),(1.388466550576198, 29)) + print(r.get_values("close")) + assert approx_equal(r.get_values("close"),(1.545835235099158, 54)) + print(r.get_values("all_far")) + assert approx_equal(r.get_values("all_far"),(0,0)) + print("OK") + +def tst_02(): + print("Comparing mixed model with target with 2 chains...") + import iotbx.pdb + from cctbx.array_family import flex + model_pdb_inp=iotbx.pdb.input(source_info='model', + lines=flex.split_lines(pdb_str_model1)) + crystal_symmetry=model_pdb_inp.crystal_symmetry() + model_hierarchy=model_pdb_inp.construct_hierarchy() + query_hierarchy=iotbx.pdb.input(source_info='query', + lines=flex.split_lines(pdb_str_query)).construct_hierarchy() + f=StringIO() + r=run(crystal_symmetry=crystal_symmetry, + chain_hierarchy=query_hierarchy,target_hierarchy=model_hierarchy,out=f) + + expected_text=""" + SEQ SCORE is fraction (close and matching target sequence). +MEAN LENGTH is the mean length of contiguous segments in the match with target sequence. (Each gap/reverse of direction starts new segment). + + + + ----ALL RESIDUES--- CLOSE RESIDUES ONLY % + MODEL --CLOSE- --FAR-- FORWARD REVERSE MIXED FOUND CA SEQ + RMSD N N N N N SCORE SEQ MATCH(%) SCORE MEAN LENGTH FRAGMENTS BAD CONNECTIONS + + Unique_target 1.55 54 7 14 29 11 39.7 0.26 9.3 0.04 6.0 7 6""" + found_text="\n".join(f.getvalue().splitlines()[-10:]) + if remove_blank(found_text)!=remove_blank(expected_text): + print("\n\nExpected: \n%s \n\nFound: \n%s" %(expected_text,found_text)) + raise AssertionError("FAILED") + + from libtbx.test_utils import approx_equal + print(r.get_values("forward")) + assert approx_equal(r.get_values("forward"),(1.6751069901864204, 14)) + print(r.get_values("reverse")) + assert approx_equal(r.get_values("reverse"),(1.388466550576198, 29)) + print(r.get_values("close")) + assert approx_equal(r.get_values("close"),(1.545835235099158, 54)) + print(r.get_values("all_far")) + assert approx_equal(r.get_values("all_far"),(0,0)) + print("OK") + +def tst_03(): + print("Comparing mixed model with target with 2 chains...as group") + import iotbx.pdb + from cctbx.array_family import flex + model_pdb_inp=iotbx.pdb.input(source_info='model', + lines=flex.split_lines(pdb_str_model1)) + crystal_symmetry=model_pdb_inp.crystal_symmetry() + model_hierarchy=model_pdb_inp.construct_hierarchy() + query_hierarchy=iotbx.pdb.input(source_info='query', + lines=flex.split_lines(pdb_str_query)).construct_hierarchy() + import os + if not os.path.isdir("cif_files"): + os.mkdir("cif_files") + + ff=open(os.path.join("cif_files","query.cif"),'w') + print(query_hierarchy.as_mmcif_string( + crystal_symmetry=model_pdb_inp.crystal_symmetry()), file=ff) + ff.close() + ff=open("model.cif",'w') + print(model_hierarchy.as_mmcif_string(), file=ff) + ff.close() + + f=StringIO() + args=["query_dir=cif_files","model.cif"] + r=run(args,out=f) + expected_text=""" + SEQ SCORE is fraction (close and matching target sequence). +MEAN LENGTH is the mean length of contiguous segments in the match with target sequence. (Each gap/reverse of direction starts new segment). + + + + ----ALL RESIDUES--- CLOSE RESIDUES ONLY % + MODEL --CLOSE- --FAR-- FORWARD REVERSE MIXED FOUND CA SEQ + RMSD N N N N N SCORE SEQ MATCH(%) SCORE MEAN LENGTH FRAGMENTS BAD CONNECTIONS + + query.cif 1.55 54 7 14 29 11 39.7 0.26 9.3 0.04 6.0 7 6""" + found_text="\n".join(f.getvalue().splitlines()[-10:]) + if remove_blank(found_text)!=remove_blank(expected_text): + print("Expected: \n%s \nFound: \n%s" %(expected_text,found_text)) + raise AssertionError("FAILED") + print("OK") + +def tst_04(): + print("Testing choosing unique sequences") + + from mmtbx.validation.chain_comparison import \ + extract_unique_part_of_sequences as eups + + seqs=[ "abcdefgh","klafmalsd"] + print() + print(seqs) + copies_in_unique,base_copies,unique_sequence_dict=eups(seqs) + for seq in copies_in_unique.keys(): + print(copies_in_unique[seq],base_copies,seq) + + seqs=[ "abcdefgh", + "klafmalsd", + "klafmalsd"] + print() + print(seqs) + copies_in_unique,base_copies,unique_sequence_dict=eups(seqs) + for seq in copies_in_unique.keys(): + print(copies_in_unique[seq],base_copies,seq) + + seqs=[ + "abcdefgh", + "klafmalsd", + ] + print() + print(seqs) + copies_in_unique,base_copies,unique_sequence_dict=eups(seqs) + for seq in copies_in_unique.keys(): + print(copies_in_unique[seq],base_copies,seq) + + seqs=[ + "abcdefgh", + "klafmalsd", + "abcdefgh", + "klafmalsd", + ] + print() + print(seqs) + copies_in_unique,base_copies,unique_sequence_dict=eups(seqs) + for seq in copies_in_unique.keys(): + print(copies_in_unique[seq],base_copies,seq) + + seqs=[ + "abcdefgh", + "klafmalsd", + "klafmalsd", + "abcdefgh", + "klafmalsd", + "klafmalsd", + ] + print() + print(seqs) + copies_in_unique,base_copies,unique_sequence_dict=eups(seqs) + for seq in copies_in_unique.keys(): + print(copies_in_unique[seq],base_copies,seq) + + print("OK") + + +ncs_spec=""" +Summary of NCS information +Fri Jan 12 11:58:49 2018 +/net/anaconda/raid1/terwill/misc/junk + + + + + +new_ncs_group +new_operator + +rota_matrix 1.0000 0.0000 0.0000 +rota_matrix 0.0000 1.0000 0.0000 +rota_matrix 0.0000 0.0000 1.0000 +tran_orth 0.0000 0.0000 0.0000 + +center_orth 112.2897 27.5224 23.1305 +CHAIN A +RMSD 0 +MATCHING 136 + RESSEQ 4:139 + +new_operator + +rota_matrix 1.0000 0.0000 0.0000 +rota_matrix 0.0000 1.0000 0.0000 +rota_matrix 0.0000 0.0000 1.0000 +tran_orth -405.0000 -405.0000 -405.0000 + +center_orth 517.2897 432.5224 428.1305 +CHAIN B +RMSD 4.32467304409e-13 +MATCHING 136 + RESSEQ 4:139 + +""" +def tst_05(): + from mmtbx.validation.chain_comparison import \ + extract_unique_part_of_hierarchy as euph + + print("Testing extraction of unique part and unique matching") + for m in [pdb_str_modela,pdb_str_modelb,pdb_str_modelaa, + pdb_str_modelaab,pdb_str_modelaabaab]: + import iotbx.pdb + from cctbx.array_family import flex + model_pdb_inp=iotbx.pdb.input(source_info='model', + lines=flex.split_lines(m)) + crystal_symmetry=model_pdb_inp.crystal_symmetry() + model_hierarchy=model_pdb_inp.construct_hierarchy() + + print("\nExtraction of unique MODEL with %s residues" %( + model_hierarchy.overall_counts().n_residues)) + query_hierarchy=iotbx.pdb.input(source_info='query', + lines=flex.split_lines(pdb_str_target)).construct_hierarchy() + unique_hierarchy=euph(model_hierarchy,target_ph=query_hierarchy) + print("FINAL chain ids: %s \n" %(" ".join(unique_hierarchy.chain_ids()))) + print("OK") + +def tst_06(): + print("Comparing mixed model with target with 2 chains...using ncs") + import iotbx.pdb + from cctbx.array_family import flex + model_pdb_inp=iotbx.pdb.input(source_info='model', + lines=flex.split_lines(pdb_str_model1)) + crystal_symmetry=model_pdb_inp.crystal_symmetry() + f=open('ncs.ncs_spec','w') + print(ncs_spec, file=f) + f.close() + f=open('model.cif','w') + print(pdb_str_model1, file=f) #model_hierarchy.as_pdb_string() + f.close() + f=open('query.cif','w') + print(pdb_str_query, file=f) #query_hierarchy.as_pdb_string() + f.close() + + f=StringIO() + args=['model.cif','query.cif','ncs_file=ncs.ncs_spec'] + r=run(args,out=f) + expected_text=""" + SEQ SCORE is fraction (close and matching target sequence). +MEAN LENGTH is the mean length of contiguous segments in the match with target sequence. (Each gap/reverse of direction starts new segment). + + + + ----ALL RESIDUES--- CLOSE RESIDUES ONLY % + MODEL --CLOSE- --FAR-- FORWARD REVERSE MIXED FOUND CA SEQ + RMSD N N N N N SCORE SEQ MATCH(%) SCORE MEAN LENGTH FRAGMENTS BAD CONNECTIONS + + Unique_target 1.67 58 64 15 29 14 42.6 0.25 8.6 0.04 4.5 16 8""" + found_text="\n".join(f.getvalue().splitlines()[-10:]) + if remove_blank(found_text)!=remove_blank(expected_text): + print("\n\nExpected: \n%s \n\nFound: \n%s" %(expected_text,found_text)) + raise AssertionError("FAILED") + + print("OK") + +if __name__=="__main__": + tst_01() + tst_02() + tst_03() + tst_04() + tst_05() + tst_06() diff --git a/mmtbx/regression/tst_domains_from_pae_cif.py b/mmtbx/regression/tst_domains_from_pae_cif.py new file mode 100644 index 0000000000..709e7c88ba --- /dev/null +++ b/mmtbx/regression/tst_domains_from_pae_cif.py @@ -0,0 +1,157 @@ +from __future__ import division, print_function +import sys, os, time + +from libtbx import group_args +import networkx as nx +from packaging import version + +import libtbx.load_env +data_dir = libtbx.env.under_dist( + module_name="mmtbx", + path="regression", + test=os.path.isdir) + +from mmtbx.domains_from_pae import get_domain_selections_from_pae_matrix + +pae_file=os.path.join(data_dir,'pae.json') +model_file=os.path.join(data_dir, 'pdbs','pae_model.cif') +pae_file_v3=os.path.join(data_dir,'AF_json_v3.json') +model_file_v3=os.path.join(data_dir, 'pdbs','AF_json_v3.cif') + +from iotbx.data_manager import DataManager +dm = DataManager() +distance_model = dm.get_model(model_file) +distance_model.add_crystal_symmetry_if_necessary() +distance_model_v3 = dm.get_model(model_file_v3) +distance_model_v3.add_crystal_symmetry_if_necessary() + +def tst_01(log = sys.stdout): + + if version.parse(nx.__version__) < version.parse('2.6.2'): + pae_power = 2.0 + pae_cutoff = 5.0 + resolution = 1.0 + else: + pae_power = 1.0 + pae_cutoff = 5.0 + resolution = 0.5 + + args = group_args( + group_args_type = 'parameters', + pae_file = pae_file, + library = 'networkx', + pae_power = pae_power, + pae_cutoff = pae_cutoff, + resolution = resolution, + select_range = False) + + selections = get_domain_selections_from_pae_matrix(pae_file = args.pae_file, + library = args.library, + pae_power = args.pae_power, pae_cutoff = args.pae_cutoff, + graph_resolution = args.resolution,) + if version.parse(nx.__version__) < version.parse('2.6.2'): + assert selections == [ + "(resseq 0:113) or (resseq 184:187)", + "(resseq 114:182) or (resseq 188:291)", + "(resseq 183:183)", + "(resseq 292:308)" + ], selections + else: + assert selections == ['(resseq 0:117) or (resseq 181:181) or (resseq 183:187)', '(resseq 118:180) or (resseq 182:182) or (resseq 188:308)'], selections + + +def tst_02(log = sys.stdout): + + if version.parse(nx.__version__) < version.parse('2.6.2'): + pae_power = 2.0 + pae_cutoff = 5.0 + resolution = 1.0 + else: + pae_power = 1.0 + pae_cutoff = 5.0 + resolution = 0.5 + + args = group_args( + group_args_type = 'parameters', + pae_file = pae_file, + library = 'networkx', + pae_power = pae_power, + pae_cutoff = pae_cutoff, + resolution = resolution, + weight_by_ca_ca_distance = 1.0, + distance_power = 1.0, + distance_model = distance_model, + select_range = False) + + + + selections = get_domain_selections_from_pae_matrix(pae_file = args.pae_file, + library=args.library, + pae_power = args.pae_power, pae_cutoff = args.pae_cutoff, + graph_resolution = args.resolution, + weight_by_ca_ca_distance = args.weight_by_ca_ca_distance, + distance_power = args.distance_power, + distance_model = args.distance_model) + if version.parse(nx.__version__) < version.parse('2.6.2'): + assert selections == [ + "(resseq 0:1) or (resseq 22:113) or (resseq 184:187)", + "(resseq 2:21)", + "(resseq 114:183) or (resseq 188:291)", + "(resseq 292:308)" + ] + else: + assert selections == ['(resseq 0:24)', '(resseq 25:62) or (resseq 66:96) or (resseq 100:111)', '(resseq 63:65)', '(resseq 97:99)', '(resseq 112:117)', '(resseq 118:135) or (resseq 142:181) or (resseq 190:199)', '(resseq 136:141)', '(resseq 182:189)', '(resseq 200:269) or (resseq 274:288)', '(resseq 270:273)', '(resseq 289:308)'], selections + +def tst_03(log = sys.stdout): + + if version.parse(nx.__version__) < version.parse('2.6.2'): + pae_power = 2.0 + pae_cutoff = 5.0 + resolution = 1.0 + else: + pae_power = 1.0 + pae_cutoff = 5.0 + resolution = 0.5 + + args = group_args( + group_args_type = 'parameters', + pae_file = pae_file_v3, + library = 'networkx', + pae_power = pae_power, + pae_cutoff = pae_cutoff, + resolution = resolution, + weight_by_ca_ca_distance = 1.0, + distance_power = 1.0, + distance_model = distance_model_v3, + select_range = False) + + + + selections = get_domain_selections_from_pae_matrix(pae_file = args.pae_file, + library=args.library, + pae_power = args.pae_power, pae_cutoff = args.pae_cutoff, + graph_resolution = args.resolution, + weight_by_ca_ca_distance = args.weight_by_ca_ca_distance, + distance_power = args.distance_power, + distance_model = args.distance_model) + if version.parse(nx.__version__) < version.parse('2.6.2'): + assert selections == ['(resseq 0:8)', '(resseq 9:16)', + '(resseq 17:85) or (resseq 95:226) or (resseq 229:253) or (resseq 258:330)', + '(resseq 86:93)', '(resseq 94:94)', '(resseq 227:228)', + '(resseq 254:257)', '(resseq 331:334)'], selections + else: + assert selections == ['(resseq 0:5)', '(resseq 6:14)', '(resseq 15:35) or (resseq 44:59) or (resseq 67:83) or (resseq 97:111) or (resseq 121:135) or (resseq 145:156) or (resseq 172:177)', '(resseq 36:43) or (resseq 60:66)', '(resseq 84:86)', '(resseq 87:92)', '(resseq 93:96)', '(resseq 112:120) or (resseq 136:144) or (resseq 157:171) or (resseq 179:180)', '(resseq 178:178) or (resseq 181:181) or (resseq 199:208)', '(resseq 182:192) or (resseq 209:214)', '(resseq 193:198) or (resseq 215:223) or (resseq 235:249) or (resseq 266:285) or (resseq 293:309) or (resseq 318:332)', '(resseq 224:226)', '(resseq 227:234)', '(resseq 250:254)', '(resseq 255:259)', '(resseq 260:265)', '(resseq 286:292) or (resseq 310:317)', '(resseq 333:334)'], selections + +if __name__ == "__main__": + + t0 = time.time() + tst_01() + print ("Time 01: ", time.time()-t0) + t1 = time.time() + tst_02() + print ("Time 02: ", time.time()-t1) + tst_03() + print ("Time 03: ", time.time()-t1) + + print ("OK") + diff --git a/mmtbx/regression/tst_find_ss_structure.py b/mmtbx/regression/tst_find_ss_structure.py index 08e8d0cae2..ec7ed7771b 100644 --- a/mmtbx/regression/tst_find_ss_structure.py +++ b/mmtbx/regression/tst_find_ss_structure.py @@ -1,9 +1,11 @@ from __future__ import absolute_import, division, print_function +import sys + from libtbx.utils import null_out from six.moves import cStringIO as StringIO from mmtbx.secondary_structure.find_ss_from_ca import find_secondary_structure -from libtbx import test_utils + def remove_blank(text): return text.replace(" ","").replace("\n","") @@ -2712,14 +2714,17 @@ def tst_13(): import iotbx.pdb.secondary_structure as ioss hierarchy=iotbx.pdb.input(source_info='text', lines=flex.split_lines(text)).construct_hierarchy() - annotation=ioss.annotation.from_records(records=flex.split_lines(anno)) + input_annotation=ioss.annotation.from_records(records=flex.split_lines(anno)) print("\nAnnotation with insertion codes") print("\nInput annotation:") - print(annotation.as_pdb_str()) + print(input_annotation.as_pdb_str()) + fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False,out=null_out()) new_annotation=fss.get_annotation() print("\nNew annotation:") - expected=ioss.annotation.from_records(records=flex.split_lines(""" + print(new_annotation.as_pdb_str()) + + expected_new=ioss.annotation.from_records(records=flex.split_lines(""" HELIX 1 1 TRP A 181 TYR A 186 3 6 SHEET 1 1 3 VAL A 161 VAL A 164 0 SHEET 2 1 3 TYR A 170 ASN A 175 -1 N ASN A 175 O VAL A 161 @@ -2727,21 +2732,17 @@ def tst_13(): """)) print(new_annotation.as_pdb_str()) - assert expected.is_same_as(new_annotation) + assert expected_new.is_same_as(new_annotation) print("\nNew forcing input annotation") - expected=ioss.annotation.from_records(records=flex.split_lines(""" -SHEET 1 1 2 GLN A 156A VAL A 164 0 -SHEET 2 1 2 TYR A 170 ASN A 175 -1 -""")) force_fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False, - user_annotation_text=annotation.as_pdb_str(), + user_annotation_text=input_annotation.as_pdb_str(), force_secondary_structure_input=True, combine_annotations=False, out=null_out()).get_annotation() print(force_fss.as_pdb_str()) - assert expected.is_same_as(force_fss) + assert input_annotation.is_same_as(force_fss) helix_icode=""" ATOM 2 CA ALA A 1A 11.323 32.055 11.635 1.00 40.00 C @@ -2943,7 +2944,7 @@ def tst_17(): if __name__=="__main__": - import sys + tst_00() tst_01() tst_02() diff --git a/mmtbx/regression/tst_find_ss_structure_cif.py b/mmtbx/regression/tst_find_ss_structure_cif.py new file mode 100644 index 0000000000..16cf46839c --- /dev/null +++ b/mmtbx/regression/tst_find_ss_structure_cif.py @@ -0,0 +1,3986 @@ +from __future__ import absolute_import, division, print_function + +from libtbx.utils import null_out +from six.moves import cStringIO as StringIO +from mmtbx.secondary_structure.find_ss_from_ca import find_secondary_structure +from iotbx.pdb.utils import get_pdb_input + + +def edit_cif_info(ann, chain_addition, text_list = [' A ',' B '], + new_text_list = [' AXZLONG ',' BXZLONG ']): + cif_str = ann.as_mmcif_str() + for x,y in zip(text_list, new_text_list): + cif_str = cif_str.replace(x,y) + pdb_inp = get_pdb_input(cif_str) + new_ann = pdb_inp.extract_secondary_structure() + return new_ann + +def edit_cif_info_list(x_list, chain_addition, text_list = None, + new_text_list = None): + new_x_list = [] + for x in x_list: + new_x_list.append( + edit_cif_info(x, chain_addition, + text_list = text_list, new_text_list = new_text_list)) + return new_x_list + +def remove_blank(text): + return text.replace(" ","").replace("\n","") + +bad_two_chain_helix_ss=""" + data_phenix +loop_ + _struct_conf.conf_type_id + _struct_conf.id + _struct_conf.pdbx_PDB_helix_id + _struct_conf.beg_label_comp_id + _struct_conf.beg_label_asym_id + _struct_conf.beg_label_seq_id + _struct_conf.pdbx_beg_PDB_ins_code + _struct_conf.end_label_comp_id + _struct_conf.end_label_asym_id + _struct_conf.end_label_seq_id + _struct_conf.pdbx_end_PDB_ins_code + _struct_conf.pdbx_PDB_helix_class + _struct_conf.details + _struct_conf.pdbx_PDB_helix_length + HELX_P 1 1 ALA AXZLONG 15 ? LYS AXZLONG 21 ? 1 ? 7 + +loop_ + _struct_conf_type.id + _struct_conf_type.criteria + _struct_conf_type.reference + HELX_P ? ? + +loop_ + _struct_sheet.id + _struct_sheet.type + _struct_sheet.number_strands + _struct_sheet.details + 1 ? 2 ? + +loop_ + _struct_sheet_order.sheet_id + _struct_sheet_order.range_id_1 + _struct_sheet_order.range_id_2 + _struct_sheet_order.offset + _struct_sheet_order.sense + 1 1 2 ? parallel + +loop_ + _struct_sheet_range.sheet_id + _struct_sheet_range.id + _struct_sheet_range.beg_label_comp_id + _struct_sheet_range.beg_label_asym_id + _struct_sheet_range.beg_label_seq_id + _struct_sheet_range.pdbx_beg_PDB_ins_code + _struct_sheet_range.end_label_comp_id + _struct_sheet_range.end_label_asym_id + _struct_sheet_range.end_label_seq_id + _struct_sheet_range.pdbx_end_PDB_ins_code + 1 1 TYR AXZLONG 50 ? TYR AXZLONG 54 ? + 1 2 ILE BXZLONG 278 ? ALA BXZLONG 282 ? + +loop_ + _pdbx_struct_sheet_hbond.sheet_id + _pdbx_struct_sheet_hbond.range_id_1 + _pdbx_struct_sheet_hbond.range_id_2 + _pdbx_struct_sheet_hbond.range_1_label_atom_id + _pdbx_struct_sheet_hbond.range_1_label_comp_id + _pdbx_struct_sheet_hbond.range_1_label_asym_id + _pdbx_struct_sheet_hbond.range_1_label_seq_id + _pdbx_struct_sheet_hbond.range_1_PDB_ins_code + _pdbx_struct_sheet_hbond.range_2_label_atom_id + _pdbx_struct_sheet_hbond.range_2_label_comp_id + _pdbx_struct_sheet_hbond.range_2_label_asym_id + _pdbx_struct_sheet_hbond.range_2_label_seq_id + _pdbx_struct_sheet_hbond.range_2_PDB_ins_code + 1 1 2 O ILE AXZLONG 51 ? N ILE BXZLONG 280 ? + + +""" + +bad_two_chain_helix_ss_correct_resname=""" + data_phenix +loop_ + _struct_conf.conf_type_id + _struct_conf.id + _struct_conf.pdbx_PDB_helix_id + _struct_conf.beg_label_comp_id + _struct_conf.beg_label_asym_id + _struct_conf.beg_label_seq_id + _struct_conf.pdbx_beg_PDB_ins_code + _struct_conf.end_label_comp_id + _struct_conf.end_label_asym_id + _struct_conf.end_label_seq_id + _struct_conf.pdbx_end_PDB_ins_code + _struct_conf.pdbx_PDB_helix_class + _struct_conf.details + _struct_conf.pdbx_PDB_helix_length + HELX_P 1 1 ALA AXZLONG 15 ? LYS AXZLONG 21 ? 1 ? 7 + +loop_ + _struct_conf_type.id + _struct_conf_type.criteria + _struct_conf_type.reference + HELX_P ? ? + +loop_ + _struct_sheet.id + _struct_sheet.type + _struct_sheet.number_strands + _struct_sheet.details + 1 ? 2 ? + +loop_ + _struct_sheet_order.sheet_id + _struct_sheet_order.range_id_1 + _struct_sheet_order.range_id_2 + _struct_sheet_order.offset + _struct_sheet_order.sense + 1 1 2 ? parallel + +loop_ + _struct_sheet_range.sheet_id + _struct_sheet_range.id + _struct_sheet_range.beg_label_comp_id + _struct_sheet_range.beg_label_asym_id + _struct_sheet_range.beg_label_seq_id + _struct_sheet_range.pdbx_beg_PDB_ins_code + _struct_sheet_range.end_label_comp_id + _struct_sheet_range.end_label_asym_id + _struct_sheet_range.end_label_seq_id + _struct_sheet_range.pdbx_end_PDB_ins_code + 1 1 TYR AXZLONG 50 ? TYR AXZLONG 54 ? + 1 2 LEU BXZLONG 278 ? ALA BXZLONG 282 ? + +loop_ + _pdbx_struct_sheet_hbond.sheet_id + _pdbx_struct_sheet_hbond.range_id_1 + _pdbx_struct_sheet_hbond.range_id_2 + _pdbx_struct_sheet_hbond.range_1_label_atom_id + _pdbx_struct_sheet_hbond.range_1_label_comp_id + _pdbx_struct_sheet_hbond.range_1_label_asym_id + _pdbx_struct_sheet_hbond.range_1_label_seq_id + _pdbx_struct_sheet_hbond.range_1_PDB_ins_code + _pdbx_struct_sheet_hbond.range_2_label_atom_id + _pdbx_struct_sheet_hbond.range_2_label_comp_id + _pdbx_struct_sheet_hbond.range_2_label_asym_id + _pdbx_struct_sheet_hbond.range_2_label_seq_id + _pdbx_struct_sheet_hbond.range_2_PDB_ins_code + 1 1 2 O ILE AXZLONG 51 ? N ILE BXZLONG 280 ? + +""" + +pdb_str_negative_residues=""" +ATOM 1 CA ASP A -5 34.633 18.762 20.254 1.00 22.59 C +ATOM 2 CA LYS A -4 36.047 17.704 23.610 1.00 19.79 C +ATOM 3 CA ILE A -3 35.551 19.482 26.886 1.00 19.33 C +ATOM 4 CA AHIS A -2 38.649 21.223 28.218 0.50 19.79 C +ATOM 5 CA BHIS A -2 38.583 21.270 28.209 0.50 20.43 C +ATOM 6 CA GLY A 138 38.261 15.285 27.690 1.00 6.80 C +ATOM 7 CA ALA A 139 34.607 14.241 27.428 1.00 4.76 C +ATOM 8 CA ALEU A 140 33.091 14.490 23.937 0.50 5.08 C +ATOM 9 CA BLEU A 140 33.072 14.565 23.972 0.50 5.41 C +ATOM 10 CA ASN A 141 30.271 17.061 23.474 1.00 5.65 C +""" + +pdb_str_hybrid_residues=""" +ATOM 1 CA ASP AXYB2 34.633 18.762 20.254 1.00 22.59 C +ATOM 2 CA LYS AXYB3 36.047 17.704 23.610 1.00 19.79 C +ATOM 3 CA ILE AXYB4 35.551 19.482 26.886 1.00 19.33 C +ATOM 4 CA AHIS AXYB5 38.649 21.223 28.218 0.50 19.79 C +ATOM 5 CA BHIS AXYB6 38.583 21.270 28.209 0.50 20.43 C +ATOM 6 CA GLY A 138 38.261 15.285 27.690 1.00 6.80 C +ATOM 7 CA ALA A 139 34.607 14.241 27.428 1.00 4.76 C +ATOM 8 CA ALEU A 140 33.091 14.490 23.937 0.50 5.08 C +ATOM 9 CA BLEU A 140 33.072 14.565 23.972 0.50 5.41 C +ATOM 10 CA ASN A 141 30.271 17.061 23.474 1.00 5.65 C +""" + +pdb_str_antiparallel_text=""" +ATOM 1 N LEU A 95 19.823 2.447 -20.604 1.00 4.22 N +ATOM 2 CA LEU A 95 19.411 3.491 -19.655 1.00 4.09 C +ATOM 3 C LEU A 95 20.437 3.482 -18.522 1.00 4.12 C +ATOM 4 O LEU A 95 20.764 2.410 -18.006 1.00 4.68 O +ATOM 5 CB LEU A 95 18.007 3.186 -19.075 1.00 4.63 C +ATOM 9 N LEU A 96 20.911 4.667 -18.125 1.00 4.11 N +ATOM 10 CA LEU A 96 21.872 4.787 -17.025 1.00 4.27 C +ATOM 11 C LEU A 96 21.308 5.812 -16.028 1.00 4.14 C +ATOM 12 O LEU A 96 21.044 6.956 -16.404 1.00 4.78 O +ATOM 13 CB ALEU A 96 23.225 5.220 -17.574 0.50 4.58 C +ATOM 21 N ARG A 97 21.144 5.374 -14.766 1.00 3.77 N +ATOM 22 CA ARG A 97 20.820 6.284 -13.673 1.00 3.69 C +ATOM 23 C ARG A 97 22.056 6.437 -12.774 1.00 3.41 C +ATOM 24 O ARG A 97 22.651 5.441 -12.329 1.00 4.05 O +ATOM 25 CB ARG A 97 19.612 5.796 -12.851 1.00 3.79 C +ATOM 32 N PHE A 98 22.413 7.695 -12.516 1.00 3.36 N +ATOM 33 CA PHE A 98 23.473 8.085 -11.601 1.00 3.42 C +ATOM 34 C PHE A 98 22.827 8.597 -10.306 1.00 3.34 C +ATOM 35 O PHE A 98 21.699 9.092 -10.321 1.00 3.88 O +ATOM 36 CB PHE A 98 24.260 9.271 -12.203 1.00 3.74 C +ATOM 43 N PHE A 117 25.991 3.957 -10.490 1.00 3.61 N +ATOM 44 CA PHE A 117 26.196 3.832 -11.931 1.00 3.74 C +ATOM 45 C PHE A 117 25.339 2.627 -12.381 1.00 3.68 C +ATOM 46 O PHE A 117 25.850 1.516 -12.565 1.00 4.07 O +ATOM 47 CB PHE A 117 27.700 3.629 -12.215 1.00 4.23 C +ATOM 54 N ALA A 118 24.027 2.850 -12.466 1.00 3.64 N +ATOM 55 CA ALA A 118 23.056 1.773 -12.686 1.00 3.60 C +ATOM 56 C ALA A 118 22.714 1.712 -14.176 1.00 3.63 C +ATOM 57 O ALA A 118 22.072 2.613 -14.700 1.00 4.10 O +ATOM 58 CB ALA A 118 21.797 2.030 -11.857 1.00 4.08 C +ATOM 59 N LEU A 119 23.182 0.650 -14.842 1.00 3.81 N +ATOM 60 CA LEU A 119 23.136 0.560 -16.297 1.00 3.98 C +ATOM 61 C LEU A 119 22.282 -0.621 -16.738 1.00 4.00 C +ATOM 62 O LEU A 119 22.608 -1.781 -16.475 1.00 5.33 O +ATOM 63 CB LEU A 119 24.577 0.411 -16.837 1.00 4.22 C +ATOM 67 N ARG A 120 21.209 -0.315 -17.470 1.00 3.85 N +ATOM 68 CA ARG A 120 20.357 -1.332 -18.102 1.00 3.95 C +ATOM 69 C ARG A 120 20.680 -1.407 -19.584 1.00 3.95 C +ATOM 70 O ARG A 120 20.778 -0.387 -20.282 1.00 4.48 O +ATOM 71 CB ARG A 120 18.872 -0.947 -17.952 1.00 4.12 C +""" +antiparallel_ss=""" +SHEET 1 1 2 LEU A 95 PHE A 98 0 +SHEET 2 1 2 PHE A 117 ARG A 120 -1 N ARG A 120 O LEU A 95 +""" +ss_text=""" +data_phenix +loop_ + _struct_conf.conf_type_id + _struct_conf.id + _struct_conf.pdbx_PDB_helix_id + _struct_conf.beg_label_comp_id + _struct_conf.beg_label_asym_id + _struct_conf.beg_label_seq_id + _struct_conf.pdbx_beg_PDB_ins_code + _struct_conf.end_label_comp_id + _struct_conf.end_label_asym_id + _struct_conf.end_label_seq_id + _struct_conf.pdbx_end_PDB_ins_code + _struct_conf.pdbx_PDB_helix_class + _struct_conf.details + _struct_conf.pdbx_PDB_helix_length + HELX_P 1 1 ALA AXZLONG 15 ? LYS AXZLONG 21 ? 1 ? 7 + +loop_ + _struct_conf_type.id + _struct_conf_type.criteria + _struct_conf_type.reference + HELX_P ? ? + +loop_ + _struct_sheet.id + _struct_sheet.type + _struct_sheet.number_strands + _struct_sheet.details + 1 ? 2 ? + +loop_ + _struct_sheet_order.sheet_id + _struct_sheet_order.range_id_1 + _struct_sheet_order.range_id_2 + _struct_sheet_order.offset + _struct_sheet_order.sense + 1 1 2 ? parallel + +loop_ + _struct_sheet_range.sheet_id + _struct_sheet_range.id + _struct_sheet_range.beg_label_comp_id + _struct_sheet_range.beg_label_asym_id + _struct_sheet_range.beg_label_seq_id + _struct_sheet_range.pdbx_beg_PDB_ins_code + _struct_sheet_range.end_label_comp_id + _struct_sheet_range.end_label_asym_id + _struct_sheet_range.end_label_seq_id + _struct_sheet_range.pdbx_end_PDB_ins_code + 1 1 TYR AXZLONG 50 ? TYR AXZLONG 54 ? + 1 2 LEU BXZLONG 278 ? ALA BXZLONG 282 ? + +loop_ + _pdbx_struct_sheet_hbond.sheet_id + _pdbx_struct_sheet_hbond.range_id_1 + _pdbx_struct_sheet_hbond.range_id_2 + _pdbx_struct_sheet_hbond.range_1_label_atom_id + _pdbx_struct_sheet_hbond.range_1_label_comp_id + _pdbx_struct_sheet_hbond.range_1_label_asym_id + _pdbx_struct_sheet_hbond.range_1_label_seq_id + _pdbx_struct_sheet_hbond.range_1_PDB_ins_code + _pdbx_struct_sheet_hbond.range_2_label_atom_id + _pdbx_struct_sheet_hbond.range_2_label_comp_id + _pdbx_struct_sheet_hbond.range_2_label_asym_id + _pdbx_struct_sheet_hbond.range_2_label_seq_id + _pdbx_struct_sheet_hbond.range_2_PDB_ins_code + 1 1 2 O ILE AXZLONG 51 ? N ILE BXZLONG 280 ? + + +""" +ss_hybrid_text = """ +data_phenix +loop_ + _struct_sheet.id + _struct_sheet.type + _struct_sheet.number_strands + _struct_sheet.details + 1 ? 2 ? + +loop_ + _struct_sheet_order.sheet_id + _struct_sheet_order.range_id_1 + _struct_sheet_order.range_id_2 + _struct_sheet_order.offset + _struct_sheet_order.sense + 1 1 2 ? anti-parallel + +loop_ + _struct_sheet_range.sheet_id + _struct_sheet_range.id + _struct_sheet_range.beg_label_comp_id + _struct_sheet_range.beg_label_asym_id + _struct_sheet_range.beg_label_seq_id + _struct_sheet_range.pdbx_beg_PDB_ins_code + _struct_sheet_range.end_label_comp_id + _struct_sheet_range.end_label_asym_id + _struct_sheet_range.end_label_seq_id + _struct_sheet_range.pdbx_end_PDB_ins_code + 1 1 ASP AXZLONG 1127550 ? HIS AXZLONG 1127553 ? + 1 2 GLY AXZLONG 138 ? ASN AXZLONG 141 ? + +loop_ + _pdbx_struct_sheet_hbond.sheet_id + _pdbx_struct_sheet_hbond.range_id_1 + _pdbx_struct_sheet_hbond.range_id_2 + _pdbx_struct_sheet_hbond.range_1_label_atom_id + _pdbx_struct_sheet_hbond.range_1_label_comp_id + _pdbx_struct_sheet_hbond.range_1_label_asym_id + _pdbx_struct_sheet_hbond.range_1_label_seq_id + _pdbx_struct_sheet_hbond.range_1_PDB_ins_code + _pdbx_struct_sheet_hbond.range_2_label_atom_id + _pdbx_struct_sheet_hbond.range_2_label_comp_id + _pdbx_struct_sheet_hbond.range_2_label_asym_id + _pdbx_struct_sheet_hbond.range_2_label_seq_id + _pdbx_struct_sheet_hbond.range_2_PDB_ins_code + 1 1 2 O ASP AXZLONG 1127550 ? N ASN AXZLONG 141 ? + +""" +ss_antiparallel_text = """ +data_phenix +loop_ + _struct_sheet.id + _struct_sheet.type + _struct_sheet.number_strands + _struct_sheet.details + 1 ? 2 ? + +loop_ + _struct_sheet_order.sheet_id + _struct_sheet_order.range_id_1 + _struct_sheet_order.range_id_2 + _struct_sheet_order.offset + _struct_sheet_order.sense + 1 1 2 ? anti-parallel + +loop_ + _struct_sheet_range.sheet_id + _struct_sheet_range.id + _struct_sheet_range.beg_label_comp_id + _struct_sheet_range.beg_label_asym_id + _struct_sheet_range.beg_label_seq_id + _struct_sheet_range.pdbx_beg_PDB_ins_code + _struct_sheet_range.end_label_comp_id + _struct_sheet_range.end_label_asym_id + _struct_sheet_range.end_label_seq_id + _struct_sheet_range.pdbx_end_PDB_ins_code + 1 1 LEU AXZLONG 95 ? PHE AXZLONG 98 ? + 1 2 PHE AXZLONG 117 ? ARG AXZLONG 120 ? + +loop_ + _pdbx_struct_sheet_hbond.sheet_id + _pdbx_struct_sheet_hbond.range_id_1 + _pdbx_struct_sheet_hbond.range_id_2 + _pdbx_struct_sheet_hbond.range_1_label_atom_id + _pdbx_struct_sheet_hbond.range_1_label_comp_id + _pdbx_struct_sheet_hbond.range_1_label_asym_id + _pdbx_struct_sheet_hbond.range_1_label_seq_id + _pdbx_struct_sheet_hbond.range_1_PDB_ins_code + _pdbx_struct_sheet_hbond.range_2_label_atom_id + _pdbx_struct_sheet_hbond.range_2_label_comp_id + _pdbx_struct_sheet_hbond.range_2_label_asym_id + _pdbx_struct_sheet_hbond.range_2_label_seq_id + _pdbx_struct_sheet_hbond.range_2_PDB_ins_code + 1 1 2 O LEU AXZLONG 95 ? N ARG AXZLONG 120 ? + + +""" +ss_negative_text = """ +data_phenix +loop_ + _struct_sheet.id + _struct_sheet.type + _struct_sheet.number_strands + _struct_sheet.details + 1 ? 2 ? + +loop_ + _struct_sheet_order.sheet_id + _struct_sheet_order.range_id_1 + _struct_sheet_order.range_id_2 + _struct_sheet_order.offset + _struct_sheet_order.sense + 1 1 2 ? anti-parallel + +loop_ + _struct_sheet_range.sheet_id + _struct_sheet_range.id + _struct_sheet_range.beg_label_comp_id + _struct_sheet_range.beg_label_asym_id + _struct_sheet_range.beg_label_seq_id + _struct_sheet_range.pdbx_beg_PDB_ins_code + _struct_sheet_range.end_label_comp_id + _struct_sheet_range.end_label_asym_id + _struct_sheet_range.end_label_seq_id + _struct_sheet_range.pdbx_end_PDB_ins_code + 1 1 ASP AXZLONG -5 ? HIS AXZLONG -2 ? + 1 2 GLY AXZLONG 138 ? ASN AXZLONG 141 ? + +loop_ + _pdbx_struct_sheet_hbond.sheet_id + _pdbx_struct_sheet_hbond.range_id_1 + _pdbx_struct_sheet_hbond.range_id_2 + _pdbx_struct_sheet_hbond.range_1_label_atom_id + _pdbx_struct_sheet_hbond.range_1_label_comp_id + _pdbx_struct_sheet_hbond.range_1_label_asym_id + _pdbx_struct_sheet_hbond.range_1_label_seq_id + _pdbx_struct_sheet_hbond.range_1_PDB_ins_code + _pdbx_struct_sheet_hbond.range_2_label_atom_id + _pdbx_struct_sheet_hbond.range_2_label_comp_id + _pdbx_struct_sheet_hbond.range_2_label_asym_id + _pdbx_struct_sheet_hbond.range_2_label_seq_id + _pdbx_struct_sheet_hbond.range_2_PDB_ins_code + 1 1 2 O ASP AXZLONG -5 ? N ASN AXZLONG 141 ? + + + +""" + +pdb_str_std_text=""" +ATOM 2 CA THRAa 3 186.743 125.884 251.259 1.00100.00 C +ATOM 5 CA ASNAa 4 189.629 123.742 252.763 1.00100.00 C +ATOM 8 CA SERAa 5 191.072 126.112 255.320 1.00100.00 C +ATOM 11 CA ASPAa 6 192.080 124.928 258.848 1.00100.00 C +ATOM 14 CA PHEAa 7 189.384 124.585 261.530 1.00100.00 C +ATOM 17 CA VALAa 8 189.248 124.466 265.315 1.00100.00 C +ATOM 20 CA VALAa 9 187.059 122.294 267.547 1.00100.00 C +ATOM 23 CA ILEAa 10 185.534 123.893 270.679 1.00100.00 C +ATOM 26 CA LYSAa 11 183.570 122.134 273.450 1.00100.00 C +ATOM 29 CA ALAAa 12 181.897 124.298 276.085 1.00100.00 C +ATOM 32 CA LEUAa 13 182.733 123.145 279.601 1.00100.00 C +ATOM 35 CA GLUAa 14 180.241 125.609 281.156 1.00100.00 C +ATOM 38 CA ASPAa 15 177.155 127.540 279.985 1.00100.00 C +ATOM 41 CA GLYAa 16 177.637 130.843 278.162 1.00100.00 C +ATOM 44 CA VALAa 17 180.958 130.212 276.395 1.00100.00 C +ATOM 47 CA ASNAa 18 181.477 132.715 273.547 1.00100.00 C +ATOM 50 CA VALAa 19 183.320 131.753 270.320 1.00100.00 C +ATOM 53 CA ILEAa 20 184.043 135.156 268.674 1.00100.00 C +ATOM 56 CA GLYAa 21 185.054 135.558 264.994 1.00100.00 C +ATOM 59 CA LEUAa 22 187.345 138.529 264.419 1.00100.00 C +ATOM 62 CA THRAa 23 187.310 140.218 261.033 1.00100.00 C +ATOM 65 CA ARGAa 24 189.831 139.523 258.335 1.00100.00 C +ATOM 68 CA GLYAa 25 191.359 142.673 256.805 1.00100.00 C +ATOM 71 CA ALAAa 26 192.794 146.041 257.837 1.00100.00 C +ATOM 74 CA ASPAa 27 190.126 146.289 260.564 1.00100.00 C +ATOM 77 CA THRAa 28 189.912 143.928 263.570 1.00100.00 C +ATOM 80 CA ARGAa 29 186.413 143.856 265.033 1.00100.00 C +ATOM 83 CA PHEAa 30 183.873 141.240 266.091 1.00100.00 C +ATOM 86 CA HISAa 31 181.625 140.079 263.343 1.00100.00 C +ATOM 89 CA HISAa 32 179.931 137.209 265.203 1.00100.00 C +ATOM 92 CA SERAa 33 179.805 135.702 268.677 1.00100.00 C +ATOM 95 CA GLUAa 34 178.501 132.109 268.857 1.00100.00 C +ATOM 98 CA CYSAa 35 177.222 131.284 272.342 1.00100.00 C +ATOM 101 CA LEUAa 36 177.646 127.700 273.502 1.00100.00 C +ATOM 104 CA ASPAa 37 175.969 125.990 276.438 1.00100.00 C +ATOM 107 CA LYSAa 38 177.682 123.298 278.488 1.00100.00 C +ATOM 110 CA GLYAa 39 178.623 120.300 276.385 1.00100.00 C +ATOM 113 CA GLUAa 40 177.892 121.761 272.941 1.00100.00 C +ATOM 116 CA VALAa 41 180.597 121.439 270.276 1.00100.00 C +ATOM 119 CA LEUAa 42 181.492 123.998 267.594 1.00100.00 C +ATOM 122 CA ILEAa 43 183.793 123.155 264.645 1.00100.00 C +ATOM 125 CA ALAAa 44 184.701 126.388 262.889 1.00100.00 C +ATOM 128 CA GLNAa 45 186.987 127.209 259.959 1.00100.00 C +ATOM 131 CA PHEAa 46 189.115 130.161 259.157 1.00100.00 C +ATOM 134 CA THRAa 47 187.356 131.901 256.203 1.00100.00 C +ATOM 137 CA GLUAa 48 187.180 134.953 253.965 1.00100.00 C +ATOM 140 CA HISAa 49 185.578 136.805 256.905 1.00100.00 C +ATOM 143 CA THRAa 50 187.343 135.292 259.938 1.00100.00 C +ATOM 146 CA SERAa 51 191.129 135.327 260.339 1.00100.00 C +ATOM 149 CA ALAAa 52 191.231 135.094 264.170 1.00100.00 C +ATOM 152 CA ILEAa 53 188.989 133.390 266.744 1.00100.00 C +ATOM 155 CA LYSAa 54 188.770 134.368 270.428 1.00100.00 C +ATOM 158 CA VALAa 55 187.303 131.970 273.016 1.00100.00 C +ATOM 161 CA ARGAa 56 185.817 133.382 276.214 1.00100.00 C +ATOM 164 CA GLYAa 57 184.672 131.065 278.997 1.00100.00 C +ATOM 167 CA LYSAa 58 185.698 127.553 280.004 1.00100.00 C +ATOM 170 CA ALAAa 59 186.172 125.294 276.966 1.00100.00 C +ATOM 173 CA TYRAa 60 188.258 122.444 275.620 1.00100.00 C +ATOM 176 CA ILEAa 61 189.863 123.277 272.265 1.00100.00 C +ATOM 179 CA GLNAa 62 191.492 121.098 269.577 1.00100.00 C +ATOM 182 CA THRAa 63 193.550 122.431 266.653 1.00100.00 C +ATOM 185 CA ARGAa 64 196.271 121.116 264.358 1.00100.00 C +ATOM 188 CA HISAa 65 198.826 122.305 266.995 1.00100.00 C +ATOM 191 CA GLYAa 66 197.443 120.330 269.914 1.00100.00 C +ATOM 194 CA VALAa 67 194.865 120.679 272.646 1.00100.00 C +ATOM 197 CA ILEAa 68 194.232 123.486 275.120 1.00100.00 C +ATOM 200 CA GLUAa 69 191.576 124.693 277.564 1.00100.00 C +ATOM 203 CA SERAa 70 190.301 128.219 277.907 1.00100.00 C +ATOM 206 CA GLUAa 71 189.167 129.249 281.377 1.00100.00 C +ATOM 209 CA GLYAa 72 186.003 131.073 282.428 1.00100.00 C +""" +std_text=pdb_str_std_text + +pdb_str_helices_text=""" +ATOM 2 CA ALA A 1 11.323 32.055 11.635 1.00 40.00 C +ATOM 7 CA ALA A 2 8.288 29.768 10.916 1.00 40.00 C +ATOM 12 CA ALA A 3 10.313 27.854 8.231 1.00 40.00 C +ATOM 17 CA ALA A 4 13.089 27.116 10.822 1.00 40.00 C +ATOM 22 CA ALA A 5 10.573 25.488 13.298 1.00 40.00 C +ATOM 27 CA ALA A 6 9.258 23.514 10.260 1.00 40.00 C +ATOM 32 CA ALA A 7 12.788 22.543 8.962 1.00 40.00 C +ATOM 37 CA ALA A 8 13.846 21.459 12.515 1.00 40.00 C +ATOM 42 CA ALA A 9 10.716 19.261 12.994 1.00 40.00 C +ATOM 47 CA ALA A 10 11.063 17.985 9.357 1.00 40.00 C +ATOM 52 CA ALA A 11 14.754 17.018 9.967 1.00 40.00 C +ATOM 57 CA ALA A 12 13.721 15.483 13.371 1.00 40.00 C +ATOM 62 CA ALA A 13 10.821 13.516 11.708 1.00 40.00 C +ATOM 67 CA ALA A 14 13.246 12.367 8.939 1.00 40.00 C +ATOM 72 CA ALA A 15 15.847 11.407 11.629 1.00 40.00 C +ATOM 77 CA ALA A 16 13.099 9.317 13.370 1.00 40.00 C +ATOM 2 CA ALA B 2 1.733 -3.620 -2.296 1.00 1.00 +ATOM 7 CA ALA B 3 -1.902 -4.065 -1.341 1.00 1.00 +ATOM 12 CA ALA B 4 -2.941 -0.441 -1.685 1.00 1.00 +ATOM 17 CA ALA B 5 -0.320 0.578 -4.218 1.00 1.00 +ATOM 22 CA ALA B 6 0.221 -2.836 -5.759 1.00 1.00 +ATOM 27 CA ALA B 7 -3.192 -4.271 -4.973 1.00 1.00 +ATOM 32 CA ALA B 8 -5.081 -0.993 -4.849 1.00 1.00 +ATOM 37 CA ALA B 9 -2.802 0.969 -7.148 1.00 1.00 +ATOM 42 CA ALA B 10 -1.460 -1.967 -9.123 1.00 1.00 +ATOM 47 CA ALA B 11 -4.418 -4.277 -8.632 1.00 1.00 +ATOM 52 CA ALA B 12 -7.044 -1.601 -8.116 1.00 1.00 +ATOM 57 CA ALA B 13 -5.323 1.151 -10.064 1.00 1.00 +ATOM 62 CA ALA B 14 -3.322 -1.073 -12.383 1.00 1.00 +ATOM 67 CA ALA B 15 -5.629 -4.072 -12.291 1.00 1.00 +ATOM 72 CA ALA B 16 -8.822 -2.205 -11.488 1.00 1.00 +ATOM 77 CA ALA B 17 -7.833 1.122 -12.996 1.00 1.00 +ATOM 82 CA ALA B 18 -5.368 -0.211 -15.540 1.00 1.00 +ATOM 87 CA ALA B 19 -6.878 -3.661 -15.920 1.00 1.00 +ATOM 92 CA ALA B 20 -10.423 -2.748 -14.958 1.00 1.00 +ATOM 97 CA ALA B 21 -10.280 0.896 -15.972 1.00 1.00 +ATOM 102 CA ALA B 22 -7.582 0.562 -18.606 1.00 1.00 +ATOM 2 CA ALA C 2 1.202 -3.661 -1.646 1.00 1.00 C +ATOM 7 CA ALA C 3 -1.466 -2.408 -4.020 1.00 1.00 C +ATOM 12 CA ALA C 4 1.288 -2.503 -6.614 1.00 1.00 C +ATOM 17 CA ALA C 5 0.312 -6.139 -7.010 1.00 1.00 C +ATOM 22 CA ALA C 6 -2.284 -4.816 -9.426 1.00 1.00 C +ATOM 27 CA ALA C 7 0.502 -5.008 -11.981 1.00 1.00 C +ATOM 32 CA ALA C 8 -0.579 -8.614 -12.375 1.00 1.00 C +ATOM 37 CA ALA C 9 -3.100 -7.225 -14.833 1.00 1.00 C +ATOM 42 CA ALA C 10 -0.285 -7.514 -17.347 1.00 1.00 C +ATOM 47 CA ALA C 11 -1.470 -11.087 -17.740 1.00 1.00 C +ATOM 52 CA ALA C 12 -3.913 -9.634 -20.239 1.00 1.00 C +ATOM 57 CA ALA C 13 -1.074 -10.021 -22.713 1.00 1.00 C +ATOM 62 CA ALA C 14 -2.362 -13.558 -23.106 1.00 1.00 C +ATOM 67 CA ALA C 15 -4.725 -12.045 -25.646 1.00 1.00 C +ATOM 72 CA ALA C 16 -1.865 -12.529 -28.077 1.00 1.00 C +ATOM 77 CA ALA C 17 -3.254 -16.028 -28.473 1.00 1.00 C +ATOM 82 CA ALA C 18 -5.534 -14.456 -31.052 1.00 1.00 C +ATOM 87 CA ALA C 19 -2.657 -15.038 -33.442 1.00 1.00 C +ATOM 92 CA ALA C 20 -4.146 -18.495 -33.840 1.00 1.00 C +ATOM 97 CA ALA C 21 -6.342 -16.867 -36.458 1.00 1.00 C +ATOM 102 CA ALA C 22 -3.451 -17.549 -38.805 1.00 1.00 C +""" + +pdb_str_one_full_helix_text=""" +ATOM 1 N ALA A 15 29.207 -2.952 12.868 1.00 16.39 N +ATOM 2 CA ALA A 15 27.822 -3.418 12.724 1.00 17.10 C +ATOM 3 C ALA A 15 27.023 -3.016 13.951 1.00 16.98 C +ATOM 4 O ALA A 15 25.872 -2.551 13.769 1.00 16.78 O +ATOM 5 N LEU A 16 27.570 -3.117 15.127 1.00 15.97 N +ATOM 6 CA LEU A 16 26.958 -2.649 16.351 1.00 18.20 C +ATOM 7 C LEU A 16 26.614 -1.169 16.344 1.00 20.28 C +ATOM 8 O LEU A 16 25.599 -0.734 16.933 1.00 18.32 O +ATOM 9 N ILE A 17 27.514 -0.365 15.791 1.00 20.97 N +ATOM 10 CA ILE A 17 27.343 1.056 15.618 1.00 20.41 C +ATOM 11 C ILE A 17 26.081 1.392 14.758 1.00 18.17 C +ATOM 12 O ILE A 17 25.380 2.240 15.282 1.00 16.46 O +ATOM 13 N SER A 18 25.930 0.759 13.657 1.00 16.97 N +ATOM 14 CA SER A 18 24.825 0.827 12.744 1.00 19.98 C +ATOM 15 C SER A 18 23.499 0.405 13.438 1.00 18.89 C +ATOM 16 O SER A 18 22.557 1.165 13.352 1.00 18.37 O +ATOM 17 N TRP A 19 23.512 -0.661 14.161 1.00 17.71 N +ATOM 18 CA TRP A 19 22.492 -1.085 15.081 1.00 15.72 C +ATOM 19 C TRP A 19 22.083 0.004 16.012 1.00 18.02 C +ATOM 20 O TRP A 19 20.820 0.244 16.160 1.00 16.93 O +ATOM 21 N ILE A 20 22.930 0.594 16.823 1.00 14.82 N +ATOM 22 CA ILE A 20 22.628 1.633 17.766 1.00 15.67 C +ATOM 23 C ILE A 20 21.917 2.819 17.080 1.00 17.51 C +ATOM 24 O ILE A 20 20.942 3.365 17.655 1.00 17.70 O +ATOM 25 N LYS A 21 22.464 3.177 15.957 1.00 16.61 N +ATOM 26 CA LYS A 21 21.888 4.236 15.157 1.00 19.84 C +ATOM 27 C LYS A 21 20.436 3.910 14.752 1.00 21.02 C +ATOM 28 O LYS A 21 19.685 4.899 14.971 1.00 22.80 O +""" +pdb_str_one_helix_beginning_text=""" +ATOM 2 CA ALA A 1 11.323 32.055 11.635 1.00 40.00 C +ATOM 7 CA ALA A 2 8.288 29.768 10.916 1.00 40.00 C +ATOM 12 CA ALA A 3 10.313 27.854 8.231 1.00 40.00 C +ATOM 17 CA ALA A 4 13.089 27.116 10.822 1.00 40.00 C +ATOM 22 CA ALA A 5 10.573 25.488 13.298 1.00 40.00 C +ATOM 27 CA ALA A 6 9.258 23.514 10.260 1.00 40.00 C +ATOM 32 CA ALA A 7 12.788 22.543 8.962 1.00 40.00 C +ATOM 37 CA ALA A 8 13.846 21.459 12.515 1.00 40.00 C +""" +pdb_str_one_helix_end_text=""" +ATOM 42 CA ALA A 9 10.716 19.261 12.994 1.00 40.00 C +ATOM 47 CA ALA A 10 11.063 17.985 9.357 1.00 40.00 C +ATOM 52 CA ALA A 11 14.754 17.018 9.967 1.00 40.00 C +ATOM 57 CA ALA A 12 13.721 15.483 13.371 1.00 40.00 C +ATOM 62 CA ALA A 13 10.821 13.516 11.708 1.00 40.00 C +ATOM 67 CA ALA A 14 13.246 12.367 8.939 1.00 40.00 C +ATOM 72 CA ALA A 15 15.847 11.407 11.629 1.00 40.00 C +ATOM 77 CA ALA A 16 13.099 9.317 13.370 1.00 40.00 C +""" +pdb_str_one_helix_middle_text=""" +ATOM 22 CA ALA A 5 10.573 25.488 13.298 1.00 40.00 C +ATOM 27 CA ALA A 6 9.258 23.514 10.260 1.00 40.00 C +ATOM 32 CA ALA A 7 12.788 22.543 8.962 1.00 40.00 C +ATOM 37 CA ALA A 8 13.846 21.459 12.515 1.00 40.00 C +ATOM 42 CA ALA A 9 10.716 19.261 12.994 1.00 40.00 C +ATOM 47 CA ALA A 10 11.063 17.985 9.357 1.00 40.00 C +ATOM 52 CA ALA A 11 14.754 17.018 9.967 1.00 40.00 C +ATOM 57 CA ALA A 12 13.721 15.483 13.371 1.00 40.00 C +ATOM 62 CA ALA A 13 10.821 13.516 11.708 1.00 40.00 C +""" +pdb_str_one_helix_text=""" +ATOM 2 CA ALA A 1 11.323 32.055 11.635 1.00 40.00 C +ATOM 7 CA ALA A 2 8.288 29.768 10.916 1.00 40.00 C +ATOM 12 CA ALA A 3 10.313 27.854 8.231 1.00 40.00 C +ATOM 17 CA ALA A 4 13.089 27.116 10.822 1.00 40.00 C +ATOM 22 CA ALA A 5 10.573 25.488 13.298 1.00 40.00 C +ATOM 27 CA ALA A 6 9.258 23.514 10.260 1.00 40.00 C +ATOM 32 CA ALA A 7 12.788 22.543 8.962 1.00 40.00 C +ATOM 37 CA ALA A 8 13.846 21.459 12.515 1.00 40.00 C +ATOM 42 CA ALA A 9 10.716 19.261 12.994 1.00 40.00 C +ATOM 47 CA ALA A 10 11.063 17.985 9.357 1.00 40.00 C +ATOM 52 CA ALA A 11 14.754 17.018 9.967 1.00 40.00 C +ATOM 57 CA ALA A 12 13.721 15.483 13.371 1.00 40.00 C +ATOM 62 CA ALA A 13 10.821 13.516 11.708 1.00 40.00 C +ATOM 67 CA ALA A 14 13.246 12.367 8.939 1.00 40.00 C +ATOM 72 CA ALA A 15 15.847 11.407 11.629 1.00 40.00 C +ATOM 77 CA ALA A 16 13.099 9.317 13.370 1.00 40.00 C +""" + +pdb_str_two_helix_text=""" +ATOM 2 CA GLY A 1 43.603 -11.488 24.325 1.00 35.57 +ATOM 6 CA ILE A 2 44.200 -8.183 22.475 1.00 27.55 +ATOM 14 CA GLY A 3 43.999 -10.264 19.329 1.00 21.05 +ATOM 18 CA ALA A 4 40.378 -11.260 20.106 1.00 21.80 +ATOM 23 CA VAL A 5 39.355 -7.658 21.083 1.00 19.34 +ATOM 30 CA LEU A 6 41.062 -6.432 17.957 1.00 17.59 +ATOM 38 CA LYS A 7 39.079 -8.646 15.636 1.00 22.55 +ATOM 47 CA VAL A 8 35.792 -7.369 17.211 1.00 20.52 +ATOM 69 CA THR A 11 34.132 -6.405 12.343 1.00 24.14 +ATOM 76 CA GLY A 12 31.584 -6.595 15.140 1.00 24.17 +ATOM 80 CA LEU A 13 31.923 -2.919 16.364 1.00 23.24 +ATOM 88 CA PRO A 14 31.026 -1.278 13.030 1.00 17.52 +ATOM 95 CA ALA A 15 27.822 -3.418 12.724 1.00 17.10 +ATOM 100 CA LEU A 16 26.958 -2.649 16.351 1.00 18.20 +ATOM 108 CA ILE A 17 27.343 1.056 15.618 1.00 20.41 +ATOM 116 CA SER A 18 24.825 0.827 12.744 1.00 19.98 +ATOM 122 CA TRP A 19 22.492 -1.085 15.081 1.00 15.72 +ATOM 136 CA ILE A 20 22.628 1.633 17.766 1.00 15.67 +ATOM 144 CA LYS A 21 21.888 4.236 15.157 1.00 19.84 +ATOM 153 CA ARG A 22 18.740 2.273 14.020 1.00 20.38 +ATOM 164 CA LYS A 23 17.500 1.928 17.550 1.00 22.62 +ATOM 173 CA ARG A 24 18.059 5.674 18.276 1.00 27.11 +ATOM 184 CA GLN A 25 15.836 6.730 15.339 1.00 37.50 +ATOM 193 CA GLN A 26 13.132 4.360 16.583 1.00 46.66 +""" + +pdb_str_two_chain_text=""" +ATOM 375 N TYR A 50 6.211 -13.569 8.292 1.00 10.98 N +ATOM 376 CA TYR A 50 7.318 -12.627 8.487 1.00 10.61 C +ATOM 377 C TYR A 50 6.766 -11.320 9.020 1.00 9.44 C +ATOM 378 O TYR A 50 5.608 -10.952 8.800 1.00 10.44 O +ATOM 379 CB TYR A 50 8.112 -12.427 7.166 1.00 11.77 C +ATOM 380 CG TYR A 50 8.994 -13.649 6.910 1.00 14.04 C +ATOM 381 CD1 TYR A 50 8.495 -14.805 6.394 1.00 14.79 C +ATOM 382 CD2 TYR A 50 10.334 -13.645 7.280 1.00 15.78 C +ATOM 383 CE1 TYR A 50 9.309 -15.912 6.201 1.00 16.35 C +ATOM 384 CE2 TYR A 50 11.185 -14.715 7.104 1.00 17.74 C +ATOM 385 CZ TYR A 50 10.649 -15.862 6.545 1.00 17.61 C +ATOM 386 OH TYR A 50 11.444 -16.974 6.380 1.00 22.90 O +ATOM 387 N ILE A 51 7.626 -10.601 9.716 1.00 9.43 N +ATOM 388 CA ILE A 51 7.269 -9.357 10.407 1.00 8.71 C +ATOM 389 C ILE A 51 7.916 -8.211 9.657 1.00 8.94 C +ATOM 390 O ILE A 51 9.112 -7.923 9.789 1.00 9.49 O +ATOM 391 CB ILE A 51 7.636 -9.391 11.898 1.00 9.57 C +ATOM 392 CG1 ILE A 51 6.877 -10.489 12.634 1.00 11.51 C +ATOM 393 CG2 ILE A 51 7.340 -8.025 12.509 1.00 9.99 C +ATOM 394 CD1 ILE A 51 7.189 -11.913 12.447 1.00 13.04 C +ATOM 395 N TYR A 52 7.103 -7.549 8.818 1.00 8.87 N +ATOM 396 CA TYR A 52 7.523 -6.401 8.024 1.00 8.95 C +ATOM 397 C TYR A 52 7.566 -5.196 8.933 1.00 8.79 C +ATOM 398 O TYR A 52 6.546 -4.870 9.560 1.00 9.43 O +ATOM 399 CB TYR A 52 6.599 -6.227 6.809 1.00 9.82 C +ATOM 400 CG TYR A 52 6.769 -7.352 5.826 1.00 9.77 C +ATOM 401 CD1 TYR A 52 6.171 -8.583 6.037 1.00 10.04 C +ATOM 402 CD2 TYR A 52 7.581 -7.227 4.699 1.00 11.49 C +ATOM 403 CE1 TYR A 52 6.330 -9.627 5.177 1.00 11.90 C +ATOM 404 CE2 TYR A 52 7.751 -8.274 3.800 1.00 12.84 C +ATOM 405 CZ TYR A 52 7.116 -9.468 4.045 1.00 12.86 C +ATOM 406 OH TYR A 52 7.270 -10.516 3.193 1.00 14.57 O +ATOM 407 N THR A 53 8.737 -4.586 9.055 1.00 8.30 N +ATOM 408 CA THR A 53 8.996 -3.643 10.133 1.00 8.29 C +ATOM 409 C THR A 53 9.384 -2.299 9.550 1.00 8.26 C +ATOM 410 O THR A 53 10.386 -2.196 8.794 1.00 10.05 O +ATOM 411 CB THR A 53 10.098 -4.225 11.054 1.00 9.01 C +ATOM 412 OG1 THR A 53 9.695 -5.497 11.548 1.00 9.73 O +ATOM 413 CG2 THR A 53 10.340 -3.320 12.250 1.00 10.75 C +ATOM 414 N TYR A 54 8.595 -1.292 9.883 1.00 8.50 N +ATOM 415 CA TYR A 54 8.688 0.046 9.368 1.00 8.54 C +ATOM 416 C TYR A 54 9.130 0.977 10.480 1.00 9.00 C +ATOM 417 O TYR A 54 8.469 1.106 11.537 1.00 9.89 O +ATOM 418 CB TYR A 54 7.350 0.517 8.786 1.00 9.33 C +ATOM 419 CG TYR A 54 6.866 -0.378 7.660 1.00 9.22 C +ATOM 420 CD1 TYR A 54 6.113 -1.523 7.899 1.00 9.26 C +ATOM 421 CD2 TYR A 54 7.207 -0.083 6.368 1.00 9.45 C +ATOM 422 CE1 TYR A 54 5.683 -2.351 6.899 1.00 9.56 C +ATOM 423 CE2 TYR A 54 6.783 -0.929 5.368 1.00 10.19 C +ATOM 424 CZ TYR A 54 6.039 -2.054 5.609 1.00 9.31 C +ATOM 425 OH TYR A 54 5.593 -2.884 4.606 1.00 10.62 O +ATOM 426 N ARG A 55 10.273 1.635 10.317 1.00 8.99 N +ATOM 427 CA ARG A 55 10.779 2.540 11.331 1.00 9.30 C +ATOM 428 C ARG A 55 10.006 3.855 11.284 1.00 9.04 C +ATOM 429 O ARG A 55 9.809 4.438 10.215 1.00 10.80 O +ATOM 430 CB ARG A 55 12.255 2.778 11.090 1.00 9.60 C +ATOM 431 CG ARG A 55 13.089 1.503 11.251 1.00 11.09 C +ATOM 432 CD ARG A 55 14.531 1.724 10.963 1.00 12.60 C +ATOM 433 NE ARG A 55 15.393 0.536 10.991 1.00 12.79 N +ATOM 434 CZ ARG A 55 15.853 -0.067 9.907 1.00 11.24 C +ATOM 435 NH1 ARG A 55 15.601 0.267 8.635 1.00 13.70 N +ATOM 436 NH2 ARG A 55 16.683 -1.110 10.084 1.00 12.83 N +ATOM 437 N VAL A 56 9.574 4.315 12.463 1.00 9.17 N +ATOM 438 CA VAL A 56 8.706 5.468 12.645 1.00 9.47 C +ATOM 439 C VAL A 56 9.399 6.439 13.577 1.00 9.55 C +ATOM 440 O VAL A 56 9.819 6.065 14.671 1.00 11.35 O +ATOM 441 CB VAL A 56 7.334 5.020 13.148 1.00 10.23 C +ATOM 442 CG1 VAL A 56 6.464 6.185 13.566 1.00 13.31 C +ATOM 443 CG2 VAL A 56 6.623 4.148 12.100 1.00 11.48 C +ATOM 444 N SER A 57 9.486 7.688 13.122 1.00 10.07 N +ATOM 445 CA SER A 57 10.220 8.739 13.797 1.00 11.56 C +ATOM 446 C SER A 57 9.413 10.020 13.948 1.00 10.72 C +ATOM 447 O SER A 57 8.594 10.296 13.076 1.00 10.93 O +ATOM 448 CB SER A 57 11.541 9.078 13.005 1.00 13.02 C +ATOM 449 OG SER A 57 12.275 7.871 12.757 1.00 16.49 O +ATOM 877 N LEU B 278 13.003 -13.579 11.217 1.00 14.16 N +ATOM 878 CA LEU B 278 11.645 -13.391 10.746 1.00 13.77 C +ATOM 879 C LEU B 278 11.240 -11.932 10.544 1.00 12.73 C +ATOM 880 O LEU B 278 10.118 -11.639 10.140 1.00 19.80 O +ATOM 881 CB LEU B 278 10.621 -14.010 11.721 1.00 17.07 C +ATOM 882 CG LEU B 278 10.887 -15.612 11.784 1.00 20.72 C +ATOM 883 CD1 LEU B 278 9.743 -16.058 12.768 1.00 26.78 C +ATOM 884 CD2 LEU B 278 10.513 -16.229 10.192 1.00 22.51 C +ATOM 885 N THR B 279 12.124 -11.019 10.844 1.00 10.85 N +ATOM 886 CA THR B 279 11.888 -9.580 10.658 1.00 10.91 C +ATOM 887 C THR B 279 12.501 -9.102 9.356 1.00 11.12 C +ATOM 888 O THR B 279 13.671 -9.407 9.078 1.00 12.89 O +ATOM 889 CB THR B 279 12.517 -8.801 11.813 1.00 10.60 C +ATOM 890 OG1 THR B 279 11.721 -8.935 12.994 1.00 11.57 O +ATOM 891 CG2 THR B 279 12.676 -7.301 11.552 1.00 12.09 C +ATOM 892 N ILE B 280 11.699 -8.402 8.572 1.00 10.77 N +ATOM 893 CA ILE B 280 12.101 -7.808 7.306 1.00 10.70 C +ATOM 894 C ILE B 280 11.929 -6.297 7.452 1.00 9.56 C +ATOM 895 O ILE B 280 10.802 -5.815 7.480 1.00 11.05 O +ATOM 896 CB ILE B 280 11.283 -8.353 6.135 1.00 11.04 C +ATOM 897 CG1 ILE B 280 11.443 -9.854 5.977 1.00 12.99 C +ATOM 898 CG2 ILE B 280 11.674 -7.630 4.848 1.00 13.91 C +ATOM 899 CD1 ILE B 280 10.627 -10.530 4.933 1.00 15.29 C +ATOM 900 N TYR B 281 13.017 -5.563 7.612 1.00 9.95 N +ATOM 901 CA TYR B 281 12.918 -4.104 7.622 1.00 10.00 C +ATOM 902 C TYR B 281 12.476 -3.631 6.240 1.00 10.83 C +ATOM 903 O TYR B 281 13.016 -4.065 5.216 1.00 13.82 O +ATOM 904 CB TYR B 281 14.242 -3.422 8.111 1.00 11.29 C +ATOM 905 CG TYR B 281 14.359 -3.643 9.634 1.00 11.38 C +ATOM 906 CD1 TYR B 281 15.128 -4.632 10.167 1.00 12.02 C +ATOM 907 CD2 TYR B 281 13.622 -2.828 10.483 1.00 12.75 C +ATOM 908 CE1 TYR B 281 15.185 -4.790 11.579 1.00 12.84 C +ATOM 909 CE2 TYR B 281 13.646 -2.973 11.857 1.00 13.88 C +ATOM 910 CZ TYR B 281 14.427 -3.954 12.373 1.00 14.15 C +ATOM 911 OH TYR B 281 14.404 -4.084 13.775 1.00 16.24 O +ATOM 912 N ALA B 282 11.500 -2.767 6.208 1.00 10.01 N +ATOM 913 CA ALA B 282 10.815 -2.397 4.984 1.00 11.13 C +ATOM 914 C ALA B 282 10.577 -0.889 4.965 1.00 10.30 C +ATOM 915 O ALA B 282 10.663 -0.156 5.937 1.00 10.83 O +ATOM 916 CB ALA B 282 9.496 -3.180 4.899 1.00 14.45 C +""" +pdb_str_multi_copy_text=""" +ATOM 1 CA SERG2 11 672.659 271.890 642.978 1.00151.51 C +ATOM 2 CA HISG2 12 673.739 270.409 646.320 1.00157.48 C +ATOM 3 CA THRG2 13 676.617 268.051 647.149 1.00156.68 C +ATOM 4 CA GLYG2 14 675.899 264.844 649.034 1.00154.13 C +ATOM 5 CA GLYG2 15 679.108 264.054 650.891 1.00153.97 C +ATOM 6 CA THRG2 23 674.070 258.460 655.967 1.00160.53 C +ATOM 7 CA THRG2 24 676.423 255.647 656.957 1.00160.10 C +ATOM 8 CA ALAG2 25 679.963 254.891 655.848 1.00154.17 C +ATOM 9 CA ALAG2 26 680.922 251.245 656.223 1.00154.52 C +ATOM 10 CA ILEG2 37 680.349 251.357 651.276 1.00154.78 C +ATOM 11 CA ILEG2 38 678.241 254.479 651.807 1.00152.40 C +ATOM 12 CA GLYG2 39 674.481 254.465 652.075 1.00157.18 C +ATOM 13 CA PHEG2 40 672.890 257.774 651.173 1.00152.30 C +ATOM 14 CA GLUG2 41 669.611 257.161 652.958 1.00156.89 C +ATOM 15 CA ILEG2 49 666.867 263.693 645.296 1.00158.19 C +ATOM 16 CA GLUG2 50 667.733 263.423 641.604 1.00158.68 C +ATOM 17 CA TYRG2 51 671.207 262.216 640.645 1.00151.14 C +ATOM 18 CA VALG2 52 671.421 262.783 636.919 1.00155.98 C +ATOM 19 CA GLYG2 53 674.142 261.362 634.725 1.00154.05 C +ATOM 20 CA PROG2 62 690.221 255.358 649.160 1.00161.63 C +ATOM 21 CA ARGG2 63 693.277 254.515 651.225 1.00159.36 C +ATOM 22 CA THRG2 64 693.822 251.215 653.008 1.00158.95 C +ATOM 23 CA THRG2 65 695.857 250.702 656.156 1.00160.97 C +ATOM 24 CA GLUG2 66 699.182 248.925 656.483 1.00163.99 C +ATOM 25 CA SERG2 67 701.205 248.093 659.588 1.00166.35 C +ATOM 26 CA ILEG2 68 704.997 247.740 659.591 1.00170.65 C +ATOM 27 CA THRG2 69 707.072 246.430 662.481 1.00173.92 C +ATOM 28 CA GLYG2 70 710.480 248.079 662.226 1.00177.42 C +ATOM 29 CA ASPG2 75 713.949 252.746 655.039 1.00173.01 C +ATOM 30 CA THRG2 76 712.573 250.621 652.174 1.00170.65 C +ATOM 31 CA VALG2 77 708.870 249.996 652.727 1.00169.78 C +ATOM 32 CA VALG2 78 707.766 246.476 651.749 1.00172.32 C +ATOM 33 CA VALG2 100 699.875 259.341 647.120 1.00166.60 C +ATOM 34 CA ALAG2 101 700.963 257.718 650.404 1.00164.58 C +ATOM 35 CA VALG2 102 701.179 258.953 653.979 1.00162.87 C +ATOM 36 CA ALAG2 103 702.867 257.427 656.993 1.00165.65 C +ATOM 37 CA TYRG2 104 702.632 257.897 660.750 1.00167.15 C +ATOM 38 CA ASNG2 105 704.941 256.587 663.466 1.00170.08 C +ATOM 39 CA VALG2 106 702.716 255.629 666.398 1.00168.11 C +ATOM 40 CA GLYG2 109 703.748 260.527 667.204 1.00167.04 C +ATOM 41 CA VALG2 110 705.343 262.143 664.141 1.00167.66 C +ATOM 42 CA GLNG2 111 704.011 262.240 660.588 1.00166.26 C +ATOM 43 CA VALG2 112 706.906 260.533 658.815 1.00167.70 C +ATOM 44 CA ALAG2 116 711.004 258.660 647.111 1.00169.85 C +ATOM 45 CA VALG2 117 708.484 256.299 645.553 1.00170.77 C +ATOM 46 CA ASPG2 118 708.969 253.226 643.380 1.00174.41 C +ATOM 47 CA TYRG2 119 705.807 252.551 641.381 1.00171.25 C +ATOM 48 CA ASPG2 122 704.803 249.088 644.789 1.00174.07 C +ATOM 49 CA GLUG2 123 707.403 250.324 647.277 1.00173.78 C +ATOM 50 CA VALG2 124 707.938 253.704 648.922 1.00169.72 C +ATOM 51 CA THRG2 125 710.797 255.033 651.041 1.00171.78 C +ATOM 52 CA LEUG2 126 710.575 256.678 654.450 1.00169.68 C +ATOM 53 CA ASPG2 134 708.092 250.470 666.277 1.00176.26 C +ATOM 54 CA THRG2 135 704.740 250.368 664.472 1.00172.24 C +ATOM 55 CA VALG2 136 704.731 252.503 661.323 1.00167.53 C +ATOM 56 CA LYSG2 137 701.217 252.839 659.914 1.00163.35 C +ATOM 57 CA VALG2 138 701.163 253.650 656.194 1.00162.44 C +ATOM 58 CA TRPG2 139 698.086 254.634 654.195 1.00161.65 C +ATOM 59 CA PROG2 140 698.736 254.094 650.473 1.00160.01 C +ATOM 60 CA ILEG2 141 696.468 255.002 647.598 1.00161.49 C +ATOM 61 CA METG2 142 694.160 252.243 646.370 1.00158.89 C +ATOM 62 CA GLYG2 145 688.472 248.069 642.529 1.00161.75 C +ATOM 63 CA ASPG2 146 684.984 248.329 641.037 1.00161.37 C +ATOM 64 CA VALG2 147 682.243 250.828 641.888 1.00155.59 C +ATOM 65 CA GLNG2 148 678.568 251.150 640.989 1.00152.50 C +ATOM 66 CA PHEG2 149 675.564 253.048 642.353 1.00151.93 C +ATOM 67 CA ARGG2 150 672.598 250.981 643.552 1.00151.84 C +ATOM 68 CA LEUG2 151 669.086 252.076 644.529 1.00150.99 C +ATOM 69 CA VALG2 152 667.838 250.000 647.467 1.00152.42 C +ATOM 70 CA ASNG2 153 664.134 250.339 648.278 1.00153.50 C +ATOM 71 CA PROG2 168 687.142 250.935 637.661 1.00160.31 C +ATOM 72 CA LEUG2 169 688.516 252.524 640.783 1.00159.19 C +ATOM 73 CA TYRG2 170 692.006 253.510 639.589 1.00162.34 C +ATOM 74 CA ARGG2 171 690.581 255.651 636.779 1.00163.81 C +ATOM 75 CA TRPG2 172 689.312 257.923 639.532 1.00159.04 C +ATOM 76 CA HISG2 173 693.019 258.504 640.236 1.00160.31 C +ATOM 77 CA ASPG2 174 694.707 258.891 636.838 1.00163.51 C +ATOM 78 CA PHEG2 175 692.359 261.697 635.895 1.00164.10 C +ATOM 79 CA PROG2 176 692.847 264.852 637.973 1.00164.94 C +ATOM 80 CA GLYG2 188 672.254 256.633 634.404 1.00150.48 C +ATOM 81 CA SERG2 189 669.843 258.590 636.542 1.00151.32 C +ATOM 82 CA VALG2 190 668.359 258.078 640.009 1.00150.42 C +ATOM 83 CA THRG2 191 665.323 259.881 641.397 1.00151.52 C +ATOM 84 CA TRPG2 192 665.114 258.592 644.952 1.00154.98 C +ATOM 85 CA GLUG2 196 664.755 254.887 649.832 1.00156.20 C +ATOM 86 CA THRG2 197 668.559 254.735 649.786 1.00155.71 C +ATOM 87 CA VALG2 198 671.434 254.866 647.309 1.00153.21 C +ATOM 88 CA GLUG2 199 674.434 252.722 648.164 1.00153.70 C +ATOM 89 CA VALG2 200 677.820 252.558 646.464 1.00151.33 C +ATOM 90 CA LEUG2 201 679.168 249.071 645.768 1.00153.34 C +ATOM 91 CA LEUG2 202 682.922 248.516 645.715 1.00156.54 C +ATOM 92 CA ASPG2 203 684.797 245.322 644.888 1.00164.02 C +ATOM 93 CA ALAG2 204 688.441 245.597 645.932 1.00161.21 C +ATOM 94 CA GLUG2 225 680.703 263.065 647.464 1.00156.34 C +ATOM 95 CA GLNG2 226 678.643 263.859 644.399 1.00154.90 C +ATOM 96 CA ASPG2 227 676.860 266.889 643.014 1.00156.12 C +ATOM 97 CA VALG2 228 673.131 266.174 642.923 1.00155.70 C +ATOM 98 CA GLUG2 229 670.054 268.163 641.926 1.00154.93 C +TER +ATOM 99 CA ARGWy 15 120.437 414.861 579.347 1.00 30.00 C +ATOM 100 CA LEUWy 16 118.463 412.415 577.240 1.00 30.00 C +ATOM 101 CA GLYWy 17 118.534 409.852 580.055 1.00 30.00 C +ATOM 102 CA ARGWy 18 117.304 412.493 582.499 1.00 30.00 C +ATOM 103 CA LEUWy 19 114.479 413.600 580.202 1.00 30.00 C +ATOM 104 CA VALWy 20 113.409 409.997 579.631 1.00 30.00 C +ATOM 105 CA ASPWy 21 113.538 409.209 583.359 1.00 30.00 C +ATOM 106 CA VALWy 22 111.688 412.291 584.630 1.00 30.00 C +ATOM 107 CA LEUWy 23 108.997 411.976 581.954 1.00 30.00 C +ATOM 108 CA GLUWy 24 108.327 408.259 582.608 1.00 30.00 C +ATOM 109 CA SERWy 36 103.189 389.864 586.522 1.00 30.00 C +ATOM 110 CA VALWy 37 101.527 389.072 583.207 1.00 30.00 C +ATOM 111 CA THRWy 38 99.495 386.332 584.885 1.00 30.00 C +ATOM 112 CA GLNWy 39 98.146 388.814 587.414 1.00 30.00 C +ATOM 113 CA ASNWy 40 97.643 391.329 584.620 1.00 30.00 C +ATOM 114 CA ILEWy 41 95.385 388.873 582.829 1.00 30.00 C +ATOM 115 CA ASPWy 42 93.727 387.970 586.116 1.00 30.00 C +ATOM 116 CA ARGWy 43 92.880 391.586 586.908 1.00 30.00 C +ATOM 117 CA THRWy 44 90.369 391.588 584.049 1.00 30.00 C +ATOM 118 CA ARGWy 45 89.329 387.934 583.798 1.00 30.00 C +ATOM 119 CA TYRWy 57 84.834 397.337 600.087 1.00 28.58 C +ATOM 120 CA PHEWy 58 84.256 397.935 603.745 1.00 28.58 C +ATOM 121 CA SERWy 59 81.080 397.288 605.631 1.00 28.58 C +ATOM 122 CA THRWy 60 80.129 397.085 609.232 1.00 28.58 C +ATOM 123 CA TRPWy 73 85.481 408.794 620.165 1.00 28.58 C +ATOM 124 CA GLUWy 74 85.299 405.315 618.767 1.00 28.58 C +ATOM 125 CA ARGWy 75 87.588 404.794 615.793 1.00 28.58 C +ATOM 126 CA LEUWy 76 86.761 402.474 612.929 1.00 28.58 C +ATOM 127 CA ASPWy 77 89.512 401.568 610.492 1.00 28.58 C +ATOM 128 CA GLUWy 83 86.218 407.191 598.572 1.00 28.58 C +ATOM 129 CA THRWy 84 82.465 406.937 598.909 1.00 28.58 C +ATOM 130 CA VALWy 85 81.270 406.635 602.487 1.00 28.58 C +ATOM 131 CA ASNWy 86 77.658 405.777 603.207 1.00 28.58 C +ATOM 132 CA ILEWy 87 76.187 406.153 606.676 1.00 28.58 C +ATOM 133 CA ARGWy 88 72.820 404.596 607.396 1.00 28.58 C +ATOM 134 CA THRWy 89 72.114 406.202 610.718 1.00 28.58 C +ATOM 135 CA ASPWy 92 71.821 410.436 615.695 1.00 28.58 C +ATOM 136 CA ILEWy 93 75.581 410.571 615.331 1.00 28.58 C +ATOM 137 CA ASPWy 94 78.611 412.814 615.160 1.00 28.58 C +ATOM 138 CA ILEWy 95 80.918 411.557 612.441 1.00 28.58 C +ATOM 139 CA ALAWy 96 84.503 412.633 611.924 1.00 28.58 C +ATOM 140 CA PHEWy 97 87.164 412.454 609.238 1.00 28.58 C +ATOM 141 CA VALWy 106 83.050 417.115 612.993 1.00 28.58 C +ATOM 142 CA ILEWy 107 79.837 416.570 611.051 1.00 28.58 C +ATOM 143 CA ARGWy 108 76.512 415.914 612.727 1.00 28.58 C +ATOM 144 CA VALWy 109 74.028 413.525 611.136 1.00 28.58 C +ATOM 145 CA ARGWy 110 70.503 413.339 612.503 1.00 28.58 C +ATOM 146 CA PROWy 115 71.316 408.056 604.780 1.00 28.58 C +ATOM 147 CA PHEWy 116 74.355 410.264 604.459 1.00 28.58 C +ATOM 148 CA THRWy 117 76.453 409.808 601.328 1.00 28.58 C +ATOM 149 CA ILEWy 118 79.595 411.826 601.263 1.00 28.58 C +ATOM 150 CA PHEWy 128 89.716 406.354 608.844 1.00 28.58 C +ATOM 151 CA ILEWy 129 86.461 407.343 610.499 1.00 28.58 C +ATOM 152 CA TRPWy 130 85.322 408.270 613.973 1.00 28.58 C +ATOM 153 CA LEUWy 131 81.953 408.127 615.714 1.00 28.58 C +ATOM 154 CA ARGWy 132 80.468 409.700 618.829 1.00 28.58 C +ATOM 155 CA GLNWy 133 76.929 409.395 620.092 1.00 28.58 C +ATOM 156 CA GLYWy 142 73.668 402.397 612.876 1.00 28.58 C +ATOM 157 CA ILEWy 143 75.268 400.971 609.792 1.00 28.58 C +ATOM 158 CA GLNWy 144 78.292 401.955 607.690 1.00 28.58 C +ATOM 159 CA ILEWy 145 78.857 400.860 604.078 1.00 28.58 C +ATOM 160 CA ILEWy 146 81.877 402.244 602.293 1.00 28.58 C +ATOM 161 CA ALAWy 147 82.888 401.759 598.671 1.00 28.58 C +ATOM 162 CA PHEWy 148 86.162 402.464 596.931 1.00 28.58 C +TER +ATOM 163 CA PHEzy 21 113.436 495.542 626.654 1.00 30.00 C +ATOM 164 CA VALzy 22 113.344 495.929 630.415 1.00 30.00 C +ATOM 165 CA ASPzy 23 111.073 495.290 633.374 1.00 7.88 C +ATOM 166 CA GLUzy 24 110.713 497.176 636.654 1.00 8.25 C +ATOM 167 CA LEUzy 37 115.682 496.432 636.616 1.00 3.32 C +ATOM 168 CA THRzy 38 115.672 493.374 634.376 1.00 3.35 C +ATOM 169 CA ILEzy 39 116.974 493.440 630.814 1.00 3.43 C +ATOM 170 CA GLUzy 40 115.421 490.561 628.809 1.00 3.74 C +ATOM 171 CA THRzy 71 122.977 501.491 649.055 1.00 3.59 C +ATOM 172 CA ARGzy 72 124.767 499.630 646.282 1.00 3.24 C +ATOM 173 CA VALzy 73 123.947 499.218 642.600 1.00 2.99 C +ATOM 174 CA ILEzy 74 125.116 495.999 640.938 1.00 3.00 C +ATOM 175 CA VALzy 75 124.701 495.686 637.171 1.00 3.12 C +ATOM 176 CA GLNzy 76 125.420 492.035 636.492 1.00 3.11 C +ATOM 177 CA LYSzy 77 125.353 489.678 633.523 1.00 3.48 C +ATOM 178 CA CYSzy 78 122.996 486.732 633.998 1.00 3.94 C +ATOM 179 CA VALzy 90 130.042 494.542 634.875 1.00 30.00 C +ATOM 180 CA PHEzy 91 129.274 497.308 637.383 1.00 7.58 C +ATOM 181 CA ASNzy 92 129.328 497.553 641.172 1.00 6.80 C +ATOM 182 CA ASPzy 93 129.197 500.879 642.972 1.00 5.89 C +ATOM 183 CA THRzy 94 127.604 502.711 645.868 1.00 5.58 C +ATOM 184 CA LEUzy 95 124.478 504.593 644.818 1.00 5.02 C +ATOM 185 CA GLYzy 96 125.346 507.430 647.193 1.00 30.00 C +ATOM 186 CA ARGzy 97 128.447 508.119 645.122 1.00 30.00 C +ATOM 187 CA PHEzy 98 126.202 509.190 642.228 1.00 4.76 C +ATOM 188 CA ASPzy 99 124.945 512.783 642.059 1.00 4.32 C +ATOM 189 CA ASPzy 106 129.213 516.851 632.338 1.00 5.14 C +ATOM 190 CA PROzy 107 131.268 513.924 630.990 1.00 4.90 C +ATOM 191 CA ASPzy 108 133.647 514.165 633.930 1.00 30.00 C +ATOM 192 CA PHEzy 109 130.662 513.533 636.226 1.00 30.00 C +ATOM 193 CA METzy 110 129.553 510.289 634.565 1.00 5.10 C +ATOM 194 CA ARGzy 111 130.189 506.721 635.712 1.00 4.66 C +ATOM 195 CA ILEzy 124 119.871 488.710 630.783 1.00 4.01 C +ATOM 196 CA VALzy 125 121.381 491.733 632.532 1.00 3.51 C +ATOM 197 CA LYSzy 126 120.037 492.423 636.008 1.00 3.27 C +ATOM 198 CA VALzy 127 120.267 495.388 638.357 1.00 3.08 C +ATOM 199 CA PHEzy 128 120.504 494.509 642.045 1.00 3.07 C +ATOM 200 CA VALzy 129 119.824 497.272 644.564 1.00 30.00 C +ATOM 201 CA ASPzy 130 121.341 496.425 647.959 1.00 30.00 C +ATOM 202 CA ILEzy 131 119.598 498.577 650.580 1.00 30.00 C +""" +pdb_str_strands_text=""" +ATOM 1 N GLY B 23 75.748 31.574 -24.376 1.00 58.86 N +ATOM 2 CA GLY B 23 76.475 30.862 -25.415 1.00 59.81 C +ATOM 3 C GLY B 23 77.927 30.531 -25.134 1.00 60.79 C +ATOM 4 O GLY B 23 78.447 30.790 -24.037 1.00 61.67 O +ATOM 5 N PHE B 24 78.585 29.965 -26.144 1.00 61.14 N +ATOM 6 CA PHE B 24 79.949 29.472 -26.012 1.00 61.19 C +ATOM 7 C PHE B 24 80.944 30.243 -26.876 1.00 63.09 C +ATOM 8 O PHE B 24 80.642 30.610 -28.010 1.00 64.18 O +ATOM 9 N ARG B 25 82.129 30.486 -26.333 1.00 64.55 N +ATOM 10 CA ARG B 25 83.259 31.022 -27.092 1.00 66.14 C +ATOM 11 C ARG B 25 84.369 30.015 -26.941 1.00 67.43 C +ATOM 12 O ARG B 25 84.649 29.575 -25.829 1.00 67.73 O +ATOM 13 N HIS B 26 85.003 29.620 -28.035 1.00 69.33 N +ATOM 14 CA HIS B 26 86.018 28.591 -27.914 1.00 70.83 C +ATOM 15 C HIS B 26 87.300 28.976 -28.604 1.00 71.56 C +ATOM 16 O HIS B 26 87.385 30.005 -29.255 1.00 71.19 O +ATOM 17 N GLN B 27 88.303 28.131 -28.423 1.00 73.27 N +ATOM 18 CA GLN B 27 89.565 28.220 -29.128 1.00 74.94 C +ATOM 19 C GLN B 27 90.136 26.807 -29.242 1.00 75.41 C +ATOM 20 O GLN B 27 90.278 26.098 -28.245 1.00 75.24 O +ATOM 21 N ASN B 28 90.430 26.392 -30.470 1.00 76.59 N +ATOM 22 CA ASN B 28 91.030 25.085 -30.727 1.00 77.27 C +ATOM 23 C ASN B 28 92.077 25.140 -31.836 1.00 78.04 C +ATOM 24 O ASN B 28 92.478 26.226 -32.274 1.00 77.66 O +ATOM 25 N GLY B 31 91.225 27.382 -34.660 1.00 77.75 N +ATOM 26 CA GLY B 31 91.082 28.818 -34.394 1.00 77.38 C +ATOM 27 C GLY B 31 90.111 29.130 -33.271 1.00 77.12 C +ATOM 28 O GLY B 31 90.048 28.415 -32.267 1.00 76.86 O +ATOM 29 N THR B 32 89.356 30.213 -33.433 1.00 76.72 N +ATOM 30 CA THR B 32 88.434 30.670 -32.391 1.00 75.83 C +ATOM 31 C THR B 32 87.081 31.029 -32.982 1.00 75.68 C +ATOM 32 O THR B 32 87.014 31.617 -34.052 1.00 75.73 O +ATOM 33 N GLY B 33 86.011 30.676 -32.272 1.00 75.64 N +ATOM 34 CA GLY B 33 84.637 30.973 -32.708 1.00 74.81 C +ATOM 35 C GLY B 33 83.704 31.316 -31.559 1.00 73.94 C +ATOM 36 O GLY B 33 84.134 31.411 -30.406 1.00 74.08 O +ATOM 37 N GLN B 34 82.423 31.488 -31.885 1.00 72.72 N +ATOM 38 CA GLN B 34 81.403 31.939 -30.933 1.00 71.35 C +ATOM 39 C GLN B 34 80.018 31.496 -31.400 1.00 69.74 C +ATOM 40 O GLN B 34 79.642 31.760 -32.530 1.00 70.46 O +ATOM 41 N ALA B 35 79.250 30.842 -30.538 1.00 67.76 N +ATOM 42 CA ALA B 35 77.893 30.432 -30.897 1.00 66.29 C +ATOM 43 C ALA B 35 76.934 30.553 -29.715 1.00 65.90 C +ATOM 44 O ALA B 35 77.299 30.262 -28.574 1.00 66.09 O +ATOM 45 N ALA B 36 75.712 30.988 -30.000 1.00 64.80 N +ATOM 46 CA ALA B 36 74.680 31.141 -28.988 1.00 63.86 C +ATOM 47 C ALA B 36 74.125 29.759 -28.638 1.00 63.78 C +ATOM 48 O ALA B 36 74.159 28.866 -29.479 1.00 64.19 O +TER +ATOM 49 N GLY D 23 83.971 32.951 6.721 1.00 45.61 N +ATOM 50 CA GLY D 23 85.372 32.663 6.691 1.00 46.22 C +ATOM 51 C GLY D 23 85.873 31.235 6.715 1.00 45.42 C +ATOM 53 CA PHE D 24 87.986 30.081 7.243 1.00 46.15 C +ATOM 54 C PHE D 24 88.639 29.840 8.586 1.00 45.73 C +ATOM 55 N ARG D 25 88.677 28.529 8.785 1.00 46.53 N +ATOM 56 CA ARG D 25 89.502 27.858 9.773 1.00 46.92 C +ATOM 57 C ARG D 25 90.351 26.863 9.012 1.00 48.22 C +ATOM 58 O ARG D 25 89.902 26.301 8.005 1.00 48.21 O +ATOM 59 N HIS D 26 91.589 26.663 9.458 1.00 49.57 N +ATOM 60 CA HIS D 26 92.485 25.737 8.758 1.00 50.26 C +ATOM 61 C HIS D 26 93.451 25.007 9.666 1.00 50.46 C +ATOM 62 O HIS D 26 93.608 25.375 10.824 1.00 49.89 O +ATOM 63 N GLN D 27 94.091 23.974 9.118 1.00 51.49 N +ATOM 64 CA GLN D 27 95.222 23.320 9.764 1.00 52.01 C +ATOM 65 C GLN D 27 96.246 22.782 8.749 1.00 51.98 C +ATOM 66 N ASN D 28 97.431 23.381 8.906 1.00 53.20 N +ATOM 67 CA ASN D 28 98.667 23.022 8.198 1.00 53.62 C +ATOM 68 C ASN D 28 99.782 22.741 9.188 1.00 53.76 C +ATOM 69 O ASN D 28 99.562 22.726 10.389 1.00 54.00 O +ATOM 70 N GLY D 31 100.345 24.907 12.346 1.00 50.53 N +ATOM 71 CA GLY D 31 99.329 24.965 13.394 1.00 50.19 C +ATOM 72 C GLY D 31 97.937 25.229 12.840 1.00 50.80 C +ATOM 73 O GLY D 31 97.654 24.926 11.672 1.00 52.16 O +ATOM 74 N THR D 32 97.064 25.791 13.673 1.00 49.82 N +ATOM 75 CA THR D 32 95.691 26.083 13.281 1.00 49.15 C +ATOM 76 C THR D 32 95.490 27.580 13.139 1.00 50.69 C +ATOM 77 O THR D 32 96.305 28.374 13.631 1.00 51.88 O +ATOM 78 N GLY D 33 94.399 27.976 12.477 1.00 51.32 N +ATOM 79 CA GLY D 33 94.117 29.407 12.250 1.00 50.79 C +ATOM 80 C GLY D 33 92.666 29.678 11.925 1.00 50.08 C +ATOM 81 O GLY D 33 91.908 28.728 11.662 1.00 49.88 O +ATOM 82 N GLN D 34 92.291 30.966 11.956 1.00 49.01 N +ATOM 83 CA GLN D 34 90.926 31.420 11.677 1.00 49.25 C +ATOM 84 C GLN D 34 90.983 32.793 10.985 1.00 48.70 C +ATOM 85 O GLN D 34 91.799 33.610 11.349 1.00 49.25 O +ATOM 86 N ALA D 35 90.136 33.053 9.985 1.00 48.59 N +ATOM 87 CA ALA D 35 90.096 34.388 9.361 1.00 48.02 C +ATOM 88 C ALA D 35 88.791 34.664 8.628 1.00 48.49 C +ATOM 89 O ALA D 35 88.251 33.788 7.951 1.00 49.54 O +ATOM 90 N ALA D 36 88.285 35.881 8.768 1.00 48.74 N +ATOM 91 CA ALA D 36 87.038 36.277 8.117 1.00 49.59 C +ATOM 92 C ALA D 36 87.257 36.465 6.633 1.00 50.35 C +ATOM 93 O ALA D 36 88.340 36.838 6.226 1.00 50.20 O +TER +END +""" +pdb_str_strands_add_o_text=""" +ATOM 1 N GLY B 23 75.748 31.574 -24.376 1.00 58.86 N +ATOM 2 CA GLY B 23 76.475 30.862 -25.415 1.00 59.81 C +ATOM 3 C GLY B 23 77.927 30.531 -25.134 1.00 60.79 C +ATOM 4 O GLY B 23 78.447 30.790 -24.037 1.00 61.67 O +ATOM 5 N PHE B 24 78.585 29.965 -26.144 1.00 61.14 N +ATOM 6 CA PHE B 24 79.949 29.472 -26.012 1.00 61.19 C +ATOM 7 C PHE B 24 80.944 30.243 -26.876 1.00 63.09 C +ATOM 8 O PHE B 24 80.642 30.610 -28.010 1.00 64.18 O +ATOM 9 N ARG B 25 82.129 30.486 -26.333 1.00 64.55 N +ATOM 10 CA ARG B 25 83.259 31.022 -27.092 1.00 66.14 C +ATOM 11 C ARG B 25 84.369 30.015 -26.941 1.00 67.43 C +ATOM 12 O ARG B 25 84.649 29.575 -25.829 1.00 67.73 O +ATOM 13 N HIS B 26 85.003 29.620 -28.035 1.00 69.33 N +ATOM 14 CA HIS B 26 86.018 28.591 -27.914 1.00 70.83 C +ATOM 15 C HIS B 26 87.300 28.976 -28.604 1.00 71.56 C +ATOM 16 O HIS B 26 87.385 30.005 -29.255 1.00 71.19 O +ATOM 17 N GLN B 27 88.303 28.131 -28.423 1.00 73.27 N +ATOM 18 CA GLN B 27 89.565 28.220 -29.128 1.00 74.94 C +ATOM 19 C GLN B 27 90.136 26.807 -29.242 1.00 75.41 C +ATOM 20 O GLN B 27 90.278 26.098 -28.245 1.00 75.24 O +ATOM 21 N ASN B 28 90.430 26.392 -30.470 1.00 76.59 N +ATOM 22 CA ASN B 28 91.030 25.085 -30.727 1.00 77.27 C +ATOM 23 C ASN B 28 92.077 25.140 -31.836 1.00 78.04 C +ATOM 24 O ASN B 28 92.478 26.226 -32.274 1.00 77.66 O +ATOM 25 N GLY B 31 91.225 27.382 -34.660 1.00 77.75 N +ATOM 26 CA GLY B 31 91.082 28.818 -34.394 1.00 77.38 C +ATOM 27 C GLY B 31 90.111 29.130 -33.271 1.00 77.12 C +ATOM 28 O GLY B 31 90.048 28.415 -32.267 1.00 76.86 O +ATOM 29 N THR B 32 89.356 30.213 -33.433 1.00 76.72 N +ATOM 30 CA THR B 32 88.434 30.670 -32.391 1.00 75.83 C +ATOM 31 C THR B 32 87.081 31.029 -32.982 1.00 75.68 C +ATOM 32 O THR B 32 87.014 31.617 -34.052 1.00 75.73 O +ATOM 33 N GLY B 33 86.011 30.676 -32.272 1.00 75.64 N +ATOM 34 CA GLY B 33 84.637 30.973 -32.708 1.00 74.81 C +ATOM 35 C GLY B 33 83.704 31.316 -31.559 1.00 73.94 C +ATOM 36 O GLY B 33 84.134 31.411 -30.406 1.00 74.08 O +ATOM 37 N GLN B 34 82.423 31.488 -31.885 1.00 72.72 N +ATOM 38 CA GLN B 34 81.403 31.939 -30.933 1.00 71.35 C +ATOM 39 C GLN B 34 80.018 31.496 -31.400 1.00 69.74 C +ATOM 40 O GLN B 34 79.642 31.760 -32.530 1.00 70.46 O +ATOM 41 N ALA B 35 79.250 30.842 -30.538 1.00 67.76 N +ATOM 42 CA ALA B 35 77.893 30.432 -30.897 1.00 66.29 C +ATOM 43 C ALA B 35 76.934 30.553 -29.715 1.00 65.90 C +ATOM 44 O ALA B 35 77.299 30.262 -28.574 1.00 66.09 O +ATOM 45 N ALA B 36 75.712 30.988 -30.000 1.00 64.80 N +ATOM 46 CA ALA B 36 74.680 31.141 -28.988 1.00 63.86 C +ATOM 47 C ALA B 36 74.125 29.759 -28.638 1.00 63.78 C +ATOM 48 O ALA B 36 74.159 28.866 -29.479 1.00 64.19 O +TER +ATOM 49 N GLY D 23 83.971 32.951 6.721 1.00 45.61 N +ATOM 50 CA GLY D 23 85.372 32.663 6.691 1.00 46.22 C +ATOM 51 C GLY D 23 85.873 31.235 6.715 1.00 45.42 C +ATOM 52 N PHE D 24 87.131 31.246 7.173 1.00 46.55 N +ATOM 53 CA PHE D 24 87.986 30.081 7.243 1.00 46.15 C +ATOM 54 C PHE D 24 88.639 29.840 8.586 1.00 45.73 C +ATOM 54 O PHE D 24 88.639 31.000 9.400 1.00 45.73 C +ATOM 55 N ARG D 25 88.677 28.529 8.785 1.00 46.53 N +ATOM 56 CA ARG D 25 89.502 27.858 9.773 1.00 46.92 C +ATOM 57 C ARG D 25 90.351 26.863 9.012 1.00 48.22 C +ATOM 58 O ARG D 25 89.902 26.301 8.005 1.00 48.21 O +ATOM 59 N HIS D 26 91.589 26.663 9.458 1.00 49.57 N +ATOM 60 CA HIS D 26 92.485 25.737 8.758 1.00 50.26 C +ATOM 61 C HIS D 26 93.451 25.007 9.666 1.00 50.46 C +ATOM 62 O HIS D 26 93.608 25.375 10.824 1.00 49.89 O +ATOM 63 N GLN D 27 94.091 23.974 9.118 1.00 51.49 N +ATOM 64 CA GLN D 27 95.222 23.320 9.764 1.00 52.01 C +ATOM 65 C GLN D 27 96.246 22.782 8.749 1.00 51.98 C +ATOM 66 N ASN D 28 97.431 23.381 8.906 1.00 53.20 N +ATOM 67 CA ASN D 28 98.667 23.022 8.198 1.00 53.62 C +ATOM 68 C ASN D 28 99.782 22.741 9.188 1.00 53.76 C +ATOM 69 O ASN D 28 99.562 22.726 10.389 1.00 54.00 O +ATOM 70 N GLY D 31 100.345 24.907 12.346 1.00 50.53 N +ATOM 71 CA GLY D 31 99.329 24.965 13.394 1.00 50.19 C +ATOM 72 C GLY D 31 97.937 25.229 12.840 1.00 50.80 C +ATOM 73 O GLY D 31 97.654 24.926 11.672 1.00 52.16 O +ATOM 74 N THR D 32 97.064 25.791 13.673 1.00 49.82 N +ATOM 75 CA THR D 32 95.691 26.083 13.281 1.00 49.15 C +ATOM 76 C THR D 32 95.490 27.580 13.139 1.00 50.69 C +ATOM 77 O THR D 32 96.305 28.374 13.631 1.00 51.88 O +ATOM 78 N GLY D 33 94.399 27.976 12.477 1.00 51.32 N +ATOM 79 CA GLY D 33 94.117 29.407 12.250 1.00 50.79 C +ATOM 80 C GLY D 33 92.666 29.678 11.925 1.00 50.08 C +ATOM 81 O GLY D 33 91.908 28.728 11.662 1.00 49.88 O +ATOM 82 N GLN D 34 92.291 30.966 11.956 1.00 49.01 N +ATOM 83 CA GLN D 34 90.926 31.420 11.677 1.00 49.25 C +ATOM 84 C GLN D 34 90.983 32.793 10.985 1.00 48.70 C +ATOM 85 O GLN D 34 91.799 33.610 11.349 1.00 49.25 O +ATOM 86 N ALA D 35 90.136 33.053 9.985 1.00 48.59 N +ATOM 87 CA ALA D 35 90.096 34.388 9.361 1.00 48.02 C +ATOM 88 C ALA D 35 88.791 34.664 8.628 1.00 48.49 C +ATOM 89 O ALA D 35 88.251 33.788 7.951 1.00 49.54 O +ATOM 90 N ALA D 36 88.285 35.881 8.768 1.00 48.74 N +ATOM 91 CA ALA D 36 87.038 36.277 8.117 1.00 49.59 C +ATOM 92 C ALA D 36 87.257 36.465 6.633 1.00 50.35 C +ATOM 93 O ALA D 36 88.340 36.838 6.226 1.00 50.20 O +TER +END +""" +pdb_str_sheets =""" +ATOM 2 CA THRAa 3 186.743 125.884 251.259 1.00100.00 C +ATOM 5 CA ASNAa 4 189.629 123.742 252.763 1.00100.00 C +ATOM 8 CA SERAa 5 191.072 126.112 255.320 1.00100.00 C +ATOM 11 CA ASPAa 6 192.080 124.928 258.848 1.00100.00 C +ATOM 14 CA PHEAa 7 189.384 124.585 261.530 1.00100.00 C +ATOM 17 CA VALAa 8 189.248 124.466 265.315 1.00100.00 C +ATOM 20 CA VALAa 9 187.059 122.294 267.547 1.00100.00 C +ATOM 23 CA ILEAa 10 185.534 123.893 270.679 1.00100.00 C +ATOM 26 CA LYSAa 11 183.570 122.134 273.450 1.00100.00 C +ATOM 29 CA ALAAa 12 181.897 124.298 276.085 1.00100.00 C +ATOM 32 CA LEUAa 13 182.733 123.145 279.601 1.00100.00 C +ATOM 35 CA GLUAa 14 180.241 125.609 281.156 1.00100.00 C +ATOM 38 CA ASPAa 15 177.155 127.540 279.985 1.00100.00 C +ATOM 41 CA GLYAa 16 177.637 130.843 278.162 1.00100.00 C +ATOM 44 CA VALAa 17 180.958 130.212 276.395 1.00100.00 C +ATOM 47 CA ASNAa 18 181.477 132.715 273.547 1.00100.00 C +ATOM 50 CA VALAa 19 183.320 131.753 270.320 1.00100.00 C +ATOM 53 CA ILEAa 20 184.043 135.156 268.674 1.00100.00 C +ATOM 56 CA GLYAa 21 185.054 135.558 264.994 1.00100.00 C +ATOM 59 CA LEUAa 22 187.345 138.529 264.419 1.00100.00 C +ATOM 62 CA THRAa 23 187.310 140.218 261.033 1.00100.00 C +ATOM 65 CA ARGAa 24 189.831 139.523 258.335 1.00100.00 C +ATOM 68 CA GLYAa 25 191.359 142.673 256.805 1.00100.00 C +ATOM 71 CA ALAAa 26 192.794 146.041 257.837 1.00100.00 C +ATOM 74 CA ASPAa 27 190.126 146.289 260.564 1.00100.00 C +ATOM 77 CA THRAa 28 189.912 143.928 263.570 1.00100.00 C +ATOM 80 CA ARGAa 29 186.413 143.856 265.033 1.00100.00 C +ATOM 83 CA PHEAa 30 183.873 141.240 266.091 1.00100.00 C +ATOM 86 CA HISAa 31 181.625 140.079 263.343 1.00100.00 C +ATOM 89 CA HISAa 32 179.931 137.209 265.203 1.00100.00 C +ATOM 92 CA SERAa 33 179.805 135.702 268.677 1.00100.00 C +ATOM 95 CA GLUAa 34 178.501 132.109 268.857 1.00100.00 C +ATOM 98 CA CYSAa 35 177.222 131.284 272.342 1.00100.00 C +ATOM 101 CA LEUAa 36 177.646 127.700 273.502 1.00100.00 C +ATOM 104 CA ASPAa 37 175.969 125.990 276.438 1.00100.00 C +ATOM 107 CA LYSAa 38 177.682 123.298 278.488 1.00100.00 C +ATOM 110 CA GLYAa 39 178.623 120.300 276.385 1.00100.00 C +ATOM 113 CA GLUAa 40 177.892 121.761 272.941 1.00100.00 C +ATOM 116 CA VALAa 41 180.597 121.439 270.276 1.00100.00 C +ATOM 119 CA LEUAa 42 181.492 123.998 267.594 1.00100.00 C +ATOM 122 CA ILEAa 43 183.793 123.155 264.645 1.00100.00 C +ATOM 125 CA ALAAa 44 184.701 126.388 262.889 1.00100.00 C +ATOM 128 CA GLNAa 45 186.987 127.209 259.959 1.00100.00 C +ATOM 131 CA PHEAa 46 189.115 130.161 259.157 1.00100.00 C +ATOM 134 CA THRAa 47 187.356 131.901 256.203 1.00100.00 C +ATOM 137 CA GLUAa 48 187.180 134.953 253.965 1.00100.00 C +ATOM 140 CA HISAa 49 185.578 136.805 256.905 1.00100.00 C +ATOM 143 CA THRAa 50 187.343 135.292 259.938 1.00100.00 C +ATOM 146 CA SERAa 51 191.129 135.327 260.339 1.00100.00 C +ATOM 149 CA ALAAa 52 191.231 135.094 264.170 1.00100.00 C +ATOM 152 CA ILEAa 53 188.989 133.390 266.744 1.00100.00 C +ATOM 155 CA LYSAa 54 188.770 134.368 270.428 1.00100.00 C +ATOM 158 CA VALAa 55 187.303 131.970 273.016 1.00100.00 C +ATOM 161 CA ARGAa 56 185.817 133.382 276.214 1.00100.00 C +ATOM 164 CA GLYAa 57 184.672 131.065 278.997 1.00100.00 C +ATOM 167 CA LYSAa 58 185.698 127.553 280.004 1.00100.00 C +ATOM 170 CA ALAAa 59 186.172 125.294 276.966 1.00100.00 C +ATOM 173 CA TYRAa 60 188.258 122.444 275.620 1.00100.00 C +ATOM 176 CA ILEAa 61 189.863 123.277 272.265 1.00100.00 C +ATOM 179 CA GLNAa 62 191.492 121.098 269.577 1.00100.00 C +ATOM 182 CA THRAa 63 193.550 122.431 266.653 1.00100.00 C +ATOM 185 CA ARGAa 64 196.271 121.116 264.358 1.00100.00 C +ATOM 188 CA HISAa 65 198.826 122.305 266.995 1.00100.00 C +ATOM 191 CA GLYAa 66 197.443 120.330 269.914 1.00100.00 C +ATOM 194 CA VALAa 67 194.865 120.679 272.646 1.00100.00 C +ATOM 197 CA ILEAa 68 194.232 123.486 275.120 1.00100.00 C +ATOM 200 CA GLUAa 69 191.576 124.693 277.564 1.00100.00 C +ATOM 203 CA SERAa 70 190.301 128.219 277.907 1.00100.00 C +ATOM 206 CA GLUAa 71 189.167 129.249 281.377 1.00100.00 C +ATOM 209 CA GLYAa 72 186.003 131.073 282.428 1.00100.00 C +""" +pdb_str_unusual_residues=""" +ATOM 8 CA GLY A 2 24.485 19.185 6.248 1.00 11.14 C +HETATM 15 CA 23F A 3 26.939 16.455 5.194 1.00 9.61 C +ATOM 33 CA ALA A 4 29.149 18.888 3.424 1.00 9.96 C +HETATM 43 CA 23F A 5 30.573 19.304 6.910 1.00 6.42 C +HETATM 61 CA 23F A 6 32.558 16.167 6.280 1.00 6.41 C +ATOM 79 CA ALA A 7 35.089 18.339 4.563 1.00 6.26 C +HETATM 89 CA 23F A 8 36.195 19.092 8.094 1.00 6.38 C +HETATM 107 CA 23F A 9 38.283 15.914 7.621 1.00 7.78 C +ATOM 125 CA ALA A 10 40.789 18.180 5.892 1.00 8.66 C +ATOM 135 CA GLY A 11 41.608 19.716 9.325 1.00 10.78 C +ATOM 142 CA GLY A 12 44.498 17.479 9.975 1.00 17.00 C +ATOM 149 CA GLY A 13 43.927 17.193 13.603 1.00 13.58 C +ATOM 156 CA GLY A 14 41.242 17.379 16.363 1.00 11.14 C +HETATM 163 CA 23F A 15 39.608 20.319 14.616 1.00 7.70 C +ATOM 181 CA ALA A 16 38.402 17.853 12.023 1.00 7.08 C +ATOM 191 CA LEU A 17 35.810 16.973 14.649 1.00 6.22 C +HETATM 210 CA 23F A 18 34.098 20.219 13.633 1.00 6.81 C +ATOM 228 CA ALA A 19 32.642 18.019 10.889 1.00 6.28 C +ATOM 238 CA LEU A 20 30.139 16.927 13.574 1.00 6.81 C +HETATM 257 CA 23F A 21 28.460 20.242 12.654 1.00 8.80 C +ATOM 275 CA ALA A 22 27.017 18.382 9.700 1.00 7.89 C +""" +pdb_str_alt_confs_no_a=""" +ATOM 651 CA BPRO E 1 14.350 6.490 -29.205 0.50 16.99 C +ATOM 658 CA BPRO E 2 12.612 6.495 -25.864 0.50 14.37 C +ATOM 666 CA AGLY E 3 12.816 7.962 -32.315 0.55 19.29 C +ATOM 667 CA BGLY E 3 13.074 9.621 -23.839 0.45 12.65 C +ATOM 674 CA APRO E 4 14.350 6.490 -29.205 0.50 16.99 C +ATOM 675 CA BPRO E 4 15.262 10.063 -20.808 0.50 15.34 C +ATOM 688 CA APRO E 5 12.612 6.495 -25.864 0.50 14.37 C +ATOM 689 CA BPRO E 5 14.316 8.840 -17.372 0.50 10.66 C +ATOM 702 CA AGLY E 6 13.074 9.621 -23.839 0.50 12.65 C +ATOM 703 CA BGLY E 6 11.932 10.884 -15.276 0.50 7.99 C +ATOM 710 CA APRO E 7 15.262 10.063 -20.808 0.50 15.34 C +ATOM 711 CA BPRO E 7 13.150 12.796 -12.241 0.50 9.73 C """ +pdb_str_tst_2_text=""" +ATOM 2 CA GLY A 1 43.603 -11.488 24.325 1.00 35.57 +ATOM 6 CA ILE A 2 44.200 -8.183 22.475 1.00 27.55 +ATOM 14 CA GLY A 3 43.999 -10.264 19.329 1.00 21.05 +ATOM 18 CA ALA A 4 40.378 -11.260 20.106 1.00 21.80 +ATOM 23 CA VAL A 5 39.355 -7.658 21.083 1.00 19.34 +ATOM 30 CA LEU A 6 41.062 -6.432 17.957 1.00 17.59 +ATOM 38 CA LYS A 7 39.079 -8.646 15.636 1.00 22.55 +ATOM 47 CA VAL A 8 35.792 -7.369 17.211 1.00 20.52 +ATOM 69 CA THR A 11 34.132 -6.405 12.343 1.00 24.14 +ATOM 76 CA GLY A 12 31.584 -6.595 15.140 1.00 24.17 +ATOM 80 CA LEU A 13 31.923 -2.919 16.364 1.00 23.24 +ATOM 88 CA PRO A 14 31.026 -1.278 13.030 1.00 17.52 +ATOM 95 CA ALA A 15 27.822 -3.418 12.724 1.00 17.10 +ATOM 100 CA LEU A 16 26.958 -2.649 16.351 1.00 18.20 +ATOM 108 CA ILE A 17 27.343 1.056 15.618 1.00 20.41 +ATOM 116 CA SER A 18 24.825 0.827 12.744 1.00 19.98 +ATOM 122 CA TRP A 19 22.492 -1.085 15.081 1.00 15.72 +ATOM 136 CA ILE A 20 22.628 1.633 17.766 1.00 15.67 +ATOM 144 CA LYS A 21 21.888 4.236 15.157 1.00 19.84 +ATOM 153 CA ARG A 22 18.740 2.273 14.020 1.00 20.38 +ATOM 164 CA LYS A 23 17.500 1.928 17.550 1.00 22.62 +ATOM 173 CA ARG A 24 18.059 5.674 18.276 1.00 27.11 +ATOM 184 CA GLN A 25 15.836 6.730 15.339 1.00 37.50 +ATOM 193 CA GLN A 26 13.132 4.360 16.583 1.00 46.66 +""" + + + +pdb_str_two_chain_one_full_helix_text = \ + pdb_str_two_chain_text+pdb_str_one_full_helix_text + +# Convert to mmcif: +chain_addition = "XZLONG" +from libtbx.test_utils import convert_pdb_to_cif_for_pdb_str +convert_pdb_to_cif_for_pdb_str(locals(),chain_addition=chain_addition) + +def tst_00(): + print("Finding sheets, splitting and merging...", end=' ') + import iotbx.pdb + from cctbx.array_family import flex + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_std_text)).construct_hierarchy() + fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False,out=null_out()) + cif_block=fss.annotation.as_cif_block() + import iotbx.pdb.secondary_structure as ioss + annotation=ioss.annotation.from_cif_block(cif_block) + f=StringIO() + print("New records: \n",annotation.as_pdb_or_mmcif_str(), file=f) + spl=annotation.split_sheets() + print("After split_sheets: \n",spl.as_pdb_or_mmcif_str(), file=f) + merged=spl.merge_sheets() + print("After merge_sheets: \n",merged.as_pdb_or_mmcif_str(), file=f) + print("\nSpl:\n",spl.as_pdb_or_mmcif_str(), file=f) + assert merged.is_same_as(annotation) + print("\nComparing merged and spl:", file=f) + print("\nMerged:\n",merged.as_pdb_or_mmcif_str(), file=f) + print("\nSpl:\n",spl.as_pdb_or_mmcif_str(), file=f) + print("\nFINAL PDB selections:\n",merged.as_atom_selections(), file=f) + assert merged.is_same_as(spl) + found_text=f.getvalue() + + expected_text=""" +New records: + data_phenix +loop_ + _struct_sheet.id + _struct_sheet.type + _struct_sheet.number_strands + _struct_sheet.details + 1 ? 3 ? + 2 ? 4 ? + +loop_ + _struct_sheet_order.sheet_id + _struct_sheet_order.range_id_1 + _struct_sheet_order.range_id_2 + _struct_sheet_order.offset + _struct_sheet_order.sense + 1 1 2 ? anti-parallel + 1 2 3 ? anti-parallel + 2 1 2 ? anti-parallel + 2 2 3 ? anti-parallel + 2 3 4 ? anti-parallel + +loop_ + _struct_sheet_range.sheet_id + _struct_sheet_range.id + _struct_sheet_range.beg_label_comp_id + _struct_sheet_range.beg_label_asym_id + _struct_sheet_range.beg_label_seq_id + _struct_sheet_range.pdbx_beg_PDB_ins_code + _struct_sheet_range.end_label_comp_id + _struct_sheet_range.end_label_asym_id + _struct_sheet_range.end_label_seq_id + _struct_sheet_range.pdbx_end_PDB_ins_code + 1 1 HIS AaXZLONG 32 ? LEU AaXZLONG 36 ? + 1 2 VAL AaXZLONG 17 ? LEU AaXZLONG 22 ? + 1 3 ALA AaXZLONG 52 ? VAL AaXZLONG 55 ? + 2 1 GLU AaXZLONG 40 ? GLN AaXZLONG 45 ? + 2 2 PHE AaXZLONG 7 ? ALA AaXZLONG 12 ? + 2 3 LYS AaXZLONG 58 ? THR AaXZLONG 63 ? + 2 4 GLY AaXZLONG 66 ? GLU AaXZLONG 71 ? + +loop_ + _pdbx_struct_sheet_hbond.sheet_id + _pdbx_struct_sheet_hbond.range_id_1 + _pdbx_struct_sheet_hbond.range_id_2 + _pdbx_struct_sheet_hbond.range_1_label_atom_id + _pdbx_struct_sheet_hbond.range_1_label_comp_id + _pdbx_struct_sheet_hbond.range_1_label_asym_id + _pdbx_struct_sheet_hbond.range_1_label_seq_id + _pdbx_struct_sheet_hbond.range_1_PDB_ins_code + _pdbx_struct_sheet_hbond.range_2_label_atom_id + _pdbx_struct_sheet_hbond.range_2_label_comp_id + _pdbx_struct_sheet_hbond.range_2_label_asym_id + _pdbx_struct_sheet_hbond.range_2_label_seq_id + _pdbx_struct_sheet_hbond.range_2_PDB_ins_code + 1 1 2 O HIS AaXZLONG 32 ? N GLY AaXZLONG 21 ? + 1 2 3 O ILE AaXZLONG 20 ? N LYS AaXZLONG 54 ? + 2 1 2 O GLU AaXZLONG 40 ? N ALA AaXZLONG 12 ? + 2 2 3 O VAL AaXZLONG 9 ? N GLN AaXZLONG 62 ? + 2 3 4 O ALA AaXZLONG 59 ? N SER AaXZLONG 70 ? + + +After split_sheets: + data_phenix +loop_ + _struct_sheet.id + _struct_sheet.type + _struct_sheet.number_strands + _struct_sheet.details + 1 ? 2 ? + 2 ? 2 ? + 3 ? 2 ? + 4 ? 2 ? + 5 ? 2 ? + +loop_ + _struct_sheet_order.sheet_id + _struct_sheet_order.range_id_1 + _struct_sheet_order.range_id_2 + _struct_sheet_order.offset + _struct_sheet_order.sense + 1 1 2 ? anti-parallel + 2 1 2 ? anti-parallel + 3 1 2 ? anti-parallel + 4 1 2 ? anti-parallel + 5 1 2 ? anti-parallel + +loop_ + _struct_sheet_range.sheet_id + _struct_sheet_range.id + _struct_sheet_range.beg_label_comp_id + _struct_sheet_range.beg_label_asym_id + _struct_sheet_range.beg_label_seq_id + _struct_sheet_range.pdbx_beg_PDB_ins_code + _struct_sheet_range.end_label_comp_id + _struct_sheet_range.end_label_asym_id + _struct_sheet_range.end_label_seq_id + _struct_sheet_range.pdbx_end_PDB_ins_code + 1 1 HIS AaXZLONG 32 ? LEU AaXZLONG 36 ? + 1 2 VAL AaXZLONG 17 ? LEU AaXZLONG 22 ? + 2 1 VAL AaXZLONG 17 ? LEU AaXZLONG 22 ? + 2 2 ALA AaXZLONG 52 ? VAL AaXZLONG 55 ? + 3 1 GLU AaXZLONG 40 ? GLN AaXZLONG 45 ? + 3 2 PHE AaXZLONG 7 ? ALA AaXZLONG 12 ? + 4 1 PHE AaXZLONG 7 ? ALA AaXZLONG 12 ? + 4 2 LYS AaXZLONG 58 ? THR AaXZLONG 63 ? + 5 1 LYS AaXZLONG 58 ? THR AaXZLONG 63 ? + 5 2 GLY AaXZLONG 66 ? GLU AaXZLONG 71 ? + +loop_ + _pdbx_struct_sheet_hbond.sheet_id + _pdbx_struct_sheet_hbond.range_id_1 + _pdbx_struct_sheet_hbond.range_id_2 + _pdbx_struct_sheet_hbond.range_1_label_atom_id + _pdbx_struct_sheet_hbond.range_1_label_comp_id + _pdbx_struct_sheet_hbond.range_1_label_asym_id + _pdbx_struct_sheet_hbond.range_1_label_seq_id + _pdbx_struct_sheet_hbond.range_1_PDB_ins_code + _pdbx_struct_sheet_hbond.range_2_label_atom_id + _pdbx_struct_sheet_hbond.range_2_label_comp_id + _pdbx_struct_sheet_hbond.range_2_label_asym_id + _pdbx_struct_sheet_hbond.range_2_label_seq_id + _pdbx_struct_sheet_hbond.range_2_PDB_ins_code + 1 1 2 O HIS AaXZLONG 32 ? N GLY AaXZLONG 21 ? + 2 1 2 O ILE AaXZLONG 20 ? N LYS AaXZLONG 54 ? + 3 1 2 O GLU AaXZLONG 40 ? N ALA AaXZLONG 12 ? + 4 1 2 O VAL AaXZLONG 9 ? N GLN AaXZLONG 62 ? + 5 1 2 O ALA AaXZLONG 59 ? N SER AaXZLONG 70 ? + + +After merge_sheets: + data_phenix +loop_ + _struct_sheet.id + _struct_sheet.type + _struct_sheet.number_strands + _struct_sheet.details + 1 ? 3 ? + 2 ? 4 ? + +loop_ + _struct_sheet_order.sheet_id + _struct_sheet_order.range_id_1 + _struct_sheet_order.range_id_2 + _struct_sheet_order.offset + _struct_sheet_order.sense + 1 1 2 ? anti-parallel + 1 2 3 ? anti-parallel + 2 1 2 ? anti-parallel + 2 2 3 ? anti-parallel + 2 3 4 ? anti-parallel + +loop_ + _struct_sheet_range.sheet_id + _struct_sheet_range.id + _struct_sheet_range.beg_label_comp_id + _struct_sheet_range.beg_label_asym_id + _struct_sheet_range.beg_label_seq_id + _struct_sheet_range.pdbx_beg_PDB_ins_code + _struct_sheet_range.end_label_comp_id + _struct_sheet_range.end_label_asym_id + _struct_sheet_range.end_label_seq_id + _struct_sheet_range.pdbx_end_PDB_ins_code + 1 1 HIS AaXZLONG 32 ? LEU AaXZLONG 36 ? + 1 2 VAL AaXZLONG 17 ? LEU AaXZLONG 22 ? + 1 3 ALA AaXZLONG 52 ? VAL AaXZLONG 55 ? + 2 1 GLU AaXZLONG 40 ? GLN AaXZLONG 45 ? + 2 2 PHE AaXZLONG 7 ? ALA AaXZLONG 12 ? + 2 3 LYS AaXZLONG 58 ? THR AaXZLONG 63 ? + 2 4 GLY AaXZLONG 66 ? GLU AaXZLONG 71 ? + +loop_ + _pdbx_struct_sheet_hbond.sheet_id + _pdbx_struct_sheet_hbond.range_id_1 + _pdbx_struct_sheet_hbond.range_id_2 + _pdbx_struct_sheet_hbond.range_1_label_atom_id + _pdbx_struct_sheet_hbond.range_1_label_comp_id + _pdbx_struct_sheet_hbond.range_1_label_asym_id + _pdbx_struct_sheet_hbond.range_1_label_seq_id + _pdbx_struct_sheet_hbond.range_1_PDB_ins_code + _pdbx_struct_sheet_hbond.range_2_label_atom_id + _pdbx_struct_sheet_hbond.range_2_label_comp_id + _pdbx_struct_sheet_hbond.range_2_label_asym_id + _pdbx_struct_sheet_hbond.range_2_label_seq_id + _pdbx_struct_sheet_hbond.range_2_PDB_ins_code + 1 1 2 O HIS AaXZLONG 32 ? N GLY AaXZLONG 21 ? + 1 2 3 O ILE AaXZLONG 20 ? N LYS AaXZLONG 54 ? + 2 1 2 O GLU AaXZLONG 40 ? N ALA AaXZLONG 12 ? + 2 2 3 O VAL AaXZLONG 9 ? N GLN AaXZLONG 62 ? + 2 3 4 O ALA AaXZLONG 59 ? N SER AaXZLONG 70 ? + + + +Spl: + data_phenix +loop_ + _struct_sheet.id + _struct_sheet.type + _struct_sheet.number_strands + _struct_sheet.details + 1 ? 2 ? + 2 ? 2 ? + 3 ? 2 ? + 4 ? 2 ? + 5 ? 2 ? + +loop_ + _struct_sheet_order.sheet_id + _struct_sheet_order.range_id_1 + _struct_sheet_order.range_id_2 + _struct_sheet_order.offset + _struct_sheet_order.sense + 1 1 2 ? anti-parallel + 2 1 2 ? anti-parallel + 3 1 2 ? anti-parallel + 4 1 2 ? anti-parallel + 5 1 2 ? anti-parallel + +loop_ + _struct_sheet_range.sheet_id + _struct_sheet_range.id + _struct_sheet_range.beg_label_comp_id + _struct_sheet_range.beg_label_asym_id + _struct_sheet_range.beg_label_seq_id + _struct_sheet_range.pdbx_beg_PDB_ins_code + _struct_sheet_range.end_label_comp_id + _struct_sheet_range.end_label_asym_id + _struct_sheet_range.end_label_seq_id + _struct_sheet_range.pdbx_end_PDB_ins_code + 1 1 HIS AaXZLONG 32 ? LEU AaXZLONG 36 ? + 1 2 VAL AaXZLONG 17 ? LEU AaXZLONG 22 ? + 2 1 VAL AaXZLONG 17 ? LEU AaXZLONG 22 ? + 2 2 ALA AaXZLONG 52 ? VAL AaXZLONG 55 ? + 3 1 GLU AaXZLONG 40 ? GLN AaXZLONG 45 ? + 3 2 PHE AaXZLONG 7 ? ALA AaXZLONG 12 ? + 4 1 PHE AaXZLONG 7 ? ALA AaXZLONG 12 ? + 4 2 LYS AaXZLONG 58 ? THR AaXZLONG 63 ? + 5 1 LYS AaXZLONG 58 ? THR AaXZLONG 63 ? + 5 2 GLY AaXZLONG 66 ? GLU AaXZLONG 71 ? + +loop_ + _pdbx_struct_sheet_hbond.sheet_id + _pdbx_struct_sheet_hbond.range_id_1 + _pdbx_struct_sheet_hbond.range_id_2 + _pdbx_struct_sheet_hbond.range_1_label_atom_id + _pdbx_struct_sheet_hbond.range_1_label_comp_id + _pdbx_struct_sheet_hbond.range_1_label_asym_id + _pdbx_struct_sheet_hbond.range_1_label_seq_id + _pdbx_struct_sheet_hbond.range_1_PDB_ins_code + _pdbx_struct_sheet_hbond.range_2_label_atom_id + _pdbx_struct_sheet_hbond.range_2_label_comp_id + _pdbx_struct_sheet_hbond.range_2_label_asym_id + _pdbx_struct_sheet_hbond.range_2_label_seq_id + _pdbx_struct_sheet_hbond.range_2_PDB_ins_code + 1 1 2 O HIS AaXZLONG 32 ? N GLY AaXZLONG 21 ? + 2 1 2 O ILE AaXZLONG 20 ? N LYS AaXZLONG 54 ? + 3 1 2 O GLU AaXZLONG 40 ? N ALA AaXZLONG 12 ? + 4 1 2 O VAL AaXZLONG 9 ? N GLN AaXZLONG 62 ? + 5 1 2 O ALA AaXZLONG 59 ? N SER AaXZLONG 70 ? + + + +Comparing merged and spl: + +Merged: + data_phenix +loop_ + _struct_sheet.id + _struct_sheet.type + _struct_sheet.number_strands + _struct_sheet.details + 1 ? 3 ? + 2 ? 4 ? + +loop_ + _struct_sheet_order.sheet_id + _struct_sheet_order.range_id_1 + _struct_sheet_order.range_id_2 + _struct_sheet_order.offset + _struct_sheet_order.sense + 1 1 2 ? anti-parallel + 1 2 3 ? anti-parallel + 2 1 2 ? anti-parallel + 2 2 3 ? anti-parallel + 2 3 4 ? anti-parallel + +loop_ + _struct_sheet_range.sheet_id + _struct_sheet_range.id + _struct_sheet_range.beg_label_comp_id + _struct_sheet_range.beg_label_asym_id + _struct_sheet_range.beg_label_seq_id + _struct_sheet_range.pdbx_beg_PDB_ins_code + _struct_sheet_range.end_label_comp_id + _struct_sheet_range.end_label_asym_id + _struct_sheet_range.end_label_seq_id + _struct_sheet_range.pdbx_end_PDB_ins_code + 1 1 HIS AaXZLONG 32 ? LEU AaXZLONG 36 ? + 1 2 VAL AaXZLONG 17 ? LEU AaXZLONG 22 ? + 1 3 ALA AaXZLONG 52 ? VAL AaXZLONG 55 ? + 2 1 GLU AaXZLONG 40 ? GLN AaXZLONG 45 ? + 2 2 PHE AaXZLONG 7 ? ALA AaXZLONG 12 ? + 2 3 LYS AaXZLONG 58 ? THR AaXZLONG 63 ? + 2 4 GLY AaXZLONG 66 ? GLU AaXZLONG 71 ? + +loop_ + _pdbx_struct_sheet_hbond.sheet_id + _pdbx_struct_sheet_hbond.range_id_1 + _pdbx_struct_sheet_hbond.range_id_2 + _pdbx_struct_sheet_hbond.range_1_label_atom_id + _pdbx_struct_sheet_hbond.range_1_label_comp_id + _pdbx_struct_sheet_hbond.range_1_label_asym_id + _pdbx_struct_sheet_hbond.range_1_label_seq_id + _pdbx_struct_sheet_hbond.range_1_PDB_ins_code + _pdbx_struct_sheet_hbond.range_2_label_atom_id + _pdbx_struct_sheet_hbond.range_2_label_comp_id + _pdbx_struct_sheet_hbond.range_2_label_asym_id + _pdbx_struct_sheet_hbond.range_2_label_seq_id + _pdbx_struct_sheet_hbond.range_2_PDB_ins_code + 1 1 2 O HIS AaXZLONG 32 ? N GLY AaXZLONG 21 ? + 1 2 3 O ILE AaXZLONG 20 ? N LYS AaXZLONG 54 ? + 2 1 2 O GLU AaXZLONG 40 ? N ALA AaXZLONG 12 ? + 2 2 3 O VAL AaXZLONG 9 ? N GLN AaXZLONG 62 ? + 2 3 4 O ALA AaXZLONG 59 ? N SER AaXZLONG 70 ? + + + +Spl: + data_phenix +loop_ + _struct_sheet.id + _struct_sheet.type + _struct_sheet.number_strands + _struct_sheet.details + 1 ? 2 ? + 2 ? 2 ? + 3 ? 2 ? + 4 ? 2 ? + 5 ? 2 ? + +loop_ + _struct_sheet_order.sheet_id + _struct_sheet_order.range_id_1 + _struct_sheet_order.range_id_2 + _struct_sheet_order.offset + _struct_sheet_order.sense + 1 1 2 ? anti-parallel + 2 1 2 ? anti-parallel + 3 1 2 ? anti-parallel + 4 1 2 ? anti-parallel + 5 1 2 ? anti-parallel + +loop_ + _struct_sheet_range.sheet_id + _struct_sheet_range.id + _struct_sheet_range.beg_label_comp_id + _struct_sheet_range.beg_label_asym_id + _struct_sheet_range.beg_label_seq_id + _struct_sheet_range.pdbx_beg_PDB_ins_code + _struct_sheet_range.end_label_comp_id + _struct_sheet_range.end_label_asym_id + _struct_sheet_range.end_label_seq_id + _struct_sheet_range.pdbx_end_PDB_ins_code + 1 1 HIS AaXZLONG 32 ? LEU AaXZLONG 36 ? + 1 2 VAL AaXZLONG 17 ? LEU AaXZLONG 22 ? + 2 1 VAL AaXZLONG 17 ? LEU AaXZLONG 22 ? + 2 2 ALA AaXZLONG 52 ? VAL AaXZLONG 55 ? + 3 1 GLU AaXZLONG 40 ? GLN AaXZLONG 45 ? + 3 2 PHE AaXZLONG 7 ? ALA AaXZLONG 12 ? + 4 1 PHE AaXZLONG 7 ? ALA AaXZLONG 12 ? + 4 2 LYS AaXZLONG 58 ? THR AaXZLONG 63 ? + 5 1 LYS AaXZLONG 58 ? THR AaXZLONG 63 ? + 5 2 GLY AaXZLONG 66 ? GLU AaXZLONG 71 ? + +loop_ + _pdbx_struct_sheet_hbond.sheet_id + _pdbx_struct_sheet_hbond.range_id_1 + _pdbx_struct_sheet_hbond.range_id_2 + _pdbx_struct_sheet_hbond.range_1_label_atom_id + _pdbx_struct_sheet_hbond.range_1_label_comp_id + _pdbx_struct_sheet_hbond.range_1_label_asym_id + _pdbx_struct_sheet_hbond.range_1_label_seq_id + _pdbx_struct_sheet_hbond.range_1_PDB_ins_code + _pdbx_struct_sheet_hbond.range_2_label_atom_id + _pdbx_struct_sheet_hbond.range_2_label_comp_id + _pdbx_struct_sheet_hbond.range_2_label_asym_id + _pdbx_struct_sheet_hbond.range_2_label_seq_id + _pdbx_struct_sheet_hbond.range_2_PDB_ins_code + 1 1 2 O HIS AaXZLONG 32 ? N GLY AaXZLONG 21 ? + 2 1 2 O ILE AaXZLONG 20 ? N LYS AaXZLONG 54 ? + 3 1 2 O GLU AaXZLONG 40 ? N ALA AaXZLONG 12 ? + 4 1 2 O VAL AaXZLONG 9 ? N GLN AaXZLONG 62 ? + 5 1 2 O ALA AaXZLONG 59 ? N SER AaXZLONG 70 ? + + + +FINAL PDB selections: + ["chain 'AaXZLONG' and resid 32 through 36 ", "chain 'AaXZLONG' and resid 17 through 22 ", "chain 'AaXZLONG' and resid 52 through 55 ", "chain 'AaXZLONG' and resid 40 through 45 ", "chain 'AaXZLONG' and resid 7 through 12 ", "chain 'AaXZLONG' and resid 58 through 63 ", "chain 'AaXZLONG' and resid 66 through 71 "] + + + """ + if remove_blank(found_text)!=remove_blank(expected_text): + print("Expected: \n%s \nFound: \n%s" %(expected_text,found_text)) + raise AssertionError("FAILED") + + print("\nDone with tst_00") + print("OK") + + +def tst_01(): + print("Finding helices...", end=' ') + import iotbx.pdb + from cctbx.array_family import flex + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_two_helix_text)).construct_hierarchy() + fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False,out=null_out()) + + expected_text=""" +Model 1 N: 8 Start: 1 End: 8 +Class: Alpha helix N: 8 Start: 1 End: 8 Rise: 1.56 A Dot: 0.98 + +Model 2 N: 16 Start: 11 End: 26 +Class: Alpha helix N: 16 Start: 11 End: 26 Rise: 1.58 A Dot: 0.98 + +FINAL PDB RECORDS: +data_phenix +loop_ + _struct_conf.conf_type_id + _struct_conf.id + _struct_conf.pdbx_PDB_helix_id + _struct_conf.beg_label_comp_id + _struct_conf.beg_label_asym_id + _struct_conf.beg_label_seq_id + _struct_conf.pdbx_beg_PDB_ins_code + _struct_conf.end_label_comp_id + _struct_conf.end_label_asym_id + _struct_conf.end_label_seq_id + _struct_conf.pdbx_end_PDB_ins_code + _struct_conf.pdbx_PDB_helix_class + _struct_conf.details + _struct_conf.pdbx_PDB_helix_length + HELX_P 1 1 GLY AXZLONG 1 ? VAL AXZLONG 8 ? 1 ? 8 + HELX_P 2 2 THR AXZLONG 11 ? GLN AXZLONG 26 ? 1 ? 16 + +loop_ + _struct_conf_type.id + _struct_conf_type.criteria + _struct_conf_type.reference + HELX_P ? ? + + + + +FINAL PDB selections: +"(chain 'AXZLONG' and resid 1 through 8 ) or (chain 'AXZLONG' and resid 11 through 26 )" +""" + f=StringIO() + fss.show_summary(out=f,verbose=True) + found_text=f.getvalue() + #assert not test_utils.show_diff(found_text, expected_text) + if remove_blank(found_text)!=remove_blank(expected_text): + print("Expected: \n%s \nFound: \n%s" %(expected_text,found_text)) + raise AssertionError("FAILED") + print("\nDone with tst_01") + print("OK") + +def tst_02(): + print("Finding helices...", end=' ') + import iotbx.pdb + from cctbx.array_family import flex + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_tst_2_text)).construct_hierarchy() + fss=find_secondary_structure( + hierarchy=hierarchy,ss_by_chain=False,out=null_out()) + + expected_text=""" +Model 1 N: 8 Start: 1 End: 8 +Class: Alpha helix N: 8 Start: 1 End: 8 Rise: 1.56 A Dot: 0.98 + +Model 2 N: 16 Start: 11 End: 26 +Class: Alpha helix N: 16 Start: 11 End: 26 Rise: 1.58 A Dot: 0.98 + +FINAL PDB RECORDS: +data_phenix +loop_ + _struct_conf.conf_type_id + _struct_conf.id + _struct_conf.pdbx_PDB_helix_id + _struct_conf.beg_label_comp_id + _struct_conf.beg_label_asym_id + _struct_conf.beg_label_seq_id + _struct_conf.pdbx_beg_PDB_ins_code + _struct_conf.end_label_comp_id + _struct_conf.end_label_asym_id + _struct_conf.end_label_seq_id + _struct_conf.pdbx_end_PDB_ins_code + _struct_conf.pdbx_PDB_helix_class + _struct_conf.details + _struct_conf.pdbx_PDB_helix_length + HELX_P 1 1 GLY AXZLONG 1 ? VAL AXZLONG 8 ? 1 ? 8 + HELX_P 2 2 THR AXZLONG 11 ? GLN AXZLONG 26 ? 1 ? 16 + +loop_ + _struct_conf_type.id + _struct_conf_type.criteria + _struct_conf_type.reference + HELX_P ? ? + + + + +FINAL PDB selections: +"(chain 'AXZLONG' and resid 1 through 8 ) or (chain 'AXZLONG' and resid 11 through 26 )" +""" + f=StringIO() + fss.show_summary(out=f,verbose=True) + found_text=f.getvalue() + #assert not test_utils.show_diff(found_text, expected_text) + if remove_blank(found_text)!=remove_blank(expected_text): + print("Expected: \n%s \nFound: \n%s" %(expected_text,found_text)) + raise AssertionError("FAILED") + print("\nDone with tst_02") + print("OK") + +def tst_03(): + print("Finding alpha,3-10 and pi helices...", end=' ') + import iotbx.pdb + from cctbx.array_family import flex + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_helices_text)).construct_hierarchy() + fss=find_secondary_structure( + hierarchy=hierarchy,ss_by_chain=False,out=null_out()) + + expected_text=""" + +Model 1 N: 16 Start: 1 End: 16 +Class: Alpha helix N: 16 Start: 1 End: 16 Rise: 1.51 A Dot: 0.98 + +Model 2 N: 21 Start: 2 End: 22 +Class: Pi helix N: 21 Start: 2 End: 22 Rise: 0.96 A Dot: 0.98 + +Model 3 N: 21 Start: 2 End: 22 +Class: 3-10 helix N: 20 Start: 2 End: 21 Rise: 1.99 A Dot: 1.00 + +FINAL PDB RECORDS: +data_phenix +loop_ + _struct_conf.conf_type_id + _struct_conf.id + _struct_conf.pdbx_PDB_helix_id + _struct_conf.beg_label_comp_id + _struct_conf.beg_label_asym_id + _struct_conf.beg_label_seq_id + _struct_conf.pdbx_beg_PDB_ins_code + _struct_conf.end_label_comp_id + _struct_conf.end_label_asym_id + _struct_conf.end_label_seq_id + _struct_conf.pdbx_end_PDB_ins_code + _struct_conf.pdbx_PDB_helix_class + _struct_conf.details + _struct_conf.pdbx_PDB_helix_length + HELX_P 1 1 ALA AXZLONG 1 ? ALA AXZLONG 16 ? 1 ? 16 + HELX_P 1 1 ALA CXZLONG 2 ? ALA CXZLONG 21 ? 5 ? 20 + HELX_P 1 1 ALA BXZLONG 2 ? ALA BXZLONG 22 ? 3 ? 21 + +loop_ + _struct_conf_type.id + _struct_conf_type.criteria + _struct_conf_type.reference + HELX_P ? ? + + + + +FINAL PDB selections: +"(chain 'AXZLONG' and resid 1 through 16 ) or (chain 'CXZLONG' and resid 2 through 21 ) or (chain 'BXZLONG' and resid 2 through 22 )" + + +""" + f=StringIO() + fss.show_summary(out=f,verbose=True) + found_text=f.getvalue() + #assert not test_utils.show_diff(found_text, expected_text) + if remove_blank(found_text)!=remove_blank(expected_text): + print("Expected: \n%s \nFound: \n%s" %(expected_text,found_text)) + raise AssertionError("FAILED") + print("\nDone with tst_03") + print("OK") + +def tst_04(): + print("Finding sheets...", end=' ') + import iotbx.pdb + from cctbx.array_family import flex + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_sheets)).construct_hierarchy() + fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False,out=null_out()) + + expected_text=""" +Model 1 N: 70 Start: 3 End: 72 +Class: Beta strand N: 10 Start: 3 End: 12 Rise: 3.32 A Dot: 0.88 +Class: Beta strand N: 9 Start: 16 End: 24 Rise: 3.24 A Dot: 0.97 +Class: Beta strand N: 4 Start: 27 End: 30 Rise: 3.34 A Dot: 0.95 +Class: Beta strand N: 6 Start: 31 End: 36 Rise: 3.29 A Dot: 0.99 +Class: Beta strand N: 8 Start: 40 End: 47 Rise: 3.30 A Dot: 0.96 +Class: Beta strand N: 5 Start: 51 End: 55 Rise: 3.41 A Dot: 1.00 +Class: Beta strand N: 6 Start: 58 End: 63 Rise: 3.41 A Dot: 0.96 +Class: Beta strand N: 7 Start: 66 End: 72 Rise: 3.41 A Dot: 0.98 + +FINAL PDB RECORDS: +data_phenix +loop_ + _struct_sheet.id + _struct_sheet.type + _struct_sheet.number_strands + _struct_sheet.details + 1 ? 3 ? + 2 ? 4 ? + +loop_ + _struct_sheet_order.sheet_id + _struct_sheet_order.range_id_1 + _struct_sheet_order.range_id_2 + _struct_sheet_order.offset + _struct_sheet_order.sense + 1 1 2 ? anti-parallel + 1 2 3 ? anti-parallel + 2 1 2 ? anti-parallel + 2 2 3 ? anti-parallel + 2 3 4 ? anti-parallel + +loop_ + _struct_sheet_range.sheet_id + _struct_sheet_range.id + _struct_sheet_range.beg_label_comp_id + _struct_sheet_range.beg_label_asym_id + _struct_sheet_range.beg_label_seq_id + _struct_sheet_range.pdbx_beg_PDB_ins_code + _struct_sheet_range.end_label_comp_id + _struct_sheet_range.end_label_asym_id + _struct_sheet_range.end_label_seq_id + _struct_sheet_range.pdbx_end_PDB_ins_code + 1 1 HIS AaXZLONG 32 ? LEU AaXZLONG 36 ? + 1 2 VAL AaXZLONG 17 ? LEU AaXZLONG 22 ? + 1 3 ALA AaXZLONG 52 ? VAL AaXZLONG 55 ? + 2 1 GLU AaXZLONG 40 ? GLN AaXZLONG 45 ? + 2 2 PHE AaXZLONG 7 ? ALA AaXZLONG 12 ? + 2 3 LYS AaXZLONG 58 ? THR AaXZLONG 63 ? + 2 4 GLY AaXZLONG 66 ? GLU AaXZLONG 71 ? + +loop_ + _pdbx_struct_sheet_hbond.sheet_id + _pdbx_struct_sheet_hbond.range_id_1 + _pdbx_struct_sheet_hbond.range_id_2 + _pdbx_struct_sheet_hbond.range_1_label_atom_id + _pdbx_struct_sheet_hbond.range_1_label_comp_id + _pdbx_struct_sheet_hbond.range_1_label_asym_id + _pdbx_struct_sheet_hbond.range_1_label_seq_id + _pdbx_struct_sheet_hbond.range_1_PDB_ins_code + _pdbx_struct_sheet_hbond.range_2_label_atom_id + _pdbx_struct_sheet_hbond.range_2_label_comp_id + _pdbx_struct_sheet_hbond.range_2_label_asym_id + _pdbx_struct_sheet_hbond.range_2_label_seq_id + _pdbx_struct_sheet_hbond.range_2_PDB_ins_code + 1 1 2 O HIS AaXZLONG 32 ? N GLY AaXZLONG 21 ? + 1 2 3 O ILE AaXZLONG 20 ? N LYS AaXZLONG 54 ? + 2 1 2 O GLU AaXZLONG 40 ? N ALA AaXZLONG 12 ? + 2 2 3 O VAL AaXZLONG 9 ? N GLN AaXZLONG 62 ? + 2 3 4 O ALA AaXZLONG 59 ? N SER AaXZLONG 70 ? + + + + +FINAL PDB selections: +"(chain 'AaXZLONG' and resid 32 through 36 ) or (chain 'AaXZLONG' and resid 17 through 22 ) or (chain 'AaXZLONG' and resid 52 through 55 ) or (chain 'AaXZLONG' and resid 40 through 45 ) or (chain 'AaXZLONG' and resid 7 through 12 ) or (chain 'AaXZLONG' and resid 58 through 63 ) or (chain 'AaXZLONG' and resid 66 through 71 )" + +""" + f=StringIO() + fss.show_summary(out=f,verbose=True) + found_text=f.getvalue() + #assert not test_utils.show_diff(found_text, expected_text) + if remove_blank(found_text)!=remove_blank(expected_text): + print("Expected: \n%s \nFound: \n%s" %(expected_text,found_text)) + raise AssertionError("FAILED") + print("\nDone with tst_04") + print("OK") + +def tst_05(): + print("Finding sheets with separate chains...", end=' ') + import iotbx.pdb + from cctbx.array_family import flex + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_two_chain_text)).construct_hierarchy() + fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False,out=null_out()) + + expected_text=""" +Model 1 N: 8 Start: 50 End: 57 +Class: Beta strand N: 8 Start: 50 End: 57 Rise: 3.21 A Dot: 0.97 + +Model 2 N: 5 Start: 278 End: 282 +Class: Beta strand N: 5 Start: 278 End: 282 Rise: 3.16 A Dot: 0.98 + +FINAL PDB RECORDS: +data_phenix +loop_ + _struct_sheet.id + _struct_sheet.type + _struct_sheet.number_strands + _struct_sheet.details + 1 ? 2 ? + +loop_ + _struct_sheet_order.sheet_id + _struct_sheet_order.range_id_1 + _struct_sheet_order.range_id_2 + _struct_sheet_order.offset + _struct_sheet_order.sense + 1 1 2 ? parallel + +loop_ + _struct_sheet_range.sheet_id + _struct_sheet_range.id + _struct_sheet_range.beg_label_comp_id + _struct_sheet_range.beg_label_asym_id + _struct_sheet_range.beg_label_seq_id + _struct_sheet_range.pdbx_beg_PDB_ins_code + _struct_sheet_range.end_label_comp_id + _struct_sheet_range.end_label_asym_id + _struct_sheet_range.end_label_seq_id + _struct_sheet_range.pdbx_end_PDB_ins_code + 1 1 TYR AXZLONG 50 ? TYR AXZLONG 54 ? + 1 2 LEU BXZLONG 278 ? ALA BXZLONG 282 ? + +loop_ + _pdbx_struct_sheet_hbond.sheet_id + _pdbx_struct_sheet_hbond.range_id_1 + _pdbx_struct_sheet_hbond.range_id_2 + _pdbx_struct_sheet_hbond.range_1_label_atom_id + _pdbx_struct_sheet_hbond.range_1_label_comp_id + _pdbx_struct_sheet_hbond.range_1_label_asym_id + _pdbx_struct_sheet_hbond.range_1_label_seq_id + _pdbx_struct_sheet_hbond.range_1_PDB_ins_code + _pdbx_struct_sheet_hbond.range_2_label_atom_id + _pdbx_struct_sheet_hbond.range_2_label_comp_id + _pdbx_struct_sheet_hbond.range_2_label_asym_id + _pdbx_struct_sheet_hbond.range_2_label_seq_id + _pdbx_struct_sheet_hbond.range_2_PDB_ins_code + 1 1 2 O ILE AXZLONG 51 ? N ILE BXZLONG 280 ? + + + + +FINAL PDB selections: +"(chain 'AXZLONG' and resid 50 through 54 ) or (chain 'BXZLONG' and resid 278 through 282 )" + + +""" + f=StringIO() + fss.show_summary(out=f,verbose=True) + found_text=f.getvalue() + if remove_blank(found_text)!=remove_blank(expected_text): + print("Expected: \n%s \nFound: \n%s" %(expected_text,found_text)) + raise AssertionError("FAILED") + print("\nDone with tst_05") + print("OK") + +def tst_06(): + print("Finding sheets with unusual residues...", end=' ') + import iotbx.pdb + from cctbx.array_family import flex + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_unusual_residues)).construct_hierarchy() + fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False,out=null_out()) + + expected_text=""" + +Model 1 N: 21 Start: 2 End: 22 +Class: Alpha helix N: 10 Start: 3 End: 12 Rise: 2.00 A Dot: 0.98 +Class: Alpha helix N: 10 Start: 13 End: 22 Rise: 1.96 A Dot: 0.97 + +FINAL PDB RECORDS: +data_phenix +loop_ + _struct_conf.conf_type_id + _struct_conf.id + _struct_conf.pdbx_PDB_helix_id + _struct_conf.beg_label_comp_id + _struct_conf.beg_label_asym_id + _struct_conf.beg_label_seq_id + _struct_conf.pdbx_beg_PDB_ins_code + _struct_conf.end_label_comp_id + _struct_conf.end_label_asym_id + _struct_conf.end_label_seq_id + _struct_conf.pdbx_end_PDB_ins_code + _struct_conf.pdbx_PDB_helix_class + _struct_conf.details + _struct_conf.pdbx_PDB_helix_length + HELX_P 1 1 23F AXZLONG 3 ? GLY AXZLONG 12 ? 1 ? 10 + HELX_P 2 2 GLY AXZLONG 13 ? ALA AXZLONG 22 ? 1 ? 10 + +loop_ + _struct_conf_type.id + _struct_conf_type.criteria + _struct_conf_type.reference + HELX_P ? ? + + + + +FINAL PDB selections: +"(chain 'AXZLONG' and resid 3 through 12 ) or (chain 'AXZLONG' and resid 13 through 22 )" + + +""" + f=StringIO() + fss.show_summary(out=f,verbose=True) + found_text=f.getvalue() + if remove_blank(found_text)!=remove_blank(expected_text): + print("Expected: \n%s \nFound: \n%s" %(expected_text,found_text)) + raise AssertionError("FAILED") + print("\nDone with tst_06") + print("OK") + +def tst_07(): + print("Finding sheets with alt confs where there is no A for first res...") + import iotbx.pdb + from cctbx.array_family import flex + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_alt_confs_no_a)).construct_hierarchy() + fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False,verbose=True,out=null_out()) + + expected_text=""" +Model 1 N: 5 Start: 3 End: 7 +Class: Beta strand N: 4 Start: 4 End: 7 Rise: 3.27 A Dot: 0.91""" + f=StringIO() + fss.show_summary(out=f,verbose=True) + found_text=f.getvalue() + if remove_blank(found_text)!=remove_blank(expected_text): + print("Expected: \n%s \nFound: \n%s" %(expected_text,found_text)) + raise AssertionError("FAILED") + print("\nDone with tst_07") + print("OK") + +def tst_08(): + print("Checking similar annotations and overlapping annotations") + + import iotbx.pdb + from cctbx.array_family import flex + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_one_helix_text)).construct_hierarchy() + + ann_one_helix_beg=get_annotation(pdb_str_one_helix_beginning_text) + ann_one_helix_middle=get_annotation(pdb_str_one_helix_middle_text) + ann_one_helix_end=get_annotation(pdb_str_one_helix_end_text) + ann_one_helix=get_annotation(pdb_str_one_helix_text) + for h1 in ann_one_helix_beg.helices: + for h2 in ann_one_helix_beg.helices: + print("Should be same:",h1.is_similar_to(other=h2,hierarchy=hierarchy)) + assert h1.is_similar_to(other=h2,hierarchy=hierarchy) + for maximum_length_difference in [4,8]: + for minimum_overlap in [6,10]: + for h1 in ann_one_helix_beg.helices: + for h2 in ann_one_helix.helices: + value=h1.is_similar_to(other=h2,hierarchy=hierarchy, + maximum_length_difference=maximum_length_difference, + minimum_overlap=minimum_overlap) + print("Comparison:",value) + assert (value and maximum_length_difference==8 and + minimum_overlap==6) or not value + + assert ann_one_helix_beg.overlaps_with(other=ann_one_helix, + hierarchy=hierarchy) + assert not ann_one_helix_beg.overlaps_with(other=ann_one_helix_end, + hierarchy=hierarchy) + + # Now strands and sheets + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_std_text)).construct_hierarchy() + fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False,out=null_out()) + import iotbx.pdb.secondary_structure as ioss + + + s1_records=""" +SHEET 1 1 3 HISAa 32 LEUAa 36 0 +SHEET 2 1 3 VALAa 17 LEUAa 22 -1 N GLYAa 21 O HISAa 32 +SHEET 3 1 3 ALAAa 52 VALAa 55 -1 N LYSAa 54 O ILEAa 20 +""" + s1_not_overlap_records=""" +SHEET 1 1 3 HISAa 32 LEUAa 36 0 +SHEET 1 2 4 GLUAa 40 GLNAa 45 0 +SHEET 3 2 4 LYSAa 58 THRAa 63 -1 +""" + + s1_similar_records=""" +SHEET 1 1 3 HISAa 32 LEUAa 36 0 +SHEET 2 1 3 VALAa 18 LEUAa 22 -1 N VALAa 19 O GLUAa 34 +SHEET 3 1 3 ALAAa 50 VALAa 57 -1 N LYSAa 54 O ILEAa 20 +""" + + s1_diff_records=""" +SHEET 1 2 4 GLUAa 40 GLNAa 45 0 +SHEET 2 2 4 PHEAa 7 ALAAa 12 -1 N ALAAa 12 O GLUAa 40 +SHEET 3 2 4 LYSAa 58 THRAa 63 -1 N GLNAa 62 O VALAa 9 +""" + s1_reverse_diff_records=""" +SHEET 1 2 4 GLUAa 40 GLNAa 45 0 +SHEET 2 2 4 PHEAa 7 ALAAa 12 1 N ALAAa 12 O GLUAa 40 +SHEET 3 2 4 LYSAa 58 THRAa 63 -1 N GLNAa 62 O VALAa 9 +""" + + s1_similar_reg_records=""" +SHEET 1 1 3 HISAa 32 LEUAa 36 0 +SHEET 2 1 3 VALAa 17 LEUAa 22 -1 N ILEAa 20 O SERAa 33 +SHEET 3 1 3 ALAAa 52 VALAa 55 -1 N LYSAa 54 O ILEAa 20 +""" + + s1_similar_backwards=""" +SHEET 2 1 3 VALAa 18 LEUAa 22 0 +SHEET 3 1 3 ALAAa 50 VALAa 57 -1 O ILEAa 20 N LYSAa 54 +SHEET 1 1 3 HISAa 32 LEUAa 36 -1 O SERAa 33 N ILEAa 20 +""" + + s1_similar_backwards_2=""" +SHEET 2 1 3 VALAa 18 LEUAa 22 0 +SHEET 3 1 3 ALAAa 50 VALAa 57 -1 O ILEAa 20 N LYSAa 54 +SHEET 1 1 3 HISAa 32 LEUAa 36 -1 O SERAa 33 N ILEAa 20 +""" + + s1_full=ioss.annotation.from_records(records=flex.split_lines(s1_records)) + s1_not_overlap=ioss.annotation.from_records(records=flex.split_lines(s1_not_overlap_records)) + s1_similar=ioss.annotation.from_records(records=flex.split_lines(s1_similar_records)) + s1_diff=ioss.annotation.from_records(records=flex.split_lines(s1_diff_records)) + s1_reverse_diff=ioss.annotation.from_records(records=flex.split_lines(s1_reverse_diff_records)) + + # Convert all these annotations to ones with .replace(chain_addition,"") + text_list = ['Aa'] + new_text_list = [] + for t in text_list: + new_text_list.append("%s%s" %(t,chain_addition)) + s1_full,s1_not_overlap,s1_similar,s1_diff,s1_reverse_diff= edit_cif_info_list( + [s1_full,s1_not_overlap,s1_similar,s1_diff,s1_reverse_diff], + chain_addition,text_list = text_list, new_text_list = new_text_list) + + print("\nChecking overlap:") + assert s1_full.overlaps_with(other=s1_similar,hierarchy=hierarchy) + assert not s1_full.overlaps_with(other=s1_diff,hierarchy=hierarchy) + assert not s1_full.overlaps_with(other=s1_not_overlap,hierarchy=hierarchy) + + print("tst_08 ok so far...") + + print("\nChecking similar strands:", end=' ') + f=StringIO() + for s1 in s1_full.sheets: + for str1 in s1.strands: + for s2 in s1_similar.sheets: + for str2 in s2.strands: + value=str1.is_similar_to(other=str2,hierarchy=hierarchy, + maximum_length_difference=4) + print(str1.as_atom_selections(),str2.as_atom_selections(),value) + print(str1.as_atom_selections(),str2.as_atom_selections(),value, file=f) + assert f.getvalue().replace(chain_addition,"")=="""chain 'Aa' and resid 32 through 36 chain 'Aa' and resid 32 through 36 True +chain 'Aa' and resid 32 through 36 chain 'Aa' and resid 18 through 22 False +chain 'Aa' and resid 32 through 36 chain 'Aa' and resid 50 through 57 False +chain 'Aa' and resid 17 through 22 chain 'Aa' and resid 32 through 36 False +chain 'Aa' and resid 17 through 22 chain 'Aa' and resid 18 through 22 True +chain 'Aa' and resid 17 through 22 chain 'Aa' and resid 50 through 57 False +chain 'Aa' and resid 52 through 55 chain 'Aa' and resid 32 through 36 False +chain 'Aa' and resid 52 through 55 chain 'Aa' and resid 18 through 22 False +chain 'Aa' and resid 52 through 55 chain 'Aa' and resid 50 through 57 True +""" + + print("\nChecking different strands:", end=' ') + for s1 in s1_full.sheets: + for str1 in s1.strands: + for s2 in s1_diff.sheets: + for str2 in s2.strands: + print(str1.as_atom_selections(),str2.as_atom_selections(),\ + str1.is_similar_to(other=str2,hierarchy=hierarchy, + maximum_length_difference=4)) + + print("\nChecking similar sheets:", end=' ') + for s1 in s1_full.sheets: + for s2 in s1_similar.sheets: + value=s1.is_similar_to(other=s2,hierarchy=hierarchy, + maximum_length_difference=4) + print(value) + assert value + + print("\nChecking non-similar sheets:", end=' ') + for s1 in s1_full.sheets: + for s2 in s1_diff.sheets: + value=s1.is_similar_to(other=s2,hierarchy=hierarchy, + maximum_length_difference=4) + print(value) + assert not value + + print("\nChecking similar overall annotations:", end=' ') + value=s1_full.is_similar_to(other=s1_similar,hierarchy=hierarchy, + maximum_length_difference=4) + print(value) + assert value + + print("\nChecking different overall annotations:", end=' ') + value=s1_full.is_similar_to(other=s1_diff,hierarchy=hierarchy, + maximum_length_difference=4) + print(value) + assert not value + + print("\nChecking different overall directions:", end=' ') + value=s1_full.is_similar_to(other=s1_reverse_diff,hierarchy=hierarchy, + maximum_length_difference=4) + print(value) + assert not value + + + # parallel strands + print("\n\nChecking parallel strands...") + + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_two_chain_text)).construct_hierarchy() + fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False,out=null_out()) + records=fss.annotation.as_pdb_or_mmcif_str() + import iotbx.pdb.secondary_structure as ioss + + + s2_records=""" +FINAL PDB RECORDS: +SHEET 1 1 2 TYR A 50 TYR A 54 0 +SHEET 2 1 2 LEU B 278 ALA B 282 1 N ILE B 280 O ILE A 51 +""" + + s2_similar_records=""" +FINAL PDB RECORDS: +SHEET 1 1 2 TYR A 50 TYR A 54 0 +SHEET 2 1 2 LEU B 278 ALA B 282 1 N ALA B 282 O THR A 53 +""" + + s2_similar_records_2=""" +FINAL PDB RECORDS: +SHEET 1 1 2 TYR A 50 TYR A 54 0 +SHEET 2 1 2 LEU B 278 ALA B 282 1 O LEU B 278 N ILE A 51 +""" + + s2_different_records=""" +FINAL PDB RECORDS: +SHEET 1 1 2 TYR A 50 TYR A 54 0 +SHEET 2 1 2 LEU B 278 ALA B 282 1 O ILE B 280 N ILE A 51 +""" + + s2_full=ioss.annotation.from_records(records=flex.split_lines(s2_records)) + s2_similar=ioss.annotation.from_records(records=flex.split_lines(s2_similar_records)) + s2_similar_2=ioss.annotation.from_records(records=flex.split_lines(s2_similar_records_2)) + s2_different=ioss.annotation.from_records(records=flex.split_lines(s2_different_records)) + + # Convert all these annotations to ones with .replace(chain_addition,"") + text_list = [' A ',' B '] + new_text_list = [] + for t in text_list: + new_text_list.append(" %s%s " %(t.strip(),chain_addition)) + s2_full,s2_similar,s2_similar_2,s2_different= edit_cif_info_list( + [s2_full,s2_similar,s2_similar_2,s2_different], + chain_addition,text_list = text_list, new_text_list = new_text_list) + + print("\nChecking similar overall annotations (offset by 2):", end=' ') + value=s2_full.is_similar_to(other=s2_similar,hierarchy=hierarchy, + maximum_length_difference=4) + print(value) + assert value + + print("\nChecking similar overall annotations (switch N/O):", end=' ') + value=s2_full.is_similar_to(other=s2_similar_2,hierarchy=hierarchy, + maximum_length_difference=4) + print(value) + assert value + + print("\nChecking different overall annotations (offset by 1):", end=' ') + value=s2_full.is_similar_to(other=s2_different,hierarchy=hierarchy, + maximum_length_difference=4) + print(value) + assert not value + + print("\nDone with tst_08") + print("\nOK") + + + +def tst_09(): + print("Comparing sheets and helices...", end=' ') + + helix_1=""" +HELIX 1 1 GLY A 1 VAL A 8 1 8 +""" + helix_2=""" +HELIX 2 2 THR A 11 GLN A 26 1 16 +""" + sheet_1=""" +SHEET 1 1 3 HISAa 32 LEUAa 36 0 +SHEET 2 1 3 VALAa 17 LEUAa 22 -1 N GLYAa 21 O HISAa 32 +SHEET 3 1 3 ALAAa 52 VALAa 55 1 N LYSAa 54 O ILEAa 20 +""" + sheet_2=""" +SHEET 1 2 4 GLUAa 40 GLNAa 45 0 +SHEET 2 2 4 PHEAa 7 ALAAa 12 -1 N ALAAa 12 O GLUAa 40 +SHEET 3 2 4 LYSAa 58 THRAa 63 1 N GLNAa 62 O VALAa 9 +SHEET 4 2 4 GLYAa 66 GLUAa 71 -1 N SERAa 70 O ALAAa 59 +""" + import iotbx.pdb.secondary_structure as ioss + from cctbx.array_family import flex + + h1=ioss.annotation.from_records(records=flex.split_lines(helix_1)) + h2=ioss.annotation.from_records(records=flex.split_lines(helix_2)) + s1=ioss.annotation.from_records(records=flex.split_lines(sheet_1)) + s2=ioss.annotation.from_records(records=flex.split_lines(sheet_2)) + assert h1.is_same_as(h1) + assert h2.is_same_as(h2) + assert not h1.is_same_as(h2) + assert not h1.is_same_as(s1) + assert not s1.is_same_as(s2) + assert s1.is_same_as(s1) + for a in s1.sheets: + for b in s1.sheets: + assert (a==b and a.is_same_as(b)) or (not a.is_same_as(b)) + for sa in a.strands: + for sb in b.strands: + assert (sa==sb and sa.is_same_as(sb)) or (not sa.is_same_as(sb)) + print("\nDone with tst_09") + print("OK") + + +def get_annotation(text): + import iotbx.pdb + from cctbx.array_family import flex + import iotbx.pdb.secondary_structure as ioss + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(text)).construct_hierarchy() + fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False,out=null_out()) + cif_block=fss.annotation.as_cif_block() + return ioss.annotation.from_cif_block(cif_block) + +def tst_10(): + + import iotbx.pdb + from cctbx.array_family import flex + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_two_chain_one_full_helix_text) + ).construct_hierarchy() + + text_helix_1=""" +HELIX 1 1 ALA A 15 LYS A 21 1 7 +""" + text_helix_2=""" +HELIX 1 1 LEU A 16 LYS A 21 1 6 +""" + text_sheet_1=""" +SHEET 1 1 2 ILE A 51 TYR A 54 0 +SHEET 2 1 2 THR B 279 ALA B 282 1 N ILE B 280 O ILE A 51 +""" + text_sheet_2=""" +SHEET 1 1 2 TYR A 50 TYR A 54 0 +SHEET 2 1 2 LEU B 278 ALA B 282 1 N ILE B 280 O ILE A 51 +""" + import iotbx.pdb.secondary_structure as ioss + from cctbx.array_family import flex + h1=ioss.annotation.from_records(records=flex.split_lines(text_helix_1)) + h2=ioss.annotation.from_records(records=flex.split_lines(text_helix_2)) + s1=ioss.annotation.from_records(records=flex.split_lines(text_sheet_1)) + s2=ioss.annotation.from_records(records=flex.split_lines(text_sheet_2)) + + hs1=ioss.annotation.from_records(records=flex.split_lines(text_helix_1+text_sheet_1)) + hs2=ioss.annotation.from_records(records=flex.split_lines(text_helix_2+text_sheet_2)) + + # Convert all these annotations to ones with .replace(chain_addition,"") + text_list = [' A ',' B '] + new_text_list = [] + for t in text_list: + new_text_list.append(" %s%s " %(t.strip(),chain_addition)) + h1, h2, s1, s2, hs1, hs2 = edit_cif_info_list([h1, h2, s1, s2, hs1, hs2], + chain_addition,text_list = text_list, new_text_list = new_text_list) + + + print("\nCombining annotations") + + ann_all=get_annotation(pdb_str_one_full_helix_text+pdb_str_two_chain_text) + + print("\nCombining annotations from two parts") + ann_one_full_helix=get_annotation(pdb_str_one_full_helix_text) + ann_two_chain=get_annotation(pdb_str_two_chain_text) + + ann_combined=ann_one_full_helix.combine_annotations(other=ann_two_chain, + hierarchy=hierarchy) + + print("\nCombining annotations from overlapping helix annotations") + ann_combined=h1.combine_annotations(other=h2,hierarchy=hierarchy) + + print("\nCombining annotations from overlapping strand annotations") + ann_combined=s1.combine_annotations(other=s2,hierarchy=hierarchy, + minimum_overlap=3,out=sys.stdout) + + print("\nCombining annotations from overlapping strand and helix annotations") + ann_combined=hs1.combine_annotations(other=hs2,hierarchy=hierarchy, + minimum_overlap=3,out=sys.stdout) + + + print("OK") + +def tst_11(): + + print("\nCounting H-bonds") + + import iotbx.pdb + import iotbx.pdb.secondary_structure as ioss + from cctbx.array_family import flex + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_two_chain_text)).construct_hierarchy() + fss=find_secondary_structure( + hierarchy=hierarchy,ss_by_chain=False,out=null_out()) + ann=fss.get_annotation() + + text_list = [' A ',' B '] + new_text_list = [] + for t in text_list: + new_text_list.append(" %s%s " %(t.strip(),chain_addition)) + [ann] = edit_cif_info_list([ann], + chain_addition,text_list = text_list, new_text_list = new_text_list) + + print("Good H-bonds: %d Poor H-Bonds: %d" %( + fss.number_of_good_h_bonds, + fss.number_of_poor_h_bonds,)) + assert fss.number_of_good_h_bonds==4 and fss.number_of_poor_h_bonds==0 + + print("\nCounting H-bonds using ioss.annotation:") + + number_of_good_h_bonds,number_of_poor_h_bonds=ann.count_h_bonds( + hierarchy=hierarchy) + print("Good H-bonds: %d Poor H-Bonds: %d" %( + fss.number_of_good_h_bonds, + fss.number_of_poor_h_bonds,)) + assert fss.number_of_good_h_bonds==4 and fss.number_of_poor_h_bonds==0 + + print("\nCounting residues in secondary structure:", end=' ') + print(ann.count_residues(hierarchy=hierarchy)) + assert ann.count_residues(hierarchy=hierarchy)==10 + + print("\nCounting H-bonds in helix:") + + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_one_full_helix_text)).construct_hierarchy() + fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False,out=null_out()) + ann=fss.get_annotation() + + print("\nH-bonds with cutoff=3.5 (default):\n") + number_of_good_h_bonds,number_of_poor_h_bonds=ann.count_h_bonds( + hierarchy=hierarchy) + print("Good H-bonds: %d Poor H-Bonds: %d" %( + number_of_good_h_bonds, + number_of_poor_h_bonds,)) + assert number_of_good_h_bonds==3 and number_of_poor_h_bonds==0 + + print("\nH-bonds with cutoff=3.0:\n") + number_of_good_h_bonds,number_of_poor_h_bonds=ann.count_h_bonds( + hierarchy=hierarchy,max_h_bond_length=3.0) + print("Good H-bonds: %d Poor H-Bonds: %d" %( + number_of_good_h_bonds, + number_of_poor_h_bonds,)) + assert number_of_good_h_bonds==1 and number_of_poor_h_bonds==2 + + print("\nCount number of residues in secondary structure:", end=' ') + print(ann.count_residues(hierarchy=hierarchy)) + assert ann.count_residues(hierarchy=hierarchy) ==7 + + print("\nH-bonds in mixed helix/strand") + + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_two_chain_one_full_helix_text) + ).construct_hierarchy() + fss=find_secondary_structure( + hierarchy=hierarchy,ss_by_chain=False,out=null_out()) + ann=fss.get_annotation() + + print("\nH-bonds with cutoff=3.0 :\n") + number_of_good_h_bonds,number_of_poor_h_bonds=ann.count_h_bonds( + hierarchy=hierarchy,max_h_bond_length=3.0) + print("Good H-bonds: %d Poor H-Bonds: %d" %( + number_of_good_h_bonds, + number_of_poor_h_bonds,)) + assert number_of_good_h_bonds==5 and number_of_poor_h_bonds==2, (number_of_good_h_bonds,number_of_poor_h_bonds) + + print("\nCount number of residues in secondary structure:", end=' ') + print(ann.count_residues(hierarchy=hierarchy)) + assert ann.count_residues(hierarchy=hierarchy) ==17 + print(ann.as_mmcif_str()) + + print("\nMake sure force and original ss are equivalent") + force_fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False, + user_annotation_text=ss_text, + force_secondary_structure_input=True, + combine_annotations=False, + out=null_out()) + number_of_good_h_bonds,number_of_poor_h_bonds=\ + force_fss.get_annotation().count_h_bonds( + hierarchy=hierarchy,max_h_bond_length=3.0) + print("Good H-bonds: %d Poor H-Bonds: %d" %( + number_of_good_h_bonds, + number_of_poor_h_bonds,)) + assert number_of_good_h_bonds==5 and number_of_poor_h_bonds==2 + + print("\nInput annotation:") + print("\nOutput annotation:") + print("\nIs same: ",fss.get_annotation().is_similar_to( + other=force_fss.get_annotation(),hierarchy=hierarchy)) + + print("\nCorrect bad H-bond register in input") + fix_fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False, + user_annotation_text=bad_two_chain_helix_ss, + force_secondary_structure_input=False, + combine_annotations=False, + search_secondary_structure=False,out=null_out()) + fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False, + combine_annotations=False, + out=null_out()) + print("\nInput:") + print("\nFixed:") + print("\nGood:") + print("Is same: ", fix_fss.get_annotation().is_similar_to( + hierarchy=hierarchy,other=fss.get_annotation())) + assert fix_fss.get_annotation().is_similar_to( + hierarchy=hierarchy,other=fss.get_annotation()) + + print("\nForce bad H-bond register in input") + + pdb_inp = get_pdb_input(bad_two_chain_helix_ss_correct_resname) + bad_anno = pdb_inp.extract_secondary_structure() + + no_fix_fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False, + user_annotation_text=bad_anno.as_pdb_or_mmcif_str(), + force_secondary_structure_input=True, + combine_annotations=False, + search_secondary_structure=False,out=null_out()) + print("\nInput:") + print("\nNot fixed:") + print("\nGood:") + print("Is same as unfixed: ", no_fix_fss.get_annotation().is_similar_to( + hierarchy=hierarchy,other=bad_anno)) + assert no_fix_fss.get_annotation().is_similar_to( + hierarchy=hierarchy,other=bad_anno) + + print("\nNegative residue numbers...") + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_negative_residues) + ).construct_hierarchy() + + fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False, + combine_annotations=False,args = ['remove_missing_atom_annotation=True'], + out=null_out()) + + pdb_inp = get_pdb_input(ss_negative_text) + anno = pdb_inp.extract_secondary_structure() + + fss_expected=find_secondary_structure( + hierarchy=hierarchy,ss_by_chain=False, + user_annotation_text=anno.as_pdb_or_mmcif_str(), + force_secondary_structure_input=True, + combine_annotations=False, + search_secondary_structure=False,out=null_out()) + assert fss.get_annotation().is_same_as(fss_expected.get_annotation()) + + print("\nHybrid-36 residue numbers...") + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_hybrid_residues) + ).construct_hierarchy() + fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False, + combine_annotations=False, + out=null_out()) + fss_expected=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False, + user_annotation_text=ss_hybrid_text, + force_secondary_structure_input=True, + combine_annotations=False, + search_secondary_structure=False,out=null_out()) + assert fss.get_annotation().is_same_as(fss_expected.get_annotation()) + + + print("\nNow for antiparallel:Make sure force and original ss are equivalent") + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_antiparallel_text) + ).construct_hierarchy() + fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False, + combine_annotations=False, + out=null_out()) + fss_expected=find_secondary_structure( + hierarchy=hierarchy,ss_by_chain=False, + user_annotation_text=ss_antiparallel_text, + force_secondary_structure_input=True, + combine_annotations=False, + search_secondary_structure=False,out=null_out()) + + number_of_good_h_bonds,number_of_poor_h_bonds=\ + fss_expected.get_annotation().count_h_bonds( + hierarchy=hierarchy,max_h_bond_length=3.0) + print("Good H-bonds: %d Poor H-Bonds: %d" %( + number_of_good_h_bonds, + number_of_poor_h_bonds,)) + assert number_of_good_h_bonds==3 and number_of_poor_h_bonds==1 + + print("\nInput annotation:") + print("\nOutput annotation:") + print("\nIs same: ",fss.get_annotation().is_similar_to( + other=force_fss.get_annotation(),hierarchy=hierarchy)) + + print("\nRemove annotation with too few H-bonds") + force_fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False, + user_annotation_text=ss_antiparallel_text, + force_secondary_structure_input=True, + combine_annotations=False, + require_h_bonds=True, # has no effect as force=true + minimum_h_bonds=4,out=null_out()) + number_of_good_h_bonds,number_of_poor_h_bonds=\ + force_fss.get_annotation().count_h_bonds( + hierarchy=hierarchy) + print("Good H-bonds: %d Poor H-Bonds: %d" %( + number_of_good_h_bonds, + number_of_poor_h_bonds,)) + assert number_of_good_h_bonds==4 and number_of_poor_h_bonds==0 + + force_fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False, + user_annotation_text=ss_antiparallel_text, + combine_annotations=False, + require_h_bonds=True, + minimum_h_bonds=5,out=null_out()) + number_of_good_h_bonds,number_of_poor_h_bonds=\ + force_fss.get_annotation().count_h_bonds( + hierarchy=hierarchy) + print("Good H-bonds: %d Poor H-Bonds: %d" %( + number_of_good_h_bonds, + number_of_poor_h_bonds,)) + assert number_of_good_h_bonds==0 and number_of_poor_h_bonds==0 + + print("\nNow remove annotation with too many poor H-bonds") + force_fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False, + user_annotation_text=ss_antiparallel_text, + combine_annotations=False, + require_h_bonds=True, # has no effect as force=true + max_h_bond_length=2.0,maximum_poor_h_bonds=0,out=null_out()) + number_of_good_h_bonds,number_of_poor_h_bonds=\ + force_fss.get_annotation().count_h_bonds( + hierarchy=hierarchy) + print("Good H-bonds: %d Poor H-Bonds: %d" %( + number_of_good_h_bonds, + number_of_poor_h_bonds,)) + assert number_of_good_h_bonds==0 and number_of_poor_h_bonds==0 + + + +def tst_12(): + pdb_text=""" +ATOM 3265 N LYS A 11 -14.874 -4.165 7.826 1.00 14.62 N +ATOM 3266 CA LYS A 11 -16.168 -3.852 7.241 1.00 15.85 C +ATOM 3267 C LYS A 11 -16.310 -4.478 5.853 1.00 16.45 C +ATOM 3268 O LYS A 11 -17.075 -5.419 5.680 1.00 17.01 O +ATOM 3269 CB LYS A 11 -16.375 -2.333 7.183 1.00 15.92 C +ATOM 3279 N ALA A 12 -15.570 -3.971 4.870 1.00 16.88 N +ATOM 3280 CA ALA A 12 -15.727 -4.395 3.487 1.00 17.42 C +ATOM 3281 C ALA A 12 -14.354 -4.610 2.875 1.00 17.46 C +ATOM 3282 O ALA A 12 -13.333 -4.252 3.459 1.00 16.02 O +ATOM 3283 CB ALA A 12 -16.525 -3.371 2.681 1.00 18.05 C +ATOM 3286 N VAL A 13 -14.338 -5.186 1.671 1.00 16.89 N +ATOM 3287 CA VAL A 13 -13.093 -5.691 1.103 1.00 17.82 C +ATOM 3288 C VAL A 13 -12.694 -4.871 -0.112 1.00 17.45 C +ATOM 3289 O VAL A 13 -13.105 -5.157 -1.241 1.00 17.89 O +ATOM 3290 CB VAL A 13 -13.228 -7.182 0.746 1.00 17.97 C +ATOM 3292 N GLY A 14 -11.871 -3.863 0.111 1.00 16.43 N +ATOM 3293 CA GLY A 14 -11.449 -2.983 -0.958 1.00 15.97 C +ATOM 3294 C GLY A 14 -9.986 -3.186 -1.252 1.00 15.81 C +ATOM 3295 O GLY A 14 -9.221 -3.645 -0.406 1.00 15.35 O +ATOM 3303 N LYS A 15 -9.601 -2.849 -2.479 1.00 15.98 N +ATOM 3304 CA LYS A 15 -8.222 -2.951 -2.936 1.00 16.09 C +ATOM 3305 C LYS A 15 -7.563 -1.610 -2.666 1.00 15.49 C +ATOM 3306 O LYS A 15 -8.222 -0.574 -2.732 1.00 15.59 O +ATOM 3307 CB LYS A 15 -8.149 -3.328 -4.412 1.00 16.75 C +ATOM 191 N GLY A 16 -6.280 -1.630 -2.332 1.00 33.75 N +ATOM 192 CA GLY A 16 -5.558 -0.433 -1.960 1.00 33.31 C +ATOM 193 C GLY A 16 -4.172 -0.442 -2.546 1.00 31.97 C +ATOM 194 O GLY A 16 -3.854 -1.323 -3.340 1.00 30.11 O +ATOM 199 N ILE A 17 -3.342 0.521 -2.175 1.00 31.75 N +ATOM 200 CA ILE A 17 -1.957 0.575 -2.628 1.00 31.88 C +ATOM 201 C ILE A 17 -1.127 1.136 -1.486 1.00 31.99 C +ATOM 202 O ILE A 17 -1.509 2.125 -0.859 1.00 31.57 O +ATOM 203 CB ILE A 17 -1.800 1.416 -3.903 1.00 32.40 C +ATOM 204 N VAL A 18 0.004 0.509 -1.198 1.00 32.65 N +ATOM 205 CA VAL A 18 0.896 0.990 -0.150 1.00 33.76 C +ATOM 206 C VAL A 18 1.576 2.251 -0.664 1.00 33.35 C +ATOM 207 O VAL A 18 1.822 2.385 -1.864 1.00 32.40 O +ATOM 208 CB VAL A 18 1.921 -0.084 0.242 1.00 34.81 C +ATOM 214 N ALA A 19 1.864 3.189 0.235 1.00 33.49 N +ATOM 215 CA ALA A 19 2.476 4.453 -0.156 1.00 33.94 C +ATOM 216 C ALA A 19 3.647 4.826 0.744 1.00 33.82 C +ATOM 217 O ALA A 19 4.665 5.324 0.270 1.00 34.04 O +ATOM 218 CB ALA A 19 1.424 5.566 -0.161 1.00 33.76 C +ATOM 5 N LYS A 20 3.524 4.588 2.035 1.00 20.21 N +ATOM 6 CA LYS A 20 4.589 4.865 2.977 1.00 19.04 C +ATOM 7 C LYS A 20 4.900 3.577 3.721 1.00 20.37 C +ATOM 8 O LYS A 20 3.998 2.918 4.200 1.00 17.74 O +ATOM 9 CB LYS A 20 4.180 5.980 3.946 1.00 22.23 C +ATOM 1297 N GLY A 21 6.167 3.188 3.771 1.00 21.17 N +ATOM 1298 CA GLY A 21 6.567 1.981 4.467 1.00 22.82 C +ATOM 1299 C GLY A 21 7.532 2.314 5.576 1.00 24.28 C +ATOM 1300 O GLY A 21 8.482 3.050 5.360 1.00 27.83 O +ATOM 1305 N LYS A 22 7.291 1.774 6.768 1.00 26.26 N +ATOM 1306 CA LYS A 22 8.105 2.113 7.923 1.00 27.25 C +ATOM 1307 C LYS A 22 9.402 1.326 7.995 1.00 27.39 C +ATOM 1308 O LYS A 22 10.038 1.312 9.052 1.00 29.75 O +ATOM 1309 CB LYS A 22 7.323 1.893 9.220 1.00 26.82 C +ATOM 3906 N LYS A 23 9.821 0.689 6.909 1.00 32.62 N +ATOM 3907 CA LYS A 23 11.000 -0.160 6.913 1.00 33.45 C +ATOM 3908 C LYS A 23 12.234 0.608 6.475 1.00 33.95 C +ATOM 3909 O LYS A 23 12.243 1.267 5.436 1.00 34.22 O +ATOM 3910 CB LYS A 23 10.814 -1.365 5.994 1.00 33.95 C +ATOM 3913 N LYS A 24 13.291 0.499 7.271 1.00 33.95 N +ATOM 3914 CA LYS A 24 14.615 0.840 6.781 1.00 32.30 C +ATOM 3915 C LYS A 24 15.027 -0.172 5.724 1.00 31.52 C +ATOM 3916 O LYS A 24 14.201 -0.949 5.241 1.00 29.72 O +ATOM 3917 CB LYS A 24 15.613 0.857 7.933 1.00 34.60 C +ATOM 3920 N ALA A 25 16.304 -0.163 5.349 1.00 27.55 N +ATOM 3921 CA ALA A 25 16.838 -1.114 4.366 1.00 25.34 C +ATOM 3922 C ALA A 25 16.151 -0.996 3.006 1.00 23.20 C +ATOM 3923 O ALA A 25 16.799 -1.059 1.963 1.00 24.26 O +ATOM 3924 CB ALA A 25 16.750 -2.552 4.874 1.00 26.43 C +ATOM 3932 N ILE A 26 14.832 -0.838 3.002 1.00 20.88 N +ATOM 3933 CA ILE A 26 14.048 -0.875 1.759 1.00 23.21 C +ATOM 3934 C ILE A 26 14.475 0.341 0.951 1.00 21.96 C +ATOM 3935 O ILE A 26 13.782 1.356 0.859 1.00 22.39 O +ATOM 3936 CB ILE A 26 12.544 -0.903 2.023 1.00 20.20 C +ATOM 2399 N GLY A 27 15.640 0.227 0.329 1.00 10.32 N +ATOM 2400 CA GLY A 27 16.116 1.315 -0.491 1.00 10.62 C +ATOM 2401 C GLY A 27 16.940 0.819 -1.650 1.00 10.75 C +ATOM 2402 O GLY A 27 17.880 0.042 -1.462 1.00 10.08 O +ATOM 2407 N GLY A 28 16.611 1.269 -2.854 1.00 11.47 N +ATOM 2408 CA GLY A 28 17.308 0.770 -4.022 1.00 12.20 C +ATOM 2409 C GLY A 28 17.197 1.622 -5.270 1.00 11.92 C +ATOM 2410 O GLY A 28 16.494 1.244 -6.216 1.00 12.26 O +ATOM 2415 N GLY A 29 17.894 2.762 -5.282 1.00 12.31 N +ATOM 2416 CA GLY A 29 18.014 3.611 -6.460 1.00 12.71 C +ATOM 2417 C GLY A 29 19.359 4.295 -6.410 1.00 12.69 C +ATOM 2418 O GLY A 29 20.288 3.888 -7.087 1.00 13.22 O +ATOM 449 N ILE A 30 19.449 5.350 -5.610 1.00 23.48 N +ATOM 450 CA ILE A 30 20.728 5.833 -5.100 1.00 22.97 C +ATOM 451 C ILE A 30 20.902 5.094 -3.760 1.00 23.25 C +ATOM 452 O ILE A 30 20.443 3.960 -3.612 1.00 24.94 O +ATOM 453 N LYS A 31 21.544 5.715 -2.779 1.00 22.86 N +ATOM 454 CA LYS A 31 21.646 5.092 -1.470 1.00 22.95 C +ATOM 455 C LYS A 31 20.766 5.753 -0.426 1.00 21.87 C +ATOM 456 O LYS A 31 21.050 5.626 0.766 1.00 21.87 O +ATOM 457 CB LYS A 31 23.094 5.108 -0.988 1.00 23.61 C +ATOM 459 N VAL A 32 19.716 6.454 -0.841 1.00 19.42 N +ATOM 460 CA VAL A 32 18.826 7.113 0.099 1.00 18.30 C +ATOM 461 C VAL A 32 17.907 6.077 0.728 1.00 18.42 C +ATOM 462 O VAL A 32 18.040 4.876 0.474 1.00 18.87 O +ATOM 463 CB VAL A 32 18.032 8.215 -0.613 1.00 18.52 C +ATOM 1237 N ILE A 33 16.962 6.536 1.539 1.00 9.62 N +ATOM 1238 CA ILE A 33 15.980 5.673 2.178 1.00 8.49 C +ATOM 1239 C ILE A 33 15.027 6.551 2.974 1.00 9.76 C +ATOM 1240 O ILE A 33 15.455 7.295 3.858 1.00 8.68 O +ATOM 1241 CB ILE A 33 16.645 4.634 3.086 1.00 8.36 C +ATOM 1245 N ARG A 34 13.739 6.460 2.675 1.00 10.12 N +ATOM 1246 CA ARG A 34 12.720 7.097 3.493 1.00 11.50 C +ATOM 1247 C ARG A 34 12.176 6.092 4.497 1.00 11.68 C +ATOM 1248 O ARG A 34 12.576 4.927 4.492 1.00 12.46 O +ATOM 1249 CB ARG A 34 11.597 7.637 2.617 1.00 11.89 C +ATOM 1252 N ALA A 35 11.261 6.542 5.359 1.00 12.69 N +ATOM 1253 CA ALA A 35 10.695 5.705 6.407 1.00 12.80 C +ATOM 1254 C ALA A 35 9.704 6.492 7.245 1.00 12.75 C +ATOM 1255 O ALA A 35 10.102 7.213 8.159 1.00 10.48 O +ATOM 1256 CB ALA A 35 11.786 5.152 7.326 1.00 13.55 C +ATOM 1260 N GLY A 36 8.419 6.317 6.969 1.00 12.49 N +ATOM 1261 CA GLY A 36 7.413 7.124 7.633 1.00 14.21 C +ATOM 1262 C GLY A 36 6.724 6.371 8.750 1.00 14.40 C +ATOM 1263 O GLY A 36 7.125 6.436 9.918 1.00 13.51 O +ATOM 1264 N ILE A 37 5.631 5.667 8.361 1.00 14.51 N +ATOM 1265 CA ILE A 37 4.757 4.897 9.247 1.00 15.20 C +ATOM 1266 C ILE A 37 3.531 4.471 8.455 1.00 15.16 C +ATOM 1267 O ILE A 37 2.628 5.268 8.222 1.00 15.72 O +ATOM 1268 CB ILE A 37 4.357 5.694 10.504 1.00 14.18 C +ATOM 2971 N VAL A 38 3.481 3.184 8.101 1.00 9.75 N +ATOM 2972 CA VAL A 38 2.765 2.611 6.949 1.00 10.34 C +ATOM 2973 C VAL A 38 1.415 3.251 6.635 1.00 9.75 C +ATOM 2974 O VAL A 38 0.701 3.685 7.540 1.00 10.53 O +ATOM 2975 CB VAL A 38 2.595 1.089 7.128 1.00 11.46 C +ATOM 263 N GLY A 39 1.054 3.302 5.349 1.00 16.54 N +ATOM 264 CA GLY A 39 -0.179 3.934 4.919 1.00 17.07 C +ATOM 265 C GLY A 39 -0.606 3.526 3.528 1.00 16.93 C +ATOM 266 O GLY A 39 0.234 3.196 2.695 1.00 17.75 O +ATOM 273 N LYS A 40 -1.905 3.551 3.256 1.00 16.86 N +ATOM 274 CA LYS A 40 -2.430 2.997 2.011 1.00 17.62 C +ATOM 275 C LYS A 40 -3.416 3.986 1.407 1.00 18.44 C +ATOM 276 O LYS A 40 -3.964 4.825 2.121 1.00 18.27 O +ATOM 277 CB LYS A 40 -3.100 1.654 2.268 1.00 17.83 C +ATOM 5 N VAL A 41 -3.644 3.888 0.105 1.00 20.21 N +ATOM 6 CA VAL A 41 -4.654 4.679 -0.580 1.00 19.04 C +ATOM 7 C VAL A 41 -5.536 3.711 -1.345 1.00 20.37 C +ATOM 8 O VAL A 41 -5.039 2.917 -2.149 1.00 17.74 O +ATOM 9 CB VAL A 41 -4.021 5.719 -1.517 1.00 22.23 C +ATOM 1969 N LYS A 42 -6.836 3.764 -1.090 1.00 12.88 N +ATOM 1970 CA LYS A 42 -7.784 2.830 -1.684 1.00 14.47 C +ATOM 1971 C LYS A 42 -7.782 3.004 -3.194 1.00 13.46 C +ATOM 1972 O LYS A 42 -7.234 3.982 -3.705 1.00 14.70 O +ATOM 1973 CB LYS A 42 -9.180 3.041 -1.109 1.00 15.03 C +ATOM 1976 N VAL A 43 -8.373 2.053 -3.908 1.00 12.97 N +ATOM 1977 CA VAL A 43 -8.322 2.024 -5.361 1.00 14.42 C +ATOM 1978 C VAL A 43 -9.555 1.303 -5.878 1.00 14.78 C +ATOM 1979 O VAL A 43 -10.114 0.446 -5.188 1.00 14.65 O +ATOM 1980 CB VAL A 43 -7.043 1.339 -5.875 1.00 13.91 C +ATOM 1984 N SER A 44 -10.000 1.673 -7.073 1.00 15.03 N +ATOM 1985 CA SER A 44 -11.023 0.891 -7.741 1.00 15.75 C +ATOM 1986 C SER A 44 -10.368 -0.303 -8.413 1.00 15.86 C +ATOM 1987 O SER A 44 -9.147 -0.360 -8.551 1.00 15.75 O +ATOM 1988 CB SER A 44 -11.768 1.745 -8.762 1.00 16.01 C +ATOM 1989 N LYS A 45 -11.179 -1.267 -8.826 1.00 16.93 N +ATOM 1990 CA LYS A 45 -10.625 -2.460 -9.445 1.00 17.52 C +ATOM 1991 C LYS A 45 -10.218 -2.198 -10.892 1.00 17.12 C +ATOM 1992 O LYS A 45 -9.270 -2.810 -11.391 1.00 18.20 O +ATOM 1993 CB LYS A 45 -11.629 -3.607 -9.366 1.00 18.01 C +ATOM 1881 N ASP A 46 -10.915 -1.298 -11.583 1.00 20.72 N +ATOM 1882 CA ASP A 46 -10.523 -0.966 -12.946 1.00 21.11 C +ATOM 1883 C ASP A 46 -9.778 0.363 -13.015 1.00 21.62 C +ATOM 1884 O ASP A 46 -8.732 0.469 -13.665 1.00 20.59 O +ATOM 1885 CB ASP A 46 -11.747 -0.928 -13.857 1.00 21.60 C +ATOM 1893 N ALA A 47 -10.301 1.380 -12.347 1.00 20.82 N +ATOM 1894 CA ALA A 47 -9.733 2.713 -12.424 1.00 20.91 C +ATOM 1895 C ALA A 47 -8.475 2.824 -11.574 1.00 20.66 C +ATOM 1896 O ALA A 47 -7.683 1.879 -11.483 1.00 22.58 O +ATOM 1897 CB ALA A 47 -10.756 3.761 -11.979 1.00 20.41 C +ATOM 1901 N VAL A 48 -8.294 4.001 -10.974 1.00 20.80 N +ATOM 1902 CA VAL A 48 -7.114 4.275 -10.166 1.00 21.07 C +ATOM 1903 C VAL A 48 -7.477 4.641 -8.728 1.00 21.38 C +ATOM 1904 O VAL A 48 -7.724 3.749 -7.915 1.00 22.41 O +ATOM 1905 CB VAL A 48 -6.270 5.380 -10.817 1.00 21.52 C +ATOM 1909 N ALA A 49 -7.528 5.927 -8.391 1.00 21.20 N +ATOM 1910 CA ALA A 49 -7.793 6.318 -7.011 1.00 22.10 C +ATOM 1911 C ALA A 49 -9.288 6.274 -6.724 1.00 22.33 C +ATOM 1912 O ALA A 49 -10.084 5.954 -7.606 1.00 22.72 O +ATOM 1913 CB ALA A 49 -7.230 7.708 -6.733 1.00 22.39 C +ATOM 1293 N ILE A 50 -9.665 6.569 -5.482 1.00 15.59 N +ATOM 1294 CA ILE A 50 -11.064 6.537 -5.061 1.00 14.93 C +ATOM 1295 C ILE A 50 -11.437 7.694 -4.146 1.00 14.02 C +ATOM 1296 O ILE A 50 -12.402 7.562 -3.377 1.00 13.06 O +ATOM 1297 CB ILE A 50 -11.418 5.198 -4.382 1.00 14.73 C +ATOM 1300 N LYS A 51 -10.693 8.799 -4.187 1.00 12.35 N +ATOM 1301 CA LYS A 51 -10.992 10.061 -3.519 1.00 11.94 C +ATOM 1302 C LYS A 51 -9.740 10.921 -3.593 1.00 12.47 C +ATOM 1303 O LYS A 51 -8.663 10.442 -3.947 1.00 12.54 O +ATOM 1304 CB LYS A 51 -11.426 9.877 -2.064 1.00 12.38 C +ATOM 1312 N GLY A 52 -9.892 12.204 -3.270 1.00 12.56 N +ATOM 1313 CA GLY A 52 -8.751 13.100 -3.195 1.00 12.72 C +ATOM 1314 C GLY A 52 -8.035 13.020 -1.860 1.00 13.42 C +ATOM 1315 O GLY A 52 -8.581 13.435 -0.839 1.00 14.00 O +ATOM 1319 N ASP A 53 -6.808 12.510 -1.855 1.00 12.19 N +ATOM 1320 CA ASP A 53 -6.110 12.121 -0.631 1.00 13.93 C +ATOM 1321 C ASP A 53 -5.430 13.323 -0.005 1.00 13.79 C +ATOM 1322 O ASP A 53 -5.474 14.428 -0.540 1.00 14.44 O +ATOM 1323 CB ASP A 53 -5.076 11.043 -0.931 1.00 14.33 C +ATOM 2041 N GLY A 54 -4.774 13.101 1.124 1.00 17.99 N +ATOM 2042 CA GLY A 54 -3.898 14.102 1.699 1.00 18.66 C +ATOM 2043 C GLY A 54 -4.412 14.606 3.025 1.00 18.49 C +ATOM 2044 O GLY A 54 -5.322 14.033 3.626 1.00 17.63 O +ATOM 2786 N GLY A 55 -3.802 15.690 3.480 1.00 11.04 N +ATOM 2787 CA GLY A 55 -4.206 16.360 4.695 1.00 10.44 C +ATOM 2788 C GLY A 55 -3.005 16.632 5.581 1.00 11.03 C +ATOM 2789 O GLY A 55 -1.986 17.154 5.145 1.00 10.97 O +ATOM 2792 N GLY A 56 -3.165 16.290 6.857 1.00 13.14 N +ATOM 2793 CA GLY A 56 -2.044 16.293 7.770 1.00 14.46 C +ATOM 2794 C GLY A 56 -1.169 15.067 7.652 1.00 15.15 C +ATOM 2795 O GLY A 56 -0.106 15.017 8.280 1.00 19.82 O +ATOM 363 N ALA A 57 -1.583 14.078 6.862 1.00 20.15 N +ATOM 364 CA ALA A 57 -0.839 12.836 6.718 1.00 20.14 C +ATOM 365 C ALA A 57 -0.498 12.547 5.266 1.00 19.98 C +ATOM 366 O ALA A 57 -0.530 11.393 4.844 1.00 19.91 O +ATOM 367 CB ALA A 57 -1.620 11.670 7.325 1.00 20.73 C +ATOM 371 N GLY A 58 -0.166 13.569 4.495 1.00 19.39 N +ATOM 372 CA GLY A 58 0.160 13.363 3.105 1.00 19.02 C +ATOM 373 C GLY A 58 1.646 13.352 2.847 1.00 19.48 C +ATOM 374 O GLY A 58 2.311 14.384 2.950 1.00 18.91 O +ATOM 377 N ILE A 59 2.177 12.185 2.519 1.00 20.12 N +ATOM 378 CA ILE A 59 3.568 12.028 2.124 1.00 21.09 C +ATOM 379 C ILE A 59 3.733 10.627 1.556 1.00 21.27 C +ATOM 380 O ILE A 59 3.966 9.675 2.301 1.00 22.08 O +ATOM 381 CB ILE A 59 4.525 12.267 3.300 1.00 21.22 C +ATOM 2210 N LYS A 60 3.590 10.492 0.247 1.00 30.93 N +ATOM 2211 CA LYS A 60 3.884 9.238 -0.415 1.00 30.78 C +ATOM 2212 C LYS A 60 5.392 9.069 -0.462 1.00 30.67 C +ATOM 2213 O LYS A 60 6.118 9.757 0.257 1.00 30.90 O +ATOM 2214 CB LYS A 60 3.289 9.232 -1.818 1.00 31.02 C +ATOM 2221 N ALA A 61 5.871 8.169 -1.309 1.00 30.33 N +ATOM 2222 CA ALA A 61 7.299 7.964 -1.493 1.00 30.26 C +ATOM 2223 C ALA A 61 7.651 8.280 -2.938 1.00 30.68 C +ATOM 2224 O ALA A 61 6.856 8.027 -3.844 1.00 30.49 O +ATOM 2225 CB ALA A 61 7.697 6.538 -1.137 1.00 29.87 C +ATOM 2224 N ARG A 62 8.845 8.826 -3.154 1.00 25.61 N +ATOM 2225 CA ARG A 62 9.290 9.085 -4.515 1.00 25.59 C +ATOM 2226 C ARG A 62 9.350 7.805 -5.330 1.00 25.38 C +ATOM 2227 O ARG A 62 9.267 7.852 -6.561 1.00 25.11 O +ATOM 2228 CB ARG A 62 10.655 9.771 -4.506 1.00 26.01 C +ATOM 2229 N ALA A 63 9.489 6.657 -4.669 1.00 25.45 N +ATOM 2230 CA ALA A 63 9.487 5.394 -5.392 1.00 25.77 C +ATOM 2231 C ALA A 63 8.192 5.196 -6.167 1.00 25.02 C +ATOM 2232 O ALA A 63 8.186 4.511 -7.193 1.00 24.90 O +ATOM 2233 CB ALA A 63 9.715 4.237 -4.424 1.00 26.08 C +ATOM 2238 N LYS A 64 7.093 5.809 -5.724 1.00 24.57 N +ATOM 2239 CA LYS A 64 5.841 5.665 -6.455 1.00 24.50 C +ATOM 2240 C LYS A 64 5.925 6.269 -7.845 1.00 24.15 C +ATOM 2241 O LYS A 64 5.025 6.053 -8.661 1.00 24.20 O +ATOM 2242 CB LYS A 64 4.691 6.281 -5.665 1.00 24.19 C +ATOM 149 N LYS A 65 7.006 6.976 -8.153 1.00 20.45 N +ATOM 150 CA LYS A 65 7.282 7.415 -9.513 1.00 20.20 C +ATOM 151 C LYS A 65 7.482 6.227 -10.444 1.00 20.10 C +ATOM 152 O LYS A 65 7.850 6.397 -11.607 1.00 21.12 O +ATOM 153 CB LYS A 65 8.514 8.322 -9.538 1.00 19.83 C +ATOM 154 N LYS A 66 7.263 5.025 -9.938 1.00 17.29 N +ATOM 155 CA LYS A 66 7.155 3.819 -10.749 1.00 17.32 C +ATOM 156 C LYS A 66 5.686 3.638 -11.116 1.00 19.29 C +ATOM 157 O LYS A 66 5.181 2.514 -11.159 1.00 18.79 O +ATOM 158 CB LYS A 66 7.687 2.606 -10.000 1.00 17.96 C +ATOM 161 N GLY A 67 4.994 4.753 -11.343 1.00 19.37 N +ATOM 162 CA GLY A 67 3.673 4.711 -11.935 1.00 21.34 C +ATOM 163 C GLY A 67 2.563 5.305 -11.110 1.00 21.74 C +ATOM 164 O GLY A 67 1.532 4.657 -10.943 1.00 22.38 O +ATOM 165 N GLY A 68 2.723 6.521 -10.607 1.00 20.48 N +ATOM 166 CA GLY A 68 1.738 7.091 -9.712 1.00 19.86 C +ATOM 167 C GLY A 68 0.960 8.276 -10.250 1.00 20.71 C +ATOM 168 O GLY A 68 1.521 9.347 -10.495 1.00 20.81 O +ATOM 781 N GLY A 69 -0.344 8.089 -10.439 1.00 16.86 N +ATOM 782 CA GLY A 69 -1.254 9.192 -10.679 1.00 17.03 C +ATOM 783 C GLY A 69 -1.751 9.734 -9.357 1.00 17.13 C +ATOM 784 O GLY A 69 -2.764 10.436 -9.287 1.00 17.67 O +ATOM 789 N LYS A 70 -1.039 9.362 -8.294 1.00 16.95 N +ATOM 790 CA LYS A 70 -1.236 9.895 -6.951 1.00 17.08 C +ATOM 791 C LYS A 70 -0.354 11.127 -6.811 1.00 16.68 C +ATOM 792 O LYS A 70 0.540 11.180 -5.967 1.00 16.80 O +ATOM 793 CB LYS A 70 -0.908 8.845 -5.897 1.00 17.17 C +ATOM 797 N LYS A 71 -0.582 12.110 -7.679 1.00 16.94 N +ATOM 798 CA LYS A 71 -0.103 13.471 -7.489 1.00 17.08 C +ATOM 799 C LYS A 71 -1.061 14.233 -6.590 1.00 17.51 C +ATOM 800 O LYS A 71 -1.126 15.461 -6.633 1.00 17.76 O +ATOM 801 CB LYS A 71 0.064 14.193 -8.823 1.00 16.48 C +ATOM 804 N SER A 72 -1.826 13.498 -5.787 1.00 17.36 N +ATOM 805 CA SER A 72 -2.715 14.065 -4.790 1.00 17.64 C +ATOM 806 C SER A 72 -2.081 14.099 -3.406 1.00 17.95 C +ATOM 807 O SER A 72 -2.789 14.304 -2.419 1.00 19.26 O +ATOM 808 CB SER A 72 -4.030 13.284 -4.760 1.00 16.94 C +ATOM 814 N GLY A 73 -0.767 13.914 -3.311 1.00 17.32 N +ATOM 815 CA GLY A 73 -0.067 13.999 -2.048 1.00 17.70 C +ATOM 816 C GLY A 73 0.799 15.236 -1.978 1.00 18.50 C +ATOM 817 O GLY A 73 0.720 16.131 -2.820 1.00 18.13 O +ATOM 818 N ALA A 74 1.640 15.288 -0.948 1.00 18.71 N +ATOM 819 CA ALA A 74 2.639 16.339 -0.801 1.00 19.65 C +ATOM 820 C ALA A 74 3.987 15.786 -0.345 1.00 20.21 C +ATOM 821 O ALA A 74 4.488 16.159 0.714 1.00 20.94 O +ATOM 822 CB ALA A 74 2.147 17.406 0.168 1.00 19.63 C +ATOM 829 N LYS A 75 4.578 14.893 -1.132 1.00 20.07 N +ATOM 830 CA LYS A 75 5.874 14.306 -0.815 1.00 19.78 C +ATOM 831 C LYS A 75 6.973 15.359 -0.868 1.00 19.42 C +ATOM 832 O LYS A 75 6.975 16.315 -0.095 1.00 19.47 O +ATOM 833 CB LYS A 75 6.202 13.162 -1.779 1.00 19.85 C +TER +ATOM 1 N ARG A 81 -10.933 -1.719 10.506 1.00 27.82 N +ATOM 2 CA ARG A 81 -11.823 -1.081 9.549 1.00 23.15 C +ATOM 3 C ARG A 81 -11.988 -1.971 8.326 1.00 24.44 C +ATOM 4 O ARG A 81 -12.205 -3.166 8.454 1.00 23.56 O +ATOM 5 N ILE A 82 -11.875 -1.381 7.142 1.00 20.21 N +ATOM 6 CA ILE A 82 -12.024 -2.097 5.881 1.00 19.04 C +ATOM 7 C ILE A 82 -10.960 -3.191 5.811 1.00 20.37 C +ATOM 8 O ILE A 82 -9.946 -3.125 6.503 1.00 17.74 O +ATOM 9 CB ILE A 82 -11.921 -1.138 4.692 1.00 22.23 C +ATOM 546 N VAL A 83 -11.184 -4.199 4.975 1.00 22.37 N +ATOM 547 CA VAL A 83 -10.271 -5.334 4.882 1.00 26.00 C +ATOM 548 C VAL A 83 -9.683 -5.376 3.480 1.00 30.26 C +ATOM 549 O VAL A 83 -10.257 -5.985 2.576 1.00 35.19 O +ATOM 550 CB VAL A 83 -10.987 -6.648 5.223 1.00 25.74 C +ATOM 555 N VAL A 84 -8.519 -4.763 3.306 1.00 24.40 N +ATOM 556 CA VAL A 84 -7.998 -4.413 1.994 1.00 26.29 C +ATOM 557 C VAL A 84 -7.173 -5.555 1.420 1.00 28.06 C +ATOM 558 O VAL A 84 -6.494 -6.285 2.134 1.00 29.61 O +ATOM 559 CB VAL A 84 -7.159 -3.125 2.053 1.00 31.28 C +ATOM 566 N ILE A 85 -7.231 -5.697 0.103 1.00 30.54 N +ATOM 567 CA ILE A 85 -6.344 -6.591 -0.621 1.00 29.29 C +ATOM 568 C ILE A 85 -5.288 -5.732 -1.291 1.00 31.77 C +ATOM 569 O ILE A 85 -5.224 -5.656 -2.519 1.00 31.74 O +ATOM 570 CB ILE A 85 -7.097 -7.446 -1.645 1.00 30.40 C +ATOM 574 N ILE A 86 -4.461 -5.091 -0.486 1.00 28.71 N +ATOM 575 CA ILE A 86 -3.466 -4.149 -0.972 1.00 31.03 C +ATOM 576 C ILE A 86 -2.529 -4.827 -1.953 1.00 32.44 C +ATOM 577 O ILE A 86 -2.334 -6.037 -1.912 1.00 36.01 O +ATOM 578 CB ILE A 86 -2.679 -3.530 0.199 1.00 25.27 C +ATOM 718 N GLY A 87 -1.968 -4.055 -2.861 1.00 9.32 N +ATOM 719 CA GLY A 87 -0.932 -4.502 -3.767 1.00 7.48 C +ATOM 720 C GLY A 87 -0.251 -3.320 -4.410 1.00 7.50 C +ATOM 721 O GLY A 87 -0.783 -2.757 -5.368 1.00 10.36 O +ATOM 726 N GLY A 88 0.919 -2.932 -3.888 1.00 9.75 N +ATOM 727 CA GLY A 88 1.563 -1.693 -4.258 1.00 9.75 C +ATOM 728 C GLY A 88 3.052 -1.667 -3.956 1.00 10.39 C +ATOM 729 O GLY A 88 3.761 -2.663 -4.113 1.00 11.83 O +ATOM 734 N ILE A 89 3.521 -0.493 -3.507 1.00 10.14 N +ATOM 735 CA ILE A 89 4.944 -0.178 -3.331 1.00 12.16 C +ATOM 736 C ILE A 89 5.495 -0.650 -1.987 1.00 8.45 C +ATOM 737 O ILE A 89 5.766 0.166 -1.097 1.00 13.94 O +ATOM 738 CB ILE A 89 5.204 1.331 -3.485 1.00 15.51 C +ATOM 746 N LYS A 90 5.681 -1.967 -1.845 1.00 10.12 N +ATOM 747 CA LYS A 90 6.148 -2.597 -0.617 1.00 8.93 C +ATOM 748 C LYS A 90 5.631 -4.028 -0.556 1.00 6.60 C +ATOM 749 O LYS A 90 5.807 -4.788 -1.504 1.00 9.21 O +ATOM 5 N VAL A 91 5.002 -4.404 0.553 1.00 20.21 N +ATOM 6 CA VAL A 91 4.298 -5.673 0.720 1.00 19.04 C +ATOM 7 C VAL A 91 5.176 -6.898 0.503 1.00 20.37 C +ATOM 8 O VAL A 91 5.212 -7.447 -0.599 1.00 17.74 O +ATOM 9 CB VAL A 91 3.087 -5.740 -0.219 1.00 22.23 C +ATOM 3961 N LYS A 92 5.856 -7.361 1.551 1.00 27.85 N +ATOM 3962 CA LYS A 92 6.534 -8.646 1.492 1.00 28.85 C +ATOM 3963 C LYS A 92 5.486 -9.714 1.271 1.00 29.89 C +ATOM 3964 O LYS A 92 4.298 -9.472 1.464 1.00 29.91 O +ATOM 3965 N ALA A 93 5.914 -10.896 0.865 1.00 31.04 N +ATOM 3966 CA ALA A 93 4.991 -11.881 0.329 1.00 32.00 C +ATOM 3967 C ALA A 93 4.826 -13.092 1.236 1.00 32.74 C +ATOM 3968 O ALA A 93 5.773 -13.537 1.890 1.00 32.70 O +ATOM 3969 CB ALA A 93 5.448 -12.347 -1.048 1.00 32.14 C +ATOM 3972 N LYS A 94 3.604 -13.615 1.256 1.00 33.67 N +ATOM 3973 CA LYS A 94 3.306 -14.983 1.651 1.00 34.45 C +ATOM 3974 C LYS A 94 2.420 -15.578 0.567 1.00 34.91 C +ATOM 3975 O LYS A 94 1.197 -15.637 0.717 1.00 34.86 O +ATOM 3976 CB LYS A 94 2.616 -15.036 3.006 1.00 34.55 C +ATOM 3981 N ILE A 95 3.040 -15.999 -0.525 1.00 35.68 N +ATOM 3982 CA ILE A 95 2.350 -16.583 -1.663 1.00 36.06 C +ATOM 3983 C ILE A 95 3.326 -16.436 -2.814 1.00 36.64 C +ATOM 3984 O ILE A 95 4.488 -16.084 -2.602 1.00 36.89 O +ATOM 3985 N GLY A 96 2.876 -16.714 -4.028 1.00 37.18 N +ATOM 3986 CA GLY A 96 3.567 -16.234 -5.207 1.00 37.54 C +ATOM 3987 C GLY A 96 2.749 -15.074 -5.715 1.00 37.30 C +ATOM 3988 O GLY A 96 1.682 -15.285 -6.291 1.00 37.64 O +ATOM 2898 N ALA A 97 3.190 -13.847 -5.478 1.00 10.14 N +ATOM 2899 CA ALA A 97 2.185 -12.800 -5.494 1.00 11.76 C +ATOM 2900 C ALA A 97 2.720 -11.537 -6.141 1.00 11.70 C +ATOM 2901 O ALA A 97 3.610 -10.879 -5.596 1.00 11.58 O +ATOM 2902 CB ALA A 97 1.697 -12.502 -4.074 1.00 13.45 C +ATOM 2904 N LYS A 98 2.143 -11.204 -7.307 1.00 11.11 N +ATOM 2905 CA LYS A 98 2.267 -9.877 -7.899 1.00 11.97 C +ATOM 2906 C LYS A 98 1.355 -8.867 -7.224 1.00 13.33 C +ATOM 2907 O LYS A 98 1.823 -7.792 -6.847 1.00 13.19 O +ATOM 2908 CB LYS A 98 1.962 -9.920 -9.390 1.00 11.60 C +ATOM 2910 N LYS A 99 0.074 -9.165 -7.073 1.00 14.27 N +ATOM 2911 CA LYS A 99 -0.777 -8.405 -6.169 1.00 16.74 C +ATOM 2912 C LYS A 99 -0.888 -9.174 -4.863 1.00 17.34 C +ATOM 2913 O LYS A 99 -1.407 -10.286 -4.829 1.00 18.30 O +ATOM 2914 CB LYS A 99 -2.171 -8.161 -6.763 1.00 18.21 C +ATOM 2918 N VAL A 100 -0.362 -8.593 -3.784 1.00 18.48 N +ATOM 2919 CA VAL A 100 -0.280 -9.286 -2.501 1.00 18.43 C +ATOM 2920 C VAL A 100 -1.650 -9.810 -2.116 1.00 18.02 C +ATOM 2921 O VAL A 100 -2.308 -9.283 -1.206 1.00 17.17 O +ATOM 2922 CB VAL A 100 0.300 -8.382 -1.401 1.00 19.81 C +ATOM 9078 N GLY A 101 -2.064 -10.885 -2.791 1.00 14.81 N +ATOM 9079 CA GLY A 101 -3.396 -11.459 -2.697 1.00 14.61 C +ATOM 9080 C GLY A 101 -3.816 -11.831 -1.300 1.00 15.70 C +ATOM 9081 O GLY A 101 -4.495 -12.837 -1.075 1.00 19.52 O +ATOM 9086 N GLY A 102 -3.405 -11.010 -0.355 1.00 15.31 N +ATOM 9087 CA GLY A 102 -3.685 -11.285 1.022 1.00 16.53 C +ATOM 9088 C GLY A 102 -4.695 -10.267 1.436 1.00 13.65 C +ATOM 9089 O GLY A 102 -4.825 -9.244 0.768 1.00 13.71 O +ATOM 9095 N VAL A 103 -5.429 -10.520 2.508 1.00 17.42 N +ATOM 9096 CA VAL A 103 -6.373 -9.523 2.953 1.00 17.66 C +ATOM 9097 C VAL A 103 -5.844 -8.885 4.220 1.00 17.97 C +ATOM 9098 O VAL A 103 -6.282 -9.213 5.327 1.00 16.61 O +ATOM 9099 CB VAL A 103 -7.763 -10.141 3.142 1.00 17.30 C +ATOM 9102 N ILE A 104 -4.890 -7.966 4.061 1.00 14.21 N +ATOM 9103 CA ILE A 104 -4.452 -7.082 5.130 1.00 15.11 C +ATOM 9104 C ILE A 104 -5.597 -6.134 5.455 1.00 16.87 C +ATOM 9105 O ILE A 104 -6.647 -6.165 4.813 1.00 15.71 O +ATOM 9106 CB ILE A 104 -3.180 -6.311 4.746 1.00 15.53 C +ATOM 9110 N LYS A 105 -5.399 -5.278 6.449 1.00 16.52 N +ATOM 9111 CA LYS A 105 -6.520 -4.544 7.031 1.00 17.93 C +ATOM 9112 C LYS A 105 -6.201 -3.052 7.074 1.00 17.88 C +ATOM 9113 O LYS A 105 -5.045 -2.646 7.092 1.00 18.77 O +ATOM 9114 CB LYS A 105 -6.824 -5.102 8.410 1.00 18.90 C +ATOM 5 N ALA A 106 -7.232 -2.216 7.115 1.00 20.21 N +ATOM 6 CA ALA A 106 -7.056 -0.781 6.956 1.00 19.04 C +ATOM 7 C ALA A 106 -7.931 0.002 7.928 1.00 20.37 C +ATOM 8 O ALA A 106 -9.066 -0.386 8.200 1.00 17.74 O +ATOM 9 CB ALA A 106 -7.372 -0.379 5.523 1.00 22.23 C +ATOM 4765 N ILE A 107 -7.413 1.116 8.427 1.00 15.76 N +ATOM 4766 CA ILE A 107 -8.037 1.869 9.505 1.00 16.10 C +ATOM 4767 C ILE A 107 -8.385 3.260 8.981 1.00 16.16 C +ATOM 4768 O ILE A 107 -7.719 4.245 9.315 1.00 16.39 O +ATOM 4769 CB ILE A 107 -7.129 1.951 10.734 1.00 16.21 C +ATOM 4772 N ARG A 108 -9.446 3.365 8.184 1.00 16.03 N +ATOM 4773 CA ARG A 108 -9.875 4.668 7.688 1.00 16.68 C +ATOM 4774 C ARG A 108 -10.775 4.501 6.471 1.00 16.75 C +ATOM 4775 O ARG A 108 -10.508 3.666 5.608 1.00 17.20 O +ATOM 4776 N ARG A 109 -11.843 5.288 6.384 1.00 16.99 N +ATOM 4777 CA ARG A 109 -12.827 5.134 5.322 1.00 17.03 C +ATOM 4778 C ARG A 109 -13.169 6.448 4.638 1.00 16.97 C +ATOM 4779 O ARG A 109 -14.132 7.110 5.019 1.00 17.08 O +ATOM 4780 N GLY A 110 -12.410 6.827 3.628 1.00 16.68 N +ATOM 4781 CA GLY A 110 -12.642 8.085 2.962 1.00 16.30 C +ATOM 4782 C GLY A 110 -11.689 8.321 1.812 1.00 15.96 C +ATOM 4783 O GLY A 110 -11.854 7.791 0.716 1.00 15.78 O +ATOM 806 N ILE A 111 -10.649 9.116 2.095 1.00 15.21 N +ATOM 807 CA ILE A 111 -9.750 9.578 1.038 1.00 15.25 C +ATOM 808 C ILE A 111 -8.321 9.099 1.283 1.00 14.48 C +ATOM 809 O ILE A 111 -7.801 8.237 0.566 1.00 13.95 O +ATOM 810 CB ILE A 111 -9.818 11.109 0.914 1.00 18.69 C +ATOM 817 N LYS A 112 -7.659 9.668 2.288 1.00 13.23 N +ATOM 818 CA LYS A 112 -6.223 9.478 2.464 1.00 12.29 C +ATOM 819 C LYS A 112 -5.854 8.095 2.963 1.00 11.93 C +ATOM 820 O LYS A 112 -4.663 7.826 3.179 1.00 12.30 O +ATOM 821 CB LYS A 112 -5.666 10.517 3.435 1.00 13.42 C +ATOM 826 N VAL A 113 -6.841 7.227 3.178 1.00 11.35 N +ATOM 827 CA VAL A 113 -6.604 5.842 3.569 1.00 10.38 C +ATOM 828 C VAL A 113 -5.998 5.810 4.962 1.00 11.79 C +ATOM 829 O VAL A 113 -5.491 6.818 5.458 1.00 13.75 O +ATOM 830 N GLY A 114 -6.049 4.653 5.606 1.00 10.10 N +ATOM 831 CA GLY A 114 -5.425 4.485 6.899 1.00 9.84 C +ATOM 832 C GLY A 114 -4.098 3.765 6.757 1.00 10.25 C +ATOM 833 O GLY A 114 -3.749 3.273 5.691 1.00 9.82 O +ATOM 5 N GLY A 115 -3.373 3.728 7.868 1.00 20.21 N +ATOM 6 CA GLY A 115 -2.267 2.805 7.963 1.00 19.04 C +ATOM 7 C GLY A 115 -2.770 1.375 7.931 1.00 20.37 C +ATOM 8 O GLY A 115 -3.792 1.040 8.528 1.00 17.74 O +ATOM 775 N GLY A 116 -2.062 0.527 7.203 1.00 16.60 N +ATOM 776 CA GLY A 116 -2.402 -0.870 7.202 1.00 17.27 C +ATOM 777 C GLY A 116 -2.317 -1.462 8.594 1.00 19.96 C +ATOM 778 O GLY A 116 -1.650 -0.942 9.481 1.00 18.97 O +ATOM 786 N LYS A 117 -3.011 -2.575 8.793 1.00 20.70 N +ATOM 787 CA LYS A 117 -2.870 -3.317 10.035 1.00 20.75 C +ATOM 788 C LYS A 117 -2.072 -4.590 9.793 1.00 26.23 C +ATOM 789 O LYS A 117 -2.473 -5.451 9.007 1.00 38.53 O +ATOM 790 CB LYS A 117 -4.236 -3.637 10.639 1.00 23.72 C +ATOM 1832 N ILE A 118 -0.938 -4.698 10.472 1.00 12.23 N +ATOM 1833 CA ILE A 118 -0.002 -5.792 10.295 1.00 12.84 C +ATOM 1834 C ILE A 118 1.212 -5.529 11.182 1.00 12.33 C +ATOM 1835 O ILE A 118 1.098 -5.094 12.329 1.00 11.94 O +ATOM 1836 CB ILE A 118 0.416 -5.975 8.818 1.00 13.17 C +ATOM 2465 N ALA A 119 2.387 -5.797 10.617 1.00 13.65 N +ATOM 2466 CA ALA A 119 3.683 -5.570 11.236 1.00 12.43 C +ATOM 2467 C ALA A 119 4.432 -4.444 10.535 1.00 13.72 C +ATOM 2468 O ALA A 119 5.295 -4.711 9.697 1.00 14.32 O +ATOM 2469 CB ALA A 119 4.520 -6.843 11.180 1.00 12.02 C +ATOM 31 N VAL A 120 4.126 -3.185 10.860 1.00 5.87 N +ATOM 32 CA VAL A 120 4.852 -2.058 10.280 1.00 6.28 C +ATOM 33 C VAL A 120 6.325 -2.200 10.613 1.00 6.30 C +ATOM 34 O VAL A 120 6.767 -1.822 11.701 1.00 6.82 O +ATOM 35 CB VAL A 120 4.289 -0.729 10.794 1.00 6.30 C +ATOM 43 N LYS A 121 7.090 -2.731 9.665 1.00 6.85 N +ATOM 44 CA LYS A 121 8.324 -3.457 9.940 1.00 7.33 C +ATOM 45 C LYS A 121 9.432 -2.496 10.352 1.00 7.22 C +ATOM 46 O LYS A 121 9.532 -1.393 9.814 1.00 8.07 O +ATOM 47 CB LYS A 121 8.721 -4.287 8.725 1.00 7.37 C +ATOM 51 N ILE A 122 10.245 -2.915 11.332 1.00 7.60 N +ATOM 52 CA ILE A 122 11.466 -2.211 11.718 1.00 8.54 C +ATOM 53 C ILE A 122 12.686 -3.134 11.750 1.00 9.00 C +ATOM 54 O ILE A 122 13.814 -2.661 11.938 1.00 10.14 O +ATOM 636 N GLY A 123 12.493 -4.436 11.572 1.00 22.14 N +ATOM 637 CA GLY A 123 13.615 -5.356 11.617 1.00 21.89 C +ATOM 638 C GLY A 123 14.000 -5.831 10.227 1.00 19.25 C +ATOM 639 O GLY A 123 13.170 -6.364 9.480 1.00 19.23 O +ATOM 644 N GLY A 124 15.285 -5.684 9.913 1.00 17.08 N +ATOM 645 CA GLY A 124 15.711 -5.611 8.522 1.00 16.06 C +ATOM 646 C GLY A 124 15.397 -6.863 7.752 1.00 16.14 C +ATOM 647 O GLY A 124 15.825 -7.969 8.102 1.00 14.51 O +ATOM 652 N GLY A 125 14.634 -6.699 6.671 1.00 15.60 N +ATOM 653 CA GLY A 125 14.267 -7.769 5.792 1.00 16.03 C +ATOM 654 C GLY A 125 15.002 -7.694 4.472 1.00 15.94 C +ATOM 655 O GLY A 125 16.219 -7.551 4.417 1.00 16.51 O +ATOM 5 N VAL A 126 14.226 -7.758 3.396 1.00 20.21 N +ATOM 6 CA VAL A 126 14.787 -7.748 2.047 1.00 19.04 C +ATOM 7 C VAL A 126 15.479 -6.424 1.772 1.00 20.37 C +ATOM 8 O VAL A 126 14.821 -5.414 1.530 1.00 17.74 O +ATOM 9 CB VAL A 126 13.693 -7.995 1.011 1.00 22.23 C +ATOM 14 N LYS A 127 16.810 -6.434 1.776 1.00 19.31 N +ATOM 15 CA LYS A 127 17.595 -5.278 1.359 1.00 19.58 C +ATOM 16 C LYS A 127 17.394 -5.015 -0.125 1.00 19.91 C +ATOM 17 O LYS A 127 16.414 -5.454 -0.725 1.00 19.76 O +ATOM 18 CB LYS A 127 19.076 -5.509 1.633 1.00 20.42 C +ATOM 19 N VAL A 128 18.346 -4.320 -0.729 1.00 17.69 N +ATOM 20 CA VAL A 128 18.346 -4.201 -2.176 1.00 17.51 C +ATOM 21 C VAL A 128 19.633 -3.583 -2.668 1.00 14.26 C +ATOM 22 O VAL A 128 20.715 -3.968 -2.249 1.00 14.38 O +ATOM 23 CB VAL A 128 17.155 -3.391 -2.675 1.00 17.33 C +TER +ATOM 726 N LYS A 141 5.819 -10.424 5.061 1.00 9.48 N +ATOM 727 CA LYS A 141 5.877 -9.822 6.378 1.00 8.99 C +ATOM 728 C LYS A 141 4.735 -8.852 6.546 1.00 9.97 C +ATOM 729 O LYS A 141 4.546 -8.280 7.611 1.00 11.19 O +ATOM 730 CB LYS A 141 7.209 -9.105 6.595 1.00 9.39 C +ATOM 733 N LYS A 142 3.997 -8.645 5.463 1.00 9.26 N +ATOM 734 CA LYS A 142 2.855 -7.745 5.445 1.00 8.32 C +ATOM 735 C LYS A 142 1.682 -8.537 4.918 1.00 8.47 C +ATOM 736 O LYS A 142 0.694 -7.974 4.451 1.00 8.93 O +ATOM 737 CB LYS A 142 3.122 -6.513 4.577 1.00 8.23 C +ATOM 744 N GLY A 143 1.805 -9.853 4.977 1.00 7.76 N +ATOM 745 CA GLY A 143 0.781 -10.744 4.483 1.00 10.15 C +ATOM 746 C GLY A 143 -0.489 -10.662 5.291 1.00 10.23 C +ATOM 747 O GLY A 143 -0.914 -9.570 5.664 1.00 10.32 O +ATOM 748 N VAL A 144 -1.074 -11.811 5.628 1.00 11.54 N +ATOM 749 CA VAL A 144 -2.418 -11.828 6.194 1.00 12.37 C +ATOM 750 C VAL A 144 -2.498 -11.028 7.492 1.00 11.94 C +ATOM 751 O VAL A 144 -3.493 -11.114 8.220 1.00 10.53 O +ATOM 752 CB VAL A 144 -2.878 -13.285 6.391 1.00 13.66 C +ATOM 757 N GLY A 145 -1.484 -10.229 7.793 1.00 12.14 N +ATOM 758 CA GLY A 145 -1.449 -9.459 9.013 1.00 10.62 C +ATOM 759 C GLY A 145 -2.596 -8.505 9.213 1.00 11.20 C +ATOM 760 O GLY A 145 -2.822 -8.051 10.324 1.00 10.38 O +TER +ATOM 726 N GLY A 131 -5.004 -10.220 15.078 1.00 9.48 N +ATOM 727 CA GLY A 131 -3.704 -9.586 15.089 1.00 8.99 C +ATOM 728 C GLY A 131 -2.604 -10.549 14.742 1.00 9.97 C +ATOM 729 O GLY A 131 -1.480 -10.145 14.481 1.00 11.19 O +ATOM 733 N GLY A 132 -2.948 -11.828 14.740 1.00 9.26 N +ATOM 734 CA GLY A 132 -2.009 -12.893 14.479 1.00 8.32 C +ATOM 735 C GLY A 132 -2.675 -14.250 14.440 1.00 8.47 C +ATOM 736 O GLY A 132 -2.016 -15.279 14.591 1.00 8.93 O +ATOM 744 N LYS A 133 -3.987 -14.266 14.231 1.00 7.76 N +ATOM 745 CA LYS A 133 -4.748 -15.497 14.096 1.00 10.15 C +ATOM 746 C LYS A 133 -4.656 -16.004 12.672 1.00 10.23 C +ATOM 747 O LYS A 133 -5.505 -16.776 12.235 1.00 10.32 O +ATOM 748 N LYS A 134 -3.616 -15.577 11.950 1.00 11.54 N +ATOM 749 CA LYS A 134 -3.415 -15.991 10.565 1.00 12.37 C +ATOM 750 C LYS A 134 -2.058 -15.549 10.044 1.00 11.94 C +ATOM 751 O LYS A 134 -1.515 -16.164 9.125 1.00 10.53 O +ATOM 752 CB LYS A 134 -4.519 -15.426 9.684 1.00 13.66 C +ATOM 757 N ILE A 135 -1.498 -14.500 10.628 1.00 12.14 N +ATOM 758 CA ILE A 135 -0.212 -13.942 10.248 1.00 10.62 C +ATOM 759 C ILE A 135 0.870 -14.998 10.253 1.00 11.20 C +ATOM 760 O ILE A 135 1.939 -14.786 10.816 1.00 10.38 O +ATOM 761 CB ILE A 135 0.180 -12.801 11.183 1.00 11.50 C +TER +END +""" + first_annotation_text=""" +SHEET 1 1 2 VAL A 18 GLY A 21 0 +SHEET 2 1 2 VAL A 38 VAL A 41 -1 +""" + + second_annotation_text=""" +SHEET 1 1 4 LYS A 40 VAL A 43 0 +SHEET 2 1 4 ALA A 12 VAL A 18 -1 N ILE A 17 O VAL A 41 +SHEET 3 1 4 ARG A 81 GLY A 87 1 N VAL A 83 O ALA A 12 +SHEET 4 1 4 VAL A 103 ILE A 107 -1 N ALA A 106 O ILE A 82 +""" + + import iotbx.pdb + from cctbx.array_family import flex + + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_text) + ).construct_hierarchy() + + import iotbx.pdb.secondary_structure as ioss + first_annotation=ioss.annotation.from_records(records=flex.split_lines(first_annotation_text)) + second_annotation=ioss.annotation.from_records(records=flex.split_lines(second_annotation_text)) + + print("\nMerging annotations and checking on sheet numbering") + print("\nFirst annotation: ") + print("\nSecond annotation: ") + merged=second_annotation.combine_annotations(other=first_annotation, hierarchy=hierarchy) + print("\nMerged: ") + assert merged.is_similar_to(other=second_annotation,hierarchy=hierarchy) + + + + std_short=""" +ATOM 41 N ALA E 9 16.983 19.664 12.537 1.00 40.00 N +ATOM 42 CA ALA E 9 18.325 19.700 13.075 1.00 40.00 C +ATOM 43 C ALA E 9 18.282 19.275 14.530 1.00 40.00 C +ATOM 44 O ALA E 9 19.094 19.698 15.348 1.00 40.00 O +ATOM 45 CB ALA E 9 18.921 21.097 12.944 1.00 40.00 C +ATOM 46 N ALA E 10 17.311 18.426 14.838 1.00 40.00 N +ATOM 47 CA ALA E 10 16.934 18.105 16.208 1.00 40.00 C +ATOM 48 C ALA E 10 15.691 17.248 16.171 1.00 40.00 C +ATOM 49 O ALA E 10 15.418 16.533 17.133 1.00 40.00 O +ATOM 50 CB ALA E 10 16.643 19.341 17.056 1.00 40.00 C +ATOM 51 N ALA E 11 14.918 17.340 15.101 1.00 40.00 N +ATOM 52 CA ALA E 11 13.892 16.372 14.777 1.00 40.00 C +ATOM 53 C ALA E 11 14.481 15.437 13.750 1.00 40.00 C +ATOM 54 O ALA E 11 14.140 14.259 13.695 1.00 40.00 O +ATOM 55 CB ALA E 11 12.642 17.047 14.251 1.00 40.00 C +ATOM 56 N ALA E 12 15.357 15.975 12.922 1.00 40.00 N +ATOM 57 CA ALA E 12 16.068 15.188 11.935 1.00 40.00 C +ATOM 58 C ALA E 12 17.302 14.592 12.578 1.00 40.00 C +ATOM 59 O ALA E 12 17.738 13.498 12.224 1.00 40.00 O +ATOM 60 CB ALA E 12 16.473 16.043 10.745 1.00 40.00 C +ATOM 61 N ALA E 13 17.885 15.327 13.522 1.00 40.00 N +ATOM 62 CA ALA E 13 19.089 14.889 14.207 1.00 40.00 C +ATOM 63 C ALA E 13 18.624 13.974 15.341 1.00 40.00 C +ATOM 64 O ALA E 13 19.426 13.210 15.854 1.00 40.00 O +ATOM 65 CB ALA E 13 19.937 16.062 14.623 1.00 40.00 C +ATOM 66 N ALA E 14 17.377 14.036 15.725 1.00 40.00 N +ATOM 67 CA ALA E 14 16.776 12.964 16.497 1.00 40.00 C +ATOM 68 C ALA E 14 16.849 11.628 15.781 1.00 40.00 C +ATOM 69 O ALA E 14 17.479 11.493 14.731 1.00 40.00 O +ATOM 70 CB ALA E 14 15.332 13.334 16.814 1.00 40.00 C +ATOM 71 N ALA E 15 16.245 10.605 16.362 1.00 40.00 N +ATOM 72 CA ALA E 15 15.885 9.387 15.650 1.00 40.00 C +ATOM 73 C ALA E 15 14.370 9.403 15.597 1.00 40.00 C +ATOM 74 O ALA E 15 13.752 9.549 14.543 1.00 40.00 O +ATOM 75 CB ALA E 15 16.418 8.148 16.352 1.00 40.00 C +ATOM 76 N ALA E 16 13.770 9.311 16.781 1.00 40.00 N +ATOM 77 CA ALA E 16 12.311 9.393 16.932 1.00 40.00 C +ATOM 78 C ALA E 16 11.863 10.591 17.771 1.00 40.00 C +ATOM 79 O ALA E 16 10.793 11.154 17.534 1.00 40.00 O +ATOM 80 CB ALA E 16 11.787 8.113 17.522 1.00 40.00 C +TER +""" + std=""" +ATOM 36 N ALA E 8 13.630 20.859 12.915 1.00 40.00 N +ATOM 37 CA ALA E 8 14.599 19.792 12.772 1.00 40.00 C +ATOM 38 C ALA E 8 15.979 20.231 13.192 1.00 40.00 C +ATOM 39 O ALA E 8 16.128 21.067 14.087 1.00 40.00 O +ATOM 40 CB ALA E 8 14.646 19.295 11.334 1.00 40.00 C +""" + std_short + + anno=""" +HELIX 1 1 ALA E 8 ALA E 14 1 7 +HELIX 1 1 ALA E 9 ALA E 14 1 7 +""" + + sheet_anno=""" +SHEET 1 1 4 LYS A 40 VAL A 43 0 +SHEET 2 1 4 ALA A 12 VAL A 18 -1 N ILE A 17 O VAL A 41 +SHEET 3 1 4 ARG A 81 GLY A 87 1 N VAL A 83 O ALA A 12 +SHEET 4 1 4 VAL A 103 ILE A 107 -1 N ALA A 106 O ILE A 82 +SHEET 1 2 2 ALA A 12 VAL A 18 0 +SHEET 2 2 2 ARG A 81 GLY A 87 1 +""" + bad_sheet_anno=""" +SHEET 1 1 4 LYS A 40 VAL A 43 0 +SHEET 2 1 4 GLY A 10 VAL A 18 -1 N ILE A 17 O VAL A 41 +SHEET 3 1 4 ARG A 81 GLY A 87 1 N VAL A 83 O ALA A 12 +SHEET 4 1 4 VAL A 103 ILE A 107 -1 N ALA A 106 O ILE A 82 +""" + + print("\nRemoving bad annotation and duplicate annotation\n") + + print("\nRemoving duplicate sheets") + annotation=ioss.annotation.from_records(records=flex.split_lines(sheet_anno)) + new_annotation=annotation.remove_overlapping_annotations( + hierarchy=hierarchy) + print("New annotation:") + expected=ioss.annotation.from_records(records=flex.split_lines(""" +SHEET 1 1 4 LYS A 40 VAL A 43 0 +SHEET 2 1 4 ALA A 12 VAL A 18 -1 N ILE A 17 O VAL A 41 +SHEET 3 1 4 ARG A 81 GLY A 87 1 N VAL A 83 O ALA A 12 +SHEET 4 1 4 VAL A 103 ILE A 107 -1 N ALA A 106 O ILE A 82 + """)) + assert new_annotation.is_same_as(expected) + + print("\nRemoving bad sheets") + annotation=ioss.annotation.from_records(records=flex.split_lines( + bad_sheet_anno)) + from mmtbx.secondary_structure.find_ss_from_ca import remove_bad_annotation + new_annotation=remove_bad_annotation(annotation,hierarchy=hierarchy) + print("New annotation:") + expected=ioss.annotation.from_records(records=flex.split_lines(""" +SHEET 1 3 2 ARG A 81 GLY A 87 0 +SHEET 2 3 2 VAL A 103 ILE A 107 -1 N ALA A 106 O ILE A 82 """)) + assert new_annotation.is_same_as(expected) + + + + import iotbx.pdb + from cctbx.array_family import flex + std_hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(std)).construct_hierarchy() + short_hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(std_short)).construct_hierarchy() + + import iotbx.pdb.secondary_structure as ioss + annotation=ioss.annotation.from_records(records=flex.split_lines(anno)) + + print("\nRemoving duplicate helices") + + print("\nRemoving duplicate helix annotation\n") + expected=ioss.annotation.from_records(records=flex.split_lines(""" +HELIX 1 1 ALA E 8 ALA E 14 1 7 + """)) + + new_annotation=annotation.remove_overlapping_annotations( + hierarchy=std_hierarchy) + assert new_annotation.is_same_as(expected) + + print("\nRemoving bad annotation\n") + expected=ioss.annotation.from_records(records=flex.split_lines(""" +HELIX 1 1 ALA E 9 ALA E 14 1 7 + """)) + + from mmtbx.secondary_structure.find_ss_from_ca import remove_bad_annotation + new_annotation=remove_bad_annotation(annotation,hierarchy=short_hierarchy, + out=null_out()) + assert new_annotation.is_same_as(expected) + + +def tst_13(): + text=""" +ATOM 1158 CA GLU A 156 -8.682 11.320 15.966 1.00 10.43 C +ATOM 1167 CA GLN A 156A -6.656 11.562 12.759 1.00 9.67 C +ATOM 1176 CA LEU A 157 -4.088 9.262 11.060 1.00 7.37 C +ATOM 1184 CA ASP A 158 -0.686 11.064 10.807 1.00 7.30 C +ATOM 1192 CA HIS A 159 2.219 8.525 11.247 1.00 5.74 C +ATOM 1202 CA GLY A 160 3.410 5.357 9.460 1.00 4.69 C +ATOM 1206 CA VAL A 161 4.873 2.505 11.506 1.00 4.06 C +ATOM 1213 CA LEU A 162 5.253 -1.330 11.465 1.00 4.26 C +ATOM 1221 CA LEU A 163 3.267 -3.988 13.368 1.00 3.63 C +ATOM 1229 CA VAL A 164 5.734 -6.749 14.393 1.00 3.93 C +ATOM 1236 CA GLY A 165 3.593 -8.854 16.787 1.00 4.71 C +ATOM 1240 CA TYR A 166 0.655 -9.045 19.213 1.00 4.48 C +ATOM 1252 CA ASN A 167 -0.292 -10.850 22.465 1.00 5.51 C +ATOM 1260 CA ASP A 167A -3.960 -11.826 23.104 1.00 6.24 C +ATOM 1268 CA SER A 167B -3.078 -13.777 26.298 1.00 8.74 C +ATOM 1275 CA ALA A 167C -1.804 -10.753 28.295 1.00 8.17 C +ATOM 1280 CA ALA A 167D -3.879 -9.096 31.017 1.00 8.79 C +ATOM 1285 CA VAL A 168 -4.502 -6.306 28.540 1.00 7.67 C +ATOM 1292 CA PRO A 169 -4.105 -7.677 24.962 1.00 6.12 C +ATOM 1299 CA TYR A 170 -1.596 -5.595 22.934 1.00 4.66 C +ATOM 1311 CA TRP A 171 0.102 -4.825 19.619 1.00 4.56 C +ATOM 1325 CA ILE A 172 3.927 -4.560 19.307 1.00 4.40 C +ATOM 1333 CA ILE A 173 4.979 -1.652 16.989 1.00 3.93 C +ATOM 1341 CA LYS A 174 8.388 -0.666 15.529 1.00 3.87 C +ATOM 1350 CA ASN A 175 8.873 3.137 15.566 1.00 4.64 C +ATOM 1358 CA SER A 176 11.580 5.250 13.796 1.00 5.32 C +ATOM 1364 CA TRP A 177 12.553 7.546 16.722 1.00 5.40 C +ATOM 1378 CA THR A 178 15.829 5.844 17.894 1.00 5.35 C +ATOM 1385 CA THR A 179 16.311 3.064 20.481 1.00 7.16 C +ATOM 1392 CA GLN A 180 16.334 5.566 23.406 1.00 6.59 C +ATOM 1405 CA TRP A 181 12.544 6.150 22.843 1.00 5.77 C +ATOM 1419 CA GLY A 182 9.950 3.677 24.216 1.00 6.03 C +ATOM 1423 CA GLU A 183 10.962 0.080 24.830 1.00 6.05 C +ATOM 1432 CA GLU A 184 14.314 0.060 22.937 1.00 6.35 C +ATOM 1441 CA GLY A 185 12.464 1.895 20.102 1.00 4.92 C +ATOM 1445 CA TYR A 186 9.218 -0.136 20.229 1.00 5.14 C +ATOM 1457 CA ILE A 187 5.733 0.737 21.605 1.00 5.19 C +ATOM 1465 CA ARG A 188 2.937 -1.524 22.890 1.00 5.72 C +ATOM 1476 CA ILE A 189 -0.685 -0.274 22.541 1.00 6.24 C +ATOM 1484 CA ALA A 190 -3.901 -1.997 23.697 1.00 6.52 C +""" + anno=""" +SHEET 1 1 3 GLN A 156A VAL A 164 0 +SHEET 2 1 3 TYR A 170 ASN A 175 -1 N ASN A 175 O VAL A 161 +""" + + import iotbx.pdb + from cctbx.array_family import flex + import iotbx.pdb.secondary_structure as ioss + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(text)).construct_hierarchy() + input_annotation=ioss.annotation.from_records( + records=flex.split_lines(anno)) + print("\nAnnotation with insertion codes") + print("\nInput annotation:") + + fss=find_secondary_structure(hierarchy=hierarchy, + ss_by_chain=False,out=null_out()) + new_annotation=fss.get_annotation() + + expected_new=ioss.annotation.from_records(records=flex.split_lines(""" +HELIX 1 1 TRP A 181 TYR A 186 3 6 +SHEET 1 1 3 VAL A 161 VAL A 164 0 +SHEET 2 1 3 TYR A 170 ASN A 175 -1 N ASN A 175 O VAL A 161 +SHEET 3 1 3 ILE A 187 ALA A 190 -1 N ILE A 189 O TRP A 171 +""")) + + assert expected_new.is_same_as(new_annotation) + + + print("\nNew forcing input annotation") + + force_fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False, + user_annotation_text=input_annotation.as_pdb_str(), + force_secondary_structure_input=True, + combine_annotations=False, + out=null_out()).get_annotation() + assert input_annotation.is_same_as(force_fss) + + + helix_icode=""" +ATOM 2 CA ALA A 1A 11.323 32.055 11.635 1.00 40.00 C +ATOM 7 CA ALA A 4B 8.288 29.768 10.916 1.00 40.00 C +ATOM 12 CA ALA A 4C 10.313 27.854 8.231 1.00 40.00 C +ATOM 17 CA ALA A 4D 13.089 27.116 10.822 1.00 40.00 C +ATOM 22 CA ALA A 5 10.573 25.488 13.298 1.00 40.00 C +ATOM 27 CA ALA A 6 9.258 23.514 10.260 1.00 40.00 C +ATOM 32 CA ALA A 7 12.788 22.543 8.962 1.00 40.00 C +ATOM 37 CA ALA A 8 13.846 21.459 12.515 1.00 40.00 C +ATOM 42 CA ALA A 9 10.716 19.261 12.994 1.00 40.00 C +ATOM 47 CA ALA A 10 11.063 17.985 9.357 1.00 40.00 C +ATOM 52 CA ALA A 11 14.754 17.018 9.967 1.00 40.00 C +ATOM 57 CA ALA A 12 13.721 15.483 13.371 1.00 40.00 C +ATOM 62 CA ALA A 13 10.821 13.516 11.708 1.00 40.00 C +ATOM 67 CA ALA A 14 13.246 12.367 8.939 1.00 40.00 C +ATOM 72 CA ALA A 15 15.847 11.407 11.629 1.00 40.00 C +ATOM 77 CA ALA A 16 13.099 9.317 13.370 1.00 40.00 C +""" + helix_icode_ss=""" +HELIX 1 1 ALA A 1A ALA A 16 1 16 +""" + + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(helix_icode)).construct_hierarchy() + annotation=ioss.annotation.from_records( + records=flex.split_lines(helix_icode_ss)) + print("\nHelix annotation with insertion codes") + print("NOTE: currently misses the residues with insertion codes except those") + print("at the ends of a string of insertion codes") + fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False, + out=null_out()).get_annotation() + expected=ioss.annotation.from_records( + records=flex.split_lines(""" +HELIX 1 1 ALA A 4D ALA A 16 1 13 +""")) + assert expected.is_same_as(fss) + + print("\nHelix annotation with input annotation and insertion codes") + force_fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False, + user_annotation_text=annotation.as_pdb_or_mmcif_str(), + force_secondary_structure_input=True, + combine_annotations=False, + out=null_out()).get_annotation() + expected=ioss.annotation.from_records( + records=flex.split_lines(""" +HELIX 1 1 ALA A 1A ALA A 16 1 16 +""")) + assert expected.is_same_as(force_fss) + +def tst_14(): + text_pi_alpha=""" +ATOM 1 CA LYS U 65 9.083 9.180 -3.939 1.00 30.00 UNK C +ATOM 2 CA LYS U 66 8.415 5.910 -5.790 1.00 30.00 UNK C +ATOM 3 CA ARG U 67 6.335 7.380 -8.591 1.00 30.00 UNK C +ATOM 4 CA GLY U 68 8.644 5.764 -11.121 1.00 30.00 UNK C +ATOM 5 CA LYS U 69 6.554 2.639 -10.591 1.00 30.00 UNK C +ATOM 6 CA GLY U 70 3.920 4.296 -12.763 1.00 30.00 UNK C +ATOM 7 CA LYS U 71 1.379 5.357 -10.152 1.00 30.00 UNK C +ATOM 8 CA VAL U 72 1.224 9.093 -10.806 1.00 30.00 UNK C +ATOM 9 CA LYS U 73 -2.228 10.251 -9.725 1.00 30.00 UNK C +ATOM 10 CA VAL U 74 -1.340 8.736 -6.335 1.00 30.00 UNK C +ATOM 11 CA LYS U 75 0.620 11.990 -6.338 1.00 30.00 UNK C +ATOM 12 CA VAL U 76 -2.498 13.792 -5.167 1.00 30.00 UNK C +ATOM 13 CA GLY U 77 -0.596 14.285 -1.925 1.00 30.00 UNK C +ATOM 14 CA GLY U 78 2.056 16.680 -0.704 1.00 30.00 UNK C +""" + + annotation_text=""" +HELIX 2 2 LYS U 71 PRO U 78 5 8 +""" + overlapping_text=""" +HELIX 1 1 LYS U 66 LYS U 71 1 6 +HELIX 1 1 VAL U 72 GLY U 77 5 6 +""" + + import iotbx.pdb + from cctbx.array_family import flex + + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(text_pi_alpha) + ).construct_hierarchy() + + import iotbx.pdb.secondary_structure as ioss + annotation=ioss.annotation.from_records(records=flex.split_lines(annotation_text)) + overlapping_annotation=ioss.annotation.from_records(records=flex.split_lines(overlapping_text)) + + print("\nMerging annotations that overlap") + print("First annotation") + print("Overlapping annotation") + merged=overlapping_annotation.combine_annotations(other=annotation, hierarchy=hierarchy) + print("\nMerged: ") + assert merged.is_same_as(other=annotation) + +def tst_15(): + import iotbx.pdb + from cctbx.array_family import flex + + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_multi_copy_text) + ).construct_hierarchy() + annotation_std=find_secondary_structure( + hierarchy=hierarchy,ss_by_chain=False, + use_representative_chains=False,out=null_out()).get_annotation() + annotation_chains=find_secondary_structure( + hierarchy=hierarchy,ss_by_chain=True, + use_representative_chains=False,out=null_out()).get_annotation() + annotation_chains_rep=find_secondary_structure( + hierarchy=hierarchy,ss_by_chain=True, + use_representative_chains=True,out=null_out()).get_annotation() + assert annotation_std.is_same_as(other=annotation_chains) + assert annotation_std.is_same_as(other=annotation_chains_rep) + print("OK") + + +def tst_16(): + print("Checking missing atoms...", end=' ') + import iotbx.pdb + from cctbx.array_family import flex + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_strands_text)).construct_hierarchy() + fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False,out=null_out()) + + expected_text=""" +Model 1 N: 6 Start: 23 End: 28 +Class: Beta strand N: 6 Start: 23 End: 28 Rise: 3.42 A Dot: 0.97 + +Model 2 N: 6 Start: 31 End: 36 +Class: Beta strand N: 6 Start: 31 End: 36 Rise: 3.54 A Dot: 0.98 + +Model 3 N: 6 Start: 23 End: 28 +Class: Beta strand N: 6 Start: 23 End: 28 Rise: 3.44 A Dot: 0.96 + +Model 4 N: 6 Start: 31 End: 36 +Class: Beta strand N: 6 Start: 31 End: 36 Rise: 3.56 A Dot: 0.98 + +FINAL PDB RECORDS: +data_phenix +loop_ + _struct_sheet.id + _struct_sheet.type + _struct_sheet.number_strands + _struct_sheet.details + 1 ? 2 ? + 2 ? 2 ? + +loop_ + _struct_sheet_order.sheet_id + _struct_sheet_order.range_id_1 + _struct_sheet_order.range_id_2 + _struct_sheet_order.offset + _struct_sheet_order.sense + 1 1 2 ? anti-parallel + 2 1 2 ? anti-parallel + +loop_ + _struct_sheet_range.sheet_id + _struct_sheet_range.id + _struct_sheet_range.beg_label_comp_id + _struct_sheet_range.beg_label_asym_id + _struct_sheet_range.beg_label_seq_id + _struct_sheet_range.pdbx_beg_PDB_ins_code + _struct_sheet_range.end_label_comp_id + _struct_sheet_range.end_label_asym_id + _struct_sheet_range.end_label_seq_id + _struct_sheet_range.pdbx_end_PDB_ins_code + 1 1 GLY BXZLONG 23 ? ASN BXZLONG 28 ? + 1 2 GLY BXZLONG 31 ? ALA BXZLONG 36 ? + 2 1 GLY DXZLONG 23 ? ASN DXZLONG 28 ? + 2 2 GLY DXZLONG 31 ? ALA DXZLONG 36 ? + +loop_ + _pdbx_struct_sheet_hbond.sheet_id + _pdbx_struct_sheet_hbond.range_id_1 + _pdbx_struct_sheet_hbond.range_id_2 + _pdbx_struct_sheet_hbond.range_1_label_atom_id + _pdbx_struct_sheet_hbond.range_1_label_comp_id + _pdbx_struct_sheet_hbond.range_1_label_asym_id + _pdbx_struct_sheet_hbond.range_1_label_seq_id + _pdbx_struct_sheet_hbond.range_1_PDB_ins_code + _pdbx_struct_sheet_hbond.range_2_label_atom_id + _pdbx_struct_sheet_hbond.range_2_label_comp_id + _pdbx_struct_sheet_hbond.range_2_label_asym_id + _pdbx_struct_sheet_hbond.range_2_label_seq_id + _pdbx_struct_sheet_hbond.range_2_PDB_ins_code + 1 1 2 O PHE BXZLONG 24 ? N ALA BXZLONG 35 ? + 2 1 2 O PHE DXZLONG 24 ? N ALA DXZLONG 35 ? + + + + +FINAL PDB selections: +"(chain 'BXZLONG' and resid 23 through 28 ) or (chain 'BXZLONG' and resid 31 through 36 ) or (chain 'DXZLONG' and resid 23 through 28 ) or (chain 'DXZLONG' and resid 31 through 36 )" +""" + f=StringIO() + fss.show_summary(out=f,verbose=True) + found_text=f.getvalue() + #assert not test_utils.show_diff(found_text, expected_text) + if remove_blank(found_text)!=remove_blank(expected_text): + print("Expected: \n%s \nFound: \n%s" %(expected_text,found_text)) + raise AssertionError("FAILED") + print("OK") + +def tst_17(): + print("Checking missing atoms part 2...", end=' ') + import iotbx.pdb + from cctbx.array_family import flex + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_strands_add_o_text)).construct_hierarchy() + fss=find_secondary_structure(hierarchy=hierarchy,ss_by_chain=False,out=null_out()) + + expected_text=""" +Model 1 N: 6 Start: 23 End: 28 +Class: Beta strand N: 6 Start: 23 End: 28 Rise: 3.42 A Dot: 0.97 + +Model 2 N: 6 Start: 31 End: 36 +Class: Beta strand N: 6 Start: 31 End: 36 Rise: 3.54 A Dot: 0.98 + +Model 3 N: 6 Start: 23 End: 28 +Class: Beta strand N: 6 Start: 23 End: 28 Rise: 3.44 A Dot: 0.96 + +Model 4 N: 6 Start: 31 End: 36 +Class: Beta strand N: 6 Start: 31 End: 36 Rise: 3.56 A Dot: 0.98 + +FINAL PDB RECORDS: +data_phenix +loop_ + _struct_sheet.id + _struct_sheet.type + _struct_sheet.number_strands + _struct_sheet.details + 1 ? 2 ? + 2 ? 2 ? + +loop_ + _struct_sheet_order.sheet_id + _struct_sheet_order.range_id_1 + _struct_sheet_order.range_id_2 + _struct_sheet_order.offset + _struct_sheet_order.sense + 1 1 2 ? anti-parallel + 2 1 2 ? anti-parallel + +loop_ + _struct_sheet_range.sheet_id + _struct_sheet_range.id + _struct_sheet_range.beg_label_comp_id + _struct_sheet_range.beg_label_asym_id + _struct_sheet_range.beg_label_seq_id + _struct_sheet_range.pdbx_beg_PDB_ins_code + _struct_sheet_range.end_label_comp_id + _struct_sheet_range.end_label_asym_id + _struct_sheet_range.end_label_seq_id + _struct_sheet_range.pdbx_end_PDB_ins_code + 1 1 GLY BXZLONG 23 ? ASN BXZLONG 28 ? + 1 2 GLY BXZLONG 31 ? ALA BXZLONG 36 ? + 2 1 GLY DXZLONG 23 ? ASN DXZLONG 28 ? + 2 2 GLY DXZLONG 31 ? ALA DXZLONG 36 ? + +loop_ + _pdbx_struct_sheet_hbond.sheet_id + _pdbx_struct_sheet_hbond.range_id_1 + _pdbx_struct_sheet_hbond.range_id_2 + _pdbx_struct_sheet_hbond.range_1_label_atom_id + _pdbx_struct_sheet_hbond.range_1_label_comp_id + _pdbx_struct_sheet_hbond.range_1_label_asym_id + _pdbx_struct_sheet_hbond.range_1_label_seq_id + _pdbx_struct_sheet_hbond.range_1_PDB_ins_code + _pdbx_struct_sheet_hbond.range_2_label_atom_id + _pdbx_struct_sheet_hbond.range_2_label_comp_id + _pdbx_struct_sheet_hbond.range_2_label_asym_id + _pdbx_struct_sheet_hbond.range_2_label_seq_id + _pdbx_struct_sheet_hbond.range_2_PDB_ins_code + 1 1 2 O PHE BXZLONG 24 ? N ALA BXZLONG 35 ? + 2 1 2 O PHE DXZLONG 24 ? N ALA DXZLONG 35 ? + + + + +FINAL PDB selections: +"(chain 'BXZLONG' and resid 23 through 28 ) or (chain 'BXZLONG' and resid 31 through 36 ) or (chain 'DXZLONG' and resid 23 through 28 ) or (chain 'DXZLONG' and resid 31 through 36 )" +""" + f=StringIO() + fss.show_summary(out=f,verbose=True) + found_text=f.getvalue() + #assert not test_utils.show_diff(found_text, expected_text) + if remove_blank(found_text)!=remove_blank(expected_text): + print("Expected: \n%s \nFound: \n%s" %(expected_text,found_text)) + raise AssertionError("FAILED") + print("OK") + + +if __name__=="__main__": + import sys + tst_00() + tst_01() + tst_02() + tst_03() + tst_04() + tst_05() + tst_06() + tst_07() + tst_08() + tst_09() + tst_10() + tst_11() + tst_12() + tst_13() + tst_14() + tst_15() + tst_16() + tst_17() + print("OK") diff --git a/mmtbx/regression/tst_minimize_chain.py b/mmtbx/regression/tst_minimize_chain.py index 8efcc4b70c..b94ac53b70 100644 --- a/mmtbx/regression/tst_minimize_chain.py +++ b/mmtbx/regression/tst_minimize_chain.py @@ -568,7 +568,7 @@ def tst_01(): mtz_object.write(file_name = "%s_map.mtz"%prefix) from mmtbx.building.merge_models import run as merge_models - hierarchy=merge_models( + hierarchy, pdb_out=merge_models( map_data=target_map_data, pdb_inp=pdb_inp, dist_max=100, diff --git a/mmtbx/regression/tst_minimize_chain_cif.py b/mmtbx/regression/tst_minimize_chain_cif.py new file mode 100644 index 0000000000..bfdb9aa665 --- /dev/null +++ b/mmtbx/regression/tst_minimize_chain_cif.py @@ -0,0 +1,679 @@ +from __future__ import absolute_import, division, print_function + +from libtbx.test_utils import convert_pdb_to_cif_for_pdb_str + +import time +from mmtbx.building.minimize_chain import run,ccp4_map +import iotbx.pdb +pdb_str_two_models = """\ +CRYST1 29.475 46.191 27.490 90.00 90.00 90.00 P 21 21 21 +MODEL 0 +ATOM 1 N ALA A 1 14.622 35.477 13.274 1.00 40.00 N +ATOM 2 CA ALA A 1 14.323 35.055 14.635 1.00 40.00 C +ATOM 3 C ALA A 1 13.442 33.808 14.656 1.00 40.00 C +ATOM 4 O ALA A 1 13.848 32.796 15.227 1.00 40.00 O +ATOM 5 CB ALA A 1 13.675 36.191 15.414 1.00 40.00 C +ATOM 6 N ALA A 2 12.256 33.870 14.012 1.00 40.00 N +ATOM 7 CA ALA A 2 11.288 32.768 13.916 1.00 40.00 C +ATOM 8 C ALA A 2 11.847 31.573 13.125 1.00 40.00 C +ATOM 9 O ALA A 2 11.553 30.422 13.462 1.00 40.00 O +ATOM 10 CB ALA A 2 10.000 33.267 13.276 1.00 40.00 C +ATOM 11 N ALA A 3 12.664 31.856 12.084 1.00 40.00 N +ATOM 12 CA ALA A 3 13.313 30.854 11.231 1.00 40.00 C +ATOM 13 C ALA A 3 14.391 30.082 11.994 1.00 40.00 C +ATOM 14 O ALA A 3 14.616 28.906 11.687 1.00 40.00 O +ATOM 15 CB ALA A 3 13.915 31.517 10.000 1.00 40.00 C +ATOM 16 N ALA A 4 15.063 30.744 12.976 1.00 40.00 N +ATOM 17 CA ALA A 4 16.089 30.116 13.822 1.00 40.00 C +ATOM 18 C ALA A 4 15.441 29.043 14.703 1.00 40.00 C +ATOM 19 O ALA A 4 15.888 27.897 14.671 1.00 40.00 O +ATOM 20 CB ALA A 4 16.785 31.160 14.683 1.00 40.00 C +ATOM 1 N ALA E 1 14.622 35.477 13.274 1.00 40.00 N +ATOM 2 CA ALA E 1 14.323 35.055 14.635 1.00 40.00 C +ATOM 3 C ALA E 1 13.442 33.808 14.656 1.00 40.00 C +ATOM 4 O ALA E 1 13.848 32.796 15.227 1.00 40.00 O +ATOM 5 CB ALA E 1 13.675 36.191 15.414 1.00 40.00 C +ATOM 6 N ALA E 2 12.256 33.870 14.012 1.00 40.00 N +ATOM 7 CA ALA E 2 11.288 32.768 13.916 1.00 40.00 C +ATOM 8 C ALA E 2 11.847 31.573 13.125 1.00 40.00 C +ATOM 9 O ALA E 2 11.553 30.422 13.462 1.00 40.00 O +ATOM 10 CB ALA E 2 10.000 33.267 13.276 1.00 40.00 C +ATOM 11 N ALA E 3 12.664 31.856 12.084 1.00 40.00 N +ATOM 12 CA ALA E 3 13.313 30.854 11.231 1.00 40.00 C +ATOM 13 C ALA E 3 14.391 30.082 11.994 1.00 40.00 C +ATOM 14 O ALA E 3 14.616 28.906 11.687 1.00 40.00 O +ATOM 15 CB ALA E 3 13.915 31.517 10.000 1.00 40.00 C +ATOM 16 N ALA E 4 15.063 30.744 12.976 1.00 40.00 N +ATOM 17 CA ALA E 4 16.089 30.116 13.822 1.00 40.00 C +ATOM 18 C ALA E 4 15.441 29.043 14.703 1.00 40.00 C +ATOM 19 O ALA E 4 15.888 27.897 14.671 1.00 40.00 O +ATOM 20 CB ALA E 4 16.785 31.160 14.683 1.00 40.00 C +ATOM 21 N ALA E 5 13.827 28.582 13.930 1.00 40.00 N +ATOM 22 CA ALA E 5 12.803 27.643 13.582 1.00 40.00 C +ATOM 23 C ALA E 5 11.925 27.972 12.295 1.00 40.00 C +ATOM 24 O ALA E 5 11.311 29.016 12.217 1.00 40.00 O +ATOM 25 CB ALA E 5 11.884 27.496 14.800 1.00 40.00 C +ATOM 26 N ALA E 6 11.824 27.002 11.326 1.00 40.00 N +ATOM 27 CA ALA E 6 11.579 27.271 9.948 1.00 40.00 C +ATOM 28 C ALA E 6 10.688 26.172 9.315 1.00 40.00 C +ATOM 29 O ALA E 6 9.810 26.435 8.479 1.00 40.00 O +ATOM 30 CB ALA E 6 12.892 27.434 9.163 1.00 40.00 C +ATOM 31 N ALA E 7 10.985 24.936 9.568 1.00 40.00 N +ATOM 32 CA ALA E 7 10.223 23.915 8.805 1.00 40.00 C +ATOM 33 C ALA E 7 9.182 23.205 9.603 1.00 40.00 C +ATOM 34 O ALA E 7 7.945 23.417 9.434 1.00 40.00 O +ATOM 35 CB ALA E 7 11.183 22.804 8.200 1.00 40.00 C +ATOM 36 N ALA E 8 9.745 22.435 10.542 1.00 40.00 N +ATOM 37 CA ALA E 8 9.210 21.425 11.476 1.00 40.00 C +ATOM 38 C ALA E 8 10.256 20.419 11.733 1.00 40.00 C +ATOM 39 O ALA E 8 9.992 19.490 12.460 1.00 40.00 O +ATOM 40 CB ALA E 8 7.965 20.817 10.947 1.00 40.00 C +ATOM 41 N ALA E 9 14.664 23.357 15.803 1.00 40.00 N +ATOM 42 CA ALA E 9 13.716 22.261 15.994 1.00 40.00 C +ATOM 43 C ALA E 9 13.754 21.279 14.822 1.00 40.00 C +ATOM 44 O ALA E 9 13.654 20.075 15.051 1.00 40.00 O +ATOM 45 CB ALA E 9 12.314 22.805 16.193 1.00 40.00 C +ATOM 46 N ALA E 10 13.942 21.791 13.578 1.00 40.00 N +ATOM 47 CA ALA E 10 14.063 20.985 12.357 1.00 40.00 C +ATOM 48 C ALA E 10 15.322 20.116 12.421 1.00 40.00 C +ATOM 49 O ALA E 10 15.235 18.910 12.169 1.00 40.00 O +ATOM 50 CB ALA E 10 14.105 21.881 11.130 1.00 40.00 C +ATOM 51 N ALA E 11 16.480 20.722 12.803 1.00 40.00 N +ATOM 52 CA ALA E 11 17.754 20.018 12.967 1.00 40.00 C +ATOM 53 C ALA E 11 17.631 18.976 14.089 1.00 40.00 C +ATOM 54 O ALA E 11 18.074 17.837 13.908 1.00 40.00 O +ATOM 55 CB ALA E 11 18.870 21.004 13.279 1.00 40.00 C +ATOM 56 N ALA E 12 16.972 19.356 15.217 1.00 40.00 N +ATOM 57 CA ALA E 12 16.721 18.483 16.371 1.00 40.00 C +ATOM 58 C ALA E 12 15.851 17.277 15.972 1.00 40.00 C +ATOM 59 O ALA E 12 16.201 16.140 16.310 1.00 40.00 O +ATOM 60 CB ALA E 12 16.052 19.269 17.490 1.00 40.00 C +ATOM 61 N ALA E 13 17.693 10.781 12.936 1.00 40.00 N +ATOM 62 CA ALA E 13 18.559 9.862 13.648 1.00 40.00 C +ATOM 63 C ALA E 13 17.678 8.677 14.105 1.00 40.00 C +ATOM 64 O ALA E 13 16.810 8.236 13.332 1.00 40.00 O +ATOM 65 CB ALA E 13 19.221 10.551 14.826 1.00 40.00 C +ATOM 66 N ALA E 14 17.647 8.453 15.439 1.00 40.00 N +ATOM 67 CA ALA E 14 16.666 7.551 16.066 1.00 40.00 C +ATOM 68 C ALA E 14 15.298 8.147 16.400 1.00 40.00 C +ATOM 69 O ALA E 14 14.633 7.785 17.376 1.00 40.00 O +ATOM 70 CB ALA E 14 17.224 7.034 17.308 1.00 40.00 C +ATOM 71 N ALA E 15 14.855 9.000 15.485 1.00 40.00 N +ATOM 72 CA ALA E 15 13.517 9.710 15.635 1.00 40.00 C +ATOM 73 C ALA E 15 12.304 8.858 15.586 1.00 40.00 C +ATOM 74 O ALA E 15 11.625 8.812 14.564 1.00 40.00 O +ATOM 75 CB ALA E 15 13.302 10.842 14.526 1.00 40.00 C +ATOM 76 N ALA E 16 12.014 8.140 16.649 1.00 40.00 N +ATOM 77 CA ALA E 16 11.279 6.863 16.560 1.00 40.00 C +ATOM 78 C ALA E 16 10.003 6.986 17.409 1.00 40.00 C +ATOM 79 O ALA E 16 9.883 8.020 18.086 1.00 40.00 O +ATOM 80 CB ALA E 16 12.188 5.653 16.999 1.00 40.00 C + +TER +ENDMDL +MODEL 1 +ATOM 1 N ALA A 1 17.517 34.071 6.538 1.00 40.00 N +ATOM 2 CA ALA A 1 17.992 35.348 7.004 1.00 40.00 C +ATOM 3 C ALA A 1 16.863 35.986 7.792 1.00 40.00 C +ATOM 4 O ALA A 1 16.713 37.242 7.909 1.00 40.00 O +ATOM 5 CB ALA A 1 18.477 36.116 5.812 1.00 40.00 C +ATOM 6 N ALA A 2 16.080 35.113 8.348 1.00 40.00 N +ATOM 7 CA ALA A 2 15.254 35.581 9.495 1.00 40.00 C +ATOM 8 C ALA A 2 15.628 35.262 10.863 1.00 40.00 C +ATOM 9 O ALA A 2 16.066 36.143 11.629 1.00 40.00 O +ATOM 10 CB ALA A 2 13.821 35.144 9.297 1.00 40.00 C +ATOM 11 N ALA A 3 15.670 34.035 11.221 1.00 40.00 N +ATOM 12 CA ALA A 3 15.746 33.569 12.729 1.00 40.00 C +ATOM 13 C ALA A 3 16.380 32.197 13.043 1.00 40.00 C +ATOM 14 O ALA A 3 17.557 32.017 13.009 1.00 40.00 O +ATOM 15 CB ALA A 3 14.390 33.574 13.297 1.00 40.00 C +ATOM 16 N ALA A 4 15.437 31.334 13.516 1.00 40.00 N +ATOM 17 CA ALA A 4 15.810 29.953 13.900 1.00 40.00 C +ATOM 18 C ALA A 4 14.876 28.948 13.219 1.00 40.00 C +ATOM 19 O ALA A 4 15.088 28.561 12.135 1.00 40.00 O +ATOM 20 CB ALA A 4 15.807 29.747 15.562 1.00 40.00 C +ATOM 1 N ALA E 1 17.517 34.071 6.538 1.00 40.00 N +ATOM 2 CA ALA E 1 17.992 35.348 7.004 1.00 40.00 C +ATOM 3 C ALA E 1 16.863 35.986 7.792 1.00 40.00 C +ATOM 4 O ALA E 1 16.713 37.242 7.909 1.00 40.00 O +ATOM 5 CB ALA E 1 18.477 36.116 5.812 1.00 40.00 C +ATOM 6 N ALA E 2 16.080 35.113 8.348 1.00 40.00 N +ATOM 7 CA ALA E 2 15.254 35.581 9.495 1.00 40.00 C +ATOM 8 C ALA E 2 15.628 35.262 10.863 1.00 40.00 C +ATOM 9 O ALA E 2 16.066 36.143 11.629 1.00 40.00 O +ATOM 10 CB ALA E 2 13.821 35.144 9.297 1.00 40.00 C +ATOM 11 N ALA E 3 15.670 34.035 11.221 1.00 40.00 N +ATOM 12 CA ALA E 3 15.746 33.569 12.729 1.00 40.00 C +ATOM 13 C ALA E 3 16.380 32.197 13.043 1.00 40.00 C +ATOM 14 O ALA E 3 17.557 32.017 13.009 1.00 40.00 O +ATOM 15 CB ALA E 3 14.390 33.574 13.297 1.00 40.00 C +ATOM 16 N ALA E 4 15.437 31.334 13.516 1.00 40.00 N +ATOM 17 CA ALA E 4 15.810 29.953 13.900 1.00 40.00 C +ATOM 18 C ALA E 4 14.876 28.948 13.219 1.00 40.00 C +ATOM 19 O ALA E 4 15.088 28.561 12.135 1.00 40.00 O +ATOM 20 CB ALA E 4 15.807 29.747 15.562 1.00 40.00 C +ATOM 21 N ALA E 5 14.338 29.398 15.423 1.00 40.00 N +ATOM 22 CA ALA E 5 13.573 28.488 16.298 1.00 40.00 C +ATOM 23 C ALA E 5 13.042 27.288 15.513 1.00 40.00 C +ATOM 24 O ALA E 5 12.981 26.179 16.048 1.00 40.00 O +ATOM 25 CB ALA E 5 12.433 29.233 16.975 1.00 40.00 C +ATOM 26 N ALA E 6 12.715 27.518 14.221 1.00 40.00 N +ATOM 27 CA ALA E 6 12.258 26.514 13.260 1.00 40.00 C +ATOM 28 C ALA E 6 13.440 25.620 12.865 1.00 40.00 C +ATOM 29 O ALA E 6 13.361 24.405 13.060 1.00 40.00 O +ATOM 30 CB ALA E 6 11.664 27.193 12.032 1.00 40.00 C +ATOM 31 N ALA E 7 14.556 26.234 12.374 1.00 40.00 N +ATOM 32 CA ALA E 7 15.788 25.543 11.962 1.00 40.00 C +ATOM 33 C ALA E 7 16.411 24.694 13.075 1.00 40.00 C +ATOM 34 O ALA E 7 16.954 23.625 12.782 1.00 40.00 O +ATOM 35 CB ALA E 7 16.806 26.540 11.433 1.00 40.00 C +ATOM 36 N ALA E 8 16.327 25.168 14.343 1.00 40.00 N +ATOM 37 CA ALA E 8 16.846 24.459 15.515 1.00 40.00 C +ATOM 38 C ALA E 8 16.009 23.197 15.768 1.00 40.00 C +ATOM 39 O ALA E 8 16.568 22.097 15.858 1.00 40.00 O +ATOM 40 CB ALA E 8 16.833 25.368 16.742 1.00 40.00 C +ATOM 41 N ALA E 9 11.466 20.737 11.268 1.00 40.00 N +ATOM 42 CA ALA E 9 12.607 19.889 11.232 1.00 40.00 C +ATOM 43 C ALA E 9 12.924 19.328 12.523 1.00 40.00 C +ATOM 44 O ALA E 9 12.790 20.050 13.539 1.00 40.00 O +ATOM 45 CB ALA E 9 13.739 20.662 10.656 1.00 40.00 C +ATOM 46 N ALA E 10 13.495 18.150 12.482 1.00 40.00 N +ATOM 47 CA ALA E 10 14.007 17.595 13.654 1.00 40.00 C +ATOM 48 C ALA E 10 15.157 16.724 13.724 1.00 40.00 C +ATOM 49 O ALA E 10 15.159 16.000 14.620 1.00 40.00 O +ATOM 50 CB ALA E 10 12.870 16.878 14.366 1.00 40.00 C +ATOM 51 N ALA E 11 16.092 16.782 12.766 1.00 40.00 N +ATOM 52 CA ALA E 11 17.076 15.791 12.430 1.00 40.00 C +ATOM 53 C ALA E 11 16.462 14.506 11.790 1.00 40.00 C +ATOM 54 O ALA E 11 15.459 14.602 11.077 1.00 40.00 O +ATOM 55 CB ALA E 11 17.943 15.352 13.622 1.00 40.00 C +ATOM 56 N ALA E 12 17.191 13.458 11.773 1.00 40.00 N +ATOM 57 CA ALA E 12 16.985 12.246 11.074 1.00 40.00 C +ATOM 58 C ALA E 12 17.956 11.169 11.712 1.00 40.00 C +ATOM 59 O ALA E 12 18.839 10.657 11.173 1.00 40.00 O +ATOM 60 CB ALA E 12 17.278 12.440 9.655 1.00 40.00 C +ATOM 61 N ALA E 13 14.748 17.535 15.215 1.00 40.00 N +ATOM 62 CA ALA E 13 13.821 16.516 14.708 1.00 40.00 C +ATOM 63 C ALA E 13 14.530 15.563 13.752 1.00 40.00 C +ATOM 64 O ALA E 13 14.266 14.360 13.793 1.00 40.00 O +ATOM 65 CB ALA E 13 12.636 17.173 14.008 1.00 40.00 C +ATOM 66 N ALA E 14 15.437 16.112 12.903 1.00 40.00 N +ATOM 67 CA ALA E 14 16.246 15.367 11.939 1.00 40.00 C +ATOM 68 C ALA E 14 17.277 14.511 12.676 1.00 40.00 C +ATOM 69 O ALA E 14 17.512 13.363 12.286 1.00 40.00 O +ATOM 70 CB ALA E 14 16.942 16.329 10.986 1.00 40.00 C +ATOM 71 N ALA E 15 17.863 15.069 13.767 1.00 40.00 N +ATOM 72 CA ALA E 15 18.847 14.407 14.629 1.00 40.00 C +ATOM 73 C ALA E 15 18.213 13.257 15.427 1.00 40.00 C +ATOM 74 O ALA E 15 18.922 12.322 15.816 1.00 40.00 O +ATOM 75 CB ALA E 15 19.475 15.418 15.573 1.00 40.00 C +ATOM 76 N ALA E 16 16.879 13.325 15.652 1.00 40.00 N +ATOM 77 CA ALA E 16 16.099 12.317 16.370 1.00 40.00 C +ATOM 78 C ALA E 16 15.822 11.106 15.488 1.00 40.00 C +ATOM 79 O ALA E 16 15.658 10.000 15.999 1.00 40.00 O +ATOM 80 CB ALA E 16 14.790 12.918 16.852 1.00 40.00 C +TER +ENDMDL +""" +pdb_str_answer_AE= """\ +CRYST1 29.475 46.191 27.490 90.00 90.00 90.00 P 21 21 21 +HELIX 1 1 ALA E 1 ALA E 16 1 16 +ATOM 1 N ALA A 1 14.622 35.477 13.274 1.00 40.00 N +ATOM 2 CA ALA A 1 14.323 35.055 14.635 1.00 40.00 C +ATOM 3 C ALA A 1 13.442 33.808 14.656 1.00 40.00 C +ATOM 4 O ALA A 1 13.848 32.796 15.227 1.00 40.00 O +ATOM 5 CB ALA A 1 13.675 36.191 15.414 1.00 40.00 C +ATOM 6 N ALA A 2 12.256 33.870 14.012 1.00 40.00 N +ATOM 7 CA ALA A 2 11.288 32.768 13.916 1.00 40.00 C +ATOM 8 C ALA A 2 11.847 31.573 13.125 1.00 40.00 C +ATOM 9 O ALA A 2 11.553 30.422 13.462 1.00 40.00 O +ATOM 10 CB ALA A 2 10.000 33.267 13.276 1.00 40.00 C +ATOM 11 N ALA A 3 12.664 31.856 12.084 1.00 40.00 N +ATOM 12 CA ALA A 3 13.313 30.854 11.231 1.00 40.00 C +ATOM 13 C ALA A 3 14.391 30.082 11.994 1.00 40.00 C +ATOM 14 O ALA A 3 14.616 28.906 11.687 1.00 40.00 O +ATOM 15 CB ALA A 3 13.915 31.517 10.000 1.00 40.00 C +ATOM 16 N ALA A 4 15.063 30.744 12.976 1.00 40.00 N +ATOM 17 CA ALA A 4 16.089 30.116 13.822 1.00 40.00 C +ATOM 18 C ALA A 4 15.441 29.043 14.703 1.00 40.00 C +ATOM 19 O ALA A 4 15.888 27.897 14.671 1.00 40.00 O +ATOM 20 CB ALA A 4 16.785 31.160 14.683 1.00 40.00 C +ATOM 1 N ALA E 1 14.622 35.477 13.274 1.00 40.00 N +ATOM 2 CA ALA E 1 14.323 35.055 14.635 1.00 40.00 C +ATOM 3 C ALA E 1 13.442 33.808 14.656 1.00 40.00 C +ATOM 4 O ALA E 1 13.848 32.796 15.227 1.00 40.00 O +ATOM 5 CB ALA E 1 13.675 36.191 15.414 1.00 40.00 C +ATOM 6 N ALA E 2 12.256 33.870 14.012 1.00 40.00 N +ATOM 7 CA ALA E 2 11.288 32.768 13.916 1.00 40.00 C +ATOM 8 C ALA E 2 11.847 31.573 13.125 1.00 40.00 C +ATOM 9 O ALA E 2 11.553 30.422 13.462 1.00 40.00 O +ATOM 10 CB ALA E 2 10.000 33.267 13.276 1.00 40.00 C +ATOM 11 N ALA E 3 12.664 31.856 12.084 1.00 40.00 N +ATOM 12 CA ALA E 3 13.313 30.854 11.231 1.00 40.00 C +ATOM 13 C ALA E 3 14.391 30.082 11.994 1.00 40.00 C +ATOM 14 O ALA E 3 14.616 28.906 11.687 1.00 40.00 O +ATOM 15 CB ALA E 3 13.915 31.517 10.000 1.00 40.00 C +ATOM 16 N ALA E 4 15.063 30.744 12.976 1.00 40.00 N +ATOM 17 CA ALA E 4 16.089 30.116 13.822 1.00 40.00 C +ATOM 18 C ALA E 4 15.441 29.043 14.703 1.00 40.00 C +ATOM 19 O ALA E 4 15.888 27.897 14.671 1.00 40.00 O +ATOM 20 CB ALA E 4 16.785 31.160 14.683 1.00 40.00 C +ATOM 21 N ALA E 5 14.338 29.398 15.423 1.00 40.00 N +ATOM 22 CA ALA E 5 13.573 28.488 16.298 1.00 40.00 C +ATOM 23 C ALA E 5 13.042 27.288 15.513 1.00 40.00 C +ATOM 24 O ALA E 5 12.981 26.179 16.048 1.00 40.00 O +ATOM 25 CB ALA E 5 12.433 29.233 16.975 1.00 40.00 C +ATOM 26 N ALA E 6 12.715 27.518 14.221 1.00 40.00 N +ATOM 27 CA ALA E 6 12.258 26.514 13.260 1.00 40.00 C +ATOM 28 C ALA E 6 13.440 25.620 12.865 1.00 40.00 C +ATOM 29 O ALA E 6 13.361 24.405 13.060 1.00 40.00 O +ATOM 30 CB ALA E 6 11.664 27.193 12.032 1.00 40.00 C +ATOM 31 N ALA E 7 14.556 26.234 12.374 1.00 40.00 N +ATOM 32 CA ALA E 7 15.788 25.543 11.962 1.00 40.00 C +ATOM 33 C ALA E 7 16.411 24.694 13.075 1.00 40.00 C +ATOM 34 O ALA E 7 16.954 23.625 12.782 1.00 40.00 O +ATOM 35 CB ALA E 7 16.806 26.540 11.433 1.00 40.00 C +ATOM 36 N ALA E 8 16.327 25.168 14.343 1.00 40.00 N +ATOM 37 CA ALA E 8 16.846 24.459 15.515 1.00 40.00 C +ATOM 38 C ALA E 8 16.009 23.197 15.768 1.00 40.00 C +ATOM 39 O ALA E 8 16.568 22.097 15.858 1.00 40.00 O +ATOM 40 CB ALA E 8 16.833 25.368 16.742 1.00 40.00 C +ATOM 41 N ALA E 9 14.664 23.357 15.803 1.00 40.00 N +ATOM 42 CA ALA E 9 13.716 22.261 15.994 1.00 40.00 C +ATOM 43 C ALA E 9 13.754 21.279 14.822 1.00 40.00 C +ATOM 44 O ALA E 9 13.654 20.075 15.051 1.00 40.00 O +ATOM 45 CB ALA E 9 12.314 22.805 16.193 1.00 40.00 C +ATOM 46 N ALA E 10 13.942 21.791 13.578 1.00 40.00 N +ATOM 47 CA ALA E 10 14.063 20.985 12.357 1.00 40.00 C +ATOM 48 C ALA E 10 15.322 20.116 12.421 1.00 40.00 C +ATOM 49 O ALA E 10 15.235 18.910 12.169 1.00 40.00 O +ATOM 50 CB ALA E 10 14.105 21.881 11.130 1.00 40.00 C +ATOM 51 N ALA E 11 16.480 20.722 12.803 1.00 40.00 N +ATOM 52 CA ALA E 11 17.754 20.018 12.967 1.00 40.00 C +ATOM 53 C ALA E 11 17.631 18.976 14.089 1.00 40.00 C +ATOM 54 O ALA E 11 18.074 17.837 13.908 1.00 40.00 O +ATOM 55 CB ALA E 11 18.870 21.004 13.279 1.00 40.00 C +ATOM 56 N ALA E 12 16.972 19.356 15.217 1.00 40.00 N +ATOM 57 CA ALA E 12 16.721 18.483 16.371 1.00 40.00 C +ATOM 58 C ALA E 12 15.851 17.277 15.972 1.00 40.00 C +ATOM 59 O ALA E 12 16.201 16.140 16.310 1.00 40.00 O +ATOM 60 CB ALA E 12 16.052 19.269 17.490 1.00 40.00 C +ATOM 61 N ALA E 13 14.748 17.535 15.215 1.00 40.00 N +ATOM 62 CA ALA E 13 13.821 16.516 14.708 1.00 40.00 C +ATOM 63 C ALA E 13 14.530 15.563 13.752 1.00 40.00 C +ATOM 64 O ALA E 13 14.266 14.360 13.793 1.00 40.00 O +ATOM 65 CB ALA E 13 12.636 17.173 14.008 1.00 40.00 C +ATOM 66 N ALA E 14 15.437 16.112 12.903 1.00 40.00 N +ATOM 67 CA ALA E 14 16.246 15.367 11.939 1.00 40.00 C +ATOM 68 C ALA E 14 17.277 14.511 12.676 1.00 40.00 C +ATOM 69 O ALA E 14 17.512 13.363 12.286 1.00 40.00 O +ATOM 70 CB ALA E 14 16.942 16.329 10.986 1.00 40.00 C +ATOM 71 N ALA E 15 17.863 15.069 13.767 1.00 40.00 N +ATOM 72 CA ALA E 15 18.847 14.407 14.629 1.00 40.00 C +ATOM 73 C ALA E 15 18.213 13.257 15.427 1.00 40.00 C +ATOM 74 O ALA E 15 18.922 12.322 15.816 1.00 40.00 O +ATOM 75 CB ALA E 15 19.475 15.418 15.573 1.00 40.00 C +ATOM 76 N ALA E 16 16.879 13.325 15.652 1.00 40.00 N +ATOM 77 CA ALA E 16 16.099 12.317 16.370 1.00 40.00 C +ATOM 78 C ALA E 16 15.822 11.106 15.488 1.00 40.00 C +ATOM 79 O ALA E 16 15.658 10.000 15.999 1.00 40.00 O +ATOM 80 CB ALA E 16 14.790 12.918 16.852 1.00 40.00 C +TER +END +""" + + +pdb_str_answer_full = """\ +CRYST1 29.475 46.191 27.490 90.00 90.00 90.00 P 21 21 21 +HELIX 1 1 ALA E 1 ALA E 16 1 16 +ATOM 1 N ALA E 1 14.622 35.477 13.274 1.00 40.00 N +ATOM 2 CA ALA E 1 14.323 35.055 14.635 1.00 40.00 C +ATOM 3 C ALA E 1 13.442 33.808 14.656 1.00 40.00 C +ATOM 4 O ALA E 1 13.848 32.796 15.227 1.00 40.00 O +ATOM 5 CB ALA E 1 13.675 36.191 15.414 1.00 40.00 C +ATOM 6 N ALA E 2 12.256 33.870 14.012 1.00 40.00 N +ATOM 7 CA ALA E 2 11.288 32.768 13.916 1.00 40.00 C +ATOM 8 C ALA E 2 11.847 31.573 13.125 1.00 40.00 C +ATOM 9 O ALA E 2 11.553 30.422 13.462 1.00 40.00 O +ATOM 10 CB ALA E 2 10.000 33.267 13.276 1.00 40.00 C +ATOM 11 N ALA E 3 12.664 31.856 12.084 1.00 40.00 N +ATOM 12 CA ALA E 3 13.313 30.854 11.231 1.00 40.00 C +ATOM 13 C ALA E 3 14.391 30.082 11.994 1.00 40.00 C +ATOM 14 O ALA E 3 14.616 28.906 11.687 1.00 40.00 O +ATOM 15 CB ALA E 3 13.915 31.517 10.000 1.00 40.00 C +ATOM 16 N ALA E 4 15.063 30.744 12.976 1.00 40.00 N +ATOM 17 CA ALA E 4 16.089 30.116 13.822 1.00 40.00 C +ATOM 18 C ALA E 4 15.441 29.043 14.703 1.00 40.00 C +ATOM 19 O ALA E 4 15.888 27.897 14.671 1.00 40.00 O +ATOM 20 CB ALA E 4 16.785 31.160 14.683 1.00 40.00 C +ATOM 21 N ALA E 5 14.338 29.398 15.423 1.00 40.00 N +ATOM 22 CA ALA E 5 13.573 28.488 16.298 1.00 40.00 C +ATOM 23 C ALA E 5 13.042 27.288 15.513 1.00 40.00 C +ATOM 24 O ALA E 5 12.981 26.179 16.048 1.00 40.00 O +ATOM 25 CB ALA E 5 12.433 29.233 16.975 1.00 40.00 C +ATOM 26 N ALA E 6 12.715 27.518 14.221 1.00 40.00 N +ATOM 27 CA ALA E 6 12.258 26.514 13.260 1.00 40.00 C +ATOM 28 C ALA E 6 13.440 25.620 12.865 1.00 40.00 C +ATOM 29 O ALA E 6 13.361 24.405 13.060 1.00 40.00 O +ATOM 30 CB ALA E 6 11.664 27.193 12.032 1.00 40.00 C +ATOM 31 N ALA E 7 14.556 26.234 12.374 1.00 40.00 N +ATOM 32 CA ALA E 7 15.788 25.543 11.962 1.00 40.00 C +ATOM 33 C ALA E 7 16.411 24.694 13.075 1.00 40.00 C +ATOM 34 O ALA E 7 16.954 23.625 12.782 1.00 40.00 O +ATOM 35 CB ALA E 7 16.806 26.540 11.433 1.00 40.00 C +ATOM 36 N ALA E 8 16.327 25.168 14.343 1.00 40.00 N +ATOM 37 CA ALA E 8 16.846 24.459 15.515 1.00 40.00 C +ATOM 38 C ALA E 8 16.009 23.197 15.768 1.00 40.00 C +ATOM 39 O ALA E 8 16.568 22.097 15.858 1.00 40.00 O +ATOM 40 CB ALA E 8 16.833 25.368 16.742 1.00 40.00 C +ATOM 41 N ALA E 9 14.664 23.357 15.803 1.00 40.00 N +ATOM 42 CA ALA E 9 13.716 22.261 15.994 1.00 40.00 C +ATOM 43 C ALA E 9 13.754 21.279 14.822 1.00 40.00 C +ATOM 44 O ALA E 9 13.654 20.075 15.051 1.00 40.00 O +ATOM 45 CB ALA E 9 12.314 22.805 16.193 1.00 40.00 C +ATOM 46 N ALA E 10 13.942 21.791 13.578 1.00 40.00 N +ATOM 47 CA ALA E 10 14.063 20.985 12.357 1.00 40.00 C +ATOM 48 C ALA E 10 15.322 20.116 12.421 1.00 40.00 C +ATOM 49 O ALA E 10 15.235 18.910 12.169 1.00 40.00 O +ATOM 50 CB ALA E 10 14.105 21.881 11.130 1.00 40.00 C +ATOM 51 N ALA E 11 16.480 20.722 12.803 1.00 40.00 N +ATOM 52 CA ALA E 11 17.754 20.018 12.967 1.00 40.00 C +ATOM 53 C ALA E 11 17.631 18.976 14.089 1.00 40.00 C +ATOM 54 O ALA E 11 18.074 17.837 13.908 1.00 40.00 O +ATOM 55 CB ALA E 11 18.870 21.004 13.279 1.00 40.00 C +ATOM 56 N ALA E 12 16.972 19.356 15.217 1.00 40.00 N +ATOM 57 CA ALA E 12 16.721 18.483 16.371 1.00 40.00 C +ATOM 58 C ALA E 12 15.851 17.277 15.972 1.00 40.00 C +ATOM 59 O ALA E 12 16.201 16.140 16.310 1.00 40.00 O +ATOM 60 CB ALA E 12 16.052 19.269 17.490 1.00 40.00 C +ATOM 61 N ALA E 13 14.748 17.535 15.215 1.00 40.00 N +ATOM 62 CA ALA E 13 13.821 16.516 14.708 1.00 40.00 C +ATOM 63 C ALA E 13 14.530 15.563 13.752 1.00 40.00 C +ATOM 64 O ALA E 13 14.266 14.360 13.793 1.00 40.00 O +ATOM 65 CB ALA E 13 12.636 17.173 14.008 1.00 40.00 C +ATOM 66 N ALA E 14 15.437 16.112 12.903 1.00 40.00 N +ATOM 67 CA ALA E 14 16.246 15.367 11.939 1.00 40.00 C +ATOM 68 C ALA E 14 17.277 14.511 12.676 1.00 40.00 C +ATOM 69 O ALA E 14 17.512 13.363 12.286 1.00 40.00 O +ATOM 70 CB ALA E 14 16.942 16.329 10.986 1.00 40.00 C +ATOM 71 N ALA E 15 17.863 15.069 13.767 1.00 40.00 N +ATOM 72 CA ALA E 15 18.847 14.407 14.629 1.00 40.00 C +ATOM 73 C ALA E 15 18.213 13.257 15.427 1.00 40.00 C +ATOM 74 O ALA E 15 18.922 12.322 15.816 1.00 40.00 O +ATOM 75 CB ALA E 15 19.475 15.418 15.573 1.00 40.00 C +ATOM 76 N ALA E 16 16.879 13.325 15.652 1.00 40.00 N +ATOM 77 CA ALA E 16 16.099 12.317 16.370 1.00 40.00 C +ATOM 78 C ALA E 16 15.822 11.106 15.488 1.00 40.00 C +ATOM 79 O ALA E 16 15.658 10.000 15.999 1.00 40.00 O +ATOM 80 CB ALA E 16 14.790 12.918 16.852 1.00 40.00 C +TER +END +""" + +pdb_str_answer = """\ +CRYST1 29.475 46.191 27.490 90.00 90.00 90.00 P 21 21 21 +HELIX 1 1 ALA E 1 ALA E 16 1 16 +ATOM 2 CA ALA E 1 14.323 35.055 14.635 1.00 40.00 C +ATOM 7 CA ALA E 2 11.288 32.768 13.916 1.00 40.00 C +ATOM 12 CA ALA E 3 13.313 30.854 11.231 1.00 40.00 C +ATOM 17 CA ALA E 4 16.089 30.116 13.822 1.00 40.00 C +ATOM 22 CA ALA E 5 13.573 28.488 16.298 1.00 40.00 C +ATOM 27 CA ALA E 6 12.258 26.514 13.260 1.00 40.00 C +ATOM 32 CA ALA E 7 15.788 25.543 11.962 1.00 40.00 C +ATOM 37 CA ALA E 8 16.846 24.459 15.515 1.00 40.00 C +ATOM 42 CA ALA E 9 13.716 22.261 15.994 1.00 40.00 C +ATOM 47 CA ALA E 10 14.063 20.985 12.357 1.00 40.00 C +ATOM 52 CA ALA E 11 17.754 20.018 12.967 1.00 40.00 C +ATOM 57 CA ALA E 12 16.721 18.483 16.371 1.00 40.00 C +ATOM 62 CA ALA E 13 13.821 16.516 14.708 1.00 40.00 C +ATOM 67 CA ALA E 14 16.246 15.367 11.939 1.00 40.00 C +ATOM 72 CA ALA E 15 18.847 14.407 14.629 1.00 40.00 C +ATOM 77 CA ALA E 16 16.099 12.317 16.370 1.00 40.00 C +TER +END +""" + +pdb_str_poor = """\ +CRYST1 29.475 46.191 27.490 90.00 90.00 90.00 P 21 21 21 +ATOM 2 CA ALA E 1 17.992 35.348 7.004 1.00 40.00 C +ATOM 7 CA ALA E 2 15.254 35.581 9.495 1.00 40.00 C +ATOM 12 CA ALA E 3 15.746 33.569 12.729 1.00 40.00 C +ATOM 17 CA ALA E 4 15.810 29.953 13.900 1.00 40.00 C +ATOM 22 CA ALA E 5 12.803 27.643 13.582 1.00 40.00 C +ATOM 27 CA ALA E 6 11.579 27.271 9.948 1.00 40.00 C +ATOM 32 CA ALA E 7 10.223 23.915 8.805 1.00 40.00 C +ATOM 37 CA ALA E 8 9.210 21.425 11.476 1.00 40.00 C +ATOM 42 CA ALA E 9 12.607 19.889 11.232 1.00 40.00 C +ATOM 47 CA ALA E 10 14.007 17.595 13.654 1.00 40.00 C +ATOM 52 CA ALA E 11 17.076 15.791 12.430 1.00 40.00 C +ATOM 57 CA ALA E 12 16.985 12.246 11.074 1.00 40.00 C +ATOM 62 CA ALA E 13 18.559 9.862 13.648 1.00 40.00 C +ATOM 67 CA ALA E 14 16.666 7.551 16.066 1.00 40.00 C +ATOM 72 CA ALA E 15 13.517 9.710 15.635 1.00 40.00 C +ATOM 77 CA ALA E 16 11.279 6.863 16.560 1.00 40.00 C +TER +""" + +pdb_str_poor_full = """\ +CRYST1 29.475 46.191 27.490 90.00 90.00 90.00 P 21 21 21 +ATOM 1 N ALA E 1 17.517 34.071 6.538 1.00 40.00 N +ATOM 2 CA ALA E 1 17.992 35.348 7.004 1.00 40.00 C +ATOM 3 C ALA E 1 16.863 35.986 7.792 1.00 40.00 C +ATOM 4 O ALA E 1 16.713 37.242 7.909 1.00 40.00 O +ATOM 5 CB ALA E 1 18.477 36.116 5.812 1.00 40.00 C +ATOM 6 N ALA E 2 16.080 35.113 8.348 1.00 40.00 N +ATOM 7 CA ALA E 2 15.254 35.581 9.495 1.00 40.00 C +ATOM 8 C ALA E 2 15.628 35.262 10.863 1.00 40.00 C +ATOM 9 O ALA E 2 16.066 36.143 11.629 1.00 40.00 O +ATOM 10 CB ALA E 2 13.821 35.144 9.297 1.00 40.00 C +ATOM 11 N ALA E 3 15.670 34.035 11.221 1.00 40.00 N +ATOM 12 CA ALA E 3 15.746 33.569 12.729 1.00 40.00 C +ATOM 13 C ALA E 3 16.380 32.197 13.043 1.00 40.00 C +ATOM 14 O ALA E 3 17.557 32.017 13.009 1.00 40.00 O +ATOM 15 CB ALA E 3 14.390 33.574 13.297 1.00 40.00 C +ATOM 16 N ALA E 4 15.437 31.334 13.516 1.00 40.00 N +ATOM 17 CA ALA E 4 15.810 29.953 13.900 1.00 40.00 C +ATOM 18 C ALA E 4 14.876 28.948 13.219 1.00 40.00 C +ATOM 19 O ALA E 4 15.088 28.561 12.135 1.00 40.00 O +ATOM 20 CB ALA E 4 15.807 29.747 15.562 1.00 40.00 C +ATOM 21 N ALA E 5 13.827 28.582 13.930 1.00 40.00 N +ATOM 22 CA ALA E 5 12.803 27.643 13.582 1.00 40.00 C +ATOM 23 C ALA E 5 11.925 27.972 12.295 1.00 40.00 C +ATOM 24 O ALA E 5 11.311 29.016 12.217 1.00 40.00 O +ATOM 25 CB ALA E 5 11.884 27.496 14.800 1.00 40.00 C +ATOM 26 N ALA E 6 11.824 27.002 11.326 1.00 40.00 N +ATOM 27 CA ALA E 6 11.579 27.271 9.948 1.00 40.00 C +ATOM 28 C ALA E 6 10.688 26.172 9.315 1.00 40.00 C +ATOM 29 O ALA E 6 9.810 26.435 8.479 1.00 40.00 O +ATOM 30 CB ALA E 6 12.892 27.434 9.163 1.00 40.00 C +ATOM 31 N ALA E 7 10.985 24.936 9.568 1.00 40.00 N +ATOM 32 CA ALA E 7 10.223 23.915 8.805 1.00 40.00 C +ATOM 33 C ALA E 7 9.182 23.205 9.603 1.00 40.00 C +ATOM 34 O ALA E 7 7.945 23.417 9.434 1.00 40.00 O +ATOM 35 CB ALA E 7 11.183 22.804 8.200 1.00 40.00 C +ATOM 36 N ALA E 8 9.745 22.435 10.542 1.00 40.00 N +ATOM 37 CA ALA E 8 9.210 21.425 11.476 1.00 40.00 C +ATOM 38 C ALA E 8 10.256 20.419 11.733 1.00 40.00 C +ATOM 39 O ALA E 8 9.992 19.490 12.460 1.00 40.00 O +ATOM 40 CB ALA E 8 7.965 20.817 10.947 1.00 40.00 C +ATOM 41 N ALA E 9 11.466 20.737 11.268 1.00 40.00 N +ATOM 42 CA ALA E 9 12.607 19.889 11.232 1.00 40.00 C +ATOM 43 C ALA E 9 12.924 19.328 12.523 1.00 40.00 C +ATOM 44 O ALA E 9 12.790 20.050 13.539 1.00 40.00 O +ATOM 45 CB ALA E 9 13.739 20.662 10.656 1.00 40.00 C +ATOM 46 N ALA E 10 13.495 18.150 12.482 1.00 40.00 N +ATOM 47 CA ALA E 10 14.007 17.595 13.654 1.00 40.00 C +ATOM 48 C ALA E 10 15.157 16.724 13.724 1.00 40.00 C +ATOM 49 O ALA E 10 15.159 16.000 14.620 1.00 40.00 O +ATOM 50 CB ALA E 10 12.870 16.878 14.366 1.00 40.00 C +ATOM 51 N ALA E 11 16.092 16.782 12.766 1.00 40.00 N +ATOM 52 CA ALA E 11 17.076 15.791 12.430 1.00 40.00 C +ATOM 53 C ALA E 11 16.462 14.506 11.790 1.00 40.00 C +ATOM 54 O ALA E 11 15.459 14.602 11.077 1.00 40.00 O +ATOM 55 CB ALA E 11 17.943 15.352 13.622 1.00 40.00 C +ATOM 56 N ALA E 12 17.191 13.458 11.773 1.00 40.00 N +ATOM 57 CA ALA E 12 16.985 12.246 11.074 1.00 40.00 C +ATOM 58 C ALA E 12 17.956 11.169 11.712 1.00 40.00 C +ATOM 59 O ALA E 12 18.839 10.657 11.173 1.00 40.00 O +ATOM 60 CB ALA E 12 17.278 12.440 9.655 1.00 40.00 C +ATOM 61 N ALA E 13 17.693 10.781 12.936 1.00 40.00 N +ATOM 62 CA ALA E 13 18.559 9.862 13.648 1.00 40.00 C +ATOM 63 C ALA E 13 17.678 8.677 14.105 1.00 40.00 C +ATOM 64 O ALA E 13 16.810 8.236 13.332 1.00 40.00 O +ATOM 65 CB ALA E 13 19.221 10.551 14.826 1.00 40.00 C +ATOM 66 N ALA E 14 17.647 8.453 15.439 1.00 40.00 N +ATOM 67 CA ALA E 14 16.666 7.551 16.066 1.00 40.00 C +ATOM 68 C ALA E 14 15.298 8.147 16.400 1.00 40.00 C +ATOM 69 O ALA E 14 14.633 7.785 17.376 1.00 40.00 O +ATOM 70 CB ALA E 14 17.224 7.034 17.308 1.00 40.00 C +ATOM 71 N ALA E 15 14.855 9.000 15.485 1.00 40.00 N +ATOM 72 CA ALA E 15 13.517 9.710 15.635 1.00 40.00 C +ATOM 73 C ALA E 15 12.304 8.858 15.586 1.00 40.00 C +ATOM 74 O ALA E 15 11.625 8.812 14.564 1.00 40.00 O +ATOM 75 CB ALA E 15 13.302 10.842 14.526 1.00 40.00 C +ATOM 76 N ALA E 16 12.014 8.140 16.649 1.00 40.00 N +ATOM 77 CA ALA E 16 11.279 6.863 16.560 1.00 40.00 C +ATOM 78 C ALA E 16 10.003 6.986 17.409 1.00 40.00 C +ATOM 79 O ALA E 16 9.883 8.020 18.086 1.00 40.00 O +ATOM 80 CB ALA E 16 12.188 5.653 16.999 1.00 40.00 C +TER +""" + +convert_pdb_to_cif_for_pdb_str(locals()) +def tst_01(): + print("\nTesting merge_model\n") + prefix='tst_01' + # Full good answer model + pdb_file_name_answer_full = "%s_answer_full.cif"%prefix + pdb_inp = iotbx.pdb.input(source_info=None, lines = pdb_str_answer_AE) + ph_answer_full = pdb_inp.construct_hierarchy() + info = ph_answer_full.pdb_or_mmcif_string_info( + target_filename = "%s_answer.cif"%prefix, + crystal_symmetry = pdb_inp.crystal_symmetry(), + write_file = True) + ph_answer_full.atoms().reset_i_seq() + xrs_answer_full = pdb_inp.xray_structure_simple() + + # Two models we want to merge + pdb_file_name_two_models = "%s_poor_two_models.cif"%prefix + pdb_inp = iotbx.pdb.input(source_info=None, lines = pdb_str_two_models) + full_two_models = pdb_inp.construct_hierarchy() + info = full_two_models.pdb_or_mmcif_string_info( + target_filename = "%s_two_models.cif"%prefix, + crystal_symmetry = pdb_inp.crystal_symmetry(), + write_file = True) + xrs_two_models_full = pdb_inp.xray_structure_simple() + + # Compute target map + fc = xrs_answer_full.structure_factors(d_min=3.5).f_calc() + fft_map = fc.fft_map(resolution_factor = 0.25) + fft_map.apply_sigma_scaling() + target_map_data = fft_map.real_map_unpadded() + ccp4_map(crystal_symmetry=fc.crystal_symmetry(), + file_name="%s_map.ccp4" %prefix, + map_data=target_map_data) + # Output map coefficients + mtz_dataset = fc.as_mtz_dataset(column_root_label="FC") + mtz_object = mtz_dataset.mtz_object() + mtz_object.write(file_name = "%s_map.mtz"%prefix) + + from mmtbx.building.merge_models import run as merge_models + hierarchy, pdb_out=merge_models( + map_data=target_map_data, + pdb_inp=pdb_inp, + dist_max=100, + verbose=True) + + pdb_inp=hierarchy.as_pdb_input(crystal_symmetry=fc.crystal_symmetry()) + xrs=pdb_inp.xray_structure_simple() + refined_ph=pdb_inp.construct_hierarchy() + info = refined_ph.pdb_or_mmcif_string_info( + target_filename = "%s_refined.cif"%prefix, + crystal_symmetry = pdb_inp.crystal_symmetry(), + write_file = True) + rmsd=xrs.sites_cart().rms_difference(xrs_answer_full.sites_cart()) + print("RMSD from TARGET allowing any CROSSOVERS: %8.2f " %(rmsd)) + return rmsd + + +def tst_02(args,prefix=None): + + if prefix is None: + prefix='tst_02' + # Full good answer model + pdb_file_name_answer_full = "%s_answer_full.cif"%prefix + pdb_inp = iotbx.pdb.input(source_info=None, lines = pdb_str_answer_full) + ph_answer_full = pdb_inp.construct_hierarchy() + info = ph_answer_full.pdb_or_mmcif_string_info( + target_filename = "%s_answer_full.cif"%prefix, + crystal_symmetry = pdb_inp.crystal_symmetry(), + write_file = True) + ph_answer_full.atoms().reset_i_seq() + xrs_answer_full = pdb_inp.xray_structure_simple() + + # Poor full model that we want to refine so it matches the answer + pdb_file_name_poor = "%s_poor.cif"%prefix + pdb_inp = iotbx.pdb.input(source_info=None, lines = pdb_str_poor_full) + ph_poor_full = pdb_inp.construct_hierarchy() + info = ph_poor_full.pdb_or_mmcif_string_info( + target_filename = "%s_poor.cif"%prefix, + crystal_symmetry = pdb_inp.crystal_symmetry(), + write_file = True) + ph_poor_full.atoms().reset_i_seq() + xrs_poor_full = pdb_inp.xray_structure_simple() + + # Compute target map + fc = xrs_answer_full.structure_factors(d_min=3.5).f_calc() + fft_map = fc.fft_map(resolution_factor = 0.25) + fft_map.apply_sigma_scaling() + target_map_data = fft_map.real_map_unpadded() + ccp4_map(crystal_symmetry=fc.crystal_symmetry(), + file_name="%s_map.ccp4" %prefix, + map_data=target_map_data) + # Output map coefficients + mtz_dataset = fc.as_mtz_dataset(column_root_label="FC") + mtz_object = mtz_dataset.mtz_object() + mtz_object.write(file_name = "%s_map.mtz"%prefix) + + hierarchy,multiple_model_hierarchy=run( + args=args,map_data=target_map_data, + crystal_symmetry=fc.crystal_symmetry(), + pdb_string=pdb_str_poor_full) + + pdb_inp=hierarchy.as_pdb_input(crystal_symmetry=fc.crystal_symmetry()) + xrs_refined=pdb_inp.xray_structure_simple() + info = hierarchy.pdb_or_mmcif_string_info( + target_filename = "%s_refined.cif"%prefix, + crystal_symmetry = pdb_inp.crystal_symmetry(), + write_file = True) + info = multiple_model_hierarchy.pdb_or_mmcif_string_info( + target_filename = "%s_refined_all_states.cif"%prefix, + crystal_symmetry = pdb_inp.crystal_symmetry(), + write_file = True) + rmsd=xrs_refined.sites_cart().rms_difference(xrs_answer_full.sites_cart()) + print("RMSD from TARGET for FULL-model refinement: %8.2f " %(rmsd)) + return rmsd + +if (__name__ == "__main__"): + t0=time.time() + print("\nRunning merge_models alone") + rmsd=tst_01() + print("Time: %6.4f"%(time.time()-t0)) + print("OK") + + args=["number_of_build_cycles=2","number_of_macro_cycles=1","number_of_trials=2","random_seed=77141"] + t0=time.time() + print("Running standard minimize_chain") + extra_args=['merge_models=False','pdb_out=std.cif'] + rmsd=tst_02(args+extra_args,prefix='tst_02') + print("Time: %6.4f"%(time.time()-t0)) + print("OK") + print("RMSD %7.2f "%rmsd) + + t0=time.time() + print("\nRunning standard minimize_chain plus merge_models") + extra_args=['merge_models=True','pdb_out=merged.cif'] + rmsd=tst_02(args+extra_args,prefix='tst_03') + print("Time: %6.4f"%(time.time()-t0)) + print("OK") + print("RMSD %7.2f "%rmsd) diff --git a/mmtbx/regression/tst_pdbtools.py b/mmtbx/regression/tst_pdbtools.py index 8ea3b69b88..94620b281c 100644 --- a/mmtbx/regression/tst_pdbtools.py +++ b/mmtbx/regression/tst_pdbtools.py @@ -1313,6 +1313,7 @@ def exercise(args): exercise_mmcif_support() exercise_segid_manipulations() exercise_result_is_empty() + print("OK") if (__name__ == "__main__"): exercise(sys.argv[1:]) diff --git a/mmtbx/regression/tst_process_predicted_model_cif.py b/mmtbx/regression/tst_process_predicted_model_cif.py new file mode 100644 index 0000000000..c96ef06edf --- /dev/null +++ b/mmtbx/regression/tst_process_predicted_model_cif.py @@ -0,0 +1,299 @@ +from __future__ import division, print_function +import sys, os, time + +from libtbx.test_utils import approx_equal +import iotbx.phil + +import libtbx.load_env +data_dir = libtbx.env.under_dist( + module_name="mmtbx", + path=os.path.join("regression","pdbs"), + test=os.path.isdir) + +pae_data_dir = libtbx.env.under_dist( + module_name="mmtbx", + path="regression", + test=os.path.isdir) + +from iotbx.data_manager import DataManager +from mmtbx.process_predicted_model import split_model_into_compact_units, \ + get_cutoff_b_value, \ + get_b_values_from_plddt, get_rmsd_from_plddt, \ + process_predicted_model, master_phil_str, get_plddt_from_b + +from mmtbx.domains_from_pae import parse_pae_file +master_phil = iotbx.phil.parse(master_phil_str) +params = master_phil.extract() + +# NOTE: Slightly different results from .pdb version because of rounding +# carried out (2 digits for b_value) when pdb hierarchy is converted +# to pdb_input through # formatted string, but mmcif string +# (required by the long chain name +# used in this test) rounds to 5 digits. Happens to make a difference +# in this test. + +model_file=os.path.join(data_dir,'fibronectin_af_ca_1358_1537.cif') +pae_model_file=os.path.join(data_dir,'pae_model.cif') +pae_file=os.path.join(pae_data_dir,'pae.json') + +def tst_01(log = sys.stdout): + + + # Check calculations of conversion between rmsd, plddt , and B values + print("\nChecking conversions between rmsd, plddt and B-values", file = log) + for maximum_rmsd, minimum_plddt, target_b in [ + (1.5, None, 59.2175263686), + (None,0.7,59.2175263686), + (1.5,0.7,59.2175263686), + (1.0, None, 26.3189006083), + (None,0.5,293.306328196),]: + print() + cutoff_b = get_cutoff_b_value( + maximum_rmsd, + minimum_plddt, + log = log) + print("maximum_rmsd: %s min plddt %s Cutoff B: %.2f" %( + maximum_rmsd, minimum_plddt, + cutoff_b), file = log) + assert approx_equal(cutoff_b, target_b) + + + # Read in alphafold model and get pLDDT from B-value field + print("\nReading in alphafold model with plddt values in B-value field", + file = log) + + dm = DataManager() + dm.set_overwrite(True) + m = dm.get_model(model_file) + pae_m = dm.get_model(pae_model_file) + pae_matrix = parse_pae_file(pae_file) + + plddt_values = m.get_hierarchy().atoms().extract_b().deep_copy() + print("\npLDDT mean:",plddt_values.min_max_mean().mean) + assert approx_equal(plddt_values.min_max_mean().mean, 82.5931111111) + + # Multiply plddt_values by 0.01 (fractional) + fractional_plddt = plddt_values * 0.01 + + # Convert plddt to b + b_values = get_b_values_from_plddt(plddt_values) + print("B-value mean:",b_values.min_max_mean().mean) + assert approx_equal(b_values.min_max_mean().mean, 24.7254093338) + + # Convert b to plddt + plddt = get_plddt_from_b(b_values) + assert approx_equal(plddt,fractional_plddt) + plddt = get_plddt_from_b(b_values, input_plddt_is_fractional=False) + assert approx_equal(plddt,plddt_values) + + # Convert plddt to rmsd + rmsd_values = get_rmsd_from_plddt(plddt_values) + print("RMSD mean:",rmsd_values.min_max_mean().mean) + assert approx_equal(rmsd_values.min_max_mean().mean, 0.93559254135) + + # use process_predicted_model to convert plddt or rmsd to B return with + # mark_atoms_to_ignore_with_occ_zero + + print("\nConverting plddt to B values and using mark_atoms_to_ignore_with_occ_zero", file = log) + params.process_predicted_model.maximum_fraction_close = 0.5 + params.process_predicted_model.b_value_field_is = 'plddt' + params.process_predicted_model.remove_low_confidence_residues = True + params.process_predicted_model.maximum_rmsd = 1.5 + params.process_predicted_model.split_model_by_compact_regions = True + params.process_predicted_model.maximum_domains = 3 + + model_info = process_predicted_model(m, params, mark_atoms_to_keep_with_occ_one= True) + models = model_info.model_list + for mm,vrms,target_vrms,n1,n2 in zip(models,model_info.vrms_list,[1.1506528458663525,1.1506528458663525],[85,87],[87,85]): + model_occ_values = mm.get_hierarchy().atoms().extract_occ() + assert model_occ_values.count(1) == n1 + assert model_occ_values.count(0) == n2 + assert approx_equal(vrms, target_vrms, eps=0.01) + + # use process_predicted_model to convert plddt or rmsd to B + + print("\nConverting plddt to B values", file = log) + params.process_predicted_model.maximum_fraction_close = 0.5 + params.process_predicted_model.b_value_field_is = 'plddt' + params.process_predicted_model.remove_low_confidence_residues = False + params.process_predicted_model.split_model_by_compact_regions = False + params.process_predicted_model.input_plddt_is_fractional = None + + model_info = process_predicted_model(m, params) + model = model_info.model + model_b_values = model.get_hierarchy().atoms().extract_b() + assert approx_equal(b_values, model_b_values, eps = 0.02) # come back rounded + + + print("\nConverting fractional plddt to B values", file = log) + ph = model.get_hierarchy().deep_copy() + ph.atoms().set_b(fractional_plddt) + test_model = model.as_map_model_manager().model_from_hierarchy(ph, + return_as_model = True) + params.process_predicted_model.maximum_fraction_close = 0.5 + params.process_predicted_model.b_value_field_is = 'plddt' + params.process_predicted_model.remove_low_confidence_residues = False + params.process_predicted_model.split_model_by_compact_regions = False + params.process_predicted_model.input_plddt_is_fractional = None + model_info = process_predicted_model(test_model, params) + model = model_info.model + model_b_values = model.get_hierarchy().atoms().extract_b() + assert approx_equal(b_values, model_b_values, eps = 3) # come back very rounded + + ph = model.get_hierarchy().deep_copy() + ph.atoms().set_b(rmsd_values) + test_model = model.as_map_model_manager().model_from_hierarchy(ph, + return_as_model = True) + + print("\nConverting rmsd to B values", file = log) + params.process_predicted_model.maximum_fraction_close = 0.5 + params.process_predicted_model.b_value_field_is = 'rmsd' + params.process_predicted_model.remove_low_confidence_residues = False + params.process_predicted_model.split_model_by_compact_regions = False + params.process_predicted_model.input_plddt_is_fractional = None + model_info = process_predicted_model(test_model, params) + model = model_info.model + model_b_values = model.get_hierarchy().atoms().extract_b() + assert approx_equal(b_values, model_b_values, eps = 0.5) # come back rounded + + print("B-values > 59: %s of %s" %( + (model_b_values > 59).count(True), model_b_values.size()), file = log) + + print("\nConverting rmsd to B values and selecting rmsd < 1.5", file = log) + params.process_predicted_model.maximum_fraction_close = 0.5 + params.process_predicted_model.b_value_field_is = 'rmsd' + params.process_predicted_model.remove_low_confidence_residues = True + params.process_predicted_model.maximum_rmsd = 1.5 + params.process_predicted_model.split_model_by_compact_regions = False + params.process_predicted_model.input_plddt_is_fractional = None + + model_info = process_predicted_model(test_model, params) + model = model_info.model + print("Residues before: %s After: %s " %( + test_model.get_hierarchy().overall_counts().n_residues, + model.get_hierarchy().overall_counts().n_residues,), file = log) + + # Check splitting model into domains + print("\nSplitting model into domains", file = log) + model_info = split_model_into_compact_units(model, + adjust_domain_size = False, + maximum_fraction_close = 0.5, log = log) + + chainid_list = model_info.chainid_list + print("Segments found: %s" %(" ".join(chainid_list)), file = log) + assert len(chainid_list) == 1, len(chainid_list) + + # Check processing and splitting model into domains, adjusting domain size automatically + print("\nProcessing and splitting model into domains", file = log) + + params.process_predicted_model.maximum_fraction_close = 0.5 + params.process_predicted_model.b_value_field_is = 'plddt' + params.process_predicted_model.remove_low_confidence_residues = True + params.process_predicted_model.maximum_rmsd = 1.5 + params.process_predicted_model.split_model_by_compact_regions = True + params.process_predicted_model.maximum_domains = 3 + params.process_predicted_model.adjust_domain_size = True + model_info = process_predicted_model(m, params, log = log) + + chainid_list = model_info.chainid_list + print("Segments found: %s" %(" ".join(chainid_list)), file = log) + assert len(chainid_list) == 2 + + + mmm = model_info.model.as_map_model_manager() + mmm.write_model('model_with_groupings.cif', format = 'cif') + residue_count = [] + expected_residue_count = [85, 87] + for chainid in chainid_list: + selection_string = "chain %s" %(chainid) + ph = model_info.model.get_hierarchy() + asc1 = ph.atom_selection_cache() + sel = asc1.selection(selection_string) + m1 = model_info.model.select(sel) + n = m1.get_hierarchy().overall_counts().n_residues + print("Residues in %s: %s" %( + selection_string, n), + file = log) + residue_count.append(n) + assert expected_residue_count == residue_count + + # Check processing and splitting model into domains + print("\nProcessing and splitting model into domains without adjusting domain size", file = log) + + params.process_predicted_model.maximum_fraction_close = 0.5 + params.process_predicted_model.b_value_field_is = 'plddt' + params.process_predicted_model.remove_low_confidence_residues = True + params.process_predicted_model.maximum_rmsd = 1.5 + params.process_predicted_model.split_model_by_compact_regions = True + params.process_predicted_model.maximum_domains = 3 + params.process_predicted_model.adjust_domain_size = False + model_info = process_predicted_model(m, params, log = log) + + chainid_list = model_info.chainid_list + print("Segments found: %s" %(" ".join(chainid_list)), file = log) + assert len(chainid_list) == 1 + + + mmm = model_info.model.as_map_model_manager() + mmm.write_model('model_with_groupings.cif',format = 'cif') + residue_count = [] + expected_residue_count = [172] + for chainid in chainid_list: + selection_string = "chain %s" %(chainid) + ph = model_info.model.get_hierarchy() + asc1 = ph.atom_selection_cache() + sel = asc1.selection(selection_string) + m1 = model_info.model.select(sel) + n = m1.get_hierarchy().overall_counts().n_residues + print("Residues in %s: %s" %( + selection_string, n), + file = log) + residue_count.append(n) + assert expected_residue_count == residue_count + + # Now process and use pae model and pae model file + print("\nProcessing and splitting model into domains with pae", file = log) + + + params.process_predicted_model.maximum_fraction_close = 0.5 + params.process_predicted_model.b_value_field_is = 'plddt' + params.process_predicted_model.remove_low_confidence_residues = True + params.process_predicted_model.maximum_rmsd = 0.7 + params.process_predicted_model.split_model_by_compact_regions = True + params.process_predicted_model.maximum_domains = 3 + params.process_predicted_model.pae_power= 2 + model_info = process_predicted_model(pae_m, params, pae_matrix = pae_matrix, + log = log) + +def tst_02(log = sys.stdout): + + + # Split into domains with chunks + print("\nSplitting into domains with chunks", + file = log) + + dm = DataManager() + dm.set_overwrite(True) + model = dm.get_model(model_file) + model.add_crystal_symmetry_if_necessary() + + # Check splitting model into domains + print("\nSplitting model into domains", file = log) + model_info = split_model_into_compact_units(model, + break_into_chunks_if_length_is = model.overall_counts().n_residues, + chunk_size = 70, + overlap_size = 50, + adjust_domain_size = True, + maximum_fraction_close = 0.5, log = log) + + chainid_list = model_info.chainid_list + print("Segments found: %s" %(" ".join(chainid_list)), file = log) + assert len(chainid_list) == 2 + +if __name__ == "__main__": + + t0 = time.time() + tst_01() + tst_02() + print ("Time:", time.time()-t0) + print ("OK") diff --git a/mmtbx/regression/tst_regularize_from_pdb_cif.py b/mmtbx/regression/tst_regularize_from_pdb_cif.py new file mode 100644 index 0000000000..bef18e3249 --- /dev/null +++ b/mmtbx/regression/tst_regularize_from_pdb_cif.py @@ -0,0 +1,100 @@ +from __future__ import absolute_import, division, print_function + +from libtbx.utils import null_out +from six.moves import cStringIO as StringIO +from mmtbx.secondary_structure.regularize_from_pdb import \ + replace_with_segments_from_pdb + +def remove_blank(text): + return text.replace(" ","").replace("\n","") + +pdb_str_1=""" +ATOM 1 CA GLY U 111 6.802 13.378 -2.270 1.00 52.86 C +ATOM 2 CA GLY U 112 4.244 15.964 -0.444 1.00 52.86 C +ATOM 3 CA GLY U 113 1.213 15.704 -1.022 1.00 52.86 C +ATOM 4 CA GLY U 114 -0.519 14.243 -3.109 1.00 52.86 C +ATOM 5 CA GLY U 115 -2.874 13.497 -4.987 1.00 52.86 C +ATOM 6 CA GLY U 116 -0.713 13.888 -7.199 1.00 52.86 C +ATOM 7 CA GLY U 117 1.212 11.376 -6.966 1.00 52.86 C +ATOM 8 CA GLY U 118 -1.819 10.012 -8.645 1.00 52.86 C +ATOM 9 CA GLY U 119 0.375 9.344 -10.927 1.00 52.86 C +ATOM 10 CA GLY U 120 2.317 5.692 -10.865 1.00 52.86 C +ATOM 11 CA GLY U 121 4.732 3.967 -11.502 1.00 52.86 C +ATOM 12 CA GLY U 122 8.166 5.698 -10.793 1.00 42.55 C +ATOM 13 CA GLY U 123 6.434 6.101 -6.390 1.00 52.86 C +ATOM 14 CA GLY U 124 9.700 6.022 -5.333 1.00 52.86 C +ATOM 15 CA GLY U 125 8.739 8.281 -3.579 1.00 52.86 C +ATOM 16 CA GLY U 126 6.548 8.326 -1.298 1.00 52.86 C +ATOM 17 CA GLY U 127 4.110 9.670 -0.100 1.00 52.86 C +ATOM 18 CA GLY U 128 3.406 11.974 2.546 1.00 52.86 C +ATOM 19 CA GLY U 129 0.747 12.768 3.800 1.00 52.86 C +ATOM 20 CA GLY U 130 -1.068 13.851 6.552 1.00 52.86 C +ATOM 21 CA GLY U 131 -3.058 16.387 5.476 1.00 52.86 C +ATOM 22 CA GLY U 132 -4.637 14.251 3.493 1.00 52.86 C +ATOM 23 CA GLY U 133 -4.850 12.995 0.227 1.00 52.86 C +ATOM 24 CA GLY U 134 -7.881 13.254 -1.451 1.00 52.86 C +ATOM 25 CA GLY U 135 -10.306 12.656 -3.983 1.00 52.86 C +TER +END +""" + +# Convert to mmcif: +chain_addition = "ZXLONG" +from libtbx.test_utils import convert_pdb_to_cif_for_pdb_str +convert_pdb_to_cif_for_pdb_str(locals(),chain_addition=chain_addition) + +def tst_01(): + print("Regularizing allowing insertions...", end=' ') + import iotbx.pdb + from cctbx.array_family import flex + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_1)).construct_hierarchy() + r=replace_with_segments_from_pdb(args=[],pdb_hierarchy=hierarchy, + out=null_out()) + + expected_text=""" +ID: 1 ChainID: 'U%s' RMSD: 1.31 A (n=22) Junction RMSD: 0.68 A (n=7) +Complete: True Insertions/deletions: True +Input model start: 111 end: 135 length: 25 +Replacement start: 111 end: 136 length: 26 +""" %(chain_addition) + f=StringIO() + for rss in r.model_replacement_segment_summaries: + rss.show_summary(out=f) + + found_text=f.getvalue() + if remove_blank(found_text)!=remove_blank(expected_text): + print("Expected: \n%s \nFound: \n%s" %(expected_text,found_text)) + raise AssertionError("FAILED") + print("OK") + +def tst_02(): + print("Regularizing not allowing insertions...", end=' ') + import iotbx.pdb + from cctbx.array_family import flex + hierarchy=iotbx.pdb.input(source_info='text', + lines=flex.split_lines(pdb_str_1)).construct_hierarchy() + r=replace_with_segments_from_pdb(args=['alpha.allow_insertions=false'], + pdb_hierarchy=hierarchy, + out=null_out()) + + expected_text=""" +ID: 1 ChainID: 'U%s' RMSD: 1.28 A (n=25) Junction RMSD: 0.68 A (n=8) +Complete: True Insertions/deletions: False +Input model start: 111 end: 135 length: 25 +Replacement start: 111 end: 135 length: 25 +""" %(chain_addition) + f=StringIO() + for rss in r.model_replacement_segment_summaries: + rss.show_summary(out=f) + + found_text=f.getvalue() + if remove_blank(found_text)!=remove_blank(expected_text): + print("Expected: \n%s \nFound: \n%s" %(expected_text,found_text)) + raise AssertionError("FAILED") + print("OK") + + +if __name__=="__main__": + tst_01() + tst_02() diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index cdb97b1348..675f9214a2 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -68,7 +68,9 @@ "$D/ias/tst_ias.py", "$D/refinement/tst_fit_rotamers.py", "$D/regression/tst_process_predicted_model.py", + "$D/regression/tst_process_predicted_model_cif.py", "$D/regression/tst_domains_from_pae.py", + "$D/regression/tst_domains_from_pae_cif.py", ["$D/refinement/tst_anomalous_scatterer_groups.py", "P3"], "$D/refinement/tst_rigid_body.py", "$D/refinement/tst_rigid_body_groups_from_pdb_chains.py", @@ -203,11 +205,15 @@ "$D/conformation_dependent_library/tst_mcl_02.py", "$D/conformation_dependent_library/tst_mcl_03.py", "$D/regression/tst_find_ss_structure.py", + "$D/regression/tst_find_ss_structure_cif.py", "$D/regression/tst_fix_rotamer_outliers.py", "$D/regression/tst_chain_comparison.py", + "$D/regression/tst_chain_comparison_cif.py", "$D/regression/tst_regularize_from_pdb.py", + "$D/regression/tst_regularize_from_pdb_cif.py", "$D/regression/tst_find_ncs.py", "$D/regression/tst_minimize_chain.py", + "$D/regression/tst_minimize_chain_cif.py", "$D/regression/tst_sequence_validation.py", "$D/regression/tst_prune_model.py", "$D/regression/tst_real_space_correlation.py", diff --git a/mmtbx/secondary_structure/find_ss_from_ca.py b/mmtbx/secondary_structure/find_ss_from_ca.py index 7f2024d17a..a72fd7d4ba 100644 --- a/mmtbx/secondary_structure/find_ss_from_ca.py +++ b/mmtbx/secondary_structure/find_ss_from_ca.py @@ -21,6 +21,7 @@ from six.moves import zip from six.moves import range from six.moves import cStringIO as StringIO +from iotbx.pdb.utils import get_pdb_hierarchy master_phil = iotbx.phil.parse(""" @@ -257,6 +258,7 @@ master_params = master_phil ######## Methods for getting selection strings from a model ############ + def get_selection_from_chain_dict(chain_dict, minimum_segment_length = None, return_as_dict = False): ''' Create a selection based on a dict of residues present in each chain. @@ -340,12 +342,23 @@ def compress_indices(values): return new_compressed_values ######## END Methods for getting selection strings from a model ############ +def get_new_chain_id(existing_chain_ids): + # Generate something new... + lc = "abcdefghijklmnopqrstuvwxyz" + uc = lc.upper() + cc = uc+lc + eci = [] + for x in existing_chain_ids: + eci.append(x.strip()) + existing_chain_ids = eci + for b in " "+cc: + for a in cc: + d = (a+b).strip() + if not d in existing_chain_ids: + return d + raise AssertionError ("Not able to generate a new chain ID") -def get_pdb_hierarchy(text=None): - return iotbx.pdb.input( - source_info=None,lines=flex.split_lines(text)).construct_hierarchy() - def is_close_to(r,last_r,distance_cutoff=None,use_default_distance_cutoff=True): if not r or not last_r: return None @@ -526,9 +539,7 @@ def merge_hierarchies_from_models(models=None,resid_offset=None, # sort by chain_type if provided in one or more # replace hetero=True by hetero=False if replace_hetatm is set - new_hierarchy=iotbx.pdb.input( - source_info="Model", - lines=flex.split_lines("")).construct_hierarchy() + new_hierarchy=create_new_hierarchy() mm=iotbx.pdb.hierarchy.model() new_hierarchy.append_model(mm) if renumber: # just get chain once in advance @@ -596,19 +607,38 @@ def merge_hierarchies_from_models(models=None,resid_offset=None, new_hierarchy=new_hierarchy.apply_atom_selection(atom_selection) if remove_ter_records or remove_break_records: - new_records=flex.split_lines("") - for line in new_hierarchy.as_pdb_string().splitlines(): - if ( ((not remove_ter_records) or (not line.startswith("TER" )) ) and - ((not remove_break_records) or (not line.startswith("BREAK")) ) ): - new_records.append(line) - - new_hierarchy=iotbx.pdb.input( - source_info="Model", lines=new_records).construct_hierarchy() + new_hierarchy = remove_ter_or_break(new_hierarchy) new_model=model_info(hierarchy=new_hierarchy,info=info) return new_model +def pdb_or_mmcif_fn_info(fn): + b0,e0 = os.path.splitext(fn) + fn_pdb = "%s.pdb" %(b0) + fn_cif = "%s.cif" %(b0) + if os.path.isfile(fn_pdb): + return group_args( + file_name = fn_pdb, + format = 'pdb') + elif os.path.isfile(fn_cif): + return group_args( + file_name = fn_cif, + format = 'mmcif') + return fn_cif + else: + return None + +def remove_ter_or_break(ph): + for m0 in ph.models(): + for c0 in m0.chains(): + first = True + for residue_group in c0.residue_groups(): + if not first: + residue_group.link_to_previous = True + first = False + return ph + def get_average_direction(diffs=None, i=None,j=None): if not diffs: return None if i is None and j is None: @@ -658,10 +688,11 @@ def offset_residue_numbers(hierarchy, offset = 0): current_resno = rg.resseq_as_int() rg.resseq = resseq_encode(current_resno + offset) -def merge_and_renumber_everything(hierarchy, current_resno = 1): +def merge_and_renumber_everything(hierarchy, current_resno = 1, + chain_id = 'A'): new_hierarchy, mm = create_new_hierarchy_and_model() cc = iotbx.pdb.hierarchy.chain() - cc.id = 'A' + cc.id = chain_id mm.append_chain(cc) for model in hierarchy.models(): @@ -856,8 +887,10 @@ def verify_existence(hierarchy=None, prev_hierarchy=None,strand=None,registration=None,helix=None): ok=True - if not hierarchy: - raise Sorry("Need a model for user annotation input") + if hierarchy and is_ca_only_hierarchy(hierarchy): + is_ca_only = True + else: + is_ca_only = False for sh in [strand,helix]: if sh: @@ -888,14 +921,14 @@ def verify_existence(hierarchy=None, if registration: cur_atom=get_atom_index(hierarchy=hierarchy, - atom_name=registration.cur_atom, + atom_name= None if is_ca_only else registration.cur_atom, resname=registration.cur_resname, chain_id=registration.cur_chain_id, resseq=registration.cur_resseq, icode=registration.cur_icode) if cur_atom is None: raise Sorry( - "A residue in an strand registration is missing in the input model:"+ + "A residue in a strand registration is missing in the input model:"+ "%s %s %s %s %s" %( registration.cur_atom,registration.cur_resname, registration.cur_chain_id,registration.cur_resseq, @@ -903,26 +936,28 @@ def verify_existence(hierarchy=None, if registration and prev_hierarchy: prev_atom=get_atom_index(hierarchy=prev_hierarchy, - atom_name=registration.prev_atom, + atom_name=None if is_ca_only else registration.prev_atom, resname=registration.prev_resname, chain_id=registration.prev_chain_id, resseq=registration.prev_resseq, icode=registration.prev_icode) if prev_atom is None: raise Sorry( - "A residue in an strand registration is missing in the input model:"+ + "A residue in a previous strand registration is missing in the input model:"+ "%s %s %s %s %s" %( registration.prev_atom,registration.prev_resname, registration.prev_chain_id,registration.prev_resseq, registration.prev_icode)) def get_atom_index(hierarchy=None,atom_name=None,resname=None, - chain_id=None,resseq=None,icode=None): + chain_id=None,resseq=None,icode=None, + take_first_if_missing = None): # NOTE: could speed up using atom cache and iselection # find the index in hierarchy of this atom if not hierarchy: return None count=-1 + first_present = None for model in hierarchy.models(): for chain in model.chains(): for conformer in chain.conformers(): @@ -933,9 +968,14 @@ def get_atom_index(hierarchy=None,atom_name=None,resname=None, or not residue.icode==icode: continue for atom in residue.atoms(): + if first_present is None: + first_present = count if atom_name is None or atom.name==atom_name: return count - return None + if take_first_if_missing: # XXX Added in case it is ca model and force + return first_present + else: + return None def have_n_or_o(models): have_n=False @@ -1230,9 +1270,9 @@ def remove_bad_annotation(annotation,hierarchy=None, if deleted_something: new_annotation.merge_sheets() - if new_annotation.as_pdb_str(): + if new_annotation.as_pdb_or_mmcif_str(): print("User annotation after removing bad parts:", file=out) - print(new_annotation.as_pdb_str(), file=out) + print(new_annotation.as_pdb_or_mmcif_str(), file=out) else: print("No annotation left after removing bad parts", file=out) return None @@ -1251,7 +1291,7 @@ def remove_bad_annotation(annotation,hierarchy=None, if not no_overlap_annotation.is_same_as(other=new_annotation): print("Edited annotation without overlaps:", file=out) - print(no_overlap_annotation.as_pdb_str(), file=out) + print(no_overlap_annotation.as_pdb_or_mmcif_str(), file=out) print(file=out) return no_overlap_annotation @@ -1723,17 +1763,14 @@ def apply_lsq_fit(self,lsq_fit_obj=None,hierarchy=None, start_res=None,end_res=None): atom_selection="resid %s through %s" %(resseq_encode(start_res), resseq_encode(end_res)) - sele=hierarchy.apply_atom_selection(atom_selection) asc=hierarchy.atom_selection_cache() sel = asc.selection(string = atom_selection) - assert sele.overall_counts().n_residues # should not be None - f=StringIO() - for atom in sele.atoms_with_labels(): - new_xyz=lsq_fit_obj.r * matrix.col(atom.xyz) + lsq_fit_obj.t - atom.set_xyz(new_xyz) - print(atom.format_atom_record(), file=f) - return get_pdb_hierarchy(text=f.getvalue()) + new_ph = hierarchy.select(sel).deep_copy() + xyz = new_ph.atoms().extract_xyz() + new_xyz = lsq_fit_obj.r.elems * xyz + lsq_fit_obj.t.elems + new_ph.atoms().set_xyz(new_xyz) + return new_ph.as_pdb_input().construct_hierarchy() # XXX seems to reformat def get_site(self,resno=None): first_residue=self.get_start_resno() @@ -2504,7 +2541,6 @@ def list_h_bonds(self,segment=None,helix_type='alpha', number_of_poor_h_bonds=0 for i in range(segment.length()-next_i): - cur_residue=get_indexed_residue( segment.hierarchy,index=i) cur_atom,cur_xyz=get_atom_from_residue( @@ -2717,7 +2753,6 @@ def pdb_records(self,segment_list=None, # sheet allow_ca_only_model=allow_ca_only_model,out=f) good_in_sheet+=n_good poor_in_sheet+=n_poor - register=self.get_pdb_strand_register(segment=s, previous_segment=previous_s,first_last_1_and_2=first_last_1_and_2, allow_ca_only_model=allow_ca_only_model, @@ -2749,7 +2784,6 @@ def is_even(self,i): def get_pdb_strand_register(self,segment=None,previous_segment=None, first_last_1_and_2=None,allow_ca_only_model=None, all_h_bonds=None): - for h_bond in all_h_bonds: # choose first that is ok if not h_bond.is_ok(): continue @@ -2812,11 +2846,9 @@ def list_h_bonds(self,segment=None,previous_segment=None, first_ca_1,last_ca_1,first_ca_2,last_ca_2,is_parallel,i_index,j_index=\ first_last_1_and_2 - for i in range(previous_segment.length()): if i_index is None or j_index is None: continue if not self.is_even(i-i_index): continue - local_i_index=i_index+(i-i_index) if is_parallel: local_j_index=j_index+(i-i_index) @@ -3068,6 +3100,10 @@ def __init__(self): self.pdb_three_ten_helix_list=[] self.pdb_pi_helix_list=[] self.pdb_sheet_list=[] + self._have_annotations = False + + def have_annotations(self): + return self._have_annotations def add_from_model(self,model): if model.find_beta: @@ -3254,13 +3290,15 @@ def get_ind_h_bond_sheet(self, resname=registration.cur_resname, chain_id=registration.cur_chain_id, resseq=registration.cur_resseq, - icode=registration.cur_icode) + icode=registration.cur_icode, + take_first_if_missing = True) j_bond=get_atom_index(hierarchy=strand_j.hierarchy, atom_name=registration.prev_atom, resname=registration.prev_resname, chain_id=registration.prev_chain_id, resseq=registration.prev_resseq, - icode=registration.prev_icode) + icode=registration.prev_icode, + take_first_if_missing = True) else: prev_atom=registration.prev_atom strand_i=self.all_strands[i] @@ -3270,13 +3308,15 @@ def get_ind_h_bond_sheet(self, resname=registration.prev_resname, chain_id=registration.prev_chain_id, resseq=registration.prev_resseq, - icode=registration.prev_icode) + icode=registration.prev_icode, + take_first_if_missing = True) j_bond=get_atom_index(hierarchy=strand_j.hierarchy, atom_name=registration.cur_atom, resname=registration.cur_resname, chain_id=registration.cur_chain_id, resseq=registration.cur_resseq, - icode=registration.cur_icode) + icode=registration.cur_icode, + take_first_if_missing = True) assert sense in [-1,1] i_index=i_bond @@ -3305,7 +3345,6 @@ def get_ind_h_bond_sheet(self, # N of residue i in strand n H-bonds to O of residue i' in strand n+1 j_index=j_bond# everything is ok already - return i_index,j_index else: @@ -3505,7 +3544,10 @@ def set_up_pdb_records(self,allow_ca_only_model=None, # determine if there are N and O atoms present. # If not, set allow_ca_only_model=True - allow_ca_only_model=(not have_n_or_o(models)) + if (allow_ca_only_model is None): + allow_ca_only_model=(not have_n_or_o(models)) + if force_secondary_structure_input: + allow_ca_model_only = True f=StringIO() print("\nList of H-bonds expected from helices and from strand pairings", file=f) @@ -3576,26 +3618,33 @@ def get_fa(find_what='find_alpha',models=None): self.h_bond_text=text return number_of_good_h_bonds,number_of_poor_h_bonds - def save_pdb_records_as_string(self): - all_pdb_records=StringIO() - self.all_selection_records=[] + def get_annotation(self): + all_helices = [] + all_sheets = [] + self._have_annotations = False + self.all_selection_records = [] for helix in self.pdb_alpha_helix_list: - print(helix.as_pdb_str(), file=all_pdb_records) + all_helices.append(helix) self.all_selection_records+=helix.as_atom_selections() + self._have_annotations = True for helix in self.pdb_three_ten_helix_list: - print(helix.as_pdb_str(), file=all_pdb_records) + all_helices.append(helix) self.all_selection_records+=helix.as_atom_selections() + self._have_annotations = True for helix in self.pdb_pi_helix_list: - print(helix.as_pdb_str(), file=all_pdb_records) + all_helices.append(helix) self.all_selection_records+=helix.as_atom_selections() + self._have_annotations = True for sheet in self.pdb_sheet_list: - print(sheet.as_pdb_str(), file=all_pdb_records) + all_sheets.append(sheet) self.all_selection_records+=sheet.as_atom_selections() - - self.all_pdb_records=all_pdb_records.getvalue() + self._have_annotations = True + from iotbx.pdb.secondary_structure import annotation + all_annotations = annotation(helices = all_helices, sheets = all_sheets) + return all_annotations def get_pdb_alpha_helix_list(self): if hasattr(self,'pdb_alpha_helix_list'): @@ -3613,16 +3662,6 @@ def get_pdb_sheet_list(self): if hasattr(self,'pdb_sheet_list'): return self.pdb_sheet_list - def get_all_pdb_records(self): - if hasattr(self,'all_pdb_records'): - return self.all_pdb_records - - def get_annotation(self): - self.save_pdb_records_as_string() - records=self.all_pdb_records - import iotbx.pdb.secondary_structure as ioss - return ioss.annotation.from_records(records=flex.split_lines(records)) - def get_all_selection_records(self): if not hasattr(self,'all_selection_records'): return @@ -3953,7 +3992,7 @@ def __init__(self,params=None,args=None,hierarchy=None,models=None, # get annotation: print("\nNew working annotation:", file=out) working_annotation=self.helix_strand_segments.get_annotation() - print(working_annotation.as_pdb_str(), file=out) + print(working_annotation.as_pdb_or_mmcif_str(), file=out) if params.find_ss_structure.combine_annotations and \ composite_user_annotation: @@ -3961,7 +4000,7 @@ def __init__(self,params=None,args=None,hierarchy=None,models=None, working_annotation=composite_user_annotation.combine_annotations( hierarchy=hierarchy, other=working_annotation) print("\nMerged annotation:\n", file=out) - print(working_annotation.as_pdb_str(), file=out) + print(working_annotation.as_pdb_or_mmcif_str(), file=out) # Remove annotation that does not match model @@ -4004,6 +4043,16 @@ def __init__(self,params=None,args=None,hierarchy=None,models=None, out=out) self.h_bond_text=self.helix_strand_segments.h_bond_text working_annotation=self.helix_strand_segments.get_annotation() + # Remove bad if it was introduced here + if 0 and params.find_ss_structure.remove_missing_atom_annotation: + print("ZZ REMOVING BAD") + working_annotation=remove_bad_annotation( + working_annotation, + hierarchy=hierarchy, + max_h_bond_length=params.find_ss_structure.max_h_bond_length, + remove_overlaps=False, # XXX Required to prevent recursion + out=out) + print("ZZ work",working_annotation.as_mmcif_str()) elif self.user_helix_strand_segments and secondary_structure_input and \ not params.find_ss_structure.combine_annotations: @@ -4037,9 +4086,9 @@ def __init__(self,params=None,args=None,hierarchy=None,models=None, # user annotation combined with new annotation if remove_text: print(remove_text, file=out) print("\nRunning analysis with new annotation", file=out) - if working_annotation and working_annotation.as_pdb_str(): + if working_annotation and working_annotation.as_pdb_or_mmcif_str(): fss=find_secondary_structure(hierarchy=hierarchy, - user_annotation_text=working_annotation.as_pdb_str(), + user_annotation_text=working_annotation.as_pdb_or_mmcif_str(), force_secondary_structure_input=True, combine_annotations=False, max_h_bond_length=params.find_ss_structure.max_h_bond_length, @@ -4224,9 +4273,9 @@ def show_summary(self,verbose=None,pdb_records_file=None,out=sys.stdout): model.find_beta.show_summary(out=out) if model.find_other: model.find_other.show_summary(out=out) - if self.annotation and self.annotation.as_pdb_str(): + if self.annotation and self.annotation.as_pdb_or_mmcif_str(): print("\nFINAL PDB RECORDS:", file=out) - print(self.annotation.as_pdb_str(), file=out) + print(self.annotation.as_pdb_or_mmcif_str(), file=out) if self.params.control.verbose: print("\n\nFINAL HELIX selections:", file=out) @@ -4240,7 +4289,7 @@ def show_summary(self,verbose=None,pdb_records_file=None,out=sys.stdout): if pdb_records_file and self.annotation: f=open(pdb_records_file,'w') - print(self.annotation.as_pdb_str(), file=f) + print(self.annotation.as_pdb_or_mmcif_str(), file=f) f.close() print("\nRecords written to %s\n" %( pdb_records_file), file=out) @@ -4264,22 +4313,26 @@ def get_user_ss(self,params=None,hierarchy=None, # Read ss structure from this file now print("\nReading secondary structure records from %s\n" %(file_name), file=out) user_annotation_text=open(file_name).read() - - import iotbx.pdb.secondary_structure as ioss - user_annotation=ioss.annotation.from_records( - records=flex.split_lines(user_annotation_text)) + import iotbx.pdb + user_annotation=iotbx.pdb.input(source_info=None, + lines = flex.split_lines( + user_annotation_text)).extract_secondary_structure() print("\nUser helix/strand records as input:\n", file=out) - print(user_annotation.as_pdb_str(), file=out) + print(user_annotation.as_pdb_or_mmcif_str(), file=out) if params.input_files.force_secondary_structure_input: if params.find_ss_structure.combine_annotations: - print("\nThis secondary structure annotation will be taken as is and"+\ - " then will be \ncombined with an edited version (updating H-bonding)", file=out) + print("\nThis secondary structure annotation will be taken as is and"+\ + " then will be \ncombined with an edited version (updating H-bonding)", + file=out) else: - print("\nThis secondary structure annotation will be used as is.\n", file=out) + print("\nThis secondary structure annotation will be used as is.\n", + file=out) remove_overlaps=False else: - print("\nThis secondary structure annotation will be modified if necessary\n", file=out) + print( + "\nThis secondary structure annotation will be modified if necessary\n", + file=out) remove_overlaps=True # Remove any parts of this annotation that do not exist in the hierarchy user_annotation=remove_bad_annotation( @@ -4412,6 +4465,8 @@ def get_user_ss(self,params=None,hierarchy=None, prev_strand_id=len(self.user_helix_strand_segments.all_strands)-1 prev_hierarchy=ph + + self.user_number_of_good_h_bonds,self.user_number_of_poor_h_bonds=\ self.user_helix_strand_segments.set_up_pdb_records(models=self.user_models, max_h_bond_length=params.find_ss_structure.max_h_bond_length, @@ -4419,31 +4474,32 @@ def get_user_ss(self,params=None,hierarchy=None, params.input_files.force_secondary_structure_input, allow_ca_only_model=params.beta.allow_ca_only_model,out=local_out) print("\nNumber of good H-bonds: %d Number of poor H-bonds: %d" %( - self.user_number_of_good_h_bonds,self.user_number_of_poor_h_bonds), file=out) + self.user_number_of_good_h_bonds,self.user_number_of_poor_h_bonds), + file=out) edited_annotation=self.user_helix_strand_segments.get_annotation() - if self.user_helix_strand_segments.get_all_pdb_records(): + if self.user_helix_strand_segments.have_annotations(): if params.input_files.force_secondary_structure_input: print("\nWorking PDB RECORDS (equivalent to input records):", file=out) else: print("\nInput PDB RECORDS as modified:", file=out) - print(edited_annotation.as_pdb_str(), file=out) + print(edited_annotation.as_pdb_or_mmcif_str(), file=out) if params.find_ss_structure.combine_annotations: print("\nMerging input and edited annotation", file=out) edited_annotation=self.user_helix_strand_segments.get_annotation() print("\nEdited annotation:", file=out) - print(edited_annotation.as_pdb_str(), file=out) + print(edited_annotation.as_pdb_or_mmcif_str(), file=out) print("\nUser annotation:", file=out) - print(user_annotation.as_pdb_str(), file=out) + print(user_annotation.as_pdb_or_mmcif_str(), file=out) combined_annotation=edited_annotation.combine_annotations( hierarchy=hierarchy, other=user_annotation) # will take edited if equal if combined_annotation: print("\nMerged annotation (input and edited input annotation):\n", file=out) - print(combined_annotation.as_pdb_str(), file=out) + print(combined_annotation.as_pdb_or_mmcif_str(), file=out) return combined_annotation else: @@ -4597,8 +4653,8 @@ def get_params(self,args,out=sys.stdout): sheets=fss.get_pdb_sheet_list() print "\nHelix Summary" for helix in alpha_helices: - print helix.as_pdb_str() + print helix.as_pdb_or_mmcif_str() print "\nSheet Summary" for sheet in sheets: - print sheet.as_pdb_str() + print sheet.as_pdb_or_mmcif_str() """ diff --git a/mmtbx/secondary_structure/regularize_from_pdb.py b/mmtbx/secondary_structure/regularize_from_pdb.py index 7199397f3d..fc48363d25 100644 --- a/mmtbx/secondary_structure/regularize_from_pdb.py +++ b/mmtbx/secondary_structure/regularize_from_pdb.py @@ -16,8 +16,10 @@ find_secondary_structure, \ find_helix,find_beta_strand,find_other_structure,helix,strand,other,\ get_atom_list,\ - model_info,split_model,merge_hierarchies_from_models, \ - get_pdb_hierarchy + model_info,split_model +from mmtbx.secondary_structure.find_ss_from_ca import \ + merge_hierarchies_from_models +from iotbx.pdb.utils import get_pdb_hierarchy from six.moves import zip from six.moves import range @@ -1668,11 +1670,12 @@ def __init__(self,pdb_hierarchy=None,args=None, # write out results if params.output_files.pdb_out: + info = replacement_model.hierarchy.pdb_or_mmcif_string_info( + target_filename = params.output_files.pdb_out, + write_file = True,) + params.output_files.pdb_out = info.file_name print("\nWriting output PDB file to %s" %( params.output_files.pdb_out), file=out) - f=open(params.output_files.pdb_out,'w') - print(replacement_model.hierarchy.as_pdb_string(), file=f) - f.close() self.replacement_model=replacement_model def replacement_hierarchy(self): @@ -2209,7 +2212,7 @@ def link_groups(self,params=None,model=None,connected_groups=None, for cg in connected_groups: print(cg.show_comprehensive_summary()) for cg in connected_groups: print("\nGROUP:") - print(cg.as_model(is_left_end=True).hierarchy.as_pdb_string()) + print(cg.as_model(is_left_end=True).hierarchy.as_pdb_string()) # PDB OK debug only connected_groups=self.sort_and_remove_overlapping_groups(connected_groups) @@ -2218,7 +2221,7 @@ def link_groups(self,params=None,model=None,connected_groups=None, for cg in connected_groups: print(cg.show_comprehensive_summary()) for cg in connected_groups: print("\nGROUP:") - print(cg.as_model(is_left_end=True).hierarchy.as_pdb_string()) + print(cg.as_model(is_left_end=True).hierarchy.as_pdb_string()) # PDB OK debug only connected_groups=self.combine_groups_by_residue(connected_groups, maximum_junction_rmsd=maximum_junction_rmsd, @@ -2519,7 +2522,7 @@ def get_replacement_segments(self,params,model=None, print_output=False if print_output: - print("Output model:\n%s" %(r.replacement_hierarchy().as_pdb_string())) + print("Output model:\n%s" %(r.replacement_hierarchy().as_pdb_string())) # PDB OK debug only print("\nSummary by segment:") diff --git a/mmtbx/validation/chain_comparison.py b/mmtbx/validation/chain_comparison.py index ad9d514201..2fa34dd5c1 100644 --- a/mmtbx/validation/chain_comparison.py +++ b/mmtbx/validation/chain_comparison.py @@ -300,7 +300,6 @@ def best_match(sites1,sites2,crystal_symmetry=None, unit_cell=crystal_symmetry.unit_cell() sps=crystal_symmetry.special_position_settings(min_distance_sym_equiv=0.5) - from scitbx.array_family import flex # Match coordinates from cctbx import sgtbx @@ -643,7 +642,7 @@ def get_sorted_matching_chains( def split_chains_with_unique_four_char_id(ph): from mmtbx.secondary_structure.find_ss_from_ca import split_model,model_info,\ - merge_hierarchies_from_models, make_four_char_unique_chain_id + make_four_char_unique_chain_id chain_model=model_info(hierarchy=ph) distance_cutoff=15. # basically use sequence jumps to ID breaks chain_models=split_model(model=chain_model,distance_cutoff=distance_cutoff) @@ -1245,13 +1244,15 @@ def run(args=None, if params.input_files.test_unique_part_of_target_only and \ params.output_files.match_pdb_file: print("Note: Cannot use test_unique_part_of_target_only "+\ - "with match_pdb_file...\nturning off test_unique_part_of_target_only", file=out) + "with match_pdb_file...\nturning "+ + "off test_unique_part_of_target_only", file=out) params.input_files.test_unique_part_of_target_only=False if params.input_files.unique_query_only and \ params.input_files.unique_part_of_target_only: print("Warning: You have specified unique_query_only and" +\ - " unique_part_of_target_only. \nThis is not normally appropriate ", file=out) + " unique_part_of_target_only. "+ + "\nThis is not normally appropriate ", file=out) if params.input_files.unique_target_pdb_in and \ params.input_files.unique_query_only: print("Using %s as target for unique chains" %( @@ -1335,6 +1336,17 @@ def run(args=None, chain_hierarchy.remove_alt_confs(always_keep_one_conformer=True) target_hierarchy.remove_alt_confs(always_keep_one_conformer=True) + # Convert to forward_compatible_pdb if necessary + conversion_info_dict = {} + for ph in (chain_hierarchy, target_hierarchy): + if not ph.fits_in_pdb_format(): + from iotbx.pdb.forward_compatible_pdb_cif_conversion \ + import forward_compatible_pdb_cif_conversion + conversion_info = forward_compatible_pdb_cif_conversion(hierarchy = ph) + conversion_info.\ + convert_hierarchy_to_forward_compatible_pdb_representation(ph) + conversion_info_dict[ph] = conversion_info + total_target=target_hierarchy.overall_counts().n_residues total_chain=chain_hierarchy.overall_counts().n_residues diff --git a/mmtbx/validation/clashscore.py b/mmtbx/validation/clashscore.py index c654159666..27e4e2fe08 100644 --- a/mmtbx/validation/clashscore.py +++ b/mmtbx/validation/clashscore.py @@ -126,6 +126,16 @@ def __init__(self, verbose=False, do_flips=False, out=sys.stdout): + if (not pdb_hierarchy.fits_in_pdb_format()): + from iotbx.pdb.forward_compatible_pdb_cif_conversion \ + import forward_compatible_pdb_cif_conversion + conversion_info = forward_compatible_pdb_cif_conversion( + hierarchy = pdb_hierarchy) + conversion_info.\ + convert_hierarchy_to_forward_compatible_pdb_representation(pdb_hierarchy) + print("Converted model to forward_compatible PDB for clashscore") + else: + conversion_info = None validation.__init__(self) self.b_factor_cutoff = b_factor_cutoff self.fast = fast @@ -180,6 +190,10 @@ def __init__(self, if (save_modified_hierarchy): self.pdb_hierarchy = iotbx.pdb.input( pdb_string=self.probe_clashscore_manager.h_pdb_string).construct_hierarchy() + if conversion_info: + conversion_info.convert_hierarchy_to_full_representation( + self.pdb_hierarchy) + self.clash_dict[model.id] = self.probe_clashscore_manager.clashscore self.clash_dict_b_cutoff[model.id] = self.probe_clashscore_manager.\ clashscore_b_cutoff @@ -191,6 +205,10 @@ def __init__(self, self.clashscore_b_cutoff = self.probe_clashscore_manager.\ clashscore_b_cutoff + if conversion_info: + print("Converted model back to full representation") + conversion_info.convert_hierarchy_to_full_representation(pdb_hierarchy) + def get_clashscore(self): return self.clashscore From 908c7215c65a3c6c3188c2c6d1cef438a81a2b9a Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Thu, 1 Feb 2024 10:07:48 -0800 Subject: [PATCH 089/748] Clean clutter and update test to not require restraints --- iotbx/cli_parser.py | 1 + iotbx/command_line/pdb_cif_conversion.py | 54 +++++++++---------- iotbx/pdb/utils.py | 14 ++--- ...in_shift_and_unit_cell_crystal_symmetry.py | 1 - ...hift_and_unit_cell_crystal_symmetry_cif.py | 1 - mmtbx/model/model.py | 2 +- 6 files changed, 36 insertions(+), 37 deletions(-) diff --git a/iotbx/cli_parser.py b/iotbx/cli_parser.py index 2ed53ed126..f906aff376 100644 --- a/iotbx/cli_parser.py +++ b/iotbx/cli_parser.py @@ -879,6 +879,7 @@ def run_program(program_class=None, parser_class=CCTBXParser, custom_process_arg if args is None: args = sys.argv[1:] + # start profiling pr = None if '--profile' in args: diff --git a/iotbx/command_line/pdb_cif_conversion.py b/iotbx/command_line/pdb_cif_conversion.py index fef7317696..8ce34c6cba 100644 --- a/iotbx/command_line/pdb_cif_conversion.py +++ b/iotbx/command_line/pdb_cif_conversion.py @@ -22,7 +22,7 @@ TOOLS AVAILABLE TO FIND CODE THAT NEEDS TO BE MADE CIF-COMPATIBLE CREATING CIF TESTS TO CHECK CODE WITH MODELS THAT CANNOT FIT IN PDB FORMAT USING FORWARD-COMPATIBLE PDB FORMAT FOR CODE REQUIRING PDB-FORMATTED TEXT - DETAILS OF METHODS ADDED FOR WORKING WITH PDB/CIF + DETAILS OF METHODS ADDED FOR WORKING WITH PDB/CIF =========================================================================== =========================================================================== @@ -61,7 +61,7 @@ =========================================================================== =========================================================================== - RECOMMENDED OVERALL APPROACHES + RECOMMENDED OVERALL APPROACHES (DETAILS IN THE SECTION "DETAILED SUGGESTIONS FOR MAKING CODE CIF-COMPLIANT") I. USE THE PROGRAM TEMPLATE @@ -108,8 +108,8 @@ b. All code that accumulates lines from multiple PDB files and then interprets the new lines should be replaced by reading each PDB file and merging the resulting hierarchies or models. This can be done for model files - with the simple_combine or add_hierarchies methods available in - iotbx.pdb.utils, or simple custom code can be written to add chains + with the simple_combine or add_hierarchies methods available in + iotbx.pdb.utils, or simple custom code can be written to add chains from one hierarchy onto another hierarchy. @@ -119,9 +119,9 @@ V. CREATE CIF TESTS TO CHECK CODE WITH MODELS THAT CANNOT FIT IN PDB FORMAT For any code that uses pdb/cif files or that uses the hierarchy object - should be tested with models that do not fit in PDB format. It is + should be tested with models that do not fit in PDB format. It is recommended that each standard test using models should be duplicated - and run with non-PDB-compliant models. The tool + and run with non-PDB-compliant models. The tool convert_pdb_to_cif_for_pdb_str can be used to edit strings in place in tests so that identical starting strings can be used in the original and non-PDB-compliant tests. @@ -162,9 +162,9 @@ A. Use the Program Template and use data_manager for all model read/write. If you do this there is only one thing you need to do: capture the actual file name written by - the data_manager. + the data_manager. - The program template automatically adds the scope + The program template automatically adds the scope 'output.target_output_format' to your parameters, allowing a user to set the output format. If it is not set, the program template sets it to the format of the default incoming model if @@ -237,7 +237,7 @@ def get_results(self): A. You will want to remove all instances of the following methods. None of these are mmcif-compliant: - model.model_as_pdb() + model.model_as_pdb() ph.as_pdb_string() ph.write_pdb_file() @@ -253,7 +253,7 @@ def get_results(self): print("Wrote model to '%s'" %file_name) Use instead model.pdb_or_mmcif_string_info(): - + file_name = 'mypdb.pdb' info = model.pdb_or_mmcif_string_info( target_format = params.output_files.target_output_format, @@ -270,7 +270,7 @@ def get_results(self): Use instead model.pdb_or_mmcif_string_info() which will give you a PDB or mmcif string as appropriate: - + info = model.pdb_or_mmcif_string_info( target_format = params.output_files.target_output_format) str = info.pdb_string @@ -309,7 +309,7 @@ def get_results(self): for line in open(model_file).readlines(): do_something_based_on_a_line_in_file(line) - You will want instead to read in the model to get a hierarchy, then + You will want instead to read in the model to get a hierarchy, then use hierarchy methods to change or interpret the hierarchy. C. If your code catenates model text like this: @@ -357,14 +357,14 @@ def get_results(self): V. TOOLS AVAILABLE TO FIND CODE THAT NEEDS TO BE MADE CIF-COMPATIBLE A. You can use the libtbx.find_pdb_mmcif_problems to help identify code - that needs to be modified to make it cif-compatible. + that needs to be modified to make it cif-compatible. You can say: libtbx.find_pdb_mmcif_problems phenix/phenix/command_line and it (recursively) will go through all files/directories in command_line - and look for problems + and look for problems Or you can work on just one file: @@ -377,7 +377,7 @@ def get_results(self): B. Run libtbx.find_pdb_mmcif_problems with the argument "mark_lines": 1. Run it like this: - + libtbx.find_pdb_mmcif_problems phase_and_build.py mark_lines This will edit phase_and_build.py, placing text like: @@ -389,7 +389,7 @@ def get_results(self): b. fix the problems c. mark non-problems with the text " # PDB OK", add explanation if you want - 3. Then clean up by running: + 3. Then clean up by running: libtbx.find_pdb_mmcif_problems phase_and_build.py unmark_lines @@ -397,7 +397,7 @@ def get_results(self): 4. Finally, run: - libtbx.find_pdb_mmcif_problems phase_and_build.py + libtbx.find_pdb_mmcif_problems phase_and_build.py again to make sure you got it all. @@ -445,7 +445,7 @@ def get_results(self): chain IDs (and optionally HETATM residue names) may be different. B. If your test uses models in PDB files, you may simply want to - make copies of all your models, converting your PDB files into + make copies of all your models, converting your PDB files into mmCIF and edit the chain IDs: You can do this with pdbtools: @@ -494,7 +494,7 @@ def get_results(self): These methods are described in detail in the hierarchy.py code. --------------------------------------------------------------------------- --------------------------------------------------------------------------- - DETAILS OF METHODS ADDED FOR WORKING WITH PDB/CIF + DETAILS OF METHODS ADDED FOR WORKING WITH PDB/CIF MODULE: iotbx/cli_parser.py @@ -518,7 +518,7 @@ def write_model_file(self, model_str, filename=Auto, extension=Auto, MODULE: iotbx/pdb/hierarchy.py: -Methods for converting hierarchy to forward-compatible (fits in PDB format, +Methods for converting hierarchy to forward-compatible (fits in PDB format, see above): def is_forward_compatible_hierarchy(self): @@ -528,14 +528,14 @@ def as_forward_compatible_hierarchy(self, conversion_info = None): def forward_compatible_hierarchy_as_standard(self, conversion_info = None): def as_forward_compatible_string(self, **kw): -Method for writing as PDB or mmCIF string, using supplied target_format if +Method for writing as PDB or mmCIF string, using supplied target_format if possible, optionally writing as file, returning group_args object with text string, file_name written, and is_mmcif marker: def pdb_or_mmcif_string_info(self, NOTE: This method and the corresponding method in model.py use -default of segid_as_auth_segid = True, different from the default in +default of segid_as_auth_segid = True, different from the default in model_as_mmcif() in model.py and as_mmcif_string() in hierarchy.py The default of segid_as_auth_segid = True causes any text in the SEGID field read from a PDB-formatted file to be written to the auth_segid field @@ -555,14 +555,14 @@ def sort_chains_by_id(self): MODULE: mmtbx/model/model.py: Method matching one of the same name in hierarchy.py, -for writing as PDB or mmCIF string, using supplied target_format if +for writing as PDB or mmCIF string, using supplied target_format if possible, optionally writing as file, returning group_args object with text string, file_name written, and is_mmcif marker: def pdb_or_mmcif_string_info(self, NOTE: This method and the corresponding method in hierarchy.py use -default of segid_as_auth_segid = True, different from the default in +default of segid_as_auth_segid = True, different from the default in model_as_mmcif() in model.py and as_mmcif_string() in hierarchy.py. The default of segid_as_auth_segid = True causes any text in the SEGID field read from a PDB-formatted file to be written to the auth_segid field @@ -581,7 +581,7 @@ def move_down_scope_to_input_files(params, levels = 3): Method to find file named with 'pdb' or 'cif' when given one or the other. Returns the file supplied if present, otherwise the other file if it is present, -otherwise empty string. Can find files with the pdb/cif followed by an +otherwise empty string. Can find files with the pdb/cif followed by an underscore such as myfile.pdb_1. Only looks for pdb/cif in the extension: def get_cif_or_pdb_file_if_present(file_name): @@ -629,13 +629,13 @@ def check_for_incorrect_spacings(atoms): Method checking for atom names starting with "Z" (used as pseudo-atoms) -def check_for_pseudo_atoms(atoms): +def check_for_pseudo_atoms(atoms): MODULE: iotbx/pdb/forward_compatible_pdb_cif_conversion.py This module has low-level methods for conversion of hierarchies to a PDB-compatible -form, for reading and writing these hierarchies, and for converting them +form, for reading and writing these hierarchies, and for converting them back to the original form. Normally the methods in the hierarchy class should be used, rather diff --git a/iotbx/pdb/utils.py b/iotbx/pdb/utils.py index 0513adca40..4ce995dccc 100644 --- a/iotbx/pdb/utils.py +++ b/iotbx/pdb/utils.py @@ -342,7 +342,7 @@ def get_pdb_info(text = None, file_name = None, lines = None, check_pseudo = False, return_pdb_hierarchy = False, return_group_args = False, allow_incorrect_spacing = False): - ''' Get a pdb_input object from pdb or mmcif file, construct a + ''' Get a pdb_input object from pdb or mmcif file, construct a hierarchy, check the hierarchy for missing elements and fill them in if from pdb. Return group_args object with hierarchy, pdb_input, and crystal_symmetry. @@ -378,15 +378,15 @@ def get_pdb_input(text = None, file_name = None, lines = None, return_group_args = False, allow_incorrect_spacing = False): - ''' Get a pdb_input object from pdb or mmcif file, construct a + ''' Get a pdb_input object from pdb or mmcif file, construct a hierarchy, check the hierarchy for missing elements and fill them in if from pdb. Return hierarchy, pdb_input, or group_args object with hierarchy, pdb_input, and crystal_symmetry. Normally use instead the info = get_pdb_info method and then - you have hierarchy, pdb_input and crystal_symmetry all available + you have hierarchy, pdb_input and crystal_symmetry all available - ''' + ''' lines = get_lines(text = text, file_name = file_name, lines = lines) # Get input object as pdb_inp @@ -610,7 +610,7 @@ def catenate_segment_onto_chain(model_chain, s2, gap = 1, def simple_combine(model_list, create_new_chain_ids_if_necessary = True): - ''' Method to combine the chains in a set of models to create a new + ''' Method to combine the chains in a set of models to create a new model with all the chains. param: model_list: list of model objects param: create_new_chain_ids_if_necessary: If True (default), if a @@ -630,8 +630,8 @@ def simple_combine(model_list, return model def get_cif_or_pdb_file_if_present(file_name): - ''' Identify whether a file with the name file_name or with - alternate extensions replacing pdb/cif is present. + ''' Identify whether a file with the name file_name or with + alternate extensions replacing pdb/cif is present. If file_name is present, return file_name. If not, and alternative is present, return alternative file name Otherwise return empty string diff --git a/iotbx/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry.py b/iotbx/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry.py index 0485fdfd0d..48be1943f8 100644 --- a/iotbx/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry.py +++ b/iotbx/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry.py @@ -1,6 +1,5 @@ from __future__ import absolute_import, division, print_function from iotbx.data_manager import DataManager -import libtbx.load_env import os diff --git a/iotbx/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry_cif.py b/iotbx/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry_cif.py index 8b2348f730..6ebc7ad009 100644 --- a/iotbx/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry_cif.py +++ b/iotbx/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry_cif.py @@ -1,6 +1,5 @@ from __future__ import absolute_import, division, print_function from iotbx.data_manager import DataManager -import libtbx.load_env import os def exercise(): diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index 058bd1f89b..8f451511c5 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -1835,7 +1835,7 @@ def model_as_mmcif(self, cif_block.sort(key=category_sort_function) cif[cif_block_name] = cif_block - if not skip_restraints: + if not skip_restraints and self.restraints_manager_available(): restraints = self.extract_restraints_as_cif_blocks() cif.update(restraints) From 67ea9fc40ae88743edbeeab8d3518e865292d6b0 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Thu, 1 Feb 2024 12:34:52 -0800 Subject: [PATCH 090/748] Some comments for new functions --- iotbx/pdb/utils.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/iotbx/pdb/utils.py b/iotbx/pdb/utils.py index 4ce995dccc..d4f176b7de 100644 --- a/iotbx/pdb/utils.py +++ b/iotbx/pdb/utils.py @@ -154,6 +154,10 @@ def get_input_model_file_name_from_params(params): return file_name def target_output_format_in_params(params): + """ + Find and return value of target_output_format parameter that may be under + output_files or output phil scope. + """ for x in ['output_files','output']: if params and hasattr(params,x) and \ hasattr(getattr(params,x),'target_output_format'): @@ -180,6 +184,11 @@ def get_target_output_format_from_file_name(file_name, return target_output_format def move_down_scope_to_input_files(params, levels = 3): + """ + Find one of the scope names from target_scopes below in params. + levels - depth of the nested scopes to look in. + returns first suitable name/scope. + """ target_scopes = ['input_files','output','output_files','map_model',] if levels < 0: return None @@ -197,6 +206,15 @@ def move_down_scope_to_input_files(params, levels = 3): def set_target_output_format_in_params(params, file_name = None, default = 'pdb', target_output_format = None, out = sys.stdout, quiet = True): + """ + Find target_output_format parameter in params and: + - If it is not None, leave it as it was + - If it is None: + - set it to extension of file_name or default; + Return what was set - "pdb" or "mmcif" + """ + # Note that this assignment will change params only inside this + # function (?). Params outside this function will remain unchanged. params = move_down_scope_to_input_files(params) # Do we have it set already: target_output_format = target_output_format_in_params(params) From 442faae10ad366ec62dfae38117c462e4a02d7a1 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Thu, 1 Feb 2024 13:04:32 -0800 Subject: [PATCH 091/748] Better explanation --- iotbx/pdb/utils.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/iotbx/pdb/utils.py b/iotbx/pdb/utils.py index d4f176b7de..6f37e11fae 100644 --- a/iotbx/pdb/utils.py +++ b/iotbx/pdb/utils.py @@ -213,9 +213,13 @@ def set_target_output_format_in_params(params, - set it to extension of file_name or default; Return what was set - "pdb" or "mmcif" """ - # Note that this assignment will change params only inside this - # function (?). Params outside this function will remain unchanged. params = move_down_scope_to_input_files(params) + # Now params pointing out at the correct level of phil scope, the one + # containing output_files.target_output_format. + # Note that level to which params points outside this function is not changed. + # At the same time the value of output_files.target_output_format outside + # WILL be changed by statements below. + # Do we have it set already: target_output_format = target_output_format_in_params(params) if not target_output_format: From 851ee9ba77fd7727a2d2d1cbecfd6f6acf05da61 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 1 Feb 2024 13:51:32 -0800 Subject: [PATCH 092/748] Example showing how to set PENG1996 table for electron form-factors --- cctbx/xray/boost_python/tst_xray.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/cctbx/xray/boost_python/tst_xray.py b/cctbx/xray/boost_python/tst_xray.py index 21d6c257e3..d1763b93ba 100644 --- a/cctbx/xray/boost_python/tst_xray.py +++ b/cctbx/xray/boost_python/tst_xray.py @@ -749,6 +749,24 @@ def exercise_rotate(): scatterers=s) assert approx_equal(r[0].site, (-0.02,-0.01,-0.3)) +def exercise_scattering_type_registry_1(): + reg = xray.scattering_type_registry() + scatterers = flex.xray_scatterer(( + xray.scatterer("O"), + xray.scatterer("O1-"))) + reg.process(scatterers) + reg.assign_from_table(table="PENG1996") + d = reg.as_type_gaussian_dict() + # Values from peng1996.cpp: + O_minus = d["O1-"] + assert approx_equal(O_minus.array_of_a()[2], 1.17, 0.01) + assert approx_equal(O_minus.array_of_b()[1], 2.64, 0.01) + assert approx_equal(O_minus.c(), 0, 0.001) + O = d["O"] + assert approx_equal(O.array_of_a()[3], 0.8814, 0.0001) + assert approx_equal(O.array_of_b()[4], 28.2194, 0.00001) + assert approx_equal(O.c(), 0, 0.001) + def exercise_scattering_type_registry(): reg = xray.scattering_type_registry() assert len(reg.type_index_pairs_as_dict()) == 0 @@ -1983,6 +2001,7 @@ def exercise_r_factor(): assert approx_equal(r.scale_ls(), 0.1) def run(): + exercise_scattering_type_registry_1() exercise_r_factor() exercise_extinction_correction() exercise_twin_components() From cffb0162f7a32d042e861261b72d795df70d4cd1 Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 1 Feb 2024 17:34:48 -0700 Subject: [PATCH 093/748] Update pdb_cif_conversion.py to move undesirable methods that may be occasionally needed to an Appendix --- iotbx/command_line/pdb_cif_conversion.py | 310 ++++++++++++----------- 1 file changed, 157 insertions(+), 153 deletions(-) diff --git a/iotbx/command_line/pdb_cif_conversion.py b/iotbx/command_line/pdb_cif_conversion.py index 8ce34c6cba..d6db389207 100644 --- a/iotbx/command_line/pdb_cif_conversion.py +++ b/iotbx/command_line/pdb_cif_conversion.py @@ -7,7 +7,7 @@ =========================================================================== CCTBX methods, tools, and strategies for conversion of PDB-format based methods to mmCIF/PDB compatible methods -2024-01-30 TT +2024-01-30 2024-02-01 TT =========================================================================== =========================================================================== SECTIONS: @@ -17,24 +17,23 @@ RECOMMENDED OVERALL APPROACHES DETAILED SUGGESTIONS FOR MAKING CODE CIF-COMPLIANT USING THE PROGRAM TEMPLATE TO HANDLE PDB/MMCIF INPUT/OUTPUT - TOOLS AVAILABLE IF YOU CANNOT USE THE PROGRAM TEMPLATE REWRITING CODE USING PDB-FORMATTED TEXT TOOLS AVAILABLE TO FIND CODE THAT NEEDS TO BE MADE CIF-COMPATIBLE CREATING CIF TESTS TO CHECK CODE WITH MODELS THAT CANNOT FIT IN PDB FORMAT - USING FORWARD-COMPATIBLE PDB FORMAT FOR CODE REQUIRING PDB-FORMATTED TEXT DETAILS OF METHODS ADDED FOR WORKING WITH PDB/CIF + APPENDIX: TOOLS FOR EXCEPTIONAL CASES + USING FORWARD-COMPATIBLE PDB FORMAT FOR CODE REQUIRING PDB-FORMATTED TEXT + TOOLS AVAILABLE IF YOU CANNOT USE THE PROGRAM TEMPLATE =========================================================================== =========================================================================== SUMMARY OF RECOMMENDED PROCEDURES -I. USE THE PROGRAM TEMPLATE -II. TOOLS ARE AVAILABLE IF YOU CANNOT USE THE PROGRAM TEMPLATE -III. IF CODE USES PDB-FORMATTED TEXT IT SHOULD BE REWRITTEN -IV. TOOLS ARE AVAILABLE TO FIND CODE THAT NEEDS TO BE MADE CIF-COMPATIBLE -V. CREATE CIF TESTS TO CHECK CODE WITH MODELS THAT CANNOT FIT IN PDB FORMAT -VI. USE FORWARD-COMPATIBLE PDB FORMAT FOR CODE REQUIRING PDB-FORMATTED TEXT +I. USE THE PROGRAM TEMPLATE +II. IF CODE USES PDB-FORMATTED TEXT IT SHOULD BE REWRITTEN +III. TOOLS ARE AVAILABLE TO FIND CODE THAT NEEDS TO BE MADE CIF-COMPATIBLE +IV. CREATE CIF TESTS TO CHECK CODE WITH MODELS THAT CANNOT FIT IN PDB FORMAT =========================================================================== =========================================================================== @@ -59,9 +58,11 @@ 2. User specifies mmCIF, or 3. Input model is mmCIF and User does not specify which to use =========================================================================== +=========================================================================== + RECOMMENDED OVERALL APPROACHES +=========================================================================== =========================================================================== - RECOMMENDED OVERALL APPROACHES (DETAILS IN THE SECTION "DETAILED SUGGESTIONS FOR MAKING CODE CIF-COMPLIANT") I. USE THE PROGRAM TEMPLATE @@ -71,32 +72,7 @@ taken care of for you, except only that you need to capture the actual file names written by the data_manager. -II. TOOLS ARE AVAILABLE IF YOU CANNOT USE THE PROGRAM TEMPLATE - -For existing code that cannot use the Program Template or that -reads and writes files outside of the Program Template: - - a. Try to pass the data_manager from the Program Template and use - it to read/write files in your programs. Then once again you only - need to capture the actual file names written by the data_manager. - - b. If you cannot use the data_manager, use the pdb_or_mmcif_string_info - method of the model manager or the hierarchy to write your files. - This method allows setting the preferred output format and capturing - the name of the actual file that is written. - - Normally you should keep track of the actual file name that is written - and then use that later when you read the file back in. If you do - not use this approach, you can use the get_cif_or_pdb_file_if_present - tool from iotbx.pdb.utils with your guess of the file name, and it will - return the name of the file with that name if present, or the name of a - present file with the opposite extension if it is present instead, - or blank if neither is present. - - You can use the get_pdb_info tool from iotbx.pdb.utils or the - iotbx.pdb.input method to read in either mmCIF or PDB formatted files. - -III. IF CODE USES PDB-FORMATTED TEXT IT SHOULD BE REWRITTEN +II. IF CODE USES PDB-FORMATTED TEXT IT SHOULD BE REWRITTEN If code parses PDB-formatted text, generally it should be rewritten to use the methods in the hierarchy class. @@ -112,12 +88,11 @@ iotbx.pdb.utils, or simple custom code can be written to add chains from one hierarchy onto another hierarchy. - -IV. TOOLS ARE AVAILABLE TO FIND CODE THAT NEEDS TO BE MADE CIF-COMPATIBLE +III. TOOLS ARE AVAILABLE TO FIND CODE THAT NEEDS TO BE MADE CIF-COMPATIBLE You can find possibly-problematic code using the tool libtbx.find_pdb_mmcif_problems and specifying a file or directory to check -V. CREATE CIF TESTS TO CHECK CODE WITH MODELS THAT CANNOT FIT IN PDB FORMAT +IV. CREATE CIF TESTS TO CHECK CODE WITH MODELS THAT CANNOT FIT IN PDB FORMAT For any code that uses pdb/cif files or that uses the hierarchy object should be tested with models that do not fit in PDB format. It is recommended that each standard test using models should be duplicated @@ -126,37 +101,12 @@ tests so that identical starting strings can be used in the original and non-PDB-compliant tests. -VI. USING FORWARD-COMPATIBLE PDB FORMAT FOR CODE REQUIRING PDB-FORMATTED TEXT -If you have code or 3rd party code that requires PDB-formatted text you can -convert any hierarchy into a forward-compatible hierarchy that can be -formatted in PDB format (hybrid-36 PDB format). This conversion (currently) -amounts to replacing chainIDs that are longer than 2 characters with -2-character IDs, and residue names that are 5 characters long with -3-character residue names. A table of conversions is kept that allows -reversion of the hierarchy to its original form. - -a. This procedure is only partially supported and is not encouraged for - anything except cases that cannot be managed without PDB formatting. - -b. When this is done, it should be carried out either one-way (conversion - to forward-compatible PDB and never converted back), or else the - conversion should be carried out, the operation with the converted file - done, and the result converted back, all in one small block. - -c. Note that conversion may be very complicated if the chain IDs or the - residue names are needed in whatever operation is done with the - converted file. This is one of the reasons this approach is not - recommended except where required. Tools are supplied to convert - any text-based parameters are used with the converted file, but they - are not general and not always simple to use. - +=========================================================================== +=========================================================================== + DETAILED SUGGESTIONS FOR MAKING CODE CIF-COMPLIANT =========================================================================== =========================================================================== - DETAILED SUGGESTIONS FOR MAKING CODE CIF-COMPLIANT - ---------------------------------------------------------------------------- ---------------------------------------------------------------------------- I. USING THE PROGRAM TEMPLATE TO HANDLE PDB/MMCIF INPUT/OUTPUT A. Use the Program Template and use data_manager for @@ -183,56 +133,7 @@ def get_results(self): --------------------------------------------------------------------------- --------------------------------------------------------------------------- - -II. TOOLS AVAILABLE IF YOU CANNOT USE THE PROGRAM TEMPLATE - -If you do not use the Program template, you will need to keep track -of the target output format and write your files with a pdb/cif-aware -method. - -1. Add target_output_format to your "output" or "output_files" scope: - - target_output_format = *None pdb mmcif - .type = choice - .help = Desired output format (if possible). Choices are None (\ - try to use input format), pdb, mmcif. If output model\ - does not fit in pdb format, mmcif will be used. \ - Default is pdb. - .short_caption = Desired output format - -2. After you set up your parameters, set the target_output_format: - - from iotbx.pdb.utils import set_target_output_format_in_params - set_target_output_format_in_params(params) - -3. When you write model files, supply the target output format and - capture the actual file name written: - -a. If you have a data manager and a model object: - - file_name = self.data_manager.write_model_file( - model, self.params.output.file_name) - print("Model written to '%s'" %file_name) - -b. If have only a hierarchy and crystal_symmetry and params: - - info = ph.pdb_or_mmcif_string_info( - target_format = params.output_files.target_output_format, - target_filename = params.output.file_name, - write_file = True, - crystal_symmetry=crystal_symmetry) - file_name = info.file_name - print("Model written to '%s'" %file_name) - -c. When you read pdb/mmcif files, if you do not know the ending .pdb or - .mmcif, use the function get_cif_or_pdb_file_if_present: - - from iotbx.pdb.utils import get_cif_or_pdb_file_if_present - fn = get_cif_or_pdb_file_if_present(fn) - ---------------------------------------------------------------------------- ---------------------------------------------------------------------------- -III. REWRITING CODE USING PDB-FORMATTED TEXT +II. REWRITING CODE USING PDB-FORMATTED TEXT A. You will want to remove all instances of the following methods. None of these are mmcif-compliant: @@ -354,7 +255,7 @@ def get_results(self): --------------------------------------------------------------------------- --------------------------------------------------------------------------- -V. TOOLS AVAILABLE TO FIND CODE THAT NEEDS TO BE MADE CIF-COMPATIBLE +III. TOOLS AVAILABLE TO FIND CODE THAT NEEDS TO BE MADE CIF-COMPATIBLE A. You can use the libtbx.find_pdb_mmcif_problems to help identify code that needs to be modified to make it cif-compatible. @@ -414,7 +315,7 @@ def get_results(self): --------------------------------------------------------------------------- --------------------------------------------------------------------------- -V. CREATING CIF TESTS TO CHECK CODE WITH MODELS THAT CANNOT FIT IN PDB FORMAT +IV. CREATING CIF TESTS TO CHECK CODE WITH MODELS THAT CANNOT FIT IN PDB FORMAT You will want to create a cif-only version of all your tests that use models. The purpose of this is to test all the code that handles @@ -460,41 +361,11 @@ def get_results(self): so you don't overwrite xxx.cif with the new cif-formatted version of xxx.pdb ---------------------------------------------------------------------------- ---------------------------------------------------------------------------- -VI. USING FORWARD-COMPATIBLE PDB FORMAT FOR CODE REQUIRING PDB-FORMATTED TEXT - - The hierarchy class has tools to convert a hierarchy that cannot fit into - PDB format into one that can and to keep track of the conversion so that - it can be reversed. - - The main tools are: - - 1. Convert a hierarchy to one that fits in PDB format, saving conversion - information - fc_ph = ph.as_forward_compatible_hierarchy() - - 2. Get the conversion information: - conversion_info = fc_ph.conversion_info() - - 3. Convert back using saved conversion info : - original_ph = fc_ph.forward_compatible_hierarchy_as_standard() - - 4. Convert one-way to PDB format compatible string: - str = ph.as_forward_compatible_string() - - 5. Identify whether hierarchy has been converted: - is_fc = ph.is_forward_compatible_hierarchy() - - 6. Use saved conversion_info to edit text containing words matching - chain IDs or residue names, making new text match the chain IDs and - residue names used in the forward_compatible hierarchy: - new_text = ph.convert_multi_word_text_to_forward_compatible(text) - - These methods are described in detail in the hierarchy.py code. ---------------------------------------------------------------------------- ---------------------------------------------------------------------------- +=========================================================================== +=========================================================================== DETAILS OF METHODS ADDED FOR WORKING WITH PDB/CIF +=========================================================================== +=========================================================================== MODULE: iotbx/cli_parser.py @@ -667,6 +538,139 @@ def get_forward_compatible_pdb_text_from_full_text(self, =========================================================================== =========================================================================== + APPENDIX: TOOLS FOR EXCEPTIONAL CASES +=========================================================================== +=========================================================================== + +I. TOOLS AVAILABLE IF YOU CANNOT USE THE PROGRAM TEMPLATE + +For existing code that cannot use the Program Template or that +reads and writes files outside of the Program Template: + + a. Try to pass the data_manager from the Program Template and use + it to read/write files in your programs. Then once again you only + need to capture the actual file names written by the data_manager. + + b. If you cannot use the data_manager, use the pdb_or_mmcif_string_info + method of the model manager or the hierarchy to write your files. + This method allows setting the preferred output format and capturing + the name of the actual file that is written. + + Normally you should keep track of the actual file name that is written + and then use that later when you read the file back in. If you do + not use this approach, you can use the get_cif_or_pdb_file_if_present + tool from iotbx.pdb.utils with your guess of the file name, and it will + return the name of the file with that name if present, or the name of a + present file with the opposite extension if it is present instead, + or blank if neither is present. + + You can use the get_pdb_info tool from iotbx.pdb.utils or the + iotbx.pdb.input method to read in either mmCIF or PDB formatted files. + +Here is how you can do these things. Note that this only applies for +modules that really cannot use the Program template. + +1. Add target_output_format to your "output" or "output_files" scope: + + target_output_format = *None pdb mmcif + .type = choice + .help = Desired output format (if possible). Choices are None (\ + try to use input format), pdb, mmcif. If output model\ + does not fit in pdb format, mmcif will be used. \ + Default is pdb. + .short_caption = Desired output format + +2. After you set up your parameters, set the target_output_format: + + from iotbx.pdb.utils import set_target_output_format_in_params + set_target_output_format_in_params(params) + +3. When you write model files, supply the target output format and + capture the actual file name written: + +a. If you have a data manager and a model object: + + file_name = self.data_manager.write_model_file( + model, self.params.output.file_name) + print("Model written to '%s'" %file_name) + +b. If have only a hierarchy and crystal_symmetry and params: + + info = ph.pdb_or_mmcif_string_info( + target_format = params.output_files.target_output_format, + target_filename = params.output.file_name, + write_file = True, + crystal_symmetry=crystal_symmetry) + file_name = info.file_name + print("Model written to '%s'" %file_name) + +c. When you read pdb/mmcif files, if you do not know the ending .pdb or + .mmcif, use the function get_cif_or_pdb_file_if_present: + + from iotbx.pdb.utils import get_cif_or_pdb_file_if_present + fn = get_cif_or_pdb_file_if_present(fn) + +--------------------------------------------------------------------------- +--------------------------------------------------------------------------- + +II. USING FORWARD-COMPATIBLE PDB FORMAT FOR CODE REQUIRING PDB-FORMATTED TEXT + +If you have code or 3rd party code that requires PDB-formatted text you can +convert any hierarchy into a forward-compatible hierarchy that can be +formatted in PDB format (hybrid-36 PDB format). This conversion (currently) +amounts to replacing chainIDs that are longer than 2 characters with +2-character IDs, and residue names that are 5 characters long with +3-character residue names. A table of conversions is kept that allows +reversion of the hierarchy to its original form. + +a. This procedure is only partially supported and is not encouraged for + anything except cases that cannot be managed without PDB formatting. + +b. When this is done, it should be carried out either one-way (conversion + to forward-compatible PDB and never converted back), or else the + conversion should be carried out, the operation with the converted file + done, and the result converted back, all in one small block. + +c. Note that conversion may be very complicated if the chain IDs or the + residue names are needed in whatever operation is done with the + converted file. This is one of the reasons this approach is not + recommended except where required. Tools are supplied to convert + any text-based parameters are used with the converted file, but they + are not general and not always simple to use. + +d. The hierarchy class has tools to convert a hierarchy that cannot fit into + PDB format into one that can and to keep track of the conversion so that + it can be reversed. + + The main tools are: + + 1. Convert a hierarchy to one that fits in PDB format, saving conversion + information + fc_ph = ph.as_forward_compatible_hierarchy() + + 2. Get the conversion information: + conversion_info = fc_ph.conversion_info() + + 3. Convert back using saved conversion info : + original_ph = fc_ph.forward_compatible_hierarchy_as_standard() + + 4. Convert one-way to PDB format compatible string: + str = ph.as_forward_compatible_string() + + 5. Identify whether hierarchy has been converted: + is_fc = ph.is_forward_compatible_hierarchy() + + 6. Use saved conversion_info to edit text containing words matching + chain IDs or residue names, making new text match the chain IDs and + residue names used in the forward_compatible hierarchy: + new_text = ph.convert_multi_word_text_to_forward_compatible(text) + + These methods are described in detail in the hierarchy.py code. +=========================================================================== +=========================================================================== + + + ''' From f7d4554793d41f938ddd48b2512200e28dab7ec4 Mon Sep 17 00:00:00 2001 From: terwill Date: Fri, 2 Feb 2024 05:59:46 -0800 Subject: [PATCH 094/748] Move guess_chemical_elements to hierarchy; rename check_for_incorrect_spacings with set_element_ignoring_spacings --- iotbx/command_line/pdb_cif_conversion.py | 21 +++- iotbx/pdb/hierarchy.py | 31 +++++ iotbx/pdb/tst_utils.py | 25 ++++ iotbx/pdb/utils.py | 154 ++++++++++++++++++----- 4 files changed, 195 insertions(+), 36 deletions(-) diff --git a/iotbx/command_line/pdb_cif_conversion.py b/iotbx/command_line/pdb_cif_conversion.py index d6db389207..1e50107c68 100644 --- a/iotbx/command_line/pdb_cif_conversion.py +++ b/iotbx/command_line/pdb_cif_conversion.py @@ -415,13 +415,14 @@ def pdb_or_mmcif_string_info(self, Methods supplied so that code elsewhere does not need to parse PDB formatted strings to remove HETATM, TER, and BREAK records and to sort chains in order -of chain ID: +of chain ID, and to guess the element type of atoms where it is not specified: def remove_hetero(self): def contains_hetero(self): def contains_break_records(self): def remove_ter_or_break(self): def sort_chains_by_id(self): + def guess_chemical_elements(self, check_pseudo = False, MODULE: mmtbx/model/model.py: @@ -464,6 +465,7 @@ def add_hierarchy(s1_ph, s2_ph, create_new_chain_ids_if_necessary = True): def catenate_segment_onto_chain(model_chain, s2, gap = 1, def get_chain(s1_ph, chain_id = None): + Methods to merge and edit models: def add_model(s1, s2, create_new_chain_ids_if_necessary = True): @@ -471,6 +473,11 @@ def catenate_segments(s1, s2, gap = 1, def catenate_segment_onto_chain(model_chain, s2, gap = 1, def simple_combine(model_list, +Method to keep track of the relative numbering of models with +similar hierarchies: + +class numbering_dict: + Method to get hierarchy and pdb_input objects from text files. These differ from iotbx.pdb.input() and construct_hierarchy() by allowing empty text for both mmCIF and PDB input, and in packaging a hierarchy, pdb_input, and @@ -485,18 +492,20 @@ def get_pdb_info(text = None, file_name = None, lines = None, def get_pdb_hierarchy(text=None, file_name = None, def get_pdb_input(text = None, file_name = None, lines = None, -Helper methods for reading pdb_input text and getting hierarchy +Helper methods for reading pdb_input text and getting hierarchy, +allowing input of models that have incomplete or incorrect +atom and element specifications def lines_are_really_text(lines): def get_lines(text = None, file_name = None, lines = None): def type_of_pdb_input(pdb_inp): def try_to_get_hierarchy(pdb_inp): -Methods to guess elements in atoms object from a hierarchy: +Methods to check for missing elements and incorrect spacings in +atom names in a hierarchy: -def check_for_missing_elements(atoms, file_name = None): -def guess_chemical_elements(atoms, check_pseudo = False, -def check_for_incorrect_spacings(atoms): +def check_for_missing_elements(hierarchy, file_name = None): +def set_element_ignoring_spacings(hierarchy): Method checking for atom names starting with "Z" (used as pseudo-atoms) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index e33c95d327..54bab19d4b 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -1661,6 +1661,37 @@ def contains_break_records(self): is_first_in_chain = False return False + def guess_chemical_elements(self, + check_pseudo = False, + convert_atom_names_to_uppercase = True, + allow_incorrect_spacing = None): + ''' Attempt to guess chemical elements for all atoms in hierarchy + where this is not set. Normally used only just after reading in + PDB-formatted files that do not have elements specified + ''' + # Standard set of chemical elements based on atom names (and leading spaces) + atoms = self.atoms() + if convert_atom_names_to_uppercase: + for at in atoms: + at.name = at.name.upper() + atoms.set_chemical_element_simple_if_necessary() + + # Check to see if all have an element now + elements = atoms.extract_element().strip() + if elements.all_ne(""): # all done + return + + # Check for incorrect spacings (atom name has space before it but should + # not or opposite) + if allow_incorrect_spacing: + from iotbx.pdb.utils import set_element_ignoring_spacings + set_element_ignoring_spacings(self) + + # Check for pseudo-atoms (ZU ZC etc that represent groups of atoms) + if check_pseudo: + from iotbx.pdb.utils import check_for_pseudo_atoms + check_for_pseudo_atoms(self) + def as_mmcif_string(self, crystal_symmetry=None, data_block_name=None, diff --git a/iotbx/pdb/tst_utils.py b/iotbx/pdb/tst_utils.py index 37a04c0dfe..ed3b181e4c 100644 --- a/iotbx/pdb/tst_utils.py +++ b/iotbx/pdb/tst_utils.py @@ -15,6 +15,17 @@ ATOM 10 CA ASN A 141 30.271 17.061 23.474 1.00 5.65 C """ +pseudo_as_pdb=""" +ATOM 10 CA ASN A 141 30.271 17.061 23.474 1.00 5.65 +ATOM 24 ZC1' GC U 11 10.024 9.813 3.777 1.00 36.50 UNK +""" +spacing_as_pdb=""" +ATOM 10 I ASN A 141 30.271 17.061 23.474 1.00 5.65 +ATOM 11 I ASN A 141 30.271 17.061 23.474 1.00 5.65 +HETATM 12 I LIG A 141 30.271 17.061 23.474 1.00 5.65 +HETATM 13 I LIG A 141 30.271 17.061 23.474 1.00 5.65 +""" + as_pdb = pdb_str_to_be_cif # Convert pdb_str_hybrid_residues to mmcif: from libtbx.test_utils import convert_pdb_to_cif_for_pdb_str @@ -26,6 +37,18 @@ def exercise_all_chain_ids(): assert len(ids)==3906 assert len(set(ids))==3906 +def exercise_set_element_ignoring_spacings(): + from iotbx.pdb.utils import get_pdb_info + pdb_info = get_pdb_info(spacing_as_pdb, allow_incorrect_spacing = True) + from iotbx.pdb.utils import set_element_ignoring_spacings + set_element_ignoring_spacings(pdb_info.hierarchy) + +def exercise_check_pseudo_atoms(): + from iotbx.pdb.utils import get_pdb_info + pdb_info = get_pdb_info(pseudo_as_pdb, check_pseudo = True) + from iotbx.pdb.utils import check_for_pseudo_atoms + check_for_pseudo_atoms(pdb_info.hierarchy) + def exercise_get_pdb_info(): from iotbx.pdb.utils import get_pdb_info pdb_info_from_pdb = get_pdb_info(as_pdb) @@ -41,6 +64,8 @@ def exercise_get_pdb_info(): pdb_info_from_cif.crystal_symmetry) def run(): + exercise_set_element_ignoring_spacings() + exercise_check_pseudo_atoms() exercise_get_pdb_info() exercise_all_chain_ids() print("OK") diff --git a/iotbx/pdb/utils.py b/iotbx/pdb/utils.py index 6f37e11fae..ee13e8f967 100644 --- a/iotbx/pdb/utils.py +++ b/iotbx/pdb/utils.py @@ -346,7 +346,8 @@ def get_lines(text = None, file_name = None, lines = None): from cctbx.array_family import flex return flex.split_lines(text) -def check_for_missing_elements(atoms, file_name = None): +def check_for_missing_elements(hierarchy, file_name = None): + atoms = hierarchy.atoms() elements = atoms.extract_element().strip() if (not elements.all_ne("")): n_missing = elements.count("") @@ -423,15 +424,14 @@ def get_pdb_input(text = None, file_name = None, lines = None, if type_of_pdb_input(pdb_inp) == 'pdb': # Guess elements if missing for PDB ph = try_to_get_hierarchy(pdb_inp) - atoms = ph.atoms() - guess_chemical_elements(atoms, check_pseudo = check_pseudo, + ph.guess_chemical_elements(check_pseudo = check_pseudo, allow_incorrect_spacing = allow_incorrect_spacing) - check_for_missing_elements(ph.atoms()) + check_for_missing_elements(ph) else: # Make sure we have an element for each atom # try to construct and save empty ph if fails ph = try_to_get_hierarchy(pdb_inp) - check_for_missing_elements(ph.atoms()) + check_for_missing_elements(ph) # Return what is requested if return_group_args: @@ -446,28 +446,16 @@ def get_pdb_input(text = None, file_name = None, lines = None, else: return pdb_inp -def guess_chemical_elements(atoms, check_pseudo = False, - allow_incorrect_spacing = None): - # Standard set of chemical elements based on atom names (and leading spaces) - for at in atoms: - at.name = at.name.upper() - atoms.set_chemical_element_simple_if_necessary() - # Check to see if all have an element now - elements = atoms.extract_element().strip() - if elements.all_ne(""): # all done - return - - # Check for incorrect spacings (atom name has space before it but should - # not or opposite) - if allow_incorrect_spacing: - check_for_incorrect_spacings(atoms) - - # Check for pseudo-atoms (ZU ZC etc that represent groups of atoms) - if check_pseudo: - check_for_pseudo_atoms(atoms) +def set_element_ignoring_spacings(hierarchy): + ''' Set missing elements ignoring spacings. This allows + reading a PDB file where there are no elements given and the + atom names are not justified properly. Intended for hetero atoms + even if they are not marked as such. Normally try to set + elements in normal way first. + ''' -def check_for_incorrect_spacings(atoms): + atoms = hierarchy.atoms() elements = atoms.extract_element().strip() sel = (elements == "") atoms_sel = atoms.select(sel) @@ -478,9 +466,9 @@ def check_for_incorrect_spacings(atoms): at.name = " "+at.name[:3] atoms.set_chemical_element_simple_if_necessary() -def check_for_pseudo_atoms(atoms): +def check_for_pseudo_atoms(hierarchy): # Check for special case where PDB input contains pseudo-atoms ZC ZU etc - + atoms = hierarchy.atoms() # Do we already have all the elements elements = atoms.extract_element().strip() if elements.all_ne(""): # all done @@ -533,8 +521,9 @@ def try_to_get_hierarchy(pdb_inp): atoms are present. Modify this text to match the assertion if necessary""" raise Sorry(ph_text+"\n"+text+"\n"+str(e)) + def add_model(s1, s2, create_new_chain_ids_if_necessary = True): - ''' add chains from s2 to existing s1''' + ''' Add chains from s2 to existing s1 to create new composite model''' if not s1: s2.reset_after_changing_hierarchy() return s2 @@ -572,9 +561,11 @@ def add_model(s1, s2, create_new_chain_ids_if_necessary = True): for model_mm in s1_ph.models()[:1]: model_mm.append_chain(new_chain) s1.reset_after_changing_hierarchy() + + # Handle model.info().numbering_dict if present if hasattr(s1,'info') and s1.info().get('numbering_dict') and \ hasattr(s2,'info') and s2.info().get('numbering_dict'): - s1.info().numbering_dict.add_from_other(s2.info().numbering_dict) # XXX fixed... never should have worked before + s1.info().numbering_dict.add_from_other(s2.info().numbering_dict) return s1 def catenate_segments(s1, s2, gap = 1, @@ -645,7 +636,7 @@ def simple_combine(model_list, model = None for m in model_list: if not model: - model = m + model = m # ZZZ why cannot this be a deep_copy? else: model = add_model(model, m, create_new_chain_ids_if_necessary = create_new_chain_ids_if_necessary) @@ -675,6 +666,109 @@ def get_cif_or_pdb_file_if_present(file_name): else: return "" # return empty string so os.path.isfile(return_value) works +class numbering_dict: + ''' Set up a dict that keeps track of chain ID, residue ID and icode for + residues relative to their initial values + dict with keys of original residue chain ID, resseq, icode + inverse_dict with keys of current, values of original + ''' + def __init__(self, m): + self.file_name = m.info().file_name + self.ph = m.get_hierarchy().deep_copy() + self.dd = self.get_dict(m) # keys are original, values current + self.get_inverse_dict() # keys are current, values original + + def show_summary(self): + print("Summary of numbering dict for %s: " %(self.file_name)) + for model in self.ph.models(): + for chain in model.chains(): + for rg in chain.residue_groups(): + for conformer in rg.conformers(): + r = conformer.only_residue() + key = self.get_key(r) + print(key, self.original_key_from_current(key)) + + def update(self, new_m): + ''' Update the dicts to refer to new current model + new_m must be similar hierarchy to previous current model + ''' + new_dd = {} + new_ph = new_m.get_hierarchy() + ph = self.ph + + + for new_model, model in zip(new_ph.models()[:1], ph.models()[:1]): + for new_chain, chain in zip(new_model.chains(), model.chains()): + for new_rg, rg in zip(new_chain.residue_groups(), chain.residue_groups()): + for new_conformer, conformer in zip( + new_rg.conformers(), + rg.conformers()): + new_r = new_conformer.only_residue() + r = conformer.only_residue() + + new_key = self.get_key(new_r) + key = self.get_key(r) + original_key = self.original_key_from_current(key) + new_dd[original_key] = new_key + self.dd = new_dd + self.ph = new_ph.deep_copy() + self.get_inverse_dict() + + def get_original_key_list_from_atoms(self, atoms): + original_key_list = [] + for key in self.get_key_list_from_atoms(atoms): + original_key_list.append(self.original_key_from_current(key)) + return original_key_list + + def get_key_list_from_atoms(self, atoms): + key_list = [] + for a in atoms: + rg = a.parent().parent() + for c in rg.conformers(): + r = c.only_residue() + key_list.append(self.get_key(r)) + return key_list + + def add_from_other(self, other): + for key in other.dd.keys(): + self.dd[key] = other.dd[key] + self.get_inverse_dict() + + def get_key(self, r): + conformer = r.parent() + chain = conformer.parent() + return "%s %s %s %s" %(r.resname, chain.id, r.resseq, r.icode) + + def current_key_from_current_r(self,r): + return self.get_key(r) + + def original_key_from_current_r(self,r): + key = self.get_key(r) + return self.original_key_from_current(key) + + def original_key_from_current(self, key): + return self.inverse_dict[key] + + def current_key_from_original(self, key): + return self.dd[key] + + def get_inverse_dict(self): + self.inverse_dict = {} + for key in self.dd.keys(): + self.inverse_dict[self.dd[key]] = key + + def get_dict(self, m): + dd = {} + ph = m.get_hierarchy() + for model in ph.models()[:1]: + for chain in model.chains(): + for rg in chain.residue_groups(): + for conformer in rg.conformers(): + r = conformer.only_residue() + key = self.get_key(r) + dd[key] = key + return dd + if __name__ == '__main__': import time l=0 From ed154c0dd21eb9d1e8b45cc3e1fd15df75fa8002 Mon Sep 17 00:00:00 2001 From: terwill Date: Sat, 3 Feb 2024 10:52:25 -0800 Subject: [PATCH 095/748] Clean up add_models/add_hierarchies --- iotbx/command_line/pdb_cif_conversion.py | 36 ++- iotbx/pdb/tst_utils.py | 32 +++ iotbx/pdb/utils.py | 275 +++++++++++-------- mmtbx/regression/tst_chain_comparison_cif.py | 1 + mmtbx/secondary_structure/find_ss_from_ca.py | 16 -- 5 files changed, 220 insertions(+), 140 deletions(-) diff --git a/iotbx/command_line/pdb_cif_conversion.py b/iotbx/command_line/pdb_cif_conversion.py index 1e50107c68..ddda48508d 100644 --- a/iotbx/command_line/pdb_cif_conversion.py +++ b/iotbx/command_line/pdb_cif_conversion.py @@ -84,7 +84,7 @@ b. All code that accumulates lines from multiple PDB files and then interprets the new lines should be replaced by reading each PDB file and merging the resulting hierarchies or models. This can be done for model files - with the simple_combine or add_hierarchies methods available in + with the add_models or add_hierarchies methods available in iotbx.pdb.utils, or simple custom code can be written to add chains from one hierarchy onto another hierarchy. @@ -142,9 +142,19 @@ def get_results(self): ph.as_pdb_string() ph.write_pdb_file() -Suggested replacements: +The best replacement in all cases is to use the Program template, pass +the data_manager into any modules that write out models, and +use the data_manager to write your model files. If you only have a +hierarchy you can still say: - 1. If your code uses model.model_as_pdb(): + m = hierarchy.as_model_manager(crystal_symmetry = crystal_symmetry) + file_name = 'mypdb.pdb' + file_name = data_manager.write_model_file(m, file_name) + +If for some reason you cannot use the data_manager to write files, +here are some alternatives: + + 1. If your code uses model.model_as_pdb() like this: file_name = 'mypdb.pdb' str = model.model_as_pdb() @@ -153,7 +163,7 @@ def get_results(self): f.close() print("Wrote model to '%s'" %file_name) - Use instead model.pdb_or_mmcif_string_info(): + then use instead model.pdb_or_mmcif_string_info(): file_name = 'mypdb.pdb' info = model.pdb_or_mmcif_string_info( @@ -228,8 +238,8 @@ def get_results(self): new_file_name = 'combined.pdb' m1 = dm.get_model_file(model_file) m2 = dm.get_model_file(other_model_file) - from iotbx.pdb.utils import simple_combine - m1 = simple_combine(model_list = [m1,m2]) # NOTE: changes m1 in place + from iotbx.pdb.utils import add_models + m1 = add_models(model_list = [m1,m2]) new_file_name = dm.write_model_file(m1, new_file_name) # capture actual name print("Wrote combined model lines to '%s'" %new_file_name) @@ -460,18 +470,18 @@ def get_cif_or_pdb_file_if_present(file_name): Methods to merge hierarchies: -def add_hierarchies(ph_list, create_new_chain_ids_if_necessary = True): -def add_hierarchy(s1_ph, s2_ph, create_new_chain_ids_if_necessary = True): -def catenate_segment_onto_chain(model_chain, s2, gap = 1, -def get_chain(s1_ph, chain_id = None): +def add_hierarchies(hierarchies, create_new_chain_ids_if_necessary = True): +def add_hierarchy(hierarchy, other, create_new_chain_ids_if_necessary = True): +def catenate_segment_onto_chain(chain, model, gap = 1, +def get_chain(hierarchy, chain_id = None): Methods to merge and edit models: -def add_model(s1, s2, create_new_chain_ids_if_necessary = True): -def catenate_segments(s1, s2, gap = 1, +def catenate_segments(model, other, gap = 1, def catenate_segment_onto_chain(model_chain, s2, gap = 1, -def simple_combine(model_list, +def add_models(model_list, +def add_model(model, other, create_new_chain_ids_if_necessary = True): Method to keep track of the relative numbering of models with similar hierarchies: diff --git a/iotbx/pdb/tst_utils.py b/iotbx/pdb/tst_utils.py index ed3b181e4c..00f40eb6b6 100644 --- a/iotbx/pdb/tst_utils.py +++ b/iotbx/pdb/tst_utils.py @@ -15,6 +15,20 @@ ATOM 10 CA ASN A 141 30.271 17.061 23.474 1.00 5.65 C """ +pdb_str_other=""" +CRYST1 40.339 36.116 46.266 90.00 90.00 90.00 P 1 +ATOM 1 CA ASP DXYB2 34.633 18.762 20.254 1.00 22.59 C +ATOM 2 CA LYS DXYB3 36.047 17.704 23.610 1.00 19.79 C +ATOM 3 CA ILE DXYB4 35.551 19.482 26.886 1.00 19.33 C +ATOM 4 CA AHIS DXYB5 38.649 21.223 28.218 0.50 19.79 C +ATOM 5 CA BHIS DXYB6 38.583 21.270 28.209 0.50 20.43 C +ATOM 6 CA GLY D 138 38.261 15.285 27.690 1.00 6.80 C +ATOM 7 CA ALA D 139 34.607 14.241 27.428 1.00 4.76 C +ATOM 8 CA ALEU D 140 33.091 14.490 23.937 0.50 5.08 C +ATOM 9 CA BLEU D 140 33.072 14.565 23.972 0.50 5.41 C +ATOM 10 CA ASN D 141 30.271 17.061 23.474 1.00 5.65 C +""" + pseudo_as_pdb=""" ATOM 10 CA ASN A 141 30.271 17.061 23.474 1.00 5.65 ATOM 24 ZC1' GC U 11 10.024 9.813 3.777 1.00 36.50 UNK @@ -27,16 +41,33 @@ """ as_pdb = pdb_str_to_be_cif +other_as_pdb = pdb_str_other + # Convert pdb_str_hybrid_residues to mmcif: from libtbx.test_utils import convert_pdb_to_cif_for_pdb_str convert_pdb_to_cif_for_pdb_str(locals(), chain_addition="ZXLONG") as_cif = pdb_str_to_be_cif # now it is cif +other_as_cif = pdb_str_other# now it is cif def exercise_all_chain_ids(): ids = iotbx.pdb.utils.all_chain_ids() assert len(ids)==3906 assert len(set(ids))==3906 +def exercise_add_models_and_hierarchies(): + from iotbx.pdb.utils import get_pdb_info, add_models, add_hierarchies + ph1 = get_pdb_info(as_pdb).hierarchy + ph2 = get_pdb_info(other_as_pdb).hierarchy + m1 = ph1.as_model_manager(crystal_symmetry = None) + m2 = ph2.as_model_manager(crystal_symmetry = None) + ph = add_hierarchies(hierarchy_list = [ph1,ph2]) + ph2a = ph.apply_atom_selection("chain D") + assert ph2.is_similar_hierarchy(ph2a) + m = add_models(model_list = [m1,m2]) + ph1a = m.get_hierarchy().apply_atom_selection("chain A") + assert ph1a.is_similar_hierarchy(ph1) + + def exercise_set_element_ignoring_spacings(): from iotbx.pdb.utils import get_pdb_info pdb_info = get_pdb_info(spacing_as_pdb, allow_incorrect_spacing = True) @@ -64,6 +95,7 @@ def exercise_get_pdb_info(): pdb_info_from_cif.crystal_symmetry) def run(): + exercise_add_models_and_hierarchies() exercise_set_element_ignoring_spacings() exercise_check_pseudo_atoms() exercise_get_pdb_info() diff --git a/iotbx/pdb/utils.py b/iotbx/pdb/utils.py index ee13e8f967..8706488a42 100644 --- a/iotbx/pdb/utils.py +++ b/iotbx/pdb/utils.py @@ -277,52 +277,10 @@ def catenate_segment_onto_chain(model_chain, s2, gap = 1, awl = atom.fetch_labels() atom.segid = new_segid -def add_hierarchies(ph_list, create_new_chain_ids_if_necessary = True): - new_ph_list = [] - for ph in ph_list: - if ph: - new_ph_list.append(ph) - if not new_ph_list: - return None - ph = ph_list[0] - for i in range(1, len(ph_list)): - ph = add_hierarchy(ph, ph_list[i], create_new_chain_ids_if_necessary = - create_new_chain_ids_if_necessary) - return ph - - -def add_hierarchy(s1_ph, s2_ph, create_new_chain_ids_if_necessary = True): - ''' Add chains from hierarchy s2_ph to existing hierarchy s1_ph''' - if not s1_ph: - return s2_ph - s1_ph = s1_ph.deep_copy() - if not s2_ph: - return s1_ph - existing_chain_ids = s1_ph.chain_ids() - for model_mm_2 in s2_ph.models()[:1]: - for chain in model_mm_2.chains(): - if chain.id in existing_chain_ids: # duplicate chains in add_model - if not create_new_chain_ids_if_necessary: - # append to existing chain - existing_chain = get_chain(s1_ph, chain_id = chain.id) - catenate_segment_onto_chain(existing_chain, None, gap = 1, - keep_numbers = True, insertion_chain= chain.detached_copy()) - continue - else: - chain.id = get_new_chain_id(existing_chain_ids) - new_chain = chain.detached_copy() - existing_chain_ids.append(chain.id) - for model_mm in s1_ph.models()[:1]: - model_mm.append_chain(new_chain) - return s1_ph - -def get_chain(s1_ph, chain_id = None): - for model in s1_ph.models(): - for chain in model.chains(): - if chain.id == chain_id: - return chain - def lines_are_really_text(lines): + ''' Catch case where lines are supplied but actually it is just text, + not a list or flex array of lines + ''' if lines and type(lines) in (type('abc'), type(b'abc')): return True else: @@ -446,11 +404,10 @@ def get_pdb_input(text = None, file_name = None, lines = None, else: return pdb_inp - def set_element_ignoring_spacings(hierarchy): ''' Set missing elements ignoring spacings. This allows reading a PDB file where there are no elements given and the - atom names are not justified properly. Intended for hetero atoms + atom names are not justified properly. Intended for hetero atoms even if they are not marked as such. Normally try to set elements in normal way first. ''' @@ -521,27 +478,119 @@ def try_to_get_hierarchy(pdb_inp): atoms are present. Modify this text to match the assertion if necessary""" raise Sorry(ph_text+"\n"+text+"\n"+str(e)) +def add_hierarchies(hierarchy_list, create_new_chain_ids_if_necessary = True): + if not hierarchy_list: + return None + new_hierarchy_list = [] + for hierarchy in hierarchy_list: + if hierarchy and (hierarchy.overall_counts().n_residues > 0): + new_hierarchy_list.append(hierarchy) + hierarchy_list = new_hierarchy_list + if not hierarchy_list: + return None + + hierarchy = hierarchy_list[0] + for ph in hierarchy_list[1:]: + hierarchy = add_hierarchy(hierarchy, ph, + create_new_chain_ids_if_necessary = create_new_chain_ids_if_necessary) + return hierarchy + +def add_hierarchy(hierarchy, other, create_new_chain_ids_if_necessary = True): + ''' Add chains from hierarchy other to existing hierarchy. + Only adds chains from first model in other hierarchy''' + if not hierarchy: + return other + hierarchy = hierarchy.deep_copy() + if not other: + return hierarchy + existing_chain_ids = hierarchy.chain_ids() + for model in other.models()[:1]: + for chain in model.chains(): + if chain.id in existing_chain_ids: # duplicate chains in add_model + if not create_new_chain_ids_if_necessary: + # append to existing chain + existing_chain = get_chain(hierarchy, chain_id = chain.id) + catenate_segment_onto_chain(existing_chain, None, gap = 1, + keep_numbers = True, insertion_chain= chain.detached_copy()) + continue + else: + chain.id = get_new_chain_id(existing_chain_ids) + new_chain = chain.detached_copy() + existing_chain_ids.append(chain.id) + for model_mm in hierarchy.models()[:1]: + model_mm.append_chain(new_chain) + hierarchy.remove_ter_or_break() + return hierarchy + +def get_chain(hierarchy, chain_id = None): + for model in hierarchy.models(): + for chain in model.chains(): + if chain.id == chain_id: + return chain -def add_model(s1, s2, create_new_chain_ids_if_necessary = True): - ''' Add chains from s2 to existing s1 to create new composite model''' - if not s1: - s2.reset_after_changing_hierarchy() - return s2 - s1.add_crystal_symmetry_if_necessary() - s1 = s1.deep_copy() - if not s2: - s1.reset_after_changing_hierarchy() - return s1 - s1_ph = s1.get_hierarchy() # working hierarchy +def add_models(model_list, create_new_chain_ids_if_necessary = True): + ''' Method to combine the chains in a set of models to create a new + model with all the chains. + param: model_list: list of model objects + param: create_new_chain_ids_if_necessary: If True (default), if a + model has a duplicate chain ID, create a new one and rename it + returns: first model in model_list with all chains from all models. + ''' + + if not model_list: + return None # nothing to do + new_model_list = [] + for m in model_list: + if m and (m.get_hierarchy().overall_counts().n_residues > 0): + new_model_list.append(m) + model_list = new_model_list + if not model_list: + return None # nothing to do + + if model_list[0].crystal_symmetry() is not None: + model_list[0] = model_list[0].deep_copy() + m_had_crystal_symmetry = True + else: # Need crystal symmetry for deep_copy of model + crystal_symmetry = None + for m in model_list: + if m.crystal_symmetry() and (not crystal_symmetry): + crystal_symmetry = m.crystal_symmetry() + break + # Can deep-copy a hierarchy without crystal_symmetry + ph = model_list[0].get_hierarchy().deep_copy() + model_list[0] = ph.as_model_manager(crystal_symmetry = crystal_symmetry) + model_list[0].add_crystal_symmetry_if_necessary() + m_had_crystal_symmetry = False + + model = model_list[0] + for m in model_list[1:]: + model = add_model(model, m, + create_new_chain_ids_if_necessary = create_new_chain_ids_if_necessary) + + if not m_had_crystal_symmetry: + model = model.get_hierarchy().as_model_manager(crystal_symmetry = None) + return model + +def add_model(model, other, create_new_chain_ids_if_necessary = True): + ''' Add chains from other to existing model to create new composite model''' + if not model: + other.reset_after_changing_hierarchy() + return other + model.add_crystal_symmetry_if_necessary() + model = model.deep_copy() + if not other: + model.reset_after_changing_hierarchy() + return model + model_ph = model.get_hierarchy() # working hierarchy existing_chain_ids = [] - from mmtbx.secondary_structure.find_ss_from_ca import get_new_chain_id - for model_mm1 in s1_ph.models()[:1]: + for model_mm1 in model_ph.models()[:1]: for chain in model_mm1.chains(): if not chain.id.strip(): chain.id = get_new_chain_id(existing_chain_ids) - existing_chain_ids = s1_ph.chain_ids() - for model_mm_2 in s2.get_hierarchy().models()[:1]: - for chain in model_mm_2.chains(): + existing_chain_ids = model_ph.chain_ids() + + for model_mm2 in other.get_hierarchy().models()[:1]: + for chain in model_mm2.chains(): if not chain.id.strip(): chain.id = get_new_chain_id(existing_chain_ids) @@ -550,7 +599,7 @@ def add_model(s1, s2, create_new_chain_ids_if_necessary = True): # append to existing chain from iotbx.pdb.utils import get_chain from iotbx.pdb.utils import catenate_segment_onto_chain - existing_chain = get_chain(s1_ph, chain_id = chain.id) + existing_chain = get_chain(model_ph, chain_id = chain.id) catenate_segment_onto_chain(existing_chain, None, gap = 1, keep_numbers = True, insertion_chain= chain.detached_copy()) continue @@ -558,53 +607,74 @@ def add_model(s1, s2, create_new_chain_ids_if_necessary = True): chain.id = get_new_chain_id(existing_chain_ids) new_chain = chain.detached_copy() existing_chain_ids.append(chain.id) - for model_mm in s1_ph.models()[:1]: + for model_mm in model_ph.models()[:1]: model_mm.append_chain(new_chain) - s1.reset_after_changing_hierarchy() + # Remove TER/BREAK + model.get_hierarchy().remove_ter_or_break() + model.reset_after_changing_hierarchy() # Handle model.info().numbering_dict if present - if hasattr(s1,'info') and s1.info().get('numbering_dict') and \ - hasattr(s2,'info') and s2.info().get('numbering_dict'): - s1.info().numbering_dict.add_from_other(s2.info().numbering_dict) - return s1 + if hasattr(model,'info') and model.info().get('numbering_dict') and \ + hasattr(other,'info') and other.info().get('numbering_dict'): + model.info().numbering_dict.add_from_other(other.info().numbering_dict) + return model -def catenate_segments(s1, s2, gap = 1, +def get_new_chain_id(existing_chain_ids): + # Generate something new... + lc = "abcdefghijklmnopqrstuvwxyz" + uc = lc.upper() + cc = uc+lc + eci = [] + for x in existing_chain_ids: + eci.append(x.strip()) + existing_chain_ids = eci + for b in " "+cc: + for a in cc: + d = (a+b).strip() + if not d in existing_chain_ids: + return d + raise AssertionError ("Not able to generate a new chain ID") + + +def catenate_segments(model, other, gap = 1, keep_numbers = False): ''' - catenate two models and renumber starting with first residue of s1 - if gap is set, start s2 gap residue numbers higher than the end of s1 + catenate two models and renumber starting with first residue of model + if gap is set, start other gap residue numbers higher than the end of model if keep_numbers is set, just keep all the residue numbers ''' - s1 = s1.deep_copy() - s1 = s1.apply_selection_string("not (name OXT)") # get rid of these - s1_ph = s1.get_hierarchy() # working hierarchy - for model_mm in s1_ph.models()[:1]: + model = model.deep_copy() + model = model.apply_selection_string("not (name OXT)") # get rid of these + model_ph = model.get_hierarchy() # working hierarchy + for model_mm in model_ph.models()[:1]: for model_chain in model_mm.chains()[:1]: from iotbx.pdb.utils import catenate_segment_onto_chain catenate_segment_onto_chain( model_chain, - s2, + other, gap = gap, keep_numbers = keep_numbers) - s1.reset_after_changing_hierarchy() - return s1 -def catenate_segment_onto_chain(model_chain, s2, gap = 1, + model.reset_after_changing_hierarchy() + return model + +def catenate_segment_onto_chain(chain, other_model, gap = 1, keep_numbers = False, insertion_chain = None): - ''' catenate residues from s2 onto model_chain''' + ''' catenate residues from other (mmtbx.model object) onto chain. + Only includes first chain of first model in other''' from iotbx.pdb import resseq_encode - if not model_chain: + if not chain: return if not insertion_chain: - s2_as_ph = s2.get_hierarchy() - if not s2_as_ph.overall_counts().n_residues > 0: + other_model_as_ph = other_model.get_hierarchy() + if not other_model_as_ph.overall_counts().n_residues > 0: return - insertion_chain = s2.get_hierarchy().models()[0].chains()[0] - new_segid = model_chain.residue_groups( + insertion_chain = other_model.get_hierarchy().models()[0].chains()[0] + new_segid = chain.residue_groups( )[0].atom_groups()[0].atoms()[0].segid highest_resseq = None - if len(model_chain.residue_groups()) > 0: - highest_resseq = model_chain.residue_groups()[0].resseq_as_int() - for rg in model_chain.residue_groups(): + if len(chain.residue_groups()) > 0: + highest_resseq = chain.residue_groups()[0].resseq_as_int() + for rg in chain.residue_groups(): rg_resseq = rg.resseq_as_int() highest_resseq=max(highest_resseq,rg_resseq) resseq_as_int = highest_resseq + (gap - 1) @@ -613,7 +683,7 @@ def catenate_segment_onto_chain(model_chain, s2, gap = 1, rg_copy = rg.detached_copy() if (not keep_numbers): rg_copy.resseq = resseq_encode(resseq_as_int) - model_chain.append_residue_group( + chain.append_residue_group( residue_group = rg_copy) rg_copy.link_to_previous = True # Required for ag in rg_copy.atom_groups(): @@ -621,26 +691,6 @@ def catenate_segment_onto_chain(model_chain, s2, gap = 1, awl = atom.fetch_labels() atom.segid = new_segid -def simple_combine(model_list, - create_new_chain_ids_if_necessary = True): - ''' Method to combine the chains in a set of models to create a new - model with all the chains. - param: model_list: list of model objects - param: create_new_chain_ids_if_necessary: If True (default), if a - model has a duplicate chain ID, create a new one and rename it - returns: first model in model_list with all chains from all models. - NOTE: first model in model_list is modified by this method. Make - a deep_copy before hand if you want to keep it. - ''' - - model = None - for m in model_list: - if not model: - model = m # ZZZ why cannot this be a deep_copy? - else: - model = add_model(model, m, - create_new_chain_ids_if_necessary = create_new_chain_ids_if_necessary) - return model def get_cif_or_pdb_file_if_present(file_name): ''' Identify whether a file with the name file_name or with @@ -648,6 +698,9 @@ def get_cif_or_pdb_file_if_present(file_name): If file_name is present, return file_name. If not, and alternative is present, return alternative file name Otherwise return empty string + NOTE: This is not intended for use on initial read-in of models. That + should be done by the DataManager. This is only for intermediate files + in modules where it is not feasible to use the DataManager. ''' import os diff --git a/mmtbx/regression/tst_chain_comparison_cif.py b/mmtbx/regression/tst_chain_comparison_cif.py index b599829254..e9d9d8b791 100644 --- a/mmtbx/regression/tst_chain_comparison_cif.py +++ b/mmtbx/regression/tst_chain_comparison_cif.py @@ -848,6 +848,7 @@ def tst_06(): print("OK") if __name__=="__main__": + tst_06() # ZZZ tst_01() tst_02() tst_03() diff --git a/mmtbx/secondary_structure/find_ss_from_ca.py b/mmtbx/secondary_structure/find_ss_from_ca.py index a72fd7d4ba..c954edf229 100644 --- a/mmtbx/secondary_structure/find_ss_from_ca.py +++ b/mmtbx/secondary_structure/find_ss_from_ca.py @@ -342,22 +342,6 @@ def compress_indices(values): return new_compressed_values ######## END Methods for getting selection strings from a model ############ -def get_new_chain_id(existing_chain_ids): - # Generate something new... - lc = "abcdefghijklmnopqrstuvwxyz" - uc = lc.upper() - cc = uc+lc - eci = [] - for x in existing_chain_ids: - eci.append(x.strip()) - existing_chain_ids = eci - for b in " "+cc: - for a in cc: - d = (a+b).strip() - if not d in existing_chain_ids: - return d - raise AssertionError ("Not able to generate a new chain ID") - def is_close_to(r,last_r,distance_cutoff=None,use_default_distance_cutoff=True): if not r or not last_r: From 54727e750100f81603453e7069899469221d157c Mon Sep 17 00:00:00 2001 From: terwill Date: Sun, 4 Feb 2024 15:52:26 -0700 Subject: [PATCH 096/748] Split pdb_or_mmcif_info into write_pdb_or_mmcif_file and as_pdb_or_mmcif_string --- iotbx/command_line/pdb_cif_conversion.py | 58 ++++++------- iotbx/pdb/hierarchy.py | 78 ++++++++++++++++- iotbx/pdb/tst_hierarchy.py | 88 ++++++++++++++++++++ mmtbx/model/model.py | 79 +++++++++++++++++- mmtbx/regression/model/tst_model.py | 101 +++++++++++++++++++++++ 5 files changed, 373 insertions(+), 31 deletions(-) diff --git a/iotbx/command_line/pdb_cif_conversion.py b/iotbx/command_line/pdb_cif_conversion.py index ddda48508d..5786dd5861 100644 --- a/iotbx/command_line/pdb_cif_conversion.py +++ b/iotbx/command_line/pdb_cif_conversion.py @@ -143,15 +143,15 @@ def get_results(self): ph.write_pdb_file() The best replacement in all cases is to use the Program template, pass -the data_manager into any modules that write out models, and -use the data_manager to write your model files. If you only have a +the data_manager into any modules that write out models, and +use the data_manager to write your model files. If you only have a hierarchy you can still say: m = hierarchy.as_model_manager(crystal_symmetry = crystal_symmetry) file_name = 'mypdb.pdb' file_name = data_manager.write_model_file(m, file_name) -If for some reason you cannot use the data_manager to write files, +If for some reason you cannot use the data_manager to write files, here are some alternatives: 1. If your code uses model.model_as_pdb() like this: @@ -163,14 +163,12 @@ def get_results(self): f.close() print("Wrote model to '%s'" %file_name) - then use instead model.pdb_or_mmcif_string_info(): + then use instead model.write_pdb_or_mmcif_file(): file_name = 'mypdb.pdb' - info = model.pdb_or_mmcif_string_info( + file_name = model.write_pdb_or_mmcif_file( target_format = params.output_files.target_output_format, - target_filename = file_name, - write_file = True) - file_name = info.file_name + target_filename = file_name) print("Wrote model to '%s'" %file_name) 2. If your code uses ph.as_pdb_string() and you need the string: @@ -179,12 +177,11 @@ def get_results(self): str = ph.as_pdb_string() print("Doing something with a string %s" %str) - Use instead model.pdb_or_mmcif_string_info() which will give you a PDB or + Use instead model.as_pdb_or_mmcif_string() which will give you a PDB or mmcif string as appropriate: - info = model.pdb_or_mmcif_string_info( + str = model.as_pdb_or_mmcif_string( target_format = params.output_files.target_output_format) - str = info.pdb_string print("Doing something with a string %s" %str) 3. If your code uses ph.as_pdb_string() or ph.write_pdb_file() and you are @@ -203,14 +200,12 @@ def get_results(self): str = ph.write_model_file(file_name) print("Wrote model to '%s'" %file_name) - Use instead pdb_or_mmcif_string_info: + Use instead write_pdb_or_mmcif_file: file_name = 'mypdb.pdb' - info = ph.pdb_or_mmcif_string_info( + file_name = ph.write_pdb_or_mmcif_string( target_format = params.output_files.target_output_format, - target_filename = file_name, - write_file = True) - file_name = info.file_name + target_filename = file_name) print("Wrote model to '%s'" %file_name) B. You will want to rewrite all code that interprets model text line-by-line. @@ -254,7 +249,7 @@ def get_results(self): f.close() print("Wrote intermediate model lines to '%s'" %new_file_name) - Use the data_manager or pdb_or_mmcif_string_info to write the file, and + Use the data_manager or write_pdb_or_mmcif_file to write the file, and capture the actual file name so that you can use it when you read the contents of the file back in. @@ -410,10 +405,14 @@ def forward_compatible_hierarchy_as_standard(self, conversion_info = None): def as_forward_compatible_string(self, **kw): Method for writing as PDB or mmCIF string, using supplied target_format if -possible, optionally writing as file, returning group_args object with -text string, file_name written, and is_mmcif marker: +possible, returning file name written: - def pdb_or_mmcif_string_info(self, + def write_pdb_or_mmcif_file(self, + +Method for obtaining a PDB or mmCIF string, using supplied target_format if +possible, returning the string: + + def as_pdb_or_mmcif_string(self, NOTE: This method and the corresponding method in model.py use default of segid_as_auth_segid = True, different from the default in @@ -436,12 +435,15 @@ def guess_chemical_elements(self, check_pseudo = False, MODULE: mmtbx/model/model.py: -Method matching one of the same name in hierarchy.py, -for writing as PDB or mmCIF string, using supplied target_format if -possible, optionally writing as file, returning group_args object with -text string, file_name written, and is_mmcif marker: +Method for writing as PDB or mmCIF string, using supplied target_format if +possible, returning file name written: + + def write_pdb_or_mmcif_file(self, + +Method for obtaining a PDB or mmCIF string, using supplied target_format if +possible, returning the string: - def pdb_or_mmcif_string_info(self, + def as_pdb_or_mmcif_string(self, NOTE: This method and the corresponding method in hierarchy.py use default of segid_as_auth_segid = True, different from the default in @@ -570,7 +572,7 @@ def get_forward_compatible_pdb_text_from_full_text(self, it to read/write files in your programs. Then once again you only need to capture the actual file names written by the data_manager. - b. If you cannot use the data_manager, use the pdb_or_mmcif_string_info + b. If you cannot use the data_manager, use the write_pdb_or_mmcif_file method of the model manager or the hierarchy to write your files. This method allows setting the preferred output format and capturing the name of the actual file that is written. @@ -615,12 +617,10 @@ def get_forward_compatible_pdb_text_from_full_text(self, b. If have only a hierarchy and crystal_symmetry and params: - info = ph.pdb_or_mmcif_string_info( + file_name = ph.write_pdb_or_mmcif_file( target_format = params.output_files.target_output_format, target_filename = params.output.file_name, - write_file = True, crystal_symmetry=crystal_symmetry) - file_name = info.file_name print("Model written to '%s'" %file_name) c. When you read pdb/mmcif files, if you do not know the ending .pdb or diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index 54bab19d4b..41562f7e32 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -749,14 +749,90 @@ def as_forward_compatible_string(self, **kw): import hierarchy_as_forward_compatible_pdb_string return hierarchy_as_forward_compatible_pdb_string(self, **kw) + def as_pdb_or_mmcif_string(self, + target_format = None, + segid_as_auth_segid = True, + remark_section = None, + **kw): + ''' + Shortcut for pdb_or_mmcif_string_info with write_file=False, returning + only the string representing this hierarchy. The string may be in + PDB or mmCIF format, with target_format used if it is feasible. + + Method to allow shifting from general writing as pdb to + writing as mmcif, with the change in two places (here and model.py) + Use default of segid_as_auth_segid=True here (different than + as_mmcif_string()) + :param target_format: desired output format, pdb or mmcif + :param segid_as_auth_segid: use the segid in hierarchy as the auth_segid + in mmcif output + :param remark_section: if supplied and format is pdb, add this text + :param **kw: any keywords suitable for as_pdb_string() + and as_mmcif_string() + :returns text string representing this hierarchy + ''' + + info = self.pdb_or_mmcif_string_info( + target_format = target_format, + segid_as_auth_segid = segid_as_auth_segid, + remark_section = remark_section, + write_file = False, + **kw) + return info.pdb_string + + def write_pdb_or_mmcif_file(self, + target_filename, + target_format = None, + data_manager = None, + overwrite = True, + segid_as_auth_segid = True, + remark_section = None, + **kw): + ''' + Shortcut for pdb_or_mmcif_string_info with write_file=True, returning + only the name of the file that is written. The file may be written + in PDB or mmCIF format, with target_format used if feasible. + + Method to allow shifting from general writing as pdb to + writing as mmcif, with the change in two places (here and model.py) + Use default of segid_as_auth_segid=True here (different than + as_mmcif_string()) + :param target_format: desired output format, pdb or mmcif + :param target_filename: desired output file name, to be modified to + match the output format + :param data_manager: data_manager to write files + :param overwrite: parameter to set overwrite=True in data_manager if True + :param segid_as_auth_segid: use the segid in hierarchy as the auth_segid + in mmcif output + :param remark_section: if supplied and format is pdb, add this text + :param **kw: any keywords suitable for as_pdb_string() + and as_mmcif_string() + :returns name of file that is written + ''' + + info = self.pdb_or_mmcif_string_info( + target_filename = target_filename, + target_format = target_format, + data_manager = data_manager, + overwrite = overwrite, + segid_as_auth_segid = segid_as_auth_segid, + remark_section = remark_section, + write_file = True, + **kw) + return info.file_name + def pdb_or_mmcif_string_info(self, target_format = None, target_filename = None, data_manager = None, overwrite = True, - segid_as_auth_segid = True, write_file = False, + segid_as_auth_segid = True, + write_file = False, remark_section = None, **kw): """ + NOTE: Normally use instead either as_pdb_or_mmcif_string + write_pdb_or_mmcif_file. + Method to allow shifting from general writing as pdb to writing as mmcif, with the change in two places (here and model.py) Use default of segid_as_auth_segid=True here (different than diff --git a/iotbx/pdb/tst_hierarchy.py b/iotbx/pdb/tst_hierarchy.py index 6ea1aa1784..6d22b26ce6 100644 --- a/iotbx/pdb/tst_hierarchy.py +++ b/iotbx/pdb/tst_hierarchy.py @@ -7311,6 +7311,92 @@ def exercise_contains_hetero(): assert not h.contains_hetero() +def exercise_as_pdb_or_mmcif_string(): + pdb_inp_lines = flex.split_lines("""\ +ATOM 1 CA ASP A 1 47.975 -63.194 59.946 1.00 33.86 C +ATOM 5 CA VAL A 2 44.978 -63.576 62.233 1.00 29.81 C +ATOM 8 N GLN B 3 44.585 -65.878 62.864 1.00 25.93 N +ATOM 9 CA GLN B 3 44.166 -67.262 62.686 1.00 24.46 C +ATOM 10 C GLN B 3 42.730 -67.505 63.153 1.00 23.33 C +ATOM 11 O GLN B 3 42.389 -67.234 64.302 1.00 20.10 O +ATOM 12 N MET B 4 41.894 -68.026 62.256 1.00 24.27 N +ATOM 13 CA MET B 4 40.497 -68.318 62.576 1.00 22.89 C +ATOM 14 C MET B 4 40.326 -69.824 62.795 1.00 21.48 C +ATOM 15 O MET B 4 40.633 -70.625 61.911 1.00 23.73 O +""") + h = pdb.input(source_info=None, lines=pdb_inp_lines).construct_hierarchy() + assert h.fits_in_pdb_format() + text = h.as_pdb_or_mmcif_string() + pdb_inp = pdb.input(source_info=None, lines=flex.split_lines(text)) + is_mmcif = (str(type(pdb_inp)).find('cif')>0) + assert not is_mmcif + + h.only_model().chains()[1].id = "long_chain_id" + assert not h.fits_in_pdb_format() + text = h.as_pdb_or_mmcif_string() + pdb_inp = pdb.input(source_info=None, lines=flex.split_lines(text)) + is_mmcif = (str(type(pdb_inp)).find('cif')>0) + assert is_mmcif + + h = pdb.input(source_info=None, lines=pdb_inp_lines).construct_hierarchy() + assert h.fits_in_pdb_format() + text = h.as_pdb_or_mmcif_string(target_format='mmcif') + pdb_inp = pdb.input(source_info=None, lines=flex.split_lines(text)) + is_mmcif = (str(type(pdb_inp)).find('cif')>0) + assert is_mmcif + + h.only_model().chains()[1].id = "long_chain_id" + assert not h.fits_in_pdb_format() + text = h.as_pdb_or_mmcif_string(target_format='pdb') + pdb_inp = pdb.input(source_info=None, lines=flex.split_lines(text)) + is_mmcif = (str(type(pdb_inp)).find('cif')>0) + assert is_mmcif + +def exercise_write_pdb_or_mmcif_file(): + pdb_inp_lines = flex.split_lines("""\ +ATOM 1 CA ASP A 1 47.975 -63.194 59.946 1.00 33.86 C +ATOM 5 CA VAL A 2 44.978 -63.576 62.233 1.00 29.81 C +ATOM 8 N GLN B 3 44.585 -65.878 62.864 1.00 25.93 N +ATOM 9 CA GLN B 3 44.166 -67.262 62.686 1.00 24.46 C +ATOM 10 C GLN B 3 42.730 -67.505 63.153 1.00 23.33 C +ATOM 11 O GLN B 3 42.389 -67.234 64.302 1.00 20.10 O +ATOM 12 N MET B 4 41.894 -68.026 62.256 1.00 24.27 N +ATOM 13 CA MET B 4 40.497 -68.318 62.576 1.00 22.89 C +ATOM 14 C MET B 4 40.326 -69.824 62.795 1.00 21.48 C +ATOM 15 O MET B 4 40.633 -70.625 61.911 1.00 23.73 O +""") + from iotbx.pdb.utils import get_pdb_input + h = pdb.input(source_info=None, lines=pdb_inp_lines).construct_hierarchy() + assert h.fits_in_pdb_format() + + file_name = h.write_pdb_or_mmcif_file('target_pdb.pdb') + assert file_name == 'target_pdb.pdb' + pdb_inp = get_pdb_input(file_name = file_name) + is_mmcif = (str(type(pdb_inp)).find('cif')>0) + assert not is_mmcif + + file_name = h.write_pdb_or_mmcif_file('target_pdb.pdb', target_format='mmcif') + assert file_name == 'target_pdb.cif' + pdb_inp = get_pdb_input(file_name = file_name) + is_mmcif = (str(type(pdb_inp)).find('cif')>0) + assert is_mmcif + + h.only_model().chains()[1].id = "long_chain_id" + assert not h.fits_in_pdb_format() + + file_name = h.write_pdb_or_mmcif_file('target_pdb.pdb') + assert file_name == 'target_pdb.cif' + pdb_inp = get_pdb_input(file_name = file_name) + is_mmcif = (str(type(pdb_inp)).find('cif')>0) + assert is_mmcif + + file_name = h.write_pdb_or_mmcif_file('target_pdb.pdb', target_format='pdb') + assert file_name == 'target_pdb.cif' + pdb_inp = get_pdb_input(file_name = file_name) + is_mmcif = (str(type(pdb_inp)).find('cif')>0) + assert is_mmcif + + def exercise_fits_in_pdb_format(): pdb_inp_lines = flex.split_lines("""\ ATOM 1 CA ASP A 1 47.975 -63.194 59.946 1.00 33.86 C @@ -7419,6 +7505,8 @@ def exercise(args): exercise_remove_ter_or_break() exercise_contains_hetero() exercise_forward_compatibility() + exercise_as_pdb_or_mmcif_string() + exercise_write_pdb_or_mmcif_file() if (not forever): break print(format_cpu_times()) diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index 8f451511c5..eb003d775e 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -1683,8 +1683,81 @@ def can_be_unique_with_biomt(self): return False return True + def as_pdb_or_mmcif_string(self, + target_format = None, + segid_as_auth_segid = True, + remark_section = None, + **kw): + ''' + Shortcut for pdb_or_mmcif_string_info with write_file=False, returning + only the string representing this hierarchy. The string may be in + PDB or mmCIF format, with target_format used if it is feasible. + + Method to allow shifting from general writing as pdb to + writing as mmcif, with the change in two places (here and model.py) + Use default of segid_as_auth_segid=True here (different than + as_mmcif_string()) + :param target_format: desired output format, pdb or mmcif + :param segid_as_auth_segid: use the segid in hierarchy as the auth_segid + in mmcif output + :param remark_section: if supplied and format is pdb, add this text + :param **kw: any keywords suitable for as_pdb_string() + and as_mmcif_string() + :returns text string representing this hierarchy + ''' + + info = self.pdb_or_mmcif_string_info( + target_format = target_format, + segid_as_auth_segid = segid_as_auth_segid, + remark_section = remark_section, + write_file = False, + **kw) + return info.pdb_string + + def write_pdb_or_mmcif_file(self, + target_filename, + target_format = None, + data_manager = None, + overwrite = True, + segid_as_auth_segid = True, + remark_section = None, + **kw): + ''' + Shortcut for pdb_or_mmcif_string_info with write_file=True, returning + only the name of the file that is written. The file may be written + in PDB or mmCIF format, with target_format used if feasible. + + Method to allow shifting from general writing as pdb to + writing as mmcif, with the change in two places (here and model.py) + Use default of segid_as_auth_segid=True here (different than + as_mmcif_string()) + :param target_format: desired output format, pdb or mmcif + :param target_filename: desired output file name, to be modified to + match the output format + :param data_manager: data_manager to write files + :param overwrite: parameter to set overwrite=True in data_manager if True + :param segid_as_auth_segid: use the segid in hierarchy as the auth_segid + in mmcif output + :param remark_section: if supplied and format is pdb, add this text + :param **kw: any keywords suitable for as_pdb_string() + and as_mmcif_string() + :returns name of file that is written + ''' + + info = self.pdb_or_mmcif_string_info( + target_filename = target_filename, + target_format = target_format, + data_manager = data_manager, + overwrite = overwrite, + segid_as_auth_segid = segid_as_auth_segid, + remark_section = remark_section, + write_file = True, + **kw) + return info.file_name + def pdb_or_mmcif_string_info(self, - target_filename = None, target_format = None, + target_filename = None, + target_format = None, segid_as_auth_segid = True, write_file = False, data_manager = None, @@ -1693,6 +1766,10 @@ def pdb_or_mmcif_string_info(self, **kw): # Method to allow shifting from general writing as pdb # to writing as mmcif, with the change in two places (here and hierarchy.py) + + # NOTE: normally use either write_pdb_or_mmcif_file or + # as_pdb_or_mmcif_string instead of this general function + # Note default of segid_as_auth_segid = True, different from # as_mmcif_string() diff --git a/mmtbx/regression/model/tst_model.py b/mmtbx/regression/model/tst_model.py index 8e6d7606b5..eaff3c56ce 100644 --- a/mmtbx/regression/model/tst_model.py +++ b/mmtbx/regression/model/tst_model.py @@ -1503,7 +1503,106 @@ def exercise_11_ss_annotations(): else: assert 0 +def exercise_12_as_pdb_or_mmcif_string(): + pdb_inp_lines = flex.split_lines("""\ +CRYST1 107.161 107.161 93.144 90.00 90.00 120.00 H 3 9 +ATOM 1 CA ASP A 1 47.975 -63.194 59.946 1.00 33.86 C +ATOM 5 CA VAL A 2 44.978 -63.576 62.233 1.00 29.81 C +ATOM 8 N GLN B 3 44.585 -65.878 62.864 1.00 25.93 N +ATOM 9 CA GLN B 3 44.166 -67.262 62.686 1.00 24.46 C +ATOM 10 C GLN B 3 42.730 -67.505 63.153 1.00 23.33 C +ATOM 11 O GLN B 3 42.389 -67.234 64.302 1.00 20.10 O +ATOM 12 N MET B 4 41.894 -68.026 62.256 1.00 24.27 N +ATOM 13 CA MET B 4 40.497 -68.318 62.576 1.00 22.89 C +ATOM 14 C MET B 4 40.326 -69.824 62.795 1.00 21.48 C +ATOM 15 O MET B 4 40.633 -70.625 61.911 1.00 23.73 O +""") + from iotbx.pdb.utils import get_pdb_input, get_pdb_info + pdb_info = get_pdb_info(lines=pdb_inp_lines) + h = pdb_info.hierarchy + m = h.as_model_manager(crystal_symmetry = pdb_info.crystal_symmetry) + assert m.can_be_output_as_pdb() + + text = m.as_pdb_or_mmcif_string() + pdb_inp = get_pdb_input(text) + is_mmcif = (str(type(pdb_inp)).find('cif')>0) + assert not is_mmcif + + m.get_hierarchy().only_model().chains()[1].id = "long_chain_id" + assert not m.can_be_output_as_pdb() + text = m.as_pdb_or_mmcif_string() + pdb_inp = get_pdb_input(text) + is_mmcif = (str(type(pdb_inp)).find('cif')>0) + assert is_mmcif + + pdb_info = get_pdb_info(lines=pdb_inp_lines) + h = pdb_info.hierarchy + m = h.as_model_manager(crystal_symmetry = pdb_info.crystal_symmetry) + assert m.can_be_output_as_pdb() + + text = m.as_pdb_or_mmcif_string(target_format='mmcif') + pdb_inp = get_pdb_input(text) + is_mmcif = (str(type(pdb_inp)).find('cif')>0) + assert is_mmcif + + m.get_hierarchy().only_model().chains()[1].id = "long_chain_id" + assert not m.can_be_output_as_pdb() + text = m.as_pdb_or_mmcif_string(target_format='pdb') + pdb_inp = get_pdb_input(text) + is_mmcif = (str(type(pdb_inp)).find('cif')>0) + assert is_mmcif + +def exercise_13_write_pdb_or_mmcif_file(): + pdb_inp_lines = flex.split_lines("""\ +CRYST1 107.161 107.161 93.144 90.00 90.00 120.00 H 3 9 +ATOM 1 CA ASP A 1 47.975 -63.194 59.946 1.00 33.86 C +ATOM 5 CA VAL A 2 44.978 -63.576 62.233 1.00 29.81 C +ATOM 8 N GLN B 3 44.585 -65.878 62.864 1.00 25.93 N +ATOM 9 CA GLN B 3 44.166 -67.262 62.686 1.00 24.46 C +ATOM 10 C GLN B 3 42.730 -67.505 63.153 1.00 23.33 C +ATOM 11 O GLN B 3 42.389 -67.234 64.302 1.00 20.10 O +ATOM 12 N MET B 4 41.894 -68.026 62.256 1.00 24.27 N +ATOM 13 CA MET B 4 40.497 -68.318 62.576 1.00 22.89 C +ATOM 14 C MET B 4 40.326 -69.824 62.795 1.00 21.48 C +ATOM 15 O MET B 4 40.633 -70.625 61.911 1.00 23.73 O +""") + from iotbx.pdb.utils import get_pdb_input, get_pdb_info + pdb_info = get_pdb_info(lines=pdb_inp_lines) + h = pdb_info.hierarchy + m = h.as_model_manager(crystal_symmetry = pdb_info.crystal_symmetry) + assert m.can_be_output_as_pdb() + + file_name = m.write_pdb_or_mmcif_file('target_pdb.pdb') + assert file_name == 'target_pdb.pdb' + pdb_inp = get_pdb_input(file_name = file_name) + is_mmcif = (str(type(pdb_inp)).find('cif')>0) + assert not is_mmcif + + file_name = m.write_pdb_or_mmcif_file('target_pdb.pdb', target_format='mmcif') + assert file_name == 'target_pdb.cif' + pdb_inp = get_pdb_input(file_name = file_name) + is_mmcif = (str(type(pdb_inp)).find('cif')>0) + assert is_mmcif + + m.get_hierarchy().only_model().chains()[1].id = "long_chain_id" + assert not m.can_be_output_as_pdb() + + file_name = m.write_pdb_or_mmcif_file('target_pdb.pdb') + assert file_name == 'target_pdb.cif' + pdb_inp = get_pdb_input(file_name = file_name) + is_mmcif = (str(type(pdb_inp)).find('cif')>0) + assert is_mmcif + + file_name = m.write_pdb_or_mmcif_file('target_pdb.pdb', target_format='pdb') + assert file_name == 'target_pdb.cif' + pdb_inp = get_pdb_input(file_name = file_name) + is_mmcif = (str(type(pdb_inp)).find('cif')>0) + assert is_mmcif + def run(): + exercise_12_as_pdb_or_mmcif_string() + exercise_13_write_pdb_or_mmcif_file() + return # ZZ exercise_00() exercise() exercise_2() @@ -1519,6 +1618,8 @@ def run(): exercise_9() exercise_10() exercise_11_ss_annotations() + exercise_12_as_pdb_or_mmcif_string() + exercise_13_write_pdb_or_mmcif_file() print(format_cpu_times()) if (__name__ == "__main__"): From 0f9dffe7c21e9f0c3e20e5b3fbf6b119b2e2d8f9 Mon Sep 17 00:00:00 2001 From: terwill Date: Sun, 4 Feb 2024 17:17:54 -0800 Subject: [PATCH 097/748] Use write_pdb_or_mmcif_file instead of pdb_or_mmcif_string_info --- cctbx/maptbx/segment_and_split_map.py | 12 ++----- iotbx/command_line/pdb_cif_conversion.py | 2 +- mmtbx/building/merge_models.py | 7 ++-- mmtbx/building/minimize_chain.py | 3 +- mmtbx/command_line/sort_hetatms.py | 6 ++-- mmtbx/regression/tst_minimize_chain_cif.py | 35 ++++++++----------- .../regularize_from_pdb.py | 7 ++-- 7 files changed, 25 insertions(+), 47 deletions(-) diff --git a/cctbx/maptbx/segment_and_split_map.py b/cctbx/maptbx/segment_and_split_map.py index 30055e5309..6f3096e4f2 100644 --- a/cctbx/maptbx/segment_and_split_map.py +++ b/cctbx/maptbx/segment_and_split_map.py @@ -8443,14 +8443,10 @@ def apply_origin_shift(origin_shift = None, if shifted_pdb_file and pdb_hierarchy: - info = pdb_hierarchy.pdb_or_mmcif_string_info( + shifted_pdb_file = pdb_hierarchy.write_pdb_or_mmcif_file( target_filename = shifted_pdb_file, crystal_symmetry = tracking_data.crystal_symmetry) - shifted_pdb_file = info.file_name - f = open(shifted_pdb_file, 'w') - print(info.pdb_string, file = f) - f.close() print("Wrote shifted pdb file to %s" %( shifted_pdb_file), file = out) tracking_data.set_shifted_pdb_info(file_name = shifted_pdb_file, @@ -8495,14 +8491,10 @@ def restore_pdb(params, tracking_data = None, out = sys.stdout): pdb_hierarchy = pdb_hierarchy, out = out) - info = pdb_hierarchy.pdb_or_mmcif_string_info( + params.output_files.restored_pdb = pdb_hierarchy.write_pdb_or_mmcif_file( crystal_symmetry = tracking_data.crystal_symmetry, target_filename = params.output_files.restored_pdb) - tracking_data.crystal_symmetry = info.file_name - f = open(params.output_files.restored_pdb, 'w') - print(info.pdb_string, file = f) - f.close() print("Wrote restored pdb file to %s" %( params.output_files.restored_pdb), file = out) diff --git a/iotbx/command_line/pdb_cif_conversion.py b/iotbx/command_line/pdb_cif_conversion.py index 5786dd5861..cade3b11d8 100644 --- a/iotbx/command_line/pdb_cif_conversion.py +++ b/iotbx/command_line/pdb_cif_conversion.py @@ -203,7 +203,7 @@ def get_results(self): Use instead write_pdb_or_mmcif_file: file_name = 'mypdb.pdb' - file_name = ph.write_pdb_or_mmcif_string( + file_name = ph.write_pdb_or_mmcif_file( target_format = params.output_files.target_output_format, target_filename = file_name) print("Wrote model to '%s'" %file_name) diff --git a/mmtbx/building/merge_models.py b/mmtbx/building/merge_models.py index 5e5c0d1f5a..2f7a2b04e4 100644 --- a/mmtbx/building/merge_models.py +++ b/mmtbx/building/merge_models.py @@ -826,12 +826,9 @@ def run( print(pdb_hierarchy.as_pdb_string()) if pdb_out: - info = pdb_hierarchy.pdb_or_mmcif_string_info(target_filename = pdb_out, + pdb_out = pdb_hierarchy.write_pdb_or_mmcif_file(target_filename = pdb_out, crystal_symmetry = crystal_symmetry) - f=open(info.file_name,'w') - print(info.pdb_string, file = f) - print("Final model is in: %s\n" %(f.name)) - f.close() + print("Final model is in: %s\n" %(pdb_out)) return pdb_hierarchy, pdb_out diff --git a/mmtbx/building/minimize_chain.py b/mmtbx/building/minimize_chain.py index 11f74df011..b75e85bf12 100644 --- a/mmtbx/building/minimize_chain.py +++ b/mmtbx/building/minimize_chain.py @@ -220,9 +220,8 @@ def get_pdb_inp( crystal_symmetry=crystal_symmetry) if pdb_string is None: ph = pdb_inp.construct_hierarchy() - info = ph.pdb_or_mmcif_string_info( + pdb_string = ph.as_pdb_or_mmcif_string( crystal_symmetry = crystal_symmetry) - pdb_string = info.pdb_string return pdb_inp,cryst1_line,pdb_string def run_one_cycle( diff --git a/mmtbx/command_line/sort_hetatms.py b/mmtbx/command_line/sort_hetatms.py index 726bd7df0b..e4d9422a01 100644 --- a/mmtbx/command_line/sort_hetatms.py +++ b/mmtbx/command_line/sort_hetatms.py @@ -399,10 +399,8 @@ def run(args, out=sys.stdout, sorting_params=None): params.output_file = os.path.splitext( os.path.basename(params.file_name))[0] + "_sorted.pdb" if (not result.pdb_hierarchy.fits_in_pdb_format()): - info = result.pdb_hierarchy.pdb_or_mmcif_string_info( - target_filename = params.output_file, - write_file = True) - params.output_file = info.file_name + params.output_file = result.pdb_hierarchy.write_pdb_or_mmcif_file( + target_filename = params.output_file) else: # standard pdb file f = open(params.output_file, "w") diff --git a/mmtbx/regression/tst_minimize_chain_cif.py b/mmtbx/regression/tst_minimize_chain_cif.py index bfdb9aa665..b91e18e074 100644 --- a/mmtbx/regression/tst_minimize_chain_cif.py +++ b/mmtbx/regression/tst_minimize_chain_cif.py @@ -547,10 +547,9 @@ def tst_01(): pdb_file_name_answer_full = "%s_answer_full.cif"%prefix pdb_inp = iotbx.pdb.input(source_info=None, lines = pdb_str_answer_AE) ph_answer_full = pdb_inp.construct_hierarchy() - info = ph_answer_full.pdb_or_mmcif_string_info( + fn = ph_answer_full.write_pdb_or_mmcif_file( target_filename = "%s_answer.cif"%prefix, - crystal_symmetry = pdb_inp.crystal_symmetry(), - write_file = True) + crystal_symmetry = pdb_inp.crystal_symmetry()) ph_answer_full.atoms().reset_i_seq() xrs_answer_full = pdb_inp.xray_structure_simple() @@ -558,10 +557,9 @@ def tst_01(): pdb_file_name_two_models = "%s_poor_two_models.cif"%prefix pdb_inp = iotbx.pdb.input(source_info=None, lines = pdb_str_two_models) full_two_models = pdb_inp.construct_hierarchy() - info = full_two_models.pdb_or_mmcif_string_info( + fn = full_two_models.write_pdb_or_mmcif_file( target_filename = "%s_two_models.cif"%prefix, - crystal_symmetry = pdb_inp.crystal_symmetry(), - write_file = True) + crystal_symmetry = pdb_inp.crystal_symmetry()) xrs_two_models_full = pdb_inp.xray_structure_simple() # Compute target map @@ -587,10 +585,9 @@ def tst_01(): pdb_inp=hierarchy.as_pdb_input(crystal_symmetry=fc.crystal_symmetry()) xrs=pdb_inp.xray_structure_simple() refined_ph=pdb_inp.construct_hierarchy() - info = refined_ph.pdb_or_mmcif_string_info( + fn = refined_ph.write_pdb_or_mmcif_file( target_filename = "%s_refined.cif"%prefix, - crystal_symmetry = pdb_inp.crystal_symmetry(), - write_file = True) + crystal_symmetry = pdb_inp.crystal_symmetry()) rmsd=xrs.sites_cart().rms_difference(xrs_answer_full.sites_cart()) print("RMSD from TARGET allowing any CROSSOVERS: %8.2f " %(rmsd)) return rmsd @@ -604,10 +601,9 @@ def tst_02(args,prefix=None): pdb_file_name_answer_full = "%s_answer_full.cif"%prefix pdb_inp = iotbx.pdb.input(source_info=None, lines = pdb_str_answer_full) ph_answer_full = pdb_inp.construct_hierarchy() - info = ph_answer_full.pdb_or_mmcif_string_info( + fn = ph_answer_full.write_pdb_or_mmcif_file( target_filename = "%s_answer_full.cif"%prefix, - crystal_symmetry = pdb_inp.crystal_symmetry(), - write_file = True) + crystal_symmetry = pdb_inp.crystal_symmetry()) ph_answer_full.atoms().reset_i_seq() xrs_answer_full = pdb_inp.xray_structure_simple() @@ -615,10 +611,9 @@ def tst_02(args,prefix=None): pdb_file_name_poor = "%s_poor.cif"%prefix pdb_inp = iotbx.pdb.input(source_info=None, lines = pdb_str_poor_full) ph_poor_full = pdb_inp.construct_hierarchy() - info = ph_poor_full.pdb_or_mmcif_string_info( + fn = ph_poor_full.write_pdb_or_mmcif_file( target_filename = "%s_poor.cif"%prefix, - crystal_symmetry = pdb_inp.crystal_symmetry(), - write_file = True) + crystal_symmetry = pdb_inp.crystal_symmetry()) ph_poor_full.atoms().reset_i_seq() xrs_poor_full = pdb_inp.xray_structure_simple() @@ -642,14 +637,12 @@ def tst_02(args,prefix=None): pdb_inp=hierarchy.as_pdb_input(crystal_symmetry=fc.crystal_symmetry()) xrs_refined=pdb_inp.xray_structure_simple() - info = hierarchy.pdb_or_mmcif_string_info( + fn = hierarchy.write_pdb_or_mmcif_file( target_filename = "%s_refined.cif"%prefix, - crystal_symmetry = pdb_inp.crystal_symmetry(), - write_file = True) - info = multiple_model_hierarchy.pdb_or_mmcif_string_info( + crystal_symmetry = pdb_inp.crystal_symmetry()) + fn = multiple_model_hierarchy.write_pdb_or_mmcif_file( target_filename = "%s_refined_all_states.cif"%prefix, - crystal_symmetry = pdb_inp.crystal_symmetry(), - write_file = True) + crystal_symmetry = pdb_inp.crystal_symmetry()) rmsd=xrs_refined.sites_cart().rms_difference(xrs_answer_full.sites_cart()) print("RMSD from TARGET for FULL-model refinement: %8.2f " %(rmsd)) return rmsd diff --git a/mmtbx/secondary_structure/regularize_from_pdb.py b/mmtbx/secondary_structure/regularize_from_pdb.py index fc48363d25..15d895c4ea 100644 --- a/mmtbx/secondary_structure/regularize_from_pdb.py +++ b/mmtbx/secondary_structure/regularize_from_pdb.py @@ -1670,10 +1670,9 @@ def __init__(self,pdb_hierarchy=None,args=None, # write out results if params.output_files.pdb_out: - info = replacement_model.hierarchy.pdb_or_mmcif_string_info( - target_filename = params.output_files.pdb_out, - write_file = True,) - params.output_files.pdb_out = info.file_name + params.output_files.pdb_out = \ + replacement_model.hierarchy.write_pdb_or_mmcif_file( + target_filename = params.output_files.pdb_out) print("\nWriting output PDB file to %s" %( params.output_files.pdb_out), file=out) self.replacement_model=replacement_model From 7ee7c1692ca51c3a3d47651fc2d1f82dd1a1949a Mon Sep 17 00:00:00 2001 From: terwill Date: Mon, 5 Feb 2024 08:27:01 -0800 Subject: [PATCH 098/748] Unrecommend the output_files scope for target_output_format --- iotbx/command_line/pdb_cif_conversion.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/iotbx/command_line/pdb_cif_conversion.py b/iotbx/command_line/pdb_cif_conversion.py index cade3b11d8..28a1f3a943 100644 --- a/iotbx/command_line/pdb_cif_conversion.py +++ b/iotbx/command_line/pdb_cif_conversion.py @@ -167,7 +167,7 @@ def get_results(self): file_name = 'mypdb.pdb' file_name = model.write_pdb_or_mmcif_file( - target_format = params.output_files.target_output_format, + target_format = params.output.target_output_format, target_filename = file_name) print("Wrote model to '%s'" %file_name) @@ -181,7 +181,7 @@ def get_results(self): mmcif string as appropriate: str = model.as_pdb_or_mmcif_string( - target_format = params.output_files.target_output_format) + target_format = params.output.target_output_format) print("Doing something with a string %s" %str) 3. If your code uses ph.as_pdb_string() or ph.write_pdb_file() and you are @@ -204,7 +204,7 @@ def get_results(self): file_name = 'mypdb.pdb' file_name = ph.write_pdb_or_mmcif_file( - target_format = params.output_files.target_output_format, + target_format = params.output.target_output_format, target_filename = file_name) print("Wrote model to '%s'" %file_name) @@ -455,7 +455,7 @@ def as_pdb_or_mmcif_string(self, MODULE: iotbx/pdb/utils.py: -Methods to set the target_output_format parameter in the scope output/output_files: +Methods to set the target_output_format parameter in the scope output: def set_target_output_format_in_params(params, def get_input_model_file_name_from_params(params): @@ -591,7 +591,9 @@ def get_forward_compatible_pdb_text_from_full_text(self, Here is how you can do these things. Note that this only applies for modules that really cannot use the Program template. -1. Add target_output_format to your "output" or "output_files" scope: +1. Add target_output_format to your "output" scope (if you do not have + an output scope and have an output_files scope, that is allowed + but not recommended): target_output_format = *None pdb mmcif .type = choice @@ -618,7 +620,7 @@ def get_forward_compatible_pdb_text_from_full_text(self, b. If have only a hierarchy and crystal_symmetry and params: file_name = ph.write_pdb_or_mmcif_file( - target_format = params.output_files.target_output_format, + target_format = params.output.target_output_format, target_filename = params.output.file_name, crystal_symmetry=crystal_symmetry) print("Model written to '%s'" %file_name) From 21b0e9868014ac2c65711ea112c4229904518274 Mon Sep 17 00:00:00 2001 From: terwill Date: Mon, 5 Feb 2024 14:04:17 -0800 Subject: [PATCH 099/748] Modify data_manager/model.py to remove the extension and append_ext keywords and only use format and self._target_output_format --- .../html_files/doc_hlo_data_manager.html | 2 +- iotbx/command_line/pdb_cif_conversion.py | 2 +- iotbx/data_manager/model.py | 77 +++++++++++++------ iotbx/regression/tst_data_manager.py | 4 +- mmtbx/command_line/map_box.py | 4 +- 5 files changed, 58 insertions(+), 31 deletions(-) diff --git a/cctbx_website/html_files/doc_hlo_data_manager.html b/cctbx_website/html_files/doc_hlo_data_manager.html index 91cfe062d4..2d4b9a1ae9 100644 --- a/cctbx_website/html_files/doc_hlo_data_manager.html +++ b/cctbx_website/html_files/doc_hlo_data_manager.html @@ -81,7 +81,7 @@

Reading and writing model information

dm.write_model_file(model,filename="output_model.pdb") # write model to a file
 
-

Note that the DataManager can write either in PDB or CIF format. By default it writes out whichever format was used when the model was read in, or PDB format if the model was not read in from a file. You can specify which format you want with a keyword: extension="pdb".

+

Note that the DataManager can write either in PDB or CIF format. By default it writes out whichever format was used when the model was read in, or PDB format if the model was not read in from a file. You can specify which format you want with a keyword: format="pdb".

diff --git a/iotbx/command_line/pdb_cif_conversion.py b/iotbx/command_line/pdb_cif_conversion.py index 28a1f3a943..3bff73fedb 100644 --- a/iotbx/command_line/pdb_cif_conversion.py +++ b/iotbx/command_line/pdb_cif_conversion.py @@ -389,7 +389,7 @@ def set_target_output_format(self, target_output_format): format and to write as mmCIF it does not, or if the user specified cif as the output format. - def write_model_file(self, model_str, filename=Auto, extension=Auto, + def write_model_file(self, model_str, filename=Auto, format=Auto, MODULE: iotbx/pdb/hierarchy.py: diff --git a/iotbx/data_manager/model.py b/iotbx/data_manager/model.py index e47a712e13..3a08cf6dfa 100644 --- a/iotbx/data_manager/model.py +++ b/iotbx/data_manager/model.py @@ -277,8 +277,8 @@ def get_default_output_model_filename(self, extension=Auto): filename += extension return filename - def write_model_file(self, model_str, filename=Auto, extension=Auto, - format=Auto, overwrite=Auto, append_ext = True): + def write_model_file(self, model_str, filename=Auto, + format=Auto, overwrite=Auto): ''' Function for writing a model to file @@ -287,21 +287,19 @@ def write_model_file(self, model_str, filename=Auto, extension=Auto, model_str: str or mmtbx.model.manager object The string to be written or a model object. If a model object is provided, the format (PDB or mmCIF) of the original file is kept - unless specified with format below + unless specified with format or target_output_format below. + If a string is provided, the format must be specified as pdb or cif filename: str or Auto The output filename. If set to Auto, a default filename is generated based on params.output.prefix, params.output.suffix, and params.output.serial - extension: str or Auto - The extension to be added. If set to Auto, defaults to .cif format: pdb or cif (mmcif treated as cif) or Auto. If set to Auto, defaults to format of original file. If self._target_output_format is not None, - always write to this format if possible + always write model objects to this format if possible. overwrite: bool or Auto Overwrite filename if it exists. If set to Auto, the overwrite state of the DataManager is used. - append_ext: bool. If True append extension if necessary Returns ------- @@ -311,33 +309,54 @@ def write_model_file(self, model_str, filename=Auto, extension=Auto, extension to cif by default. This function may alter the extension based on the desired format. ''' - target_output_format = getattr(self,'_target_output_format',None) - if target_output_format and (format in [Auto, None]): - # Take format from self._target_output_format - format = target_output_format + if format == 'mmcif': format = 'cif' # mmcif and cif are synonyms here if isinstance(model_str, mmtbx.model.manager): - if format == 'cif' or ( - format is Auto and model_str.input_model_format_cif()): + # Get overall preference for output format + if (format is Auto) and hasattr(self,'_target_output_format') and ( + self._target_output_format is not None): + format = self._target_output_format + + # Write as mmCIF if: + # 1. format was supplied as 'cif' or + # 2. format was Auto and target_output_format was set to 'cif', or + # 3. format was Auto, no target_output_format set and this model was + # cif when read in, or + # 4. model does not fit in PDB format + if (format == 'cif') or (format is Auto and + model_str.input_model_format_cif()) or ( + not model_str.get_hierarchy().fits_in_pdb_format()): extension = '.cif' + format = 'cif' model_str = model_str.model_as_mmcif() else: - if model_str.get_hierarchy().fits_in_pdb_format(): - extension = '.pdb' - model_str = model_str.model_as_pdb() - else: # XXX Catch case where it does not fit in PDB format - extension = '.cif' - model_str = model_str.model_as_mmcif() + extension = '.pdb' + format = 'pdb' + model_str = model_str.model_as_pdb() + + else: # writing a string. Output format must be specified on input + + if format == 'cif': + extension = '.cif' + elif format == 'pdb': + extension = '.pdb' + else: # no extension + extension = Auto + + # Get the filename and add extension if necessary if filename is Auto: filename = self.get_default_output_model_filename(extension=extension) - elif (extension is not Auto) and (not filename.endswith(extension)) and ( - append_ext): - if filename.endswith(".pdb") or filename.endswith(".cif"): - fn,ext = os.path.splitext(filename) - filename = fn + extension # replace extension + elif extension and (extension is not Auto) and ( + not extension_matches_ending(filename, extension)): + other_extension = ".pdb" if extension == ".cif" else ".cif" + fn,ext = os.path.splitext(filename) + if ext == other_extension: # swap extension + filename = fn + extension + elif extension_matches_ending(filename, other_extension): + filename = fn + "%s_%s" %(extension, ext.split("_")[1]) else: filename += extension if model_str: @@ -346,5 +365,13 @@ def write_model_file(self, model_str, filename=Auto, extension=Auto, else: return '' -# ============================================================================= +def extension_matches_ending(filename, extension): + if not extension: + return True + fn, ext = os.path.splitext(filename) + if ext == extension: + return True + if "_" in ext and ext.split("_")[0] == extension: + return True + # ============================================================================= # end diff --git a/iotbx/regression/tst_data_manager.py b/iotbx/regression/tst_data_manager.py index 2138207143..66037a7db4 100644 --- a/iotbx/regression/tst_data_manager.py +++ b/iotbx/regression/tst_data_manager.py @@ -878,8 +878,8 @@ def test_model_skip_ss_annotations(): ATOM 305 CD1 ILE A 20 21.947 6.045 5.765 1.00 12.70 C """ dm = DataManager(['model']) - dm.write_model_file(good_h_str + pdb_str, filename='good', extension='.pdb', overwrite=True) - dm.write_model_file(bad_h_str + pdb_str, filename='bad', extension='.pdb', overwrite=True) + dm.write_model_file(good_h_str + pdb_str, filename='good', format='pdb', overwrite=True) + dm.write_model_file(bad_h_str + pdb_str, filename='bad', format='pdb', overwrite=True) dm.process_model_file('good.pdb') try: dm.process_model_file('bad.pdb') diff --git a/mmtbx/command_line/map_box.py b/mmtbx/command_line/map_box.py index d2bc3284c0..8c5a1c8717 100644 --- a/mmtbx/command_line/map_box.py +++ b/mmtbx/command_line/map_box.py @@ -1216,9 +1216,9 @@ def run(args, filename = "%s_box"%output_prefix else: filename = "%s"%params.output_file_name_prefix full_filename = dm.write_model_file( - model, filename = filename, extension = ".pdb") + model, filename = filename, format = "pdb") print("Writing boxed PDB with box unit cell to %s" %( - "%s" %filename), file = log) + "%s" %full_filename), file = log) # Write NCS file if NCS if ncs_object and ncs_object.max_operators()>0: From c840fa66398b11e0dc1ed12a42ba6de2e9e8040b Mon Sep 17 00:00:00 2001 From: terwill Date: Mon, 5 Feb 2024 14:55:22 -0800 Subject: [PATCH 100/748] fix format/extension in docs --- cctbx_website/html_files/doc_hlo_model_map_manager.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cctbx_website/html_files/doc_hlo_model_map_manager.html b/cctbx_website/html_files/doc_hlo_model_map_manager.html index ce6bc0c3e8..4134d6fc7a 100644 --- a/cctbx_website/html_files/doc_hlo_model_map_manager.html +++ b/cctbx_website/html_files/doc_hlo_model_map_manager.html @@ -83,7 +83,7 @@

Setting up the Map-Model manager

If you write out either one then they will be written out in their original locations.

dm.write_real_map_file(mm,filename="my_map_original_location.mrc")    # write map
-dm.write_model_file(model,filename="my_model_original_location", extension="pdb") # model
+dm.write_model_file(model,filename="my_model_original_location", format="pdb") # model
 
@@ -102,7 +102,7 @@

Cutting out parts of maps and models

filename="box_around_219-223.mrc") # write the map out # dm.write_model_file(box_mmm.model(), # get the boxed model - filename="box_around_219-223", extension="pdb") # write out boxed model + filename="box_around_219-223", format="pdb") # write out boxed model

If you have a look at the map and model in box_around_219-223.mrc and box_around_219-223.pdb you will see that the map and model are only parts of the map and model that were in the original model.pdb and map.mrc that we started with.

From 6db5a99ffe45fbf94771a95ee05fcf83b058d30b Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 6 Feb 2024 08:51:36 -0800 Subject: [PATCH 101/748] Changes to fix the Q|R errors --- mmtbx/hydrogens/reduce_hydrogen.py | 1 + mmtbx/ligands/hierarchy_utils.py | 8 +++- mmtbx/ligands/ready_set_basics.py | 4 +- mmtbx/ligands/ready_set_utils.py | 76 ++++++++++++++++++++---------- 4 files changed, 62 insertions(+), 27 deletions(-) diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index c86badf5bd..5fc41bc89e 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -221,6 +221,7 @@ def run(self): p.pdb_interpretation.use_neutron_distances = self.use_neutron_distances p.pdb_interpretation.proceed_with_excessive_length_bonds=True #p.pdb_interpretation.automatic_linking.link_metals = True + p.pdb_interpretation.automatic_linking.link_residues = True t0 = time.time() #p.pdb_interpretation.restraints_library.cdl=False # XXX this triggers a bug !=360 diff --git a/mmtbx/ligands/hierarchy_utils.py b/mmtbx/ligands/hierarchy_utils.py index 4d98d99d8e..c5319bf080 100644 --- a/mmtbx/ligands/hierarchy_utils.py +++ b/mmtbx/ligands/hierarchy_utils.py @@ -101,7 +101,7 @@ def attempt_to_squash_alt_loc(hierarchy): rg.remove_atom_group(ags[1]) return squash_hierarchy -def get_bonds_as_dict(geometry_restraints_manager): +def get_bonds_as_dict(geometry_restraints_manager, include_non_zero_origin_id=True): bonds={} for bond in geometry_restraints_manager.get_all_bond_proxies(): if not hasattr(bond, 'get_proxies_with_origin_id'): continue @@ -110,6 +110,12 @@ def get_bonds_as_dict(geometry_restraints_manager): tmp.append(p.i_seqs[1]) tmp=bonds.setdefault(p.i_seqs[1], []) tmp.append(p.i_seqs[0]) + if include_non_zero_origin_id: + for p in bond.get_proxies_without_origin_id(0): + tmp=bonds.setdefault(p.i_seqs[0], []) + tmp.append(p.i_seqs[1]) + tmp=bonds.setdefault(p.i_seqs[1], []) + tmp.append(p.i_seqs[0]) return bonds def get_valences(element, charge): diff --git a/mmtbx/ligands/ready_set_basics.py b/mmtbx/ligands/ready_set_basics.py index 1eff90df67..a7e04b1472 100644 --- a/mmtbx/ligands/ready_set_basics.py +++ b/mmtbx/ligands/ready_set_basics.py @@ -69,9 +69,9 @@ def get_hierarchy_atom(name, element, xyz, occ=1., b=20.): atom.segid = ' '*4 return atom -def get_hierarchy_h_atom(name, xyz, heavy_atom): +def get_hierarchy_h_atom(name, xyz, heavy_atom, proton_element='H'): return get_hierarchy_atom(name, - 'H', + proton_element, xyz, heavy_atom.occ, heavy_atom.b, diff --git a/mmtbx/ligands/ready_set_utils.py b/mmtbx/ligands/ready_set_utils.py index 022e9ba15e..970259e19c 100644 --- a/mmtbx/ligands/ready_set_utils.py +++ b/mmtbx/ligands/ready_set_utils.py @@ -13,6 +13,12 @@ get_class = iotbx.pdb.common_residue_names_get_class +def distance2(xyz1, xyz2): + d2=0 + for k in range(3): + d2+=(xyz2[k]-xyz1[k])**2 + return d2 + def is_n_terminal_residue(residue_group): residues = [] for atom_group in residue_group.atom_groups(): @@ -39,7 +45,7 @@ def validate_c_ca_n_for_n_terminal(c,ca,n,bonds): if bonds is None: return True nb = bonds.get(n.i_seq, None) if not nb: return False - if len(nb) not in [1]: return False + if len(nb) not in [1, 2]: return False return True def validate_c_ca_n_for_c_terminal(c,ca,n,bonds): @@ -55,6 +61,7 @@ def add_n_terminal_hydrogens_to_atom_group(ag, append_to_end_of_model=False, retain_original_hydrogens=True, n_ca_c=None, + verbose=False, ): rc=[] if n_ca_c is not None: @@ -68,12 +75,6 @@ def add_n_terminal_hydrogens_to_atom_group(ag, if c is None: return 'no C' if not validate_c_ca_n_for_n_terminal(c, ca, n, bonds): return [] - # if bonds: - # ns = [] - # for key in bonds: - # if n.i_seq == key[0]: - # ns.append(key) - # if len(ns)>=3: return rc proton_element, proton_name = get_proton_info(ag) atom = ag.get_atom(proton_element) # just so happens that the atom is named H/D @@ -89,12 +90,7 @@ def add_n_terminal_hydrogens_to_atom_group(ag, else: if ag.get_atom(proton_name): # maybe needs to be smarter or actually work ag.remove_atom(ag.get_atom(proton_name)) - #if use_capping_hydrogens and 0: - # for i, atom in enumerate(ag.atoms()): - # if atom.name == ' H3 ': - # ag.remove_atom(i) - # break - # add H1 + rh3 = construct_xyz(n, 1.0, ca, 109.5, c, dihedral, @@ -115,15 +111,25 @@ def add_n_terminal_hydrogens_to_atom_group(ag, #if ag.atoms()[0].parent().resname=='PRO': # number_of_hydrogens=-1 # # should name the hydrogens correctly + if bonds: + atoms=ag.atoms() + i_seqs = atoms.extract_i_seq() + number_of_heavy=0 + for i_seq in bonds.get(n.i_seq, []): + if i_seq in i_seqs: + if not atoms[i_seq].element_is_hydrogen(): + number_of_heavy+=1 + else: + number_of_heavy+=1 + if number_of_heavy==2: + number_of_hydrogens-=2 + if verbose: print('number_of_heavy', number_of_heavy) + if verbose: print('number_of_hydrogens',number_of_hydrogens) if h_count+d_count>=number_of_hydrogens: return [] - def distance2(xyz1, xyz2): - d2=0 - for k in range(3): - d2+=(xyz2[k]-xyz1[k])**2 - return d2 j=0 for i in range(0, number_of_hydrogens): name = " %s%d " % (proton_element, i+1) + if number_of_hydrogens==1: name = ' %s ' % proton_element if retain_original_hydrogens: if i==0 and ag.get_atom(proton_name): continue if i==1 and ag.get_atom(proton_name): @@ -141,6 +147,7 @@ def distance2(xyz1, xyz2): atom.occ = n.occ atom.b = n.b atom.segid = ' '*4 + if verbose: print('adding', atom.quote()) if append_to_end_of_model and i+1==number_of_hydrogens: rg = _add_atom_to_chain(atom, ag, @@ -676,16 +683,37 @@ def delete_charged_n_terminal_hydrogens(hierarchy): ag.remove_atom(h3) def add_water_hydrogen_atoms_simple(hierarchy, log=None): + displacements = [ + [ 1.0, 0.0, 0.0], + [-0.7, -0.7, 0.0], + [ 0.0, 1.0, 0.0], + [-0.7, -0.7, 0.0], + [ 0.0, 0.0, 1.0], + [ 0.0, -0.7, -0.7], + ] for atom_group in hierarchy.atom_groups(): if atom_group.resname in ['HOH', 'DOD']: + proton_element='H' + if atom_group.resname=='DOD': proton_element='D' if len(atom_group.atoms())==3: continue + names = [atom.name for atom in atom_group.atoms()] o_atom = atom_group.atoms()[0] - xyz = (o_atom.xyz[0]+1, o_atom.xyz[1], o_atom.xyz[2]) - h1 = get_hierarchy_h_atom(' H1 ', xyz, o_atom) - atom_group.append_atom(h1) - xyz = (o_atom.xyz[0]-0.7, o_atom.xyz[1]-0.7, o_atom.xyz[2]) - h2 = get_hierarchy_h_atom(' H2 ', xyz, o_atom) - atom_group.append_atom(h2) + for name in [' %s1 ' % proton_element, ' %s2 ' % proton_element]: + if name not in names: + j=0 + min_d2=0 + while min_d2<.9: + xyz = (o_atom.xyz[0]+displacements[j][0], + o_atom.xyz[1]+displacements[j][1], + o_atom.xyz[2]+displacements[j][2]) + min_d2 = 1e9 + for atom in atom_group.atoms(): + d2 = distance2(xyz, atom.xyz) + min_d2=min(d2, min_d2) + j+=1 + h = get_hierarchy_h_atom(name, xyz, o_atom, proton_element=proton_element) + atom_group.append_atom(h) + # for atom in atom_group.atoms(): print(atom.format_atom_record()) def add_main_chain_atoms(hierarchy, geometry_restraints_manager, From 39fd031050cc78d57c07a82fad9a6b153f550af2 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 6 Feb 2024 09:59:18 -0800 Subject: [PATCH 102/748] Clean clutter --- iotbx/data_manager/model.py | 2 +- iotbx/pdb/tst_utils.py | 12 ++++++------ iotbx/pdb/utils.py | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/iotbx/data_manager/model.py b/iotbx/data_manager/model.py index 3a08cf6dfa..e3268f9c2d 100644 --- a/iotbx/data_manager/model.py +++ b/iotbx/data_manager/model.py @@ -354,7 +354,7 @@ def write_model_file(self, model_str, filename=Auto, other_extension = ".pdb" if extension == ".cif" else ".cif" fn,ext = os.path.splitext(filename) if ext == other_extension: # swap extension - filename = fn + extension + filename = fn + extension elif extension_matches_ending(filename, other_extension): filename = fn + "%s_%s" %(extension, ext.split("_")[1]) else: diff --git a/iotbx/pdb/tst_utils.py b/iotbx/pdb/tst_utils.py index 00f40eb6b6..b4429b9e46 100644 --- a/iotbx/pdb/tst_utils.py +++ b/iotbx/pdb/tst_utils.py @@ -30,14 +30,14 @@ """ pseudo_as_pdb=""" -ATOM 10 CA ASN A 141 30.271 17.061 23.474 1.00 5.65 +ATOM 10 CA ASN A 141 30.271 17.061 23.474 1.00 5.65 ATOM 24 ZC1' GC U 11 10.024 9.813 3.777 1.00 36.50 UNK """ spacing_as_pdb=""" -ATOM 10 I ASN A 141 30.271 17.061 23.474 1.00 5.65 -ATOM 11 I ASN A 141 30.271 17.061 23.474 1.00 5.65 -HETATM 12 I LIG A 141 30.271 17.061 23.474 1.00 5.65 -HETATM 13 I LIG A 141 30.271 17.061 23.474 1.00 5.65 +ATOM 10 I ASN A 141 30.271 17.061 23.474 1.00 5.65 +ATOM 11 I ASN A 141 30.271 17.061 23.474 1.00 5.65 +HETATM 12 I LIG A 141 30.271 17.061 23.474 1.00 5.65 +HETATM 13 I LIG A 141 30.271 17.061 23.474 1.00 5.65 """ as_pdb = pdb_str_to_be_cif @@ -71,7 +71,7 @@ def exercise_add_models_and_hierarchies(): def exercise_set_element_ignoring_spacings(): from iotbx.pdb.utils import get_pdb_info pdb_info = get_pdb_info(spacing_as_pdb, allow_incorrect_spacing = True) - from iotbx.pdb.utils import set_element_ignoring_spacings + from iotbx.pdb.utils import set_element_ignoring_spacings set_element_ignoring_spacings(pdb_info.hierarchy) def exercise_check_pseudo_atoms(): diff --git a/iotbx/pdb/utils.py b/iotbx/pdb/utils.py index 8706488a42..60db1ab58c 100644 --- a/iotbx/pdb/utils.py +++ b/iotbx/pdb/utils.py @@ -548,7 +548,7 @@ def add_models(model_list, create_new_chain_ids_if_necessary = True): return None # nothing to do if model_list[0].crystal_symmetry() is not None: - model_list[0] = model_list[0].deep_copy() + model_list[0] = model_list[0].deep_copy() m_had_crystal_symmetry = True else: # Need crystal symmetry for deep_copy of model crystal_symmetry = None From 8f502568291934525d3901988af9b1d93c9772a7 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 6 Feb 2024 10:31:23 -0800 Subject: [PATCH 103/748] Print conversion info to out --- mmtbx/validation/clashscore.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mmtbx/validation/clashscore.py b/mmtbx/validation/clashscore.py index 27e4e2fe08..7848c20b89 100644 --- a/mmtbx/validation/clashscore.py +++ b/mmtbx/validation/clashscore.py @@ -133,7 +133,8 @@ def __init__(self, hierarchy = pdb_hierarchy) conversion_info.\ convert_hierarchy_to_forward_compatible_pdb_representation(pdb_hierarchy) - print("Converted model to forward_compatible PDB for clashscore") + print( + "Converted model to forward_compatible PDB for clashscore",file = out) else: conversion_info = None validation.__init__(self) @@ -206,7 +207,7 @@ def __init__(self, clashscore_b_cutoff if conversion_info: - print("Converted model back to full representation") + print("Converted model back to full representation", file = out) conversion_info.convert_hierarchy_to_full_representation(pdb_hierarchy) def get_clashscore(self): From 78c0e789876f2c7be9ba0e64fa35ea16cbaec85b Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 6 Feb 2024 10:46:24 -0800 Subject: [PATCH 104/748] Only print out if verbose --- mmtbx/validation/clashscore.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mmtbx/validation/clashscore.py b/mmtbx/validation/clashscore.py index 7848c20b89..63b5338e8b 100644 --- a/mmtbx/validation/clashscore.py +++ b/mmtbx/validation/clashscore.py @@ -133,7 +133,8 @@ def __init__(self, hierarchy = pdb_hierarchy) conversion_info.\ convert_hierarchy_to_forward_compatible_pdb_representation(pdb_hierarchy) - print( + if verbose: + print( "Converted model to forward_compatible PDB for clashscore",file = out) else: conversion_info = None @@ -207,7 +208,8 @@ def __init__(self, clashscore_b_cutoff if conversion_info: - print("Converted model back to full representation", file = out) + if verbose: + print("Converted model back to full representation", file = out) conversion_info.convert_hierarchy_to_full_representation(pdb_hierarchy) def get_clashscore(self): From b0181bf5d3e69d378e612b3b40b57ea1ab419c74 Mon Sep 17 00:00:00 2001 From: nksauter Date: Tue, 6 Feb 2024 12:00:59 -0800 Subject: [PATCH 105/748] Port the diffBragg diffuse halo code to the exascale/kokkos API. (#957) * Supporting class, diffuse_api Within the exascale kokkos API, the new class is a container for diffuse scattering parameters and unit cell basis vectors. Modification of function signature to include diffuse_api, cell params. * Expose diffuse_api class to Python * Reuse the diffBragg diffuse stencil code. Allows the exascale kokkos API to use the same diffuse scaling as diffBragg. * Tie exascale kokkos API diffuse-> diffbragg kokkos * Delete file that was committed by accident. * Fix issues raised by @dermen and @Trzs --- .../diffBragg/src/diffBragg_kokkos_kernel.cpp | 16 +++- simtbx/diffBragg/src/diffuse_util_kokkos.h | 5 +- simtbx/kokkos/SConscript | 15 ++++ simtbx/kokkos/kokkos_ext.cpp | 81 +++++++++++++++++ simtbx/kokkos/simulation.cpp | 8 ++ simtbx/kokkos/simulation.h | 14 +++ simtbx/kokkos/simulation_kernels.h | 87 ++++++++++++++++++- 7 files changed, 218 insertions(+), 8 deletions(-) diff --git a/simtbx/diffBragg/src/diffBragg_kokkos_kernel.cpp b/simtbx/diffBragg/src/diffBragg_kokkos_kernel.cpp index f6bfe0b119..5705914642 100644 --- a/simtbx/diffBragg/src/diffBragg_kokkos_kernel.cpp +++ b/simtbx/diffBragg/src/diffBragg_kokkos_kernel.cpp @@ -156,6 +156,7 @@ void kokkos_sum_over_steps( const KOKKOS_MAT3 eig_Otranspose = eig_O.transpose(); const KOKKOS_MAT3 Amat_init = eig_U * Bmat_realspace * eig_Otranspose; const KOKKOS_MAT3 Ainv = eig_U*(Bmat_realspace.transpose().inverse())* (eig_O.inverse()); + const CUDAREAL reciprocal_space_volume = 8*M_PI*M_PI*M_PI*Ainv.determinant(); const KOKKOS_MAT3 _NABC {Na, Nd, Nf, Nd, Nb, Ne, Nf, Ne, Nc}; const double NABC_det = _NABC.determinant(); // TODO is this slow ? const double NABC_det_sq = NABC_det * NABC_det; @@ -164,6 +165,10 @@ void kokkos_sum_over_steps( KOKKOS_MAT3 anisoG_local; CUDAREAL anisoG_determ = 0; KOKKOS_MAT3 anisoU_local; + const CUDAREAL _tmpfac = M_PI * 0.63 / fudge; + const CUDAREAL diffuse_scale = reciprocal_space_volume * sqrt(_tmpfac*_tmpfac*_tmpfac); + // ***NEEDS UPDATE: use legacy API for passing diffuse scale as KOKKOS_MAT3 + KOKKOS_MAT3 diffuse_scale_mat3(diffuse_scale,0,0,0,0,0,0,0,0); vector_mat3_t laue_mats = vector_mat3_t("laue_mats", 24); vector_vec3_t dG_dgam = vector_vec3_t("dG_dgam", 3); vector_cudareal_t dG_trace = vector_cudareal_t("dG_trace", 3); @@ -444,7 +449,8 @@ void kokkos_sum_over_steps( // are we doing diffuse scattering CUDAREAL step_diffuse_param[6] = {0, 0, 0, 0, 0, 0}; if (use_diffuse) { - calc_diffuse_at_hkl(H_vec,H0,dHH,h_min,k_min,l_min,h_max,k_max,l_max,h_range,k_range,l_range,Ainv,FhklLinear,num_laue_mats,laue_mats,anisoG_local,dG_trace,anisoG_determ,anisoU_local,dG_dgam,(refine_flag & REFINE_DIFFUSE)>0,&I0,step_diffuse_param); + // ***NEEDS UPDATE: use legacy API for passing diffuse scale as KOKKOS_MAT3 + calc_diffuse_at_hkl(H_vec,H0,dHH,h_min,k_min,l_min,h_max,k_max,l_max,h_range,k_range,l_range,diffuse_scale_mat3,FhklLinear,num_laue_mats,laue_mats,anisoG_local,dG_trace,anisoG_determ,anisoU_local,dG_dgam,(refine_flag & REFINE_DIFFUSE)>0,&I0,step_diffuse_param); } // end s_use_diffuse outer CUDAREAL _F_cell = default_F; @@ -1334,6 +1340,7 @@ void kokkos_sum_over_steps( const KOKKOS_MAT3 eig_Otranspose = eig_O.transpose(); const KOKKOS_MAT3 Amat_init = eig_U * Bmat_realspace * eig_Otranspose; const KOKKOS_MAT3 Ainv = eig_U*(Bmat_realspace.transpose().inverse())* (eig_O.inverse()); + const CUDAREAL reciprocal_space_volume = 8*M_PI*M_PI*M_PI*Ainv.determinant(); const KOKKOS_MAT3 _NABC {Na, Nd, Nf, Nd, Nb, Ne, Nf, Ne, Nc}; const double NABC_det = _NABC.determinant(); // TODO is this slow ? const double NABC_det_sq = NABC_det * NABC_det; @@ -1342,6 +1349,10 @@ void kokkos_sum_over_steps( KOKKOS_MAT3 anisoG_local; CUDAREAL anisoG_determ = 0; KOKKOS_MAT3 anisoU_local; + const CUDAREAL _tmpfac = M_PI * 0.63 / fudge; + const CUDAREAL diffuse_scale = reciprocal_space_volume * sqrt(_tmpfac*_tmpfac*_tmpfac); + // ***NEEDS UPDATE: use legacy API for passing diffuse scale as KOKKOS_MAT3 + KOKKOS_MAT3 diffuse_scale_mat3(diffuse_scale,0,0,0,0,0,0,0,0); vector_mat3_t laue_mats = vector_mat3_t("laue_mats", 24); vector_vec3_t dG_dgam = vector_vec3_t("dG_dgam", 3); vector_cudareal_t dG_trace = vector_cudareal_t("dG_trace", 3); @@ -1619,7 +1630,8 @@ void kokkos_sum_over_steps( // are we doing diffuse scattering CUDAREAL step_diffuse_param[6] = {0, 0, 0, 0, 0, 0}; if (use_diffuse) { - calc_diffuse_at_hkl(H_vec,H0,dHH,h_min,k_min,l_min,h_max,k_max,l_max,h_range,k_range,l_range,Ainv,FhklLinear,num_laue_mats,laue_mats,anisoG_local,dG_trace,anisoG_determ,anisoU_local,dG_dgam,(refine_flag & REFINE_DIFFUSE)>0,&I0,step_diffuse_param); + // ***NEEDS UPDATE: use legacy API for passing diffuse scale as KOKKOS_MAT3 + calc_diffuse_at_hkl(H_vec,H0,dHH,h_min,k_min,l_min,h_max,k_max,l_max,h_range,k_range,l_range,diffuse_scale_mat3,FhklLinear,num_laue_mats,laue_mats,anisoG_local,dG_trace,anisoG_determ,anisoU_local,dG_dgam,(refine_flag & REFINE_DIFFUSE)>0,&I0,step_diffuse_param); } // end s_use_diffuse outer CUDAREAL _F_cell = default_F; diff --git a/simtbx/diffBragg/src/diffuse_util_kokkos.h b/simtbx/diffBragg/src/diffuse_util_kokkos.h index 397db20f73..f7f712b4e4 100644 --- a/simtbx/diffBragg/src/diffuse_util_kokkos.h +++ b/simtbx/diffBragg/src/diffuse_util_kokkos.h @@ -549,8 +549,9 @@ int gen_laue_mats(int laue_group_num, vector_mat3_t lmats, KOKKOS_MAT3 rpa) { return num_mats; }; +// ***NEEDS UPDATE: use legacy API for passing diffuse scale as KOKKOS_MAT3 KOKKOS_FUNCTION -void calc_diffuse_at_hkl(KOKKOS_VEC3 H_vec, KOKKOS_VEC3 H0, KOKKOS_VEC3 dHH, int h_min, int k_min, int l_min, int h_max, int k_max, int l_max, int h_range, int k_range, int l_range, KOKKOS_MAT3 Ainv, const vector_cudareal_t FhklLinear, int num_laue_mats, const vector_mat3_t laue_mats, KOKKOS_MAT3 anisoG_local, vector_cudareal_t dG_trace, CUDAREAL anisoG_determ, KOKKOS_MAT3 anisoU_local, const vector_vec3_t dG_dgam, bool refine_diffuse, CUDAREAL *I0, CUDAREAL *step_diffuse_param){ +void calc_diffuse_at_hkl(KOKKOS_VEC3 H_vec, KOKKOS_VEC3 H0, KOKKOS_VEC3 dHH, int h_min, int k_min, int l_min, int h_max, int k_max, int l_max, int h_range, int k_range, int l_range, const KOKKOS_MAT3 diffuse_scale_mat3, const vector_cudareal_t FhklLinear, int num_laue_mats, const vector_mat3_t laue_mats, KOKKOS_MAT3 anisoG_local, vector_cudareal_t dG_trace, CUDAREAL anisoG_determ, KOKKOS_MAT3 anisoU_local, const vector_vec3_t dG_dgam, bool refine_diffuse, CUDAREAL *I0, CUDAREAL *step_diffuse_param){ constexpr CUDAREAL four_mpi_sq = 4.*M_PI*M_PI; // loop over laue matrices int num_stencil_points = (2*dHH[0] + 1) * (2*dHH[1] + 1) * (2*dHH[2] + 1); @@ -573,7 +574,7 @@ void calc_diffuse_at_hkl(KOKKOS_VEC3 H_vec, KOKKOS_VEC3 H0, KOKKOS_VEC3 dHH, int else _this_diffuse_scale = 1.0; - _this_diffuse_scale *= _this_diffuse_scale/(CUDAREAL)num_laue_mats/(CUDAREAL)num_stencil_points; + _this_diffuse_scale *= _this_diffuse_scale * diffuse_scale_mat3(0,0) / (CUDAREAL)num_laue_mats; // legacy API for passing diffuse_scale const KOKKOS_VEC3 H0_offset(H0[0]+hh, H0[1]+kk, H0[2]+ll); const KOKKOS_VEC3 delta_H_offset = H_vec - H0_offset; diff --git a/simtbx/kokkos/SConscript b/simtbx/kokkos/SConscript index 2407718563..bc72ee122d 100644 --- a/simtbx/kokkos/SConscript +++ b/simtbx/kokkos/SConscript @@ -127,6 +127,21 @@ if use_sycl: kokkos_env.Replace(CXXFLAGS=[list(OrderedDict.fromkeys(kokkos_env['CXXFLAGS']))]) kokkos_env.Replace(SHLINKFLAGS=[list(OrderedDict.fromkeys(kokkos_env['SHLINKFLAGS']))]) +if True: # diffuse code in exascale API + # "if True" block is intended to demark the linkage against the eigen library + # which is needed to reuse the diffBragg function calc_diffuse_at_hkl() within kokkos/simulation. + # This block can be removed in the future if the eigen dependency is replaced by kokkoslib. + env_etc.eigen_dist = os.path.abspath(os.path.join(libtbx.env.dist_path("simtbx"),"../../eigen")) + if not os.path.isdir(env_etc.eigen_dist) and hasattr(env_etc, "conda_cpppath"): + for candidate in env_etc.conda_cpppath: + if os.path.isdir(os.path.join(candidate, "eigen3")): + env_etc.eigen_dist = os.path.abspath(os.path.join(os.path.join(candidate, "eigen3"))) + if os.path.isdir(env_etc.eigen_dist): + env_etc.eigen_include = env_etc.eigen_dist + env_etc.include_registry.append( + env=kokkos_env, + paths=[env_etc.eigen_include]) + simtbx_kokkos_lib = kokkos_env.SharedLibrary( target="#lib/libsimtbx_kokkos.so", source=[ diff --git a/simtbx/kokkos/kokkos_ext.cpp b/simtbx/kokkos/kokkos_ext.cpp index 56eb018a95..f630f9bd3e 100644 --- a/simtbx/kokkos/kokkos_ext.cpp +++ b/simtbx/kokkos/kokkos_ext.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "simtbx/kokkos/kokkos_instance.h" #include "simtbx/kokkos/detector.h" @@ -10,6 +11,47 @@ namespace simtbx { namespace Kokkos { + namespace { + static void set_anisoG(simtbx::Kokkos::diffuse_api& diffuse, boost::python::list const& values) { + double g0 = boost::python::extract(values[0]); + double g1 = boost::python::extract(values[1]); + double g2 = boost::python::extract(values[2]); + diffuse.anisoG << g0,0,0,0,g1,0,0,0,g2; + } + + static boost::python::tuple get_anisoG(simtbx::Kokkos::diffuse_api const& diffuse) { + return boost::python::make_tuple(diffuse.anisoG[0],diffuse.anisoG[4],diffuse.anisoG[8]); + } + + static void set_anisoU(simtbx::Kokkos::diffuse_api& diffuse, boost::python::list const& values) { + double g0 = boost::python::extract(values[0]); + double g1 = boost::python::extract(values[1]); + double g2 = boost::python::extract(values[2]); + diffuse.anisoU << g0,0,0,0,g1,0,0,0,g2; + } + + static boost::python::tuple get_anisoU(simtbx::Kokkos::diffuse_api const& diffuse) { + return boost::python::make_tuple(diffuse.anisoU[0],diffuse.anisoU[4],diffuse.anisoU[8]); + } + + static void set_rotate_principal_axes(simtbx::Kokkos::diffuse_api& diffuse, std::string const& value) { + if (value==std::string("a,b,c")){ + diffuse.rotate_principal_axes << 1.,0.,0.,0.,1.,0.,0.,0.,1.; + } else if (value==std::string("a-b,a+b,c")){ + double sqrt2o2 = std::sqrt(2.)/2.; + diffuse.rotate_principal_axes << sqrt2o2,-sqrt2o2,0.,sqrt2o2,sqrt2o2,0.,0.,0.,1.; + } else { + throw std::string("rotation case not implemented"); + } + } + + static boost::python::tuple get_rotate_principal_axes(simtbx::Kokkos::diffuse_api const& diffuse) { + return boost::python::make_tuple(diffuse.rotate_principal_axes[0],diffuse.rotate_principal_axes[1],diffuse.rotate_principal_axes[2], + diffuse.rotate_principal_axes[3],diffuse.rotate_principal_axes[4],diffuse.rotate_principal_axes[5], + diffuse.rotate_principal_axes[6],diffuse.rotate_principal_axes[7],diffuse.rotate_principal_axes[8]); + } + } + struct kokkos_instance_wrapper { static void @@ -91,6 +133,8 @@ namespace simtbx { namespace Kokkos { wrap() { using namespace boost::python; + typedef return_value_policy rbv; + typedef default_call_policies dcp; using namespace simtbx::Kokkos; class_("exascale_api",no_init ) .def(init( @@ -130,6 +174,43 @@ namespace simtbx { namespace Kokkos { (arg_("detector")), "Modify pixels with noise on CPU. Unusual pattern, returns pixels directly instead of saving persistent") .def("show",&simtbx::Kokkos::exascale_api::show) + .add_property("diffuse", + make_getter(&simtbx::Kokkos::exascale_api::diffuse,rbv()), + make_setter(&simtbx::Kokkos::exascale_api::diffuse,dcp()), + "the diffuse parameters for the simulation.") + ; + + class_("diffuse_api",no_init ) + .def(init<>()) + .add_property("enable", + make_getter(&simtbx::Kokkos::diffuse_api::enable,rbv()), + make_setter(&simtbx::Kokkos::diffuse_api::enable,dcp()), + "whether or not to simulate diffuse.") + .add_property("stencil_size", + make_getter(&simtbx::Kokkos::diffuse_api::stencil_size,rbv()), + make_setter(&simtbx::Kokkos::diffuse_api::stencil_size,dcp()), + "") + .add_property("symmetrize_diffuse", + make_getter(&simtbx::Kokkos::diffuse_api::symmetrize_diffuse,rbv()), + make_setter(&simtbx::Kokkos::diffuse_api::symmetrize_diffuse,dcp()), + "") + .add_property("laue_group_num", + make_getter(&simtbx::Kokkos::diffuse_api::laue_group_num,rbv()), + make_setter(&simtbx::Kokkos::diffuse_api::laue_group_num,dcp()), + "") + .add_property("anisoG", + make_function(&get_anisoG,rbv()), + make_function(&set_anisoG,dcp()), + "") + .add_property("anisoU", + make_function(&get_anisoU,rbv()), + make_function(&set_anisoU,dcp()), + "") + .add_property("rotate_principal_axes", + make_function(&get_rotate_principal_axes,rbv()), + make_function(&set_rotate_principal_axes,dcp()), + "") + .def("show",&simtbx::Kokkos::diffuse_api::show) ; } }; diff --git a/simtbx/kokkos/simulation.cpp b/simtbx/kokkos/simulation.cpp index 3770383e61..5644654192 100644 --- a/simtbx/kokkos/simulation.cpp +++ b/simtbx/kokkos/simulation.cpp @@ -217,6 +217,9 @@ namespace Kokkos { // for call for all panels at the same time + // set up cell basis vectors for the diffuse parameters (convert vec4 to vec3) + diffuse.a0 << SIM.a0[1],SIM.a0[2],SIM.a0[3]; diffuse.b0 << SIM.b0[1],SIM.b0[2],SIM.b0[3]; diffuse.c0 << SIM.c0[1],SIM.c0[2],SIM.c0[3]; + debranch_maskall_Kernel( kdt.m_panel_count, kdt.m_slow_dim_size, kdt.m_fast_dim_size, active_pixel_list.size(), SIM.oversample, SIM.point_pixel, @@ -242,6 +245,7 @@ namespace Kokkos { SIM.nopolar, m_polar_vector, SIM.polarization, SIM.fudge, kdt.m_active_pixel_list, + diffuse, // return arrays: kdt.m_floatimage, kdt.m_omega_reduction, @@ -301,6 +305,9 @@ namespace Kokkos { kokkostbx::transfer_double2kokkos(c_source_I, &(weighted_I), 1); kokkostbx::transfer_double2kokkos(c_source_lambda, &(SIM.source_lambda[ictr]), 1); + // set up cell basis vectors for the diffuse parameters (convert vec4 to vec3) + diffuse.a0 << SIM.a0[1],SIM.a0[2],SIM.a0[3]; diffuse.b0 << SIM.b0[1],SIM.b0[2],SIM.b0[3]; diffuse.c0 << SIM.c0[1],SIM.c0[2],SIM.c0[3]; + debranch_maskall_Kernel( kdt.m_panel_count, kdt.m_slow_dim_size, kdt.m_fast_dim_size, active_pixel_list.size(), SIM.oversample, SIM.point_pixel, @@ -326,6 +333,7 @@ namespace Kokkos { SIM.nopolar, m_polar_vector, SIM.polarization, SIM.fudge, kdt.m_active_pixel_list, + diffuse, // return arrays: kdt.m_floatimage, kdt.m_omega_reduction, diff --git a/simtbx/kokkos/simulation.h b/simtbx/kokkos/simulation.h index f1fc1c68ca..ca2d763ad7 100644 --- a/simtbx/kokkos/simulation.h +++ b/simtbx/kokkos/simulation.h @@ -18,6 +18,19 @@ namespace simtbx { namespace Kokkos { namespace af = scitbx::af; +struct diffuse_api { + inline diffuse_api() {}; + inline void show() {}; + bool enable = false; + mat3 anisoG; + mat3 anisoU; + int stencil_size = 1; + bool symmetrize_diffuse = true; + int laue_group_num = 12; + mat3 rotate_principal_axes; + vec3 a0, b0, c0; // cell basis vectors +}; + struct exascale_api { inline exascale_api(const simtbx::nanoBragg::nanoBragg& nB) : SIM(nB) { } @@ -72,6 +85,7 @@ struct exascale_api { CUDAREAL m_water_size = 0; CUDAREAL m_water_F = 0; CUDAREAL m_water_MW = 0; + diffuse_api diffuse; }; } // Kokkos } // simtbx diff --git a/simtbx/kokkos/simulation_kernels.h b/simtbx/kokkos/simulation_kernels.h index 6058b58ccf..0a91f33e59 100644 --- a/simtbx/kokkos/simulation_kernels.h +++ b/simtbx/kokkos/simulation_kernels.h @@ -6,7 +6,8 @@ using mat3 = kokkostbx::matrix3; #include #include - +#include +#include // test diffuse halo in exascale API context. using simtbx::nanoBragg::shapetype; using simtbx::nanoBragg::hklParams; @@ -363,6 +364,7 @@ void debranch_maskall_Kernel(int npanels, int spixels, int fpixels, int total_pi int nopolar, const vector_cudareal_t polar_vector, CUDAREAL polarization, CUDAREAL fudge, const vector_size_t pixel_lookup, + simtbx::Kokkos::diffuse_api diffuse, vector_float_t floatimage /*out*/, vector_float_t omega_reduction /*out*/, vector_float_t max_I_x_reduction /*out*/, vector_float_t max_I_y_reduction /*out*/, vector_bool_t rangemap) { @@ -378,6 +380,68 @@ void debranch_maskall_Kernel(int npanels, int spixels, int fpixels, int total_pi const int s_k_max = s_k_min + s_k_range - 1; const int s_l_max = s_l_min + s_l_range - 1; + // set up diffuse scattering if needed + vector_mat3_t laue_mats = vector_mat3_t("laue_mats",24); + vector_cudareal_t dG_trace = vector_cudareal_t("dG_trace",3); + vector_vec3_t dG_dgam = vector_vec3_t("dG_dgam",3); + int num_laue_mats = 0; + int dhh = 0, dkk = 0, dll = 0; + KOKKOS_MAT3 rotate_principal_axes = diffuse.rotate_principal_axes; // (1,0,0,0,1,0,0,0,1); + int laue_group_num = diffuse.laue_group_num; + int stencil_size = diffuse.stencil_size; + KOKKOS_MAT3 anisoG = diffuse.anisoG; // (300.,0,0,0,100.,0,0,0,300.); + KOKKOS_MAT3 anisoU = diffuse.anisoU; // (0.48,0,0,0,0.16,0,0,0,0.16); + KOKKOS_MAT3 Bmat_realspace(1.,0,0,0,1.,0,0,0,1.); // Placeholder + KOKKOS_MAT3 anisoG_local; + CUDAREAL anisoG_determ = 0; + KOKKOS_MAT3 anisoU_local; + bool use_diffuse=diffuse.enable; + // ***NEEDS UPDATE: use legacy API for passing diffuse scale as KOKKOS_MAT3 + vector_mat3_t diffuse_scale_mat3 = vector_mat3_t("diffuse_scale_mat3",1); + + if (use_diffuse){ + anisoG_local = anisoG; + anisoU_local = anisoU; + + if (laue_group_num < 1 || laue_group_num >14 ){ + throw std::string("Laue group number not in range 1-14"); + } + + Kokkos::parallel_reduce("prepare diffuse mats", 1, KOKKOS_LAMBDA (const int& i, int& num_laue_mats_temp){ + num_laue_mats_temp = gen_laue_mats(laue_group_num, laue_mats, rotate_principal_axes); + // KOKKOS_MAT3 rotate_principal_axes; + // rotate_principal_axes << 0.70710678, -0.70710678, 0., 0.70710678, 0.70710678, 0., 0., 0., 1.; + + KOKKOS_MAT3 Amatrix(diffuse.a0[0],diffuse.a0[1],diffuse.a0[2],diffuse.b0[0],diffuse.b0[1],diffuse.b0[2], + diffuse.c0[0],diffuse.c0[1],diffuse.c0[2]); + KOKKOS_MAT3 Ainv = Amatrix.inverse()*1.e-10; + CUDAREAL reciprocal_space_volume = 8*M_PI*M_PI*M_PI*Ainv.determinant(); + CUDAREAL _tmpfac = M_PI * 0.63 / fudge; + CUDAREAL diffuse_scale = reciprocal_space_volume * sqrt(_tmpfac*_tmpfac*_tmpfac); + + // ***NEEDS UPDATE: use legacy API for passing diffuse scale as KOKKOS_MAT3 + diffuse_scale_mat3(0)(0,0) = diffuse_scale; + + for ( int iL = 0; iL < num_laue_mats_temp; iL++ ){ + laue_mats(iL) = Ainv * laue_mats(iL); + } + const KOKKOS_MAT3 Ginv = anisoG_local.inverse(); + const KOKKOS_MAT3 dG = Bmat_realspace * Ginv; + for (int i_gam=0; i_gam<3; i_gam++){ + dG_dgam(i_gam)[i_gam] = 1; + KOKKOS_MAT3 temp_dgam; + temp_dgam(i_gam, 0) = dG_dgam(i_gam)[0]; + temp_dgam(i_gam, 1) = dG_dgam(i_gam)[1]; + temp_dgam(i_gam, 2) = dG_dgam(i_gam)[2]; + dG_trace(i_gam) = (Ginv*temp_dgam).trace(); + } + }, num_laue_mats); + anisoG_determ = anisoG_local.determinant(); + dhh = dkk = dll = stencil_size; // Limits of stencil for diffuse calc + } + KOKKOS_VEC3 dHH(dhh,dkk,dll); + // end of diffuse setup + // Implementation notes. This kernel is aggressively debranched, therefore the assumptions are: // 1) mosaicity non-zero positive // 2) xtal shape is "Gauss" i.e. 3D spheroid. @@ -516,14 +580,29 @@ void debranch_maskall_Kernel(int npanels, int spixels, int fpixels, int total_pi // structure factor of the lattice (paralelpiped crystal) // F_latt = sin(M_PI*s_Na*h)*sin(M_PI*s_Nb*k)*sin(M_PI*s_Nc*l)/sin(M_PI*h)/sin(M_PI*k)/sin(M_PI*l); - CUDAREAL F_latt = 1.0; // Shape transform for the crystal. + CUDAREAL I_latt = 1.0; // Shape transform for the crystal. CUDAREAL hrad_sqr = 0.0; // handy radius in reciprocal space, squared hrad_sqr = (h - h0) * (h - h0) * Na * Na + (k - k0) * (k - k0) * Nb * Nb + (l - l0) * (l - l0) * Nc * Nc; // fudge the radius so that volume and FWHM are similar to square_xtal spots double my_arg = hrad_sqr / 0.63 * fudge; - F_latt = Na * Nb * Nc * exp(-(my_arg)); + { + CUDAREAL F_latt = Na * Nb * Nc * exp(-(my_arg)); + I_latt = F_latt * F_latt; + } + + // new code for diffuse. + if (use_diffuse) { + KOKKOS_VEC3 H_vec(h,k,l); + KOKKOS_VEC3 H0(h0,k0,l0); + CUDAREAL step_diffuse_param[6]; + // ***NEEDS UPDATE: use legacy API for passing diffuse scale as KOKKOS_MAT3 + calc_diffuse_at_hkl(H_vec,H0,dHH,s_h_min,s_k_min,s_l_min,s_h_max,s_k_max, + s_l_max,s_h_range,s_k_range,s_l_range,diffuse_scale_mat3(0),Fhkl,num_laue_mats,laue_mats, + anisoG_local,dG_trace,anisoG_determ,anisoU_local,dG_dgam,false,&I_latt,step_diffuse_param); + } + // end s_use_diffuse outer // structure factor of the unit cell CUDAREAL F_cell = default_F; @@ -545,7 +624,7 @@ void debranch_maskall_Kernel(int npanels, int spixels, int fpixels, int total_pi // now we have the structure factor for this pixel // convert amplitudes into intensity (photons per steradian) - I += F_cell * F_cell * F_latt * F_latt * source_fraction * capture_fraction * omega_pixel; + I += F_cell * F_cell * I_latt * source_fraction * capture_fraction * omega_pixel; omega_sub_reduction += omega_pixel; } // end of mosaic loop } // end of phi loop From fcaa1a6cde28b4223e26ebe7bbb32ae699545b85 Mon Sep 17 00:00:00 2001 From: Russell Taylor Date: Tue, 6 Feb 2024 15:39:59 -0500 Subject: [PATCH 106/748] R2s (#965) * Speeding up atom information dumping by pulling code out of an inner loop * Speeding up Mover placement by only checking hydrogens to see if they are in rotatable hydrogen list. * Recompute the score at the original coarse location during fine optimization because other Movers in our clique may have changed, which could change this score from the one recorded during coarse optimization. * Directly placing rotatable hydrogens on the correct atoms rather than checking every atom's i_seq against the list of rotatable hydrogens greatly speeds up Mover placement. By placing all SingleHydrogenRotators after all tetrahedral alignments and flip Mover lockdowns, we should improve optimization by taking these fixed motions into account before optimizing. * Printing additional info to help determine which parts are slow. * Avoids filling in the atom-dump information when it will not be printed. Bumped version number to reflect recent changes in behavior while speeding up Mover placement. * Version 2.6.0 of Probe2 uses a set to accelerate searches for atoms in the current model, reducing runtime by more than a factor of 10 for larger models. * Removing the option to use implicit hydrogen distances for probe2, bumping major version number for probe2 to 3.0 to reflect this change in functionality. Per Jane Richardson: We never ourselves use implicit radii and truly don't want anyone else to do it, since the a major point of our work is that they give the wrong results. We needed that option initially in order to show how bad they are! It's an even stronger point than no methyl rotations. * Adding information about how to run probe2 for a ligand against the molecule to --help * Simplifying instructions * Properly set default description file name for both PDB and CIF input files. * Adding check for running original reduce on an mmCIF format file, raising a Sorry() if we try this. * Improved error message. * Implementing bottleneck function from Reduce2 into C++. * Version 4.0.0 of probe2 makes pointmasters for alternate conformations for dots and it removes the alt-a restriction from the source selection by default so that all alternates are considered. --- mmtbx/probe/Helpers.py | 62 +-- mmtbx/programs/probe2.py | 289 ++++++----- mmtbx/programs/reduce2.py | 8 +- mmtbx/reduce/Movers.py | 11 +- mmtbx/reduce/Optimizers.cpp | 6 +- mmtbx/reduce/Optimizers.py | 198 +++---- mmtbx/reduce/boost_python/reduce_bpl.cpp | 27 + mmtbx/regression/__init__.py | 634 +++++++++++++++++++++++ mmtbx/regression/tst_reduce_timeout.py | 71 ++- mmtbx/utils/__init__.py | 8 + 10 files changed, 1019 insertions(+), 295 deletions(-) diff --git a/mmtbx/probe/Helpers.py b/mmtbx/probe/Helpers.py index ff8134adda..eb5e0b54d9 100644 --- a/mmtbx/probe/Helpers.py +++ b/mmtbx/probe/Helpers.py @@ -102,11 +102,6 @@ .short_caption = Count weak hydrogen bonds .help = Separately account for weak hydrogen bonds (-LweakHbonds in probe) - implicit_hydrogens = False - .type = bool - .short_caption = Model has implicit hydrogens - .help = Use implicit hydrogens, no water proxies (-implicit in probe) - ignore_ion_interactions = False .type = bool .short_caption = Ignore ion interactions @@ -363,9 +358,6 @@ def getExtraAtomInfo(model, bondedNeighborLists, useNeutronDistances = False, pr self.params.probe from a Program Template program that includes the probe_phil_parameters from above in its master PHIL parameters string. If None, local defaults will be used. The following are used: - implicit_hydrogens (bool): Default is to use distances consistent with - explicitly-listed Hydrgoens, but setting this to True implicit-Hydrogen distances instead. - This must be set consistently with the hydrogens in the model. set_polar_hydrogen_radius(bool): Default is to override the radius for polar Hydrogen atoms with 1.05. Setting this to false uses the CCTBX value. :returns a ExtraAtomInfoMap with an entry for every atom in the model suitable for @@ -374,12 +366,6 @@ def getExtraAtomInfo(model, bondedNeighborLists, useNeutronDistances = False, pr warnings = "" - # Pull parameters from PHIL parameters, if they are present. Otherwise, set to - # defaults - useImplicitHydrogenDistances = False - if probePhil is not None: - useImplicitHydrogenDistances = probePhil.implicit_hydrogens - # Traverse the hierarchy and look up the extra data to be filled in. extras = probeExt.ExtraAtomInfoMap([],[]) mon_lib_srv = model.get_mon_lib_srv() @@ -413,10 +399,10 @@ def getExtraAtomInfo(model, bondedNeighborLists, useNeutronDistances = False, pr extra.vdwRadius = model.get_specific_ion_radius(a.i_seq) warnings += ("Using ionic radius for "+a.name.strip()+": "+str(extra.vdwRadius)+ " (rather than "+ - str(model.get_specific_vdw_radius(a.i_seq, useImplicitHydrogenDistances))+ + str(model.get_specific_vdw_radius(a.i_seq, False))+ ")\n") else: - extra.vdwRadius = model.get_specific_vdw_radius(a.i_seq, useImplicitHydrogenDistances) + extra.vdwRadius = model.get_specific_vdw_radius(a.i_seq, False) # Mark aromatic ring N and C atoms as acceptors as a hack to enable the # ring itself to behave as an acceptor. @@ -454,10 +440,7 @@ def getExtraAtomInfo(model, bondedNeighborLists, useNeutronDistances = False, pr if (a.name.strip().upper() == 'C' or AtomTypes.IsSpecialAminoAcidCarbonyl(a.parent().resname.strip().upper(), a.name.upper()) ): - if useImplicitHydrogenDistances: - expected = 1.80 - else: - expected = 1.65 + expected = 1.65 if extra.vdwRadius != expected: warnings += ("Overriding radius for "+a.name.strip()+": "+str(expected)+ " (was "+str(extra.vdwRadius)+")\n") @@ -503,13 +486,13 @@ def writeAtomInfoToString(atoms, extraAtomInfo): ################################################################################# # Dump information about all of the atoms in the model into a string. ret = "" + acceptorChoices = ["noAcceptor","isAcceptor"] + donorChoices = ["noDonor","isDonor"] + metallicChoices = ["noMetallic","isMetallic"] for a in atoms: chainID = a.parent().parent().parent().id resName = a.parent().resname.upper() resID = str(a.parent().parent().resseq_as_int()) - acceptorChoices = ["noAcceptor","isAcceptor"] - donorChoices = ["noDonor","isDonor"] - metallicChoices = ["noMetallic","isMetallic"] alt = a.parent().altloc if alt == " " or alt == "": alt = "-" @@ -911,8 +894,7 @@ def Test(inFileName = None): ) class philLike: - def __init__(self, useImplicitHydrogenDistances = False): - self.implicit_hydrogens = useImplicitHydrogenDistances + def __init__(self): self.set_polar_hydrogen_radius = True #======================================================================== @@ -920,7 +902,7 @@ def __init__(self, useImplicitHydrogenDistances = False): # for which we know the answer and then we verify that the results are what # we expect. - # Spot check the values on the atoms for standard, neutron distances, implicit hydrogen distances, + # Spot check the values on the atoms for standard, neutron distances, # and original Probe results. standardChecks = [ # Name, vdwRadius, isAcceptor, isDonor, isIon @@ -942,30 +924,18 @@ def __init__(self, useImplicitHydrogenDistances = False): ["O", 1.4, True, False, False], ["CD2", 1.75, False, False, False] ] - implicitChecks = [ - # Name, vdwRadius, isAcceptor, isDonor, isIon - ["CU", 0.72, False, False, True], - ["N", 1.6, False, True, False], - ["ND1", 1.6, False, True, False], - ["C", 1.8, False, False, False], - ["CB", 1.92, False, False, False], - ["O", 1.52, True, False, False], - ["CD2", 1.74, False, False, False] - ] # Situations to run the test in and expected results: cases = [ - # Use neutron distances, use implicit distances, expected results - [False, False, standardChecks], - [True, False, neutronChecks], - [False, True, implicitChecks] + # Use neutron distances, expected results + [False, standardChecks], + [True, neutronChecks] ] for cs in cases: useNeutronDistances = cs[0] - useImplicitHydrogenDistances = cs[1] - checks = cs[2] - runType = "; neutron,implicit = "+str(useNeutronDistances)+","+str(useImplicitHydrogenDistances) + checks = cs[1] + runType = "; neutron = "+str(useNeutronDistances) dm = iotbx.data_manager.DataManager(['model']) dm.process_model_str("1xso_snip.pdb",pdb_1xso_his_61) @@ -991,7 +961,7 @@ def __init__(self, useImplicitHydrogenDistances = False): # Get the extra atom information for the model using default parameters. # Make a PHIL-like structure to hold the parameters. extras = getExtraAtomInfo(model,bondedNeighborLists, - useNeutronDistances=useNeutronDistances,probePhil=philLike(useImplicitHydrogenDistances)).extraAtomInfo + useNeutronDistances=useNeutronDistances,probePhil=philLike()).extraAtomInfo # Get the atoms for the first model in the hierarchy. atoms = model.get_hierarchy().models()[0].atoms() @@ -1219,7 +1189,7 @@ def __init__(self, useImplicitHydrogenDistances = False): # When clamped, we can't go further than the non-Hydrogen bound except for Hydrogens nestedNeighborsForN4 = [ None, 3, 5, 8, 9, 9, 9] extraInfo = getExtraAtomInfo(model, bondedNeighborLists, - useNeutronDistances=False,probePhil=philLike(False)).extraAtomInfo + useNeutronDistances=False,probePhil=philLike()).extraAtomInfo hugeRadius = 1000 for N in range(1,7): count = len(getAtomsWithinNBonds(N4, bondedNeighborLists, extraInfo, hugeRadius, N, 3)) @@ -1284,7 +1254,7 @@ def __init__(self, useImplicitHydrogenDistances = False): p.pdb_interpretation.use_neutron_distances = False model.process(make_restraints=True, pdb_interpretation_params = p) # make restraints - ret = getExtraAtomInfo(model, bondedNeighborLists, False, philLike(False)) + ret = getExtraAtomInfo(model, bondedNeighborLists, False, philLike()) #======================================================================== # Run unit tests on the dihedralChoicesForRotatableHydrogens class. Both diff --git a/mmtbx/programs/probe2.py b/mmtbx/programs/probe2.py index 2b968662cc..d4730382f8 100644 --- a/mmtbx/programs/probe2.py +++ b/mmtbx/programs/probe2.py @@ -29,7 +29,7 @@ # @todo See if we can remove the shift and box once reduce_hydrogen is complete from cctbx.maptbx.box import shift_and_box_model -version = "2.5.0" +version = "4.0.0" master_phil_str = ''' profile = False @@ -37,7 +37,7 @@ .short_caption = Profile the run .help = Profile the performance of the entire run -source_selection = "(altid a or altid '' or altid ' ') and occupancy > 0.33" +source_selection = "occupancy > 0.33" .type = atom_selection .short_caption = Source selection .help = Source selection description @@ -243,6 +243,11 @@ .type = bool .short_caption = Compute scores rather than counting .help = Compute scores rather than just counting dots (-spike, -nospike in probe) + + altid_as_pointmaster = True + .type = bool + .short_caption = Add alternate IDs as point masters for atoms that are in alternate conformations + .help = Add alternate IDs as point masters for atoms that are in alternate conformations } ''' + Helpers.probe_phil_parameters @@ -568,10 +573,12 @@ class Program(ProgramTemplate): producing summaries or lists of all contacts, in Kinemage or raw format, depending on the Phil parameters. -By default, it compares all atoms in the A alternate that meet an occupancy +By default, it compares all atoms in all alternates that meet an occupancy criterion against themselves and produces a Kinemage-format file showing all of the dot interactions. See below for the Phil parameter equivalents to some -original probe command-line arguments. +original probe command-line arguments. (Note that the original probe selected +only the a alternate by default, but version 4 of probe2 selects all alternates by default +because it also adds point masters for all alternates.) Inputs: PDB or mmCIF file containing atomic model @@ -611,6 +618,9 @@ class Program(ProgramTemplate): The most simple dotkin: mmtbx.probe2 approach=self source_selection="all" output.file_name=out.kin input.pdb + The probe2 command line to test a ligand named TMP against everything else: + mmtbx.probe2 approach=both source_selection="resname TMP" target_selection="not resname TMP" PDBfilename + Equivalent PHIL arguments for original Probe command-line options: -defaults: source_selection="(altid a or altid '' or altid ' ') and occupancy > 0.33" @@ -1176,7 +1186,7 @@ def _writeRawOutput(self, groupName, masterName): def _writeOutput(self, groupName, masterName): ''' - Describe summary counts for data of various kinds. + Describe contacts for data of various kinds. :param groupName: Name to give to the group. :param masterName: Name for the master command. :return: String to be added to the output. @@ -1334,6 +1344,21 @@ def _writeOutput(self, groupName, masterName): ptmast = ptmast[:3]+gapNames[-1]+ptmast[4:] gapcounts[-1] += 1 + # Add alternate conformation masters to the pointmaster unless we've been told not to + if self.params.output.altid_as_pointmaster: + alt = '' + if (not a.parent().altloc in [' ', '']): + alt = a.parent().altloc + if (not t is None) and (not t.parent().altloc in [' ', '']): + alt += t.parent().altloc + if alt != '': + # Find the index of the second single quote in the ptmaster string + + idx = ptmast.rfind("'") + # Insert the alternate conformation into the ptmaster string at this index, + # using the lower-case version of the alternate conformation character. + ptmast = ptmast[:idx] + alt.lower() + ptmast[idx:] + if interactionType in [probeExt.InteractionType.SmallOverlap, probeExt.InteractionType.Bump, probeExt.InteractionType.BadBump]: ret += 'P {}{:.3f},{:.3f},{:.3f} {{"}}{} {}{:.3f},{:.3f},{:.3f}\n'.format( @@ -1894,6 +1919,7 @@ def run(self): ################################################################################ # Get the other characteristics we need to know about each atom to do our work. + make_sub_header('Getting extra atom characteristics', out=self.logger) self._inWater = {} self._inHet = {} self._inMainChain = {} @@ -1918,7 +1944,7 @@ def run(self): ################################################################################ # Ensure that the model we've been passed has at least one Hydrogen bonded to a Carbon # and at least one polar Hydrogen (bonded to N, O, or S). Otherwise, raise a Sorry. - if not (self.params.ignore_lack_of_explicit_hydrogens or self.params.probe.implicit_hydrogens): + if not self.params.ignore_lack_of_explicit_hydrogens: foundCBonded = False foundPolar = False for a in allAtoms: @@ -1943,6 +1969,7 @@ def run(self): # lists of atoms that are in each selection, a subset of the atoms in the model. # If there is no model_id in the selection criteria, these may include atoms from # multiple models in the hierarchy. + make_sub_header('Getting atom selections', out=self.logger) source_sel = self.model.selection(self.params.source_selection) allSourceAtoms = set() for a in allAtoms: @@ -1967,6 +1994,7 @@ def run(self): # We get lists of all atoms present in each hierarchy model that we're running. # This is a list of one when only one is selected and it is all of the available ones # when no particular one is selected. + make_sub_header('Getting atom lists', out=self.logger) atomLists = [ self.model.get_atoms() ] if (self.params.approach == 'self' and (self.params.source_selection is None or 'model' not in self.params.source_selection) and @@ -1977,19 +2005,25 @@ def run(self): for i in range(numModels): atomLists.append( self.model.get_hierarchy().models()[i].atoms() ) + make_sub_header('Processing atom lists', out=self.logger) for modelIndex, atoms in enumerate(atomLists): ################################################################################ # Get the subset of the source selection and target selection for this hierarchy # model. + + # Make an acceleration structure for determining whether an atom is in the ones we + # are considering in the current list. This is a set rather than a list to make it + # rapid to determine membership. + atomsInThisModel = set(atoms) source_atoms = set() for a in allSourceAtoms: - if a in atoms: + if a in atomsInThisModel: source_atoms.add(a) target_atoms = set() for a in allTargetAtoms: - if a in atoms: + if a in atomsInThisModel: target_atoms.add(a) ########################### @@ -2016,7 +2050,9 @@ def atomID(a): # Sort the atoms by an ID that is consistent from run to run so that they end up # in our data structures in the same order for each run. + make_sub_header('Sorting atoms', out=self.logger) all_selected_atoms = sorted(source_atoms.union(target_atoms), key=lambda x:atomID(x)) + make_sub_header('Getting bonded-neighbor lists', out=self.logger) bondedNeighborLists = Helpers.getBondedNeighborLists(all_selected_atoms, bondProxies) ################################################################################ @@ -2035,129 +2071,128 @@ def atomID(a): selectedAtomsIncludingKept = all_selected_atoms ################################################################################ - # If we're not doing implicit hydrogens, add Phantom hydrogens to waters and mark + # Add Phantom hydrogens to waters and mark # the water oxygens as not being donors in atoms that are in the source or target selection. # Also clear the donor status of all N, O, S atoms because we have explicit hydrogen donors. self._phantomHydrogenOutput = "" phantomHydrogens = [] - if not self.params.probe.implicit_hydrogens: - make_sub_header('Adjusting for explicit hydrogens', out=self.logger) - if self.params.output.record_added_hydrogens: - self._phantomHydrogenOutput += "@master {water H?}\n" - self._phantomHydrogenOutput += '@vectorlist {water H?} color= gray master={water H?}\n' - - # @todo Look up the radius of a water Hydrogen. This may require constructing a model with - # a single water in it and asking about the hydrogen radius. This could also become a - # Phil parameter. Also look up the OH bond distance rather than hard-coding it here. - phantomHydrogenRadius = 1.05 - placedHydrogenDistance = 0.84 - if self.params.use_neutron_distances: - phantomHydrogenRadius = 1.0 - placedHydrogenDistance = 0.98 - - adjustedHydrogenRadius = self.params.atom_radius_offset + (phantomHydrogenRadius * self.params.atom_radius_scale) - - # Check all selected atoms to see if we need to add Phantom Hydrogens to them. - # Don't add Phantom Hydrogens to atoms that are not selected, even if they are kept. - maxISeq = Helpers.getMaxISeq(self.model) - for a in all_selected_atoms: - - # Ignore Hydrogens whose parameters are out of bounds. - if a.element_is_hydrogen(): - # In the original code, this looks at H atoms with parent N,O,S atoms - # and marks them as donors. This is handled for us below in the call - # to Helpers.fixupExplicitDonors(). - - # If we are in a water, make sure our occupancy and temperature (b) factor are acceptable. - # If they are not, set the class for the atom to 'ignore'. - # This handles the case where there were explicit Hydrogens on waters and so - # we won't add Phantom Hydrogens. - if self._inWater[a] and (a.occ < self.params.minimum_water_hydrogen_occupancy or - a.b > self.params.maximum_water_hydrogen_b): - self._atomClasses[a] = 'ignore' - - # If we are the Oxygen in a water, then add phantom hydrogens pointing towards nearby acceptors - elif self._inWater[a] and a.element == 'O': - # We're an acceptor and not a donor. - # @todo Original Probe code only cleared the donor status if it found a bonded - # Hydrogen in the same conformation whose occupancy was > 0.1. Here, we're turning - # it off regardless of the occupancy. - ei = self._extraAtomInfo.getMappingFor(a) - ei.isDonor = False - ei.isAcceptor = True - self._extraAtomInfo.setMappingFor(a, ei) - - # If we don't yet have Hydrogens attached, add phantom hydrogen(s) - if len(bondedNeighborLists[a]) == 0: - # NOTE: The Phantoms have i_seq numbers that are sequential and that are higher than - # all other atoms in the model. Each one has a unique i_seq. - newPhantoms = Helpers.getPhantomHydrogensFor(maxISeq, a, self._spatialQuery, self._extraAtomInfo, - 0.0, True, adjustedHydrogenRadius, placedHydrogenDistance) - maxISeq += len(newPhantoms) - for p in newPhantoms: - - # Put in our list of Phantom Hydrogens - phantomHydrogens.append(p) - - # Add the atom to the general spatial-query data structure - self._spatialQuery.add(p) - - # Set the extra atom information for this atom - ei = probeExt.ExtraAtomInfo(adjustedHydrogenRadius, False, True, True) - self._extraAtomInfo.setMappingFor(p, ei) - - # Set the atomClass and other data based on the parent Oxygen. - self._atomClasses[p] = self._atom_class_for(a) - self._inWater[p] = self._inWater[a] - self._inMainChain[p] = self._inMainChain[a] - self._inSideChain[p] = self._inSideChain[a] - self._inHet[p] = self._inHet[a] - - # Mark the Phantom Hydrogens as being bonded to their Oxygen so that - # dots on a Phantom Hydrogen within its Oxygen will be excluded. - bondedNeighborLists[p] = [a] - - # It was thought that in the future, we may add these bonds, but that will cause the - # Phantom Hydrogens to mask their water Oxygens from close contacts or - # clashes with the acceptors, which is a change in behavior from the - # original Probe and would have the undesirable effect of a potential - # Hydrogen hiding a true collision. - # Not marking these as bonded requires special-case handling - # of Phantom Hydrogen interactions in the dot-scoring code. - # This means that we have a one-way bond, which is unusual but suits our - # purposes. - # Not done: bondedNeighborLists[a].append(p) - - # Add the new atom to any selections that the old atom was in. - if a in source_atoms: - source_atoms.add(p) - if a in target_atoms: - target_atoms.add(p) - - # Report on the creation if we've been asked to - if self.params.output.record_added_hydrogens: - - resName = a.parent().resname.strip().upper() - resID = str(a.parent().parent().resseq_as_int()) - chainID = a.parent().parent().parent().id - iCode = a.parent().parent().icode - alt = a.parent().altloc - self._phantomHydrogenOutput += '{{{:4.4s}{:1s}{:>3s}{:>2s}{:>4s}{:1s}}}P {:8.3f}{:8.3f}{:8.3f}\n'.format( - a.name, alt, resName, chainID, resID, iCode, - a.xyz[0], a.xyz[1], a.xyz[2]) - - resName = p.parent().resname.strip().upper() - resID = str(p.parent().parent().resseq_as_int()) - chainID = p.parent().parent().parent().id - iCode = p.parent().parent().icode - alt = p.parent().altloc - self._phantomHydrogenOutput += '{{{:4.4s}{:1s}{:>3s}{:>2s}{:>4s}{:1s}}}L {:8.3f}{:8.3f}{:8.3f}\n'.format( - p.name, alt, resName, chainID, resID, iCode, - p.xyz[0], p.xyz[1], p.xyz[2]) - - # Fix up the donor status for all of the atoms now that we've added the final explicit - # Phantom Hydrogens. - Helpers.fixupExplicitDonors(selectedAtomsIncludingKept, bondedNeighborLists, self._extraAtomInfo) + make_sub_header('Adjusting for explicit hydrogens', out=self.logger) + if self.params.output.record_added_hydrogens: + self._phantomHydrogenOutput += "@master {water H?}\n" + self._phantomHydrogenOutput += '@vectorlist {water H?} color= gray master={water H?}\n' + + # @todo Look up the radius of a water Hydrogen. This may require constructing a model with + # a single water in it and asking about the hydrogen radius. This could also become a + # Phil parameter. Also look up the OH bond distance rather than hard-coding it here. + phantomHydrogenRadius = 1.05 + placedHydrogenDistance = 0.84 + if self.params.use_neutron_distances: + phantomHydrogenRadius = 1.0 + placedHydrogenDistance = 0.98 + + adjustedHydrogenRadius = self.params.atom_radius_offset + (phantomHydrogenRadius * self.params.atom_radius_scale) + + # Check all selected atoms to see if we need to add Phantom Hydrogens to them. + # Don't add Phantom Hydrogens to atoms that are not selected, even if they are kept. + maxISeq = Helpers.getMaxISeq(self.model) + for a in all_selected_atoms: + + # Ignore Hydrogens whose parameters are out of bounds. + if a.element_is_hydrogen(): + # In the original code, this looks at H atoms with parent N,O,S atoms + # and marks them as donors. This is handled for us below in the call + # to Helpers.fixupExplicitDonors(). + + # If we are in a water, make sure our occupancy and temperature (b) factor are acceptable. + # If they are not, set the class for the atom to 'ignore'. + # This handles the case where there were explicit Hydrogens on waters and so + # we won't add Phantom Hydrogens. + if self._inWater[a] and (a.occ < self.params.minimum_water_hydrogen_occupancy or + a.b > self.params.maximum_water_hydrogen_b): + self._atomClasses[a] = 'ignore' + + # If we are the Oxygen in a water, then add phantom hydrogens pointing towards nearby acceptors + elif self._inWater[a] and a.element == 'O': + # We're an acceptor and not a donor. + # @todo Original Probe code only cleared the donor status if it found a bonded + # Hydrogen in the same conformation whose occupancy was > 0.1. Here, we're turning + # it off regardless of the occupancy. + ei = self._extraAtomInfo.getMappingFor(a) + ei.isDonor = False + ei.isAcceptor = True + self._extraAtomInfo.setMappingFor(a, ei) + + # If we don't yet have Hydrogens attached, add phantom hydrogen(s) + if len(bondedNeighborLists[a]) == 0: + # NOTE: The Phantoms have i_seq numbers that are sequential and that are higher than + # all other atoms in the model. Each one has a unique i_seq. + newPhantoms = Helpers.getPhantomHydrogensFor(maxISeq, a, self._spatialQuery, self._extraAtomInfo, + 0.0, True, adjustedHydrogenRadius, placedHydrogenDistance) + maxISeq += len(newPhantoms) + for p in newPhantoms: + + # Put in our list of Phantom Hydrogens + phantomHydrogens.append(p) + + # Add the atom to the general spatial-query data structure + self._spatialQuery.add(p) + + # Set the extra atom information for this atom + ei = probeExt.ExtraAtomInfo(adjustedHydrogenRadius, False, True, True) + self._extraAtomInfo.setMappingFor(p, ei) + + # Set the atomClass and other data based on the parent Oxygen. + self._atomClasses[p] = self._atom_class_for(a) + self._inWater[p] = self._inWater[a] + self._inMainChain[p] = self._inMainChain[a] + self._inSideChain[p] = self._inSideChain[a] + self._inHet[p] = self._inHet[a] + + # Mark the Phantom Hydrogens as being bonded to their Oxygen so that + # dots on a Phantom Hydrogen within its Oxygen will be excluded. + bondedNeighborLists[p] = [a] + + # It was thought that in the future, we may add these bonds, but that will cause the + # Phantom Hydrogens to mask their water Oxygens from close contacts or + # clashes with the acceptors, which is a change in behavior from the + # original Probe and would have the undesirable effect of a potential + # Hydrogen hiding a true collision. + # Not marking these as bonded requires special-case handling + # of Phantom Hydrogen interactions in the dot-scoring code. + # This means that we have a one-way bond, which is unusual but suits our + # purposes. + # Not done: bondedNeighborLists[a].append(p) + + # Add the new atom to any selections that the old atom was in. + if a in source_atoms: + source_atoms.add(p) + if a in target_atoms: + target_atoms.add(p) + + # Report on the creation if we've been asked to + if self.params.output.record_added_hydrogens: + + resName = a.parent().resname.strip().upper() + resID = str(a.parent().parent().resseq_as_int()) + chainID = a.parent().parent().parent().id + iCode = a.parent().parent().icode + alt = a.parent().altloc + self._phantomHydrogenOutput += '{{{:4.4s}{:1s}{:>3s}{:>2s}{:>4s}{:1s}}}P {:8.3f}{:8.3f}{:8.3f}\n'.format( + a.name, alt, resName, chainID, resID, iCode, + a.xyz[0], a.xyz[1], a.xyz[2]) + + resName = p.parent().resname.strip().upper() + resID = str(p.parent().parent().resseq_as_int()) + chainID = p.parent().parent().parent().id + iCode = p.parent().parent().icode + alt = p.parent().altloc + self._phantomHydrogenOutput += '{{{:4.4s}{:1s}{:>3s}{:>2s}{:>4s}{:1s}}}L {:8.3f}{:8.3f}{:8.3f}\n'.format( + p.name, alt, resName, chainID, resID, iCode, + p.xyz[0], p.xyz[1], p.xyz[2]) + + # Fix up the donor status for all of the atoms now that we've added the final explicit + # Phantom Hydrogens. + Helpers.fixupExplicitDonors(selectedAtomsIncludingKept, bondedNeighborLists, self._extraAtomInfo) ################################################################################ # Add ionic bonds to the bonded-neighbor list so that we won't count interactions diff --git a/mmtbx/programs/reduce2.py b/mmtbx/programs/reduce2.py index 4f81f8628d..12e53dec99 100644 --- a/mmtbx/programs/reduce2.py +++ b/mmtbx/programs/reduce2.py @@ -36,7 +36,7 @@ from iotbx.data_manager import DataManager import csv -version = "2.1.0" +version = "2.2.0" master_phil_str = ''' approach = *add remove @@ -1166,7 +1166,8 @@ def validate(self): if self.params.output.description_file_name is None: self.params.output.description_file_name=self.params.output.filename.replace('.pdb', '.txt') - # raise Sorry("Must specify output.description_file_name") + self.params.output.description_file_name=self.params.output.description_file_name.replace('.cif', + '.txt') # Check the model ID to make sure they didn't set it to 0 if self.params.model_id == 0: @@ -1224,7 +1225,8 @@ def run(self): flipStates = self.params.set_flip_states, verbosity=self.params.verbosity, cliqueOutlineFileName=self.params.output.clique_outline_file_name, - keepExistingH = self.params.keep_existing_H) + keepExistingH = self.params.keep_existing_H, + fillAtomDump = self.params.output.print_atom_info) doneOpt = time.time() outString += opt.getInfo() outString += 'Time to Add Hydrogen = {:.3f} sec'.format(doneAdd-startAdd)+'\n' diff --git a/mmtbx/reduce/Movers.py b/mmtbx/reduce/Movers.py index 92e3153b09..ac24a0b66b 100644 --- a/mmtbx/reduce/Movers.py +++ b/mmtbx/reduce/Movers.py @@ -22,7 +22,7 @@ import mmtbx_probe_ext as probe import traceback from mmtbx.probe.Helpers import rvec3, lvec3, dihedralChoicesForRotatableHydrogens -from mmtbx_reduce_ext import RotateAtomDegreesAroundAxisDir +from mmtbx_reduce_ext import RotateAtomDegreesAroundAxisDir, FindPosesFor ################################################################################## # This is a set of classes that implement Reduce's "Movers". These are sets of @@ -313,14 +313,7 @@ def _posesFor(self, angles): positions of all atoms when rotated about the axis by the associated angle. There is one entry in the list for each angle. """ - # @todo Turn this into a flex array of flex arrays rather than a list of flex arrays. - poses = [] - for agl in angles: - atoms = flex.vec3_double() - for atm in self._atoms: - atoms.append(RotateAtomDegreesAroundAxisDir(self._axis[0], self._axis[1], atm, agl)) - poses.append(atoms) - return poses; + return FindPosesFor(angles, self._atoms, self._axis[0], self._axis[1]) def _computeCoarsePositions(self): return PositionReturn(self._atoms, diff --git a/mmtbx/reduce/Optimizers.cpp b/mmtbx/reduce/Optimizers.cpp index 5540d270db..664f624db8 100644 --- a/mmtbx/reduce/Optimizers.cpp +++ b/mmtbx/reduce/Optimizers.cpp @@ -822,9 +822,11 @@ boost::python::tuple OptimizerC::OptimizeSingleMoverFine(boost::python::object c molprobity::reduce::PositionReturn coarse = boost::python::extract(mover.attr("CoarsePositions")()); - double initialScore = m_highScores[mover.ptr()]; - double maxScore = initialScore; + // Because other Movers in our clique may have been adjusted since we did coarse optimization, + // we need to recompute the score at our current position. unsigned coarseLoc = m_coarseLocations[mover.ptr()]; + double initialScore = scorePosition(coarse, coarseLoc, 0); + double maxScore = initialScore; molprobity::reduce::PositionReturn fine = boost::python::extract(mover.attr("FinePositions")(coarseLoc)); if (fine.positions.size() > 0) { diff --git a/mmtbx/reduce/Optimizers.py b/mmtbx/reduce/Optimizers.py index b46408b775..cafa8d9d35 100644 --- a/mmtbx/reduce/Optimizers.py +++ b/mmtbx/reduce/Optimizers.py @@ -163,7 +163,8 @@ def __init__(self, probePhil, addFlipMovers, model, modelIndex = 0, altID = None flipStates = '', verbosity = 1, cliqueOutlineFileName = None, - keepExistingH = False + keepExistingH = False, + fillAtomDump = True ): """Constructor. This is the wrapper class for the C++ OptimizerC and it implements the machinery that finds and optimizes Movers. @@ -222,6 +223,8 @@ def __init__(self, probePhil, addFlipMovers, model, modelIndex = 0, altID = None for each clique, as another master. These are useful for determining why the cliques are as they are. :param keepExistingH: If True, then existing Hydrogens will be kept and not removed. + :param fillAtomDump: If true, fill in the atomDump string with the atom information. + This can take a long time to do, so the caller may want to turn it off if they don't need it. """ ################################################################################ @@ -547,7 +550,7 @@ def __init__(self, probePhil, addFlipMovers, model, modelIndex = 0, altID = None # Fix up the donor status for all of the atoms now that we've added the final explicit # Phantom Hydrogens. Helpers.fixupExplicitDonors(self._atoms, bondedNeighborLists, self._extraAtomInfo) - atomDump = Helpers.writeAtomInfoToString(self._atoms, self._extraAtomInfo) + self._infoString += _ReportTiming(self._verbosity, "fixup explicit doners") ################################################################################ # Construct dot-sphere cache. @@ -730,7 +733,9 @@ def _printPose(self, m): ################################################################################# # Dump information about all of the atoms in the model into a string. - self._atomDump = Helpers.writeAtomInfoToString(myModel.atoms(), self._extraAtomInfo) + if fillAtomDump: + self._atomDump = Helpers.writeAtomInfoToString(myModel.atoms(), self._extraAtomInfo) + self._infoString += _ReportTiming(self._verbosity, "dump atom info to string") ################################################################################# # Report the fraction of atoms that were calculated and the fraction that were cached. @@ -746,6 +751,8 @@ def getInfo(self): detail on this can be set by setting the verbosity parameter during Optimizer construction. :return: the information so far collected in the string. Calling this method also clears the information, so that later calls will not repeat it. + If the object was constructed with fillAtomDump = False, then the atom dump will always be + empty. """ ret = self._infoString self._infoString = "" @@ -824,9 +831,9 @@ def _PlaceMovers(self, atoms, rotatableHydrogenIDs, bondedNeighborLists, hParame """Produce a list of Movers for atoms in a pdb.hierarchy.conformer that has added Hydrogens. :param atoms: flex array of atoms to search. This must have all Hydrogens needed by the Movers present in the structure already. - :param rotateableHydrogenIDs: List of sequence IDs that include those of single hydrogens - that are rotatable. It might include additional rotatable hydrogens (three bonded to the - same parent atom) or it might not. + :param rotatableHydrogenIDs: List of sequence IDs that include those of single hydrogens + that are rotatable. These are hydrogens that are the only one bound to their neighbor + and they are rotatable. :param bondedNeighborLists: A dictionary that contains an entry for each atom in the structure that the atom from the first parameter interacts with that lists all of the bonded atoms. Can be obtained by calling mmtbx.probe.Helpers.getBondedNeighborLists(). @@ -859,7 +866,7 @@ def _PlaceMovers(self, atoms, rotatableHydrogenIDs, bondedNeighborLists, hParame # construct the appropriate Mover. The construction may fail because not all required # atoms are present (especially the Hydrogens). If the construction succeeds, add the # Mover to the list of those to return. When they fail, add the output to the information - # string. + # string. We check single-hydrogen rotators later. for a in atoms: # Find the stripped upper-case atom and residue names and the residue ID, @@ -868,77 +875,6 @@ def _PlaceMovers(self, atoms, rotatableHydrogenIDs, bondedNeighborLists, hParame resName = a.parent().resname.strip().upper() resNameAndID = _ResNameAndID(a) - # See if we should construct a MoverSingleHydrogenRotator here. - # @todo This is placing on atoms C and N in CYS 352; and on HE2 and CA in SER 500 of 4z4d - if a.i_seq in rotatableHydrogenIDs: - try: - # Skip Hydrogens that are not bound to an atom that only has a single other - # atom bound to it -- we will handle those in other cases. - neighbor = bondedNeighborLists[a][0] - if len(bondedNeighborLists[neighbor]) == 2: - - # Get the list of atoms that are bonded in a chain to the hydrogen. They - # cannot be either hydrogen-bond acceptors nor touches/clashes with this atom. - bonded = Helpers.getAtomsWithinNBonds(a, bondedNeighborLists, self._extraAtomInfo, - self._probeRadius, self._bondedNeighborDepth, 3) - - # Construct a list of nearby atoms that are potential acceptors and potential touches. - # The potential acceptors are also potential touches. - potentialAcceptors = [] - potentialTouches = [] - - # Get the list of nearby atoms. The center of the search is the atom that - # the Hydrogen is bound to and its radius is 4 (these values are pulled from - # the Reduce C++ code). We skip ones whose radius is inside the neighbor so - # that we don't count the hydrogen itself. - maxDist = 4.0 - nearby = self._spatialQuery.neighbors(neighbor.xyz, - self._extraAtomInfo.getMappingFor(neighbor).vdwRadius, - maxDist) - - # Check each nearby atom to see if its distance from the neighbor is within - # the sum of the hydrogen-bond length of the neighbor atom, the radius of - # a polar Hydrogen, and the radius of the nearby atom, indicating potential - # overlap. - # O-H & N-H bond len == 1.0, S-H bond len == 1.3 - XHbondlen = 1.0 - if neighbor.element == "S": - XHbondlen = 1.3 - candidates = [] - for n in nearby: - # We don't count bonded atoms. - if not n in bonded: - # We treat them all as potential touches/clashes. - potentialTouches.append(n) - d = (Helpers.rvec3(neighbor.xyz) - Helpers.rvec3(n.xyz)).length() - if d <= XHbondlen + self._extraAtomInfo.getMappingFor(n).vdwRadius + polarHydrogenRadius: - candidates.append(n) - - # See if each candidate atom is a potential acceptor or a flip partner from - # Histidine or NH2 flips (which may be moved into that atom's position during a flip). - # We check the partner (N's for GLN And ASN, C's for HIS) because if it is the O or - # N atom, we will already be checking it as an acceptor now. - # In any case, it is a potential touch. - for c in candidates: - cName = c.name.strip().upper() - resName = c.parent().resname.strip().upper() - flipPartner = ( - (cName == 'ND2' and resName == 'ASN') or - (cName == 'NE2' and resName == 'GLN') or - (cName == 'CE1' and resName == 'HIS') or (cName == 'CD2' and resName == 'HIS') ) - acceptor = self._extraAtomInfo.getMappingFor(c).isAcceptor - if acceptor or flipPartner: - potentialAcceptors.append(c) - - self._movers.append(Movers.MoverSingleHydrogenRotator(a, bondedNeighborLists, self._extraAtomInfo, - hParameters, potentialAcceptors, - potentialTouches)) - self._infoString += _VerboseCheck(self._verbosity, 1,"Added MoverSingleHydrogenRotator "+str(len(self._movers))+" to "+resNameAndID+" "+aName+ - " with "+str(len(potentialAcceptors))+" potential nearby acceptors\n") - self._moverInfo[self._movers[-1]] = "SingleHydrogenRotator at "+resNameAndID+" "+aName; - except Exception as e: - self._infoString += _VerboseCheck(self._verbosity, 0,"Could not add MoverSingleHydrogenRotator to "+resNameAndID+" "+aName+": "+str(e)+"\n") - # See if we should construct a MoverNH3Rotator here. # Find any Nitrogen that has four total bonded neighbors, three of which are Hydrogens. # @todo Is this a valid way to search for them? @@ -1160,6 +1096,95 @@ def _modifyIfNeeded(nitro, coarseNitroPos, hydro): except Exception as e: self._infoString += _VerboseCheck(self._verbosity, 0,"Could not add MoverHisFlip to "+resNameAndID+": "+str(e)+"\n") + # Make a dictionary looked up up by i_seq that returns the relevant atom. We use this to + # look up the single-hydrogen rotators. We only place atoms that are in our current model + # index and alternate. + atomDict = {} + for a in atoms: + atomDict[a.i_seq] = a + + # Insert all single-hydrogen rotators, which we have a list of. Do this after we've + # done all of the other Movers so that any lock-down placements will have been done + # before we check. + for i in rotatableHydrogenIDs: + # Find out the associated atom + try: + a = atomDict[i] + except KeyError: + # This atom is not in our current model index or alternate, so skip it. + continue + + aName = a.name.strip().upper() + resName = a.parent().resname.strip().upper() + resNameAndID = _ResNameAndID(a) + try: + # Skip Hydrogens that are not bound to an atom that only has a single other + # atom bound to it -- we will handle those in other cases. + neighbor = bondedNeighborLists[a][0] + if len(bondedNeighborLists[neighbor]) == 2: + + # Get the list of atoms that are bonded in a chain to the hydrogen. They + # cannot be either hydrogen-bond acceptors nor touches/clashes with this atom. + bonded = Helpers.getAtomsWithinNBonds(a, bondedNeighborLists, self._extraAtomInfo, + self._probeRadius, self._bondedNeighborDepth, 3) + + # Construct a list of nearby atoms that are potential acceptors and potential touches. + # The potential acceptors are also potential touches. + potentialAcceptors = [] + potentialTouches = [] + + # Get the list of nearby atoms. The center of the search is the atom that + # the Hydrogen is bound to and its radius is 4 (these values are pulled from + # the Reduce C++ code). We skip ones whose radius is inside the neighbor so + # that we don't count the hydrogen itself. + maxDist = 4.0 + nearby = self._spatialQuery.neighbors(neighbor.xyz, + self._extraAtomInfo.getMappingFor(neighbor).vdwRadius, + maxDist) + + # Check each nearby atom to see if its distance from the neighbor is within + # the sum of the hydrogen-bond length of the neighbor atom, the radius of + # a polar Hydrogen, and the radius of the nearby atom, indicating potential + # overlap. + # O-H & N-H bond len == 1.0, S-H bond len == 1.3 + XHbondlen = 1.0 + if neighbor.element == "S": + XHbondlen = 1.3 + candidates = [] + for n in nearby: + # We don't count bonded atoms. + if not n in bonded: + # We treat them all as potential touches/clashes. + potentialTouches.append(n) + d = (Helpers.rvec3(neighbor.xyz) - Helpers.rvec3(n.xyz)).length() + if d <= XHbondlen + self._extraAtomInfo.getMappingFor(n).vdwRadius + polarHydrogenRadius: + candidates.append(n) + + # See if each candidate atom is a potential acceptor or a flip partner from + # Histidine or NH2 flips (which may be moved into that atom's position during a flip). + # We check the partner (N's for GLN And ASN, C's for HIS) because if it is the O or + # N atom, we will already be checking it as an acceptor now. + # In any case, it is a potential touch. + for c in candidates: + cName = c.name.strip().upper() + resName = c.parent().resname.strip().upper() + flipPartner = ( + (cName == 'ND2' and resName == 'ASN') or + (cName == 'NE2' and resName == 'GLN') or + (cName == 'CE1' and resName == 'HIS') or (cName == 'CD2' and resName == 'HIS') ) + acceptor = self._extraAtomInfo.getMappingFor(c).isAcceptor + if acceptor or flipPartner: + potentialAcceptors.append(c) + + self._movers.append(Movers.MoverSingleHydrogenRotator(a, bondedNeighborLists, self._extraAtomInfo, + hParameters, potentialAcceptors, + potentialTouches)) + self._infoString += _VerboseCheck(self._verbosity, 1,"Added MoverSingleHydrogenRotator "+str(len(self._movers))+" to "+resNameAndID+" "+aName+ + " with "+str(len(potentialAcceptors))+" potential nearby acceptors\n") + self._moverInfo[self._movers[-1]] = "SingleHydrogenRotator at "+resNameAndID+" "+aName; + except Exception as e: + self._infoString += _VerboseCheck(self._verbosity, 0,"Could not add MoverSingleHydrogenRotator to "+resNameAndID+" "+aName+": "+str(e)+"\n") + return deleteAtoms @@ -1316,7 +1341,7 @@ def _subsetGraph(g, keepLabels): # Class to pass default Probe parameters as if they were in a probePhil structure class _philLike: - def __init__(self, useImplicitHydrogenDistances = False): + def __init__(self): self.probe_radius = 0.25 self.density = 16.0 self.worse_clash_cutoff = 0.5 @@ -1328,7 +1353,6 @@ def __init__(self, useImplicitHydrogenDistances = False): self.hydrogen_bond_weight = 4.0 self.gap_weight = 0.25 self.allow_weak_hydrogen_bonds = False - self.implicit_hydrogens = useImplicitHydrogenDistances self.ignore_ion_interactions = False self.set_polar_hydrogen_radius = True self.excluded_bond_chain_length = 4 @@ -1360,7 +1384,7 @@ def _optimizeFragment(pdb_raw, bondedNeighborDepth = 4): model.process(make_restraints=True,pdb_interpretation_params=p) # make restraints # Optimization will place the movers. - probePhil = _philLike(False) + probePhil = _philLike() return Optimizer(probePhil, True, model, bondedNeighborDepth=bondedNeighborDepth) def Test(inFileName = None, dumpAtoms = False): @@ -1704,7 +1728,7 @@ def Test(inFileName = None, dumpAtoms = False): bondedNeighborLists = Helpers.getBondedNeighborLists(atoms, bondProxies) # Get the probeExt.ExtraAtomInfo needed to determine which atoms are potential acceptors. - probePhil = _philLike(False) + probePhil = _philLike() ret = Helpers.getExtraAtomInfo(model = model, bondedNeighborLists = bondedNeighborLists, useNeutronDistances=False, probePhil=probePhil) extra = ret.extraAtomInfo @@ -1727,7 +1751,7 @@ def Test(inFileName = None, dumpAtoms = False): # Optimization will place the movers, which should be none because the Histidine flip # will be constrained by the ionic bonds. There is a rotatable hydrogen placed at the # terminus, but no Flip Mover. - probePhil = _philLike(False) + probePhil = _philLike() opt = Optimizer(probePhil, True, model) movers = opt._movers if len(movers) != 1: @@ -1828,7 +1852,7 @@ def Test(inFileName = None, dumpAtoms = False): bondedNeighborLists = Helpers.getBondedNeighborLists(atoms, bondProxies) # Get the probeExt.ExtraAtomInfo needed to determine which atoms are potential acceptors. - probePhil = _philLike(False) + probePhil = _philLike() ret = Helpers.getExtraAtomInfo(model = model, bondedNeighborLists = bondedNeighborLists, useNeutronDistances=False,probePhil=probePhil) extra = ret.extraAtomInfo @@ -1842,7 +1866,7 @@ def Test(inFileName = None, dumpAtoms = False): # Make sure that the orientation for all of the movers is correct. # Test with each type of optimizer, from the base to the more derived, so # that we find out about failures on the base classes first. - probePhil = _philLike(False) + probePhil = _philLike() global _DoCliqueOptimizationInC @@ -1932,7 +1956,7 @@ def Test(inFileName = None, dumpAtoms = False): bondedNeighborLists = Helpers.getBondedNeighborLists(atoms, bondProxies) # Get the probeExt.ExtraAtomInfo needed to determine which atoms are potential acceptors. - probePhil = _philLike(False) + probePhil = _philLike() ret = Helpers.getExtraAtomInfo(model = model, bondedNeighborLists = bondedNeighborLists, useNeutronDistances=False,probePhil=probePhil) extra = ret.extraAtomInfo @@ -1944,7 +1968,7 @@ def Test(inFileName = None, dumpAtoms = False): # Optimization will place the movers. Make sure we got as many as we expected. # Make sure that the orientation for all of the movers is correct. - probePhil = _philLike(False) + probePhil = _philLike() opt = Optimizer(probePhil, True, model, modelIndex = 0, altID = None, bondedNeighborDepth = 4, useNeutronDistances = False, diff --git a/mmtbx/reduce/boost_python/reduce_bpl.cpp b/mmtbx/reduce/boost_python/reduce_bpl.cpp index 9fef27970a..4e32aabaa7 100644 --- a/mmtbx/reduce/boost_python/reduce_bpl.cpp +++ b/mmtbx/reduce/boost_python/reduce_bpl.cpp @@ -65,6 +65,30 @@ static scitbx::vec3 RotateAtomDegreesAroundAxisDir( ); } +scitbx::af::shared< scitbx::af::shared > FindPosesFor( + scitbx::af::shared const& angles, + scitbx::af::shared const& atoms, + scitbx::vec3 const& axis_point_1, + scitbx::vec3 const& axis_direction +) { + scitbx::af::shared< scitbx::af::shared > result; + for (size_t angle = 0; angle < angles.size(); angle++) { + scitbx::af::shared atomPoses; + for (size_t atom = 0; atom < atoms.size(); atom++) { + atomPoses.push_back(molprobity::probe::Point( + RotateAtomDegreesAroundAxisDir( + axis_point_1, + axis_direction, + atoms[atom], + angles[angle] + ) + )); + } + result.push_back(atomPoses); + } + return result; +} + BOOST_PYTHON_MODULE(mmtbx_reduce_ext) { // Dependencies @@ -188,4 +212,7 @@ BOOST_PYTHON_MODULE(mmtbx_reduce_ext) def("RotateAtomDegreesAroundAxisDir", RotateAtomDegreesAroundAxisDir, "Rotate an atom in place around an axis direction in degrees."); + + def("FindPosesFor", FindPosesFor, + "Find poses for atoms around an axis direction in degrees."); } diff --git a/mmtbx/regression/__init__.py b/mmtbx/regression/__init__.py index 5b97637649..e2ba5695dd 100644 --- a/mmtbx/regression/__init__.py +++ b/mmtbx/regression/__init__.py @@ -70,6 +70,640 @@ ATOM 59 OXT TYR A 7 11.358 2.999 7.612 1.00 17.49 O END """ +model_1yjp_cif = """\ +data_1YJP +# +_entry.id 1YJP +# +_audit.revision_id 1 +_audit.creation_date 2005-01-14 +_audit.update_record 'initial release' +# +_audit_conform.dict_name mmcif_pdbx.dic +_audit_conform.dict_version 5.286 +_audit_conform.dict_location http://mmcif.pdb.org/dictionaries/ascii/mmcif_pdbx.dic +# +loop_ +_database_2.database_id +_database_2.database_code +PDB 1YJP +RCSB RCSB031590 +WWPDB D_1000031590 +# +_pdbx_database_related.db_name PDB +_pdbx_database_related.db_id 1YJO +_pdbx_database_related.details . +_pdbx_database_related.content_type unspecified +# +_pdbx_database_status.entry_id 1YJP +_pdbx_database_status.deposit_site RCSB +_pdbx_database_status.process_site RCSB +_pdbx_database_status.recvd_initial_deposition_date 2005-01-15 +_pdbx_database_status.status_code REL +_pdbx_database_status.status_code_sf REL +_pdbx_database_status.status_code_mr ? +_pdbx_database_status.SG_entry ? +_pdbx_database_status.pdb_format_compatible Y +_pdbx_database_status.status_code_cs ? +_pdbx_database_status.methods_development_category ? +# +loop_ +_audit_author.name +_audit_author.pdbx_ordinal +'Nelson, R.' 1 +'Sawaya, M.R.' 2 +'Balbirnie, M.' 3 +'Madsen, A.O.' 4 +'Riekel, C.' 5 +'Grothe, R.' 6 +'Eisenberg, D.' 7 +# +loop_ +_citation.id +_citation.title +_citation.journal_abbrev +_citation.journal_volume +_citation.page_first +_citation.page_last +_citation.year +_citation.journal_id_ASTM +_citation.country +_citation.journal_id_ISSN +_citation.journal_id_CSD +_citation.book_publisher +_citation.pdbx_database_id_PubMed +_citation.pdbx_database_id_DOI +primary 'Structure of the cross-beta spine of amyloid-like fibrils.' Nature 435 773 778 2005 +NATUAS UK 0028-0836 0006 ? 15944695 10.1038/nature03680 +1 'Refinement of Macromolecular Structures by the Maximum-Likelihood Method' 'Acta Crystallogr.,Sect.D' 53 240 255 1997 +ABCRE6 DK 0907-4449 0766 ? ? ? +# +loop_ +_citation_author.citation_id +_citation_author.name +_citation_author.ordinal +primary 'Nelson, R.' 1 +primary 'Sawaya, M.R.' 2 +primary 'Balbirnie, M.' 3 +primary 'Madsen, A.O.' 4 +primary 'Riekel, C.' 5 +primary 'Grothe, R.' 6 +primary 'Eisenberg, D.' 7 +1 'Murshudov, G.N.' 8 +1 'Vagin, A.A.' 9 +1 'Dodson, E.J.' 10 +# +_cell.entry_id 1YJP +_cell.length_a 21.937 +_cell.length_b 4.866 +_cell.length_c 23.477 +_cell.angle_alpha 90.00 +_cell.angle_beta 107.08 +_cell.angle_gamma 90.00 +_cell.Z_PDB 2 +_cell.pdbx_unique_axis ? +# +_symmetry.entry_id 1YJP +_symmetry.space_group_name_H-M 'P 1 21 1' +_symmetry.pdbx_full_space_group_name_H-M ? +_symmetry.cell_setting ? +_symmetry.Int_Tables_number 4 +_symmetry.space_group_name_Hall ? +# +loop_ +_entity.id +_entity.type +_entity.src_method +_entity.pdbx_description +_entity.formula_weight +_entity.pdbx_number_of_molecules +_entity.pdbx_ec +_entity.pdbx_mutation +_entity.pdbx_fragment +_entity.details +1 polymer syn 'Eukaryotic peptide chain release factor GTP-binding subunit' 836.807 1 ? ? 'prion determining domain of Sup35' ? +2 water nat water 18.015 7 ? ? ? ? +# +_entity_name_com.entity_id 1 +_entity_name_com.name +'ERF2, Translation release factor 3, ERF3, ERF-3, Omnipotent suppressor protein 2, G1 to S phase transition protein 1' +# +_entity_poly.entity_id 1 +_entity_poly.type 'polypeptide(L)' +_entity_poly.nstd_linkage no +_entity_poly.nstd_monomer no +_entity_poly.pdbx_seq_one_letter_code GNNQQNY +_entity_poly.pdbx_seq_one_letter_code_can GNNQQNY +_entity_poly.pdbx_strand_id A +_entity_poly.pdbx_target_identifier ? +# +loop_ +_entity_poly_seq.entity_id +_entity_poly_seq.num +_entity_poly_seq.mon_id +_entity_poly_seq.hetero +1 1 GLY n +1 2 ASN n +1 3 ASN n +1 4 GLN n +1 5 GLN n +1 6 ASN n +1 7 TYR n +# +_pdbx_entity_src_syn.entity_id 1 +_pdbx_entity_src_syn.pdbx_src_id 1 +_pdbx_entity_src_syn.pdbx_alt_source_flag sample +_pdbx_entity_src_syn.pdbx_beg_seq_num ? +_pdbx_entity_src_syn.pdbx_end_seq_num ? +_pdbx_entity_src_syn.organism_scientific ? +_pdbx_entity_src_syn.organism_common_name ? +_pdbx_entity_src_syn.ncbi_taxonomy_id ? +_pdbx_entity_src_syn.details 'This sequence is from the prion determining domain of Saccharomyces cerevisiae Sup35' +# +_struct_ref.id 1 +_struct_ref.db_name UNP +_struct_ref.db_code ERF2_YEAST +_struct_ref.pdbx_db_accession P05453 +_struct_ref.entity_id 1 +_struct_ref.pdbx_seq_one_letter_code GNNQQNY +_struct_ref.pdbx_align_begin 7 +_struct_ref.pdbx_db_isoform ? +# +_struct_ref_seq.align_id 1 +_struct_ref_seq.ref_id 1 +_struct_ref_seq.pdbx_PDB_id_code 1YJP +_struct_ref_seq.pdbx_strand_id A +_struct_ref_seq.seq_align_beg 1 +_struct_ref_seq.pdbx_seq_align_beg_ins_code ? +_struct_ref_seq.seq_align_end 7 +_struct_ref_seq.pdbx_seq_align_end_ins_code ? +_struct_ref_seq.pdbx_db_accession P05453 +_struct_ref_seq.db_align_beg 7 +_struct_ref_seq.pdbx_db_align_beg_ins_code ? +_struct_ref_seq.db_align_end 13 +_struct_ref_seq.pdbx_db_align_end_ins_code ? +_struct_ref_seq.pdbx_auth_seq_align_beg 1 +_struct_ref_seq.pdbx_auth_seq_align_end 7 +# +loop_ +_chem_comp.id +_chem_comp.type +_chem_comp.mon_nstd_flag +_chem_comp.name +_chem_comp.pdbx_synonyms +_chem_comp.formula +_chem_comp.formula_weight +ASN 'L-peptide linking' y ASPARAGINE ? 'C4 H8 N2 O3' 132.118 +GLN 'L-peptide linking' y GLUTAMINE ? 'C5 H10 N2 O3' 146.144 +GLY 'peptide linking' y GLYCINE ? 'C2 H5 N O2' 75.067 +HOH non-polymer . WATER ? 'H2 O' 18.015 +TYR 'L-peptide linking' y TYROSINE ? 'C9 H11 N O3' 181.189 +# +_exptl.method 'X-RAY DIFFRACTION' +_exptl.entry_id 1YJP +_exptl.crystals_number 1 +# +_exptl_crystal.id 1 +_exptl_crystal.density_meas ? +_exptl_crystal.density_percent_sol 14.03 +_exptl_crystal.density_Matthews 1.43 +_exptl_crystal.description ? +_exptl_crystal.F_000 ? +_exptl_crystal.preparation ? +# +_exptl_crystal_grow.crystal_id 1 +_exptl_crystal_grow.method 'VAPOR DIFFUSION, HANGING DROP' +_exptl_crystal_grow.pH 7 +_exptl_crystal_grow.temp 298 +_exptl_crystal_grow.temp_details ? +_exptl_crystal_grow.pdbx_details 'water, pH 7, VAPOR DIFFUSION, HANGING DROP, temperature 298K' +_exptl_crystal_grow.pdbx_pH_range . +# +_diffrn.id 1 +_diffrn.ambient_temp 100 +_diffrn.ambient_temp_details ? +_diffrn.crystal_id 1 +# +_diffrn_detector.diffrn_id 1 +_diffrn_detector.detector CCD +_diffrn_detector.type MARRESEARCH +_diffrn_detector.pdbx_collection_date 2004-06-12 +_diffrn_detector.details 'Ellipsoidal Mirror' +# +_diffrn_radiation.diffrn_id 1 +_diffrn_radiation.wavelength_id 1 +_diffrn_radiation.pdbx_diffrn_protocol 'SINGLE WAVELENGTH' +_diffrn_radiation.monochromator 'channel-cut Si-111 monochromator' +_diffrn_radiation.pdbx_monochromatic_or_laue_m_l M +_diffrn_radiation.pdbx_scattering_type x-ray +# +_diffrn_radiation_wavelength.id 1 +_diffrn_radiation_wavelength.wavelength 0.975 +_diffrn_radiation_wavelength.wt 1.0 +# +_diffrn_source.diffrn_id 1 +_diffrn_source.source SYNCHROTRON +_diffrn_source.type 'ESRF BEAMLINE ID13' +_diffrn_source.pdbx_wavelength 0.975 +_diffrn_source.pdbx_wavelength_list 0.975 +_diffrn_source.pdbx_synchrotron_site ESRF +_diffrn_source.pdbx_synchrotron_beamline ID13 +# +_reflns.d_resolution_low 80.00 +_reflns.d_resolution_high 1.80 +_reflns.number_obs 509 +_reflns.percent_possible_obs 89.5 +_reflns.pdbx_Rmerge_I_obs 0.204 +_reflns.pdbx_chi_squared 1.057 +_reflns.entry_id 1YJP +_reflns.observed_criterion_sigma_F 0 +_reflns.observed_criterion_sigma_I 0 +_reflns.number_all 509 +_reflns.pdbx_Rsym_value ? +_reflns.pdbx_netI_over_sigmaI 3.75 +_reflns.B_iso_Wilson_estimate 45.6 +_reflns.pdbx_redundancy 2.0 +_reflns.R_free_details ? +_reflns.limit_h_max ? +_reflns.limit_h_min ? +_reflns.limit_k_max ? +_reflns.limit_k_min ? +_reflns.limit_l_max ? +_reflns.limit_l_min ? +_reflns.observed_criterion_F_max ? +_reflns.observed_criterion_F_min ? +_reflns.pdbx_scaling_rejects ? +_reflns.pdbx_diffrn_id 1 +_reflns.pdbx_ordinal 1 +# +_reflns_shell.d_res_low 1.94 +_reflns_shell.d_res_high 1.80 +_reflns_shell.number_unique_all 85 +_reflns_shell.percent_possible_all 84.2 +_reflns_shell.Rmerge_I_obs 0.491 +_reflns_shell.pdbx_redundancy ? +_reflns_shell.pdbx_chi_squared 1.092 +_reflns_shell.number_unique_obs ? +_reflns_shell.meanI_over_sigI_obs 1.5 +_reflns_shell.pdbx_Rsym_value ? +_reflns_shell.percent_possible_obs ? +_reflns_shell.number_measured_all ? +_reflns_shell.number_measured_obs ? +_reflns_shell.pdbx_diffrn_id ? +_reflns_shell.pdbx_ordinal 1 +# +_refine.entry_id 1YJP +_refine.ls_d_res_high 1.80 +_refine.ls_d_res_low 22.44 +_refine.pdbx_ls_sigma_F 0 +_refine.pdbx_ls_sigma_I 0 +_refine.ls_number_reflns_all 474 +_refine.ls_number_reflns_obs 474 +_refine.ls_number_reflns_R_free 20 +_refine.ls_percent_reflns_obs ? +_refine.ls_R_factor_all 0.18139 +_refine.ls_R_factor_obs 0.18139 +_refine.ls_R_factor_R_work 0.18086 +_refine.ls_R_factor_R_free 0.19014 +_refine.ls_redundancy_reflns_obs ? +_refine.pdbx_data_cutoff_high_absF ? +_refine.pdbx_data_cutoff_low_absF ? +_refine.ls_number_parameters ? +_refine.ls_number_restraints ? +_refine.ls_percent_reflns_R_free ? +_refine.ls_R_factor_R_free_error ? +_refine.ls_R_factor_R_free_error_details ? +_refine.pdbx_method_to_determine_struct 'FOURIER SYNTHESIS' +_refine.pdbx_starting_model ? +_refine.pdbx_ls_cross_valid_method THROUGHOUT +_refine.pdbx_R_Free_selection_details RANDOM +_refine.pdbx_stereochem_target_val_spec_case ? +_refine.pdbx_stereochemistry_target_values 'Engh & Huber' +_refine.solvent_model_details ? +_refine.solvent_model_param_bsol ? +_refine.solvent_model_param_ksol ? +_refine.occupancy_max ? +_refine.occupancy_min ? +_refine.pdbx_isotropic_thermal_model ? +_refine.B_iso_mean ? +_refine.aniso_B[1][1] ? +_refine.aniso_B[1][2] ? +_refine.aniso_B[1][3] ? +_refine.aniso_B[2][2] ? +_refine.aniso_B[2][3] ? +_refine.aniso_B[3][3] ? +_refine.details ? +_refine.B_iso_min ? +_refine.B_iso_max ? +_refine.correlation_coeff_Fo_to_Fc ? +_refine.correlation_coeff_Fo_to_Fc_free ? +_refine.pdbx_solvent_vdw_probe_radii ? +_refine.pdbx_solvent_ion_probe_radii ? +_refine.pdbx_solvent_shrinkage_radii ? +_refine.overall_SU_R_Cruickshank_DPI ? +_refine.overall_SU_R_free ? +_refine.overall_SU_B ? +_refine.overall_SU_ML ? +_refine.pdbx_overall_ESU_R ? +_refine.pdbx_overall_ESU_R_Free ? +_refine.pdbx_data_cutoff_high_rms_absF ? +_refine.ls_wR_factor_R_free ? +_refine.ls_wR_factor_R_work ? +_refine.overall_FOM_free_R_set ? +_refine.overall_FOM_work_R_set ? +_refine.pdbx_refine_id 'X-RAY DIFFRACTION' +_refine.pdbx_diffrn_id 1 +_refine.pdbx_TLS_residual_ADP_flag ? +_refine.pdbx_overall_phase_error ? +_refine.pdbx_overall_SU_R_free_Cruickshank_DPI ? +_refine.pdbx_overall_SU_R_Blow_DPI ? +_refine.pdbx_overall_SU_R_free_Blow_DPI ? +# +_refine_hist.pdbx_refine_id 'X-RAY DIFFRACTION' +_refine_hist.cycle_id LAST +_refine_hist.pdbx_number_atoms_protein 59 +_refine_hist.pdbx_number_atoms_nucleic_acid 0 +_refine_hist.pdbx_number_atoms_ligand 0 +_refine_hist.number_atoms_solvent 7 +_refine_hist.number_atoms_total 66 +_refine_hist.d_res_high 1.80 +_refine_hist.d_res_low 22.44 +# +loop_ +_refine_ls_restr.type +_refine_ls_restr.dev_ideal +_refine_ls_restr.dev_ideal_target +_refine_ls_restr.number +_refine_ls_restr.weight +_refine_ls_restr.pdbx_refine_id +_refine_ls_restr.pdbx_restraint_function +r_angle_refined_deg 1.228 ? ? ? 'X-RAY DIFFRACTION' ? +r_bond_refined_d 0.014 ? ? ? 'X-RAY DIFFRACTION' ? +# +_struct.entry_id 1YJP +_struct.title 'Structure of GNNQQNY from yeast prion Sup35' +_struct.pdbx_descriptor PROTEIN +_struct.pdbx_model_details ? +_struct.pdbx_CASP_flag ? +_struct.pdbx_model_type_details ? +# +_struct_keywords.entry_id 1YJP +_struct_keywords.pdbx_keywords 'PROTEIN BINDING' +_struct_keywords.text 'beta sheet, steric zipper, glutamine zipper, asparagine zipper, PROTEIN BINDING' +# +loop_ +_struct_asym.id +_struct_asym.pdbx_blank_PDB_chainid_flag +_struct_asym.pdbx_modified +_struct_asym.entity_id +_struct_asym.details +A N N 1 ? +B N N 2 ? +# +_atom_sites.entry_id 1YJP +_atom_sites.fract_transf_matrix[1][1] 0.045585 +_atom_sites.fract_transf_matrix[1][2] 0.000000 +_atom_sites.fract_transf_matrix[1][3] 0.014006 +_atom_sites.fract_transf_matrix[2][1] 0.000000 +_atom_sites.fract_transf_matrix[2][2] 0.205508 +_atom_sites.fract_transf_matrix[2][3] 0.000000 +_atom_sites.fract_transf_matrix[3][1] 0.000000 +_atom_sites.fract_transf_matrix[3][2] 0.000000 +_atom_sites.fract_transf_matrix[3][3] 0.044560 +_atom_sites.fract_transf_vector[1] 0.00000 +_atom_sites.fract_transf_vector[2] 0.00000 +_atom_sites.fract_transf_vector[3] 0.00000 +# +loop_ +_atom_type.symbol +C +N +O +# +loop_ +_atom_site.group_PDB +_atom_site.id +_atom_site.type_symbol +_atom_site.label_atom_id +_atom_site.label_alt_id +_atom_site.label_comp_id +_atom_site.label_asym_id +_atom_site.label_entity_id +_atom_site.label_seq_id +_atom_site.pdbx_PDB_ins_code +_atom_site.Cartn_x +_atom_site.Cartn_y +_atom_site.Cartn_z +_atom_site.occupancy +_atom_site.B_iso_or_equiv +_atom_site.pdbx_formal_charge +_atom_site.auth_seq_id +_atom_site.auth_comp_id +_atom_site.auth_asym_id +_atom_site.auth_atom_id +_atom_site.pdbx_PDB_model_num +ATOM 1 N N . GLY A 1 1 ? -9.009 4.612 6.102 1.00 16.77 ? 1 GLY A N 1 +ATOM 2 C CA . GLY A 1 1 ? -9.052 4.207 4.651 1.00 16.57 ? 1 GLY A CA 1 +ATOM 3 C C . GLY A 1 1 ? -8.015 3.140 4.419 1.00 16.16 ? 1 GLY A C 1 +ATOM 4 O O . GLY A 1 1 ? -7.523 2.521 5.381 1.00 16.78 ? 1 GLY A O 1 +ATOM 5 N N . ASN A 1 2 ? -7.656 2.923 3.155 1.00 15.02 ? 2 ASN A N 1 +ATOM 6 C CA . ASN A 1 2 ? -6.522 2.038 2.831 1.00 14.10 ? 2 ASN A CA 1 +ATOM 7 C C . ASN A 1 2 ? -5.241 2.537 3.427 1.00 13.13 ? 2 ASN A C 1 +ATOM 8 O O . ASN A 1 2 ? -4.978 3.742 3.426 1.00 11.91 ? 2 ASN A O 1 +ATOM 9 C CB . ASN A 1 2 ? -6.346 1.881 1.341 1.00 15.38 ? 2 ASN A CB 1 +ATOM 10 C CG . ASN A 1 2 ? -7.584 1.342 0.692 1.00 14.08 ? 2 ASN A CG 1 +ATOM 11 O OD1 . ASN A 1 2 ? -8.025 0.227 1.016 1.00 17.46 ? 2 ASN A OD1 1 +ATOM 12 N ND2 . ASN A 1 2 ? -8.204 2.155 -0.169 1.00 11.72 ? 2 ASN A ND2 1 +ATOM 13 N N . ASN A 1 3 ? -4.438 1.590 3.905 1.00 12.26 ? 3 ASN A N 1 +ATOM 14 C CA . ASN A 1 3 ? -3.193 1.904 4.589 1.00 11.74 ? 3 ASN A CA 1 +ATOM 15 C C . ASN A 1 3 ? -1.955 1.332 3.895 1.00 11.10 ? 3 ASN A C 1 +ATOM 16 O O . ASN A 1 3 ? -1.872 0.119 3.648 1.00 10.42 ? 3 ASN A O 1 +ATOM 17 C CB . ASN A 1 3 ? -3.259 1.378 6.042 1.00 12.15 ? 3 ASN A CB 1 +ATOM 18 C CG . ASN A 1 3 ? -2.006 1.739 6.861 1.00 12.82 ? 3 ASN A CG 1 +ATOM 19 O OD1 . ASN A 1 3 ? -1.702 2.925 7.072 1.00 15.05 ? 3 ASN A OD1 1 +ATOM 20 N ND2 . ASN A 1 3 ? -1.271 0.715 7.306 1.00 13.48 ? 3 ASN A ND2 1 +ATOM 21 N N . GLN A 1 4 ? -1.005 2.228 3.598 1.00 10.29 ? 4 GLN A N 1 +ATOM 22 C CA . GLN A 1 4 ? 0.384 1.888 3.199 1.00 10.53 ? 4 GLN A CA 1 +ATOM 23 C C . GLN A 1 4 ? 1.435 2.606 4.088 1.00 10.24 ? 4 GLN A C 1 +ATOM 24 O O . GLN A 1 4 ? 1.547 3.843 4.115 1.00 8.86 ? 4 GLN A O 1 +ATOM 25 C CB . GLN A 1 4 ? 0.656 2.148 1.711 1.00 9.80 ? 4 GLN A CB 1 +ATOM 26 C CG . GLN A 1 4 ? 1.944 1.458 1.213 1.00 10.25 ? 4 GLN A CG 1 +ATOM 27 C CD . GLN A 1 4 ? 2.504 2.044 -0.089 1.00 12.43 ? 4 GLN A CD 1 +ATOM 28 O OE1 . GLN A 1 4 ? 2.744 3.268 -0.190 1.00 14.62 ? 4 GLN A OE1 1 +ATOM 29 N NE2 . GLN A 1 4 ? 2.750 1.161 -1.091 1.00 9.05 ? 4 GLN A NE2 1 +ATOM 30 N N . GLN A 1 5 ? 2.154 1.821 4.871 1.00 10.38 ? 5 GLN A N 1 +ATOM 31 C CA . GLN A 1 5 ? 3.270 2.361 5.640 1.00 11.39 ? 5 GLN A CA 1 +ATOM 32 C C . GLN A 1 5 ? 4.594 1.768 5.172 1.00 11.52 ? 5 GLN A C 1 +ATOM 33 O O . GLN A 1 5 ? 4.768 0.546 5.054 1.00 12.05 ? 5 GLN A O 1 +ATOM 34 C CB . GLN A 1 5 ? 3.056 2.183 7.147 1.00 11.96 ? 5 GLN A CB 1 +ATOM 35 C CG . GLN A 1 5 ? 1.829 2.950 7.647 1.00 10.81 ? 5 GLN A CG 1 +ATOM 36 C CD . GLN A 1 5 ? 1.344 2.414 8.954 1.00 13.10 ? 5 GLN A CD 1 +ATOM 37 O OE1 . GLN A 1 5 ? 0.774 1.325 9.002 1.00 10.65 ? 5 GLN A OE1 1 +ATOM 38 N NE2 . GLN A 1 5 ? 1.549 3.187 10.039 1.00 12.30 ? 5 GLN A NE2 1 +ATOM 39 N N . ASN A 1 6 ? 5.514 2.664 4.856 1.00 11.99 ? 6 ASN A N 1 +ATOM 40 C CA . ASN A 1 6 ? 6.831 2.310 4.318 1.00 12.30 ? 6 ASN A CA 1 +ATOM 41 C C . ASN A 1 6 ? 7.854 2.761 5.324 1.00 13.40 ? 6 ASN A C 1 +ATOM 42 O O . ASN A 1 6 ? 8.219 3.943 5.374 1.00 13.92 ? 6 ASN A O 1 +ATOM 43 C CB . ASN A 1 6 ? 7.065 3.016 2.993 1.00 12.13 ? 6 ASN A CB 1 +ATOM 44 C CG . ASN A 1 6 ? 5.961 2.735 2.003 1.00 12.77 ? 6 ASN A CG 1 +ATOM 45 O OD1 . ASN A 1 6 ? 5.798 1.604 1.551 1.00 14.27 ? 6 ASN A OD1 1 +ATOM 46 N ND2 . ASN A 1 6 ? 5.195 3.747 1.679 1.00 10.07 ? 6 ASN A ND2 1 +ATOM 47 N N . TYR A 1 7 ? 8.292 1.817 6.147 1.00 14.70 ? 7 TYR A N 1 +ATOM 48 C CA . TYR A 1 7 ? 9.159 2.144 7.299 1.00 15.18 ? 7 TYR A CA 1 +ATOM 49 C C . TYR A 1 7 ? 10.603 2.331 6.885 1.00 15.91 ? 7 TYR A C 1 +ATOM 50 O O . TYR A 1 7 ? 11.041 1.811 5.855 1.00 15.76 ? 7 TYR A O 1 +ATOM 51 C CB . TYR A 1 7 ? 9.061 1.065 8.369 1.00 15.35 ? 7 TYR A CB 1 +ATOM 52 C CG . TYR A 1 7 ? 7.665 0.929 8.902 1.00 14.45 ? 7 TYR A CG 1 +ATOM 53 C CD1 . TYR A 1 7 ? 6.771 0.021 8.327 1.00 15.68 ? 7 TYR A CD1 1 +ATOM 54 C CD2 . TYR A 1 7 ? 7.210 1.756 9.920 1.00 14.80 ? 7 TYR A CD2 1 +ATOM 55 C CE1 . TYR A 1 7 ? 5.480 -0.094 8.796 1.00 13.46 ? 7 TYR A CE1 1 +ATOM 56 C CE2 . TYR A 1 7 ? 5.904 1.649 10.416 1.00 14.33 ? 7 TYR A CE2 1 +ATOM 57 C CZ . TYR A 1 7 ? 5.047 0.729 9.831 1.00 15.09 ? 7 TYR A CZ 1 +ATOM 58 O OH . TYR A 1 7 ? 3.766 0.589 10.291 1.00 14.39 ? 7 TYR A OH 1 +ATOM 59 O OXT . TYR A 1 7 ? 11.358 2.999 7.612 1.00 17.49 ? 7 TYR A OXT 1 +HETATM 60 O O . HOH B 2 . ? -6.471 5.227 7.124 1.00 22.62 ? 8 HOH A O 1 +HETATM 61 O O . HOH B 2 . ? 10.431 1.858 3.216 1.00 19.71 ? 9 HOH A O 1 +HETATM 62 O O . HOH B 2 . ? -11.286 1.756 -1.468 1.00 17.08 ? 10 HOH A O 1 +HETATM 63 O O . HOH B 2 . ? 11.808 4.179 9.970 1.00 23.99 ? 11 HOH A O 1 +HETATM 64 O O . HOH B 2 . ? 13.605 1.327 9.198 1.00 26.17 ? 12 HOH A O 1 +HETATM 65 O O . HOH B 2 . ? -2.749 3.429 10.024 1.00 39.15 ? 13 HOH A O 1 +HETATM 66 O O . HOH B 2 . ? -1.500 0.682 10.967 1.00 43.49 ? 14 HOH A O 1 +# +loop_ +_pdbx_poly_seq_scheme.asym_id +_pdbx_poly_seq_scheme.entity_id +_pdbx_poly_seq_scheme.seq_id +_pdbx_poly_seq_scheme.mon_id +_pdbx_poly_seq_scheme.ndb_seq_num +_pdbx_poly_seq_scheme.pdb_seq_num +_pdbx_poly_seq_scheme.auth_seq_num +_pdbx_poly_seq_scheme.pdb_mon_id +_pdbx_poly_seq_scheme.auth_mon_id +_pdbx_poly_seq_scheme.pdb_strand_id +_pdbx_poly_seq_scheme.pdb_ins_code +_pdbx_poly_seq_scheme.hetero +A 1 1 GLY 1 1 1 GLY GLY A . n +A 1 2 ASN 2 2 2 ASN ASN A . n +A 1 3 ASN 3 3 3 ASN ASN A . n +A 1 4 GLN 4 4 4 GLN GLN A . n +A 1 5 GLN 5 5 5 GLN GLN A . n +A 1 6 ASN 6 6 6 ASN ASN A . n +A 1 7 TYR 7 7 7 TYR TYR A . n +# +loop_ +_pdbx_nonpoly_scheme.asym_id +_pdbx_nonpoly_scheme.entity_id +_pdbx_nonpoly_scheme.mon_id +_pdbx_nonpoly_scheme.ndb_seq_num +_pdbx_nonpoly_scheme.pdb_seq_num +_pdbx_nonpoly_scheme.auth_seq_num +_pdbx_nonpoly_scheme.pdb_mon_id +_pdbx_nonpoly_scheme.auth_mon_id +_pdbx_nonpoly_scheme.pdb_strand_id +_pdbx_nonpoly_scheme.pdb_ins_code +B 2 HOH 1 8 8 HOH HOH A . +B 2 HOH 2 9 9 HOH HOH A . +B 2 HOH 3 10 10 HOH HOH A . +B 2 HOH 4 11 11 HOH HOH A . +B 2 HOH 5 12 12 HOH HOH A . +B 2 HOH 6 13 13 HOH HOH A . +B 2 HOH 7 14 14 HOH HOH A . +# +_pdbx_struct_assembly.id 1 +_pdbx_struct_assembly.details author_defined_assembly +_pdbx_struct_assembly.method_details ? +_pdbx_struct_assembly.oligomeric_details dimeric +_pdbx_struct_assembly.oligomeric_count 2 +# +_pdbx_struct_assembly_gen.assembly_id 1 +_pdbx_struct_assembly_gen.oper_expression 1,2 +_pdbx_struct_assembly_gen.asym_id_list A,B +# +loop_ +_pdbx_struct_oper_list.id +_pdbx_struct_oper_list.type +_pdbx_struct_oper_list.name +_pdbx_struct_oper_list.symmetry_operation +_pdbx_struct_oper_list.matrix[1][1] +_pdbx_struct_oper_list.matrix[1][2] +_pdbx_struct_oper_list.matrix[1][3] +_pdbx_struct_oper_list.vector[1] +_pdbx_struct_oper_list.matrix[2][1] +_pdbx_struct_oper_list.matrix[2][2] +_pdbx_struct_oper_list.matrix[2][3] +_pdbx_struct_oper_list.vector[2] +_pdbx_struct_oper_list.matrix[3][1] +_pdbx_struct_oper_list.matrix[3][2] +_pdbx_struct_oper_list.matrix[3][3] +_pdbx_struct_oper_list.vector[3] +1 'identity operation' 1_555 x,y,z 1.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 1.0000000000 +0.0000000000 0.0000000000 0.0000000000 0.0000000000 1.0000000000 0.0000000000 +2 'crystal symmetry operation' 2_555 -x,y+1/2,-z -1.0000000000 0.0000000000 0.0000000000 0.0000000000 0.0000000000 1.0000000000 +0.0000000000 2.4330000000 0.0000000000 0.0000000000 -1.0000000000 0.0000000000 +# +loop_ +_pdbx_audit_revision_history.ordinal +_pdbx_audit_revision_history.data_content_type +_pdbx_audit_revision_history.major_revision +_pdbx_audit_revision_history.minor_revision +_pdbx_audit_revision_history.revision_date +1 'Structure model' 1 0 2005-06-14 +2 'Structure model' 1 1 2008-04-30 +3 'Structure model' 1 2 2011-07-13 +4 'Structure model' 1 3 2017-10-11 +# +_pdbx_audit_revision_details.ordinal 1 +_pdbx_audit_revision_details.revision_ordinal 1 +_pdbx_audit_revision_details.data_content_type 'Structure model' +_pdbx_audit_revision_details.provider repository +_pdbx_audit_revision_details.type 'Initial release' +_pdbx_audit_revision_details.description ? +# +loop_ +_pdbx_audit_revision_group.ordinal +_pdbx_audit_revision_group.revision_ordinal +_pdbx_audit_revision_group.data_content_type +_pdbx_audit_revision_group.group +1 2 'Structure model' 'Version format compliance' +2 3 'Structure model' 'Version format compliance' +3 4 'Structure model' 'Refinement description' +# +_pdbx_audit_revision_category.ordinal 1 +_pdbx_audit_revision_category.revision_ordinal 4 +_pdbx_audit_revision_category.data_content_type 'Structure model' +_pdbx_audit_revision_category.category software +# +loop_ +_software.name +_software.version +_software.date +_software.type +_software.contact_author +_software.contact_author_email +_software.classification +_software.location +_software.language +_software.citation_id +_software.pdbx_ordinal +REFMAC . ? program 'Murshudov, G.N.' ccp4@dl.ac.uk refinement http://www.ccp4.ac.uk/main.html Fortran ? 1 +DENZO . ? ? ? ? 'data reduction' ? ? ? 2 +SCALEPACK . ? ? ? ? 'data scaling' ? ? ? 3 +# +_pdbx_database_remark.id 300 +_pdbx_database_remark.text +;BIOMOLECULE: 1 +THIS ENTRY CONTAINS THE CRYSTALLOGRAPHIC ASYMMETRIC UNIT +WHICH CONSISTS OF 1 CHAIN(S). The second beta strand of +the beta sandwich is generated as described in remark 350. +Beta sheets are generated from unit cell translations +along the unit cell b dimension: x,y+1,z. +; +# +_pdbx_entity_nonpoly.entity_id 2 +_pdbx_entity_nonpoly.name water +_pdbx_entity_nonpoly.comp_id HOH +# +""" model_1yjp_with_waters = model_1yjp.replace('END', '''TER HETATM 61 O HOH A 8 -6.471 5.227 7.124 1.00 22.62 O HETATM 62 O HOH A 9 10.431 1.858 3.216 1.00 19.71 O diff --git a/mmtbx/regression/tst_reduce_timeout.py b/mmtbx/regression/tst_reduce_timeout.py index e11ee8eeca..70e0b95d4c 100644 --- a/mmtbx/regression/tst_reduce_timeout.py +++ b/mmtbx/regression/tst_reduce_timeout.py @@ -1,7 +1,7 @@ from __future__ import absolute_import, division, print_function from mmtbx.utils import run_reduce_with_timeout from time import time -from mmtbx.regression import model_1yjp +from mmtbx.regression import model_1yjp, model_1yjp_cif import sys from six.moves import zip @@ -32,28 +32,57 @@ def exercise(prefix="tst_reduce_timeout_1"): assert l1 == l2 assert 'ATOM 0 HB3 GLN A 5 3.844 2.489 7.623 1.00 11.96 H new' in stdout_lines_1 assert 'ATOM 0 HB3 GLN A 5 3.844 2.489 7.623 1.00 11.96 H new' in stdout_lines_2 - t0 = time() - rr = run_reduce_with_timeout( - stdin_lines=None, - file_name=fn, - parameters="-oh -his -flip -keep -allalt -pen9999", - override_auto_timeout_with=0.01) - t1 = time() - assert t1-t0 < 0.1 - assert rr.return_code == -15 - t0 = time() - rr = run_reduce_with_timeout( - stdin_lines=model_1yjp, - file_name=None, - parameters="-oh -his -flip -keep -allalt -pen9999 -", - override_auto_timeout_with=0.01) - t1 = time() - assert t1-t0 < 0.1 - assert rr.return_code == -15 + # Timeout does not work on Windows for such low values. + if sys.platform != 'win32': + t0 = time() + rr = run_reduce_with_timeout( + stdin_lines=None, + file_name=fn, + parameters="-oh -his -flip -keep -allalt -pen9999", + override_auto_timeout_with=0.01) + t1 = time() + assert t1-t0 < 0.1 + assert rr.return_code == -15 + + t0 = time() + rr = run_reduce_with_timeout( + stdin_lines=model_1yjp, + file_name=None, + parameters="-oh -his -flip -keep -allalt -pen9999 -", + override_auto_timeout_with=0.01) + t1 = time() + assert t1-t0 < 0.1 + assert rr.return_code == -15 + + # Make sure that we get Sorry() when trying with mMCIF file, both on the + # command line and via stdin. + got_Sorry = False + try: + fn = "%s.cif" % prefix + with open(fn, 'w') as f: + f.write(model_1yjp_cif) + rr = run_reduce_with_timeout( + stdin_lines=None, + file_name=fn, + parameters="-oh -his -flip -keep -allalt -pen9999", + override_auto_timeout_with=None) + except Exception as e: + got_Sorry = True + assert got_Sorry==True, "Expected Sorry() exception when opening CIF file, but did not get one." + + got_Sorry = False + try: + rr = run_reduce_with_timeout( + stdin_lines=model_1yjp_cif, + file_name=None, + parameters="-oh -his -flip -keep -allalt -pen9999 -", + override_auto_timeout_with=None) + except Exception as e: + got_Sorry = True + assert got_Sorry==True, "Expected Sorry() exception when opening CIF file, but did not get one." print("OK") if __name__ == "__main__" : - if sys.platform != 'win32': - exercise() + exercise() diff --git a/mmtbx/utils/__init__.py b/mmtbx/utils/__init__.py index 5fe47c7016..da080996e9 100644 --- a/mmtbx/utils/__init__.py +++ b/mmtbx/utils/__init__.py @@ -2211,6 +2211,14 @@ def __init__(self, if stdin_lines is not None and parameters.split()[-1] != '-': raise Sorry(" - should appear at the end of parameters when using stdin_lines mode.") + # Verify that we're not trying to run on an mMCIF file. + if file_name is not None: + if ".cif".lower() in file_name.lower(): + raise Sorry("Reduce cannot read mmCIF files. Please convert to PDB format or use mmtbx.reduce2.") + else: + if "data_" == stdin_lines[0:5]: + raise Sorry("Reduce cannot read mmCIF files. Please convert to PDB format or use mmtbx.reduce2.") + size_bytes = len(stdin_lines) if stdin_lines is not None else 0 command_to_run="molprobity.reduce " if file_name is not None: From fbf9d4f4a4ed47ae623995126bc952ab78b8d7cc Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 6 Feb 2024 13:41:39 -0800 Subject: [PATCH 107/748] Remove write_pdb_or_mmcif_file from model.py --- iotbx/command_line/pdb_cif_conversion.py | 20 +++++----- mmtbx/model/model.py | 49 +++-------------------- mmtbx/regression/model/tst_model.py | 51 ------------------------ 3 files changed, 14 insertions(+), 106 deletions(-) diff --git a/iotbx/command_line/pdb_cif_conversion.py b/iotbx/command_line/pdb_cif_conversion.py index 3bff73fedb..f865df7118 100644 --- a/iotbx/command_line/pdb_cif_conversion.py +++ b/iotbx/command_line/pdb_cif_conversion.py @@ -163,12 +163,15 @@ def get_results(self): f.close() print("Wrote model to '%s'" %file_name) - then use instead model.write_pdb_or_mmcif_file(): + then get a data_manager and use it instead: file_name = 'mypdb.pdb' - file_name = model.write_pdb_or_mmcif_file( - target_format = params.output.target_output_format, - target_filename = file_name) + from iotbx.data_manager import DataManager + dm = DataManager() + dm.set_overwrite(True) + file_name = dm.write_model_file(model, + filename = file_name, + format = params.output.target_output_format) print("Wrote model to '%s'" %file_name) 2. If your code uses ph.as_pdb_string() and you need the string: @@ -249,7 +252,7 @@ def get_results(self): f.close() print("Wrote intermediate model lines to '%s'" %new_file_name) - Use the data_manager or write_pdb_or_mmcif_file to write the file, and + Use the data_manager to write the file, and capture the actual file name so that you can use it when you read the contents of the file back in. @@ -435,11 +438,6 @@ def guess_chemical_elements(self, check_pseudo = False, MODULE: mmtbx/model/model.py: -Method for writing as PDB or mmCIF string, using supplied target_format if -possible, returning file name written: - - def write_pdb_or_mmcif_file(self, - Method for obtaining a PDB or mmCIF string, using supplied target_format if possible, returning the string: @@ -573,7 +571,7 @@ def get_forward_compatible_pdb_text_from_full_text(self, need to capture the actual file names written by the data_manager. b. If you cannot use the data_manager, use the write_pdb_or_mmcif_file - method of the model manager or the hierarchy to write your files. + method of the hierarchy to write your files. This method allows setting the preferred output format and capturing the name of the actual file that is written. diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index eb003d775e..551a4b8471 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -1714,47 +1714,6 @@ def as_pdb_or_mmcif_string(self, **kw) return info.pdb_string - def write_pdb_or_mmcif_file(self, - target_filename, - target_format = None, - data_manager = None, - overwrite = True, - segid_as_auth_segid = True, - remark_section = None, - **kw): - ''' - Shortcut for pdb_or_mmcif_string_info with write_file=True, returning - only the name of the file that is written. The file may be written - in PDB or mmCIF format, with target_format used if feasible. - - Method to allow shifting from general writing as pdb to - writing as mmcif, with the change in two places (here and model.py) - Use default of segid_as_auth_segid=True here (different than - as_mmcif_string()) - :param target_format: desired output format, pdb or mmcif - :param target_filename: desired output file name, to be modified to - match the output format - :param data_manager: data_manager to write files - :param overwrite: parameter to set overwrite=True in data_manager if True - :param segid_as_auth_segid: use the segid in hierarchy as the auth_segid - in mmcif output - :param remark_section: if supplied and format is pdb, add this text - :param **kw: any keywords suitable for as_pdb_string() - and as_mmcif_string() - :returns name of file that is written - ''' - - info = self.pdb_or_mmcif_string_info( - target_filename = target_filename, - target_format = target_format, - data_manager = data_manager, - overwrite = overwrite, - segid_as_auth_segid = segid_as_auth_segid, - remark_section = remark_section, - write_file = True, - **kw) - return info.file_name - def pdb_or_mmcif_string_info(self, target_filename = None, target_format = None, @@ -1767,10 +1726,12 @@ def pdb_or_mmcif_string_info(self, # Method to allow shifting from general writing as pdb # to writing as mmcif, with the change in two places (here and hierarchy.py) - # NOTE: normally use either write_pdb_or_mmcif_file or - # as_pdb_or_mmcif_string instead of this general function + # NOTE: Normally use the data_manager to write any files and use + # tools in the hierarchy to manipulate any aspects of a hierarchy. - # Note default of segid_as_auth_segid = True, different from + # If you need a pdb string, normally use as_pdb_or_mmcif_string + # instead of this general function + # Note default of segid_as_auth_segid = True, different from # as_mmcif_string() if target_format in ['None',None]: # set the default format here diff --git a/mmtbx/regression/model/tst_model.py b/mmtbx/regression/model/tst_model.py index eaff3c56ce..1b3d5510e1 100644 --- a/mmtbx/regression/model/tst_model.py +++ b/mmtbx/regression/model/tst_model.py @@ -1552,57 +1552,7 @@ def exercise_12_as_pdb_or_mmcif_string(): is_mmcif = (str(type(pdb_inp)).find('cif')>0) assert is_mmcif -def exercise_13_write_pdb_or_mmcif_file(): - pdb_inp_lines = flex.split_lines("""\ -CRYST1 107.161 107.161 93.144 90.00 90.00 120.00 H 3 9 -ATOM 1 CA ASP A 1 47.975 -63.194 59.946 1.00 33.86 C -ATOM 5 CA VAL A 2 44.978 -63.576 62.233 1.00 29.81 C -ATOM 8 N GLN B 3 44.585 -65.878 62.864 1.00 25.93 N -ATOM 9 CA GLN B 3 44.166 -67.262 62.686 1.00 24.46 C -ATOM 10 C GLN B 3 42.730 -67.505 63.153 1.00 23.33 C -ATOM 11 O GLN B 3 42.389 -67.234 64.302 1.00 20.10 O -ATOM 12 N MET B 4 41.894 -68.026 62.256 1.00 24.27 N -ATOM 13 CA MET B 4 40.497 -68.318 62.576 1.00 22.89 C -ATOM 14 C MET B 4 40.326 -69.824 62.795 1.00 21.48 C -ATOM 15 O MET B 4 40.633 -70.625 61.911 1.00 23.73 O -""") - from iotbx.pdb.utils import get_pdb_input, get_pdb_info - pdb_info = get_pdb_info(lines=pdb_inp_lines) - h = pdb_info.hierarchy - m = h.as_model_manager(crystal_symmetry = pdb_info.crystal_symmetry) - assert m.can_be_output_as_pdb() - - file_name = m.write_pdb_or_mmcif_file('target_pdb.pdb') - assert file_name == 'target_pdb.pdb' - pdb_inp = get_pdb_input(file_name = file_name) - is_mmcif = (str(type(pdb_inp)).find('cif')>0) - assert not is_mmcif - - file_name = m.write_pdb_or_mmcif_file('target_pdb.pdb', target_format='mmcif') - assert file_name == 'target_pdb.cif' - pdb_inp = get_pdb_input(file_name = file_name) - is_mmcif = (str(type(pdb_inp)).find('cif')>0) - assert is_mmcif - - m.get_hierarchy().only_model().chains()[1].id = "long_chain_id" - assert not m.can_be_output_as_pdb() - - file_name = m.write_pdb_or_mmcif_file('target_pdb.pdb') - assert file_name == 'target_pdb.cif' - pdb_inp = get_pdb_input(file_name = file_name) - is_mmcif = (str(type(pdb_inp)).find('cif')>0) - assert is_mmcif - - file_name = m.write_pdb_or_mmcif_file('target_pdb.pdb', target_format='pdb') - assert file_name == 'target_pdb.cif' - pdb_inp = get_pdb_input(file_name = file_name) - is_mmcif = (str(type(pdb_inp)).find('cif')>0) - assert is_mmcif - def run(): - exercise_12_as_pdb_or_mmcif_string() - exercise_13_write_pdb_or_mmcif_file() - return # ZZ exercise_00() exercise() exercise_2() @@ -1619,7 +1569,6 @@ def run(): exercise_10() exercise_11_ss_annotations() exercise_12_as_pdb_or_mmcif_string() - exercise_13_write_pdb_or_mmcif_file() print(format_cpu_times()) if (__name__ == "__main__"): From 0319c8b4f946a1f9bd26606a8958fcbea34b31a4 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 7 Feb 2024 15:55:12 -0800 Subject: [PATCH 108/748] boost: add -lrt for building libboost_chrono on linux --- boost_adaptbx/SConscript | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/boost_adaptbx/SConscript b/boost_adaptbx/SConscript index 4ad2aef819..221d784444 100644 --- a/boost_adaptbx/SConscript +++ b/boost_adaptbx/SConscript @@ -366,16 +366,19 @@ e.g. with "yum install python-dev" or "apt-get install python-dev". os.path.join(env_etc.boost_dist, 'libs', 'chrono', 'src', '*.cpp'))] # For Windows (c.f. point 2 above) env_boost_chrono.Append(CPPDEFINES={'BOOST_CHRONO_DYN_LINK':1}) + libs = ['boost_system'] + if sys.platform.startswith("linux"): # require realtime extensions for clock_gettime + libs.append('rt') if boost_thread_uses_winthreads: env_boost_chrono.StaticLibrary( target='#lib/boost_chrono', source=boost_chrono_src, - LIBS=['boost_system']) + LIBS=libs) else: env_boost_chrono.SharedLibrary( target='#lib/boost_chrono', source=boost_chrono_src, - LIBS=['boost_system']) + LIBS=libs) #Boost.Timer? if os.path.isdir(os.path.join(env_etc.boost_dist, 'boost', 'timer')): From d14b7466d9815a8f62e046a403df9170fff2809d Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 6 Feb 2024 09:06:59 -0800 Subject: [PATCH 109/748] Major changes to qscore. 1. Implemented kdtree in pure python with flex arrays to speed up nn probe queries, 2. Aggregation by residue which matches the method in mapq, 3. Removed all tests that required running mapq on command line, moved to a personal test file, 4. Check actual qscore values in tests rather than summed values, 5. Misc cleanup, indentation. --- cctbx/maptbx/qscore.py | 1270 ++++++++++++++++++++++++++++++------ cctbx/maptbx/tst_qscore.py | 757 ++++++++++++++++----- cctbx/programs/qscore.py | 194 ++++-- 3 files changed, 1807 insertions(+), 414 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index dd04df81a4..2dfa73d22c 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -8,28 +8,41 @@ """ from __future__ import division +<<<<<<< Updated upstream import math import sys from libtbx.utils import null_out from collections import defaultdict from multiprocessing import Pool, cpu_count +======= +from libtbx.utils import null_out +from multiprocessing import Pool +>>>>>>> Stashed changes from itertools import chain +from collections import defaultdict import numpy as np import numpy.ma as ma - from scipy.spatial import KDTree +import pandas as pd -import cctbx from cctbx.array_family import flex -from scitbx_array_family_flex_ext import bool as flex_bool +<<<<<<< Updated upstream +try: + from tqdm import tqdm +except ImportError: + from .qscore_utils import DummyTQDM as tqdm + + +def radial_shell_worker_v1_np(args): +======= master_phil_str = """ qscore { - nproc = 16 + nproc = 1 .type = int .help = Number of processors to use .short_caption = Number of processors to use @@ -49,10 +62,10 @@ .help = Min number of radial probes to use .short_caption = Number of radial probes to use .expert_level = 1 - selection = None + selection_str = None .type = str - .help = Only test atoms within this selection - .short_caption = Only test atoms within this selection + .help = Only calculate q for atoms within this selection + .short_caption = Only calculate q for atoms within this selection .expert_level = 1 shell_radius_start = 0.1 @@ -70,7 +83,8 @@ shell_radius_num = 20 .type = int .help = The number of radial shells - .short_caption = The number of radial shells (includes start/stop, so minimum 2) + .short_caption = The number of radial shells\ + (includes start/stop, so minimum 2) .expert_level = 1 shells = None @@ -85,16 +99,17 @@ probe_allocation_method = precalculate .type = str .help = The method used to allocate radial probes - .short_caption = Either 'progressive' or 'precalculate'. Progressive is the original method \ - where probes are proposed and rejected iteratively. \ - Precalculate is a method where probes are pre-allocated and \ - rejected once. Parallelization is done by radial shell. \ - Precalculate is much faster but will yield slightly different results. - - progress = False - .type = bool - .help = Report progress - .short_caption = Report progress bar + .short_caption = Either 'progressive' or 'precalculate'. \ + Progressive is the original method \ + where probes are proposed and rejected iteratively. \ + Precalculate is where probes are pre-allocated and \ + rejected once. Parallelization is done by radial shell.\ + Precalculate is faster but with slightly varied results. + + backend = numpy + .type = str + .help = Either 'numpy' or 'flex' + .short_caption = Determines which backend mdoe is used .expert_level = 1 debug = False @@ -106,7 +121,164 @@ """ -def get_probe_mask(atom_tree,probes_xyz,r=None,expected=None,log=null_out(),debug=False): + + +################################################################################ +#### Probe generation functions +################################################################################ + +# Original mapq version +def SpherePtsVectorized ( ctr, rad, N ) : + """ + Function for generating points on a sphere. For testing only. + It retains the original mapq code pattern + """ + thetas, phis = [], [] + from math import acos, sin, cos, sqrt, pi + for k in range ( 1, N+1 ) : + h = -1.0 + ( 2.0*float(k-1)/float(N-1) ) + phis.append ( acos(h) ) + thetas.append ( 0 if k == 1 or k == N else + (thetas[k-2] + 3.6/sqrt(N*(1.0-h**2.0))) % (2*pi) ) + + pts = [None] * N + for i, theta, phi in zip ( range(N), thetas, phis ): + v = np.array([ sin(phi)*cos(theta), sin(phi)*sin(theta), cos(phi)]) + + pt = ctr + v * rad + pts[i] = pt + pts = np.array(pts) + pts = pts.swapaxes(0,1) + return pts + + +# Fast numpy version +def generate_probes_np(atoms_xyz, rad, n_probes): + """ + Generate probes using the same methodology as Pintile mapq, but vectorized + + atoms_xyz: np array of shape (n_atoms,3) + rad: the radius at which to place the probes + N: the number of probes per atom + + Returns: + probes (np.ndarray): shape (n_atoms,n_probes,3) + """ + assert atoms_xyz.ndim == 2 and atoms_xyz.shape[-1]==3, ( + "Provide coordinates in shape (n_atoms,3)") + + N = n_probes + h = -1.0 + (2.0 * np.arange(N) / float(N-1)) + phis = np.arccos(h) + + thetas = np.zeros(N) + a = (3.6 / np.sqrt(N * (1.0 - h[1:-1]**2))) + thetas[1:-1] = a + thetas = np.cumsum(thetas) + + + x = np.sin(phis) * np.cos(thetas) + y = np.sin(phis) * np.sin(thetas) + z = np.cos(phis) + + probes = rad * np.stack([x, y, z], axis=-1) + + # Adjusting location of generated points relative to point ctr + probes = probes.reshape(-1, 1, 3) + atoms_xyz.reshape(1, -1, 3) + + # reshape (n_atoms,n_probes,3) + probes = probes.swapaxes(0,1) + return probes + + +# Generate Points with flex + +def cumsum_flex(arr): + """ + Return an array that is the cumulative sum of arr + Analogous to np.cumsum + """ + result = flex.double(len(arr)) + running_sum = 0.0 + for i, x in enumerate(arr): + running_sum += x + result[i] = running_sum + return result + +def broadcast_add_vec3(ctr, points): + """ + Broadcast add two flex.vec3_double arrays. + + Params: + ctr (flex.vec3_double): the 'center' coordinates + points (flex.vec3_double): the points that will be added to each ctr + + Returns: + result (flex.vec3_double): array of shape (N*M,3), 1 point for each center + """ + N = points.size() + M = ctr.size() + extended_ctr = flex.vec3_double() + extended_points = flex.vec3_double() + + # Extend ctr and points + for point in ctr: + extended_ctr.extend(flex.vec3_double([point] * N)) + for _ in range(M): + extended_points.extend(points) + + # Perform addition + result = flex.vec3_double(M * N) + space =flex.size_t_range(M*N) + for i in space: + pt = extended_ctr[i:i+1] + extended_points[i:i+1] + result=result.set_selected(space[i:i+1],pt) + return result + + +def generate_probes_flex(ctr, rad, N): +>>>>>>> Stashed changes + """ + Calulate qscore for a single radial shell using version 1 (serial probe allocation) and numpy + """ + ( + i, + atoms_xyz, + n_probes, + radius_shell, + tree, + rtol, + selection, + n_probes_target, + ) = args + +<<<<<<< Updated upstream + # + # manage selection input + if selection is None: + selection = np.arange(len(atoms_xyz)) +======= + # Generating spherical coordinates + x = flex.sin(phis) * flex.cos(thetas) + y = flex.sin(phis) * flex.sin(thetas) + z = flex.cos(phis) + points = rad * flex.vec3_double(x, y, z) + # Adding the generated points to center points + probes = broadcast_add_vec3(ctr, points) + return probes + + +################################################################################ +#### Progressive mode functions +################################################################################ + +def get_probe_mask( + atom_tree, + probes_xyz, + r=None, + expected=None, + log=null_out(), + ): """ atoms_xyz shape (n_atoms,3) probes_xyz shape (n_atoms,n_probes,3) @@ -117,7 +289,9 @@ def get_probe_mask(atom_tree,probes_xyz,r=None,expected=None,log=null_out(),debu """ assert r is not None, "Provide a radius" - assert probes_xyz.ndim ==3 and probes_xyz.shape[-1] == 3, "Provide probes_xyz as shape: (n_atoms,n_probes,3)" + assert probes_xyz.ndim ==3 and probes_xyz.shape[-1] == 3,( + "Provide probes_xyz as shape: (n_atoms,n_probes,3)") + n_atoms_probe,n_probes,_ = probes_xyz.shape dim = probes_xyz.shape[-1] # 3 for cartesian coords @@ -157,109 +331,48 @@ def get_probe_mask(atom_tree,probes_xyz,r=None,expected=None,log=null_out(),debu other_points_within_r.append(other_indices) # true are points that don't get rejected - num_nbrs_other = np.array([len(inds) for i,inds in enumerate(other_points_within_r)]) - print(num_nbrs_other,file=log) + num_nbrs_other = np.array( + [len(inds) for i,inds in enumerate(other_points_within_r)]) + num_nbrs_other = num_nbrs_other.reshape((n_atoms_probe,n_probes)) mask = num_nbrs_other==0 return mask -# Generating probes -def generate_probes_np(atoms_xyz, rad, n_probes): - """ - atoms_xyz: np array of shape (n_atoms,3) - rad: the radius at which to place the probes - N: the number of probes per atom - Returns: - probes (np.ndarray): shape (n_atoms,n_probes,3) - """ - assert atoms_xyz.ndim == 2 and atoms_xyz.shape[-1]==3, "Provide coordinates in shape (n_atoms,3)" - N = n_probes - h = -1.0 + (2.0 * np.arange(N) / float(N-1)) - phis = np.arccos(h) - - thetas = np.zeros(N) - a = (3.6 / np.sqrt(N * (1.0 - h[1:-1]**2))) - thetas[1:-1] = a - thetas = np.cumsum(thetas) - - - x = np.sin(phis) * np.cos(thetas) - y = np.sin(phis) * np.sin(thetas) - z = np.cos(phis) - - probes = rad * np.stack([x, y, z], axis=-1) - - # Adjusting location of generated points relative to point ctr - probes = probes.reshape(-1, 1, 3) + atoms_xyz.reshape(1, -1, 3) - - # reshape (n_atoms,n_probes,3) - probes = probes.swapaxes(0,1) - return probes - -def SpherePtsVectorized ( ctr, rad, N ) : - """ - Function for generating points on a sphere. For testing, it retains the original - mapq pattern - """ - thetas, phis = [], [] - from math import acos, sin, cos, sqrt, pi - for k in range ( 1, N+1 ) : - h = -1.0 + ( 2.0*float(k-1)/float(N-1) ) - phis.append ( acos(h) ) - thetas.append ( 0 if k == 1 or k == N else - (thetas[k-2] + 3.6/sqrt(N*(1.0-h**2.0))) % (2*pi) ) - - pts = [None] * N - for i, theta, phi in zip ( range(N), thetas, phis ): - v = np.array([ sin(phi)*cos(theta), sin(phi)*sin(theta), cos(phi)]) - - pt = ctr + v * rad - pts[i] = pt - pts = np.array(pts) - pts = pts.swapaxes(0,1) - return pts - -def _shell_probes_progressive_wrapper(kwargs): - """ - A wrapper function to pass kwargs for 'shell_probes_progressive' - to multiprocessing pool. - """ - return shell_probes_progressive(**kwargs) - -def shell_probes_progressive( atoms_xyz=None, # A numpy array of shape (N,3) - atoms_tree=None, # An atom_xyz scipy kdtree - selection=None, # An atom selection - n_probes_target=8,# The desired number of probes per shell - n_probes_max=16, # The maximum number of probes allowed - n_probes_min=4, - RAD=1.5, # The nominal radius of this shell - rtol=0.9, # Multiplied with RAD to get actual radius - log = null_out(), - ): +def shell_probes_progressive( + atoms_xyz=None, # A numpy array of shape (N,3) + atoms_tree=None, # An atom_xyz scipy kdtree + selection_bool=None,# Boolean atom selection + n_probes_target=8,# The desired number of probes per shell + n_probes_max=16, # The maximum number of probes allowed + n_probes_min=4, + RAD=1.5, # The nominal radius of this shell + rtol=0.9, # Multiplied with RAD to get actual radius + log = null_out(), + ): """ Generate probes progressively for a single shell (radius) """ # Do input validation if not atoms_tree: - assert atoms_tree is None, "If not providing an atom tree, provide a 2d atom coordinate array to build tree" + assert atoms_tree is None, ( + "If not providing an atom tree, \ + provide a 2d atom coordinate array to build tree") + atoms_tree = KDTree(atoms_xyz) # Manage log if log is None: - log = null_out() + log = null_out() # manage selection input - if selection is None: - selection = np.arange(atoms_xyz.shape[0]) - else: - selection = np.array(selection) - assert selection.dtype in [int,bool] + if selection_bool is None: + selection_bool = np.full(len(atoms_xyz),True) # do selection - atoms_xyz_sel = atoms_xyz[selection] + atoms_xyz_sel = atoms_xyz[selection_bool] n_atoms = atoms_xyz_sel.shape[0] all_pts = [] # list of probe arrays for each atom @@ -274,15 +387,19 @@ def shell_probes_progressive( atoms_xyz=None, # A numpy array of shape (N,3) # try to get at least numPts] points at [RAD] distance # from the atom, that are not closer to other atoms N_i = 50 + + # If we find the necessary number of probes in the first iteration, + # then i will never go to 1 for i in range(0, N_i): rejections = 0 - # if we find the necessary number of probes in the first iteration, then i will never go to 1 - # points on a sphere at radius RAD... - n_pts_to_grab = (n_probes_target + i * 2) # progressively more points are grabbed with each failed iter - #print(f"Grabbing {n_pts_to_grab} probes at RAD {RAD} using generate_probes_np()",file=log) - outPts = generate_probes_np(coord, RAD, n_pts_to_grab) # get the points in shape (n_atoms,n_pts_to_grab,3) + + # progressively more points are grabbed with each failed iter + n_pts_to_grab = (n_probes_target + i * 2) + + # get the points in shape (n_atoms,n_pts_to_grab,3) + outPts = generate_probes_np(coord, RAD, n_pts_to_grab) # initialize points to keep at_pts, at_pts_i = [None] * outPts.shape[1], 0 @@ -294,8 +411,8 @@ def shell_probes_progressive( atoms_xyz=None, # A numpy array of shape (N,3) # will get mask of shape (n_atoms,n_probes) mask = get_probe_mask(atoms_tree,outPts,r=outRAD,expected=atom_i,log=log) - - for pt_i, pt in enumerate(outPts[0]): # identify which ones to keep, progressively grow pts list + # identify which ones to keep, progressively grow pts list + for pt_i, pt in enumerate(outPts[0]): keep = mask[0,pt_i] # only one atom TODO: vectorize atoms if keep: at_pts[at_pts_i] = pt @@ -321,10 +438,10 @@ def shell_probes_progressive( atoms_xyz=None, # A numpy array of shape (N,3) #Finish working on a single atom - pts = np.array(pts) if pts.shape == (0,): # all probes clashed pts = np.full((n_probes_max,3),np.nan) +>>>>>>> Stashed changes else: assert pts.shape == (n_probes_max,3), ( f"Generated points shape:{pts.shape}, expected: {(n_probes_max,3)}, try increasing n_probes_max" @@ -402,12 +519,97 @@ def shell_probes_precalculate(atoms_xyz=None, # A numpy array of shape (N,3) return probe_xyz, probe_mask +<<<<<<< Updated upstream +def radial_shell_worker_v2_np(args): +======= +################################################################################ +#### numpy/scipy-based functions (precalculate mode) +################################################################################ + +def shell_probes_precalculate( + atoms_xyz=None, # A numpy array of shape (N,3) + atoms_tree=None, # An atom_xyz scipy kdtree + selection_bool=None,# Boolean atom selection + n_probes_target=8,# The desired number of probes per shell + n_probes_max=16, # The maximum number of probes allowed + n_probes_min=4, # The min number of probes allowed without error + RAD=1.5, # The nominal radius of this shell + rtol=0.9, # Multiplied with RAD to get actual radius + log = null_out(), + strict = False, + ): + """ + Generate probes by precalculating for a single shell (radius) + """ + + # Do input validation + if not atoms_tree: + assert atoms_tree is None, ("If not providing an atom tree,\ + provide a 2d atom coordinate array to build tree") + + # make atom kdtree + atoms_tree = KDTree(atoms_xyz) + + # Manage log + if log is None: + log = null_out() + + # manage selection input + if selection_bool is None: + selection_bool = np.full(len(atoms_xyz),True) + + + # do selection + atoms_xyz_sel = atoms_xyz[selection_bool] + + # get probe coordinates + probe_xyz = generate_probes_np(atoms_xyz_sel, RAD, n_probes_max) + n_atoms, n_probes, _ = probe_xyz.shape + probe_xyz_flat = probe_xyz.reshape(-1,3) + + # modify "real" radius as in mapq + outRAD = RAD*rtol + + # query kdtree to get neighbors and their distances + dists, atom_indices = atoms_tree.query(probe_xyz_flat, k=2) + dists = dists.reshape((n_atoms,n_probes,2)) + atom_indices = atom_indices.reshape((n_atoms,n_probes,2)) + + # Build an index array that would be expected if each probe is near "its" atom + row_indices = np.arange(n_atoms)[:, np.newaxis] + + # Mask for whether each probe's nearest atom is the one expected + expected_atom_mask = atom_indices[:,:,0]==row_indices + + # A second mask to determine if the second nearest neighbor should be rejected + # (whether the second nearest neighbor is within the rejection radius) + within_r_mask = dists[:,:,1]= n_probes_min, ( + f"Some atoms have less than {n_probes_min} probes. \ + ({len(problematic_probes)}). Consider raising n_probes_max") + + return probe_xyz, probe_mask + + def get_probes( atoms_xyz=None, + sites_cart = None, atoms_tree = None, params=None, + selection_bool_np = None, + selection_bool_flex=None, worker_func=None, log=None): +>>>>>>> Stashed changes """ Generate probes for atom coordinates. """ @@ -446,44 +648,97 @@ def get_probes( return probe_xyz, probe_mask +<<<<<<< Updated upstream +def ndarray_to_nested_list(arr): + """ + Convert a NumPy array of arbitrary dimensions into a nested list. + :param arr: A NumPy array. + :return: A nested list representing the array. + """ + if arr.ndim == 1: + return arr.tolist() + return [ndarray_to_nested_list(sub_arr) for sub_arr in arr] + +# Example usage +======= def calc_qscore(mmm,params,log=null_out(),debug=False): """ Calculate qscore from map model manager """ model = mmm.model() + # never do hydrogen + model = model.select(model.selection("not element H")) mm = mmm.map_manager() +>>>>>>> Stashed changes - # Get atoms - atom_xyz = model.get_sites_cart().as_numpy_array() - - # Get probes and probe mask (probes to reject) - if params.probe_allocation_method == "progressive": - worker_func=_shell_probes_progressive_wrapper - else: - worker_func=_shell_probes_precalculate_wrapper +def qscore_np( + mmm, + selection=None, + n_probes=32, + shells=np.array( + [ + 0.1, + 0.27272727, + 0.44545455, + 0.61818182, + 0.79090909, + 0.96363636, + 1.13636364, + 1.30909091, + 1.48181818, + 1.65454545, + 1.82727273, + 2.0, + ] + ), + version=2, + nproc=cpu_count(), + log=sys.stdout, +): + """ + Calculate the qscore metric per-atom from an mmtbx map-model-manager, using numpy + """ + model = mmm.model() + mm = mmm.map_manager() + volume = mm.map_data().as_numpy_array() + radii = shells + voxel_size = mm.pixel_sizes() - probe_xyz,probe_mask = get_probes( - atoms_xyz=atom_xyz, - atoms_tree = None, - params=params, - worker_func=worker_func, - log = log, + probe_xyz, probe_mask = radial_shell_mp_np( + model, + n_probes=n_probes, + num_processes=nproc, + selection=selection, + version=version, + radii=radii, + log=log, ) - n_shells, n_atoms, n_probes, _ = probe_xyz.shape + # after the probe generation, versions 1 and 2 are the same - # flatten - probe_xyz_flat = probe_xyz.reshape((n_atoms * n_shells * n_probes, 3)) - probe_mask_flat = probe_mask.reshape(-1) # (n_shells*n_atoms*n_probes,) + # infer params from shape + n_shells, n_atoms, n_probes, _ = probe_xyz.shape + + # flatten + probe_xyz_flat = probe_xyz.reshape((n_atoms * n_shells * n_probes, 3)) + probe_mask_flat = probe_mask.reshape(-1) # (n_shells*n_atoms*n_probes,) - # apply the mask to get only the xyz for selected probes - masked_probe_xyz_flat = probe_xyz_flat[probe_mask_flat] +<<<<<<< Updated upstream + # select mask=True probes + masked_probe_xyz_flat = probe_xyz_flat[probe_mask_flat] + # interpolate + masked_density = trilinear_interpolation( + volume, masked_probe_xyz_flat, voxel_size=voxel_size +======= # interpolate volume = mm.map_data().as_numpy_array() voxel_size = mm.pixel_sizes() - masked_density = trilinear_interpolation(volume, masked_probe_xyz_flat, voxel_size=voxel_size) + # masked_density = trilinear_interpolation( + # volume, masked_probe_xyz_flat, voxel_size=voxel_size) + masked_density = mm.density_at_sites_cart( + flex.vec3_double(masked_probe_xyz_flat)).as_numpy_array() d_vals = np.full((n_shells, n_atoms, n_probes),np.nan) d_vals[probe_mask] = masked_density @@ -519,6 +774,14 @@ def calc_qscore(mmm,params,log=null_out(),debug=False): # CALCULATE Q q = rowwise_corrcoef(g_vals_2d, d_vals_2d, mask=mask_2d) + # round sensibly + q = np.around(q,4) + + # aggregate per residue + qscore_df = aggregate_qscore_per_residue(model,q,window=3) + q = flex.double(q) + qscore_per_residue = flex.double(qscore_df["Q-scorePerResidue"].values) + # Output if debug or params.debug: # Collect debug data @@ -529,30 +792,196 @@ def calc_qscore(mmm,params,log=null_out(),debug=False): "d_vals":d_vals, "g_vals":g_vals, "qscore_per_atom":q, + "qscore_per_residue":qscore_per_residue, + "qscore_dataframe":qscore_df, } else: result = { "qscore_per_atom":q, + "qscore_per_residue":qscore_per_residue, + "qscore_dataframe":qscore_df } return result +################################################################################ +#### CCTBX flex-based functions (precalculate mode) +################################################################################ +def shell_probes_precalculate_flex( + atoms_xyz=None, # sites_cart. Flex vec3_double + atoms_tree=None, # A KDTree + selection_bool=None, # Boolean atom selection + n_probes_target=8,# The desired number of probes per shell + n_probes_max=16, # The maximum number of probes allowed + n_probes_min=4, # The min number of probes allowed without error + RAD=1.5, # The nominal radius of this shell + rtol=0.9, # Multiplied with RAD to get actual radius + log = null_out(), + strict = False, + ): + """ + Generate probes by precalculating for a single shell (radius) + """ + # Do input validation + if not atoms_tree: + assert atoms_tree is None, ("If not providing an atom tree,\ + provide a 2d atom coordinate array to build tree") -def ndarray_to_nested_list(arr): + # make atom kdtree + atoms_tree = KDTreeFlex(atoms_xyz) + + # Manage log + if log is None: + log = null_out() + + # manage selection input + + if selection_bool is None: + selection_bool = flex.bool(len(atoms_xyz),True) + + + # do selection + sites_sel = atoms_xyz.select(selection_bool) + n_atoms = len(sites_sel) + + # get probe coordinates + probe_sites = generate_probes_flex(sites_sel, RAD, n_probes_max) + + + # modify "real" radius as in mapq + outRAD = RAD*rtol + + # query kdtree to get neighbors and their distances + dists,atom_indices = atoms_tree.query_nearest_neighbors(probe_sites,k=2) + atom_indices_flat = flex_from_list(atom_indices) + + # Perform equivalent to atom_indices[:,:,0] if (n_atoms,n_probes,k) + dim0_indices = flex.size_t_range(0, n_atoms*n_probes_max*2, 2) + atom_indices_flat = atom_indices_flat.select(dim0_indices) + + # Build an index array that would be expected if each probe is near "its" atom + row_indices_flat = flex.size_t([ + i for i in range(n_atoms) for _ in range(n_probes_max)]) + + + # Mask for whether each probe's nearest atom is the one expected + expected_mask = row_indices_flat == atom_indices_flat + + + # A second mask to determine if the second nearest neighbor should be rejected + # (whether the second nearest neighbor is within the rejection radius) + dists = flex_from_list(dists) + # perform equivalent selcetion to dists[:,:,1] if (n_atoms,n_probes,k) + dist_dim1_sel = flex.size_t([i * 2 + 1 for i in range(n_atoms * n_probes_max)]) + dists_dim1 = dists.select(dist_dim1_sel) + within_r_mask = dists_dim1>>>>>> Stashed changes + ) + + # reshape interpolated values to (n_shells,n_atoms, n_probes) + + d_vals = np.zeros((n_shells, n_atoms, n_probes)) + d_vals[probe_mask] = masked_density + + # reshape to (M,N*L) for rowwise correlation + + d_vals_2d = d_vals.transpose(1, 0, 2).reshape(d_vals.shape[1], -1) + + # create the reference data + + M = volume + maxD = min(M.mean() + M.std() * 10, M.max()) + minD = max(M.mean() - M.std() * 1, M.min()) + A = maxD - minD + B = minD + u = 0 + sigma = 0.6 + x = np.array(radii) + y = A * np.exp(-0.5 * ((x - u) / sigma) ** 2) + B + + # Stack and reshape data for correlation calc + + # stack the reference to shape (n_shells,n_atoms,n_probes) + g_vals = np.repeat(y[:, None], n_probes, axis=1) + g_vals = np.expand_dims(g_vals, 1) + g_vals = np.tile(g_vals, (n_atoms, 1)) + + # reshape + g_vals_2d = g_vals.transpose(1, 0, 2).reshape(g_vals.shape[1], -1) + d_vals_2d = d_vals.transpose(1, 0, 2).reshape(d_vals.shape[1], -1) + mask_2d = probe_mask.transpose(1, 0, 2).reshape(probe_mask.shape[1], -1) + + # # CALCULATE Q + + # # numpy + q = rowwise_corrcoef(g_vals_2d, d_vals_2d, mask=mask_2d) + + # # Log + # import os + + # print("FINISHING...") + # print(os.getcwd()) + # print("saving atoms xyz: atom_xyz_np.npy") + # np.save("atoms_xyz_np.npy",model.get_sites_cart().as_numpy_array()) + # print("saving probe xyz: probe_xyz_np.npy") + # np.save("probe_xyz_np.npy",probe_xyz) + # print("saving probe mask: probe_mask_np.npy") + # np.save("probe_mask_np.npy",probe_mask) + # print("saving qscore: qscore_np.npy") + # np.save("qscore_np.npy",q) + + return q + ############################################################################## # Code below here requires refactoring ############################################################################## +<<<<<<< Updated upstream def radial_shell_worker_v2_flex(args): """ Calulate qscore for a single radial shell using version 2 (parallel probe allocation) and flex only @@ -579,6 +1008,88 @@ def radial_shell_worker_v2_flex(args): ) probe_mask = counts == 0 return probe_xyz, probe_mask +======= + # for each "shell row" + for shell_idx,(probe_xyz,probe_mask) in enumerate(zip(probe_xyzs,probe_masks)): + probe_mask.reshape(flex.grid(n_atoms*params.n_probes_max)) + probe_xyz_sel = probe_xyz.select(probe_mask) + + # get d_vals for a "shell row" + d_vals = mm.density_at_sites_cart(probe_xyz_sel) + + # get reference for the "shell row" + g_vals = flex.double(n_atoms*params.n_probes_max,y_cctbx[shell_idx]) + g_vals = g_vals.select(probe_mask) + + # calc flat indices for the shell + start_idx = shell_idx * n_atoms * n_probes + stop_idx = start_idx + n_atoms * n_probes + shell_space = flex.size_t_range(start_idx,stop_idx) + + # apply shell mask + masked_shell_space = shell_space.select(probe_mask) + + # put d,g, mask into results + full_flat_d.set_selected(masked_shell_space,d_vals) + full_flat_g.set_selected(masked_shell_space,g_vals) + full_flat_mask = full_flat_mask.set_selected(shell_space,probe_mask) + + # calculate q + def calculate_1d_indices_for_atom(n_shells, n_atoms, n_probes, atom_idx): + indices_1d = [] + for shell_idx in range(n_shells): + for probe_idx in range(n_probes): + index_1d = shell_idx * (n_atoms * n_probes) + atom_idx * n_probes + probe_idx + indices_1d.append(index_1d) + return indices_1d + + qscore_per_atom = [] + mask_check_1d = [] + for atomi in range(n_atoms): + inds = calculate_1d_indices_for_atom(n_shells,n_atoms,n_probes,atomi) + inds = flex.size_t(inds) + + # select an "atom row" for d,g,mask values + d_row = full_flat_d.select(inds) + g_row = full_flat_g.select(inds) + mask = full_flat_mask.select(inds) + + # subset the d,g rows using the mask + d = d_row.select(mask) + g = g_row.select(mask) + + # calculate correlation between masked d and g + qval = flex.linear_correlation(d, g).coefficient() + qscore_per_atom.append(qval) + + qscore_per_atom = flex.double(qscore_per_atom) + + qscore_df = aggregate_qscore_per_residue(model,np.array(qscore_per_atom),window=3) + qscore_per_residue = flex.double(qscore_df["Q-scorePerResidue"].values) + + # Output + if debug or params.debug: + # Collect debug data + result = { + "atom_xyz":atoms_xyz, + "probe_xyz":probe_xyzs, + "probe_mask":probe_masks, + "d_vals":full_flat_d, + "g_vals":full_flat_g, + "qscore_per_atom":qscore_per_atom, + "mask_check_1d":mask_check_1d, + "qscore_per_residue":qscore_per_residue, + "qscore_dataframe":qscore_df + } + else: + result = { + "qscore_per_atom":qscore_per_atom, + "qscore_per_residue":qscore_per_residue, + "qscore_dataframe":qscore_df + + } + return result +>>>>>>> Stashed changes def radial_shell_v2_mp_flex( @@ -600,6 +1111,7 @@ def radial_shell_v2_mp_flex( else: worker_func = radial_shell_worker_v2_flex +<<<<<<< Updated upstream # get a "tree", which is just a dictionary of index:local neighbor indices tree, _ = query_atom_neighbors(model, radius=3.5) atoms_xyz = model.get_sites_cart() @@ -658,6 +1170,17 @@ def radial_shell_v2_mp_flex( out_mask.reshape(flex.grid(n_shells, n_atoms, n_probes)) return out_probes, out_mask +======= +################################################################################ +#### KDTree implementation using flex arrays (no numpy/scipy) +################################################################################ +class KDTreeFlexNode: + def __init__(self, index, point, left=None, right=None): + self.index = index + self.point = point + self.left = left + self.right = right +>>>>>>> Stashed changes def qscore_flex( @@ -690,6 +1213,7 @@ def qscore_flex( volume = mm.map_data() voxel_size = mm.pixel_sizes() +<<<<<<< Updated upstream probe_xyz, probe_mask = radial_shell_v2_mp_flex( model, n_probes=n_probes, @@ -702,17 +1226,90 @@ def qscore_flex( # aliases probe_xyz_cctbx = probe_xyz probe_mask_cctbx = probe_mask +======= + + def pre_sort_indices(self, points): + # Sort indices for each axis and return the sorted indices + x,y,z = points.parts() + sorted_indices = [ + flex.sort_permutation(x), + flex.sort_permutation(y), + flex.sort_permutation(z)] + return sorted_indices + + def build_tree(self, indices, points, depth): + if not indices: + return None + + axis = depth % self.dims + + + sorted_indices = self.axis_sorted_indices[axis] + + + # Step 4: Create an empty boolean mask of length N, initially set to False + mask = flex.bool(len(sorted_indices),False) + + # Directly set mask to True for positions in your query array + mask.set_selected(indices,True) + + # Step 5: Apply the mask to the sorted indices, + # then use this to create a sorted mask + # This step seems to be where you're looking to optimize. + # To directly use the sorted_indices to index into 'mask' and maintain sorting: + sorted_mask = mask.select(sorted_indices) + + # Now, apply this sorted_mask to select from the sorted_indices + sorted_indices_this_axis = sorted_indices.select(sorted_mask) + + + if len(sorted_indices_this_axis) == 0: + return None + + median_idx = len(sorted_indices_this_axis) // 2 + median_index = sorted_indices_this_axis[median_idx] + + left_indices = sorted_indices_this_axis[:median_idx] + right_indices = sorted_indices_this_axis[median_idx + 1:] + + return KDTreeFlexNode( + median_index, + points[median_index:median_index+1], + left=self.build_tree(left_indices, points, depth + 1), + right=self.build_tree(right_indices, points, depth + 1) + ) + def _nearest_neighbor(self, root, point, depth=0, best=None, k=1): + if root is None: + return best + + if best is None: + best = [] +>>>>>>> Stashed changes # infer params from shape n_shells, n_atoms, n_probes, _ = probe_xyz.focus() # APPLY MASK BEFORE INTERPOLATION +<<<<<<< Updated upstream probe_mask_cctbx_fullflat = [] for val in probe_mask_cctbx: for _ in range(3): # since A has an additional dimension of size 3 probe_mask_cctbx_fullflat.append(val) +======= + # Check the current root distance + current_dist = root.point.max_distance(point) + if len(best) < k or current_dist < best[-1]['dist']: + best.append({'index': root.index, 'dist': current_dist}) + best.sort(key=lambda x: x['dist']) + best = best[:k] # Keep only k nearest + + # Check if we need to search the opposite branch + if len(best) < k or ( + abs(point[0][axis] - root.point[0][axis]) < best[-1]['dist']): + best = self._nearest_neighbor(opposite_branch, point, depth + 1, best, k) +>>>>>>> Stashed changes mask = flex.bool(probe_mask_cctbx_fullflat) # indices = flex.int([i for i in range(1, keep_mask_cctbx.size() + 1) for _ in range(3)]) @@ -720,6 +1317,7 @@ def qscore_flex( # sel_indices = indices.select(mask) masked_probe_xyz_flat_cctbx = flex.vec3_double(sel) +<<<<<<< Updated upstream # INTERPOLATE masked_density_cctbx = mm.density_at_sites_cart( @@ -808,6 +1406,16 @@ def custom_reshape_indices(flex_array): q = flex.double(q_cctbx) return q +======= + def query_nearest_neighbors(self, query_points, k=1): + dists, inds = [], [] + for i,point in enumerate(query_points): + point = query_points[i:i+1] + nearest = self._nearest_neighbor(self.root, point, k=k) + dists.append([n['dist'] for n in nearest]) + inds.append([n['index'] for n in nearest]) + return dists, inds +>>>>>>> Stashed changes # qscore utils @@ -1017,84 +1625,85 @@ def query_ball_point_flex(tree, tree_xyz, query_xyz, r=None): # flex utils def flex_from_list(lst, signed_int=False): - """Generate a flex array from a list, try to infer type""" - flat_list, shape = flatten_and_shape(lst) - dtype = get_dtype_of_list(flat_list) - type_mapper = {int: flex.size_t, - float: flex.double, - bool: flex.bool} - if signed_int: - type_mapper[int] = flex.int16 - - # make flex array - assert dtype in type_mapper, f"Unrecognized type: {dtype}" - flex_func = type_mapper[dtype] - flex_array = flex_func(flat_list) - if len(shape) > 1: - flex_array.reshape(flex.grid(*shape)) - return flex_array + """Generate a flex array from a list, try to infer type""" + flat_list, shape = flatten_and_shape(lst) + dtype = get_dtype_of_list(flat_list) + type_mapper = {int: flex.size_t, + float: flex.double, + bool: flex.bool} + if signed_int: + type_mapper[int] = flex.int16 + + # make flex array + assert dtype in type_mapper, f"Unrecognized type: {dtype}" + flex_func = type_mapper[dtype] + flex_array = flex_func(flat_list) + if len(shape) > 1: + flex_array.reshape(flex.grid(*shape)) + return flex_array def flatten_and_shape(lst): - """Flatten a nested list and return its shape.""" - def helper(l): - if not isinstance(l, list): - return [l], () - flat = [] - shapes = [] - for item in l: - f, s = helper(item) - flat.extend(f) - shapes.append(s) - if len(set(shapes)) != 1: - raise ValueError("Ragged nested list detected.") - return flat, (len(l),) + shapes[0] - - flattened, shape = helper(lst) - return flattened, shape + """Flatten a nested list and return its shape.""" + def helper(l): + if not isinstance(l, list): + return [l], () + flat = [] + shapes = [] + for item in l: + f, s = helper(item) + flat.extend(f) + shapes.append(s) + if len(set(shapes)) != 1: + raise ValueError("Ragged nested list detected.") + return flat, (len(l),) + shapes[0] + + flattened, shape = helper(lst) + return flattened, shape def get_dtype_of_list(lst): - dtypes = {type(item) for item in lst} + dtypes = {type(item) for item in lst} - if len(dtypes) > 1: - raise ValueError("Multiple data types detected.") - elif len(dtypes) == 0: - raise ValueError("Empty list provided.") - else: - return dtypes.pop() + if len(dtypes) > 1: + raise ValueError("Multiple data types detected.") + elif len(dtypes) == 0: + raise ValueError("Empty list provided.") + else: + return dtypes.pop() def nd_to_1d_indices(indices, shape): - """Generate the 1d indices given nd indices and an array shape""" - # Normalize indices to always use slice objects - normalized_indices = [] - for dim, idx in enumerate(indices): - if idx is None: - normalized_indices.append(slice(0, shape[dim])) - else: - normalized_indices.append(idx) - - # If any index is a slice, recursively call function for each value in slice - for dim, (i, s) in enumerate(zip(normalized_indices, shape)): - if isinstance(i, slice): - result_indices = [] - start, stop, step = i.indices(s) - for j in range(start, stop, step): - new_indices = list(normalized_indices) - new_indices[dim] = j - result_indices.extend(nd_to_1d_indices(new_indices, shape)) - return result_indices - - # If no slices, calculate single 1D index - index = 0 - stride = 1 - for i, dim in reversed(list(zip(normalized_indices, shape))): - index += i * stride - stride *= dim - return [index] - - + """Generate the 1d indices given nd indices and an array shape""" + # Normalize indices to always use slice objects + normalized_indices = [] + for dim, idx in enumerate(indices): + if idx is None: + normalized_indices.append(slice(0, shape[dim])) + else: + normalized_indices.append(idx) + + # If any index is a slice, recursively call function for each value in slice + for dim, (i, s) in enumerate(zip(normalized_indices, shape)): + if isinstance(i, slice): + result_indices = [] + start, stop, step = i.indices(s) + for j in range(start, stop, step): + new_indices = list(normalized_indices) + new_indices[dim] = j + result_indices.extend(nd_to_1d_indices(new_indices, shape)) + return result_indices + + # If no slices, calculate single 1D index + index = 0 + stride = 1 + for i, dim in reversed(list(zip(normalized_indices, shape))): + index += i * stride + stride *= dim + return [index] + + +<<<<<<< Updated upstream def optimized_nd_to_1d_indices(i, shape): """Similar to above, but hardcoded to select a single index on dimension 1""" # For fixed input of (None, i, None), we directly compute based on given structure @@ -1134,3 +1743,250 @@ def flex_std(flex_array): # Compute the standard deviation std_dev = (sum_squared_deviations / (n - 1)) ** 0.5 return std_dev +======= +def cdist_flex(A, B): + """A flex implementation of the cdist function""" + + def indices_2d_flex(dimensions): + N = len(dimensions) + if N != 2: + raise ValueError("Only 2D is supported for this implementation.") + + # Create the row indices + row_idx = flex.size_t(chain.from_iterable( + [[i] * dimensions[1] for i in range(dimensions[0])])) + + # Create the column indices + col_idx = flex.size_t(chain.from_iterable( + [list(range(dimensions[1])) for _ in range(dimensions[0])])) + + return row_idx, col_idx + + i_idxs, j_idxs = indices_2d_flex((A.focus()[0], B.focus()[0])) + + r = i_idxs + xi = i_idxs*3 + yi = i_idxs*3 + 1 + zi = i_idxs*3 + 2 + + xa = A.select(xi) + ya = A.select(yi) + za = A.select(zi) + + xj = j_idxs*3 + yj = j_idxs*3 + 1 + zj = j_idxs*3 + 2 + + xb = B.select(xj) + yb = B.select(yj) + zb = B.select(zj) + + d = ((xb - xa)**2 + (yb - ya)**2 + (zb - za)**2)**0.5 + d.reshape(flex.grid((A.focus()[0], B.focus()[0]))) + + return d + +def trilinear_interpolation(voxel_grid, coords, voxel_size=None, offset=None): + """Numpy trilinear interpolation""" + assert voxel_size is not None,( + "Provide voxel size as an array or single value") + + # Apply offset if provided + if offset is not None: + coords = coords - offset + + # Transform coordinates to voxel grid index space + index_coords = coords / voxel_size + + # Split the index_coords array into three arrays: x, y, and z + x, y, z = index_coords.T + + # Truncate to integer values + x0, y0, z0 = np.floor([x, y, z]).astype(int) + x1, y1, z1 = np.ceil([x, y, z]).astype(int) + + # Ensure indices are within grid boundaries + x0, y0, z0 = np.clip([x0, y0, z0], 0, voxel_grid.shape[0]-1) + x1, y1, z1 = np.clip([x1, y1, z1], 0, voxel_grid.shape[0]-1) + + # Compute weights + xd, yd, zd = [arr - arr.astype(int) for arr in [x, y, z]] + + # Interpolate along x + c00 = voxel_grid[x0, y0, z0]*(1-xd) + voxel_grid[x1, y0, z0]*xd + c01 = voxel_grid[x0, y0, z1]*(1-xd) + voxel_grid[x1, y0, z1]*xd + c10 = voxel_grid[x0, y1, z0]*(1-xd) + voxel_grid[x1, y1, z0]*xd + c11 = voxel_grid[x0, y1, z1]*(1-xd) + voxel_grid[x1, y1, z1]*xd + + # Interpolate along y + c0 = c00*(1-yd) + c10*yd + c1 = c01*(1-yd) + c11*yd + + # Interpolate along z + c = c0*(1-zd) + c1*zd + + return c + + +def rowwise_corrcoef(A, B, mask=None): + """Numpy masked array rowwise correlation coefficient""" + assert A.shape == B.shape, ( + f"A and B must have the same shape, got: {A.shape} and {B.shape}") + + if mask is not None: + assert mask.shape == A.shape, "mask must have the same shape as A and B" + A = ma.masked_array(A, mask=np.logical_not(mask)) + B = ma.masked_array(B, mask=np.logical_not(mask)) + + # Calculate means + A_mean = ma.mean(A, axis=1, keepdims=True) + B_mean = ma.mean(B, axis=1, keepdims=True) + + # Subtract means + A_centered = A - A_mean + B_centered = B - B_mean + + # Calculate sum of products + sumprod = ma.sum(A_centered * B_centered, axis=1) + + # Calculate square roots of the sum of squares + sqrt_sos_A = ma.sqrt(ma.sum(A_centered**2, axis=1)) + sqrt_sos_B = ma.sqrt(ma.sum(B_centered**2, axis=1)) + + # Return correlation coefficients + cc = sumprod / (sqrt_sos_A * sqrt_sos_B) + return cc.data + +def starmap_wrapper(task): + """ + A generic wrapper function to call any worker function with specified arguments. + Params: + task (dict): A dictionary containing the 'func', 'args', and 'kwargs' keys. + + Returns: + return: The result of the worker function call. + """ + # Extract the function to call, its args, and kwargs from the task + func = task['func'] + args = task.get('args', ()) + kwargs = task.get('kwargs', {}) + + # Dynamically call the function with args and kwargs + return func(*args, **kwargs) + + +def aggregate_qscore_per_residue(model,qscore_per_atom,window=3): + # assign residue indices to each atom + + model = model.select(model.selection("not element H")) + atoms = model.get_atoms() + res_seqs = [atom.parent().parent().resseq_as_int() for atom in atoms] + chain_ids = [atom.parent().parent().parent().id for atom in atoms] + res_names = ["".join(atom.parent().parent().unique_resnames()) for atom in atoms] + names = [atom.name.strip() for atom in atoms] + df = pd.DataFrame({"resseq":res_seqs, + "chain_id":chain_ids, + "resname":res_names, + "name":names, + "Q-score":qscore_per_atom, + + }) + + # group atoms into residues + df["rg_index"] = df.groupby(["chain_id","resseq","resname"]).ngroup() + + # average qscore by residue + grouped_means = df.groupby(['chain_id',"resseq","resname","rg_index"],as_index=False)['Q-score'].mean() + + # roll over residue means + for chain_id,group in grouped_means.groupby("chain_id"): + grouped_means.loc[group.index, "Q-scorePerResidue"] = variable_neighbors_rolling_mean(group["Q-score"],window).values + + + # now grouped means is a df with each row being a "residue" "QscoreRollingMean" is the per-residue value to match mapq + + # place back in atom df + df = df.merge(grouped_means[['rg_index', 'Q-scorePerResidue']], on='rg_index', how='left') + df.drop("rg_index",axis=1,inplace=True) + return df + +def variable_neighbors_rolling_mean(series, window=3): + """ + Aggregate per-atom qscore to per-residue in the same + manner as the original mapq program + """ + # Container for the rolling means + rolling_means = [] + + # Calculate rolling mean for each index + for i in range(len(series)): + # Determine the start and end indices of the window + start_idx = max(0, i - window) + end_idx = min(len(series), i + window + 1) + + # Calculate mean for the current window + window_mean = series.iloc[start_idx:end_idx].mean() + rolling_means.append(window_mean) + + return pd.Series(rolling_means) + + +def write_bild_spheres(xyz,filename="sphere.bild",r=0.5): + """ + Write a chimerax .bild file with spheres + + Params: + xyz (np.array): Cartesian coordinates (N,3) + filename (str): The filename for the .bild file + r (float): sphere radius + """ + out = "" + for x,y,z in xyz: + s = f".sphere {x} {y} {z} {r}\n" + out+=s + + with open(filename,"w") as fh: + fh.write(out) + + + +def cctbx_atoms_to_df(atoms): + """ + Build a pandas dataframe from a cctbx shared atoms object + + Params: + atoms (iotbx_pdb_hierarchy_ext.af_shared_atom): The atom array + + Returns: + df_atoms (pd.DataFrame): A pandas dataframe with the core data present + """ + # Define values composition + func_mapper = { + #"model_id", # model + "id":lambda atom: atom.i_seq, + "Chain":lambda atom: atom.parent().parent().parent().id, + "Resseq":lambda atom: atom.parent().parent().resseq_as_int(), + "Resname":lambda atom: atom.parent().parent().unique_resnames()[0], + "Name":lambda atom: atom.name.strip(), + "Element":lambda atom: atom.element, + "Alt Loc": lambda atom: atom.parent().altloc + } + + # Build as dictionaries + data = defaultdict(list) + for atom in atoms: + for key,func in func_mapper.items(): + data[key].append(func(atom)) + + + # Include values non-composition + xyz = atoms.extract_xyz().as_numpy_array() + data["x"] = xyz[:,0] + data["y"] = xyz[:,1] + data["z"] = xyz[:,2] + + # Build dataframe from dictionaries + df_atoms = pd.DataFrame(data,index=list(range(len(atoms)))) + + return df_atoms +>>>>>>> Stashed changes diff --git a/cctbx/maptbx/tst_qscore.py b/cctbx/maptbx/tst_qscore.py index 215c671206..96d9f050a6 100644 --- a/cctbx/maptbx/tst_qscore.py +++ b/cctbx/maptbx/tst_qscore.py @@ -1,18 +1,28 @@ from __future__ import absolute_import, division, print_function import os +<<<<<<< Updated upstream +from cctbx.array_family import flex +import libtbx +from libtbx import group_args +from libtbx.utils import null_out +from iotbx.cli_parser import run_program +import numpy as np +from scipy.spatial import KDTree + + + + ] +======= import copy -import subprocess import shutil from pathlib import Path -import json -import argparse from iotbx.data_manager import DataManager from cctbx.array_family import flex import libtbx -from libtbx import group_args +from cctbx.maptbx.box import shift_and_box_model +from iotbx.map_model_manager import map_model_manager from libtbx.utils import null_out -from iotbx.cli_parser import run_program import numpy as np from scipy.spatial import KDTree @@ -20,15 +30,238 @@ from cctbx.maptbx.qscore import ( generate_probes_np, - SpherePtsVectorized, get_probe_mask, - get_probes, shell_probes_progressive, shell_probes_precalculate, - _shell_probes_progressive_wrapper, - _shell_probes_precalculate_wrapper + shell_probes_precalculate_flex, + calc_qscore, + calc_qscore_flex + ) -from cctbx.programs.qscore import Program as QscoreProgram + +def isclose_or_nan(a, b, atol=1e-3): + # perform isclose comparison, treating nans as equal + return np.isclose(a, b, atol=atol) | (np.isnan(a) & np.isnan(b)) + + +################################################################################ +#### Test probe generation +################################################################################ + +def test_probe_generation(): + # test the primary points generation function against expected data + atoms_xyz = np.array([[ 5.276, 12.488, 16.069], + [ 5.649, 13.947, 16.076]]) + + probes_expected = np.array([[ + [ 5.276 , 12.488 , 15.969 ], + [ 5.2588, 12.5558, 15.9976], + [ 5.186 , 12.4803, 16.0261], + [ 5.2564, 12.391 , 16.0547], + [ 5.3636, 12.442 , 16.0833], + [ 5.3304, 12.5601, 16.1119], + [ 5.2115, 12.5151, 16.1404], + [ 5.276 , 12.488 , 16.169 ]], + + [[ 5.649 , 13.947 , 15.976 ], + [ 5.6318, 14.0148, 16.0046], + [ 5.559 , 13.9393, 16.0331], + [ 5.6294, 13.85 , 16.0617], + [ 5.7366, 13.901 , 16.0903], + [ 5.7034, 14.0191, 16.1189], + [ 5.5845, 13.9741, 16.1474], + [ 5.649 , 13.947 , 16.176 ]]]) + + probes_xyz = generate_probes_np(atoms_xyz,0.1,8) + assert np.all(np.isclose(probes_xyz,probes_expected,atol=1e-3)) + +def test_probe_masking(): + # test the progressive probe masking function against test data + atoms_xyz = np.array([ + [0,0,-1], + [0,0,1], + ]) + + # probes_xyz shape (2,4,3), (n_atoms,n_probes,3) + probes_xyz = np.array([ + [[0,0,-2], + [0,0,-0.5], + [0,0,0], + [0,0,0.5]], + + [[0,0,-2], + [0,0,-0.5], + [0,0,0], + [0,0,0.5]]]) + + atom_tree = KDTree(atoms_xyz) + + calculated_result = get_probe_mask(atom_tree,probes_xyz,r=1.4) + manual_result = np.array([[ True, True, False, False], + [False, False, False, True]]) + + + assert np.all(calculated_result==manual_result) + + + +def test_shell_probes(): + # Test full progressive probe generation for a single shell + atoms_xyz = np.array([[ 5.276, 12.488, 16.069], + [ 5.649, 13.947, 16.076]]) + + # Test progressive + + expected_probes = np.array([[[ 5.276 , 12.488 , 14.569 ], + [ 5.0515, 13.4037, 14.9023], + [ 4.0297, 12.4397, 15.2357], + [ 4.825 , 11.1476, 15.569 ], + [ 6.3669, 11.4721, 15.9023], + [ 4.0466, 12.6981, 16.9023], + [ 5.343 , 11.5476, 17.2357], + [ 5.276 , 12.488 , 17.569 ], + [ np.nan, np.nan, np.nan], + [ np.nan, np.nan, np.nan]], + + [[ 5.649 , 13.947 , 14.576 ], + [ 5.4245, 14.8627, 14.9093], + [ 4.4027, 13.8987, 15.2427], + [ 6.7399, 12.9311, 15.9093], + [ 7.0245, 14.5216, 16.2427], + [ 5.6032, 15.3605, 16.576 ], + [ 4.4196, 14.1571, 16.9093], + [ 5.716 , 13.0066, 17.2427], + [ 5.649 , 13.947 , 17.576 ], + [ np.nan, np.nan, np.nan]]]) + shell_func = shell_probes_progressive + probe_xyz, probe_mask = shell_func( + atoms_xyz=atoms_xyz, + atoms_tree = None, + selection_bool=None, + n_probes_target=8, + n_probes_max=10, + RAD=1.5, + rtol=0.9, + log = null_out()) + assert np.all(isclose_or_nan(probe_xyz,expected_probes,atol=1e-3)) + + # test precalculate (numpy) + + expected_probes = np.array( + + [[[5.2760, 12.4880, 14.5690], + [5.0515, 13.4037, 14.9023], + [4.0297, 12.4397, 15.2357], + [4.8250, 11.1476, 15.5690], + [6.3669, 11.4721, 15.9023], + [6.6515, 13.0626, 16.2357], + [5.2302, 13.9015, 16.5690], + [4.0466, 12.6981, 16.9023], + [5.3430, 11.5476, 17.2357], + [5.2760, 12.4880, 17.5690]], + + [[5.6490, 13.9470, 14.5760], + [5.4245, 14.8627, 14.9093], + [4.4027, 13.8987, 15.2427], + [5.1980, 12.6066, 15.5760], + [6.7399, 12.9311, 15.9093], + [7.0245, 14.5216, 16.2427], + [5.6032, 15.3605, 16.5760], + [4.4196, 14.1571, 16.9093], + [5.7160, 13.0066, 17.2427], + [5.6490, 13.9470, 17.5760]]]) + + shell_func = shell_probes_precalculate + probe_xyz, probe_mask = shell_func( + atoms_xyz=atoms_xyz, + atoms_tree = None, + selection_bool=None, + n_probes_target=8, + n_probes_max=10, + RAD=1.5, + rtol=0.9, + log = null_out()) + + assert np.all(isclose_or_nan(probe_xyz,expected_probes,atol=1e-3)) + + # test precalculate (flex) + shell_func = shell_probes_precalculate_flex + probe_xyz,probe_mask = shell_func( + atoms_xyz=flex.vec3_double(atoms_xyz), + atoms_tree = None, + selection_bool=None, + n_probes_target=8, + n_probes_max=10, + RAD=1.5, + rtol=0.9, + log = null_out()) + + # test at single shell + probe_xyz = np.array(probe_xyz) + probe_xyz = probe_xyz.reshape(expected_probes.shape) + assert np.all(isclose_or_nan(probe_xyz,expected_probes,atol=1e-3)) + + +################################################################################ +#### Test templates for real data +################################################################################ + +def convert_dict_to_group_args(d): + # Recursive conversion of nested dictionary to nested group_args + def convert_func(d): + if isinstance(d, dict): + converted_items = {k: convert_func(v) for k, v in d.items()} + return libtbx.group_args(**converted_items) + else: + return d + + return convert_func(d) + +def convert_group_args_to_dict(g): + # Recursive conversion of nested group args to nested dictionary + def convert_func(g): + if isinstance(g, libtbx.group_args): + converted_items = {k: convert_func(v) for k, v in g.__dict__.items() if not k.startswith('_')} + return converted_items + else: + return g + + return convert_func(g) + + +# a template to store configuration for a single test +test_template ={ + + "data":{ + "name":None, + "model_str":None, + "model_file":None, + "map_file":None, + "test_dir":None, + }, + "results":{ + "expected":{}, + "calc":{}, + }, + "params":{ + "selection_str":None, # Just calculate q score for a sub-selection + "iselection":None, + "shells": [0.0,0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1., + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. ], + "n_probes_target":8, + "n_probes_max":16, + "n_probes_min":4, + "nproc":4, + "probe_allocation_method":None, + "backend":None, + "debug":True, + "rtol":0.9, + } +>>>>>>> Stashed changes +} +# make flex arrays +expected_results = {key: flex.double(val) + for key, val in list(expected_results.items())} @@ -452,189 +685,377 @@ def run_template(template,mapq_location=None): } } +<<<<<<< Updated upstream if (__name__ == "__main__"): - parser = argparse.ArgumentParser(description="Run qscore tests") - - # Figure out if using mapq - parser.add_argument('--mapq_location', - type=str, - help='Compare to mapq results. Example: /Users/user/Desktop/Chimera.app/Contents/Resources/share/mapq') - args = parser.parse_args() - mapq_location = args.mapq_location - if mapq_location is None: - mapq = False + """ + Test random files to verify basic functionality remains unchanged + Data from phenix_regression/real_space_refine/data + """ + for test_name in [17]: # [17,42,48]: + exercise(test_name) + print("OK") +======= +def run_test(test): + + if isinstance(test,dict): + test = convert_dict_to_group_args(test) + + print() + print("#"*79) + print("Running test "+test.data.name) + print("\tModel File:",test.data.model_file) + print("\tMap:",test.data.map_file) + if test.data.model_str is not None: + print("\tModel Str:\n",test.data.map_file) + + dm = DataManager() + assert [test.data.model_file,test.data.model_str].count(None)==1 + if test.data.model_file is not None: + dm.process_model_file(test.data.model_file) + elif test.data.model_str is not None: + dm.process_model_str(test.data.name,test.data.model_str) + + # get model + model = dm.get_model() + + # rebox as p1 + #model = shift_and_box_model(model) + + + # get data from file or calculated + if test.data.map_file is not None: + dm.process_real_map_file(test.data.map_file) + mm = dm.get_real_map() + mmm = map_model_manager(model=model,map_manager=mm) else: - mapq = True - - - # Start tests... + mmm = map_model_manager(model=model) + mmm.generate_map(d_min=2) - #1. test probe generation - test_probe_generation() - - #2. test probe masking (for progressive) - test_probe_masking() + params = test.params + if params.backend == "numpy": + q_func = calc_qscore + elif params.backend == "flex": + q_func = calc_qscore_flex - #3. test single shell probe generation - test_shell_probes(probe_allocation_method="progressive") - test_shell_probes(probe_allocation_method="precalculate") + result = q_func(mmm,params,log=null_out(),debug=True) + test.results.calc = convert_dict_to_group_args(result) + for key,value_expected in test.results.expected.__dict__.items(): + value_calc= np.array(test.results.calc.__dict__[key]) + assert np.all(isclose_or_nan(value_expected,value_calc)), ( +f"Failed test: {test.data.name}\nExpected:\n{value_expected}\nCalc:\n{value_calc}") + print("Done.\n") + return convert_group_args_to_dict(test) - #4. test multi-shell probe generation - test_get_probes(probe_allocation_method="progressive") - test_get_probes(probe_allocation_method="precalculate") +################################################################################ +#### Define and run tests +################################################################################ +def build_tests(test_dir="qscore_tst_dir"): - #5. test some real files - templates = [] + # make test dir + test_dir = Path("qscore_tst_dir") + if test_dir.exists(): + shutil.rmtree(test_dir) + test_dir.mkdir() - def get_base_map_model(test_name): - # model - pdb_file_repo = libtbx.env.find_in_repositories( - relative_path=f"phenix_regression/real_space_refine/data/tst_{test_name}.pdb", - test=os.path.isfile) + tests = {} - # map - map_file_repo = libtbx.env.find_in_repositories( - relative_path=f"phenix_regression/real_space_refine/data/tst_{test_name}.ccp4", - test=os.path.isfile) - return pdb_file_repo,map_file_repo - # Do some small fragments (progressive) - base_model_name, base_map_name = get_base_map_model(17) - test_name = Path(base_model_name).stem + #4. map/model from regression dir (tst2) numpy/precalculate + test = copy.deepcopy(test_template) + tst2_model_file = libtbx.env.find_in_repositories( + relative_path=\ + f"cctbx_project/iotbx/regression/data/non_zero_origin_model_split.pdb", + test=os.path.isfile) + tst2_map_file = libtbx.env.find_in_repositories( + relative_path=\ + f"cctbx_project/iotbx/regression/data/non_zero_origin_map.ccp4", + test=os.path.isfile) + test["data"]["model_file"] = tst2_model_file + test["data"]["map_file"] = tst2_map_file + test["data"]["name"] = "tst2_precalc_numpy" + test["data"]["test_dir"] = test_dir + test["params"]["n_probes_max"] = 32 + test["params"]["probe_allocation_method"] = "precalculate" + test["params"]["backend"] = "numpy" + expected_qscore_per_atom= np.array([ + 0.79852, 0.80609, 0.80133, 0.72103, 0.75883, 0.81456, 0.82049, + 0.77932, 0.77675, 0.78246, 0.84899, 0.71687, 0.77178, 0.82013, + 0.82884, 0.82516, 0.88237, 0.79658, 0.84557, 0.80930, 0.78813, + 0.80125, 0.66020, 0.77447, 0.82493, 0.80411, 0.81775, 0.75656, + 0.79463, 0.84372, 0.66545, 0.78583, 0.80262, 0.88354, 0.80967, + 0.83346, 0.70284, 0.83037, 0.79684, 0.69537, 0.74061, 0.79931, + 0.88578, 0.86837, 0.79809, 0.70589, 0.76989, 0.82633, 0.60241, + 0.77312, 0.67250, 0.79516, 0.78177, 0.72057, 0.77841, 0.84436, + 0.81322, 0.77128, 0.79111, 0.83423, 0.82586, 0.81274, 0.70658, + 0.76125, 0.83175, 0.76124, 0.78605, 0.83369, 0.76933, 0.81073, + 0.67650, 0.73330, 0.83762, 0.76627, 0.77703, 0.77652, 0.78147, + 0.85242, 0.70684, 0.81237, 0.80886, 0.87575, 0.74811, 0.74911, + 0.87672, 0.76362, + ]) + test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom + tests[test["data"]["name"]] = test - # 1 atom fragment + #tst2 flex precalculate test = copy.deepcopy(test_template) - test["data"]["name"] = f"{test_name}_0" - test["data"]["model_file_base"] = base_model_name - test["data"]["map_file_base"] = base_map_name - test["data"]["fragment_iselection"] = [0] - templates.append(test) + test["data"]["model_file"] = tst2_model_file + test["data"]["map_file"] = tst2_map_file + test["data"]["name"] = "tst2_precalc_flex" + test["data"]["test_dir"] = test_dir + test["params"]["n_probes_max"] = 32 + test["params"]["probe_allocation_method"] = "precalculate" + test["params"]["backend"] = "flex" + test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom + tests[test["data"]["name"]] = test - # 2 atom fragment + # tst2 progressive (numpy) test = copy.deepcopy(test_template) - test["data"]["name"] = f"{test_name}_0-1" - test["data"]["model_file_base"] = base_model_name - test["data"]["map_file_base"] = base_map_name - test["data"]["fragment_iselection"] = [0,1] - templates.append(test) + test["data"]["model_file"] = tst2_model_file + test["data"]["map_file"] = tst2_map_file + test["data"]["name"] = "tst2_progressive_numpy" + test["data"]["test_dir"] = test_dir + test["params"]["n_probes_max"] = 16 + test["params"]["n_probes_target"] = 8 + test["params"]["probe_allocation_method"] = "progressive" + test["params"]["backend"] = "numpy" + expected_qscore_per_atom= np.array([ + 0.81621, 0.79426, 0.83739, 0.67616, 0.75113, 0.81278, 0.75789, + 0.75623, 0.77865, 0.80018, 0.83847, 0.67525, 0.78909, 0.81843, + 0.81285, 0.80816, 0.89982, 0.73878, 0.81402, 0.79254, 0.81353, + 0.81543, 0.64347, 0.75470, 0.84479, 0.80404, 0.77552, 0.75578, + 0.80234, 0.84508, 0.66298, 0.76894, 0.76924, 0.90342, 0.78303, + 0.79723, 0.73253, 0.83709, 0.84759, 0.60567, 0.75056, 0.77734, + 0.89625, 0.85381, 0.74985, 0.69442, 0.80130, 0.82290, 0.57231, + 0.70518, 0.72775, 0.83440, 0.82770, 0.73152, 0.76289, 0.84503, + 0.79984, 0.75651, 0.79504, 0.82964, 0.83653, 0.83177, 0.68769, + 0.79369, 0.83867, 0.67165, 0.78174, 0.85420, 0.73200, 0.82028, + 0.73856, 0.79636, 0.83043, 0.69672, 0.79881, 0.75317, 0.78247, + 0.83621, 0.74694, 0.81975, 0.79633, 0.87402, 0.74882, 0.72080, + 0.87380, 0.74778, + ]) + test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom + tests[test["data"]["name"]] = test - # 3 atom fragment + #5. 1yjp with simulated density + # precalculated with numpy test = copy.deepcopy(test_template) - test["data"]["name"] = f"{test_name}_0-2" - test["data"]["model_file_base"] = base_model_name - test["data"]["map_file_base"] = base_map_name - test["data"]["fragment_iselection"] = [0,1,2] - templates.append(test) + yjp_model_file = libtbx.env.find_in_repositories( + relative_path=\ + f"cctbx_project/iotbx/regression/data/1yjp.pdb", + test=os.path.isfile) + test["data"]["model_file"] = yjp_model_file + test["data"]["name"] = "1yjp_precalc_numpy" + test["data"]["test_dir"] = test_dir + test["data"]["map_file"] = None + test["params"]["n_probes_max"] = 32 + test["params"]["probe_allocation_method"] = "precalculate" + test["params"]["backend"] = "numpy" + expected_qscore_per_atom= np.array([ + 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + -0.10505, 0.03062, 0.00000, 0.67700, 0.95088, 0.94763, 0.75051, + 0.89511, 0.87489, 0.97221, 0.91645, 0.91834, 0.13628, 0.22108, + 0.09771, 0.94044, 0.87528, 0.92334, 0.95104, 0.92881, 0.91000, + 0.88136, 0.97055, 0.95707, 0.93397, 0.86285, 0.87010, 0.97105, + 0.90625, 0.88578, 0.96754, 0.96147, 0.93298, 0.86254, 0.89024, + 0.95584, 0.90034, 0.91163, 0.62957, 0.91963, 0.23041, 0.91662, + 0.89745, 0.95870, 0.94299, 0.00000, 0.97742, 0.00000, 0.95322, + 0.96996, 0.89275, 0.91926, + ]) + test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom + tests[test["data"]["name"]] = test - # 4 atom fragment + + # precalcualted with flex test = copy.deepcopy(test_template) - test["data"]["name"] = f"{test_name}_0-3" - test["data"]["model_file_base"] = base_model_name - test["data"]["map_file_base"] = base_map_name - test["data"]["fragment_iselection"] = [0,1,2,3] - templates.append(test) - - # full molecules - - # 17 - # progressive - base_model_name, base_map_name = get_base_map_model(17) - test_name = Path(base_model_name).stem + test["data"]["model_file"] = yjp_model_file + test["data"]["name"] = "1yjp_precalc_flex" + test["data"]["test_dir"] = test_dir + test["data"]["map_file"] = None + test["params"]["n_probes_max"] = 32 + test["params"]["probe_allocation_method"] = "precalculate" + test["params"]["backend"] = "flex" + test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom + tests[test["data"]["name"]] = test + + # progressive (numpy) test = copy.deepcopy(test_template) - test["data"]["name"] = test_name+"_progressive" - test["data"]["model_file_base"] = base_model_name - test["data"]["map_file_base"] = base_map_name + test["data"]["model_file"] = yjp_model_file + test["data"]["name"] = "1yjp_progressive_numpy" + test["data"]["test_dir"] = test_dir + test["data"]["map_file"] = None + test["params"]["n_probes_max"] = 16 + test["params"]["n_probes_target"] = 8 test["params"]["probe_allocation_method"] = "progressive" - test["results"]["q_sum_expected"] = 85.74585520218474 - test["results"]["probe_sum_expected"] = 7033351.9964000005 - templates.append(test) - - # precalculate + test["params"]["backend"] = "numpy" + expected_qscore_per_atom= np.array([ + 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, + 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.07689, + 0.19082, 0.02124, 0.00000, 0.74434, 0.93599, 0.93209, 0.77202, + 0.91962, 0.91928, 0.96171, 0.91251, 0.91642, 0.36156, 0.31734, + 0.00000, 0.94018, 0.90381, 0.93852, 0.94966, 0.93188, 0.91575, + 0.91731, 0.97200, 0.95272, 0.94102, 0.89297, 0.91385, 0.96626, + 0.89274, 0.91538, 0.96871, 0.96205, 0.93226, 0.89114, 0.92745, + 0.94155, 0.90361, 0.92891, 0.74236, 0.92431, 0.28466, 0.91468, + 0.93081, 0.96238, 0.93960, 0.00000, 0.97779, 0.00000, 0.94679, + 0.97174, 0.89276, 0.90919, + ]) + test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom + tests[test["data"]["name"]] = test + + #6. 1yjp with simulated density and shift and box + dm = DataManager() + dm.process_model_file(yjp_model_file) + model = dm.get_model() + model = shift_and_box_model(model) + boxed_1yjp_path = Path(test_dir,"1yjp_boxed.pdb") + dm.write_model_file(model.model_as_pdb(),filename=str(boxed_1yjp_path),overwrite=True) + + # precalculated with numpy test = copy.deepcopy(test_template) - test["data"]["name"] = test_name+"_precalc" - test["data"]["model_file_base"] = base_model_name - test["data"]["map_file_base"] = base_map_name - test["params"]["n_probes_max"] = 128 + test["data"]["name"] = "1yjp_boxed_precalc_numpy" + test["data"]["test_dir"] = test_dir + #test["data"]["model_file"] = str(boxed_1yjp_path) + test["data"]["model_str"] = model.model_as_pdb() + test["data"]["map_file"] = None + test["params"]["n_probes_max"] = 32 test["params"]["probe_allocation_method"] = "precalculate" - test["results"]["q_sum_expected"] = 87.87610388144196 - test["results"]["probe_sum_expected"] = 108903540.12935309 - templates.append(test) - - # 42 - # progressive - base_model_name, base_map_name = get_base_map_model(42) - test_name = Path(base_model_name).stem - test = copy.deepcopy(test_template) - test["data"]["name"] = test_name+"_progressive" - test["data"]["model_file_base"] = base_model_name - test["data"]["map_file_base"] = base_map_name - test["results"]["q_sum_expected"] = 65.18062030153557 - test["results"]["probe_sum_expected"] = 479151.29789999995 - templates.append(test) - - # precalculate + test["params"]["backend"] = "numpy" + expected_qscore_per_atom = np.array([ + 0.96035, 0.91590, 0.92283, 0.96654, 0.94164, 0.89421, 0.91464, + 0.97026, 0.91649, 0.91408, 0.97073, 0.95491, 0.94386, 0.88791, + 0.90950, 0.97556, 0.92062, 0.92067, 0.96957, 0.95537, 0.94550, + 0.87780, 0.89461, 0.97148, 0.93788, 0.92123, 0.90062, 0.96383, + 0.96746, 0.94327, 0.88461, 0.90352, 0.97037, 0.93105, 0.92621, + 0.90266, 0.96954, 0.96153, 0.94760, 0.86363, 0.88383, 0.96882, + 0.92100, 0.91835, 0.96474, 0.95877, 0.92953, 0.88268, 0.89251, + 0.95668, 0.91766, 0.91907, 0.92488, 0.92805, 0.93958, 0.93576, + 0.90368, 0.96675, 0.95459, 0.97762, 0.97334, 0.98168, 0.97580, + 0.97306, 0.96717, 0.96175, + ]) + test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom + tests[test["data"]["name"]] = test + + # precalculated with flex test = copy.deepcopy(test_template) - test["data"]["name"] = test_name+"_precalc" - test["data"]["model_file_base"] = base_model_name - test["data"]["map_file_base"] = base_map_name - test["params"]["n_probes_max"] = 128 + test["data"]["model_file"] = str(boxed_1yjp_path) + test["data"]["name"] = "1yjp_boxed_precalc_flex" + test["data"]["test_dir"] = test_dir + test["data"]["map_file"] = None + test["params"]["n_probes_max"] = 32 test["params"]["probe_allocation_method"] = "precalculate" - test["results"]["q_sum_expected"] = 65.98930853051141 - test["results"]["probe_sum_expected"] = 7393520.8060661685 - templates.append(test) - - # 48 - # progressive - base_model_name, base_map_name = get_base_map_model(48) - test_name = Path(base_model_name).stem + test["params"]["backend"] = "flex" + test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom + tests[test["data"]["name"]] = test + + #7 tst2 with shift_and_box (numpy,precalculate) + + tst2_model_file = libtbx.env.find_in_repositories( + relative_path=\ + f"cctbx_project/iotbx/regression/data/non_zero_origin_model_split.pdb", + test=os.path.isfile) + tst2_map_file = libtbx.env.find_in_repositories( + relative_path=\ + f"cctbx_project/iotbx/regression/data/non_zero_origin_map.ccp4", + test=os.path.isfile) + + dm = DataManager() + dm.process_model_file(tst2_model_file) + model = dm.get_model() + #model = shift_and_box_model(model) + boxed_tst2_path = Path(test_dir,"tst2_boxed.pdb") + dm.write_model_file(model.model_as_pdb(),filename=str(boxed_tst2_path),overwrite=True) + test = copy.deepcopy(test_template) - test["data"]["name"] = test_name+"_progressive" - test["data"]["model_file_base"] = base_model_name - test["data"]["map_file_base"] = base_map_name - test["results"]["q_sum_expected"] = 74.57025665508365 - test["results"]["probe_sum_expected"] = 904759.264 - templates.append(test) - - # precalculate + test["data"]["model_file"] = str(boxed_tst2_path) + test["data"]["map_file"] = tst2_map_file + test["data"]["name"] = "tst2_boxed_precalc_numpy" + test["data"]["test_dir"] = test_dir + test["params"]["n_probes_max"] = 32 + test["params"]["probe_allocation_method"] = "precalculate" + test["params"]["backend"] = "numpy" + expected_qscore_per_atom = np.array([ + 0.79852, 0.80609, 0.80133, 0.72103, 0.75883, 0.81456, 0.82049, + 0.77932, 0.77675, 0.78246, 0.84899, 0.71687, 0.77178, 0.82013, + 0.82884, 0.82516, 0.88237, 0.79658, 0.84557, 0.80930, 0.78813, + 0.80125, 0.66020, 0.77447, 0.82493, 0.80411, 0.81775, 0.75656, + 0.79463, 0.84372, 0.66545, 0.78583, 0.80262, 0.88354, 0.80967, + 0.83346, 0.70284, 0.83037, 0.79684, 0.69537, 0.74061, 0.79931, + 0.88578, 0.86837, 0.79809, 0.70589, 0.76989, 0.82633, 0.60241, + 0.77312, 0.67250, 0.79516, 0.78177, 0.72057, 0.77841, 0.84436, + 0.81322, 0.77128, 0.79111, 0.83423, 0.82586, 0.81274, 0.70658, + 0.76125, 0.83175, 0.76124, 0.78605, 0.83369, 0.76933, 0.81073, + 0.67650, 0.73330, 0.83762, 0.76627, 0.77703, 0.77652, 0.78147, + 0.85242, 0.70684, 0.81237, 0.80886, 0.87575, 0.74811, 0.74911, + 0.87672, 0.76362, + ]) + test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom + tests[test["data"]["name"]] = test + + # tst2, shift_and_box, precalculate, flex test = copy.deepcopy(test_template) - test["data"]["name"] = test_name+"_precalc" - test["data"]["model_file_base"] = base_model_name - test["data"]["map_file_base"] = base_map_name - test["params"]["n_probes_max"] = 128 + test["data"]["model_file"] = str(boxed_tst2_path) + test["data"]["map_file"] = tst2_map_file + test["data"]["name"] = "tst2_boxed_precalc_flex" + test["data"]["test_dir"] = test_dir + test["params"]["n_probes_max"] = 32 test["params"]["probe_allocation_method"] = "precalculate" - test["results"]["q_sum_expected"] = 75.99978032145603 - test["results"]["probe_sum_expected"] = 13979341.58057615 - templates.append(test) - - # prepare files - templates = prepare_test_data(templates) - - # run templates - templates = [run_template(template,mapq_location=mapq_location) for template in templates] - - - # Compare progressive and precalculate - for template in templates: - name = template["data"]["name"] - for other_template in templates: - other_name = other_template["data"]["name"] - - if "progressive" in name: - if name.strip("progressive") == other_name.strip("precalc"): - debug_data_cctbx = template["results"]["cctbx"] - debug_data_cctbx_mp = other_template["results"]["cctbx"] - probe_xyz = debug_data_cctbx["probe_xyz"] - probe_xyz_mp = debug_data_cctbx_mp["probe_xyz"] - qscore_per_atom = debug_data_cctbx["qscore_per_atom"] - qscore_per_atom_mp = debug_data_cctbx_mp["qscore_per_atom"] - - rmsd = np.sqrt(np.mean((qscore_per_atom-qscore_per_atom_mp) ** 2)) - cc = np.corrcoef(qscore_per_atom, qscore_per_atom_mp)[0][1] - print(template["data"]["name"],"rmsd",rmsd) - print(template["data"]["name"],"CC",cc) - assert rmsd<0.1, rmsd - assert cc>0.9, cc - - print("OK") + test["params"]["backend"] = "flex" + test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom + tests[test["data"]["name"]] = test + + # tst2, shift_and_box, progressive, numpy + test = copy.deepcopy(test_template) + test["data"]["model_file"] = str(boxed_tst2_path) + test["data"]["map_file"] = tst2_map_file + test["data"]["name"] = "tst2_boxed_progressive_numpy" + test["data"]["test_dir"] = test_dir + test["params"]["n_probes_max"] = 16 + test["params"]["n_probes_target"] = 8 + test["params"]["probe_allocation_method"] = "progressive" + test["params"]["backend"] = "numpy" + expected_qscore_per_atom = np.array([ + 0.81621, 0.79426, 0.83739, 0.67616, 0.75113, 0.81278, 0.75789, + 0.75623, 0.77865, 0.80018, 0.83847, 0.67525, 0.78909, 0.81843, + 0.81285, 0.80816, 0.89982, 0.73878, 0.81402, 0.79254, 0.81353, + 0.81543, 0.64347, 0.75470, 0.84479, 0.80404, 0.77552, 0.75578, + 0.80234, 0.84508, 0.66298, 0.76894, 0.76924, 0.90342, 0.78303, + 0.79723, 0.73253, 0.83709, 0.84759, 0.60567, 0.75056, 0.77734, + 0.89625, 0.85381, 0.74985, 0.69442, 0.80130, 0.82290, 0.57231, + 0.70518, 0.72775, 0.83440, 0.82770, 0.73152, 0.76289, 0.84503, + 0.79984, 0.75651, 0.79504, 0.82964, 0.83653, 0.83177, 0.68769, + 0.79369, 0.83867, 0.67165, 0.78174, 0.85420, 0.73200, 0.82028, + 0.73856, 0.79636, 0.83043, 0.69672, 0.79881, 0.75317, 0.78247, + 0.83621, 0.74694, 0.81975, 0.79633, 0.87402, 0.74882, 0.72080, + 0.87380, 0.74778, + + ]) + test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom + tests[test["data"]["name"]] = test + + + return tests + + + + +if (__name__ == "__main__"): + + + #1. test probe generation + test_probe_generation() + + #2. test probe masking (for progressive) + test_probe_masking() + + #3. test single shell probe generation + test_shell_probes() + + + + # Test on some real models + tests = build_tests() + for test_name,test in tests.items(): + test = run_test(test) +>>>>>>> Stashed changes diff --git a/cctbx/programs/qscore.py b/cctbx/programs/qscore.py index a8af6f5956..79a09b6f48 100644 --- a/cctbx/programs/qscore.py +++ b/cctbx/programs/qscore.py @@ -1,30 +1,93 @@ from __future__ import absolute_import, division, print_function +<<<<<<< Updated upstream +from phenix.program_template import ProgramTemplate +from libtbx import group_args +from cctbx.maptbx.qscore import qscore_np + +======= + +import json +from pathlib import Path + from libtbx.program_template import ProgramTemplate from libtbx import group_args -from iotbx.pdb import input as pdb_input -from mmtbx.model import manager as model_manager -from iotbx.map_manager import map_manager -from iotbx.map_model_manager import map_model_manager -from cctbx.maptbx import qscore +from cctbx.maptbx.qscore import ( + calc_qscore, + calc_qscore_flex, + cctbx_atoms_to_df, + write_bild_spheres +) +>>>>>>> Stashed changes import numpy as np # ============================================================================= class Program(ProgramTemplate): - description = """ + description = """ Perform a Qscore analysis for map-model fit """ - datatypes = ['phil', 'model', 'real_map'] + datatypes = ['phil', 'model', 'real_map'] +<<<<<<< Updated upstream master_phil_str = """ - include scope cctbx.maptbx.qscore.master_phil_str - """ + nproc = 8 + .type = int + .help = Number of processors to use + .short_caption = Number of processors to use + .expert_level = 1 + n_probes = 32 + .type = int + .help = Number of radial probes to use + .short_caption = Number of radial probes to use + .expert_level = 1 + selection = None + .type = str + .help = Only test atoms within this selection + .short_caption = Only test atoms within this selection + .expert_level = 1 + + shell_radius_start = 0.1 + .type = float + .help = Start testing density at this radius from atom + .short_caption = Start testing density at this radius from atom + .expert_level = 1 + + shell_radius_stop = 2 + .type = float + .help = Stop testing density at this radius from atom + .short_caption = Stop testing density at this radius from atom + .expert_level = 1 + + shell_radius_num = 20 + .type = int + .help = The number of radial shells + .short_caption = The number of radial shells (includes start/stop, so minimum 2) + .expert_level = 1 + + probe_allocation_method = precalculate + .type = str + .help = The method used to allocate radial probes + .short_caption = Either 'progressive' or 'precalculate'. Progressive is the original method \ + where probes are proposed and rejected iteratively. \ + Precalculate is a method where probes are pre-allocated and \ + rejected once. Parallelization is done by radial shell. \ + Precalculate is much faster but will yield slightly different results. + + +======= + master_phil_str = """ + include scope cctbx.maptbx.qscore.master_phil_str +>>>>>>> Stashed changes + """ - def validate(self): - pass + def validate(self): + assert self.params.qscore.backend in [ + "numpy","flex" + ], "Provide one of 'numpy', 'flex'" +<<<<<<< Updated upstream def run(self): print("Running") @@ -75,31 +138,84 @@ def run(self): def get_results(self): return self.result - - - def _unsort_model(self,model): - - # A very hacky way to get a model with atoms unsorted. Only works for pdb - # TODO: Need to add sort kwarg to data_manager.process_model_file somehow - model_input = model.get_model_input() - if 'cif' not in str(model_input.__class__): - h = pdb_input(source_info=None,lines=model_input.as_pdb_string()).construct_hierarchy(sort_atoms=False) - atom_name_list = [s.strip() for s in h.atoms().extract_name()] - scatterer_list = [s.strip() for s in h.atoms().extract_element()] - - model = model_manager.from_sites_cart(h.atoms().extract_xyz(), - crystal_symmetry=model.crystal_symmetry(), - atom_name_list = atom_name_list, - scatterer_list=scatterer_list - ) - return model - - @staticmethod - def _mmm_from_model_and_map(model,map): - map_data = map.map_data() - mm = map_manager(map_data=map_data, - unit_cell_grid=map_data.accessor().all(), - unit_cell_crystal_symmetry=model.unit_cell_crystal_symmetry(), - wrapping=False) - mmm = map_model_manager(model=model,map_manager=mm) - return mmm +======= + assert self.params.qscore.probe_allocation_method in [ + "progressive", "precalculate" + ], "Provide one of 'progressive' or 'precalculate'" + + def run(self): + print("Running") + + # get initial data + mmm = self.data_manager.get_map_model_manager() + + # calculate shells + if len(self.params.qscore.shells) ==0 : + start = self.params.qscore.shell_radius_start + stop = self.params.qscore.shell_radius_stop + num = self.params.qscore.shell_radius_num + shells = list(np.linspace( + start, + stop, + num, + endpoint=True)) + for shell in shells: + self.params.qscore.shells.append(shell) + + + # ignore hydrogens + model = mmm.model() + model = model.select(model.selection("not element H")) + + # make mmm + mmm.set_model(model,overwrite=True) + + + # run qscore + backend = self.params.qscore.backend + calc_func = calc_qscore if backend == "numpy" else calc_qscore_flex + qscore_result= calc_func( + mmm, + self.params.qscore, + log=self.logger) + + + self.result = group_args(**qscore_result) + + # # save as dataframe + # df = cctbx_atoms_to_df(model.get_atoms()) + # df["Q-score"] = self.result.qscore_per_atom + # self.result.qscore_dataframe = + + + + self.write_results() + + def get_results(self): + return self.result + + def get_results_as_JSON(self): + results_dict = { + "flat_results" : self.result.qscore_dataframe.to_dict(orient="records") + } + return json.dumps(results_dict,indent=2) + + + def write_results(self): + with open("qscore_results.json","w") as fh: + fh.write(self.get_results_as_JSON()) + + # write bild files + if self.params.qscore.debug: + print("Writing probe debug files...Using a small selection is recommended", + file=self.logger) + debug_path = Path("qscore_debug") + debug_path.mkdir(exist_ok=True) + for i,shell in enumerate(self.params.qscore.shells): + shell = str(round(shell,2)) + probe_xyz = self.result.probe_xyz[i] + n_shells, n_atoms,n_probes,_ = self.result.probe_xyz.shape + probe_xyz_flat = probe_xyz.reshape((n_atoms*n_probes,3)) + out_file = Path(debug_path,f"probes_shell_{shell}.bild") + write_bild_spheres(probe_xyz_flat,str(out_file),r=0.2) +>>>>>>> Stashed changes From 1a8f24af55895c363660347a5707f3a116e5be97 Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 6 Feb 2024 13:23:08 -0800 Subject: [PATCH 110/748] Major changes all at once to qscore numpy code due to a failed git stash operation. --- cctbx/maptbx/qscore.py | 1500 +++--------------------------------- cctbx/maptbx/tst_qscore.py | 493 +----------- 2 files changed, 128 insertions(+), 1865 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index 2dfa73d22c..241199d108 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -1,157 +1,17 @@ -""" -This code provides methods to calculate the qscore metric for map-model validation, -as developed by Pintile et al. - -Two main modes are provided. - 1. progressive: Allocates probes progressively, and should give identical results to mapq - 2. precalculate: Allocates probes once and rejects. Should give analogous results and is faster. -""" - -from __future__ import division -<<<<<<< Updated upstream -import math import sys -from libtbx.utils import null_out -from collections import defaultdict -from multiprocessing import Pool, cpu_count -======= -from libtbx.utils import null_out from multiprocessing import Pool ->>>>>>> Stashed changes -from itertools import chain -from collections import defaultdict - import numpy as np import numpy.ma as ma from scipy.spatial import KDTree import pandas as pd - +from libtbx.utils import null_out from cctbx.array_family import flex -<<<<<<< Updated upstream -try: - from tqdm import tqdm -except ImportError: - from .qscore_utils import DummyTQDM as tqdm - - -def radial_shell_worker_v1_np(args): -======= -master_phil_str = """ - qscore - { - - nproc = 1 - .type = int - .help = Number of processors to use - .short_caption = Number of processors to use - .expert_level = 1 - n_probes_target = 8 - .type = int - .help = Number of radial probes to use - .short_caption = Number of radial probes to use - .expert_level = 1 - n_probes_max = 16 - .type = int - .help = Max number of radial probes to use - .short_caption = Number of radial probes to use - .expert_level = 1 - n_probes_min = 4 - .type = int - .help = Min number of radial probes to use - .short_caption = Number of radial probes to use - .expert_level = 1 - selection_str = None - .type = str - .help = Only calculate q for atoms within this selection - .short_caption = Only calculate q for atoms within this selection - .expert_level = 1 - - shell_radius_start = 0.1 - .type = float - .help = Start testing density at this radius from atom - .short_caption = Start testing density at this radius from atom - .expert_level = 1 - - shell_radius_stop = 2 - .type = float - .help = Stop testing density at this radius from atom - .short_caption = Stop testing density at this radius from atom - .expert_level = 1 - - shell_radius_num = 20 - .type = int - .help = The number of radial shells - .short_caption = The number of radial shells\ - (includes start/stop, so minimum 2) - .expert_level = 1 - - shells = None - .type = float - .multiple = True - .help = Explicitly provide radial shells - - rtol = 0.9 - .type = float - .help = Mapq rtol value, the "real" shell radii are r*rtol - - probe_allocation_method = precalculate - .type = str - .help = The method used to allocate radial probes - .short_caption = Either 'progressive' or 'precalculate'. \ - Progressive is the original method \ - where probes are proposed and rejected iteratively. \ - Precalculate is where probes are pre-allocated and \ - rejected once. Parallelization is done by radial shell.\ - Precalculate is faster but with slightly varied results. - - backend = numpy - .type = str - .help = Either 'numpy' or 'flex' - .short_caption = Determines which backend mdoe is used - .expert_level = 1 - - debug = False - .type = bool - .help = Return much more debug information - .short_caption = Returns a dictionary with additional debug information - .expert_level = 1 - } - - """ - - - ################################################################################ #### Probe generation functions ################################################################################ -# Original mapq version -def SpherePtsVectorized ( ctr, rad, N ) : - """ - Function for generating points on a sphere. For testing only. - It retains the original mapq code pattern - """ - thetas, phis = [], [] - from math import acos, sin, cos, sqrt, pi - for k in range ( 1, N+1 ) : - h = -1.0 + ( 2.0*float(k-1)/float(N-1) ) - phis.append ( acos(h) ) - thetas.append ( 0 if k == 1 or k == N else - (thetas[k-2] + 3.6/sqrt(N*(1.0-h**2.0))) % (2*pi) ) - - pts = [None] * N - for i, theta, phi in zip ( range(N), thetas, phis ): - v = np.array([ sin(phi)*cos(theta), sin(phi)*sin(theta), cos(phi)]) - - pt = ctr + v * rad - pts[i] = pt - pts = np.array(pts) - pts = pts.swapaxes(0,1) - return pts - - # Fast numpy version def generate_probes_np(atoms_xyz, rad, n_probes): """ @@ -191,83 +51,6 @@ def generate_probes_np(atoms_xyz, rad, n_probes): return probes -# Generate Points with flex - -def cumsum_flex(arr): - """ - Return an array that is the cumulative sum of arr - Analogous to np.cumsum - """ - result = flex.double(len(arr)) - running_sum = 0.0 - for i, x in enumerate(arr): - running_sum += x - result[i] = running_sum - return result - -def broadcast_add_vec3(ctr, points): - """ - Broadcast add two flex.vec3_double arrays. - - Params: - ctr (flex.vec3_double): the 'center' coordinates - points (flex.vec3_double): the points that will be added to each ctr - - Returns: - result (flex.vec3_double): array of shape (N*M,3), 1 point for each center - """ - N = points.size() - M = ctr.size() - extended_ctr = flex.vec3_double() - extended_points = flex.vec3_double() - - # Extend ctr and points - for point in ctr: - extended_ctr.extend(flex.vec3_double([point] * N)) - for _ in range(M): - extended_points.extend(points) - - # Perform addition - result = flex.vec3_double(M * N) - space =flex.size_t_range(M*N) - for i in space: - pt = extended_ctr[i:i+1] + extended_points[i:i+1] - result=result.set_selected(space[i:i+1],pt) - return result - - -def generate_probes_flex(ctr, rad, N): ->>>>>>> Stashed changes - """ - Calulate qscore for a single radial shell using version 1 (serial probe allocation) and numpy - """ - ( - i, - atoms_xyz, - n_probes, - radius_shell, - tree, - rtol, - selection, - n_probes_target, - ) = args - -<<<<<<< Updated upstream - # - # manage selection input - if selection is None: - selection = np.arange(len(atoms_xyz)) -======= - # Generating spherical coordinates - x = flex.sin(phis) * flex.cos(thetas) - y = flex.sin(phis) * flex.sin(thetas) - z = flex.cos(phis) - points = rad * flex.vec3_double(x, y, z) - # Adding the generated points to center points - probes = broadcast_add_vec3(ctr, points) - return probes - - ################################################################################ #### Progressive mode functions ################################################################################ @@ -438,90 +221,78 @@ def shell_probes_progressive( #Finish working on a single atom - pts = np.array(pts) + pts = np.array(pts) # should be shape (n_probes,3) + assert pts.shape == (n_probes_max,3),( + + f"Pts shape must be ({n_probes_max},3), not {pts.shape})") + if pts.shape == (0,): # all probes clashed pts = np.full((n_probes_max,3),np.nan) ->>>>>>> Stashed changes - else: - assert pts.shape == (n_probes_max,3), ( - f"Generated points shape:{pts.shape}, expected: {(n_probes_max,3)}, try increasing n_probes_max" - ) - #iterations_shell.append(i+1) + all_pts.append(pts) - # Finish the shell function - probes_xyz = np.array(all_pts) - assert probes_xyz.shape == (n_atoms,n_probes_max,3),( - f"probes not allocated correctly, probes_xyz.shape: {probes_xyz.shape}, expected: {(n_atoms,n_probes_max,3)}" - ) - probe_mask = ~(np.isnan(probes_xyz))[:,:,0] - return probes_xyz, probe_mask + # prepare output + probe_xyz = np.stack(all_pts) + probe_mask = ~(np.isnan(probe_xyz))[:,:,0] -def _shell_probes_precalculate_wrapper(kwargs): - """ - A wrapper function to pass kwargs for 'shell_probes_progressive' - to multiprocessing pool. - """ - return shell_probes_precalculate(**kwargs) - -def shell_probes_precalculate(atoms_xyz=None, # A numpy array of shape (N,3) - atoms_tree=None, # An atom_xyz scipy kdtree - selection=None, # An atom selection - n_probes_target=8,# The desired number of probes per shell - n_probes_max=16, # The maximum number of probes allowed - n_probes_min=4, # The min number of probes allowed without error - RAD=1.5, # The nominal radius of this shell - rtol=0.9, # Multiplied with RAD to get actual radius - log = null_out(), - strict = False, - ): + return probe_xyz, probe_mask + +################################################################################ +#### Run shell functions for multiple shells(possibly in parallel) +################################################################################ +def get_probes( + atoms_xyz=None, + sites_cart = None, + atoms_tree = None, + params=None, + selection_bool_np = None, + selection_bool_flex=None, + worker_func=None, + log=None): """ - Generate probes by precalculating for a single shell (radius) + Generate probes for multiple radial shells (params.shells) """ + if params.backend == "numpy": + assert worker_func in [shell_probes_progressive,shell_probes_precalculate] + if atoms_tree is None: + atoms_tree = KDTree(atoms_xyz) + selection_bool = selection_bool_np + else: + assert False, f"Unrecognized backend: {params.backend}" - # Do input validation - if not atoms_tree: - assert atoms_tree is None, "If not providing an atom tree, provide a 2d atom coordinate array to build tree" - atoms_tree = KDTree(atoms_xyz) - - # Manage log - if log is None: - log = null_out() - # manage selection input - if selection is None: - selection = np.arange(atoms_xyz.shape[0]) + kwargs_list = [ + { + "atoms_xyz":atoms_xyz, # A numpy array of shape (N,3) + "atoms_tree":atoms_tree, # An atom_xyz scipy kdtree + "selection_bool":selection_bool,# Boolean atom selection + "n_probes_target":params.n_probes_target,# The desired number of probes per shell + "n_probes_max":params.n_probes_max, # The maximum number of probes allowed + "n_probes_min":params.n_probes_min, + "RAD":RAD, # The nominal radius of this shell + "rtol":params.rtol, # Multiplied with RAD to get actual radius + "log":log, + } + for RAD in params.shells] + #DEBUG + if params.nproc=="DEBUG": + with Pool() as pool: + results = pool.map(starmap_wrapper, kwargs_list) else: - assert selection.dtype == bool + results = [] + for kwarg in kwargs_list: + result = worker_func(**kwarg) + results.append(result) - # do selection - atoms_xyz_sel = atoms_xyz[selection] - # get probe coordinates - probe_xyz = generate_probes_np(atoms_xyz_sel, RAD, n_probes_max) - n_atoms, n_probes, _ = probe_xyz.shape - probe_xyz_flat = probe_xyz.reshape(-1,3) + probe_xyz = [result[0] for result in results] + probe_mask = [result[1] for result in results] - outRAD = RAD*rtol - dists, atom_indices = atoms_tree.query(probe_xyz_flat, k=2) - dists = dists.reshape((n_atoms,n_probes,2)) - atom_indices = atom_indices.reshape((n_atoms,n_probes,2)) - row_indices = np.arange(n_atoms)[:, np.newaxis] - expected_atom_mask = atom_indices[:,:,0]==row_indices # whether each probe's nearest atom is the one expected - within_r_mask = dists[:,:,1]= n_probes_min, f"Some atoms have less than {n_probes_min} probes ({len(problematic_probes)}). Consider raising n_probes_max" - return probe_xyz, probe_mask - - -<<<<<<< Updated upstream -def radial_shell_worker_v2_np(args): -======= + if params.backend == "numpy": + return np.stack(probe_xyz), np.array(probe_mask) + else: + return probe_xyz, probe_mask ################################################################################ #### numpy/scipy-based functions (precalculate mode) ################################################################################ @@ -599,68 +370,6 @@ def shell_probes_precalculate( return probe_xyz, probe_mask - -def get_probes( - atoms_xyz=None, - sites_cart = None, - atoms_tree = None, - params=None, - selection_bool_np = None, - selection_bool_flex=None, - worker_func=None, - log=None): ->>>>>>> Stashed changes - """ - Generate probes for atom coordinates. - """ - - if atoms_tree is None: - atoms_tree = KDTree(atoms_xyz) - - kwargs_list = [ - { - 'atoms_xyz':atoms_xyz, - 'atoms_tree':atoms_tree, - 'selection':params.selection, - 'n_probes_target':params.n_probes_target, - 'n_probes_max':params.n_probes_max, - 'n_probes_min':params.n_probes_min, - 'RAD':RAD, - 'rtol':params.rtol, - } for RAD in params.shells] - - # Create a pool of worker processes - if params.nproc > 1: - with Pool(params.nproc) as pool: - results = pool.starmap(worker_func, [(kwargs,) for kwargs in kwargs_list]) - else: - results = [] - for kwargs in kwargs_list: - result = worker_func(kwargs) - results.append(result) - - probe_xyz_all = [result[0] for result in results] - probe_mask_all = [result[1] for result in results] - - # # stack numpy - probe_xyz = np.stack(probe_xyz_all) - probe_mask = np.stack(probe_mask_all) - return probe_xyz, probe_mask - - -<<<<<<< Updated upstream -def ndarray_to_nested_list(arr): - """ - Convert a NumPy array of arbitrary dimensions into a nested list. - :param arr: A NumPy array. - :return: A nested list representing the array. - """ - if arr.ndim == 1: - return arr.tolist() - return [ndarray_to_nested_list(sub_arr) for sub_arr in arr] - -# Example usage -======= def calc_qscore(mmm,params,log=null_out(),debug=False): """ Calculate qscore from map model manager @@ -669,76 +378,54 @@ def calc_qscore(mmm,params,log=null_out(),debug=False): # never do hydrogen model = model.select(model.selection("not element H")) mm = mmm.map_manager() ->>>>>>> Stashed changes - - -def qscore_np( - mmm, - selection=None, - n_probes=32, - shells=np.array( - [ - 0.1, - 0.27272727, - 0.44545455, - 0.61818182, - 0.79090909, - 0.96363636, - 1.13636364, - 1.30909091, - 1.48181818, - 1.65454545, - 1.82727273, - 2.0, - ] - ), - version=2, - nproc=cpu_count(), - log=sys.stdout, -): - """ - Calculate the qscore metric per-atom from an mmtbx map-model-manager, using numpy - """ - model = mmm.model() - mm = mmm.map_manager() - volume = mm.map_data().as_numpy_array() - radii = shells - voxel_size = mm.pixel_sizes() - - probe_xyz, probe_mask = radial_shell_mp_np( - model, - n_probes=n_probes, - num_processes=nproc, - selection=selection, - version=version, - radii=radii, - log=log, - ) - # after the probe generation, versions 1 and 2 are the same - # infer params from shape - n_shells, n_atoms, n_probes, _ = probe_xyz.shape + # Get atoms + atoms_xyz = model.get_sites_cart().as_numpy_array() - # flatten - probe_xyz_flat = probe_xyz.reshape((n_atoms * n_shells * n_probes, 3)) - probe_mask_flat = probe_mask.reshape(-1) # (n_shells*n_atoms*n_probes,) + # do selection + if params.selection_str != None: + selection_bool = mmm.model().selection(params.selection_str).as_numpy_array() # boolean + if selection_bool.sum() ==0: + print("Finished... nothing selected") + return {"qscore_per_atom":None} + else: + selection_bool = np.full(len(atoms_xyz),True) + + # determine worker func + if params.probe_allocation_method == "precalculate": + worker_func=shell_probes_precalculate + else: + worker_func=shell_probes_progressive + + + # Get probes and probe mask (probes to reject) + probe_xyz,probe_mask = get_probes( + atoms_xyz=atoms_xyz, + atoms_tree = None, + params=params, + selection_bool_np = selection_bool, + worker_func=worker_func, + log = log, + ) + + # after the probe generation, versions 1 and 2 are the same -<<<<<<< Updated upstream - # select mask=True probes - masked_probe_xyz_flat = probe_xyz_flat[probe_mask_flat] + # infer params from shape + n_shells, n_atoms, n_probes, _ = probe_xyz.shape + + # flatten + probe_xyz_flat = probe_xyz.reshape((n_atoms * n_shells * n_probes, 3)) + probe_mask_flat = probe_mask.reshape(-1) # (n_shells*n_atoms*n_probes,) + masked_probe_xyz_flat = probe_xyz_flat[probe_mask_flat] - # interpolate - masked_density = trilinear_interpolation( - volume, masked_probe_xyz_flat, voxel_size=voxel_size -======= # interpolate volume = mm.map_data().as_numpy_array() voxel_size = mm.pixel_sizes() # masked_density = trilinear_interpolation( # volume, masked_probe_xyz_flat, voxel_size=voxel_size) masked_density = mm.density_at_sites_cart( - flex.vec3_double(masked_probe_xyz_flat)).as_numpy_array() + flex.vec3_double(masked_probe_xyz_flat)).as_numpy_array() d_vals = np.full((n_shells, n_atoms, n_probes),np.nan) d_vals[probe_mask] = masked_density @@ -786,7 +473,7 @@ def qscore_np( if debug or params.debug: # Collect debug data result = { - "atom_xyz":atom_xyz, + "atom_xyz":atoms_xyz, "probe_xyz":probe_xyz, "probe_mask":probe_mask, "d_vals":d_vals, @@ -803,988 +490,7 @@ def qscore_np( } return result -################################################################################ -#### CCTBX flex-based functions (precalculate mode) -################################################################################ -def shell_probes_precalculate_flex( - atoms_xyz=None, # sites_cart. Flex vec3_double - atoms_tree=None, # A KDTree - selection_bool=None, # Boolean atom selection - n_probes_target=8,# The desired number of probes per shell - n_probes_max=16, # The maximum number of probes allowed - n_probes_min=4, # The min number of probes allowed without error - RAD=1.5, # The nominal radius of this shell - rtol=0.9, # Multiplied with RAD to get actual radius - log = null_out(), - strict = False, - ): - """ - Generate probes by precalculating for a single shell (radius) - """ - - # Do input validation - if not atoms_tree: - assert atoms_tree is None, ("If not providing an atom tree,\ - provide a 2d atom coordinate array to build tree") - # make atom kdtree - atoms_tree = KDTreeFlex(atoms_xyz) - - # Manage log - if log is None: - log = null_out() - - # manage selection input - - if selection_bool is None: - selection_bool = flex.bool(len(atoms_xyz),True) - - - # do selection - sites_sel = atoms_xyz.select(selection_bool) - n_atoms = len(sites_sel) - - # get probe coordinates - probe_sites = generate_probes_flex(sites_sel, RAD, n_probes_max) - - - # modify "real" radius as in mapq - outRAD = RAD*rtol - - # query kdtree to get neighbors and their distances - dists,atom_indices = atoms_tree.query_nearest_neighbors(probe_sites,k=2) - atom_indices_flat = flex_from_list(atom_indices) - - # Perform equivalent to atom_indices[:,:,0] if (n_atoms,n_probes,k) - dim0_indices = flex.size_t_range(0, n_atoms*n_probes_max*2, 2) - atom_indices_flat = atom_indices_flat.select(dim0_indices) - - # Build an index array that would be expected if each probe is near "its" atom - row_indices_flat = flex.size_t([ - i for i in range(n_atoms) for _ in range(n_probes_max)]) - - - # Mask for whether each probe's nearest atom is the one expected - expected_mask = row_indices_flat == atom_indices_flat - - - # A second mask to determine if the second nearest neighbor should be rejected - # (whether the second nearest neighbor is within the rejection radius) - dists = flex_from_list(dists) - # perform equivalent selcetion to dists[:,:,1] if (n_atoms,n_probes,k) - dist_dim1_sel = flex.size_t([i * 2 + 1 for i in range(n_atoms * n_probes_max)]) - dists_dim1 = dists.select(dist_dim1_sel) - within_r_mask = dists_dim1>>>>>> Stashed changes - ) - - # reshape interpolated values to (n_shells,n_atoms, n_probes) - - d_vals = np.zeros((n_shells, n_atoms, n_probes)) - d_vals[probe_mask] = masked_density - - # reshape to (M,N*L) for rowwise correlation - - d_vals_2d = d_vals.transpose(1, 0, 2).reshape(d_vals.shape[1], -1) - - # create the reference data - - M = volume - maxD = min(M.mean() + M.std() * 10, M.max()) - minD = max(M.mean() - M.std() * 1, M.min()) - A = maxD - minD - B = minD - u = 0 - sigma = 0.6 - x = np.array(radii) - y = A * np.exp(-0.5 * ((x - u) / sigma) ** 2) + B - - # Stack and reshape data for correlation calc - - # stack the reference to shape (n_shells,n_atoms,n_probes) - g_vals = np.repeat(y[:, None], n_probes, axis=1) - g_vals = np.expand_dims(g_vals, 1) - g_vals = np.tile(g_vals, (n_atoms, 1)) - - # reshape - g_vals_2d = g_vals.transpose(1, 0, 2).reshape(g_vals.shape[1], -1) - d_vals_2d = d_vals.transpose(1, 0, 2).reshape(d_vals.shape[1], -1) - mask_2d = probe_mask.transpose(1, 0, 2).reshape(probe_mask.shape[1], -1) - - # # CALCULATE Q - - # # numpy - q = rowwise_corrcoef(g_vals_2d, d_vals_2d, mask=mask_2d) - - # # Log - # import os - - # print("FINISHING...") - # print(os.getcwd()) - # print("saving atoms xyz: atom_xyz_np.npy") - # np.save("atoms_xyz_np.npy",model.get_sites_cart().as_numpy_array()) - # print("saving probe xyz: probe_xyz_np.npy") - # np.save("probe_xyz_np.npy",probe_xyz) - # print("saving probe mask: probe_mask_np.npy") - # np.save("probe_mask_np.npy",probe_mask) - # print("saving qscore: qscore_np.npy") - # np.save("qscore_np.npy",q) - - return q - - -############################################################################## -# Code below here requires refactoring -############################################################################## - - -<<<<<<< Updated upstream -def radial_shell_worker_v2_flex(args): - """ - Calulate qscore for a single radial shell using version 2 (parallel probe allocation) and flex only - """ - # unpack args - i, atoms_xyz, n_probes, radius_shell, rtol, tree, selection = args - - # manage selection input - if selection is None: - selection = flex.size_t_range(len(atoms_xyz)) - else: - assert isinstance(selection, flex_bool) - - # do selection - n_atoms = selection.count(True) - atoms_xyz_sel = atoms_xyz.select(selection) - - # get probe coordinates - probe_xyz = sphere_points_flex(atoms_xyz_sel, radius_shell, n_probes) - - # query to find the number of atoms within the clash range of each probe - counts = query_ball_point_flex( - tree, atoms_xyz, probe_xyz, r=radius_shell * rtol - ) - probe_mask = counts == 0 - return probe_xyz, probe_mask -======= - # for each "shell row" - for shell_idx,(probe_xyz,probe_mask) in enumerate(zip(probe_xyzs,probe_masks)): - probe_mask.reshape(flex.grid(n_atoms*params.n_probes_max)) - probe_xyz_sel = probe_xyz.select(probe_mask) - - # get d_vals for a "shell row" - d_vals = mm.density_at_sites_cart(probe_xyz_sel) - - # get reference for the "shell row" - g_vals = flex.double(n_atoms*params.n_probes_max,y_cctbx[shell_idx]) - g_vals = g_vals.select(probe_mask) - - # calc flat indices for the shell - start_idx = shell_idx * n_atoms * n_probes - stop_idx = start_idx + n_atoms * n_probes - shell_space = flex.size_t_range(start_idx,stop_idx) - - # apply shell mask - masked_shell_space = shell_space.select(probe_mask) - - # put d,g, mask into results - full_flat_d.set_selected(masked_shell_space,d_vals) - full_flat_g.set_selected(masked_shell_space,g_vals) - full_flat_mask = full_flat_mask.set_selected(shell_space,probe_mask) - - # calculate q - def calculate_1d_indices_for_atom(n_shells, n_atoms, n_probes, atom_idx): - indices_1d = [] - for shell_idx in range(n_shells): - for probe_idx in range(n_probes): - index_1d = shell_idx * (n_atoms * n_probes) + atom_idx * n_probes + probe_idx - indices_1d.append(index_1d) - return indices_1d - - qscore_per_atom = [] - mask_check_1d = [] - for atomi in range(n_atoms): - inds = calculate_1d_indices_for_atom(n_shells,n_atoms,n_probes,atomi) - inds = flex.size_t(inds) - - # select an "atom row" for d,g,mask values - d_row = full_flat_d.select(inds) - g_row = full_flat_g.select(inds) - mask = full_flat_mask.select(inds) - - # subset the d,g rows using the mask - d = d_row.select(mask) - g = g_row.select(mask) - - # calculate correlation between masked d and g - qval = flex.linear_correlation(d, g).coefficient() - qscore_per_atom.append(qval) - - qscore_per_atom = flex.double(qscore_per_atom) - - qscore_df = aggregate_qscore_per_residue(model,np.array(qscore_per_atom),window=3) - qscore_per_residue = flex.double(qscore_df["Q-scorePerResidue"].values) - - # Output - if debug or params.debug: - # Collect debug data - result = { - "atom_xyz":atoms_xyz, - "probe_xyz":probe_xyzs, - "probe_mask":probe_masks, - "d_vals":full_flat_d, - "g_vals":full_flat_g, - "qscore_per_atom":qscore_per_atom, - "mask_check_1d":mask_check_1d, - "qscore_per_residue":qscore_per_residue, - "qscore_dataframe":qscore_df - } - else: - result = { - "qscore_per_atom":qscore_per_atom, - "qscore_per_residue":qscore_per_residue, - "qscore_dataframe":qscore_df - - } - return result ->>>>>>> Stashed changes - - -def radial_shell_v2_mp_flex( - model, - n_probes=32, - radii=np.linspace(0.1, 2, 12), - rtol=0.9, - num_processes=cpu_count(), - selection=None, - version=2, - log=sys.stdout, -): - """ - Generate probes for a model file using flex only - """ - assert version in [1, 2], "Version must be 1 or 2" - if version == 1: - assert False - else: - worker_func = radial_shell_worker_v2_flex - -<<<<<<< Updated upstream - # get a "tree", which is just a dictionary of index:local neighbor indices - tree, _ = query_atom_neighbors(model, radius=3.5) - atoms_xyz = model.get_sites_cart() - - # i,atoms_xyz,n_probes,radius_shell,rtol, selection= args - # Create argument tuples for each chunk - - args = [ - (i, atoms_xyz, n_probes, radius_shell, rtol, tree, selection) - for i, radius_shell in enumerate(radii) - ] - - # Create a pool of worker processes - if num_processes > 1: - with Pool(num_processes) as p: - # Use the pool to run the trilinear_interpolation_worker function in parallel - results = list( - tqdm(p.imap(worker_func, args), total=len(args), file=log) - ) - else: - results = [] - for arg in tqdm(args, file=log): - # for arg in args: - result = worker_func(arg) - results.append(result) - - # stack the results from each shell into single arrays - probe_xyz_all = [result[0] for result in results] - probe_mask_all = [result[1] for result in results] - - # # debug - # return probe_xyz_all, probe_mask_all,tree - - n_atoms = probe_xyz_all[0].focus()[0] - n_shells = len(probe_mask_all) - out_shape = (n_shells, n_atoms, n_probes, 3) - out_size = math.prod(out_shape) - shell_size = math.prod(out_shape[1:]) - out_probes = flex.double(out_size, -1.0) - out_mask = flex.bool(n_atoms * n_shells * n_probes, False) - - for i, p in enumerate(probe_xyz_all): - start = i * shell_size - stop = start + shell_size - out_probes = out_probes.set_selected( - flex.size_t_range(start, stop), p.as_1d() - ) - out_probes.reshape(flex.grid(*out_shape)) - - for i, k in enumerate(probe_mask_all): - start = i * (n_atoms * n_probes) - stop = start + (n_atoms * n_probes) - out_mask = out_mask.set_selected( - flex.size_t_range(start, stop), k.as_1d() - ) - out_mask.reshape(flex.grid(n_shells, n_atoms, n_probes)) - - return out_probes, out_mask -======= -################################################################################ -#### KDTree implementation using flex arrays (no numpy/scipy) -################################################################################ -class KDTreeFlexNode: - def __init__(self, index, point, left=None, right=None): - self.index = index - self.point = point - self.left = left - self.right = right ->>>>>>> Stashed changes - - -def qscore_flex( - mmm, - selection=None, - n_probes=32, - shells=[ - 0.1, - 0.27272727, - 0.44545455, - 0.61818182, - 0.79090909, - 0.96363636, - 1.13636364, - 1.30909091, - 1.48181818, - 1.65454545, - 1.82727273, - 2.0, - ], - version=2, - nproc=cpu_count(), -): - """ - Calculate the qscore metric per-atom from an mmtbx map-model-manager, using flex only - """ - model = mmm.model() - mm = mmm.map_manager() - radii = shells - volume = mm.map_data() - voxel_size = mm.pixel_sizes() - -<<<<<<< Updated upstream - probe_xyz, probe_mask = radial_shell_v2_mp_flex( - model, - n_probes=n_probes, - num_processes=nproc, - selection=selection, - version=version, - radii=radii, - ) - - # aliases - probe_xyz_cctbx = probe_xyz - probe_mask_cctbx = probe_mask -======= - - def pre_sort_indices(self, points): - # Sort indices for each axis and return the sorted indices - x,y,z = points.parts() - sorted_indices = [ - flex.sort_permutation(x), - flex.sort_permutation(y), - flex.sort_permutation(z)] - return sorted_indices - - def build_tree(self, indices, points, depth): - if not indices: - return None - - axis = depth % self.dims - - - sorted_indices = self.axis_sorted_indices[axis] - - - # Step 4: Create an empty boolean mask of length N, initially set to False - mask = flex.bool(len(sorted_indices),False) - - # Directly set mask to True for positions in your query array - mask.set_selected(indices,True) - - # Step 5: Apply the mask to the sorted indices, - # then use this to create a sorted mask - # This step seems to be where you're looking to optimize. - # To directly use the sorted_indices to index into 'mask' and maintain sorting: - sorted_mask = mask.select(sorted_indices) - - # Now, apply this sorted_mask to select from the sorted_indices - sorted_indices_this_axis = sorted_indices.select(sorted_mask) - - - if len(sorted_indices_this_axis) == 0: - return None - - median_idx = len(sorted_indices_this_axis) // 2 - median_index = sorted_indices_this_axis[median_idx] - - left_indices = sorted_indices_this_axis[:median_idx] - right_indices = sorted_indices_this_axis[median_idx + 1:] - - return KDTreeFlexNode( - median_index, - points[median_index:median_index+1], - left=self.build_tree(left_indices, points, depth + 1), - right=self.build_tree(right_indices, points, depth + 1) - ) - def _nearest_neighbor(self, root, point, depth=0, best=None, k=1): - if root is None: - return best - - if best is None: - best = [] ->>>>>>> Stashed changes - - # infer params from shape - n_shells, n_atoms, n_probes, _ = probe_xyz.focus() - - # APPLY MASK BEFORE INTERPOLATION - -<<<<<<< Updated upstream - probe_mask_cctbx_fullflat = [] - - for val in probe_mask_cctbx: - for _ in range(3): # since A has an additional dimension of size 3 - probe_mask_cctbx_fullflat.append(val) -======= - # Check the current root distance - current_dist = root.point.max_distance(point) - if len(best) < k or current_dist < best[-1]['dist']: - best.append({'index': root.index, 'dist': current_dist}) - best.sort(key=lambda x: x['dist']) - best = best[:k] # Keep only k nearest - - # Check if we need to search the opposite branch - if len(best) < k or ( - abs(point[0][axis] - root.point[0][axis]) < best[-1]['dist']): - best = self._nearest_neighbor(opposite_branch, point, depth + 1, best, k) ->>>>>>> Stashed changes - - mask = flex.bool(probe_mask_cctbx_fullflat) - # indices = flex.int([i for i in range(1, keep_mask_cctbx.size() + 1) for _ in range(3)]) - sel = probe_xyz_cctbx.select(mask) - # sel_indices = indices.select(mask) - masked_probe_xyz_flat_cctbx = flex.vec3_double(sel) - -<<<<<<< Updated upstream - # INTERPOLATE - - masked_density_cctbx = mm.density_at_sites_cart( - masked_probe_xyz_flat_cctbx - ) - - # reshape interpolated values to (n_shells,n_atoms, n_probes) - - probe_mask_cctbx.reshape(flex.grid(n_shells * n_atoms * n_probes)) - d_vals_cctbx = flex.double(probe_mask_cctbx.size(), 0.0) - d_vals_cctbx = d_vals_cctbx.set_selected( - probe_mask_cctbx, masked_density_cctbx - ) - d_vals_cctbx.reshape(flex.grid(n_shells, n_atoms, n_probes)) - - # reshape to (M,N*L) for rowwise correlation - - def custom_reshape_indices(flex_array): - N, M, L = flex_array.focus() - result = flex.double(flex.grid(M, N * L)) - - for i in range(N): - for j in range(M): - for k in range(L): - # Calculate the original flat index - old_index = i * M * L + j * L + k - # Calculate the new flat index after transpose and reshape - new_index = j * N * L + i * L + k - result[new_index] = flex_array[old_index] - - return result - - d_vals_2d_cctbx = custom_reshape_indices(d_vals_cctbx) - - # create the reference data - M = volume - M_std = flex_std(M) - M_mean = flex.mean(M) - maxD_cctbx = min(M_mean + M_std * 10, flex.max(M)) - minD_cctbx = max(M_mean - M_std * 1, flex.min(M)) - A_cctbx = maxD_cctbx - minD_cctbx - B_cctbx = minD_cctbx - u = 0 - sigma = 0.6 - x = flex.double(radii) - y_cctbx = ( - A_cctbx * flex.exp(-0.5 * ((flex.double(x) - u) / sigma) ** 2) - + B_cctbx - ) - - # Stack and reshape data for correlation calc - - # 1. Repeat y for n_probes (equivalent to np.repeat) - g_vals_cctbx = [[val] * n_probes for val in y_cctbx] - - # 2. Add a new dimension (equivalent to np.expand_dims) - g_vals_expanded = [[item] for item in g_vals_cctbx] - - # 3. Tile for each atom (equivalent to np.tile) - g_vals_tiled = [] - for item in g_vals_expanded: - g_vals_tiled.append(item * n_atoms) - - g_vals_cctbx = flex.double(np.array(g_vals_tiled)) - - # # CALCULATE Q - - d_vals_cctbx = d_vals_cctbx.as_1d() - g_vals_cctbx = g_vals_cctbx.as_1d() - probe_mask_cctbx_double = probe_mask_cctbx.as_1d().as_double() - q_cctbx = [] - for atomi in range(n_atoms): - inds = nd_to_1d_indices( - (None, atomi, None), (n_shells, n_atoms, n_probes) - ) - # inds = optimized_nd_to_1d_indices(atomi,(n_shells,n_atoms,n_probes)) - inds = flex.uint32(inds) - d_row = d_vals_cctbx.select(inds) - g_row = g_vals_cctbx.select(inds) - mask = probe_mask_cctbx.select(inds) - - d = d_row.select(mask) - g = g_row.select(mask) - qval = flex.linear_correlation(d, g).coefficient() - q_cctbx.append(qval) - - q = flex.double(q_cctbx) - return q -======= - def query_nearest_neighbors(self, query_points, k=1): - dists, inds = [], [] - for i,point in enumerate(query_points): - point = query_points[i:i+1] - nearest = self._nearest_neighbor(self.root, point, k=k) - dists.append([n['dist'] for n in nearest]) - inds.append([n['index'] for n in nearest]) - return dists, inds ->>>>>>> Stashed changes - - -# qscore utils - -def trilinear_interpolation(voxel_grid, coords, voxel_size=None, offset=None): - """Numpy trilinear interpolation""" - assert voxel_size is not None, "Provide voxel size as an array or single value" - - # Apply offset if provided - if offset is not None: - coords = coords - offset - - # Transform coordinates to voxel grid index space - index_coords = coords / voxel_size - - # Split the index_coords array into three arrays: x, y, and z - x, y, z = index_coords.T - - # Truncate to integer values - x0, y0, z0 = np.floor([x, y, z]).astype(int) - x1, y1, z1 = np.ceil([x, y, z]).astype(int) - - # Ensure indices are within grid boundaries - x0, y0, z0 = np.clip([x0, y0, z0], 0, voxel_grid.shape[0]-1) - x1, y1, z1 = np.clip([x1, y1, z1], 0, voxel_grid.shape[0]-1) - - # Compute weights - xd, yd, zd = [arr - arr.astype(int) for arr in [x, y, z]] - - # Interpolate along x - c00 = voxel_grid[x0, y0, z0]*(1-xd) + voxel_grid[x1, y0, z0]*xd - c01 = voxel_grid[x0, y0, z1]*(1-xd) + voxel_grid[x1, y0, z1]*xd - c10 = voxel_grid[x0, y1, z0]*(1-xd) + voxel_grid[x1, y1, z0]*xd - c11 = voxel_grid[x0, y1, z1]*(1-xd) + voxel_grid[x1, y1, z1]*xd - - # Interpolate along y - c0 = c00*(1-yd) + c10*yd - c1 = c01*(1-yd) + c11*yd - - # Interpolate along z - c = c0*(1-zd) + c1*zd - - return c - - -def rowwise_corrcoef(A, B, mask=None): - """Numpy masked array rowwise correlation coefficient""" - assert A.shape == B.shape, f"A and B must have the same shape, got: {A.shape} and {B.shape}" - - if mask is not None: - assert mask.shape == A.shape, "mask must have the same shape as A and B" - A = ma.masked_array(A, mask=np.logical_not(mask)) - B = ma.masked_array(B, mask=np.logical_not(mask)) - - # Calculate means - A_mean = ma.mean(A, axis=1, keepdims=True) - B_mean = ma.mean(B, axis=1, keepdims=True) - - # Subtract means - A_centered = A - A_mean - B_centered = B - B_mean - - # Calculate sum of products - sumprod = ma.sum(A_centered * B_centered, axis=1) - - # Calculate square roots of the sum of squares - sqrt_sos_A = ma.sqrt(ma.sum(A_centered**2, axis=1)) - sqrt_sos_B = ma.sqrt(ma.sum(B_centered**2, axis=1)) - - # Return correlation coefficients - cc = sumprod / (sqrt_sos_A * sqrt_sos_B) - return cc.data - -def cdist_flex(A, B): - """A flex implementation of the cdist function""" - - def indices_2d_flex(dimensions): - N = len(dimensions) - if N != 2: - raise ValueError("Only 2D is supported for this implementation.") - - # Create the row indices - row_idx = flex.size_t(chain.from_iterable( - [[i] * dimensions[1] for i in range(dimensions[0])])) - - # Create the column indices - col_idx = flex.size_t(chain.from_iterable( - [list(range(dimensions[1])) for _ in range(dimensions[0])])) - - return row_idx, col_idx - - i_idxs, j_idxs = indices_2d_flex((A.focus()[0], B.focus()[0])) - - r = i_idxs - xi = i_idxs*3 - yi = i_idxs*3 + 1 - zi = i_idxs*3 + 2 - - xa = A.select(xi) - ya = A.select(yi) - za = A.select(zi) - - xj = j_idxs*3 - yj = j_idxs*3 + 1 - zj = j_idxs*3 + 2 - - xb = B.select(xj) - yb = B.select(yj) - zb = B.select(zj) - - d = ((xb - xa)**2 + (yb - ya)**2 + (zb - za)**2)**0.5 - d.reshape(flex.grid((A.focus()[0], B.focus()[0]))) - - return d - - -def query_atom_neighbors(model, radius=3.5, include_self=True, only_unit=True): - """Perform radial nearest neighbor searches using cctbx tools, for atom coordinates in a model""" - crystal_symmetry = model.crystal_symmetry() - hierarchy = model.get_hierarchy() - sites_cart = hierarchy.atoms().extract_xyz() - sst = crystal_symmetry.special_position_settings().site_symmetry_table( - sites_cart=sites_cart) - conn_asu_mappings = crystal_symmetry.special_position_settings().\ - asu_mappings(buffer_thickness=5) - conn_asu_mappings.process_sites_cart( - original_sites=sites_cart, - site_symmetry_table=sst) - conn_pair_asu_table = cctbx.crystal.pair_asu_table( - asu_mappings=conn_asu_mappings) - conn_pair_asu_table.add_all_pairs(distance_cutoff=radius) - pair_generator = cctbx.crystal.neighbors_fast_pair_generator( - conn_asu_mappings, - distance_cutoff=radius) - fm = crystal_symmetry.unit_cell().fractionalization_matrix() - om = crystal_symmetry.unit_cell().orthogonalization_matrix() - - pairs = list(pair_generator) - inds = defaultdict(list) - dists = defaultdict(list) - - for pair in pairs: - i, j = pair.i_seq, pair.j_seq - rt_mx_i = conn_asu_mappings.get_rt_mx_i(pair) - rt_mx_j = conn_asu_mappings.get_rt_mx_j(pair) - rt_mx_ji = rt_mx_i.inverse().multiply(rt_mx_j) - - if (only_unit and rt_mx_ji.is_unit_mx()) or (not only_unit): - d = round(math.sqrt(pair.dist_sq), 6) - inds[i].append(j) - dists[i].append(d) - - # add reverse - inds[j].append(i) - dists[j].append(d) - # print(pair.i_seq, pair.j_seq, rt_mx_ji, math.sqrt(pair.dist_sq), de) - - # add self - if include_self: - for key, value in list(inds.items()): - dval = dists[key] - dists[key] = dval+[0.0] - inds[key] = value+[key] - - # sort - for key, value in list(inds.items()): - dval = dists[key] - # sort - sorted_pairs = sorted(set(list(zip(value, dval)))) - value_sorted, dval_sorted = zip(*sorted_pairs) - inds[key] = value_sorted - dists[key] = dval_sorted - - return inds, dists - - -def query_ball_point_flex(tree, tree_xyz, query_xyz, r=None): - """ - Imitate the api of the scipy.spatial query_ball_point function, but using only flex arrays. - Note: This just copies the api, it does not actually use a tree structure, so is much slower. - """ - assert r is not None, "provide radius" - n_atoms, n_probes, _ = query_xyz.focus() - counts = [] - - for atom_i in range(n_atoms): - probe_range = (n_probes * atom_i * 3, n_probes * (atom_i+1) * 3) - atom_probes_xyz = query_xyz.select(flex.size_t_range(*probe_range)) - atom_probes_xyz.reshape(flex.grid(n_probes, 3)) - nbrs = tree[atom_i] - n_nbrs = len(nbrs) - nbrs_xyz = tree_xyz.select(flex.size_t(nbrs)).as_1d().as_double() - nbrs_xyz.reshape(flex.grid(len(nbrs), 3)) - d = cdist_flex(nbrs_xyz, atom_probes_xyz) - sel = d < r - count = [] - for nbr_i in range(n_probes): - nbr_range = (slice(0, n_nbrs), slice(nbr_i, nbr_i+1)) - count_nbr = sel[nbr_range].count(True) - count.append(count_nbr) - - counts.append(count) - - counts = flex_from_list(counts) - return counts - - -# flex utils -def flex_from_list(lst, signed_int=False): - """Generate a flex array from a list, try to infer type""" - flat_list, shape = flatten_and_shape(lst) - dtype = get_dtype_of_list(flat_list) - type_mapper = {int: flex.size_t, - float: flex.double, - bool: flex.bool} - if signed_int: - type_mapper[int] = flex.int16 - - # make flex array - assert dtype in type_mapper, f"Unrecognized type: {dtype}" - flex_func = type_mapper[dtype] - flex_array = flex_func(flat_list) - if len(shape) > 1: - flex_array.reshape(flex.grid(*shape)) - return flex_array - - -def flatten_and_shape(lst): - """Flatten a nested list and return its shape.""" - def helper(l): - if not isinstance(l, list): - return [l], () - flat = [] - shapes = [] - for item in l: - f, s = helper(item) - flat.extend(f) - shapes.append(s) - if len(set(shapes)) != 1: - raise ValueError("Ragged nested list detected.") - return flat, (len(l),) + shapes[0] - - flattened, shape = helper(lst) - return flattened, shape - - -def get_dtype_of_list(lst): - dtypes = {type(item) for item in lst} - - if len(dtypes) > 1: - raise ValueError("Multiple data types detected.") - elif len(dtypes) == 0: - raise ValueError("Empty list provided.") - else: - return dtypes.pop() - - -def nd_to_1d_indices(indices, shape): - """Generate the 1d indices given nd indices and an array shape""" - # Normalize indices to always use slice objects - normalized_indices = [] - for dim, idx in enumerate(indices): - if idx is None: - normalized_indices.append(slice(0, shape[dim])) - else: - normalized_indices.append(idx) - - # If any index is a slice, recursively call function for each value in slice - for dim, (i, s) in enumerate(zip(normalized_indices, shape)): - if isinstance(i, slice): - result_indices = [] - start, stop, step = i.indices(s) - for j in range(start, stop, step): - new_indices = list(normalized_indices) - new_indices[dim] = j - result_indices.extend(nd_to_1d_indices(new_indices, shape)) - return result_indices - - # If no slices, calculate single 1D index - index = 0 - stride = 1 - for i, dim in reversed(list(zip(normalized_indices, shape))): - index += i * stride - stride *= dim - return [index] - - -<<<<<<< Updated upstream -def optimized_nd_to_1d_indices(i, shape): - """Similar to above, but hardcoded to select a single index on dimension 1""" - # For fixed input of (None, i, None), we directly compute based on given structure - result_indices = [] - - # Pre-compute for 1st dimension which is always a slice - start1, stop1 = 0, shape[0] - - # Pre-compute for 3rd dimension which is always a slice - start3, stop3 = 0, shape[2] - stride3 = 1 - - # Directly compute for 2nd dimension which is variable - stride2 = shape[2] - index2 = i * stride2 * shape[0] - - for val1 in range(start1, stop1): - for val3 in range(start3, stop3): - result_indices.append(val1 * stride2 + index2 + val3 * stride3) - - return result_indices - - -def flex_std(flex_array): - """Standard deviation""" - n = flex_array.size() - if n <= 1: - raise ValueError("Sample size must be greater than 1") - - # Compute the mean - mean_value = flex.mean(flex_array) - - # Compute the sum of squared deviations - squared_deviations = (flex_array - mean_value) ** 2 - sum_squared_deviations = flex.sum(squared_deviations) - - # Compute the standard deviation - std_dev = (sum_squared_deviations / (n - 1)) ** 0.5 - return std_dev -======= -def cdist_flex(A, B): - """A flex implementation of the cdist function""" - - def indices_2d_flex(dimensions): - N = len(dimensions) - if N != 2: - raise ValueError("Only 2D is supported for this implementation.") - - # Create the row indices - row_idx = flex.size_t(chain.from_iterable( - [[i] * dimensions[1] for i in range(dimensions[0])])) - - # Create the column indices - col_idx = flex.size_t(chain.from_iterable( - [list(range(dimensions[1])) for _ in range(dimensions[0])])) - - return row_idx, col_idx - - i_idxs, j_idxs = indices_2d_flex((A.focus()[0], B.focus()[0])) - - r = i_idxs - xi = i_idxs*3 - yi = i_idxs*3 + 1 - zi = i_idxs*3 + 2 - - xa = A.select(xi) - ya = A.select(yi) - za = A.select(zi) - - xj = j_idxs*3 - yj = j_idxs*3 + 1 - zj = j_idxs*3 + 2 - - xb = B.select(xj) - yb = B.select(yj) - zb = B.select(zj) - - d = ((xb - xa)**2 + (yb - ya)**2 + (zb - za)**2)**0.5 - d.reshape(flex.grid((A.focus()[0], B.focus()[0]))) - - return d def trilinear_interpolation(voxel_grid, coords, voxel_size=None, offset=None): """Numpy trilinear interpolation""" @@ -1857,6 +563,7 @@ def rowwise_corrcoef(A, B, mask=None): cc = sumprod / (sqrt_sos_A * sqrt_sos_B) return cc.data + def starmap_wrapper(task): """ A generic wrapper function to call any worker function with specified arguments. @@ -1888,7 +595,7 @@ def aggregate_qscore_per_residue(model,qscore_per_atom,window=3): "chain_id":chain_ids, "resname":res_names, "name":names, - "Q-score":qscore_per_atom, + "Q-score":np.array(qscore_per_atom), }) @@ -1897,6 +604,12 @@ def aggregate_qscore_per_residue(model,qscore_per_atom,window=3): # average qscore by residue grouped_means = df.groupby(['chain_id',"resseq","resname","rg_index"],as_index=False)['Q-score'].mean() + # DEBUG: + + if 'Q-score' not in grouped_means.columns: + import pdb + pdb.set_trace() + # roll over residue means for chain_id,group in grouped_means.groupby("chain_id"): @@ -1989,4 +702,5 @@ def cctbx_atoms_to_df(atoms): df_atoms = pd.DataFrame(data,index=list(range(len(atoms)))) return df_atoms ->>>>>>> Stashed changes + + diff --git a/cctbx/maptbx/tst_qscore.py b/cctbx/maptbx/tst_qscore.py index 96d9f050a6..5443047d2e 100644 --- a/cctbx/maptbx/tst_qscore.py +++ b/cctbx/maptbx/tst_qscore.py @@ -1,18 +1,5 @@ from __future__ import absolute_import, division, print_function import os -<<<<<<< Updated upstream -from cctbx.array_family import flex -import libtbx -from libtbx import group_args -from libtbx.utils import null_out -from iotbx.cli_parser import run_program -import numpy as np -from scipy.spatial import KDTree - - - - ] -======= import copy import shutil from pathlib import Path @@ -33,9 +20,9 @@ get_probe_mask, shell_probes_progressive, shell_probes_precalculate, - shell_probes_precalculate_flex, + #shell_probes_precalculate_flex, calc_qscore, - calc_qscore_flex + #calc_qscore_flex ) @@ -184,22 +171,22 @@ def test_shell_probes(): assert np.all(isclose_or_nan(probe_xyz,expected_probes,atol=1e-3)) - # test precalculate (flex) - shell_func = shell_probes_precalculate_flex - probe_xyz,probe_mask = shell_func( - atoms_xyz=flex.vec3_double(atoms_xyz), - atoms_tree = None, - selection_bool=None, - n_probes_target=8, - n_probes_max=10, - RAD=1.5, - rtol=0.9, - log = null_out()) + # # test precalculate (flex) + # shell_func = shell_probes_precalculate_flex + # probe_xyz,probe_mask = shell_func( + # atoms_xyz=flex.vec3_double(atoms_xyz), + # atoms_tree = None, + # selection_bool=None, + # n_probes_target=8, + # n_probes_max=10, + # RAD=1.5, + # rtol=0.9, + # log = null_out()) - # test at single shell - probe_xyz = np.array(probe_xyz) - probe_xyz = probe_xyz.reshape(expected_probes.shape) - assert np.all(isclose_or_nan(probe_xyz,expected_probes,atol=1e-3)) + # # test at single shell + # probe_xyz = np.array(probe_xyz) + # probe_xyz = probe_xyz.reshape(expected_probes.shape) + # assert np.all(isclose_or_nan(probe_xyz,expected_probes,atol=1e-3)) ################################################################################ @@ -257,444 +244,7 @@ def convert_func(g): "debug":True, "rtol":0.9, } ->>>>>>> Stashed changes } -# make flex arrays -expected_results = {key: flex.double(val) - for key, val in list(expected_results.items())} - - - - -def isclose_or_nan(a, b, atol=1e-3): - # perform isclose comparison, treating nans as equal - return np.isclose(a, b, atol=atol) | (np.isnan(a) & np.isnan(b)) - -def test_probe_generation(): - # test the primary points generation function against expected data - atoms_xyz = np.array([[ 5.276, 12.488, 16.069], - [ 5.649, 13.947, 16.076]]) - - probes_expected = np.array([[ - [ 5.276 , 12.488 , 15.969 ], - [ 5.2588, 12.5558, 15.9976], - [ 5.186 , 12.4803, 16.0261], - [ 5.2564, 12.391 , 16.0547], - [ 5.3636, 12.442 , 16.0833], - [ 5.3304, 12.5601, 16.1119], - [ 5.2115, 12.5151, 16.1404], - [ 5.276 , 12.488 , 16.169 ]], - - [[ 5.649 , 13.947 , 15.976 ], - [ 5.6318, 14.0148, 16.0046], - [ 5.559 , 13.9393, 16.0331], - [ 5.6294, 13.85 , 16.0617], - [ 5.7366, 13.901 , 16.0903], - [ 5.7034, 14.0191, 16.1189], - [ 5.5845, 13.9741, 16.1474], - [ 5.649 , 13.947 , 16.176 ]]]) - - probes_xyz = generate_probes_np(atoms_xyz,0.1,8) - assert np.all(np.isclose(probes_xyz,probes_expected,atol=1e-3)) - - - # test that our points generator functions don't diverge on - # a large amount of points - points = np.random.random((1000,3)) - rads = np.linspace(0,2.0,20) - Ns = [2] - # test point by point - for point in points: - for rad in rads: - for N in Ns: - mapq_values = SpherePtsVectorized(point[None,:],rad,N) - cctbx_values = generate_probes_np(point[None,:],rad,N) - assert np.all(np.isclose(mapq_values,cctbx_values,atol=1e-3)) - - # test vectorized over points - for rad in rads: - for N in Ns: - mapq_values = SpherePtsVectorized(points,rad,N) - cctbx_values = generate_probes_np(points,rad,N) - assert np.all(np.isclose(mapq_values,cctbx_values,atol=1e-3)) - - -def test_probe_masking(): - # test the progressive probe masking function against test data - atoms_xyz = np.array([ - [0,0,-1], - [0,0,1], - ]) - - # probes_xyz shape (2,4,3), (n_atoms,n_probes,3) - probes_xyz = np.array([ - [[0,0,-2], - [0,0,-0.5], - [0,0,0], - [0,0,0.5]], - - [[0,0,-2], - [0,0,-0.5], - [0,0,0], - [0,0,0.5]]]) - - atom_tree = KDTree(atoms_xyz) - - calculated_result = get_probe_mask(atom_tree,probes_xyz,r=1.4) - manual_result = np.array([[ True, True, False, False], - [False, False, False, True]]) - - - assert np.all(calculated_result==manual_result) - -def test_shell_probes(probe_allocation_method="progressive"): - # Test full progressive probe generation for a single shell - atoms_xyz = np.array([[ 5.276, 12.488, 16.069], - [ 5.649, 13.947, 16.076]]) - - if probe_allocation_method=="progressive": - shell_func = shell_probes_progressive - expected_probes = np.array([[[ 5.276 , 12.488 , 14.569 ], - [ 5.0515, 13.4037, 14.9023], - [ 4.0297, 12.4397, 15.2357], - [ 4.825 , 11.1476, 15.569 ], - [ 6.3669, 11.4721, 15.9023], - [ 4.0466, 12.6981, 16.9023], - [ 5.343 , 11.5476, 17.2357], - [ 5.276 , 12.488 , 17.569 ], - [ np.nan, np.nan, np.nan], - [ np.nan, np.nan, np.nan]], - - [[ 5.649 , 13.947 , 14.576 ], - [ 5.4245, 14.8627, 14.9093], - [ 4.4027, 13.8987, 15.2427], - [ 6.7399, 12.9311, 15.9093], - [ 7.0245, 14.5216, 16.2427], - [ 5.6032, 15.3605, 16.576 ], - [ 4.4196, 14.1571, 16.9093], - [ 5.716 , 13.0066, 17.2427], - [ 5.649 , 13.947 , 17.576 ], - [ np.nan, np.nan, np.nan]]]) - - elif probe_allocation_method == "precalculate": - shell_func = shell_probes_precalculate - expected_probes = np.array( - - [[[5.2760, 12.4880, 14.5690], - [5.0515, 13.4037, 14.9023], - [4.0297, 12.4397, 15.2357], - [4.8250, 11.1476, 15.5690], - [6.3669, 11.4721, 15.9023], - [6.6515, 13.0626, 16.2357], - [5.2302, 13.9015, 16.5690], - [4.0466, 12.6981, 16.9023], - [5.3430, 11.5476, 17.2357], - [5.2760, 12.4880, 17.5690]], - - [[5.6490, 13.9470, 14.5760], - [5.4245, 14.8627, 14.9093], - [4.4027, 13.8987, 15.2427], - [5.1980, 12.6066, 15.5760], - [6.7399, 12.9311, 15.9093], - [7.0245, 14.5216, 16.2427], - [5.6032, 15.3605, 16.5760], - [4.4196, 14.1571, 16.9093], - [5.7160, 13.0066, 17.2427], - [5.6490, 13.9470, 17.5760]]]) - - probes_xyz, _ = shell_func(atoms_xyz=atoms_xyz, - atoms_tree = None, - selection=None, - n_probes_target=8, - n_probes_max=10, - RAD=1.5, - rtol=0.9, - log = null_out()) - - if probe_allocation_method == "precalculate": - print(probes_xyz) - assert np.all(isclose_or_nan(probes_xyz,expected_probes,atol=1e-3)) - -def test_get_probes(probe_allocation_method="progressive"): - # Test the full progressive probe generation for multiple shells - - atoms_xyz = np.array([[ 5.276, 12.488, 16.069], - [ 5.649, 13.947, 16.076]]) - - params = group_args( - selection=None, - shells = np.array([0.0,0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1., 1.1, 1.2, 1.3, - 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. ]), - n_probes_target=8, - n_probes_max=16, - n_probes_min=4, - rtol=0.9, - nproc=1, - probe_allocation_method=probe_allocation_method, - log = null_out() - ) - - if probe_allocation_method == "progressive": - worker_func = _shell_probes_progressive_wrapper - sum_expected = 12343.8878 - elif probe_allocation_method == "precalculate": - worker_func = _shell_probes_precalculate_wrapper - sum_expected = 23337.6710 - - probes_xyz,probe_mask = get_probes(atoms_xyz=atoms_xyz, - params=params, - worker_func=worker_func, - log = null_out()) - - - sum_calc = probes_xyz[~np.isnan(np.around(probes_xyz,3))].sum() - - - print(probe_allocation_method,sum_calc) - assert np.all(np.isclose(sum_calc,sum_expected)), ( - "The sum of generated probes do not match previous values obtained from mapq. Debug probe generation." - ) - - -################################ -# Tests with real data -################################ - -def prepare_test_data(templates): - """ - Prepare folders with data files for each test - """ - - for i,template in enumerate(templates): - test_dir_name = template["data"]["name"] - - is_fragment = False - if template["data"]["fragment_iselection"] not in [None,[]]: - i_sel = template["data"]["fragment_iselection"] - is_fragment = True - test_dir = Path(test_dir_name) - - # make test directory and copy data - test_dir.mkdir(exist_ok=True) - templates[i]["data"]["test_dir"] = str(test_dir.absolute()) - model_path_base = Path(template["data"]["model_file_base"]) - map_path_base = Path(template["data"]["map_file_base"]) - model_path = test_dir / Path(f"model.pdb") - map_path = test_dir / Path(f"map.ccp4") - shutil.copyfile(model_path_base,model_path) - shutil.copyfile(map_path_base,map_path) - - # possibly make fragment files - if is_fragment: - dm = DataManager() - dm.process_model_file(str(model_path)) - model = dm.get_model() - sel = np.full(model.get_number_of_atoms(),False) - sel[i_sel] = True - model_sel = model.select(flex.bool(sel)) - dm.write_model_file(model_sel.model_as_pdb(),str(model_path),overwrite=True) - - # record in template the data in test directory - templates[i]["data"]["model_file"] = str(model_path) - templates[i]["data"]["map_file"] = str(map_path) - - return templates - -def run_test_template_mapq(template, - mapq_location=None, - mapq_debug_data_filename="debug_data_mapq.json"): - """ - Run mapq via Chimera on the command line. Load debug results - NOTE: The debug results rely on a modified version of mapq. The releaseed version does not write - all the intermediate data. - """ - assert mapq_location is not None - mapq_location = Path(mapq_location) - model_path = Path(template["data"]["model_file"]) - map_path = Path(template["data"]["map_file"]) - test_dir = Path(template["data"]["test_dir"]) - - # run program - mapq_executable = mapq_location / Path("mapq_cmd.py") - chimera_path = mapq_location / Path("../../../../../Chimera.app") - mapq_command = f"python {mapq_executable.absolute()} {chimera_path.absolute()} map={map_path.absolute()} pdb={model_path.absolute()} bfactor=1.0" - # q is stored in bfactor column of pdb, with: bfactor = f * (1.0-Qscore). The scale factor f is provided with the 'bfactor' arg - # Bfactor 'f' should not affect q result - print(f"Running mapq with command:") - print(mapq_command) - print("\n\n") - subprocess.run(mapq_command.split()) - debug_data = load_mapq_debug_data(test_dir) - return debug_data - - - -def load_mapq_debug_data(test_dir): - """ - Load the mapq intermediate results. Looks for a file 'debug_data_mapq.json' in - the test directory. - """ - - # anticipate output data file path - data_file = Path(test_dir,Path("debug_data_mapq.json")).absolute() - # load debug data - with open(data_file,"r") as fh: - debug_data = json.load(fh) - def _is_ragged(a): - # don't force arrays for ragged data - if isinstance(a, list): - # Check if all elements are lists and have the same length - if all(isinstance(i, list) for i in a): - length = len(a[0]) - return any(len(i) != length for i in a) - else: - # It's a list, but not a list of lists - return False - else: - # Not a list, so it's not a ragged array in the typical sense - return False - - debug_data = {key:np.array(value) if not _is_ragged(value) else value for key,value in debug_data.items()} - return debug_data - - -def run_test_template_cctbx(template): - """ - Run a test using the progressive method added to cctbx - """ - - - params = group_args( - selection=None, - shells = template["params"]["shells"], - n_probes_target=template["params"]["n_probes_target"], - n_probes_max=template["params"]["n_probes_max"], - n_probes_min=template["params"]["n_probes_min"], - rtol=template["params"]["rtol"], - nproc=template["params"]["nproc"], - probe_allocation_method = template["params"]["probe_allocation_method"], - log = null_out(), - ) - model_filename = template["data"]["model_file"] - map_filename = template["data"]["map_file"] - - param_args = [f"{key}={getattr(params,key)}" for key in params.keys() if key not in ["shells","log"]] - for shell in params.shells: - param_args.append(f"shells={shell}") - args = [model_filename,map_filename, "debug=True"] + param_args - print(args) - result = run_program(program_class=QscoreProgram,args=args) - result = {key:getattr(result,key) for key in result.keys()} # group_args to dict - return result - -def run_template(template,mapq_location=None): - print("Template") - print(json.dumps(template,indent=2)) - - # get data - debug_data = run_test_template_cctbx(template) - probe_xyz = debug_data["probe_xyz"] - probe_mask = debug_data["probe_mask"] - d_vals = debug_data["d_vals"] - g_vals = debug_data["g_vals"] - qscore_per_atom = debug_data["qscore_per_atom"] - - # Record sums - template["results"]["probe_sum"] = probe_xyz[~np.isnan(probe_xyz)].sum() - template["results"]["q_sum"] = qscore_per_atom.sum() - - if template["results"]["probe_sum_expected"] is not None: - assert np.isclose(template["results"]["probe_sum"],template["results"]["probe_sum_expected"],atol=1e-2) - if template["results"]["q_sum_expected"]: - assert np.isclose(template["results"]["q_sum"],template["results"]["q_sum_expected"],atol=1e-2) - - # Record all data - template["results"]["cctbx"] = debug_data - - # run mapq, check results with progressive - if mapq_location is not None: - if template["params"]["probe_allocation_method"] == "progressive": - debug_data_mapq = run_test_template_mapq(template,mapq_location = mapq_location) - - probe_xyz_mapq = debug_data_mapq["probe_xyz"] - probe_mask_mapq = debug_data_mapq["probe_mask"] - d_vals_mapq = debug_data_mapq["d_vals"] - g_vals_mapq = debug_data_mapq["g_vals"] - qscore_per_atom_mapq = debug_data_mapq["qscore_per_atom"] - - # Check probes - assert np.all(isclose_or_nan(probe_xyz,probe_xyz_mapq)) - assert np.all(isclose_or_nan(probe_mask,probe_mask_mapq)) - - # Check d and g - assert np.all(isclose_or_nan(d_vals,d_vals_mapq)) - assert np.all(isclose_or_nan(g_vals,g_vals_mapq)) - - # Check q - assert np.all(isclose_or_nan(qscore_per_atom,qscore_per_atom_mapq)) - - # Check q from actual pdb output file - test_dir = Path(template["data"]["test_dir"]) - model_path = Path(template["data"]["model_file"]) - map_path = Path(template["data"]["map_file"]) - dm = DataManager() - mapq_output_file = Path(test_dir, f"{model_path.stem}.pdb__Q__{map_path.stem}.ccp4.pdb") - _ = dm.process_model_file(str(mapq_output_file)) - model = dm.get_model() - pseudo_b = model.get_b_iso().as_numpy_array() - q_test = pseudo_b - # Round heavily to match bfactor - q_calc = np.around(qscore_per_atom,decimals=2) - assert set(q_test)==set(q_calc) - - # record sums - template["results"]["probe_sum"] = probe_xyz_mapq[~np.isnan(probe_xyz)].sum() - template["results"]["q_sum"] = qscore_per_atom_mapq.sum() - template["results"]["mapq"] = debug_data_mapq - return template - - -# a template to store configuration for a single test -test_template ={ - - "data":{ - "name":None, - "model_file":None, - "model_file_base":None, - "map_file":None, - "map_file_base":None, - "test_dir":None, - "fragment_iselection":None, # actually reduce the file - }, - "results":{ - "probe_sum":None, - "q_sum":None, - "probe_sum_expected":None, - "q_sum_expected":None, - }, - "params":{ - "selection":None, # Just calculate q score for a sub-selection - "iselection":None, - "shells": [0.0,0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1., 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. ], - "n_probes_target":8, - "n_probes_max":16, - "n_probes_min":4, - "nproc":4, - "probe_allocation_method":"progressive", - "rtol":0.9, - } -} - -<<<<<<< Updated upstream -if (__name__ == "__main__"): - """ - Test random files to verify basic functionality remains unchanged - Data from phenix_regression/real_space_refine/data - """ - for test_name in [17]: # [17,42,48]: - exercise(test_name) - print("OK") -======= def run_test(test): if isinstance(test,dict): @@ -807,7 +357,7 @@ def build_tests(test_dir="qscore_tst_dir"): test["params"]["probe_allocation_method"] = "precalculate" test["params"]["backend"] = "flex" test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom - tests[test["data"]["name"]] = test + #tests[test["data"]["name"]] = test # tst2 progressive (numpy) test = copy.deepcopy(test_template) @@ -877,7 +427,7 @@ def build_tests(test_dir="qscore_tst_dir"): test["params"]["probe_allocation_method"] = "precalculate" test["params"]["backend"] = "flex" test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom - tests[test["data"]["name"]] = test + #tests[test["data"]["name"]] = test # progressive (numpy) test = copy.deepcopy(test_template) @@ -947,7 +497,7 @@ def build_tests(test_dir="qscore_tst_dir"): test["params"]["probe_allocation_method"] = "precalculate" test["params"]["backend"] = "flex" test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom - tests[test["data"]["name"]] = test + #tests[test["data"]["name"]] = test #7 tst2 with shift_and_box (numpy,precalculate) @@ -1003,7 +553,7 @@ def build_tests(test_dir="qscore_tst_dir"): test["params"]["probe_allocation_method"] = "precalculate" test["params"]["backend"] = "flex" test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom - tests[test["data"]["name"]] = test + #tests[test["data"]["name"]] = test # tst2, shift_and_box, progressive, numpy test = copy.deepcopy(test_template) @@ -1058,4 +608,3 @@ def build_tests(test_dir="qscore_tst_dir"): tests = build_tests() for test_name,test in tests.items(): test = run_test(test) ->>>>>>> Stashed changes From fa2604bd8b2333dea9934727bea141f2eec7f6bb Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 6 Feb 2024 14:36:34 -0800 Subject: [PATCH 111/748] Qscore: adding all the flex code after git stash incident --- cctbx/maptbx/qscore.py | 536 +++++++++++++++++++++++++++++++++++++ cctbx/maptbx/tst_qscore.py | 68 +++-- 2 files changed, 582 insertions(+), 22 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index 241199d108..3896356dcb 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -1,5 +1,6 @@ import sys from multiprocessing import Pool +from itertools import chain import numpy as np import numpy.ma as ma from scipy.spatial import KDTree @@ -12,6 +13,89 @@ #### Probe generation functions ################################################################################ +def SpherePtsVectorized ( ctr, rad, N ) : + """ + Function for generating points on a sphere. For testing only. + It retains the original mapq code pattern + """ + thetas, phis = [], [] + from math import acos, sin, cos, sqrt, pi + for k in range ( 1, N+1 ) : + h = -1.0 + ( 2.0*float(k-1)/float(N-1) ) + phis.append ( acos(h) ) + thetas.append ( 0 if k == 1 or k == N else + (thetas[k-2] + 3.6/sqrt(N*(1.0-h**2.0))) % (2*pi) ) + + pts = [None] * N + for i, theta, phi in zip ( range(N), thetas, phis ): + v = np.array([ sin(phi)*cos(theta), sin(phi)*sin(theta), cos(phi)]) + + pt = ctr + v * rad + pts[i] = pt + pts = np.array(pts) + pts = pts.swapaxes(0,1) + return pts + + + +# Generate Points with flex + +def cumsum_flex(arr): + """ + Return an array that is the cumulative sum of arr + Analogous to np.cumsum + """ + result = flex.double(len(arr)) + running_sum = 0.0 + for i, x in enumerate(arr): + running_sum += x + result[i] = running_sum + return result + +def broadcast_add_vec3(ctr, points): + """ + Broadcast add two flex.vec3_double arrays. + + Params: + ctr (flex.vec3_double): the 'center' coordinates + points (flex.vec3_double): the points that will be added to each ctr + + Returns: + result (flex.vec3_double): array of shape (N*M,3), 1 point for each center + """ + N = points.size() + M = ctr.size() + extended_ctr = flex.vec3_double() + extended_points = flex.vec3_double() + + # Extend ctr and points + for point in ctr: + extended_ctr.extend(flex.vec3_double([point] * N)) + for _ in range(M): + extended_points.extend(points) + + # Perform addition + result = flex.vec3_double(M * N) + space =flex.size_t_range(M*N) + for i in space: + pt = extended_ctr[i:i+1] + extended_points[i:i+1] + result=result.set_selected(space[i:i+1],pt) + return result + + + +def generate_probes_flex(ctr, rad, N): + """ + TODO: replace with actual flex code. Code lost during failed git stash + """ + ctr = np.array(ctr) + + out= generate_probes_np(ctr,rad,N) + n_atoms,_ = ctr.shape + out = out.reshape((n_atoms*N,3)) + return flex.vec3_double(out) + + # Fast numpy version def generate_probes_np(atoms_xyz, rad, n_probes): """ @@ -258,6 +342,10 @@ def get_probes( if atoms_tree is None: atoms_tree = KDTree(atoms_xyz) selection_bool = selection_bool_np + elif params.backend == "flex": + if atoms_tree is None: + atoms_tree = KDTreeFlex(atoms_xyz) + selection_bool = selection_bool_flex else: assert False, f"Unrecognized backend: {params.backend}" @@ -704,3 +792,451 @@ def cctbx_atoms_to_df(atoms): return df_atoms +################################################################################ +#### CCTBX flex-based functions (precalculate mode) +################################################################################ +def shell_probes_precalculate_flex( + atoms_xyz=None, # sites_cart. Flex vec3_double + atoms_tree=None, # A KDTree + selection_bool=None, # Boolean atom selection + n_probes_target=8,# The desired number of probes per shell + n_probes_max=16, # The maximum number of probes allowed + n_probes_min=4, # The min number of probes allowed without error + RAD=1.5, # The nominal radius of this shell + rtol=0.9, # Multiplied with RAD to get actual radius + log = null_out(), + strict = False, + ): + """ + Generate probes by precalculating for a single shell (radius) + """ + + # Do input validation + if not atoms_tree: + assert atoms_tree is None, ("If not providing an atom tree,\ + provide a 2d atom coordinate array to build tree") + + # make atom kdtree + atoms_tree = KDTreeFlex(atoms_xyz) + + # Manage log + if log is None: + log = null_out() + + # manage selection input + + if selection_bool is None: + selection_bool = flex.bool(len(atoms_xyz),True) + + + # do selection + sites_sel = atoms_xyz.select(selection_bool) + n_atoms = len(sites_sel) + + # get probe coordinates + probe_sites = generate_probes_flex(sites_sel, RAD, n_probes_max) + + + # modify "real" radius as in mapq + outRAD = RAD*rtol + + # query kdtree to get neighbors and their distances + dists,atom_indices = atoms_tree.query(probe_sites,k=2) + atom_indices_flat = flex_from_list(atom_indices) + + # Perform equivalent to atom_indices[:,:,0] if (n_atoms,n_probes,k) + dim0_indices = flex.size_t_range(0, n_atoms*n_probes_max*2, 2) + atom_indices_flat = atom_indices_flat.select(dim0_indices) + + # Build an index array that would be expected if each probe is near "its" atom + row_indices_flat = flex.size_t([ + i for i in range(n_atoms) for _ in range(n_probes_max)]) + + + # Mask for whether each probe's nearest atom is the one expected + expected_mask = row_indices_flat == atom_indices_flat + + + # A second mask to determine if the second nearest neighbor should be rejected + # (whether the second nearest neighbor is within the rejection radius) + dists = flex_from_list(dists) + # perform equivalent selcetion to dists[:,:,1] if (n_atoms,n_probes,k) + dist_dim1_sel = flex.size_t([i * 2 + 1 for i in range(n_atoms * n_probes_max)]) + dists_dim1 = dists.select(dist_dim1_sel) + within_r_mask = dists_dim1 1: + flex_array.reshape(flex.grid(*shape)) + return flex_array + + +def flatten_and_shape(lst): + """Flatten a nested list and return its shape.""" + def helper(l): + if not isinstance(l, list): + return [l], () + flat = [] + shapes = [] + for item in l: + f, s = helper(item) + flat.extend(f) + shapes.append(s) + if len(set(shapes)) != 1: + raise ValueError("Ragged nested list detected.") + return flat, (len(l),) + shapes[0] + + flattened, shape = helper(lst) + return flattened, shape + + +def get_dtype_of_list(lst): + dtypes = {type(item) for item in lst} + + if len(dtypes) > 1: + raise ValueError("Multiple data types detected.") + elif len(dtypes) == 0: + raise ValueError("Empty list provided.") + else: + return dtypes.pop() + + +def nd_to_1d_indices(indices, shape): + """Generate the 1d indices given nd indices and an array shape""" + # Normalize indices to always use slice objects + normalized_indices = [] + for dim, idx in enumerate(indices): + if idx is None: + normalized_indices.append(slice(0, shape[dim])) + else: + normalized_indices.append(idx) + + # If any index is a slice, recursively call function for each value in slice + for dim, (i, s) in enumerate(zip(normalized_indices, shape)): + if isinstance(i, slice): + result_indices = [] + start, stop, step = i.indices(s) + for j in range(start, stop, step): + new_indices = list(normalized_indices) + new_indices[dim] = j + result_indices.extend(nd_to_1d_indices(new_indices, shape)) + return result_indices + + # If no slices, calculate single 1D index + index = 0 + stride = 1 + for i, dim in reversed(list(zip(normalized_indices, shape))): + index += i * stride + stride *= dim + return [index] + + +def cdist_flex(A, B): + """A flex implementation of the cdist function""" + + def indices_2d_flex(dimensions): + N = len(dimensions) + if N != 2: + raise ValueError("Only 2D is supported for this implementation.") + + # Create the row indices + row_idx = flex.size_t(chain.from_iterable( + [[i] * dimensions[1] for i in range(dimensions[0])])) + + # Create the column indices + col_idx = flex.size_t(chain.from_iterable( + [list(range(dimensions[1])) for _ in range(dimensions[0])])) + + return row_idx, col_idx + + i_idxs, j_idxs = indices_2d_flex((A.focus()[0], B.focus()[0])) + + r = i_idxs + xi = i_idxs*3 + yi = i_idxs*3 + 1 + zi = i_idxs*3 + 2 + + xa = A.select(xi) + ya = A.select(yi) + za = A.select(zi) + + xj = j_idxs*3 + yj = j_idxs*3 + 1 + zj = j_idxs*3 + 2 + + xb = B.select(xj) + yb = B.select(yj) + zb = B.select(zj) + + d = ((xb - xa)**2 + (yb - ya)**2 + (zb - za)**2)**0.5 + d.reshape(flex.grid((A.focus()[0], B.focus()[0]))) + + return d + +################################################################################ +#### KDTree implementation using flex arrays (no numpy/scipy) +################################################################################ +class KDTreeFlexNode: + def __init__(self, index, point, left=None, right=None): + self.index = index + self.point = point + self.left = left + self.right = right + + +class KDTreeFlex: + def __init__(self, points): + self.dims = len(points[0]) + self.axis_sorted_indices = self.pre_sort_indices(points) + self.root = self.build_tree(flex.size_t_range(len(points)), points, 0) + + + def pre_sort_indices(self, points): + # Sort indices for each axis and return the sorted indices + x,y,z = points.parts() + sorted_indices = [flex.sort_permutation(x),flex.sort_permutation(y),flex.sort_permutation(z)] + return sorted_indices + + def build_tree(self, indices, points, depth): + if not indices: + return None + + axis = depth % self.dims + + + sorted_indices = self.axis_sorted_indices[axis] + + + # Step 4: Create an empty boolean mask of length N, initially set to False + mask = flex.bool(len(sorted_indices),False) + + # Directly set mask to True for positions in your query array + mask.set_selected(indices,True) + + # Step 5: Apply the mask to the sorted indices, then use this to create a sorted mask + # This step seems to be where you're looking to optimize. + # To directly use the sorted_indices to index into 'mask' and maintain sorting: + sorted_mask = mask.select(sorted_indices) + + # Now, apply this sorted_mask to select from the sorted_indices + sorted_indices_this_axis = sorted_indices.select(sorted_mask) + + + if len(sorted_indices_this_axis) == 0: + return None + + median_idx = len(sorted_indices_this_axis) // 2 + median_index = sorted_indices_this_axis[median_idx] + + left_indices = sorted_indices_this_axis[:median_idx] + right_indices = sorted_indices_this_axis[median_idx + 1:] + + return KDTreeFlexNode( + median_index, + points[median_index:median_index+1], + left=self.build_tree(left_indices, points, depth + 1), + right=self.build_tree(right_indices, points, depth + 1) + ) + def _nearest_neighbor(self, root, point, depth=0, best=None, k=1): + if root is None: + return best + + if best is None: + best = [] + + axis = depth % self.dims + next_branch = root.left if point[0][axis] < root.point[0][axis] else root.right + opposite_branch = root.right if next_branch is root.left else root.left + + # Recursively search the next branch + best = self._nearest_neighbor(next_branch, point, depth + 1, best, k) + + # Check the current root distance + current_dist = root.point.max_distance(point) + if len(best) < k or current_dist < best[-1]['dist']: + best.append({'index': root.index, 'dist': current_dist}) + best.sort(key=lambda x: x['dist']) + best = best[:k] # Keep only k nearest + + # Check if we need to search the opposite branch + if len(best) < k or abs(point[0][axis] - root.point[0][axis]) < best[-1]['dist']: + best = self._nearest_neighbor(opposite_branch, point, depth + 1, best, k) + + return best + + def query(self, query_points, k=1): + dists, inds = [], [] + for i,point in enumerate(query_points): + nearest = self._nearest_neighbor(self.root, query_points[i:i+1], k=k) + dists.append([n['dist'] for n in nearest]) + inds.append([n['index'] for n in nearest]) + return dists, inds + diff --git a/cctbx/maptbx/tst_qscore.py b/cctbx/maptbx/tst_qscore.py index 5443047d2e..f152963373 100644 --- a/cctbx/maptbx/tst_qscore.py +++ b/cctbx/maptbx/tst_qscore.py @@ -17,12 +17,14 @@ from cctbx.maptbx.qscore import ( generate_probes_np, + generate_probes_flex, get_probe_mask, shell_probes_progressive, shell_probes_precalculate, - #shell_probes_precalculate_flex, + shell_probes_precalculate_flex, calc_qscore, - #calc_qscore_flex + calc_qscore_flex, + KDTreeFlex ) @@ -58,10 +60,15 @@ def test_probe_generation(): [ 5.7034, 14.0191, 16.1189], [ 5.5845, 13.9741, 16.1474], [ 5.649 , 13.947 , 16.176 ]]]) - + # np probes_xyz = generate_probes_np(atoms_xyz,0.1,8) assert np.all(np.isclose(probes_xyz,probes_expected,atol=1e-3)) + # flex + atoms_xyz = flex.vec3_double(atoms_xyz) + probes_xyz = np.array(generate_probes_flex(atoms_xyz,0.1,8)).reshape((2,8,3)) + assert np.all(np.isclose(probes_xyz,probes_expected,atol=1e-3)) + def test_probe_masking(): # test the progressive probe masking function against test data atoms_xyz = np.array([ @@ -171,23 +178,38 @@ def test_shell_probes(): assert np.all(isclose_or_nan(probe_xyz,expected_probes,atol=1e-3)) - # # test precalculate (flex) - # shell_func = shell_probes_precalculate_flex - # probe_xyz,probe_mask = shell_func( - # atoms_xyz=flex.vec3_double(atoms_xyz), - # atoms_tree = None, - # selection_bool=None, - # n_probes_target=8, - # n_probes_max=10, - # RAD=1.5, - # rtol=0.9, - # log = null_out()) + # test precalculate (flex) + shell_func = shell_probes_precalculate_flex + probe_xyz,probe_mask = shell_func( + atoms_xyz=flex.vec3_double(atoms_xyz), + atoms_tree = None, + selection_bool=None, + n_probes_target=8, + n_probes_max=10, + RAD=1.5, + rtol=0.9, + log = null_out()) + + # test at single shell + probe_xyz = np.array(probe_xyz) + probe_xyz = probe_xyz.reshape(expected_probes.shape) + assert np.all(isclose_or_nan(probe_xyz,expected_probes,atol=1e-3)) + + +def test_kdtree_flex(): + # make sure the custom kdtree returns same results as scipy + points_np = np.random.random((1000,3))*10 + points_np_query = np.random.random((100,3))*10 + tree = KDTree(points_np) + dists,inds = tree.query(points_np_query,k=3) - # # test at single shell - # probe_xyz = np.array(probe_xyz) - # probe_xyz = probe_xyz.reshape(expected_probes.shape) - # assert np.all(isclose_or_nan(probe_xyz,expected_probes,atol=1e-3)) + points_flex = flex.vec3_double(points_np) + points_flex_query = flex.vec3_double(points_np_query) + tree_flex = KDTreeFlex(points_flex) + dists_flex,inds_flex = tree_flex.query(points_flex_query,k=3) + assert np.all(np.isclose(np.array(dists_flex),dists)) + assert np.all(np.isclose(np.array(inds_flex),inds)) ################################################################################ #### Test templates for real data @@ -357,7 +379,7 @@ def build_tests(test_dir="qscore_tst_dir"): test["params"]["probe_allocation_method"] = "precalculate" test["params"]["backend"] = "flex" test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom - #tests[test["data"]["name"]] = test + tests[test["data"]["name"]] = test # tst2 progressive (numpy) test = copy.deepcopy(test_template) @@ -427,7 +449,7 @@ def build_tests(test_dir="qscore_tst_dir"): test["params"]["probe_allocation_method"] = "precalculate" test["params"]["backend"] = "flex" test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom - #tests[test["data"]["name"]] = test + tests[test["data"]["name"]] = test # progressive (numpy) test = copy.deepcopy(test_template) @@ -497,7 +519,7 @@ def build_tests(test_dir="qscore_tst_dir"): test["params"]["probe_allocation_method"] = "precalculate" test["params"]["backend"] = "flex" test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom - #tests[test["data"]["name"]] = test + tests[test["data"]["name"]] = test #7 tst2 with shift_and_box (numpy,precalculate) @@ -553,7 +575,7 @@ def build_tests(test_dir="qscore_tst_dir"): test["params"]["probe_allocation_method"] = "precalculate" test["params"]["backend"] = "flex" test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom - #tests[test["data"]["name"]] = test + tests[test["data"]["name"]] = test # tst2, shift_and_box, progressive, numpy test = copy.deepcopy(test_template) @@ -602,6 +624,8 @@ def build_tests(test_dir="qscore_tst_dir"): #3. test single shell probe generation test_shell_probes() + #4. test flex kdtree + test_kdtree_flex() # Test on some real models From 1a29ef9144f010d45315f4deeff040b4c55caf0f Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 6 Feb 2024 14:38:37 -0800 Subject: [PATCH 112/748] Clean clutter --- cctbx/maptbx/qscore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index 3896356dcb..87941b1586 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -1,4 +1,4 @@ -import sys +from __future__ import division from multiprocessing import Pool from itertools import chain import numpy as np From b1e4ef5aad31b82811022ac73452599d30155fcd Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 6 Feb 2024 19:03:27 -0800 Subject: [PATCH 113/748] Qscore: fix qscore code after git stash incident --- cctbx/programs/qscore.py | 114 --------------------------------------- 1 file changed, 114 deletions(-) diff --git a/cctbx/programs/qscore.py b/cctbx/programs/qscore.py index 79a09b6f48..f2294b543e 100644 --- a/cctbx/programs/qscore.py +++ b/cctbx/programs/qscore.py @@ -1,11 +1,4 @@ from __future__ import absolute_import, division, print_function -<<<<<<< Updated upstream -from phenix.program_template import ProgramTemplate -from libtbx import group_args -from cctbx.maptbx.qscore import qscore_np - -======= - import json from pathlib import Path @@ -17,7 +10,6 @@ cctbx_atoms_to_df, write_bild_spheres ) ->>>>>>> Stashed changes import numpy as np # ============================================================================= @@ -30,56 +22,8 @@ class Program(ProgramTemplate): datatypes = ['phil', 'model', 'real_map'] -<<<<<<< Updated upstream - master_phil_str = """ - nproc = 8 - .type = int - .help = Number of processors to use - .short_caption = Number of processors to use - .expert_level = 1 - n_probes = 32 - .type = int - .help = Number of radial probes to use - .short_caption = Number of radial probes to use - .expert_level = 1 - selection = None - .type = str - .help = Only test atoms within this selection - .short_caption = Only test atoms within this selection - .expert_level = 1 - - shell_radius_start = 0.1 - .type = float - .help = Start testing density at this radius from atom - .short_caption = Start testing density at this radius from atom - .expert_level = 1 - - shell_radius_stop = 2 - .type = float - .help = Stop testing density at this radius from atom - .short_caption = Stop testing density at this radius from atom - .expert_level = 1 - - shell_radius_num = 20 - .type = int - .help = The number of radial shells - .short_caption = The number of radial shells (includes start/stop, so minimum 2) - .expert_level = 1 - - probe_allocation_method = precalculate - .type = str - .help = The method used to allocate radial probes - .short_caption = Either 'progressive' or 'precalculate'. Progressive is the original method \ - where probes are proposed and rejected iteratively. \ - Precalculate is a method where probes are pre-allocated and \ - rejected once. Parallelization is done by radial shell. \ - Precalculate is much faster but will yield slightly different results. - - -======= master_phil_str = """ include scope cctbx.maptbx.qscore.master_phil_str ->>>>>>> Stashed changes """ def validate(self): @@ -87,58 +31,6 @@ def validate(self): "numpy","flex" ], "Provide one of 'numpy', 'flex'" -<<<<<<< Updated upstream - def run(self): - print("Running") - - # do selection - mmm = self.data_manager.get_map_model_manager() - if self.params.qscore.selection != None: - selection = np.where(mmm.model().selection(self.params.qscore.selection).as_numpy_array())[0] - if len(selection)==0: - print("Finished... nothing selected") - self.result = group_args() - return - self.params.qscore.selection = selection - - # calculate shells - - if len(self.params.qscore.shells) ==0 : - start = self.params.qscore.shell_radius_start - stop = self.params.qscore.shell_radius_stop - num = self.params.qscore.shell_radius_num - shells = list(np.linspace( - start, - stop, - num, - endpoint=True)) - for shell in shells: - self.params.qscore.shells.append(shell) - - - # unsort model, make new mmm - model = self._unsort_model(mmm.model()) - # ignore hydrogens - model = model.select(model.selection("not element H")) - - # make mmm - mmm.set_model(model,overwrite=True) - - - # run qscore - qscore_result= qscore.calc_qscore( - mmm, - self.params.qscore, - log=self.logger) - - - self.result = group_args(**qscore_result) - - - - def get_results(self): - return self.result -======= assert self.params.qscore.probe_allocation_method in [ "progressive", "precalculate" ], "Provide one of 'progressive' or 'precalculate'" @@ -182,11 +74,6 @@ def run(self): self.result = group_args(**qscore_result) - # # save as dataframe - # df = cctbx_atoms_to_df(model.get_atoms()) - # df["Q-score"] = self.result.qscore_per_atom - # self.result.qscore_dataframe = - self.write_results() @@ -218,4 +105,3 @@ def write_results(self): probe_xyz_flat = probe_xyz.reshape((n_atoms*n_probes,3)) out_file = Path(debug_path,f"probes_shell_{shell}.bild") write_bild_spheres(probe_xyz_flat,str(out_file),r=0.2) ->>>>>>> Stashed changes From e77867d86335d4067ae4d94fa4f7e59416172b4e Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 6 Feb 2024 19:05:05 -0800 Subject: [PATCH 114/748] Remove unused function --- cctbx/maptbx/qscore.py | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index 87941b1586..bc0f8e80be 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -13,30 +13,6 @@ #### Probe generation functions ################################################################################ -def SpherePtsVectorized ( ctr, rad, N ) : - """ - Function for generating points on a sphere. For testing only. - It retains the original mapq code pattern - """ - thetas, phis = [], [] - from math import acos, sin, cos, sqrt, pi - for k in range ( 1, N+1 ) : - h = -1.0 + ( 2.0*float(k-1)/float(N-1) ) - phis.append ( acos(h) ) - thetas.append ( 0 if k == 1 or k == N else - (thetas[k-2] + 3.6/sqrt(N*(1.0-h**2.0))) % (2*pi) ) - - pts = [None] * N - for i, theta, phi in zip ( range(N), thetas, phis ): - v = np.array([ sin(phi)*cos(theta), sin(phi)*sin(theta), cos(phi)]) - - pt = ctr + v * rad - pts[i] = pt - pts = np.array(pts) - pts = pts.swapaxes(0,1) - return pts - - # Generate Points with flex From 8dfab519e2997880c358811996c64ba010bb498e Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 6 Feb 2024 19:13:40 -0800 Subject: [PATCH 115/748] Fix mp bug --- cctbx/maptbx/qscore.py | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index bc0f8e80be..1810f67b65 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -325,28 +325,33 @@ def get_probes( else: assert False, f"Unrecognized backend: {params.backend}" - - kwargs_list = [ + task_list = [ { - "atoms_xyz":atoms_xyz, # A numpy array of shape (N,3) - "atoms_tree":atoms_tree, # An atom_xyz scipy kdtree - "selection_bool":selection_bool,# Boolean atom selection - "n_probes_target":params.n_probes_target,# The desired number of probes per shell - "n_probes_max":params.n_probes_max, # The maximum number of probes allowed - "n_probes_min":params.n_probes_min, - "RAD":RAD, # The nominal radius of this shell - "rtol":params.rtol, # Multiplied with RAD to get actual radius - "log":log, + "func": worker_func, # Specify the function to call + "kwargs": { + "atoms_xyz": atoms_xyz, # A numpy array of shape (N,3) + "atoms_tree": atoms_tree, # An atom_xyz scipy kdtree + "selection_bool": selection_bool, # Boolean atom selection + "n_probes_target": params.n_probes_target, # The desired number of probes per shell + "n_probes_max": params.n_probes_max, # The maximum number of probes allowed + "n_probes_min": params.n_probes_min, + "RAD": RAD, # The nominal radius of this shell + "rtol": params.rtol, # Multiplied with RAD to get actual radius + "log": log, } - for RAD in params.shells] - #DEBUG - if params.nproc=="DEBUG": + } for RAD in params.shells + ] + + if params.nproc>1: with Pool() as pool: - results = pool.map(starmap_wrapper, kwargs_list) + print(params.nproc) + results = pool.map(starmap_wrapper, task_list) else: results = [] - for kwarg in kwargs_list: - result = worker_func(**kwarg) + for task in task_list: + worker_func = task["func"] + kwargs = task["kwargs"] + result = worker_func(**kwargs) results.append(result) @@ -995,7 +1000,6 @@ def calculate_1d_indices_for_atom(n_shells, n_atoms, n_probes, atom_idx): ############################################################################### - def flex_from_list(lst, signed_int=False): """Generate a flex array from a list, try to infer type""" flat_list, shape = flatten_and_shape(lst) From 64c7fb3a3575157c61a14e276c5de2e23aeebd88 Mon Sep 17 00:00:00 2001 From: cschlick Date: Wed, 7 Feb 2024 00:59:43 -0800 Subject: [PATCH 116/748] Qscore: fix residue aggregation bug --- cctbx/maptbx/qscore.py | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index 1810f67b65..5df05d0424 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -668,28 +668,23 @@ def aggregate_qscore_per_residue(model,qscore_per_atom,window=3): }) - # group atoms into residues - df["rg_index"] = df.groupby(["chain_id","resseq","resname"]).ngroup() + df["rg_index"] = df.groupby(["chain_id", "resseq", "resname"]).ngroup() + grouped_means = df.groupby(['chain_id', "resseq", "resname", "rg_index"], + as_index=False)['Q-score'].mean().rename( + columns={'Q-score': 'Q-Residue'}) - # average qscore by residue - grouped_means = df.groupby(['chain_id',"resseq","resname","rg_index"],as_index=False)['Q-score'].mean() - # DEBUG: + grouped_means['RollingMean'] = None # Initialize column to avoid KeyError - if 'Q-score' not in grouped_means.columns: - import pdb - pdb.set_trace() + for chain_id, group in grouped_means.groupby("chain_id"): + # Your actual variable rolling mean calculation here + rolling_means = variable_neighbors_rolling_mean(group['Q-Residue'], window) + grouped_means.loc[group.index, 'RollingMean'] = rolling_means.values - # roll over residue means - for chain_id,group in grouped_means.groupby("chain_id"): - grouped_means.loc[group.index, "Q-scorePerResidue"] = variable_neighbors_rolling_mean(group["Q-score"],window).values - - - # now grouped means is a df with each row being a "residue" "QscoreRollingMean" is the per-residue value to match mapq - - # place back in atom df - df = df.merge(grouped_means[['rg_index', 'Q-scorePerResidue']], on='rg_index', how='left') - df.drop("rg_index",axis=1,inplace=True) + # Merge the updated 'Q-Residue' and 'RollingMean' back into the original DataFrame + df = df.merge(grouped_means[['rg_index', 'Q-Residue', 'RollingMean']], on='rg_index', how='left') + df.drop("rg_index", axis=1, inplace=True) + df["Q-scorePerResidue"] = df["RollingMean"].astype(float) return df def variable_neighbors_rolling_mean(series, window=3): From c8132cf4bb79e6a44b887671b12768b028745b90 Mon Sep 17 00:00:00 2001 From: cschlick Date: Thu, 8 Feb 2024 11:44:57 -0800 Subject: [PATCH 117/748] Fix py27 syntax --- cctbx/programs/qscore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cctbx/programs/qscore.py b/cctbx/programs/qscore.py index f2294b543e..0061ab5d59 100644 --- a/cctbx/programs/qscore.py +++ b/cctbx/programs/qscore.py @@ -103,5 +103,5 @@ def write_results(self): probe_xyz = self.result.probe_xyz[i] n_shells, n_atoms,n_probes,_ = self.result.probe_xyz.shape probe_xyz_flat = probe_xyz.reshape((n_atoms*n_probes,3)) - out_file = Path(debug_path,f"probes_shell_{shell}.bild") + out_file = Path(debug_path,"probes_shell_"+shell+".bild") write_bild_spheres(probe_xyz_flat,str(out_file),r=0.2) From 78042def4133c1aba564f63cd459da895adbd6b5 Mon Sep 17 00:00:00 2001 From: cschlick Date: Thu, 8 Feb 2024 12:15:19 -0800 Subject: [PATCH 118/748] Qscore: add phil string --- cctbx/maptbx/qscore.py | 666 ++++++++--------------------------------- 1 file changed, 120 insertions(+), 546 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index 5df05d0424..dc9344aade 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -1,76 +1,101 @@ from __future__ import division +from collections import defaultdict from multiprocessing import Pool -from itertools import chain + +from libtbx.utils import null_out +from cctbx.array_family import flex import numpy as np import numpy.ma as ma from scipy.spatial import KDTree import pandas as pd -from libtbx.utils import null_out -from cctbx.array_family import flex - -################################################################################ -#### Probe generation functions -################################################################################ -# Generate Points with flex -def cumsum_flex(arr): - """ - Return an array that is the cumulative sum of arr - Analogous to np.cumsum - """ - result = flex.double(len(arr)) - running_sum = 0.0 - for i, x in enumerate(arr): - running_sum += x - result[i] = running_sum - return result +master_phil_str = """ + qscore + { + + nproc = 16 + .type = int + .help = Number of processors to use + .short_caption = Number of processors to use + .expert_level = 1 + n_probes_target = 8 + .type = int + .help = Number of radial probes to use + .short_caption = Number of radial probes to use + .expert_level = 1 + n_probes_max = 16 + .type = int + .help = Max number of radial probes to use + .short_caption = Number of radial probes to use + .expert_level = 1 + n_probes_min = 4 + .type = int + .help = Min number of radial probes to use + .short_caption = Number of radial probes to use + .expert_level = 1 + selection = None + .type = str + .help = Only test atoms within this selection + .short_caption = Only test atoms within this selection + .expert_level = 1 + + shell_radius_start = 0.1 + .type = float + .help = Start testing density at this radius from atom + .short_caption = Start testing density at this radius from atom + .expert_level = 1 + + shell_radius_stop = 2 + .type = float + .help = Stop testing density at this radius from atom + .short_caption = Stop testing density at this radius from atom + .expert_level = 1 + + shell_radius_num = 20 + .type = int + .help = The number of radial shells + .short_caption = The number of radial shells (includes start/stop, so minimum 2) + .expert_level = 1 + + shells = None + .type = float + .multiple = True + .help = Explicitly provide radial shells + + rtol = 0.9 + .type = float + .help = Mapq rtol value, the "real" shell radii are r*rtol + + probe_allocation_method = precalculate + .type = str + .help = The method used to allocate radial probes + .short_caption = Either 'progressive' or 'precalculate'. Progressive is the original method \ + where probes are proposed and rejected iteratively. \ + Precalculate is a method where probes are pre-allocated and \ + rejected once. Parallelization is done by radial shell. \ + Precalculate is much faster but will yield slightly different results. + + progress = False + .type = bool + .help = Report progress + .short_caption = Report progress bar + .expert_level = 1 + + debug = False + .type = bool + .help = Return much more debug information + .short_caption = Returns a dictionary with additional debug information + .expert_level = 1 + } -def broadcast_add_vec3(ctr, points): """ - Broadcast add two flex.vec3_double arrays. - - Params: - ctr (flex.vec3_double): the 'center' coordinates - points (flex.vec3_double): the points that will be added to each ctr - - Returns: - result (flex.vec3_double): array of shape (N*M,3), 1 point for each center - """ - N = points.size() - M = ctr.size() - extended_ctr = flex.vec3_double() - extended_points = flex.vec3_double() - - # Extend ctr and points - for point in ctr: - extended_ctr.extend(flex.vec3_double([point] * N)) - for _ in range(M): - extended_points.extend(points) - - # Perform addition - result = flex.vec3_double(M * N) - space =flex.size_t_range(M*N) - for i in space: - pt = extended_ctr[i:i+1] + extended_points[i:i+1] - result=result.set_selected(space[i:i+1],pt) - return result - - - -def generate_probes_flex(ctr, rad, N): - """ - TODO: replace with actual flex code. Code lost during failed git stash - """ - ctr = np.array(ctr) - - out= generate_probes_np(ctr,rad,N) - n_atoms,_ = ctr.shape - out = out.reshape((n_atoms*N,3)) - return flex.vec3_double(out) +################################################################################ +#### Probe generation functions +################################################################################ # Fast numpy version def generate_probes_np(atoms_xyz, rad, n_probes): @@ -318,40 +343,31 @@ def get_probes( if atoms_tree is None: atoms_tree = KDTree(atoms_xyz) selection_bool = selection_bool_np - elif params.backend == "flex": - if atoms_tree is None: - atoms_tree = KDTreeFlex(atoms_xyz) - selection_bool = selection_bool_flex else: assert False, f"Unrecognized backend: {params.backend}" - task_list = [ + + kwargs_list = [ { - "func": worker_func, # Specify the function to call - "kwargs": { - "atoms_xyz": atoms_xyz, # A numpy array of shape (N,3) - "atoms_tree": atoms_tree, # An atom_xyz scipy kdtree - "selection_bool": selection_bool, # Boolean atom selection - "n_probes_target": params.n_probes_target, # The desired number of probes per shell - "n_probes_max": params.n_probes_max, # The maximum number of probes allowed - "n_probes_min": params.n_probes_min, - "RAD": RAD, # The nominal radius of this shell - "rtol": params.rtol, # Multiplied with RAD to get actual radius - "log": log, + "atoms_xyz":atoms_xyz, # A numpy array of shape (N,3) + "atoms_tree":atoms_tree, # An atom_xyz scipy kdtree + "selection_bool":selection_bool,# Boolean atom selection + "n_probes_target":params.n_probes_target,# The desired number of probes per shell + "n_probes_max":params.n_probes_max, # The maximum number of probes allowed + "n_probes_min":params.n_probes_min, + "RAD":RAD, # The nominal radius of this shell + "rtol":params.rtol, # Multiplied with RAD to get actual radius + "log":log, } - } for RAD in params.shells - ] - - if params.nproc>1: + for RAD in params.shells] + #DEBUG + if params.nproc=="DEBUG": with Pool() as pool: - print(params.nproc) - results = pool.map(starmap_wrapper, task_list) + results = pool.map(starmap_wrapper, kwargs_list) else: results = [] - for task in task_list: - worker_func = task["func"] - kwargs = task["kwargs"] - result = worker_func(**kwargs) + for kwarg in kwargs_list: + result = worker_func(**kwarg) results.append(result) @@ -668,23 +684,28 @@ def aggregate_qscore_per_residue(model,qscore_per_atom,window=3): }) - df["rg_index"] = df.groupby(["chain_id", "resseq", "resname"]).ngroup() - grouped_means = df.groupby(['chain_id', "resseq", "resname", "rg_index"], - as_index=False)['Q-score'].mean().rename( - columns={'Q-score': 'Q-Residue'}) + # group atoms into residues + df["rg_index"] = df.groupby(["chain_id","resseq","resname"]).ngroup() + + # average qscore by residue + grouped_means = df.groupby(['chain_id',"resseq","resname","rg_index"],as_index=False)['Q-score'].mean() + # DEBUG: + + if 'Q-score' not in grouped_means.columns: + import pdb + pdb.set_trace() + - grouped_means['RollingMean'] = None # Initialize column to avoid KeyError + # roll over residue means + for chain_id,group in grouped_means.groupby("chain_id"): + grouped_means.loc[group.index, "Q-scorePerResidue"] = variable_neighbors_rolling_mean(group["Q-score"],window).values - for chain_id, group in grouped_means.groupby("chain_id"): - # Your actual variable rolling mean calculation here - rolling_means = variable_neighbors_rolling_mean(group['Q-Residue'], window) - grouped_means.loc[group.index, 'RollingMean'] = rolling_means.values + # now grouped means is a df with each row being a "residue" "QscoreRollingMean" is the per-residue value to match mapq - # Merge the updated 'Q-Residue' and 'RollingMean' back into the original DataFrame - df = df.merge(grouped_means[['rg_index', 'Q-Residue', 'RollingMean']], on='rg_index', how='left') - df.drop("rg_index", axis=1, inplace=True) - df["Q-scorePerResidue"] = df["RollingMean"].astype(float) + # place back in atom df + df = df.merge(grouped_means[['rg_index', 'Q-scorePerResidue']], on='rg_index', how='left') + df.drop("rg_index",axis=1,inplace=True) return df def variable_neighbors_rolling_mean(series, window=3): @@ -768,450 +789,3 @@ def cctbx_atoms_to_df(atoms): return df_atoms -################################################################################ -#### CCTBX flex-based functions (precalculate mode) -################################################################################ -def shell_probes_precalculate_flex( - atoms_xyz=None, # sites_cart. Flex vec3_double - atoms_tree=None, # A KDTree - selection_bool=None, # Boolean atom selection - n_probes_target=8,# The desired number of probes per shell - n_probes_max=16, # The maximum number of probes allowed - n_probes_min=4, # The min number of probes allowed without error - RAD=1.5, # The nominal radius of this shell - rtol=0.9, # Multiplied with RAD to get actual radius - log = null_out(), - strict = False, - ): - """ - Generate probes by precalculating for a single shell (radius) - """ - - # Do input validation - if not atoms_tree: - assert atoms_tree is None, ("If not providing an atom tree,\ - provide a 2d atom coordinate array to build tree") - - # make atom kdtree - atoms_tree = KDTreeFlex(atoms_xyz) - - # Manage log - if log is None: - log = null_out() - - # manage selection input - - if selection_bool is None: - selection_bool = flex.bool(len(atoms_xyz),True) - - - # do selection - sites_sel = atoms_xyz.select(selection_bool) - n_atoms = len(sites_sel) - - # get probe coordinates - probe_sites = generate_probes_flex(sites_sel, RAD, n_probes_max) - - - # modify "real" radius as in mapq - outRAD = RAD*rtol - - # query kdtree to get neighbors and their distances - dists,atom_indices = atoms_tree.query(probe_sites,k=2) - atom_indices_flat = flex_from_list(atom_indices) - - # Perform equivalent to atom_indices[:,:,0] if (n_atoms,n_probes,k) - dim0_indices = flex.size_t_range(0, n_atoms*n_probes_max*2, 2) - atom_indices_flat = atom_indices_flat.select(dim0_indices) - - # Build an index array that would be expected if each probe is near "its" atom - row_indices_flat = flex.size_t([ - i for i in range(n_atoms) for _ in range(n_probes_max)]) - - - # Mask for whether each probe's nearest atom is the one expected - expected_mask = row_indices_flat == atom_indices_flat - - - # A second mask to determine if the second nearest neighbor should be rejected - # (whether the second nearest neighbor is within the rejection radius) - dists = flex_from_list(dists) - # perform equivalent selcetion to dists[:,:,1] if (n_atoms,n_probes,k) - dist_dim1_sel = flex.size_t([i * 2 + 1 for i in range(n_atoms * n_probes_max)]) - dists_dim1 = dists.select(dist_dim1_sel) - within_r_mask = dists_dim1 1: - flex_array.reshape(flex.grid(*shape)) - return flex_array - - -def flatten_and_shape(lst): - """Flatten a nested list and return its shape.""" - def helper(l): - if not isinstance(l, list): - return [l], () - flat = [] - shapes = [] - for item in l: - f, s = helper(item) - flat.extend(f) - shapes.append(s) - if len(set(shapes)) != 1: - raise ValueError("Ragged nested list detected.") - return flat, (len(l),) + shapes[0] - - flattened, shape = helper(lst) - return flattened, shape - - -def get_dtype_of_list(lst): - dtypes = {type(item) for item in lst} - - if len(dtypes) > 1: - raise ValueError("Multiple data types detected.") - elif len(dtypes) == 0: - raise ValueError("Empty list provided.") - else: - return dtypes.pop() - - -def nd_to_1d_indices(indices, shape): - """Generate the 1d indices given nd indices and an array shape""" - # Normalize indices to always use slice objects - normalized_indices = [] - for dim, idx in enumerate(indices): - if idx is None: - normalized_indices.append(slice(0, shape[dim])) - else: - normalized_indices.append(idx) - - # If any index is a slice, recursively call function for each value in slice - for dim, (i, s) in enumerate(zip(normalized_indices, shape)): - if isinstance(i, slice): - result_indices = [] - start, stop, step = i.indices(s) - for j in range(start, stop, step): - new_indices = list(normalized_indices) - new_indices[dim] = j - result_indices.extend(nd_to_1d_indices(new_indices, shape)) - return result_indices - - # If no slices, calculate single 1D index - index = 0 - stride = 1 - for i, dim in reversed(list(zip(normalized_indices, shape))): - index += i * stride - stride *= dim - return [index] - - -def cdist_flex(A, B): - """A flex implementation of the cdist function""" - - def indices_2d_flex(dimensions): - N = len(dimensions) - if N != 2: - raise ValueError("Only 2D is supported for this implementation.") - - # Create the row indices - row_idx = flex.size_t(chain.from_iterable( - [[i] * dimensions[1] for i in range(dimensions[0])])) - - # Create the column indices - col_idx = flex.size_t(chain.from_iterable( - [list(range(dimensions[1])) for _ in range(dimensions[0])])) - - return row_idx, col_idx - - i_idxs, j_idxs = indices_2d_flex((A.focus()[0], B.focus()[0])) - - r = i_idxs - xi = i_idxs*3 - yi = i_idxs*3 + 1 - zi = i_idxs*3 + 2 - - xa = A.select(xi) - ya = A.select(yi) - za = A.select(zi) - - xj = j_idxs*3 - yj = j_idxs*3 + 1 - zj = j_idxs*3 + 2 - - xb = B.select(xj) - yb = B.select(yj) - zb = B.select(zj) - - d = ((xb - xa)**2 + (yb - ya)**2 + (zb - za)**2)**0.5 - d.reshape(flex.grid((A.focus()[0], B.focus()[0]))) - - return d - -################################################################################ -#### KDTree implementation using flex arrays (no numpy/scipy) -################################################################################ -class KDTreeFlexNode: - def __init__(self, index, point, left=None, right=None): - self.index = index - self.point = point - self.left = left - self.right = right - - -class KDTreeFlex: - def __init__(self, points): - self.dims = len(points[0]) - self.axis_sorted_indices = self.pre_sort_indices(points) - self.root = self.build_tree(flex.size_t_range(len(points)), points, 0) - - - def pre_sort_indices(self, points): - # Sort indices for each axis and return the sorted indices - x,y,z = points.parts() - sorted_indices = [flex.sort_permutation(x),flex.sort_permutation(y),flex.sort_permutation(z)] - return sorted_indices - - def build_tree(self, indices, points, depth): - if not indices: - return None - - axis = depth % self.dims - - - sorted_indices = self.axis_sorted_indices[axis] - - - # Step 4: Create an empty boolean mask of length N, initially set to False - mask = flex.bool(len(sorted_indices),False) - - # Directly set mask to True for positions in your query array - mask.set_selected(indices,True) - - # Step 5: Apply the mask to the sorted indices, then use this to create a sorted mask - # This step seems to be where you're looking to optimize. - # To directly use the sorted_indices to index into 'mask' and maintain sorting: - sorted_mask = mask.select(sorted_indices) - - # Now, apply this sorted_mask to select from the sorted_indices - sorted_indices_this_axis = sorted_indices.select(sorted_mask) - - - if len(sorted_indices_this_axis) == 0: - return None - - median_idx = len(sorted_indices_this_axis) // 2 - median_index = sorted_indices_this_axis[median_idx] - - left_indices = sorted_indices_this_axis[:median_idx] - right_indices = sorted_indices_this_axis[median_idx + 1:] - - return KDTreeFlexNode( - median_index, - points[median_index:median_index+1], - left=self.build_tree(left_indices, points, depth + 1), - right=self.build_tree(right_indices, points, depth + 1) - ) - def _nearest_neighbor(self, root, point, depth=0, best=None, k=1): - if root is None: - return best - - if best is None: - best = [] - - axis = depth % self.dims - next_branch = root.left if point[0][axis] < root.point[0][axis] else root.right - opposite_branch = root.right if next_branch is root.left else root.left - - # Recursively search the next branch - best = self._nearest_neighbor(next_branch, point, depth + 1, best, k) - - # Check the current root distance - current_dist = root.point.max_distance(point) - if len(best) < k or current_dist < best[-1]['dist']: - best.append({'index': root.index, 'dist': current_dist}) - best.sort(key=lambda x: x['dist']) - best = best[:k] # Keep only k nearest - - # Check if we need to search the opposite branch - if len(best) < k or abs(point[0][axis] - root.point[0][axis]) < best[-1]['dist']: - best = self._nearest_neighbor(opposite_branch, point, depth + 1, best, k) - - return best - - def query(self, query_points, k=1): - dists, inds = [], [] - for i,point in enumerate(query_points): - nearest = self._nearest_neighbor(self.root, query_points[i:i+1], k=k) - dists.append([n['dist'] for n in nearest]) - inds.append([n['index'] for n in nearest]) - return dists, inds - From cf9adb532103bbd7c08566e06dd76f2900d23aad Mon Sep 17 00:00:00 2001 From: cschlick Date: Thu, 8 Feb 2024 12:21:50 -0800 Subject: [PATCH 119/748] Qscore: Finishing merge from branch qscore_recovery --- cctbx/maptbx/qscore.py | 579 ++++++++++++++++++++++++++++++++++--- cctbx/maptbx/tst_qscore.py | 2 +- 2 files changed, 545 insertions(+), 36 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index dc9344aade..91f0bdad79 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -97,6 +97,65 @@ #### Probe generation functions ################################################################################ + +# Generate Points with flex + +def cumsum_flex(arr): + """ + Return an array that is the cumulative sum of arr + Analogous to np.cumsum + """ + result = flex.double(len(arr)) + running_sum = 0.0 + for i, x in enumerate(arr): + running_sum += x + result[i] = running_sum + return result + +def broadcast_add_vec3(ctr, points): + """ + Broadcast add two flex.vec3_double arrays. + + Params: + ctr (flex.vec3_double): the 'center' coordinates + points (flex.vec3_double): the points that will be added to each ctr + + Returns: + result (flex.vec3_double): array of shape (N*M,3), 1 point for each center + """ + N = points.size() + M = ctr.size() + extended_ctr = flex.vec3_double() + extended_points = flex.vec3_double() + + # Extend ctr and points + for point in ctr: + extended_ctr.extend(flex.vec3_double([point] * N)) + for _ in range(M): + extended_points.extend(points) + + # Perform addition + result = flex.vec3_double(M * N) + space =flex.size_t_range(M*N) + for i in space: + pt = extended_ctr[i:i+1] + extended_points[i:i+1] + result=result.set_selected(space[i:i+1],pt) + return result + + + +def generate_probes_flex(ctr, rad, N): + """ + TODO: replace with actual flex code. Code lost during failed git stash + """ + ctr = np.array(ctr) + + out= generate_probes_np(ctr,rad,N) + n_atoms,_ = ctr.shape + out = out.reshape((n_atoms*N,3)) + return flex.vec3_double(out) + + # Fast numpy version def generate_probes_np(atoms_xyz, rad, n_probes): """ @@ -343,31 +402,40 @@ def get_probes( if atoms_tree is None: atoms_tree = KDTree(atoms_xyz) selection_bool = selection_bool_np + elif params.backend == "flex": + if atoms_tree is None: + atoms_tree = KDTreeFlex(atoms_xyz) + selection_bool = selection_bool_flex else: assert False, f"Unrecognized backend: {params.backend}" - - kwargs_list = [ + task_list = [ { - "atoms_xyz":atoms_xyz, # A numpy array of shape (N,3) - "atoms_tree":atoms_tree, # An atom_xyz scipy kdtree - "selection_bool":selection_bool,# Boolean atom selection - "n_probes_target":params.n_probes_target,# The desired number of probes per shell - "n_probes_max":params.n_probes_max, # The maximum number of probes allowed - "n_probes_min":params.n_probes_min, - "RAD":RAD, # The nominal radius of this shell - "rtol":params.rtol, # Multiplied with RAD to get actual radius - "log":log, + "func": worker_func, # Specify the function to call + "kwargs": { + "atoms_xyz": atoms_xyz, # A numpy array of shape (N,3) + "atoms_tree": atoms_tree, # An atom_xyz scipy kdtree + "selection_bool": selection_bool, # Boolean atom selection + "n_probes_target": params.n_probes_target, # The desired number of probes per shell + "n_probes_max": params.n_probes_max, # The maximum number of probes allowed + "n_probes_min": params.n_probes_min, + "RAD": RAD, # The nominal radius of this shell + "rtol": params.rtol, # Multiplied with RAD to get actual radius + "log": log, } - for RAD in params.shells] - #DEBUG - if params.nproc=="DEBUG": + } for RAD in params.shells + ] + + if params.nproc>1: with Pool() as pool: - results = pool.map(starmap_wrapper, kwargs_list) + print(params.nproc) + results = pool.map(starmap_wrapper, task_list) else: results = [] - for kwarg in kwargs_list: - result = worker_func(**kwarg) + for task in task_list: + worker_func = task["func"] + kwargs = task["kwargs"] + result = worker_func(**kwargs) results.append(result) @@ -684,28 +752,23 @@ def aggregate_qscore_per_residue(model,qscore_per_atom,window=3): }) - # group atoms into residues - df["rg_index"] = df.groupby(["chain_id","resseq","resname"]).ngroup() - - # average qscore by residue - grouped_means = df.groupby(['chain_id',"resseq","resname","rg_index"],as_index=False)['Q-score'].mean() - # DEBUG: + df["rg_index"] = df.groupby(["chain_id", "resseq", "resname"]).ngroup() + grouped_means = df.groupby(['chain_id', "resseq", "resname", "rg_index"], + as_index=False)['Q-score'].mean().rename( + columns={'Q-score': 'Q-Residue'}) - if 'Q-score' not in grouped_means.columns: - import pdb - pdb.set_trace() + grouped_means['RollingMean'] = None # Initialize column to avoid KeyError + for chain_id, group in grouped_means.groupby("chain_id"): + # Your actual variable rolling mean calculation here + rolling_means = variable_neighbors_rolling_mean(group['Q-Residue'], window) + grouped_means.loc[group.index, 'RollingMean'] = rolling_means.values - # roll over residue means - for chain_id,group in grouped_means.groupby("chain_id"): - grouped_means.loc[group.index, "Q-scorePerResidue"] = variable_neighbors_rolling_mean(group["Q-score"],window).values - - # now grouped means is a df with each row being a "residue" "QscoreRollingMean" is the per-residue value to match mapq - - # place back in atom df - df = df.merge(grouped_means[['rg_index', 'Q-scorePerResidue']], on='rg_index', how='left') - df.drop("rg_index",axis=1,inplace=True) + # Merge the updated 'Q-Residue' and 'RollingMean' back into the original DataFrame + df = df.merge(grouped_means[['rg_index', 'Q-Residue', 'RollingMean']], on='rg_index', how='left') + df.drop("rg_index", axis=1, inplace=True) + df["Q-scorePerResidue"] = df["RollingMean"].astype(float) return df def variable_neighbors_rolling_mean(series, window=3): @@ -789,3 +852,449 @@ def cctbx_atoms_to_df(atoms): return df_atoms +################################################################################ +#### CCTBX flex-based functions (precalculate mode) +################################################################################ +def shell_probes_precalculate_flex( + atoms_xyz=None, # sites_cart. Flex vec3_double + atoms_tree=None, # A KDTree + selection_bool=None, # Boolean atom selection + n_probes_target=8,# The desired number of probes per shell + n_probes_max=16, # The maximum number of probes allowed + n_probes_min=4, # The min number of probes allowed without error + RAD=1.5, # The nominal radius of this shell + rtol=0.9, # Multiplied with RAD to get actual radius + log = null_out(), + strict = False, + ): + """ + Generate probes by precalculating for a single shell (radius) + """ + + # Do input validation + if not atoms_tree: + assert atoms_tree is None, ("If not providing an atom tree,\ + provide a 2d atom coordinate array to build tree") + + # make atom kdtree + atoms_tree = KDTreeFlex(atoms_xyz) + + # Manage log + if log is None: + log = null_out() + + # manage selection input + + if selection_bool is None: + selection_bool = flex.bool(len(atoms_xyz),True) + + + # do selection + sites_sel = atoms_xyz.select(selection_bool) + n_atoms = len(sites_sel) + + # get probe coordinates + probe_sites = generate_probes_flex(sites_sel, RAD, n_probes_max) + + + # modify "real" radius as in mapq + outRAD = RAD*rtol + + # query kdtree to get neighbors and their distances + dists,atom_indices = atoms_tree.query(probe_sites,k=2) + atom_indices_flat = flex_from_list(atom_indices) + + # Perform equivalent to atom_indices[:,:,0] if (n_atoms,n_probes,k) + dim0_indices = flex.size_t_range(0, n_atoms*n_probes_max*2, 2) + atom_indices_flat = atom_indices_flat.select(dim0_indices) + + # Build an index array that would be expected if each probe is near "its" atom + row_indices_flat = flex.size_t([ + i for i in range(n_atoms) for _ in range(n_probes_max)]) + + + # Mask for whether each probe's nearest atom is the one expected + expected_mask = row_indices_flat == atom_indices_flat + + + # A second mask to determine if the second nearest neighbor should be rejected + # (whether the second nearest neighbor is within the rejection radius) + dists = flex_from_list(dists) + # perform equivalent selcetion to dists[:,:,1] if (n_atoms,n_probes,k) + dist_dim1_sel = flex.size_t([i * 2 + 1 for i in range(n_atoms * n_probes_max)]) + dists_dim1 = dists.select(dist_dim1_sel) + within_r_mask = dists_dim1 1: + flex_array.reshape(flex.grid(*shape)) + return flex_array + + +def flatten_and_shape(lst): + """Flatten a nested list and return its shape.""" + def helper(l): + if not isinstance(l, list): + return [l], () + flat = [] + shapes = [] + for item in l: + f, s = helper(item) + flat.extend(f) + shapes.append(s) + if len(set(shapes)) != 1: + raise ValueError("Ragged nested list detected.") + return flat, (len(l),) + shapes[0] + + flattened, shape = helper(lst) + return flattened, shape + + +def get_dtype_of_list(lst): + dtypes = {type(item) for item in lst} + + if len(dtypes) > 1: + raise ValueError("Multiple data types detected.") + elif len(dtypes) == 0: + raise ValueError("Empty list provided.") + else: + return dtypes.pop() + + +def nd_to_1d_indices(indices, shape): + """Generate the 1d indices given nd indices and an array shape""" + # Normalize indices to always use slice objects + normalized_indices = [] + for dim, idx in enumerate(indices): + if idx is None: + normalized_indices.append(slice(0, shape[dim])) + else: + normalized_indices.append(idx) + + # If any index is a slice, recursively call function for each value in slice + for dim, (i, s) in enumerate(zip(normalized_indices, shape)): + if isinstance(i, slice): + result_indices = [] + start, stop, step = i.indices(s) + for j in range(start, stop, step): + new_indices = list(normalized_indices) + new_indices[dim] = j + result_indices.extend(nd_to_1d_indices(new_indices, shape)) + return result_indices + + # If no slices, calculate single 1D index + index = 0 + stride = 1 + for i, dim in reversed(list(zip(normalized_indices, shape))): + index += i * stride + stride *= dim + return [index] + + +def cdist_flex(A, B): + """A flex implementation of the cdist function""" + + def indices_2d_flex(dimensions): + N = len(dimensions) + if N != 2: + raise ValueError("Only 2D is supported for this implementation.") + + # Create the row indices + row_idx = flex.size_t(chain.from_iterable( + [[i] * dimensions[1] for i in range(dimensions[0])])) + + # Create the column indices + col_idx = flex.size_t(chain.from_iterable( + [list(range(dimensions[1])) for _ in range(dimensions[0])])) + + return row_idx, col_idx + + i_idxs, j_idxs = indices_2d_flex((A.focus()[0], B.focus()[0])) + + r = i_idxs + xi = i_idxs*3 + yi = i_idxs*3 + 1 + zi = i_idxs*3 + 2 + + xa = A.select(xi) + ya = A.select(yi) + za = A.select(zi) + + xj = j_idxs*3 + yj = j_idxs*3 + 1 + zj = j_idxs*3 + 2 + + xb = B.select(xj) + yb = B.select(yj) + zb = B.select(zj) + + d = ((xb - xa)**2 + (yb - ya)**2 + (zb - za)**2)**0.5 + d.reshape(flex.grid((A.focus()[0], B.focus()[0]))) + + return d + +################################################################################ +#### KDTree implementation using flex arrays (no numpy/scipy) +################################################################################ +class KDTreeFlexNode: + def __init__(self, index, point, left=None, right=None): + self.index = index + self.point = point + self.left = left + self.right = right + + +class KDTreeFlex: + def __init__(self, points): + self.dims = len(points[0]) + self.axis_sorted_indices = self.pre_sort_indices(points) + self.root = self.build_tree(flex.size_t_range(len(points)), points, 0) + + + def pre_sort_indices(self, points): + # Sort indices for each axis and return the sorted indices + x,y,z = points.parts() + sorted_indices = [flex.sort_permutation(x),flex.sort_permutation(y),flex.sort_permutation(z)] + return sorted_indices + + def build_tree(self, indices, points, depth): + if not indices: + return None + + axis = depth % self.dims + + + sorted_indices = self.axis_sorted_indices[axis] + + + # Step 4: Create an empty boolean mask of length N, initially set to False + mask = flex.bool(len(sorted_indices),False) + + # Directly set mask to True for positions in your query array + mask.set_selected(indices,True) + + # Step 5: Apply the mask to the sorted indices, then use this to create a sorted mask + # This step seems to be where you're looking to optimize. + # To directly use the sorted_indices to index into 'mask' and maintain sorting: + sorted_mask = mask.select(sorted_indices) + + # Now, apply this sorted_mask to select from the sorted_indices + sorted_indices_this_axis = sorted_indices.select(sorted_mask) + + + if len(sorted_indices_this_axis) == 0: + return None + + median_idx = len(sorted_indices_this_axis) // 2 + median_index = sorted_indices_this_axis[median_idx] + + left_indices = sorted_indices_this_axis[:median_idx] + right_indices = sorted_indices_this_axis[median_idx + 1:] + + return KDTreeFlexNode( + median_index, + points[median_index:median_index+1], + left=self.build_tree(left_indices, points, depth + 1), + right=self.build_tree(right_indices, points, depth + 1) + ) + def _nearest_neighbor(self, root, point, depth=0, best=None, k=1): + if root is None: + return best + + if best is None: + best = [] + + axis = depth % self.dims + next_branch = root.left if point[0][axis] < root.point[0][axis] else root.right + opposite_branch = root.right if next_branch is root.left else root.left + + # Recursively search the next branch + best = self._nearest_neighbor(next_branch, point, depth + 1, best, k) + + # Check the current root distance + current_dist = root.point.max_distance(point) + if len(best) < k or current_dist < best[-1]['dist']: + best.append({'index': root.index, 'dist': current_dist}) + best.sort(key=lambda x: x['dist']) + best = best[:k] # Keep only k nearest + + # Check if we need to search the opposite branch + if len(best) < k or abs(point[0][axis] - root.point[0][axis]) < best[-1]['dist']: + best = self._nearest_neighbor(opposite_branch, point, depth + 1, best, k) + + return best + + def query(self, query_points, k=1): + dists, inds = [], [] + for i,point in enumerate(query_points): + nearest = self._nearest_neighbor(self.root, query_points[i:i+1], k=k) + dists.append([n['dist'] for n in nearest]) + inds.append([n['index'] for n in nearest]) + return dists, inds \ No newline at end of file diff --git a/cctbx/maptbx/tst_qscore.py b/cctbx/maptbx/tst_qscore.py index f152963373..f2a85d7abd 100644 --- a/cctbx/maptbx/tst_qscore.py +++ b/cctbx/maptbx/tst_qscore.py @@ -631,4 +631,4 @@ def build_tests(test_dir="qscore_tst_dir"): # Test on some real models tests = build_tests() for test_name,test in tests.items(): - test = run_test(test) + test = run_test(test) \ No newline at end of file From 510316ec75a577d65283acbb119c51c6a9a7246d Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Sat, 10 Feb 2024 11:34:12 -0800 Subject: [PATCH 120/748] Clean clutter --- cctbx/maptbx/qscore.py | 2 +- cctbx/maptbx/tst_qscore.py | 2 +- mmtbx/model/model.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index 91f0bdad79..73f2e3fa34 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -1297,4 +1297,4 @@ def query(self, query_points, k=1): nearest = self._nearest_neighbor(self.root, query_points[i:i+1], k=k) dists.append([n['dist'] for n in nearest]) inds.append([n['index'] for n in nearest]) - return dists, inds \ No newline at end of file + return dists, inds diff --git a/cctbx/maptbx/tst_qscore.py b/cctbx/maptbx/tst_qscore.py index f2a85d7abd..f152963373 100644 --- a/cctbx/maptbx/tst_qscore.py +++ b/cctbx/maptbx/tst_qscore.py @@ -631,4 +631,4 @@ def build_tests(test_dir="qscore_tst_dir"): # Test on some real models tests = build_tests() for test_name,test in tests.items(): - test = run_test(test) \ No newline at end of file + test = run_test(test) diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index 551a4b8471..506058269e 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -1729,8 +1729,8 @@ def pdb_or_mmcif_string_info(self, # NOTE: Normally use the data_manager to write any files and use # tools in the hierarchy to manipulate any aspects of a hierarchy. - # If you need a pdb string, normally use as_pdb_or_mmcif_string - # instead of this general function + # If you need a pdb string, normally use as_pdb_or_mmcif_string + # instead of this general function # Note default of segid_as_auth_segid = True, different from # as_mmcif_string() From baeff833f2d81997e7d91277731da4e4cc45bc3b Mon Sep 17 00:00:00 2001 From: terwill Date: Sun, 11 Feb 2024 11:12:53 -0700 Subject: [PATCH 121/748] Add 2nd citation for mmseqs2 --- libtbx/citations.params | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libtbx/citations.params b/libtbx/citations.params index 96f368cea0..3b10bf44aa 100644 --- a/libtbx/citations.params +++ b/libtbx/citations.params @@ -479,6 +479,18 @@ citation { doi_id = doi:10.1038/s41592-022-01488-1 pmid = 35637307 } + +citation { + article_id = mmseqs2b + authors = Mirdita M, Steinegger M, Söding J + title = MMseqs2 desktop and local web server app for fast interactive sequence searches + journal = Bioinformatics + volume = 35 + pages = 2856-2858 + year = 2019 + doi_id = 10.1093/bioinformatics/bty1057 + pmid = 30615063 +} citation { article_id = mmseqs2 authors = Steinegger M, Söding J From d898fac4bc53efb637c4a52d6ce6cdb8ac2f54cc Mon Sep 17 00:00:00 2001 From: Nicholas K Sauter Date: Sun, 11 Feb 2024 17:20:54 -0800 Subject: [PATCH 122/748] Add a unit test for the diffuse halo model. The diffuse halo always adds photons or leaves pixels the same, never subtracts photons. More sophisticated tests are possible. Dials spotfinding is available in the unit test. --- simtbx/gpu/tst_shoeboxes.py | 1 + simtbx/tests/tst_unified.py | 31 +++++++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/simtbx/gpu/tst_shoeboxes.py b/simtbx/gpu/tst_shoeboxes.py index 7ee8338e85..448623e317 100644 --- a/simtbx/gpu/tst_shoeboxes.py +++ b/simtbx/gpu/tst_shoeboxes.py @@ -73,6 +73,7 @@ def extensions_for_shoebox_usage(self, params, argchk=False, gpu_background=True SIM.interpolate = 0 # allocate GPU arrays gpu_simulation = get_exascale("exascale_api",params.context)(nanoBragg = SIM) + assert hasattr(gpu_simulation, "diffuse")==(params.context=="kokkos_gpu") # diffuse halo only implemented in kokkos gpu_simulation.allocate() gpu_detector = get_exascale("gpu_detector",params.context)( deviceId=SIM.device_Id, detector=self.DETECTOR, beam=self.BEAM) diff --git a/simtbx/tests/tst_unified.py b/simtbx/tests/tst_unified.py index 32956a5f78..b49fb7efd0 100644 --- a/simtbx/tests/tst_unified.py +++ b/simtbx/tests/tst_unified.py @@ -101,7 +101,7 @@ def reset_pythony_beams(self,SIM): # for mono-wavelength addition of background pythony_beams.append(BeamFactory.from_dict(beam_descr)) SIM.xray_beams = pythony_beams - def modularized_exafel_api_for_GPU(self, params, argchk=False, gpu_background=True, sources=False): + def modularized_exafel_api_for_GPU(self, params, argchk=False, gpu_background=True, sources=False, diffuse=None): gpu_channels_type = get_exascale("gpu_energy_channels",params.context) gpu_channels_singleton = gpu_channels_type (deviceId = 0) @@ -122,6 +122,7 @@ def modularized_exafel_api_for_GPU(self, params, argchk=False, gpu_background=Tr SIM.interpolate = 0 # allocate GPU arrays gpu_simulation = get_exascale("exascale_api",params.context)(nanoBragg = SIM) + assert hasattr(gpu_simulation, "diffuse")==(params.context=="kokkos_gpu") # diffuse halo only implemented in kokkos gpu_simulation.allocate() gpu_detector = get_exascale("gpu_detector",params.context)( deviceId=SIM.device_Id, detector=self.DETECTOR, beam=self.BEAM) @@ -143,6 +144,22 @@ def modularized_exafel_api_for_GPU(self, params, argchk=False, gpu_background=Tr for panel in self.DETECTOR: sz = panel.get_image_size() NN += sz[0]*sz[1] + if diffuse: + diffuse_param = gpu_simulation.diffuse # makes a copy of diffuse parameters for local editing + diffuse_param.enable=True + diffuse_param.stencil_size=1 + diffuse_param.symmetrize_diffuse=True + diffuse_param.anisoG=[300.,100.,300.] + diffuse_param.anisoU=[0.48,0.16,0.16] + diffuse_param.rotate_principal_axes="a,b,c" + gpu_simulation.diffuse = diffuse_param + print("enable", gpu_simulation.diffuse.enable) + print("stencil_size", gpu_simulation.diffuse.stencil_size) + print("symmetrize_diffuse", gpu_simulation.diffuse.symmetrize_diffuse) + print("laue_group_num", gpu_simulation.diffuse.laue_group_num) + print("anisoG", gpu_simulation.diffuse.anisoG) + print("anisoU", gpu_simulation.diffuse.anisoU) + print("rotate_principal_axes", gpu_simulation.diffuse.rotate_principal_axes) gpu_simulation.add_energy_multichannel_mask_allpanel( ichannels = flex.int(range(len(self.flux))), gpu_amplitudes = gpu_channels_singleton, @@ -150,6 +167,10 @@ def modularized_exafel_api_for_GPU(self, params, argchk=False, gpu_background=Tr pixel_active_list_ints = flex.size_t(range(NN)), weights = self.frac/len(self.frac) ) + if diffuse: + diffuse_param.enable = False # disable so the next test isn't affected + gpu_simulation.diffuse = diffuse_param + per_image_scale_factor = self.domains_per_crystal # 1.0 gpu_detector.scale_in_place(per_image_scale_factor) # apply scale directly on GPU if sources is False: @@ -252,10 +273,16 @@ def special_test_case_1(self,SIM,gpu_detector): if "kokkos" in params.context: print("\n# Use case 2 (%s). Monochromatic source"%params.context)#"sources=True": use multichannel API - SIM2 = SWC.modularized_exafel_api_for_GPU(params=params, argchk=False, gpu_background=True, sources=True) + SIM2 = SWC.modularized_exafel_api_for_GPU(params=params, argchk=False, gpu_background=True, sources=True, diffuse=False) SIM2.to_cbf("test_unified_%s_002.cbf"%(params.context), intfile_scale=scale) # Bragg spot intensity should scale exactly with weight, using multichannel API assert np.allclose(SIM1.raw_pixels, SIM2.raw_pixels) # equate monochromatic, two Bragg interfaces + print("\n# Use case diffuse 2 (%s). Monochromatic source"%params.context) + SIM2D = SWC.modularized_exafel_api_for_GPU(params=params, argchk=False, gpu_background=True, sources=True, diffuse=True) + SIM2D.to_cbf("test_unified_%s_diffuse_002.cbf"%(params.context), intfile_scale=scale) + #assert that the diffuse scattering simulation always adds photons to pixels + assert np.all( (SIM2D.raw_pixels.as_1d() >= SIM2.raw_pixels.as_1d()).as_numpy_array() ) + print("Diffuse signal confirmed >= 0 for all pixels") # Use explicitly 3-color code and equate with explicitly 1-color: print ("\n Equate background") From 22bf1d8d71ddeffe9b50b14b99926c3fb6e69a1c Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Mon, 12 Feb 2024 09:13:52 -0800 Subject: [PATCH 123/748] small terminal correction --- mmtbx/ligands/ready_set_utils.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mmtbx/ligands/ready_set_utils.py b/mmtbx/ligands/ready_set_utils.py index 970259e19c..faaaa28547 100644 --- a/mmtbx/ligands/ready_set_utils.py +++ b/mmtbx/ligands/ready_set_utils.py @@ -112,12 +112,17 @@ def add_n_terminal_hydrogens_to_atom_group(ag, # number_of_hydrogens=-1 # # should name the hydrogens correctly if bonds: + def _get_atom_with_i_seq(ag, i_seq): + for atom in ag.atoms(): + if atom.i_seq==i_seq: return atom + return None atoms=ag.atoms() i_seqs = atoms.extract_i_seq() number_of_heavy=0 for i_seq in bonds.get(n.i_seq, []): if i_seq in i_seqs: - if not atoms[i_seq].element_is_hydrogen(): + ba = _get_atom_with_i_seq(ag, i_seq) + if not ba.element_is_hydrogen(): number_of_heavy+=1 else: number_of_heavy+=1 From e0c125ae2abba409c56d0d4384d2ad164229a99e Mon Sep 17 00:00:00 2001 From: Nicholas K Sauter Date: Mon, 12 Feb 2024 11:18:34 -0800 Subject: [PATCH 124/748] Additional testing of diffuse halo. Halo signal is pretty weak. Calculate one comparision pair without background to enhance visibility. --- simtbx/tests/tst_unified.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/simtbx/tests/tst_unified.py b/simtbx/tests/tst_unified.py index b49fb7efd0..7cf234a6ac 100644 --- a/simtbx/tests/tst_unified.py +++ b/simtbx/tests/tst_unified.py @@ -184,7 +184,8 @@ def modularized_exafel_api_for_GPU(self, params, argchk=False, gpu_background=Tr SIM.flux=1e12 SIM.beamsize_mm=0.003 # square (not user specified) SIM.exposure_s=1.0 # multiplies flux x exposure - gpu_simulation.add_background(gpu_detector) + if gpu_background: + gpu_simulation.add_background(gpu_detector) gpu_detector.write_raw_pixels(SIM) # updates SIM.raw_pixels from GPU if self.special == 1: #special test breaks encapsulation @@ -284,6 +285,17 @@ def special_test_case_1(self,SIM,gpu_detector): assert np.all( (SIM2D.raw_pixels.as_1d() >= SIM2.raw_pixels.as_1d()).as_numpy_array() ) print("Diffuse signal confirmed >= 0 for all pixels") + if "kokkos" in params.context: # same thing but with no background + print("\n# Use case 2 with no background (%s). Monochromatic source"%params.context)#"sources=True": use multichannel API + SIM2NB = SWC.modularized_exafel_api_for_GPU(params=params, argchk=False, gpu_background=False, sources=True, diffuse=False) + SIM2NB.to_cbf("test_unified_%s_nb_002.cbf"%(params.context), intfile_scale=scale) + print("\n# Use case diffuse 2 with no background (%s). Monochromatic source"%params.context) + SIM2DNB = SWC.modularized_exafel_api_for_GPU(params=params, argchk=False, gpu_background=False, sources=True, diffuse=True) + SIM2DNB.to_cbf("test_unified_%s_diffuse_nb_002.cbf"%(params.context), intfile_scale=scale) + #assert that the diffuse scattering simulation always adds photons to pixels + assert np.all( (SIM2DNB.raw_pixels.as_1d() >= SIM2NB.raw_pixels.as_1d()).as_numpy_array() ) + print("Diffuse signal confirmed >= 0 for all pixels") + # Use explicitly 3-color code and equate with explicitly 1-color: print ("\n Equate background") weights = flex.double([(0./6.), (0./6.), (0./6.)]) # background only shot From c825fa9fda18d3b2b6b947411929197bba74ef21 Mon Sep 17 00:00:00 2001 From: Russ Taylor Date: Mon, 12 Feb 2024 14:24:09 -0500 Subject: [PATCH 125/748] Adding new required Probe2 parameter when Reduce2 calls it as a harnessed program. This turns the dots in Flipkins on and off along with the geometry when looking at different alternates. --- mmtbx/programs/reduce2.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmtbx/programs/reduce2.py b/mmtbx/programs/reduce2.py index 12e53dec99..a63c843d25 100644 --- a/mmtbx/programs/reduce2.py +++ b/mmtbx/programs/reduce2.py @@ -1017,6 +1017,7 @@ def _MakeProbePhil(self, movers_to_check, temp_output_file_name): newParams.output.__inject__('atoms_are_masters', False) newParams.output.__inject__('default_point_color', 'gray') newParams.output.__inject__('compute_scores', True) + newParams.output.__inject__('altid_as_pointmaster', True) return newParams # ------------------------------------------------------------------------------ From 617a6aa6f6e393d020fc5adbabe071c512955b8c Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Mon, 12 Feb 2024 11:46:34 -0800 Subject: [PATCH 126/748] Clean clutter [skip ci] --- libtbx/citations.params | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libtbx/citations.params b/libtbx/citations.params index 3b10bf44aa..0a4a3b2d0a 100644 --- a/libtbx/citations.params +++ b/libtbx/citations.params @@ -484,12 +484,12 @@ citation { article_id = mmseqs2b authors = Mirdita M, Steinegger M, Söding J title = MMseqs2 desktop and local web server app for fast interactive sequence searches - journal = Bioinformatics + journal = Bioinformatics volume = 35 - pages = 2856-2858 + pages = 2856-2858 year = 2019 doi_id = 10.1093/bioinformatics/bty1057 - pmid = 30615063 + pmid = 30615063 } citation { article_id = mmseqs2 From 56553ef19f1078a4abf5f379bc448773cc4b4b25 Mon Sep 17 00:00:00 2001 From: cschlick Date: Mon, 12 Feb 2024 10:18:50 -0800 Subject: [PATCH 127/748] Qscore: update phil str --- cctbx/maptbx/qscore.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index 73f2e3fa34..c626798ef5 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -36,7 +36,7 @@ .help = Min number of radial probes to use .short_caption = Number of radial probes to use .expert_level = 1 - selection = None + selection_str = None .type = str .help = Only test atoms within this selection .short_caption = Only test atoms within this selection @@ -78,10 +78,9 @@ rejected once. Parallelization is done by radial shell. \ Precalculate is much faster but will yield slightly different results. - progress = False - .type = bool - .help = Report progress - .short_caption = Report progress bar + backend = numpy + .type = str + .help = Choose backend numpy or flex .expert_level = 1 debug = False @@ -409,6 +408,7 @@ def get_probes( else: assert False, f"Unrecognized backend: {params.backend}" + assert params.shells is not None, "Must provide explicit radial shells" task_list = [ { "func": worker_func, # Specify the function to call From 7836bfc68b54ce31f2340290d4699ce0e4462e82 Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 13 Feb 2024 11:52:35 -0800 Subject: [PATCH 128/748] Qscore: add test for program template --- cctbx/maptbx/tst_qscore.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/cctbx/maptbx/tst_qscore.py b/cctbx/maptbx/tst_qscore.py index f152963373..eec8cc9f72 100644 --- a/cctbx/maptbx/tst_qscore.py +++ b/cctbx/maptbx/tst_qscore.py @@ -7,9 +7,12 @@ from iotbx.data_manager import DataManager from cctbx.array_family import flex import libtbx +from libtbx import phil from cctbx.maptbx.box import shift_and_box_model from iotbx.map_model_manager import map_model_manager from libtbx.utils import null_out +from cctbx.programs.qscore import Program as QscoreProgram + import numpy as np from scipy.spatial import KDTree @@ -610,6 +613,17 @@ def build_tests(test_dir="qscore_tst_dir"): return tests +def test_program_template(test): + print("Running prgram template test: ",test["data"]["name"]) + model_file = test["data"]["model_file"] + map_file = test["data"]["map_file"] + dm = DataManager() + dm.process_model_file(str(model_file)) + dm.process_real_map_file(str(map_file)) + params = phil.parse(QscoreProgram.master_phil_str,process_includes=True).extract() + task = QscoreProgram(dm,params) + task.run() + results = task.get_results() if (__name__ == "__main__"): @@ -632,3 +646,8 @@ def build_tests(test_dir="qscore_tst_dir"): tests = build_tests() for test_name,test in tests.items(): test = run_test(test) + + + # Test if program template runs, with default phil + test_program_template(list(tests.values())[-1]) + From d35b86e3553fb1251ec44a66ed247507fd0a2dc2 Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 13 Feb 2024 11:39:19 -0800 Subject: [PATCH 129/748] Qscore: bugfix for case where shells are not explicit. Remove debug print statement --- cctbx/maptbx/qscore.py | 1 - cctbx/programs/qscore.py | 16 +++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index c626798ef5..14d2add310 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -428,7 +428,6 @@ def get_probes( if params.nproc>1: with Pool() as pool: - print(params.nproc) results = pool.map(starmap_wrapper, task_list) else: results = [] diff --git a/cctbx/programs/qscore.py b/cctbx/programs/qscore.py index 0061ab5d59..1faef05bb2 100644 --- a/cctbx/programs/qscore.py +++ b/cctbx/programs/qscore.py @@ -42,7 +42,12 @@ def run(self): mmm = self.data_manager.get_map_model_manager() # calculate shells - if len(self.params.qscore.shells) ==0 : + if (len(self.params.qscore.shells) ==0 or + self.params.qscore.shells[0] is None): + if None in self.params.qscore.shells: + self.params.qscore.shells.remove(None) + + # add a range of shells start = self.params.qscore.shell_radius_start stop = self.params.qscore.shell_radius_stop num = self.params.qscore.shell_radius_num @@ -51,8 +56,13 @@ def run(self): stop, num, endpoint=True)) - for shell in shells: - self.params.qscore.shells.append(shell) + + shells = [ + 0.0,0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1., + 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. + ] + for shell in reversed(shells): + self.params.qscore.shells.insert(0,shell) # ignore hydrogens From 269fba28614aa5521e260403fe19a3c66de42f8e Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 13 Feb 2024 17:09:40 -0800 Subject: [PATCH 130/748] Debugging output --- mmtbx/geometry_restraints/base_qm_manager.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/mmtbx/geometry_restraints/base_qm_manager.py b/mmtbx/geometry_restraints/base_qm_manager.py index b93e0c17f4..c40b017859 100644 --- a/mmtbx/geometry_restraints/base_qm_manager.py +++ b/mmtbx/geometry_restraints/base_qm_manager.py @@ -265,6 +265,13 @@ def check_file_read_safe(self, optimise_ligand=True, optimise_h=True, constrain_ for i, (line1, line2) in enumerate(zip(outl.splitlines(),lines.splitlines())): if line1!=line2: print(' ! %s "%s" <> "%s"' % (i+1, line1, line2)) print('='*80) + f, ext = os.path.splitext(filename) + f=open('old%s' % ext, 'w') + f.write(lines) + del f + f=open('new%s' % ext, 'w') + f.write(outl) + del f raise Sorry('something has changed making the QM input files different') return outl==lines @@ -284,7 +291,8 @@ def get_opt(self, coordinate_filename_ext='.xyz', log_filename_ext='.log', redirect_output=True, - log=None): + log=None, + verbose=False): if self.program_goal in ['opt', 'strain']: optimise_ligand=True # elif self.program_goal in ['energy']: @@ -294,19 +302,22 @@ def get_opt(self, coordinates = None rc=True if check_file_read_safe: + if verbose: print('check_file_read_safe',check_file_read_safe) rc = self.check_file_read_safe(optimise_ligand=optimise_ligand, optimise_h=optimise_h, constrain_torsions=constrain_torsions, ) + if verbose: print('rc',rc) if file_read and rc: filename = self.get_coordinate_filename() if os.path.exists(filename): lf = self.get_log_filename() if os.path.exists(lf): process_qm_log_file(lf, log=log) - # print(' Reading coordinates from %s\n' % filename, file=log) + if verbose: print(' Reading coordinates from %s\n' % filename) coordinates = self.read_xyz_output() if coordinates is None: + if verbose: print('no coordinates') self.opt_setup(optimise_ligand=optimise_ligand, optimise_h=optimise_h, constrain_torsions=constrain_torsions, From d9f9ab1232ec9b5bd6831e25cce060881ab794d6 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 13 Feb 2024 17:11:24 -0800 Subject: [PATCH 131/748] Display updates --- mmtbx/geometry_restraints/quantum_interface.py | 4 ++++ .../geometry_restraints/quantum_restraints_manager.py | 10 ++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/mmtbx/geometry_restraints/quantum_interface.py b/mmtbx/geometry_restraints/quantum_interface.py index 4cb1aba16f..54fc7c8169 100644 --- a/mmtbx/geometry_restraints/quantum_interface.py +++ b/mmtbx/geometry_restraints/quantum_interface.py @@ -251,6 +251,10 @@ def default_defaults(qmr): assert 0 return qmr +def get_working_directory(model, params): + rc = 'qm_work_dir' + return rc + def get_preamble(macro_cycle, i, qmr, old_style=False, compact_selection_syntax=True): qmr = populate_qmr_defaults(qmr) s='' diff --git a/mmtbx/geometry_restraints/quantum_restraints_manager.py b/mmtbx/geometry_restraints/quantum_restraints_manager.py index 50996baab7..3764f26f2a 100644 --- a/mmtbx/geometry_restraints/quantum_restraints_manager.py +++ b/mmtbx/geometry_restraints/quantum_restraints_manager.py @@ -492,7 +492,9 @@ def get_qm_manager(ligand_model, buffer_model, qmr, program_goal, log=StringIO() specific_atom_charges=specific_atom_charges, log=log) if total_charge!=qmr.package.charge: - print(u' Update charge %s ~> %s' % (qmr.package.charge, total_charge), + print(u' Update charge for "%s" cluster : %s ~> %s' % (qmr.selection, + qmr.package.charge, + total_charge), file=log) qmr.package.charge=total_charge qmm = qmm(electron_model.get_atoms(), @@ -969,7 +971,7 @@ def run_jobs(objects, macro_cycle, nproc=1, log=StringIO()): key = (ligand_model.get_number_of_atoms(), buffer_model.get_number_of_atoms()) time_query = qmm.get_timings() - curve_fit_3d.load_and_display(key, time_query) + curve_fit_3d.load_and_display(qmm.program_goal, key, time_query, show=True) elif qmm.program_goal in ['energy', 'strain', 'bound']: energy=xyz units=xyz_buffer @@ -1084,7 +1086,7 @@ def is_ligand_going_to_be_same_size(qmr): # assert objects if not objects: return None - working_dir = 'qm_work_dir' + working_dir = quantum_interface.get_working_directory(model, params) if not os.path.exists(working_dir): try: os.mkdir(working_dir) except Exception as e: pass @@ -1159,7 +1161,7 @@ def is_ligand_going_to_be_same_size(qmr): write_pdb_file(buffer_model, '%s_cluster_final_%s.pdb' % (prefix, preamble), log) final_pdbs[-1].append('%s_cluster_final_%s.pdb' % (prefix, preamble)) if qmr.do_not_update_restraints: - print(' Skipping updating restaints') + print(' Skipping updating restaints %s %s' % (prefix, preamble), file=log) continue # # transfer geometry to proxies From e8cacca2e0d4942031eeab9566ee1bc1fdfb5a0e Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 13 Feb 2024 17:12:10 -0800 Subject: [PATCH 132/748] useful updates --- mmtbx/monomer_library/__init__.py | 12 ++++++++++++ mmtbx/monomer_library/linking_mixins.py | 3 ++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/mmtbx/monomer_library/__init__.py b/mmtbx/monomer_library/__init__.py index e69de29bb2..7468b0927a 100644 --- a/mmtbx/monomer_library/__init__.py +++ b/mmtbx/monomer_library/__init__.py @@ -0,0 +1,12 @@ +from __future__ import absolute_import, division, print_function + +import iotbx + +def is_monomer_library_file(file_name): + try: + cif_model = iotbx.cif.reader(file_path=file_name).model() + for cif_block in cif_model.values(): + if '_chem_comp_atom' in cif_block: + return True + except Exception as e: + return False diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index 1488c8821b..bcb39e8e90 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -234,6 +234,7 @@ def possible_cyclic_peptide(atom1, ): if verbose: print(atom1.quote(),atom2.quote()) + if atom1.element_is_hydrogen() or atom2.element_is_hydrogen(): return False chain1 = atom1.parent().parent().parent() chain2 = atom1.parent().parent().parent() if not chain1.id == chain2.id: @@ -517,7 +518,7 @@ def _nonbonded_pair_generator_geometry_restraints_sort( # # if verbose: - print(i_seq, j_seq, atom1.quote(), end=' ') + print('nonbonded', i_seq, j_seq, atom1.quote(), end=' ') print(atom2.quote(), end=' ') print("Distance: %0.2f" % distance, rt_mx_ji, sym_op) From 20ef6adfa44ef27e8b29ebb783bb702cf285b1b2 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 14 Feb 2024 12:09:54 -0800 Subject: [PATCH 133/748] iotbx: hide DataManager PHIL scope in GUI by default --- iotbx/data_manager/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/iotbx/data_manager/__init__.py b/iotbx/data_manager/__init__.py index 5fbd429b8d..af54fe5167 100644 --- a/iotbx/data_manager/__init__.py +++ b/iotbx/data_manager/__init__.py @@ -217,7 +217,10 @@ def __init__(self, datatypes=None, phil=None, custom_options=None, self.load_custom_phil_extract = 'load_%s_phil_extract' # dynamically construct master PHIL string - self.master_phil_str = 'data_manager {\n' + self.master_phil_str = '''\ +data_manager + .style = noauto +{''' for datatype in self.datatypes: # check if a datatype has a custom PHIL str From 610ebc6fffe2960ac8923732a2ee3c86bd354823 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 14 Feb 2024 12:16:40 -0800 Subject: [PATCH 134/748] Move output dir scope to the bottom --- mmtbx/programs/fmodel.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mmtbx/programs/fmodel.py b/mmtbx/programs/fmodel.py index 8c6394424c..5f89e3201a 100644 --- a/mmtbx/programs/fmodel.py +++ b/mmtbx/programs/fmodel.py @@ -50,6 +50,7 @@ master_phil_str = ''' include scope libtbx.phil.interface.tracking_params + high_resolution = None .type = float .expert_level=1 @@ -156,6 +157,13 @@ .short_caption = f'' } } +gui + .help = "GUI-specific parameter required for output directory" +{ + output_dir = None + .type = path + .style = output_dir +} '''%fmodel_from_xray_structure_params_str fmodel_from_xray_structure_params = iotbx.phil.parse( @@ -254,6 +262,8 @@ class Program(ProgramTemplate): master_phil_str = master_phil_str +# show_data_manager_scope_by_default = True + # --------------------------------------------------------------------------- def validate(self): From 75066aa3b30b277dcb7f06f408490054459faaec Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 14 Feb 2024 14:56:09 -0800 Subject: [PATCH 135/748] updates for the GUI --- mmtbx/programs/fmodel.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mmtbx/programs/fmodel.py b/mmtbx/programs/fmodel.py index 5f89e3201a..5dc107e2ff 100644 --- a/mmtbx/programs/fmodel.py +++ b/mmtbx/programs/fmodel.py @@ -113,6 +113,7 @@ format = *mtz cns .type = choice .short_caption = File format + .input_size = 100 label = FMODEL .type = str .short_caption = Data label @@ -163,6 +164,11 @@ output_dir = None .type = path .style = output_dir + + data_column_label = None + .type = str + .style = noauto renderer:draw_any_label_widget + .input_size = 300 } '''%fmodel_from_xray_structure_params_str From b6e1e2de6828566d12759bc3d4f3780c689b088b Mon Sep 17 00:00:00 2001 From: terwill Date: Fri, 16 Feb 2024 08:58:27 -0800 Subject: [PATCH 136/748] Add method to set a parameter value based on a set of possibilities, excluding all possibilities that have already been used --- libtbx/program_template.py | 88 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/libtbx/program_template.py b/libtbx/program_template.py index 24183ffd79..3af7bed5a9 100644 --- a/libtbx/program_template.py +++ b/libtbx/program_template.py @@ -413,7 +413,95 @@ def set_target_output_format(self): out = self.logger) self.data_manager.set_target_output_format(target_output_format) + # --------------------------------------------------------------------------- + def _params_as_dict(self, params = None, base_name_list = None): + """ Split up a params object into a dict of each individual parameter name + as key and value as value. Add base name on to attribute name, + Recursively traverse the params object.""" + if not params: params = self.params + if not base_name_list: base_name_list = [] + params_dict = {} + for x in dir(params): + if x.startswith("__"): continue + v = getattr(params,x) + b = base_name_list + [x] + if hasattr(v,'__phil_name__'): + params_dict.update(self._params_as_dict(v, base_name_list = b)) + else: + params_dict[".".join(b)] = v + return params_dict + + def _fn_is_assigned(self, fn = None): + """ Determine if fn is assigned to some parameter""" + if fn in list(self._params_as_dict().values()): + return True + else: + return False + + + def _get_scope_and_parameter(self, parameter_name = None, base = None): + """ Get the full scope and the parmenter from a parameter name. + For example: autobuild.data -> (self.params.autobuild, 'data') + """ + if base is None: + base = self.params + assert parameter_name is not None, "Missing parameter name" + spl = parameter_name.split(".") + name = spl[-1] + path = spl[:-1] + for p in path: + assert hasattr(base, p), "Missing scope: %s" %(p) + base = getattr(base, p) + return base, name + + def assign_if_value_is_unique_and_unassigned(self, + parameter_name = None, + possible_values = None): + """ Method to assign a value to a parameter that has no value so far, + choosing value from a list of possible values, eliminating all values + that have been assigned to another parameter already. + Normally used like this in a Program template: + + self.assign_if_value_is_unique_and_unassigned( + parameter_name = 'autobuild.data', + possible_values = self.data_manager.get_miller_array_names()) + + Raises Sorry if there are multiple possibilities. + + parameter: parameter_name: The name of the parameter in the context + of self.params (self.params.autobuild.data is + autobuild.data) + parameter: possible_values: Possible values of this parameter, usually from + the data_manager + + sets: value of full parameter to a unique value if present + returns: None + """ + scope, par = self._get_scope_and_parameter(parameter_name) + + v = getattr(scope, par) + has_value = (not v in [Auto, 'None',None]) + if has_value: + return # nothing to do, already assigned value to this parameter + + possibilities = [] + for p in possible_values: + if p in [Auto, 'None',None]: + continue # not relevant + elif (not self._fn_is_assigned(p)): # not already assigned + possibilities.append(p) + if len(possibilities) == 1: + setattr(scope, par, possibilities[0]) + elif len(possibilities) < 1: + return # No unused possibilities for this parameter + else: + from libtbx.utils import Sorry + raise Sorry("Please set these parameters with keywords: (%s), " %( + " ".join(possibilities)) + "\nFor example, '%s=%s'" %( + parameter_name, possibilities[0])) + # --------------------------------------------------------------------------- + def get_default_output_filename(self, prefix=Auto, suffix=Auto, serial=Auto, filename=Auto): ''' From 9ba152e380fb74fc494471e912720b9b619aa07f Mon Sep 17 00:00:00 2001 From: terwill Date: Fri, 16 Feb 2024 09:56:04 -0800 Subject: [PATCH 137/748] Add get_parameter_value --- libtbx/program_template.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/libtbx/program_template.py b/libtbx/program_template.py index 3af7bed5a9..a9adc234bb 100644 --- a/libtbx/program_template.py +++ b/libtbx/program_template.py @@ -440,8 +440,25 @@ def _fn_is_assigned(self, fn = None): return False + def get_parameter_value(self, parameter_name, base = None): + """ Get the full scope and the parameter from a parameter name. + Then get value of this parameter + For example: autobuild.data -> (self.params.autobuild, 'data') + returns value of self.params.autobuild.data + + parameter: parameter_name: text parameter name in context of self.params + parameter: base: base scope path to add before parameter name + returns: value of self.params.parameter_name + """ + + scope, par = self._get_scope_and_parameter(parameter_name, base = base) + if not hasattr(scope, par): + print("The parameter %s does not exist" %(parameter_name), + file = self.logger) + return getattr(scope, par) + def _get_scope_and_parameter(self, parameter_name = None, base = None): - """ Get the full scope and the parmenter from a parameter name. + """ Get the full scope and the parameter from a parameter name. For example: autobuild.data -> (self.params.autobuild, 'data') """ if base is None: @@ -478,20 +495,20 @@ def assign_if_value_is_unique_and_unassigned(self, sets: value of full parameter to a unique value if present returns: None """ - scope, par = self._get_scope_and_parameter(parameter_name) + v = self.get_parameter_value(parameter_name) - v = getattr(scope, par) - has_value = (not v in [Auto, 'None',None]) + has_value = not (v in ['Auto',Auto, 'None',None]) if has_value: return # nothing to do, already assigned value to this parameter possibilities = [] for p in possible_values: - if p in [Auto, 'None',None]: + if p in ['Auto',Auto, 'None',None]: continue # not relevant elif (not self._fn_is_assigned(p)): # not already assigned possibilities.append(p) if len(possibilities) == 1: + scope, par = self._get_scope_and_parameter(parameter_name) setattr(scope, par, possibilities[0]) elif len(possibilities) < 1: return # No unused possibilities for this parameter From a4359bc600eaca8a8ef07474ee0aa40836eb88ff Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Fri, 16 Feb 2024 14:07:55 -0800 Subject: [PATCH 138/748] Using built-in safeguards for phil values. --- .../torsion_restraints/reference_model.py | 2 +- mmtbx/monomer_library/pdb_interpretation.py | 14 ++++----- .../monomer_library/tst_pdb_interpretation.py | 29 ++++++++++--------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/mmtbx/geometry_restraints/torsion_restraints/reference_model.py b/mmtbx/geometry_restraints/torsion_restraints/reference_model.py index 8f5e6df739..766041becf 100644 --- a/mmtbx/geometry_restraints/torsion_restraints/reference_model.py +++ b/mmtbx/geometry_restraints/torsion_restraints/reference_model.py @@ -62,7 +62,7 @@ .type = bool .short_caption = use starting model as reference sigma = 1.0 - .type = float + .type = float(value_min=0.001) limit = 15.0 .type = float hydrogens = False diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index 48fa4a5e6d..0b1aff1c08 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -255,7 +255,7 @@ def __init__(self, residue_name, atom_name, atom_element): selection = all .type = atom_selection sigma = 0.2 - .type = float + .type = float(value_min=0.001) limit = 1.0 .type = float top_out = False @@ -571,9 +571,9 @@ def __init__(self, residue_name, atom_name, atom_element): " Example: symmetry_operation = -x-1,-y,z" .type = str distance_ideal = None - .type = float + .type = float(value_min=0.001) sigma = None - .type = float + .type = float(value_min=0.001) slack = None .type = float limit = -1.0 @@ -601,7 +601,7 @@ def __init__(self, residue_name, atom_name, atom_element): angle_ideal = None .type = float sigma = None - .type = float + .type = float(value_min=0.001) } dihedral .optional = True @@ -628,7 +628,7 @@ def __init__(self, residue_name, atom_name, atom_element): alt_angle_ideals = None .type = floats sigma = None - .type = float + .type = float(value_min=0.001) periodicity = 1 .type = int } @@ -644,7 +644,7 @@ def __init__(self, residue_name, atom_name, atom_element): .type = atom_selection .input_size = 400 sigma = None - .type = float + .type = float(value_min=0.001) } parallelity .optional = True @@ -661,7 +661,7 @@ def __init__(self, residue_name, atom_name, atom_element): .type = atom_selection .input_size = 400 sigma = 0.027 - .type = float + .type = float(value_min=0.001) target_angle_deg = 0 .type = float } diff --git a/mmtbx/monomer_library/tst_pdb_interpretation.py b/mmtbx/monomer_library/tst_pdb_interpretation.py index d373ad6959..d0999eb8f8 100644 --- a/mmtbx/monomer_library/tst_pdb_interpretation.py +++ b/mmtbx/monomer_library/tst_pdb_interpretation.py @@ -2386,19 +2386,30 @@ def exercise_bad_custom_bonds(mon_lib_srv, ener_lib): atom_selection_2 = chain N and resname O and name NE } bond { - distance_ideal = -1 + distance_ideal = 2 } +}""" + bad_edits = """\ +pdb_interpretation.geometry_restraints.edits { bond { - distance_ideal = 2 + distance_ideal = -1 } bond { distance_ideal = 2 sigma = -1 } -}""" +} +""" gm_phil = iotbx.phil.parse( monomer_library.pdb_interpretation.grand_master_phil_str, process_includes=True) + edits_phil = iotbx.phil.parse(edits+bad_edits) + try: + working_phil = gm_phil.fetch(edits_phil) + except RuntimeError as e: + assert str(e) == "geometry_restraints.edits.bond.distance_ideal element is less than the minimum allowed value: -1 < 0.001 (input line 25)", str(e) + else: raise Exception_expected + edits_phil = iotbx.phil.parse(edits) working_phil = gm_phil.fetch(edits_phil) params = working_phil.extract() @@ -2437,26 +2448,16 @@ def exercise_bad_custom_bonds(mon_lib_srv, ener_lib): Warning: Ignoring bond with distance_ideal = None: atom_selection_1 = None atom_selection_2 = "chain N and resname O and name NE" - Warning: Ignoring bond with distance_ideal < 0: - atom_selection_1 = None - atom_selection_2 = None - distance_ideal = -1 Warning: Ignoring bond with sigma = None: atom_selection_1 = None atom_selection_2 = None distance_ideal = 2 - Warning: Ignoring bond with sigma <= 0: - atom_selection_1 = None - atom_selection_2 = None - distance_ideal = 2 - sigma = -1 - slack = 0 Total number of added/changed bonds: 2""" log = log.getvalue().splitlines() found = 0 for e in expected.splitlines(): if(e in log): found += 1 - assert found > 39, found + assert found > 29, found def exercise_allow_polymer_cross_special_position(mon_lib_srv, ener_lib): raw_records = """\ From 6f00fcc0e235018327004595e81616ef50591251 Mon Sep 17 00:00:00 2001 From: terwill Date: Fri, 16 Feb 2024 15:45:19 -0700 Subject: [PATCH 139/748] Fix finding parameter values --- libtbx/program_template.py | 47 ++++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/libtbx/program_template.py b/libtbx/program_template.py index a9adc234bb..e8bd39297f 100644 --- a/libtbx/program_template.py +++ b/libtbx/program_template.py @@ -426,19 +426,46 @@ def _params_as_dict(self, params = None, base_name_list = None): if x.startswith("__"): continue v = getattr(params,x) b = base_name_list + [x] - if hasattr(v,'__phil_name__'): - params_dict.update(self._params_as_dict(v, base_name_list = b)) + if isinstance(v,libtbx.phil.scope_extract): + self._update_params_dict(params_dict, + self._params_as_dict(v, base_name_list = b)) + elif isinstance(v, libtbx.phil.scope_extract_list): + for vv in v: + if hasattr(vv,'__phil_name__'): + self._update_params_dict(params_dict, + self._params_as_dict(vv, base_name_list = b)) + else: + params_dict[".".join(b)] = vv else: params_dict[".".join(b)] = v return params_dict - + + def _update_params_dict(self, params_dict, other_params_dict): + for key in other_params_dict.keys(): + if not key in params_dict: + params_dict[key] = other_params_dict[key] + else: + if not other_params_dict[key]: + pass + elif not params_dict[key]: + params_dict[key] = other_params_dict[key] + else: + if not isinstance(params_dict[key], list): + params_dict[key] = [ params_dict[key]] + if not isinstance(other_params_dict[key], list): + other_params_dict[key] = [ other_params_dict[key]] + params_dict[key] += other_params_dict[key] + return params_dict def _fn_is_assigned(self, fn = None): """ Determine if fn is assigned to some parameter""" - if fn in list(self._params_as_dict().values()): - return True + for x in list(self._params_as_dict().values()): + if fn == x: + return True + if isinstance(x, list) and fn in x: + return True else: return False - + def get_parameter_value(self, parameter_name, base = None): """ Get the full scope and the parameter from a parameter name. @@ -460,7 +487,7 @@ def get_parameter_value(self, parameter_name, base = None): def _get_scope_and_parameter(self, parameter_name = None, base = None): """ Get the full scope and the parameter from a parameter name. For example: autobuild.data -> (self.params.autobuild, 'data') - """ + """ if base is None: base = self.params assert parameter_name is not None, "Missing parameter name" @@ -476,7 +503,7 @@ def assign_if_value_is_unique_and_unassigned(self, parameter_name = None, possible_values = None): """ Method to assign a value to a parameter that has no value so far, - choosing value from a list of possible values, eliminating all values + choosing value from a list of possible values, eliminating all values that have been assigned to another parameter already. Normally used like this in a Program template: @@ -493,7 +520,7 @@ def assign_if_value_is_unique_and_unassigned(self, the data_manager sets: value of full parameter to a unique value if present - returns: None + returns: None """ v = self.get_parameter_value(parameter_name) @@ -501,7 +528,7 @@ def assign_if_value_is_unique_and_unassigned(self, if has_value: return # nothing to do, already assigned value to this parameter - possibilities = [] + possibilities = [] for p in possible_values: if p in ['Auto',Auto, 'None',None]: continue # not relevant From a09dd915031b2bcc94090f259e262986752949f6 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Fri, 16 Feb 2024 14:31:46 -0800 Subject: [PATCH 140/748] iotbx: clean up get_program_params --- iotbx/cli_parser.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/iotbx/cli_parser.py b/iotbx/cli_parser.py index f906aff376..9ac34dd8ab 100644 --- a/iotbx/cli_parser.py +++ b/iotbx/cli_parser.py @@ -20,7 +20,7 @@ from libtbx import citations from libtbx.program_template import ProgramTemplate from libtbx.str_utils import wordwrap -from libtbx.utils import multi_out, show_times, Sorry +from libtbx.utils import multi_out, null_out, show_times, Sorry # ============================================================================= class ParserBase(argparse.ArgumentParser): @@ -275,12 +275,6 @@ def add_default_options(self): '--dry-run', '--dry_run', action='store_true', help='performs basic validation the input arguments, but does not run the program' ) - # --get-parser - # proceeds until the validate step - self.add_argument( - '--get-parser', '--get_parser', action='store_true', - help='sets up the parameters only' - ) # --citations will use the default format # --citations= will use the specified format @@ -913,8 +907,6 @@ def run_program(program_class=None, parser_class=CCTBXParser, custom_process_arg unused_phil_raises_sorry=unused_phil_raises_sorry, logger=logger) namespace = parser.parse_args(args) - if namespace.get_parser: - return parser # start program if namespace.dry_run: @@ -985,10 +977,10 @@ def get_program_params(run): from phenix.programs import map_to_model as run """ - from iotbx.cli_parser import run_program - parser=run_program(program_class=run.Program,args=['--get_parser'], - logger=sys.stdout) - return parser.working_phil.extract() - + parser = CCTBXParser(program_class=run.Program, + logger=null_out()) + _ = parser.parse_args([]) + return parser.working_phil.extract() +# ============================================================================= # end From 26c0fdc778c081d5b9a20b17ea7697fffd98e6a6 Mon Sep 17 00:00:00 2001 From: Pavel Date: Fri, 16 Feb 2024 18:47:56 -0800 Subject: [PATCH 141/748] Add a comment about practical use --- cctbx/eltbx/electron_scattering.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cctbx/eltbx/electron_scattering.h b/cctbx/eltbx/electron_scattering.h index 08ac46f661..7078514d05 100644 --- a/cctbx/eltbx/electron_scattering.h +++ b/cctbx/eltbx/electron_scattering.h @@ -30,6 +30,15 @@ namespace cctbx { namespace eltbx { namespace electron_scattering { electron_scattering::peng19965_iterator, electron_scattering::peng1996, xray_scattering::base + + ****** Practical note (adopted from Dorothee Liebschner): ****** + To use these parameters one needs to implement the divergent contribution + from the unscreened Coulomb potential of the ionic charge. See formula 4 in + Acta Cryst. (1998). A54, 481-485. This term is not available in our code. + It isn't clear how to do the Fourier Transform of this. So unless we figure + this out and make this available, we cannot use the form factors of ions from + Peng. The efforts from UCLA people was to approximate the curves for the ions + using negative coefficients. Then the divergent charge term is not needed. */ class peng1996: public xray_scattering::base<5> { From 196a0fc917a69e0f76f1cd2fdefd84901ed9cef6 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Fri, 16 Feb 2024 19:14:52 -0800 Subject: [PATCH 142/748] Don't drop SS annotations on model deep_copy --- mmtbx/model/model.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index 506058269e..e513b2d02a 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -3324,7 +3324,9 @@ def rms_b_iso_or_b_equiv_bonded(self): b_isos = bs) def deep_copy(self): - return self.select(selection = flex.bool(self.size(), True)) + new_model = self.select(selection = flex.bool(self.size(), True)) + new_model.set_ss_annotation(self.get_ss_annotation()) + return new_model def add_ias(self, fmodel=None, ias_params=None, file_name=None, build_only=False): From b8ec5c6fc3409f6ebd4ee800377f0ab1ae0bac5a Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Fri, 16 Feb 2024 19:15:18 -0800 Subject: [PATCH 143/748] Functionality to renumber residues in SS elements --- iotbx/pdb/secondary_structure.py | 65 ++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/iotbx/pdb/secondary_structure.py b/iotbx/pdb/secondary_structure.py index 99ea08a6ac..3ced76427f 100644 --- a/iotbx/pdb/secondary_structure.py +++ b/iotbx/pdb/secondary_structure.py @@ -498,6 +498,35 @@ def present_in_hierarchy(self, hierarchy): return True return False + def _change_residue_numbering_in_place_helper(self, renumbering_dictionary, se=["start", "end"]): + """ Changes residue numbers and insertion codes in annotations. + For cases where one needs to renumber hierarchy and keep annotations + consisten with the new numbering. + Not for cases where residues removed or added. + Therefore residue name stays the same. + + Called from derived classes. + + Args: + renumbering_dictionary (_type_): data structure to match old and new numbering: + {'chain id': + {(old resseq, icode):(new resseq, icode)} + } + se: labels for start and end. Also can be ["cur", "prev"] in sheet registrations + """ + for start_end in se: + chain_id_attr = "%s_chain_id" % start_end + resseq_attr = "%s_resseq" % start_end + icode_attr = "%s_icode" % start_end + chain_dic = renumbering_dictionary.get(getattr(self, chain_id_attr), None) + if chain_dic is not None: + resseq, icode = getattr(self, resseq_attr), getattr(self, icode_attr) + new_resseq, new_icode = chain_dic.get((resseq, icode), (None, None)) + if new_resseq is not None and new_icode is not None: + setattr(self, resseq_attr, new_resseq) + setattr(self, icode_attr, new_icode) + + def count_h_bonds(self,hierarchy=None, max_h_bond_length=None,ss_by_chain=False): "Count good and poor H-bonds in this hierarchy" @@ -1071,6 +1100,24 @@ def remove_3_10_helices(self): filtered_helices.append(h) self.helices = filtered_helices + def change_residue_numbering_in_place(self, renumbering_dictionary): + """ Changes residue numbers and insertion codes in annotations. + For cases where one needs to renumber hierarchy and keep annotations + consisten with the new numbering. + Not for cases where residues removed or added. + Therefore residue name stays the same. + + Args: + renumbering_dictionary (_type_): data structure to match old and new numbering: + {'chain id': + {(old resseq, icode):(new resseq, icode)} + } + """ + for h in self.helices: + h.change_residue_numbering_in_place(renumbering_dictionary) + for sh in self.sheets: + sh.change_residue_numbering_in_place(renumbering_dictionary) + def as_cif_loops(self): """ Returns list of loops needed to represent SS annotation. The first for @@ -2216,6 +2263,10 @@ def is_same_as(self,other=None): return False return True + def change_residue_numbering_in_place(self, renumbering_dictionary): + self._change_residue_numbering_in_place_helper(renumbering_dictionary) + + #============================================================================= # ad88888ba 88 88 88888888888 88888888888 888888888888 # d8" "8b 88 88 88 88 88 @@ -2319,6 +2370,9 @@ def set_new_chain_ids(self, new_chain_id): self.start_chain_id = new_chain_id self.end_chain_id = new_chain_id + def change_residue_numbering_in_place(self, renumbering_dictionary): + self._change_residue_numbering_in_place_helper(renumbering_dictionary) + def sense_as_cif(self): if self.sense == 0: return '?' @@ -2507,6 +2561,9 @@ def as_atom_selections(self, add_segid=None): resid_prev, self.prev_atom.strip()) return sele_curr, sele_prev + def change_residue_numbering_in_place(self, renumbering_dictionary): + self._change_residue_numbering_in_place_helper(renumbering_dictionary, se=["cur", "prev"]) + def is_same_as(self,other=None): if not other: return False @@ -2794,6 +2851,14 @@ def remove_short_strands(self, size=3): self.renumber_strands() self.erase_hbond_list() + def change_residue_numbering_in_place(self, renumbering_dictionary): + self.erase_hbond_list() + for st in self.strands: + st.change_residue_numbering_in_place(renumbering_dictionary) + for reg in self.registrations: + if reg is not None: + reg.change_residue_numbering_in_place(renumbering_dictionary) + def deep_copy(self): return copy.deepcopy(self) From bc51a80990cc3be3fde570a165a01b635ea3915f Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Sat, 17 Feb 2024 07:20:01 -0800 Subject: [PATCH 144/748] Test for fresh functionality --- iotbx/pdb/tst_secondary_structure.py | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/iotbx/pdb/tst_secondary_structure.py b/iotbx/pdb/tst_secondary_structure.py index 0df7fd185e..c738a53955 100644 --- a/iotbx/pdb/tst_secondary_structure.py +++ b/iotbx/pdb/tst_secondary_structure.py @@ -5,6 +5,7 @@ import iotbx from scitbx.array_family import flex from mmtbx.secondary_structure import sec_str_master_phil +from libtbx.test_utils import assert_lines_in_text pdb_1ywf_cutted = """\ HELIX 1 1 ALA A 16 THR A 18 5 3 @@ -2112,12 +2113,47 @@ def exercise_multiplication(): assert ss_back.sheets[0].sheet_id == 'AF7' print("OK") +def exercise_change_residue_numbering(): + ss_records = """\ +HELIX 14 14 SER A 252 ALA A 260 1 9 +HELIX 15 15 SER A 263 LEU A 275 1 13 +SHEET 1 A 5 ARG B 13 ASP B 14 0 +SHEET 2 A 5 LEU B 27 SER B 30 -1 O ARG B 29 N ARG B 13 +SHEET 3 A 5 VAL B 156 HIS B 159 1 O VAL B 156 N PHE B 28 +SHEET 4 A 5 ASP B 51 ASP B 54 1 N ALA B 51 O LEU B 157 +SHEET 5 A 5 ASP B 74 LEU B 77 1 O HIS B 74 N VAL B 52 +""" + ss_annot = ss.annotation.from_records(records=ss_records.split('\n')) + renumbering_dictionary = { + 'A':{ + (' 252', ' '): (' 253', 'A'), + (' 275', ' '): (' 276', 'A'), + }, + 'B':{ + (' 27', ' '): (' 28', 'C'), + (' 13', ' '): (' 13', 'D'), + }} + ss_annot.change_residue_numbering_in_place(renumbering_dictionary) + new_ss_str = ss_annot.as_pdb_str() + # print(new_ss_str) + assert_lines_in_text(new_ss_str, """\ +HELIX 14 14 SER A 253A ALA A 260 1 9 +HELIX 15 15 SER A 263 LEU A 276A 1 13 +SHEET 1 A 5 ARG B 13D ASP B 14 0 +SHEET 2 A 5 LEU B 28C SER B 30 -1 O ARG B 29 N ARG B 13D +SHEET 3 A 5 VAL B 156 HIS B 159 1 O VAL B 156 N PHE B 28 +SHEET 4 A 5 ASP B 51 ASP B 54 1 N ALA B 51 O LEU B 157 +SHEET 5 A 5 ASP B 74 LEU B 77 1 O HIS B 74 N VAL B 52 +""") + + def exercise(args): exercise_single() tst_pdb_file() tst_parsing_phil() exercise_only_b_altloc() exercise_multiplication() + exercise_change_residue_numbering() if (__name__ == "__main__"): exercise(sys.argv[1:]) From e6fd48f6f1197a60fd8a0ddafdcc8b49b41616eb Mon Sep 17 00:00:00 2001 From: terwill Date: Sun, 18 Feb 2024 08:03:24 -0800 Subject: [PATCH 145/748] Allow write of phil format ncs_spec in data_manager --- iotbx/data_manager/ncs_spec.py | 11 +++++++++-- mmtbx/ncs/ncs.py | 10 ++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/iotbx/data_manager/ncs_spec.py b/iotbx/data_manager/ncs_spec.py index bc769ceedd..15a9a0afcb 100644 --- a/iotbx/data_manager/ncs_spec.py +++ b/iotbx/data_manager/ncs_spec.py @@ -43,13 +43,20 @@ def get_default_output_ncs_spec_filename(self): filename += '.ncs_spec' return filename - def write_ncs_spec_file(self, ncs_object, filename=Auto, overwrite=Auto): + def write_ncs_spec_file(self, ncs_object, filename=Auto, overwrite=Auto, + format = 'ncs_spec'): + + assert format in ['ncs_spec','phil'] # default options if (filename is Auto): filename = self.get_default_output_ncs_spec_filename() - ncs_str = ncs_object.as_ncs_spec_string() + # set output extension + import os + fn, ext = os.path.splitext(filename) + filename = "%s.%s" %(fn, format) + ncs_str = ncs_object.as_ncs_spec_string(format = format) return self._write_text(NcsSpecDataManager.datatype, ncs_str, filename=filename, overwrite=overwrite) diff --git a/mmtbx/ncs/ncs.py b/mmtbx/ncs/ncs.py index acae52e3b6..1dfdd99cb4 100644 --- a/mmtbx/ncs/ncs.py +++ b/mmtbx/ncs/ncs.py @@ -3875,13 +3875,19 @@ def shift_cart(self): def shift_back_cart(self): return tuple([-a for a in self.shift_cart()]) - def as_ncs_spec_string(self): + def as_ncs_spec_string(self, format = 'ncs_spec'): ''' shifts to original location and returns text string ''' + assert format in ['ncs_spec','phil'] shifted_ncs=self.coordinate_offset(coordinate_offset=self.shift_back_cart()) - return shifted_ncs.format_all_for_group_specification( + if format == 'ncs_spec': + return shifted_ncs.format_all_for_group_specification( log=null_out(),quiet=True,out=null_out()) + elif format == 'phil': + return shifted_ncs.format_all_for_phenix_refine( + quiet=True,out=null_out()) + def format_all_for_group_specification(self,log=None,quiet=True,out=None, file_name=None): From 047557eae60c480544f1880c3bbf617ea6f8105a Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Sun, 18 Feb 2024 16:20:00 -0800 Subject: [PATCH 146/748] Fmodel: small changes for GUI. --- mmtbx/programs/fmodel.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mmtbx/programs/fmodel.py b/mmtbx/programs/fmodel.py index 5dc107e2ff..7491d78317 100644 --- a/mmtbx/programs/fmodel.py +++ b/mmtbx/programs/fmodel.py @@ -10,6 +10,7 @@ import random from libtbx.utils import Sorry from cctbx.array_family import flex +from libtbx import group_args fmodel_from_xray_structure_params_str = """\ fmodel @@ -437,4 +438,10 @@ def run(self): print("Output file name:", ofn, file=self.logger) print("All done.", file=self.logger) print("-"*79, file=self.logger) - return ofn + self.output_file = ofn + + def get_results(self): + return group_args( + output_file=self.output_file, + model=self.data_manager.get_default_model_name()) + From b89a36e7583c8112695c6f5f49c5ac2a834ade2d Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Mon, 19 Feb 2024 08:15:28 -0800 Subject: [PATCH 147/748] iotbx: fix test for Windows --- iotbx/pdb/tst_secondary_structure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iotbx/pdb/tst_secondary_structure.py b/iotbx/pdb/tst_secondary_structure.py index c738a53955..d3b7259936 100644 --- a/iotbx/pdb/tst_secondary_structure.py +++ b/iotbx/pdb/tst_secondary_structure.py @@ -2144,7 +2144,7 @@ def exercise_change_residue_numbering(): SHEET 3 A 5 VAL B 156 HIS B 159 1 O VAL B 156 N PHE B 28 SHEET 4 A 5 ASP B 51 ASP B 54 1 N ALA B 51 O LEU B 157 SHEET 5 A 5 ASP B 74 LEU B 77 1 O HIS B 74 N VAL B 52 -""") +""".strip()) def exercise(args): From d19083fc8f1755d87c4bbed9409073d23ba49e74 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Tue, 20 Feb 2024 09:44:28 -0800 Subject: [PATCH 148/748] README: update branch name for Python 3.12 test results [skip ci] --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 25221ef5c9..6d3b9f8c56 100644 --- a/README.md +++ b/README.md @@ -159,8 +159,8 @@ A subset of tests is run on the current `cctbx-base` packages every night (10 pm --> - - variant + + variant @@ -231,8 +231,8 @@ A subset of tests is run on the current `cctbx-base` packages every night (10 pm --> - - variant + + variant @@ -363,8 +363,8 @@ A subset of tests is run on the current `cctbx-base` packages every night (10 pm --> - - variant + + variant From 7d5bc85422d94eaa0582f077a16b41afe0d58d08 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Tue, 20 Feb 2024 10:25:41 -0800 Subject: [PATCH 149/748] mmtbx: update import --- mmtbx/geometry_restraints/afitt.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mmtbx/geometry_restraints/afitt.py b/mmtbx/geometry_restraints/afitt.py index 9da674c23a..6a715c1d62 100644 --- a/mmtbx/geometry_restraints/afitt.py +++ b/mmtbx/geometry_restraints/afitt.py @@ -3,7 +3,7 @@ import copy from cctbx.array_family import flex from libtbx.utils import Sorry -import StringIO +from six.moves import cStringIO as StringIO from libtbx import easy_run from six.moves import zip from six.moves import range @@ -364,7 +364,7 @@ def make_afitt_input(self, sites_cart, resname_i, instance_i): assert len(elements) == len(sites_cart_ptrs), \ "No. of atoms in residue %s, instance %d does not equal to \ number of atom seq pointers." %(self.resname[resname_i], instance_i) - f=StringIO.StringIO() + f = StringIO() if len(self.covalent_data) == 0 or self.covalent_data[r_i][i_i] == None: # if True: f.write( '%d\n' %self.n_atoms[r_i]) @@ -445,7 +445,7 @@ def get_afitt_command(): cmd = "afitt_helper_mmff help" # used because afitt_helper_mmff hangs on no input ero = easy_run.fully_buffered(command=cmd, ) - out = StringIO.StringIO() + out = StringIO() ero.show_stderr(out=out) exe = "afitt_helper_mmff" if out.getvalue().find("OpenEye")>-1: @@ -467,7 +467,7 @@ def call_afitt(afitt_input, ff): ero = easy_run.fully_buffered(command=cmd, stdin_lines=afitt_input, ) - out = StringIO.StringIO() + out = StringIO() ero.show_stdout(out=out) if 'ENERGYTAG' not in out.getvalue().split(): ero.show_stderr() From 4036489f854def3d2fa77fb8788f1b2d20515138 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 20 Feb 2024 12:59:34 -0800 Subject: [PATCH 150/748] Fix functionality --- mmtbx/secondary_structure/build/ss_idealization.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mmtbx/secondary_structure/build/ss_idealization.py b/mmtbx/secondary_structure/build/ss_idealization.py index 08930168ac..cebd164d32 100644 --- a/mmtbx/secondary_structure/build/ss_idealization.py +++ b/mmtbx/secondary_structure/build/ss_idealization.py @@ -765,6 +765,8 @@ def whole_minimization(self): # print "="*80 # print "="*80 # print "="*80 + if not self.model.restraints_manager_available(): + self.model.process(make_restraints=True) grm = self.model.get_restraints_manager() ssm_log = null_out() if self.processed_params.verbose: From 03ad9e6cd922863ed9e597a915395210b411c0cd Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 21 Feb 2024 16:39:21 -0800 Subject: [PATCH 151/748] Bump year in notices [skip ci] --- COPYRIGHT.txt | 2 +- LICENSE.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index 420a9edae6..063e3465a7 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -1,6 +1,6 @@ *** Copyright Notice *** -cctbx Copyright (c) 2006 - 2023, The Regents of the University of +cctbx Copyright (c) 2006 - 2024, The Regents of the University of California, through Lawrence Berkeley National Laboratory (subject to receipt of any required approvals from the U.S. Dept. of Energy). All rights reserved. diff --git a/LICENSE.txt b/LICENSE.txt index a4d71d3886..1eebe60227 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ *** License agreement *** -cctbx Copyright (c) 2006 - 2023, The Regents of the University of +cctbx Copyright (c) 2006 - 2024, The Regents of the University of California, through Lawrence Berkeley National Laboratory (subject to receipt of any required approvals from the U.S. Dept. of Energy). All rights reserved. From 850fe7c3fda5de1b377aad893474019d4afc787d Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 22 Feb 2024 13:08:17 -0700 Subject: [PATCH 152/748] Catch near-int in add_tuples_int --- iotbx/map_manager.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/iotbx/map_manager.py b/iotbx/map_manager.py index b56b35ec87..1c06356a0c 100644 --- a/iotbx/map_manager.py +++ b/iotbx/map_manager.py @@ -2803,7 +2803,16 @@ def subtract_tuples_int(t1, t2): return tuple(flex.int(t1)-flex.int(t2)) def add_tuples_int(t1, t2): - return tuple(flex.int(t1)+flex.int(t2)) + try: + return tuple(flex.int(t1)+flex.int(t2)) + except Exception as e: # not integers + t1a = [] + for x in t1: + t1a.append(round(x)) + t2a = [] + for x in t2: + t2a.append(round(x)) + return tuple(flex.int(t1a)+flex.int(t2a)) def remove_site_with_most_neighbors(sites_cart): useful_norms_list = [] From 7467524eb9204575322456384499d0b7cd9c1c26 Mon Sep 17 00:00:00 2001 From: Derek Mendez Date: Fri, 23 Feb 2024 07:33:32 -0800 Subject: [PATCH 153/748] weaken the assertion --- simtbx/nanoBragg/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simtbx/nanoBragg/__init__.py b/simtbx/nanoBragg/__init__.py index eea55d7e1a..37ac4ef4bf 100644 --- a/simtbx/nanoBragg/__init__.py +++ b/simtbx/nanoBragg/__init__.py @@ -60,7 +60,7 @@ def set_mosaic_blocks_sym(self, crystal, reference_symbol, orig_mos_domains, ref # this should be equivalent to column matrix of real space vectors a,b,c = crystal_reference.get_real_space_vectors() - assert sqr(a+b+c).transpose()==A + assert np.allclose(sqr(a+b+c).transpose().elems , A.elems) # get the originally set mosaic blocks mos_blocks = self.get_mosaic_blocks()[:orig_mos_domains] From bf2ebeb085a56478babb73f920e812633d82692e Mon Sep 17 00:00:00 2001 From: Derek Mendez Date: Fri, 23 Feb 2024 07:47:29 -0800 Subject: [PATCH 154/748] patch up the script * dont duplicate the phil file, simply append to it * accepts multiple directories as inputs --- simtbx/command_line/estimate_Ncells_Eta.py | 31 +++++++++++++++------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/simtbx/command_line/estimate_Ncells_Eta.py b/simtbx/command_line/estimate_Ncells_Eta.py index 816b56c582..1b6b95349d 100644 --- a/simtbx/command_line/estimate_Ncells_Eta.py +++ b/simtbx/command_line/estimate_Ncells_Eta.py @@ -4,9 +4,9 @@ from argparse import ArgumentParser parser = ArgumentParser() -parser.add_argument("dirname", help="still process output folder", type=str) +parser.add_argument("dirname", help="still process output folder", type=str, nargs="+") parser.add_argument("--updatePhil", default=None, help="name of an exisiting stage 1 phil file to update (just the init.Ncells portion)", type=str) -parser.add_argument("--expSuffix", help="extension of refined experiments", type=str, default="_refined.expt") +parser.add_argument("--expSuffix", help="extension of refined experiments (default: _refined.expt)", type=str, default="_refined.expt") parser.add_argument("--thresh", type=float, default=7, help="MAD score for outliers (default=7 standard deviation above the median)") parser.add_argument("--useMean", action="store_true", help="set Eta and Nabc using the mean (default is median)") parser.add_argument("--NabcMax", type=float, default=70, help="If estaimated Nabc is above this value, it will set to this value") @@ -28,8 +28,14 @@ import glob from dxtbx.model import ExperimentList -glob_s = os.path.join(args.dirname, "*%s" % args.expSuffix) -fnames = glob.glob(glob_s) +fnames = [] +for dirname in args.dirname: + glob_s = os.path.join(dirname, "*%s" % args.expSuffix) + fnames += glob.glob(glob_s) +if not fnames: + if COMM.rank==0: + print("no fnames") + exit() #def main(jid): all_Ns = [] @@ -63,8 +69,15 @@ #for N,mos in results: # all_Ns += N # all_mos_spreads += mos +# template of the additional phil: +phil = """\ninit {{ + Nabc = [{n},{n},{n}] + eta_abc = [{m},{m},{m}] +}}\n +""" if COMM.rank==0: + print("Obtained %d estimates ..." % len(all_Ns)) import pandas import pylab as plt from simtbx.diffBragg import utils @@ -98,15 +111,13 @@ mean_N = args.NabcMax if mean_N > args.NabcMax else args.NabcMin print("Estimated N=%f, setting it to %f" %(temp, mean_N)) - phil = """\ninit {{ - Nabc = [{n},{n},{n}] - eta_abc = [{m},{m},{m}] - }}\n""".format(n=round(mean_N,4), m=mean_mos) + phil = phil.format(n=round(mean_N,4), m=mean_mos) if args.updatePhil is not None: - with open(args.updatePhil, "r+") as o: + with open(args.updatePhil, "r") as o: s = o.read() - s += phil + s += phil + with open(args.updatePhil, "w") as o: o.write(s) if args.plot: df.hist(bins=100, log=True) From 085d25e860716f05bcc7016bdd26bd4b0b32b433 Mon Sep 17 00:00:00 2001 From: terwill Date: Sat, 24 Feb 2024 14:34:57 -0700 Subject: [PATCH 155/748] Turn off auto-help in CCTBXParser get_program_params --- iotbx/cli_parser.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iotbx/cli_parser.py b/iotbx/cli_parser.py index 9ac34dd8ab..a1ebac9a98 100644 --- a/iotbx/cli_parser.py +++ b/iotbx/cli_parser.py @@ -299,11 +299,11 @@ def add_default_options(self): ) # --------------------------------------------------------------------------- - def parse_args(self, args): + def parse_args(self, args, skip_help = False): ''' ''' # default behavior with no arguments - if len(args) == 0: + if (len(args) == 0) and (not skip_help): self.print_help() self.exit() @@ -979,7 +979,7 @@ def get_program_params(run): parser = CCTBXParser(program_class=run.Program, logger=null_out()) - _ = parser.parse_args([]) + _ = parser.parse_args([], skip_help = True) return parser.working_phil.extract() # ============================================================================= From ac18d69ff9b12b81c66f6cb13989552d0f8ffe7a Mon Sep 17 00:00:00 2001 From: terwill Date: Sun, 25 Feb 2024 19:37:29 -0800 Subject: [PATCH 156/748] Allow specifying a list of top-level scopes to remove. This allows backward compatibility in which an overall scope has been removed --- iotbx/phil.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/iotbx/phil.py b/iotbx/phil.py index 1aac85f650..36d5a10b09 100644 --- a/iotbx/phil.py +++ b/iotbx/phil.py @@ -264,7 +264,9 @@ def get_file(self, file_name, force_type=None): # Utilities for Phenix GUI class setup_app_generic(object): - def __init__(self, master_phil_path): + def __init__(self, master_phil_path, + top_level_scopes_to_remove = None): + self.top_level_scopes_to_remove = top_level_scopes_to_remove master_phil = self.load_from_cache_if_possible(master_phil_path) if master_phil is None : raise Sorry("Couldn't start program using specified phil object (%s)!" % @@ -284,12 +286,13 @@ def __call__(self, args): command_name="phenix", usage_opts=["[model.pdb]", "[data.mtz]"], app_options=None, + top_level_scopes_to_remove = self.top_level_scopes_to_remove, home_scope="") return (self.master_phil,working_phil,options, unused_args) # TODO probably redundant, replace with process_command_line or similar? def parse_command_line_phil_args(self, args, master_phil, command_name, usage_opts, - app_options, home_scope, log=sys.stdout): + app_options, home_scope, top_level_scopes_to_remove = None, log=sys.stdout): sources = [] unused_args = [] interpreter = master_phil.command_line_argument_interpreter( @@ -298,6 +301,16 @@ def parse_command_line_phil_args(self, args, master_phil, command_name, usage_op if os.path.isfile(arg): try : user_phil = parse(file_name=arg) + if top_level_scopes_to_remove: + # ---------------------------------------------------------------- + # Backwards compatibility for modules with top-level scope removed + if user_phil and user_phil.objects and \ + (len(user_phil.objects) == 1) and \ + (user_phil.objects[0].name in top_level_scopes_to_remove): + print("REMOVING TOP-LEVEL SCOPE '%s'" %(user_phil.objects[0].name )) + user_phil.objects = user_phil.objects[0].objects + # ---------------------------------------------------------------- + sources.append(user_phil) except Exception as e : unused_args.append(os.path.abspath(arg)) From 0362c736de2cee340ba10756048da756521d8fe0 Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 20 Feb 2024 23:01:14 -0800 Subject: [PATCH 157/748] Fix bug where zero-probe atoms crash. --- cctbx/maptbx/qscore.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index 14d2add310..b5cfef0dda 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -365,12 +365,17 @@ def shell_probes_progressive( #Finish working on a single atom pts = np.array(pts) # should be shape (n_probes,3) - assert pts.shape == (n_probes_max,3),( - - f"Pts shape must be ({n_probes_max},3), not {pts.shape})") if pts.shape == (0,): # all probes clashed pts = np.full((n_probes_max,3),np.nan) + print(f"Failed to assign any probes to atom: {atom_i}") + + + assert pts.shape == (n_probes_max,3),( + + f"Pts shape must be ({n_probes_max},3), not {pts.shape}). Reached i={i}") + + all_pts.append(pts) From d62486f06ef213339422dabde63e8fe0870187eb Mon Sep 17 00:00:00 2001 From: cschlick Date: Mon, 26 Feb 2024 23:52:08 -0800 Subject: [PATCH 158/748] Qscore: Committing most the changes from code review --- cctbx/maptbx/qscore.py | 209 +++++++++++++++++++++---------------- cctbx/maptbx/tst_qscore.py | 10 +- cctbx/programs/qscore.py | 123 +++++++++++++++------- 3 files changed, 212 insertions(+), 130 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index b5cfef0dda..74306b94c3 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -10,13 +10,11 @@ import pandas as pd - - master_phil_str = """ qscore { - nproc = 16 + nproc = 1 .type = int .help = Number of processors to use .short_caption = Number of processors to use @@ -36,9 +34,9 @@ .help = Min number of radial probes to use .short_caption = Number of radial probes to use .expert_level = 1 - selection_str = None + selection = None .type = str - .help = Only test atoms within this selection + .help = Only calculate atoms within this selection .short_caption = Only test atoms within this selection .expert_level = 1 @@ -60,11 +58,6 @@ .short_caption = The number of radial shells (includes start/stop, so minimum 2) .expert_level = 1 - shells = None - .type = float - .multiple = True - .help = Explicitly provide radial shells - rtol = 0.9 .type = float .help = Mapq rtol value, the "real" shell radii are r*rtol @@ -83,11 +76,9 @@ .help = Choose backend numpy or flex .expert_level = 1 - debug = False + write_probes = False .type = bool - .help = Return much more debug information - .short_caption = Returns a dictionary with additional debug information - .expert_level = 1 + .help = Write the qscore probes as a .bild file to visualize in Chimera } """ @@ -156,18 +147,18 @@ def generate_probes_flex(ctr, rad, N): # Fast numpy version -def generate_probes_np(atoms_xyz, rad, n_probes): +def generate_probes_np(sites_cart, rad, n_probes): """ Generate probes using the same methodology as Pintile mapq, but vectorized - atoms_xyz: np array of shape (n_atoms,3) + sites_cart: np array of shape (n_atoms,3) rad: the radius at which to place the probes N: the number of probes per atom Returns: probes (np.ndarray): shape (n_atoms,n_probes,3) """ - assert atoms_xyz.ndim == 2 and atoms_xyz.shape[-1]==3, ( + assert sites_cart.ndim == 2 and sites_cart.shape[-1]==3, ( "Provide coordinates in shape (n_atoms,3)") N = n_probes @@ -187,7 +178,7 @@ def generate_probes_np(atoms_xyz, rad, n_probes): probes = rad * np.stack([x, y, z], axis=-1) # Adjusting location of generated points relative to point ctr - probes = probes.reshape(-1, 1, 3) + atoms_xyz.reshape(1, -1, 3) + probes = probes.reshape(-1, 1, 3) + sites_cart.reshape(1, -1, 3) # reshape (n_atoms,n_probes,3) probes = probes.swapaxes(0,1) @@ -206,7 +197,7 @@ def get_probe_mask( log=null_out(), ): """ - atoms_xyz shape (n_atoms,3) + sites_cart shape (n_atoms,3) probes_xyz shape (n_atoms,n_probes,3) If expected is None, infer atom indices from probes_xyz @@ -267,7 +258,7 @@ def get_probe_mask( def shell_probes_progressive( - atoms_xyz=None, # A numpy array of shape (N,3) + sites_cart=None, # A numpy array of shape (N,3) atoms_tree=None, # An atom_xyz scipy kdtree selection_bool=None,# Boolean atom selection n_probes_target=8,# The desired number of probes per shell @@ -287,7 +278,7 @@ def shell_probes_progressive( "If not providing an atom tree, \ provide a 2d atom coordinate array to build tree") - atoms_tree = KDTree(atoms_xyz) + atoms_tree = KDTree(sites_cart) # Manage log if log is None: @@ -295,15 +286,15 @@ def shell_probes_progressive( # manage selection input if selection_bool is None: - selection_bool = np.full(len(atoms_xyz),True) + selection_bool = np.full(len(sites_cart),True) # do selection - atoms_xyz_sel = atoms_xyz[selection_bool] - n_atoms = atoms_xyz_sel.shape[0] + sites_cart_sel = sites_cart[selection_bool] + n_atoms = sites_cart_sel.shape[0] all_pts = [] # list of probe arrays for each atom for atom_i in range(n_atoms): - coord = atoms_xyz_sel[atom_i:atom_i+1] + coord = sites_cart_sel[atom_i:atom_i+1] outRAD = RAD * rtol @@ -363,17 +354,14 @@ def shell_probes_progressive( # End sampling iteration + #Finish working on a single atom pts = np.array(pts) # should be shape (n_probes,3) - - if pts.shape == (0,): # all probes clashed + if pts.shape == (0,): # all probes clashed, continue with zero probes pts = np.full((n_probes_max,3),np.nan) - print(f"Failed to assign any probes to atom: {atom_i}") - assert pts.shape == (n_probes_max,3),( - - f"Pts shape must be ({n_probes_max},3), not {pts.shape}). Reached i={i}") + f"Pts shape must be ({n_probes_max},3), not {pts.shape})") @@ -390,48 +378,54 @@ def shell_probes_progressive( #### Run shell functions for multiple shells(possibly in parallel) ################################################################################ def get_probes( - atoms_xyz=None, - sites_cart = None, + sites_cart=None, atoms_tree = None, - params=None, + shells = None, + n_probes_target=None, + n_probes_max=None, + n_probes_min=None, + rtol=None, + nproc=1, + backend=None, selection_bool_np = None, - selection_bool_flex=None, + selection_bool_flex = None, worker_func=None, - log=None): + log = null_out()): + """ - Generate probes for multiple radial shells (params.shells) + Generate probes for multiple radial shells (shells) """ - if params.backend == "numpy": + if backend == "numpy": assert worker_func in [shell_probes_progressive,shell_probes_precalculate] if atoms_tree is None: - atoms_tree = KDTree(atoms_xyz) + atoms_tree = KDTree(sites_cart) selection_bool = selection_bool_np - elif params.backend == "flex": + elif backend == "flex": if atoms_tree is None: - atoms_tree = KDTreeFlex(atoms_xyz) + atoms_tree = KDTreeFlex(sites_cart) selection_bool = selection_bool_flex else: - assert False, f"Unrecognized backend: {params.backend}" + assert False, f"Unrecognized backend: {backend}" - assert params.shells is not None, "Must provide explicit radial shells" + assert shells is not None, "Must provide explicit radial shells" task_list = [ { "func": worker_func, # Specify the function to call "kwargs": { - "atoms_xyz": atoms_xyz, # A numpy array of shape (N,3) + "sites_cart": sites_cart, # A numpy array of shape (N,3) "atoms_tree": atoms_tree, # An atom_xyz scipy kdtree "selection_bool": selection_bool, # Boolean atom selection - "n_probes_target": params.n_probes_target, # The desired number of probes per shell - "n_probes_max": params.n_probes_max, # The maximum number of probes allowed - "n_probes_min": params.n_probes_min, + "n_probes_target": n_probes_target, # The desired number of probes per shell + "n_probes_max": n_probes_max, # The maximum number of probes allowed + "n_probes_min": n_probes_min, "RAD": RAD, # The nominal radius of this shell - "rtol": params.rtol, # Multiplied with RAD to get actual radius + "rtol": rtol, # Multiplied with RAD to get actual radius "log": log, } - } for RAD in params.shells + } for RAD in shells ] - if params.nproc>1: + if nproc>1: with Pool() as pool: results = pool.map(starmap_wrapper, task_list) else: @@ -446,7 +440,7 @@ def get_probes( probe_xyz = [result[0] for result in results] probe_mask = [result[1] for result in results] - if params.backend == "numpy": + if backend == "numpy": return np.stack(probe_xyz), np.array(probe_mask) else: return probe_xyz, probe_mask @@ -455,7 +449,7 @@ def get_probes( ################################################################################ def shell_probes_precalculate( - atoms_xyz=None, # A numpy array of shape (N,3) + sites_cart=None, # A numpy array of shape (N,3) atoms_tree=None, # An atom_xyz scipy kdtree selection_bool=None,# Boolean atom selection n_probes_target=8,# The desired number of probes per shell @@ -476,7 +470,7 @@ def shell_probes_precalculate( provide a 2d atom coordinate array to build tree") # make atom kdtree - atoms_tree = KDTree(atoms_xyz) + atoms_tree = KDTree(sites_cart) # Manage log if log is None: @@ -484,14 +478,14 @@ def shell_probes_precalculate( # manage selection input if selection_bool is None: - selection_bool = np.full(len(atoms_xyz),True) + selection_bool = np.full(len(sites_cart),True) # do selection - atoms_xyz_sel = atoms_xyz[selection_bool] + sites_cart_sel = sites_cart[selection_bool] # get probe coordinates - probe_xyz = generate_probes_np(atoms_xyz_sel, RAD, n_probes_max) + probe_xyz = generate_probes_np(sites_cart_sel, RAD, n_probes_max) n_atoms, n_probes, _ = probe_xyz.shape probe_xyz_flat = probe_xyz.reshape(-1,3) @@ -527,30 +521,43 @@ def shell_probes_precalculate( return probe_xyz, probe_mask -def calc_qscore(mmm,params,log=null_out(),debug=False): + +def calc_qscore(mmm, + selection=None, + shells=None, + n_probes_target=8, + n_probes_max=16, + n_probes_min=4, + rtol=0.9, + probe_allocation_method=None, + backend='numpy', + nproc=1, + log=null_out(), + params=None,# TODO: remove this + debug=False): """ Calculate qscore from map model manager """ model = mmm.model() # never do hydrogen - model = model.select(model.selection("not element H")) + model = model.remove_hydrogens() mm = mmm.map_manager() # Get atoms - atoms_xyz = model.get_sites_cart().as_numpy_array() + sites_cart = model.get_sites_cart().as_numpy_array() # do selection - if params.selection_str != None: - selection_bool = mmm.model().selection(params.selection_str).as_numpy_array() # boolean + if selection != None: + selection_bool = mmm.model().selection(selection).as_numpy_array() # boolean if selection_bool.sum() ==0: print("Finished... nothing selected") return {"qscore_per_atom":None} else: - selection_bool = np.full(len(atoms_xyz),True) + selection_bool = np.full(len(sites_cart),True) # determine worker func - if params.probe_allocation_method == "precalculate": + if probe_allocation_method == "precalculate": worker_func=shell_probes_precalculate else: worker_func=shell_probes_progressive @@ -558,9 +565,15 @@ def calc_qscore(mmm,params,log=null_out(),debug=False): # Get probes and probe mask (probes to reject) probe_xyz,probe_mask = get_probes( - atoms_xyz=atoms_xyz, + sites_cart=sites_cart, atoms_tree = None, - params=params, + shells=shells, + n_probes_target=n_probes_target, + n_probes_max=n_probes_max, + n_probes_min=n_probes_min, + rtol=rtol, + nproc=nproc, + backend=backend, selection_bool_np = selection_bool, worker_func=worker_func, log = log, @@ -589,7 +602,7 @@ def calc_qscore(mmm,params,log=null_out(),debug=False): # g vals # create the reference data - radii = params.shells + radii = shells M = volume maxD = min(M.mean() + M.std() * 10, M.max()) minD = max(M.mean() - M.std() * 1, M.min()) @@ -624,13 +637,13 @@ def calc_qscore(mmm,params,log=null_out(),debug=False): # aggregate per residue qscore_df = aggregate_qscore_per_residue(model,q,window=3) q = flex.double(q) - qscore_per_residue = flex.double(qscore_df["Q-scorePerResidue"].values) + qscore_per_residue = flex.double(qscore_df["Q-ResidueRolling"].values) # Output - if debug or params.debug: + if debug: # Collect debug data result = { - "atom_xyz":atoms_xyz, + "atom_xyz":sites_cart, "probe_xyz":probe_xyz, "probe_mask":probe_mask, "d_vals":d_vals, @@ -772,7 +785,8 @@ def aggregate_qscore_per_residue(model,qscore_per_atom,window=3): # Merge the updated 'Q-Residue' and 'RollingMean' back into the original DataFrame df = df.merge(grouped_means[['rg_index', 'Q-Residue', 'RollingMean']], on='rg_index', how='left') df.drop("rg_index", axis=1, inplace=True) - df["Q-scorePerResidue"] = df["RollingMean"].astype(float) + df["Q-ResidueRolling"] = df["RollingMean"].astype(float) + df.drop(columns=["RollingMean"],inplace=True) return df def variable_neighbors_rolling_mean(series, window=3): @@ -860,7 +874,7 @@ def cctbx_atoms_to_df(atoms): #### CCTBX flex-based functions (precalculate mode) ################################################################################ def shell_probes_precalculate_flex( - atoms_xyz=None, # sites_cart. Flex vec3_double + sites_cart=None, # sites_cart. Flex vec3_double atoms_tree=None, # A KDTree selection_bool=None, # Boolean atom selection n_probes_target=8,# The desired number of probes per shell @@ -881,7 +895,7 @@ def shell_probes_precalculate_flex( provide a 2d atom coordinate array to build tree") # make atom kdtree - atoms_tree = KDTreeFlex(atoms_xyz) + atoms_tree = KDTreeFlex(sites_cart) # Manage log if log is None: @@ -890,11 +904,11 @@ def shell_probes_precalculate_flex( # manage selection input if selection_bool is None: - selection_bool = flex.bool(len(atoms_xyz),True) + selection_bool = flex.bool(len(sites_cart),True) # do selection - sites_sel = atoms_xyz.select(selection_bool) + sites_sel = sites_cart.select(selection_bool) n_atoms = len(sites_sel) # get probe coordinates @@ -940,7 +954,19 @@ def shell_probes_precalculate_flex( return probe_xyz, probe_mask -def calc_qscore_flex(mmm,params,log=null_out(),debug=False): +def calc_qscore_flex(mmm, + selection=None, + shells=None, + n_probes_target=8, + n_probes_max=16, + n_probes_min=4, + rtol=0.9, + probe_allocation_method=None, + backend='flex', + nproc=1, + log=null_out(), + params=None,# TODO: remove this + debug=False): """ Calculate qscore from map model manager """ @@ -952,24 +978,31 @@ def calc_qscore_flex(mmm,params,log=null_out(),debug=False): # Get atoms - atoms_xyz = model.get_sites_cart() + sites_cart = model.get_sites_cart() # do selection - if params.selection_str != None: - selection_bool = mmm.model().selection(params.selection_str) # boolean + if selection != None: + selection_bool = mmm.model().selection(selection) # boolean if selection_bool.count(True) ==0: print("Finished... nothing selected") return {"qscore_per_atom":None} else: - selection_bool = flex.bool(len(atoms_xyz),True) + selection_bool = flex.bool(len(sites_cart),True) + # Get probes and probe mask (probes to reject) # Get probes and probe mask (probes to reject) probe_xyzs,probe_masks = get_probes( - atoms_xyz=atoms_xyz, + sites_cart=sites_cart, atoms_tree = None, - params=params, - selection_bool_flex = selection_bool, + shells=shells, + n_probes_target=n_probes_target, + n_probes_max=n_probes_max, + n_probes_min=n_probes_min, + rtol=rtol, + nproc=nproc, + backend=backend, + selection_bool_np = selection_bool, worker_func=shell_probes_precalculate_flex, log = log, ) @@ -987,7 +1020,7 @@ def calc_qscore_flex(mmm,params,log=null_out(),debug=False): B_cctbx = minD_cctbx u = 0 sigma = 0.6 - x = flex.double(params.shells) + x = flex.double(shells) y_cctbx = ( A_cctbx * flex.exp(-0.5 * ((flex.double(x) - u) / sigma) ** 2) + B_cctbx @@ -998,14 +1031,14 @@ def calc_qscore_flex(mmm,params,log=null_out(),debug=False): full_flat_mask = flex.bool(n_shells*n_atoms*n_probes) # for each "shell row" for shell_idx,(probe_xyz,probe_mask) in enumerate(zip(probe_xyzs,probe_masks)): - probe_mask.reshape(flex.grid(n_atoms*params.n_probes_max)) + probe_mask.reshape(flex.grid(n_atoms*n_probes_max)) probe_xyz_sel = probe_xyz.select(probe_mask) # get d_vals for a "shell row" d_vals = mm.density_at_sites_cart(probe_xyz_sel) # get reference for the "shell row" - g_vals = flex.double(n_atoms*params.n_probes_max,y_cctbx[shell_idx]) + g_vals = flex.double(n_atoms*n_probes_max,y_cctbx[shell_idx]) g_vals = g_vals.select(probe_mask) # calc flat indices for the shell @@ -1052,13 +1085,13 @@ def calculate_1d_indices_for_atom(n_shells, n_atoms, n_probes, atom_idx): qscore_per_atom = flex.double(qscore_per_atom) qscore_df = aggregate_qscore_per_residue(model,np.array(qscore_per_atom),window=3) - qscore_per_residue = flex.double(qscore_df["Q-scorePerResidue"].values) + qscore_per_residue = flex.double(qscore_df["Q-ResidueRolling"].values) # Output - if debug or params.debug: + if debug: # Collect debug data result = { - "atom_xyz":atoms_xyz, + "atom_xyz":sites_cart, "probe_xyz":probe_xyzs, "probe_mask":probe_masks, "d_vals":full_flat_d, diff --git a/cctbx/maptbx/tst_qscore.py b/cctbx/maptbx/tst_qscore.py index eec8cc9f72..809ef8a188 100644 --- a/cctbx/maptbx/tst_qscore.py +++ b/cctbx/maptbx/tst_qscore.py @@ -256,8 +256,7 @@ def convert_func(g): "calc":{}, }, "params":{ - "selection_str":None, # Just calculate q score for a sub-selection - "iselection":None, + "selection":None, # Just calculate q score for a sub-selection "shells": [0.0,0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1., 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. ], "n_probes_target":8, @@ -311,8 +310,11 @@ def run_test(test): q_func = calc_qscore elif params.backend == "flex": q_func = calc_qscore_flex - - result = q_func(mmm,params,log=null_out(),debug=True) + params = convert_group_args_to_dict(params) + result = q_func(mmm, + **params, + params=convert_dict_to_group_args(params), + log=null_out()) test.results.calc = convert_dict_to_group_args(result) for key,value_expected in test.results.expected.__dict__.items(): value_calc= np.array(test.results.calc.__dict__[key]) diff --git a/cctbx/programs/qscore.py b/cctbx/programs/qscore.py index 1faef05bb2..2adec566ca 100644 --- a/cctbx/programs/qscore.py +++ b/cctbx/programs/qscore.py @@ -10,7 +10,9 @@ cctbx_atoms_to_df, write_bild_spheres ) +from libtbx.utils import Sorry import numpy as np +import pandas as pd # ============================================================================= @@ -27,13 +29,25 @@ class Program(ProgramTemplate): """ def validate(self): - assert self.params.qscore.backend in [ + if not self.params.qscore.backend in [ "numpy","flex" - ], "Provide one of 'numpy', 'flex'" + ]: + raise Sorry("Provide one of 'numpy', 'flex'") - assert self.params.qscore.probe_allocation_method in [ + if not self.params.qscore.probe_allocation_method in [ "progressive", "precalculate" - ], "Provide one of 'progressive' or 'precalculate'" + ]: + raise Sorry("Provide one of 'progressive' or 'precalculate'") + + if not (8<=self.params.qscore.n_probes_max<=128) or ( + not (8<=self.params.qscore.n_probes_max<=128) + ): + raise Sorry("Provide n_probe values in the range 8-128") + + if not (4<=self.params.qscore.shell_radius_num<=128): + raise SOrry("Provide shell_radius_num values in range 4-128") + + def run(self): print("Running") @@ -42,51 +56,89 @@ def run(self): mmm = self.data_manager.get_map_model_manager() # calculate shells - if (len(self.params.qscore.shells) ==0 or - self.params.qscore.shells[0] is None): - if None in self.params.qscore.shells: - self.params.qscore.shells.remove(None) - - # add a range of shells - start = self.params.qscore.shell_radius_start - stop = self.params.qscore.shell_radius_stop - num = self.params.qscore.shell_radius_num - shells = list(np.linspace( - start, - stop, - num, - endpoint=True)) - - shells = [ - 0.0,0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1., - 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. - ] - for shell in reversed(shells): - self.params.qscore.shells.insert(0,shell) + self.shells = [] + # add a range of shells + start = self.params.qscore.shell_radius_start + stop = self.params.qscore.shell_radius_stop + num = self.params.qscore.shell_radius_num + shells = list(np.linspace( + start, + stop, + num, + endpoint=True)) + + for shell in reversed(shells): + self.shells.insert(0,shell) # ignore hydrogens model = mmm.model() - model = model.select(model.selection("not element H")) + model = model.remove_hydrogens() # make mmm mmm.set_model(model,overwrite=True) - + # print output + print("Running Q-score:") + param_output = group_args( + n_probes_max=self.params.qscore.n_probes_max, + n_probes_target=self.params.qscore.n_probes_target, + rtol=self.params.qscore.rtol, + probe_allocation_method=self.params.qscore.probe_allocation_method, + selection=self.params.qscore.selection, + ) + print(param_output) + print("\nRadial shells used:") + print([round(shell,2) for shell in shells]) # run qscore backend = self.params.qscore.backend calc_func = calc_qscore if backend == "numpy" else calc_qscore_flex qscore_result= calc_func( mmm, - self.params.qscore, + selection=self.params.qscore.selection, + n_probes_target=self.params.qscore.n_probes_target, + n_probes_max=self.params.qscore.n_probes_max, + n_probes_min=self.params.qscore.n_probes_min, + rtol=self.params.qscore.rtol, + shells=self.shells, + probe_allocation_method = self.params.qscore.probe_allocation_method, + backend=backend, + nproc=self.params.qscore.nproc, log=self.logger) self.result = group_args(**qscore_result) - - - self.write_results() + # calculate some metrics + print("\nFinished running. Q-score results:") + df = self.result.qscore_dataframe + sel_mc = "protein and (name C or name N or name CA or name O or name CB)" + sel_mc = model.selection(sel_mc) + sel_sc = ~sel_mc + q_sc = df["Q-score"].iloc[sel_sc.as_numpy_array()].mean() + q_mc = df["Q-score"].iloc[sel_mc.as_numpy_array()].mean() + q_all = df["Q-score"].mean() + q_chains = df.groupby("chain_id").agg('mean',numeric_only=True) + q_chains = q_chains[["Q-score"]] + print("\nBy residue:") + print("----------------------------------------") + pd.set_option('display.max_rows', None) + print(df) + print("\nBy chain:") + print("----------------------------------------") + print(q_chains) + print("\nBy structure:") + print("----------------------------------------") + print(" Mean side chain Q-score:",round(q_sc,3)) + print(" Mean main chain Q-score:",round(q_mc,3)) + print(" Mean overall Q-score:",round(q_all,3)) + print(" Use --json flat to get json output") + + # store in results + self.result.q_score_chain_df = q_chains + self.result.q_score_side_chain = q_sc + self.result.q_score_main_chain = q_mc + self.result.q_score_overall = q_all def get_results(self): return self.result @@ -97,18 +149,13 @@ def get_results_as_JSON(self): } return json.dumps(results_dict,indent=2) - - def write_results(self): - with open("qscore_results.json","w") as fh: - fh.write(self.get_results_as_JSON()) - # write bild files - if self.params.qscore.debug: + if self.params.qscore.write_probes: print("Writing probe debug files...Using a small selection is recommended", file=self.logger) debug_path = Path("qscore_debug") debug_path.mkdir(exist_ok=True) - for i,shell in enumerate(self.params.qscore.shells): + for i,shell in enumerate(self.shells): shell = str(round(shell,2)) probe_xyz = self.result.probe_xyz[i] n_shells, n_atoms,n_probes,_ = self.result.probe_xyz.shape From 8de579f53b87bb8f54c5c087b1aee3b6cbf3c857 Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 27 Feb 2024 08:33:50 -0800 Subject: [PATCH 159/748] Qscore: code review changes applied to tst --- cctbx/maptbx/tst_qscore.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/cctbx/maptbx/tst_qscore.py b/cctbx/maptbx/tst_qscore.py index 809ef8a188..57cd1af9d2 100644 --- a/cctbx/maptbx/tst_qscore.py +++ b/cctbx/maptbx/tst_qscore.py @@ -42,7 +42,7 @@ def isclose_or_nan(a, b, atol=1e-3): def test_probe_generation(): # test the primary points generation function against expected data - atoms_xyz = np.array([[ 5.276, 12.488, 16.069], + sites_cart = np.array([[ 5.276, 12.488, 16.069], [ 5.649, 13.947, 16.076]]) probes_expected = np.array([[ @@ -64,17 +64,17 @@ def test_probe_generation(): [ 5.5845, 13.9741, 16.1474], [ 5.649 , 13.947 , 16.176 ]]]) # np - probes_xyz = generate_probes_np(atoms_xyz,0.1,8) + probes_xyz = generate_probes_np(sites_cart,0.1,8) assert np.all(np.isclose(probes_xyz,probes_expected,atol=1e-3)) # flex - atoms_xyz = flex.vec3_double(atoms_xyz) - probes_xyz = np.array(generate_probes_flex(atoms_xyz,0.1,8)).reshape((2,8,3)) + sites_cart = flex.vec3_double(sites_cart) + probes_xyz = np.array(generate_probes_flex(sites_cart,0.1,8)).reshape((2,8,3)) assert np.all(np.isclose(probes_xyz,probes_expected,atol=1e-3)) def test_probe_masking(): # test the progressive probe masking function against test data - atoms_xyz = np.array([ + sites_cart = np.array([ [0,0,-1], [0,0,1], ]) @@ -91,7 +91,7 @@ def test_probe_masking(): [0,0,0], [0,0,0.5]]]) - atom_tree = KDTree(atoms_xyz) + atom_tree = KDTree(sites_cart) calculated_result = get_probe_mask(atom_tree,probes_xyz,r=1.4) manual_result = np.array([[ True, True, False, False], @@ -104,7 +104,7 @@ def test_probe_masking(): def test_shell_probes(): # Test full progressive probe generation for a single shell - atoms_xyz = np.array([[ 5.276, 12.488, 16.069], + sites_cart = np.array([[ 5.276, 12.488, 16.069], [ 5.649, 13.947, 16.076]]) # Test progressive @@ -132,7 +132,7 @@ def test_shell_probes(): [ np.nan, np.nan, np.nan]]]) shell_func = shell_probes_progressive probe_xyz, probe_mask = shell_func( - atoms_xyz=atoms_xyz, + sites_cart=sites_cart, atoms_tree = None, selection_bool=None, n_probes_target=8, @@ -170,7 +170,7 @@ def test_shell_probes(): shell_func = shell_probes_precalculate probe_xyz, probe_mask = shell_func( - atoms_xyz=atoms_xyz, + sites_cart=sites_cart, atoms_tree = None, selection_bool=None, n_probes_target=8, @@ -184,7 +184,7 @@ def test_shell_probes(): # test precalculate (flex) shell_func = shell_probes_precalculate_flex probe_xyz,probe_mask = shell_func( - atoms_xyz=flex.vec3_double(atoms_xyz), + sites_cart=flex.vec3_double(sites_cart), atoms_tree = None, selection_bool=None, n_probes_target=8, From 9507ecf048387040c28c37d53083ef74801fd83e Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 27 Feb 2024 08:39:26 -0800 Subject: [PATCH 160/748] Fix indentation --- cctbx/maptbx/qscore.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index 74306b94c3..980a5c1372 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -98,8 +98,8 @@ def cumsum_flex(arr): result = flex.double(len(arr)) running_sum = 0.0 for i, x in enumerate(arr): - running_sum += x - result[i] = running_sum + running_sum += x + result[i] = running_sum return result def broadcast_add_vec3(ctr, points): @@ -348,9 +348,9 @@ def shell_probes_progressive( i_log.append(i) if i>=N_i: - assert False, "Too many iterations to get probes" + assert False, "Too many iterations to get probes" if i>0: - print("Going another round..",file=log) + print("Going another round..",file=log) # End sampling iteration @@ -431,10 +431,10 @@ def get_probes( else: results = [] for task in task_list: - worker_func = task["func"] - kwargs = task["kwargs"] - result = worker_func(**kwargs) - results.append(result) + worker_func = task["func"] + kwargs = task["kwargs"] + result = worker_func(**kwargs) + results.append(result) probe_xyz = [result[0] for result in results] @@ -778,8 +778,8 @@ def aggregate_qscore_per_residue(model,qscore_per_atom,window=3): for chain_id, group in grouped_means.groupby("chain_id"): # Your actual variable rolling mean calculation here - rolling_means = variable_neighbors_rolling_mean(group['Q-Residue'], window) - grouped_means.loc[group.index, 'RollingMean'] = rolling_means.values + rolling_means = variable_neighbors_rolling_mean(group['Q-Residue'], window) + grouped_means.loc[group.index, 'RollingMean'] = rolling_means.values # Merge the updated 'Q-Residue' and 'RollingMean' back into the original DataFrame @@ -899,12 +899,12 @@ def shell_probes_precalculate_flex( # Manage log if log is None: - log = null_out() + log = null_out() # manage selection input if selection_bool is None: - selection_bool = flex.bool(len(sites_cart),True) + selection_bool = flex.bool(len(sites_cart),True) # do selection @@ -1263,7 +1263,7 @@ def pre_sort_indices(self, points): def build_tree(self, indices, points, depth): if not indices: - return None + return None axis = depth % self.dims @@ -1287,7 +1287,7 @@ def build_tree(self, indices, points, depth): if len(sorted_indices_this_axis) == 0: - return None + return None median_idx = len(sorted_indices_this_axis) // 2 median_index = sorted_indices_this_axis[median_idx] From 80b9987922abb57f60fee68a5e6d0f3b24934c2f Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 27 Feb 2024 08:40:06 -0800 Subject: [PATCH 161/748] Fix indentation for tst --- cctbx/maptbx/tst_qscore.py | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/cctbx/maptbx/tst_qscore.py b/cctbx/maptbx/tst_qscore.py index 57cd1af9d2..f4dfc3d72f 100644 --- a/cctbx/maptbx/tst_qscore.py +++ b/cctbx/maptbx/tst_qscore.py @@ -225,7 +225,7 @@ def convert_func(d): converted_items = {k: convert_func(v) for k, v in d.items()} return libtbx.group_args(**converted_items) else: - return d + return d return convert_func(d) @@ -236,7 +236,7 @@ def convert_func(g): converted_items = {k: convert_func(v) for k, v in g.__dict__.items() if not k.startswith('_')} return converted_items else: - return g + return g return convert_func(g) @@ -280,7 +280,7 @@ def run_test(test): print("\tModel File:",test.data.model_file) print("\tMap:",test.data.map_file) if test.data.model_str is not None: - print("\tModel Str:\n",test.data.map_file) + print("\tModel Str:\n",test.data.map_file) dm = DataManager() assert [test.data.model_file,test.data.model_str].count(None)==1 @@ -298,18 +298,18 @@ def run_test(test): # get data from file or calculated if test.data.map_file is not None: - dm.process_real_map_file(test.data.map_file) - mm = dm.get_real_map() - mmm = map_model_manager(model=model,map_manager=mm) + dm.process_real_map_file(test.data.map_file) + mm = dm.get_real_map() + mmm = map_model_manager(model=model,map_manager=mm) else: - mmm = map_model_manager(model=model) - mmm.generate_map(d_min=2) + mmm = map_model_manager(model=model) + mmm.generate_map(d_min=2) params = test.params if params.backend == "numpy": - q_func = calc_qscore + q_func = calc_qscore elif params.backend == "flex": - q_func = calc_qscore_flex + q_func = calc_qscore_flex params = convert_group_args_to_dict(params) result = q_func(mmm, **params, @@ -317,8 +317,8 @@ def run_test(test): log=null_out()) test.results.calc = convert_dict_to_group_args(result) for key,value_expected in test.results.expected.__dict__.items(): - value_calc= np.array(test.results.calc.__dict__[key]) - assert np.all(isclose_or_nan(value_expected,value_calc)), ( + value_calc= np.array(test.results.calc.__dict__[key]) + assert np.all(isclose_or_nan(value_expected,value_calc)), ( f"Failed test: {test.data.name}\nExpected:\n{value_expected}\nCalc:\n{value_calc}") print("Done.\n") return convert_group_args_to_dict(test) @@ -332,7 +332,7 @@ def build_tests(test_dir="qscore_tst_dir"): # make test dir test_dir = Path("qscore_tst_dir") if test_dir.exists(): - shutil.rmtree(test_dir) + shutil.rmtree(test_dir) test_dir.mkdir() @@ -647,9 +647,8 @@ def test_program_template(test): # Test on some real models tests = build_tests() for test_name,test in tests.items(): - test = run_test(test) + test = run_test(test) # Test if program template runs, with default phil test_program_template(list(tests.values())[-1]) - From ac1fcf3a2854bb3bf1b0fe02fbf03cf41a89e9c0 Mon Sep 17 00:00:00 2001 From: cschlick Date: Wed, 28 Feb 2024 11:00:53 -0800 Subject: [PATCH 162/748] Qscore: only retain a single method (numpy precalculate) based on comments from group --- cctbx/maptbx/qscore.py | 819 ++----------------------------------- cctbx/maptbx/tst_qscore.py | 265 +----------- cctbx/programs/qscore.py | 39 +- 3 files changed, 53 insertions(+), 1070 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index 980a5c1372..0814227818 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -1,9 +1,11 @@ from __future__ import division from collections import defaultdict from multiprocessing import Pool +import warnings from libtbx.utils import null_out from cctbx.array_family import flex + import numpy as np import numpy.ma as ma from scipy.spatial import KDTree @@ -19,21 +21,12 @@ .help = Number of processors to use .short_caption = Number of processors to use .expert_level = 1 - n_probes_target = 8 + n_probes = 32 .type = int .help = Number of radial probes to use .short_caption = Number of radial probes to use .expert_level = 1 - n_probes_max = 16 - .type = int - .help = Max number of radial probes to use - .short_caption = Number of radial probes to use - .expert_level = 1 - n_probes_min = 4 - .type = int - .help = Min number of radial probes to use - .short_caption = Number of radial probes to use - .expert_level = 1 + selection = None .type = str .help = Only calculate atoms within this selection @@ -62,20 +55,6 @@ .type = float .help = Mapq rtol value, the "real" shell radii are r*rtol - probe_allocation_method = precalculate - .type = str - .help = The method used to allocate radial probes - .short_caption = Either 'progressive' or 'precalculate'. Progressive is the original method \ - where probes are proposed and rejected iteratively. \ - Precalculate is a method where probes are pre-allocated and \ - rejected once. Parallelization is done by radial shell. \ - Precalculate is much faster but will yield slightly different results. - - backend = numpy - .type = str - .help = Choose backend numpy or flex - .expert_level = 1 - write_probes = False .type = bool .help = Write the qscore probes as a .bild file to visualize in Chimera @@ -88,63 +67,6 @@ ################################################################################ -# Generate Points with flex - -def cumsum_flex(arr): - """ - Return an array that is the cumulative sum of arr - Analogous to np.cumsum - """ - result = flex.double(len(arr)) - running_sum = 0.0 - for i, x in enumerate(arr): - running_sum += x - result[i] = running_sum - return result - -def broadcast_add_vec3(ctr, points): - """ - Broadcast add two flex.vec3_double arrays. - - Params: - ctr (flex.vec3_double): the 'center' coordinates - points (flex.vec3_double): the points that will be added to each ctr - - Returns: - result (flex.vec3_double): array of shape (N*M,3), 1 point for each center - """ - N = points.size() - M = ctr.size() - extended_ctr = flex.vec3_double() - extended_points = flex.vec3_double() - - # Extend ctr and points - for point in ctr: - extended_ctr.extend(flex.vec3_double([point] * N)) - for _ in range(M): - extended_points.extend(points) - - # Perform addition - result = flex.vec3_double(M * N) - space =flex.size_t_range(M*N) - for i in space: - pt = extended_ctr[i:i+1] + extended_points[i:i+1] - result=result.set_selected(space[i:i+1],pt) - return result - - - -def generate_probes_flex(ctr, rad, N): - """ - TODO: replace with actual flex code. Code lost during failed git stash - """ - ctr = np.array(ctr) - - out= generate_probes_np(ctr,rad,N) - n_atoms,_ = ctr.shape - out = out.reshape((n_atoms*N,3)) - return flex.vec3_double(out) - # Fast numpy version def generate_probes_np(sites_cart, rad, n_probes): @@ -185,195 +107,6 @@ def generate_probes_np(sites_cart, rad, n_probes): return probes -################################################################################ -#### Progressive mode functions -################################################################################ - -def get_probe_mask( - atom_tree, - probes_xyz, - r=None, - expected=None, - log=null_out(), - ): - """ - sites_cart shape (n_atoms,3) - probes_xyz shape (n_atoms,n_probes,3) - - If expected is None, infer atom indices from probes_xyz - Else expected should be a single value, or have shape (n_atoms,n_probes) - - """ - - assert r is not None, "Provide a radius" - assert probes_xyz.ndim ==3 and probes_xyz.shape[-1] == 3,( - "Provide probes_xyz as shape: (n_atoms,n_probes,3)") - - n_atoms_probe,n_probes,_ = probes_xyz.shape - dim = probes_xyz.shape[-1] # 3 for cartesian coords - - - # reshaped_probes shape (n_atoms*n_probes,3) - reshaped_probes = probes_xyz.reshape(-1, 3) - atom_indices = np.tile(np.arange(n_atoms_probe), (probes_xyz.shape[1], 1)).T - - if not expected: - atom_indices = np.tile(np.arange(n_atoms_probe), (probes_xyz.shape[1], 1)).T - else: - atom_indices = np.full(probes_xyz.shape,expected) - - associated_indices = atom_indices.reshape(-1) - - - # query - # Check if any other tree points are within r of each query point - query_points = reshaped_probes - other_points_within_r = [] - for i, (query_point,idx) in enumerate(zip(query_points,associated_indices)): - - indices_within_r = atom_tree.query_ball_point(query_point, r) - - # Exclude the associated point - associated_index = associated_indices[i] - other_indices = [] - for idx in indices_within_r: - if idx != associated_index: - other_indices.append(idx) - if len(indices_within_r)==0: - other_indices.append(-1) - - - print(other_indices,file=log) - - other_points_within_r.append(other_indices) - - # true are points that don't get rejected - num_nbrs_other = np.array( - [len(inds) for i,inds in enumerate(other_points_within_r)]) - - num_nbrs_other = num_nbrs_other.reshape((n_atoms_probe,n_probes)) - mask = num_nbrs_other==0 - - return mask - - -def shell_probes_progressive( - sites_cart=None, # A numpy array of shape (N,3) - atoms_tree=None, # An atom_xyz scipy kdtree - selection_bool=None,# Boolean atom selection - n_probes_target=8,# The desired number of probes per shell - n_probes_max=16, # The maximum number of probes allowed - n_probes_min=4, - RAD=1.5, # The nominal radius of this shell - rtol=0.9, # Multiplied with RAD to get actual radius - log = null_out(), - ): - """ - Generate probes progressively for a single shell (radius) - """ - - # Do input validation - if not atoms_tree: - assert atoms_tree is None, ( - "If not providing an atom tree, \ - provide a 2d atom coordinate array to build tree") - - atoms_tree = KDTree(sites_cart) - - # Manage log - if log is None: - log = null_out() - - # manage selection input - if selection_bool is None: - selection_bool = np.full(len(sites_cart),True) - - # do selection - sites_cart_sel = sites_cart[selection_bool] - n_atoms = sites_cart_sel.shape[0] - - all_pts = [] # list of probe arrays for each atom - for atom_i in range(n_atoms): - coord = sites_cart_sel[atom_i:atom_i+1] - outRAD = RAD * rtol - - - print(coord,file=log) - pts = [] - i_log = [] - # try to get at least numPts] points at [RAD] distance - # from the atom, that are not closer to other atoms - N_i = 50 - - # If we find the necessary number of probes in the first iteration, - # then i will never go to 1 - for i in range(0, N_i): - rejections = 0 - - - - # progressively more points are grabbed with each failed iter - n_pts_to_grab = (n_probes_target + i * 2) - - # get the points in shape (n_atoms,n_pts_to_grab,3) - outPts = generate_probes_np(coord, RAD, n_pts_to_grab) - - # initialize points to keep - at_pts, at_pts_i = [None] * outPts.shape[1], 0 - - # mask for outPts, are they are closest to the expected atom - # mask shape (n_atoms,n_pts_to_grab) - # NOTE: n_atoms != len(outPts) - - # will get mask of shape (n_atoms,n_probes) - mask = get_probe_mask(atoms_tree,outPts,r=outRAD,expected=atom_i,log=log) - - # identify which ones to keep, progressively grow pts list - for pt_i, pt in enumerate(outPts[0]): - keep = mask[0,pt_i] # only one atom TODO: vectorize atoms - if keep: - at_pts[at_pts_i] = pt - at_pts_i += 1 - else: - #print("REJECTING...",pt,file=log) - rejections+=1 - pass - - # check if we have enough points to break the search loop - if ( at_pts_i >= n_probes_target): - pts.extend(at_pts[0:at_pts_i]) - pts = pts + [np.array([np.nan,np.nan,np.nan])]*(n_probes_max-len(pts)) - #print(pts) - break - - i_log.append(i) - if i>=N_i: - assert False, "Too many iterations to get probes" - if i>0: - print("Going another round..",file=log) - # End sampling iteration - - - - #Finish working on a single atom - pts = np.array(pts) # should be shape (n_probes,3) - if pts.shape == (0,): # all probes clashed, continue with zero probes - pts = np.full((n_probes_max,3),np.nan) - - assert pts.shape == (n_probes_max,3),( - f"Pts shape must be ({n_probes_max},3), not {pts.shape})") - - - - all_pts.append(pts) - - - # prepare output - probe_xyz = np.stack(all_pts) - probe_mask = ~(np.isnan(probe_xyz))[:,:,0] - - return probe_xyz, probe_mask - ################################################################################ #### Run shell functions for multiple shells(possibly in parallel) ################################################################################ @@ -381,31 +114,20 @@ def get_probes( sites_cart=None, atoms_tree = None, shells = None, - n_probes_target=None, - n_probes_max=None, - n_probes_min=None, + n_probes = None, rtol=None, nproc=1, - backend=None, - selection_bool_np = None, - selection_bool_flex = None, + selection_bool = None, worker_func=None, log = null_out()): """ Generate probes for multiple radial shells (shells) """ - if backend == "numpy": - assert worker_func in [shell_probes_progressive,shell_probes_precalculate] - if atoms_tree is None: - atoms_tree = KDTree(sites_cart) - selection_bool = selection_bool_np - elif backend == "flex": - if atoms_tree is None: - atoms_tree = KDTreeFlex(sites_cart) - selection_bool = selection_bool_flex - else: - assert False, f"Unrecognized backend: {backend}" + + atoms_tree = KDTree(sites_cart) + + assert shells is not None, "Must provide explicit radial shells" task_list = [ @@ -415,9 +137,7 @@ def get_probes( "sites_cart": sites_cart, # A numpy array of shape (N,3) "atoms_tree": atoms_tree, # An atom_xyz scipy kdtree "selection_bool": selection_bool, # Boolean atom selection - "n_probes_target": n_probes_target, # The desired number of probes per shell - "n_probes_max": n_probes_max, # The maximum number of probes allowed - "n_probes_min": n_probes_min, + "n_probes": n_probes, # The desired number of probes per shell "RAD": RAD, # The nominal radius of this shell "rtol": rtol, # Multiplied with RAD to get actual radius "log": log, @@ -440,21 +160,14 @@ def get_probes( probe_xyz = [result[0] for result in results] probe_mask = [result[1] for result in results] - if backend == "numpy": - return np.stack(probe_xyz), np.array(probe_mask) - else: - return probe_xyz, probe_mask -################################################################################ -#### numpy/scipy-based functions (precalculate mode) -################################################################################ + return np.stack(probe_xyz), np.array(probe_mask) + def shell_probes_precalculate( sites_cart=None, # A numpy array of shape (N,3) atoms_tree=None, # An atom_xyz scipy kdtree selection_bool=None,# Boolean atom selection - n_probes_target=8,# The desired number of probes per shell - n_probes_max=16, # The maximum number of probes allowed - n_probes_min=4, # The min number of probes allowed without error + n_probes=8,# The desired number of probes per shell RAD=1.5, # The nominal radius of this shell rtol=0.9, # Multiplied with RAD to get actual radius log = null_out(), @@ -485,7 +198,7 @@ def shell_probes_precalculate( sites_cart_sel = sites_cart[selection_bool] # get probe coordinates - probe_xyz = generate_probes_np(sites_cart_sel, RAD, n_probes_max) + probe_xyz = generate_probes_np(sites_cart_sel, RAD, n_probes) n_atoms, n_probes, _ = probe_xyz.shape probe_xyz_flat = probe_xyz.reshape(-1,3) @@ -511,13 +224,16 @@ def shell_probes_precalculate( probe_mask = expected_atom_mask & ~within_r_mask # Debug/Validation on number of probes per atom + n_probes_min = 4 + strict=False n_probes_per_atom = probe_mask.sum(axis=1) - insufficient_probes = np.where(n_probes_per_atom= n_probes_min, ( + if n_probes_per_atom.min() >= n_probes_min: + print( f"Some atoms have less than {n_probes_min} probes. \ - ({len(problematic_probes)}). Consider raising n_probes_max") + ({len(problematic_probes)}). Consider raising n_probes") return probe_xyz, probe_mask @@ -525,12 +241,8 @@ def shell_probes_precalculate( def calc_qscore(mmm, selection=None, shells=None, - n_probes_target=8, - n_probes_max=16, - n_probes_min=4, + n_probes=8, rtol=0.9, - probe_allocation_method=None, - backend='numpy', nproc=1, log=null_out(), params=None,# TODO: remove this @@ -557,10 +269,7 @@ def calc_qscore(mmm, selection_bool = np.full(len(sites_cart),True) # determine worker func - if probe_allocation_method == "precalculate": - worker_func=shell_probes_precalculate - else: - worker_func=shell_probes_progressive + worker_func=shell_probes_precalculate # Get probes and probe mask (probes to reject) @@ -568,13 +277,10 @@ def calc_qscore(mmm, sites_cart=sites_cart, atoms_tree = None, shells=shells, - n_probes_target=n_probes_target, - n_probes_max=n_probes_max, - n_probes_min=n_probes_min, + n_probes=n_probes, rtol=rtol, nproc=nproc, - backend=backend, - selection_bool_np = selection_bool, + selection_bool = selection_bool, worker_func=worker_func, log = log, ) @@ -635,6 +341,8 @@ def calc_qscore(mmm, q = np.around(q,4) # aggregate per residue + + model = model.select(flex.bool(selection_bool)) qscore_df = aggregate_qscore_per_residue(model,q,window=3) q = flex.double(q) qscore_per_residue = flex.double(qscore_df["Q-ResidueRolling"].values) @@ -759,7 +467,7 @@ def aggregate_qscore_per_residue(model,qscore_per_atom,window=3): atoms = model.get_atoms() res_seqs = [atom.parent().parent().resseq_as_int() for atom in atoms] chain_ids = [atom.parent().parent().parent().id for atom in atoms] - res_names = ["".join(atom.parent().parent().unique_resnames()) for atom in atoms] + res_names = [atom.parent().resname for atom in atoms] names = [atom.name.strip() for atom in atoms] df = pd.DataFrame({"resseq":res_seqs, "chain_id":chain_ids, @@ -776,12 +484,14 @@ def aggregate_qscore_per_residue(model,qscore_per_atom,window=3): grouped_means['RollingMean'] = None # Initialize column to avoid KeyError + # Until pandas is updated, need to suppress warning + warnings.filterwarnings("ignore", category=FutureWarning) for chain_id, group in grouped_means.groupby("chain_id"): - # Your actual variable rolling mean calculation here rolling_means = variable_neighbors_rolling_mean(group['Q-Residue'], window) grouped_means.loc[group.index, 'RollingMean'] = rolling_means.values + # Merge the updated 'Q-Residue' and 'RollingMean' back into the original DataFrame df = df.merge(grouped_means[['rg_index', 'Q-Residue', 'RollingMean']], on='rg_index', how='left') df.drop("rg_index", axis=1, inplace=True) @@ -868,470 +578,3 @@ def cctbx_atoms_to_df(atoms): df_atoms = pd.DataFrame(data,index=list(range(len(atoms)))) return df_atoms - - -################################################################################ -#### CCTBX flex-based functions (precalculate mode) -################################################################################ -def shell_probes_precalculate_flex( - sites_cart=None, # sites_cart. Flex vec3_double - atoms_tree=None, # A KDTree - selection_bool=None, # Boolean atom selection - n_probes_target=8,# The desired number of probes per shell - n_probes_max=16, # The maximum number of probes allowed - n_probes_min=4, # The min number of probes allowed without error - RAD=1.5, # The nominal radius of this shell - rtol=0.9, # Multiplied with RAD to get actual radius - log = null_out(), - strict = False, - ): - """ - Generate probes by precalculating for a single shell (radius) - """ - - # Do input validation - if not atoms_tree: - assert atoms_tree is None, ("If not providing an atom tree,\ - provide a 2d atom coordinate array to build tree") - - # make atom kdtree - atoms_tree = KDTreeFlex(sites_cart) - - # Manage log - if log is None: - log = null_out() - - # manage selection input - - if selection_bool is None: - selection_bool = flex.bool(len(sites_cart),True) - - - # do selection - sites_sel = sites_cart.select(selection_bool) - n_atoms = len(sites_sel) - - # get probe coordinates - probe_sites = generate_probes_flex(sites_sel, RAD, n_probes_max) - - - # modify "real" radius as in mapq - outRAD = RAD*rtol - - # query kdtree to get neighbors and their distances - dists,atom_indices = atoms_tree.query(probe_sites,k=2) - atom_indices_flat = flex_from_list(atom_indices) - - # Perform equivalent to atom_indices[:,:,0] if (n_atoms,n_probes,k) - dim0_indices = flex.size_t_range(0, n_atoms*n_probes_max*2, 2) - atom_indices_flat = atom_indices_flat.select(dim0_indices) - - # Build an index array that would be expected if each probe is near "its" atom - row_indices_flat = flex.size_t([ - i for i in range(n_atoms) for _ in range(n_probes_max)]) - - - # Mask for whether each probe's nearest atom is the one expected - expected_mask = row_indices_flat == atom_indices_flat - - - # A second mask to determine if the second nearest neighbor should be rejected - # (whether the second nearest neighbor is within the rejection radius) - dists = flex_from_list(dists) - # perform equivalent selcetion to dists[:,:,1] if (n_atoms,n_probes,k) - dist_dim1_sel = flex.size_t([i * 2 + 1 for i in range(n_atoms * n_probes_max)]) - dists_dim1 = dists.select(dist_dim1_sel) - within_r_mask = dists_dim1 1: - flex_array.reshape(flex.grid(*shape)) - return flex_array - - -def flatten_and_shape(lst): - """Flatten a nested list and return its shape.""" - def helper(l): - if not isinstance(l, list): - return [l], () - flat = [] - shapes = [] - for item in l: - f, s = helper(item) - flat.extend(f) - shapes.append(s) - if len(set(shapes)) != 1: - raise ValueError("Ragged nested list detected.") - return flat, (len(l),) + shapes[0] - - flattened, shape = helper(lst) - return flattened, shape - - -def get_dtype_of_list(lst): - dtypes = {type(item) for item in lst} - - if len(dtypes) > 1: - raise ValueError("Multiple data types detected.") - elif len(dtypes) == 0: - raise ValueError("Empty list provided.") - else: - return dtypes.pop() - - -def nd_to_1d_indices(indices, shape): - """Generate the 1d indices given nd indices and an array shape""" - # Normalize indices to always use slice objects - normalized_indices = [] - for dim, idx in enumerate(indices): - if idx is None: - normalized_indices.append(slice(0, shape[dim])) - else: - normalized_indices.append(idx) - - # If any index is a slice, recursively call function for each value in slice - for dim, (i, s) in enumerate(zip(normalized_indices, shape)): - if isinstance(i, slice): - result_indices = [] - start, stop, step = i.indices(s) - for j in range(start, stop, step): - new_indices = list(normalized_indices) - new_indices[dim] = j - result_indices.extend(nd_to_1d_indices(new_indices, shape)) - return result_indices - - # If no slices, calculate single 1D index - index = 0 - stride = 1 - for i, dim in reversed(list(zip(normalized_indices, shape))): - index += i * stride - stride *= dim - return [index] - - -def cdist_flex(A, B): - """A flex implementation of the cdist function""" - - def indices_2d_flex(dimensions): - N = len(dimensions) - if N != 2: - raise ValueError("Only 2D is supported for this implementation.") - - # Create the row indices - row_idx = flex.size_t(chain.from_iterable( - [[i] * dimensions[1] for i in range(dimensions[0])])) - - # Create the column indices - col_idx = flex.size_t(chain.from_iterable( - [list(range(dimensions[1])) for _ in range(dimensions[0])])) - - return row_idx, col_idx - - i_idxs, j_idxs = indices_2d_flex((A.focus()[0], B.focus()[0])) - - r = i_idxs - xi = i_idxs*3 - yi = i_idxs*3 + 1 - zi = i_idxs*3 + 2 - - xa = A.select(xi) - ya = A.select(yi) - za = A.select(zi) - - xj = j_idxs*3 - yj = j_idxs*3 + 1 - zj = j_idxs*3 + 2 - - xb = B.select(xj) - yb = B.select(yj) - zb = B.select(zj) - - d = ((xb - xa)**2 + (yb - ya)**2 + (zb - za)**2)**0.5 - d.reshape(flex.grid((A.focus()[0], B.focus()[0]))) - - return d - -################################################################################ -#### KDTree implementation using flex arrays (no numpy/scipy) -################################################################################ -class KDTreeFlexNode: - def __init__(self, index, point, left=None, right=None): - self.index = index - self.point = point - self.left = left - self.right = right - - -class KDTreeFlex: - def __init__(self, points): - self.dims = len(points[0]) - self.axis_sorted_indices = self.pre_sort_indices(points) - self.root = self.build_tree(flex.size_t_range(len(points)), points, 0) - - - def pre_sort_indices(self, points): - # Sort indices for each axis and return the sorted indices - x,y,z = points.parts() - sorted_indices = [flex.sort_permutation(x),flex.sort_permutation(y),flex.sort_permutation(z)] - return sorted_indices - - def build_tree(self, indices, points, depth): - if not indices: - return None - - axis = depth % self.dims - - - sorted_indices = self.axis_sorted_indices[axis] - - - # Step 4: Create an empty boolean mask of length N, initially set to False - mask = flex.bool(len(sorted_indices),False) - - # Directly set mask to True for positions in your query array - mask.set_selected(indices,True) - - # Step 5: Apply the mask to the sorted indices, then use this to create a sorted mask - # This step seems to be where you're looking to optimize. - # To directly use the sorted_indices to index into 'mask' and maintain sorting: - sorted_mask = mask.select(sorted_indices) - - # Now, apply this sorted_mask to select from the sorted_indices - sorted_indices_this_axis = sorted_indices.select(sorted_mask) - - - if len(sorted_indices_this_axis) == 0: - return None - - median_idx = len(sorted_indices_this_axis) // 2 - median_index = sorted_indices_this_axis[median_idx] - - left_indices = sorted_indices_this_axis[:median_idx] - right_indices = sorted_indices_this_axis[median_idx + 1:] - - return KDTreeFlexNode( - median_index, - points[median_index:median_index+1], - left=self.build_tree(left_indices, points, depth + 1), - right=self.build_tree(right_indices, points, depth + 1) - ) - def _nearest_neighbor(self, root, point, depth=0, best=None, k=1): - if root is None: - return best - - if best is None: - best = [] - - axis = depth % self.dims - next_branch = root.left if point[0][axis] < root.point[0][axis] else root.right - opposite_branch = root.right if next_branch is root.left else root.left - - # Recursively search the next branch - best = self._nearest_neighbor(next_branch, point, depth + 1, best, k) - - # Check the current root distance - current_dist = root.point.max_distance(point) - if len(best) < k or current_dist < best[-1]['dist']: - best.append({'index': root.index, 'dist': current_dist}) - best.sort(key=lambda x: x['dist']) - best = best[:k] # Keep only k nearest - - # Check if we need to search the opposite branch - if len(best) < k or abs(point[0][axis] - root.point[0][axis]) < best[-1]['dist']: - best = self._nearest_neighbor(opposite_branch, point, depth + 1, best, k) - - return best - - def query(self, query_points, k=1): - dists, inds = [], [] - for i,point in enumerate(query_points): - nearest = self._nearest_neighbor(self.root, query_points[i:i+1], k=k) - dists.append([n['dist'] for n in nearest]) - inds.append([n['index'] for n in nearest]) - return dists, inds diff --git a/cctbx/maptbx/tst_qscore.py b/cctbx/maptbx/tst_qscore.py index f4dfc3d72f..67def39e42 100644 --- a/cctbx/maptbx/tst_qscore.py +++ b/cctbx/maptbx/tst_qscore.py @@ -5,7 +5,6 @@ from pathlib import Path from iotbx.data_manager import DataManager -from cctbx.array_family import flex import libtbx from libtbx import phil from cctbx.maptbx.box import shift_and_box_model @@ -20,14 +19,8 @@ from cctbx.maptbx.qscore import ( generate_probes_np, - generate_probes_flex, - get_probe_mask, - shell_probes_progressive, shell_probes_precalculate, - shell_probes_precalculate_flex, calc_qscore, - calc_qscore_flex, - KDTreeFlex ) @@ -63,84 +56,17 @@ def test_probe_generation(): [ 5.7034, 14.0191, 16.1189], [ 5.5845, 13.9741, 16.1474], [ 5.649 , 13.947 , 16.176 ]]]) - # np probes_xyz = generate_probes_np(sites_cart,0.1,8) assert np.all(np.isclose(probes_xyz,probes_expected,atol=1e-3)) - # flex - sites_cart = flex.vec3_double(sites_cart) - probes_xyz = np.array(generate_probes_flex(sites_cart,0.1,8)).reshape((2,8,3)) - assert np.all(np.isclose(probes_xyz,probes_expected,atol=1e-3)) - -def test_probe_masking(): - # test the progressive probe masking function against test data - sites_cart = np.array([ - [0,0,-1], - [0,0,1], - ]) - - # probes_xyz shape (2,4,3), (n_atoms,n_probes,3) - probes_xyz = np.array([ - [[0,0,-2], - [0,0,-0.5], - [0,0,0], - [0,0,0.5]], - - [[0,0,-2], - [0,0,-0.5], - [0,0,0], - [0,0,0.5]]]) - atom_tree = KDTree(sites_cart) - - calculated_result = get_probe_mask(atom_tree,probes_xyz,r=1.4) - manual_result = np.array([[ True, True, False, False], - [False, False, False, True]]) - - - assert np.all(calculated_result==manual_result) def test_shell_probes(): - # Test full progressive probe generation for a single shell sites_cart = np.array([[ 5.276, 12.488, 16.069], [ 5.649, 13.947, 16.076]]) - # Test progressive - - expected_probes = np.array([[[ 5.276 , 12.488 , 14.569 ], - [ 5.0515, 13.4037, 14.9023], - [ 4.0297, 12.4397, 15.2357], - [ 4.825 , 11.1476, 15.569 ], - [ 6.3669, 11.4721, 15.9023], - [ 4.0466, 12.6981, 16.9023], - [ 5.343 , 11.5476, 17.2357], - [ 5.276 , 12.488 , 17.569 ], - [ np.nan, np.nan, np.nan], - [ np.nan, np.nan, np.nan]], - - [[ 5.649 , 13.947 , 14.576 ], - [ 5.4245, 14.8627, 14.9093], - [ 4.4027, 13.8987, 15.2427], - [ 6.7399, 12.9311, 15.9093], - [ 7.0245, 14.5216, 16.2427], - [ 5.6032, 15.3605, 16.576 ], - [ 4.4196, 14.1571, 16.9093], - [ 5.716 , 13.0066, 17.2427], - [ 5.649 , 13.947 , 17.576 ], - [ np.nan, np.nan, np.nan]]]) - shell_func = shell_probes_progressive - probe_xyz, probe_mask = shell_func( - sites_cart=sites_cart, - atoms_tree = None, - selection_bool=None, - n_probes_target=8, - n_probes_max=10, - RAD=1.5, - rtol=0.9, - log = null_out()) - assert np.all(isclose_or_nan(probe_xyz,expected_probes,atol=1e-3)) # test precalculate (numpy) @@ -173,25 +99,13 @@ def test_shell_probes(): sites_cart=sites_cart, atoms_tree = None, selection_bool=None, - n_probes_target=8, - n_probes_max=10, + n_probes=10, RAD=1.5, rtol=0.9, log = null_out()) assert np.all(isclose_or_nan(probe_xyz,expected_probes,atol=1e-3)) - # test precalculate (flex) - shell_func = shell_probes_precalculate_flex - probe_xyz,probe_mask = shell_func( - sites_cart=flex.vec3_double(sites_cart), - atoms_tree = None, - selection_bool=None, - n_probes_target=8, - n_probes_max=10, - RAD=1.5, - rtol=0.9, - log = null_out()) # test at single shell probe_xyz = np.array(probe_xyz) @@ -199,20 +113,6 @@ def test_shell_probes(): assert np.all(isclose_or_nan(probe_xyz,expected_probes,atol=1e-3)) -def test_kdtree_flex(): - # make sure the custom kdtree returns same results as scipy - points_np = np.random.random((1000,3))*10 - points_np_query = np.random.random((100,3))*10 - tree = KDTree(points_np) - dists,inds = tree.query(points_np_query,k=3) - - points_flex = flex.vec3_double(points_np) - points_flex_query = flex.vec3_double(points_np_query) - tree_flex = KDTreeFlex(points_flex) - dists_flex,inds_flex = tree_flex.query(points_flex_query,k=3) - - assert np.all(np.isclose(np.array(dists_flex),dists)) - assert np.all(np.isclose(np.array(inds_flex),inds)) ################################################################################ #### Test templates for real data @@ -259,12 +159,8 @@ def convert_func(g): "selection":None, # Just calculate q score for a sub-selection "shells": [0.0,0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1., 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. ], - "n_probes_target":8, - "n_probes_max":16, - "n_probes_min":4, + "n_probes":8, "nproc":4, - "probe_allocation_method":None, - "backend":None, "debug":True, "rtol":0.9, } @@ -306,10 +202,8 @@ def run_test(test): mmm.generate_map(d_min=2) params = test.params - if params.backend == "numpy": - q_func = calc_qscore - elif params.backend == "flex": - q_func = calc_qscore_flex + q_func = calc_qscore + params = convert_group_args_to_dict(params) result = q_func(mmm, **params, @@ -353,9 +247,7 @@ def build_tests(test_dir="qscore_tst_dir"): test["data"]["map_file"] = tst2_map_file test["data"]["name"] = "tst2_precalc_numpy" test["data"]["test_dir"] = test_dir - test["params"]["n_probes_max"] = 32 - test["params"]["probe_allocation_method"] = "precalculate" - test["params"]["backend"] = "numpy" + test["params"]["n_probes"] = 32 expected_qscore_per_atom= np.array([ 0.79852, 0.80609, 0.80133, 0.72103, 0.75883, 0.81456, 0.82049, 0.77932, 0.77675, 0.78246, 0.84899, 0.71687, 0.77178, 0.82013, @@ -374,45 +266,7 @@ def build_tests(test_dir="qscore_tst_dir"): test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom tests[test["data"]["name"]] = test - #tst2 flex precalculate - test = copy.deepcopy(test_template) - test["data"]["model_file"] = tst2_model_file - test["data"]["map_file"] = tst2_map_file - test["data"]["name"] = "tst2_precalc_flex" - test["data"]["test_dir"] = test_dir - test["params"]["n_probes_max"] = 32 - test["params"]["probe_allocation_method"] = "precalculate" - test["params"]["backend"] = "flex" - test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom - tests[test["data"]["name"]] = test - # tst2 progressive (numpy) - test = copy.deepcopy(test_template) - test["data"]["model_file"] = tst2_model_file - test["data"]["map_file"] = tst2_map_file - test["data"]["name"] = "tst2_progressive_numpy" - test["data"]["test_dir"] = test_dir - test["params"]["n_probes_max"] = 16 - test["params"]["n_probes_target"] = 8 - test["params"]["probe_allocation_method"] = "progressive" - test["params"]["backend"] = "numpy" - expected_qscore_per_atom= np.array([ - 0.81621, 0.79426, 0.83739, 0.67616, 0.75113, 0.81278, 0.75789, - 0.75623, 0.77865, 0.80018, 0.83847, 0.67525, 0.78909, 0.81843, - 0.81285, 0.80816, 0.89982, 0.73878, 0.81402, 0.79254, 0.81353, - 0.81543, 0.64347, 0.75470, 0.84479, 0.80404, 0.77552, 0.75578, - 0.80234, 0.84508, 0.66298, 0.76894, 0.76924, 0.90342, 0.78303, - 0.79723, 0.73253, 0.83709, 0.84759, 0.60567, 0.75056, 0.77734, - 0.89625, 0.85381, 0.74985, 0.69442, 0.80130, 0.82290, 0.57231, - 0.70518, 0.72775, 0.83440, 0.82770, 0.73152, 0.76289, 0.84503, - 0.79984, 0.75651, 0.79504, 0.82964, 0.83653, 0.83177, 0.68769, - 0.79369, 0.83867, 0.67165, 0.78174, 0.85420, 0.73200, 0.82028, - 0.73856, 0.79636, 0.83043, 0.69672, 0.79881, 0.75317, 0.78247, - 0.83621, 0.74694, 0.81975, 0.79633, 0.87402, 0.74882, 0.72080, - 0.87380, 0.74778, - ]) - test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom - tests[test["data"]["name"]] = test #5. 1yjp with simulated density # precalculated with numpy @@ -425,9 +279,7 @@ def build_tests(test_dir="qscore_tst_dir"): test["data"]["name"] = "1yjp_precalc_numpy" test["data"]["test_dir"] = test_dir test["data"]["map_file"] = None - test["params"]["n_probes_max"] = 32 - test["params"]["probe_allocation_method"] = "precalculate" - test["params"]["backend"] = "numpy" + test["params"]["n_probes"] = 32 expected_qscore_per_atom= np.array([ 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, @@ -444,43 +296,6 @@ def build_tests(test_dir="qscore_tst_dir"): tests[test["data"]["name"]] = test - # precalcualted with flex - test = copy.deepcopy(test_template) - test["data"]["model_file"] = yjp_model_file - test["data"]["name"] = "1yjp_precalc_flex" - test["data"]["test_dir"] = test_dir - test["data"]["map_file"] = None - test["params"]["n_probes_max"] = 32 - test["params"]["probe_allocation_method"] = "precalculate" - test["params"]["backend"] = "flex" - test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom - tests[test["data"]["name"]] = test - - # progressive (numpy) - test = copy.deepcopy(test_template) - test["data"]["model_file"] = yjp_model_file - test["data"]["name"] = "1yjp_progressive_numpy" - test["data"]["test_dir"] = test_dir - test["data"]["map_file"] = None - test["params"]["n_probes_max"] = 16 - test["params"]["n_probes_target"] = 8 - test["params"]["probe_allocation_method"] = "progressive" - test["params"]["backend"] = "numpy" - expected_qscore_per_atom= np.array([ - 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, - 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.07689, - 0.19082, 0.02124, 0.00000, 0.74434, 0.93599, 0.93209, 0.77202, - 0.91962, 0.91928, 0.96171, 0.91251, 0.91642, 0.36156, 0.31734, - 0.00000, 0.94018, 0.90381, 0.93852, 0.94966, 0.93188, 0.91575, - 0.91731, 0.97200, 0.95272, 0.94102, 0.89297, 0.91385, 0.96626, - 0.89274, 0.91538, 0.96871, 0.96205, 0.93226, 0.89114, 0.92745, - 0.94155, 0.90361, 0.92891, 0.74236, 0.92431, 0.28466, 0.91468, - 0.93081, 0.96238, 0.93960, 0.00000, 0.97779, 0.00000, 0.94679, - 0.97174, 0.89276, 0.90919, - ]) - test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom - tests[test["data"]["name"]] = test - #6. 1yjp with simulated density and shift and box dm = DataManager() dm.process_model_file(yjp_model_file) @@ -496,9 +311,7 @@ def build_tests(test_dir="qscore_tst_dir"): #test["data"]["model_file"] = str(boxed_1yjp_path) test["data"]["model_str"] = model.model_as_pdb() test["data"]["map_file"] = None - test["params"]["n_probes_max"] = 32 - test["params"]["probe_allocation_method"] = "precalculate" - test["params"]["backend"] = "numpy" + test["params"]["n_probes"] = 32 expected_qscore_per_atom = np.array([ 0.96035, 0.91590, 0.92283, 0.96654, 0.94164, 0.89421, 0.91464, 0.97026, 0.91649, 0.91408, 0.97073, 0.95491, 0.94386, 0.88791, @@ -514,17 +327,6 @@ def build_tests(test_dir="qscore_tst_dir"): test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom tests[test["data"]["name"]] = test - # precalculated with flex - test = copy.deepcopy(test_template) - test["data"]["model_file"] = str(boxed_1yjp_path) - test["data"]["name"] = "1yjp_boxed_precalc_flex" - test["data"]["test_dir"] = test_dir - test["data"]["map_file"] = None - test["params"]["n_probes_max"] = 32 - test["params"]["probe_allocation_method"] = "precalculate" - test["params"]["backend"] = "flex" - test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom - tests[test["data"]["name"]] = test #7 tst2 with shift_and_box (numpy,precalculate) @@ -549,9 +351,7 @@ def build_tests(test_dir="qscore_tst_dir"): test["data"]["map_file"] = tst2_map_file test["data"]["name"] = "tst2_boxed_precalc_numpy" test["data"]["test_dir"] = test_dir - test["params"]["n_probes_max"] = 32 - test["params"]["probe_allocation_method"] = "precalculate" - test["params"]["backend"] = "numpy" + test["params"]["n_probes"] = 32 expected_qscore_per_atom = np.array([ 0.79852, 0.80609, 0.80133, 0.72103, 0.75883, 0.81456, 0.82049, 0.77932, 0.77675, 0.78246, 0.84899, 0.71687, 0.77178, 0.82013, @@ -570,46 +370,6 @@ def build_tests(test_dir="qscore_tst_dir"): test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom tests[test["data"]["name"]] = test - # tst2, shift_and_box, precalculate, flex - test = copy.deepcopy(test_template) - test["data"]["model_file"] = str(boxed_tst2_path) - test["data"]["map_file"] = tst2_map_file - test["data"]["name"] = "tst2_boxed_precalc_flex" - test["data"]["test_dir"] = test_dir - test["params"]["n_probes_max"] = 32 - test["params"]["probe_allocation_method"] = "precalculate" - test["params"]["backend"] = "flex" - test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom - tests[test["data"]["name"]] = test - - # tst2, shift_and_box, progressive, numpy - test = copy.deepcopy(test_template) - test["data"]["model_file"] = str(boxed_tst2_path) - test["data"]["map_file"] = tst2_map_file - test["data"]["name"] = "tst2_boxed_progressive_numpy" - test["data"]["test_dir"] = test_dir - test["params"]["n_probes_max"] = 16 - test["params"]["n_probes_target"] = 8 - test["params"]["probe_allocation_method"] = "progressive" - test["params"]["backend"] = "numpy" - expected_qscore_per_atom = np.array([ - 0.81621, 0.79426, 0.83739, 0.67616, 0.75113, 0.81278, 0.75789, - 0.75623, 0.77865, 0.80018, 0.83847, 0.67525, 0.78909, 0.81843, - 0.81285, 0.80816, 0.89982, 0.73878, 0.81402, 0.79254, 0.81353, - 0.81543, 0.64347, 0.75470, 0.84479, 0.80404, 0.77552, 0.75578, - 0.80234, 0.84508, 0.66298, 0.76894, 0.76924, 0.90342, 0.78303, - 0.79723, 0.73253, 0.83709, 0.84759, 0.60567, 0.75056, 0.77734, - 0.89625, 0.85381, 0.74985, 0.69442, 0.80130, 0.82290, 0.57231, - 0.70518, 0.72775, 0.83440, 0.82770, 0.73152, 0.76289, 0.84503, - 0.79984, 0.75651, 0.79504, 0.82964, 0.83653, 0.83177, 0.68769, - 0.79369, 0.83867, 0.67165, 0.78174, 0.85420, 0.73200, 0.82028, - 0.73856, 0.79636, 0.83043, 0.69672, 0.79881, 0.75317, 0.78247, - 0.83621, 0.74694, 0.81975, 0.79633, 0.87402, 0.74882, 0.72080, - 0.87380, 0.74778, - - ]) - test["results"]["expected"]["qscore_per_atom"] = expected_qscore_per_atom - tests[test["data"]["name"]] = test return tests @@ -631,17 +391,12 @@ def test_program_template(test): if (__name__ == "__main__"): - #1. test probe generation + # test probe generation test_probe_generation() - #2. test probe masking (for progressive) - test_probe_masking() - - #3. test single shell probe generation + # test single shell probe generation test_shell_probes() - #4. test flex kdtree - test_kdtree_flex() # Test on some real models diff --git a/cctbx/programs/qscore.py b/cctbx/programs/qscore.py index 2adec566ca..9053ee88eb 100644 --- a/cctbx/programs/qscore.py +++ b/cctbx/programs/qscore.py @@ -6,7 +6,6 @@ from libtbx import group_args from cctbx.maptbx.qscore import ( calc_qscore, - calc_qscore_flex, cctbx_atoms_to_df, write_bild_spheres ) @@ -29,19 +28,8 @@ class Program(ProgramTemplate): """ def validate(self): - if not self.params.qscore.backend in [ - "numpy","flex" - ]: - raise Sorry("Provide one of 'numpy', 'flex'") - - if not self.params.qscore.probe_allocation_method in [ - "progressive", "precalculate" - ]: - raise Sorry("Provide one of 'progressive' or 'precalculate'") - - if not (8<=self.params.qscore.n_probes_max<=128) or ( - not (8<=self.params.qscore.n_probes_max<=128) - ): + # test for sane parameters + if not (4<=self.params.qscore.n_probes<=512): raise Sorry("Provide n_probe values in the range 8-128") if not (4<=self.params.qscore.shell_radius_num<=128): @@ -81,28 +69,20 @@ def run(self): # print output print("Running Q-score:") param_output = group_args( - n_probes_max=self.params.qscore.n_probes_max, - n_probes_target=self.params.qscore.n_probes_target, + n_probes=self.params.qscore.n_probes, rtol=self.params.qscore.rtol, - probe_allocation_method=self.params.qscore.probe_allocation_method, selection=self.params.qscore.selection, ) print(param_output) print("\nRadial shells used:") print([round(shell,2) for shell in shells]) # run qscore - backend = self.params.qscore.backend - calc_func = calc_qscore if backend == "numpy" else calc_qscore_flex - qscore_result= calc_func( + qscore_result= calc_qscore( mmm, selection=self.params.qscore.selection, - n_probes_target=self.params.qscore.n_probes_target, - n_probes_max=self.params.qscore.n_probes_max, - n_probes_min=self.params.qscore.n_probes_min, + n_probes=self.params.qscore.n_probes, rtol=self.params.qscore.rtol, shells=self.shells, - probe_allocation_method = self.params.qscore.probe_allocation_method, - backend=backend, nproc=self.params.qscore.nproc, log=self.logger) @@ -110,8 +90,12 @@ def run(self): self.result = group_args(**qscore_result) # calculate some metrics - print("\nFinished running. Q-score results:") df = self.result.qscore_dataframe + if self.params.qscore.selection is not None: + model = model.select(model.selection(self.params.qscore.selection)) + assert model.get_number_of_atoms()==len(df) + print("\nFinished running. Q-score results:") + sel_mc = "protein and (name C or name N or name CA or name O or name CB)" sel_mc = model.selection(sel_mc) sel_sc = ~sel_mc @@ -132,7 +116,8 @@ def run(self): print(" Mean side chain Q-score:",round(q_sc,3)) print(" Mean main chain Q-score:",round(q_mc,3)) print(" Mean overall Q-score:",round(q_all,3)) - print(" Use --json flat to get json output") + print("\n Use --json flag to get json output") + # store in results self.result.q_score_chain_df = q_chains From 6e759dc2ffb055ba232794253f63d12484956956 Mon Sep 17 00:00:00 2001 From: cschlick Date: Wed, 28 Feb 2024 11:03:57 -0800 Subject: [PATCH 163/748] clean clutter and unused imports --- cctbx/maptbx/tst_qscore.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cctbx/maptbx/tst_qscore.py b/cctbx/maptbx/tst_qscore.py index 67def39e42..cedddfff03 100644 --- a/cctbx/maptbx/tst_qscore.py +++ b/cctbx/maptbx/tst_qscore.py @@ -13,7 +13,6 @@ from cctbx.programs.qscore import Program as QscoreProgram import numpy as np -from scipy.spatial import KDTree From 7b32060a735f8f1d210fb34965f89e828150f29e Mon Sep 17 00:00:00 2001 From: Russ Taylor Date: Thu, 29 Feb 2024 08:24:37 -0500 Subject: [PATCH 164/748] Updating Reduce2 README.md --- mmtbx/reduce/README.md | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/mmtbx/reduce/README.md b/mmtbx/reduce/README.md index c4f81bb100..8e40a0dc62 100644 --- a/mmtbx/reduce/README.md +++ b/mmtbx/reduce/README.md @@ -111,24 +111,8 @@ repository. The tests include adding flip movers in both cases and then running the reduce2 and original reduce outputs and then compares the total scores to see which is better. The following files were tested, resulting in the same or better scores for most. The ones with worse -scores point to a set of outstanding issues with hydrogen placement that are still being investigated. -- 1bti: Reduce2 better. -- 1crn: Reduce2 better. -- 1ehz: Reduce2 better. -- 1otf: Reduce2 better. -- 1pq7_fragment: Same. -- 1ubq-nh3_test: **Reduce2 worse**. -- 1xso: Reduce2 better. -- 1yk4_snip: Reduce2 better. -- 2mbw_fragment: **Reduce2 worse**. -- 3cp5_fragment: Reduce2 better. -- 4fen: Reduce2 better. -- 5dka_fragment: Reduce2 better. -- 6xhv: Reduce2 better. -- 6t5h_fragment: Reduce2 better. -- 6tte_fragment: **Reduce2 worse**. -- 6vw1_fragment: **Reduce2 worse**. -- 7c31: Reduce2 better. +scores appear to be due to hydrogen placement difference for non-movable hydrogens where Reduce2 is +using more-correct angles that sometimes have lower scores in Probe2 but are nonetheless more accurate. Additional tests were performed using the **comparison_file** command-line option to compare the behavior of reduce2 with original reduce on a Mover-by-Mover basis. 3VYK was studied along @@ -136,9 +120,9 @@ with 1DFU. These tests turned up other issues that are being investigated. The 1 also studied, which has 164 Movers; the overall score was 75 higher for Reduce2, issues were created (and then resolved) for individual residues that were significantly lower. -As of 7/21/2023, the issues under investigation are described in the status and issues document at +As of 2/29/2024, the issues under investigation are described in the status and issues document at https://docs.google.com/document/d/1ogzS6QlBnPJRGU2CNzHvw0KhV8E5fXdwO1TwUEM7GQc/edit?usp=sharing which is being used to track ongoing issues. The major issues are: -- Some hydrogens are being placed improperly (sometimes too many sometimes too few). +- Ionic bonds are not being handled properly, causing flip Movers to be adjustable near ions. - The restraints information for many files in the PDB is not available, so many files cannot be run. - The mostly-Python Reduce2 is significantly slower than the original C++ reduce. From f13a1c66898babf93e0a82fe3a1246b58594201b Mon Sep 17 00:00:00 2001 From: randyjread Date: Fri, 1 Mar 2024 10:26:53 +0000 Subject: [PATCH 165/748] Add check for requested docking sphere too near edge of reconstruction. --- cctbx/maptbx/prepare_map_for_docking.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/cctbx/maptbx/prepare_map_for_docking.py b/cctbx/maptbx/prepare_map_for_docking.py index 7c76bfb769..82970893d7 100644 --- a/cctbx/maptbx/prepare_map_for_docking.py +++ b/cctbx/maptbx/prepare_map_for_docking.py @@ -1517,15 +1517,31 @@ def assess_cryoem_errors( # Get map coefficients for maps after spherical masking # Define box big enough to hold sphere plus soft masking + # Attempt to cope with spheres too near edge of full map, + # and don't let box deviate too far from cubic boundary_to_smoothing_ratio = 2 soft_mask_radius = d_min padding = soft_mask_radius * boundary_to_smoothing_ratio cushion = flex.double(3,radius+padding) cart_min = flex.double(sphere_cent_map) - cushion cart_max = flex.double(sphere_cent_map) + cushion - for i in range(3): # Keep within input map + for i in range(3): # Keep within input map, check whether box has been reduced too much cart_min[i] = max(cart_min[i],0) cart_max[i] = min(cart_max[i],ucpars[i]-spacings[i]) + min_box_width = flex.min(cart_max - cart_min) + if min_box_width < 2*(radius+padding): + # Probably better to reduce boundary width than radius + new_boundary_to_smoothing_ratio = max(1.5, (min_box_width/2.-radius)/d_min) + radius_check = min_box_width/2. - new_boundary_to_smoothing_ratio * d_min + if radius_check < 0.8*radius: # Allowable sphere would be too small + print("\nModel sphere has radius of ",radius, file=log) + print("Sphere that fits where requested has radius of ",radius_check, file=log) + raise Sorry("Target sphere too near edge of map") + elif radius_check < radius: + print("\nWARNING: Model sphere radius reduced from ",radius, + " to ",radius_check," to stay within map", file=log) + radius = radius_check + boundary_to_smoothing_ratio = new_boundary_to_smoothing_ratio cs = mmm.crystal_symmetry() uc = cs.unit_cell() @@ -1994,7 +2010,7 @@ def run(): if args.model is not None: if not (args.cutout_model or args.flatten_model): - raise Sorry('Use for model must be specified (flatten or cut out map') + raise Sorry("Use for model must be specified (flatten or cut out map)") model_file = args.model model = dm.get_model(model_file) From 24ef7130888a8d33881676c5acd56fddb1089719 Mon Sep 17 00:00:00 2001 From: Randy Read Date: Fri, 1 Mar 2024 11:32:20 +0000 Subject: [PATCH 166/748] Reducing boundary_to_smoothing_ratio to keep larger sphere of density turned out to be a bad idea. --- cctbx/maptbx/prepare_map_for_docking.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/cctbx/maptbx/prepare_map_for_docking.py b/cctbx/maptbx/prepare_map_for_docking.py index 82970893d7..72e83183ac 100644 --- a/cctbx/maptbx/prepare_map_for_docking.py +++ b/cctbx/maptbx/prepare_map_for_docking.py @@ -1530,10 +1530,8 @@ def assess_cryoem_errors( cart_max[i] = min(cart_max[i],ucpars[i]-spacings[i]) min_box_width = flex.min(cart_max - cart_min) if min_box_width < 2*(radius+padding): - # Probably better to reduce boundary width than radius - new_boundary_to_smoothing_ratio = max(1.5, (min_box_width/2.-radius)/d_min) - radius_check = min_box_width/2. - new_boundary_to_smoothing_ratio * d_min - if radius_check < 0.8*radius: # Allowable sphere would be too small + radius_check = min_box_width/2. - padding + if radius_check < 0.8*radius: # Allowable sphere would be too small to consider print("\nModel sphere has radius of ",radius, file=log) print("Sphere that fits where requested has radius of ",radius_check, file=log) raise Sorry("Target sphere too near edge of map") @@ -1541,7 +1539,6 @@ def assess_cryoem_errors( print("\nWARNING: Model sphere radius reduced from ",radius, " to ",radius_check," to stay within map", file=log) radius = radius_check - boundary_to_smoothing_ratio = new_boundary_to_smoothing_ratio cs = mmm.crystal_symmetry() uc = cs.unit_cell() From 984ac95f5a4230e215b49bff6e6dc0b3aa65ff62 Mon Sep 17 00:00:00 2001 From: Randy Read Date: Fri, 1 Mar 2024 13:08:32 +0000 Subject: [PATCH 167/748] Only warn about significant changes in cutout sphere size. --- cctbx/maptbx/prepare_map_for_docking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cctbx/maptbx/prepare_map_for_docking.py b/cctbx/maptbx/prepare_map_for_docking.py index 72e83183ac..cb7f7c6f1b 100644 --- a/cctbx/maptbx/prepare_map_for_docking.py +++ b/cctbx/maptbx/prepare_map_for_docking.py @@ -1535,7 +1535,7 @@ def assess_cryoem_errors( print("\nModel sphere has radius of ",radius, file=log) print("Sphere that fits where requested has radius of ",radius_check, file=log) raise Sorry("Target sphere too near edge of map") - elif radius_check < radius: + elif radius_check < radius*0.99: print("\nWARNING: Model sphere radius reduced from ",radius, " to ",radius_check," to stay within map", file=log) radius = radius_check From 5f4e9e0f124a5f199409bac51b3381586c593c7b Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Fri, 1 Mar 2024 15:22:37 -0800 Subject: [PATCH 168/748] passing bonds for better completion --- mmtbx/ligands/ready_set_utils.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/mmtbx/ligands/ready_set_utils.py b/mmtbx/ligands/ready_set_utils.py index faaaa28547..a957e72c29 100644 --- a/mmtbx/ligands/ready_set_utils.py +++ b/mmtbx/ligands/ready_set_utils.py @@ -591,6 +591,15 @@ def get_bonds(): if rc: additional_hydrogens.append(rc) return additional_hydrogens +def _check_for(atom_holder, resname, name): + for atom in atom_holder.atoms(): + if atom.name.strip()!=name.strip(): continue + p1 = atom.parent() + if p1.resname.strip()!=resname.strip(): continue + print(atom.quote(), resname, name) + return True + return False + def add_terminal_hydrogens_via_residue_groups(hierarchy, geometry_restraints_manager, terminate_all_N_terminals=False, @@ -600,6 +609,9 @@ def add_terminal_hydrogens_via_residue_groups(hierarchy, retain_original_hydrogens=True, verbose=False, ): + # assert not _check_for(hierarchy, '0QS', 'HC') + from mmtbx.ligands.hierarchy_utils import get_bonds_as_dict + bonds=get_bonds_as_dict(geometry_restraints_manager) additional_hydrogens = [] for residue_group, start, end in generate_residue_group_with_start_and_end( hierarchy, @@ -618,6 +630,7 @@ def add_terminal_hydrogens_via_residue_groups(hierarchy, else: rc = add_n_terminal_hydrogens_to_residue_group( residue_group, + bonds=bonds, use_capping_hydrogens=use_capping_hydrogens, append_to_end_of_model=append_to_end_of_model, retain_original_hydrogens=retain_original_hydrogens, @@ -628,6 +641,7 @@ def add_terminal_hydrogens_via_residue_groups(hierarchy, # assert ptr==0 rc = add_c_terminal_oxygens_to_residue_group( residue_group, + bonds=bonds, use_capping_hydrogens=use_capping_hydrogens, append_to_end_of_model=append_to_end_of_model, ) From 5cdc535ba55b612636bbb21d15d9ee2186539992 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Fri, 1 Mar 2024 16:04:48 -0800 Subject: [PATCH 169/748] Update CHANGELOG.rst for ${version} release [skip ci] --- CHANGELOG.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b592fa75a6..213469e3d0 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,9 @@ +2024.2 +====== + +* Improved handling of writing models in mmCIF or PDB formats +* Speedups to reduce2 and probe2 + 2024.1 ====== From 9601aa6330b865ef7807c86822151eab0f6dcda7 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Fri, 1 Mar 2024 16:10:12 -0800 Subject: [PATCH 170/748] fixes tests --- mmtbx/ligands/ready_set_utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mmtbx/ligands/ready_set_utils.py b/mmtbx/ligands/ready_set_utils.py index a957e72c29..cd0398d207 100644 --- a/mmtbx/ligands/ready_set_utils.py +++ b/mmtbx/ligands/ready_set_utils.py @@ -106,7 +106,9 @@ def add_n_terminal_hydrogens_to_atom_group(ag, if ag.get_atom(h): h_count+=1 if ag.get_atom(h.replace('H', 'D')): d_count+=1 number_of_hydrogens=3 + if verbose: print('number_of_hydrogens',number_of_hydrogens) if use_capping_hydrogens: + if verbose: print('use_capping_hydrogens...') number_of_hydrogens-=1 #if ag.atoms()[0].parent().resname=='PRO': # number_of_hydrogens=-1 @@ -124,8 +126,8 @@ def _get_atom_with_i_seq(ag, i_seq): ba = _get_atom_with_i_seq(ag, i_seq) if not ba.element_is_hydrogen(): number_of_heavy+=1 - else: - number_of_heavy+=1 + # else: + # number_of_heavy+=1 if number_of_heavy==2: number_of_hydrogens-=2 if verbose: print('number_of_heavy', number_of_heavy) From 32bc4f59f373a636c96fda33ab880df44bdf47da Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Fri, 1 Mar 2024 16:43:42 -0800 Subject: [PATCH 171/748] small change for PRO --- mmtbx/ligands/ready_set_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mmtbx/ligands/ready_set_utils.py b/mmtbx/ligands/ready_set_utils.py index cd0398d207..27f80e3c05 100644 --- a/mmtbx/ligands/ready_set_utils.py +++ b/mmtbx/ligands/ready_set_utils.py @@ -106,7 +106,7 @@ def add_n_terminal_hydrogens_to_atom_group(ag, if ag.get_atom(h): h_count+=1 if ag.get_atom(h.replace('H', 'D')): d_count+=1 number_of_hydrogens=3 - if verbose: print('number_of_hydrogens',number_of_hydrogens) + if verbose: print('starting number_of_hydrogens',number_of_hydrogens) if use_capping_hydrogens: if verbose: print('use_capping_hydrogens...') number_of_hydrogens-=1 @@ -128,7 +128,7 @@ def _get_atom_with_i_seq(ag, i_seq): number_of_heavy+=1 # else: # number_of_heavy+=1 - if number_of_heavy==2: + if number_of_heavy==2 and ag.resname!='PRO': # need central PRO-like... number_of_hydrogens-=2 if verbose: print('number_of_heavy', number_of_heavy) if verbose: print('number_of_hydrogens',number_of_hydrogens) From 8ead00ca14efadab50de8b65041ceb10dddcb29c Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Mon, 4 Mar 2024 11:54:28 -0800 Subject: [PATCH 172/748] mmtbx: fix loggraph output in xtriage - Fixes #970 --- mmtbx/scaling/xtriage.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mmtbx/scaling/xtriage.py b/mmtbx/scaling/xtriage.py index 2dc10b4ec9..e411bce9e0 100644 --- a/mmtbx/scaling/xtriage.py +++ b/mmtbx/scaling/xtriage.py @@ -1393,8 +1393,9 @@ def run(args, command_name="phenix.xtriage", return_result=False, from libtbx import easy_pickle easy_pickle.dump(data_file_name, raw_data) if (params.scaling.input.parameters.reporting.loggraphs): - graph_out = mmtbx.scaling.loggraph_output(output_file) - xtriage_results.show(out=graph_out) + with open(params.scaling.input.parameters.reporting.log, 'a') as output_file: + graph_out = mmtbx.scaling.loggraph_output(output_file) + xtriage_results.show(out=graph_out) return xtriage_results def change_symmetry(miller_array, space_group_symbol, file_name=None, From 4164a7a154ca3f149613e83018436e2daf896ee7 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Mon, 4 Mar 2024 12:57:28 -0800 Subject: [PATCH 173/748] mmtbx: add test for xtriage loggraph output --- mmtbx/scaling/tst_xtriage.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mmtbx/scaling/tst_xtriage.py b/mmtbx/scaling/tst_xtriage.py index 541dfa3017..e7a348d4c9 100644 --- a/mmtbx/scaling/tst_xtriage.py +++ b/mmtbx/scaling/tst_xtriage.py @@ -564,8 +564,18 @@ def exercise_2(): args = [hkl_file, pdb_file] result = xtriage.run(args=args, out=null_out()) +def exercise_loggraph(): + mtz_file = libtbx.env.find_in_repositories( + relative_path="mmtbx/regression/mtz/tst_xtriage_fmodel.mtz", + test=os.path.isfile) + result = xtriage.run( + args=[mtz_file, 'scaling.input.parameters.reporting.loggraphs=True'], + out=null_out() + ) + if (__name__ == "__main__"): #exercise_2() exercise_1() exercise_analyze_resolution_limits() + exercise_loggraph() print("OK") From 0cc438bf673ebf2be12d4923bd9eba50825707be Mon Sep 17 00:00:00 2001 From: cschlick Date: Thu, 29 Feb 2024 11:30:58 -0800 Subject: [PATCH 174/748] Changes from code review2 --- cctbx/maptbx/qscore.py | 58 +++------------------------------------- cctbx/programs/qscore.py | 22 +++++++-------- 2 files changed, 13 insertions(+), 67 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index 0814227818..1b7c0d5fd3 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -124,7 +124,7 @@ def get_probes( """ Generate probes for multiple radial shells (shells) """ - + # Create before multiprocessing atoms_tree = KDTree(sites_cart) @@ -181,9 +181,7 @@ def shell_probes_precalculate( if not atoms_tree: assert atoms_tree is None, ("If not providing an atom tree,\ provide a 2d atom coordinate array to build tree") - - # make atom kdtree - atoms_tree = KDTree(sites_cart) + assert atoms_tree is not None # Manage log if log is None: @@ -233,7 +231,7 @@ def shell_probes_precalculate( if n_probes_per_atom.min() >= n_probes_min: print( f"Some atoms have less than {n_probes_min} probes. \ - ({len(problematic_probes)}). Consider raising n_probes") + ({len(problematic_probes)}). Consider raising n_probes",file=log) return probe_xyz, probe_mask @@ -245,7 +243,6 @@ def calc_qscore(mmm, rtol=0.9, nproc=1, log=null_out(), - params=None,# TODO: remove this debug=False): """ Calculate qscore from map model manager @@ -263,7 +260,7 @@ def calc_qscore(mmm, if selection != None: selection_bool = mmm.model().selection(selection).as_numpy_array() # boolean if selection_bool.sum() ==0: - print("Finished... nothing selected") + print("Finished... nothing selected",file=log) return {"qscore_per_atom":None} else: selection_bool = np.full(len(sites_cart),True) @@ -298,8 +295,6 @@ def calc_qscore(mmm, # interpolate volume = mm.map_data().as_numpy_array() voxel_size = mm.pixel_sizes() - # masked_density = trilinear_interpolation( - # volume, masked_probe_xyz_flat, voxel_size=voxel_size) masked_density = mm.density_at_sites_cart( flex.vec3_double(masked_probe_xyz_flat)).as_numpy_array() @@ -341,7 +336,6 @@ def calc_qscore(mmm, q = np.around(q,4) # aggregate per residue - model = model.select(flex.bool(selection_bool)) qscore_df = aggregate_qscore_per_residue(model,q,window=3) q = flex.double(q) @@ -369,49 +363,6 @@ def calc_qscore(mmm, return result - -def trilinear_interpolation(voxel_grid, coords, voxel_size=None, offset=None): - """Numpy trilinear interpolation""" - assert voxel_size is not None,( - "Provide voxel size as an array or single value") - - # Apply offset if provided - if offset is not None: - coords = coords - offset - - # Transform coordinates to voxel grid index space - index_coords = coords / voxel_size - - # Split the index_coords array into three arrays: x, y, and z - x, y, z = index_coords.T - - # Truncate to integer values - x0, y0, z0 = np.floor([x, y, z]).astype(int) - x1, y1, z1 = np.ceil([x, y, z]).astype(int) - - # Ensure indices are within grid boundaries - x0, y0, z0 = np.clip([x0, y0, z0], 0, voxel_grid.shape[0]-1) - x1, y1, z1 = np.clip([x1, y1, z1], 0, voxel_grid.shape[0]-1) - - # Compute weights - xd, yd, zd = [arr - arr.astype(int) for arr in [x, y, z]] - - # Interpolate along x - c00 = voxel_grid[x0, y0, z0]*(1-xd) + voxel_grid[x1, y0, z0]*xd - c01 = voxel_grid[x0, y0, z1]*(1-xd) + voxel_grid[x1, y0, z1]*xd - c10 = voxel_grid[x0, y1, z0]*(1-xd) + voxel_grid[x1, y1, z0]*xd - c11 = voxel_grid[x0, y1, z1]*(1-xd) + voxel_grid[x1, y1, z1]*xd - - # Interpolate along y - c0 = c00*(1-yd) + c10*yd - c1 = c01*(1-yd) + c11*yd - - # Interpolate along z - c = c0*(1-zd) + c1*zd - - return c - - def rowwise_corrcoef(A, B, mask=None): """Numpy masked array rowwise correlation coefficient""" assert A.shape == B.shape, ( @@ -463,7 +414,6 @@ def starmap_wrapper(task): def aggregate_qscore_per_residue(model,qscore_per_atom,window=3): # assign residue indices to each atom - model = model.select(model.selection("not element H")) atoms = model.get_atoms() res_seqs = [atom.parent().parent().resseq_as_int() for atom in atoms] chain_ids = [atom.parent().parent().parent().id for atom in atoms] diff --git a/cctbx/programs/qscore.py b/cctbx/programs/qscore.py index 9053ee88eb..e1b136220d 100644 --- a/cctbx/programs/qscore.py +++ b/cctbx/programs/qscore.py @@ -30,15 +30,15 @@ class Program(ProgramTemplate): def validate(self): # test for sane parameters if not (4<=self.params.qscore.n_probes<=512): - raise Sorry("Provide n_probe values in the range 8-128") + raise Sorry("Provide n_probe values in the range 4-512") if not (4<=self.params.qscore.shell_radius_num<=128): - raise SOrry("Provide shell_radius_num values in range 4-128") + raise Sorry("Provide shell_radius_num values in range 4-128") def run(self): - print("Running") + self._print("Running") # get initial data mmm = self.data_manager.get_map_model_manager() @@ -49,11 +49,7 @@ def run(self): start = self.params.qscore.shell_radius_start stop = self.params.qscore.shell_radius_stop num = self.params.qscore.shell_radius_num - shells = list(np.linspace( - start, - stop, - num, - endpoint=True)) + shells = list(np.linspace(start,stop,num,endpoint=True)) for shell in reversed(shells): self.shells.insert(0,shell) @@ -67,15 +63,15 @@ def run(self): mmm.set_model(model,overwrite=True) # print output - print("Running Q-score:") + self._print("Running Q-score:") param_output = group_args( n_probes=self.params.qscore.n_probes, rtol=self.params.qscore.rtol, selection=self.params.qscore.selection, ) - print(param_output) - print("\nRadial shells used:") - print([round(shell,2) for shell in shells]) + self._print(param_output) + self._print("\nRadial shells used:") + self._print([round(shell,2) for shell in shells]) # run qscore qscore_result= calc_qscore( mmm, @@ -94,7 +90,7 @@ def run(self): if self.params.qscore.selection is not None: model = model.select(model.selection(self.params.qscore.selection)) assert model.get_number_of_atoms()==len(df) - print("\nFinished running. Q-score results:") + self._print("\nFinished running. Q-score results:") sel_mc = "protein and (name C or name N or name CA or name O or name CB)" sel_mc = model.selection(sel_mc) From 81e487d5ee94cd184401b89e6deadb2eba87aed2 Mon Sep 17 00:00:00 2001 From: cschlick Date: Mon, 4 Mar 2024 15:45:34 -0800 Subject: [PATCH 175/748] Migrate to easy_mp --- cctbx/maptbx/qscore.py | 98 ++++++++++++++++++---------------------- cctbx/programs/qscore.py | 31 ++++++++----- 2 files changed, 64 insertions(+), 65 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index 1b7c0d5fd3..0ce74240a4 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -5,7 +5,7 @@ from libtbx.utils import null_out from cctbx.array_family import flex - +from libtbx import easy_mp import numpy as np import numpy.ma as ma from scipy.spatial import KDTree @@ -58,6 +58,10 @@ write_probes = False .type = bool .help = Write the qscore probes as a .bild file to visualize in Chimera + + write_to_bfactor_pdb = False + .type = bool + .help = Write out a pdb file with the Q-score per atom in the B-factor field } """ @@ -110,6 +114,20 @@ def generate_probes_np(sites_cart, rad, n_probes): ################################################################################ #### Run shell functions for multiple shells(possibly in parallel) ################################################################################ + +class GatherProbes: + def __init__(self, + func, + fixed_kwargs, + ): + self.func = func + self.fixed_kwargs = fixed_kwargs + + def __call__(self,RAD): + + return self.func(RAD=RAD,**self.fixed_kwargs) + + def get_probes( sites_cart=None, atoms_tree = None, @@ -130,32 +148,21 @@ def get_probes( assert shells is not None, "Must provide explicit radial shells" - task_list = [ - { - "func": worker_func, # Specify the function to call - "kwargs": { - "sites_cart": sites_cart, # A numpy array of shape (N,3) - "atoms_tree": atoms_tree, # An atom_xyz scipy kdtree - "selection_bool": selection_bool, # Boolean atom selection - "n_probes": n_probes, # The desired number of probes per shell - "RAD": RAD, # The nominal radius of this shell - "rtol": rtol, # Multiplied with RAD to get actual radius - "log": log, + fixed_kwargs = { + "sites_cart": sites_cart, # A numpy array of shape (N,3) + "atoms_tree": atoms_tree, # An atom_xyz scipy kdtree + "selection_bool": selection_bool, # Boolean atom selection + "n_probes": n_probes, # The desired number of probes per shell + "rtol": rtol, # Multiplied with RAD to get actual radius + "log": log, } - } for RAD in shells - ] - if nproc>1: - with Pool() as pool: - results = pool.map(starmap_wrapper, task_list) - else: - results = [] - for task in task_list: - worker_func = task["func"] - kwargs = task["kwargs"] - result = worker_func(**kwargs) - results.append(result) + gather = GatherProbes(worker_func,fixed_kwargs) + results = easy_mp.pool_map( + processes=nproc, + fixed_func=gather, + args=shells) probe_xyz = [result[0] for result in results] probe_mask = [result[1] for result in results] @@ -250,6 +257,7 @@ def calc_qscore(mmm, model = mmm.model() # never do hydrogen model = model.remove_hydrogens() + mmm.set_model(model) mm = mmm.map_manager() @@ -258,12 +266,13 @@ def calc_qscore(mmm, # do selection if selection != None: - selection_bool = mmm.model().selection(selection).as_numpy_array() # boolean + selection_bool = mmm.model().selection(selection) # boolean if selection_bool.sum() ==0: print("Finished... nothing selected",file=log) return {"qscore_per_atom":None} else: - selection_bool = np.full(len(sites_cart),True) + selection_bool = flex.bool(model.get_number_of_atoms(),True) + # determine worker func worker_func=shell_probes_precalculate @@ -342,24 +351,22 @@ def calc_qscore(mmm, qscore_per_residue = flex.double(qscore_df["Q-ResidueRolling"].values) # Output + result = { + "qscore_per_atom":q, + "qscore_per_residue":qscore_per_residue, + "qscore_dataframe":qscore_df + } + if debug: # Collect debug data - result = { + result.update({ "atom_xyz":sites_cart, "probe_xyz":probe_xyz, "probe_mask":probe_mask, "d_vals":d_vals, "g_vals":g_vals, - "qscore_per_atom":q, - "qscore_per_residue":qscore_per_residue, - "qscore_dataframe":qscore_df, - } - else: - result = { - "qscore_per_atom":q, - "qscore_per_residue":qscore_per_residue, - "qscore_dataframe":qscore_df - } + }) + return result @@ -393,23 +400,6 @@ def rowwise_corrcoef(A, B, mask=None): return cc.data -def starmap_wrapper(task): - """ - A generic wrapper function to call any worker function with specified arguments. - Params: - task (dict): A dictionary containing the 'func', 'args', and 'kwargs' keys. - - Returns: - return: The result of the worker function call. - """ - # Extract the function to call, its args, and kwargs from the task - func = task['func'] - args = task.get('args', ()) - kwargs = task.get('kwargs', {}) - - # Dynamically call the function with args and kwargs - return func(*args, **kwargs) - def aggregate_qscore_per_residue(model,qscore_per_atom,window=3): # assign residue indices to each atom diff --git a/cctbx/programs/qscore.py b/cctbx/programs/qscore.py index e1b136220d..8b675ba228 100644 --- a/cctbx/programs/qscore.py +++ b/cctbx/programs/qscore.py @@ -2,6 +2,7 @@ import json from pathlib import Path +from cctbx.array_family import flex from libtbx.program_template import ProgramTemplate from libtbx import group_args from cctbx.maptbx.qscore import ( @@ -64,12 +65,6 @@ def run(self): # print output self._print("Running Q-score:") - param_output = group_args( - n_probes=self.params.qscore.n_probes, - rtol=self.params.qscore.rtol, - selection=self.params.qscore.selection, - ) - self._print(param_output) self._print("\nRadial shells used:") self._print([round(shell,2) for shell in shells]) # run qscore @@ -84,20 +79,20 @@ def run(self): self.result = group_args(**qscore_result) - # calculate some metrics df = self.result.qscore_dataframe if self.params.qscore.selection is not None: model = model.select(model.selection(self.params.qscore.selection)) assert model.get_number_of_atoms()==len(df) - self._print("\nFinished running. Q-score results:") + + self._print("\nFinished running. Q-score results:") sel_mc = "protein and (name C or name N or name CA or name O or name CB)" sel_mc = model.selection(sel_mc) sel_sc = ~sel_mc - q_sc = df["Q-score"].iloc[sel_sc.as_numpy_array()].mean() - q_mc = df["Q-score"].iloc[sel_mc.as_numpy_array()].mean() - q_all = df["Q-score"].mean() + q_sc = flex.mean(self.result.qscore_per_atom.select(sel_sc)) + q_mc = flex.mean(self.result.qscore_per_atom.select(sel_mc)) + q_all = flex.mean(self.result.qscore_per_atom) q_chains = df.groupby("chain_id").agg('mean',numeric_only=True) q_chains = q_chains[["Q-score"]] print("\nBy residue:") @@ -121,6 +116,13 @@ def run(self): self.result.q_score_main_chain = q_mc self.result.q_score_overall = q_all + # write out + if self.params.qscore.write_probes: + self.write_bild_spheres() + + if self.params.qscore.write_to_bfactor_pdb: + self.write_to_bfactor_pdb(model,self.result.qscore_per_atom) + def get_results(self): return self.result @@ -130,6 +132,13 @@ def get_results_as_JSON(self): } return json.dumps(results_dict,indent=2) + def write_to_bfactor_pdb(self,model,qscore_per_atom): + model.set_b_iso(qscore_per_atom) + + with open("qscore_bfactor_field.pdb","w") as fh: + fh.write(model.model_as_pdb()) + + def write_bild_spheres(self): # write bild files if self.params.qscore.write_probes: print("Writing probe debug files...Using a small selection is recommended", From 356dea735c66f8a7779571fc411f4b76abb3fea1 Mon Sep 17 00:00:00 2001 From: cschlick Date: Mon, 4 Mar 2024 15:51:20 -0800 Subject: [PATCH 176/748] Update tests --- cctbx/maptbx/qscore.py | 4 +--- cctbx/maptbx/tst_qscore.py | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index 0ce74240a4..48ef5536fa 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -186,9 +186,7 @@ def shell_probes_precalculate( # Do input validation if not atoms_tree: - assert atoms_tree is None, ("If not providing an atom tree,\ - provide a 2d atom coordinate array to build tree") - assert atoms_tree is not None + atoms_tree = KDTree(np.array(sites_cart)) # Manage log if log is None: diff --git a/cctbx/maptbx/tst_qscore.py b/cctbx/maptbx/tst_qscore.py index cedddfff03..925437aabf 100644 --- a/cctbx/maptbx/tst_qscore.py +++ b/cctbx/maptbx/tst_qscore.py @@ -206,7 +206,6 @@ def run_test(test): params = convert_group_args_to_dict(params) result = q_func(mmm, **params, - params=convert_dict_to_group_args(params), log=null_out()) test.results.calc = convert_dict_to_group_args(result) for key,value_expected in test.results.expected.__dict__.items(): From 581e9e94d68f18d55b0c12c35b6c1eeaf84cd154 Mon Sep 17 00:00:00 2001 From: cschlick Date: Mon, 4 Mar 2024 15:52:26 -0800 Subject: [PATCH 177/748] Clean clutter --- cctbx/maptbx/qscore.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index 48ef5536fa..eb6bc0e5d2 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -1,6 +1,5 @@ from __future__ import division from collections import defaultdict -from multiprocessing import Pool import warnings from libtbx.utils import null_out From 5ac1d6c7504409c6f5a50e4c793cdd37e63ca2bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Tcho=C5=84?= Date: Mon, 4 Mar 2024 18:38:13 -0800 Subject: [PATCH 178/748] Evaluation of preferential orientation (#967) * Prepare base file structure for preferential orientation analysis * Prepare a general skeleton to calculate average orientation * Testing; it seems my coworker has little idea about the IRLS algorithm * Implement MisesFisherCalculator to determine pref. ori. of vectors * Implemented some functions for Watson distribution, but no fit * Fix WatsonDistribution calculator: eigenvectors were transposed * Fix WatsonDistribution calculator: eigenvectors were transposed * Clean and add docstrings; add snippet of sampling code * Temporarily save work, to find out later how to get a,b,c vecs * Explicitely def `SphericalDistribution`, `Hedgehog`, mu system * Scrap direct space vectors instead of matrices; clean code * Add sampling reference * Make read_reflections/experiments accept sequence, not str args * Correctly concatenate strings, not `WatsonDistribution` * Convert gridspec dimensions to ints * Normalize vectors before passing to Distribution constructor * Change `WatsonDistribution.fit` to act in place * Correctly print kappa in `WatsonDistribution.__str__` * Convert `DirectSpaceVectorScraper` to a `Collection` dataclass * Remove unused Mises-Fisher distibution code, bugfixes * `find_preferential_orientation` for many linear combinations of a, b, c * Manually remove outdated updates to drift scripts * Add `preferential_orientation.py` to `py2_syntax_exceptions.txt` * Minor type hints, TODOs * Don't use arrowheads when plotting hedgehog quiver * Experiments should be now passed as individual *args to reader * Simplify expt handling, make `DirectSpaceVectors` `ndarray`' subclass * Add vector mu and mu-ring to plot distributions * Let `params_from_phil` handle any arbitrary scope provided * Let `params_from_phil` handle any arbitrary scope provided 2 * Make DirectSpaceVectors a subclass of numpy ndarray 3 * Make DirectSpaceVectors a subclass of numpy ndarray 4 * FIx issues with `mu_basis_vectors`, vstacking, DirectSpaceVectors * By default, symmetrize expts: if this works I will be fricking elated * Change header comment style not to validate PEP 8 "# " rule * Fix/reimplement `find_preferential_orientation_direction` function * Fix/reimplement `find_preferential_orientation_direction` function 2 * Fix/reimplement `find_preferential_orientation_direction` function 3 * Fix/reimplement `find_preferential_orientation_direction` function 5 * Generalize, vectorize transformation; consider only unique PseudoNode-s * Generalization fixes 1 * Generalization fixes 2 * Generalization fixes 3 * Generalization fixes 4 * When determining directions, use positive numbers first * Previous order was already fine * Fix transform direction - correct now; tested on 3-fold rotation * Move reporting into a dedicated function * Implement hammer plot for plotting larger distributions * Implement hammer plot for plotting larger distributions 2 * Implement hammer plot for plotting larger distributions 3 * Implement simple MPI support * Hotfixes to MPI (which isn't helpful because seems transfer limited?) * Hotfixes to MPI, fix 2 * Hotfixes to MPI, fix 3 * Hotfixes to MPI, fix 4 * Hotfixes to MPI, improve plotting * Hotfixes to MPI, improve plotting 2 * Hotfixes to MPI, improve plotting 3 * Fix Lab Y axis direction on Hammer plot * Prepare a preference worker, auto-determine the space group * Minor hotfixes with preference worker * Look for preference along zone axes, not direct lattice directions * Implement ASCII "plotting" for worker & headless processing * Fixes to preferential worker * Long in the main log only * Long in the main log only, make ASCII plots slightly wider * Long in the main log only, make ASCII plots slightly wider * Remove accidental whitespace * `exercise_watson_distribution` using more samples and two heatplots * `exercise_watson_distribution` using more samples and two heatplots 2 * `exercise_watson_distribution` using more samples and two heatplots 3 * Declutter, more type hints, no longer WIP * Rename in `py2_syntax_exceptions.txt` * Extradited offending walrus operators * Protect installations without matplotlib by delaying exception * Completely hide the matplotlib imports to avoid backend issues * Remove f-string from preference worker --- .azure-pipelines/py2_syntax_exceptions.txt | 1 + xfel/command_line/drift.py | 4 +- xfel/command_line/preference.py | 13 + .../application/preference/__init__.py | 0 .../merging/application/preference/factory.py | 10 + .../application/preference/preference.py | 54 ++ xfel/util/drift.py | 6 +- xfel/util/preference.py | 670 ++++++++++++++++++ 8 files changed, 753 insertions(+), 5 deletions(-) create mode 100644 xfel/command_line/preference.py create mode 100644 xfel/merging/application/preference/__init__.py create mode 100644 xfel/merging/application/preference/factory.py create mode 100644 xfel/merging/application/preference/preference.py create mode 100644 xfel/util/preference.py diff --git a/.azure-pipelines/py2_syntax_exceptions.txt b/.azure-pipelines/py2_syntax_exceptions.txt index ed005d33d1..7ccaa19222 100644 --- a/.azure-pipelines/py2_syntax_exceptions.txt +++ b/.azure-pipelines/py2_syntax_exceptions.txt @@ -13,6 +13,7 @@ xfel/ui/db/job.py xfel/command_line/cxi_mpi_submit.py xfel/command_line/fee_calibration.py xfel/util/drift.py +xfel/util/preference.py cctbx/maptbx/qscore.py cctbx/maptbx/tst_qscore.py mmtbx/geometry_restraints/geo_file_parsing.py diff --git a/xfel/command_line/drift.py b/xfel/command_line/drift.py index 29684a3882..c07f7d02ef 100644 --- a/xfel/command_line/drift.py +++ b/xfel/command_line/drift.py @@ -2,11 +2,11 @@ from __future__ import division import sys -from xfel.util.drift import params_from_phil, run, message +from xfel.util.drift import phil_scope, params_from_phil, run, message if __name__ == '__main__': if '--help' in sys.argv[1:] or '-h' in sys.argv[1:]: print(message) exit() - params = params_from_phil(sys.argv[1:]) + params = params_from_phil(phil_scope, sys.argv[1:]) run(params) diff --git a/xfel/command_line/preference.py b/xfel/command_line/preference.py new file mode 100644 index 0000000000..67b1f7e0c3 --- /dev/null +++ b/xfel/command_line/preference.py @@ -0,0 +1,13 @@ +# LIBTBX_SET_DISPATCHER_NAME cctbx.xfel.preference + +from __future__ import division +import sys +from xfel.util.preference import params_from_phil, phil_scope, run, message + + +if __name__ == '__main__': + if '--help' in sys.argv[1:] or '-h' in sys.argv[1:]: + print(message) + exit() + params = params_from_phil(phil_scope, sys.argv[1:]) + run(params) diff --git a/xfel/merging/application/preference/__init__.py b/xfel/merging/application/preference/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xfel/merging/application/preference/factory.py b/xfel/merging/application/preference/factory.py new file mode 100644 index 0000000000..22b3441c8b --- /dev/null +++ b/xfel/merging/application/preference/factory.py @@ -0,0 +1,10 @@ +from __future__ import absolute_import, division, print_function +from xfel.merging.application.preference.preference import PreferenceWorker +from xfel.merging.application.worker import factory as factory_base + + +class factory(factory_base): + """Factory for PreferenceWorker which evaluates preferential orientation""" + @staticmethod + def from_parameters(params, additional_info=None, mpi_helper=None, mpi_logger=None): + return [PreferenceWorker(params, mpi_helper, mpi_logger)] diff --git a/xfel/merging/application/preference/preference.py b/xfel/merging/application/preference/preference.py new file mode 100644 index 0000000000..183c2e1b26 --- /dev/null +++ b/xfel/merging/application/preference/preference.py @@ -0,0 +1,54 @@ +from __future__ import absolute_import, division, print_function + +from functools import wraps + +import numpy as np + +from xfel.merging.application.worker import worker +from xfel.util.preference import ascii_plot, DirectSpaceBases, \ + find_preferential_distribution, space_group_auto + + +def return_input_expts_refls_if_error(run_method): + @wraps(run_method) + def run_method_wrapper(worker_instance, experiments, reflections): + try: + return run_method(worker_instance, experiments, reflections) + except Exception: # noqa - this is meant to catch everything + worker_instance.logger.log('Error when running worker, returning input') + return experiments, reflections + return run_method_wrapper + + +class PreferenceWorker(worker): + """Read lattice vectors, apply symmetry, look for preferential orientation""" + + def __init__(self, params, mpi_helper=None, mpi_logger=None): + kwargs = dict(params=params, mpi_helper=mpi_helper, mpi_logger=mpi_logger) + super(PreferenceWorker, self).__init__(**kwargs) + + def __repr__(self): + return 'Evaluate preferential orientation' + + @return_input_expts_refls_if_error + def run(self, experiments, reflections): + sg, message_ = space_group_auto(experiments, comm=self.mpi_helper.comm) + if self.mpi_helper.rank == 0: + for message_line in message_.split('\n'): + self.logger.main_log(message_line) + self.logger.main_log('') + abc_stack = DirectSpaceBases.from_expts(experiments, sg) + abc_stack = abc_stack.symmetrize(sg.build_derived_point_group()) + abc_stacks = self.mpi_helper.comm.gather(abc_stack) + if self.mpi_helper.comm.rank != 0: + return experiments, reflections + abc_stack = DirectSpaceBases(np.concatenate(abc_stacks, axis=0)) + distributions = find_preferential_distribution(abc_stack, sg) + self.logger.main_log(distributions.table) + self.logger.main_log('') + pref_direction, pref_distribution = distributions.best + self.logger.main_log('Vector distribution for zone axes family ' + + pref_direction) + self.logger.main_log(ascii_plot(pref_distribution.vectors)) + self.logger.main_log('') + return experiments, reflections diff --git a/xfel/util/drift.py b/xfel/util/drift.py index 2901be49a1..e5fa049cfc 100644 --- a/xfel/util/drift.py +++ b/xfel/util/drift.py @@ -140,7 +140,7 @@ phil_scope = parse(phil_scope_str) -def params_from_phil(args): +def params_from_phil(phil_scope_, args): user_phil = [] for arg in args: if os.path.isfile(arg): @@ -150,7 +150,7 @@ def params_from_phil(args): user_phil.append(parse(arg)) except Exception: raise Sorry("Unrecognized argument: %s" % arg) - params_ = phil_scope.fetch(sources=user_phil).extract() + params_ = phil_scope_.fetch(sources=user_phil).extract() return params_ @@ -1007,5 +1007,5 @@ def run(params_): if '--help' in sys.argv[1:] or '-h' in sys.argv[1:]: print(message) exit() - params = params_from_phil(sys.argv[1:]) + params = params_from_phil(phil_scope, sys.argv[1:]) run(params) diff --git a/xfel/util/preference.py b/xfel/util/preference.py new file mode 100644 index 0000000000..cfb04f45bb --- /dev/null +++ b/xfel/util/preference.py @@ -0,0 +1,670 @@ +from __future__ import division + +import abc +from collections import Counter, deque, UserDict +from dataclasses import dataclass +import glob +from numbers import Number +from typing import Any, Iterable, List, Sequence, Tuple, TypeVar, Union +import sys + +from cctbx import sgtbx +from dxtbx.model import ExperimentList +from iotbx.phil import parse +from libtbx import Auto, table_utils +from libtbx.mpi4py import MPI +from xfel.util.drift import params_from_phil, read_experiments + +import numpy as np +import scipy as sp + + +message = """ +This utility tool aims to determinate, characterise, and quantify the degree +of preferential orientation in crystals. To this aim, it investigates the +the distribution of various crystallographic directions on a sphere in 3D. +The code assumes each set of vectors follows Wilson Distribution, and attempts +to model said distribution by fitting its parameter `mu` and `kappa`. + +Wilson distribution describes a bimodal arrangement of points / unit vectors +on a sphere around a central axis called `mu`. The distribution is invariant +to any rotation around `mu` and inversion, and its exact type depends on the +concentration parameter `kappa`. For `kappa` > 0, the points are focused in +the polar region around +/- `mu`. In case of `kappa` < 0, the points +concentrate mostly in a equatorial region far from `mu`. `kappa` close to 0 +describes a distribution uniform on sphere: no preferential orientation. + +This code has been prepared using the following books & papers as references: +- http://palaeo.spb.ru/pmlibrary/pmbooks/mardia&jupp_2000.pdf, section 10.3.2 +- https://www.sciencedirect.com/science/article/pii/S0047259X12002084, sect. 2 +- https://www.tandfonline.com/doi/abs/10.1080/03610919308813139 +""".strip() + + +phil_scope_str = """ + input { + glob = None + .type = str + .multiple = True + .help = glob which matches all expt files to be investigated. + exclude = None + .type = str + .multiple = True + .help = glob which matches all expt files to be excluded from input. + space_group = Auto + .type = space_group + .help = Reject all expts that are not described by this space group. \ + Investigate only directions that are symmetrically equivalent \ + according to the point symmetry of given group. \ + By default, look at the most common space group only. + symmetrize = True + .type = bool + .help = Apply point group symmetry extracted from `space_group` to \ + extracted unit cell bases to avoid bias introduced by indexing + } + plot { + style = none ascii *hammer hedgehog + .type = choice + .help = Which kind of plot should be produced: \ + Ascii writes a crude heatmap of distribution in x/y coords.\ + Hammer plots heatmap of distribution on Hammer projection.\ + Hedgehog draws all individual vectors (use for small data only). + } +""" +phil_scope = parse(phil_scope_str) + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ CONVENIENCE AND TYPING ~~~~~~~~~~~~~~~~~~~~~~~~~ # + + +COMM = MPI.COMM_WORLD +Int3 = Tuple[int, int, int] +Number3 = Sequence[Number] +sg_p1 = sgtbx.space_group('P 1') # noqa +pg_i1 = sg_p1.build_derived_laue_group() +SgtbxPointGroup = Any +SgtbxSpaceGroup = Any +SgtbxSymmOp = Any +T = TypeVar('T') + + +def flatten(sequence: Sequence[Sequence[T]]) -> List[T]: + """Flatten a sequence of sequences into a 1-dimensional list""" + return [element for sub_sequence in sequence for element in sub_sequence] + + +def locate_paths(include_globs: Iterable[str], + exclude_globs: Iterable[str], + ) -> List[str]: + """Return a list of expt paths in `include_globs`, outside `exclude_globs`""" + include_paths = flatten([glob.glob(ig) for ig in include_globs]) + exclude_paths = flatten([glob.glob(eg) for eg in exclude_globs]) + return [path for path in include_paths if path not in exclude_paths] + + +def space_group_auto(expts: Iterable[ExperimentList], + comm: type(COMM) = None, + ) -> Tuple[SgtbxSpaceGroup, str]: + """Return the most common space groups across comm world, and summary str""" + counter = Counter([e.crystal.get_space_group().make_tidy() for e in expts]) + if comm is not None: + counters = comm.allgather(counter) + counter = sum(counters, Counter()) + message_ = '' + for sg, sg_count in counter.items(): + message_ += f'Found {sg_count:6d} expts with space group {sg.info()}\n' + most_common = counter.most_common(1)[0][0] + message_ += f'Evaluating the most common space group {most_common.info()}' + return most_common, message_ + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SYMMETRY HANDLING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # + + +def transform(vectors: Union[Number3, Iterable[Number3]], + symm_op: SgtbxSymmOp, + ) -> np.ndarray[Number3]: + """Transform Number3 or Nx3 Iterable of Number3-s using symm_op """ + vectors = np.array(list(vectors)) # read generators, avoid tuples + symm_op_m3 = np.array(symm_op.as_double_array()[:9]).reshape((3, 3)) + return vectors @ symm_op_m3.T + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ ORIENTATION SCRAPPING ~~~~~~~~~~~~~~~~~~~~~~~~~~ # + + +class DirectSpaceBases(np.ndarray): + """ + This class is responsible for scraping and storing vectors a, b, c; + Preferably, these come from expts, but the class can be initiated with + a raw numpy array as well. It is 3-dimensional, with individual dimensions + representing: + + - [n, :, :] - access n-th 3x3 array of a, b, c vectors; + - [:, n, :] - access an Nx3 array of a (n=0), b (n=1), or c (n=2) vectors; + - [:, :, n] - access an Nx3 array of x (n=0), y (n=1), or z (n=2) components. + + Consequently, the object is always (and must be init. using) a Nx3n3 array. + """ + def __new__(cls, abcs: np.ndarray): + if abcs.ndim != 3 or abcs.shape[1] != 3 or abcs.shape[2] != 3: + msg = 'DirectSpaceVectors must be init with a Nx3x3 array of abc vectors' + raise ValueError(msg) + return super().__new__(cls, abcs.shape, dtype=float, buffer=abcs) + + @classmethod + def from_expts(cls, + expts: ExperimentList, + space_group: SgtbxSpaceGroup = sg_p1, + ) -> 'DirectSpaceBases': + """Extract N [a, b, c] arrays from N expts into a Nx3x3 ndarray, return""" + abcs = [] + for expt in expts: + expt_sg = expt.crystal.get_space_group() + if expt_sg != space_group: + continue + abcs.append(expt.crystal.get_real_space_vectors().as_numpy_array()) + new = np.stack(abcs, axis=0) if abcs else np.empty(shape=(0, 3, 3)) + return cls(new) + + @property + def a(self) -> np.ndarray: + return np.array(self[:, 0, :]) + + @property + def b(self) -> np.ndarray: + return np.array(self[:, 1, :]) + + @property + def c(self) -> np.ndarray: + return np.array(self[:, 2, :]) + + @property + def x(self) -> np.ndarray: + return np.array(self[:, :, 0]) + + @property + def y(self) -> np.ndarray: + return np.array(self[:, :, 1]) + + @property + def z(self) -> np.ndarray: + return np.array(self[:, :, 2]) + + def transform(self, symm_op: SgtbxSymmOp) -> 'DirectSpaceBases': + """Transform all vectors in self using sgtbx rt_mx-type object""" + if self.size: + x = transform(self.x, symm_op) + y = transform(self.y, symm_op) + z = transform(self.z, symm_op) + new = np.stack([x, y, z], axis=2) + else: + new = np.empty(shape=(0, 3, 3)) + return self.__class__(new) + + def symmetrize(self, point_group: SgtbxPointGroup) -> 'DirectSpaceBases': + """Transform all vectors in self using all symm. ops. in point group""" + transformed = [self.transform(symm_op) for symm_op in point_group] + return self.__class__(np.concatenate(transformed, axis=0)) + + +# ~~~~~~~~~~~~~~~~~~~ PREFERENTIAL ORIENTATION CALCULATOR ~~~~~~~~~~~~~~~~~~~ # + + +def cart2sph(xyz: np.ndarray) -> np.ndarray: + """Convert an array of xyz vectors into an array of r, polar, azim vectors""" + r = np.linalg.norm(xyz, axis=1) + polar = np.arccos(xyz[:, 2] / r) + azim = np.arctan2(xyz[:, 1], xyz[:, 0]) + return np.vstack([r, polar, azim]).T + + +class SphericalDistribution: + """ + General class for handling distribution of unit vectors in 3D. Operates in + and provides methods to transform between different coordinate systems: + - `cart` - Cartesian coordinates X, Y, Z in laboratory reference frame; + - `sph` - Spherical ref. system with e1 = Z, polar e2 from Z to X, azim. XY; + - `mu_sph` - Spherical reference system with e1 = mu and e2, e3 arbitrary; + """ + E1 = np.array([1, 0, 0]) + E2 = np.array([0, 1, 0]) + E3 = np.array([0, 0, 1]) + + def __init__(self): + self.vectors: np.ndarray = np.empty((0, 3), dtype=float) + self.mu: np.ndarray = np.array([1., 0., 0.], dtype=float) + + @staticmethod + def normalized(vectors: np.ndarray, axis: int = -1) -> np.ndarray: + """Return `vectors` normalized using standard l2 norm along `axis` """ + l2 = np.atleast_1d(np.linalg.norm(vectors, 2, axis)) + l2[l2 == 0] = 1 + return vectors / np.expand_dims(l2, axis) + + @staticmethod + def are_parallel(v: np.ndarray, w: np.ndarray, eps: float = 1e-8) -> bool: + return abs(np.dot(v, w) / (np.linalg.norm(v) * np.linalg.norm(w))) < 1 - eps + + @property + def mu_basis_vectors(self) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: + """Basis vector of cartesian system in which e1 = mu; e2 & e3 arbitrary""" + e1 = self.mu / np.linalg.norm(self.mu) + e0 = self.E1 if not self.are_parallel(e1, self.E1) else self.E2 + e2 = np.cross(e1, e0) / np.linalg.norm(np.cross(e1, e0)) + e3 = np.cross(e1, e2) / np.linalg.norm(np.cross(e1, e2)) + return e1, e2, e3 + + @property + def mu_ring(self) -> np.ndarray: + """A closed 3D ring of points around vector self.mu used for plotting""" + azim = np.linspace(0.0, 2*np.pi, num=100, endpoint=True) + r = np.ones_like(azim) + polar = np.full_like(azim, np.pi / 2) + return self.mu_sph2cart(np.vstack([r, polar, azim]).T) + + def mu_sph2cart(self, r_polar_azim: np.ndarray) -> np.ndarray: + """Convert spherical coordinates r, polar, azim to cartesian in mu basis""" + r, polar, azim = np.hsplit(r_polar_azim, 3) + e1, e2, e3 = self.mu_basis_vectors + e1_component = e1 * np.cos(polar) + e2_component = e2 * np.sin(polar) * np.cos(azim) + e3_component = e3 * np.sin(polar) * np.sin(azim) + return r * (e1_component + e2_component + e3_component) + + +class WatsonDistribution(SphericalDistribution): + """Class for holding, fitting, and generating Watson distribution. + Description names reflect those used in respective references: + - https://arxiv.org/pdf/1104.4422.pdf, page 3 + - http://palaeo.spb.ru/pmlibrary/pmbooks/mardia&jupp_2000.pdf, section 10.3.2 + - https://www.tandfonline.com/doi/abs/10.1080/03610919308813139""" + def __init__(self, mu: np.ndarray = None, kappa: float = None) -> None: + super().__init__() + self.kappa: float = kappa + self.mu: np.ndarray = mu + self.nll: float = np.Infinity + + def __str__(self) -> str: + return f'Watson Distribution around mu={self.mu} with kappa={self.kappa}' + + @classmethod + def from_vectors(cls, vectors: np.ndarray) -> 'WatsonDistribution': + """Define the distribution by fitting it to a list of vectors""" + new = WatsonDistribution() + new.fit(vectors=cls.normalized(vectors)) + return new + + @property + def r_avg(self) -> float: + """Length of the not-normalized mean direction of vectors, bar{R}""" + return np.linalg.norm(self.x_avg) + + @property + def x_avg(self) -> np.ndarray: + """Sum of vectors divided by their count, bar{x}""" + return np.sum(self.vectors, axis=0) / self.vectors.shape[0] + + @staticmethod + def kummer_function(a: float, b: float, kappa: float) -> float: + """Confluent hypergeometric function 1F1, a.k.a. Kummer function""" + return sp.special.hyp1f1(a, b, kappa) + + @property + def scatter_matrix(self) -> np.ndarray: + """Scatter matrix of `vectors` distribution (9.2.10)""" + return np.matmul(self.vectors.T, self.vectors) / len(self.vectors) + + def log_likelihood(self, kappa: float, mu: np.ndarray) -> float: + """Log likelihood of given mu, kappa given current vectors. (10.3.30)""" + t = self.scatter_matrix + m = self.kummer_function(1/2, 3/2, kappa) + return len(self.vectors) * (kappa * mu.T @ t @ mu - np.log(m)) + + def nll_of_kappa(self, kappa: float, mu: np.ndarray) -> float: + """Negative log likelihood of this Watson Distribution as a function + of kappa, with `mu` and `vectors` fixed and given in `params`""" + return -self.log_likelihood(kappa=kappa, mu=mu) + + def fit(self, vectors: np.ndarray) -> None: + """Fit distribution to `vectors`, update `self.mu` and `self.kappa`""" + self.vectors = vectors + eig_val, eig_vec = np.linalg.eig(self.scatter_matrix) + fitted = {'mu': np.array([1., 0., 0.]), 'kappa': 0., 'nll': np.inf} + for eig_val, eig_vec in zip(eig_val, eig_vec.T): + result = sp.optimize.minimize(self.nll_of_kappa, x0=0., args=eig_vec) + nll = result['fun'] + if nll < fitted['nll']: + fitted = {'mu': eig_vec, 'kappa': result['x'][0], 'nll': nll} + self.kappa = fitted['kappa'] + self.mu = fitted['mu'] + self.nll = fitted['nll'] + + def sample(self, n: int, seed: int = 42) -> np.ndarray: + """Sample `n` vectors from self, based on doi 10.1080/03610919308813139""" + if n < 0: + return + k = self.kappa + rho = (4 * k) / (2 * k + 3 + ((2 * k + 3) ** 2 - 16 * k) ** 0.5) + r = ((3 * rho) / (2 * k)) ** 3 * np.exp(-3 + 2 * k / rho) + rng = np.random.default_rng(seed=seed) + + def cos2_of_polar(_n: int) -> np.ndarray: + u0 = rng.uniform(size=2*_n) + u1 = rng.uniform(size=2*_n) + s = u0 ** 2 / (1 - rho * (1 - u0 ** 2)) + v = (r * u1 ** 2) / (1 - rho * s) ** 3 + good_s = s[v <= np.exp(2 * k * s)] + return good_s[:_n] if len(good_s) >= _n else \ + np.concatenate([good_s, cos2_of_polar(_n-len(good_s))], axis=None) + u2 = rng.uniform(size=n) + theta = np.arccos(cos2_of_polar(n) ** 0.5) + phi = 4 * np.pi * u2 + theta[u2 < 0.5] = np.pi - theta[u2 < 0.5] + phi[u2 >= 0.5] = 2 * np.pi * (2 * u2[u2 >= 0.5] - 1) + self.vectors = self.mu_sph2cart(np.vstack([np.ones_like(theta), theta, phi]).T) + + +class ZoneAxisFamily(tuple): + """Class for handling "crystal forms", i.e. sets of symm-equiv. zone axes.""" + + def __str__(self) -> str: + return f'{{{self[0]},{self[1]},{self[2]}}}' + + +class UniquePseudoNodeGenerator: + """ + This class generates a list of unique pseudo-nodes; each pseudo-node + represents a single pseudo-vector expressed using integer coordinates + in cartesian space. They can be used to express all possible unique + lattice directions or zone axes with indices up to `radius`. + For example, pseudo-nodes [1, 1, 0], [-1, -1, 0], and [2, 2, 0] all express + the same pseudo-vector [1, 1, 0], independent of symmetry + """ + def __init__(self, laue_group: SgtbxPointGroup = pg_i1) -> None: + self.point_group = laue_group + self.nodes_to_yield = deque() + self.nodes_considered = set() + self.expand(around=(0, 0, 0), radius=3) + + def __iter__(self) -> 'UniquePseudoNodeGenerator': + return self + + def __next__(self) -> Int3: + if self.nodes_to_yield: + return self.nodes_to_yield.popleft() + raise StopIteration + + def add(self, nodes: Iterable[Int3]) -> None: + """Add new pseudo-nodes, but only if they hadn't been yielded yet""" + for node in nodes: + node = tuple(node) + symmetry_equivalents = {tuple(transform(node, symm_op)) + for symm_op in self.point_group} + if not symmetry_equivalents.intersection(self.nodes_considered): + self.nodes_to_yield.append(node) + self.nodes_considered.add(node) + + def expand(self, around: Int3, radius: int = 2) -> None: + """Generate new direction pseudo-vectors in a `RADIUS` around `around`.""" + p_range = np.arange(around[0] - radius, around[0] + radius + 1) + q_range = np.arange(around[1] - radius, around[1] + radius + 1) + r_range = np.arange(around[2] - radius, around[2] + radius + 1) + pqr_mesh = np.meshgrid(p_range, q_range, r_range) + pqr = np.column_stack([mesh_comp.ravel() for mesh_comp in pqr_mesh]) + pqr = pqr[np.linalg.norm(pqr, axis=1) <= radius] + p, q, r = pqr.T + pqr = pqr[(p > 0) | ((p == 0) & (q > 0)) | ((p == 0) & (q == 0) & (r == 1))] + pqr = pqr // np.gcd(np.gcd(pqr[:, 0], pqr[:, 1]), pqr[:, 2])[:, np.newaxis] + self.add(np.unique(pqr, axis=0)) + + +class PreferentialDistributionResults(UserDict[Int3, WatsonDistribution]): + """UserDict holding information about fit results with convenient methods""" + + @property + def best(self) -> Tuple[Int3, WatsonDistribution]: + """Return a tuple w/ best fit (most offending) direction & distribution""" + return list(self.sorted.items())[0] + + @property + def sorted(self) -> 'PreferentialDistributionResults': + return self.__class__(sorted(self.items(), key=lambda i: i[1].nll)) + + def plot(self, kind: str = 'hedgehog'): + """Plot all results in self as a hedgehog or hammer plot """ + artists = {'hedgehog': HedgehogArtist, 'hammer': HammerArtist} + artist = artists[kind]() + for direction, distribution in self.items(): + hh = Hedgehog(distribution=distribution, color='r', name=str(direction)) + artist.register_hedgehog(hh) + artist.plot() + + @property + def table(self) -> str: + """Prepare a pretty string for logging""" + table_data = [['Direction', 'kappa', 'mu', 'NLL']] + for dir_, v in self.sorted.items(): + kappa = f'{v.kappa:+.3f}' + mu = f'[{v.mu[0]:+.3f},{v.mu[1]:+.3f},{v.mu[2]:+.3f}]' + nll = f'{v.nll:.2E}' + table_data.append([str(dir_), kappa, mu, nll]) + return table_utils.format(table_data, has_header=1, delim=' ') + + +def find_preferential_distribution( + dsv: DirectSpaceBases, + space_group: SgtbxSpaceGroup +) -> PreferentialDistributionResults: + """Look for a preferential orientation along any unique zone axis {hkl}""" + laue_group = space_group.build_derived_laue_group() + unique_pseudo_node_generator = UniquePseudoNodeGenerator(laue_group) + results = PreferentialDistributionResults() + for upn in unique_pseudo_node_generator: + a_star = np.cross(dsv.b, dsv.c) # not normalized by volume! + b_star = np.cross(dsv.c, dsv.a) # not normalized by volume! + c_star = np.cross(dsv.a, dsv.b) # not normalized by volume! + vectors = a_star * upn[0] + b_star * upn[1] + c_star * upn[2] + results[ZoneAxisFamily(upn)] = WatsonDistribution.from_vectors(vectors) + return results + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~ ORIENTATION VISUALIZING ~~~~~~~~~~~~~~~~~~~~~~~~~ # + +@dataclass +class Hedgehog: + """Class for holding any `SphericalDistribution` with its metadata""" + distribution: SphericalDistribution + color: str + name: str + + +class BaseDistributionArtist(abc.ABC): + """Base class for plotting hedgehogs of vector distributions""" + PROJECTION: str = NotImplemented + + def __init__(self) -> None: + self.hedgehogs = [] + from mpl_toolkits.mplot3d import Axes3D # noqa: required to use 3D axes + import matplotlib.pyplot as plt + self.plt = plt + self._init_figure() + + def _init_figure(self) -> None: + self.fig = self.plt.figure(constrained_layout=True) + self.axes = [] + + def _generate_axes(self) -> None: + from matplotlib.gridspec import GridSpec + len_ = len(self.hedgehogs) + axes_grid_width = np.ceil(np.sqrt(len_)).astype(int) + axes_grid_height = np.ceil(len_ / axes_grid_width).astype(int) + gs = GridSpec(axes_grid_height, axes_grid_width, figure=self.fig) + for h in range(axes_grid_height): + for w in range(axes_grid_width): + ax = self.fig.add_subplot(gs[h, w], projection=self.PROJECTION) + if len(self.axes) >= len_: + ax.set_axis_off() + self.axes.append(ax) + + def register_hedgehog(self, hedgehog: Hedgehog) -> None: + self.hedgehogs.append(hedgehog) + + @abc.abstractmethod + def plot(self) -> None: + pass + + +class HedgehogArtist(BaseDistributionArtist): + """Class responsible for drawing distribution of vectors as "hedgehogs".""" + PROJECTION = '3d' + + def _plot_hedgehog(self, axes: 'plt.Axes', hedgehog: Hedgehog) -> None: + origin = [0., 0., 0.] + name = hedgehog.name + v = hedgehog.distribution.vectors + mu = hedgehog.distribution.mu + mu_ring = hedgehog.distribution.mu_ring + alpha = 1 / np.log2(len(v) + 1E-8) + axes.quiver(*origin, v[:, 0], v[:, 1], v[:, 2], colors=hedgehog.color, + alpha=alpha, arrow_length_ratio=0.0) + axes.quiver(*-mu, *2*mu, colors='k', arrow_length_ratio=0.1) + axes.plot(mu_ring[:, 0], mu_ring[:, 1], mu_ring[:, 2], color='k') + axes.set_xlim([-1, 1]) + axes.set_ylim([-1, 1]) + axes.set_zlim([-1, 1]) + axes.set_label(axes.get_label() + ' ' + name if axes.get_label() else name) + + def plot(self): + self._generate_axes() + for ax, hedgehog in zip(self.axes, self.hedgehogs): + self._plot_hedgehog(axes=ax, hedgehog=hedgehog) + self.plt.show() + + +def calculate_geographic_heat(vectors: np.ndarray, n_bins: int = 10, + ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: + """ + For an array of cartesian vectors, calculate and return: + - edges of bins in azimuth coordinates, + - edges of bins in polar coordinates, + - heatmap on sphere in azimuth/polar coordinates, + Assuming a geographic definition of polar angle (i.e. from pi/2 to -pi/2). + """ + polar_edges = np.linspace(-np.pi / 2., np.pi / 2., n_bins + 1) + azim_edges = np.linspace(-np.pi, np.pi, n_bins + 1) + r_polar_azim = cart2sph(vectors) + polar = np.pi / 2 - r_polar_azim[:, 1] + azim = r_polar_azim[:, 2] + polar_centers = (polar_edges[:-1] + polar_edges[1:]) / 2 + heat, azim_edges, polar_edges = np.histogram2d( + x=azim, y=polar, bins=[azim_edges, polar_edges]) + heat = np.divide(heat, np.tile(np.cos(polar_centers), (n_bins, 1))) + return azim_edges, polar_edges, heat.T # heat transposed for x/y plotting + + +class HammerArtist(BaseDistributionArtist): + """Class responsible for drawing distributions as hammer heatmaps""" + PROJECTION = 'hammer' + + def _plot_hammer(self, ax: 'plt.Axes', hedgehog: Hedgehog) -> None: + geo_heat = calculate_geographic_heat(vectors=hedgehog.distribution.vectors) + ax.grid(False) + ax.pcolor(*geo_heat, cmap=self.plt.get_cmap('viridis')) + axes_params = {'ls': '', 'marker': 'o', 'mec': 'w'} # lab x, y, and z-axes + ax.plot(0., 0., c='r', **axes_params) + ax.plot([-np.pi / 2, np.pi / 2], [0., 0.], c='g', **axes_params) + ax.plot([0., 0.], [-np.pi / 2, np.pi / 2], c='b', **axes_params) + ax.tick_params(labelbottom=False, labelleft=False) + ax.set_title(hedgehog.name) + + def plot(self) -> None: + self._generate_axes() + for ax, hedgehog in zip(self.axes, self.hedgehogs): + self._plot_hammer(ax=ax, hedgehog=hedgehog) + self.plt.show() + + +def ascii_plot(vectors: np.ndarray, n_bins: int = 10) -> str: + """A string with geographic heat plot on a simple xy cartesian coords""" + px_width = 4 + _, _, heat = calculate_geographic_heat(vectors=vectors) + minh, maxh = np.min(heat), np.max(heat) + int_heat = np.rint(4.0 / (maxh - minh) * (heat.T - minh)).astype(int) + colormap = ' ░▒▓█' + plot_array = np.empty((px_width * n_bins + 2, n_bins + 2,), dtype=str) # x/y + plot_array[0, 0] = '┌' + plot_array[-1, 0] = '┐' + plot_array[0, -1] = '└' + plot_array[-1, -1] = '┘' + plot_array[1:-1, 0] = '─' + plot_array[1:-1, -1] = '─' + plot_array[0, 1:-1] = '│' + plot_array[-1, 1:-1] = '│' + for azim_i in range(n_bins): + for polar_i in range(n_bins): + azim_from = px_width * azim_i + 1 + azim_to = px_width * (azim_i + 1) + 1 + color = colormap[int_heat[azim_i, polar_i]] + plot_array[azim_from:azim_to, polar_i + 1] = color + mx = 1 + (px_width * n_bins) // 2 + my = 1 + n_bins // 2 + plot_array[0, my] = 'X' + plot_array[mx, my] = 'X' + plot_array[-1, my] = 'X' + plot_array[mx // 2, my] = 'Y' + plot_array[mx + mx // 2, my] = 'Y' + plot_array[mx, 0] = 'Z' + plot_array[mx, -1] = 'Z' + return '\n'.join(''.join(c for c in line) for line in plot_array.T) + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ENTRY POINTS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # + + +def run(params_) -> None: + expt_paths = locate_paths(params_.input.glob, params_.input.exclude) + expt_paths = expt_paths[COMM.rank::COMM.size] + expts = read_experiments(*expt_paths) + sgi = params_.input.space_group + space_group = space_group_auto(expts, COMM)[0] if sgi is Auto else sgi.group() + abc_stack = DirectSpaceBases.from_expts(expts, space_group) + if params_.input.symmetrize: + abc_stack = abc_stack.symmetrize(space_group.build_derived_point_group()) + abc_stacks = COMM.gather(abc_stack) + if COMM.rank != 0: + return + abc_stack = DirectSpaceBases(np.concatenate(abc_stacks, axis=0)) + distributions = find_preferential_distribution(abc_stack, space_group) + print(distributions.table) + + plot_style = params_.plot.style + if plot_style != 'none': + if plot_style == 'ascii': + for direction, distribution in distributions.items(): + print(f'Ascii distribution heat plot for direction {direction}:') + print(ascii_plot(distribution.vectors)) + else: + distributions.plot(plot_style) + + +def exercise_watson_distribution() -> None: + ha = HammerArtist() + for kappa in [-10.0, -1.0, -0.1, -0.01, .000001, 0.01, 0.1, 1.0, 10.]: + wd = WatsonDistribution(mu=np.array([0, 0, 1]), kappa=kappa) + wd.sample(1_000_000) + wd.fit(wd.vectors) + print(wd) + hh = Hedgehog(distribution=wd, color='r', name='kappa=' + str(kappa)) + ha.register_hedgehog(hh) + print(ascii_plot(hh.distribution.vectors)) + ha.plot() + + +params = [] +if __name__ == '__main__': + if '--help' in sys.argv[1:] or '-h' in sys.argv[1:]: + print(message) + exit() + params = params_from_phil(phil_scope, sys.argv[1:]) + run(params) From efd53bb5d8074977ca262ddbb2faae1a1196ffb0 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 5 Mar 2024 13:23:42 -0700 Subject: [PATCH 179/748] Add interleave_alt_confs --- iotbx/pdb/tst_hierarchy.py | 64 ++++++++++++++++++++++++++++++++++++++ iotbx/pdb/utils.py | 40 ++++++++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/iotbx/pdb/tst_hierarchy.py b/iotbx/pdb/tst_hierarchy.py index 6d22b26ce6..7cabbf724a 100644 --- a/iotbx/pdb/tst_hierarchy.py +++ b/iotbx/pdb/tst_hierarchy.py @@ -7396,6 +7396,67 @@ def exercise_write_pdb_or_mmcif_file(): is_mmcif = (str(type(pdb_inp)).find('cif')>0) assert is_mmcif +def exercise_interleave_alt_confs(): + pdb_inp_lines_1 = flex.split_lines("""\ +CRYST1 14.600 26.100 29.200 90.00 90.00 90.00 P 21 21 21 +SCALE1 0.068493 -0.000000 -0.000000 0.00000 +SCALE2 0.000000 0.038314 -0.000000 0.00000 +SCALE3 0.000000 0.000000 0.034247 0.00000 +ATOM 17 N ASER 4 -0.155 3.125 4.014 1.00 17.55 N +ATOM 18 CA ASER 4 -0.175 1.896 4.797 1.00 15.51 C +ATOM 19 C ASER 4 1.158 1.683 5.505 1.00 16.48 C +ATOM 20 O ASER 4 1.508 0.560 5.868 1.00 6.79 O +ATOM 21 CB ASER 4 -0.490 0.698 3.899 1.00 17.79 C +ATOM 22 OG ASER 4 -1.752 0.849 3.272 0.50 11.67 O +ATOM 24 N ALEU 5 1.898 2.771 5.698 1.00 10.29 N +ATOM 25 CA ALEU 5 3.208 2.705 6.333 1.00 3.27 C +ATOM 26 C ALEU 5 3.407 3.868 7.301 1.00 7.66 C +ATOM 27 O ALEU 5 3.458 5.024 6.884 1.00 14.56 O +ATOM 28 CB ALEU 5 4.310 2.711 5.272 1.00 3.87 C +ATOM 29 CG ALEU 5 5.736 2.474 5.769 1.00 14.70 C +ATOM 30 CD1ALEU 5 5.818 1.155 6.516 1.00 19.83 C +ATOM 31 CD2ALEU 5 6.719 2.499 4.611 1.00 13.84 C + """) + + pdb_inp_lines_2 = flex.split_lines("""\ +CRYST1 14.600 26.100 29.200 90.00 90.00 90.00 P 21 21 21 +SCALE1 0.068493 -0.000000 -0.000000 0.00000 +SCALE2 0.000000 0.038314 -0.000000 0.00000 +SCALE3 0.000000 0.000000 0.034247 0.00000 +ATOM 17 N BSER 4 -0.155 3.125 4.014 1.00 17.55 N +ATOM 18 CA BSER 4 -0.175 1.896 4.797 1.00 15.51 C +ATOM 19 C BSER 4 1.158 1.683 5.505 1.00 16.48 C +ATOM 20 O BSER 4 1.508 0.560 5.868 1.00 6.79 O +ATOM 21 CB BSER 4 -0.490 0.698 3.899 1.00 17.79 C +ATOM 23 OG BSER 4 0.484 0.555 2.880 0.50 2.71 O +ATOM 24 N BLEU 5 1.898 2.771 5.698 1.00 10.29 N +ATOM 25 CA BLEU 5 3.208 2.705 6.333 1.00 3.27 C +ATOM 26 C BLEU 5 3.407 3.868 7.301 1.00 7.66 C +ATOM 27 O BLEU 5 3.458 5.024 6.884 1.00 14.56 O +ATOM 28 CB BLEU 5 4.310 2.711 5.272 1.00 3.87 C +ATOM 29 CG BLEU 5 5.736 2.474 5.769 1.00 14.70 C +ATOM 30 CD1BLEU 5 5.818 1.155 6.516 1.00 19.83 C +ATOM 31 CD2BLEU 5 6.719 2.499 4.611 1.00 13.84 C +""") + + h1 = pdb.input(source_info=None, lines=pdb_inp_lines_1).construct_hierarchy() + h2 = pdb.input(source_info=None, lines=pdb_inp_lines_2).construct_hierarchy() + + # Interleave the alt confs + from iotbx.pdb.utils import interleave_alt_confs + new_h = interleave_alt_confs(h1,h2) + + # Make sure we got both confs + new_h1 = new_h.apply_atom_selection('altloc A') + new_h2 = new_h.apply_atom_selection('altloc B') + assert new_h1.as_pdb_string() == h1.as_pdb_string() + assert new_h2.as_pdb_string() == h2.as_pdb_string() + + assert new_h1.is_similar_hierarchy(h1) + assert new_h2.is_similar_hierarchy(h2) + + assert not new_h1.is_similar_hierarchy(h2) + assert not new_h2.is_similar_hierarchy(h1) def exercise_fits_in_pdb_format(): pdb_inp_lines = flex.split_lines("""\ @@ -7445,6 +7506,8 @@ def exercise(args): prev = key phenix_regression_pdb_file_names = get_phenix_regression_pdb_file_names() while True: + exercise_interleave_alt_confs() + break # ZZ exercise_remove_residue_groups_with_atoms_on_special_positions_selective() exercise_shift_to_origin() exercise_rename_chain_id() @@ -7507,6 +7570,7 @@ def exercise(args): exercise_forward_compatibility() exercise_as_pdb_or_mmcif_string() exercise_write_pdb_or_mmcif_file() + exercise_interleave_alt_confs() if (not forever): break print(format_cpu_times()) diff --git a/iotbx/pdb/utils.py b/iotbx/pdb/utils.py index 60db1ab58c..f0a5c688b2 100644 --- a/iotbx/pdb/utils.py +++ b/iotbx/pdb/utils.py @@ -719,6 +719,46 @@ def get_cif_or_pdb_file_if_present(file_name): else: return "" # return empty string so os.path.isfile(return_value) works +def interleave_alt_confs(ph1, ph2): + """ Method to interleave alternate conformations in two hierarchies + Requires that all atoms are present in both hierarchies, and that the + hierarchies have different altloc values for each atom + """ + + # Check that hierarchies are similar + ph1_no_alt = ph1.deep_copy() + ph1_no_alt.remove_alt_confs(always_keep_one_conformer=True) + ph2_no_alt = ph2.deep_copy() + ph2_no_alt.remove_alt_confs(always_keep_one_conformer=True) + assert ph1_no_alt.is_similar_hierarchy(ph2_no_alt), \ + "Models do not have the same hierarchy" + + # Interleave the hierarchies + from iotbx.pdb import hierarchy + new_ph = hierarchy.root() + for m0, m1 in zip(ph1.models(), ph2.models()): + m = hierarchy.model() + m.id = m0.id + new_ph.append_model(m) + for c0, c1 in zip(m0.chains(), m1.chains()): + c = hierarchy.chain() + c.id = c0.id + m.append_chain(c) + for rg0, rg1 in zip(c0.residue_groups(), c1.residue_groups()): + r = hierarchy.residue_group() + assert rg0.icode == rg1.icode, "Residue icodes must match" + assert rg0.resseq == rg1.resseq, "Residue resseqs must match" + r.resseq = rg0.resseq + r.icode = rg0.icode + c.append_residue_group(r) + for ag0, ag1 in zip(rg0.atom_groups(), rg1.atom_groups()): + assert ag0.resname == ag1.resname, "Atoms need matching residue names" + assert ag0.altloc != ag1.altloc, "Atoms need different altloc values" + # Append each conformer for this atom group + r.append_atom_group(ag0.detached_copy()) + r.append_atom_group(ag1.detached_copy()) + return new_ph + class numbering_dict: ''' Set up a dict that keeps track of chain ID, residue ID and icode for residues relative to their initial values From 833b22ad6e0660e2e2ae3356d7c990aa0609cecf Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 6 Mar 2024 11:09:01 -0800 Subject: [PATCH 180/748] Suggest using convert_pdb_to_cif_for_pdb_str at end of script, so that a single script can run standard and mmCIF-only tests --- iotbx/command_line/pdb_cif_conversion.py | 71 ++++++++++++------- libtbx/test_utils/__init__.py | 26 +++++-- mmtbx/regression/tst_chain_comparison_cif.py | 28 +++++--- mmtbx/regression/tst_find_ss_structure_cif.py | 3 +- 4 files changed, 85 insertions(+), 43 deletions(-) diff --git a/iotbx/command_line/pdb_cif_conversion.py b/iotbx/command_line/pdb_cif_conversion.py index f865df7118..01717a8c76 100644 --- a/iotbx/command_line/pdb_cif_conversion.py +++ b/iotbx/command_line/pdb_cif_conversion.py @@ -95,11 +95,12 @@ IV. CREATE CIF TESTS TO CHECK CODE WITH MODELS THAT CANNOT FIT IN PDB FORMAT For any code that uses pdb/cif files or that uses the hierarchy object should be tested with models that do not fit in PDB format. It is - recommended that each standard test using models should be duplicated - and run with non-PDB-compliant models. The tool - convert_pdb_to_cif_for_pdb_str can be used to edit strings in place in - tests so that identical starting strings can be used in the original and - non-PDB-compliant tests. + recommended that each standard test using models should either be + duplicated and run with non-PDB-compliant models, or run twice in the + same script, once as-is, and once after converting models to + non-PDB-compliant models. The tool convert_pdb_to_cif_for_pdb_str + can be used to edit strings in place in tests so that identical + starting strings can be used in the original and non-PDB-compliant tests. =========================================================================== =========================================================================== @@ -326,32 +327,48 @@ def get_results(self): IV. CREATING CIF TESTS TO CHECK CODE WITH MODELS THAT CANNOT FIT IN PDB FORMAT You will want to create a cif-only version of all your tests that use - models. The purpose of this is to test all the code that handles + models. This can be done for some tests just by adding a few lines of + code at the end of the test where the methods in the test script are + called. The purpose of the extra testing is to test all the code that handles chain IDs and residue names. A. Simple conversion of tests to mmCIF if your test uses PDB strings. If your test has PDB strings like: pdb_str_1 = """pdb-text""" at the - top of the file, before any function definitions, you can convert - the test to mmCIF by placing two lines below all the pdb_str_xxx - definitions: - - from libtbx.test_utils import convert_pdb_to_cif_for_pdb_str - convert_pdb_to_cif_for_pdb_str(locals()) - - This will make all your PDB strings into mmCIF strings with long - chain IDS. You can choose how to edit your chain ids if you want: - - convert_pdb_to_cif_for_pdb_str(locals(), chain_addition="ZXLONG") - - You might also want to rename some of your residue names - - You can also do this for strings that have some other name: - - my_string="""text""" - convert_pdb_to_cif_for_pdb_str(locals(), key_str = 'my_string') - - Now your test should run just as it did before except that the - chain IDs (and optionally HETATM residue names) may be different. + top of the file, you can make a small change at the end of your script + to run mmCIF tests. + + Suppose the end of your script looks like: + +if __name__=="__main__": + tst_01() + tst_02() + + Then just paste all this in, and indent the tst_01() if necessary: + +if __name__=="__main__": + for as_cif in (False, True): # XXX as_cif is one way so True must be last + if as_cif: + print("\n CONVERTING PDB STRINGS TO CIF AND CHANGING "+ + "CHAIN ID/HETATM RESIDUE NAMES\n") + # Convert to mmcif and make long chain ID and HETATM resname: + from libtbx.test_utils import convert_pdb_to_cif_for_pdb_str + convert_pdb_to_cif_for_pdb_str(locals()) + else: + print("\n USING PDB STRINGS AS IS\n") + + tst_01() + tst_02() + + This will run tst_01 and tst_02 twice. The first time is as usual. The + second time all the pdb_str_xxxx text strings will be converted to mmCIF + format and chain names and HETATM residue names will be made incompatible + with PDB format. + + If your test just produces numbers, the two versions of the tests should + give identical results and no other changes are necessary. If the test + depends on chain ID or on residue names, then it may be necessary to + pass in the value of "as_cif=as_cif" and have different checks in it + for each case. B. If your test uses models in PDB files, you may simply want to make copies of all your models, converting your PDB files into diff --git a/libtbx/test_utils/__init__.py b/libtbx/test_utils/__init__.py index 98b6e6ad25..d738d8e7dc 100644 --- a/libtbx/test_utils/__init__.py +++ b/libtbx/test_utils/__init__.py @@ -848,22 +848,40 @@ def exercise(): assert precision_approx_equal(0.799999,0.800004,precision=18)==False print("OK") -def convert_pdb_to_cif_for_pdb_str(locals, chain_addition = "ZXLONG", key_str="pdb_str"): +def convert_pdb_to_cif_for_pdb_str(locals, chain_addition = "ZXLONG", + key_str="pdb_str", hetatm_name_addition = "ZY", print_new_string = True): # Converts all the strings that start with "pdb_str" from PDB to mmcif # format, adding chain_addition to chain names + # If hetatm_name_addition is set, add to hetatm names + # If print_new_string is set, print the new strings keys = list(locals.keys()) for key in keys: if (not key.startswith(key_str)) or (type(locals[key]) != type("abc")): continue from iotbx.pdb.utils import get_pdb_input - pdb_inp = get_pdb_input(locals[key]) + original_string = locals[key] + pdb_inp = get_pdb_input(original_string) ph = pdb_inp.construct_hierarchy() if ph.overall_counts().n_residues < 1: continue for model in ph.models(): for chain in model.chains(): - chain.id = "%s%s" %(chain.id,chain_addition) - new_string = ph.as_mmcif_string(crystal_symmetry = pdb_inp.crystal_symmetry()) + chain.id = "%s%s" %(chain.id.strip(),chain_addition) + if hetatm_name_addition: + for rg in chain.residue_groups(): + for ag in rg.atom_groups(): + for at in ag.atoms(): + if at.hetero and len(ag.resname)<=3: + ag.resname = "%s%s" %(ag.resname.strip(), hetatm_name_addition) + break + new_string = ph.as_mmcif_string( + crystal_symmetry = pdb_inp.crystal_symmetry()) locals[key] = new_string + if print_new_string: + print("\n",79*"=","\n", + "ORIGINAL STRING '%s':\n%s" %(key, original_string)) + print("\n",79*"=","\n", + "MODIFIED STRING '%s':\n%s" %(key, new_string), + "\n",79*"=","\n") if (__name__ == "__main__"): exercise() diff --git a/mmtbx/regression/tst_chain_comparison_cif.py b/mmtbx/regression/tst_chain_comparison_cif.py index e9d9d8b791..2790887608 100644 --- a/mmtbx/regression/tst_chain_comparison_cif.py +++ b/mmtbx/regression/tst_chain_comparison_cif.py @@ -144,6 +144,7 @@ def remove_blank(text): ATOM 1043 CA VAL 137 127.877 32.680 17.955 1.00 32.92 P9 ATOM 1050 CA LYS 138 128.895 35.931 19.718 1.00 36.89 P9 ATOM 1059 CA GLY 139 126.242 36.878 22.264 0.67 38.21 P9 +HETATM 1060 CA CA 140 126.242 36.878 22.264 0.67 38.21 P9 CA """ pdb_str_query=""" @@ -561,10 +562,6 @@ def remove_blank(text): ATOM 62 CA TYR G 11 200.215 131.269 31.467 1.00 29.03 P9 """ -# Convert to mmcif: -chain_addition = "XZLONG" -from libtbx.test_utils import convert_pdb_to_cif_for_pdb_str -convert_pdb_to_cif_for_pdb_str(locals(),chain_addition=chain_addition) def tst_01(): print("Comparing mixed model with target...") @@ -848,10 +845,19 @@ def tst_06(): print("OK") if __name__=="__main__": - tst_06() # ZZZ - tst_01() - tst_02() - tst_03() - tst_04() - tst_05() - tst_06() + for as_cif in (False, True): # XXX as_cif is one way so True must be last + if as_cif: + print("\n CONVERTING PDB STRINGS TO CIF AND CHANGING "+ + "CHAIN ID/HETATM RESIDUE NAMES\n") + # Convert to mmcif and make long chain ID and HETATM resname: + from libtbx.test_utils import convert_pdb_to_cif_for_pdb_str + convert_pdb_to_cif_for_pdb_str(locals()) + else: + print("\n USING PDB STRINGS AS IS\n") + + tst_01() + tst_02() + tst_03() + tst_04() + tst_05() + tst_06() diff --git a/mmtbx/regression/tst_find_ss_structure_cif.py b/mmtbx/regression/tst_find_ss_structure_cif.py index 16cf46839c..0e059d3226 100644 --- a/mmtbx/regression/tst_find_ss_structure_cif.py +++ b/mmtbx/regression/tst_find_ss_structure_cif.py @@ -1368,7 +1368,8 @@ def remove_blank(text): # Convert to mmcif: chain_addition = "XZLONG" from libtbx.test_utils import convert_pdb_to_cif_for_pdb_str -convert_pdb_to_cif_for_pdb_str(locals(),chain_addition=chain_addition) +convert_pdb_to_cif_for_pdb_str(locals(),chain_addition=chain_addition, + hetatm_name_addition="") def tst_00(): print("Finding sheets, splitting and merging...", end=' ') From 5ae7d0e3e38029aab1dab1c6b7eeb57ac881092d Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 6 Mar 2024 12:12:55 -0700 Subject: [PATCH 181/748] clean up formatting --- mmtbx/command_line/map_box.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mmtbx/command_line/map_box.py b/mmtbx/command_line/map_box.py index 8c5a1c8717..827b34f4a4 100644 --- a/mmtbx/command_line/map_box.py +++ b/mmtbx/command_line/map_box.py @@ -1197,7 +1197,8 @@ def run(args, box_crystal_symmetry = mam.map_manager().crystal_symmetry(), pdb_outside_box_msg = "", gridding_first = getattr(mam, 'gridding_first', (0, 0, 0)), - gridding_last = getattr(mam, 'gridding_last', mam.map_manager().map_data().all()), + gridding_last = getattr(mam, + 'gridding_last', mam.map_manager().map_data().all()), solvent_content = params.solvent_content, origin_shift_grid_units = [ -x for x in mam.map_manager().origin_shift_grid_units], @@ -1207,7 +1208,8 @@ def run(args, map_manager = mam.map_manager() ncs_object = mam.map_manager().ncs_object() from iotbx.data_manager import DataManager - dm = DataManager(datatypes = ['model', 'ncs_spec', 'real_map', 'miller_array']) + dm = DataManager(datatypes = [ + 'model', 'ncs_spec', 'real_map', 'miller_array']) dm.set_overwrite(True) # Write PDB file From 0268fe66f88c1b0befcc96d3cb6285d2686b3217 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 6 Mar 2024 13:15:15 -0800 Subject: [PATCH 182/748] iotbx: add --json-filename flag to CCTBXParser - Optionally specify JSON output filename - --json-filename implies --json so only one flag is needed if a non-default filename is needed for JSON output --- iotbx/cli_parser.py | 28 ++++++++-- iotbx/regression/tst_cli_parser.py | 82 ++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+), 5 deletions(-) diff --git a/iotbx/cli_parser.py b/iotbx/cli_parser.py index a1ebac9a98..2ff0c55238 100644 --- a/iotbx/cli_parser.py +++ b/iotbx/cli_parser.py @@ -248,8 +248,21 @@ def add_default_options(self): # return JSON output from program self.add_argument( '--json', action='store_true', - help='writes or overwrites the JSON output for the program to file (%s)' % - self.json_filename + help='''\ +writes or overwrites the JSON output for the program to file (%s). +Use --json-filename to specify a different filename for the output.''' % + self.json_filename, + ) + + # --json-filename + # set a non-default filename for JSON output + self.add_argument( + '--json-filename', '--json_filename', action='store', + type=str, default=None, + help='''\ +optionally specify a filename for JSON output. If a filename is provided, +the .json extension will be added automatically if it does not already exist. +Also, specifying this flag implies that --json is also specified.''' ) # --overwrite @@ -939,15 +952,20 @@ def run_program(program_class=None, parser_class=CCTBXParser, custom_process_arg pr.dump_stats('profile.out') # output JSON - if namespace.json: + if namespace.json or namespace.json_filename: result = task.get_results_as_JSON() if result is not None: - with open(parser.json_filename, 'w') as f: + json_filename = parser.json_filename + if namespace.json_filename is not None: + json_filename = namespace.json_filename + if not json_filename.endswith('.json'): + json_filename += '.json' + with open(json_filename, 'w') as f: f.write(result) else: print('', file=logger) print('!'*79, file=logger) - print('WARNING: The get_results_as_JSON function has not been defined for this program') + print('WARNING: The get_results_as_JSON function has not been defined for this program', file=logger) print('!'*79, file=logger) # stop timer diff --git a/iotbx/regression/tst_cli_parser.py b/iotbx/regression/tst_cli_parser.py index 7602c1e694..8932056c95 100644 --- a/iotbx/regression/tst_cli_parser.py +++ b/iotbx/regression/tst_cli_parser.py @@ -1,6 +1,7 @@ from __future__ import absolute_import, division, print_function import os +import json from six.moves import cStringIO as StringIO @@ -340,6 +341,86 @@ def run(self): except Sorry as s: assert 'duplicate user_selected_labels' in str(s) +# ----------------------------------------------------------------------------- +def test_json(): + class testProgram(ProgramTemplate): + program_name = 'tst_cli_parser' + datatypes = ['model', 'phil'] + def validate(self): + pass + def run(self): + pass + + data_dir = os.path.dirname(os.path.abspath(__file__)) + model_1yjp = os.path.join(data_dir, 'data', '1yjp.pdb') + + # check for get_results_as_JSON function + parser_log = StringIO() + logger = multi_out() + logger.register('parser_log', parser_log) + + run_program( + program_class=testProgram, + args=['--overwrite', '--json', model_1yjp], + logger=parser_log + ) + + parser_log.flush() + text = parser_log.getvalue() + assert 'WARNING: The get_results_as_JSON function has not been defined for this program' in text + + logger.close() + + # check that json file is output + expected_result = {'key': 'value'} + class testProgram(ProgramTemplate): + program_name = 'tst_cli_parser' + datatypes = ['model', 'phil'] + def validate(self): + pass + def run(self): + pass + def get_results_as_JSON(self): + dummy_results = expected_result + return json.dumps(dummy_results, indent=2) + + run_program( + program_class=testProgram, + args=['--quiet', '--overwrite', '--json', model_1yjp] + ) + + expected_filename = 'tst_cli_parser_result.json' + assert os.path.exists(expected_filename) + with open(expected_filename, 'r') as f: + result = json.loads(f.read()) + assert result == expected_result + os.remove(expected_filename) + + # check non-default filename + expected_filename = 'non-default.json' + run_program( + program_class=testProgram, + args=['--quiet', '--overwrite', '--json', + '--json-filename', expected_filename, model_1yjp] + ) + assert os.path.exists(expected_filename) + with open(expected_filename, 'r') as f: + result = json.loads(f.read()) + assert result == expected_result + os.remove(expected_filename) + + # try only with --json_filename and without .json extension + filename = 'non-default' + run_program( + program_class=testProgram, + args=['--quiet', '--overwrite', + '--json_filename', filename, model_1yjp] + ) + assert os.path.exists(expected_filename) + with open(expected_filename, 'r') as f: + result = json.loads(f.read()) + assert result == expected_result + os.remove(expected_filename) # ============================================================================= if __name__ == '__main__': @@ -347,5 +428,6 @@ def run(self): test_label_parsing() test_model_type_parsing() test_user_selected_labels() + test_json() print("OK") From 952400881595ec7bdeeab5a28dcf3aab16116952 Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 6 Mar 2024 14:58:16 -0700 Subject: [PATCH 183/748] Generalize interleave_alt_confs and move test to tst_utils.py --- iotbx/pdb/tst_hierarchy.py | 65 -------------------------------------- iotbx/pdb/tst_utils.py | 65 ++++++++++++++++++++++++++++++++++++++ iotbx/pdb/utils.py | 26 +++++++++++++-- 3 files changed, 89 insertions(+), 67 deletions(-) diff --git a/iotbx/pdb/tst_hierarchy.py b/iotbx/pdb/tst_hierarchy.py index 7cabbf724a..b895b9ffbb 100644 --- a/iotbx/pdb/tst_hierarchy.py +++ b/iotbx/pdb/tst_hierarchy.py @@ -7396,68 +7396,6 @@ def exercise_write_pdb_or_mmcif_file(): is_mmcif = (str(type(pdb_inp)).find('cif')>0) assert is_mmcif -def exercise_interleave_alt_confs(): - pdb_inp_lines_1 = flex.split_lines("""\ -CRYST1 14.600 26.100 29.200 90.00 90.00 90.00 P 21 21 21 -SCALE1 0.068493 -0.000000 -0.000000 0.00000 -SCALE2 0.000000 0.038314 -0.000000 0.00000 -SCALE3 0.000000 0.000000 0.034247 0.00000 -ATOM 17 N ASER 4 -0.155 3.125 4.014 1.00 17.55 N -ATOM 18 CA ASER 4 -0.175 1.896 4.797 1.00 15.51 C -ATOM 19 C ASER 4 1.158 1.683 5.505 1.00 16.48 C -ATOM 20 O ASER 4 1.508 0.560 5.868 1.00 6.79 O -ATOM 21 CB ASER 4 -0.490 0.698 3.899 1.00 17.79 C -ATOM 22 OG ASER 4 -1.752 0.849 3.272 0.50 11.67 O -ATOM 24 N ALEU 5 1.898 2.771 5.698 1.00 10.29 N -ATOM 25 CA ALEU 5 3.208 2.705 6.333 1.00 3.27 C -ATOM 26 C ALEU 5 3.407 3.868 7.301 1.00 7.66 C -ATOM 27 O ALEU 5 3.458 5.024 6.884 1.00 14.56 O -ATOM 28 CB ALEU 5 4.310 2.711 5.272 1.00 3.87 C -ATOM 29 CG ALEU 5 5.736 2.474 5.769 1.00 14.70 C -ATOM 30 CD1ALEU 5 5.818 1.155 6.516 1.00 19.83 C -ATOM 31 CD2ALEU 5 6.719 2.499 4.611 1.00 13.84 C - """) - - pdb_inp_lines_2 = flex.split_lines("""\ -CRYST1 14.600 26.100 29.200 90.00 90.00 90.00 P 21 21 21 -SCALE1 0.068493 -0.000000 -0.000000 0.00000 -SCALE2 0.000000 0.038314 -0.000000 0.00000 -SCALE3 0.000000 0.000000 0.034247 0.00000 -ATOM 17 N BSER 4 -0.155 3.125 4.014 1.00 17.55 N -ATOM 18 CA BSER 4 -0.175 1.896 4.797 1.00 15.51 C -ATOM 19 C BSER 4 1.158 1.683 5.505 1.00 16.48 C -ATOM 20 O BSER 4 1.508 0.560 5.868 1.00 6.79 O -ATOM 21 CB BSER 4 -0.490 0.698 3.899 1.00 17.79 C -ATOM 23 OG BSER 4 0.484 0.555 2.880 0.50 2.71 O -ATOM 24 N BLEU 5 1.898 2.771 5.698 1.00 10.29 N -ATOM 25 CA BLEU 5 3.208 2.705 6.333 1.00 3.27 C -ATOM 26 C BLEU 5 3.407 3.868 7.301 1.00 7.66 C -ATOM 27 O BLEU 5 3.458 5.024 6.884 1.00 14.56 O -ATOM 28 CB BLEU 5 4.310 2.711 5.272 1.00 3.87 C -ATOM 29 CG BLEU 5 5.736 2.474 5.769 1.00 14.70 C -ATOM 30 CD1BLEU 5 5.818 1.155 6.516 1.00 19.83 C -ATOM 31 CD2BLEU 5 6.719 2.499 4.611 1.00 13.84 C -""") - - h1 = pdb.input(source_info=None, lines=pdb_inp_lines_1).construct_hierarchy() - h2 = pdb.input(source_info=None, lines=pdb_inp_lines_2).construct_hierarchy() - - # Interleave the alt confs - from iotbx.pdb.utils import interleave_alt_confs - new_h = interleave_alt_confs(h1,h2) - - # Make sure we got both confs - new_h1 = new_h.apply_atom_selection('altloc A') - new_h2 = new_h.apply_atom_selection('altloc B') - assert new_h1.as_pdb_string() == h1.as_pdb_string() - assert new_h2.as_pdb_string() == h2.as_pdb_string() - - assert new_h1.is_similar_hierarchy(h1) - assert new_h2.is_similar_hierarchy(h2) - - assert not new_h1.is_similar_hierarchy(h2) - assert not new_h2.is_similar_hierarchy(h1) - def exercise_fits_in_pdb_format(): pdb_inp_lines = flex.split_lines("""\ ATOM 1 CA ASP A 1 47.975 -63.194 59.946 1.00 33.86 C @@ -7506,8 +7444,6 @@ def exercise(args): prev = key phenix_regression_pdb_file_names = get_phenix_regression_pdb_file_names() while True: - exercise_interleave_alt_confs() - break # ZZ exercise_remove_residue_groups_with_atoms_on_special_positions_selective() exercise_shift_to_origin() exercise_rename_chain_id() @@ -7570,7 +7506,6 @@ def exercise(args): exercise_forward_compatibility() exercise_as_pdb_or_mmcif_string() exercise_write_pdb_or_mmcif_file() - exercise_interleave_alt_confs() if (not forever): break print(format_cpu_times()) diff --git a/iotbx/pdb/tst_utils.py b/iotbx/pdb/tst_utils.py index b4429b9e46..47977013ac 100644 --- a/iotbx/pdb/tst_utils.py +++ b/iotbx/pdb/tst_utils.py @@ -94,12 +94,77 @@ def exercise_get_pdb_info(): assert pdb_info_from_pdb.crystal_symmetry.is_similar_symmetry( pdb_info_from_cif.crystal_symmetry) +def exercise_interleave_alt_confs(): + from scitbx.array_family import flex + import iotbx.pdb + pdb_inp_lines_1 = flex.split_lines("""\ +CRYST1 14.600 26.100 29.200 90.00 90.00 90.00 P 21 21 21 +SCALE1 0.068493 -0.000000 -0.000000 0.00000 +SCALE2 0.000000 0.038314 -0.000000 0.00000 +SCALE3 0.000000 0.000000 0.034247 0.00000 +ATOM 17 N ASER 4 -0.155 3.125 4.014 1.00 17.55 N +ATOM 18 CA ASER 4 -0.175 1.896 4.797 1.00 15.51 C +ATOM 19 C ASER 4 1.158 1.683 5.505 1.00 16.48 C +ATOM 20 O ASER 4 1.508 0.560 5.868 1.00 6.79 O +ATOM 21 CB ASER 4 -0.490 0.698 3.899 1.00 17.79 C +ATOM 22 OG ASER 4 -1.752 0.849 3.272 0.50 11.67 O +ATOM 24 N ALEU 5 1.898 2.771 5.698 1.00 10.29 N +ATOM 25 CA ALEU 5 3.208 2.705 6.333 1.00 3.27 C +ATOM 26 C ALEU 5 3.407 3.868 7.301 1.00 7.66 C +ATOM 27 O ALEU 5 3.458 5.024 6.884 1.00 14.56 O +ATOM 28 CB ALEU 5 4.310 2.711 5.272 1.00 3.87 C +ATOM 29 CG ALEU 5 5.736 2.474 5.769 1.00 14.70 C +ATOM 30 CD1ALEU 5 5.818 1.155 6.516 1.00 19.83 C +ATOM 31 CD2ALEU 5 6.719 2.499 4.611 1.00 13.84 C + """) + + pdb_inp_lines_2 = flex.split_lines("""\ +CRYST1 14.600 26.100 29.200 90.00 90.00 90.00 P 21 21 21 +SCALE1 0.068493 -0.000000 -0.000000 0.00000 +SCALE2 0.000000 0.038314 -0.000000 0.00000 +SCALE3 0.000000 0.000000 0.034247 0.00000 +ATOM 17 N BSER 4 -0.155 3.125 4.014 1.00 17.55 N +ATOM 18 CA BSER 4 -0.175 1.896 4.797 1.00 15.51 C +ATOM 19 C BSER 4 1.158 1.683 5.505 1.00 16.48 C +ATOM 20 O BSER 4 1.508 0.560 5.868 1.00 6.79 O +ATOM 21 CB BSER 4 -0.490 0.698 3.899 1.00 17.79 C +ATOM 23 OG BSER 4 0.484 0.555 2.880 0.50 2.71 O +ATOM 24 N BLEU 5 1.898 2.771 5.698 1.00 10.29 N +ATOM 25 CA BLEU 5 3.208 2.705 6.333 1.00 3.27 C +ATOM 26 C BLEU 5 3.407 3.868 7.301 1.00 7.66 C +ATOM 27 O BLEU 5 3.458 5.024 6.884 1.00 14.56 O +ATOM 28 CB BLEU 5 4.310 2.711 5.272 1.00 3.87 C +ATOM 29 CG BLEU 5 5.736 2.474 5.769 1.00 14.70 C +ATOM 30 CD1BLEU 5 5.818 1.155 6.516 1.00 19.83 C +ATOM 31 CD2BLEU 5 6.719 2.499 4.611 1.00 13.84 C +""") + + h1 = iotbx.pdb.input(source_info=None, lines=pdb_inp_lines_1).construct_hierarchy() + h2 = iotbx.pdb.input(source_info=None, lines=pdb_inp_lines_2).construct_hierarchy() + + # Interleave the alt confs + from iotbx.pdb.utils import interleave_alt_confs + new_h = interleave_alt_confs(h1,h2) + + # Make sure we got both confs + new_h1 = new_h.apply_atom_selection('altloc A') + new_h2 = new_h.apply_atom_selection('altloc B') + assert new_h1.as_pdb_string() == h1.as_pdb_string() + assert new_h2.as_pdb_string() == h2.as_pdb_string() + + assert new_h1.is_similar_hierarchy(h1) + assert new_h2.is_similar_hierarchy(h2) + + assert not new_h1.is_similar_hierarchy(h2) + assert not new_h2.is_similar_hierarchy(h1) + def run(): exercise_add_models_and_hierarchies() exercise_set_element_ignoring_spacings() exercise_check_pseudo_atoms() exercise_get_pdb_info() exercise_all_chain_ids() + exercise_interleave_alt_confs() print("OK") if __name__ == '__main__': diff --git a/iotbx/pdb/utils.py b/iotbx/pdb/utils.py index f0a5c688b2..7dbadde321 100644 --- a/iotbx/pdb/utils.py +++ b/iotbx/pdb/utils.py @@ -719,10 +719,12 @@ def get_cif_or_pdb_file_if_present(file_name): else: return "" # return empty string so os.path.isfile(return_value) works -def interleave_alt_confs(ph1, ph2): +def interleave_alt_confs(ph1, ph2, selection_string = None): """ Method to interleave alternate conformations in two hierarchies Requires that all atoms are present in both hierarchies, and that the - hierarchies have different altloc values for each atom + hierarchies have different altloc values for each atom. + If selection_string is supplied, remove all alternate conformations that + are not in the selection (keep just selected alternate conformations) """ # Check that hierarchies are similar @@ -757,6 +759,26 @@ def interleave_alt_confs(ph1, ph2): # Append each conformer for this atom group r.append_atom_group(ag0.detached_copy()) r.append_atom_group(ag1.detached_copy()) + + if selection_string: # Identify atoms to save only one conformer by index + asc1=new_ph.atom_selection_cache() + sel1=asc1.selection(string = selection_string) # sel1[i] = True to keep + + i = 0 + for model in new_ph.models(): + for chain in model.chains(): + for rg in chain.residue_groups(): + remove = [] + first = True + for ag in rg.atom_groups(): + for at in ag.atoms(): + if ((not first) and (not ag in remove) and (not sel1[i])): + remove.append(ag) + i += 1 # same indexing as sel1 with this traverse of hierarchy + first = False + for ag in remove: # remove all the unwanted atom groups + rg.remove_atom_group(atom_group=ag) + return new_ph class numbering_dict: From 4e1b6ae4ab64ffcbb35025140e58e46c41344501 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Wed, 6 Mar 2024 13:26:12 -0800 Subject: [PATCH 184/748] Hide non-useful output --- mmtbx/programs/rama_z.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/mmtbx/programs/rama_z.py b/mmtbx/programs/rama_z.py index cb6fc75d99..306716414a 100644 --- a/mmtbx/programs/rama_z.py +++ b/mmtbx/programs/rama_z.py @@ -113,12 +113,14 @@ def run(self): self.data_manager.write_model_file(selected_model, filename=fn) self._write_plots_if_needed(selected_model, label, type_of_plot='HSL') result = self.get_results() - res_info = self.rama_z.get_detailed_values() - print ("Individual residues info:", file=self.logger) - print ("Residue name, type, SS, (phi, psi), Z", file=self.logger) - for i in res_info: - print ('%4s %10s %1s (%7.2f, %7.2f) %7.4f' % ( - i[2], res_type_labels[i[1]], i[3], i[4], i[5], i[6]), file=self.logger) + # This brings 0 value to the user. Per-residue numbers + # should not be analyzed, therefore no reason to print them. + # res_info = self.rama_z.get_detailed_values() + # print ("Individual residues info:", file=self.logger) + # print ("Residue name, type, SS, (phi, psi), Z", file=self.logger) + # for i in res_info: + # print ('%4s %10s %1s (%7.2f, %7.2f) %7.4f' % ( + # i[2], res_type_labels[i[1]], i[3], i[4], i[5], i[6]), file=self.logger) print(result.as_string(prefix=""), file = self.logger) From bef9cdc023bf59afb6eb36c59fb93b6749675ece Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Wed, 6 Mar 2024 14:19:00 -0800 Subject: [PATCH 185/748] add json results --- mmtbx/programs/rama_z.py | 15 ++++++++++++--- mmtbx/validation/rama_z.py | 10 ++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/mmtbx/programs/rama_z.py b/mmtbx/programs/rama_z.py index 306716414a..8074a7ac10 100644 --- a/mmtbx/programs/rama_z.py +++ b/mmtbx/programs/rama_z.py @@ -79,6 +79,7 @@ def _write_plots_if_needed(self, model, label, type_of_plot='whole'): self.plots[i].save_image(fn, dpi=300) def run(self): + self.result = None models = [] for model_name in self.data_manager.get_model_names(): models.append(self.data_manager.get_model(model_name)) @@ -112,7 +113,7 @@ def run(self): print("Writing out partial model: %s" % fn, file=self.logger) self.data_manager.write_model_file(selected_model, filename=fn) self._write_plots_if_needed(selected_model, label, type_of_plot='HSL') - result = self.get_results() + self.result = self.get_results() # This brings 0 value to the user. Per-residue numbers # should not be analyzed, therefore no reason to print them. # res_info = self.rama_z.get_detailed_values() @@ -122,8 +123,16 @@ def run(self): # print ('%4s %10s %1s (%7.2f, %7.2f) %7.4f' % ( # i[2], res_type_labels[i[1]], i[3], i[4], i[5], i[6]), file=self.logger) - print(result.as_string(prefix=""), file = self.logger) + print(self.result.as_string(prefix=""), file = self.logger) + # print(self.result.as_json(), file=self.logger) # --------------------------------------------------------------------------- def get_results(self): - return self.rama_z.get_result() + if self.result is None: + self.result = self.rama_z.get_result() + return self.result + + def get_results_as_JSON(self): + if self.result is None: + self.result = self.rama_z.get_result() + return self.result.as_json() diff --git a/mmtbx/validation/rama_z.py b/mmtbx/validation/rama_z.py index fd1f9a3539..381ad3b531 100644 --- a/mmtbx/validation/rama_z.py +++ b/mmtbx/validation/rama_z.py @@ -15,6 +15,7 @@ from scitbx.math import linear_interpolation_2d import numpy as np import math +import json import os import sys @@ -46,6 +47,15 @@ def as_string(self, prefix=''): ] return "\n".join(strs) + def as_json(self): + data = {} + for name, obj in [('whole', self.whole), ('helix', self.helix), + ('sheet', self.sheet), ('loop', self.loop)]: + data[name] = {'value':obj.value, + 'std':obj.std, + 'n_residues':obj.n} + return json.dumps(data, indent=2) + class rama_z(object): def __init__(self, models, log): db_path = libtbx.env.find_in_repositories( From 182dd01b7e3dfa33998e673d69d027d2ce8a1aa1 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 6 Mar 2024 15:01:15 -0800 Subject: [PATCH 186/748] Declutter: remove mmtbx/cablam directory. Was for development purposes only. --- mmtbx/cablam/SConscript | 10 - mmtbx/cablam/__init__.py | 0 .../boost_python/cablam_align_utils_ext.cpp | 48 - mmtbx/cablam/cablam_align.py | 385 ----- mmtbx/cablam/cablam_align_utils.h | 106 -- mmtbx/cablam/cablam_fingerprints.py | 398 ----- mmtbx/cablam/cablam_math.py | 374 ----- mmtbx/cablam/cablam_res.py | 326 ----- mmtbx/cablam/cablam_training.py | 1236 ---------------- mmtbx/cablam/cablam_validate.py | 1285 ----------------- mmtbx/cablam/fingerprints/__init__.py | 0 .../fingerprints/alpha_helix_3_full.pickle | Bin 1016 -> 0 bytes .../fingerprints/alpha_helix_3hs.pickle | Bin 827 -> 0 bytes .../fingerprints/alpha_helix_3os.pickle | Bin 818 -> 0 bytes .../cablam/fingerprints/antiparallel_beta.py | 337 ----- .../fingerprints/antiparallel_beta_bridge.py | 207 --- .../antiparallel_beta_bridge_close.pickle | Bin 1451 -> 0 bytes .../antiparallel_beta_bridge_wide.pickle | Bin 1320 -> 0 bytes .../fingerprints/antiparallel_beta_cwc.pickle | Bin 1928 -> 0 bytes .../fingerprints/antiparallel_beta_wcw.pickle | Bin 1883 -> 0 bytes mmtbx/cablam/fingerprints/how_to.py | 145 -- .../cablam/fingerprints/parallel_beta.pickle | Bin 1779 -> 0 bytes mmtbx/cablam/fingerprints/parallel_beta.py | 240 --- .../fingerprints/parallel_beta_bridge.pickle | Bin 1374 -> 0 bytes .../fingerprints/regular_helix_definitions.py | 174 --- .../fingerprints/threeten_general.pickle | Bin 1219 -> 0 bytes mmtbx/regression/tst_cablam.py | 219 --- 27 files changed, 5490 deletions(-) delete mode 100644 mmtbx/cablam/SConscript delete mode 100644 mmtbx/cablam/__init__.py delete mode 100644 mmtbx/cablam/boost_python/cablam_align_utils_ext.cpp delete mode 100644 mmtbx/cablam/cablam_align.py delete mode 100644 mmtbx/cablam/cablam_align_utils.h delete mode 100644 mmtbx/cablam/cablam_fingerprints.py delete mode 100644 mmtbx/cablam/cablam_math.py delete mode 100644 mmtbx/cablam/cablam_res.py delete mode 100644 mmtbx/cablam/cablam_training.py delete mode 100644 mmtbx/cablam/cablam_validate.py delete mode 100644 mmtbx/cablam/fingerprints/__init__.py delete mode 100644 mmtbx/cablam/fingerprints/alpha_helix_3_full.pickle delete mode 100644 mmtbx/cablam/fingerprints/alpha_helix_3hs.pickle delete mode 100644 mmtbx/cablam/fingerprints/alpha_helix_3os.pickle delete mode 100644 mmtbx/cablam/fingerprints/antiparallel_beta.py delete mode 100644 mmtbx/cablam/fingerprints/antiparallel_beta_bridge.py delete mode 100644 mmtbx/cablam/fingerprints/antiparallel_beta_bridge_close.pickle delete mode 100644 mmtbx/cablam/fingerprints/antiparallel_beta_bridge_wide.pickle delete mode 100644 mmtbx/cablam/fingerprints/antiparallel_beta_cwc.pickle delete mode 100644 mmtbx/cablam/fingerprints/antiparallel_beta_wcw.pickle delete mode 100644 mmtbx/cablam/fingerprints/how_to.py delete mode 100644 mmtbx/cablam/fingerprints/parallel_beta.pickle delete mode 100644 mmtbx/cablam/fingerprints/parallel_beta.py delete mode 100644 mmtbx/cablam/fingerprints/parallel_beta_bridge.pickle delete mode 100644 mmtbx/cablam/fingerprints/regular_helix_definitions.py delete mode 100644 mmtbx/cablam/fingerprints/threeten_general.pickle delete mode 100644 mmtbx/regression/tst_cablam.py diff --git a/mmtbx/cablam/SConscript b/mmtbx/cablam/SConscript deleted file mode 100644 index 67b1edbe19..0000000000 --- a/mmtbx/cablam/SConscript +++ /dev/null @@ -1,10 +0,0 @@ -Import("env_etc") - -if (not env_etc.no_boost_python): - Import("env_iotbx_boost_python_ext") - env = env_iotbx_boost_python_ext.Clone() - env.Prepend(LIBS=["cctbx", "scitbx_boost_python"]) - env_etc.enable_more_warnings(env=env) - env.SharedLibrary( - target="#lib/mmtbx_cablam_align_utils_ext", - source=["boost_python/cablam_align_utils_ext.cpp"]) diff --git a/mmtbx/cablam/__init__.py b/mmtbx/cablam/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/mmtbx/cablam/boost_python/cablam_align_utils_ext.cpp b/mmtbx/cablam/boost_python/cablam_align_utils_ext.cpp deleted file mode 100644 index 15274c3cc1..0000000000 --- a/mmtbx/cablam/boost_python/cablam_align_utils_ext.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - - -namespace mmtbx { namespace cablam { -namespace boost_python { - - void wrap_cablam_align_utils_proxies () - { - using namespace boost::python; - def("get_similar_regions", get_similar_regions); - - typedef index_mean i_m; - typedef return_value_policy rbv; - class_("index_mean", no_init) - .def(init(( - arg("i_1"), - arg("i_2"), - arg("mean"), - arg("window_length")))) - .add_property("i_1", make_getter(&i_m::i_1, rbv())) - .add_property("i_2", make_getter(&i_m::i_2, rbv())) - .add_property("mean", make_getter(&i_m::mean, rbv())) - .add_property("window_length", make_getter(&i_m::window_length, rbv())) - ; - } - - void wrap_cablam_align_utils () - { - wrap_cablam_align_utils_proxies(); - } - -}}} -BOOST_PYTHON_MODULE(mmtbx_cablam_align_utils_ext) -{ - mmtbx::cablam::boost_python::wrap_cablam_align_utils(); -} diff --git a/mmtbx/cablam/cablam_align.py b/mmtbx/cablam/cablam_align.py deleted file mode 100644 index 4bd0a08f1f..0000000000 --- a/mmtbx/cablam/cablam_align.py +++ /dev/null @@ -1,385 +0,0 @@ -from __future__ import absolute_import, division, print_function -# (jEdit options) :folding=explicit:collapseFolds=1: -################################################################################ -# -# Sandbox to play with cablam objects -# -################################################################################ - -import os, sys -from mmtbx.cablam import cablam_validate -import libtbx.phil.command_line -from iotbx import pdb -from iotbx import file_reader -from libtbx import group_args -import boost_adaptbx.boost.python as bp -from six.moves import range -cpputils = bp.import_ext("mmtbx_cablam_align_utils_ext") - -# {{{ phil -#------------------------------------------------------------------------------- -master_phil = libtbx.phil.parse(""" -cablam_align { - pdb_infile_1 = None - .type = path - .help = '''input PDB file''' - pdb_infile_2 = None - .type = path - .help = '''input PDB file''' - chain_1 = None - .type = str - .help = '''chain for pdb_infile_1''' - chain_2 = None - .type = str - .help = '''chain for pdb_infile_2''' - help = False - .type = bool - .help = '''help and data interpretation messages''' - threshold = 10 - .type = float - .help = '''keeps all regions who have diff list averages lower than this''' - window_size = 10 - .type = int - .help = '''the size of the regions when looking for similarities''' -} -""", process_includes=True) -#------------------------------------------------------------------------------- -#}}} - -# {{{ usage -def usage(): - sys.stderr.write(""" --------------------------------------------------------------------------------- -python cablam_align.py 1234.pdb abcd.pdb - -The user must provide TWO and only TWO pdb files. --------------------------------------------------------------------------------- -""") -#}}} - -# {{{ cablam_residues -class cablam_residues(object): - - #{{{ get_continuous_segments - # retuns a list of segments. segments are list of cablam linked_residue objects - def get_continuous_segments(self): - segments = [] - n_residues =[v for k,v in self.cablam_residues.items() if v.prevres == None] - for res in n_residues : - cur_res = res - segment = [] - while cur_res != None : - segment.append(cur_res) - cur_res = cur_res.nextres - segments.append(segment) - return segments - #}}} - - #{{{ __init__ - def __init__(self, - pdb_infile = None, - pdbid = None, - hierarchy = None): - assert pdb_infile != None or hierarchy != None - if pdb_infile != None and hierarchy != None : - w = "WARNING: pdb_infile AND hierarchy detected; hierarchy will be used.\n" - sys.stderr.write(w) - if hierarchy == None : - pdb_io = pdb.input(pdb_infile) - hierarchy = pdb_io.construct_hierarchy() - assert hierarchy != None - if pdbid == None : self.pdbid = os.path.basename(pdb_infile)[:-4] - else : self.pdbid = pdbid - self.cablam_residues = cablam_validate.setup(hierarchy = hierarchy, - pdbid = self.pdbid) - - # get continuous segments - self.segments = self.get_continuous_segments() - #}}} - -#}}} - -# {{{ not_enough_pdbs -def not_enough_pdbs(): - sys.stderr.write("You must provide TWO and only TWO pdb files\n") - usage() - sys.exit() -#}}} - -# {{{ FindSimilarCablamRegions -################################################################################ -# -# FindSimilarCablamRegions will align cablam measures. -# residues_1 and residues_2 are cablam_residues objects (found in this -# script) -# window_size is the size of the regions you want to align -# in_and_out; false means use ONLY pseudo CA in true means use in AND out -# threshold is the upper limit 'difference mean' that will be accepted when -# determining if two regions are similar. Please see RLab wiki for more -# info on how this works. -# -# NOTE: if threshold is zero then the object simple_aligned_regions will return -# a list that contains the one entry of aligned residue that had the -# smallest difference mean. -# -################################################################################ -class FindSimilarCablamRegions(object): - - def __init__(self, - residues_1, - residues_2, - window_size, - in_and_out = False, - threshold = None): - self.residues_1 = residues_1 - self.residues_2 = residues_2 - self.window_size = window_size - self.in_and_out = in_and_out - self.threshold = threshold - - # get simple_aligned_regions - self.simple_align_measures() - - - # {{{ get_measures - def get_measures(self, segment): - measures = [] - for r in segment : - if len(r.measures) == 0 : - # needed for cpputils - measures.append(None) - continue - if self.in_and_out : - measures.append(r.measures["CA_d_out"] + r.measures["CA_d_in"]) - else :measures.append(r.measures["CA_d_in"]) - return measures - # }}} - - # {{{ simple_align_measures - def simple_align_measures(self): - similar_regions = [] - smallest_mean = 5000 - self.simple_aligned_regions = [] - # for each continuous segment in res 1 compare to each segment it seg 2 - # and find similar regions - for seg_1 in self.residues_1.segments : - measures_1 = self.get_measures(seg_1) - for seg_2 in self.residues_2.segments : - measures_2 = self.get_measures(seg_2) - # sr = find_similar_regions(measures_1,measures_2) - similar_regions = cpputils.get_similar_regions(measures_1, - measures_2, - self.threshold, - self.window_size) - - # similar_regions is a list of objects (made in cpp) having these - # attributes: i_1, i_2, mean, window_length. i_1 and i_2 are the stating - # indecies in measures_1 and measures_2, respectively, which align. By - # extention, i_1 and i_2 are also the stating idecies in seg_ and seg_2. - # get similar regions residues (cablam linked_residue objects) - for sr in similar_regions : - is_1 = [i for i in range(sr.i_1, sr.i_1 + sr.window_length)] - is_2 = [i for i in range(sr.i_2, sr.i_2 + sr.window_length)] - ar = [] - for i in range(len(is_1)): - ar.append((seg_1[is_1[i]], seg_2[is_2[i]])) - if self.threshold > 0 : - self.simple_aligned_regions.append(group_args(aligned_residues = ar, - mean = sr.mean)) - else: - if sr.mean < smallest_mean : - smallest_mean = sr.mean - self.simple_aligned_regions = [group_args(aligned_residues = ar, - mean = sr.mean)] - # }}} - - - -# }}} - -# {{{ AlignCablamMeasures -class AlignCablamMeasures(object): - - # {{{ __init__ - def __init__(self, hierarchy_1, - hierarchy_2, - pdb_name_1, - pdb_name_2, - window_size, - threshold): - - # get cablam residues - residues_1 = cablam_residues(hierarchy = hierarchy_1, pdbid = pdb_name_1) - residues_2 = cablam_residues(hierarchy = hierarchy_2, pdbid = pdb_name_2) - - #find similar fragments in the two pdb - self.simple_similar_region_obj = \ - FindSimilarCablamRegions(residues_1 = residues_1, - residues_2 = residues_2, - window_size = window_size, - in_and_out = False, - threshold = threshold) - - self.hierarchy_1 = hierarchy_1 - self.hierarchy_2 = hierarchy_2 - # Now we have a list of similar regions (cablam_aln_obj.simple_aligned_regions). - # These regions can overlap. For such cases we want to find extended regions. - # i.e. we have two lists (this is simplified) [1,2,3,4,5] and [3,4,5,6,7], - # we can then assume that [1,2,3,4,5,6,7] is a good alignment too. - # get aligned_residues - self.condense_simple_aligned_regions() - # }}} - - # {{{ print_simple_similar_regions - def print_simple_similar_regions(self, log): - for i,ar in enumerate(self.simple_similar_region_obj.simple_aligned_regions): - print("similar fragment %i" % i, file=log) - print("mean : %.03f, diff : %i" % (ar.mean,abs(ar.aligned_residues[0][0].resnum-ar.aligned_residues[0][1].resnum)), file=log) - for t in ar.aligned_residues : - print(t[0].id_to_str(),t[1].id_to_str(), file=log) - # }}} - - # {{{ condense_simple_aligned_regions - def condense_simple_aligned_regions(self): - - self.aligned_regions = [] - sar = self.simple_similar_region_obj.simple_aligned_regions - current_region = sar[0] - # iterate through simple_aligned_regions - i = 0 - break_one, break_two = False,False - new_region = None#sar[0][:] - while 1 : - if new_region == None : new_region = sar[i].aligned_residues[:] - i += 1 - if i == len(sar): - if new_region not in self.aligned_regions : - self.aligned_regions.append(new_region) - break - next_region = sar[i].aligned_residues[:] - - # if the first pair in next_region is not in new_region no others will be - if next_region[0] not in new_region : - if new_region not in self.aligned_regions : - self.aligned_regions.append(new_region) - # check to see if any regions already in self.aligned_regions align - new_region = None - for region in self.aligned_regions : - if next_region[0] in region : - for pair in next_region : - if pair in region : continue - else : region.append(pair) - new_region = region - break - if new_region == None : new_region = next_region - else : - for pair in next_region : - if pair in new_region : continue - else : new_region.append(pair) - - # }}} - - # {{{ print_aligned_regions - def print_aligned_regions(self,log): - for i,region in enumerate(self.aligned_regions): - self.print_region(region,i,log) - # }}} - - # {{{ print_region - def print_region(self, region, title, log): - print("*"*77, file=log) - print("**** %s" % title, file=log) - print("diff : %i" % abs(region[0][0].resnum-region[0][1].resnum), file=log) - for t in region : - print(t[0].id_to_str(), t[1].id_to_str(), file=log) - # }}} - -# }}} - -# {{{ get_chain_selection -def get_chain_selection(hierarchy, chain): - s = "chain %s" % chain.upper() - sel = hierarchy.atom_selection_cache().selection(string = s) - return hierarchy.select(sel) -# }}} - -# {{{ cablam_align_wrapper -# wrapper for AlignCablamMeasures -def cablam_align_wrapper(pdb_1, pdb_2, window_size, threshold, - chain_1 = None, chain_2 = None, - pdb_name_1 = None, pdb_name_2 = None): - - # {{{ get pdb hierarchies - if pdb_name_1 == None : pdb_name_1 = os.path.basename(pdb_1)[:-4] - if pdb_name_2 == None : pdb_name_2 = os.path.basename(pdb_2)[:-4] - pdb_io = pdb.input(pdb_1) - hierarchy_1 = pdb_io.construct_hierarchy() - pdb_io = pdb.input(pdb_2) - hierarchy_2 = pdb_io.construct_hierarchy() - - # get chain selections - if chain_1 != None : hierarchy_1 = get_chain_selection(hierarchy_1,chain_1) - if chain_2 != None : hierarchy_2 = get_chain_selection(hierarchy_2,chain_2) - # }}} - - return AlignCablamMeasures(hierarchy_1 = hierarchy_1, - hierarchy_2 = hierarchy_2, - pdb_name_1 = pdb_name_1, - pdb_name_2 = pdb_name_2, - window_size = window_size, - threshold = threshold) - -# }}} - -# {{{ run -def run(args): - - #{{{ phil parsing - #----------------------------------------------------------------------------- - interpreter = libtbx.phil.command_line.argument_interpreter(master_phil=master_phil) - sources = [] - pdbs = [] - for arg in args: - if os.path.isfile(arg): #Handles loose filenames - input_file = file_reader.any_file(arg) - if (input_file.file_type == "pdb"): - # sources.append(interpreter.process(arg="pdb_infile=\"%s\"" % arg)) - pdbs.append(arg) - elif (input_file.file_type == "phil"): - sources.append(input_file.file_object) - else: #Handles arguments with xxx=yyy formatting - arg_phil = interpreter.process(arg=arg) - sources.append(arg_phil) - work_phil = master_phil.fetch(sources=sources) - work_params = work_phil.extract() - params = work_params.cablam_align - if work_params.cablam_align.pdb_infile_1 == None and work_params.cablam_align.pdb_infile_2 == None : - if len(pdbs) != 2 : not_enough_pdbs() - else : - work_params.cablam_align.pdb_infile_1 = pdbs[0] - work_params.cablam_align.pdb_infile_2 = pdbs[1] - params = work_params.cablam_align - - if params.help: - usage() - sys.exit() - #----------------------------------------------------------------------------- - #}}} end phil parsing - - acm = cablam_align_wrapper(pdb_1 = params.pdb_infile_1, - pdb_2 = params.pdb_infile_2, - window_size = params.window_size, - threshold = params.threshold, - chain_1 = params.chain_1, - chain_2 = params.chain_2) - - acm.print_aligned_regions(sys.stdout) - -#}}} - -# {{{ "__main__" -#------------------------------------------------------------------------------- -if __name__ == "__main__": - run(sys.argv[1:]) -#------------------------------------------------------------------------------- -#}}} diff --git a/mmtbx/cablam/cablam_align_utils.h b/mmtbx/cablam/cablam_align_utils.h deleted file mode 100644 index b2dd2ef4d9..0000000000 --- a/mmtbx/cablam/cablam_align_utils.h +++ /dev/null @@ -1,106 +0,0 @@ -// (jEdit options) :folding=indent:collapseFolds=1: -#include -#include -#include -#include -#include -#include -#include - - -namespace mmtbx { namespace cablam { - - struct index_mean - { - // This is just a little object to hold inecies for simialr regions - // found by get_similar_regions, which returns a list of these objects - index_mean( - int i_1, - int i_2, - double mean, - int window_length) - : - i_1(i_1), - i_2(i_2), - mean(mean), - window_length(window_length) - {} - int i_1; - int i_2; - double mean; - int window_length; - }; - - boost::python::list get_similar_regions( - boost::python::list list_1, - boost::python::list list_2, - double threshold, - int window_len) - { - // This function returns a a list of index_mean objects, - // if im = index_mean object then im has three attributes, im.i_1 is the - // index of list 1, im.i_2 is the index of list 2, and im.mean is the mean - // of the diff_list as explained below. - // Only diff_lists with their mean <= threshold will be returned in the - // return list. IF threshold !> 0 then returns the fragments with the - // lowest diff_list mean - boost::python::ssize_t i_1, i_2, i_w; - boost::python::list return_list; - double smallest_mean = 9999; - // - for(i_1=0;i_1 value(list_1[i_w]); - if( !value.check() ) none_in = true; - window.append(list_1[i_w]); - } - if(none_in) continue; - // slide the window across list_2 and check for similarities - for(i_2=0;i_2 value(list_2[i_w]); - if( !value.check() ) none_in = true; - target.append(list_2[i_w]); - } - if(none_in) continue; - assert(boost::python::len(target) == boost::python::len(window)); - // get diff list - boost::python::list diff_list; - for(i_w=0;i_w(window[i_w]); - double v2 = boost::python::extract(target[i_w]); - double diff = std::abs(v1 - v2); - if(diff > 180) diff = 360 - diff; - diff_list.append(diff); - } - assert(boost::python::len(window) == boost::python::len(diff_list)); - // get the average of the diff_list - double sum = 0; - for(int i_d=0;i_d(diff_list[i_d]); - double average; - average = sum/boost::python::len(diff_list); - if((threshold > 0) && (average <= threshold)) - return_list.append(index_mean(i_1, i_2, average, window_len)); - else if(threshold <= 0) { - // return_list.append(index_mean(i_1, i_2, average)); - // return_list.append(average); - if(average < smallest_mean) { - smallest_mean = average; - if(boost::python::len(return_list) > 0) return_list.pop(0); - return_list.append(index_mean(i_1, i_2, average, window_len)); - } - } - } - } - return return_list; - } - - -}} diff --git a/mmtbx/cablam/cablam_fingerprints.py b/mmtbx/cablam/cablam_fingerprints.py deleted file mode 100644 index 94abf68260..0000000000 --- a/mmtbx/cablam/cablam_fingerprints.py +++ /dev/null @@ -1,398 +0,0 @@ -from __future__ import absolute_import, division, print_function -# (jEdit options) :folding=explicit:collapseFolds=1: -# -#cablam_fingerprints -#Author: Christopher Williams, contact christopher.j.williams@duke.edu -# -#cablam_fingerprints holds objects and methods related to the identification of -# secondary structure and other motifs in protein structures. -#It is called primarily by cablam_training, but may become called elsewhere as -# motifs move into validation and correction routines -# -#2013-09-17: Initial Upload -#2014-02-07: -#Found motifs now stored as objects rather than as labels in the linked_residue -# objects. This allows more robust and varied handling downstream (eg output), -# but required substantial rewrite of the functions in this file. - -import os, sys -import libtbx.load_env -from libtbx import easy_pickle -from libtbx.utils import Sorry - -#Checks return either "False" or a debug string describing the reason for failure. -# This will let me get debug with maybe-cleaner code - -#{{{ class objects -#------------------------------------------------------------------------------- -class motif(object): - def __init__(self, - motif_name="",residue_names={},superpose_order = {}): - self.motif_name = motif_name - self.residue_names = residue_names #labels for printing keyed by indices for residues in the motif - self.superpose_order = superpose_order # format as {'a':['CA','O'],'b':['CA']} - self.residues = [] - - def add_residue(self, allowed_resname=[], banned_resname=[],cis_or_trans=None, - sequence_move=None, bond_move='', - end_of_motif=False, index=''): - new_residue = residue(allowed_resname, banned_resname, cis_or_trans, - sequence_move, bond_move, end_of_motif, index) - self.residues.append(new_residue) - return new_residue - -#------------------------------------------------------------------------------- -class residue(object): - def check_resname(self,residue): - if residue.resname in reslist: - return True - - def add_bond(self, required=True,banned=False,allow_bifurcated=False, - src_atom='', trg_index=''): - new_bond = bond(required, banned, allow_bifurcated, src_atom, trg_index) - self.bonds.append(new_bond) - return new_bond - - def __init__(self, - allowed_resname=[], banned_resname=[], cis_or_trans=None, - sequence_move=None, bond_move='', - end_of_motif=False, index=''): - - self.allowed_resname=allowed_resname - self.banned_resname=banned_resname - self.cis_or_trans=cis_or_trans - self.sequence_move=sequence_move - self.bond_move=bond_move - self.end_of_motif=end_of_motif - self.index=index - self.bonds=[] - -#------------------------------------------------------------------------------- -class bond(object): - def add_target_atom(self, atomname=None, anyatom=False, seqdist=None, - anyseqdist=False): - self.trg_atoms.append(target_atom(atomname, anyatom, seqdist, anyseqdist)) - - def __init__(self, - required=True, banned=False, allow_bifurcated=False, - src_atom='', trg_index=''): - - self.required=required - self.banned=banned - self.allow_bifurcated=allow_bifurcated - self.src_atom=src_atom - self.trg_atoms=[] #what actually goes here? list of target_atom objects - self.trg_index=trg_index - -#------------------------------------------------------------------------------- -class target_atom(object): - def __init__(self, - atomname = None, anyatom=False, seqdist=None, anyseqdist=False): - self.atomname = atomname - self.anyatom = anyatom - self.seqdist = seqdist - self.anyseqdist = anyseqdist -#}}} - -#{{{ found motif object -class motif_instance(object): - def is_complete(self): - if len(self.residues) == self.needed_length: return True - else: return False - - #a check before printing that all residues have all values needed to print - def has_all_measures(self, kinorder): - for residue in self.residues.values(): - for needed_measure in kinorder: - if needed_measure not in residue.measures: - return False - return True - - def add_to_instance(self, index, residue): - self.residues[index] = residue - - def build_superposition(self, motif): - superpose_list = [] - for index in motif.superpose_order: - atoms = motif.superpose_order[index] - residue = self.residues[index] - chain = residue.chain - resseq = str(residue.resnum) - for atom in atoms: - #altloc " " breaks down on alternates, probably do care about this. - if len(residue.alts) > 1 and residue.firstalt(atom): - atom_order = "(chain "+chain+" and resseq "+resseq+" and name "+atom+ " and altloc "+residue.firstalt(atom)+")" - else: - atom_order = "(chain "+chain+" and resseq "+resseq+" and name "+atom+")" - superpose_list.append(atom_order) - self.superpose_thus = "\"" + " or ".join(superpose_list) + "\"" - - def __init__(self, fingerprint): - self.needed_length = len(fingerprint.residues) - self.residues = {} - self.names = fingerprint.residue_names - self.superpose_thus = "" -#}}} - -#{{{ check protein -#------------------------------------------------------------------------------- -def check_protein(protein, motif_name_list): - #debug = True - debug = False - found_motifs = {} - motif_list = fetch_fingerprints(motif_name_list) - # TODO: is protein a dict, if so put a hint comment - reslist = list(protein.keys()) - reslist.sort() - for motif in motif_list: - found_motifs[motif.motif_name] = [] - #for resid in protein: - for resid in reslist: - residue = protein[resid] - for motif in motif_list: - candidate = motif_instance(motif) - failed = check_for_motif(motif,residue,candidate)#returns either False or debug info - if failed: - candidate = None - if debug==True: print(failed) - continue - else: - #print candidate.needed_length, candidate.residues, len(candidate.residues) - if candidate.is_complete(): - #print candidate.needed_length, candidate.residues, len(candidate.residues) -#1b16FH_A.pdb -#finished motif wide_helix_turn -#7 {'': } 1 - candidate.build_superposition(motif) - found_motifs[motif.motif_name].append(candidate) - return found_motifs -#------------------------------------------------------------------------------- -#}}} - -#{{{ check for motif function -#------------------------------------------------------------------------------- -def check_for_motif(motif, active_residue, candidate): - motif_index = 0 - motif_complete = False - while not motif_complete: - motif_residue = motif.residues[motif_index] - if not active_residue: - return "Missing residue for index " + motif_residue.index - fail_residue_checks = fail_residue_check(motif_residue, active_residue) - if fail_residue_checks: - return fail_residue_checks - for bond in motif_residue.bonds: - fail_forbidden_bond_checks = fail_forbidden_bond_check(bond, active_residue) - if fail_forbidden_bond_checks: - return fail_forbidden_bond_checks - fail_required_bond_checks = fail_required_bond_check(bond, active_residue, candidate) - if fail_required_bond_checks: - return fail_required_bond_checks - fail_index_checks = fail_index_match(motif_residue.index, active_residue, candidate) - if fail_index_checks: - return fail_index_checks - candidate.add_to_instance(motif_residue.index, active_residue) - if motif_residue.end_of_motif: - motif_complete = True - else: - motif_index += 1 - active_residue = do_move(motif_residue, active_residue, candidate) - sys.stderr.write("finished motif "+ motif.motif_name+"\n") - return 0 -#------------------------------------------------------------------------------- -#}}} - -#{{{ do move (keep) -def do_move(check_residue, active_residue, motif_in_progress): - new_res = active_residue - if check_residue.sequence_move: - move_dist = check_residue.sequence_move - if move_dist > 0: - while move_dist > 0: - if not new_res.nextres: - return None - else: - new_res = new_res.nextres - move_dist -= 1 - elif move_dist < 0: - while move_dist < 0: - if not new_res.prevres: - return None - else: - new_res = new_res.prevres - move_dist += 1 - return new_res - elif check_residue.bond_move: - move_index = check_residue.bond_move - try: - return motif_in_progress.residues[move_index] - except KeyError: - sys.stderr.write('\nTried to move to a residue not yet indexed at index \"'+check_residue.bond_move+'\"\n') - sys.stderr.write('Please check fingerprint definition. Exiting . . .\n') - sys.exit() - else: - sys.stderr.write('\nNo move specified for residue indexed as\"'+check_residue.index+'\"\n') - sys.stderr.write('Please check fingerprint definition. Exiting . . .\n') - sys.exit() -#}}} - -#{{{ fail residue check -#------------------------------------------------------------------------------- -def fail_residue_check(motif_residue, active_residue): - resname = active_residue.id_with_resname()[0:3] - if motif_residue.allowed_resname: - if resname.upper() not in motif_residue.allowed_resname: - return active_residue.id_with_resname() + " resname not in allowed list" - if motif_residue.banned_resname: - if resname.upper() in motif_residue.banned_resname: - return active_residue.id_with_resname() + " resname in banned list" - if motif_residue.cis_or_trans: - fail_cis_or_trans_check = fail_cis_or_trans_check(motif_residue.cis_or_trans, active_residue) - if fail_cis_or_trans_check: - return fail_cis_or_trans_check - return 0 - -###minor function for fail residue check -def fail_cis_or_trans_check(cis_or_trans, active_residue): - if 'omega' not in active_residue.measures: - return active_residue.id_with_resname() + " has no value for omega dihedral" - omega = active_residue.measures['omega'] - if cis_or_trans=='trans' and not (omega >= 120 or omega <= -120): - return active_residue.id_with_resname() + " omega dihedral is not trans" - if cis_or_trans=='cis' and not (omega >= -60 and omega <= 60): - return active_residue.id_with_resname() + " omega dihedral is not cis" - return 0 -#------------------------------------------------------------------------------- -#}}} - -#{{{ fail required bond check function -#------------------------------------------------------------------------------- -def fail_required_bond_check(check_bond, active_residue, candidate): - if check_bond.banned or not check_bond.required: - return 0 - if not active_residue.probe: - return active_residue.id_with_resname() + " Missing all probe information" - if check_bond.src_atom not in active_residue.probe: - return active_residue.id_with_resname() + " Missing probe information for src_atom "+check_bond.src_atom - if len(active_residue.probe[check_bond.src_atom]) > 1 and not check_bond.allow_bifurcated: - return active_residue.id_with_resname() + " Disallowed bifucated bond at src_atom "+check_bond.src_atom - #----------------------------------------------------------------------------- - for src_atom in active_residue.probe: - if src_atom == check_bond.src_atom: - for bond_name in active_residue.probe[src_atom]:#ie for each bond partner - observed_bond = active_residue.probe[src_atom][bond_name] - for trg_atom in check_bond.trg_atoms: - if (trg_atom.anyatom or trg_atom.atomname == observed_bond.atom) and (trg_atom.anyseqdist or trg_atom.seqdist == observed_bond.seqdist): - index = check_bond.trg_index - trg_residue = observed_bond.residue - fail_index_matching = fail_index_match(index, trg_residue, candidate) - if fail_index_matching: - return fail_index_matching - else: - if index: candidate.add_to_instance(index, trg_residue) - return 0 - return active_residue.id_with_resname() + " No matching bond for " + check_bond.src_atom -#------------------------------------------------------------------------------- -#}}} - -#{{{ fail forbidden bond check -#------------------------------------------------------------------------------- -#At the moment, does not check for generic bans against indexed residues w/o -# specific sequence relationship -def fail_forbidden_bond_check(check_bond, active_residue): - if not check_bond.banned: - return 0 - # TODO: is active residie.prob a dict ? if so put a hint comment - if check_bond.src_atom not in active_residue.probe.keys(): - return 0 - src_atom = check_bond.src_atom - for bond_name in active_residue.probe[src_atom]: - observed_bond = active_residue.probe[src_atom][bond_name] - for trg_atom in check_bond.trg_atoms: - if ((trg_atom.anyatom)or(trg_atom.atomname == observed_bond.atom)) and ((trg_atom.anyseqdist)or(trg_atom.seqdist == observed_bond.seqdist)): - return active_residue.id_with_resname() + " Residue has forbidden bond" - else: pass - else: pass - else: return 0 -#------------------------------------------------------------------------------- -#}}} - -#{{{ bonding info storage reference -#------------------------------------------------------------------------------- -#Reference for how bond info gets stored into residue.probe -# recordkey = trgResidue.id_with_resname() + trgAtomname -# record = group_args(residue = trgResidue, -# atom = trgAtomname, -# dotcount = dotcount, -# mingap = mingap, -# seqdist = srcResidue.seq_dist(trgResidue)) -# srcResidue.probe[srcAtomname][recordkey] = record -#for srcatom in residue.probe: - # for record in residue.probe[srcatom]: - # check_bond = residue.probe[srcatom][record] -#------------------------------------------------------------------------------- -#}}} - -#{{{ fail index match -#------------------------------------------------------------------------------- -def fail_index_match(index, residue, motif_in_progress): - if not index: return 0 #i.e. the dafault index of '' - for observed_index in motif_in_progress.residues.keys(): - if index == observed_index and motif_in_progress.residues[index] != residue: - return "Index "+index+" already identified, does not match new residue "+residue.id_with_resname() - if motif_in_progress.residues[observed_index] == residue and observed_index != index: - return "Residue "+residue.id_with_resname()+" already indexed, does not match new index "+index - else: return 0 -#------------------------------------------------------------------------------- -#}}} - -#{{{ make pickle function -#This .pickles and stores a motif fingerprint object -#------------------------------------------------------------------------------- -def make_pickle(motif): - pwd = os.getcwd() - fingerprints_dir = libtbx.env.find_in_repositories( - "cctbx_project/mmtbx/cablam/fingerprints") - if fingerprints_dir is None: - raise Sorry("""\ -Problem locating cablam fingerprints dir""") - os.chdir(fingerprints_dir) - filename = motif.motif_name + ".pickle" - print("Converting", motif.motif_name, "to pickle file . . .") - easy_pickle.dump(file_name=filename,obj=motif) - print(". . . Done") - os.chdir(pwd) -#------------------------------------------------------------------------------- -#}}} - -#{{{ fetch fingerprints function -#Given a list of string which match .pickled motif names, returns a list of -# unpickled motif fingerprint objects -#------------------------------------------------------------------------------- -def fetch_fingerprints(motif_list): - fingerprint_list = [] - for motif in motif_list: - path = "cctbx_project/mmtbx/cablam/fingerprints/"+motif+".pickle" - picklefile = libtbx.env.find_in_repositories( - relative_path=path, test=os.path.isfile) - if picklefile is None: - raise Sorry("\nCould not find a needed pickle file for motif "+motif+" in chem_data.\nExiting.\n") - else: - fingerprint_list.append(easy_pickle.load(file_name=picklefile)) - return fingerprint_list -#------------------------------------------------------------------------------- -#}}} - -#{{{ get all labels function -#Returns a list of all the residues labels for all the motifs in a list -#May be needed for some output functions -#------------------------------------------------------------------------------- -def get_all_labels(motif_name_list): - motifs = fetch_fingerprints(motif_name_list) - label_list = [] - for motif in motifs: - for residue_name in motif.residue_names.values(): - label_list.append(residue_name) - return label_list -#------------------------------------------------------------------------------- -#}}} diff --git a/mmtbx/cablam/cablam_math.py b/mmtbx/cablam/cablam_math.py deleted file mode 100644 index a210a9bd94..0000000000 --- a/mmtbx/cablam/cablam_math.py +++ /dev/null @@ -1,374 +0,0 @@ -from __future__ import absolute_import, division, print_function -# (jEdit options) :folding=explicit:collapseFolds=1: -#The cablam_math module provides functions to calculate the backbone measures -# used by the cablam system. -#The linked_residue.measures = {} dictionary will be empty unless functions from -# this module are called. -#One general note is that many of these calculations require atoms from many -# different residues. The first part of most functions deals with finding the -# necessary atoms. If a required atom (or residue) is missing, the function -# will not add an entry to the measures dictionary in the current residue. An -# attempt to access the missing value will give a KeyError exception that must -# be caught. -#Yes, the residue numbering is idiosyncratic: res2 is usually the res of -# interest because 2 is its zero-indexed position in the CA pseudodihedral -# calculations that define cablam-space. -#2012-03-02, This module has taken over the functions formerly in -# cjw_vectormath.py Also, results of these calculations will be stored in -# linked_residue.measures instead of .results -#2012-09-03, The old cablam_measures() is now ca_measures(), and a new -# cablam_measures() function has been written to return CA_d_in, CA_d_out, and -# CO_d_in, in correspondence with the current version of cablam_validate -# contours -#2012-12-04: The previous calcualtion of omega was "exiting" At least for -# cis-peptide purposes, the "entering" omega is the relevant one. Correct -# entering omega is now calculated. -#2013-02-01: cablam_measures() now also calculates CA_a, the CA virtual angle. -# This is used for the ca contours added to cablam_validate. - -#Note that geometry measures currently default to 'first_alt' in all cases for -# all atoms retrieved by getatomxyz() -#Plan to develop special-use program to deal with alternates more completely. - -import math -from cctbx import geometry_restraints - -#{{{ vector math functions, formerly in cjw_vectormath.py -#------------------------------------------------------------------------------- - -#Returns a vector connecting point p1 to point p2 -def vectorize(p1, p2): - v = [ p2[0]-p1[0] , p2[1]-p1[1] , p2[2]-p1[2] ] - return v - -#Returns the scalar length of a vector -def veclen(v): - return math.sqrt( v[0]**2 + v[1]**2 + v[2]**2 ) - -#Dot product of two vectors -def dot(v1, v2): - return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2] - -#Cross product of two vectors -def cross(v1, v2): - x = v1[1]*v2[2] - v1[2]*v2[1] - y = v1[2]*v2[0] - v1[0]*v2[2] - z = v1[0]*v2[1] - v1[1]*v2[0] - return [x,y,z] - -#Finds the line from a1 to a2, drops a perpendicular to it from b1, and returns -# the point of intersection. -def perptersect(a1, a2, b1): - #Find the slope of line A in each direction, A is in vector notation - A = [a2[0]-a1[0], a2[1]-a1[1], a2[2]-a1[2]] - #Solve the parametric equations (dot of perpendiculars=0). . . - t = (A[0]*(b1[0]-a1[0]) + A[1]*(b1[1]-a1[1]) + A[2]*(b1[2]-a1[2])) / ((A[0]**2)+(A[1]**2)+(A[2]**2)) - # . . . and use the result to find the new point b2 on the line - b2 = [a1[0]+A[0]*t, a1[1]+A[1]*t, a1[2]+A[2]*t] - return b2 - -#Returns the perpendicular distance from point b1 to the a1-a2 line -def perpdist(a1, a2, b1): - b2 = perptersect(a1, a2, b1) - distance = veclen(vectorize(b1,b2)) - return distance -#------------------------------------------------------------------------------- -#}}} - -#{{{ CA pseudodihedral/angle calculator -#Adds 'CA_d_in','CA_d_out', 'CA_a_in', 'CA_a', and 'CA_a_out' to -# residue.measures={} for each residue in protein where protein is a dictionary -# of cablam_res classes -#------------------------------------------------------------------------------- -def CApseudos(protein, dodihedrals = True, doangles = True): - for resid2 in protein: - res2 = protein[resid2] #residue n - gotall = False - if res2.prevres: - res1 = res2.prevres # n-1 - if res1.prevres: - res0 = res1.prevres # n-2 - if res2.nextres: - res3 = res2.nextres # n+1 - if res3.nextres: - res4 = res3.nextres # n+2 - gotall = True - if not gotall: - continue - - CA_0 = res0.getatomxyz('CA') - CA_1 = res1.getatomxyz('CA') - CA_2 = res2.getatomxyz('CA') - CA_3 = res3.getatomxyz('CA') - CA_4 = res4.getatomxyz('CA') - if None in [CA_0,CA_1,CA_2,CA_3,CA_4]: - continue - - if dodihedrals: - d_in = geometry_restraints.dihedral(sites=[CA_0,CA_1,CA_2,CA_3], - angle_ideal=-40, weight=1) - d_out = geometry_restraints.dihedral(sites=[CA_1,CA_2,CA_3,CA_4], - angle_ideal=-40, weight=1) - - res2.measures['CA_d_in'] = d_in.angle_model - res2.measures['CA_d_out'] = d_out.angle_model - - if doangles: - a_in = geometry_restraints.angle(sites=[CA_0,CA_1,CA_2], - angle_ideal=120, weight=1) - a = geometry_restraints.angle(sites=[CA_1,CA_2,CA_3], - angle_ideal=120, weight=1) - a_out = geometry_restraints.angle(sites=[CA_2,CA_3,CA_4], - angle_ideal=120, weight=1) - res2.measures['CA_a_in'] = a_in.angle_model - res2.measures['CA_a'] = a.angle_model - res2.measures['CA_a_out'] = a_out.angle_model -#------------------------------------------------------------------------------- -#}}} - -#{{{ CO pseudodihedral calculator -#Adds 'CO_d_in' and 'CA_O_out' dihedrals to residue.measures={} for each residue -# in protein where protein is a dictionary of cablam_res classes -#------------------------------------------------------------------------------- -def COpseudodihedrals(protein): - for resid2 in protein: - res2 = protein[resid2] #residue n - gotall = False - if res2.prevres: - res1 = res2.prevres # n-1 - if res2.nextres: - res3 = res2.nextres # n+1 - if res3.nextres: - res4 = res3.nextres # n+2 - gotall = True - if not gotall: - continue - - CA_1, O_1 = res1.getatomxyz('CA'),res1.getatomxyz('O') - CA_2, O_2 = res2.getatomxyz('CA'),res2.getatomxyz('O') - CA_3, O_3 = res3.getatomxyz('CA'),res3.getatomxyz('O') - CA_4 = res4.getatomxyz('CA') - if None in [CA_1,CA_2,CA_3,CA_4,O_1,O_2,O_3]: - continue - - pseudoC_1 = perptersect(CA_1,CA_2,O_1) - pseudoC_2 = perptersect(CA_2,CA_3,O_2) - pseudoC_3 = perptersect(CA_3,CA_4,O_3) - - d_in = geometry_restraints.dihedral(sites=[O_1, pseudoC_1, pseudoC_2, O_2], - angle_ideal=-40, weight=1) - d_out = geometry_restraints.dihedral(sites=[O_2, pseudoC_2, pseudoC_3, O_3], - angle_ideal=-40, weight=1) - - res2.measures['CO_d_in'] = d_in.angle_model - res2.measures['CO_d_out'] = d_out.angle_model -#------------------------------------------------------------------------------- -#}}} - -#{{{ cablam measures calculator (CA_d_in, CA_d_out, CO_d_in, CA_a) -#Adds 'CA_d_in', 'CA_d_out', 'CA_d_in', and 'CA_a' only to residue.measures={} -# for each residue in portein where protein is a dictionary of cablem_res -# classes. -#This function is a condensed version of CApseudos() and COpsedudodihedrals() -# above, returning only the measures currently in use by cablam annotation. -#------------------------------------------------------------------------------- -def cablam_measures(protein): - for resid2 in protein: - res2 = protein[resid2] #residue n - gotall = False - if res2.prevres: - res1 = res2.prevres # n-1 - if res1.prevres: - res0 = res1.prevres # n-2 - if res2.nextres: - res3 = res2.nextres # n+1 - if res3.nextres: - res4 = res3.nextres # n+2 - gotall = True - if not gotall: - continue - - CA_0 = res0.getatomxyz('CA') - CA_1, O_1 = res1.getatomxyz('CA'),res1.getatomxyz('O') - CA_2, O_2 = res2.getatomxyz('CA'),res2.getatomxyz('O') - CA_3 = res3.getatomxyz('CA') - CA_4 = res4.getatomxyz('CA') - if None in [CA_0,CA_1,CA_2,CA_3,CA_4,O_1,O_2]: - #getatomxyz returns either an xyz list (tuple?) or None - continue - - d_in = geometry_restraints.dihedral(sites=[CA_0,CA_1,CA_2,CA_3], - angle_ideal=-40, weight=1) - d_out = geometry_restraints.dihedral(sites=[CA_1,CA_2,CA_3,CA_4], - angle_ideal=-40, weight=1) - pseudoC_1 = perptersect(CA_1,CA_2,O_1) - pseudoC_2 = perptersect(CA_2,CA_3,O_2) - co_in = geometry_restraints.dihedral(sites=[O_1, pseudoC_1, pseudoC_2, O_2], - angle_ideal=-40, weight=1) - ca_a = geometry_restraints.angle(sites=[CA_1,CA_2,CA_3], - angle_ideal=120, weight=1) - - res2.measures['CA_d_in'] = d_in.angle_model - res2.measures['CA_d_out'] = d_out.angle_model - res2.measures['CO_d_in'] = co_in.angle_model - res2.measures['CA_a'] = ca_a.angle_model -#------------------------------------------------------------------------------- -#}}} - -#{{{ ca measures calculator (CA_d_in, CA_d_out, CA_a) -#Adds 'CA_d_in', 'CA_d_out', and 'CA_a' only to residue.measures={} for each -# residue in portein where protein is a dictionary of cablem_res classes. -#This function is a condensed version of CApseudos() above. -#------------------------------------------------------------------------------- -def ca_measures(protein): - for resid2 in protein: - res2 = protein[resid2] #residue n - gotall = False - if res2.prevres: - res1 = res2.prevres # n-1 - if res1.prevres: - res0 = res1.prevres # n-2 - if res2.nextres: - res3 = res2.nextres # n+1 - if res3.nextres: - res4 = res3.nextres # n+2 - gotall = True - if not gotall: - continue - - CA_0 = res0.getatomxyz('CA') - CA_1 = res1.getatomxyz('CA') - CA_2 = res2.getatomxyz('CA') - CA_3 = res3.getatomxyz('CA') - CA_4 = res4.getatomxyz('CA') - if None in [CA_0,CA_1,CA_2,CA_3,CA_4]: - #getatomxyz returns either an xyz list (tuple?) or None - continue - - d_in = geometry_restraints.dihedral(sites=[CA_0,CA_1,CA_2,CA_3], - angle_ideal=-40, weight=1) - d_out = geometry_restraints.dihedral(sites=[CA_1,CA_2,CA_3,CA_4], - angle_ideal=-40, weight=1) - a = geometry_restraints.angle(sites=[CA_1,CA_2,CA_3], - angle_ideal=120, weight=1) - - res2.measures['CA_d_in'] = d_in.angle_model - res2.measures['CA_d_out'] = d_out.angle_model - res2.measures['CA_a'] = a.angle_model -#------------------------------------------------------------------------------- -#}}} - -#{{{ Ramachandran calculator -#Adds 'phi' 'psi' 'phi+1' and 'psi-1' dehedrals to residue.measures={} for each -# residue in protein where protein is a dictionary of cablam_res classes -#------------------------------------------------------------------------------- -def phipsi(protein): - for resid2 in protein: - res2 = protein[resid2] #residue n - gotall = False - if res2.prevres: - res1 = res2.prevres # n-1 - if res2.nextres: - res3 = res2.nextres # n+1 - gotall = True - if not gotall: - continue - - CO_1 = res1.getatomxyz('C') - N_2 = res2.getatomxyz('N') - CA_2,C_2 = res2.getatomxyz('CA'),res2.getatomxyz('C') - N_3 = res3.getatomxyz('N') - if None in [CO_1,N_2,CA_2,C_2,N_3]: - continue - - phi = geometry_restraints.dihedral(sites=[CO_1, N_2, CA_2, C_2], - angle_ideal=-40, weight=1) - psi = geometry_restraints.dihedral(sites=[N_2, CA_2, C_2, N_3], - angle_ideal=-40, weight=1) - - res2.measures['phi'] = phi.angle_model - res2.measures['psi'] = psi.angle_model - - res1.measures['phi+1'] = phi.angle_model - res3.measures['psi-1'] = psi.angle_model -#------------------------------------------------------------------------------- -#}}} - -#{{{ tau angle calculator -#Adds 'tau' angle (N-CA-C) to residue.measures={} for each residue in protein -# where protein is a dictionary of cablam_res classes -#------------------------------------------------------------------------------- -def taucalc(protein): - for resid2 in protein: - res2 = protein[resid2] - - N = res2.getatomxyz('N') - CA = res2.getatomxyz('CA') - C = res2.getatomxyz('C') - if None in [N,CA,C]: - continue - - tau = geometry_restraints.angle(sites=[N,CA,C], angle_ideal=120, weight=1) - res2.measures['tau'] = tau.angle_model -#------------------------------------------------------------------------------- -#}}} - -#{{{ omega angle calculator -#Adds 'omega' dihedral (peptide plane dihedral) to residue.measures={} for each -# residue in protein where protein is a dictionary of cablam_res classes -#------------------------------------------------------------------------------- -def omegacalc(protein): - for resid2 in protein: - res2 = protein[resid2] - gotall = False - if res2.prevres: - res1 = res2.prevres #n+1 - gotall = True - if not gotall: - continue - - CA = res1.getatomxyz('CA') - C = res1.getatomxyz('C') - N_2 = res2.getatomxyz('N') - CA_2= res2.getatomxyz('CA') - if None in [CA, C, N_2, CA_2]: - #print res2.resnum, CA, C, N_2, CA_2 - continue - - omega = geometry_restraints.dihedral(sites=[CA,C,N_2,CA_2], - angle_ideal=-40, weight=1) - - res2.measures['omega'] = omega.angle_model -#------------------------------------------------------------------------------- - -#{{{ old omega angle calculator -#Old version that calculates the "exiting" version of omega (not suitable for -# IDing cis-peptides) May be removed entirely in the future. -#Adds 'omega' dihedral (peptide plane dihedral) to residue.measures={} for each -# residue in protein where protein is a dictionary of cablam_res classes -#------------------------------------------------------------------------------- -#def old_omegacalc(protein): -# for resid2 in protein: -# res2 = protein[resid2] -# gotall = False -# if res2.nextres: -# res3 = res2.nextres #n+1 -# gotall = True -# if not gotall: -# continue -# -# CA = res2.getatomxyz('CA') -# C = res2.getatomxyz('C') -# N_2 = res3.getatomxyz('N') -# CA_2= res3.getatomxyz('CA') -# if None in [CA, C, N_2, CA_2]: -# #print res2.resnum, CA, C, N_2, CA_2 -# continue -# -# omega = geometry_restraints.dihedral(sites=[CA,C,N_2,CA_2], -# angle_ideal=-40, weight=1) -# -# res2.measures['omega'] = omega.angle_model -#------------------------------------------------------------------------------- -#}}} -#}}} diff --git a/mmtbx/cablam/cablam_res.py b/mmtbx/cablam/cablam_res.py deleted file mode 100644 index 26c727c93d..0000000000 --- a/mmtbx/cablam/cablam_res.py +++ /dev/null @@ -1,326 +0,0 @@ -from __future__ import absolute_import, division, print_function -# (jEdit options) :folding=explicit:collapseFolds=1: -#This module contains the linked_residue class and the functions needed to build -# and access instances of it. -#2012-09-05: -# prunerestype() moved to this module from cablam_training -# linked_residue.id_with_resname() changed to return pdb-column-formatted ids -#2012-10-09: -# self.resid is now stored in each linked_residue object -#2013_02_01: Added a step in linked_residue.__init__() that flags HETATOMs and a -# step in construct_linked_residues() that skips adding them to the -# resdata/protein object. Will this be a problem for synthetic or other -# non-standard residues? -#2013-09-17: changed formatting for id_with_resname to rg.atom.pdb_label_columns -# Tried to add handling for HETATOMS in __init__. May or may not fully work. -#Next: added mp_id() to produce MolPribity-friendly resids - - -import sys -from mmtbx.cablam.cablam_math import veclen, vectorize - -#{{{ linked_residue class -#This class holds information on protein residues (as defined by residue_group -# in pdb.hierarchy). See the __init__ for details. It also maintains sequence -# relationships through a connectivity check and references "prevres" and -# "nextres" to the class instances of sequence-adjacent residues. The intent is -# to allow easy stepping forward and backward through the residue sequence. -#For example: self.resnum returns the current residue number, -# self.nextres.resnum returns the residue number of the next residue in -# sequence, if such a residue exists. This is not protected by a .get or -# anything, so you have to do your own error catching, usually of the form: -# if self.nextres: return self.nextres.resnum -#The class was designed for use with cablam, which requires forward and backward -# sequence awareness, but it could be used elsewhere. It contains a generic -# results={} dictionary usable by anyone willing to make unique keys for their -# data. -#It is recommended that all instances of this class for a protein be members of -# some iterable (I use a dictionary keyed with the cablam_key() function in -# this module). Do not rely on sequence connectivity alone (which breaks due to -# multiple chains or missing atoms) to let you find all residues. -#The class should deal with insertion codes well, since different icodes seem to -# be in different rg's in the hierarchy. -#The class does not deal with alts well, however, as an rg may contain several -# ag's. The firstalt() function provides some relief, but is really a dodge -# rather than a fix. I do not expect this to be a problem at low resolution -# (where alts are rare), but it does present a problem for high-res training. -#------------------------------------------------------------------------------- -class linked_residue(object): - - #Prints kinemage point-style output for a list of measures given in kinorder - def printtokin(self, kinorder, writeto=sys.stdout): - outline = ['{'+self.pdbid+' '+self.id_with_resname()+'}'] - for order in kinorder: - try: - outline.append(str(self.measures[order])) - except KeyError: - return - writeto.write(' '.join(outline)+'\n') - - #Prints comma-separated output for a list of measures given in kinorder - def printtocsv(self, kinorder, doconnections=False, writeto=sys.stdout): - outline = [self.id_with_resname()] - for order in kinorder: - try: - outline.append(str(self.measures[order])) - except KeyError: - outline.append('NULL') - if doconnections: - if self.prevres: outline.append(self.prevres.id_with_resname()) - else: outline.append('NULL') - if self.nextres: outline.append(self.nextres.id_with_resname()) - else: outline.append('NULL') - writeto.write(','.join(outline)+'\n') #note the ',' in the join here - - #id_to_string and id_with_resname return string concatenations of residue - # identifiers. The identifier order should be standard with other RLab - def id_to_str(self, sep=' '): - resid_string = sep.join( - [self.pdbid, self.model, self.chain, str(self.resnum), self.icode]) - return resid_string - - def id_with_resname(self): - # Formatted as: 'ALA A####I' - resid_string = self.rg.atoms()[0].pdb_label_columns()[5:] - return resid_string - - def mp_id(self): - #An id consistent with MolProbity 'cnit' ids - #Formatted as: ccnnnnilttt - # c: 2-char Chain ID, space for none - # n: sequence number, right justified, space padded - # i: insertion code, space for none - # l: alternate ID, space for none - # t: residue type (ALA, LYS, etc.), all caps left justified, space padded - #(Not sure about the 2-char Chain IDs just yet) - #(alternates are not going to be handled properly yet) - resid_string = self.id_with_resname() - resname = resid_string[0:3] - chain = resid_string[3:5] - resnum = resid_string[5:9] - ins = resid_string[9:10] - alt = self.firstalt("CA") - if alt is None or alt == '': - alt = " " - mpid_string = chain + resnum + ins + alt + resname - return mpid_string - - #Removes the references that sequence-adjacent linked_residue class instances - # have to this instance. Helps maintain correct sequence connectivity and may - # allow this instance to be removed from memory. - #Used in cablam_training.stripB() and cablam_training.prunerestype() - def removelinks(self): - if self.prevres: - self.prevres.nextres = None - if self.nextres: - self.nextres.prevres = None - - #Returns the first alt index in alts that has an atom of the requested name - # Removes some guesswork from atom lookup, but really just acrobatics around - # the problem of how to store and access alts usefully - def firstalt(self, atomname): - for alt in self.alts: - try: - if self.atomxyz[alt][atomname]: - return alt - else: - continue - except KeyError: - continue - else: - return None - - #simplified retrieval around firstalt for the common case of atom coords - def getatomxyz(self, atomname): - firstalt = self.firstalt(atomname) - try: - return self.atomxyz[firstalt][atomname] - except KeyError: - return None - - #There needs to be a CA-only consecutive check. Adding one is a high priority. - def consecutive(self, res1, res2): - if res1 and res2: #check against empties - try: - C = res1.atomxyz[res1.firstalt('C')]['C'] - N = res2.atomxyz[res2.firstalt('N')]['N'] - #firstalt returns None if it can't find an atom, - # and a key of None gives a KeyError here - except KeyError: - #if there aren't a C and an N, assume the two are not properly bonded - return False - bondlen = veclen(vectorize(C,N)) - if bondlen <= 2.0: - #2.0A is the peptide bond cutoff used by O for model building and - # potentially-fragmented chains. O's generous cutoff seemed appropriate - # since I expect to process in-progress models with this program - #RLab (probably) uses 1.4 +- 0.3, official textbook is about 1.33 - #O's Ca-Ca distance is 4.5A - return True - else: - return False - else: - return False - - def seq_dist(self, otherres): - ############################################ - # Returns distance in sequence with insertion codes accounted for. - # The return value is negative if res is N-terminal to this. - # The return value is positive if res is C-terminal to this. - # The return value is None if res couldn't be found due to chain break etc. - ############################################ - if self is otherres: - return 0 - if self.chain != otherres.chain:# or self.model != otherres.model: - return None - #guess which direction to look - # the "<=" and ">=" should let this look back or forward from within an - # insertion - if self.resnum <= otherres.resnum: - delta = 0 - cur = self - while cur != None: - delta += 1 - if cur.nextres is otherres: return delta - cur = cur.nextres - if self.resnum >= otherres.resnum: - delta = 0 - cur = self - while cur != None: - delta -= 1 - if cur.prevres is otherres: return delta - cur = cur.prevres - return None - - def __init__(self, - rg, prevres=None, pdbid='pdbid', modelid='', chainid='', - targetatoms=["CA","O","C","N"] - ): - - self.rg = rg #the source residue group is preserved for additional data and - #ease in transfering back to hierarchy mode - - self.pdbid = pdbid - self.model = modelid - self.chain = chainid - self.resnum = int(rg.resseq.strip()) - #self.resseq = rg.resid[:-1] - self.icode = rg.icode - self.resid = cablam_key(self.model, self.chain, self.resnum, self.icode) - self.hetero = False #marks whether this is a HETATOM - - #alts: 'alt' and 'resname' keyed by ag.altloc in the form of '','A','B' etc. - #atomxyz: xyz coords, indexed by ag.altloc, and atom.name within each alt - # e.g. atomxyz['']['CA'] returns the coordinates of a non-alt Calpha - #atomb: atomic b, indexed by ag.altloc, and atom.name within each alt - self.alts = {} - self.atomxyz = {} - self.atomb = {} - ### What about anisou? Not handled yet. - - #hierachy looping and data extraction - for ag in rg.atom_groups(): - #if not ag.is_protein(): Need sopmething like this that works - # self.is_protein=True - self.alts[ag.altloc] = {'alt':ag.altloc, 'resname':ag.resname} - self.atomxyz[ag.altloc] = {} - self.atomb[ag.altloc] = {} - for atom in ag.atoms(): - if atom.hetero and ag.resname.upper() != 'MSE': - self.hetero=True - for targetatom in targetatoms: - if atom.name.strip() == targetatom: - self.atomxyz[ag.altloc][targetatom] = atom.xyz - self.atomb[ag.altloc][targetatom] = atom.b - - #Note that a reference to the related residue is stored, not a dictionary - # key for the wrapper dictionary - #Someone clever may want to teach me how to use weakref() if the mutual - # references that result from this cause memory problems - if prevres and self.consecutive(prevres, self): - self.prevres = prevres #Connect this residue to previous - prevres.nextres = self #And the previous residue to this one - else: - self.prevres = None #Adjacency is handled in an outside function - self.nextres = None - - self.probe = {'O':{},'H':{}} #holder for hydrogen bonding, indexed by 'target' residue+atom, see cablam_training.add_probe_data() - self.probeH = [] - self.probeO = [] - - self.measures = {} #Holder for cablam-space geometric measures - self.motifs = {} #Holder for identified motifs from fingerprints/probetrain - self.results = {} #Generic holder for calcuated values of interest - -#------------------------------------------------------------------------------- -#}}} - -#{{{ prunerestype function -#Deletes all members of a given residue type from a dictionary of residues -#"Residue type" is determined from pdb.hierarchy's ag.resname, the upshot being -# that non-residues like "HOH" waters and het groups can also be pruned to -# improve performance if their three-letter codes are known. -#------------------------------------------------------------------------------- -def prunerestype(resdata, restype): - # TODO is resdata a dict ? put a hint - reslist = list(resdata.keys()) - for residue in reslist: - for alt in resdata[residue].alts: - if resdata[residue].alts[alt]['resname'].strip() == restype: - resdata[residue].removelinks() - trash = resdata.pop(residue) - break -#------------------------------------------------------------------------------- -#}}} - -#{{{ cablam_key function -#The "protein" or "resdata" dictionary returned by construct_linked_residues() -# below uses a particular key construction to access (and order) its contents -#This function provides that construction so that residues in resdata may be -# accessed from anywhere. The string returned is .sort()able -#------------------------------------------------------------------------------- -def cablam_key(modelid=None, chainid=None, resnum=None, icode=None): - if None not in [modelid, chainid, resnum, icode]: - resid_string = ' '.join([modelid, chainid, '%04i' % resnum, icode]) - #The bit of string formatting here ('%04i' % resnum) helps .sort() later by - # adding 0's to the left side of resnum until resnum is 4 characters long. - # May or may not be compatible with Hybrid36 or other numbering schemes. - return resid_string - else: - sys.stderr.write(""" -Missing value for cablam_res.cablam_key(pdbid, modelid, chainid, resnum, icode) -Please pass complete information - """) - sys.exit() -#------------------------------------------------------------------------------- -#}}} - -#{{{ construct_linked_residues function -#------------------------------------------------------------------------------- -#This function returns a dictionary of linked_residue objects with keys as -# defined by cablam_key() above. It is responsible for iterating over part of -# the hierarchy, but most of the work is done by the __init__() in the -# linked_residue class. -#targetatoms handling is likely to see some change as I add compatibility for -# CA-only mainchain traces. Currently "C" and "N" are necessary for the -# sequency adjacency check linked_residue.consecutive(), which checks for -# appropriate peptide bond length -#targetatoms is a list of strings that identify pdb atoms, e.g. "CA" or "CD1" -def construct_linked_residues( - hierarchy, targetatoms=["CA","O","C","N"], pdbid='pdbid' - ): - protein = {} - for model in hierarchy.models(): - for chain in model.chains(): - prevres = None - for rg in chain.residue_groups(): - residue = linked_residue( - rg, prevres=prevres, pdbid=pdbid, modelid=model.id, chainid=chain.id, - targetatoms=targetatoms) - resid_string = cablam_key(model.id, chain.id, residue.resnum, rg.icode) - if not residue.hetero: #automatically skip het atoms - protein[resid_string] = residue - prevres = residue #important update for determining connectivity - return protein -#------------------------------------------------------------------------------- -#}}} diff --git a/mmtbx/cablam/cablam_training.py b/mmtbx/cablam/cablam_training.py deleted file mode 100644 index 1c2db3eb24..0000000000 --- a/mmtbx/cablam/cablam_training.py +++ /dev/null @@ -1,1236 +0,0 @@ -from __future__ import absolute_import, division, print_function -# (jEdit options) :folding=explicit:collapseFolds=1: -#This module contains the training/exploration components of cablam -#It can be run stand-alone with many commandline options -#It is intended for use in determining contours, motif fingerprints, etc for -# the annotation portion -#It is probably not intended for direct use in phenix, but is included as a -# useful tool for understanding the cablam system -#The May 2012 update reflects a substantial change in method. from the previous -# version. DSSP has been abandoned in favor of directly assessing hydrogen -# bonding patterns determined by Probe. Hydrogen bonding pattern definitions -# are stored in fingerprints.py, but will likely be assembled into a separate -# library in the future. -#2012-09-05 cablam_training can now run probe if precomputed probe files are not -# provided. Argument parsing has been updated to libtbx.phil for phenix -# compatibility. cablam=True now yields CA_d_in, CA_d_out, and (instead of -# CA_a) CO_d_in. usage() help message added. -#2012-12-04: Added cis_or_trans argument for selecting cis or non-cis peptides -# during printing. Default returns all residues. -#2013-09-17: Major fingerprints rewrite to use new fingerprints objects/methods -# /storage. See cablam_fingerprints.py and the fingerprints dir. -# add_probe_data now stores full 4-character pdb-style atom names -# New output: probe_mode=sequence will print amino acid sequence for motif -#2014_02_07: Updates to probe output methods to match changes in -# cablam_fingerprints. Motifs without continuous sequence now supported for all -# probe outputs -#Next: iotbx.file_reader incorporated to control input -#To do: Collect cis-peptides for analysis. Are they identifiable in cablamspace? -# Add clash filtering. 0.4 is sufficient clash to cull, mc-mc are the important -# contacts, at least for base cablam - -import os, sys -from iotbx import pdb #contains the very useful hierarchy -from mmtbx.cablam import cablam_res #contains a data structure derived from -# hierarchy, but more suited to cablam's needs - specifically it can hold -# geometric and probe measures and can look forward and backward in sequence -from mmtbx.cablam import cablam_math #contains geometric measure calculators -#from mmtbx.cablam import fingerprints #contains motif definitions -from mmtbx.cablam import cablam_fingerprints -#import cablam_fingerprints -# Storage for motif definitions subject to change -from libtbx import easy_run -import libtbx.phil.command_line -from iotbx import file_reader -from libtbx import group_args - -#{{{ phil -#------------------------------------------------------------------------------- -master_phil = libtbx.phil.parse(""" -cablam_training { - file_or_dir = None - .type = path - .help = '''input pdb file or dir thereof''' - separate_files = False - .type = bool - .help = '''Generate a separate, auto-named output file for each input file''' - give_kin = False - .type = bool - .help = '''Print output to screen in .kin format (default is comma-separated .csv format)''' - give_connections = False - .type = bool - .help = '''Add prevres and nextres columns to .csv output''' - debug = False - .type = bool - .help = '''Adds some text printed to stderr for debugging esp. for fingerprints''' - - all_measures = False - .type = bool - .help = '''Does all measures''' - cad = False - .type = bool - .help = '''2 CA pseudo dihedrals''' - caa = False - .type = bool - .help = '''3 CA pseudo angles''' - cod = False - .type = bool - .help = '''2 CO pseudo dihedrals''' - rama = False - .type = bool - .help = '''2 Ramachandran dihedrals: phi, psi''' - exrama = False - .type = bool - .help = '''4 Ramachandran dihedrals: psi-1, phi, psi, phi+1''' - tau = False - .type = bool - .help = '''1 backbone angle: tau (defined by N-CA-C)''' - omega = False - .type = bool - .help = '''1 backbone dihedral: omega (defined by CA_1-C_1-N_2-CA_2)''' - cablam = False - .type = bool - .help = '''Shortcut for just cablam-relevant measures CA_d_in, CA_d_out, CO_in''' - - probe_motifs = None - .type = strings - .help = '''Activates hydrogen bonding analysis, probe=motif_name1,motif_name2,... use --listmotifs to list available fingerprints''' - probe_path = None - .type = path - .help = '''Stores path to dir of probed files, probe will be called for each file if this is not provided''' - probe_mode = *kin annote instance sequence superpose - .type = choice - .help = '''=kin for dotlist kins (default) =annote for ball on model, =instance for vectorlist kins''' - list_motifs = False - .type = bool - .help = '''print motifs/fingerprints available to screen''' - - b_max = None - .type = float - .help = '''Set a max b factor, residues containing a backbone atom with higher b will be pruned, recommended: -b=30''' - prune_alts = False - .type = bool - .help = '''Removes all residues with alternate conformations in relevant atoms''' - prune = None - .type = strings - .help = '''List of restypes to be pruned, separated by commas, no spaces eg PRO''' - skip_types = None - .type = strings - .help = '''List of restypes to be skipped during printing, separated by commas''' - include_types = None - .type = strings - .help = '''List of restypes to be printed, all others will be skipped''' - - cis_or_trans = *both cis trans - .type = choice - .help = '''selects whether cis-peptides, trans-peptides, or both will be returned''' - - fear = False - .type = bool - .help = '''turns on fear-to-tread analysis (this is temporary)''' - - help = False - .type = bool - .help = '''print help text to screen''' -} -""", process_includes=True) -#------------------------------------------------------------------------------- -#}}} - -#{{{ usage notes -#------------------------------------------------------------------------------- -def usage(): - sys.stderr.write(""" -phenix.cablam_training or cablam_training.py is a program intended for the - exploration of protein structure datasets, the annotation of motifs of - interest, and the training of reference datasets. It was used in the - construction of the reference contours used by cablam_validate. It contains a - number of features and modes and is intended primarily as a development tool - rather than a utility for typical users. However, anyone interested in - exploring protein backboen geometry may find something of use here. - --------------------------------------------------------------------------------- -file_or_dir=*path* - Path to a pdb file or dir of pdb files to operate on, the only argument that - doesn't need an explicit flag --------------------------------------------------------------------------------- - ------Basic Printing Options----------------------------------------------------- -separate_files=True/False - Generate a separate, auto-named output file in the current dir for each input - file, default output prints a single file to screen - -give_kin=True/False - Print output to screen in .kin format, may be combinded with separate_files, - default output prints comma-separated .csv format - -give_connections=True/False - If set to True, adds prevres and nextres columns to .csv output - -skip_types=restype1,restype2 -include_types=restype3,restype4 - Together, these control which residue types are printed to screen or file. - Default prints all residues. - Residue types and relationships given to skip_types are excluded from printing - If only include_types is used, only the listed restypes will be printed - If include_types and skip_types are both used, then the types given to - include_types will override those skipped by skip_types. - - List restypes by their 3-letter code and separated by commas withoug spaces, - e.g. GLY,PRO,ALA,TRP - Sequence relationships may be represented with underscores, e.g. _PRO is - pre-proline, and GLY__ (2 underscores) is post-post-glycine - - examples: - skip_types=PRO would print every residue except proline - include_types=PRO,GLY would print *only* glycines and prolines - skip_types=_PRO include_types=GLY would skip pre-prolines unless they were - also glycines - -cis_or_trans='cis' 'trans' 'both' - Selects printing for cis-peptides or trans-peptides exclusively. The default - is 'both' which will print all residues. cis is defined as -60 to +60 degrees - trans is defined as 120 to 180 and -120 to -180 degrees for the omega dihedral - Note that selecting 'cis' or 'trans' will also stop printing for any residue - for which omega cannot be calculated. --------------------------------------------------------------------------------- - ------Probe and Motif Search Options--------------------------------------------- -This is an alternate mode which searches for hydrogen bonding patterns defined - in fingerprints. - -probe_motifs=motif_name1,motif_name2 - This flag activates hydrogen bonding pattern analysis, which will not run - otherwise. The flag accepts a spaceless string of comma-separated motif names - to search for. Use list_motifs=True to get a list of available motifs. - -probe_path=*path* - cablam_training can use precomputed probe results to speed up runs on large - datasets. If a path to such prepared files is not provided, Reduce and Probe - will be run on each pdb file, which may be time-consuming. - - Running: - phenix.probe -u -condense -self -mc -NOVDWOUT -NOCLASHOUT MC filename.pdb > filename.probe - Should produce appropriately formatted and named files for this option - -probe_mode=kin/annote/instance/sequence - These are printing options for hydrogen bond pattern analysis, which overrides - the Basic Printing Options above. -Choose 1 of 3: -=kin returns automatically-named kinemage files, one for each unique member - residue in each motif. The kins are high-dimensional dotlists containing the - measures specified in the commandline (see below for options). This is the - default printing. -=annote returns an automatically-named kinemage file for each pdb file. These - kins are balllists that highlight the selected motifs of interest if appended - to existing kinemages of the structures. -=instance returns an automatically-named vectorlist kinemage file for each motif - of interest. Each kin is a high-dimensional vectorlist that shows the path of - a multi-residue motif through the measures specified in the commandline - (see below for options) -=sequence prints to screen the animo acid sequence of the motif of interest. - Does not behave with multiple motifs. Uses single-letter amino acid codes, if - a residue type is unrecognized, will print 'X' followed by the 3-letter code. - -list_motifs=True/False - Prints to screen a list of all the motifs/"fingerprints" currently available - for hydrogen bond pattern search --------------------------------------------------------------------------------- - ------Geometric Measures--------------------------------------------------------- -All of these default to False, and some output modes will not function unless at - least one of these options is turned on. When in doubt, cablam=True and/or - rama=True will provide relevant information. - -cad=True/False - For each residue, calculate the 2 C-alpha pseudo dihedrals - -caa=True/False - For each residue, calculate the 3 C-alpha pseudo angles - -cod=True/False - For each residue, calculate the 2 carbonyl oxygen pseudo dihedrals - -rama=True/False - For each residue, calculate Ramachandran dihedrals phi and psi - -exrama=True/False - For each residue, calculate Ramachandran dihedrals psi-1, phi, psi, phi+1 - -tau=True/False - For each residue, calculate backbone angle tau, defined by N-NA-C - -omega=True/False - For each residue, calculate backbone peptide dihedral, - defined by CA_1,C_1,N_2,CA_2 - -all_measures=True/False - For each residue, calculate all of the above measures (may be overkill) - -cablam=True/False - Recommended, but not default behavior. - For each residue calculate the measures most relevant to cablam analysis: - CA_d_in, CA_d_out, CO_in --------------------------------------------------------------------------------- - ------Quality Control Options---------------------------------------------------- -b_max=#.# - Set a max b factor value. Residues containing a backbone atom with higher b - will be pruned and excluded from all calculations. Note this may affect - neighboring residues. Strongly Recommenced: b_max=30.0 - -prune_alts=True/False - Prune and excludes from calculations all residues with alternate conformations - for backbone atoms. Note this may affect neighboring residues. Default is - prune_alts=False, which results in only the first alternate position for each - residue being reported on. - -prune=restype1,restype2 - Prune and exclude from calculations the selected list of residue types. Note - this may affect neighboring residues. Restypes should be given as 3-letter - codes, e.g. GLY,PRO, but this option does not yet support the sequence - relationship that skip_types= and include_types= do. --------------------------------------------------------------------------------- - ------Help Options--------------------------------------------------------------- -help=True/False - Displays this help message. - -list_motifs=True/False - Prints to screen a list of all the motifs/"fingerprints" currently available - for hydrogen bond pattern search - -debug=True/False - Activates print-to-stderr debugging notes for hydrogen bond pattern search. - This may be valuable when trying to define a new pattern correctly and with - proper format. --------------------------------------------------------------------------------- - -Examples: -phenix.cablam_training cad=True cod=True skip_types=GLY,PRO,_PRO,ILE,VAL b_max=30.0 kin=True file_or_dir=path/pdbfilename.pdb - -phenix.cablam_training cablam=True b_max=30.0 prune=GLY probe_motifs=parallel_beta,antiparallel_beta_cwc,antiparallel_beta_wcw probe_mode=kin probe_path=path/database/probefiles file_or_dir=path/database/pdbfiles - -""") -#------------------------------------------------------------------------------- -#}}} - -#{{{ stripB function -#Deletes all residues containing any atom of interest with atom.b > bmax from -# a dictionary of residues, so that the uncertainty in these atoms cannot -# contaminate later calculations. -#Important for training, not for annotation -#Will need to make distinction between main- and side-chain eventually -#------------------------------------------------------------------------------- -def stripB(resdata, bmax): - reslist = list(resdata.keys()) - for resid in reslist: - deleted = False - for alt in resdata[resid].alts: - if deleted: - break - for atom in resdata[resid].atomb[alt]: - if resdata[resid].atomb[alt][atom] > bmax: - resdata[resid].removelinks() - trash = resdata.pop(resid) - deleted = True - break -#------------------------------------------------------------------------------- -#}}} - -#{{{ prune alts function -#Deletes all residues that have alternate conformations at one or more atoms -# from a dictionary of residues, so that uncertainty in these atoms or in their -# relations with other atoms in the structure cannot contaminate later -# calculations. -#A function for robustly handling and choosing among alternates is eventually -# forthcoming, but will be separate. -#------------------------------------------------------------------------------- -def prune_alts(resdata): - reslist = list(resdata.keys()) - for resid in reslist: - residue = resdata[resid] - if len(residue.alts) > 1: - residue.removelinks() - trash = resdata.pop(resid) -#------------------------------------------------------------------------------- -#}}} - -#{{{ skipcheck function -#Residue types can be skipped during output without pruning their influence -# entirely. This function handles checks for skipping, and returns boolean True -# if the residue should be skipped. -#Additional functionality is expected in this function over time. More complex -# sequence-sensitive selection is probable as I expand my training needs. -#As with pruning, important in training, less so in annotation. -#------------------------------------------------------------------------------- -def skipcheck(residue, skiplist, inclist): - if skiplist: #if there's anything to skip... - doskip = False #...the default state is include - elif inclist: #if there's nothing to skip but thing to include... - doskip = True #...the default state is skip - else: - return False #if skip and include are empty, return default 'include' - - for skip in skiplist: - currentres = residue - if skip.startswith('_') and skip.endswith('_'): - sys.stderr.write('\n\ - Invalid --skip flag argument: '+skip+ ' has\'_\' on both sides\n\n') - sys.exit() - - #Underscores are used in the commandline call to indicate position relative - # to a residue of interest. For example, '_PRO' refers to pre-proline, and - # 'GLY__' (two underscores) refers to post-post-glycine. These loops - # manage the underscores - while skip.startswith('_'): - if currentres.nextres: - currentres = currentres.nextres - skip = skip[1:] - else: - return True #cannot determine inclusion, so exclude - while skip.endswith('_'): - if currentres.prevres: - currentres = currentres.prevres - skip = skip[:-1] - else: - return True #cannot determine inclusion, so exclude - - if currentres.firstalt('CA') is not None: - resname = currentres.alts[currentres.firstalt('CA')]['resname'] - else: - return True - if resname == skip.upper(): - doskip = True - - for inc in inclist: - currentres = residue - if inc.startswith('_') and inc.endswith('_'): - sys.stderr.write('\n\ - Invalid --skip flag argument: '+inc+ ' has\'_\' on both sides\n\n') - sys.exit() - - while inc.startswith('_'): - if currentres.nextres: - currentres = currentres.nextres - inc = inc[1:] - else: - return True - while inc.endswith('_'): - if currentres.prevres: - currentres = currentres.prevres - inc = inc[:-1] - else: - return True #cannot determine inclusion, so exclude - - if currentres.firstalt('CA') is not None: - resname = currentres.alts[currentres.firstalt('CA')]['resname'] - else: - return True #cannot determine inclusion, so exclude - if resname == inc.upper(): - doskip = False - - return doskip -#------------------------------------------------------------------------------- -#}}} - -#{{{ fails cis check function -#Allows cis or trans peptides to be skipped during printing. Passing -# cis_or_trans='both' will print all residues. Residues without an omega value -# will be skipped unless cis_or_trans=='both'. -#As with pruning, important in training, less so in annotation. -#------------------------------------------------------------------------------- -def fails_cis_check(residue,cis_or_trans): - doskip = True - if cis_or_trans == 'both': - doskip = False - else: - if 'omega' not in residue.measures: - doskip = True - else: - omega = residue.measures['omega'] - if cis_or_trans == 'cis' and (omega >= -30 and omega <= 30): - doskip = False - if cis_or_trans == 'trans' and (omega >= 150 or omega <= -150): - doskip = False - - return doskip -#------------------------------------------------------------------------------- -#}}} - -#{{{ make probe data function -#If a precomputed probe file has not been provided, this function calls probe to -# generate appropriate data for use in add_probe_data() -#------------------------------------------------------------------------------- -def make_probe_data(hierarchy): - trim_command = "phenix.reduce -quiet -trim -" - build_command = "phenix.reduce -oh -his -flip -pen9999 -keep -allalt -" - #probe_command = "phenix.probe -u -condense -self -mc -NOVDWOUT -NOCLASHOUT MC -" - probe_command = "phenix.probe -u -condense -self -mc -NOVDWOUT -NOCLASHOUT ALL -" - - for i,m in enumerate(hierarchy.models()): - #multi-model compatibility coming soon? - #probe doesn't keep model data, so add_probe_data doesn't handle that - #so this just takes the first model - model = m - break - r = pdb.hierarchy.root() - mdc = model.detached_copy() - r.append_model(mdc) - - sys.stderr.write(' cleaning . . .\n') - clean_out = easy_run.fully_buffered(trim_command, stdin_lines=r.as_pdb_string()) - sys.stderr.write(' reducing . . .\n') - build_out = easy_run.fully_buffered(build_command, stdin_lines=clean_out.stdout_lines) - #print build_out.stdout_lines - input_str = '\n'.join(build_out.stdout_lines) - sys.stderr.write(' probing . . .\n') - probe_out = easy_run.fully_buffered(probe_command, stdin_lines=input_str) - #print '\n'.join(probe_out) - - #print '\n'.join(probe_out.stdout_lines) - return probe_out.stdout_lines -#------------------------------------------------------------------------------- -#}}} - -#{{{ add probe data function -#Adds mainchina-mainchain hydrogen bonding information from 'unformated' Probe -# output to a dictionary of residues. -#At the moment, reliant on precomputed .probe files, will gain run-time Probe -#May gain other contact relationship info, by mc-mc H-bonds are most important -#------------------------------------------------------------------------------- -def add_probe_data(resdata, open_probe_file): - #print open_probe_file - reskeys = list(resdata.keys()) - for line in open_probe_file: - #Probe Unformatted Output: - #name:pat:type:srcAtom:targAtom:min-gap:gap:spX:spY:spZ:spikeLen:score:stype:ttype:x:y:z:sBval:tBval - #for condensed output we have: - #name:pat:type:srcAtom:targAtom:*dotcount*:min-gap:gap:spX:spY:spZ:spikeLen:score:stype:ttype:x:y:z:sBval:tBval - ###'name' is set by the user on the command line - ###'pat' is one of 1->1, 1->2, or 2->1; where 1 is src and 2 is targ. - ###'type' is one of wc, cc, so, bo, hb (wide/close contact, small/bad overlap, h-bond). - ###'srcAtom' and 'targAtom' follow the pattern CNNNNITTT AAAAL, where C is chain, N is number, I is insertion code, T is residue type, A is atom name, and L is alternate conformation flag. - ###'*dotcount*' is condensed-output-only, and gives the number of dots in the contact - ###'min-gap' is the distance between atoms, minus their van der Waals radii; i.e., the distance of closest approach for their vdW surfaces. gap is the distance between vdW surfaces at the current dot. Negative values indicate overlap (clashes or H-bonds). - ###'x','y','z' is a point on the vdW surface; 'spX','spY','spZ' is tip of spike, if any (same as x,y,z for contacts) - ###'score' is "this dot's contribution to the [Probe] score" (scaled already? YES) - ###'stype' and 'ttype' are heavy-atom element name (C, N, O, etc) - - if not line.strip(): continue #averts an IndexError problem with empty lines - bnana = line.split(':') - - name = bnana[0] - pattern = bnana[1] - interactiontype = bnana[2] - if not interactiontype == 'hb': continue #skip non-h-bonds - - srcAtom = bnana[3] - srcChain = srcAtom[0:2].strip() - srcNum = int(srcAtom[2:6].strip()) - srcIns = srcAtom[6:7]#.strip() - srcResname = srcAtom[7:10].strip() - if srcResname == 'HOH': continue #skip waters - srcAtomname = srcAtom[11:15]#.strip() - srcAlt = srcAtom[15:16].strip() - - trgAtom = bnana[4] - #going to count dots per bond as a measure of strength instead - trgChain = trgAtom[0:2].strip() - trgNum = int(trgAtom[2:6].strip()) - trgNumStr = trgAtom[2:6] - trgIns = trgAtom[6:7]#.strip() - trgResname = trgAtom[7:10].strip() - #if trgResname == 'HOH': continue #skip waters - trgAtomname = trgAtom[11:15]#.strip() - trgAlt = trgAtom[15:16].strip() - - dotcount = bnana[5] - mingap = bnana[6] - - #new model for probe storage------------------------------------------------ - # If targ is not in resdata then it is likely a water or hetgroup. However, - # we want to have a record of the hb info. In this case 'residue' in 'record' - # will be an object with chain, resnum, resname, and icode. - # If src is not in resdata then we arn't interested. - src_key = ' '.join(['', srcChain, '%04i' % srcNum, srcIns]) - if src_key not in list(resdata.keys()) : continue - srcResidue = resdata[src_key] - targ_key = ' '.join(['', trgChain, '%04i' % trgNum, trgIns]) - if targ_key not in list(resdata.keys()): - continue - #trgResidue = group_args(chain = trgChain, - # resnum = trgNum, - # resname = trgResname, - # icode = trgIns) - #recordkey = trgResname +' '+trgChain + trgNumStr + trgIns + trgAtomname - else: - trgResidue = resdata[targ_key] - recordkey = trgResidue.id_with_resname() + trgAtomname - record = group_args(residue = trgResidue, - atom = trgAtomname, - dotcount = dotcount, - mingap = mingap, - seqdist = srcResidue.seq_dist(trgResidue)) - if srcAtomname not in list(srcResidue.probe.keys()): - srcResidue.probe[srcAtomname] = {} - #####srcResidue = resdata[' '.join(['', srcChain, '%04i' % srcNum, srcIns])] - #####trgResidue = resdata[' '.join(['', trgChain, '%04i' % trgNum, trgIns])] - #####recordkey = trgResidue.id_with_resname() + trgAtomname - #####record = group_args(residue=trgResidue, atom=trgAtomname, mingap=mingap, seqdist=srcResidue.seq_dist(trgResidue)) - ######print [trgResidue.id_with_resname(),trgAtomname,dotcount,srcResidue.seq_dist(trgResidue)] - #####if srcAtomname not in srcResidue.probe.keys(): - ##### srcResidue.probe[srcAtomname] = {} - #probe keys first by the current residue's atom, then by the target - # residue's id and atom, id+atom is unique enough to handle bifurcations - srcResidue.probe[srcAtomname][recordkey] = record - #end new model for probe storage-------------------------------------------- - #reference: resid_string = ' '.join([modelid,chainid,'%04i' % resnum,icode]) -#------------------------------------------------------------------------------- -#}}} - -#{{{ Output function collection -#A collection of headers, formatting, and printint functions used in output -#Default output is to stdout, but anything with a .write can be passed to the -# 'writeto=' argument of most functions. Functions that lack a 'writeto=' -# generate or find uniquely named files in the working dir for their output. -#Print methods called by these functions are generally from cablam_res.py -#------------------------------------------------------------------------------- - -#{{{ --- kin_frame --- -#------------------------------------------------------------------------------- -#kin_frame is a 3-dimensional frame for dihedral-space (-180 to 180) kinemages -def kin_frame(writeto=sys.stdout): - writeto.write(""" -@group {Rama Frame} -@dotlist {center} color= yellow off -0 0 0 -@vectorlist {frame_xy} color= yellow -P -180 -180 0 -180 -180 0 -180 180 0 --180 180 0 --180 -180 0 -@vectorlist {frame_xz} color= yellow -P -180 0 -180 -180 0 -180 -180 0 180 --180 0 180 --180 0 -180 -@vectorlist {frame_yz} color= yellow -P 0 -180 -180 -0 180 -180 -0 180 180 -0 -180 180 -0 -180 -180 - -""") -#------------------------------------------------------------------------------- -#}}} - -#{{{ --- CSV printing --- -#------------------------------------------------------------------------------- -#csv_header writes column names for the top of a .csv -#It starts with a comma for a reason, but I don't remember what it is -def csv_header(kinorder, doconnections=False, writeto=sys.stdout): - writeto.write(',pdb:model:chain:resnum:ins:resname,') - writeto.write(','.join(kinorder)) - if doconnections: - writeto.write(',prevres,nextres') - writeto.write('\n') - -#Prints residues in comma-separated format, suitable for contouring and other -# analysis -#This is currently the default behavior of cablam_training. This output format -# is used to generate percentile and probability contours for cablam_annote -# using the programs Silk and kin2Dcont/kin3Dcont from the Richardson Lab. -def csv_print(protein, kinorder, skiplist=[], inclist=[], - doconnections=False, cis_or_trans='both', writeto=sys.stdout): - reslist = list(protein.keys()) - reslist.sort() - for resid in reslist: - if skipcheck(protein[resid], skiplist, inclist): - pass - elif fails_cis_check(protein[resid],cis_or_trans): - pass - else: - protein[resid].printtocsv(kinorder, doconnections, writeto) -#------------------------------------------------------------------------------- -#}}} - -#{{{ --- Generic KIN printing --- -#------------------------------------------------------------------------------- -#kin_header writes the start of a kinemage file -#@text provides self-documentation of the commandline used to generate the .kin -#@dimensions and @dimminmax allow the .kin to handle high-dimensional data -def kin_header(kinorder,kinranges, writeto=sys.stdout): - if len(kinorder) == 0: - sys.stderr.write('\nNo geometric measures (e.g. rama=True) specified') - sys.stderr.write('\nExiting . . .\n') - sys.exit() - writeto.write('@text\n') - for arg in sys.argv: - writeto.write(arg + ' ') - writeto.write('\n\n@kinemage\n') - writeto.write('@dimensions {' + '} {'.join(kinorder)+'}\n') - writeto.write('@dimminmax '+ ' '.join(kinranges)+'\n') - kin_frame(writeto=writeto) - writeto.write('@group {points}\n') - writeto.write( - '@dotlist {points} nobutton dimension='+str(len(kinorder))+'\n') - -#prints residues in .kin format -#Uses skipcheck() to select residues to print (default includes all) -def kin_print(protein, kinorder, skiplist=[], inclist=[], cis_or_trans='both', - writeto=sys.stdout): - if len(kinorder) == 0: - sys.stderr.write('\nNo geometric measures (e.g. rama=True) specified') - sys.stderr.write('\nExiting . . .\n') - sys.exit() - reslist = list(protein.keys()) - reslist.sort() - for resid in reslist: - if skipcheck(protein[resid], skiplist, inclist): - pass - elif fails_cis_check(protein[resid],cis_or_trans): - pass - else: - protein[resid].printtokin(kinorder, writeto) -#------------------------------------------------------------------------------- -#}}} - -#{{{ --- Default PROBE printing --- -#------------------------------------------------------------------------------- -#Creates files and prints headers in them for generic probe output -#One .kin for each unique label in each motif. This can produce a lot of files. -def kin_print_probe_header(full_label_list, kinorder, kinranges): - if len(kinorder) == 0: - sys.stderr.write('\nNo geometric measures (e.g. rama=True) specified') - sys.stderr.write('\nExiting . . .\n') - sys.exit() - outfiles = {} - for label in full_label_list: - outfiles[label] = open(label+'.kin','a') - outfiles[label].write('\n@kinemage\n') - outfiles[label].write('@dimensions {' + '} {'.join(kinorder)+'}\n') - outfiles[label].write('@dimminmax '+ ' '.join(kinranges)+'\n') - kin_frame(writeto=outfiles[label]) - outfiles[label].write( - '@group {'+label+'} dominant animate\n@dotlist {'+label+ - '} dimension='+str(len(kinorder))+'\n') - return outfiles - -#For producing distributions of points in cablam space -#Generic output is one point (many dimensions) for each residue that matches a -# motif definition/fingerprint. -def kin_print_probe(motif_instances, kinorder, outfiles): - for motif_name in motif_instances: - for instance in motif_instances[motif_name]: - if not instance.has_all_measures(kinorder): - sys.stderr.write( - ' '+motif_name+' has incomplete measures, probably due to b_max\n') - continue - for index in instance.names: - residue = instance.residues[index] - name = instance.names[index] - residue.printtokin(kinorder, writeto=outfiles[name]) -#------------------------------------------------------------------------------- -#}}} - -#{{{ --- PROBE ANNOTE printing --- -#------------------------------------------------------------------------------- -#For annotating an existing .kin file with balls at CA's participating in -# motifs of interest. -#Produces one .kin per input file. -#Does not require a header as such. -def kin_print_probe_annote(motif_instances, writeto=sys.stdout): - for motif_name in motif_instances: - if motif_instances[motif_name]: - writeto.write('@group {'+motif_name+'}\n') - ref_instance = motif_instances[motif_name][0] - indices = list(ref_instance.residues.keys()) - indices.sort() - for index in indices: - writeto.write('@balllist {'+ref_instance.names[index]+'}\n') - for instance in motif_instances[motif_name]: - residue = instance.residues[index] - firstalt = residue.firstalt('CA') - CAxyz = residue.atomxyz[firstalt]['CA'] - pointid = residue.pdbid+' '+ residue.chain +' '+ str(residue.resnum)+' '+ instance.names[index] - writeto.write("{ "+pointid+" } "+str(CAxyz[0])+" "+str(CAxyz[1])+" "+str(CAxyz[2])+"\n") - -#{{{ -def old_kin_print_probe_annote(resdata, motif_list, writeto=sys.stdout): - reskeys = list(resdata.keys()) - reskeys.sort() - motifs = cablam_fingerprints.fetch_fingerprints(motif_list) - for motif in motifs: - writeto.write('@group {'+motif.motif_name+'}\n') - for label in motif.residue_names.values(): - writeto.write('@balllist {'+label+'}\n') - for resid in reskeys: - residue = resdata[resid] - if label in residue.motifs: - firstalt = residue.firstalt('CA') - #try: - CAxyz = residue.atomxyz[firstalt]['CA'] - pointid = residue.pdbid +' '+ residue.chain +' '+ str(residue.resnum)+' '+ label - writeto.write("{ "+pointid+" } "+str(CAxyz[0])+" "+str(CAxyz[1])+" "+str(CAxyz[2])+"\n") -#}}} -#------------------------------------------------------------------------------- -#}}} - -#{{{ --- PROBE BY INSTANCE printing --- -#------------------------------------------------------------------------------- -#Creates files and prints headers in them for instance output -#One .kin for each motif. This can produce several files. -def kin_print_by_instance_header(motif_list, kinorder, kinranges): - if len(kinorder) == 0: - sys.stderr.write('\nNo geometric measures (e.g. rama=True) specified') - sys.stderr.write('\nExiting . . .\n') - sys.exit() - outfiles = {} - motifs = cablam_fingerprints.fetch_fingerprints(motif_list) - for motif in motifs: - motif_name = motif.motif_name - outfiles[motif_name] = open(motif_name+'_instances.kin', 'w') - outfiles[motif_name].write('@text\n') - for arg in sys.argv: - outfiles[motif_name].write(arg + ' ') - outfiles[motif_name].write('\n@kinemage\n') - outfiles[motif_name].write('@dimensions {' + '} {'.join(kinorder)+'}\n') - outfiles[motif_name].write('@dimminmax '+ ' '.join(kinranges)+'\n') - kin_frame(writeto=outfiles[motif_name]) - return outfiles - -#What this means is: each instance of a full motif, printed as a vector list so -# the path through cablam space can be followed -def kin_print_by_instance(motif_instances, motif_list, kinorder, outfiles): - for motif_name in motif_instances: - for instance in motif_instances[motif_name]: - if not instance.has_all_measures(kinorder): - sys.stderr.write( - ' '+motif_name+' has incomplete measures, probably due to b_max\n') - continue - indices = list(instance.names.keys()) - indices.sort() - #print indices - residue = instance.residues[indices[0]] - outfiles[motif_name].write( - '@group {'+residue.pdbid.rstrip('.pdb')+' '+str(residue.resnum)+ - '} dominant animate\n@vectorlist {'+motif_name+ - '} dimension='+str(len(kinorder))+'\n') - for index in indices:#instance.names: - residue = instance.residues[index] - name = instance.names[index] - outline = ['{'+residue.id_with_resname()+'_'+name+'}'] - for order in kinorder: - outline.append(str(residue.measures[order])) - outfiles[motif_name].write(' '.join(outline)+'\n') - -#print a string of 1-char resnames for each motif instance, -# for use with WebLogo and the like. -def res_seq_by_instance(motif_instances): - #reshash contains the standard 3char to 1char mappings, followed by an ever- - # growing list of non-standard animo acids - reshash = {'GLY':'G','ALA':'A','VAL':'V','ILE':'I','LEU':'L','PHE':'F', - 'TRP':'W','MET':'M','GLU':'E','GLN':'Q','ASP':'D','ASN':'N','SER':'S', - 'THR':'T','TYR':'Y','HIS':'H','LYS':'K','PRO':'P','CYS':'C','ARG':'R', - 'MSE':'M','SME':'M','CSO':'C','OCS':'C','CSX':'C','CME':'C','YCM':'C', - 'MLY':'K'} - for motif_name in motif_instances: - for instance in motif_instances[motif_name]: - indices = list(instance.residues.keys()) - indices.sort() - seq_string = [] - for index in indices: - resname = instance.residues[index].id_with_resname()[0:3] - if resname in reshash: - code = reshash[resname] - else: - #non-standard amino acids not already handled can be found in the - # output by searching for 'X' - code = 'X'+resname - seq_string.append(code) - seq_string.append('\n') - sys.stdout.write(''.join(seq_string)) -#------------------------------------------------------------------------------- -#}}} - -#{{{ --- PROBE superposition --- -#------------------------------------------------------------------------------- -#First step: excise the relevant bits of each pdb file -def trim_motifs(motif_instances, filename, superpose_refs): - pwd = os.getcwd() - for motif_name in motif_instances: - if os.path.isdir(motif_name): pass - else: os.mkdir(motif_name) - os.chdir(motif_name) - - instance_num = 0 - for instance in motif_instances[motif_name]: - instance_num += 1 - outputfile = os.path.basename(filename) + "_" + str(instance_num) + ".pdb" - resnums = [] - for residue in instance.residues.values(): - resnum = str(residue.resnum) - resnums.append(resnum) - selection = "resseq "+ " or resseq ".join(resnums) - command = 'phenix.pdbtools stop_for_unknowns=False modify.keep=\"'+selection+'\" '+filename + " output.file_name=" + outputfile - #output.file_name=***** - #sys.stderr.write(command) - runthis = easy_run.fully_buffered(command) - if motif_name not in superpose_refs: - superpose_refs[motif_name] = {"motif":instance,"filename":outputfile} - else: - sys.stderr.write("trying to superpose\n") - ref = superpose_refs[motif_name] - #phenix.superpose_pdbs fixed.pdb moving.pdb selection_fixed="name CA" selection_moving="name CA" - command = "phenix.superpose_pdbs "+ ref["filename"] + " " + outputfile + " selection_default_fixed="+ref["motif"].superpose_thus +" selection_default_moving="+instance.superpose_thus + " output.file_name=" + outputfile - sys.stderr.write(command) - sys.stderr.write("\n") - runthis = easy_run.fully_buffered(command) - os.chdir(pwd) - return superpose_refs -#------------------------------------------------------------------------------- -#}}} - -#------------------------------------------------------------------------------- -#}}} - -#{{{ run -#The run function is currently rather messy. (Indeed, all of -# cablam_training is a bit messy, as it's really a development tool, not a -# general-use program.) Hopefully, everything needed for general use (structure -# annotation) has been packaged in other modules for easy access. Good luck. - -def run(args): - #{{{ phil parsing - #----------------------------------------------------------------------------- - interpreter = libtbx.phil.command_line.argument_interpreter(master_phil=master_phil) - sources = [] - for arg in args: - if os.path.isfile(arg): - input_file = file_reader.any_file(arg) - if (input_file.file_type == "pdb"): - sources.append(interpreter.process(arg="file_or_dir=\"%s\"" % arg)) - elif (input_file.file_type == "phil"): - sources.append(input_file.file_object) - elif os.path.isdir(arg): - sources.append(interpreter.process(arg="file_or_dir=\"%s\"" % arg)) - else: - arg_phil = interpreter.process(arg=arg) - sources.append(arg_phil) - work_phil = master_phil.fetch(sources=sources) - work_params = work_phil.extract() - params = work_params.cablam_training - #catch missing file or dir later? - #if not work_params.cablam_training.file_or_dir: - # usage() - # sys.exit() - params = work_params.cablam_training - #----------------------------------------------------------------------------- - #}}} end phil parsing - - if params.help: - usage() - sys.exit() - - if params.list_motifs: - sys.stdout.write('\n') - fileset = os.listdir(libtbx.env.find_in_repositories( - "cctbx_project/mmtbx/cablam/fingerprints")) - for filename in fileset: - if filename.endswith(".pickle"): - motifname = os.path.splitext(os.path.basename(filename))[0] - sys.stdout.write(motifname + '\n') - sys.exit() - - if not params.file_or_dir: - usage() - sys.exit() - if os.path.isdir(params.file_or_dir): - fileset = os.listdir(params.file_or_dir) - dirpath = params.file_or_dir - elif os.path.isfile(params.file_or_dir): - fileset = [params.file_or_dir] - dirpath = None - else: - sys.stderr.write("Could not identify valid target file or dir.\n") - usage() - sys.exit() - - #{{{ measurement selection - #This section manages the user's orders for calculations - #Note: The 'kin' in kinorder and kin ranges is a misnomer - #----------------------------------------------------------------------------- - if params.all_measures: - params.cad = True - params.caa = True - params.cod = True - params.exrama = True - params.tau = True - params.omega = True - - kinorder, kinranges = [],[] - if params.cad: - kinorder.append('CA_d_in'), kinranges.append('-180 180') - kinorder.append('CA_d_out'), kinranges.append('-180 180') - else: - pass - - if params.cod: - kinorder.append('CO_d_in'), kinranges.append('-180 180') - kinorder.append('CO_d_out'), kinranges.append('-180 180') - else: - pass - - if params.caa: - kinorder.append('CA_a_in'), kinranges.append('0 180') - kinorder.append('CA_a'), kinranges.append('0 180') - kinorder.append('CA_a_out'), kinranges.append('0 180') - else: - pass - - if params.cablam: - if 'CA_d_in' not in kinorder: - kinorder.append('CA_d_in'), kinranges.append('-180 180') - if 'CA_d_out' not in kinorder: - kinorder.append('CA_d_out'), kinranges.append('-180 180') - if 'CO_d_in' not in kinorder: - kinorder.append('CO_d_in'), kinranges.append('-180 180') - if 'CA_a' not in kinorder: - kinorder.append('CA_a'), kinranges.append('0, 180') - else: - pass - - if params.rama or params.exrama: - if params.exrama: - kinorder.append('psi-1'), kinranges.append('-180 180') - kinorder.append('phi'), kinranges.append('-180 180') - kinorder.append('psi'), kinranges.append('-180 180') - kinorder.append('phi+1'), kinranges.append('-180 180') - else: - kinorder.append('phi'), kinranges.append('-180 180') - kinorder.append('psi'), kinranges.append('-180 180') - else: - pass - - if params.tau: - kinorder.append('tau'), kinranges.append('0 180') - else: - pass - - if params.omega: - kinorder.append('omega'), kinranges.append('-180 180') - else: - pass - - #The following lines record the order and values for kinorder and kinranges - # for sake of reference - #kinorder = ['CA_d_in', 'CA_d_out','CO_d_in', 'CO_d_out', - # 'psi-1', 'phi', 'psi', 'phi+1', 'tau', 'omega'] - #kinranges = ['-180 180','-180 180','-180 180','-180 180', - # '-180 180','-180 180','-180 180','-180 180','0 180', '-180 180'] - #----------------------------------------------------------------------------- - #}}} - - #{{{ setup - #----------------------------------------------------------------------------- - targetatoms = ["CA","O","C","N"] - superpose_refs = {} - - outfiles = {} - if params.probe_motifs: - motif_list = params.probe_motifs[0].split(',') - if params.probe_path: - probefilelist = os.listdir(params.probe_path) - if params.probe_mode == 'kin':# or params.probe_mode == None: - outfiles = kin_print_probe_header(cablam_fingerprints.get_all_labels(motif_list),kinorder,kinranges) - elif params.probe_mode == 'instance': - outfiles = kin_print_by_instance_header(motif_list, kinorder, kinranges) - - prunelist = [] - if params.prune: - prunelist = params.prune[0].split(',') - prunelist = [res.upper() for res in prunelist] #Ha ha! List comprehension! - - skiplist = [] - inclist = [] - if params.skip_types: - skiplist = params.skip_types[0].split(',') - if params.include_types: - inclist = params.include_types[0].split(',') - - if params.separate_files: - pass - else: - if params.give_kin: - kin_header(kinorder,kinranges) - elif params.probe_motifs: - pass - else: - csv_header(kinorder,params.give_connections) - #----------------------------------------------------------------------------- - #}}} - - #{{{ get file, start loop - #----------------------------------------------------------------------------- - for filename in fileset: - #if not filename.endswith('.pdb'): - # continue - if dirpath: #must add the path if using the listed contents of a dir - filename = os.path.join(dirpath,filename) - else: - pass - - pdbid = os.path.basename(filename) - - if not os.path.isfile(filename): continue - pdb_in = file_reader.any_file(filename) - if pdb_in.file_type != "pdb": - sys.stderr.write(filename +" not id'd as readable file\n") - continue - sys.stderr.write(pdbid+'\n') - pdb_io = pdb.input(filename) - hierarchy = pdb_io.construct_hierarchy() - resdata = cablam_res.construct_linked_residues(hierarchy,targetatoms,pdbid) - if not resdata: #skips further processing of files not readable by hierarchy - continue - #----------------------------------------------------------------------------- - #}}} - - #{{{ preprocessing - #--------------------------------------------------------------------------- - cablam_res.prunerestype(resdata, 'HOH') - for restype in prunelist: - cablam_res.prunerestype(resdata, restype) - - if params.b_max: - stripB(resdata,params.b_max) - - if params.prune_alts: - prune_alts(resdata) - #--------------------------------------------------------------------------- - #}}} - - #{{{ calculation calls - #--------------------------------------------------------------------------- - if params.cad and params.caa: - cablam_math.CApseudos(resdata, dodihedrals = True, doangles = True) - elif params.cad: - cablam_math.CApseudos(resdata, dodihedrals = True, doangles = False) - elif params.caa: - cablam_math.CApseudos(resdata, dodihedrals = False, doangles = True) - else: #no CA-based calculations - pass - - if params.cod: - cablam_math.COpseudodihedrals(resdata) - else: - pass - - if params.rama or params.exrama: - cablam_math.phipsi(resdata) - else: - pass - - if params.tau: - cablam_math.taucalc(resdata) - else: - pass - - if params.omega or params.cis_or_trans != 'both': - cablam_math.omegacalc(resdata) - else: - pass - - if params.cablam: - cablam_math.cablam_measures(resdata) - else: - pass - #--------------------------------------------------------------------------- - #}}} - - #{{{ probe stuff - #--------------------------------------------------------------------------- - #need the run phenix.probe - if params.probe_motifs and params.probe_path: - probefilename = pdbid.rstrip('.pdb') + '.probe' - if probefilename in probefilelist: - probefilepath = os.path.join(params.probe_path,probefilename) - open_probe_file = open(probefilepath) - add_probe_data(resdata,open_probe_file) - open_probe_file.close() - else: - continue - elif params.probe_motifs: - add_probe_data(resdata,make_probe_data(hierarchy)) - - if params.probe_motifs: - found_motifs = cablam_fingerprints.check_protein(resdata, motif_list) - #found_motifs is a dictionary. The keys are motif names. - # The values are lists of cablam_fingerprints.motif_instance objects. - #--------------------------------------------------------------------------- - #}}} - - #{{{ output - #--------------------------------------------------------------------------- - #--probemode=kin for dotlist kins, this is the default - #--probemode=annote for balls drawn at CA positions on the model - #--probemode=instance for kins where each veclist is one instance of motif - if params.probe_motifs:# and args.probepath: - if params.probe_mode == 'kin':# or params.probe_mode == None: - kin_print_probe(found_motifs, kinorder, outfiles) - elif params.probe_mode == 'annote': - outfile = open(pdbid+'cablam_motifs.kin','w') - #kin_print_probe_annote(resdata, motif_list, writeto=outfile) - kin_print_probe_annote(found_motifs, writeto=outfile) - outfile.close() - elif params.probe_mode == 'instance': - #kin_print_by_instance(resdata, motif_list, kinorder, outfiles) - kin_print_by_instance(found_motifs, motif_list, kinorder, outfiles) - elif params.probe_mode == 'sequence': - res_seq_by_instance(found_motifs) - #res_seq_by_instance(resdata, motif_list) - elif params.probe_mode == 'superpose': - #trim_motifs(resdata, filename, motif_list) - superpose_refs = trim_motifs(found_motifs, filename,superpose_refs) - #superpose_motifs(motif_list) - else: - sys.stderr.write('\n\nUnrecognized probemode request\n\n') - sys.exit() - #add if args.kin once things basically work - outfile = sys.stdout - #need printer from probe version - #Not sure what the stray outfile=sys.stdout is doing here anymore - - #default printing, with no arguments, is to .csv, one line per residue - #--separatefiles writes a separate file for each input file to working dir - #--kin prints kinemage file, dotlist, one point per residue - #--doconnections adds connectivity information to csv output - else: - if params.give_kin: - if params.separate_files: - outfile = open(pdbid+'_cablam.kin','w') - kin_header(kinorder,kinranges,writeto=outfile) - kin_print(resdata, kinorder, skiplist, inclist, params.cis_or_trans, writeto=outfile) - outfile.close() - else: - kin_print(resdata,kinorder,skiplist,inclist,params.cis_or_trans) - else: - if params.separate_files: - outfile = open(pdbid+'_cablam.csv','w') - csv_header(kinorder,params.give_connections,writeto=outfile) - csv_print(resdata, kinorder, skiplist, inclist, params.give_connections,params.cis_or_trans, writeto=outfile) - outfile.close() - else: - csv_print(resdata,kinorder,skiplist,inclist,params.give_connections,params.cis_or_trans,) - - if outfiles: - for filename in outfiles: - outfiles[filename].close() - #--------------------------------------------------------------------------- - #}}} -#------------------------------------------------------------------------------- -#}}} diff --git a/mmtbx/cablam/cablam_validate.py b/mmtbx/cablam/cablam_validate.py deleted file mode 100644 index 31219eac7e..0000000000 --- a/mmtbx/cablam/cablam_validate.py +++ /dev/null @@ -1,1285 +0,0 @@ -from __future__ import absolute_import, division, print_function -# (jEdit options) :folding=explicit:collapseFolds=1: -# -#cablam_validate -#Author: Christopher Williams, contact christopher.j.williams@duke.edu -# -#cablam_validate is part of the cablam system for use in Phenix and cctbx, -# specifically, cablam_validate uses contour information derived from -# cablam_training to validate the backbone of protein models. -#cablam_validate accepts a protein model (as pdb or Phenix hierarchy) and -# calculates backbone geometry for each residue. The backbone geometry is -# compared against expected behavior and outliers are marked. Each outlier is -# then checked for similarity to regular secondary structure types. Numerical -# values are returned to indicate which seconday structure type each outlier is -# likely to be. -#cablam_validate can return this data as machine-friendly, comma-separated text. -# It can also print validation markup in kinemage format, which can be appended -# to an existing protein kinemage. -#Within the Phenix environment, cablam_validate can return a list of custom -# objects (see cablam_validation class below) which includes relevant data and -# a link to the hierarchy rg object for each outlier residue. Be sure to pass -# a hierarchy object into cablam_validate.run() if you want to access this -# functionality. -#Notes on contour levels: For the CA contours, the choice of 0.5% for "allowed" -# reflects a level around which a significant change occurs in the behavior of -# these contours (new minor clusters appear and bridges form between existing -# clusters) and which provideds good covereage of the secondary structure motif -# contours. The choice of 2% for "favored" is an intentional parallel to Rama -# validation. -# -#2012-08-03: Initial upload -# A "run whole protein to find probable structure" function might be nice -#2012-09-05: -# General cleanup. usage() help message and interpretation() guide to output. -# analyze_pdb() is now the easiest way to run the script from within phenix. -#2012-10-09: -# The "outliers" object returned by analyze_pdb is now a dict instead of a list -# The keys are the same as those used by cablam_res. cablam_measures now -# handles all the calculations setup() needs. -#2013-02-01: -# Added oneline output. Supports dir of files, as well as single files. Added -# checks for CA-only contours. Added find_partial_sec_struc and -# find_whole_sec_struc to piece individual residue assignments together into -# complete secondary structure elements. Added multicrit kinemage printing. -#2013-09-17: -# Added support for threeten helices throughout. -#2014-02-07: -# Added test validation for cis vs tran proline. -# Added stand-alone output for HELIX/SHEET records. -#2014-03-07: cleaned up commandline control for outputs, now all "output=" -#Next: iotbx.file_reader incorporated to control input, cleaned up oneline output -#Next: give_text now in MolProbity format (colons and cnit ids) - -import os, sys -import libtbx.phil.command_line #argument parsing -from iotbx import pdb #contains hierarchy data structure -from iotbx import file_reader -from mmtbx.cablam import cablam_res #contains a data structure derived from -# hierarchy, but more suited to cablam's needs - specifically it can hold -# geometric and probe measures and can look forward and backward in sequence -from mmtbx.cablam import cablam_math #contains geometric measure calculators -from mmtbx.rotamer.n_dim_table import NDimTable #handles contours -from libtbx import easy_pickle #NDimTables are stored as pickle files -from libtbx import easy_run -import libtbx.load_env - -#{{{ phil -#------------------------------------------------------------------------------- -master_phil = libtbx.phil.parse(""" -cablam_validate { - pdb_infile = None - .type = path - .help = '''input PDB file or dirpath''' - output = *text kin ca_kin full_kin markup_no_ribbons points records records_plus_pdb oneline - .type = choice - .help = '''choose output type, - =text for comma-separated outlier summary - =kin print markup kinemage to screen - =ca_kin print CA geo markup kinemage to screen - =full_kin open in King a multi-crit-type kinemage with markup - =markup_no_ribbons print allowed, outlier, and ca geom outlier markup kin - =points print cablam-space points to sys.stdout, in kinemage dotlist format - =records print HELIX and SHEET-style records based on CaBLAM analysis - =records_plus_pdb print HELIX and SHHET-style records as part of a pdb file - =oneline print one-line validation to sys.stdout: percent of cablam outliers - ''' - outlier_cutoff = 0.05 - .type = float - .help = '''sets the contour level for detecting outliers, e.g. outlier_cutoff=0.01 for accepting the top 99%, defaults to 0.05''' - check_prolines = False - .type = bool - .help = '''test of a function to differentiate cis vs trans prolines''' - help = False - .type = bool - .help = '''help and data interpretation messages''' -} -""", process_includes=True) -#------------------------------------------------------------------------------- -#}}} - -#{{{ classes: cablam_validation, motif_guess, and motif_chunk -#------------------------------------------------------------------------------- -#This object holds information on one residue for purposes of cablam_validate -#It's mostly just a package for data passing and access -class cablam_validation(object): - def __init__(self, residue=None,outlier_level=None,ca_geom_outlier_level=None): - self.residue = residue #cablam_res.linked_residue object - self.outlier_level = outlier_level #percentile level in "peptide_expectations" contours - self.ca_geom_outlier_level = ca_geom_outlier_level - self.loose_alpha = None #percentile level in motif contour - self.regular_alpha= None #percentile level in motif contour - self.loose_beta = None #percentile level in motif contour - self.regular_beta = None #percentile level in motif contour - self.loose_threeten = None - self.regular_threeten = None - self.suggestion = "" - if self.residue: - self.rg = self.residue.rg #rg object from a source hierarchy - else: - self.rg = None - -#Class for holding percentile contour level values in residue object -class motif_value(object): - def __init__(self): - self.loose_alpha = None - self.regular_alpha = None - self.loose_beta = None - self.regular_beta = None - self.loose_threeten = None - self.regular_threeten = None - -class motif_guess(object): - def __init__(self): - self.loose_alpha = False - self.regular_alpha = False - self.loose_beta = False - self.regular_beta = False - self.loose_threeten = False - self.regular_threeten = False - -class motif_chunk(object): - def print_record(self,writeto=sys.stdout): - if self.motif_type == 'helix': - self.print_helix_record(writeto=writeto) - elif self.motif_type == 'threeten': - self.print_threeten_record(writeto=writeto) - elif self.motif_type == 'sheet': - self.print_sheet_record(writeto=writeto) - else: - sys.stderr.write( - '\ntried to print a record that was not \'helix\' or \'sheet\'\n') - sys.exit() - - def print_helix_record(self,helix_num=1,writeto=sys.stdout): - motif_start_id = self.motif_start.id_with_resname() - motif_end_id = self.motif_end.id_with_resname() - motif_len = self.motif_end.resnum - self.motif_start.resnum + 1 - if motif_len >= 3: - #Note: the following code makes me hate HELIX record formatting - writeto.write('HELIX '+ '%3i' %helix_num +' '+ '%3i' %helix_num +' '+ - motif_start_id[:5]+' '+motif_start_id[5:]+' '+ motif_end_id[:5] +' '+ - motif_end_id[5:] +' 1 '+'%5i'%motif_len+ - '\n') - - def print_threeten_record(self,helix_num=1,writeto=sys.stdout): - motif_start_id = self.motif_start.id_with_resname() - motif_end_id = self.motif_end.id_with_resname() - motif_len = self.motif_end.resnum - self.motif_start.resnum + 1 - if motif_len >= 1: - #Note: the following code makes me hate HELIX record formatting - writeto.write('HELIX '+ '%3i' %helix_num +' '+ '%3i' %helix_num +' '+ - motif_start_id[:5]+' '+motif_start_id[5:]+' '+ motif_end_id[:5] +' '+ - motif_end_id[5:] +' 5 '+'%5i'%motif_len+ - '\n') - - def print_sheet_record(self,sheet_id='U',strand_num=1,strand_count=1, - strand_sense=0,writeto=sys.stdout): - motif_start_id = self.motif_start.id_with_resname() - motif_end_id = self.motif_end.id_with_resname() - writeto.write('SHEET '+'%3i' %strand_num +' '+'%3s'%sheet_id + - '%2i'%strand_count +' '+ motif_start_id+' '+motif_end_id + - '%2i'%strand_sense+'\n') - - def __init__(self): - self.motif_start = None #will hold residue object - self.motif_end = None #will hold residue object - self.motif_type = None #'helix' or 'sheet' for the moment -#------------------------------------------------------------------------------- -#}}} - -#{{{ usage -#------------------------------------------------------------------------------- -def usage(): - sys.stderr.write(""" -phenix.cablam_validate file.pdb [options ...] - -Options: - - pdb_infile=filename input PDB file - some output formats support a dir of files in this - field - outlier_cutoff=0.05 sets the contour level for detecting outliers, - e.g. outlier_cutoff=0.01 for accepting the top 99%, - defaults to 0.05 - output= - kin : prints markup kinemage for a single outlier - cutoff to screen - text : prints machine-readable columnated and comma- - separated data to screen - (default output) - points : prints cablam-space points to screen, - in kinemage dotlist format - records : prints HELIX and SHEET-style records to - screen, based on CaBLAM secondary structure - analysis - records_plus_pdb : prints HELIX and SHEET records and - the associated pdb file to screen - ca_kin : prints a kinemage with ca-contour outliers - marked - full_kin : opens a phenix.king window with multicrit - style markup for the submitted structure. Also - saves a .pdb with HELIX and SHEET records and a - .kin with other markup to working dir - markup_no_ribbons : prints 'allowed', 'outlier', and - 'ca geom outlier' kinemage markup to screen - oneline : prints oneline-style output to screen. - Supports printing for multiple files - - help=False prints this usage text, plus notes on data - interpretation to screen - -Example: - -phenix.cablam_validate file.pdb output=full_kin --------------------------------------------------------------------------------- -""") -#------------------------------------------------------------------------------- -#}}} - -#{{{ interpretation -#------------------------------------------------------------------------------- -#This function holds a print-to-screen explanation of what the numbers mean -def interpretation(): - sys.stderr.write(""" -cablam_validate data interpretation: - -Text: - Text output is provided in comma-separated format: - residue,contour_level,loose_alpha,regular_alpha,loose_beta,regular_beta - - 'residue' is a residue identifier formatted as pdb columns 18 to 27 (1 index) - - 'contour_level' is the 3D outlier contour at which this residue was found. - Smaller values are worse outliers. Residues with values <=0.05 are worth - concern. - - 'loose_alpha' is a 2D percentile contour for this residue's similarity to - alpha helix. A high value indicates some amount of helix character, but not - necessarily the presence of a regular helix. - >0.001 is meaningful, >0.01 is likely - - 'regular_alpha' is a 2D percentile contour for this residue's similarity to - regular alpha helix. The contours for regular helix are very tight. - >0.00001 is meaningful, >0.0001 is likely - - 'loose_beta' is a 2D percentile contour for this residue's similarity to - beta strand. A high value indicates some amount of strand character, but - not necessarily the presence of a regular strand. - >0.01 is meaningful, >0.1 is likely - - 'regular_beta' is a 2D percentile contour for this residue's similarity to - regular beta sheet. Beta structure contours are generally more permissive - than helix contours, and the contour values should not be judged on the same - scale. - >0.001 is meaningful, >0.01 is likely - - ('meaningful' and 'likely' scores are subject to change as the system is - refined) - -Kin: - Kin output is provided in a kinemage format and should be appended to an open - kinemage of the structure of interest. This provides validation markup of - the structure. Markup takes the form of purple lines, drawn to follow the - peptide plane diherdrals used to determine outliers. Clicking on the - vertices or on a point in the middle of the center line will bring up - validation numbers. - - The first value corresponds to 'contour_level' in the text output. - - The values preceded by 'a' and 'rega' correspond to 'loose_alpha' and - 'regular_alpha', respectively. - - The values preceded by 'b' and 'regb' correspond to 'loose_beta' and - 'regular_beta', respectively. - -Points: - Points output is provided in kinemage dotlist format. Each point corresponds - to one outlier residue and is plotted in the 3D cablam space used to - determine outliers (dimensions are CA_pseudodihedral_in, - CA_pseudodihedral_out, and peptide_plane_psedudodihedral). These points may - be appended to contour kinemages to visualize outliers in that space. - This output is intended primarily for developer and exploratory use, rather - than for validation per se. - -""") -#------------------------------------------------------------------------------- -#}}} - -#{{{ setup -#------------------------------------------------------------------------------- -#Wrapper for the construction of the resdata object needed for validation -# All you need is a hierarchy object -def setup(hierarchy,pdbid='pdbid'): - resdata=cablam_res.construct_linked_residues(hierarchy, - targetatoms=['CA','C','N','O'],pdbid=pdbid) - cablam_math.cablam_measures(resdata) - cablam_math.omegacalc(resdata) - return resdata -#------------------------------------------------------------------------------- -#}}} - -#{{{ fetch_expectations -#------------------------------------------------------------------------------- -#This function finds, unpickles, and returns N-Dim Tables of expected residue -# behavior for use in determining outliers -#The return object is a dict keyed by residue type: 'general','gly','pro' -#One set of contours defines peptide behavior (CA_d_in,CA_d_out,peptide): -def fetch_peptide_expectations(): - categories = ['general','gly','transpro','cispro'] - unpickled = {} - for category in categories: - picklefile = libtbx.env.find_in_repositories( - relative_path=( - "chem_data/cablam_data/cablam.8000.expected."+category+".pickle"), - test=os.path.isfile) - if (picklefile is None): - sys.stderr.write("\nCould not find a needed pickle file for category "+ - category+" in chem_data.\nExiting.\n") - sys.exit() - ndt = easy_pickle.load(file_name=picklefile) - unpickled[category] = ndt - return unpickled - -#One set of contours defines CA trace (CA_d_in,CA_d_out,CA_a): -def fetch_ca_expectations(): - categories = ['general','gly','transpro','cispro'] - unpickled = {} - for category in categories: - picklefile = libtbx.env.find_in_repositories( - relative_path=( - "chem_data/cablam_data/cablam.8000.expected."+category+"_CA.pickle"), - test=os.path.isfile) - if (picklefile is None): - sys.stderr.write("\nCould not find a needed pickle file for category "+ - category+" in chem_data.\nExiting.\n") - sys.exit() - ndt = easy_pickle.load(file_name=picklefile) - unpickled[category] = ndt - return unpickled -#------------------------------------------------------------------------------- -#}}} - -#{{{ fetch_motifs -#------------------------------------------------------------------------------- -#This function finds, unpickles, and returns N-Dim Tables of secondary structure -# behavior for use in determining what an outlier residue might really be -#The return object is a dict keyed by secondary structure type: -# 'loose_beta','regular_beta','loose_alpha','regular_alpha' -def fetch_motifs(): - motifs = ['loose_beta','regular_beta','loose_alpha','regular_alpha', - 'loose_threeten','regular_threeten'] - unpickled = {} - for motif in motifs: - picklefile = libtbx.env.find_in_repositories( - relative_path=( - "chem_data/cablam_data/cablam.8000.motif."+motif+".pickle"), - test=os.path.isfile) - if (picklefile is None): - sys.stderr.write("\nCould not find a needed pickle file for motif "+ - motif+" in chem_data.\nExiting.\n") - sys.exit() - ndt = easy_pickle.load(file_name=picklefile) - unpickled[motif] = ndt - return unpickled -#------------------------------------------------------------------------------- -#}}} - -#{{{ fetch cis trans pro -#------------------------------------------------------------------------------- -#This function finds, unpickles, and returns N-Dim Tables of proline behavior -# for use in determining cis versus trans peptide confirmation -#The return object is a dict keyed by: 'cis' and 'trans' -def fetch_cis_trans_proline(): - confs = ['cis','trans'] - unpickled = {} - for conf in confs: - picklefile = libtbx.env.find_in_repositories( - relative_path=( - "chem_data/cablam_data/cablam.8000.proline."+conf+".pickle"), - test=os.path.isfile) - if (picklefile is None): - sys.stderr.write("\nCould not find a needed pickle file for "+ - conf+" proline in chem_data.\nExiting.\n") - sys.exit() - ndt = easy_pickle.load(file_name=picklefile) - unpickled[conf] = ndt - return unpickled -#------------------------------------------------------------------------------- -#}}} - -#{{{ find_outliers -#------------------------------------------------------------------------------- -#These are used by the helix_or_sheet function -#For each residue, check the relevant measures against 3D contours and record -# outliers. Outliercutoffs can be set on use, but default to generally useful -# values. cutoff=1.0 will consider all residues outliers and is a quick way to -# get contour data for all residues. -def find_peptide_outliers(resdata,expectations,cutoff=0.05): - outliers = {} - reskeys = list(resdata.keys()) - reskeys.sort() - for resid in reskeys: - residue = resdata[resid] - if 'CA_d_in' in residue.measures and 'CA_d_out' in residue.measures and 'CO_d_in' in residue.measures: - cablam_point = [residue.measures['CA_d_in'],residue.measures['CA_d_out'],residue.measures['CO_d_in']] - resname = residue.alts[residue.firstalt('CA')]['resname'] - if resname.upper() == 'GLY': - percentile = expectations['gly'].valueAt(cablam_point) - elif resname.upper() == 'PRO': - #Splitting cis vs trans at 90, rather than having a twisted category - # This way, no residues are left out of cablam analysis - # Use omegalyze for nontrans peptide validation - if ('omega' not in residue.measures) or (residue.measures['omega'] >= 90) or (residue.measures['omega'] <= -90): - percentile = expectations['transpro'].valueAt(cablam_point) - else: - percentile = expectations['cispro'].valueAt(cablam_point) - #percentile = expectations['pro'].valueAt(cablam_point) - else: - percentile = expectations['general'].valueAt(cablam_point) - - if percentile < cutoff: - outliers[resid] = cablam_validation(residue=residue,outlier_level=percentile) - return outliers - -def find_ca_outliers(resdata,expectations,cutoff=0.005): - outliers = {} - reskeys = list(resdata.keys()) - reskeys.sort() - for resid in reskeys: - residue = resdata[resid] - if 'CA_d_in' in residue.measures and 'CA_d_out' in residue.measures and 'CA_a' in residue.measures: - cablam_point = [residue.measures['CA_d_in'],residue.measures['CA_d_out'],residue.measures['CA_a']] - resname = residue.alts[residue.firstalt('CA')]['resname'] - if resname.upper() == 'GLY': - percentile = expectations['gly'].valueAt(cablam_point) - elif resname.upper() == 'PRO': - if ('omega' not in residue.measures) or (residue.measures['omega'] >= 90) or (residue.measures['omega'] <= -90): - percentile = expectations['transpro'].valueAt(cablam_point) - else: - percentile = expectations['cispro'].valueAt(cablam_point) - #percentile = expectations['pro'].valueAt(cablam_point) - else: - percentile = expectations['general'].valueAt(cablam_point) - - if percentile < cutoff: - outliers[resid] = cablam_validation(residue=residue,outlier_level=percentile) - return outliers - -def find_all_residue_stats(resdata,peptide_expectations,ca_geom_expectations): - residue_stats = {} - reskeys = list(resdata.keys()) - reskeys.sort() - for resid in reskeys: - residue = resdata[resid] - if 'CA_d_in' in residue.measures and 'CA_d_out' in residue.measures and 'CO_d_in' in residue.measures and 'CA_a' in residue.measures: - peptide_point = [residue.measures['CA_d_in'],residue.measures['CA_d_out'],residue.measures['CO_d_in']] - ca_geom_point = [residue.measures['CA_d_in'],residue.measures['CA_d_out'],residue.measures['CA_a']] - resname = residue.alts[residue.firstalt('CA')]['resname'] - if resname.upper() == 'GLY': - peptide_percentile = peptide_expectations['gly'].valueAt(peptide_point) - ca_geom_percentile = ca_geom_expectations['gly'].valueAt(ca_geom_point) - elif resname.upper() == 'PRO': - if ('omega' not in residue.measures) or (residue.measures['omega'] >= 90) or (residue.measures['omega'] <= -90): - peptide_percentile = peptide_expectations['transpro'].valueAt(peptide_point) - ca_geom_percentile = ca_geom_expectations['transpro'].valueAt(ca_geom_point) - else: - peptide_percentile = peptide_expectations['cispro'].valueAt(peptide_point) - ca_geom_percentile = ca_geom_expectations['cispro'].valueAt(ca_geom_point) - else: - peptide_percentile = peptide_expectations['general'].valueAt(peptide_point) - ca_geom_percentile = ca_geom_expectations['general'].valueAt(ca_geom_point) - - residue_stats[resid] = cablam_validation(residue=residue,outlier_level=peptide_percentile,ca_geom_outlier_level=ca_geom_percentile) - return residue_stats -#------------------------------------------------------------------------------- -#}}} - -#{{{ helix_or_sheet (wrapper) and helix_or_sheet_res -#------------------------------------------------------------------------------- -#Labels individual residues as alpha or beta -def helix_or_sheet(residue_stats, motifs): - alpha_cutoff = 0.001 - beta_cutoff = 0.0001 - threeten_cutoff = 0.001 - for res_stat in residue_stats.values(): - residue = res_stat.residue - contours = helix_or_sheet_res(residue, motifs) - if contours: - res_stat.loose_alpha = contours['loose_alpha'] - res_stat.regular_alpha = contours['regular_alpha'] - res_stat.loose_beta = contours['loose_beta'] - res_stat.regular_beta = contours['regular_beta'] - res_stat.loose_threeten= contours['loose_threeten'] - res_stat.regular_threeten = contours['regular_threeten'] - -#this single-residue level of the check is intentionally independent from the -# cablam_validation class in case getting contour levels for a single residue -# is desirable -def helix_or_sheet_res(residue, motifs): - contours = {'residue':residue} - if 'CA_d_in' in residue.measures and 'CA_d_out' in residue.measures: - cablam_point = [residue.measures['CA_d_in'],residue.measures['CA_d_out']] - for motifname, contour in motifs.items(): - contours[motifname] = contour.valueAt(cablam_point) - return contours - else: - return None -#------------------------------------------------------------------------------- -#}}} - -#{{{ assign_sec_struc -def assign_sec_struc(residues): - alpha_cutoff = 0.001 - beta_cutoff = 0.0001 - threeten_cutoff = 0.001 - ca_geom_cutoff = 0.005 - for resid in residues: - res = residues[resid] - res.suggestion = ' ' - if res.ca_geom_outlier_level < ca_geom_cutoff: - continue - if res.loose_alpha >= alpha_cutoff: - try: - if residues[res.residue.prevres.resid].loose_alpha >= alpha_cutoff and residues[res.residue.nextres.resid].loose_alpha >= alpha_cutoff: - res.suggestion = ' try alpha helix ' - except KeyError: - pass - if res.regular_beta >= beta_cutoff: - try: - if residues[res.residue.prevres.resid].regular_beta >= beta_cutoff and residues[res.residue.nextres.resid].regular_beta >= beta_cutoff: - res.suggestion = ' try beta sheet ' - except KeyError: - pass - if res.loose_threeten >= threeten_cutoff and res.loose_threeten > res.loose_alpha: - try: - if residues[res.residue.prevres.resid].loose_threeten >= threeten_cutoff or residues[res.residue.nextres.resid].loose_threeten >= threeten_cutoff: - res.suggestion = ' try three-ten ' - except KeyError: - pass -#}}} - -#{{{ find_partial_sec_struc function -#------------------------------------------------------------------------------- -def find_partial_sec_struc(resdata,ca_outliers={}): - - #these numbers are low-end contour cutoffs for these motifs - #The numbers are best-guesses from looking at marked-up structures, esp 2o01 - # and ribosome - #Values may change during development. - loose_alpha_cutoff = 0.001 #0.1% - #reg_beta_cutoff = 0.001 #0.1% - reg_beta_cutoff = 0.0001 #this cutoff is a bit generous, beta needs - # forthcoming though-space relationships to work properly - loose_threeten_cutoff = 0.001 - reg_threeten_cutoff = 0.001 - - expectations = fetch_peptide_expectations() - motifs = fetch_motifs() - - allres = find_peptide_outliers(resdata, expectations, cutoff=1.0) - helix_or_sheet(allres, motifs) - - for resid in resdata: - resdata[resid].motif_guess = motif_guess() - - #Some alternative logic from earlier versions is included for reference and - # development - for resid in resdata: - if resid not in allres: - #couldn't calculate all relevant data for the residue and cannot make - #further assessment - continue - residue = resdata[resid] - if resid in list(ca_outliers.keys()): - #if the residue is a ca outlier, it recieves no sec struc assignment - #(residue.motif guess must be created for each residue, however) - continue - - #loose alpha - if allres[resid].loose_alpha >= loose_alpha_cutoff: - try: - if allres[residue.nextres.resid].loose_alpha >= loose_alpha_cutoff and allres[residue.prevres.resid].loose_alpha >= loose_alpha_cutoff: - residue.motif_guess.loose_alpha = True - except KeyError: - pass - - #loose beta - if allres[resid].regular_beta >= reg_beta_cutoff: - try: - if allres[residue.nextres.resid].regular_beta >= reg_beta_cutoff and allres[residue.prevres.resid].regular_beta >= reg_beta_cutoff: - residue.motif_guess.regular_beta = True - residue.prevres.motif_guess.regular_beta = True - residue.nextres.motif_guess.regular_beta = True - except KeyError: - pass - - #loose 3-10 - if (allres[resid].loose_threeten >= loose_threeten_cutoff) and (allres[resid].loose_threeten > allres[resid].loose_alpha): - try: - if allres[residue.nextres.resid].loose_threeten >= loose_threeten_cutoff or allres[residue.prevres.resid].loose_threeten >= loose_threeten_cutoff: - residue.motif_guess.loose_threeten = True - except KeyError: - pass -#------------------------------------------------------------------------------- -#}}} - -#{{{ find_whole_sec_struc function -#------------------------------------------------------------------------------- -def find_whole_sec_struc(resdata): - reskeys = list(resdata.keys()) - reskeys.sort() - motifs = [] - current_motif = None - #search for helix - for resid in reskeys: - residue=resdata[resid] - if residue.motif_guess.loose_alpha: - if current_motif: - current_motif.motif_end = residue - else: #start new motif - current_motif = motif_chunk() - motifs.append(current_motif) - current_motif.motif_type = 'helix' - current_motif.motif_start = residue - current_motif.motif_end = residue - if not residue.nextres: - current_motif = None - else: - if current_motif: #reached end of motif - current_motif = None - else: - pass - #search for threeten - for resid in reskeys: - residue = resdata[resid] - if residue.motif_guess.loose_threeten: - if current_motif: - current_motif.motif_end = residue - else: - current_motif = motif_chunk() - motifs.append(current_motif) - current_motif.motif_type = 'threeten' - current_motif.motif_start = residue - current_motif.motif_end = residue - if not residue.nextres: - current_motif = None - else: - if current_motif: - current_motif = None - else: - pass - #search for sheet - for resid in reskeys: - residue=resdata[resid] - if residue.motif_guess.regular_beta: - if current_motif: - current_motif.motif_end = residue - else: #start new motif - current_motif = motif_chunk() - motifs.append(current_motif) - current_motif.motif_type = 'sheet' - current_motif.motif_start = residue - current_motif.motif_end = residue - if not residue.nextres: - current_motif = None - else: - if current_motif: #reached end of motif - current_motif = None - else: - pass - return motifs -#------------------------------------------------------------------------------- -#}}} - -#{{{ check prolines function -#------------------------------------------------------------------------------- -#This is a function in development: cis-proline vs trans-proline seem to have -# mostly-distinct distributions in CaBLAM space. This funtion attempts to -# determine if a proline's CA trace is modeled in agreement with its omega -# dihedral. It is clear that errors can be detected. It is not yet clear how -# to correct those errors (whether the fault is more likely to be in the CA -# trace or in the omega dihedral. Use with care.) -def check_prolines(hierarchy,pdbid='pdbid'): - cis_cutoff = 0.005 - trans_cutoff = 0.005 - resdata = setup(hierarchy,pdbid) - #cablam_math.omegacalc(resdata) - pro_contour = fetch_cis_trans_proline() - reskeys = list(resdata.keys()) - reskeys.sort() - for resid in reskeys: - residue = resdata[resid] - if residue.id_with_resname()[0:3].upper() == 'PRO': - if 'omega' in residue.measures and 'CA_d_in' in residue.measures and 'CA_d_out' in residue.measures: - omega = residue.measures['omega'] - cablam_point = [residue.measures['CA_d_in'],residue.measures['CA_d_out']] - cislevel = pro_contour['cis'].valueAt(cablam_point) - translevel = pro_contour['trans'].valueAt(cablam_point) - if (omega >= -30) and (omega <= 30): #modeled as cis - if cislevel < cis_cutoff: - print("bad CIS at ", pdbid, residue.id_with_resname(), "value:%.3f" %cislevel) - if translevel >= 0.1:#trans_cutoff: - print(" try TRANS. value:%.3f" %translevel) - else: - print(" no suggestion. trans value:%.3f" %translevel) - elif (omega >=150) or (omega <= -150): #modeled as trans - if translevel < trans_cutoff: - print("bad TRANS at ", pdbid, residue.id_with_resname(), "value:%.3f" %translevel) - if cislevel >= 0.1:#cis_cutoff: - print(" try CIS. value:%.3f" %cislevel) - else: - print(" no suggestion. cis value:%.3f" %cislevel) - else: #modeled as twisted - print("TWISTED peptide at ", pdbid, residue.id_with_resname()) - print(" TRANS score: %.3f" %translevel, " CIS score: %.3f" %cislevel) -#}}} - -#{{{ print_helix_sheet_records function -#------------------------------------------------------------------------------- -#This function accepts a hierarchy object and returns HELIX and SHEET-style -# records for major secondary structure elements found in that model by CaBLAM. -# cablam_multicrit_kin() also returns these records, but as part of a pbd file -def print_helix_sheet_records(hierarchy, ca_cutoff=0.005, pdbid='pdbid',writeto=sys.stdout): - resdata=setup(hierarchy,pdbid) - ca_expectations = fetch_ca_expectations() - motif_contours = fetch_motifs() - - ca_outliers = find_ca_outliers(resdata,ca_expectations,cutoff=ca_cutoff) - - find_partial_sec_struc(resdata,ca_outliers=ca_outliers) - motifs = find_whole_sec_struc(resdata) - for motif in motifs: - motif.print_record(writeto=writeto) -#------------------------------------------------------------------------------- -#}}} - -#{{{ print_pdb_with_new_helix_sheet_records function -#------------------------------------------------------------------------------- -def print_pdb_with_new_helix_sheet_records(hierarchy, ca_cutoff=0.005, pdbid='pdbid', writeto=sys.stdout): - #This function prints CaBLAM-based HELIX and SHEET records as part of a pdb - # file. - print_helix_sheet_records(hierarchy, ca_cutoff, pdbid, writeto) - writeto.write(hierarchy.as_pdb_string()) -#------------------------------------------------------------------------------- -#}}} - -#{{{ print_cablam_markup_kin function -#------------------------------------------------------------------------------- -def print_cablam_markup_kin(hierarchy, peptide_cutoff=0.05, peptide_bad_cutoff=0.01, ca_cutoff=0.005, pdbid='pdbid', writeto=sys.stdout): - #This function prints the three main kinemage markup vectorlists - resdata=setup(hierarchy,pdbid) - peptide_expectations = fetch_peptide_expectations() - ca_expectations = fetch_ca_expectations() - motif_contours = fetch_motifs() - - peptide_outliers=find_peptide_outliers(resdata,peptide_expectations,cutoff=peptide_cutoff) - helix_or_sheet(peptide_outliers,motif_contours) - give_kin(peptide_outliers, peptide_cutoff, color='purple', writeto=writeto) - give_kin(peptide_outliers, peptide_bad_cutoff, color='magenta', writeto=writeto) - - ca_outliers = find_ca_outliers(resdata,ca_expectations,cutoff=ca_cutoff) - helix_or_sheet(ca_outliers,motif_contours) - give_ca_kin(ca_outliers, ca_cutoff, writeto=writeto) -#------------------------------------------------------------------------------- -#}}} - -#{{{ cablam_multicrit_kin function -#------------------------------------------------------------------------------- -#This function accepts a hierarchy object and returns a comprehensive validation -# kinemage, in an open phenix.king window. Likely to return .kin-format text -# once I get ahold of the ribbon code -def cablam_multicrit_kin(hierarchy, peptide_cutoff=0.05, peptide_bad_cutoff=0.01, ca_cutoff=0.005, pdbid='pdbid', writeto=sys.stdout): - outfile_kin = open(pdbid+'_cablam_multi.kin','w') - outfile_pdb = open(pdbid+'_cablam_multi.pdb','w') - resdata=setup(hierarchy,pdbid) - peptide_expectations = fetch_peptide_expectations() - ca_expectations = fetch_ca_expectations() - motif_contours = fetch_motifs() - - peptide_outliers=find_peptide_outliers(resdata,peptide_expectations,cutoff=peptide_cutoff) - helix_or_sheet(peptide_outliers,motif_contours) - give_kin(peptide_outliers, peptide_cutoff, color='purple', writeto=outfile_kin) - give_kin(peptide_outliers, peptide_bad_cutoff, color='magenta', writeto=outfile_kin) - - #peptide_bad_outliers=find_peptide_outliers(resdata,peptide_expectations,cutoff=peptide_bad_cutoff) - #helix_or_sheet(peptide_bad_outliers,motif_contours) - #give_kin(peptide_bad_outliers, peptide_bad_cutoff, color='magenta', writeto=outfile_kin) - - ca_outliers = find_ca_outliers(resdata,ca_expectations,cutoff=ca_cutoff) - helix_or_sheet(ca_outliers,motif_contours) #This call for dev purposes, need to know what's flagged and interesting - give_ca_kin(ca_outliers, ca_cutoff, writeto=outfile_kin) - - find_partial_sec_struc(resdata,ca_outliers=ca_outliers) - motifs = find_whole_sec_struc(resdata) - for motif in motifs: - motif.print_record(writeto=outfile_pdb) - outfile_pdb.write(hierarchy.as_pdb_string()) - outfile_kin.close() - outfile_pdb.close() - king_command = 'phenix.king -m ' + pdbid+'_cablam_multi.pdb ' + pdbid+'_cablam_multi.kin' - #'king -m' merges the files that follow - easy_run.fully_buffered(king_command) -#------------------------------------------------------------------------------- -#}}} - -#{{{ output functions -#------------------------------------------------------------------------------- -def give_kin(outliers, outlier_cutoff, color='purple', writeto=sys.stdout): - #The kinemage markup is purple dihedrals following outlier CO angles - #This angle was chosen because it is indicative of the most likely source of - # problems - #Purple was chosen because it is easily distinguished from (green) Rama - # markup, and because the cablam measures share some philosophical - # similarity with perp distance in RNA markup - #writeto.write('\n@kinemage') - writeto.write('\n@subgroup {cablam out '+str(outlier_cutoff)+'} dominant\n') - writeto.write('@vectorlist {cablam outliers} color= '+color+' width= 4 master={cablam out '+str(outlier_cutoff)+'}') - #writeto.write('@vectorlist') - reskeys = list(outliers.keys()) - reskeys.sort() - for resid in reskeys: - outlier = outliers[resid] - if outlier.outlier_level >= outlier_cutoff: - continue - #Shouldn't have to do checking here, since only residues with calculable values should get to this point - residue = outlier.residue - prevres = residue.prevres - nextres = residue.nextres - CA_1, O_1 = prevres.getatomxyz('CA'),prevres.getatomxyz('O') - CA_2, O_2 = residue.getatomxyz('CA'),residue.getatomxyz('O') - CA_3 = nextres.getatomxyz('CA') - - pseudoC_1 = cablam_math.perptersect(CA_1,CA_2,O_1) - pseudoC_2 = cablam_math.perptersect(CA_2,CA_3,O_2) - - midpoint = [ (pseudoC_1[0]+pseudoC_2[0])/2.0 , (pseudoC_1[1]+pseudoC_2[1])/2.0 , (pseudoC_1[2]+pseudoC_2[2])/2.0 ] - - stats = ' '.join(['%.5f' %outlier.outlier_level, 'alpha'+'%.5f' %outlier.loose_alpha, 'beta'+'%.5f' %outlier.regular_beta]) - - writeto.write('\n{'+stats+'} P '+ str(O_1[0]) +' '+ str(O_1[1]) +' '+ str(O_1[2])) - writeto.write('\n{'+stats+'} '+ str(pseudoC_1[0]) +' '+ str(pseudoC_1[1]) +' '+ str(pseudoC_1[2])) - writeto.write('\n{'+stats+'} '+ str(midpoint[0]) +' '+ str(midpoint[1]) +' '+ str(midpoint[2])) - writeto.write('\n{'+stats+'} '+ str(pseudoC_2[0]) +' '+ str(pseudoC_2[1]) +' '+ str(pseudoC_2[2])) - writeto.write('\n{'+stats+'} '+ str(O_2[0]) +' '+ str(O_2[1]) +' '+ str(O_2[2])) - writeto.write('\n') - -def give_ca_kin(outliers, outlier_cutoff, writeto=sys.stdout): - #Kinemage markup as red CA virtual angles, since that is the measure unique to - #this validation. - writeto.write('\n@subgroup {ca out '+str(outlier_cutoff)+'} dominant\n') - writeto.write('@vectorlist {ca outliers} color= red width= 4 master={ca geom outliers}') - reskeys = list(outliers.keys()) - reskeys.sort() - for resid in reskeys: - outlier = outliers[resid] - residue = outlier.residue - prevres = residue.prevres - nextres = residue.nextres - CA_1 = prevres.getatomxyz('CA') - CA_2 = residue.getatomxyz('CA') - CA_3 = nextres.getatomxyz('CA') - - #Note: 'stats' should be simplified after I'm certain that the cutoffs are in the right places - stats = ' '.join(['%.5f' %outlier.outlier_level, 'alpha'+'%.5f' %outlier.loose_alpha, 'beta'+'%.5f' %outlier.regular_beta]) - - #CA_2[0]+(CA_2[0]-CA_1[0])*0.9 - - writeto.write('\n{'+stats+'} P '+str(CA_2[0]-(CA_2[0]-CA_1[0])*0.9)+' '+str(CA_2[1]-(CA_2[1]-CA_1[1])*0.9)+' '+str(CA_2[2]-(CA_2[2]-CA_1[2])*0.9)) - #writeto.write('\n{'+stats+'} P '+str(CA_1[0])+' '+str(CA_1[1])+' '+str(CA_1[2])) - writeto.write('\n{'+stats+'} '+str(CA_2[0])+' '+str(CA_2[1])+' '+str(CA_2[2])) - writeto.write('\n{'+stats+'} '+str(CA_2[0]-(CA_2[0]-CA_3[0])*0.9)+' '+str(CA_2[1]-(CA_2[1]-CA_3[1])*0.9)+' '+str(CA_2[2]-(CA_2[2]-CA_3[2])*0.9)) - #writeto.write('\n{'+stats+'} '+str(CA_3[0])+' '+str(CA_3[1])+' '+str(CA_3[2])) - writeto.write('\n') - - -def give_points(outliers, outlier_cutoff=0.05, writeto=sys.stdout): - #This prints a dotlist in kinemage format - #Each dot is one outlier residue in 3D space for visual comparison to expected - # behavior contours - writeto.write('\n@kinemage\n') - writeto.write('@group {cablam outliers} dominant\n') - writeto.write('@dotlist {cablam outliers}') - reskeys = list(outliers.keys()) - reskeys.sort() - for resid in reskeys: - outlier = outliers[resid] - if outlier.outlier_level >= outlier_cutoff: - continue - residue = outlier.residue - if 'CA_d_in' in residue.measures and 'CA_d_out' in residue.measures and 'CO_d_in' in residue.measures: - cablam_point = [residue.measures['CA_d_in'],residue.measures['CA_d_out'],residue.measures['CO_d_in']] - writeto.write('{'+residue.id_with_resname()+'} '+'%.3f' %cablam_point[0]+' '+'%.3f' %cablam_point[1]+' '+'%.3f' %cablam_point[2]+'\n') - writeto.write('\n') - -def give_text(outliers, writeto=sys.stdout): - #This prints a comma-separated line of data for each outlier residue - #Intended for easy machine readability - #writeto.write('\nresidue,contour_level,loose_alpha,regular_alpha,loose_beta,regular_beta,threeten') - writeto.write('residue : outlier_type : contour_level : ca_contour_level : sec struc recommendation : alpha score : beta score : three-ten score') - reskeys = list(outliers.keys()) - reskeys.sort() - for resid in reskeys: - outlier = outliers[resid] - if outlier.ca_geom_outlier_level < 0.005: - outlier_type = ' CA Geom Outlier ' - elif outlier.outlier_level < 0.01: - outlier_type = ' CaBLAM Outlier ' - elif outlier.outlier_level < 0.05: - outlier_type = ' CaBLAM Disfavored ' - else: - outlier_type = ' ' - #outlist = [outlier.residue.mp_id(), '%.5f' %outlier.outlier_level, '%.5f' %outlier.loose_alpha, '%.5f' %outlier.regular_alpha, '%.5f' %outlier.loose_beta, '%.5f' %outlier.regular_beta, '%.5f' %outlier.loose_threeten] - #try: - outlist = [outlier.residue.mp_id(), outlier_type, '%.5f' %outlier.outlier_level, '%.5f' %outlier.ca_geom_outlier_level, outlier.suggestion, '%.5f' %outlier.loose_alpha, '%.5f' %outlier.regular_beta, '%.5f' %outlier.loose_threeten] - #except TypeError: - # print '\n',outlier.residue.mp_id(), outlier_type, outlier.outlier_level, outlier.ca_geom_outlier_level, outlier.loose_alpha, outlier.regular_beta, outlier.loose_threeten - # sys.exit() - writeto.write('\n'+':'.join(outlist)) - writeto.write('\n') -#------------------------------------------------------------------------------- -#}}} - -#{{{ oneline function -#------------------------------------------------------------------------------- -#Outputs cablam validation information in format similar to molprobity oneline. -# Contents of this output subject to change: percents of cablam-relevant -# outliers and annotation. -def oneline_header(writeto=sys.stdout): - #Write column labels for oneline output - writeto.write('pdbid:residues:cablam_disfavored_percent:cablam_outlier_percent:ca_geom_outlier_percent\n') - -def oneline(hierarchy, peptide_cutoff=0.05, peptide_bad_cutoff=0.01, ca_cutoff=0.005, pdbid='pdbid', writeto=sys.stdout): - resdata=setup(hierarchy,pdbid) - peptide_expectations = fetch_peptide_expectations() - ca_expectations = fetch_ca_expectations() - - residue_count = 0 - peptide_outlier_count = 0 - peptide_bad_outlier_count = 0 - ca_outlier_count = 0 - for resid in resdata.keys(): # TODO: if resdata is a dict, the keys call can be removed - residue = resdata[resid] - if 'CA_d_in' in residue.measures and 'CA_d_out' in residue.measures and 'CO_d_in' in residue.measures and 'CA_a' in residue.measures: - #This check ensures that only calculable, protein residues are considered - residue_count += 1 - resname = residue.alts[residue.firstalt('CA')]['resname'] - peptide_point = [residue.measures['CA_d_in'],residue.measures['CA_d_out'],residue.measures['CO_d_in']] - ca_point = [residue.measures['CA_d_in'],residue.measures['CA_d_out'],residue.measures['CA_a']] - #there are separate contours for gly, for pro, and for other residues - if resname.upper() == 'GLY': - peptide_percentile = peptide_expectations['gly'].valueAt(peptide_point) - ca_percentile = ca_expectations['gly'].valueAt(ca_point) - elif resname.upper() == 'PRO': - if ('omega' not in residue.measures) or (residue.measures['omega'] >= 90) or (residue.measures['omega'] <= -90): - peptide_percentile = peptide_expectations['transpro'].valueAt(peptide_point) - ca_percentile = ca_expectations['transpro'].valueAt(ca_point) - else: - peptide_percentile = peptide_expectations['cispro'].valueAt(peptide_point) - ca_percentile = ca_expectations['cispro'].valueAt(ca_point) - #elif resname.upper() == 'PRO': - # peptide_percentile = peptide_expectations['pro'].valueAt(peptide_point) - # ca_percentile = ca_expectations['pro'].valueAt(ca_point) - else: - peptide_percentile = peptide_expectations['general'].valueAt(peptide_point) - ca_percentile = ca_expectations['general'].valueAt(ca_point) - - if peptide_percentile < peptide_cutoff: - peptide_outlier_count += 1 - if peptide_percentile < peptide_bad_cutoff: - peptide_bad_outlier_count += 1 - if ca_percentile < ca_cutoff: - ca_outlier_count += 1 - - try: - peptide_outlier_percent = peptide_outlier_count/residue_count*100 - except ZeroDivisionError: - peptide_outlier_percent = 0 - try: - peptide_bad_outlier_percent = peptide_bad_outlier_count/residue_count*100 - except ZeroDivisionError: - peptide_bad_outlier_percent = 0 - try: - ca_outlier_percent = ca_outlier_count/residue_count*100 - except ZeroDivisionError: - ca_outlier_percent = 0 - #sys.stderr.write(pdbid+'\n') #Doesn't need bc pdbid printed in output - writeto.write(pdbid.lower()+':'+str(residue_count)+':'+'%.1f'%peptide_outlier_percent+':'+'%.1f'%peptide_bad_outlier_percent+':'+'%.2f'%ca_outlier_percent+'\n') -#------------------------------------------------------------------------------- -#}}} - -#{{{ analyze_pdb -#------------------------------------------------------------------------------- -#Returns a list of cablam_validation objects, one for each residue identified as -# a potential outliers. This list is the object of choice for internal access -# to cablam output. -#The default outlier_cutoff = 0.05 catches most outliers of interest, although -# it may also flag loops and other low-population motifs as potential outliers. -# Setting outlier_cutoff=1.0 will return a validation object for every residue. -def analyze_pdb(hierarchy, outlier_cutoff=0.05, pdbid='pdbid'): - resdata=setup(hierarchy,pdbid) - peptide_expectations = fetch_peptide_expectations() - ca_geom_expectations = fetch_ca_expectations() - motifs = fetch_motifs() - - residue_stats = find_all_residue_stats(resdata, peptide_expectations, ca_geom_expectations) - helix_or_sheet(residue_stats, motifs) - assign_sec_struc(residue_stats) - - return residue_stats - -#Alternative call to find ca-trace outliers -def analyze_pdb_ca(hierarchy, outlier_cutoff=0.005, pdbid='pdbid'): - resdata=setup(hierarchy,pdbid) - ca_expectations = fetch_ca_expectations() - motifs = fetch_motifs() - - outliers = find_ca_outliers(resdata, ca_expectations, cutoff=outlier_cutoff) - helix_or_sheet(outliers, motifs) - - return outliers - -def analyze_pdb_gui(hierarchy, pdbid='pdbid'): - outlier_cutoff = 0.05 - ca_outlier_cutoff = 0.005 - resdata=setup(hierarchy,pdbid) - peptide_expectations = fetch_peptide_expectations() - ca_expectations = fetch_ca_expectations() - motifs = fetch_motifs() - - outliers = find_peptide_outliers(resdata, peptide_expectations, cutoff=outlier_cutoff) - ca_outliers = find_ca_outliers(resdata, ca_expectations, cutoff=ca_outlier_cutoff) - helix_or_sheet(outliers,motifs) - find_partial_sec_struc(resdata,ca_outliers=ca_outliers) - for outlier in outliers.values(): - if outlier.residue.motif_guess.regular_beta: - outlier.suggestion = 'try Beta Strand' - elif outlier.residue.motif_guess.loose_threeten: - outlier.suggestion = 'try ThreeTen' - elif outlier.residue.motif_guess.loose_alpha: - outlier.suggestion = 'try Alpha Helix' - else: - pass #suggestion = '' - return outliers -#------------------------------------------------------------------------------- -#}}} - -#{{{ run -#------------------------------------------------------------------------------- -#Run is intended largely for commandline access. Its default output is comma- -# separated text to stdout. -def run(args): - #{{{ phil parsing - #----------------------------------------------------------------------------- - interpreter = libtbx.phil.command_line.argument_interpreter(master_phil=master_phil) - sources = [] - for arg in args: - if os.path.isfile(arg): #Handles loose filenames - input_file = file_reader.any_file(arg) - if (input_file.file_type == "pdb"): - sources.append(interpreter.process(arg="pdb_infile=\"%s\"" % arg)) - elif (input_file.file_type == "phil"): - sources.append(input_file.file_object) - elif os.path.isdir(arg): - sources.append(interpreter.process(arg="pdb_infile=\"%s\"" % arg)) - else: #Handles arguments with xxx=yyy formatting - arg_phil = interpreter.process(arg=arg) - sources.append(arg_phil) - work_phil = master_phil.fetch(sources=sources) - work_params = work_phil.extract() - params = work_params.cablam_validate - #----------------------------------------------------------------------------- - #}}} end phil parsing - - if params.help: - usage() - interpretation() - sys.exit() - - if not params.pdb_infile: - sys.stdout.write( - '\nMissing input data, please provide .pdb file\n') - usage() - sys.exit() - if os.path.isdir(params.pdb_infile): - fileset = [] - dirpath = params.pdb_infile - for filename in os.listdir(params.pdb_infile): - fileset.append(os.path.join(dirpath,filename)) - elif os.path.isfile(params.pdb_infile): - fileset = [params.pdb_infile] - if params.output=='oneline': - oneline_header() - for pdb_infile in fileset: - if not os.path.isfile(pdb_infile): continue - pdb_in = file_reader.any_file(pdb_infile) - if pdb_in.file_type != "pdb": - sys.stderr.write(pdb_infile +" not id'd as readable file\n") - continue - pdbid = os.path.splitext(os.path.basename(pdb_infile))[0] - pdb_io = pdb.input(pdb_infile) - hierarchy = pdb_io.construct_hierarchy() - - if params.output=='oneline': - oneline(hierarchy, pdbid=pdbid) - elif params.output=='ca_kin': - ca_outliers = analyze_pdb_ca( - hierarchy, outlier_cutoff=params.outlier_cutoff, pdbid=pdbid) - give_ca_kin(ca_outliers,params.outlier_cutoff) - elif params.output=='full_kin': - cablam_multicrit_kin(hierarchy,peptide_cutoff=params.outlier_cutoff,pdbid=pdbid) - elif params.output=='markup_no_ribbons': - print_cablam_markup_kin(hierarchy, pdbid=pdbid) - elif params.check_prolines: - check_prolines(hierarchy,pdbid=pdbid) - elif params.output=='records': - print_helix_sheet_records(hierarchy,ca_cutoff=0.005,pdbid='pdbid',writeto=sys.stdout) - elif params.output=='records_plus_pdb': - print_pdb_with_new_helix_sheet_records(hierarchy,ca_cutoff=0.005,pdbid='pdbid',writeto=sys.stdout) - else: - outliers = analyze_pdb( - hierarchy, outlier_cutoff=params.outlier_cutoff, pdbid=pdbid) - - if params.output=='kin': - give_kin(outliers,params.outlier_cutoff) - if params.output=='points': - give_points(outliers,params.outlier_cutoff) - if params.output=='text': - give_text(outliers) -#------------------------------------------------------------------------------- -#}}} - -#class beta_strand(object): -# def __init__(self): -# self.members = [] -# self.mates = [] -# -#def get_strands(motifs): -# strands = [] -# for motif in motifs: -# if motif.motif_type == 'sheet': -# strand = beta_strand() -# start = motif.motif_start -# end = motif.motif_end -# curres = start -# strand.members.append(start) -# while curres is not end: -# curres = curres.nextres -# strand.members.append(curres) -# strands.append(strand) -# return strands -# -#def pair_beta(strands): -# #CA-CA interstrand distance for antiparallel alternates between ~4 and ~6 -# #for parallel, distances are consistantly just under 5 -# dist_cutoff = 6.5 -# index1 = 0 -# while index1 < len(strands): -# strand1 = strands[index1] -# index2 = index1 + 1 -# while index2 < len(strands): -# strand2 = strands[index2] -# for residue1 in strand1.members: -# res1ca = residue1.getatomxyz('CA') -# for residue2 in strand2.members: -# res2ca = residue2.getatomxyz('CA') -# resdist = cablam_math.veclen(cablam_math.vectorize(res1ca,res2ca)) -# if resdist <= dist_cutoff: -# strand1.mates.append(strand2) -# strand2.mates.append(strand1) -# index2 += 1 -# index1 += 1 -# -# -# -##The following is a function in progress to connect beta strands into sheets. -##Do not use without further development -#def stitch_beta(motifs): #pass in an iterable of motif_chunk class instances -# strands = [] -# for motif in motifs: -# if motif.motif_type == 'sheet': -# strands.append(motif) -# else: pass -# for strand1 in strands: -# for strand2 in strands: -# strand1_dir = cablam_math.vectorize(strand1.motif_start.getatomxyz('CA'),strand1.motif_end.getatomxyz('CA')) -# strand2_dir = cablam_math.vectorize(strand2.motif_start.getatomxyz('CA'),strand2.motif_end.getatomxyz('CA')) -# strand_dot_product = cablam_math.dot(strand1_dir,strand2_dir) -# if strand_dot_product < 0: #antiparallel -# curres = strand1.motif_start -# pass -# elif strand_dot_product >0: #parallel -# pass -# pass -# #check if parallel or antiparallel with dot product -# #for residue in strand 1: -# #for residue in strand 2: -# #if close enough: -# #walk in direction -# -# -# return sheets -# -##Find potential mates based on distance -##For each mate, see if there's a good parrallel/ antiparallel local direction (3 residues?) -##Based on par/anti-par, find best alignment of residues minimizing res-res distance -##Check pleat for this alignment -## -##Define units as peptides, not residues -#class beta_strand(object): -# def __init__(self): -# self.residues -# self.peptides = [] -# self.mates = [] -# -#class peptide(object): -# def check_for_mate(self, other_peptide, dist_cutoff = 6.5): -# dist11 = find_distance(self.res1_CA,other_peptide.res1_CA) -# dist22 = find_distance(self.res2_CA,other_peptide.res2_CA) -# dist12 = find_distance(self.res1_CA,other_peptide.res2_CA) -# dist21 = find_distance(self.res2_CA,other_peptide.res1_CA) -# if dist11 <= dist_cutoff and dist22 <= dist_cutoff: -# self.mates.append(peptide_mate(other_peptide)) -# elif dist12 <= dist_cutoff and dist21 <= dist_cutoff: -# self.mates.append(peptide_mate(other_peptide)) -# else: -# pass -# -# def __init__(self, residue): -# self.dist_cutoff = 6.5 -# self.res1 = residue -# self.res1_CA = residue.getatomxyz("CA") -# self.res2 = residue.nextres -# self.res2_CA = res2.getatomxyz("CA") -# self.mates = [] -# self.nextpep = None -# self.prevpep = None -# -#class peptide_mate(object): -# def __init__(self, peptide): -# self.peptide = peptide -# -#def find_distance(point1,point2): -# return cablam_math.veclen(cablam_math.vectorize(point1,point2)) -# -#def get_strands(motifs): -# strands = [] -# for motif in motifs: -# if motif.motif_type == 'sheet': -# strand = beta_strand() -# start = motif.motif_start -# end = motif.motif_end -# curres = start -# strand.members.append(start) -# prevpep = None -# while curres is not end: -# peptide = peptide(curres) -# if prevpep: -# peptide.prevpep = prevpep -# prevpep.nextpep = peptide -# strand.peptides.append(peptide) -# curres = curres.nextres -# prevpep = peptide -# strand.residues.append(curres) -# strands.append(strand) -# return strands diff --git a/mmtbx/cablam/fingerprints/__init__.py b/mmtbx/cablam/fingerprints/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/mmtbx/cablam/fingerprints/alpha_helix_3_full.pickle b/mmtbx/cablam/fingerprints/alpha_helix_3_full.pickle deleted file mode 100644 index d7410f4db0d781ffced89f6fec8efed01b8dbc6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1016 zcma)**>BT85XPI5)8ry8S6iBJv~@W`q1;!wDUB4K_A#>7@g`%*N5*SIcvuPE;{O>b ztk(%bL{WLNHU7T&ezUXwvD$at&>Xk>)O4sjdl&=T8?s;&*j~sr*AMN1hME1JxGM0B zPAUQ8wiPkMqb}o^6__I#lQgI^0%`zr?6GlZ3?j$DJSR0CjbtyMGs6!o7GObOkrZb= zIF@>->8Df7^ctR(9A$wOoz$q~_}`di$ZrV>R(n_@<-W~jk`V^f<5=&KlIeSv;rd@0 zo+B$HXL}YKV?(}HP3n1n`PX{5PI8Hyq;bV=Z4ozxYRVcLTz=+lr{ zxDk_lnuD8hGB-wcAnRKbQVN5ik>XsDI7J@x4I26`Zj)^5ORI&=RFc#qv18lbzR^MofN3|UA5kcNr5x8Y#!onCrgS+Rh{0R3_X^iI?<$fuGxa zBi)puT#=D0^cr#DbjZ; p?7hGbOG!Tp{IpVZX(k>iKB9oEy7goP3b|4>_?ca(2U7!E} diff --git a/mmtbx/cablam/fingerprints/alpha_helix_3hs.pickle b/mmtbx/cablam/fingerprints/alpha_helix_3hs.pickle deleted file mode 100644 index 1544b6c0601b97d32bd0e2ac4ec0bd363b228587..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 827 zcmaizTW`}q5JsEQ+)Qq?<<^!q(3ZLs!lm5d2OyBb(>_|OwY|w$itWs<4dG!Wc#Hot zQW)C_LI@PelC9bCoU@Jd0ZrMh=**e|DoTRai?>wDE`vbU^TeIwAi)4-G!Dp#xp$4S_<3Z8{yW1G_-64j|9#vB4)c>}9Z@ z!ND9T062srpj|$N-20iqOB+rzC@tX(Y*?89q2V{|xxp8I!8TT`mj&yU!Poz0y(w64 Z4Ziz7YX}$f)RnCK3yKqu@1d5ugI_{JA;16t diff --git a/mmtbx/cablam/fingerprints/alpha_helix_3os.pickle b/mmtbx/cablam/fingerprints/alpha_helix_3os.pickle deleted file mode 100644 index 898568a98937a473f2d4d18b25798c44fd1a0489..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 818 zcmaiy*>BT85Qm$R)8wKpS6kX}l)4ncQEvDHkSe85`xvd(_9kN~UT1b~2oEd4Tl`-$ zwiAR9D3T>xfYZC&1G{7Fv9=!?BJo5EWw1YDEiYC9kK(TqZ?G*^3soQ& zxI>R!Pbl@r_q$`7l{mTKV$V0g9llD zY)nH<^}{7=C3?zBn|ox_G}`APi6cB>)xp(ZfX8JduNfSS@&0C^MChqZiZ%{DAg_lO zAGxd{)c2zGNyZvRVi1}HA755kGp`oIJ0<8Bg1XG1@H%srrJkURb*Pd`<;!xCPcAF0 zEorXtgbK7Bcuq;kf6h~j&s^w25BejZiNg-92JFHf&`gJr59_(b7cT5)aFD^_66o}B z1jj%}de@e}g_0ppOo diff --git a/mmtbx/cablam/fingerprints/antiparallel_beta.py b/mmtbx/cablam/fingerprints/antiparallel_beta.py deleted file mode 100644 index 89fb0fd07b..0000000000 --- a/mmtbx/cablam/fingerprints/antiparallel_beta.py +++ /dev/null @@ -1,337 +0,0 @@ -from __future__ import absolute_import, division, print_function -from mmtbx.cablam import cablam_fingerprints - -#Antiparallel beta, close -#Original by Christopher Williams, converted to new format by Danny Oh -#Two strands: -# g (h)* i* (j)* k -# r (q)* p* (o)* n - -antiparallel_beta_wcw = cablam_fingerprints.motif( - motif_name = "antiparallel_beta_wcw", - residue_names = {"i":"antiparallel_beta_close", "p":"antiparallel_beta_close"}) - -residue1 = antiparallel_beta_wcw.add_residue( - bond_move = 'p', - end_of_motif = False, - index = 'i') -bond1 = residue1.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'p') -bond1.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond2 = residue1.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'p') -bond2.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue2 = antiparallel_beta_wcw.add_residue( - sequence_move = 1, - end_of_motif = False, - index = 'p') -bond3 = residue2.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'i') -bond3.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond4 = residue2.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'i') -bond4.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue3 = antiparallel_beta_wcw.add_residue( - sequence_move = 1, - end_of_motif = False, - index = 'q') - -residue4 = antiparallel_beta_wcw.add_residue( - bond_move = 'g', - end_of_motif = False, - index = 'r') -bond5 = residue4.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'g') -bond5.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond6 = residue4.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'g') -bond6.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue5 = antiparallel_beta_wcw.add_residue( - sequence_move = 1, - end_of_motif = False, - index = 'g') -bond7 = residue5.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'r') -bond7.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond8 = residue5.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'r') -bond8.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue6 = antiparallel_beta_wcw.add_residue( - sequence_move = 2, - end_of_motif = False, - index = 'h') - -residue7 = antiparallel_beta_wcw.add_residue( - sequence_move = 1, - end_of_motif = False, - index = 'j') - -residue8 = antiparallel_beta_wcw.add_residue( - bond_move = 'n', - end_of_motif = False, - index = 'k') -bond9 = residue8.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'n') -bond9.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond10 = residue8.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'n') -bond10.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue9 = antiparallel_beta_wcw.add_residue( - sequence_move = 1, - end_of_motif = False, - index = 'n') -bond11 = residue9.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'k') -bond11.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond12 = residue9.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'k') -bond12.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue10 = antiparallel_beta_wcw.add_residue( - sequence_move = 1, - end_of_motif = False, - index = 'o') -residue11 = antiparallel_beta_wcw.add_residue( - end_of_motif = True, - index = 'p') -bond13 = residue11.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'i') -bond13.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond14 = residue11.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'i') -bond14.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -#------------------------------------------------------------------------------- - -#Antiparallel beta wide -#Original by Christopher Williams, converted to new format by Danny Oh -#Two strands: -# e (f) g* (h)* i* (j) k -# t (s) r* (q)* p* (o) n - -antiparallel_beta_cwc = cablam_fingerprints.motif( - motif_name = "antiparallel_beta_cwc", - residue_names = {"q":"antiparallel_beta_wide", "h":"antiparallel_beta_wide"}) - -residue1 = antiparallel_beta_cwc.add_residue( - bond_move = 'p', - end_of_motif = False, - index = 'i') -bond1 = residue1.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'p') -bond1.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond2 = residue1.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'p') -bond2.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue2 = antiparallel_beta_cwc.add_residue( - sequence_move = 1, - end_of_motif = False, - index = 'p') -bond3 = residue2.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'i') -bond3.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond4 = residue2.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'i') -bond4.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue3 = antiparallel_beta_cwc.add_residue( - sequence_move = 1, - end_of_motif = False, - index = 'q') - - -residue4 = antiparallel_beta_cwc.add_residue( - bond_move = 'g', - end_of_motif = False, - index = 'r') -bond5 = residue4.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'g') -bond5.add_target_atom( - atomname = ' O ', - anyseqdist = True) -bond6 = residue4.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'g') -bond6.add_target_atom( - atomname = ' H ', - anyseqdist = True) - -residue5 = antiparallel_beta_cwc.add_residue( - sequence_move = 1, - end_of_motif = False, - index = 'g') -bond7 = residue5.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'r') -bond7.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond8 = residue5.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'r') -bond8.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue6 = antiparallel_beta_cwc.add_residue( - sequence_move = 1, - end_of_motif = False, - index = 'h') - -residue7 = antiparallel_beta_cwc.add_residue( - sequence_move = 2, - end_of_motif = False, - index = 'i') -bond9 = residue7.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'p') -bond9.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond10 = residue7.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'p') -bond10.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue8 = antiparallel_beta_cwc.add_residue( - bond_move = 'n', - end_of_motif = False, - index = 'k') -bond11 = residue8.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'n') -bond11.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue9 = antiparallel_beta_cwc.add_residue( - sequence_move = 6, - end_of_motif = False, - index = 'n') -bond12 = residue9.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'k') -bond12.add_target_atom( - atomname = ' H ', - anyseqdist = True) - -residue10 = antiparallel_beta_cwc.add_residue( - bond_move = 'e', - end_of_motif = False, - index = 't') -bond13 = residue10.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'e') -bond13.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue11 = antiparallel_beta_cwc.add_residue( - sequence_move = 2, - end_of_motif = False, - index = 'e') -bond14 = residue11.add_bond( - required = True, - src_atom = ' O ', - trg_index = 't') -bond14.add_target_atom( - atomname = ' H ', - anyseqdist = True) - -residue12 = antiparallel_beta_cwc.add_residue( - end_of_motif = True, - index = 'g') - -if __name__ == "__main__": - cablam_fingerprints.make_pickle(antiparallel_beta_wcw) - cablam_fingerprints.make_pickle(antiparallel_beta_cwc) diff --git a/mmtbx/cablam/fingerprints/antiparallel_beta_bridge.py b/mmtbx/cablam/fingerprints/antiparallel_beta_bridge.py deleted file mode 100644 index 179a3b2dd5..0000000000 --- a/mmtbx/cablam/fingerprints/antiparallel_beta_bridge.py +++ /dev/null @@ -1,207 +0,0 @@ -from __future__ import absolute_import, division, print_function -from mmtbx.cablam import cablam_fingerprints - -#Antiparallel Beta Bridge/loose definitions, uses 4 bonds -#Original by Christopher Williams, converted to new format by Danny Oh -#Two strands: -# g (h) i (j) k -# r (q) p (o) n -antiparallel_beta_bridge_close = cablam_fingerprints.motif( - motif_name = "antiparallel_beta_bridge_close", - residue_names = {"i":"antiparallel_beta_bridge_close", "p":"antiparallel_beta_bridge_close"}) - -residue1 = antiparallel_beta_bridge_close.add_residue( - bond_move = 'p', - index = 'i') -bond1 = residue1.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'p') -bond1.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond2 = residue1.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'p') -bond2.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue2 = antiparallel_beta_bridge_close.add_residue( - sequence_move = 2, - index = 'p') -bond3 = residue2.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'i') -bond3.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond4 = residue2.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'i') -bond4.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue3 = antiparallel_beta_bridge_close.add_residue( - bond_move = 'g', - index = 'r') -bond5 = residue3.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'g') -bond5.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue4 = antiparallel_beta_bridge_close.add_residue( - sequence_move = 4, - index = 'g') -bond6 = residue4.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'r') -bond6.add_target_atom( - atomname = ' H ', - anyseqdist = True) - -residue5 = antiparallel_beta_bridge_close.add_residue( - bond_move = 'n', - index = 'k') -bond7 = residue5.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'n') -bond7.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue6 = antiparallel_beta_bridge_close.add_residue( - sequence_move = 2, - index = 'n') -bond8 = residue6.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'k') -bond8.add_target_atom( - atomname = ' H ', - anyseqdist = True) - -residue7 = antiparallel_beta_bridge_close.add_residue( - end_of_motif = True, - index = 'p') -bond9 = residue7.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'i') -bond9.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond10 = residue7.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'i') -bond10.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -#------------------------------------------------------------------------------- - -#Original by Christopher Williams, converted to new format by Danny Oh -#Two strands: -# (g) h i j (k) -# (r) q p o (n) - -antiparallel_beta_bridge_wide = cablam_fingerprints.motif( - motif_name = "antiparallel_beta_bridge_wide", - residue_names = {"i":"antiparallel_beta_bridge_wide", "p":"antiparallel_beta_bridge_wide"}) - -residue1 = antiparallel_beta_bridge_wide.add_residue( - sequence_move = 1, - index = 'i') - -residue2 = antiparallel_beta_bridge_wide.add_residue( - bond_move = 'o', - index = 'j') -bond1 = residue2.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'o') -bond1.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond2 = residue2.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'o') -bond2.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue3 = antiparallel_beta_bridge_wide.add_residue( - sequence_move = 1, - index = 'o') -bond3 = residue3.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'j') -bond3.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond4 = residue3.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'j') -bond4.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue4 = antiparallel_beta_bridge_wide.add_residue( - sequence_move = 1, - index = 'p') - -residue5 = antiparallel_beta_bridge_wide.add_residue( - bond_move = 'h', - index = 'q') -bond5 = residue5.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'h') -bond5.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond6 = residue5.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'h') -bond6.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue6 = antiparallel_beta_bridge_wide.add_residue( - sequence_move = 1, - index = 'h') -bond7 = residue6.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'q') -bond7.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond8 = residue6.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'q') -bond8.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue7 = antiparallel_beta_bridge_wide.add_residue( - end_of_motif = True, - index = 'i') -if __name__ == "__main__": - cablam_fingerprints.make_pickle(antiparallel_beta_bridge_close) - cablam_fingerprints.make_pickle(antiparallel_beta_bridge_wide) diff --git a/mmtbx/cablam/fingerprints/antiparallel_beta_bridge_close.pickle b/mmtbx/cablam/fingerprints/antiparallel_beta_bridge_close.pickle deleted file mode 100644 index bc6f52b054ae51f811c348061a6a7aa73671a9b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1451 zcma)+=~vT05Wp>RlnN9CFF>dV5In&9R=h>g;@c6Zw} zjqo0R>g#r9e!rR7?(ZJEUXQHJC7W6`T5o@tRnK>sXb8`b!a_ZWylMe*i+`X8VXr}k z1q(eVW~NW;EQDT!K7-^uGDH2yYfwRJHC8h%7E#j@p5rppt_2~3ev)hO{+JZQxFM^{ zBQp>V6EJ{~C;4{O5C$tyFn0H9#}{CqG#f$~Hb_yTgP+VXWQATbY(ujfG7k=D=i=^tU)L)l{8B>VR&o#+_T#)015zLoKULETBElB37 zWE!L(W0R1@t=OWm#Z`-^5KbF>vdO2Ke0qy3XFkIXF2&Apg*uC{WbnBrpD*(TKFiz5 zj10?iG4pNK+Qf313^BQupen!18wcl_5}|f`9^rz)M|hEsmiZXj!{wqHe4I~kxsZ#7 z*0_XlIjiAGjaj8}MQdC|xRz=diH1(Tj&NgpvhLxgPQHb3J55e|;LB@0yyJNXVWrD6 z=PFT=h~CwxdkFWlC^s3`1C4r!@Ms4V<;&%i^cdku7fDaVO+c#}^c3M)79^5^tZC45 zgcm8OGY|<{>rF{zg!L{`&R0EcB&e4f^$Ov27Ud^Bz0s(*2qZ;y#+U8s9m4xAlJ3b* zKp!;dBf_UFXd~(Avj%-ZsHC7wPhETZieUar>fEPqt@}g~tSqW?pKOhC5ZDeV?O8=| jw5~dAg|%I diff --git a/mmtbx/cablam/fingerprints/antiparallel_beta_bridge_wide.pickle b/mmtbx/cablam/fingerprints/antiparallel_beta_bridge_wide.pickle deleted file mode 100644 index b956b5a27d250002851032044c370e1a98d991a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1320 zcma)+S5wO9hX_~%Suk*TL@z69Z-?3}l*mP`;ewJ%ef5eJG)RfD; zfE%7~a~}f&d6sW44KS#qpzV*u(Gdz;)gn*L9N|;Y( z;T(LA-qoTkdO zQ~DKwtC`Y!;?BKJ=hrmlbY0*^x6_7nnvb1sDyLflw^OI(j*}AK5xBcotT68>@qK{@ zsW^+dmPlR1hbp%dw866u-1^KL5YM0%m9Rs~+BRNawY z39RiEt4Obv_>Dk06=x%5nqL=qo8eT=QwQ^1g85$HL$?z;m>-oB6Zn)mbz^=O__9~5 pFuyACH-Yb|IE$I>^M`=Go7358UIvo?BxlK$r>-~rlvkFu@(=n;wBG;# diff --git a/mmtbx/cablam/fingerprints/antiparallel_beta_cwc.pickle b/mmtbx/cablam/fingerprints/antiparallel_beta_cwc.pickle deleted file mode 100644 index 1b10ed9a74dcb43a33322c0b25e54ef26d58fb1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1928 zcma)-_j}V;6o#unmYc7Pn2`+`+nzKMGr>YRx5GV7G2wE+O6IXtL_I48MPxnNa9K>O#FHU#?glu zA#5?lbR=WnOQjXqEg54gVbl}`#BMuC{I(t0&8BQxj!bN8)%PUEgrU?}DrV!ftxpYO zX@!v|Ba9O!#6<737?U+r%$NK0>MM9%8%+_WO);yH;i~j3{kKdCGd0YLDc6rR$x0$S zh%r|clTH|TRx7+Gu}v6lG3p1NT*G!@_+rMfgJ9r<9X0F}qgg|YT{Y}}1+lESf;Y6) zn}oMaF~?SxWG?Gy=Ez<^>L{TT-n{kQdLYzy_T@9f7dq+?{zdH+wJ>=4@@`_0kPl7P_=xavS;N;F^O?pctnn$~vqHnnHMse6!WYBMoZ(Au{)+H*(OhIuOUs7p zdwxUscB3bHp5@9@gwq3+Mk9+9<&n;GBb_CjD_b@4$$rOH-xGe=#EK)GC;T|v%=5Uw z&C7&~MRR{1QY}@BM3)HF0Z*QMBiFp#)x1KuS|&yLTkk> z0@c3|(Oivl~FJZj^l`;+NsYCd0BPoAFc+C1=r4-$7 UCx0jLOzax|KDw(eo~O>@|D8N~?EnA( diff --git a/mmtbx/cablam/fingerprints/antiparallel_beta_wcw.pickle b/mmtbx/cablam/fingerprints/antiparallel_beta_wcw.pickle deleted file mode 100644 index 2ad38ccfb1094933eae10dbfcc0bd46cb6ad53a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1883 zcma)-_jl7s6ouD;G?PZ}By`b2-3lzQOE0Dl-3Un@dqix>SA_(2AHBr?HKUQ0k!;R^ zpL{%e_ucQlXL;TYIIUJ>FU&fY-LzWW53}xi4IZ=u*Neh(%a7c88Kr&iF+f;muaD||0Tyt$;1X-uf`X!DxsgSEziq!SY5>$Hkb%PtgT|*Pk<%GWvrJ}8weW>Hl?Uc z+pWieV@14%O&vCr`e1V>NsibJzmYxPH z%i64D-(qZAu`QB_`w0gOv8f|Acf^)OkuZyG!VnVdph&C^5oQgsyCe2g#9lEix?;}8 zWxJSr4o^36xWdM`T#H|q-{nsYM>^6X+3iunF+)snXE~+h7i#0+nGo&Vf;?`Lt_{jh7$it_^V&6GMrT6Q-sr6tTTwi*GgiE^KZhLUQTp5 zi;$MiME=BK?y_`j>FNNY%(9T~JgP370fgG16tim42~`bXAG35w2@-K2k*| zx}?X^(o&0OUf4!AU@B9C0A|kvgLM^@TZxz%#!g~!>O!R^9v0tnbeNy7jgfCj0 dPb3E~|NJ;huS0e9;VWC)f91_P^N^LZ-vBHgY62g=Xr~jgYLhSHzM$DkPLkd5ixvVYRlJ!#VKe zb5=7u-|SskKbO`WCp70K>xS7foZgS#u-zv2+rI6FLD}&_yHQ4I;un?@mT7F%=YefS zTz3tJ2Ut!R&{)Z4Yukozv|7BSn>;l1ddmwqRZnNTgFJ4?)et? zF+><7x*fiZPY+tT#pJ&6N-_*N2J6H*9DDdmL5qb`GvgMUWl?p0d zO}rLhR}H)WeNv&}H+iVGDPxZW+e_G|u|dQAthV0YVS{pJmK}sRP-R2$qB=fJW=_k@ z309WcL~?LGGL6U-am7P~!&T3Fw#Nx4G%+T|#pJLM3tmD)E9)8{iyA9 z(tYArgxCFIFX{EB+v_di-C{J=tESN26Z8zN*y{tqD4Lr|FH@Q81S>NadKE{&35^_T zsTto(Ct+=>QxpVyahgK?sM2N#tt>4?l>^V+EQjFclGM#=CP7~JP}&3(lj3()CHX2T zAcTKOQkW6pQ_<`shcc_obA->CIe#emH}wnQYd@z*C!JS*BT&E6PL;B{{5RsP`?*q| PCVXe3g%1yYMCRllDwtKm diff --git a/mmtbx/cablam/fingerprints/parallel_beta.py b/mmtbx/cablam/fingerprints/parallel_beta.py deleted file mode 100644 index 014ec9ab6d..0000000000 --- a/mmtbx/cablam/fingerprints/parallel_beta.py +++ /dev/null @@ -1,240 +0,0 @@ -from __future__ import absolute_import, division, print_function -from mmtbx.cablam import cablam_fingerprints - -#Parallel beta -#Original by Christopher Williams, converted to new format by Danny Oh -#Two strands: -# (g) h* i* j* (k) -# m (n) o* p* q* (r) s - -parallel_beta = cablam_fingerprints.motif( - motif_name = "parallel_beta", - residue_names = {"i":"parallel_beta_close", "p":"parallel_beta_wide"}) - -residue1 = parallel_beta.add_residue( - sequence_move = 1, - index = 'i') -bond1 = residue1.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'q') -bond1.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond2 = residue1.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'o') -bond2.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue2 = parallel_beta.add_residue( - sequence_move = 1, - index = 'j') - -residue3 = parallel_beta.add_residue( - bond_move = 's', - index = 'k') -bond3 = residue3.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'q') -bond3.add_target_atom( - atomname = ' O ', - anyseqdist = True) -bond4 = residue3.add_bond( - required = True, - src_atom = ' O ', - trg_index = 's') -bond4.add_target_atom( - atomname = ' H ', - anyseqdist = True) - -residue4 = parallel_beta.add_residue( - sequence_move = -2, - index = 's') -bond5 = residue4.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'k') -bond5.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue5 = parallel_beta.add_residue( - sequence_move = -1, - index = 'q') -bond6 = residue5.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'k') -bond6.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond7 = residue5.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'i') -bond7.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue6 = parallel_beta.add_residue( - sequence_move = -1, - index = 'p') - -residue7 = parallel_beta.add_residue( - sequence_move = -2, - index = 'o') -bond8 = residue7.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'i') -bond8.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond9 = residue7.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'g') -bond9.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue8 = parallel_beta.add_residue( - bond_move = 'g', - index = 'm') -bond10 = residue8.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'g') -bond10.add_target_atom( - atomname = ' H ', - anyseqdist = True) - -residue9 = parallel_beta.add_residue( - sequence_move = 1, - index = 'g') -bond11 = residue9.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'o') -bond11.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond12 = residue9.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'm') -bond12.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue10 = parallel_beta.add_residue( - sequence_move = 1, - index = 'h') - -residue11 = parallel_beta.add_residue( - end_of_motif = True, - index = 'i') - -#------------------------------------------------------------------------------- - -#Parallel beta bridges -#Original by Christopher Williams, converted to new format by Danny Oh -#Two strands: -# (g) h i j (k) -# (n) o p q (r) - -parallel_beta_bridge = cablam_fingerprints.motif( - motif_name = "parallel_beta_bridge", - residue_names = {"i":"parallel_beta_bridge_close", "p":"parallel_beta_bridge_wide"}) - -residue1 = parallel_beta_bridge.add_residue( - sequence_move = 2, - index = 'i') -bond1 = residue1.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'q') -bond1.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond2 = residue1.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'o') -bond2.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue2 = parallel_beta_bridge.add_residue( - bond_move = 'q', - index = 'k') -bond3 = residue2.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'q') -bond3.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue3 = parallel_beta_bridge.add_residue( - sequence_move = -1, - index = 'q') -bond4 = residue3.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'k') -bond4.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond5 = residue3.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'i') -bond5.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue4 = parallel_beta_bridge.add_residue( - sequence_move = -1, - index = 'p') - -residue5 = parallel_beta_bridge.add_residue( - bond_move = 'g', - index = 'o') -bond6 = residue5.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'i') -bond6.add_target_atom( - atomname = ' H ', - anyseqdist = True) -bond7 = residue5.add_bond( - required = True, - src_atom = ' H ', - trg_index = 'g') -bond7.add_target_atom( - atomname = ' O ', - anyseqdist = True) - -residue6 = parallel_beta_bridge.add_residue( - sequence_move = 2, - index = 'g') -bond8 = residue6.add_bond( - required = True, - src_atom = ' O ', - trg_index = 'o') -bond8.add_target_atom( - atomname = ' H ', - anyseqdist = True) - -residue7 = parallel_beta_bridge.add_residue( - end_of_motif = True, - index = 'i') - -if __name__ == "__main__": - cablam_fingerprints.make_pickle(parallel_beta) - cablam_fingerprints.make_pickle(parallel_beta_bridge) diff --git a/mmtbx/cablam/fingerprints/parallel_beta_bridge.pickle b/mmtbx/cablam/fingerprints/parallel_beta_bridge.pickle deleted file mode 100644 index 06366d951b747670573bd4ec7da129be7549eca7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1374 zcma)+X;;%g6ox6XlnN9OR5qy_q%Mg2zHbOx+{V4eq?vYdXp_EK1V79<`i=f-y_q(o z11ErgaIfy!PT*&1ZeW))Nag>aTjGGm zhCJ@uR>*b7sBs@X61^Hr*=(wAct*9#tGdYpLpMF!s&Ktjb$yOLma4PKJqtE$i=#he zSwE~3l&W>tv$%(}!~jdTU_LTM9MtyLZPjNmNWw!B!y3zymAk<$oqmg)ku73`4VG-5 zNP6HIj*rm-8!%nR(rfNdjxpB7dTqzzn>Z9j8#WEcX}e&&hzZsk)%!SH#F78-ii$Hh zN>Y;&QyLplQo3oEL$726+`@E&^))$|X+*&h+8&+HZn1&DtLROiV=M)h_PvsB1a1v; ztS7gY%OTgSiOzf+FXF`hlL`#4!UJ_p1}91El*DO`^&8GFb@hCM_0#Gs+Yhi%VCm>k zjZY)yGBNWkL$z_qnXS+?LQ_N$&q|!r#B@W3|+YTx<{{+U+HY%bLiF5iwd2V>A^(t6CT1 zVnWbLt|*VI64yFC5PMu#9ycUz?%`pGrGnTd-IBQ7M(T<{h(UKWMY=0-uamS+q+FEv zz9K!4c$kp#abnf{NaAs4vmI+bQO!>!o+Zu6xWv-RU-~4f&n1?3s@7YoyNX{(th5!U zDp4>u4z}71_EO^2ZZ{RIpxo9ZUMFsy!QM!`?QE{Z!QQFn_Yy2=ZV%Qr{|^!$+dS3$ zE3xJ$HNnpkUphh21E(y%D$qBHVglN>q(!fGC*%7rq3xP9};EQ>Aa4A8lc0 zmbKUgr7EdZ_4M@jb!TdR_V`hxyzOP5c?}lre%x9p>pa;?La9p~CaIUy?>-0*O%K!(!@?oN5!RJ!(1P8(LV6P&ZY1c5tkt&WlhxfRfZ)2Id9MgErfii0} z;_p0gX{~4!$E!F2!+w|&$yEuHDNb&{kQd9qjpA<{kHZn@4`sl&@kB9?QIAQvr@&Md zr=h>dPw`|GPaUpR%f?Ca=oyYB|cL;z?mEdS{R(oi@q@n6N*=wFr<>Y z+tN8lW~DUoU8dp)=b*2$S*hTBE2W5~c)p4k4i{1^sdHt@*m#k=E@^Ze7-aH?DZP-x zV9GHFQ-zn;d!bZB&GZ%tx=PR`uqnBnb0yC_Mh}coB;(TOtx+zoTQE%L$Bku=g!_9|dj Date: Thu, 7 Mar 2024 11:08:50 -0800 Subject: [PATCH 187/748] mmtbx: remove deleted SConscript - clean clutter --- iotbx/command_line/pdb_cif_conversion.py | 4 ++-- libtbx/test_utils/__init__.py | 4 ++-- mmtbx/SConscript | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/iotbx/command_line/pdb_cif_conversion.py b/iotbx/command_line/pdb_cif_conversion.py index 01717a8c76..66798e4e41 100644 --- a/iotbx/command_line/pdb_cif_conversion.py +++ b/iotbx/command_line/pdb_cif_conversion.py @@ -98,8 +98,8 @@ recommended that each standard test using models should either be duplicated and run with non-PDB-compliant models, or run twice in the same script, once as-is, and once after converting models to - non-PDB-compliant models. The tool convert_pdb_to_cif_for_pdb_str - can be used to edit strings in place in tests so that identical + non-PDB-compliant models. The tool convert_pdb_to_cif_for_pdb_str + can be used to edit strings in place in tests so that identical starting strings can be used in the original and non-PDB-compliant tests. =========================================================================== diff --git a/libtbx/test_utils/__init__.py b/libtbx/test_utils/__init__.py index d738d8e7dc..d1950c87ff 100644 --- a/libtbx/test_utils/__init__.py +++ b/libtbx/test_utils/__init__.py @@ -848,7 +848,7 @@ def exercise(): assert precision_approx_equal(0.799999,0.800004,precision=18)==False print("OK") -def convert_pdb_to_cif_for_pdb_str(locals, chain_addition = "ZXLONG", +def convert_pdb_to_cif_for_pdb_str(locals, chain_addition = "ZXLONG", key_str="pdb_str", hetatm_name_addition = "ZY", print_new_string = True): # Converts all the strings that start with "pdb_str" from PDB to mmcif # format, adding chain_addition to chain names @@ -868,7 +868,7 @@ def convert_pdb_to_cif_for_pdb_str(locals, chain_addition = "ZXLONG", for chain in model.chains(): chain.id = "%s%s" %(chain.id.strip(),chain_addition) if hetatm_name_addition: - for rg in chain.residue_groups(): + for rg in chain.residue_groups(): for ag in rg.atom_groups(): for at in ag.atoms(): if at.hetero and len(ag.resname)<=3: diff --git a/mmtbx/SConscript b/mmtbx/SConscript index 0b27a56b19..0998369319 100644 --- a/mmtbx/SConscript +++ b/mmtbx/SConscript @@ -28,7 +28,6 @@ if not libtbx.env.module_is_installed("mmtbx"): SConscript("geometry_restraints/SConscript") SConscript("secondary_structure/SConscript") SConscript("den/SConscript") - SConscript("cablam/SConscript") SConscript("geometry/SConscript") SConscript("rotamer/SConscript") SConscript("validation/SConscript") From 3dd69dc8f9d165e423503fa2bbf674a759c0dfa3 Mon Sep 17 00:00:00 2001 From: David Moreau Date: Thu, 7 Mar 2024 11:57:25 -0800 Subject: [PATCH 188/748] Ev11 mll (#958) * Reformulated EV11 error model. This reformulation of the EV11 error model is designed to be more robust to outlier intensities. * Reformulation of the EV11 to accomodate outliers. * Edits to enable a formulated EV11 model * Use cc determined after post refinement. * Updated with correct variances * Edits to finalize the MLL error model * Final updates for ev11_mll * clean clutter * Merge Ev11 and Ev11 MLL into a single algorithm * New overall scaling methods * Reformulation of error model * Correct math error in overall scaling. * Restore lost phil statements for clustering * Bugfix for cctbx.xfel.mpi_integrate (doesn't have the merging scope being tested here in merge.py) * Refactor calculate_intensity_bin_limits_mll for large datasets When gathering a ton of data to a single node, the MPI pickle limit can get it when using lowercase gather. Instead, preallocate a numpy array and use MPI Gatherv. * Corrected conflicts * Fixed conflicts * Adding mm24 specific errors file * Removed unnecessary code * Removed unnecessary portions of diagnostic plotting * Removed unneccesary edits * Matching original file * Reverted minor change * Stylistic changes * Added to py2 syntax exceptions * Updates to pass tests * Fixed math and random seed errors Math: The initialization algorithm had incorrect math Random seed: added a random seed that can be set from the phil file * Edits after Aaron Brewster's code review * Updates to large gather and reproducibility to random subsampling * Clean clutter * bug fix * Update phil strings --------- Co-authored-by: Aaron Brewster --- .azure-pipelines/py2_syntax_exceptions.txt | 1 + .../application/errors/error_modifier_mm24.py | 800 ++++++++++++++++++ xfel/merging/application/errors/factory.py | 3 + xfel/merging/application/mpi_helper.py | 10 + xfel/merging/application/phil/phil.py | 47 +- .../postrefine/postrefinement_rs.py | 21 +- .../postrefine/postrefinement_rs2.py | 20 +- .../application/scale/experiment_scaler.py | 3 +- xfel/merging/command_line/merge.py | 7 + 9 files changed, 903 insertions(+), 9 deletions(-) create mode 100644 xfel/merging/application/errors/error_modifier_mm24.py diff --git a/.azure-pipelines/py2_syntax_exceptions.txt b/.azure-pipelines/py2_syntax_exceptions.txt index 7ccaa19222..1c33954913 100644 --- a/.azure-pipelines/py2_syntax_exceptions.txt +++ b/.azure-pipelines/py2_syntax_exceptions.txt @@ -13,6 +13,7 @@ xfel/ui/db/job.py xfel/command_line/cxi_mpi_submit.py xfel/command_line/fee_calibration.py xfel/util/drift.py +xfel/merging/application/errors/error_modifier_mm24.py xfel/util/preference.py cctbx/maptbx/qscore.py cctbx/maptbx/tst_qscore.py diff --git a/xfel/merging/application/errors/error_modifier_mm24.py b/xfel/merging/application/errors/error_modifier_mm24.py new file mode 100644 index 0000000000..1d36656065 --- /dev/null +++ b/xfel/merging/application/errors/error_modifier_mm24.py @@ -0,0 +1,800 @@ +from __future__ import absolute_import, division, print_function +from dials.array_family import flex +import math +import numpy as np +import os +import scipy.optimize +from scipy.special import gamma +from scipy.special import polygamma +import scipy.stats +from xfel.merging.application.worker import worker +from xfel.merging.application.reflection_table_utils import reflection_table_utils + +class error_modifier_mm24(worker): + def __init__(self, params, mpi_helper=None, mpi_logger=None): + super(error_modifier_mm24, self).__init__(params=params, mpi_helper=mpi_helper, mpi_logger=mpi_logger) + if not self.params.merging.error.mm24.expected_gain is None: + self.expected_sf = math.sqrt(self.params.merging.error.mm24.expected_gain) + else: + self.expected_sf = None + if self.params.merging.error.mm24.n_max_differences is None: + self.limit_differences = True + else: + self.limit_differences = False + + self.n_coefs = self.params.merging.error.mm24.n_degrees + 1 + self.tuning_param = self.params.merging.error.mm24.tuning_param + self.number_of_intensity_bins = self.params.merging.error.mm24.number_of_intensity_bins + if self.params.merging.error.mm24.cc_after_pr: + self.cc_key = 'correlation_after_post' + else: + self.cc_key = 'correlation' + + def __repr__(self): + return 'Adjust intensity errors -- mm24' + + def run(self, experiments, reflections): + '''Modify intensity errors according to Mittan-Moreau 202X''' + assert self.params.merging.error.model == "mm24" + self.logger.log_step_time("ERROR_MODIFIER_MM24") + self.logger.log("Modifying intensity errors -- mm24 method (starting with %d reflections)"%(len(reflections))) + reflections = self.modify_errors(reflections) + self.logger.log_step_time("ERROR_MODIFIER_MM24", True) + return experiments, reflections + + def modify_errors(self, reflections): + # First set up a reflection table to do work downstream. + reflections = self.setup_work_arrays(reflections) + # Now moving to intensities, find the bin limits using global min/max of the means of each reflection + self.calculate_intensity_bin_limits() + # Once bin limits are determined, assign intensities on each rank to appropriate bin limits + self.distribute_differences_over_intensity_bins() + self.initialize_ev11_params() + # Run LBFGSB minimizer + # -- only rank0 does minimization but gradients/functionals are calculated using all rank + self.run_minimizer() + if self.params.merging.error.mm24.do_diagnostics: + self.plot_diagnostics(reflections) + # Finally update the variances of each reflection as per Eq (10) in Brewster et. al (2019) + reflections['intensity.sum.variance'] = self._get_var_ev11( + reflections['intensity.sum.variance'], + reflections['biased_mean'], + reflections[self.cc_key] + ) + del reflections['biased_mean'] + return reflections + + def setup_work_arrays(self, reflections): + self.work_table = flex.reflection_table() + self.refl_biased_means = [] + biased_mean = flex.double() # Go with the pairwise differences in self.work_table + biased_mean_to_reflections = flex.double() # Put into the original reflection table + self.biased_mean_count = flex.double() # Used to calculate the number of reflections in each intensity bin + pairwise_differences = flex.double() + pairwise_differences_normalized = flex.double() + counting_stats_var_i = flex.double() + counting_stats_var_j = flex.double() + correlation_i = flex.double() + correlation_j = flex.double() + number_of_reflections = 0 + + for refls in reflection_table_utils.get_next_hkl_reflection_table(reflections): + number_of_measurements = refls.size() + # if the returned "refls" list is empty, it's the end of the input "reflections" list + if number_of_measurements == 0: + break + refls_biased_mean = flex.double(len(refls), flex.mean(refls['intensity.sum.value'])) + biased_mean_to_reflections.extend(refls_biased_mean) + self.refl_biased_means.append(refls_biased_mean[0]) + if number_of_measurements > self.params.merging.minimum_multiplicity: + I = refls['intensity.sum.value'].as_numpy_array() + var_cs = refls['intensity.sum.variance'].as_numpy_array() + correlation = refls[self.cc_key].as_numpy_array() + number_of_reflections += I.size + self.biased_mean_count.extend(flex.double(I.size, refls_biased_mean[0])) + indices = np.triu_indices(n=I.size, k=1) + N = indices[0].size + if self.limit_differences == False: + if N > self.params.merging.error.mm24.n_max_differences: + # random number generation needs to be consistent between symmetry related reflections + # for reproducibility + rng = np.random.default_rng(seed=self.params.merging.error.mm24.random_seed) + # Reflections are in different order when run with different numbers of ranks + sort_indices = np.argsort(I) + rng.shuffle(sort_indices) + I = I[sort_indices] + var_cs = var_cs[sort_indices] + correlation = correlation[sort_indices] + # this option is for performance trade-offs + if N > 1000: + subset_indices = rng.choice( + N, + size=self.params.merging.error.mm24.n_max_differences, + replace=False, + shuffle=False + ) + else: + subset_indices = rng.permutation(N)[:self.params.merging.error.mm24.n_max_differences] + indices = (indices[0][subset_indices], indices[1][subset_indices]) + N = self.params.merging.error.mm24.n_max_differences + differences = flex.double(np.abs(I[indices[0]] - I[indices[1]])) + pairwise_differences.extend(differences) + biased_mean.extend(flex.double(N, refls_biased_mean[0])) + counting_stats_var_i.extend(flex.double(var_cs[indices[0]])) + counting_stats_var_j.extend(flex.double(var_cs[indices[1]])) + correlation_i.extend(flex.double(correlation[indices[0]])) + correlation_j.extend(flex.double(correlation[indices[1]])) + + self.work_table['pairwise_differences'] = pairwise_differences + self.work_table['biased_mean'] = biased_mean + self.work_table['counting_stats_var_i'] = counting_stats_var_i + self.work_table['counting_stats_var_j'] = counting_stats_var_j + self.work_table['correlation_i'] = correlation_i + self.work_table['correlation_j'] = correlation_j + reflections['biased_mean'] = biased_mean_to_reflections + + self.logger.log(f"Number of work reflections selected: {number_of_reflections}") + return reflections + + def calculate_intensity_bin_limits(self): + '''Calculate the intensity bins between the 0.5 and 99.5 percentiles''' + all_biased_means = self.mpi_helper.gather_variable_length_numpy_arrays( + np.array(self.refl_biased_means, dtype=float), root=0, dtype=float + ) + if self.mpi_helper.rank == 0: + all_biased_means = np.sort(all_biased_means) + lower_percentile = 0.005 + upper_percentile = 0.995 + n = all_biased_means.size + lower = all_biased_means[int(lower_percentile * n)] + upper = all_biased_means[int(upper_percentile * n)] + self.intensity_bin_limits = np.linspace(lower, upper, self.number_of_intensity_bins + 1) + else: + self.intensity_bin_limits = np.empty(self.number_of_intensity_bins + 1) + self.mpi_helper.comm.Bcast(self.intensity_bin_limits, root=0) + + def distribute_differences_over_intensity_bins(self): + self.intensity_bins = [flex.reflection_table() for i in range(self.number_of_intensity_bins)] + self.n_differences_in_bin = flex.double(self.number_of_intensity_bins, 0) + self.n_refls_in_bin = flex.double(self.number_of_intensity_bins, 0) + self.bin_weighting = flex.double(self.number_of_intensity_bins, 0) + count = self.work_table.size() + for bin_index in range(self.number_of_intensity_bins): + subset_work_table = self.work_table.select( + (self.work_table['biased_mean'] >= self.intensity_bin_limits[bin_index]) + & (self.work_table['biased_mean'] < self.intensity_bin_limits[bin_index + 1]) + ) + self.intensity_bins[bin_index].extend(subset_work_table) + self.n_differences_in_bin[bin_index] = self.mpi_helper.comm.allreduce( + len(subset_work_table), self.mpi_helper.MPI.SUM + ) + + subset_biased_mean = self.biased_mean_count.select( + (self.biased_mean_count >= self.intensity_bin_limits[bin_index]) + & (self.biased_mean_count < self.intensity_bin_limits[bin_index + 1]) + ) + self.n_refls_in_bin[bin_index] = self.mpi_helper.comm.allreduce( + len(subset_biased_mean), self.mpi_helper.MPI.SUM + ) + if self.n_differences_in_bin[bin_index] > 0: + self.bin_weighting[bin_index] = math.sqrt(self.n_refls_in_bin[bin_index]) / self.n_differences_in_bin[bin_index] + + # for debugging + number_of_differences_distributed = 0 + for intensity_bin in self.intensity_bins: + number_of_differences_distributed += intensity_bin.size() + self.logger.log( + "Distributed over intensity bins %d out of %d differences" + % (number_of_differences_distributed, count) + ) + + def initialize_ev11_params(self): + mean_differences = np.zeros(self.number_of_intensity_bins) + for bin_index, differences in enumerate(self.intensity_bins): + summation = self.mpi_helper.comm.reduce( + flex.sum(differences['pairwise_differences']), op=self.mpi_helper.MPI.SUM, root=0 + ) + counts = self.mpi_helper.comm.reduce( + len(differences['pairwise_differences']), op=self.mpi_helper.MPI.SUM, root=0 + ) + if self.mpi_helper.rank == 0: + mean_differences[bin_index] = summation / counts + + if self.mpi_helper.rank == 0: + def fitting_equation(params, y0, return_jac): + sf = params[0] + sadd = params[1] + prefactor = 2 / np.sqrt(np.pi) + arg = sf**2 * (x + sadd**2 * x**2) + curve = prefactor * np.sqrt(arg) + y0 + if return_jac: + darg_dsf = 2 * sf * (x + sadd**2 * x**2) + darg_dsadd = 2 * sf**2 * sadd * x**2 + dcurve_darg = 1/2 * prefactor/np.sqrt(arg) + dcurve_dsf = dcurve_darg * darg_dsf + dcurve_dsadd = dcurve_darg * darg_dsadd + return curve, dcurve_dsf, dcurve_dsadd + else: + return curve + + def target_fun_bfgs(params, x, y): + curve, dcurve_dsf, dcurve_dsadd = fitting_equation(params, y[0], True) + arg = (curve - y) / y + darg_dcurve = 1 / y + loss = 0.5 * np.sum(arg**2) + dloss_dsf = np.sum(arg * darg_dcurve * dcurve_dsf) + dloss_dsadd = np.sum(arg * darg_dcurve * dcurve_dsadd) + return loss, (dloss_dsf, dloss_dsadd) + + def target_fun_scalar(sadd, x, y): + curve = fitting_equation([self.expected_sf, sadd], y[0], False) + arg = (curve - y) / y + darg_dcurve = 1 / y + loss = 0.5 * np.sum(arg**2) + return loss + + bin_centers = (self.intensity_bin_limits[1:] + self.intensity_bin_limits[:-1]) / 2 + positive_indices = bin_centers > 0 + x = bin_centers[positive_indices] + y = mean_differences[positive_indices] + good_indices = np.invert(np.isnan(y)) + x = x[good_indices] + y = y[good_indices] + + self.sadd = [0 for i in range(self.n_coefs)] + if self.expected_sf is None: + results = scipy.optimize.minimize( + target_fun_bfgs, + x0=(1, 1), + args=(x, y), + jac=True, + method='BFGS' + ) + self.sfac = abs(float(results.x[0])) + self.sadd[0] = abs(float(results.x[1])) + fit_curve = fitting_equation(results.x, y[0], False) + else: + results = scipy.optimize.minimize_scalar( + target_fun_scalar, + bounds=(0, 10), + args=(x, y), + ) + self.sfac = self.expected_sf + self.sadd[0] = abs(float(results.x)) + + if self.params.merging.error.mm24.do_diagnostics: + import matplotlib.pyplot as plt + fit_curve = fitting_equation([self.sfac, self.sadd[0]], y[0], False) + fig, axes = plt.subplots(1, 1, figsize=(5, 3)) + axes.plot( + bin_centers, mean_differences, + linestyle='none', marker='.', color=[0, 0, 0], label='Data' + ) + axes.plot(x, fit_curve, color=[0, 0.8, 0], label='Initialization') + axes.legend() + fig.tight_layout() + fig.savefig(os.path.join( + self.params.output.output_dir, + self.params.output.prefix + '_initial_differences.png' + )) + plt.close() + + else: + self.sfac = 0 + self.sadd = [0 for i in range(self.n_coefs)] + self.sfac = self.mpi_helper.comm.bcast(self.sfac, root=0) + self.sadd = self.mpi_helper.comm.bcast(self.sadd, root=0) + + def run_minimizer(self): + from scitbx import lbfgsb + + comm = self.mpi_helper.comm + MPI = self.mpi_helper.MPI + size = self.mpi_helper.size + + if self.params.merging.error.mm24.tuning_param_opt: + param_offset = 2 + param_shift = 1 + self.x = flex.double([self.tuning_param, self.sfac, *self.sadd]) + else: + param_offset = 1 + param_shift = 0 + self.x = flex.double([self.sfac, *self.sadd]) + self.n = self.n_coefs + param_offset + if self.mpi_helper.rank == 0: + self.logger.main_log( + 'Initial Parameter Estimates = ' + + f'sfac: {self.sfac} ' + + f'sadd: {self.sadd[0]} ' + + f'nu: {self.tuning_param} ' + ) + l = flex.double(self.n, 1e-8) + u = flex.double(self.n, 0) + if self.params.merging.error.mm24.tuning_param_opt: + # normalization for the truncated t-distribution is numerically unstable for nu < 2 + l[0] = 2 + if self.x[0] < 2: + self.x[0] = 2 + for degree_index in range(self.n_coefs): + l[degree_index + param_offset] = -1000 + if self.mpi_helper.rank == 0: + self.minimizer = lbfgsb.minimizer( + n = self.n, + l = l, + u = u, + nbd = flex.int(self.n, 1), + ) + while True: + self.compute_functional_and_gradients() + status = -1 + if self.mpi_helper.rank == 0: + if self.minimizer.process(self.x, self.L, self.g): + if self.params.merging.error.mm24.tuning_param_opt: + self.tuning_param = self.x[0] + tuning_param = f'{self.tuning_param:0.3f}' + self.sfac = self.x[0 + param_shift] + self.sadd = self.x[1 + param_shift:] + sfac = f'{self.sfac:0.3f}' + sadd = [f'{self.sadd[i]:0.3f}' for i in range(self.n_coefs)] + log_out = 'intermediate minimization results = '\ + + f'loss: {self.L:.2f} '\ + + f'sfac: {sfac} '\ + + f'sadd: {sadd} ' + if self.params.merging.error.mm24.tuning_param_opt: + log_out += f'nu: {tuning_param}' + self.logger.main_log(log_out) + status = 1 + elif self.minimizer.is_terminated(): + status=0 + + comm.Barrier() + status = comm.bcast(status, root=0) + if status == 1: + self.tuning_param = comm.bcast(self.tuning_param, root=0) + self.sfac = comm.bcast(self.sfac, root=0) + self.sadd = comm.bcast(self.sadd, root=0) + pass + if status==0: + break + + if self.mpi_helper.rank == 0: + tuning_param = f'{self.tuning_param:0.3f}' + sfac = f'{self.sfac:0.3f}' + sadd = [f'{self.sadd[i]:0.3f}' for i in range(self.n_coefs)] + log_out = 'FINAL EV11 VALUES = '\ + + f'loss: {self.L:.2f} '\ + + f'sfac: {sfac} '\ + + f'sadd: {sadd} ' + if self.params.merging.error.mm24.tuning_param_opt: + log_out += f'nu: {tuning_param}' + self.logger.main_log(log_out) + + def compute_functional_and_gradients(self): + self.calculate_functional() + if self.mpi_helper.rank == 0: + if self.params.merging.error.mm24.tuning_param_opt: + self.g = flex.double([self.dL_dnu, self.dL_dsfac, *self.dL_dsadd]) + else: + self.g = flex.double([self.dL_dsfac, *self.dL_dsadd]) + + def verify_derivatives(self): + shift = 0.000001 + import copy + if self.params.merging.error.mm24.tuning_param_opt: + self.n = self.n_coefs + 3 + else: + self.n = self.n_coefs + 2 + + self.calculate_functional() + sfac = copy.copy(self.sfac) + sadd = copy.copy(self.sadd) + tuning_param = copy.copy(self.tuning_param) + if self.mpi_helper.rank == 0: + TF = copy.copy(self.L) + der_wrt_sfac = copy.copy(self.dL_dsfac) + der_wrt_sadd = copy.copy(self.dL_dsadd) + if self.params.merging.error.mm24.tuning_param_opt: + der_wrt_nu = copy.copy(self.dL_dnu) + + # Tuning param + if self.params.merging.error.mm24.tuning_param_opt: + self.tuning_param = tuning_param * (1 + shift) + self.calculate_functional() + if self.mpi_helper.rank == 0: + TF_p = copy.copy(self.L) + self.tuning_param = tuning_param * (1 - shift) + self.calculate_functional() + if self.mpi_helper.rank == 0: + TF_m = copy.copy(self.L) + self.tuning_param = tuning_param + if self.mpi_helper.rank == 0: + check_der_wrt_nu = (TF_p - TF_m) / (2 * shift * tuning_param) + print(f'der_wrt_nu numerical: {check_der_wrt_nu} analytical {der_wrt_nu}') + + # sfac + self.sfac = sfac * (1 + shift) + self.calculate_functional() + if self.mpi_helper.rank == 0: + TF_p = copy.copy(self.L) + self.sfac = sfac * (1 - shift) + self.calculate_functional() + if self.mpi_helper.rank == 0: + TF_m = copy.copy(self.L) + self.sfac = sfac + if self.mpi_helper.rank == 0: + check_der_wrt_sfac = (TF_p - TF_m) / (2 * shift * sfac) + print(f'der_wrt_sfac numerical: {check_der_wrt_sfac} analytical {der_wrt_sfac}') + + # sadd: + for degree_index in range(self.n_coefs): + if sadd[degree_index] == 0: + self.sadd[degree_index] = shift + else: + self.sadd[degree_index] = sadd[degree_index] * (1 + shift) + self.calculate_functional() + if self.mpi_helper.rank == 0: + TF_p = copy.copy(self.L) + if sadd[degree_index] == 0: + self.sadd[degree_index] = -shift + else: + self.sadd[degree_index] = sadd[degree_index] * (1 - shift) + self.calculate_functional() + if self.mpi_helper.rank == 0: + TF_m = copy.copy(self.L) + self.sadd[degree_index] = sadd[degree_index] + if self.mpi_helper.rank == 0: + if sadd[degree_index] == 0: + check_der_wrt_sadd = (TF_p - TF_m) / (2 * shift) + else: + check_der_wrt_sadd = (TF_p - TF_m) / (2 * shift * sadd[degree_index]) + print( + f'der_wrt_sadd - degree {degree_index} ' + + f'numerical: {check_der_wrt_sadd} ' + + f'analytical {der_wrt_sadd[degree_index]}' + ) + + def _loss_function_gaus(self, differences, var_i, var_j): + var = var_i + var_j + z = differences / flex.sqrt(var) + dz_dvar = -differences / (2 * var**(3/2)) + L1 = 1/2*flex.log(var) + dL1_dvar = 1/2 * 1/var + L2 = 1/2 * z**2 + dL2_dz = z + L = L1 + L2 + dL_dvar_x = dL1_dvar + dL2_dz * dz_dvar + return L, dL_dvar_x + + def _loss_function_t(self, differences, var_i, var_j): + v = self.tuning_param + var = var_i + var_j + z = differences / flex.sqrt(var) + dz_dvar = -differences / (2 * var**(3/2)) + arg = 1 + 1/v * z**2 + darg_dz = 2*z/v + + L1 = 1/2 * flex.log(var) + dL1_dvar = 1/2 * 1/var + L2 = (v+1)/2 * flex.log(arg) + dL2_darg = (v+1)/2 * 1/arg + dL2_dvar = dL2_darg * darg_dz * dz_dvar + L = L1 + L2 + dL_dvar_x = dL1_dvar + dL2_dvar + return L, dL_dvar_x + + def _loss_function_t_opt(self, differences, var_i, var_j): + v = self.tuning_param + var = var_i + var_j + z = differences / flex.sqrt(var) + dz_dvar = -differences / (2 * var**(3/2)) + arg = 1 + 1/v * z**2 + darg_dz = 2*z/v + darg_dv = -z**2 / v**2 + darg_dvar = darg_dz * dz_dvar + + L0 = -math.log(gamma((v+1)/2)) + dL0_dv = -float(polygamma(0, (v+1)/2) * 1/2) + + L1 = 1/2 * math.log(np.pi) + + L2 = 1/2 * math.log(v) + dL2_dv = 1 / (2*v) + + L3 = math.log(gamma(v/2)) + dL3_dv = float(polygamma(0, v/2) * 1/2) + + L4 = 1/2 * flex.log(var) + dL4_dvar = 1/2 * 1/var + + L5 = (v+1)/2 * flex.log(arg) + dL5_dvar = (v+1)/2 * 1/arg * darg_dvar + dL5_dv = 1/2 * flex.log(arg) + (v+1)/2 * 1/arg * darg_dv + + L = L0 + L1 + L2 + L3 + L4 + L5 + dL_dvar = dL4_dvar + dL5_dvar + dL_dv = dL0_dv + dL2_dv + dL3_dv + dL5_dv + return L, dL_dvar, dL_dv + + def _get_sadd(self, correlation): + sadd = flex.double(len(correlation), 0) + dsadd_dsaddi = [flex.double(len(correlation), 0) for i in range(self.n_coefs)] + for degree_index in range(self.n_coefs): + sadd += self.sadd[degree_index] * correlation**degree_index + dsadd_dsaddi[degree_index] = correlation**degree_index + return sadd, dsadd_dsaddi + + def _get_var_ev11(self, counting_err, biased_mean, correlation, return_der=False): + sadd, dsadd_dsaddi = self._get_sadd(correlation) + var = self.sfac**2 * (counting_err + sadd**2 * biased_mean**2) + if return_der: + dvar_dsfac = 2 * self.sfac * (counting_err + sadd**2 * biased_mean**2) + dvar_dsadd = 2 * self.sfac**2 * sadd * biased_mean**2 + return var, dvar_dsfac, dvar_dsadd, dsadd_dsaddi + else: + return var + + def calculate_functional(self): + comm = self.mpi_helper.comm + MPI = self.mpi_helper.MPI + L_bin_rank = flex.double(self.number_of_intensity_bins, 0) + dL_dsfac_bin_rank = flex.double(self.number_of_intensity_bins, 0) + dL_dsadd_bin_rank = [flex.double(self.number_of_intensity_bins, 0) for i in range(self.n_coefs)] + if self.params.merging.error.mm24.tuning_param_opt: + dL_dnu_bin_rank = flex.double(self.number_of_intensity_bins, 0) + + for bin_index, differences in enumerate(self.intensity_bins): + if len(differences) > 0: + var_i, dvar_i_dsfac, dvar_i_dsadd, dsadd_i_dsaddi = self._get_var_ev11( + differences['counting_stats_var_i'], + differences['biased_mean'], + differences['correlation_i'], + return_der=True + ) + var_j, dvar_j_dsfac, dvar_j_dsadd, dsadd_j_dsaddi = self._get_var_ev11( + differences['counting_stats_var_j'], + differences['biased_mean'], + differences['correlation_j'], + return_der=True + ) + + if self.params.merging.error.mm24.likelihood == 'normal': + L_in_bin, dL_dvar_x = self._loss_function_gaus( + differences['pairwise_differences'], var_i, var_j + ) + elif self.params.merging.error.mm24.likelihood == 't-dist': + if self.params.merging.error.mm24.tuning_param_opt: + L_in_bin, dL_dvar_x, dL_dnu = self._loss_function_t_opt( + differences['pairwise_differences'], var_i, var_j + ) + dL_dnu_bin_rank[bin_index] = flex.sum(dL_dnu) + else: + L_in_bin, dL_dvar_x = self._loss_function_t( + differences['pairwise_differences'], var_i, var_j + ) + L_bin_rank[bin_index] = flex.sum(L_in_bin) + dL_dsfac_bin_rank[bin_index] = flex.sum(dL_dvar_x * (dvar_i_dsfac + dvar_j_dsfac)) + for degree_index in range(self.n_coefs): + dL_dsadd_bin_rank[degree_index][bin_index] = flex.sum(dL_dvar_x * ( + dvar_i_dsadd * dsadd_i_dsaddi[degree_index] + dvar_j_dsadd * dsadd_j_dsaddi[degree_index] + )) + + L_bin = comm.reduce(L_bin_rank, MPI.SUM, root=0) + dL_dsfac_bin = comm.reduce(dL_dsfac_bin_rank, MPI.SUM, root=0) + dL_dsadd_bin = [None for i in range(self.n_coefs)] + for degree_index in range(self.n_coefs): + dL_dsadd_bin[degree_index] = comm.reduce(dL_dsadd_bin_rank[degree_index], MPI.SUM, root=0) + if self.params.merging.error.mm24.tuning_param_opt: + dL_dnu_bin = comm.reduce(dL_dnu_bin_rank, MPI.SUM, root=0) + + if self.mpi_helper.rank == 0: + self.L = flex.sum(self.bin_weighting * L_bin) + self.dL_dsfac = flex.sum(self.bin_weighting * dL_dsfac_bin) + self.dL_dsadd = [0 for i in range(self.n_coefs)] + for degree_index in range(self.n_coefs): + self.dL_dsadd[degree_index] = flex.sum(self.bin_weighting * dL_dsadd_bin[degree_index]) + if self.params.merging.error.mm24.tuning_param_opt: + self.dL_dnu = flex.sum(self.bin_weighting * dL_dnu_bin) + + def plot_diagnostics(self, reflections): + def get_rankits(n, down_sample, distribution): + prob_level = (np.arange(1, n+1) - 0.5) / n + if distribution == 'half normal': + return scipy.stats.halfnorm.ppf(prob_level[::down_sample]) + elif distribution == 'half t-dist': + prob_level = (prob_level + 1) / 2 + return scipy.stats.t.ppf(prob_level[::down_sample], df=self.tuning_param) + + # In intensity bins, the estimated std of I/sigma based on pairwise differences + # See Absolute pairwise differences: https://en.wikipedia.org/wiki/Robust_measures_of_scale + # Rousseeuw, Peter J.; Croux, Christophe (December 1993), + # "Alternatives to the Median Absolute Deviation", + # Journal of the American Statistical Association, 88 (424): 1273–1283 + # This gets the conversion factor from median pairwise differences to standard deviation + def min_fun_t(c, df): + term0 = scipy.stats.t.ppf(3/4, df=df) + term1 = scipy.stats.t.cdf(term0 + 1/c, df=df) + term2 = scipy.stats.t.cdf(term0 - 1/c, df=df) + term3 = 1/2 + diff = term1 - term2 - term3 + return diff**2 + if self.mpi_helper.rank == 0: + if self.params.merging.error.mm24.likelihood == 'normal': + conversion_factor = 1.1926 + elif self.params.merging.error.mm24.likelihood == 't-dist': + results = scipy.optimize.minimize_scalar( + min_fun_t, + bounds=(0.1, 2), + args=(self.tuning_param) + ) + conversion_factor = results.x + else: + conversion_factor = None + conversion_factor = self.mpi_helper.comm.bcast(conversion_factor) + median_differences = [[] for i in range(self.number_of_intensity_bins)] + for refls in reflection_table_utils.get_next_hkl_reflection_table(reflections): + number_of_reflections = refls.size() + if number_of_reflections == 0: + break + elif number_of_reflections > 1: + biased_mean = flex.mean(refls['intensity.sum.value']) + bin_index = np.searchsorted(self.intensity_bin_limits, biased_mean) - 1 + if biased_mean > self.intensity_bin_limits[0] and biased_mean < self.intensity_bin_limits[-1]: + I = refls['intensity.sum.value'].as_numpy_array() + var_ev11_flex = self._get_var_ev11( + refls['intensity.sum.variance'], + flex.double(len(refls), biased_mean), + refls[self.cc_key] + ) + var_ev11 = var_ev11_flex.as_numpy_array() + + # calculate the median difference for the pairwise differences + differences = np.abs(I[np.newaxis] - I[:, np.newaxis]) + variances = var_ev11[np.newaxis] + var_ev11[:, np.newaxis] + median_differences[bin_index].append( + np.median(differences / np.sqrt(variances), axis=1) + ) + binned_scale = np.zeros(self.number_of_intensity_bins) + for bin_index in range(self.number_of_intensity_bins): + if len(median_differences[bin_index]) > 0: + median_differences[bin_index] = np.concatenate(median_differences[bin_index]) + all_median_differences = self.mpi_helper.gather_variable_length_numpy_arrays( + np.array(median_differences[bin_index], dtype=float), root=0, dtype=float + ) + if self.mpi_helper.rank == 0: + binned_scale[bin_index] = np.median(all_median_differences) * conversion_factor + + # Get all the pairwise differences onto rank 0 for plotting + pairwise_differences = [] + for bin_index, differences in enumerate(self.intensity_bins): + if len(differences) > 0: + var_i = self._get_var_ev11( + differences['counting_stats_var_i'], + differences['biased_mean'], + differences['correlation_i'], + return_der=False + ) + var_j = self._get_var_ev11( + differences['counting_stats_var_j'], + differences['biased_mean'], + differences['correlation_j'], + return_der=False + ) + normalized_differences = differences['pairwise_differences'] / flex.sqrt(var_i + var_j) + pairwise_differences.append(normalized_differences.as_numpy_array()) + all_pairwise_differences = self.mpi_helper.gather_variable_length_numpy_arrays( + np.concatenate(pairwise_differences), root=0, dtype=float + ) + + if self.mpi_helper.rank == 0: + import matplotlib.pyplot as plt + sorted_pairwise_differences = np.sort(all_pairwise_differences) + lim = 5 + downsample = 10000 + I_scale = 100000 + grey1 = np.array([99, 102, 106]) / 255 + grey2 = np.array([177, 179, 179]) / 255 + + pairwise_differences_bins = np.linspace(0, lim, 101) + pairwise_differences_db = pairwise_differences_bins[1] - pairwise_differences_bins[0] + pairwise_differences_centers = (pairwise_differences_bins[1:] + pairwise_differences_bins[:-1]) / 2 + pairwise_differences_hist, _ = np.histogram( + sorted_pairwise_differences, bins=pairwise_differences_bins, density=True + ) + + fig, axes = plt.subplots(1, 3, figsize=(8, 3)) + axes[0].bar( + pairwise_differences_centers, pairwise_differences_hist, + width=pairwise_differences_db, label='$\omega_{hkl}$' + ) + axes[0].plot( + pairwise_differences_centers, + scipy.stats.halfnorm.pdf(pairwise_differences_centers), + color=grey1, label='Normal' + ) + if self.params.merging.error.mm24.likelihood == 't-dist': + axes[0].plot( + pairwise_differences_centers, + 2*scipy.stats.t.pdf(pairwise_differences_centers, df=self.tuning_param), + color=grey2, label=f't-dist\n$\\nu: ${self.tuning_param:0.1f}' + ) + + axes[0].legend(frameon=False, fontsize=8, handlelength=1) + axes[0].set_ylabel('Distribution of $\omega_{hbk}$') + axes[0].set_xlabel('Normalized PD ($\omega_{hbk}$)') + axes[0].set_xlim([0, 4.5]) + axes[0].set_xticks([0, 1, 2, 3, 4]) + + axes[1].plot([0, lim], [0, lim], color=[0, 0, 0], linewidth=1, linestyle=':') + axes[1].plot( + sorted_pairwise_differences[::downsample], + get_rankits(sorted_pairwise_differences.size, downsample, 'half normal'), + color=grey1 + ) + if self.params.merging.error.mm24.likelihood == 't-dist': + axes[1].plot( + sorted_pairwise_differences[::downsample], + get_rankits(sorted_pairwise_differences.size, downsample, 'half t-dist'), + color=grey2 + ) + + axes[1].set_ylim([0, lim]) + axes[1].set_ylabel('Rankits') + axes[1].set_xlabel('Sorted Normalized PD ($\omega_{hbk}$)') + axes[1].set_box_aspect(1) + axes[1].set_xticks([0, 1, 2, 3, 4]) + axes[1].set_yticks([0, 1, 2, 3, 4]) + axes[1].set_xlim([0, 4.5]) + axes[1].set_ylim([0, 4.5]) + + intensity_centers = (self.intensity_bin_limits[1:] + self.intensity_bin_limits[:-1]) / 2 + x = intensity_centers / I_scale + if self.params.merging.error.mm24.likelihood == 't-dist': + v = self.tuning_param + term0 = v / (v - 2) + term1 = 4*v / (np.pi * (v - 1)**2) + term2 = (gamma((v + 1) / 2) / gamma(v / 2))**2 + expected_sigma = np.sqrt(term0 - term1 * term2) + axes[2].plot([x[0], x[-1]], expected_sigma * np.ones(2), color=grey2) + axes[2].plot([x[0], x[-1]], np.sqrt(1 - 2/np.pi) * np.ones(2), color=[0, 0, 0]) + axes[2].plot(x, binned_scale, label='STD') + + axes[2].set_ylabel('Standard Deviation of $I_{hbk}/\sigma_{hbk}$') + axes[2].set_xlabel('Mean Intensity X 100,000') + fig.tight_layout() + fig.savefig(os.path.join( + self.params.output.output_dir, + self.params.output.prefix + '_PairwiseDifferences.png' + )) + plt.close() + + # Get the correlations for later plotting + cc_all = self.mpi_helper.gather_variable_length_numpy_arrays( + np.unique(self.work_table['correlation_i'].as_numpy_array()), root=0, dtype=float + ) + if self.mpi_helper.rank == 0: + # CC & sadd plots # + bins = np.linspace(cc_all.min(), cc_all.max(), 101) + dbin = bins[1] - bins[0] + centers = (bins[1:] + bins[:-1]) / 2 + hist_all, _ = np.histogram(cc_all, bins=bins) + + hist_color = np.array([0, 49, 60]) / 256 + line_color = np.array([213, 120, 0]) / 256 + sadd, _ = self._get_sadd(flex.double(centers)) + fig, axes_hist = plt.subplots(1, 1, figsize=(5, 3)) + axes_sadd = axes_hist.twinx() + axes_hist.bar(centers, hist_all / 1000, width=dbin, color=hist_color) + axes_sadd.plot(centers, (self.sfac * sadd)**2, color=line_color) + axes_hist.set_xlabel('Correlation Coefficient') + axes_hist.set_ylabel('Lattices (x1,000)') + axes_sadd.set_ylabel('$s_{\mathrm{fac}}^2 \\times s_{\mathrm{add}}^2$') + fig.tight_layout() + fig.savefig(os.path.join( + self.params.output.output_dir, + self.params.output.prefix + '_sadd.png' + )) + plt.close() + +if __name__ == '__main__': + from xfel.merging.application.worker import exercise_worker + exercise_worker(error_modifier) diff --git a/xfel/merging/application/errors/factory.py b/xfel/merging/application/errors/factory.py index 067f86444f..366439b9e0 100644 --- a/xfel/merging/application/errors/factory.py +++ b/xfel/merging/application/errors/factory.py @@ -2,6 +2,7 @@ from xfel.merging.application.errors.error_modifier_sr import error_modifier_sr from xfel.merging.application.errors.error_modifier_ev11 import error_modifier_ev11 from xfel.merging.application.errors.error_modifier_ha14 import error_modifier_ha14 +from xfel.merging.application.errors.error_modifier_mm24 import error_modifier_mm24 from xfel.merging.application.worker import factory as factory_base class factory(factory_base): @@ -18,4 +19,6 @@ def from_parameters(params, additional_info=[], mpi_helper=None, mpi_logger=None return [error_modifier_sr(params, mpi_helper, mpi_logger)] elif params.merging.error.model == "ev11": return [error_modifier_ev11(params, mpi_helper, mpi_logger)] + elif params.merging.error.model == "mm24": + return [error_modifier_mm24(params, mpi_helper, mpi_logger)] return [] diff --git a/xfel/merging/application/mpi_helper.py b/xfel/merging/application/mpi_helper.py index 87557e2906..c6ce22f61d 100644 --- a/xfel/merging/application/mpi_helper.py +++ b/xfel/merging/application/mpi_helper.py @@ -1,6 +1,7 @@ from __future__ import absolute_import, division, print_function from six.moves import range from libtbx.mpi4py import MPI +import numpy as np from dials.array_family import flex import sys @@ -86,3 +87,12 @@ def check_errors(self): sys.stderr.write("\nError reported by process %d: %s\n"%(error[0], error[1])) sys.stderr.flush() self.comm.Abort(1) + + def gather_variable_length_numpy_arrays(self, send_arrays, root=0, dtype=float): + lengths = self.comm.gather(send_arrays.size, root=root) + if self.rank == root: + gathered_arrays = np.empty(np.sum(lengths), dtype=dtype) + else: + gathered_arrays = None + self.comm.Gatherv(sendbuf=send_arrays, recvbuf=(gathered_arrays, lengths), root=root) + return gathered_arrays diff --git a/xfel/merging/application/phil/phil.py b/xfel/merging/application/phil/phil.py index b1e7eb988a..7076b11431 100644 --- a/xfel/merging/application/phil/phil.py +++ b/xfel/merging/application/phil/phil.py @@ -432,6 +432,10 @@ .type = choice .help = rs only, eta_deff protocol 7 .expert_level = 3 + partiality_threshold_hcfix = 0.2 + .type = float ( value_min = 0.0001 ) + .help = Throw out observations below this value. Hard coded as 0.2 for rs2 + .help = Minimum positive value is required because partiality appears in the denominator rs { fix = thetax thetay *RS G BFACTOR .type = choice(multi=True) @@ -478,14 +482,13 @@ .help = Spot radius for lower plot reflects partiality. Only implemented for rs_hybrid } """ - merging_phil = """ merging { minimum_multiplicity = 2 .type = int(value_min=2) .help = If defined, merged structure factors not produced for the Miller indices below this threshold. error { - model = ha14 *ev11 errors_from_sample_residuals + model = ha14 *ev11 mm24 errors_from_sample_residuals .type = choice .multiple = False .help = ha14, formerly sdfac_auto, apply sdfac to each-image data assuming negative @@ -513,6 +516,46 @@ .type = bool .help = If True, plot refinement steps during refinement. } + mm24 + .help = Maximum log-likelihood from Mittan-Moreau 2024 + { + expected_gain = None + .help = Expected gain used for s_fac initialization.\ + If None, initialize s_fac using routine. + .type = float + number_of_intensity_bins = 100 + .help = Number of intensity bins + .type = int + n_degrees = 2 + .help = s_add as a n_degree polynomial of the correlation coefficient + .type = int + tuning_param = 10 + .help = Tuning param for t-dist in maximum log likelihood + .type = float + n_max_differences = 100 + .help = Maximum number of pairwise differences per reflection.\ + If None, then do not limit the maximum number of differences + .type = int + random_seed = 50298 + .help = Seed used to establish the random number generator for\ + subsampling the pairwise differences. + .type = int + tuning_param_opt = False + .type = bool + .help = If True, optimize the t-distribution's tuning parameter + likelihood = normal *t-dist + .help = Choice for likelihood function. + .type = choice + .multiple = False + cc_after_pr = True + .type = bool + .help = If True - use correlation coefficient determined after post-refinement.\ + If False - use correlation coefficient determined before. \ + If post-refinement is not performed, must be False. + do_diagnostics = False + .type = bool + .help = Make diagnostic plots. + } } plot_single_index_histograms = False .type = bool diff --git a/xfel/merging/application/postrefine/postrefinement_rs.py b/xfel/merging/application/postrefine/postrefinement_rs.py index f096863bae..a5b2004614 100644 --- a/xfel/merging/application/postrefine/postrefinement_rs.py +++ b/xfel/merging/application/postrefine/postrefinement_rs.py @@ -173,6 +173,19 @@ def run(self, experiments, reflections): assert result_observations_original_index.size() == result_observations.size() assert result_matches.pairs().size() == result_observations_original_index.size() + # Calculate the correlation of each frame after corrections. + # This is used in the MM24 error model to determine a per frame level of error + if "correlation_after_post" in self.params.input.persistent_refl_cols: + I_observed = result_observations.data() + matches = miller.match_multi_indices( + miller_indices_unique = miller_set.indices(), + miller_indices = result_observations.indices() + ) + I_reference = flex.double([i_model.data()[pair[0]] for pair in matches.pairs()]) + I_invalid = flex.bool([i_model.sigmas()[pair[0]] < 0. for pair in matches.pairs()]) + I_weight = flex.double(len(result_observations.sigmas()), 1.) + I_weight.set_selected(I_invalid, 0.) + SWC_after_post = simple_weighted_correlation(I_weight, I_reference, I_observed) except (AssertionError, ValueError, RuntimeError) as e: error_detected = True reason = repr(e) @@ -203,9 +216,11 @@ def run(self, experiments, reflections): new_exp_reflections['intensity.sum.value.unmodified'] = exp_reflections_match_results['intensity.sum.value.unmodified'] new_exp_reflections['intensity.sum.variance.unmodified'] = exp_reflections_match_results['intensity.sum.variance.unmodified'] for key in self.params.input.persistent_refl_cols: - if key not in new_exp_reflections.keys(): + if not key in new_exp_reflections.keys() and key in exp_reflections_match_results.keys(): new_exp_reflections[key] = exp_reflections_match_results[key] - + if self.params.merging.error.model == 'mm24': + if "correlation_after_post" in self.params.input.persistent_refl_cols: + new_exp_reflections["correlation_after_post"] = flex.double(len(new_exp_reflections), SWC_after_post.corr) new_reflections.extend(new_exp_reflections) # report rejected experiments, reflections @@ -271,7 +286,7 @@ def result_for_cxi_merge(self): scaler = self.refinery.scaler_callable(self.parameterization_class(self.MINI.x)) if self.params.postrefinement.algorithm == "rs": - fat_selection = (self.refinery.lorentz_callable(self.parameterization_class(self.MINI.x)) > 0.2) + fat_selection = (self.refinery.lorentz_callable(self.parameterization_class(self.MINI.x)) > self.params.postrefinement.partiality_threshold_hcfix) fats = self.refinery.lorentz_callable(self.parameterization_class(self.MINI.x)) else: fat_selection = (self.refinery.lorentz_callable(self.parameterization_class(self.MINI.x)) < 0.9) diff --git a/xfel/merging/application/postrefine/postrefinement_rs2.py b/xfel/merging/application/postrefine/postrefinement_rs2.py index 468e65f2f0..5194ad387f 100644 --- a/xfel/merging/application/postrefine/postrefinement_rs2.py +++ b/xfel/merging/application/postrefine/postrefinement_rs2.py @@ -174,6 +174,19 @@ def run(self, experiments, reflections): assert result_observations_original_index.size() == result_observations.size() assert result_matches.pairs().size() == result_observations_original_index.size() + # Calculate the correlation of each frame after corrections. + # This is used in the MM24 error model to determine a per frame level of error + if "correlation_after_post" in self.params.input.persistent_refl_cols: + I_observed = result_observations.data() + matches = miller.match_multi_indices( + miller_indices_unique = miller_set.indices(), + miller_indices = result_observations.indices() + ) + I_reference = flex.double([i_model.data()[pair[0]] for pair in matches.pairs()]) + I_invalid = flex.bool([i_model.sigmas()[pair[0]] < 0. for pair in matches.pairs()]) + I_weight = flex.double(len(result_observations.sigmas()), 1.) + I_weight.set_selected(I_invalid, 0.) + SWC_after_post = simple_weighted_correlation(I_weight, I_reference, I_observed) except (AssertionError, ValueError, RuntimeError) as e: error_detected = True reason = repr(e) @@ -206,7 +219,9 @@ def run(self, experiments, reflections): for key in self.params.input.persistent_refl_cols: if key not in new_exp_reflections.keys(): new_exp_reflections[key] = exp_reflections_match_results[key] - + if self.params.merging.error.model == 'mm24': + if "correlation_after_post" in self.params.input.persistent_refl_cols: + new_exp_reflections["correlation_after_post"] = flex.double(len(new_exp_reflections), SWC_after_post.corr) new_reflections.extend(new_exp_reflections) # report rejected experiments, reflections @@ -284,8 +299,7 @@ def result_for_cxi_merge(self): partiality_array = self.refinery.get_partiality_array(values) p_scaler = flex.pow(partiality_array, 0.5*self.params.postrefinement.merge_partiality_exponent) - - fat_selection = (partiality_array > 0.2) + fat_selection = (partiality_array > self.params.postrefinement.partiality_threshold_hcfix) fat_count = fat_selection.count(True) scaler_s = scaler.select(fat_selection) p_scaler_s = p_scaler.select(fat_selection) diff --git a/xfel/merging/application/scale/experiment_scaler.py b/xfel/merging/application/scale/experiment_scaler.py index c0a4110a62..8976d72557 100644 --- a/xfel/merging/application/scale/experiment_scaler.py +++ b/xfel/merging/application/scale/experiment_scaler.py @@ -91,7 +91,8 @@ def run(self, experiments, reflections): ): exp_reflections['intensity.sum.value'] *= result.slope exp_reflections['intensity.sum.variance'] *= (result.slope**2) - + if self.params.merging.error.model == 'mm24': + exp_reflections['correlation'] = flex.double(len(exp_reflections), result.correlation) new_experiments.append(experiment) new_reflections.extend(exp_reflections) diff --git a/xfel/merging/command_line/merge.py b/xfel/merging/command_line/merge.py index f045308541..c763fd2263 100644 --- a/xfel/merging/command_line/merge.py +++ b/xfel/merging/command_line/merge.py @@ -218,6 +218,13 @@ def _resolve_persistent_columns(self): if key not in self.params.input.persistent_refl_cols: self.params.input.persistent_refl_cols.append(key) + if hasattr(self.params, 'merging') and self.params.merging.error.model == "mm24": + if self.params.merging.error.mm24.cc_after_pr: + if "correlation_after_post" not in self.params.input.persistent_refl_cols: + self.params.input.persistent_refl_cols.append("correlation_after_post") + else: + if "correlation" not in self.params.input.persistent_refl_cols: + self.params.input.persistent_refl_cols.append("correlation") if __name__ == '__main__': script = Script() From a4fbcb91e706b8dfd0afb7e821f83fdcb10af618 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 7 Mar 2024 08:46:44 -0800 Subject: [PATCH 189/748] change some params --- mmtbx/geometry_restraints/quantum_interface.py | 9 +++++++-- mmtbx/geometry_restraints/quantum_restraints_manager.py | 6 ++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/mmtbx/geometry_restraints/quantum_interface.py b/mmtbx/geometry_restraints/quantum_interface.py index 54fc7c8169..8a831fffb9 100644 --- a/mmtbx/geometry_restraints/quantum_interface.py +++ b/mmtbx/geometry_restraints/quantum_interface.py @@ -241,7 +241,7 @@ def default_defaults(qmr): default_defaults(qmr) if qmr.package.method is Auto: qmr.package.method='AM1' - # qmr.package.method='PBEh-3c' + qmr.package.method='PBEh-3c' elif program=='mopac': default_defaults(qmr) if qmr.package.method is Auto: @@ -251,9 +251,14 @@ def default_defaults(qmr): assert 0 return qmr -def get_working_directory(model, params): +def get_working_directory(model, params, prefix=None): rc = 'qm_work_dir' return rc + if prefix is None: + prefix = getattr(params.output, 'prefix', None) + if prefix is not None: + rc='%s_%s' % (prefix, rc) + return rc def get_preamble(macro_cycle, i, qmr, old_style=False, compact_selection_syntax=True): qmr = populate_qmr_defaults(qmr) diff --git a/mmtbx/geometry_restraints/quantum_restraints_manager.py b/mmtbx/geometry_restraints/quantum_restraints_manager.py index 3764f26f2a..285cebecc4 100644 --- a/mmtbx/geometry_restraints/quantum_restraints_manager.py +++ b/mmtbx/geometry_restraints/quantum_restraints_manager.py @@ -358,8 +358,9 @@ def validate_ligand_buffer_models(ligand_model, buffer_model, qmr, log=None): "ccp4_mon_lib_rna_dna"]: raise Sorry('QI cannot protonate RNA/DNA : "%s"' % atom_group.id_str()) -def get_ligand_buffer_models(model, qmr, verbose=False, write_steps=False, log=None): +def get_ligand_buffer_models(model, qmr, verbose=False, write_steps=False, log=None, debug=False): if WRITE_STEPS_GLOBAL: write_steps=True + if debug: write_steps=True ligand_model = select_and_reindex(model, qmr.selection) # # check for to sparse selections like a ligand in two monomers @@ -915,7 +916,8 @@ def setup_qm_jobs(model, # # get ligand and buffer region models # - ligand_model, buffer_model = get_ligand_buffer_models(model, qmr) + debug=getattr(params.qi, 'debug', False) + ligand_model, buffer_model = get_ligand_buffer_models(model, qmr, debug=debug) # # get appropriate QM manager # From 6afd31b61bc0576cc3febe7e6fe78a2ce1fcc9d4 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Fri, 8 Mar 2024 10:24:09 -0800 Subject: [PATCH 190/748] major update for NQH and logger --- mmtbx/chemical_components/__init__.py | 96 +++++++++- mmtbx/ligands/rdkit_utils.py | 28 ++- mmtbx/ligands/ready_set_utils.py | 2 + mmtbx/programs/quantum_interface.py | 260 ++++++++++++++++++-------- 4 files changed, 307 insertions(+), 79 deletions(-) diff --git a/mmtbx/chemical_components/__init__.py b/mmtbx/chemical_components/__init__.py index 45e5d20e15..2444e8f7ff 100644 --- a/mmtbx/chemical_components/__init__.py +++ b/mmtbx/chemical_components/__init__.py @@ -75,6 +75,15 @@ def get_cif_filename(code): return os.path.join( data_dir, "%s" % code[0].lower(), "data_%s.cif" % code.upper()) +def is_chemical_components_file(filename): + try: + cif_model = iotbx.cif.reader(file_path=file_name).model() + for cif_block in cif_model.values(): + if "_atom_site" in cif_block: + return True + except Exception as e: + return False + def is_code(code): filename = get_cif_filename(code) if os.path.exists(filename): return True @@ -247,8 +256,10 @@ def _cmp_smiles_length(f1, f2): for d in dirs: if not os.path.isdir(os.path.join(data_dir, d)): continue filenames += os.listdir(os.path.join(data_dir, d)) + # if len(filenames)>100: break if sort_reverse_by_smiles: - filenames.sort(_cmp_smiles_length) + import functools + filenames = sorted(filenames, key=functools.cmp_to_key(_cmp_smiles_length)) else: filenames.sort() for filename in filenames: @@ -271,8 +282,9 @@ def get_header(code): break return outl -def get_group(code, split_rna_dna=False, split_l_d=False): +def get_group(code, split_rna_dna=False, split_l_d=False, verbose=False): t = get_type(code) + if verbose: print('get_group',code, t) if t is not None: t=t.replace('"','').upper() else: @@ -332,6 +344,86 @@ def get_restraints_group(code, split_rna_dna=True, split_l_d=True): }[g] assert 0 +def get_as_atom_group(code): + import iotbx + from mmtbx.ligands.hierarchy_utils import _new_atom + cif = get_cif_dictionary(code) + if not cif: return cif + tmp = [] + ag = iotbx.pdb.hierarchy.atom_group() + ag.resname=code + '''comp_id : BB9 + atom_id : HG + alt_atom_id : HG + type_symbol : H + charge : 0 + pdbx_align : 1 + pdbx_aromatic_flag : N + pdbx_leaving_atom_flag : N + pdbx_stereo_config : N + model_Cartn_x : 14.295 + model_Cartn_y : -4.046 + model_Cartn_z : 26.134 + pdbx_model_Cartn_x_ideal : -3.161 + pdbx_model_Cartn_y_ideal : -1.326 + pdbx_model_Cartn_z_ideal : -0.0 + pdbx_component_atom_id : HG + pdbx_component_comp_id : BB9 + pdbx_ordinal : 12 ''' +# def _new_atom(name, element, xyz, occ, b, hetero, segid=' '*4): + use_model=True + for item in cif["_chem_comp_atom"]: + xyz = (item.model_Cartn_x, + item.model_Cartn_y, + item.model_Cartn_z, + ) + print(xyz) + if '?' in xyz: + xyz = (item.pdbx_model_Cartn_x_ideal, + item.pdbx_model_Cartn_y_ideal, + item.pdbx_model_Cartn_z_ideal, + ) + print(xyz) + use_model=False + break + for item in cif["_chem_comp_atom"]: + if use_model: + xyz = (item.model_Cartn_x, + item.model_Cartn_y, + item.model_Cartn_z, + ) + else: + xyz = (item.pdbx_model_Cartn_x_ideal, + item.pdbx_model_Cartn_y_ideal, + item.pdbx_model_Cartn_z_ideal, + ) + assert '?' not in xyz + atom = _new_atom(item.atom_id, + item.type_symbol, + xyz, + 1., + 20., + True, + ) + ag.append_atom(atom) + return ag + +def get_as_hierarchy(code): + import iotbx + ag = get_as_atom_group(code) + rg = iotbx.pdb.hierarchy.residue_group() + rg.resseq='1' + rg.append_atom_group(ag) + chain = iotbx.pdb.hierarchy.chain() + chain.id='A' + chain.append_residue_group(rg) + model = iotbx.pdb.hierarchy.model() + model.append_chain(chain) + ph = iotbx.pdb.hierarchy.root() + ph.append_model(model) + ph.reset_atom_i_seqs() + return ph + if __name__=="__main__": print('\nSMILES') print(get_smiles(sys.argv[1])) diff --git a/mmtbx/ligands/rdkit_utils.py b/mmtbx/ligands/rdkit_utils.py index 3f1a3fd511..c252d08c95 100644 --- a/mmtbx/ligands/rdkit_utils.py +++ b/mmtbx/ligands/rdkit_utils.py @@ -56,18 +56,22 @@ def read_chemical_component_filename(filename): for code, monomer in ccd.items(): break raise Sorry(''' - Generating H restraints from Chemical Componets for %s failed. Please supply + Generating H restraints from Chemical Components for %s failed. Please supply restraints. ''' % code) for i, (code, monomer) in enumerate(ccd.items()): molecule = Chem.Mol() + desc = monomer.get_loop_or_row('_chem_comp') rwmol = Chem.RWMol(molecule) atom = monomer.get_loop_or_row('_chem_comp_atom') # if atom is None: continue conformer = Chem.Conformer(atom.n_rows()) for j, tmp in enumerate(atom.iterrows()): + print(tmp) new = Chem.Atom(tmp.get('_chem_comp_atom.type_symbol').capitalize()) new.SetFormalCharge(int(tmp.get('_chem_comp_atom.charge'))) + for prop in ['atom_id', 'type_symbol']: + new.SetProp(prop, tmp.get('_chem_comp_atom.%s' % prop, '?')) rdatom = rwmol.AddAtom(new) xyz = (float(xyzs[j][0]), float(xyzs[j][1]), float(xyzs[j][2])) conformer.SetAtomPosition(rdatom, xyz) @@ -81,9 +85,31 @@ def read_chemical_component_filename(filename): atom2 = lookup.get(atom2) order = tmp.get('_chem_comp_bond.value_order') order = bond_order_ccd[order] + print('---') rwmol.AddBond(atom1, atom2, order) rwmol.AddConformer(conformer) + Chem.SanitizeMol(rwmol) + # from rdkit.Chem.PropertyMol import PropertyMol molecule = rwmol.GetMol() + # molecule = PropertyMol(molecule) + print(dir(molecule)) + print(desc) + print(dir(desc)) + for key, item in desc.items(): + key = key.split('.')[1] + print(key,list(item)) + molecule.SetProp(key,item[0]) + print(molecule.HasProp(key)) + print(molecule.GetProp(key)) + print(dir(molecule.GetPropNames())) + print(molecule.GetPropsAsDict()) + # print(dir(rwmol)) + return molecule + +def mol_from_chemical_component(code): + from mmtbx.chemical_components import get_cif_filename + rc = get_cif_filename(code) + molecule = read_chemical_component_filename(rc) return molecule def convert_model_to_rdkit(cctbx_model): diff --git a/mmtbx/ligands/ready_set_utils.py b/mmtbx/ligands/ready_set_utils.py index 27f80e3c05..d716e9cc30 100644 --- a/mmtbx/ligands/ready_set_utils.py +++ b/mmtbx/ligands/ready_set_utils.py @@ -63,6 +63,8 @@ def add_n_terminal_hydrogens_to_atom_group(ag, n_ca_c=None, verbose=False, ): + if bonds is None: + print('\n\t%s\n' % 'add_n_terminal_hydrogens_to_atom_group has not being given bonds') rc=[] if n_ca_c is not None: n, ca, c = n_ca_c diff --git a/mmtbx/programs/quantum_interface.py b/mmtbx/programs/quantum_interface.py index 59ff6ac10e..3deaa9b900 100644 --- a/mmtbx/programs/quantum_interface.py +++ b/mmtbx/programs/quantum_interface.py @@ -1,6 +1,7 @@ # LIBTBX_SET_DISPATCHER_NAME phenix.development.qi from __future__ import absolute_import, division, print_function import os +import sys import time import copy @@ -12,6 +13,7 @@ from mmtbx.geometry_restraints.quantum_restraints_manager import update_restraints from mmtbx.geometry_restraints.quantum_restraints_manager import min_dist2 from mmtbx.geometry_restraints.quantum_interface import get_qm_restraints_scope +from mmtbx.geometry_restraints.quantum_interface import get_working_directory from mmtbx.geometry_restraints.qi_utils import classify_histidine from mmtbx.geometry_restraints.qi_utils import run_serial_or_parallel from mmtbx.geometry_restraints.qi_utils import get_hbonds_via_filenames @@ -21,6 +23,7 @@ import iotbx.phil from libtbx.utils import Sorry from libtbx.utils import null_out +from libtbx.utils import multi_out from mmtbx.monomer_library.linking_setup import ad_hoc_single_metal_residue_element_types @@ -51,7 +54,7 @@ def merge_water(filenames, chain_id='A'): for id_str, ags in waters.items(): if len(ags)>1 or 1: for i, ag in enumerate(ags): - ag.altloc='ABCDEF'[i] + ag.altloc='ABCDEFGHIJKLMNOPQRSTUVWXYZ'[i] for atom in ag.atoms(): outl += '%s\n' % atom.format_atom_record() print('-'*80) @@ -157,6 +160,7 @@ def generate_flipping_his(ag, chain_id=None, resseq=None): assert_histidine_double_protonated(ag) + ag=ag.detached_copy() booleans = [[1,1], [1,0], [0,1]] if include_unprotonated: booleans = [[1,1], [1,0], [0,1], [0,0]] for flip in range(2): @@ -191,6 +195,7 @@ def generate_flipping_NQ(ag, return_hierarchy=False, chain_id=None, resseq=None): + ag=ag.detached_copy() if ag.resname=='ASN': hs = ['HD21', 'HD22'] nos = [' ND2', ' OD1'] @@ -223,7 +228,7 @@ def generate_flipping_NQ(ag, else: yield rc -def get_selection_from_user(hierarchy, include_amino_acids=None): +def get_selection_from_user(hierarchy, include_amino_acids=None, log=None): j=0 opts = [] for residue_group in hierarchy.residue_groups(): @@ -254,21 +259,22 @@ def get_selection_from_user(hierarchy, include_amino_acids=None): ts.append("(%s and altloc '%s')" % (sel_str, altloc)) opts.append(' or '.join(ts)) j+=1 - print('\n\n') + print('\n\n', file=log) for i, sel in enumerate(opts): - print(' %2d : "%s"' % (i+1,sel)) + print(' %2d : "%s"' % (i+1,sel), file=log) if len(opts)==1: - print('\n Automatically selecting') - rc=opts[0] + print('\n Automatically selecting', file=log) + rc=[opts[0]] + return rc else: rc = input('\n Enter selection by choosing number or typing a new one ~> ') try: rc = int(rc) - rc = opts[rc-1] + rc = [opts[rc-1]] except ValueError: pass except IndexError: - rc = 'resid 1' + rc = ['resid 1'] return rc class Program(ProgramTemplate): @@ -317,12 +323,19 @@ class Program(ProgramTemplate): .type = bool each_water = False .type = bool + merge_water = False + .type = bool nproc = 1 .type = int randomise_selection = None .type = float verbose = False .type = bool + debug = False + .type = bool + .style = hidden + .help = more output including PDB files from each step + } """ % (get_qm_restraints_scope()) @@ -341,6 +354,11 @@ def validate(self): # --------------------------------------------------------------------------- def run(self, log=None): + self.logger = multi_out() + self.logger.register("stdout", sys.stdout) + log_filename = '%s.log' % self.data_manager.get_default_output_filename() + log_file = open(log_filename, 'w') + self.logger.register('logfile', log_file) model = self.data_manager.get_model() self.restraint_filenames = [] rc = self.data_manager.get_restraint_names() @@ -354,9 +372,9 @@ def run(self, log=None): if not self.params.qi.selection: rc = get_selection_from_user(model.get_hierarchy(), include_amino_acids=[resname]) - if rc.find('resname %s' % resname)>-1: + if rc[0].find('resname %s' % resname)>-1: self.params.qi.format='qi' - self.params.qi.selection = [rc] + self.params.qi.selection = rc # include_amino_acids=self.params.qi.include_amino_acids if include_amino_acids: @@ -364,11 +382,12 @@ def run(self, log=None): if (not self.params.qi.selection and len(self.params.qi.qm_restraints)==0 and not self.params.qi.each_amino_acid and - not self.params.qi.each_water + not self.params.qi.each_water and + not self.params.qi.merge_water ): rc = get_selection_from_user(model.get_hierarchy(), include_amino_acids=include_amino_acids) - self.params.qi.selection = [rc] + self.params.qi.selection = rc # # validate selection # @@ -381,7 +400,7 @@ def run(self, log=None): if selection: selection_array = model.selection(selection) selected_model = model.select(selection_array) - print('Selected model %s' % selected_model, file=log) + print('Selected model %s' % selected_model, file=self.logger) self.data_manager.add_model('ligand', selected_model) ags = selected_model.get_hierarchy().atom_groups() names = [] @@ -390,6 +409,8 @@ def run(self, log=None): if names[0] in ad_hoc_single_metal_residue_element_types: include_nearest_neighbours=True + qm_work_dir = get_working_directory(model, self.params) + if self.params.qi.step_buffer_radius: step_buffer_radius = self.params.qi.step_buffer_radius assert len(step_buffer_radius.split(','))==3 @@ -431,45 +452,61 @@ def run(self, log=None): pf)) return - if self.params.qi.each_water: - # merge_water(['4ny6_cluster_final_A_101_3.5_C_PM6-D3H4.pdb', - # '4ny6_cluster_final_A_102_3.5_C_PM6-D3H4.pdb']) - # assert 0 - hierarchy = model.get_hierarchy() - outl = '' - for rg in hierarchy.residue_groups(): - if len(rg.atom_groups())!=1: continue - resname=rg.atom_groups()[0].resname - include_amino_acids=self.params.qi.include_amino_acids - if include_amino_acids and include_amino_acids!=resname: continue - gc = get_class(resname) - if gc not in ['common_water']: continue - selection = 'chain %s and resid %s' % (rg.parent().id, rg.resseq.strip()) - qi_phil_string = self.get_single_qm_restraints_scope(selection) - qi_phil_string = self.set_all_write_to_true(qi_phil_string) - qi_phil_string = qi_phil_string.replace('ignore_x_h_distance_protein = False', - 'ignore_x_h_distance_protein = True') - print(' writing phil for %s %s' % (rg.id_str(), rg.atom_groups()[0].resname)) - outl += '%s' % qi_phil_string - pf = '%s_water.phil' % ( - self.data_manager.get_default_model_name().replace('.pdb','')) - f=open(pf, 'w') - f.write('qi {\n') - for line in outl.splitlines(): - if line.strip().startswith('.'): continue - f.write('%s\n' % line) - f.write('}\n') - del f - - ih = 'each_water=True' - print(''' - - mmtbx.quantum_interface %s run_qmr=True %s %s - ''' % (self.data_manager.get_default_model_name(), - ih, - pf)) + if self.params.qi.merge_water: + pf = self.data_manager.get_default_model_name().replace('.pdb', '') + if os.path.exists(qm_work_dir): + os.chdir(qm_work_dir) + filenames=[] + for filename in os.listdir('.'): + if not filename.startswith(pf): continue + if not filename.endswith('pdb'): continue + if filename.find('HOH')==-1: continue + if filename.find('_cluster_final_')==-1: continue + filenames.append(filename) + merge_water(filenames) + else: + print('no working directory') - if self.params.qi.run_qmr: + if self.params.qi.each_water: + if not self.params.qi.run_qmr: + hierarchy = model.get_hierarchy() + outl = '' + for rg in hierarchy.residue_groups(): + if len(rg.atom_groups())!=1: continue + resname=rg.atom_groups()[0].resname + include_amino_acids=self.params.qi.include_amino_acids + if include_amino_acids and include_amino_acids!=resname: continue + gc = get_class(resname) + if gc not in ['common_water']: continue + selection = 'chain %s and resid %s and resname HOH' % (rg.parent().id, rg.resseq.strip()) + qi_phil_string = self.get_single_qm_restraints_scope(selection) + qi_phil_string = self.set_one_write_to_true(qi_phil_string, 'pdb_final_buffer') + qi_phil_string = qi_phil_string.replace('ignore_x_h_distance_protein = False', + 'ignore_x_h_distance_protein = True') + qi_phil_string = qi_phil_string.replace('do_not_update_restraints = False', + 'do_not_update_restraints = True') + print(' writing phil for %s %s' % (rg.id_str(), rg.atom_groups()[0].resname)) + outl += '%s' % qi_phil_string + pf = '%s_water.phil' % ( + self.data_manager.get_default_model_name().replace('.pdb','')) + f=open(pf, 'w') + f.write('qi {\n') + for line in outl.splitlines(): + if line.strip().startswith('.'): continue + f.write('%s\n' % line) + f.write('}\n') + del f + + ih = 'each_water=True' + print(''' + + mmtbx.quantum_interface %s run_qmr=True %s %s + ''' % (self.data_manager.get_default_model_name(), + ih, + pf)) + + # if self.params.qi.run_qmr: + else: rc = self.run_qmr(self.params.qi.format) print(rc) args = [] @@ -478,8 +515,8 @@ def run(self, log=None): args.append(filenames[-1]) print('args'*10) print(args) + os.chdir(qm_work_dir) merge_water(args) - assert 0 return if self.params.qi.randomise_selection: @@ -555,17 +592,47 @@ def run(self, log=None): print('"%s"' % self.params.qi.iterate_NQH) assert self.params.qi.randomise_selection==None if self.params.qi.iterate_NQH=='HIS': - self.iterate_histidine() + rc = self.iterate_histidine() elif self.params.qi.iterate_NQH=='ASN': - self.iterate_ASN() + rc = self.iterate_ASN() elif self.params.qi.iterate_NQH=='GLN': - self.iterate_GLN() + rc = self.iterate_GLN() else: assert 0 + if rc: + update, filename = rc + self.update_residue(filename) + model = self.data_manager.get_model() + fn=self.data_manager.get_default_model_name() + self.data_manager.write_model_file(model, + fn.replace('.pdb', '_flipped.pdb'), + overwrite=True) if self.params.qi.iterate_metals: self.iterate_metals() + def update_residue(self, filename): + def dist2(r1,r2): return (r1[0]-r2[0])**2+(r1[1]-r2[1])**2+(r1[2]-r2[2])**2 + selection = self.params.qi.qm_restraints[0].selection + model = self.data_manager.get_model() + from iotbx import pdb + pdb_inp = pdb.input(filename) + hierarchy = pdb_inp.construct_hierarchy() + asc = hierarchy.atom_selection_cache() + sel = asc.selection(selection) + hierarchy = hierarchy.select(sel) + for replace in hierarchy.residue_groups(): pass + hierarchy = model.get_hierarchy() + for h_model in hierarchy.models(): + for chain in h_model.chains(): + for rgi, residue_group in enumerate(chain.residue_groups()): + for atom1 in replace.atoms(): break + for atom2 in residue_group.atoms(): break + d2 = dist2(atom1.xyz, atom2.xyz) + if d2<1e-3: + chain.remove_residue_group(residue_group) + chain.insert_residue_group(rgi, replace) + def get_selected_hierarchy(self): selection = self.params.qi.qm_restraints[0].selection model = self.data_manager.get_model() @@ -660,6 +727,7 @@ def iterate_NQH(self, nq_or_h, classify_nqh, add_nqh_H_atoms, generate_flipping, self.write_qmr_phil(iterate_NQH=True) print('Restart command with PHIL file') return + qm_work_dir = get_working_directory(self.data_manager.get_model(), self.params) nproc = self.params.qi.nproc preamble = get_preamble(None, 0, self.params.qi.qm_restraints[0]) hierarchy = self.get_selected_hierarchy() @@ -684,7 +752,7 @@ def iterate_NQH(self, nq_or_h, classify_nqh, add_nqh_H_atoms, generate_flipping, for rg in chain.residue_groups(): if rg.resseq!=rg_resseq: continue for j, ag in enumerate(rg.atom_groups()): pass - assert j==0 + assert j==0, 'alt. loc. not supported' rg.remove_atom_group(ag) rg.insert_atom_group(0, flipping_his) self.params.output.prefix='iterate_%s_%02d' % (nq_or_h, i+1) @@ -737,7 +805,7 @@ def iterate_NQH(self, nq_or_h, classify_nqh, add_nqh_H_atoms, generate_flipping, )) results = run_serial_or_parallel(update_restraints, argstuples, nproc) for i, filename in enumerate(filenames): - filename=os.path.join('qm_work_dir', filename) + filename=os.path.join(qm_work_dir, filename) assert os.path.exists(filename), ' Output %s missing' % filename results[i].filename = filename return results @@ -750,22 +818,21 @@ def _process_energies(self, energies, units, resname='HIS', energy_adjustment=No energy=energy[1] if i in adjust: if units.lower() in ['kcal/mol']: - # energy-=247.80642 # Heat of formation - # energy-=156.9 - energy+=26.9295 - # energy+=94.51 - assert 0 + if energy_adjustment is None: + energy_adjustment=94.51 elif units.lower() in ['hartree']: energy+=0.5 assert 0 elif units.lower() in ['ev']: if energy_adjustment is None: # energy_adjustment=13.61 # ??? - # energy_adjustment=4.098 # 94.51 kcal/mol JM - energy_adjustment=5.157 # 118.931 - energy+=energy_adjustment + energy_adjustment=4.098 # 94.51 kcal/mol JM else: assert 0 + # + # ADJUST!!! + # + energy-=energy_adjustment te.append(energy) outl='' if resname=='HIS': @@ -779,10 +846,11 @@ def classify_NQ(args): pass get_first_ag, generate_flipping_NQ, log=log) - if rc is None: return + if rc is None: return None protonation = ['original', 'flipped'] nproc = self.params.qi.nproc - self.process_flipped_jobs('ASN', rc, protonation=protonation, nproc=nproc, log=log) + rc = self.process_flipped_jobs('ASN', rc, protonation=protonation, nproc=nproc, log=log) + return rc def iterate_GLN(self, log=None): def classify_NQ(args): pass @@ -791,10 +859,11 @@ def classify_NQ(args): pass get_first_ag, generate_flipping_NQ, log=log) - if rc is None: return + if rc is None: return None protonation = ['original', 'flipped'] nproc = self.params.qi.nproc - self.process_flipped_jobs('GLN', rc, protonation=protonation, nproc=nproc, log=log) + rc = self.process_flipped_jobs('GLN', rc, protonation=protonation, nproc=nproc, log=log) + return rc def iterate_histidine(self, log=None): rc=self.iterate_NQH('HIS', @@ -802,7 +871,7 @@ def iterate_histidine(self, log=None): add_histidine_H_atoms, generate_flipping_his, log=log) - if rc is None: return + if rc is None: return None protonation = [ 'HD1, HE2', 'HD1 only', 'HE2 only', @@ -812,7 +881,8 @@ def iterate_histidine(self, log=None): ] nproc = self.params.qi.nproc energy_adjustment=self.params.qi.proton_energy_difference - self.process_flipped_jobs('HIS', rc, protonation=protonation, nproc=nproc, energy_adjustment=energy_adjustment, log=log) + rc = self.process_flipped_jobs('HIS', rc, protonation=protonation, nproc=nproc, energy_adjustment=energy_adjustment, log=log) + return rc def process_flipped_jobs(self, resname, rc, protonation=None, id_str=None, nproc=-1, energy_adjustment=None, log=None): energies = [] @@ -823,7 +893,7 @@ def process_flipped_jobs(self, resname, rc, protonation=None, id_str=None, nproc for i, res in enumerate(rc): for selection, te in res.energies.items(): pass te=te[0] - print(' Energy %d %s : %07.1f %s # ligand atoms : %d # cluster atoms : %d' % ( + print(' Energy %d %s : %9.1f %s # ligand atoms : %d # cluster atoms : %d' % ( i+1, te[0], te[1], @@ -863,7 +933,10 @@ def process_flipped_jobs(self, resname, rc, protonation=None, id_str=None, nproc original_ch[0]) ) # - outl = ' %i. %-20s : %7.5f %s ~> %10.2f kcal/mol. H-Bonds : %2d rmsd : %7.2f rotamer "%s"' + final_result=None + close_result=[] + outl = ' %i. %-20s : %12.3f %s ~> %10.2f kcal/mol. H-Bonds : %2d rmsd : %7.2f rotamer "%s"' + # outl = '%i|%-20s|%7.5f|%s|%10.2f|%2d|%7.2f|%s' for i, filename in enumerate(filenames): assert os.path.exists(filename), '"%s"' % filename if self.params.qi.run_directory: @@ -896,10 +969,35 @@ def process_flipped_jobs(self, resname, rc, protonation=None, id_str=None, nproc rotamers[i], ) print(outl % args, file=log) + update=False + if de<1e-3: + final_result = outl % args + tmp = protonation[i] + tmp=tmp.replace('only','') + # tmp=tmp.replace('flipped', '') + if original_ch[1]: + if tmp.strip()==original_ch[1].strip(): + final_result += ' SAME' + elif tmp.replace('flipped', '').strip()==original_ch[1].strip(): + final_result += ' FLIPPED' + else: + final_result += ' DIFFERENT' + update=True + else: + update=i + j=i + elif de<6.: + close_result.append(outl % args) cmd += '\n\n' print(cmd) print(pymols) + print('!!! %s' % final_result) + if close_result: + print('\nClose') + for cl in close_result: + print(' >< %s' % cl) + return update, filenames[j] def step_thru_buffer_radii(self, id_str=None, log=None): from mmtbx.geometry_restraints.quantum_interface import get_preamble @@ -983,7 +1081,6 @@ def run_qmr(self, format, log=None): log=log, ) energies = digest_return_energy_object(rc, 1, energy_only=True) - outl = energies.as_string() print(outl, file=log) # @@ -1038,6 +1135,9 @@ def set_all_write_to_true(self, qi_phil_string): outl += '%s\n' % line return outl + def set_one_write_to_true(self, qi_phil_string, attr): + return qi_phil_string.replace(' %s' % attr, ' *%s' % attr) + def write_qmr_phil(self, iterate_NQH=False, iterate_metals=False, @@ -1045,7 +1145,10 @@ def write_qmr_phil(self, output_format=None, include_nearest_neighbours=False, log=None): - qi_phil_string = self.get_single_qm_restraints_scope(self.params.qi.selection[0]) + qi_phil_string = '' + for i in range(len(self.params.qi.selection)): + qi_phil_string += self.get_single_qm_restraints_scope(self.params.qi.selection[i]) + # qi_phil_string = self.get_single_qm_restraints_scope(self.params.qi.selection[0]) # qi_phil_string = self.set_all_calculate_to_true(qi_phil_string) # qi_phil_string = self.set_all_write_to_true(qi_phil_string) qi_phil = iotbx.phil.parse(qi_phil_string, @@ -1053,6 +1156,8 @@ def write_qmr_phil(self, ) qi_phil_string = qi_phil_string.replace(' pdb_final_buffer', ' *pdb_final_buffer') + # qi_phil_string = qi_phil_string.replace(' pdb_buffer', + # ' *pdb_buffer') # qi_phil.show() qi_phil_string = qi_phil_string.replace('qm_restraints', @@ -1082,7 +1187,10 @@ def write_qmr_phil(self, 'protein_optimisation_freeze = *all None main_chain main_chain_to_beta main_chain_to_delta torsions', 'protein_optimisation_freeze = all None main_chain main_chain_to_beta *main_chain_to_delta *torsions') qi_phil_string = qi_phil_string.replace( - 'solvent_model = None', 'solvent_model = EPS=78.4 PRECISE NSPA=92') + # 'solvent_model = None', 'solvent_model = EPS=78.4 PRECISE LET DDMIN=0.0 NSPA=92', + 'solvent_model = None', 'solvent_model = EPS=78.4', + ) + # qi_phil_string = qi_phil_string.replace('buffer = 3.5', 'buffer = 4.') if iterate_metals: qi_phil_string = qi_phil_string.replace('refinement.', '') From c28b4008ac4f4b90f31f6b9573fbeee732445652 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Fri, 8 Mar 2024 10:41:47 -0800 Subject: [PATCH 191/748] raise sorry if MOPAC not installed --- mmtbx/programs/quantum_interface.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mmtbx/programs/quantum_interface.py b/mmtbx/programs/quantum_interface.py index 3deaa9b900..57dca2b094 100644 --- a/mmtbx/programs/quantum_interface.py +++ b/mmtbx/programs/quantum_interface.py @@ -989,6 +989,9 @@ def process_flipped_jobs(self, resname, rc, protonation=None, id_str=None, nproc elif de<6.: close_result.append(outl % args) + if units.lower()=='dirac': + raise Sorry('MOPAC not installed! Please install or update to Python3.') + cmd += '\n\n' print(cmd) print(pymols) From 215bf72c7f87c46307dd7aa07555b508e7d8f0e5 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 8 Mar 2024 12:36:50 -0800 Subject: [PATCH 192/748] remove tst_cablam.py from regression (this test is retired) --- mmtbx/run_tests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index 675f9214a2..e6ce424360 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -253,7 +253,6 @@ # "$D/regression/tst_validation_summary.py", "$D/regression/tst_maps_misc.py", - "$D/regression/tst_cablam.py", "$D/regression/tst_anomalous_substructure.py", "$D/regression/tst_map_coeffs_simple.py", # From 7c5159e7f20363c4ba01abd76efe71681066bf02 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Fri, 8 Mar 2024 14:29:19 -0800 Subject: [PATCH 193/748] print to multi --- mmtbx/model/model.py | 4 +- mmtbx/programs/quantum_interface.py | 85 +++++++++++++++-------------- 2 files changed, 46 insertions(+), 43 deletions(-) diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index e513b2d02a..3d40c4ba25 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -652,8 +652,8 @@ def __repr__(self): sc = (0, 0, 0) return "Model manager "+\ - "%s" %(self.model_number()) if self.model_number() is not None else "" + \ - "\n%s\nChains: %s Residues %s (%s - %s)\nWorking coordinate shift %s)" %( + ("%s" %(self.model_number()) if self.model_number() is not None else "") + \ + "\nSymmetry: %s Chains: %s Residues: %s (%s - %s)\nWorking coordinate shift %s)" %( str(self.unit_cell_crystal_symmetry()).replace("\n"," "), str(nchains), str(nres), diff --git a/mmtbx/programs/quantum_interface.py b/mmtbx/programs/quantum_interface.py index 57dca2b094..6cb8f8b106 100644 --- a/mmtbx/programs/quantum_interface.py +++ b/mmtbx/programs/quantum_interface.py @@ -21,6 +21,7 @@ import iotbx.pdb import iotbx.phil +from libtbx import Auto from libtbx.utils import Sorry from libtbx.utils import null_out from libtbx.utils import multi_out @@ -301,7 +302,7 @@ class Program(ProgramTemplate): .style = hidden format = *phenix_refine qi .type = choice - write_qmr_phil = False + write_qmr_phil = Auto .type = bool run_qmr = False .type = bool @@ -351,6 +352,9 @@ def validate(self): self.params.output.prefix = prefix if self.params.qi.randomise_selection and self.params.qi.randomise_selection>0.5: raise Sorry('Random select value %s is too large' % self.params.qi.randomise_selection) + if self.params.qi.write_qmr_phil is Auto: + if self.params.qi.run_qmr: + self.params.qi.write_qmr_phil=False # --------------------------------------------------------------------------- def run(self, log=None): @@ -400,7 +404,7 @@ def run(self, log=None): if selection: selection_array = model.selection(selection) selected_model = model.select(selection_array) - print('Selected model %s' % selected_model, file=self.logger) + print('Selected model:\n%s' % selected_model, file=self.logger) self.data_manager.add_model('ligand', selected_model) ags = selected_model.get_hierarchy().atom_groups() names = [] @@ -437,7 +441,7 @@ def run(self, log=None): qi_phil_string = qi_phil_string.replace('ignore_x_h_distance_protein = False', 'ignore_x_h_distance_protein = True') qi_phil_string = qi_phil_string.replace(' pdb_final_buffer', ' *pdb_final_buffer') - print(' writing phil for %s %s' % (rg.id_str(), rg.atom_groups()[0].resname)) + print(' writing phil for %s %s' % (rg.id_str(), rg.atom_groups()[0].resname), file=self.logger) outl += '%s' % qi_phil_string pf = '%s_all.phil' % ( self.data_manager.get_default_model_name().replace('.pdb','')) @@ -449,7 +453,7 @@ def run(self, log=None): f.write('}\n') del f print(' phenix.refine %s %s qi.nproc=6' % (self.data_manager.get_default_model_name(), - pf)) + pf), file=self.logger) return if self.params.qi.merge_water: @@ -465,7 +469,7 @@ def run(self, log=None): filenames.append(filename) merge_water(filenames) else: - print('no working directory') + print('no working directory', file=self.logger) if self.params.qi.each_water: if not self.params.qi.run_qmr: @@ -485,7 +489,7 @@ def run(self, log=None): 'ignore_x_h_distance_protein = True') qi_phil_string = qi_phil_string.replace('do_not_update_restraints = False', 'do_not_update_restraints = True') - print(' writing phil for %s %s' % (rg.id_str(), rg.atom_groups()[0].resname)) + print(' writing phil for %s %s' % (rg.id_str(), rg.atom_groups()[0].resname), file=self.logger) outl += '%s' % qi_phil_string pf = '%s_water.phil' % ( self.data_manager.get_default_model_name().replace('.pdb','')) @@ -503,7 +507,7 @@ def run(self, log=None): mmtbx.quantum_interface %s run_qmr=True %s %s ''' % (self.data_manager.get_default_model_name(), ih, - pf)) + pf), file=self.logger) # if self.params.qi.run_qmr: else: @@ -566,7 +570,7 @@ def run(self, log=None): ih, pf, ih2, - )) + ), file=self.logger) return if self.params.qi.run_directory: @@ -589,7 +593,7 @@ def run(self, log=None): self.run_qmr(self.params.qi.format) if self.params.qi.iterate_NQH: - print('"%s"' % self.params.qi.iterate_NQH) + print('"%s"' % self.params.qi.iterate_NQH, file=self.logger) assert self.params.qi.randomise_selection==None if self.params.qi.iterate_NQH=='HIS': rc = self.iterate_histidine() @@ -645,7 +649,7 @@ def iterate_metals(self, log=None): from mmtbx.geometry_restraints.quantum_interface import get_preamble if len(self.params.qi.qm_restraints)<1: self.write_qmr_phil(iterate_metals=True) - print('Restart command with PHIL file') + print('Restart command with PHIL file', file=self.logger) return def generate_metals(s): if s.lower()=='all': s='LI,NA,MG,K,CA,CU,ZN' @@ -668,7 +672,7 @@ def generate_metals(s): filenames = [] t0=time.time() for element in generate_metals(self.params.qi.iterate_metals): - print('Substituting element : %s' % element) + print('Substituting element : %s' % element, file=self.logger) model = self.data_manager.get_model() if nproc>1: model=model.deep_copy() hierarchy = model.get_hierarchy() @@ -694,7 +698,7 @@ def generate_metals(s): filenames.append('%s_cluster_final_%s.pdb' % (self.params.output.prefix, preamble)) if nproc==-1: - print(' Running metal swap %s' % (element), file=log) + print(' Running metal swap %s' % (element), file=self.logger) res = update_restraints(model, self.params, never_write_restraints=True, @@ -703,9 +707,9 @@ def generate_metals(s): energies.append(energies) units=res.units rmsds.append(res.rmsds[0][1]) - print(' Energy : %s %s' % (energies[-1],units), file=log) - print(' Time : %ds' % (time.time()-t0), file=log) - print(' RMSD : %8.3f' % res.rmsds[0][1], file=log) + print(' Energy : %s %s' % (energies[-1],units), file=self.logger) + print(' Time : %ds' % (time.time()-t0), file=self.logger) + print(' RMSD : %8.3f' % res.rmsds[0][1], file=self.logger) else: params = copy.deepcopy(self.params) argstuples.append(( model, @@ -725,7 +729,7 @@ def iterate_NQH(self, nq_or_h, classify_nqh, add_nqh_H_atoms, generate_flipping, from mmtbx.geometry_restraints.quantum_interface import get_preamble if len(self.params.qi.qm_restraints)<1: self.write_qmr_phil(iterate_NQH=True) - print('Restart command with PHIL file') + print('Restart command with PHIL file', file=self.logger) return qm_work_dir = get_working_directory(self.data_manager.get_model(), self.params) nproc = self.params.qi.nproc @@ -782,7 +786,7 @@ def iterate_NQH(self, nq_or_h, classify_nqh, add_nqh_H_atoms, generate_flipping, preamble)) # if nproc==-1: - print(' Running %s flip %d' % (nq_or_h, i+1), file=log) + print(' Running %s flip %d' % (nq_or_h, i+1), file=self.logger) res = update_restraints(model, self.params, never_write_restraints=True, @@ -791,9 +795,9 @@ def iterate_NQH(self, nq_or_h, classify_nqh, add_nqh_H_atoms, generate_flipping, energies.append(energies) units=res.units rmsds.append(res.rmsds[0][1]) - print(' Energy : %s %s' % (energies[-1],units), file=log) - print(' Time : %ds' % (time.time()-t0), file=log) - print(' RMSD : %8.3f' % res.rmsds[0][1], file=log) + print(' Energy : %s %s' % (energies[-1],units), file=self.logger) + print(' Time : %ds' % (time.time()-t0), file=self.logger) + print(' RMSD : %8.3f' % res.rmsds[0][1], file=self.logger) else: params = copy.deepcopy(self.params) argstuples.append(( model, @@ -900,7 +904,7 @@ def process_flipped_jobs(self, resname, rc, protonation=None, id_str=None, nproc res.units, te[2], te[3], - )) + ), file=self.logger) energies.append(te) units=res.units rmsds.append(res.rmsds[0][1]) @@ -925,13 +929,13 @@ def process_flipped_jobs(self, resname, rc, protonation=None, id_str=None, nproc if resname not in ['radius']: hierarchy = self.get_selected_hierarchy() original_ch = classify_histidine(hierarchy, resname=resname) - print('\n\nEnergies in units of %s' % units, file=log) - print('%s\n' % outl, file=log) + print('\n\nEnergies in units of %s' % units, file=self.logger) + print('%s\n' % outl, file=self.logger) print(' %i. %-20s : rotamer "%s"' % ( 0, original_ch[1], - original_ch[0]) - ) + original_ch[0]), + file=self.logger) # final_result=None close_result=[] @@ -968,7 +972,7 @@ def process_flipped_jobs(self, resname, rc, protonation=None, id_str=None, nproc rmsds[i], rotamers[i], ) - print(outl % args, file=log) + print(outl % args, file=self.logger) update=False if de<1e-3: final_result = outl % args @@ -993,20 +997,20 @@ def process_flipped_jobs(self, resname, rc, protonation=None, id_str=None, nproc raise Sorry('MOPAC not installed! Please install or update to Python3.') cmd += '\n\n' - print(cmd) - print(pymols) - print('!!! %s' % final_result) + print(cmd, file=self.logger) + print(pymols, file=self.logger) + print('!!! %s' % final_result, file=self.logger) if close_result: - print('\nClose') + print('\nClose', file=self.logger) for cl in close_result: - print(' >< %s' % cl) + print(' >< %s' % cl, file=self.logger) return update, filenames[j] def step_thru_buffer_radii(self, id_str=None, log=None): from mmtbx.geometry_restraints.quantum_interface import get_preamble if len(self.params.qi.qm_restraints)<1: self.write_qmr_phil(step_buffer_radius=True) - print('Restart command with PHIL file') + print('Restart command with PHIL file', file=self.logger) return nproc = self.params.qi.nproc # @@ -1040,7 +1044,7 @@ def step_thru_buffer_radii(self, id_str=None, log=None): preamble)) # if nproc==-1: - print(' Running radius %d' % (r), file=log) + print(' Running radius %d' % (r), file=self.logger) res = update_restraints(model, params, never_write_restraints=True, @@ -1049,9 +1053,9 @@ def step_thru_buffer_radii(self, id_str=None, log=None): energies.append(res.energies) units=res.units rmsds.append(res.rmsds[0][1]) - print(' Energy : %s %s' % (energies[-1],units), file=log) - print(' Time : %ds' % (time.time()-t0), file=log) - print(' RMSD : %8.3f' % res.rmsds[0][1], file=log) + print(' Energy : %s %s' % (energies[-1],units), file=self.logger) + print(' Time : %ds' % (time.time()-t0), file=self.logger) + print(' RMSD : %8.3f' % res.rmsds[0][1], file=self.logger) else: argstuples.append(( model, params, @@ -1085,7 +1089,7 @@ def run_qmr(self, format, log=None): ) energies = digest_return_energy_object(rc, 1, energy_only=True) outl = energies.as_string() - print(outl, file=log) + print(outl, file=self.logger) # # minimise ligands geometry # @@ -1098,7 +1102,7 @@ def run_qmr(self, format, log=None): else: digest_return_energy_object(rc, 1, False, energies) outl = energies.as_string() - print(outl, file=log) + print(outl, file=self.logger) return rc def get_single_qm_restraints_scope(self, selection): @@ -1177,7 +1181,6 @@ def write_qmr_phil(self, step=1 tmp = 'qi {\n' for r in stepper(start, end, step): - print(r) tmp+=qi_phil_string.replace('buffer = 3.5', 'buffer = %s' % r) tmp += '\n}\n' qi_phil_string = tmp @@ -1230,11 +1233,11 @@ def safe_filename(s): self.data_manager.get_default_model_name().replace('.pdb',''), safe_filename(self.params.qi.selection[0]), ) - print(' Writing QMR phil scope to %s' % pf, file=log) + print(' Writing QMR phil scope to %s' % pf, file=self.logger) f=open(pf, 'w') for line in qi_phil_string.splitlines(): if line.strip().startswith('.'): continue - print('%s' % line) + print('%s' % line, file=self.logger) f.write('%s\n' % line) del f return pf From 613fb3310e15343f92f9f4f5ea7aee8737e1fcca Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Fri, 8 Mar 2024 12:49:51 -0800 Subject: [PATCH 194/748] libtbx: add compatibility for newer versions of clang - Compilation failure with a Boost header - https://reviews.llvm.org/D150226 --- libtbx/SConscript | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libtbx/SConscript b/libtbx/SConscript index 3dcd2c53e0..db4a5c42ba 100644 --- a/libtbx/SConscript +++ b/libtbx/SConscript @@ -972,6 +972,12 @@ int main() { min_macos = 11.0 base_macos_flags = ['-stdlib=libc++', '-mmacosx-version-min=%s' % min_macos] + # Boost issue with newer versions of clang + # include/boost/mpl/aux_/integral_wrapper.hpp:73:31: error: integer value -1 is outside the valid range of values [0, 3] for this enumeration type + # https://reviews.llvm.org/D150226 + if env_etc.clang_version[0] >= 15: + base_macos_flags.append('-Wno-enum-constexpr-conversion') + link_flags = ["-w"] # suppress "source/lib does not exist" warning link_flags.extend(base_macos_flags) if libtbx.env.build_options.force_32bit: From 639f25591c4ad4625d346c0f2c50d585348c6128 Mon Sep 17 00:00:00 2001 From: randyjread Date: Mon, 11 Mar 2024 14:34:56 +0000 Subject: [PATCH 195/748] Changes to allow docking to work as well as possible when search sphere near edge of map. --- cctbx/maptbx/prepare_map_for_docking.py | 36 ++++++++++++------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/cctbx/maptbx/prepare_map_for_docking.py b/cctbx/maptbx/prepare_map_for_docking.py index cb7f7c6f1b..f4846df1b8 100644 --- a/cctbx/maptbx/prepare_map_for_docking.py +++ b/cctbx/maptbx/prepare_map_for_docking.py @@ -1517,28 +1517,27 @@ def assess_cryoem_errors( # Get map coefficients for maps after spherical masking # Define box big enough to hold sphere plus soft masking - # Attempt to cope with spheres too near edge of full map, - # and don't let box deviate too far from cubic + # Warn if sphere too near edge of full map for soft mask to reach zero + # or if less than about 85% of sphere would be within full map + # (outside by >= half-radius) boundary_to_smoothing_ratio = 2 soft_mask_radius = d_min padding = soft_mask_radius * boundary_to_smoothing_ratio cushion = flex.double(3,radius+padding) cart_min = flex.double(sphere_cent_map) - cushion cart_max = flex.double(sphere_cent_map) + cushion - for i in range(3): # Keep within input map, check whether box has been reduced too much - cart_min[i] = max(cart_min[i],0) - cart_max[i] = min(cart_max[i],ucpars[i]-spacings[i]) - min_box_width = flex.min(cart_max - cart_min) - if min_box_width < 2*(radius+padding): - radius_check = min_box_width/2. - padding - if radius_check < 0.8*radius: # Allowable sphere would be too small to consider - print("\nModel sphere has radius of ",radius, file=log) - print("Sphere that fits where requested has radius of ",radius_check, file=log) - raise Sorry("Target sphere too near edge of map") - elif radius_check < radius*0.99: - print("\nWARNING: Model sphere radius reduced from ",radius, - " to ",radius_check," to stay within map", file=log) - radius = radius_check + max_outside = 0. + for i in range(3): + if cart_min[i] < 0: + max_outside = max(max_outside, -cart_min[i]) + if cart_max[i] > ucpars[i]-spacings[i]: + max_outside = max(max_outside, cart_max[i]-(ucpars[i]-spacings[i])) + if max_outside > padding + radius/2: + print("\nWARNING: substantial fraction of sphere is outside map volume", file=log) + elif max_outside > padding: + print("\nWARNING: sphere is partially outside map volume", file=log) + elif max_outside > 0: + print("\nWARNING: sphere too near map edge to allow full extent of smooth masking", file=log) cs = mmm.crystal_symmetry() uc = cs.unit_cell() @@ -1936,7 +1935,7 @@ def run(): defaults to narrowest extent of input map divided by 4 --no_shift_map_origin: don't shift output mtz file to match input map on its origin default False - --no_define_ordered_volume: don't define ordered volume for comparison with cutout volume + --no_determine_ordered_volume: don't define ordered volume for comparison with cutout volume default False --file_root: root name for output files --mute (or -m): mute output @@ -1997,7 +1996,8 @@ def run(): protein_mw = None nucleic_mw = None if (args.protein_mw is None) and (args.nucleic_mw is None): - raise Sorry("At least one of protein_mw or nucleic_mw must be given") + if determine_ordered_volume: + raise Sorry("At least one of protein_mw or nucleic_mw must be given") if args.protein_mw is not None: protein_mw = args.protein_mw if args.nucleic_mw is not None: From 5909dc1b763fa95208d463cd0d9d5560cea0aa07 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 11 Mar 2024 15:30:54 -0700 Subject: [PATCH 196/748] Make possible and expose parameters to tweak plots. --- mmtbx/nci/hbond.py | 6 ---- mmtbx/nci/skew_kurt_plot.py | 15 ++++++++- mmtbx/programs/hbond.py | 62 +++++++++++++++++++++++++++++++------ 3 files changed, 66 insertions(+), 17 deletions(-) diff --git a/mmtbx/nci/hbond.py b/mmtbx/nci/hbond.py index 289946921e..9dbe851f9f 100644 --- a/mmtbx/nci/hbond.py +++ b/mmtbx/nci/hbond.py @@ -101,12 +101,6 @@ def get_stats(data, min_data_size=10): output_stats_pdf = False .type = bool .short_caption = Output stats in PDF - output_skew_kurtosis_plot = False - .type = bool - .short_caption = Output skew-kurtosis plot with result in png format - plot_colorblind_friendly = True - .type = bool - .short_caption = Use colorblind friendly palette for skew-kurtosis plot add_hydrogens_if_absent = False .type = bool .short_caption = Add hydrogens if they are not present in the model(s) diff --git a/mmtbx/nci/skew_kurt_plot.py b/mmtbx/nci/skew_kurt_plot.py index e2ff0691cc..2b2002727e 100644 --- a/mmtbx/nci/skew_kurt_plot.py +++ b/mmtbx/nci/skew_kurt_plot.py @@ -5,6 +5,7 @@ from mmtbx.utils.grid2d import Grid2D import numpy as np import matplotlib.pyplot as plt +from libtbx.utils import Sorry import os def get_filling_data(data, x_nbins, y_nbins, xmin, xmax, ymin, ymax, @@ -49,6 +50,7 @@ def make_figure( dot_size, type='all', colorblind_friendly=True, + override_palette = {}, resolution=300): """ Plots skew-kurtosis plot and saves it to .png file @@ -58,6 +60,7 @@ def make_figure( Rha_coords (iterable): list of skew-kurtosis coordinates of Rha [(),(),..] type (str, optional): Type of contours to plot. Defaults to 'all'. Allowed 'all', 'alpha', 'beta'. colorblind_friendly (bool, optional): Use color-blind friendly palette. Defaults to True. + override_palette (dict, optional): keys and values to overide color_palette values. resolution (int, optional): Resolution of outputted figure. Defaults to 300. """ assert type in ['all', 'alpha', 'beta'] @@ -65,11 +68,12 @@ def make_figure( relative_path="mmtbx/nci")+'/filtered_raw_data.pkl' assert os.path.isfile(pkl_fn) db = easy_pickle.load(pkl_fn) - # settings color_palette = {'colormap': 'PiYG', 'contour_left':'green', 'contour_right':'mediumvioletred', + 'contour_thick_left':1.5, + 'contour_thick_right':1.5, 'theta_color':'green', 'theta_contour':'black', 'Rha_color': 'deeppink', @@ -79,11 +83,19 @@ def make_figure( color_palette = {'colormap': 'cividis', 'contour_left':'yellow', 'contour_right':'darkblue', + 'contour_thick_left':1.5, + 'contour_thick_right':1.5, 'theta_color':'yellow', 'theta_contour':'black', 'Rha_color': 'darkblue', 'Rha_contour': 'white', } + for k,v in override_palette.items(): + if k in color_palette: + color_palette[k] = v + else: + raise Sorry("%s parameter is not in the used palette options." % k) + contours = {'all': [-0.14, 0.14], 'alpha': [-0.14, 0.14], 'beta': [-0.14, 0.14]} @@ -118,6 +130,7 @@ def make_figure( origin="lower", linestyles=['solid', 'solid'], colors=[color_palette['contour_right'],color_palette['contour_left']], + linewidths=[color_palette['contour_thick_right'], color_palette['contour_thick_left']], extent=[xmin, xmax, ymin, ymax], ) diff --git a/mmtbx/programs/hbond.py b/mmtbx/programs/hbond.py index 13c142ea95..bbe7592182 100644 --- a/mmtbx/programs/hbond.py +++ b/mmtbx/programs/hbond.py @@ -18,17 +18,51 @@ class Program(ProgramTemplate): datatypes = ['model', 'phil', 'restraint'] - master_phil_str = mmtbx.nci.hbond.master_phil_str + + master_phil_str = ''' + include scope mmtbx.nci.hbond.master_phil_str + + output_skew_kurtosis_plot = False + .type = bool + .short_caption = Output skew-kurtosis plot with result in png format + plot_colorblind_friendly = True + .type = bool + .short_caption = Use colorblind friendly palette for skew-kurtosis plot + plot_parameters_override + .help = These parameters will override preset values in plots. The values \ + will be passed directly to matplotlib functions, so should be valid \ + matplotlib color names. + { + colormap = None + .type = str + contour_left = None + .type = str + contour_right = None + .type = str + contour_thick_left = None + .type = float(value_min=0.1, value_max=10) + contour_thick_right = None + .type = float(value_min=0.1, value_max=10) + theta_color = None + .type = str + theta_contour = None + .type = str + Rha_color = None + .type = str + Rha_contour = None + .type = str + } + ''' + # % mmtbx.nci.hbond.master_phil_str # --------------------------------------------------------------------------- def validate(self): - print('Validating inputs', file=self.logger) + self._print('Validating inputs') self.data_manager.has_models(raise_sorry=True) # --------------------------------------------------------------------------- def run(self): - print('Using model: %s' % self.data_manager.get_default_model_name(), - file=self.logger) + self._print('Using model: %s' % self.data_manager.get_default_model_name()) inp_models = [] for model_name in self.data_manager.get_model_names(): inp_models.append((model_name, self.data_manager.get_model(model_name))) @@ -47,7 +81,7 @@ def run(self): self.results = mmtbx.nci.hbond.find(model = model) if self.params.hbond.show_hbonds: self.results.show(log = self.logger) - print("-"*79, file=self.logger) + self._print("-"*79) #self.results.show_summary(log = self.logger) prefix=self.params.output.prefix if not prefix: @@ -60,8 +94,7 @@ def run(self): stats = mmtbx.nci.hbond.stats(model = model, prefix="%s_stats" % prefix, output_stats_pdf = self.params.hbond.output_stats_pdf) if stats is None: - print('\n\tLimited number of H-bonds so statistics are not calculated.', - file=self.logger) + self._print('\n\tLimited number of H-bonds so statistics are not calculated.') return min_data_size=self.params.hbond.min_data_size # These are the values to be used for the plot! @@ -70,21 +103,30 @@ def run(self): theta1_data.append(stats.all.get_counts(min_data_size=min_data_size).theta_1) Rha_data.append( stats.all.get_counts(min_data_size=min_data_size).d_HA) - if self.params.hbond.output_skew_kurtosis_plot and self.results.get_counts(): + if self.params.output_skew_kurtosis_plot and len(theta1_data) > 0 and len(Rha_data) > 0: # To use other than 'all' type, nci.hbond.find needs to be called with selected model again, # like in stats(). fn = '%s_skew_kurtosis' % prefix - if self.params.hbond.plot_colorblind_friendly: + if self.params.plot_colorblind_friendly: fn += "_cbf" theta1_c = [(x.skew, x.kurtosis) for x in theta1_data] Rha_c = [(x.skew, x.kurtosis) for x in Rha_data] + op = {} + for param_name in dir(self.params.plot_parameters_override): + if not param_name.startswith('__'): + param_value = getattr(self.params.plot_parameters_override, param_name) + if param_value != None: + op[param_name] = param_value + mmtbx.nci.skew_kurt_plot.make_figure( file_name=fn, theta1_coords=theta1_c, Rha_coords=Rha_c, dot_size = self.params.hbond.dot_size, type='all', - colorblind_friendly=self.params.hbond.plot_colorblind_friendly) + override_palette = op, + colorblind_friendly=self.params.plot_colorblind_friendly) + self._print("\nOutputted plot as %s.png" % fn) # --------------------------------------------------------------------------- def get_results(self): From b1eb16921f89c1ac087c95913e56cda460ab97bc Mon Sep 17 00:00:00 2001 From: cschlick Date: Mon, 11 Mar 2024 16:12:14 -0700 Subject: [PATCH 197/748] Change output formatting to be more consistent. Fix bugs where side-chain/main-chain selections are emtpy. --- cctbx/maptbx/qscore.py | 52 ++++++++++++---------------- cctbx/programs/qscore.py | 75 +++++++++++++++++++++++++++++----------- 2 files changed, 77 insertions(+), 50 deletions(-) diff --git a/cctbx/maptbx/qscore.py b/cctbx/maptbx/qscore.py index eb6bc0e5d2..4a1778460e 100644 --- a/cctbx/maptbx/qscore.py +++ b/cctbx/maptbx/qscore.py @@ -166,7 +166,11 @@ def get_probes( probe_xyz = [result[0] for result in results] probe_mask = [result[1] for result in results] - return np.stack(probe_xyz), np.array(probe_mask) + n_shells = len(shells) + probe_xyz_stacked = np.empty((n_shells,*probe_xyz[0].shape)) + for i,array in enumerate(probe_xyz): + probe_xyz_stacked[i] = array + return probe_xyz_stacked, np.array(probe_mask) def shell_probes_precalculate( @@ -309,7 +313,6 @@ def calc_qscore(mmm, # g vals # create the reference data - radii = shells M = volume maxD = min(M.mean() + M.std() * 10, M.max()) minD = max(M.mean() - M.std() * 1, M.min()) @@ -317,7 +320,7 @@ def calc_qscore(mmm, B = minD u = 0 sigma = 0.6 - x = np.array(radii) + x = np.array(shells) y = A * np.exp(-0.5 * ((x - u) / sigma) ** 2) + B # Stack and reshape data for correlation calc @@ -345,7 +348,7 @@ def calc_qscore(mmm, model = model.select(flex.bool(selection_bool)) qscore_df = aggregate_qscore_per_residue(model,q,window=3) q = flex.double(q) - qscore_per_residue = flex.double(qscore_df["Q-ResidueRolling"].values) + qscore_per_residue = flex.double(qscore_df["Q-Residue"].values) # Output result = { @@ -402,38 +405,28 @@ def aggregate_qscore_per_residue(model,qscore_per_atom,window=3): # assign residue indices to each atom atoms = model.get_atoms() - res_seqs = [atom.parent().parent().resseq_as_int() for atom in atoms] - chain_ids = [atom.parent().parent().parent().id for atom in atoms] - res_names = [atom.parent().resname for atom in atoms] - names = [atom.name.strip() for atom in atoms] - df = pd.DataFrame({"resseq":res_seqs, - "chain_id":chain_ids, - "resname":res_names, - "name":names, - "Q-score":np.array(qscore_per_atom), - - }) - + df = cctbx_atoms_to_df(atoms) + df["Q-score"] = qscore_per_atom df["rg_index"] = df.groupby(["chain_id", "resseq", "resname"]).ngroup() grouped_means = df.groupby(['chain_id', "resseq", "resname", "rg_index"], as_index=False)['Q-score'].mean().rename( columns={'Q-score': 'Q-Residue'}) - grouped_means['RollingMean'] = None # Initialize column to avoid KeyError + #grouped_means['RollingMean'] = None # Initialize column to avoid KeyError # Until pandas is updated, need to suppress warning warnings.filterwarnings("ignore", category=FutureWarning) - for chain_id, group in grouped_means.groupby("chain_id"): - rolling_means = variable_neighbors_rolling_mean(group['Q-Residue'], window) - grouped_means.loc[group.index, 'RollingMean'] = rolling_means.values + # for chain_id, group in grouped_means.groupby("chain_id"): + # rolling_means = variable_neighbors_rolling_mean(group['Q-Residue'], window) + # grouped_means.loc[group.index, 'RollingMean'] = rolling_means.values # Merge the updated 'Q-Residue' and 'RollingMean' back into the original DataFrame - df = df.merge(grouped_means[['rg_index', 'Q-Residue', 'RollingMean']], on='rg_index', how='left') + df = df.merge(grouped_means[['rg_index', 'Q-Residue']], on='rg_index', how='left') df.drop("rg_index", axis=1, inplace=True) - df["Q-ResidueRolling"] = df["RollingMean"].astype(float) - df.drop(columns=["RollingMean"],inplace=True) + # df["Q-ResidueRolling"] = df["RollingMean"].astype(float) + # df.drop(columns=["RollingMean"],inplace=True) return df def variable_neighbors_rolling_mean(series, window=3): @@ -490,12 +483,13 @@ def cctbx_atoms_to_df(atoms): func_mapper = { #"model_id", # model "id":lambda atom: atom.i_seq, - "Chain":lambda atom: atom.parent().parent().parent().id, - "Resseq":lambda atom: atom.parent().parent().resseq_as_int(), - "Resname":lambda atom: atom.parent().parent().unique_resnames()[0], - "Name":lambda atom: atom.name.strip(), - "Element":lambda atom: atom.element, - "Alt Loc": lambda atom: atom.parent().altloc + "model_id":lambda atom: atom.parent().parent().parent().parent().id, + "chain_id":lambda atom: atom.parent().parent().parent().id, + "resseq":lambda atom: atom.parent().parent().resseq_as_int(), + "resname":lambda atom: atom.parent().parent().unique_resnames()[0], + "name":lambda atom: atom.name.strip(), + "element":lambda atom: atom.element, + "altloc": lambda atom: atom.parent().altloc } # Build as dictionaries diff --git a/cctbx/programs/qscore.py b/cctbx/programs/qscore.py index 8b675ba228..e136a7e463 100644 --- a/cctbx/programs/qscore.py +++ b/cctbx/programs/qscore.py @@ -39,7 +39,10 @@ def validate(self): def run(self): - self._print("Running") + # set up logging + log = open("qscore.log", "w") + + self.logger.register("log", log, atexit_send_to=None) # get initial data mmm = self.data_manager.get_map_model_manager() @@ -58,6 +61,7 @@ def run(self): # ignore hydrogens model = mmm.model() + model.add_crystal_symmetry_if_necessary() model = model.remove_hydrogens() # make mmm @@ -65,8 +69,10 @@ def run(self): # print output self._print("Running Q-score:") - self._print("\nRadial shells used:") - self._print([round(shell,2) for shell in shells]) + self._print("\nRadial shells (Radii used to place probes):") + self._print(",".join([str(round(shell,2)) for shell in shells])) + self._print("\n Number of probes per radial shell: "+str(self.params.qscore.n_probes)) + # run qscore qscore_result= calc_qscore( mmm, @@ -81,33 +87,59 @@ def run(self): self.result = group_args(**qscore_result) # calculate some metrics df = self.result.qscore_dataframe + # round + df_numeric = df.select_dtypes(include=['number']).round(2) + df[df_numeric.columns] = df_numeric + if self.params.qscore.selection is not None: model = model.select(model.selection(self.params.qscore.selection)) assert model.get_number_of_atoms()==len(df) - self._print("\nFinished running. Q-score results:") + self._print("\nFinished running.\n\n Q-score results:") sel_mc = "protein and (name C or name N or name CA or name O or name CB)" sel_mc = model.selection(sel_mc) sel_sc = ~sel_mc - q_sc = flex.mean(self.result.qscore_per_atom.select(sel_sc)) - q_mc = flex.mean(self.result.qscore_per_atom.select(sel_mc)) + + # Side chains + df["Side Chain"] = pd.NA + if sel_sc.count(True)>0: + q_sc = flex.mean(self.result.qscore_per_atom.select(sel_sc)) + q_sc = round(q_sc,2) + df.loc[sel_sc.as_numpy_array(),"Side Chain"] = np.array(self.result.qscore_per_atom.select(sel_sc)) + else: + q_sc = None + df["Side Chain"] = df["Side Chain"].astype("Float64") + + # Main chain + df["Main Chain"] = pd.NA + if sel_mc.count(True)>0: + q_mc = flex.mean(self.result.qscore_per_atom.select(sel_mc)) + q_mc = round(q_mc,2) + df.loc[sel_sc.as_numpy_array(),"Main Chain"] = np.array(self.result.qscore_per_atom.select(sel_mc)) + else: + q_mc = None + df["Main Chain"] = df["Main Chain"].astype("Float64") + # All q_all = flex.mean(self.result.qscore_per_atom) + q_all = round(q_all,2) + + # Per chain q_chains = df.groupby("chain_id").agg('mean',numeric_only=True) - q_chains = q_chains[["Q-score"]] - print("\nBy residue:") - print("----------------------------------------") - pd.set_option('display.max_rows', None) - print(df) - print("\nBy chain:") - print("----------------------------------------") - print(q_chains) - print("\nBy structure:") - print("----------------------------------------") - print(" Mean side chain Q-score:",round(q_sc,3)) - print(" Mean main chain Q-score:",round(q_mc,3)) - print(" Mean overall Q-score:",round(q_all,3)) - print("\n Use --json flag to get json output") + q_chains.drop(columns=["id","resseq","x","y","z","Q-Residue"],inplace=True) + q_chains = q_chains.round(2) + self._print("\n\nBy residue:") + self._print("----------------------------------------") + pd.set_option('display.max_rows', 20) + df.drop(columns=["x","y","z","id","Q-score"],inplace=True) + self._print(df.groupby(["model_id","chain_id","resseq","altloc"]).agg("mean")) + self._print("\n\nBy chain:") + self._print("----------------------------------------") + self._print(q_chains) + self._print("\n\nAll:") + self._print("----------------------------------------") + df = pd.DataFrame({"Main Chain":[q_mc],"Side Chain":[q_sc],"Overall":[q_all]}) + self._print(df) # store in results @@ -123,6 +155,7 @@ def run(self): if self.params.qscore.write_to_bfactor_pdb: self.write_to_bfactor_pdb(model,self.result.qscore_per_atom) + def get_results(self): return self.result @@ -141,7 +174,7 @@ def write_to_bfactor_pdb(self,model,qscore_per_atom): def write_bild_spheres(self): # write bild files if self.params.qscore.write_probes: - print("Writing probe debug files...Using a small selection is recommended", + self._print("Writing probe debug files...Using a small selection is recommended", file=self.logger) debug_path = Path("qscore_debug") debug_path.mkdir(exist_ok=True) From b41cef08e4ce2d564681ef469205d6feea495250 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Mon, 11 Mar 2024 17:20:55 -0700 Subject: [PATCH 198/748] Hide print unless verbose=true --- mmtbx/ligands/ready_set_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/ligands/ready_set_utils.py b/mmtbx/ligands/ready_set_utils.py index d716e9cc30..68195ddd38 100644 --- a/mmtbx/ligands/ready_set_utils.py +++ b/mmtbx/ligands/ready_set_utils.py @@ -63,7 +63,7 @@ def add_n_terminal_hydrogens_to_atom_group(ag, n_ca_c=None, verbose=False, ): - if bonds is None: + if bonds is None and verbose: print('\n\t%s\n' % 'add_n_terminal_hydrogens_to_atom_group has not being given bonds') rc=[] if n_ca_c is not None: From 133c0a41e729fb586cec3fabbe58382b9c6240fd Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 12 Mar 2024 08:27:11 -0700 Subject: [PATCH 199/748] Fix add and subtract tuples_int --- iotbx/map_manager.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/iotbx/map_manager.py b/iotbx/map_manager.py index 1c06356a0c..3313665083 100644 --- a/iotbx/map_manager.py +++ b/iotbx/map_manager.py @@ -2799,8 +2799,18 @@ def get_sites_cart_from_index( sites_frac.append(site_frac) sites_cart = crystal_symmetry.unit_cell().orthogonalize(sites_frac) return sites_cart + def subtract_tuples_int(t1, t2): - return tuple(flex.int(t1)-flex.int(t2)) + try: + return tuple(flex.int(t1)-flex.int(t2)) + except Exception as e: # not integers + t1a = [] + for x in t1: + t1a.append(int(round(x))) + t2a = [] + for x in t2: + t2a.append(int(round(x))) + return tuple(flex.int(tuple(t1a))-flex.int(tuple(t2a))) def add_tuples_int(t1, t2): try: @@ -2808,11 +2818,11 @@ def add_tuples_int(t1, t2): except Exception as e: # not integers t1a = [] for x in t1: - t1a.append(round(x)) + t1a.append(int(round(x))) t2a = [] for x in t2: - t2a.append(round(x)) - return tuple(flex.int(t1a)+flex.int(t2a)) + t2a.append(int(round(x))) + return tuple(flex.int(tuple(t1a))+flex.int(tuple(t2a))) def remove_site_with_most_neighbors(sites_cart): useful_norms_list = [] From c1faca7cadcbaad86a4d18014cf8f8e4cd67bb54 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 12 Mar 2024 10:57:44 -0700 Subject: [PATCH 200/748] Clean up add_tuples_int --- iotbx/map_manager.py | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/iotbx/map_manager.py b/iotbx/map_manager.py index 3313665083..49687512fb 100644 --- a/iotbx/map_manager.py +++ b/iotbx/map_manager.py @@ -2800,29 +2800,25 @@ def get_sites_cart_from_index( sites_cart = crystal_symmetry.unit_cell().orthogonalize(sites_frac) return sites_cart -def subtract_tuples_int(t1, t2): - try: - return tuple(flex.int(t1)-flex.int(t2)) - except Exception as e: # not integers - t1a = [] - for x in t1: - t1a.append(int(round(x))) - t2a = [] - for x in t2: - t2a.append(int(round(x))) - return tuple(flex.int(tuple(t1a))-flex.int(tuple(t2a))) +def _round_tuple_int(t): + new_t = [] + for x in t: + new_t.append(int(round(x))) + return new_t def add_tuples_int(t1, t2): try: return tuple(flex.int(t1)+flex.int(t2)) except Exception as e: # not integers - t1a = [] - for x in t1: - t1a.append(int(round(x))) - t2a = [] - for x in t2: - t2a.append(int(round(x))) - return tuple(flex.int(tuple(t1a))+flex.int(tuple(t2a))) + return tuple( + flex.int(_round_tuple_int(t1)) + flex.int(_round_tuple_int(t2))) + +def subtract_tuples_int(t1, t2): + try: + return tuple(flex.int(t1)-flex.int(t2)) + except Exception as e: # not integers + return tuple( + flex.int(_round_tuple_int(t1)) - flex.int(_round_tuple_int(t2))) def remove_site_with_most_neighbors(sites_cart): useful_norms_list = [] From 28c58040ae9f2957112d358fe884be8d996934e3 Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Tue, 12 Mar 2024 11:01:19 -0700 Subject: [PATCH 201/748] XFEL: remove defaults channel and add natsort Co-authored-by: Derek Mendez Co-authored-by: Billy K. Poon --- xfel/conda_envs/psana_environment.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xfel/conda_envs/psana_environment.yml b/xfel/conda_envs/psana_environment.yml index eb213a9543..2c4191e43e 100644 --- a/xfel/conda_envs/psana_environment.yml +++ b/xfel/conda_envs/psana_environment.yml @@ -3,7 +3,7 @@ channels: - lcls-i - conda-forge - cctbx - - defaults + dependencies: # conda compilers - c-compiler @@ -45,6 +45,7 @@ dependencies: - pandas - pybind11 - setuptools + - natsort # cctbx channel - libsvm_py From 3708dfb0ca8fd8d123b7e03d2543fe8a172e4856 Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Tue, 12 Mar 2024 11:45:02 -0700 Subject: [PATCH 202/748] XFEL: explicitly supress the defaults channel --- xfel/conda_envs/psana_environment.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/xfel/conda_envs/psana_environment.yml b/xfel/conda_envs/psana_environment.yml index 2c4191e43e..d942df5bc3 100644 --- a/xfel/conda_envs/psana_environment.yml +++ b/xfel/conda_envs/psana_environment.yml @@ -3,6 +3,7 @@ channels: - lcls-i - conda-forge - cctbx + - nodefaults dependencies: # conda compilers From 8e4a1f69bacb2218b4d48bd5ed589eecce8de39c Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 12 Mar 2024 11:59:36 -0700 Subject: [PATCH 203/748] Add TODO comments --- mmtbx/hydrogens/reduce_hydrogen.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index 5fc41bc89e..759454c3f6 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -208,6 +208,7 @@ def run(self): ['common_amino_acid', 'modified_amino_acid', 'd_amino_acid']): if ag.get_atom('H'): ag.remove_atom(ag.get_atom('H')) + #TODO this places NH3 at #1 even if there is a non-standard residue rc = add_n_terminal_hydrogens_to_residue_group(rgs) # rc is always empty list? @@ -418,6 +419,7 @@ def add_missing_H_atoms_at_bogus_position(self): # ------------------------------------------------------------------------------ def validate_electrons(self): + #TODO maybe do this only for special places? Metal coordination or linking? from elbow.quantum import electrons atom_valences = electrons.electron_distribution( # XXX How do we get this working on models with alternate locations? @@ -436,6 +438,9 @@ def exclude_H_on_links(self): An exception are HD1 and HE2 of HIS. The mover functionality in reduce will take care of those. + + TODO: Could restraints manager have a list of links with relevant information? + Then we don't have to loop through all proxies here. """ origin_ids = linking_class() grm = self.model.get_restraints_manager() From 9db127039e551454ba98e685467b5fe7015d3fd9 Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 12 Mar 2024 12:09:36 -0700 Subject: [PATCH 204/748] Qscore: bugfix --- cctbx/programs/qscore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cctbx/programs/qscore.py b/cctbx/programs/qscore.py index e136a7e463..3fadc6fc7f 100644 --- a/cctbx/programs/qscore.py +++ b/cctbx/programs/qscore.py @@ -116,7 +116,7 @@ def run(self): if sel_mc.count(True)>0: q_mc = flex.mean(self.result.qscore_per_atom.select(sel_mc)) q_mc = round(q_mc,2) - df.loc[sel_sc.as_numpy_array(),"Main Chain"] = np.array(self.result.qscore_per_atom.select(sel_mc)) + df.loc[sel_mc.as_numpy_array(),"Main Chain"] = np.array(self.result.qscore_per_atom.select(sel_mc)) else: q_mc = None df["Main Chain"] = df["Main Chain"].astype("Float64") From 509ee4daba5445a4899824ddb1460a223b6670a2 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 12 Mar 2024 12:36:24 -0700 Subject: [PATCH 205/748] Add test --- mmtbx/run_tests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index e6ce424360..d37bdbbb51 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -148,6 +148,7 @@ "$D/hydrogens/tst.py", "$D/hydrogens/tst_add_hydrogen.py", "$D/hydrogens/tst_add_hydrogen_2.py", + "$D/hydrogens/tst_add_hydrogen_3.py", "$D/hydrogens/tst_validate_H.py", "$D/hydrogens/tst_connectivity.py", "$D/hydrogens/tst_riding_coefficients.py", From 200d02c79ea65960b3fe35745d58a8ba1f4464ad Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 12 Mar 2024 13:56:59 -0600 Subject: [PATCH 206/748] Allow writing external origin to ccp4 file; minor caption additions to map_model_cc --- iotbx/map_manager.py | 19 ++++++++++++++++--- mmtbx/command_line/map_box.py | 13 +++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/iotbx/map_manager.py b/iotbx/map_manager.py index 49687512fb..8f980dea23 100644 --- a/iotbx/map_manager.py +++ b/iotbx/map_manager.py @@ -286,6 +286,9 @@ def __init__(self, # Initialize that this is not a dummy map_manager self._is_dummy_map_manager = False + # Initialize that there is no output_external_origin + self.output_external_origin = None + # Initialize program_name, limitations, labels self.file_name = file_name # input file (source of this manager) self.program_name = None # Name of program using this manager @@ -456,6 +459,10 @@ def set_unit_cell_crystal_symmetry(self, crystal_symmetry): if self._ncs_object: self._ncs_object = self.shift_ncs_object_to_match_map_and_return_new_ncs_object(self._ncs_object) + def set_output_external_origin(self, value): + assert isinstance(value, tuple) or isinstance(value,list) + self.output_external_origin = tuple(value) + def set_original_origin_and_gridding(self, original_origin = None, gridding = None): @@ -819,6 +826,9 @@ def write_map(self, file_name): Output labels are generated from existing self.labels, self.program_name, and self.limitations + If self.output_external_origin is specified, write that value to file + + ''' # Make sure we have map_data @@ -859,8 +869,11 @@ def write_map(self, file_name): crystal_symmetry = crystal_symmetry, # unit cell and space group map_data = map_data, unit_cell_grid = unit_cell_grid, # optional gridding of full unit cell - origin_shift_grid_units = origin_shift_grid_units, # optional origin shift + origin_shift_grid_units = origin_shift_grid_units, # origin shift labels = labels, + external_origin = self.output_external_origin, + + out = f) self._print(f.getvalue()) else: # map_data has not been shifted to (0, 0, 0). Shift it and then write @@ -2812,11 +2825,11 @@ def add_tuples_int(t1, t2): except Exception as e: # not integers return tuple( flex.int(_round_tuple_int(t1)) + flex.int(_round_tuple_int(t2))) - + def subtract_tuples_int(t1, t2): try: return tuple(flex.int(t1)-flex.int(t2)) - except Exception as e: # not integers + except Exception as e: # not integers return tuple( flex.int(_round_tuple_int(t1)) - flex.int(_round_tuple_int(t2))) diff --git a/mmtbx/command_line/map_box.py b/mmtbx/command_line/map_box.py index 827b34f4a4..97b7d9518f 100644 --- a/mmtbx/command_line/map_box.py +++ b/mmtbx/command_line/map_box.py @@ -677,6 +677,10 @@ def modify_params(params = None, "keep_map_size is False\n", file = log) params.output_format = remove_element(params.output_format, element = 'mtz') + if params.output_external_origin and (not params.keep_origin): + raise Sorry( + "If you specify an external origin you must set keep_origin=True") + if (write_output_files) and ("mtz" in params.output_format) and ( (params.extract_unique)): print("\nNOTE: Skipping write of mtz file as extract_unique = True\n", @@ -1164,6 +1168,7 @@ def run(args, # keep_origin == False leave origin at (0, 0, 0) # keep_origin == True: we shift everything back to where it was, # output_origin_grid_units = 10, 10, 10: output origin is at (10, 10, 10) + # output_external_origin = 10,10,10; set output_external_origin value print("\nBox cell dimensions: (%.2f, %.2f, %.2f) A" %( mam.map_manager().crystal_symmetry().unit_cell().parameters()[:3]), @@ -1212,6 +1217,14 @@ def run(args, 'model', 'ncs_spec', 'real_map', 'miller_array']) dm.set_overwrite(True) + if params.output_external_origin: + assert (isinstance(params.output_external_origin,tuple) or \ + isinstance(params.output_external_origin,list)) and \ + len(params.output_external_origin) == 3 + map_manager.set_output_external_origin(params.output_external_origin) + print("Set output_external_origin to %s" %( + str(params.output_external_origin)), file = log) + # Write PDB file if model: if(params.output_file_name_prefix is None): From 5400b43d8c62e92c2eb96143703da6998cef4bdd Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 13 Mar 2024 12:10:12 -0700 Subject: [PATCH 207/748] Improve test --- mmtbx/programs/fmodel.py | 2 +- mmtbx/regression/tst_fmodel_no_cryst1.py | 38 +++++++++++++++--------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/mmtbx/programs/fmodel.py b/mmtbx/programs/fmodel.py index 7491d78317..2a7039c556 100644 --- a/mmtbx/programs/fmodel.py +++ b/mmtbx/programs/fmodel.py @@ -389,7 +389,7 @@ def run(self): xray_structure = pdb_hierarchy.extract_xray_structure(crystal_symmetry = cs) if (cs is None): cs = xray_structure.crystal_symmetry() print('\nCrystal symmetry used: ', file=self.logger) - cs.show_summary() + cs.show_summary(f=self.logger) if (miller_array is not None): if (miller_array.crystal_symmetry() is None): diff --git a/mmtbx/regression/tst_fmodel_no_cryst1.py b/mmtbx/regression/tst_fmodel_no_cryst1.py index 6096df9559..28ea9befac 100644 --- a/mmtbx/regression/tst_fmodel_no_cryst1.py +++ b/mmtbx/regression/tst_fmodel_no_cryst1.py @@ -1,12 +1,12 @@ from __future__ import absolute_import, division, print_function -from libtbx import easy_run from mmtbx.programs import fmodel from iotbx.cli_parser import run_program from libtbx.utils import null_out, Sorry import os def exercise(): - with open("tmp_fmodel_fake_p1.pdb", "w") as f: + model_fn = "tmp_fmodel_fake_p1.pdb" + with open(model_fn, "w") as f: f.write("""\ ATOM 47 N TYR A 7 8.292 1.817 6.147 1.00 14.70 N ATOM 48 CA TYR A 7 9.159 2.144 7.299 1.00 15.18 C @@ -22,25 +22,35 @@ def exercise(): ATOM 58 OH TYR A 7 3.766 0.589 10.291 1.00 14.39 O ATOM 59 OXT TYR A 7 11.358 2.999 7.612 1.00 17.49 O """) - args = ["phenix.fmodel", "tmp_fmodel_fake_p1.pdb", "high_resolution=2", + args = [model_fn, "high_resolution=2", "output.file_name=tmp_fmodel_fake_p1.mtz"] - result = easy_run.fully_buffered(args) - assert (result.return_code != 0) and (len(result.stderr_lines) > 0) + try: + run_program(program_class=fmodel.Program, args=args, logger=null_out()) + except Sorry as s: + assert('Symmetry information in model file is incomplete or missing' + in str(s)) + else: + raise Exception_expected args.append("generate_fake_p1_symmetry=True") - result = easy_run.fully_buffered(args).raise_if_errors() - assert (result.return_code == 0) - assert os.path.isfile("tmp_fmodel_fake_p1.mtz") + r = run_program(program_class=fmodel.Program, args=args, logger=null_out()) + assert os.path.isfile(r.output_file) from iotbx import crystal_symmetry_from_any - symm = crystal_symmetry_from_any.extract_from("tmp_fmodel_fake_p1.mtz") + symm = crystal_symmetry_from_any.extract_from(r.output_file) assert (str(symm.space_group_info()) == "P 1") - args.append("tmp_fmodel_fake_p1.mtz") + args.append(r.output_file) args.append("labels.name=FMODEL,PHIFMODEL") - try : + try: run_program(program_class=fmodel.Program, args=args, logger=null_out()) - except Sorry : - pass - else : + except Sorry as s: + assert('high_resolution and low_resolution must be undefined if reflection' + in str(s)) + else: raise Exception_expected + + # Clean up files + os.remove(r.output_file) + os.remove(model_fn) + print("OK") if (__name__ == "__main__"): From 12249522d0675a7529c849d55197b3b7c7d09cc3 Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 13 Mar 2024 16:31:44 -0600 Subject: [PATCH 208/748] Add short_captions --- mmtbx/maps/map_model_cc.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mmtbx/maps/map_model_cc.py b/mmtbx/maps/map_model_cc.py index afc4a851c9..146f115ced 100644 --- a/mmtbx/maps/map_model_cc.py +++ b/mmtbx/maps/map_model_cc.py @@ -15,7 +15,8 @@ resolution = None .type = float .help = Data (map) resolution - .expert_level=0 + .short_caption = Resolution (optional in GUI) + .expert_level=1 scattering_table = wk1995 it1992 n_gaussian neutron *electron .type = choice .help = Scattering table (X-ray, neutron or electron) @@ -23,6 +24,7 @@ atom_radius = None .type = float .help = Atom radius for masking. If undefined then calculated automatically + .short_caption = Atom radius (optional) .expert_level=0 keep_map_calc = False .type = bool @@ -31,6 +33,7 @@ wrapping = None .type = bool .help = You can specify whether your maps wrap around outside boundaries + .short_caption = Wrapping (optional) .expert_level=3 ignore_symmetry_conflicts = False .type = bool @@ -43,15 +46,19 @@ cc_per_chain = True .type = bool .help = Compute local model-map CC for each chain + .short_caption = CC by chain cc_per_residue = True .type = bool .help = Compute local model-map CC for each residue + .short_caption = CC by residue cc_per_residue_group = False .type = bool .help = Compute local model-map CC for each residue group + .short_caption = CC by residue group fsc = True .type = bool .help = Compute FSC + .short_caption = FSC cc_mask = True .type = bool cc_volume = True From 0586a1e68617b7d025b59af9385ae81f59309cb6 Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 13 Mar 2024 16:32:47 -0700 Subject: [PATCH 209/748] Replace all map correlation tools with MapCorrelations --- mmtbx/regression/tst_map_model_cc.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmtbx/regression/tst_map_model_cc.py b/mmtbx/regression/tst_map_model_cc.py index e4ff8a9b14..99fcb6ab54 100644 --- a/mmtbx/regression/tst_map_model_cc.py +++ b/mmtbx/regression/tst_map_model_cc.py @@ -83,6 +83,7 @@ def run(prefix="tst_map_model_cc"): checked = 0 cmd = " ".join([ "phenix.map_model_cc", + "force", "%s_shifted.pdb"%prefix, "%s_shifted.ccp4"%prefix, "resolution=1.5", From 6163b4d115294b38c3a5da4faee99c3171388b03 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 14 Mar 2024 11:30:20 -0700 Subject: [PATCH 210/748] Fixes for reduce2 --- .../quantum_restraints_manager.py | 15 ++++-- mmtbx/hydrogens/reduce_hydrogen.py | 32 +++++++++++- mmtbx/ligands/chemistry.py | 16 ++++++ mmtbx/ligands/hierarchy_utils.py | 18 ++----- mmtbx/ligands/ready_set_utils.py | 1 + mmtbx/monomer_library/linking_mixins.py | 12 +++-- mmtbx/programs/quantum_interface.py | 50 ++++++++++++++++--- 7 files changed, 115 insertions(+), 29 deletions(-) diff --git a/mmtbx/geometry_restraints/quantum_restraints_manager.py b/mmtbx/geometry_restraints/quantum_restraints_manager.py index 285cebecc4..a5d059ffd0 100644 --- a/mmtbx/geometry_restraints/quantum_restraints_manager.py +++ b/mmtbx/geometry_restraints/quantum_restraints_manager.py @@ -374,6 +374,7 @@ def get_ligand_buffer_models(model, qmr, verbose=False, write_steps=False, log=N else: buffer_selection_string = 'residues_within(%s, %s)' % (qmr.buffer, qmr.selection) + if debug: print('buffer_selection_string',buffer_selection_string) buffer_model = select_and_reindex(model, buffer_selection_string) if write_steps: write_pdb_file(buffer_model, 'pre_remove_altloc.pdb', None) if 0: retain_only_one_alternative_conformation(buffer_model, 'B') @@ -408,7 +409,9 @@ def compare_id_str(s1,s2): return True return False for atom1 in ligand_atoms: + if debug: print('ligand',atom1.quote()) for atom2 in buffer_atoms: + if debug: print('buffer',atom2.quote()) if compare_id_str(atom1.id_str(), atom2.id_str()): break else: @@ -633,12 +636,14 @@ def update_bond_restraints(ligand_model, else: if not(i_atom.tmp in ligand_i_seqs and j_atom.tmp in ligand_i_seqs): continue - print(' %-2d %s - %s %5.3f ~> %5.3f' % ( + Z=(distance_model-bond.distance_ideal)/sigma + print(' %-2d %s - %s %5.3f ~> %5.3f (Z=%4.1f)' % ( i, i_atom.id_str().replace('pdb=',''), j_atom.id_str().replace('pdb=',''), bond.distance_ideal, - distance_model), file=log) + distance_model, + Z), file=log) bond.distance_ideal=distance_model i_seqs=[i_atom.tmp, j_atom.tmp] bond=model_grm.geometry.bond_params_table.lookup(*list(i_seqs)) @@ -728,13 +733,15 @@ def update_angle_restraints(ligand_model, # ligand_lookup[key]=angle_model # key = (int(i_seqs[0]), int(i_seqs[1]), int(i_seqs[2])) i+=1 - print(' %-2d %s - %s - %s %5.1f ~> %5.1f' % ( + Z=(angle_model-angle_ideal)/sigma + print(' %-2d %s - %s - %s %5.1f ~> %5.1f (Z=%4.1f)' % ( i, i_atom.id_str().replace('pdb=',''), j_atom.id_str().replace('pdb=',''), k_atom.id_str().replace('pdb=',''), angle_ideal, - angle_model), file=log) + angle_model, + Z), file=log) assert len(intersect)!=0, '%s' % intersect # key = (atoms[key[0]].tmp, atoms[key[1]].tmp, atoms[key[2]].tmp) # model_lookup[key]=angle_model diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index 759454c3f6..19517ff065 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -404,6 +404,7 @@ def add_missing_H_atoms_at_bogus_position(self): for mh in missing_h: # TODO: this should be probably in a central place + # NWM: I have something like this in ready_set_utils if len(mh) < 4: mh = (' ' + mh).ljust(4) a = (iotbx.pdb.hierarchy.atom() .set_name(new_name=mh) @@ -442,10 +443,12 @@ def exclude_H_on_links(self): TODO: Could restraints manager have a list of links with relevant information? Then we don't have to loop through all proxies here. """ + from mmtbx.ligands.chemistry import get_valences origin_ids = linking_class() grm = self.model.get_restraints_manager() bond_proxies_simple, asu = grm.geometry.get_all_bond_proxies( sites_cart = self.model.get_sites_cart()) + atoms = self.model.get_atoms() elements = self.model.get_hierarchy().atoms().extract_element() exclusion_iseqs = list() exclusion_dict = dict() @@ -463,13 +466,18 @@ def exclude_H_on_links(self): exclusion_dict[j] = proxy.origin_id sel_remove = flex.size_t() - atoms = self.model.get_atoms() # Find H atoms bound to linked atoms removed_dict = dict() + parent_dict = dict() + bonds = dict() for proxy in all_proxies: if( isinstance(proxy, ext.bond_simple_proxy)): i,j=proxy.i_seqs elif(isinstance(proxy, ext.bond_asu_proxy)): i,j=proxy.i_seq,proxy.j_seq else: assert 0 # never goes here + bonds.setdefault(i,[]) + bonds[i].append(j) + bonds.setdefault(j,[]) + bonds[j].append(i) # Exception for HIS HD1 and HE2 if (atoms[i].parent().resname == 'HIS' and atoms[i].name.strip() in ['HD1','DD1', 'HE2', 'DE2']): continue @@ -478,9 +486,31 @@ def exclude_H_on_links(self): if(elements[i] in ["H","D"] and j in exclusion_iseqs): sel_remove.append(i) removed_dict[i] = exclusion_dict[j] + parent_dict[i]=j if(elements[j] in ["H","D"] and i in exclusion_iseqs): sel_remove.append(j) removed_dict[j] = exclusion_dict[i] + parent_dict[j]=i + # remove H atoms NOT to remove - double negative! + remove_from_sel_remove=[] + for ii, i_seq in reversed(list(enumerate(sel_remove))): + j_seq=parent_dict[i_seq] + # need to add the use of atomic charge + valences=get_valences(elements[j_seq]) + number_of_bonds=len(bonds[j_seq]) + if number_of_bonds in valences: + # remove this H from delection + remove_from_sel_remove.append(i_seq) # ?? + del removed_dict[i_seq] + else: + bonds[j_seq].remove(i_seq) + bonds[i_seq].remove(j_seq) + if remove_from_sel_remove: + sel_remove=list(sel_remove) + for r in remove_from_sel_remove: + sel_remove.remove(r) + # print('keep',atoms[r].quote()) + sel_remove=flex.size_t(sel_remove) # sl_removed = [(atom.id_str().replace('pdb=','').replace('"',''), origin_ids.get_origin_key(removed_dict[atom.i_seq])) diff --git a/mmtbx/ligands/chemistry.py b/mmtbx/ligands/chemistry.py index 8cab981cc1..29db643941 100644 --- a/mmtbx/ligands/chemistry.py +++ b/mmtbx/ligands/chemistry.py @@ -79,3 +79,19 @@ 0, 0, 1, 2, 3, 0, 0, 0, ) + +def get_valences(element, atomic_number=None, charge=0): + assert atomic_number!=0 + assert type(charge) is type(1) + if atomic_number is None: + atomic_number = elements.index(element.title()) + rc = valences[atomic_number] + if rc is None: return [] + if type(rc)==type([]): + for i, j in enumerate(rc): + rc[i]+=charge + return rc + else: + rc += charge + return [rc] + diff --git a/mmtbx/ligands/hierarchy_utils.py b/mmtbx/ligands/hierarchy_utils.py index c5319bf080..0921d502f7 100644 --- a/mmtbx/ligands/hierarchy_utils.py +++ b/mmtbx/ligands/hierarchy_utils.py @@ -118,26 +118,18 @@ def get_bonds_as_dict(geometry_restraints_manager, include_non_zero_origin_id=Tr tmp.append(p.i_seqs[0]) return bonds -def get_valences(element, charge): - valence = { - # 'C' : 4, - 'N' : 3, - 'O' : 2, - } - rc = valence.get(element) - if rc is None: return [] - rc += charge - return [rc] - def simple_valence_check(ph, geometry_restraints_manager): + from mmtbx.ligands.chemistry import get_valences bonds = get_bonds_as_dict(geometry_restraints_manager.geometry) for atom in ph.atoms(): if atom.element_is_hydrogen(): continue if atom.parent().resname in ['HOH']: continue number_of_bonds = len(bonds.get(atom.i_seq, None)) # if number_of_bonds is None: continue - if number_of_bonds not in get_valences(atom.element, atom.charge_as_int()): - assert 0 + # print(atom.quote(), number_of_bonds, get_valences(atom.element, atom.charge_as_int())) + v = get_valences(atom.element, charge=atom.charge_as_int()) + if number_of_bonds not in v: + print(atom.quote(), number_of_bonds, v) def main(filename): from iotbx import pdb diff --git a/mmtbx/ligands/ready_set_utils.py b/mmtbx/ligands/ready_set_utils.py index 68195ddd38..de8955982e 100644 --- a/mmtbx/ligands/ready_set_utils.py +++ b/mmtbx/ligands/ready_set_utils.py @@ -149,6 +149,7 @@ def _get_atom_with_i_seq(ag, i_seq): if ag.resname=='PRO': if i==0: continue + # _new_atom in heirarchy_utils.py atom = iotbx.pdb.hierarchy.atom() atom.name = name atom.element = proton_element diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index bcb39e8e90..d1bcbbef5e 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -518,6 +518,7 @@ def _nonbonded_pair_generator_geometry_restraints_sort( # # if verbose: + print('='*80) print('nonbonded', i_seq, j_seq, atom1.quote(), end=' ') print(atom2.quote(), end=' ') print("Distance: %0.2f" % distance, rt_mx_ji, sym_op) @@ -583,10 +584,11 @@ def _nonbonded_pair_generator_geometry_restraints_sort( key.append(str(rt_mx_ji)) key = tuple(key) # hydrogens - if atom1.element.strip() in hydrogens: - done[atom2.id_str()] = atom1.id_str() - if atom2.element.strip() in hydrogens: - done[atom1.id_str()] = atom2.id_str() + if atom1.parent().parent().resseq==atom2.parent().parent().resseq: + if atom1.element.strip() in hydrogens: + done[atom2.id_str()] = atom1.id_str() + if atom2.element.strip() in hydrogens: + done[atom1.id_str()] = atom2.id_str() # bond length cutoff & some logic aa_rc = linking_utils.is_atom_pair_linked( atom1, @@ -621,6 +623,7 @@ def _nonbonded_pair_generator_geometry_restraints_sort( print('link_metals',link_metals) if ( atom1.element.strip().upper() in hydrogens or atom2.element.strip().upper() in hydrogens): + if verbose: print('hydrogens') pass else: done.setdefault(key, []) @@ -691,6 +694,7 @@ def _nonbonded_pair_generator_geometry_restraints_sort( if atom2_key: if atom2_key in done: continue done[atom2_key] = key + if verbose: print(done) # current_number_of_links = len(done.setdefault(key, [])) if(current_number_of_links >= diff --git a/mmtbx/programs/quantum_interface.py b/mmtbx/programs/quantum_interface.py index 6cb8f8b106..fc088bf68e 100644 --- a/mmtbx/programs/quantum_interface.py +++ b/mmtbx/programs/quantum_interface.py @@ -229,6 +229,28 @@ def generate_flipping_NQ(ag, else: yield rc +def should_get_selection_from_user(params): + def qm_restraints_has_selection(params): + if len(params.qi.qm_restraints)==0: + return True + if not params.qi.qm_restraints[0].selection: + return True + return False + bools = [ + qm_restraints_has_selection(params), + not params.qi.each_amino_acid, + not params.qi.each_water, + not params.qi.merge_water, + ] + bc=0 + if not params.qi.selection: + for i, boolean in enumerate(bools): + print(i, boolean) + if boolean: bc+=1 + else: + return False + return bc==len(bools) + def get_selection_from_user(hierarchy, include_amino_acids=None, log=None): j=0 opts = [] @@ -383,15 +405,27 @@ def run(self, log=None): include_amino_acids=self.params.qi.include_amino_acids if include_amino_acids: include_amino_acids=[include_amino_acids] - if (not self.params.qi.selection and - len(self.params.qi.qm_restraints)==0 and - not self.params.qi.each_amino_acid and - not self.params.qi.each_water and - not self.params.qi.merge_water - ): + + rc = should_get_selection_from_user(self.params) + print(dir(self.params)) + print('rc',rc) + if rc: + # if (not self.params.qi.selection and + # len(self.params.qi.qm_restraints)==0 and + # not self.params.qi.each_amino_acid and + # not self.params.qi.each_water and + # not self.params.qi.merge_water + # ): rc = get_selection_from_user(model.get_hierarchy(), include_amino_acids=include_amino_acids) + print('rc',rc) self.params.qi.selection = rc + if len(self.params.qi.qm_restraints)!=0: + print(self.params.qi.qm_restraints) + for attr, item in self.params.qi.qm_restraints[0].__dict__.items(): + print(attr, item) + # print(self.params.qi.selection) + # print(getattr(self.params.qi.selection, attr)) # # validate selection # @@ -509,7 +543,6 @@ def run(self, log=None): ih, pf), file=self.logger) - # if self.params.qi.run_qmr: else: rc = self.run_qmr(self.params.qi.format) print(rc) @@ -535,6 +568,8 @@ def run(self, log=None): model.set_sites_cart(sites_cart) if self.params.qi.write_qmr_phil: + # for attr, item in self.params.qi.qm_restraints[0].__dict__.items(): + # print(attr, item) pf = self.write_qmr_phil(iterate_NQH=self.params.qi.iterate_NQH, iterate_metals=self.params.qi.iterate_metals, step_buffer_radius=self.params.qi.step_buffer_radius, @@ -1229,6 +1264,7 @@ def safe_filename(s): s=s.replace("'",'') return s + print(self.params.qi.selection) pf = '%s_%s.phil' % ( self.data_manager.get_default_model_name().replace('.pdb',''), safe_filename(self.params.qi.selection[0]), From be67fedf6c50c093eb644b0469aeabe4d06364c1 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 14 Mar 2024 11:58:00 -0700 Subject: [PATCH 211/748] small change --- mmtbx/ligands/ready_set_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mmtbx/ligands/ready_set_utils.py b/mmtbx/ligands/ready_set_utils.py index de8955982e..943315d6bb 100644 --- a/mmtbx/ligands/ready_set_utils.py +++ b/mmtbx/ligands/ready_set_utils.py @@ -63,8 +63,8 @@ def add_n_terminal_hydrogens_to_atom_group(ag, n_ca_c=None, verbose=False, ): - if bonds is None and verbose: - print('\n\t%s\n' % 'add_n_terminal_hydrogens_to_atom_group has not being given bonds') + if verbose and bonds is None: + print('\n\t%s\n' % 'add_n_terminal_hydrogens_to_atom_group has not been given bonds') rc=[] if n_ca_c is not None: n, ca, c = n_ca_c From d43c2a517f57d857047ba20d521e249b3c99b690 Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 14 Mar 2024 14:26:26 -0600 Subject: [PATCH 212/748] Remove model_as_pdb() from cctbx_website docs --- cctbx_website/html_files/doc_hlo_model_manager.html | 4 +++- cctbx_website/html_files/doc_models_hierarchy.html | 8 ++++++-- cctbx_website/html_files/script_1.html | 11 +++++++++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/cctbx_website/html_files/doc_hlo_model_manager.html b/cctbx_website/html_files/doc_hlo_model_manager.html index d64e8531b3..4aa2cd00bd 100644 --- a/cctbx_website/html_files/doc_hlo_model_manager.html +++ b/cctbx_website/html_files/doc_hlo_model_manager.html @@ -148,8 +148,10 @@

Atom selections with the Model Manager

Now ca_only_model is a new model that contains a piece of the original model object. In this case it contains all the atoms with the name “CA”. Let’s print it in PDB format to see what residues are present:

-
print (ca_only_model.model_as_pdb())      #  print out the CA-only model in PDB format
+
print (ca_only_model.as_pdb_or_mmcif_string())      #  print out the CA-only model in PDB format
 
+

Note that if the model did not fit in PDB format it would write in mmCIF +format instead.

map_and_model diff --git a/cctbx_website/html_files/doc_models_hierarchy.html b/cctbx_website/html_files/doc_models_hierarchy.html index 16d174ad22..8f5289406a 100644 --- a/cctbx_website/html_files/doc_models_hierarchy.html +++ b/cctbx_website/html_files/doc_models_hierarchy.html @@ -77,8 +77,8 @@

Quick overview

residue_group.remove_atom_group(atom_group) if (residue_group.atom_groups_size() == 0): chain.remove_residue_group(residue_group) -with open("model_Zn_free.pdb", "w") as f: - f.write(m.model_as_pdb()) +model_file_name = dm.write_model_file(m, "model_Zn_free.pdb") +print("File name written: %s" %(model_file_name))

This will change the hierarchy in place, i.e. we removed the ZN atoms from the hierarchy and cannot recover it.
@@ -86,6 +86,10 @@

Quick overview

pdb_hierarchy = model.get_hierarchy() #   Get hierarchy object
 
+

We also wrote the model out using the data manager and obtained the +actual file name written. This last step is necessary because a model that +does not fit in PDB format will be written out as mmCIF with the suffix .cif. +

It is possible to get a pdb_hierarchy() object directly:

diff --git a/cctbx_website/html_files/script_1.html b/cctbx_website/html_files/script_1.html index d542c053da..430ec92a95 100644 --- a/cctbx_website/html_files/script_1.html +++ b/cctbx_website/html_files/script_1.html @@ -56,10 +56,17 @@

Create a random structure and save as PDB

Save the model as PDB file:

# Write it into PDB file
-with open("model.pdb","w") as fo:
-  fo.write(model.model_as_pdb())
+from iotbx.data_manager import DataManager
+dm = DataManager()
+dm.set_overwrite(True)
+output_file_name = dm.write_model_file(model, "model.pdb")
+print("Output file name: %s" %(output_file_name))
 
+

Note that we have used the data_manager to write out the model file. If the +model fits in PDB format it will write as PDB with the suffix .pdb, but if it +does not fit it will write as mmCIF with the suffix .cif.

+

Here is an example for a model that was created using this procedure (your model will look different, as the procedue will place the atoms at random places):

fig1 From 777437f7cb09e0ae1d28560e8c418689d426352d Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 14 Mar 2024 16:01:17 -0600 Subject: [PATCH 213/748] Move plan_sad_experiment to program_template --- mmtbx/command_line/plan_sad_experiment.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mmtbx/command_line/plan_sad_experiment.py b/mmtbx/command_line/plan_sad_experiment.py index 8c301406a5..7fa384ee58 100644 --- a/mmtbx/command_line/plan_sad_experiment.py +++ b/mmtbx/command_line/plan_sad_experiment.py @@ -1,5 +1,3 @@ -# LIBTBX_SET_DISPATCHER_NAME phenix.plan_sad_experiment - from __future__ import absolute_import, division, print_function import mmtbx.scaling.plan_sad_experiment from mmtbx.scaling.plan_sad_experiment import get_fp_fdp, get_residues_and_ha @@ -11,7 +9,7 @@ import sys from six.moves import range -master_phil = iotbx.phil.parse(""" +master_params = """ include scope libtbx.phil.interface.tracking_params input_files { data = None @@ -263,8 +261,8 @@ .help = '''Verbose output''' .short_caption = Verbose output } -""", process_includes=True) -master_params = master_phil +""" +master_phil = iotbx.phil.parse(master_params, process_includes=True) def get_params(args,out=sys.stdout): command_line = iotbx.phil.process_command_line_with_files( @@ -537,3 +535,4 @@ def finish_job(result): if __name__=="__main__": run(sys.argv[1:]) + From 49489b14574d1b169531852d5c297d570643a05d Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 14 Mar 2024 15:06:28 -0700 Subject: [PATCH 214/748] Reduce2: Add tests --- mmtbx/hydrogens/tst_add_hydrogen_2.py | 64 +----- mmtbx/hydrogens/tst_add_hydrogen_3.py | 320 +++++++++++++++++++++++++- 2 files changed, 316 insertions(+), 68 deletions(-) diff --git a/mmtbx/hydrogens/tst_add_hydrogen_2.py b/mmtbx/hydrogens/tst_add_hydrogen_2.py index 7e7b6fb3af..77fb55f3c2 100644 --- a/mmtbx/hydrogens/tst_add_hydrogen_2.py +++ b/mmtbx/hydrogens/tst_add_hydrogen_2.py @@ -18,8 +18,7 @@ def run(): test_006() test_007() test_008() - #test_009() - test_010() + test_009() # ------------------------------------------------------------------------------ @@ -172,19 +171,10 @@ def test_008(): # ------------------------------------------------------------------------------ def test_009(): - ''' - 1KYC: SIN linked to GLU1, but later in file. Goal: no NH3 to GLU. - ''' - compare_models(pdb_str = pdb_str_009) - assert 0 - -# ------------------------------------------------------------------------------ - -def test_010(): ''' 7JX4: ACE linked to GLY1 Goal: H1,2,3 on ACE and no H to HYP. ''' - compare_models(pdb_str = pdb_str_010) + compare_models(pdb_str = pdb_str_009) # ------------------------------------------------------------------------------ @@ -644,56 +634,6 @@ def test_010(): ''' pdb_str_009 = ''' -REMARK 1KYC: SIN is linked to GLU 1, but at end of model file -CRYST1 19.769 30.000 32.270 90.00 90.00 90.00 P 1 -ATOM 1 N GLU A 1 9.100 10.903 6.846 1.00 18.32 N -ATOM 2 CA GLU A 1 8.321 10.315 7.917 1.00 16.97 C -ATOM 3 C GLU A 1 9.162 9.612 8.973 1.00 15.25 C -ATOM 4 O GLU A 1 8.910 9.774 10.170 1.00 14.23 O -ATOM 5 CB GLU A 1 7.291 9.304 7.380 1.00 17.54 C -ATOM 6 CG GLU A 1 6.485 8.581 8.454 1.00 19.79 C -ATOM 7 CD GLU A 1 5.488 9.479 9.156 1.00 20.81 C -ATOM 8 OE1 GLU A 1 5.000 10.445 8.534 1.00 23.39 O -ATOM 9 OE2 GLU A 1 5.180 9.223 10.333 1.00 21.60 O -ATOM 10 HA GLU A 1 7.863 11.056 8.343 1.00 16.97 H -ATOM 11 HB2 GLU A 1 6.662 9.777 6.812 1.00 17.54 H -ATOM 12 HB3 GLU A 1 7.761 8.630 6.865 1.00 17.54 H -ATOM 13 HG2 GLU A 1 7.094 8.232 9.123 1.00 19.79 H -ATOM 14 HG3 GLU A 1 5.993 7.854 8.042 1.00 19.79 H -ATOM 15 N GLU A 2 10.111 8.769 8.574 1.00 15.28 N -ATOM 16 CA GLU A 2 10.916 8.018 9.519 1.00 14.99 C -ATOM 17 C GLU A 2 11.541 8.882 10.615 1.00 13.85 C -ATOM 18 O GLU A 2 11.362 8.667 11.822 1.00 13.88 O -ATOM 19 CB GLU A 2 12.024 7.270 8.757 1.00 16.20 C -ATOM 20 CG GLU A 2 12.869 6.426 9.713 1.00 17.22 C -ATOM 21 CD GLU A 2 14.152 5.903 9.124 1.00 17.43 C -ATOM 22 OE1 GLU A 2 14.556 6.396 8.052 1.00 18.62 O -ATOM 23 OE2 GLU A 2 14.769 5.000 9.734 1.00 17.26 O -ATOM 24 H GLU A 2 10.307 8.616 7.751 1.00 15.28 H -ATOM 25 HA GLU A 2 10.334 7.388 9.972 1.00 14.99 H -ATOM 26 HB2 GLU A 2 12.604 7.912 8.318 1.00 16.20 H -ATOM 27 HB3 GLU A 2 11.622 6.681 8.099 1.00 16.20 H -ATOM 28 HG2 GLU A 2 13.101 6.970 10.482 1.00 17.22 H -ATOM 29 HG3 GLU A 2 12.344 5.661 9.995 1.00 17.22 H -HETATM 30 O1 SO4 A 101 11.629 25.000 26.048 0.50 20.11 O -HETATM 31 O2 SO4 A 101 10.541 22.822 26.297 0.50 21.85 O -HETATM 32 O3 SO4 A 101 9.524 24.537 24.875 0.50 20.45 O -HETATM 33 O4 SO4 A 101 9.520 24.852 27.270 0.50 19.22 O -HETATM 34 S SO4 A 101 10.313 24.291 26.126 0.50 19.91 S -HETATM 35 C1 SIN A 0 10.126 11.723 7.051 1.00 19.39 C -HETATM 36 C2 SIN A 0 10.828 12.260 5.817 1.00 21.62 C -HETATM 37 C3 SIN A 0 11.448 13.629 6.056 1.00 22.69 C -HETATM 38 C4 SIN A 0 10.468 14.784 6.095 1.00 23.92 C -HETATM 39 O1 SIN A 0 10.519 11.999 8.189 1.00 19.91 O -HETATM 40 O3 SIN A 0 10.949 15.933 6.216 1.00 24.14 O -HETATM 41 O4 SIN A 0 9.264 14.547 6.337 1.00 25.37 O -HETATM 42 H21 SIN A 0 10.110 12.330 5.000 1.00 21.62 H -HETATM 43 H22 SIN A 0 11.609 11.561 5.518 1.00 21.62 H -HETATM 44 H31 SIN A 0 11.985 13.602 7.004 1.00 22.69 H -HETATM 45 H32 SIN A 0 12.173 13.820 5.265 1.00 22.69 H -''' - -pdb_str_010 = ''' REMARK 7JX4: ACE linked at GLY 1 and HYP (PRO-like) CRYST1 72.365 24.756 25.357 90.00 98.72 90.00 C 1 2 1 HETATM 1 C ACE A 0 38.724 1.027 10.647 1.00 35.12 C diff --git a/mmtbx/hydrogens/tst_add_hydrogen_3.py b/mmtbx/hydrogens/tst_add_hydrogen_3.py index 6d9f28a14b..0d9f3b75be 100644 --- a/mmtbx/hydrogens/tst_add_hydrogen_3.py +++ b/mmtbx/hydrogens/tst_add_hydrogen_3.py @@ -3,22 +3,26 @@ import mmtbx.model import iotbx.pdb from mmtbx.hydrogens import reduce_hydrogen +from mmtbx.hydrogens.tst_add_hydrogen import compare_models from libtbx.utils import null_out #from libtbx.test_utils import approx_equal # ------------------------------------------------------------------------------ def run(): - test_000(pdb_str = pdb_str_000) - test_001(pdb_str = pdb_str_001) + test_000() + test_001() + test_002() + test_003() + test_004() # ------------------------------------------------------------------------------ -def test_000(pdb_str): +def test_000(): ''' Make sure reduce does not crash for single_atom_residue models ''' - pdb_inp = iotbx.pdb.input(lines=pdb_str.split("\n"), source_info=None) + pdb_inp = iotbx.pdb.input(lines=pdb_str_000.split("\n"), source_info=None) # initial model (has no H atoms) model_initial = mmtbx.model.manager(model_input = pdb_inp, log = null_out()) number_h_expected = model_initial.get_hd_selection().count(True) @@ -34,12 +38,12 @@ def test_000(pdb_str): # ------------------------------------------------------------------------------ -def test_001(pdb_str): +def test_001(): ''' Check keyword n_terminal_charge: NH3 on resseq 1, first residue in chain, or no NH3 at all ''' - pdb_inp = iotbx.pdb.input(lines=pdb_str.split("\n"), source_info=None) + pdb_inp = iotbx.pdb.input(lines=pdb_str_001.split("\n"), source_info=None) # initial model model_initial = mmtbx.model.manager(model_input = pdb_inp, log = null_out()) # @@ -88,6 +92,33 @@ def test_001(pdb_str): # ------------------------------------------------------------------------------ +def test_002(): + ''' + SIN forms covalent link to GLU 1. Make sure the default NH3 at the + N-terminal becomes a single peptide H in this particular scenario. + ''' + compare_models(pdb_str = pdb_str_002) + +# ------------------------------------------------------------------------------ + +def test_003(): + ''' + Carbohydrate forms covlalent link to ASN. Make sure valence is correct for + the NAG and protein links. Both parts are in double conformation. + ''' + compare_models(pdb_str = pdb_str_003) + +# ------------------------------------------------------------------------------ + +def test_004(): + ''' + Carbohydrate forms covlalent link to ASN. Make sure valence is correct for + the NAG and protein links. + ''' + compare_models(pdb_str = pdb_str_004) + +# ------------------------------------------------------------------------------ + pdb_str_000 = """ REMARK Make sure reduce does not crash for single_atom_residue models CRYST1 22.029 33.502 24.035 90.00 90.00 90.00 P 1 @@ -175,6 +206,283 @@ def test_001(pdb_str): END """ +pdb_str_002 = """ +REMARK Make sure linking and valence are correct (keep one H of NH3 terminal) +CRYST1 33.386 33.386 65.691 90.00 90.00 120.00 H 3 2 +SCALE1 0.029953 0.017293 0.000000 0.00000 +SCALE2 0.000000 0.034586 0.000000 0.00000 +SCALE3 0.000000 0.000000 0.015223 0.00000 +ATOM 1 N GLU A 1 10.117 25.200 2.571 1.00 -1.00 N +ANISOU 1 N GLU A 1 3000 2835 1127 208 -142 -228 N +ATOM 2 CA GLU A 1 9.338 24.612 3.642 1.00 -1.00 C +ANISOU 2 CA GLU A 1 2595 2691 1161 236 -238 -217 C +ATOM 3 C GLU A 1 10.179 23.909 4.698 1.00 -1.00 C +ANISOU 3 C GLU A 1 2462 2375 957 271 -124 -310 C +ATOM 4 O GLU A 1 9.927 24.071 5.895 1.00 -1.00 O +ANISOU 4 O GLU A 1 2439 2116 850 143 -268 -383 O +ATOM 5 CB GLU A 1 8.308 23.601 3.105 1.00 -1.00 C +ANISOU 5 CB GLU A 1 2772 2664 1227 243 -283 -303 C +ATOM 6 CG GLU A 1 7.502 22.878 4.179 1.00 -1.00 C +ANISOU 6 CG GLU A 1 2867 3180 1472 61 -157 -268 C +ATOM 7 CD GLU A 1 6.505 23.776 4.881 1.00 -1.00 C +ANISOU 7 CD GLU A 1 3055 3241 1610 122 -165 -363 C +ATOM 8 OE1 GLU A 1 6.017 24.742 4.259 1.00 -1.00 O +ANISOU 8 OE1 GLU A 1 3535 3430 1924 346 -221 -295 O +ATOM 9 OE2 GLU A 1 6.197 23.520 6.058 1.00 -1.00 O +ANISOU 9 OE2 GLU A 1 3239 3344 1625 40 -119 -371 O +ATOM 10 H1 GLU A 1 9.876 24.837 1.795 1.00 18.32 H +ATOM 13 HA GLU A 1 8.880 25.353 4.068 1.00 16.97 H +ATOM 14 HB2 GLU A 1 7.679 24.074 2.537 1.00 17.54 H +ATOM 15 HB3 GLU A 1 8.778 22.927 2.590 1.00 17.54 H +ATOM 16 HG2 GLU A 1 8.111 22.529 4.848 1.00 19.79 H +ATOM 17 HG3 GLU A 1 7.010 22.151 3.767 1.00 19.79 H +TER +HETATM 18 C1 SIN A 0 11.143 26.020 2.776 1.00 -1.00 C +ANISOU 18 C1 SIN A 0 3119 2972 1277 124 -163 -240 C +HETATM 19 C2 SIN A 0 11.845 26.557 1.542 1.00 -1.00 C +ANISOU 19 C2 SIN A 0 3459 3368 1388 102 -39 -151 C +HETATM 20 C3 SIN A 0 12.465 27.926 1.781 1.00 -1.00 C +ANISOU 20 C3 SIN A 0 3640 3427 1555 45 -9 -143 C +HETATM 21 C4 SIN A 0 11.485 29.081 1.820 1.00 -1.00 C +ANISOU 21 C4 SIN A 0 3756 3638 1693 179 8 -113 C +HETATM 22 O1 SIN A 0 11.536 26.296 3.914 1.00 -1.00 O +ANISOU 22 O1 SIN A 0 3338 3021 1204 43 -125 -241 O +HETATM 23 O3 SIN A 0 11.966 30.230 1.941 1.00 -1.00 O +ANISOU 23 O3 SIN A 0 3949 3621 1603 176 -78 -76 O +HETATM 24 O4 SIN A 0 10.281 28.844 2.062 1.00 -1.00 O +ANISOU 24 O4 SIN A 0 3699 3930 2011 285 2 -324 O +HETATM 25 H21 SIN A 0 11.127 26.627 0.725 1.00 21.62 H +HETATM 26 H22 SIN A 0 12.626 25.858 1.243 1.00 21.62 H +HETATM 27 H31 SIN A 0 13.002 27.899 2.729 1.00 22.69 H +HETATM 28 H32 SIN A 0 13.190 28.117 0.990 1.00 22.69 H +END +""" + + +pdb_str_003 = """ +REMARK scenario for linking, valence and a double conformation +CRYST1 39.670 48.940 71.610 88.74 97.15 108.44 P 1 +SCALE1 0.025208 0.008405 0.003318 0.00000 +SCALE2 0.000000 0.021539 0.000398 0.00000 +SCALE3 0.000000 0.000000 0.014076 0.00000 +ATOM 1 N AASN A 74 12.741 6.714 3.033 0.88 5.87 N +ATOM 2 CA AASN A 74 13.110 7.769 2.091 0.88 6.12 C +ATOM 3 C AASN A 74 11.884 8.130 1.219 0.88 5.86 C +ATOM 4 O AASN A 74 10.858 7.490 1.271 0.88 6.44 O +ATOM 5 CB AASN A 74 14.293 7.285 1.218 0.88 7.27 C +ATOM 6 CG AASN A 74 15.066 8.432 0.603 0.88 8.82 C +ATOM 7 OD1AASN A 74 15.487 9.375 1.229 0.88 11.36 O +ATOM 8 ND2AASN A 74 15.252 8.317 -0.703 0.88 8.84 N +ATOM 9 H AASN A 74 13.382 6.467 3.550 0.88 5.87 H +ATOM 10 HA AASN A 74 13.396 8.571 2.556 0.88 6.12 H +ATOM 11 HB2AASN A 74 14.904 6.771 1.769 0.88 7.27 H +ATOM 12 HB3AASN A 74 13.951 6.732 0.498 0.88 7.27 H +ATOM 13 HD21AASN A 74 14.863 7.686 -1.139 0.88 8.84 H +ATOM 15 N BASN A 74 12.696 6.684 3.030 0.12 5.92 N +ATOM 16 CA BASN A 74 13.040 7.695 2.058 0.12 6.02 C +ATOM 17 C BASN A 74 11.859 8.100 1.181 0.12 5.93 C +ATOM 18 O BASN A 74 10.802 7.435 1.187 0.12 7.07 O +ATOM 19 CB BASN A 74 14.200 7.209 1.214 0.12 5.18 C +ATOM 20 CG BASN A 74 15.493 7.906 1.579 0.12 3.11 C +ATOM 21 OD1BASN A 74 15.680 8.391 2.668 0.12 3.08 O +ATOM 22 ND2BASN A 74 16.411 7.915 0.608 0.12 3.22 N +ATOM 23 H BASN A 74 13.365 6.396 3.487 0.12 5.92 H +ATOM 24 HA BASN A 74 13.309 8.501 2.527 0.12 6.02 H +ATOM 25 HB2BASN A 74 14.012 7.388 0.279 0.12 5.18 H +ATOM 26 HB3BASN A 74 14.319 6.256 1.352 0.12 5.18 H +ATOM 27 HD21BASN A 74 16.242 7.490 -0.121 0.12 3.22 H +TER +HETATM 29 C1 ANAG C 1 16.113 9.249 -1.424 0.74 8.24 C +HETATM 30 C2 ANAG C 1 16.970 8.487 -2.451 0.74 7.99 C +HETATM 31 C3 ANAG C 1 17.836 9.477 -3.177 0.74 8.76 C +HETATM 32 C4 ANAG C 1 17.107 10.640 -3.663 0.74 10.13 C +HETATM 33 C5 ANAG C 1 16.092 11.231 -2.643 0.74 8.62 C +HETATM 34 C6 ANAG C 1 15.151 12.287 -3.168 0.74 9.76 C +HETATM 35 C7 ANAG C 1 17.696 6.180 -1.895 0.74 8.89 C +HETATM 36 C8 ANAG C 1 18.571 5.397 -0.988 0.74 9.89 C +HETATM 37 N2 ANAG C 1 17.767 7.513 -1.768 0.74 8.57 N +HETATM 38 O3 ANAG C 1 18.515 8.763 -4.246 0.74 10.65 O +HETATM 39 O4 ANAG C 1 18.042 11.683 -3.981 0.74 13.35 O +HETATM 40 O5 ANAG C 1 15.310 10.151 -2.140 0.74 7.25 O +HETATM 41 O6 ANAG C 1 14.360 11.822 -4.218 0.74 8.68 O +HETATM 42 O7 ANAG C 1 16.861 5.728 -2.714 0.74 10.29 O +HETATM 43 H1 ANAG C 1 16.684 9.730 -0.805 0.74 8.24 H +HETATM 44 H2 ANAG C 1 16.401 8.030 -3.090 0.74 7.99 H +HETATM 45 H3 ANAG C 1 18.456 9.829 -2.519 0.74 8.76 H +HETATM 46 H4 ANAG C 1 16.631 10.272 -4.424 0.74 10.13 H +HETATM 47 H5 ANAG C 1 16.602 11.677 -1.949 0.74 8.62 H +HETATM 48 H61ANAG C 1 15.688 13.047 -3.442 0.74 9.76 H +HETATM 49 H62ANAG C 1 14.606 12.589 -2.424 0.74 9.76 H +HETATM 50 H81ANAG C 1 19.036 6.002 -0.389 0.74 9.89 H +HETATM 51 H82ANAG C 1 19.216 4.900 -1.515 0.74 9.89 H +HETATM 52 H83ANAG C 1 18.028 4.781 -0.471 0.74 9.89 H +HETATM 53 HN2ANAG C 1 18.352 7.824 -1.219 0.74 8.57 H +HETATM 55 HO3ANAG C 1 18.959 8.129 -3.895 0.74 10.65 H +HETATM 57 HO6ANAG C 1 14.872 11.499 -4.815 0.74 8.68 H +HETATM 58 C1 BNAG C 1 17.701 8.609 0.704 0.26 6.07 C +HETATM 59 C2 BNAG C 1 18.523 8.170 -0.427 0.26 8.31 C +HETATM 60 C3 BNAG C 1 19.761 8.820 -0.183 0.26 6.55 C +HETATM 61 C4 BNAG C 1 19.463 10.425 -0.498 0.26 10.04 C +HETATM 62 C5 BNAG C 1 18.496 10.802 0.555 0.26 8.70 C +HETATM 63 C6 BNAG C 1 17.911 12.176 0.535 0.26 13.23 C +HETATM 64 C7 BNAG C 1 18.720 5.989 -1.367 0.26 10.97 C +HETATM 65 C8 BNAG C 1 19.249 4.641 -1.192 0.26 12.42 C +HETATM 66 N2 BNAG C 1 18.962 6.846 -0.336 0.26 9.44 N +HETATM 67 O3 BNAG C 1 20.699 8.721 -1.435 0.26 14.71 O +HETATM 68 O4 BNAG C 1 20.552 11.276 -0.389 0.26 12.04 O +HETATM 69 O5 BNAG C 1 17.320 9.980 0.458 0.26 7.16 O +HETATM 70 O6 BNAG C 1 17.693 12.418 -0.804 0.26 19.92 O +HETATM 71 O7 BNAG C 1 18.181 6.220 -2.430 0.26 11.69 O +HETATM 72 H1 BNAG C 1 18.211 8.549 1.527 0.26 6.07 H +HETATM 73 H2 BNAG C 1 18.012 8.327 -1.237 0.26 8.31 H +HETATM 74 H3 BNAG C 1 20.062 8.479 0.674 0.26 6.55 H +HETATM 75 H4 BNAG C 1 19.176 10.456 -1.424 0.26 10.04 H +HETATM 76 H5 BNAG C 1 19.021 10.704 1.364 0.26 8.70 H +HETATM 77 H61BNAG C 1 18.525 12.807 0.942 0.26 13.23 H +HETATM 78 H62BNAG C 1 17.099 12.201 1.065 0.26 13.23 H +HETATM 79 H81BNAG C 1 19.656 4.567 -0.315 0.26 12.42 H +HETATM 80 H82BNAG C 1 19.915 4.466 -1.875 0.26 12.42 H +HETATM 81 H83BNAG C 1 18.526 4.000 -1.271 0.26 12.42 H +HETATM 82 HN2BNAG C 1 19.380 6.582 0.368 0.26 9.44 H +HETATM 84 HO3BNAG C 1 20.316 9.121 -2.080 0.26 14.71 H +HETATM 86 HO6BNAG C 1 18.423 12.288 -1.220 0.26 19.92 H +HETATM 87 C1 ANAG C 2 17.995 12.199 -5.260 0.74 19.86 C +HETATM 88 C2 ANAG C 2 18.677 13.574 -5.253 0.74 23.29 C +HETATM 89 C3 ANAG C 2 18.830 14.151 -6.591 0.74 29.68 C +HETATM 90 C4 ANAG C 2 19.318 13.037 -7.482 0.74 30.27 C +HETATM 91 C5 ANAG C 2 18.591 11.736 -7.460 0.74 29.19 C +HETATM 92 C6 ANAG C 2 19.149 10.584 -8.227 0.74 33.79 C +HETATM 93 C7 ANAG C 2 18.471 14.805 -3.050 0.74 27.91 C +HETATM 94 C8 ANAG C 2 17.772 15.886 -2.243 0.74 37.24 C +HETATM 95 N2 ANAG C 2 18.165 14.566 -4.332 0.74 22.31 N +HETATM 96 O3 ANAG C 2 19.864 15.164 -6.531 0.74 40.55 O +HETATM 97 O4 ANAG C 2 19.327 13.494 -8.818 0.74 46.76 O +HETATM 98 O5 ANAG C 2 18.644 11.227 -6.086 0.74 21.90 O +HETATM 99 O6 ANAG C 2 20.567 10.602 -8.018 0.74 41.31 O +HETATM 100 O7 ANAG C 2 19.396 14.260 -2.622 0.74 24.10 O +HETATM 101 H1 ANAG C 2 18.016 11.864 -4.350 0.74 19.86 H +HETATM 102 H2 ANAG C 2 19.547 13.331 -4.899 0.74 23.29 H +HETATM 103 H3 ANAG C 2 17.981 14.517 -6.883 0.74 29.68 H +HETATM 104 H4 ANAG C 2 20.179 12.882 -7.064 0.74 30.27 H +HETATM 105 H5 ANAG C 2 17.721 11.946 -7.834 0.74 29.19 H +HETATM 106 H61ANAG C 2 18.738 9.762 -7.916 0.74 33.79 H +HETATM 107 H62ANAG C 2 18.910 10.675 -9.163 0.74 33.79 H +HETATM 108 H81ANAG C 2 17.079 16.294 -2.785 0.74 37.24 H +HETATM 109 H82ANAG C 2 18.419 16.560 -1.981 0.74 37.24 H +HETATM 110 H83ANAG C 2 17.375 15.490 -1.451 0.74 37.24 H +HETATM 111 HN2ANAG C 2 17.567 15.083 -4.671 0.74 22.31 H +HETATM 113 HO3ANAG C 2 20.590 14.783 -6.307 0.74 40.55 H +HETATM 114 HO4ANAG C 2 19.521 14.322 -8.826 0.74 46.76 H +HETATM 115 HO6ANAG C 2 20.857 11.373 -8.226 0.74 41.31 H +HETATM 116 C1 BNAG C 2 20.710 12.370 -1.239 0.26 14.76 C +HETATM 117 C2 BNAG C 2 21.943 13.194 -0.806 0.26 19.56 C +HETATM 118 C3 BNAG C 2 22.215 14.268 -1.785 0.26 24.38 C +HETATM 119 C4 BNAG C 2 22.458 13.627 -3.140 0.26 21.94 C +HETATM 120 C5 BNAG C 2 21.254 12.760 -3.461 0.26 20.16 C +HETATM 121 C6 BNAG C 2 21.355 12.027 -4.829 0.26 23.66 C +HETATM 122 C7 BNAG C 2 22.490 13.708 1.511 0.26 32.27 C +HETATM 123 C8 BNAG C 2 21.906 14.269 2.792 0.26 36.29 C +HETATM 124 N2 BNAG C 2 21.644 13.753 0.496 0.26 26.94 N +HETATM 125 O3 BNAG C 2 23.271 15.027 -1.295 0.26 27.97 O +HETATM 126 O4 BNAG C 2 22.468 14.619 -4.109 0.26 26.97 O +HETATM 127 O5 BNAG C 2 20.976 11.868 -2.415 0.26 11.40 O +HETATM 128 O6 BNAG C 2 22.466 11.207 -5.128 0.26 29.08 O +HETATM 129 O7 BNAG C 2 23.600 13.383 1.407 0.26 21.94 O +HETATM 130 H1 BNAG C 2 19.928 12.942 -1.289 0.26 14.76 H +HETATM 131 H2 BNAG C 2 22.730 12.628 -0.768 0.26 19.56 H +HETATM 132 H3 BNAG C 2 21.443 14.847 -1.886 0.26 24.38 H +HETATM 133 H4 BNAG C 2 23.296 13.144 -3.071 0.26 21.94 H +HETATM 134 H5 BNAG C 2 20.480 13.340 -3.539 0.26 20.16 H +HETATM 135 H61BNAG C 2 21.284 12.729 -5.495 0.26 23.66 H +HETATM 136 H62BNAG C 2 20.541 11.503 -4.893 0.26 23.66 H +HETATM 137 H81BNAG C 2 20.980 14.517 2.641 0.26 36.29 H +HETATM 138 H82BNAG C 2 22.413 15.051 3.060 0.26 36.29 H +HETATM 139 H83BNAG C 2 21.953 13.595 3.488 0.26 36.29 H +HETATM 140 HN2BNAG C 2 20.879 14.130 0.606 0.26 26.94 H +HETATM 142 HO3BNAG C 2 23.951 14.520 -1.236 0.26 27.97 H +HETATM 143 HO4BNAG C 2 22.798 15.328 -3.776 0.26 26.97 H +HETATM 144 HO6BNAG C 2 23.173 11.663 -5.010 0.26 29.08 H +END +""" + +pdb_str_004 = """ +REMARK Linking + valence scenario for a carbohydrate +CRYST1 39.670 48.940 71.610 88.74 97.15 108.44 P 1 +SCALE1 0.025208 0.008405 0.003318 0.00000 +SCALE2 0.000000 0.021539 0.000398 0.00000 +SCALE3 0.000000 0.000000 0.014076 0.00000 +ATOM 1 N ASN B 74 -3.026 34.995 30.688 1.00 9.05 N +ATOM 2 CA ASN B 74 -2.493 35.978 31.595 1.00 9.88 C +ATOM 3 C ASN B 74 -1.547 35.327 32.616 1.00 9.26 C +ATOM 4 O ASN B 74 -1.420 34.120 32.689 1.00 9.22 O +ATOM 5 CB ASN B 74 -3.624 36.727 32.324 1.00 12.24 C +ATOM 6 CG ASN B 74 -3.216 38.094 32.845 1.00 14.21 C +ATOM 7 OD1 ASN B 74 -2.472 38.834 32.203 1.00 18.21 O +ATOM 8 ND2 ASN B 74 -3.692 38.409 34.028 1.00 16.96 N +ATOM 9 H ASN B 74 -2.549 34.876 29.982 1.00 9.05 H +ATOM 10 HA ASN B 74 -1.988 36.631 31.085 1.00 9.88 H +ATOM 11 HB2 ASN B 74 -3.912 36.195 33.082 1.00 12.24 H +ATOM 12 HB3 ASN B 74 -4.362 36.854 31.708 1.00 12.24 H +ATOM 13 HD21 ASN B 74 -4.198 37.847 34.438 1.00 16.96 H +TER +HETATM 15 C1 NAG D 1 -3.389 39.731 34.716 1.00 15.06 C +HETATM 16 C2 NAG D 1 -4.468 40.105 35.528 1.00 16.43 C +HETATM 17 C3 NAG D 1 -4.201 41.525 36.083 1.00 15.29 C +HETATM 18 C4 NAG D 1 -2.754 41.564 36.747 1.00 15.66 C +HETATM 19 C5 NAG D 1 -1.708 40.987 35.892 1.00 17.17 C +HETATM 20 C6 NAG D 1 -0.490 40.596 36.940 1.00 25.12 C +HETATM 21 C7 NAG D 1 -6.706 39.271 34.932 1.00 17.46 C +HETATM 22 C8 NAG D 1 -7.943 39.400 34.022 1.00 20.06 C +HETATM 23 N2 NAG D 1 -5.748 40.154 34.750 1.00 16.04 N +HETATM 24 O3 NAG D 1 -5.243 41.846 36.992 1.00 17.10 O +HETATM 25 O4 NAG D 1 -2.597 43.022 36.916 1.00 18.40 O +HETATM 26 O5 NAG D 1 -2.177 39.700 35.427 1.00 15.81 O +HETATM 27 O6 NAG D 1 0.621 40.445 35.919 1.00 26.15 O +HETATM 28 O7 NAG D 1 -6.670 38.382 35.716 1.00 17.36 O +HETATM 29 H1 NAG D 1 -3.305 40.387 34.006 1.00 15.06 H +HETATM 30 H2 NAG D 1 -4.545 39.445 36.235 1.00 16.43 H +HETATM 31 H3 NAG D 1 -4.201 42.160 35.350 1.00 15.29 H +HETATM 32 H4 NAG D 1 -2.726 41.025 37.553 1.00 15.66 H +HETATM 33 H5 NAG D 1 -1.456 41.561 35.151 1.00 17.17 H +HETATM 34 H61 NAG D 1 -0.689 39.788 37.439 1.00 25.12 H +HETATM 35 H62 NAG D 1 -0.340 41.295 37.596 1.00 25.12 H +HETATM 36 H81 NAG D 1 -7.800 40.119 33.386 1.00 20.06 H +HETATM 37 H82 NAG D 1 -8.722 39.596 34.566 1.00 20.06 H +HETATM 38 H83 NAG D 1 -8.079 38.566 33.546 1.00 20.06 H +HETATM 39 HN2 NAG D 1 -5.852 40.780 34.170 1.00 16.04 H +HETATM 41 HO3 NAG D 1 -5.213 41.286 37.631 1.00 17.10 H +HETATM 43 HO6 NAG D 1 0.364 39.894 35.325 1.00 26.15 H +HETATM 44 C1 NAG D 2 -2.391 43.486 38.203 1.00 21.11 C +HETATM 45 C2 NAG D 2 -1.775 44.823 37.997 1.00 26.59 C +HETATM 46 C3 NAG D 2 -1.585 45.513 39.294 1.00 26.26 C +HETATM 47 C4 NAG D 2 -2.959 45.457 39.969 1.00 29.92 C +HETATM 48 C5 NAG D 2 -3.462 44.035 40.104 1.00 30.15 C +HETATM 49 C6 NAG D 2 -4.756 43.848 40.745 1.00 35.86 C +HETATM 50 C7 NAG D 2 -0.234 44.953 35.978 1.00 30.77 C +HETATM 51 C8 NAG D 2 1.206 44.728 35.397 1.00 33.11 C +HETATM 52 N2 NAG D 2 -0.459 44.736 37.311 1.00 26.48 N +HETATM 53 O3 NAG D 2 -1.072 46.826 39.192 1.00 28.25 O +HETATM 54 O4 NAG D 2 -2.849 45.859 41.286 1.00 32.37 O +HETATM 55 O5 NAG D 2 -3.648 43.578 38.774 1.00 23.11 O +HETATM 56 O6 NAG D 2 -5.481 44.858 40.253 1.00 30.27 O +HETATM 57 O7 NAG D 2 -1.176 45.443 35.293 1.00 29.59 O +HETATM 58 H1 NAG D 2 -1.822 42.981 38.805 1.00 21.11 H +HETATM 59 H2 NAG D 2 -2.392 45.317 37.434 1.00 26.59 H +HETATM 60 H3 NAG D 2 -0.902 45.033 39.787 1.00 26.26 H +HETATM 61 H4 NAG D 2 -3.496 46.020 39.389 1.00 29.92 H +HETATM 62 H5 NAG D 2 -2.821 43.547 40.644 1.00 30.15 H +HETATM 63 H61 NAG D 2 -4.662 43.876 41.710 1.00 35.86 H +HETATM 64 H62 NAG D 2 -5.117 42.974 40.529 1.00 35.86 H +HETATM 65 H81 NAG D 2 1.786 44.392 36.098 1.00 33.11 H +HETATM 66 H82 NAG D 2 1.552 45.570 35.063 1.00 33.11 H +HETATM 67 H83 NAG D 2 1.163 44.083 34.673 1.00 33.11 H +HETATM 68 HN2 NAG D 2 0.216 44.531 37.802 1.00 26.48 H +HETATM 70 HO3 NAG D 2 -1.634 47.292 38.756 1.00 28.25 H +HETATM 71 HO4 NAG D 2 -2.248 46.457 41.343 1.00 32.37 H +HETATM 72 HO6 NAG D 2 -5.060 45.582 40.396 1.00 30.27 H +END +""" + # ------------------------------------------------------------------------------ if (__name__ == "__main__"): From 21d45d3d3052e51dcb5d2a3f43e6fd85063b0423 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 14 Mar 2024 15:27:05 -0700 Subject: [PATCH 215/748] Avoid code duplication --- mmtbx/hydrogens/tst_add_hydrogen.py | 7 +++ mmtbx/hydrogens/tst_add_hydrogen_2.py | 80 +-------------------------- 2 files changed, 9 insertions(+), 78 deletions(-) diff --git a/mmtbx/hydrogens/tst_add_hydrogen.py b/mmtbx/hydrogens/tst_add_hydrogen.py index b5fc9c143b..97cbf0c7f2 100644 --- a/mmtbx/hydrogens/tst_add_hydrogen.py +++ b/mmtbx/hydrogens/tst_add_hydrogen.py @@ -55,11 +55,18 @@ def compare_models(pdb_str, model_h_added = reduce_add_h_obj.get_model() hd_sel_h_added = model_h_added.get_hd_selection() + # For debugging # f = open("m_initial.pdb","w") # f.write(model_initial.model_as_pdb()) # f.close() +# f = open("m_initial.cif","w") +# f.write(model_initial.model_as_mmcif()) +# f.close() # f = open("m_added.pdb","w") # f.write(model_h_added.model_as_pdb()) +# f.close() +# f = open("m_added.cif","w") +# f.write(model_h_added.model_as_mmcif()) # f.close() ph_h_added = model_h_added.get_hierarchy() diff --git a/mmtbx/hydrogens/tst_add_hydrogen_2.py b/mmtbx/hydrogens/tst_add_hydrogen_2.py index 77fb55f3c2..31fe30f630 100644 --- a/mmtbx/hydrogens/tst_add_hydrogen_2.py +++ b/mmtbx/hydrogens/tst_add_hydrogen_2.py @@ -1,16 +1,12 @@ from __future__ import absolute_import, division, print_function import time import mmtbx.model -import iotbx.pdb -from mmtbx.hydrogens import reduce_hydrogen -from libtbx.utils import null_out -from libtbx.test_utils import approx_equal +from mmtbx.hydrogens.tst_add_hydrogen import compare_models -# ------------------------------------------------------------------------------ def run(): test_000() - test_001() + #test_001() test_002() test_003() test_004() @@ -22,78 +18,6 @@ def run(): # ------------------------------------------------------------------------------ -def compare_models(pdb_str, - contains = None, - not_contains = None): - ''' - Function to compare model with new H to the known answer (pdb_str) - ''' - # - pdb_inp = iotbx.pdb.input(lines=pdb_str.split("\n"), source_info=None) - # initial model - model_initial = mmtbx.model.manager(model_input = pdb_inp, - log = null_out()) - ph_initial = model_initial.get_hierarchy() - hd_sel_initial = model_initial.get_hd_selection() - h_atoms_initial = ph_initial.select(hd_sel_initial).atoms() - h_names_initial = list(h_atoms_initial.extract_name()) - # number of H in pdb string (right answer) - number_h_expected = hd_sel_initial.count(True) - - # get model obj without H atoms - model_without_h = model_initial.select(~hd_sel_initial) - # make sure model without H indeed has no H atoms - hd_sel_without_h = model_without_h.get_hd_selection() - assert (hd_sel_without_h is not None) - assert (hd_sel_without_h.count(True) == 0) - - # place H atoms again - reduce_add_h_obj = reduce_hydrogen.place_hydrogens(model = model_without_h) - reduce_add_h_obj.run() - # - model_h_added = reduce_add_h_obj.get_model() - hd_sel_h_added = model_h_added.get_hd_selection() - - #f = open("m_initial.pdb","w") - #f.write(model_initial.model_as_pdb()) - #f.close() - #f = open("m_initial.cif","w") - #f.write(model_initial.model_as_mmcif()) - #f.close() - #f = open("m_added.pdb","w") - #f.write(model_h_added.model_as_pdb()) - #f.close() - #f = open("m_added.cif","w") - #f.write(model_h_added.model_as_mmcif()) - #f.close() - - ph_h_added = model_h_added.get_hierarchy() - assert ph_initial.is_similar_hierarchy(other=ph_h_added) - - number_h_added = hd_sel_h_added.count(True) - assert(number_h_expected == number_h_added) - - h_atoms_added = ph_h_added.select(hd_sel_h_added).atoms() - h_names_added = list(h_atoms_added.extract_name()) - - if not_contains: - assert (not_contains not in h_names_added) - if contains: - assert (contains in h_names_added) - - sc_h_initial = model_initial.select(hd_sel_initial).get_sites_cart() - sc_h_added = model_h_added.select(hd_sel_h_added).get_sites_cart() - - d1 = {h_names_initial[i]: sc_h_initial[i] for i in range(len(h_names_initial))} - d2 = {h_names_added[i]: sc_h_added[i] for i in range(len(h_names_added))} - - # check if coordinates are correct - for name, sc in d2.items(): - assert(name in d1) - assert approx_equal(sc, d1[name], 0.01), name - -# ------------------------------------------------------------------------------ - def test_000(): ''' CDL is true by default. Will crash for this example if is False. From 313ac6e5c8f9a1a1c1b91298ee5f0d0e607f1814 Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 14 Mar 2024 16:51:47 -0600 Subject: [PATCH 216/748] Move chain_comparison to program_template --- mmtbx/regression/tst_chain_comparison.py | 18 ++++++++++++++---- mmtbx/validation/chain_comparison.py | 7 ++++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/mmtbx/regression/tst_chain_comparison.py b/mmtbx/regression/tst_chain_comparison.py index 1effe860b6..aedda48958 100644 --- a/mmtbx/regression/tst_chain_comparison.py +++ b/mmtbx/regression/tst_chain_comparison.py @@ -3,6 +3,10 @@ from six.moves import cStringIO as StringIO from mmtbx.validation.chain_comparison import run +from iotbx.cli_parser import run_program + + + def remove_blank(text): return text.replace(" ","").replace("\n","") @@ -604,7 +608,7 @@ def tst_03(): query.pdb 1.55 54 7 14 29 11 39.7 0.26 9.3 0.04 6.0 7 6""" found_text="\n".join(f.getvalue().splitlines()[-10:]) if remove_blank(found_text)!=remove_blank(expected_text): - print("Expected: \n%s \nFound: \n%s" %(expected_text,found_text)) + print("Expected at tst_03: \n%s \nFound: \n%s" %(expected_text,found_text)) raise AssertionError("FAILED") print("OK") @@ -802,6 +806,11 @@ def tst_05(): print("OK") def tst_06(): + try: + from phenix.programs import chain_comparison + except Exception as e: + return # no phenix + print("Comparing mixed model with target with 2 chains...using ncs") import iotbx.pdb from cctbx.array_family import flex @@ -820,7 +829,8 @@ def tst_06(): f=StringIO() args=['model.pdb','query.pdb','ncs_file=ncs.ncs_spec'] - r=run(args,out=f) + run_program(program_class=chain_comparison.Program, args = args, logger = f) + f.flush() expected_text=""" SEQ SCORE is fraction (close and matching target sequence). MEAN LENGTH is the mean length of contiguous segments in the match with target sequence. (Each gap/reverse of direction starts new segment). @@ -832,9 +842,9 @@ def tst_06(): RMSD N N N N N SCORE SEQ MATCH(%) SCORE MEAN LENGTH FRAGMENTS BAD CONNECTIONS Unique_target 1.67 58 64 15 29 14 42.6 0.25 8.6 0.04 4.5 16 8""" - found_text="\n".join(f.getvalue().splitlines()[-10:]) + found_text="\n".join(f.getvalue().strip().splitlines()[-17:-6]) if remove_blank(found_text)!=remove_blank(expected_text): - print("\n\nExpected: \n%s \n\nFound: \n%s" %(expected_text,found_text)) + print("\n\nExpected tst_06: \n%s \n\nFound: \n%s" %(expected_text,found_text)) raise AssertionError("FAILED") print("OK") diff --git a/mmtbx/validation/chain_comparison.py b/mmtbx/validation/chain_comparison.py index 2fa34dd5c1..00b7ba28fa 100644 --- a/mmtbx/validation/chain_comparison.py +++ b/mmtbx/validation/chain_comparison.py @@ -16,7 +16,8 @@ from six.moves import zip from six.moves import range -master_phil = iotbx.phil.parse(""" + +master_params = """ input_files { pdb_in = None @@ -179,8 +180,8 @@ .type = path .style = output_dir } -""", process_includes=True) -master_params = master_phil +""" +master_phil = iotbx.phil.parse(master_params, process_includes=True) class rmsd_values: def __init__(self,params=None): From 773e9a2a56dfc305b75af8d73068f2d8fa59816a Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 15 Mar 2024 10:10:54 -0700 Subject: [PATCH 217/748] Add test --- mmtbx/hydrogens/tst_add_hydrogen_3.py | 117 +++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 1 deletion(-) diff --git a/mmtbx/hydrogens/tst_add_hydrogen_3.py b/mmtbx/hydrogens/tst_add_hydrogen_3.py index 0d9f3b75be..143fcf64a0 100644 --- a/mmtbx/hydrogens/tst_add_hydrogen_3.py +++ b/mmtbx/hydrogens/tst_add_hydrogen_3.py @@ -5,7 +5,6 @@ from mmtbx.hydrogens import reduce_hydrogen from mmtbx.hydrogens.tst_add_hydrogen import compare_models from libtbx.utils import null_out -#from libtbx.test_utils import approx_equal # ------------------------------------------------------------------------------ @@ -15,6 +14,7 @@ def run(): test_002() test_003() test_004() + test_005() # ------------------------------------------------------------------------------ @@ -119,6 +119,15 @@ def test_004(): # ------------------------------------------------------------------------------ +def test_005(): + ''' + Carbohydrate (BMA) forms covlalent link to ASN. Make sure valence is correct for + the NAG and protein links. This example is from Russel (6vw1). + ''' + compare_models(pdb_str = pdb_str_005) + +# ------------------------------------------------------------------------------ + pdb_str_000 = """ REMARK Make sure reduce does not crash for single_atom_residue models CRYST1 22.029 33.502 24.035 90.00 90.00 90.00 P 1 @@ -483,6 +492,112 @@ def test_004(): END """ +pdb_str_005 = """ +CRYST1 80.435 118.034 112.075 90.00 93.12 90.00 P 1 21 1 +SCALE1 0.012432 0.000000 0.000678 0.00000 +SCALE2 0.000000 0.008472 0.000000 0.00000 +SCALE3 0.000000 0.000000 0.008936 0.00000 +ATOM 1 N ASN A 90 76.017 -20.785 155.731 1.00 -1.00 N +ANISOU 1 N ASN A 90 17156 21970 15197 -6703 124 870 N +ATOM 2 CA ASN A 90 75.942 -19.415 156.227 1.00 -1.00 C +ANISOU 2 CA ASN A 90 17577 22797 16129 -6189 29 1252 C +ATOM 3 C ASN A 90 77.350 -18.831 156.235 1.00 -1.00 C +ANISOU 3 C ASN A 90 17170 21823 15645 -5768 103 1134 C +ATOM 4 O ASN A 90 78.239 -19.359 156.912 1.00 -1.00 O +ANISOU 4 O ASN A 90 17802 21588 16095 -5569 283 881 O +ATOM 5 CB ASN A 90 75.320 -19.390 157.626 1.00 -1.00 C +ANISOU 5 CB ASN A 90 18758 23893 17672 -5918 105 1419 C +ATOM 6 CG ASN A 90 75.068 -17.982 158.153 1.00 -1.00 C +ANISOU 6 CG ASN A 90 19640 25239 19120 -5436 46 1805 C +ATOM 7 OD1 ASN A 90 75.922 -17.100 158.061 1.00 -1.00 O +ANISOU 7 OD1 ASN A 90 18832 24282 18399 -5077 50 1839 O +ATOM 8 ND2 ASN A 90 73.886 -17.776 158.730 1.00 -1.00 N +ANISOU 8 ND2 ASN A 90 21686 27829 21572 -5430 16 2088 N +ATOM 9 H ASN A 90 76.270 -20.847 154.911 1.00142.97 H +ATOM 10 HA ASN A 90 75.375 -18.865 155.664 1.00148.71 H +ATOM 11 HB2 ASN A 90 75.921 -19.835 158.244 1.00158.76 H +ATOM 12 HB3 ASN A 90 74.468 -19.854 157.599 1.00158.76 H +ATOM 13 HD21 ASN A 90 73.315 -18.418 158.763 1.00187.09 H +TER +HETATM 15 C1 NAG C 1 73.523 -16.504 159.309 1.00103.52 C +HETATM 16 C2 NAG C 1 72.427 -15.749 158.564 1.00114.27 C +HETATM 17 C3 NAG C 1 72.112 -14.434 159.280 1.00117.99 C +HETATM 18 C4 NAG C 1 71.829 -14.658 160.763 1.00124.42 C +HETATM 19 C5 NAG C 1 72.930 -15.509 161.403 1.00121.57 C +HETATM 20 C6 NAG C 1 72.619 -15.937 162.820 1.00122.81 C +HETATM 21 C7 NAG C 1 71.992 -15.651 156.147 1.00125.03 C +HETATM 22 C8 NAG C 1 72.570 -15.344 154.798 1.00127.15 C +HETATM 23 N2 NAG C 1 72.819 -15.497 157.186 1.00121.51 N +HETATM 24 O3 NAG C 1 70.990 -13.814 158.662 1.00116.89 O +HETATM 25 O4 NAG C 1 71.791 -13.386 161.404 1.00133.35 O +HETATM 26 O5 NAG C 1 73.123 -16.717 160.654 1.00114.93 O +HETATM 27 O6 NAG C 1 73.745 -15.787 163.673 1.00121.65 O +HETATM 28 O7 NAG C 1 70.831 -16.020 156.289 1.00125.47 O +HETATM 29 H1 NAG C 1 74.336 -15.975 159.299 1.00103.52 H +HETATM 30 H2 NAG C 1 71.632 -16.305 158.561 1.00114.27 H +HETATM 31 H3 NAG C 1 72.914 -13.895 159.195 1.00117.99 H +HETATM 32 H4 NAG C 1 70.979 -15.124 160.802 1.00124.42 H +HETATM 33 H5 NAG C 1 73.736 -14.970 161.406 1.00121.57 H +HETATM 34 H61 NAG C 1 71.867 -15.409 163.130 1.00122.81 H +HETATM 35 H62 NAG C 1 72.316 -16.858 162.792 1.00122.81 H +HETATM 36 H81 NAG C 1 73.509 -15.120 154.894 1.00127.15 H +HETATM 37 H82 NAG C 1 72.095 -14.593 154.409 1.00127.15 H +HETATM 38 H83 NAG C 1 72.477 -16.121 154.225 1.00127.15 H +HETATM 39 HN2 NAG C 1 73.625 -15.236 157.040 1.00121.51 H +HETATM 41 HO3 NAG C 1 70.851 -13.074 159.056 1.00116.89 H +HETATM 43 HO6 NAG C 1 74.400 -16.202 163.325 1.00121.65 H +HETATM 44 C1 NAG C 2 70.691 -13.209 162.330 1.00143.22 C +HETATM 45 C2 NAG C 2 71.046 -12.013 163.217 1.00149.90 C +HETATM 46 C3 NAG C 2 69.929 -11.751 164.223 1.00153.90 C +HETATM 47 C4 NAG C 2 68.594 -11.600 163.506 1.00157.09 C +HETATM 48 C5 NAG C 2 68.339 -12.806 162.605 1.00152.27 C +HETATM 49 C6 NAG C 2 67.082 -12.672 161.777 1.00151.75 C +HETATM 50 C7 NAG C 2 73.401 -11.485 163.670 1.00150.52 C +HETATM 51 C8 NAG C 2 74.621 -11.843 164.465 1.00149.56 C +HETATM 52 N2 NAG C 2 72.312 -12.226 163.901 1.00151.39 N +HETATM 53 O3 NAG C 2 70.226 -10.571 164.961 1.00153.21 O +HETATM 54 O4 NAG C 2 67.540 -11.490 164.456 1.00163.16 O +HETATM 55 O5 NAG C 2 69.429 -12.972 161.684 1.00147.83 O +HETATM 56 O6 NAG C 2 67.313 -11.906 160.602 1.00151.36 O +HETATM 57 O7 NAG C 2 73.402 -10.566 162.856 1.00149.17 O +HETATM 58 H1 NAG C 2 70.621 -14.004 162.882 1.00143.22 H +HETATM 59 H2 NAG C 2 71.140 -11.238 162.641 1.00149.90 H +HETATM 60 H3 NAG C 2 69.893 -12.528 164.802 1.00153.90 H +HETATM 61 H4 NAG C 2 68.684 -10.788 162.984 1.00157.09 H +HETATM 62 H5 NAG C 2 68.256 -13.586 163.175 1.00152.27 H +HETATM 63 H61 NAG C 2 66.399 -12.268 162.336 1.00151.75 H +HETATM 64 H62 NAG C 2 66.770 -13.565 161.563 1.00151.75 H +HETATM 65 H81 NAG C 2 74.432 -12.623 165.009 1.00149.56 H +HETATM 66 H82 NAG C 2 74.862 -11.097 165.037 1.00149.56 H +HETATM 67 H83 NAG C 2 75.353 -12.038 163.859 1.00149.56 H +HETATM 68 HN2 NAG C 2 72.354 -12.860 164.480 1.00151.39 H +HETATM 70 HO3 NAG C 2 70.256 -9.922 164.413 1.00153.21 H +HETATM 72 HO6 NAG C 2 67.657 -11.163 160.832 1.00151.36 H +HETATM 73 C1 BMA C 3 67.036 -10.135 164.465 1.00164.84 C +HETATM 74 C2 BMA C 3 65.513 -10.187 164.205 1.00164.51 C +HETATM 75 C3 BMA C 3 64.912 -8.784 164.326 1.00164.84 C +HETATM 76 C4 BMA C 3 65.353 -8.085 165.626 1.00165.75 C +HETATM 77 C5 BMA C 3 66.886 -8.117 165.760 1.00164.34 C +HETATM 78 C6 BMA C 3 67.377 -7.517 167.067 1.00159.95 C +HETATM 79 O2 BMA C 3 64.864 -10.998 165.174 1.00162.15 O +HETATM 80 O3 BMA C 3 63.491 -8.819 164.251 1.00162.71 O +HETATM 81 O4 BMA C 3 64.902 -6.737 165.632 1.00164.98 O +HETATM 82 O5 BMA C 3 67.321 -9.489 165.704 1.00164.62 O +HETATM 83 O6 BMA C 3 66.718 -6.271 167.265 1.00154.88 O +HETATM 84 H1 BMA C 3 67.454 -9.653 163.734 1.00164.84 H +HETATM 85 H2 BMA C 3 65.448 -10.536 163.302 1.00164.51 H +HETATM 86 H3 BMA C 3 65.260 -8.317 163.550 1.00164.84 H +HETATM 87 H4 BMA C 3 64.914 -8.536 166.365 1.00165.75 H +HETATM 88 H5 BMA C 3 67.297 -7.591 165.056 1.00164.34 H +HETATM 89 H61 BMA C 3 67.191 -8.125 167.800 1.00159.95 H +HETATM 90 H62 BMA C 3 68.339 -7.396 167.035 1.00159.95 H +HETATM 92 HO2 BMA C 3 65.200 -10.810 165.932 1.00162.15 H +HETATM 93 HO3 BMA C 3 63.182 -9.145 164.973 1.00162.71 H +HETATM 94 HO4 BMA C 3 65.175 -6.362 166.344 1.00164.98 H +HETATM 95 HO6 BMA C 3 65.881 -6.399 167.190 1.00154.88 H +END +""" + # ------------------------------------------------------------------------------ if (__name__ == "__main__"): From 3416a26f530585e358ff6d19287962e910aece34 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Mon, 18 Mar 2024 11:51:40 -0700 Subject: [PATCH 218/748] Clean clutter [skip ci] --- cctbx_website/html_files/doc_models_hierarchy.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cctbx_website/html_files/doc_models_hierarchy.html b/cctbx_website/html_files/doc_models_hierarchy.html index 8f5289406a..0da45727a1 100644 --- a/cctbx_website/html_files/doc_models_hierarchy.html +++ b/cctbx_website/html_files/doc_models_hierarchy.html @@ -88,7 +88,7 @@

Quick overview

We also wrote the model out using the data manager and obtained the actual file name written. This last step is necessary because a model that -does not fit in PDB format will be written out as mmCIF with the suffix .cif. +does not fit in PDB format will be written out as mmCIF with the suffix .cif.

It is possible to get a pdb_hierarchy() object directly:

From b6f016eb849455313ec7e352368b074b8edabbd7 Mon Sep 17 00:00:00 2001 From: cschlick Date: Mon, 18 Mar 2024 17:11:30 -0700 Subject: [PATCH 219/748] Add support for planes when parsing .geo files. Add support for id_str labels. Add test --- mmtbx/geometry_restraints/geo_file_parsing.py | 205 ++++++- .../tst_geo_file_parsing.py | 535 ++++++++++++++++-- 2 files changed, 678 insertions(+), 62 deletions(-) diff --git a/mmtbx/geometry_restraints/geo_file_parsing.py b/mmtbx/geometry_restraints/geo_file_parsing.py index 83d4acdbdb..25dfd2a9ed 100644 --- a/mmtbx/geometry_restraints/geo_file_parsing.py +++ b/mmtbx/geometry_restraints/geo_file_parsing.py @@ -1,32 +1,56 @@ from __future__ import division, print_function import re +import json +from collections import defaultdict import pandas as pd import numpy as np + def tryfloat(value): + # Try to make float try: return float(value) except Exception: return value + +# Pattern to plit on either space or id_str +pattern = re.compile(r'pdb="[^"]*"|\S+') + + +# Define classes for restraints with fixed number of atoms class BondRestraint: restraint_label = 'bond' @classmethod - def from_geo_lines(cls,lines,settings): + def from_geo_lines(cls, lines, settings): # start make restraint n_atoms = settings["n_atoms"] restraint_key = cls.restraint_label key_index = n_atoms - value_index = n_atoms+1 - atom_indices = ["i","j","k","l","m","n"] - atoms_i_seqs = [int(re.search(r'\d+', lines[i]).group()) for i in range(0,n_atoms)] - keys = [e for e in lines[key_index].split()] - values = [tryfloat(e) for e in lines[value_index].split()] - d = {"restraint_type":restraint_key} + value_index = n_atoms + 1 + + # Extract atom sequences or pdb strings + atoms_i_seqs = [] + for i in range(n_atoms): + match = pattern.findall(lines[i].replace(cls.restraint_label,"")) + parts = [part.strip() for part in match if part.strip() != ""] + if len(parts)>0: + # Assuming the first match is the desired one; adjust as necessary + atoms_i_seqs.append(parts[0]) + else: + atoms_i_seqs.append(lines[i].replace(cls.restraint_label,"").strip()) + + keys = pattern.findall(lines[key_index]) + values = [tryfloat(value) for value in pattern.findall(lines[value_index])] + d = {"restraint_type": restraint_key} for i, i_seq in enumerate(atoms_i_seqs): - k = "{}_seq".format(atom_indices[i]) - v = i_seq - d[k] = v - d.update({key:value for key,value in zip(keys,values)}) + if "pdb" in i_seq: + k = f"id_str_{i}" + else: + k = f"i_seq_{i}" + d[k] = i_seq + + d.update({key: value for key, value in zip(keys, values)}) return cls(d) + def __init__(self, data_dict): self.data_dict = data_dict class AngleRestraint(BondRestraint): @@ -39,6 +63,115 @@ class ChiralityRestraint(BondRestraint): restraint_label = 'chirality' class CBetaRestraint(BondRestraint): restraint_label = 'c-beta' + +# Planes have variable n_atoms +class PlanarityRestraint: + restraint_label = 'plane' + + @classmethod + def from_geo_lines(cls, lines, settings): + planes_data = [] + headers = None + current_plane_data = {} + + for i,line in enumerate(lines): + if 'delta' in line: # Header line detected + headers = line.split() + continue # Skip to the next iteration after setting headers + + + # Handling a new "plane" line or a continuation of plane data + if line.startswith(cls.restraint_label): + # New "plane" entry; save the previous one if it exists + if current_plane_data: + planes_data.append(current_plane_data) + # Reset current_plane_data for a new "plane" entry + current_plane_data = {header: [] for header in headers} + current_plane_data['plane_indices'] = [] # Ensure 'plane_indices' is initialized + + # Split the line using the precompiled pattern, then strip and filter + matches = [match.group() for match in pattern.finditer(line)] + parts = [part.strip() for part in matches if part.strip()!=""] + #print(line) + #print(parts) + + start_idx = 1 if line.startswith(cls.restraint_label) else 0 + #print("Start idx:",start_idx) + # Adjust parsing according to the specific needs, for simplicity assuming plane_index is first + plane_index = parts[start_idx] + # Append the plane_index after conversion to integer if necessary + current_plane_data['plane_indices'].append(int(plane_index) if plane_index.isdigit() else plane_index) + + # Assign values to their corresponding headers + value_idx = start_idx + 1 + #print("Value idx:",value_idx) + for header, value in zip(headers, parts[value_idx:]): + current_plane_data[header].append(tryfloat(value)) + + + + # Add the last plane's data if it exists + #print(current_plane_data) + if current_plane_data: + planes_data.append(current_plane_data) + + + # another pass to ensure equal length data + assert len(planes_data)==1 + plane_data = planes_data[0] + lens = [len(value) for value in plane_data.values()] + max_len = max(lens) + + for key,value in list(plane_data.items()): + if len(value)==1: + plane_data[key] = value*max_len + if key == "plane_indices": + if any([isinstance(v,str) and ("pdb" in v) for v in value]): + plane_data["id_str"] = value + else: + plane_data["i_seq"] = value + del plane_data["plane_indices"] + + return cls({"plane": plane_data}) + + + def __init__(self, data_dict): + self.data_dict = data_dict + + @staticmethod + def form_dataframe(planes): + planes = [d["plane"] for d in planes] + + # Find max length + max_len = 0 + for plane in planes: + lens = [len(value) for value in plane.values()] + assert len(set(lens))==1, "Error: mismatched data lens" + if max(lens)>max_len: + max_len = max(lens) + + # expand each dict + expanded_planes= [] + for plane in planes: + plane_len = len(list(plane.values())[0]) + expanded_plane = {} + for key,value in plane.items(): + cols = [] + values = [] + for i in range(1,max_len+1): + col_name = f"{key}_{i}" + if i<=plane_len: + col_value = value[i-1] + else: + col_value = pd.NA + cols.append(col_name) + values.append(col_value) + expanded_plane.update(dict(zip(cols,values))) + expanded_planes.append(expanded_plane) + # make df + df = pd.DataFrame.from_records(expanded_planes) + return df + restraint_settings = { "nonbonded":{ # name of restraint "header_label":"Nonbonded interactions", # search string @@ -76,12 +209,12 @@ class CBetaRestraint(BondRestraint): "cif_key":"_phenix_restraint_c-beta", "restraint_class":CBetaRestraint, }, - # "plane":{ - # "header_label":"Planarity restraints", - # "n_atoms":None, - # "cif_key":"_phenix_restraint_planarity", - # "restraint_class":PlanarityRestraint, - # }, + "plane":{ + "header_label":"Planarity restraints", + "n_atoms":None, + "cif_key":"_phenix_restraint_planarity", + "restraint_class":PlanarityRestraint, + }, } def split_into_sections(lines): """ @@ -123,14 +256,21 @@ def extract_restraint_objs_from_group(group, new_entry_indicator = 'dihedral' else: new_entry_indicator = restraint_key + restraint_label = restraint_key for idx,line in enumerate(group): # Check if the line is the start of a new entry within the restraint if new_entry_indicator in line: if restraint_lines: # If there are already lines collected for a previous entry, save them + if restraint_key == "plane": + restraint_lines = restraint_lines[:-1] restraints.append(restraint_lines) - restraint_lines = [line] + restraint_lines = [] + if restraint_key == "plane": + if idx>1: + restraint_lines.append(group[idx-1]) + restraint_lines.append(line) else: # This is the first entry in the restraint if restraint_key == "plane": @@ -142,6 +282,8 @@ def extract_restraint_objs_from_group(group, restraint_lines.append(line) # Add the last set of lines if not empty if restraint_lines: + if restraint_key == "plane": + restraint_lines = restraint_lines[:-1] restraints.append(restraint_lines) s = set([len(r) for r in restraints]) if restraint_key != "plane": @@ -176,7 +318,12 @@ def parse_geo_file(filename,return_format='dict'): restraint_key=restraint_label) restraint_dicts_all[restraint_label] = [obj.data_dict for obj in restraint_objs] # convert dicts to dataframes and fill nan with None - dfs = {key:pd.DataFrame(value).replace({np.nan: None}) for key,value in restraint_dicts_all.items()} + dfs = {key:pd.DataFrame(value).replace({np.nan: None}) for key,value in restraint_dicts_all.items() if key != "plane"} + + # add planes + if "plane" in restraint_dicts_all: + df = PlanarityRestraint.form_dataframe(restraint_dicts_all["plane"]) + dfs["plane"] = df if return_format == "df": return dfs elif return_format == "dict": @@ -184,4 +331,22 @@ def parse_geo_file(filename,return_format='dict'): return {key:df.to_dict(orient='records') for key,df in dfs.items()} elif return_format == "json": # same format as dict, but as json string - return {key:df.to_json(orient='records') for key,df in dfs.items()} + d = {key:df.to_json(orient='records') for key,df in dfs.items()} + d = {key:json.loads(v) for key,v in d.items()} + return json.dumps(d,indent=2) + + + +def add_i_seq_columns_from_id_str(restraint_dfs,model): + """ + Given a dict of pandas DataFrames, each containing one type of restraint data, + add i_seq columns from a model by translating the existing id_str columns + """ + restraint_dfs = d + mapping_dict = {atom.id_str():atom.i_seq for atom in model.get_atoms()} + for restraint_name,df in restraint_dfs.items(): + id_str_cols = [col for col in df.columns if "id_str" in col] + i_seq_cols = [col.replace("id_str","i_seq") for col in id_str_cols] + for i_seq_col,id_str_col in zip(i_seq_cols,id_str_cols): + df[i_seq_col] = df[id_str_col].map(mapping_dict) + return restraint_dfs \ No newline at end of file diff --git a/mmtbx/geometry_restraints/tst_geo_file_parsing.py b/mmtbx/geometry_restraints/tst_geo_file_parsing.py index a559070a4f..432db86b46 100644 --- a/mmtbx/geometry_restraints/tst_geo_file_parsing.py +++ b/mmtbx/geometry_restraints/tst_geo_file_parsing.py @@ -130,24 +130,24 @@ "nonbonded": [ { "restraint_type": "nonbonded", - "i_seq": 106, - "j_seq": 110, + "i_seq_0": "106", + "i_seq_1": "110", "model": 1.719, "vdw": 1.85, "sym.op.": "-x+1,y-1/2,-z+1" }, { "restraint_type": "nonbonded", - "i_seq": 29, - "j_seq": 34, + "i_seq_0": "29", + "i_seq_1": "34", "model": 1.859, "vdw": 1.85, "sym.op.": "x,y+1,z" }, { "restraint_type": "nonbonded", - "i_seq": 33, - "j_seq": 61, + "i_seq_0": "33", + "i_seq_1": "61", "model": 1.876, "vdw": 1.85, "sym.op.": null @@ -156,9 +156,9 @@ "angle": [ { "restraint_type": "angle", - "i_seq": 23, - "j_seq": 24, - "k_seq": 25, + "i_seq_0": "23", + "i_seq_1": "24", + "i_seq_2": "25", "ideal": 108.9, "model": 113.48, "delta": -4.58, @@ -168,9 +168,9 @@ }, { "restraint_type": "angle", - "i_seq": 37, - "j_seq": 38, - "k_seq": 39, + "i_seq_0": "37", + "i_seq_1": "38", + "i_seq_2": "39", "ideal": 108.02, "model": 111.93, "delta": -3.91, @@ -182,8 +182,8 @@ "bond": [ { "restraint_type": "bond", - "i_seq": 38, - "j_seq": 39, + "i_seq_0": "38", + "i_seq_1": "39", "ideal": 1.522, "model": 1.553, "delta": -0.03, @@ -193,8 +193,8 @@ }, { "restraint_type": "bond", - "i_seq": 37, - "j_seq": 38, + "i_seq_0": "37", + "i_seq_1": "38", "ideal": 1.46, "model": 1.485, "delta": -0.025, @@ -206,10 +206,10 @@ "dihedral": [ { "restraint_type": "dihedral", - "i_seq": 24, - "j_seq": 25, - "k_seq": 37, - "l_seq": 38, + "i_seq_0": "24", + "i_seq_1": "25", + "i_seq_2": "37", + "i_seq_3": "38", "ideal": 180.0, "model": 166.21, "delta": 13.79, @@ -221,10 +221,10 @@ }, { "restraint_type": "dihedral", - "i_seq": 58, - "j_seq": 59, - "k_seq": 60, - "l_seq": 61, + "i_seq_0": "58", + "i_seq_1": "59", + "i_seq_2": "60", + "i_seq_3": "61", "ideal": 0.0, "model": -72.39, "delta": 72.39, @@ -238,10 +238,10 @@ "chirality": [ { "restraint_type": "chirality", - "i_seq": 55, - "j_seq": 54, - "k_seq": 56, - "l_seq": 58, + "i_seq_0": "55", + "i_seq_1": "54", + "i_seq_2": "56", + "i_seq_3": "58", "both_signs": "False", "ideal": 2.51, "model": 2.39, @@ -252,10 +252,10 @@ }, { "restraint_type": "chirality", - "i_seq": 72, - "j_seq": 71, - "k_seq": 73, - "l_seq": 75, + "i_seq_0": "72", + "i_seq_1": "71", + "i_seq_2": "73", + "i_seq_3": "75", "both_signs": "False", "ideal": 2.51, "model": 2.62, @@ -268,10 +268,10 @@ "c-beta": [ { "restraint_type": "c-beta", - "i_seq": 37, - "j_seq": 39, - "k_seq": 38, - "l_seq": 41, + "i_seq_0": "dihedral", + "i_seq_1": "39", + "i_seq_2": "38", + "i_seq_3": "41", "ideal": 122.8, "model": 126.95, "delta": -4.15, @@ -282,10 +282,10 @@ }, { "restraint_type": "c-beta", - "i_seq": 56, - "j_seq": 54, - "k_seq": 55, - "l_seq": 58, + "i_seq_0": "dihedral", + "i_seq_1": "54", + "i_seq_2": "55", + "i_seq_3": "58", "ideal": -122.6, "model": -126.01, "delta": 3.41, @@ -294,19 +294,459 @@ "weight": 0.16, "residual": 1.86 } + ], + "plane": [ + { + "delta_1": 0.007, + "delta_2": 0.029, + "delta_3": -0.003, + "delta_4": 0.001, + "delta_5": 0.003, + "delta_6": -0.001, + "delta_7": -0.013, + "delta_8": -0.001, + "delta_9": -0.029, + "delta_10": -0.016, + "delta_11": 0.017, + "delta_12": 0.005, + "sigma_1": 0.02, + "sigma_2": 0.02, + "sigma_3": 0.02, + "sigma_4": 0.02, + "sigma_5": 0.02, + "sigma_6": 0.02, + "sigma_7": 0.02, + "sigma_8": 0.02, + "sigma_9": 0.02, + "sigma_10": 0.02, + "sigma_11": 0.02, + "sigma_12": 0.02, + "weight_1": 2500.0, + "weight_2": 2500.0, + "weight_3": 2500.0, + "weight_4": 2500.0, + "weight_5": 2500.0, + "weight_6": 2500.0, + "weight_7": 2500.0, + "weight_8": 2500.0, + "weight_9": 2500.0, + "weight_10": 2500.0, + "weight_11": 2500.0, + "weight_12": 2500.0, + "rms_deltas_1": 0.0143, + "rms_deltas_2": 0.0143, + "rms_deltas_3": 0.0143, + "rms_deltas_4": 0.0143, + "rms_deltas_5": 0.0143, + "rms_deltas_6": 0.0143, + "rms_deltas_7": 0.0143, + "rms_deltas_8": 0.0143, + "rms_deltas_9": 0.0143, + "rms_deltas_10": 0.0143, + "rms_deltas_11": 0.0143, + "rms_deltas_12": 0.0143, + "residual_1": 6.15, + "residual_2": 6.15, + "residual_3": 6.15, + "residual_4": 6.15, + "residual_5": 6.15, + "residual_6": 6.15, + "residual_7": 6.15, + "residual_8": 6.15, + "residual_9": 6.15, + "residual_10": 6.15, + "residual_11": 6.15, + "residual_12": 6.15, + "i_seq_1": 89, + "i_seq_2": 90, + "i_seq_3": 91, + "i_seq_4": 92, + "i_seq_5": 93, + "i_seq_6": 94, + "i_seq_7": 95, + "i_seq_8": 96, + "i_seq_9": 102, + "i_seq_10": 103, + "i_seq_11": 104, + "i_seq_12": 105 + }, + { + "delta_1": -0.003, + "delta_2": -0.022, + "delta_3": 0.019, + "delta_4": -0.002, + "delta_5": -0.012, + "delta_6": null, + "delta_7": null, + "delta_8": null, + "delta_9": null, + "delta_10": null, + "delta_11": null, + "delta_12": null, + "sigma_1": 0.02, + "sigma_2": 0.02, + "sigma_3": 0.02, + "sigma_4": 0.02, + "sigma_5": 0.02, + "sigma_6": null, + "sigma_7": null, + "sigma_8": null, + "sigma_9": null, + "sigma_10": null, + "sigma_11": null, + "sigma_12": null, + "weight_1": 2500.0, + "weight_2": 2500.0, + "weight_3": 2500.0, + "weight_4": 2500.0, + "weight_5": 2500.0, + "weight_6": null, + "weight_7": null, + "weight_8": null, + "weight_9": null, + "weight_10": null, + "weight_11": null, + "weight_12": null, + "rms_deltas_1": 0.0155, + "rms_deltas_2": 0.0155, + "rms_deltas_3": 0.0155, + "rms_deltas_4": 0.0155, + "rms_deltas_5": 0.0155, + "rms_deltas_6": null, + "rms_deltas_7": null, + "rms_deltas_8": null, + "rms_deltas_9": null, + "rms_deltas_10": null, + "rms_deltas_11": null, + "rms_deltas_12": null, + "residual_1": 3.62, + "residual_2": 3.62, + "residual_3": 3.62, + "residual_4": 3.62, + "residual_5": 3.62, + "residual_6": null, + "residual_7": null, + "residual_8": null, + "residual_9": null, + "residual_10": null, + "residual_11": null, + "residual_12": null, + "i_seq_1": 13, + "i_seq_2": 14, + "i_seq_3": 15, + "i_seq_4": 16, + "i_seq_5": 19, + "i_seq_6": null, + "i_seq_7": null, + "i_seq_8": null, + "i_seq_9": null, + "i_seq_10": null, + "i_seq_11": null, + "i_seq_12": null + } ] } +""" +# Now with labels rather than i_seqs +sample_geo_text_2 = """ +Bond restraints: 3 +Sorted by residual: +bond pdb=" N GLY A 1 " + pdb=" CA GLY A 1 " + ideal model delta sigma weight residual + 1.451 1.507 -0.056 1.60e-02 3.91e+03 1.23e+01 +bond pdb=" CA GLN A 4 " + pdb=" C GLN A 4 " + ideal model delta sigma weight residual + 1.522 1.553 -0.030 1.18e-02 7.18e+03 6.53e+00 +bond pdb=" N GLN A 4 " + pdb=" CA GLN A 4 " + ideal model delta sigma weight residual + 1.460 1.485 -0.025 1.17e-02 7.31e+03 4.40e+00 + +Bond angle restraints: 2 +Sorted by residual: +angle pdb=" N ASN A 3 " + pdb=" CA ASN A 3 " + pdb=" C ASN A 3 " + ideal model delta sigma weight residual + 108.90 113.48 -4.58 1.63e+00 3.76e-01 7.90e+00 +angle pdb=" N GLN A 4 " + pdb=" CA GLN A 4 " + pdb=" C GLN A 4 " + ideal model delta sigma weight residual + 108.02 111.93 -3.91 1.78e+00 3.16e-01 4.84e+00 +Dihedral angle restraints: 3 + sinusoidal: 15 + harmonic: 7 +Sorted by residual: +dihedral pdb=" CA ASN A 3 " + pdb=" C ASN A 3 " + pdb=" N GLN A 4 " + pdb=" CA GLN A 4 " + ideal model delta harmonic sigma weight residual + 180.00 166.21 13.79 0 5.00e+00 4.00e-02 7.60e+00 +dihedral pdb=" CB GLN A 5 " + pdb=" CG GLN A 5 " + pdb=" CD GLN A 5 " + pdb=" OE1 GLN A 5 " + ideal model delta sinusoidal sigma weight residual + 0.00 -72.39 72.39 2 3.00e+01 1.11e-03 4.85e+00 +dihedral pdb=" CB GLN A 4 " + pdb=" CG GLN A 4 " + pdb=" CD GLN A 4 " + pdb=" OE1 GLN A 4 " + ideal model delta sinusoidal sigma weight residual + 0.00 54.08 -54.08 2 3.00e+01 1.11e-03 3.50e+00 +Planarity restraints: 2 +Sorted by residual: + delta sigma weight rms_deltas residual +plane pdb=" CB TYR A 7 " -0.006 2.00e-02 2.50e+03 9.66e-03 1.87e+00 + pdb=" CG TYR A 7 " 0.022 2.00e-02 2.50e+03 + pdb=" CD1 TYR A 7 " -0.008 2.00e-02 2.50e+03 + pdb=" CD2 TYR A 7 " -0.004 2.00e-02 2.50e+03 + pdb=" CE1 TYR A 7 " 0.002 2.00e-02 2.50e+03 + pdb=" CE2 TYR A 7 " -0.001 2.00e-02 2.50e+03 + pdb=" CZ TYR A 7 " -0.011 2.00e-02 2.50e+03 + pdb=" OH TYR A 7 " 0.006 2.00e-02 2.50e+03 + delta sigma weight rms_deltas residual +plane pdb=" CB ASN A 2 " 0.006 2.00e-02 2.50e+03 1.19e-02 1.42e+00 + pdb=" CG ASN A 2 " -0.021 2.00e-02 2.50e+03 + pdb=" OD1 ASN A 2 " 0.008 2.00e-02 2.50e+03 + pdb=" ND2 ASN A 2 " 0.007 2.00e-02 2.50e+03 """ +test_data_json_2 = """ +{ + "angle": [ + { + "restraint_type": "angle", + "id_str_0": "pdb=\\\" N ASN A 3 \\\"", + "id_str_1": "pdb=\\\" CA ASN A 3 \\\"", + "id_str_2": "pdb=\\\" C ASN A 3 \\\"", + "ideal": 108.9, + "model": 113.48, + "delta": -4.58, + "sigma": 1.63, + "weight": 0.376, + "residual": 7.9 + }, + { + "restraint_type": "angle", + "id_str_0": "pdb=\\\" N GLN A 4 \\\"", + "id_str_1": "pdb=\\\" CA GLN A 4 \\\"", + "id_str_2": "pdb=\\\" C GLN A 4 \\\"", + "ideal": 108.02, + "model": 111.93, + "delta": -3.91, + "sigma": 1.78, + "weight": 0.316, + "residual": 4.84 + } + ], + "bond": [ + { + "restraint_type": "bond", + "id_str_0": "pdb=\\\" N GLY A 1 \\\"", + "id_str_1": "pdb=\\\" CA GLY A 1 \\\"", + "ideal": 1.451, + "model": 1.507, + "delta": -0.056, + "sigma": 0.016, + "weight": 3910.0, + "residual": 12.3 + }, + { + "restraint_type": "bond", + "id_str_0": "pdb=\\\" CA GLN A 4 \\\"", + "id_str_1": "pdb=\\\" C GLN A 4 \\\"", + "ideal": 1.522, + "model": 1.553, + "delta": -0.03, + "sigma": 0.0118, + "weight": 7180.0, + "residual": 6.53 + }, + { + "restraint_type": "bond", + "id_str_0": "pdb=\\\" N GLN A 4 \\\"", + "id_str_1": "pdb=\\\" CA GLN A 4 \\\"", + "ideal": 1.46, + "model": 1.485, + "delta": -0.025, + "sigma": 0.0117, + "weight": 7310.0, + "residual": 4.4 + } + ], + "dihedral": [ + { + "restraint_type": "dihedral", + "id_str_0": "pdb=\\\" CA ASN A 3 \\\"", + "id_str_1": "pdb=\\\" C ASN A 3 \\\"", + "id_str_2": "pdb=\\\" N GLN A 4 \\\"", + "id_str_3": "pdb=\\\" CA GLN A 4 \\\"", + "ideal": 180.0, + "model": 166.21, + "delta": 13.79, + "harmonic": 0.0, + "sigma": 5.0, + "weight": 0.04, + "residual": 7.6, + "sinusoidal": null + }, + { + "restraint_type": "dihedral", + "id_str_0": "pdb=\\\" CB GLN A 5 \\\"", + "id_str_1": "pdb=\\\" CG GLN A 5 \\\"", + "id_str_2": "pdb=\\\" CD GLN A 5 \\\"", + "id_str_3": "pdb=\\\" OE1 GLN A 5 \\\"", + "ideal": 0.0, + "model": -72.39, + "delta": 72.39, + "harmonic": null, + "sigma": 30.0, + "weight": 0.00111, + "residual": 4.85, + "sinusoidal": 2.0 + }, + { + "restraint_type": "dihedral", + "id_str_0": "pdb=\\\" CB GLN A 4 \\\"", + "id_str_1": "pdb=\\\" CG GLN A 4 \\\"", + "id_str_2": "pdb=\\\" CD GLN A 4 \\\"", + "id_str_3": "pdb=\\\" OE1 GLN A 4 \\\"", + "ideal": 0.0, + "model": 54.08, + "delta": -54.08, + "harmonic": null, + "sigma": 30.0, + "weight": 0.00111, + "residual": 3.5, + "sinusoidal": 2.0 + } + ], + "plane": [ + { + "delta_1": -0.006, + "delta_2": 0.022, + "delta_3": -0.008, + "delta_4": -0.004, + "delta_5": 0.002, + "delta_6": -0.001, + "delta_7": -0.011, + "delta_8": 0.006, + "sigma_1": 0.02, + "sigma_2": 0.02, + "sigma_3": 0.02, + "sigma_4": 0.02, + "sigma_5": 0.02, + "sigma_6": 0.02, + "sigma_7": 0.02, + "sigma_8": 0.02, + "weight_1": 2500.0, + "weight_2": 2500.0, + "weight_3": 2500.0, + "weight_4": 2500.0, + "weight_5": 2500.0, + "weight_6": 2500.0, + "weight_7": 2500.0, + "weight_8": 2500.0, + "rms_deltas_1": 0.00966, + "rms_deltas_2": 0.00966, + "rms_deltas_3": 0.00966, + "rms_deltas_4": 0.00966, + "rms_deltas_5": 0.00966, + "rms_deltas_6": 0.00966, + "rms_deltas_7": 0.00966, + "rms_deltas_8": 0.00966, + "residual_1": 1.87, + "residual_2": 1.87, + "residual_3": 1.87, + "residual_4": 1.87, + "residual_5": 1.87, + "residual_6": 1.87, + "residual_7": 1.87, + "residual_8": 1.87, + "id_str_1": "pdb=\\\" CB TYR A 7 \\\"", + "id_str_2": "pdb=\\\" CG TYR A 7 \\\"", + "id_str_3": "pdb=\\\" CD1 TYR A 7 \\\"", + "id_str_4": "pdb=\\\" CD2 TYR A 7 \\\"", + "id_str_5": "pdb=\\\" CE1 TYR A 7 \\\"", + "id_str_6": "pdb=\\\" CE2 TYR A 7 \\\"", + "id_str_7": "pdb=\\\" CZ TYR A 7 \\\"", + "id_str_8": "pdb=\\\" OH TYR A 7 \\\"" + }, + { + "delta_1": 0.006, + "delta_2": -0.021, + "delta_3": 0.008, + "delta_4": null, + "delta_5": null, + "delta_6": null, + "delta_7": null, + "delta_8": null, + "sigma_1": 0.02, + "sigma_2": 0.02, + "sigma_3": 0.02, + "sigma_4": null, + "sigma_5": null, + "sigma_6": null, + "sigma_7": null, + "sigma_8": null, + "weight_1": 2500.0, + "weight_2": 2500.0, + "weight_3": 2500.0, + "weight_4": null, + "weight_5": null, + "weight_6": null, + "weight_7": null, + "weight_8": null, + "rms_deltas_1": 0.0119, + "rms_deltas_2": 0.0119, + "rms_deltas_3": 0.0119, + "rms_deltas_4": null, + "rms_deltas_5": null, + "rms_deltas_6": null, + "rms_deltas_7": null, + "rms_deltas_8": null, + "residual_1": 1.42, + "residual_2": 1.42, + "residual_3": 1.42, + "residual_4": null, + "residual_5": null, + "residual_6": null, + "residual_7": null, + "residual_8": null, + "id_str_1": "pdb=\\\" CB ASN A 2 \\\"", + "id_str_2": "pdb=\\\" CG ASN A 2 \\\"", + "id_str_3": "pdb=\\\" OD1 ASN A 2 \\\"", + "id_str_4": null, + "id_str_5": null, + "id_str_6": null, + "id_str_7": null, + "id_str_8": null + } + ] +} +""" + test_data = json.loads(test_data_json) +test_data_2 = json.loads(test_data_json_2) # load file with open("tst_geo_parsing.geo","w") as fh: fh.write(sample_geo_text) +# load file +with open("tst_geo_parsing_2.geo","w") as fh: + fh.write(sample_geo_text_2) + # read back in geo_dict = parse_geo_file("tst_geo_parsing.geo",return_format='dict') +geo_dict_2 = parse_geo_file("tst_geo_parsing_2.geo",return_format='dict') + # define comparison functions @@ -339,13 +779,24 @@ def compare_custom(d1,d2): # test -def test(): +def test1(): + print("Test1") for key,d_list in geo_dict.items(): for j,d in enumerate(d_list): d_ref = test_data[key][j] same = compare_custom(d,d_ref) print(same) + +def test2(): + print("Test2") + for key,d_list in geo_dict_2.items(): + for j,d in enumerate(d_list): + d_ref = test_data_2[key][j] + same = compare_custom(d,d_ref) + print(same) + if __name__ == '__main__': - test() + test1() + test2() print("Finished") From ed8893a9197ce751c991980fc7614faf634e6e88 Mon Sep 17 00:00:00 2001 From: Vincent Chen Date: Mon, 5 Feb 2024 18:27:05 -0500 Subject: [PATCH 220/748] cleanup in clashscore, add params output to json --- mmtbx/programs/clashscore.py | 38 +++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/mmtbx/programs/clashscore.py b/mmtbx/programs/clashscore.py index 4b26aedb7c..ce594f1597 100644 --- a/mmtbx/programs/clashscore.py +++ b/mmtbx/programs/clashscore.py @@ -85,21 +85,21 @@ class Program(ProgramTemplate): def validate(self): self.data_manager.has_models(raise_sorry=True) - def get_results_as_JSON(self): - if self.params.do_flips : self.params.keep_hydrogens = False - hierarchy = self.data_manager.get_model().get_hierarchy() - - result = clashscore( - pdb_hierarchy=hierarchy, - fast = self.params.fast, - condensed_probe = self.params.condensed_probe, - keep_hydrogens=self.params.keep_hydrogens, - nuclear=self.params.nuclear, - out=self.logger, - verbose=self.params.verbose and not quiet, - b_factor_cutoff=self.params.b_factor_cutoff, - do_flips=self.params.do_flips) - return result.as_JSON() + #def get_results_as_JSON(self): + # if self.params.do_flips : self.params.keep_hydrogens = False + # hierarchy = self.data_manager.get_model().get_hierarchy() + + # result = clashscore( + # pdb_hierarchy=hierarchy, + # fast = self.params.fast, + # condensed_probe = self.params.condensed_probe, + # keep_hydrogens=self.params.keep_hydrogens, + # nuclear=self.params.nuclear, + # out=self.logger, + # verbose=self.params.verbose and not quiet, + # b_factor_cutoff=self.params.b_factor_cutoff, + # do_flips=self.params.do_flips) + # return result.as_JSON() def run(self, quiet=None): #preserved how quiet was passed to the old run, not sure why """ @@ -113,7 +113,13 @@ def run(self, quiet=None): #preserved how quiet was passed to the old run, not s if self.params.do_flips : self.params.keep_hydrogens = False hierarchy = self.data_manager.get_model().get_hierarchy() self.info_json = {"model_name":self.data_manager.get_default_model_name(), - "time_analyzed": str(datetime.now())} + "time_analyzed": str(datetime.now()), + "params": {"fast":self.params.fast, + "condensed_probe":self.params.condensed_probe, + "keep_hydrogens":self.params.keep_hydrogens, + "nuclear":self.params.nuclear, + "b_factor_cutoff":self.params.b_factor_cutoff, + "do_flips":self.params.do_flips}} self.results = clashscore( pdb_hierarchy=hierarchy, fast = self.params.fast, From 8275dbaf3ad9c2649e25940044389c68f0eb8951 Mon Sep 17 00:00:00 2001 From: Vincent Chen Date: Mon, 5 Feb 2024 18:29:10 -0500 Subject: [PATCH 221/748] adding pperp_dist and probable_pucker evaluation to rna_validate --- mmtbx/validation/rna_validate.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mmtbx/validation/rna_validate.py b/mmtbx/validation/rna_validate.py index 5d0e84502f..7c47c74915 100644 --- a/mmtbx/validation/rna_validate.py +++ b/mmtbx/validation/rna_validate.py @@ -107,6 +107,8 @@ class rna_pucker(residue): "is_delta_outlier", "epsilon_angle", "is_epsilon_outlier", + "Pperp_distance", + "probable_pucker", "model_id", ] @@ -403,6 +405,13 @@ def _get_next_residue(): self.pucker_perp_xyz[key] = [ana.p_perp_xyz, ana.o3p_perp_xyz] self.pucker_dist[key] = [ana.p_distance_c1p_outbound_line, ana.o3p_distance_c1p_outbound_line] + pucker.Pperp_distance=ana.p_distance_c1p_outbound_line + if not pucker.Pperp_distance: + pucker.probable_pucker=None + elif pucker.Pperp_distance and pucker.Pperp_distance < 2.9: + pucker.probable_pucker="C2'-endo" + else: + pucker.probable_pucker="C3'-endo" def get_sugar_xyz_mean(self, residue): sugar_atoms = [" C1'", " C2'", " C3'", " C4'", " O4'"] From c5d1eb287fd60be0919b27176c563f6cb2e9f43d Mon Sep 17 00:00:00 2001 From: Vincent Chen Date: Mon, 5 Feb 2024 18:30:09 -0500 Subject: [PATCH 222/748] add macromolecule_type to mp_validate_bonds output --- mmtbx/validation/mp_validate_bonds.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/mmtbx/validation/mp_validate_bonds.py b/mmtbx/validation/mp_validate_bonds.py index 022e303781..4dce8a416f 100644 --- a/mmtbx/validation/mp_validate_bonds.py +++ b/mmtbx/validation/mp_validate_bonds.py @@ -20,7 +20,7 @@ # individual validation results class mp_bond(atoms): - __slots__ = atoms.__slots__ + ["sigma", "delta", "target", "distance_value"] + __slots__ = atoms.__slots__ + ["sigma", "delta", "target", "distance_value", "macromolecule_type"] @staticmethod def header(): @@ -55,7 +55,7 @@ def as_table_row_phenix(self): self.score ] class mp_angle(atoms): - __slots__ = atoms.__slots__ + ["sigma", "delta", "target", "angle_value"] + __slots__ = atoms.__slots__ + ["sigma", "delta", "target", "angle_value", "macromolecule_type"] @staticmethod def header(): @@ -136,6 +136,11 @@ def __init__(self, pdb_hierarchy, pdb_atoms, geometry_restraints_manager, self.n_outliers_small_by_model[model_id] += 1 else: self.n_outliers_large_by_model[model_id] += 1 + mm_type="OTHER" + if pdb_atoms[proxy.i_seqs[0]].parent().parent().parent().is_protein(): + mm_type="PROTEIN" + elif pdb_atoms[proxy.i_seqs[0]].parent().parent().parent().is_na(): + mm_type="NA" if (is_outlier or not outliers_only): self.results.append(mp_bond( atoms_info=get_atoms_info(pdb_atoms, proxy.i_seqs), @@ -145,7 +150,8 @@ def __init__(self, pdb_hierarchy, pdb_atoms, geometry_restraints_manager, score=num_sigmas, delta=restraint.delta, xyz=flex.vec3_double([pdb_atoms[proxy.i_seqs[0]].xyz, pdb_atoms[proxy.i_seqs[1]].xyz]).mean(), - outlier=is_outlier)) + outlier=is_outlier, + macromolecule_type=mm_type)) def get_result_class(self) : return mp_bond @@ -222,6 +228,11 @@ def __init__(self, pdb_hierarchy, pdb_atoms, geometry_restraints_manager, self.n_outliers_small_by_model[model_id] += 1 else: self.n_outliers_large_by_model[model_id] += 1 + mm_type="OTHER" + if pdb_atoms[proxy.i_seqs[0]].parent().parent().parent().is_protein(): + mm_type="PROTEIN" + elif pdb_atoms[proxy.i_seqs[0]].parent().parent().parent().is_na(): + mm_type="NA" if (is_outlier or not outliers_only): self.results.append(mp_angle( atoms_info=get_atoms_info(pdb_atoms, proxy.i_seqs), @@ -231,7 +242,8 @@ def __init__(self, pdb_hierarchy, pdb_atoms, geometry_restraints_manager, score=num_sigmas, delta=restraint.delta, xyz=pdb_atoms[proxy.i_seqs[1]].xyz, - outlier=is_outlier)) + outlier=is_outlier, + macromolecule_type=mm_type)) def get_result_class(self) : return mp_angle From 3320bc1e897e4bce97f037cce090b936dfbf7d32 Mon Sep 17 00:00:00 2001 From: Vincent Chen Date: Mon, 5 Feb 2024 18:53:58 -0500 Subject: [PATCH 223/748] added cdl option to mp_validate_bonds and params to json output --- mmtbx/programs/mp_validate_bonds.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mmtbx/programs/mp_validate_bonds.py b/mmtbx/programs/mp_validate_bonds.py index 23ced25712..ff409009d9 100644 --- a/mmtbx/programs/mp_validate_bonds.py +++ b/mmtbx/programs/mp_validate_bonds.py @@ -18,6 +18,7 @@ class Program(ProgramTemplate): model=input_file input PDB file outliers_only=False only print outliers json=False Outputs results as JSON compatible dictionary + use_cdl=True Use the Conformational Dependent Library (cdl) for reference values verbose=False verbose text output Example: @@ -33,6 +34,9 @@ class Program(ProgramTemplate): json = False .type = bool .help = "Prints results as JSON format dictionary" + use_cdl = True + .type = bool + .help = "Use conformational dependent library for reference values" use_parent = False .type = bool """ @@ -48,12 +52,16 @@ def run(self): model.set_stop_for_unknowns(False) hierarchy = model.get_hierarchy() self.info_json = {"model_name":self.data_manager.get_default_model_name(), - "time_analyzed": str(datetime.now())} + "time_analyzed": str(datetime.now()), + "params": {"use_cdl":self.params.use_cdl, + "outliers_only":self.params.outliers_only, + }} p = manager.get_default_pdb_interpretation_params() ##print(dir(p.pdb_interpretation)) p.pdb_interpretation.allow_polymer_cross_special_position=True p.pdb_interpretation.flip_symmetric_amino_acids=False p.pdb_interpretation.clash_guard.nonbonded_distance_threshold = None + p.pdb_interpretation.restraints_library.cdl=self.params.use_cdl model.set_log(log = null_out()) model.process(make_restraints=True, pdb_interpretation_params=p) geometry = model.get_restraints_manager().geometry From 040c48749c64f3b3edb8e9d3034b9440c6c60f61 Mon Sep 17 00:00:00 2001 From: chrissciwilliams Date: Mon, 12 Feb 2024 11:02:47 -0500 Subject: [PATCH 224/748] add percentile calcualtions for MolProbity site tables --- .../molprobity/percentile_clashscore.py | 1816 + .../molprobity/percentile_mpscore.py | 27699 ++++++++++++++++ 2 files changed, 29515 insertions(+) create mode 100644 mmtbx/validation/molprobity/percentile_clashscore.py create mode 100644 mmtbx/validation/molprobity/percentile_mpscore.py diff --git a/mmtbx/validation/molprobity/percentile_clashscore.py b/mmtbx/validation/molprobity/percentile_clashscore.py new file mode 100644 index 0000000000..bb94d9cd97 --- /dev/null +++ b/mmtbx/validation/molprobity/percentile_clashscore.py @@ -0,0 +1,1816 @@ +from __future__ import absolute_import, division, print_function + +def get_percentile_for_clashscore(clashscore, resolution=None): + windowHalfWidth = 0.25 + + nSamples = 0 + nWorse = 0 + if not resolution: # None or 0. Resol. not defined -- e.g. NMR structures. Compare to full DB. + minres = 0 + maxres = 9999 + elif(resolution - windowHalfWidth < 0.65): + minres = 0 + maxres = max(0.65, resolution) + windowHalfWidth + elif(resolution + windowHalfWidth > 3.25): + minres = min(3.25, resolution) - windowHalfWidth + maxres = 9999 + else: + minres = resolution - windowHalfWidth + maxres = resolution + windowHalfWidth + + for i in clashscores_by_resolution(): + #[pdbFile,resolution,clashscore] + if minres <= i[1] <= maxres: + nSamples += 1 + if i[2] >= clashscore: + nWorse += 1 + pctRank = int(100.0*nWorse/nSamples) + return {"minres":minres, "maxres":maxres, "count":nSamples, "percentile":pctRank} + +#Clashscore vs. resolution statistics from SCOP 2000 dataset (circa 2004) +#[pdbFile,resolution,clashscore], +def clashscores_by_resolution(): + return [["1ejgH",0.54,0], +["1ucsH",0.62,10.03], +["3al1H",0.75,2.04], +["1hjeH",0.75,17.440001], +["1gciH",0.78,4.55], +["1iuaH",0.8,8.96], +["1gdnH",0.81,17.18], +["1nwzH",0.82,4.69], +["1n55H",0.83,6.7], +["1m40H",0.85,6.18], +["1mc2H",0.85,6.69], +["1muwH",0.86,5.08], +["1g6xH",0.86,11.87], +["1alzH",0.86,18.870001], +["1dy5H",0.87,7.04], +["1gweH",0.88,6.63], +["1etnH",0.89,0], +["1f9yH",0.89,6.47], +["1i1wH",0.89,13.57], +["1oewH",0.9,3.17], +["1ix9H",0.9,6.85], +["1m24H",0.9,7.3], +["1et1H",0.9,8.55], +["1g66H",0.9,14], +["2pvbH",0.91,2.5], +["1iqzH",0.92,3.41], +["1l9lH",0.92,4.67], +["3lztH",0.92,12.58], +["1rb9H",0.92,14.75], +["2fdnH",0.94,1.35], +["1kwfH",0.94,2.3199999], +["1nlsH",0.94,4.51], +["1mxtH",0.95,6.3], +["1ahoH",0.96,3.1500001], +["1ufyH",0.96,4.94], +["1k5cH",0.96,6.18], +["1c75H",0.97,5.79], +["1f94H",0.97,6.85], +["1byiH",0.97,7.49], +["1m1qH",0.97,7.87], +["1ixhH",0.98,2.47], +["1k4iH",0.98,7.96], +["1ug6H",0.99,3.98], +["1ittH",1,0], +["1c7kH",1,2.0699999], +["1eb6H",1,2.6900001], +["2erlH",1,3.53], +["1ga6H",1,5.1], +["1msoH",1,6.39], +["1nqjH",1,7.17], +["1g2yH",1,7.3], +["1o7jH",1,7.31], +["1exrH",1,8.07], +["1lniH",1,8.87], +["1a6mH",1,9.09], +["1lkkH",1,9.15], +["1jfbH",1,9.42], +["1od3H",1,10.07], +["1gkmH",1,11.41], +["1oaiH",1,13.33], +["1mn8H",1,33.07], +["1cxqH",1.02,3.0599999], +["1qtwH",1.02,4.34], +["1cc8H",1.02,9.21], +["1i27H",1.02,13.4], +["1mfmH",1.02,21.940001], +["1kqpH",1.03,5.8], +["1lu0H",1.03,7.53], +["1xy1H",1.04,0], +["1i2tH",1.04,4.15], +["1oe1H",1.04,6.33], +["1d5tH",1.04,6.91], +["1lwbH",1.05,2.74], +["3silH",1.05,2.9000001], +["1fsgH",1.05,3.03], +["1jclH",1.05,3.38], +["1euwH",1.05,5.82], +["1mooH",1.05,5.92], +["1kmvH",1.05,7.5], +["1psrH",1.05,8.92], +["1m9zH",1.05,10.11], +["1m2dH",1.05,10.2], +["1lqtH",1.05,11.99], +["1kjqH",1.05,19.9], +["1qowH",1.0599999,4.23], +["1nkdH",1.0700001,12.89], +["1koiH",1.08,3.83], +["1jbeH",1.08,5.45], +["1ds1H",1.08,6.03], +["1k5nH",1.09,5.02], +["1kzkH",1.09,7.13], +["1jk3H",1.09,9.1], +["1n62H",1.09,13.49], +["2igdH",1.1,1.08], +["1c5eH",1.1,2.4100001], +["1h4gH",1.1,4.67], +["1itxH",1.1,5.75], +["1qj4H",1.1,5.82], +["1ql0H",1.1,6.82], +["1i40H",1.1,6.9], +["1ls1H",1.1,7.45], +["1qlwH",1.1,7.76], +["1l3kH",1.1,9.32], +["1oh0H",1.1,10.43], +["1bkrH",1.1,12.8], +["1f86H",1.1,13.81], +["1gmxH",1.1,29.58], +["1jm1H",1.11,2.71], +["1oc7H",1.11,2.96], +["1jf8H",1.12,3.89], +["1k7cH",1.12,5.08], +["1g2bH",1.12,5.91], +["1n8kH",1.13,5.59], +["1kngH",1.14,3.32], +["1swuH",1.14,6.57], +["1odmH",1.15,3.26], +["1hdoH",1.15,5.71], +["1vfyH",1.15,6.84], +["1h4aH",1.15,8.97], +["1b6gH",1.15,9.09], +["1gwmH",1.15,21.02], +["1hbnH",1.16,5.12], +["1m1nH",1.16,6.57], +["1h4xH",1.16,25.459999], +["1czpH",1.17,6.9], +["1c9oH",1.17,12.84], +["1n3lH",1.1799999,12.66], +["1ubkH",1.1799999,14.65], +["1lqpH",1.1900001,4.8], +["1ifcH",1.1900001,12.82], +["1o7iH",1.2,3.02], +["1kwnH",1.2,3.63], +["1arbH",1.2,4.03], +["1nz0H",1.2,4.15], +["1l0iH",1.2,4.17], +["1qu9H",1.2,4.21], +["1me4H",1.2,5.42], +["1jg1H",1.2,6.07], +["1c0pH",1.2,6.7], +["1bx7H",1.2,6.95], +["1qtnH",1.2,7.36], +["1knmH",1.2,7.48], +["1nwwH",1.2,7.67], +["1munH",1.2,8.04], +["1fyeH",1.2,8.56], +["1m15H",1.2,9.11], +["1gyoH",1.2,9.51], +["2pthH",1.2,9.77], +["1oboH",1.2,10.28], +["1j98H",1.2,11.14], +["1lokH",1.2,15.06], +["1hqjH",1.2,15.81], +["1o08H",1.2,16.18], +["1mj4H",1.2,16.34], +["1ijvH",1.2,17.610001], +["1lc0H",1.2,19.09], +["1cseH",1.2,19.450001], +["1lb3H",1.21,6.62], +["1d4oH",1.21,8.34], +["1kyfH",1.22,7.01], +["1i0vH",1.23,5.45], +["1oi7H",1.23,7.73], +["1nteH",1.24,10.56], +["1gntH",1.25,3.0599999], +["1eaqH",1.25,5.27], +["1o8bH",1.25,5.53], +["3chbH",1.25,5.88], +["1e58H",1.25,6.28], +["2tpsH",1.25,6.81], +["1c1dH",1.25,7.67], +["1j96H",1.25,8.98], +["1m4lH",1.25,9.19], +["1k3xH",1.25,10.47], +["1mf7H",1.25,10.81], +["1j9bH",1.26,7.28], +["1n0qH",1.26,13.3], +["1ctqH",1.26,13.57], +["1gxuH",1.27,11.4], +["1mqkH",1.28,8.06], +["1qksH",1.28,10.62], +["1gkpH",1.29,6.25], +["1bxaH",1.3,2.49], +["1fcyH",1.3,3.0699999], +["1o2dH",1.3,3.5], +["1jcdH",1.3,3.53], +["1eu1H",1.3,3.73], +["1lq9H",1.3,4.45], +["1hdhH",1.3,4.69], +["1nxmH",1.3,5.54], +["1gk9H",1.3,5.75], +["1g61H",1.3,5.8], +["1k3yH",1.3,6.03], +["7fd1H",1.3,6.11], +["1ox0H",1.3,6.73], +["1hyoH",1.3,6.83], +["1ispH",1.3,7.02], +["1jhgH",1.3,8.41], +["1qddH",1.3,8.54], +["1gztH",1.3,9.85], +["1flmH",1.3,9.91], +["1oqvH",1.3,10.11], +["1es9H",1.3,10.12], +["1gz8H",1.3,10.26], +["1hzyH",1.3,10.66], +["1fk5H",1.3,10.73], +["1lzlH",1.3,11.05], +["1jl1H",1.3,12.92], +["1f9vH",1.3,16.35], +["1nuyH",1.3,16.65], +["1dg6H",1.3,17.76], +["1cy5H",1.3,17.99], +["1kmtH",1.3,18.620001], +["1i12H",1.3,28.290001], +["1gwuH",1.3099999,6.9], +["1kgdH",1.3099999,13.72], +["1gxmH",1.3200001,5.66], +["1mkkH",1.3200001,8.15], +["1e7lH",1.3200001,8.53], +["1gpiH",1.3200001,10], +["1lzjH",1.3200001,13.41], +["1ogwH",1.3200001,21.879999], +["1kkoH",1.33,19.370001], +["1utgH",1.34,21.49], +["2lisH",1.35,3.1300001], +["1gyxH",1.35,4.52], +["1kypH",1.35,7.31], +["1e85H",1.35,8.48], +["1gppH",1.35,8.61], +["1e5kH",1.35,11.3], +["1g2rH",1.35,12.01], +["1kufH",1.35,12.73], +["1ijyH",1.35,13.27], +["1pinH",1.35,33.45], +["1lyvH",1.36,7.34], +["1rhsH",1.36,34.36], +["1f1eH",1.37,7.38], +["1jo0H",1.37,12.59], +["1hx0H",1.38,5.71], +["1gvoH",1.38,7.91], +["1jkvH",1.39,4.81], +["1h2wH",1.39,7.46], +["1n8vH",1.39,26.120001], +["1llfH",1.4,4.47], +["1m55H",1.4,5.22], +["1f0iH",1.4,5.42], +["1o98H",1.4,7.12], +["1ezgH",1.4,7.3], +["1kqrH",1.4,7.86], +["1k3iH",1.4,7.87], +["1fo8H",1.4,8.2], +["1o7nH",1.4,8.3], +["1iw0H",1.4,8.5], +["1m1fH",1.4,8.81], +["1en2H",1.4,8.89], +["1eazH",1.4,8.92], +["1gk7H",1.4,9.1], +["1sgpH",1.4,9.13], +["1ygeH",1.4,9.48], +["3vubH",1.4,9.75], +["1fp2H",1.4,10.58], +["1gk8H",1.4,10.66], +["1qopH",1.4,10.95], +["4eugH",1.4,10.99], +["1n13H",1.4,11.34], +["1l6rH",1.4,11.35], +["1obdH",1.4,11.49], +["1mnnH",1.4,12.13], +["1fw9H",1.4,12.26], +["1m22H",1.4,12.4], +["1gp0H",1.4,12.53], +["256bH",1.4,12.67], +["1jy2H",1.4,12.81], +["1ng6H",1.4,12.89], +["1svfH",1.4,13.13], +["1k7jH",1.4,13.21], +["1ltzH",1.4,13.91], +["1htyH",1.4,15.56], +["1ew4H",1.4,16.25], +["1ifrH",1.4,17.09], +["1ew0H",1.4,21.48], +["1kr4H",1.4,23.290001], +["1qgvH",1.4,30.860001], +["1o04H",1.42,4.57], +["1m7gH",1.4299999,8.1], +["1m0kH",1.4299999,28.41], +["1kb0H",1.4400001,10.77], +["1qh5H",1.45,4.51], +["1fm0H",1.45,4.61], +["1lriH",1.45,5.31], +["1gvdH",1.45,5.41], +["1i88H",1.45,5.77], +["1goiH",1.45,6.54], +["1o06H",1.45,6.58], +["1abaH",1.45,7.74], +["1gvfH",1.45,8.23], +["1is3H",1.45,8.23], +["1lw9H",1.45,8.63], +["1di6H",1.45,8.65], +["1hztH",1.45,8.99], +["1kw3H",1.45,8.99], +["1hz4H",1.45,9.32], +["1i71H",1.45,10.05], +["1ji7H",1.45,10.49], +["1idpH",1.45,10.96], +["1qqfH",1.45,10.97], +["1io0H",1.45,11.46], +["1thfH",1.45,11.89], +["1ikpH",1.45,11.92], +["1n7sH",1.45,12.43], +["1bgfH",1.45,13.15], +["2endH",1.45,13.19], +["1lm4H",1.45,13.6], +["1c1kH",1.45,15.89], +["1jboH",1.45,16.49], +["1c8cH",1.45,29.469999], +["1qreH",1.46,7.8], +["1g3pH",1.46,9.3], +["1lc5H",1.46,9.4], +["1gv9H",1.46,12.67], +["1fx2H",1.46,22.639999], +["1m2kH",1.47,54.12], +["1g6uH",1.48,7.89], +["1l7mH",1.48,8.83], +["1ucaH",1.48,9.42], +["3sebH",1.48,9.75], +["1gqiH",1.48,9.8], +["8abpH",1.49,9.82], +["1my7H",1.49,36.59], +["1l7lH",1.5,0.57], +["1ocyH",1.5,1.65], +["2engH",1.5,3.37], +["1nwaH",1.5,3.39], +["1fr3H",1.5,3.63], +["1gd0H",1.5,3.7], +["1dp7H",1.5,4.5], +["1ofzH",1.5,4.71], +["1m7jH",1.5,4.77], +["1brtH",1.5,4.78], +["1lr7H",1.5,4.89], +["1kgsH",1.5,4.97], +["1g6sH",1.5,5.02], +["1dciH",1.5,5.46], +["1nf9H",1.5,5.76], +["3ezmH",1.5,5.97], +["1mlaH",1.5,6.02], +["1iomH",1.5,6.12], +["1ezmH",1.5,6.17], +["1k20H",1.5,6.91], +["1nytH",1.5,7.01], +["1h05H",1.5,7.04], +["1km4H",1.5,7.09], +["1kr7H",1.5,7.14], +["2mcmH",1.5,7.16], +["1a4iH",1.5,7.22], +["1lv7H",1.5,7.26], +["1jl0H",1.5,7.39], +["1f9zH",1.5,7.51], +["1ig5H",1.5,7.53], +["1e19H",1.5,7.53], +["1opdH",1.5,7.7], +["1cruH",1.5,7.96], +["1bx4H",1.5,8.19], +["1koeH",1.5,8.22], +["1dqzH",1.5,8.29], +["1cipH",1.5,8.33], +["2arcH",1.5,8.7], +["1egwH",1.5,8.97], +["1pefH",1.5,9.15], +["1whiH",1.5,9.29], +["1nziH",1.5,9.37], +["1qczH",1.5,9.66], +["1inlH",1.5,9.72], +["1qg8H",1.5,9.75], +["1o6vH",1.5,9.79], +["1lucH",1.5,10.17], +["1ej0H",1.5,10.5], +["1iq6H",1.5,10.52], +["1o9gH",1.5,10.58], +["1m2xH",1.5,10.65], +["1qqqH",1.5,10.99], +["1jz8H",1.5,11.05], +["1od6H",1.5,11.56], +["1hw1H",1.5,11.81], +["1ntvH",1.5,11.85], +["1i0rH",1.5,12.63], +["1k7kH",1.5,12.68], +["1mg4H",1.5,12.79], +["1i52H",1.5,12.91], +["1dj0H",1.5,12.93], +["1aieH",1.5,13.49], +["1elkH",1.5,13.63], +["1ekqH",1.5,13.81], +["1jr8H",1.5,13.82], +["1ijqH",1.5,14.15], +["1qe3H",1.5,14.46], +["1p1mH",1.5,14.51], +["1c4oH",1.5,14.82], +["1lmiH",1.5,15.1], +["1j77H",1.5,15.14], +["1dfmH",1.5,15.33], +["1wfbH",1.5,15.52], +["1mtpH",1.5,15.56], +["1f46H",1.5,16.08], +["1d7pH",1.5,16.41], +["1n7oH",1.5,16.51], +["1byqH",1.5,16.75], +["1l7aH",1.5,17.200001], +["1fl0H",1.5,17.65], +["1gs5H",1.5,17.68], +["1ah7H",1.5,17.690001], +["1fj2H",1.5,17.77], +["1b8oH",1.5,17.799999], +["1krhH",1.5,17.98], +["1kpfH",1.5,18.549999], +["1gmuH",1.5,20.42], +["1cs1H",1.5,20.75], +["1f7lH",1.5,21.629999], +["1b0uH",1.5,22.120001], +["1irqH",1.5,22.42], +["1nlqH",1.5,22.870001], +["1edmH",1.5,32.16], +["1lo7H",1.5,33.35], +["1h32H",1.5,34.52], +["1lyqH",1.5,39.4], +["1qhvH",1.51,5.04], +["1t1dH",1.51,12.64], +["1hq1H",1.52,13.08], +["1oznH",1.52,14.46], +["1iv3H",1.52,14.97], +["1qq5H",1.52,14.99], +["1h16H",1.53,15.9], +["1j6zH",1.54,8.9], +["3grsH",1.54,9.1], +["1dlwH",1.54,9.78], +["1l2hH",1.54,9.92], +["1dypH",1.54,10.28], +["1orcH",1.54,14.11], +["1dl2H",1.54,18.969999], +["1na3H",1.55,3.68], +["4ubpH",1.55,7.34], +["1mv8H",1.55,8.31], +["1nthH",1.55,9.2], +["1d2sH",1.55,10.42], +["1jkeH",1.55,11.18], +["1nogH",1.55,11.93], +["1f0lH",1.55,11.99], +["1hqsH",1.55,12.49], +["1j34H",1.55,13.61], +["1a62H",1.55,13.73], +["1l2pH",1.55,13.88], +["1h99H",1.55,14.36], +["1nc7H",1.55,14.46], +["1mg7H",1.55,14.66], +["1evlH",1.55,16.9], +["1uteH",1.55,17.190001], +["1ugiH",1.55,18.85], +["1kq1H",1.55,19.99], +["1ihrH",1.55,20.280001], +["1eyhH",1.5599999,8.96], +["2a0bH",1.5700001,5.4], +["1m65H",1.5700001,8.69], +["1moqH",1.5700001,10.39], +["1a8dH",1.5700001,13.49], +["1dk8H",1.5700001,13.8], +["1jovH",1.5700001,19.969999], +["1ju3H",1.58,4.32], +["1ms9H",1.58,8.04], +["1awsH",1.58,22.370001], +["1noxH",1.59,3.7], +["1k7iH",1.59,6.83], +["3pviH",1.59,10.24], +["1o1zH",1.6,2.99], +["1b6aH",1.6,5.24], +["1h2cH",1.6,5.31], +["1j2jH",1.6,5.32], +["1hfeH",1.6,6.16], +["1a8eH",1.6,6.36], +["1b8zH",1.6,6.41], +["1lamH",1.6,6.42], +["1of4H",1.6,6.68], +["1qmgH",1.6,7.04], +["1ccwH",1.6,7.18], +["1bfdH",1.6,7.28], +["1l5oH",1.6,7.34], +["1k92H",1.6,7.57], +["1juhH",1.6,7.68], +["1aquH",1.6,7.68], +["1fi2H",1.6,7.72], +["1iupH",1.6,7.73], +["1g87H",1.6,8.31], +["1elwH",1.6,8.67], +["3nulH",1.6,9.1], +["1nfpH",1.6,9.11], +["1a1iH",1.6,9.5], +["1n2eH",1.6,9.54], +["1fbnH",1.6,9.72], +["1kwmH",1.6,9.73], +["1n08H",1.6,10.17], +["1hqkH",1.6,10.32], +["1l9xH",1.6,10.32], +["1euvH",1.6,10.44], +["1nc5H",1.6,10.45], +["1m7yH",1.6,10.68], +["1kyhH",1.6,10.83], +["1uaqH",1.6,10.86], +["1zinH",1.6,10.94], +["1qgiH",1.6,11], +["1i60H",1.6,11.58], +["1h80H",1.6,11.63], +["1dj7H",1.6,11.7], +["1kqfH",1.6,11.83], +["1kwgH",1.6,12], +["1mk0H",1.6,12.22], +["1aopH",1.6,12.31], +["1g6gH",1.6,12.44], +["1fcqH",1.6,12.55], +["1iu8H",1.6,12.56], +["1jkxH",1.6,12.93], +["7odcH",1.6,13.02], +["1n57H",1.6,13.16], +["16pkH",1.6,13.28], +["1jnrH",1.6,13.37], +["1eyvH",1.6,13.8], +["1o97H",1.6,14.36], +["1gvpH",1.6,14.44], +["1gpqH",1.6,14.53], +["1mrjH",1.6,14.56], +["153lH",1.6,14.68], +["1e2wH",1.6,15.03], +["1b3aH",1.6,15.29], +["1in4H",1.6,15.57], +["1hozH",1.6,15.67], +["1jhjH",1.6,15.92], +["1werH",1.6,15.99], +["1lj9H",1.6,16.049999], +["1k4nH",1.6,16.26], +["1fr2H",1.6,16.450001], +["1o26H",1.6,16.620001], +["1j3aH",1.6,16.629999], +["1nm8H",1.6,16.77], +["1bd0H",1.6,16.9], +["1jatH",1.6,17.1], +["1dd9H",1.6,17.190001], +["1vccH",1.6,17.379999], +["1i58H",1.6,17.51], +["1bfgH",1.6,17.66], +["1eonH",1.6,18.959999], +["1kafH",1.6,19.530001], +["1m4jH",1.6,19.799999], +["1gy6H",1.6,19.870001], +["1g4yH",1.6,20.25], +["1ohlH",1.6,21.879999], +["1fiuH",1.6,22.75], +["2ilkH",1.6,23.68], +["2cuaH",1.6,24.360001], +["1g8qH",1.6,25.280001], +["1d8wH",1.6,26.469999], +["1jb3H",1.6,29.790001], +["1fwxH",1.6,34.98], +["1on2H",1.61,18.610001], +["1m26H",1.62,6.71], +["1d0dH",1.62,7.15], +["1iatH",1.62,9.81], +["1gnyH",1.63,2.22], +["1dzoH",1.63,2.4000001], +["1qgwH",1.63,5.97], +["1jjyH",1.63,11.37], +["1k77H",1.63,12.71], +["1qsaH",1.65,2.5999999], +["1kcqH",1.65,3.2], +["1dhnH",1.65,7.23], +["1i9sH",1.65,8.05], +["1jixH",1.65,9.1], +["1l6pH",1.65,9.15], +["1h9mH",1.65,9.16], +["1qtxH",1.65,9.46], +["1jfxH",1.65,9.9], +["1dtdH",1.65,9.98], +["1o9wH",1.65,10.56], +["1dwkH",1.65,11.58], +["1hx6H",1.65,12.43], +["1hxrH",1.65,12.59], +["1cqmH",1.65,12.62], +["1tx4H",1.65,13.38], +["1onwH",1.65,13.84], +["1ezwH",1.65,15.83], +["1l8rH",1.65,17.360001], +["1d0cH",1.65,17.559999], +["1gxrH",1.65,17.82], +["1oxsH",1.65,17.969999], +["1l6xH",1.65,17.969999], +["1qjpH",1.65,18.49], +["1iwlH",1.65,19.27], +["1mvfH",1.65,21.49], +["1gteH",1.65,22.110001], +["1fjjH",1.66,4.22], +["4uagH",1.66,8.21], +["2hmzH",1.66,8.27], +["1e4cH",1.66,8.69], +["1vnsH",1.66,10.73], +["1fxoH",1.66,14.44], +["1gtkH",1.66,15], +["1l3lH",1.66,20.18], +["1n1jH",1.67,6.8], +["1f60H",1.67,9.6], +["1k1eH",1.67,15.52], +["1ns5H",1.6799999,17.049999], +["1jy1H",1.6900001,9.26], +["2hftH",1.6900001,15.09], +["1gaiH",1.7,3.0599999], +["1obfH",1.7,3.35], +["1mofH",1.7,3.6], +["1dszH",1.7,4.44], +["1qhoH",1.7,4.81], +["1lj8H",1.7,5.64], +["1dqgH",1.7,5.78], +["1kidH",1.7,5.81], +["1nepH",1.7,5.84], +["1nrjH",1.7,6.19], +["1hp1H",1.7,6.45], +["1a8oH",1.7,6.52], +["1dmgH",1.7,6.64], +["1qcxH",1.7,7.26], +["2ahjH",1.7,7.41], +["1fvkH",1.7,7.53], +["1uekH",1.7,7.59], +["1ajjH",1.7,7.72], +["1ctfH",1.7,7.94], +["1p5vH",1.7,7.96], +["1h6hH",1.7,8.42], +["1dqiH",1.7,8.43], +["1l3sH",1.7,8.43], +["1akoH",1.7,8.57], +["1mjhH",1.7,8.67], +["1ornH",1.7,8.79], +["1i19H",1.7,8.9], +["1ftrH",1.7,8.95], +["1pdoH",1.7,9], +["1d02H",1.7,9.03], +["1ay7H",1.7,9.03], +["1hjzH",1.7,9.52], +["1n0wH",1.7,9.56], +["2bopH",1.7,9.61], +["1nvmH",1.7,9.68], +["1jhdH",1.7,9.8], +["1k94H",1.7,9.84], +["1k4gH",1.7,9.94], +["1mwvH",1.7,10.03], +["1molH",1.7,10.24], +["1gs9H",1.7,10.52], +["1qd1H",1.7,10.98], +["1fltH",1.7,11.06], +["1a12H",1.7,11.85], +["1erzH",1.7,12.12], +["1f5nH",1.7,12.3], +["1b2pH",1.7,12.47], +["1h03H",1.7,12.86], +["1bgcH",1.7,12.95], +["1m33H",1.7,12.96], +["1jw9H",1.7,13.04], +["1k0rH",1.7,13.08], +["1j83H",1.7,13.19], +["1d3vH",1.7,13.25], +["1izcH",1.7,13.92], +["1kzqH",1.7,14.19], +["1duvH",1.7,14.4], +["1kaeH",1.7,14.65], +["1fndH",1.7,14.71], +["1igqH",1.7,14.71], +["1dmhH",1.7,15.08], +["1m9xH",1.7,15.25], +["1mogH",1.7,15.31], +["1n6aH",1.7,15.32], +["1ks9H",1.7,15.44], +["1o0iH",1.7,15.68], +["1gx5H",1.7,15.69], +["1ogqH",1.7,16.25], +["1p1jH",1.7,16.290001], +["1jm0H",1.7,16.450001], +["1vhhH",1.7,16.870001], +["1mxiH",1.7,17.139999], +["1h6fH",1.7,17.76], +["1pe0H",1.7,17.790001], +["1dbgH",1.7,17.940001], +["1dc1H",1.7,18.18], +["1gx3H",1.7,18.18], +["1jx4H",1.7,18.51], +["1gmiH",1.7,18.74], +["1aqzH",1.7,19.08], +["1vieH",1.7,20.110001], +["1eexH",1.7,20.32], +["1eyeH",1.7,21.190001], +["1nqzH",1.7,21.370001], +["1f3uH",1.7,21.66], +["1josH",1.7,22.110001], +["1ddwH",1.7,22.690001], +["1d4aH",1.7,24.059999], +["1azoH",1.7,24.09], +["1mgqH",1.7,24.139999], +["1njhH",1.7,24.32], +["1mtyH",1.7,24.370001], +["1ewfH",1.7,25.629999], +["1pmiH",1.7,26.83], +["1htwH",1.7,28.42], +["1tfeH",1.7,28.5], +["1j79H",1.7,32.91], +["1ij2H",1.7,33.88], +["1p3qH",1.7,34.6], +["1mz9H",1.7,46.24], +["1gxyH",1.71,10.42], +["1gyvH",1.71,12.88], +["1d0qH",1.71,13.42], +["1gwyH",1.71,13.71], +["1jmkH",1.71,14.62], +["1bm8H",1.71,23.790001], +["1lfpH",1.72,68.41], +["1jtgH",1.73,9.36], +["1fs5H",1.73,21.700001], +["1pcfH",1.74,6.04], +["1g60H",1.74,7.25], +["1ldgH",1.74,8.69], +["1qf8H",1.74,9.37], +["1jiwH",1.74,10.53], +["1jyaH",1.74,23.85], +["1gq8H",1.75,5.62], +["1o3uH",1.75,5.91], +["1kptH",1.75,7.09], +["1kw4H",1.75,7.25], +["3claH",1.75,8.05], +["1gqzH",1.75,8.29], +["1gtfH",1.75,8.44], +["1chdH",1.75,9.12], +["1k2yH",1.75,9.4], +["1behH",1.75,9.97], +["2bbkH",1.75,10.15], +["1ed9H",1.75,10.51], +["1jakH",1.75,10.52], +["1oi2H",1.75,10.79], +["1k6wH",1.75,11.04], +["1nrzH",1.75,11.28], +["1b9mH",1.75,11.68], +["1f32H",1.75,12.78], +["1mixH",1.75,12.95], +["1nszH",1.75,13.03], +["1n8fH",1.75,13.6], +["1go3H",1.75,13.71], +["1avwH",1.75,14.04], +["1g8mH",1.75,14.66], +["1bkbH",1.75,14.97], +["1pg4H",1.75,15.59], +["1d2vH",1.75,15.76], +["1iktH",1.75,15.86], +["1cqxH",1.75,16.1], +["1ne2H",1.75,16.889999], +["1hm9H",1.75,17.35], +["3htsH",1.75,17.969999], +["1j8bH",1.75,18.18], +["1gnuH",1.75,18.700001], +["1l1lH",1.75,20.219999], +["1k9uH",1.75,22.379999], +["1evyH",1.75,23.219999], +["1h5uH",1.76,14.79], +["1dk0H",1.77,10.12], +["1f0jH",1.77,16.57], +["1lplH",1.77,18.120001], +["1qazH",1.78,6.36], +["1oi1H",1.78,10.51], +["1axnH",1.78,18.940001], +["1j23H",1.78,20.43], +["1iabH",1.79,5.3], +["1dxgH",1.8,2.99], +["1kp6H",1.8,4.32], +["2porH",1.8,4.65], +["1bdoH",1.8,4.8], +["1h6lH",1.8,4.85], +["1kveH",1.8,4.89], +["1iibH",1.8,4.98], +["1vsrH",1.8,5.08], +["1fe6H",1.8,5.49], +["1mgtH",1.8,5.52], +["3proH",1.8,5.93], +["2sakH",1.8,6.02], +["1dqsH",1.8,6.09], +["1jyhH",1.8,6.1], +["1m3uH",1.8,6.33], +["1o6sH",1.8,6.69], +["2dpmH",1.8,6.72], +["1fn9H",1.8,6.74], +["1jidH",1.8,6.77], +["1a73H",1.8,7.54], +["1n9pH",1.8,7.73], +["1e1hH",1.8,7.81], +["1a3aH",1.8,8.25], +["1uroH",1.8,8.56], +["1b9wH",1.8,8.65], +["1tyuH",1.8,8.65], +["1dpjH",1.8,8.74], +["1bb1H",1.8,8.82], +["1ak0H",1.8,8.94], +["1m0wH",1.8,9.26], +["1c3cH",1.8,9.26], +["1c02H",1.8,9.35], +["1dl5H",1.8,9.56], +["1vcaH",1.8,9.67], +["1qo7H",1.8,9.72], +["1toaH",1.8,9.9], +["1mhnH",1.8,9.9], +["1ualH",1.8,9.97], +["1h70H",1.8,9.97], +["1qnaH",1.8,9.99], +["1dozH",1.8,10.3], +["1dowH",1.8,10.6], +["1iirH",1.8,10.83], +["1g55H",1.8,11.05], +["2baaH",1.8,11.25], +["1a92H",1.8,11.29], +["1cf9H",1.8,11.81], +["1h72H",1.8,11.93], +["2nacH",1.8,12.04], +["1jhfH",1.8,12.11], +["1oneH",1.8,12.14], +["1dbxH",1.8,12.15], +["1nh8H",1.8,12.16], +["1mpgH",1.8,12.25], +["2sliH",1.8,12.31], +["1cl8H",1.8,12.38], +["1khcH",1.8,12.42], +["1jp3H",1.8,12.83], +["1e1aH",1.8,12.84], +["1npkH",1.8,12.95], +["1jsdH",1.8,12.95], +["1bu8H",1.8,12.99], +["1ld8H",1.8,13.49], +["1k0iH",1.8,14.05], +["1mskH",1.8,14.05], +["1uxyH",1.8,14.11], +["1mugH",1.8,14.19], +["1pymH",1.8,14.21], +["1h4rH",1.8,14.23], +["1jtaH",1.8,14.27], +["2tgiH",1.8,14.27], +["1mwpH",1.8,14.4], +["1ny1H",1.8,14.62], +["1uchH",1.8,14.73], +["1gdoH",1.8,14.83], +["1dqeH",1.8,14.92], +["1tifH",1.8,15.01], +["1j6oH",1.8,15.37], +["1rtmH",1.8,15.52], +["1sluH",1.8,15.58], +["1k6kH",1.8,15.61], +["1fpoH",1.8,15.75], +["1j8rH",1.8,15.86], +["1fc6H",1.8,16.07], +["1mwxH",1.8,16.24], +["1kzfH",1.8,16.309999], +["1c7sH",1.8,16.41], +["1ivwH",1.8,16.41], +["1oxjH",1.8,16.68], +["1mtzH",1.8,16.809999], +["1e6cH",1.8,17], +["1aylH",1.8,17.040001], +["1orvH",1.8,17.059999], +["1dinH",1.8,17.07], +["1f1mH",1.8,17.309999], +["1cy9H",1.8,17.85], +["1j09H",1.8,17.879999], +["1mh9H",1.8,17.959999], +["1lxjH",1.8,19.1], +["1lbuH",1.8,19.24], +["1ig0H",1.8,19.299999], +["1dfuH",1.8,19.459999], +["3eipH",1.8,19.459999], +["1iz5H",1.8,19.629999], +["1l8bH",1.8,19.68], +["1i9zH",1.8,20.07], +["1pgsH",1.8,20.540001], +["1dusH",1.8,20.67], +["1guqH",1.8,21.219999], +["1lfwH",1.8,21.809999], +["1f0yH",1.8,21.91], +["1nkpH",1.8,21.98], +["1bg6H",1.8,22.09], +["1lvmH",1.8,22.190001], +["1hxnH",1.8,22.23], +["1jh6H",1.8,22.440001], +["1nxuH",1.8,23.16], +["3magH",1.8,23.309999], +["1khxH",1.8,23.67], +["1i4jH",1.8,23.959999], +["1ja1H",1.8,24.67], +["1iq4H",1.8,25.280001], +["1lb6H",1.8,25.52], +["1bd8H",1.8,25.559999], +["1ku3H",1.8,25.59], +["3bamH",1.8,25.76], +["1mmlH",1.8,25.76], +["1lm5H",1.8,26.18], +["1iqcH",1.8,26.52], +["1a9xH",1.8,27.110001], +["1g8eH",1.8,30.629999], +["1g9zH",1.8,30.700001], +["1qnfH",1.8,31.32], +["1m1sH",1.8,33.29], +["1hcrH",1.8,34.08], +["1h7cH",1.8,34.12], +["3sicH",1.8,36.05], +["1c3pH",1.8,41.57], +["1e0tH",1.8,46.54], +["2spcH",1.8,53.51], +["1fs1H",1.8,77.03], +["1c96H",1.8099999,14.57], +["1a34H",1.8099999,14.98], +["1gqeH",1.8099999,18.35], +["1l7dH",1.8099999,20.639999], +["1b65H",1.8200001,12.19], +["1h8pH",1.8200001,13.83], +["1iyeH",1.8200001,16.98], +["1hw5H",1.8200001,32.67], +["1o13H",1.83,2.72], +["1hq0H",1.83,8.44], +["1jr2H",1.84,17.690001], +["1b25H",1.85,8.14], +["1extH",1.85,9.52], +["1k8wH",1.85,10.48], +["1l1dH",1.85,11.18], +["1tolH",1.85,11.21], +["1cqqH",1.85,16.120001], +["1f4lH",1.85,16.18], +["1j75H",1.85,17.65], +["3fapH",1.85,18.360001], +["1jbwH",1.85,19.82], +["1eyqH",1.85,20.01], +["1ex2H",1.85,20.24], +["1lm8H",1.85,20.67], +["1oo0H",1.85,22.719999], +["1l8aH",1.85,23.280001], +["1avyH",1.85,24.6], +["1guxH",1.85,26.110001], +["1cq3H",1.85,26.360001], +["1vlsH",1.85,34.59], +["1lmlH",1.86,10.43], +["1g1jH",1.86,15.04], +["1khdH",1.86,17.84], +["1e6iH",1.87,10.39], +["1h1yH",1.87,12.43], +["1gyhH",1.89,6.32], +["1nnwH",1.9,2.1099999], +["1c2aH",1.9,2.8499999], +["1o4wH",1.9,4.11], +["1ailH",1.9,4.42], +["1slmH",1.9,5.05], +["1h6wH",1.9,5.16], +["1o1xH",1.9,5.22], +["1pl3H",1.9,5.74], +["1jd5H",1.9,6.67], +["1k30H",1.9,6.8], +["1whoH",1.9,6.84], +["1cpoH",1.9,7.43], +["1i8aH",1.9,7.52], +["1vpsH",1.9,7.7], +["1rsyH",1.9,7.79], +["1guiH",1.9,8.1], +["1ae9H",1.9,8.21], +["1rh4H",1.9,8.36], +["1bxyH",1.9,8.45], +["1eybH",1.9,8.5], +["1d2tH",1.9,8.91], +["1e0bH",1.9,9.09], +["1qmyH",1.9,9.18], +["1nxjH",1.9,9.24], +["1lu9H",1.9,9.51], +["1mkyH",1.9,9.76], +["1jfrH",1.9,9.79], +["1c1yH",1.9,9.84], +["1ad2H",1.9,9.95], +["1svbH",1.9,10.08], +["1b66H",1.9,10.16], +["1b0nH",1.9,10.29], +["1hn0H",1.9,10.49], +["1ci4H",1.9,10.6], +["1g72H",1.9,10.86], +["1epwH",1.9,11.13], +["1a8lH",1.9,11.31], +["1eejH",1.9,11.34], +["1b5qH",1.9,11.36], +["1czaH",1.9,11.43], +["1jhsH",1.9,11.58], +["1qnxH",1.9,11.77], +["1jflH",1.9,11.84], +["1dzfH",1.9,11.87], +["1jk7H",1.9,11.89], +["1j9lH",1.9,12.19], +["1ei5H",1.9,12.22], +["1dtoH",1.9,12.23], +["1jdhH",1.9,12.24], +["1li1H",1.9,12.48], +["1ll2H",1.9,12.51], +["1soxH",1.9,12.83], +["1b8aH",1.9,13.06], +["1ayoH",1.9,13.07], +["1k6dH",1.9,13.13], +["1qcsH",1.9,13.51], +["1ef1H",1.9,13.59], +["1oaoH",1.9,13.74], +["1gprH",1.9,13.82], +["1m0dH",1.9,13.87], +["1fkmH",1.9,14], +["1etxH",1.9,14.33], +["1at0H",1.9,14.34], +["1on3H",1.9,14.74], +["1b93H",1.9,14.82], +["1i7nH",1.9,14.9], +["1n67H",1.9,15.14], +["1phmH",1.9,15.18], +["1rypH",1.9,15.21], +["1jdwH",1.9,15.59], +["1ib2H",1.9,15.84], +["1jyoH",1.9,16.26], +["1f08H",1.9,16.440001], +["1seiH",1.9,16.709999], +["1ez3H",1.9,17.43], +["1nj4H",1.9,17.51], +["1regH",1.9,17.59], +["1hx1H",1.9,17.68], +["1ca1H",1.9,17.780001], +["2hddH",1.9,18.370001], +["1obbH",1.9,18.66], +["1kekH",1.9,18.889999], +["1n9lH",1.9,19.02], +["1nriH",1.9,19.129999], +["1f00H",1.9,19.15], +["1iwmH",1.9,19.190001], +["1rssH",1.9,19.24], +["1f5mH",1.9,19.700001], +["1oisH",1.9,19.799999], +["1musH",1.9,19.860001], +["1ivnH",1.9,20.719999], +["1p4kH",1.9,21.01], +["1chmH",1.9,21.129999], +["4bclH",1.9,21.27], +["1jmxH",1.9,21.33], +["1di2H",1.9,21.5], +["1qqpH",1.9,21.68], +["1i1qH",1.9,21.719999], +["2piiH",1.9,21.92], +["1iowH",1.9,22.32], +["7ahlH",1.9,22.33], +["1bazH",1.9,22.35], +["1b63H",1.9,22.51], +["1f0kH",1.9,22.75], +["1f0xH",1.9,23.280001], +["1e3oH",1.9,23.469999], +["1c8uH",1.9,23.73], +["1k12H",1.9,24.030001], +["1efdH",1.9,24.34], +["1m6yH",1.9,27.33], +["1g4mH",1.9,30.860001], +["1ezjH",1.9,33.46], +["1n5uH",1.9,34], +["1orsH",1.9,34.74], +["1gu9H",1.9,35.64], +["1cukH",1.9,35.77], +["1fleH",1.9,35.81], +["1lshH",1.9,35.89], +["1lvkH",1.9,35.93], +["1c8zH",1.9,38.58], +["1zfjH",1.9,39.54], +["1eerH",1.9,40.44], +["1lslH",1.9,42.8], +["1qr0H",1.9,50.57], +["1qb0H",1.91,13.58], +["1jqeH",1.91,16.1], +["1ikoH",1.92,19.719999], +["1ku1H",1.9299999,13.61], +["1ekjH",1.9299999,21.040001], +["1bc8H",1.9299999,24.1], +["1jztH",1.9400001,12.52], +["1kblH",1.9400001,19.709999], +["1kx5H",1.9400001,25.35], +["1ptqH",1.95,5.06], +["1o4tH",1.95,6.78], +["1klxH",1.95,9.69], +["1pucH",1.95,9.78], +["1o75H",1.95,12.35], +["1itwH",1.95,12.97], +["1qhdH",1.95,14.02], +["1mdwH",1.95,14.29], +["1ni4H",1.95,14.74], +["1gvnH",1.95,15.67], +["2pspH",1.95,15.83], +["1ko7H",1.95,16.879999], +["1ospH",1.95,17.84], +["1icxH",1.95,18.43], +["1g8fH",1.95,19.76], +["1a4mH",1.95,20.07], +["1l3iH",1.95,22.709999], +["1hs6H",1.95,25.32], +["1k04H",1.95,25.790001], +["1b12H",1.95,26.040001], +["1gpjH",1.95,27.32], +["1crzH",1.95,30.34], +["1g8lH",1.95,30.530001], +["1m1hH",1.95,42.63], +["1beaH",1.95,44.23], +["1h7mH",1.96,10.2], +["1lg7H",1.96,26.059999], +["1m5wH",1.96,32.02], +["1l3pH",1.98,8.05], +["1i9gH",1.98,13.27], +["1by2H",2,3.0899999], +["1qoyH",2,4.39], +["1tl2H",2,5.74], +["1d2zH",2,5.96], +["1ct5H",2,6.84], +["1nbaH",2,6.99], +["1o22H",2,7.05], +["1oe4H",2,7.08], +["1mkaH",2,7.6], +["1mbyH",2,7.75], +["1plzH",2,7.8], +["1gsaH",2,7.88], +["2mltH",2,7.97], +["1he1H",2,8.26], +["1hoeH",2,8.35], +["5csmH",2,8.4], +["1xerH",2,8.53], +["2sqcH",2,8.56], +["1qlmH",2,8.74], +["1j5uH",2,9.01], +["1ni9H",2,9.13], +["1pprH",2,9.18], +["1cozH",2,9.18], +["1h3nH",2,9.66], +["1kskH",2,9.69], +["1cvrH",2,9.69], +["1sraH",2,10.4], +["1dvoH",2,10.48], +["1a1xH",2,10.94], +["1dkzH",2,10.97], +["1dxrH",2,11.03], +["1gl4H",2,11.21], +["1surH",2,11.5], +["1reqH",2,11.8], +["1n1bH",2,11.88], +["1mvlH",2,12.88], +["4mt2H",2,12.97], +["1h1dH",2,12.99], +["1ituH",2,13.03], +["1g13H",2,13.1], +["1bm9H",2,13.53], +["1fc3H",2,13.59], +["1p42H",2,13.68], +["1i36H",2,13.91], +["1a6qH",2,14.14], +["1ekrH",2,14.17], +["1aolH",2,14.25], +["1ga8H",2,14.26], +["1eg3H",2,14.61], +["1o8aH",2,14.63], +["3tdtH",2,14.77], +["1o0wH",2,14.78], +["1hb6H",2,15.08], +["1af7H",2,15.37], +["1d3yH",2,15.38], +["1icfH",2,15.4], +["1ogsH",2,15.5], +["1g38H",2,15.58], +["1bifH",2,15.6], +["1hhsH",2,15.7], +["1i4mH",2,15.7], +["1h3fH",2,16.030001], +["1e8cH",2,16.030001], +["1mgpH",2,16.16], +["1ic2H",2,16.549999], +["1amxH",2,16.57], +["1el6H",2,16.58], +["1tigH",2,16.66], +["1h6kH",2,17.030001], +["1knqH",2,17.23], +["1pswH",2,17.33], +["2dtrH",2,17.34], +["1ofdH",2,17.58], +["1rl6H",2,17.620001], +["1h8eH",2,17.700001], +["1ohtH",2,17.809999], +["1oacH",2,18.040001], +["1jr7H",2,18.049999], +["1dqaH",2,18.15], +["2ptdH",2,18.24], +["1d8cH",2,18.469999], +["1jc4H",2,18.540001], +["1nigH",2,19.120001], +["1hufH",2,19.6], +["1g2fH",2,19.74], +["1gotH",2,19.85], +["1kcmH",2,19.870001], +["1g73H",2,19.92], +["1kmoH",2,20.01], +["1nf5H",2,20.219999], +["1k8kH",2,20.42], +["1m5iH",2,20.77], +["1sacH",2,21.360001], +["1bhtH",2,21.65], +["1n7zH",2,21.809999], +["1kpgH",2,21.870001], +["1io1H",2,22.059999], +["1iegH",2,22.24], +["1cewH",2,22.440001], +["1hf8H",2,23.030001], +["1e7uH",2,23.07], +["1whtH",2,23.08], +["1mzgH",2,23.299999], +["1or7H",2,23.4], +["1bkcH",2,23.690001], +["1dj8H",2,23.99], +["1fviH",2,24.540001], +["1czyH",2,24.85], +["1k32H",2,24.860001], +["1eziH",2,24.889999], +["1qjbH",2,25.309999], +["1gxjH",2,25.4], +["1fmtH",2,25.440001], +["1byrH",2,25.450001], +["1nxzH",2,25.48], +["1aocH",2,25.780001], +["1gefH",2,26.190001], +["1mu5H",2,26.620001], +["1dm9H",2,26.629999], +["1mkiH",2,26.629999], +["1spbH",2,28.209999], +["1f3vH",2,28.309999], +["1fp3H",2,28.52], +["1o0sH",2,28.559999], +["1kp8H",2,28.9], +["1ia9H",2,29.610001], +["1pocH",2,30.25], +["1dceH",2,30.709999], +["1ff9H",2,31.110001], +["1lcyH",2,31.120001], +["1lddH",2,31.88], +["1h1rH",2,33.17], +["1l2lH",2,33.51], +["1nkzH",2,33.76], +["1d2oH",2,34.04], +["1i8dH",2,34.22], +["1dfaH",2,36.66], +["1d8hH",2,38.33], +["1g7sH",2,39.3], +["1nijH",2,40.7], +["1f83H",2,44.92], +["1dd3H",2,44.94], +["1a77H",2,45.76], +["1m1gH",2,50.06], +["1m3yH",2,50.52], +["1k87H",2,52.91], +["1dtjH",2,53.22], +["1mscH",2,57.54], +["1eayH",2,62.11], +["1l6kH",2,80.69], +["1jc9H",2.01,15.55], +["1n2fH",2.01,16.07], +["1li4H",2.01,18.879999], +["1evuH",2.01,20.040001], +["1l0wH",2.01,25.92], +["1nw1H",2.02,14.04], +["1fqjH",2.02,15.27], +["1f3lH",2.03,16.09], +["1k24H",2.03,44.32], +["1jtkH",2.04,11.48], +["1qi9H",2.05,7.44], +["1dkqH",2.05,21.940001], +["1go4H",2.05,39.28], +["1f44H",2.05,40.24], +["1lt8H",2.05,49.69], +["1aa7H",2.0799999,23.49], +["1c94H",2.0799999,36], +["1coiH",2.0999999,4.26], +["2tctH",2.0999999,7.48], +["1thtH",2.0999999,9.32], +["16vpH",2.0999999,11.47], +["1gl1H",2.0999999,11.57], +["1ax4H",2.0999999,11.64], +["1kloH",2.0999999,12.55], +["1a8rH",2.0999999,12.7], +["1dmtH",2.0999999,12.75], +["1qd6H",2.0999999,12.98], +["1e8gH",2.0999999,13.08], +["1ldfH",2.0999999,13.15], +["1kwsH",2.0999999,13.75], +["4sgbH",2.0999999,13.98], +["1lhpH",2.0999999,14.3], +["1k4tH",2.0999999,14.49], +["1br9H",2.0999999,14.59], +["1lrzH",2.0999999,15.12], +["1m1eH",2.0999999,15.48], +["1dcqH",2.0999999,15.62], +["1rmdH",2.0999999,15.89], +["1dyoH",2.0999999,16.82], +["1n81H",2.0999999,17.02], +["1h09H",2.0999999,17.120001], +["1qmhH",2.0999999,17.25], +["1smfH",2.0999999,17.290001], +["1eucH",2.0999999,17.540001], +["1uadH",2.0999999,17.879999], +["1brwH",2.0999999,18.59], +["1omzH",2.0999999,18.77], +["1j1vH",2.0999999,18.82], +["1ed1H",2.0999999,18.9], +["1h5wH",2.0999999,19.42], +["1fs0H",2.0999999,19.469999], +["1a32H",2.0999999,19.690001], +["1isiH",2.0999999,20.040001], +["1h59H",2.0999999,20.809999], +["1dq3H",2.0999999,20.83], +["1ewnH",2.0999999,21.43], +["2e2aH",2.0999999,21.91], +["1mkfH",2.0999999,22.049999], +["1lf6H",2.0999999,22.200001], +["1m98H",2.0999999,22.379999], +["1accH",2.0999999,23.49], +["1escH",2.0999999,23.73], +["1ep3H",2.0999999,25.860001], +["1ofuH",2.0999999,26.07], +["1aisH",2.0999999,26.610001], +["1ek9H",2.0999999,27.120001], +["1a3qH",2.0999999,29.120001], +["2cblH",2.0999999,29.860001], +["1otgH",2.0999999,30.700001], +["1d09H",2.0999999,33.73], +["1cosH",2.0999999,35.27], +["1iznH",2.0999999,37.08], +["1heiH",2.0999999,41.46], +["1f2vH",2.0999999,47.56], +["1jl5H",2.0999999,51.2], +["1mswH",2.0999999,63.68], +["1lvaH",2.1199999,17.879999], +["1n0uH",2.1199999,33.94], +["1h1oH",2.1300001,45.46], +["1i5nH",2.1400001,12.93], +["1in0H",2.1400001,29.129999], +["1h2kH",2.1500001,9.8], +["1cfrH",2.1500001,14.04], +["1k3bH",2.1500001,18.35], +["1ocxH",2.1500001,18.4], +["1dvkH",2.1500001,19.17], +["1h54H",2.1500001,19.450001], +["1ezfH",2.1500001,21.049999], +["1b8kH",2.1500001,23.16], +["1nvvH",2.1800001,11.5], +["1ednH",2.1800001,88.15], +["1bjaH",2.1900001,20.870001], +["1kwiH",2.1900001,25.49], +["1ecmH",2.2,7.82], +["1smtH",2.2,7.88], +["1qc7H",2.2,8.32], +["1p5hH",2.2,8.83], +["1ixcH",2.2,8.91], +["1cxzH",2.2,9.25], +["1llaH",2.2,9.28], +["1dhsH",2.2,10.73], +["1qfhH",2.2,10.92], +["1aw8H",2.2,11.07], +["1efyH",2.2,11.56], +["1dmuH",2.2,11.82], +["1iexH",2.2,12.07], +["2irfH",2.2,12.21], +["1im3H",2.2,12.22], +["1nv8H",2.2,12.37], +["1qamH",2.2,13.79], +["1gmlH",2.2,13.93], +["1j7lH",2.2,14.01], +["1gpmH",2.2,14.14], +["1dkuH",2.2,14.44], +["1i8nH",2.2,14.91], +["1gmjH",2.2,15.66], +["1ii7H",2.2,16.15], +["1kjnH",2.2,16.57], +["1lnsH",2.2,16.66], +["1jlxH",2.2,16.860001], +["1xvaH",2.2,16.879999], +["1cfzH",2.2,17.049999], +["1qrvH",2.2,17.290001], +["1f7uH",2.2,17.559999], +["1phzH",2.2,17.709999], +["1ihnH",2.2,18.129999], +["1kyqH",2.2,18.34], +["1no4H",2.2,18.379999], +["1m4zH",2.2,18.98], +["1n7vH",2.2,19.09], +["1bouH",2.2,19.879999], +["1n4kH",2.2,19.940001], +["1n69H",2.2,20.26], +["1p35H",2.2,20.84], +["1iicH",2.2,20.959999], +["1i5pH",2.2,21.469999], +["1qlaH",2.2,21.48], +["1em2H",2.2,21.549999], +["1is2H",2.2,21.690001], +["1a5tH",2.2,21.85], +["1l8dH",2.2,22.309999], +["1imjH",2.2,22.709999], +["1tulH",2.2,22.809999], +["1i3jH",2.2,23.299999], +["1jocH",2.2,23.309999], +["1vmoH",2.2,24.74], +["1is1H",2.2,25.049999], +["1jvsH",2.2,25.559999], +["1hw7H",2.2,25.92], +["1h6pH",2.2,27.09], +["1oxwH",2.2,27.23], +["1devH",2.2,27.309999], +["1im8H",2.2,27.530001], +["1kuuH",2.2,29], +["1jmtH",2.2,29.459999], +["1tyfH",2.2,29.700001], +["1ewqH",2.2,31.379999], +["1gkzH",2.2,32.17], +["1f6yH",2.2,32.36], +["1xxaH",2.2,33.35], +["1mazH",2.2,33.88], +["1iq8H",2.2,34.7], +["1pfoH",2.2,35.02], +["1hf2H",2.2,35.18], +["1ycsH",2.2,37.97], +["1mkmH",2.2,45.56], +["1g9mH",2.2,47.45], +["1k1fH",2.2,57.93], +["1grjH",2.2,59.24], +["1bpyH",2.2,60.46], +["1mbxH",2.25,9.23], +["1c8nH",2.25,10.36], +["1ignH",2.25,12.84], +["1js3H",2.25,14.44], +["1qo0H",2.25,15.43], +["1jqiH",2.25,21.790001], +["1k78H",2.25,23.24], +["1p32H",2.25,25.290001], +["1bg1H",2.25,27.610001], +["1fi4H",2.27,25.190001], +["1oc0H",2.28,7.58], +["1a79H",2.28,31.129999], +["1nx8H",2.3,4.6], +["2rebH",2.3,6.49], +["1j5yH",2.3,9.18], +["1f35H",2.3,9.92], +["1am7H",2.3,10.22], +["1b33H",2.3,11.15], +["1k4zH",2.3,13.03], +["1jtdH",2.3,13.51], +["1l1sH",2.3,13.65], +["2occH",2.3,13.9], +["1ezvH",2.3,14.58], +["1fxkH",2.3,16.459999], +["1ik9H",2.3,16.68], +["1l3aH",2.3,16.799999], +["1g71H",2.3,16.91], +["1kcfH",2.3,17.110001], +["1gzsH",2.3,18.219999], +["1ycqH",2.3,19.1], +["1js8H",2.3,19.469999], +["1obrH",2.3,20.18], +["1jk4H",2.3,20.23], +["1dbhH",2.3,20.360001], +["2rslH",2.3,21.32], +["1jsuH",2.3,21.77], +["1g31H",2.3,21.83], +["1rl2H",2.3,23.129999], +["1j6rH",2.3,23.48], +["1b79H",2.3,24.200001], +["1l0bH",2.3,25.110001], +["1qexH",2.3,26.440001], +["1fjrH",2.3,27.33], +["2prgH",2.3,29.26], +["2fokH",2.3,29.530001], +["1j7nH",2.3,30.18], +["1djxH",2.3,30.91], +["1nbfH",2.3,33.3], +["1lp1H",2.3,35.43], +["1l0sH",2.3,37.92], +["1l8wH",2.3,38.25], +["1lssH",2.3,41.61], +["1qdmH",2.3,41.88], +["1dcpH",2.3,41.95], +["1m41H",2.3,43.18], +["1biaH",2.3,45.74], +["1e5rH",2.3,46.29], +["4htcH",2.3,48.5], +["1m56H",2.3,50.93], +["1a2xH",2.3,53.17], +["1gd8H",2.3,56.31], +["1bl0H",2.3,60.68], +["1kitH",2.3,62.05], +["1k3rH",2.3,66.09], +["1f3mH",2.3,69.32], +["1ltqH",2.3299999,31.7], +["1jqnH",2.3499999,20.23], +["1l0lH",2.3499999,38.07], +["1bu6H",2.3699999,73.1], +["1a9nH",2.3800001,19.309999], +["1lj2H",2.3800001,22.41], +["1ev7H",2.3800001,31.15], +["1no1H",2.4000001,3.37], +["1debH",2.4000001,9.51], +["1af6H",2.4000001,10.46], +["1f8yH",2.4000001,11.52], +["1a8yH",2.4000001,11.72], +["1pfkH",2.4000001,11.9], +["1l5jH",2.4000001,14.78], +["1n1cH",2.4000001,15.11], +["1n8yH",2.4000001,15.46], +["1jmmH",2.4000001,15.75], +["1i8tH",2.4000001,15.8], +["1eaiH",2.4000001,16.1], +["1qgoH",2.4000001,16.43], +["1kiyH",2.4000001,17.940001], +["1bcoH",2.4000001,18.25], +["1cbfH",2.4000001,19.35], +["1e44H",2.4000001,20.42], +["1loxH",2.4000001,20.42], +["1ifqH",2.4000001,20.49], +["1l0qH",2.4000001,21.049999], +["1k6yH",2.4000001,21.450001], +["1hi9H",2.4000001,21.52], +["1qiuH",2.4000001,21.639999], +["1qmeH",2.4000001,21.889999], +["1qtqH",2.4000001,21.9], +["1f1zH",2.4000001,22.030001], +["1qpoH",2.4000001,22.290001], +["1iu4H",2.4000001,22.959999], +["1colH",2.4000001,23.82], +["1jj2H",2.4000001,24.58], +["1ot5H",2.4000001,25.860001], +["1nbwH",2.4000001,26.110001], +["1ipaH",2.4000001,26.559999], +["2trcH",2.4000001,27.040001], +["1k1xH",2.4000001,27.110001], +["1ehkH",2.4000001,27.17], +["1h3qH",2.4000001,27.620001], +["1o9lH",2.4000001,28.450001], +["1jsxH",2.4000001,28.549999], +["1qs0H",2.4000001,28.91], +["1htqH",2.4000001,30.110001], +["1nd6H",2.4000001,30.73], +["1hnnH",2.4000001,30.85], +["1jadH",2.4000001,34.5], +["1avqH",2.4000001,34.77], +["1epuH",2.4000001,38.98], +["1f89H",2.4000001,40.12], +["1kkhH",2.4000001,41.72], +["1jalH",2.4000001,46.06], +["1jogH",2.4000001,50.85], +["1ubyH",2.4000001,63.05], +["1hh0H",2.4000001,115.27], +["1k47H",2.4200001,26.23], +["1m4uH",2.4200001,39.61], +["1hc7H",2.4300001,14.85], +["1gz5H",2.4300001,17.790001], +["1hk8H",2.45,6.31], +["1ei7H",2.45,31.059999], +["1knzH",2.45,33.46], +["1lpbH",2.46,29.629999], +["1ejfH",2.49,16.309999], +["1fuiH",2.5,11.23], +["1ckmH",2.5,11.49], +["1b5tH",2.5,11.74], +["1pyaH",2.5,11.81], +["1sryH",2.5,11.88], +["1g99H",2.5,14.65], +["2polH",2.5,15.93], +["1ytfH",2.5,16.129999], +["1nw3H",2.5,16.219999], +["1a7jH",2.5,16.860001], +["1di1H",2.5,17.43], +["1qhxH",2.5,17.959999], +["1cmiH",2.5,17.969999], +["1jofH",2.5,18.84], +["1efuH",2.5,19.559999], +["1e3pH",2.5,20.190001], +["1o12H",2.5,21.469999], +["1bjtH",2.5,22.049999], +["1auaH",2.5,22.49], +["1hlvH",2.5,22.700001], +["1jeyH",2.5,22.860001], +["2pvaH",2.5,23.030001], +["1bt3H",2.5,23.280001], +["1e5dH",2.5,23.32], +["1nknH",2.5,23.469999], +["1rlrH",2.5,24.5], +["1cliH",2.5,25.07], +["1gy9H",2.5,26.370001], +["1iuhH",2.5,27.030001], +["1jb0H",2.5,27.52], +["1efnH",2.5,28.200001], +["1f5aH",2.5,28.74], +["1zymH",2.5,29.780001], +["1f6dH",2.5,30.059999], +["1o7fH",2.5,30.629999], +["1zmeH",2.5,31.280001], +["1kzyH",2.5,31.72], +["1m2oH",2.5,31.85], +["1cjyH",2.5,32.09], +["1i31H",2.5,32.2], +["1dcfH",2.5,34.99], +["1bdfH",2.5,35.26], +["1nniH",2.5,35.41], +["1b4aH",2.5,37.79], +["1oqeH",2.5,39.11], +["1i4dH",2.5,41.52], +["1p1cH",2.5,42.66], +["1qpzH",2.5,42.67], +["1fx3H",2.5,44.17], +["1dabH",2.5,44.85], +["1dm0H",2.5,44.96], +["1knyH",2.5,46.2], +["1kpsH",2.5,49.5], +["1b7yH",2.5,54.14], +["1hjrH",2.5,55.73], +["1sknH",2.5,60.85], +["1kfuH",2.5,67.91], +["1otsH",2.51,44.9], +["1c0mH",2.53,34.58], +["1914H",2.53,37.08], +["1l5aH",2.55,25.370001], +["1p0yH",2.55,38.61], +["1gtdH",2.5599999,27.92], +["1mmsH",2.5699999,30.65], +["1gw5H",2.5899999,33.9], +["1ml8H",2.5999999,9.93], +["1jg5H",2.5999999,13.43], +["1cbyH",2.5999999,14.33], +["1ixmH",2.5999999,14.36], +["1kkeH",2.5999999,14.4], +["1hstH",2.5999999,15.46], +["1k2fH",2.5999999,16.35], +["1nktH",2.5999999,17.02], +["1bvpH",2.5999999,17.209999], +["1h8lH",2.5999999,19.950001], +["1avgH",2.5999999,20.48], +["1o70H",2.5999999,23.040001], +["1ebdH",2.5999999,23.809999], +["1lktH",2.5999999,23.99], +["1i78H",2.5999999,24.639999], +["1b3qH",2.5999999,24.73], +["1kc6H",2.5999999,25.25], +["1a6dH",2.5999999,25.799999], +["1hynH",2.5999999,26.65], +["1h9dH",2.5999999,27.73], +["1h0xH",2.5999999,29.01], +["1k8tH",2.5999999,31.299999], +["1b89H",2.5999999,33.06], +["1ft9H",2.5999999,33.55], +["1l9vH",2.5999999,33.96], +["1lxaH",2.5999999,34.38], +["1lrvH",2.5999999,35.57], +["1irxH",2.5999999,37.04], +["1lnzH",2.5999999,38.14], +["1cf7H",2.5999999,41.59], +["1ngvH",2.5999999,41.9], +["1divH",2.5999999,42.42], +["1repH",2.5999999,44.09], +["1c4zH",2.5999999,49.63], +["1hcnH",2.5999999,50.39], +["1nekH",2.5999999,53.2], +["1eulH",2.5999999,53.27], +["1g1xH",2.5999999,55.25], +["1l9hH",2.5999999,63.47], +["1bpoH",2.5999999,65.87], +["1jopH",2.5999999,72.35], +["1iw7H",2.5999999,89.58], +["1qu7H",2.5999999,96.19], +["1j1dH",2.6099999,52.1], +["1lrrH",2.6500001,30.99], +["1keyH",2.6500001,38.16], +["1ni5H",2.6500001,38.23], +["1m9sH",2.6500001,47.99], +["1hkxH",2.6500001,48.02], +["1yrgH",2.6600001,22.860001], +["1qm4H",2.6600001,45.93], +["1c4kH",2.7,9.2], +["2vsgH",2.7,19.690001], +["1ddlH",2.7,22.610001], +["4kbpH",2.7,23.68], +["1gmeH",2.7,25.25], +["1aepH",2.7,26.959999], +["1ecrH",2.7,28.84], +["1k8qH",2.7,31.51], +["1i9bH",2.7,32.56], +["1k5dH",2.7,33.56], +["1h2iH",2.7,34.36], +["1d5yH",2.7,36.03], +["1d7mH",2.7,36.12], +["1bowH",2.7,39.48], +["1anvH",2.7,44.44], +["1gkuH",2.7,46.56], +["1bcpH",2.7,48.05], +["1kgyH",2.7,54.97], +["1c3gH",2.7,59.71], +["1dt9H",2.7,70.93], +["1psdH",2.75,23.01], +["1jbgH",2.75,34.64], +["1pkpH",2.8,15.82], +["1avoH",2.8,19.85], +["1jmuH",2.8,22.42], +["1g8xH",2.8,32.11], +["1fyxH",2.8,33.67], +["1b04H",2.8,38.83], +["1de4H",2.8,39.48], +["1f59H",2.8,39.6], +["1omiH",2.8,40.17], +["1ebpH",2.8,41.1], +["1preH",2.8,41.48], +["1i50H",2.8,43.83], +["1mhdH",2.8,44.84], +["1ku9H",2.8,50.61], +["1fqvH",2.8,52.63], +["2bbvH",2.8,57.77], +["1dkgH",2.8,70.02], +["1cr6H",2.8,70.24], +["1tdjH",2.8,80.4], +["1hekH",2.8,122.82], +["1jpyH",2.8499999,30.6], +["1j5sH",2.8499999,40.68], +["1mr1H",2.8499999,43.29], +["1odhH",2.8499999,45.26], +["1dgsH",2.9000001,25.110001], +["1cjaH",2.9000001,29.969999], +["1n10H",2.9000001,34.64], +["1qf6H",2.9000001,35.39], +["1nkvH",2.9000001,35.82], +["1mi1H",2.9000001,38.14], +["1kmiH",2.9000001,40.44], +["1fo1H",2.9000001,42.56], +["1ir6H",2.9000001,43.64], +["1i1gH",2.9000001,44.5], +["1f02H",2.9000001,46.03], +["1k28H",2.9000001,46.32], +["1nuiH",2.9000001,47.53], +["4dpvH",2.9000001,47.85], +["1nt2H",2.9000001,60.56], +["1ivsH",2.9000001,63.2], +["1dfcH",2.9000001,65.55], +["1jhnH",2.9000001,90.52], +["1o0uH",2.95,6.87], +["1ngmH",2.95,29.219999], +["1oy1H",2.95,31.09], +["1ho8H",2.95,141.48], +["1miwH",3,20], +["1ny7H",3,20.17], +["1g0yH",3,29.860001], +["1ciiH",3,30.299999], +["1ltlH",3,33.84], +["1bmtH",3,36.11], +["1bo1H",3,38.46], +["1m5yH",3,38.88], +["2bpaH",3,41.13], +["1ij5H",3,41.83], +["1huxH",3,46.54], +["1qojH",3,56.17], +["1fezH",3,56.59], +["1c8bH",3,57.03], +["1ko6H",3,73.86], +["1ldjH",3,103.4], +["1jchH",3.02,111.02], +["1nyhH",3.0999999,7.46], +["1jv2H",3.0999999,53.42], +["1lb2H",3.0999999,59.76], +["1miuH",3.0999999,89.39], +["1iblH",3.1099999,50.92], +["1cdzH",3.2,41.83], +["1l7vH",3.2,49.52], +["1f15H",3.2,53.69], +["1flcH",3.2,71.76], +["1gm5H",3.24,163.44], +["1eiyH",3.3,54.75], +["1g5gH",3.3,64.47], +["1qgtH",3.3,101.57], +["1hqmH",3.3,130.42999], +["1ihmH",3.4,26.309999], +["1oyeH",3.48,22.799999], +["2btvH",3.5,31.35], +["1al0H",3.5,56.72], +["1mslH",3.5,60.69], +["1m1cH",3.5,73.08]] diff --git a/mmtbx/validation/molprobity/percentile_mpscore.py b/mmtbx/validation/molprobity/percentile_mpscore.py new file mode 100644 index 0000000000..cb84347255 --- /dev/null +++ b/mmtbx/validation/molprobity/percentile_mpscore.py @@ -0,0 +1,27699 @@ +from __future__ import absolute_import, division, print_function + +def get_percentile_for_mpscore(clashscore, resolution=None): + windowHalfWidth = 0.25 + + nSamples = 0 + nWorse = 0 + if not resolution: # None or 0. Resol. not defined -- e.g. NMR structures. Compare to full DB. + minres = 0 + maxres = 99 + else: + minres = min(resolution, 3.50) - windowHalfwidth; + maxres = max(resolution, 0.75) + windowHalfwidth; + + for i in mpscores_by_resolution(): + #[pdbFile,resolution,clashscore] + if minres <= i[1] <= maxres: + nSamples += 1 + if i[2] >= clashscore: + nWorse += 1 + pctRank = int(100.0*nWorse/nSamples) + return {"minres":minres, "maxres":maxres, "count":nSamples, "percentile":pctRank} + +def mpscores_by_resolution(): + #pdbId,resol,eff.resol -- 30 June 2006, IWD -- "clip12" + 0.41245 + return [["2b97",0.75,1.965260872336], +["1x6z",0.78,1.38745408536147], +["1gci",0.78,1.05470435911845], +["1iua",0.8,1.64212757497556], +["1w0n",0.8,2.0836361525806], +["1pq7",0.8,1.40322386347032], +["1fy5",0.81,1.62828809448369], +["1fy4",0.81,1.59135142739061], +["1fn8",0.81,1.66883424214649], +["1gdn",0.81,1.70571711969543], +["1nwz",0.82,1.66273419950510], +["1cbn",0.83,0.970727514512122], +["1ssx",0.83,1.42870224947083], +["1xvo",0.84,1.02205130751648], +["1mc2",0.85,1.36903323841399], +["3pyp",0.85,1.96507607211783], +["1x8q",0.85,1.47639065933330], +["1x8p",0.85,1.70029352930509], +["1pq5",0.85,1.17350577050062], +["2f01",0.85,1.90826825082061], +["1m40",0.85,1.67793846656451], +["1pjx",0.85,2.41122584229608], +["1g6x",0.86,2.31637739119693], +["1muw",0.86,1.50475120841812], +["1v6p",0.87,2.57474442433433], +["1dy5",0.87,1.66299647379316], +["1gwe",0.88,1.50961178838326], +["1jxx",0.89,0.601278956827984], +["1jxt",0.89,0.601278956827984], +["1jxw",0.89,0.601278956827984], +["1jxy",0.89,1.33625163535425], +["1ab1",0.89,1.28516631375339], +["1f9y",0.89,1.61531738166949], +["1ywa",0.89,1.58985790971229], +["1i1w",0.89,1.70014491078253], +["1byz",0.9,0.79722467662333], +["1et1",0.9,1.46556029569114], +["1n9b",0.9,1.45806136117409], +["2bw4",0.9,1.80782912681078], +["1ix9",0.9,1.47899648682437], +["1ixb",0.9,1.72757862340319], +["2pvb",0.91,1.33569533977138], +["1j0p",0.91,1.83073427284885], +["1rb9",0.92,1.99470920587762], +["2g6f",0.92,1.11501099782361], +["1vb0",0.92,2.14418017375127], +["1l9l",0.92,1.91398289725916], +["1iqz",0.92,1.23824235523948], +["1pwm",0.92,1.71764107719594], +["1n4w",0.92,1.63625617364406], +["1vbw",0.93,1.92391883244999], +["1ok0",0.93,1.58407360138726], +["1b0y",0.93,2.22577416660285], +["1gdq",0.93,1.51065324750634], +["1ea7",0.93,1.50245327484180], +["2fdn",0.94,1.63534129137094], +["1iee",0.94,1.72147450702498], +["1nls",0.94,1.76275626296856], +["2bt9",0.94,1.36514515245320], +["1kwf",0.94,1.01230979933563], +["1brf",0.95,1.34864805697728], +["1kth",0.95,2.44412155672569], +["1zzk",0.95,1.96196303545522], +["1ot6",0.95,2.41376551577349], +["4lzt",0.95,1.14505307288157], +["1hj9",0.95,1.47261659245232], +["1lug",0.95,2.1689523488084], +["1nki",0.95,1.45204791479956], +["1rtq",0.95,1.65734277898701], +["1mj5",0.95,1.53528039967973], +["7a3h",0.95,1.56957712241735], +["1z8a",0.95,1.77501239923204], +["1bxo",0.95,1.68479776533973], +["1s5n",0.95,1.49859162368353], +["1n1p",0.95,1.81337964919360], +["1n4u",0.95,1.79782814796552], +["1mxt",0.95,1.61968267993994], +["1aho",0.96,1.40005363599364], +["1u2h",0.96,1.69404458946789], +["1x6x",0.96,0.970677714183958], +["1ufy",0.96,1.08699834728506], +["1luq",0.96,1.85009685540048], +["1k5c",0.96,1.65054053135397], +["1f94",0.97,1.52710850798342], +["1tg0",0.97,1.6877852220793], +["1c75",0.97,1.41145599070115], +["1xmk",0.97,2.08944444932598], +["1m1q",0.97,1.84112525702981], +["1g4i",0.97,1.49659567238551], +["1vl9",0.97,2.15801411714167], +["1ywb",0.97,1.51705632257489], +["2ayw",0.97,1.63455611685111], +["1byi",0.97,1.77728577169661], +["8a3h",0.97,1.65252881886739], +["2bf6",0.97,1.64897868755912], +["1xg0",0.97,1.31170906688403], +["1tqg",0.98,2.28642291234592], +["1unq",0.98,1.63773559280312], +["2g58",0.98,3.03471078517007], +["2bzz",0.98,1.79421791420039], +["1gqv",0.98,1.87244075051495], +["1k4i",0.98,1.66061877624400], +["1ylj",0.98,1.74800506592178], +["1ic6",0.98,1.81476126245236], +["1v0l",0.98,1.09758950175659], +["1ixh",0.98,1.41085583668854], +["1gvt",0.98,1.23421354192129], +["1s5m",0.98,1.33796145194283], +["1jxu",0.99,0.601278956827984], +["1mwq",0.99,1.56678641372351], +["1sfd",0.99,1.39902984652871], +["2fou",0.99,1.59185810643121], +["1mnz",0.99,1.24669250346491], +["1ug6",0.99,1.23085869772635], +["1p1x",0.99,1.13474501701809], +["1w3m",1,2.96745994285501], +["8rxn",1,1.72919606626825], +["1k6u",1,1.93086130704385], +["5pti",1,2.1403851141216], +["1oai",1,1.80816971031490], +["1ir0",1,1.73651619539919], +["1mso",1,1.67780053040031], +["1lkk",1,2.07570022430012], +["2chh",1,1.33780062707138], +["1g2y",1,1.78742574035072], +["1c7k",1,1.32081947861138], +["1k2a",1,2.20536196965758], +["1r2m",1,1.54976664287303], +["1exr",1,1.875003765893], +["1a6m",1,1.72412553397326], +["1tt8",1,1.89786825693417], +["1eb6",1,1.30848979173881], +["1sy2",1,1.65004169791853], +["1sy3",1,1.58864690265008], +["1ywc",1,1.47639065933330], +["1lni",1,1.68925832044561], +["1t2h",1,1.66107563174927], +["1cex",1,1.93724573982803], +["1k4p",1,2.00902333461964], +["1hj8",1,1.65290971565084], +["2a6z",1,1.37722036044188], +["1pq8",1,1.49865868161911], +["2cws",1,1.98829792889211], +["1y55",1,2.08556237694191], +["2gh7",1,1.89615281061706], +["1zk4",1,1.40685215916001], +["2agt",1,1.95538208964503], +["1gvw",1,1.00830256830075], +["1gvx",1,1.05148779960237], +["1kcc",1,1.91471927898541], +["2abb",1,1.76277013524646], +["1ga6",1,1.38637751606975], +["1mn8",1,2.60716820867592], +["1uzv",1,1.42647444919781], +["1n4v",1,1.73171573314211], +["1gkm",1,2.34531964148716], +["1q6z",1,1.44470604115825], +["1o7j",1,1.45352164599838], +["1sxx",1.01,1.59492649718705], +["1x8o",1.01,1.43060000693230], +["1sy1",1.01,1.52848756786558], +["1cc8",1.02,1.95266338266629], +["1i27",1.02,1.99640687246575], +["1m1r",1.02,1.77586445770808], +["1rw1",1.02,1.20247764716140], +["1cxq",1.02,1.09654216431889], +["1mfm",1.02,2.01084381619419], +["1s0q",1.02,1.38974250848757], +["1s0r",1.02,1.45711566166128], +["1p7w",1.02,2.08619573416477], +["1qtw",1.02,1.50525511182961], +["1y93",1.03,1.71289092768851], +["1nh0",1.03,1.63013174913562], +["1xqo",1.03,1.25750061219750], +["1v0k",1.03,1.29624924594969], +["1is9",1.03,1.77260084005138], +["1kqp",1.03,1.4826622133792], +["1i2t",1.04,1.43316850967083], +["1naz",1.04,1.38583747707700], +["1tjx",1.04,2.1099107888219], +["1uow",1.04,2.09668039464648], +["1qxy",1.04,1.68160783982238], +["2bog",1.04,1.64755366977676], +["2anx",1.04,1.77503236069638], +["2anv",1.04,1.56942040963805], +["1w3l",1.04,1.76296210854757], +["1z3n",1.04,1.68912377421543], +["1oe1",1.04,1.37389321061503], +["1d5t",1.04,1.91328478614400], +["1wui",1.04,2.00591493197973], +["1cnr",1.05,0.957100031169252], +["1sf3",1.05,1.85835124317269], +["1m9z",1.05,2.01874212139], +["1lwb",1.05,1.22128204383019], +["1kf3",1.05,1.45048258090311], +["1euw",1.05,1.80681693966839], +["1r2q",1.05,2.06073667602764], +["1sxw",1.05,2.08512728707764], +["1kmv",1.05,1.81806998888534], +["1psr",1.05,2.17753271262093], +["1m2d",1.05,2.06905307159271], +["2c71",1.05,2.06230979891735], +["1rqw",1.05,1.62253504887887], +["1sfh",1.05,1.03335346715865], +["2fhl",1.05,2.08607147167554], +["1zjy",1.05,1.86123846535287], +["1moo",1.05,1.61330177439429], +["2axw",1.05,1.30595783903335], +["1od8",1.05,1.09443972817606], +["1t41",1.05,1.67610746611427], +["1ixg",1.05,1.10584411872434], +["1rwy",1.05,1.32101099145688], +["1gvv",1.05,1.20272100487632], +["1yqs",1.05,1.20597717718260], +["2aba",1.05,1.57719658444914], +["3sil",1.05,1.42167393765951], +["1jfc",1.05,1.69904929702467], +["1w8f",1.05,1.74877502636576], +["1fsg",1.05,1.27246216240993], +["1jcl",1.05,1.12984058411354], +["1kjq",1.05,2.33515855928042], +["1lqt",1.05,1.71147319485926], +["1qow",1.06,2.21024145784620], +["1czb",1.06,1.14970604218682], +["1sx2",1.06,1.47066704226949], +["1swy",1.06,1.18684706580796], +["1swz",1.06,1.56762305294122], +["1pmh",1.06,1.69337367384501], +["1n40",1.06,1.74527454022647], +["1sxy",1.07,1.72915510635711], +["1sfs",1.07,1.90628019962141], +["1gdu",1.07,1.33491166511681], +["2c9v",1.07,1.50107935862351], +["1v0m",1.07,1.24912723677965], +["1xju",1.07,1.45066225396818], +["2ffy",1.07,1.81817653552414], +["1pwg",1.07,1.32720357548087], +["1jbe",1.08,1.29361713584284], +["1koi",1.08,1.62353324895033], +["1ywd",1.08,2.34626010840394], +["1x8n",1.08,2.02828686447295], +["1w66",1.08,1.22875725987755], +["1p7v",1.08,2.17194825810768], +["1h11",1.08,1.38484977541223], +["1ocq",1.08,1.40296921008428], +["1uwc",1.08,1.28830358850945], +["1w23",1.08,1.67720653111353], +["1jk3",1.09,1.84850685670733], +["1kms",1.09,1.80359965431413], +["1kzk",1.09,1.57576124529174], +["1k5n",1.09,1.30048949510951], +["2car",1.09,2.00983492419086], +["1n62",1.09,2.03242383467070], +["1iro",1.1,1.77844510343202], +["1bq8",1.1,0.756224715184947], +["2igd",1.1,0.811799191116927], +["1igd",1.1,1.94733646298101], +["1t8k",1.1,1.67802374013906], +["1ctj",1.1,1.22345413473652], +["2fe5",1.1,1.43929609712084], +["1t2i",1.1,1.42978596865951], +["1sf5",1.1,1.76737855341967], +["1gmx",1.1,2.11206471426042], +["1bkr",1.1,2.25288709462576], +["1d4t",1.1,1.97357654287920], +["1zwp",1.1,2.21960744551290], +["1tk4",1.1,2.50162268651], +["1tj9",1.1,2.73534400086842], +["2bax",1.1,2.30459767497221], +["1kf2",1.1,1.30597635529106], +["1kf4",1.1,1.54886349440802], +["1f9i",1.1,2.15677714960854], +["1lks",1.1,2.04401940515238], +["1x1k",1.1,1.34104008559492], +["1z2u",1.1,0.7642048436267], +["1a6k",1.1,1.93898949177680], +["2cal",1.1,1.63708590475341], +["1l3k",1.1,1.90798886450088], +["1i40",1.1,1.77885134021181], +["1kt6",1.1,2.46684642725574], +["1pm1",1.1,2.10382986717483], +["1qv0",1.1,1.53898362497323], +["1qv1",1.1,1.62255181718175], +["1p5f",1.1,1.42595481652861], +["2aib",1.1,1.45981191289747], +["1s65",1.1,1.91429742978461], +["2avo",1.1,2.02895273207188], +["2avs",1.1,2.16303694622391], +["1uz3",1.1,2.36444294162349], +["2aog",1.1,1.65612689223172], +["2avm",1.1,2.18682973244991], +["1bs9",1.1,1.24184475484639], +["1k4o",1.1,2.08022452092484], +["1xvm",1.1,1.25076410496898], +["1f86",1.1,2.30391311600235], +["1qnj",1.1,1.09654216431889], +["1zjz",1.1,1.66713567214948], +["1oh0",1.1,1.75197595888850], +["1qj4",1.1,1.35511503216636], +["2fos",1.1,1.41843038320960], +["1ylt",1.1,1.7949419536064], +["1ong",1.1,1.02475231697349], +["1rg8",1.1,1.33193916582951], +["1c5e",1.1,1.27275413456017], +["1ls1",1.1,1.52221963379330], +["1uoz",1.1,1.28907671638537], +["1v0n",1.1,0.933669124375694], +["2b3h",1.1,1.29839747665728], +["1nnf",1.1,1.72380178550207], +["1t2d",1.1,1.43927728272404], +["1pwl",1.1,1.40734815168107], +["1ys1",1.1,1.08996597123797], +["1r0r",1.1,1.40646489643005], +["2bwi",1.1,1.75186269705531], +["2abs",1.1,1.78486916527367], +["1yfq",1.1,2.2058925666684], +["1pwc",1.1,1.39458937793518], +["1kdv",1.1,1.47164361973008], +["1kdy",1.1,1.54765253078424], +["2ab0",1.1,1.54703130451909], +["1h4g",1.1,1.39402339623609], +["1itx",1.1,1.43684967224021], +["2a70",1.1,1.60979022719031], +["1g8t",1.1,1.87601478101020], +["1xf6",1.1,1.38583747707700], +["1o5x",1.1,1.68464857128414], +["1jcj",1.1,1.12664137175994], +["1sby",1.1,2.21143235356679], +["1zl0",1.1,1.60283054379727], +["1su8",1.1,2.11067112182543], +["1wuk",1.1,2.01774897066459], +["1wcg",1.1,1.46736080017521], +["1jm1",1.11,1.09654216431889], +["1i1x",1.11,1.14317755243118], +["1oc7",1.11,1.14532708429951], +["1g2b",1.12,1.52021030545271], +["1tuk",1.12,2.10616514994066], +["1sau",1.12,1.5651951453648], +["1jse",1.12,2.14885214619684], +["1jf8",1.12,1.666461628314], +["1lu4",1.12,2.40939449875541], +["1a7s",1.12,2.11374062608729], +["1k7c",1.12,1.42976745591961], +["2eut",1.12,1.35962546292959], +["2bw5",1.12,1.70474611873133], +["1oe2",1.12,1.16871151766509], +["1mpl",1.12,1.00093356953214], +["1ra0",1.12,1.51868792039840], +["1ym1",1.12,1.6293828031522], +["1h1n",1.12,1.29543241080254], +["1su7",1.12,2.09477705905715], +["2ccw",1.13,1.76679634713675], +["1wtn",1.13,1.14785095230744], +["1u07",1.13,2.09621404823498], +["1v7t",1.13,2.0455698261971], +["1z53",1.13,1.71202793355041], +["1scw",1.13,1.16925719078273], +["1n8k",1.13,1.57258580151728], +["1v7s",1.14,1.44071250128928], +["1wyx",1.14,1.3738694798973], +["1kng",1.14,1.64625801856425], +["1odv",1.14,1.70875174573892], +["1k6a",1.14,1.09033474946576], +["1gok",1.14,1.41682307707501], +["1p6o",1.14,1.83404042179512], +["1rxj",1.14,2.0082829314293], +["1swu",1.14,1.87094717834611], +["1g2z",1.15,1.81695358427534], +["1hg7",1.15,1.27831689229720], +["1vfy",1.15,1.55981329428162], +["1k8u",1.15,1.66014659978131], +["1xmt",1.15,1.56356839670481], +["1zmi",1.15,1.68648241654376], +["1j0o",1.15,2.18097531512210], +["1i8o",1.15,1.50345074197269], +["1b9o",1.15,2.37858702858625], +["1kf5",1.15,1.15252113785079], +["1kf7",1.15,1.30757388982488], +["1kf8",1.15,1.98493759816174], +["1f98",1.15,2.03207205474733], +["1jsf",1.15,1.82073770868319], +["1t3y",1.15,1.57589437770145], +["1o8s",1.15,1.44985222517525], +["1xt5",1.15,1.89561811643495], +["2bzv",1.15,1.49516112335812], +["1a6g",1.15,1.64075014306077], +["1a6n",1.15,1.85701861114746], +["2bwf",1.15,1.15452547504738], +["1u7r",1.15,1.62113608340038], +["1bzp",1.15,1.62627716518539], +["1bzr",1.15,1.27403155534561], +["1gwm",1.15,2.18547330057612], +["1h4a",1.15,1.69991042316585], +["1sy0",1.15,1.81376127287995], +["1d2u",1.15,2.31534442570534], +["1rge",1.15,1.49760802630631], +["1agy",1.15,1.03395106963060], +["2fhz",1.15,1.70686620205432], +["1hdo",1.15,1.38745152746604], +["1xod",1.15,1.4415564924071], +["2awk",1.15,1.57869689805791], +["1uto",1.15,1.3641491919776], +["1utq",1.15,1.66433216566083], +["1utn",1.15,1.85116406353852], +["1oxd",1.15,1.73754714683920], +["1vzi",1.15,1.88575017250402], +["2fov",1.15,1.56160765587926], +["1z70",1.15,1.33578626703711], +["1tkj",1.15,1.40461370906511], +["1hf6",1.15,1.62508197765035], +["1h2j",1.15,1.70873455061337], +["1q0e",1.15,1.41656387830843], +["1b6g",1.15,1.55051079786286], +["1odm",1.15,1.17224716872206], +["1kcd",1.15,2.03298991488522], +["2bwd",1.15,1.65321102570794], +["1oe3",1.15,1.56299451395663], +["1sde",1.15,1.37178422661743], +["1i4u",1.15,1.79171582362293], +["1e9g",1.15,1.35785651826973], +["1suf",1.15,1.93594186056495], +["1het",1.15,1.64264348404902], +["1heu",1.15,1.67250313303023], +["1npi",1.16,1.66502156663757], +["1kou",1.16,1.97086004141762], +["1tzb",1.16,1.61109218611817], +["1x9i",1.16,1.40677921297824], +["1hbn",1.16,1.46591415802795], +["1mro",1.16,1.68088663817024], +["1m1n",1.16,1.73568877370549], +["1c9o",1.17,2.24213039989377], +["1sl9",1.17,1.80158678111868], +["1czp",1.17,1.99329213389501], +["1wkq",1.17,1.96062130117244], +["1hvb",1.17,1.37628995613210], +["1kq6",1.18,2.74575383345489], +["1tjm",1.18,2.02416074670353], +["1n3l",1.18,2.57733896867272], +["1t1g",1.18,1.88262340390676], +["1t1e",1.18,2.18544545752138], +["1ubk",1.18,2.36317559498192], +["2frg",1.19,2.02334296823080], +["2fj8",1.19,1.49083520879302], +["1ljn",1.19,1.22345413473652], +["1ifc",1.19,2.20538714346636], +["1gu2",1.19,1.63126875364749], +["1lqp",1.19,1.62578094931254], +["1uwk",1.19,2.00114534217497], +["1n60",1.19,1.88361376660698], +["1sen",1.2,0.945259225169856], +["1bx7",1.2,1.69550626036113], +["1irn",1.2,1.04416274194194], +["1bq9",1.2,1.67107332574743], +["5rxn",1.2,2.54836080089533], +["4rxn",1.2,3.14235327860535], +["2knt",1.2,2.33879707745381], +["1y0m",1.2,1.41042029200509], +["2sn3",1.2,2.23695141317663], +["1ijv",1.2,2.6989824920823], +["1wm3",1.2,2.29256018991533], +["1cc7",1.2,1.99356303545627], +["1sn9",1.2,2.32468376279026], +["1usm",1.2,2.16029332076212], +["1l0i",1.2,1.56525718112629], +["1mj4",1.2,1.84333923435408], +["2akf",1.2,1.56005274952911], +["1wri",1.2,1.23283558554120], +["1ynv",1.2,1.49589422367457], +["1m5a",1.2,3.02384889660652], +["1wn2",1.2,1.93822880370042], +["1ugu",1.2,2.23333755116577], +["1sqz",1.2,2.45575077154848], +["1uwn",1.2,1.76160030884085], +["1knl",1.2,1.88374431766459], +["1djt",1.2,2.19084329662804], +["1knm",1.2,1.61466542551526], +["1qio",1.2,1.76839740250225], +["1tu9",1.2,1.95087989749498], +["2a26",1.2,1.58081261422421], +["1cz9",1.2,1.8493574148161], +["2fcl",1.2,1.51159310419128], +["1ucr",1.2,2.13420591678193], +["1bz6",1.2,1.77975534711576], +["2bk9",1.2,1.68451839867655], +["1j98",1.2,1.63650387513503], +["1hqj",1.2,2.52205539284641], +["1lf7",1.2,2.10057521570887], +["1i76",1.2,2.31750872435815], +["1cku",1.2,1.59006660361030], +["1amm",1.2,2.21879416721448], +["1i6t",1.2,2.21037269611287], +["2fkk",1.2,1.45248014689210], +["2bbr",1.2,1.88993995436013], +["1g7a",1.2,1.51576655891911], +["1rgg",1.2,1.82690481026992], +["1rgh",1.2,1.69311640032518], +["1rgf",1.2,2.08436952005596], +["2pth",1.2,1.71985277312225], +["1t3r",1.2,1.80386856652997], +["1qrw",1.2,1.67945327951585], +["1qq4",1.2,1.91065495699220], +["1ve4",1.2,2.07168698632555], +["1k1t",1.2,1.64802347327026], +["1z0w",1.2,2.1482043348253], +["1he2",1.2,1.72728899138632], +["1kwn",1.2,1.21197367670572], +["1v8h",1.2,1.67074851685933], +["1gyo",1.2,1.92752940994873], +["1me4",1.2,1.22345413473652], +["1me3",1.2,1.40314990883341], +["1jg1",1.2,1.50926235261940], +["1fye",1.2,1.77376241114872], +["1fy2",1.2,2.08769335706326], +["1o08",1.2,2.08638511480634], +["2nlr",1.2,1.48986280052292], +["1vk1",1.2,0.950345322373524], +["1y59",1.2,1.50371970454827], +["2blv",1.2,1.55263401321076], +["2blw",1.2,1.56435070122798], +["1uai",1.2,1.99307346515309], +["1kg2",1.2,1.50167313197792], +["1mun",1.2,1.92095956481476], +["1o7i",1.2,1.7236213659869], +["2g2s",1.2,1.51932147339795], +["1atg",1.2,1.45032548166596], +["1vr7",1.2,2.08059847715454], +["1i3h",1.2,2.22211373616919], +["1y53",1.2,2.00577573785798], +["1ymt",1.2,1.91030636541275], +["1qtn",1.2,1.83688670674284], +["1o0o",1.2,2.61991681611065], +["1o0h",1.2,2.69725454926379], +["1arb",1.2,1.47322367048861], +["1ylp",1.2,1.76436702439597], +["1nym",1.2,1.41604114886224], +["1xdn",1.2,1.32109392419143], +["1yr4",1.2,1.69811325635566], +["2f91",1.2,1.76690941020270], +["1tkf",1.2,1.41826156737942], +["1xbu",1.2,1.41791964242595], +["1nww",1.2,1.45862574565813], +["1lc0",1.2,2.20454173961391], +["1lok",1.2,2.17647254236427], +["1zby",1.2,1.60561218769373], +["1w3k",1.2,1.50712699773364], +["1e0w",1.2,0.715772856642468], +["1z2n",1.2,1.46288062995265], +["1q35",1.2,1.60707468358047], +["1s1p",1.2,1.91792865295650], +["1ryo",1.2,1.78998450144411], +["1cse",1.2,2.44250650925276], +["1obo",1.2,1.52435407877203], +["1wxc",1.2,1.72258520388345], +["1pwd",1.2,1.15865011281288], +["1pw1",1.2,1.31933842479931], +["1r5y",1.2,1.56165252161593], +["1m15",1.2,1.65072298575862], +["1qu9",1.2,1.0728008573201], +["1i24",1.2,1.38648693877638], +["1h12",1.2,1.46690040053583], +["1nz0",1.2,1.65964426249592], +["1ney",1.2,1.43292408756123], +["1e4m",1.2,1.72751923963879], +["1pi3",1.2,1.30224604285945], +["1po7",1.2,1.29308456715851], +["2bhz",1.2,1.45634467770457], +["2bln",1.2,1.58270187777823], +["1w32",1.2,1.88750479386733], +["2c0r",1.2,1.88395582475955], +["1mgo",1.2,1.44237750158679], +["1ubl",1.2,2.36560442188242], +["1qw9",1.2,2.28969536389651], +["1tqw",1.2,1.53334821537207], +["1qwn",1.2,1.59027022874538], +["1w6s",1.2,1.65884538514698], +["1q6o",1.2,1.59688129697277], +["1sxk",1.21,2.44417531340188], +["1skg",1.21,2.96349123164206], +["1e29",1.21,1.91933601625354], +["1lb3",1.21,1.34398233955609], +["1d4o",1.21,1.90358940623486], +["1j8a",1.21,1.22963562196612], +["2b69",1.21,0.971961256759092], +["1n63",1.21,1.78857491660771], +["9pti",1.22,1.56286758592315], +["1g39",1.22,2.36692884885382], +["2f8g",1.22,2.14889118376704], +["1kyf",1.22,2.12433740735429], +["1z2p",1.22,1.43766252680257], +["1mju",1.22,1.87910350333737], +["1yno",1.22,1.55698839960266], +["1hxh",1.22,1.84768942877991], +["1ycc",1.23,2.52216879632263], +["1th6",1.23,2.24518019132866], +["2arm",1.23,2.24518019132866], +["1ppz",1.23,1.72478008968441], +["1pqa",1.23,1.80644029084515], +["2a3n",1.23,1.22839808476024], +["1nte",1.24,1.86303864907803], +["1wma",1.24,1.42290073085931], +["2c9s",1.24,2.17146579747082], +["2c9u",1.24,1.64490872200028], +["1z2o",1.24,1.51170131277103], +["1usc",1.24,1.79186493661528], +["1wuh",1.24,1.97315888317806], +["1jni",1.25,1.37343371638810], +["1msi",1.25,1.80975504106658], +["2c60",1.25,1.68878233741344], +["1y6x",1.25,1.16157101563331], +["1mfg",1.25,1.82505891475439], +["1unr",1.25,2.31015645289891], +["1qau",1.25,2.02527462111721], +["1zma",1.25,1.39633720660444], +["2ft6",1.25,1.3085342389448], +["1tjq",1.25,2.84455344199520], +["1tg1",1.25,3.07712104739411], +["1tjk",1.25,2.8607991357569], +["2d6b",1.25,2.64910613363840], +["2fvv",1.25,1.72559401092371], +["1s3c",1.25,1.46716217356999], +["2fg1",1.25,1.76141755046425], +["1hq2",1.25,1.16871151766509], +["1q0n",1.25,1.62591631701000], +["1hk0",1.25,1.83431527303718], +["1ml7",1.25,1.62364736482684], +["1rfk",1.25,1.53296742168010], +["1i8v",1.25,1.39594750388537], +["1mf7",1.25,2.40334881926003], +["1sdu",1.25,1.39791938164698], +["2f81",1.25,2.01198390083082], +["1cus",1.25,1.49150045843869], +["1m2b",1.25,2.15388845671484], +["1lxz",1.25,1.6505589123319], +["1s83",1.25,1.15655756577919], +["2fzu",1.25,1.78616731761596], +["1ooh",1.25,1.7363404376669], +["1k3x",1.25,2.05720854401843], +["2foq",1.25,1.83598589882847], +["1oaa",1.25,1.77030421943149], +["1tkh",1.25,1.30291037828273], +["1ird",1.25,1.84809371601016], +["2dfo",1.25,1.76573549370977], +["1m4l",1.25,1.96688227528307], +["2b3n",1.25,2.37846321379937], +["1tmm",1.25,1.79093484935588], +["2wea",1.25,1.27504558943552], +["1wms",1.25,2.27636327355804], +["1qft",1.25,1.93478211319764], +["1o8b",1.25,1.58575959630078], +["1mex",1.25,1.60829808998471], +["2b82",1.25,1.31464029704652], +["2tps",1.25,1.84215439776823], +["3chb",1.25,1.57506104635042], +["1jeu",1.25,2.05789545349848], +["1yly",1.25,1.36745875104939], +["2cov",1.25,1.59232816140901], +["1gnt",1.25,1.33147539448454], +["2dfq",1.25,1.87252158870876], +["1ynp",1.25,1.69387129860935], +["1c1d",1.25,1.8546628173076], +["1m70",1.25,1.72987150501570], +["1rwh",1.25,1.2319135300617], +["1lqu",1.25,1.58247005579545], +["1gnl",1.25,1.57814421162675], +["1oa0",1.25,1.53253825370322], +["1upx",1.25,1.50198621247608], +["7rsa",1.26,0.904107539056337], +["1j9b",1.26,1.79227785568528], +["1ctq",1.26,2.31173777599446], +["1n0q",1.26,1.91547544959421], +["2cc6",1.27,1.66325390948987], +["1gxu",1.27,1.65455849963564], +["2cak",1.27,2.39687976837530], +["2bjd",1.27,1.82020784152988], +["1ikj",1.27,1.88548314658985], +["1vyp",1.27,1.54819881984336], +["1wdp",1.27,1.71858053322774], +["1kt7",1.27,2.53132336998043], +["1c52",1.28,2.20321505273575], +["1rtt",1.28,1.51751850019469], +["1mqk",1.28,1.90038581464040], +["1w04",1.28,1.29119311993476], +["1t1i",1.28,2.06360736409244], +["1wdq",1.28,1.81510448431211], +["1vlb",1.28,1.93808779241655], +["1qks",1.28,1.77436696673596], +["1pqh",1.29,1.23863514252176], +["1zbz",1.29,1.45604086659489], +["2aeb",1.29,2.28057132507363], +["1gkp",1.3,1.73901190825532], +["1zmk",1.3,1.71020653690551], +["1jo8",1.3,1.79913226688491], +["1sn4",1.3,2.74086264291555], +["1ptx",1.3,1.30816811311667], +["1seg",1.3,1.81059752040564], +["1pid",1.3,2.22317889739994], +["1ulr",1.3,1.54267518446438], +["1ls9",1.3,1.3725844997413], +["1fk5",1.3,1.68534537292288], +["1cy5",1.3,2.41476378738608], +["1w2l",1.3,2.39517683917659], +["1qt9",1.3,1.00030303478462], +["1jhg",1.3,1.43021529028650], +["1v70",1.3,1.91272117376716], +["1bxa",1.3,1.44947987862062], +["2rac",1.3,1.21699260402446], +["1fus",1.3,1.37148365745910], +["7fd1",1.3,1.71166318624300], +["1rro",1.3,1.64211849389331], +["1pwa",1.3,1.92966194304152], +["1r29",1.3,2.09196727368661], +["135l",1.3,2.30480106648153], +["1w8u",1.3,1.31821553223422], +["2df6",1.3,1.95826890359981], +["1o8x",1.3,1.23917042626338], +["1qdd",1.3,1.88419391890664], +["1dg6",1.3,2.34038657132952], +["1zce",1.3,2.19693569180752], +["1f4p",1.3,1.26565602384815], +["1jcd",1.3,1.14317755243118], +["1jl1",1.3,1.99286046076022], +["1jw8",1.3,1.44607165841799], +["1rut",1.3,0.991191604184062], +["1uso",1.3,1.72502001185635], +["1sxv",1.3,1.42973612033866], +["1k6f",1.3,1.12884143520705], +["1xeo",1.3,1.53749160209949], +["1x1r",1.3,1.35045652139913], +["1z6m",1.3,1.66495928244465], +["1isp",1.3,1.98868243273586], +["1mjn",1.3,2.02301657428599], +["1g7b",1.3,1.47344035177278], +["1vp8",1.3,1.15037620165004], +["1ucd",1.3,1.91549696867403], +["1sdt",1.3,1.13174753832513], +["2a1e",1.3,1.59273093081704], +["1s6g",1.3,2.07519642618280], +["1tw7",1.3,2.05578134364005], +["2aoc",1.3,1.38047537573856], +["2avq",1.3,1.88945489578639], +["1yj1",1.3,2.09530753448231], +["1es9",1.3,2.40685925464503], +["2by6",1.3,1.34905319550174], +["1vd6",1.3,1.89737543984659], +["1lq9",1.3,1.56719723203369], +["1utp",1.3,1.48266231721815], +["2by7",1.3,1.34905319550174], +["2by8",1.3,1.37531153264405], +["2bya",1.3,1.37531153264405], +["2by5",1.3,1.42056568143491], +["2by9",1.3,1.42199434872765], +["2g6e",1.3,1.58927157928058], +["1qwy",1.3,1.12165379218767], +["2fhn",1.3,1.88015867589622], +["1fcy",1.3,1.44873951742782], +["1flm",1.3,1.76341495872567], +["2f69",1.3,1.88310791940331], +["1wcw",1.3,2.33719964196708], +["1ozu",1.3,1.64296502136634], +["1tf8",1.3,1.23376264510803], +["1tf9",1.3,1.43153064271297], +["1dcs",1.3,1.64159650481862], +["1kmt",1.3,1.75357176284157], +["1xub",1.3,1.64692851377640], +["2c4b",1.3,1.51582343455503], +["1gz8",1.3,1.95448065356647], +["2as4",1.3,1.16693758820814], +["2euq",1.3,1.51675072739460], +["1f9v",1.3,2.47791276117729], +["1tjy",1.3,1.59082863758256], +["1x98",1.3,2.12615331723213], +["1lzl",1.3,2.33287188543941], +["1rya",1.3,1.90698764169525], +["1wly",1.3,1.84983653001325], +["2bjs",1.3,1.33017858296191], +["1vly",1.3,1.35952841592623], +["1tbf",1.3,1.68991638272081], +["1nuw",1.3,2.59209003235189], +["1uzw",1.3,1.52406748131309], +["1bk0",1.3,1.18748045611553], +["2bu9",1.3,1.27761275189745], +["1yg9",1.3,1.98093877928820], +["1hb2",1.3,1.23499683174895], +["1obn",1.3,1.39328280414143], +["1to2",1.3,1.55624942943092], +["1wkr",1.3,1.04534700544190], +["2fcj",1.3,1.87287566832829], +["1pw8",1.3,1.35792012543342], +["1usf",1.3,1.57029927195599], +["1ka1",1.3,2.17323479136449], +["1s2p",1.3,1.72309116388049], +["1ocj",1.3,1.68916053351309], +["1nlu",1.3,1.37552043300169], +["1wpn",1.3,1.34925476469615], +["1dbf",1.3,2.12296293729788], +["1nxm",1.3,1.79500780127824], +["1jnd",1.3,1.73351773962712], +["1h13",1.3,1.46248394543657], +["1xwt",1.3,1.15795534673656], +["1wmd",1.3,1.42442815380976], +["1ncw",1.3,1.91209483683671], +["1k3y",1.3,1.77600939568967], +["1g61",1.3,1.77221612623104], +["1gzt",1.3,1.51133281599173], +["2a50",1.3,2.10286108791205], +["1vdw",1.3,1.66093084228094], +["1jr0",1.3,1.90566606281449], +["1djr",1.3,1.36818650946346], +["1wvf",1.3,1.42952257284146], +["1jev",1.3,2.00423305267933], +["2d1s",1.3,1.36533234808536], +["1o7q",1.3,1.78779944251856], +["1ynq",1.3,1.92035169289497], +["1i12",1.3,2.17167426755067], +["1i0d",1.3,2.27065198477283], +["1i0b",1.3,2.67935448020201], +["1hzy",1.3,2.13744106067325], +["1jgm",1.3,2.28785294674433], +["1z41",1.3,1.56028268371163], +["2bie",1.3,1.43319239437484], +["1o2d",1.3,1.11086365968396], +["1j2r",1.3,1.74271684571710], +["1sg4",1.3,2.16149844672110], +["1rwa",1.3,1.36432897433213], +["1eu1",1.3,1.38278059678279], +["1gk9",1.3,1.48334505213847], +["1hyo",1.3,1.70754895627866], +["1tqs",1.3,1.52058769941316], +["1qx1",1.3,1.68845134130987], +["1hdh",1.3,1.65450159131730], +["1t6u",1.3,1.36665164277056], +["1r0m",1.3,1.93505114294234], +["1n61",1.3,1.89159843205425], +["1aac",1.31,0.865567791625972], +["1vmh",1.31,1.03819150164992], +["1gwu",1.31,1.64835306953442], +["1nyk",1.31,1.26496153246650], +["1ocn",1.31,1.27465653291537], +["1vf8",1.31,2.41723723609287], +["1snr",1.31,1.39038268794185], +["1kgd",1.31,1.73045737267180], +["2fgo",1.32,2.00441798936302], +["1hzc",1.32,1.70416906053066], +["2a13",1.32,1.26282715992725], +["1x3s",1.32,2.02022057321229], +["1mkk",1.32,1.46740466999038], +["1v9y",1.32,2.09227780655838], +["2aof",1.32,1.98632692217466], +["1z0j",1.32,1.20920863447034], +["1lzj",1.32,2.01071045954243], +["1e7l",1.32,1.39477866018890], +["1r9z",1.32,1.47738130347233], +["1rak",1.32,1.62620842553501], +["1q5m",1.32,2.06997233018044], +["1gxm",1.32,1.69262857083779], +["1plc",1.33,1.87830812017273], +["1wtm",1.33,1.8749584142765], +["193l",1.33,1.91206620123604], +["2cuo",1.33,1.43780955993837], +["1rtz",1.33,2.20893093160187], +["1o3d",1.33,1.70657386098195], +["2blq",1.33,1.32857119891821], +["2blo",1.33,1.38358211852796], +["2boq",1.33,1.48803420516156], +["1wx3",1.33,1.9143582798753], +["2etx",1.33,1.40936403153166], +["1kko",1.33,2.25895623966971], +["1o9i",1.33,1.16871151766509], +["1utg",1.34,2.60996425418831], +["2d01",1.34,2.08539212645161], +["1rmz",1.34,2.05290575130082], +["1vhu",1.34,1.62088113399071], +["5ptp",1.34,2.16905042258855], +["1ujp",1.34,1.56156240632248], +["2a3u",1.34,1.44108992528784], +["1vh5",1.34,1.78528751966192], +["1yph",1.34,1.34448404781155], +["1ubt",1.34,2.57038646464876], +["1ubr",1.34,2.52624421467092], +["1obx",1.35,1.77206268393728], +["1g2r",1.35,2.18519790809216], +["6fd1",1.35,1.46932485355558], +["1up9",1.35,2.51910025986045], +["1pz4",1.35,1.90401424638973], +["1sv3",1.35,2.56123418789152], +["1bqk",1.35,1.83793561970292], +["1e85",1.35,1.59870092217169], +["2lis",1.35,1.64891775072271], +["1vkk",1.35,1.53495442383163], +["1tzv",1.35,2.59194577195724], +["1sjw",1.35,1.60859688443426], +["1j8q",1.35,1.68132947910401], +["1gyy",1.35,1.6825900151067], +["1gyx",1.35,1.50837462940762], +["1pin",1.35,2.62309278315595], +["1gjn",1.35,1.37507223972059], +["1fd3",1.35,2.15183087137569], +["1rb0",1.35,2.48025035181979], +["1ky3",1.35,2.38952176849327], +["5p21",1.35,1.91312829962227], +["1oh4",1.35,1.73645829832731], +["1e5k",1.35,2.08508574776894], +["1ukf",1.35,1.83140097130132], +["2a8f",1.35,1.52128609985437], +["1yn3",1.35,2.27275593807195], +["1t7i",1.35,1.78356642334466], +["2bb9",1.35,1.86036381739819], +["1gpp",1.35,1.88456382481245], +["1u9c",1.35,1.49671535547859], +["1mqo",1.35,2.20945774711271], +["1kyp",1.35,1.33130025886175], +["1yjf",1.35,1.52100067711706], +["1kg5",1.35,1.40273712048686], +["2g3d",1.35,1.70859853258636], +["1eaj",1.35,1.35160039632186], +["1ijy",1.35,1.60273050859141], +["1mqi",1.35,1.51933751929543], +["1lzi",1.35,1.82865661270774], +["1lqk",1.35,1.77853510824512], +["1p2j",1.35,1.32148048462772], +["1ojr",1.35,1.8033812028389], +["1pb7",1.35,2.17425274569659], +["1zgk",1.35,1.24116922583546], +["2aqd",1.35,1.08051483436644], +["1si0",1.35,1.49278769386163], +["1qje",1.35,1.61679443217737], +["1p5b",1.35,2.17151687400591], +["1p4c",1.35,2.59473173442878], +["2fxu",1.35,1.59941983808445], +["1wu4",1.35,1.66524927672448], +["1lk2",1.35,1.90841535307283], +["2c1i",1.35,1.86197431311485], +["1bsm",1.35,2.57422027522426], +["1i0h",1.35,1.50087766301817], +["1wzd",1.35,1.58776999615562], +["1wdr",1.35,1.63655900939186], +["1e6q",1.35,1.69338529727121], +["1e6s",1.35,1.82188694082891], +["1rf2",1.35,1.90783248516139], +["1rdp",1.35,1.81482836140778], +["1pzk",1.35,1.86304194488961], +["1ylz",1.35,1.58402716028632], +["1w9m",1.35,1.36734341953741], +["1u1w",1.35,1.56896809219095], +["1m6z",1.35,1.7256767813214], +["1rw9",1.35,1.16929667733846], +["1vef",1.35,1.8448227345065], +["1ubh",1.35,2.27326670662521], +["1ubj",1.35,2.42371914991790], +["1ubo",1.35,2.56555231607208], +["1ubu",1.35,2.56986368973016], +["2c4j",1.35,1.06884740223163], +["1f1g",1.35,1.98729334938343], +["1wdd",1.35,1.99339323197735], +["1smm",1.36,2.13598466623908], +["2esk",1.36,1.65663173868790], +["1zir",1.36,2.16102439929978], +["1wbe",1.36,1.7525807621066], +["1qwh",1.36,1.36570277198769], +["1ly0",1.36,1.76381106519004], +["1c5s",1.36,1.98201290423208], +["2izg",1.36,1.90145387493749], +["2izh",1.36,1.89963915284317], +["1rhs",1.36,2.78223649392042], +["1qfv",1.36,1.95487803613415], +["1y2k",1.36,1.14317755243118], +["1vim",1.36,1.72201370768730], +["2akz",1.36,1.87442725707849], +["1lyv",1.36,1.52007237696544], +["1f1e",1.37,1.57189387852137], +["1jo0",1.37,2.10510665752642], +["1kug",1.37,2.18839295830119], +["1gi4",1.37,1.69192590168014], +["1c1t",1.37,1.7687250411733], +["1c1p",1.37,1.86087464710439], +["1c1q",1.37,1.85175425040422], +["1c1r",1.37,2.00015574099037], +["1c5u",1.37,1.73185825732248], +["1c5t",1.37,1.94428939576654], +["1thm",1.37,1.32534073835051], +["1xoz",1.37,1.93451835284753], +["1od1",1.37,1.12493551373993], +["1rgz",1.37,1.59713955647223], +["1ouw",1.37,1.57115123653376], +["1smw",1.38,1.82170486926010], +["1ryq",1.38,0.987143309462223], +["1nxb",1.38,4.88265733990703], +["1kqw",1.38,2.28381250653205], +["1mh1",1.38,2.31527091425206], +["1s9u",1.38,1.88891361769064], +["1gi2",1.38,1.42670371456121], +["1o2w",1.38,1.49130468072901], +["1o38",1.38,1.73785845953382], +["1fcz",1.38,1.21559888507671], +["1fd0",1.38,1.56433053428697], +["1gvo",1.38,1.69833628130498], +["1gvs",1.38,1.85677842856942], +["1gvr",1.38,2.53813007737249], +["1xmz",1.38,1.91920216170103], +["1hx0",1.38,1.36119734875835], +["1gve",1.38,1.63323794920894], +["1gt9",1.38,2.40165265330307], +["2rta",1.39,2.3459831896719], +["1sjy",1.39,2.24995920692453], +["2c3v",1.39,2.47933823378473], +["1i1j",1.39,1.66153186443122], +["1yiw",1.39,1.72364628753970], +["1ghz",1.39,1.58407263841247], +["2rtg",1.39,2.17074333031216], +["2rtq",1.39,2.62009499039319], +["2eur",1.39,1.61167511490235], +["1y9u",1.39,1.70061036133474], +["2cz1",1.39,1.48524652433476], +["1h2w",1.39,1.67166769691152], +["1pi4",1.39,1.77431043721752], +["1k55",1.39,1.91045554068293], +["1jkv",1.39,1.35212892292969], +["2bkx",1.4,1.79756790191154], +["1bx8",1.4,1.87972978006291], +["2bn1",1.4,1.53384494111768], +["2bn3",1.4,1.53534403581344], +["1rdg",1.4,1.90837528772572], +["1rpo",1.4,2.07032276012237], +["3ebx",1.4,2.76030140253537], +["1pfb",1.4,1.73944738984769], +["1t7e",1.4,2.16304231398302], +["1yu5",1.4,1.48467878270579], +["1ssh",1.4,1.36009343585484], +["1en2",1.4,2.06070833389558], +["2fq3",1.4,1.91645497925726], +["1awd",1.4,1.47710338760134], +["1ben",1.4,2.0130986856881], +["2brf",1.4,1.70874011034559], +["2axi",1.4,2.52903273827391], +["3vub",1.4,1.69334812776630], +["1eaz",1.4,2.14690746598971], +["6fdr",1.4,1.78993849332421], +["7fdr",1.4,1.77899669302802], +["1upd",1.4,2.36601012568652], +["1wr5",1.4,2.33930676534762], +["1vzm",1.4,1.89815555936543], +["1kr4",1.4,2.21827823613529], +["1ifr",1.4,2.10597836602365], +["1hh7",1.4,1.50345074197269], +["1v30",1.4,2.08834950755681], +["1h10",1.4,1.70083407595577], +["1pbj",1.4,1.82365832841302], +["1ti0",1.4,2.6153307714085], +["1faz",1.4,1.73510675339455], +["2ft7",1.4,1.34221942832611], +["1eic",1.4,2.87385913601185], +["1eid",1.4,3.02209253507272], +["2blp",1.4,1.56127664272786], +["2blz",1.4,1.56127664272786], +["1rpg",1.4,2.15116772567935], +["1eie",1.4,2.87968882082352], +["1fs3",1.4,2.98863434091818], +["2phy",1.4,2.13733715880682], +["1jzg",1.4,1.80350608100452], +["2blx",1.4,1.82840915464759], +["2bly",1.4,1.71531201053315], +["194l",1.4,2.09802719095095], +["2ihl",1.4,1.6771692242024], +["1qgv",1.4,3.1676708463551], +["1qyz",1.4,1.98550449202249], +["1iwv",1.4,1.15972768315702], +["1iwu",1.4,1.13654739134884], +["1iwx",1.4,1.40303593344921], +["1iww",1.4,1.41017695380371], +["1iwy",1.4,1.41017695380371], +["1jwr",1.4,1.62032512921698], +["1i5f",1.4,1.81144894557005], +["1d06",1.4,2.85331552182265], +["1ew0",1.4,2.72356008057571], +["1kv0",1.4,2.52791098552410], +["1lju",1.4,2.17034720423737], +["1hmt",1.4,1.98356622149809], +["1hms",1.4,2.40743499461737], +["1hmr",1.4,2.51800610171226], +["1gp0",1.4,2.09715438922813], +["1eco",1.4,1.96066475537647], +["1ecd",1.4,2.01564802847472], +["1eca",1.4,2.06433570197368], +["1ecn",1.4,2.07539456929158], +["1iju",1.4,2.88981122749416], +["1kjl",1.4,1.83722887973984], +["1w8t",1.4,1.33070801271431], +["1qk8",1.4,1.78489709436912], +["1i5g",1.4,1.7720671995536], +["1jl7",1.4,1.57474753435823], +["1jf3",1.4,1.69495537397310], +["1jl6",1.4,1.82466797038092], +["1jf4",1.4,1.88942670910065], +["2b06",1.4,1.80185584116044], +["1ng6",1.4,1.62019949997638], +["1f21",1.4,2.37694309456351], +["1dwt",1.4,1.49082000788559], +["2evk",1.4,1.77032735014190], +["1u7s",1.4,2.28106927389271], +["1bvd",1.4,2.15258612749832], +["1mbd",1.4,2.53305388392745], +["1dxd",1.4,1.93645376227506], +["1dxc",1.4,1.49585003577545], +["1h1x",1.4,1.81102460234834], +["1kqr",1.4,2.21081073610753], +["1ezg",1.4,1.66691001922694], +["1i73",1.4,2.61335931154033], +["1fw9",1.4,1.92321259289655], +["1rcf",1.4,1.39728351775106], +["1ye8",1.4,1.14390393410459], +["2ew0",1.4,2.03373090094436], +["1kt3",1.4,2.50096883192126], +["2f1s",1.4,1.69221652690499], +["1sxu",1.4,1.54349849934817], +["1erx",1.4,1.97316528503036], +["1d3s",1.4,2.29671886240527], +["1v7r",1.4,1.84558739646929], +["2fi1",1.4,1.12467703429404], +["2g7s",1.4,1.68097005311754], +["1svf",1.4,1.67246385817524], +["1q92",1.4,1.9707544611283], +["1sdv",1.4,1.34012933291082], +["2aod",1.4,1.29181240708576], +["2ftr",1.4,1.20309052581427], +["1y43",1.4,1.40110664405163], +["1he3",1.4,1.83614674455940], +["2aoi",1.4,1.74445386195335], +["1he4",1.4,1.38612718519104], +["2blu",1.4,1.27031527986808], +["2blr",1.4,1.29598424191759], +["1m1f",1.4,1.8281074504823], +["1k7j",1.4,1.79179657909759], +["1uyl",1.4,2.00107465239978], +["256b",1.4,2.2259830667706], +["2cxv",1.4,2.02916369916053], +["2cz2",1.4,1.66472964992213], +["1o03",1.4,1.71351184677636], +["1y5a",1.4,1.57901456601044], +["1s5s",1.4,1.12051371008626], +["1o3l",1.4,1.40087927031207], +["1n6x",1.4,1.42952652736676], +["1n6y",1.4,1.26096679624217], +["1c1n",1.4,1.96833789253348], +["1o3j",1.4,1.84970144839657], +["1c2h",1.4,1.84828923139091], +["1c2j",1.4,1.97607211348253], +["1c2m",1.4,2.06860138183404], +["1c1o",1.4,2.00383823662078], +["1tpp",1.4,2.01572517242329], +["1uu6",1.4,1.39290561113183], +["1muy",1.4,2.20999383820826], +["4eug",1.4,2.08321259019397], +["2b3p",1.4,1.85454126719416], +["1g8a",1.4,1.65935798082984], +["2fwq",1.4,1.84742423740956], +["2fsq",1.4,1.31360266134914], +["1zi8",1.4,1.93541785072966], +["1f7d",1.4,2.39561094807297], +["1sgp",1.4,2.31264299716278], +["1gg6",1.4,1.62193478289757], +["2any",1.4,1.39992678181963], +["1mk5",1.4,1.54305164001231], +["2rti",1.4,2.49674561240993], +["2izc",1.4,2.78155821565707], +["1haz",1.4,1.70268820380097], +["1jlt",1.4,1.92402637114023], +["1yc5",1.4,1.49402266694206], +["1s2o",1.4,1.85199989560143], +["1rjc",1.4,1.56391836997048], +["1eao",1.4,1.50347929523741], +["1qts",1.4,1.83768853914471], +["1oaf",1.4,2.01976242786500], +["1rl0",1.4,1.47160817816122], +["1ie9",1.4,1.99416774081233], +["1t7r",1.4,1.40759547557168], +["1uxz",1.4,1.61144008847037], +["1es5",1.4,2.10480287334098], +["1yt4",1.4,1.60375873689446], +["1uq5",1.4,1.70244209683332], +["1ypq",1.4,1.72731389211944], +["1u7i",1.4,1.62093468883229], +["1jy2",1.4,1.86566006622573], +["1st3",1.4,1.71401893825021], +["1svn",1.4,2.29511556329629], +["1ltz",1.4,2.20948914405870], +["2cit",1.4,1.43970815720984], +["1h8d",1.4,2.70045978302654], +["1x99",1.4,1.64404412688018], +["1mnn",1.4,1.81805586869954], +["1y20",1.4,1.90178677660527], +["3sdh",1.4,1.37013762931530], +["1ru1",1.4,2.14738708012062], +["2as3",1.4,1.22797075429227], +["2eup",1.4,1.68253134549964], +["1gcu",1.4,2.31677679563294], +["1obd",1.4,1.98228640483711], +["1u4g",1.4,2.0238388589267], +["2ctc",1.4,2.15649510732763], +["1y8a",1.4,1.78084961771730], +["1dry",1.4,1.69424945546212], +["1x96",1.4,2.193416026362], +["1x97",1.4,2.34217153580564], +["1q5y",1.4,1.98075242297286], +["1xgk",1.4,1.63258450994994], +["1qjf",1.4,1.59234875250624], +["1fo8",1.4,1.75912575132261], +["1w3v",1.4,1.45960410519550], +["1hb3",1.4,1.44785757862189], +["1v37",1.4,1.47520793283354], +["2b6d",1.4,2.71882854100638], +["1qnr",1.4,1.35038137438608], +["1fp2",1.4,2.01283444125494], +["1s0p",1.4,2.84695212947155], +["1q2q",1.4,1.58341102423548], +["1h91",1.4,2.28418768924702], +["1uww",1.4,1.47008402538034], +["1oki",1.4,1.71489283717295], +["1h61",1.4,2.31082958865869], +["2g84",1.4,1.53745303994328], +["1ga4",1.4,1.23116707129270], +["1kdz",1.4,1.72876953238106], +["1ga1",1.4,1.42516424294612], +["2a83",1.4,1.42457709121036], +["1u7g",1.4,2.487985455809], +["1m55",1.4,1.19446992387936], +["1r6x",1.4,2.03012044085681], +["1f8d",1.4,2.3022801164908], +["1d1z",1.4,1.86702037581046], +["1ql3",1.4,1.536020909291], +["1t5b",1.4,1.85318611669331], +["2bu3",1.4,2.03350143369345], +["2c78",1.4,1.43051507123612], +["1yuz",1.4,1.62520568795909], +["1f24",1.4,1.49946151535407], +["1f25",1.4,1.43441058927946], +["1f26",1.4,1.37409986639612], +["1oi6",1.4,1.38901467431279], +["1yrc",1.4,1.78872234212848], +["1g57",1.4,2.10800582107414], +["1t5k",1.4,1.55365048672119], +["1p1v",1.4,1.99915908267696], +["1ra5",1.4,2.35002297051007], +["1ks8",1.4,1.87064560343138], +["1ruk",1.4,2.06072404740599], +["1rup",1.4,2.03818276317362], +["2tnf",1.4,2.3229298240528], +["2bnu",1.4,2.65041253913919], +["1g67",1.4,1.89047531953863], +["1pwb",1.4,1.92995780020235], +["1l6r",1.4,1.56531539322146], +["1g6c",1.4,1.72624769984232], +["1kv7",1.4,2.22005735551145], +["1k0m",1.4,1.97676624162672], +["1tzp",1.4,1.53254338979571], +["1uay",1.4,1.61046837654651], +["1f0i",1.4,1.87530828272906], +["1ktn",1.4,1.81157093423404], +["1b16",1.4,1.61599414276937], +["1o98",1.4,1.57172327406281], +["2olb",1.4,2.28272916665567], +["1rkq",1.4,1.49003394729571], +["1q7l",1.4,1.21195308234761], +["1wb4",1.4,1.50093615081287], +["1gkl",1.4,1.54880297283413], +["1wb5",1.4,1.55505055688554], +["1iw0",1.4,1.71234606901389], +["1jub",1.4,2.12516289032451], +["1g5a",1.4,1.60560497708239], +["1w5q",1.4,1.61275435400991], +["1xyz",1.4,1.53562330844195], +["1o7n",1.4,2.13902154441397], +["1y2b",1.4,1.12099342581889], +["1k3i",1.4,1.74530565622648], +["1qop",1.4,1.68582666822095], +["1z44",1.4,1.63787076415541], +["1c1x",1.4,2.06543963239295], +["1qfm",1.4,1.3932143873193], +["1o6g",1.4,1.64457063501007], +["1odz",1.4,1.23949296683779], +["1o1h",1.4,1.78203293135473], +["1wuj",1.4,1.89044025405434], +["1ubm",1.4,2.32981125648684], +["1h2r",1.4,3.06365370062506], +["1f8n",1.4,1.63232440401708], +["1rmt",1.4,1.72454156333294], +["1ub3",1.4,1.80915847563076], +["1yge",1.4,1.99678277208949], +["1zgo",1.4,2.23929221602160], +["1y9z",1.4,1.93005865413160], +["1z5r",1.4,2.00249622495738], +["2dcy",1.4,1.68135503853889], +["1n13",1.4,1.57016918712357], +["1wbi",1.4,1.25350134156080], +["1m22",1.4,1.78028348702320], +["1sjm",1.4,1.34550771376486], +["1hty",1.4,1.97946020271439], +["1uzb",1.4,1.89639089136846], +["2bhq",1.4,1.62906606740261], +["2bjk",1.4,1.59994553731169], +["1llf",1.4,1.69060241096562], +["1gq1",1.4,1.52157595320391], +["1gk8",1.4,2.01602651025915], +["2f9s",1.4,1.35869286141469], +["1vju",1.4,1.99235381204794], +["1mb3",1.41,2.05555615399760], +["2bwq",1.41,2.06074273647319], +["2rtl",1.41,2.52055636889801], +["1xph",1.41,1.27056175249073], +["1o35",1.41,1.43949085709312], +["1o2u",1.41,1.61792027928482], +["2f46",1.41,1.15247360851151], +["1bxq",1.41,1.23454525984338], +["1tc1",1.41,2.07759201789995], +["1x9d",1.41,0.888356821163171], +["1xsz",1.41,1.53595312378535], +["1gkf",1.41,1.63118293035811], +["1qh4",1.41,2.18399824302094], +["1qlq",1.42,1.75537663948625], +["1tgr",1.42,1.5863751656851], +["2d02",1.42,2.05130854165332], +["1cxu",1.42,2.40207410077183], +["2aoh",1.42,2.16378232862146], +["1gi1",1.42,1.56054977839655], +["1gi0",1.42,1.71249109423966], +["2a6y",1.42,2.04117095501443], +["1k3w",1.42,1.94000420649122], +["2f22",1.42,1.28088745959626], +["1yii",1.42,1.98588774804487], +["1pkh",1.42,2.23603874598437], +["1nof",1.42,1.42694857181490], +["1v0u",1.42,1.77881671971172], +["1mxr",1.42,1.80176751453694], +["1pp0",1.42,2.24788411082517], +["1o04",1.42,1.35127181927366], +["1pz7",1.42,2.88629576737417], +["1smu",1.43,2.13828184332519], +["3msi",1.43,2.39758413056504], +["1v05",1.43,1.77608293713114], +["1b0b",1.43,1.42316530708231], +["1m0m",1.43,2.71784996348161], +["1o3k",1.43,1.46244443254587], +["1c5q",1.43,1.66551683856584], +["1c5p",1.43,1.92272461981611], +["3eug",1.43,2.01458364634842], +["2a49",1.43,1.3932143873193], +["1z89",1.43,1.84192167999394], +["1ur1",1.43,1.89950154291755], +["1rk6",1.43,1.81902256463585], +["1m7g",1.43,1.55252674559734], +["1g33",1.44,1.45771621863619], +["1k96",1.44,1.53758282688156], +["1j9e",1.44,1.42697090418121], +["2esq",1.44,1.97121121952506], +["1qx2",1.44,1.91992786308668], +["1zie",1.44,2.10005106319221], +["1kys",1.44,1.63040754916848], +["1gi3",1.44,1.80366757899508], +["1zdy",1.44,1.79305951279384], +["1r66",1.44,1.96780723608714], +["1rd9",1.44,1.77035438802846], +["1kb0",1.44,1.96569579654775], +["1gvd",1.45,1.48842924281568], +["1df4",1.45,2.21495037241498], +["1c8c",1.45,3.11523948160593], +["1yu8",1.45,1.71283444107630], +["1xyi",1.45,2.31004274687345], +["1os6",1.45,1.95075907115466], +["1i71",1.45,2.1943905972832], +["1aba",1.45,1.7427240842758], +["1nnx",1.45,1.91828915334538], +["1lri",1.45,1.79923018001534], +["4vub",1.45,1.85612672454009], +["1uku",1.45,1.42801205818901], +["1xaw",1.45,2.07381600940448], +["1n1x",1.45,1.94698426801474], +["1wlu",1.45,1.50148463466908], +["1xbi",1.45,2.07124168325650], +["1nko",1.45,2.65989328619833], +["1pko",1.45,1.79175761787813], +["1ymn",1.45,2.38158129773514], +["3rn3",1.45,2.77381971746578], +["1bgf",1.45,2.0331807130405], +["1z67",1.45,1.61481232875684], +["1pa7",1.45,1.24173568907608], +["1x2i",1.45,1.63996324670363], +["1is3",1.45,2.14168789032948], +["1eu5",1.45,1.89159391709174], +["2end",1.45,2.09488437319977], +["1w1g",1.45,2.31180258300099], +["1j3f",1.45,1.42423954958370], +["1dws",1.45,1.37616109569447], +["1dwr",1.45,1.39737307683254], +["1hzt",1.45,1.75370960649694], +["1v9q",1.45,1.46733953667969], +["1tmj",1.45,2.78121673587341], +["1uuy",1.45,1.87756325740464], +["2f3y",1.45,1.52165827856088], +["1lw9",1.45,2.04651858225932], +["1io0",1.45,1.98402268557557], +["1zgt",1.45,2.04709206131487], +["1t68",1.45,2.33277643391953], +["1di6",1.45,1.52925810008883], +["1u0x",1.45,1.41164787934679], +["1wl8",1.45,1.73794281556535], +["2b0a",1.45,1.66846143394418], +["2f80",1.45,1.95866070808498], +["1ybk",1.45,1.723049433527], +["1kuk",1.45,2.13219227606452], +["2dct",1.45,1.89841981300327], +["2erf",1.45,1.89241311126787], +["1wei",1.45,1.75238136093438], +["1c1k",1.45,2.22093551169505], +["1hlq",1.45,1.84576137719443], +["1fm0",1.45,1.17131244407209], +["1s6h",1.45,1.15251485789371], +["1o2r",1.45,1.25530059853486], +["1o37",1.45,1.75988723155216], +["1o2y",1.45,1.49372711943366], +["1q4a",1.45,1.82562935744153], +["1dlf",1.45,1.84484059763601], +["2f5t",1.45,1.87480662526709], +["1ji7",1.45,1.99611711155254], +["1sq2",1.45,1.59981949134777], +["1t8z",1.45,2.25532624501169], +["1thf",1.45,2.02460979977399], +["1vwk",1.45,2.79730447007849], +["1vwj",1.45,2.7001695017021], +["1vwl",1.45,2.65924123857588], +["1hf4",1.45,2.13302524679472], +["1pzp",1.45,2.10070363428185], +["1n7s",1.45,1.77367630271741], +["1qqf",1.45,2.13016580524515], +["1pb8",1.45,2.12214497574817], +["1si6",1.45,2.09289562104389], +["2d5x",1.45,1.68344758220163], +["1kw6",1.45,1.94539191883267], +["1kw3",1.45,2.06026088944101], +["2as6",1.45,1.11470047613342], +["2as2",1.45,1.10381999032223], +["2euu",1.45,1.45639214537279], +["2euo",1.45,1.48801040067668], +["2glz",1.45,1.08376893265742], +["1q0r",1.45,1.74336999639673], +["1ve1",1.45,1.94360467453238], +["1pa2",1.45,1.68947956679111], +["2cyg",1.45,1.53552019165385], +["1xlq",1.45,1.54276264239374], +["1e6u",1.45,2.01633408728202], +["1si1",1.45,1.43722658548690], +["1lzk",1.45,2.39832002033636], +["1blz",1.45,1.24347589429758], +["2fgq",1.45,2.30510064055241], +["1jbo",1.45,2.04870034285789], +["1tm5",1.45,1.47610798195458], +["1wua",1.45,1.5303905374289], +["1rcq",1.45,1.66502094520399], +["1r50",1.45,1.84390954921753], +["1qz5",1.45,1.68048977534321], +["1rl9",1.45,2.25632923717114], +["1yyd",1.45,1.70762664552710], +["1hz4",1.45,1.57864688316845], +["1lm4",1.45,1.75099040754504], +["1wu6",1.45,1.67755443848402], +["1x7q",1.45,1.96675988454588], +["2ado",1.45,1.58838915638802], +["1re9",1.45,1.97119720093386], +["1z72",1.45,1.40944968303279], +["1x1z",1.45,1.48583908269848], +["1idp",1.45,1.92208112477684], +["1q9r",1.45,2.13483112579547], +["2a53",1.45,2.07649351312892], +["2a54",1.45,2.28245203832335], +["1v4p",1.45,1.45622291416211], +["1wvq",1.45,1.80282020635108], +["1md2",1.45,1.84576125750746], +["1qh5",1.45,1.57331253419902], +["2d1t",1.45,1.55359639229021], +["1w5r",1.45,2.00326475113750], +["2d5z",1.45,1.37731037094025], +["1w1h",1.45,1.60040367196808], +["1ikp",1.45,1.86774515937340], +["1tzc",1.45,1.45571921970151], +["1xd3",1.45,1.6768961758347], +["1n82",1.45,1.73641225595978], +["1zkk",1.45,1.45858637554203], +["1w2p",1.45,1.82113069650406], +["2c0c",1.45,1.57373834196483], +["1urs",1.45,1.84301924218808], +["1u3w",1.45,1.87560264763971], +["1rwf",1.45,1.34998648952861], +["1gm7",1.45,1.66745142818426], +["1i88",1.45,1.54678280867328], +["2cvd",1.45,1.62118871577096], +["2bry",1.45,1.76726147949601], +["1goi",1.45,1.77576534940202], +["1j40",1.45,1.93686651469440], +["1j41",1.45,1.93316415391968], +["2a8y",1.45,2.15354517977755], +["1sqn",1.45,1.94000292196781], +["1vmg",1.46,1.46070445505607], +["2fb6",1.46,1.48754655544172], +["2iza",1.46,2.16495112166605], +["1vwg",1.46,2.78961145749978], +["2fbb",1.46,1.76098240684088], +["1w70",1.46,1.17083253218724], +["1kt5",1.46,2.4243994962266], +["1g3p",1.46,1.96973252355261], +["1gv9",1.46,2.01339927328158], +["1o33",1.46,1.41314979858164], +["1o2x",1.46,1.36414431826812], +["1tke",1.46,1.93632939390982], +["2fbr",1.46,1.78275678950233], +["1fx2",1.46,2.56091295712795], +["1v0h",1.46,1.38617334449621], +["1o82",1.46,1.52170552050053], +["1hnj",1.46,1.73902900435521], +["1w3x",1.46,1.55291823985697], +["1mzy",1.46,1.84276642015811], +["1r8s",1.46,1.65181398405524], +["1lc5",1.46,1.67023275666162], +["1c0k",1.46,1.93480649899025], +["1vmf",1.46,1.25131990662402], +["1sr7",1.46,2.26207425840994], +["1llr",1.46,1.96464187348855], +["1pzj",1.46,1.84467086592345], +["1gx4",1.46,1.72234517189828], +["1jig",1.46,3.15673727944649], +["2bff",1.46,1.7503149418124], +["1m5e",1.46,1.80878695698558], +["1mqd",1.46,1.84104074506653], +["1hj5",1.46,1.83205274903103], +["1kt4",1.46,2.7940969101227], +["1t6f",1.47,1.01975821333025], +["1seh",1.47,1.67996061688171], +["4gcr",1.47,2.28833881353838], +["1oqq",1.47,2.32574299710978], +["1m0l",1.47,2.56336034722292], +["1smo",1.47,1.74673346623574], +["1o2p",1.47,1.55956581261732], +["1c2i",1.47,1.82916993686883], +["1c5r",1.47,2.14096160255742], +["1fcx",1.47,1.41690603960168], +["2rtf",1.47,1.84870599385039], +["1uyx",1.47,1.75796087055738], +["1uyy",1.47,1.93484841427523], +["1c5l",1.47,2.34843448624209], +["7atj",1.47,1.70052944854033], +["1qbz",1.47,2.03737329297714], +["1rku",1.47,1.77172044848855], +["1n92",1.47,1.50354930537759], +["1pl4",1.47,1.7679690227706], +["1ju2",1.47,1.48001446705533], +["1yxl",1.48,2.16107471813282], +["2gcu",1.48,1.35230352881279], +["1g6u",1.48,1.76600784339323], +["1upq",1.48,2.28814584733864], +["1vm9",1.48,1.46037542811015], +["2fup",1.48,1.41415303309673], +["1vwh",1.48,2.70970516002659], +["1iwz",1.48,1.69300115562089], +["1b67",1.48,2.52246501936511], +["1ru2",1.48,2.19228217194702], +["2rn2",1.48,2.40917361194187], +["1ek0",1.48,2.4570683508426], +["1uca",1.48,1.56621950301605], +["1zd8",1.48,1.43794085634561], +["1c5v",1.48,2.18078003750224], +["1tky",1.48,1.89402851310146], +["1q4b",1.48,1.76172403856899], +["3seb",1.48,2.48282844737471], +["2izl",1.48,1.8946864638537], +["1vyo",1.48,1.59883427547532], +["1o4y",1.48,1.31631852071597], +["1wpu",1.48,1.99508928420497], +["1dzk",1.48,2.43496183941939], +["1kjv",1.48,1.80251972534981], +["1xh3",1.48,1.66015867145902], +["2bcm",1.48,1.49565209265057], +["1l7m",1.48,1.73193603438258], +["1rum",1.48,1.96898845190807], +["2bcg",1.48,1.58595227549839], +["1gqi",1.48,1.85812419053840], +["1s8n",1.48,2.17517745487149], +["1u06",1.49,1.12395340845155], +["1qkd",1.49,2.77761774651278], +["1vyk",1.49,1.59879183518964], +["1z1s",1.49,1.85722156942459], +["1xnb",1.49,1.79613781256541], +["1my7",1.49,2.52081980015805], +["1gi6",1.49,1.57011975380846], +["1uu4",1.49,1.30650507824861], +["1z0n",1.49,1.56629722029006], +["1ziz",1.49,1.96701922043249], +["2afy",1.49,1.1021716210976], +["1xso",1.49,1.72597981208752], +["8abp",1.49,2.04120957569575], +["1so7",1.49,1.96399128064942], +["1uzm",1.49,1.90352890934434], +["1q9q",1.49,2.46670106964204], +["1h2x",1.49,1.41452423744338], +["1pi5",1.49,1.79097779516431], +["1zni",1.5,2.30977119100115], +["1z21",1.5,1.37738463348181], +["1q9b",1.5,2.50339786390175], +["1crn",1.5,0.560238208041396], +["1yzm",1.5,0.876256448091225], +["6rxn",1.5,1.22578272278610], +["1czq",1.5,1.70390656864329], +["2c8r",1.5,1.05354587553636], +["1iu5",1.5,1.36458680161419], +["7rxn",1.5,1.49495346223472], +["1r0i",1.5,0.749128467091287], +["1fhh",1.5,2.46554815108236], +["1fhm",1.5,2.74214562328904], +["1b13",1.5,1.44993025229484], +["2ovo",1.5,2.01025428259828], +["4pti",1.5,1.79618908540810], +["1qke",1.5,2.53526886431974], +["1uoy",1.5,1.58480841217576], +["1yu7",1.5,1.08376893265742], +["1cka",1.5,1.70981366120493], +["1wto",1.5,2.25043473148254], +["1ff4",1.5,2.41489632537544], +["1t7a",1.5,2.47699368370277], +["1sna",1.5,2.11612113872254], +["1uti",1.5,2.29599775129418], +["1lr7",1.5,1.25494944654101], +["1wfb",1.5,1.29951666378088], +["1jek",1.5,1.63761593570596], +["1dp7",1.5,1.59237354166403], +["1edm",1.5,2.83725109996049], +["1uha",1.5,1.83229855171174], +["1eyt",1.5,2.41304159207715], +["1cyo",1.5,1.88650676662214], +["1ehd",1.5,1.90726455265316], +["1yd0",1.5,1.11400570230641], +["1g9o",1.5,1.78966141255443], +["6rlx",1.5,2.20990807619499], +["1n7e",1.5,1.90634747753116], +["1irq",1.5,2.29746503597214], +["4ins",1.5,2.05151684542592], +["3ins",1.5,2.13249209526141], +["1zeh",1.5,2.18706379200782], +["1urr",1.5,2.18380391906629], +["2plt",1.5,1.33043559461560], +["1ln4",1.5,2.21129194823932], +["3ezm",1.5,1.33223340495362], +["1td4",1.5,2.08986816883532], +["1qw2",1.5,1.68108796510788], +["5cyt",1.5,1.87787007286747], +["9rnt",1.5,1.42279032386873], +["2b4z",1.5,1.78475891170509], +["1o4r",1.5,2.11449420493155], +["1zmh",1.5,2.28334422483168], +["1o43",1.5,2.02342126803757], +["1o4a",1.5,2.471248031219], +["1sha",1.5,2.7020398862845], +["1wpa",1.5,1.96293894666794], +["4cpv",1.5,2.89051056645869], +["1kr7",1.5,1.39373645047941], +["1aap",1.5,2.16087871829141], +["1y9l",1.5,1.60724317020001], +["1kpf",1.5,2.03924120254921], +["1vyi",1.5,1.62914672334757], +["2mcm",1.5,1.46788694940810], +["1ccr",1.5,2.37067740200564], +["1noa",1.5,1.12296903239747], +["1t2j",1.5,2.30327642314492], +["1vc3",1.5,1.82173970337561], +["1e87",1.5,2.07268260573973], +["2bwk",1.5,1.52926121722068], +["1f7l",1.5,1.84244106314332], +["1poa",1.5,2.49385243731468], +["2b1f",1.5,1.89619585573923], +["2cyj",1.5,2.46300913657384], +["1sz8",1.5,1.97797215298141], +["1ux7",1.5,1.66398546759364], +["1l7l",1.5,0.796795141363517], +["1isu",1.5,2.10079186356436], +["1qto",1.5,2.23123853407347], +["1whi",1.5,1.95297604642708], +["2bni",1.5,1.78474323617262], +["1kmz",1.5,2.32885095031118], +["1pmy",1.5,2.37143283350467], +["1une",1.5,1.68384997795967], +["1rnd",1.5,1.88914953203437], +["1rnc",1.5,2.06833564477924], +["1ymr",1.5,2.97976061454186], +["1rhb",1.5,2.44573374533505], +["1izr",1.5,2.72542156157122], +["1ymw",1.5,3.02291248752284], +["2rat",1.5,1.6237039772836], +["3rat",1.5,1.93646518324454], +["4rat",1.5,1.77328429871254], +["6rat",1.5,1.86764442148437], +["8rat",1.5,2.09635721893686], +["5rat",1.5,2.21745621070731], +["1rat",1.5,1.97847752259260], +["7rat",1.5,2.26685732027904], +["9rat",1.5,2.49184299986796], +["1izp",1.5,2.60159582816215], +["1agi",1.5,2.38564366002544], +["1n0r",1.5,2.46523101336232], +["1tp6",1.5,1.70286544887419], +["1rie",1.5,1.29886518323491], +["1fgy",1.5,2.11474772173476], +["1vwr",1.5,2.73071301814918], +["1kll",1.5,2.32119260536943], +["1jzf",1.5,2.15256934907887], +["2c8o",1.5,1.83454104213145], +["1aki",1.5,1.99367875112413], +["1vau",1.5,1.65510195288185], +["1lzb",1.5,1.47214037380483], +["1vdq",1.5,1.51425387534426], +["2c8p",1.5,1.76049147659861], +["1lzr",1.5,1.37598125731938], +["1rex",1.5,1.89574365978199], +["1lz1",1.5,2.28872994790290], +["1sj1",1.5,2.54004506335836], +["1wvh",1.5,2.90135405760086], +["1lmi",1.5,2.54167585148031], +["1rxi",1.5,2.23432820222592], +["1g7n",1.5,1.58072391885418], +["1icm",1.5,2.24042996299410], +["1zbf",1.5,1.48158262975580], +["1zhv",1.5,1.92216798786459], +["1c1l",1.5,1.28908736659927], +["1h05",1.5,1.81499285032244], +["2g1u",1.5,1.26846621526389], +["2czs",1.5,2.60443814720445], +["1gz2",1.5,2.39830495461826], +["1lo7",1.5,2.55800066261161], +["2sns",1.5,4.89199339650865], +["1flp",1.5,2.06064015994567], +["1o7u",1.5,1.72703131882041], +["1o85",1.5,1.71126801920888], +["1ggz",1.5,2.26451936337564], +["1w1d",1.5,1.68759698208094], +["2hbg",1.5,2.36109262142681], +["1hbg",1.5,2.34946156111197], +["2g2c",1.5,1.23129584227082], +["1q1f",1.5,2.42867192044536], +["1x91",1.5,1.6477247790582], +["2eso",1.5,1.79773109159490], +["1wcu",1.5,1.62147245683751], +["1x46",1.5,1.39373645047941], +["1oal",1.5,1.36903323841399], +["1do1",1.5,1.09863426903849], +["1bvc",1.5,1.67561357425321], +["1mbc",1.5,2.94631669276424], +["1od6",1.5,1.79750131987165], +["2mbw",1.5,2.48823261886591], +["1abs",1.5,2.49863622157979], +["1roc",1.5,1.79115477721419], +["1wrm",1.5,2.15205459995816], +["1g1t",1.5,2.05197553565844], +["1f9h",1.5,1.26424394144677], +["1hka",1.5,2.40572041320838], +["1eqm",1.5,2.5633109578223], +["1t9p",1.5,2.71771514960754], +["2bzu",1.5,1.69864627453877], +["1d7p",1.5,2.47378216926399], +["1ntv",1.5,1.709923347328], +["1hd2",1.5,1.41685695193779], +["2fr2",1.5,1.91801357215462], +["2cfe",1.5,1.10158320221077], +["1qcz",1.5,1.4354508699512], +["1wmh",1.5,1.80030467252748], +["1p7s",1.5,1.89594328310030], +["1fl0",1.5,2.48703627489811], +["1zw6",1.5,1.52894201724263], +["1z6n",1.5,1.72213648555306], +["821p",1.5,2.37081760318568], +["1nwa",1.5,1.29354289942315], +["1llm",1.5,1.89634534859869], +["1koe",1.5,1.95787051602230], +["1v3w",1.5,2.49843390350389], +["1w2i",1.5,1.13651834013806], +["1ej0",1.5,1.93928328420091], +["1pee",1.5,1.74746582460936], +["2sga",1.5,1.94660376183022], +["1shu",1.5,1.23421354192129], +["1bte",1.5,1.54644903417071], +["1ep0",1.5,1.86364833407872], +["1np4",1.5,2.29164968084307], +["1ike",1.5,2.57240801106204], +["1z3e",1.5,1.52339609694582], +["2bvv",1.5,1.94551907689373], +["2b5h",1.5,1.66479869148543], +["2gh2",1.5,1.62259232812197], +["1tua",1.5,1.62325361962831], +["1hpg",1.5,1.78054184377236], +["1x82",1.5,1.54399844733057], +["1v2x",1.5,3.04050411261681], +["2fom",1.5,1.39140819540394], +["2bfq",1.5,1.43164957278976], +["1ui0",1.5,1.18763477746665], +["2coh",1.5,1.75395491958112], +["1na5",1.5,2.16508600356106], +["1xl2",1.5,1.89841885371358], +["1tal",1.5,1.95008671788684], +["2ull",1.5,3.36731709233585], +["1ocy",1.5,1.45346255968930], +["1j77",1.5,1.88192522106582], +["1iqq",1.5,1.96389755223128], +["1lyq",1.5,2.97860880429016], +["1omr",1.5,3.07839359607696], +["1sqe",1.5,1.99512592877964], +["1nn5",1.5,1.69572956250344], +["1m2a",1.5,2.43327229981025], +["1kui",1.5,2.07001181404677], +["2eng",1.5,1.4303535305236], +["1lfm",1.5,2.03926113992427], +["1k7k",1.5,2.05859822375937], +["1he5",1.5,1.52658216122979], +["2c79",1.5,1.84846022802190], +["1k49",1.5,2.12714135093293], +["2bt6",1.5,1.10071614337630], +["1nf9",1.5,1.82722948042356], +["1jr8",1.5,1.66755148249334], +["1km6",1.5,1.57175276974374], +["1klz",1.5,1.69981552631599], +["1km2",1.5,1.45169369640664], +["1km3",1.5,1.35612612864388], +["1km4",1.5,1.43674702111264], +["1kly",1.5,1.79292792310666], +["1km5",1.5,1.18435279544232], +["1byq",1.5,2.69605278513044], +["1qwx",1.5,1.9451822806493], +["1p3c",1.5,1.18363898939879], +["1jg4",1.5,1.44248809552219], +["1jg2",1.5,1.62330329126991], +["1v8e",1.5,1.90325638149939], +["1kgs",1.5,1.6780870852699], +["1jbz",1.5,1.91942469802821], +["1yj2",1.5,1.50620176081775], +["1oa4",1.5,1.6798695102626], +["1utm",1.5,1.24870197823162], +["1kyr",1.5,1.67473551279353], +["1qyf",1.5,1.69118101065175], +["1bty",1.5,1.56030466438153], +["1o2n",1.5,1.41063803640694], +["1o2v",1.5,1.53851031802729], +["1gj6",1.5,1.71439582432769], +["1xug",1.5,1.80936811702472], +["1o34",1.5,1.76052124872625], +["1o2q",1.5,1.65900659214968], +["1c2l",1.5,2.27832389945941], +["1o2i",1.5,1.87769803638076], +["1tld",1.5,2.47064892722777], +["1xui",1.5,2.05408792729046], +["1i1n",1.5,1.90370949555037], +["1kg7",1.5,1.4845798922332], +["1kg6",1.5,1.65510966509510], +["1tje",1.5,2.18059314446291], +["1tkg",1.5,2.48215380764019], +["1eeq",1.5,1.86966688742438], +["1z1q",1.5,1.69548776573283], +["1s6z",1.5,2.14912248498921], +["2eug",1.5,2.21614903679334], +["2asb",1.5,2.84131947867482], +["1bio",1.5,2.15469868955911], +["1oaq",1.5,1.57327511695533], +["1dyq",1.5,2.32632969580514], +["1yhh",1.5,1.13890720434526], +["1x9q",1.5,1.95179104961277], +["1jyk",1.5,2.28827271194227], +["1ggd",1.5,1.88796388527582], +["1s67",1.5,2.48903700890863], +["1zi9",1.5,1.48171275864848], +["1z3x",1.5,1.13271184780584], +["1qg8",1.5,2.22600531193236], +["1qgq",1.5,2.35675683768193], +["1qb7",1.5,1.78055439571345], +["1xrk",1.5,1.62555351801349], +["1l1g",1.5,1.71122008455246], +["1l0z",1.5,1.87185793864404], +["2ax6",1.5,1.93976378343596], +["1h9h",1.5,2.04165688320866], +["2rte",1.5,1.67509103203122], +["2rtb",1.5,2.67916250613755], +["2rtp",1.5,2.60434952078518], +["2rtc",1.5,2.71828518997386], +["1y5h",1.5,1.43606364559423], +["2c07",1.5,1.30228560684663], +["2erb",1.5,1.78267929165511], +["1n28",1.5,2.67373346082057], +["1z6s",1.5,2.05665137575154], +["1o0n",1.5,2.39595586663042], +["1o0m",1.5,2.24347907495414], +["1o0f",1.5,2.53336493620297], +["1zvh",1.5,1.98549666865647], +["2bsy",1.5,1.8727363925225], +["1o9g",1.5,1.91946695934582], +["1lv7",1.5,2.09711152625722], +["1yp0",1.5,2.61185504634113], +["1f9z",1.5,2.01404839260875], +["2btc",1.5,2.06889251791521], +["1r5l",1.5,2.15782138148219], +["1nq7",1.5,2.08563845655342], +["1hn4",1.5,2.29034107939033], +["1gj7",1.5,2.78382428753437], +["1vwi",1.5,2.86730254289146], +["2b0p",1.5,1.54027682187570], +["1rxf",1.5,1.95859689410854], +["1hjg",1.5,1.63673234676123], +["1xfp",1.5,1.52698206112438], +["1gs5",1.5,2.15781553921048], +["1b0u",1.5,2.29449364821872], +["2ax2",1.5,2.27013061791692], +["1ja9",1.5,1.66866142666755], +["1qqq",1.5,2.04030949255207], +["1j1m",1.5,1.42925641048090], +["1iq6",1.5,1.60623329505727], +["1rxg",1.5,1.41995035337406], +["1c9n",1.5,1.62013912052311], +["1vl7",1.5,1.52987820602814], +["1wsd",1.5,1.64716714402860], +["1st9",1.5,1.89688965712542], +["1nzj",1.5,1.45996220458216], +["2bod",1.5,1.32298820722102], +["1brt",1.5,1.52975277244179], +["1uo9",1.5,1.91289208476319], +["1jks",1.5,2.16472853789141], +["2prk",1.5,2.63633581391371], +["2pkc",1.5,2.50179180717951], +["1y1z",1.5,2.06008415309314], +["1b8o",1.5,2.47508387144829], +["1oh3",1.5,1.72636697295796], +["1egw",1.5,1.49412997560715], +["1y2t",1.5,1.56010817826374], +["2bv9",1.5,1.71637885807739], +["1unb",1.5,2.24821327349025], +["2av0",1.5,1.55882456944694], +["1szh",1.5,1.90184374755914], +["1q1a",1.5,2.20749728744051], +["1uv4",1.5,1.97228099679109], +["1bn7",1.5,1.58943748278979], +["1bn6",1.5,1.86454395853645], +["1c5n",1.5,2.27337060607210], +["1lc3",1.5,1.91277911465745], +["1jdr",1.5,1.80960654276448], +["1szd",1.5,1.65591372069970], +["1oc8",1.5,1.86437058961836], +["1cqw",1.5,2.07666423640401], +["1o81",1.5,2.14418431531940], +["1f9t",1.5,2.41582048806698], +["1us5",1.5,1.76204981118204], +["1ezm",1.5,1.95920341299566], +["1sh8",1.5,1.64404015497943], +["1bqc",1.5,1.91442536833460], +["1nzi",1.5,2.03995435660326], +["1e30",1.5,2.03230903320531], +["1elk",1.5,1.93998469958918], +["1mla",1.5,1.89258111130666], +["2b3l",1.5,2.10504324208932], +["2ctb",1.5,1.85848077380261], +["1j8u",1.5,1.59045370494732], +["1e7s",1.5,1.80209218164333], +["2f62",1.5,1.17387235779847], +["2a94",1.5,1.57952299316142], +["1cip",1.5,1.62143652416251], +["1svs",1.5,1.49454191802315], +["1ys2",1.5,1.06836571689135], +["1a2p",1.5,1.42091780415638], +["1k6x",1.5,2.10138403773056], +["1u8z",1.5,1.83337874901904], +["1gxn",1.5,1.28898378244636], +["2web",1.5,1.50967354195412], +["2wed",1.5,1.43212659519677], +["2wec",1.5,1.58590197534550], +["2arc",1.5,2.04955380798881], +["1i0r",1.5,1.62061270338986], +["1hy7",1.5,2.04555938607717], +["1qiq",1.5,1.3525317467129], +["1hb4",1.5,1.25185116793868], +["1fo9",1.5,1.60365026855270], +["1o3y",1.5,1.69116425723148], +["2bay",1.5,1.62342663037427], +["2bqz",1.5,2.44363150740537], +["2fgr",1.5,2.28753793115892], +["1jx6",1.5,2.16096068451163], +["2b65",1.5,2.66462452227763], +["1wx4",1.5,1.93193161944715], +["1lw6",1.5,1.32957706328648], +["1bx4",1.5,1.76709065704776], +["1qnp",1.5,1.25691666935419], +["1qns",1.5,1.55817166346572], +["1gd0",1.5,1.53345447843169], +["1v5i",1.5,1.70615493990343], +["1a2y",1.5,1.83343553731529], +["1mtp",1.5,1.64606406179673], +["1fg7",1.5,2.01114529453841], +["1g2q",1.5,2.02402935544107], +["1k9z",1.5,2.12362444596581], +["1m4i",1.5,2.08999937026803], +["1i6w",1.5,1.75671523085537], +["1w3u",1.5,1.95688245687455], +["1pvm",1.5,2.30045631946303], +["1uas",1.5,1.95924750027688], +["1h50",1.5,2.38647239593311], +["1oc6",1.5,1.53021974577333], +["1kq3",1.5,1.42684971976605], +["2f8a",1.5,0.974792372154106], +["1rh9",1.5,1.28478621955664], +["2a8k",1.5,1.88545397158346], +["1iom",1.5,1.35790179041191], +["1kpu",1.5,1.45867291128124], +["1xyo",1.5,1.84644026061296], +["1xyp",1.5,1.97106756961777], +["1enx",1.5,2.0083438015611], +["1g7p",1.5,1.82555291099340], +["1zhl",1.5,1.61059005230757], +["1i86",1.5,1.64787220954151], +["1ql4",1.5,1.64176780119316], +["2avv",1.5,2.33518524030459], +["1h32",1.5,2.51024879723162], +["1gut",1.5,1.73064079380827], +["1s1f",1.5,2.26455788473255], +["1gej",1.5,1.9752546747789], +["1yv1",1.5,1.68402309430121], +["1ofn",1.5,1.5741468761494], +["1ht6",1.5,1.61143426505847], +["1h14",1.5,1.39351541570334], +["2cz0",1.5,1.87332691649223], +["1p1m",1.5,2.03651623345793], +["2cz6",1.5,1.44168230827088], +["2fe6",1.5,2.1031337382578], +["2a35",1.5,1.83501332034386], +["1uuq",1.5,1.51333379072623], +["1iyb",1.5,1.69924303369127], +["1tu7",1.5,1.80143565686993], +["1j97",1.5,1.6198703946476], +["1n45",1.5,2.24752981967603], +["1g6s",1.5,1.55240479399027], +["1x8r",1.5,1.46737736053349], +["1rur",1.5,2.39802421309362], +["2aju",1.5,2.24638028816067], +["2ajv",1.5,1.87960917334743], +["1wme",1.5,1.50402612178986], +["1ks2",1.5,2.04844968804235], +["1qwo",1.5,1.60806454417289], +["1fmk",1.5,2.85536524854765], +["1zhx",1.5,1.64034109143059], +["1dfm",1.5,2.3584556658838], +["1k3l",1.5,2.21739360124804], +["1oyg",1.5,1.16189269475263], +["1kgc",1.5,2.01038072743143], +["2src",1.5,3.10090989198017], +["2bp6",1.5,1.64636764007159], +["1g69",1.5,1.80332963364836], +["1fj2",1.5,2.16330473880842], +["1j05",1.5,2.40266248122203], +["1sg0",1.5,1.92459402339064], +["1xi2",1.5,2.38134498229405], +["1pf3",1.5,1.81201771015949], +["1sqs",1.5,2.04066549106531], +["1qe3",1.5,2.19804372615073], +["1k38",1.5,2.20178642453487], +["1m7j",1.5,1.42997585572478], +["1sx5",1.5,2.27603398197902], +["1yn9",1.5,1.2665974780106], +["1m6k",1.5,1.72383085764842], +["1b4v",1.5,1.65191277158859], +["1e73",1.5,1.74278812271393], +["1e71",1.5,1.75745486672999], +["1ekq",1.5,2.18909905989217], +["1c4o",1.5,2.00391768050483], +["1nkg",1.5,1.66587858316578], +["1fr7",1.5,2.13310275747922], +["1jd0",1.5,1.53234054925651], +["1m6j",1.5,1.57743078385536], +["1uza",1.5,1.68509481329167], +["1u8t",1.5,2.69825425710411], +["1dj0",1.5,2.09269190712504], +["1j3w",1.5,1.58139596706590], +["1vqs",1.5,1.12542099846651], +["1gmw",1.5,2.79947677622342], +["1uxa",1.5,2.06199519757089], +["1gmu",1.5,2.09236456687431], +["1dqz",1.5,2.09335110517670], +["1u0k",1.5,1.60823544246464], +["1ybi",1.5,1.51234069894302], +["1y0p",1.5,1.95935888462251], +["1bz0",1.5,2.15737694618356], +["1thb",1.5,2.88051742421819], +["1qz0",1.5,1.95385720557229], +["1bab",1.5,2.19201255431668], +["1a4i",1.5,1.69740949842133], +["2bhy",1.5,1.55540237693832], +["2by3",1.5,1.60785761010370], +["2by2",1.5,1.57599370660941], +["1ofw",1.5,1.75623399821108], +["1y37",1.5,1.55267864385908], +["1x9h",1.5,1.75678433583500], +["1jl0",1.5,1.45455222812111], +["1ijq",1.5,2.40836365616362], +["1k20",1.5,1.46987067841786], +["1ofz",1.5,1.67367933472244], +["1e19",1.5,1.78827996640626], +["1iw1",1.5,1.62285942186545], +["2bmr",1.5,1.69821752046567], +["1l7a",1.5,2.36488145650004], +["1ukv",1.5,1.43838119823997], +["1f1u",1.5,1.59696274838588], +["1kfc",1.5,1.52233316498364], +["1luc",1.5,1.97839144679061], +["1tjp",1.5,1.58625274639299], +["1l8n",1.5,1.91261712351059], +["1h6r",1.5,1.71203291263093], +["1krh",1.5,2.09217851775537], +["1hzj",1.5,2.15163216593297], +["1ek6",1.5,2.13932190859687], +["1i3n",1.5,2.13444142940942], +["1i3m",1.5,2.20782630366883], +["1i3k",1.5,2.17894255611848], +["1i3l",1.5,2.24171090039030], +["1oc2",1.5,1.99285547138266], +["1w3h",1.5,2.12948257194446], +["1bw9",1.5,2.13532791011715], +["1l0g",1.5,1.70908708653624], +["1e8m",1.5,1.91890565848698], +["1e8n",1.5,1.50773995212524], +["2c54",1.5,2.02746461726554], +["1n7o",1.5,2.678428953093], +["2aml",1.5,1.22859800623277], +["2fnu",1.5,1.63396334654619], +["1rwg",1.5,1.34573206459538], +["1v5d",1.5,1.64575723825704], +["1oad",1.5,1.54240403493507], +["1v6s",1.5,1.50095310134588], +["1fr3",1.5,1.24886776601590], +["1v5v",1.5,1.51300009239648], +["1wul",1.5,2.18240252162104], +["2bwr",1.5,1.18859752106979], +["1j2w",1.5,1.66015619334226], +["2al1",1.5,2.03079958445212], +["1m2x",1.5,1.94116074430737], +["1wrv",1.5,2.21890021810125], +["1dvj",1.5,1.4862742352387], +["1cru",1.5,2.02136644773496], +["1o6v",1.5,2.19948727800435], +["2c3n",1.5,1.56577780794340], +["1r2r",1.5,1.49738676636623], +["1hxk",1.5,2.00939755729457], +["1nyt",1.5,1.62662648750888], +["1kdg",1.5,1.22892916178790], +["1uiw",1.5,1.50756691722300], +["1inl",1.5,1.87628815727532], +["1oa2",1.5,1.76330988626473], +["1t61",1.5,2.23718697047557], +["1orr",1.5,2.43171226823289], +["2bkl",1.5,1.35156193006832], +["1h41",1.5,1.73017849212614], +["2cdc",1.5,1.97685726564204], +["1cs1",1.5,2.64930974199678], +["1qs1",1.5,2.07584957216938], +["1dgf",1.5,1.87249295366729], +["1n5w",1.5,1.68725636393971], +["1h5q",1.5,1.95285951834493], +["1jz7",1.5,2.40141589907262], +["1jz8",1.5,2.21371138473577], +["1t60",1.5,2.53906607747803], +["2a5j",1.5,1.32225245665014], +["1ah7",1.5,2.2979481717632], +["1xb3",1.5,1.79605903039371], +["1zkp",1.5,1.84139878538471], +["1mg4",1.5,2.11066382973488], +["2bkv",1.5,1.97828144350146], +["1pyl",1.51,1.50838382566923], +["1vjk",1.51,0.733357640417026], +["1t1d",1.51,2.35895758835406], +["1yv4",1.51,2.05703656531373], +["1t00",1.51,2.18134873344536], +["1x6q",1.51,1.27563331765651], +["1gwl",1.51,1.46752578503479], +["1n6h",1.51,1.75660919894068], +["1qhv",1.51,1.67086262902592], +["1o3i",1.51,1.67657579750766], +["1df8",1.51,1.97633085967256], +["2d1e",1.51,1.93808156722081], +["1y1n",1.51,2.2878014013403], +["1ypy",1.51,2.03822261095183], +["1o7e",1.51,1.75173616216122], +["1xc1",1.51,2.91698570953122], +["1whz",1.52,1.86548271256585], +["1hq1",1.52,2.86055428359977], +["1vmj",1.52,1.31439644005994], +["2esp",1.52,1.65236420481328], +["1pqm",1.52,1.98154545321932], +["2fsr",1.52,2.05091678721883], +["2a2k",1.52,1.90654323383782], +["1p8h",1.52,3.1429466367652], +["1w2u",1.52,1.55383024252967], +["1x1t",1.52,1.58136086324787], +["1ie8",1.52,2.06054940910506], +["1li9",1.52,1.35153837665747], +["1w7b",1.52,1.95503959134565], +["1c4q",1.52,1.50569392622551], +["1rgy",1.52,1.76047318323858], +["1h46",1.52,1.62266545628338], +["2a6v",1.52,2.00759951813697], +["1qq5",1.52,1.90649361685358], +["1iv3",1.52,2.28747143179920], +["1lz8",1.53,1.91401696880525], +["1wvp",1.53,1.78899438198477], +["1s6s",1.53,1.96193326013307], +["1utk",1.53,1.78624891867531], +["1o3h",1.53,1.60005997139578], +["1rv9",1.53,2.05601913416956], +["1qq9",1.53,1.20986853229413], +["1jvp",1.53,2.59443896548949], +["1gvj",1.53,1.96908571473798], +["2auo",1.53,1.38692007884509], +["1s73",1.53,1.72090062047422], +["1t6c",1.53,1.94474064176561], +["1yme",1.53,2.47208215975522], +["1xvx",1.53,1.44673121308704], +["2eu9",1.53,1.51026755235801], +["1usg",1.53,1.58098588095573], +["1xil",1.53,1.96974779583111], +["1n9y",1.53,2.23603617553711], +["1v0t",1.53,1.81031670932192], +["1ohp",1.53,2.25745392021475], +["1ijh",1.53,2.01149983523739], +["1k4v",1.53,1.84295499094627], +["1l0d",1.53,1.63964412578666], +["1kvl",1.53,1.77822203213651], +["1lxk",1.53,2.98025856624242], +["1vkp",1.53,2.16123513772466], +["1urd",1.53,1.80150443481449], +["1h16",1.53,2.04153153053621], +["1lk9",1.53,1.91179024065323], +["1xg5",1.53,1.37470625597865], +["1vhf",1.54,1.65832288276373], +["5pal",1.54,1.84878154164050], +["1dlw",1.54,1.51228375404187], +["1tp5",1.54,2.19584074817794], +["1zia",1.54,2.1311488142105], +["1wu9",1.54,0.963446123839352], +["1s3d",1.54,1.65907723232509], +["1sk2",1.54,2.01980790243832], +["1l2h",1.54,2.2411339928173], +["1p6y",1.54,1.99764263939543], +["1n6p",1.54,1.68672341719475], +["121p",1.54,2.22956172155879], +["2bz1",1.54,1.73228804310161], +["2aoe",1.54,1.99006641461073], +["2b9a",1.54,1.85698431916723], +["2aiq",1.54,2.40078599347618], +["1z9t",1.54,1.49571812313431], +["1z6d",1.54,1.84341802641409], +["1qve",1.54,1.56766058273977], +["1yb6",1.54,1.59382508866606], +["2cba",1.54,1.71700746842007], +["2b49",1.54,1.65553656636153], +["1dyp",1.54,1.60313453339889], +["2aii",1.54,1.25610208683319], +["1tk2",1.54,2.56479576479376], +["1jtv",1.54,1.54847485340856], +["1vzq",1.54,1.43483015265842], +["2bc3",1.54,2.95213633983330], +["5cpa",1.54,3.07998283459754], +["1gvg",1.54,1.83252728261695], +["1dpt",1.54,1.52656053853301], +["1j6z",1.54,1.77441289256809], +["2b2h",1.54,2.42860085928947], +["1e5m",1.54,1.73296573249322], +["1szn",1.54,1.64947836502943], +["2bw8",1.54,1.51259120318193], +["3grs",1.54,2.29803141157413], +["1dl2",1.54,2.12200316009847], +["1xor",1.54,1.05355378648085], +["1ee2",1.54,1.80584053090843], +["1qv9",1.54,2.16057350453030], +["1vhw",1.54,1.77139807389543], +["2f8i",1.54,2.05295588735164], +["2b5a",1.54,1.10792356381412], +["3ovo",1.55,2.48544302595057], +["2f60",1.55,1.33748232850902], +["1l2p",1.55,1.64951138794945], +["2cc9",1.55,1.96884288844843], +["1hta",1.55,2.00427169381376], +["1dsl",1.55,2.13871587717668], +["1jyr",1.55,2.29010710483133], +["1loy",1.55,1.71957578264079], +["1lov",1.55,1.65967664890799], +["1o4g",1.55,2.66584996547191], +["1o48",1.55,2.40654670014222], +["1x6y",1.55,1.66075684115655], +["1paz",1.55,2.22635878845494], +["2bh4",1.55,1.70894129296729], +["2ft8",1.55,1.34398233955609], +["1moy",1.55,1.86052062556232], +["1a62",1.55,2.30594196130845], +["1lzy",1.55,2.19327662737442], +["1lit",1.55,2.47268246533338], +["1sl4",1.55,2.12474755264697], +["1sk1",1.55,1.92792522565479], +["1kjr",1.55,1.62661631553155], +["1qhq",1.55,1.83486476609899], +["1ej8",1.55,2.41764458531473], +["1w4s",1.55,1.51392938277418], +["1smb",1.55,1.27747330774937], +["2b0v",1.55,1.70822922590413], +["1nog",1.55,1.59003740642860], +["1jcv",1.55,1.28608714858358], +["1do3",1.55,1.20516546587147], +["1kbr",1.55,2.09762092282465], +["1sz7",1.55,2.05318540366799], +["1ra9",1.55,2.18570951620788], +["1xep",1.55,1.60096017868477], +["1p3n",1.55,1.93399214368109], +["2bv2",1.55,1.77858951663133], +["2c4w",1.55,2.87098685959115], +["1n6r",1.55,1.96707104852305], +["1n6k",1.55,1.74221073891511], +["1d2s",1.55,2.31462239039314], +["1na3",1.55,1.60348861869024], +["2f9l",1.55,2.38337722527519], +["1tgx",1.55,1.49250057435209], +["1p9h",1.55,1.55918232598309], +["1c5h",1.55,1.83501336936142], +["1pmj",1.55,1.59883195122923], +["1yna",1.55,1.95305632917799], +["1z0c",1.55,2.41351972428198], +["1k1u",1.55,2.18465945688718], +["1z0b",1.55,2.11035733434975], +["1ix2",1.55,2.07248103399272], +["1daz",1.55,2.09508549701792], +["1qrf",1.55,1.92578905245606], +["1nn3",1.55,1.64736805486791], +["1inj",1.55,1.80245105233884], +["1sfx",1.55,1.24470772525520], +["2a4o",1.55,1.64920749829704], +["1vl1",1.55,1.28629378562498], +["1c3w",1.55,2.57654839389493], +["1os8",1.55,1.57209074217436], +["1o30",1.55,1.59825711330887], +["1o3n",1.55,1.77184078417632], +["1o3m",1.55,1.79576684593190], +["1o3f",1.55,1.8100106542883], +["1o3g",1.55,1.8100106542883], +["2ptn",1.55,1.97296343391007], +["1o3o",1.55,2.02212150261481], +["1try",1.55,1.75355422176798], +["1kg3",1.55,1.87429076639559], +["1q4c",1.55,1.92727993858550], +["1x7s",1.55,1.26140564790974], +["2dlf",1.55,1.93801331122752], +["1tlu",1.55,1.88573885517523], +["1deo",1.55,1.6226635274089], +["1l8s",1.55,2.84484473539721], +["1zk2",1.55,1.42240713703218], +["1zk0",1.55,1.54896601127711], +["1es2",1.55,2.28216893024316], +["2b13",1.55,2.09998051754938], +["1r82",1.55,2.04862124491906], +["1xz6",1.55,2.25542289247473], +["1wt1",1.55,2.25494665268527], +["1zi5",1.55,1.99624106771770], +["1zg4",1.55,2.02860996810640], +["1f7z",1.55,1.70342598238851], +["2czl",1.55,1.54967641147900], +["1y1j",1.55,1.15152618169842], +["2a84",1.55,1.24441959327144], +["2aij",1.55,1.46510866386327], +["1egq",1.55,2.39883155944366], +["1qum",1.55,2.22035214119440], +["1tzt",1.55,2.31212037424306], +["1j34",1.55,2.02802391818378], +["1iwh",1.55,2.31951885645167], +["2evg",1.55,1.31530558957645], +["2as1",1.55,1.10484959772542], +["2eus",1.55,1.55026725756106], +["2ghs",1.55,1.25927400973762], +["2f71",1.55,1.87069313088863], +["1ute",1.55,2.59404307606471], +["2b3k",1.55,1.80768449373719], +["1w4w",1.55,1.52045182692402], +["1y7l",1.55,1.70483667419004], +["1u8y",1.55,1.80987853062540], +["1tca",1.55,1.27437213458513], +["1u11",1.55,1.74758947253319], +["1oz2",1.55,1.87237371626760], +["2fp1",1.55,1.43974462731671], +["1hb1",1.55,1.33733344740886], +["1ghe",1.55,2.17068548337378], +["1y34",1.55,1.41188125346388], +["1r5m",1.55,1.67604827296669], +["2b9h",1.55,1.70325581635052], +["1zkj",1.55,1.84703463393361], +["1uqz",1.55,1.51187578227233], +["1z8g",1.55,1.37229804250608], +["1xnk",1.55,1.90706992995367], +["1g58",1.55,2.21260888883350], +["1gw9",1.55,1.67504909322865], +["1ioo",1.55,1.79824606150128], +["1wl4",1.55,2.071235675002], +["1bs3",1.55,2.05671509309314], +["1avm",1.55,2.34945532530875], +["2cyz",1.55,1.53512112265041], +["1qmq",1.55,2.18031342693342], +["1gtv",1.55,1.74720972084842], +["2f8y",1.55,2.32196812707915], +["1x8v",1.55,1.90314315965201], +["1ozw",1.55,1.93004929894887], +["2aay",1.55,1.58425676641931], +["1ksc",1.55,1.94002280839121], +["2a6x",1.55,2.02581111582493], +["1snn",1.55,2.06198692350113], +["2ddd",1.55,1.85973198981856], +["2ddc",1.55,2.11461737548736], +["1g4t",1.55,1.80799341919374], +["1nth",1.55,1.72844274083536], +["1nc7",1.55,1.89380699471779], +["2f6u",1.55,1.95445678636115], +["1y07",1.55,2.04464758631599], +["1zr6",1.55,2.05607032136293], +["2bem",1.55,1.54154190407513], +["1m1p",1.55,1.92790415386056], +["2foy",1.55,1.8820235566517], +["1xoc",1.55,1.94767531265164], +["1y4w",1.55,1.58747143084213], +["1jcz",1.55,1.65931947159702], +["1edq",1.55,1.37725176736800], +["1oa1",1.55,1.23473040825672], +["1shh",1.55,2.34883038672725], +["1jke",1.55,2.23673984277167], +["2by1",1.55,1.63067072922038], +["2by0",1.55,1.56975408656631], +["1t1u",1.55,3.25980782128363], +["1to4",1.55,1.37013762931530], +["1w6g",1.55,1.45043366421777], +["2c2n",1.55,1.65540815934723], +["2bmq",1.55,1.60106141269277], +["1wbh",1.55,2.00789767536166], +["2c0a",1.55,2.05753395699981], +["1w5p",1.55,1.74135824118178], +["1yu6",1.55,1.73316149888473], +["1xom",1.55,1.28513787490727], +["1ugi",1.55,2.40634917266893], +["1wtj",1.55,1.77639193344294], +["1w2v",1.55,2.12045966268389], +["1mg7",1.55,1.65491320106403], +["1kq1",1.55,2.3390782384688], +["1n7n",1.55,2.33569459898184], +["1n7p",1.55,2.50288285518385], +["1elu",1.55,2.0269081632316], +["4ubp",1.55,1.85742170441146], +["2a1o",1.55,1.93061721295427], +["1d5n",1.55,2.31860075074198], +["1qqj",1.55,1.69566660715043], +["1yiz",1.55,3.56121447729987], +["1ejd",1.55,1.77983580358966], +["1u6k",1.55,2.14005148070598], +["1iv4",1.55,2.43423190411821], +["1iv2",1.55,2.5337139823461], +["1zds",1.55,1.660159709037], +["1f0l",1.55,1.95467321070961], +["1xu9",1.55,1.81523112838224], +["1j3y",1.55,1.92923966054493], +["1wmw",1.55,1.70284290580585], +["1evl",1.55,2.17881400894364], +["1mv8",1.55,1.98216516800431], +["1jyw",1.55,2.32061346181164], +["1onj",1.56,2.15186087444985], +["2bkf",1.56,1.58706301615934], +["1eyh",1.56,1.62930108414611], +["1rao",1.56,1.77358745101983], +["1u53",1.56,1.64454367226485], +["1vb6",1.56,1.99844358605586], +["1lo6",1.56,1.56098947594505], +["2rth",1.56,2.61438324978579], +["1gja",1.56,2.40752489519625], +["2euz",1.56,1.18123688598068], +["2evf",1.56,1.19774120003366], +["2bju",1.56,2.28571060192831], +["1w9e",1.56,1.86739892204383], +["1y1k",1.56,1.44212006001689], +["1sxr",1.56,1.75512342427415], +["1yu0",1.56,1.27184142588832], +["1bq6",1.56,2.07838213569510], +["1bi5",1.56,1.84051738491581], +["1oo2",1.56,2.64575366274825], +["1gkb",1.56,1.79941730579986], +["1vke",1.56,1.55293688172020], +["2afw",1.56,1.94362904808690], +["1egu",1.56,2.74948304690102], +["1gdv",1.57,3.45536459463372], +["1o4k",1.57,1.69184177682552], +["2ai4",1.57,2.06324913297309], +["2a0b",1.57,1.66013600134391], +["2d0n",1.57,2.52524788361310], +["1dk8",1.57,1.80630481799810], +["1p37",1.57,1.87579040746680], +["1pqi",1.57,2.63654965617906], +["2fx6",1.57,1.93815484599588], +["1akz",1.57,1.52744797657407], +["1m65",1.57,1.77442260054196], +["2f9h",1.57,2.48201026897465], +["2ize",1.57,2.58600994597147], +["1zi1",1.57,2.27932600045145], +["1xbb",1.57,1.62808835048124], +["1jov",1.57,2.3567338668345], +["2eux",1.57,1.37203656112282], +["1a3h",1.57,1.39495365961133], +["1hch",1.57,1.56816881375074], +["1via",1.57,1.73110892299375], +["1tm3",1.57,1.57145613356012], +["1moq",1.57,1.75295374635965], +["1r9y",1.57,1.53368767782385], +["1a8d",1.57,2.81384043836579], +["1zed",1.57,2.25271141798869], +["1lyc",1.57,2.38050765782592], +["2bme",1.57,2.08249611597917], +["1x7y",1.57,1.83582544099759], +["1r45",1.57,2.14487445716474], +["1zz1",1.57,2.04481524036962], +["1p1r",1.57,1.32965153425092], +["1gv5",1.58,1.29755922376388], +["1wn9",1.58,1.89087911599636], +["1wna",1.58,1.78425750507963], +["2d2y",1.58,1.10381999032223], +["1akr",1.58,2.24411599170478], +["1wwi",1.58,1.82345344415803], +["1p2r",1.58,2.03100056377204], +["1p2l",1.58,2.0661417629852], +["1awq",1.58,2.92488387675222], +["2fdd",1.58,1.66543680350608], +["1r55",1.58,1.77490442978456], +["1fma",1.58,1.94368834818542], +["1q4d",1.58,1.87505159472268], +["2bzg",1.58,1.83669992081437], +["2izf",1.58,1.96257236263942], +["2rto",1.58,2.65407958712606], +["1cp7",1.58,1.40024142154682], +["2fi4",1.58,1.50350524811421], +["2fi5",1.58,1.46070445505607], +["2fi3",1.58,1.35440920650854], +["1o2g",1.58,2.47141167136010], +["1iz7",1.58,2.34383364032138], +["1mkr",1.58,1.63779376625500], +["1vrm",1.58,1.37670448115907], +["2aex",1.58,1.9037150263512], +["1y5w",1.58,1.81427311208400], +["1y5v",1.58,2.01189256008341], +["1xs0",1.58,3.22378366569906], +["1wyc",1.58,1.30413027005814], +["1r9x",1.58,1.5246045147381], +["1xby",1.58,1.52366910555320], +["1skb",1.58,1.53902256569328], +["1xta",1.58,2.19648990966497], +["1ys7",1.58,2.30128192739639], +["1awr",1.58,3.23553287745370], +["1ms9",1.58,1.87220679605304], +["1sd8",1.59,1.39353309840975], +["1v7q",1.59,2.10265120980605], +["1nox",1.59,1.15886214676781], +["1w0h",1.59,1.24521838998529], +["1o39",1.59,1.83136038562675], +["1dpo",1.59,2.21703176971154], +["1exa",1.59,1.45532091710073], +["1zjp",1.59,2.04400387999251], +["2a8w",1.59,1.66746973098892], +["1wsz",1.59,2.34259453698034], +["1zhj",1.59,1.9280126010656], +["1vhn",1.59,1.2542260097421], +["1r9l",1.59,1.15155308392864], +["1mrq",1.59,1.47845094973459], +["1tm7",1.59,1.56283482131185], +["1ye3",1.59,1.75707104650430], +["1vio",1.59,1.69512034457173], +["1g6i",1.59,2.22808292685078], +["2cdp",1.59,1.83330894358733], +["1bzz",1.59,2.16071404035292], +["1bz1",1.59,2.16448021864545], +["1vht",1.59,1.79916758946966], +["1e2r",1.59,1.85965227393822], +["1uz9",1.6,1.91520612434112], +["1guu",1.6,2.03050230281608], +["1r0f",1.6,1.10001494247582], +["1r0g",1.6,1.10001494247582], +["1b2j",1.6,1.44993025229484], +["1knt",1.6,1.74613461713696], +["7pti",1.6,2.23778836259604], +["1ywp",1.6,1.39514264858437], +["1bf4",1.6,2.55883160502038], +["2ccn",1.6,2.18159025934967], +["1wtv",1.6,2.55954610605356], +["2jia",1.6,1.76351716963550], +["5msi",1.6,2.04158875628788], +["4msi",1.6,2.08103695627454], +["1azp",1.6,2.68290139870508], +["1qr9",1.6,2.985360919793], +["4icb",1.6,2.14200865180091], +["1vcc",1.6,2.44927639198712], +["1wm2",1.6,2.18197892624698], +["1u84",1.6,1.70721885830266], +["451c",1.6,2.52878450662783], +["351c",1.6,2.55980467581949], +["2d3d",1.6,0.93328709288676], +["1cm3",1.6,2.62753480695483], +["1a1i",1.6,1.58346764511443], +["1a1h",1.6,2.14405068954253], +["1ptf",1.6,1.55362102394918], +["1gvp",1.6,2.36262988662412], +["1yd3",1.6,0.710612278866998], +["1yd2",1.6,0.849014163991869], +["2ygs",1.6,1.66479943582727], +["1s29",1.6,1.49471512935257], +["1box",1.6,2.03616642318518], +["1trz",1.6,2.63705659260653], +["1zeg",1.6,1.60297615805569], +["1iuz",1.6,1.52798938897273], +["1pnc",1.6,1.36629807285837], +["1pnd",1.6,1.58958561674672], +["2b9d",1.6,3.00319055843819], +["3cao",1.6,2.07217490861756], +["1o4m",1.6,2.10672434049768], +["1o4n",1.6,2.73054757918595], +["1mfw",1.6,2.26110427885804], +["1x0t",1.6,2.07575400362457], +["1co6",1.6,2.55267090172236], +["1bkf",1.6,2.60473748031395], +["3cyr",1.6,1.57195839535836], +["1cdp",1.6,2.27395324200172], +["5cpv",1.6,2.45607999011156], +["1jer",1.6,3.19113203514532], +["1hxi",1.6,1.59506985098890], +["1aal",1.6,2.53693152785298], +["1efq",1.6,2.41464519012652], +["2rhe",1.6,2.88900698237049], +["2rns",1.6,1.84354794283337], +["1rnu",1.6,1.81186273437662], +["1rnv",1.6,1.99210212307472], +["1mav",1.6,2.13546431989609], +["4bp2",1.6,2.24228726817370], +["1zv1",1.6,1.84521819656283], +["1xte",1.6,2.37086956338156], +["2bez",1.6,1.70154206623123], +["1r5r",1.6,2.16232652020669], +["2awg",1.6,1.53140677776176], +["2b29",1.6,2.54569068400457], +["1mvo",1.6,1.54670136539847], +["1q7a",1.6,2.68683210564989], +["1kp4",1.6,2.01334242593571], +["1mg6",1.6,2.28210666622295], +["8paz",1.6,2.66025843271187], +["1m5t",1.6,1.5996023464138], +["1vkq",1.6,1.80709444995421], +["1cxc",1.6,2.64042192567949], +["1bqr",1.6,2.10717205700329], +["4fgf",1.6,2.47246607620951], +["1a5p",1.6,2.75650047618905], +["4rsd",1.6,2.31197404033949], +["1bel",1.6,2.27962548275017], +["3rsd",1.6,2.10569375451834], +["1rob",1.6,2.67489281289896], +["2asf",1.6,1.41856368636724], +["1s1z",1.6,2.19198770689124], +["1s1y",1.6,2.19281519491407], +["1ts0",1.6,2.0229887396638], +["1ts6",1.6,2.0229887396638], +["1t1a",1.6,2.55401670283286], +["1uxx",1.6,2.14362631878645], +["1t1b",1.6,2.80544297666727], +["1bfg",1.6,2.52210755675276], +["1vwm",1.6,2.84376130516231], +["1j3a",1.6,1.71045456630589], +["1jb3",1.6,2.87464519863880], +["1jze",1.6,2.95021945836169], +["1b8z",1.6,1.54400757765036], +["1cuo",1.6,1.50751517707139], +["1vat",1.6,1.58640279607998], +["1t3p",1.6,1.80254788590588], +["1lza",1.6,1.8842797885605], +["1vds",1.6,1.90734742186622], +["1yil",1.6,1.94402480798565], +["1lmq",1.6,2.43561873029804], +["3nul",1.6,1.23116707129270], +["1lid",1.6,1.49652290452906], +["1lif",1.6,1.66559009790992], +["1lie",1.6,1.78833748311822], +["1adl",1.6,1.69451178642336], +["1lic",1.6,1.88311908737388], +["1kuh",1.6,1.51929323683653], +["1eqt",1.6,2.44279939773782], +["1b3a",1.6,1.8514159763657], +["1o8v",1.6,1.48248416028729], +["1zzo",1.6,1.94484551973129], +["1wld",1.6,1.78384039954119], +["1r62",1.6,1.59591882318975], +["1c1f",1.6,1.78272990888042], +["1hi2",1.6,2.31998529832511], +["1lmt",1.6,2.41808650760824], +["1ey4",1.6,2.99969699003624], +["1ey0",1.6,2.86078414525568], +["1tvg",1.6,2.30274819947755], +["2b3g",1.6,1.73391970865013], +["5nul",1.6,1.82573500955616], +["1wqj",1.6,1.82843459313948], +["1x6o",1.6,1.38583747707700], +["1tzw",1.6,2.18689834000678], +["1ugx",1.6,1.01118522348699], +["1id0",1.6,2.75267762896691], +["1mba",1.6,2.19524105131249], +["2fl4",1.6,2.01130422453855], +["2c8s",1.6,2.5556139101954], +["2eve",1.6,1.37791878349091], +["1jxb",1.6,2.27325184123161], +["1nz3",1.6,2.55749440301035], +["1mbo",1.6,2.51344336808504], +["1mz0",1.6,1.44062284630109], +["1n9i",1.6,1.66131517224048], +["1n9x",1.6,1.40506279437438], +["1myz",1.6,1.59026408251352], +["1co9",1.6,2.11255783902314], +["1cio",1.6,2.29869782483297], +["1ufj",1.6,1.87430167177552], +["1fcs",1.6,2.97768344515894], +["1md6",1.6,1.89305406796919], +["1y4m",1.6,2.64255863251875], +["1ie0",1.6,1.7012353220181], +["1c09",1.6,1.45210753940750], +["2ilk",1.6,2.72348279191790], +["2ewr",1.6,1.17135862953214], +["1znd",1.6,2.63641115357099], +["1znk",1.6,2.67894620133244], +["1zng",1.6,2.70580308945867], +["1ra2",1.6,2.07967939004603], +["2f3z",1.6,1.87563848116301], +["1uux",1.6,1.71168202595643], +["1wc9",1.6,2.09508478666015], +["1jhj",1.6,1.87575264743813], +["1a3c",1.6,2.51533188476136], +["1vdn",1.6,2.21447367991053], +["1yb3",1.6,1.34150405164562], +["1qra",1.6,2.20242595587501], +["1g12",1.6,1.71413550594073], +["1h96",1.6,1.19861545277446], +["1n6i",1.6,1.67187967414645], +["1n6n",1.6,1.73832926713060], +["1n6l",1.6,1.69784013248411], +["1tyj",1.6,2.27383344098495], +["1g8q",1.6,2.65528950257657], +["1rfy",1.6,1.42297049061579], +["1y0u",1.6,1.14146444655127], +["1mr3",1.6,2.05320379312463], +["1yw5",1.6,1.77653458247659], +["1dj7",1.6,2.06386376946698], +["1ky2",1.6,2.34910407725616], +["1k4n",1.6,2.37328151161748], +["1di7",1.6,2.09407856872058], +["1eqd",1.6,2.75784855696197], +["1t1v",1.6,2.19439747885426], +["154l",1.6,2.25975153593500], +["153l",1.6,2.18714160974698], +["1hv0",1.6,1.90798637336413], +["1xnc",1.6,1.90705974162838], +["1sk7",1.6,2.33015755890175], +["1ps4",1.6,1.55826372683329], +["1q2u",1.6,1.55826372683329], +["2cve",1.6,1.86221408180509], +["1j1g",1.6,1.70149527113093], +["2ap3",1.6,1.28562173741326], +["2sfa",1.6,2.56445407357899], +["1j1f",1.6,1.68051647711875], +["1wt6",1.6,2.53310231587635], +["1fvg",1.6,2.22028756806022], +["1q91",1.6,1.8138617899776], +["1ru0",1.6,1.69156316019166], +["1rki",1.6,2.15171532177467], +["1cuj",1.6,2.10954877492446], +["1y0h",1.6,1.74420983167054], +["1qrx",1.6,1.87193050961436], +["1jxg",1.6,1.78606291708930], +["1ylx",1.6,1.70150504818116], +["2c0z",1.6,1.54937923188180], +["1umj",1.6,1.90728902518044], +["1fi2",1.6,1.79276817120544], +["2et1",1.6,1.84661533385934], +["1w3o",1.6,2.07589534795052], +["1iuj",1.6,2.75559228854507], +["1j2j",1.6,1.43350403075619], +["2aoj",1.6,2.3580898997544], +["1nf8",1.6,1.44190881571855], +["1gsi",1.6,1.67644592326456], +["1lor",1.6,1.64817081371208], +["1nmy",1.6,1.46381369910601], +["1nn0",1.6,2.32335393381607], +["1e9a",1.6,1.63624226891388], +["1e9c",1.6,2.25588312097266], +["1e2f",1.6,2.14650979801602], +["2gim",1.6,2.16541346804499], +["1e9e",1.6,1.66846624569051], +["1pew",1.6,2.87237755601], +["1ro2",1.6,2.97402589154613], +["1ft5",1.6,2.70885666475199], +["1ppn",1.6,2.67564161429896], +["1nln",1.6,2.21092862682463], +["1fr2",1.6,1.85715509100140], +["1rz2",1.6,2.39287342100013], +["1khq",1.6,1.69034752843881], +["2ayh",1.6,2.20369971292043], +["1t92",1.6,1.84322835897397], +["2brc",1.6,1.59352507931992], +["1f2a",1.6,1.62890537900696], +["2byi",1.6,1.81376416851831], +["1k4l",1.6,2.44730895760269], +["1fqt",1.6,1.64373196322927], +["1zin",1.6,2.01120329225392], +["1ii5",1.6,1.91938949779172], +["1x7t",1.6,1.49642474108066], +["1rc9",1.6,1.49623824757158], +["2evr",1.6,1.09760627022802], +["2f7i",1.6,1.65519887537325], +["1y3v",1.6,1.43608777996396], +["1y5u",1.6,1.78377320030775], +["1fni",1.6,2.51275224755879], +["1gi5",1.6,2.02092818336195], +["1v2l",1.6,1.84535786376966], +["1j16",1.6,1.53124072679301], +["1eeu",1.6,1.70655057902329], +["1dad",1.6,2.00062185740281], +["1dak",1.6,1.92013678804308], +["1kg4",1.6,1.46146521229519], +["1q73",1.6,1.80426159791225], +["1g4y",1.6,2.68158278538590], +["1eug",1.6,2.21891231871286], +["5eug",1.6,2.24455754056127], +["1ou8",1.6,1.64872535151237], +["1o1z",1.6,1.23065800209935], +["2cxa",1.6,1.82300842605287], +["2awj",1.6,1.98310012288875], +["1p5z",1.6,1.46365765576126], +["1yc7",1.6,1.99559443772581], +["1x8h",1.6,1.69242768951974], +["1nfp",1.6,2.13555604011295], +["1sok",1.6,1.48436177355596], +["1fbn",1.6,2.02258601455148], +["1g8s",1.6,2.06810614034652], +["1ct4",1.6,2.0567812729866], +["8gch",1.6,2.43090076629095], +["1na0",1.6,1.25050172748077], +["1gct",1.6,2.09057962314650], +["3gct",1.6,2.10225591141009], +["1ab9",1.6,1.60436688821063], +["1xdz",1.6,1.42829536615922], +["1nme",1.6,1.57862220752556], +["1scs",1.6,1.97938570027258], +["1ow4",1.6,2.1397453502758], +["1btu",1.6,1.94608693027882], +["2izd",1.6,2.89342268438151], +["1wli",1.6,1.91567589365061], +["1wll",1.6,1.72688324291883], +["1jif",1.6,1.94817090740520], +["1hax",1.6,1.35388820927365], +["1elw",1.6,1.45486920092709], +["1qr3",1.6,2.61537712509466], +["1wcv",1.6,2.51986958051247], +["1vap",1.6,2.97219072855576], +["1nu0",1.6,1.86931854506206], +["1xpc",1.6,2.84858149738678], +["1ftk",1.6,2.23412671285060], +["1dbw",1.6,2.29047351629489], +["2beq",1.6,2.11369624779696], +["1w4o",1.6,2.49471370536080], +["1gy6",1.6,2.41450597607878], +["1zo2",1.6,2.18752521402523], +["1mrk",1.6,2.30147573140229], +["1mrj",1.6,2.20928862365130], +["1qtp",1.6,1.59308230669328], +["1u0q",1.6,2.01057475720524], +["1lln",1.6,2.2690727660672], +["2g30",1.6,1.83533871467531], +["1mp8",1.6,2.18914686992881], +["1mct",1.6,2.08783659342412], +["2a7m",1.6,2.4166964863468], +["1qwg",1.6,1.69242624080537], +["1nwp",1.6,1.78843379300601], +["1b2l",1.6,1.74934589564602], +["1g6h",1.6,2.15634194743577], +["1b2k",1.6,2.51423458811036], +["1lkr",1.6,2.71511998441079], +["1cil",1.6,1.92518300292251], +["1t7f",1.6,1.31798856794597], +["1fr4",1.6,2.8912463461601], +["2bl8",1.6,1.70209383820431], +["1p1n",1.6,2.03344085632906], +["1lzs",1.6,2.19823270045313], +["1g0e",1.6,1.87970260697905], +["1hcb",1.6,2.01496977783968], +["1lk0",1.6,1.93536463811208], +["1vka",1.6,0.795101268462388], +["1qgi",1.6,2.12479859763443], +["1uof",1.6,2.27676262585844], +["2evc",1.6,2.29117989115616], +["1t7m",1.6,1.78909440759992], +["1uyz",1.6,1.57208220687315], +["1p1o",1.6,1.62325664403229], +["3pnp",1.6,1.85931256677109], +["1yvm",1.6,2.09340063854622], +["1nxy",1.6,1.72267933922423], +["1g6g",1.6,1.86168799550043], +["1m4j",1.6,2.21825558699253], +["1hjf",1.6,1.72109856343251], +["1kyh",1.6,1.80432049358557], +["1q5p",1.6,2.01030573442014], +["1ndu",1.6,1.94711745275237], +["1urw",1.6,2.08192328036549], +["1qpc",1.6,1.87282798890129], +["2dri",1.6,1.78838596939527], +["1iup",1.6,1.62379860838859], +["1uk8",1.6,1.70959038797999], +["1h00",1.6,2.16925131027429], +["1jy3",1.6,1.80488133638446], +["1sup",1.6,2.02422285802705], +["1iyn",1.6,2.15871788109966], +["2bvd",1.6,1.46264713144968], +["1q4u",1.6,2.37971748642698], +["1ukk",1.6,2.15144796699514], +["1i60",1.6,1.94422272176018], +["1pb9",1.6,2.08125741709119], +["1n57",1.6,2.31264312766276], +["1p2k",1.6,1.59562319817582], +["1p63",1.6,2.06602948736122], +["1q4t",1.6,2.29868435502869], +["1wmq",1.6,2.56827506447127], +["1cg5",1.6,1.93992421861674], +["1jat",1.6,2.15200202243892], +["1yj3",1.6,2.47066001579558], +["1aht",1.6,2.22762213165356], +["1p0h",1.6,2.24033477569278], +["1f2t",1.6,1.82937915733703], +["1lj9",1.6,1.93224544646374], +["1ns9",1.6,1.89954024480373], +["1i5r",1.6,2.01745932095671], +["1exq",1.6,2.89552661752379], +["5hbi",1.6,1.51861822279491], +["7hbi",1.6,1.63644730943283], +["4hbi",1.6,1.76924639142253], +["4sdh",1.6,2.07730735456938], +["1v2b",1.6,1.07393105697307], +["2c30",1.6,1.60173898766181], +["1x2j",1.6,2.17048893283315], +["1ndd",1.6,1.82145053936509], +["1it2",1.6,2.27929412760599], +["1h6t",1.6,2.15673438919159], +["1up3",1.6,1.37311599979827], +["3man",1.6,1.80821720613029], +["1t46",1.6,1.85315487091802], +["1in4",1.6,1.83631841167333], +["1ryl",1.6,2.18580967490528], +["1euv",1.6,1.97484119184586], +["1xsq",1.6,2.16787557253907], +["1uaq",1.6,1.88779047676268], +["2g62",1.6,1.49860745798819], +["2bnj",1.6,1.20607458265824], +["1pa1",1.6,1.63849362024308], +["1xtm",1.6,3.0557698503909], +["1sz3",1.6,2.87101310673313], +["2bz6",1.6,1.51685024240642], +["1dd9",1.6,2.00275914438270], +["1w4y",1.6,1.31044197531266], +["1h57",1.6,1.45570827403845], +["1h5h",1.6,1.46730627671934], +["1h5i",1.6,1.54213801497798], +["1h5k",1.6,1.57838105432256], +["1h5l",1.6,1.50475197916232], +["1h5j",1.6,1.41037871464896], +["1h5e",1.6,1.51671487857299], +["1h5d",1.6,1.52730603304453], +["1h5a",1.6,1.44322588435245], +["1h5f",1.6,1.64227278294095], +["1t9i",1.6,1.98774998105352], +["1n08",1.6,1.88293205257007], +["1mrp",1.6,2.51360443345037], +["1qwk",1.6,1.41686620828576], +["1fcq",1.6,2.42770747659393], +["1cvl",1.6,1.81301710118740], +["1e7q",1.6,2.2029841006017], +["1e7r",1.6,2.08492179658249], +["2f64",1.6,0.752603513988154], +["2f67",1.6,1.15319871266095], +["1su2",1.6,3.53437626309583], +["1kjp",1.6,1.42291217630526], +["1kkk",1.6,1.46565575065485], +["1kjo",1.6,1.47879506168189], +["2tmn",1.6,2.40470271345204], +["6tmn",1.6,2.49294402203213], +["1kei",1.6,1.63276273172557], +["5tmn",1.6,2.40091619809943], +["8tln",1.6,2.25960376044957], +["1hnd",1.6,2.50002435021437], +["1ry6",1.6,2.4064465794019], +["1wtf",1.6,1.82384129867208], +["1a54",1.6,1.86264972638317], +["1odn",1.6,1.16712141944536], +["1o6l",1.6,1.2219657094442], +["1wer",1.6,2.77422762371093], +["1btk",1.6,2.47122996924373], +["1ynd",1.6,1.86233092904532], +["830c",1.6,2.51121900173985], +["1q11",1.6,1.75498157864888], +["1nux",1.6,2.49914394687122], +["1a8e",1.6,1.98903147831244], +["1wlz",1.6,1.98065598636786], +["1vki",1.6,1.27884225572536], +["2bdr",1.6,1.8955580356046], +["1ktp",1.6,2.48846653385703], +["1epn",1.6,1.92638414857431], +["1y0y",1.6,1.84451293747014], +["1n70",1.6,1.69157808170014], +["2er7",1.6,1.97564842044259], +["1wa0",1.6,1.17917873242578], +["1epm",1.6,1.79892241335442], +["1y4a",1.6,1.95258613937569], +["1hsr",1.6,2.20700099378377], +["1aru",1.6,2.14781040493914], +["1arv",1.6,2.11295684705966], +["1arw",1.6,2.14710400003919], +["1c48",1.6,1.87844542124364], +["1mkz",1.6,1.69816782481084], +["1h7n",1.6,2.16195684849114], +["2ahl",1.6,2.31565574177231], +["1l5o",1.6,1.82714451118523], +["3pte",1.6,1.5735780869525], +["1jfu",1.6,1.88631237648029], +["1ur2",1.6,1.68794688535366], +["2c0h",1.6,0.933463904624877], +["1xkn",1.6,1.86273584257665], +["1b6a",1.6,1.27472045850639], +["1qzy",1.6,1.66033603268823], +["1z6f",1.6,1.73151281630574], +["1qgx",1.6,2.4039085463854], +["1m44",1.6,1.29361713584284], +["1s22",1.6,1.26640121477166], +["1xh8",1.6,1.74887772213645], +["1d3g",1.6,1.81062116637356], +["1yyg",1.6,1.94148623105472], +["1yzr",1.6,1.90782123226714], +["1yzp",1.6,1.86967331627118], +["2b5w",1.6,1.32310881463036], +["1qz6",1.6,1.21401029198833], +["2fhp",1.6,1.75808849844237], +["1wny",1.6,2.27728244069861], +["1s44",1.6,2.29633118217310], +["1i58",1.6,2.25895249738509], +["1h51",1.6,1.78567757628011], +["1jrr",1.6,2.0013960011743], +["1ga0",1.6,1.98909936108437], +["2asm",1.6,1.34998212477998], +["1nc5",1.6,1.88147129334948], +["1h60",1.6,2.37335311436259], +["1yt3",1.6,1.69886616753286], +["1g7q",1.6,2.11249596351510], +["1ree",1.6,1.85777366813480], +["1red",1.6,1.90634973082220], +["1uhk",1.6,1.82130215251583], +["1edg",1.6,2.22723807918067], +["1m6o",1.6,2.03097097750557], +["7odc",1.6,2.45250708275384], +["2sim",1.6,2.64080774650401], +["2sil",1.6,2.64740714424582], +["1dim",1.6,2.63937358257551], +["2cc0",1.6,1.45281247275209], +["1aoe",1.6,2.14184816836172], +["1zhk",1.6,2.04638866315395], +["1u1s",1.6,2.42140355629745], +["1xic",1.6,1.77072187604777], +["3xis",1.6,1.85873308175139], +["1tks",1.6,2.56355448749969], +["4xis",1.6,1.83351258773543], +["1xis",1.6,1.78235353102018], +["1nyw",1.6,2.23644478943165], +["1lqv",1.6,2.18817988448675], +["1xib",1.6,1.80828235256183], +["1xif",1.6,1.96355658183622], +["2qwc",1.6,2.00533572531539], +["1xpp",1.6,2.49069382001079], +["1qrr",1.6,1.62466382252156], +["1qdv",1.6,2.66097824230760], +["1gug",1.6,1.52250254276729], +["1i2c",1.6,1.46386397912137], +["1my6",1.6,1.82562806124459], +["1yux",1.6,1.74689049212076], +["1gei",1.6,2.14762905974106], +["1ru4",1.6,1.58902467915280], +["1ar5",1.6,2.29217010973282], +["2c77",1.6,1.78966240160277], +["1phg",1.6,2.37835560541113], +["1phc",1.6,2.34218043054386], +["1phd",1.6,2.56257186993436], +["1phe",1.6,2.47121933487526], +["1phf",1.6,2.69070721218606], +["1phb",1.6,2.58831052580135], +["1ws8",1.6,2.34666572482126], +["1q7e",1.6,1.71269661225420], +["1iu8",1.6,1.61059005230757], +["2czd",1.6,1.92475711471905], +["1pp3",1.6,2.01228389858545], +["1gcy",1.6,2.58142624121766], +["1gso",1.6,2.15806926614036], +["16pk",1.6,2.19001638131043], +["1km1",1.6,1.43592365451252], +["1m7y",1.6,2.07066096003957], +["1qk5",1.6,1.99160360424879], +["1q0x",1.6,2.05713870709761], +["1q36",1.6,1.50398740586351], +["1g6t",1.6,1.29398326345388], +["1g4e",1.6,1.88090768666758], +["1um5",1.6,2.35993074154918], +["1ngz",1.6,2.28554725765446], +["1ksd",1.6,1.97225953235442], +["1egn",1.6,1.50186393798445], +["1q2b",1.6,1.42491452346264], +["1mxg",1.6,1.80101630976425], +["1nlb",1.6,2.59965272680704], +["1zhy",1.6,1.92582369989005], +["1fh0",1.6,2.27874955661562], +["2b4h",1.6,1.9534356293219], +["1k92",1.6,1.79325407331887], +["1xss",1.6,2.07721672755522], +["1pw9",1.6,2.05647314546171], +["1aop",1.6,2.06029333107688], +["1wku",1.6,1.67645951623929], +["1wq7",1.6,2.87258252716955], +["1p5d",1.6,1.38850453232106], +["1yxy",1.6,1.41535896017243], +["1eon",1.6,2.25951118705738], +["1wr8",1.6,1.98958729369999], +["1o6t",1.6,1.84678860429620], +["1po5",1.6,3.21194623424340], +["1zk7",1.6,1.83342744111137], +["1wnl",1.6,2.07216664244992], +["1wpy",1.6,2.50456830621608], +["2ah6",1.6,1.11601392515130], +["1t0a",1.6,1.98624888888461], +["1fs7",1.6,2.15172090081975], +["1fs8",1.6,2.07822422602343], +["1v51",1.6,1.54519699972628], +["1gy7",1.6,2.39624490504121], +["1oko",1.6,1.49165203744609], +["1b5e",1.6,2.19977313824093], +["1n9m",1.6,1.88833921522838], +["1zke",1.6,1.63625248373952], +["1lam",1.6,1.66700590639604], +["1c7j",1.6,2.16498079254464], +["1k4f",1.6,2.11997631882231], +["1nf0",1.6,2.17853016627778], +["1wza",1.6,2.53806848893442], +["1y3n",1.6,2.17962420553392], +["1v3h",1.6,2.16746954408379], +["1z32",1.6,1.44029154554294], +["1smd",1.6,2.08713618462541], +["1yya",1.6,1.40506279437438], +["1w9d",1.6,1.62662866870819], +["1e6x",1.6,1.62374715356844], +["1e72",1.6,1.76444525328151], +["1jlj",1.6,1.60874408280959], +["1gpq",1.6,2.03395089679104], +["1wd7",1.6,2.73132609090794], +["1jl3",1.6,1.72667883659849], +["1rcv",1.6,1.95626917900525], +["1efi",1.6,2.19671979673466], +["1yms",1.6,1.66267554007143], +["1bfd",1.6,1.70639912429051], +["2bce",1.6,2.4479392646663], +["2bgk",1.6,2.88053244186032], +["2d1r",1.6,1.48522598856837], +["1a8u",1.6,1.48599246260743], +["1e2u",1.6,1.34762959912088], +["1rp0",1.6,1.72408053950211], +["1aqu",1.6,2.32180242836695], +["1o97",1.6,2.22090053755338], +["1gkk",1.6,1.55405567091452], +["1n2e",1.6,1.51788123303258], +["1mop",1.6,1.44581253048429], +["1q9i",1.6,2.16922051884138], +["1h7z",1.6,2.29794089463640], +["1v4x",1.6,2.02925850809713], +["1f6k",1.6,1.76979393517161], +["1f2u",1.6,3.19553580311798], +["1u4b",1.6,1.70120444796957], +["1nk4",1.6,1.58823422995813], +["1tvp",1.6,1.78931609321481], +["1f74",1.6,1.65829337473801], +["1vma",1.6,1.94033912839507], +["1v5e",1.6,2.34002846805593], +["1nm8",1.6,2.06435946413889], +["1u69",1.6,1.34721345780588], +["2fct",1.6,1.45960134961115], +["2fcu",1.6,1.54719427985884], +["1uf5",1.6,1.63821941380972], +["1s0i",1.6,2.01266461277732], +["2ah2",1.6,1.96187172692339], +["1hoz",1.6,2.29194209694052], +["1kic",1.6,2.11790799113050], +["1kaf",1.6,2.26188918669773], +["1n1t",1.6,2.26784132018923], +["1s1d",1.6,1.69813786670619], +["1eg9",1.6,2.21691966324749], +["1tbb",1.6,1.39461015025000], +["1kwg",1.6,1.78147810309650], +["1v8c",1.6,1.79343616713730], +["1s95",1.6,2.16216046545867], +["1w5m",1.6,1.67686091853689], +["1x7d",1.6,1.71383541706587], +["1y1p",1.6,1.79363291015141], +["1dsx",1.6,2.14270857030012], +["1dys",1.6,2.17824332999543], +["1tjo",1.6,2.26004775081586], +["1vz3",1.6,1.46048327152316], +["1o6f",1.6,1.50734473553947], +["1pe9",1.6,1.96661827010469], +["1vhd",1.6,1.73713133047291], +["1ojn",1.6,2.23737650967943], +["1t4b",1.6,1.61581512367120], +["1yd9",1.6,2.37370384996807], +["1u3u",1.6,1.91807151908738], +["1ejx",1.6,2.31920039859960], +["1w0p",1.6,2.21919719552583], +["1uer",1.6,2.63947261934617], +["1ues",1.6,2.73188844747336], +["1bd0",1.6,2.6268234401089], +["2bsv",1.6,2.54641682881196], +["2bsu",1.6,2.66254882094576], +["1hqk",1.6,1.58586547781217], +["1kj8",1.6,2.73665595484501], +["1rrm",1.6,1.72148607877206], +["1kj9",1.6,2.62461057644978], +["2c46",1.6,1.56193935796002], +["2gyi",1.6,2.50054720536505], +["1kji",1.6,2.70527351535455], +["2gl5",1.6,1.58398624798988], +["1kwm",1.6,2.03821332172553], +["1dz4",1.6,1.60371127557567], +["1s9r",1.6,1.55401948320685], +["1fgr",1.6,1.71903014824766], +["1ajs",1.6,2.32710053833915], +["1jkx",1.6,2.13997653017555], +["2g6y",1.6,1.94967022828505], +["1h80",1.6,2.03259563023269], +["1wvm",1.6,1.92242478781149], +["1o26",1.6,1.83394074481975], +["1y6v",1.6,2.17016796015225], +["1nbu",1.6,2.32864244541308], +["2apj",1.6,1.48155878403918], +["1hfe",1.6,1.53712430609742], +["2f9n",1.6,2.18262861056235], +["1qwm",1.6,1.89786917980041], +["1qwl",1.6,2.12968538396902], +["1j1n",1.6,1.99675184806654], +["1s3e",1.6,1.59507208013291], +["1gee",1.6,1.89146089013257], +["1j31",1.6,2.13647635809728], +["2bo9",1.6,1.75845273633268], +["2dg5",1.6,1.99339358420441], +["1hj3",1.6,1.89878572892516], +["1hj4",1.6,1.93750249980443], +["1u0f",1.6,1.98276027855436], +["1u0e",1.6,1.92591418938194], +["1j3z",1.6,1.86009700061774], +["1xg4",1.6,2.20474205668284], +["1fiu",1.6,2.40428782026677], +["1l9x",1.6,1.76256962056095], +["1xk7",1.6,1.79384305500261], +["1g87",1.6,1.79713839804063], +["1bav",1.6,2.91927668967643], +["1kxv",1.6,2.54216134829201], +["1ccw",1.6,1.8313833973494], +["1dki",1.6,2.01544846198411], +["1f1x",1.6,1.73299629961047], +["1ji1",1.6,2.08080407636916], +["1tqj",1.6,2.16345562284234], +["1p0z",1.6,1.66660544422725], +["1pzg",1.6,1.51393557775341], +["1juh",1.6,1.59875530083231], +["1q0g",1.6,1.51386057974704], +["1ufo",1.6,2.09429152308687], +["2cdb",1.6,1.95774482270753], +["1zz0",1.6,1.76895855593157], +["1kqf",1.6,1.91182463628800], +["1uxl",1.6,1.98097710387286], +["1xpm",1.6,2.23582161144665], +["1jnr",1.6,1.93693491893510], +["1d8w",1.6,2.67094596081843], +["2fym",1.6,1.61162941355055], +["1gtz",1.6,1.31411841024812], +["1dps",1.6,1.69670286790924], +["1qh1",1.6,1.54176000453117], +["1qgu",1.6,1.52413409370264], +["1qh8",1.6,1.62326803998796], +["1qmg",1.6,1.50936280308343], +["1iy8",1.6,1.63146784408523], +["1y7b",1.6,1.96121541241498], +["8ruc",1.6,2.15931864039727], +["1fwx",1.6,2.79963139661745], +["1kxq",1.6,2.49842241035473], +["1rm6",1.6,1.63364245793569], +["1e6y",1.6,1.72223549685124], +["1y2m",1.6,1.45794304360053], +["1px3",1.6,2.53130727422576], +["1px4",1.6,2.53644764720508], +["2ar1",1.6,1.83917204894676], +["2a0m",1.6,1.33013338476462], +["1vk5",1.6,1.71026384472849], +["1lqa",1.6,1.63958518672473], +["2aen",1.6,1.19692475379155], +["1s8i",1.61,1.36508444067563], +["1xrt",1.61,2.41181484518929], +["1r0q",1.61,2.59017025136508], +["1zcx",1.61,1.58963733138482], +["1tfj",1.61,1.78587844502211], +["1h4y",1.61,2.11236170113411], +["1elt",1.61,1.69513932566009], +["1r7u",1.61,2.02982199718108], +["1li0",1.61,1.99894870090727], +["1on2",1.61,2.14201762272123], +["1xkg",1.61,1.43507741403723], +["1h55",1.61,1.43238164553677], +["1c5c",1.61,2.13340986944302], +["1z3v",1.61,1.57376285471736], +["1p5g",1.61,1.26563680272542], +["2fta",1.61,2.33852647868989], +["1xo7",1.61,2.25483902807832], +["1jqc",1.61,2.44942405176012], +["1pj5",1.61,1.54753241602560], +["1u60",1.61,1.90370323494212], +["1guj",1.62,1.14751500473465], +["1f5b",1.62,1.91394534773645], +["1d0d",1.62,1.49580103474491], +["2bwl",1.62,1.18601626382038], +["1wol",1.62,3.03386648975673], +["1p64",1.62,1.58049469915322], +["1vjf",1.62,1.23684841592369], +["1p8u",1.62,3.67529898375471], +["1o0a",1.62,2.77965670110243], +["1o2t",1.62,1.98816872563439], +["1v2o",1.62,1.63290302706756], +["2rtr",1.62,2.40076817960351], +["1jzi",1.62,2.10392383320518], +["1w9t",1.62,1.94343732228468], +["2ftl",1.62,1.41954692572740], +["1jkl",1.62,2.29560161707699], +["1h5c",1.62,1.35896264514035], +["1r6w",1.62,1.64620333884271], +["1h63",1.62,2.1629307249881], +["1htr",1.62,2.29942615670734], +["1t93",1.62,3.31580168140602], +["1kv8",1.62,1.55757440808065], +["2abw",1.62,2.06416369371347], +["1iat",1.62,2.03638760021897], +["1m26",1.62,1.91305486605924], +["1ikq",1.62,1.99331564826882], +["1gzj",1.62,1.85169286668221], +["1tp9",1.62,2.0735444469563], +["1h2b",1.62,1.99269527479382], +["1fgt",1.62,1.61673323665437], +["1fgo",1.62,1.63456578512850], +["1dzo",1.63,1.30335024360015], +["1x6p",1.63,1.61079365011679], +["2aj6",1.63,1.80217421647007], +["1ir8",1.63,1.09654216431889], +["2bsw",1.63,1.92499872589698], +["1gny",1.63,1.33532732515930], +["1xww",1.63,1.41708455649362], +["2cpl",1.63,1.61345713650859], +["1pzs",1.63,1.53613108166901], +["1lko",1.63,2.14808639095754], +["1iwd",1.63,1.68818259564497], +["1aky",1.63,2.0632712756484], +["1qqu",1.63,2.66879999577686], +["1c1s",1.63,1.75420386345157], +["1o2o",1.63,1.79693166869331], +["1o2k",1.63,1.80207016668661], +["1tqh",1.63,2.0954373382834], +["1n83",1.63,1.81618727876956], +["1zvy",1.63,1.74464724887674], +["1o5c",1.63,2.57506773765884], +["1lcn",1.63,1.98810780374324], +["1th9",1.63,1.92701343324167], +["1k77",1.63,1.82384600036524], +["1rcj",1.63,1.61919806772019], +["1r2z",1.63,2.10028385456302], +["1qyw",1.63,1.61472822330299], +["2cj4",1.63,1.51667834250697], +["2fbn",1.63,1.28987593020055], +["1ds0",1.63,1.91408312297144], +["2cpp",1.63,2.15851994754915], +["1pha",1.63,2.48524409152821], +["1ugp",1.63,1.49427853958948], +["1qgw",1.63,1.44915918529856], +["1mg5",1.63,2.05997518451401], +["1ju4",1.63,1.75498697468245], +["1e5p",1.63,2.24624809680352], +["1tb7",1.63,1.20684617436862], +["1q3l",1.64,2.40118615954447], +["1h98",1.64,1.73436515692465], +["1zpw",1.64,1.67985508949283], +["1dpw",1.64,2.02872378949994], +["1h6m",1.64,1.96965588693271], +["2utg",1.64,3.11765022701106], +["1x3k",1.64,1.44527073584457], +["2cyh",1.64,2.16499423058753], +["1ciz",1.64,2.18063167099498], +["1lkp",1.64,2.12202758381020], +["1dai",1.64,1.77565775598604], +["1o3e",1.64,1.92662917938454], +["1o3c",1.64,1.80856547481073], +["1dag",1.64,1.86695818934334], +["1dah",1.64,1.95418514509425], +["2a0n",1.64,1.41110618955359], +["1gj8",1.64,2.58577148355084], +["1zjo",1.64,1.81769814824104], +["1bue",1.64,1.24692321570346], +["2bok",1.64,1.43689985830596], +["1o83",1.64,1.80382097454496], +["2bof",1.64,1.33278193862758], +["1mkq",1.64,1.67062787768925], +["1vje",1.64,1.68822943400176], +["1ogi",1.64,1.81768213614633], +["1wrr",1.64,1.5719553917973], +["3a3h",1.64,1.81957086287930], +["2fp2",1.64,1.38059875862195], +["1h7p",1.64,2.30547122980894], +["1xh9",1.64,1.61811014874387], +["2asp",1.64,1.40780592582984], +["1yw9",1.64,2.04275212489633], +["1pu6",1.64,1.76929342574048], +["1sk9",1.64,2.46639266527325], +["1kap",1.64,1.46982206937509], +["1wds",1.64,1.86372226443128], +["2ffu",1.64,1.79454467407005], +["2cdo",1.64,1.96461072867587], +["1l7r",1.64,1.93413203231820], +["1n1s",1.64,2.32892093003911], +["1su6",1.64,2.3927712411095], +["2afx",1.64,1.94280824885659], +["2bfc",1.64,1.81882295529947], +["2rmc",1.64,1.93830222382907], +["1yll",1.64,2.57711239928759], +["1u0a",1.64,1.25539402663687], +["1g8k",1.64,1.57944871046823], +["1sdb",1.65,2.41680281949333], +["1ds3",1.65,2.27130432274446], +["1kfn",1.65,2.59776594265071], +["1be7",1.65,1.63925188497332], +["2ccb",1.65,2.51873266871503], +["1b7j",1.65,1.26706343820001], +["1jab",1.65,1.36215467477687], +["1b7i",1.65,1.80636939734996], +["6msi",1.65,1.65655140045783], +["1ekl",1.65,2.00508675021048], +["1ame",1.65,1.57571135648356], +["1cxy",1.65,2.00899988116895], +["1uln",1.65,1.85618567296382], +["1jk2",1.65,2.5074383111708], +["1zld",1.65,1.07441112612948], +["1kcq",1.65,1.33418783127335], +["4gsp",1.65,1.62594061996324], +["2wrp",1.65,1.87855426414777], +["1erv",1.65,2.10704736980703], +["1o4l",1.65,2.39181126890363], +["1sbx",1.65,1.55702580248526], +["1pc4",1.65,1.94176746495501], +["1pal",1.65,2.99527173874995], +["1bu3",1.65,2.23077545392059], +["1xw3",1.65,1.66812580952355], +["1n3z",1.65,2.24613450706732], +["1ui9",1.65,1.76301939622124], +["1ln8",1.65,2.04272486709443], +["1unp",1.65,2.28615862650912], +["2a7b",1.65,1.89181059710988], +["1l6p",1.65,2.47803155986957], +["1dhn",1.65,1.37068875230970], +["1dz3",1.65,1.85412331129793], +["1tew",1.65,1.97444543459523], +["1vwo",1.65,2.78321560111568], +["1dpx",1.65,2.00768681531550], +["1w6z",1.65,1.9347328342124], +["1qjp",1.65,2.26718869621210], +["1snc",1.65,3.16568997323705], +["1ihz",1.65,3.11670230932798], +["2fdx",1.65,2.09841260959044], +["1sd9",1.65,1.78431267392426], +["1i9d",1.65,1.61466889089341], +["2f1w",1.65,2.18596636072385], +["1v8y",1.65,1.57394443716628], +["1uov",1.65,1.75828727976890], +["1yoi",1.65,2.33098213600646], +["1yog",1.65,2.35179226264091], +["1yoh",1.65,2.32197089773819], +["1m45",1.65,1.59624319840828], +["1sk4",1.65,2.25315320580352], +["119l",1.65,1.90585109388202], +["1lpy",1.65,2.69152776135072], +["1pqd",1.65,2.11134631133011], +["1pqo",1.65,2.25702309046047], +["1l58",1.65,2.31864251878164], +["1o9w",1.65,1.63589124448938], +["1w8m",1.65,2.70119721567648], +["1qtx",1.65,1.82775347008827], +["2fn4",1.65,1.80265599842426], +["1m8u",1.65,2.24160239102702], +["1aqb",1.65,2.72319447815938], +["1iwl",1.65,2.52830387348869], +["1wub",1.65,2.91472555216455], +["1pq1",1.65,2.52838014846433], +["1im5",1.65,2.35770145749443], +["1y66",1.65,2.67107981440274], +["1ufi",1.65,2.55538573904154], +["1fr9",1.65,2.27554757280139], +["1i9s",1.65,1.59705513004111], +["1h4c",1.65,2.292547072783], +["1hjj",1.65,2.32105525076057], +["1h4e",1.65,2.43343475822376], +["1us6",1.65,2.05738000582228], +["1n3y",1.65,1.85379684408514], +["1e6b",1.65,2.01377387287302], +["1cqm",1.65,1.95636436909420], +["1nrv",1.65,1.60107940096522], +["1swx",1.65,2.05760442664152], +["1l8r",1.65,2.38494174095749], +["1yer",1.65,1.94104284178802], +["1kx9",1.65,2.36666836450128], +["1dix",1.65,2.41267154418968], +["1e2d",1.65,1.58619596758612], +["9pap",1.65,2.76573471476866], +["1sdi",1.65,1.82885752224253], +["2a46",1.65,1.88971986397162], +["1jfx",1.65,1.75457386953441], +["1pva",1.65,2.37264379901917], +["1tj6",1.65,1.56165452944249], +["1hxr",1.65,1.93576339910238], +["1dts",1.65,1.99901193079493], +["1nqd",1.65,2.92390790849790], +["1kgb",1.65,2.66225313857861], +["1tgn",1.65,3.24456357365583], +["1u5h",1.65,2.60139772780444], +["2cul",1.65,1.56325454630886], +["1y5b",1.65,1.41949205028684], +["2fx4",1.65,1.23617231961497], +["1o2j",1.65,1.73493639965049], +["1o2s",1.65,1.73727564978679], +["1c2e",1.65,2.02889678345700], +["1o2z",1.65,2.05132003201698], +["1c2g",1.65,2.03974670382053], +["1c2d",1.65,2.28442444634184], +["1c2k",1.65,2.59099441891726], +["1v2m",1.65,2.05339376949628], +["1vj2",1.65,1.88328267140607], +["2aip",1.65,2.32249948016002], +["1ct2",1.65,1.98113338023514], +["1sri",1.65,3.07904607882766], +["1sfi",1.65,1.25222345662474], +["2ax9",1.65,2.04332521336912], +["1dza",1.65,2.11042587756929], +["1l6x",1.65,2.33987264907685], +["2a7c",1.65,1.09622847539275], +["1uo6",1.65,1.48052081218943], +["3est",1.65,2.09362134800833], +["2a7j",1.65,1.72754616167087], +["1esa",1.65,2.01751341919512], +["1elg",1.65,2.03926007456126], +["2rtd",1.65,2.2395286602617], +["1nes",1.65,2.05064977101305], +["1g2n",1.65,2.21227054297699], +["1yo3",1.65,2.02520216957098], +["1zko",1.65,1.26986438549825], +["1lp8",1.65,1.78168187597939], +["1j9m",1.65,2.04453034317329], +["1c5y",1.65,2.73738048130609], +["2ev0",1.65,1.78060035159712], +["1y51",1.65,1.84318380477969], +["1m5c",1.65,1.56846517745974], +["1cc3",1.65,2.51820407484574], +["1s50",1.65,2.16194183195623], +["1uy0",1.65,1.85652221756047], +["1mqj",1.65,1.53168335986178], +["1iys",1.65,1.61307950798695], +["1zj1",1.65,1.85602297263218], +["1bbz",1.65,2.62956401599567], +["1o54",1.65,1.51630077793156], +["1r80",1.65,2.10954944752369], +["1lz7",1.65,2.48519948586666], +["1w6n",1.65,2.14769931257317], +["2gdz",1.65,1.44700348566554], +["1f5r",1.65,1.75882245420733], +["2b9e",1.65,1.60073793935605], +["2ftm",1.65,1.37123916279841], +["1p2i",1.65,1.67260352840387], +["1h9m",1.65,1.72076500901586], +["2bzl",1.65,1.78190870513709], +["1jqz",1.65,2.38945113077607], +["1yjh",1.65,2.23302840202909], +["2cwc",1.65,1.82423784817864], +["1cnv",1.65,2.00101733616577], +["1wmu",1.65,2.04209914549558], +["1ghx",1.65,2.59671538184707], +["1nnh",1.65,0.667267994766753], +["1vpd",1.65,1.49058204763677], +["1fhu",1.65,2.03173422187544], +["1mk8",1.65,1.71142284141524], +["1ml2",1.65,2.08376253961865], +["1r4u",1.65,1.70852983764035], +["1cbj",1.65,1.86895719518063], +["4a3h",1.65,1.33004130643793], +["1gy1",1.65,1.93507694770797], +["1g4c",1.65,2.23407816645824], +["1m93",1.65,2.16889709013392], +["1wzz",1.65,1.52309814516205], +["2bcq",1.65,1.78015144777245], +["2erx",1.65,1.26393923545280], +["1i0s",1.65,1.58937887195280], +["1zsw",1.65,1.53966329674963], +["1mvf",1.65,2.43353921519709], +["1iej",1.65,2.25783494318187], +["1w06",1.65,2.07177481546933], +["1phn",1.65,2.18448517377087], +["1kcb",1.65,2.33065561131470], +["1wa1",1.65,1.43945013607372], +["1udc",1.65,1.86486393864744], +["1udb",1.65,2.00513725713238], +["1qnq",1.65,1.27726027940928], +["1ode",1.65,1.94934273210554], +["1fpx",1.65,2.09347985526641], +["1ezw",1.65,2.16025604313346], +["1jg7",1.65,2.08235585310703], +["1oxs",1.65,2.01169174414870], +["1r3s",1.65,1.71283312388775], +["2b61",1.65,1.60572550796795], +["1xrf",1.65,2.1895056342006], +["1ueb",1.65,1.40302574525504], +["1s99",1.65,2.08030207730640], +["1dtd",1.65,2.27586822045853], +["3psg",1.65,2.80700838389212], +["1cem",1.65,1.24532088015296], +["1wb0",1.65,1.82854280154570], +["1tx4",1.65,2.29357444718676], +["1zkc",1.65,1.95867152356741], +["1gw1",1.65,1.17218646034865], +["1vi0",1.65,2.26200873319632], +["1ucg",1.65,1.68395406233985], +["2bvo",1.65,2.14665369563545], +["1bs0",1.65,2.34291914808775], +["6xia",1.65,2.03072028716823], +["1php",1.65,2.33700944208896], +["2d0q",1.65,1.48089198018014], +["1oe8",1.65,2.34924384459044], +["1i0x",1.65,1.41145134305047], +["2fpq",1.65,1.58020249974386], +["1sqg",1.65,2.38543552752066], +["1vhq",1.65,1.46212077805353], +["2fq9",1.65,1.72419144319981], +["1sk8",1.65,2.25684119549359], +["2f0c",1.65,1.52359722606761], +["1wky",1.65,1.89441818949554], +["1iby",1.65,2.30751158950489], +["1mep",1.65,2.83532433640196], +["1ooe",1.65,1.41807121383839], +["1jae",1.65,1.71202094810431], +["1v4y",1.65,1.60217903435298], +["3std",1.65,2.11659406415077], +["2a2n",1.65,2.29953088925607], +["1b8s",1.65,1.80299440271329], +["1e70",1.65,1.72071772022941], +["2a65",1.65,1.87121918625293], +["2al5",1.65,1.34688859747985], +["1pyo",1.65,2.05669223830738], +["1k07",1.65,1.73954524699385], +["1k2x",1.65,1.58937682377066], +["1t3m",1.65,1.97951096018562], +["1njx",1.65,1.68603730285578], +["1vhl",1.65,1.97546593556763], +["2cwl",1.65,1.37616109569447], +["1e0x",1.65,1.67227355185607], +["1qsa",1.65,1.14725835469018], +["1s0j",1.65,1.93998151693181], +["1uuv",1.65,2.34385887287], +["1w5n",1.65,1.69363924179828], +["1gxr",1.65,2.20027566612752], +["1y7t",1.65,2.34315132108479], +["1hfo",1.65,2.12287778306375], +["1mqq",1.65,2.09511141306599], +["1vkf",1.65,1.63385775389781], +["1h2z",1.65,1.5889300871676], +["1yqd",1.65,2.01905641187898], +["1w3y",1.65,2.16836808051787], +["2cvl",1.65,1.66906875240689], +["1ok7",1.65,2.26476475025384], +["1u3v",1.65,1.74390881932770], +["1onw",1.65,2.10509358875437], +["1u6r",1.65,1.45363611817734], +["2aal",1.65,2.2212433241042], +["2d29",1.65,1.64375023841820], +["1mm7",1.65,1.89868433178893], +["2ex0",1.65,2.05148319643323], +["1ubp",1.65,1.87821771194768], +["1kol",1.65,1.80132049644844], +["1fyf",1.65,2.13314401299723], +["1k2o",1.65,2.05357337729855], +["1pj6",1.65,1.58539210180045], +["1d0c",1.65,2.62219027569527], +["2b5r",1.65,1.76773423761338], +["1qk3",1.65,1.98694433998931], +["1iv1",1.65,2.92243487328981], +["1bu7",1.65,2.23993822890873], +["1jpz",1.65,1.50959541802998], +["1wle",1.65,2.34191408261764], +["2d1y",1.65,1.78549159418246], +["1lcp",1.65,1.67543830656510], +["1s3b",1.65,1.84412255795627], +["1j9q",1.65,1.86056312644654], +["1mo9",1.65,2.11346135714892], +["2a9w",1.65,2.29724970952524], +["1hx6",1.65,2.05603222032919], +["1w4n",1.65,1.51366206895381], +["1ms3",1.65,2.13541649480613], +["1w0d",1.65,2.35361686067038], +["1dw9",1.65,1.94979633166440], +["1dwk",1.65,1.93963254569658], +["1vl2",1.65,1.77247367215557], +["1twy",1.65,1.7683695710823], +["1yve",1.65,1.8722072669012], +["1o7t",1.65,2.54376747714081], +["1p80",1.65,1.98542770306605], +["1n9e",1.65,1.68356822598074], +["1gte",1.65,2.18197332541899], +["1pgx",1.66,1.76477325242475], +["1eis",1.66,1.64875989805987], +["1mm9",1.66,2.07941566417838], +["3chy",1.66,1.68199057963020], +["2a7d",1.66,1.98892791537832], +["1jkb",1.66,1.69136961993342], +["1jka",1.66,1.70879957068246], +["1o6d",1.66,2.50775870414455], +["1v8w",1.66,1.85022125541663], +["1fjj",1.66,1.12981234202172], +["5hpg",1.66,2.46349843552352], +["1e4c",1.66,2.05251476579650], +["1o31",1.66,1.76909408584000], +["1t65",1.66,1.71658788598410], +["1t0p",1.66,1.74504959205881], +["2aft",1.66,1.21381703662339], +["1gtk",1.66,2.41588462062502], +["2d81",1.66,1.41659036902812], +["1ymi",1.66,1.96920266516621], +["1tku",1.66,2.70765175118091], +["4uag",1.66,1.86797456945157], +["1xbv",1.66,1.41251624401417], +["2hmz",1.66,1.99236469944750], +["2hmq",1.66,2.13500019256772], +["1vpm",1.66,1.97219626895081], +["1vns",1.66,1.74728872441827], +["1jg9",1.66,1.92986370890473], +["2afm",1.66,1.88713876069564], +["1gzg",1.66,2.17575717364133], +["1cpc",1.66,2.21092682357107], +["1l0f",1.66,1.6758227035133], +["1zr3",1.66,2.29797185823046], +["1l3l",1.66,2.26436998945989], +["1e3u",1.66,2.15921577203613], +["3bto",1.66,1.65539741340992], +["1fxo",1.66,1.90728246370240], +["1krn",1.67,1.41075936401285], +["1sty",1.67,2.12611642102189], +["1n1j",1.67,1.37507223972059], +["1p46",1.67,2.21400261988272], +["1p6z",1.67,1.60267933690947], +["2cth",1.67,2.24782641233336], +["1w7z",1.67,1.99306890388555], +["3vgc",1.67,2.14536317606753], +["1exx",1.67,1.65965310947648], +["1h9l",1.67,1.88882384926883], +["1qxw",1.67,1.54260399331454], +["2ccy",1.67,2.26920837593761], +["2cbb",1.67,1.70287049385252], +["2cbd",1.67,1.88382156095928], +["1zj0",1.67,2.16318014687097], +["1c9m",1.67,1.83546742027747], +["1y1g",1.67,1.29149676339229], +["1y1h",1.67,1.28707703635529], +["2etw",1.67,1.49087680933614], +["2aj7",1.67,1.43825273109305], +["7abp",1.67,2.13965361595683], +["6abp",1.67,2.26604717021856], +["1zkl",1.67,1.56652023732832], +["2bjf",1.67,0.987847830830783], +["1tmg",1.67,1.6924888595218], +["1anf",1.67,3.20516212065713], +["1r87",1.67,1.59132486042473], +["5cha",1.67,3.27652238839427], +["1f60",1.67,1.74159147039821], +["1mw9",1.67,2.11347668337218], +["1rjo",1.67,1.45310566102581], +["1b4k",1.67,2.28018670677720], +["1y2c",1.67,1.17996406395733], +["1gql",1.67,1.63949012501728], +["1k1e",1.67,2.19075698104674], +["1yp5",1.68,1.37199487984995], +["1gv2",1.68,1.93099457949872], +["3c2c",1.68,2.96734957198683], +["1s69",1.68,2.02141239043402], +["2a15",1.68,1.69631115309114], +["2bw9",1.68,1.49904717121507], +["2mye",1.68,2.46644704661898], +["1u14",1.68,2.23600221350437], +["1gcq",1.68,2.02943308498102], +["2fp7",1.68,1.47497851076123], +["1sd5",1.68,1.90201939818147], +["1ojq",1.68,1.8493923795343], +["2trx",1.68,1.75794123104498], +["1o2l",1.68,2.04395579657487], +["2bq4",1.68,2.5573688199195], +["2f2b",1.68,1.81006091762705], +["1w4q",1.68,2.63238180941222], +["1qxz",1.68,1.85272035922873], +["1o5a",1.68,2.48598064173748], +["2bgi",1.68,2.23366457296037], +["2euw",1.68,1.46878053392642], +["6a3h",1.68,1.51027662723632], +["1ns5",1.68,2.18826769681230], +["1om1",1.68,1.96772176720473], +["1to1",1.68,1.58735210276358], +["2bwa",1.68,1.959457883835], +["1fjh",1.68,2.45953201367197], +["4cha",1.68,2.35491957601424], +["1hfu",1.68,1.68458863833687], +["2afz",1.68,1.83154002681004], +["1czf",1.68,1.84885751775808], +["1piy",1.68,2.21377186596516], +["1q0m",1.68,1.63314696208521], +["2bhx",1.68,2.00476826561953], +["1rky",1.68,1.44178107521452], +["1gnx",1.68,1.84452055038909], +["1ud9",1.68,2.31940657305556], +["1th7",1.68,1.93312279067872], +["1s6a",1.69,2.37355051539188], +["1rbx",1.69,2.40611900776853], +["1rbw",1.69,2.27203184846224], +["1uy4",1.69,1.91445878742799], +["1y7y",1.69,2.11445983375079], +["2a4d",1.69,1.99794788713792], +["1wsw",1.69,2.38731612733278], +["1uwf",1.69,1.56878802628948], +["1lkm",1.69,2.07864059845583], +["1xzg",1.69,1.64294328098520], +["1ffa",1.69,1.78763944300625], +["1ffe",1.69,1.67661611540565], +["1cuy",1.69,1.87331751744937], +["1xzf",1.69,1.74024164734244], +["1xzj",1.69,1.74586913441288], +["1xzh",1.69,1.78737023837750], +["1ffd",1.69,1.77077151866077], +["1xzi",1.69,1.84453877142039], +["1xzl",1.69,1.88337456439128], +["1cuu",1.69,2.01728288486449], +["2hft",1.69,2.57861772184671], +["1h2e",1.69,1.83080082043825], +["1n8n",1.69,1.56984021605802], +["1enf",1.69,1.99491814844740], +["1o2m",1.69,1.59848752773592], +["1u21",1.69,2.05154960224843], +["1w4p",1.69,2.59210988723537], +["1vzh",1.69,1.90340909846457], +["1vzg",1.69,2.02341101507647], +["1xqp",1.69,1.29518172348769], +["1s2w",1.69,1.55841960910613], +["1zi3",1.69,1.91497774894198], +["1zj3",1.69,1.98283880851276], +["1zj2",1.69,1.72326348766785], +["2a8u",1.69,2.16393952183082], +["1sbm",1.69,1.42192612190675], +["1sdq",1.69,1.69058727223901], +["1jp4",1.69,1.65334033914172], +["1kli",1.69,2.10474615475992], +["1y3c",1.69,1.55971891221378], +["1vpj",1.69,1.37848713810522], +["1d6f",1.69,2.09308327935524], +["1cml",1.69,2.20400836449715], +["1jy1",1.69,1.88891901208244], +["1ska",1.69,2.56958003008539], +["1ry8",1.69,2.63581679102307], +["1ry0",1.69,2.80588173582898], +["2bfe",1.69,1.95434991369012], +["2bi1",1.69,2.07420088063338], +["2bi2",1.69,2.13315632272678], +["2bi3",1.69,2.08472446309863], +["1q6q",1.7,1.42490586473299], +["1x38",1.7,2.02176593464905], +["1usd",1.7,2.16788412759427], +["1wkx",1.7,0.49999908702147], +["1b17",1.7,1.34922769281048], +["1b2d",1.7,1.52741423537008], +["1b2a",1.7,1.57326051339877], +["9ins",1.7,2.34557680807026], +["1r0h",1.7,1.60124347345291], +["1rop",1.7,1.91376583203484], +["6pti",1.7,1.56475986710828], +["1fxd",1.7,1.84981363594837], +["1jb6",1.7,2.00868738546716], +["1vie",1.7,2.7361153871852], +["1uo4",1.7,1.87625425662675], +["2ccf",1.7,2.02993175001251], +["2ccc",1.7,2.05645372880891], +["1sn1",1.7,2.93573309557233], +["1ypc",1.7,0.983764100153305], +["1wtq",1.7,2.73720742424572], +["2g0c",1.7,2.18971497367664], +["1fw4",1.7,2.14352801892694], +["1uj0",1.7,2.26078840448701], +["7ame",1.7,2.24396945117327], +["7msi",1.7,2.07832150545074], +["1mog",1.7,2.63210245525758], +["1ctf",1.7,2.21278713385802], +["1j2l",1.7,1.63347674035764], +["1a8o",1.7,1.52751610780834], +["1b7v",1.7,2.18488777802726], +["1z0p",1.7,2.19387621347143], +["1bt0",1.7,2.57036754581880], +["1wfa",1.7,1.64659851629092], +["1h75",1.7,1.90550967319753], +["1rwj",1.7,1.85811119138991], +["1tsf",1.7,1.85644139133848], +["2bop",1.7,2.39582068340623], +["1gkh",1.7,3.01719842990817], +["1ij2",1.7,2.64559376251324], +["2buo",1.7,2.45951579835359], +["1mgr",1.7,1.96830494553888], +["1a70",1.7,2.21589927579501], +["1j27",1.7,2.20971010447318], +["1frd",1.7,2.13789733327758], +["1w41",1.7,1.04770569542907], +["1jos",1.7,2.52783431584082], +["1kdj",1.7,1.70740019679031], +["1tuv",1.7,2.68981701768227], +["1nza",1.7,1.65940953279649], +["4bir",1.7,1.39501246357642], +["1hyf",1.7,1.49533969500577], +["1rga",1.7,1.73660107379335], +["1ygt",1.7,2.23930020305678], +["1f2f",1.7,1.49386735456639], +["2a9i",1.7,1.92482898153746], +["1ert",1.7,1.98320868844449], +["1rh6",1.7,2.03616783528333], +["1njh",1.7,2.13381268716299], +["1o4q",1.7,2.31844949304974], +["1o42",1.7,2.17351205579944], +["1o4j",1.7,2.08455263387013], +["1o41",1.7,2.35451560019275], +["1o4o",1.7,2.51439746329595], +["1o44",1.7,2.25196158547666], +["1o49",1.7,2.60427569223755], +["1d3w",1.7,2.69564051152528], +["1fkj",1.7,1.73305287429466], +["1fkb",1.7,1.6831981527123], +["1fkf",1.7,1.95326449849363], +["1fkl",1.7,2.02157095916743], +["1vmb",1.7,1.49495797562627], +["1b8l",1.7,2.12816820383915], +["2b8m",1.7,1.42648397463594], +["1v07",1.7,1.17431005232345], +["1wjx",1.7,1.89749475803061], +["1ddw",1.7,2.20721465737467], +["1uqx",1.7,1.72967106486402], +["1ean",1.7,1.59336621130299], +["2cbo",1.7,1.45981191289747], +["1un3",1.7,1.18650359288803], +["1rbd",1.7,1.98391480837155], +["1jdl",1.7,2.18020303446969], +["2cy3",1.7,2.47844620973639], +["1rbh",1.7,1.93263260588787], +["1m8a",1.7,2.36140844388859], +["1cot",1.7,2.17603686670156], +["1alc",1.7,3.90609075439213], +["3era",1.7,2.06485188369522], +["6ebx",1.7,2.77348521068424], +["1ras",1.7,2.92163953360651], +["2b96",1.7,2.02571004394083], +["1bp2",1.7,2.76459379772021], +["1hml",1.7,2.06931493360792], +["1c9v",1.7,2.56990698201294], +["3rsp",1.7,2.48154837658438], +["1tg4",1.7,2.87516098261204], +["1y80",1.7,0.977544844379707], +["1tdv",1.7,2.77471200159499], +["1mc9",1.7,2.58640385346775], +["1z9l",1.7,1.70398137608009], +["1vwq",1.7,2.693900387011], +["1e6m",1.7,1.96968071198925], +["1jzh",1.7,2.28326905456200], +["1rsu",1.7,2.45416021187243], +["1pdo",1.7,1.82986714474744], +["1lsd",1.7,2.27976122872344], +["1lse",1.7,2.13606021931871], +["1f10",1.7,2.27401625448483], +["1vdt",1.7,1.92922917974287], +["1hel",1.7,2.08061966390403], +["1lsc",1.7,2.08061966390403], +["1lz9",1.7,2.12025700669314], +["1lsb",1.7,2.64447716746684], +["2aub",1.7,1.99304282540278], +["1lsf",1.7,2.70531906683475], +["1lsm",1.7,2.34013682890637], +["1lsa",1.7,2.63404488933116], +["1rst",1.7,2.65688993434588], +["1tay",1.7,2.07345320745215], +["1ge1",1.7,1.50640617162367], +["1tdy",1.7,1.99421624621722], +["1tcy",1.7,1.99483015036645], +["1rey",1.7,1.97965362971547], +["1rez",1.7,2.19349683311112], +["1nep",1.7,1.39303651770939], +["1rxe",1.7,2.16540389823562], +["1lib",1.7,1.97580125372719], +["1uy2",1.7,1.85912086909936], +["1g74",1.7,2.15299410042311], +["1u4p",1.7,1.84803532603162], +["1gmi",1.7,2.79423105046706], +["1is6",1.7,1.96791196727826], +["1dqg",1.7,1.37509951579109], +["1kqx",1.7,2.49291304469929], +["2f1y",1.7,2.26740567636598], +["1h0s",1.7,1.77338063771047], +["1ey5",1.7,2.99979970880173], +["1syd",1.7,2.23917341847834], +["1stg",1.7,2.81327271814887], +["1stn",1.7,2.15448636738588], +["1sno",1.7,2.06245871880021], +["1eyd",1.7,2.59176492869429], +["1rnj",1.7,1.95588161676208], +["1iuk",1.7,2.88527668565684], +["1yrk",1.7,1.67811901299162], +["1sta",1.7,2.09375846162528], +["1b9d",1.7,2.08784024074362], +["1qkk",1.7,2.06072773683289], +["1zd0",1.7,1.57207869088372], +["1yy6",1.7,2.20331266615094], +["1tfe",1.7,2.28539865454611], +["1ear",1.7,2.14359360996060], +["1wka",1.7,1.58607083313628], +["1h6h",1.7,1.86912791128096], +["1cll",1.7,3.03582548980337], +["1gs9",1.7,2.31416726350388], +["1uv7",1.7,2.26251151293954], +["1ewx",1.7,1.50457100237393], +["1vsd",1.7,2.23321461625834], +["1w92",1.7,2.23112917218842], +["1xyy",1.7,3.1079081583077], +["1nb9",1.7,1.97181565189372], +["1nb0",1.7,2.28160979736796], +["1prw",1.7,1.74313748838747], +["1b9f",1.7,2.58494349163528], +["1jp9",1.7,1.56095944341964], +["1jpb",1.7,1.64687157146128], +["1jcc",1.7,1.83712502564622], +["1npg",1.7,1.60649482879814], +["1zxu",1.7,2.26166167410722], +["2jcw",1.7,1.57424790934669], +["1yaz",1.7,2.51391314864562], +["1f18",1.7,1.37142175096258], +["2evp",1.7,1.81546239666261], +["1hrm",1.7,1.99995820286816], +["1xch",1.7,2.21122359477474], +["1nz5",1.7,2.44202081476902], +["1wla",1.7,2.4406406972160], +["1rse",1.7,2.31255112547859], +["1do4",1.7,1.20516546587147], +["2bli",1.7,1.48285413628693], +["1vxh",1.7,2.15698953374644], +["1vxd",1.7,2.22715557600075], +["1vxc",1.7,2.36574718872971], +["1vxg",1.7,2.39583066313775], +["1vxf",1.7,2.37090486789984], +["1gdj",1.7,2.69313125350608], +["2gdm",1.7,2.7360251157345], +["1vxe",1.7,2.60693612744761], +["1cik",1.7,2.11033250351448], +["1lue",1.7,1.76834679225318], +["1f65",1.7,1.92606790654070], +["1ltw",1.7,2.41964279314013], +["1mcy",1.7,2.57705759451141], +["1dti",1.7,2.50630718023828], +["1mym",1.7,2.70119862759571], +["2spm",1.7,2.64813617396078], +["1tes",1.7,2.68442406700083], +["1mtj",1.7,2.77626958003792], +["1mll",1.7,2.72356119533848], +["2spo",1.7,2.54951460321192], +["1mls",1.7,2.86715046066817], +["2spl",1.7,2.66992574699574], +["2mge",1.7,2.75972160605069], +["2spn",1.7,2.75243432577829], +["1bgc",1.7,2.45180431085252], +["1mxi",1.7,2.34424268720333], +["1dsz",1.7,2.01628419328455], +["1vhh",1.7,2.45776829850065], +["1znl",1.7,2.8616043525997], +["1qy1",1.7,2.63724887202575], +["1clu",1.7,2.17551930046983], +["1h0a",1.7,2.1494357632007], +["2d3g",1.7,1.68934326791253], +["1df7",1.7,2.26482453458180], +["1jvw",1.7,1.87544503952220], +["1hfs",1.7,1.46455545824922], +["1qst",1.7,3.01124656552795], +["2g40",1.7,1.19363595210687], +["1urm",1.7,1.66986301368841], +["1asu",1.7,3.29398130599089], +["1l74",1.7,2.08832517177257], +["1l36",1.7,2.13207520559266], +["1l68",1.7,1.87134839524582], +["161l",1.7,1.86946213908383], +["1l83",1.7,2.12077705810547], +["1l65",1.7,2.09083507163718], +["1lyh",1.7,1.99418416211371], +["1l66",1.7,1.99489020282895], +["241l",1.7,2.06790442748552], +["244l",1.7,2.14272275073945], +["130l",1.7,1.52274229095493], +["217l",1.7,1.80710355256433], +["1l92",1.7,1.86889512878731], +["1l62",1.7,1.84960948383175], +["110l",1.7,1.94707069109297], +["1g07",1.7,2.06005145871057], +["131l",1.7,2.11832379164696], +["128l",1.7,1.84888397989251], +["1kni",1.7,2.49658289674692], +["1g0m",1.7,2.07520112519559], +["1lwg",1.7,2.58805379831732], +["4lzm",1.7,1.98308630694001], +["129l",1.7,2.15841199879398], +["138l",1.7,1.97640151545039], +["221l",1.7,2.06267362569314], +["139l",1.7,2.07482887505301], +["1d9w",1.7,2.32684484711922], +["173l",1.7,2.3620637425756], +["3dfr",1.7,2.4181090304742], +["237l",1.7,1.98466350066662], +["1l33",1.7,2.32030341472575], +["1l22",1.7,2.35197271248531], +["1l08",1.7,2.58906603760123], +["1l02",1.7,2.64414037310492], +["1l01",1.7,2.67063107542213], +["1l23",1.7,2.27246357932366], +["1l19",1.7,2.30421967925389], +["3lzm",1.7,2.30421967925389], +["1l60",1.7,2.37055767894847], +["1l32",1.7,2.28488384156137], +["1l46",1.7,2.16779106760773], +["1l30",1.7,2.29491565941728], +["1l47",1.7,2.22332293742254], +["1l17",1.7,2.30699019122379], +["1l12",1.7,2.56188577406154], +["1l26",1.7,2.55509604307279], +["1l15",1.7,2.58708617144143], +["1l05",1.7,2.57254697685095], +["1l14",1.7,2.60256428120736], +["1l45",1.7,2.32854437946754], +["1l44",1.7,2.29404869875816], +["1l52",1.7,2.39803177808965], +["1l09",1.7,2.60125372426864], +["2lzm",1.7,2.60175815851452], +["1l06",1.7,2.62633385374181], +["1l04",1.7,2.62682689659219], +["1l03",1.7,2.39836040661184], +["1l11",1.7,2.63391258735234], +["1l07",1.7,2.61953085885497], +["1l10",1.7,2.64978985635085], +["1l29",1.7,2.6353639834866], +["1l13",1.7,2.64325940558751], +["1l18",1.7,2.18169878012902], +["1l16",1.7,2.56736228794619], +["1l48",1.7,2.30204905089468], +["1l24",1.7,2.37580880078776], +["1w8v",1.7,1.97032884560464], +["1bzs",1.7,2.06620742501692], +["1xj0",1.7,2.06109690447453], +["1wkc",1.7,2.15100527121878], +["1lf0",1.7,1.64058897063828], +["1lf5",1.7,2.21748477594242], +["1zd9",1.7,1.67321985383824], +["1y63",1.7,1.54645267395285], +["1yck",1.7,2.80290108458583], +["1nqz",1.7,2.55345273545469], +["1kao",1.7,2.10083790040816], +["1oix",1.7,2.26378589836263], +["1ymd",1.7,1.32475856990509], +["1yml",1.7,1.71650105943690], +["1czn",1.7,1.13654739134884], +["1ymk",1.7,1.69477943024974], +["1f5f",1.7,2.77709212693112], +["1r03",1.7,1.54389231337103], +["2fck",1.7,2.4786174307751], +["1j54",1.7,1.41560026985231], +["1jyd",1.7,2.66323010040026], +["1ng2",1.7,2.17542434888547], +["1fzq",1.7,2.33289657618973], +["1hbq",1.7,2.87611566335682], +["1kdk",1.7,3.04407466323825], +["2fd5",1.7,2.00905655908103], +["1wnz",1.7,2.60624122206404], +["1eiz",1.7,1.82529868779795], +["1sl8",1.7,1.47857130941409], +["1ytq",1.7,1.64749544386684], +["2c2q",1.7,2.1121930013985], +["1ay7",1.7,1.93542704090867], +["1q2h",1.7,1.54165694843793], +["1ryb",1.7,2.23567839365205], +["1ido",1.7,2.61969235861993], +["1kso",1.7,1.95529108747862], +["1xxn",1.7,2.19408421206157], +["1knb",1.7,2.69867512176832], +["1mol",1.7,2.15405926545244], +["8dfr",1.7,2.93210880104783], +["2f8o",1.7,1.22367436495763], +["2gen",1.7,1.84980009452984], +["1txl",1.7,2.65756771748924], +["1hz6",1.7,1.39403624358666], +["1i9t",1.7,1.72568383503371], +["1i70",1.7,1.43169513084408], +["1gmp",1.7,1.73907974775040], +["2aia",1.7,2.01526571180943], +["2aie",1.7,1.98407507019185], +["1kid",1.7,1.76720782623057], +["1t56",1.7,1.92693596308050], +["1juv",1.7,2.12629018297149], +["1qoa",1.7,1.86830901765704], +["1z4m",1.7,1.83473748687305], +["1qf9",1.7,2.37723720503043], +["1iue",1.7,2.20272963269182], +["1r1t",1.7,1.78494449809646], +["1nkr",1.7,2.52622718872647], +["1r8m",1.7,1.87314324517333], +["1dif",1.7,1.50453554969636], +["2bbb",1.7,1.92343742567277], +["1ida",1.7,2.64931672888687], +["2alp",1.7,2.04893027036709], +["1upi",1.7,2.27328446048823], +["1ffi",1.7,1.49645939260372], +["1z3q",1.7,1.28383816013141], +["1sgw",1.7,0.979593389877052], +["1k2b",1.7,2.17803732671801], +["2et7",1.7,1.89800311779873], +["1e2g",1.7,1.80894634107331], +["1yqh",1.7,1.26369476143796], +["1e9b",1.7,1.72814626579436], +["1e2q",1.7,1.86158689167030], +["1nmx",1.7,1.6678678938437], +["1e9d",1.7,1.778087539733], +["1yc1",1.7,2.52578204238457], +["1azo",1.7,2.50636306881576], +["1xsv",1.7,1.69196695842661], +["1cvz",1.7,1.68877343728259], +["1pg6",1.7,2.16089552239314], +["1j02",1.7,1.90429701626699], +["1wab",1.7,2.74573790974820], +["3bc2",1.7,2.86408127726989], +["1emv",1.7,2.06689220866586], +["1orn",1.7,1.7923115392032], +["1pip",1.7,2.77821893776523], +["1yal",1.7,2.08442486094705], +["1bww",1.7,2.29345133889612], +["1dae",1.7,1.73950465376198], +["1b4p",1.7,2.85873939628745], +["1mz9",1.7,2.79480793089538], +["2act",1.7,1.89410360083725], +["2a6b",1.7,1.0556123170877], +["1f50",1.7,2.62505998111845], +["1pbt",1.7,1.93286887362780], +["1p3q",1.7,2.83937001957995], +["1igq",1.7,2.08161461143313], +["1rdl",1.7,1.57129524278464], +["1rdo",1.7,1.63102716989453], +["1n5s",1.7,2.00704129734366], +["1utl",1.7,1.65600411789280], +["2awm",1.7,2.08602081209009], +["1sgt",1.7,1.67670123951182], +["1y3x",1.7,1.80224455183280], +["1s81",1.7,1.46640576189747], +["1tpo",1.7,1.76834452679585], +["1c2f",1.7,2.11784520191595], +["1o36",1.7,1.96489772436162], +["1tx8",1.7,1.52423337287312], +["3ptb",1.7,2.27201158366907], +["3ptn",1.7,2.26959609589559], +["2tgt",1.7,2.42622411785032], +["1tgt",1.7,2.5080275522238], +["1rxp",1.7,2.05827370286050], +["1v2r",1.7,1.97334483485668], +["2b77",1.7,1.83714831810221], +["2msb",1.7,1.79365825395299], +["1daf",1.7,1.51073554806805], +["1h4w",1.7,1.65603448351903], +["1kqj",1.7,1.31234120130413], +["1x8g",1.7,1.56077079908318], +["1osy",1.7,2.28439749794463], +["1mfa",1.7,1.83042208428137], +["2f6r",1.7,1.96994675380067], +["1j1y",1.7,1.42345733166795], +["1y1d",1.7,2.14524021326580], +["1ijn",1.7,1.71691305186153], +["1o1y",1.7,1.25854830528027], +["2axc",1.7,1.51015362671999], +["1zj4",1.7,1.92912666016426], +["1zj5",1.7,1.95662623258468], +["1ds2",1.7,1.90498664206609], +["1tmi",1.7,2.30964146856393], +["2bka",1.7,1.66357728927338], +["1n6a",1.7,2.26357170800636], +["1zic",1.7,1.84425514271218], +["1zi6",1.7,1.84727687460688], +["2bjv",1.7,1.41480725840998], +["1etb",1.7,2.06896794913022], +["1z3y",1.7,1.13174753832513], +["1p28",1.7,1.88439002357741], +["1spj",1.7,1.40836951530368], +["1wxj",1.7,1.81312238197605], +["2d2e",1.7,1.96365017922568], +["1b2p",1.7,2.40984980704671], +["2ax8",1.7,2.01342727990964], +["1dq0",1.7,1.62477901150062], +["1bec",1.7,2.78954110634679], +["1ecs",1.7,2.49857949781397], +["1y52",1.7,1.84897933487882], +["2br6",1.7,1.94797383329671], +["1gz9",1.7,1.84385905121442], +["1rxk",1.7,1.97862009273888], +["1hay",1.7,1.75185513171389], +["1qgf",1.7,1.50706550184983], +["1hv7",1.7,1.39984539034006], +["1lka",1.7,1.54888241033028], +["1lkb",1.7,1.60904174511478], +["1e38",1.7,1.58518319234135], +["1e36",1.7,1.78668588141012], +["1elf",1.7,2.06292705418416], +["1fv0",1.7,1.93408758256136], +["1y4l",1.7,2.77842673825593], +["1vr9",1.7,1.6777959875951], +["1t1j",1.7,1.46292765829979], +["1n0w",1.7,1.39840643281005], +["1fdr",1.7,1.88565143869105], +["1u9d",1.7,2.44957079427130], +["1f5w",1.7,1.76016521814125], +["3lyn",1.7,2.59971063312199], +["1xp6",1.7,2.92630944928514], +["1afl",1.7,2.411284178058], +["1afk",1.7,2.10121327455759], +["1qhc",1.7,2.99197354615568], +["1v6t",1.7,1.92124384494469], +["1tcs",1.7,2.75063934237985], +["1gis",1.7,2.26985982874184], +["1uog",1.7,2.39867989643276], +["1h03",1.7,2.14032940764339], +["1zki",1.7,1.30661791558761], +["1m2g",1.7,2.16030053820237], +["1m2j",1.7,2.52312152336941], +["1vcd",1.7,1.68701300008037], +["1fa8",1.7,1.95527639036158], +["1eta",1.7,3.16155711315852], +["1zps",1.7,1.72643100452921], +["1v9f",1.7,2.14409573977477], +["1t7t",1.7,1.42064208951684], +["1zs9",1.7,2.10527865823499], +["1tsh",1.7,2.78641130054108], +["1tta",1.7,2.93078513894671], +["1ttc",1.7,3.48547938853661], +["1ttb",1.7,2.63918563917662], +["1eye",1.7,2.78303741806819], +["1lpd",1.7,2.11380925626932], +["1yns",1.7,2.90587236958101], +["1lpc",1.7,1.91173418935870], +["1p99",1.7,1.97223013869488], +["1vdp",1.7,2.35964056639282], +["1m33",1.7,2.09384590714560], +["1mua",1.7,2.40633487728695], +["1sck",1.7,1.6789004313852], +["2a14",1.7,1.14129373319071], +["1cam",1.7,1.89538647551078], +["1yo1",1.7,1.78074241744463], +["2bb7",1.7,1.77234135945781], +["2f5g",1.7,2.5202081770658], +["2evm",1.7,2.18392785252394], +["1ev5",1.7,1.98173637305239], +["1c24",1.7,2.27014785398735], +["1erm",1.7,2.30642115364778], +["1fqg",1.7,2.55215399252573], +["1vp6",1.7,2.06570158568321], +["1y7r",1.7,2.47027266031089], +["1gzw",1.7,1.97099134222567], +["2aio",1.7,2.04001375831673], +["1sml",1.7,2.48534570219172], +["1cg6",1.7,1.36654535867604], +["1cb0",1.7,1.38771055736752], +["2fy7",1.7,2.04431767392692], +["1p9a",1.7,2.40818759602355], +["1fy8",1.7,2.03088414883700], +["1uek",1.7,2.14713684254990], +["1urx",1.7,1.50358699038287], +["2ai3",1.7,2.18146840477528], +["1ako",1.7,1.95419985585683], +["3tgk",1.7,1.98943577674366], +["1ia8",1.7,3.00211500018875], +["3lck",1.7,1.65023667732922], +["1ub4",1.7,2.12077090609987], +["1zxt",1.7,2.09869301528379], +["1jye",1.7,2.05602253745283], +["1uk7",1.7,1.36402771754997], +["1uka",1.7,1.51934435651820], +["2ev6",1.7,2.22997497088768], +["2ai2",1.7,1.90513113107663], +["1sc0",1.7,2.07932326405306], +["1o0i",1.7,2.39444635778931], +["1uar",1.7,1.84911845061552], +["2a88",1.7,1.59210523068941], +["1s01",1.7,1.18676817727668], +["2a7x",1.7,1.49301202775222], +["1j30",1.7,1.80439791635646], +["1uu3",1.7,1.31904022607902], +["2a5s",1.7,2.1668699460066], +["1f2o",1.7,1.52954605800806], +["1u1v",1.7,1.33630073841920], +["1uob",1.7,2.42496354137057], +["1jy0",1.7,2.21367064019786], +["1aqz",1.7,2.68812715549825], +["1fds",1.7,2.10437002522179], +["2axy",1.7,1.90779647311913], +["1mjh",1.7,1.46646081097306], +["1m16",1.7,2.29572787877926], +["2aq6",1.7,1.93037747087808], +["2bjn",1.7,2.52774369013345], +["1nrw",1.7,1.89706242618019], +["1yrw",1.7,1.54979358843484], +["1lgt",1.7,1.62286091389047], +["1aoh",1.7,1.84395522125486], +["2hbi",1.7,1.47556550302034], +["2av3",1.7,1.70181551717262], +["1hbi",1.7,1.90741187614238], +["1yoc",1.7,2.05846052158798], +["1i3d",1.7,2.09223112806465], +["1jm0",1.7,2.47912337667685], +["1ks9",1.7,2.00702487054733], +["2eun",1.7,1.78401175683908], +["1vfj",1.7,2.09188769455208], +["2cyp",1.7,2.17817559678252], +["1yi9",1.7,2.85272150737992], +["1lf1",1.7,2.37694568079200], +["1kok",1.7,1.61006523307574], +["1go2",1.7,1.93466470061416], +["1qgy",1.7,2.10413315820874], +["1elv",1.7,1.77528322226863], +["1fnb",1.7,2.49252005580011], +["1fnd",1.7,2.24194578095187], +["1x2r",1.7,2.37953394567729], +["2f6v",1.7,1.85537700249521], +["2f6z",1.7,1.90046730714031], +["2f6t",1.7,1.74093561954305], +["1wdv",1.7,1.53426168799453], +["1izc",1.7,1.86741537436235], +["1e9p",1.7,1.72727151035857], +["1doj",1.7,2.86245476562959], +["1xfs",1.7,2.07093556405789], +["1e0v",1.7,1.18264298409313], +["1gor",1.7,1.75313681403408], +["1mwc",1.7,1.76983898846275], +["1f9u",1.7,2.87986129970807], +["1abe",1.7,2.23579678669969], +["1xiv",1.7,1.32292805854633], +["1ee3",1.7,1.54842215075037], +["1jb9",1.7,2.32160812818839], +["1nty",1.7,1.60490919399051], +["1h58",1.7,1.54153710809810], +["1ltm",1.7,1.75550346295641], +["1u4o",1.7,1.41159463242733], +["1j8t",1.7,1.88791255218055], +["1q9e",1.7,1.86243441942775], +["1dde",1.7,2.09740406798884], +["1gwt",1.7,1.51170670267786], +["1gca",1.7,1.65144821077429], +["2bw0",1.7,1.96670593113904], +["1sbp",1.7,1.98965172851797], +["1qus",1.7,1.43542218746976], +["1zs4",1.7,2.10792276814937], +["1mk4",1.7,2.25674507568824], +["1ogq",1.7,2.45289766640881], +["1qge",1.7,1.75174794092601], +["2f2t",1.7,1.08481644253644], +["2ffc",1.7,1.92993885338677], +["1t24",1.7,1.77464768162465], +["1ysb",1.7,1.81811049432816], +["1s2a",1.7,1.53176401641165], +["1frb",1.7,2.08112005303637], +["2b5g",1.7,2.27136399441055], +["1fjq",1.7,1.77506468941724], +["1ks7",1.7,1.49154097657527], +["1hyt",1.7,2.01388281149091], +["1kro",1.7,1.5783762005434], +["1zdp",1.7,2.53105341328831], +["1z9g",1.7,2.57334184137685], +["1pe5",1.7,2.27413255650438], +["2fqx",1.7,2.15543790074217], +["4tmn",1.7,2.47017516681003], +["1thl",1.7,2.51893045449748], +["1lnd",1.7,2.06328692288541], +["1lnf",1.7,2.12978137796997], +["1lne",1.7,2.19286836844663], +["3tmn",1.7,2.46492683190278], +["4dfr",1.7,2.65215713629943], +["1zd7",1.7,1.85356380370627], +["2fa1",1.7,2.46556588507071], +["1el3",1.7,2.32285918402108], +["1jw9",1.7,2.01811678053843], +["1syy",1.7,1.94010060021694], +["2d80",1.7,1.68667007745655], +["1v71",1.7,2.27325427542597], +["1p5v",1.7,2.09036963491581], +["2abh",1.7,1.98657290739185], +["1qul",1.7,1.93005113751550], +["1a40",1.7,2.1822276901485], +["1ti7",1.7,1.75409235296743], +["1b20",1.7,1.69483287041862], +["1i7h",1.7,2.01419315193336], +["1o6k",1.7,1.52696242306311], +["1ppm",1.7,1.72647857057944], +["1ppl",1.7,1.96408135423259], +["1yle",1.7,1.74301988779389], +["1w9q",1.7,1.77207798189087], +["2c7p",1.7,1.69743187682493], +["1m2r",1.7,2.13701890454376], +["2f6l",1.7,1.51589870045045], +["1k94",1.7,1.52499162790966], +["1nrj",1.7,1.9512082613482], +["1v9t",1.7,2.65888756514871], +["1z57",1.7,1.25744910001242], +["2ery",1.7,1.32764364454764], +["1mxe",1.7,1.93381959728951], +["1xuc",1.7,1.79475805665536], +["1ne9",1.7,1.75835275823367], +["2a5l",1.7,1.90729124991236], +["2gc9",1.7,1.43169665686038], +["1d1i",1.7,1.30264385442556], +["1et7",1.7,1.84806881033119], +["1xfi",1.7,1.92548921446758], +["1l4b",1.7,2.10019310621723], +["1jx4",1.7,2.39567543353104], +["1dgw",1.7,3.11981076569682], +["1tm4",1.7,1.49244215882564], +["1tm1",1.7,1.34368447065010], +["1llp",1.7,1.81867811786034], +["1z15",1.7,2.01495786664893], +["2bky",1.7,2.20835124500337], +["1uac",1.7,3.20468636216663], +["1f6b",1.7,2.49242090669897], +["1ppv",1.7,2.35621215777595], +["1oio",1.7,2.19174630321961], +["1t6e",1.7,1.96267848867118], +["1r3t",1.7,1.70811550144614], +["1r3w",1.7,1.71436140295201], +["1r3q",1.7,1.62883169621428], +["2aso",1.7,1.69041493905409], +["1j83",1.7,1.71798708813507], +["1qcx",1.7,2.05219524659360], +["1mdo",1.7,2.03494626183257], +["1pxg",1.7,1.95146598274020], +["1vlo",1.7,1.15211834057550], +["1oc5",1.7,1.42107783431267], +["1jq5",1.7,1.52712806882602], +["1p0b",1.7,2.24061246198617], +["1wk8",1.7,2.64916688400957], +["1qd9",1.7,1.96600234611403], +["1u17",1.7,2.48365666253405], +["1h6f",1.7,2.22571009197419], +["4mbp",1.7,3.07579012832668], +["3mbp",1.7,3.01015486219356], +["1lfk",1.7,1.88104686565311], +["1pe0",1.7,1.90839635956092], +["1k4g",1.7,2.28670806672613], +["1fvk",1.7,1.96328223101694], +["1gvy",1.7,1.41104642853245], +["1flt",1.7,2.48943210502898], +["1vjo",1.7,1.82980909579073], +["2b8l",1.7,1.77949533626429], +["1fzk",1.7,1.71934810242996], +["1hpm",1.7,1.60158972060377], +["1kay",1.7,1.63242020403296], +["2bup",1.7,1.52281571231514], +["1bup",1.7,1.49123516389481], +["1ba1",1.7,1.79780758801490], +["1kax",1.7,1.73240276958042], +["1kaz",1.7,1.68830429363354], +["1n2r",1.7,1.99538498244156], +["1syv",1.7,2.04646896493620], +["1rvk",1.7,2.42920092473691], +["1hjz",1.7,1.51332007045728], +["1vjp",1.7,1.82249769200589], +["1zsd",1.7,1.77671019193616], +["1ia1",1.7,2.24460869186631], +["1m79",1.7,2.00740338271143], +["2ccj",1.7,1.68780030716004], +["1xii",1.7,1.79615737640913], +["1xij",1.7,1.98565595338005], +["1xig",1.7,2.1197779704374], +["1xih",1.7,2.12387374752635], +["2bnm",1.7,1.70824780420401], +["1xid",1.7,2.06784586503785], +["1xie",1.7,2.32435173531610], +["1cgz",1.7,2.16210903178260], +["2qwa",1.7,2.05368125026247], +["1f8c",1.7,2.31733591785316], +["1mwe",1.7,2.25673590411334], +["1pm9",1.7,2.03948998976178], +["1d02",1.7,1.72875905372410], +["2as9",1.7,2.44151066556107], +["1jhd",1.7,1.60878568160869], +["1xi3",1.7,1.12860483791128], +["1jne",1.7,2.39782865847624], +["1fva",1.7,3.01272558721671], +["1ehg",1.7,1.60499178499749], +["1cmn",1.7,1.96145357619631], +["1ehe",1.7,1.97759686402347], +["1cl6",1.7,1.98796904710506], +["1cmj",1.7,2.00206215105739], +["1ehf",1.7,2.00404546948838], +["1exm",1.7,2.07544199218085], +["2fer",1.7,1.83599846478208], +["1yrd",1.7,2.05006718464309], +["1gek",1.7,2.72782418303287], +["1pb3",1.7,2.29342887970224], +["1pb1",1.7,2.27623447183376], +["1eyn",1.7,1.7140956935064], +["2uag",1.7,1.48999940967093], +["1u5d",1.7,2.20973863762313], +["1csc",1.7,3.04912742135263], +["2csc",1.7,3.18607176446883], +["1rzf",1.7,1.64978392200731], +["1zan",1.7,2.32400579175449], +["1so4",1.7,1.52454097699242], +["1m6d",1.7,2.173811745748], +["2bc2",1.7,2.05780424592861], +["1mi4",1.7,1.66203824193272], +["1icr",1.7,1.61843449205631], +["1z3t",1.7,1.31437696707079], +["1z3w",1.7,1.65654755026434], +["1ylr",1.7,1.28075105743429], +["1tuo",1.7,2.32661433681492], +["2ajs",1.7,2.15196556106045], +["6cel",1.7,1.40110806295762], +["1q72",1.7,1.98786805792363], +["1css",1.7,2.62815321154727], +["1csi",1.7,2.67519105591709], +["1csr",1.7,2.79855194926344], +["2aef",1.7,2.30993842299147], +["2avd",1.7,1.83041285153748], +["1pvy",1.7,2.47648096317033], +["1ynl",1.7,2.22779409005566], +["1zhw",1.7,1.72073464445395], +["1wpv",1.7,2.39258849186564], +["1d2i",1.7,2.26350587182876], +["2bwv",1.7,1.12487245040519], +["2bwx",1.7,1.05978315394676], +["1pmi",1.7,2.57153568343921], +["1eq9",1.7,2.43846695333573], +["1swh",1.7,2.79013861277055], +["1kyt",1.7,2.07943656806432], +["1fj0",1.7,1.25388763163479], +["1g4s",1.7,1.72819969288938], +["1xkp",1.7,1.92473141551015], +["2ltn",1.7,2.5516411164994], +["1cjc",1.7,1.95776105649919], +["1v58",1.7,1.61130123867763], +["1ewf",1.7,2.83605324773572], +["1nbx",1.7,2.51290731130254], +["1gsn",1.7,2.05176423511934], +["1l2q",1.7,1.78309746967394], +["2a52",1.7,2.28110091743672], +["2hlc",1.7,1.89140241253219], +["1n4x",1.7,2.56012494974192], +["1dnc",1.7,2.07153906236178], +["1fon",1.7,2.64510241261431], +["1n68",1.7,2.29240374635931], +["1twd",1.7,2.19409006950249], +["1e42",1.7,2.18805285035017], +["1vjs",1.7,2.44705845158076], +["1x7i",1.7,2.46813879479633], +["1nqm",1.7,2.33491035263861], +["1htw",1.7,3.08041024902019], +["1kl4",1.7,2.08444333990377], +["1gai",1.7,1.11098777044206], +["1w1o",1.7,1.36260805923536], +["1nms",1.7,1.83734179421617], +["1t6v",1.7,1.30877880464700], +["1qhf",1.7,1.82767342007842], +["1ukg",1.7,1.58935804011881], +["1ofl",1.7,1.89183098867092], +["1dbo",1.7,2.32448823824399], +["1dbg",1.7,2.41914180670926], +["1agj",1.7,2.61204064789568], +["1e43",1.7,1.83229445623863], +["1v10",1.7,3.60000587117935], +["1qq7",1.7,1.74604789407165], +["1v0v",1.7,1.71788446781417], +["1v0r",1.7,1.71325291502149], +["1kl3",1.7,2.20830713495376], +["1f0v",1.7,2.42084155085857], +["1lj8",1.7,1.50791483351163], +["1ayx",1.7,1.84017278892295], +["2ai8",1.7,1.46025841787151], +["1ohs",1.7,2.20516999868499], +["1rxy",1.7,1.28691470848706], +["1w9b",1.7,1.7326961732705], +["1mgq",1.7,2.14648460419807], +["1mo0",1.7,1.72583683400489], +["1r12",1.7,1.90388559732389], +["1gsk",1.7,1.88554187552772], +["2ddf",1.7,1.62827139551194], +["1kzq",1.7,2.22192763483929], +["1txn",1.7,2.30203582461199], +["1lt5",1.7,2.33464166102853], +["1eqj",1.7,2.90058805564022], +["1i2s",1.7,2.68061716741737], +["1gkj",1.7,2.48695780977241], +["1i2w",1.7,2.83762059824892], +["1oa8",1.7,2.14868475418721], +["1hqq",1.7,1.82141420051618], +["1xng",1.7,1.82160990852364], +["1hp1",1.7,1.57376778522513], +["2evo",1.7,2.06561460374858], +["1ymx",1.7,1.59163348037999], +["1ylh",1.7,1.50686795999143], +["1axw",1.7,1.70806775442517], +["1gx5",1.7,2.14163992306018], +["1deu",1.7,2.28755954249470], +["2cxx",1.7,1.99445787662021], +["1w4x",1.7,1.72109534874212], +["1pfv",1.7,1.78559573713942], +["1yqv",1.7,1.60236897535941], +["1wmz",1.7,1.26739113530319], +["1bkp",1.7,2.13853178182551], +["2g0w",1.7,1.52959973524151], +["1jtc",1.7,2.46295661634378], +["1s5a",1.7,1.94434238266488], +["2fex",1.7,1.65808911714053], +["1jt7",1.7,2.32725303286363], +["1t82",1.7,1.94960416307112], +["1iho",1.7,1.84187426176296], +["1n2b",1.7,1.48986773577525], +["1qxm",1.7,1.85499127985560], +["2d60",1.7,1.92535616758360], +["1j7y",1.7,1.83218457705171], +["1qsi",1.7,2.03738598055570], +["1qsh",1.7,2.11130102270921], +["1bbb",1.7,2.5759937026139], +["1n2i",1.7,1.41294316877845], +["1g3m",1.7,1.99042369736135], +["1ta3",1.7,1.62517321801666], +["1v4w",1.7,2.31349704609186], +["1t8o",1.7,1.3433955132003], +["1nk0",1.7,1.59051612129074], +["1l3t",1.7,1.91201834611802], +["1xwl",1.7,2.41564867951907], +["1bf6",1.7,1.91734399606057], +["1ugw",1.7,1.79346147585108], +["2g76",1.7,1.37737525162329], +["1w8o",1.7,1.47252745361029], +["1qfz",1.7,2.40850428582444], +["1erz",1.7,1.76705494167511], +["2biv",1.7,1.69912797634974], +["1nr0",1.7,1.83854384056247], +["1e2k",1.7,2.27843704942023], +["1d3v",1.7,2.20814522423965], +["1zgd",1.7,2.09879330721366], +["1dmh",1.7,2.35036180938310], +["1sii",1.7,1.46459879328379], +["1wnw",1.7,2.07758183780778], +["1jqx",1.7,2.02051004237689], +["1xcr",1.7,1.60460214492539], +["1fd4",1.7,3.08536517680400], +["1s18",1.7,1.75840325811561], +["1odt",1.7,2.22014128711106], +["2etv",1.7,1.70916910677579], +["2ags",1.7,2.06354647506544], +["1gof",1.7,2.24328183684937], +["1o7g",1.7,2.22404126686695], +["1k7x",1.7,2.20663232643739], +["1qd1",1.7,1.69709188124643], +["1l6s",1.7,2.34085245062718], +["1k0r",1.7,2.48452197443066], +["1k8z",1.7,2.91086896695727], +["1w56",1.7,1.76611972658301], +["1y2d",1.7,1.16211520067943], +["1ydy",1.7,2.18350851235178], +["1xdh",1.7,2.31580091373350], +["4pga",1.7,2.46767955717751], +["1k3u",1.7,1.72413747023895], +["1obf",1.7,1.31680966952257], +["2cwh",1.7,1.81115698616619], +["1txg",1.7,1.83303090691824], +["1k9d",1.7,1.55745714048517], +["1r6v",1.7,2.49438335611503], +["1j79",1.7,3.09481083601475], +["1xik",1.7,2.75804663083559], +["1qho",1.7,1.38926644656619], +["1qhp",1.7,1.39743833763883], +["1pxz",1.7,2.70128372838952], +["1rxq",1.7,1.99138752891345], +["2bcn",1.7,3.03086294050359], +["1wy2",1.7,1.95825429203807], +["1e5t",1.7,1.34712377933418], +["2bvw",1.7,1.96108510165734], +["1vg8",1.7,1.77821354679298], +["1c82",1.7,2.73076819154549], +["2c5e",1.7,1.76851310365736], +["1gu7",1.7,1.64771251287539], +["1wo8",1.7,2.05070445561266], +["1zy7",1.7,1.93784608708084], +["1jd1",1.7,2.24182970780282], +["1sg6",1.7,2.28391388061404], +["1ftm",1.7,1.94260443286599], +["1nsc",1.7,2.08087065169726], +["1iyh",1.7,1.81937921569061], +["1w9p",1.7,1.42338291707333], +["1t2b",1.7,2.28129009222432], +["2ahj",1.7,1.73136649500223], +["2feu",1.7,2.03936121456944], +["2bnq",1.7,2.37168758750701], +["1ut1",1.7,2.53531157776403], +["2bii",1.7,1.84476535842992], +["1g24",1.7,2.48549427126886], +["1yum",1.7,3.21634585381389], +["1rff",1.7,2.23348794303174], +["5rub",1.7,3.19993982160044], +["1yki",1.7,1.42053275834610], +["1vcl",1.7,1.28761248490263], +["1oa3",1.7,1.86264865851989], +["1upt",1.7,1.82099176573466], +["1a0j",1.7,1.91243325917429], +["1km0",1.7,1.61917855963606], +["1pby",1.7,2.58927103737982], +["1j8f",1.7,2.74724109882147], +["1p3d",1.7,1.695232266666], +["1ooy",1.7,2.20526498855470], +["1zpe",1.7,2.16109513150165], +["2fzv",1.7,1.81463449933438], +["1tad",1.7,2.15757457706364], +["1k56",1.7,2.21515746143429], +["1v00",1.7,2.07593650730056], +["1k54",1.7,1.84822257710164], +["1fec",1.7,2.26531626408259], +["1e6w",1.7,2.49949582221809], +["1z0s",1.7,1.91681836379626], +["1oja",1.7,1.63440432616626], +["2c65",1.7,1.55187791300058], +["2c67",1.7,1.69798950860233], +["1o6i",1.7,1.94706861705283], +["1e6p",1.7,1.99882692924625], +["1duv",1.7,2.19797086092071], +["1l9o",1.7,1.85773961545744], +["1l9q",1.7,1.94282601495564], +["1xe0",1.7,2.60482771565773], +["1s5u",1.7,2.26445053364523], +["1f3u",1.7,2.74260503485578], +["1p1j",1.7,2.07963093324821], +["1gco",1.7,1.83575044169418], +["1i19",1.7,1.64160541266985], +["2dbx",1.7,1.89428864017792], +["1d4a",1.7,2.79183357350745], +["1q74",1.7,1.21650820722351], +["1g0o",1.7,1.55949237242146], +["1q8a",1.7,2.45410048143749], +["1u0g",1.7,1.98391864365579], +["1lvw",1.7,1.95634421855962], +["1w3i",1.7,2.02511756335264], +["1ftr",1.7,1.85627911063487], +["1a12",1.7,2.27202222658600], +["1m9x",1.7,2.43611293566584], +["1ga2",1.7,1.90170686108024], +["1q8f",1.7,1.73864432996252], +["1jsl",1.7,1.93388691273752], +["1jsr",1.7,1.74705726488464], +["1gqg",1.7,1.64643499940347], +["1w27",1.7,2.54650909446610], +["2c5q",1.7,1.99500360437628], +["1gc0",1.7,2.29286232051154], +["1mwv",1.7,1.72938649386931], +["1pu0",1.7,2.07733947219843], +["1xes",1.7,1.83836964214544], +["2al4",1.7,1.85938743698707], +["1m3k",1.7,2.52886593044296], +["2fjb",1.7,1.99684852534777], +["2byw",1.7,2.07370178090084], +["1i7o",1.7,2.35596367242756], +["1gtt",1.7,2.02426766172573], +["1uqr",1.7,1.87561603007974], +["1eex",1.7,2.75031499857736], +["2cb2",1.7,1.62032720591183], +["1t0b",1.7,1.87097826236642], +["1qmv",1.7,1.61174934571466], +["1nhc",1.7,1.90809481133432], +["1geg",1.7,1.75751198182973], +["1mty",1.7,2.65729218826463], +["1zxi",1.7,1.90694047826447], +["1nvm",1.7,1.72872940397486], +["2c6q",1.7,1.65624903761971], +["1pn0",1.7,1.76164454341274], +["1dp0",1.7,2.26633040975143], +["1y81",1.7,1.93870738751102], +["2a9d",1.7,1.77058223759166], +["1xzo",1.7,3.35325268759063], +["2exr",1.7,1.42124839936747], +["1eoe",1.7,1.85170725118970], +["1yqc",1.71,2.75810479535169], +["1mid",1.71,1.83599013237286], +["1bm8",1.71,2.09482741157152], +["1sf9",1.71,1.87544673687865], +["1gyv",1.71,1.96006924858197], +["1kxx",1.71,2.02439811579071], +["104m",1.71,2.01697605767935], +["2bit",1.71,1.86533771990720], +["2biu",1.71,1.92237579512748], +["1g81",1.71,2.31212491773193], +["1d0q",1.71,2.67766863698957], +["1ywf",1.71,2.06195809943319], +["1ywn",1.71,1.41032937903256], +["1mlw",1.71,1.6970246952663], +["1gt1",1.71,2.22102710462062], +["2fqw",1.71,2.02168850203621], +["2ahk",1.71,2.13553770048878], +["1gwy",1.71,2.29570902662861], +["1kpv",1.71,1.6914748076968], +["1uxw",1.71,1.46766270581738], +["1m78",1.71,2.05428494991038], +["1dje",1.71,2.54935192563033], +["2xis",1.71,1.83023633992383], +["1uz4",1.71,1.31713507029936], +["1gxy",1.71,1.77982978885883], +["1jmk",1.71,2.4046989519236], +["1v0y",1.71,1.42633540607619], +["1sw0",1.71,2.19541476781391], +["1r88",1.71,1.57808891042482], +["1l3v",1.71,1.91580809448429], +["1o07",1.71,1.75225643101251], +["1s0a",1.71,2.15545300560342], +["1tw9",1.71,2.37731695719119], +["1z7a",1.71,1.86308270350880], +["1z8k",1.71,1.37178886262135], +["1tw6",1.71,1.41510540120795], +["1r1g",1.72,1.77477040273318], +["1lom",1.72,2.20586021123573], +["2fke",1.72,1.53056203585909], +["1fkd",1.72,1.36958579196815], +["1mkt",1.72,2.62094824091325], +["1cpq",1.72,1.68319194799266], +["1h87",1.72,1.44388168908639], +["1ey9",1.72,3.27109854131003], +["1ii3",1.72,3.04455860049942], +["1ziq",1.72,2.08864619095071], +["1v3z",1.72,1.67412572787981], +["1jf2",1.72,1.64508867096952], +["1meo",1.72,1.25485528660038], +["1qrg",1.72,1.95124009897560], +["1p3e",1.72,1.84343916851862], +["2a47",1.72,2.08611378846500], +["1v2s",1.72,1.70593055717635], +["1lys",1.72,2.83271866418528], +["2yas",1.72,1.54273986176119], +["2gdn",1.72,1.92178253762209], +["1tzx",1.72,2.17538394512516], +["1rwr",1.72,1.74898007070647], +["1bqb",1.72,2.11803982261002], +["1fh9",1.72,2.01648642881065], +["1i6l",1.72,2.18244192889636], +["1i6m",1.72,2.18906721529882], +["1i6k",1.72,2.30323776705259], +["1wa2",1.72,1.42232182397650], +["1y3f",1.72,1.63745308661512], +["1z16",1.72,2.32101741414616], +["1uqy",1.72,1.86198180549587], +["2b2f",1.72,2.45477691553057], +["1x2t",1.72,2.04203449242342], +["1nr4",1.72,2.34763274894283], +["1e1d",1.72,1.66241872909497], +["1m9e",1.72,2.47682658816189], +["2fds",1.72,2.04219652098086], +["1xon",1.72,1.45979898541015], +["1b5f",1.72,2.59498876554077], +["1ke4",1.72,1.76873273802823], +["1qip",1.72,1.86011890704128], +["1llb",1.72,1.70631899348826], +["1x7z",1.72,1.80755286775014], +["1qbi",1.72,2.11520244630132], +["2f5x",1.72,1.34990937525518], +["1b7d",1.73,2.41183480887636], +["3paz",1.73,2.79424428095382], +["2av4",1.73,2.09314368006199], +["1or3",1.73,2.58096617123159], +["1oaj",1.73,2.62329784060634], +["1yso",1.73,0.870385026211036], +["232l",1.73,2.44972813753673], +["1el4",1.73,1.7650945595162], +["1xl5",1.73,1.50380448171168], +["1zhr",1.73,2.17309429787909], +["1gjc",1.73,2.85256732060266], +["1m5d",1.73,1.77642169901991], +["1jvj",1.73,1.7501667018603], +["1y1e",1.73,1.26188798963425], +["2aik",1.73,1.47575098333780], +["1xjv",1.73,2.75997372445955], +["1gj5",1.73,2.59890226075332], +["1w34",1.73,2.17380960470015], +["1lii",1.73,3.22935355521195], +["1hg8",1.73,3.14637858562408], +["1c0l",1.73,2.41443403697033], +["2a9k",1.73,1.68715328212533], +["1xv5",1.73,2.17748588002418], +["1wmf",1.73,1.78184797709806], +["1ueh",1.73,1.98500922486019], +["1q9v",1.73,2.09574124149698], +["1ush",1.73,1.79461432849159], +["1fs5",1.73,2.62485727843735], +["1hl7",1.73,1.49461727861069], +["1hkh",1.73,1.65092607152609], +["1nqp",1.73,1.67076519517881], +["1m9f",1.73,2.01992885975882], +["1sih",1.73,1.47941852066689], +["2bt3",1.73,1.37483687143479], +["1b80",1.73,1.13845228246281], +["1x7w",1.73,1.87244495075271], +["2bi9",1.73,2.09285112136475], +["2bi5",1.73,2.19701860765813], +["1zru",1.73,2.01938983268043], +["1a2z",1.73,2.09885711503460], +["1vr5",1.73,1.27462578559507], +["2c31",1.73,2.18253614619476], +["2c62",1.74,2.04314580540863], +["1icn",1.74,2.30419578889407], +["1snm",1.74,3.30404462626546], +["1myt",1.74,2.60677749269381], +["1v8n",1.74,2.00921299014159], +["1im6",1.74,2.13004819852377], +["102l",1.74,2.17052080508636], +["1z4r",1.74,2.32529919548586], +["2fcb",1.74,2.29733963264726], +["1h4d",1.74,2.13461874337165], +["2etj",1.74,1.89025918388459], +["2ah5",1.74,1.65206341446589], +["1n5q",1.74,2.18420210514179], +["1kza",1.74,1.82570665612022], +["1jya",1.74,1.86389020773039], +["1ylw",1.74,1.87686337311153], +["1y2w",1.74,1.55952286330198], +["1ltu",1.74,2.32250037183391], +["3hhb",1.74,2.15828773546406], +["1kxm",1.74,2.27245812963925], +["1xvy",1.74,1.6779214134465], +["1ldg",1.74,2.07007716546411], +["1qf8",1.74,1.75299810542740], +["1vjv",1.74,1.38188832257329], +["1kfw",1.74,1.72868764664719], +["1q9t",1.74,2.45228160208919], +["1g94",1.74,1.51831370299077], +["1g60",1.74,2.04255429636570], +["1gwh",1.74,1.6147598678794], +["2f34",1.74,2.47039463673234], +["1zha",1.74,1.97702226281189], +["1xm8",1.74,1.51096553636999], +["1pe1",1.74,2.25141790034871], +["1pcf",1.74,1.57860980005193], +["2hhb",1.74,2.08702387378923], +["4hhb",1.74,3.92007455294165], +["1jiw",1.74,1.73893384389063], +["1px5",1.74,1.69844575190557], +["1q2o",1.74,1.85628734445316], +["1ajr",1.74,2.32237264526171], +["1ges",1.74,1.82442461076477], +["1r1n",1.74,3.20379281011932], +["1vjw",1.75,1.25854830528027], +["1k33",1.75,2.53305111947893], +["2spg",1.75,1.91530844216469], +["1kw4",1.75,1.34922769281048], +["1uj8",1.75,1.94926743221389], +["3hts",1.75,2.65139654033964], +["1okh",1.75,1.53148256512764], +["1j8b",1.75,2.62373601449986], +["1byp",1.75,2.55780615914987], +["1svy",1.75,2.16694844208423], +["1se0",1.75,2.54503314877373], +["1o4i",1.75,2.02006904829854], +["1f5c",1.75,2.49933118625052], +["1pvb",1.75,1.87620824131934], +["1o7s",1.75,2.0608378646247], +["1ikt",1.75,1.82877295183532], +["1gnu",1.75,1.97889320948031], +["1o3u",1.75,1.49081149764188], +["1rbe",1.75,2.03338757482002], +["1gsv",1.75,1.63699785597664], +["1f32",1.75,2.21887403587524], +["1vwp",1.75,2.40961312293419], +["1dyz",1.75,2.57010239963553], +["1dz0",1.75,2.57010239963553], +["1uih",1.75,1.32109392419143], +["1rfp",1.75,1.68209450577442], +["1iot",1.75,1.36514515245320], +["1hew",1.75,2.54508647029285], +["1yik",1.75,2.24289903956726], +["1lma",1.75,2.63435880869355], +["2ali",1.75,2.23157030980317], +["1mdc",1.75,1.64221419719220], +["1fe0",1.75,1.51972220221974], +["1vr8",1.75,0.930989043243292], +["1fe4",1.75,1.59591882318975], +["1ey8",1.75,3.12285444906433], +["1ey6",1.75,3.00972462753872], +["1bkb",1.75,2.16752827417608], +["5nll",1.75,2.06251693640045], +["2fk9",1.75,1.62965190037475], +["1r0u",1.75,1.89745794387152], +["1wk9",1.75,2.03731060116891], +["1k9u",1.75,1.98403096431183], +["1fuk",1.75,2.69782368184188], +["1xvq",1.75,1.83941503070484], +["1jv4",1.75,3.06610821556526], +["1qy2",1.75,2.62713441459892], +["1q42",1.75,2.05504906780103], +["1avs",1.75,2.86907586803085], +["1o9v",1.75,1.74704956175494], +["240l",1.75,1.62083487784104], +["166l",1.75,2.01164073235298], +["165l",1.75,2.20852454148908], +["1l90",1.75,2.03299151048484], +["1qud",1.75,2.20172301003185], +["1l59",1.75,1.78872332618200], +["1l63",1.75,1.9775764610704], +["1dyb",1.75,2.32656003069643], +["1kw5",1.75,2.30274511613399], +["206l",1.75,2.08667690585035], +["247l",1.75,2.16607584119586], +["1l41",1.75,2.29578957512691], +["1n0y",1.75,1.94523524590654], +["1ha1",1.75,2.7946342177899], +["1o9z",1.75,2.09638003492383], +["1xz1",1.75,1.87927241260580], +["1xz3",1.75,1.8877717746858], +["1g2p",1.75,1.88882141505340], +["1lhw",1.75,2.47511830753272], +["1wrd",1.75,2.05129926051284], +["1cv8",1.75,1.52319921246740], +["1xjt",1.75,2.56717017366886], +["1y0k",1.75,1.63514544907515], +["1ysq",1.75,1.60834059277256], +["1h0p",1.75,2.37095203616792], +["2c2p",1.75,1.92987120772494], +["1frw",1.75,2.24748374021879], +["1epz",1.75,2.02089586242694], +["1r8n",1.75,2.81145167647646], +["2atf",1.75,1.33064770716497], +["1wv3",1.75,1.7289013718937], +["1lm6",1.75,1.79276423129350], +["1s2z",1.75,2.05299442213891], +["1qyb",1.75,1.87116739559824], +["1bk7",1.75,2.25053600363006], +["1ym3",1.75,1.56774434651822], +["1d4l",1.75,1.90645901277762], +["1b6l",1.75,1.39432421174948], +["1ryn",1.75,3.51301713797626], +["1mtr",1.75,2.21004706604986], +["1z4k",1.75,1.67533238423587], +["1cub",1.75,1.83598104638097], +["1cuc",1.75,2.08631466126767], +["1xzm",1.75,1.82132219619056], +["1cuf",1.75,1.99840488704061], +["1cuh",1.75,2.08381650800076], +["1xzc",1.75,1.97584511070026], +["1ffc",1.75,1.67770921314045], +["1cug",1.75,1.77021504130567], +["1xze",1.75,2.22279872395517], +["1cux",1.75,1.88744034385022], +["1ffb",1.75,1.78238645567609], +["1xzb",1.75,2.12255696615588], +["1chd",1.75,2.10997417160837], +["1p3u",1.75,1.78529869526284], +["1r77",1.75,1.69974326122618], +["1xkr",1.75,2.39572835904553], +["1mix",1.75,1.63294741804646], +["2a7i",1.75,1.31733103134400], +["1thw",1.75,2.29343754462993], +["1thv",1.75,2.78008526709884], +["1kpt",1.75,1.79648648107014], +["1nmz",1.75,1.64736805486791], +["3cla",1.75,1.77743498653559], +["1ewp",1.75,2.07172404165534], +["1nn6",1.75,2.13717613741377], +["1nlr",1.75,1.97748016730352], +["1l2e",1.75,1.68243333578671], +["1y3y",1.75,1.96482007834098], +["1o3b",1.75,1.85258948028813], +["1tx7",1.75,2.45168177513192], +["1v2w",1.75,1.94888263436693], +["1qy5",1.75,2.44642372213376], +["1fhn",1.75,2.58368056051196], +["1udh",1.75,2.08381643584815], +["1udg",1.75,2.36803287474842], +["1wod",1.75,1.69670351706163], +["1amf",1.75,1.92139495307076], +["2br9",1.75,1.16104122542790], +["2sgf",1.75,2.06731030013526], +["1qwz",1.75,2.10686725432865], +["2a7a",1.75,1.80220685603907], +["1e37",1.75,1.93323414412801], +["1elc",1.75,2.30572443047884], +["2bjw",1.75,1.48790252493073], +["2fue",1.75,1.21618630815921], +["1d2n",1.75,1.78645242954993], +["1oag",1.75,1.97600430349619], +["1gi8",1.75,2.80810167905878], +["1e6f",1.75,2.50833662115693], +["1jjf",1.75,1.95561816559631], +["1c5x",1.75,2.8507664021721], +["1xfj",1.75,2.03175407482756], +["7yas",1.75,1.84813841138249], +["1gjd",1.75,2.22627971493437], +["2cx7",1.75,1.77361138809360], +["1lg5",1.75,2.46387101776271], +["1pv5",1.75,2.22222371360802], +["1c22",1.75,2.21759619144568], +["1wvj",1.75,1.79201990787800], +["1r7y",1.75,2.03091574846658], +["1jwp",1.75,1.70602919061692], +["1ny0",1.75,1.90061286197822], +["1zar",1.75,1.45934209235869], +["1f4b",1.75,1.76839732508810], +["1r81",1.75,2.34611635817149], +["1tvx",1.75,3.13819876311356], +["1dyt",1.75,2.45393871105832], +["1g6a",1.75,1.69172845358072], +["1xjo",1.75,1.90853549318042], +["1eg2",1.75,2.0546404387416], +["3bth",1.75,1.61284166486712], +["1umk",1.75,1.82196775963448], +["1bh6",1.75,1.74245523394986], +["1gqz",1.75,1.70917279090841], +["1a8q",1.75,1.5273266893303], +["1sub",1.75,1.4410792016674], +["1y21",1.75,1.98372057569225], +["1h8i",1.75,2.86320768404865], +["1ghw",1.75,2.56289442726014], +["1v96",1.75,2.31751005431456], +["1o5g",1.75,2.44707604921098], +["1suu",1.75,2.00056692503202], +["1nu3",1.75,1.27197431067379], +["2anz",1.75,1.45865460323816], +["1up0",1.75,1.38966509580223], +["1c1u",1.75,2.32666279193475], +["1szc",1.75,2.07622968980145], +["1r51",1.75,2.18961736901896], +["1k66",1.75,1.69839611966024], +["1us4",1.75,1.56097469732025], +["1e9q",1.75,1.72592119214947], +["1uuj",1.75,2.00916458154656], +["1b31",1.75,1.6565403221961], +["1bg4",1.75,1.57441951071717], +["1qi2",1.75,1.53330188074462], +["2cwk",1.75,1.62441142878905], +["1myg",1.75,3.07821433519577], +["1bap",1.75,2.42405580816844], +["1f57",1.75,1.67321941287414], +["1d9v",1.75,2.49139607192855], +["1wwz",1.75,2.02831234542692], +["1gq8",1.75,1.91487107595147], +["2f1f",1.75,2.89482897792335], +["2bcr",1.75,1.76952836953127], +["2d2j",1.75,1.92469545913178], +["2a9s",1.75,1.75485645534642], +["1y0r",1.75,1.97665147922574], +["1qwd",1.75,1.93898202182544], +["1ryf",1.75,2.04094825783985], +["1ryh",1.75,1.82121675489323], +["1lrk",1.75,2.06984909765783], +["2bjq",1.75,1.85543778515079], +["1eb3",1.75,2.15354429812077], +["1h7o",1.75,2.63918936147001], +["1g7j",1.75,2.16223872854843], +["2b0j",1.75,2.5092938265718], +["1evy",1.75,2.55550690436703], +["2bl0",1.75,1.87940964472590], +["1snt",1.75,2.40998623115237], +["1zsy",1.75,1.62399200308514], +["1gp6",1.75,1.55090843491676], +["1ne2",1.75,2.31259673501511], +["1p57",1.75,1.89799255176265], +["1o5e",1.75,2.15951213828001], +["1q66",1.75,2.19087732021848], +["1u7l",1.75,1.78002527479473], +["1beh",1.75,2.02470329053252], +["1waw",1.75,1.81423942695995], +["1j58",1.75,1.77623539625694], +["1w50",1.75,2.58172303048897], +["1leg",1.75,2.84657249372138], +["1h1a",1.75,1.77438916361509], +["2c1g",1.75,2.45466324541257], +["1avw",1.75,2.4383157803415], +["2aq5",1.75,1.60078341376018], +["1h33",1.75,2.2552531827733], +["1i2b",1.75,1.55524219342848], +["1dym",1.75,1.43091487655441], +["2ete",1.75,1.68392825898572], +["1m0u",1.75,2.05323935262807], +["5cp4",1.75,2.20360093383097], +["1wzg",1.75,1.51230273443715], +["1rmy",1.75,1.71659936426161], +["1k6w",1.75,1.90407922501362], +["1mj8",1.75,2.03726100213157], +["1tu6",1.75,2.02821412910309], +["1k0o",1.75,2.05493668630026], +["2a6w",1.75,2.30461458957764], +["6gsv",1.75,2.21028495961908], +["1vpb",1.75,1.15104255182248], +["2ex4",1.75,1.74092759381626], +["1rua",1.75,2.37333302517496], +["1pl1",1.75,1.45775193357388], +["2bws",1.75,1.09276768345204], +["1w8h",1.75,1.61753872745929], +["2aop",1.75,2.04158010314943], +["1fo3",1.75,2.32170486039248], +["1sn2",1.75,2.1700067623687], +["1dqn",1.75,2.20910030951613], +["1dqp",1.75,2.18051769674267], +["1k2y",1.75,1.90182474282898], +["1sat",1.75,1.63743973581210], +["2fpe",1.75,2.21120201380783], +["1q8p",1.75,1.63892213243994], +["1wov",1.75,2.15485238699798], +["1wd3",1.75,1.67356394550101], +["1pg2",1.75,2.10912090940391], +["1i8f",1.75,2.11789917142090], +["1d4x",1.75,2.42695401229708], +["1g2a",1.75,1.54932514842346], +["1v0s",1.75,1.82006784438942], +["1jak",1.75,1.59943620508294], +["1s7y",1.75,1.81056211073063], +["1vhv",1.75,2.1021921485249], +["1xqh",1.75,2.65718115652046], +["1o9s",1.75,2.64727515827418], +["2aax",1.75,1.63982893262329], +["1e7w",1.75,2.29233685575528], +["1yrb",1.75,2.31511709931704], +["1b32",1.75,1.83182337352942], +["1b4z",1.75,1.88784106984973], +["1f4g",1.75,1.52562290885069], +["1hzo",1.75,1.87529267937838], +["1kzi",1.75,2.07191650706309], +["1uxb",1.75,2.44446274135039], +["1xe7",1.75,1.96558476443186], +["1a7u",1.75,1.80001262733215], +["1go3",1.75,1.68261989089081], +["1aqy",1.75,2.3252043066794], +["1w99",1.75,1.70483734162133], +["1opj",1.75,2.41270573963804], +["2bxy",1.75,1.49179669728248], +["2bxz",1.75,1.50321671309223], +["1p2m",1.75,1.33345891156621], +["1t8n",1.75,1.41879157183012], +["1t8l",1.75,1.32171228661491], +["1ku8",1.75,1.76156649349763], +["1xgs",1.75,2.05833640951775], +["1uxj",1.75,2.03901046076385], +["1ur5",1.75,2.06756065734069], +["1ty0",1.75,2.39635769030173], +["1msv",1.75,1.58459139750651], +["4lip",1.75,1.58645136405755], +["1o7m",1.75,2.2049591225056], +["1kfe",1.75,1.85171600262978], +["1nrz",1.75,2.36640808452276], +["1oi2",1.75,2.00603800648858], +["1k9f",1.75,1.672812974828], +["1nsx",1.75,2.5090991060008], +["1nsz",1.75,2.4696579924244], +["1w9i",1.75,1.08761342110341], +["1gtj",1.75,1.99758217696029], +["1fsy",1.75,1.82507078688452], +["1s5d",1.75,1.51894504366417], +["1ocb",1.75,1.37420503610744], +["2b0t",1.75,2.04281177899636], +["1h17",1.75,2.06997624430492], +["1nqu",1.75,1.24985938219434], +["1kjj",1.75,2.73428759293243], +["1my3",1.75,1.85542884836289], +["1eyz",1.75,2.72037496815178], +["1ez1",1.75,2.89764945014775], +["1g2o",1.75,2.05117998648171], +["1se6",1.75,2.94139183158185], +["1cqx",1.75,2.36969143804624], +["1tcv",1.75,1.77481265365393], +["1h4p",1.75,2.22073203980218], +["1vh4",1.75,1.46083244793799], +["1op3",1.75,2.50505154225519], +["1q2e",1.75,1.51976081919029], +["1p7k",1.75,2.07436272412658], +["1k75",1.75,1.91193231338416], +["1gq6",1.75,1.88712366302191], +["1q9w",1.75,2.83163371271389], +["1ed8",1.75,2.14453532066329], +["1ed9",1.75,2.21424769484931], +["1lk5",1.75,1.92566101101664], +["1zg7",1.75,2.51466257190885], +["1hm9",1.75,2.39966805749729], +["2bbk",1.75,2.17882148709353], +["1vgg",1.75,1.62557236575811], +["1xkz",1.75,2.00044325358032], +["1pz3",1.75,2.36839364851978], +["1l9p",1.75,1.89593356573048], +["1l9t",1.75,1.84141774124725], +["1npy",1.75,2.06534152853612], +["1rre",1.75,2.6938823529234], +["1w6u",1.75,2.35112229211706], +["1d2v",1.75,2.13536750339830], +["1xx1",1.75,2.23560284929027], +["1x6v",1.75,1.99551429996048], +["1g8m",1.75,2.10633385577591], +["1t0t",1.75,1.84098112381396], +["1o66",1.75,1.62899629514588], +["1hdu",1.75,2.68860045667872], +["1hee",1.75,2.68860045667872], +["1jlv",1.75,2.44867472534439], +["1pg4",1.75,1.87718732170423], +["1u8f",1.75,1.80926552025821], +["1n8f",1.75,1.97405978857746], +["1sy7",1.75,2.01975238769379], +["1gtf",1.75,1.95054118886822], +["1w2w",1.75,1.69247366178425], +["1ne7",1.75,2.17290467592215], +["1vlp",1.75,1.41683943699130], +["1egv",1.75,2.81664848568001], +["1woh",1.75,2.2004512220716], +["1qsg",1.75,1.38648325970481], +["1l1l",1.75,2.41874374389856], +["1jz3",1.75,2.3578214359104], +["1jyv",1.75,2.47323319860061], +["1jyx",1.75,2.577160216187], +["2gfs",1.75,1.15274147214202], +["1pm4",1.76,2.69967645608911], +["1r3y",1.76,1.63841578152165], +["1pdq",1.76,1.99032857871424], +["1chz",1.76,3.33027136230161], +["2fcf",1.76,1.09232685806425], +["1i3i",1.76,1.36577935139619], +["1vpi",1.76,2.30489767998607], +["4paz",1.76,2.82313500689466], +["5paz",1.76,2.695664176172], +["1chn",1.76,1.33539017117092], +["1uib",1.76,1.29690473869460], +["1uia",1.76,1.94385800252359], +["1ios",1.76,1.33509386528126], +["1ior",1.76,1.70009796215476], +["1oeb",1.76,1.87426420460265], +["1jzw",1.76,1.92503790171524], +["1v8i",1.76,1.86477416671871], +["1ht9",1.76,1.82075104510635], +["1vi3",1.76,1.46110563494976], +["1xem",1.76,1.54532716473434], +["1mik",1.76,2.01533150353831], +["1k9k",1.76,1.66052623495468], +["1qq0",1.76,2.12708545256728], +["1brn",1.76,2.5916374281452], +["1u9k",1.76,2.35676777651416], +["1tq5",1.76,2.95260439727204], +["1slg",1.76,2.82883197403116], +["1yb7",1.76,1.76035935577423], +["1ghp",1.76,2.72808890782093], +["1xq0",1.76,2.14170317032947], +["2vhb",1.76,2.62824534475215], +["1pda",1.76,1.94799409861525], +["1apb",1.76,2.54878299279215], +["1ell",1.76,1.69037586581974], +["2pvi",1.76,2.33012528803452], +["2acs",1.76,2.36735353525998], +["2acu",1.76,2.23225699919272], +["2acr",1.76,2.43061094267279], +["2acq",1.76,2.42684278159426], +["1n93",1.76,1.37948131368961], +["1uuf",1.76,1.84446802335897], +["1sng",1.76,1.44282552633246], +["1m7a",1.76,2.1124962375474], +["1xw2",1.76,1.24912723677965], +["1q6r",1.76,1.62032019148252], +["1te2",1.76,1.81817523757003], +["1ynb",1.76,2.08363828029502], +["1jl2",1.76,2.36661219168952], +["1l7q",1.76,1.84678445249023], +["1cnz",1.76,2.52877263723676], +["1h5u",1.76,2.8427940069944], +["1c8k",1.76,3.17064086378527], +["1i2m",1.76,2.28701796859526], +["1uwl",1.76,2.29620757851222], +["1zai",1.76,2.09685323223707], +["1zz3",1.76,1.91156751465319], +["2b6h",1.76,1.12000217402367], +["1vph",1.76,1.93203304747674], +["1pwt",1.77,2.40699750134425], +["1lpl",1.77,2.4888841596924], +["1tov",1.77,0.874493536861242], +["3bu4",1.77,1.81966233347515], +["5bu4",1.77,1.97795119950555], +["2fgf",1.77,2.29274537985494], +["1jef",1.77,1.93242257950134], +["1gwd",1.77,2.01198271622761], +["134l",1.77,1.90113092184438], +["1tby",1.77,2.20676691579106], +["1laa",1.77,2.16286780291036], +["133l",1.77,2.14414603448806], +["1r67",1.77,2.22065542711616], +["2blh",1.77,1.41011317926453], +["110m",1.77,2.34345674846198], +["1o4v",1.77,1.5975406892208], +["1ucc",1.77,1.63881610883396], +["1gmr",1.77,1.76353789683803], +["1o2h",1.77,2.01054404058816], +["1vf1",1.77,1.67944077630646], +["1mvq",1.77,1.49930264954090], +["1taz",1.77,1.8231416250446], +["1fhv",1.77,2.16377345161798], +["1zoe",1.77,2.50028176269824], +["2a6s",1.77,2.27223878116516], +["1s8f",1.77,2.60837942362164], +["1dk0",1.77,2.439343370908], +["1pkk",1.77,2.09620600109426], +["1u55",1.77,2.35782818229213], +["3uag",1.77,1.72774447018487], +["1ys6",1.77,2.58771072140466], +["1y1t",1.77,2.46633170609995], +["1r4p",1.77,1.93398531399621], +["1f0j",1.77,2.15193455428572], +["2bfb",1.77,1.79904696614738], +["2bia",1.77,2.26155172358506], +["1y7a",1.77,2.39557662620848], +["1r7a",1.77,1.67154885160638], +["1rx0",1.77,1.69540072627681], +["1m4t",1.77,2.5153200589047], +["1g1l",1.77,2.00776486756597], +["1ev3",1.78,1.87794505917048], +["1mzm",1.78,2.13673300999270], +["1sdz",1.78,2.82371028710109], +["1yv6",1.78,2.29626365518587], +["1fn5",1.78,2.11787475415121], +["1n4f",1.78,2.54878430142753], +["1j23",1.78,2.18503930510438], +["1j24",1.78,1.61246695080830], +["1j25",1.78,1.76783113461514], +["1uv0",1.78,2.48261073734966], +["1khi",1.78,2.12599082867948], +["1uzp",1.78,2.63006417147901], +["1emy",1.78,2.20504652557469], +["1top",1.78,1.84587794475349], +["1yzq",1.78,2.24567109084095], +["1fej",1.78,2.01276247399239], +["1o32",1.78,1.81179130292469], +["1sre",1.78,2.66511267503933], +["1y6i",1.78,1.8570188743886], +["8est",1.78,2.18328364491540], +["4est",1.78,1.92021560739265], +["1mvu",1.78,2.10131023213005], +["1jvu",1.78,2.34952171158537], +["1zk1",1.78,1.58540612971676], +["1gqn",1.78,2.2045626324961], +["1jt1",1.78,1.81801443472575], +["1ew6",1.78,2.12117241995967], +["1wta",1.78,1.44406180239701], +["1ypk",1.78,2.27064025239863], +["1jt4",1.78,2.60233249708185], +["1ypj",1.78,2.664560346468], +["1x7v",1.78,1.81709280959416], +["1yoe",1.78,1.10564457476407], +["1nq6",1.78,1.47482518495431], +["1h1t",1.78,2.42223097959847], +["1axn",1.78,2.60075422662303], +["1qaz",1.78,1.98721112848186], +["1o5f",1.78,2.09154270307157], +["1x84",1.78,2.38942137843876], +["1pvf",1.78,2.49519430280538], +["1vp2",1.78,1.71462838809048], +["1ia3",1.78,2.054774510217], +["1ysr",1.78,2.04401862351907], +["1qh7",1.78,1.33545330475779], +["1zea",1.78,2.3867913914030], +["1seq",1.78,1.88821427733915], +["1pfw",1.78,1.73990180502465], +["1d3c",1.78,2.54535344617796], +["1h2y",1.78,1.48199135535182], +["1vlj",1.78,1.69278404065268], +["1a8i",1.78,2.04000075209327], +["1p6k",1.78,2.18053066198268], +["1l9s",1.78,1.87012826045533], +["1l9r",1.78,1.90968241452627], +["1hbo",1.78,1.77167059950795], +["1flu",1.79,1.83829796388262], +["1rgx",1.79,2.22456120033269], +["1xr9",1.79,1.77895060789259], +["1h9o",1.79,2.54900504510345], +["1gsx",1.79,2.57019617626389], +["1umv",1.79,2.33763589210071], +["1ioq",1.79,1.51601860710132], +["1kxy",1.79,1.78889036282659], +["1xyv",1.79,2.10684366314505], +["1zvc",1.79,1.56349750074628], +["2fq4",1.79,2.15348611722217], +["1ec0",1.79,1.51070106651763], +["1iab",1.79,2.01376610997208], +["2bv7",1.79,1.65216724839092], +["1yk5",1.79,1.52193650227472], +["2ccs",1.79,2.35070445083767], +["1f2s",1.79,1.93350332710788], +["1nxq",1.79,1.23040203523109], +["1gi7",1.79,2.66822248227516], +["1i2k",1.79,2.44048336474463], +["1h01",1.79,1.99224994432868], +["1xp0",1.79,1.80003086185875], +["1m2q",1.79,2.68949475349666], +["2fg0",1.79,1.17598153029054], +["2fr1",1.79,2.45338507268973], +["2bew",1.79,1.83168682028814], +["1q9o",1.79,2.62675541741763], +["1x74",1.79,2.05444757639418], +["1rk4",1.79,1.73381012324187], +["1mjf",1.8,1.53888855399804], +["1q7d",1.8,1.51660604958004], +["1b19",1.8,1.16871151766509], +["1b18",1.8,1.34922769281048], +["1b2b",1.8,1.41708455649362], +["1b2g",1.8,1.52969500396967], +["1b2c",1.8,1.65236298905713], +["1cad",1.8,1.66001612448711], +["1caa",1.8,1.91470248974794], +["1t9q",1.8,3.02668001841815], +["1oks",1.8,2.3396658414603], +["1fca",1.8,1.58106804109348], +["1yod",1.8,2.70248864157454], +["1b6q",1.8,2.35777961454701], +["1shg",1.8,2.50715040105512], +["8pti",1.8,2.95293242122195], +["1qkx",1.8,1.63628945709359], +["1cq4",1.8,1.66131196683736], +["1zik",1.8,2.92670116833133], +["1mhn",1.8,1.96148103610882], +["1vif",1.8,3.08937239605849], +["1zii",1.8,2.97485126271414], +["1ku3",1.8,2.49810636822766], +["1i5x",1.8,1.57291813907093], +["1fas",1.8,2.50752336403591], +["1yib",1.8,1.60873965779006], +["1iq9",1.8,2.55569720600429], +["2zta",1.8,3.0980096451292], +["2cc7",1.8,2.00167982718556], +["1mhx",1.8,1.99474992686291], +["1gzi",1.8,2.08373519724462], +["9ame",1.8,1.70455933433995], +["1wtr",1.8,2.76622746583897], +["1dul",1.8,1.88769092879758], +["1xak",1.8,2.45915142438243], +["1riy",1.8,1.67182589801579], +["1ruw",1.8,2.56835180029214], +["1dxg",1.8,1.26887747531854], +["1z96",1.8,1.00443817160659], +["1hpi",1.8,2.1808616779558], +["1k51",1.8,1.63236178941822], +["1hyp",1.8,2.75247533188647], +["1tif",1.8,2.48460488302079], +["1ubq",1.8,2.58688200277616], +["1ubi",1.8,2.74137698091883], +["2b8i",1.8,2.17481281893425], +["1kp6",1.8,1.55510636315962], +["3kiv",1.8,3.68551985015165], +["1bdo",1.8,1.50966306630588], +["1zt3",1.8,1.96989372494579], +["1t07",1.8,1.41954692572740], +["1m2m",1.8,1.75894468498829], +["1m2i",1.8,1.84910042047790], +["1lqx",1.8,1.46952844871855], +["1m20",1.8,1.52817584998056], +["2ceu",1.8,2.35192093869933], +["1cm2",1.8,2.66262872157637], +["1cei",1.8,2.21645736205681], +["1vqa",1.8,1.29951972505657], +["1vqb",1.8,1.36865944091461], +["1vqc",1.8,1.29503036575436], +["1vqe",1.8,1.29503036575436], +["1vqf",1.8,1.36865944091461], +["1vqi",1.8,1.29503036575436], +["1vqh",1.8,1.4468820315674], +["1vqj",1.8,1.71835009566995], +["1a68",1.8,2.08167993910141], +["1pch",1.8,2.33836116361743], +["1nps",1.8,2.45151114793001], +["1yd1",1.8,1.04416274194194], +["1ycz",1.8,1.30249690169064], +["1n98",1.8,2.55812722676957], +["1y02",1.8,1.58873889157837], +["1yd5",1.8,1.11299802738931], +["1ten",1.8,1.68627797029027], +["1fna",1.8,2.6738919650276], +["1bxv",1.8,2.11626627994771], +["1b9w",1.8,2.15379712844983], +["1fk3",1.8,1.85003159231843], +["1fk1",1.8,2.1658336190272], +["1fk2",1.8,2.52665480072727], +["1fk0",1.8,2.59240836430096], +["1fk4",1.8,2.52914594794879], +["1ij3",1.8,2.78916276141369], +["1dfu",1.8,2.04818826276705], +["2tci",1.8,2.75020671222345], +["1off",1.8,1.97707122292217], +["1gcm",1.8,3.40901685203359], +["2cbp",1.8,2.43108378451962], +["1mwp",1.8,1.93962808321648], +["1rwe",1.8,2.05758171096669], +["1lds",1.8,2.14963193128442], +["7pcy",1.8,2.25866066373446], +["1rn4",1.8,2.41942727949589], +["1j7c",1.8,1.65004571648505], +["1j7a",1.8,2.22747408523531], +["1j7b",1.8,2.25832941899450], +["2acy",1.8,2.30763060322151], +["2pcy",1.8,2.62927138947703], +["5pcy",1.8,2.75005036621803], +["1yn4",1.8,2.32119916131373], +["2fd4",1.8,2.53451229920196], +["1w42",1.8,1.12000217402367], +["1n8u",1.8,2.2781473019097], +["1fao",1.8,2.04793338768323], +["2b1y",1.8,1.61497533202685], +["3wrp",1.8,3.3449946051287], +["1kdi",1.8,2.15607003958476], +["1zfp",1.8,2.06945251235639], +["1qad",1.8,1.46423747234912], +["1h7c",1.8,2.39803667635903], +["1bb1",1.8,1.54625349705038], +["1fzu",1.8,1.18944141124444], +["8rnt",1.8,1.65054747006987], +["2aae",1.8,1.61366729457150], +["1hz1",1.8,1.69130572689427], +["1i2e",1.8,1.55453537213454], +["4bu4",1.8,1.38329552525350], +["5gsp",1.8,1.61200832270600], +["6rnt",1.8,1.84132715934086], +["3rnt",1.8,2.11592469211668], +["2rnt",1.8,2.25720372863951], +["2gsp",1.8,1.62839586453175], +["1det",1.8,2.75893980693212], +["2fmb",1.8,2.52698319904032], +["1fmb",1.8,2.53828916839812], +["1o4c",1.8,2.44045309324761], +["1lxj",1.8,2.14539560354164], +["1bmb",1.8,1.72976504654494], +["1xau",1.8,2.85239848883612], +["1aaj",1.8,1.79849108862921], +["1rds",1.8,2.54925529635059], +["1erw",1.8,1.64595440633057], +["1o47",1.8,1.78612776903567], +["1o45",1.8,2.26926394602885], +["1pc5",1.8,2.04375776798534], +["1v2z",1.8,1.76790244166100], +["2cdv",1.8,2.16027597349413], +["1j4i",1.8,1.90826994738552], +["1j4h",1.8,2.02379736719267], +["1lkl",1.8,2.25171801248974], +["1bhf",1.8,3.01038113908975], +["4pal",1.8,2.17618760543293], +["2pal",1.8,2.57005023310893], +["1gn0",1.8,1.92969475763472], +["1cih",1.8,2.79845835949489], +["1cig",1.8,3.00729060039678], +["1cie",1.8,2.75614245338734], +["1w0u",1.8,2.15622623577792], +["2apx",1.8,1.33389458997072], +["1m1s",1.8,3.02700429768550], +["2apb",1.8,1.72608211958391], +["1gzl",1.8,2.92003907378433], +["1wad",1.8,2.49961824903389], +["1roa",1.8,2.08435282111067], +["1ytc",1.8,2.35417528244277], +["2apf",1.8,2.46425601141689], +["1rtu",1.8,1.04661339665601], +["2tgi",1.8,2.74956496310298], +["4fiv",1.8,2.65593499125928], +["1lcj",1.8,2.56174602568247], +["1rzy",1.8,1.88702331543349], +["1jid",1.8,1.372886137594], +["1evh",1.8,1.63800086264545], +["1z3l",1.8,2.2707466369479], +["1py9",1.8,1.80075553530775], +["1i07",1.8,2.65907219824448], +["1r9h",1.8,1.54775033984330], +["2fi9",1.8,2.07927048046095], +["1a7d",1.8,1.32533164120908], +["1a7e",1.8,1.54501772007886], +["1rbf",1.8,2.01148305874964], +["1rbi",1.8,2.30041445991655], +["1rbg",1.8,2.40525165715831], +["1a3d",1.8,2.39514480393010], +["1ekg",1.8,2.32293289613398], +["1wou",1.8,2.04802706012195], +["1u29",1.8,1.38048888344348], +["1pzb",1.8,2.67431915829292], +["1pza",1.8,2.70365894816566], +["2apq",1.8,1.22886782653039], +["1k5b",1.8,3.15575805185665], +["1ea2",1.8,2.05754214030628], +["1dly",1.8,1.60617817392767], +["1s8h",1.8,1.88946941705301], +["2sak",1.8,1.82689610562327], +["1xki",1.8,1.80753066319952], +["1srn",1.8,3.57567419222612], +["1p90",1.8,2.44635543733652], +["1rtx",1.8,2.84269303210949], +["1c44",1.8,2.93169267008406], +["1k59",1.8,2.95035276601066], +["1b1i",1.8,3.14261124873486], +["1bpq",1.8,2.21729705147761], +["1mku",1.8,3.11472613470484], +["2bpp",1.8,2.98914918551623], +["1a4v",1.8,2.7138626665093], +["2cw4",1.8,2.50419478357841], +["1s7i",1.8,2.56843337273734], +["1c9x",1.8,2.56544315858647], +["1c8w",1.8,2.83022927688466], +["1rnw",1.8,2.53167122181598], +["1rnn",1.8,2.64289546711596], +["1izq",1.8,2.61896920813653], +["1rha",1.8,2.71946402774446], +["1fkq",1.8,3.03311844891233], +["1cgo",1.8,2.31091524399658], +["1at5",1.8,1.57764849035809], +["1u5x",1.8,2.28047897836671], +["1at6",1.8,1.66655346237189], +["2chf",1.8,2.93001174210958], +["2che",1.8,2.97690540375046], +["1ijt",1.8,1.71685077901360], +["1u2b",1.8,0.971961256759092], +["1dt1",1.8,2.36898647181485], +["1bwj",1.8,1.66187609731102], +["1bwh",1.8,1.61626665280264], +["1bvx",1.8,1.75930476062688], +["1bwi",1.8,1.68209450577442], +["1lzd",1.8,2.06319645580369], +["1lze",1.8,2.02070328629602], +["1lzc",1.8,2.01855673419138], +["1heo",1.8,2.17555280402760], +["132l",1.8,2.28685392032047], +["1azf",1.8,2.28311973952030], +["1hen",1.8,2.20680547052021], +["1heq",1.8,2.22175562285527], +["1lzg",1.8,1.86383849693185], +["1hem",1.8,2.1752030638665], +["1her",1.8,2.32791638449375], +["1ykz",1.8,1.70746863387668], +["1hep",1.8,2.39154101287787], +["1lmn",1.8,2.23361966648775], +["1lmo",1.8,2.31842133161096], +["2bqm",1.8,1.9071569302614], +["1lz4",1.8,1.91159591924129], +["2bqj",1.8,2.28883226776307], +["2bqo",1.8,2.21062604264110], +["2bqh",1.8,2.27119376350365], +["1ix0",1.8,2.13781334827505], +["2bqk",1.8,2.17664993894573], +["2bqg",1.8,2.06135840986246], +["2bqi",1.8,2.2678844114638], +["2bql",1.8,2.11341386936967], +["2bqn",1.8,2.40320384762586], +["2bqf",1.8,1.87932186199054], +["2bqb",1.8,1.90254149012787], +["2bqc",1.8,2.04997365318881], +["2bqd",1.8,2.04997365318881], +["2bqe",1.8,1.92455996712629], +["1hz9",1.8,2.17420827297052], +["1lhm",1.8,1.51699681826623], +["2bqa",1.8,2.13082243843185], +["1b5u",1.8,1.35231881173893], +["1cj8",1.8,1.53134532681942], +["1ge0",1.8,1.25730183600803], +["1c45",1.8,1.74251905248359], +["2hec",1.8,1.7789804138152], +["2hee",1.8,1.61096547824458], +["1cj6",1.8,1.67496354863431], +["1ge4",1.8,1.80766368078994], +["1b7r",1.8,1.61559036537828], +["1gdx",1.8,1.70568228846611], +["1gdw",1.8,1.70625184367309], +["1ckf",1.8,1.72170110348756], +["1jkd",1.8,1.9507163767258], +["1lhi",1.8,1.43260308372297], +["2hef",1.8,1.64885045995215], +["1di3",1.8,1.78406355316854], +["1ckc",1.8,1.67064062131718], +["1gb5",1.8,2.13174183195373], +["1ge3",1.8,1.95957660010336], +["2hea",1.8,1.92222938337664], +["1gay",1.8,1.92261005354592], +["1gbo",1.8,2.26641133183650], +["2hed",1.8,2.07355186489637], +["1hnl",1.8,2.3359849195162], +["1lhj",1.8,2.46234040746006], +["1lhk",1.8,1.52732854562910], +["1cj7",1.8,1.56829690412971], +["2meg",1.8,1.56985640204091], +["1ckd",1.8,1.69987496009242], +["1gb2",1.8,1.73765070474030], +["1ip4",1.8,1.65944447961832], +["1wqn",1.8,1.60495057258466], +["1wqp",1.8,1.69987496009242], +["1wqr",1.8,1.60495057258466], +["1gb7",1.8,1.48057727022527], +["1ip1",1.8,1.48057727022527], +["1ip6",1.8,1.36609804114757], +["2mee",1.8,1.50557041517436], +["1c43",1.8,1.58003408110319], +["1gfj",1.8,1.29361713584284], +["1yan",1.8,1.80857286581523], +["1eq4",1.8,1.74438214915767], +["1gb0",1.8,1.51245911093098], +["1gb8",1.8,1.39797988185328], +["2meb",1.8,1.53679065131224], +["2med",1.8,1.67057906125698], +["2mei",1.8,1.61059373921293], +["1gf8",1.8,1.51368603527787], +["1cj9",1.8,1.69966546382427], +["1eq5",1.8,1.98287216831041], +["1eqe",1.8,2.19486680337713], +["1wqq",1.8,1.77404194232169], +["1gf7",1.8,1.64082615176888], +["1gfa",1.8,1.42821229440923], +["2mef",1.8,1.70081147381293], +["2meh",1.8,1.7013833240718], +["1wqo",1.8,1.80123213190233], +["1gf6",1.8,1.66798093648151], +["1gfe",1.8,1.56984630819956], +["1gb3",1.8,1.59435999253353], +["1gf9",1.8,1.47988076345583], +["1gaz",1.8,1.48038729826123], +["1ip2",1.8,1.88568660982056], +["1ip5",1.8,1.67307275246091], +["1gfk",1.8,1.67408401767206], +["1yam",1.8,1.84892213038383], +["1yap",1.8,1.84892213038383], +["207l",1.8,2.0542744237322], +["1gfg",1.8,1.50353920823935], +["1yaq",1.8,1.87297622760191], +["1inu",1.8,1.64088571982885], +["1gfh",1.8,1.74165604615556], +["1wqm",1.8,1.89623381497071], +["1gfr",1.8,1.76185315111134], +["1gf4",1.8,1.91761976333085], +["1gfv",1.8,1.86205069581300], +["1yao",1.8,1.88249387566061], +["1lhh",1.8,1.9506755501181], +["1gbw",1.8,2.01956035907783], +["1gft",1.8,2.12660624096414], +["1loz",1.8,2.39930446600363], +["1gb9",1.8,2.10182253775488], +["1gb6",1.8,1.91383917159305], +["1gby",1.8,1.79983830487322], +["1gbz",1.8,2.60391688566305], +["1gbx",1.8,2.16047537746068], +["1gfu",1.8,1.83470584375891], +["1i1z",1.8,2.42112254589286], +["1b7n",1.8,2.84405622976103], +["1lhl",1.8,1.18092627832470], +["1gf0",1.8,1.63712589930424], +["1gf3",1.8,1.86583869675673], +["3lhm",1.8,1.38156399122116], +["1gf5",1.8,1.73725364039636], +["1gez",1.8,1.70488836655843], +["2lhm",1.8,1.80067654080100], +["1b7o",1.8,2.86416518807730], +["1b7l",1.8,3.03754820854948], +["1ly2",1.8,1.56994951408848], +["1nfn",1.8,2.80959821876885], +["1ce9",1.8,2.81261575725815], +["1mzb",1.8,1.62779410831324], +["1mz4",1.8,1.49044041892407], +["1j22",1.8,1.85864044242747], +["1sl5",1.8,2.34597167555957], +["1hza",1.8,2.04361630035099], +["1uy1",1.8,1.52117058113313], +["1fee",1.8,1.86517343601748], +["1gu4",1.8,2.08755377902823], +["2eif",1.8,2.43229973989425], +["1i2h",1.8,1.25494944654101], +["1lz5",1.8,2.39158760545053], +["1vsr",1.8,1.58843262695069], +["1wlw",1.8,1.84089981278855], +["1uix",1.8,2.22921486749518], +["1hi3",1.8,2.54459297409365], +["1hi5",1.8,2.80054218995747], +["1hi4",1.8,2.73782022356018], +["1f2z",1.8,2.15243285208002], +["1kab",1.8,2.35766673887039], +["1syc",1.8,2.52232055378862], +["1syf",1.8,2.16516314908906], +["1sye",1.8,2.71106319359918], +["1txq",1.8,2.18915080166786], +["1r9w",1.8,1.99545053690816], +["1khc",1.8,2.30551332143555], +["2fbh",1.8,2.35701204739821], +["1syb",1.8,2.43134773251432], +["1enj",1.8,2.93848718811177], +["1sk0",1.8,1.95479738232034], +["1sjz",1.8,1.99748214797468], +["1cbs",1.8,1.83067366646143], +["1lz6",1.8,2.36598549636866], +["6nul",1.8,1.72298948930754], +["2fax",1.8,1.65148547978741], +["2fox",1.8,2.13096034624628], +["5ull",1.8,2.0951454422038], +["2fvx",1.8,2.19762257502310], +["1fld",1.8,2.07402562195483], +["2flv",1.8,2.06900492017162], +["1hdk",1.8,2.81604066809645], +["1lo8",1.8,3.02653674020649], +["2g64",1.8,1.66749341758245], +["1lcl",1.8,2.11097404286677], +["1g86",1.8,2.59781652267945], +["1qkq",1.8,2.78393165454432], +["1k52",1.8,2.02587064574741], +["1hz5",1.8,2.3485466009282], +["2cj7",1.8,2.09928539272711], +["1k6k",1.8,2.31120297374878], +["1h9k",1.8,1.76173292458927], +["1clm",1.8,2.48808700465861], +["2fcs",1.8,2.11450361590352], +["1h9j",1.8,1.75218518840556], +["1q5z",1.8,1.59418848030206], +["4tsv",1.8,3.59541465091764], +["1ahr",1.8,3.49454710660666], +["2fal",1.8,2.4196636328917], +["1wsb",1.8,2.18796051058722], +["1xt6",1.8,2.92215204450718], +["1azl",1.8,1.95135238089185], +["1akt",1.8,2.29032854332117], +["1pxd",1.8,2.08304991895658], +["1p4m",1.8,2.09181529485322], +["1edu",1.8,2.06957214317792], +["1npk",1.8,2.29608478664716], +["1dbu",1.8,2.34661239859214], +["1bj7",1.8,1.78858697132714], +["1v8r",1.8,1.89678960930379], +["1rlh",1.8,1.90959521335485], +["1ilk",1.8,2.4447817860168], +["1asw",1.8,2.84463369746020], +["1f1a",1.8,1.77400028317804], +["1b4l",1.8,2.05841705338653], +["1b4t",1.8,1.96741469675742], +["1nz4",1.8,2.56723666324357], +["1bje",1.8,2.56160317998197], +["1ebc",1.8,2.15453054850960], +["2blj",1.8,1.59051694265740], +["2myd",1.8,2.18612082751851], +["2myc",1.8,2.48988334475342], +["1swm",1.8,2.44063657137098], +["1gdi",1.8,3.09525052660674], +["1gdl",1.8,2.90130703662358], +["1gdk",1.8,2.85751554106494], +["2cmm",1.8,3.04817680714806], +["1soi",1.8,2.12774327482805], +["1co8",1.8,2.31523572296799], +["1f63",1.8,2.05283962374997], +["1n9f",1.8,1.57986006836273], +["1ch2",1.8,1.94333878777516], +["1n9h",1.8,1.67208040959689], +["1ofk",1.8,2.22064423037921], +["1ch9",1.8,2.32754934761981], +["2mgg",1.8,2.75359180435875], +["1mlk",1.8,2.87995830003506], +["1mlo",1.8,2.94138998174275], +["2mgd",1.8,2.65988647380832], +["1mtk",1.8,3.03243064897156], +["2mgf",1.8,2.91964010355007], +["1mlm",1.8,2.95941327784496], +["1ycl",1.8,1.94237605533101], +["1rbs",1.8,2.33905287806652], +["1rbv",1.8,2.51852977840068], +["1kva",1.8,2.52259211306687], +["1rbt",1.8,2.50172004711252], +["1rbu",1.8,2.44833390806576], +["1rbr",1.8,2.33964433885582], +["1law",1.8,2.67439944574507], +["1lav",1.8,2.65463901860989], +["1jyh",1.8,1.46418409013717], +["2b18",1.8,2.08084649934754], +["2fu0",1.8,1.63015615676706], +["1t8g",1.8,2.0206584612144], +["2bep",1.8,1.58376988709894], +["1s7k",1.8,1.95146318211576], +["2a4v",1.8,1.83711589895825], +["1g5t",1.8,2.86185679377299], +["1yp6",1.8,2.56840383954431], +["1qy0",1.8,2.70849678971584], +["1dg7",1.8,2.42073557466112], +["1v8m",1.8,1.79913158054513], +["1zzi",1.8,1.90983025770224], +["1ra3",1.8,2.27447105001540], +["1rf7",1.8,2.37238388721486], +["1ra8",1.8,2.43270335096872], +["1rx2",1.8,2.64224786264596], +["1kxo",1.8,2.56221945463002], +["2bm3",1.8,1.79600864295383], +["156l",1.8,1.85551167874316], +["159l",1.8,1.98578910999872], +["250l",1.8,2.16666720877472], +["158l",1.8,2.06051405250024], +["164l",1.8,1.64782027880063], +["162l",1.8,1.69535015404818], +["163l",1.8,1.91172847058037], +["185l",1.8,1.97906237080657], +["1lyj",1.8,1.8870879821527], +["1ulm",1.8,1.90112162849273], +["1cvk",1.8,2.11507835285968], +["188l",1.8,2.10460767984373], +["107l",1.8,1.95148139756848], +["160l",1.8,2.06289513551622], +["182l",1.8,2.10343724827101], +["229l",1.8,2.17530691274458], +["184l",1.8,2.10177134694441], +["181l",1.8,2.21038038074667], +["187l",1.8,2.32603814560857], +["238l",1.8,2.27305172053391], +["1nhb",1.8,2.28193062697132], +["186l",1.8,2.30200191831457], +["183l",1.8,2.43677641429069], +["239l",1.8,2.27368912790582], +["1l80",1.8,2.52528314752142], +["113l",1.8,1.71563051698190], +["114l",1.8,1.75473944428794], +["115l",1.8,1.95865491029664], +["1l61",1.8,1.84911586933736], +["1lye",1.8,1.88418010544948], +["1lyg",1.8,1.94433944023398], +["126l",1.8,1.81100564053395], +["1l91",1.8,1.9775764610704], +["260l",1.8,2.17925819890382], +["1l94",1.8,2.04453927511342], +["1lyf",1.8,1.99367528229732], +["1g1w",1.8,2.10372108471603], +["112l",1.8,2.05047462662934], +["1l93",1.8,2.06442321094117], +["108l",1.8,1.94214205429966], +["1l87",1.8,2.01710470127453], +["1c69",1.8,2.23719566253774], +["111l",1.8,2.21067286517648], +["1llh",1.8,2.50571156568821], +["226l",1.8,2.39469896243172], +["1l86",1.8,2.34670344013175], +["1cv3",1.8,2.43657913587405], +["1p56",1.8,2.59339125165441], +["122l",1.8,1.58636911190856], +["123l",1.8,1.76288983492855], +["120l",1.8,1.95884705233298], +["118l",1.8,1.61264009266713], +["7lzm",1.8,2.02894001368461], +["6lzm",1.8,2.10067222896742], +["1dye",1.8,2.10128502247479], +["5lzm",1.8,2.16326402535226], +["1qsb",1.8,2.15499529737843], +["1ncz",1.8,2.31368489246929], +["1ncx",1.8,2.65472837325253], +["1ysp",1.8,2.42576080241566], +["1lb6",1.8,2.11969520019679], +["1zp5",1.8,3.24332014166863], +["258l",1.8,2.28515571144582], +["1smx",1.8,1.59886883256760], +["1huq",1.8,1.73382949676481], +["245l",1.8,2.1779947598218], +["242l",1.8,2.09529964337579], +["246l",1.8,2.32022695551937], +["1g0p",1.8,2.2956219920443], +["255l",1.8,1.78424367737738], +["1g0j",1.8,2.03146008076616], +["1qt5",1.8,1.99843545611191], +["1g0l",1.8,2.21313349586399], +["1qt7",1.8,2.12730141248736], +["1g0q",1.8,2.15751258694523], +["1l35",1.8,2.25866020342575], +["1l25",1.8,2.41059043138966], +["1l98",1.8,2.33399438267277], +["1l42",1.8,2.20280043694797], +["1l43",1.8,2.18856765591378], +["1l27",1.8,2.29578957512691], +["1l38",1.8,2.39803177808965], +["1l31",1.8,2.60587002821787], +["256l",1.8,2.52143490518211], +["1l56",1.8,2.5094271009262], +["1l49",1.8,2.42200568033523], +["1l4u",1.8,2.21448668132338], +["1w8l",1.8,2.53160430593352], +["1mug",1.8,2.00375829075660], +["1usn",1.8,1.44989461147737], +["1lop",1.8,2.4771323530028], +["1wz3",1.8,1.94456605961259], +["1cjw",1.8,1.88373735900752], +["1kux",1.8,2.05648586529610], +["1j2a",1.8,2.47707997508864], +["1jah",1.8,2.45165856421001], +["1jai",1.8,2.56492742064817], +["1luz",1.8,1.89183868600141], +["3eip",1.8,2.61421977267567], +["1cwl",1.8,2.14119631795160], +["1fxl",1.8,2.15643545074774], +["1hc9",1.8,2.17083463286128], +["1cwk",1.8,2.3560269160309], +["1cwj",1.8,2.17799006268055], +["1bck",1.8,2.29405461641219], +["1caq",1.8,2.27380711400579], +["1czl",1.8,1.45667319707423], +["1rm8",1.8,2.60275104240324], +["1mgt",1.8,1.72146169667450], +["1n6o",1.8,1.67419386524326], +["1eue",1.8,2.07848857994435], +["1mu4",1.8,1.91151463775872], +["2bmd",1.8,2.58282374317187], +["1wba",1.8,1.87352125954128], +["1ccz",1.8,2.93395364235133], +["1dyw",1.8,2.7609460997022], +["2fcr",1.8,2.00944454330892], +["1fnl",1.8,2.52411788833908], +["1fgl",1.8,2.10974128915015], +["1j53",1.8,1.53009362420173], +["1lhu",1.8,2.48568880506733], +["1fel",1.8,3.59498283992513], +["1g8e",1.8,3.18642435574884], +["1lmb",1.8,2.19781956878633], +["1jwq",1.8,1.68650448837772], +["2biq",1.8,1.93674184450580], +["2bip",1.8,1.71533291768207], +["2cxh",1.8,1.72843386060489], +["1kn3",1.8,2.14774970096495], +["1sgc",1.8,2.32947855423681], +["1ybx",1.8,1.46537085321649], +["1nu4",1.8,2.17039661532650], +["1n7f",1.8,2.03031817213478], +["1ugn",1.8,2.18456828108706], +["1rym",1.8,2.53653919770318], +["1u1q",1.8,2.14004625902972], +["1u1r",1.8,2.49332204789209], +["3sga",1.8,2.20381228165504], +["4sga",1.8,2.10155522248638], +["5sga",1.8,2.09928680605976], +["2cx1",1.8,1.55692582182987], +["2cx0",1.8,2.02342465618213], +["1hv1",1.8,1.92972718627205], +["1bvv",1.8,2.01647828872625], +["1c5i",1.8,2.09944242878128], +["2gar",1.8,2.67709857469184], +["1uxo",1.8,1.50227328111352], +["1s3v",1.8,2.90158737434092], +["1mvt",1.8,3.37266615515133], +["1xda",1.8,2.56090785072969], +["1pdv",1.8,1.69284513944085], +["1jbk",1.8,2.18191730013866], +["2cvb",1.8,2.09569963165341], +["1frr",1.8,2.90174444283561], +["1upg",1.8,1.99764512702556], +["1q0p",1.8,1.87440440308706], +["1gmq",1.8,1.74992383244824], +["1uci",1.8,1.54663938007828], +["1uck",1.8,1.54663938007828], +["1sar",1.8,2.06765317811484], +["2sar",1.8,2.22179998877208], +["1hh8",1.8,1.86616479624692], +["1vm0",1.8,1.95208187606736], +["1ihj",1.8,2.16380734443075], +["1a92",1.8,1.91074841145398], +["1qbs",1.8,2.65250763849936], +["1qog",1.8,1.80042638744524], +["1qof",1.8,1.62879970344843], +["1qob",1.8,1.81928185008045], +["1ljp",1.8,1.45441700496984], +["1z4j",1.8,1.59575577505185], +["1z4l",1.8,1.77254693187511], +["1mh9",1.8,2.3362288974869], +["1dus",1.8,2.16397712512208], +["1v4b",1.8,1.78013827989741], +["1n9p",1.8,1.80039726920627], +["1hvr",1.8,2.61667478444515], +["1qbr",1.8,2.66430377973807], +["1qbu",1.8,2.98086374238344], +["1hwr",1.8,2.92751293174692], +["1hvh",1.8,3.57144647290321], +["2bfw",1.8,1.62548205247466], +["1ec3",1.8,1.90776521315613], +["1hvk",1.8,1.85036746603715], +["1hvi",1.8,1.91389390829539], +["1hvl",1.8,1.93120516655221], +["1g35",1.8,1.47109266105054], +["1pro",1.8,2.19253861973776], +["1bwb",1.8,2.27896245605497], +["1w5v",1.8,1.74242071844100], +["1hxw",1.8,2.15540408881052], +["1w5w",1.8,1.59036629207935], +["1j8r",1.8,1.98919303095923], +["1kzf",1.8,2.01563815485807], +["1xza",1.8,1.98386357217585], +["1cua",1.8,1.80184824413709], +["1fg6",1.8,1.70190106192855], +["1sp5",1.8,1.37398059180526], +["1dnl",1.8,2.52771053617241], +["1fe6",1.8,1.45398328625523], +["2fdi",1.8,1.97194597154646], +["1ast",1.8,1.67233926101285], +["1no5",1.8,2.49593028899555], +["1w3p",1.8,1.67028773698877], +["1khx",1.8,2.77191518507544], +["1ijb",1.8,1.81530042239574], +["1v77",1.8,2.31438166337608], +["1hvc",1.8,2.13043101239786], +["1vd1",1.8,2.32519583657146], +["1r1q",1.8,2.24091430495155], +["1iib",1.8,1.26211699720426], +["1q3o",1.8,2.29568895236947], +["1vd3",1.8,2.13626670888450], +["1vcz",1.8,2.4252425621381], +["1uch",1.8,2.31065341443076], +["2axe",1.8,2.03860524371682], +["3cyt",1.8,2.60671271532006], +["1bir",1.8,2.03775881422992], +["1z78",1.8,2.81416554958900], +["1my5",1.8,2.44831550856587], +["1cmc",1.8,1.83323419857506], +["1cmb",1.8,2.70846317672414], +["1l8f",1.8,2.01702268146361], +["1lr2",1.8,1.72184462511106], +["1lr3",1.8,1.87527881210020], +["1se8",1.8,2.12170114897585], +["1woj",1.8,1.58928018573388], +["1x9u",1.8,2.01309681987574], +["1ft6",1.8,2.50323288573665], +["1aun",1.8,2.18241240833485], +["1cpn",1.8,2.75297806810323], +["1zn6",1.8,1.8547352295678], +["1e99",1.8,1.50520352576947], +["1dv7",1.8,1.99167678386615], +["1hxn",1.8,3.09589225053223], +["1yuk",1.8,2.74258532486399], +["1ro0",1.8,2.43199583289414], +["1ix4",1.8,1.81464724465982], +["2spc",1.8,3.65904862490203], +["1lbu",1.8,2.99287124935643], +["2fbq",1.8,1.68808957149806], +["1ah6",1.8,2.97248505466541], +["1keb",1.8,1.81779293565123], +["1gbg",1.8,2.11547846474519], +["1xzz",1.8,2.46304044686670], +["1f2b",1.8,1.83627768626965], +["1mem",1.8,2.68051522061518], +["1j48",1.8,2.06536677867372], +["1ppo",1.8,2.90188412190294], +["1xvj",1.8,1.91641692384748], +["1t6t",1.8,1.75368128948747], +["1nqc",1.8,1.91983284149782], +["1xqa",1.8,2.03430436985650], +["1p2f",1.8,1.6192789753935], +["1i4j",1.8,2.87292410875234], +["1d4w",1.8,2.05201481390835], +["1rmo",1.8,2.19049126154419], +["1ept",1.8,2.58424672072101], +["1vzw",1.8,1.18843127802281], +["2cd0",1.8,2.53969885116002], +["2axo",1.8,2.64398818555935], +["1c8r",1.8,2.73493916792780], +["1f4z",1.8,2.93696692688009], +["1kzb",1.8,1.97540368125575], +["1m07",1.8,2.40331206913517], +["1jby",1.8,2.96261553531768], +["1aks",1.8,2.55101555144917], +["1rdj",1.8,1.49750925892382], +["1rdn",1.8,1.64159673068325], +["1rdi",1.8,1.57332050222427], +["1rdk",1.8,1.80836492699652], +["1kze",1.8,1.85849051092275], +["1nqn",1.8,2.3127249745674], +["2tbs",1.8,2.35970699857693], +["1vfa",1.8,2.0584693274189], +["1fh2",1.8,2.41039344888518], +["1y3w",1.8,2.18241989932527], +["1y3u",1.8,1.47301651234753], +["1s6f",1.8,1.02739318758660], +["1qbn",1.8,2.17320537268223], +["1qbo",1.8,2.10751614340009], +["1qa0",1.8,2.25336487235223], +["1qb6",1.8,2.38429507357305], +["1fn6",1.8,2.62921434336699], +["1qb9",1.8,2.55640261570726], +["1ppc",1.8,1.83673500774505], +["1g3d",1.8,1.71750341302518], +["1v2n",1.8,1.71693008321954], +["1f0t",1.8,2.15375625323532], +["1bju",1.8,1.97325895986228], +["1may",1.8,2.13863336882006], +["1v2u",1.8,1.55027686920416], +["1bjv",1.8,1.98520607292836], +["1g3e",1.8,1.95173928745222], +["1g3b",1.8,1.83398448940338], +["1tnh",1.8,1.98840660058473], +["1tng",1.8,2.07457628562915], +["1g3c",1.8,2.02747032324312], +["1az8",1.8,2.18005372278124], +["1tnk",1.8,2.06291263052518], +["1tnj",1.8,2.10758297152993], +["1qb1",1.8,2.22874192193772], +["1tgc",1.8,2.58441387213573], +["2tga",1.8,2.60936634945744], +["1v2v",1.8,2.1340893472974], +["1max",1.8,2.77943746065700], +["1qcp",1.8,2.73968047296546], +["1tgb",1.8,3.18796183145811], +["1gvl",1.8,2.92365876556915], +["2g5u",1.8,1.87031104671583], +["1emh",1.8,1.81124998857806], +["1nco",1.8,2.20351308646036], +["1dam",1.8,2.02786198831086], +["1dbs",1.8,2.03117735981939], +["1a82",1.8,2.10470378778636], +["1bs1",1.8,2.03889442541138], +["1kpe",1.8,2.00769029264425], +["1qyq",1.8,1.38351960168834], +["1qkm",1.8,1.82774656380094], +["1uj4",1.8,1.78689853643853], +["1weg",1.8,1.62325361962831], +["1mud",1.8,1.46541155819536], +["1jrs",1.8,2.18384267324967], +["1ytt",1.8,2.20268735973791], +["1cgh",1.8,2.45126325636263], +["2g5z",1.8,1.78843331367035], +["1srg",1.8,2.60132434865249], +["2pab",1.8,3.64628716356899], +["1ton",1.8,2.88232757994045], +["2ahe",1.8,1.40478699280461], +["1tt6",1.8,1.63104594998131], +["1srj",1.8,2.93858309582938], +["1dic",1.8,2.20319223126234], +["2c53",1.8,1.43686765147072], +["1zcr",1.8,1.19782253581806], +["1lau",1.8,1.8439749591126], +["1h8u",1.8,2.32443836023752], +["1e4h",1.8,1.83405439487920], +["1e5a",1.8,1.82049479717995], +["2boo",1.8,2.19049467978835], +["1i8k",1.8,2.33512936567426], +["1eo6",1.8,1.91402864226382], +["1din",1.8,2.43993508097308], +["2vgc",1.8,2.30039003305214], +["2gmt",1.8,3.40670099765612], +["1s66",1.8,2.38256030632492], +["1zix",1.8,1.77763020925101], +["3sgb",1.8,2.24320708153897], +["7gch",1.8,3.32108579933704], +["1ct0",1.8,1.91380558997851], +["1sgr",1.8,2.34893902419327], +["2sgq",1.8,2.25822256608929], +["1sgy",1.8,2.31299652776277], +["1sge",1.8,2.36833085581207], +["1sgd",1.8,2.31862413364692], +["1sgn",1.8,2.46896798591072], +["3sgq",1.8,2.41943023583273], +["2sge",1.8,2.62235050569079], +["2sgd",1.8,2.80148369682226], +["2sgp",1.8,2.91574502915233], +["1dow",1.8,1.55769915859630], +["1afq",1.8,1.74869516308800], +["1xy7",1.8,1.62285539465989], +["2c96",1.8,2.03002752520211], +["2gct",1.8,2.63362963319427], +["1sbw",1.8,1.74172352799093], +["1qyo",1.8,1.50357626269959], +["1z95",1.8,1.95050923160010], +["2axa",1.8,1.75961876745569], +["1al3",1.8,2.87648924324791], +["1qny",1.8,1.72827727116237], +["1lst",1.8,1.83141286053588], +["2ba2",1.8,2.34806614604066], +["1e12",1.8,2.28772142263573], +["1b0e",1.8,1.77571713905591], +["1ol0",1.8,1.74534525798352], +["1eas",1.8,2.42879518472179], +["2foh",1.8,1.92182122502399], +["6est",1.8,2.16785641675131], +["1e34",1.8,2.25470176432657], +["1bma",1.8,1.78125037447239], +["1kpm",1.8,2.32413749283336], +["1ob8",1.8,2.00924148408763], +["1ual",1.8,1.74145005762881], +["1iu1",1.8,2.16486284765755], +["2rtn",1.8,2.54438702190947], +["1dxj",1.8,1.59121672089069], +["1jie",1.8,2.32211876720416], +["7est",1.8,3.11325060926429], +["1xxs",1.8,2.95374210036820], +["2baa",1.8,2.49143551628359], +["1jq9",1.8,2.6102811304798], +["1rwz",1.8,1.70092636341683], +["1xp9",1.8,2.76834326157024], +["1xp1",1.8,2.76800792696747], +["1k50",1.8,1.68090977542796], +["1mrg",1.8,2.88466618043377], +["1xps",1.8,2.12102022547810], +["8rsa",1.8,2.54847327475108], +["9rsa",1.8,2.73749598867640], +["1jn4",1.8,3.36317087297607], +["1giu",1.8,2.72211687638909], +["1f5k",1.8,2.71507588094110], +["1wuc",1.8,1.86582519878712], +["1db1",1.8,1.63872777459669], +["1m2h",1.8,2.21369298150692], +["2stb",1.8,1.81507801124783], +["2sta",1.8,2.05436936330957], +["1xow",1.8,1.88545748523808], +["1rg0",1.8,2.5585207675268], +["1wn6",1.8,1.95125391139231], +["2c4n",1.8,1.92443815308138], +["1ulk",1.8,2.10194860863331], +["1fa5",1.8,2.23910132544023], +["1q9u",1.8,1.55899236927056], +["1kyu",1.8,1.74855946652457], +["1mml",1.8,2.92601735413097], +["1bze",1.8,3.07447801856789], +["1tyr",1.8,3.14817125798299], +["1prz",1.8,2.18850764767965], +["1gi9",1.8,2.59436981928863], +["1str",1.8,2.70872109705630], +["1jzj",1.8,2.54505416329581], +["1i53",1.8,2.71087762958067], +["1gj9",1.8,2.7582217006329], +["1jt2",1.8,2.07720537390825], +["1h70",1.8,2.21875858833153], +["1ztw",1.8,2.29761944890855], +["1gqb",1.8,2.17665672062799], +["1azc",1.8,2.53112532497708], +["1aiz",1.8,2.37600257769427], +["2aza",1.8,2.73863499922293], +["5lym",1.8,2.46934332364128], +["1ljh",1.8,2.51391904967227], +["1ljf",1.8,2.50743629912596], +["1sc9",1.8,1.64453381612082], +["1t79",1.8,1.50300055060122], +["1l1t",1.8,2.04112024542862], +["1ypv",1.8,1.93759256699687], +["1cni",1.8,2.17838670668011], +["1zsc",1.8,2.22856153750797], +["1cnj",1.8,2.18975935976501], +["1alq",1.8,2.51855754915911], +["1gqa",1.8,2.47836776446966], +["1hxl",1.8,1.96292474502754], +["1ip3",1.8,1.57374619102206], +["1bb3",1.8,2.48252865896848], +["1bb5",1.8,2.68494116423908], +["1zb0",1.8,1.33807735649368], +["1ift",1.8,2.40714762277362], +["1cai",1.8,1.97587071392589], +["1yo0",1.8,1.84075087121772], +["1yo2",1.8,1.73151179772406], +["1thk",1.8,1.95486284038057], +["1tg3",1.8,1.99783067640769], +["1ray",1.8,1.88907383952511], +["1rzb",1.8,1.93981172345527], +["1g52",1.8,1.74342325484637], +["1i9q",1.8,2.16429772658714], +["2f4f",1.8,2.83148818535344], +["1zzm",1.8,2.29411443227894], +["1syh",1.8,1.51946376474720], +["1sc3",1.8,2.30392477471667], +["1bbh",1.8,2.41567882490073], +["1mqh",1.8,1.56755188794269], +["1esi",1.8,2.53976401984341], +["1iyo",1.8,2.17498098147508], +["1flj",1.8,2.27272008166592], +["1j6o",1.8,2.03886637359839], +["1cl8",1.8,2.43448040068301], +["1j1q",1.8,2.02056718860398], +["1gik",1.8,3.96719761780909], +["1wt0",1.8,2.12222279019944], +["1wt3",1.8,2.60334909879316], +["1gns",1.8,2.31890386591890], +["1hxz",1.8,2.36135468084805], +["1qah",1.8,2.4825878262783], +["2bs6",1.8,1.30948947330959], +["1c21",1.8,2.32636759245155], +["1suc",1.8,1.99653638088377], +["1jwz",1.8,1.99748685035121], +["1btl",1.8,1.20366567598923], +["1bt5",1.8,1.73711070740369], +["1tdz",1.8,1.59785768555716], +["1lz0",1.8,2.07676150738384], +["1ak0",1.8,2.2302701330677], +["1tdl",1.8,1.41720613363278], +["1tdg",1.8,1.59148497145799], +["1w6p",1.8,2.35455119412168], +["1tys",1.8,1.13750090228206], +["1nvr",1.8,2.26544238289184], +["1nvs",1.8,2.23466489338957], +["1pk1",1.8,2.01731804955692], +["1sue",1.8,2.29475734027331], +["1mcv",1.8,2.17607082678995], +["1iav",1.8,1.97300025892852], +["1c9j",1.8,1.88519223100754], +["1ndq",1.8,2.28751360146152], +["1dbi",1.8,1.77636557654604], +["4vhb",1.8,2.41611345696459], +["1y1f",1.8,1.41652912429404], +["1e0c",1.8,1.68873707348564], +["1nul",1.8,1.93738340340118], +["1uk9",1.8,1.43639591463163], +["1ukb",1.8,1.53826935898730], +["1f2p",1.8,1.34162054756905], +["1t8h",1.8,2.06319029943036], +["1ppf",1.8,2.65781133606256], +["1py3",1.8,2.17689138243651], +["1dqe",1.8,2.40789785799572], +["2bik",1.8,1.41128517931850], +["1a8s",1.8,2.05846336416186], +["2hvm",1.8,1.7817082357953], +["1xws",1.8,1.64941011680375], +["1kve",1.8,1.90255403042830], +["1kvd",1.8,1.91378196108310], +["1nh8",1.8,2.25675826338878], +["1om0",1.8,1.92212272986532], +["1au9",1.8,1.2921603312893], +["1aqn",1.8,1.33653292895676], +["1ak9",1.8,1.45790915795727], +["2st1",1.8,1.88165704793123], +["1yja",1.8,1.95663743378888], +["1yjb",1.8,1.82992793202926], +["1sbh",1.8,1.82077926524670], +["1yjc",1.8,2.37327004626197], +["1taw",1.8,2.05566522448918], +["3btm",1.8,1.65092016094330], +["1ydi",1.8,2.28610626495975], +["3btf",1.8,1.71213549263593], +["1a4w",1.8,2.91610131317683], +["1t6k",1.8,2.19467120918834], +["1i6n",1.8,1.86472727513959], +["1ig1",1.8,2.53045875177183], +["1ht3",1.8,2.68953001328642], +["2b6n",1.8,1.39335702045929], +["1tgs",1.8,2.36964449758715], +["1tom",1.8,2.30647738090549], +["1qbv",1.8,2.52252937755283], +["1h08",1.8,2.23435996109714], +["1q04",1.8,1.8447057306807], +["1z71",1.8,2.31302269382576], +["1nm6",1.8,2.09658912877199], +["1ntf",1.8,2.01492650648732], +["2bv5",1.8,1.66417767302609], +["1ypg",1.8,2.24519030474042], +["1oem",1.8,2.37965217041723], +["1r1w",1.8,1.80219477817606], +["1eok",1.8,2.43721535358915], +["1j35",1.8,2.71590577434876], +["1zgy",1.8,3.23183253247597], +["1w9a",1.8,1.18323516263224], +["1f0n",1.8,2.63733571728848], +["4pnp",1.8,2.26868470555602], +["1xxo",1.8,2.13223297683244], +["1z6e",1.8,2.64820404474032], +["1wdy",1.8,1.61567944988085], +["1yvt",1.8,1.98622724132521], +["1ibe",1.8,2.63921871200718], +["1cho",1.8,2.7668757559938], +["1ay6",1.8,3.25997512446008], +["1ba8",1.8,3.2676993277951], +["1tml",1.8,2.05380810922867], +["1m6p",1.8,2.35586921386282], +["2evi",1.8,1.59915073776831], +["1rpj",1.8,1.99834472409230], +["6hbi",1.8,1.6796517507512], +["2aup",1.8,1.94425255004598], +["2auq",1.8,1.71893279509747], +["1eb1",1.8,2.52014926066916], +["1kxn",1.8,2.09293382831331], +["1nar",1.8,2.38374327293084], +["4dcg",1.8,2.36373841300766], +["3mag",1.8,2.45919833351817], +["1v39",1.8,2.48467747731572], +["1mtz",1.8,2.30279929228202], +["1xro",1.8,2.80473900853064], +["2c6i",1.8,2.50386031121082], +["1kjw",1.8,1.91156117318282], +["1amp",1.8,1.88157620530580], +["1ryc",1.8,1.91978105440956], +["1cca",1.8,1.95386146059285], +["1hcl",1.8,2.72068522942331], +["1g5f",1.8,2.07163159175946], +["1g4h",1.8,2.07689134580041], +["2fvh",1.8,2.22029020429558], +["1yhv",1.8,2.79018017728883], +["1yhw",1.8,3.02640464552873], +["1c3d",1.8,1.97720198845495], +["1k5p",1.8,1.84814776469039], +["1k63",1.8,1.74124102702109], +["1b2r",1.8,2.19835024040801], +["1h72",1.8,1.65251791931536], +["1w7x",1.8,1.67035940753528], +["1r4s",1.8,1.91119589682747], +["1j7k",1.8,1.57564945527899], +["1r0p",1.8,1.40064124125735], +["1c83",1.8,2.48158014793959], +["2c27",1.8,2.35304983389774], +["1dbx",1.8,2.23237835014265], +["1in6",1.8,2.0607173122791], +["2exm",1.8,2.95572921951897], +["1ykr",1.8,3.04084065729026], +["2bge",1.8,2.36971999841925], +["1inn",1.8,1.87794822386398], +["1k2e",1.8,1.82526641235889], +["1zuo",1.8,1.86230477055128], +["2por",1.8,1.86437503316279], +["1tux",1.8,2.20460985799911], +["1ksh",1.8,2.54542518514385], +["1j7x",1.8,2.53058466996195], +["1eeo",1.8,2.25715076636695], +["1goq",1.8,2.41586055451568], +["1ptz",1.8,1.99163546641576], +["1m6m",1.8,2.18756544978284], +["1mwd",1.8,2.08385901693065], +["1u5a",1.8,1.12086906930901], +["1jhf",1.8,2.16010099432877], +["5abp",1.8,2.31204989321151], +["1fs1",1.8,2.97874475168286], +["1g55",1.8,1.95609918268299], +["1h6u",1.8,2.15630311651443], +["1doz",1.8,1.58719205358199], +["1beb",1.8,3.06170317786872], +["1pgs",1.8,2.68201816569907], +["1pyf",1.8,2.06145071117772], +["1exp",1.8,2.03928431504526], +["2exo",1.8,2.12939834422359], +["1b6t",1.8,2.46255056250841], +["1g85",1.8,2.18514214735943], +["1ta8",1.8,1.58105942845308], +["1gt3",1.8,2.52618746738099], +["2a0k",1.8,1.10165069699009], +["1az1",1.8,2.26516296705165], +["1tag",1.8,1.97284963383802], +["1cs8",1.8,1.86153956911462], +["1t26",1.8,1.77955013748545], +["1xov",1.8,2.00742409349205], +["1s2c",1.8,1.60677624321106], +["1kr6",1.8,1.57726304379668], +["1kl6",1.8,1.60077515842732], +["1pe8",1.8,2.10720397114847], +["1lnb",1.8,2.12265629117921], +["1lnc",1.8,2.16742594870449], +["1dhj",1.8,2.48838609760023], +["1k6i",1.8,2.37651326099223], +["1j5x",1.8,1.8377508653113], +["1t40",1.8,2.26671950469180], +["1j4r",1.8,2.45531440248814], +["1vzo",1.8,2.4095741782615], +["2esr",1.8,2.02948154192851], +["1vhs",1.8,1.86054957696879], +["1qs7",1.8,1.90842317013551], +["1b0w",1.8,2.90958581143910], +["1b2x",1.8,1.79645941328448], +["1a73",1.8,2.06285493027800], +["1pot",1.8,3.33683863020633], +["3app",1.8,2.13430881595066], +["1tl9",1.8,1.86152064523315], +["1bg2",1.8,2.72834563654323], +["1xfk",1.8,1.90348827587474], +["2apr",1.8,1.38729235124925], +["1apt",1.8,1.74597676063060], +["1apv",1.8,1.62735313436224], +["1apw",1.8,1.78515699282784], +["1apu",1.8,1.85583364594882], +["1ppk",1.8,1.79060602938765], +["4pep",1.8,2.73947296693636], +["1euj",1.8,2.39456581001361], +["2ag4",1.8,1.61340230626411], +["1wko",1.8,1.62761975001921], +["3apr",1.8,1.45599607778886], +["2d2h",1.8,1.97050874582952], +["1fqe",1.8,2.39617302310649], +["1d3k",1.8,2.25825536588496], +["1a8f",1.8,2.44092350286175], +["1nv0",1.8,2.68411865754579], +["1lf2",1.8,2.78023090828715], +["1n5n",1.8,2.19714396516002], +["1nkp",1.8,2.41523838721272], +["1tr9",1.8,1.84354265000286], +["1rhc",1.8,1.87307490100682], +["1v1t",1.8,2.02803105921928], +["1i9z",1.8,2.55358610075373], +["1c02",1.8,2.22627012287084], +["5er2",1.8,2.32397907527004], +["1xud",1.8,1.74710404253015], +["1vai",1.8,2.97924307613759], +["1fob",1.8,2.08126080194180], +["2f0a",1.8,2.44035752024521], +["2g3t",1.8,2.53461934963791], +["2b9f",1.8,2.17208293197678], +["2sec",1.8,1.77154894803955], +["1gzb",1.8,2.25375005357956], +["1j71",1.8,2.05697573441508], +["3er5",1.8,2.02993544327967], +["1e6c",1.8,2.41548690013772], +["2ben",1.8,1.78585701083662], +["1a9y",1.8,2.12696999142275], +["1nah",1.8,1.71161005855252], +["1xel",1.8,1.97094364379079], +["1uda",1.8,2.10642165530325], +["1lrl",1.8,2.21615716412693], +["1et8",1.8,1.85672518838753], +["1slu",1.8,2.39059043196398], +["9wga",1.8,3.1748768905655], +["1vbi",1.8,2.00913528568526], +["1weh",1.8,1.79009635626649], +["1gjp",1.8,2.83708656792128], +["1uxy",1.8,1.76830732535068], +["2mbr",1.8,2.21556655205722], +["1wx2",1.8,2.40733743227587], +["1mo1",1.8,1.87986826467523], +["1foa",1.8,2.14561940927237], +["2aq2",1.8,2.25554655563], +["1unk",1.8,2.51988921859453], +["1y3d",1.8,1.49684411232250], +["1y3b",1.8,1.75851688372235], +["1y33",1.8,1.90619675662929], +["1s9d",1.8,1.96595892501774], +["1dgm",1.8,1.68569660693072], +["1xiy",1.8,1.97570823636936], +["1ek5",1.8,2.38643295867638], +["1j1p",1.8,2.0302107687644], +["1j1x",1.8,2.01580776664672], +["1j1o",1.8,2.18981100706228], +["1v33",1.8,2.18293049786324], +["1bg6",1.8,2.77967742300265], +["1jh8",1.8,2.45661638690968], +["2a5d",1.8,1.87443901103940], +["1ag9",1.8,1.82156949172840], +["1vfb",1.8,1.83315952520359], +["1g7i",1.8,2.51651539731314], +["1vfl",1.8,2.73022692469172], +["1zzc",1.8,2.06525698258709], +["1w8k",1.8,2.72756236459889], +["1vpr",1.8,1.85615472129996], +["1nvk",1.8,1.68177032686006], +["1boa",1.8,1.42506760612303], +["1wbs",1.8,1.96399644833491], +["1h6l",1.8,2.15603910455256], +["1ka0",1.8,2.07513746529628], +["1bn5",1.8,1.53641569528135], +["1b59",1.8,1.52654400110962], +["1x83",1.8,2.56725756258431], +["1xuo",1.8,1.61942584299701], +["1lkc",1.8,1.76347649632737], +["1m4g",1.8,2.03330359841852], +["1m4d",1.8,1.90656379278486], +["1lc8",1.8,1.91267946053100], +["1r4z",1.8,1.77937188306038], +["1udz",1.8,2.52330504841512], +["1tfz",1.8,2.48233263406132], +["1iq4",1.8,2.57508049973521], +["1uro",1.8,1.86891179604696], +["1umg",1.8,2.05635198612410], +["1qkr",1.8,1.96358060836246], +["1xqf",1.8,1.29901970805462], +["1lc7",1.8,2.15033260283375], +["1ytb",1.8,2.20213087090349], +["2fik",1.8,2.27932864113119], +["1jpu",1.8,1.81805724616533], +["1jh6",1.8,2.61512141856416], +["1jta",1.8,2.2119963937311], +["1d3h",1.8,1.86975221918179], +["1l8b",1.8,2.72010938216323], +["1lfa",1.8,2.35527136994384], +["1vys",1.8,2.24326128988893], +["1i59",1.8,2.53012359241793], +["1sqd",1.8,2.21231864813501], +["1qna",1.8,2.00199641439049], +["1tqf",1.8,1.74497190952952], +["1vk8",1.8,2.29236063656925], +["1ke1",1.8,1.93758132122934], +["2b8v",1.8,2.12220620150706], +["1dmb",1.8,3.14826687925669], +["1lls",1.8,2.21859436097336], +["2psg",1.8,2.24332118281659], +["1atz",1.8,1.65134722684661], +["1r86",1.8,1.98726192268596], +["2aob",1.8,2.53737912781999], +["1k4h",1.8,2.35361863970561], +["1qxj",1.8,1.95500887520265], +["1qy4",1.8,2.22212489143174], +["1c3p",1.8,2.99967147206331], +["1urg",1.8,2.04177959604053], +["1wyb",1.8,1.62750392832117], +["1iir",1.8,1.56523529014153], +["1lm5",1.8,2.37596319071589], +["1uhh",1.8,1.67156596241738], +["1uhj",1.8,1.86720987597079], +["1uhi",1.8,2.26045879997394], +["1fzm",1.8,1.63735553176177], +["1vd5",1.8,1.83850872671197], +["1fzo",1.8,1.74450633230524], +["1uvq",1.8,1.53981850926693], +["2ccm",1.8,2.34302480891319], +["2sic",1.8,3.32117122399698], +["3sic",1.8,3.39189642092624], +["2fur",1.8,1.56973493353263], +["2axf",1.8,2.05430338727934], +["1isa",1.8,1.84122363956593], +["1isc",1.8,1.61488955982337], +["1za5",1.8,2.26073324781472], +["1cs6",1.8,2.15237870294250], +["1fc6",1.8,2.38863255927171], +["1nnc",1.8,2.19992431317714], +["1l7f",1.8,1.99403012338221], +["2qwg",1.8,2.29034060453501], +["1f8b",1.8,2.50505482802778], +["2qwh",1.8,2.23774990864757], +["2qwk",1.8,2.36917887222199], +["1n4g",1.8,1.557344908613], +["1kk1",1.8,2.18561894489405], +["1gus",1.8,1.8415422721013], +["1k0i",1.8,1.96397939520971], +["1ars",1.8,3.08782904059564], +["1art",1.8,3.04365192726536], +["1f5j",1.8,1.75519359279990], +["1vca",1.8,2.60587860610344], +["2fnj",1.8,2.43745182968302], +["1xuq",1.8,2.05501745094683], +["1atl",1.8,1.87137048015951], +["2bsp",1.8,1.94899609355915], +["1bn8",1.8,1.61212517079581], +["1xqd",1.8,1.77382036466986], +["1xre",1.8,2.26511392389079], +["1r1p",1.8,2.55376685516974], +["2bwm",1.8,1.45880550644472], +["1aye",1.8,1.95632353889233], +["1k3o",1.8,2.65507235559201], +["1dlj",1.8,1.68473465943770], +["2d09",1.8,3.17381771277095], +["3mds",1.8,1.86623166084885], +["1mng",1.8,1.86615335590968], +["2cz7",1.8,1.49603648537964], +["1akd",1.8,2.17998895790385], +["1oe7",1.8,2.42522821654002], +["1yac",1.8,1.74004184476305], +["1t85",1.8,2.08324913413050], +["1ajk",1.8,1.82619616799771], +["1x8d",1.8,2.1967345867663], +["1sjn",1.8,1.57389960959521], +["1hdi",1.8,2.39530955322358], +["1zjc",1.8,1.70424643382273], +["3bam",1.8,2.82984961868271], +["1vgt",1.8,2.17149926313034], +["1glq",1.8,1.72377009563301], +["1pgt",1.8,2.2648589425871], +["1f5s",1.8,1.91338119576333], +["1l7n",1.8,2.09296780924403], +["1wy1",1.8,1.55689394472826], +["1ejc",1.8,1.80665669525372], +["1uae",1.8,2.15823432968899], +["1ia6",1.8,1.53516652749036], +["1t2w",1.8,2.53708600022093], +["2bjb",1.8,1.89719241160991], +["1xbz",1.8,1.59856341379768], +["1jax",1.8,1.70212928418277], +["1k70",1.8,1.83165409122387], +["1uj2",1.8,1.84891847076625], +["2c9h",1.8,2.06888828950407], +["1so5",1.8,1.71921420829499], +["1q6l",1.8,1.53392405845991], +["1ugr",1.8,1.51775123917634], +["1ire",1.8,1.52512128017615], +["1n7m",1.8,2.41300070343291], +["2a77",1.8,2.83315278851135], +["1q25",1.8,3.05830952828632], +["1yks",1.8,2.60501158304114], +["1kcv",1.8,2.74851706492162], +["1vfr",1.8,1.77936730008714], +["1xw5",1.8,1.96109169504320], +["2gst",1.8,2.44952088159228], +["1ve2",1.8,2.33521404101325], +["1auo",1.8,2.44803621281175], +["1um4",1.8,2.64974269206245], +["1um6",1.8,2.88045224103799], +["1l7i",1.8,2.17038718691046], +["1amz",1.8,2.64705959128849], +["2b4v",1.8,1.66113824264887], +["1jgu",1.8,2.33426958494819], +["1r89",1.8,2.04600874612162], +["1jjt",1.8,2.66243491385054], +["1qup",1.8,2.09753165091224], +["1hyy",1.8,3.09754137123552], +["1hyx",1.8,3.40767722836744], +["1pl2",1.8,1.51892710920003], +["1jje",1.8,2.77042136498627], +["1k0n",1.8,2.22036812964615], +["1pz5",1.8,2.26210197490815], +["1dll",1.8,2.7934276333704], +["1swl",1.8,2.43852542853013], +["1xp2",1.8,2.09499460475832], +["1rtm",1.8,1.98613096257574], +["1nc9",1.8,2.88433020074058], +["1bu8",1.8,2.16908776929795], +["4aop",1.8,2.26379045929494], +["1g9h",1.8,1.65555910200382], +["2gi3",1.8,1.45656495108440], +["2boj",1.8,1.50284074765512], +["6gep",1.8,1.99076250081557], +["1len",1.8,2.74494377996861], +["2lal",1.8,3.09648470744662], +["1swc",1.8,2.83556215719902], +["1swg",1.8,2.20862108339942], +["1h0b",1.8,1.84857321935530], +["2blf",1.8,1.17486270242987], +["1py6",1.8,2.51298005814457], +["1bkj",1.8,1.05716066606688], +["1m6i",1.8,1.89127084341659], +["1tv4",1.8,1.78198100640876], +["1zw0",1.8,2.52058786505114], +["1hyl",1.8,2.27417775204287], +["1lvm",1.8,2.57813181708614], +["1k7q",1.8,1.65163728449182], +["6cha",1.8,3.54287797475136], +["1xcf",1.8,2.77256744196345], +["1dug",1.8,2.76515019260338], +["1gx1",1.8,2.11563953660127], +["1t4h",1.8,1.91273127937896], +["1vyb",1.8,1.95145775049761], +["1lfw",1.8,2.4221533305534], +["1h8z",1.8,2.46957863476580], +["1j09",1.8,2.24634550524000], +["1ny1",1.8,2.08275042594546], +["1af0",1.8,1.69164735559114], +["1suz",1.8,2.50047857223944], +["1w1q",1.8,1.37296339086818], +["1rk5",1.8,1.64709371484461], +["1rjq",1.8,1.61135721113683], +["1rjp",1.8,1.54409370473070], +["1qnf",1.8,2.97985613717251], +["1xff",1.8,2.06012295532454], +["1kgi",1.8,2.25739344714669], +["1jsd",1.8,2.20142815879327], +["1cy9",1.8,2.17383768252264], +["1s1a",1.8,1.70243696975546], +["1nlv",1.8,2.79852852680659], +["1nm1",1.8,2.49557392983481], +["1kl5",1.8,2.18554388409709], +["1tph",1.8,2.00012411933323], +["2cga",1.8,2.59118794568593], +["6std",1.8,1.78121735396433], +["7std",1.8,2.22002821180733], +["2etg",1.8,2.24237653994127], +["1i45",1.8,1.81628057208976], +["1fpo",1.8,1.99179306783324], +["1wn5",1.8,1.45351116962021], +["1hny",1.8,2.04327231522571], +["1gr7",1.8,1.47071788531727], +["1tpf",1.8,2.53628024768893], +["1fxp",1.8,2.11091476557399], +["3cox",1.8,1.88674794393431], +["1cbo",1.8,1.93464708366707], +["1fvu",1.8,2.37165217316657], +["1a28",1.8,2.02880271265626], +["1coy",1.8,1.93662628415777], +["1vic",1.8,2.21394819435545], +["1sd3",1.8,2.05684249734574], +["1s9t",1.8,2.11427006766524], +["1lbv",1.8,3.10710052510989], +["1jcx",1.8,2.18453390198752], +["1woq",1.8,2.10063088587429], +["1dxe",1.8,2.09377447779861], +["1xq6",1.8,2.51783153770619], +["1rwi",1.8,1.85450919782496], +["1vc4",1.8,1.97498714914710], +["1lro",1.8,2.15195172355716], +["1t8x",1.8,2.16701493813811], +["1pck",1.8,2.01701634571396], +["1fmc",1.8,2.38404719702078], +["1uuz",1.8,2.41224216072919], +["1ftl",1.8,1.76434725968227], +["1p1w",1.8,1.89106393019886], +["1i22",1.8,2.85918132174161], +["1lrq",1.8,2.08561619864797], +["1oyw",1.8,2.17580968419788], +["2aqj",1.8,2.10612223360279], +["1b1h",1.8,1.71098918262975], +["2rkm",1.8,1.80286240473420], +["1b6h",1.8,1.91359566094434], +["1b51",1.8,1.86978639004979], +["1b9j",1.8,1.82491520872650], +["1b3f",1.8,1.93857611944816], +["1b58",1.8,2.16006508981067], +["1qka",1.8,1.80009830842296], +["1b5j",1.8,1.89972421768398], +["1qkb",1.8,2.04134992320487], +["1b46",1.8,2.01750116734768], +["1qx4",1.8,2.33527963977315], +["1fxq",1.8,2.08808939186737], +["1x1n",1.8,1.53023649872197], +["1fsj",1.8,1.48723134492127], +["1y1m",1.8,1.95774422117204], +["1umz",1.8,2.31519624989807], +["1ayl",1.8,2.23881913682059], +["1ea5",1.8,2.10100630276152], +["1dg3",1.8,1.94509382056164], +["1k9t",1.8,2.07298508328575], +["1tyv",1.8,1.50815447713359], +["1qq1",1.8,1.65626320183713], +["1tyx",1.8,1.80737065487800], +["1tyw",1.8,1.82347406886031], +["1tyu",1.8,1.79106780225188], +["1eib",1.8,1.41288024155412], +["1ffr",1.8,2.09839547605108], +["1thg",1.8,1.72165413963396], +["1w2f",1.8,2.67825738194489], +["1p7p",1.8,1.85050455837924], +["1mna",1.8,2.68608435083205], +["2a61",1.8,2.07418350399244], +["1nby",1.8,2.48451728120312], +["1svd",1.8,1.52834169183180], +["1vla",1.8,1.68467063335043], +["1qwi",1.8,1.65716730270931], +["1mpg",1.8,1.81415307131669], +["1m38",1.8,2.43338483657203], +["1o6s",1.8,2.13281321199715], +["1a3n",1.8,1.57421592609776], +["1a3o",1.8,1.91563234715437], +["1kss",1.8,2.09968644449997], +["1qjd",1.8,2.68327692871857], +["1gbu",1.8,2.33947001850469], +["1a01",1.8,2.20549856962988], +["1o1n",1.8,2.02311893345035], +["1r1y",1.8,1.83482491941402], +["1qpw",1.8,2.99526889573328], +["1qi8",1.8,1.99364637820968], +["1ye2",1.8,2.31672401296620], +["1o1o",1.8,2.12388635407048], +["1yvq",1.8,1.84060955473999], +["1sdk",1.8,2.65220759356231], +["1sdl",1.8,2.81536053136854], +["1fhj",1.8,2.74263772040107], +["1n2g",1.8,1.41807121383839], +["1a3a",1.8,1.80253421206228], +["1o1p",1.8,1.89774916284515], +["1c7c",1.8,1.88808865267336], +["1o1l",1.8,2.20000786078811], +["1hy3",1.8,2.16387678214198], +["1n2j",1.8,1.67190704589277], +["1c7d",1.8,2.09134913361984], +["2aa1",1.8,1.63318069193930], +["1gx0",1.8,1.78367090116319], +["1gww",1.8,1.98099608369882], +["1f7b",1.8,1.32977047206906], +["1feh",1.8,1.97973759803835], +["1pym",1.8,2.23328907700855], +["1p2n",1.8,1.32109392419143], +["1t8m",1.8,1.43118242756706], +["1p2q",1.8,1.69753456262848], +["1f0y",1.8,1.91785125778257], +["1nkc",1.8,1.55045052808232], +["1nke",1.8,1.78292684450796], +["1l3u",1.8,1.98083932986619], +["4bdp",1.8,2.89535001110939], +["2bdp",1.8,2.71763190338550], +["19hc",1.8,1.52717232839068], +["1pxv",1.8,2.20447045942346], +["1wlg",1.8,2.20891554085174], +["1ypf",1.8,2.40520598931559], +["1o5k",1.8,1.74921205192462], +["1h4r",1.8,2.070729957914], +["1v5f",1.8,2.14811050720918], +["1uxk",1.8,2.01638109298123], +["1s5o",1.8,2.74191851853549], +["2f57",1.8,1.38084472547376], +["1v99",1.8,2.02443364515162], +["2fcv",1.8,1.52434690279264], +["1yj7",1.8,1.65106487135219], +["1s4i",1.8,3.5834213901901], +["2ber",1.8,1.76958021361671], +["1qfy",1.8,2.27487248887147], +["1x39",1.8,1.93622982097812], +["1uf8",1.8,1.72509557457506], +["1xxq",1.8,2.05204797367190], +["1i1d",1.8,2.12887163675126], +["2bdw",1.8,2.42028196421848], +["1wwr",1.8,2.60560982440406], +["2bfy",1.8,2.40982485763495], +["1jrc",1.8,1.96189364336434], +["1jue",1.8,1.84925724363769], +["2bfx",1.8,2.56536261922270], +["1ytl",1.8,2.28796678322061], +["1qwr",1.8,2.11774163219815], +["2b7k",1.8,2.17946093098391], +["1y9i",1.8,1.94789180233339], +["1rli",1.8,2.13652358375774], +["1y4t",1.8,2.19950977787067], +["1dl5",1.8,1.66589657212196], +["1ebl",1.8,2.56592279735574], +["2cyb",1.8,2.27866633621273], +["1oau",1.8,3.00314694304142], +["1ig0",1.8,2.47385261270258], +["1g16",1.8,2.08483745525913], +["1k6j",1.8,2.07092198843220], +["1uh4",1.8,2.37134875367959], +["1bdm",1.8,2.53845873681255], +["1f1r",1.8,1.55017637657765], +["1z08",1.8,1.44861038716942], +["1kfj",1.8,2.06055775186159], +["1qoq",1.8,1.57168121202648], +["1w4v",1.8,2.42067666851093], +["1vbu",1.8,1.64799834824456], +["1vbr",1.8,1.95562024655789], +["1gad",1.8,2.30921589510443], +["1n7h",1.8,1.28494862667428], +["1x88",1.8,2.06198230600382], +["1nxu",1.8,2.61715220283068], +["1hrn",1.8,3.19690064835737], +["1hxp",1.8,2.52755434353054], +["1ujn",1.8,2.01353298764048], +["2cwf",1.8,1.63351977610458], +["1z48",1.8,1.87931004078865], +["1jp7",1.8,2.22023871306624], +["1yr2",1.8,1.55676526577795], +["2udp",1.8,2.36350140116764], +["1a6v",1.8,3.68946456555226], +["1pm2",1.8,2.12083809037768], +["1u7h",1.8,1.77535412488037], +["3sli",1.8,2.35440639035471], +["2sli",1.8,2.37604772085358], +["4sli",1.8,2.43491683363380], +["1v1r",1.8,1.98903634117234], +["1zze",1.8,1.82864434444236], +["1mmz",1.8,2.50763102745072], +["1nsu",1.8,2.48790249795064], +["1mmx",1.8,2.49403359093443], +["1mmu",1.8,2.41599517954582], +["1nsr",1.8,2.65392388272432], +["1nsv",1.8,2.66927827684784], +["1ns8",1.8,2.61125713903506], +["1qpa",1.8,2.19989782337427], +["3pro",1.8,1.93504165909873], +["1usi",1.8,1.62161416340431], +["1ket",1.8,1.56314570808155], +["1b82",1.8,1.35389729969074], +["1wvg",1.8,3.22671201149809], +["1jpv",1.8,2.46508342945551], +["1sxq",1.8,1.75280812862512], +["1m5r",1.8,1.97323415657556], +["1f7t",1.8,2.12475919470085], +["1ll5",1.8,1.85104062147553], +["1n71",1.8,2.57660457765257], +["2bjr",1.8,1.72064735713381], +["1j1b",1.8,2.81103342097603], +["1tf1",1.8,2.44646802119837], +["2cd9",1.8,1.87570507249214], +["1ld8",1.8,1.92986362312915], +["1kew",1.8,1.98605658212016], +["2bev",1.8,1.92675122789298], +["2a1h",1.8,1.81627961113689], +["1fn9",1.8,1.54116414576778], +["1tn6",1.8,1.50503166644290], +["1ytv",1.8,2.02829057968095], +["1p0f",1.8,1.84505487837043], +["1v4v",1.8,2.58555648936769], +["2gdq",1.8,1.84374105910047], +["1qv6",1.8,1.42930952166511], +["2ohx",1.8,1.95402059567587], +["1qv7",1.8,1.78529243300993], +["2nac",1.8,1.97388979753551], +["1yx1",1.8,1.87803402665441], +["1ci9",1.8,2.28893775513241], +["1x1i",1.8,2.31528620106068], +["1dqs",1.8,1.69101901954474], +["1qnn",1.8,2.3563866547014], +["1xql",1.8,2.18404622274032], +["1y0b",1.8,1.76392866125754], +["1i7u",1.8,1.99131668804091], +["1duz",1.8,2.103348606809], +["1tvb",1.8,1.98851877516582], +["1elq",1.8,2.36755378126259], +["1bjw",1.8,2.37833196963531], +["1t0n",1.8,2.33292383693234], +["1gm9",1.8,1.94055645567437], +["1b5p",1.8,2.5480292959084], +["1qo7",1.8,1.59423051926189], +["1el5",1.8,2.12897858059540], +["1xym",1.8,2.10356245449064], +["1xyl",1.8,2.20633442410372], +["1my2",1.8,2.34286077631848], +["1mxu",1.8,1.92091996615134], +["1lbc",1.8,2.27229757438992], +["1gd9",1.8,2.51032129308624], +["1gde",1.8,2.09309650405465], +["1nzc",1.8,2.24193544128078], +["2a97",1.8,2.90020964599914], +["1v7v",1.8,2.02404660826639], +["1nsd",1.8,2.05944789772636], +["1afw",1.8,3.13001132850049], +["1iyi",1.8,1.91698389053313], +["2as0",1.8,2.17219632180549], +["1h2a",1.8,2.92446089622439], +["2c25",1.8,1.49567294771113], +["1nzy",1.8,2.63769871506657], +["1vme",1.8,1.33195670584206], +["1k06",1.8,2.81942355825916], +["1t3i",1.8,1.76593180027575], +["1ww3",1.8,2.51663422828601], +["1o76",1.8,2.19837287125142], +["1t87",1.8,1.86631962202404], +["1rzh",1.8,1.94094421680474], +["1e3a",1.8,1.83939155685163], +["1giq",1.8,2.72545123753809], +["1jny",1.8,2.82899543488907], +["1o9p",1.8,2.13840440761031], +["1och",1.8,2.30803431606405], +["1o9q",1.8,2.3033168425725], +["1ock",1.8,1.88068468126468], +["1skq",1.8,2.83476430151763], +["1tu8",1.8,1.90199563535653], +["1pt7",1.8,1.99420623015812], +["1ed5",1.8,2.41696707060718], +["1aqw",1.8,1.95413271303829], +["1o2a",1.8,1.87207240937123], +["1xtt",1.8,2.24821687316932], +["8fab",1.8,2.21992634633473], +["1c3c",1.8,2.02447297051475], +["1dqq",1.8,2.61715120100847], +["1esj",1.8,2.43913403518494], +["1uz8",1.8,2.13680035885189], +["1ngx",1.8,2.63612062805002], +["1qj5",1.8,2.03640594682861], +["1c7s",1.8,2.32359610620694], +["1kqc",1.8,1.70983123520766], +["1kqb",1.8,1.66244695736659], +["1icu",1.8,2.40732080578564], +["1te6",1.8,2.57747286065485], +["1v6c",1.8,2.00322574532844], +["1rqp",1.8,2.30714369106831], +["1p43",1.8,2.01833826458672], +["1yqp",1.8,2.11560210532239], +["1zhs",1.8,1.57496826720772], +["1i4y",1.8,2.21300201145355], +["1hcj",1.8,2.43004979257129], +["1s57",1.8,2.15387054523857], +["1n0x",1.8,2.43864850192209], +["1jou",1.8,2.58407404079830], +["1vdk",1.8,1.97923649042651], +["1gqy",1.8,1.99394126906373], +["1m0w",1.8,1.84547250819032], +["1ro7",1.8,2.20701964974158], +["1cyd",1.8,2.22845530432074], +["1e4d",1.8,2.06180243063503], +["1m21",1.8,1.68825352288473], +["2bek",1.8,2.05495134550265], +["1vga",1.8,2.0239950299317], +["1m2w",1.8,1.48398263302934], +["1xm3",1.8,2.30700481836566], +["1rjd",1.8,1.89111468437317], +["2bk3",1.8,1.95228740581370], +["1qw8",1.8,2.30998094520459], +["1ur9",1.8,2.63602155535368], +["1aom",1.8,1.7657535946148], +["1zlq",1.8,2.15939257425908], +["1pwx",1.8,3.59489056437583], +["1zdq",1.8,1.33199283151228], +["1npn",1.8,2.21378503202951], +["1fd7",1.8,2.00061972763372], +["1eef",1.8,1.90045876468693], +["1r33",1.8,1.59309996540483], +["1ps3",1.8,2.09134060296418], +["2bhp",1.8,1.59185639107801], +["1xu7",1.8,2.21352982763860], +["1xk4",1.8,1.96155515329362], +["1o60",1.8,2.24489707992837], +["1sio",1.8,2.43247735185545], +["1sw5",1.8,1.85612219087806], +["1naa",1.8,1.28628500995881], +["1kbq",1.8,2.75677558315083], +["1t6g",1.8,1.80242708139427], +["2dbw",1.8,2.08240042746544], +["1aoq",1.8,1.87934061372401], +["1hm5",1.8,2.37225121619888], +["1o58",1.8,1.61570494346058], +["1cxp",1.8,1.94092367615640], +["1m64",1.8,1.87388925558824], +["2cvz",1.8,1.89666135451525], +["1xs1",1.8,2.63386133374038], +["1jq3",1.8,1.94356494685850], +["1gpe",1.8,1.82306570191449], +["1hl2",1.8,2.07576487558712], +["1thz",1.8,1.88646990080861], +["1ndb",1.8,1.74265485783141], +["1t7q",1.8,1.75691968929755], +["1mr7",1.8,2.15791701727313], +["1hfw",1.8,2.02148829496870], +["1hg1",1.8,2.17713253312711], +["1k72",1.8,1.67219133268602], +["1iqc",1.8,2.56041791896163], +["1ja1",1.8,2.64754143169396], +["1ui8",1.8,1.90865590363667], +["1wmo",1.8,2.07710130819128], +["1wmn",1.8,2.16822583742601], +["1iu7",1.8,2.35211120370836], +["1iqy",1.8,2.39884638749207], +["1ivw",1.8,2.38112034078473], +["1ms1",1.8,2.02366936912072], +["1vqq",1.8,2.36229344616080], +["1mi3",1.8,1.34519645334962], +["2a40",1.8,1.67734111577753], +["1gd1",1.8,2.38231703399423], +["1vkn",1.8,1.57963590093264], +["1jds",1.8,1.61943347998585], +["1jg8",1.8,2.10061379822353], +["1pam",1.8,1.89892221668108], +["1guq",1.8,2.67877835483935], +["1gup",1.8,2.7912779457336], +["1clx",1.8,2.42099879206000], +["1je1",1.8,1.9594981371848], +["1rkx",1.8,2.26238015680018], +["1epx",1.8,2.32164969022353], +["1wap",1.8,2.13034596817094], +["1zah",1.8,2.40489175445848], +["1ryi",1.8,1.95948892503768], +["1mg0",1.8,1.62784757829701], +["1wxx",1.8,1.78908312713666], +["1j2t",1.8,1.73386905972148], +["1wz8",1.8,2.09234409606636], +["1r9d",1.8,2.05498929467810], +["2fje",1.8,2.14505710270052], +["1ukj",1.8,3.53500557974299], +["1l5w",1.8,2.23573301559415], +["1e3d",1.8,1.96486727365462], +["1w96",1.8,1.96609164045079], +["1f8m",1.8,2.18393196666870], +["1uc4",1.8,2.32055966576973], +["1e0t",1.8,3.04096904875240], +["1gu1",1.8,1.59478502263056], +["1d0i",1.8,1.98359590044184], +["1wog",1.8,2.24136948751416], +["1tez",1.8,2.125329945963], +["1m7s",1.8,1.98635877230928], +["1dgg",1.8,2.43628713569374], +["1xvb",1.8,2.4684230451014], +["1yif",1.8,2.21996867296429], +["1tt0",1.8,1.71675663974244], +["1ir1",1.8,2.16078763015934], +["1h0h",1.8,1.93251710285254], +["1hbm",1.8,1.50998075757490], +["1t3q",1.8,2.13705636879235], +["1tr0",1.8,2.08859556095319], +["1z03",1.8,2.52709609595763], +["1z02",1.8,2.62268150818841], +["1z01",1.8,2.73233084787757], +["2fli",1.8,2.46649651556018], +["1m3u",1.8,1.37297234647188], +["1hl5",1.8,1.97429082657157], +["1cf9",1.8,2.12759912391718], +["1orv",1.8,2.59033628191957], +["1q52",1.8,2.19874433464288], +["1jyn",1.8,2.33772539643685], +["1jz5",1.8,2.50354184996076], +["1p7g",1.8,2.83850187763029], +["1flq",1.8,1.33628977183649], +["1zr0",1.8,2.71572841830199], +["1tvh",1.8,2.11582283411423], +["1c7b",1.8,1.99657981130273], +["2a10",1.8,1.47757372586524], +["1va4",1.8,1.92481602482395], +["1ywo",1.81,2.28222088027477], +["1m6t",1.81,1.73150212927036], +["1csu",1.81,2.61157287756768], +["1w7o",1.81,2.78255925805414], +["1gyu",1.81,2.30564732836051], +["1a34",1.81,2.28724826465153], +["1z06",1.81,1.64788413089352], +["1z07",1.81,1.26748710149791], +["1sht",1.81,1.9903463010831], +["1oej",1.81,2.47452789139093], +["1ucj",1.81,1.48305960209754], +["1ebw",1.81,1.79480221536266], +["1d4i",1.81,1.6630484631059], +["1d4h",1.81,1.49495346223472], +["1d4j",1.81,1.49495346223472], +["1yc4",1.81,2.20526731168830], +["1kg9",1.81,2.48311202757413], +["1fny",1.81,2.27156036761621], +["1o3p",1.81,2.90708103386096], +["1x8b",1.81,2.72255739955371], +["1xeg",1.81,1.96511773677915], +["1qyv",1.81,1.56728317681411], +["1ype",1.81,2.05354896587532], +["1sl3",1.81,2.40238118581106], +["1gj4",1.81,2.83190606011754], +["1q33",1.81,2.30785504384874], +["1jln",1.81,2.5480763498237], +["2c3f",1.81,1.4784112158243], +["1zoh",1.81,2.26423148536949], +["1fux",1.81,2.14188528171611], +["1v3y",1.81,1.85101855437428], +["1s38",1.81,2.44841932854070], +["1gqe",1.81,2.24852157433473], +["2c3w",1.81,2.22284230113678], +["2a78",1.81,1.93594993418822], +["1tc2",1.81,1.94980725500087], +["1xbx",1.81,1.39595468490368], +["1gnd",1.81,2.78546512902789], +["1qyg",1.81,2.00063045188612], +["1ndj",1.81,2.67762083129849], +["2fr0",1.81,2.55219549264608], +["1y9a",1.81,2.04073309139514], +["1c96",1.81,2.76353597351271], +["1xya",1.81,2.18410267186383], +["1mly",1.81,2.33195153694958], +["1l7d",1.81,2.45906205103539], +["1p81",1.81,2.11874313607341], +["1flw",1.81,1.41905558989247], +["1zt5",1.82,2.08110566840705], +["1imx",1.82,2.30035859433331], +["1ybz",1.82,0.759602177677527], +["1be9",1.82,2.45714946536150], +["1nxp",1.82,2.63273807354162], +["1x6r",1.82,1.77313895679066], +["2rtk",1.82,2.60416220853913], +["1vwb",1.82,2.54969679005419], +["1hc0",1.82,2.51391718693761], +["1jap",1.82,2.37469129950399], +["1gto",1.82,2.50342649851161], +["1h8p",1.82,1.67499444942929], +["1uec",1.82,2.07653105732639], +["1v98",1.82,1.89282007466927], +["1ucl",1.82,1.54663938007828], +["1iv7",1.82,2.52800935050823], +["1jf0",1.82,2.21754732676569], +["1vaj",1.82,2.16601431841363], +["1ini",1.82,2.25575231681694], +["2a7l",1.82,1.78759090039346], +["2cbe",1.82,2.00195834215189], +["1h9s",1.82,2.09683933745388], +["1xrl",1.82,2.93443867858195], +["1stq",1.82,1.97487626581498], +["5a3h",1.82,1.55980967987494], +["1gy2",1.82,1.94719039148706], +["1fh7",1.82,2.05619544707908], +["1pe7",1.82,2.27849206933751], +["1v73",1.82,2.43596219051443], +["1dw0",1.82,1.74952354068034], +["1fp1",1.82,2.23717527378399], +["1eur",1.82,2.75444416330765], +["1ia2",1.82,2.21365976503247], +["1n0n",1.82,2.20571566626668], +["1hw5",1.82,3.28839068825878], +["1w78",1.82,2.18217349772382], +["1v84",1.82,2.39998099959721], +["1zsq",1.82,2.69510388244529], +["1ry9",1.82,1.91824838778967], +["1hl4",1.82,2.31633879483439], +["1uze",1.82,1.97962726604975], +["1b2s",1.82,1.76889063910263], +["1nqx",1.82,1.26706343820001], +["1dmr",1.82,1.67093646061558], +["1vp4",1.82,1.56972178919754], +["1iye",1.82,2.17984500786879], +["1wur",1.82,1.40046942026447], +["2bg5",1.82,2.51568210585037], +["1euh",1.82,2.08564820517294], +["1b65",1.82,2.40778487338994], +["1xb6",1.82,1.17573423283395], +["2hts",1.83,2.28958162428058], +["1s7z",1.83,2.29088734194711], +["1o13",1.83,1.11798009358310], +["1rfs",1.83,1.93077282313085], +["1r8o",1.83,2.78932591326285], +["1o5u",1.83,1.71805637002207], +["1iiq",1.83,1.62688987621322], +["1iae",1.83,1.78855717460983], +["1zrn",1.83,2.20111797665794], +["1wnh",1.83,2.26324182203406], +["1bit",1.83,2.38623874709274], +["1utj",1.83,1.51904035016848], +["1r9c",1.83,1.98934039359159], +["2bsj",1.83,1.72837463635518], +["1amk",1.83,3.05996624366343], +["2b44",1.83,1.47961860755782], +["1xwv",1.83,2.40339503097993], +["1g45",1.83,1.77068437144527], +["1vhb",1.83,2.38077733261993], +["1yqe",1.83,1.85447053141199], +["1dqy",1.83,2.47772051410766], +["1ylm",1.83,1.84534861475894], +["1bu5",1.83,2.51998312613469], +["1dzp",1.83,2.37777125030790], +["2fne",1.83,2.20344442234714], +["1hq0",1.83,1.81055069705406], +["1e00",1.83,2.45081625725465], +["1gn8",1.83,2.65195449949674], +["1c3i",1.83,2.14763525109586], +["1gun",1.83,1.77794965361437], +["1t2q",1.83,1.88542544812197], +["1ob0",1.83,1.60052969733000], +["1h7e",1.83,2.06615020604442], +["1tcd",1.83,2.42389746251618], +["5tim",1.83,2.60927499978695], +["1tx2",1.83,2.08610089496881], +["2g8x",1.83,2.35792539257665], +["1vlr",1.83,1.51064879351316], +["1z84",1.83,1.59791744371042], +["1xoq",1.83,1.47803249948661], +["1mxo",1.83,2.09386185900105], +["1u5b",1.83,1.86322903156104], +["1cl1",1.83,1.71640577210631], +["1xc7",1.83,2.11800197591235], +["1s09",1.83,2.08495671418017], +["2bk5",1.83,1.44450062049398], +["1w4r",1.83,1.7826907421254], +["1yqw",1.83,1.69549492428605], +["1fly",1.83,1.70009796215476], +["1fdn",1.84,1.96172292476866], +["1c4w",1.84,2.07274633143400], +["1b0d",1.84,1.38901467431279], +["2cj5",1.84,2.11342664458821], +["102m",1.84,2.45166232083028], +["1f8a",1.84,3.08064171224768], +["1xcm",1.84,2.15238599489558], +["1a44",1.84,1.97393417795178], +["1e4b",1.84,2.20108029779624], +["1xlo",1.84,2.05988565165863], +["1hne",1.84,3.35601940380765], +["1sqo",1.84,2.30113134554511], +["1g4j",1.84,1.91754211110836], +["1g46",1.84,2.28650316191824], +["1i9m",1.84,2.30451708468405], +["1zao",1.84,1.75982837663451], +["1tib",1.84,2.72194391560097], +["1ss4",1.84,1.94797588755472], +["1tz0",1.84,2.25755926871889], +["1rn1",1.84,1.89446599681672], +["1rkd",1.84,1.78345067939240], +["1y48",1.84,1.75504617083599], +["1i13",1.84,2.04848789340274], +["2cu5",1.84,1.65235015642397], +["1s3x",1.84,1.39164434575980], +["1cgk",1.84,2.08699056756724], +["1ze3",1.84,1.49924710354985], +["1aqk",1.84,3.52721572788219], +["2a4a",1.84,1.93521119607742], +["1sh7",1.84,2.01016003627909], +["1y4v",1.84,2.40587207423296], +["1sgj",1.84,2.28426964353697], +["1wci",1.84,1.85819837564686], +["1mb4",1.84,2.27853364953359], +["1o69",1.84,1.93389684617793], +["2ag5",1.84,1.62518871126534], +["1t2a",1.84,2.13778383383113], +["1v0z",1.84,1.99084020791296], +["2fjd",1.84,2.04867163269916], +["1jku",1.84,2.32961731734061], +["2c3m",1.84,2.30534586407411], +["1ir2",1.84,2.07766329208166], +["2bei",1.84,1.75200034150782], +["1mmi",1.85,2.89215970991088], +["1j8e",1.85,1.59448514359519], +["1cgd",1.85,1.86146234194427], +["1cag",1.85,2.18741920671845], +["1j75",1.85,2.19654746865113], +["1t7b",1.85,2.01627454087291], +["1igv",1.85,2.04217170444496], +["2cwy",1.85,1.57043531410099], +["1she",1.85,1.60791000954268], +["2byg",1.85,1.24414201589329], +["1i2g",1.85,1.62929001271427], +["1o4d",1.85,2.14474210292525], +["1o4b",1.85,2.18908948826351], +["1nxo",1.85,2.08219312317711], +["1hcv",1.85,2.35420621787808], +["2rln",1.85,1.95018568055793], +["1r9f",1.85,1.61215470843734], +["1mi0",1.85,3.28633865041377], +["1faa",1.85,2.59918839972996], +["1pzc",1.85,2.28297169854374], +["1gsw",1.85,2.13178479013098], +["1o3w",1.85,1.76222220666757], +["1fit",1.85,2.26848839757207], +["2f6e",1.85,1.11831933810116], +["1vwn",1.85,2.95643387922991], +["1uc0",1.85,1.64521694108263], +["1uif",1.85,1.81286307827746], +["2a7f",1.85,2.08027112319384], +["1qqy",1.85,2.26368481653574], +["1tuh",1.85,1.59620666571981], +["1gtw",1.85,1.98080637775181], +["1eyc",1.85,3.2263634471492], +["1ez8",1.85,2.92695563515813], +["1vyf",1.85,2.28004897710449], +["1sth",1.85,2.61904253830683], +["1gak",1.85,2.22847443282608], +["1tzu",1.85,2.51110747428428], +["1dok",1.85,2.22465883822951], +["1eb0",1.85,2.56528795651192], +["1bz4",1.85,2.06707591190487], +["1vls",1.85,3.51224240471939], +["1kfr",1.85,1.64185589699434], +["1bg7",1.85,1.75418851599214], +["1do7",1.85,1.20516546587147], +["2al7",1.85,2.16507464885197], +["1obm",1.85,2.48245546170663], +["2b3m",1.85,1.80614150344017], +["1oby",1.85,1.92096480415428], +["1tol",1.85,2.34334633412662], +["1ex8",1.85,2.65787172358432], +["157l",1.85,2.13678240178636], +["1l73",1.85,2.86875917323802], +["155l",1.85,1.85130438553119], +["220l",1.85,1.84962497085416], +["1l71",1.85,2.36318209016018], +["1quh",1.85,2.43651435617811], +["1l72",1.85,2.43007557864677], +["127l",1.85,1.96171909634679], +["1epy",1.85,2.36745065931191], +["109l",1.85,1.84654931115430], +["1l88",1.85,2.077596777345], +["1li3",1.85,2.15175948323439], +["1lgw",1.85,2.30103154875656], +["1cu2",1.85,2.32933299302838], +["125l",1.85,1.80811586928321], +["224l",1.85,2.10206710274333], +["146l",1.85,1.97272498576492], +["1qs9",1.85,2.32442124453963], +["1g0k",1.85,2.01936010756856], +["1qt3",1.85,2.19872839355449], +["1l21",1.85,2.39110345441979], +["1g06",1.85,2.32572815468106], +["1l39",1.85,2.43776144540993], +["1l40",1.85,2.43550015364653], +["1l37",1.85,2.36629832455103], +["1l20",1.85,2.31735076220273], +["1l53",1.85,2.75611728603406], +["1l50",1.85,2.41497533555406], +["1xen",1.85,1.80244370101638], +["1gnr",1.85,3.29562646218393], +["1o6a",1.85,1.69633896799966], +["1d03",1.85,1.39134411707269], +["1czo",1.85,1.35502657039362], +["1d04",1.85,1.42283650932879], +["1e3b",1.85,2.70876716510281], +["1yzl",1.85,1.89070852865496], +["1udv",1.85,2.61482983152709], +["1cyn",1.85,2.55062495247256], +["1cqq",1.85,2.66586106718690], +["1l1q",1.85,2.46705900610112], +["1y88",1.85,2.09942421062442], +["1avy",1.85,2.96822006391644], +["1zs7",1.85,1.72293626947035], +["1sdo",1.85,1.49412997560715], +["2fxq",1.85,2.52165862046801], +["1b6k",1.85,1.57703139773832], +["1d4k",1.85,1.92004785276292], +["1b6j",1.85,1.46622295298853], +["1z1r",1.85,1.62286156361316], +["1b6m",1.85,1.40833026325350], +["1z1h",1.85,1.73490551990488], +["1vct",1.85,1.84911187376558], +["1zjr",1.85,2.52298846225332], +["1ff0",1.85,1.46755950837727], +["1fg8",1.85,2.24947004214668], +["1ayf",1.85,2.21102849648272], +["1r54",1.85,2.08091458562367], +["1n5i",1.85,1.55400870504583], +["1n5j",1.85,1.59982842021325], +["1uzx",1.85,2.43057418027365], +["1rni",1.85,2.7527481357423], +["2abk",1.85,1.96981429251625], +["1d6o",1.85,2.05875973703393], +["1i2a",1.85,2.15151940078705], +["1amw",1.85,2.46209720688266], +["1qrl",1.85,2.82977452299444], +["1t15",1.85,2.45330611678765], +["1zip",1.85,2.05006731469091], +["1hna",1.85,2.95200715539191], +["1pk3",1.85,1.73274690719976], +["2bbh",1.85,2.16311936667397], +["2gab",1.85,1.52584837915083], +["1dxk",1.85,2.37256206053996], +["1bvt",1.85,2.66398987154965], +["1kzc",1.85,1.86726277945978], +["2awl",1.85,2.04355053493630], +["1u5v",1.85,2.48395467435573], +["1s84",1.85,1.20436816394146], +["1s82",1.85,1.01373389880161], +["1qy8",1.85,2.57473920711510], +["1t32",1.85,2.51556967129295], +["3fiv",1.85,3.02084344950715], +["2asu",1.85,1.32379027529193], +["2g9k",1.85,2.2533895116614], +["1wz1",1.85,1.93060872200277], +["2b94",1.85,1.36540395514891], +["2anw",1.85,2.41419351404699], +["1uaj",1.85,1.81874444392930], +["1xs5",1.85,1.76178940996264], +["1uvo",1.85,1.24842696117402], +["1uvp",1.85,1.53759403490077], +["1gwa",1.85,2.33991177905972], +["1z76",1.85,1.40305036271609], +["1fxf",1.85,2.93304996754951], +["1t6l",1.85,2.55216425803569], +["1zch",1.85,1.81191178237325], +["1ri8",1.85,1.43002330591594], +["1vwa",1.85,2.73420093959246], +["1o5b",1.85,2.72964419717401], +["1v8a",1.85,1.89204584110676], +["1c5z",1.85,2.72712492067651], +["1bv3",1.85,2.37385050453347], +["1ztt",1.85,2.7873984279413], +["3yas",1.85,1.98598831606738], +["1h9n",1.85,1.83266101596391], +["1gsj",1.85,1.90238895739472], +["1nnk",1.85,2.23072427622353], +["1xhy",1.85,1.62476492561299], +["1ckq",1.85,2.45025327534832], +["1zi4",1.85,2.12439566004079], +["1jwv",1.85,2.03653007596636], +["1v3r",1.85,2.02243466346142], +["1rwx",1.85,2.06098322963321], +["1bsg",1.85,1.71118246593615], +["2bxx",1.85,1.87875745970778], +["2c3b",1.85,1.23775284647430], +["1zbi",1.85,1.96769504836001], +["1v3s",1.85,2.0620760793623], +["2btr",1.85,2.53032094241555], +["2b55",1.85,2.56998017796581], +["3bte",1.85,1.90297371240625], +["1llo",1.85,1.80773548241696], +["3btk",1.85,1.68643203334899], +["1r3f",1.85,2.16553386026849], +["1puo",1.85,2.10556477835698], +["2aqz",1.85,1.90651319442559], +["2f2e",1.85,2.31569338307484], +["1ypm",1.85,2.63625367058757], +["1ypl",1.85,2.67625266992804], +["1ai8",1.85,2.44978574728155], +["1h07",1.85,2.3579970651822], +["1y2u",1.85,1.65200986643705], +["1jt5",1.85,2.23360724417799], +["1a3e",1.85,2.31233555160495], +["1zc0",1.85,1.62183999919191], +["1w8z",1.85,1.72450376066806], +["1u6d",1.85,1.33643623364649], +["1nxf",1.85,1.71819557854319], +["1l1d",1.85,1.70154784274623], +["1e1x",1.85,2.55093212390575], +["1ghy",1.85,2.32851600614513], +["1ghv",1.85,2.63155677826150], +["1sog",1.85,1.79038013448196], +["1k6e",1.85,1.84024639376224], +["1k26",1.85,1.85961032071387], +["2b54",1.85,3.47343793031372], +["1pty",1.85,1.64351092660355], +["1e9o",1.85,1.78377507395058], +["1e5j",1.85,1.60962322242725], +["1c39",1.85,2.09711219953449], +["1k8w",1.85,1.99175063553098], +["2auw",1.85,2.4559781508269], +["1wch",1.85,2.30563226692413], +["1v9m",1.85,2.00015299319834], +["2cfi",1.85,2.31504654184706], +["1sdw",1.85,2.48089980426742], +["2a7g",1.85,1.43714469588745], +["1dyj",1.85,2.670323657047], +["1ext",1.85,1.45292342612835], +["1t2e",1.85,2.01128043124013], +["1vfv",1.85,2.76409785373316], +["1zxx",1.85,1.99734694890093], +["1gux",1.85,3.12456797986736], +["2b3u",1.85,2.28548898668269], +["1oth",1.85,2.03119584444997], +["137l",1.85,2.50575773109249], +["2ao0",1.85,2.94333801340683], +["1yyz",1.85,2.02401847908853], +["2c7q",1.85,2.28736124990169], +["2a3t",1.85,1.60298237594714], +["2d2g",1.85,1.95093025405193], +["1jqf",1.85,1.97214402755142], +["1qfo",1.85,1.81445778022804], +["1y65",1.85,2.02926738506030], +["1j9y",1.85,1.32470259578797], +["1xur",1.85,1.71987835560654], +["2c2h",1.85,1.77930495708748], +["1ix1",1.85,1.75322125216350], +["1jvb",1.85,1.87743138272028], +["1g7h",1.85,2.83785918118423], +["1kiq",1.85,2.34138888468568], +["1lm8",1.85,2.69384463486021], +["1r7o",1.85,1.47038026289198], +["1nwk",1.85,1.70219232466399], +["2f4m",1.85,2.71899998512142], +["1r3r",1.85,1.5111297645797], +["1mdl",1.85,2.49141935409418], +["1obq",1.85,1.84510400051871], +["1q63",1.85,2.2546306484011], +["1zh5",1.85,1.63708344372871], +["1j3q",1.85,2.56378777173216], +["1ex2",1.85,2.30558242284592], +["1yw7",1.85,2.23450452621675], +["1f3e",1.85,2.47603197175096], +["1pud",1.85,2.54220691183433], +["1xdc",1.85,1.99942720097628], +["1jf1",1.85,2.01575864512549], +["1elj",1.85,2.06784010290723], +["1isb",1.85,1.7860855175532], +["1ia4",1.85,2.10264654514021], +["1ai9",1.85,2.77085535419191], +["1u7c",1.85,2.58301862921383], +["1l7g",1.85,1.97464970685690], +["1l7h",1.85,1.95528232558940], +["1pk6",1.85,2.17036108511880], +["2b2i",1.85,2.58749859562189], +["2b2j",1.85,3.00032965147791], +["1snf",1.85,1.69603394994211], +["1odo",1.85,1.87404145883653], +["1luv",1.85,2.48042565915116], +["1eqc",1.85,1.50789649781005], +["1cz1",1.85,1.45586936985732], +["1kjz",1.85,2.24548051606876], +["1r4b",1.85,2.15694929537628], +["1bv4",1.85,2.137845535218], +["1bt8",1.85,2.16136174769856], +["1z8p",1.85,2.09560428807243], +["1jbw",1.85,2.73194281277842], +["1wzf",1.85,1.66799045266212], +["2cze",1.85,1.86689292896716], +["2cz5",1.85,2.33898623895199], +["2czf",1.85,2.61984841238986], +["1wnx",1.85,1.68744662257651], +["1p8f",1.85,2.41907171052229], +["1q0u",1.85,2.69265287320169], +["2cxk",1.85,1.90437226744078], +["1jpt",1.85,1.82255825862316], +["1eyq",1.85,2.28947853230576], +["1e4y",1.85,2.93721370429511], +["1e4v",1.85,2.26430906536484], +["1flr",1.85,3.54065788853455], +["1xwg",1.85,1.70689188004935], +["6gsu",1.85,2.10926669410363], +["6gsw",1.85,2.19135050742225], +["2ajx",1.85,2.27576261615193], +["2ak1",1.85,2.32051249397777], +["1al6",1.85,2.60370860937177], +["1jgv",1.85,2.02483435357823], +["1viz",1.85,2.53034601061024], +["1yej",1.85,2.45483108138524], +["1y6l",1.85,2.04671073784769], +["1bxt",1.85,2.63046955770327], +["1h5b",1.85,2.40696199227798], +["2ak3",1.85,1.96995622313499], +["1f3f",1.85,2.2376848416874], +["1cq3",1.85,2.65170112919178], +["1aqm",1.85,1.64507848362985], +["1znb",1.85,1.96545359824950], +["1a7t",1.85,2.05349591938851], +["1tz8",1.85,1.89692700838139], +["1e1m",1.85,1.95724929715529], +["1grb",1.85,2.56239206179203], +["1qvz",1.85,1.76467559553577], +["1us3",1.85,1.57513766835972], +["1xfg",1.85,2.33665330212084], +["1q8v",1.85,1.52011012247776], +["1qo2",1.85,1.98452118581238], +["1v82",1.85,2.48243317897411], +["2ewb",1.85,1.79370848768379], +["1ssq",1.85,2.47606552847535], +["1us2",1.85,1.54843303381284], +["1t96",1.85,2.07810393104118], +["1t99",1.85,2.17442760542476], +["1pcw",1.85,2.02899135906576], +["1e65",1.85,1.94847458337463], +["1jbm",1.85,2.57815249159248], +["1vkh",1.85,1.60042634690339], +["2ab2",1.85,1.77519694564966], +["1qsw",1.85,2.80346227128972], +["1fww",1.85,2.07581188581301], +["1vem",1.85,2.52145416670643], +["1m0z",1.85,2.24590986297453], +["1jmv",1.85,1.74799138596701], +["1ygg",1.85,1.61945056865438], +["1gx6",1.85,2.15034859734864], +["1t8t",1.85,1.58941624395942], +["1n4o",1.85,1.86995017215396], +["2cwz",1.85,1.58340576995037], +["1f4l",1.85,2.32481558649667], +["1nbz",1.85,2.66428787330962], +["2a86",1.85,1.83877284818173], +["8prk",1.85,1.54032482472398], +["1o1m",1.85,1.97975815039503], +["1g9v",1.85,1.96436661954930], +["1qxe",1.85,1.98724122272922], +["1t7c",1.85,1.43037545199617], +["1x23",1.85,2.55436650104160], +["2amd",1.85,2.36939906577995], +["2a42",1.85,1.86763004732056], +["1u79",1.85,2.64226977564544], +["1jps",1.85,2.29662275573475], +["1wnv",1.85,1.93197281941755], +["1lur",1.85,2.58428875407115], +["1yb5",1.85,1.79870205530627], +["1vqu",1.85,1.98727412544349], +["1w5o",1.85,1.73092717469867], +["1x0l",1.85,2.47904761466650], +["1u6e",1.85,1.96989132128012], +["1k9e",1.85,1.63591614199831], +["1z45",1.85,2.73412151512271], +["1z42",1.85,1.91124863451807], +["1nss",1.85,2.45131147557980], +["1ns7",1.85,2.5298677003518], +["1nsm",1.85,2.65354186061392], +["1ns4",1.85,2.47157308414746], +["1mmy",1.85,2.52764528332986], +["1ns0",1.85,2.51339906014032], +["1dhk",1.85,2.11769503834496], +["1b85",1.85,1.33626559997530], +["1uop",1.85,1.52708261118003], +["1muc",1.85,1.85959666063321], +["1jkm",1.85,2.34891753455566], +["1lax",1.85,1.84182358730823], +["1e2v",1.85,2.11039377459764], +["1ef8",1.85,2.47270595285087], +["1epf",1.85,2.68711834785588], +["2aag",1.85,2.39149429904895], +["1l9e",1.85,2.27233660620697], +["2a89",1.85,2.15873706114689], +["1m5b",1.85,1.83175182005712], +["1qt1",1.85,2.05374616135207], +["2gb0",1.85,2.15123441803558], +["1u7k",1.85,1.93756233934708], +["1ie7",1.85,2.15390500266659], +["1tok",1.85,2.46563590263353], +["1w9u",1.85,1.49561672256742], +["1xa3",1.85,1.55967559365498], +["1zzs",1.85,1.83205761372806], +["2fn0",1.85,1.99012221484529], +["1fgq",1.85,1.86525320583929], +["1lwd",1.85,2.09434709133479], +["1zp3",1.85,1.84998901427775], +["1ejb",1.85,1.8582734250753], +["1ejm",1.85,1.90172263071987], +["1qba",1.85,2.06545780176613], +["2al2",1.85,2.43988850576084], +["1zux",1.85,2.11094339846242], +["2cbu",1.85,1.64291347291825], +["1w7u",1.85,2.06598920203018], +["1w7t",1.85,2.13991455857179], +["1w7s",1.85,2.20813640750585], +["2cb5",1.85,1.94062782909853], +["1p31",1.85,1.88073391750927], +["2fe8",1.85,1.90270826300832], +["2c3q",1.85,1.55929866934851], +["1uiu",1.85,3.08430992381527], +["1gpf",1.85,1.96326748950141], +["1w1y",1.85,2.03021145189465], +["1w1v",1.85,2.05353128091429], +["1ogb",1.85,1.77777397858948], +["1as8",1.85,1.97596837859837], +["1cjd",1.85,2.72345461876188], +["1xmn",1.85,2.41822807048803], +["1dnu",1.85,1.8364843572869], +["2es4",1.85,2.06565140798024], +["1wve",1.85,1.81603669381436], +["1kgn",1.85,1.88264832405129], +["1m5s",1.85,2.44167968534737], +["1hjx",1.85,2.11387505983392], +["1pfz",1.85,1.84924956428079], +["1j2u",1.85,1.70590214834903], +["1l8a",1.85,2.90196256318313], +["1xk6",1.85,1.86134725678236], +["1ek4",1.85,1.9763862978744], +["1egm",1.85,2.87957178701105], +["2b3y",1.85,2.36644618570586], +["1woi",1.85,2.23560209161478], +["1hpu",1.85,1.85551145092384], +["1b25",1.85,1.8185223468539], +["1y67",1.85,1.35796197678425], +["1u9u",1.86,1.46865423392736], +["1g1j",1.86,1.77277674474785], +["1ij1",1.86,2.50589351744906], +["1ij0",1.86,2.65077090445047], +["1g02",1.86,1.53492218459492], +["1r75",1.86,2.47878049039155], +["2fo3",1.86,1.5559439797825], +["1ra4",1.86,2.26521564518429], +["1mh8",1.86,2.41831907189013], +["1yxh",1.86,2.41265677844388], +["1q6v",1.86,2.89121842806914], +["1tgm",1.86,2.64983625496579], +["1vwc",1.86,2.74623702357871], +["2c05",1.86,2.35322869560368], +["2exv",1.86,2.13042430026860], +["1cwc",1.86,2.19840063828932], +["1cwh",1.86,2.53693960453075], +["1cwf",1.86,2.37490435217497], +["1cwo",1.86,2.11890008407205], +["1czh",1.86,1.70801841487188], +["1ywm",1.86,1.50549414367658], +["2c0n",1.86,1.91585701396648], +["1rpi",1.86,2.89154323981126], +["1qjj",1.86,2.14185443844337], +["1dyr",1.86,2.78873554186793], +["1dzv",1.86,2.39543018523357], +["1d0b",1.86,1.84125073726280], +["1aec",1.86,1.58257301576871], +["1p8i",1.86,2.63806762754145], +["1f9m",1.86,2.50246461130581], +["1k1a",1.86,2.3659073623047], +["1fzz",1.86,2.47120423363525], +["1t14",1.86,1.59723215692697], +["1qd2",1.86,2.11908274445675], +["1op9",1.86,1.63326724256801], +["1j1i",1.86,2.48158686241773], +["1ghm",1.86,2.5448020454095], +["1g54",1.86,2.23004170925546], +["1g3z",1.86,2.04035192916926], +["1g48",1.86,2.15402499424422], +["1i9n",1.86,2.37975655894578], +["1i9o",1.86,2.35800870270328], +["1i3e",1.86,1.83232268340546], +["1hzg",1.86,1.86189074600549], +["1vho",1.86,2.11075739525003], +["1lij",1.86,3.26062909201336], +["1lp4",1.86,2.35585839197387], +["1lpu",1.86,2.45582594957179], +["2ays",1.86,2.98712934497710], +["1bg0",1.86,1.71504942026116], +["1qn4",1.86,2.21512986932603], +["1yu2",1.86,1.42169323780526], +["1lbk",1.86,2.07642386175373], +["1ruq",1.86,2.28284712381094], +["1yb0",1.86,1.89568464100674], +["1q6c",1.86,2.42592718135852], +["1y7w",1.86,2.10891602174856], +["1rq2",1.86,1.84094403212633], +["1q2w",1.86,2.14943888428064], +["1w5z",1.86,1.75284950427271], +["1r17",1.86,2.28778369495338], +["1hxq",1.86,2.48963355815915], +["1jb7",1.86,2.25777569749258], +["1r8q",1.86,2.30164015475602], +["1tzz",1.86,2.28845298891036], +["1i89",1.86,1.98518933687255], +["1ed4",1.86,2.38613252892805], +["1ger",1.86,1.87122673656528], +["1zx0",1.86,2.54369087427095], +["1z90",1.86,2.26339039872063], +["1xjj",1.86,2.30764118640541], +["1khd",1.86,2.21466866865246], +["2bz4",1.86,2.15256123348701], +["1zpd",1.86,1.52409953432943], +["1y4j",1.86,1.78076488916405], +["1rgk",1.87,1.82945165940996], +["1m5u",1.87,1.65028274665846], +["1y9t",1.87,2.06737432875503], +["1e6i",1.87,1.47387279716671], +["1vwd",1.87,2.54700854245375], +["2fzp",1.87,1.71508507742507], +["1rj1",1.87,1.93997599490227], +["1czt",1.87,2.52449684237502], +["1vi4",1.87,1.42291793835647], +["1cv5",1.87,2.15934759844892], +["1h8n",1.87,2.69689867198450], +["1x09",1.87,2.39629322778225], +["2fhq",1.87,2.38338702049528], +["1n12",1.87,1.63367789878007], +["1goo",1.87,1.90773920129442], +["2cmd",1.87,2.30246253074044], +["1pvv",1.87,3.16674322356897], +["1j39",1.87,2.21657663421252], +["1pt6",1.87,2.15872427286969], +["1tc6",1.87,2.00906075526132], +["1h1y",1.87,1.97558562022670], +["3gcb",1.87,1.76944059693851], +["2f35",1.87,2.31326208342975], +["1y9g",1.87,1.65423734435415], +["1k0y",1.87,1.87791701727778], +["1kd2",1.87,2.25396307451635], +["1onr",1.87,1.90713423841548], +["1ll9",1.87,2.09453349497836], +["1zxm",1.87,2.27544298565474], +["1f3d",1.87,1.84933525405896], +["1hww",1.87,2.00185916059831], +["1yu4",1.87,1.60009188711022], +["1hjs",1.87,2.10063374060889], +["1sjd",1.87,3.0415328616018], +["1m3z",1.87,2.56592581059376], +["1m4s",1.87,2.45073669138081], +["1g0r",1.87,2.09649059009232], +["1w2t",1.87,2.39875633629318], +["1k34",1.88,1.88345733251471], +["1mfl",1.88,1.78387611574443], +["1ey7",1.88,3.35946295316907], +["111m",1.88,2.65483139420511], +["1zmf",1.88,2.22538239030328], +["1dw6",1.88,2.06006548137683], +["1w3q",1.88,1.71824437273870], +["1b00",1.88,3.0810571706087], +["2cbc",1.88,1.96306129657369], +["1cah",1.88,1.93738261037114], +["1u7b",1.88,2.75794774691684], +["2b52",1.88,3.10113619697588], +["1wf3",1.88,2.15925219501470], +["2a5i",1.88,2.92889892239425], +["1xwq",1.88,1.40547424094428], +["1xjz",1.88,2.66391506847203], +["1rul",1.88,2.56194995736569], +["1wxo",1.88,1.97395330951571], +["2a2m",1.88,1.37381463799472], +["1keq",1.88,1.84087384974077], +["1y6z",1.88,2.99288716893963], +["1xg7",1.88,1.19778956996703], +["1oiz",1.88,2.16649932583232], +["1u1x",1.88,1.77628997814293], +["1shr",1.88,1.7796932409863], +["1dss",1.88,2.18730942153675], +["1jpr",1.88,2.37991231655841], +["1xx2",1.88,2.11787587292100], +["1dms",1.88,2.06280006782743], +["1usl",1.88,1.58974689217174], +["1s6v",1.88,2.28656969116202], +["3csu",1.88,2.76180710365755], +["1zcz",1.88,1.48618587239067], +["1f5z",1.88,1.91223116474772], +["2exh",1.88,2.24858647625412], +["1u36",1.89,1.59761000984080], +["1tq3",1.89,2.48323358147128], +["1mkv",1.89,2.50952013277525], +["1uy3",1.89,1.70669579211302], +["1d2w",1.89,2.2703926013198], +["1cup",1.89,2.38641890651263], +["1kw7",1.89,2.30291358350819], +["214l",1.89,3.08750788896183], +["1x7n",1.89,1.59275442150143], +["1u3i",1.89,1.84445880754872], +["1fy3",1.89,2.29369317748848], +["2ao6",1.89,1.72260288099088], +["1a4a",1.89,2.18473546609882], +["1bul",1.89,1.50711835993012], +["1qyx",1.89,1.72993938857107], +["2evj",1.89,1.70778025160295], +["1duw",1.89,2.51418495338445], +["1bva",1.89,2.62480548168813], +["1vkc",1.89,1.01343205750388], +["1ixi",1.89,2.39297872305635], +["1uzi",1.89,2.32227551182358], +["1n43",1.89,2.91191036266722], +["1svz",1.89,2.84949465038208], +["1hsl",1.89,3.29871744645122], +["1fy6",1.89,2.17263529795239], +["1m2t",1.89,2.57313125476098], +["1y9m",1.89,1.82160447186631], +["1y0o",1.89,2.60329909024025], +["1viy",1.89,1.78794893279339], +["2beu",1.89,2.13900931964159], +["1v3e",1.89,2.40397035683548], +["1zth",1.89,2.72878641757507], +["2c8m",1.89,2.39425658472169], +["1oih",1.89,1.83252209842488], +["1vhc",1.89,1.84146772315733], +["1zaj",1.89,2.27278947103892], +["1zal",1.89,2.46211632043587], +["1gyh",1.89,2.09554763960951], +["1gge",1.89,2.15605543713783], +["1gg9",1.89,2.20510893080418], +["2gge",1.89,2.27031039209879], +["1oz9",1.89,1.42052789955708], +["2aif",1.9,2.67105244909679], +["1dph",1.9,2.26562101469442], +["1cph",1.9,1.85056773484462], +["1b2e",1.9,1.37923816724595], +["1b2f",1.9,1.41954692572740], +["1eq7",1.9,1.87502111939761], +["1dfn",1.9,2.22769915460151], +["2cce",1.9,1.8918737147075], +["1ckb",1.9,2.00629997014165], +["1snb",1.9,3.83471929154537], +["2cc8",1.9,2.32712958129821], +["2msj",1.9,2.69227641776032], +["8ame",1.9,1.82330132930399], +["2msi",1.9,2.03922016615654], +["1wd0",1.9,3.12141693664902], +["1hh5",1.9,2.57145621595924], +["1cfw",1.9,1.50021437654766], +["1ail",1.9,1.66754386622343], +["1jml",1.9,2.17577705644961], +["1ntn",1.9,3.6069928506979], +["1pk4",1.9,2.85614153313788], +["1enm",1.9,2.02670242290952], +["1m59",1.9,1.57704836181085], +["1lr6",1.9,1.8768396257371], +["1ehb",1.9,2.15895063219861], +["1a1g",1.9,2.82832790353760], +["1jk1",1.9,2.01637357883647], +["1a1k",1.9,2.34986282914321], +["1rb1",1.9,3.17239412035023], +["1rb4",1.9,2.19416169127563], +["1c6r",1.9,2.32171829914709], +["1wuw",1.9,2.42981192519355], +["1cyi",1.9,2.77709660011213], +["1k9p",1.9,1.66820554312740], +["1yd4",1.9,1.01554225947257], +["1cyj",1.9,2.60883668214830], +["1gq4",1.9,1.79883758291025], +["1bxu",1.9,1.99740192633772], +["1fk7",1.9,1.96435895448266], +["1fk6",1.9,2.43605451150241], +["1mzl",1.9,2.56832952208223], +["1q8b",1.9,2.05515604651693], +["1who",1.9,2.09295424679759], +["1qzm",1.9,2.94344455907188], +["1u9p",1.9,2.12026656842469], +["1tyl",1.9,2.87678968496450], +["1tym",1.9,2.86785599397452], +["3mth",1.9,2.79178099511284], +["1t4f",1.9,2.08941583352932], +["1rb6",1.9,2.16360475131041], +["1rb5",1.9,2.12430689553362], +["3pcy",1.9,2.34370403916316], +["6pcy",1.9,2.68074779074572], +["1wq8",1.9,1.615901987099], +["1yv7",1.9,2.55812352862971], +["3car",1.9,2.30450402827458], +["1q4r",1.9,1.63526671279709], +["7rnt",1.9,1.76893060098167], +["1vck",1.9,1.82285522892894], +["1lra",1.9,1.87955345682799], +["1rls",1.9,2.14860535048865], +["1low",1.9,1.56224316400217], +["1rnt",1.9,2.60349215434215], +["1bu4",1.9,1.70309118612059], +["3gsp",1.9,1.48384049435124], +["1skz",1.9,1.91465888534030], +["1u3z",1.9,1.78893620987137], +["1rms",1.9,2.64686240935248], +["1hrc",1.9,2.79980494391113], +["1o4p",1.9,2.12283555655996], +["1wwc",1.9,2.70167261726376], +["1gk6",1.9,2.34798299309285], +["1crh",1.9,3.60135576482173], +["2fd2",1.9,2.57044161475212], +["1fd2",1.9,2.44613735997784], +["5fd1",1.9,2.49914279158958], +["1g6b",1.9,2.05959322618825], +["1fdd",1.9,2.40905179862805], +["1b2o",1.9,1.79698525309572], +["1io3",1.9,2.20279415266202], +["1irv",1.9,4.04339552663197], +["1b8r",1.9,2.3063701817004], +["1cif",1.9,3.09685809732553], +["1gmg",1.9,1.95533987416508], +["1raq",1.9,2.91591209389921], +["1chj",1.9,2.97718491531021], +["1csw",1.9,2.7421848100119], +["1csv",1.9,3.16673219686457], +["1csx",1.9,3.2569448922407], +["1ctz",1.9,3.93142304618979], +["2ycc",1.9,3.98614705286275], +["1ddv",1.9,2.09150589482178], +["1f4n",1.9,1.64133176689819], +["2apv",1.9,1.23830243839377], +["1rnb",1.9,3.28599041975336], +["1n9l",1.9,1.95111259648563], +["2hdd",1.9,2.67220618396077], +["1jd5",1.9,2.27515042311108], +["1sfp",1.9,2.20606067908435], +["1km8",1.9,2.24304139950361], +["1yea",1.9,3.54415239642868], +["2pii",1.9,2.61379842458453], +["5fiv",1.9,2.38940596909043], +["6fiv",1.9,2.61239620535866], +["1nxx",1.9,2.54347261287850], +["1lsl",1.9,3.28585186055417], +["1neu",1.9,2.64993472046871], +["1b11",1.9,3.03866055306281], +["1fnj",1.9,1.46558026783865], +["1ezj",1.9,2.99403583699659], +["4rhn",1.9,1.50510357932955], +["1xj3",1.9,1.84698571445465], +["1shf",1.9,1.8519348312349], +["1tmy",1.9,3.01662635861563], +["1bxy",1.9,2.12987021236931], +["1e0b",1.9,2.30288930315614], +["1u5f",1.9,1.56083567175148], +["1mai",1.9,2.37475875649192], +["1e21",1.9,2.93423059310727], +["2bgv",1.9,1.63336932261300], +["1dun",1.9,1.98784456062045], +["1c2a",1.9,1.69061477257764], +["1u6t",1.9,2.08310683310642], +["1opy",1.9,2.53334758867691], +["1oho",1.9,1.95162900814017], +["1dmm",1.9,2.87219188851098], +["1buo",1.9,2.10957546701253], +["1rno",1.9,2.49887035642014], +["1rar",1.9,2.56387037839063], +["1kvx",1.9,3.06050713305895], +["1c74",1.9,2.30971299101049], +["1ceh",1.9,2.78563633020587], +["1gh4",1.9,2.20831229572117], +["1kvy",1.9,2.83973953661288], +["1mks",1.9,3.19984175072301], +["1hfx",1.9,2.49609841300510], +["1ymv",1.9,1.45922584433204], +["1m8s",1.9,2.20880438034482], +["1m8r",1.9,2.33780325098620], +["1bfb",1.9,3.23487589842521], +["1rnx",1.9,2.62218900315987], +["1rnz",1.9,2.64989029237574], +["1rca",1.9,2.87827007495803], +["1c0b",1.9,4.47881449655431], +["1bas",1.9,1.95031994968268], +["1o4w",1.9,1.42318272133186], +["2pyr",1.9,2.22941720113185], +["2pyp",1.9,2.13733715880682], +["1s4r",1.9,2.54197445991669], +["1dfx",1.9,2.89952350713087], +["1s4s",1.9,2.67449965200120], +["1jug",1.9,2.33604554186318], +["1wtp",1.9,2.62978975231549], +["1di2",1.9,2.24199789030823], +["1e84",1.9,1.53049878995407], +["1eif",1.9,3.26150200407287], +["1e6l",1.9,1.9626906711682], +["1o7v",1.9,2.85043139480106], +["1d4z",1.9,1.48243072257354], +["1kh0",1.9,2.07604263437100], +["1doi",1.9,2.01683684866078], +["2fit",1.9,2.56439216142426], +["1hhl",1.9,1.9407310475396], +["1uat",1.9,2.33295524816228], +["1lsn",1.9,2.3906996130174], +["1lsy",1.9,1.91140483659338], +["1ir7",1.9,1.73961665462369], +["1hsx",1.9,2.08860313863188], +["1ved",1.9,1.46602076705407], +["1f0w",1.9,2.4360053814721], +["1jiy",1.9,1.74117000433176], +["1ir9",1.9,1.97026275937638], +["1jis",1.9,1.96259837293674], +["1jj1",1.9,2.20680547052021], +["1yl0",1.9,2.07937241051431], +["1jj0",1.9,1.66579093375061], +["1yky",1.9,1.68226637337691], +["1jit",1.9,2.03497994766661], +["1ykx",1.9,1.71020653690551], +["1z55",1.9,2.24146877242012], +["6lyt",1.9,2.61411044178502], +["1yl1",1.9,2.24194515307467], +["5lyt",1.9,3.82876045036366], +["2a1i",1.9,2.71161950297457], +["1i20",1.9,1.64836537796079], +["1e3o",1.9,2.49187055994916], +["2cy5",1.9,2.24685890825205], +["1utx",1.9,1.58059156236103], +["1b0n",1.9,1.99508824048653], +["1ab0",1.9,2.10611727742497], +["1lis",1.9,2.17889678274919], +["1elr",1.9,1.52006635604643], +["1vfq",1.9,2.12224841268005], +["1fwu",1.9,1.98218027167203], +["3nuc",1.9,2.81332786449449], +["1is4",1.9,2.23494473418330], +["1ez6",1.9,2.95090672349618], +["1nuc",1.9,2.68475506646560], +["1rsy",1.9,1.74226818410662], +["1dup",1.9,2.37186700936137], +["1kaa",1.9,2.48192590381340], +["1syg",1.9,2.61980080153306], +["1xgw",1.9,2.41403462271740], +["2g3a",1.9,1.41609560725981], +["1g15",1.9,2.39574725651359], +["1kdb",1.9,2.46113928057228], +["1kda",1.9,2.55589518404027], +["1nl1",1.9,2.88082992866928], +["1rss",1.9,2.26584690690728], +["4nul",1.9,1.90797722042171], +["1fln",1.9,1.87170782562266], +["1fla",1.9,2.39663053084767], +["4nll",1.9,2.09121389013288], +["1fvx",1.9,2.14138431835532], +["1j74",1.9,2.39659302756862], +["1r1m",1.9,2.77845294506695], +["1h7i",1.9,2.39075934123535], +["1u9l",1.9,2.28629898153870], +["1ebt",1.9,2.09933747415122], +["1moh",1.9,2.15937993550591], +["1vlk",1.9,3.21794372592377], +["2fy6",1.9,1.73386885588945], +["1lat",1.9,3.24175542982068], +["1o1x",1.9,1.39171272743432], +["2azw",1.9,1.8607400900793], +["1fip",1.9,2.42569050575366], +["1thq",1.9,2.09251716410667], +["1at0",1.9,2.14217245356207], +["1a5x",1.9,2.36495733293718], +["1a5v",1.9,2.60294708370159], +["1jmw",1.9,4.08766791813905], +["1vkb",1.9,1.17747195954736], +["1emu",1.9,2.04226703247382], +["5mba",1.9,2.51152316629413], +["1akq",1.9,2.06889797866901], +["2fx2",1.9,2.26092409434029], +["1aku",1.9,2.21113434378991], +["4fx2",1.9,2.75690085463492], +["3fx2",1.9,2.82734248014880], +["1puf",1.9,2.48068003681789], +["1buu",1.9,1.95055620857914], +["1ezk",1.9,1.87596880564356], +["1hlw",1.9,2.07106936064879], +["1a3z",1.9,2.35103505646468], +["2a6c",1.9,1.26424394144677], +["1rcy",1.9,2.0400514683145], +["1r4v",1.9,1.69911347650645], +["1npf",1.9,1.49040444664838], +["1v8u",1.9,2.08718887520319], +["2rdv",1.9,2.26560450699996], +["1hsy",1.9,2.63056187822235], +["1nz2",1.9,2.56475691752019], +["1ymb",1.9,3.48241870630219], +["1iop",1.9,1.84113089241083], +["2bwh",1.9,1.63495964834840], +["2myb",1.9,2.55285610295245], +["1mlu",1.9,3.03757717508536], +["1ch1",1.9,2.45365384602924], +["1j52",1.9,2.09904425112384], +["1ch7",1.9,2.55815330907009], +["1jdo",1.9,2.48218957323111], +["1mgn",1.9,2.63822630810024], +["2mgm",1.9,2.79246823982264], +["1mti",1.9,2.84035169688495], +["1moa",1.9,2.79788926962027], +["2mgc",1.9,2.57061829421682], +["1rdb",1.9,2.29775572262129], +["1kvb",1.9,2.9382147238397], +["1kvc",1.9,3.18798429258876], +["1lke",1.9,2.08225296664721], +["1kex",1.9,2.51444063033291], +["1alu",1.9,2.45502575667386], +["1u2p",1.9,1.68438055502118], +["1goa",1.9,3.32500418019328], +["1tcf",1.9,3.19415881855908], +["1ujc",1.9,2.32928878549788], +["1i06",1.9,2.83658620382961], +["1lnm",1.9,2.41531367733777], +["1gvc",1.9,2.51365680518125], +["966c",1.9,3.3855357814169], +["103l",1.9,2.86047761970995], +["1dg9",1.9,2.11107927339026], +["1t5i",1.9,3.10137476108133], +["1k12",1.9,2.62572857797795], +["1rvd",1.9,2.28204706405995], +["1gpr",1.9,2.35461055111054], +["1h6w",1.9,1.53474675082100], +["1yoa",1.9,2.17263063513977], +["1jom",1.9,2.30215550208474], +["1ra1",1.9,2.44681248917846], +["1rx9",1.9,2.54361301174308], +["1rc4",1.9,2.97398447107491], +["1k95",1.9,1.57425013366180], +["1nu2",1.9,1.82562193843693], +["1czs",1.9,2.26260312689460], +["1iw2",1.9,2.10490595640456], +["1wt4",1.9,2.62951140688778], +["192l",1.9,2.36043669038617], +["1l64",1.9,2.05268761391893], +["1cge",1.9,2.53727555612254], +["1l75",1.9,2.69291545267447], +["1c6l",1.9,1.96751642932899], +["248l",1.9,2.12550928597438], +["1l89",1.9,2.36512617104438], +["1l84",1.9,2.64424967454157], +["1c6h",1.9,1.52868098100088], +["1c6i",1.9,1.75926193695206], +["1c6k",1.9,2.04262582977198], +["1c6j",1.9,2.0819434936517], +["1g0g",1.9,2.01164073235298], +["1l67",1.9,1.98090666736718], +["235l",1.9,1.99418416211371], +["228l",1.9,2.25469894186028], +["222l",1.9,2.28038480348124], +["1qsq",1.9,2.22693925521408], +["236l",1.9,1.97113193400171], +["1c6g",1.9,2.23933576792754], +["1l79",1.9,2.17868744483744], +["1quo",1.9,2.30810609875502], +["1i6s",1.9,2.3183929940505], +["1c6e",1.9,2.33039043160105], +["1l70",1.9,2.54861013552944], +["1c6p",1.9,2.0216187579697], +["1c6q",1.9,1.94433944023398], +["1l76",1.9,2.08765028875520], +["1cv6",1.9,2.14575335660759], +["1l55",1.9,2.06373652941534], +["1g1v",1.9,2.11563012963462], +["233l",1.9,2.23366224936717], +["257l",1.9,2.33138816390614], +["1cv4",1.9,2.24581749872703], +["225l",1.9,2.26976373495181], +["1qug",1.9,2.33023761903302], +["234l",1.9,2.30536350679865], +["1l69",1.9,2.24484400343299], +["1lgx",1.9,2.28191182723424], +["223l",1.9,2.63039367159552], +["1b6i",1.9,2.54972375562468], +["1lgu",1.9,2.57795523592820], +["1dyf",1.9,2.27483115329742], +["1l57",1.9,2.09971806283429], +["1dya",1.9,2.26858537914991], +["195l",1.9,2.38403975345146], +["1qtb",1.9,2.76418950293666], +["1wc8",1.9,2.48230290143550], +["1vg1",1.9,1.74660758025884], +["148l",1.9,2.42618654707242], +["1u7o",1.9,1.85228009304940], +["2alf",1.9,2.48704919556831], +["1qnt",1.9,1.93805000785700], +["3cyh",1.9,1.84465531983451], +["249l",1.9,2.13799885247885], +["254l",1.9,2.05088066691542], +["1l28",1.9,2.27639752819211], +["1qt6",1.9,2.22193309289955], +["1pqj",1.9,2.24115374211661], +["1l54",1.9,2.38597136967422], +["1l00",1.9,2.58789891113702], +["1qt8",1.9,2.67168883575885], +["230l",1.9,2.51101435524866], +["1z2a",1.9,1.91315649621456], +["1l34",1.9,2.38569739374727], +["172l",1.9,2.98315741699754], +["1l51",1.9,2.31808005802057], +["1mmq",1.9,2.35800522886124], +["1wlj",1.9,1.49618571332281], +["2nll",1.9,3.40464040549771], +["2atv",1.9,1.35931572046922], +["1cwi",1.9,2.34501120669047], +["1jtm",1.9,2.42627773388059], +["1up1",1.9,2.06156286118265], +["1czk",1.9,1.30733757871154], +["1czr",1.9,1.35190301177319], +["1ihc",1.9,2.20607840996279], +["1fu0",1.9,1.92897401349591], +["1ua8",1.9,2.40041453537991], +["1baz",1.9,2.57368461634823], +["1qzn",1.9,1.61832314973167], +["1e8k",1.9,2.53366541100708], +["1xhd",1.9,1.49496255370863], +["2fha",1.9,1.61776938215261], +["1b2v",1.9,2.47398415184927], +["1erb",1.9,2.93444992968447], +["1yfu",1.9,1.96729050937377], +["1ci4",1.9,1.54349601157284], +["1hbp",1.9,2.96167668663798], +["1eto",1.9,2.36629832455103], +["1ehh",1.9,2.45229682794108], +["1iqb",1.9,2.27045637932511], +["1fen",1.9,2.95397984382285], +["1sqw",1.9,2.56626320026367], +["1fem",1.9,3.59838616293684], +["1krl",1.9,2.42563152950852], +["1h0j",1.9,2.36227144280663], +["2bin",1.9,1.71472770316169], +["2fv8",1.9,1.61484408858042], +["1y9q",1.9,1.74972079850370], +["1mr8",1.9,2.58654812724296], +["1cdw",1.9,2.53414036453894], +["1eyl",1.9,2.08008859754436], +["1q08",1.9,1.84420636233348], +["2cw9",1.9,2.02998087982796], +["2bio",1.9,1.98680430965897], +["1rz3",1.9,1.72852261634501], +["1u1p",1.9,1.60311204971228], +["1rec",1.9,2.42067057337382], +["1wj9",1.9,1.76739612425963], +["1lqy",1.9,2.15270944736854], +["1lmh",1.9,1.64951138794945], +["1iv9",1.9,2.2424176422696], +["1p71",1.9,2.50352337904619], +["1q1y",1.9,1.86838178483970], +["1ex7",1.9,2.53971508593511], +["1u72",1.9,3.2025285973448], +["1s3w",1.9,2.85955936034548], +["1mvs",1.9,3.21268488334268], +["1cuk",1.9,3.12776784371321], +["1jhs",1.9,1.90642732811829], +["1i8u",1.9,1.52655394179672], +["1i82",1.9,1.61614797825226], +["1eq6",1.9,1.88398847704584], +["1iap",1.9,1.74859803223729], +["3tss",1.9,2.37029494441478], +["1dvb",1.9,2.90236432723369], +["1b71",1.9,3.00106212776797], +["1vk2",1.9,1.45210409360332], +["3ukd",1.9,2.19188891505337], +["1et9",1.9,2.19499266337796], +["1qcs",1.9,1.93492233603152], +["5ukd",1.9,2.52090942181168], +["1yzf",1.9,1.86263434654038], +["1tef",1.9,1.51211041269393], +["2bpy",1.9,1.96282427126714], +["2bpv",1.9,2.11785634424619], +["1w5y",1.9,1.47214037380483], +["1izh",1.9,1.60203151807749], +["2aid",1.9,2.2650223245294], +["1met",1.9,2.65602130521869], +["1mer",1.9,2.44636786508828], +["1mes",1.9,2.46403512086105], +["1w5x",1.9,1.63908452099701], +["2a4f",1.9,1.64922517452441], +["1bwa",1.9,2.60287371316976], +["1meu",1.9,2.62411470380753], +["1hpv",1.9,2.57409175928087], +["4upj",1.9,2.72082507978599], +["1sgu",1.9,2.42801229803604], +["1ukz",1.9,2.03720795377637], +["1bud",1.9,2.38267144485712], +["2cut",1.9,2.37311234245141], +["1dto",1.9,2.33842967338600], +["1fgc",1.9,1.91131266880304], +["1p12",1.9,2.22945120883371], +["1fff",1.9,1.94986994676319], +["1e9f",1.9,2.34208917197454], +["1f39",1.9,2.02985914318226], +["1iaa",1.9,1.70456237247994], +["1yp1",1.9,2.33527622631306], +["1q7r",1.9,2.20633291829248], +["1mt7",1.9,1.91391894822260], +["1w3r",1.9,2.03260743365577], +["1u0s",1.9,2.64691037380953], +["1qav",1.9,1.80626614853652], +["1nzl",1.9,2.00158604880218], +["1is0",1.9,2.28247531132514], +["1za4",1.9,2.09965196832332], +["1kd8",1.9,1.61958603812136], +["1bhh",1.9,3.4614103622643], +["1gsm",1.9,2.91151116194480], +["2cd2",1.9,3.09310789995374], +["1ly3",1.9,3.23629218830243], +["1x9r",1.9,2.43171704411424], +["1uy6",1.9,1.80148296853832], +["1fw1",1.9,1.87304009621930], +["3gar",1.9,3.3022523063732], +["1nn1",1.9,1.96389108356231], +["1qnx",1.9,1.89259564978464], +["1uy7",1.9,2.28799074689859], +["1k3s",1.9,2.20909196416007], +["4eng",1.9,2.17509733755556], +["2fem",1.9,2.62803739042972], +["1e98",1.9,2.31277773078451], +["1xj6",1.9,2.20249923097446], +["1miz",1.9,2.53015433624938], +["1coj",1.9,1.97507703392052], +["1dzf",1.9,2.33439101989258], +["1ppp",1.9,3.60764895284203], +["1d7h",1.9,2.03623381725964], +["1d7i",1.9,2.20299906680602], +["1bl4",1.9,2.55906829992237], +["1ivj",1.9,2.16048959810147], +["1vgi",1.9,2.17953346589108], +["1p3j",1.9,2.6790993899674], +["1a75",1.9,3.05606325785633], +["3eng",1.9,1.89339316796462], +["1yet",1.9,2.46517611450586], +["1tk1",1.9,2.80027772938440], +["1wtl",1.9,3.24443535584103], +["2bl9",1.9,2.26309796301035], +["2f7d",1.9,2.43491019654520], +["2byh",1.9,1.63454763091267], +["1qy6",1.9,2.32627357557968], +["2gau",1.9,1.83707511010921], +["1vpp",1.9,2.20014368860033], +["1ms6",1.9,1.80377384380291], +["2ebo",1.9,2.69260510406941], +["1iit",1.9,1.84681802452366], +["1iiw",1.9,2.21597481391532], +["1nvi",1.9,2.30781846464180], +["1cd0",1.9,2.31163922191395], +["1mvc",1.9,1.7027632325464], +["1ois",1.9,2.69462560414321], +["1d2t",1.9,2.13482357707007], +["2f51",1.9,2.08625062409931], +["1kzd",1.9,1.88384165531021], +["1pw3",1.9,2.20198018442080], +["1rmm",1.9,2.25460334969416], +["1zol",1.9,1.27380526412382], +["1rdm",1.9,1.84099129225825], +["1mv9",1.9,2.32229958501862], +["1n5t",1.9,1.58305881275163], +["1twb",1.9,2.25712823586095], +["1q8r",1.9,2.4625854592093], +["1ema",1.9,2.64425135278858], +["1fmg",1.9,2.59657497940962], +["1f0u",1.9,1.23648170725426], +["1pph",1.9,1.79917427520426], +["1mtu",1.9,1.54533372145911], +["1mts",1.9,1.50431422389907], +["1g36",1.9,1.92507788539850], +["1tps",1.9,1.50820852874831], +["1mtv",1.9,1.71603754106095], +["1k1p",1.9,1.80108426281071], +["1mtw",1.9,1.81389261943592], +["1tnl",1.9,2.01311427559654], +["1nc6",1.9,1.77873317430741], +["1tni",1.9,2.17302762257737], +["2bza",1.9,1.89483570967222], +["1v2t",1.9,2.23217412426031], +["1v2j",1.9,2.40633821412038], +["1fgv",1.9,2.29110599296459], +["1q3f",1.9,1.94253466899364], +["1gl2",1.9,1.67126327713539], +["1zzz",1.9,2.65756224684496], +["1v9z",1.9,2.77376804804402], +["1slm",1.9,2.02594778553788], +["1wef",1.9,1.56947916678821], +["1x8i",1.9,1.77371476017421], +["1au8",1.9,2.40937395704279], +["1klt",1.9,2.96246966857229], +["1t31",1.9,2.43387900488673], +["1ek3",1.9,1.93778134156357], +["1dvy",1.9,1.34632158969240], +["1dvu",1.9,1.44665526536955], +["1dvz",1.9,1.48412185668879], +["1dvt",1.9,1.52931572336221], +["1yhi",1.9,0.998976463238855], +["1p62",1.9,1.60469857140922], +["1qhj",1.9,2.29281909036027], +["1x08",1.9,2.34989595173742], +["1v6d",1.9,2.74876370282338], +["1k1b",1.9,2.27941456227743], +["1qr0",1.9,3.50887741726347], +["1pyu",1.9,1.96075118945093], +["1e3f",1.9,1.42272329360634], +["1x06",1.9,2.27444974203839], +["1zd6",1.9,1.40235006944628], +["1pt1",1.9,2.26467889224051], +["1t95",1.9,2.00991302981494], +["1qx3",1.9,2.63697207707507], +["1tvd",1.9,2.31407223417140], +["1fx4",1.9,2.12612121215026], +["1ttr",1.9,2.59200103265219], +["1ziy",1.9,1.71437849904065], +["1vgc",1.9,2.09230842454415], +["1dut",1.9,2.7415650717724], +["1dex",1.9,1.98720288877633], +["2gch",1.9,3.03078547024114], +["4gch",1.9,3.61275767539830], +["3gch",1.9,3.75455779263499], +["1gcd",1.9,2.56969680335686], +["1s68",1.9,2.54477911757120], +["1j5p",1.9,2.46005336076696], +["1pyq",1.9,1.86423588264080], +["1sgq",1.9,2.24416530090821], +["1cso",1.9,2.30886740581481], +["1r6l",1.9,2.61206936146237], +["2d3k",1.9,2.07999753698811], +["2bsh",1.9,2.56341317438307], +["2ax7",1.9,1.91121356724445], +["1rk8",1.9,1.84061952801135], +["1q1c",1.9,2.51529248164228], +["1dq6",1.9,1.88232632225971], +["1jn2",1.9,2.38946070782426], +["1b9k",1.9,1.64323708266694], +["2lao",1.9,2.40927483894016], +["1vet",1.9,3.12466536132539], +["1s4k",1.9,2.08733947403613], +["1xkf",1.9,1.82577694084234], +["2ftz",1.9,1.88203236644044], +["1zm8",1.9,1.58851803714116], +["1ax0",1.9,1.73829583741516], +["2c2a",1.9,2.96399810553488], +["1se4",1.9,3.32199016466351], +["1e35",1.9,2.06694480962725], +["2foa",1.9,1.66463136258858], +["2fob",1.9,1.69049861599997], +["2fog",1.9,2.11129974401613], +["9est",1.9,2.5221519524414], +["1reg",1.9,2.9904387239548], +["1tlm",1.9,2.78138101253248], +["2ess",1.9,1.67237689208812], +["1sj0",1.9,2.98591413936477], +["1qix",1.9,1.88043978507066], +["1cqs",1.9,3.14889135634868], +["1q5t",1.9,3.03609674261342], +["2c99",1.9,1.70769847908242], +["1u73",1.9,2.22286512311070], +["1lsq",1.9,1.98218214314633], +["1c1y",1.9,1.89326683860723], +["2c98",1.9,1.90397546667548], +["1njr",1.9,2.23011840461015], +["2gfh",1.9,1.59101032631390], +["1fhw",1.9,2.36120354803477], +["1sqt",1.9,2.30906456338150], +["1yim",1.9,2.78401061848942], +["1ufk",1.9,2.38027508579018], +["1gr2",1.9,2.3408342851706], +["2d2f",1.9,1.86986375317549], +["1uc7",1.9,1.91230563836972], +["1xpt",1.9,2.06764669972879], +["1wbu",1.9,2.02425087243688], +["1lyx",1.9,2.34383217493993], +["1bsr",1.9,1.80860589966704], +["11bg",1.9,2.06151368457486], +["2ayr",1.9,2.19476308163405], +["3ert",1.9,2.51026541952079], +["1nsf",1.9,2.27602816823520], +["1nri",1.9,2.44860099417167], +["1rkg",1.9,1.909041995751], +["1ci3",1.9,2.24786719329444], +["1o0x",1.9,2.37323601979977], +["1vh7",1.9,1.66948711487477], +["1fa6",1.9,2.19783700229313], +["1fa7",1.9,2.58282012392173], +["1idr",1.9,2.07727126903974], +["1h9i",1.9,1.72257950016149], +["1wxh",1.9,1.97016867356651], +["1wxg",1.9,2.00668023201931], +["1slt",1.9,3.05021110481676], +["1rwl",1.9,2.54569498829717], +["2trh",1.9,2.98332328300715], +["1bzd",1.9,2.94049762615034], +["1gjb",1.9,2.99166345149718], +["1sb2",1.9,2.33317711736770], +["1k4w",1.9,2.5081805853156], +["1zpv",1.9,2.18103889507996], +["1ll2",1.9,2.29126624609860], +["1ukm",1.9,1.73644596446842], +["1txi",1.9,1.84430768633096], +["1hw6",1.9,2.01802781628265], +["1es4",1.9,2.44448378090295], +["1r3d",1.9,1.93831436361424], +["1ydb",1.9,2.18586608373348], +["1nap",1.9,3.55869256649019], +["2f5d",1.9,1.85444017655363], +["1rcm",1.9,1.78412160431522], +["1jj3",1.9,2.21261284857953], +["1dkk",1.9,2.48172384261415], +["1ljg",1.9,2.68762343478956], +["4lyt",1.9,3.55852995000092], +["3lyt",1.9,4.2694357897552], +["1wxe",1.9,2.14882445085333], +["1cnx",1.9,2.36351086302052], +["2ca2",1.9,2.67903863964152], +["1yas",1.9,2.46980008452716], +["1k9j",1.9,2.45376468813017], +["1cng",1.9,2.14582109918101], +["2h4n",1.9,1.86218009621841], +["1f2w",1.9,2.40055250111654], +["1lgd",1.9,2.55222819333685], +["1fw0",1.9,2.82861385887753], +["1ohb",1.9,1.94024781322959], +["2fyx",1.9,1.45441700496984], +["1ip7",1.9,2.15858772613427], +["1sei",1.9,2.84786794359042], +["1tg9",1.9,1.94721914397522], +["1el1",1.9,3.30344007516724], +["1caz",1.9,1.96406799410377], +["1bic",1.9,2.09298645926936], +["1rzd",1.9,1.91640792120128], +["1cak",1.9,2.19564867076864], +["1rza",1.9,1.94667647334842], +["1caj",1.9,2.00347979048463], +["1rze",1.9,2.06174956946154], +["1bcd",1.9,2.07911594001043], +["1rzc",1.9,2.03723564195926], +["1raz",1.9,2.62634424778982], +["1uge",1.9,2.25635594473203], +["1dja",1.9,2.2587905248635], +["1ayo",1.9,2.41598499398006], +["1mq4",1.9,2.59168362314726], +["1cao",1.9,2.21456704105618], +["1can",1.9,2.0830242721015], +["1ll3",1.9,2.61876513103917], +["1ymq",1.9,1.75723892304745], +["1cra",1.9,1.98283811349883], +["1w80",1.9,1.72530367064876], +["1j1r",1.9,1.97778367440513], +["1wt2",1.9,2.27132234375623], +["2cay",1.9,1.70958102220191], +["1efd",1.9,2.8440280519675], +["2mat",1.9,2.54075654154699], +["1co7",1.9,2.75874037486245], +["1hnk",1.9,2.42389061318656], +["1xpb",1.9,2.38128432296237], +["1nyy",1.9,1.82340888907143], +["1pzo",1.9,2.22118183419639], +["1erq",1.9,2.77127420892972], +["1uq4",1.9,1.89777834704141], +["1p4f",1.9,1.57245889819937], +["1f4e",1.9,1.81984621608535], +["1gnv",1.9,1.80971553899765], +["1edt",1.9,2.53111414436332], +["1w6o",1.9,2.17272221802180], +["1ldt",1.9,2.39629636960894], +["1c8z",1.9,3.21182517690225], +["3tgl",1.9,2.73445219164884], +["1pji",1.9,1.94463126169249], +["1nnj",1.9,2.01995580665520], +["1fsf",1.9,2.85622969560683], +["1htv",1.9,2.85306464846618], +["1usp",1.9,2.16424868500967], +["3gal",1.9,3.24556482633129], +["2byc",1.9,2.78683633344816], +["1bkz",1.9,2.83277304958429], +["2c3i",1.9,1.42346249479562], +["2fyb",1.9,1.99371104759587], +["2fya",1.9,2.21400722435962], +["2bhe",1.9,3.05057519416789], +["1pjj",1.9,1.98999087072515], +["2bzi",1.9,1.56562161452804], +["1r4x",1.9,1.64345167881273], +["1vjl",1.9,2.28450427120091], +["1b66",1.9,1.92232614296055], +["1scn",1.9,2.74182262707677], +["1sud",1.9,2.28570597931154], +["1s02",1.9,2.11885212887392], +["3btg",1.9,1.70776605237487], +["2gjs",1.9,2.05604382904572], +["2bzh",1.9,1.49612209209359], +["1y2g",1.9,2.55843479691739], +["3btd",1.9,1.82296281006767], +["3btq",1.9,1.73005678207648], +["3btt",1.9,1.48957210532028], +["1h9r",1.9,2.12121119946069], +["1k68",1.9,2.46730853476530], +["1evr",1.9,1.94718469787228], +["1e25",1.9,1.64812354287045], +["1z2v",1.9,1.77435982764354], +["1y9w",1.9,2.47321644196419], +["1tpa",1.9,2.32046885868133], +["2ptc",1.9,2.09554695262079], +["2tgp",1.9,2.61158459339759], +["3tpi",1.9,2.34893964844364], +["1uu7",1.9,2.52648631614410], +["1zrb",1.9,2.58183281584890], +["1ev6",1.9,1.66152814804383], +["1cg8",1.9,2.18880206672295], +["1ta6",1.9,2.62676722397272], +["1q44",1.9,2.01135843697831], +["1sr8",1.9,2.63731635745016], +["1f00",1.9,2.40434674392216], +["1y2v",1.9,1.74687512399586], +["1sb1",1.9,2.22307417076246], +["1g32",1.9,2.82196155344881], +["1t49",1.9,2.00649142009555], +["1i3c",1.9,1.71107683164086], +["1f0p",1.9,2.78549930770841], +["1h0v",1.9,2.39978009353231], +["1g0b",1.9,2.41552137848241], +["1a27",1.9,2.73376504573528], +["1nhk",1.9,1.82337716291534], +["1fle",1.9,3.28054650175511], +["1z7k",1.9,2.73803606493977], +["1p14",1.9,1.5126785083156], +["1ut7",1.9,1.92613095189571], +["1zwx",1.9,1.62448090250073], +["1fg4",1.9,2.94198589997883], +["2fbl",1.9,2.50439654676375], +["2bkr",1.9,1.52787518211113], +["1han",1.9,1.46876268617881], +["1knd",1.9,1.58302926067870], +["1knf",1.9,1.66279267920120], +["1jzm",1.9,1.93379236402687], +["1ls6",1.9,2.06781081200221], +["1g2l",1.9,2.45657242781312], +["3prn",1.9,2.09594496738724], +["1up5",1.9,2.44885892221417], +["2c6m",1.9,2.56967605160155], +["1vp3",1.9,2.43786746424820], +["1v1i",1.9,2.54954012571552], +["1lkf",1.9,2.39311058690847], +["3lkf",1.9,2.17901471005226], +["2c6k",1.9,2.3907360175054], +["1up2",1.9,1.21954021660672], +["1cp6",1.9,2.41544856024113], +["2anp",1.9,1.8354466414195], +["1cmp",1.9,2.06177890126575], +["4ccx",1.9,2.05997160952156], +["1f08",1.9,2.00712266608608], +["1ujk",1.9,1.91724546456280], +["1v93",1.9,1.54496156363525], +["1hck",1.9,2.83536681101923], +["1c1w",1.9,2.66657068472435], +["1c5o",1.9,2.80138161699069], +["1no9",1.9,2.55452396963999], +["1jci",1.9,1.9412447270336], +["1jk7",1.9,2.26206511564968], +["1w35",1.9,1.88834556202699], +["2man",1.9,1.83936079301494], +["1vgx",1.9,1.74579977616215], +["1in7",1.9,1.76324725476283], +["1bx0",1.9,1.83140983554591], +["1bx1",1.9,1.86511586354985], +["1in8",1.9,1.66271817871720], +["1d7o",1.9,2.14817112957454], +["1eno",1.9,2.49215834489872], +["1a48",1.9,2.39111568761147], +["1aax",1.9,1.91941867030845], +["1cpo",1.9,1.90151057165120], +["1f9f",1.9,2.42067298922715], +["1sxn",1.9,1.59697179143606], +["1sxa",1.9,1.58195378696028], +["1sxc",1.9,1.63716581582461], +["1u94",1.9,1.79204012417865], +["2c3s",1.9,2.58115293698705], +["1een",1.9,2.28592031190248], +["1phm",1.9,2.25518040466291], +["1ixk",1.9,2.16031124428848], +["1ugh",1.9,2.65804248139344], +["1i7b",1.9,2.04400461982062], +["1azv",1.9,2.49624106449323], +["1m6c",1.9,2.19191131967104], +["1myj",1.9,2.74748345142559], +["1myh",1.9,3.26323443405431], +["1ir3",1.9,1.67422894269741], +["2ap1",1.9,1.39742128919839], +["1abf",1.9,2.38398762803252], +["1hye",1.9,2.21566732948272], +["1zle",1.9,1.26268357322280], +["1qou",1.9,1.99598315398851], +["1v6h",1.9,1.89307468152283], +["1iow",1.9,2.83720898247634], +["1c1h",1.9,2.29789056871541], +["2ag6",1.9,2.31303190257262], +["1zh0",1.9,2.3326876607811], +["1qw0",1.9,1.88023985160469], +["2aps",1.9,2.17339614767859], +["1ak1",1.9,2.44171970754885], +["1zei",1.9,2.87697353668021], +["2gbp",1.9,2.54112978163526], +["1gcg",1.9,1.72550922834936], +["1bgp",1.9,1.39110487552564], +["2had",1.9,2.32367289603493], +["1ede",1.9,2.58598582497024], +["1d2a",1.9,2.68076419307118], +["1shk",1.9,2.17890316693344], +["1emd",1.9,2.61260160452568], +["2xyl",1.9,2.0535308659518], +["1fhd",1.9,1.99966211920489], +["1m3q",1.9,2.39361473939531], +["1wl7",1.9,2.29566525923665], +["2fsj",1.9,1.60786228009995], +["1xvw",1.9,1.96446540921349], +["1tm2",1.9,2.06249359151324], +["1t25",1.9,1.52531595886816], +["1ysd",1.9,1.86096465605762], +["1jkg",1.9,2.01288913351800], +["1hnh",1.9,2.54462829102504], +["1fjw",1.9,1.87610935077132], +["1kto",1.9,1.55586232797104], +["2fqy",1.9,2.14973593995907], +["1lna",1.9,2.28315373193775], +["1tmn",1.9,2.38767974266007], +["1dyi",1.9,2.73399486367193], +["1dhi",1.9,2.24179404993889], +["2drc",1.9,2.35281446517859], +["3drc",1.9,2.14960888622929], +["1dra",1.9,2.3309619792725], +["1dyh",1.9,2.74366955065927], +["2d0k",1.9,2.38331005014686], +["1u58",1.9,2.48452217725845], +["1wtc",1.9,2.17362067405845], +["1g5n",1.9,1.94653873525191], +["1a8a",1.9,2.64921460359689], +["1a8b",1.9,2.92233173279838], +["1bri",1.9,2.19317011171417], +["1ist",1.9,2.20648867036628], +["1fkm",1.9,2.31987801705706], +["1qui",1.9,2.23248491123999], +["1quj",1.9,2.24694732940033], +["1pbp",1.9,2.29567265369353], +["1c9y",1.9,2.14370707779132], +["1qth",1.9,4.16677039158083], +["1tlo",1.9,2.28275796678364], +["1ib2",1.9,2.09547266513073], +["1hgx",1.9,2.04727086270836], +["1zsx",1.9,1.53968569229014], +["1ize",1.9,1.40810020883023], +["1izd",1.9,1.69378076501381], +["1np6",1.9,2.39991084135467], +["1lf4",1.9,2.24814568749169], +["1pmz",1.9,1.97122321763074], +["2cy7",1.9,2.32037932633277], +["1q98",1.9,2.66468717126592], +["2c9w",1.9,1.78489054729171], +["1ygh",1.9,2.56675581719595], +["1b8p",1.9,2.06626718706838], +["2c7o",1.9,1.86531392552310], +["2c7r",1.9,2.03130799519727], +["1eyw",1.9,1.96929980596109], +["1oqg",1.9,2.02205444323586], +["1nv4",1.9,2.8373509806048], +["1nuz",1.9,2.77487155092372], +["1tfa",1.9,2.18954754446099], +["2fa8",1.9,2.09246038998451], +["2bi0",1.9,2.13876871899313], +["1epq",1.9,1.95684074671325], +["1ceo",1.9,2.02221623112580], +["1epp",1.9,1.96706224544161], +["1ent",1.9,1.93615111489497], +["1ae9",1.9,1.47574322058444], +["1nv1",1.9,2.8956172697397], +["1nv5",1.9,2.8956172697397], +["1t45",1.9,1.87617946980780], +["1lee",1.9,3.04512585949164], +["1dw1",1.9,2.00245536573466], +["1n67",1.9,2.19890099746963], +["1g1s",1.9,2.06497101497688], +["2ble",1.9,1.91477702436711], +["1nie",1.9,2.33390237823482], +["1nic",1.9,2.31397684767668], +["1b63",1.9,2.05103202782700], +["1pp1",1.9,1.58186695519453], +["1haw",1.9,1.60209343597157], +["1xf8",1.9,1.87861994695819], +["1p4n",1.9,1.78636598280855], +["1vq3",1.9,1.56379492380450], +["1et5",1.9,1.90228501031372], +["1hau",1.9,1.47319633586819], +["1gs8",1.9,1.55798753080401], +["1ck6",1.9,2.18892977210049], +["1ary",1.9,2.34733494872755], +["1arx",1.9,2.35243077369225], +["1arp",1.9,2.48772113302589], +["1tiq",1.9,2.50868504939874], +["1yvo",1.9,1.80724528194199], +["1kvr",1.9,2.01158286141203], +["1a9z",1.9,2.16995406462003], +["1nkx",1.9,2.80295964480089], +["1kvu",1.9,2.21025460680922], +["1lrj",1.9,2.68306964298374], +["1qzg",1.9,2.7934048684466], +["2g93",1.9,2.42189100766446], +["1m8z",1.9,2.3464444120898], +["1wgt",1.9,2.58081940828493], +["1w31",1.9,2.95927047079122], +["1fth",1.9,2.01138747014295], +["1g49",1.9,2.68561380297609], +["1gif",1.9,2.77187467941091], +["1nj4",1.9,2.47399112982961], +["1zav",1.9,2.63739004211097], +["1m66",1.9,1.91080095083480], +["4bcl",1.9,2.76455418834689], +["1alv",1.9,2.40762146649120], +["1ikg",1.9,1.52628963578958], +["1kq9",1.9,1.31234120130413], +["1v7b",1.9,2.24777726962331], +["1d0v",1.9,2.74596068226728], +["1d0s",1.9,2.89891802723653], +["1l5n",1.9,2.01228049121651], +["1l5f",1.9,1.93752433059377], +["1gcz",1.9,2.25724317370399], +["1ua6",1.9,2.15462464760014], +["1iaz",1.9,2.1984202635409], +["1xuu",1.9,2.26383905539404], +["1g7m",1.9,2.12608378376742], +["1xh6",1.9,2.20845313672936], +["1js2",1.9,2.37133541297135], +["1wlt",1.9,2.3652596287265], +["1je5",1.9,2.70771335744584], +["1f5m",1.9,2.47439944030638], +["1jg6",1.9,1.9662738482174], +["1me8",1.9,1.94442256089931], +["1iwm",1.9,2.51895352912382], +["1i5a",1.9,2.39102460744443], +["1zes",1.9,2.08697390534268], +["2adu",1.9,2.151120629709], +["1i5c",1.9,2.44314398106515], +["2bje",1.9,2.11041067612454], +["1k9y",1.9,2.08723281228601], +["1srr",1.9,3.52848976551493], +["1p52",1.9,1.91771261789970], +["1f2j",1.9,2.34382465431561], +["2mnr",1.9,1.64207543776411], +["1g01",1.9,2.08447788880450], +["1r3v",1.9,1.98299489987366], +["1g0c",1.9,2.22501185363106], +["1q8u",1.9,1.54288920270592], +["2cwq",1.9,2.03854132035215], +["1jdw",1.9,2.3835238418101], +["1p0d",1.9,2.36031124968168], +["1k30",1.9,1.66167141240763], +["1agq",1.9,2.52746182364197], +["1vlc",1.9,1.59853148698552], +["1gz1",1.9,2.18435288529407], +["1v2d",1.9,2.30823334690960], +["1c0i",1.9,2.70375831662559], +["1tg5",1.9,2.78889564584890], +["1h62",1.9,2.44369464936867], +["1g8i",1.9,2.18267528415223], +["1vhe",1.9,1.59644227142106], +["1xbw",1.9,2.85576957517269], +["1mor",1.9,2.29341275777653], +["1qn9",1.9,2.22945465626489], +["2dcz",1.9,1.22500794103684], +["1hsb",1.9,2.07556911050196], +["1ez3",1.9,2.15237509532084], +["1jvy",1.9,2.58775235041957], +["1r58",1.9,2.67891992036896], +["1u56",1.9,2.4983660931623], +["2bhg",1.9,2.31893285028706], +["1fqa",1.9,2.42589634646937], +["1fqb",1.9,2.34135079670135], +["1pl3",1.9,1.63660958349448], +["1d7b",1.9,1.64530316648062], +["1d7d",1.9,1.8541142235189], +["1xhk",1.9,2.25478125089023], +["1ca1",1.9,2.62310802666429], +["1nh2",1.9,1.55930501913937], +["1mdq",1.9,3.11514006598990], +["1l3j",1.9,1.88486892259311], +["1sq9",1.9,2.54288622467968], +["1qne",1.9,2.45963108809756], +["1acv",1.9,1.66078805728493], +["1q3e",1.9,2.10922350262433], +["1bhe",1.9,2.39863970751724], +["1fzj",1.9,1.87862331313403], +["1iak",1.9,2.20114760758716], +["1e4f",1.9,2.35205717593295], +["1d7c",1.9,1.85168246169872], +["1qqn",1.9,1.76693135992671], +["1ba0",1.9,2.14562455646127], +["1qqm",1.9,1.67639765013428], +["1qqo",1.9,1.62081207915216], +["1zx8",1.9,1.5360489556132], +["1t1z",1.9,2.21831645639727], +["1ydp",1.9,2.79462518742825], +["1wbx",1.9,2.03383313151716], +["1wwj",1.9,2.91417193939831], +["2bno",1.9,2.04958981320459], +["1dil",1.9,2.7044614483747], +["1n2a",1.9,2.49935346944795], +["2ngr",1.9,2.11598830298304], +["1fc9",1.9,3.14507065951513], +["1clk",1.9,2.39352481614087], +["8xia",1.9,1.85166529703611], +["9xia",1.9,1.7834825499762], +["1m4v",1.9,2.09625883997643], +["1ktb",1.9,2.03822042592031], +["2qwf",1.9,2.24166079689283], +["1uol",1.9,1.84813965989273], +["1u1t",1.9,1.91764703118276], +["1o91",1.9,2.09181158553867], +["1wc3",1.9,2.11566861628129], +["1hsh",1.9,2.91692123889758], +["1vsc",1.9,3.04766780102563], +["1avx",1.9,3.46601850668905], +["1pbe",1.9,3.00461920411847], +["1kk3",1.9,2.30419930561997], +["1ap6",1.9,2.46301770598404], +["1eqp",1.9,1.65085113871059], +["1u2w",1.9,2.39483222429928], +["2g3p",1.9,2.68914946627546], +["1et6",1.9,1.50751793054013], +["1toj",1.9,2.08902531368247], +["1toi",1.9,2.14621444979231], +["1svb",1.9,1.99153611840320], +["1tro",1.9,3.02010753884948], +["1qis",1.9,2.45671750490985], +["1qit",1.9,2.79654311654413], +["1y4i",1.9,2.58076731885893], +["2fre",1.9,1.8373932101302], +["1g0s",1.9,2.52693107190293], +["1ar4",1.9,2.36483054583819], +["1ys3",1.9,2.17360137444471], +["1mky",1.9,1.54351990208467], +["1r1s",1.9,2.96811982936911], +["6cp4",1.9,2.23091081197511], +["1cp4",1.9,2.31387970261513], +["6cpp",1.9,2.35620037123434], +["3cpp",1.9,2.47379908634933], +["1t9m",1.9,2.29497020098849], +["1i5z",1.9,2.17805159376686], +["1eu8",1.9,2.41472589270176], +["1j6p",1.9,1.94292458260122], +["2hoh",1.9,1.30917110137279], +["1bvi",1.9,1.45891749564893], +["1rkv",1.9,1.72555685461465], +["1qoz",1.9,1.52934194320898], +["1o0e",1.9,2.14208506770336], +["1lol",1.9,2.07478357874285], +["1lp6",1.9,1.82158115778024], +["1ws7",1.9,2.49248166649313], +["1iso",1.9,1.66664766666605], +["1ai2",1.9,2.75226125507217], +["1ai3",1.9,2.90952870862843], +["1nsw",1.9,2.61761853891714], +["3gss",1.9,2.36923533041348], +["6gss",1.9,2.38606603975944], +["2gss",1.9,2.32720481206443], +["21gs",1.9,2.40488100447355], +["22gs",1.9,2.52565601839882], +["18gs",1.9,2.57267655211893], +["16gs",1.9,2.65140800885295], +["19gs",1.9,2.79316711987426], +["1eyb",1.9,1.75129332059948], +["1vjd",1.9,2.38024379994425], +["17gs",1.9,2.31222110626398], +["1l7p",1.9,2.27765133434429], +["1glp",1.9,1.65380953140136], +["13gs",1.9,2.31920906406177], +["2bt0",1.9,2.03184337046654], +["2cdd",1.9,2.03184337046654], +["2pgt",1.9,2.53119473913567], +["1jdc",1.9,2.70194249940175], +["1jdd",1.9,2.85370246115128], +["2bz5",1.9,2.42171476938263], +["1nut",1.9,1.98715805919295], +["1nuq",1.9,2.08495294436084], +["1nuu",1.9,2.35834373346782], +["1nup",1.9,2.31018056478874], +["1esg",1.9,2.60856402935631], +["1s3k",1.9,2.33281331343943], +["5cts",1.9,2.98202505527984], +["4csc",1.9,3.1852448167149], +["3csc",1.9,3.32002064116996], +["1u0z",1.9,2.08573769805946], +["1bc2",1.9,2.29632716889633], +["1so3",1.9,1.53705642625791], +["1x8t",1.9,1.93504902944994], +["1mhw",1.9,2.19450887047359], +["1z4o",1.9,1.82398645638655], +["1eeh",1.9,2.04520654996502], +["2c1x",1.9,2.13006656382157], +["1k6d",1.9,2.12286497317533], +["1v5y",1.9,1.8638013516279], +["3gst",1.9,2.52066156836818], +["4gst",1.9,2.92946940272469], +["1kel",1.9,2.34341649001407], +["1jfq",1.9,2.93498809318035], +["1c1e",1.9,3.38508928273073], +["1dy4",1.9,1.33112374922917], +["7cel",1.9,1.40340730771992], +["5cel",1.9,1.47733023898542], +["6fab",1.9,3.23570435280378], +["2f1g",1.9,1.56352879215414], +["2c1z",1.9,1.96273879678452], +["1ce1",1.9,2.71198662098949], +["4enl",1.9,2.51572254374644], +["1m0s",1.9,2.03193854261623], +["1ml6",1.9,2.05593219587453], +["1zht",1.9,1.85311675256344], +["1zhz",1.9,2.03319522026569], +["1r8c",1.9,2.13673584361328], +["1swq",1.9,2.49933204635889], +["1b93",1.9,2.25239389843008], +["1wl9",1.9,1.15098353985370], +["1yei",1.9,2.54695612233745], +["1kn2",1.9,2.68503686811072], +["1kn4",1.9,2.64233680878232], +["1yec",1.9,2.84279895593157], +["1f3a",1.9,2.70763250161360], +["1koq",1.9,2.06558585826128], +["1dvf",1.9,3.02792625116935], +["2fb4",1.9,2.6665558784436], +["1kwz",1.9,2.01457909768737], +["1kww",1.9,1.97167753614029], +["1kdo",1.9,2.12889467917960], +["1okb",1.9,1.55481168524864], +["1kop",1.9,2.15782208968813], +["1rxd",1.9,2.65451611063797], +["2fim",1.9,2.24020044643071], +["3rp2",1.9,2.96954772006757], +["1yai",1.9,2.15136177454878], +["1loe",1.9,2.54622758111967], +["1zck",1.9,2.95811175541883], +["1bgv",1.9,2.67708429245775], +["1shm",1.9,1.94342526281384], +["2bqp",1.9,2.52853804741941], +["1v7p",1.9,1.78113797432916], +["1esf",1.9,2.75384519254502], +["2bpb",1.9,1.35893304266149], +["1les",1.9,2.42868305525538], +["1umw",1.9,2.85936060898687], +["1ovn",1.9,2.28853064918183], +["1zx9",1.9,2.15079576539610], +["2a56",1.9,1.85405780326940], +["1swd",1.9,3.07983947832069], +["2fkm",1.9,1.55801866910574], +["1pcm",1.9,1.94992828014285], +["2bg1",1.9,2.03215126917388], +["1jfl",1.9,1.67588780934445], +["1ua4",1.9,1.94457898011313], +["1fmi",1.9,2.57148514451107], +["1sfl",1.9,3.03579569583782], +["1mus",1.9,2.52450495650504], +["1sn5",1.9,2.17369881599663], +["1sn0",1.9,2.18589446321021], +["1k4q",1.9,2.54373281972195], +["1afb",1.9,1.67528657666168], +["1gfl",1.9,2.6231780248534], +["1zcj",1.9,2.66582486385174], +["1l2t",1.9,1.99157387422509], +["1nxj",1.9,1.66264468307561], +["1eo4",1.9,2.36772867058738], +["1blx",1.9,3.02213461803671], +["1s55",1.9,2.83034577372339], +["1qmy",1.9,2.15818759159480], +["1swr",1.9,2.71752216584886], +["1h5x",1.9,2.48844348834633], +["1suo",1.9,1.92306906918662], +["1xg2",1.9,1.56505317385505], +["1qvw",1.9,2.04746604727654], +["1n75",1.9,2.18181058020870], +["1t06",1.9,2.04562692738777], +["1w17",1.9,1.94981056235915], +["1vhy",1.9,2.44849216311013], +["2gep",1.9,2.09027378217948], +["1rqb",1.9,1.82402687895897], +["1kff",1.9,2.43424510797592], +["1w1r",1.9,1.48495548445101], +["1y5e",1.9,2.00585816789728], +["1wzc",1.9,2.47516173017693], +["1zfj",1.9,2.91953120231518], +["2a07",1.9,2.36821410754352], +["1y4c",1.9,1.98637914895717], +["1jsm",1.9,2.68864748056126], +["1zeb",1.9,2.29816302420089], +["1v83",1.9,2.46682853000307], +["1zef",1.9,2.44758022722955], +["1nmd",1.9,2.48208471249670], +["1bli",1.9,2.25352232423399], +["2d3n",1.9,1.74459282109235], +["1wpc",1.9,1.93942226306742], +["1wlk",1.9,2.24612569223843], +["1e3x",1.9,1.63155092475635], +["1lan",1.9,1.75614753632474], +["1pu5",1.9,2.49011372422076], +["1gyb",1.9,2.62018508818008], +["2fhx",1.9,2.07195591338566], +["1b97",1.9,2.43747357857848], +["1b94",1.9,2.57080364643789], +["1hx1",1.9,2.20539068986093], +["1qb5",1.9,2.45192400271906], +["1tpu",1.9,2.06381698344148], +["1tpv",1.9,2.07601117691268], +["1tpb",1.9,2.02501861472145], +["1tpw",1.9,2.52517868867152], +["1tpc",1.9,2.28950176726518], +["1v3i",1.9,2.35968861435527], +["1pg0",1.9,2.34479302485592], +["1y3q",1.9,2.09474720467201], +["1jxk",1.9,1.80522738933897], +["1byb",1.9,2.95678502785608], +["7tim",1.9,3.07482977251664], +["1ypi",1.9,3.44887720392400], +["1j9l",1.9,2.21041185804844], +["1j9j",1.9,2.26959467729168], +["1yag",1.9,1.87176117241015], +["1kbk",1.9,2.25442045261325], +["1ig3",1.9,2.20684910835179], +["1udr",1.9,1.61113814467017], +["1kbb",1.9,2.22116361267325], +["1u30",1.9,1.73154670564952], +["1xcx",1.9,2.20483473594112], +["2c5l",1.9,2.32308086214662], +["1m03",1.9,1.52233415999805], +["1gyc",1.9,2.11034646458131], +["1yuc",1.9,2.16309341600077], +["1esw",1.9,1.88458945596308], +["1o0y",1.9,2.12944831377615], +["1icj",1.9,2.65421241853755], +["1bs4",1.9,2.59492759578468], +["1bsz",1.9,2.68964633050285], +["1r8h",1.9,2.21540485616632], +["1nnw",1.9,1.31871753689036], +["1ufb",1.9,2.20049088778219], +["1the",1.9,2.75282067097984], +["1fws",1.9,2.04687826753206], +["2azu",1.9,1.60512266715729], +["4azu",1.9,1.61529447240874], +["5azu",1.9,1.91388706636532], +["1vlx",1.9,2.39149133974811], +["1r1c",1.9,3.09964183302893], +["1ejj",1.9,3.03955930833902], +["2cye",1.9,2.62053133025391], +["1m0d",1.9,2.01658740912691], +["1ih8",1.9,1.82887153678949], +["1pq4",1.9,2.8303228208436], +["1fwt",1.9,2.10663788691374], +["1nnp",1.9,2.33128616039093], +["1jcy",1.9,2.13571102494731], +["1xu1",1.9,1.74718283972538], +["1g3k",1.9,1.97033024885387], +["1jjw",1.9,2.06195311483579], +["1yqt",1.9,2.31738202661982], +["2f7w",1.9,2.19722010252665], +["2ae2",1.9,1.99743445836508], +["2apg",1.9,1.91862134680859], +["1b4h",1.9,1.78042843067416], +["1b5h",1.9,1.78579274980058], +["1b0h",1.9,1.97529621701067], +["1b2h",1.9,1.95097356331847], +["1ei5",1.9,2.30835361193136], +["1jfr",1.9,2.1307006725423], +["1qh3",1.9,1.79986154837409], +["1b5i",1.9,1.66243735678355], +["1jtp",1.9,1.77710153807933], +["1oen",1.9,2.44495986569384], +["1obw",1.9,2.43894551675266], +["2cy0",1.9,2.55997254841816], +["1mrz",1.9,2.25873948398058], +["1yt8",1.9,1.75481528391787], +["2f4p",1.9,1.50959940848972], +["1njk",1.9,2.76455219439917], +["1yix",1.9,2.77337346211300], +["1ee8",1.9,2.50806818594354], +["1r3j",1.9,2.01498549790568], +["1pbq",1.9,2.26572177769601], +["1aq2",1.9,2.59989255525626], +["2a0q",1.9,2.62277022355144], +["1sw1",1.9,1.83790205354903], +["1sw4",1.9,1.72079850131147], +["1x6l",1.9,1.9606543356435], +["1jdh",1.9,1.63713293960605], +["1ffq",1.9,1.53036480151352], +["1ehn",1.9,1.58419771157173], +["1clc",1.9,2.08594630615206], +["1ecl",1.9,2.73223848733306], +["1v0o",1.9,2.43637007748827], +["1d2m",1.9,2.97234099730931], +["1ndg",1.9,2.15186781079433], +["1ov8",1.9,1.66966937672983], +["1v8f",1.9,1.748403223928], +["3daa",1.9,2.1998824383476], +["9gac",1.9,2.50169860682206], +["1zq9",1.9,2.06482320268869], +["1xua",1.9,1.46497741720975], +["1mw8",1.9,2.71411021483642], +["1yuy",1.9,2.33133056591039], +["1rj9",1.9,2.77099623983462], +["2f99",1.9,2.10604319166596], +["1n2x",1.9,2.61909645729519], +["1buw",1.9,2.10234146935749], +["1ors",1.9,2.93773067576114], +["1e6a",1.9,1.67338010696421], +["1g08",1.9,2.64793468374644], +["1m6y",1.9,2.70854460358128], +["2aot",1.9,2.18349130477397], +["1xz7",1.9,1.91726553921493], +["1y7d",1.9,2.47631251695543], +["1y83",1.9,2.4667062488152], +["1xz2",1.9,1.75755068609621], +["1vwt",1.9,2.15777877728992], +["1hbb",1.9,2.29013172226277], +["1cls",1.9,2.40396770157295], +["1c8u",1.9,2.63594983238324], +["1o1j",1.9,1.93859610757091], +["1xq5",1.9,3.05168052798826], +["1mum",1.9,2.30203269662171], +["9gaf",1.9,2.14863786660336], +["1nk8",1.9,1.4856654578825], +["1nk7",1.9,1.64384890169635], +["1njw",1.9,1.59972188826871], +["1nk9",1.9,1.97123361256817], +["1xc9",1.9,2.38458434917846], +["3bdp",1.9,3.08077662744341], +["1cf3",1.9,1.37432025485573], +["1z83",1.9,1.19530226520746], +["1yxc",1.9,1.87237823569373], +["1wsh",1.9,2.43927338584627], +["1ff3",1.9,1.82985329892400], +["1n5u",1.9,2.79432791881989], +["1ws5",1.9,1.91395326191968], +["1ws4",1.9,2.01791924669981], +["1x1y",1.9,2.11081146081625], +["1p4k",1.9,2.46159178061412], +["1p4v",1.9,2.47482090046218], +["1eer",1.9,3.65805084153854], +["1jpn",1.9,2.27939735388381], +["1v1h",1.9,2.12096906557275], +["1qgj",1.9,1.86096822165489], +["1q7t",1.9,2.02514441304380], +["1st0",1.9,2.58970970987159], +["1vbk",1.9,1.57598964103718], +["1qhi",1.9,2.81338121255476], +["2ki5",1.9,2.80886034952320], +["1e2i",1.9,2.50315504795315], +["1t7n",1.9,1.95087616754866], +["1uj1",1.9,2.87667514624946], +["1e2h",1.9,2.32017233556083], +["1uf7",1.9,1.72949560123092], +["1wwk",1.9,2.41391432578951], +["1p0k",1.9,2.14933572457916], +["1xxu",1.9,2.41511668174754], +["2a8j",1.9,2.33911216790522], +["2adf",1.9,1.88430295523111], +["1uxg",1.9,2.08020232516587], +["1m9d",1.9,2.07624027102753], +["1i7n",1.9,2.26315501363799], +["1dlt",1.9,2.38800402843203], +["1qte",1.9,1.26884893745642], +["1jrb",1.9,1.95185304355974], +["2cx5",1.9,1.74186662791702], +["8gss",1.9,2.28030540769843], +["1sov",1.9,1.51760894189529], +["1y7p",1.9,2.65118212168296], +["1k7f",1.9,2.24557803408496], +["1g9g",1.9,1.32685571094877], +["1g9j",1.9,1.4347908112983], +["2f02",1.9,1.54682468089026], +["1lr5",1.9,2.04988559888981], +["1xed",1.9,2.91687030422929], +["1lrh",1.9,1.85836192386578], +["1k4m",1.9,2.39318144277975], +["1k8x",1.9,2.06122325977909], +["1beu",1.9,2.57098408457013], +["1o7w",1.9,2.1319169918418], +["1f1v",1.9,1.64297681993441], +["1gog",1.9,2.29228329417395], +["1a5a",1.9,2.70355149868210], +["1l6y",1.9,2.82889699983915], +["1ubs",1.9,2.94184532460382], +["1sow",1.9,1.54812446414602], +["1i8j",1.9,2.52136292194358], +["1u7p",1.9,1.86445623788421], +["1kfb",1.9,1.79543067279470], +["1xjb",1.9,2.25547248148073], +["2tys",1.9,2.26533848473603], +["1bmd",1.9,2.56896755833184], +["1ez2",1.9,2.41848834415742], +["1p6b",1.9,2.41860921268963], +["1djp",1.9,2.34598786386352], +["1qqp",1.9,2.68979596293383], +["1q0b",1.9,2.18226005148695], +["1kv9",1.9,2.3656653138639], +["1mqp",1.9,1.90785624967309], +["1jc1",1.9,3.65655912038522], +["1uod",1.9,2.02636363585360], +["1qw7",1.9,2.30399643189979], +["2bpq",1.9,1.94253151025246], +["1l7j",1.9,3.67726014387609], +["1b8d",1.9,2.06449951619590], +["1cb8",1.9,2.29843911658432], +["1oab",1.9,2.04651870040862], +["1zwy",1.9,2.11332875257754], +["1piz",1.9,2.21323019473415], +["1pj0",1.9,2.2949955652935], +["1bxk",1.9,2.87431897604103], +["1yfd",1.9,1.95127498257467], +["2f49",1.9,2.33141175524885], +["1xge",1.9,2.11805795320525], +["2gf0",1.9,1.64633750029795], +["1mn0",1.9,2.59683261551587], +["1z47",1.9,2.43501020637351], +["1i1q",1.9,2.59946056931241], +["1n1e",1.9,1.93134426686459], +["1stm",1.9,2.23398951258405], +["1t91",1.9,2.16478103161000], +["1moj",1.9,2.29421556202508], +["1f0k",1.9,2.29496704891022], +["1v16",1.9,1.91650107660179], +["1iv8",1.9,2.64701112146286], +["2bt2",1.9,1.62620645665363], +["1g4m",1.9,3.08954736942716], +["2coi",1.9,2.90014592454824], +["1pk9",1.9,2.42412790516852], +["1l0e",1.9,1.78117616506414], +["1fsw",1.9,1.81918302589265], +["2c1l",1.9,2.36410306493603], +["1xfc",1.9,2.32564891664328], +["1jyo",1.9,2.36236674979896], +["2nap",1.9,2.65365816017429], +["1kt8",1.9,3.15684363628368], +["1qjw",1.9,2.01596813857233], +["1vom",1.9,2.80548754730759], +["1wzn",1.9,1.87386674120732], +["1s63",1.9,1.96208588451887], +["2akr",1.9,2.23105700115163], +["1x13",1.9,1.91708525039024], +["1t64",1.9,2.24810704408358], +["1kta",1.9,3.12776436477130], +["1ijx",1.9,2.06610451868325], +["1gyg",1.9,2.40823449521504], +["1z9o",1.9,2.31782612730155], +["1lvk",1.9,3.2782863871816], +["1ez9",1.9,2.32763909234443], +["1o61",1.9,1.76829186534751], +["1m05",1.9,2.44937814401656], +["1tzy",1.9,2.38898397308911], +["1g29",1.9,2.09665459511429], +["1xiw",1.9,2.15756426240525], +["1vgy",1.9,2.06692339457064], +["1pnk",1.9,2.40446085697016], +["1qzr",1.9,1.91890707589150], +["1w0o",1.9,2.20942381291872], +["1rwc",1.9,1.8233130152748], +["2sfp",1.9,2.43332089429638], +["1y8z",1.9,2.37857513168423], +["1gmy",1.9,1.84012216749578], +["1o4s",1.9,1.97737877978592], +["2ff4",1.9,1.78238331350237], +["1sft",1.9,2.35865426576662], +["1vfs",1.9,2.93719097387244], +["1ejw",1.9,2.50263092720532], +["1ysl",1.9,2.18896448027899], +["1ef1",1.9,2.34331347621447], +["1rjy",1.9,2.28524860833758], +["1fv1",1.9,2.61048598163223], +["1u0v",1.9,1.98726473339961], +["1el8",1.9,2.20802347560599], +["1el7",1.9,2.08085638813632], +["1l9c",1.9,2.24869169770818], +["4dmr",1.9,1.59927546657985], +["1my1",1.9,2.37468982172265], +["1my0",1.9,2.32821161827548], +["1mxz",1.9,2.35711610879007], +["1my4",1.9,2.18175017552626], +["1mxw",1.9,2.01047194503298], +["1ftj",1.9,2.26009187705694], +["1ued",1.9,2.01485524143245], +["1chw",1.9,2.43227857040359], +["1a4q",1.9,2.32313264309894], +["1ta9",1.9,1.70538766716585], +["2fd6",1.9,2.98857376798082], +["1n3i",1.9,1.91257700035667], +["1z7g",1.9,2.30312905251105], +["1fng",1.9,2.20655998656353], +["1fne",1.9,2.27567141296564], +["1yro",1.9,2.38289597288295], +["2a3b",1.9,1.54975225650074], +["1fkn",1.9,2.39156473989608], +["1v40",1.9,2.31936870596874], +["1q0q",1.9,1.83104258990032], +["1jxz",1.9,2.496141313397], +["1xa4",1.9,1.71592898583389], +["1chm",1.9,2.78933244146549], +["7aat",1.9,2.32511146345124], +["1z62",1.9,2.60985005720807], +["1dz6",1.9,2.15500493137467], +["1dz8",1.9,2.11344996827222], +["1dz9",1.9,2.26584357901234], +["1t86",1.9,1.89542442519565], +["2a1n",1.9,2.16587026589102], +["1t88",1.9,2.13815751682335], +["1zzq",1.9,2.17123477181731], +["1p6i",1.9,2.34513715108357], +["1zzu",1.9,1.84565646595934], +["1fgm",1.9,1.78263008066186], +["1ww2",1.9,2.65109541476987], +["2agd",1.9,1.65021498009969], +["1t3c",1.9,2.93275475954845], +["2cst",1.9,2.88246875826699], +["1a88",1.9,1.84934405374356], +["1los",1.9,2.24717751525702], +["2bnr",1.9,2.36788682953108], +["1ocm",1.9,2.24258930965558], +["1gpb",1.9,3.87248361497714], +["1obj",1.9,2.28983110231947], +["1kd0",1.9,2.20023521863775], +["1usq",1.9,2.29198233489887], +["1h4h",1.9,2.12586342125381], +["1x1o",1.9,2.21103746584016], +["1nw2",1.9,2.10417400354993], +["5nse",1.9,2.40806508837039], +["1nse",1.9,2.76835952097624], +["1dmk",1.9,2.6120990551218], +["1td1",1.9,1.92849947302632], +["2fef",1.9,1.64498304333075], +["1y60",1.9,2.03701931681178], +["1dlg",1.9,2.0411173676329], +["1qco",1.9,1.66047958804212], +["1yiy",1.9,3.66628157558143], +["1qcn",1.9,2.02320673812591], +["1xyf",1.9,1.85841363338145], +["1xxm",1.9,1.85919598680773], +["1dv1",1.9,2.51895911160799], +["1lu9",1.9,1.57524679142208], +["1c7t",1.9,2.54890446235537], +["1kqd",1.9,1.69380805490075], +["1qa7",1.9,3.54122496324263], +["1ggx",1.9,2.16194272480489], +["1zgp",1.9,1.73559752033114], +["1qu1",1.9,2.64937473102525], +["1xw6",1.9,2.36406868012131], +["12e9",1.9,2.59813403823097], +["1qk4",1.9,2.06689500633101], +["1ebh",1.9,2.45105626956318], +["1b8a",1.9,1.94273557893935], +["1yqo",1.9,2.09146596031444], +["1cq1",1.9,2.41190476391126], +["1rhh",1.9,2.53607326446945], +["1zhq",1.9,1.52358559037976], +["1b8j",1.9,2.13219884303375], +["1mzn",1.9,1.89824900495589], +["1cza",1.9,1.91103762658268], +["1jmx",1.9,2.85173726923732], +["1wlv",1.9,1.88375283893341], +["1sox",1.9,2.27368079547247], +["1wzo",1.9,1.74699609128642], +["1zpg",1.9,2.21596213541489], +["1n2m",1.9,2.09060827624717], +["1nxd",1.9,2.17153641197411], +["1unn",1.9,2.84848135860293], +["1obb",1.9,2.21532067621182], +["1k57",1.9,2.09567651482117], +["1oqs",1.9,2.61037533536250], +["2ao9",1.9,2.17673474410639], +["1np7",1.9,2.55920870995070], +["1jv1",1.9,2.20663286260821], +["1hn0",1.9,2.40918157751278], +["1tg7",1.9,1.81757025016113], +["1v08",1.9,2.10619368685064], +["1h49",1.9,2.52275928363487], +["1rzp",1.9,1.90166311442584], +["2bk4",1.9,1.69766629332443], +["1ur8",1.9,2.14035620481609], +["1w1t",1.9,1.95617401566839], +["1u6z",1.9,1.83918213101142], +["1f0x",1.9,2.88453140399382], +["1px0",1.9,2.78236990104763], +["1npj",1.9,2.2654206511484], +["1j9s",1.9,1.90614097642892], +["1amu",1.9,1.90175657662320], +["2fuw",1.9,2.53109816896027], +["1tqt",1.9,1.86716339526234], +["1loj",1.9,2.90426863831908], +["1qg6",1.9,2.06327450265968], +["2bja",1.9,1.93376227338513], +["1xb9",1.9,2.62094266349713], +["2b4y",1.9,1.96727658449333], +["2aka",1.9,2.4322447949115], +["1rlm",1.9,2.31495982710987], +["2esl",1.9,2.39256623486926], +["1q8j",1.9,2.65020548973662], +["2b6e",1.9,1.97386756394449], +["1qsj",1.9,3.25500695814844], +["1aoz",1.9,2.25924521425127], +["2g5c",1.9,2.48573899078808], +["1g98",1.9,2.67224283264503], +["1koj",1.9,2.84110408819932], +["1otj",1.9,2.54087455638855], +["1yxm",1.9,2.31438692140317], +["1lsh",1.9,3.11420305332558], +["1d5l",1.9,1.75894992533316], +["1dnw",1.9,1.80201504760644], +["1d7w",1.9,2.18532932690531], +["1xg3",1.9,2.23116254351596], +["1hvy",1.9,2.34207425763637], +["1h5t",1.9,2.43638889705323], +["1h5r",1.9,2.51288774445458], +["1ava",1.9,2.68157461578189], +["1wws",1.9,2.06955122675619], +["1j0h",1.9,1.94287943977192], +["1f28",1.9,2.89544782130734], +["1h74",1.9,2.89096802358371], +["1ndf",1.9,2.27371388155330], +["1oni",1.9,2.21967770831545], +["1wa3",1.9,2.28067890118969], +["1m9y",1.9,2.49257071278431], +["1tf4",1.9,1.99751282600905], +["1kfg",1.9,1.97903532418859], +["1i9c",1.9,1.85667886019071], +["1xje",1.9,2.18341208442232], +["1ivu",1.9,2.20599861863967], +["2dfd",1.9,1.54552368039847], +["1g72",1.9,2.08775088368450], +["1t3t",1.9,2.20211251869438], +["1epw",1.9,1.93453743954682], +["1s0e",1.9,2.23860357959509], +["1h8v",1.9,2.10488302080679], +["1hg0",1.9,2.10805898874028], +["1pzh",1.9,1.56590518991496], +["1j4a",1.9,2.6275889261296], +["1qgd",1.9,1.45165682702401], +["2chs",1.9,2.17862328008337], +["1vjj",1.9,2.23438233517912], +["1li1",1.9,2.03413143912574], +["1t5o",1.9,2.59956747080382], +["1h1m",1.9,1.92628316634072], +["1lw4",1.9,1.8857478152618], +["1umd",1.9,1.93388949434238], +["1odk",1.9,1.56103504267830], +["1uks",1.9,2.21492447542886], +["1d7f",1.9,2.43790863621917], +["1h83",1.9,2.15338891652217], +["1b5q",1.9,2.07502158232802], +["1b37",1.9,2.05228161300968], +["1h82",1.9,2.41485504953412], +["1gqk",1.9,1.79605219417598], +["1gqj",1.9,1.89581747153071], +["1qdb",1.9,1.83724288711858], +["1pl8",1.9,2.01496824466092], +["1vps",1.9,1.69238739622861], +["2b2o",1.9,1.21020462458189], +["2b2r",1.9,1.13561189176592], +["1x7u",1.9,1.95223878389274], +["2ash",1.9,1.80082294405353], +["1l7e",1.9,2.84180727395562], +["1fba",1.9,2.28608333251462], +["1ado",1.9,2.37345510789400], +["1pfq",1.9,3.24027987183399], +["1s5e",1.9,2.01572489173120], +["1c9s",1.9,1.99524465314441], +["1uhg",1.9,2.54836626366101], +["1utf",1.9,2.00989197796695], +["1utv",1.9,2.03443857984441], +["1r0d",1.9,2.0634299724468], +["1e61",1.9,1.57372794645738], +["1u1i",1.9,3.94023340728811], +["1xn2",1.9,2.27379551958340], +["2buh",1.9,2.38672403725094], +["1sff",1.9,2.10775302332885], +["1rf6",1.9,3.00696946952219], +["1ec7",1.9,2.65760561709007], +["1zgq",1.9,1.53471713231818], +["1vkm",1.9,1.61687034191081], +["1ec8",1.9,2.48829793878026], +["1uxm",1.9,2.86112380317126], +["1xf1",1.9,3.16341092533916], +["1z10",1.9,2.41107438577088], +["1h64",1.9,2.3970440943397], +["1q16",1.9,2.23703113952682], +["1h1l",1.9,1.98960148827513], +["1uvj",1.9,2.53107747617987], +["1gu9",1.9,3.05079599264065], +["1gk2",1.9,2.52174122985049], +["2ahu",1.9,1.90142570030142], +["1zem",1.9,2.44944750467435], +["1yi7",1.9,2.00045618214384], +["1jiq",1.9,2.03268264971921], +["1fzw",1.9,2.36714575057261], +["1pkx",1.9,2.16272795898289], +["1mpx",1.9,1.47171877367471], +["1hbu",1.9,1.92987562051115], +["1kek",1.9,2.81476652081476], +["1ojx",1.9,1.64502929207396], +["1ods",1.9,2.10141479087625], +["1ynf",1.9,2.22022469371960], +["1uyp",1.9,2.84561554094913], +["1yg6",1.9,2.61951440720500], +["1hfb",1.9,2.86898373424758], +["1oao",1.9,2.41381204231286], +["1qws",1.9,2.29174256037718], +["1szo",1.9,1.54864809389719], +["1c7n",1.9,2.22450553160859], +["1v55",1.9,2.36041099620723], +["1o02",1.9,1.61557723802477], +["1zo8",1.9,2.61305314117653], +["1h7w",1.9,2.17271364428872], +["1yar",1.9,1.99912621827494], +["1yq2",1.9,1.83035819484880], +["1ryp",1.9,2.63188792996812], +["1u3y",1.9,1.73169430262111], +["1u3j",1.9,1.82954387953902], +["1yyh",1.9,1.45973199999864], +["1z40",1.9,2.08924800842461], +["1so6",1.9,1.46594708173683], +["1nl7",1.9,2.61542809091275], +["6paz",1.91,2.82711097941416], +["1mjs",1.91,2.30458928616504], +["1qb0",1.91,1.65857932778646], +["1ko3",1.91,2.1141151661262], +["1z0m",1.91,1.93645919465726], +["1a4b",1.91,2.23799670229743], +["1vk4",1.91,1.36393755405181], +["2f4j",1.91,2.45480013811548], +["1qvj",1.91,2.29938016166402], +["1r7s",1.91,2.01446961433363], +["1lt1",1.91,2.26184546572755], +["1vbl",1.91,2.40380304989946], +["1y57",1.91,1.38884961179771], +["1uzn",1.91,2.09981841503689], +["1u09",1.91,1.88544693159238], +["1cns",1.91,2.45225265792286], +["1yh3",1.91,3.16212731987136], +["2gf6",1.91,2.28911802021935], +["1jpa",1.91,1.87636056396425], +["1pfu",1.91,1.90301029055558], +["1sfq",1.91,2.32231381061028], +["1jqe",1.91,2.21321498549639], +["1y4g",1.91,2.05826658658992], +["1rq3",1.91,2.01776097496801], +["1xxt",1.91,2.38511032528915], +["1q1r",1.91,2.26342785849821], +["1lk3",1.91,2.20605263958212], +["1r0k",1.91,1.87178685070782], +["1z6o",1.91,1.54179862232518], +["1lr0",1.91,1.94122702010304], +["1pgb",1.92,2.42903627243166], +["1uo3",1.92,2.11587135077041], +["1nxs",1.92,2.68363792317374], +["1o7z",1.92,2.77243532778908], +["1nxw",1.92,2.45773189059856], +["1w5k",1.92,1.62381605868183], +["1vwf",1.92,2.46498298812986], +["1iko",1.92,2.35891571295747], +["1fua",1.92,2.33511517074071], +["1dzz",1.92,2.32154640434370], +["1ak2",1.92,2.161268012577], +["1xuj",1.92,2.16303376356457], +["1v2p",1.92,1.86591915602129], +["1u02",1.92,1.69244233890265], +["1nwo",1.92,2.21967439470271], +["1i9p",1.92,2.43557557155280], +["1pzt",1.92,2.16606623644435], +["1kqz",1.92,1.83523658652627], +["1kqy",1.92,1.88361525640060], +["1kr0",1.92,1.92506257962792], +["1fjs",1.92,2.52206508986214], +["1urn",1.92,2.01644907222134], +["1ppb",1.92,2.89548819380547], +["2bsa",1.92,2.01813793986950], +["1gom",1.92,1.63262785632403], +["1bvw",1.92,1.73526010095457], +["1i14",1.92,1.91562322910126], +["1jzo",1.92,1.81923860533873], +["1f6t",1.92,2.98620072417538], +["1z0k",1.92,1.72516003668246], +["1a4u",1.92,2.53791642599369], +["2bib",1.92,2.27110175247309], +["1xm6",1.92,1.80734723624384], +["1gwi",1.92,1.8928686347286], +["1xl0",1.92,2.37671830388241], +["2akm",1.92,2.71938331901892], +["2bvf",1.92,2.18307789090380], +["1k7h",1.92,2.22458584084436], +["1vr6",1.92,1.73748738304147], +["1pqu",1.92,2.35210227371984], +["1qfl",1.92,2.89374813642451], +["2c1d",1.92,2.16418518165420], +["1ggj",1.92,2.37449784404806], +["1f9p",1.93,2.69592287716677], +["1bc8",1.93,3.06459283705274], +["1oap",1.93,2.44466682939366], +["3lyo",1.93,2.37744575383929], +["2lyo",1.93,2.234804047812], +["1lyo",1.93,2.25016755594047], +["1w15",1.93,2.44944129419438], +["1rn8",1.93,2.14545856109529], +["1yvd",1.93,1.75716866870370], +["1b1c",1.93,1.97446915407513], +["1kwa",1.93,2.47277677533001], +["2f8p",1.93,2.13208898469183], +["1p11",1.93,2.13220073484241], +["1nd1",1.93,2.75036849829756], +["1tio",1.93,1.94870499194343], +["2tio",1.93,1.92365460551827], +["1jw6",1.93,2.37114951105292], +["1nli",1.93,2.30478359813414], +["2dcc",1.93,2.68544747457697], +["1i9l",1.93,1.98631634981564], +["1if4",1.93,2.0911964874445], +["1i8z",1.93,2.16763322854827], +["2c43",1.93,2.15748020993522], +["2cz4",1.93,2.39093922536683], +["1y08",1.93,2.09730513461926], +["1h2s",1.93,1.63511572653434], +["1k22",1.93,1.91617126941250], +["2prn",1.93,2.27124013029947], +["1jsz",1.93,2.48232234584305], +["1dj5",1.93,2.23842702973054], +["1dj1",1.93,2.36649192996243], +["1dzm",1.93,2.78111907618327], +["1qh0",1.93,2.13844038052815], +["1zdn",1.93,2.33684352831137], +["1cyq",1.93,2.21321876202426], +["1q54",1.93,2.46788000403616], +["1q4w",1.93,2.30379552285448], +["1qn5",1.93,2.21911848455781], +["1q5d",1.93,2.44329232107122], +["1kl1",1.93,2.1181381852084], +["1kkj",1.93,2.26614025211111], +["1kkp",1.93,2.01838903464611], +["1ku1",1.93,2.07638475551602], +["1pu7",1.93,2.18418463445648], +["1yzx",1.93,1.73118287002117], +["1e3z",1.93,1.71955016490066], +["1tt1",1.93,2.13107024074643], +["2afq",1.93,1.98550615632523], +["1cp2",1.93,2.92842007236595], +["1pfy",1.93,1.90910655288653], +["1wc1",1.93,2.10369882529411], +["1klu",1.93,2.67868925470219], +["1f4t",1.93,2.72633130012826], +["1tc5",1.93,2.00877344971144], +["2vpf",1.93,2.42931627416645], +["1xkx",1.93,2.49969388661672], +["1d1v",1.93,2.305533506532], +["1foi",1.93,2.31876796011000], +["1bd3",1.93,3.40049987000561], +["1m9n",1.93,2.17519691937320], +["1ekj",1.93,2.54276120706187], +["1dm5",1.93,2.64158831195972], +["1l6w",1.93,1.65041625367239], +["2c3y",1.93,2.72594554454025], +["1w8r",1.93,1.83746547217432], +["1azq",1.94,2.9106293646897], +["1sjv",1.94,2.26152733438915], +["2cy4",1.94,2.57408746949212], +["1ixl",1.94,2.27979023556010], +["1eqv",1.94,2.10017607260552], +["1fqi",1.94,2.20417647015657], +["1woz",1.94,2.06940226646332], +["1cx7",1.94,2.39600154605964], +["1xlr",1.94,2.51602051791632], +["1vgj",1.94,2.36000994891348], +["1inc",1.94,2.04791913023033], +["1xtp",1.94,1.39889013902498], +["1pxw",1.94,2.03713120227761], +["2dc8",1.94,2.32250095685844], +["2dcb",1.94,2.45118192135032], +["2dc9",1.94,2.50796721811239], +["2dc7",1.94,2.63297591375648], +["1z5y",1.94,2.648954611456], +["2giv",1.94,2.85417022175432], +["1c5w",1.94,2.70358660144790], +["1uri",1.94,2.35152901453471], +["1if8",1.94,2.37689114076514], +["1g53",1.94,2.23230047838922], +["1nw6",1.94,2.05556914657423], +["2euv",1.94,1.67131396836969], +["1n99",1.94,1.88501623383917], +["2f94",1.94,1.82680670289555], +["1i5b",1.94,2.5832222778044], +["2akp",1.94,2.96841427520671], +["1t6n",1.94,2.47027189025538], +["1aqv",1.94,2.13446554397439], +["1jvk",1.94,2.87660453982901], +["1gsu",1.94,3.04702653198412], +["1jzt",1.94,2.26289975525319], +["1fwn",1.94,2.19769972581366], +["1w2d",1.94,2.3299324664521], +["1zhh",1.94,1.27183237793318], +["1daa",1.94,2.14842689986420], +["1xru",1.94,1.70457555277208], +["2a6n",1.94,1.56954076734469], +["1wva",1.94,3.10544385648955], +["2cw5",1.94,2.01544706158535], +["1q5k",1.94,2.30038439911789], +["1kcl",1.94,1.96939575330244], +["1x14",1.94,2.2723269930833], +["1vch",1.94,2.52084405346016], +["1p2d",1.94,2.51009985187011], +["1fnu",1.94,3.10534607339758], +["1tl0",1.94,1.64686286411331], +["1kx5",1.94,3.08881340383771], +["1xky",1.94,1.61506600768054], +["1m1t",1.94,2.7117888221611], +["1d2e",1.94,2.74446609303386], +["1nto",1.94,2.40527460636817], +["1svm",1.94,2.53903928462297], +["1v97",1.94,2.29380369828753], +["2c8q",1.95,1.17660398278653], +["1ptq",1.95,1.55193768474257], +["1ljo",1.95,1.67854110313873], +["1os3",1.95,1.96334955551307], +["1lou",1.95,2.24397833003582], +["1opc",1.95,2.93546135087766], +["1cqy",1.95,3.03714841078306], +["1puc",1.95,1.77429442947629], +["1rhl",1.95,1.57424313438127], +["1i2f",1.95,1.30396247826278], +["2bu4",1.95,1.46839376904506], +["1o5j",1.95,2.00715790088452], +["1fkh",1.95,2.35522766883989], +["1i77",1.95,1.48872938093198], +["1yeb",1.95,2.95392827075518], +["1nze",1.95,2.65520918885635], +["1tfg",1.95,2.41893846238391], +["1lve",1.95,3.32178229828718], +["1bea",1.95,3.60584834501148], +["1rlk",1.95,1.99808326745087], +["1pqe",1.95,2.33113871204232], +["1zyx",1.95,2.39792079354949], +["2bh5",1.95,1.88042815045524], +["1hq8",1.95,2.48474088436486], +["1kvw",1.95,3.41094640584500], +["1e86",1.95,2.21272268013984], +["1gp3",1.95,2.63289847492362], +["1snp",1.95,2.34566049973399], +["1uic",1.95,1.87963377732349], +["1uie",1.95,1.97531504050386], +["1uig",1.95,1.44295313374835], +["1uid",1.95,2.11346316236809], +["1klx",1.95,1.50871439723968], +["1mq7",1.95,1.6192789753935], +["1enc",1.95,3.14684824279159], +["1syl",1.95,1.99188935353386], +["1ea8",1.95,2.46997202095523], +["1r2d",1.95,2.43069889327988], +["1k04",1.95,2.21800188129528], +["1y2q",1.95,2.14326616789092], +["1vsh",1.95,2.80682923121689], +["1n1f",1.95,2.94505682640463], +["1b8e",1.95,3.41478146935019], +["1o16",1.95,1.92546348210771], +["1icx",1.95,2.38648159325059], +["1zde",1.95,1.90278401320504], +["1uz2",1.95,2.89138345055027], +["1gv8",1.95,2.41630286984909], +["1f47",1.95,2.28750666724834], +["191l",1.95,2.34738108694245], +["200l",1.95,2.69289163899828], +["1l99",1.95,2.72376606329283], +["2b58",1.95,2.07835874038368], +["2b3v",1.95,2.25575122753429], +["1aew",1.95,1.98482497198771], +["1izm",1.95,2.81709814962926], +["1jrl",1.95,1.76175073749807], +["1a58",1.95,2.57171354162974], +["1l1r",1.95,2.3647814032132], +["1svi",1.95,2.30917104029944], +["2f9m",1.95,2.27596241455550], +["1m1h",1.95,3.0863618785865], +["1owf",1.95,2.19400615179803], +["1g2k",1.95,1.50751793054013], +["1bsw",1.95,2.32382095337], +["1bam",1.95,1.88875668203342], +["1i39",1.95,2.3072993917887], +["1tlv",1.95,2.61955581934188], +["1wm5",1.95,2.12958950602263], +["1sx6",1.95,2.05192413634061], +["1g3u",1.95,1.67298449806916], +["1qrm",1.95,2.28847964748397], +["1nrg",1.95,2.98438665500476], +["1ewc",1.95,2.31151641431793], +["1y71",1.95,2.12087625842624], +["1yuo",1.95,1.87018566285261], +["1o4t",1.95,1.91679090582697], +["1ppy",1.95,1.86541939324327], +["1i7e",1.95,3.0697380455479], +["1e8i",1.95,2.33464323314767], +["1u00",1.95,2.28770515309624], +["1lcz",1.95,2.54907101376645], +["2ctv",1.95,2.18452238079298], +["1axy",1.95,2.08097397033794], +["1ax2",1.95,2.08179739824161], +["1axz",1.95,1.81978077578347], +["1ax1",1.95,2.2185889264144], +["1fb2",1.95,3.28129841634693], +["1gs4",1.95,2.40304300483322], +["1m48",1.95,2.15772784121481], +["2cxb",1.95,2.22018794677792], +["1oae",1.95,2.50101372522245], +["2aa2",1.95,2.23311068754213], +["1sts",1.95,2.73246113496841], +["1ydc",1.95,2.04933274421834], +["1hd7",1.95,2.20006150925522], +["1lj4",1.95,2.50598815922998], +["1ttm",1.95,2.56795702661200], +["1sep",1.95,2.01675930912456], +["1tem",1.95,1.41460786275092], +["1c27",1.95,2.52332881344294], +["1p77",1.95,2.58531487947212], +["2a3i",1.95,3.01126300809657], +["2btl",1.95,2.38599598450356], +["1g68",1.95,1.81070515781632], +["4gal",1.95,2.96489696976633], +["1k27",1.95,1.50035144463634], +["1xc8",1.95,1.83047625868494], +["1uk6",1.95,1.58791433647536], +["1pm5",1.95,1.70308886090596], +["1su9",1.95,2.02545397421392], +["1t7v",1.95,2.34840869747809], +["1uu9",1.95,1.96232578485798], +["2hrv",1.95,2.01101471353986], +["1lhc",1.95,2.88835865245323], +["1w4t",1.95,1.97410398313699], +["1q4s",1.95,2.57160618955733], +["1omh",1.95,2.90013222255957], +["1jt3",1.95,2.09601553553531], +["1biz",1.95,2.40437211834974], +["1tu1",1.95,1.84964133565433], +["2c7s",1.95,1.80044385820269], +["1kw9",1.95,1.6434413682076], +["1yli",1.95,2.46479050378822], +["2biy",1.95,1.85106624895188], +["1spg",1.95,2.97864036770812], +["2c68",1.95,2.28013551078141], +["1e1v",1.95,2.69543961223061], +["1vp9",1.95,2.4280852050952], +["2vp3",1.95,2.54586613309994], +["1i7k",1.95,2.35416927685437], +["1c5m",1.95,3.49346918682744], +["1yon",1.95,1.97252958629957], +["2a0c",1.95,2.77481520568559], +["1pw2",1.95,2.53791954831123], +["1pxi",1.95,2.6793968695172], +["1bis",1.95,2.43711061134947], +["1frq",1.95,2.26270889111534], +["1q0z",1.95,1.78796163746969], +["1j1u",1.95,2.50858389762033], +["1ecv",1.95,2.46118153254333], +["2chl",1.95,1.94166383976121], +["1sug",1.95,1.87824527674104], +["1zb6",1.95,2.32488650585908], +["1qhz",1.95,1.60520045787140], +["1zu4",1.95,2.27404133732136], +["1mno",1.95,2.05320370703041], +["1ihb",1.95,2.39807283803379], +["1fh8",1.95,2.00656959667086], +["2tli",1.95,1.7905173996937], +["3tli",1.95,1.60455250663009], +["4tli",1.95,1.83326530408258], +["7tli",1.95,1.75777232289419], +["1bcy",1.95,2.96524856900399], +["1bc3",1.95,2.70364571919968], +["1pze",1.95,1.80495492471390], +["1h45",1.95,2.01639455265988], +["1aii",1.95,2.03972757090546], +["1t6s",1.95,2.45645860291955], +["1gr0",1.95,2.55559529060380], +["1mx3",1.95,2.64207715358634], +["1s17",1.95,2.1227043178137], +["1wae",1.95,1.69756893741049], +["1ywr",1.95,3.37317668461868], +["1xe4",1.95,2.06028400954203], +["2a33",1.95,1.97607418182942], +["1elp",1.95,2.82127736251060], +["1yby",1.95,1.41347980327573], +["1mjw",1.95,2.37184583159891], +["1meh",1.95,2.07524521449281], +["1y1x",1.95,1.2590660507474], +["2c1a",1.95,1.84152306600913], +["2apo",1.95,1.90552405223362], +["1m3s",1.95,1.91850500224623], +["1m7v",1.95,1.4418427794984], +["1s39",1.95,2.47284654784174], +["1wor",1.95,2.09652521472730], +["1yhl",1.95,2.33038319948937], +["1y42",1.95,2.08067224784414], +["1qn3",1.95,2.08622059497569], +["1a7c",1.95,1.81513444362014], +["1nu5",1.95,2.12648354317648], +["1enu",1.95,2.50316902177053], +["1ucf",1.95,1.69803695897229], +["2gc1",1.95,1.75200507667415], +["1hle",1.95,1.94288732592082], +["2g5d",1.95,2.44661283167664], +["1xti",1.95,2.73940517711368], +["1itv",1.95,2.72598275472150], +["1ww9",1.95,2.39401398431192], +["1w9h",1.95,2.39291455073996], +["1szx",1.95,2.60546108562596], +["1tq4",1.95,2.06602353967395], +["1kk0",1.95,2.14779513115302], +["1jbv",1.95,2.62634132010566], +["1qhd",1.95,2.2515554177627], +["1xly",1.95,2.83812295624750], +["1mie",1.95,2.70258379799267], +["1td0",1.95,2.24399540455007], +["1rkt",1.95,2.17765467485371], +["1crz",1.95,2.68682663004166], +["2aee",1.95,1.95965188502867], +["1wst",1.95,1.81151606883424], +["3hoh",1.95,1.32035729499465], +["5gss",1.95,2.52908599315103], +["1uwv",1.95,2.48966490816172], +["1uag",1.95,1.93232502186577], +["2b9w",1.95,1.35271409809353], +["2ba9",1.95,2.10711324015199], +["1sm3",1.95,2.62967932860369], +["1ydk",1.95,1.82649853734835], +["1lgv",1.95,2.43604829193218], +["1gaf",1.95,2.23437705496550], +["1e4w",1.95,2.73056576391479], +["1d7u",1.95,2.85123220657046], +["2fbj",1.95,2.89549957319098], +["1a3l",1.95,2.20754789276531], +["1yoj",1.95,2.06103396325993], +["2as8",1.95,2.87690867105634], +["1y0e",1.95,2.4218185015012], +["1kwu",1.95,1.92167632937634], +["1kwt",1.95,1.92860108240823], +["3kmb",1.95,1.93543097846296], +["1kdt",1.95,2.56450019442844], +["1i8p",1.95,1.54709767870771], +["1swo",1.95,2.67497613763725], +["1e1k",1.95,1.96702006853987], +["1fif",1.95,1.83484126460910], +["1fih",1.95,2.09981768226399], +["1txo",1.95,1.30666121407960], +["1y12",1.95,1.28974417910554], +["1fk8",1.95,2.59697898777013], +["2cwm",1.95,2.77390207431141], +["1l2i",1.95,1.62386182323706], +["1yb1",1.95,1.17573423283395], +["1aq6",1.95,2.22306931347939], +["5std",1.95,2.67692313756276], +["1q6e",1.95,2.44701198474077], +["1qkz",1.95,2.55403521831243], +["2flb",1.95,2.66270628837637], +["1u2y",1.95,2.04541093441004], +["1u33",1.95,2.09250236176628], +["1m04",1.95,1.50920379610277], +["1ycj",1.95,2.36568154462885], +["1w2c",1.95,1.87474853548581], +["1zy4",1.95,2.48693090204259], +["1g8f",1.95,2.32886855702563], +["2aa6",1.95,1.77420142166514], +["1v9e",1.95,2.60095792576777], +["1yvr",1.95,2.13127160946504], +["1sa3",1.95,2.04558078866336], +["1khy",1.95,2.47778260791691], +["1tsd",1.95,2.79729722089134], +["1t8u",1.95,1.64844562207072], +["1j5w",1.95,2.22983453850575], +["1nzk",1.95,2.19985922075836], +["1q7f",1.95,3.01080808120126], +["1l5u",1.95,1.81000343776134], +["1b4f",1.95,2.59122720587126], +["1oj6",1.95,2.72359467740426], +["1rqj",1.95,2.02825318326719], +["1of1",1.95,2.08281819494302], +["1hs6",1.95,2.90571171894461], +["1h7s",1.95,2.26956577433007], +["2a75",1.95,2.20543675386819], +["1mdw",1.95,2.36033631796485], +["1eua",1.95,2.18752096988750], +["1o7p",1.95,2.29258025575015], +["1bsl",1.95,3.20186617041913], +["1ogd",1.95,1.70609832243414], +["1nns",1.95,2.09811565489786], +["1q40",1.95,1.90090370995770], +["6q21",1.95,3.84102712971368], +["1pj1",1.95,2.19718997279057], +["1r65",1.95,2.24279166415727], +["1osp",1.95,2.30596141760896], +["1xhn",1.95,2.05309636339377], +["2asd",1.95,1.96067907581570], +["1ns2",1.95,2.644563598438], +["1l7k",1.95,2.61050704973573], +["1pb0",1.95,2.37757375343251], +["1r1h",1.95,2.89972653383132], +["1v11",1.95,1.76126571804342], +["1gvn",1.95,1.68490746406581], +["1w9l",1.95,1.64563869849882], +["1ekf",1.95,3.1352723391053], +["1lts",1.95,2.14245094834085], +["1zb1",1.95,2.54910808326009], +["2f6q",1.95,1.76181329425873], +["2aqv",1.95,2.05567933424533], +["2aqo",1.95,2.18748415641823], +["1hf3",1.95,2.26777644650609], +["1nlf",1.95,2.16033990336185], +["1xqk",1.95,2.36896206423847], +["2av1",1.95,2.12824134518496], +["1vi6",1.95,1.87048501799409], +["1l9d",1.95,2.28871112874037], +["1m5f",1.95,1.87945571179343], +["1aw7",1.95,2.43134542642507], +["1mxy",1.95,2.04275923043194], +["1mxv",1.95,1.98659690332163], +["1i8b",1.95,1.94846231862401], +["2a3e",1.95,1.53554595395788], +["1o75",1.95,1.64508213472748], +["1zpt",1.95,2.02785095469469], +["1rs7",1.95,2.35387928687991], +["1rs6",1.95,2.37014454069258], +["1y4k",1.95,1.68824149705659], +["1gzf",1.95,2.39495493527089], +["1d0o",1.95,2.31265474335034], +["1dm6",1.95,2.43662242018931], +["4nse",1.95,2.45145779813766], +["1vl4",1.95,1.68646156063237], +["1nec",1.95,1.75820754215842], +["1b12",1.95,2.67638946141450], +["2brr",1.95,1.84821987527217], +["2cbv",1.95,1.84000776068008], +["1oyj",1.95,2.46001609670729], +["1vl5",1.95,1.44717573027880], +["1fur",1.95,2.29642357322582], +["1ekx",1.95,1.75807323553747], +["1m1z",1.95,2.41706104186337], +["1r5z",1.95,2.4265340651725], +["1uws",1.95,2.06707908882928], +["1uwt",1.95,2.04962965012574], +["1uwu",1.95,2.050131245755], +["1jgt",1.95,2.44430650214101], +["1uiv",1.95,2.83522099536080], +["1j9t",1.95,2.01397016955305], +["1r34",1.95,1.87481085994712], +["1pn2",1.95,1.77337688256064], +["1svl",1.95,2.72613206431835], +["2dbu",1.95,2.06123978322277], +["1t4d",1.95,2.80618961346152], +["1l3i",1.95,2.28098264626923], +["1f73",1.95,1.94303606093677], +["1lv5",1.95,3.20093074731759], +["1z7x",1.95,1.55155114328989], +["1olm",1.95,2.33835208304762], +["1o6z",1.95,2.26174830278235], +["1fo6",1.95,2.19522834830954], +["2oat",1.95,2.66043219366387], +["2b4g",1.95,1.70757234747959], +["1h4o",1.95,2.01055958387103], +["2d0i",1.95,2.35511594050298], +["1ni4",1.95,2.21209864737554], +["1a4m",1.95,2.74319575131353], +["1i7q",1.95,2.74072307191500], +["1k3t",1.95,3.06422366329044], +["1um0",1.95,2.98522358195489], +["1u1g",1.95,1.86568724369913], +["1m1o",1.95,2.75675879539011], +["2asv",1.95,2.19954585811711], +["1g5h",1.95,2.40321426288331], +["2byz",1.95,2.22444495474499], +["1ynh",1.95,2.0699438795209], +["1kbv",1.95,2.55630630749463], +["1umn",1.95,1.88925873418175], +["1p1h",1.95,3.20697470419506], +["2bo4",1.95,2.07532455636317], +["1nfv",1.95,2.10764035931035], +["2ajc",1.95,2.52489182116209], +["1itw",1.95,2.01148637134298], +["2f2h",1.95,2.40861196477013], +["2c1u",1.95,2.21280114829060], +["1h7m",1.96,1.62790963210375], +["1km9",1.96,1.64032948311910], +["1kxw",1.96,1.76545785719686], +["1ifb",1.96,3.50492777928660], +["1a2t",1.96,2.80324780905086], +["1lg7",1.96,2.65537466066414], +["2bf3",1.96,2.54596484437359], +["1s36",1.96,1.34486368868503], +["1teg",1.96,2.08576759679486], +["2cwa",1.96,1.79678822523639], +["1zio",1.96,2.17948346066897], +["2aky",1.96,2.09501071321973], +["1s5p",1.96,2.74112653744827], +["1zhm",1.96,2.26611563862519], +["1hcz",1.96,2.3574753020813], +["1g4o",1.96,2.19315929335525], +["1e5h",1.96,1.87998977091784], +["1vhx",1.96,2.44004909473275], +["1jsv",1.96,2.72101691557731], +["1prn",1.96,2.21197839894412], +["1pxo",1.96,2.69073258791804], +["1be0",1.96,1.89563330598606], +["1jol",1.96,2.63809414049954], +["1qrp",1.96,1.49763213273388], +["1z17",1.96,1.92203393411758], +["1rhf",1.96,2.09681015651640], +["2g74",1.96,2.64886097132818], +["1nfs",1.96,2.45964841452044], +["1mdx",1.96,1.93216196732463], +["1u18",1.96,2.29154656475805], +["1gar",1.96,2.96907630158137], +["1t0o",1.96,2.26962699264621], +["1q9k",1.96,3.2516415353502], +["1n7y",1.96,2.78412877962835], +["1g97",1.96,1.45005063829949], +["1g9k",1.96,1.42333498364761], +["1p60",1.96,2.06695795937577], +["1y9r",1.96,3.69986055130827], +["1pr9",1.96,2.41099352098873], +["1gwf",1.96,1.83671145634976], +["2g9z",1.96,2.36003232431811], +["1v5g",1.96,2.23147389424898], +["1ptm",1.96,2.56190619396671], +["1xgi",1.96,1.97881333707969], +["1xyb",1.96,1.96286087957411], +["1vi9",1.96,2.11482839144693], +["1hrd",1.96,2.93171955298766], +["1xfo",1.96,2.03520657690359], +["1lvo",1.96,2.80276862677073], +["1k7w",1.96,2.37247515825152], +["1m5w",1.96,2.94143161078614], +["1xu5",1.96,2.42971287529810], +["1xvg",1.96,2.30508581137296], +["1fz7",1.96,2.38391854864735], +["1fz1",1.96,2.13940925931304], +["3pcg",1.96,2.61288708223589], +["2bbe",1.97,1.76241141257368], +["1chh",1.97,3.28715978469096], +["2imn",1.97,2.47652503977065], +["2lzt",1.97,1.62771821282424], +["1lzt",1.97,3.49215030032702], +["2snm",1.97,3.36365026569138], +["1v8v",1.97,2.02317415087638], +["1fm4",1.97,1.55113448347130], +["1ky0",1.97,2.22319747629345], +["1d3j",1.97,2.19676352615956], +["1d4y",1.97,2.37262284074023], +["1e48",1.97,2.63190922899527], +["1unf",1.97,2.53054103126433], +["1pry",1.97,1.53168311470118], +["1r7x",1.97,2.08040314403270], +["1k2v",1.97,2.63121432276359], +["1t0h",1.97,1.98965455787993], +["1jbs",1.97,2.40091741925547], +["9abp",1.97,2.64729985755343], +["2d7v",1.97,2.53920865149202], +["1d0l",1.97,1.29216008757072], +["1nfz",1.97,2.22157325821272], +["2g73",1.97,2.52483453282943], +["1le6",1.97,1.97607969460027], +["1q6h",1.97,1.46636580225937], +["1z4n",1.97,2.02319720318541], +["2d03",1.97,2.23264462203169], +["1va0",1.97,1.82126549619941], +["2b56",1.97,2.13897190557068], +["1vzx",1.97,1.69183102129383], +["1vzu",1.97,2.0798739613725], +["1o7o",1.97,2.10970381211034], +["1wx1",1.97,2.07930773454808], +["1xgj",1.97,2.22534653471624], +["1fxh",1.97,2.05489941977616], +["1ms7",1.97,2.18878039866784], +["1kti",1.97,2.78953658941640], +["1jqb",1.97,2.50102338269450], +["1hd3",1.98,2.61723796529352], +["1l3p",1.98,1.78895957560960], +["1kt9",1.98,2.19309287116805], +["1f3z",1.98,3.70361608870395], +["1l0j",1.98,2.48457684355593], +["1v0a",1.98,1.80676053453174], +["1z4i",1.98,2.03627379906965], +["1uy8",1.98,2.16776939923467], +["4tmk",1.98,2.39909504252097], +["5tmp",1.98,2.81170163159635], +["1yf4",1.98,2.13964530989012], +["1h7l",1.98,2.76644465875536], +["1qcc",1.98,1.78310862826267], +["1ml9",1.98,3.07086317446042], +["1if7",1.98,2.21339164263883], +["1zcv",1.98,1.72836600196831], +["1i9g",1.98,2.21522326186201], +["1shv",1.98,3.04776673908155], +["2b4w",1.98,2.39397955078810], +["1c1v",1.98,2.69520162093947], +["1mdn",1.98,2.29819156543063], +["1v7l",1.98,2.99278563658763], +["1xdw",1.98,1.74574729172090], +["2tec",1.98,2.31357644638152], +["2bim",1.98,1.69075970898384], +["1njs",1.98,1.96586015976288], +["2aha",1.98,2.90823083596883], +["7taa",1.98,2.22491477286564], +["1zvr",1.98,2.94758226500663], +["1xnf",1.98,1.96961656656427], +["1hds",1.98,5.37328827266315], +["1y7z",1.98,2.48073442139035], +["1y4p",1.98,2.13246730495044], +["1zud",1.98,2.57784167639262], +["2dh4",1.98,2.33839928101445], +["1c97",1.98,2.74821370050390], +["1p6h",1.98,2.47049470827256], +["1xnj",1.98,2.75984282680007], +["1n9g",1.98,1.77614928642692], +["3pcc",1.98,2.54100616624529], +["1vdv",1.98,2.12148743078277], +["2evh",1.99,1.73178580295392], +["1uo2",1.99,2.07464296111419], +["1m47",1.99,2.14553549967118], +["1tp3",1.99,2.55367338132875], +["1dm1",1.99,2.05965865744225], +["1tfu",1.99,2.65608230749531], +["2aoa",1.99,3.33741876625694], +["2evt",1.99,2.18273532380060], +["1rjk",1.99,1.8146864025212], +["1ztf",1.99,3.01849518865378], +["1zcy",1.99,1.95173313682325], +["1uwz",1.99,1.6413900168548], +["1ux0",1.99,1.78296178245564], +["1tqm",1.99,2.07261999462191], +["2bts",1.99,2.0748549006571], +["1mu6",1.99,2.58180376177697], +["1j99",1.99,2.44515498211941], +["1w3w",1.99,2.07014375738151], +["1g1b",1.99,2.55491203647614], +["1vqz",1.99,1.46602076705407], +["1xo5",1.99,2.13003360457328], +["1s7q",1.99,2.05419698225082], +["1s7s",1.99,2.31235049096615], +["2g45",1.99,2.00613382614787], +["1q6y",1.99,2.34016972413606], +["1p5u",1.99,1.99407389746105], +["1jxj",1.99,1.75849281471092], +["1pzi",1.99,2.15310434179525], +["1xy0",1.99,2.48524263380135], +["2fb5",1.99,1.9971295491606], +["2gpn",1.99,2.03521032361800], +["1e6z",1.99,1.98443502090246], +["2bex",1.99,1.98445049501223], +["1tzj",1.99,2.38317344759538], +["1vax",1.99,2.1585462798675], +["1zbg",2,2.24642331429946], +["1y8y",2,2.66467330764542], +["1bph",2,2.04328314907837], +["1aph",2,2.43820533656733], +["1kfm",2,2.25831669724292], +["2mlt",2,2.25132696051881], +["1rdv",2,3.19779889080979], +["1r0j",2,2.25182997522330], +["1dur",2,1.78036826855767], +["1bpt",2,2.76054185852917], +["1em7",2,2.86094042653676], +["1qkw",2,1.81614603140855], +["1gzr",2,2.98777194971049], +["1egp",2,1.94630059519825], +["1fsc",2,2.37023227068535], +["1h02",2,3.47582594049595], +["4mt2",2,3.02731367177326], +["5ebx",2,2.80814118380104], +["1r69",2,1.79695976557106], +["1ypa",2,1.84038962499158], +["1ypb",2,1.38868884659847], +["1bnz",2,2.63940741471967], +["1omy",2,2.21981852441944], +["1bkv",2,1.70696893610368], +["2ci2",2,3.23415930243892], +["2ame",2,1.65708620059418], +["1t6o",2,2.18852644366476], +["3il8",2,2.45759663517506], +["1mjc",2,2.67322654497256], +["1y0n",2,3.07581037452017], +["1dcd",2,2.51560545641529], +["1aik",2,2.66319282572437], +["1b0x",2,1.92531254431309], +["1tgg",2,2.03436478518795], +["1hoe",2,2.45689157912495], +["1l0h",2,2.15384912556769], +["1esr",2,2.94298912173796], +["1nh9",2,2.12335579058820], +["1pzw",2,2.96645460179381], +["1pht",2,2.44988895955408], +["2f8k",2,1.50493240219486], +["1g1i",2,2.38547525876258], +["1a1j",2,1.64629340380459], +["1j2x",2,2.20160347467205], +["1hip",2,3.86402048502424], +["1poh",2,3.12969438713527], +["1vku",2,1.92679312980767], +["1r5q",2,2.20773094106244], +["1ayi",2,1.90120821740501], +["1hb6",2,1.79119003174374], +["1j55",2,2.28201245045589], +["1ae3",2,2.47150421255695], +["1ae2",2,2.57602151223172], +["2hpr",2,2.56386611702195], +["1y50",2,2.11547241659388], +["1nfj",2,2.56498039041457], +["1tig",2,2.22996616578055], +["1yqb",2,1.50317875341467], +["1mho",2,1.96542049078418], +["1yo5",2,1.64982828506655], +["1x6j",2,1.94416957119136], +["2f15",2,2.55215091429140], +["1hbk",2,2.41068540977676], +["1xe1",2,1.53186528853345], +["2gnk",2,2.63449004562607], +["1az5",2,2.17038240577224], +["1q4v",2,2.44191297853593], +["1j73",2,2.33353042674054], +["1zij",2,3.97753449198036], +["1zim",2,3.55084326470568], +["1izb",2,2.96016663431133], +["1ris",2,2.13510864960970], +["2c3g",2,3.29325821755541], +["6ins",2,3.70709804661596], +["1oow",2,1.7403095862771], +["1mgw",2,1.76343987407487], +["3tlh",2,2.61039383742669], +["2es9",2,2.45871008120287], +["2az8",2,2.092928978468], +["1xer",2,1.67919345828149], +["1fhg",2,1.66322432911217], +["1p1l",2,1.64461939650242], +["1shd",2,2.60916368709005], +["1j2v",2,3.53379944728864], +["1w0t",2,2.21806448549928], +["3kvt",2,1.74216379549008], +["1m5i",2,2.46706045013659], +["1fys",2,1.75212066137546], +["1rgl",2,1.94791845044044], +["1lxi",2,2.78388397390728], +["1o4f",2,2.12982501416931], +["1aan",2,1.95782019893481], +["1aiu",2,2.22611835329675], +["1mb0",2,2.37000975138348], +["2cvk",2,2.22953093488419], +["1gxq",2,2.73846239611145], +["1fut",2,2.43608858304901], +["1uwm",2,2.29914889374942], +["1cri",2,2.7571336816787], +["1crg",2,2.99243655079791], +["1btn",2,2.46384852343260], +["1o4e",2,2.55805397343941], +["1o46",2,2.63743017255712], +["1a1x",2,2.23878125852273], +["1shb",2,2.71518591990779], +["1irw",2,3.42324830215795], +["1c9h",2,1.95314489342877], +["2cym",2,3.3682260655817], +["1fkg",2,2.12672567519289], +["1gmb",2,1.65163311793472], +["1he7",2,2.91016357559826], +["1xw4",2,1.89705510247771], +["1du0",2,2.18311165690176], +["1ei8",2,2.27139143741014], +["1acx",2,4.62630518575949], +["1b9a",2,2.37321465761653], +["2tir",2,1.98230599244924], +["1chi",2,3.28877690643702], +["1ox3",2,1.20435220401248], +["1jpc",2,2.05225375389229], +["1cew",2,3.41140983100551], +["1i4m",2,2.20936727248857], +["1aa2",2,2.85226671389556], +["1s3p",2,2.22265410216053], +["2apw",2,2.03824825290892], +["1npl",2,2.679857329604], +["1by2",2,1.74065642941488], +["1xd6",2,2.58860927645674], +["1w6x",2,2.28515546938980], +["2c2c",2,2.97427233654361], +["1tgj",2,2.01905838256365], +["1jgg",2,3.37053356525869], +["1lgp",2,2.33851385606444], +["1l4x",2,2.55581476453286], +["1yhf",2,1.95663132449989], +["2imm",2,2.49889157875398], +["5lve",2,2.32967999543517], +["3lve",2,2.45556141342325], +["1kjt",2,2.27473808985702], +["2bti",2,2.34844954820856], +["1fnk",2,1.97546750218351], +["1z3m",2,2.33944885809621], +["1i0c",2,2.56040867360705], +["1xj2",2,2.14250225574079], +["1npu",2,2.53003159728283], +["1cs3",2,2.39539074965435], +["1z3p",2,1.96767797404702], +["1wq6",2,2.46134082743907], +["1uhd",2,2.45837838033177], +["1fiv",2,2.76290435859007], +["1rbc",2,2.49521654514477], +["1nxv",2,2.51672997671954], +["1mh7",2,2.60863764456246], +["1ae7",2,2.3739952871006], +["1uii",2,1.52779521298273], +["1e97",2,3.12912645168895], +["1rri",2,1.86669606188488], +["1h53",2,2.88453499167184], +["2bz8",2,3.13333895037389], +["1ssc",2,2.69964664885353], +["1ppa",2,2.77685313780677], +["1fkv",2,2.48528217334260], +["1hmk",2,2.68378369089897], +["1py0",2,2.23294251390363], +["4srn",2,3.38880112703182], +["1nzn",2,1.99592412758108], +["1h52",2,3.00112142548523], +["1ssa",2,3.40954322526986], +["1ssb",2,3.44063861012655], +["3srn",2,3.83197037437312], +["7paz",2,3.08045145328299], +["1huf",2,3.00676920401721], +["1hby",2,2.99621644312778], +["1b1j",2,3.71173224834092], +["1b1e",2,3.28373792658055], +["2ang",2,3.22635890351063], +["1zib",2,2.54171855356978], +["1bk9",2,1.98865090613551], +["3rsk",2,2.3880679088571], +["1eow",2,1.78449799986528], +["1rsm",2,1.97946844427393], +["1aqp",2,2.30215469717005], +["1rnm",2,2.57660085484963], +["1rnq",2,2.59798254303742], +["5rsa",2,2.69473800043930], +["6rsa",2,2.78678514326061], +["1f7s",2,2.10627016507410], +["1rny",2,2.76996127202632], +["1c0c",2,4.39101035639999], +["1ob9",2,2.29768867063209], +["1acf",2,3.06091225050102], +["1h04",2,2.29130565441490], +["2ftb",2,1.78856129207743], +["1kh8",2,2.31432080087761], +["1tvq",2,1.83487991758204], +["1yig",2,2.03465560659562], +["1sem",2,2.78472025279426], +["1gmm",2,2.47086761990886], +["1qg7",2,3.11285073392609], +["1j5u",2,1.86158134313740], +["5chy",2,2.65295982165459], +["1di4",2,2.38594574453843], +["1inr",2,2.44491724897636], +["1lsz",2,2.21502792745614], +["2cds",2,1.56511277978320], +["1hsw",2,2.53895279557315], +["1dkj",2,2.30426871339067], +["1lpi",2,2.58043628001167], +["2lym",2,2.56789666514052], +["1ps5",2,2.16997112960390], +["3lym",2,2.56122483478772], +["6lyz",2,3.45418498002514], +["3lyz",2,3.69492226497487], +["2lyz",2,3.4865434326745], +["4lyz",2,3.71031116342985], +["5lyz",2,3.71754907620286], +["1lyz",2,4.38997963437583], +["1bb7",2,2.02460181781941], +["1bb6",2,2.34206826023308], +["1lmc",2,2.38163593808860], +["1lmp",2,2.51955390771735], +["1msc",2,4.08314192405885], +["1bff",2,3.09145498965106], +["1nfo",2,3.03371873270774], +["1b5x",2,2.23901884007304], +["1e6k",2,2.41560321436948], +["1ge2",2,2.2379933285679], +["1b7p",2,2.61911143787095], +["1ckh",2,1.74251700186599], +["1ubz",2,2.46884841671287], +["1b7q",2,3.13606087964956], +["1jhc",2,2.30985071346069], +["1t3x",2,1.53884623080655], +["1u4l",2,1.58340576995037], +["1u4m",2,1.62688987621322], +["1abo",2,1.92095417451381], +["1q8c",2,3.24893653921548], +["1uz0",2,1.90784284168844], +["1o8p",2,2.0160350885959], +["1tqo",2,2.07287815460846], +["1jfv",2,2.28093443607793], +["2ifb",2,2.96324361537241], +["1tou",2,1.78472626237191], +["1tow",2,1.62423843954487], +["2amu",2,1.39471649789516], +["1gr3",2,2.14352241573362], +["1lpj",2,3.16262750094799], +["2dhq",2,2.00010937445495], +["2nuc",2,2.79789887665703], +["1a2u",2,2.93066567829759], +["1iul",2,2.601235411884], +["1is5",2,2.05971726633121], +["1wlc",2,1.92162051152519], +["1ve0",2,1.86940507250630], +["1poc",2,3.08335182832138], +["1h1h",2,2.78081764777667], +["1eya",2,3.21376908818079], +["1rlj",2,2.52434149887848], +["2c02",2,2.27613593391876], +["1f2y",2,2.33170409463614], +["1f2m",2,2.48433901413989], +["1b68",2,2.18859571535495], +["1taf",2,1.90653120550605], +["1tn3",2,3.35885550253678], +["1kdc",2,2.48429327844418], +["1twu",2,2.47329251400728], +["1stb",2,2.93005282181645], +["1enk",2,2.95995742719586], +["3cbs",2,1.67289135733633], +["2cxc",2,2.73836083380368], +["1fso",2,2.13409520168288], +["1sfu",2,2.54262926320075], +["1fil",2,2.73684630233783], +["1y2f",2,2.69851589328507], +["1bvq",2,3.30328701108557], +["1pne",2,2.54839315574446], +["1q2y",2,2.53702616438029], +["2d28",2,2.86360744577662], +["1ifg",2,2.67938733468067], +["1p4p",2,2.5325466980441], +["1ekr",2,2.80569798056194], +["1r2i",2,2.73345383164207], +["1osd",2,2.05033740498552], +["1ety",2,2.48413215839216], +["1c3k",2,2.07993836135618], +["7ins",2,3.63748929686024], +["1nig",2,2.53793533429525], +["1yoy",2,1.74157172727225], +["1c3m",2,2.53659117927706], +["1o80",2,2.98303320734387], +["1etv",2,2.26982124366758], +["1l5z",2,1.95303746287852], +["1a5w",2,2.69074549891708], +["1lin",2,2.23029708214906], +["2cj6",2,2.36594067840991], +["1aly",2,3.61220845542043], +["3mba",2,2.46492210150836], +["2fam",2,2.54071538621192], +["4mba",2,2.57792185594873], +["1akv",2,2.23818641555784], +["1i1o",2,2.08984912651538], +["1fx1",2,4.05092572106026], +["1cdm",2,2.41192819217717], +["1rfj",2,2.39789841285425], +["2lhb",2,2.71121895184065], +["1o22",2,1.88507379812734], +["31bi",2,3.22789960762507], +["2faz",2,2.29838642028424], +["1ndc",2,1.63055496473474], +["1wrj",2,2.42144073097798], +["1qg5",2,3.15045453073721], +["1amx",2,2.54966446666312], +["1ibh",2,2.01628895595664], +["1ibd",2,2.50609573517264], +["1rnh",2,3.01649940094476], +["1ws1",2,2.56179209698884], +["1fia",2,2.59292714520416], +["1i1b",2,2.15697170017192], +["21bi",2,3.27595949332912], +["4i1b",2,3.34105398024126], +["1sra",2,1.90751544725975], +["1duo",2,3.0357838011136], +["1vh2",2,1.59141124482392], +["1dvo",2,2.10228014792130], +["1byr",2,2.82833384412209], +["1bys",2,2.84752723022764], +["1ly1",2,1.62749291095104], +["1lhs",2,2.97630407120648], +["1lht",2,2.37476374603507], +["1azi",2,3.24380444580346], +["1yma",2,3.65840818269855], +["1ymc",2,3.55478118608465], +["1mbn",2,4.06713943742041], +["2lh2",2,2.27219615686082], +["1mbi",2,2.27748125285664], +["2lh3",2,2.38199211544584], +["2lh5",2,2.2468476612063], +["1lh3",2,2.47679706437712], +["1lh1",2,2.26989454144841], +["2lh1",2,2.19626546628817], +["2lh6",2,2.36405659080483], +["1lh2",2,2.36620658813398], +["1lh5",2,2.33366998732225], +["5mbn",2,2.4677294043768], +["2lh7",2,2.168887180577], +["1lh6",2,2.58353020972557], +["4mbn",2,2.54384343749418], +["1lh7",2,2.44324973879446], +["1vxa",2,3.41670227314584], +["1spe",2,3.29515371391813], +["1vxb",2,4.27144403049322], +["1iwq",2,2.37218070930451], +["1iob",2,3.49051796278099], +["2i1b",2,2.98554848870007], +["1z7c",2,3.3713316554009], +["1eso",2,2.58460585563416], +["1mlf",2,2.51885526930492], +["1mlg",2,2.9777329307683], +["1mlh",2,2.50559465257043], +["2mgb",2,2.78052774510689], +["1ch3",2,2.42138982977488], +["1cp0",2,2.72866526587751], +["1mln",2,2.81034715880527], +["1mlr",2,2.79529354583996], +["1mlq",2,2.70813836815338], +["1mlj",2,2.80929630694092], +["2mgk",2,2.89740139260518], +["1mod",2,3.02752646600539], +["2mgj",2,3.10354956588291], +["2mgi",2,2.95375454604893], +["1moc",2,3.08508817804179], +["2mgh",2,2.86472406820565], +["2mgl",2,3.03981166159341], +["1etw",2,2.13460709912367], +["1gob",2,3.11498040559527], +["2tn4",2,2.41820203020458], +["1t9o",2,1.91195213203455], +["1txj",2,1.83939738166484], +["1goc",2,3.5051121482403], +["1i05",2,2.09107219998541], +["1j85",2,2.84607460869605], +["1yh2",2,2.05166896704469], +["2e2c",2,2.74344165073463], +["1esl",2,2.1399825553183], +["1yp7",2,2.57154528548096], +["1zne",2,2.97136760311657], +["1jj9",2,2.54972572583670], +["1dy3",2,2.09648613760092], +["1t4a",2,2.07934892427068], +["1dg8",2,2.59455462704422], +["1dg5",2,2.36817445802607], +["1rfe",2,1.93900592845763], +["1eh7",2,1.81637727330533], +["1a85",2,2.59005055145619], +["1a86",2,2.55612029869117], +["1wgb",2,2.35537991995724], +["1rg7",2,3.013692385423], +["1bv1",2,2.17667287443580], +["1cm1",2,2.12175441669176], +["1rx1",2,2.81398672270754], +["1rx6",2,2.85999972614233], +["1u9b",2,2.78724600769043], +["1i04",2,2.58771599730632], +["1hyb",2,2.01477296482585], +["2g2d",2,1.34221942832611], +["2g6b",2,1.89101032602221], +["4tnc",2,2.95855328260214], +["1p2t",2,1.84827035022097], +["1p2u",2,2.08602829228451], +["1u9a",2,2.56317382717278], +["1ioz",2,2.43014488258207], +["5tnc",2,2.95937496579524], +["1s21",2,1.95392596128521], +["190l",2,2.51257953656116], +["1c60",2,1.72657464917832], +["1c6d",2,1.91172847058037], +["1c6f",2,1.91172847058037], +["1c61",2,1.70326998282239], +["1c64",2,2.11507835285968], +["1c6c",2,2.25469894186028], +["227l",2,2.19997820581859], +["142l",2,2.24993187713956], +["1c63",2,2.35742723505272], +["1c65",2,2.33955491433145], +["2l78",2,2.27912471461008], +["1l85",2,2.57215042823896], +["141l",2,1.86889512878731], +["1li2",2,2.19286662228947], +["1lyi",2,1.96324006935470], +["143l",2,2.27102054015594], +["1c6t",2,2.32477743582259], +["147l",2,2.27088777957326], +["1li6",2,2.45353285055201], +["1l81",2,2.24238794799238], +["1l95",2,2.39387209797770], +["1tla",2,2.41002801870834], +["1d3n",2,2.55172361269178], +["145l",2,2.45350263669795], +["1l96",2,2.50439047340122], +["1qsr",2,2.47934410889219], +["1sn8",2,1.72196893433020], +["2af9",2,1.8973202374337], +["253l",2,2.17862545170690], +["1rl6",2,2.30944314448868], +["1qtz",2,2.46296340993727], +["152l",2,2.6095639214142], +["1lyd",2,2.83017946093895], +["1wrz",2,2.66958501472906], +["1huw",2,2.213287925137], +["1l4y",2,2.41408295224967], +["1vbs",2,2.14687971792857], +["1eh6",2,1.88176444608750], +["1kuv",2,2.82948687215547], +["1zvq",2,1.96958284993978], +["721p",2,2.81987729411855], +["1ge5",2,1.86224448442692], +["1cwm",2,2.06192054238102], +["1b8y",2,2.53423687461526], +["1wv9",2,3.35958627328484], +["1m8g",2,1.56756993757701], +["1yzk",2,1.38149744943203], +["1ftg",2,2.6705419219462], +["1flv",2,3.03877353191152], +["1dy2",2,2.27774111300712], +["1yzg",2,2.64622532755852], +["1ym9",2,1.32475856990509], +["1txy",2,2.78944573714720], +["1czu",2,1.25423686120074], +["3rab",2,1.96909589706516], +["4q21",2,3.01646644546821], +["1xtq",2,2.43418666423847], +["1ys0",2,2.26687087530719], +["2bl1",2,2.14471900606612], +["1awp",2,2.53048643714975], +["1l8j",2,2.55976538874484], +["2ew1",2,2.87830093560741], +["1mvl",2,2.20685863655458], +["1rcd",2,2.07101476466791], +["1rci",2,2.49413732653992], +["1zj6",2,2.10695766114169], +["1fcg",2,2.33455525530548], +["1spv",2,2.40613701042555], +["1sph",2,2.67927260254043], +["1lki",2,2.36388583613595], +["1aaz",2,2.08027546904840], +["1qoi",2,2.3132516475541], +["1mq9",2,1.96618486880613], +["1rkb",2,2.22649301380570], +["2cy2",2,2.68384340570245], +["2prd",2,2.31481068189558], +["1j00",2,2.52424870051643], +["1yfw",2,1.95162423380916], +["1yfx",2,2.47855052702980], +["1lhn",2,2.5738364025169], +["1jyj",2,2.46072468266200], +["1jeo",2,1.73521634703883], +["1gcs",2,2.85685427672247], +["1g2f",2,2.76249839571953], +["1t8a",2,2.55820852059051], +["1rbp",2,2.60429015610547], +["1c6o",2,1.78552121273991], +["1v2g",2,2.28643381973482], +["1lho",2,2.03599417024591], +["2atz",2,2.48193590797183], +["1fbs",2,2.43420467766451], +["1fn0",2,2.88265411591052], +["1fbu",2,2.01981994385755], +["1fbq",2,2.41392486679783], +["1xyn",2,2.54870077735250], +["1t9f",2,2.95593013406791], +["1dpf",2,1.81881743941663], +["1fjl",2,2.47618549263087], +["1q0a",2,1.81391231390313], +["1cdy",2,3.94124856764089], +["1t4m",2,1.54824072583131], +["1s7f",2,2.39234064986251], +["1m7b",2,2.17169015907765], +["1cws",2,2.13465971436022], +["1uvc",2,2.91573568478985], +["2cvj",2,2.22727797698447], +["2cu6",2,1.84729400098449], +["1euo",2,2.67062536881377], +["1v76",2,1.86699154243480], +["1zon",2,2.81760701450191], +["1bk1",2,1.71212143867353], +["1mk1",2,1.77241881905382], +["1u1k",2,2.02776083758827], +["1u1m",2,1.91312416903908], +["1u1o",2,1.97037397539087], +["1u1l",2,2.15137241701874], +["1umh",2,2.15222378366786], +["1s6c",2,2.12435430551619], +["1ipc",2,2.33255544622129], +["1ln0",2,2.34218091481218], +["1pi1",2,1.70473712775534], +["2cxd",2,1.95717681091876], +["1a64",2,3.01360158418606], +["1drf",2,3.62947356920159], +["1gky",2,2.05142012239405], +["1rgp",2,3.09534770104053], +["1jlm",2,2.77099587293893], +["1hjl",2,2.35483030018296], +["1a2j",2,1.95046779213225], +["1vqt",2,1.9043175958522], +["2fiu",2,1.77541416285096], +["1rsn",2,1.69714851284960], +["1cdc",2,2.5773348122818], +["1jyq",2,1.90256099043121], +["1jjv",2,2.42014691666283], +["1wq9",2,2.54923476559187], +["1utu",2,2.96593235084114], +["4ukd",2,2.12835758244996], +["1ipb",2,2.33911698429426], +["1b6p",2,1.80833821813529], +["2ai7",2,2.22849064741239], +["1v74",2,1.44906300955091], +["2amh",2,1.47713863439304], +["1v9h",2,2.31715139023528], +["1c8s",2,3.57096669456759], +["1dmp",2,3.00057614111231], +["1z4p",2,2.18605459578888], +["1pbv",2,1.73294543579504], +["1byo",2,2.85265628215392], +["1rl8",2,2.76193041593033], +["1ody",2,3.24268784502626], +["1k6v",2,1.55546991050087], +["1hvj",2,1.85895708401152], +["1wbm",2,1.54159183245927], +["1npw",2,1.95319420980389], +["1npa",2,1.97463703161334], +["1hpx",2,1.86806142035476], +["1wbk",2,1.62500636310553], +["1hsg",2,2.19482779466026], +["7upj",2,2.22841555981218], +["1msn",2,1.56913373678652], +["1mrw",2,1.62081207915216], +["1npv",2,1.91678266850730], +["1msm",2,1.63937763113163], +["1ajv",2,2.12033381684040], +["1ec2",2,1.650368875558], +["1mrx",2,1.66634134423933], +["1bv7",2,2.56036350773666], +["1htg",2,2.07945378643287], +["1ajx",2,2.51669060592477], +["1bv9",2,2.7432905629756], +["1odx",2,2.88707473226008], +["2hpe",2,2.67792734962635], +["1axa",2,2.86050541108341], +["1a30",2,1.88460981108717], +["1hiv",2,2.42734042095245], +["1gbj",2,1.73953001181607], +["1fzv",2,2.80167912294574], +["1p01",2,2.05307892100770], +["5hvp",2,2.45440222996327], +["2fm9",2,2.01181442832822], +["1r23",2,1.89778719615377], +["2b0c",2,2.00106194050305], +["1g79",2,2.76297551541150], +["1p02",2,2.31582170188693], +["1z77",2,1.44233477059418], +["1l5b",2,3.63076852022244], +["1bft",2,3.14739646934426], +["1qde",2,2.42203691065792], +["4aig",2,2.12890777230435], +["1iag",2,2.81177630949607], +["1kj7",2,2.02522651315578], +["2ga1",2,1.03819150164992], +["1mzw",2,1.85951119000074], +["4cd2",2,2.92522864758262], +["1f7a",2,2.21448836219658], +["1kjg",2,2.01304272578206], +["1mt9",2,2.27257079909487], +["1tsq",2,2.33586574219901], +["1kjh",2,1.93453115101810], +["1i55",2,2.22459237746149], +["1kjf",2,2.22197686368925], +["1nsj",2,2.84096396700637], +["1cfb",2,1.28427445004295], +["1e26",2,2.96587581099544], +["1gnk",2,2.60187849048695], +["1jv6",2,2.4733593306948], +["1rgc",2,2.38524927439332], +["2aad",2,2.48043362535547], +["1b2m",2,2.18047818678676], +["1w77",2,3.39723302866833], +["1h2f",2,1.8705212352152], +["1mrs",2,1.95222941663645], +["1wd5",2,2.05798189431773], +["1oa7",2,2.08685027634378], +["1oa9",2,2.55321160813133], +["2a48",2,2.51965442486402], +["1a09",2,1.90167894298071], +["1e2e",2,2.37038111051161], +["1uy9",2,2.14588365411711], +["1uyg",2,2.28350051239714], +["1uyc",2,2.44614746128372], +["1uye",2,2.35358697591944], +["1uyf",2,2.22774255891903], +["1yul",2,2.18534548283413], +["2fua",2,2.26831903877727], +["1r7l",2,2.63185845117582], +["1u5p",2,1.40832505613517], +["1row",2,2.29526987700946], +["1ppd",2,2.49497437826695], +["1ulx",2,1.79735280642974], +["1a7x",2,2.03970470126032], +["1eym",2,2.58092535828608], +["1rei",2,3.63467522034876], +["1qz4",2,1.90160770311576], +["1khp",2,2.27559182359306], +["1io2",2,2.21468144261932], +["1wcz",2,2.39446282412623], +["4cla",2,1.67308867840415], +["1vid",2,2.47493095659766], +["1am1",2,2.72665632965449], +["1b8c",2,2.58933848471713], +["1kg8",2,2.75084385384867], +["1mgy",2,2.13743295643365], +["1cpm",2,2.69282846766637], +["1gov",2,2.15561257855957], +["1goy",2,2.20211027924617], +["2apt",2,2.23533577424892], +["1h1d",2,2.29406129431856], +["1i6p",2,1.83951090571860], +["1dvp",2,2.82175672725419], +["1bhd",2,2.60777663999705], +["1aim",2,1.71159503725998], +["1ewl",2,2.07887120162009], +["1f2c",2,1.65097859613440], +["1ewm",2,1.85969043600804], +["2bdl",2,1.64401609763978], +["1sur",2,2.23853796659142], +["1xio",2,1.39425787424786], +["1meg",2,2.61403633512633], +["1vkw",2,1.82818735125511], +["1kea",2,2.18146575647093], +["2arv",2,2.8937290138175], +["1vc1",2,2.89371820154576], +["1dkz",2,1.95868924127934], +["1a7q",2,2.35774733157142], +["1zrm",2,2.19607693481428], +["1a7o",2,2.76876573195435], +["1ix3",2,2.02264618779700], +["1mw7",2,2.73646481181683], +["2cmk",2,2.75387538251706], +["1xw8",2,2.69431617333814], +["1e2x",2,1.87757887354216], +["2fdr",2,1.98025902475563], +["1bol",2,2.47262042915325], +["2rsp",2,2.36908568057363], +["1emg",2,2.29609688152178], +["1pts",2,2.83149582518391], +["1o3a",2,2.00760318356169], +["1tyn",2,2.00717319261268], +["1k1n",2,1.78517778040642], +["1jir",2,2.0911700933843], +["1k1o",2,1.93186854107581], +["1v2k",2,2.11300142653310], +["1eb2",2,2.18894172717645], +["1gbt",2,2.51838074243076], +["1j15",2,1.82335087976057], +["1j17",2,2.15402073463495], +["1emj",2,1.74928746976648], +["1og1",2,2.26382676438639], +["1dkx",2,2.44947212506907], +["1kpa",2,2.05336468635575], +["1kpb",2,2.08359050882829], +["1av5",2,3.03662996560902], +["2g16",2,1.34973831696243], +["1z1p",2,2.43351378570295], +["1ct5",2,2.02789662053389], +["1uj5",2,1.83649928221533], +["1btz",2,1.89171992845724], +["1a8v",2,2.78212609632972], +["1yoz",2,2.80989608763799], +["1srf",2,2.96627099829542], +["1bm7",2,2.34376297408478], +["1bmz",2,2.46666365339349], +["1qxt",2,1.44466270447019], +["1q7s",2,2.18509631459121], +["1dvq",2,1.37833048868763], +["1dvs",2,1.55041288591936], +["1dvx",2,1.68909942363061], +["1qy3",2,1.49079351134863], +["1dst",2,3.03383859004243], +["1iii",2,1.63644041207609], +["1p9q",2,2.40017981230976], +["1aol",2,2.52735028994035], +["2fiv",2,2.86809208860343], +["1j1t",2,1.98430989608357], +["1xcj",2,2.92171217869732], +["1xcl",2,3.02494517860283], +["1iau",2,3.01970108065868], +["1x42",2,2.30126820174989], +["1sh6",2,3.31589999202476], +["1m49",2,2.14414362781050], +["1pt0",2,2.26200900778486], +["1h9p",2,2.40993886994568], +["1ij8",2,2.48118122627805], +["1z5p",2,1.70335302130841], +["1xvh",2,1.83791591961320], +["1tha",2,2.93136257045868], +["2rox",2,3.07996507389531], +["1i4p",2,2.87153961858278], +["1swt",2,2.5210914941992], +["2cha",2,3.38815245548271], +["1sko",2,3.19288134567373], +["1wr2",2,1.97241345996906], +["1r6m",2,2.54616975750019], +["1ksk",2,2.27180729080967], +["1pob",2,3.07653037536904], +["1ghb",2,3.21157290015219], +["1op0",2,1.99238561072286], +["1qgs",2,2.23048806131548], +["1tl2",2,1.88803844943799], +["1qb8",2,1.71114985411760], +["1uns",2,2.57011564690106], +["1h7q",2,2.47992708918135], +["1g3q",2,1.55543857189355], +["2fda",2,2.09116586676216], +["2cna",2,4.39759824377401], +["1scr",2,1.88076095344830], +["1con",2,2.40262961402731], +["1dq5",2,2.50389018281849], +["1eem",2,3.47940702360087], +["1ohq",2,2.31820517977877], +["1za0",2,1.60713801906567], +["1zh2",2,2.40568299526701], +["1v13",2,3.01457677471187], +["1ste",2,2.39711222270439], +["1bm9",2,2.87105457334797], +["2ad1",2,2.86745099367774], +["1d9c",2,2.35219055294663], +["1pqf",2,2.06316261967713], +["1lte",2,2.15246544192719], +["2bsx",2,3.40241006546698], +["1iz4",2,2.84020014298356], +["1ji0",2,2.73535736387644], +["1eat",2,2.45034128679696], +["2fo9",2,2.03338822135362], +["1eau",2,2.56385932682010], +["2fod",2,2.23358827902409], +["2foc",2,2.15472537642844], +["2btn",2,2.33139480404862], +["1x7r",2,2.08825050239955], +["1gua",2,2.15396153945044], +["1jwi",2,2.40300495121786], +["1due",2,2.60500421961770], +["1dua",2,2.72160929734952], +["1tq9",2,2.89102485231981], +["1sd4",2,2.45577813738841], +["1gsl",2,2.18114874616666], +["1led",2,2.22230954399981], +["1lec",2,2.2479010373505], +["1jq8",2,2.66917612411495], +["1byf",2,2.14820968871066], +["1jb2",2,2.45610711020625], +["1p5x",2,2.22382254185579], +["1p6d",2,2.46089707821830], +["1sqa",2,2.60214038810029], +["1zv5",2,1.91997907598906], +["1urq",2,1.47489008389244], +["1dck",2,2.18691737226313], +["1ma3",2,2.18292248977863], +["1ahc",2,2.25409158259264], +["1mrh",2,3.21249409218984], +["1afu",2,2.40056442244692], +["1eos",2,2.3161432706058], +["1i37",2,3.15993181545469], +["1u1b",2,2.43293238295822], +["1b6v",2,3.09526681028859], +["1fx9",2,3.15698255597193], +["1do6",2,2.05303060423074], +["1vja",2,2.41086783441201], +["1i38",2,3.04670819199748], +["2arp",2,3.03979072967523], +["1jul",2,2.26775657283221], +["1a53",2,2.41630628531612], +["1igs",2,2.56984348485505], +["1ztd",2,1.77809302882113], +["1tw4",2,1.85613537323911], +["1h8x",2,2.41565392250024], +["1f9q",2,3.03424338492375], +["5csm",2,2.10312739781903], +["1if2",2,1.25854830528027], +["1ogx",2,2.74741519090239], +["1qds",2,1.55947095691647], +["1vc8",2,1.94598714717410], +["2f5n",2,2.30111016641106], +["1bz8",2,3.28497143108544], +["1ppe",2,2.40253418182310], +["2c4x",2,1.82473796791583], +["1qyu",2,1.93232709432797], +["1kyd",2,2.0174590901905], +["1coz",2,1.94159050087981], +["1xb8",2,2.24649573372821], +["2dnj",2,1.94254559845284], +["1wcx",2,2.42960721957056], +["1dtj",2,3.02343005453952], +["1j3m",2,2.86697633158864], +["2try",2,3.28940415754407], +["2f5p",2,2.10783553617476], +["1x25",2,1.55096988597765], +["1ky6",2,2.23815243314199], +["1vin",2,2.10741291915563], +["1f9r",2,2.93898837869656], +["1qi7",2,1.99046292084256], +["1rte",2,2.20425736317937], +["1hb8",2,1.67405806181514], +["1jvl",2,1.53943953481220], +["1hec",2,2.64438512296718], +["1hea",2,2.76319576623711], +["1es6",2,2.58232913274972], +["1rxz",2,3.30843403721196], +["1e3v",2,2.53411871372121], +["1hed",2,2.66603058730533], +["1heb",2,2.74023756142845], +["1n4l",2,2.75974533865121], +["1t74",2,1.93985307914750], +["1rcp",2,2.36888154033632], +["1lje",2,2.44830407688657], +["1lji",2,2.46869926805150], +["1lj3",2,2.55598784522265], +["1ljj",2,2.59989366275384], +["1uco",2,3.08939370450495], +["4yas",2,1.69305999971677], +["1cnw",2,2.36356348746402], +["1fql",2,2.52250279298493], +["3ca2",2,2.50654704963535], +["1ca2",2,2.39976891472727], +["1fqm",2,2.53087796578758], +["1hug",2,2.37925748155685], +["1crm",2,2.42419091020057], +["2cab",2,2.41418911914545], +["1i6j",2,2.48386599692512], +["3dni",2,2.40399014385272], +["1kcm",2,2.63820563459935], +["1f2l",2,3.40111364483019], +["1l2d",2,1.83751691235738], +["1y4y",2,1.61137239675987], +["1avn",2,2.44848065246424], +["1h4n",2,1.64667280659746], +["1zsb",2,2.18541833694982], +["1fqn",2,2.58235182998693], +["2abe",2,2.26309788227834], +["1hw3",2,2.40670841262289], +["1djc",2,2.89161073259805], +["1kge",2,2.39893112995964], +["3blm",2,2.72366807566452], +["1a8p",2,2.58997141003272], +["2ev5",2,2.01850462589754], +["1jxm",2,2.27654179777169], +["1ifs",2,2.34130276687937], +["1teu",2,1.99470483594456], +["1tbt",2,1.83665890379726], +["1teq",2,2.05155481868922], +["1tb0",2,2.03064148957608], +["1ugb",2,1.77022806152207], +["1te3",2,2.05629834895839], +["1t9n",2,2.17654023413895], +["1if5",2,2.2840555564792], +["1ze8",2,2.31195192138079], +["1i90",2,2.25665399146014], +["1i91",2,2.46132088865630], +["1azm",2,2.53757484458261], +["1if9",2,2.32486519231789], +["1fqr",2,2.93286747507279], +["1ugd",2,2.02680077128373], +["1ugf",2,2.07058005839800], +["1ugc",2,2.18668890809391], +["1uga",2,2.00436442062208], +["1zcu",2,2.15086446751649], +["1fvi",2,2.89641754779034], +["1pye",2,2.42889983972678], +["2d05",2,1.98163747628763], +["1puj",2,2.23457795550796], +["1rwn",2,2.42777531240188], +["1iyp",2,2.25070540621631], +["1esz",2,2.59084731781817], +["1xwy",2,2.3170107661036], +["1czm",2,2.79591684310180], +["1bzm",2,2.90225013759779], +["1y6o",2,2.00548576236619], +["1j1s",2,2.41148052531111], +["1xba",2,2.32518366946374], +["1skf",2,2.72251086108513], +["1c23",2,2.48894810860902], +["2bv1",2,1.54408441319876], +["1evg",2,2.17686376877557], +["1arc",2,1.91399018354270], +["1esu",2,2.43818882634577], +["1lhy",2,1.70721885830266], +["1axb",2,1.89681839806173], +["2gal",2,2.81389293555013], +["1hg2",2,2.99049716194875], +["1hf8",2,2.93005726589225], +["1hfa",2,3.0285457230276], +["1hg5",2,3.05194248643557], +["3mat",2,2.78658665468986], +["2a72",2,1.57165783425881], +["1bdb",2,2.13031947525931], +["1c8y",2,2.14836713775225], +["1ouv",2,2.60837167844095], +["1c8x",2,2.91064832441380], +["1q2p",2,1.89714236105158], +["5gal",2,3.07957652154129], +["1tqi",2,2.11095395745586], +["1nvq",2,2.37762658253301], +["1wzu",2,1.84629679771848], +["1dui",2,2.87706815235225], +["1lqo",2,1.94213250020394], +["1xbc",2,2.15470494868702], +["1a78",2,2.98565621119531], +["2bgm",2,3.20891019586764], +["2fs2",2,2.54154887331663], +["2b4l",2,2.21455136687504], +["1yze",2,3.48647433928263], +["1jea",2,2.21534842704306], +["2f93",2,1.49330489307426], +["1r78",2,2.20974661122148], +["1qpe",2,2.1443080856433], +["1v9o",2,2.17245267540677], +["2br1",2,2.47534049966971], +["1yvi",2,1.91570146174862], +["1drk",2,1.80944375789044], +["4mat",2,3.31747442593203], +["1qpd",2,2.14513235105338], +["1eg4",2,2.48665656934521], +["2ai1",2,2.05489876949254], +["1nkz",2,3.05491437754356], +["1wkj",2,1.65179419477918], +["1iuo",2,1.6609972573131], +["1i7p",2,1.77155290933686], +["1avt",2,2.45887028749801], +["1kr1",2,2.02336501551182], +["1aq1",2,2.60858629289924], +["1fy7",2,2.60766466160414], +["1sca",2,2.96017898649432], +["1ik6",2,2.47680792524747], +["2tdt",2,2.67397890243556], +["3tdt",2,2.44243648876826], +["1kgq",2,2.7174418034746], +["1af7",2,2.82361180970187], +["1md0",2,2.04266170535758], +["1mgp",2,1.93587615235333], +["1yxv",2,1.84777718303169], +["1ywv",2,2.00011690557013], +["1yxx",2,2.10789566715952], +["1yxt",2,2.46113836404206], +["1b6z",2,2.43717356991509], +["2plc",2,2.54598267521277], +["1st2",2,2.46097813679347], +["1ltv",2,2.24242999152517], +["1gii",2,2.75363792885104], +["1ga8",2,2.10557781221266], +["1g9r",2,1.99088354176789], +["1ke6",2,1.78372716524719], +["1pa9",2,2.70154904037007], +["1ke9",2,2.33001692989463], +["1ke7",2,1.70420136416577], +["1wmy",2,1.64549183331895], +["1b8n",2,2.4037113292272], +["1ke8",2,1.79070359782556], +["1bcu",2,2.30935815755864], +["1xjd",2,2.75086030410255], +["1z8j",2,3.01479945634938], +["1t4v",2,2.67010244637281], +["1t4u",2,2.80852946740445], +["1pzz",2,1.88172375894941], +["1mue",2,2.45670521708138], +["1nt1",2,2.33419811659427], +["1g37",2,2.38642554854385], +["1mu8",2,2.22051669109249], +["2byd",2,1.51261827084484], +["2fk8",2,1.58003761435813], +["2aao",2,2.4414722973877], +["1ad8",2,2.53628214286489], +["1d6w",2,3.36899725074094], +["1znj",2,2.66990655795936], +["1m4r",2,2.38074322214953], +["1eam",2,2.42770826233942], +["1a9q",2,2.31213937799092], +["1a9r",2,2.29934274703455], +["1zej",2,1.82805422852757], +["1ajz",2,2.66906212885314], +["1aj2",2,2.85287038378113], +["1aj0",2,2.94340229221861], +["1a9s",2,2.45354767632934], +["1h1w",2,2.23574218835601], +["1g30",2,2.73183008066206], +["1xi0",2,2.75380582925274], +["1ni9",2,2.15138368827043], +["1a9t",2,2.25722609476647], +["1nlk",2,2.14565862840907], +["1qiz",2,2.65235575782526], +["1k1k",2,2.65320303425596], +["2hbe",2,3.46195934375822], +["2mhb",2,3.15380520965693], +["1a4f",2,3.01465247841000], +["2nck",2,2.17269274831949], +["2ebn",2,2.52516880843429], +["1lpg",2,2.78661960798678], +["1mzg",2,2.70066288284324], +["1yq5",2,1.68084785263869], +["1psz",2,2.36815161652109], +["1hbt",2,2.27974318128691], +["1qz1",2,2.52268215538502], +["1z8i",2,2.76574211812466], +["1jwg",2,2.44060446216050], +["1ye5",2,2.20538511542009], +["1kwb",2,1.86579010602924], +["1kw8",2,1.63286051413670], +["1kmy",2,1.43871130788238], +["1t0j",2,2.11722453826159], +["5prn",2,2.02863396497848], +["1wde",2,2.8372368489684], +["1eiq",2,2.66424465319269], +["1eil",2,2.62594595576229], +["1eir",2,2.78721682141396], +["1a9o",2,2.76209624974075], +["1pbn",2,2.72341226422556], +["1j8y",2,2.37009419700146], +["1b38",2,2.63227108664606], +["3mct",2,2.44585108199989], +["1jte",2,2.49712631768673], +["1bky",2,2.45941728052928], +["1p39",2,2.56357865131381], +["1s3z",2,2.56296767168394], +["1xqw",2,3.11163973985188], +["1ldd",2,3.20803450848984], +["1txr",2,2.3848633464967], +["1bes",2,2.67818872326213], +["1ccc",2,2.04936574521129], +["1ccl",2,2.13227959617054], +["2erv",2,1.75202880448843], +["1c7f",2,2.44003695872461], +["1u2k",2,3.15116720597686], +["1lcy",2,2.76298300165364], +["1dse",2,2.44273863825438], +["1gsh",2,2.19758122436968], +["1ae8",2,3.16320695240515], +["1afe",2,3.20810188901917], +["1d07",2,2.77039635652237], +["1jbb",2,2.46914660574489], +["1csn",2,2.13838179637553], +["1mt3",2,3.33645482704837], +["1u32",2,2.32681333430198], +["1uma",2,3.16859388979015], +["2f4w",2,2.44674364972275], +["1iz8",2,2.6867744141375], +["1gd2",2,1.99102866808624], +["1krj",2,1.85643859380446], +["2b53",2,3.11788302117941], +["1j8m",2,2.78915403545588], +["1qur",2,2.99674255631281], +["2gno",2,0.888396566666415], +["1h73",2,1.81735250977848], +["1frn",2,2.81368463904397], +["1np8",2,2.34041072685041], +["1pvl",2,2.46604158230322], +["1iip",2,2.90833101056387], +["1t4g",2,2.35137446730802], +["1vjy",2,1.84781599523746], +["1sqh",2,2.91074886438802], +["2azr",2,1.30956242700037], +["1n2s",2,2.75929652388394], +["1z4e",2,2.05474453691938], +["1acb",2,2.83689542003778], +["1w94",2,2.5412209223419], +["1in5",2,2.02180417290216], +["1g1f",2,1.84758099269007], +["1sxs",2,1.92380524116899], +["1sxb",2,1.49489596589907], +["1cob",2,2.81875594754791], +["2a3h",2,1.61919108717323], +["2bx3",2,2.48195074776155], +["1qj1",2,2.90366123056536], +["1nlw",2,2.77423972962632], +["1jbu",2,1.85007831052055], +["1t9j",2,2.49598764273917], +["1rxw",2,2.23266495416561], +["1xew",2,2.82305687638678], +["1yjk",2,2.3351889503775], +["1ceq",2,1.96455318713324], +["2f6f",2,1.92359232333825], +["1nm2",2,2.08445088478183], +["1qoy",2,1.54524785518509], +["1hag",2,4.06019991011233], +["1myi",2,2.94489054573508], +["1ihs",2,2.19275691551253], +["1i72",2,2.00284100735366], +["1u4s",2,1.22854025457019], +["1elm",2,1.82498247999352], +["1cpx",2,2.04827137590714], +["1urv",2,2.62167117783472], +["6atj",2,1.46217305455755], +["1kzm",2,1.42442934682469], +["1ic2",2,1.98817694548983], +["1u98",2,1.80616976868897], +["1iy7",2,2.19459938806270], +["7cpa",2,2.78694078667932], +["8cpa",2,2.9655778808665], +["6cpa",2,3.03530135764977], +["1cbx",2,3.0443181990589], +["3cpa",2,3.08897667262381], +["1dmw",2,1.96121496857758], +["1n06",2,2.40543599384593], +["4pah",2,1.80764832865110], +["3pah",2,1.60939619094638], +["1mmt",2,1.84022874953566], +["1pah",2,2.44232653248214], +["1glg",2,2.45076021562556], +["2fpm",2,2.45423181706334], +["1i4a",2,2.29289783792344], +["1n0i",2,2.25098489779469], +["1mmk",2,1.96975406496973], +["1xiz",2,2.43014604716839], +["1mx6",2,2.48473850027945], +["1gia",2,1.33997751542034], +["2fyt",2,2.53896265768490], +["1obp",2,2.77507729702494], +["1ynr",2,2.27000798804262], +["1j01",2,2.0260494183022], +["2lig",2,3.01398256417575], +["1mx4",2,2.50832429988397], +["1hvf",2,2.55796146761617], +["1hvd",2,2.65084833587096], +["1svk",2,1.83349064170204], +["1as0",2,2.15774279223290], +["1dd3",2,2.94946967948234], +["1pnf",2,2.31885006128412], +["1gsa",2,1.98946421358219], +["1xlp",2,2.10918877316618], +["1z1y",2,2.29588652378677], +["1xf0",2,1.55197625192867], +["1zcb",2,2.07729359591027], +["1a77",2,3.67887819167768], +["1a76",2,3.71895455215739], +["1trb",2,2.90825912413066], +["1fjo",2,1.75106994469661], +["1fjv",2,1.73169842311800], +["1fj3",2,1.85812557147303], +["1fju",2,2.03379834863299], +["1ros",2,2.31314823869223], +["1qlm",2,1.91484731814681], +["2fe7",2,1.84778165647532], +["1s1r",2,1.71433236303269], +["1npc",2,2.49583254165761], +["1bsa",2,2.78113451400292], +["1zsz",2,2.09353234631892], +["1nij",2,3.40190608392594], +["1bnf",2,2.19531416319547], +["1bc0",2,3.22513249425979], +["3cms",2,3.12508217780281], +["1bsc",2,2.81565106636084], +["1brk",2,2.13599827179092], +["1zdr",2,2.84771462140617], +["1brj",2,2.38578559392515], +["3lip",2,2.01277150353806], +["1brh",2,2.37261771924243], +["1bsb",2,2.82079133948033], +["1bse",2,3.15463051992296], +["2fxf",2,2.54552397783432], +["1wq4",2,2.47131009673098], +["1gxj",2,2.51821734617173], +["2pia",2,2.32027739902654], +["1zcm",2,2.32354525016152], +["2aqw",2,2.4608710241732], +["1evx",2,2.04506907182481], +["1wq3",2,2.46047214055809], +["1x8x",2,1.82456943810585], +["1b21",2,2.48753071587231], +["2bcv",2,1.76569609153789], +["1b4e",2,2.26494776864678], +["1h44",2,2.51089361991974], +["1rtp",2,2.28370985944897], +["1pui",2,2.40377003637703], +["1lct",2,3.16727291706942], +["1eh3",2,2.14376137142612], +["1uh9",2,1.42877615949515], +["1m2p",2,2.22812673442929], +["1l97",2,3.80151050453908], +["2gao",2,1.4954444334847], +["1f3v",2,2.87507478007806], +["1psw",2,1.88957753639864], +["1i6i",2,2.74569686735644], +["1zyj",2,2.65093850741177], +["1lr4",2,2.47161305693372], +["201l",2,2.82304066370390], +["1gyn",2,2.03289078432652], +["1d4n",2,2.51193882025874], +["1nv3",2,3.00196986803003], +["1yxi",2,2.33988680760167], +["1pso",2,1.60214551004559], +["1pme",2,2.48497727385451], +["1eed",2,1.79476451653073], +["1fc3",2,2.84224504358552], +["6ldh",2,3.76500389437334], +["1i9y",2,2.77993338596551], +["4er1",2,1.79370876935145], +["1epo",2,2.74043428238407], +["3er3",2,2.86971337167095], +["5er1",2,3.21223800827805], +["1gew",2,1.99011162829694], +["1fpq",2,2.37601358140984], +["1tv9",2,1.74433778521130], +["1ge7",2,1.76129451119971], +["1qy7",2,1.88008745140054], +["1u90",2,1.93212265627166], +["2bos",2,1.44579248746891], +["1j33",2,2.17569738638528], +["1spb",2,2.96781744107718], +["4er2",2,2.33699763375385], +["1epl",2,2.72938017182979], +["1nhi",2,2.53861811182719], +["1ri6",2,1.82759954687782], +["1yv5",2,1.43217357361090], +["1g17",2,2.59133895733485], +["1xx6",2,2.14876531000828], +["2er6",2,2.95516825788933], +["2ae0",2,1.69409242307748], +["1smr",2,2.69821816980526], +["1xix",2,1.97112092063688], +["1zz2",2,2.70603677418037], +["1er8",2,2.45500715772701], +["1n2d",2,1.91034594534196], +["2b4b",2,2.79913157005054], +["1y4d",2,2.4213879664334], +["1mee",2,2.39624866895478], +["1slw",2,2.68823760536441], +["2b4d",2,2.80473263036083], +["1d1k",2,1.36458680161419], +["2gfo",2,2.18690368808476], +["1ljt",2,2.07614265595434], +["1nai",2,2.43177043877329], +["1mff",2,2.02188181722634], +["1icc",2,2.19786656227229], +["1ia5",2,2.37013651776919], +["2g5j",2,2.54079640696849], +["7wga",2,3.15889911942289], +["1l5m",2,2.26851522156004], +["1jhr",2,2.47241834736514], +["3tec",2,2.41197419265997], +["1mka",2,1.77984281778113], +["1mkb",2,2.11175820728034], +["1g7l",2,2.10109604138273], +["1knq",2,2.20227071199933], +["1cqr",2,2.45113773863356], +["1d7x",2,2.45930677155434], +["1cgq",2,2.03044966278787], +["1h7r",2,3.4451854284099], +["2cav",2,3.09773611661115], +["1x0a",2,1.69051885715091], +["1scj",2,2.63307219446933], +["1qno",2,1.56961071084325], +["1yht",2,1.94800173949954], +["1n0s",2,2.68944083861294], +["1s14",2,2.52923055270652], +["1nzu",2,2.64676398003625], +["1l5k",2,2.13417247214826], +["1jhu",2,2.62587443111772], +["1l4m",2,2.07498826733848], +["1jhq",2,2.57157250850558], +["1jhx",2,2.52971718618601], +["1jha",2,2.50430603456768], +["1jhy",2,2.59624786932934], +["1jho",2,2.66915252751159], +["1jhv",2,2.56017869363308], +["2scp",2,2.87791710419592], +["1lj0",2,1.91421843787773], +["1by7",2,2.59927586370219], +["1l4l",2,2.14040812275218], +["1l4e",2,2.39652585701790], +["1l5l",2,2.19370698802164], +["1l4n",2,2.3061092397547], +["2cwg",2,2.94339969110306], +["1aoc",2,2.99183290678156], +["1kir",2,2.82970816581362], +["1bht",2,2.99933540756168], +["1gox",2,2.83883258794283], +["1ndy",2,2.95352874430362], +["1ndw",2,3.3503082493659], +["1ndz",2,3.47811137318507], +["1r3c",2,1.99197535558660], +["1zz6",2,2.41151100177927], +["1qin",2,1.36940332717320], +["1hv6",2,1.82799507130569], +["1zzl",2,2.55540520622647], +["1nzd",2,1.87765231420703], +["1lqb",2,2.61284450928136], +["1kq0",2,1.80556658960480], +["1hur",2,3.35405814351761], +["1wbv",2,1.94379855354824], +["1wbt",2,2.31397088607776], +["1d6j",2,2.68971102365596], +["2b5v",2,2.31290235041398], +["2c1b",2,1.51490796216257], +["1sn7",2,2.73164026535179], +["1l3r",2,1.99668858316026], +["1ow2",2,2.69301414758984], +["1wdc",2,2.77985730438246], +["2ajg",2,2.30593728074592], +["1g0v",2,1.77623578640276], +["1yqj",2,2.86293500076416], +["1mpp",2,1.87078226331945], +["1mns",2,1.73577220170634], +["1mn2",2,1.94284923240490], +["1mn1",2,2.12039197106369], +["1q8t",2,1.7845672986692], +["1eus",2,2.69057778909198], +["1t0i",2,2.38944305258438], +["1apm",2,2.79594500138277], +["2b0m",2,2.35032871675347], +["1ue0",2,2.80053819624443], +["1obu",2,2.14994190203816], +["1gl4",2,1.88763534336798], +["1o7k",2,1.92297785197403], +["1pjc",2,2.94640754414041], +["2fc1",2,2.69287448152278], +["1a6q",2,2.56124183441089], +["1gvq",2,2.40043281466420], +["2bm5",2,2.18725906855026], +["1djl",2,2.17254948238912], +["1wop",2,2.25016645707592], +["4thi",2,2.25561734145487], +["3thi",2,2.15610133170263], +["1nx1",2,2.48666873333035], +["1z2w",2,2.73842063656351], +["1ald",2,3.70404299895978], +["1ul3",2,2.31286398961626], +["1zop",2,2.60764317768703], +["1s12",2,2.84133854163468], +["2b9l",2,2.53501753224285], +["1np1",2,2.75806935607571], +["2np1",2,2.96863599691141], +["1sgm",2,2.85713270875514], +["1gp1",2,2.18844923157596], +["1wmx",2,3.25185340064484], +["1n8o",2,2.39748492942466], +["1mos",2,2.03790727943790], +["1vpk",2,1.76715006592048], +["1yd6",2,2.08328396205658], +["1ke2",2,2.13888259677341], +["1hru",2,2.53603663248783], +["1fnf",2,2.87103079683076], +["1r5g",2,2.61703744269947], +["1vjn",2,1.87997223144279], +["1jw5",2,2.48064914891038], +["1jw4",2,2.44923324881785], +["1hix",2,2.79351074333359], +["1mpb",2,1.77129863051384], +["1zjl",2,2.06461576224072], +["1ziu",2,1.93888766067419], +["1q43",2,1.95373449822147], +["1xmb",2,1.61740214105276], +["2g3b",2,2.02649354714164], +["1efz",2,2.31930392875196], +["1qlp",2,2.54943752394323], +["1d2o",2,3.2689831285589], +["2fez",2,1.9334803868674], +["1ac1",2,1.70136210151754], +["1dyk",2,2.62104643404651], +["2gc0",2,1.78422004126543], +["1dsb",2,2.20430984723463], +["1r1u",2,2.89710673325171], +["1lg9",2,2.33849072494210], +["1xbf",2,2.43686008084321], +["1uw8",2,1.22346429648039], +["1sul",2,2.43880970212445], +["2ex1",2,2.48169821247476], +["1pbw",2,3.00974983728113], +["1ok8",2,2.73758067100583], +["1fbt",2,2.86003218748909], +["1p18",2,2.54284374309351], +["2bvq",2,2.45536160286877], +["1t1y",2,2.10917162996142], +["1a1n",2,2.40123322033963], +["1qc5",2,2.11215050159838], +["1juf",2,2.60519903776316], +["1mp9",2,1.85097188513502], +["1vfh",2,2.79178445292826], +["1bay",2,2.03234670095337], +["2axg",2,2.21261799202960], +["1k5u",2,2.37987330295873], +["2bss",2,2.06581618772576], +["1u77",2,2.48780705939877], +["1dj9",2,3.15895942896560], +["2bi7",2,1.97207210910677], +["1b9i",2,2.60699548404305], +["1b9h",2,2.53559385838341], +["1w2h",2,2.22770560428865], +["1fc7",2,2.71744293791019], +["1eay",2,3.57281066501062], +["1q5u",2,2.04080510999352], +["1v5c",2,1.91946744666236], +["2bat",2,2.89959261299255], +["7nn9",2,2.12592610674792], +["2qwd",2,2.16266534783897], +["2qwb",2,2.27600798390948], +["1bji",2,2.31621301346532], +["2qwe",2,2.19147069482675], +["2qwj",2,2.36703780629044], +["2qwi",2,2.40456804173851], +["1uut",2,1.59423176966356], +["2awp",2,1.45889345335396], +["1cc4",2,2.08701141893520], +["1bgn",2,1.87424164827896], +["1woc",2,3.06385946189482], +["1iut",2,1.9460040371352], +["1iux",2,2.18423034466498], +["1iuw",2,2.13609650936617], +["1iuu",2,2.05155336404815], +["1doc",2,2.14377257760061], +["1dob",2,2.25034243839342], +["1k0l",2,2.06923698321054], +["1io1",2,2.89701879835004], +["1toe",2,2.52177435830084], +["1spa",2,3.24249021946753], +["1g4v",2,3.38055052335124], +["1z05",2,1.66231387905291], +["1c5k",2,3.09592762020227], +["1v5x",2,2.82044207755127], +["1vpe",2,2.2813585530561], +["1oyc",2,2.65135674216660], +["1ulw",2,1.97959009870680], +["1rom",2,2.34696791142960], +["2rom",2,2.18744864520632], +["1dfa",2,3.56349313143762], +["1a94",2,2.83934552348878], +["1a8k",2,3.50853793288388], +["1jip",2,2.54241252519678], +["1o63",2,2.31553556597358], +["1vra",2,1.51778869767102], +["1pca",2,2.89568268682914], +["1dth",2,2.71428873907387], +["1znv",2,2.20252369927517], +["1z8q",2,2.36446284754472], +["1wpo",2,3.29486307830666], +["2au3",2,2.01989881899196], +["1iz6",2,2.7106873739822], +["2a8a",2,2.07507665742029], +["1rp8",2,1.52859666422678], +["1rp9",2,1.67539327981064], +["1rpk",2,1.77674785849088], +["1p6w",2,2.02237851095647], +["1kmj",2,1.56318470391928], +["1yjs",2,2.35793954057139], +["1jf9",2,1.58912945354971], +["7cpp",2,2.34217869791735], +["1gem",2,2.51176539541291], +["1iwi",2,2.45466426984167], +["1iwj",2,2.44506529994738], +["1iwk",2,2.49593249484385], +["1wht",2,2.74347686242399], +["1s96",2,2.42735682909058], +["7fab",2,2.47416898877674], +["5hoh",2,1.52893800750225], +["1qh6",2,1.68443492004964], +["1w7l",2,1.98842442012961], +["1ng5",2,3.44896043966664], +["1hj6",2,2.87088026673228], +["1o20",2,1.41998946958922], +["1jra",2,2.19610763966355], +["1lh0",2,2.33878210549677], +["1rmq",2,2.19360441634374], +["1zvi",2,2.85545571409188], +["2bam",2,2.86436037120178], +["1pn9",2,2.35727239076218], +["1kbn",2,2.49778806808788], +["1ieg",2,2.59240959653414], +["1mfe",2,2.50194811296924], +["1qi4",2,2.70413074025465], +["1qpk",2,2.70986730330155], +["1qi5",2,2.68181289472681], +["1qi3",2,2.65735586413699], +["1yun",2,3.18407532195257], +["2btw",2,2.87157645960975], +["1bqu",2,1.97804640681900], +["1uax",2,2.51923742575692], +["1edh",2,1.65438247631353], +["1vag",2,2.854158866516], +["1ied",2,2.79174222857482], +["1rmg",2,2.23263534968454], +["1t2p",2,2.94538525896497], +["1s1q",2,1.94025940756478], +["1q0y",2,2.08270482403316], +["2bab",2,1.40420862649531], +["1gv3",2,2.06383417281089], +["1p9b",2,2.60875614027661], +["5fwg",2,3.76487824731238], +["1ank",2,3.38090074046814], +["1l2l",2,2.86095625378776], +["1bm3",2,3.74657563397140], +["1v4a",2,2.25129339310137], +["1kp2",2,2.33131163414745], +["1hav",2,2.64366949836132], +["35c8",2,2.69009358779979], +["25c8",2,3.19780577496467], +["1uet",2,2.62594609212087], +["1rz7",2,2.12365849303911], +["1ugq",2,1.65168943098079], +["1ugs",2,1.77288222702673], +["2bre",2,2.14631524124720], +["1ueu",2,2.77303817790288], +["1mz8",2,2.31945729328678], +["1k97",2,2.09308199046219], +["1ylu",2,1.64506019543770], +["1gd7",2,3.02164640617722], +["2mcg",2,4.59949689636806], +["3mcg",2,4.82618799253412], +["1d5i",2,2.9648815187155], +["1d6v",2,3.17756902489110], +["1d7r",2,3.05299342460399], +["1zc9",2,2.22267875317213], +["1m0q",2,2.64203394669351], +["1ia7",2,1.67203261944912], +["1qf5",2,2.28345684038267], +["1idt",2,2.4070516811063], +["1dd6",2,2.48648331787115], +["1npz",2,2.13402935239224], +["1t3f",2,2.13390754873762], +["1v5z",2,2.21492481962153], +["1bif",2,2.33197274069987], +["5gst",2,3.25145091281622], +["1uan",2,2.19509856582151], +["1lv0",2,2.29207113886952], +["1h1b",2,3.01087409363727], +["3cel",2,1.60030533688385], +["1riu",2,2.00295079759466], +["2bfk",2,2.33069695404890], +["1cr9",2,2.31862468750355], +["1mxd",2,2.20467151100398], +["1nbv",2,3.90665654654895], +["1kp3",2,2.28327085968415], +["1bl3",2,2.79658588153087], +["2cts",2,3.17559916497723], +["1vge",2,2.93102310164640], +["1r8b",2,2.24571853701377], +["1eo9",2,2.54488188557611], +["1pkw",2,1.78216564801166], +["1xd5",2,2.36206410683902], +["2aor",2,2.32758740108194], +["1yeg",2,2.66576439794622], +["1yef",2,2.73779097259638], +["1wl6",2,1.18600990063851], +["1f3b",2,2.48382701566994], +["1sbs",2,2.60918919733242], +["1gse",2,2.21884025878340], +["1u8i",2,2.70518085649489], +["1tqx",2,2.30381486527865], +["1v9a",2,2.06317292696517], +["1diw",2,2.94093889877908], +["1vav",2,2.80716621659288], +["1kwx",2,1.77995339213312], +["1kwv",2,2.00716025898739], +["1kx0",2,1.9989472009364], +["1kwy",2,2.05801224228372], +["2kmb",2,1.77105456935271], +["4kmb",2,1.80904938284018], +["1eke",2,2.47009782901922], +["1sws",2,2.66906001346281], +["1mzh",2,2.56641466808468], +["1qja",2,2.3811952252625], +["1ff9",2,2.80808237008355], +["1tj1",2,1.98416518858727], +["1kdn",2,2.29495258194086], +["1hmd",2,1.94303067133075], +["1hmo",2,1.97376824271169], +["1nhp",2,2.06088831405955], +["1nhq",2,2.12081911288074], +["1e4i",2,2.73204247965563], +["2f5b",2,2.84809756280028], +["1aqh",2,1.76757503528010], +["2fea",2,1.87537167648436], +["1uzl",2,2.78759517721759], +["1ucn",2,2.51386168338993], +["1gef",2,2.49321071193355], +["1qcf",2,2.66245282961207], +["1swj",2,2.95665491931267], +["1vcv",2,2.30519252350197], +["1v6z",2,1.99673839695584], +["1s4v",2,1.5324537094103], +["4gep",2,2.3887666212544], +["1f58",2,2.18482654272528], +["2bj4",2,1.9469017218235], +["1goz",2,2.59972055493845], +["1r9o",2,2.86914424037572], +["1pii",2,2.72966027907994], +["1dsu",2,3.15910329979716], +["1s53",2,2.50780149599925], +["1kme",2,2.45939055540394], +["1s51",2,2.9027083936061], +["1v9k",2,2.79406374392993], +["1z5z",2,2.82329275593804], +["1tjg",2,2.06300094476027], +["2fkf",2,1.72245692503444], +["1az0",2,2.17804844153135], +["2c1n",2,2.78473270868447], +["1bgb",2,2.8102237034197], +["1k7g",2,1.48648713342903], +["1tiw",2,1.93479901456239], +["1bsu",2,2.59633621235049], +["1v57",2,1.62493828382408], +["2bmi",2,2.15107486305935], +["1h9w",2,2.30524187294259], +["1pcj",2,1.95060594067450], +["1tv2",2,1.98922601663892], +["1ra6",2,2.40001299533098], +["1f83",2,3.29478425833305], +["1wvv",2,1.26146561426160], +["1afa",2,2.0508331322258], +["1afd",2,2.36243089727336], +["1bch",2,2.24981835682], +["2bzs",2,2.32501247321169], +["1mu5",2,2.71570925960368], +["1rt8",2,2.36525170753376], +["1go8",2,1.63155702515052], +["2f6x",2,2.15146743945954], +["1xan",2,2.10485385219651], +["1grg",2,2.3951451843377], +["1grf",2,2.42986989088812], +["1gra",2,2.39948256537948], +["1gre",2,2.48204670541943], +["1swk",2,2.4279421607189], +["1swp",2,2.53806199717569], +["1nqb",2,2.13115881825006], +["1dqt",2,2.47059223570715], +["1sh5",2,2.49275884100541], +["1nc1",2,2.4182647947852], +["1z5o",2,1.97667075715408], +["1lx7",2,2.01263929685988], +["2b0d",2,2.84308039831376], +["1qjb",2,2.98958466886095], +["1u5k",2,2.44753071037633], +["1n7k",2,2.15496447835540], +["1dek",2,2.72247602536732], +["1p27",2,2.92584791616619], +["2be6",2,2.34844573094733], +["1eo3",2,2.61064458518928], +["1srp",2,2.67873848098285], +["2arz",2,2.42136303624116], +["1q5x",2,2.29607990057727], +["1akl",2,2.57926471695967], +["1rqh",2,2.23332546221994], +["2fno",2,1.59481648177710], +["1gah",2,1.49514490749310], +["1rr2",2,2.25426616287113], +["1fs9",2,2.27908958435919], +["1swf",2,2.51470266306228], +["1gic",2,2.73433589124521], +["1rrk",2,2.31763443829748], +["1w1s",2,1.95265499968612], +["2pgd",2,2.55941579071625], +["1yf9",2,1.70681066342432], +["1y89",2,1.48460787991058], +["1o0w",2,2.12486168175094], +["1m85",2,1.66076874083017], +["1e93",2,1.88870798452764], +["1uzy",2,1.94587975377760], +["1qmp",2,1.85973155572805], +["1esv",2,3.31325375650980], +["1geq",2,2.66364957895526], +["1n3o",2,1.75969280158236], +["2ff3",2,1.93967002220870], +["2f7f",2,2.03318703040341], +["1r1d",2,1.4994543854534], +["1u9m",2,2.23260381886617], +["1g13",2,2.18537173268775], +["1c7i",2,2.49525263869295], +["1hvx",2,1.77588598346891], +["1rw0",2,2.36607775214516], +["2fkb",2,2.18868528881228], +["1n4a",2,2.25185650326277], +["1rva",2,1.86927042311474], +["2ag2",2,2.13701065300578], +["1v03",2,2.46566287251625], +["1k4e",2,2.45696139114422], +["1p15",2,3.9250288012823], +["1tjj",2,2.09048703113209], +["1n5b",2,2.28568831849241], +["1u7e",2,2.44212917680559], +["1n2z",2,1.97074898343908], +["1pqk",2,2.68574234129336], +["1c0g",2,1.46856255877928], +["1oe4",2,2.07394683896410], +["1nxz",2,2.82972481210608], +["1fof",2,2.03687769305359], +["1q6g",2,2.30047766209774], +["1q6d",2,2.41861435207027], +["1y3p",2,2.50566332811162], +["1dqk",2,2.30865048010733], +["1mfu",2,1.77480172201719], +["1btc",2,2.68614579195528], +["1ilv",2,2.74783312223369], +["2fu5",2,2.26647036050785], +["1h8y",2,2.46838632174792], +["1kwh",2,2.50836352282085], +["1g2i",2,2.19127661834066], +["2awh",2,2.37344497018657], +["1ci1",2,2.41294501791737], +["1kgu",2,2.36610037857536], +["1mfv",2,1.74174778614456], +["1xd0",2,1.73767854117732], +["1bsi",2,2.13804050085583], +["1xh0",2,2.18621448994155], +["1cpu",2,2.17239350901111], +["1xcw",2,2.14957551942688], +["1xgz",2,2.25377985890908], +["2cpu",2,2.38447852814360], +["3cpu",2,2.65828275697562], +["1kgx",2,2.72219297081685], +["1z0u",2,2.62163004496591], +["1u46",2,2.06222253629885], +["2g7c",2,2.15513752705558], +["1xt8",2,2.10760055068811], +["1sux",2,1.76475906800812], +["1t44",2,2.02973294298932], +["1n1d",2,2.51465266964005], +["1g73",2,2.7249247223017], +["1dwf",2,1.76349149030026], +["1dwg",2,1.76349149030026], +["1dwh",2,1.76349149030026], +["1dwi",2,1.76349149030026], +["1cwy",2,1.74954719838517], +["1woy",2,2.6145441788088], +["1a8h",2,3.09008360152503], +["1r0s",2,2.07649927618702], +["1r16",2,2.03085299130249], +["1zuc",2,1.95821966966512], +["1clv",2,1.67608313793623], +["1lbw",2,3.17919212027666], +["1w6l",2,1.65116165280999], +["1h5y",2,1.84744613576004], +["1te5",2,3.11929873794065], +["1ezl",2,3.58068215508927], +["1e5y",2,1.88878358238659], +["1e5z",2,1.99992688630160], +["1dpe",2,2.54191839363404], +["2afg",2,3.26038324034748], +["1g8z",2,1.93877111728688], +["1eei",2,2.08082819002200], +["2chb",2,2.42859498874712], +["1d2z",2,1.42449762067186], +["1chp",2,2.59168709801133], +["1zy5",2,2.58320198380236], +["1eb4",2,2.55359956173578], +["1c14",2,2.63666640963306], +["1i36",2,2.40047213892244], +["1mbl",2,2.76179380861927], +["4blm",2,2.94325456274999], +["1czy",2,2.49773630935487], +["1fto",2,2.27459434333142], +["1fsn",2,2.74124828592765], +["1p1u",2,2.06208125327874], +["1fsq",2,2.88729819326227], +["1fsr",2,3.18862278194939], +["1lci",2,2.05586507258434], +["1j18",2,2.09081658933972], +["2b50",2,2.29073842710881], +["1knc",2,1.81356333307415], +["1b3h",2,1.87612765713481], +["1b7h",2,2.35557293491775], +["1wmb",2,1.8254586602157], +["1b05",2,2.15312388631775], +["1b3g",2,2.02530249690842], +["1p0i",2,2.42738842285501], +["1wdj",2,2.34505791023858], +["1hyu",2,2.24401996860575], +["1ddt",2,2.75217101571654], +["1f4f",2,1.94646207804165], +["1f4c",2,2.08526078045244], +["1qci",2,2.70282243796045], +["1g0n",2,2.44803072271665], +["1jg0",2,2.51328886792983], +["2b1e",2,1.83133995866706], +["2bsz",2,2.52941368398448], +["1v0p",2,2.59611632584792], +["1hy2",2,2.47936741736358], +["1l1e",2,2.83662217783389], +["1syn",2,2.74348144454924], +["1gcw",2,3.02097971808271], +["1k4c",2,2.08962092974739], +["1zlj",2,2.12795458843691], +["1p42",2,1.93970877842242], +["1ekk",2,2.33057211674726], +["1fgk",2,1.6505952101151], +["1k3d",2,2.64542861960447], +["1k3c",2,2.49475143192431], +["1tws",2,2.17095360885842], +["1qa1",2,1.74228461373343], +["1qa2",2,1.76126201821005], +["1qa3",2,1.73308834326629], +["1x6n",2,1.78639019034049], +["2a5t",2,2.37423296245672], +["1clw",2,1.72339202362164], +["1qrb",2,1.80544608199442], +["1tsp",2,2.37561132028884], +["2nsy",2,1.86596956871150], +["1nqe",2,2.91312120132694], +["1sel",2,2.08982076062417], +["1sbk",2,2.35196178625013], +["1gcv",2,2.76432546393351], +["1uxe",2,2.13534953069912], +["1yvx",2,2.43823155419245], +["1r5t",2,2.24461657957239], +["1vky",2,1.60558348269231], +["1dqj",2,2.59715715238707], +["1l5x",2,2.69678821658238], +["1g2w",2,2.01908485125720], +["1ia9",2,3.05244041531511], +["1icf",2,2.69766680571433], +["1iqd",2,2.56653408015425], +["1xml",2,2.31394078769406], +["1wiw",2,2.14432239056064], +["1hzw",2,2.25310796310021], +["2c2x",2,2.53961813915624], +["2for",2,1.71632460921935], +["1h0d",2,2.55118962279489], +["1zc3",2,2.77842650395924], +["1uok",2,2.86261354302099], +["1wg8",2,2.86648673421339], +["2dab",2,1.82724670470817], +["1a0g",2,1.97764600577642], +["1de7",2,1.97821770037141], +["3rub",2,3.0994720909615], +["1pzx",2,2.58731739394803], +["1wgj",2,1.74807635918162], +["1rif",2,3.05421514386995], +["1g7t",2,3.15496647037827], +["2b7a",2,1.75795327624949], +["1o1k",2,1.63198864917567], +["1v4u",2,2.78490546925341], +["2fh7",2,2.03094662486422], +["1xz4",2,1.86578850098665], +["1y4f",2,2.05988955756295], +["1y45",2,2.04992608142529], +["1yih",2,2.52401030888508], +["1gbv",2,2.82348903860525], +["1j7w",2,2.51481596662547], +["1a0z",2,2.32246153716599], +["1a00",2,2.31617468253241], +["6hbw",2,2.32266447758355], +["1g7s",2,3.2505123759657], +["1dan",2,2.25987704098596], +["1vzt",2,2.01790344503912], +["1n2h",2,1.85873268521668], +["1jc4",2,2.14647631295394], +["1o86",2,2.09281471277971], +["1o8a",2,2.13882223578297], +["1uzf",2,2.10944333233030], +["1sr4",2,2.10235936814156], +["1d3y",2,2.49425169730616], +["1brs",2,2.5842121805608], +["1s2u",2,2.36767890794655], +["1p2o",2,1.81718043223936], +["1ts3",2,1.99624345472596], +["1d5z",2,2.39352161032766], +["1rj4",2,2.16766107156631], +["1a96",2,1.80567784263949], +["1s2t",2,2.17985503048594], +["1njy",2,1.76280718770009], +["1ua1",2,1.83472889877831], +["1njz",2,1.80720241710117], +["1nkb",2,1.89754399424400], +["1u47",2,1.80076017987774], +["1kuj",2,1.93385671204915], +["1d5m",2,2.34704144229354], +["1yxd",2,1.78695691858830], +["3had",2,2.28364089200417], +["1i8d",2,2.86487183096782], +["1it6",2,2.28274064159407], +["1z6j",2,3.03821112925944], +["1n3f",2,2.61529235776383], +["1wsi",2,2.58429414812754], +["1qya",2,1.60142305922866], +["1v9b",2,1.99400176827919], +["2b3j",2,2.34123208356282], +["1apy",2,2.11534605435053], +["2bw3",2,1.97774261243210], +["1mej",2,2.10075712007079], +["1qga",2,2.56505590762216], +["2sod",2,4.52968884154885], +["1xtl",2,3.14174037394901], +["2a8l",2,2.14591227436004], +["1m9c",2,2.21730957558315], +["1wyk",2,2.15169941943891], +["1fmt",2,2.65200771921526], +["1aq0",2,1.51691873623540], +["1srd",2,3.68928593855065], +["1xxr",2,1.99089916642917], +["1pev",2,2.27120042748339], +["1wof",2,2.26633489325678], +["1wra",2,2.39294319231446], +["1mki",2,2.66906644518475], +["1yw4",2,2.91476635264876], +["1dlm",2,2.7474474700044], +["1he1",2,1.40810020883023], +["1uir",2,2.64539851868892], +["1dor",2,1.72421083984264], +["2dor",2,1.96407197134030], +["1el6",2,1.82561836318028], +["1ty2",2,2.55798833051042], +["1z82",2,1.89550489366671], +["1kie",2,2.61250030191511], +["1lld",2,2.94329742738648], +["1fns",2,2.27946364498578], +["2ew2",2,1.84980124058273], +["1u24",2,2.61283640590047], +["1mwm",2,2.93344677812555], +["2awd",2,1.93597659307803], +["1mvy",2,2.03685866256106], +["1mw3",2,2.12773270643541], +["1jgi",2,2.11461061124544], +["1fbw",2,1.55384358831231], +["1fce",2,1.62080669391995], +["1cm4",2,1.5892190434829], +["1hn9",2,2.22024388071759], +["1kz8",2,2.45069461075665], +["1bre",2,3.93811708859716], +["1a5b",2,2.60446836343139], +["1eun",2,2.43417035043999], +["1cun",2,2.40631146411805], +["1frp",2,2.24855895432612], +["1uh2",2,2.45722415449534], +["1qic",2,3.1785426072914], +["1v3u",2,1.86012890975858], +["1tki",2,2.27995072411534], +["1ttq",2,2.72935998388296], +["1qia",2,2.48958049484741], +["1xo0",2,3.28299973799857], +["1pv9",2,2.58276869302821], +["1w89",2,2.19581128496612], +["1yr0",2,1.99193147101391], +["1ylk",2,1.72752553700535], +["1cw2",2,2.64360989550332], +["1tkl",2,2.52390837074477], +["1t9s",2,1.69256197375615], +["1iz9",2,2.01859543404695], +["1wzi",2,2.21200186400376], +["1wze",2,2.17700621670097], +["1xkw",2,1.98442905417525], +["1s4b",2,1.92106961348418], +["1psc",2,2.41557718514607], +["1p6c",2,2.72886609243703], +["1djo",2,2.29735903619539], +["1dc6",2,3.24675714470985], +["1dc5",2,3.40096487410836], +["1szw",2,2.24263581119692], +["1zba",2,2.99494607465593], +["1v3v",2,1.84091831206927], +["1kmo",2,2.61046663423303], +["2a67",2,2.44262406368272], +["1p6x",2,2.21499047116133], +["9ldt",2,3.29797094540526], +["1crw",2,2.19854782627473], +["1szj",2,2.33159930631538], +["1jc0",2,4.06688969285687], +["2ahb",2,2.58068516595741], +["1uoe",2,2.19814587757668], +["2a8i",2,2.33015966249649], +["1h3j",2,2.10219219445886], +["1jdz",2,2.36240965532343], +["1ly9",2,1.81941153324582], +["1lyk",2,2.00760076975368], +["1fm2",2,2.09030512924034], +["1mqr",2,1.89287147999159], +["1yga",2,2.34957982526832], +["2d1i",2,2.7715596157592], +["1ror",2,2.1821464049863], +["1hmu",2,2.30862325512609], +["1hm2",2,2.33247188384080], +["2c6c",2,2.13872951333676], +["1ib4",2,2.69014513536815], +["1b43",2,2.87088479678664], +["1jdt",2,2.45792742567756], +["1pim",2,2.49528330857682], +["1sli",2,2.30680706550867], +["1sll",2,2.4908746284873], +["1rsr",2,2.27944880367888], +["1y79",2,2.77221361361841], +["1ujm",2,2.13521013665599], +["1cgt",2,2.15441019736229], +["1b57",2,2.31229178845332], +["1eo5",2,2.25132531439802], +["1ot1",2,1.47716384634515], +["1pj9",2,1.69358562974959], +["1cdg",2,2.50160942289687], +["1bbp",2,2.52113021239555], +["1ro6",2,2.30782072336051], +["1lcf",2,3.55736825195554], +["1cb6",2,3.06117521702547], +["1sst",2,2.64648205502558], +["1x80",2,2.03925130382673], +["2b4i",2,2.57098614746436], +["1yv3",2,1.61284404830440], +["1dzb",2,3.36191198965103], +["1icq",2,2.26461492105588], +["2fna",2,1.74616608518309], +["1v1m",2,1.72516418171750], +["1q8i",2,2.77837172590906], +["1wiy",2,1.79694890335705], +["1nwh",2,1.99631005641983], +["1d8c",2,2.53014637930721], +["1iel",2,1.99240111993536], +["1pw7",2,2.61527927079786], +["1yrr",2,2.16436762570339], +["1qfs",2,1.87303169741084], +["1a05",2,2.50497505604454], +["1sbz",2,2.38961208602002], +["2bls",2,3.51584155278478], +["1hrk",2,2.33938907541504], +["1mzc",2,1.97102524014966], +["1ld7",2,2.09898936954929], +["1fr1",2,2.82018218571137], +["1cdk",2,2.65992026951229], +["1f9g",2,2.93967273378344], +["1loh",2,2.98713342591317], +["1io8",2,3.37645332241164], +["1w9j",2,1.22285941666188], +["1eg5",2,2.23897822551770], +["1cb2",2,1.77286303337389], +["1qk2",2,2.14249411454654], +["2c59",2,2.01625015164687], +["1w19",2,1.99577937110685], +["5bj4",2,2.32085153186487], +["1q45",2,2.39852379222598], +["1d1b",2,3.44886150172565], +["1lt4",2,2.02692451393971], +["1lt3",2,2.10509970486834], +["1u5u",2,2.03053577877869], +["1jcr",2,1.80483740732723], +["1got",2,2.67466026556641], +["1kvo",2,2.59748778530613], +["1d0x",2,3.15644534106429], +["1d0y",2,3.31213411150568], +["1d0z",2,2.81850197301251], +["1tvf",2,1.94600986051225], +["1mmd",2,2.87238172156535], +["1d8d",2,1.97748664233162], +["2avt",2,2.48216573760210], +["1po9",2,2.3654628295781], +["1kz1",2,2.30490858884508], +["1d1a",2,3.53544111038542], +["1wsr",2,1.56910435808370], +["1c3r",2,3.05411226433178], +["1u3a",2,2.65869687532439], +["1m6h",2,1.79549884960092], +["1fwi",2,2.11012432156011], +["1fwf",2,2.12927725537598], +["1fwe",2,2.32380226287281], +["1ht0",2,1.91287555854617], +["1a71",2,2.29385968542072], +["1ju9",2,2.11482694817456], +["1axe",2,2.3965565237957], +["1r6u",2,2.76523050831224], +["1ejr",2,2.15469695424757], +["1eju",2,2.18316305668192], +["1cfm",2,2.55247189906457], +["1bf2",2,2.33625107347829], +["1vgm",2,2.2583820279637], +["1ci8",2,2.22463939125394], +["1kx3",2,2.23135756370120], +["1fnn",2,2.25551370833961], +["1amj",2,2.35764949292056], +["8acn",2,2.42247793019893], +["1ami",2,2.43720635644527], +["7acn",2,2.46547127551420], +["1wbz",2,2.51722687176278], +["2bnl",2,1.64489255636243], +["1l6f",2,2.23956927130892], +["1l6g",2,2.49757496089794], +["1h2g",2,1.74270801137674], +["2clr",2,2.54886924410592], +["1t0m",2,2.45645390112118], +["1fwd",2,2.13967894774662], +["1fwc",2,2.19371276644404], +["1fwa",2,2.18683066135529], +["1fwb",2,2.18683066135529], +["1ejs",2,2.13276728737228], +["1ejt",2,2.17130125401815], +["1fwg",2,2.12409566050398], +["1fwh",2,2.21491990749105], +["1gm8",2,2.17439476637852], +["1a5m",2,2.17761395658287], +["2kau",2,2.24036397004431], +["1wkv",2,2.12505379253993], +["1ha3",2,1.90496048004033], +["1h65",2,2.07605656952175], +["1y8t",2,3.43622945009996], +["1n2t",2,2.09746695785557], +["1eli",2,2.08190932842317], +["1el9",2,2.18195447640315], +["1mbm",2,2.24955560871152], +["1mxx",2,2.01684787939854], +["1p1q",2,2.47551523844266], +["1ku0",2,2.27854538259687], +["1d6i",2,2.28872435052680], +["1ybq",2,2.64587368689351], +["1v7x",2,2.02070735086479], +["1e18",2,1.69679503938244], +["1tpz",2,2.57507781613503], +["1ykj",2,2.91104865742901], +["1ll7",2,2.34279838638538], +["1g38",2,2.37711762683559], +["2fyd",2,2.20454651143626], +["1nmm",2,2.52271979788089], +["1nf5",2,2.58395908070465], +["2fyc",2,2.53566208351625], +["1nqi",2,2.71031613288483], +["1nkh",2,2.844297319554], +["1ids",2,2.26579444725383], +["2b8t",2,1.45572212259715], +["1i80",2,2.35447294955295], +["2ubp",2,2.1718173140676], +["3ubp",2,2.21240150977076], +["1w9v",2,1.61158307642422], +["1y5y",2,2.29472311925072], +["1ahx",2,3.33363040634431], +["1kkc",2,1.89503571200080], +["1m7h",2,2.48485402222920], +["1rrv",2,1.76424461025073], +["1h3f",2,2.04974330178488], +["1b4d",2,2.24113817755009], +["1evk",2,2.46666413973963], +["1jdp",2,3.02137111077745], +["1fp3",2,3.16083216269595], +["1p4j",2,2.37399035738279], +["1uyu",2,1.78118992775645], +["2gpa",2,2.44520804400678], +["1h2v",2,1.98014490085142], +["1lwn",2,2.47589403142542], +["1lwo",2,2.58003270001691], +["1mmv",2,2.38841801229619], +["1p6j",2,2.31232600621529], +["1lzx",2,2.35770926582739], +["1mmw",2,2.42846142409616], +["2aec",2,1.75600313242974], +["2ah9",2,1.83260873055967], +["2aes",2,1.77158952924657], +["2ae7",2,1.98035646172526], +["2cdy",2,1.72918911089445], +["1j3n",2,2.40890259887123], +["1en4",2,1.78115749487504], +["1en6",2,1.94964737578479], +["1h3n",2,1.8394717884167], +["1lxy",2,1.77754392803428], +["2cwx",2,2.5625263394514], +["1ykw",2,2.18192106399082], +["1obl",2,2.28583636078591], +["1ocl",2,2.32460979280476], +["1o9n",2,2.40791777248198], +["2c21",2,1.49120654069004], +["2bkq",2,2.45581373277879], +["1e8y",2,3.18348218218046], +["1aqx",2,3.77462710567623], +["1i83",2,2.35238428415416], +["1pt5",2,2.15677904236081], +["1d1x",2,2.46019151337454], +["1d1w",2,2.55159972746412], +["1dmi",2,2.47979423028133], +["1foo",2,2.43552603467366], +["1z5g",2,1.39840643281005], +["1tcu",2,1.64921358791893], +["1rov",2,3.59653339199594], +["1f61",2,2.01459467036952], +["1aug",2,2.37767988051335], +["1ik3",2,3.7426545632191], +["1k4k",2,3.03128555006265], +["1l6k",2,3.18193118848646], +["1naw",2,2.6392727981889], +["1ub5",2,2.87038079267353], +["1rgt",2,2.28296995732460], +["1o24",2,2.2554405712638], +["1mu7",2,2.18750800264155], +["1c3q",2,2.35339785372847], +["1isz",2,1.96355716834141], +["1it0",2,2.04687840178251], +["1d8h",2,3.51400002467641], +["2az4",2,2.43798616295296], +["1dp4",2,1.6429977176302], +["1rrh",2,2.82905199056913], +["1bzy",2,3.27958206247742], +["2g6x",2,2.62456023702401], +["1hil",2,2.45301466466474], +["1uyw",2,1.91761470980206], +["1rzg",2,2.46301016185633], +["1kxg",2,2.16977757220844], +["1o29",2,2.27607572725128], +["1qbb",2,2.05811682255380], +["1ade",2,2.70225378369635], +["1v3b",2,2.3390632673413], +["1e7u",2,2.76358876723616], +["2btj",2,2.17523836957058], +["1yy8",2,2.57759015300767], +["2c1p",2,2.69335286113599], +["1g7k",2,2.61124865791763], +["2cel",2,1.56406936262958], +["2c2w",2,2.59438718228965], +["1uz1",2,1.90813251875713], +["1v6w",2,2.14176328668959], +["1p48",2,2.07172305164333], +["2one",2,3.38983815373941], +["1lo2",2,2.86015707555584], +["1lo0",2,2.92154475410855], +["1z0h",2,2.91729553460341], +["1jme",2,2.36593512721274], +["1w3j",2,2.11739809035018], +["1p0w",2,1.9718905151514], +["1p0x",2,2.12842824349406], +["1smi",2,2.65002526392200], +["1kh5",2,2.38879906654964], +["1s5z",2,2.70033101866468], +["1e8v",2,2.70818807410173], +["1usr",2,2.70797867309443], +["1e8u",2,2.66650816409351], +["1lob",2,2.58409555196780], +["1get",2,2.12171548319499], +["1uqu",2,3.06934345620640], +["1ew9",2,2.48550380979239], +["1alk",2,3.0696158327773], +["1w44",2,2.44377291010709], +["1uqt",2,2.7924406170014], +["1nue",2,1.86304412026770], +["1u2x",2,2.43478205656883], +["1ik4",2,2.28006904403823], +["1egh",2,2.37422249114727], +["1jmz",2,2.80514581899936], +["1g5y",2,3.32834623515948], +["1fuq",2,2.37003737340852], +["1ktw",2,2.03637754720315], +["2bmh",2,2.8212503621259], +["1cjb",2,2.99793141216872], +["1lk7",2,2.41118254666567], +["1zg9",2,2.70389628574147], +["1zg8",2,2.79639750770767], +["1wuq",2,1.46909156571077], +["2hpd",2,2.35587133734283], +["2acv",2,2.39077300414013], +["2air",2,3.38510838281411], +["1xv2",2,2.11950885656877], +["1z5b",2,1.86104800996940], +["1d3b",2,2.38079633108473], +["1ppr",2,1.74027012651596], +["1hqg",2,2.22118674690123], +["5cna",2,2.33260477205171], +["1qdc",2,2.29145669109688], +["2bra",2,2.9970236992316], +["1ho1",2,2.72947785047691], +["1e3s",2,1.74518781553508], +["1shq",2,2.09903021962776], +["1zp9",2,2.57901119558785], +["1p8x",2,2.68023463134990], +["1js1",2,2.66963816128278], +["1npp",2,3.04762676751078], +["1j4g",2,2.62949938140949], +["1m1g",2,3.49789941479889], +["2shp",2,2.95032796890733], +["2fpz",2,2.33105714564884], +["1dpg",2,2.51706047684879], +["1feb",2,2.84141199515232], +["1r0v",2,2.82073620494139], +["1f9a",2,3.00146681609142], +["1gv4",2,2.55281704281783], +["1qrz",2,3.02719719734612], +["1e55",2,2.41860089239293], +["1ddj",2,3.14168282415456], +["1ulu",2,1.78729616807778], +["1rje",2,1.69682080489903], +["1e8c",2,2.11886615236594], +["1e3w",2,2.06774388462081], +["2afn",2,1.93319624137008], +["1aq8",2,1.88614396117315], +["1ecf",2,2.08093791113019], +["1h0i",2,2.22829656938914], +["1pz2",2,2.48940115608009], +["1h0g",2,2.19120259909464], +["1mzz",2,2.84230280024651], +["1j9r",2,2.10993446474929], +["1rm4",2,2.51823619085822], +["1nba",2,2.17530081291373], +["1as7",2,2.15765609174233], +["1bkc",2,2.96043972773390], +["1sac",2,2.85957635780466], +["1u7t",2,2.26576047339194], +["1d01",2,2.61500355757125], +["1xkl",2,2.46106008605205], +["1n1b",2,1.80239916019354], +["1d0a",2,2.46264515692437], +["1j3b",2,1.89784752357329], +["1b3l",2,2.32608344170051], +["1g6k",2,1.83283642307684], +["1rwb",2,2.36842641242802], +["1yrz",2,2.64525988525542], +["1fpz",2,3.44065058348530], +["1mhy",2,1.88272846128801], +["1rlo",2,2.61146474987775], +["2an1",2,2.24120351544625], +["1cle",2,2.13678515399419], +["1aof",2,1.98421138715748], +["1h66",2,2.82703598030405], +["2fuv",2,1.74375691679092], +["1p2c",2,2.59983154895780], +["1lar",2,2.99723863213626], +["1i7w",2,1.68674652720072], +["1h1s",2,2.96496039035864], +["1h1r",2,3.12898613107934], +["1q4g",2,2.4059810271739], +["2ayl",2,2.49324254808244], +["2ax0",2,1.46836139992982], +["1q85",2,2.81805405362822], +["1nhu",2,2.07446287564695], +["1xtb",2,2.43486660300268], +["1nb4",2,3.06492513552295], +["1kpg",2,2.5537769751715], +["1kph",2,2.43052322908180], +["1lj1",2,2.27104081130162], +["1ksu",2,2.36608612807832], +["1jrx",2,2.89361368962535], +["1jrz",2,2.57918127977798], +["1sr9",2,2.07841933823744], +["1wp4",2,1.94808925562921], +["1xs6",2,2.03849466788065], +["1l2w",2,1.97109145267874], +["1w37",2,2.07120749394068], +["1wzl",2,2.43932514568931], +["2fhj",2,2.22969020408228], +["2fhk",2,1.97363438392694], +["1kgp",2,1.70395146287238], +["1oqu",2,2.06821012597485], +["1sct",2,2.24395594957777], +["1wsj",2,2.64635192823168], +["1xl7",2,1.95590860919827], +["1xmc",2,2.11878472849266], +["1guz",2,2.717677917149], +["1o0s",2,2.69078542164355], +["1rvg",2,2.64860893331645], +["1fcj",2,2.52104716696204], +["1js4",2,1.79322449322940], +["4tf4",2,1.96760580823495], +["2fkz",2,2.39216103074110], +["1vdh",2,1.75305456842623], +["1cb7",2,1.89383849014612], +["1iqx",2,2.17889419539965], +["1ms5",2,2.04678634200585], +["1ui7",2,2.47267803774024], +["1wmp",2,2.00777506915413], +["1olz",2,3.41675029038300], +["1ms8",2,1.89624954008068], +["1zow",2,2.66637405008323], +["2sqc",2,1.97704235323559], +["1mws",2,2.56902759316075], +["1f07",2,2.07812155025660], +["1s0b",2,2.34658322634142], +["1g9b",2,2.22045386477685], +["1vlg",2,1.58270583683613], +["1np3",2,2.00630597701756], +["3pga",2,2.87825087415347], +["1t8q",2,2.52349589805448], +["1n7z",2,2.53681700748068], +["1tzk",2,2.40021115497289], +["1tyz",2,2.10451436472172], +["2fm0",2,1.92046455799202], +["1oyn",2,2.17757078834104], +["2czc",2,2.67540574191781], +["1or0",2,2.00931067002809], +["1sgx",2,2.24726243579623], +["1gg1",2,2.54193529455584], +["1trk",2,2.23229175260948], +["1f2d",2,2.93014583897946], +["1s9f",2,2.28026604385438], +["1jdv",2,1.87854683979261], +["1d00",2,2.72366918844102], +["1v3k",2,1.90224382901036], +["1i75",2,2.01900103071057], +["1ukq",2,2.18766770619043], +["1v3m",2,2.11451916294771], +["1v3j",2,2.28666261990701], +["1ded",2,2.6378445025243], +["1usk",2,1.45522921188237], +["1h84",2,2.22891280586561], +["1h86",2,2.21952015332557], +["1x0p",2,2.06473176997057], +["2tod",2,2.98811852146416], +["1v7c",2,2.11612569881696], +["1ex0",2,2.56053113971552], +["1k9s",2,2.09885766158482], +["1ecp",2,2.79728332791767], +["1itk",2,1.81507795199066], +["1pl6",2,1.92824591203894], +["2d0o",2,2.24145305005066], +["1vpn",2,1.82713391354681], +["2b2s",2,1.14794022891552], +["2fkp",2,2.12711251466064], +["2cca",2,1.91820023955047], +["1tjl",2,3.44802665687386], +["1pvn",2,1.95958301156696], +["1spu",2,2.77036111062274], +["1qak",2,2.53606086473196], +["1oac",2,2.56440583726734], +["1gy8",2,1.92444821327127], +["1ewg",2,3.37058318903954], +["1tk3",2,2.91950125488637], +["1vj0",2,1.54911894555882], +["1t7l",2,2.37618423472799], +["1gc2",2,2.67319226638401], +["1o8u",2,1.70177055931896], +["1bto",2,2.14497813783716], +["1f8g",2,2.43403188697935], +["1n18",2,1.71782649100059], +["1j20",2,2.47189936246976], +["1h5n",2,1.82390953687327], +["2f2s",2,2.82241173358714], +["1xet",2,1.95823939790027], +["2cx9",2,2.18404281595633], +["1xpk",2,2.14220192727921], +["1xpl",2,2.18678982601623], +["1e60",2,2.07502739404508], +["1sp8",2,2.70251870556388], +["1dm3",2,2.83050592497798], +["1u0w",2,2.67855989457443], +["1w1x",2,2.4689982447213], +["1sgz",2,2.30351372011143], +["1oj7",2,1.56097136069223], +["1wa5",2,2.65784531903999], +["1xn3",2,2.41109271326877], +["2fja",2,2.20318208568811], +["1l5v",2,2.16429200064937], +["1ydg",2,1.64734611855043], +["1dqa",2,2.48273996238433], +["1lp9",2,2.57829101562199], +["2bz3",2,2.15300745544123], +["1h4f",2,2.29612454471202], +["2byx",2,1.96685825821416], +["1m3y",2,3.34263769824294], +["2bb6",2,2.91855219791947], +["1k8k",2,2.73650502707381], +["3tmk",2,3.15487246951846], +["1twi",2,2.15742495680830], +["2avw",2,2.40581740537738], +["1muu",2,2.35214444518090], +["1w7v",2,1.13201929873258], +["1jdf",2,2.02080990149525], +["1ecq",2,3.03858598421126], +["1gu0",2,2.08672352384449], +["1ec9",2,2.48163539418735], +["1dce",2,3.29987146209507], +["1tjw",2,2.19837622269791], +["1tjv",2,1.91824484689634], +["2bzd",2,2.44420412380415], +["1wqa",2,2.78601612758748], +["2b1x",2,2.40507980532479], +["1kxt",2,3.28979045675184], +["1f8r",2,2.09665163448448], +["1ct9",2,3.26159043938159], +["1y4z",2,2.43441925710406], +["1dgh",2,2.46107242745093], +["1hhs",2,2.33079477203226], +["1uvm",2,2.4770123332736], +["1uvl",2,2.63367678591900], +["2ahv",2,1.96037850142056], +["1j11",2,2.31626317157784], +["1t5r",2,2.37245356322813], +["1xvf",2,2.47116137815731], +["1xvc",2,2.51559519258937], +["1ozh",2,2.23178064106191], +["1o94",2,2.16957721539506], +["1m5h",2,2.80140478062228], +["1h6k",2,2.15425705154051], +["1x0r",2,3.01553038540352], +["1wpb",2,1.77058933111150], +["1m3d",2,2.51857903350473], +["1pmm",2,1.85976709691055], +["1req",2,2.38124334199662], +["1w85",2,1.97712900549663], +["1eq2",2,2.69226183191599], +["1h8e",2,2.57291022892382], +["1tqy",2,2.72889543284790], +["1r27",2,2.46273919870964], +["1m5q",2,2.47165357612684], +["1f8s",2,2.09290628617487], +["1c30",2,2.90574826285882], +["1k32",2,2.59787787907132], +["1ti6",2,2.46869132343140], +["1vlf",2,2.44478709957434], +["1sx3",2,2.36319495024577], +["1kp8",2,2.75138585109695], +["2b9v",2,2.11316652687182], +["2ayv",2,1.94289582489208], +["1yzv",2,1.83226252778185], +["1u1d",2,2.12099808927253], +["1u1e",2,2.21709850476586], +["1rfx",2,2.13362455045723], +["1t5h",2,1.74029449023453], +["1vji",2,2.60743790021841], +["2a9a",2,1.91999566617955], +["1e6h",2.01,3.13035685920394], +["2d9r",2.01,2.62906899141389], +["1bc7",2.01,2.97543585121911], +["2esw",2.01,2.75671642884284], +["1tjn",2.01,2.68116011065414], +["1ljl",2.01,1.74493262559056], +["2atr",2.01,2.45377332201772], +["1icw",2.01,2.67407270129749], +["2apl",2.01,1.97394129586761], +["1cx6",2.01,2.28843612428093], +["1t6h",2.01,1.92336454432203], +["1gwg",2.01,2.24410803008126], +["1ebz",2.01,1.65153431118695], +["1cuv",2.01,2.51490920545187], +["2g7g",2.01,1.83950491768275], +["2azc",2.01,2.21035475684325], +["1vjg",2.01,1.95476355419677], +["1jc9",2.01,1.96857909383138], +["1yb2",2.01,2.1376504179716], +["2bsi",2.01,2.61911778333304], +["1xvs",2.01,2.99787287136344], +["1wt9",2.01,2.42418675984408], +["1n2f",2.01,2.11829904356534], +["1qn2",2.01,2.74741723425268], +["1dp2",2.01,2.29302056174031], +["1xt4",2.01,2.17166305942911], +["1i79",2.01,2.25433020483254], +["2fvg",2.01,1.77229546567548], +["1edb",2.01,2.51877904311416], +["1lwy",2.01,2.67337482591095], +["1t2c",2.01,1.8941073137243], +["1yw2",2.01,3.64589437679829], +["1w81",2.01,2.85478468250582], +["1xzk",2.01,2.13275861331829], +["1vec",2.01,2.4172930932835], +["1zl9",2.01,2.12130048630747], +["1m4n",2.01,2.20388415359191], +["1u13",2.01,1.92806578059861], +["1li4",2.01,2.51042598719445], +["1xaf",2.01,2.49192440351474], +["1wo2",2.01,1.70225706333284], +["1ua3",2.01,1.97110089689126], +["1l9y",2.01,2.04643433663469], +["1oj4",2.01,1.95516025657114], +["1u45",2.01,1.97204982902160], +["1mw0",2.01,1.87765104746553], +["1uvz",2.01,2.56535780310411], +["1yxo",2.01,2.28577178764254], +["1s4p",2.01,2.29646876905625], +["1s4o",2.01,2.35366143980039], +["1s4n",2.01,2.50636994311321], +["1yxq",2.01,2.17948315982446], +["1vmk",2.01,1.87968931763227], +["1ddg",2.01,3.20215097957232], +["1m9q",2.01,1.78577787597415], +["1m9k",2.01,2.05518951916138], +["1wuo",2.01,2.65169438921638], +["1gq3",2.01,2.98470058043478], +["2ae8",2.01,2.45527875671527], +["1nqo",2.01,2.14003104527647], +["1evu",2.01,2.8585321087168], +["2av6",2.01,2.21684512713836], +["2af6",2.01,2.11938156135009], +["1h7x",2.01,2.07790967829246], +["2a5z",2.02,2.09580212266722], +["1ylq",2.02,2.56619412552061], +["1qx8",2.02,2.37045848379965], +["1zp8",2.02,2.83990012859885], +["1zpa",2.02,2.95269709125716], +["1b92",2.02,2.27300373986759], +["105m",2.02,2.63089189781375], +["1l0k",2.02,2.39553343996111], +["1j84",2.02,2.55842865078472], +["1e20",2.02,2.82222757185689], +["1u6q",2.02,2.34749061882435], +["1xpz",2.02,2.31481445695372], +["1vm1",2.02,2.34555970913507], +["1v75",2.02,2.119404270883], +["1way",2.02,1.66758010643098], +["1dk7",2.02,2.33658330271672], +["1ds4",2.02,2.54561607263278], +["2ng1",2.02,2.89167155812817], +["1zdw",2.02,1.97427413284863], +["1d0k",2.02,1.71553944580823], +["1cbk",2.02,2.22248240166545], +["2a5f",2.02,1.90473444920242], +["1svg",2.02,2.0270462536764], +["1j3p",2.02,2.51899069221015], +["1yzh",2.02,2.32976850230441], +["2b4j",2.02,2.13828588559842], +["1rd5",2.02,2.27855742729084], +["2fv9",2.02,2.21707274359156], +["1ven",2.02,2.54287812602856], +["1va5",2.02,2.32776612897285], +["1st4",2.02,2.84552319345581], +["1khf",2.02,2.12999463008818], +["1wx5",2.02,3.35784009591191], +["2amx",2.02,2.04334096432438], +["1z8h",2.02,1.88317026813228], +["1fqj",2.02,2.00066971984502], +["1uwq",2.02,2.07551135316722], +["2byn",2.02,2.09701534280285], +["1q1g",2.02,2.23958439946995], +["2azb",2.03,2.40179354417797], +["1w40",2.03,1.85249244926512], +["2cbm",2.03,1.60936596075698], +["1zr8",2.03,2.50921050312822], +["1c10",2.03,2.61700596208329], +["1qtk",2.03,2.77841407602913], +["1ocs",2.03,2.13315554552387], +["1jd3",2.03,2.47616907977145], +["1xln",2.03,2.16974082165382], +["1k24",2.03,3.56554759382881], +["1i3v",2.03,2.79914340578925], +["1an1",2.03,2.10166142364922], +["1sd1",2.03,1.77828901399237], +["1dsp",2.03,2.36340198497494], +["1dso",2.03,2.60157137451536], +["1ng1",2.03,2.38940054474052], +["1mcx",2.03,1.95755637426422], +["1z3a",2.03,2.77446112229028], +["1b2z",2.03,2.34016282890803], +["1f3l",2.03,2.83597871380376], +["1alw",2.03,2.39406799977438], +["1geb",2.03,2.54879847486580], +["1md3",2.03,2.54762888005419], +["1px7",2.03,2.15828478974929], +["1yye",2.03,2.76296613270318], +["1k6s",2.03,2.32380478593392], +["1sw3",2.03,1.47688342820763], +["1jfh",2.03,1.81820944690152], +["1xh1",2.03,2.45855877661047], +["3erd",2.03,2.60609611898347], +["1qqt",2.03,2.44774964417594], +["1y5j",2.03,2.55590723574773], +["1idq",2.03,2.09128134556414], +["2kfn",2.03,2.91366140366445], +["2kfz",2.03,2.92047342824964], +["1rys",2.03,2.34929967957692], +["1lga",2.03,2.04544313586323], +["1z6q",2.03,2.47240206717891], +["2ane",2.03,2.9633965005316], +["1qwu",2.03,1.89846782423962], +["1tqv",2.03,2.06454646466047], +["1tqu",2.03,1.99604449498616], +["1bvy",2.03,3.02890193314777], +["2aj3",2.03,3.00009178518231], +["2fm5",2.03,2.02908590781318], +["1q32",2.03,2.36041885822862], +["1fe8",2.03,2.63677963972590], +["1g8j",2.03,1.97857252590356], +["2min",2.03,2.32389177099232], +["3min",2.03,2.40951418312098], +["1fz3",2.03,2.3312312500967], +["1mj0",2.03,2.25660979469157], +["2b8j",2.03,1.78391173678501], +["1h34",2.04,2.79656013624938], +["2avp",2.04,2.25680823484004], +["1iu9",2.04,2.14668833158263], +["1qll",2.04,2.66259460788815], +["2fgn",2.04,2.31213581100492], +["2ars",2.04,1.85285409315296], +["1g1d",2.04,1.96725856361965], +["1jtk",2.04,2.08369809891495], +["1riw",2.04,2.30188908343212], +["1d3d",2.04,2.5808922089132], +["6prn",2.04,2.08816213950704], +["1s7c",2.04,2.41796128729124], +["1cef",2.04,2.18701245726372], +["1khz",2.04,2.57899269360974], +["2a7v",2.04,2.61840080618728], +["1g09",2.04,2.62895252964256], +["1g0a",2.04,2.70916641783785], +["1ghq",2.04,2.52280337064917], +["2g8l",2.04,1.23193073509157], +["2trs",2.04,2.86713969856799], +["1nwc",2.04,2.32047696782154], +["1x15",2.04,2.10800721557850], +["1fyh",2.04,2.44258722655916], +["2a92",2.04,2.33137663447211], +["2bbd",2.04,2.48759049025875], +["1dyu",2.04,2.58988088528084], +["1smh",2.04,2.01564214664173], +["4ame",2.05,1.90347328847593], +["1b6w",2.05,2.1441595877728], +["2psr",2.05,1.95692443560507], +["1ub9",2.05,2.72122738501122], +["2fls",2.05,1.86507926715531], +["1crj",2.05,2.87139219037171], +["1gm4",2.05,1.77697890912475], +["2c5k",2.05,1.57836336058815], +["1vpz",2.05,1.99107504290044], +["1ugm",2.05,2.06136634332606], +["1duc",2.05,2.10761185787250], +["1dmn",2.05,2.80340913567943], +["1t6a",2.05,1.33919893002603], +["1e83",2.05,1.84353948774262], +["1fgz",2.05,2.21184358704587], +["1joi",2.05,1.79993249696623], +["1d1m",2.05,2.81637209815861], +["1nae",2.05,2.13609444609505], +["4lyo",2.05,2.35273081180366], +["1hzi",2.05,2.49729344453335], +["1b56",2.05,2.44363178377882], +["1a3u",2.05,2.83538029697077], +["2enb",2.05,3.25298259635985], +["1vsf",2.05,2.75572277668389], +["2fzt",2.05,0.960569474694351], +["1d3f",2.05,2.14059287393092], +["1l77",2.05,2.12447733143541], +["1cuq",2.05,2.45943548111840], +["1ky1",2.05,2.57278701245253], +["1cu5",2.05,2.59029436319875], +["1wlf",2.05,1.95468253269004], +["1e7z",2.05,2.67749542862948], +["1dat",2.05,2.27697351892437], +["1ilw",2.05,2.54325607465218], +["1fmz",2.05,2.55087057954762], +["1s30",2.05,1.98721541465516], +["1z4q",2.05,2.19884094900875], +["1cpi",2.05,1.96096688538159], +["7lpr",2.05,2.45118918565077], +["2bsm",2.05,1.94975289422010], +["1bxi",2.05,2.80238660554685], +["1aya",2.05,2.75278613600602], +["1vdf",2.05,3.28760947081948], +["1zgh",2.05,1.02046866988409], +["1fnz",2.05,2.22770607347131], +["1hb0",2.05,1.7919956167292], +["1uak",2.05,1.93503439103134], +["1ub0",2.05,2.01381014411183], +["2fpd",2.05,2.23925926788244], +["1txz",2.05,2.32709761419195], +["2ffz",2.05,2.44535640635298], +["1jvt",2.05,2.57316818653909], +["1lbf",2.05,2.54181826631595], +["2f5o",2.05,2.49087571072764], +["1sef",2.05,2.8551157216043], +["1vlz",2.05,1.92354003542156], +["1q3b",2.05,2.21835301139920], +["1cnh",2.05,2.09039214757667], +["1xeu",2.05,2.90182673462529], +["1ypu",2.05,2.1686087548759], +["1nw5",2.05,2.22298015692909], +["1f56",2.05,2.16492752766285], +["1h4k",2.05,2.17343916461042], +["1luf",2.05,1.82316121640367], +["3btw",2.05,1.89773099649408], +["2bzj",2.05,1.55138458041098], +["1ckp",2.05,2.43325670735950], +["1q03",2.05,1.88823792306508], +["1em9",2.05,1.70646865114163], +["2bij",2.05,1.96490483092264], +["1nfu",2.05,2.95494500675533], +["1ffh",2.05,1.46203976964905], +["1ns6",2.05,1.55739323062004], +["1ym5",2.05,2.27658714766235], +["1kag",2.05,2.35316879212486], +["1k0z",2.05,2.60865028451723], +["1sxz",2.05,1.71616795318747], +["1g9y",2.05,3.00301784911701], +["1yzt",2.05,1.60561826177068], +["1cet",2.05,2.14763988258244], +["1obg",2.05,2.30045561871946], +["1r9q",2.05,1.56182129152820], +["1rkp",2.05,2.18009901285636], +["1yvh",2.05,2.49090108597259], +["1m3h",2.05,2.78551077609839], +["1f44",2.05,3.32869904259448], +["1dsn",2.05,3.33021397744428], +["1gyd",2.05,2.15049688523859], +["1tli",2.05,1.89465759307569], +["1bc1",2.05,3.18230480776504], +["1bns",2.05,2.86138194955493], +["1gxo",2.05,2.11881599202947], +["1vjz",2.05,1.49381425587225], +["1y7m",2.05,2.73240556088187], +["6mht",2.05,2.03184941839163], +["1t6q",2.05,1.37982732106897], +["1n84",2.05,2.28558936754716], +["1e82",2.05,2.00875678746251], +["1e81",2.05,2.58018367443485], +["1e80",2.05,2.13766308329028], +["1e5o",2.05,2.57058384565864], +["1bq5",2.05,2.81437787219935], +["1ftf",2.05,2.3216556191264], +["1v72",2.05,1.94283185755481], +["2poo",2.05,2.79145735836388], +["1xh5",2.05,1.95426664087605], +["1jqa",2.05,1.90808638437191], +["1bd9",2.05,1.69293629810253], +["1agd",2.05,2.17355423307073], +["1uz5",2.05,2.42474702492345], +["1rc0",2.05,1.85433335648805], +["1jy5",2.05,1.75644001696905], +["4hoh",2.05,1.92009687273275], +["1dkq",2.05,2.50137662170072], +["1d7s",2.05,2.84755457294348], +["1h5z",2.05,2.19347041238519], +["1dq2",2.05,2.67294603102647], +["1u8x",2.05,2.56736401264199], +["2ez6",2.05,2.24386505744252], +["2f5a",2.05,2.92555913216548], +["2bbw",2.05,1.92479698620371], +["2b51",2.05,2.44922912732771], +["1tj2",2.05,1.98644783906585], +["2a6q",2.05,2.12041740262281], +["1k89",2.05,2.99260968298358], +["1a6r",2.05,2.17929975680912], +["1oy3",2.05,3.11947065026919], +["2pka",2.05,3.09342930830416], +["1ro8",2.05,2.46853211203072], +["1tqn",2.05,3.28782016294595], +["2bbs",2.05,2.37640871709283], +["1qae",2.05,2.29651751659391], +["1q8q",2.05,1.55733948417940], +["1q8s",2.05,1.72906019274318], +["2ftw",2.05,1.95515030965038], +["1b95",2.05,2.48632994108614], +["2ff6",2.05,2.07496653396781], +["1o5d",2.05,2.84271851309996], +["2a6r",2.05,2.24418516383108], +["1lnx",2.05,2.02051496989503], +["1sz6",2.05,2.60312350600061], +["1w6r",2.05,2.4058739512230], +["1g7c",2.05,2.23657229847553], +["1qid",2.05,2.44752574150838], +["1nh6",2.05,1.70121109675043], +["2g7z",2.05,1.80637182430917], +["1ufv",2.05,2.02316886355652], +["1okk",2.05,1.52102669527921], +["1bro",2.05,2.34534623999374], +["2tss",2.05,1.80394728603599], +["2a6l",2.05,1.59557299362343], +["1wpm",2.05,2.01135657406024], +["1wpp",2.05,1.64101663254456], +["1i7d",2.05,2.72922022857047], +["1i2o",2.05,1.60008707689753], +["1i2p",2.05,1.67819298041384], +["1i2q",2.05,1.71690416555507], +["1i2n",2.05,1.57207508269531], +["2afb",2.05,1.75135040690412], +["1dx9",2.05,2.14648551678515], +["1rdz",2.05,2.70127414865986], +["1ly8",2.05,2.18565931257975], +["1b7g",2.05,2.05854729434537], +["1biq",2.05,2.86504780646181], +["1lt8",2.05,3.20229429866282], +["1q8y",2.05,2.49850645967034], +["1q2x",2.05,1.81417399241009], +["1w9k",2.05,1.99999621296730], +["1io9",2.05,3.36136033834554], +["1ee0",2.05,2.34228325150650], +["1nis",2.05,2.48627018324854], +["1nit",2.05,2.48930388356219], +["1fgh",2.05,2.42051778917341], +["1aco",2.05,2.46705777437688], +["2av7",2.05,2.01876082229484], +["1ajq",2.05,2.29820194509099], +["1nqv",2.05,1.39737307683254], +["1s32",2.05,2.57422164162928], +["1efc",2.05,2.86666328398641], +["1un7",2.05,2.48888122593701], +["1wkb",2.05,3.03824591539266], +["2b67",2.05,2.44974038244204], +["1lzz",2.05,2.39336339538234], +["1m00",2.05,2.4299028752191], +["1zzr",2.05,2.43767976456388], +["1k0g",2.05,2.83305008582061], +["1ed6",2.05,2.65638452924994], +["1vl0",2.05,1.62288281909864], +["1mu9",2.05,2.4396361136075], +["1d8i",2.05,3.15987146686496], +["1oe9",2.05,1.88521427140730], +["1xqc",2.05,2.34756655969566], +["1p0v",2.05,2.19931940222237], +["1lod",2.05,2.63168165470480], +["1xey",2.05,1.91125370182016], +["1jju",2.05,3.07981964455013], +["1eum",2.05,2.53874572669947], +["1q7b",2.05,2.02106533406991], +["1hxj",2.05,2.28274247316924], +["1rm0",2.05,2.75017513175081], +["2fpo",2.05,2.31659368706491], +["1qi9",2.05,1.81296383372948], +["1ym2",2.05,2.11306407786405], +["1go4",2.05,2.92155955445948], +["2hbs",2.05,2.23521456753492], +["1z0e",2.05,3.26861733758615], +["1o6u",2.05,1.73535175920286], +["1qy9",2.05,1.56286126243832], +["2aa3",2.05,2.35569035614076], +["1q1l",2.05,2.73671148829457], +["1o17",2.05,2.84733286091546], +["1lw5",2.05,1.80011210281378], +["1kev",2.05,1.94947450692092], +["2b2q",2.05,1.33997088870018], +["1lvu",2.05,2.74858824760539], +["1yaa",2.05,2.45829801260086], +["1uz6",2.05,1.98045908629163], +["2bpl",2.05,2.93680562034372], +["1z11",2.05,2.56913075513605], +["2bys",2.05,1.67717723877034], +["1fz6",2.05,2.55748558073294], +["3pch",2.05,2.62192500090581], +["1nf4",2.05,2.16019756310929], +["1h6d",2.05,2.52110476712947], +["1uw9",2.05,2.14483319697351], +["2gdb",2.06,2.58896685396836], +["1a0b",2.06,2.08856089637898], +["1wdg",2.06,2.87376224393156], +["1ujb",2.06,1.27173858598931], +["1d2y",2.06,2.35936097288600], +["1z22",2.06,1.77014269374561], +["1yzn",2.06,2.05280913482002], +["1vr3",2.06,1.70613416050233], +["1la1",2.06,2.37186395342005], +["1cqv",2.06,2.69859229165824], +["1laf",2.06,2.01679771247447], +["1lah",2.06,1.78826694427455], +["1lag",2.06,1.83114036005077], +["1jt9",2.06,2.45155015291934], +["11ba",2.06,2.34479240015017], +["1hw4",2.06,2.75123971776573], +["1ym0",2.06,1.55817930672922], +["1t01",2.06,2.76593574799704], +["1tfr",2.06,2.67349684357482], +["1a5g",2.06,3.24058878404233], +["1vmd",2.06,1.81241518769067], +["1qf2",2.06,1.86377631431209], +["1qp1",2.06,3.08753841536109], +["1gza",2.06,2.15864840202302], +["2f9k",2.06,1.73279401299995], +["1pu2",2.06,1.76317951482238], +["1oza",2.06,2.18187514126332], +["1pqp",2.06,2.17470407704456], +["1fvj",2.06,1.90341863650135], +["1vgk",2.06,2.37764119354876], +["1i0i",2.06,2.08111925476944], +["1ebk",2.06,3.12855888765845], +["1ds7",2.06,2.78513235725329], +["1fx6",2.06,2.29877137053060], +["2fzq",2.06,2.12878379320738], +["1ee1",2.06,2.05023856992956], +["1vep",2.06,2.62350434240029], +["1crl",2.06,2.14947370809616], +["1xlz",2.06,1.85819746058475], +["1kvm",2.06,2.07498931151064], +["1cm7",2.06,3.51479171312455], +["1p4h",2.06,2.49597681881577], +["2b0o",2.06,2.56577905514665], +["1xjq",2.06,2.47187733448129], +["3pce",2.06,2.65324325746879], +["1ykk",2.06,2.0124517994947], +["1pga",2.07,2.6177909376509], +["1uo5",2.07,2.64085286681654], +["1unu",2.07,2.46535153636375], +["1unt",2.07,3.30852367847174], +["1e9m",2.07,1.42805183299751], +["103m",2.07,2.46229258850342], +["101m",2.07,2.61841927322863], +["2gf4",2.07,2.14261366675701], +["1yu9",2.07,1.82348996891719], +["1jnw",2.07,2.13718994524054], +["1q06",2.07,2.21329584248887], +["1t63",2.07,2.13447278554705], +["1b5g",2.07,3.36311338903637], +["1d4p",2.07,2.56460627855168], +["1yzi",2.07,2.94090296897003], +["1mni",2.07,2.76408031245159], +["1gwo",2.07,1.58784000979515], +["1sv0",2.07,2.48000023386114], +["1jiv",2.07,2.33649982050158], +["1r2v",2.07,3.04339169728789], +["1mdz",2.07,2.18448618695726], +["1qlh",2.07,2.17503415589638], +["1u4h",2.07,2.15182813694885], +["1yu1",2.07,2.10557758434448], +["1udx",2.07,2.50947449612519], +["1ajo",2.07,2.01740064860766], +["1olt",2.07,1.96164899271984], +["1usb",2.07,2.30588893388066], +["1wd4",2.07,1.76778219533801], +["1bfn",2.07,2.22643487418731], +["1q4n",2.07,1.86250996948804], +["2d42",2.07,2.31354071274748], +["1xq7",2.07,2.824162593778], +["1vl8",2.07,1.52977718649888], +["2lyn",2.07,2.88757727730334], +["2f4b",2.07,2.91173005569248], +["1y2z",2.07,2.51483328390355], +["2qil",2.07,2.05869556939833], +["2ddh",2.07,2.41229805076390], +["1kxr",2.07,2.51848866012851], +["1yz0",2.07,2.83921693562258], +["2a3c",2.07,1.45822826026033], +["1s2q",2.07,1.76901373821222], +["2byp",2.07,1.70447589571491], +["1fz0",2.07,2.34253579860204], +["2c12",2.07,2.23396644421809], +["2a3z",2.08,2.05410720958257], +["1z27",2.08,2.64798777637875], +["1u8u",2.08,2.3263367308305], +["1a6p",2.08,2.39178355299644], +["1crc",2.08,3.87425342921672], +["1gy0",2.08,2.3525927731603], +["1yr7",2.08,3.15679633101392], +["1w8p",2.08,2.58052378608598], +["2a5a",2.08,2.95112531697344], +["1aa7",2.08,2.32569487309594], +["1gt5",2.08,2.48108159939929], +["1mww",2.08,3.06590809813242], +["5cpp",2.08,2.36954165765155], +["1xk3",2.08,2.06582036482349], +["1xk1",2.08,2.69290108596264], +["1rlu",2.08,1.80444476006601], +["1d8y",2.08,3.10180204411575], +["1q13",2.08,3.18894328813863], +["2cvq",2.08,1.99199617394213], +["2fp4",2.08,2.38267783954937], +["1yx2",2.08,2.74509307216012], +["1e3i",2.08,2.28042505349476], +["1yfs",2.08,2.62734451214301], +["1tzm",2.08,2.55687193263385], +["1w20",2.08,2.35988911846702], +["1w21",2.08,2.35988911846702], +["1zmd",2.08,2.17925983225695], +["2f8m",2.09,1.94244421262276], +["107m",2.09,2.34144852561709], +["1nqy",2.09,2.41309597488879], +["1ya9",2.09,2.56321683652407], +["1u4e",2.09,3.01106164424234], +["1dzu",2.09,2.15304709477582], +["2g43",2.09,2.38113296280307], +["2amy",2.09,2.36672391340526], +["5est",2.09,2.26418104595566], +["1le7",2.09,2.32432067229605], +["1zb2",2.09,1.47430480375246], +["1if6",2.09,2.28248473618057], +["1r7t",2.09,2.19564268142492], +["1r7v",2.09,2.31002827342704], +["1yjq",2.09,1.84961782253526], +["1ko1",2.09,2.81134568486886], +["2alu",2.09,3.01838684660329], +["2b41",2.09,3.11629057650742], +["1a59",2.09,2.43773832183208], +["1zli",2.09,2.28663757750955], +["2f96",2.09,1.45931413064784], +["1rfd",2.09,2.18165638628115], +["1hkd",2.09,2.26675394647292], +["1vr4",2.09,3.10989339017565], +["1b9n",2.09,2.67502258296744], +["1cxk",2.09,2.15652207286664], +["1z6b",2.09,2.28667111166471], +["1dfi",2.09,2.68633839041273], +["1sc6",2.09,2.90070597071798], +["1rp7",2.09,2.91836761175755], +["1rrl",2.09,3.25413423336930], +["1vjh",2.1,1.99367248480251], +["1ybm",2.1,1.83776188458030], +["1vjq",2.1,2.47888738936977], +["2ghl",2.1,3.36582445384193], +["1enh",2.1,2.10057830027454], +["1kna",2.1,1.85717760013518], +["1i5y",2.1,1.73524015027532], +["1d1l",2.1,2.60368982173030], +["1qm7",2.1,3.37946879674323], +["6ame",2.1,2.29534939049281], +["1qr8",2.1,3.51309206231283], +["1lr8",2.1,2.40754847798060], +["1wvn",2.1,1.80327763488123], +["1bcg",2.1,2.45459818218952], +["1kiv",2.1,3.74066859699484], +["2fi0",2.1,2.28588411585416], +["1blu",2.1,2.62522207968852], +["1es1",2.1,2.04234176582645], +["1a32",2.1,3.1050522911093], +["1zaa",2.1,2.78443484886885], +["1cos",2.1,3.57464766725613], +["2bs5",2.1,1.53889170087772], +["1uvb",2.1,3.14152591041681], +["2fb0",2.1,1.45396432820873], +["1j1v",2.1,1.83368622605741], +["1h59",2.1,2.07802522662818], +["1mb1",2.1,3.36571824941489], +["1kc2",2.1,2.64366355085243], +["1bm2",2.1,1.96111853264956], +["1rzx",2.1,1.98415748139467], +["1tze",2.1,2.45666515712009], +["1wwb",2.1,3.26834624355335], +["1eru",2.1,1.74133106829733], +["1auc",2.1,2.86729034479182], +["1nn7",2.1,2.34161442251278], +["1b0t",2.1,2.43753218932246], +["1a6l",2.1,2.39573792024062], +["1frk",2.1,2.36753635800137], +["1fda",2.1,2.29950744530315], +["1fri",2.1,2.65604939412628], +["1axq",2.1,2.60204686800006], +["1xg8",2.1,2.77419921694869], +["2coq",2.1,3.13315364316159], +["1f1w",2.1,2.57858467263331], +["2cwp",2.1,2.6271600002181], +["1bkl",2.1,3.17885517720417], +["1zox",2.1,2.04184746867816], +["1wy9",2.1,2.41119697743818], +["1o3x",2.1,3.23199358911823], +["1ed1",2.1,2.64898587028925], +["3rhn",2.1,1.95036520772852], +["1ne8",2.1,1.68970707799683], +["1rmd",2.1,2.75671939733739], +["1y28",2.1,2.92138615839069], +["1od9",2.1,2.62867581720106], +["2awf",2.1,1.84355495031658], +["1un4",2.1,2.09695227389666], +["1gs3",2.1,2.86423846319398], +["3bp2",2.1,3.1296335293573], +["1gcl",2.1,3.87831042527139], +["1gv7",2.1,2.65323322122815], +["1w6y",2.1,2.25452690182018], +["1kqu",2.1,2.30858812196552], +["1pod",2.1,3.42252407209226], +["4rsk",2.1,2.19986936553297], +["1rbn",2.1,2.14350248814551], +["2ch9",2.1,2.13967768178020], +["1u9r",2.1,2.00369070399147], +["1cpr",2.1,1.79944239633568], +["1jpo",2.1,2.54173784995000], +["4lym",2.1,3.10032736621326], +["1xei",2.1,3.90477041569681], +["1xej",2.1,4.20739534252566], +["2es0",2.1,1.27668856608533], +["1rem",2.1,1.86326817875719], +["1gev",2.1,2.5445537052966], +["1tr5",2.1,1.56171463689015], +["1u8b",2.1,2.65862995914918], +["1yiv",2.1,2.38139453199762], +["1dc9",2.1,2.02756526599705], +["2hmb",2.1,3.01313745360274], +["1gu5",2.1,2.17471847263703], +["1cm9",2.1,2.77340191834209], +["1w9w",2.1,2.27804987216291], +["5nuc",2.1,2.70766516010391], +["1aex",2.1,2.80216222697127], +["1a3t",2.1,2.8087358006578], +["1crb",2.1,1.76302697934966], +["1wjg",2.1,2.25393851935871], +["2fbi",2.1,2.52785215563437], +["1h0r",2.1,1.972637265197], +["1a3k",2.1,1.94669302415043], +["2cbs",2.1,2.04258081932287], +["1xcv",2.1,2.27617101746503], +["1jwf",2.1,2.67861243395548], +["2fop",2.1,2.47904451866956], +["1n05",2.1,2.37712323789319], +["1r2e",2.1,2.65901903283168], +["1k53",2.1,2.05556942253739], +["1xjc",2.1,2.00981476277708], +["1qqh",2.1,2.61544858908233], +["1ngn",2.1,2.64004367490610], +["1etk",2.1,2.14315518116463], +["1vsj",2.1,2.89324005196325], +["1qj9",2.1,3.23250552911295], +["1hhq",2.1,2.71241506039239], +["1nsp",2.1,2.26184986077916], +["1f3g",2.1,3.45233371228498], +["1gyj",2.1,2.34131211664963], +["1b5l",2.1,2.76234725535253], +["1ibb",2.1,2.14356633160825], +["1bzo",2.1,2.77383667106240], +["1q7h",2.1,2.17074689992567], +["1j6v",2.1,2.01573954038879], +["5i1b",2.1,3.08296220089054], +["3sod",2.1,3.1783070307288], +["1f1d",2.1,2.11190939167965], +["1t4q",2.1,2.63115323133402], +["1twe",2.1,2.84795700163537], +["1too",2.1,2.81772220924848], +["2a11",2.1,3.25405241322783], +["1cp5",2.1,2.58752228107585], +["1ufp",2.1,2.28506783111157], +["1ch5",2.1,2.94048530048448], +["1phr",2.1,2.22738598037805], +["1fyl",2.1,2.28666479317474], +["1v8l",2.1,1.77886974658246], +["1w8i",2.1,1.70519476948795], +["1g5r",2.1,2.59361450033853], +["205l",2.1,2.73373583622316], +["1znh",2.1,2.83389573608918], +["1mnc",2.1,2.66868602601952], +["1mmb",2.1,2.55283313236542], +["1c6m",2.1,2.11922450143531], +["1c66",2.1,2.7146738312611], +["2b72",2.1,1.79117659264051], +["2b75",2.1,1.85133592742501], +["2b6t",2.1,2.01590877898758], +["2b74",2.1,1.86314953535473], +["1klo",2.1,2.64573931998451], +["1cu6",2.1,2.38889435267258], +["1ctw",2.1,2.51628207929740], +["1l82",2.1,3.05762482027043], +["1c6a",2.1,1.85539584174846], +["140l",2.1,2.24231065243175], +["1cv1",2.1,2.32002677651528], +["197l",2.1,2.93651130260728], +["1dyd",2.1,2.35421357546513], +["144l",2.1,2.32085105629122], +["1dyg",2.1,2.12567723587131], +["1dyc",2.1,2.48679442975962], +["1ncy",2.1,2.73890067910461], +["1lwk",2.1,3.44562901552548], +["1iqv",2.1,2.17520724043043], +["2nul",2.1,2.24463867262445], +["5cyh",2.1,2.40440199804514], +["4cyh",2.1,2.15782705922657], +["252l",2.1,2.58789498751554], +["1qt4",2.1,2.81637672539203], +["1sfe",2.1,2.88862863543928], +["1cwa",2.1,2.11045320582152], +["2c5j",2.1,2.02926873885244], +["1obv",2.1,1.99056416139928], +["1dux",2.1,2.76347038941252], +["2bmj",2.1,1.87629246272253], +["1qng",2.1,1.65321475817162], +["1xeq",2.1,2.60294914553720], +["1pue",2.1,3.20798860411889], +["2bsf",2.1,1.81465669073999], +["1bef",2.1,4.05431338477434], +["1ftn",2.1,3.03759886413338], +["1bwo",2.1,2.52818568312994], +["1tfk",2.1,2.55596162724675], +["1cwr",2.1,2.46067882634703], +["1ore",2.1,1.85947516421116], +["1lli",2.1,2.09136762567064], +["1ta0",2.1,2.42001320207463], +["2bb2",2.1,2.93274474036615], +["1znw",2.1,1.70986810888319], +["1br9",2.1,2.6484719487484], +["1u1n",2.1,1.99825177126854], +["1po6",2.1,2.27028630589448], +["2up1",2.1,2.05325060244260], +["1hfp",2.1,2.89428472931318], +["1boz",2.1,2.82260653875796], +["1hfq",2.1,2.71437356965905], +["1hfr",2.1,3.07994082433427], +["1pd8",2.1,3.23613569265149], +["2f3n",2.1,1.98050612554673], +["1zm0",2.1,3.42793218308635], +["1ygs",2.1,2.86497382649985], +["1g0x",2.1,2.0658459106035], +["1fio",2.1,2.15231851819072], +["1uct",2.1,2.23872044596648], +["1uhn",2.1,1.98814369499343], +["1ryt",2.1,2.45148680811103], +["1lvg",2.1,2.52272081631105], +["1qbj",2.1,2.48792202576114], +["1mjv",2.1,2.51853642359063], +["1nch",2.1,3.10489665552661], +["1tev",2.1,2.41383512469886], +["1g1c",2.1,2.15816410181232], +["1cqn",2.1,2.01149704214496], +["1s2b",2.1,2.73532065417751], +["3adk",2.1,3.81781327533533], +["1cuz",2.1,1.80304748504699], +["1ewn",2.1,2.43785837667363], +["1qbt",2.1,2.74869914125812], +["2tct",2.1,2.14439262447772], +["1ec1",2.1,1.67967167756368], +["1lv1",2.1,2.07873314101049], +["2bqv",2.1,1.41460786275092], +["1t7k",2.1,1.93970601822408], +["4phv",2.1,2.32693541690313], +["1odw",2.1,2.65511848946828], +["1j8s",2.1,2.19309279175929], +["1t4w",2.1,1.97236292413407], +["2g7l",2.1,2.60083788528063], +["1m4w",2.1,1.75622409387588], +["1p3t",2.1,2.35907665110047], +["2bf2",2.1,2.61401398876118], +["1g77",2.1,2.92295962053177], +["6lpr",2.1,2.39003534231189], +["1p05",2.1,2.60018282116876], +["2fdh",2.1,1.76484753322253], +["2fdf",2.1,1.82836851944818], +["1iac",2.1,1.98964825649495], +["1tsu",2.1,2.72352539344101], +["1kzl",2.1,1.70327655798165], +["1kd9",2.1,1.99327827263563], +["1p7i",2.1,1.38545818428718], +["1p7j",2.1,1.81582730841668], +["1nzv",2.1,2.51106879149216], +["1vj3",2.1,3.60154915399518], +["1ly4",2.1,4.08643256878906], +["1fb6",2.1,2.03463343461064], +["1mjl",2.1,2.79603213473931], +["1kk9",2.1,2.48557671626109], +["1lvf",2.1,1.78811498420409], +["2fdj",2.1,1.80150918692999], +["1f2v",2.1,3.20349409421866], +["2brq",2.1,1.94475033851344], +["1rz4",2.1,1.88390036298017], +["1vf6",2.1,2.35255200897233], +["1pe6",2.1,2.84035438779601], +["1xq1",2.1,2.3764554229469], +["1bwp",2.1,2.74932839966252], +["1pop",2.1,1.88892686320606], +["1rrx",2.1,2.3718932754823], +["1qb2",2.1,2.43939718126925], +["1ewo",2.1,1.89408139867704], +["1q6k",2.1,2.46347084718553], +["1u9x",2.1,2.09802401107005], +["1p92",2.1,3.32688946284156], +["1h68",2.1,2.16921724220917], +["1kr5",2.1,2.60311388779056], +["1gec",2.1,3.32537593901098], +["2c9y",2.1,2.43102573520933], +["1emk",2.1,2.79530162233831], +["1tff",2.1,2.39243777143411], +["2ak2",2.1,2.38296343645912], +["1v1q",2.1,2.90854763873679], +["1ep7",2.1,2.36573619717151], +["2tgd",2.1,4.14024470878226], +["1lgq",2.1,2.39188571261767], +["1yp9",2.1,2.44326188808331], +["2a7h",2.1,2.32654491632084], +["1auj",2.1,2.05027473422414], +["1ql7",2.1,2.30178798523791], +["1h9g",2.1,2.58438995167449], +["1ks5",2.1,2.10310459963843], +["1qye",2.1,2.67100348655742], +["1f0b",2.1,3.86850311118233], +["1yyy",2.1,2.65756224684496], +["1bfp",2.1,3.19943892141761], +["1xqm",2.1,1.77204056069651], +["8pch",2.1,2.43475971209170], +["1b54",2.1,3.10523869765825], +["1cks",2.1,2.37984082866955], +["1dzi",2.1,2.71365489283870], +["1k61",2.1,2.25229407236353], +["1qkp",2.1,2.36563151921189], +["1qko",2.1,2.34936684763997], +["2c56",2.1,1.67121097953926], +["1z6u",2.1,1.78282658199662], +["1smf",2.1,2.41764642785326], +["1upv",2.1,2.63517064419874], +["1bfv",2.1,2.62578397019797], +["1cfv",2.1,2.56605684395403], +["1xap",2.1,2.52447993025118], +["4vgc",2.1,2.24016712067126], +["1i4r",2.1,2.58883280584216], +["1spx",2.1,2.17902833341555], +["1gmh",2.1,2.51834738524263], +["6gch",2.1,3.67647086395806], +["4sgb",2.1,2.53575386119421], +["1ksl",2.1,2.64637047443917], +["1ge8",2.1,2.27317276479238], +["3p2p",2.1,3.78511796443906], +["1zpb",2.1,2.39374748756253], +["1pzl",2.1,2.66195122121282], +["2aud",2.1,3.38930728679813], +["1vpl",2.1,2.03601711421350], +["1rnf",2.1,2.74474006121396], +["1elb",2.1,2.32006197831323], +["1exf",2.1,1.60162484346036], +["1sc4",2.1,2.39844752710039], +["2c9c",2.1,1.45391608626837], +["1ty8",2.1,2.42283533492349], +["2frn",2.1,3.18611142986434], +["2bej",2.1,2.2678067366931], +["1f5l",2.1,2.10005517980281], +["2fuc",2.1,2.02713030136480], +["1xtz",2.1,2.31087928033583], +["1poe",2.1,3.52966809713831], +["1r5c",2.1,2.08355419387703], +["1txf",2.1,2.59514952241624], +["1tpe",2.1,2.59491030846079], +["3fib",2.1,2.09561539450967], +["1fib",2.1,2.20485338514663], +["1tzf",2.1,2.86818993149739], +["1f2x",2.1,2.41184572952675], +["2c26",2.1,2.07032807735771], +["1k5v",2.1,2.38845070025042], +["1ri5",2.1,2.27898457247501], +["1n4h",2.1,2.46897922815158], +["5ca2",2.1,2.77609002730047], +["4ca2",2.1,2.63040993104911], +["2c3j",2.1,2.90310756428565], +["1y6a",2.1,2.13524006702069], +["1s19",2.1,1.70743417049965], +["1ldf",2.1,2.09342283166095], +["1cim",2.1,2.05134462013526], +["1cin",2.1,1.98478600781903], +["1ydd",2.1,2.87013214596252], +["1zx2",2.1,2.51450235840743], +["1okl",2.1,2.07533580466211], +["1yda",2.1,2.64089043439938], +["1dcb",2.1,2.84330474862466], +["2brh",2.1,2.84260169127482], +["2brg",2.1,2.98940866297103], +["1ljk",2.1,2.44356222971094], +["1gcp",2.1,2.075996376736], +["1e5i",2.1,1.92789468034663], +["1t76",2.1,1.83692673902778], +["1bn1",2.1,2.23836464957836], +["1bn4",2.1,2.39007671393447], +["1djb",2.1,2.71829466857434], +["1lbb",2.1,2.30842530067684], +["1ghl",2.1,2.31082978773472], +["1eou",2.1,2.48420419918169], +["1cay",2.1,2.13534979325146], +["1sd2",2.1,1.92704725484804], +["1y6b",2.1,1.70125017772164], +["1nas",2.1,1.73386876386312], +["1fid",2.1,2.0653933531505], +["1j2z",2.1,2.50441294627108], +["1u0j",2.1,2.74255493510194], +["1jcm",2.1,3.02568696316527], +["1rwo",2.1,2.41080042499855], +["1rwv",2.1,2.44310448771456], +["2a9u",2.1,2.05082715984591], +["1jtt",2.1,1.54924941442283], +["1fdq",2.1,3.28116026488264], +["1m08",2.1,2.5228786469833], +["1s61",2.1,2.53092264310482], +["1iyq",2.1,2.43112631031984], +["1us8",2.1,2.11468317757017], +["2anj",2.1,2.23125399111342], +["2ag8",2.1,2.60416717162260], +["1zg6",2.1,2.67321537666317], +["1ero",2.1,2.73785426016633], +["1z93",2.1,2.69491289439448], +["1z97",2.1,2.874879058563], +["1zrh",2.1,1.83471007297510], +["3vhb",2.1,3.36989206420418], +["3tms",2.1,2.69017156416518], +["1sua",2.1,2.72726124944256], +["1c92",2.1,2.78148066407255], +["1c91",2.1,2.22667485409000], +["1c3f",2.1,2.90291275121685], +["1c93",2.1,3.05782999771368], +["1w6q",2.1,2.82821348697676], +["1tqp",2.1,2.30351799530996], +["1aob",2.1,1.91154021573715], +["1bdu",2.1,2.11795958376152], +["1b7x",2.1,3.14013539144365], +["1yav",2.1,2.22343018920360], +["1eqf",2.1,2.07408778414324], +["1nw7",2.1,2.13902276508080], +["1sw2",2.1,2.35257904493116], +["2brb",2.1,2.58443900844764], +["1zw2",2.1,2.87169663331974], +["2be4",2.1,2.14776123831762], +["1ndh",2.1,3.98239279614417], +["1dm2",2.1,3.00633660897280], +["1h4m",2.1,2.24580204723244], +["1brb",2.1,2.26263230075168], +["2thf",2.1,3.31279941458713], +["1vsb",2.1,2.64938170908797], +["2hex",2.1,2.85614603708278], +["1t80",2.1,2.31271162205467], +["2ac3",2.1,2.58932898683267], +["1thp",2.1,3.32585743784441], +["2bj7",2.1,1.84882284067653], +["2bj8",2.1,2.08039257895428], +["1s1s",2.1,3.03260063968623], +["1ca8",2.1,3.14326636730739], +["1shx",2.1,2.9502918246969], +["2tpi",2.1,2.70329205913059], +["2fk7",2.1,1.61807548239561], +["1dcq",2.1,2.25897531741602], +["1bb0",2.1,3.06952938149751], +["1a80",2.1,2.90244614235929], +["1xr1",2.1,3.38752279492232], +["1bzx",2.1,2.05936847282809], +["1hxf",2.1,3.35626389500494], +["1hxe",2.1,3.51936421952759], +["1h0w",2.1,2.58378685885329], +["7kme",2.1,3.36724056070274], +["1t71",2.1,3.22302519487700], +["8kme",2.1,3.82862461645975], +["1aix",2.1,2.75502442997152], +["1tdh",2.1,1.74977471111820], +["1mq5",2.1,2.60942321267037], +["1mq6",2.1,2.82908885433814], +["1eoj",2.1,2.35655148230442], +["1ktt",2.1,2.67415184463437], +["1eom",2.1,2.02817645408245], +["1f0r",2.1,2.44882421802292], +["1nfw",2.1,3.01316936355241], +["1f0s",2.1,3.05015316792964], +["1eol",2.1,2.38569953794132], +["1d3p",2.1,2.63256393260957], +["1w8w",2.1,1.82663166184621], +["1ksn",2.1,3.00867442711704], +["1c4u",2.1,3.63520710104918], +["1i57",2.1,2.38258680048603], +["1hho",2.1,3.46182732107879], +["1nfy",2.1,2.71532436666298], +["1wdi",2.1,2.31216384045510], +["2f06",2.1,2.84404754472098], +["2f1r",2.1,2.4508924216575], +["1ilr",2.1,2.52843176431274], +["1kwc",2.1,1.93147509650945], +["1j1l",2.1,2.71540445770609], +["2c6o",2.1,3.08727614510608], +["1b39",2.1,2.88474158152402], +["1wz7",2.1,3.26975569813426], +["1xqx",2.1,2.94068621475990], +["2c69",2.1,2.72450208145508], +["5gds",2.1,2.93868486534453], +["1xry",2.1,1.68771148664382], +["1cmt",2.1,1.86030952619202], +["1aee",2.1,1.91452466912074], +["1aet",2.1,1.97414977376657], +["1aeb",2.1,1.94225098562194], +["1aef",2.1,1.94225098562194], +["1aed",2.1,1.9428042572446], +["1aeq",2.1,1.95372132857328], +["1aeg",2.1,1.95425990227409], +["1aej",2.1,1.95425990227409], +["1aeh",2.1,1.96541536459042], +["1ac8",2.1,1.99771463547858], +["1aem",2.1,2.01857924245836], +["1aek",2.1,2.02818802380046], +["1cmu",2.1,2.13982360092124], +["1aes",2.1,2.14884041243985], +["1aev",2.1,2.07981323049572], +["1ccg",2.1,2.38763999747674], +["1aeo",2.1,2.41757217287159], +["1aen",2.1,2.43400034423523], +["1aeu",2.1,2.45768917495763], +["1ac4",2.1,2.47232333502745], +["1ccb",2.1,2.38584757627108], +["1ccj",2.1,1.95159734354883], +["1aa4",2.1,1.97412498577392], +["1a2g",2.1,2.24493668679918], +["1a2f",2.1,2.17485979715361], +["1cck",2.1,2.23777871201795], +["1c4v",2.1,4.15238227126694], +["1a2c",2.1,4.03706153317117], +["1l5y",2.1,1.83975376291207], +["1k3a",2.1,1.98628695386005], +["2bcd",2.1,1.87349508411883], +["1wyw",2.1,1.7610807478244], +["1rjb",2.1,2.18931548713676], +["1xc3",2.1,1.85813301703169], +["1iht",2.1,2.03530889130101], +["1gjr",2.1,2.66179344244445], +["1xms",2.1,2.00152404083246], +["1vpg",2.1,1.57520847747463], +["2fpk",2.1,2.75174758847835], +["1w9y",2.1,2.93947042063317], +["1t9r",2.1,2.06662906878367], +["2b07",2.1,1.36746398027872], +["1c87",2.1,2.52010183542879], +["1wzv",2.1,1.89229449340888], +["1epa",2.1,3.24487877836807], +["1yh6",2.1,2.04900644648182], +["2e2a",2.1,1.83859819301376], +["1esc",2.1,3.28144004420227], +["1qi0",2.1,1.75574276881199], +["1rb7",2.1,1.82934094669716], +["1irk",2.1,2.1100451180134], +["1r3e",2.1,3.41066146087268], +["1ycb",2.1,3.14785946731922], +["1d5r",2.1,3.38583859493602], +["1ut0",2.1,2.62167117783472], +["1lrm",2.1,1.47565003897505], +["1qvs",2.1,1.29764448890820], +["1u4n",2.1,2.3640455152543], +["1tto",2.1,1.47214037380483], +["5pah",2.1,1.90124657421715], +["1tdw",2.1,2.11650586298845], +["16vp",2.1,1.98682031930086], +["2bx6",2.1,2.20630631161516], +["2ac4",2.1,1.80295850737749], +["1qdr",2.1,1.65997693414023], +["1qdt",2.1,1.65727400098286], +["1dyo",2.1,2.58165705802295], +["1bez",2.1,2.08780158859677], +["3phm",2.1,2.6090985915913], +["2cbl",2.1,3.19464588495173], +["1ebm",2.1,2.48800470270728], +["1gkd",2.1,2.19800073283945], +["1a5z",2.1,3.06937157685528], +["1jhh",2.1,2.26007644320670], +["1lww",2.1,2.93610109587897], +["1drt",2.1,2.63584002143364], +["1wm1",2.1,2.23038827741493], +["1by4",2.1,4.1335206763031], +["1gt4",2.1,3.06127841551257], +["1tr7",2.1,2.36586555760200], +["1xgd",2.1,2.21615670974938], +["1bh2",2.1,2.09836439704754], +["1mzs",2.1,2.29943711019908], +["1tde",2.1,2.53199471359519], +["5tli",2.1,2.01206611341927], +["6tli",2.1,2.13638949852844], +["1os0",2.1,1.77309732624077], +["1y3g",2.1,2.61106776979983], +["1jwb",2.1,2.68854468441818], +["1tlx",2.1,2.06122620278902], +["1pta",2.1,2.6880168354231], +["1rb2",2.1,3.12770881925530], +["1c28",2.1,3.39854025670676], +["1vhm",2.1,2.36390340119096], +["1nos",2.1,3.01453562626163], +["1bcw",2.1,3.29076653693944], +["1bng",2.1,2.27287872724924], +["1n41",2.1,2.13919758897157], +["1n42",2.1,2.08853145036195], +["1n00",2.1,3.10487718026485], +["1g8p",2.1,3.02427797399574], +["1j6w",2.1,2.37153704706045], +["2lip",2.1,2.25799123313172], +["1bne",2.1,2.39656511464604], +["1bni",2.1,2.85021528267699], +["1bnj",2.1,2.39215153284183], +["1zjm",2.1,1.62693560287152], +["1bwn",2.1,3.58283321787923], +["1cgf",2.1,2.94676449635166], +["1cz0",2.1,2.15260127453848], +["1mw5",2.1,2.40929664711062], +["1wru",2.1,2.99124455650942], +["2f84",2.1,2.40483725955640], +["175l",2.1,3.00547571693101], +["216l",2.1,3.44399421322669], +["1fcu",2.1,2.52044700251037], +["1uh7",2.1,1.32540371829947], +["1d1g",2.1,2.4432938544626], +["1b8v",2.1,1.92830189070221], +["1y25",2.1,2.10728725619334], +["1nmk",2.1,1.94890962571593], +["5apr",2.1,1.64290506175573], +["1fqf",2.1,2.43337151507424], +["1n7x",2.1,2.19675903124314], +["1nft",2.1,2.45678045701932], +["1w03",2.1,2.07938089105036], +["1ldm",2.1,3.54637522247627], +["4ape",2.1,3.30897048854485], +["2f2l",2.1,1.52454097699242], +["1cz3",2.1,2.45368618661836], +["1sed",2.1,1.85959921197262], +["1b62",2.1,2.69503901869527], +["1nv2",2.1,2.83715677736113], +["2f6m",2.1,2.17164144051804], +["1dw3",2.1,1.88374147801745], +["1jce",2.1,2.15448751528537], +["2nrd",2.1,2.38664344894471], +["1pzm",2.1,1.84514872175628], +["1pqz",2.1,3.14958491926417], +["2bal",2.1,2.02103459655369], +["1sbn",2.1,3.52629715936057], +["1qzz",2.1,2.59868571904125], +["1ndt",2.1,1.80911782873977], +["1jcf",2.1,1.83897035036386], +["2sni",2.1,2.44534274205298], +["1re8",2.1,2.29766720872315], +["1eag",2.1,2.73058714416601], +["1bx6",2.1,4.26952698053018], +["1e54",2.1,2.66910341914512], +["4er4",2.1,3.33138576322196], +["2a5w",2.1,1.8568348489373], +["1vj1",2.1,1.83898317943269], +["1fs0",2.1,2.28675812804151], +["1zax",2.1,2.53302705769626], +["2cau",2.1,2.566994580792], +["1sb8",2.1,1.63774066266481], +["1qnh",2.1,1.73130862438234], +["1jxl",2.1,2.33509804647473], +["1s10",2.1,2.48962024608469], +["1how",2.1,2.67392933628854], +["1zz7",2.1,2.34523747035985], +["1z18",2.1,2.23746554510802], +["1hh2",2.1,3.77115359850881], +["1xaa",2.1,2.13903273737438], +["1xab",2.1,2.35738589777273], +["1g2u",2.1,2.36903757114105], +["1xad",2.1,3.1355638747946], +["1xac",2.1,3.15692593790856], +["1l4g",2.1,2.34555549730053], +["1l4h",2.1,2.19263181257493], +["1l4f",2.1,2.32903808143768], +["1v9n",2.1,2.54675005910131], +["1gp4",2.1,1.68294176329252], +["1ic7",2.1,2.46384650973161], +["1s4u",2.1,2.81318978143821], +["1r2j",2.1,2.97565789485418], +["1b6r",2.1,3.22147415944029], +["1wph",2.1,2.16699624121624], +["1kip",2.1,2.78452569573228], +["1ove",2.1,2.29983062197020], +["3erk",2.1,3.50638869786932], +["1p38",2.1,2.53631771898438], +["1nzf",2.1,2.10444372188976], +["1poo",2.1,2.91089070022905], +["1q61",2.1,1.94643781268838], +["1pkj",2.1,2.03728557077441], +["1jl5",2.1,2.99171955801963], +["1hx3",2.1,2.39737240580198], +["1vhr",2.1,2.12375234385458], +["1axi",2.1,2.47469753984097], +["1pno",2.1,2.35844649022058], +["1gwn",2.1,2.47801727338659], +["1l1n",2.1,2.3898381955363], +["1mdr",2.1,1.96573513026673], +["1dtn",2.1,2.53078547329148], +["1mra",2.1,3.26297873161816], +["1g64",2.1,3.38508060776561], +["1lg2",2.1,1.93221884427559], +["1jph",2.1,1.78801816554634], +["1okg",2.1,2.74033780753754], +["1y54",2.1,3.33968999666457], +["1yhk",2.1,1.71505929595020], +["2jdw",2.1,2.35259791585121], +["1pjb",2.1,2.92023706882350], +["1say",2.1,2.94686782461814], +["2esc",2.1,2.69865690942981], +["1xrv",2.1,2.90239222277489], +["1nvp",2.1,2.48429334759976], +["1xqe",2.1,1.58059339988948], +["2ald",2.1,2.83244530847036], +["1x9z",2.1,2.37038246874852], +["1xdg",2.1,1.94304679934898], +["2gan",2.1,2.97640440266794], +["1q65",2.1,2.68399657236171], +["1as4",2.1,1.76124496667579], +["1pea",2.1,2.94092385312767], +["1qn8",2.1,2.23913526715017], +["1qn6",2.1,2.18601862287287], +["1mpc",2.1,1.82852543499142], +["3sdp",2.1,4.64022894850684], +["1n2v",2.1,2.71754132488818], +["1dy9",2.1,2.78162096266616], +["1ais",2.1,3.07974643453412], +["1zvd",2.1,2.58944091067224], +["2gc3",2.1,1.70945398781424], +["2gc2",2.1,2.19600267314996], +["1nd7",2.1,3.56629419290596], +["1sek",2.1,3.2750744215095], +["1xmx",2.1,2.51075046196588], +["1hp7",2.1,2.74502158401405], +["1s2m",2.1,1.68218039757012], +["1rk1",2.1,2.10899001058679], +["1vok",2.1,2.89960913917799], +["2yhx",2.1,4.53728442676397], +["1dvn",2.1,2.91668896971500], +["1agc",2.1,2.12827738596571], +["2a8t",2.1,2.38857316126479], +["1jge",2.1,1.88381568208307], +["2bst",2.1,2.27420944186569], +["1u20",2.1,2.17629780380885], +["1ffg",2.1,1.88924586737846], +["1grn",2.1,2.33807848369104], +["1fcf",2.1,3.54029212541783], +["1pie",2.1,3.40835635423788], +["1kk2",2.1,2.31942920542511], +["1pdh",2.1,2.12745820729675], +["1smc",2.1,1.36239942945269], +["1n5k",2.1,2.08135198909618], +["1pxc",2.1,1.96849908422028], +["1dod",2.1,2.23034302982326], +["1w2g",2.1,2.16265179427328], +["1amr",2.1,3.01613413634903], +["1rbz",2.1,2.01048384702404], +["1lrz",2.1,1.79814161770892], +["1htd",2.1,2.42630464416196], +["1g6n",2.1,2.45296780539845], +["1aox",2.1,2.85724969702752], +["2f5u",2.1,2.64888177305127], +["1a0f",2.1,2.46206695087378], +["1d7y",2.1,2.71688198707270], +["1jio",2.1,2.59998394850335], +["1o64",2.1,2.44518050725319], +["1zrf",2.1,1.83900825672600], +["1tmk",2.1,2.18943383486023], +["1pkf",2.1,2.55647142711], +["1eup",2.1,2.60344589686189], +["1yjz",2.1,2.52237917220099], +["2cp4",2.1,2.47556371674467], +["8cpp",2.1,2.22693540046760], +["4cp4",2.1,2.38451368600536], +["1w7k",2.1,2.56382552675272], +["1mjo",2.1,2.83759756586444], +["1gir",2.1,2.71619591725765], +["1eog",2.1,2.52636207783074], +["1zgn",2.1,2.07597479400647], +["12gs",2.1,2.47568459538698], +["1md4",2.1,2.29677960126967], +["1cw4",2.1,2.21107059394982], +["1cw1",2.1,2.24671507389927], +["4pgt",2.1,2.87062779626417], +["1exb",2.1,2.16974853229276], +["1vjc",2.1,2.28201925682904], +["1yrt",2.1,3.18918154781071], +["1c3e",2.1,2.74031609294605], +["1c2t",2.1,2.76495712381966], +["1px6",2.1,2.19495711324715], +["1o5z",2.1,2.42365772056888], +["1mfb",2.1,2.38129416711086], +["1mfd",2.1,2.45081164019268], +["1mfc",2.1,2.56426567168992], +["1qw6",2.1,2.9418292131184], +["1mh3",2.1,2.33863785308294], +["1knw",2.1,2.09588179241220], +["1fxw",2.1,2.77527968942575], +["1dqm",2.1,3.05007783146127], +["1jep",2.1,2.05791601576744], +["1df9",2.1,4.05759172061034], +["2f2g",2.1,1.88224570513001], +["1sz9",2.1,2.44882812714637], +["1sqf",2.1,2.84679124959478], +["1twr",2.1,2.38835089253555], +["2b6c",2.1,2.05639527167754], +["1c5b",2.1,2.66623857827561], +["2bg7",2.1,2.29970457606818], +["1pkz",2.1,1.9715321682597], +["2dkb",2.1,2.53549107304205], +["2rcs",2.1,2.24321705263396], +["1aj7",2.1,2.31507485649624], +["1lon",2.1,2.54626689383471], +["1ah8",2.1,2.65525441734262], +["1dqd",2.1,3.23702411238899], +["1ykc",2.1,2.3692410138692], +["1ve3",2.1,2.46449834205625], +["1clo",2.1,2.90643655102632], +["2ajy",2.1,2.50673924958833], +["2c9z",2.1,2.07336761311660], +["1jg3",2.1,1.79850115471925], +["1ynk",2.1,2.99126878688355], +["1l7t",2.1,2.70694329938517], +["1r8a",2.1,2.28167378713972], +["1u2o",2.1,2.20438615623989], +["1p3r",2.1,2.47810038159893], +["1yek",2.1,2.70251274570009], +["1pt2",2.1,1.57299436440593], +["1wlr",2.1,1.28867743308824], +["1npm",2.1,2.43104853972558], +["1u8h",2.1,2.70385584146439], +["1d0h",2.1,2.90948304732014], +["2aej",2.1,2.61371326733091], +["1a3r",2.1,1.63949903963614], +["1qs4",2.1,2.39626807561449], +["1kmb",2.1,1.93395640400979], +["1gxz",2.1,1.71095899273276], +["2axn",2.1,2.56761292568929], +["1wt5",2.1,2.99645417425882], +["1nhr",2.1,2.09050601587212], +["3aop",2.1,2.16971727370586], +["1l0p",2.1,1.82404302671357], +["1i4g",2.1,2.66951654073637], +["1e9x",2.1,2.26180074706721], +["3geo",2.1,2.24667709393380], +["5gep",2.1,2.36810117026670], +["1bqp",2.1,2.49014233714497], +["1log",2.1,2.66629534951041], +["1e0p",2.1,1.83751562224808], +["3bct",2.1,1.83821590310447], +["1a31",2.1,2.80868734311091], +["1soq",2.1,2.14024908854952], +["1rv5",2.1,2.73385936935661], +["1w5d",2.1,3.09528501638773], +["1bcj",2.1,2.14405256185262], +["1tjh",2.1,2.46165207878678], +["1u5g",2.1,2.70315737626322], +["1bwc",2.1,2.48180623889567], +["1go7",2.1,1.43592365451252], +["2a9m",2.1,2.6057207586993], +["1z59",2.1,1.83656284788576], +["1nr6",2.1,2.56530232157968], +["1q3a",2.1,3.76396676620764], +["2f20",2.1,2.46111092434167], +["1z5n",2.1,2.35217000879900], +["1x8c",2.1,2.52360815295801], +["1xxl",2.1,1.84171593824974], +["1tj0",2.1,2.02329530002950], +["1w1b",2.1,2.22209579900462], +["1rjr",2.1,1.70752047457694], +["1s2l",2.1,2.55216230134867], +["6taa",2.1,3.29171300355746], +["2aaa",2.1,2.94197342319144], +["1qwt",2.1,2.56697967422909], +["1n3p",2.1,1.78732833212094], +["1wp6",2.1,1.94139787591173], +["1w9x",2.1,1.89341434411708], +["1xtg",2.1,2.6026034194955], +["1wox",2.1,1.99115684019871], +["1kws",2.1,1.87096623526525], +["1lru",2.1,2.820127240097], +["1xuv",2.1,2.85162408836991], +["1qq6",2.1,1.63246016545375], +["1stx",2.1,2.77344818829252], +["1rid",2.1,4.22969224216581], +["1rvc",2.1,1.81797137475940], +["1rvb",2.1,2.04535896973839], +["1zdt",2.1,2.57334321283831], +["1s2d",2.1,2.07265749563926], +["1g27",2.1,3.05676166082456], +["1q6f",2.1,2.59927846493647], +["1s2g",2.1,2.48183374749887], +["2c6e",2.1,2.74642446136141], +["1bry",2.1,1.67479932442215], +["1j9k",2.1,2.37057402784809], +["1yvn",2.1,2.6944202268107], +["1tpd",2.1,2.43633538125505], +["1nm9",2.1,1.82187922906302], +["1kb3",2.1,2.67987543590008], +["1kgw",2.1,2.4441425643752], +["1huc",2.1,2.84174036137568], +["1ici",2.1,2.19535452975973], +["1sw6",2.1,2.68331472628812], +["1isi",2.1,2.40684959870484], +["1hp5",2.1,1.84912577983696], +["1m01",2.1,1.64744761011933], +["1qd6",2.1,2.51346095867184], +["1z98",2.1,2.42802474856373], +["1qfe",2.1,1.91384234244860], +["1qyr",2.1,2.13351031409506], +["1bs6",2.1,2.98870726975499], +["1cte",2.1,3.02732779408869], +["1otv",2.1,2.33990829521078], +["1wmg",2.1,2.93247468665184], +["3azu",2.1,2.27508506737945], +["1lrn",2.1,2.1730098554096], +["1chq",2.1,3.05794298175424], +["1nd4",2.1,2.12405484933038], +["1u4d",2.1,2.11188602862815], +["1b8f",2.1,2.77690032578828], +["1m4y",2.1,1.86013679246915], +["1em8",2.1,1.84233483257119], +["1fzr",2.1,2.30003497442740], +["1z1n",2.1,2.93512507082083], +["1x89",2.1,2.65925746254735], +["1z54",2.1,2.46115802901045], +["1x71",2.1,2.58603450022026], +["1k2p",2.1,3.68012432617534], +["1syi",2.1,2.2318548728048], +["1itc",2.1,2.04590838306351], +["1b9z",2.1,2.44371860148216], +["1y7i",2.1,2.75854382320388], +["1eb8",2.1,2.42790386886866], +["1eb9",2.1,2.43111434246800], +["1e89",2.1,2.42173490275019], +["1olc",2.1,2.45296761573433], +["2az5",2.1,2.20446750777763], +["1xlw",2.1,2.21044287066716], +["1d6a",2.1,2.37425929877297], +["1qcg",2.1,2.58966584194254], +["1qcj",2.1,2.96964182610249], +["1wxd",2.1,2.4364592873578], +["1fm9",2.1,3.28357405375744], +["1c90",2.1,2.75118926912347], +["1wng",2.1,1.77771038889877], +["1vce",2.1,2.09903628487041], +["1tlc",2.1,2.79766885021874], +["1un1",2.1,2.45037744068970], +["1dea",2.1,2.42279960809374], +["1yhc",2.1,1.89565962577812], +["1e66",2.1,2.16155997970378], +["1qif",2.1,2.43991142129239], +["1qie",2.1,2.53500630608463], +["1trh",2.1,2.16647902624806], +["1xqr",2.1,2.24993939120752], +["1v18",2.1,2.18887597381603], +["1aui",2.1,2.51060971361245], +["1s4m",2.1,2.72491141211723], +["1ba2",2.1,2.16356188445454], +["1doh",2.1,2.14938658532901], +["2hhm",2.1,2.36442368080114], +["2gac",2.1,2.41943594129168], +["1hwu",2.1,2.44565418140336], +["1iep",2.1,2.72706657748708], +["2ahs",2.1,1.56225805238718], +["1xgu",2.1,2.54597169358570], +["1ndm",2.1,2.73115864354694], +["1xgp",2.1,2.65076397546124], +["1xgr",2.1,2.41604369811916], +["1xgt",2.1,2.42269698629743], +["1xgq",2.1,2.54407184245294], +["1n2o",2.1,1.70430978189185], +["2fiy",2.1,2.54715128044174], +["9gaa",2.1,2.45338279575704], +["2daa",2.1,2.35964523149306], +["1yto",2.1,2.31522200063816], +["1vbj",2.1,3.01282766900318], +["1bo6",2.1,2.74505524951968], +["2f98",2.1,2.18009273017149], +["1y44",2.1,2.52459617521942], +["1huj",2.1,2.84709440520872], +["1efv",2.1,2.07808296453696], +["1vi2",2.1,2.47977988534482], +["1a3q",2.1,3.30370163980526], +["1k4t",2.1,2.55452949151679], +["2fjm",2.1,2.23546087223304], +["1t08",2.1,2.03193312430619], +["1y0d",2.1,2.39705416158211], +["1jeb",2.1,2.41565565714144], +["1p2h",2.1,2.96995253138921], +["1y7g",2.1,2.6672512167768], +["1y7c",2.1,2.70345688407763], +["1yhe",2.1,2.0575268289275], +["1y4b",2.1,2.12611659716086], +["1hba",2.1,2.36783412695291], +["1nej",2.1,2.89965255525531], +["1dke",2.1,2.58689111681278], +["1hga",2.1,2.93233987485303], +["1gzx",2.1,3.1786091684565], +["1hgc",2.1,3.09647920070954], +["1hgb",2.1,3.06947780866482], +["1ep3",2.1,2.74629595421761], +["1m1e",2.1,1.90163011831058], +["1ca0",2.1,2.66742796035115], +["1jwn",2.1,1.86678823958292], +["1b27",2.1,2.40169729151008], +["1b2u",2.1,2.33135599578661], +["1vnc",2.1,2.43081030164331], +["1iim",2.1,2.24394645469488], +["1q6n",2.1,2.71394489304324], +["1ua0",2.1,2.52971983802374], +["1it3",2.1,3.2786980311956], +["1fjm",2.1,2.07632973345878], +["1u48",2.1,2.09770161807848], +["1nk5",2.1,2.01146350354602], +["1nk6",2.1,1.89136731144769], +["2g09",2.1,1.76755562923000], +["1tht",2.1,2.53453443988616], +["1fak",2.1,3.23879899852909], +["1h3i",2.1,3.2409588321213], +["1xv1",2.1,2.05971982879342], +["1dt0",2.1,3.22763689177415], +["1x1w",2.1,2.56966264931148], +["1o87",2.1,2.05647334844644], +["1jfz",2.1,3.62560738460747], +["1uld",2.1,2.48305024978022], +["1kfs",2.1,2.94542023235315], +["1pyw",2.1,2.33511665854009], +["1w8n",2.1,1.86326448528184], +["1v1a",2.1,3.27254599704868], +["1nhx",2.1,1.94253675551311], +["1ut9",2.1,2.58572527634578], +["1p7c",2.1,2.60019662401838], +["1nez",2.1,3.11085253840856], +["2abq",2.1,3.22380834885966], +["1h19",2.1,2.35788410575664], +["1lhp",2.1,2.07718116226234], +["1u5q",2.1,2.84721328639123], +["1u5r",2.1,2.87374906046491], +["1uxh",2.1,2.32517029120012], +["1uxi",2.1,2.39237229936928], +["2fv7",2.1,1.70124714884526], +["1dkd",2.1,2.38132146334698], +["2b2n",2.1,2.45512105153896], +["1jqv",2.1,1.87679496978055], +["1vj7",2.1,2.85669513905706], +["2dex",2.1,2.62574302873018], +["5fbp",2.1,2.33712542168572], +["2dew",2.1,2.74203119430876], +["1n1v",2.1,2.32233821700733], +["1ziw",2.1,2.48626303864403], +["1fpf",2.1,2.51976052892646], +["1fpd",2.1,2.36668000031497], +["1mw1",2.1,2.19186132173152], +["1mw2",2.1,2.28226413668253], +["1m98",2.1,2.62589719452164], +["1nf3",2.1,2.27055828202259], +["2cwn",2.1,2.19473540190933], +["1i2r",2.1,1.71240756399451], +["1tcb",2.1,1.66405837646518], +["1uj3",2.1,2.50809156897026], +["1fq0",2.1,2.20387041871553], +["1hp0",2.1,2.23494430629631], +["1gjw",2.1,2.20181049291649], +["1oil",2.1,2.41485838642741], +["1f06",2.1,2.68483497775426], +["2fme",2.1,2.95743208582681], +["2fsk",2.1,2.08283056005917], +["1y2e",2.1,1.34432597470277], +["2aep",2.1,2.11865386016771], +["1p72",2.1,2.24063841996102], +["2bjg",2.1,2.87786319613877], +["1r8k",2.1,2.4906284211896], +["1acc",2.1,2.79848026149458], +["1ic0",2.1,2.53327101586377], +["1v8g",2.1,2.08719173476798], +["1dpm",2.1,2.61349818895742], +["1irj",2.1,2.69952874279387], +["1i0z",2.1,2.47151520044360], +["1hzp",2.1,2.44559687982436], +["1mzj",2.1,3.59056415496843], +["1qmh",2.1,2.51013377145051], +["1ph6",2.1,2.4225929232003], +["1ii6",2.1,3.07334555097941], +["1hm3",2.1,2.35618101526688], +["1q41",2.1,2.15200221205399], +["1svv",2.1,1.77521597046364], +["1b77",2.1,2.22232737547890], +["1s0o",2.1,2.47153258437828], +["1x8l",2.1,1.81180682250187], +["1qdw",2.1,2.45720626528081], +["1cxe",2.1,2.35044632548591], +["1pr6",2.1,2.2870507730387], +["1kam",2.1,2.62653226631314], +["1lfi",2.1,3.86425681943908], +["1n8i",2.1,1.96931062195393], +["1x7x",2.1,1.88181052162256], +["1eud",2.1,2.28613709770178], +["1dmt",2.1,2.31245541597103], +["1euc",2.1,2.33123041292517], +["1jrg",2.1,2.85576269218904], +["1qht",2.1,3.65887169129786], +["1a69",2.1,3.13088774933601], +["1wz9",2.1,2.21452851285782], +["1yyq",2.1,2.14904460162521], +["1s7n",2.1,2.43745941646392], +["1ga9",2.1,2.47553518271061], +["1m8t",2.1,3.08703973779314], +["1zkd",2.1,1.96219617713338], +["1w61",2.1,1.94835915383704], +["2cog",2.1,2.65898216033222], +["1mma",2.1,3.7906952865817], +["1y5x",2.1,2.57929114464376], +["1uoq",2.1,2.03877800388346], +["1o1t",2.1,2.12313167563217], +["1j1c",2.1,2.85774394712344], +["1w6k",2.1,2.08542440155728], +["1sa4",2.1,1.74850032456842], +["1hgw",2.1,2.20301810503977], +["1qk0",2.1,2.24152873879782], +["1mmn",2.1,3.09637577986033], +["1kzp",2.1,1.99880993833576], +["1yxa",2.1,1.99098135031852], +["1fmv",2.1,3.15921361163290], +["1wue",2.1,2.61412208149549], +["1o62",2.1,1.88157869772403], +["2a0u",2.1,2.01631769134775], +["1mkf",2.1,2.76168451192587], +["2aro",2.1,2.34358310996917], +["1dju",2.1,2.7970693032795], +["1vrp",2.1,2.57043953979857], +["2c7n",2.1,2.48799746924392], +["1h5w",2.1,2.64151255260531], +["1na6",2.1,2.91611527688864], +["1tk9",2.1,2.32169824789067], +["2oxi",2.1,2.29453212073059], +["1hld",2.1,2.38631399649602], +["1r31",2.1,2.38020464744696], +["1yad",2.1,2.24469758987528], +["1mh5",2.1,3.24622482568986], +["1qlv",2.1,3.07034338874024], +["1od5",2.1,2.89771874817471], +["1x1j",2.1,2.57999500293385], +["5acn",2.1,2.80474969413111], +["1s16",2.1,2.32570487567217], +["1hsa",2.1,2.13244782798012], +["1ou0",2.1,2.81241682005275], +["1mhc",2.1,2.74467109510192], +["1p3w",2.1,2.63547667289407], +["1pjh",2.1,1.94519210779349], +["1x9m",2.1,2.42568134267793], +["1j32",2.1,2.23194729666299], +["1nr5",2.1,2.61020459034851], +["2bes",2.1,1.43561494007169], +["1kxp",2.1,1.99058353568675], +["1oqm",2.1,2.54666433136761], +["1axk",2.1,2.19203931174433], +["1wno",2.1,2.4571572697547], +["2a3a",2.1,1.74422091676129], +["1m4h",2.1,2.16755331908115], +["1s3t",2.1,1.74954122512831], +["1bqd",2.1,3.10192398529898], +["1bqa",2.1,2.93511204790531], +["1fdp",2.1,2.97701666976368], +["1r6t",2.1,2.19378449354116], +["1aka",2.1,2.55333747979232], +["1ef0",2.1,3.24151092005169], +["1v9s",2.1,2.43610700840433], +["1p4g",2.1,2.51872053169139], +["1xl1",2.1,2.43011556860668], +["1s08",2.1,2.44413331813231], +["2cun",2.1,2.60566796529737], +["2a1m",2.1,2.39681645932947], +["1c8j",2.1,2.70535537657385], +["3amv",2.1,2.69126943344731], +["1obc",2.1,1.69456825257856], +["2fn1",2.1,2.261659964882], +["1d7k",2.1,3.15070144011857], +["1c3h",2.1,3.23728684750128], +["1vew",2.1,1.55634838756093], +["1f1s",2.1,2.97555298011877], +["1ry5",2.1,2.18255672470941], +["1qov",2.1,1.93584554943006], +["1kkr",2.1,2.65286403911553], +["1sz0",2.1,3.24518075108421], +["1yzy",2.1,2.51277147533809], +["1pj7",2.1,1.89085599534276], +["1ztc",2.1,1.71347123724169], +["1foj",2.1,2.61985867058107], +["1dm7",2.1,2.63170611349267], +["3nse",2.1,2.50517436238443], +["1z88",2.1,1.45712300425154], +["1z94",2.1,2.74675416287258], +["1rg1",2.1,2.30037117647638], +["1jva",2.1,2.71820483520482], +["1mjj",2.1,2.44034982858370], +["1ofu",2.1,2.61578082909098], +["1rg2",2.1,2.33096007979057], +["1n8q",2.1,3.04428683707208], +["1jnq",2.1,3.57872670760965], +["1hei",2.1,3.57102008030319], +["1w6t",2.1,1.76830369296688], +["1vgr",2.1,2.7047670336396], +["1nc2",2.1,1.89163891406749], +["1jqh",2.1,2.77496561886973], +["1mgv",2.1,2.73504709152788], +["1cqd",2.1,2.45763700854142], +["1o28",2.1,2.19917137476309], +["1iwe",2.1,2.76641537241642], +["1msw",2.1,3.68242368174062], +["1ni6",2.1,2.67326838245766], +["1kar",2.1,2.41631230541377], +["1a4j",2.1,3.54587386762309], +["1ee4",2.1,1.83914836640980], +["1kah",2.1,2.52485068010512], +["1brw",2.1,2.23961001675121], +["1fl5",2.1,2.9008087958679], +["1isy",2.1,1.93118713608413], +["1v6v",2.1,2.10831802072030], +["1isv",2.1,2.09893688213014], +["1v6x",2.1,2.20095983516517], +["1v6u",2.1,2.24664363969884], +["1isx",2.1,2.27264180778104], +["1isw",2.1,2.46067118725727], +["1ebg",2.1,2.55452625711371], +["1yzw",2.1,1.27089683757355], +["1i1k",2.1,2.5263652677262], +["1i4z",2.1,3.03489012477425], +["1hv9",2.1,2.94026548635784], +["1pq9",2.1,2.19388519923841], +["2ew8",2.1,1.93750933990561], +["1wn3",2.1,1.96019584241336], +["1tug",2.1,3.73913151785875], +["1d09",2.1,3.29514892807762], +["1s7m",2.1,2.52551567196697], +["1n78",2.1,2.64336200208193], +["1rla",2.1,2.52099640287716], +["2c7i",2.1,2.58030470982980], +["1g5c",2.1,2.5800784764337], +["2f9o",2.1,2.39487717261554], +["1nfr",2.1,2.17262895736431], +["1xc6",2.1,1.87903907613393], +["1e56",2.1,2.53206510252191], +["1e4n",2.1,2.55677380977895], +["1mhh",2.1,2.37505297304928], +["2g39",2.1,2.07898627908162], +["1yi8",2.1,3.68678231862942], +["1w1p",2.1,2.06067442788064], +["1va6",2.1,2.18705005913618], +["1l9w",2.1,2.60811732557923], +["1q4q",2.1,3.32232100498068], +["1rm5",2.1,2.37827291616949], +["1g3j",2.1,1.86189380756522], +["1n0t",2.1,1.98114708031542], +["2bgj",2.1,2.49624923412642], +["1ukc",2.1,1.94917096217870], +["1p1k",2.1,2.86835724185409], +["1ho5",2.1,2.91484830515995], +["1fm6",2.1,3.56011161517146], +["1oi8",2.1,1.94558253420098], +["1zgc",2.1,2.38268708388946], +["1h9x",2.1,2.30890396631756], +["1jvn",2.1,2.02306625517150], +["1bkh",2.1,2.41636489880024], +["1ujq",2.1,2.21103859369042], +["1xkq",2.1,2.44839603419068], +["1lnw",2.1,2.74753056041939], +["1izn",2.1,2.89413937468604], +["1j3k",2.1,2.31201647899048], +["1rr9",2.1,3.1252898495599], +["1e8g",2.1,2.36843417414999], +["1q7m",2.1,2.78698895542393], +["1qr6",2.1,3.76066424861764], +["1h1p",2.1,2.92014380131031], +["2c5t",2.1,2.99312767185251], +["2c5o",2.1,3.08628839216011], +["2c5n",2.1,3.17683783638437], +["1hox",2.1,2.75506413572611], +["2ax1",2.1,1.51722585416143], +["1ehy",2.1,2.38458439798009], +["1w73",2.1,2.18908595396580], +["1s2v",2.1,2.69665197434475], +["2bht",2.1,4.01884110943493], +["1u2e",2.1,2.82527600823224], +["1ve6",2.1,2.18670848711762], +["1iin",2.1,2.03837847574028], +["1w3n",2.1,2.09970994175890], +["1w3t",2.1,2.12557642744309], +["1pox",2.1,1.51349927853280], +["1fwk",2.1,2.82729734122933], +["1vk0",2.1,2.04007886959262], +["2esn",2.1,2.77260052846867], +["1xmd",2.1,2.07871324907868], +["1h3g",2.1,2.51878311310267], +["1rz1",2.1,2.16141318724817], +["1hqz",2.1,2.37498040303665], +["1izo",2.1,2.97733862919743], +["1ivv",2.1,2.55262202970887], +["1ib6",2.1,2.70653655927181], +["1yup",2.1,3.08064493308482], +["1o68",2.1,1.75916129432747], +["1k8c",2.1,1.99754091624227], +["1q0c",2.1,2.12917278474036], +["1ek9",2.1,3.11022458706858], +["1t6j",2.1,3.11890222573289], +["1tg6",2.1,2.84706848815868], +["1g9a",2.1,2.28305338553565], +["1rzt",2.1,2.19078437024268], +["1tz2",2.1,2.33829825542871], +["1zkn",2.1,2.17380526088887], +["1cf2",2.1,2.14093007457225], +["1l9n",2.1,2.41470363365886], +["1rle",2.1,2.30213697476372], +["1l9m",2.1,2.72956597307279], +["1umb",2.1,2.00099053088007], +["2aq1",2.1,2.78168094043242], +["1v3l",2.1,2.16960678353802], +["1h81",2.1,2.50535461678415], +["1q0k",2.1,1.64577552064457], +["2a1f",2.1,2.08242891075952], +["1odl",2.1,1.87865823435089], +["1ggu",2.1,3.02345052713332], +["2ccd",2.1,2.58852735524188], +["1d6z",2.1,2.40041253673329], +["1f13",2.1,2.48818701664185], +["1fdj",2.1,2.83955360698606], +["1x70",2.1,2.2003080039174], +["1nu6",2.1,2.95637102283408], +["1sjc",2.1,3.29044607883022], +["1utd",2.1,2.19546402436705], +["1dof",2.1,2.39715632530725], +["1j1z",2.1,2.42589694414457], +["1mj3",2.1,2.24019288433031], +["1wb9",2.1,2.04917753255164], +["2bl2",2.1,1.92157065431222], +["1q3k",2.1,2.66674493195633], +["1yir",2.1,2.61492236043439], +["1hw8",2.1,2.09924551998036], +["1fzd",2.1,3.27471546875604], +["1l5r",2.1,2.70588543582951], +["1l5s",2.1,2.67960007463804], +["2bwn",2.1,1.81108043873306], +["1hwl",2.1,2.33695468178897], +["1ei6",2.1,2.88957912725652], +["1xoi",2.1,2.99838134813216], +["1tbg",2.1,3.10680406355296], +["1igw",2.1,2.56610904980429], +["1dq8",2.1,2.61349401320968], +["2a5h",2.1,3.02893445843994], +["1de6",2.1,2.85503446453435], +["1oxk",2.1,2.29347956046177], +["2rma",2.1,2.35324550036257], +["2rmb",2.1,2.39170468342058], +["1szs",2.1,2.21412588950882], +["2cw6",2.1,2.87405189422132], +["1l8p",2.1,1.99040836731655], +["1iwp",2.1,2.94818094384896], +["1tju",2.1,2.19578720551261], +["1wcq",2.1,1.95438141255178], +["1uf3",2.1,2.54782882086281], +["1c7g",2.1,2.77427924742926], +["1ax4",2.1,2.41151698343741], +["1wnd",2.1,2.32202792936110], +["1s3q",2.1,2.25008950467962], +["1vkd",2.1,2.16912276415046], +["1ukp",2.1,2.25393033887529], +["1uko",2.1,2.57283655443354], +["1uhv",2.1,2.95868724578545], +["1ez0",2.1,1.75189200181368], +["2d4e",2.1,1.93076653021634], +["1j0y",2.1,2.15582249173076], +["1j10",2.1,2.22776586889863], +["1j12",2.1,2.38308872414183], +["2d83",2.1,2.26711756625994], +["1xmg",2.1,2.68375893141224], +["1fz8",2.1,2.43395802406884], +["2fbw",2.1,2.09330703154269], +["1pj3",2.1,2.61555434595296], +["1z7d",2.1,2.66528389343675], +["1pk8",2.1,2.04872776645379], +["1tue",2.1,2.19609485637367], +["2afh",2.1,2.45313283959587], +["3pcd",2.1,2.41918462062537], +["2bvc",2.1,1.40384644572831], +["1tkk",2.1,2.33661566268687], +["1r9m",2.1,2.74912396577951], +["1a8r",2.1,2.15773588933045], +["1gqo",2.1,2.78879881511876], +["1e5q",2.1,1.93714836863552], +["1wyu",2.1,2.57693897806718], +["1vlq",2.1,1.41494219465336], +["1ppj",2.1,2.08441328333425], +["1pp9",2.1,2.03637604187216], +["1jz4",2.1,2.73305530226446], +["1jz6",2.1,2.96071988149545], +["1jz2",2.1,2.9966219513995], +["1a49",2.1,3.30620290983717], +["1xsj",2.1,2.33382955373269], +["1yrq",2.1,2.16566442210926], +["1zum",2.1,1.94047069941845], +["1m6v",2.1,3.07678711038168], +["1kee",2.1,2.8429592304474], +["1t36",2.1,2.97881668506350], +["1ce8",2.1,3.02411803175633], +["1c3o",2.1,2.91621043182752], +["1bxr",2.1,3.14691110393916], +["2bjo",2.1,2.06215350852970], +["1rby",2.1,2.17746766071459], +["1m46",2.1,1.61976485199599], +["1tvl",2.1,2.09491382544915], +["1rbq",2.1,2.01003983152982], +["2b6x",2.11,1.85133592742501], +["1t6m",2.11,3.06342607757083], +["1ttz",2.11,2.50228797112548], +["1wwp",2.11,2.85634053363806], +["2dca",2.11,2.64406132063968], +["2f4z",2.11,2.48857947121104], +["2b59",2.11,2.67208928879722], +["4cpp",2.11,2.51795316984869], +["2gsr",2.11,2.23533013730017], +["1uou",2.11,2.37681827669363], +["1h6n",2.11,2.33767776253594], +["2c36",2.11,2.31842167508817], +["1yev",2.11,2.36549122732122], +["1rq4",2.11,2.26983316221834], +["1xzv",2.11,2.47864236641567], +["1xz5",2.11,2.44560051017979], +["1rqa",2.11,2.22252397296751], +["1y4q",2.11,2.52321097299452], +["1rps",2.11,2.10473973772178], +["1vnh",2.11,1.90666207201499], +["1q99",2.11,2.74093646252221], +["1h0k",2.11,1.5134775659279], +["1zq7",2.11,2.33880790940263], +["1od0",2.11,2.24913349975031], +["2ey4",2.11,2.71699863903218], +["1mb9",2.11,2.55098001815386], +["2bel",2.11,1.85092090786811], +["2f36",2.11,2.31733620833787], +["1nq5",2.11,2.1813677400931], +["1y1r",2.11,2.07871296978394], +["1ngk",2.11,2.52609128790372], +["1yp2",2.11,2.76200012810557], +["1u0u",2.11,3.28765099985899], +["2aj8",2.11,2.57401962412417], +["1xa5",2.12,2.05999458916827], +["1cv0",2.12,2.29347893427102], +["1cu3",2.12,2.53495092623800], +["1d3m",2.12,2.63113606124355], +["1yc3",2.12,2.5223853315913], +["1lva",2.12,2.56257081266345], +["1je8",2.12,2.37244299201577], +["1a46",2.12,3.16221151246487], +["1e06",2.12,2.53820741386080], +["2f70",2.12,1.93864198807628], +["1ja8",2.12,2.5513048593869], +["1z85",2.12,1.71208225906446], +["1e1o",2.12,1.58626330854196], +["1h7f",2.12,1.97667204641808], +["1veo",2.12,2.66921461868192], +["1yeu",2.12,2.54521080159615], +["1y35",2.12,2.51769670975678], +["1zdz",2.12,2.41071585091619], +["1z0a",2.12,2.12851834949017], +["1e3e",2.12,2.16950630372822], +["1n0u",2.12,2.64837778227349], +["1ub6",2.12,3.23348487371367], +["1oif",2.12,2.17799690943067], +["1kcx",2.12,2.53787189769171], +["1s2y",2.12,1.89253390118765], +["1xjk",2.12,2.72570563290643], +["5pgm",2.12,2.41480269588693], +["1dtm",2.13,3.06272898355032], +["1duk",2.13,3.4566741183786], +["1gm6",2.13,3.39319617733755], +["1ssw",2.13,2.13882638239307], +["1uky",2.13,2.36289109490711], +["1gbk",2.13,1.85931797008891], +["5lpr",2.13,2.06763833732030], +["1emb",2.13,2.48704521932332], +["2cc1",2.13,2.30806397848690], +["1gfy",2.13,2.75565563071845], +["2f3g",2.13,3.3651768299972], +["2azp",2.13,1.8962473644095], +["1h1o",2.13,3.36385176898358], +["1em1",2.13,2.21615846690114], +["1pu8",2.13,2.21950631311981], +["1ud2",2.13,1.99983183073062], +["1h7g",2.13,1.99132988647228], +["1mzr",2.13,2.20187434524208], +["1y85",2.13,2.43021436385891], +["1xye",2.13,2.09272239541636], +["1y31",2.13,2.68007479259848], +["1ro9",2.13,2.25440439630147], +["1s5b",2.13,1.86329100369896], +["1lti",2.13,2.8106161881058], +["1vgq",2.13,2.37988974147752], +["1s9p",2.13,2.17466707048371], +["1uzz",2.13,2.5293908090164], +["1ump",2.13,1.94835461933877], +["3pck",2.13,2.69197884203241], +["3pcj",2.13,2.73141662694482], +["4wbc",2.14,2.73259391104188], +["1unv",2.14,2.95175955360136], +["2fwk",2.14,3.94005657518016], +["1qji",2.14,1.92116843027195], +["1kdd",2.14,1.88396704888603], +["1f09",2.14,3.75839218275698], +["1in0",2.14,3.09660315732373], +["1m7z",2.14,1.47642170690158], +["3pgt",2.14,2.71704775799666], +["1riq",2.14,2.24662043261908], +["1dlk",2.14,2.36943240944298], +["1i5n",2.14,1.78854464492966], +["1e67",2.14,1.97988226098189], +["1abr",2.14,3.40621325869199], +["1y5f",2.14,2.57293668397425], +["1y0w",2.14,1.95139386380406], +["1a0u",2.14,2.42847810767485], +["1y0t",2.14,2.50769301242614], +["1ibq",2.14,2.95710153334021], +["1zzt",2.14,2.36269134075356], +["1dty",2.14,3.46359405585293], +["1uwr",2.14,1.98751303338508], +["1jqy",2.14,2.82593964843496], +["2af4",2.15,3.19892894871564], +["2fu2",2.15,2.13687211867708], +["1b8k",2.15,3.23947988740064], +["1pcs",2.15,1.51149314572976], +["4pcy",2.15,2.86343859848833], +["1bxm",2.15,1.83913252392497], +["1i3z",2.15,3.40061142170766], +["1m4b",2.15,2.30850179096438], +["6rhn",2.15,1.91727766041931], +["1ux8",2.15,2.81921803717384], +["1dmq",2.15,2.46942083945146], +["1hh1",2.15,3.05974616637234], +["1cgn",2.15,2.2345044112137], +["1u61",2.15,2.21929568175421], +["1xrx",2.15,2.0249090204142], +["1ena",2.15,3.00319623787877], +["1anu",2.15,2.08435050446178], +["2a1v",2.15,2.05673528858486], +["1r6c",2.15,2.22980435187425], +["1dtl",2.15,2.54870300418637], +["1ash",2.15,2.78286799699423], +["1rda",2.15,3.09577065534815], +["1sv4",2.15,2.60790199472752], +["2a90",2.15,3.06302041029975], +["1qmr",2.15,1.69572484514685], +["1u8a",2.15,2.62709127771632], +["1wrk",2.15,2.09495549499675], +["1wu3",2.15,2.64507576063786], +["1t8f",2.15,2.02023619008013], +["2b73",2.15,1.71754751748027], +["1faj",2.15,2.62135331299246], +["1z0f",2.15,1.97790171965547], +["1a33",2.15,2.05461190535000], +["1xg6",2.15,2.65637107719574], +["2byo",2.15,1.89019897838645], +["1wqg",2.15,2.6213434934102], +["1ktz",2.15,2.43145306051463], +["1izi",2.15,2.39172353130585], +["1gba",2.15,1.89608232247257], +["1ztz",2.15,2.65287649690222], +["1gbb",2.15,1.80509953345228], +["1gbl",2.15,2.01253796594401], +["3lpr",2.15,2.25082354359519], +["1gbf",2.15,1.94780710506295], +["1p03",2.15,2.31976899109864], +["1gen",2.15,3.00569588075759], +["1i3a",2.15,2.16788483914371], +["1mt8",2.15,2.31614599670637], +["1e4a",2.15,2.29518875779374], +["1e47",2.15,2.4008816425223], +["1mjk",2.15,2.19990442015661], +["1rc7",2.15,1.81382783966052], +["1x3e",2.15,2.54097325962183], +["2bjm",2.15,3.76633028839627], +["1uhb",2.15,3.00760022285250], +["1zyb",2.15,1.49643435277433], +["1p9y",2.15,2.13080026306133], +["1dq1",2.15,2.10660378776101], +["1veu",2.15,2.67606221541439], +["1mb8",2.15,2.74832349925393], +["1hnu",2.15,2.63420578867653], +["1yr6",2.15,3.28335147398192], +["1ky7",2.15,2.32744399045314], +["1ktj",2.15,2.56222650444731], +["1bnt",2.15,2.33684204928059], +["1bnu",2.15,2.43486100724838], +["1cnk",2.15,2.42526848190554], +["1awc",2.15,2.44312987451632], +["1qmj",2.15,2.43978598721733], +["1yhs",2.15,2.33668021563778], +["1vfn",2.15,3.5129128004789], +["1m13",2.15,2.75762561133192], +["1be6",2.15,3.02513481420599], +["1vh9",2.15,2.30682231148104], +["1y91",2.15,3.40295856995613], +["1cfr",2.15,2.25482106582304], +["1r1x",2.15,2.31961985392198], +["1nfx",2.15,2.77680227545363], +["1i4s",2.15,3.73767913275933], +["1dvk",2.15,2.2036112391994], +["1e02",2.15,3.0489978625077], +["1h42",2.15,1.81958774625383], +["1jbr",2.15,2.87988458429676], +["2f6y",2.15,2.28769330661104], +["1pxh",2.15,2.31338865422809], +["1mn7",2.15,2.76220178556807], +["1ule",2.15,2.13178365071685], +["2g15",2.15,2.89325112510647], +["1xku",2.15,2.24437224793042], +["1gw2",2.15,1.58706594645350], +["6pah",2.15,1.87699421496689], +["1ko9",2.15,2.37148943712206], +["1id2",2.15,2.46975239492181], +["1or4",2.15,3.05568389664051], +["1mau",2.15,2.55146148504731], +["1nv6",2.15,2.9916646360983], +["1cec",2.15,1.99470273717084], +["1mew",2.15,2.32961759957001], +["1kvq",2.15,2.089097888263], +["1kvt",2.15,2.43526632944462], +["1kvs",2.15,2.95822974163717], +["1ylv",2.15,2.56603534034827], +["1rlz",2.15,2.20931097379018], +["2f92",2.15,2.20662257619123], +["1k3b",2.15,2.99432156612054], +["1mjx",2.15,2.83147868385888], +["1h2k",2.15,1.97153054337586], +["1zk8",2.15,1.91892793967308], +["2asi",2.15,2.96938171375069], +["1nx6",2.15,1.87552671630488], +["1tb4",2.15,2.66220416941706], +["1pr3",2.15,2.61142878779763], +["1me7",2.15,2.05255106327311], +["1jht",2.15,2.49773680997706], +["1lek",2.15,2.40981810830161], +["1hk9",2.15,2.37718580666203], +["1d6h",2.15,2.51184796565061], +["1qg3",2.15,2.41748138308333], +["2d0e",2.15,3.1392316797591], +["1tbw",2.15,2.02380309187784], +["1jgl",2.15,2.31894355486557], +["1byu",2.15,2.2846203950054], +["1nur",2.15,2.30353675008916], +["1axt",2.15,2.84631453695059], +["1eoa",2.15,2.25250119621419], +["1vpo",2.15,2.95522750586993], +["2ar7",2.15,1.32352214736715], +["2znb",2.15,2.4833381239265], +["1bss",2.15,3.08030989546977], +["1bua",2.15,2.45060140732383], +["1vf2",2.15,2.32032614879986], +["1vf3",2.15,2.63302674010248], +["2bwc",2.15,2.28877333765485], +["1pju",2.15,1.86920035981236], +["1q79",2.15,2.50066215820229], +["1sx8",2.15,2.92417438922371], +["1ud4",2.15,1.68268378757748], +["1ud3",2.15,2.37814678075029], +["4std",2.15,2.52490459094353], +["1cbg",2.15,2.10134430830164], +["1cyy",2.15,2.57429341533011], +["1mqg",2.15,2.18960739629344], +["1mm6",2.15,2.10897411947593], +["1tx0",2.15,2.40348500748944], +["5eau",2.15,2.27034820286226], +["1vco",2.15,2.41076725843769], +["1h23",2.15,2.420671030885], +["1f4d",2.15,2.38826192916252], +["1h22",2.15,2.48962161930098], +["1slc",2.15,2.87416683563191], +["1ihu",2.15,2.86395848317755], +["1mdb",2.15,2.48453615009860], +["1ocx",2.15,2.20569864620787], +["117e",2.15,2.3045503840805], +["1vne",2.15,1.95934791651623], +["1vni",2.15,1.92408712890349], +["1m76",2.15,1.93035819987614], +["1u49",2.15,2.16439979387908], +["1vk3",2.15,2.33638734207012], +["1vm7",2.15,1.63644563391297], +["1t6d",2.15,2.14517895789732], +["1uf4",2.15,2.0684945145875], +["1lt7",2.15,2.98967030015206], +["1lev",2.15,3.16560433503204], +["1f29",2.15,1.93292157948883], +["1tb5",2.15,2.14119081604248], +["1nv7",2.15,2.9667020233777], +["1g5b",2.15,2.68832424407017], +["1po0",2.15,2.7974370462373], +["2d3i",2.15,2.59336190944188], +["1h76",2.15,2.27913808941413], +["1sqi",2.15,2.68078411246443], +["1uim",2.15,2.44464980714605], +["1r8g",2.15,2.57885490991196], +["1rjm",2.15,2.17794485982044], +["1kds",2.15,2.44061039840773], +["1ke3",2.15,2.07320666123014], +["1nvj",2.15,2.26135927505071], +["1fmw",2.15,3.19292274391279], +["1yre",2.15,2.54808929031595], +["1hq3",2.15,2.47425078177728], +["1duy",2.15,2.44553169789279], +["1cc1",2.15,2.3802046953033], +["1k7d",2.15,2.25781772550404], +["1aym",2.15,2.18152102606781], +["3ran",2.15,2.38569526900869], +["1k2r",2.15,2.73713771466547], +["2bkk",2.15,3.13917758955363], +["1v2a",2.15,3.09712682399575], +["2bh2",2.15,2.53580533947729], +["1tyo",2.15,2.55560735081651], +["1udd",2.15,2.55492551041604], +["1mlz",2.15,2.51193066103379], +["1no3",2.15,2.98709714893817], +["1yfr",2.15,3.12097997019742], +["1t0q",2.15,2.30924831542138], +["1kw2",2.15,2.32653438674701], +["1iyd",2.15,2.66645489122707], +["1v6i",2.15,2.04510453078765], +["2c63",2.15,1.78842413747307], +["1shn",2.15,2.18765092314387], +["1ezf",2.15,2.63473849823601], +["1uc2",2.15,2.22785188955471], +["1vz5",2.15,1.78724413718121], +["1tz7",2.15,2.1531612107485], +["2d1p",2.15,2.52275818703289], +["2c3d",2.15,2.26480615518031], +["2c3c",2.15,2.23944565755185], +["1nir",2.15,2.44589129811145], +["2awz",2.15,1.44167101639381], +["1qo8",2.15,3.12472343308174], +["1fp6",2.15,2.59685310134773], +["1ve5",2.15,2.85882216250832], +["2byl",2.15,2.17503829804390], +["2ahr",2.15,2.20729429580272], +["1rpn",2.15,2.33982238318413], +["1hju",2.15,2.02691275468376], +["1gqh",2.15,2.06674321376166], +["1szr",2.15,2.09347124556002], +["1ped",2.15,2.65960854931011], +["2ewc",2.15,2.19186451243085], +["1ssm",2.15,2.68372810662993], +["1jrq",2.15,2.52721084387242], +["2fuq",2.15,2.04140328839276], +["1h54",2.15,2.26230617931582], +["1kh3",2.15,2.72743159663114], +["1w72",2.15,1.74948023379765], +["1x31",2.15,2.14824027461459], +["2cev",2.15,1.91787357981097], +["1atj",2.15,2.13675682194143], +["1uvi",2.15,2.43881281134064], +["2ahw",2.15,2.10455649437757], +["1ylo",2.15,2.2039974149315], +["1fz2",2.15,2.35582903101956], +["1fyz",2.15,2.33722244644388], +["2exi",2.15,2.27980348723308], +["2afa",2.15,2.32897402237978], +["2bzn",2.15,1.86423760603521], +["2pcd",2.15,2.58487962265502], +["3pcf",2.15,2.66347176489870], +["3pcl",2.15,2.8120170048525], +["1ggh",2.15,2.35584868587118], +["1o01",2.15,1.78789352239915], +["1xhf",2.15,1.97558071538419], +["1ydh",2.15,2.05062210243652], +["1w5g",2.16,1.66733311121956], +["1czj",2.16,2.64185213238634], +["1ks3",2.16,2.62385491162398], +["1s4q",2.16,1.66959379044837], +["1xt0",2.16,2.18740826257216], +["2fsw",2.16,2.64057169152152], +["1mom",2.16,3.29609859317819], +["1c3l",2.16,2.71349652491896], +["1ljw",2.16,2.59109393290284], +["1beq",2.16,2.63917973944008], +["1u9t",2.16,3.51217582505983], +["1wbo",2.16,2.25739579757316], +["1npx",2.16,2.39035927559079], +["1zx1",2.16,2.0538233995477], +["1spq",2.16,1.27195725461636], +["1eoo",2.16,3.10309608378462], +["1w4l",2.16,2.48901756788261], +["1v8d",2.16,2.85705724625466], +["1xzu",2.16,2.6614863855107], +["1y22",2.16,2.46124086544180], +["1wls",2.16,3.14032861406927], +["1pc3",2.16,2.79671850505721], +["1t3a",2.16,2.62432730817271], +["2abz",2.16,2.59942893733149], +["1mc1",2.16,2.65472035933516], +["2azd",2.16,2.32641114182299], +["2a2o",2.16,1.35266825058453], +["1u9h",2.17,2.83743746645986], +["1w5l",2.17,2.44134392966120], +["1b5v",2.17,1.99180647552196], +["1b5w",2.17,2.20362462574166], +["1irc",2.17,2.88250867579943], +["1s7d",2.17,2.46610491031495], +["1dzw",2.17,2.42122502872824], +["1ivl",2.17,2.79730360880082], +["1qd5",2.17,2.60772563773603], +["2aix",2.17,2.20298806259392], +["1r6f",2.17,3.14836296792333], +["1z5m",2.17,2.80014595597567], +["2f2o",2.17,3.25612232689549], +["1zso",2.17,2.27833721944162], +["2br0",2.17,2.86707965423594], +["1dzr",2.17,2.55161770376596], +["1knv",2.17,2.37013313665217], +["1hfk",2.17,2.40467223820736], +["1gae",2.17,2.34209739752375], +["1zkw",2.17,2.87516556378773], +["1sh0",2.17,2.28700556971344], +["1n8j",2.17,2.17121524052811], +["1sif",2.18,2.59801911689785], +["1zk9",2.18,2.29357074874998], +["1m4a",2.18,2.87042321430396], +["1n4j",2.18,2.254718946025], +["1nr2",2.18,3.59492389707021], +["1yrv",2.18,2.94164466270982], +["1wus",2.18,1.94703351731741], +["1z6g",2.18,1.88611116116255], +["1dzx",2.18,2.69060445776453], +["1g0z",2.18,2.71534499755136], +["1u4j",2.18,3.00745486440636], +["1qdq",2.18,2.40096524462518], +["1sci",2.18,1.74662662509316], +["2a1l",2.18,2.41880637066923], +["1s1j",2.18,2.72959817977195], +["1nzq",2.18,2.60273715128235], +["1rl4",2.18,2.65314492825990], +["1jam",2.18,2.77386347769757], +["1j3r",2.18,2.40928676709919], +["1jpf",2.18,2.77173255705965], +["1zjk",2.18,2.40518200367464], +["1xk0",2.18,2.48842116137588], +["1mko",2.18,2.84220554337317], +["1d9d",2.18,3.15492353678811], +["1vrd",2.18,2.08829194493242], +["1tf5",2.18,2.88592590155429], +["1e5f",2.18,2.16310418005886], +["1e5e",2.18,1.61799179640621], +["1nvv",2.18,2.08028542278034], +["1r4c",2.18,2.67040451621258], +["1npt",2.18,2.15185493609064], +["1q23",2.18,2.92554473949640], +["2f5z",2.18,2.39831085260293], +["1kwi",2.19,2.82521454080384], +["1kxi",2.19,3.36625508251715], +["1ecy",2.19,3.76078079100476], +["1bja",2.19,2.71556831036593], +["1tjt",2.19,2.38088449055008], +["1bh3",2.19,2.30296000242847], +["2eda",2.19,2.77901394379369], +["1t21",2.19,2.0951773081746], +["1gvh",2.19,2.76786173695477], +["1yfe",2.19,2.53498448781293], +["1odb",2.19,2.20624782544338], +["2g59",2.19,2.32661378044162], +["2ae6",2.19,2.34519760304226], +["1xlx",2.19,2.61843363885924], +["1xyc",2.19,2.1176370452511], +["1s8c",2.19,2.93888592307149], +["2bk6",2.19,2.03944863655470], +["1xyg",2.19,2.13110945930941], +["2aqb",2.19,2.29126551662402], +["2bs3",2.19,2.37251395834664], +["3pcb",2.19,2.62217261869742], +["2a22",2.2,2.13378362864768], +["1xlu",2.2,2.55031129516861], +["1u9g",2.2,2.71406197176025], +["2dgc",2.2,2.23489695278797], +["1ptr",2.2,1.62553777605651], +["1bti",2.2,2.83560567044592], +["1ig7",2.2,3.06437537563221], +["1dtx",2.2,2.07624644559364], +["1ciq",2.2,2.6953374512679], +["1unw",2.2,2.98605940978064], +["1wd1",2.2,3.3508320438397], +["1coa",2.2,1.86491038846279], +["1ca5",2.2,3.87293657537759], +["1wtx",2.2,2.47440942945820], +["1wtw",2.2,2.69231725093453], +["1ca6",2.2,3.01760754002559], +["1by9",2.2,1.67044689634119], +["1f0m",2.2,3.08892656642111], +["1x8y",2.2,1.97301595759613], +["4kiv",2.2,4.0672874720917], +["2bl7",2.2,1.89697039152229], +["1bb9",2.2,2.70557266427136], +["1yhb",2.2,2.76603982303190], +["1gq5",2.2,2.53459382323315], +["1qjh",2.2,2.46323478369245], +["1rr7",2.2,3.22872191470802], +["2a66",2.2,2.59751774646359], +["1sj3",2.2,2.28745015739094], +["1i3j",2.2,2.30112322838952], +["1beo",2.2,2.36959849631537], +["2bvz",2.2,2.10220624041141], +["1odd",2.2,2.89629336560898], +["1ayd",2.2,2.61104065522040], +["1yti",2.2,2.14047719725727], +["1hef",2.2,3.37117032186497], +["1heg",2.2,3.91989774603893], +["1wrp",2.2,2.88718323178692], +["1tul",2.2,2.71204405361395], +["1fim",2.2,2.67662265962681], +["1r6y",2.2,2.70627547564426], +["4rnt",2.2,2.75235704625136], +["1gsp",2.2,1.18690470590228], +["6gsp",2.2,1.94973458878512], +["1ijr",2.2,2.47822139415609], +["1bfs",2.2,2.84180332318384], +["1fdb",2.2,2.61658802532704], +["1fkk",2.2,2.89871510498320], +["1txx",2.2,2.90056050575146], +["1cty",2.2,3.71471865948059], +["1hkf",2.2,2.4019329769349], +["3hdd",2.2,2.50743363499028], +["1zka",2.2,2.27356350165969], +["1aqe",2.2,1.58413592179267], +["1jnm",2.2,2.98534629166491], +["1aa0",2.2,2.91497754016476], +["1ecw",2.2,2.57225834943448], +["1j81",2.2,2.60656661987672], +["1igu",2.2,1.89800066650474], +["1b1u",2.2,3.92996038015244], +["1lsw",2.2,2.34481168911189], +["1jmt",2.2,2.73970389352672], +["1nbp",2.2,1.97140616544986], +["1u9f",2.2,2.33315793744668], +["1sjx",2.2,2.27744035841206], +["1rsi",2.2,2.25220697987526], +["2dhn",2.2,2.44062562794283], +["1vip",2.2,1.69602998488922], +["3sem",2.2,2.48145254050126], +["1a15",2.2,3.18900345585215], +["1cxa",2.2,2.77126095676615], +["1db4",2.2,2.87137053700430], +["1bbc",2.2,4.09266768344117], +["1bfc",2.2,3.37907096661951], +["1k46",2.2,2.24689541723133], +["1fga",2.2,3.52908964106449], +["1rpf",2.2,3.26858091569007], +["1rph",2.2,3.16675185934748], +["1dq7",2.2,3.10110207453874], +["2a7t",2.2,2.99223026117269], +["1w5j",2.2,1.90765200347039], +["2sem",2.2,2.22694973001402], +["2lz2",2.2,4.04156101846187], +["1di5",2.2,2.56643666015485], +["2fe1",2.2,1.27333134315653], +["1b5y",2.2,1.35231881173893], +["1a0k",2.2,2.47710792063692], +["208l",2.2,3.15288522601475], +["1b7m",2.2,2.67809112025214], +["1c46",2.2,3.10508690062249], +["1bhl",2.2,2.81797396995454], +["1htp",2.2,2.57532052559373], +["1pxu",2.2,1.73941155358867], +["1a3v",2.2,2.89860296459109], +["1dqo",2.2,2.58856668838540], +["1fwv",2.2,2.21798607492989], +["2pf2",2.2,4.05674859585495], +["1eni",2.2,3.05868884095115], +["1cbq",2.2,2.12207379254000], +["2foo",2.2,2.49402101625639], +["1r2h",2.2,2.22057156908929], +["1maz",2.2,2.86409694753157], +["1wmm",2.2,2.1255658356905], +["1qrv",2.2,2.25565038459996], +["1pq0",2.2,3.02951751953045], +["2fcm",2.2,2.37414552290471], +["2fcn",2.2,2.75670298291673], +["3cln",2.2,3.42942813933754], +["1vsi",2.2,2.99777476307662], +["1asv",2.2,2.79812556130127], +["1vsk",2.2,3.01561682953248], +["1vse",2.2,2.73049619824646], +["1vsl",2.2,3.40199973835692], +["1lba",2.2,2.54371898578925], +["1jmb",2.2,3.69526702783915], +["1jot",2.2,2.91058371302854], +["2a25",2.2,2.7365735079591], +["1ndk",2.2,2.55946509411206], +["4cln",2.2,4.38022139853892], +["1nb2",2.2,3.50484845513844], +["1grj",2.2,3.41574154691671], +["1ncl",2.2,2.22257409186990], +["1v8s",2.2,1.72019070841407], +["1ibf",2.2,2.17135565599589], +["1p4u",2.2,2.58321371911059], +["1jvi",2.2,2.09384241426171], +["1tp0",2.2,2.75533901846004], +["1mob",2.2,2.88780574440678], +["2mga",2.2,3.10574353078976], +["1cpw",2.2,2.54272466982991], +["1y9b",2.2,2.06234705002490], +["5pnt",2.2,2.12509930497563], +["1ihk",2.2,1.44045324275674], +["1wy6",2.2,2.25577999831874], +["1pnt",2.2,2.67146235069752], +["1z13",2.2,2.60062824593315], +["1z12",2.2,2.69907181386908], +["1fym",2.2,1.87821623419583], +["1utt",2.2,2.27040339468038], +["1rx4",2.2,2.95915057205621], +["1rx3",2.2,2.76916863559941], +["1g43",2.2,2.57358294764841], +["1lih",2.2,3.20161760272362], +["1evs",2.2,2.96951424687139], +["1x1s",2.2,2.02478014298691], +["151l",2.2,4.07142352939545], +["1c6n",2.2,2.65095657409941], +["1c67",2.2,2.69269384175201], +["2b6w",2.2,1.87243308998217], +["1c6b",2.2,2.54765589709721], +["1cu0",2.2,2.61674200294729], +["177l",2.2,3.90762644385934], +["2gbo",2.2,2.54460183611983], +["1ge6",2.2,1.90433181259681], +["1o6b",2.2,2.72661300838426], +["2tcl",2.2,1.63848322658045], +["2fg9",2.2,1.73347183204528], +["2ugi",2.2,2.42796817804684], +["2usn",2.2,2.15510229920518], +["421p",2.2,3.00065520286391], +["1cwb",2.2,2.3697153398114], +["1yg2",2.2,2.57954658586055], +["1vq2",2.2,2.26605808011310], +["1q21",2.2,3.42981556937749], +["2q21",2.2,3.67598722731859], +["1qsn",2.2,3.372077580286], +["1rcg",2.2,2.21893178981813], +["1few",2.2,2.86140018698261], +["1sl7",2.2,1.0694825097337], +["1nx2",2.2,2.18226389668456], +["1b24",2.2,3.40505747724622], +["1ino",2.2,3.13214675629945], +["1igp",2.2,3.38567103021985], +["1g2d",2.2,2.45590757119795], +["1iwn",2.2,2.62710433052988], +["2g03",2.2,2.02389754995805], +["3cd4",2.2,4.11258137707180], +["1wp7",2.2,2.79476632327244], +["2bm6",2.2,2.68861529114636], +["1am2",2.2,2.97722116171691], +["1dy0",2.2,2.00164469075538], +["1r5p",2.2,2.44022883754864], +["1wp8",2.2,2.65646581155048], +["1htj",2.2,2.56682841079699], +["1dy1",2.2,2.46298697891120], +["1ise",2.2,2.90698869435171], +["1ecm",2.2,1.72297038805718], +["1is1",2.2,2.55708406271165], +["1m5o",2.2,2.33395755231372], +["1dr1",2.2,2.82598419008003], +["1pd9",2.2,2.92455162054758], +["1u71",2.2,3.39788619997362], +["1pdb",2.2,4.17165412265249], +["1p6f",2.2,2.42500105161915], +["1qc7",2.2,2.15990303794763], +["1jyb",2.2,2.56407125011542], +["2ukd",2.2,2.24771918456998], +["1mey",2.2,3.20545542929906], +["1eje",2.2,2.65197228308803], +["1har",2.2,2.71281832562701], +["1bjz",2.2,2.38625550133609], +["1zxq",2.2,3.03947502554863], +["1fy9",2.2,2.53942816048328], +["1fya",2.2,2.30323032430659], +["1uke",2.2,2.94324360135438], +["1ohz",2.2,1.63313280474944], +["1t7j",2.2,2.16873497330826], +["1k6p",2.2,2.10369300180568], +["1aid",2.2,2.18503638692838], +["1hih",2.2,2.00738881016974], +["1htf",2.2,2.69437355745013], +["1k6c",2.2,2.04219497178244], +["1idb",2.2,2.79314134142235], +["1z8c",2.2,2.25979336575975], +["1smt",2.2,1.74501352029584], +["1qua",2.2,2.65959521049798], +["1p09",2.2,2.25165261527204], +["1yio",2.2,2.09145956350074], +["1lzq",2.2,2.64336377647909], +["1wni",2.2,2.52945632650947], +["2fap",2.2,2.37310136968968], +["1nsg",2.2,2.37552495756500], +["1g76",2.2,2.9548012863112], +["1g78",2.2,3.13892372303379], +["1gbc",2.2,1.85533192434206], +["1gbd",2.2,2.06793038158286], +["1gbh",2.2,2.17174329964546], +["9lpr",2.2,2.30813745314037], +["2fdg",2.2,1.78300129538943], +["1zlx",2.2,2.76228863237939], +["1k2c",2.2,2.40885613377819], +["2cgp",2.2,2.59834174741766], +["1cqk",2.2,2.58488531364204], +["1yn5",2.2,2.70510964894603], +["1kuu",2.2,2.90478165439843], +["2gsq",2.2,2.87524435253618], +["1qhl",2.2,3.28756436706273], +["1qsd",2.2,2.59560273399266], +["1l8d",2.2,2.68037239588661], +["1n6j",2.2,2.57122837189645], +["1a1e",2.2,2.27506720927483], +["1sgl",2.2,2.44911820419473], +["1mjm",2.2,2.50768215680562], +["1cd2",2.2,3.1888335687946], +["1imj",2.2,2.68463693508735], +["1hro",2.2,2.19329022236224], +["1bi1",2.2,2.84390980427420], +["1a1b",2.2,1.63898951228332], +["1bqs",2.2,4.09573668417686], +["1a08",2.2,1.86150698436902], +["1a07",2.2,1.96007077440784], +["1qca",2.2,2.26398802417206], +["1uyh",2.2,2.74682359044285], +["1b4b",2.2,2.87135793928572], +["2bdv",2.2,2.64932018003592], +["1boy",2.2,3.31305731554633], +["1bp4",2.2,2.36931782021888], +["1fki",2.2,2.13314716228429], +["2siv",2.2,3.07565607856569], +["1yes",2.2,2.33132280686531], +["2rbi",2.2,2.17457354044405], +["1em2",2.2,2.58865822961653], +["2aim",2.2,2.52395658533895], +["1u9v",2.2,2.43693514669164], +["1atk",2.2,2.63405851940249], +["1ayu",2.2,2.78134285537550], +["1mxs",2.2,2.63754567487457], +["1aw9",2.2,3.01798215538698], +["1mzv",2.2,2.35204909927008], +["1glo",2.2,2.39093156307929], +["1mvp",2.2,2.42642331659967], +["1mou",2.2,1.87743372459818], +["1gpc",2.2,3.18188197180712], +["1z7u",2.2,2.34640654977453], +["2cbt",2.2,4.20289066052114], +["2aoq",2.2,2.30022626159275], +["1u83",2.2,2.17627090783264], +["1ep8",2.2,2.57788515932900], +["1jv5",2.2,3.10986410222055], +["1xtn",2.2,2.50432514061021], +["1r18",2.2,2.36823311978266], +["1aw8",2.2,1.89904614869751], +["1s85",2.2,1.11817292357385], +["1k1m",2.2,1.75457739990469], +["1lqe",2.2,2.26234924086332], +["1k1i",2.2,1.84208709899869], +["1k1j",2.2,1.64152072604287], +["1btp",2.2,2.98202235761627], +["1aq7",2.2,2.67884983737130], +["1ane",2.2,2.25283752503851], +["1anc",2.2,2.58837841495939], +["1bra",2.2,2.55669981425629], +["1xxg",2.2,1.92423796106224], +["1ihn",2.2,2.29190602061756], +["1bg8",2.2,3.31938793791065], +["1dyn",2.2,3.05488676845978], +["1xji",2.2,1.96395419135731], +["1wud",2.2,1.96499552924234], +["1yln",2.2,2.49218809312726], +["1srh",2.2,3.00072528503061], +["1myw",2.2,2.49294592629075], +["1pjp",2.2,2.32814890472571], +["2brs",2.2,2.35685793039032], +["1huy",2.2,1.90543713117348], +["1kon",2.2,3.38017943641762], +["1ko2",2.2,2.05683465947019], +["1hw7",2.2,2.79769074771736], +["1x07",2.2,2.50729430547953], +["1f7n",2.2,3.04563487477324], +["1f7k",2.2,3.06879285599183], +["1z7j",2.2,1.91312591730774], +["1n69",2.2,2.40254090544416], +["1i4q",2.2,2.66393424333982], +["1scz",2.2,2.49922413537956], +["3tmy",2.2,3.15141620452173], +["1gmc",2.2,2.6988572554349], +["1gmj",2.2,1.98094075576275], +["1gha",2.2,2.75452870165749], +["1gmd",2.2,3.10140521272183], +["1qam",2.2,2.31657134204599], +["1ixz",2.2,2.60842054467611], +["1lcw",2.2,2.29193796543792], +["1k41",2.2,3.84045303258010], +["2roy",2.2,3.4379033233571], +["1r3m",2.2,2.9493968873728], +["1zh4",2.2,2.78656760596053], +["1h4u",2.2,2.72971799648749], +["1yin",2.2,2.90196527033553], +["2fof",2.2,1.87622258275373], +["2foe",2.2,2.33869970008097], +["1c1m",2.2,2.62129422532546], +["1mmj",2.2,3.48248445666226], +["1pa0",2.2,2.22412402671618], +["1ldo",2.2,2.39839896298416], +["1y92",2.2,2.39099518653172], +["1r28",2.2,2.71705534069633], +["1mn4",2.2,2.39997637633287], +["1g9i",2.2,2.91752994844991], +["1tlg",2.2,1.98220175983552], +["1q05",2.2,2.24746262069325], +["1bdy",2.2,2.09244563206892], +["1tj5",2.2,2.54566531862209], +["1joc",2.2,2.63382568982033], +["1wyy",2.2,2.29741531291067], +["1j1a",2.2,2.58983939703773], +["1ahb",2.2,2.46813327696533], +["1aha",2.2,2.20021571847064], +["1mri",2.2,3.06180057857194], +["1f8q",2.2,3.19464139592239], +["1jvv",2.2,2.62718521482816], +["1rav",2.2,3.28044480427467], +["1y94",2.2,2.86325050032425], +["2cam",2.2,3.28002818380226], +["2phi",2.2,2.99037504341138], +["1rk3",2.2,1.94024596033503], +["1xnn",2.2,2.76045153367501], +["1ab6",2.2,2.4789664325557], +["1uam",2.2,2.01060152444171], +["1qkt",2.2,2.90801842472949], +["1j4n",2.2,3.57201305383793], +["1w01",2.2,2.96922044631443], +["1plf",2.2,3.10303210505869], +["1p4x",2.2,2.95891090338531], +["2aa7",2.2,2.32987625909843], +["1s0x",2.2,2.06465174299651], +["1sp4",2.2,2.3892478982624], +["1et0",2.2,2.84304048210905], +["1xx4",2.2,2.85069286054862], +["1z3c",2.2,2.78392125808164], +["2c6d",2.2,3.01274513272047], +["1dca",2.2,2.57553075609047], +["1fx8",2.2,2.30161873940553], +["1u4r",2.2,2.31677406339516], +["5cac",2.2,2.68482365637403], +["4cac",2.2,2.56100773053187], +["1h9q",2.2,2.20186715485231], +["1cvd",2.2,2.74535113967365], +["1cct",2.2,2.65328082859027], +["1cnc",2.2,2.87000552757566], +["1i7g",2.2,2.58393117805506], +["1azb",2.2,2.60475440013732], +["6yas",2.2,1.99197430663773], +["5yas",2.2,2.12021836609837], +["1t73",2.2,1.80659359633417], +["2f5e",2.2,1.95473738960386], +["1l2c",2.2,1.95689541513708], +["1vk6",2.2,1.85930605826293], +["1obs",2.2,2.29911690023639], +["1bn3",2.2,2.42104615350283], +["1okm",2.2,1.85220881717310], +["1lg6",2.2,2.58942208705412], +["1huh",2.2,2.9579628787533], +["1kgf",2.2,2.4817119054582], +["1blc",2.2,3.47030119607802], +["1o6y",2.2,2.49920961010982], +["1b5z",2.2,2.57894330568674], +["2mea",2.2,2.50748822333493], +["1ckg",2.2,2.56306167386805], +["2mec",2.2,2.49607384128834], +["1cal",2.2,2.34605192705121], +["1ugg",2.2,2.63883864722881], +["1rwp",2.2,2.42902195820145], +["1ymp",2.2,3.77048035109751], +["1es3",2.2,2.93406138178573], +["1vpq",2.2,1.59341567774062], +["2cgw",2.2,2.88256225620304], +["2brm",2.2,2.49435580476113], +["2cgx",2.2,2.95203685812687], +["1i8n",2.2,2.27522140927573], +["1ftp",2.2,2.62624151696483], +["1bq2",2.2,2.55936723928264], +["1tsn",2.2,2.42325216670591], +["1zbl",2.2,2.06871893044286], +["1qpj",2.2,2.05806685202438], +["1bid",2.2,2.29492324099717], +["1tjs",2.2,2.62908580406311], +["1psu",2.2,2.52584626253594], +["1fs6",2.2,3.21605762921694], +["1cxz",2.2,2.26697405246491], +["3tgj",2.2,2.48215243705444], +["1eny",2.2,3.48142874111186], +["1drv",2.2,3.99340027201229], +["1dru",2.2,4.05939375815186], +["2bro",2.2,2.85256882679075], +["2f95",2.2,1.49986121057152], +["1dbp",2.2,2.04665706637176], +["1dih",2.2,3.94808352682738], +["1drw",2.2,4.03465999135247], +["1wkl",2.2,2.38346621060551], +["1bc5",2.2,3.05978016168993], +["1bfu",2.2,2.96252407828978], +["1be8",2.2,3.04076369983156], +["1yxs",2.2,2.14989395683951], +["1sbi",2.2,2.08764542233197], +["1l5p",2.2,3.05238554117834], +["1bix",2.2,2.26671059453542], +["1fxu",2.2,2.92268922271339], +["1w0x",2.2,2.85089133018389], +["1ke5",2.2,1.90673900057162], +["1phk",2.2,2.92066483002047], +["1fvt",2.2,2.26703719334821], +["1d4v",2.2,3.53707271293412], +["1r2b",2.2,2.61977657768357], +["1cnm",2.2,2.63686574159022], +["4tpi",2.2,2.3035577173065], +["1r53",2.2,2.38874150716364], +["1di8",2.2,2.1362403917923], +["1wcc",2.2,2.40391543206571], +["1zgv",2.2,2.23331362846817], +["1zgi",2.2,2.22693497630353], +["1wrq",2.2,2.37236186360278], +["1mt6",2.2,3.6612391476126], +["1xt9",2.2,2.91640066157299], +["1a61",2.2,3.56233465681688], +["1oev",2.2,1.95001587885891], +["3prk",2.2,2.76932818435925], +["1pek",2.2,3.26845818043409], +["1cf0",2.2,3.03183715858795], +["1w69",2.2,2.43911712134853], +["1pj8",2.2,3.14446121083905], +["1rsz",2.2,2.76867717349696], +["1awi",2.2,2.80300079841822], +["1wbg",2.2,2.1111144989448], +["1v3x",2.2,2.23506608456132], +["1ezq",2.2,3.29509605596494], +["1hcg",2.2,3.94515828205194], +["1ph0",2.2,2.18876123811871], +["1pyn",2.2,2.41944643866394], +["1mhq",2.2,2.91715257874471], +["1bin",2.2,3.08848653998522], +["1bhs",2.2,2.89341672370354], +["1y30",2.2,2.27472098273368], +["1n4k",2.2,2.4213799158821], +["2hbf",2.2,3.22806595859489], +["2hbd",2.2,3.37376404724063], +["1aj9",2.2,3.4055074212306], +["1fdt",2.2,2.76771122336988], +["1boi",2.2,2.37303425284906], +["1tpy",2.2,2.54912781836162], +["1lpk",2.2,2.76008825605715], +["2cc3",2.2,2.67924911254781], +["1t1n",2.2,2.85548896166519], +["2boh",2.2,2.65237108409506], +["2hgt",2.2,3.68874411904066], +["1h0o",2.2,2.67270363150791], +["1ths",2.2,3.41848038703081], +["1q6j",2.2,2.39914645209277], +["1q6m",2.2,2.69390174014353], +["1eqa",2.2,2.60649878369727], +["1b42",2.2,2.61255086442443], +["1awf",2.2,2.90132736174019], +["1t48",2.2,2.39926681537416], +["1bj9",2.2,2.30246599858722], +["1bep",2.2,2.3683598170319], +["1bem",2.2,2.74795840781718], +["1bek",2.2,2.6846572181809], +["5ccp",2.2,2.31051201715841], +["1cpd",2.2,2.5878541274045], +["1cpf",2.2,2.71187350122039], +["1ft7",2.2,2.77217602171176], +["1dcc",2.2,2.4920633252234], +["6ccp",2.2,2.37422624750518], +["7ccp",2.2,2.52622296562324], +["1cpe",2.2,2.51408146613504], +["1cpg",2.2,2.50685845138564], +["1okc",2.2,2.56039901623507], +["1b3t",2.2,2.32404521913796], +["2glt",2.2,2.64027163775845], +["1no4",2.2,2.40526051978706], +["1ebe",2.2,2.42229650179699], +["3ccp",2.2,2.41499464655349], +["4ccp",2.2,2.38784740776949], +["2ccp",2.2,2.56091414948207], +["1ccp",2.2,2.45163371946628], +["2cep",2.2,2.62614035051848], +["1tmt",2.2,2.78665191978957], +["1etr",2.2,3.29563300017295], +["1hgt",2.2,3.82292534790691], +["1ctt",2.2,3.10160052663244], +["1l6o",2.2,3.79115787327333], +["1fts",2.2,2.66756796959413], +["3ptd",2.2,3.00024915166276], +["2c0j",2.2,2.61111091070766], +["1lme",2.2,1.90696716883846], +["2f6w",2.2,2.17199665804161], +["1g7g",2.2,2.96000261025059], +["1kbz",2.2,2.4838977495799], +["1ndp",2.2,2.83190672042016], +["1uuh",2.2,2.79337183418039], +["1wax",2.2,2.26926679289268], +["1dmu",2.2,2.00205743725512], +["1mnk",2.2,2.46811247677549], +["1epb",2.2,3.2577011075721], +["1qhr",2.2,2.81604700963385], +["1qj6",2.2,2.90944939336340], +["1qj7",2.2,2.97175652411227], +["1g1g",2.2,1.74715560324416], +["1b3x",2.2,1.48731834817338], +["1mnj",2.2,2.745084526819], +["1kjn",2.2,2.62234166184102], +["1keo",2.2,3.24708361508927], +["2bq8",2.2,2.03931415899112], +["1cjl",2.2,2.26485518932903], +["1ghr",2.2,2.43769472032147], +["1iov",2.2,3.84039725372967], +["1c0e",2.2,2.88895743979823], +["1pbo",2.2,2.80889248012799], +["1ufh",2.2,2.1989547114877], +["1tg2",2.2,1.96745884057660], +["1d9y",2.2,3.05825172821730], +["1h43",2.2,2.63819169244521], +["1rz6",2.2,2.18299881579595], +["1png",2.2,2.38663698784090], +["1yip",2.2,2.72324387007090], +["1d1p",2.2,2.38274868085578], +["1tw0",2.2,1.99771298453274], +["1n3a",2.2,2.60677374373176], +["1n39",2.2,2.55837968267691], +["1bge",2.2,2.54134671592028], +["1gfi",2.2,1.85181983905798], +["1nml",2.2,2.13031983241688], +["1bws",2.2,2.89931717036893], +["1gkz",2.2,3.12148130447428], +["1eko",2.2,3.27325881842144], +["1v6y",2.2,1.73413263032375], +["1qf0",2.2,1.88293909012874], +["8tli",2.2,2.23243744191628], +["1fjt",2.2,1.79957499474828], +["1dds",2.2,2.92123706225837], +["1tsy",2.2,2.48524250031072], +["1hse",2.2,2.75888650019393], +["1gfs",2.2,2.21981813939008], +["1bsv",2.2,2.09712041931050], +["1pug",2.2,3.36901642180428], +["1shw",2.2,3.39048365593877], +["1bcz",2.2,3.39081550062974], +["4cms",2.2,2.96199385929971], +["1kn1",2.2,2.54606653504268], +["1bao",2.2,2.60496949739174], +["1t3l",2.2,2.79288597835052], +["2f8l",2.2,2.10043187688405], +["1z7w",2.2,2.46827309788187], +["2dap",2.2,2.85265104210306], +["1brg",2.2,2.8258414769198], +["1bof",2.2,1.63011092590620], +["1gdd",2.2,2.41821531142897], +["1ban",2.2,2.83065888813476], +["1a5t",2.2,2.82459731202780], +["1a74",2.2,2.98692854804307], +["1ipp",2.2,3.23849994630204], +["2cya",2.2,2.23054093099826], +["1jil",2.2,2.43653006255502], +["1yjm",2.2,1.27228678837796], +["2ged",2.2,2.25956380261102], +["2bcs",2.2,1.97061724122606], +["1vmo",2.2,3.29338097053706], +["1hqt",2.2,3.25281975824745], +["2bgu",2.2,2.13007491787112], +["2a0s",2.2,1.88654750246842], +["1wy0",2.2,2.7326123604273], +["2bgt",2.2,2.37141612744458], +["1au1",2.2,2.83495054603444], +["2bcu",2.2,2.18924200926447], +["1qxh",2.2,2.31725436941441], +["176l",2.2,3.72421772269853], +["1psn",2.2,1.50131330774953], +["1yh0",2.2,2.38800260637998], +["167l",2.2,3.46481655947169], +["1bpy",2.2,3.7400145154316], +["1m1d",2.2,3.10286693929925], +["1i5s",2.2,2.84358936153083], +["2ag9",2.2,3.1544855830544], +["1sbq",2.2,2.90645580994688], +["1xsp",2.2,1.83464480721728], +["1skm",2.2,2.33560069005914], +["1day",2.2,2.66279440743864], +["1z0d",2.2,1.74057642314051], +["1m83",2.2,2.59038221273452], +["1n7w",2.2,2.26909998426021], +["1oc1",2.2,1.83616417032157], +["2bak",2.2,2.49425100625502], +["1v04",2.2,2.44580746979380], +["1g4w",2.2,3.13016234234813], +["1dw2",2.2,2.23900312836791], +["1yq7",2.2,2.37705105705828], +["3rap",2.2,2.44245290544566], +["1rej",2.2,2.68399600963506], +["1nid",2.2,2.20749611989485], +["1xho",2.2,1.23301477228193], +["1mze",2.2,2.31176380346975], +["2er9",2.2,2.96480727729298], +["1s2j",2.2,2.43814854273801], +["2eip",2.2,2.03950405736804], +["1gs6",2.2,1.83548525954448], +["1gex",2.2,2.13110807432287], +["1bov",2.2,2.96968459885605], +["1cqf",2.2,1.38583268423517], +["2alt",2.2,3.19929872193555], +["1wgc",2.2,3.25641219262682], +["2wgc",2.2,3.21538948894191], +["1k7v",2.2,3.13691936206819], +["1k7u",2.2,3.48876163660836], +["1tec",2.2,3.03998357721099], +["1hxx",2.2,2.42621981259643], +["1si7",2.2,2.25215000203295], +["1al8",2.2,2.49698284058837], +["1ohe",2.2,1.9436310650506], +["1pmn",2.2,2.66922586398819], +["1juo",2.2,2.72621697028151], +["1dhs",2.2,2.04705767363830], +["1z9u",2.2,2.39389100354768], +["1n48",2.2,2.71065090460519], +["1nqk",2.2,2.48153790989827], +["1f7o",2.2,2.44124275606391], +["2f8c",2.2,2.21765338698499], +["1jdj",2.2,2.15961346470934], +["1slx",2.2,2.76758317093023], +["1pmq",2.2,2.58375922285004], +["1ipd",2.2,3.29144265611671], +["1me9",2.2,2.31243949492507], +["1v43",2.2,2.7094857458044], +["1jhm",2.2,2.8186322460772], +["1jhp",2.2,2.94293766193227], +["1l4k",2.2,2.20962254133615], +["1gp5",2.2,1.65420206816751], +["1mei",2.2,2.20504149278999], +["1xuz",2.2,2.40528803209332], +["1g4r",2.2,2.86457460354336], +["1efy",2.2,2.48799913116495], +["4erk",2.2,3.64713586555331], +["1air",2.2,2.33273716054194], +["2ewe",2.2,2.12353389288563], +["2pec",2.2,2.42687851807432], +["1yds",2.2,3.00674101457756], +["1ydr",2.2,3.06019560447722], +["1q8w",2.2,2.11265028125237], +["2erz",2.2,2.9196673183556], +["1w82",2.2,1.64993248992977], +["1w84",2.2,1.79470364213671], +["1o88",2.2,2.04250643526113], +["1o8g",2.2,1.75627609993227], +["1o8f",2.2,2.22896437530696], +["1o8m",2.2,2.09738932081242], +["1o8d",2.2,1.97990041551059], +["1o8j",2.2,2.26224581770380], +["1o8i",2.2,2.13452119132954], +["1o8k",2.2,2.18626740674069], +["1plu",2.2,2.29090396213270], +["1o8l",2.2,2.46757512719071], +["1o8h",2.2,2.37380336077958], +["1o8e",2.2,2.49715848412261], +["1qlg",2.2,2.84155455726555], +["1yfz",2.2,2.56777678917652], +["1fg3",2.2,2.25346829625538], +["1iji",2.2,2.20632488882796], +["1atp",2.2,3.49772497611793], +["1fmo",2.2,3.64329604018554], +["2btz",2.2,2.84911047718992], +["1jbp",2.2,3.20058335068746], +["1jpk",2.2,2.19838809917266], +["2a4n",2.2,2.76339005629915], +["1dp5",2.2,2.43187317003063], +["1gqp",2.2,2.68388213497817], +["2bm4",2.2,2.54659972281408], +["1f8f",2.2,2.46775600126715], +["2ao8",2.2,3.09772617235099], +["1u31",2.2,1.98593425434209], +["1xdd",2.2,1.93226805285108], +["1h6p",2.2,2.90759881521116], +["1l4i",2.2,2.35948352085853], +["1dzt",2.2,2.09911192645502], +["1ej1",2.2,3.04286129971220], +["1pcz",2.2,2.9705049276201], +["1lq0",2.2,2.19577109674135], +["1b78",2.2,3.1766344697885], +["2mjp",2.2,3.42584125283607], +["1js0",2.2,2.64892850540712], +["1zkb",2.2,2.03521573260731], +["1iz2",2.2,2.94064921912279], +["1wke",2.2,2.60698398769693], +["1wkf",2.2,2.80735451484212], +["1ao3",2.2,2.64459539997526], +["1jxp",2.2,3.57574491753062], +["1tbu",2.2,2.99857673928538], +["1gwj",2.2,2.77336615362768], +["1rp4",2.2,2.68986767927491], +["1k2d",2.2,3.05508040791128], +["1wu5",2.2,1.60335565177591], +["1kbg",2.2,2.55886466134814], +["2ct9",2.2,2.18975994851802], +["1etp",2.2,2.45886809845729], +["1fxi",2.2,4.66882195397675], +["1tip",2.2,2.28473696167336], +["1s8d",2.2,2.21452599343753], +["1yn7",2.2,2.41348428757412], +["1t20",2.2,1.77457277547002], +["1t1x",2.2,2.06944886354772], +["1t1w",2.2,2.04441444827704], +["1t22",2.2,2.19167370585939], +["1s9w",2.2,2.21783584292410], +["1agb",2.2,2.08869465310642], +["1agf",2.2,2.16348588391683], +["1inq",2.2,2.76064039538880], +["1yn6",2.2,2.58027983868658], +["1jpg",2.2,3.03576333018750], +["5sic",2.2,3.85660486167125], +["1ty4",2.2,2.67301128970424], +["1qew",2.2,2.14935303492229], +["1e27",2.2,2.42770033345921], +["1c80",2.2,2.87956595392886], +["1ycs",2.2,3.50960353146068], +["2bu1",2.2,2.26483780148471], +["1h30",2.2,2.55007544674844], +["1lgf",2.2,2.36299284316346], +["1xoe",2.2,2.72952462572870], +["1nn2",2.2,3.05135500883020], +["1fl1",2.2,2.33071675939225], +["1n49",2.2,3.08632200311107], +["1cc6",2.2,1.88480697355964], +["1bf3",2.2,2.12484852616828], +["1bkw",2.2,2.34434594384347], +["1d2k",2.2,2.34922517845146], +["1n0j",2.2,2.46301770598404], +["1ap5",2.2,3.03797004524668], +["1ius",2.2,2.14159333727921], +["1k0j",2.2,2.56721245839894], +["1g4x",2.2,2.90259274445982], +["1g7w",2.2,2.85673427595708], +["1g7x",2.2,3.02175838992147], +["1ix8",2.2,2.74659333829529], +["1asd",2.2,2.67557484657279], +["1qir",2.2,2.79283397796328], +["1ix7",2.2,2.85251350356987], +["1ix6",2.2,3.07215173778921], +["1amq",2.2,3.24623071353654], +["1xrg",2.2,1.28160220315011], +["1pm7",2.2,2.73261678243900], +["1v9c",2.2,2.66713157047141], +["1q0h",2.2,1.89273142294179], +["1i6x",2.2,2.66123753870274], +["1m4z",2.2,2.34706656575598], +["2ce4",2.2,2.05308027381545], +["1phz",2.2,2.87772359045998], +["1a39",2.2,1.95601356202141], +["1mk7",2.2,2.19999439503595], +["1sce",2.2,2.91911866153026], +["1x0m",2.2,2.64755894767405], +["1kmk",2.2,2.33834748154761], +["3sc2",2.2,2.86913066975257], +["1l7o",2.2,2.6317117363558], +["1bhm",2.2,2.83286251277172], +["1lwl",2.2,2.29150989348351], +["1a04",2.2,1.98714531829239], +["1gjm",2.2,2.03850813916721], +["1noo",2.2,1.99718749551537], +["3fyg",2.2,3.94861462472949], +["1saw",2.2,1.89258109969998], +["1mmm",2.2,2.00223463909158], +["1tc0",2.2,2.37149267281263], +["1igo",2.2,2.23064994450288], +["1iec",2.2,2.81304686052864], +["1www",2.2,3.38247792895901], +["1q4o",2.2,3.15791834315517], +["1vlm",2.2,1.48501912797245], +["2mip",2.2,3.52428945731421], +["1id4",2.2,2.60183667786132], +["2col",2.2,3.61986315376747], +["10gs",2.2,2.36712365246870], +["1iqu",2.2,2.38450091637252], +["1zot",2.2,3.52583578475658], +["7gss",2.2,2.52549081005027], +["1n9k",2.2,2.00041409330467], +["2glr",2.2,1.6000581398744], +["1q4j",2.2,2.55569503552490], +["1jda",2.2,3.25569729215948], +["1xwb",2.2,2.35285147718119], +["1rhg",2.2,2.86619244774014], +["1gnw",2.2,2.63349910029653], +["1nus",2.2,2.74344753123819], +["1gao",2.2,2.65511759432975], +["1ko0",2.2,2.17259001658548], +["1ay1",2.2,3.37782484156295], +["1qfh",2.2,1.94746960617622], +["1ind",2.2,3.30223308708185], +["1xwa",2.2,2.68360326502906], +["1f75",2.2,1.99320039494438], +["1f82",2.2,3.27032149951323], +["1i6o",2.2,2.27273386902446], +["1kw1",2.2,1.55934612288769], +["4ake",2.2,2.7214074179378], +["1dvg",2.2,2.52127893110736], +["1twn",2.2,2.04330487984787], +["1xk2",2.2,2.57935225097844], +["1sza",2.2,1.88368716775408], +["1a1v",2.2,2.17472199297574], +["1ngy",2.2,2.99707319644947], +["1kut",2.2,3.17525343655843], +["1vb3",2.2,2.56467619870574], +["1kcu",2.2,3.51919581304443], +["1bjm",2.2,3.87881590987573], +["1m0n",2.2,3.19127569650053], +["1qf4",2.2,2.11390116826562], +["1loo",2.2,2.64669358159835], +["1y2a",2.2,2.68775190125371], +["2cgr",2.2,2.92085263095056], +["1t33",2.2,2.52876744711640], +["2ck0",2.2,2.83768380667697], +["6gst",2.2,2.79020266935364], +["1mtc",2.2,3.15555378293707], +["6gsy",2.2,3.36385865519964], +["1kem",2.2,3.1661431537274], +["1pdz",2.2,3.01509031795127], +["1mwo",2.2,2.32939085526387], +["1s9q",2.2,1.79455211017511], +["1sp3",2.2,2.99019716677611], +["1riv",2.2,1.98676359754542], +["1scf",2.2,2.53391400734629], +["5enl",2.2,2.53552490160687], +["6enl",2.2,2.71816129688425], +["7enl",2.2,3.49421087715371], +["1kpc",2.2,3.29661995420221], +["1il1",2.2,2.70186456037891], +["1f8t",2.2,2.38306222267773], +["1eob",2.2,2.25720072679799], +["2cvh",2.2,3.49377050331889], +["1yee",2.2,2.86936135137247], +["2bwu",2.2,1.13638058152565], +["1eyr",2.2,2.33325874448927], +["1yxw",2.2,3.00757704835405], +["1lvb",2.2,2.80133532757069], +["1uth",2.2,2.35820071329307], +["1trn",2.2,2.55328134915859], +["2a2d",2.2,3.57627174815106], +["1im8",2.2,2.57277274837901], +["1uyq",2.2,2.53229307476598], +["1th0",2.2,2.63016503550721], +["1o0q",2.2,1.98180472843514], +["1yt1",2.2,2.15785796912081], +["1u16",2.2,2.38791213433370], +["5aop",2.2,2.20765069320958], +["8gep",2.2,2.77261866993611], +["1ulz",2.2,2.27939934311789], +["1fvc",2.2,2.89728330956152], +["1s54",2.2,2.52470344532196], +["1pxs",2.2,2.53899267195662], +["1tn5",2.2,2.65467309201080], +["1gcb",2.2,2.57103785651169], +["1wty",2.2,2.74605798864203], +["1k35",2.2,2.99226117279752], +["1xpi",2.2,2.24131665369259], +["1nl0",2.2,2.74650820706661], +["1rhj",2.2,2.55281472853225], +["1tv3",2.2,1.90252891268668], +["2eue",2.2,2.81102773335011], +["1dev",2.2,2.93339483167405], +["1x76",2.2,2.48377764011015], +["1z9s",2.2,2.23642891900353], +["1tji",2.2,2.35622167831932], +["1swn",2.2,2.46591303327236], +["1nc3",2.2,2.32408962172645], +["1y6q",2.2,2.22286115039313], +["1y6r",2.2,2.03082352018238], +["1bpl",2.2,2.51714989982113], +["2fm8",2.2,1.936403929808], +["1t0u",2.2,2.73272354395871], +["2c1m",2.2,2.67401998465947], +["1del",2.2,2.93158181138318], +["1ig8",2.2,2.46895452588244], +["3gly",2.2,2.04003974354877], +["1hql",2.2,2.44611088629562], +["1pfo",2.2,3.24786174515097], +["1chu",2.2,3.01405341079494], +["1zaf",2.2,2.88021094052028], +["1tzd",2.2,3.93549714001446], +["1njg",2.2,3.41424602157160], +["1fx5",2.2,2.41070805210332], +["1n46",2.2,2.81691719472982], +["1q8o",2.2,1.83070990867332], +["1n3q",2.2,1.74563849549665], +["1wow",2.2,1.88251342046201], +["1e40",2.2,1.82518778582113], +["1g40",2.2,4.11771621151539], +["1h93",2.2,1.91745878077646], +["1y8e",2.2,4.22443593528731], +["1y13",2.2,2.12341271085171], +["1qcb",2.2,2.46227488636863], +["1tgv",2.2,2.08084506042855], +["1oxn",2.2,2.52768508818379], +["1b5d",2.2,1.96819674271268], +["1ydv",2.2,2.14633352623697], +["1s3f",2.2,2.58784022025432], +["1byd",2.2,3.11473095817324], +["1byc",2.2,3.01826130035454], +["1bya",2.2,3.39299855280887], +["1mkm",2.2,3.35867991457196], +["2g38",2.2,2.27722977540752], +["1wyi",2.2,3.44423179297826], +["1h6g",2.2,2.59113544963922], +["1y2o",2.2,2.09331859425267], +["1iih",2.2,2.59800357441195], +["6tim",2.2,2.83438773069746], +["1pig",2.2,2.20366778523394], +["1ppi",2.2,2.15197881848366], +["1xh2",2.2,2.42503657031612], +["1xd1",2.2,2.50497520293114], +["1ka2",2.2,2.70569466390912], +["1cc2",2.2,1.84785874965302], +["1tgy",2.2,2.16322759593136], +["1csm",2.2,2.61532466479592], +["1uxt",2.2,2.63562557264317], +["1hp4",2.2,1.51189923351617], +["1c9k",2.2,3.59509443111031], +["1w6w",2.2,1.66534601185677], +["1lbz",2.2,3.86046330766243], +["1zvp",2.2,2.74057127106132], +["1w8e",2.2,1.59809171678619], +["1bs8",2.2,2.97919847033260], +["1cpj",2.2,3.19545313742527], +["2aa5",2.2,1.98936966942926], +["1b15",2.2,2.33907256994812], +["2tsa",2.2,2.88976552674561], +["1ils",2.2,2.07250200887701], +["1nzr",2.2,2.25543980966334], +["1ufa",2.2,2.25378755371821], +["1zjh",2.2,3.11980710272955], +["1ad1",2.2,1.65415469882223], +["2f08",2.2,2.87387614481865], +["1x8u",2.2,2.57226736609325], +["1d8a",2.2,3.06753511646514], +["1dfh",2.2,2.36013356313002], +["1k1f",2.2,3.40498219906226], +["2ab5",2.2,2.04728896784564], +["1dwq",2.2,2.56201188163666], +["2b5d",2.2,2.98408449962879], +["2ar8",2.2,2.08041276033378], +["1e8d",2.2,2.42767547921371], +["1dwo",2.2,2.45856466118784], +["1dwp",2.2,2.47275984857631], +["1b40",2.2,2.28330337120841], +["1wn0",2.2,2.35279462662901], +["1ete",2.2,2.71675188770634], +["2an4",2.2,2.02526378596697], +["1j7l",2.2,2.14771164488489], +["2an3",2.2,1.83722551908514], +["1som",2.2,2.46323374523952], +["1jtu",2.2,2.75968880588802], +["2kce",2.2,2.17488594109805], +["1odc",2.2,2.39680810075422], +["1s5h",2.2,1.94510381768798], +["1hx8",2.2,2.80988310426908], +["1fqo",2.2,2.56536867893689], +["1frz",2.2,2.70625737524462], +["1n7v",2.2,2.59047271061554], +["1gqr",2.2,2.54796120139529], +["1vxr",2.2,2.45194141497371], +["2cek",2.2,2.55297475369121], +["1nv8",2.2,2.80131045915970], +["2bj3",2.2,2.73211034887788], +["1gt6",2.2,2.69411043843885], +["1pv8",2.2,3.08712978439568], +["1ba3",2.2,2.14169582560915], +["1prg",2.2,3.26500768443504], +["1qz7",2.2,2.78869359307421], +["1e9n",2.2,2.69641037774849], +["1d1j",2.2,2.40067577662234], +["1v0b",2.2,2.55841106411101], +["2bvl",2.2,1.90526450931113], +["2gaw",2.2,2.55096753843525], +["1imb",2.2,2.13373964650599], +["1mnq",2.2,3.08204932736279], +["1dbq",2.2,4.00801395373959], +["1vb5",2.2,2.31501442172662], +["1mn6",2.2,2.479017708993], +["1yvz",2.2,2.61636725434647], +["1xl3",2.2,2.59770493114791], +["1g7r",2.2,3.44867782024466], +["1bsf",2.2,3.78605283583322], +["1m53",2.2,2.71489140438084], +["1wgi",2.2,1.90564837559031], +["1aus",2.2,2.59801681841495], +["1huk",2.2,2.7652578908046], +["1jf7",2.2,3.02498402887810], +["1hda",2.2,2.29050716458740], +["2hhe",2.2,3.19544579592731], +["1qvc",2.2,3.86462046740676], +["1mkx",2.2,3.40731852709944], +["1p2e",2.2,2.79744095120698], +["1zup",2.2,2.26366537152103], +["1uh5",2.2,2.30160163046714], +["1si4",2.2,2.5745282461701], +["1y5k",2.2,2.41735774892691], +["1j7s",2.2,2.21466517076335], +["1yh9",2.2,2.17400426656305], +["1hdb",2.2,2.36481279581686], +["2hhd",2.2,2.65655657935629], +["1ep1",2.2,3.05848373945555], +["1wtg",2.2,2.21097805797160], +["2a2l",2.2,2.56706012238218], +["1hbh",2.2,2.59679334411147], +["1g5p",2.2,3.16731015752624], +["2nip",2.2,3.19493614854503], +["1ixc",2.2,2.18079672974109], +["1vng",2.2,2.04465644373161], +["1jzk",2.2,1.79182465370343], +["1rbl",2.2,2.64141517129761], +["1xb0",2.2,2.60355840733774], +["1zc6",2.2,2.76484713164379], +["2aa4",2.2,1.92850487575839], +["1mp3",2.2,2.28896200712223], +["1mp4",2.2,2.45681372588162], +["1dia",2.2,1.60773149706433], +["1dig",2.2,1.61778684349712], +["2fjn",2.2,2.57051565009823], +["1q6s",2.2,2.5911284897087], +["1vq0",2.2,2.01108284728402], +["1s4c",2.2,3.12377774405483], +["1il0",2.2,2.25258052855884], +["1dku",2.2,2.5390652286479], +["1tsr",2.2,3.75900074949297], +["1tup",2.2,3.78634091678998], +["1n1q",2.2,2.47637026831839], +["1xva",2.2,3.02821335027789], +["2hdh",2.2,2.19420319191107], +["1fvr",2.2,1.81865196222879], +["1guy",2.2,1.97356917993895], +["1jez",2.2,2.07509111886063], +["1ulg",2.2,2.84710575212847], +["1gml",2.2,2.14936893998538], +["1fch",2.2,1.71166566678206], +["1r42",2.2,3.10682613013435], +["1jlx",2.2,2.54386219897346], +["1jly",2.2,2.56327737621313], +["1qsl",2.2,2.97073714665461], +["1krp",2.2,3.05757312341263], +["1e2m",2.2,2.56778385170757], +["1ex1",2.2,2.39071145298112], +["1uk2",2.2,3.26158774128216], +["1iex",2.2,2.23443219280214], +["1ki7",2.2,3.16032788737013], +["1ki8",2.2,3.17913347406633], +["1f7u",2.2,2.50424417829409], +["1e2n",2.2,2.54308377469601], +["1gaw",2.2,2.39936221967723], +["1wsg",2.2,2.81704271306475], +["1gw6",2.2,2.05084640279385], +["1ki2",2.2,3.36673133213849], +["1qyc",2.2,2.79435541570269], +["1wql",2.2,2.11943650767501], +["3atj",2.2,1.81448887525834], +["1i74",2.2,3.04108747483809], +["1gx2",2.2,1.69512559813798], +["1to5",2.2,1.92675896473691], +["1mz5",2.2,2.74898035616652], +["1w6c",2.2,1.88040063737521], +["1av4",2.2,2.54950025185954], +["1avk",2.2,2.75782990870724], +["1oak",2.2,3.02004896248662], +["2fhr",2.2,2.30151927094215], +["1oas",2.2,2.24128555870643], +["1w54",2.2,1.783803632485], +["1ucw",2.2,1.77515242253084], +["1fpj",2.2,2.45851634613951], +["1fpe",2.2,2.54145561081439], +["1s46",2.2,1.43066149612035], +["1nn4",2.2,2.87853521965170], +["1juq",2.2,2.44900788504531], +["1wsa",2.2,2.86263338037892], +["1i5p",2.2,2.73611883660734], +["1te0",2.2,3.93128282932981], +["1ww6",2.2,2.89858875059972], +["1ww5",2.2,2.95804880932074], +["1sz2",2.2,2.84926677552368], +["1izj",2.2,2.46266715736676], +["1izk",2.2,2.30903035416299], +["3dap",2.2,2.45592219440581], +["1dap",2.2,3.28288397222185], +["1ev9",2.2,3.20061666199919], +["1goh",2.2,2.69380219949105], +["1kbu",2.2,3.80101430539252], +["1o7h",2.2,2.42331319979793], +["4crx",2.2,3.33309685462936], +["1xb2",2.2,2.5758822108971], +["1xah",2.2,2.94660221666303], +["1bks",2.2,2.89929702409888], +["2d00",2.2,3.05789120350025], +["1kwk",2.2,1.96562592409080], +["150l",2.2,3.54555682138312], +["2irf",2.2,2.21877931680280], +["1ev4",2.2,2.97467253694172], +["1c8v",2.2,2.79681299517761], +["1qor",2.2,2.44454079911252], +["1tv8",2.2,2.69614428328222], +["1vg0",2.2,2.32025639732646], +["12as",2.2,3.19030935547559], +["1tu4",2.2,2.68490627217484], +["2bks",2.2,2.82179765846094], +["1wdt",2.2,2.26939884313527], +["1j49",2.2,3.23684844466481], +["9ldb",2.2,3.27377696450837], +["2cvx",2.2,2.82598529562313], +["1gjy",2.2,3.37594776555089], +["1ii7",2.2,2.27226733765263], +["1pz1",2.2,2.42226212932185], +["1y1o",2.2,2.54191138739907], +["1w5b",2.2,2.81424788463223], +["1q3d",2.2,2.19433751026274], +["1y0g",2.2,2.55489129663072], +["1ps9",2.2,2.98350671290230], +["1rdy",2.2,2.85863978002154], +["2c6g",2.2,2.11808040763998], +["1rzm",2.2,2.57457099996881], +["1cno",2.2,2.00958210457086], +["1rib",2.2,2.20750001374494], +["1piu",2.2,2.38815614748379], +["1pfr",2.2,2.90545065964032], +["1noz",2.2,3.66309353926578], +["1m8w",2.2,2.31707316759553], +["1rsv",2.2,3.03182672855799], +["1m8x",2.2,2.59470636347126], +["1sb7",2.2,2.5661018101861], +["1yiq",2.2,2.85446414065709], +["1cxi",2.2,2.34007343602215], +["2ca6",2.2,2.77244410786234], +["1dr0",2.2,3.46558111256428], +["1vkg",2.2,3.02905674938296], +["1fck",2.2,2.84067738836067], +["1lfg",2.2,3.40279757246374], +["1b0l",2.2,3.16659312895989], +["1ker",2.2,1.91421315527588], +["1iug",2.2,2.66191262087271], +["1u19",2.2,3.63086527416705], +["1fro",2.2,1.86606906551758], +["1tk6",2.2,2.35454157876771], +["1tkp",2.2,2.48547557377215], +["1pr0",2.2,2.7369109961958], +["1vz2",2.2,1.77482720488233], +["1noy",2.2,3.30483717878728], +["1m50",2.2,3.04889903328343], +["1bh5",2.2,2.11122950619753], +["1z5l",2.2,2.84747078053159], +["1yta",2.2,2.09182054249436], +["1f6r",2.2,2.72960194907795], +["1f6s",2.2,2.55408736928506], +["1n7r",2.2,2.95899729813680], +["1n4m",2.2,3.55809990449227], +["1s7h",2.2,2.82072933864979], +["1hgy",2.2,2.46905772563357], +["1leh",2.2,3.19533115308064], +["1w6j",2.2,1.85752030125045], +["1jmo",2.2,2.86785328174832], +["1ru3",2.2,3.49238006681466], +["1a5l",2.2,2.36795445427367], +["1jcs",2.2,1.92638736046834], +["1kzo",2.2,2.12560469779421], +["1lta",2.2,2.04546725219710], +["1qmd",2.2,1.76176197269229], +["1ejh",2.2,2.80738578263718], +["2cyc",2.2,2.19400360831586], +["1xx9",2.2,2.98185455664892], +["1p0c",2.2,2.33543886074447], +["1mp0",2.2,2.06783682257052], +["1deh",2.2,2.53668759893382], +["1hsz",2.2,2.29382550037146], +["1obh",2.2,1.95498870478120], +["1ftx",2.2,2.46275218955687], +["1niu",2.2,2.58210430172337], +["1epv",2.2,2.75308121464048], +["1s7v",2.2,3.08488217970316], +["1i7r",2.2,2.31812963926350], +["1i1y",2.2,2.43580029276607], +["1tdt",2.2,2.32286945607987], +["1h6c",2.2,2.66511313529466], +["1ryd",2.2,2.65706540165198], +["1t7p",2.2,2.41232200834954], +["1nqw",2.2,1.83715119834924], +["1fwj",2.2,2.19017375784149], +["1b5o",2.2,2.21138697229769], +["1a5k",2.2,2.28830058396925], +["1lns",2.2,2.56200606399402], +["1n31",2.2,2.25695704101759], +["1ur4",2.2,2.50099517753212], +["1ji3",2.2,2.53427822050171], +["2bgg",2.2,2.83723286750643], +["1tk5",2.2,2.49227676395571], +["1sl1",2.2,2.59518235052348], +["2ay4",2.2,2.55888698436743], +["2ay1",2.2,2.55561723360061], +["2ay8",2.2,2.69373833683362], +["2ay6",2.2,2.7488051060732], +["1nsb",2.2,2.30186645673126], +["1a4g",2.2,2.40981467338872], +["2bet",2.2,1.46861129145216], +["1cl2",2.2,1.99263524647978], +["1t3d",2.2,2.14916425299171], +["1hf2",2.2,3.16925389503823], +["1zm7",2.2,2.24333745466327], +["1nq3",2.2,1.93764197986842], +["1wy7",2.2,2.97335828973744], +["1qe5",2.2,2.63265962134614], +["1lxm",2.2,3.39220732606833], +["1kyq",2.2,2.78964863135253], +["1x2a",2.2,2.84175081232475], +["1x29",2.2,2.87142692109143], +["1aia",2.2,2.84774005380712], +["1arg",2.2,3.18920574506286], +["1lgy",2.2,2.78619108072215], +["1nvu",2.2,2.20037168309974], +["2a39",2.2,1.72144305407307], +["1jvs",2.2,2.74932953535663], +["1nf2",2.2,3.29536425014901], +["9aat",2.2,2.51281404711515], +["1tar",2.2,2.79733518427051], +["1p2b",2.2,2.44492313585877], +["1p29",2.2,2.3874690514908], +["1fc5",2.2,2.50489514582627], +["2boa",2.2,2.99435986752585], +["1k2u",2.2,2.81878587117632], +["1k2t",2.2,2.70773429765767], +["1i08",2.2,1.82028182618470], +["1i8q",2.2,3.49856038737542], +["1syo",2.2,3.31191996541744], +["1su3",2.2,2.30600599116235], +["1obk",2.2,2.4778393958051], +["1obi",2.2,2.63454729150946], +["2a5v",2.2,2.00266553437180], +["1zrq",2.2,2.04929117482858], +["1iof",2.2,2.87745073910039], +["1e8x",2.2,3.46861124394484], +["1d1y",2.2,2.61756183240557], +["1fol",2.2,2.65435314958926], +["1pt8",2.2,2.33704101307943], +["8gpb",2.2,3.22889951946672], +["1bk5",2.2,2.37636154595402], +["1iic",2.2,2.79265595638858], +["1xgv",2.2,2.78330840303977], +["1rfi",2.2,2.27946464452032], +["1hu9",2.2,3.34741667329502], +["1s06",2.2,2.17139408937591], +["1owc",2.2,3.08764680304181], +["1k3p",2.2,3.21722011986399], +["1hxs",2.2,2.12788323947276], +["1p5h",2.2,2.41088576937556], +["1xtf",2.2,2.85776935282720], +["1bou",2.2,2.70777343280383], +["2pcp",2.2,3.77425352472633], +["1lny",2.2,2.51496181698807], +["1v2i",2.2,2.75290062427015], +["1jc5",2.2,2.51311829328742], +["1ct8",2.2,2.92538573267838], +["1j1j",2.2,3.13419687771756], +["4cel",2.2,1.5093980148683], +["1kc7",2.2,2.93985776005884], +["1p2z",2.2,2.30097837499894], +["1fuj",2.2,3.29806425142243], +["1unl",2.2,2.68606831994601], +["1jxv",2.2,2.74479888557135], +["1gon",2.2,2.07354214257043], +["1p35",2.2,2.73956297997373], +["1ali",2.2,2.22266292629207], +["1qfj",2.2,2.77794452173565], +["1bd4",2.2,3.7668514239604], +["1ewk",2.2,2.09515475555317], +["1c9u",2.2,2.8825570461661], +["1zpy",2.2,3.11217948169235], +["2hrp",2.2,3.08059303290923], +["1t0s",2.2,2.72857946357171], +["1hy0",2.2,2.48102500084158], +["1loa",2.2,3.05271537302901], +["1geu",2.2,2.21660916809984], +["1ew8",2.2,2.60614720187736], +["1ivy",2.2,2.4856256010413], +["1s8a",2.2,2.21603878997801], +["1ucy",2.2,3.44065165733301], +["1tzg",2.2,2.40985431115563], +["1u2g",2.2,1.99767102492743], +["1b47",2.2,3.11050818900011], +["43c9",2.2,2.61885269694260], +["1k0d",2.2,2.59172132276252], +["1wm9",2.2,1.75671051154203], +["1vrt",2.2,3.02784764457393], +["1qu2",2.2,3.35895375281236], +["1ffy",2.2,3.35945518464775], +["1za1",2.2,3.34799809374697], +["1rzj",2.2,3.282564257215], +["1g9m",2.2,3.43389018782392], +["1z5c",2.2,2.16359111030566], +["1z5a",2.2,2.41478483560631], +["1mt1",2.2,1.87694306750708], +["1vlh",2.2,2.22823980988907], +["2fgy",2.2,2.07341800767775], +["1q2l",2.2,2.80366846210193], +["1stz",2.2,2.51867585467808], +["1t5f",2.2,2.44628329530644], +["1t4t",2.2,2.73803554097454], +["3lad",2.2,3.36934830926764], +["1krf",2.2,2.59721513066356], +["1kre",2.2,2.58611484762265], +["1kkt",2.2,2.67395295402241], +["2ako",2.2,1.54962857148889], +["1now",2.2,1.41715349757453], +["1tnd",2.2,3.14225683312848], +["1v59",2.2,2.75588536576403], +["1rth",2.2,3.44962165347468], +["1mdu",2.2,2.88966131818862], +["1ddz",2.2,2.85495308135832], +["1cfz",2.2,3.0035411437429], +["1r64",2.2,2.34820881909935], +["2bm2",2.2,3.28053534512738], +["1jv3",2.2,2.42061912656559], +["1lto",2.2,2.89718542058456], +["1mxh",2.2,2.68153499717406], +["1e4l",2.2,2.43786407409269], +["1rzq",2.2,2.14337124773485], +["1uwx",2.2,2.67459648931618], +["1apx",2.2,2.07628192962751], +["2c64",2.2,2.11817448098883], +["2byb",2.2,2.33019699704581], +["1ca4",2.2,2.65249695044121], +["1hdc",2.2,3.48647768653802], +["1rm3",2.2,2.39888949830664], +["1gyk",2.2,2.01505182429974], +["1lt6",2.2,2.84788090571621], +["1e92",2.2,2.18387609404276], +["1xkv",2.2,2.09373092824606], +["1xev",2.2,2.24539862896225], +["1wxr",2.2,2.85108753835431], +["1ytm",2.2,2.52025979992136], +["1xny",2.2,2.63197697514171], +["1r0x",2.2,2.73399779443199], +["1jki",2.2,3.87925879830057], +["1yvp",2.2,2.67956553323419], +["1n5m",2.2,2.47847021144213], +["1kyz",2.2,2.99223247992051], +["1o57",2.2,2.89909451440304], +["2phl",2.2,3.11170067165489], +["1rlt",2.2,2.89083084051744], +["1oxw",2.2,3.13325107845927], +["1yq3",2.2,2.55296028671612], +["1qlt",2.2,2.53287941216035], +["3fru",2.2,2.8719608874052], +["1vi8",2.2,2.58381159808699], +["1tx6",2.2,2.61441678027412], +["1h27",2.2,2.74034473057622], +["1aso",2.2,2.10515844663958], +["1hqn",2.2,2.57120176772130], +["1qmz",2.2,2.78273661298963], +["1w8d",2.2,2.66892445955426], +["1u2z",2.2,2.56414770337556], +["1nu7",2.2,2.60843839012536], +["1eys",2.2,3.3289131326206], +["1nu9",2.2,2.65826025262429], +["1xi1",2.2,2.96362558660732], +["1iq8",2.2,2.97505271327447], +["1e7a",2.2,3.41997671580099], +["1nal",2.2,2.98293871628340], +["1hyh",2.2,1.9548298246396], +["1vb9",2.2,2.61450640871775], +["1pix",2.2,2.52172740666293], +["1t9b",2.2,1.88708249626369], +["1vrn",2.2,2.04127517638436], +["2b2x",2.2,2.88043044707266], +["1xl8",2.2,2.19114589916468], +["3tf4",2.2,2.04495989344741], +["1rz0",2.2,2.19987730752391], +["1j2g",2.2,2.00477528344646], +["1wek",2.2,2.79567401271860], +["1ivx",2.2,2.67098874275479], +["1b06",2.2,2.72376195295608], +["1jji",2.2,2.82529828509563], +["1gtm",2.2,2.87187739068796], +["1is2",2.2,2.58485841763155], +["1r38",2.2,1.40455444511551], +["2amf",2.2,2.139279754996], +["1ksi",2.2,2.59240789351363], +["1ev2",2.2,1.92259241108973], +["1dcu",2.2,2.51710095315576], +["1s0c",2.2,2.24196213034265], +["1s0d",2.2,2.60239589261513], +["1g9d",2.2,2.65737423093597], +["4eca",2.2,2.82052216534672], +["1um9",2.2,2.13506057004545], +["1n7g",2.2,1.79826950408583], +["1pzf",2.2,1.57555661811685], +["2a8d",2.2,2.54684815285007], +["1lrt",2.2,2.54450965717651], +["1bp5",2.2,2.7476166631596], +["2dbv",2.2,2.80028489830290], +["1nqa",2.2,2.11692871532958], +["1lf9",2.2,2.52830881920627], +["2az3",2.2,2.70936470846171], +["1j0d",2.2,3.01559943077626], +["1a99",2.2,2.45530276224086], +["1com",2.2,2.35918991904857], +["1ovl",2.2,2.81172155709626], +["2cht",2.2,2.69974228985302], +["1tcm",2.2,3.69906510284897], +["1ukt",2.2,2.98193961375182], +["2cvo",2.2,2.24685171866293], +["1q0f",2.2,1.46292765829979], +["1q0d",2.2,1.60262478083277], +["1z2i",2.2,3.06999300816223], +["1pl7",2.2,2.17880842817626], +["1xdj",2.2,2.69655273690585], +["2ggi",2.2,2.45347557281333], +["1nkq",2.2,2.78673860899384], +["1cn3",2.2,2.63678135248186], +["1qaf",2.2,2.69145978645843], +["1qal",2.2,2.55834149582687], +["5bj3",2.2,2.57729309126624], +["1nwu",2.2,1.96143983498968], +["1ex5",2.2,3.35362306993306], +["1znn",2.2,2.11892202765790], +["1nw4",2.2,2.44062494561256], +["1du3",2.2,3.78884856086939], +["2ggh",2.2,2.74908158068297], +["1u8e",2.2,3.09358149929898], +["1rwq",2.2,3.22721240994599], +["1djq",2.2,2.00429278051128], +["1djn",2.2,2.02236836663609], +["1wcy",2.2,2.11374672054144], +["1sjb",2.2,3.26323509801074], +["1nmo",2.2,2.50006329136569], +["1nmp",2.2,2.52707649509467], +["1u1c",2.2,2.21437700661307], +["1pdw",2.2,2.27183516221419], +["1j21",2.2,2.72309193843976], +["1ewq",2.2,2.90422313729813], +["1s7u",2.2,2.52670184362773], +["1yym",2.2,2.80542430168933], +["1sqj",2.2,2.62947400435505], +["1e3m",2.2,2.47160589489438], +["2fw2",2.2,2.41136211758973], +["1bxb",2.2,2.60910793587905], +["1em6",2.2,2.97456380722894], +["1xim",2.2,2.05731192815404], +["1hzd",2.2,2.53518276997721], +["2aw3",2.2,2.30225211186042], +["1l6i",2.2,2.61054243373179], +["1j51",2.2,2.92361462872391], +["2byy",2.2,2.59471280330035], +["1aij",2.2,2.23408636700762], +["1vrq",2.2,2.2641960211009], +["1de5",2.2,3.17913837383273], +["1rf4",2.2,3.04589109825874], +["2aam",2.2,1.53688273714563], +["2c0u",2.2,2.40419842081180], +["1dio",2.2,3.13779284559496], +["2ai0",2.2,2.55242339733164], +["1tfw",2.2,2.05042588997734], +["1yni",2.2,2.62881252246451], +["1v1j",2.2,1.92226638048404], +["1tr1",2.2,2.75869554008493], +["1uli",2.2,1.99797740632116], +["1im3",2.2,2.10041835963323], +["1wnb",2.2,2.40699527371440], +["1sql",2.2,2.57824021890523], +["1fea",2.2,3.15362307317416], +["1siw",2.2,2.50646522789762], +["1dgb",2.2,2.55890806080316], +["1gpm",2.2,2.18754199098934], +["1zk3",2.2,2.0033839122939], +["1ux2",2.2,2.27138603039111], +["1j0z",2.2,2.24171840044868], +["5bca",2.2,2.8946858766996], +["1mmo",2.2,2.73631613682486], +["2exk",2.2,2.34749814996914], +["2exj",2.2,2.76508436666859], +["1m32",2.2,2.37803277616057], +["1y9d",2.2,2.67040388472578], +["1aa1",2.2,2.46170090186575], +["1qla",2.2,2.72391270853413], +["1up8",2.2,1.65960549608471], +["1nx9",2.2,2.08216160411278], +["1sb3",2.2,2.105765356573], +["3pca",2.2,2.55699908329441], +["1xdy",2.2,2.79680483223652], +["1s20",2.2,2.47056557670209], +["5req",2.2,2.16310783612375], +["4req",2.2,2.26175373893526], +["6req",2.2,2.12448602895708], +["7req",2.2,1.73038889742590], +["1rvx",2.2,2.83229206630395], +["1qf7",2.2,2.29411639562085], +["1g20",2.2,2.89630515941772], +["1w0j",2.2,2.34886484733001], +["1xo6",2.2,2.81515576357581], +["1u6i",2.2,2.82333431495648], +["1vqo",2.2,2.76341300488074], +["1vq8",2.2,2.81290968440178], +["1gh0",2.2,2.40219804673676], +["1ha7",2.2,1.76056620505173], +["1w91",2.2,2.99839584990488], +["2bs9",2.2,2.49893736407002], +["2a3w",2.2,2.24211535628520], +["1uw6",2.2,2.34930347768054], +["1xsi",2.2,2.59472084951299], +["1xsk",2.2,2.86961506627498], +["1uzh",2.2,2.14151254714019], +["1mjg",2.2,2.47102174737268], +["1ti4",2.2,2.58587018479321], +["1vle",2.2,2.62136067259820], +["1twl",2.2,1.47946511455393], +["1u8g",2.2,2.75772594464068], +["2a99",2.2,2.08925849682169], +["1u41",2.2,1.97786208062984], +["1t5d",2.21,1.93804195432482], +["1rrw",2.21,2.61718248182380], +["2d27",2.21,2.62474918023545], +["1mvn",2.21,2.44596713693746], +["1p61",2.21,2.56158205667104], +["1npr",2.21,2.87663177255319], +["1vyz",2.21,1.80720237825993], +["1ppw",2.21,2.86956928710323], +["1tjf",2.21,2.65850541950455], +["2cck",2.21,2.30233151445406], +["1ua7",2.21,2.23182634459614], +["2b9y",2.21,1.60584996978006], +["2eys",2.21,2.33836546450667], +["1ea1",2.21,2.62986490795795], +["1u3r",2.21,2.50328193019249], +["1kp9",2.21,2.70553819168727], +["1roz",2.21,1.74449760200383], +["1ntg",2.21,2.55983737910209], +["1r7i",2.21,2.89358508943799], +["2c5u",2.21,2.65381270380094], +["1pjq",2.21,3.27280788420681], +["1ih7",2.21,2.45183344171690], +["1ms4",2.21,2.22344203842496], +["1v8z",2.21,2.68490437446133], +["1z6t",2.21,2.02551811784809], +["3pci",2.21,2.57804924317338], +["1p7z",2.21,2.32660890228963], +["1w7h",2.21,2.31083795917889], +["1upj",2.22,3.3997101262261], +["1gh2",2.22,2.4497613107753], +["1p5s",2.22,2.10846489839647], +["1kye",2.22,2.70094492568283], +["1ul9",2.22,2.50937205380923], +["1war",2.22,1.67157703889274], +["1rrq",2.22,2.86336459085162], +["1z2x",2.22,2.53015808689856], +["1f4v",2.22,3.03047367808619], +["2b9x",2.22,1.83795476775017], +["2b2a",2.22,2.34510675225668], +["1sw7",2.22,2.04888895655227], +["1y0a",2.22,2.38912638130098], +["1yeo",2.22,2.31471285620852], +["1y4r",2.22,2.68896212401689], +["1y46",2.22,2.28449558579948], +["1td2",2.22,2.69450138031793], +["2b8w",2.22,2.68882098264605], +["1yjg",2.22,2.0933206108047], +["2afu",2.22,2.04235650683479], +["2afs",2.22,2.13718082211737], +["1j91",2.22,3.07120757169199], +["1u0m",2.22,3.62644517385468], +["1s9v",2.22,2.30692237603398], +["2b99",2.22,2.65810215854853], +["1qvo",2.22,2.77010804625859], +["1rs9",2.22,2.55933224616329], +["1rgu",2.22,2.28735429843249], +["1s89",2.22,2.10976103729759], +["2ush",2.22,2.78097499146984], +["1p4a",2.22,2.98133379749775], +["1p5e",2.22,2.51753487697018], +["1r9j",2.22,2.14145543708573], +["1hwk",2.22,2.29015919234994], +["1ykm",2.22,1.81765065136259], +["1d6p",2.23,2.74048233881254], +["1bso",2.23,2.61104294073688], +["3aky",2.23,2.73806746701235], +["1h8a",2.23,2.66894011506208], +["1mza",2.23,2.93813857844275], +["1jb4",2.23,3.18615653796107], +["1bb4",2.23,3.440311516024], +["1gan",2.23,2.6102034861904], +["1qnu",2.23,1.31491520556624], +["1qnb",2.23,2.41442635649268], +["1yft",2.23,3.26540170710265], +["1a65",2.23,2.46840174474365], +["1px2",2.23,1.98800398818166], +["1men",2.23,2.63520532856403], +["2gdk",2.23,1.80172868413656], +["1q3x",2.23,2.61118326300294], +["1tbm",2.23,1.77168730623710], +["1eyk",2.23,2.71767538992904], +["1e1y",2.23,2.64594331317185], +["1rj8",2.23,2.28699580820614], +["1w1u",2.23,2.73444696471867], +["1xl9",2.23,2.42091184999983], +["1vhj",2.23,2.34183659627704], +["1jko",2.24,3.26327319149012], +["1hey",2.24,2.42262057017431], +["1r0o",2.24,3.31529602779047], +["1bsy",2.24,2.65959767999485], +["1n5v",2.24,2.24963257978333], +["1ymg",2.24,3.23455262265380], +["1dht",2.24,3.30162697592738], +["1iuc",2.24,2.24945064275989], +["1vfz",2.24,3.17763073024153], +["1s6r",2.24,3.77730309184092], +["1i7a",2.24,2.84808611812491], +["1wb7",2.24,2.39097252712497], +["1u92",2.24,2.76865305907651], +["1u8j",2.24,2.73156438682668], +["1u95",2.24,2.66368145243596], +["1u91",2.24,2.68103722330914], +["1u8q",2.24,2.78205283291653], +["1u8k",2.24,3.0057581080786], +["2ah8",2.24,2.82716285190371], +["1zd1",2.24,2.786789152207], +["2b7d",2.24,2.90778472752525], +["1s2i",2.24,2.46467318441060], +["1svx",2.24,2.57284528898048], +["1idu",2.24,2.50085920351544], +["1i7m",2.24,2.80128558693965], +["1ug3",2.24,2.36899434796074], +["2ae5",2.24,1.74448134341822], +["2c3h",2.24,3.07717376870246], +["2a9v",2.24,1.81783576723496], +["9nse",2.24,2.43748584409282], +["1h26",2.24,3.08978770960346], +["1yxu",2.24,2.4168299491094], +["1xe3",2.24,2.5145975122119], +["2a7k",2.24,2.12592527383576], +["1vay",2.24,2.40508842653404], +["1w2z",2.24,1.92678705273914], +["2adv",2.24,1.75231781128155], +["1xlv",2.25,2.69248901452458], +["1zil",2.25,3.58750000999039], +["2pk4",2.25,3.8222980312914], +["2a3g",2.25,1.78691197074259], +["1cwd",2.25,2.57073672706905], +["1o4h",2.25,2.3939669376215], +["1rap",2.25,2.8326237497389], +["1d5e",2.25,3.17389965885619], +["1fev",2.25,2.83657906391200], +["1d5h",2.25,3.0521585339151], +["1d5d",2.25,2.82446513579769], +["1j7z",2.25,3.01592957274529], +["2ets",2.25,2.08205022762334], +["1c76",2.25,2.73098280252437], +["2mad",2.25,3.12195792515340], +["2c9l",2.25,2.33157554628861], +["1k40",2.25,2.86081988788237], +["1rcb",2.25,3.84952212105091], +["1siz",2.25,1.96719465885665], +["1cnu",2.25,2.68678210749497], +["1lpe",2.25,2.48399655004042], +["1pmk",2.25,4.72357069062076], +["1q2d",2.25,3.34392724092784], +["1q2c",2.25,3.22636725879337], +["2bs8",2.25,3.60526523100565], +["1a4p",2.25,2.66277697805608], +["1p78",2.25,2.39418709622473], +["1ej4",2.25,2.90868909625621], +["1hvs",2.25,2.17313969661401], +["1k6t",2.25,2.09032438445870], +["1p3v",2.25,2.78649141018099], +["1p10",2.25,2.29346602980695], +["2lpr",2.25,2.29346602980695], +["8lpr",2.25,2.35876750838535], +["2f7t",2.25,2.71543451083801], +["1q3p",2.25,2.90758411681554], +["1s3y",2.25,3.15369475462317], +["1jv7",2.25,2.72921981896816], +["2blc",2.25,3.1600231863056], +["1s3g",2.25,2.89768385896524], +["1c4f",2.25,3.31343732109166], +["2ssp",2.25,2.40258526218301], +["1qkn",2.25,2.51808200622943], +["1hy5",2.25,2.81381850958537], +["1xq3",2.25,1.79743687978209], +["1a98",2.25,1.82695285496837], +["1cvf",2.25,2.83577749297358], +["1ccu",2.25,2.8278577901513], +["1cva",2.25,2.76378608969398], +["1cve",2.25,2.77855747430291], +["1bnw",2.25,2.40143466269697], +["1a42",2.25,2.44614980053451], +["1kwr",2.25,2.35875312130855], +["1y6p",2.25,2.56021701594976], +["1nnr",2.25,2.43321949736152], +["1nw8",2.25,2.23739701314039], +["1lhe",2.25,3.26667306130366], +["1lhg",2.25,3.4475002695535], +["1odf",2.25,2.36072141885813], +["1ei9",2.25,2.96948449341483], +["1ncf",2.25,2.28012005105115], +["1w9f",2.25,2.13713816039338], +["1s3j",2.25,1.97318461165554], +["1dd7",2.25,2.60667226897801], +["2c5y",2.25,3.54314234788], +["1xar",2.25,2.42506964019454], +["7prn",2.25,2.76207132710174], +["1c7e",2.25,2.74919490153982], +["1a3y",2.25,2.65647419393526], +["1quf",2.25,2.82625077921435], +["1bzj",2.25,2.0419190609101], +["1b30",2.25,1.51330157875346], +["1zcw",2.25,1.88212534141840], +["1zp7",2.25,2.85823587541823], +["1vlv",2.25,1.95940370365973], +["1cps",2.25,3.23854555251772], +["1ifv",2.25,1.67418796444738], +["1mx2",2.25,2.39361049753941], +["1mnm",2.25,2.44859742002179], +["1ala",2.25,3.10932765813618], +["1o89",2.25,2.28865332348067], +["1f4m",2.25,2.36963630146908], +["1m5x",2.25,2.83862879986321], +["1v8k",2.25,3.17244490591996], +["2baj",2.25,2.82290528070385], +["1w9o",2.25,2.36363801048007], +["2aca",2.25,2.64386655554444], +["1h2l",2.25,1.88877809283804], +["1qxl",2.25,3.34435801415357], +["1a26",2.25,2.42783938397046], +["1jlu",2.25,3.16654915942646], +["1pey",2.25,2.88858295138241], +["1yob",2.25,2.92346021767218], +["1ign",2.25,2.53424552279123], +["1b7a",2.25,2.33963806008294], +["2f6h",2.25,2.12943273564120], +["1rc1",2.25,2.06997279141416], +["1mj7",2.25,2.74662507368282], +["2g9n",2.25,2.70901816126432], +["1yjy",2.25,2.44577694716306], +["1dkm",2.25,2.80174704969406], +["1ynu",2.25,2.37980373395389], +["1q6i",2.25,2.06739950662446], +["1emt",2.25,3.26569794958950], +["1fby",2.25,3.06677014082931], +["2esf",2.25,2.5142894720649], +["2cdf",2.25,2.69590395010531], +["3enl",2.25,3.00904851907568], +["1eoc",2.25,2.33984248446421], +["1eo2",2.25,2.50809643025094], +["1kdr",2.25,3.59709433440525], +["1r7m",2.25,2.95557318060797], +["2atw",2.25,2.52153710351508], +["2bvy",2.25,2.34932894613772], +["1jd7",2.25,1.85291080257971], +["1mbx",2.25,2.10532708006492], +["1orj",2.25,2.67904250297348], +["1r6o",2.25,1.74543156501248], +["1w1a",2.25,2.48677201032487], +["1cwq",2.25,4.20961379204623], +["1ifx",2.25,2.42974336006702], +["1uzj",2.25,3.16993914668077], +["1vcn",2.25,2.99986825296188], +["1r2t",2.25,2.27556371743050], +["1uxu",2.25,2.79973463240143], +["1hkp",2.25,1.97597145841442], +["1lby",2.25,3.40548138892222], +["1k78",2.25,2.53111515518225], +["1cmx",2.25,2.8979896119766], +["1zji",2.25,2.20357792897034], +["1gk3",2.25,3.6482772312018], +["1fyd",2.25,2.40318523605044], +["5eas",2.25,2.21387203650684], +["1p32",2.25,2.62979845880545], +["1hxc",2.25,2.23939345547678], +["1zco",2.25,2.49860323053622], +["1ime",2.25,2.09599062291636], +["1yfo",2.25,2.54381189125874], +["1bg1",2.25,3.26447675413358], +["1y09",2.25,2.18605554498045], +["1qxd",2.25,2.69751656986432], +["2r2f",2.25,2.661802264574], +["1g1m",2.25,3.52698039620256], +["1ciy",2.25,2.82898446185708], +["2g06",2.25,2.08426772675131], +["1jen",2.25,2.03162294206293], +["1c8n",2.25,2.09073748513843], +["2kzz",2.25,3.09784117447556], +["1m51",2.25,2.1314980811112], +["1sjh",2.25,2.51379182179447], +["1mr5",2.25,2.71755053093558], +["2dey",2.25,2.75920473538756], +["2f4i",2.25,1.94630254212680], +["2ge3",2.25,2.98586904274081], +["1fuy",2.25,2.55469488402746], +["1ps6",2.25,2.79049820940601], +["1gwc",2.25,2.11198009814152], +["1eyx",2.25,3.19173086758743], +["1r0e",2.25,2.16233642760581], +["1uin",2.25,2.07565203103344], +["1y8j",2.25,3.27791662472918], +["1tii",2.25,2.33456879191652], +["1r6b",2.25,2.91770415054341], +["1u04",2.25,2.89543194744619], +["1wn1",2.25,2.68687009722601], +["1c3b",2.25,2.85034715033242], +["1su1",2.25,2.72881209354623], +["1guf",2.25,1.77126491612415], +["1ekv",2.25,3.19112208579629], +["1ft1",2.25,2.68832850634993], +["1tn8",2.25,1.93947556221651], +["1eey",2.25,2.24823859062528], +["1fxv",2.25,2.24085840722533], +["1jqi",2.25,2.64830831774686], +["1wkh",2.25,2.16891194504657], +["1wkg",2.25,2.50744768689422], +["1yf6",2.25,1.91905850449345], +["1kq4",2.25,2.176837389998], +["1z2l",2.25,2.90593726448316], +["1dm8",2.25,2.49655957679189], +["8nse",2.25,2.77480759929421], +["1hl9",2.25,2.24123132634587], +["1nc4",2.25,2.10391075604056], +["1z3u",2.25,3.12258686567819], +["1e5x",2.25,2.77363140975918], +["6csc",2.25,3.45010082890793], +["1hqa",2.25,2.29165396496794], +["1js3",2.25,2.50579119523287], +["2pel",2.25,2.37899212327248], +["2fww",2.25,2.8468244326928], +["1rjf",2.25,1.66236960921912], +["1sl6",2.25,2.50690969348687], +["1e6n",2.25,2.20073515676562], +["1jih",2.25,2.54665704549222], +["1n5r",2.25,2.32289094054122], +["1vqr",2.25,1.67130470057308], +["2bxh",2.25,2.96992135114415], +["1qo0",2.25,2.59699662567769], +["1ym4",2.25,2.86503327118518], +["1mhl",2.25,2.10836429034637], +["1f6p",2.25,1.94602947500037], +["2cbi",2.25,2.34258787340874], +["1zro",2.25,1.80737107285697], +["1fwl",2.25,2.9438552732537], +["1kgo",2.25,2.03463511204672], +["1r44",2.25,2.95613472507528], +["1rk2",2.25,1.96169290100927], +["1xmi",2.25,2.25501741697447], +["2b4r",2.25,2.15444246017116], +["2fm1",2.25,1.59564765581175], +["1jpm",2.25,2.01454780554095], +["1ted",2.25,3.07440634291413], +["1umf",2.25,2.9636422306803], +["1v0j",2.25,2.63601900020050], +["1dlu",2.25,3.01665606854631], +["1l5q",2.25,2.54969201459499], +["2fiq",2.25,2.06600981752868], +["1y8q",2.25,2.74093799822144], +["4nos",2.25,2.83550658961043], +["1f8i",2.25,2.19365270424457], +["1qha",2.25,3.32122675460144], +["1ndo",2.25,2.28915833354487], +["2c9t",2.25,1.98941450872317], +["1xjn",2.25,2.66476768091986], +["1ffv",2.25,2.37640919129135], +["1euz",2.25,2.65140302681982], +["3pcm",2.25,2.68393005436667], +["1ykl",2.25,2.79882263486124], +["1xrh",2.25,2.76855411620117], +["1o7a",2.25,2.32691607851047], +["1rvz",2.25,2.88256793929062], +["2awi",2.25,2.77624526458052], +["2dcn",2.25,2.11869608045294], +["1vqp",2.25,2.74164645433617], +["1o05",2.25,2.00777583946336], +["1gth",2.25,2.2627016157397], +["1g65",2.25,3.05429517151482], +["1ehc",2.26,2.73646598384322], +["1twm",2.26,2.70904179355741], +["1ier",2.26,2.19943979765486], +["1fb0",2.26,2.1428389879315], +["1muf",2.26,3.08268429769871], +["1mja",2.26,2.63073849078255], +["2f0r",2.26,2.16556437851156], +["1qx0",2.26,2.39795050233121], +["1f0c",2.26,2.95741561183108], +["1f7q",2.26,2.88704138327203], +["2f4o",2.26,3.03673659963757], +["1gzq",2.26,2.85634778954438], +["1wl5",2.26,1.98723804925515], +["1qbl",2.26,3.17477943400758], +["1xvi",2.26,2.12238365244998], +["2fml",2.26,2.80853636298068], +["1u7n",2.26,2.52092428748529], +["1wut",2.26,3.06619945388982], +["1wuy",2.26,3.11976898899284], +["1wv0",2.26,3.15116790166118], +["1k08",2.26,2.99994788093839], +["1hlf",2.26,3.1832709893773], +["1hwj",2.26,2.36164624853785], +["1ggk",2.26,2.32218321496586], +["1xx7",2.26,1.522550431408], +["1upr",2.27,2.97817636356042], +["1fm5",2.27,2.97727662710955], +["1sln",2.27,2.47631241686176], +["1tr8",2.27,1.97402100210100], +["1gu8",2.27,2.16498216246785], +["1gue",2.27,2.43962373991301], +["1si9",2.27,2.64554112374653], +["1xzn",2.27,2.89209553092587], +["1cnq",2.27,2.31517605412856], +["2c24",2.27,2.13210568014756], +["2c28",2.27,2.73462051836496], +["1wal",2.27,2.42060726901298], +["1qmn",2.27,2.45699036575164], +["2bb3",2.27,3.04114767425772], +["1w0v",2.27,1.80256118559804], +["1cmv",2.27,3.18652948737378], +["2fo0",2.27,2.30457535349549], +["2b9s",2.27,1.87283947642476], +["2ax3",2.27,1.65492461602259], +["1jaz",2.27,2.24429479352576], +["1p6m",2.27,2.77005057150634], +["1vm6",2.27,1.75461351240575], +["1z0g",2.27,3.64606202614784], +["1w7a",2.27,2.46388209828998], +["1fj8",2.27,3.00597046326933], +["1wx0",2.27,2.38224070804936], +["1jkr",2.28,3.13183792730572], +["1waq",2.28,2.61987389744523], +["2bdd",2.28,2.13843427063048], +["2etd",2.28,1.19613298245390], +["1o73",2.28,2.38600957188403], +["9ilb",2.28,2.72371374634392], +["2g42",2.28,1.11501099782361], +["1e0s",2.28,1.84469320894076], +["1gbm",2.28,1.80983551866960], +["1uom",2.28,2.41358735072285], +["1rkh",2.28,2.36047311656892], +["1ck3",2.28,1.91266762982951], +["1s6m",2.28,2.66697066344384], +["2a18",2.28,1.34406262263258], +["1cvw",2.28,2.46207299979167], +["1xos",2.28,2.34666944823549], +["1ryr",2.28,2.68299039224952], +["1ko5",2.28,2.34750079354963], +["1ta4",2.28,2.97020679304137], +["2b2z",2.28,3.09880849300526], +["1oc0",2.28,1.95894099907164], +["1dkp",2.28,2.55394308046455], +["1zxc",2.28,2.67026304538757], +["4otc",2.28,2.20368407007274], +["1v4e",2.28,2.69682613872634], +["1jqd",2.28,2.34081149143956], +["1eyj",2.28,2.52064289496906], +["2fdb",2.28,2.3436701479087], +["1a79",2.28,3.39570367688717], +["2cda",2.28,2.32715584241081], +["1kdw",2.28,2.23303446684855], +["2fbm",2.28,2.67954910014164], +["1jx9",2.28,1.91122110936325], +["1v94",2.28,2.67234748120802], +["1dn0",2.28,3.28030804293096], +["2g75",2.28,2.86807342962349], +["1v3d",2.28,3.01354486032367], +["1q9l",2.28,2.95799671099758], +["1okj",2.28,2.77041113199048], +["2g80",2.28,0.964611438964596], +["1xxx",2.28,1.82697205754515], +["1ggf",2.28,2.46364969807334], +["1ito",2.29,2.50307765498250], +["1x2w",2.29,2.74515572253709], +["1o9y",2.29,2.00306465955112], +["2feg",2.29,2.72047723715708], +["1zbc",2.29,3.13052442808706], +["1yty",2.29,1.94126604387684], +["1s13",2.29,2.80491881603104], +["1msa",2.29,2.438279347304], +["1yf3",2.29,2.54479161970028], +["1t6x",2.29,2.67517521058438], +["1ys4",2.29,2.16633644803330], +["1vlu",2.29,2.17141305297925], +["2etf",2.29,2.06579078367653], +["1dlv",2.29,2.8681087095132], +["1eby",2.29,1.93336444262648], +["1jj6",2.3,2.25903172860876], +["1nhl",2.3,2.02150875763902], +["1mn3",2.3,2.62949090413858], +["1unz",2.3,2.36863947953460], +["1hpt",2.3,2.62347603673579], +["1uny",2.3,2.92203903695896], +["1gzz",2.3,3.3863000025087], +["1e6g",2.3,3.02896112483112], +["1w5i",2.3,2.45133058826761], +["1neg",2.3,2.55751017255892], +["3ame",2.3,2.05036331547384], +["1msj",2.3,2.21973647956680], +["1fyn",2.3,2.93805708265275], +["1ydl",2.3,2.48997843747251], +["1mul",2.3,2.44817662209594], +["3icb",2.3,3.14790520984757], +["1pfp",2.3,2.62403891848220], +["1jk4",2.3,2.40189157731314], +["2cuw",2.3,2.51658353719677], +["1z9f",2.3,2.91537437783631], +["2fgg",2.3,3.58753854473172], +["1a1l",2.3,2.02630862551395], +["2gn5",2.3,5.21521999213666], +["1lng",2.3,3.02219105560767], +["1ov9",2.3,2.52533756762418], +["1mpj",2.3,2.95598595648178], +["1cx0",2.3,2.55069538842956], +["1drz",2.3,2.72083466078236], +["1lph",2.3,3.53437775220600], +["1xw7",2.3,2.55556403010442], +["1ycq",2.3,2.45522236115095], +["1sip",2.3,3.50294755495311], +["1ik7",2.3,1.86011662285965], +["1cyc",2.3,5.10217737677887], +["2bir",2.3,2.04842849700534], +["1ayc",2.3,2.83544645571018], +["1qls",2.3,2.95612316186650], +["1xwc",2.3,2.91141418439448], +["1frm",2.3,2.45377066800255], +["1frh",2.3,2.46035529181416], +["1frl",2.3,2.37079621590390], +["1fer",2.3,2.17648239892462], +["1frj",2.3,2.58298631309823], +["1ff2",2.3,2.57285135925540], +["2a3p",2.3,2.35490794821484], +["1bet",2.3,2.48672973614115], +["1lp1",2.3,3.22424540881432], +["3ssi",2.3,2.95199058591723], +["1n9n",2.3,1.99014827716313], +["1tho",2.3,2.22540505876949], +["1bfe",2.3,2.71881145186767], +["1l1s",2.3,2.15196779318602], +["2esh",2.3,3.21758325972478], +["1xd7",2.3,3.31546693276125], +["1cjr",2.3,3.04339358473176], +["1j82",2.3,2.78740516072453], +["2c5i",2.3,2.41803379082207], +["1w02",2.3,3.13734790515928], +["1bl0",2.3,4.06659505864161], +["2tmy",2.3,2.98712035223184], +["1u27",2.3,2.57073203290357], +["1s8g",2.3,2.19080795576558], +["1w16",2.3,2.53021346223841], +["1byl",2.3,2.19973691008460], +["1a5q",2.3,3.31368769300527], +["5fit",2.3,2.24420463851666], +["8cho",2.3,2.63220183727992], +["1fxr",2.3,2.25485695856276], +["1lfo",2.3,2.69055588307196], +["1dv8",2.3,2.75806196696241], +["1xek",2.3,4.47488913817631], +["1o5l",2.3,1.82186757414639], +["1ku5",2.3,2.72625081794455], +["1kba",2.3,4.23813521429006], +["1qql",2.3,3.56278593076520], +["1ahq",2.3,2.92682598454910], +["1aqt",2.3,2.72585527511357], +["1cof",2.3,2.31778773928706], +["2fo7",2.3,2.11104136029678], +["1su0",2.3,3.21936669248746], +["1dud",2.3,1.95573990350744], +["1nl2",2.3,2.87270634070988], +["1hyz",2.3,2.3270218345159], +["2cy1",2.3,2.25966769138980], +["1jgs",2.3,2.97927559073571], +["1fik",2.3,2.96880927806210], +["1itg",2.3,2.75539331013055], +["1gu3",2.3,2.32730412303233], +["2asr",2.3,2.76598119320397], +["1l7z",2.3,2.83642611366622], +["3fis",2.3,3.05807890072429], +["4fis",2.3,3.21000042399059], +["2af0",2.3,2.04048779853553], +["2aed",2.3,1.77664697316593], +["1jqw",2.3,2.60488521307075], +["1hqp",2.3,3.53125983811642], +["1vjx",2.3,2.02656964182199], +["1aar",2.3,2.75133686247371], +["1jp6",2.3,1.32356200329886], +["1jp8",2.3,1.71860825257565], +["5dfr",2.3,3.62873875349504], +["1ass",2.3,3.02071852029936], +["1mnh",2.3,2.48966278375950], +["1bgd",2.3,2.88717532050032], +["1rdc",2.3,3.9488652950353], +["1cw0",2.3,2.46786255993719], +["1cyx",2.3,2.87532800461149], +["1drh",2.3,3.29583643531357], +["1rx7",2.3,3.17779370900363], +["1rx5",2.3,3.2545641537032], +["1ew3",2.3,3.10028747643051], +["1a6y",2.3,3.81494744704462], +["2fgc",2.3,2.76632781988129], +["1c25",2.3,2.66278134118521], +["1paq",2.3,3.11532888902146], +["1c62",2.3,2.16936973013991], +["196l",2.3,2.59696334753986], +["1jq6",2.3,2.78942028860409], +["1rpy",2.3,1.95078704366468], +["1jpx",2.3,2.70762236754949], +["1qtv",2.3,3.24815861268054], +["1we2",2.3,2.99476670432995], +["1yd7",2.3,1.81564298245202], +["1twq",2.3,2.70152578758645], +["1l0c",2.3,2.63702582585448], +["1p2v",2.3,2.56958223055008], +["221p",2.3,2.9846757647603], +["1agp",2.3,2.40720571126885], +["1g2e",2.3,2.28054087153343], +["1avu",2.3,3.44249120404741], +["1j5y",2.3,1.9136485090671], +["1v67",2.3,2.54445277148170], +["1a45",2.3,3.33465938704230], +["1tzq",2.3,2.21197745629695], +["1hqv",2.3,2.94599791165663], +["1pu9",2.3,3.67646573552219], +["1s7l",2.3,2.46987199967204], +["1pua",2.3,3.50840320086721], +["1cdh",2.3,4.14830988416581], +["1cwt",2.3,2.76373500076345], +["1t9z",2.3,2.52398082051788], +["1s1e",2.3,3.02206070319528], +["2alg",2.3,2.39923461258960], +["1kzn",2.3,2.54276272139208], +["4mon",2.3,4.07543840906197], +["1zny",2.3,2.00754982275781], +["1mr2",2.3,2.32390877352267], +["1mp2",2.3,2.27368019344656], +["2wbc",2.3,3.44174281537558], +["1m1u",2.3,2.66754098534859], +["1ek8",2.3,2.95953532773796], +["1ad6",2.3,3.5531657702792], +["1r22",2.3,2.91461124230925], +["1dr2",2.3,2.73617179143020], +["1dr3",2.3,2.88602201972306], +["1dls",2.3,2.40342381330094], +["1dlr",2.3,3.01449578916484], +["1l0b",2.3,2.83505439466247], +["1a2x",2.3,3.84257756863099], +["1tfo",2.3,2.71285550733703], +["1r1v",2.3,2.65641260661233], +["1es8",2.3,2.03810642258980], +["1aj6",2.3,3.04981516332517], +["1s98",2.3,3.17203102809327], +["1r94",2.3,2.70698674804567], +["1m4k",2.3,2.59559870888137], +["1qcy",2.3,2.18569834835035], +["1u9n",2.3,2.51441760756341], +["5upj",2.3,3.07102132120597], +["1tcx",2.3,2.20076523367089], +["1hii",2.3,2.27411961585702], +["1hbv",2.3,2.68051087906509], +["1sbg",2.3,2.91420510515791], +["1hos",2.3,2.65379425604702], +["4hvp",2.3,3.3231625012138], +["1gnn",2.3,3.03895680652612], +["1hps",2.3,3.28867885128576], +["1gnm",2.3,3.46676026730268], +["1gno",2.3,3.07065612671418], +["1a9m",2.3,2.74050665012603], +["1hxb",2.3,2.38338266259867], +["1ro5",2.3,3.04069791051613], +["1gbe",2.3,2.08434411125407], +["1ytg",2.3,2.58702520861551], +["2fdk",2.3,1.98113436143226], +["1mdv",2.3,2.47459451080856], +["1ywq",2.3,2.2509387886966], +["1gbi",2.3,2.27655573363567], +["1mqw",2.3,2.20676335814567], +["2fd8",2.3,1.70007687826078], +["1iad",2.3,1.79322684279936], +["1r5x",2.3,2.31400221722746], +["1q5o",2.3,2.56541325898364], +["1hj1",2.3,2.26418868434449], +["1cwe",2.3,2.86852333352731], +["2fmu",2.3,1.78030975451362], +["1tik",2.3,1.84689828976751], +["1im4",2.3,2.59641276957121], +["1klk",2.3,3.24996314836845], +["1so8",2.3,2.36223494582741], +["1fwz",2.3,2.97556025454282], +["1trq",2.3,3.11856252166332], +["1daj",2.3,3.66906431523669], +["1brx",2.3,3.37235943882165], +["1fp5",2.3,3.06198069644526], +["1auq",2.3,2.80413840755659], +["2cct",2.3,2.99912587090722], +["1bi0",2.3,2.8044237125844], +["1ouo",2.3,2.92033037491860], +["2aug",2.3,1.65008323820832], +["1i6a",2.3,2.38809230451751], +["1ubb",2.3,2.18338541328508], +["1bwq",2.3,2.97923757382955], +["7cei",2.3,3.3557097139694], +["1x0i",2.3,2.79438813889602], +["1cjs",2.3,2.36273640087464], +["1yt7",2.3,2.39564583698962], +["1u9q",2.3,2.49487714619479], +["1ayv",2.3,2.62613581853835], +["1au4",2.3,3.19416494625058], +["1bnd",2.3,3.21857875315081], +["1u9w",2.3,2.40108315973146], +["2afr",2.3,2.22303691316529], +["1m99",2.3,2.03920916058861], +["1s8l",2.3,2.27841437026543], +["1f37",2.3,2.79184774682556], +["1zzj",2.3,2.66259744684403], +["1ac6",2.3,3.25965979584665], +["1eml",2.3,3.03128601594516], +["1emm",2.3,2.75840958016973], +["1t29",2.3,3.69964773736097], +["1a41",2.3,3.57663216150978], +["2emn",2.3,2.82949542897539], +["2dyn",2.3,2.43825728447877], +["1ppg",2.3,3.12056927365026], +["1ae5",2.3,3.16157336605635], +["1z6k",2.3,2.73542119350408], +["1v2q",2.3,2.08270208973472], +["1and",2.3,2.28917686839633], +["1ql9",2.3,2.33626760822812], +["1u0y",2.3,2.24625279784540], +["1mg9",2.3,2.57265397146342], +["4lve",2.3,2.40965514464959], +["1u2c",2.3,2.8853411757804], +["2czr",2.3,2.57769603820057], +["1iw6",2.3,2.82299075540988], +["1vjm",2.3,1.99602253904225], +["1hfd",2.3,2.79321557986776], +["1flz",2.3,4.37533360984895], +["1msb",2.3,2.05401957976910], +["1ixv",2.3,2.20644900268941], +["2bf8",2.3,2.65249481029889], +["1vyd",2.3,2.61697788200550], +["1cr2",2.3,3.36823581794304], +["1thc",2.3,3.64088651460611], +["1nmn",2.3,2.57223766979663], +["1o9d",2.3,2.54728484657962], +["1m68",2.3,2.09151966388105], +["2blk",2.3,1.9254302395413], +["1cr0",2.3,3.36622896446447], +["1y75",2.3,3.17099116814363], +["1dhr",2.3,2.64038871237867], +["1vzz",2.3,2.77392429481032], +["1lcv",2.3,2.49227116063188], +["5cro",2.3,3.42165155039432], +["1nhz",2.3,2.70838312411412], +["1hfy",2.3,2.38434232942426], +["1cr1",2.3,3.44438675525627], +["1q0s",2.3,2.90030803183439], +["1esb",2.3,2.61327422649229], +["1bpb",2.3,3.70179085194193], +["1zqw",2.3,3.48874008233736], +["1zqy",2.3,3.58060122009845], +["1bru",2.3,2.13318974083797], +["1rjx",2.3,2.81600068885872], +["1rpl",2.3,3.27963933832615], +["1igm",2.3,3.72413922334951], +["1ekb",2.3,2.86852636048667], +["1xmj",2.3,2.83446976384046], +["1ion",2.3,2.8961952616751], +["1ask",2.3,2.47356736682198], +["1edo",2.3,2.99241554495285], +["1q3c",2.3,2.84869434111585], +["1ar0",2.3,2.21676745593484], +["1oun",2.3,2.90113742175889], +["1jb5",2.3,3.25448929791561], +["2evu",2.3,2.72508615406338], +["1p6e",2.3,2.47165680675466], +["1gy5",2.3,2.81886448610761], +["1isq",2.3,2.87198917046574], +["1rtf",2.3,2.4551349844354], +["2b3r",2.3,2.33675614318630], +["1f2k",2.3,3.00082928785744], +["1a7v",2.3,2.5343694670919], +["1ypr",2.3,2.61568844988686], +["1ymu",2.3,3.40934351766044], +["1dnk",2.3,3.02677441840583], +["2dc6",2.3,2.74292295126257], +["2ae1",2.3,2.36686151344601], +["1vc9",2.3,2.40895555304418], +["1rio",2.3,2.76496508470876], +["1ctm",2.3,2.45754694267809], +["2b33",2.3,0.852748770866519], +["1wxf",2.3,2.23122388786245], +["1xnh",2.3,3.0625231553789], +["1nnd",2.3,2.53889793408882], +["1blp",2.3,3.32145591455065], +["1rv1",2.3,2.83387599189742], +["1b74",2.3,3.58904235991368], +["1b73",2.3,3.66657256260925], +["1au7",2.3,3.0033832320889], +["1ca3",2.3,2.87295706529216], +["1hca",2.3,2.87913725075186], +["1udq",2.3,2.92631221804138], +["1uds",2.3,2.85874357328435], +["1udo",2.3,2.94597316041669], +["1udn",2.3,2.91057360167908], +["1cvh",2.3,2.81806000576619], +["1cvc",2.3,2.81115152884156], +["1hva",2.3,3.34629447257582], +["1tab",2.3,4.04953924011037], +["1d1u",2.3,2.9479857577442], +["1f1c",2.3,2.48175724692744], +["1lzv",2.3,2.52299792416623], +["1cny",2.3,2.66002860561403], +["1aqc",2.3,3.17641899397118], +["1zdg",2.3,2.30588852394873], +["1c79",2.3,2.85002418169084], +["1c77",2.3,2.89882367486886], +["1c78",2.3,2.89882367486886], +["1blh",2.3,3.08652347781744], +["1bnn",2.3,2.27795539479170], +["1ghi",2.3,2.68213127188217], +["1kgg",2.3,3.07048539961626], +["1plq",2.3,2.83602273516174], +["1zg1",2.3,2.52441319650249], +["2bcf",2.3,2.13806471333784], +["1rwk",2.3,2.34727097231533], +["1t5z",2.3,2.35068081517553], +["1zg5",2.3,2.45839124797421], +["1apa",2.3,3.36221316341716], +["1edy",2.3,2.07550851109324], +["1ocu",2.3,2.88821717629356], +["1zbm",2.3,2.71118835805962], +["1bjg",2.3,2.04035820327910], +["1cfy",2.3,2.39417690633621], +["1w6m",2.3,1.97139907253680], +["1cd5",2.3,2.69216716367474], +["1egi",2.3,2.63139552769658], +["1gzk",2.3,3.59077274744974], +["1br6",2.3,2.90535710986616], +["1rtc",2.3,3.28295490421717], +["1i2l",2.3,2.51132783145699], +["1mvh",2.3,3.08025373206242], +["1bo4",2.3,3.21117374677096], +["1rl2",2.3,2.59272641772177], +["1scd",2.3,2.83257999407633], +["1egg",2.3,2.64977007505031], +["1ib0",2.3,2.19796990855952], +["1xca",2.3,3.15210331308767], +["1bfk",2.3,3.26058196366005], +["1scb",2.3,3.40337074767601], +["1dhy",2.3,3.0651478297929], +["1kgt",2.3,2.93627524114449], +["1gtq",2.3,2.44106894551526], +["1gmn",2.3,2.61260703636537], +["2f1x",2.3,2.9703478862113], +["2b9c",2.3,3.60529577707406], +["2fjy",2.3,2.87945626423745], +["1nst",2.3,3.04932414267526], +["1fpc",2.3,3.3259244009114], +["1jlk",2.3,2.80463244011596], +["2eth",2.3,2.59164247397577], +["2c2y",2.3,2.42900721285525], +["1u59",2.3,2.68063413745951], +["1oky",2.3,2.66939854474773], +["1tmc",2.3,2.42162803265334], +["1ta2",2.3,2.51245432449687], +["1iod",2.3,2.69269319119592], +["1tbz",2.3,3.30773567612856], +["1n6c",2.3,2.77358000157439], +["1bhx",2.3,2.50821030686939], +["1rt9",2.3,2.86644414837094], +["1d9i",2.3,3.96198621758553], +["1zbs",2.3,3.1180900680252], +["2a8b",2.3,2.58820451518443], +["1hja",2.3,2.46828696220773], +["1qxk",2.3,2.73347819967111], +["1fsl",2.3,2.33182811199157], +["1bia",2.3,3.52462751523538], +["3dhe",2.3,3.09570746204087], +["1qiy",2.3,2.38840824485314], +["1wu1",2.3,2.726783637058], +["1o1i",2.3,2.78904528850052], +["1c40",2.3,2.82589326398651], +["1qiw",2.3,3.61889681840897], +["1thr",2.3,3.44031497600792], +["1out",2.3,2.54690154668167], +["2cdz",2.3,2.03818805774185], +["2aur",2.3,1.84221525521402], +["1m73",2.3,3.23707886071037], +["1n5d",2.3,2.39911751242547], +["1dit",2.3,3.31227244142488], +["1xsm",2.3,3.39889577274143], +["1tmb",2.3,3.60048376670508], +["8prn",2.3,2.78398358487450], +["2c6l",2.3,2.56740613723197], +["1xm1",2.3,2.79321762026570], +["1t3s",2.3,3.08433578112196], +["1xqv",2.3,2.59467218644491], +["1igb",2.3,2.09327221686932], +["1cce",2.3,2.27914423859293], +["1cmq",2.3,2.5463282442125], +["3ccx",2.3,2.10575899341028], +["2ypn",2.3,2.17026654807487], +["1ypn",2.3,2.43355298757137], +["1boh",2.3,2.53306932720846], +["1tfd",2.3,4.41416248540745], +["1xrp",2.3,3.04669652565302], +["1pxj",2.3,2.64807291695281], +["1pxp",2.3,2.79201770498228], +["1wmi",2.3,3.48360023997734], +["1iz0",2.3,2.77359737269846], +["2bdx",2.3,1.97895285216381], +["1ets",2.3,3.3072028326285], +["1hah",2.3,3.30809055269773], +["1af2",2.3,2.27860188827155], +["1aln",2.3,2.21524029014136], +["1ctu",2.3,3.23078706659333], +["1jpj",2.3,3.26456904776662], +["1q20",2.3,1.98774654069555], +["1na8",2.3,2.78827570171609], +["1e62",2.3,2.00965716468307], +["1e64",2.3,2.08555367866103], +["1e63",2.3,2.07411085187102], +["1h85",2.3,2.23851093034632], +["1bjk",2.3,2.27092478400965], +["1qgz",2.3,2.28777503965997], +["2fub",2.3,2.24873127581945], +["1kil",2.3,2.49661551830877], +["4ptd",2.3,3.18998973519056], +["1c86",2.3,2.53365949748855], +["2fpl",2.3,2.58781665072943], +["1ptv",2.3,2.65456119877927], +["1abi",2.3,3.70973058287338], +["2reb",2.3,2.13885195079478], +["1cgj",2.3,3.48227614974244], +["1cgi",2.3,3.55816150865197], +["1cb4",2.3,2.45233193986112], +["1hzf",2.3,3.07444459779447], +["1zx5",2.3,1.60729071373164], +["1cjf",2.3,3.20962240375487], +["1mhm",2.3,2.82814207447596], +["1py5",2.3,3.50132822284434], +["1q67",2.3,2.85171847831399], +["1esd",2.3,3.30785736567760], +["1b3z",2.3,1.81277453332677], +["1ny2",2.3,4.1128665105645], +["1hsk",2.3,2.08554680389654], +["2aql",2.3,2.81533393329798], +["1bob",2.3,2.73794245626211], +["1ksg",2.3,3.34608444691277], +["1rka",2.3,2.11033930127601], +["1hdq",2.3,1.67049930676874], +["2dln",2.3,3.64157086019283], +["1c9e",2.3,2.49290457040602], +["1gkx",2.3,2.87342398517200], +["1s3i",2.3,2.81635217804327], +["1am9",2.3,2.51308316807123], +["1wse",2.3,2.89241531364473], +["1ch0",2.3,1.83409686108648], +["1qz3",2.3,2.21351345176688], +["1sdj",2.3,2.86676704364396], +["2edc",2.3,2.62136844074813], +["1cij",2.3,2.30266491042148], +["1gil",2.3,2.20515532952338], +["1udt",2.3,2.78013965326835], +["1iar",2.3,2.90022640538376], +["1txc",2.3,1.94028577915514], +["1bk4",2.3,2.95303386099576], +["1lwv",2.3,2.85157999431776], +["1ea3",2.3,3.2898494562606], +["1hve",2.3,2.68855190434129], +["1k4z",2.3,2.50759372980867], +["1gkc",2.3,2.15244075146972], +["2ts1",2.3,2.33606069357622], +["1ann",2.3,2.18210993700681], +["1ah3",2.3,2.72962457882946], +["1l3f",2.3,3.67059782921178], +["1tdf",2.3,2.54846322368041], +["7tln",2.3,2.63542330932387], +["5tln",2.3,3.16853637302985], +["4tln",2.3,3.11316922014437], +["1tlp",2.3,2.68407554790283], +["1rb3",2.3,2.76784306409393], +["1nje",2.3,3.10688871207689], +["1ah0",2.3,2.54020774738155], +["2nos",2.3,2.92320338063922], +["1bsd",2.3,3.18224485860308], +["1fxs",2.3,2.05189232809483], +["1avr",2.3,2.28836149114376], +["1all",2.3,2.09343280278199], +["3kar",2.3,3.55923973788545], +["1hqd",2.3,1.77688820436704], +["1vfe",2.3,2.78187691045859], +["1j7j",2.3,2.75314933998798], +["1f35",2.3,1.92274353887477], +["1ak5",2.3,2.50108469978606], +["1xka",2.3,3.23698300307562], +["1cm0",2.3,3.08639739827291], +["1cms",2.3,3.49178312590679], +["1czi",2.3,3.76943873985372], +["1obr",2.3,2.66341285152720], +["1toh",2.3,2.57129641630597], +["1vfw",2.3,3.28383775605463], +["174l",2.3,3.41767445253101], +["1aw5",2.3,3.29859387981509], +["1psq",2.3,2.88573319091585], +["1uh8",2.3,1.47688767792551], +["1zog",2.3,3.14136171184128], +["3pep",2.3,3.06049174549508], +["1yem",2.3,1.34205767923590], +["1mmp",2.3,2.38886361301801], +["1vbt",2.3,2.50677472345642], +["1nnt",2.3,3.83228426109911], +["1a4x",2.3,2.51012755056556], +["2bll",2.3,2.26649665876477], +["1epr",2.3,2.84067495749106], +["1hku",2.3,2.56942805049212], +["1you",2.3,2.84514831419596], +["1db3",2.3,2.2165971638934], +["1gey",2.3,2.05036656023946], +["1ybo",2.3,1.92514211763799], +["1cen",2.3,2.16315862366942], +["1nhj",2.3,2.62736211290578], +["2f5i",2.3,2.95334462821314], +["1fhl",2.3,2.9735569835896], +["1hd8",2.3,2.65819567297763], +["2toh",2.3,3.06538066223486], +["1rek",2.3,2.59554852602780], +["1wfc",2.3,2.22879302228426], +["2g17",2.3,1.91521048311766], +["1zw5",2.3,1.80192443607190], +["1u2m",2.3,2.04676152372626], +["1slv",2.3,2.27300026833231], +["1dbh",2.3,2.66101218571904], +["1mbb",2.3,2.53724318474846], +["1b3d",2.3,2.39676279195833], +["1bqo",2.3,2.70799979123413], +["1sdm",2.3,2.97657177572124], +["2gd9",2.3,1.9062100018357], +["2f7m",2.3,2.57964252442316], +["1vez",2.3,2.68104773625024], +["1zaw",2.3,2.55215268305233], +["1l0s",2.3,2.67912222762387], +["1jnk",2.3,2.79353746615266], +["1f7p",2.3,2.93023015536195], +["1j93",2.3,3.29424757869341], +["1x7f",2.3,2.13724689412101], +["1r39",2.3,2.19833224292747], +["1dvi",2.3,2.05647485040232], +["1aj5",2.3,2.61551948245248], +["2b9j",2.3,2.60244256791782], +["1a5d",2.3,2.88157675932293], +["1gc9",2.3,2.64628461590472], +["1fxk",2.3,2.05693485327382], +["1bi2",2.3,2.61885771259291], +["4htc",2.3,3.54552667045725], +["1ic5",2.3,2.89405367043732], +["1c08",2.3,2.73220425951309], +["1lez",2.3,3.0953830497054], +["1lew",2.3,2.85508551264169], +["1e3j",2.3,2.35799011178817], +["2rsl",2.3,2.57901199358074], +["2paw",2.3,2.27857494526714], +["1jtn",2.3,3.72227282237703], +["1ndv",2.3,3.97146688516629], +["1stc",2.3,3.71061120967414], +["1qkj",2.3,2.92682564163202], +["1svh",2.3,2.23081768975731], +["1ydt",2.3,3.2358961627136], +["1psh",2.3,2.44918670131836], +["1goj",2.3,3.01231897593904], +["1q62",2.3,2.72799543789355], +["1sd0",2.3,2.41011808360212], +["1gtg",2.3,2.90054847774957], +["1jpi",2.3,2.14399843598087], +["1l4d",2.3,2.56182113509355], +["1erk",2.3,3.63917353921774], +["1sbr",2.3,2.80666692782887], +["1rdw",2.3,2.85748595010282], +["1d5w",2.3,2.05287592176269], +["8jdw",2.3,2.57515719678982], +["1bt4",2.3,2.07539842639184], +["2dhf",2.3,3.70872322500550], +["1dhf",2.3,3.452768478053], +["1cau",2.3,4.13901323673153], +["3np1",2.3,3.16162726418304], +["4np1",2.3,3.54141110531421], +["1nx0",2.3,3.18990693739741], +["1zzb",2.3,2.94411106664859], +["1w3c",2.3,3.10568018974517], +["1qnc",2.3,2.49866861013400], +["1fqc",2.3,3.26742310559718], +["1fqd",2.3,3.74213454562903], +["1mpd",2.3,1.83095675692774], +["1qn7",2.3,2.34044148857884], +["1ex6",2.3,3.51060500255166], +["1g0w",2.3,2.40078758955611], +["1ej3",2.3,2.30239773619935], +["1feu",2.3,2.89290566310233], +["1ahs",2.3,2.94846504147716], +["1ydx",2.3,2.30809989851243], +["1fjr",2.3,2.8806068645003], +["2vaa",2.3,1.84826365387292], +["1k8d",2.3,2.96650384962066], +["1s4y",2.3,2.98653925899173], +["1s9y",2.3,2.48853658010813], +["1age",2.3,2.10870014026323], +["1hjo",2.3,2.14104547376980], +["2bwb",2.3,2.22493686279252], +["1xr8",2.3,2.47991270265413], +["1wby",2.3,2.71474753348006], +["1a1o",2.3,2.25147192869410], +["2bsr",2.3,2.52177432655784], +["2cz3",2.3,2.43360892432571], +["1a1m",2.3,2.8120134071683], +["2b4e",2.3,2.25572026055783], +["1zww",2.3,2.33046190958637], +["4nn9",2.3,2.5416990780966], +["3nn9",2.3,2.55805916900288], +["6nn9",2.3,2.58565970791289], +["5nn9",2.3,2.47309287974253], +["1zet",2.3,3.44540485144863], +["1x92",2.3,2.30201576835818], +["1oxm",2.3,2.14269160050911], +["1lxn",2.3,1.88361057422801], +["1zyn",2.3,2.73575271632286], +["1pbd",2.3,2.54727667672936], +["1n5l",2.3,2.1715765527738], +["1aer",2.3,2.8681162479948], +["1j6r",2.3,3.14670159830667], +["2fqm",2.3,3.36261672335023], +["1x3n",2.3,2.49132871765355], +["1qnm",2.3,2.87692307374735], +["1luw",2.3,3.04260121132368], +["1phh",2.3,4.26531060965544], +["1pxb",2.3,2.04159234520897], +["1pxa",2.3,2.45947955166587], +["1doe",2.3,2.23865805260448], +["1qhu",2.3,3.08339860527187], +["1nsa",2.3,2.67175031384727], +["1pd2",2.3,2.65630726207687], +["1bqg",2.3,3.05811512550993], +["1zkg",2.3,2.03831675115039], +["1us7",2.3,2.5114463099039], +["1rbm",2.3,2.14556742964202], +["1u5y",2.3,2.84460302886887], +["1bwk",2.3,2.56332065590129], +["2ccg",2.3,2.74606072145678], +["1inp",2.3,3.56791043832792], +["1akb",2.3,2.76439775666074], +["1maq",2.3,2.90503875735011], +["1akc",2.3,2.95218480054232], +["1ama",2.3,3.25463298651414], +["1xvt",2.3,2.36650765464054], +["1jin",2.3,2.39034927347405], +["1g9q",2.3,3.02212641236688], +["1b79",2.3,2.64872013287667], +["3cp4",2.3,3.43524654746966], +["1p2y",2.3,2.44821077690463], +["1pcv",2.3,3.05957509775580], +["1wb8",2.3,2.20910108722148], +["1cpt",2.3,2.52483545913701], +["1a0q",2.3,2.37381809420035], +["1qqg",2.3,2.59991352378008], +["1ief",2.3,2.89806940622640], +["11gs",2.3,2.39090483564937], +["1ey2",2.3,1.95795461562259], +["1lq1",2.3,3.41236046243066], +["1t2o",2.3,3.0484719195023], +["1zcp",2.3,2.3109172752087], +["1mh4",2.3,2.72219270357282], +["1mrd",2.3,2.80532812083510], +["2bdq",2.3,3.00439941323963], +["1xw9",2.3,3.2820168546477], +["1mre",2.3,2.85208720166198], +["1qwc",2.3,3.30581588275169], +["1fm7",2.3,2.3413104401025], +["1fm8",2.3,2.45159717866634], +["1mac",2.3,3.13241862729494], +["1f23",2.3,2.98680650013008], +["1ik9",2.3,2.57882432112078], +["2bac",2.3,1.54220019727083], +["1f4w",2.3,2.76804484581483], +["1f4x",2.3,2.87443186306527], +["1wrn",2.3,3.00824586937888], +["1npe",2.3,2.50918225157091], +["1lhz",2.3,2.7487197966248], +["2bfz",2.3,2.51310661726976], +["2bg6",2.3,2.40919966069364], +["1j6u",2.3,2.88294403946787], +["1q5n",2.3,2.46763417891512], +["1gig",2.3,3.05894556088172], +["1m7d",2.3,2.77855282790447], +["1dcl",2.3,3.95829927029627], +["3bjl",2.3,4.11252789366104], +["1cib",2.3,2.71906664790273], +["2fhe",2.3,2.57410099880662], +["1tet",2.3,3.04017530846560], +["3bif",2.3,2.25794322498835], +["8ohm",2.3,3.20064653130948], +["1k5j",2.3,2.32828551403376], +["1a16",2.3,2.00622374866822], +["1ejo",2.3,2.80128402463594], +["1wvt",2.3,2.23244030030747], +["1lvh",2.3,2.69420301096672], +["1ggg",2.3,3.52683531046747], +["2azo",2.3,3.34324623168427], +["1ibz",2.3,2.19702750626427], +["1n51",2.3,1.89088478760081], +["1gk4",2.3,2.82075792226638], +["1yyn",2.3,3.04361866579457], +["1c7q",2.3,2.90121315714517], +["2pgi",2.3,3.21365798205245], +["1b0z",2.3,3.21379916675071], +["2g2x",2.3,1.83829562427045], +["1ka9",2.3,2.89953129592327], +["1kdp",2.3,2.79280446909256], +["1trm",2.3,3.06783948699295], +["1hqo",2.3,2.8909656964797], +["1lwx",2.3,2.88636186262528], +["1am7",2.3,1.94617412435512], +["2bef",2.3,2.43600031101667], +["1b08",2.3,2.30594065049034], +["1kxh",2.3,1.52652100878866], +["1v4s",2.3,2.61276327043887], +["1q1s",2.3,2.79497948031984], +["1mbu",2.3,1.97286387681653], +["1q5i",2.3,2.48648203115376], +["1s52",2.3,2.80591635379203], +["1zs6",2.3,1.99385330479966], +["1a8m",2.3,4.07485208086022], +["1lky",2.3,3.01209457518986], +["1g1o",2.3,2.74786268786163], +["1muh",2.3,3.29443239617109], +["1o6e",2.3,3.60337281545271], +["1lof",2.3,3.08302971512579], +["1kcf",2.3,2.24878777514223], +["1e1l",2.3,2.51867537890926], +["1pdu",2.3,1.89818161464718], +["2bnh",2.3,2.72296911496472], +["1tql",2.3,2.61211906059305], +["1wsu",2.3,3.06662642681419], +["1q5v",2.3,2.68072533486472], +["1x7j",2.3,2.52896058701853], +["1ep5",2.3,2.57479811764133], +["1grt",2.3,2.81053604149075], +["1n6b",2.3,2.96555045736582], +["1x7b",2.3,2.68859184525252], +["1cp3",2.3,2.77379039179667], +["1x78",2.3,2.53994505560168], +["2bdm",2.3,2.0285014034089], +["2bne",2.3,2.89833855556342], +["1gc5",2.3,3.41109877856285], +["1k6r",2.3,2.51221418750281], +["1wbf",2.3,2.75033953453294], +["1pgn",2.3,2.92823733448977], +["1nm0",2.3,1.82945072214381], +["1kgj",2.3,2.60821454672462], +["1ome",2.3,2.84827836368663], +["1rtk",2.3,2.44931972860408], +["1eqy",2.3,2.79285421529139], +["1b49",2.3,2.27498091971325], +["2d3l",2.3,2.25630259693493], +["1jxh",2.3,2.80268363529863], +["1cwv",2.3,3.054261796591], +["1h7h",2.3,1.96797578439961], +["1hfz",2.3,2.98218818332411], +["2baw",2.3,2.72437304923664], +["1b96",2.3,2.78321783109833], +["1eov",2.3,2.19557307782608], +["1oe5",2.3,2.91107421883171], +["1xpj",2.3,2.48766912221326], +["1p9l",2.3,2.95434273520727], +["1fgg",2.3,1.96858631327287], +["1yl5",2.3,2.3916985090116], +["2bbt",2.3,2.02853043465615], +["1pif",2.3,2.25837616860034], +["1c8q",2.3,2.28743244151906], +["1fa2",2.3,3.30751478115998], +["1isj",2.3,2.36231573262961], +["1uxr",2.3,2.68473002236117], +["1uxn",2.3,2.74108127082122], +["1yol",2.3,2.09255633068427], +["1x7g",2.3,2.90967158826522], +["1fp8",2.3,2.04071171352465], +["1qai",2.3,3.18405673268747], +["1sh2",2.3,2.60631346857240], +["1g0h",2.3,3.62024800101734], +["1ahh",2.3,2.92692131155918], +["2f7y",2.3,2.36099588402476], +["2tsb",2.3,3.11653290486411], +["1etj",2.3,2.70305062513666], +["1jxo",2.3,2.04689821869264], +["1ct1",2.3,2.41993989615915], +["1uoc",2.3,3.10095997854889], +["1ahi",2.3,2.72243732637185], +["2brk",2.3,2.04266362776698], +["1e5r",2.3,3.59966518422773], +["2d4q",2.3,2.78165278397438], +["2bmb",2.3,1.95864763370095], +["1tjr",2.3,3.13478946790113], +["1pum",2.3,3.00873851808567], +["1puu",2.3,2.90358251201828], +["1m6u",2.3,3.23681485618199], +["1vko",2.3,2.5247568142558], +["1lb9",2.3,1.95739160471963], +["1swv",2.3,2.56932185554192], +["1sww",2.3,2.71406487826641], +["1lw3",2.3,2.77360246758536], +["2a8h",2.3,2.79329628720664], +["1qaj",2.3,2.87425445784464], +["1yqy",2.3,3.18032992419755], +["1b52",2.3,2.67731934508399], +["1x7h",2.3,3.03979331984403], +["1lw1",2.3,3.33564546290771], +["1p0p",2.3,2.70439501838505], +["1lb8",2.3,2.18561915090956], +["1s7j",2.3,3.07553275677973], +["1mqb",2.3,2.76041761357698], +["1cr5",2.3,2.59880613422679], +["1yra",2.3,2.87086124172614], +["1exz",2.3,3.41637281043999], +["1sgk",2.3,2.54028153315294], +["1lss",2.3,2.96444681348067], +["2ktq",2.3,3.54166986523009], +["2gb5",2.3,1.52377765786157], +["1k74",2.3,3.36615788171142], +["1k3r",2.3,3.69732964291816], +["1zgb",2.3,2.35609991955144], +["1dx6",2.3,2.59138533449403], +["2d1q",2.3,1.95744745354620], +["1f6f",2.3,2.86798687838531], +["1k4d",2.3,2.22334215828781], +["1slb",2.3,2.94481737223334], +["2gwx",2.3,3.33981879635076], +["1jjb",2.3,2.27625988961576], +["2bva",2.3,3.76139061673456], +["1qig",2.3,2.62432058844936], +["1jtd",2.3,2.07085777325300], +["1cbu",2.3,3.60782691659188], +["1f6w",2.3,3.40289690978254], +["2dfp",2.3,2.64877265912549], +["1p9o",2.3,2.51513479538830], +["2ast",2.3,2.36994461455328], +["1g4u",2.3,2.61280167727611], +["1y2i",2.3,2.54832592201293], +["1ctn",2.3,2.68895459563014], +["3ktq",2.3,3.16131557359482], +["1qss",2.3,2.9345044303035], +["1qsy",2.3,3.07726798428907], +["1qtm",2.3,2.9519113506419], +["2prg",2.3,2.41587263628372], +["1qqr",2.3,3.02510254481167], +["1f48",2.3,3.14858259950547], +["1tw5",2.3,2.53271890335129], +["1tvy",2.3,2.67761838453634], +["1tw1",2.3,2.8804435747531], +["1o0r",2.3,2.86933885291765], +["1ima",2.3,2.10297000164524], +["1sg8",2.3,3.14826001282832], +["1jzd",2.3,2.94539731919737], +["1zd3",2.3,2.66156053554197], +["1vyu",2.3,2.20917650080006], +["1cy2",2.3,2.75014730046648], +["1cy1",2.3,2.79496106954593], +["1sgi",2.3,3.04511044334214], +["1t57",2.3,3.79605151973931], +["1rpm",2.3,2.79528166714674], +["1qdn",2.3,2.50428203721685], +["1f80",2.3,3.09076137462672], +["1rrj",2.3,2.46184683717386], +["1y14",2.3,2.71606768501316], +["1hbr",2.3,3.03950042962788], +["1smp",2.3,2.04491648500508], +["1mkw",2.3,3.58917158114363], +["1y0c",2.3,2.62960829074689], +["1bij",2.3,3.15800034609919], +["1hab",2.3,3.93295690185439], +["1y8k",2.3,2.55896614892914], +["2aou",2.3,2.24765185140221], +["1zz8",2.3,2.61931883295015], +["1y82",2.3,1.75351065293921], +["1cki",2.3,2.79543909359616], +["1q6p",2.3,2.72282480808401], +["1npd",2.3,2.83011097933319], +["1rsc",2.3,2.62808604814779], +["2d06",2.3,2.81134539071076], +["1qex",2.3,2.8592053126104], +["1s2e",2.3,2.90171765533382], +["1jn9",2.3,2.15744657277897], +["1q6t",2.3,2.54987649657660], +["1aux",2.3,2.62788420853665], +["2g07",2.3,2.14477650564586], +["1ts2",2.3,1.80650165926238], +["1zrl",2.3,2.58606070705988], +["1f14",2.3,2.07700471759617], +["1m75",2.3,2.32414786087299], +["1gal",2.3,2.81190557599542], +["2bxp",2.3,2.72705266979811], +["1s5t",2.3,2.05605013224381], +["1f17",2.3,1.99133152209770], +["2gj1",2.3,2.61888113613439], +["2c7b",2.3,3.29052576350994], +["1zwj",2.3,2.45145822137729], +["1xzp",2.3,2.98992281679959], +["3ng1",2.3,2.78475084265626], +["1iq0",2.3,2.64735517924072], +["1x1x",2.3,2.67138967412455], +["1x1u",2.3,2.83866135207037], +["1wkm",2.3,2.45803436005644], +["1rc5",2.3,3.71503206018297], +["1ni2",2.3,2.90959526756376], +["1oph",2.3,2.25010885558619], +["1dkr",2.3,2.90812919794802], +["1k9o",2.3,3.25558000556381], +["1apz",2.3,2.65693051149616], +["1ksp",2.3,3.04542926569712], +["1t7o",2.3,2.55208409903466], +["1v19",2.3,2.99379540310035], +["2a5k",2.3,2.88857434989615], +["1jwu",2.3,2.63636218356953], +["2amq",2.3,2.78138311913229], +["1ikn",2.3,3.71351986601029], +["1xec",2.3,2.67139909749392], +["1jsu",2.3,2.78704720715701], +["1ghs",2.3,2.28068329560326], +["1sqm",2.3,2.35002670619943], +["1ry2",2.3,3.40553856601174], +["1vlw",2.3,1.89401026514606], +["1u2l",2.3,2.5872394936922], +["1eqw",2.3,2.71464571223357], +["2b5i",2.3,2.88912014500392], +["1wsf",2.3,3.22961984654507], +["1hq5",2.3,2.79699106484311], +["1dlq",2.3,2.65217691016388], +["1wvb",2.3,3.36025722744063], +["2dd8",2.3,2.88619956360942], +["1wda",2.3,2.78597952071693], +["1r4f",2.3,2.46739221437587], +["1nfk",2.3,3.71376543861682], +["1qo3",2.3,2.32457186133541], +["1fpi",2.3,2.46281004599826], +["1fpl",2.3,2.43400362916757], +["1fpg",2.3,2.61387207758110], +["1oc4",2.3,2.75572229519408], +["1f9d",2.3,1.53635672410305], +["1fbo",2.3,1.72270806696568], +["1mwk",2.3,2.90531349005668], +["1ww4",2.3,3.08993233834418], +["1avh",2.3,2.96952382513559], +["1ma7",2.3,3.86530008910906], +["1n0l",2.3,2.85844393032541], +["1uuw",2.3,2.41900522580565], +["1c03",2.3,2.90086760746330], +["1t2x",2.3,1.81917084026438], +["1w9c",2.3,2.44486717040663], +["1a5s",2.3,3.36161881200971], +["1ttp",2.3,3.06828051578505], +["1u7z",2.3,2.66057980372434], +["1a50",2.3,2.42141102041233], +["2eud",2.3,2.87893191302972], +["1c9d",2.3,2.88153538753138], +["1c29",2.3,2.88696135416279], +["1cx9",2.3,3.03194106875699], +["1xwk",2.3,2.59455777515271], +["1fwy",2.3,2.39641103628487], +["1hiw",2.3,3.39182762033245], +["1xmu",2.3,1.99447464873353], +["1k7e",2.3,2.53869331370573], +["1m41",2.3,3.35438018619948], +["1xds",2.3,2.60452252787241], +["2bkt",2.3,3.42797864289058], +["2fky",2.3,2.44267528712823], +["1nb8",2.3,3.16184740906708], +["1xez",2.3,2.22945947756004], +["1v3t",2.3,2.23196161285798], +["1v6a",2.3,2.32350862340763], +["1muq",2.3,3.15820901967999], +["1q4k",2.3,2.92590039819452], +["1s8e",2.3,2.64711192793110], +["1i1i",2.3,2.52100970053237], +["1u6s",2.3,2.32177882802915], +["2b7j",2.3,3.09862796255218], +["1azt",2.3,1.86865657923116], +["1fsa",2.3,3.43327918549146], +["1zvw",2.3,2.423622102331], +["1ph5",2.3,2.52916834368374], +["1hmw",2.3,2.64496197979627], +["1ph4",2.3,2.34719584727620], +["1ph3",2.3,2.42458385214673], +["1q3w",2.3,2.45008855419333], +["1bth",2.3,2.90452881193643], +["1l3a",2.3,2.76471912937521], +["1gzs",2.3,2.43029289779024], +["2ae4",2.3,1.84544184551903], +["1s0y",2.3,2.70164635471827], +["1ciu",2.3,2.98966585757793], +["1ezs",2.3,2.14025489737118], +["1rpx",2.3,2.55217002956071], +["1p8c",2.3,3.26300252903800], +["1y23",2.3,2.43333542030887], +["1r37",2.3,2.21251135269464], +["1bxg",2.3,2.95655815658375], +["1pr1",2.3,2.72578818386239], +["1uum",2.3,2.35416095125644], +["1aa6",2.3,3.04401125853194], +["1x0v",2.3,2.65546169485967], +["1pke",2.3,2.53608070550534], +["1ics",2.3,2.27395352492409], +["1n9w",2.3,2.5445122757875], +["1yj4",2.3,2.16536375432861], +["1xai",2.3,3.55856875424494], +["1f3m",2.3,3.2925930502201], +["1kob",2.3,2.59102495292793], +["1q97",2.3,2.62129601411141], +["1pr2",2.3,2.49073469228386], +["1td5",2.3,3.01978984663930], +["1q0o",2.3,1.99093168157933], +["1azs",2.3,2.29154698142845], +["1n95",2.3,3.05571296937413], +["3bls",2.3,3.11555460177651], +["1utc",2.3,2.16677047206258], +["2muc",2.3,1.9847202136315], +["3muc",2.3,1.96111930684327], +["1ke0",2.3,2.29639531593485], +["1iem",2.3,2.19763515377581], +["1j8d",2.3,2.86793600491042], +["1o5m",2.3,2.17990393801322], +["1o1r",2.3,2.07942772981813], +["1o1s",2.3,2.38484304718519], +["1bls",2.3,3.07161461628014], +["1bjn",2.3,1.46049671181681], +["2b98",2.3,3.03545382683687], +["1mdp",2.3,2.85191785793135], +["1azz",2.3,2.57677731605152], +["1n7q",2.3,2.84199948486143], +["1jcq",2.3,2.11514806655697], +["1hjw",2.3,3.01556997807287], +["1w29",2.3,2.30132187689325], +["1ng4",2.3,2.67893252092640], +["1p19",2.3,3.72269877067032], +["1ltt",2.3,2.31422798151715], +["2b8e",2.3,2.81714583539558], +["1tn7",2.3,1.91740216399282], +["1gp2",2.3,3.28209725847623], +["1nx8",2.3,2.02282370281446], +["1p7o",2.3,2.94792475896264], +["1itq",2.3,2.49527680498892], +["1g31",2.3,2.68308635816596], +["2bvn",2.3,2.72735396465830], +["1d1c",2.3,3.39624531186539], +["1qjg",2.3,2.75578818257971], +["2d0t",2.3,2.90221878952185], +["1p3i",2.3,2.17549634390057], +["1ma0",2.3,2.03444997891596], +["1m6w",2.3,2.08366004463172], +["1li5",2.3,2.89437827127604], +["1m72",2.3,2.39688789007054], +["1m19",2.3,2.67806349061752], +["1x1h",2.3,2.63015122089742], +["1j0m",2.3,3.07501628768460], +["1xme",2.3,2.59517082362075], +["1jti",2.3,3.00052425245461], +["1tqd",2.3,2.99252251429753], +["1wu2",2.3,2.36358550714885], +["1s7t",2.3,2.26734226410989], +["1kit",2.3,3.70645851022969], +["1vft",2.3,3.34806896786333], +["1ibj",2.3,3.17585784695819], +["1js8",2.3,2.62500306448846], +["1eez",2.3,2.68918622382811], +["1nan",2.3,3.08130513081035], +["1kec",2.3,2.02516002439746], +["1kj3",2.3,2.476616675478], +["1kra",2.3,2.53551539134236], +["1sl2",2.3,2.26695269618244], +["1vym",2.3,3.28088265159579], +["1wc5",2.3,2.84704742955137], +["1rjn",2.3,2.32761285281075], +["1ws9",2.3,1.75115670167573], +["2bw7",2.3,2.91020742102918], +["1x9w",2.3,2.5795003152186], +["2ccr",2.3,2.37741892904443], +["1t3n",2.3,3.74767981842884], +["1vkz",2.3,2.50513082250895], +["1skw",2.3,2.51615605943459], +["1ay8",2.3,2.60595451472786], +["1dco",2.3,3.66013862481383], +["1dcp",2.3,3.47067106467569], +["1sks",2.3,2.69400423170447], +["1ei1",2.3,2.97601722369751], +["1pzy",2.3,2.67720747559508], +["1iyk",2.3,2.23333012528140], +["4xia",2.3,1.89910434396925], +["1xla",2.3,2.31238283988982], +["1tk0",2.3,2.60315459829335], +["2gds",2.3,2.76900627194196], +["1iea",2.3,2.60877834127836], +["1arh",2.3,3.5319852484277], +["1ahy",2.3,3.48050404924933], +["1ahe",2.3,3.4159598975097], +["1ahf",2.3,3.56941387958561], +["1ari",2.3,3.78025977658407], +["1t1r",2.3,2.74464215151626], +["1bx3",2.3,2.41856097388939], +["1f2e",2.3,2.18710013700711], +["4ovw",2.3,2.71219563563186], +["3ovw",2.3,2.45470051385001], +["2b11",2.3,2.54887205294205], +["2pcc",2.3,3.57910183425501], +["8aat",2.3,2.50029642334347], +["1dkl",2.3,2.45881194542033], +["1p2g",2.3,2.52281682055298], +["1rs8",2.3,2.65310724859380], +["1uzu",2.3,2.72201987596115], +["1c8l",2.3,2.82720326866908], +["1gfz",2.3,3.07094030080396], +["1en5",2.3,1.77760924971407], +["2b7n",2.3,2.83544485329631], +["1z8d",2.3,2.62438598427426], +["1yex",2.3,2.31495893084837], +["1sg9",2.3,2.58383583933579], +["1e6d",2.3,2.29485449684752], +["1jwk",2.3,2.03711759036479], +["1r35",2.3,2.96242420928940], +["1o9o",2.3,2.46832871087983], +["1fop",2.3,2.74314423227345], +["1axr",2.3,3.20236336894389], +["1z5u",2.3,1.52653714822978], +["1c50",2.3,3.17561096225446], +["2pri",2.3,3.22069211989705], +["2prj",2.3,3.23463376433989], +["2gpb",2.3,3.05529092041058], +["1o5o",2.3,2.27089389115639], +["4gpb",2.3,3.09591045648407], +["3gpb",2.3,3.17352738328543], +["5gpb",2.3,3.21735279191289], +["1sot",2.3,3.37306472374867], +["1tpl",2.3,2.94469460449117], +["1xkd",2.3,2.86412674170877], +["1c3u",2.3,2.36819399855156], +["1ung",2.3,3.18564138123925], +["1xf2",2.3,1.68582770946620], +["1rh0",2.3,2.34897734642668], +["1gxs",2.3,2.24012737743174], +["1nop",2.3,2.34992310157661], +["1s0w",2.3,2.19903307802194], +["1xf3",2.3,2.19991163019827], +["1nxe",2.3,3.33066404735225], +["1r4a",2.3,3.11766192446643], +["1t3z",2.3,2.38106180646949], +["1o27",2.3,2.29442910132663], +["1w4b",2.3,2.85848541001769], +["1vbh",2.3,2.53783766640634], +["1hon",2.3,3.30803387572262], +["1hoo",2.3,3.22527646320005], +["1hop",2.3,3.50467515317640], +["1v3c",2.3,2.62475238427282], +["2bmk",2.3,2.92591420849810], +["1xcc",2.3,2.20810020731227], +["1dik",2.3,3.55456420271613], +["2rus",2.3,3.47527140474446], +["1gg4",2.3,3.11470016418675], +["1i7z",2.3,2.79868794695273], +["1lo3",2.3,3.15662668147042], +["1t66",2.3,3.00037105306005], +["1vbg",2.3,2.49808168097403], +["1hm0",2.3,2.76126240756284], +["1rz8",2.3,2.83043645480902], +["1emc",2.3,2.56289576010938], +["1khj",2.3,2.30503346483304], +["1anj",2.3,2.46450273723083], +["2b3q",2.3,2.79041549837033], +["1upf",2.3,3.74708016813268], +["1m0t",2.3,2.46733208234650], +["1qgr",2.3,2.9746408351442], +["1hjk",2.3,3.05080337721171], +["2b7o",2.3,2.66984351085868], +["1w48",2.3,2.45026817344530], +["1t0r",2.3,2.74631128617049], +["1hpl",2.3,2.47785455501745], +["1pbg",2.3,2.36183242926418], +["1bbr",2.3,3.66119971201813], +["1fv3",2.3,3.41678693762273], +["1u28",2.3,2.34562001510784], +["1kbi",2.3,2.6588942034252], +["43ca",2.3,2.64912263930064], +["1fah",2.3,2.74319027141003], +["1fqk",2.3,2.41508471017665], +["1yny",2.3,2.98505808376735], +["2auk",2.3,2.70678463534882], +["1xr7",2.3,2.19812340156229], +["1f1b",2.3,3.43830709659104], +["1l5h",2.3,3.01046905650403], +["2amt",2.3,2.3117334273244], +["1ixo",2.3,2.89804914161686], +["1ixq",2.3,3.05974243340975], +["1gd8",2.3,3.65536888301985], +["4pgm",2.3,3.05241063142635], +["1dnp",2.3,2.27236121222267], +["1h48",2.3,2.28455429239630], +["1wuv",2.3,2.83365208329260], +["1cvn",2.3,2.31979301211924], +["1njf",2.3,2.80164066244314], +["1rzv",2.3,2.27390914691503], +["1rzu",2.3,2.73518703943520], +["1jvg",2.3,2.60545663061486], +["1jxn",2.3,3.13163995189870], +["1ixp",2.3,2.97840672263593], +["1ho4",2.3,2.73674024806171], +["1ixn",2.3,2.78745261051456], +["1j3l",2.3,3.06364437248235], +["1mxf",2.3,2.66305699547709], +["1aog",2.3,2.23630091052984], +["2fs9",2.3,2.67916271692976], +["1wnt",2.3,3.55736312529878], +["1hsj",2.3,3.63163641425725], +["2f9p",2.3,2.62725776987275], +["1yy5",2.3,3.02328216336198], +["2a4m",2.3,3.53774085128583], +["1ecg",2.3,2.15099579351278], +["2g7u",2.3,2.14966967708690], +["1g2c",2.3,2.61874669214944], +["1wvi",2.3,2.725433339135], +["1yt5",2.3,2.95065986226263], +["1tox",2.3,2.67453779861167], +["1jx2",2.3,2.56395849461134], +["1jwy",2.3,2.64217298563347], +["1ki1",2.3,3.14531282922845], +["2csb",2.3,2.44936353963679], +["1w76",2.3,2.78570190842043], +["1erj",2.3,2.23564498854759], +["1xnv",2.3,2.77261097622398], +["1mdt",2.3,3.01425379411277], +["1n1z",2.3,2.06225897277362], +["1n20",2.3,2.17351229851192], +["1n24",2.3,2.23144316792092], +["1ygy",2.3,3.13841302804531], +["1pvd",2.3,2.98944761020954], +["1s1m",2.3,3.77170348389437], +["1o5q",2.3,2.45269822177007], +["1kk8",2.3,3.05221446125016], +["1djx",2.3,3.20536422591462], +["1yqf",2.3,1.71740059357838], +["1uik",2.3,2.65231801370512], +["1urp",2.3,2.26990117130856], +["1j3j",2.3,2.59919057079096], +["1qbg",2.3,3.00911934487286], +["1kbo",2.3,3.20917590921690], +["1jw7",2.3,3.23402932158373], +["1iy9",2.3,2.99067407485890], +["2fok",2.3,3.27319134444543], +["1pkd",2.3,2.86021532418245], +["2c5p",2.3,3.0365032119011], +["1vyw",2.3,2.31267051464368], +["1fin",2.3,3.40972212779519], +["1ydn",2.3,2.86894994282367], +["1e6e",2.3,2.65344605652906], +["1l8w",2.3,3.0504052505874], +["1ca9",2.3,2.94471722689373], +["1pv1",2.3,3.28269941148802], +["1yox",2.3,3.01346585365867], +["2b4s",2.3,1.69396619383934], +["2bwj",2.3,1.77464579982178], +["1it7",2.3,3.01392313347808], +["1h5s",2.3,2.83032152044974], +["1ji2",2.3,2.52039865629897], +["1wzk",2.3,2.60774882516984], +["1b3u",2.3,2.67883395725331], +["1nbf",2.3,3.20958540572588], +["1o4z",2.3,2.13746157300665], +["1prc",2.3,2.98720781111832], +["1rp3",2.3,2.32141263026648], +["1llq",2.3,2.76468103532385], +["1ndi",2.3,3.28135622726136], +["1yw3",2.3,2.79449777791599], +["2ggk",2.3,2.56133068215717], +["2can",2.3,2.68929061506608], +["1gbn",2.3,2.84678293250650], +["1aor",2.3,2.31472282287082], +["1pgu",2.3,2.59819269056374], +["1ibr",2.3,3.15277136757244], +["1s7g",2.3,2.3341070618049], +["1tll",2.3,3.24965660565644], +["1ez4",2.3,2.35093552019409], +["1bgx",2.3,3.04856849398434], +["2mas",2.3,2.67828527457306], +["1fta",2.3,2.51537012784400], +["1jx1",2.3,2.97825664044917], +["1pg3",2.3,2.03340143905813], +["1ye6",2.3,1.73564838854317], +["2cx4",2.3,3.49489208937218], +["1s0f",2.3,2.98191508723319], +["1qdm",2.3,3.5301167616657], +["1ub7",2.3,2.66621347618321], +["1xsl",2.3,1.87925724778318], +["2a8c",2.3,2.78876195881087], +["1zsv",2.3,1.76153677511271], +["1ptw",2.3,2.72614540673135], +["1q9m",2.3,2.41458130141524], +["2awn",2.3,3.33546019798004], +["2scu",2.3,3.50934925748], +["1iil",2.3,2.56630257182605], +["1u5w",2.3,3.01406073385373], +["2aq3",2.3,3.94610360293585], +["1tkb",2.3,2.60289792363574], +["1fzc",2.3,3.3026011039667], +["6ald",2.3,3.11888007368562], +["1so0",2.3,3.06807561915930], +["1kr2",2.3,2.44275493857836], +["1rye",2.3,3.09564535074433], +["1y10",2.3,2.37901530698526], +["1xs2",2.3,2.39909406300884], +["1xpy",2.3,2.65939677510800], +["1j7n",2.3,3.06691970330582], +["1ixe",2.3,2.51422034148593], +["1sja",2.3,3.46831045480591], +["1u1f",2.3,2.08654988384268], +["2b35",2.3,2.84553000427593], +["2fut",2.3,2.33759156098397], +["1vz0",2.3,2.80744253173977], +["1kh2",2.3,2.67997265745425], +["1kh1",2.3,2.70242676676337], +["1ilu",2.3,2.30591363422731], +["1cm5",2.3,2.26911632548148], +["1h18",2.3,2.35710770635506], +["1j70",2.3,2.74959982912467], +["1hwi",2.3,2.18507594095697], +["1ey3",2.3,2.63211672330256], +["1bxc",2.3,2.90180036769482], +["4xim",2.3,1.90567472586735], +["1z5h",2.3,3.02440667611272], +["3xim",2.3,2.05570859452697], +["5xin",2.3,2.04725761170382], +["3xin",2.3,2.04300394272659], +["2xim",2.3,2.09309239464236], +["2xin",2.3,2.1897504336399], +["1lv8",2.3,3.20277246248993], +["1l7x",2.3,2.27180715543484], +["2ovw",2.3,2.54361383186632], +["1g5i",2.3,2.66510751268942], +["2a9g",2.3,3.31242089970634], +["2aq7",2.3,2.22702086348129], +["2aaf",2.3,3.26528441808157], +["1dd8",2.3,2.23330885068198], +["1dx5",2.3,2.50695869811156], +["1dcn",2.3,2.99592098198555], +["1rf5",2.3,2.78325780443589], +["1yp4",2.3,2.83842095202326], +["1rj7",2.3,2.41525457477579], +["1uc5",2.3,2.68234420927522], +["1wbq",2.3,1.31161668622756], +["1uc3",2.3,2.34743433698553], +["1bgg",2.3,2.5908588513843], +["1j08",2.3,2.33828351010925], +["1hy1",2.3,2.79372552064322], +["1ohv",2.3,1.95462736329655], +["2bgc",2.3,2.68727347868087], +["1jja",2.3,2.72982989901199], +["1si8",2.3,2.52023048122547], +["1q15",2.3,2.52074997508643], +["1k9x",2.3,2.80102812272945], +["1itz",2.3,2.32838378983632], +["2b43",2.3,2.70513197856085], +["1t70",2.3,3.2544911946454], +["1b33",2.3,2.0899811755383], +["1q3q",2.3,2.68697346427171], +["1xvd",2.3,2.53066059094815], +["1xu3",2.3,2.56261697523541], +["1fz9",2.3,2.83918594002026], +["1ezv",2.3,2.90107959042752], +["1kb9",2.3,2.79334387725939], +["1pj4",2.3,2.63400314547783], +["1pj2",2.3,2.80947634173191], +["1gz3",2.3,2.59298802330882], +["1m56",2.3,3.37985926175797], +["1l6l",2.3,3.39985024551503], +["1m7x",2.3,3.33080183597469], +["1t9d",2.3,2.09041560819547], +["1upp",2.3,2.76491691912192], +["1u2j",2.3,3.44669959920706], +["1rbo",2.3,2.29968759360148], +["1r56",2.3,2.40081745916717], +["2cv4",2.3,3.26829809808242], +["1tb3",2.3,2.6819540661504], +["1i10",2.3,3.14111258795615], +["2gl6",2.3,1.69119814070411], +["1w88",2.3,2.06631418510769], +["1llu",2.3,2.96155558795322], +["1mx0",2.3,3.04538126645286], +["1pmo",2.3,2.33478963181334], +["1ru7",2.3,2.7876426805631], +["1r9n",2.3,2.55516832894080], +["2afk",2.3,2.4341527053922], +["1vrg",2.3,1.58187310300643], +["1q51",2.3,2.58799745171824], +["2c91",2.3,2.20996391564786], +["1ryw",2.3,2.16320372057419], +["2occ",2.3,2.66127483439543], +["1twf",2.3,3.23042997158439], +["2bkc",2.3,2.30728349545869], +["1qhb",2.3,1.59107634809061], +["1vqm",2.3,2.78097832596951], +["1vql",2.3,2.80646824975778], +["1vqk",2.3,2.79444778387693], +["1wpg",2.3,2.82718466627191], +["1ya7",2.3,2.39900117018794], +["1upm",2.3,2.42880448537484], +["1rco",2.3,2.4135390748114], +["1uwa",2.3,2.16549979058465], +["1m34",2.3,2.66704554899359], +["2g23",2.3,3.01922371799197], +["1xma",2.3,1.36619746539549], +["2a4k",2.3,1.26746676220636], +["1rzn",2.3,2.64355611633941], +["1w55",2.3,2.08992950605232], +["1xqu",2.3,1.59585435722037], +["5rhn",2.31,1.70571595599078], +["2bhi",2.31,2.61702149037953], +["1rs2",2.31,2.94745918867349], +["2ffg",2.31,2.87566166127653], +["1jim",2.31,2.2666854317532], +["1ggl",2.31,3.68057033682318], +["1pzd",2.31,2.33001379892170], +["1v1k",2.31,2.73004627722218], +["1xcd",2.31,2.24684501606861], +["1ziv",2.31,2.36628514129792], +["1iub",2.31,2.06162921829761], +["1s7o",2.31,2.0086846000245], +["1z7b",2.31,2.52699293741287], +["1siu",2.31,2.92921923013844], +["1t67",2.31,2.55940975904943], +["1dli",2.31,2.43822762699471], +["1s6y",2.31,2.61402794225613], +["1xn0",2.31,2.06680836727174], +["1xm4",2.31,2.12877342585344], +["1ybt",2.31,2.89499541951302], +["1zee",2.31,2.79267379485934], +["1ulh",2.31,3.3030113124212], +["1l3c",2.31,2.15347618271913], +["1ajp",2.31,2.46421553580162], +["1tog",2.31,2.74089759599284], +["1j78",2.31,2.61812648342314], +["1vh0",2.31,2.59025827553350], +["1tu3",2.31,3.1104091527772], +["1vgv",2.31,2.73966483633987], +["1b0p",2.31,2.88446012774942], +["2bp3",2.32,2.41264915545637], +["2a3q",2.32,2.49307862837634], +["2f4e",2.32,3.02267918114603], +["1qtr",2.32,3.43538010088371], +["1vmi",2.32,1.81064240962364], +["1eyi",2.32,2.40710121055994], +["1vhz",2.32,2.50106693866964], +["1q87",2.32,3.03612370720953], +["2aq4",2.32,2.96460143354678], +["1hxa",2.32,2.31056622046822], +["1ayy",2.32,2.70177125490036], +["1s5w",2.32,2.03756050772157], +["1omo",2.32,3.19281531651017], +["1pez",2.32,2.070811604684], +["1o23",2.32,2.80439575917706], +["1nwg",2.32,3.10947294960664], +["1asq",2.32,2.1507720274865], +["1xmf",2.32,2.55766858501458], +["1xmh",2.32,2.44212700404809], +["2c3u",2.32,2.91921947103108], +["1zkz",2.33,2.56964637235126], +["1k5a",2.33,3.31127176530601], +["1z0i",2.33,2.57788532753988], +["1aue",2.33,2.87020700163999], +["6chy",2.33,3.40573156955029], +["1ltq",2.33,3.05638282908504], +["2a03",2.33,1.20098493203636], +["1g95",2.33,2.29076565450699], +["1mfp",2.33,2.97104866647501], +["1oie",2.33,1.78591406172107], +["2bco",2.33,2.56297331417953], +["1o65",2.33,2.50949872385877], +["1ay4",2.33,2.70531710905604], +["1zlv",2.33,2.74637871426067], +["1wc7",2.33,4.02278069715016], +["1yq4",2.33,2.77942364472532], +["1j3i",2.33,2.54044051743924], +["1xi9",2.33,1.82423561493974], +["1hw9",2.33,2.31281971491657], +["1qlb",2.33,2.79231917858704], +["2c3p",2.33,2.47408663079552], +["1nxt",2.34,2.10580466524925], +["1s0l",2.34,3.01632298559842], +["112m",2.34,2.55371236923592], +["1gx9",2.34,3.76305887055315], +["1awu",2.34,2.96355345621857], +["6upj",2.34,2.56908227026231], +["1p06",2.34,2.42394541817694], +["1cla",2.34,2.21401036804244], +["1r2y",2.34,2.29853037146108], +["1gwk",2.34,2.00702911140795], +["1zbt",2.34,1.9808753791811], +["5pep",2.34,3.4162325552381], +["1atr",2.34,2.75103949289851], +["1n64",2.34,3.0759450734768], +["1zy9",2.34,1.91297908828273], +["1ki4",2.34,3.16359765851121], +["1khg",2.34,2.5344353548801], +["1xot",2.34,2.33355832764399], +["1ya3",2.34,3.19839801389544], +["1k5q",2.34,1.87010824494146], +["1mpw",2.34,2.96692376348815], +["2nse",2.34,2.88579384348909], +["1awv",2.34,3.31686421029467], +["1t9c",2.34,1.79715484704508], +["1gqt",2.34,2.49980377007254], +["1yey",2.34,3.10260137272633], +["1yl7",2.34,2.15202962481305], +["1syx",2.35,2.30046481813455], +["2cro",2.35,3.06640152547909], +["1i3f",2.35,1.85472146324175], +["1k0k",2.35,2.86639141109856], +["1b72",2.35,2.07261810041811], +["1mkp",2.35,2.22045767334887], +["2fiw",2.35,2.73302872298512], +["1gxa",2.35,4.00425418960597], +["1mwi",2.35,2.40357982191076], +["2bt7",2.35,2.32832722139160], +["1e7n",2.35,2.36616742582954], +["1kdm",2.35,2.84949359014407], +["2b5s",2.35,2.35527559056738], +["1znx",2.35,1.96049221007328], +["1hdf",2.35,2.64359875203268], +["1ftc",2.35,2.43095928882073], +["1p5t",2.35,3.33570765739839], +["2cla",2.35,2.39796802729484], +["1yyv",2.35,2.16692000415505], +["1ap9",2.35,3.79588445702089], +["1dl7",2.35,4.28701483372130], +["1p4b",2.35,3.19003794440805], +["2enr",2.35,2.15963458800155], +["1jn3",2.35,3.10070799941025], +["1txu",2.35,2.46059017805061], +["1ccs",2.35,2.73244110984784], +["1cnb",2.35,2.76029225185335], +["2exe",2.35,2.20737425030844], +["1vzj",2.35,3.01319073617370], +["2c3l",2.35,3.26378563358503], +["1qe6",2.35,2.51276261911994], +["2f5s",2.35,2.58729100122353], +["2f5q",2.35,2.32063593822742], +["1lhd",2.35,3.25322731295133], +["1o6j",2.35,2.69196994746241], +["1cyf",2.35,2.94341650506261], +["1oc9",2.35,2.41888324327846], +["1c84",2.35,2.901657414217], +["1bzc",2.35,2.60841702388136], +["1kav",2.35,2.66495384318003], +["1a6j",2.35,2.52570683555761], +["1pz0",2.35,2.68447986195646], +["1hu0",2.35,2.81643183197148], +["1or8",2.35,3.08725724211079], +["4tms",2.35,2.74084112523775], +["1ukh",2.35,3.21853284074375], +["1d8u",2.35,2.85961165784799], +["1tzs",2.35,2.22930081016077], +["1nnq",2.35,1.21073764249155], +["1xhc",2.35,1.44207265128162], +["1g3t",2.35,2.64386067114331], +["1o5r",2.35,3.71366259399293], +["2bu5",2.35,2.93995161335385], +["1g9u",2.35,3.38601129699521], +["1ds6",2.35,2.19416569345200], +["1guv",2.35,3.10659520820344], +["1qzo",2.35,3.17459231249573], +["2crk",2.35,3.29423069066469], +["1xks",2.35,2.61288498100331], +["1a21",2.35,2.46345474580667], +["1kjm",2.35,3.19165132363909], +["2bi8",2.35,2.4822590535801], +["1f2i",2.35,3.01301839074731], +["1b9v",2.35,3.4180494037693], +["2aua",2.35,2.32669853596682], +["1egy",2.35,2.78854091130707], +["1r5b",2.35,3.13307015682905], +["2an9",2.35,2.10908349172504], +["1zb7",2.35,2.36821918909445], +["1pqy",2.35,2.24020983959746], +["2b2y",2.35,3.11696446664612], +["2ptk",2.35,3.82521185040360], +["1ow6",2.35,2.87719427631176], +["1q9h",2.35,2.30370738824714], +["1z3s",2.35,3.10346418841979], +["1rke",2.35,3.14787549781160], +["1wro",2.35,2.80477373759104], +["1v7u",2.35,2.67341144922386], +["1ra7",2.35,2.28150090859410], +["1r6q",2.35,1.45401851194748], +["1f1j",2.35,2.43278644365409], +["1e2s",2.35,2.88989006665567], +["1e24",2.35,2.07630716764126], +["2avn",2.35,1.77285349377607], +["1uxv",2.35,2.88369879815343], +["1i7i",2.35,2.83563170020577], +["1xu2",2.35,2.17159197360569], +["1vcm",2.35,2.87726874107982], +["1gpn",2.35,2.20574032201017], +["1qyn",2.35,2.67962492469908], +["1st8",2.35,2.34486559593091], +["1vj5",2.35,2.62093481228338], +["1t10",2.35,3.0153786265927], +["1nvt",2.35,2.8835857380371], +["1vnf",2.35,1.95243077220194], +["2g0a",2.35,2.09898695759083], +["2g08",2.35,2.23926372414447], +["2bdu",2.35,2.06894126697525], +["1s5v",2.35,1.86290794164369], +["1i7l",2.35,2.73568025531909], +["2afo",2.35,2.17468949782160], +["1pvp",2.35,3.75255821946912], +["1u4c",2.35,3.71896043697451], +["1q9d",2.35,2.95586290799243], +["1xaj",2.35,3.22451215100661], +["1tw3",2.35,2.35594640402259], +["2asj",2.35,2.91337059788245], +["1m80",2.35,3.24054605813726], +["1x8j",2.35,2.14284231274267], +["1dot",2.35,3.79044171462280], +["2al6",2.35,2.66278408185153], +["1pz8",2.35,2.97828120273585], +["1r1j",2.35,3.15100357425986], +["1fcn",2.35,2.8658174947645], +["1uoo",2.35,2.01991900176405], +["1q8z",2.35,2.96187551640745], +["1qu0",2.35,2.59444032051932], +["1v2f",2.35,2.56876196029996], +["1ewh",2.35,2.64080698366666], +["1u08",2.35,2.652728818961], +["1ai4",2.35,2.46628228625274], +["1d8t",2.35,2.69308537287408], +["1jmj",2.35,2.66003373853923], +["1asm",2.35,3.29594888880836], +["2czg",2.35,2.41368690942994], +["1p6l",2.35,2.50318013285242], +["1ogv",2.35,2.64170867313529], +["1m8d",2.35,2.05969862297134], +["1rtw",2.35,2.26179411289561], +["6nse",2.35,2.68023384530557], +["7nse",2.35,2.62473974121453], +["1dmj",2.35,2.62230713152518], +["1ftq",2.35,3.20512149409514], +["1fu8",2.35,3.27436463055589], +["1unh",2.35,3.14222673756901], +["1df1",2.35,3.0130975390227], +["1dwv",2.35,2.83222825103631], +["1dww",2.35,2.89541804928450], +["1nj9",2.35,3.94568768081435], +["1jqn",2.35,2.58996841810985], +["1vh8",2.35,2.62360749409072], +["1vha",2.35,2.60726353249534], +["2az1",2.35,3.01543337539650], +["1ona",2.35,2.86987694591451], +["1mu2",2.35,3.0155834492351], +["1qvv",2.35,2.77707679329784], +["1qnw",2.35,2.53966158419706], +["2d3s",2.35,2.71909906233378], +["1rtj",2.35,3.69396174766608], +["2gdd",2.35,2.71966180046693], +["1yvy",2.35,2.76824934555548], +["1pn4",2.35,2.02423970184448], +["1r0z",2.35,2.70621465003223], +["1j06",2.35,2.50469999648455], +["1j07",2.35,2.38081798072233], +["2bxa",2.35,2.80548485012087], +["1xeb",2.35,3.15338389016398], +["2cbj",2.35,2.53486147537323], +["1vbo",2.35,3.13590501537926], +["5prc",2.35,2.72019456756710], +["2bpj",2.35,2.52355443919498], +["1vgw",2.35,2.73233153926406], +["1g9c",2.35,2.60217203445666], +["1qoh",2.35,1.94329696518443], +["1jkj",2.35,2.56096515203782], +["1rjw",2.35,2.43183699864583], +["1xr2",2.35,2.54957751250819], +["1y1q",2.35,2.89375988090178], +["1yq9",2.35,2.31736137949676], +["1fj4",2.35,3.05397123474451], +["1qgh",2.35,2.67945935540862], +["1bxs",2.35,2.29862262640001], +["1l0l",2.35,3.65577667328612], +["1upa",2.35,1.81461150731892], +["1xhx",2.35,2.51686315637605], +["1ffu",2.35,2.40162847707030], +["1nf6",2.35,2.15554275069797], +["1rxc",2.35,2.01393597716380], +["1ocr",2.35,2.76177577733434], +["1pkl",2.35,2.75739028812022], +["1a5u",2.35,3.42406410586679], +["1tzl",2.35,2.46027364248783], +["1vld",2.35,2.75308397922572], +["1nv9",2.36,3.39004645960475], +["1phw",2.36,3.67125568926068], +["1ulf",2.36,2.39645881793153], +["1jms",2.36,2.57043820144422], +["1dvr",2.36,2.89044475927576], +["1ag1",2.36,2.9398237018484], +["1ux1",2.36,2.13086271720234], +["1zab",2.36,2.12174960526699], +["1y2x",2.36,1.87705817692761], +["1ak4",2.36,2.22371140468404], +["1q18",2.36,2.93284527694645], +["1ph8",2.36,2.68036684861398], +["1ai5",2.36,2.45502623828652], +["1ajn",2.36,2.44151678129007], +["1ftw",2.36,3.255304598732], +["1ggn",2.36,3.24782565821919], +["1fu4",2.36,3.26008189012135], +["1fu7",2.36,3.29082059197899], +["1hu3",2.37,2.86964541548597], +["1fqw",2.37,2.15523418882594], +["1td3",2.37,2.78656869358826], +["1stf",2.37,2.57303346542406], +["2bqr",2.37,2.87402958524107], +["7jdw",2.37,2.43737023658857], +["1qbm",2.37,3.21217624522370], +["1u93",2.37,2.69551410910986], +["1zoq",2.37,3.00019233864954], +["1ki6",2.37,2.89215501072111], +["1ki3",2.37,3.59951513465028], +["1qjv",2.37,1.91261830247244], +["1b8g",2.37,3.02800928934972], +["1r0c",2.37,3.32938858612409], +["1xr4",2.37,2.14427488068034], +["1tu5",2.37,2.93584957235303], +["1p9u",2.37,2.58542906443347], +["1hcu",2.37,2.84271726603604], +["1bu6",2.37,3.98321526672607], +["1h3l",2.38,3.2913647507021], +["1eof",2.38,2.08484869640206], +["1ttw",2.38,3.90055955987377], +["1kxf",2.38,2.46479849674928], +["1f9s",2.38,3.61715501902409], +["1pml",2.38,3.36407625315633], +["1lj2",2.38,2.49127998416897], +["1u6h",2.38,3.57827442485831], +["2cj8",2.38,2.69272686567530], +["1j6x",2.38,2.37856085925908], +["2fa7",2.38,3.01535624906353], +["1vli",2.38,2.11088448386848], +["1suj",2.38,3.16506942428658], +["2c4q",2.38,2.31925363764196], +["1dko",2.38,2.72912212346493], +["1fo2",2.38,2.66314845868142], +["1uc9",2.38,2.22435283960543], +["1a9n",2.38,2.74198892727729], +["1p0m",2.38,2.66738689798677], +["1ev7",2.38,2.89616853549253], +["1ewy",2.38,3.93864176935016], +["1ehi",2.38,2.88297708513675], +["2c7u",2.38,2.65043397647492], +["1fs4",2.38,3.22000687138554], +["1fty",2.38,3.21967938652396], +["1z52",2.38,3.09717570473187], +["1e7b",2.38,3.44362182033645], +["1gz6",2.38,2.53138256648778], +["2gf2",2.38,1.92423598544357], +["1uu1",2.38,3.25607485336299], +["1fz4",2.38,2.75643636925655], +["1exs",2.39,3.27690360002846], +["2f5y",2.39,2.39411892267355], +["2fl3",2.39,2.90218296156597], +["9mht",2.39,2.17455561470049], +["1c3v",2.39,3.02828557130474], +["2fkc",2.39,2.81965752310504], +["1b3s",2.39,2.30211271149209], +["1y9k",2.39,2.20772731752863], +["2c6p",2.39,2.61332527279078], +["2gjv",2.39,1.56345988143174], +["2biw",2.39,2.39433267684863], +["2ahx",2.4,2.43880100682701], +["1hgz",2.4,2.84023222040988], +["1hgv",2.4,3.92821732704101], +["1hh0",2.4,3.56048581913788], +["1ijw",2.4,2.45614844566592], +["1kne",2.4,2.8241963674738], +["1uo0",2.4,3.30233074581562], +["1unx",2.4,3.83696691762476], +["1szt",2.4,3.51646774155463], +["2ctx",2.4,3.89444403548044], +["1dol",2.4,2.8196106114616], +["1a7g",2.4,2.98676227151674], +["1myk",2.4,2.94500244578306], +["1qj0",2.4,2.64515343669636], +["2sam",2.4,2.46539399992910], +["1ce0",2.4,3.43918929178761], +["1nwm",2.4,3.07004957688425], +["1deb",2.4,1.74752720273563], +["2bhk",2.4,2.88623628023213], +["1fb8",2.4,2.53604542903172], +["3pal",2.4,3.03590909159983], +["1nt3",2.4,3.64588735375739], +["9ant",2.4,2.56087296459740], +["1ueg",2.4,1.88782543537273], +["1uvy",2.4,2.62238243586421], +["1b8i",2.4,3.82326469456554], +["1lt0",2.4,2.44027780128418], +["1lsv",2.4,2.54083365434275], +["1xt3",2.4,2.79944892969550], +["1drm",2.4,2.51702502237104], +["1iiz",2.4,3.40553629653518], +["1cqa",2.4,2.74664794071646], +["1u68",2.4,2.10095368973797], +["1url",2.4,2.98766096342083], +["3fit",2.4,2.826386437788], +["1ang",2.4,2.9682689980912], +["1u5z",2.4,2.53941412329607], +["4p2p",2.4,3.07736366959385], +["1rlw",2.4,2.85595125365135], +["1ax8",2.4,2.69831253494062], +["1a18",2.4,2.44947598991005], +["2c7m",2.4,2.32631680124519], +["1c7p",2.4,2.33014796926451], +["1ioc",2.4,2.51177075811824], +["1he9",2.4,3.62639112716852], +["1qmt",2.4,3.46157203397229], +["1vyg",2.4,2.67269926665761], +["1zv4",2.4,1.55492958673844], +["3nll",2.4,2.70988334096098], +["1ku7",2.4,3.21721770980477], +["2tdx",2.4,3.72828645782316], +["1h3q",2.4,3.08794242853677], +["2f5c",2.4,2.47332680957121], +["1lsg",2.4,3.62929135305205], +["1jj4",2.4,2.62335490733439], +["1tbe",2.4,3.40186572322779], +["8i1b",2.4,3.26090351043087], +["1j9g",2.4,2.33119627027231], +["1hib",2.4,3.11504717835455], +["1uzq",2.4,2.98462238482199], +["2aak",2.4,3.00274146207138], +["1wzw",2.4,2.25265907088652], +["1v5h",2.4,3.69078906271434], +["6dfr",2.4,3.45847532927481], +["1lb4",2.4,2.89540298268148], +["1mup",2.4,3.87701969971315], +["1jk6",2.4,2.48107966507351], +["1jao",2.4,2.63617577455493], +["1rh3",2.4,3.67225234582348], +["1tlq",2.4,3.46450339197896], +["1gx8",2.4,3.93292874486716], +["1lb5",2.4,2.47504996797642], +["2b6y",2.4,1.63556811118414], +["2b6z",2.4,1.80571990657351], +["2b70",2.4,1.77794006063563], +["1job",2.4,2.62711171393291], +["1fue",2.4,3.00092599685007], +["1f2q",2.4,2.5067656963394], +["1kuy",2.4,2.68093506140276], +["621p",2.4,3.12325355707162], +["2g3y",2.4,2.37634332305597], +["1m8j",2.4,2.04617829890006], +["1m8f",2.4,2.08921920775848], +["1ec6",2.4,2.66656171283994], +["2bdt",2.4,2.61938475204423], +["1rce",2.4,2.30169850636317], +["1rcc",2.4,2.27679006012758], +["1fha",2.4,2.11466989123816], +["1ha4",2.4,2.35389827584927], +["1i5i",2.4,2.55198396814935], +["1qqs",2.4,3.62832232692245], +["1oia",2.4,2.53417938849297], +["2fx0",2.4,2.48248986751109], +["1e44",2.4,2.35879040202712], +["1a2b",2.4,2.74165930791181], +["1f7c",2.4,2.28757318402949], +["1m5k",2.4,2.62411948912523], +["1umi",2.4,2.93841755282414], +["1vdx",2.4,2.26648705589336], +["2fdo",2.4,2.11863004339112], +["2sas",2.4,3.04916074183114], +["1jh7",2.4,4.07301171683503], +["1dr7",2.4,3.21108915191373], +["1dr5",2.4,3.00698159946559], +["1dr4",2.4,2.94964601262608], +["1dr6",2.4,2.98945022763574], +["1m5v",2.4,2.55963365638575], +["1h8g",2.4,2.6490152937221], +["2f44",2.4,2.83234614137249], +["1jsx",2.4,2.84124193304452], +["1yt0",2.4,2.17244362203713], +["1bj0",2.4,1.79720679175034], +["1a6i",2.4,2.69243475841491], +["1u7u",2.4,3.26929107072717], +["1f4r",2.4,2.56386338499361], +["1ork",2.4,2.65721962395929], +["1tcw",2.4,2.93238080307129], +["1vij",2.4,3.67803932257772], +["1vik",2.4,3.35641445492784], +["2bxj",2.4,2.21900698017452], +["1r6n",2.4,2.33797092227892], +["1no1",2.4,1.21197327432017], +["7hvp",2.4,3.42824840275478], +["1rnl",2.4,2.29489555380705], +["1k9v",2.4,2.80650022563996], +["1m5j",2.4,3.18697364502523], +["1bt6",2.4,3.31193193986149], +["1gsq",2.4,3.27058378399467], +["1ln1",2.4,3.202218492306], +["3ull",2.4,3.4627594552392], +["1xk5",2.4,3.43481095903871], +["2ahy",2.4,2.50159665788113], +["1trp",2.4,3.23978745625525], +["2fz4",2.4,3.57973392007919], +["1fbz",2.4,3.53634392661295], +["1k79",2.4,2.6998818686106], +["1an8",2.4,2.72284313129851], +["1g3w",2.4,2.51532692152718], +["1z9m",2.4,2.57742167903862], +["1g3s",2.4,2.34242410980007], +["1f6o",2.4,3.01250230119452], +["1oys",2.4,2.41667653482869], +["1a1c",2.4,1.86312270719521], +["1s35",2.4,1.78541382975082], +["1bwr",2.4,3.14007902724785], +["1snk",2.4,2.65931421114371], +["1dve",2.4,2.42406037360569], +["1hul",2.4,2.9793206079335], +["1ayw",2.4,2.96003854613388], +["1jgj",2.4,3.20808304677454], +["1cjm",2.4,2.65447972994043], +["1mov",2.4,1.90548398484381], +["1gta",2.4,3.06078980486716], +["1spp",2.4,2.71593122396666], +["1m4c",2.4,2.37561472525042], +["1emf",2.4,2.58363540983108], +["1wvr",2.4,2.84773580104164], +["1j14",2.4,2.10030172164362], +["1sq6",2.4,2.78212273121355], +["1yje",2.4,2.83818430698114], +["1euf",2.4,2.47383923633378], +["1qok",2.4,2.26424201480827], +["1ucq",2.4,2.82074777670915], +["1z34",2.4,2.61649336933299], +["1gmz",2.4,2.75418855844585], +["1upw",2.4,2.78357178211801], +["1i8i",2.4,3.00368641281280], +["1ttj",2.4,2.66943037521396], +["1orf",2.4,2.76428436330331], +["1i4x",2.4,3.67467337472898], +["1tti",2.4,3.38452903399175], +["1n1a",2.4,2.98303429760237], +["5p2p",2.4,3.26642281457097], +["1qan",2.4,2.38471638916494], +["1tri",2.4,3.28331040338222], +["3cna",2.4,4.74869894693446], +["3lbd",2.4,2.68538173969525], +["1hqw",2.4,2.17442943878656], +["1jmc",2.4,3.3047849871202], +["2rnf",2.4,3.38045989043243], +["1cbf",2.4,2.83433761901670], +["2gmf",2.4,2.9776675371339], +["1tp2",2.4,2.97765069391361], +["1byg",2.4,2.93687221099911], +["1hrh",2.4,3.34988223330174], +["1okr",2.4,2.67487232684997], +["1i9h",2.4,2.52346889491198], +["1ogl",2.4,2.44644344446776], +["1th8",2.4,2.05024357033536], +["1aoa",2.4,2.85187864743851], +["2art",2.4,2.71594780461614], +["1qtf",2.4,3.04241579775551], +["1zat",2.4,2.72353020570169], +["1yr8",2.4,3.67382721089459], +["1myl",2.4,2.5086914401942], +["1vj9",2.4,2.43145517820822], +["1sc8",2.4,2.31832113469135], +["1lbl",2.4,2.7338922225519], +["1ab5",2.4,2.63216208193483], +["1ozj",2.4,3.43081221267555], +["1o9h",2.4,2.30924359370124], +["1y17",2.4,2.59631437237342], +["1y8x",2.4,2.97701373691671], +["1e3g",2.4,3.20156414866096], +["1rhp",2.4,3.58319205094148], +["1hvv",2.4,2.25662707424571], +["1jj7",2.4,2.00264848672607], +["1nq0",2.4,2.89439474074160], +["1bai",2.4,3.82039101937806], +["1zdm",2.4,2.26378615048089], +["1ag0",2.4,4.04493882359790], +["1ri4",2.4,2.83750469021128], +["1oz7",2.4,3.73752098562627], +["1gyw",2.4,2.20659638182013], +["1ifq",2.4,2.55059226493288], +["1nq2",2.4,3.19869486249338], +["12ca",2.4,2.85543377104227], +["7ca2",2.4,3.02707842362542], +["8ca2",2.4,2.88049523316055], +["1cvb",2.4,2.72344117311438], +["1nbb",2.4,2.67294473046396], +["1ipa",2.4,2.87475704634214], +["1bnq",2.4,2.64417655408626], +["1qgo",2.4,2.23471639318551], +["1bnv",2.4,2.48416069622253], +["1tza",2.4,2.22875264247563], +["1mq0",2.4,2.62865806236884], +["1ifu",2.4,2.43179964877329], +["1zam",2.4,1.66771426530565], +["1a2d",2.4,3.09346593105611], +["2b6p",2.4,3.62935008083904], +["1tpk",2.4,2.57637353899379], +["1vjr",2.4,1.23547710068457], +["1l9k",2.4,2.95777491134916], +["1l2b",2.4,2.28279627684457], +["1mat",2.4,3.78004610919983], +["1yxk",2.4,2.69156787518090], +["1l8t",2.4,2.94407120896829], +["1ajm",2.4,3.13584353449847], +["1yi4",2.4,3.00455355833109], +["1zbp",2.4,2.97668473061639], +["1mpt",2.4,3.21382343059346], +["2ghr",2.4,1.46110625250754], +["1ne4",2.4,3.38336330545391], +["2f5f",2.4,2.13483262126085], +["1x8f",2.4,3.58626216778939], +["1vr2",2.4,3.22050812317075], +["1ubn",2.4,2.04215721059856], +["2bxw",2.4,1.40274641144261], +["1s5x",2.4,2.10594603847812], +["1wvw",2.4,2.74514676189586], +["1r8e",2.4,2.57478763166104], +["1nrr",2.4,2.9739110348211], +["1gjo",2.4,2.76744476609022], +["1jkk",2.4,2.42277454709651], +["1lhf",2.4,3.34709485086364], +["2bmz",2.4,2.27143817154823], +["1oec",2.4,2.64190610605863], +["2a6m",2.4,3.60425605310971], +["1ptk",2.4,2.62042541943435], +["1xkk",2.4,2.09222597772855], +["1v4i",2.4,2.55834961656788], +["1exw",2.4,3.22499638991171], +["1hcq",2.4,3.43850618496158], +["1i44",2.4,2.41846331668133], +["1c4x",2.4,3.19471374335778], +["1yjl",2.4,3.15862411493015], +["1ql6",2.4,2.46804117189275], +["1q1z",2.4,1.80833793214469], +["1kts",2.4,3.01099183029081], +["1ehw",2.4,2.28639228521446], +["1s5k",2.4,2.65953521422242], +["1ytw",2.4,2.65804756754441], +["1ytn",2.4,2.83402252442209], +["1twx",2.4,3.45912531054742], +["1nl9",2.4,2.17703529988454], +["1nz7",2.4,2.61213859615549], +["1nny",2.4,2.42492967095022], +["1no6",2.4,2.86794903035813], +["1g7v",2.4,4.3151716624489], +["1abj",2.4,3.54724164958268], +["1nrs",2.4,3.54505909120639], +["1lpz",2.4,2.94446956189961], +["1s9j",2.4,1.90983857421585], +["1hai",2.4,3.46297239841329], +["1h0n",2.4,3.73053310494501], +["1a9p",2.4,2.91404091046847], +["1xrr",2.4,3.14932940011682], +["1bej",2.4,2.57658745993207], +["1cci",2.4,2.15662487707492], +["2au1",2.4,2.97743086992937], +["1tq7",2.4,3.34347899268026], +["1bco",2.4,2.37380833534894], +["1mu0",2.4,2.94495546333681], +["2bgd",2.4,1.84112959422615], +["2cg4",2.4,2.79900259359085], +["1bjp",2.4,2.21663467540898], +["1ah5",2.4,2.44124510037448], +["2ab4",2.4,3.19355325051299], +["1n26",2.4,3.11528877583415], +["2ftp",2.4,2.40092954481575], +["1rw8",2.4,3.40154847627817], +["1g1h",2.4,1.67255994616260], +["1ese",2.4,3.3949965678552], +["1b3v",2.4,1.84131191232317], +["1pvu",2.4,2.67107537264118], +["1id1",2.4,2.73331923434403], +["1uty",2.4,2.42031057713816], +["1squ",2.4,3.40832371777543], +["1rks",2.4,2.31432734146967], +["3gbp",2.4,2.18808683868371], +["1rz5",2.4,2.08753303490485], +["1spd",2.4,4.47963243243756], +["1ux9",2.4,2.42141781476072], +["1ury",2.4,2.51893290761072], +["1f8y",2.4,2.33470854330363], +["1rdr",2.4,2.29608352301269], +["1o59",2.4,2.43562187037739], +["1en7",2.4,2.52222511624542], +["1i7c",2.4,2.59342421228500], +["2byk",2.4,3.01539574976424], +["1yz4",2.4,2.98884754562142], +["1ga5",2.4,3.11759540972963], +["1eb7",2.4,2.52692766320956], +["1c9w",2.4,2.90023533468019], +["2g86",2.4,2.77272615498361], +["1bp0",2.4,2.56825291069935], +["1bo8",2.4,2.44517350727783], +["1bo7",2.4,2.59707056227875], +["1bp6",2.4,2.72022296889763], +["1bpj",2.4,2.73135454514243], +["2g8d",2.4,3.28844524013954], +["2g8a",2.4,3.3986200612034], +["1czv",2.4,3.07805999940507], +["456c",2.4,3.27033624716254], +["1kkh",2.4,3.42908373561998], +["1xu4",2.4,2.97653004119183], +["3pfk",2.4,2.45581623454751], +["4pfk",2.4,2.60177824805952], +["1b55",2.4,4.40954223869743], +["1ep9",2.4,2.50217107168678], +["1a55",2.4,2.44371123653881], +["1cgl",2.4,3.29276353618986], +["1nw9",2.4,2.76993840370395], +["1nhh",2.4,2.55134272930029], +["1dd4",2.4,3.38791145312144], +["1ssy",2.4,2.22912059279655], +["1as3",2.4,2.56694286946801], +["1rne",2.4,2.59369213091998], +["1s3l",2.4,3.05945263854341], +["1rmh",2.4,2.52395235765962], +["2jxr",2.4,3.42571695195257], +["1u9j",2.4,2.76536202864728], +["1j19",2.4,2.56488752223633], +["1fq5",2.4,3.30051093794857], +["1dtg",2.4,2.35062610168071], +["1bpx",2.4,4.20613187649982], +["1z75",2.4,2.78424889547251], +["1z6y",2.4,2.93553067663696], +["1mzf",2.4,2.33925834796926], +["1sib",2.4,3.8149557693597], +["1ko8",2.4,3.24022559521896], +["1oq9",2.4,2.5478569518279], +["1a8y",2.4,2.70627383998353], +["1fte",2.4,2.62847838239764], +["1djs",2.4,3.29845340355534], +["1k7t",2.4,3.44189938505126], +["1hxt",2.4,2.47630992848877], +["2omf",2.4,2.73367696290825], +["1d8f",2.4,2.40845725625089], +["1rrs",2.4,2.87536415342722], +["1bi3",2.4,2.66752744318639], +["2liv",2.4,3.39655608547136], +["1jqp",2.4,2.42350269537473], +["2lbp",2.4,3.71784020020514], +["1uby",2.4,3.9379857243854], +["1rrg",2.4,3.2513451955388], +["1m7q",2.4,2.65413779805433], +["2bu6",2.4,2.80617456150022], +["1jhl",2.4,3.34020409319177], +["1fkx",2.4,3.01764984198720], +["1uio",2.4,3.12258329275388], +["1fkw",2.4,2.97206016845642], +["1uip",2.4,2.99736135483739], +["2ada",2.4,3.27990966922952], +["1add",2.4,3.33473576591048], +["2a8v",2.4,2.96632285915285], +["2pax",2.4,2.21381386869327], +["1pax",2.4,2.27054139627702], +["3pax",2.4,2.25972347969758], +["1bmk",2.4,3.21509133510987], +["2erk",2.4,2.73436111047766], +["1wbn",2.4,2.52484694905560], +["1cvm",2.4,2.90215482974896], +["1sg1",2.4,3.37164422502396], +["1wbp",2.4,3.19351713659562], +["1re0",2.4,1.92734013125863], +["2bu2",2.4,2.91798100043022], +["1pnq",2.4,2.66230638493637], +["1ps8",2.4,2.78283322069776], +["2bu7",2.4,2.68529172004752], +["2ajh",2.4,2.62983224775667], +["1n1i",2.4,2.60869180319382], +["1p0e",2.4,2.64440837682054], +["1jdx",2.4,2.57391888348304], +["3jdw",2.4,2.5276166582379], +["1bjf",2.4,2.93803021783094], +["1e96",2.4,2.59461755449118], +["1woo",2.4,2.41153307328027], +["1pdk",2.4,3.14207102546035], +["3caa",2.4,2.92025212041779], +["1o9u",2.4,2.88527633706817], +["1xm7",2.4,3.30175259434368], +["1dxp",2.4,3.33095243854775], +["1r5h",2.4,2.39630625055936], +["1tv5",2.4,2.30324952135991], +["1tfh",2.4,2.91516540870830], +["1dy8",2.4,3.02125454212916], +["8adh",2.4,3.42614044520564], +["1hiz",2.4,1.95027140827012], +["1hoc",2.4,3.42736129711522], +["1az3",2.4,3.36637104234132], +["1jmm",2.4,2.36043134013392], +["1az4",2.4,3.46268324182329], +["1bii",2.4,3.30328291341845], +["1ui6",2.4,2.32118094902332], +["1d3u",2.4,2.71895863092394], +["1sys",2.4,2.37366882154791], +["1jk8",2.4,2.79890455452608], +["1lgh",2.4,2.85793327964856], +["1xtk",2.4,3.26877820501656], +["1fgs",2.4,2.64066620333012], +["2iad",2.4,3.63505494072988], +["1ffs",2.4,2.1456914034267], +["2be3",2.4,2.41878050464879], +["1s0u",2.4,3.14728973312569], +["1n1c",2.4,2.52359115490489], +["1ktc",2.4,2.14214267756349], +["1z1e",2.4,2.88349379339895], +["1inx",2.4,2.93966024560488], +["1inw",2.4,3.18260976046822], +["1ive",2.4,3.69283346216448], +["1ivf",2.4,3.60379829737985], +["1ivc",2.4,3.50369834681783], +["1iny",2.4,2.80869512321184], +["1vcj",2.4,3.01753751795142], +["1inv",2.4,2.62658257139918], +["1inf",2.4,3.09328974473372], +["1b9t",2.4,3.44011396423532], +["1ivb",2.4,3.51444337051462], +["1zyp",2.4,2.60701190442746], +["1col",2.4,2.80093543285478], +["1cj4",2.4,2.01143680651403], +["1ui5",2.4,2.12788186857831], +["1h3t",2.4,3.10449297466211], +["1wc0",2.4,2.66026145940184], +["1asc",2.4,3.28866913451172], +["1yoo",2.4,2.70904991576886], +["1asa",2.4,2.98286847895318], +["1cq7",2.4,2.90915393997162], +["1cq8",2.4,2.89310734148195], +["1c9c",2.4,2.93325142874817], +["1aaw",2.4,3.46623611048019], +["5eaa",2.4,3.3730757556758], +["1cze",2.4,2.38824210686068], +["1h4v",2.4,2.65838732734277], +["1yla",2.4,2.68156990983788], +["1f3p",2.4,3.35057490953229], +["1map",2.4,2.92050100249721], +["1ivr",2.4,3.31151924314211], +["1xvv",2.4,2.47665735639409], +["1xvu",2.4,2.70358867669908], +["2tmk",2.4,2.39268174059669], +["1vp7",2.4,1.91611900703008], +["1ern",2.4,3.33805027359067], +["1fno",2.4,3.16631264659261], +["1vyq",2.4,3.01656524027162], +["1dkn",2.4,2.99767713583577], +["1mj2",2.4,3.18688594955101], +["1kas",2.4,2.70025067013328], +["1k6q",2.4,3.26365549728268], +["1mrc",2.4,2.90617350759515], +["1h3u",2.4,3.23702881084304], +["7icd",2.4,2.77712076962911], +["2bbc",2.4,2.90642334374255], +["1qpg",2.4,2.77730024272705], +["1mrf",2.4,2.93160142580544], +["1yis",2.4,2.38396763895028], +["2brx",2.4,2.49755329983451], +["1z0x",2.4,2.95232731659782], +["1f77",2.4,2.63371500463421], +["1ngq",2.4,3.4181760857281], +["1ngp",2.4,3.45432100539792], +["1e0d",2.4,3.18985841375634], +["1h3m",2.4,2.97350592491233], +["1yq6",2.4,1.93072878701159], +["1nlj",2.4,3.29711819691796], +["1wdu",2.4,3.0212211058772], +["1keg",2.4,2.23914196874095], +["1mez",2.4,2.54482168323616], +["4bjl",2.4,4.29022567922098], +["2bg2",2.4,2.55226192700945], +["1ehl",2.4,3.43367826992196], +["1m0o",2.4,2.86856083851839], +["1pdy",2.4,2.70771518012381], +["2b2w",2.4,3.00483745346068], +["1h8s",2.4,2.86469755410687], +["1lo4",2.4,3.3356598716027], +["1els",2.4,3.52010612525144], +["1ee5",2.4,2.59225513148109], +["2bwy",2.4,1.37685082123355], +["2bhc",2.4,1.13950328325311], +["2bn7",2.4,1.10459160461067], +["2bh3",2.4,1.26763188032690], +["1u8m",2.4,2.69197848221367], +["2bha",2.4,1.27402297461368], +["2eyr",2.4,2.15679879365730], +["2etl",2.4,2.75032164614339], +["1to9",2.4,2.80895065806841], +["1z8u",2.4,3.13477290215094], +["1b0i",2.4,1.92028205277489], +["2h1p",2.4,3.56457549674819], +["2npx",2.4,2.52316944483485], +["9atc",2.4,3.40365637407517], +["1ywt",2.4,2.83364013567421], +["1be4",2.4,4.03239983461392], +["1sfj",2.4,3.17089214202526], +["1ndl",2.4,2.31124768770264], +["1fxx",2.4,2.12855150045044], +["1dfp",2.4,2.87595142042262], +["1w3s",2.4,2.7980139114975], +["1e1n",2.4,2.74792616963883], +["1bp1",2.4,2.818106354563], +["1wrb",2.4,3.52376380272766], +["1u9e",2.4,2.31817436532845], +["4gr1",2.4,2.61286010608452], +["5grt",2.4,2.83434145602949], +["7gep",2.4,2.51329520546432], +["2atp",2.4,3.20504134743523], +["1tfc",2.4,2.4571745619309], +["1i1r",2.4,2.99580981126259], +["1nmq",2.4,2.59607155448809], +["2bg3",2.4,2.28571879082082], +["1glm",2.4,1.91922291818453], +["1rdt",2.4,2.64774523184964], +["1xa7",2.4,3.3042034052604], +["3enr",2.4,3.06239490359070], +["1dgl",2.4,3.07683543736983], +["1rty",2.4,2.60516810129985], +["1chk",2.4,2.58847205392026], +["1pk5",2.4,3.41570088097266], +["1h7k",2.4,2.37749922545658], +["1jsi",2.4,2.39598981857736], +["1jsh",2.4,2.41531910765636], +["2ewm",2.4,2.36665134361014], +["1uoj",2.4,2.15890534680245], +["1e1z",2.4,2.82949118950156], +["1jso",2.4,2.65589313980468], +["1jsn",2.4,3.05037859351442], +["1lx6",2.4,2.63049793344383], +["1gwr",2.4,2.57748505254465], +["1mss",2.4,3.03648559955575], +["1jad",2.4,2.73066933414406], +["1bll",2.4,3.06980286606922], +["1e1t",2.4,2.06866800292549], +["1ac5",2.4,2.05525729939532], +["2b5e",2.4,2.77209641314534], +["1h9b",2.4,1.82423598076494], +["1e5s",2.4,3.54392559833020], +["1c0f",2.4,1.66656649351337], +["1dej",2.4,1.60111412423761], +["1i30",2.4,2.76897508292136], +["1m7o",2.4,2.57108321157864], +["1m7p",2.4,2.57344403876195], +["1ad4",2.4,2.38593958039300], +["1i4o",2.4,3.05527018591504], +["2ap2",2.4,3.30518562863648], +["1v15",2.4,2.86703870842247], +["1lxc",2.4,2.68783307754597], +["4tim",2.4,2.65503142439994], +["1vah",2.4,2.31636122090693], +["1lbe",2.4,3.42867269875465], +["1ish",2.4,2.33367710038302], +["1uxq",2.4,2.89397387059176], +["1ky8",2.4,2.71375471765128], +["1ae1",2.4,2.50581677928847], +["1dwj",2.4,2.0891403855873], +["2btm",2.4,2.47614572737847], +["1lbx",2.4,3.80863825197486], +["1g0i",2.4,4.21752230520182], +["1l6m",2.4,2.89497069476321], +["1b14",2.4,2.93725147013308], +["1azr",2.4,2.12831447989002], +["1fgb",2.4,3.8305629539394], +["2brl",2.4,2.03988897232942], +["1k2w",2.4,2.51075587442179], +["1me5",2.4,3.86978793174520], +["2bmx",2.4,2.90502862060849], +["1rql",2.4,2.88811003684062], +["1umr",2.4,3.2901584573859], +["1rkm",2.4,2.71062436348272], +["1f1z",2.4,2.90773806742045], +["1t6z",2.4,2.83877371033134], +["1j7u",2.4,2.24472016365165], +["2ack",2.4,2.78534857846594], +["1hnn",2.4,3.02332640707164], +["1ije",2.4,2.04753757522185], +["1ut6",2.4,2.62797382270816], +["1cnt",2.4,2.69462341993138], +["1p74",2.4,2.99762318041971], +["1yz3",2.4,2.46316392163823], +["1r3i",2.4,2.47364377495535], +["1hot",2.4,2.66637424992932], +["1hor",2.4,2.64780657029620], +["2ezv",2.4,3.13433337772143], +["1vxo",2.4,2.45034542887123], +["1c4p",2.4,3.30063113064673], +["1agw",2.4,1.83405045679991], +["1jog",2.4,3.56284066175975], +["1f89",2.4,3.22688063704239], +["1yco",2.4,2.95895865591474], +["3gwx",2.4,3.63509004817367], +["1epu",2.4,3.29326593587308], +["1fr8",2.4,3.3614692357961], +["1fpu",2.4,3.10502576692974], +["1fgx",2.4,2.89189337795035], +["1qrd",2.4,2.67468783821427], +["2ram",2.4,3.46198004245334], +["1xhl",2.4,2.66877125868298], +["1jhz",2.4,3.73767209160744], +["1hia",2.4,2.96375844874382], +["1qsc",2.4,2.60167649920756], +["2azj",2.4,3.16575660521491], +["1qme",2.4,2.71315193605824], +["4daa",2.4,2.29720359950493], +["1iah",2.4,3.05394802786629], +["1n7u",2.4,2.53682482117216], +["1cy7",2.4,2.79296834626321], +["1efh",2.4,2.37936707808753], +["1pvs",2.4,2.47089699549238], +["1ep2",2.4,2.72434815628870], +["1ypp",2.4,3.13495790397083], +["1yax",2.4,2.57390693671888], +["1vp5",2.4,1.93750301943868], +["1zz9",2.4,3.09404978583641], +["1yie",2.4,2.75211569584564], +["1wun",2.4,2.29332592710468], +["1vrw",2.4,2.74839112079188], +["1c4c",2.4,2.60590034701464], +["1c4a",2.4,2.76234998232048], +["2d4r",2.4,2.99839163729666], +["1yb4",2.4,2.99617383325651], +["2aum",2.4,1.47392316357225], +["2aun",2.4,1.68383250746093], +["2bxk",2.4,2.72177290877549], +["1e7c",2.4,3.2987848889514], +["1hk4",2.4,2.76297119737005], +["1gni",2.4,3.17433303245605], +["1f12",2.4,2.39870854427236], +["1ega",2.4,3.59851368828099], +["1ugy",2.4,2.16523057972335], +["1c0a",2.4,2.88251853889837], +["1p9e",2.4,2.85982499143224], +["1joe",2.4,4.05320828362202], +["1jrk",2.4,2.91771969125361], +["1n8y",2.4,2.99482438702366], +["1viq",2.4,2.86336540503392], +["1ji6",2.4,2.79208000837218], +["1qsm",2.4,2.64825241990739], +["1vs0",2.4,2.47592458075], +["1eai",2.4,2.89279768697477], +["1khe",2.4,2.54290637477974], +["1nol",2.4,2.63569350799541], +["1e2l",2.4,2.73571268521218], +["1rq5",2.4,3.03369091946344], +["1klg",2.4,2.91298554235297], +["1uk3",2.4,3.24020815247125], +["1uug",2.4,1.81844132078213], +["1j8v",2.4,2.5914328586913], +["1hxd",2.4,4.22241246643257], +["1iaw",2.4,2.89775573132024], +["2bh1",2.4,2.10239161076990], +["1dar",2.4,3.53984330347663], +["1zu5",2.4,2.72405011713069], +["1eep",2.4,2.94536480229410], +["2eul",2.4,3.53187009226786], +["2trc",2.4,3.02697295617253], +["1non",2.4,2.84318128778930], +["1g1q",2.4,2.71450602618288], +["1gju",2.4,2.46049953711383], +["1y0z",2.4,2.11752970012097], +["1gdh",2.4,3.03790399261983], +["1pfk",2.4,2.17622243544376], +["1kfk",2.4,2.27512645097272], +["1cm8",2.4,2.87573284290013], +["1xx5",2.4,2.44135566748003], +["1xmy",2.4,2.58019202816407], +["1crx",2.4,3.29475534161533], +["1lox",2.4,2.83199113822992], +["2cvy",2.4,2.97551710658025], +["2ary",2.4,2.22932044084518], +["1xkb",2.4,3.45222472549487], +["1y2h",2.4,2.29306372688328], +["2fxa",2.4,2.46650793702589], +["2cvw",2.4,3.02419176990618], +["1ybu",2.4,3.58508764524667], +["1hfj",2.4,2.14856949196819], +["2ahc",2.4,3.80904600099346], +["1kgz",2.4,2.88566059878731], +["1brl",2.4,3.94307737806923], +["2bhm",2.4,2.28355547225708], +["1xe5",2.4,2.79445585187614], +["1y3t",2.4,3.42565042168026], +["1jpl",2.4,2.88265980008456], +["1m43",2.4,3.37570613728156], +["1bil",2.4,3.29788155617852], +["1eoi",2.4,3.86114096103444], +["2bm0",2.4,2.85926024849138], +["1w5a",2.4,2.93243332668337], +["2bnx",2.4,2.4366995093446], +["1pyx",2.4,2.49742917332241], +["2a0z",2.4,1.69733625514458], +["1jal",2.4,3.75269105337649], +["1fep",2.4,3.02925560100600], +["1avq",2.4,3.13331723939084], +["2ae3",2.4,1.93329840109851], +["2cb3",2.4,2.34747754574245], +["1n56",2.4,2.91653247816891], +["8cgt",2.4,2.24104395491249], +["3cgt",2.4,2.51192615124795], +["1dtu",2.4,2.66885371006992], +["1mjt",2.4,2.51440667446450], +["1a2o",2.4,3.63868652566367], +["2bjj",2.4,2.54818613873123], +["4pro",2.4,2.72670499083116], +["1pr4",2.4,2.58751520485161], +["1sji",2.4,3.42438431943648], +["1cul",2.4,1.94284875705371], +["1viu",2.4,2.7552272473619], +["1ub2",2.4,3.08694809007181], +["1dbt",2.4,1.84458682383073], +["1ysj",2.4,1.86268880626273], +["1kiy",2.4,2.06819622729377], +["1lbq",2.4,3.25386177167291], +["2coj",2.4,2.76122139301190], +["1vrx",2.4,2.92174400168254], +["1ece",2.4,2.26025768002679], +["1qbq",2.4,3.00154263672268], +["1idj",2.4,2.63376476275821], +["1s5j",2.4,2.76159807363621], +["1ltg",2.4,2.79436926265067], +["1ukr",2.4,1.81533546769269], +["1s9h",2.4,3.35181062356314], +["1ezu",2.4,2.69123413380638], +["1keu",2.4,2.00870798965294], +["2a01",2.4,3.80810227653556], +["1d5a",2.4,3.13807331740777], +["1rd4",2.4,2.57894559383386], +["1i8t",2.4,2.47737573864439], +["1gg2",2.4,3.31084942201889], +["1kyv",2.4,2.14899040380250], +["1kyy",2.4,2.06157810004696], +["1ehk",2.4,2.77626300298070], +["1nx4",2.4,1.85734568613911], +["1f38",2.4,2.15252013949248], +["1kho",2.4,2.02603050279024], +["1tq8",2.4,2.33960331224211], +["1xtc",2.4,4.34906780146634], +["1qs0",2.4,2.84870708322494], +["2mta",2.4,2.87103236385238], +["1u1j",2.4,3.43015797661441], +["1k6y",2.4,2.37307114835248], +["1a5n",2.4,2.32041967787848], +["1htb",2.4,2.64079026390339], +["1adb",2.4,3.3450008152998], +["1ejv",2.4,2.24805048252696], +["1p3l",2.4,2.46391092124746], +["1u6m",2.4,3.03593440222683], +["1ya6",2.4,2.9363780638952], +["1j0n",2.4,3.14356273436356], +["1t5w",2.4,2.3168101415225], +["1ukw",2.4,2.71467135909776], +["2gl8",2.4,2.90504802325187], +["1qr1",2.4,2.44580304929622], +["1q94",2.4,3.29343641866591], +["1x9e",2.4,2.70334471972906], +["1d0g",2.4,2.7178795744487], +["1ny5",2.4,3.00254097887495], +["3mdd",2.4,2.90071758105225], +["3mde",2.4,2.83773560392791], +["1skr",2.4,2.41642069799209], +["1t94",2.4,3.11088300205122], +["1xa8",2.4,2.71313115277369], +["1inh",2.4,3.58965895890878], +["1ing",2.4,3.74526081924303], +["2ay2",2.4,2.64531627441496], +["2ay5",2.4,2.68267993117367], +["2ay7",2.4,2.6255827991089], +["2ay3",2.4,2.71688082124040], +["1w5s",2.4,3.06019298071044], +["1zl6",2.4,2.82531055140894], +["1y6f",2.4,3.10700733452763], +["1xlm",2.4,2.17839513721604], +["1oke",2.4,3.23867943222515], +["1c3x",2.4,3.10369524438134], +["1ma9",2.4,2.61915237130964], +["1ktd",2.4,2.74148247521983], +["1x28",2.4,2.9306213830126], +["1aic",2.4,3.15237409073892], +["1oe0",2.4,2.63684354604404], +["1t1s",2.4,2.86631165967018], +["3nos",2.4,2.50131846918423], +["2fyw",2.4,2.32725622557334], +["1soz",2.4,3.60202036476992], +["1u74",2.4,2.88314006250764], +["1j8h",2.4,2.61805048348935], +["1yk0",2.4,3.0534420002596], +["1taq",2.4,3.56155125922038], +["1xja",2.4,2.91993101859671], +["1z6p",2.4,2.60711708775900], +["2d13",2.4,2.60023528910952], +["1trr",2.4,3.24565590375667], +["1mjq",2.4,3.46539355939498], +["1m9t",2.4,2.37074517177638], +["2boz",2.4,2.23849765208329], +["1e8z",2.4,3.3580602740382], +["1gpy",2.4,3.39314964357402], +["2skd",2.4,3.18892795504654], +["2skc",2.4,3.18334632235325], +["1noj",2.4,3.01201561207287], +["1nok",2.4,3.0738957850083], +["1vqy",2.4,1.72289770411211], +["1fa9",2.4,3.07032132233991], +["1hl8",2.4,2.30930870929368], +["1pvc",2.4,1.85253308227613], +["1qw4",2.4,2.98044261546617], +["1n2n",2.4,2.90863860729617], +["1e7v",2.4,3.22809413075349], +["1wu7",2.4,2.89141725219662], +["1vde",2.4,3.58543407823775], +["1bnc",2.4,3.31727688249003], +["1sfc",2.4,3.22564671777132], +["1b35",2.4,3.0066768686574], +["1o25",2.4,2.54424272881682], +["1yf2",2.4,3.35612091568840], +["1c5d",2.4,3.88813803323213], +["1np2",2.4,2.92134236722599], +["2gsa",2.4,2.93683062048835], +["1icv",2.4,2.53258802278434], +["1cez",2.4,3.28423351663601], +["1qln",2.4,3.46769710473783], +["2bif",2.4,2.38707045422978], +["1dbr",2.4,4.07409491492879], +["1a4k",2.4,3.65787440493907], +["1tuf",2.4,2.61067798314357], +["1qzq",2.4,2.45718312830941], +["1qfx",2.4,1.72971214973640], +["1kn9",2.4,2.88217375357462], +["1vqw",2.4,2.83306768751315], +["1b9c",2.4,2.99582437809609], +["1nm5",2.4,2.67297583607253], +["1u8w",2.4,2.76324605183626], +["1kh7",2.4,2.38021602045811], +["1kh4",2.4,2.79763477203074], +["1pjs",2.4,3.30060181270037], +["1fcb",2.4,3.83490665940001], +["2anh",2.4,2.24953353444198], +["1pq6",2.4,2.37275680234026], +["1u3q",2.4,2.93335745922426], +["1w49",2.4,2.67319810466834], +["1e5l",2.4,2.65497685842052], +["1bhn",2.4,4.21243885692015], +["1nye",2.4,3.69601827689496], +["1w4a",2.4,2.68420813960801], +["1i21",2.4,3.04130406527486], +["1jyl",2.4,3.60587457171105], +["1i1m",2.4,2.45551046156856], +["1i1l",2.4,2.65212185908675], +["1l9b",2.4,2.62105911097393], +["1wm6",2.4,1.51833659177704], +["2bkh",2.4,2.19967797758433], +["1v6k",2.4,2.18661324430767], +["1jkf",2.4,4.0289865830435], +["2a8x",2.4,2.71841097160875], +["1pxy",2.4,2.71728971888197], +["1vru",2.4,3.29076049627773], +["1mow",2.4,2.76657678251518], +["1n77",2.4,2.74831312889379], +["1g59",2.4,3.89702212342209], +["1t5g",2.4,3.10563841809009], +["1s1t",2.4,2.9892250546899], +["1sbb",2.4,3.08554380437697], +["2c3t",2.4,2.12145784471978], +["1nou",2.4,1.51310866116373], +["1jvd",2.4,2.97220422507857], +["1jeh",2.4,2.81439372141991], +["2fvz",2.4,3.88406387040827], +["1ot5",2.4,2.91333230911338], +["2tpr",2.4,2.73178326022947], +["1ewz",2.4,2.70737342598588], +["2fvl",2.4,1.40190450131377], +["1bzl",2.4,2.3221255394706], +["1nfq",2.4,2.02867359934714], +["2ahm",2.4,2.96897374275037], +["1x87",2.4,2.41196657942914], +["1r1z",2.4,2.42788017440920], +["1yid",2.4,3.64901294289851], +["1x2g",2.4,2.74189572916571], +["1f99",2.4,2.50985105343314], +["1y7v",2.4,2.94670214812847], +["1su4",2.4,3.05450792094479], +["1qas",2.4,2.8440851845897], +["1p1i",2.4,3.56248448278119], +["1px8",2.4,3.19387798142094], +["2aj4",2.4,2.99429591491524], +["2bf7",2.4,2.07354031934658], +["1qzh",2.4,3.35337185243956], +["1kz7",2.4,2.39995878537362], +["1bj1",2.4,2.77231831905689], +["1cz8",2.4,3.29644094726467], +["1h9y",2.4,2.5184308826367], +["1d9e",2.4,2.95466355704564], +["1n22",2.4,2.32264331496070], +["1n23",2.4,2.22404160487473], +["1ox6",2.4,2.29559558744366], +["1w75",2.4,2.63559777052543], +["1dqx",2.4,3.28727057219068], +["1pyd",2.4,3.17506884922529], +["1kyw",2.4,3.19425389148974], +["1zoy",2.4,3.32150541086563], +["1ii0",2.4,3.01231870929874], +["2br8",2.4,2.42352105571067], +["1qlu",2.4,2.61494592650678], +["1wmr",2.4,2.92756742980287], +["2ark",2.4,2.68131119590527], +["2cfx",2.4,2.88297128485467], +["1qpb",2.4,3.28364741239977], +["2bpm",2.4,2.09467662812262], +["1cvu",2.4,3.08226510696998], +["1gw0",2.4,2.29202595168808], +["3pmg",2.4,2.70082132530968], +["2f2f",2.4,2.70709853154468], +["2c47",2.4,2.06796196928709], +["1yff",2.4,2.03063497219877], +["1kfi",2.4,3.00186528213064], +["1kfq",2.4,2.93906179864921], +["1g51",2.4,3.12816697193026], +["1w5t",2.4,3.10330368390569], +["1j0i",2.4,2.52805607086145], +["1j4t",2.4,3.638476676924], +["3prc",2.4,2.44432671551089], +["4prc",2.4,2.73132073710249], +["1j36",2.4,3.23842484169997], +["1j37",2.4,3.30669524738322], +["2ggl",2.4,2.67485494419030], +["2pfk",2.4,2.55720863972047], +["1xjm",2.4,2.65521470133457], +["1xjf",2.4,2.72093871899009], +["1a0s",2.4,2.95365761140079], +["1a0t",2.4,2.95886721485385], +["1yc2",2.4,2.44050263008134], +["2mpr",2.4,2.45523148080055], +["1af6",2.4,2.42847040800834], +["1xbt",2.4,2.32912639057521], +["1k1x",2.4,2.73460754923327], +["1k1y",2.4,2.81138382545182], +["1ye4",2.4,1.91795210588696], +["4aah",2.4,3.0503872143686], +["2bp1",2.4,1.85218718325951], +["1nb5",2.4,3.84282943700537], +["1d9q",2.4,2.00245380669422], +["3eca",2.4,2.81290319639282], +["2bwg",2.4,2.12107428141830], +["2anu",2.4,1.88058310922186], +["1j0x",2.4,2.65068217573582], +["1iu4",2.4,3.34707683003874], +["1jdi",2.4,2.89957593489101], +["2f8j",2.4,1.61694909978773], +["1gk1",2.4,2.30311850781361], +["1gpw",2.4,3.42156411105435], +["1nug",2.4,2.73244123483120], +["1ngs",2.4,2.59554806416371], +["1s97",2.4,2.95432620667454], +["1hi9",2.4,2.50279417087713], +["1umc",2.4,2.17417486480858], +["1nd6",2.4,2.96268845595579], +["1odi",2.4,2.12595086940443], +["1odj",2.4,2.93204730577053], +["1i7s",2.4,3.69497433064322], +["7mdh",2.4,2.66066454605552], +["1cjx",2.4,2.37793421005015], +["1u10",2.4,2.38966275986788], +["1hg4",2.4,2.80902000387647], +["1lq8",2.4,3.43794537360459], +["1nbw",2.4,2.85381817820560], +["1lvn",2.4,2.71388143458341], +["1d6u",2.4,2.50501963468788], +["1d6y",2.4,2.43402864227401], +["1so2",2.4,2.9573364043574], +["2ggg",2.4,2.89562830830884], +["2tmd",2.4,2.60383513182677], +["1dvm",2.4,3.40778486661109], +["1d1t",2.4,2.55391295316373], +["2dub",2.4,2.86666898232994], +["1s7w",2.4,2.78775863921624], +["1e5v",2.4,2.11508096535936], +["1udy",2.4,3.09770533755885], +["1oh6",2.4,2.26723437524007], +["1wbd",2.4,2.26747610121192], +["2ch1",2.4,2.45502611478125], +["1egd",2.4,2.95999367539356], +["7xim",2.4,2.10976933808737], +["1l0q",2.4,2.42751796971682], +["9xim",2.4,2.16700655499935], +["8xim",2.4,2.18841131401427], +["1xin",2.4,2.03187569144774], +["1exv",2.4,2.66645732972133], +["1htz",2.4,2.81305583595022], +["1r9e",2.4,2.34636362815095], +["1qiu",2.4,2.83733950787675], +["1fc0",2.4,3.02543067101184], +["1i3r",2.4,2.42174738223758], +["2bui",2.4,2.24980836780592], +["1f91",2.4,2.04398341370630], +["1mwa",2.4,3.64467554030274], +["2av9",2.4,2.42971403767142], +["1rzz",2.4,2.52193556726305], +["1t77",2.4,2.90048196683184], +["1dfo",2.4,2.21667842906785], +["1qpo",2.4,2.83465359361773], +["1sf2",2.4,2.23948090575379], +["1h2u",2.4,2.18969998843652], +["1o9l",2.4,2.81434696089689], +["3cev",2.4,2.10997354075420], +["1bga",2.4,2.68143737216609], +["1cev",2.4,2.2461309368215], +["1kbw",2.4,2.70330300207814], +["1wyt",2.4,2.78414851149289], +["1tp7",2.4,2.8716634699277], +["1w8y",2.4,2.76870679910099], +["1vln",2.4,2.62156914076932], +["1f4j",2.4,2.77224687320627], +["1uls",2.4,2.8813827250876], +["1a4e",2.4,2.0873356209434], +["1tlb",2.4,3.06163420128463], +["1o9j",2.4,2.25868632051774], +["2agv",2.4,3.07748380691632], +["1kya",2.4,3.15422896728564], +["1q19",2.4,2.83295546619595], +["1r15",2.4,2.92622873901996], +["1afr",2.4,2.56271749708688], +["1q2v",2.4,2.8197546693365], +["1ntm",2.4,3.40534251281074], +["2fty",2.4,2.17163472678906], +["2fvk",2.4,2.07196136503878], +["2dd0",2.4,2.79721106295963], +["1xve",2.4,2.69691444412721], +["1fz5",2.4,2.70393732251519], +["1dt5",2.4,2.71528913485701], +["2a74",2.4,3.16014257604810], +["1iri",2.4,2.45295854956733], +["1bwv",2.4,2.23375941939762], +["1b4n",2.4,2.90231157540516], +["1e9r",2.4,2.77736569572307], +["3pcn",2.4,2.58562856102804], +["1foh",2.4,2.69343627689111], +["1w2m",2.4,1.39571990882028], +["1m35",2.4,1.78836999382419], +["1g8y",2.4,2.80801800046838], +["1p7y",2.4,2.527123509278], +["1vf7",2.4,2.80435234583189], +["1mx1",2.4,2.53717314195501], +["1up7",2.4,2.41360088480056], +["1e79",2.4,2.80024976501495], +["1u6j",2.4,2.93439300741220], +["1qni",2.4,2.8982815173837], +["1wyv",2.4,2.73064607162244], +["1s72",2.4,2.82041113054406], +["1vqn",2.4,2.87903512143703], +["1vq9",2.4,2.99937621819381], +["1yhq",2.4,2.71898744886575], +["1yce",2.4,2.42038950284606], +["1l1y",2.4,2.28187624622339], +["1a2v",2.4,2.89252280671592], +["1n4q",2.4,2.46755328808111], +["1yde",2.4,2.12823453642268], +["2bfg",2.4,2.98672291109963], +["1vpx",2.4,2.39089647579758], +["1yau",2.4,2.63293561159109], +["1we5",2.4,2.97299470311121], +["1rvv",2.4,2.71982490588857], +["1uzd",2.4,2.38653746322432], +["1rcx",2.4,2.50443932957493], +["1g0u",2.4,3.03396129886671], +["2a6h",2.4,4.11346731051915], +["2be5",2.4,4.13884647890237], +["1hto",2.4,2.82288651423989], +["1wtd",2.4,2.6993700946224], +["1x9g",2.41,3.22934984590424], +["1fd9",2.41,3.04370576808955], +["1x79",2.41,3.25898574496558], +["1o72",2.41,3.05820633496535], +["1wbw",2.41,2.68427738606663], +["2azm",2.41,2.22439377817517], +["2fts",2.41,2.68250430808500], +["2bhb",2.41,1.32498425017281], +["1r3l",2.41,2.32078104008042], +["1u4f",2.41,2.56602030602028], +["2bmf",2.41,3.21500786583156], +["2b3z",2.41,3.36043400846690], +["1sj2",2.41,2.79191249791563], +["1s7x",2.41,2.63355299926416], +["1t0l",2.41,2.46056628382147], +["1ykp",2.41,2.81031651745086], +["2b4a",2.42,2.38854929248149], +["1q9s",2.42,2.36579592589186], +["1syq",2.42,3.04088811175528], +["1m4u",2.42,3.5633979868545], +["1pt9",2.42,2.33233411436489], +["1q88",2.42,3.14586627651363], +["1sjs",2.42,2.16617401535787], +["1rqi",2.42,2.18306982043291], +["1pyy",2.42,2.49942150730775], +["1wy5",2.42,3.02114671309393], +["1s07",2.42,2.31990957395334], +["1ulv",2.42,2.9670073957039], +["1u3h",2.42,3.15569467371253], +["1k47",2.42,2.72049317054185], +["2cx6",2.43,2.93044369404400], +["4fua",2.43,2.67233097913930], +["1s56",2.43,3.14726713128135], +["1yqr",2.43,2.49494405099015], +["1ats",2.43,2.64638565138363], +["1e22",2.43,2.21353182127524], +["1p0q",2.43,2.58039422454046], +["1nhg",2.43,2.70447045854694], +["1jac",2.43,3.11417310795505], +["1e7h",2.43,3.33555011667203], +["1e7f",2.43,3.5766684308958], +["1kck",2.43,2.13414100255710], +["1k5s",2.43,2.09764886972569], +["1m9j",2.43,2.26209688126885], +["2be2",2.43,3.33094655434097], +["1gz5",2.43,2.85341153767742], +["1hc7",2.43,2.41185688742410], +["1dzy",2.44,3.04443040155245], +["1i3g",2.44,2.60413029142631], +["1y38",2.44,2.93122170555595], +["1o0d",2.44,3.14369220931589], +["1bjr",2.44,3.66110508157579], +["1klj",2.44,3.25942392266454], +["1qut",2.44,1.88569483837531], +["1d8m",2.44,2.26408537123617], +["1uuo",2.44,2.55208089954820], +["1h3x",2.44,3.40125366634303], +["1s2n",2.44,2.39999483931597], +["1tj7",2.44,2.53068076054832], +["2ce7",2.44,3.02973000244786], +["1ya5",2.45,3.50146628453604], +["1tc3",2.45,3.0104222454744], +["1vc7",2.45,2.57717735656942], +["1eod",2.45,2.38221621594976], +["1pp7",2.45,3.19713745272127], +["1dpy",2.45,3.02882184479481], +["1fe5",2.45,3.05576392937583], +["1nat",2.45,2.70720115689926], +["1uvx",2.45,2.88769339496409], +["1ctr",2.45,4.17969129294339], +["1c3n",2.45,2.71245714405689], +["1ib5",2.45,2.33761460766003], +["1a17",2.45,2.28221663995066], +["1p2s",2.45,2.68928522400152], +["1nx3",2.45,2.20334354832834], +["1bun",2.45,3.17204631040495], +["2buk",2.45,2.45178690950276], +["1lsp",2.45,3.09520430721435], +["2bnw",2.45,2.32333438287697], +["1m0b",2.45,2.33718902032176], +["1mrn",2.45,2.92925184319271], +["1uym",2.45,2.29872329379767], +["1q6u",2.45,2.58844896815691], +["2fd3",2.45,1.46159512997029], +["1vf4",2.45,2.32322034289321], +["1h89",2.45,3.05083850937689], +["1cl5",2.45,3.14150089829445], +["1zdf",2.45,2.12079938599130], +["1sla",2.45,2.77076230714442], +["2bzk",2.45,1.62459432926288], +["1cx4",2.45,1.92085126203380], +["1x1v",2.45,2.97871033630265], +["1v4k",2.45,3.08188520296877], +["1bqe",2.45,2.67699181886735], +["1b3y",2.45,1.82185690998266], +["2fh5",2.45,2.55457731995208], +["1n07",2.45,2.77679296776987], +["1ei7",2.45,3.26253916909833], +["1flh",2.45,2.67755895655099], +["1g05",2.45,2.44687659030375], +["1y62",2.45,1.88228903969731], +["1u8s",2.45,2.54124596029855], +["1oba",2.45,2.52477315666525], +["1xh4",2.45,2.09270298160128], +["1xag",2.45,3.04219654035598], +["2a09",2.45,3.18947844025976], +["1zb5",2.45,3.14642848272836], +["1rv6",2.45,2.80386490291923], +["2a8r",2.45,2.38439969591970], +["2a8s",2.45,2.12000959232792], +["2bs0",2.45,2.59085498012034], +["1b4x",2.45,3.35880198579331], +["20gs",2.45,3.08637144993205], +["2b2t",2.45,3.56791402881322], +["1mam",2.45,3.48388479648144], +["1jlw",2.45,3.31357168820686], +["1wsc",2.45,3.08179999243729], +["1f8w",2.45,2.04057616454524], +["2bzp",2.45,2.99724049498349], +["1lvl",2.45,3.3456154766901], +["1wvu",2.45,1.63083041851602], +["2qr2",2.45,2.33837175314986], +["1f34",2.45,2.59214694793406], +["1ep6",2.45,2.79618424588281], +["2bnf",2.45,2.80639966032501], +["1m7e",2.45,2.88119203501385], +["1dmy",2.45,2.7871171625059], +["1dmx",2.45,2.97183648200145], +["1m8n",2.45,2.80391318203794], +["1u3d",2.45,2.89182257517709], +["1i51",2.45,2.81369608138204], +["1gwq",2.45,2.42221627703233], +["1uvw",2.45,1.95385914083664], +["1a4c",2.45,2.50529699173327], +["1rkr",2.45,2.5888520683067], +["2ffj",2.45,1.68390369160644], +["1cy0",2.45,2.46307693108161], +["1vpv",2.45,1.69128322192251], +["1cy8",2.45,2.81477238497817], +["1hk8",2.45,2.33061307211737], +["1d6e",2.45,2.44407894530305], +["1d5x",2.45,3.28750608605158], +["1ej7",2.45,2.54320806051904], +["1sje",2.45,2.57320942028782], +["1f05",2.45,2.13524048167182], +["1pvw",2.45,2.61231554415903], +["1pa6",2.45,2.50802515898168], +["1m18",2.45,2.44246209037594], +["2bo6",2.45,2.69631896211221], +["2vub",2.45,2.60875259629698], +["1v4n",2.45,2.85984205812816], +["2fkw",2.45,3.08629836362439], +["1o2b",2.45,2.33871990924526], +["1fl3",2.45,3.36048710292249], +["1suw",2.45,2.95850986806760], +["1q84",2.45,2.10965967087332], +["1djw",2.45,3.31900270700833], +["1knz",2.45,2.94857236868327], +["1fdy",2.45,2.91528707784114], +["1nmt",2.45,2.86278549774914], +["2prc",2.45,2.64003863836747], +["2f6i",2.45,2.71159091067312], +["1mwr",2.45,3.11474348991476], +["1mwt",2.45,2.71592820584407], +["1re3",2.45,2.87545553735478], +["1n80",2.45,3.18679155009522], +["3dbv",2.45,2.78893310010444], +["1j0e",2.45,3.05717090621705], +["1njj",2.45,3.26756532219162], +["1aqd",2.45,2.64166843391046], +["1rxx",2.45,2.89125201031819], +["1g5x",2.45,3.18029732334575], +["1qpr",2.45,2.81861593992105], +["1qpq",2.45,2.75702119883595], +["1nd0",2.45,2.71933572340139], +["1gq7",2.45,1.99588359055534], +["1uvk",2.45,2.69624639334985], +["2byr",2.45,1.92751253237418], +["2fvm",2.45,1.90851900785856], +["1upc",2.45,1.88708910941222], +["1nzx",2.45,1.84120084034387], +["1nzz",2.45,2.04715404039277], +["2f1l",2.46,1.69283990358610], +["2blg",2.46,2.99606142882328], +["1rrc",2.46,3.02440433891302], +["1w05",2.46,2.57163669984144], +["1xha",2.46,2.37873813237885], +["1sfn",2.46,3.12029521285148], +["1lpb",2.46,2.98000108509994], +["2arh",2.46,3.18468521951606], +["1ckj",2.46,2.72167192582243], +["2ajr",2.46,1.88814947499925], +["2av8",2.46,2.71156299297156], +["1fcm",2.46,3.07805810450934], +["2ske",2.46,3.19345221912325], +["1q95",2.46,3.07292064777629], +["2gm3",2.46,2.30673267622456], +["1ewd",2.46,2.96768233306056], +["1s3o",2.47,3.56291770860583], +["1d0m",2.47,1.84251855414780], +["1xh7",2.47,2.0167058779571], +["1t7d",2.47,3.0535053689727], +["1s9a",2.47,3.18187139635913], +["1mbz",2.47,3.10606802129051], +["1ps7",2.47,3.20497470236364], +["1c5f",2.47,2.48955394610848], +["1g1a",2.47,2.73453244930981], +["1pkr",2.48,3.68330200275561], +["2bmm",2.48,3.20605041841863], +["1qcd",2.48,2.05383864507692], +["1xko",2.48,3.24101196939002], +["2alr",2.48,2.93098360375314], +["1ygb",2.48,3.68586504021554], +["1y8o",2.48,2.38304573720879], +["1h7t",2.48,2.20465111239967], +["1e7y",2.48,2.29353506166952], +["1fn3",2.48,4.37047223517252], +["2aov",2.48,2.60300469283037], +["1eo7",2.48,3.20480182419757], +["1e9i",2.48,2.82038493154515], +["2fn6",2.48,2.71495192405116], +["1ydw",2.49,3.2374195342932], +["2fpn",2.49,3.5178378783728], +["1ejf",2.49,2.41103806491711], +["2a5x",2.49,2.24066946203772], +["1sve",2.49,2.33499210787211], +["2fif",2.49,2.24221472970948], +["1hkz",2.49,2.56531183698589], +["1v47",2.49,2.81754173704415], +["1vr0",2.49,2.18355723736894], +["1u3t",2.49,2.68010643022894], +["1tkd",2.49,2.73097738436725], +["1f52",2.49,3.34615723480870], +["2b5o",2.5,2.17553820566919], +["2plh",2.5,3.19980248599595], +["4ovo",2.5,3.31889108377543], +["1w5h",2.5,3.04194632424338], +["1pi2",2.5,3.24922660042115], +["1uo1",2.5,3.72520456965212], +["1t3j",2.5,2.38310842750335], +["1rmr",2.5,2.89247233133259], +["1b7k",2.5,2.44591763563102], +["1b07",2.5,1.82406958846767], +["1dhg",2.5,2.0212314760152], +["1ckt",2.5,3.26149407142819], +["1lr9",2.5,2.28854598809958], +["1skn",2.5,3.90844233885151], +["1wk2",2.5,2.76819964536785], +["1cc5",2.5,4.3903233995543], +["1zx3",2.5,2.74290899068999], +["1fyk",2.5,2.13802433032423], +["1o51",2.5,1.81655036070027], +["1q09",2.5,2.35767778761727], +["1lxe",2.5,2.65971855737184], +["1uva",2.5,3.46099735663048], +["1qys",2.5,3.18768427867313], +["2ins",2.5,3.58960141561936], +["1vc0",2.5,2.52118711574180], +["1jca",2.5,1.43301269349174], +["1t2t",2.5,3.00161709833732], +["1b9e",2.5,2.86675834458329], +["1iza",2.5,3.62969692407591], +["1jwo",2.5,4.42768570728298], +["4fxc",2.5,3.88518362372203], +["1mft",2.5,2.90129625171368], +["1ytj",2.5,2.22519027057394], +["2az9",2.5,3.01080126561556], +["1z9w",2.5,2.7204389097935], +["1frx",2.5,2.57954065314688], +["1bik",2.5,2.74832315891185], +["1g96",2.5,2.89598568682214], +["1jsg",2.5,3.09309968999983], +["1rn7",2.5,2.38280501804361], +["1yat",2.5,2.64269722795822], +["1ubd",2.5,3.82102301609856], +["1j3e",2.5,3.28691361520783], +["1pbk",2.5,2.49347642443779], +["1zns",2.5,3.21431595202986], +["1dp8",2.5,2.76100117600727], +["1aoj",2.5,3.89519340270596], +["1cdt",2.5,3.79841087694777], +["1gd6",2.5,2.82244571653448], +["1c7h",2.5,3.33188292561192], +["1rsd",2.5,1.56426805578375], +["1pdn",2.5,2.58129007757297], +["155c",2.5,4.96770716758293], +["4fit",2.5,3.02900258108676], +["1per",2.5,3.27972629995167], +["1rpe",2.5,3.79765431439269], +["2or1",2.5,4.39936597846585], +["1rtb",2.5,3.76688357177575], +["1rta",2.5,3.74999603190913], +["2acg",2.5,3.18441090765050], +["1prq",2.5,2.80981608193125], +["1yrn",2.5,3.15195629673764], +["1akh",2.5,3.57010326669384], +["2ft9",2.5,2.45137242822764], +["1p6p",2.5,3.25195128011809], +["1qd0",2.5,2.994519848417], +["2bfh",2.5,3.09233143083267], +["3cro",2.5,4.22707481186519], +["1mpu",2.5,3.55845359912584], +["3lz2",2.5,3.64636689361187], +["8lyz",2.5,3.56168891069639], +["7lyz",2.5,3.72905778325132], +["2eql",2.5,3.24022655302728], +["1w08",2.5,2.7640743155113], +["1pf5",2.5,2.68242447951134], +["1alb",2.5,2.46569555368559], +["1hlv",2.5,2.81697275883358], +["1dcf",2.5,2.07347265102153], +["1f7r",2.5,2.79006380224563], +["6pax",2.5,2.81594930995652], +["2spt",2.5,4.02331714396609], +["1xbs",2.5,2.93343580693754], +["1z91",2.5,3.34475251497469], +["1eks",2.5,3.14889922746256], +["1zme",2.5,3.07368228755954], +["1jon",2.5,2.45168617822842], +["1hus",2.5,3.29988835782983], +["1le4",2.5,3.03407330587168], +["2hip",2.5,3.51445233416077], +["1hup",2.5,2.09836336179503], +["1af3",2.5,2.59151736247206], +["1r14",2.5,2.60648009814999], +["2a0j",2.5,2.84392107929589], +["2abx",2.5,5.14170890781682], +["1ec5",2.5,3.74845060187132], +["2hap",2.5,3.58653096523467], +["1b34",2.5,3.15295764124699], +["1z3d",2.5,2.48171770321586], +["1z2m",2.5,2.65944068054512], +["1mbs",2.5,5.12989769990527], +["2gpr",2.5,3.73920318366081], +["1u3l",2.5,2.52209650761189], +["1u2q",2.5,2.53101223235296], +["2c4v",2.5,2.68018830253451], +["1hlb",2.5,3.40435347060644], +["1r4o",2.5,3.91815764702978], +["2ao4",2.5,2.96191584518922], +["7dfr",2.5,3.83409816019158], +["1cyw",2.5,2.95334470203953], +["1b0o",2.5,3.85605920696641], +["1c68",2.5,3.11477457973278], +["171l",2.5,4.16003742214707], +["231l",2.5,2.90865023925597], +["1qtc",2.5,3.21965763420256], +["1qs5",2.5,3.59777172472722], +["1qtd",2.5,4.03179654590887], +["2agc",2.5,3.36543380865536], +["1eh8",2.5,2.5226470632506], +["1tie",2.5,2.19201119564424], +["189l",2.5,4.0665019352818], +["1u3g",2.5,3.25087654490106], +["1bxw",2.5,3.52669753359881], +["1jan",2.5,2.89689269331716], +["1gnq",2.5,3.5474731544701], +["1z6i",2.5,2.19159951801002], +["2b71",2.5,2.23772221498547], +["1t5y",2.5,2.87857205141600], +["1ws6",2.5,3.17545039115322], +["1nni",2.5,3.08433278903230], +["1lck",2.5,3.44055478913941], +["1e4j",2.5,1.82191137548984], +["1m27",2.5,2.03028031988686], +["1yha",2.5,3.66716346514227], +["261l",2.5,3.52046206695112], +["1iiu",2.5,3.20471945658536], +["1mqa",2.5,3.08698735158522], +["1brp",2.5,3.62730491898778], +["1brq",2.5,3.95332976900401], +["1qhx",2.5,2.30024944874479], +["1wdf",2.5,3.22783464696723], +["1cdj",2.5,4.05678707424975], +["1hnf",2.5,3.05815437979777], +["1znz",2.5,2.04886713578906], +["1z8f",2.5,1.90716368240065], +["1hjp",2.5,3.12911274661701], +["1rtv",2.5,3.09805920475054], +["1j9a",2.5,3.34225594377274], +["1n9z",2.5,3.44848208895382], +["1j42",2.5,2.80591222740313], +["1r6k",2.5,2.80599328032634], +["1hgu",2.5,4.30371929957456], +["1u70",2.5,3.3118142321805], +["1s3u",2.5,2.98098436723544], +["1cmi",2.5,2.76919818214321], +["1dtp",2.5,3.48994723223755], +["3ygs",2.5,2.63830305953864], +["3psr",2.5,3.12377890266835], +["1uly",2.5,2.75911084710728], +["1l9g",2.5,2.65215370565708], +["1k4j",2.5,2.54120286289302], +["1c81",2.5,2.97143793716847], +["2bfr",2.5,1.75337602188105], +["1qpi",2.5,3.12920030632667], +["3upj",2.5,2.39613710913758], +["1fxa",2.5,2.64832506208566], +["1nz6",2.5,2.30208504313346], +["1xbn",2.5,4.02010060193849], +["1lay",2.5,3.28368566948202], +["1hpo",2.5,2.43443214251729], +["1bdq",2.5,2.7299063184015], +["2trt",2.5,2.57658790460295], +["2bpz",2.5,2.00502497571895], +["3aid",2.5,2.64621320679285], +["1siv",2.5,2.94792004888963], +["1aaq",2.5,2.72010059026963], +["1hsi",2.5,3.17468805153977], +["1d4s",2.5,3.03435710654713], +["1sh9",2.5,2.93528369915137], +["1c6y",2.5,2.54909267246326], +["1c6x",2.5,2.70113653761306], +["1c6z",2.5,3.10576669577892], +["8hvp",2.5,3.59105390295475], +["1mtb",2.5,2.4677933965576], +["1ivp",2.5,3.35386856487156], +["1a8g",2.5,2.68026224568054], +["1jld",2.5,3.20936963526758], +["1bdt",2.5,2.96897697236825], +["1j0w",2.5,3.22090837383603], +["1m5m",2.5,3.14808684488359], +["1qg2",2.5,2.45671885072309], +["1pmt",2.5,3.43665668148747], +["1jnx",2.5,3.47788920293207], +["1eu4",2.5,2.11914934092626], +["1f97",2.5,1.43021529028650], +["3cd2",2.5,3.37441979231599], +["1vh6",2.5,2.19637531271364], +["1wwa",2.5,3.41414115662780], +["1cde",2.5,3.01209924592445], +["1umu",2.5,2.76106761116484], +["1zzy",2.5,2.34115209783863], +["1psp",2.5,3.16110419751849], +["2euc",2.5,3.60508338062345], +["2a8e",2.5,2.26006599128154], +["1bmc",2.5,3.35036465744717], +["1xwm",2.5,3.55500444164034], +["1bqi",2.5,3.29879390954666], +["1qpf",2.5,2.49550871654270], +["1cia",2.5,2.23426626110322], +["1qva",2.5,2.80797312380109], +["1p59",2.5,2.42014548499754], +["1r5a",2.5,3.17305503427562], +["1bgq",2.5,2.99270550505664], +["1a4h",2.5,3.12413835691846], +["1kku",2.5,3.0721436850047], +["1yk7",2.5,2.29767608096873], +["1au3",2.5,3.19215113261888], +["1ua5",2.5,2.51187050760071], +["1qxa",2.5,2.93293794546203], +["1tjd",2.5,2.61017803346972], +["2g6d",2.5,2.51545800104548], +["1xb7",2.5,1.88470381930337], +["1jjh",2.5,2.30888575382019], +["1jud",2.5,2.36986592952301], +["1uef",2.5,3.11950415332623], +["1eme",2.5,2.74795616890057], +["1y98",2.5,3.30826897782356], +["1qh9",2.5,2.66600028099389], +["1xa9",2.5,3.50784450140545], +["1cv7",2.5,3.65766851217295], +["1k1l",2.5,2.14860573687062], +["1ks4",2.5,2.77213458043108], +["1g62",2.5,2.64074845750214], +["1chg",2.5,4.12519490808297], +["1dze",2.5,3.12285155696807], +["1fy1",2.5,3.08031929095732], +["1ue1",2.5,3.30794486607632], +["1csk",2.5,3.07454222338223], +["1ljm",2.5,2.65342817710739], +["1b88",2.5,3.41292447366327], +["1iw9",2.5,2.73022102464354], +["1x0s",2.5,2.84542898730106], +["1z35",2.5,2.63032560092341], +["1z38",2.5,2.64408992187256], +["1f4k",2.5,2.92122510065387], +["1qm8",2.5,3.31838659699213], +["2bfv",2.5,2.95473682822692], +["1re1",2.5,1.89452019194398], +["1j0r",2.5,2.90579534703155], +["1c2r",2.5,2.75851093756020], +["1z1a",2.5,2.7111626853053], +["1ggv",2.5,2.22264058631275], +["1pvt",2.5,3.45682258388426], +["1gne",2.5,3.62667773449738], +["1pau",2.5,1.9127582096691], +["1rhk",2.5,1.7613197985875], +["1p9p",2.5,2.85817430109699], +["1cr4",2.5,3.26150209734602], +["1lzw",2.5,3.40632292274056], +["1gnz",2.5,3.2468121088126], +["1hdr",2.5,2.84071586786550], +["3ink",2.5,3.24339632718408], +["1est",2.5,2.54670647786441], +["1pc9",2.5,2.47979796756655], +["1zqx",2.5,3.58710780308600], +["2a1x",2.5,2.50499250065455], +["1xhe",2.5,2.87423333550473], +["2est",2.5,2.63182003279584], +["1pp2",2.5,3.3240587960344], +["1q07",2.5,2.20727372988102], +["1dpb",2.5,2.37451945342431], +["1msp",2.5,3.6618392663592], +["1adw",2.5,2.40705291514617], +["1u2s",2.5,2.58525988157772], +["1u5o",2.5,2.92922302120969], +["2aru",2.5,2.90706892356326], +["1jhe",2.5,2.90865988901112], +["1nrf",2.5,2.75665677661211], +["1hno",2.5,2.54647318136489], +["1rbb",2.5,4.14762059205251], +["1r5d",2.5,2.58976334745711], +["1y8c",2.5,2.95179310097689], +["1wdx",2.5,2.09352732784985], +["1xzx",2.5,2.7800166522164], +["1e3r",2.5,3.26251248331988], +["1juk",2.5,2.7081556976037], +["1fhx",2.5,2.79366617721902], +["1quu",2.5,3.43968676378854], +["1zdu",2.5,2.45627341765121], +["2dcd",2.5,2.78103513387201], +["1nav",2.5,2.71113695698276], +["1nf1",2.5,3.50346655132976], +["1wvc",2.5,3.77825205970808], +["1ri1",2.5,2.56082351543004], +["1ri3",2.5,2.8879656749186], +["2fp3",2.5,3.34868251324134], +["2frh",2.5,3.63102543479303], +["6ca2",2.5,2.72642205509552], +["1gaj",2.5,2.98457019255423], +["1raj",2.5,1.87211514839241], +["1bmq",2.5,3.43093266314483], +["1s0z",2.5,2.05692284418747], +["1jaf",2.5,1.93789718531143], +["1pt3",2.5,3.03155829291052], +["1yok",2.5,2.76865081631188], +["2cfv",2.5,2.75438838933012], +["2hnt",2.5,4.17894280654503], +["1i31",2.5,2.96898548304388], +["1ilz",2.5,2.67790816675342], +["1zsa",2.5,2.56977997175000], +["1c3a",2.5,3.193684754648], +["1m61",2.5,3.11376548490463], +["1kzu",2.5,2.85046779168400], +["1usw",2.5,3.43326670337884], +["2cnd",2.5,3.32940283957368], +["2ans",2.5,2.23617740985165], +["1qrh",2.5,2.91604744170443], +["1qps",2.5,3.16411204647613], +["2cgu",2.5,3.02410735370285], +["1imf",2.5,2.55181231458943], +["1a0p",2.5,3.56931321462844], +["1yi3",2.5,2.69171639652944], +["1p2a",2.5,2.85199614512565], +["1yyp",2.5,2.75401742944104], +["1uvt",2.5,2.60139083642295], +["1br5",2.5,3.19912358504923], +["1gzn",2.5,3.71032350209358], +["1vhi",2.5,2.83979030581468], +["1rpu",2.5,2.63774451567611], +["1drj",2.5,2.27470812204050], +["1rw4",2.5,3.33551824448635], +["1ewa",2.5,2.25354822054794], +["1mjb",2.5,2.62026161930738], +["1mj9",2.5,2.66385285486710], +["1sbc",2.5,3.97961492217567], +["1sbt",2.5,4.08641701501159], +["1a06",2.5,2.78604473179228], +["1je6",2.5,3.22914581555171], +["1uu8",2.5,2.48240857060902], +["1brc",2.5,2.44918109961021], +["1k0f",2.5,3.99228530593414], +["1g93",2.5,3.33968010037885], +["2bmy",2.5,2.51336220833240], +["1d8l",2.5,3.26733258802671], +["1yts",2.5,2.56449586532121], +["1gwz",2.5,4.41655204422984], +["1eh5",2.5,2.89039769714428], +["1b02",2.5,2.82124149480394], +["1ith",2.5,2.65576238363763], +["2ffs",2.5,2.13714833503700], +["1rr6",2.5,2.70820521168125], +["1a5y",2.5,2.79411768067216], +["1q14",2.5,3.17980826560168], +["1ut4",2.5,2.21062928420426], +["1wav",2.5,3.58162154845815], +["1pfg",2.5,3.92191719472981], +["1rvw",2.5,3.44230676679692], +["1fdh",2.5,3.57717814148831], +["1td6",2.5,3.28703330828961], +["1pbx",2.5,3.12191751939509], +["2kai",2.5,3.31950235317897], +["1pxl",2.5,2.99048697052218], +["2a2f",2.5,3.10663651424590], +["1q22",2.5,2.20719013713095], +["1dm4",2.5,4.22032013635866], +["1ol5",2.5,2.52992925156755], +["4thn",2.5,3.55174672653475], +["1fpr",2.5,4.423044434545], +["1xp8",2.5,3.06094303726541], +["1pxn",2.5,3.18863195810452], +["1rhd",2.5,4.24602619492504], +["3hat",2.5,3.86152085131761], +["2csn",2.5,2.3889673386577], +["1ett",2.5,3.55752643811473], +["1f42",2.5,2.21947736500507], +["1tmu",2.5,3.14618748721879], +["1jwt",2.5,3.60551779023587], +["2lkf",2.5,2.72209649829229], +["1gr1",2.5,2.15096333718858], +["1nkn",2.5,2.48644782723694], +["1aua",2.5,3.06697220363862], +["1l8g",2.5,2.79909941127320], +["1kak",2.5,2.9362530406586], +["1om9",2.5,2.60055644475100], +["1xbo",2.5,2.07401903202673], +["1f0o",2.5,2.52854741317080], +["2afc",2.5,2.77478979994082], +["2f9d",2.5,2.61735802090521], +["3por",2.5,2.77873184374785], +["1u0c",2.5,3.21622003517803], +["1pmb",2.5,3.48976803431993], +["1tiy",2.5,2.80142900379570], +["1zh6",2.5,2.49721908876958], +["1kw0",2.5,2.8099832043749], +["1ztu",2.5,2.8818014740335], +["2ac2",2.5,2.64992345109417], +["1yqk",2.5,2.73341961841223], +["1f8x",2.5,2.57393286346646], +["1uho",2.5,2.95770563659892], +["1zbx",2.5,2.69921143495774], +["1yqm",2.5,2.53350446859309], +["1efn",2.5,2.90219241037243], +["1fph",2.5,3.18438920079833], +["1twj",2.5,2.78758486967029], +["2ren",2.5,3.74691671506148], +["1tyb",2.5,2.36598979522028], +["1tyc",2.5,2.52489056036957], +["1tyd",2.5,2.42889982919454], +["1gye",2.5,2.60433761988888], +["1utz",2.5,2.32220844636260], +["1tdr",2.5,3.48372976256005], +["1nja",2.5,3.02468439698462], +["1jmf",2.5,2.85791938290295], +["1vzb",2.5,3.52126096480206], +["2g89",2.5,3.26298469983129], +["1vza",2.5,3.62103098268498], +["1lce",2.5,3.75351516869492], +["1vzc",2.5,3.75538711566671], +["1lcb",2.5,4.10244779968649], +["1njc",2.5,2.65213616122501], +["1jmh",2.5,2.88309353291572], +["1tsl",2.5,2.87684888577177], +["1tsx",2.5,2.92900474880255], +["1jmi",2.5,2.97224545652363], +["1cl0",2.5,2.6428896164376], +["1lbt",2.5,1.8851859362606], +["3pbh",2.5,3.32495930214229], +["1p5j",2.5,2.77299047843436], +["1b6b",2.5,2.99043676371780], +["2g36",2.5,1.94051299305251], +["1ko4",2.5,2.71306165481109], +["1vdc",2.5,2.56005370413828], +["1btg",2.5,3.46426883580906], +["1xex",2.5,3.01774526540444], +["1ba7",2.5,2.82955833924287], +["1zh1",2.5,2.79151884795502], +["1lio",2.5,4.79711232733018], +["1qnv",2.5,3.66141588606769], +["1u3f",2.5,2.75318627605846], +["1b8u",2.5,2.92572328032598], +["4apr",2.5,1.9658658749138], +["1hmy",2.5,3.23718234083588], +["1kv1",2.5,3.19831183760152], +["1yzu",2.5,2.60856994454721], +["6apr",2.5,1.82363739708577], +["1fj6",2.5,2.75860560035648], +["1f4o",2.5,2.73149802683918], +["1nw3",2.5,2.41362971406521], +["1s3m",2.5,3.31671004742481], +["1s3n",2.5,3.41986316140367], +["1b3e",2.5,2.72434366843444], +["1z73",2.5,2.70331697996375], +["1szb",2.5,2.99298700514332], +["1pjk",2.5,2.30424018484170], +["1zen",2.5,3.45541168169408], +["1bt3",2.5,2.86530882761559], +["1x72",2.5,2.71278741203326], +["1dxh",2.5,2.73984019906705], +["1r00",2.5,2.40456118656945], +["1j72",2.5,3.70586249159075], +["1czg",2.5,1.51596534600155], +["1w58",2.5,3.23322980128254], +["1p1g",2.5,2.22607637755574], +["1ca7",2.5,2.50402124563655], +["1qpz",2.5,3.51678050520069], +["1jft",2.5,3.62042613984245], +["1sb9",2.5,2.15972646003939], +["1biw",2.5,2.84690999269796], +["1zap",2.5,2.95691587371878], +["1vrl",2.5,2.80407634900498], +["4cpa",2.5,3.88277061992746], +["2bqu",2.5,2.79903993390243], +["1ylf",2.5,2.14481283788917], +["2axp",2.5,3.11716898343662], +["1nk1",2.5,3.735708169703], +["1pmv",2.5,2.82720918077932], +["1oyu",2.5,3.635175005662], +["1n1g",2.5,1.96590119274944], +["1m67",2.5,2.76919474761083], +["262l",2.5,3.62005266648965], +["1l2f",2.5,3.46912580241969], +["1hex",2.5,2.40896388308241], +["1sdn",2.5,2.43317994152070], +["1x94",2.5,2.67046423361813], +["1ic4",2.5,2.82477698074661], +["1nvg",2.5,2.66131384061224], +["1ubv",2.5,4.08030665809018], +["1ubw",2.5,4.05183597730136], +["1ubx",2.5,4.28918785216797], +["1h2m",2.5,1.99586397191173], +["2b9i",2.5,2.9239962967363], +["1uml",2.5,3.03490064299737], +["1wxy",2.5,3.47119605734629], +["1v78",2.5,3.56623242119645], +["1v79",2.5,3.5753147720738], +["1v7a",2.5,3.64081961129308], +["1g2x",2.5,2.76384809478578], +["1tvo",2.5,3.12524228105866], +["1wzy",2.5,3.44825965005324], +["1bl7",2.5,3.14778202546639], +["1bl6",2.5,3.22049736907516], +["1a9u",2.5,3.26590151210209], +["1jej",2.5,2.55723477919544], +["1jiu",2.5,3.10737467409261], +["1w83",2.5,2.62288317871985], +["1i9a",2.5,3.04388279731581], +["1r3u",2.5,2.93882368759333], +["1hdm",2.5,2.73893827430692], +["2ncd",2.5,3.50510691256114], +["1mji",2.5,3.370660596958], +["2f6s",2.5,2.21517401582062], +["2bu8",2.5,2.88105225729436], +["6jdw",2.5,2.36998977816596], +["9jdw",2.5,2.58413654375766], +["4jdw",2.5,2.83912059196672], +["1a1r",2.5,2.71330185522454], +["1p51",2.5,2.1885994235019], +["2g8z",2.5,3.05580775372711], +["1t3u",2.5,2.67709293277115], +["2ai9",2.5,2.83512316350378], +["1ytf",2.5,2.58039077943433], +["1xbr",2.5,2.65041172312801], +["1xip",2.5,3.19960363578214], +["1uun",2.5,2.77949801704166], +["1n3x",2.5,2.3769902005506], +["1fbl",2.5,3.16345152173673], +["2c5s",2.5,2.22673081666719], +["2alz",2.5,3.42012111589535], +["1htm",2.5,3.43281072627087], +["1zmg",2.5,2.70239884820619], +["1mkg",2.5,2.97972796414747], +["1vpf",2.5,2.73850274097675], +["1jvx",2.5,3.23803131908287], +["1c3s",2.5,3.17192190087898], +["1e9l",2.5,3.56579775029036], +["1p9r",2.5,2.78207155009681], +["1zt1",2.5,2.14553147221081], +["1d2p",2.5,3.14365817872569], +["1saz",2.5,2.77264470083432], +["1onl",2.5,2.64085534190697], +["1vac",2.5,2.31477707647220], +["2vab",2.5,1.83539432608017], +["1o5t",2.5,3.2176145675849], +["1vad",2.5,1.90397092863652], +["1a4r",2.5,3.63262612712419], +["2a6a",2.5,2.20581318732509], +["2bnn",2.5,2.32572679341098], +["1s9x",2.5,2.67567558700272], +["1qyi",2.5,3.00310485415572], +["1sqk",2.5,3.03667124077832], +["1a9e",2.5,2.45002341240680], +["1h0c",2.5,2.96497861808973], +["1khh",2.5,3.25220174430351], +["1p1c",2.5,3.21007510341301], +["2a6t",2.5,2.97382852305585], +["1nna",2.5,2.90558628903347], +["1rm1",2.5,2.96076744161052], +["1r9g",2.5,3.39091571057423], +["1guo",2.5,2.40701120915442], +["1b9s",2.5,3.54518001856871], +["1pbb",2.5,2.39457712241095], +["1cj3",2.5,2.11469897509491], +["1var",2.5,3.01659161853849], +["1iuv",2.5,2.59066594118617], +["1j59",2.5,3.87575500427704], +["1ase",2.5,2.93084812636846], +["1czc",2.5,2.5220849074794], +["2bng",2.5,2.47333873766771], +["2a2j",2.5,3.09168686833499], +["1gxp",2.5,3.32627714925347], +["1l6j",2.5,3.04889626705226], +["1bcr",2.5,3.07660052653608], +["1eft",2.5,2.88927283657674], +["1spr",2.5,2.98173462554226], +["1r61",2.5,2.70337960099790], +["1lcs",2.5,2.49669422963357], +["1jqg",2.5,2.4138925750932], +["1du5",2.5,2.429096975519], +["1ux5",2.5,3.16040031342099], +["1y97",2.5,2.92238545640945], +["9icd",2.5,2.69462313296010], +["3icd",2.5,2.70082149860312], +["4icd",2.5,2.74243819559173], +["8icd",2.5,2.76031252293459], +["5icd",2.5,2.90166214441512], +["1grp",2.5,2.58453345142822], +["1gro",2.5,2.63508133440881], +["1bl5",2.5,2.60389694318857], +["1idf",2.5,2.6930311457823], +["1idc",2.5,3.15129635548950], +["1ide",2.5,3.27934255416735], +["4gss",2.5,2.43507518138292], +["1gsd",2.5,1.95262222333347], +["1eyp",2.5,2.84432384709566], +["1qg4",2.5,2.33649357261558], +["1kf0",2.5,2.87394607376205], +["1yru",2.5,3.58953224270903], +["3pgk",2.5,4.99746834949942], +["1axd",2.5,2.59304296932192], +["1hmp",2.5,3.92126087179349], +["1o7f",2.5,3.06439866601079], +["1id5",2.5,3.30277600066340], +["1cje",2.5,3.13567170354234], +["1bz7",2.5,3.41947383322646], +["1pyb",2.5,3.38026684769962], +["1aup",2.5,3.67754523557033], +["1vff",2.5,3.31422936373948], +["1ck0",2.5,2.84288816823624], +["1rho",2.5,2.31808268452774], +["1at3",2.5,3.26234365026971], +["6cts",2.5,3.23123454173425], +["1bag",2.5,2.48932884942526], +["1fgn",2.5,3.08597744424562], +["1iid",2.5,3.52293387147066], +["15c8",2.5,3.29430355902875], +["1biu",2.5,1.86662073204043], +["1rih",2.5,2.78771835601284], +["1c7r",2.5,2.91423119598536], +["1cg3",2.5,2.75933053911687], +["1cg0",2.5,2.88902763648365], +["1cg1",2.5,2.87433855033485], +["1ch8",2.5,2.77266538674172], +["1cg4",2.5,3.0514444500065], +["1gim",2.5,3.01531623399826], +["1nht",2.5,3.49522476752954], +["1mf0",2.5,2.99144164683794], +["2bg8",2.5,2.48532720684373], +["1m7i",2.5,2.88063555753115], +["1g4p",2.5,2.29138605201965], +["1j4b",2.5,3.08583634229028], +["1ucb",2.5,2.80617219320025], +["1aur",2.5,2.88167243726396], +["1kcs",2.5,3.5499822964536], +["1cly",2.5,3.33350876387141], +["1iqw",2.5,3.04688620641798], +["1kc5",2.5,3.52858741107195], +["1lkz",2.5,3.03695745968386], +["1ial",2.5,2.82087005604771], +["1tcr",2.5,3.18498963116977], +["1ru9",2.5,2.45533320415405], +["1apn",2.5,2.80255899306634], +["2aab",2.5,3.11719271446903], +["1mnu",2.5,3.01817465357482], +["2bhd",2.5,1.11879850444609], +["1yyk",2.5,2.98102353600692], +["1l2u",2.5,3.37686153273184], +["1yfp",2.5,2.43515595059858], +["1q1t",2.5,2.60646606019035], +["1ikf",2.5,3.01004915977936], +["1dkf",2.5,3.24195669924218], +["1amh",2.5,2.62994402408556], +["1pjn",2.5,2.69027989637626], +["1xhb",2.5,3.18762805870002], +["1b4s",2.5,2.83514744164485], +["1jd9",2.5,2.56760677349249], +["1yhg",2.5,1.59581171358312], +["1z4x",2.5,2.68231492926062], +["1z4z",2.5,2.71458537566624], +["1mur",2.5,3.32911972671269], +["1mg1",2.5,3.63130456232939], +["1k0a",2.5,2.88367451748788], +["1fv2",2.5,3.27018117518694], +["1tn0",2.5,2.61693373115927], +["1hlk",2.5,2.64234997092758], +["1kr3",2.5,2.8579974514859], +["1o0t",2.5,2.05658840280058], +["2am1",2.5,3.1849167899332], +["2g9i",2.5,2.59218502187384], +["1rhm",2.5,2.49161164987890], +["1u3s",2.5,2.58362957613621], +["2bq0",2.5,2.2464090565812], +["1quq",2.5,3.15593486141647], +["1rc2",2.5,3.03621067555004], +["1xr6",2.5,2.33198766543074], +["3grt",2.5,3.03102122479416], +["1xiu",2.5,3.1868452456881], +["1itb",2.5,3.46530413677397], +["1te1",2.5,2.72092436106392], +["1k3z",2.5,3.36064354981442], +["1pp4",2.5,2.42091177679672], +["1vgo",2.5,2.87811450091456], +["1fl9",2.5,4.54612604581954], +["1gln",2.5,3.85757098679016], +["2pbg",2.5,3.24072401834921], +["1bqy",2.5,2.46887333044664], +["1ni0",2.5,3.42956959232415], +["1s3h",2.5,2.49650748919992], +["1vjt",2.5,2.22813175225982], +["1a35",2.5,2.9331971105397], +["1rqe",2.5,2.48921198342369], +["1pgp",2.5,2.50858535875187], +["1pgo",2.5,2.81518878678275], +["2b25",2.5,1.94165817824672], +["1ie4",2.5,2.60658156267148], +["1gke",2.5,3.46913656105960], +["1mqf",2.5,1.66183442963121], +["1e33",2.5,3.18056169760361], +["1ud6",2.5,2.07105208561253], +["1fgu",2.5,3.49295616992349], +["1snu",2.5,3.72343544779566], +["1xo1",2.5,2.02153570029720], +["1q7c",2.5,2.03735210649695], +["1u05",2.5,2.97290756850661], +["1wq1",2.5,3.07114587989859], +["2dpg",2.5,1.97364149844535], +["1h94",2.5,2.75290157995373], +["1rve",2.5,3.69235150749304], +["1osv",2.5,3.70581724193927], +["1v7y",2.5,2.98975447115597], +["1rh1",2.5,3.21252755051903], +["2bh9",2.5,3.49149428106315], +["1hk7",2.5,3.07554739900318], +["8tim",2.5,3.76217203335974], +["1tim",2.5,4.40550628780489], +["2ypi",2.5,4.39938517367201], +["1hl6",2.5,2.70910262615637], +["1zym",2.5,3.46026551162630], +["2viu",2.5,2.52310680468463], +["1vz4",2.5,2.74111407898175], +["1qma",2.5,2.59546466558182], +["1thn",2.5,3.29743595926310], +["1trd",2.5,3.54561940916557], +["1t8p",2.5,2.74012938288250], +["2f17",2.5,3.00901936780613], +["1k4y",2.5,3.28025598577146], +["7cat",2.5,3.63260942616912], +["1isf",2.5,2.52483829163579], +["1sj7",2.5,3.77688499856976], +["1b1y",2.5,3.08481108465754], +["1i4n",2.5,2.40689824072422], +["1bs5",2.5,3.02364248436041], +["1bs7",2.5,3.16732029322148], +["1tid",2.5,3.14280446993161], +["1pwz",2.5,2.76143600408917], +["2bhf",2.5,2.00862465891375], +["1zh7",2.5,3.61184575875171], +["2a91",2.5,2.71993944664955], +["1jql",2.5,3.34588090132458], +["1kny",2.5,3.62124188721590], +["1byk",2.5,2.57617696735748], +["1lmw",2.5,3.94668761777534], +["1jec",2.5,2.29142023200823], +["1fsi",2.5,3.21490440225731], +["1mvk",2.5,1.69052492710452], +["1dfg",2.5,2.96923487397840], +["1fic",2.5,2.42084936034856], +["1knu",2.5,2.68732980831695], +["1w4z",2.5,2.52387723839301], +["1jto",2.5,2.59409367408158], +["1ipf",2.5,2.65684283247275], +["1ipe",2.5,2.90770969260101], +["1b90",2.5,2.77123948272162], +["2jel",2.5,2.71614136766718], +["2c3a",2.5,2.61443469328695], +["1tww",2.5,2.45529566763258], +["1paf",2.5,2.92819363123801], +["2an5",2.5,2.13790280143368], +["1o4u",2.5,2.14562935776944], +["1qti",2.5,3.23279840114859], +["2fgi",2.5,2.34172430292265], +["1jtq",2.5,1.97290159471460], +["1vot",2.5,2.83317121743873], +["2aai",2.5,3.38719211034676], +["1gtr",2.5,2.44911912512460], +["1zjw",2.5,2.89422333922906], +["1ztx",2.5,3.11879864442066], +["1knr",2.5,3.51947058952388], +["1zwi",2.5,2.97349590504325], +["2atk",2.5,2.99968987373063], +["1h78",2.5,2.89534494080897], +["1ydm",2.5,3.26766770993413], +["1ktq",2.5,3.11808623076786], +["5ktq",2.5,3.25018803256632], +["1qih",2.5,2.55351304757581], +["1hbj",2.5,2.72226255007533], +["1eve",2.5,2.15909582748106], +["1mdf",2.5,2.95458317793582], +["2cw8",2.5,3.33590552955506], +["1dab",2.5,3.55582361825459], +["4ktq",2.5,4.07940878613087], +["1qrc",2.5,1.978432245576], +["1wom",2.5,2.89671447225440], +["1gwx",2.5,3.94578472225087], +["1fgi",2.5,1.99560503899497], +["1exn",2.5,2.66865485641628], +["1awb",2.5,2.01090321864840], +["1i4d",2.5,3.30316626130227], +["2b2c",2.5,2.94070252618003], +["1rtr",2.5,2.58180434536300], +["1m2z",2.5,3.46995195214148], +["1xse",2.5,2.80088787077836], +["1w93",2.5,3.98659981891658], +["1s5y",2.5,2.71715122935035], +["1yv2",2.5,2.73872996692802], +["1ycp",2.5,3.60548761276925], +["1gy9",2.5,3.00529986844938], +["1quv",2.5,3.63621353898107], +["1bsp",2.5,2.58720731166407], +["1d4d",2.5,3.51338629723294], +["1gzd",2.5,2.85319676600049], +["1i00",2.5,2.60921145910365], +["1ypt",2.5,2.09088882851892], +["1cy6",2.5,2.92518128455621], +["1fdl",2.5,2.89560498224525], +["1hwg",2.5,3.08312907706546], +["1o9b",2.5,3.40950123673889], +["2gh1",2.5,2.71831619004266], +["1w0y",2.5,2.67390701353912], +["1diz",2.5,2.94763941487177], +["1ji5",2.5,3.44605708368411], +["1fx3",2.5,3.44018311108656], +["1yvf",2.5,2.80261918993755], +["1bvn",2.5,3.58075882434892], +["1zc4",2.5,2.80798908594532], +["1luj",2.5,2.54935834966189], +["1v35",2.5,2.51178155248326], +["1ye0",2.5,2.97398892498219], +["1gli",2.5,2.24797934333614], +["1b86",2.5,3.4065556991278], +["1kht",2.5,2.52107232731791], +["1wqv",2.5,2.51706733068804], +["1xxv",2.5,2.31701927632778], +["1nnu",2.5,2.77623397217341], +["2seb",2.5,2.76065787027737], +["1gwv",2.5,2.42765886861552], +["1nwi",2.5,1.91246692849494], +["2aqx",2.5,2.96314981716821], +["1di1",2.5,2.48038009070377], +["1rd3",2.5,2.96791880023556], +["1ch4",2.5,2.54402329017851], +["1toq",2.5,2.47522769022142], +["1f9w",2.5,4.17248964095248], +["1dfj",2.5,3.15560125828961], +["1lsj",2.5,2.51080099864600], +["1ybh",2.5,2.18837370415813], +["1e7e",2.5,3.39051777963881], +["1bj5",2.5,3.38073698383903], +["2bxi",2.5,2.80650117624699], +["1e7g",2.5,3.40559644240601], +["2bxm",2.5,2.9080169000531], +["1d2g",2.5,3.40504302093117], +["1d2c",2.5,3.49066692636133], +["1bhj",2.5,3.78955311264922], +["1h9z",2.5,2.95826046410858], +["1ha2",2.5,2.93986982178455], +["1dlc",2.5,2.55867752810884], +["1tmq",2.5,2.7344670608572], +["1j4s",2.5,3.77335770866622], +["1cwu",2.5,2.96130556472704], +["1gv0",2.5,2.77597416132336], +["1sm4",2.5,2.86875901844932], +["1qg0",2.5,2.93011600011834], +["1fuu",2.5,3.12533809802497], +["1ku6",2.5,3.00519031271563], +["1u7w",2.5,3.16814944612291], +["1t3h",2.5,2.76075407159264], +["1krr",2.5,3.18091195985332], +["1mas",2.5,3.8211328922069], +["2ajp",2.5,2.18008889826772], +["1n3e",2.5,3.15061347090509], +["1euu",2.5,3.06966259979919], +["1eut",2.5,3.36040525600534], +["1e2p",2.5,2.62369771764263], +["1sda",2.5,2.81325307499199], +["1fo0",2.5,3.07903136699553], +["1rxv",2.5,2.86858213160308], +["1pi6",2.5,3.17429003447493], +["1t5x",2.5,2.52174091020779], +["1sdy",2.5,2.76653136905718], +["1e2j",2.5,2.61441532316168], +["1a14",2.5,3.34157088938652], +["2f6k",2.5,2.19119937349478], +["1uk4",2.5,3.180824768647], +["1kk6",2.5,2.90645996849502], +["2a19",2.5,2.86904542519439], +["4atj",2.5,2.29136724689671], +["1qhg",2.5,3.22207229444048], +["1pjr",2.5,2.89941223468723], +["1qhh",2.5,2.86651582334929], +["1wwl",2.5,3.22533202652675], +["1kps",2.5,3.14216096593094], +["1t5c",2.5,3.63034913783038], +["4ts1",2.5,2.70840834996989], +["1lth",2.5,3.26871567909246], +["1tco",2.5,3.29254689634287], +["1u26",2.5,3.1643742738197], +["1hjr",2.5,3.94084450995122], +["2bv3",2.5,2.81789554663449], +["2a2u",2.5,2.82145864786294], +["1fbp",2.5,2.82970396727983], +["1f9o",2.5,2.08047993355320], +["1szm",2.5,2.69757273579049], +["1fbh",2.5,2.50393107073852], +["2fgd",2.5,3.02522536050996], +["1ckn",2.5,2.78411878220566], +["1tcc",2.5,2.08105913171872], +["1fj9",2.5,2.69324533100115], +["1ckm",2.5,2.41579424056166], +["1e3p",2.5,2.66293664956285], +["1u4q",2.5,3.07079508950739], +["1rcw",2.5,2.17797724838576], +["1afs",2.5,2.3269203191337], +["1wnf",2.5,3.14591586310795], +["3crx",2.5,3.68257845405484], +["1g6o",2.5,2.60482321301921], +["1oyv",2.5,2.77636618395161], +["1xkj",2.5,2.14023169218436], +["2tsy",2.5,2.91193931297123], +["1zh8",2.5,1.79537106786065], +["1kmp",2.5,3.19029317284476], +["1yj6",2.5,2.61719152603436], +["1ho3",2.5,2.81624768079020], +["11as",2.5,3.51122036356797], +["1yvv",2.5,2.73988634470318], +["1ips",2.5,2.33058491661871], +["2fl6",2.5,2.45878065220619], +["2fl2",2.5,2.38625154058601], +["1yrs",2.5,2.85895634598048], +["1jm6",2.5,3.49737109595545], +["1dc3",2.5,3.20880023278425], +["1dc4",2.5,3.59306785729823], +["1p5c",2.5,2.3333241645675], +["1kb5",2.5,3.97227409229137], +["1qs8",2.5,2.29720051624721], +["1pff",2.5,2.10357502148468], +["1pnz",2.5,2.57862302016637], +["1hdg",2.5,2.70489286838917], +["1g0d",2.5,3.52371123867842], +["1phj",2.5,2.86638560154017], +["2aj9",2.5,3.15329738821467], +["4mdh",2.5,3.80993780395415], +["1bjt",2.5,2.86693425413349], +["1jw0",2.5,2.20897828881929], +["1lya",2.5,2.68185524994138], +["1aih",2.5,3.04071381626516], +["1czw",2.5,1.71959601233126], +["1rcu",2.5,3.05557195515872], +["1ph9",2.5,2.43621663663311], +["1gp9",2.5,3.44125937339027], +["1lyb",2.5,2.80839142549024], +["1ztp",2.5,2.07441903332734], +["1an9",2.5,2.87404118814344], +["1evi",2.5,3.11087073151865], +["1ve9",2.5,3.35906628545352], +["1rnr",2.5,2.36483059782253], +["1mrr",2.5,2.39650579724637], +["1n6m",2.5,3.66459103687213], +["1cyg",2.5,3.43571522661376], +["1keh",2.5,2.46540370976302], +["9cgt",2.5,2.16220790079993], +["5cgt",2.5,2.59017552355943], +["1cgu",2.5,3.11015578013216], +["4otb",2.5,2.64156292159054], +["1tw2",2.5,2.71026350937884], +["1cgv",2.5,2.50408817459076], +["1cgy",2.5,2.7230940476499], +["2cxg",2.5,2.93335025718731], +["1jdu",2.5,2.32457455311461], +["1gc8",2.5,2.63405425424981], +["1l7c",2.5,2.70727664677101], +["1sqy",2.5,2.96139467196906], +["2f4n",2.5,3.10453962545060], +["1pr5",2.5,2.93403023650155], +["1wpq",2.5,2.59411768406318], +["2fys",2.5,3.63250613065587], +["1nlm",2.5,3.06785793498123], +["1w22",2.5,3.39382176073234], +["1cs4",2.5,1.96555163705805], +["1ixy",2.5,2.57998574438014], +["1sxp",2.5,2.90199088851194], +["1jfa",2.5,2.54555464820503], +["1yyr",2.5,2.33682334397698], +["2ael",2.5,2.22204321669340], +["1z26",2.5,3.16530315286027], +["2fcp",2.5,3.0799085612789], +["1tb6",2.5,3.05068341627065], +["1jfg",2.5,2.42728424025181], +["1pk7",2.5,2.84063326913877], +["1w62",2.5,2.36838874242790], +["1f9c",2.5,2.84438518686536], +["1s5c",2.5,2.06151112478073], +["1yqx",2.5,2.81668399145767], +["1fr6",2.5,3.61283291140810], +["1t47",2.5,2.4492827222503], +["2thi",2.5,1.86953693659636], +["1o12",2.5,2.8495208712107], +["1ekp",2.5,3.03013713728812], +["1qaw",2.5,2.72432821416229], +["1htl",2.5,2.88068843545220], +["2pol",2.5,3.04077611006978], +["2csl",2.5,2.81580820686276], +["1pvh",2.5,3.14376335268059], +["1rlr",2.5,3.35535536605066], +["1qm6",2.5,2.01295078601533], +["1pcx",2.5,2.71381771328034], +["1to6",2.5,3.13730754724149], +["1hdx",2.5,2.71497592375058], +["1hdy",2.5,2.79915861774671], +["1hso",2.5,2.63646693571497], +["1ixx",2.5,2.84016303355584], +["1r5v",2.5,2.45495182885539], +["1miq",2.5,2.94894595381651], +["1e3l",2.5,2.85261061785379], +["2cv5",2.5,2.77628412018657], +["1pnm",2.5,2.44200956968093], +["1pnl",2.5,2.49763900427107], +["1cp9",2.5,2.4240796883453], +["1e2z",2.5,2.67731332989005], +["1b0k",2.5,2.6014501729028], +["1b0j",2.5,2.61560247109358], +["1b0m",2.5,3.00509066490999], +["6acn",2.5,2.81149268648345], +["2a9f",2.5,3.67065328425587], +["1hhi",2.5,2.42043313553128], +["1b0g",2.5,2.54790485206458], +["1hhk",2.5,1.85623296182476], +["1hhj",2.5,2.51727227285334], +["1h6a",2.5,2.77740124705683], +["1ai7",2.5,2.41622223568748], +["1ef2",2.5,2.34837354976814], +["1gck",2.5,2.99187786255602], +["1krb",2.5,2.1925681432422], +["1krc",2.5,2.31715765071649], +["1a5o",2.5,2.39996517009219], +["1buc",2.5,2.77158832180176], +["1jcn",2.5,3.35365248789208], +["1dg1",2.5,2.4107367427273], +["1khu",2.5,3.28333396617227], +["1ono",2.5,3.17054822634038], +["1ur0",2.5,2.78582239209681], +["1tgo",2.5,2.87999833120417], +["2ay9",2.5,2.79643057725845], +["1ay5",2.5,2.82105852122404], +["3dmr",2.5,2.07561075308176], +["1kbj",2.5,2.49501290101509], +["2b8q",2.5,2.63172860445859], +["1esq",2.5,2.73861796324793], +["2ax4",2.5,2.56156911127499], +["5xia",2.5,2.18051960071262], +["1xlh",2.5,2.12509574158808], +["1did",2.5,2.12214417058618], +["1xld",2.5,2.23696215644497], +["1xlf",2.5,2.25267761830562], +["1xlj",2.5,2.29328651441720], +["1xlb",2.5,2.18895766152774], +["1xlc",2.5,2.15567177898757], +["1xlg",2.5,2.26709813571610], +["1xll",2.5,2.42378950684408], +["1xlk",2.5,2.40463937325775], +["1xli",2.5,2.29289400688490], +["1xle",2.5,2.28059291710857], +["1die",2.5,2.43649910165990], +["1nhe",2.5,3.03653944995766], +["1vdd",2.5,3.41220778229281], +["1gn4",2.5,3.10745785095728], +["1pb6",2.5,2.98534287073843], +["1xmr",2.5,2.68189738888021], +["1lot",2.5,2.96368907039796], +["1asn",2.5,3.19300635854764], +["1ahg",2.5,4.02917344851528], +["1tk8",2.5,2.48961036007640], +["1g99",2.5,2.14253027401787], +["1tmo",2.5,2.38080821929234], +["1tuu",2.5,2.74318989985780], +["1nd2",2.5,2.37814270911715], +["1ncq",2.5,3.02963289727404], +["1e5d",2.5,3.01857796843392], +["1bd2",2.5,3.10447814101161], +["1p6n",2.5,2.91961321963579], +["1b5t",2.5,2.1528115743442], +["1kby",2.5,2.82014182274783], +["2bns",2.5,2.23200255503512], +["1yf0",2.5,2.46379587426978], +["2ap6",2.5,1.90951481587824], +["1vix",2.5,2.47503727160201], +["1yep",2.5,2.44305195547766], +["1mi5",2.5,2.95623223082689], +["1rg5",2.5,1.83293650535276], +["1npb",2.5,2.54245769485437], +["1nca",2.5,2.99198312209749], +["1ncb",2.5,3.2482762737617], +["1ncc",2.5,3.44522105051632], +["1ile",2.5,3.76691891981868], +["1bw0",2.5,2.1007419385981], +["1ybe",2.5,2.99832880900628], +["1ytu",2.5,2.92832903997346], +["1ufq",2.5,2.73342909959740], +["1a2k",2.5,2.81201489756796], +["1t6b",2.5,2.95965466378246], +["1zvl",2.5,3.2990573422324], +["1e8w",2.5,3.51650557755182], +["1sry",2.5,2.79279049142455], +["1ses",2.5,2.79448139197691], +["1xf4",2.5,2.86160122004384], +["1kzy",2.5,3.13058495934561], +["1xzw",2.5,2.92585627244688], +["1nxg",2.5,3.20325242110575], +["1t75",2.5,2.56344640422975], +["1u1z",2.5,2.92513345062007], +["4gsa",2.5,2.81202265608339], +["1p5r",2.5,2.86549087311555], +["1w47",2.5,2.80105991739988], +["2gm8",2.5,2.43202492113131], +["1cic",2.5,3.28564711907114], +["1aja",2.5,2.69272335717554], +["1adi",2.5,3.38966100359426], +["1ad0",2.5,2.32225220668430], +["1igj",2.5,3.31257329579655], +["1wcb",2.5,3.13968502321669], +["1t4k",2.5,3.23469882518479], +["2ab6",2.5,2.15961968881936], +["1ww8",2.5,2.34963621030703], +["1eqz",2.5,3.29767802976017], +["1b4a",2.5,3.37132097267976], +["2dik",2.5,3.96941678549387], +["1fvd",2.5,3.1903684457105], +["1yak",2.5,2.88498794520059], +["1njt",2.5,2.92640004306500], +["1a3g",2.5,3.5708325974452], +["1jls",2.5,3.70394440666477], +["1r4w",2.5,2.98469991444048], +["1zgr",2.5,2.83605384473924], +["1lwj",2.5,3.08332156717643], +["1we1",2.5,3.03574400861031], +["1p30",2.5,2.48198015915206], +["1kfu",2.5,3.88777228672834], +["1zgs",2.5,2.81593052724637], +["1wyz",2.5,3.21936191950763], +["5tsw",2.5,3.43192966642143], +["1khl",2.5,2.59351661574046], +["1khk",2.5,2.60752133424746], +["1kh9",2.5,2.38879906654964], +["1alh",2.5,2.05456204665071], +["1ani",2.5,2.37179385205736], +["1upu",2.5,3.50422079802336], +["1ajc",2.5,3.03589752496948], +["2fb1",2.5,2.85712412622242], +["1e8t",2.5,2.9038616217556], +["1ajb",2.5,2.40690884579969], +["1ajd",2.5,3.18083933114951], +["1dv2",2.5,3.53200615944112], +["1q1j",2.5,2.57510902431524], +["1za2",2.5,3.03629663423349], +["1bdf",2.5,3.43684970837189], +["1ep4",2.5,3.52336503778821], +["1enq",2.5,3.09061474645977], +["1g1u",2.5,3.19473186250578], +["2tpl",2.5,2.57522875561057], +["8atc",2.5,3.12953309684767], +["1l0y",2.5,2.7872829899687], +["1rai",2.5,3.16942249535092], +["1fk9",2.5,3.30407853107732], +["1gc1",2.5,3.60113948088801], +["1hm8",2.5,3.02646997369692], +["1rad",2.5,3.19877961978948], +["1rah",2.5,3.19145552032186], +["1rae",2.5,3.20032726820425], +["1raf",2.5,3.2024422963991], +["1raa",2.5,3.20855390716454], +["1rac",2.5,3.2433770567475], +["1rab",2.5,3.21128731897718], +["1rag",2.5,3.20262305961390], +["1ibv",2.5,2.81775409354405], +["1qgk",2.5,2.96861740101977], +["1eix",2.5,2.97836347126455], +["1pya",2.5,2.63675015297317], +["1k0c",2.5,2.73392237267818], +["1j3u",2.5,3.09299501225575], +["2tep",2.5,2.21848525904419], +["1v6l",2.5,2.38132282407641], +["1rvu",2.5,2.58412116203515], +["2bto",2.5,2.6739066684147], +["1u25",2.5,3.38841664518127], +["1o5i",2.5,2.64304860251104], +["1bq4",2.5,3.14022266438453], +["4pbg",2.5,2.97901877586328], +["1p8p",2.5,2.87037292599310], +["1ta1",2.5,2.66067039579004], +["1ewj",2.5,3.37574624981166], +["1jkh",2.5,3.41164579743914], +["1c1b",2.5,3.01694156811929], +["1wbl",2.5,3.06817444980664], +["1c1c",2.5,3.34578702534512], +["1jla",2.5,3.23588225286891], +["1np0",2.5,1.5785472942224], +["1h21",2.5,2.44457012404056], +["1z6l",2.5,3.21760819435995], +["1xef",2.5,2.35184765296929], +["1znp",2.5,3.03878241623922], +["2fxr",2.5,2.82144300910026], +["2fs8",2.5,2.83840107380270], +["1k0b",2.5,2.72799854416648], +["1vm8",2.5,2.52923054684733], +["1j0a",2.5,3.29752284605232], +["1txk",2.5,2.71695039813172], +["1g6w",2.5,2.80346326064139], +["1xhv",2.5,3.04246044537237], +["1w18",2.5,2.85326460613894], +["1e1e",2.5,3.24907326731024], +["1v26",2.5,1.98339698602595], +["1khv",2.5,2.91892684423591], +["1tx3",2.5,2.93149873492554], +["1e6r",2.5,2.27080062980760], +["2c66",2.5,2.28650738790959], +["2f61",2.5,2.64650029960378], +["8cat",2.5,3.77805705466536], +["1nia",2.5,2.29956044801432], +["2cv9",2.5,3.11588581761283], +["1omw",2.5,3.07407392014414], +["1d0j",2.5,2.96726132879382], +["1jey",2.5,2.52995424105756], +["1ug9",2.5,2.97748785285758], +["1b09",2.5,3.43986029183355], +["1b7y",2.5,3.66764154096317], +["1b7t",2.5,3.88690569233447], +["1q3h",2.5,2.53124765023414], +["1hcm",2.5,2.34962112981592], +["1xcg",2.5,2.95815194919882], +["1brm",2.5,3.16652315327345], +["2c0p",2.5,2.50093950625086], +["2c0q",2.5,2.58353644106702], +["1djh",2.5,3.24185596545364], +["1dji",2.5,3.1752393403673], +["2isd",2.5,3.21132240936398], +["2f73",2.5,3.37235398778879], +["1du4",2.5,2.75809433737681], +["1un8",2.5,2.86299689542131], +["1yhm",2.5,2.67239627467098], +["2f4l",2.5,2.06705472654513], +["1dxo",2.5,2.96699371736252], +["1gg5",2.5,2.9554318061998], +["1h25",2.5,3.3020521298613], +["1mox",2.5,3.18149925300289], +["1jvf",2.5,3.02681299980164], +["1vao",2.5,3.14579135442246], +["1eg7",2.5,3.42739778313498], +["2fdp",2.5,2.14459469850021], +["1e9h",2.5,3.38399431514728], +["1h1q",2.5,3.51389391947615], +["1h24",2.5,3.35905728340272], +["1k7l",2.5,3.57547043717602], +["1dqr",2.5,3.12079364113347], +["1n8t",2.5,2.71337678364809], +["1th1",2.5,1.96376734164866], +["1rld",2.5,3.37200923056181], +["1xmm",2.5,2.33060308385719], +["1lqf",2.5,3.19689482991987], +["1to0",2.5,3.00185288275607], +["1poi",2.5,2.97694629023159], +["1it8",2.5,3.20764315052627], +["1ao6",2.5,2.92492396334149], +["1bm0",2.5,3.12518765723933], +["1iz1",2.5,2.50641539192696], +["1pow",2.5,1.49486394212878], +["1dii",2.5,2.10405609333464], +["1q6x",2.5,2.32913882407654], +["1mda",2.5,4.16163545344311], +["1oz0",2.5,3.00217381088867], +["1k5h",2.5,3.13549263029760], +["1gv1",2.5,3.04334235713861], +["1dm0",2.5,3.62507054178262], +["1zi7",2.5,2.63717883902089], +["1oat",2.5,2.74616742477727], +["1xjg",2.5,3.03378777725029], +["1fiq",2.5,2.71955669831730], +["1esm",2.5,3.51328779596906], +["1r4q",2.5,3.04449164878945], +["1nmc",2.5,2.72777442266088], +["1cjy",2.5,3.17060175165172], +["1ms0",2.5,2.50168941797406], +["1ie3",2.5,2.7120067148511], +["1ezr",2.5,3.42819388415616], +["1qyd",2.5,3.58388933792491], +["1muk",2.5,2.77196657081505], +["1mwh",2.5,2.98467513052462], +["4fbp",2.5,2.65960781582259], +["1n35",2.5,2.80070466783997], +["1k9i",2.5,2.76864346387966], +["2b81",2.5,2.50682047120423], +["1d7a",2.5,1.78217069113648], +["1iw8",2.5,2.57528733387378], +["1efu",2.5,2.62215330561215], +["1i1e",2.5,2.6213875440048], +["1cu1",2.5,3.27655588951594], +["1rqx",2.5,2.30386391128944], +["1cer",2.5,2.80385704122088], +["2pva",2.5,3.07138638637501], +["1cli",2.5,2.91587400758629], +["1znq",2.5,2.56843326087455], +["2b4t",2.5,2.13310799112898], +["1hi8",2.5,3.53296217598798], +["4dbv",2.5,2.34071050928445], +["1dbv",2.5,2.44395418681297], +["2gd1",2.5,2.80775026377621], +["1f76",2.5,2.52698999479296], +["1gk0",2.5,2.46497326741919], +["1scu",2.5,4.41545401974274], +["1r3h",2.5,4.05151474679595], +["1lrw",2.5,3.05124961818161], +["1x9y",2.5,2.71947344712209], +["1xdp",2.5,3.20989954548857], +["1kqo",2.5,2.80318700774672], +["1uyr",2.5,2.9739962825589], +["1zcc",2.5,3.24666457259868], +["1b6s",2.5,3.32559222966083], +["1qrk",2.5,3.27774809389682], +["1ggy",2.5,3.27567741634577], +["1ykf",2.5,2.34028336020963], +["1fie",2.5,3.33661725469798], +["2ggj",2.5,2.44503372189788], +["1nwt",2.5,2.4362995944989], +["1rvt",2.5,2.97566414698098], +["1rv0",2.5,3.11218506610178], +["1n1m",2.5,3.25322791948627], +["1nu8",2.5,3.19967609440462], +["1d0n",2.5,3.09532939955544], +["1olp",2.5,2.24018123582784], +["1g7y",2.5,2.93845624727972], +["1f6d",2.5,3.0248376095017], +["1d1s",2.5,2.47351283541580], +["1gtn",2.5,2.36142764487463], +["1sj9",2.5,4.0049711748899], +["1axg",2.5,2.67913139972224], +["1lde",2.5,2.36909004545367], +["1ldy",2.5,2.47004281486421], +["2awa",2.5,1.77529135978306], +["1umy",2.5,3.56407269394159], +["1k3f",2.5,4.019094328995], +["1sos",2.5,2.73728275742779], +["1rg9",2.5,3.58503415788453], +["1p7l",2.5,3.63197947719766], +["1wbb",2.5,2.34723024079180], +["1z6z",2.5,1.68926075976830], +["1dub",2.5,2.43297884528961], +["1wuu",2.5,3.89478380263694], +["1cg2",2.5,2.02370134804061], +["1jpw",2.5,3.32254761863261], +["6xim",2.5,2.08635376980297], +["1r8w",2.5,2.46507759873649], +["1jnz",2.5,2.1971459628485], +["1lnu",2.5,3.80931796432742], +["2aw5",2.5,2.53932904070991], +["2aci",2.5,3.43804964974127], +["1dv3",2.5,2.42108510078579], +["1dv6",2.5,2.50613221807453], +["1ds8",2.5,2.48649094066153], +["1oqe",2.5,3.39030655649937], +["13pk",2.5,3.05689934848170], +["1eoh",2.5,2.99284434425007], +["1pg7",2.5,2.59781981878106], +["1mmf",2.5,3.22969680918589], +["1m2o",2.5,2.97855055941401], +["1vdm",2.5,2.58163470977264], +["2c4u",2.5,2.30854655762638], +["1a0c",2.5,2.12986960579165], +["1gu6",2.5,2.82398001853174], +["1pku",2.5,3.039569398895], +["5cev",2.5,2.17103579980297], +["1i0a",2.5,2.56373379554386], +["1auw",2.5,2.35159946075748], +["1w0m",2.5,2.76397825118084], +["1u15",2.5,2.66532243481694], +["1gz0",2.5,3.07523317539809], +["1knx",2.5,2.90052217479700], +["1m3e",2.5,2.85139187302688], +["1qi6",2.5,1.98481592506710], +["1t90",2.5,2.8175574412728], +["1g63",2.5,2.68051728775], +["1i4k",2.5,2.94610949869256], +["1ofh",2.5,3.21429959104025], +["1y5l",2.5,2.58281922089855], +["1ecj",2.5,2.55581908192954], +["1y5n",2.5,2.66539073138032], +["1ekm",2.5,2.74247571730383], +["1fp4",2.5,2.54946479798427], +["1v4g",2.5,2.50082257947855], +["1eyy",2.5,1.74738668497928], +["1uyt",2.5,3.01918953076267], +["1uv6",2.5,2.25784214216582], +["1uij",2.5,3.37474595951964], +["1p84",2.5,2.83712633786445], +["1wdk",2.5,2.70619536579293], +["1jb0",2.5,2.90275543123035], +["2gb3",2.5,1.40401085357630], +["2fjc",2.5,2.69281690820048], +["1bvu",2.5,3.76137651661825], +["1smk",2.5,2.51894155930095], +["1ldn",2.5,3.93600164763304], +["1pd5",2.5,3.28015305766400], +["1k9a",2.5,3.11556595227287], +["1vg9",2.5,2.84585422378322], +["2req",2.5,2.53488109105274], +["1rfm",2.5,2.85703228915768], +["2bm8",2.5,2.52655001219870], +["1jof",2.5,2.68197318850654], +["2buc",2.5,2.56989483254534], +["1e1r",2.5,2.81858743029493], +["1c7o",2.5,2.54585389600104], +["2ak4",2.5,2.07767389674189], +["1noi",2.5,3.24929127668103], +["1fui",2.5,2.46260238831792], +["1hr6",2.5,2.65070453982495], +["1vq7",2.5,2.87761182514604], +["1l2a",2.5,2.42120856968082], +["1e9s",2.5,2.9443386371176], +["1gyt",2.5,2.65459298310921], +["1qo5",2.5,3.53535089036429], +["2a68",2.5,4.12477742965083], +["2a69",2.5,4.14357113296441], +["1w4c",2.5,2.79087975953898], +["1gho",2.5,2.94774791984232], +["1f49",2.5,2.9537023345654], +["1bgl",2.5,3.7734118056332], +["1bgm",2.5,3.95366147627612], +["1gq2",2.5,2.9459652612634], +["1y8g",2.5,2.79974205104617], +["1txt",2.5,2.80725267448981], +["1x8s",2.5,2.22953376339504], +["2a9b",2.5,2.21276050376476], +["1xi8",2.5,2.00462614176668], +["2a9c",2.51,2.07004118058565], +["2ffm",2.51,2.54699454037609], +["1pub",2.51,3.17512940111074], +["1du7",2.51,2.89281916100095], +["1rhu",2.51,2.24623573652005], +["1pc6",2.51,3.16488834841248], +["1w2a",2.51,2.49476986682839], +["1okz",2.51,2.55628571148536], +["1pf8",2.51,2.85592429428053], +["1vev",2.51,2.67053935375146], +["1ddi",2.51,3.15608918781342], +["1jhk",2.51,2.54203671074877], +["1l8l",2.51,4.18340097713843], +["1nuh",2.51,2.54483765025141], +["1wc6",2.51,3.79457754831701], +["1ycn",2.51,2.34822062909668], +["1w45",2.51,2.81236177595584], +["1ggq",2.51,2.4126830215049], +["1ph1",2.51,2.57809930166471], +["1nvd",2.51,2.68615834559657], +["2b7p",2.51,3.2697929007544], +["1v7m",2.51,3.49067003165732], +["1y7o",2.51,2.39593160093496], +["1zxn",2.51,2.97002555099752], +["1ots",2.51,3.18159561418864], +["1h29",2.51,2.94597179778846], +["1pzv",2.52,3.21309773676058], +["1sbd",2.52,3.36638866729108], +["1vpy",2.52,2.17638665867901], +["1ilg",2.52,2.86472335131194], +["1y6k",2.52,3.05855699963973], +["1yu3",2.52,1.70393855513822], +["2fbe",2.52,3.25902124149767], +["1zkx",2.52,2.92951425048053], +["1c0u",2.52,3.25791496180961], +["1n8z",2.52,3.27544015199365], +["1szu",2.52,2.21548669939282], +["1szk",2.52,2.48873677603464], +["1ji4",2.52,2.93853899852854], +["1usy",2.52,3.61920499038355], +["1y7h",2.52,3.00486450006239], +["1914",2.53,3.30735752987298], +["1e49",2.53,2.72100990282796], +["1si5",2.53,3.03862353365938], +["1wg0",2.53,2.56724139283584], +["1pxm",2.53,3.03352377345619], +["2cx8",2.53,2.83057668914099], +["2aeh",2.53,2.88864915761334], +["2b8n",2.53,1.77854900614572], +["1c0m",2.53,3.03633081912086], +["1fcd",2.53,3.73362458726911], +["1xs4",2.53,2.07320282463733], +["1rf1",2.53,2.93597394538837], +["1zmc",2.53,2.42600577943899], +["1gzy",2.54,3.61950059928354], +["1dxs",2.54,3.18278245115954], +["1ex9",2.54,2.04531952444976], +["2b2l",2.54,3.13592445523879], +["2fxk",2.54,2.80831097250046], +["1e7m",2.54,2.42419610823313], +["2f9b",2.54,3.18190427214363], +["1p9s",2.54,3.10345648670619], +["1o67",2.54,2.49298892874651], +["1jt6",2.54,3.22712076614003], +["2bjh",2.54,3.23445238914386], +["1t8e",2.54,2.81256130879172], +["1tyh",2.54,3.24169626571879], +["2b3x",2.54,2.4062932291747], +["1qvi",2.54,3.10516910376390], +["1qx5",2.54,3.56343378110825], +["1yko",2.54,1.84762717982775], +["2frv",2.54,2.84289907276818], +["1dd5",2.55,2.94402555060675], +["1p04",2.55,2.55534547818254], +["1e46",2.55,3.15204820918223], +["1kdq",2.55,3.59896710599444], +["2a7q",2.55,3.00299490463763], +["2bbo",2.55,2.37963928505382], +["2b8p",2.55,2.962688069504], +["2a3k",2.55,2.32286062767584], +["2bil",2.55,1.91264806263926], +["1yvj",2.55,3.12591901365409], +["2aze",2.55,2.88870885181884], +["1wa6",2.55,2.80738588028052], +["1vdr",2.55,3.17542136514248], +["1drg",2.55,3.51423788134901], +["1vfx",2.55,3.99470639163329], +["1lik",2.55,3.76182311061265], +["10mh",2.55,2.34773188983634], +["1zkf",2.55,2.22324960915883], +["1hjq",2.55,2.68543952197213], +["1j4j",2.55,2.38138781044464], +["1jh9",2.55,4.0419091301039], +["2c2r",2.55,3.465489768996], +["1qr4",2.55,2.91771430055731], +["1hkm",2.55,2.79094144035621], +["1hki",2.55,3.02359689985458], +["1w51",2.55,3.14517794193641], +["2cii",2.55,2.71051424221594], +["2c5w",2.55,2.66239400208151], +["1son",2.55,2.41711211455566], +["2gtu",2.55,2.76156095834705], +["1hi6",2.55,3.16142355412004], +["1yeh",2.55,2.9479780718523], +["2bmu",2.55,2.79009288628127], +["1a8t",2.55,4.14672814525404], +["1nj1",2.55,2.77244730670350], +["1cf5",2.55,3.68654761714662], +["1uxp",2.55,2.74922088891535], +["1m0i",2.55,2.72033396013792], +["1vdz",2.55,3.37314084356272], +["2btf",2.55,3.27385556443092], +["1x7p",2.55,2.65150914652669], +["1kfv",2.55,3.13213045869102], +["1tqb",2.55,3.0342154510194], +["2bvm",2.55,2.35516410079865], +["1r74",2.55,2.96399724696419], +["1cy4",2.55,2.64514032569495], +["1irm",2.55,4.09815341467196], +["1ll1",2.55,2.55733218647831], +["1iew",2.55,2.53900532833832], +["1sev",2.55,2.61504118829907], +["1y2j",2.55,2.67321620046294], +["1u75",2.55,2.98970772929222], +["1u1h",2.55,3.29064251646988], +["1ai6",2.55,2.53887090191892], +["1ed3",2.55,3.06491177065072], +["1k2s",2.55,2.94371199479969], +["1m3x",2.55,2.18979537365925], +["1j5q",2.55,3.53527315935262], +["1j7e",2.55,2.53932256424035], +["1ya0",2.55,3.05244196290913], +["1tu0",2.55,3.87414995118856], +["1og5",2.55,3.04932172303029], +["1rt2",2.55,3.49595886386342], +["1rt1",2.55,3.19961115724418], +["1awt",2.55,3.34803842356261], +["2bfp",2.55,2.29786639722245], +["1ult",2.55,2.43523095990132], +["1r0y",2.55,3.06480913742163], +["1kzh",2.55,2.45271038596518], +["1w1k",2.55,2.88443956329625], +["1p4r",2.55,2.68739487485512], +["1l5a",2.55,2.82987586411603], +["1xdq",2.55,3.01537755186267], +["1p0y",2.55,3.0850759778096], +["2b05",2.55,1.88656950198309], +["1sfy",2.55,2.79235483485541], +["1y1s",2.55,3.06632060647132], +["1wxw",2.55,2.89002048800777], +["1h31",2.55,2.47359322768281], +["1tyq",2.55,2.79021575430947], +["1nsi",2.55,2.67123586697921], +["1u2v",2.55,2.67034082762483], +["1uwi",2.55,2.60611919796869], +["1n3s",2.55,2.59785796631195], +["1up6",2.55,2.49918030692541], +["1hr7",2.55,2.60973204562316], +["1s64",2.55,2.40309474186949], +["1v0f",2.55,2.78322420209718], +["1b01",2.56,3.62692243086368], +["3blg",2.56,2.98706708200448], +["1gtd",2.56,2.68611968653659], +["1a7h",2.56,2.45836293765911], +["1ys9",2.56,2.76500998615704], +["1l8k",2.56,3.22452188645502], +["1dsg",2.56,2.76906468369331], +["1xwr",2.56,3.2715000134758], +["2c22",2.56,2.96245084601912], +["1gkw",2.56,2.50029810925431], +["1j90",2.56,2.99595985387311], +["1u8n",2.56,2.69476294245766], +["1tpx",2.56,2.98441664045218], +["1a47",2.56,2.96944422291953], +["1m9r",2.56,2.20142887688929], +["1wp1",2.56,2.51256682562975], +["2bua",2.56,2.67207450325732], +["2ajd",2.56,3.2179617071692], +["1mms",2.57,3.58247302105784], +["1xp3",2.57,3.04725790655864], +["1ur3",2.57,3.03755950929125], +["2c2d",2.57,3.46318873076804], +["2bkw",2.57,3.04218636078739], +["1g5q",2.57,2.34954719772400], +["1ayp",2.57,3.24798014187089], +["1nak",2.57,2.9923449143701], +["1nks",2.57,3.15240392462815], +["2g5w",2.58,1.8263215629602], +["1f3h",2.58,3.93833296884863], +["1w3f",2.58,3.34556568204823], +["1n3u",2.58,2.28547000616672], +["1xq9",2.58,2.94728485179826], +["1nve",2.58,2.80628449738670], +["2ag1",2.58,2.7679253750173], +["2ag0",2.58,2.32773976151785], +["2ab1",2.59,2.06299686812233], +["2flc",2.59,3.45897056662287], +["1umo",2.59,2.82055539348924], +["1utb",2.59,2.54710140795738], +["1peg",2.59,4.05841996049498], +["2hlp",2.59,2.83280894603504], +["1xjl",2.59,2.54487785053191], +["1gaq",2.59,3.23138287385707], +["2evv",2.59,2.81762988900378], +["1asp",2.59,2.25146996752353], +["1t9a",2.59,2.00855109823757], +["1cb5",2.59,2.30370844586717], +["2br4",2.59,2.43021483932706], +["1xpg",2.59,2.60495602734729], +["1gw5",2.59,3.29024650691498], +["1zy8",2.59,3.66733857773909], +["2ce3",2.6,2.71496550470126], +["1uue",2.6,3.05795247414959], +["9msi",2.6,1.95484702515888], +["8msi",2.6,2.19361383110172], +["1baj",2.6,2.42853104139831], +["1a43",2.6,2.36949448789886], +["1dt4",2.6,2.71004753332061], +["1swi",2.6,4.3010930387867], +["1ycr",2.6,2.94967740308569], +["1fb7",2.6,2.59377089482420], +["1ci6",2.6,2.04179241884101], +["1pd3",2.6,2.60117951807608], +["1byw",2.6,2.56954873633013], +["1p65",2.6,2.65738263489800], +["1tsj",2.6,3.30785356969524], +["1env",2.6,2.56611210543844], +["1a6f",2.6,3.75163812133879], +["1cd8",2.6,2.81159573888038], +["1dp9",2.6,2.88680239380252], +["1si2",2.6,2.74825659174033], +["1si3",2.6,3.11475115648761], +["1oz6",2.6,3.27996660018139], +["1stp",2.6,2.70777329837877], +["1un5",2.6,2.13168286623457], +["1b6e",2.6,4.17472269113525], +["1zm6",2.6,3.15327809404367], +["1t37",2.6,3.3784056994879], +["1maf",2.6,2.96795173182481], +["2fhi",2.6,3.17981807115029], +["6fit",2.6,3.01561331765142], +["1o2e",2.6,2.50316788954078], +["1n29",2.6,3.27677705675231], +["1p2p",2.6,3.84435782332546], +["1ml8",2.6,2.35534138611994], +["1hik",2.6,3.37750474112731], +["1bh9",2.6,2.76030381612988], +["1dsy",2.6,2.82110620382306], +["2az2",2.6,2.82991488759562], +["2az0",2.6,2.54263950478525], +["1b1b",2.6,3.50122631338323], +["1t0z",2.6,2.12495542052911], +["1hst",2.6,3.01663622414998], +["1cf7",2.6,3.59071049921781], +["1div",2.6,3.58314331665275], +["1leo",2.6,3.23657307161464], +["1v8t",2.6,2.54316545809175], +["2gli",2.6,4.60660827892933], +["2pil",2.6,3.09677145299681], +["1ay2",2.6,3.12333708328693], +["1j2y",2.6,3.45551906222781], +["1wvl",2.6,3.27354372947894], +["1dre",2.6,3.89583620475553], +["2itg",2.6,4.45153127585847], +["1xyh",2.6,2.90538619678488], +["251l",2.6,3.28624141583397], +["1r0n",2.6,3.59240044404757], +["1nay",2.6,2.56039478659431], +["149l",2.6,3.43612843925116], +["170l",2.6,3.44446142090686], +["1lry",2.6,3.03843739560560], +["521p",2.6,3.35041995014884], +["2rap",2.6,2.53249068017941], +["1ahn",2.6,3.23102827667085], +["1gam",2.6,2.69625360010001], +["1pkv",2.6,2.37616544641076], +["1hrs",2.6,3.3507482437824], +["1h0x",2.6,3.24537377350224], +["1qhy",2.6,2.45228499638444], +["1iv5",2.6,3.84696450433282], +["1m5p",2.6,2.88660311515688], +["1pgz",2.6,2.99961529603106], +["1eh1",2.6,3.07987518564292], +["1ti1",2.6,3.77333668813063], +["1q3i",2.6,3.34176594106470], +["1z24",2.6,2.44010603388440], +["1t4e",2.6,2.98311089794382], +["1yq8",2.6,3.29396959670009], +["1vcy",2.6,3.0144794580607], +["1hcn",2.6,3.66922508854357], +["2bnz",2.6,2.72187431174651], +["1rq9",2.6,3.68538103377853], +["1ivq",2.6,3.62155564761473], +["2aig",2.6,2.80433095629678], +["1par",2.6,3.56299498474590], +["1rtg",2.6,2.89895251302532], +["1sto",2.6,4.08978808253622], +["1thu",2.6,4.3778935064996], +["1i1h",2.6,3.93917611557368], +["1bx9",2.6,2.48259835522873], +["1bvb",2.6,3.31243818070882], +["1yk8",2.6,2.68331524258422], +["1gt0",2.6,3.27792946064408], +["1au0",2.6,3.11336516679813], +["1au2",2.6,3.41615633077286], +["1s1g",2.6,2.92162379644811], +["1ue5",2.6,3.40937554122667], +["1m9b",2.6,1.94810142290531], +["1uru",2.6,2.39615018674342], +["1gtb",2.6,3.46472093183734], +["1qc6",2.6,3.99678803657318], +["2emo",2.6,3.75551557964219], +["2yfp",2.6,3.29409408564946], +["1x0k",2.6,2.83924560177680], +["1ixf",2.6,2.94930087386448], +["1dql",2.6,2.82981909060848], +["1cby",2.6,2.7756357611812], +["1z39",2.6,2.64398940546795], +["1z36",2.6,2.76831235107579], +["2sba",2.6,3.73268411879591], +["1o9c",2.6,2.70494087927006], +["1o9e",2.6,2.89101922853286], +["1skv",2.6,2.92942101095094], +["1hyq",2.6,3.17903315354142], +["1lrv",2.6,3.5549551159794], +["1zpc",2.6,2.60531068088168], +["2acj",2.6,2.94202268282357], +["1zqu",2.6,3.66548911312402], +["1mt0",2.6,3.17276021199054], +["2fnp",2.6,3.90318165048829], +["1dpc",2.6,2.50393038436265], +["1eaa",2.6,2.78709613615546], +["1ead",2.6,2.64343200365707], +["1eab",2.6,2.83002445039827], +["1eac",2.6,2.94916916740401], +["1v0d",2.6,3.20129103865624], +["1h2d",2.6,3.60535694763319], +["1pw6",2.6,2.58683299171034], +["1f92",2.6,2.81979667477388], +["2bml",2.6,2.98744070849764], +["1bj3",2.6,3.58890018754381], +["1hcx",2.6,2.9953646184992], +["1lu1",2.6,2.95902641305717], +["1sc1",2.6,3.02724015524893], +["1i6u",2.6,2.34271640514967], +["1bg5",2.6,4.58061522802025], +["1p8k",2.6,3.58863736780975], +["1ydf",2.6,3.01398093933879], +["1ice",2.6,2.7429496264813], +["1bnm",2.6,2.78820636445367], +["1fw2",2.6,2.93098724496880], +["1kwq",2.6,2.55884310102808], +["2a98",2.6,2.6828278800346], +["1dxm",2.6,2.44350795702069], +["1ev8",2.6,2.61929200331509], +["2c3k",2.6,3.04299098922046], +["1qri",2.6,2.82306381926523], +["1lxa",2.6,3.31390143790367], +["1k7s",2.6,2.99125373971583], +["1r6a",2.6,2.87254082511994], +["2cgv",2.6,3.29757459177574], +["1ft0",2.6,2.98273400487671], +["4tgl",2.6,3.60457969816484], +["1il4",2.6,2.77691590403372], +["2bhh",2.6,2.75161314132415], +["1av7",2.6,3.10946225635855], +["3vsb",2.6,3.14181892871542], +["1af4",2.6,3.12617957817524], +["1aod",2.6,2.35231942006468], +["1uyn",2.6,2.89411131027976], +["1xwj",2.6,3.32855846693271], +["1wvx",2.6,2.85463671980371], +["1kxu",2.6,3.4236540843254], +["1jkw",2.6,3.30515539045604], +["1ss9",2.6,2.88425202716515], +["2phk",2.6,2.75105629543642], +["1ujj",2.6,2.88942690739195], +["1iqn",2.6,3.06619282585627], +["1iqm",2.6,3.24275299629289], +["1iqg",2.6,3.23879252502849], +["1lft",2.6,2.91328517082059], +["1lfq",2.6,3.39305764390869], +["1pf7",2.6,3.67374825312499], +["1jtf",2.6,3.04001759058535], +["1bmm",2.6,3.32009749492677], +["1zjd",2.6,2.76037724353868], +["1ptg",2.6,3.37544861190487], +["6ptd",2.6,3.43562641775772], +["7ptd",2.6,3.59027045194317], +["1sj8",2.6,3.98558684432659], +["1u99",2.6,2.93432935516545], +["2c0k",2.6,2.77680033132758], +["1o70",2.6,2.5896071106321], +["1kc1",2.6,2.60490106936469], +["1ulc",2.6,2.56798737109514], +["1sig",2.6,3.00110448838359], +["1zbd",2.6,2.8067584011159], +["1q1m",2.6,2.31739568982224], +["1hdt",2.6,3.90029723908193], +["1ksj",2.6,3.41486710072298], +["1b3w",2.6,2.00947453083713], +["1ptu",2.6,3.43373356613758], +["2a6o",2.6,3.03878172903756], +["1ypx",2.6,3.49456162860515], +["1m14",2.6,2.81737682961890], +["1d9u",2.6,2.06083164084275], +["1kac",2.6,2.69089468427749], +["1evq",2.6,2.67890902617277], +["1yc0",2.6,2.37339761743681], +["1ld3",2.6,2.56798324826866], +["1bee",2.6,1.75724988206056], +["1by8",2.6,4.1728863854587], +["1wv4",2.6,3.55749790496156], +["1svc",2.6,3.19313701168599], +["1fn7",2.6,2.81567980796763], +["1yql",2.6,2.72852520279628], +["1l9v",2.6,3.17023268941738], +["2shk",2.6,2.6759669691967], +["2fia",2.6,2.87747130304869], +["1jpd",2.6,2.40179566863122], +["1rd7",2.6,3.24495530563966], +["1re7",2.6,3.32892664279322], +["1lbs",2.6,2.71025038463255], +["1git",2.6,2.63798607164283], +["2b0r",2.6,2.37773692878661], +["1b89",2.6,3.23842497875654], +["1g83",2.6,3.26093014385424], +["1um8",2.6,3.20317098325401], +["1i4w",2.6,3.26360630232212], +["9icw",2.6,3.860634536756], +["9icx",2.6,3.98001943885247], +["1zwk",2.6,2.61000819547955], +["1a0i",2.6,3.48565554214501], +["1bu1",2.6,2.74339160573558], +["1jiz",2.6,2.32018741761571], +["1vc2",2.6,3.20673104103183], +["1tva",2.6,2.13700810787613], +["1bpz",2.6,4.28591132671584], +["1c8t",2.6,3.64198423034952], +["2f2p",2.6,3.11448744338334], +["1b7f",2.6,3.60400340332248], +["1u5e",2.6,2.92305174708056], +["1wxq",2.6,3.51628298104227], +["1ixm",2.6,2.74082738867842], +["1ic8",2.6,3.89097870925111], +["2puc",2.6,3.88111576855467], +["2pud",2.6,3.91042819499006], +["1wet",2.6,3.99612935762226], +["1mif",2.6,2.9816199563967], +["2bz0",2.6,2.46052275634496], +["1w74",2.6,2.48839977740297], +["1d5j",2.6,3.11377776377468], +["1qq2",2.6,2.73204411467978], +["1dfv",2.6,3.37662475669282], +["2f89",2.6,2.48688732656593], +["2f8z",2.6,2.85957605674706], +["1al7",2.6,2.71299545144651], +["1di9",2.6,2.11217679894217], +["1fps",2.6,3.60663717271933], +["1q24",2.6,2.32845576318957], +["1buh",2.6,2.97753721460526], +["1tbp",2.6,3.30168373786711], +["1viv",2.6,2.7373156061593], +["2auc",2.6,2.50359311390524], +["5jdw",2.6,2.48564912832669], +["1syt",2.6,3.13809261888002], +["1qmb",2.6,3.12808859797967], +["1cqp",2.6,2.64972087651368], +["1yvw",2.6,2.20963049607091], +["1a22",2.6,2.90795670133294], +["1cav",2.6,4.38218293734905], +["1caw",2.6,4.58920657660855], +["1n1l",2.6,2.45298226965059], +["1hkj",2.6,2.80389056475314], +["1peb",2.6,2.49028199021675], +["1n3w",2.6,3.09648060633314], +["1es0",2.6,2.53250331352607], +["3hla",2.6,2.92220422423196], +["2hla",2.6,2.95935743285488], +["1gp7",2.6,2.59780585730199], +["1wkd",2.6,2.80282389047110], +["1a72",2.6,3.41951872960200], +["1iao",2.6,3.63919553117019], +["2a8q",2.6,2.24692059807372], +["1k2f",2.6,2.52399152515994], +["1e4g",2.6,3.32750884031446], +["1c5g",2.6,3.08603022450993], +["2fwo",2.6,2.92620294563544], +["1h8l",2.6,2.59114203987653], +["1c7z",2.6,2.41397795841242], +["1mst",2.6,2.29505133557121], +["2c4z",2.6,2.46992966306581], +["1vub",2.6,2.20421903164302], +["1j04",2.6,3.00097184093285], +["1vgf",2.6,2.83061154635357], +["1doa",2.6,3.04408862830869], +["1sir",2.6,2.84196323729043], +["1yvg",2.6,3.17381031550075], +["1zbo",2.6,3.14003905690763], +["1tdq",2.6,2.61092687856639], +["1asb",2.6,2.77135788823119], +["1vgl",2.6,3.27417952602874], +["2c4d",2.6,2.10251599595549], +["2phm",2.6,3.06818799053592], +["1b23",2.6,3.02020477529763], +["1uei",2.6,2.40458737394851], +["1udw",2.6,2.47431390092528], +["1jg5",2.6,2.11574798746525], +["1kcg",2.6,3.52956408030015], +["1jnu",2.6,2.66397237552357], +["1ft9",2.6,2.93713487494087], +["2alm",2.6,2.42422507705719], +["1qpp",2.6,2.52863600430101], +["1cw7",2.6,2.57676994161331], +["1xxb",2.6,3.60768875544665], +["1cpy",2.6,4.19370372482536], +["1mim",2.6,3.14539927529671], +["2cdg",2.6,2.96658791423757], +["1c12",2.6,3.14662258531128], +["1dka",2.6,3.06213735207927], +["1g0t",2.6,2.26137120039453], +["1ymf",2.6,3.38209988669453], +["1h3p",2.6,3.5455221107597], +["1v29",2.6,2.52047477441093], +["1m0p",2.6,3.69058596890505], +["1kkf",2.6,2.6307832424208], +["1soo",2.6,2.87626470874412], +["1kjx",2.6,3.63069997622903], +["1cgs",2.6,4.29589480494374], +["1hh6",2.6,3.24990795492277], +["1bog",2.6,3.30625139907766], +["1pg5",2.6,2.78904376664441], +["1onf",2.6,3.57406221173731], +["1nel",2.6,3.81506709383131], +["1err",2.6,3.10980620892953], +["1i9j",2.6,2.60283395835313], +["2cvf",2.6,4.44137105414246], +["1avg",2.6,2.99157579034418], +["2tpt",2.6,2.32802252274212], +["1b48",2.6,3.67032892967821], +["1guh",2.6,1.91716742747973], +["1u8l",2.6,2.74862001551121], +["1z4y",2.6,2.62899979181567], +["1dfq",2.6,3.4573033493888], +["1bdg",2.6,3.10576008113228], +["1f90",2.6,3.20512309947614], +["1ijk",2.6,3.17201251713555], +["1qu7",2.6,4.03369027006896], +["1hiy",2.6,3.11820519295594], +["1yfm",2.6,3.09551755896684], +["2mpa",2.6,3.0844255255568], +["1g1x",2.6,3.86819680719634], +["1mpa",2.6,3.29442207642908], +["1rin",2.6,2.44993522536935], +["1tnf",2.6,3.85518957248424], +["2bih",2.6,2.38406163970370], +["1ayz",2.6,2.67900897750756], +["1y3i",2.6,4.27693921297962], +["1k86",2.6,3.61520001336431], +["2aaq",2.6,2.88732934412216], +["1jtz",2.6,3.09604475488772], +["1sq0",2.6,2.98313211034851], +["1y8n",2.6,2.63700665958952], +["2c1j",2.6,3.31440145946808], +["1igr",2.6,3.66697763507502], +["2bnd",2.6,3.08150749646148], +["1rs0",2.6,2.62717210016571], +["1eop",2.6,3.27118781653837], +["1rc6",2.6,3.19705520404903], +["1ww1",2.6,3.10784094226482], +["1jgc",2.6,2.11271535759771], +["1fyu",2.6,2.70262761010478], +["1kp5",2.6,2.78881836070312], +["1q8m",2.6,3.01872509985581], +["1gq9",2.6,2.97386868864839], +["1gqc",2.6,2.45207252128925], +["1p8z",2.6,2.97685984780138], +["1ej9",2.6,3.07331368649515], +["1zkq",2.6,3.26687801424612], +["1b4w",2.6,3.33911385801091], +["1u3c",2.6,2.87232374899388], +["1wrl",2.6,2.55131853207226], +["1igc",2.6,4.1199813600434], +["1grw",2.6,2.67158010339878], +["1pwo",2.6,3.4857617398476], +["1s1c",2.6,2.84393562556164], +["1rr8",2.6,2.50901444770143], +["1h9d",2.6,3.04021945704469], +["1iig",2.6,2.76006255401854], +["1m2n",2.6,3.32651515732288], +["1k8t",2.6,3.208119524477], +["1ezx",2.6,3.01252044836542], +["1isg",2.6,2.6159192415895], +["2ard",2.6,2.77439089827497], +["1xkt",2.6,3.24812697886335], +["1dxf",2.6,2.61790647706734], +["1tre",2.6,3.28538974639799], +["1azn",2.6,3.48922769203094], +["1zct",2.6,2.68589413691510], +["1j9w",2.6,2.89789196336441], +["1jmy",2.6,3.24369447481458], +["1nyl",2.6,3.48717165063703], +["1pkm",2.6,3.10870207221308], +["1rjl",2.6,3.01984781161499], +["1tls",2.6,2.69082546454946], +["1wpr",2.6,3.33309694628777], +["1euy",2.6,3.17424480687334], +["1qrs",2.6,2.99896080210129], +["1i4t",2.6,3.47163018616146], +["1knp",2.6,3.54329499432541], +["1cfj",2.6,2.78663868398911], +["1p45",2.6,3.72842010516772], +["1dt3",2.6,3.03960991110501], +["1imc",2.6,3.01593610430178], +["1imd",2.6,2.98058020854843], +["1jop",2.6,3.86453585339801], +["1rd6",2.6,2.32228112628289], +["1m52",2.6,2.75648209898705], +["1s8o",2.6,3.07780544021421], +["1zd5",2.6,3.10666499498890], +["1z4s",2.6,2.38243369496132], +["1bql",2.6,3.25940718162953], +["1p8v",2.6,2.8309631125859], +["1yuw",2.6,3.24992185025108], +["1tfx",2.6,2.59184279664247], +["1q50",2.6,2.83174245433202], +["1xl4",2.6,2.51346001503432], +["2buj",2.6,2.36215337497445], +["1nih",2.6,2.85487248701386], +["1yhr",2.6,2.94372975894221], +["1hac",2.6,3.99727631956668], +["1y8i",2.6,2.60456479348924], +["1wss",2.6,2.66739808771474], +["1py1",2.6,2.83725707429833], +["1a97",2.6,1.8007223347116], +["1aby",2.6,2.86444339424988], +["2a3r",2.6,2.96477439697811], +["1zi0",2.6,2.42317618882741], +["1u7f",2.6,3.51482563809821], +["1hxy",2.6,2.82852773279544], +["2a1r",2.6,2.73868464772516], +["1mc3",2.6,3.49026510264723], +["1cbw",2.6,3.08385019456627], +["1lso",2.6,2.83373949573869], +["2bxl",2.6,2.85636284089135], +["1noc",2.6,3.08188396565227], +["2bxq",2.6,2.75158453446663], +["2bxo",2.6,2.80506814746818], +["1i78",2.6,3.01473620487416], +["1gnj",2.6,2.96878484311769], +["1tyy",2.6,3.22499756989242], +["1d9x",2.6,3.73365624569952], +["1rq7",2.6,1.98417603347637], +["1bgs",2.6,2.52060495147103], +["1wd9",2.6,2.96428906639854], +["1vcf",2.6,3.34279247357883], +["1e3h",2.6,2.56732010875472], +["2kzm",2.6,2.96610333349060], +["1vyt",2.6,3.04745300745597], +["1ps1",2.6,2.96504848770825], +["1jws",2.6,3.02650651681766], +["2uug",2.6,2.51870287877897], +["2a8m",2.6,2.96609453936204], +["1lhr",2.6,2.59952758838563], +["1upl",2.6,3.14149813571906], +["1kke",2.6,2.51180726985103], +["1lkt",2.6,2.59825411388166], +["1g44",2.6,3.75242136956408], +["1g82",2.6,2.9439027833007], +["1sg3",2.6,3.17547680599954], +["1yo8",2.6,3.08442591465424], +["1fpb",2.6,2.53945047920665], +["1fbc",2.6,2.70452470412019], +["1mnd",2.6,4.26012442704272], +["1wr6",2.6,2.95888532613871], +["2c1h",2.6,2.60707561694700], +["1w1z",2.6,3.47476587118027], +["1uh3",2.6,2.91085395982641], +["1o0v",2.6,3.26031774309433], +["1fvo",2.6,2.82103885621967], +["1zzd",2.6,3.26264561702381], +["1yxb",2.6,2.06685074157263], +["1wkp",2.6,2.20573017195984], +["1gla",2.6,3.14749689221002], +["1oy5",2.6,3.56380987627630], +["1glb",2.6,3.15196322431164], +["1huo",2.6,3.12894587760978], +["1jqu",2.6,4.31733462236698], +["1ufr",2.6,2.85347643755399], +["1bbt",2.6,2.90542476521608], +["2cvs",2.6,3.12812160343986], +["1lnz",2.6,3.33043173709821], +["2bm1",2.6,3.40377254744738], +["2a41",2.6,2.51105251566108], +["2cbq",2.6,2.52991028470889], +["2af3",2.6,3.23473230610955], +["1jvz",2.6,2.33350165521851], +["1jnf",2.6,3.01409694329025], +["1zbr",2.6,3.30230702471196], +["4cgt",2.6,3.19603132521213], +["1m8y",2.6,3.02422523888814], +["1fod",2.6,3.01453863751276], +["6cgt",2.6,3.10497189211873], +["2dij",2.6,2.71806698069009], +["1ao7",2.6,2.98718059453857], +["1r1i",2.6,4.18361305510896], +["1ymy",2.6,3.24391700225026], +["1by5",2.6,2.94149311138526], +["1ybd",2.6,2.56424886062705], +["2b7f",2.6,3.02268219661029], +["1kiz",2.6,2.19337446988174], +["1ksf",2.6,3.03604695321528], +["1q7g",2.6,3.1607011351199], +["1svo",2.6,3.04598761543627], +["1s5f",2.6,1.97929973201441], +["1ng3",2.6,2.86560113860988], +["1sa5",2.6,2.24667679705305], +["1pd1",2.6,2.59240604482726], +["1pd0",2.6,2.41910154862121], +["1ltb",2.6,2.58292952114717], +["1gl3",2.6,3.37345813468777], +["1b3q",2.6,3.13222699129694], +["1v2e",2.6,3.34936309104321], +["2fch",2.6,1.62249046053373], +["1kyx",2.6,1.99742268965788], +["1qqc",2.6,3.00915236681816], +["1a6z",2.6,3.37407084887274], +["1wsv",2.6,2.34031409650305], +["1t02",2.6,2.73147653621248], +["1kx4",2.6,2.70230784629530], +["1mc5",2.6,2.41190662644747], +["1xxf",2.6,3.22364814223595], +["1g9x",2.6,3.53720078642831], +["1li7",2.6,3.13866517103106], +["1gng",2.6,2.68264773947057], +["2cww",2.6,2.98558205684554], +["1ffp",2.6,3.27018559760025], +["1f66",2.6,2.82412630788238], +["1aqj",2.6,2.74971693098533], +["1aqi",2.6,2.93600945102848], +["1hhg",2.6,2.63434080796542], +["1bx2",2.6,3.25728519156589], +["1h6b",2.6,2.73826076841431], +["1rjz",2.6,2.79235089435136], +["1wu8",2.6,2.7359207001409], +["1rqq",2.6,2.73786919347452], +["1r8l",2.6,2.66093397236240], +["1dn1",2.6,3.00116116964233], +["1fpn",2.6,2.91171160144042], +["1dxi",2.6,4.15699574526553], +["1u76",2.6,3.31352201126062], +["1zl5",2.6,2.87868235068544], +["1axc",2.6,2.08778331373200], +["1jr1",2.6,2.88074918336173], +["1df0",2.6,3.53538933534559], +["1asl",2.6,3.79540021767639], +["1zn3",2.6,2.94242321359045], +["2etr",2.6,2.5486506593231], +["1fyt",2.6,2.7392053977823], +["2sbl",2.6,2.45860667144728], +["1k44",2.6,2.65834678994124], +["1gzh",2.6,2.8794148882419], +["1nq9",2.6,3.00943549596498], +["2esv",2.6,2.44426776755483], +["2ant",2.6,3.94665203251598], +["1uyj",2.6,3.15658090791262], +["1e04",2.6,2.75845023512618], +["1k8g",2.6,3.19151253272111], +["1tbr",2.6,3.01511611116963], +["1cmw",2.6,3.20462749207234], +["1u2r",2.6,2.71808112031569], +["1yqq",2.6,2.89956461498118], +["1p4d",2.6,3.34819678297858], +["1jwj",2.6,2.23286078993005], +["1jvq",2.6,3.22887300587891], +["1fnq",2.6,2.73243703841603], +["2bgh",2.6,3.03798744402592], +["1dwx",2.6,3.09133236503345], +["2nod",2.6,3.15024746535290], +["1nod",2.6,3.43569967889054], +["1vhk",2.6,2.91272230623448], +["1lnh",2.6,3.44231677683168], +["2ctz",2.6,3.29327218099468], +["1q1w",2.6,2.62330343443016], +["1ykb",2.6,2.94070033512489], +["1rba",2.6,4.42391698807283], +["1t16",2.6,3.40598940310940], +["1ngw",2.6,3.35017884143726], +["1axs",2.6,3.72824021401848], +["1mf2",2.6,3.06938102105479], +["1ltd",2.6,3.24252645978183], +["1ggo",2.6,3.82414319934571], +["1yaf",2.6,2.72027188831435], +["1ad5",2.6,2.99016865630986], +["1nkk",2.6,3.2834256725822], +["2fr8",2.6,2.56179539327313], +["1qb4",2.6,3.28611263255222], +["1z2z",2.6,3.36503628999551], +["1uup",2.6,2.96191382898828], +["1etz",2.6,3.13208098020525], +["1lwh",2.6,2.98596551267141], +["2eyt",2.6,2.78507996105973], +["1khn",2.6,2.93582243476174], +["1alj",2.6,2.62743806282229], +["1hkv",2.6,2.996182266130], +["1ad3",2.6,2.96534664606007], +["1elx",2.6,3.07274130892179], +["1s59",2.6,2.80700121380374], +["1ig9",2.6,3.10688034543691], +["1tkt",2.6,3.31268176648849], +["1un0",2.6,2.75205839211812], +["4at1",2.6,3.17813072128981], +["5at1",2.6,3.19334262051249], +["6at1",2.6,3.20092575851924], +["1kq7",2.6,2.59667313059276], +["1ibt",2.6,3.33368800513562], +["1sku",2.6,3.6494320573074], +["2c1t",2.6,2.49223871767711], +["1vh1",2.6,3.02010036508663], +["9rub",2.6,4.03705627692128], +["2acw",2.6,3.20316710460869], +["1nbe",2.6,3.20673937412002], +["1js6",2.6,2.80439311244341], +["1s1v",2.6,3.47229241982925], +["1jlg",2.6,3.39931258381638], +["1rev",2.6,3.09227943441651], +["1jlf",2.6,3.57571789303312], +["1dir",2.6,2.99786114584724], +["1t4p",2.6,2.96325731961375], +["1t4r",2.6,2.82935556535499], +["1efa",2.6,3.06112799517376], +["1kc6",2.6,3.03855904844035], +["1s3r",2.6,3.24785294983276], +["1lmk",2.6,3.3841731412688], +["1dxx",2.6,2.91169651162199], +["1ebd",2.6,3.04212045120249], +["1hv5",2.6,3.19849223368182], +["1m8v",2.6,3.07268556602622], +["1tyt",2.6,2.84891282269067], +["1gow",2.6,3.17335715568739], +["1s9e",2.6,3.89968023546904], +["1e1f",2.6,2.83673155113674], +["1p1f",2.6,3.63560000252981], +["1xvp",2.6,3.22142138896864], +["1t5s",2.6,3.08267345579554], +["1ymh",2.6,3.88718465905526], +["1a6d",2.6,3.04335907540206], +["1irx",2.6,3.1896653599859], +["1nbo",2.6,2.92984025666912], +["1fa0",2.6,3.10357060405380], +["2bfm",2.6,2.53905407190129], +["2bfo",2.6,2.33505443580168], +["1g8g",2.6,2.74068285485393], +["1ygz",2.6,3.60658691902366], +["1kzg",2.6,2.83194808311300], +["1dgr",2.6,2.47438177477415], +["1xf5",2.6,3.3411271396211], +["1m7r",2.6,3.28125524190584], +["1kf9",2.6,3.80208762416131], +["2a5y",2.6,3.58713771903976], +["1ja0",2.6,3.23803851644711], +["1tzh",2.6,2.51907834803965], +["2aly",2.6,2.953995194290], +["1nek",2.6,3.3099667603941], +["1djg",2.6,3.23490673046542], +["1jsc",2.6,2.41274421299243], +["1arz",2.6,3.71706932916424], +["1ii9",2.6,3.19902996497117], +["1gn9",2.6,2.38114636870976], +["1e8h",2.6,2.87964112824765], +["1cax",2.6,4.49323830849033], +["1gyr",2.6,2.25919647750999], +["1efp",2.6,3.05165497266005], +["1nob",2.6,3.0212569159178], +["1jst",2.6,3.38422471977466], +["2bkz",2.6,2.30574792959128], +["1urc",2.6,3.26735711617112], +["2tsr",2.6,2.17697693081414], +["1m6b",2.6,3.25168396241795], +["1nb6",2.6,3.20729667059997], +["1p7h",2.6,3.25643110851844], +["1e78",2.6,3.40716527687089], +["2cby",2.6,2.50828784692459], +["1fdz",2.6,2.87039313867239], +["1flg",2.6,3.29298654696381], +["1il2",2.6,3.16457516010819], +["1bvz",2.6,3.03507294374661], +["1tlf",2.6,3.52938666442310], +["1hyn",2.6,3.06908055569379], +["1e50",2.6,3.09421013280177], +["1t5l",2.6,3.08632096789725], +["1c4z",2.6,3.51235928376752], +["1v9d",2.6,3.12283395966991], +["1amo",2.6,2.92602825697817], +["1j38",2.6,3.36279691960762], +["1ma1",2.6,2.62251646328812], +["1vrb",2.6,2.77924935729588], +["1v1b",2.6,3.28618180128521], +["1y19",2.6,2.79770378570142], +["1cvj",2.6,3.60537225987651], +["1mwu",2.6,2.91424225374983], +["1sof",2.6,2.62754042405933], +["1esn",2.6,3.76425337683847], +["1mpm",2.6,2.95582576472542], +["1o8q",2.6,2.4776796966468], +["1eav",2.6,2.56101065158287], +["6pfk",2.6,2.46303020979361], +["1f31",2.6,2.71425342490571], +["1s0g",2.6,2.55948487360399], +["1o8c",2.6,1.94172264508122], +["1wyg",2.6,3.14243160256383], +["1mlv",2.6,3.12403969696666], +["1pwh",2.6,3.16904198087073], +["1qr7",2.6,2.65294666644515], +["1ywg",2.6,2.42058658111756], +["1ay0",2.6,2.67331178980768], +["1t9k",2.6,3.18842916688047], +["1yo6",2.6,3.20798757786972], +["1a4l",2.6,2.91879625092009], +["1o9k",2.6,3.33758455499771], +["1c4r",2.6,2.77700461682625], +["1htt",2.6,2.92498142533278], +["1ebu",2.6,3.08872870205362], +["1ml1",2.6,2.40427067892381], +["1z68",2.6,3.30165402627859], +["1ewe",2.6,2.98723481273511], +["1j2e",2.6,2.67566898504437], +["1mqm",2.6,3.33977723338785], +["1q12",2.6,3.41876205353929], +["1bpo",2.6,3.88290504213682], +["1kmm",2.6,3.04724818571085], +["2ajt",2.6,2.86676423004843], +["2b37",2.6,3.03739176208063], +["1hge",2.6,2.72718382180357], +["3pfl",2.6,3.01657768074870], +["1zxe",2.6,2.82135455376231], +["1bkg",2.6,2.62274478848704], +["1wgz",2.6,2.69397916606858], +["1x8m",2.6,3.30416443138934], +["2a1s",2.6,2.8834969218578], +["1egc",2.6,3.45625976121844], +["1ng9",2.6,2.22637787696133], +["5xim",2.6,2.15564323846265], +["1n8p",2.6,3.81602121794054], +["1yf1",2.6,2.51365680866456], +["1s00",2.6,2.90429490539791], +["1aig",2.6,2.75775466315135], +["1ybg",2.6,2.55004805444099], +["1uyv",2.6,2.9386329905462], +["2fwr",2.6,3.78016562528955], +["1j2p",2.6,3.18236722894751], +["1qpn",2.6,3.15567679517595], +["1bfo",2.6,3.55052265186666], +["1xtv",2.6,2.91819432428430], +["1yp3",2.6,3.27515191087054], +["1m8p",2.6,3.24271800162525], +["1b6c",2.6,2.8739325702343], +["1x9f",2.6,2.47741863151652], +["1re5",2.6,3.08481368408617], +["1i01",2.6,2.54340161777888], +["2bjy",2.6,2.38512426388924], +["1ulj",2.6,2.32755952047645], +["1gkr",2.6,3.22834038303041], +["1yov",2.6,3.20203649751678], +["1gkq",2.6,1.73496130258623], +["1cr7",2.6,2.55510988432513], +["1f33",2.6,2.45042753372636], +["1yrl",2.6,3.11085895770620], +["2euh",2.6,2.53212021240258], +["2avf",2.6,2.52254632279746], +["1xpq",2.6,3.2681326797876], +["1jbq",2.6,3.08102310554849], +["1l0n",2.6,3.38132098445655], +["1w0c",2.6,2.84244642678962], +["1bvp",2.6,2.93994475154401], +["1ntz",2.6,3.16391908426826], +["1ntk",2.6,3.59751937604545], +["1fzh",2.6,2.62395988859809], +["1i32",2.6,2.70715791128154], +["1efl",2.6,3.51454774033052], +["1efk",2.6,3.64508824141551], +["1ogp",2.6,2.88187035124089], +["1g2v",2.6,2.22410641674502], +["1pl0",2.6,2.85009089058119], +["2c2b",2.6,2.34317602462424], +["1t8s",2.6,2.96820628333008], +["1kif",2.6,2.6434669717005], +["1q5q",2.6,2.73337082070283], +["1xnw",2.6,3.58482452257304], +["1jts",2.6,3.0320829406972], +["1vq5",2.6,2.90826955551035], +["1yij",2.6,2.88676841949261], +["1p8j",2.6,2.46993900325997], +["1o00",2.6,1.86248469533228], +["1n4s",2.6,2.43382610489682], +["1iwa",2.6,3.02491259531310], +["1yg8",2.6,3.15156836420104], +["1n6e",2.6,2.95987483297947], +["1iw7",2.6,4.15393113756919], +["1jz1",2.6,3.41610921659342], +["1jz0",2.6,3.41887558405053], +["1nkt",2.6,3.02519890882756], +["2g1l",2.6,1.87257613300203], +["1yy9",2.61,3.15657590865401], +["1g5s",2.61,3.03061273859413], +["1y1i",2.61,2.14829172701255], +["1rjg",2.61,2.26072696652499], +["1zjn",2.61,2.59541788694599], +["2hmy",2.61,3.00844595127137], +["1wwm",2.61,3.18783289568865], +["2c2e",2.61,3.61553722251783], +["1rk0",2.61,2.39804647967106], +["1tg8",2.61,3.81750886627346], +["2c6w",2.61,3.33386461283372], +["1uej",2.61,2.45230504148663], +["2bww",2.61,1.65195830272046], +["1u65",2.61,2.88654169866606], +["2ffi",2.61,3.56199423492364], +["1fmx",2.61,3.40524295021198], +["1j1d",2.61,3.28921250802304], +["2bas",2.61,2.54619622031182], +["1t4c",2.61,2.92483928001528], +["2c2g",2.61,2.97595260514724], +["1ptj",2.61,3.36383277283695], +["1eqg",2.61,2.80433974688373], +["2c6t",2.61,2.76917304456426], +["1z69",2.61,2.75872556781792], +["1vl6",2.61,2.54946755932573], +["1zmb",2.61,3.13872855406719], +["1e1q",2.61,2.98135645897406], +["1v7o",2.62,3.48067986350581], +["1jfi",2.62,3.04231504569529], +["1b1x",2.62,3.05161541454299], +["1dd1",2.62,2.84992576646583], +["1rkw",2.62,3.49755569973627], +["1nva",2.62,2.84424280562701], +["1oyh",2.62,3.17899121527375], +["1e05",2.62,2.82959712033665], +["1lwc",2.62,3.34053769971019], +["1glf",2.62,4.14761375101454], +["1e1c",2.62,2.71883922694971], +["1jr4",2.63,3.01003336851874], +["1f0q",2.63,3.31440640928461], +["1vgn",2.63,2.67218218828911], +["1wdz",2.63,2.44805232584009], +["1y8p",2.63,2.71232244296804], +["1rzo",2.63,3.49041747392613], +["2fol",2.63,2.70092024207079], +["1qiv",2.64,3.48635693123508], +["1jxi",2.64,3.06654639694332], +["2cx3",2.64,3.15485869958791], +["1z9c",2.64,3.25805703072469], +["2f86",2.64,3.14852339456061], +["2hsd",2.64,3.29386308208392], +["1reu",2.65,3.02939513799372], +["1nfh",2.65,3.27447240638356], +["1xtr",2.65,3.23863359027066], +["1wqf",2.65,2.30790612504937], +["1r95",2.65,2.79128543124918], +["1ysz",2.65,2.20150391063575], +["1mzp",2.65,3.02416846821157], +["2c23",2.65,2.63231945626718], +["1ksv",2.65,3.05159846787018], +["1hjc",2.65,3.11744662604127], +["1sd7",2.65,3.43640339397853], +["1sd6",2.65,3.08150684857621], +["1ynm",2.65,3.21048733346187], +["1bw8",2.65,2.76037169342372], +["1kpi",2.65,2.41722270123853], +["1jqq",2.65,3.20749131002560], +["1u5c",2.65,2.33409884896839], +["2azq",2.65,3.20072873357882], +["1w3a",2.65,3.0222176388824], +["1tdc",2.65,3.63375342038293], +["1tdb",2.65,3.72138403102006], +["1fcv",2.65,2.65609808567228], +["1a3f",2.65,2.998532554773], +["1jma",2.65,3.29367983348282], +["1yw8",2.65,2.87808128497491], +["2atx",2.65,2.90125940701740], +["1r76",2.65,2.91502253985549], +["1qlf",2.65,2.46511601392899], +["2c50",2.65,2.57025829337147], +["1ytk",2.65,3.13527143737549], +["1q0l",2.65,2.12421598505204], +["1q5e",2.65,3.56471957802544], +["1b3n",2.65,2.9434925445259], +["1lil",2.65,4.12495596755228], +["2b2v",2.65,3.82990221519551], +["1ni5",2.65,3.41390634283425], +["1cfn",2.65,3.38107932847427], +["4znb",2.65,2.35493182829464], +["1w0f",2.65,3.53900878346956], +["1dkw",2.65,2.69856398803967], +["1bj4",2.65,2.38575729755037], +["1e3c",2.65,3.16898557195843], +["2axj",2.65,3.05077340485088], +["1oe6",2.65,3.29491411408712], +["1y0s",2.65,2.72402078394280], +["1o99",2.65,2.14454240375502], +["1nyx",2.65,3.74484969172175], +["1kg0",2.65,3.42396079894133], +["1hlu",2.65,3.71314053923326], +["1m9s",2.65,3.56623723473506], +["1qii",2.65,2.63068298628869], +["1hk1",2.65,2.91670886684819], +["2iff",2.65,3.10530438603275], +["1xdt",2.65,2.81212295308781], +["1dew",2.65,2.59392776587804], +["1u7d",2.65,3.07093517480444], +["1vqv",2.65,3.17060406958159], +["2bxn",2.65,2.93435452046180], +["1akj",2.65,2.27491145950500], +["1ihd",2.65,2.31299205765335], +["1bui",2.65,3.70398459912786], +["1pvr",2.65,3.76193281737668], +["1glc",2.65,3.95211067526235], +["1gzm",2.65,2.89511496229164], +["1m9i",2.65,3.39758098697228], +["2asl",2.65,2.4051352542757], +["1dtz",2.65,3.62714084449479], +["1u22",2.65,3.83499904110827], +["1m1a",2.65,2.91703187672583], +["1ffo",2.65,3.21506278702888], +["1vi5",2.65,2.43912924508678], +["1g8r",2.65,3.34278572342948], +["1pcr",2.65,3.29566249781391], +["1h4l",2.65,3.25990303472862], +["1key",2.65,3.22767075157033], +["1nf7",2.65,3.74964312527055], +["1k62",2.65,2.6747039448444], +["1rq0",2.65,3.59999997822522], +["1m1l",2.65,2.66391026558325], +["1klm",2.65,3.06965142100593], +["2b6a",2.65,3.37043996708923], +["1q83",2.65,2.24762532074555], +["1nno",2.65,2.41308692153268], +["1u9y",2.65,2.52052613256737], +["7prc",2.65,2.84457725103904], +["1xea",2.65,2.99479747640428], +["1dbz",2.65,2.2859970318559], +["1j4e",2.65,3.00422635545182], +["1ggt",2.65,3.46069769292037], +["1l3b",2.65,2.89368752982034], +["1flo",2.65,3.05903391705762], +["1ahj",2.65,2.55756238278378], +["2c4k",2.65,3.18917853269482], +["1jre",2.65,2.74782018945640], +["1hkx",2.65,3.42961968896085], +["1bjq",2.65,2.89658018793658], +["1c9b",2.65,3.46623349246575], +["1ag8",2.65,2.76958178424170], +["1aw2",2.65,2.96603052996035], +["1la2",2.65,3.11453938526700], +["1yi2",2.65,2.88781825260931], +["1nzw",2.65,2.06822277168515], +["1n4p",2.65,2.51154378795639], +["2fjf",2.65,2.89919665823929], +["1q3g",2.65,2.44625313572196], +["2a5g",2.66,1.95496789530387], +["1pqw",2.66,2.65308355824032], +["2bov",2.66,2.59018736924343], +["1cbv",2.66,3.8278566441836], +["1qgl",2.66,2.08279477674641], +["1ude",2.66,3.64029321079251], +["1oay",2.66,2.66273251825686], +["1svu",2.66,4.33605578624081], +["1yrg",2.66,2.89530012815090], +["1qm4",2.66,3.72027653374199], +["2bub",2.66,3.84584332793462], +["1eak",2.66,3.64815697115054], +["108m",2.67,2.77217406854204], +["3fua",2.67,2.92416634516687], +["1vpa",2.67,2.02999027862386], +["1ef7",2.67,3.10934275768153], +["2g0t",2.67,1.24616959708907], +["1cd1",2.67,3.63933624873021], +["1rqr",2.67,2.32457197923756], +["2bhs",2.67,2.77540253419067], +["1uwe",2.67,3.12500569997915], +["1zxv",2.67,3.26875724528732], +["1bdj",2.68,2.52048753641836], +["1ecz",2.68,3.36806326233000], +["1x90",2.68,2.98407308587709], +["1w3g",2.68,3.25909473055125], +["2c4y",2.68,2.41860126869729], +["1gtu",2.68,2.45686259005466], +["2bix",2.68,3.37832522072471], +["1pg8",2.68,2.74150442817477], +["1u78",2.69,2.94263956577294], +["1r7h",2.69,1.45628115634790], +["1vis",2.69,2.99073982627612], +["1e77",2.69,2.34679875726429], +["1hl1",2.69,2.50065809690368], +["1f4u",2.69,3.27970713745466], +["1s77",2.69,3.71258134266883], +["1ht8",2.69,2.83394499374620], +["1jll",2.69,3.20168566821857], +["1yfj",2.69,2.92159041558688], +["1sqb",2.69,2.83933765345011], +["1q9x",2.69,3.27871348899702], +["1u42",2.7,2.63821058734009], +["1h8k",2.7,3.95890376594833], +["1csq",2.7,3.19803199782098], +["1df5",2.7,3.65968263071637], +["1vbv",2.7,3.44961411297815], +["1qxx",2.7,3.34882324546603], +["1b5m",2.7,3.89069652005879], +["1f1f",2.7,3.13233934198235], +["1cit",2.7,3.0950371738984], +["1y47",2.7,3.38741103116226], +["1sj4",2.7,2.51636506377375], +["1vbx",2.7,2.74142126512031], +["1hhp",2.7,2.49115421361183], +["3phv",2.7,4.33505906644047], +["1mil",2.7,3.77047221555965], +["3bmp",2.7,2.67319322712266], +["1kql",2.7,2.87082329043916], +["1jd6",2.7,1.95853622243921], +["1pil",2.7,3.12184116558690], +["1d66",2.7,3.45299790419183], +["2lve",2.7,2.36498393963927], +["1apl",2.7,3.6722281207465], +["1lsx",2.7,2.27462550549115], +["1tc8",2.7,3.53704070872388], +["1rs4",2.7,1.81240896638952], +["1rry",2.7,2.53444812052639], +["2fnx",2.7,3.25166251869457], +["1k58",2.7,3.65093151416823], +["1dcy",2.7,2.96253225068255], +["1rbj",2.7,4.20181091409714], +["1xsd",2.7,3.43878363103755], +["1azu",2.7,4.31347057345396], +["1acd",2.7,2.23419551837552], +["1pbi",2.7,2.98429677533532], +["1bow",2.7,3.78815445784091], +["2a1j",2.7,3.75282232677753], +["1r2g",2.7,2.93804783873821], +["1was",2.7,3.72736854764075], +["1ri7",2.7,3.34741412807285], +["1pae",2.7,2.53450192982058], +["1vk9",2.7,2.35814465812342], +["1f9j",2.7,2.77817301919873], +["1qcq",2.7,2.81348108029579], +["1xtd",2.7,2.5967528929589], +["1aep",2.7,3.10883371317826], +["1n5z",2.7,2.74823368601338], +["1jh1",2.7,3.05284560668462], +["2bps",2.7,3.56501389225092], +["178l",2.7,3.652268541666], +["179l",2.7,4.1354654278083], +["2g7r",2.7,3.00125273071714], +["209l",2.7,4.38345629571878], +["1krq",2.7,1.44434520840677], +["1gnp",2.7,3.43482465391658], +["1c3g",2.7,3.72986094557250], +["1kb2",2.7,3.13682926713177], +["1bvo",2.7,3.40030385012574], +["1qhn",2.7,2.60115081544847], +["1cdu",2.7,3.66956407118717], +["1b87",2.7,2.43797899270619], +["1tbx",2.7,3.15344619883258], +["1yk9",2.7,3.57394375292106], +["2c3x",2.7,3.04920155700402], +["1v1g",2.7,3.55562677343305], +["1jd4",2.7,3.16154853506014], +["2cwe",2.7,3.34024663187488], +["1pex",2.7,3.70001852114411], +["1kb6",2.7,3.37425441616206], +["1bnk",2.7,2.87495313772929], +["2fde",2.7,3.00494745841120], +["1rv7",2.7,4.04468334338045], +["1xzd",2.7,2.53189529096469], +["1fap",2.7,3.23044015883688], +["1i5k",2.7,3.57566314494705], +["1eia",2.7,3.23576751812114], +["2gkw",2.7,3.07629498423981], +["2ccu",2.7,3.660711448786], +["1lm3",2.7,3.00844259958465], +["2d2a",2.7,3.48006424063361], +["1r8d",2.7,3.01413673903419], +["1qx6",2.7,2.95859880701591], +["1ldq",2.7,3.04279232659622], +["1x3f",2.7,3.2176503460645], +["1ncn",2.7,2.77554863116597], +["1yc8",2.7,2.4869775493173], +["1qz8",2.7,3.25732794343465], +["1fbm",2.7,3.28610798526501], +["1yzz",2.7,2.59403261349305], +["1w97",2.7,3.81330411173357], +["1i7f",2.7,2.99844669616584], +["1rlg",2.7,3.17809373954537], +["1ktr",2.7,2.57413532850656], +["1f3o",2.7,3.03176628451304], +["1o9f",2.7,2.74701886931368], +["5gch",2.7,3.78261282752422], +["1nlt",2.7,4.0699140297376], +["1se2",2.7,3.83419181269346], +["1z33",2.7,2.79894268434731], +["1mh2",2.7,2.53615572756268], +["1xxw",2.7,2.97933406405236], +["1qao",2.7,2.70907873418643], +["1g3r",2.7,2.63403589458702], +["1zhp",2.7,2.92092376917543], +["1lbd",2.7,4.00071298384392], +["1csg",2.7,2.95645905921971], +["1zqz",2.7,3.95497423367154], +["1zqv",2.7,4.05265540621802], +["1ozy",2.7,3.87878346913193], +["1dpd",2.7,2.52383145500080], +["1tj4",2.7,2.67466042858045], +["1avd",2.7,3.9537717139675], +["1nax",2.7,2.10705764684086], +["1hf0",2.7,3.34777899969499], +["1s03",2.7,3.06593181170163], +["1ri2",2.7,3.08539106049220], +["1ldi",2.7,2.44785949931999], +["1mih",2.7,2.48793565479768], +["2bt1",2.7,2.95832290156848], +["1u12",2.7,3.29483131965083], +["1bxx",2.7,2.80537561661043], +["2c9a",2.7,3.04372721239018], +["1rwm",2.7,2.60238924726198], +["1b8x",2.7,4.27082532213352], +["1cnf",2.7,3.68632914073462], +["1ef9",2.7,3.88510233586994], +["1a25",2.7,2.66934419636814], +["1bar",2.7,4.01274411648847], +["1ov4",2.7,2.52105165283424], +["2b0q",2.7,3.18537112835936], +["1xj7",2.7,3.58026263475365], +["1enz",2.7,4.05880700860244], +["1zid",2.7,3.39686349260879], +["1pja",2.7,2.67452342938444], +["1nh7",2.7,3.44113979719128], +["1x6u",2.7,3.39250872078854], +["1phq",2.7,3.95711818138343], +["1q3n",2.7,4.00122133459605], +["1cbi",2.7,2.78523732835275], +["1wkk",2.7,2.40483433514409], +["1w2n",2.7,2.72150563370496], +["1t7w",2.7,2.53453264024569], +["1eja",2.7,2.75868200090407], +["1q77",2.7,2.73740526318087], +["1fdw",2.7,3.61598036007808], +["1vg3",2.7,3.08158568822032], +["1rkc",2.7,4.19081294479953], +["1t4j",2.7,2.18442609656693], +["1iql",2.7,3.52671739667252], +["1fst",2.7,2.88028785751408], +["1c4y",2.7,3.84255361393052], +["2hco",2.7,3.07430493248550], +["1hco",2.7,4.24952245220149], +["1qfc",2.7,3.36539870386113], +["1lqd",2.7,2.99537885587793], +["2bmg",2.7,2.87863008253580], +["1wpt",2.7,3.47261958833916], +["1h3d",2.7,3.3766197107093], +["1v2h",2.7,3.57717825295173], +["1xrm",2.7,3.00881200411654], +["1to3",2.7,2.31817303078476], +["1ufl",2.7,3.31694433402076], +["1jbt",2.7,3.42339391577017], +["5ptd",2.7,3.29551633583482], +["1glv",2.7,3.61843272025597], +["1kc3",2.7,2.6025806712173], +["2auj",2.7,3.30905759944413], +["1t5j",2.7,2.74003728915373], +["1ecr",2.7,3.19434567378355], +["1udi",2.7,2.40956936043808], +["1ygj",2.7,3.25938724207817], +["1gag",2.7,2.53735347893615], +["1gjv",2.7,3.21255888864659], +["1n3c",2.7,2.86669756395794], +["1a1s",2.7,3.55580047002941], +["1wwh",2.7,3.12821710120453], +["2snw",2.7,3.13112626093181], +["2fzf",2.7,3.24542879409949], +["3ts1",2.7,2.84106982915417], +["2tdd",2.7,3.43080167089335], +["1zhi",2.7,2.97579581544644], +["1qub",2.7,2.62346706918002], +["1fmu",2.7,3.58118427936797], +["1l8q",2.7,3.29116402432793], +["1z7y",2.7,3.23096986166641], +["1z74",2.7,3.06085672170483], +["1sps",2.7,3.12728556894622], +["5mht",2.7,2.32592758596360], +["4mht",2.7,2.75935279626470], +["3mht",2.7,3.06014718622326], +["9ick",2.7,3.88168662382335], +["8ico",2.7,4.06094425254122], +["8ick",2.7,4.03090800927963], +["9icv",2.7,4.0749538344065], +["1zqi",2.7,4.00587883954685], +["1qsp",2.7,2.64650763280551], +["1fq6",2.7,3.36976368536037], +["1uki",2.7,3.88840333573406], +["1lf3",2.7,3.28367208655946], +["1on7",2.7,3.59636454337835], +["2cg5",2.7,3.08672706354985], +["1t97",2.7,3.61187931662767], +["5ldh",2.7,5.10372430880316], +["1mkj",2.7,2.7391278635991], +["1xdu",2.7,2.74844054532091], +["1yci",2.7,2.67884623201196], +["1bdh",2.7,3.78500246657639], +["1qqb",2.7,3.78546518640938], +["2pub",2.7,3.88836725009159], +["2pug",2.7,3.75966553608826], +["1zay",2.7,3.83448921368685], +["1vpw",2.7,3.91261690079784], +["2pue",2.7,3.92665422871556], +["1pnr",2.7,3.98315401374408], +["1pmu",2.7,3.37154093578194], +["1gfp",2.7,2.65453164488025], +["1y6n",2.7,3.01443116277398], +["1x77",2.7,2.64795118422277], +["1v34",2.7,2.75047903796326], +["1e5w",2.7,3.41414200074230], +["1z6x",2.7,3.02843263428428], +["2f7s",2.7,3.02036739204235], +["1yvb",2.7,3.69242039551038], +["1exu",2.7,3.39565210887895], +["2cpk",2.7,2.71883433925634], +["1w33",2.7,3.73513059030859], +["2rmp",2.7,3.22863412342457], +["2fm2",2.7,2.92779340889477], +["2aew",2.7,3.29062002703926], +["1iud",2.7,3.21959276029587], +["1qnl",2.7,2.97010600191023], +["1exc",2.7,3.27018518495034], +["1vhg",2.7,2.9934830755756], +["1a2l",2.7,2.41801042430587], +["2ach",2.7,3.32586882514542], +["1xtj",2.7,3.1358298862599], +["1vgp",2.7,2.82988174411962], +["1a2m",2.7,2.48108611598891], +["1adg",2.7,3.33047325547247], +["1atu",2.7,4.34393657038179], +["1qqd",2.7,3.02934346091160], +["9pai",2.7,3.07891138495566], +["1p9w",2.7,2.83164245782489], +["1bho",2.7,3.24135902477246], +["1idn",2.7,3.25310498157455], +["1bhq",2.7,3.40206263009735], +["1v1p",2.7,3.09221574393558], +["1dl3",2.7,2.90452278462295], +["1a02",2.7,3.32931267529361], +["2a8p",2.7,2.43874620131750], +["1cg9",2.7,2.28539181492043], +["1bms",2.7,2.32052785502467], +["1zdi",2.7,2.55470727180827], +["1zdh",2.7,2.47593766277000], +["1kuo",2.7,2.38293359530701], +["1ffw",2.7,2.29758732517062], +["1pa3",2.7,3.07641064167886], +["1vol",2.7,3.70792475989145], +["1pmp",2.7,3.36223858183037], +["1pbf",2.7,2.43386676290958], +["2phh",2.7,3.34701903550007], +["1cuw",2.7,2.79116264110157], +["1xhm",2.7,2.81538772548954], +["1dt9",2.7,4.03106976413354], +["1cq6",2.7,3.46580813501133], +["1ams",2.7,3.46572715710785], +["1run",2.7,3.91119225395913], +["1tqe",2.7,3.47243523163165], +["1ruo",2.7,4.19527725696466], +["1k03",2.7,2.4067959021965], +["1bwl",2.7,2.89069668084286], +["1k02",2.7,2.79708228889578], +["2b0z",2.7,3.08475018713860], +["1bjy",2.7,2.27709712009711], +["1qs2",2.7,2.59767870907172], +["1n11",2.7,3.68924503182954], +["1tq6",2.7,3.06034130512308], +["1vrr",2.7,3.03226996124780], +["1ue6",2.7,3.53957567303775], +["1i69",2.7,3.33299093285391], +["1ci0",2.7,3.43000318554461], +["2eia",2.7,3.34395612656085], +["1i1c",2.7,2.60476514575748], +["1w7m",2.7,3.01213392486798], +["1ika",2.7,3.62423997964172], +["1jn6",2.7,3.28708960013813], +["1iay",2.7,2.86309943730587], +["1ghf",2.7,3.78908824235902], +["1nkm",2.7,3.60699921013306], +["1d6n",2.7,4.48908179922688], +["2bga",2.7,2.62465293100079], +["1uev",2.7,2.94004376269049], +["1mf1",2.7,3.10012092326664], +["1a8j",2.7,4.30426566253311], +["1mcl",2.7,4.03699369117441], +["1mcr",2.7,4.17813210359709], +["1cf8",2.7,2.99734991941179], +["1hcf",2.7,2.92308620965123], +["1mcn",2.7,4.02055908643432], +["1mcq",2.7,4.00184285667756], +["1mci",2.7,3.96839764312739], +["1ibg",2.7,3.31089288097723], +["1xae",2.7,3.63517849470346], +["1mck",2.7,3.89417568724948], +["1mcd",2.7,3.89724888643494], +["1mcj",2.7,4.10334117890879], +["1mcb",2.7,3.83682983346721], +["1mcs",2.7,4.14301999983943], +["1igi",2.7,3.14000803337349], +["1fai",2.7,3.51156985363626], +["1dbj",2.7,3.39198642046726], +["1dbm",2.7,3.50072560971979], +["1dbb",2.7,3.74924170263932], +["4fab",2.7,4.74322479466144], +["1mch",2.7,3.70372951037750], +["1mcf",2.7,3.89692774504044], +["1mcc",2.7,3.89523577028024], +["1mce",2.7,4.12628364204758], +["1hh9",2.7,3.33111317096056], +["1dn2",2.7,1.82512346525517], +["1cts",2.7,3.51272861815402], +["1eba",2.7,3.14814474029117], +["1s5i",2.7,2.98094814062491], +["1dfb",2.7,3.47267597382417], +["1jaw",2.7,2.64671195306007], +["1ces",2.7,2.97975765160821], +["1mcp",2.7,4.10640666061659], +["1gsf",2.7,2.51017081748445], +["1sxt",2.7,3.38593856686188], +["1af9",2.7,3.06843237884565], +["1kix",2.7,2.25887835758657], +["1ru8",2.7,3.32635790336841], +["3znb",2.7,3.08703510813825], +["1q31",2.7,3.63086147399529], +["1z4w",2.7,2.70185374843883], +["1u0o",2.7,3.5143374262527], +["2beo",2.7,2.66795745725592], +["1ira",2.7,2.33445589948203], +["1ioa",2.7,3.30757685339428], +["3sxl",2.7,3.73481901071419], +["1k88",2.7,3.69036923043721], +["1uur",2.7,3.08754280192337], +["1yy4",2.7,2.74474674225782], +["1kv6",2.7,3.22235136984985], +["1fvp",2.7,4.14281826882508], +["1bbw",2.7,3.07629589521281], +["2grt",2.7,2.75713606088519], +["1jp5",2.7,3.06086557876132], +["2c74",2.7,1.82080087952732], +["1qvn",2.7,2.33156577761307], +["2cah",2.7,2.62122458841654], +["2cag",2.7,2.76850538576423], +["1za7",2.7,2.42175442831212], +["1gxc",2.7,3.14671567331711], +["1lap",2.7,2.93155931378153], +["1ud5",2.7,2.69313423904107], +["1yfk",2.7,2.80897595303556], +["2axh",2.7,3.16093569505401], +["1xq4",2.7,2.83378090223227], +["1bbu",2.7,2.36940968561581], +["1o8o",2.7,2.26726538831039], +["1tdk",2.7,2.51810728263508], +["1tdn",2.7,2.5904087574039], +["1ggp",2.7,4.23509077376079], +["1ybw",2.7,3.12496249189070], +["1su5",2.7,2.01381342867674], +["2mll",2.7,3.89609187568425], +["1ce7",2.7,3.89993493885702], +["1nt0",2.7,3.00980972278613], +["1uos",2.7,3.08900311046586], +["1gme",2.7,2.90468901304201], +["1hzu",2.7,2.8629326160856], +["1yfi",2.7,2.4734188435728], +["1hyr",2.7,3.39513313868904], +["1oce",2.7,3.76618574839563], +["1n7j",2.7,3.09230362800014], +["1jut",2.7,2.63979923845273], +["1qrt",2.7,3.03049967281251], +["1exd",2.7,3.43477768891539], +["1o0b",2.7,3.1352151926311], +["1yh8",2.7,2.28940697877403], +["1sq4",2.7,3.14211613712253], +["1i4l",2.7,3.53208401123621], +["1dx4",2.7,3.27176038774904], +["2bm7",2.7,3.21960874944808], +["1nqf",2.7,3.98614594556459], +["2cw7",2.7,3.14672235223683], +["1qo9",2.7,3.9821186503534], +["1bhc",2.7,2.69774405602001], +["1yjd",2.7,3.79093576943996], +["1ram",2.7,3.67409476334332], +["1ddl",2.7,2.91264007575427], +["1zd4",2.7,3.12066449162487], +["2azk",2.7,3.27815062814351], +["1hu8",2.7,3.37952913554272], +["1rlc",2.7,3.06656894893519], +["1zlp",2.7,3.5316974208274], +["1ygf",2.7,3.15484359405822], +["1yg5",2.7,3.54095351367075], +["1wv7",2.7,2.57545692959391], +["1czz",2.7,2.76200444234705], +["1xb1",2.7,3.02244132865593], +["1xd8",2.7,2.80820148110087], +["1dib",2.7,1.89165492114109], +["1hq6",2.7,2.82665603452941], +["1yhz",2.7,2.40925992695505], +["1yi0",2.7,2.40213117582432], +["1yhy",2.7,2.48074186875244], +["1hk5",2.7,2.53305954854623], +["1e7i",2.7,3.47828472980413], +["1lei",2.7,3.57113044824805], +["1cud",2.7,3.54708421376646], +["5crx",2.7,4.05457219119565], +["1tz6",2.7,3.21342290070997], +["1zun",2.7,2.73732108073169], +["1m7n",2.7,2.8212116087659], +["1u7v",2.7,3.29162137858090], +["2amp",2.7,3.71334500540117], +["1s70",2.7,3.34621799482834], +["1ng0",2.7,2.4003182527957], +["1xm5",2.7,3.367928383315], +["1h7u",2.7,2.72827805954411], +["1ea6",2.7,2.73422985440648], +["1lwi",2.7,3.06402155023311], +["2d2d",2.7,3.36830056476297], +["1ieq",2.7,2.42804012572747], +["1lq2",2.7,2.82001915426468], +["1jwm",2.7,2.97696217442546], +["1nam",2.7,3.67858458916478], +["1r11",2.7,3.55926592119729], +["1tf0",2.7,3.14867784514243], +["1tlt",2.7,3.39798661447479], +["1hde",2.7,2.51663721733754], +["1wpx",2.7,2.94540388802349], +["1fbf",2.7,2.59247530275754], +["1azw",2.7,2.86466297390545], +["1xk8",2.7,1.39283631852524], +["1vbm",2.7,2.99673603908153], +["1vbn",2.7,3.36335443225343], +["1fwr",2.7,2.59451560201139], +["1r5j",2.7,3.64503477393232], +["1me6",2.7,3.35198555377467], +["1sme",2.7,3.48331754338637], +["1m1m",2.7,3.53786738401400], +["1bt1",2.7,3.09717502277944], +["1bt2",2.7,3.29699982960204], +["1bug",2.7,3.40589668877134], +["2dld",2.7,4.32824560836013], +["1nuf",2.7,2.83570879738950], +["1bgw",2.7,3.52890860216851], +["2bse",2.7,2.72332776526945], +["2au0",2.7,3.51965120587924], +["1s0m",2.7,2.68280674873922], +["1i3o",2.7,3.07667404609446], +["1vh3",2.7,3.13180867513380], +["1dr8",2.7,3.90914394095309], +["1w59",2.7,3.29720494558252], +["1f9b",2.7,3.28170439795194], +["1i6q",2.7,4.11091109185845], +["1lqs",2.7,3.02407034216358], +["2fpi",2.7,3.41754765351063], +["1bvk",2.7,3.66336550451821], +["1r5k",2.7,3.00598936938302], +["1kjy",2.7,3.07116001798639], +["1z25",2.7,3.15200992659533], +["1dtw",2.7,3.18535165529901], +["1fcp",2.7,3.27940581501762], +["1qff",2.7,3.19561726440554], +["1l8x",2.7,3.62144010726487], +["1nl4",2.7,3.46236504538172], +["2vsg",2.7,3.18358325585805], +["1qe0",2.7,3.5537271653467], +["1ecx",2.7,2.53007434514438], +["2a59",2.7,2.69139500156392], +["1di0",2.7,3.38886087689766], +["1kp0",2.7,2.62900324433191], +["1kz6",2.7,2.4870292004895], +["1mne",2.7,3.48276266794805], +["1hh4",2.7,3.4407556327455], +["1pok",2.7,3.11391637356112], +["1qty",2.7,3.85589018582154], +["1teh",2.7,3.21551968416669], +["1p34",2.7,2.49968007269705], +["1p3g",2.7,2.67802697671286], +["1adc",2.7,3.57219795525714], +["1k8q",2.7,2.82923263995029], +["1p3p",2.7,2.64828286916342], +["1ffn",2.7,3.42353861476543], +["1til",2.7,3.09669010141408], +["1p17",2.7,3.16629562884901], +["1x9s",2.7,2.88290195729830], +["1szg",2.7,3.17972733446033], +["1zyq",2.7,2.86734603514248], +["1szf",2.7,3.02605535909036], +["1nvb",2.7,3.21079226714066], +["1tq2",2.7,3.20880769367459], +["1p16",2.7,3.09901212404399], +["1ieb",2.7,3.37455655014141], +["1h9u",2.7,2.92849533597132], +["1xd2",2.7,2.40159903176545], +["1nvw",2.7,2.43763086682809], +["1ncr",2.7,2.33753494015473], +["2pmt",2.7,2.56036544824066], +["1frf",2.7,3.11409692754532], +["1m6n",2.7,3.63653982772723], +["2beh",2.7,3.41121797953984], +["1kl2",2.7,2.97736475258419], +["1jgz",2.7,2.91755160808955], +["2bnp",2.7,2.29031148006247], +["1qj3",2.7,2.75726591537411], +["1gze",2.7,3.45630911107873], +["2fu3",2.7,3.13134528049828], +["1jgy",2.7,3.06095436296907], +["1e14",2.7,2.98636253436659], +["1m8i",2.7,2.69895647377071], +["1rqk",2.7,2.24847358734736], +["3nod",2.7,3.27413155775308], +["1k5m",2.7,2.80663928359457], +["2a5u",2.7,3.70670194164224], +["1r1l",2.7,3.18651184084571], +["1ioi",2.7,3.11197890784721], +["1t09",2.7,2.92617380987427], +["1nr9",2.7,3.29030291320763], +["1e90",2.7,3.0492138335126], +["1i3s",2.7,2.94032324482385], +["1qw5",2.7,3.08392835446764], +["1qom",2.7,3.11543243476737], +["1tel",2.7,3.27878448973638], +["1a6t",2.7,3.25078870450807], +["1c0t",2.7,3.18441987011358], +["1sfr",2.7,2.62924572631259], +["1w46",2.7,2.81887128320679], +["1hq4",2.7,3.16294947859241], +["1w26",2.7,3.49924919457739], +["2a71",2.7,2.75115810731654], +["1fve",2.7,3.3506592516416], +["1q17",2.7,3.15419257338724], +["1xm2",2.7,3.24965302320638], +["2a1w",2.7,2.63934080341145], +["1f9n",2.7,3.10685699640226], +["1a0e",2.7,2.56821643542593], +["1o7d",2.7,3.10539932233173], +["1nju",2.7,3.30795066507596], +["1b99",2.7,2.73929894585938], +["2wpo",2.7,3.4684344520746], +["1hez",2.7,3.20798087185429], +["1sus",2.7,3.69867815366166], +["1sui",2.7,3.76974702177723], +["1clq",2.7,3.32605158493312], +["1w25",2.7,2.28304778324613], +["5ttr",2.7,3.57959945436761], +["2byv",2.7,2.10854844196913], +["1s1w",2.7,3.28681177929097], +["1ezz",2.7,3.98473258916838], +["1bzw",2.7,2.14454597840130], +["1ciw",2.7,2.53290278851309], +["2csx",2.7,3.56796925050356], +["1pq2",2.7,3.23812727150337], +["2ct8",2.7,3.44981870241349], +["1n47",2.7,2.97281939635409], +["1bq3",2.7,2.68814451219612], +["3pbg",2.7,2.54553157135734], +["1tbh",2.7,3.12755925692375], +["1szq",2.7,3.14434308515631], +["1yw0",2.7,3.25848914035396], +["1hqe",2.7,3.17641319934227], +["1gxf",2.7,3.12843397751793], +["1dlo",2.7,3.23690135382593], +["1hqu",2.7,3.40157241313884], +["1khw",2.7,2.68075399416622], +["1x27",2.7,3.11892627081436], +["1xv9",2.7,3.43286966722676], +["1wpe",2.7,3.63292639588237], +["1nib",2.7,2.32848917226630], +["1p93",2.7,4.01988968266666], +["1ar1",2.7,3.04994959190288], +["1gku",2.7,3.5339435686365], +["1afc",2.7,4.20370499701598], +["1qez",2.7,2.51583617571740], +["1kl7",2.7,3.25045161011010], +["1i9b",2.7,2.87535285380075], +["1b70",2.7,3.75005512827707], +["1xf9",2.7,2.49219086016498], +["2amc",2.7,3.08193835075372], +["1nsl",2.7,3.51617480113395], +["1mhz",2.7,2.9542406222202], +["1jeq",2.7,2.99379018545465], +["2f1v",2.7,3.34984756064443], +["1ipj",2.7,3.80971449060597], +["1gjq",2.7,2.04547854860984], +["1w1l",2.7,3.05908838842719], +["1w1j",2.7,3.01992203930830], +["1ipk",2.7,4.08691787893219], +["1eqh",2.7,2.78234374011162], +["1am4",2.7,4.13501268032584], +["1ahu",2.7,3.57595122439851], +["1gy3",2.7,3.42345887953333], +["2c4g",2.7,2.65918063815725], +["1fdu",2.7,3.54238251560578], +["1n0e",2.7,3.4350615461396], +["1vkl",2.7,2.68901571524342], +["1jdy",2.7,2.74598052931753], +["1c47",2.7,2.85291477932201], +["1lxt",2.7,3.16832540595867], +["1c4g",2.7,3.35709027611522], +["2b30",2.7,2.23053704629376], +["1seb",2.7,3.18730704330011], +["1lfl",2.7,2.90010122897181], +["1nex",2.7,3.17560179484637], +["1d5y",2.7,3.37927207122532], +["1xj5",2.7,2.6651102847973], +["1ve7",2.7,3.28726804398700], +["1nxk",2.7,3.56681952775529], +["2bx8",2.7,3.18677238396015], +["2bxg",2.7,2.90296875711918], +["1g3l",2.7,2.46126584908114], +["1lbi",2.7,3.75572677100495], +["1zzh",2.7,3.2246160785685], +["2c35",2.7,3.17465277026998], +["1ws2",2.7,2.82200277017711], +["1tui",2.7,3.73981924163235], +["1dml",2.7,3.21842182530072], +["1ttt",2.7,3.75099571905016], +["1j9z",2.7,3.17290146230023], +["1kk4",2.7,3.2833134202424], +["1kk5",2.7,3.07386679533546], +["1nfi",2.7,3.34533455318413], +["2fl0",2.7,2.64792710121749], +["1kgy",2.7,3.59682712823112], +["1p73",2.7,2.83710361993145], +["1tae",2.7,2.82373122775743], +["1vcb",2.7,3.13709822074983], +["1fzf",2.7,2.96516149290090], +["1re4",2.7,3.19939049991613], +["1ii4",2.7,2.73155226996266], +["1qzt",2.7,2.64540340482355], +["1hzh",2.7,3.2273962273939], +["1ltx",2.7,3.41231378530755], +["1usx",2.7,3.3810176336938], +["1nud",2.7,2.85140105030008], +["3req",2.7,3.31652734411577], +["1tka",2.7,2.66720912615685], +["1tkc",2.7,2.80845873850044], +["1dee",2.7,2.91481166840853], +["1od2",2.7,3.41839277998139], +["1n8w",2.7,3.03621834601849], +["1s80",2.7,2.6171687335], +["1nws",2.7,2.52511051548748], +["1nwr",2.7,2.50266457488469], +["1ruy",2.7,3.14416916402564], +["1tkr",2.7,3.24590971899119], +["1o7x",2.7,3.08821485438266], +["1kxz",2.7,2.64440614979646], +["1pwu",2.7,3.22663537534422], +["1r0l",2.7,2.66225674417693], +["1hgi",2.7,2.73266270099210], +["1hgj",2.7,2.67762981236656], +["1hgh",2.7,2.77392335162635], +["1hgd",2.7,2.75079912457510], +["1fw6",2.7,3.34835623620357], +["1zhb",2.7,2.50096055675395], +["1mzo",2.7,2.75345011108879], +["1z6r",2.7,3.17556579917835], +["2ch2",2.7,2.51567207192776], +["1usv",2.7,3.33447542528333], +["1yud",2.7,3.58839790217443], +["2bwp",2.7,2.11760075069828], +["1ovw",2.7,2.83920889091809], +["1p4e",2.7,2.76757649994979], +["1p44",2.7,3.56464504313340], +["1ib1",2.7,2.79935130511239], +["1eqb",2.7,2.09421596889251], +["1adj",2.7,2.78126638431493], +["2fvi",2.7,2.12475032877049], +["4kbp",2.7,3.154890415432], +["1gul",2.7,2.73885052628181], +["1jr3",2.7,3.21849201703150], +["3lhb",2.7,1.7878338366691], +["1eqr",2.7,3.43963336362111], +["1hg3",2.7,3.21066038547353], +["4cev",2.7,2.24828469587122], +["1fag",2.7,3.25410933017301], +["1nfg",2.7,3.01890272677671], +["1ls3",2.7,2.94764566190072], +["1v6m",2.7,2.75178798431776], +["1bcp",2.7,3.59787602766772], +["1o6r",2.7,2.85286335660283], +["1tei",2.7,2.44316258293322], +["1ecb",2.7,2.96705716173497], +["1bi9",2.7,3.40247607992166], +["1sq3",2.7,2.35234505248096], +["1mb2",2.7,3.32052494502974], +["1tt7",2.7,2.89254862816777], +["1m1j",2.7,3.36080541655378], +["2ba1",2.7,3.26635613157803], +["1aw1",2.7,2.60927592255578], +["1od4",2.7,3.42069625146936], +["1zs3",2.7,2.80976812590301], +["2bku",2.7,2.39908019749743], +["1sqp",2.7,3.11672818014982], +["1ywh",2.7,3.37658334077026], +["1kf6",2.7,3.02784142212803], +["2ba0",2.7,3.04463856520359], +["1urz",2.7,2.8488774074579], +["1xhz",2.7,2.9270443813111], +["1bxn",2.7,3.09687558363852], +["4rub",2.7,3.66254819942165], +["1e6v",2.7,3.02035226838096], +["2c3o",2.7,3.16444349348597], +["1is8",2.7,2.86077316282551], +["1t8r",2.7,2.88289675947584], +["1k5d",2.7,3.34109799081614], +["2bma",2.7,3.28990187995713], +["1w8j",2.7,3.25547732928534], +["2cfy",2.7,2.40706851258413], +["2c7f",2.7,3.07130815097758], +["1l1f",2.7,3.68017604676227], +["1qk1",2.7,2.78404545204334], +["1r3n",2.7,2.73785465510499], +["1hr8",2.7,2.72436871213845], +["1ss8",2.7,2.72879116958525], +["1vq4",2.7,2.92882370353892], +["1vq6",2.7,2.94379547363099], +["1tny",2.7,2.53111362357850], +["1tno",2.7,2.35507333775190], +["1tnu",2.7,2.48860273315654], +["1aqf",2.7,3.73648174616999], +["1h2i",2.7,3.16283143945375], +["1jro",2.7,3.17186694696367], +["1t6p",2.7,3.10398765561261], +["1gt7",2.7,2.53337536012331], +["1n6f",2.7,2.9375397229976], +["1smy",2.7,3.96768802982613], +["1qox",2.7,2.23756447122614], +["1j0b",2.7,4.00290134186516], +["1jyy",2.7,3.46177844112476], +["1jyz",2.7,3.46345338485234], +["1s31",2.7,2.65737222754316], +["1po8",2.71,3.50215505721217], +["1sv9",2.71,2.75661555956119], +["2b17",2.71,2.89840072218737], +["1e31",2.71,2.97630732053807], +["1kq2",2.71,3.11078759891131], +["1z5v",2.71,3.5105944978502], +["1ga7",2.71,3.09673156095862], +["1xr3",2.71,3.03251003363421], +["1xgy",2.71,3.17785122713095], +["2f1m",2.71,2.75994875265200], +["1xjw",2.71,3.20721117792219], +["1ydo",2.71,3.29924416423024], +["1kj2",2.71,3.34847205169315], +["1pv2",2.71,3.05833122352507], +["2cy9",2.72,4.32208667019402], +["1bwz",2.72,3.33501049653490], +["2a0i",2.72,3.70121941500561], +["1c85",2.72,3.04149591506393], +["1i9i",2.72,2.94245561602026], +["1qon",2.72,3.42766522289863], +["1n54",2.72,3.41845166385329], +["1uqw",2.72,2.94671458770204], +["1t35",2.72,3.12140385079424], +["1liu",2.72,3.32060692750675], +["1rwt",2.72,1.98043013069363], +["1jc7",2.73,2.84561272582498], +["1ibc",2.73,2.72476818571041], +["1g28",2.73,2.92896960528415], +["1ygd",2.73,2.89961013087367], +["1eet",2.73,3.06734395729732], +["1h4z",2.74,3.51838298747653], +["1a29",2.74,2.13518540790833], +["1mk2",2.74,3.54027603794615], +["2aaj",2.74,2.39643173452383], +["1b6d",2.74,2.93034645216308], +["1by3",2.74,3.14777875045094], +["5rla",2.74,2.69147394144406], +["1liy",2.74,3.57393658537152], +["1jj8",2.75,2.80375341291785], +["1sjf",2.75,2.84549552681223], +["1jyu",2.75,3.49885391890894], +["1jbg",2.75,3.33152073247058], +["1vas",2.75,2.93472787137273], +["1j4x",2.75,4.18759128003479], +["1q89",2.75,3.19185736695434], +["4tss",2.75,3.76188754445959], +["1b98",2.75,3.39279859776259], +["1b8m",2.75,2.80632891187672], +["1yf5",2.75,2.18606031469625], +["1lyn",2.75,3.22080357505776], +["1hkq",2.75,3.23430389921124], +["1gzo",2.75,3.6024879960231], +["1rc8",2.75,3.31367099887851], +["1ula",2.75,4.10571583804721], +["1ulb",2.75,4.18966599510986], +["1vtk",2.75,2.561548651343], +["1tsz",2.75,3.40836636209573], +["1x0x",2.75,2.7905011768238], +["1buv",2.75,3.88263649639282], +["1rtl",2.75,2.88175302692325], +["1a6a",2.75,3.29750202911840], +["1yte",2.75,3.05347648579105], +["1v1o",2.75,2.41133213762419], +["1for",2.75,3.10594698182894], +["1h8o",2.75,2.96891686975755], +["1cfs",2.75,3.64803249523926], +["1dbn",2.75,2.84404252197765], +["1n2k",2.75,2.23616927334661], +["1zyd",2.75,3.04232190475885], +["1twz",2.75,3.08825101752305], +["1ut8",2.75,3.04111687301914], +["1ut5",2.75,3.28543463460967], +["1sxh",2.75,3.53032742975703], +["1h7a",2.75,3.43686279323468], +["1yeq",2.75,3.09137451833569], +["1do5",2.75,3.23408705339203], +["1bs2",2.75,3.01160082519423], +["1pvq",2.75,3.9111379821484], +["1rdx",2.75,4.39993931061207], +["1fml",2.75,2.49027848316030], +["1x8k",2.75,2.63208341391823], +["1yys",2.75,2.76801143965467], +["2aet",2.75,2.62721362766379], +["1fpp",2.75,3.24399258219139], +["2a57",2.75,2.45903705534583], +["1wn7",2.75,3.68536609935239], +["1p3o",2.75,2.49942740474152], +["1vz6",2.75,2.47358279459493], +["1qcw",2.75,2.96843220111843], +["1q9j",2.75,3.27094298503092], +["1oan",2.75,3.48715308428417], +["1psd",2.75,3.12178038498298], +["1rvj",2.75,2.66274371851214], +["1zlu",2.75,3.50563511271983], +["2bty",2.75,3.12667730257737], +["2c1o",2.75,3.41276071581655], +["1ati",2.75,3.14498911560458], +["1jct",2.75,2.95000638637836], +["1qoo",2.75,2.41900352789708], +["1vam",2.75,2.8881077873809], +["2ffv",2.75,3.20590405406151], +["1xup",2.75,3.95278811969898], +["1jui",2.75,2.9632617796203], +["1i5l",2.75,3.33644925466251], +["1jyc",2.75,3.33419294100662], +["1o7l",2.75,3.49917902450666], +["4ota",2.75,2.17229632652174], +["1sr6",2.75,3.67067384974137], +["1e0y",2.75,2.7994837884114], +["1ht5",2.75,3.0711329335377], +["1bko",2.75,3.35637809447629], +["1mp5",2.75,3.09851029633901], +["1le5",2.75,3.98667642829433], +["1diq",2.75,2.22821482277993], +["1t1f",2.75,3.55347322184897], +["1tqq",2.75,3.27047380780614], +["1txv",2.75,2.92721786897809], +["1j0c",2.75,3.44243143266395], +["1qxs",2.75,3.16526960542430], +["1m2v",2.75,3.03539981333762], +["1hjv",2.75,3.21274891865712], +["1vz8",2.75,3.36224039146203], +["1jvo",2.75,2.57068017530029], +["1yyl",2.75,3.08263781906730], +["1ege",2.75,3.2939058519784], +["1sxg",2.75,3.53452898735518], +["1u8r",2.75,3.0877899439628], +["1y8r",2.75,3.21773046821979], +["1smj",2.75,4.09496209386344], +["1k90",2.75,3.51720481292892], +["1td9",2.75,3.34483405438395], +["1a4z",2.75,3.00444894339488], +["1qqw",2.75,3.48145983487968], +["1liw",2.75,3.62253615509739], +["2cea",2.75,3.16253455194026], +["2ajb",2.75,3.03859748733344], +["1iru",2.75,3.18440985800321], +["1fg2",2.75,3.05574883267607], +["1a19",2.76,3.78785859261543], +["1ilh",2.76,3.55447734298258], +["8mht",2.76,2.26718813771958], +["2bob",2.76,2.63535268562949], +["1ki9",2.76,2.87678762279406], +["1b41",2.76,3.14192276703477], +["2bs4",2.76,2.81682008694253], +["1mc4",2.77,3.40210535136697], +["1q4l",2.77,2.69122785760431], +["1bd7",2.78,2.54938888269308], +["1lg1",2.78,2.86121544010232], +["1cjp",2.78,2.30326996809890], +["1oju",2.79,3.14445434469525], +["2bx4",2.79,2.48101199116015], +["1uwg",2.79,3.39721793213469], +["2br3",2.79,2.58318709221826], +["1klf",2.79,3.69438695349129], +["1jkp",2.8,2.93254494211748], +["1abq",2.8,3.50206285919088], +["1k9b",2.8,3.38430225506876], +["1ctx",2.8,4.9739258434793], +["1lfb",2.8,3.26426294422774], +["1f7y",2.8,3.66564674424912], +["1dk1",2.8,3.74544046543395], +["1h0y",2.8,3.4088863920515], +["1vc6",2.8,2.74085455295181], +["1vbz",2.8,2.91015917576762], +["1pdr",2.8,2.44737527564085], +["3hvp",2.8,3.95761641941095], +["1kx8",2.8,2.84277329148215], +["1tlk",2.8,3.44961158560827], +["1bmp",2.8,3.92745628789888], +["1f6l",2.8,2.77289238490504], +["1n9o",2.8,2.91228204251284], +["1ar2",2.8,3.55128464630192], +["1plk",2.8,3.70209769594249], +["1hdd",2.8,3.86404214815088], +["1m4m",2.8,3.69388727270014], +["1plj",2.8,3.790252549674], +["1m3w",2.8,2.67593019230049], +["1nwq",2.8,4.20990497662521], +["1qfp",2.8,2.97747203230175], +["1god",2.8,4.24361502518779], +["1uw7",2.8,3.93083439827456], +["1mae",2.8,3.18891154561987], +["1naf",2.8,3.52462985893253], +["1a0a",2.8,4.80492010013656], +["1db5",2.8,2.91032448933825], +["1d2q",2.8,3.91210435719108], +["2bow",2.8,4.14874584353958], +["1h2p",2.8,3.45731910603345], +["2drp",2.8,2.84977995803138], +["1fe3",2.8,3.52861614626067], +["2fid",2.8,2.33440353056674], +["1qa6",2.8,3.75839450108894], +["1oxz",2.8,3.77598402290025], +["1odg",2.8,3.78228715763845], +["1pll",2.8,4.42372384808489], +["2cbr",2.8,2.37814719511122], +["1o84",2.8,2.53208637538297], +["1lo9",2.8,3.67326821433366], +["1hc8",2.8,2.43893712638239], +["1xpx",2.8,3.30619381914834], +["1y39",2.8,2.85404657816104], +["1pkp",2.8,3.00146312430785], +["1fyx",2.8,3.33615114116437], +["1ril",2.8,4.15863328672259], +["2ara",2.8,3.79961166962768], +["2snv",2.8,4.05208352438621], +["1hlo",2.8,3.09647125231925], +["1asx",2.8,2.76907303097154], +["1xou",2.8,3.02306688964288], +["2mm1",2.8,4.03703720433628], +["1e0r",2.8,3.24938130430415], +["1u40",2.8,2.40201384077813], +["1rdd",2.8,4.21501368823746], +["1knj",2.8,3.29662854381591], +["1knk",2.8,3.48199552922539], +["1htn",2.8,2.91906631836968], +["1a3s",2.8,3.23071500805503], +["1jb1",2.8,3.53077452978322], +["1rx8",2.8,3.26798195444993], +["1hlz",2.8,3.75826192688261], +["1qib",2.8,2.42742961909484], +["1sk3",2.8,3.3099942570872], +["1zwl",2.8,2.24649645391124], +["1xts",2.8,2.97391599866426], +["1cid",2.8,3.96050734947424], +["1qhs",2.8,2.54246956054916], +["1wfx",2.8,2.77767743838211], +["1w2e",2.8,2.84513540773317], +["1z81",2.8,3.23458377284595], +["1bdv",2.8,2.83841798350059], +["1w8a",2.8,3.25857168815536], +["1ui1",2.8,2.68642240435324], +["1kb4",2.8,3.179728852628], +["1rw6",2.8,3.96611185577415], +["1szi",2.8,2.81886573580551], +["1lbm",2.8,2.82499422986456], +["1bdr",2.8,2.46807522261828], +["1bdl",2.8,2.95551447646758], +["2bpw",2.8,2.29882916086872], +["2bpx",2.8,2.08070831639866], +["1mui",2.8,2.64416134311610], +["9hvp",2.8,3.26698838643578], +["1zms",2.8,2.84680582221763], +["1hte",2.8,3.14484335607995], +["4fap",2.8,2.63623681727839], +["1jr9",2.8,3.62088261328909], +["3aig",2.8,2.57442277073579], +["1n5o",2.8,3.01105167538646], +["1t2u",2.8,3.34099298582339], +["1vi7",2.8,3.37934660805805], +["1g3y",2.8,3.00650468976685], +["2ahz",2.8,2.65132251229325], +["1cma",2.8,3.36075772744451], +["1k7a",2.8,2.91037711367585], +["1y01",2.8,3.80798951177115], +["1x1p",2.8,3.42116389158631], +["4pad",2.8,4.03147101144805], +["6pad",2.8,4.03998151856144], +["2pad",2.8,4.03686620823443], +["1wau",2.8,3.58562332843086], +["5pad",2.8,4.04467827974877], +["1lkv",2.8,1.91923247104765], +["1byh",2.8,3.42087143080777], +["1pad",2.8,4.04012135955669], +["1p4i",2.8,3.46869669611672], +["2c3z",2.8,3.53733744550379], +["2feo",2.8,4.35011251840375], +["1qym",2.8,2.18562426914204], +["1anb",2.8,2.99487721734576], +["2trm",2.8,3.81840767265397], +["2aem",2.8,3.06075545897399], +["1sbe",2.8,4.06468686150958], +["1xi6",2.8,2.02764756136984], +["3pgm",2.8,5.14544024655343], +["1hek",2.8,4.55325984826093], +["1iy1",2.8,3.06611178670042], +["1ycy",2.8,2.49893650299793], +["4tmy",2.8,3.34489598031255], +["1gfw",2.8,3.25476236481299], +["1skx",2.8,2.84025424660866], +["1qaq",2.8,2.91326846461682], +["1z92",2.8,3.50210486047102], +["1urt",2.8,2.85893508822791], +["1q4x",2.8,3.39240126586131], +["1una",2.8,3.39358795164836], +["1yo7",2.8,3.4432957160827], +["1nxh",2.8,3.65281668281984], +["1sax",2.8,3.15916278654999], +["3hip",2.8,2.61814261313902], +["2bpc",2.8,3.75307759807139], +["1clp",2.8,4.33571866767033], +["2csm",2.8,2.49318629155735], +["1tj3",2.8,2.75397954545958], +["1ave",2.8,3.88936105970065], +["1mhd",2.8,3.71136951725555], +["1dt2",2.8,3.85636940803781], +["1owk",2.8,2.81473391263051], +["1yr9",2.8,3.85557554094336], +["2znc",2.8,2.62457767791597], +["3znc",2.8,2.78685550312345], +["1mdy",2.8,3.45515731828447], +["2fh9",2.8,3.49183041863619], +["1fc2",2.8,3.32347393732556], +["1mdm",2.8,3.45614691244444], +["1pw5",2.8,3.52951201202262], +["9ca2",2.8,2.66857907168937], +["1lda",2.8,2.70296969360858], +["1q39",2.8,2.99482725014288], +["1rxm",2.8,2.56994559291238], +["1uvs",2.8,2.61378035011617], +["1t7s",2.8,3.20344735985572], +["1mrv",2.8,3.47040849631971], +["1ild",2.8,3.01555123005633], +["2bp5",2.8,2.82393316970111], +["1v8q",2.8,2.67439108374523], +["1obt",2.8,2.25793123702241], +["1rww",2.8,2.64736499409801], +["1uvu",2.8,3.49992901563250], +["1ft3",2.8,2.86025812508885], +["1rgs",2.8,3.90619371101427], +["1t2l",2.8,2.73156960448152], +["1mry",2.8,3.43760758097952], +["2brn",2.8,2.78182683958268], +["2bgl",2.8,3.94046916485705], +["1il3",2.8,2.94618859205606], +["1fmp",2.8,3.18044622544066], +["1t3w",2.8,3.10892741475055], +["1c9p",2.8,2.74957739045907], +["1fnh",2.8,3.92672100849095], +["1b0c",2.8,2.46257625921284], +["1gih",2.8,3.07738941297249], +["1of5",2.8,3.51358136316752], +["2sbt",2.8,4.85873408167564], +["1gmv",2.8,3.10184734080189], +["1t7y",2.8,2.54224851187307], +["1wvy",2.8,2.92856308362156], +["1sj5",2.8,2.89520002125138], +["1v4h",2.8,3.15987853584603], +["1fg5",2.8,3.84923440564144], +["1hap",2.8,4.48095017020867], +["1hao",2.8,4.50451462671343], +["2bn0",2.8,2.71217867010044], +["1wl2",2.8,2.79395792674466], +["2azl",2.8,2.83304221191864], +["1boo",2.8,3.12628265867277], +["1n0g",2.8,3.57259159088233], +["1k3e",2.8,3.22053917961776], +["1sq1",2.8,3.19183245817242], +["1g7u",2.8,4.33314597278247], +["1vea",2.8,3.36798906668892], +["1wps",2.8,3.55238574346746], +["1lfv",2.8,3.27745279308975], +["2dhb",2.8,3.78007474740755], +["1bib",2.8,3.78397621601848], +["1noh",2.8,3.28259945016026], +["1nwn",2.8,2.28865568966099], +["1ldb",2.8,3.72743085138719], +["1rct",2.8,3.5682583892189], +["1v3q",2.8,3.68393454929053], +["1yry",2.8,3.67228560393291], +["1pwy",2.8,3.79531903516812], +["1pxk",2.8,3.2041312513897], +["1bmn",2.8,3.23116173951886], +["1h88",2.8,3.4495551459937], +["1rfn",2.8,2.93355227261405], +["1xrn",2.8,2.96184065240803], +["1xrq",2.8,2.99078351179552], +["1qp9",2.8,3.14473424878807], +["2bym",2.8,2.89403426825222], +["2bc9",2.8,3.44787800509996], +["2c3e",2.8,3.40307543389503], +["1iyz",2.8,2.83735783489783], +["1gc7",2.8,3.02801683218163], +["1fot",2.8,3.79511266914569], +["1zpq",2.8,4.23852641558443], +["1ku9",2.8,3.30197968180327], +["1tgz",2.8,3.26247805968496], +["1etq",2.8,3.20921097923894], +["1z1i",2.8,3.78336450960396], +["1zl3",2.8,2.71983852537572], +["1xto",2.8,3.46336015989965], +["1wnu",2.8,3.17655365778032], +["1yhj",2.8,3.8283677297007], +["1md8",2.8,3.30185064512592], +["2vtk",2.8,2.7044306870308], +["1rft",2.8,3.31737797703204], +["1xsr",2.8,3.20433660133677], +["1mtl",2.8,3.03546924471084], +["1baw",2.8,1.53384494111768], +["1e7d",2.8,2.89830512000475], +["1tya",2.8,2.5776976949698], +["1as2",2.8,2.70592803952674], +["2bn2",2.8,3.26447358235725], +["1esp",2.8,2.17149112709091], +["1xz8",2.8,3.08947403379841], +["1edz",2.8,3.30844340212567], +["1p9n",2.8,4.05009248980786], +["1jn5",2.8,2.91858510034561], +["1jik",2.8,3.48084713801773], +["1kv2",2.8,3.96308650328496], +["1xwi",2.8,2.92417586222569], +["1jhw",2.8,3.93105646027263], +["1nrk",2.8,3.98833864242725], +["2baq",2.8,2.95999238173403], +["104l",2.8,4.27740521541902], +["1hfv",2.8,3.16461546655394], +["1mq3",2.8,2.74245511573941], +["1yd8",2.8,3.93281497783909], +["7ici",2.8,4.01172903024547], +["1zqp",2.8,3.93485629159632], +["7icv",2.8,3.97213884790472], +["9icl",2.8,3.96658668004212], +["7ict",2.8,4.01504302639736], +["7icn",2.8,4.03955143179908], +["7ice",2.8,4.0023399872969], +["8icc",2.8,4.07278526867356], +["8ici",2.8,4.09250874755716], +["8icn",2.8,4.09722505624627], +["7ics",2.8,4.18642243095361], +["1bbs",2.8,3.67074697654341], +["1fq8",2.8,3.56149018432656], +["8ldh",2.8,3.77342686286249], +["1g9t",2.8,3.06309405297353], +["1fq7",2.8,4.06136955202149], +["1g9s",2.8,2.85359409340628], +["2cv8",2.8,3.41028385037229], +["1fsz",2.8,3.83265699206115], +["1aut",2.8,3.2444242616953], +["1iz3",2.8,3.31086897962829], +["1k1s",2.8,3.08361136149173], +["1gfq",2.8,2.46960891049728], +["1kof",2.8,3.20617925050679], +["1s0n",2.8,2.85580280115822], +["1im2",2.8,3.53478710845719], +["1scm",2.8,3.40375737799888], +["1evz",2.8,2.84234737011252], +["1y6m",2.8,3.6556427730923], +["1qfk",2.8,3.09646472357775], +["1hng",2.8,2.83373849307844], +["1uv5",2.8,3.34605414194863], +["1wxz",2.8,3.44448519473178], +["4pax",2.8,2.29292804780039], +["1rq1",2.8,2.94769909198610], +["1p50",2.8,2.88914496598077], +["1hrt",2.8,4.25741512109327], +["1gol",2.8,3.71926292976497], +["1vdg",2.8,3.17981876817103], +["2b2p",2.8,3.16435826260625], +["1sv8",2.8,3.25709358186019], +["1zbw",2.8,3.25765899041220], +["3mon",2.8,3.07711867775859], +["4ald",2.8,3.45234999140866], +["1zhn",2.8,2.68428274390283], +["1pz9",2.8,3.46798291382823], +["1kt1",2.8,3.34217650364872], +["1l4z",2.8,3.14229330925205], +["1svw",2.8,4.17661074373191], +["1an0",2.8,3.49859608306438], +["1civ",2.8,3.24727484519925], +["1qlj",2.8,2.52850695851009], +["1gzp",2.8,2.25740062399174], +["1tlj",2.8,3.67733030042935], +["1cdd",2.8,3.64936466687504], +["1mxa",2.8,3.02483831474239], +["1mxb",2.8,3.07524793416283], +["1ns3",2.8,3.50853748125692], +["1x8e",2.8,2.69931710587405], +["1x3z",2.8,3.86601459657775], +["1ni3",2.8,3.30291527846571], +["1bz9",2.8,3.01163712080666], +["14gs",2.8,2.88398372013136], +["1zxz",2.8,3.2618983482472], +["2es7",2.8,3.37802476053611], +["2bs1",2.8,2.78841147126671], +["2ms2",2.8,2.35252932459391], +["1aq3",2.8,2.42418030800408], +["6msf",2.8,2.61627581467190], +["2c51",2.8,2.49837633980713], +["7msf",2.8,2.73717272901145], +["5msf",2.8,2.69788997771885], +["1j95",2.8,2.89317535186194], +["1nnb",2.8,3.07732541264143], +["1xog",2.8,3.23052235110837], +["1jvm",2.8,2.9933754160924], +["1ytd",2.8,3.05851538914101], +["1xs7",2.8,3.14831137588057], +["1cj2",2.8,2.02305144318462], +["1pbc",2.8,2.50005659954726], +["1xnp",2.8,3.78167816363164], +["1o3t",2.8,4.17233843778183], +["1o5h",2.8,2.59975971173056], +["2aat",2.8,4.793430813463], +["1asg",2.8,2.81755887122992], +["1asf",2.8,3.49459588591728], +["3aat",2.8,4.23619285178638], +["1aam",2.8,4.48060047160785], +["1f45",2.8,3.70469935591943], +["1zre",2.8,3.18329261705325], +["1zrd",2.8,3.21720946693406], +["1zrc",2.8,3.41577895519272], +["1i49",2.8,3.31808755500907], +["1vgu",2.8,3.16091324825683], +["1kxj",2.8,2.93828559404861], +["1amy",2.8,2.88245742000699], +["1bg9",2.8,2.75876215106401], +["1shj",2.8,3.19362999782504], +["1c0n",2.8,3.37255841244154], +["1i29",2.8,2.71400784899242], +["1psk",2.8,3.06361425144497], +["2aw2",2.8,2.38398324955788], +["1flk",2.8,3.77649805245077], +["1ex4",2.8,3.43757887103584], +["2f6b",2.8,2.90007924372251], +["6icd",2.8,2.96734094540548], +["2bgw",2.8,3.11205381133833], +["1dky",2.8,3.17353303810119], +["1gss",2.8,3.31505872822773], +["1xm9",2.8,3.87152900576074], +["1a2n",2.8,2.84109655885392], +["1b0v",2.8,2.9560692345176], +["1ysc",2.8,4.06624971027312], +["2adi",2.8,3.42803296627118], +["1xxc",2.8,4.18529676710349], +["1ine",2.8,3.51405379269676], +["1f4y",2.8,3.90968013261979], +["1dwu",2.8,2.77617070167013], +["1bwu",2.8,3.60529704275831], +["2a1a",2.8,2.86155329775432], +["1jrh",2.8,3.17475286126381], +["1cfq",2.8,3.55765684630533], +["2eck",2.8,2.75921923426654], +["1nl6",2.8,3.34814883334784], +["1a5f",2.8,3.94760568559482], +["1plg",2.8,3.02170438989137], +["1cft",2.8,3.3682162942548], +["1ggb",2.8,3.03150941562367], +["1ggc",2.8,3.26438862399304], +["1bbd",2.8,3.77157618138244], +["1eyg",2.8,4.41415856321404], +["1dgd",2.8,2.74832683942483], +["1d7v",2.8,3.24963733311542], +["1dge",2.8,3.31492353692821], +["1gin",2.8,3.03081046936848], +["1ksz",2.8,3.42225713695574], +["1it9",2.8,3.61940209975929], +["1wnc",2.8,4.59249498170224], +["1x75",2.8,3.18624470626156], +["2f19",2.8,3.42999290563339], +["1m71",2.8,3.44873855673508], +["1rmf",2.8,3.39893013531515], +["1dba",2.8,3.54806179346089], +["1ml0",2.8,3.04045264181801], +["1clz",2.8,3.39554531933028], +["1ejl",2.8,2.57969906873299], +["1iq1",2.8,2.80374381876612], +["2lgs",2.8,2.92248730122019], +["1otp",2.8,2.65915814589976], +["1ens",2.8,3.02584214452512], +["1ai1",2.8,3.59813484028225], +["1py2",2.8,2.35286265691891], +["1yz5",2.8,2.79416900880798], +["1l8o",2.8,4.03999149833003], +["1ifh",2.8,3.07366020906518], +["1frg",2.8,2.99707202999791], +["2igf",2.8,3.36387506850398], +["1omi",2.8,3.39408522096592], +["1bux",2.8,2.96842134014185], +["1l1j",2.8,3.46735094294032], +["1joa",2.8,2.51529600009581], +["1w0e",2.8,3.73437165376518], +["1ebp",2.8,3.65114522431408], +["1z50",2.8,2.69178816921455], +["1om7",2.8,2.58675093926494], +["1ksw",2.8,3.5326967552478], +["3f58",2.8,2.90700321400141], +["1nub",2.8,2.87694878819891], +["1grl",2.8,3.86996656389937], +["2f58",2.8,3.30879891332573], +["1mm8",2.8,3.23238948823755], +["2am2",2.8,3.64148185647362], +["1p0s",2.8,3.38517856056205], +["1xr5",2.8,3.10346634969238], +["4grt",2.8,3.38828919771395], +["1uus",2.8,3.23629746267694], +["2d9q",2.8,3.98630113221931], +["1nj5",2.8,2.81811571703608], +["1q78",2.8,2.97145815998099], +["1n9r",2.8,3.42479938542959], +["2btp",2.8,1.95432568748509], +["1xc4",2.8,3.51842915912297], +["1u5j",2.8,2.96225357872755], +["2f66",2.8,3.05803704637073], +["1ab4",2.8,2.84791933918836], +["1nm3",2.8,3.38611010548241], +["1m7u",2.8,3.3299306644295], +["1a52",2.8,2.93104879013913], +["1wp0",2.8,2.88609036958519], +["1c1j",2.8,3.37600121478683], +["1okx",2.8,2.53309671467691], +["1o8n",2.8,2.11499131607401], +["1y7u",2.8,3.15776877997276], +["1x7e",2.8,3.03998501593304], +["3ypi",2.8,3.36663015496848], +["1y1l",2.8,3.49086489706795], +["1tdj",2.8,4.27458913357163], +["1fw3",2.8,2.67891913543636], +["1yf8",2.8,3.67779773358949], +["1tfm",2.8,3.87100737611018], +["1hti",2.8,3.22222885210036], +["1ha0",2.8,3.34738158157673], +["3tim",2.8,3.18298829946963], +["1p8d",2.8,3.27499587755248], +["1iaj",2.8,3.9367271686619], +["1e3k",2.8,3.87934673992898], +["4csm",2.8,2.92491044789964], +["1btm",2.8,3.09635594383204], +["1g6y",2.8,3.31227870076443], +["2b3o",2.8,3.56403177753238], +["1lu2",2.8,3.06525875987084], +["1znc",2.8,2.40507120747472], +["1pio",2.8,3.31037580823951], +["1dqu",2.8,4.2871543935704], +["1u54",2.8,3.07820810296766], +["1i2z",2.8,2.88764151499201], +["1urh",2.8,3.54881709322008], +["1yv9",2.8,2.99600369538849], +["1rqn",2.8,2.8129703068161], +["1hwm",2.8,3.71656771550642], +["1hwn",2.8,3.94005166076449], +["1wk4",2.8,3.55404275602311], +["1p91",2.8,3.68922856632648], +["1pag",2.8,2.6715334566439], +["1vq1",2.8,2.74625784452252], +["1amn",2.8,3.31576973852209], +["1y3h",2.8,3.65237251442203], +["1acl",2.8,3.07159386030126], +["1ax9",2.8,3.25455802794405], +["1il5",2.8,2.7455589062568], +["1n7i",2.8,3.26834775845268], +["1acj",2.8,2.48419141964325], +["2b4m",2.8,2.58026052580675], +["1t6y",2.8,3.65516735418446], +["1gts",2.8,2.84561397452264], +["1tzi",2.8,2.98863000009149], +["1tqc",2.8,3.24875995653372], +["1r3k",2.8,3.09644535747970], +["1qyy",2.8,3.42024896841818], +["1qij",2.8,2.80298262582357], +["1egj",2.8,3.40002049713179], +["5eat",2.8,2.13169692541746], +["2akj",2.8,3.3520558122022], +["1md9",2.8,3.35986361185902], +["1wd8",2.8,3.48714047529288], +["1ybv",2.8,2.45370914523611], +["1tq0",2.8,3.51311320981171], +["1gwb",2.8,3.89552967854325], +["1fvh",2.8,3.58974238328717], +["1a36",2.8,3.1680524800381], +["1mh0",2.8,3.4778805271267], +["1iun",2.8,2.98654847538588], +["1akn",2.8,3.17008590092516], +["1izy",2.8,3.35622645288977], +["1z19",2.8,2.52014227931220], +["1qmf",2.8,2.25344207849949], +["1pgl",2.8,2.85866135697734], +["1d4e",2.8,3.80866889650202], +["1hk3",2.8,2.9123957662869], +["1hk2",2.8,2.97717315803716], +["1xe8",2.8,3.17963579839854], +["1yen",2.8,3.28523562026867], +["1z4u",2.8,2.89661974428290], +["1fok",2.8,3.52032592861687], +["3hhr",2.8,3.21316831886934], +["2pgh",2.8,3.57787957268978], +["1uf9",2.8,3.27973684873659], +["1dgp",2.8,2.90140086059291], +["1qap",2.8,3.60697153704115], +["1xd9",2.8,2.91919961565867], +["1xdb",2.8,3.19146419346824], +["1uh0",2.8,2.48027437373173], +["1uh1",2.8,2.19119491058969], +["1mtn",2.8,3.69725978364582], +["1uor",2.8,4.54033510939353], +["1z8n",2.8,2.75776883454505], +["1cn4",2.8,3.92576583349572], +["1eh4",2.8,3.76181134813049], +["1ibs",2.8,3.23768778130663], +["1a0r",2.8,2.76237002360506], +["1f2n",2.8,3.40480746154354], +["1xgm",2.8,3.49168550887536], +["1jk0",2.8,3.33198466258723], +["2eui",2.8,3.19731102819187], +["2d2q",2.8,3.39778066122963], +["1bkd",2.8,2.46423803029726], +["1kru",2.8,3.36197892652513], +["1krv",2.8,3.45519394129960], +["1qp8",2.8,3.63806396964654], +["1p0n",2.8,2.72391186104822], +["1iev",2.8,2.90638323185173], +["1tm0",2.8,3.40098262475928], +["1bcm",2.8,2.70562679750735], +["1wlh",2.8,3.72636953403268], +["1mrl",2.8,2.38876600335813], +["1z1j",2.8,3.74962478886442], +["2g2j",2.8,3.85091919142474], +["1rfv",2.8,2.56879233041719], +["2bx9",2.8,3.01014825004468], +["1b04",2.8,3.53614296293268], +["4sbv",2.8,4.19627051629126], +["1ck7",2.8,3.83312014934944], +["1sly",2.8,2.68143713650134], +["1avl",2.8,2.69868120611621], +["1k1w",2.8,3.43415888215389], +["1kwp",2.8,3.89816954846584], +["1uvh",2.8,3.94266258279487], +["1k8f",2.8,3.60935154736062], +["1mir",2.8,2.99993908692231], +["1hyg",2.8,3.42397216065377], +["1xa0",2.8,3.33185138545509], +["2fmt",2.8,3.26759207407942], +["1n1y",2.8,2.71869196035746], +["1wcs",2.8,3.2529250041244], +["3fbp",2.8,3.62842243459508], +["1atn",2.8,3.03710245890338], +["2fbp",2.8,3.83037968844121], +["1dk5",2.8,3.48260199387619], +["1ef3",2.8,3.07449631815908], +["1evt",2.8,3.13924677917566], +["2ewn",2.8,3.36083190715093], +["1f88",2.8,3.34123231497192], +["1hzx",2.8,3.55652307426632], +["2f9c",2.8,3.90862604985988], +["1thj",2.8,2.94337640523598], +["1rfz",2.8,3.49886131034811], +["1uu2",2.8,3.61818875817833], +["1vll",2.8,2.31559478014297], +["1e0o",2.8,3.41130592932907], +["1xns",2.8,3.05922056706722], +["1opx",2.8,3.13077955767164], +["1nly",2.8,2.94248880037821], +["1dct",2.8,3.40711480854576], +["1wlq",2.8,3.69679480893592], +["1tv7",2.8,3.00619427921704], +["1fnm",2.8,3.34524269290266], +["1ls5",2.8,4.03455863721084], +["1xe6",2.8,3.0581499060194], +["1cvs",2.8,2.79301334390506], +["1nql",2.8,3.47721992278531], +["1bim",2.8,3.83688179942220], +["1xal",2.8,3.56230039125872], +["1syk",2.8,3.25733393443066], +["1k1q",2.8,3.80191093210462], +["1wpw",2.8,2.76171084128828], +["1otc",2.8,2.47468104198755], +["1dkg",2.8,3.90365679129994], +["1pxt",2.8,3.59548701717527], +["1peq",2.8,2.73418986612987], +["1lia",2.8,2.75222689163119], +["2aja",2.8,3.33239433572028], +["1av8",2.8,2.47775429780198], +["1lgc",2.8,3.47830107700588], +["2atl",2.8,2.96518969292333], +["1gs0",2.8,3.03657892273257], +["1n04",2.8,3.69495720911464], +["1blf",2.8,2.99206214651259], +["1wqs",2.8,4.38990498855045], +["1dpz",2.8,3.74842591476642], +["2pcb",2.8,3.84399642636077], +["1lfh",2.8,3.5660140131827], +["1jx7",2.8,3.41510663116945], +["1uea",2.8,3.46137679122614], +["1vfg",2.8,4.16529223962376], +["1ky9",2.8,3.92230527881992], +["1cjt",2.8,2.03249146805937], +["1tl7",2.8,2.98180834025852], +["1h8f",2.8,2.85766475679793], +["1cju",2.8,2.30293850085656], +["1z9d",2.8,2.69725181468529], +["1fdo",2.8,3.32681526526279], +["1gtl",2.8,3.10440794848116], +["1bjo",2.8,2.26465475030794], +["2a58",2.8,2.55314802608688], +["1zxj",2.8,3.31741985004355], +["1bjj",2.8,3.36219858079753], +["1n25",2.8,3.21365025404775], +["1xrs",2.8,3.48003020678572], +["1xz0",2.8,2.26501739294006], +["1xu8",2.8,3.08375998921592], +["1cd9",2.8,2.80266609943804], +["1kkl",2.8,3.09153695727387], +["2mys",2.8,3.97585176526679], +["1dlh",2.8,3.57857320797461], +["1z7l",2.8,2.9462640876592], +["1qay",2.8,2.74670103712721], +["1kpr",2.8,3.60656925742262], +["1tme",2.8,3.32580462278597], +["1i7t",2.8,3.10390537593007], +["1i1f",2.8,2.82196359164156], +["1gvm",2.8,3.24722141740343], +["1pnv",2.8,3.09164360004659], +["1p1b",2.8,3.51611059074532], +["1i1a",2.8,3.49554648484047], +["2dmr",2.8,2.47433465250765], +["1v4l",2.8,3.59178018244337], +["1pn3",2.8,3.14013288476056], +["1kkm",2.8,3.22766694940744], +["1y6g",2.8,3.42262966891138], +["2bck",2.8,2.67802683354025], +["2b0u",2.8,3.33596839349189], +["1kt2",2.8,2.80876554349085], +["1aib",2.8,3.05433572843393], +["1aoi",2.8,3.02920825418363], +["1qax",2.8,2.72782485061148], +["4rcr",2.8,5.11774791941864], +["1c8m",2.8,2.45873772265353], +["1qju",2.8,2.15005133845946], +["1qjy",2.8,2.20827905140973], +["1qjx",2.8,2.39559848950343], +["1nd3",2.8,2.50077084324797], +["1kez",2.8,3.28075598498058], +["2b10",2.8,2.62031503229499], +["1tas",2.8,3.65709292425139], +["1l1o",2.8,3.8500717188877], +["1mk9",2.8,3.50339949413677], +["1jgw",2.8,2.42694383149378], +["1lk6",2.8,3.32708587172755], +["1ems",2.8,3.16709725072441], +["1qsf",2.8,3.52237993387135], +["1qse",2.8,3.48194059714649], +["1qrn",2.8,3.02981856017367], +["1f6n",2.8,2.96430114416173], +["1rgn",2.8,2.76895011924957], +["1umx",2.8,3.24055472616331], +["1fn4",2.8,4.66052372820057], +["1bi8",2.8,3.76124850252441], +["1iax",2.8,3.00741971508709], +["1u0l",2.8,3.70709345703773], +["1dzg",2.8,3.36544555280391], +["1gg3",2.8,3.87580771779109], +["1odu",2.8,2.33829761259934], +["1vbe",2.8,2.4966826477864], +["1vbc",2.8,2.58722803423541], +["1vbb",2.8,2.53995711450208], +["3hdh",2.8,3.16154049539550], +["1t1l",2.8,3.88504180163836], +["1kfa",2.8,3.28808840642653], +["1p5q",2.8,3.54387236760044], +["2gm7",2.8,2.39566925284413], +["1bye",2.8,4.21304717576901], +["5csc",2.8,4.34091630817837], +["1bln",2.8,2.99995619259176], +["1kd7",2.8,3.55125549233973], +["1sdd",2.8,3.85446581427661], +["1bk6",2.8,2.64964341008298], +["1d5b",2.8,3.60322391769367], +["1a7a",2.8,3.18777260849246], +["1iyx",2.8,3.22172356521659], +["1c72",2.8,2.92140106821129], +["1yj5",2.8,1.97111643191208], +["2bhr",2.8,3.37677378424333], +["1jde",2.8,4.4447674575123], +["1fl6",2.8,3.41827517803644], +["1r43",2.8,3.10880815186718], +["1igf",2.8,3.40390542929176], +["1ggi",2.8,3.41641713892361], +["1m7w",2.8,3.5663467739756], +["1yyw",2.8,3.32425710800650], +["1ad9",2.8,2.57057513551379], +["1fiy",2.8,3.35439842687877], +["3gtu",2.8,2.36226897065429], +["1kx1",2.8,3.40469690788317], +["1og6",2.8,3.30505146436035], +["1hkw",2.8,3.20781675149404], +["1o6p",2.8,3.11324063217012], +["1nsk",2.8,2.84677812703979], +["2fyi",2.8,2.99769447133022], +["1pre",2.8,3.49165500394708], +["1vbf",2.8,3.36828547706757], +["1w7w",2.8,2.51924692360072], +["1pjt",2.8,3.44578094311071], +["1elz",2.8,2.55964977603098], +["1ely",2.8,3.11634424551897], +["1dgk",2.8,2.4189392209034], +["1pqc",2.8,2.43250900161791], +["1hkc",2.8,3.05444692263529], +["1lw0",2.8,3.4428539441869], +["2gbd",2.8,3.19644572604133], +["1f59",2.8,3.41004407329571], +["1q9y",2.8,3.17726230631517], +["1waj",2.8,3.76930250045416], +["1tl3",2.8,3.27107248056564], +["1dgj",2.8,2.61637090697861], +["1acm",2.8,2.89583720582527], +["7at1",2.8,2.77449225823614], +["8at1",2.8,2.96435037010682], +["2at1",2.8,3.23179601489946], +["1at1",2.8,3.26902752745702], +["3at1",2.8,3.41608687498142], +["1qwj",2.8,3.41102034199687], +["1l0x",2.8,2.96863527383681], +["1fhf",2.8,3.02980967678304], +["1aro",2.8,3.66596912779024], +["2ar9",2.8,3.06240028057916], +["1jle",2.8,3.79433480848158], +["1eo8",2.8,3.30394401092955], +["1fat",2.8,3.02810490798351], +["1dtq",2.8,3.47899186835201], +["1i5o",2.8,3.49767306197433], +["1tth",2.8,3.78510832273568], +["1qf3",2.8,2.20020050754256], +["1cj0",2.8,3.24828974737008], +["1jxq",2.8,2.50808387065636], +["1g8w",2.8,2.95266772622994], +["1wth",2.8,3.61267136062821], +["1qfu",2.8,3.46272084986431], +["1lwf",2.8,3.5651635427666], +["2c5m",2.8,3.74811452368787], +["1s1x",2.8,3.53613210747749], +["1agr",2.8,2.89827306835683], +["1tbj",2.8,2.76974008573906], +["1r1o",2.8,3.20064123183502], +["1hqh",2.8,3.68027491307696], +["1t4s",2.8,3.34567181133143], +["2d3p",2.8,2.72657607131599], +["1tv6",2.8,3.3930367376976], +["1lpf",2.8,3.09159759541742], +["1qdo",2.8,2.92794436705623], +["1rt6",2.8,3.33599385772269], +["1hci",2.8,3.67455608223805], +["1im9",2.8,3.02313632947031], +["1akm",2.8,3.35748348315995], +["2ar0",2.8,3.15546633376685], +["1a2a",2.8,3.92310220291132], +["1s9g",2.8,3.85762999291531], +["1typ",2.8,2.78530407918293], +["2bbv",2.8,3.76033115915727], +["1q47",2.8,3.52834967724933], +["1bzq",2.8,3.3379156932707], +["1woa",2.8,2.10675837547654], +["1wob",2.8,1.98255599663591], +["1lzo",2.8,3.28532458122112], +["1ikx",2.8,3.21841502806921], +["1hni",2.8,3.73544734794521], +["1fgj",2.8,2.92671536536109], +["1jri",2.8,3.23593578541616], +["1tmh",2.8,2.74854569173591], +["1lgn",2.8,2.60381473121958], +["1mhp",2.8,3.35013817279408], +["1g8h",2.8,2.82290383448427], +["1jee",2.8,2.96695053212063], +["1tw8",2.8,3.31910827961121], +["1cqz",2.8,4.10627399187718], +["1cr6",2.8,4.11425691188075], +["2fjg",2.8,2.91176766197814], +["1d5f",2.8,3.56683709605846], +["2akw",2.8,3.17368814880248], +["1l2o",2.8,4.03788674181821], +["1v8o",2.8,3.31423335915766], +["1csj",2.8,3.17338229959719], +["1aql",2.8,3.36759545753898], +["2ad5",2.8,3.76955156253805], +["1eth",2.8,3.94657143408471], +["1djy",2.8,3.46749812441305], +["2a7w",2.8,2.84198003213651], +["1zag",2.8,2.81075255268305], +["1u9z",2.8,2.8021628842388], +["1fxz",2.8,3.16278899209611], +["1dxq",2.8,3.31234993063293], +["1n0f",2.8,3.55928294482360], +["1zj8",2.8,2.62645423102934], +["1mab",2.8,4.11738037389394], +["1kia",2.8,3.46490055587874], +["1dzn",2.8,3.26415915246946], +["1u0r",2.8,3.55819670508592], +["1bq7",2.8,3.05135835227581], +["2vao",2.8,3.71082177787542], +["1fvv",2.8,2.94820426094673], +["1h28",2.8,3.82869866031153], +["1hv4",2.8,3.51712404255283], +["1gn1",2.8,3.2890612975669], +["1ozb",2.8,2.88236525079267], +["1nvf",2.8,2.90016954403622], +["1nbh",2.8,3.55056995331443], +["1xni",2.8,2.89430117084104], +["1sma",2.8,4.08965628054207], +["1xxj",2.8,3.3573786543121], +["1j0j",2.8,2.87271054940090], +["1n0h",2.8,2.34544711543015], +["1oy0",2.8,2.68556117984439], +["1b7b",2.8,2.78311266796399], +["1qhm",2.8,3.25712625476607], +["1mpy",2.8,3.10587871684454], +["1khr",2.8,3.27795562083772], +["1bqh",2.8,3.62725489427032], +["1mpr",2.8,2.61522925533169], +["1mpo",2.8,3.20285647537558], +["1n1h",2.8,2.87894831450044], +["1n38",2.8,2.93436312105527], +["2b5n",2.8,3.66112601216123], +["1nyr",2.8,3.85882993991272], +["1nb3",2.8,3.84840154315191], +["1lt9",2.8,3.23579437074854], +["1qrq",2.8,2.6290170867489], +["1ltj",2.8,3.14279438714272], +["1spi",2.8,4.29039746566393], +["1igt",2.8,3.48905095547718], +["2bis",2.8,2.69981479363148], +["1ty3",2.8,3.03561462767087], +["4gpd",2.8,4.9221257499632], +["1ihx",2.8,2.57208349485598], +["1o6o",2.8,3.16477292227483], +["1qmi",2.8,3.73039607464969], +["1bos",2.8,1.6662029326183], +["1p3h",2.8,3.0335394371133], +["1xp4",2.8,3.4293820237835], +["1m63",2.8,2.58326519998029], +["1avo",2.8,2.50054345629397], +["2awo",2.8,3.58570260779713], +["2hmi",2.8,3.87586581119245], +["1r0a",2.8,3.65686784772196], +["1gyp",2.8,2.76571713357724], +["1a7k",2.8,3.00191812392353], +["1nlx",2.8,2.86320596532483], +["1qdu",2.8,3.85471783978818], +["2fgh",2.8,3.00246895663627], +["1lyl",2.8,2.37434483749926], +["2brw",2.8,2.83591558841977], +["1q1b",2.8,3.78248462453452], +["1cf1",2.8,3.22428570593751], +["1lm1",2.8,3.92836391193279], +["1pww",2.8,3.44652085738209], +["1kmn",2.8,3.7776784559137], +["1kqg",2.8,2.11591172611954], +["1e94",2.8,3.56826684913189], +["1r6z",2.8,2.98119065332397], +["1qxp",2.8,4.44356847333995], +["1hqy",2.8,3.74623012100532], +["2b36",2.8,2.99675452096841], +["1ll6",2.8,2.89665556177110], +["1ll4",2.8,2.91523585426593], +["1m6x",2.8,3.0547186890038], +["1rdf",2.8,3.73136555177871], +["2bwo",2.8,2.4352845946434], +["1ych",2.8,3.32638784689801], +["1ycg",2.8,3.32638120802957], +["1bvr",2.8,3.71877997579203], +["1vyj",2.8,3.57469418482987], +["1g6r",2.8,3.84162403846937], +["1dq9",2.8,3.37612382502221], +["1rzr",2.8,4.12079799279685], +["1nl3",2.8,3.32384653192699], +["1ady",2.8,2.7927250682152], +["1ygp",2.8,3.06732541899532], +["1b3r",2.8,3.16857435712343], +["1ky4",2.8,3.34674388660124], +["1xtu",2.8,2.80477991925772], +["1rqc",2.8,3.50421853820364], +["1xwf",2.8,3.56682745870099], +["1ky5",2.8,3.47326126969561], +["1d4f",2.8,4.09282695287129], +["1jym",2.8,3.27633113715033], +["1mfz",2.8,2.95064270129735], +["1nfd",2.8,4.31743505918146], +["2ap9",2.8,3.24741052277868], +["1y18",2.8,2.96849352473906], +["1xwo",2.8,3.39103891641744], +["1bg3",2.8,2.90492502576479], +["1hkb",2.8,3.27662846256385], +["1jag",2.8,3.10437553451031], +["2acl",2.8,3.29168731812126], +["1ao0",2.8,2.91545583152888], +["1e0u",2.8,3.18025264088188], +["1ohy",2.8,2.42156522254521], +["3sqc",2.8,2.646432610042], +["1gsz",2.8,3.10427165839143], +["1h36",2.8,2.61069219622308], +["1o79",2.8,2.7842220976947], +["1h37",2.8,2.82326863272936], +["1h3b",2.8,2.82942806236824], +["1o6h",2.8,2.92179380133297], +["1h35",2.8,2.76226717934095], +["1h39",2.8,2.85154175533329], +["1o6q",2.8,2.92767344343208], +["1pwe",2.8,3.23143790967935], +["1aei",2.8,2.57898249463990], +["1uul",2.8,3.28277798335593], +["1iqp",2.8,3.33907064279235], +["1y9e",2.8,3.8928859816753], +["1uys",2.8,3.21602637614994], +["1th3",2.8,3.48947546100649], +["1th2",2.8,3.51692464519966], +["1tgu",2.8,3.58468214877806], +["1bpw",2.8,3.05821235224028], +["1w2x",2.8,3.19301080987105], +["1g8x",2.8,3.30374980774127], +["1oqb",2.8,3.0794858676853], +["1t5a",2.8,2.73906408378486], +["1mok",2.8,3.27879602803752], +["2a1t",2.8,2.94089544873597], +["1geh",2.8,3.59223948678349], +["1za6",2.8,3.6883620446251], +["1foe",2.8,3.25662510228478], +["1e2t",2.8,3.6516638497701], +["1ohf",2.8,3.04219981130822], +["1g23",2.8,2.54297452126029], +["1gl6",2.8,2.93944297834572], +["1rfu",2.8,3.4929563046899], +["1v9l",2.8,3.38673455825528], +["1n5x",2.8,2.75071898001667], +["3pva",2.8,3.17071683707776], +["1wpl",2.8,2.62156920772485], +["1is7",2.8,3.15913664617842], +["1t8w",2.8,3.19422073384332], +["1kfl",2.8,2.68666188491133], +["1u9i",2.8,3.39224652174126], +["1yjx",2.8,2.95013699912516], +["1tf7",2.8,3.38092458232458], +["1iph",2.8,2.72218057789916], +["1lwu",2.8,3.6467465464211], +["1ohh",2.8,3.30985451563197], +["2otc",2.8,2.77058428930370], +["1ht2",2.8,3.71752743557207], +["1ht1",2.8,3.72465966402701], +["1hwz",2.8,3.73018261554199], +["1jmu",2.8,2.63295926591767], +["1de4",2.8,3.29998107404338], +["1zgl",2.8,4.01374611106158], +["1zm9",2.8,3.40935119551699], +["1zpu",2.8,2.86817368689311], +["1mx5",2.8,2.81860109019696], +["1abb",2.8,3.66739017151392], +["1n3r",2.8,2.87447241349551], +["1fbx",2.8,2.98434691324449], +["1k83",2.8,3.42621086684982], +["1rv2",2.8,3.47041472166723], +["1occ",2.8,3.03320913244459], +["1oco",2.8,3.17133754041695], +["1i50",2.8,3.32532944909528], +["1m90",2.8,2.96995353151326], +["1jqk",2.8,3.41291225507592], +["1fqv",2.8,3.25722850507517], +["1oel",2.8,2.79505175144656], +["1yit",2.8,3.04293016053827], +["1qun",2.8,3.69772699836828], +["2bo8",2.8,2.95760445419518], +["1ye9",2.8,3.24765045640633], +["1kv3",2.8,3.09569825184440], +["1n4r",2.8,2.61037492951432], +["1mfr",2.8,2.03389339374661], +["1f4a",2.8,3.3565457490522], +["1f4h",2.8,3.78912137537073], +["1f3x",2.8,3.24749721999604], +["1ryy",2.8,2.33602820685231], +["2c37",2.8,2.53497717391052], +["2br2",2.8,2.57023748659244], +["1n6d",2.8,2.94819259259157], +["2fak",2.8,2.92352118702281], +["2f16",2.8,3.00962040262928], +["2a6e",2.8,4.13835208989003], +["1rxs",2.8,2.28553053732286], +["1wf4",2.8,3.17220632605595], +["1we3",2.8,3.15680221425455], +["1mcz",2.8,2.12402875831614], +["1mt5",2.8,2.89497538678338], +["2fg5",2.8,1.81512361292724], +["1tt4",2.8,2.7930473162424], +["1yew",2.8,3.89972799107848], +["1zmw",2.8,2.93063553348601], +["1pcq",2.81,3.17954131499672], +["1svt",2.81,3.36124761030642], +["1jzb",2.81,3.03382008747969], +["1u6l",2.81,3.62488934867318], +["1uvr",2.81,2.76338651537551], +["1t6i",2.81,1.57523440851301], +["1yw1",2.81,2.72942700477865], +["1u6a",2.81,2.81554281643885], +["1rj5",2.81,2.78588040187285], +["1tkz",2.81,3.31938795644995], +["1xdi",2.81,3.47073544626772], +["1lwe",2.81,3.4680464453881], +["2af7",2.81,3.54565928735164], +["1vfo",2.81,3.02925791673252], +["2fie",2.81,3.06551215478798], +["1rf0",2.81,3.19772341017318], +["1i2d",2.81,3.02865072087414], +["1q6w",2.81,2.86030977288148], +["1lb1",2.81,2.65378569514028], +["1ver",2.82,3.21743984395578], +["1ha5",2.82,3.36724461943345], +["1hl0",2.83,2.87548391309959], +["1hzv",2.83,2.85912191711622], +["1e51",2.83,3.39112695233153], +["1udu",2.83,4.27362698288526], +["1qlr",2.83,3.20128446239128], +["2br5",2.83,2.77689954012898], +["1j2q",2.83,3.45651369386582], +["1kuq",2.84,3.17755658657476], +["2mib",2.84,3.12054093899935], +["1h2n",2.84,2.11213794145498], +["1tsi",2.84,3.81046516129741], +["1jus",2.84,3.3913206959065], +["1p8m",2.84,2.89526904342606], +["1u3p",2.85,2.66891393249358], +["1odh",2.85,3.43738825017361], +["1mwj",2.85,2.37129801445943], +["1vei",2.85,3.3042751002862], +["1h3w",2.85,3.45883430450646], +["2d2s",2.85,3.30074069263125], +["1uiy",2.85,3.13143353077837], +["2er8",2.85,3.20548187753612], +["1lsu",2.85,3.87651605330143], +["1tnr",2.85,2.75788314283062], +["1v41",2.85,3.74252325092298], +["2c7l",2.85,2.51442244613788], +["2ago",2.85,3.11260617582172], +["1xqb",2.85,3.25884148326731], +["2cfb",2.85,2.60290814835645], +["1imv",2.85,3.18982850057537], +["1dzs",2.85,2.54650151332355], +["1u1y",2.85,2.84948016441983], +["1p7r",2.85,2.86459845558754], +["1jx0",2.85,3.56973448750602], +["1ttu",2.85,3.57451431604644], +["1uex",2.85,3.16793448403108], +["1nj6",2.85,2.84494454764391], +["1jpy",2.85,3.15183907706287], +["1sq7",2.85,1.76105862311464], +["2bx2",2.85,3.14192936200911], +["1b9b",2.85,3.24454876273148], +["1jxe",2.85,2.44593661408302], +["1e3q",2.85,3.43068207992960], +["1gji",2.85,3.60742387393136], +["1v4j",2.85,2.85343886944277], +["2d2m",2.85,3.30765370687565], +["1mr1",2.85,3.60514348435294], +["1xl6",2.85,3.47552555048372], +["1sqc",2.85,2.68446562867698], +["1u80",2.85,3.1819290143487], +["2fa2",2.85,3.33033822119976], +["1vrs",2.85,3.00526215202896], +["1v53",2.85,3.03381961465945], +["1vcu",2.85,3.07480036394195], +["1jtx",2.85,3.59910165777249], +["1w3b",2.85,3.54255085309976], +["1mhe",2.85,2.96772270693496], +["1nua",2.85,2.97966916189513], +["2bl4",2.85,3.32323249038411], +["2bi4",2.85,3.56402081208017], +["1dzh",2.85,3.20490221695319], +["1m8h",2.85,2.93382889505468], +["1zlw",2.85,3.17538697278948], +["1jfm",2.85,3.83372915816756], +["1rit",2.85,3.06370589681300], +["1tkx",2.85,3.30351800024763], +["1dzq",2.85,2.47482130002478], +["1h4s",2.85,2.91343832145347], +["1l2g",2.85,3.52743397038037], +["1qe1",2.85,3.62209186078022], +["1r2s",2.85,2.26730060426399], +["1z0z",2.85,2.88850939486887], +["1shz",2.85,3.18669481723091], +["1yj8",2.85,1.85129592559482], +["1h1c",2.85,3.56012943512881], +["1uu0",2.85,3.70569453340954], +["1j5s",2.85,3.08992272848772], +["1lql",2.85,3.44338879011130], +["2b9b",2.85,3.18754932753460], +["1pwv",2.85,3.44906642213055], +["1n5a",2.85,3.28720009941178], +["1fun",2.85,2.76524134644065], +["1frv",2.85,4.17330335616272], +["1n0v",2.85,3.10295213762353], +["1jnh",2.85,3.58876665526693], +["1pzn",2.85,3.73320965321073], +["1f30",2.85,3.03023064257359], +["1h3a",2.85,2.63215521312004], +["1w8q",2.85,2.71859424005949], +["1xco",2.85,3.43406245705066], +["1kn0",2.85,2.97221805025616], +["1sqv",2.85,3.355152078717], +["1sxj",2.85,3.39542803302564], +["2b5l",2.85,3.70299302280748], +["1w0k",2.85,2.63838912033108], +["1bmf",2.85,3.28899694785686], +["1up4",2.85,2.57626411454754], +["1tnb",2.85,2.56484537583099], +["1jkq",2.86,3.74730293436443], +["1q46",2.86,3.18678512817258], +["1v45",2.86,3.65245226521878], +["1mc0",2.86,3.20251317084051], +["1zdk",2.86,2.84312855955734], +["1x8z",2.86,3.34424452782044], +["1imh",2.86,3.34518470026129], +["1u5i",2.86,3.99873333287358], +["6gpb",2.86,3.25694245031309], +["1y56",2.86,3.18815310028701], +["1p33",2.86,3.15702088300593], +["2bzf",2.87,2.90579580326237], +["1ja2",2.87,3.22008122395866], +["1c1z",2.87,3.38047902362203], +["7mht",2.87,1.84482274424494], +["1bvl",2.87,3.88625317526876], +["1lix",2.87,3.96843813826081], +["1sej",2.87,3.28236490333168], +["1pyg",2.87,2.95719905787526], +["1dff",2.88,3.20461955248837], +["2gki",2.88,3.41741378564127], +["1ud8",2.88,2.82452302749852], +["1yy3",2.88,4.0637262600389], +["1s76",2.88,3.61194831300111], +["2plv",2.88,3.49691858659125], +["1veb",2.89,2.55552132904034], +["1qvt",2.89,3.53434584823531], +["1r52",2.89,3.04727392376538], +["1ju6",2.89,3.06693751997808], +["1rqf",2.89,2.67006501099396], +["1fpy",2.89,3.55913216564308], +["4hb1",2.9,2.33511452856437], +["1rgv",2.9,2.86890650646366], +["1q1h",2.9,4.10445406251494], +["1l9a",2.9,3.54464018046379], +["1vby",2.9,2.61734597944272], +["1ysa",2.9,3.41409756992567], +["2bnk",2.9,3.40315541845475], +["1an4",2.9,4.81113203875435], +["1dkt",2.9,3.16500199968463], +["41bi",2.9,2.95393693025621], +["1rmv",2.9,4.28567327062530], +["1kxb",2.9,2.71369406261154], +["1hlm",2.9,3.70833907155704], +["1glu",2.9,4.39021104391882], +["1ble",2.9,3.16249610501474], +["1fyv",2.9,3.46827374779013], +["1std",2.9,2.75620083343948], +["1nuk",2.9,3.95062368174325], +["2fgs",2.9,2.61462501873858], +["1an2",2.9,4.34240570531076], +["1etu",2.9,3.77175547187653], +["1grq",2.9,2.91042978796120], +["1grr",2.9,2.8851199433757], +["1cdi",2.9,4.26441148236294], +["1tgh",2.9,3.65613053531623], +["1wqh",2.9,3.58717799966587], +["1i5d",2.9,3.99670089399359], +["1h6o",2.9,3.34417102206526], +["1wd6",2.9,2.55451433698054], +["2dli",2.9,3.79264858489106], +["2fzl",2.9,3.79127775352048], +["2cax",2.9,2.74292592336069], +["2anb",2.9,2.53808740386697], +["1l0a",2.9,3.41957168734855], +["1qpl",2.9,2.80181338321421], +["1rm9",2.9,2.87218494075591], +["1lel",2.9,3.51704751781771], +["4skn",2.9,3.02865780737471], +["1tfp",2.9,3.06198036592848], +["1z37",2.9,2.99173887166078], +["1d9g",2.9,2.78397203064091], +["1rxh",2.9,3.63772193479666], +["1mzd",2.9,3.35981326332218], +["1u2t",2.9,2.76106397663328], +["1e7k",2.9,3.32173839487701], +["1wsp",2.9,3.48299524529853], +["1muo",2.9,4.2649328138372], +["1va7",2.9,1.93060849579448], +["1nq1",2.9,3.62816186942348], +["1scq",2.9,2.04178726123737], +["1hlc",2.9,3.17277520715371], +["3prg",2.9,2.92207000245758], +["1a5i",2.9,3.1393622052456], +["1pl9",2.9,3.84771548052259], +["1an7",2.9,3.09658953152409], +["1cbr",2.9,2.90609814022388], +["1fiz",2.9,3.202393735022], +["1i1g",2.9,3.66114231314734], +["1wm0",2.9,3.60432229110677], +["1qqe",2.9,3.27796764418166], +["1ft4",2.9,3.90985294557972], +["2b0l",2.9,3.76204077554537], +["1d3q",2.9,3.1313815007778], +["1iqi",2.9,3.65002991033457], +["1ioe",2.9,3.74914109051263], +["1iqe",2.9,3.82841799073299], +["1rpz",2.9,3.44437067639247], +["1q1k",2.9,3.45521256163615], +["1hut",2.9,4.62702871230878], +["1rfg",2.9,3.96978254478614], +["1ovv",2.9,3.78416928604132], +["1jwa",2.9,3.31494014903725], +["1ptt",2.9,3.17435351606112], +["1zcl",2.9,3.91156012287773], +["1u0d",2.9,3.81661062233739], +["2bk0",2.9,2.51884777597239], +["2cbn",2.9,3.41318929687597], +["2fk6",2.9,3.47280089474534], +["1p6a",2.9,2.40340099256110], +["1bcf",2.9,2.99753294539239], +["1az2",2.9,3.47464223912276], +["1thy",2.9,2.89542828164697], +["1tsv",2.9,2.98054378124743], +["5lip",2.9,2.27556512524584], +["2bpf",2.9,4.05490956387891], +["1isn",2.9,3.38234807487828], +["9icm",2.9,3.95939106905795], +["7ich",2.9,4.05007826622025], +["7ick",2.9,4.00106750572115], +["9ico",2.9,3.97645019697372], +["8icm",2.9,4.02128205938185], +["7icq",2.9,4.00908351426418], +["9icq",2.9,4.0521011412544], +["9icu",2.9,4.03254316977216], +["8icp",2.9,4.10090897008552], +["9ich",2.9,4.07223029297661], +["8icr",2.9,4.13297450190282], +["1zqf",2.9,4.12348164227757], +["9ics",2.9,4.11479164248075], +["8icf",2.9,4.13317194282834], +["8ics",2.9,4.1540699694655], +["1c8o",2.9,3.4444594869047], +["1x7a",2.9,4.12987750095056], +["1agx",2.9,3.62348786389732], +["1grv",2.9,3.08516211870441], +["1l0o",2.9,3.51577944874504], +["1qp7",2.9,3.98945345167375], +["1qp0",2.9,4.07004914057361], +["2pua",2.9,3.95815198543951], +["1jfs",2.9,3.89694370452283], +["1lw7",2.9,3.68035784151578], +["1ctp",2.9,3.86668519429894], +["1vci",2.9,2.80862935971446], +["1nun",2.9,3.36076617949559], +["1f02",2.9,3.41416448407531], +["1zsh",2.9,3.78149004780903], +["1j7v",2.9,3.43904061416647], +["1jsy",2.9,3.73744282643997], +["2jdx",2.9,2.65626256433617], +["1ljy",2.9,3.38514813983318], +["2b40",2.9,3.22733843520533], +["1xhg",2.9,3.2679894536373], +["1tfv",2.9,3.71881155791526], +["1zbk",2.9,3.41731967595181], +["2aos",2.9,3.62946709936389], +["1kaw",2.9,4.40417518643987], +["4caa",2.9,2.97604185352733], +["1b7e",2.9,4.40331723984277], +["1es7",2.9,2.72958695858511], +["1cmk",2.9,3.55817586199228], +["1fo1",2.9,3.40378703450334], +["1rgq",2.9,2.51406598341725], +["2c5r",2.9,3.45033425297603], +["1adf",2.9,3.14121733844981], +["5adh",2.9,3.58289893846969], +["1hwh",2.9,3.75110649773754], +["1bp3",2.9,4.04997876240146], +["1jhn",2.9,4.28678924176311], +["1ce6",2.9,3.05761420346049], +["1zy0",2.9,3.64832522150366], +["2ghj",2.9,3.17263799873921], +["1py4",2.9,4.42636760783454], +["1zdj",2.9,2.56159267822308], +["1ir6",2.9,3.60688333492709], +["1yue",2.9,3.75204145085649], +["5tss",2.9,3.11419978942579], +["1z1f",2.9,3.29243840290821], +["1sm8",2.9,1.79808441481820], +["1kj4",2.9,3.12811018025232], +["1r5n",2.9,3.33872741518352], +["1ln3",2.9,3.38469476280285], +["1ln2",2.9,3.5726749417291], +["1jdn",2.9,3.36325161536654], +["1fh5",2.9,3.52247974666820], +["1fc1",2.9,3.03943424069592], +["1w7n",2.9,2.86664640868497], +["1k05",2.9,3.38547222218025], +["1nbq",2.9,3.88862190336004], +["2csg",2.9,2.99200694698748], +["1guk",2.9,3.38206107699645], +["2adj",2.9,3.47766389536058], +["2nmt",2.9,3.78397618151737], +["1h3e",2.9,3.14817521500141], +["1baf",2.9,3.06493772532369], +["1z3z",2.9,3.23440698416809], +["1b4j",2.9,3.81956310878132], +["1b2w",2.9,3.5141818907425], +["1nld",2.9,3.41851711806936], +["2dbl",2.9,3.56131417165397], +["1iaq",2.9,3.14574093690384], +["1yyo",2.9,2.99974904047065], +["1e32",2.9,3.45925781757435], +["1dq4",2.9,2.98410415116819], +["2bwt",2.9,1.51477860854930], +["1ejy",2.9,2.98213413103548], +["1cu4",2.9,3.13247148577342], +["1uhl",2.9,3.94798257802989], +["1nt2",2.9,3.80100185056664], +["1kcr",2.9,3.78996635315263], +["1q34",2.9,3.44375876171364], +["1mn9",2.9,2.90650030570414], +["1wv2",2.9,3.38684007177723], +["1i4h",2.9,2.99290911870751], +["1n10",2.9,3.32372732789656], +["2bde",2.9,3.33329392798041], +["1xnx",2.9,3.18331087771036], +["1jn1",2.9,3.76707365524995], +["1r1k",2.9,3.61075974892275], +["1nui",2.9,3.38183660447746], +["1ku2",2.9,3.16591414255682], +["1bpn",2.9,3.26839297916378], +["1bpm",2.9,3.30041674936128], +["2f8e",2.9,2.57329924114317], +["1yl6",2.9,2.7248086553524], +["1ssd",2.9,1.76864166033631], +["1ssg",2.9,2.39390088724189], +["1kmc",2.9,3.00415854949822], +["1p4l",2.9,3.81174782590185], +["2bct",2.9,2.71678406024649], +["1eku",2.9,3.29285103927816], +["1m5n",2.9,3.98728333126895], +["1pkn",2.9,3.66995444534978], +["1a5h",2.9,2.84465855870586], +["1hwo",2.9,3.99949037067358], +["1yom",2.9,3.18370673519335], +["1t98",2.9,3.19936301592050], +["1wnr",2.9,2.69015402118812], +["1v14",2.9,2.88730505320018], +["1xo2",2.9,3.56190384081494], +["1bkn",2.9,3.95584563228505], +["1gqf",2.9,3.41683898859159], +["1qik",2.9,2.92969061962235], +["1pgw",2.9,2.91361879413208], +["1hxg",2.9,2.42940263709919], +["1fbv",2.9,3.41209981162631], +["2fz1",2.9,3.98783704504179], +["2fz2",2.9,3.94368608535221], +["1bf5",2.9,3.59213568270976], +["5daa",2.9,2.37597117397551], +["1igz",2.9,3.64110859553976], +["1j9c",2.9,3.59358891376497], +["4dpv",2.9,3.18339003440664], +["1h79",2.9,3.2916367935015], +["1pkg",2.9,3.34481802170685], +["1xzq",2.9,3.47268341435485], +["1a9w",2.9,1.97758490431584], +["1nip",2.9,4.60002077925673], +["1y8w",2.9,3.22696842159338], +["1coh",2.9,1.79040959534516], +["2d4h",2.9,3.22109179821576], +["2a79",2.9,2.69503588983069], +["1zmu",2.9,3.11042126325512], +["1yi1",2.9,2.53233365561505], +["1hm7",2.9,3.55831972190355], +["1vkx",2.9,4.10577645239795], +["1f8u",2.9,3.1751202201884], +["1lqg",2.9,3.72791747133943], +["1xgn",2.9,3.45160531021901], +["1j4u",2.9,3.42674379804379], +["1qso",2.9,3.00181380577162], +["1tz3",2.9,3.4415132288404], +["1rqg",2.9,3.60102707182395], +["1f7v",2.9,2.93669170103098], +["2fsn",2.9,3.45765361975042], +["1mz6",2.9,3.52754475070993], +["1fbd",2.9,3.05933295711079], +["2a2g",2.9,2.55467365738230], +["1zca",2.9,2.38341812311780], +["1avc",2.9,3.26465151937856], +["1qf6",2.9,3.3850018335214], +["1cja",2.9,3.3299118327147], +["2cvu",2.9,3.12340524485295], +["2cvv",2.9,3.02242216106798], +["1j3h",2.9,3.07071028527129], +["1psa",2.9,2.75934796147315], +["1gpd",2.9,5.08358642363795], +["1zuj",2.9,3.54375524808780], +["1ph7",2.9,2.93067583237943], +["1gzu",2.9,3.86820444906932], +["1yvu",2.9,2.89265800745538], +["2agp",2.9,3.2687904518764], +["1tz9",2.9,3.52319517248366], +["1ybf",2.9,3.2673145533326], +["1brr",2.9,3.39932676547837], +["1tko",2.9,2.59079815106476], +["1u0h",2.9,3.1133976462899], +["1bnl",2.9,3.33914465340582], +["2aek",2.9,2.58857780677867], +["1yyt",2.9,2.89423645159856], +["1b3o",2.9,3.58086973231656], +["1o6c",2.9,3.15099858216483], +["1nkv",2.9,3.34377159532621], +["1fdi",2.9,3.51199573346866], +["1c9i",2.9,3.41700225667544], +["1vsg",2.9,3.01798024214329], +["1c9l",2.9,3.15846521179293], +["1o9t",2.9,3.50425945238615], +["1t13",2.9,2.81395985417636], +["1q1e",2.9,3.47762456832653], +["1g50",2.9,3.75984871122730], +["1rpw",2.9,3.47277683866616], +["1p3m",2.9,2.90773115454715], +["1p3k",2.9,2.91079595182685], +["1wuf",2.9,3.28468308487020], +["1p3f",2.9,3.12470363824086], +["1jt0",2.9,3.65222206670451], +["6adh",2.9,4.37372870719399], +["1r5w",2.9,3.60871522516838], +["1nrx",2.9,3.32293833677059], +["1xvl",2.9,3.64105618083127], +["1zla",2.9,3.04025226632733], +["1fs2",2.9,3.18687246602511], +["1tf2",2.9,3.32998598497816], +["1nfb",2.9,3.79000221694274], +["1gn6",2.9,2.21853397711643], +["1ser",2.9,2.66126981369000], +["2a4z",2.9,3.65867860908251], +["1ayn",2.9,2.25549349976776], +["1ruf",2.9,3.52009768084088], +["1rue",2.9,3.6248867861799], +["1rud",2.9,3.60090309623028], +["1r09",2.9,3.66911387331957], +["1yk1",2.9,3.25848320286759], +["1br8",2.9,3.54480201007283], +["1qjs",2.9,3.13605305798925], +["1mi1",2.9,3.3253136029753], +["168l",2.9,3.96462216460577], +["1m8e",2.9,3.10007036664536], +["1ncd",2.9,3.22902975953612], +["1azx",2.9,2.97877846972612], +["1d4m",2.9,3.02321110825625], +["1eah",2.9,2.46668357175034], +["1h8t",2.9,3.35229860155512], +["1um2",2.9,3.86336381749038], +["1e03",2.9,3.23113308998488], +["1piv",2.9,2.38525571606644], +["1vba",2.9,2.53113858952048], +["1vaf",2.9,3.31687203748208], +["1ar9",2.9,2.32353559491810], +["1ar7",2.9,2.30342773578847], +["1al2",2.9,2.28404862541849], +["1ar6",2.9,2.31117192465226], +["1asj",2.9,2.46670934251025], +["1vbd",2.9,2.48015387707703], +["1ar8",2.9,2.67154155605205], +["1po1",2.9,2.28794183945850], +["1po2",2.9,2.42312081614378], +["1fg9",2.9,3.80311173894134], +["1xqs",2.9,3.36639871997989], +["1ldc",2.9,3.49961494102074], +["1dj2",2.9,2.73196667909276], +["1iai",2.9,3.72755507329944], +["1aif",2.9,4.18569156246597], +["1rus",2.9,3.83910867427801], +["1lco",2.9,3.37479616910678], +["1him",2.9,3.18792351311078], +["4cts",2.9,3.86600494965765], +["1qu3",2.9,4.20783096264569], +["1f5o",2.9,2.38907696963453], +["1f5p",2.9,2.46287638487321], +["2tbv",2.9,4.09602891951400], +["2bvt",2.9,2.97648960658020], +["1tl1",2.9,3.34529403342587], +["2a0f",2.9,4.4596981583475], +["1shs",2.9,3.44624287370818], +["1k28",2.9,3.46238674403674], +["1y4u",2.9,3.32483445529549], +["1v6j",2.9,2.4362557683541], +["1rir",2.9,3.1623389287669], +["1rvy",2.9,2.84352311952674], +["1g9n",2.9,3.63324827968585], +["1rzk",2.9,3.73777007598495], +["1rt4",2.9,2.83638421792058], +["1rt5",2.9,3.05521846143415], +["1p8n",2.9,3.2245058045622], +["1hqf",2.9,3.88628399059761], +["2d3r",2.9,3.022052561601], +["1b9l",2.9,2.74966863176495], +["1dfc",2.9,4.00023443839819], +["1fko",2.9,3.53892793523653], +["1fkp",2.9,3.55540297414363], +["1y4s",2.9,3.5179810358803], +["3hvt",2.9,4.36137179864628], +["2c4c",2.9,2.72815027039941], +["1xdk",2.9,3.92431801607653], +["2bhl",2.9,3.55518796918181], +["1sv5",2.9,4.00711003299814], +["2b5j",2.9,3.89132793046943], +["1s6p",2.9,4.13841958697381], +["1jzr",2.9,3.16894056327547], +["1srq",2.9,3.35735612507567], +["1t5t",2.9,3.13241482784227], +["2csd",2.9,2.62688495648344], +["2bki",2.9,2.39825221782252], +["1pys",2.9,2.79666348417637], +["1ob1",2.9,3.54537914274451], +["1no7",2.9,3.95220499783045], +["1nen",2.9,3.35940305955966], +["1uw5",2.9,3.36243168263293], +["1bl9",2.9,2.66805810762040], +["4prg",2.9,4.17745782115302], +["1n15",2.9,2.3537814549756], +["1n50",2.9,2.38496665676788], +["1n90",2.9,2.38874160225781], +["1e8f",2.9,3.27489425840503], +["1zj9",2.9,3.21824114613076], +["2c5x",2.9,4.2225624501223], +["1a7l",2.9,2.47460853161379], +["2c5v",2.9,3.81685662473977], +["1nhv",2.9,2.90395166234259], +["1bml",2.9,4.04158208473406], +["1nb7",2.9,3.57897932774378], +["1ygr",2.9,3.85357795785432], +["1ygu",2.9,3.87023109507288], +["1dgs",2.9,3.21515130136893], +["1v9p",2.9,3.66902158081988], +["1vfk",2.9,3.1924248017704], +["1vfm",2.9,3.31487793876842], +["2a1b",2.9,4.00457441884573], +["1ze1",2.9,3.5475507601136], +["2pjr",2.9,3.86793395530330], +["1t72",2.9,3.5463334082055], +["1q3u",2.9,3.25192056442845], +["1sv6",2.9,3.40853786101728], +["1n8b",2.9,3.53970630296327], +["1ty5",2.9,3.05822847754699], +["1ty6",2.9,2.94404604125038], +["1cqj",2.9,2.99382950371449], +["1g3n",2.9,3.10581440325554], +["1nd5",2.9,3.46662259079147], +["2hpa",2.9,3.24596368759680], +["1jqj",2.9,3.95688490355775], +["1xcb",2.9,3.55112401830061], +["1us1",2.9,3.04328343956233], +["1fzb",2.9,3.54030180713521], +["1qu4",2.9,3.30184113359442], +["1fza",2.9,3.80770010642425], +["2c2v",2.9,4.32547031278374], +["1f9e",2.9,3.32722964520661], +["1tee",2.9,3.14624484336555], +["1ruz",2.9,3.36237914308684], +["1n73",2.9,3.65820374241036], +["1mql",2.9,3.47358439051092], +["1w1w",2.9,3.31608628102889], +["1ryz",2.9,4.02718132003379], +["3hmg",2.9,2.74922943531965], +["1hgg",2.9,2.83475307485456], +["2pfl",2.9,2.47467499228227], +["2ajf",2.9,3.26921887450673], +["1zyz",2.9,3.29257835741882], +["2f3o",2.9,2.67215459048814], +["1eqn",2.9,3.42546792920608], +["2abr",2.9,4.00425566846946], +["1e4o",2.9,3.64663809270505], +["1ias",2.9,3.28729331156147], +["1we0",2.9,3.33803444710431], +["1ul1",2.9,3.68975180040815], +["1ivs",2.9,3.89192476699019], +["1gax",2.9,3.94706992307181], +["2bte",2.9,3.20436214196252], +["2bvh",2.9,2.83618056826016], +["1h4t",2.9,2.81773289816215], +["1prt",2.9,3.40323280138209], +["1m3i",2.9,3.49622529419250], +["1h3c",2.9,2.79036378723019], +["1eji",2.9,3.28539352923836], +["1g6q",2.9,2.83518812537391], +["1d2r",2.9,3.12208260633292], +["1t9g",2.9,3.27085713655484], +["1vfp",2.9,3.30105783729809], +["1hht",2.9,3.0284822917078], +["1z7m",2.9,3.18736437500054], +["1tr2",2.9,4.15591159680389], +["1m54",2.9,4.04219681627998], +["1q3r",2.9,2.97540807612151], +["1maa",2.9,3.24415684329618], +["1pxx",2.9,3.3253700931009], +["1r1r",2.9,2.50368974345741], +["1d4c",2.9,3.58268846610006], +["1fsk",2.9,3.73326351590836], +["2tmg",2.9,3.49649655888527], +["1tye",2.9,3.11126086659867], +["1r0b",2.9,3.53924833328964], +["1s4e",2.9,2.71076290557663], +["1h8h",2.9,3.12326389348378], +["2c8n",2.9,3.10718846126489], +["1ijg",2.9,3.22150530317767], +["1zm4",2.9,3.27933415400999], +["2a7s",2.9,3.03128957084975], +["1qgn",2.9,3.35353869250263], +["9gpb",2.9,3.78633553185444], +["7gpb",2.9,3.66912497889329], +["1a9c",2.9,2.17630065537179], +["1gpa",2.9,3.85979421620829], +["1rzi",2.9,4.0092242607542], +["1h38",2.9,3.77879937141387], +["1ocz",2.9,3.26944812520277], +["1qvg",2.9,3.148192464898], +["1yjw",2.9,3.08874475668084], +["1mkd",2.9,2.54377518114715], +["1br2",2.9,3.69292897872245], +["1tnz",2.9,2.69756163716315], +["2ewo",2.9,3.64369581782547], +["1pjl",2.9,4.33977467159980], +["1soj",2.9,3.10741187587633], +["1yc6",2.9,3.08684505142418], +["1mx9",2.9,3.1394368590583], +["1zn2",2.91,3.23229023927828], +["1q1q",2.91,3.25275974532055], +["1t69",2.91,3.26846412200946], +["2bq5",2.91,3.02249665748349], +["2glu",2.91,3.19422937239041], +["1gt2",2.91,3.42790557658865], +["1qzu",2.91,3.92008218397783], +["1xxd",2.91,3.55124976279831], +["1kca",2.91,3.07023278492305], +["1x2h",2.91,3.28996492587546], +["2bn4",2.91,3.68065948124413], +["1q3v",2.91,3.49340897964073], +["1zr5",2.92,3.15387012491339], +["1xwd",2.92,3.22955404644122], +["2b5m",2.92,3.77040354446495], +["1xck",2.92,2.83885457105359], +["2ucz",2.93,3.15454754659224], +["1ff5",2.93,3.08251566209170], +["1eaw",2.93,3.57842020930378], +["1gld",2.93,3.97573630445823], +["1ja4",2.94,3.00923387941220], +["1ffl",2.94,2.73911500187228], +["1d3a",2.94,3.08637077642543], +["1gle",2.94,4.06281650235556], +["4rla",2.94,2.61493232320631], +["2bm9",2.94,3.072113630498], +["1bfr",2.94,2.22692510991847], +["1wbc",2.95,3.79435429284491], +["1fzp",2.95,4.7388723373017], +["1iy0",2.95,3.22638132993017], +["1v9i",2.95,3.64330881507133], +["1p8l",2.95,3.50090278918121], +["1yj0",2.95,3.24048162428224], +["2b20",2.95,3.41362664518021], +["2cfq",2.95,4.44134162004386], +["2b2u",2.95,3.83891435820366], +["1l2j",2.95,2.72006157799007], +["1ho8",2.95,4.76487898874755], +["1qos",2.95,2.66185508890468], +["1uwh",2.95,3.06586768521498], +["1p22",2.95,3.94728805125340], +["1de8",2.95,3.32068157743576], +["1p7d",2.95,2.95877791648102], +["1r8x",2.95,3.36244857374261], +["1ka8",2.95,3.77561690662347], +["1vi1",2.95,3.08716726836475], +["1yyu",2.95,2.86140904550228], +["1qjq",2.95,3.32881335068103], +["1u0n",2.95,3.55969602968558], +["1jup",2.95,3.75957853868086], +["1u1u",2.95,4.17531745267071], +["1n59",2.95,3.10209719643159], +["1s7r",2.95,3.10498586758308], +["1a0o",2.95,3.13491705773684], +["1o0u",2.95,2.77326563021772], +["1t34",2.95,3.2160652961078], +["1rv4",2.95,2.68610430724714], +["1p8q",2.95,3.27427845975989], +["1zkm",2.95,3.49412491693376], +["1ngm",2.95,3.61526435495417], +["2ban",2.95,3.89660516274923], +["1sh3",2.95,3.0502981557942], +["1xhu",2.95,3.69812508423252], +["1jed",2.95,2.80413888683123], +["1djz",2.95,3.71210363779885], +["2bxe",2.95,3.03345724136067], +["2bxf",2.95,3.08260365371412], +["1syr",2.95,2.90303619067803], +["2fhy",2.95,2.77980980195856], +["1ywk",2.95,3.37625707654692], +["2ecp",2.95,3.22002550995151], +["1f6m",2.95,3.38546021130686], +["1k93",2.95,3.64685895179754], +["1v5b",2.95,3.44056116095324], +["2buf",2.95,3.73920143033793], +["1q81",2.95,3.18636132070229], +["2bo7",2.95,2.54015482255984], +["1ja6",2.96,2.95319541888584], +["2ldx",2.96,4.49302409039005], +["1rrp",2.96,3.94389206341146], +["2fpg",2.96,3.13522654648174], +["1qvu",2.96,3.53805207217813], +["2etk",2.96,2.36307659988954], +["1p8o",2.96,2.90312103808899], +["1xls",2.96,3.72717703187867], +["2aow",2.97,3.00386545814815], +["1jty",2.97,3.80666990087997], +["2d5n",2.97,3.51044913687352], +["1kyo",2.97,3.20010340627194], +["1sf4",2.98,2.72434214575632], +["1ja7",2.98,3.35567025728113], +["1im0",2.98,3.11961205065829], +["1zx4",2.98,3.95873283919231], +["1jum",2.98,3.62045990742561], +["1zvv",2.98,3.97244205560921], +["1th4",2.98,3.76009358946323], +["1q82",2.98,3.07556986763583], +["2be1",2.98,3.92411637325307], +["1pem",2.99,3.12788061824526], +["1vel",2.99,3.0448483669232], +["1bxz",2.99,3.21932277272078], +["1b3k",2.99,3.25712072278791], +["2fhh",2.99,3.34520975970202], +["1pf9",2.99,3.23276979034645], +["1dgc",3,2.90171196187350], +["6cro",3,4.27387611358778], +["3orc",3,4.36547166562846], +["1aum",3,1.92169021967359], +["1ccd",3,3.77367784964016], +["1jl9",3,3.64564063666485], +["1qoj",3,4.08022800072084], +["1whp",3,2.24489388812517], +["1avv",3,3.37554455294285], +["1fav",3,2.79793402525255], +["1ayb",3,2.65721722381100], +["1cry",3,3.84015789484703], +["1dh3",3,4.66195871531596], +["2ere",3,3.76134680757196], +["1cjq",3,3.28247225351868], +["1h2q",3,3.08083368985355], +["1od7",3,3.00251704763189], +["2bp2",3,4.45764408781927], +["1af5",3,4.17485759092536], +["1uot",3,3.39615466389375], +["1oct",3,2.97590828024905], +["1hij",3,3.18875232875794], +["1bh8",3,3.03566788617375], +["1le2",3,3.79569191957567], +["1fyw",3,3.44482116053928], +["1r4r",3,3.85943700648858], +["1s60",3,3.6229032989241], +["1ufu",3,3.36583418203353], +["2bt8",3,2.93580579535136], +["1bsk",3,1.99869100579659], +["1bsj",3,2.15966113167215], +["1wg3",3,3.5151879439386], +["1ynw",3,3.70715192252573], +["1h9v",3,2.63212575087319], +["1rrf",3,3.87611212776853], +["1dov",3,2.48906432430837], +["1r8i",3,3.59999326629279], +["1v1f",3,3.61086493258369], +["1hrp",3,3.50503680758474], +["2upj",3,3.03948307106213], +["1yt9",3,3.17114652405418], +["2hpf",3,3.86298789776526], +["1ij9",3,2.75554337470753], +["2dl2",3,3.93405963304878], +["1b6u",3,3.87581356800159], +["1o3s",3,3.43062434028887], +["1o3r",3,3.07524052460804], +["1o3q",3,3.37158883691991], +["1dr9",3,3.40904815470653], +["1ykh",3,3.24891133771335], +["1if1",3,4.85670434782736], +["1vzv",3,3.77095113595654], +["1ay9",3,2.24843423053994], +["1fhe",3,4.4458064117752], +["1niv",3,2.57701241084817], +["2blb",3,3.39943309655522], +["1b0f",3,2.86731719798265], +["1rmp",3,3.10096387942325], +["1nhy",3,3.47758090171492], +["1ja3",3,4.41932008522075], +["1x3g",3,3.359879701353], +["1ql8",3,2.73369519443262], +["1nde",3,3.7858891051896], +["1e2o",3,2.73658010307287], +["1lem",3,3.03537886124270], +["1zp2",3,3.15659820809641], +["1iu3",3,4.11546158141419], +["1bu2",3,3.32683415220972], +["1rhr",3,3.76705373433573], +["1j5t",3,3.34616084682845], +["2fpf",3,2.85859300131073], +["1r6g",3,2.74765259810305], +["2not",3,2.39672272936595], +["1rfb",3,4.71414643871739], +["1yow",3,3.31641320335236], +["1dcm",3,3.30467613050253], +["1nom",3,3.91087355563114], +["2avi",3,3.32682618959871], +["1k8r",3,3.35027996136578], +["1ex3",3,4.35444109907849], +["1fv9",3,3.95942055072354], +["1yhn",3,3.81753851627303], +["1pdg",3,4.36320960621650], +["1ijd",3,4.17773323327705], +["1avz",3,3.16059420434416], +["1o7y",3,3.84481529718791], +["1foc",3,4.71509377622164], +["2axm",3,3.22745297715507], +["2c6j",3,3.82507785805793], +["1plr",3,3.65955715680879], +["1hes",3,3.13549418324587], +["1cne",3,4.37260264014109], +["1b3j",3,4.12471259955581], +["2bj1",3,3.29767391244455], +["1dpr",3,3.99114220732457], +["1apg",3,3.21117690249217], +["1gl0",3,2.49312318648019], +["1mvx",3,3.15881164619556], +["2bj9",3,2.37907110432749], +["1ny3",3,3.50855231603416], +["1jyf",3,2.92087641884696], +["1w2o",3,2.76788027143519], +["1gg0",3,3.39409894981056], +["1t7z",3,2.85232445641691], +["1exj",3,4.54754972321754], +["2ayu",3,3.84850260769534], +["1pyp",3,5.06289159445136], +["1wat",3,3.70335552310154], +["1d3t",3,3.17676234202864], +["1iqh",3,3.51464840769316], +["1iqj",3,3.69317066014882], +["1s0h",3,3.88222429051019], +["1nrp",3,4.57215386936322], +["1fax",3,3.09919687912539], +["1h6s",3,2.69718917436837], +["1dwc",3,3.08180098531610], +["1dwd",3,2.89476598636819], +["1dwe",3,2.72663658120827], +["2ldb",3,3.87981688821169], +["1w8b",3,2.51313056167129], +["1ko6",3,3.93194666060826], +["1zrz",3,3.84497690892176], +["1qo4",3,2.24156745483785], +["1g19",3,3.19641711064411], +["1ral",3,4.00994382351839], +["1t62",3,3.35327032934912], +["3vtk",3,3.73258629959572], +["1aow",3,3.95536614773186], +["1h56",3,3.20914311743542], +["1kq5",3,3.11579654969449], +["1hvg",3,3.00443940404616], +["1tsm",3,3.4108092337337], +["1ee9",3,3.09419472504775], +["1n44",3,3.5585373460595], +["1nph",3,3.56083548928774], +["1llc",3,4.20386564352723], +["1qml",3,4.00903602969646], +["1yx9",3,2.87718013466480], +["9ict",3,4.02344007578569], +["7icg",3,3.99616664290919], +["7icm",3,4.07219540204649], +["7icp",3,3.99183867056414], +["8icq",3,4.06825672455455], +["8ica",3,4.09005617781529], +["9ica",3,4.14434367314834], +["1zqn",3,4.04215888696049], +["8icx",3,4.12871175048172], +["9icy",3,4.14640404013355], +["9icr",3,4.09890020583829], +["9icn",3,4.08391417999444], +["7icr",3,4.10730850825823], +["9icf",3,4.17331756959404], +["9icg",3,4.15878867049488], +["8icu",3,4.17701544580668], +["1g0y",3,3.35552443644433], +["3ldh",3,4.98047005863542], +["2c7j",3,3.02445289640018], +["2er0",3,3.32637740686164], +["1qb3",3,3.24349389673485], +["1qqa",3,3.95559034625924], +["1qp4",3,3.93757555215492], +["2puf",3,4.08365224251346], +["1bdi",3,4.07886488537355], +["1bt9",3,3.00343615991986], +["1hxu",3,2.68481441386508], +["1mpf",3,2.91061981225846], +["1mbt",3,2.79373502622755], +["2g9d",3,3.90162523201843], +["1sv2",3,2.92547698246348], +["1rpa",3,3.36245612478777], +["1rpt",3,3.61590002667480], +["1kig",3,3.84560231326175], +["1kdh",3,3.48499657080224], +["1kej",3,3.78570913304824], +["1m6e",3,4.21362583666144], +["2g41",3,3.11234488181215], +["2fdm",3,3.13996789427344], +["1gdt",3,3.27128042860883], +["1zoo",3,2.53367267633722], +["1pfx",3,3.75798210615801], +["1ue8",3,3.64186607564554], +["1ovz",3,3.47617209727323], +["2chr",3,2.86148915043302], +["1d5s",3,3.39407843569656], +["9api",3,2.48210895167577], +["7api",3,2.92220654768796], +["1io4",3,3.50067697613660], +["1xrb",3,3.19479011217910], +["1xra",3,3.24749980775750], +["1xrc",3,3.25709040244523], +["1x3w",3,4.08290410188584], +["1mxc",3,3.11183416248314], +["1e28",3,3.26204740146821], +["1grc",3,3.09154564540717], +["1hhh",3,2.45131819755286], +["1fl7",3,3.47767889202942], +["1zy1",3,3.51969878370001], +["1mva",3,2.32453571394743], +["1aq4",3,2.59224177792164], +["2bny",3,2.57744384126608], +["1mvb",3,2.34722141184894], +["2ala",3,2.65360178125237], +["1shl",3,3.17617696501155], +["1ytz",3,3.7919334372876], +["1zmy",3,3.21697394689635], +["1bgj",3,2.79098458604843], +["1wc4",3,3.19935327050498], +["1cgp",3,3.21397660437292], +["1yq1",3,3.61624727089551], +["1z5w",3,3.63486133087743], +["1slh",3,1.75778902192027], +["2pro",3,4.45994259994132], +["2rve",3,3.7167356467605], +["1vgz",3,3.18426355422877], +["1jq7",3,3.90552610264112], +["1i5e",3,2.80866061689739], +["1wcd",3,3.20566304187582], +["1jnl",3,3.31305470719365], +["1fig",3,3.84927279102141], +["3ck0",3,3.60766869938630], +["1cl7",3,3.79182706867823], +["2fgw",3,3.3960651775265], +["1y6e",3,2.9026569065252], +["2afv",3,3.03887526325395], +["1dbk",3,3.496790052544], +["32c2",3,3.99707761970053], +["1ae6",3,3.40279410134696], +["1rw3",3,4.19316907460828], +["1acy",3,3.40198074727228], +["1vcp",3,3.2942488731942], +["1fpt",3,3.42155483223149], +["1dt6",3,4.02775608611751], +["2bri",3,3.34680644954006], +["2b7y",3,3.79894094577657], +["1qag",3,3.70816822074280], +["2ig2",3,3.33706043842719], +["2atc",3,5.05532495884545], +["1rhq",3,3.89706247887908], +["1r20",3,4.02122061626241], +["2a9n",3,2.94484831054663], +["1f9k",3,2.80676855533126], +["1ddn",3,3.65905055910405], +["1n4d",3,3.36809002689489], +["1lm7",3,3.55942270794699], +["1f5t",3,3.29945336489569], +["1wne",3,3.01741307636996], +["1fq1",3,4.08954581230995], +["2taa",3,4.83014125315906], +["1ti8",3,3.64021357146734], +["1z6a",3,3.76565765520291], +["1zdl",3,3.43133948438214], +["1tdo",3,2.57006778782975], +["2d7s",3,3.63005819303036], +["1bmt",3,3.36553305169427], +["1mo2",3,3.71874850845126], +["1ka4",3,2.77866254355569], +["1ism",3,2.86011564800046], +["3csm",3,2.96428980224616], +["1hjb",3,3.67906021221282], +["1m8k",3,2.86696396723820], +["1ze2",3,3.49526586624070], +["1d0e",3,3.80938510081409], +["1s28",3,3.65408060560172], +["1hux",3,3.22460974175097], +["1lp3",3,4.10047785407257], +["1r10",3,3.33749358286024], +["1qru",3,3.27477789164773], +["1ijf",3,1.84671205278105], +["1y5r",3,3.11840991681151], +["2ass",3,3.37288036375664], +["1i4e",3,3.96083803324512], +["1qim",3,2.98692337230323], +["1gqs",3,3.08012258117948], +["1c8e",3,3.50435828556429], +["1mru",3,3.60542800047949], +["2f1t",3,3.54080409961503], +["1gqw",3,3.22611354294302], +["1zd2",3,3.28214153761918], +["2cas",3,3.4676422518013], +["1c8d",3,3.20322788267933], +["1c8g",3,3.41058859344173], +["1c8f",3,3.53109143540676], +["1de9",3,3.03220342817622], +["1fe2",3,3.73678110176694], +["1diy",3,3.64784045522810], +["3hfm",3,4.17238243101589], +["1adu",3,2.84416765627665], +["1ny7",3,3.09727947571528], +["1eh9",3,4.60479677962702], +["1eha",3,4.65222047134289], +["1bmv",3,4.13680834978827], +["1w2k",3,2.9711260692902], +["1hlt",3,4.06786889641315], +["1seu",3,2.74813555182461], +["1t8i",3,3.13476227998312], +["1equ",3,3.73259511894164], +["1sc7",3,2.61607438879719], +["1cmy",3,3.62938426081333], +["1b9y",3,3.02326847177122], +["1b9x",3,2.82651906843098], +["1xxp",3,2.48851753406658], +["1k7y",3,3.19269326733319], +["2aw6",3,2.72490143844916], +["1tp8",3,2.53409323965081], +["1awh",3,3.6715833492948], +["1iis",3,3.94342831935308], +["1w87",3,3.274977286407], +["1s48",3,3.41760386509314], +["1s49",3,3.41976300618509], +["1fss",3,3.08325102879110], +["1r4l",3,4.17682778869406], +["1d9f",3,2.9765067776014], +["1d6m",3,3.18292822601718], +["1cii",3,3.25590887477499], +["1gff",3,4.19723794994798], +["1bp7",3,3.68494771316464], +["1mqs",3,3.63032801892018], +["1nma",3,3.39087424554931], +["1rlv",3,3.80064676495868], +["2aeq",3,3.73124164966447], +["1smv",3,2.83067242949721], +["1u7x",3,3.67537809961586], +["2g6t",3,3.40959553771756], +["1c6v",3,4.04570860372399], +["2a87",3,3.26450180446515], +["1fpk",3,3.13559363784108], +["2akq",3,3.88955190466228], +["1fbg",3,3.13121441800128], +["1fbe",3,3.46767262788737], +["1c8b",3,3.81976325368479], +["1gxk",3,3.63055007030255], +["1i8l",3,3.46904558290429], +["1x9n",3,3.93159708142804], +["1bo1",3,3.44752976428993], +["2bpa",3,3.41247487535423], +["1hak",3,3.11678316551324], +["1e6j",3,2.49396014550219], +["1ihi",3,3.29409960826891], +["1z3i",3,3.01681721192206], +["1c4t",3,2.84137876770014], +["2aho",3,3.83804859427653], +["1rqd",3,2.35304952494375], +["2ahd",3,3.64831644994790], +["1l5t",3,3.39554262502043], +["1fq9",3,3.09397025592534], +["1zbe",3,3.14402831833104], +["1ebo",3,3.50240529127018], +["2avu",3,3.65557541092189], +["1viw",3,3.79893954728198], +["1peo",3,3.28467270752235], +["1zvu",3,2.89565189434655], +["1a5c",3,3.09183304824868], +["1g88",3,3.07343681103949], +["7cgt",3,3.13078023583267], +["1rgi",3,2.88786486527423], +["1b8h",3,2.89487683125795], +["1gyl",3,4.61430955465979], +["1cjv",3,2.27701647296373], +["1uk1",3,3.83671295871106], +["1uk0",3,4.28419325499132], +["1cjk",3,2.34221927050896], +["2ayq",3,2.86292703815172], +["1tve",3,3.61601393944982], +["1rfq",3,4.53981150330211], +["4rve",3,3.99827022095108], +["1piw",3,3.51600882921668], +["1sp9",3,3.35712902465649], +["1hv8",3,3.6170177831899], +["1rpq",3,2.63209988281614], +["1hlg",3,3.17439334114418], +["1d8e",3,2.62070613613008], +["1p3a",3,2.92954236166497], +["1chr",3,3.9504858611038], +["1dva",3,3.94623555501556], +["1p3b",3,3.02968170416081], +["1zt4",3,3.66582037189286], +["1u35",3,3.11887233952796], +["2fni",3,2.37868688636249], +["1qc9",3,3.66880757420815], +["1zt7",3,3.08950380049493], +["1axm",3,3.31450933606988], +["1efx",3,3.54513071048726], +["1sze",3,3.41105740137574], +["1dch",3,4.20225470300195], +["1miw",3,3.16951622075660], +["1ant",3,3.82035147682647], +["1tau",3,3.77289368098952], +["1bev",3,3.01945998217820], +["1pst",3,3.50146347078756], +["1pss",3,3.59554207866489], +["1tuy",3,3.09110801523726], +["1ruj",3,3.52298826714022], +["1rui",3,3.59690148973834], +["4rhv",3,3.54362804769437], +["1vrh",3,3.59585539108531], +["2r06",3,3.62042103823457], +["1r08",3,3.62693414197538], +["2rs1",3,3.59710029079252], +["2rr1",3,3.59599276344322], +["2rs5",3,3.61776604930229], +["2r07",3,3.65131076327421], +["2hwb",3,3.65624160607941], +["1hrv",3,3.59837340234224], +["2rm2",3,3.62774953690598], +["2hwc",3,3.64723833710795], +["1rug",3,3.6314629347278], +["2rmu",3,3.58959861076205], +["2rs3",3,3.65522480471966], +["1ruh",3,3.61814228208773], +["1rmu",3,3.60820829737127], +["2r04",3,3.63735428341639], +["1hri",3,3.71564678679329], +["1tat",3,3.52465257084911], +["2mev",3,3.58544868965234], +["1rhi",3,3.19869384455324], +["169l",3,4.12638630394462], +["1m74",3,3.62903840562265], +["1ein",3,3.28513761920287], +["1e9y",3,3.59690903066735], +["1e9z",3,3.86947632874409], +["1gxl",3,3.63734371347505], +["1ldj",3,4.23813823730459], +["1gh7",3,3.57752045774108], +["1jzq",3,3.64958622995259], +["1yst",3,4.29988203661701], +["1yuh",3,3.96576469302342], +["3gsb",3,3.07327849623827], +["1qz2",3,3.54498894172742], +["1t04",3,3.17904659003093], +["1wup",3,3.67664376376787], +["1dj3",3,2.79520662112148], +["1hnc",3,2.93768068787996], +["2hck",3,3.25367679832459], +["1azy",3,2.85838088798392], +["2bxr",3,3.2789649671982], +["1he8",3,3.30562077131352], +["1h6z",3,3.41554137961234], +["1h0m",3,3.45356429441157], +["2rla",3,3.76982386085981], +["1rt3",3,3.09223676339919], +["2bg4",3,3.15162900756909], +["1lw2",3,3.53333013272688], +["1osg",3,2.86589032606623], +["1s1u",3,3.43901045031194], +["1h4q",3,3.02411930893287], +["1z63",3,3.55259382752961], +["1jlc",3,3.77910629316404], +["1u2d",3,2.45522667671812], +["1jlq",3,3.65606798242086], +["1qot",3,2.83693164377001], +["1hqx",3,3.69189768378096], +["1m3j",3,3.90790092576455], +["1val",3,3.16721198638581], +["1dtt",3,3.60310724355774], +["1rt7",3,3.21844148102461], +["1jlb",3,3.47703390779532], +["1rti",3,2.96735623086041], +["1ikv",3,3.47484526249548], +["1ikw",3,3.30016777251629], +["1iky",3,3.41791430030789], +["1a3x",3,4.04294817816774], +["1t05",3,3.98427126938834], +["1joj",3,3.44667054551645], +["1a3w",3,4.06022741473189], +["1a0l",3,2.98156965989448], +["1suq",3,3.90331843171921], +["1s6q",3,3.78464226010465], +["1hnv",3,3.88582441566964], +["1glj",3,4.31304055445656], +["1bwf",3,4.37379693554867], +["1gll",3,4.58865447564779], +["1tvr",3,4.23906171692538], +["1hpz",3,3.65277998608492], +["1xv8",3,3.10023660154987], +["1xp5",3,3.5713955976501], +["1jn0",3,3.7628308239132], +["1d2h",3,4.53604343235224], +["1qat",3,3.15710754794328], +["1kcw",3,3.63262665847557], +["2br7",3,2.97694706799386], +["1fez",3,3.75956276258758], +["1zyc",3,3.69342112946625], +["1ek2",3,4.3305876424076], +["1z2c",3,3.29645547892086], +["1ypo",3,2.9570286770536], +["1f8v",3,3.19346269541767], +["1kqm",3,4.3939139151956], +["1qbk",3,4.16984765600448], +["2f43",3,3.96382952380548], +["1nbi",3,3.87740876093805], +["1w1m",3,3.39439944866905], +["1fpm",3,3.8511440745183], +["1pkq",3,3.6399464609031], +["2bhv",3,3.03926131372064], +["1fbi",3,3.68845137039300], +["1myp",3,4.51711335174595], +["1owr",3,3.24500628874279], +["1cj1",3,3.29015907897084], +["1hbs",3,4.63187786710963], +["1kkq",3,4.03168532105473], +["1juj",3,3.33187388596], +["1k23",3,3.13969977540952], +["1z0v",3,4.05484073600569], +["1i7x",3,2.72357427054382], +["1z0t",3,3.93147826196587], +["1efw",3,3.93446773033224], +["1ktk",3,4.15712777625805], +["1le9",3,4.07940585298634], +["1g1y",3,3.20083853851729], +["1f51",3,3.91077256004502], +["1mr9",3,3.693819896417], +["2axv",3,2.82580472078242], +["2axz",3,3.29981103686070], +["2cge",3,3.61193543243954], +["2c6n",3,3.74699160893138], +["1gti",3,2.28841895421810], +["1ahw",3,3.83453847618065], +["1ltk",3,3.6477429930325], +["1rj2",3,3.75636399964045], +["1mpq",3,3.27246309586257], +["1uaa",3,4.31481970494306], +["1tah",3,2.75299553155813], +["1yvl",3,3.67767805402275], +["2erj",3,2.8704023252901], +["2a7r",3,3.25499402308442], +["1rxt",3,4.04937400609128], +["1t2f",3,3.71099958095227], +["1qle",3,3.75575921042563], +["1ihy",3,2.98271916667484], +["1pvj",3,3.12014172893284], +["1qol",3,3.26487163013886], +["1gmo",3,3.12819304819140], +["1rp5",3,3.00158051715237], +["1xdo",3,3.47845728012973], +["1fze",3,3.15935552913266], +["1g4a",3,4.30422854081295], +["1wok",3,3.80764585299214], +["1hys",3,4.0156879740963], +["1n6q",3,4.01086508095907], +["1bvs",3,4.754623223439], +["1jh5",3,3.55189515302209], +["2d0p",3,3.76640936023997], +["1ltl",3,3.36333775060725], +["1vz7",3,3.58719513658426], +["1ord",3,3.49110956348552], +["1llz",3,3.89861235545753], +["1agn",3,3.20494690381102], +["1a81",3,4.53351526319396], +["1hgf",3,2.68399361680481], +["4hmg",3,2.84233936422556], +["2hmg",3,2.97191465751194], +["1m5y",3,3.23400786189194], +["1rd8",3,3.32736946598029], +["1crk",3,3.27011510502390], +["1n3n",3,3.42507351645588], +["1ycf",3,3.4313681877425], +["1yah",3,2.66794428191808], +["1ya8",3,3.07479725207930], +["1ojl",3,4.13785956458469], +["1wb1",3,4.36079527309565], +["2cxe",3,4.44016274285418], +["2nsi",3,2.69858060052935], +["3kbp",3,3.31550861035189], +["2fl5",3,3.32864432661226], +["1e0j",3,3.77388352461212], +["1gum",3,3.34928898805023], +["1a0d",3,2.7628350053656], +["1zs8",3,3.33576349735065], +["1kpl",3,3.30526149962446], +["1vf5",3,4.33200394127419], +["1jqo",3,3.51593550711995], +["2b24",3,3.33257120450122], +["1nlz",3,3.26650499407863], +["1v6o",3,2.90790937716787], +["1l8i",3,3.0669339532372], +["1gph",3,2.88749147115344], +["1s26",3,3.5220912951084], +["1zq1",3,3.59908658593424], +["1qi1",3,2.53566186408305], +["1maw",3,3.43772271278632], +["1mio",3,3.4648525663525], +["1wac",3,3.25025082503905], +["1ukl",3,3.70712987405042], +["1hi0",3,2.9064471894087], +["1hi1",3,3.25301882415451], +["1uvn",3,3.61631340636126], +["1urj",3,3.21382107986997], +["2a3x",3,2.92898518138969], +["1be3",3,4.14408872050130], +["1gnh",3,3.05736415160097], +["1sqq",3,3.3515419117044], +["1i33",3,2.93304145856286], +["5cox",3,3.89684767685715], +["1cx2",3,3.96288758400296], +["1ddx",3,4.35574386330287], +["1m57",3,3.91669402206260], +["3r1r",3,3.07606488853297], +["2r1r",3,2.89104719966918], +["1r8y",3,3.22102909780889], +["1aip",3,3.75552374592994], +["1s4f",3,3.85182844096755], +["1xdm",3,3.7435124611683], +["1n32",3,3.70390092585074], +["1pvo",3,3.51786233242205], +["1pv4",3,3.69503688679424], +["1xmq",3,3.56357130357357], +["1fjg",3,3.58447717363094], +["1xdl",3,3.78316733559761], +["1qvr",3,3.45295052291508], +["1do0",3,3.75011523404042], +["1b26",3,2.40381838394070], +["2pda",3,3.50180811194579], +["1gki",3,2.98687689989824], +["1gl7",3,3.27399080108592], +["1zcf",3,3.22625743276619], +["1lkx",3,3.65035310673542], +["1h4j",3,2.83393719930973], +["1t8y",3,3.21973222329520], +["1xfd",3,3.77830937382496], +["1ea0",3,4.09130011107266], +["2f1d",3,2.66822627680961], +["1x9j",3,2.88467739201863], +["1nbm",3,2.58427624968664], +["1w5e",3,3.45739303282095], +["1g21",3,3.70469458769699], +["1n2c",3,2.78813318567824], +["1ulq",3,2.94432523758109], +["1sxi",3,3.88209357735164], +["1k0u",3,3.65853449384008], +["1twc",3,3.73327688302442], +["2gfb",3,3.3007371785188], +["1nji",3,2.97164759987213], +["1k9m",3,3.04722540788571], +["1q86",3,3.10940971955760], +["1kd1",3,3.07909998597843], +["1k8a",3,3.08165460194820], +["1n8r",3,3.12522247171726], +["1jjk",3,3.67171547736668], +["1yjn",3,3.15325020412438], +["1wdw",3,2.83898412766335], +["2cb6",3,3.1025587603604], +["1z7e",3,3.1545352296657], +["1kiu",3,3.8403055197158], +["1qki",3,3.07107231263182], +["1bgy",3,4.12116675030019], +["1r4m",3,3.28213395860600], +["1hn1",3,3.7072819737483], +["1xfb",3,3.18480782948255], +["1q3s",3,3.39831761935635], +["1f3w",3,3.20367810999349], +["2ex3",3,2.32485062850043], +["1gtp",3,2.30847413477075], +["1jrp",3,3.55736286755086], +["2axt",3,3.54793628421395], +["1jd2",3,3.28706899349873], +["2fny",3,3.14851214075655], +["1zyr",3,4.16888606977088], +["1mnf",3,2.7675489723524], +["1aon",3,3.89625666874907], +["1sx4",3,3.45747979460809], +["1y6j",3.01,3.48781725954834], +["1ps0",3.01,3.60980305399635], +["1z5s",3.01,3.57085728465065], +["1yfh",3.01,3.09015635468439], +["1tly",3.01,3.12364675244489], +["2boc",3.01,2.89332871691635], +["1yvk",3.01,3.39097997387126], +["1jgx",3.01,2.87434893186713], +["1hr9",3.01,2.97597681196253], +["1k73",3.01,2.91825412085961], +["1kc8",3.01,3.02778616561113], +["1k1d",3.01,3.24018286856325], +["1g2m",3.02,3.12751913791557], +["1ii8",3.02,3.68555620782023], +["2b12",3.02,3.23957552500428], +["1u8o",3.02,2.75151764741999], +["2a30",3.02,3.16541475569125], +["2a2z",3.02,3.25843262641149], +["1jch",3.02,4.34947481113464], +["1ua2",3.02,3.85261242489027], +["2byj",3.02,2.09737094146107], +["1vcg",3.02,3.48477927995635], +["1p75",3.02,3.16974867195067], +["1tij",3.03,3.28648059942742], +["1zy2",3.03,3.50262640175195], +["1w1i",3.03,3.0351489699362], +["1ltr",3.04,2.49220305093328], +["1lpa",3.04,3.20343744827820], +["1n8s",3.04,3.52235488640723], +["1vak",3.05,2.85596010785726], +["1fos",3.05,3.05686650038933], +["1nys",3.05,3.45530112386713], +["1zu8",3.05,3.39636492798931], +["1sr0",3.05,3.31162527020978], +["1ksy",3.05,3.06354434864983], +["1pp8",3.05,4.49809565089678], +["1y64",3.05,4.40141941217433], +["1vcw",3.05,3.70983825908128], +["1xiq",3.05,3.10270006860550], +["1bot",3.05,4.36499092756198], +["1xct",3.05,3.81617388276883], +["2bxd",3.05,3.14732802476609], +["1ztm",3.05,3.35724284658654], +["1xn1",3.05,3.2462755212199], +["1xnq",3.05,3.76290425255165], +["1j5e",3.05,3.64871971613317], +["1xpu",3.05,3.04133858057628], +["1p53",3.06,2.85716098051587], +["1jjo",3.06,3.93182436397134], +["2bcj",3.06,2.17456556781503], +["2cxf",3.07,3.2617743844703], +["1z5x",3.07,3.20606551333306], +["1zm2",3.07,3.34652465608482], +["1zm3",3.07,3.40480136670445], +["1l3w",3.08,4.23365405154915], +["1t9x",3.08,3.67398379591927], +["1fub",3.09,3.88342449926061], +["2fkh",3.09,3.05039298608455], +["1tda",3.09,3.65273699766975], +["1faw",3.09,2.99772079518760], +["1qx7",3.09,3.95821923427556], +["1yfl",3.09,3.55723129953554], +["1w57",3.09,3.21660800289411], +["1ifp",3.1,2.38516368019234], +["1ql1",3.1,2.96649699864733], +["1nyh",3.1,2.84649772229195], +["1u6b",3.1,3.09107221558209], +["1fhi",3.1,4.06395012613657], +["1zlk",3.1,3.26173414225013], +["1ql2",3.1,2.85177627891565], +["1r4i",3.1,3.56493420902725], +["1kxc",3.1,2.60463200980388], +["1kxa",3.1,2.84103908999439], +["1llt",3.1,2.93651243234732], +["1c7y",3.1,3.57099633034116], +["1fqx",3.1,3.11179869855107], +["1mfq",3.1,3.42994617980926], +["1ddk",3.1,3.72378225303422], +["1un6",3.1,3.38015661391070], +["2cbf",3.1,3.80465832185314], +["1nuo",3.1,3.69992943633433], +["1qqk",3.1,4.11507948744837], +["1y0x",3.1,3.07557504928604], +["1g5u",3.1,4.37851863404769], +["1il9",3.1,2.91402461201167], +["1i3p",3.1,3.58811508289205], +["1t7x",3.1,2.79143816657729], +["1vg2",3.1,2.96500362816591], +["1lfz",3.1,3.6449174951464], +["1nro",3.1,4.64456109075967], +["1gub",3.1,2.79619351661279], +["1nrn",3.1,3.95073889116316], +["1nyu",3.1,3.67628595677068], +["1vcq",3.1,3.22330976604285], +["1nwe",3.1,2.31861082035638], +["1a87",3.1,3.35988969263825], +["1ij6",3.1,3.33272647781064], +["1p69",3.1,2.68835771374059], +["1mo3",3.1,3.35442191261526], +["1cko",3.1,3.19825198521827], +["1gfn",3.1,2.93106248134916], +["1mq2",3.1,2.36772760280607], +["8icz",3.1,4.1150298924182], +["7icf",3.1,4.05636872893673], +["8icb",3.1,4.12661094871347], +["9icj",3.1,4.20381518021396], +["1zqg",3.1,4.14834580303431], +["1zqh",3.1,4.21457968633868], +["7icl",3.1,4.14230993057272], +["8icl",3.1,4.17405191756948], +["8ict",3.1,4.19178222922921], +["9ici",3.1,4.21533068815717], +["9icp",3.1,4.16556468033631], +["8icy",3.1,4.25262263123525], +["9icc",3.1,4.23471766993190], +["2d4z",3.1,3.39446240478985], +["1jcg",3.1,2.91444017001483], +["1lb2",3.1,3.74138783691019], +["1hl3",3.1,2.95513045792658], +["2hio",3.1,3.15735110058603], +["1tf6",3.1,4.43371980294343], +["2b31",3.1,3.35688469750013], +["1a7b",3.1,3.25061342465168], +["1k8i",3.1,3.36801912680897], +["8api",3.1,3.18786542938116], +["1xqj",3.1,3.2983551334738], +["1ddh",3.1,3.86021027040891], +["1uqs",3.1,4.13541427723781], +["1s9k",3.1,3.42862356565724], +["1ldp",3.1,3.85230365559883], +["1ts5",3.1,1.87435658852043], +["1h3v",3.1,3.61371995336343], +["1gri",3.1,4.09449608186979], +["1mal",3.1,3.32263299554130], +["1bbj",3.1,3.38144889469197], +["1c1a",3.1,3.67557366248056], +["2mcp",3.1,4.06821728374987], +["1hin",3.1,3.71600644111356], +["1fq3",3.1,4.23836285291627], +["1m10",3.1,3.47884994710709], +["1bmo",3.1,2.82119273388281], +["1nh3",3.1,3.02230635249788], +["1q0t",3.1,3.70992966373364], +["1tlw",3.1,3.13711812270581], +["1tlz",3.1,3.34251506960142], +["1fp9",3.1,2.92347586254102], +["1jow",3.1,3.77728089174968], +["1hwp",3.1,4.08179106310251], +["1xfa",3.1,2.94820527952141], +["1euq",3.1,3.59221430901255], +["1n21",3.1,2.59800608184745], +["1ztv",3.1,2.1406594565643], +["1u67",3.1,3.79983085674045], +["1igx",3.1,3.79482705946418], +["1tl8",3.1,3.03136476531807], +["1y8h",3.1,3.093068420135], +["2b3t",3.1,3.99397131045489], +["1nqh",3.1,4.2516161564419], +["1yw6",3.1,3.59824340611038], +["1sms",3.1,3.90115675861945], +["1evw",3.1,3.34827825780489], +["2pah",3.1,3.32286850442283], +["1mc8",3.1,3.8746304316209], +["1xb4",3.1,3.74154471252868], +["1ph2",3.1,2.67425695565411], +["1sr5",3.1,3.77030445126257], +["1mf8",3.1,3.29723406442141], +["1bwd",3.1,3.5580745850498], +["3kin",3.1,4.15499322288314], +["1miu",3.1,4.27240727334427], +["1qkc",3.1,3.80069294411968], +["1yqu",3.1,2.81096030225797], +["1o90",3.1,3.47745856529124], +["1kz4",3.1,2.24036069900224], +["1kz9",3.1,2.40081507078985], +["1ckl",3.1,3.80283642574636], +["1id3",3.1,3.53323974155318], +["1xqg",3.1,3.10273835757299], +["1ktl",3.1,3.60995661179505], +["1f3j",3.1,3.51326154780469], +["1h15",3.1,3.70097944019450], +["1bih",3.1,3.66047262871424], +["1ruc",3.1,3.62671916046061], +["1tbq",3.1,3.15811436147603], +["1k6n",3.1,2.79169274313949], +["1k6l",3.1,2.75534176315432], +["1rlb",3.1,3.81398523413466], +["2rcr",3.1,4.54875645272905], +["1r24",3.1,4.47182084666058], +["1gqq",3.1,3.34355767341178], +["1ibu",3.1,3.47720604551639], +["1yed",3.1,3.22857854147877], +["2tun",3.1,4.01002367134344], +["1q90",3.1,3.20080756803327], +["1tbl",3.1,3.52501020719413], +["1ldk",3.1,4.22998432574991], +["1rz9",3.1,3.10129255319864], +["1mv5",3.1,3.4460955864006], +["1fb1",3.1,3.8730641016207], +["1bqm",3.1,3.61113750945496], +["2bwe",3.1,3.07807070848643], +["1jpp",3.1,2.57908836598157], +["1ek1",3.1,4.46384089306703], +["1e0f",3.1,3.17244324465802], +["2fjh",3.1,3.27091569279909], +["1st6",3.1,3.64380450024377], +["2acz",3.1,3.50814686655992], +["1un9",3.1,3.38881784623523], +["1jwh",3.1,3.94110164863662], +["1ud1",3.1,3.1580381786875], +["1s5g",3.1,3.76912891536052], +["1cqe",3.1,2.62300294459767], +["1ahv",3.1,2.97304220655137], +["1fdv",3.1,3.84852364040529], +["1q7q",3.1,3.47466397351193], +["2bxc",3.1,3.03961047206846], +["1vfu",3.1,3.65928127337909], +["1ob5",3.1,4.45170953701732], +["1smq",3.1,3.40098632520268], +["1nzb",3.1,3.67888474677116], +["1ty7",3.1,3.22697081014424], +["1ere",3.1,2.99456455179362], +["1c16",3.1,3.42651195466898], +["1ynt",3.1,3.77488536377729], +["1t03",3.1,3.7957453137257], +["1n5y",3.1,3.93762838236364], +["2cg9",3.1,3.91933158686996], +["1jv2",3.1,3.86948455696751], +["1zmx",3.1,2.38890338983785], +["1u8c",3.1,3.95226626256547], +["1e69",3.1,3.52096548554887], +["1toc",3.1,3.64445821468575], +["1c41",3.1,2.75211044564812], +["1wb2",3.1,4.35527563627642], +["1gxd",3.1,3.95644327508455], +["1pzu",3.1,3.59288478707166], +["1i9r",3.1,4.19333308709903], +["2exy",3.1,3.82048691086025], +["1jxa",3.1,4.37392047928558], +["1z3h",3.1,3.35714326594261], +["2c57",3.1,3.33228296344942], +["1u6g",3.1,3.98371749876902], +["1iwo",3.1,3.75465835259474], +["1sva",3.1,3.87104040439678], +["1o96",3.1,3.35054696836088], +["5r1r",3.1,3.10441991599272], +["7r1r",3.1,3.17478798413875], +["6r1r",3.1,3.16570018484708], +["1xnr",3.1,3.80391090565102], +["1b3b",3.1,3.23804349789891], +["1xlt",3.1,3.89386123263599], +["1ddo",3.1,3.42504333324399], +["1k5g",3.1,3.65899235432230], +["1cow",3.1,3.30060070064441], +["1efr",3.1,3.33128379614005], +["1q5r",3.1,3.38573313555752], +["1ny6",3.1,4.13845531635149], +["1i3q",3.1,3.56698789453532], +["1qvf",3.1,2.97651586196174], +["1kqs",3.1,3.02458833437373], +["1rxu",3.1,2.27404853292312], +["1e7p",3.1,3.68999777242446], +["1i43",3.1,3.35644006537144], +["1kyi",3.1,3.58934075119068], +["2c38",3.1,2.83178109481839], +["2afi",3.1,2.69235586852341], +["1zmv",3.11,3.32054286007527], +["1rh7",3.11,3.3138246801337], +["1yqn",3.11,2.49072645281532], +["1nj2",3.11,3.11842892493184], +["1t9u",3.11,3.63530369395161], +["1yae",3.11,3.45058274354371], +["1nne",3.11,3.35318305961285], +["1yrh",3.11,2.32565234914699], +["1ibl",3.11,3.74519467128598], +["1exi",3.12,4.53269730256723], +["2aox",3.12,3.25940189234125], +["2fo1",3.12,4.08526716535498], +["1hxm",3.12,3.25482794694908], +["1pfc",3.13,4.97743602212247], +["1r49",3.13,3.44828172184749], +["1lpq",3.14,3.83902141470423], +["2dbt",3.14,2.75412931189138], +["2erg",3.15,3.99931266791123], +["1pm3",3.15,3.8025938867099], +["1zau",3.15,4.35721431946093], +["1q1n",3.15,3.44668215037446], +["1w60",3.15,3.38931125449236], +["2av5",3.15,3.55007556310259], +["1hbx",3.15,3.81708127732418], +["1bke",3.15,3.42560558822188], +["1d9z",3.15,4.0907972130773], +["1tyg",3.15,3.86471537340059], +["1wa9",3.15,3.99849736277741], +["1adq",3.15,3.00784322257835], +["2a81",3.15,2.23805411601857], +["1kfx",3.15,4.16314850105294], +["1ft8",3.15,3.46382035749243], +["2bxs",3.15,3.87196909521704], +["1sgf",3.15,3.03553584753118], +["2g4c",3.15,3.80628964793218], +["1dxl",3.15,3.85719550162596], +["1lj7",3.15,3.61064529086564], +["1xpo",3.15,3.10914480217771], +["1xpr",3.15,2.93983736945024], +["1yhu",3.15,3.18744523082962], +["2bgn",3.15,2.98255204945852], +["1dwb",3.16,2.99981904720524], +["1ds5",3.16,4.00633021156819], +["1bcc",3.16,3.59226425429405], +["1moz",3.17,3.25436189926032], +["1pgq",3.17,2.92408631685770], +["2c0b",3.18,3.85224110733998], +["2bvg",3.18,3.37614195157692], +["1k6o",3.19,3.37420631180462], +["1o92",3.19,3.50017319507503], +["1ewr",3.19,3.97822346658667], +["2c0w",3.2,2.69146163987045], +["1e7o",3.2,4.1651841975683], +["1z1x",3.2,3.669477110107], +["1cdz",3.2,3.84716201426002], +["5rnt",3.2,3.58055311593319], +["1dks",3.2,3.48280326073897], +["1t38",3.2,3.28310394429096], +["1u43",3.2,2.61759283197690], +["2cxl",3.2,2.56878216365025], +["1pyi",3.2,4.29232426659268], +["1srs",3.2,2.71285483969085], +["1j87",3.2,3.28976330255082], +["1dkh",3.2,4.09140903355329], +["1yfy",3.2,3.6143055457249], +["1zp6",3.2,3.84130755427151], +["2xat",3.2,3.18602092006872], +["1xat",3.2,2.93173057321780], +["1q1p",3.2,3.91742605030147], +["1iy2",3.2,3.36264683572024], +["1p6v",3.2,4.08872158523431], +["1j7i",3.2,3.04395986050508], +["1uyo",3.2,3.64228030864323], +["2ac5",3.2,3.77362848152861], +["1t43",3.2,4.17783690765627], +["1dqv",3.2,4.26202892758081], +["1iqk",3.2,3.61798886535151], +["1iqf",3.2,3.83389477989278], +["1p8t",3.2,3.59688415083798], +["1e8o",3.2,3.40739156421452], +["2bke",3.2,2.8385387756303], +["1xqy",3.2,4.00808348583018], +["1cqt",3.2,3.50698958356745], +["1md7",3.2,3.54609424462722], +["1x24",3.2,3.35747793097661], +["2bzo",3.2,4.05811197777289], +["1mo6",3.2,3.3093619444109], +["1pbh",3.2,3.74963802281292], +["1jod",3.2,3.37904384084033], +["1jij",3.2,4.16628736445423], +["1jii",3.2,4.21449866223887], +["1mo4",3.2,3.66254086240528], +["1zqo",3.2,4.10310510340557], +["8ice",3.2,4.18156139742376], +["8icv",3.2,4.17907643796641], +["8icj",3.2,4.18887512915678], +["1zqc",3.2,4.13898727720067], +["1zqm",3.2,4.15824817866509], +["1zqb",3.2,4.19694551537786], +["1zqk",3.2,4.17662742983867], +["9icb",3.2,4.22374797972022], +["2c7k",3.2,3.01380413165490], +["2auh",3.2,3.04422507333497], +["1j86",3.2,3.17930900093779], +["7adh",3.2,4.57878620774224], +["2aji",3.2,2.64634252424739], +["1w3z",3.2,3.78470184360939], +["1ry7",3.2,4.11607551843778], +["1ixs",3.2,3.7251544073629], +["1ue7",3.2,3.81548289680069], +["1bl8",3.2,4.32478186756747], +["1qa9",3.2,3.95525425661302], +["1msd",3.2,3.42103725297666], +["1y7e",3.2,3.70652556463465], +["1xa6",3.2,4.12199155520809], +["2a8z",3.2,2.98622695027296], +["1r5o",3.2,3.50067760210147], +["2bhj",3.2,4.572742534253], +["1vjb",3.2,3.13099694331029], +["1jnn",3.2,3.47461237421490], +["1gh6",3.2,3.81689022925941], +["1i85",3.2,3.68135978239475], +["1lwt",3.2,4.01252341644424], +["1eqq",3.2,3.91763667460913], +["1v5w",3.2,4.14031406248897], +["1cn1",3.2,5.02378926573701], +["1cwp",3.2,3.46554203412972], +["1n2l",3.2,2.35973050091135], +["1snx",3.2,4.20446788508755], +["1ljr",3.2,3.75684231583379], +["2ljr",3.2,4.01861597405030], +["1k4s",3.2,4.08285049781109], +["1rh5",3.2,3.69812184805693], +["1b2y",3.2,1.99619524022139], +["1e57",3.2,4.17644447311978], +["1f15",3.2,3.92894272443863], +["1sfk",3.2,3.53054411866054], +["1p5y",3.2,3.05846750703870], +["1ebv",3.2,3.13173152918794], +["1adv",3.2,3.08052227228525], +["1wl0",3.2,2.73024506356499], +["1hqr",3.2,3.63053940557738], +["2d2n",3.2,3.7577254457063], +["2b92",3.2,3.31625163271896], +["1eui",3.2,3.59980648763900], +["1o9x",3.2,3.37563501360454], +["1s9i",3.2,3.37000092824193], +["1kln",3.2,3.54059227307181], +["1mah",3.2,3.32651401596899], +["1kqa",3.2,3.14649863086028], +["1e4k",3.2,4.26224220615834], +["1hlp",3.2,3.99136231061233], +["1lo5",3.2,3.79503896948079], +["1vit",3.2,3.64211905097409], +["1hqc",3.2,3.89752094883577], +["1hc3",3.2,3.7889669248912], +["1hc6",3.2,3.82053190332777], +["1hc5",3.2,3.79513019353259], +["1hc4",3.2,3.84824925727341], +["1hc2",3.2,4.13380031814282], +["1hc1",3.2,4.2174878587452], +["1o14",3.2,3.39550889618399], +["1mco",3.2,3.79119564317215], +["1hcy",3.2,4.15455315451189], +["1btj",3.2,3.62024894614035], +["1o77",3.2,3.73048962108339], +["1i6b",3.2,4.36167095567687], +["1e5n",3.2,2.50400474771306], +["1peu",3.2,3.82737609847535], +["1n9a",3.2,3.02639371213813], +["2flq",3.2,3.65936181880796], +["1c0w",3.2,3.72403368241579], +["2d31",3.2,3.54674291203157], +["1ath",3.2,3.08737260297729], +["1qku",3.2,3.54248143981122], +["3hud",3.2,3.37990385327197], +["1a9b",3.2,2.80923778932603], +["1fug",3.2,3.99784476360875], +["1nvx",3.2,2.65949485304345], +["1r1a",3.2,4.21678887087623], +["2esm",3.2,2.90437444178068], +["2bhn",3.2,3.56724851481585], +["1qab",3.2,4.54470001830437], +["2btq",3.2,3.54994288215741], +["2bb5",3.2,3.03794984037121], +["1mec",3.2,3.97432161020365], +["1a0h",3.2,4.02514831039755], +["1j88",3.2,3.01380416028214], +["1z7s",3.2,3.65320391535852], +["1sjp",3.2,3.01397188078668], +["2frd",3.2,1.94176094875298], +["1ibw",3.2,3.23466453273237], +["1hmv",3.2,3.43281558060523], +["1pci",3.2,3.49868743056657], +["1p8s",3.2,3.55106245712948], +["1sky",3.2,3.44651234137784], +["2f1z",3.2,4.05523562071905], +["1fx0",3.2,3.596435289368], +["1pp6",3.2,3.90846474913412], +["1uwb",3.2,3.84628261581146], +["2ayn",3.2,3.70914715621308], +["1bo5",3.2,4.16807429495753], +["1a6e",3.2,3.29364343441756], +["1osm",3.2,2.98087449823964], +["1kaq",3.2,3.91150438891943], +["1fvf",3.2,3.71852079135355], +["1ucx",3.2,3.18987775754038], +["1kk7",3.2,4.00152525943344], +["1fp7",3.2,3.81964102814032], +["1l7v",3.2,3.38726351898372], +["1ksx",3.2,3.46520199779969], +["1xcp",3.2,3.18329797810277], +["2bxb",3.2,3.15416259155513], +["1ea9",3.2,4.14500278598688], +["1jf5",3.2,2.9759848810337], +["1jf6",3.2,2.93462086720009], +["1jl8",3.2,3.17228817646288], +["1wzm",3.2,3.32494389521712], +["1rer",3.2,3.74603634470008], +["1j0k",3.2,3.06675465826052], +["1lbh",3.2,3.83652056263921], +["1ws3",3.2,3.10172282655411], +["1d9k",3.2,4.23284032283837], +["2ffh",3.2,2.91027970389254], +["1lqm",3.2,3.30329466737065], +["7pck",3.2,2.93952518988741], +["1osn",3.2,3.39571768587761], +["1mpn",3.2,3.31447625146720], +["3bta",3.2,3.70275952718241], +["1nyq",3.2,3.97143835022811], +["1igy",3.2,3.97912599566854], +["1kno",3.2,3.79518610892092], +["2fnq",3.2,3.78320065766316], +["1n86",3.2,3.79786614060696], +["1cvi",3.2,3.62196143138002], +["1pu4",3.2,3.02057380558878], +["1mqn",3.2,3.32754584211644], +["1l5g",3.2,3.79608307639867], +["1q2s",3.2,3.18877328599369], +["1sl0",3.2,3.70721959668896], +["5hmg",3.2,2.84067070958149], +["1iyl",3.2,3.87899698242468], +["1ya4",3.2,3.07961652078853], +["1slq",3.2,3.45174087312404], +["1wb3",3.2,4.39020944795768], +["1yr3",3.2,2.98831317707131], +["1zxo",3.2,3.67766977284907], +["1e2y",3.2,3.64134967416805], +["1jy7",3.2,2.79980740670753], +["2fee",3.2,3.48273239514915], +["2exw",3.2,3.92235827205940], +["1tfy",3.2,2.91469859642256], +["1flc",3.2,4.18915456056344], +["2abm",3.2,3.38395915038150], +["1v1s",3.2,3.35928338382991], +["1waf",3.2,4.15066039053148], +["1nj8",3.2,3.96108972992482], +["1sk6",3.2,3.88216720339965], +["1l8h",3.2,3.38580641944709], +["1rtd",3.2,2.95747007057396], +["1gl9",3.2,3.94502431290001], +["1dpp",3.2,2.8615754816324], +["1o5w",3.2,3.51457237893647], +["1nu1",3.2,3.70977912121191], +["1gga",3.2,3.05469754285445], +["1k25",3.2,3.81116057599685], +["4r1r",3.2,2.88873980543003], +["2eyq",3.2,3.56478971911149], +["1xy3",3.2,2.85834824184742], +["1hr0",3.2,3.84715593758856], +["1mto",3.2,3.54760367103903], +["1dao",3.2,3.44141684387262], +["1j1w",3.2,3.51384701685182], +["1hwy",3.2,3.92806429158913], +["1jnb",3.2,3.82649810788164], +["1fou",3.2,4.24976792960192], +["1ynj",3.2,3.98258677575207], +["1w5c",3.2,4.02645115946745], +["1n3t",3.2,3.09427218365750], +["1iok",3.2,3.84572875020129], +["1s0v",3.2,4.27279156098979], +["1twa",3.2,3.72155089359168], +["1m1k",3.2,3.04743277898834], +["1q7y",3.2,3.3238061787086], +["1i41",3.2,3.67563386871696], +["1cx8",3.2,3.78021305063036], +["1xfx",3.2,4.08205807765104], +["1m1y",3.2,3.46252788976184], +["1yaj",3.2,3.36700603451198], +["1ogy",3.2,3.81537450111113], +["1fnt",3.2,3.75581458561216], +["2aj2",3.21,3.38740590380969], +["1zbv",3.21,3.47942949535669], +["1q9c",3.21,2.81337455619920], +["1y1u",3.21,3.87590718243873], +["1wz2",3.21,4.13888662379663], +["1sf7",3.22,2.74894694165472], +["1sfg",3.22,2.85648131425683], +["1sfb",3.22,2.95660463891242], +["1sf6",3.22,3.08126836683889], +["1shy",3.22,3.6392233997661], +["1x86",3.22,3.34391197315574], +["1z7q",3.22,3.45612766057662], +["1gka",3.23,3.75119492296746], +["1t8b",3.23,3.82345758871154], +["1u8p",3.23,2.76375085696774], +["1t9t",3.23,3.62801815095125], +["1t9w",3.23,3.10395653651334], +["2fhg",3.23,3.26443479814911], +["1fu2",3.24,4.20404606794235], +["1v8j",3.24,3.97853513611064], +["1t0k",3.24,3.15442976301338], +["1gm5",3.24,4.82974157076387], +["1yt2",3.25,2.51468624015087], +["1mo5",3.25,3.60352637413505], +["1bey",3.25,4.11472073746862], +["1hw2",3.25,3.29715497773636], +["1h9t",3.25,4.09165197847038], +["1ijs",3.25,3.91472748378341], +["1z14",3.25,3.28582812448334], +["2f8x",3.25,3.59427505480662], +["2vis",3.25,3.49434919427385], +["2vit",3.25,3.47658965332893], +["2vir",3.25,3.51085448940378], +["1r46",3.25,3.53997262474295], +["1t3e",3.25,3.51848092628863], +["1szp",3.25,3.71567075235248], +["1l9j",3.25,3.16847966353499], +["1s78",3.25,3.17998097284191], +["1z7n",3.25,3.18891108695365], +["1xmo",3.25,3.87098532696335], +["1i48",3.25,3.72739186795127], +["1xfz",3.25,4.03207447132049], +["1sc5",3.26,3.51416914284494], +["1p1z",3.26,4.30517577065442], +["1usz",3.28,3.66270864685222], +["1k39",3.29,3.31724695112477], +["1tgk",3.3,3.83819260645699], +["2c9n",3.3,2.27292428900217], +["2fcq",3.3,2.43114193057597], +["1vb4",3.3,2.9746367184774], +["1lx5",3.3,3.92599941694978], +["1mbv",3.3,3.47732265704663], +["1zw3",3.3,3.7571739641746], +["1lfy",3.3,3.48639808808081], +["1t39",3.3,3.53482591095588], +["1ube",3.3,3.86108758180812], +["1xri",3.3,2.68291915752573], +["2pbh",3.3,3.7052624182534], +["7icu",3.3,4.0647353118431], +["8ich",3.3,4.13876711229802], +["1zqs",3.3,4.12657494523227], +["1zql",3.3,4.16695615430178], +["8icg",3.3,4.20957089794438], +["7ico",3.3,4.17885932762345], +["1zqq",3.3,4.29672501193242], +["8icw",3.3,4.30577715770317], +["1zqj",3.3,4.34423753139135], +["9ice",3.3,4.36593972677222], +["1gfo",3.3,2.69847585884016], +["1vey",3.3,3.26927788072831], +["2hpq",3.3,4.19625552948982], +["2hpp",3.3,4.23660025073562], +["1y11",3.3,3.57615047838564], +["1sru",3.3,3.73386945167218], +["1gkv",3.3,2.74120981060045], +["1lgb",3.3,3.97449773104849], +["1u9o",3.3,3.53648733225125], +["2cfp",3.3,4.48879790877828], +["1yke",3.3,3.52881582452755], +["2bsk",3.3,3.48704234369927], +["1pw4",3.3,4.00631007677003], +["1koa",3.3,3.8539622474125], +["1x9p",3.3,3.89941033552136], +["2etn",3.3,4.46480669121798], +["1rgb",3.3,4.1979473211832], +["3ljr",3.3,4.0044571429601], +["1b44",3.3,2.67126594062845], +["1p5w",3.3,2.75210827519699], +["1fpv",3.3,4.00446292321363], +["1vg4",3.3,3.43911391932366], +["1rts",3.3,2.74842293301847], +["1qgt",3.3,4.41886794767899], +["1ydz",3.3,3.29614968783337], +["2d26",3.3,3.99251248279376], +["2bap",3.3,3.42863597911356], +["1ixr",3.3,4.29725427420517], +["3pjr",3.3,4.25058040745554], +["2cwo",3.3,3.39922994993145], +["2anl",3.3,4.11589909258689], +["1j1e",3.3,3.26330113354207], +["2brv",3.3,3.32716562047179], +["1mq8",3.3,3.77552060217560], +["1blb",3.3,4.46674793074052], +["1poj",3.3,3.03716684122534], +["2eto",3.3,2.25662305522360], +["1na1",3.3,3.12641993015831], +["1mqt",3.3,3.5344043146781], +["1ux4",3.3,3.73145719252817], +["1iss",3.3,3.49103738527839], +["2b4c",3.3,3.03156882084881], +["1nda",3.3,3.48757240839744], +["2msp",3.3,4.06720434711933], +["1bqn",3.3,4.07767301056904], +["2by4",3.3,3.78480412010588], +["1t2v",3.3,2.6969295642576], +["2fdc",3.3,2.90948848787160], +["1ahz",3.3,3.21470192106982], +["1ivo",3.3,3.88665734640387], +["1eiy",3.3,3.89157217636849], +["2c5d",3.3,3.4891790624801], +["2c2l",3.3,3.75258893589624], +["1j2b",3.3,3.94162397257819], +["1jib",3.3,3.46432587115884], +["1gvi",3.3,3.71507318085242], +["1z3g",3.3,3.57278603219749], +["1lnl",3.3,4.18277166582885], +["1ut2",3.3,3.6736083660493], +["2f55",3.3,4.01172795222248], +["1dlp",3.3,4.64562125536709], +["1cqi",3.3,3.35422609122282], +["1szz",3.3,3.02116276137514], +["1lul",3.3,3.35757260016440], +["1p0t",3.3,2.22290277141765], +["1ayr",3.3,3.84414028538926], +["1m1x",3.3,3.77708010950772], +["1gc4",3.3,3.64844690303942], +["2a73",3.3,3.13154846550013], +["1c9t",3.3,3.02839636421942], +["1e0k",3.3,3.84806791203595], +["4gtu",3.3,3.44432052304335], +["2byt",3.3,3.10276903501631], +["1pk0",3.3,3.59398614409344], +["1fay",3.3,2.94977577500309], +["1zye",3.3,3.08324247626793], +["1fzi",3.3,2.58031903543538], +["2b76",3.3,4.17411348060634], +["1g5g",3.3,3.90944749607944], +["1l0v",3.3,3.56715593049751], +["1v7n",3.3,4.36847610836051], +["1hnz",3.3,3.73964876964884], +["1lnq",3.3,3.31640672766131], +["2b4k",3.3,2.96381889542780], +["1hqm",3.3,4.46402233795347], +["1i6v",3.3,4.43456282580583], +["1nr1",3.3,4.04860618717888], +["1gc3",3.3,3.66807164432981], +["1c2y",3.3,3.81218988001847], +["1ynn",3.3,3.93948451375095], +["1twg",3.3,3.97682805578215], +["1i6h",3.3,3.70640187916962], +["1gt8",3.3,2.7675721419078], +["1xfy",3.3,4.23065107080714], +["2c39",3.3,2.64260040224745], +["1nr7",3.3,3.70774430929704], +["2cw0",3.3,4.19070730111367], +["1otz",3.3,2.45522703244411], +["2fug",3.3,3.94843143276911], +["1oda",3.31,3.3255567854906], +["1f6h",3.31,4.27874377970661], +["1tx9",3.31,3.79801835369781], +["1nqg",3.31,3.95887021989473], +["2b7q",3.31,3.57670477050309], +["1ibm",3.31,3.86572734430185], +["1ibk",3.31,3.8780362037949], +["2fed",3.32,3.02006426763221], +["1l6z",3.32,4.53908518802687], +["1y69",3.33,3.99708777333857], +["1zt2",3.33,3.44790721537952], +["2ffl",3.33,2.75149871047121], +["1s94",3.34,3.80610621590468], +["2a3l",3.34,4.42859410976417], +["1xft",3.35,4.22803448767139], +["1vg6",3.35,2.61636261648588], +["2d3o",3.35,3.92499510131464], +["1ob2",3.35,4.00532262388698], +["1a38",3.35,3.96771631798545], +["1lqj",3.35,4.2119791070341], +["1za3",3.35,3.07709788351197], +["1n33",3.35,3.98596041814315], +["1xfv",3.35,4.20264262280987], +["1xfu",3.35,4.22340060443677], +["1zzn",3.37,4.16114827443294], +["1yz6",3.37,3.92961906036565], +["1biy",3.37,4.10723839940854], +["1vc5",3.4,2.48409556896707], +["1ze0",3.4,3.91839129342981], +["1yab",3.4,3.77843569340720], +["1vb2",3.4,3.34410164849763], +["1mjp",3.4,4.20521617823105], +["1ncj",3.4,4.12864348259985], +["1vg7",3.4,2.68040576701117], +["1zqt",3.4,4.1183811264188], +["1ts4",3.4,3.17178582103372], +["2fx3",3.4,3.55943329407483], +["1bi7",3.4,4.19343668963526], +["1v4t",3.4,3.49059942053328], +["1u63",3.4,4.40647760244266], +["1h1z",3.4,2.97489159240104], +["1uaz",3.4,3.50901093388227], +["1js9",3.4,4.56947921033721], +["1laj",3.4,4.49029075803025], +["1p7q",3.4,3.6966411104022], +["1pth",3.4,3.38493041114225], +["1wkz",3.4,3.15252558597532], +["1r30",3.4,3.88083018104397], +["1g1r",3.4,3.76364221027203], +["1ou5",3.4,4.08214126576707], +["1qjm",3.4,3.97456887860858], +["1n76",3.4,2.87734696633309], +["1ft2",3.4,2.89264443013956], +["1zr4",3.4,3.21238248011059], +["2d0u",3.4,3.02414302044221], +["1ggm",3.4,3.92618391881593], +["1b76",3.4,3.94576059371478], +["1kmh",3.4,3.84091151770656], +["2byq",3.4,2.89068016245533], +["1iyj",3.4,4.15859312032367], +["1po3",3.4,3.64918789572037], +["1gyq",3.4,2.84956175674369], +["1ihm",3.4,2.99207797319125], +["1gn2",3.4,2.85847671919082], +["1ypz",3.4,3.98339645607704], +["2ft3",3.4,3.80447432892132], +["2d3t",3.4,2.73369291349665], +["1hnw",3.4,3.77539707227479], +["1hnx",3.4,3.82617446390946], +["1twh",3.4,3.94540054981076], +["1vyh",3.4,3.86943247336135], +["1xfw",3.4,4.11665981339962], +["1pma",3.4,3.47954731851392], +["1g3i",3.41,3.79151710085471], +["1ll0",3.43,3.51947793197728], +["2b48",3.45,3.74094320405138], +["1ud0",3.45,3.92611160633772], +["1wl1",3.45,3.06382065519775], +["1zcd",3.45,4.16723208282507], +["1r47",3.45,3.64546350490644], +["1ohg",3.45,3.38944277516014], +["1q57",3.45,4.3541094914346], +["1xxh",3.45,3.84224339100825], +["1kct",3.46,4.70368072718313], +["2avy",3.46,4.01400813462169], +["2aw7",3.46,4.00670837535047], +["2aw4",3.46,4.34883249995722], +["1hm4",3.47,3.61840246847693], +["1oye",3.48,3.6383890019184], +["1jkt",3.49,4.39936231047652], +["1o93",3.49,3.5042691139793], +["1emr",3.5,4.08006612871515], +["1kzz",3.5,4.07691223512474], +["1u87",3.5,3.73270983515943], +["1rf3",3.5,4.42118362825598], +["1bm1",3.5,3.31396581357854], +["2brd",3.5,3.76649030825608], +["1nrq",3.5,4.67323007157055], +["1sgh",3.5,4.22889553652109], +["1xgo",3.5,4.44310545272577], +["1vbp",3.5,3.62518218067301], +["1ubf",3.5,3.75634463861856], +["1fb5",3.5,4.14040142063791], +["1zqd",3.5,4.29858275054629], +["7icj",3.5,4.28563493812123], +["1ubg",3.5,3.91211759823144], +["1gfm",3.5,2.65771659181315], +["1fr5",3.5,3.25302335970505], +["1zl1",3.5,3.32615999371498], +["1qbe",3.5,2.93197835778201], +["1hkg",3.5,5.10486174705682], +["1dwn",3.5,3.60970641138578], +["1g6v",3.5,3.51857937721973], +["1frs",3.5,3.34413833408253], +["1u88",3.5,4.14119563874623], +["1lws",3.5,4.12785165786584], +["2ayo",3.5,4.15490074414064], +["1mcw",3.5,4.98386198294577], +["1hnb",3.5,3.27218959363423], +["1zak",3.5,2.99167354535223], +["1kyn",3.5,3.92745264452168], +["1fll",3.5,4.24249041897325], +["1x9t",3.5,3.88441878605624], +["1dzl",3.5,4.30826398690415], +["1a6c",3.5,3.86797596929923], +["1s58",3.5,4.68232476156153], +["1uwj",3.5,3.6280573337735], +["1hx9",3.5,2.68205141749687], +["1rhz",3.5,4.13652145552643], +["1hx5",3.5,2.95550549321733], +["1msl",3.5,4.11867989778232], +["1k3v",3.5,3.90088842607018], +["1c8h",3.5,3.49567665289212], +["1mvm",3.5,4.34845303144304], +["1z1c",3.5,3.83006978749526], +["1wl3",3.5,2.79541902048351], +["1t89",3.5,4.00489322213729], +["1iix",3.5,4.06563000448642], +["1f6a",3.5,3.57567580020778], +["1rb8",3.5,3.43728866759136], +["1m06",3.5,3.33096270430036], +["1mje",3.5,4.3173554720109], +["1qfw",3.5,3.91418536409741], +["1fmd",3.5,3.63093310667331], +["3gpd",3.5,4.92728780008229], +["1ryx",3.5,4.55728115147439], +["1kib",3.5,3.13948938875197], +["1ymm",3.5,4.04918894817465], +["1x81",3.5,3.26758812404474], +["1n94",3.5,3.55858310890259], +["2g01",3.5,4.13874288375689], +["1lcu",3.5,3.73996695784407], +["1miv",3.5,3.43650474916255], +["1tmf",3.5,4.7990745828722], +["1cov",3.5,3.13909040070609], +["1jh0",3.5,2.83645396975227], +["1pv6",3.5,4.0523504986588], +["1qmo",3.5,3.53810597192241], +["1cq9",3.5,2.57229384092956], +["1jck",3.5,3.36854197440057], +["1n9s",3.5,3.59063002944947], +["1iwg",3.5,3.74475527354222], +["1zp0",3.5,3.30090153062920], +["1pge",3.5,3.32251835283967], +["1prh",3.5,3.34915108743997], +["2a1d",3.5,3.75957519515875], +["1al0",3.5,3.81892646063391], +["1xfh",3.5,3.82654955355382], +["1cd3",3.5,4.4386977651142], +["2fix",3.5,4.2200246335852], +["2cde",3.5,3.59471510941489], +["1m1c",3.5,3.92701529702907], +["1j5o",3.5,4.19725930344026], +["1pgr",3.5,3.18219191122181], +["1i0e",3.5,4.04357696333352], +["1zrt",3.5,4.62711183138494], +["1v6n",3.5,3.47935995858147], +["1pto",3.5,3.71946615667744], +["1fft",3.5,4.22373411978878], +["2bcc",3.5,3.8011536266103], +["2b7m",3.5,3.42528301663083], +["1xcq",3.5,4.41092884676472], +["1wdl",3.5,2.99058106605253], +["1ken",3.5,4.25556919915362], +["3tat",3.5,4.52491067007896], +["1kpk",3.5,3.73963326511460], +["1ypw",3.5,4.59225594244554], +["1z8l",3.5,3.67207239056044], +["1kog",3.5,3.84797960263008], +["1r9t",3.5,4.79762225291626], +["1w2b",3.5,3.36984213918050], +["1br1",3.5,4.43838333444752], +["1s5l",3.5,3.80416999607971], +["2gls",3.5,4.98089815085941], +["1nqt",3.5,4.13002681937211], +["2btv",3.5,3.45587895484918], +["1uf2",3.5,3.22566865362218]] From 1e50aac3d3c158eb5bf26b46ee11e2f8fe91ab38 Mon Sep 17 00:00:00 2001 From: chrissciwilliams Date: Thu, 29 Feb 2024 17:57:09 -0500 Subject: [PATCH 225/748] added summary counts for protein,na,other --- mmtbx/validation/mp_validate_bonds.py | 102 ++++++++++++++++++++------ 1 file changed, 79 insertions(+), 23 deletions(-) diff --git a/mmtbx/validation/mp_validate_bonds.py b/mmtbx/validation/mp_validate_bonds.py index 4dce8a416f..2c40fbafff 100644 --- a/mmtbx/validation/mp_validate_bonds.py +++ b/mmtbx/validation/mp_validate_bonds.py @@ -1,4 +1,3 @@ - # TODO reduce to one outlier per residue # CDL on by default? @@ -104,6 +103,23 @@ def __init__(self, pdb_hierarchy, pdb_atoms, geometry_restraints_manager, validation.__init__(self) self.n_outliers_large_by_model = {} self.n_outliers_small_by_model = {} + self.n_outliers_protein_by_model = {} + self.n_outliers_na_by_model = {} + self.n_outliers_other_by_model = {} + self.n_total_protein_by_model = {} + self.n_total_na_by_model = {} + self.n_total_other_by_model = {} + for m in pdb_hierarchy.models(): + self.n_total_by_model[m.id] = 0 + self.n_outliers_by_model[m.id] = 0 + self.n_outliers_small_by_model[m.id] = 0 + self.n_outliers_large_by_model[m.id] = 0 + self.n_total_protein_by_model[m.id] = 0 + self.n_outliers_protein_by_model[m.id] = 0 + self.n_total_na_by_model[m.id] = 0 + self.n_outliers_na_by_model[m.id] = 0 + self.n_total_other_by_model[m.id] = 0 + self.n_outliers_other_by_model[m.id] = 0 cutoff = 4 sites_cart = pdb_atoms.extract_xyz() flags = geometry_restraints.flags.flags(default=True) @@ -119,28 +135,33 @@ def __init__(self, pdb_hierarchy, pdb_atoms, geometry_restraints_manager, atom2 = pdb_atoms[proxy.i_seqs[1]].name labels = pdb_atoms[proxy.i_seqs[0]].fetch_labels() model_id = labels.model_id - if model_id not in self.n_total_by_model.keys(): - self.n_total_by_model[model_id] = 0 - self.n_outliers_by_model[model_id] = 0 - self.n_outliers_small_by_model[model_id] = 0 - self.n_outliers_large_by_model[model_id] = 0 self.n_total += 1 self.n_total_by_model[model_id] += 1 + if pdb_atoms[proxy.i_seqs[0]].parent().parent().parent().is_protein(): + mm_type="PROTEIN" + self.n_total_protein_by_model[model_id] += 1 + elif pdb_atoms[proxy.i_seqs[0]].parent().parent().parent().is_na(): + mm_type="NA" + self.n_total_na_by_model[model_id] += 1 + else: + mm_type="OTHER" + self.n_total_other_by_model[model_id] += 1 sigma = sqrt(1 / restraint.weight) num_sigmas = - restraint.delta / sigma is_outlier = (abs(num_sigmas) >= cutoff) if is_outlier: self.n_outliers += 1 self.n_outliers_by_model[model_id] += 1 + if mm_type == "PROTEIN": + self.n_outliers_protein_by_model[model_id] += 1 + elif mm_type == "NA": + self.n_outliers_na_by_model[model_id] += 1 + else: + self.n_outliers_other_by_model[model_id] += 1 if num_sigmas < 0: self.n_outliers_small_by_model[model_id] += 1 else: self.n_outliers_large_by_model[model_id] += 1 - mm_type="OTHER" - if pdb_atoms[proxy.i_seqs[0]].parent().parent().parent().is_protein(): - mm_type="PROTEIN" - elif pdb_atoms[proxy.i_seqs[0]].parent().parent().parent().is_na(): - mm_type="NA" if (is_outlier or not outliers_only): self.results.append(mp_bond( atoms_info=get_atoms_info(pdb_atoms, proxy.i_seqs), @@ -174,7 +195,13 @@ def as_JSON(self, addon_json={}): summary_results[mod_id] = {"num_outliers": self.n_outliers_by_model[mod_id], "num_total": self.n_total_by_model[mod_id], "num_outliers_too_small": self.n_outliers_small_by_model[mod_id], - "num_outliers_too_large": self.n_outliers_large_by_model[mod_id]} + "num_outliers_too_large": self.n_outliers_large_by_model[mod_id], + "num_total_protein": self.n_total_protein_by_model[mod_id], + "num_outliers_protein": self.n_outliers_protein_by_model[mod_id], + "num_total_na": self.n_total_na_by_model[mod_id], + "num_outliers_na": self.n_outliers_na_by_model[mod_id], + "num_total_other": self.n_total_other_by_model[mod_id], + "num_outliers_other": self.n_outliers_other_by_model[mod_id]} data['summary_results'] = summary_results return json.dumps(data, indent=2) @@ -198,6 +225,23 @@ def __init__(self, pdb_hierarchy, pdb_atoms, geometry_restraints_manager, validation.__init__(self) self.n_outliers_large_by_model = {} self.n_outliers_small_by_model = {} + self.n_outliers_protein_by_model = {} + self.n_outliers_na_by_model = {} + self.n_outliers_other_by_model = {} + self.n_total_protein_by_model = {} + self.n_total_na_by_model = {} + self.n_total_other_by_model = {} + for m in pdb_hierarchy.models(): + self.n_total_by_model[m.id] = 0 + self.n_outliers_by_model[m.id] = 0 + self.n_outliers_small_by_model[m.id] = 0 + self.n_outliers_large_by_model[m.id] = 0 + self.n_total_protein_by_model[m.id] = 0 + self.n_outliers_protein_by_model[m.id] = 0 + self.n_total_na_by_model[m.id] = 0 + self.n_outliers_na_by_model[m.id] = 0 + self.n_total_other_by_model[m.id] = 0 + self.n_outliers_other_by_model[m.id] = 0 cutoff = 4 sites_cart = pdb_atoms.extract_xyz() flags = geometry_restraints.flags.flags(default=True) @@ -211,28 +255,34 @@ def __init__(self, pdb_hierarchy, pdb_atoms, geometry_restraints_manager, atom3 = pdb_atoms[proxy.i_seqs[2]].name labels = pdb_atoms[proxy.i_seqs[0]].fetch_labels() model_id = labels.model_id - if model_id not in self.n_total_by_model.keys(): - self.n_total_by_model[model_id] = 0 - self.n_outliers_by_model[model_id] = 0 - self.n_outliers_small_by_model[model_id] = 0 - self.n_outliers_large_by_model[model_id] = 0 self.n_total += 1 self.n_total_by_model[model_id] += 1 + if pdb_atoms[proxy.i_seqs[0]].parent().parent().parent().is_protein(): + mm_type="PROTEIN" + self.n_total_protein_by_model[model_id] += 1 + elif pdb_atoms[proxy.i_seqs[0]].parent().parent().parent().is_na(): + mm_type="NA" + self.n_total_na_by_model[model_id] += 1 + else: + mm_type="OTHER" + self.n_total_other_by_model[model_id] += 1 sigma = sqrt(1 / restraint.weight) num_sigmas = - restraint.delta / sigma is_outlier = (abs(num_sigmas) >= cutoff) if is_outlier: self.n_outliers += 1 self.n_outliers_by_model[model_id] += 1 + if mm_type == "PROTEIN": + self.n_outliers_protein_by_model[model_id] += 1 + elif mm_type == "NA": + self.n_outliers_na_by_model[model_id] += 1 + else: + self.n_outliers_other_by_model[model_id] += 1 if num_sigmas < 0: self.n_outliers_small_by_model[model_id] += 1 else: self.n_outliers_large_by_model[model_id] += 1 - mm_type="OTHER" - if pdb_atoms[proxy.i_seqs[0]].parent().parent().parent().is_protein(): - mm_type="PROTEIN" - elif pdb_atoms[proxy.i_seqs[0]].parent().parent().parent().is_na(): - mm_type="NA" + if (is_outlier or not outliers_only): self.results.append(mp_angle( atoms_info=get_atoms_info(pdb_atoms, proxy.i_seqs), @@ -266,7 +316,13 @@ def as_JSON(self, addon_json={}): summary_results[mod_id] = {"num_outliers": self.n_outliers_by_model[mod_id], "num_total": self.n_total_by_model[mod_id], "num_outliers_too_small": self.n_outliers_small_by_model[mod_id], - "num_outliers_too_large": self.n_outliers_large_by_model[mod_id]} + "num_outliers_too_large": self.n_outliers_large_by_model[mod_id], + "num_total_protein": self.n_total_protein_by_model[mod_id], + "num_outliers_protein": self.n_outliers_protein_by_model[mod_id], + "num_total_na": self.n_total_na_by_model[mod_id], + "num_outliers_na": self.n_outliers_na_by_model[mod_id], + "num_total_other": self.n_total_other_by_model[mod_id], + "num_outliers_other": self.n_outliers_other_by_model[mod_id]} data['summary_results'] = summary_results return json.dumps(data, indent=2) From bfbfdc522647bee98080878cfa51de6031015301 Mon Sep 17 00:00:00 2001 From: chrissciwilliams Date: Sat, 2 Mar 2024 16:37:29 -0500 Subject: [PATCH 226/748] initial MolProbity site table from json code --- .../validation/molprobity/table_from_json.py | 1055 +++++++++++++++++ 1 file changed, 1055 insertions(+) create mode 100644 mmtbx/validation/molprobity/table_from_json.py diff --git a/mmtbx/validation/molprobity/table_from_json.py b/mmtbx/validation/molprobity/table_from_json.py new file mode 100644 index 0000000000..a89e10711a --- /dev/null +++ b/mmtbx/validation/molprobity/table_from_json.py @@ -0,0 +1,1055 @@ +from __future__ import division +import os, sys +import json + +red = '#ff9999' +yellow = '#ffff99' +green = '#99ff99' + +def make_reskey(model_id, chain_id, resseq, icode): + #create a unique string residue key with mmCIF-like placeholders for blank fields + #The residue key is space-delimited + return ' '.join([model_id.strip() or '.', chain_id.strip() or '.', resseq.strip(), icode.strip() or '?']) + +class merged_validations(): + def __init__(self, hierarchy): + self.data = {} + self.indices = [] #reskeys in the same order as hierarchy + self.validation_types = [] + self.summaries = {} + self.model_ids = [] + for model in hierarchy.models(): + model_id = model.id.strip() + self.model_ids.append(model_id) + for chain in model.chains(): + chain_id = chain.id.strip() + for rg in chain.residue_groups(): + #alts with different resnames? + resseq = rg.resseq.strip() + icode = rg.icode.strip() + reskey = make_reskey(model_id, chain_id, resseq, icode) + self.indices.append(reskey) + self.data[reskey] = residue(rg, model_id, chain_id, resseq, icode) + + def add_summaries(self, json_list): + for val_json in json_list: + self.add_summary(val_json) + + def add_summary(self, val_json): + val_type = val_json["validation_type"] + self.summaries[val_type] = val_json["summary_results"] + + def add_validations(self, json_list): + for val_json in json_list: + val_type = val_json["validation_type"] + #some validations especially those with multiple results per residue require special loading + #these are clashscore, bond lengths, bond angles, chirals + self.validation_types.append(val_type) + if val_type == "clashscore": + self.add_clashscore(val_json) + elif val_type in ["mp_bonds", "mp_angles"]: + self.add_geometry(val_json) + else: + self.add_validation(val_json) + for reskey in self.data: + #print(reskey) + self.data[reskey].get_alternates() + + def add_validation(self, val_json): + val_type = val_json["validation_type"] + for result in val_json["flat_results"]: + reskey = make_reskey(result["model_id"], result["chain_id"], result["resseq"].strip(), result["icode"]) + if not self.data[reskey].validations.get(val_type): + self.data[reskey].validations[val_type] = {} + self.data[reskey].validations[val_type][result["altloc"].strip()] = result + if result["outlier"]: + self.data[reskey].has_outlier = True + + def add_clashscore(self, val_json): + assert val_json["validation_type"] == "clashscore" + #each contact only gets one clash entry, so it needs to be stired twice for the residue table + # once for the source and once for the target + #Usage of clash info should check whether reskey == srcreskey + # if not, then treat the target as the source + for result in val_json["flat_results"]: + srcreskey = make_reskey(result["model_id"], result["chain_id"], result["resseq"], result["icode"]) + if not self.data[srcreskey].validations.get("clashscore"): + self.data[srcreskey].validations["clashscore"] = {} + if not self.data[srcreskey].validations["clashscore"].get(result["altloc"].strip()): + self.data[srcreskey].validations["clashscore"][result["altloc"].strip()] = [] + self.data[srcreskey].validations["clashscore"][result["altloc"].strip()].append(result) + self.data[srcreskey].has_outlier = True + + trgreskey = make_reskey(result["model_id"], result["target_chain_id"], result["target_resseq"], result["target_icode"]) + if not self.data[trgreskey].validations.get("clashscore"): + self.data[trgreskey].validations["clashscore"] = {} + if not self.data[trgreskey].validations["clashscore"].get(result["target_altloc"].strip()): + self.data[trgreskey].validations["clashscore"][result["target_altloc"].strip()] = [] + self.data[trgreskey].validations["clashscore"][result["target_altloc"].strip()].append(result) + self.data[trgreskey].has_outlier = True + #once all results are loaded, sort from worst to mildest clash + for reskey in self.data: + if not self.data[reskey].validations.get("clashscore"): + continue + for altloc in self.data[reskey].validations["clashscore"]: + #clash overlaps are stored as negative values (vdw gaps would be positive) + #so default ascending sort should put worst clash first + self.data[reskey].validations["clashscore"][altloc].sort(key=lambda x: x["overlap"]) + + def add_geometry(self, val_json): + val_type = val_json["validation_type"] + assert val_type in ["mp_bonds", "mp_angles"] + for result in val_json["flat_results"]: + #for both bonds and angles, the measure is assigned to the residue of the second atom (index 1) in the list + #this only really matters at residue-residue joins + reskey = make_reskey(result["atoms_model_id"][1], result["atoms_chain_id"][1], result["atoms_resseq"][1], result["atoms_icode"][1]) + + #a bond or angle should be a mix of '' and possible a single alternate id + #if multiple alternate ids are involved in a single bond, this will return the "highest" alternate + #That's a weird case, and whether it shows up is based on how the hierarchy processes complex alternates. + altloc = sorted(result["atoms_altloc"], reverse=True)[0].strip() + + if not self.data[reskey].validations.get(val_type): + self.data[reskey].validations[val_type] = {} + if not self.data[reskey].validations[val_type].get(altloc): + self.data[reskey].validations[val_type][altloc] = [] + self.data[reskey].validations[val_type][altloc].append(result) + self.data[reskey].has_outlier = True #needs to be outliers_only input + #once all results are loaded, sort from worst to mildest + #deviations can be too large or too small, so abs() is necessary + for reskey in self.data: + if not self.data[reskey].validations.get(val_type): + continue + for altloc in self.data[reskey].validations[val_type]: + self.data[reskey].validations[val_type][altloc].sort(key=lambda x: abs(x["score"]), reverse=True) + + def get_table_order(self): + #jsons may be received in any order + master_order = ["clashscore", + "ramalyze", + "rotalyze", + "cbetadev", + "cablam", + "rna_puckers", + "rna_suites", + "mp_bonds", + "mp_angles", + "omegalyze"] + table_order = [] + for x in master_order: + if x in self.validation_types: + table_order.append(x) + return table_order + + def make_summary_table(self, model, red = '#ff9999', yellow = '#ffff99', green = '#99ff99'): + # TODO: add a cleverness to do the first model if model==None + #red = '#ff9999' + #yellow = '#ffff99' + #green = '#99ff99' + lines = [] + table_order = self.get_table_order() + if model.strip(): + lines.append("
Summary statistics: Model {model}".format(model)) + else: + lines.append("
Summary statistics") + lines.append("") + lines += self.summary_table_clashscore(model, red, yellow, green) + lines += self.summary_table_proteins(model, red, yellow, green) + if "omegalyze" in table_order: + lines = lines + self.summary_table_peptide_omegas(model, show_all=True) + lines = lines + self.summary_table_nucleic_acids(model) + lines = lines + self.summary_table_low_res(model) + lines = lines + self.summary_table_additional(model) + lines.append("
") + lines.append(self.under_table_text(table_order)) + print("\n".join(lines)) + + def under_table_text(self, table_order): + notes = [] + notes.append("In the two column results, the left column gives the raw count, right column gives the percentage.") + notes.append("
Some validations count different numbers of residues. E.g. Ramachandran's φ or ψ is incomplete at chain ends, and Gly residues have no sidechains for rotamers.") + if "clashscore" in table_order: + notes.append("
100th percentile is the best among structures of comparable resolution; 0th percentile is the worst. For clashscore the comparative set of structures was selected in 2004, for MolProbity score in 2006.") + if "ramalyze" in table_order and "rotalyze" in table_order: + notes.append("
MolProbity score combines the clashscore, rotamer, and Ramachandran evaluations into a single score, normalized to be on the same scale as X-ray resolution.") + if "rna_suites" in table_order: + notes.append("
RNA backbone sugar-to-sugar suites are rotameric. Outliers are RNA suites that don't fall into recognized rotamers.") + return "\n".join(notes) + + def summary_table_clashscore(self, model, red, yellow, green, resolution=None): + resolution=2.0 + lines = [] + if "clashscore" in self.summaries: + from mmtbx.validation.molprobity import percentile_clashscore + data = self.summaries["clashscore"][model] + pct_stats = percentile_clashscore.get_percentile_for_clashscore(data["clashscore"], resolution=resolution) + #pct_stats = {"minres":minres, "maxres":maxres, "count":nSamples, "percentile":pctRank} + if pct_stats["percentile"] >= 66: color=green + elif pct_stats["percentile"] < 33: color=red + else: color=yellow + #ordinal = lambda n: "%d%s" % (n,"tsnrhtdd"[(n//10%10!=1)*(n%10<4)*n%10::4]) + if not resolution: + range_text = "(N={count}, all resolutions)".format(count=pct_stats["count"]) + else: + range_text = "(N={count}, {minres}Å - {maxres}Å)".format(count=pct_stats["count"], minres=pct_stats["minres"], maxres=pct_stats["maxres"]) + lines.append(""" + All-Atom Contacts + Clashscore, all atoms +  {clashscore:.2f} + {percentile}th percentile {range_text} + """.format(color=color, clashscore=data["clashscore"], percentile=pct_stats["percentile"], range_text=range_text)) + return lines + + def summary_table_proteins(self, model, red, yellow, green, resolution=None): + protein_lines = [] + rows = 0 + if "rotalyze" in self.summaries: + rows +=2 + data = self.summaries["rotalyze"][model] + if data["outlier_percentage"] <= 0.3: color=green + elif data["outlier_percentage"] > 1.5: color=red + else: color=yellow + protein_lines.append(" ") + protein_lines.append(""" Poor rotamers +  {num_outliers} / {num_residues} +  {outlier_percentage:.2f}% + Goal: <0.3% + """.format(color= color, num_outliers=data["num_outliers"], num_residues=data["num_residues"], outlier_percentage=data["outlier_percentage"])) + + if data["num_residues"] == 0: + color=green #none would be more accurate; does 'transparent' work? + favored_pct = 0 + else: + favored_pct = data["num_favored"]/data["num_residues"]*100.0 + if favored_pct >= 98: color=green + elif favored_pct < 95: color=red + else: color=yellow + protein_lines.append(""" + Favored rotamers +  {num_favored} / {num_residues} +  {favored_pct:.2f}% + Goal: >98% + """.format(color=color, num_favored=data["num_favored"], num_residues=data["num_residues"], favored_pct=favored_pct)) + + if "ramalyze" in self.summaries: + rows += 2 + data = self.summaries["ramalyze"][model] + if data["outlier_percentage"] <= 0.05: color=green + elif data["outlier_percentage"] > 0.5 and data["num_outliers"] >= 2: color=red + else: color=yellow + protein_lines.append(" ") + protein_lines.append(""" Ramachandran outliers +  {num_outliers} / {num_residues} +  {outlier_percentage:.2f}% + Goal: <0.05% + """.format(color=color, num_outliers=data["num_outliers"], num_residues=data["num_residues"], outlier_percentage=data["outlier_percentage"])) + + if data["favored_percentage"] >= 98: color=green + elif data["favored_percentage"] < 95: color=red + else: color=yellow + protein_lines.append(""" + Ramachandran favored +  {num_favored} / {num_residues} +  {favored_percentage:.2f}% + Goal: >98% + """.format(color=color, num_favored=data["num_favored"], num_residues=data["num_residues"], favored_percentage=data["favored_percentage"])) + + if "rama_z" in self.summaries: + #not yet available in json + #work w/Oleg to get compatible output + pass + + #MolProbity Score + if "clashscore" in self.summaries and "ramalyze" in self.summaries and "rotalyze" in self.summaries: + rows += 1 + from mmtbx.validation.utils import molprobity_score + from mmtbx.validation.molprobity import percentile_mpscore + mpscore = molprobity_score(self.summaries["clashscore"][model]["clashscore"], + self.summaries["rotalyze"][model]["outlier_percentage"], + self.summaries["ramalyze"][model]["favored_percentage"]) + pct_stats = percentile_mpscore.get_percentile_for_mpscore(mpscore, resolution=resolution) + #pct_stats = {"minres":minres, "maxres":maxres, "count":nSamples, "percentile":pctRank} + if pct_stats["percentile"] >= 66: color=green + elif pct_stats["percentile"] < 33: color=red + else: color=yellow + range_text = "(N={count}, {minres}Å - {maxres}Å)".format(count=pct_stats["count"], minres=pct_stats["minres"], maxres=pct_stats["maxres"]) + protein_lines.append(""" + MolProbity score +  {mpscore:.2f} + {percentile}th percentile {range_text} + """.format(color=color, mpscore=mpscore, percentile=pct_stats["percentile"], range_text=range_text)) + + if "cbetadev" in self.summaries: + rows += 1 + data = self.summaries["cbetadev"][model] + if data["num_outliers"] == 0: color=green + elif data["outlier_percentage"] >= 5: color=red + else: color=yellow + protein_lines.append(" ") + protein_lines.append(""" Cβ deviations >0.25Å +  {num_outliers} / {num_cbeta_residues} +  {outlier_percentage:.2f}% + Goal: 0 + """.format(color=color, num_outliers=data["num_outliers"], num_cbeta_residues=data["num_cbeta_residues"], outlier_percentage=data["outlier_percentage"])) + + if "mp_bonds" in self.summaries and self.summaries["mp_bonds"][model]["num_total_protein"] > 0: + rows += 1 + data = self.summaries["mp_bonds"][model] + if data["num_total_protein"] == 0: + pct_outliers = 0.0 + else: + pct_outliers = data["num_outliers_protein"]/data["num_total_protein"]*100.0 + if pct_outliers < 0.01: color=green + elif pct_outliers >= 0.2: color=red + else: color=yellow + protein_lines.append(" ") + protein_lines.append(""" Bad bonds +  {num_outliers_protein} / {num_total_protein} +  {pct_outliers:.2f}% + Goal: 0% + """.format(color=color, num_outliers_protein=data["num_outliers_protein"], num_total_protein=data["num_total_protein"], pct_outliers=pct_outliers)) + + if "mp_angles" in self.summaries and self.summaries["mp_angles"][model]["num_total_protein"] > 0: + rows += 1 + data = self.summaries["mp_angles"][model] + if data["num_total_protein"] == 0: + pct_outliers = 0.0 + else: + pct_outliers = data["num_outliers_protein"]/data["num_total_protein"]*100.0 + if pct_outliers < 0.1: color=green + elif pct_outliers >= 0.5: color=red + else: color=yellow + protein_lines.append(" ") + protein_lines.append(""" Bad angles +  {num_outliers_protein} / {num_total_protein} +  {pct_outliers:.2f}% + Goal: 0.1% + """.format(color=color, num_outliers_protein=data["num_outliers_protein"], num_total_protein=data["num_total_protein"], pct_outliers=pct_outliers)) + + if rows == 0: + return [] + #Overwrite the first with the Protein Geometry section cell + protein_lines[0] = """ + Protein Geometry""".format(rows=rows) + return protein_lines + + def summary_table_peptide_omegas(self, model, show_all=False): + data = self.summaries["omegalyze"][model] + lines = [] + rows = 1 + if data["num_proline"] == 0: + pct_cis_pro = 0.0 + else: + pct_cis_pro = data["num_cis_proline"]/data["num_proline"]*100.0 + lines.append(""" Cis Prolines +  {num_cis_proline} / {num_proline} +  {pct_cis_pro:.2f} + Expected: ≤1 per chain, or ≤5% + """.format(num_cis_proline=data["num_cis_proline"], num_proline=data["num_proline"], pct_cis_pro=pct_cis_pro)) + + if show_all or data["num_cis_general"] != 0: + rows += 1 + if data["num_general"] == 0: + pct_cis_general = 0.0 + else: + pct_cis_general = data["num_cis_general"]/data["num_general"]*100.0 + if pct_cis_general <= 0.05: color=green + elif pct_cis_general > 0.1: color=red + else: color=yellow + lines.append(""" + Cis nonProlines +  {num_cis_general} / {num_general} +  {pct_cis_general}% + Goal: <0.05% + """.format(color=color, num_cis_general=data["num_cis_general"], num_general=data["num_general"], pct_cis_general=pct_cis_general)) + + num_twisted = data["num_twisted_proline"] + data["num_twisted_general"] + if show_all or num_twisted != 0: + rows += 1 + num_res = data["num_general"]+data["num_proline"] + if num_res == 0: + pct_twisted = 0.0 + else: + pct_twisted = num_twisted/num_res*100.0 + if num_twisted == 0: color=green + elif pct_twisted > 0.1: color=red + else: color=yellow + lines.append(""" + Twisted peptides +  {num_twisted} / {num_res} +  {pct_twisted}% + Goal: 0 + """.format(color=color, num_twisted=num_twisted, num_res=num_res, pct_twisted=pct_twisted)) + omega_lines = [" "," Peptide Omegas".format(rows=len(lines))] + lines + return omega_lines + + def summary_table_nucleic_acids(self, model): + lines=[] + rows = 0 + if "rna_puckers" in self.summaries: + rows += 1 + data = self.summaries["rna_puckers"][model] + if data["num_residues"] == 0: + pct_outliers = 0.0 + else: + pct_outliers = data["num_outliers"]/data["num_residues"]*100.0 + if data["num_outliers"] == 0: color=green + elif pct_outliers > 5: color=red + else: color=yellow + lines.append(" ") + lines.append(""" Probably wrong sugar puckers +  {num_outliers} / {num_residues} +  {pct_outliers:.2f}% + Goal: 0 + """.format(color=color, num_outliers=data["num_outliers"], num_residues=data["num_residues"], pct_outliers=pct_outliers)) + + if "rna_suites" in self.summaries: + rows += 1 + data = self.summaries["rna_suites"][model] + if data["num_suites"] == 0: + pct_outliers = 0.0 + else: + pct_outliers = data["num_outliers"]/data["num_suites"]*100.0 + if pct_outliers <= 5: color=green + elif pct_outliers > 15: color=red + else: color=yellow + lines.append(" ") + lines.append(""" Bad backbone conformations +  {num_outliers} / {num_suites} +  {pct_outliers:.2f}% + Goal: ≤ 5% + """.format(color=color, num_outliers=data["num_outliers"], num_suites=data["num_suites"], pct_outliers=pct_outliers)) + + #if "rna_bonds" in self.summaries: + if "mp_bonds" in self.summaries and self.summaries["mp_bonds"][model]["num_total_na"] > 0: + rows += 1 + data = self.summaries["mp_bonds"][model] + if data["num_total_na"] == 0: + pct_outliers = 0.0 + else: + pct_outliers = data["num_outliers_na"]/data["num_total_na"]*100.0 + if pct_outliers < 0.01: color=green + elif pct_outliers >= 0.2: color=red + else: color=yellow + lines.append(" ") + lines.append(""" Bad bonds +  {num_outliers_na} / {num_total_na} +  {pct_outliers:.2f}% + Goal: 0% + """.format(color=color, num_outliers_na=data["num_outliers_na"], num_total_na=data["num_total_na"], pct_outliers=pct_outliers)) + + if "mp_angles" in self.summaries and self.summaries["mp_angles"][model]["num_total_na"] > 0: + rows += 1 + data = self.summaries["mp_angles"][model] + if data["num_total_na"] == 0: + pct_outliers = 0.0 + else: + pct_outliers = data["num_outliers_na"]/data["num_total_na"]*100.0 + if pct_outliers < 0.1: color=green + elif pct_outliers >= 0.5: color=red + else: color=yellow + lines.append(" ") + lines.append(""" Bad bonds +  {num_outliers_na} / {num_total_na} +  {pct_outliers:.2f}% + Goal: <0.1% + """.format(color=color, num_outliers_na=data["num_outliers_na"], num_total_na=data["num_total_na"], pct_outliers=pct_outliers)) + + if rows == 0: + return [] + lines[0] = """ + Nucleic Acid
Geometry""".format(rows=rows) + return lines + + def summary_table_low_res(self, model): #Right now, this just means 2 rows of CaBLAM + if "cablam" not in self.summaries: + return [] + lines = [] + lines.append(""" + Low-resolution Criteria""") + data = self.summaries["cablam"][model] + if data["cablam_outliers_percentage"] <=1: color=green + elif data["cablam_outliers_percentage"] > 5: color=red + else: color=yellow + lines.append(""" CaBLAM outliers +  {num_cablam_outliers} / {num_residues} +  {cablam_outliers_percentage:.1f}% + Goal: <1.0%""".format( + color=color, num_cablam_outliers=data["num_cablam_outliers"], num_residues=data["num_residues"], cablam_outliers_percentage=data["cablam_outliers_percentage"])) + + if data["ca_geom_outliers_percentage"] <=0.5: color=green + elif data["ca_geom_outliers_percentage"] > 1: color=red + else: color=yellow + lines.append(""" + CA Geometry outliers +  {num_ca_geom_outliers} / {num_residues} +  {ca_geom_outliers_percentage:.1f}% + Goal: <1.0%""".format( + color=color, num_ca_geom_outliers=data["num_ca_geom_outliers"], num_residues=data["num_residues"], ca_geom_outliers_percentage=data["ca_geom_outliers_percentage"])) + + return lines + + def summary_table_additional(self, model): + first_row=True + lines = [] + rows=0 + if "chirals" in self.summaries: + rows+=1 + #nothing to load yet, add later + lines.append(" ") + lines.append() + if "undowser" in self.summaries: + rows+=1 + data = self.summaries["undowser"][model] + if data["num_waters"] == 0: + pct_outliers = 0.0 + else: + pct_outliers = data["num_outliers"]/data["num_waters"]*100.0 + lines.append(" ") + lines.append(""" Waters with clashes +  {num_outliers} / {num_waters} +  {pct_outliers:.2f}% + See UnDowser table for details + """.format( + num_outliers=data["num_outliers"], num_waters=data["num_waters"], pct_outliers=pct_outliers)) + if rows == 0: + return [] + lines[0] = """ + Additional validations""".format(rows=rows) + return lines + + def clash_header(self, model): + return " Clash > 0.4Å
Clashscore: {clashscore:.2f}".format( + clashscore=self.summaries["clashscore"][model]["clashscore"]) + + def rama_header(self, model): + return " Ramachandran
Outliers: {num_outliers} out of {num_residues}".format( + num_outliers=self.summaries["ramalyze"][model]["num_outliers"], num_residues=self.summaries["ramalyze"][model]["num_residues"]) + + def rota_header(self, model): + return " Rotamer
Poor rotamers: {num_outliers} out of {num_residues}".format( + num_outliers=self.summaries["rotalyze"][model]["num_outliers"], num_residues=self.summaries["rotalyze"][model]["num_residues"]) + + def cbdev_header(self, model): + return " Cβ deviation
Outliers: {num_outliers} out of {num_cbeta_residues}".format( + num_outliers=self.summaries["cbetadev"][model]["num_outliers"], num_cbeta_residues=self.summaries["cbetadev"][model]["num_cbeta_residues"]) + + def cablam_header(self, model): + return " CaBLAM
Outliers: {num_cablam_outliers} out of {num_residues}".format( + num_cablam_outliers=self.summaries["cablam"][model]["num_cablam_outliers"], num_residues=self.summaries["cablam"][model]["num_residues"]) + + def pperp_header(self, model): + return " Base-P perp dist.
Outliers: {num_outliers} out of {num_residues}".format( + num_outliers=self.summaries["rna_puckers"][model]["num_outliers"], num_residues=self.summaries["rna_puckers"][model]["num_residues"]) + + def suite_header(self, model): + return " RNA suite conf.
Outliers: {num_outliers} out of {num_suites}".format( + num_outliers=self.summaries["rna_suites"][model]["num_outliers"], num_suites=self.summaries["rna_suites"][model]["num_suites"]) + + def bonds_header(self, model): + return " Bond lengths
Outliers: {num_outliers} out of {num_total}".format( + num_outliers=self.summaries["mp_bonds"][model]["num_outliers"], num_total=self.summaries["mp_bonds"][model]["num_total"]) + + def angles_header(self, model): + return " Bond angles
Outliers: {num_outliers} out of {num_total}".format( + num_outliers=self.summaries["mp_angles"][model]["num_outliers"], num_total=self.summaries["mp_angles"][model]["num_total"]) + + def omegalyze_header(self, model): + total_res = self.summaries["omegalyze"][model]["num_proline"] + self.summaries["omegalyze"][model]["num_general"] + total_nontrans = self.summaries["omegalyze"][model]["num_cis_proline"] + self.summaries["omegalyze"][model]["num_twisted_proline"] + self.summaries["omegalyze"][model]["num_cis_general"] + self.summaries["omegalyze"][model]["num_twisted_general"] + return " Cis Peptides
Non-Trans: {total_nontrans} out of {total_res}".format( + total_nontrans=total_nontrans, total_res=total_res) + + def make_multicrit_table(self, model, outliers_only=False): + lines = [] + #lines.append(self.html_header()) + if model.strip(): + lines.append("
Multi-criterion table: Model {model}".format(model)) + else: + lines.append("
Multi-criterion table") + lines.append("") + lines.append(" ") + #lines.append(" ") + lines.append(" ") + lines.append(" ") + lines.append(" ") + lines.append(" ") + lines.append(" ") + #for val_type in self.validation_types: + table_order = self.get_table_order() + for val_type in table_order: + #lines.append(" " % val_type) #this needs more details + #lines.append(" " % val_type) #this needs more details + if val_type == "clashscore": + lines.append(self.clash_header(model)) + elif val_type == "ramalyze": + lines.append(self.rama_header(model)) + elif val_type == "rotalyze": + lines.append(self.rota_header(model)) + elif val_type == "cbetadev": + lines.append(self.cbdev_header(model)) + elif val_type == "cablam": + lines.append(self.cablam_header(model)) + elif val_type == "rna_puckers": + lines.append(self.pperp_header(model)) + elif val_type == "rna_suites": + lines.append(self.suite_header(model)) + elif val_type == "mp_bonds": + lines.append(self.bonds_header(model)) + elif val_type == "mp_angles": + lines.append(self.angles_header(model)) + elif val_type == "omegalyze": + lines.append(self.omegalyze_header(model)) + else: + lines.append(" " % val_type) #this needs more details + lines.append(" ") + + line_colors = ['#ffffff','#f0f0f0'] + count = 0 + for reskey in self.indices: + if outliers_only and not self.data[reskey].has_outlier: + continue + color = line_colors[count % 2] + lines.append(self.data[reskey].residue_cells(color)) + for alt in self.data[reskey].alternates: + if alt != self.data[reskey].alternates[0]: + lines.append(" ".format(color=color)) + lines.append(" ".format(resname=self.data[reskey].find_resname(alt=alt))) + if alt in self.data[reskey].modeled_alternates: + lines.append(" ".format(alt=alt)) + else: + lines.append(" ".format(alt=alt)) + ##for val_type in self.validation_types: + for val_type in table_order: + if val_type == "clashscore": + lines.append(self.data[reskey].clash_cell(alt, reskey)) + elif val_type == "ramalyze": + lines.append(self.data[reskey].ramalyze_cell(alt)) + elif val_type == "rotalyze": + lines.append(self.data[reskey].rotalyze_cell(alt)) + elif val_type == "cbetadev": + lines.append(self.data[reskey].cbetadev_cell(alt)) + elif val_type == "cablam": + lines.append(self.data[reskey].cablam_cell(alt)) + elif val_type == "rna_puckers": + lines.append(self.data[reskey].base_p_perp_cell(alt)) + elif val_type == "rna_suites": + lines.append(self.data[reskey].suitename_cell(alt)) + elif val_type == "mp_bonds": + lines.append(self.data[reskey].bond_length_cell(alt)) + elif val_type == "mp_angles": + lines.append(self.data[reskey].bond_angle_cell(alt)) + elif val_type == "omegalyze": + lines.append(self.data[reskey].omegalyze_cell(alt)) + + lines.append(" ") + count+=1 + lines.append("
ModelChain#insResalt%s%s%s
{resname}{alt}({alt})
") + print("\n".join(lines)) + + + def html_header(self): + return """ + + + + MolProbity Table Test + + + +""" + + def html_header_d(self): + return """ + + + + + + + + + + MolProbity Table Test + + + + + + + + + + + + + + + + + + + + + + + + + + """ + +class residue(): + def __init__(self, rg, model_id, chain_id, resseq, icode): + self.reskey = make_reskey(model_id, chain_id, resseq, icode) + self.model_id = model_id + self.chain_id = chain_id + self.resseq = resseq + self.icode = icode + self.resnames = self.get_resnames_from_hierarchy(rg) + self.resname = self.resnames[sorted(self.resnames.keys())[0]] #returns resname of first altloc alphabetically + self.has_outlier = False + self.validations = {} + self.alternates = [''] + self.modeled_alternates = self.get_alts_from_hierarchy(rg) + self.colors = {"severe":"#ee4d4d", + "outlier":"#ff76a9", + "mild":"#ffb3cc"} + + def get_alternates(self): + allalts = []+self.modeled_alternates + for validation in self.validations: + allalts += self.validations[validation] + if not allalts: + allalts.append('') + self.alternates = sorted(set(allalts)) + #print(self.reskey, self.alternates) + + def get_resnames_from_hierarchy(self, rg): + #Intended to handle the rare case where a residue has alternates with different residue names + #May eventually need work to tie residue names to altlocs + #This is assumed rare enough to be low priority + resnames = {} + for ag in rg.atom_groups(): + resnames[ag.altloc] = ag.resname + return resnames + + def get_alts_from_hierarchy(self, rg): + #Help track whether an alt came from the model or from calculations + modeled_alternates = [] + for ag in rg.atom_groups(): + modeled_alternates.append(ag.altloc.strip()) + return modeled_alternates + + def find_resname(self, alt=''): + res = self.resnames.get(alt) + if res: + return res + else: + #return self.resname+"*" #this version marks the guess/default + return self.resname #default based on first alphabetical altloc + + def residue_cells(self,color): + #residue identifiers, plus row management for alternates + lines = [] + lines.append(" ".format(color=color)) + #lines.append(" {resid}".format(rows=len(self.alternates), resid=self.model_id)) + lines.append(" {resid}".format(rows=len(self.alternates), resid=self.chain_id)) + lines.append(" {resid}".format(rows=len(self.alternates), resid=self.resseq)) + lines.append(" {resid}".format(rows=len(self.alternates), resid=self.icode)) + + return("\n".join(lines)) + + def clash_cell(self, alt, reskey): + clash_data_res = self.validations.get("clashscore") + if clash_data_res is None: + return " -" + clash_data = clash_data_res.get(alt) + if clash_data is None: + return " -" + clash_size = abs(clash_data[0]["overlap"]) + if clash_size < 0.5: color = self.colors["mild"] #implicitely clash_size>=0.4 + elif clash_size > 0.9: color = self.colors["severe"] + else: color = self.colors["outlier"] + line1 = "{clash_size:.2f}Å".format(color=color, clash_size=clash_size) + if reskey == make_reskey(clash_data[0]["model_id"], clash_data[0]["chain_id"], clash_data[0]["resseq"], clash_data[0]["icode"]): + line2 = "
{src_atom} with {trg_chain} {trg_resseq}{trg_icode} {trg_resname} {trg_atom} {trg_altloc}".format(src_atom=clash_data[0]["name"], + trg_chain=clash_data[0]["target_chain_id"], + trg_resseq=clash_data[0]["target_resseq"], + trg_icode=clash_data[0]["target_icode"], + trg_resname=clash_data[0]["target_resname"], + trg_atom=clash_data[0]["target_name"], + trg_altloc=clash_data[0]["target_altloc"]) + else: #swap source and target in the cell + line2 = "
{src_atom} with {trg_chain} {trg_resseq}{trg_icode} {trg_resname} {trg_atom} {trg_altloc}".format(src_atom=clash_data[0]["target_name"], + trg_chain=clash_data[0]["chain_id"], + trg_resseq=clash_data[0]["resseq"], + trg_icode=clash_data[0]["icode"], + trg_resname=clash_data[0]["resname"], + trg_atom=clash_data[0]["name"], + trg_altloc=clash_data[0]["altloc"]) + return line1+line2+"" + + def bond_length_cell(self, alt): + geom_data_res = self.validations.get("mp_bonds") + if geom_data_res is None: + return " -" + geom_data = geom_data_res.get(alt) + if geom_data is None: + return " -" + geom_score = abs(geom_data[0]["score"]) + if geom_score >= 10: color = self.colors["severe"] + else: color = self.colors["outlier"] #implicitly score>=4 + line1 = "{outlier_count} OUTLIERS(S)".format(color=color, outlier_count=len(geom_data)) + line2 = "
worst is {atom1}--{atom2}: {geom_score:.1f} σ".format( + atom1=geom_data[0]["atoms_name"][0].strip(), atom2=geom_data[0]["atoms_name"][1].strip(), geom_score=geom_score) + return line1+line2+"" + + def bond_angle_cell(self, alt): + geom_data_res = self.validations.get("mp_angles") + if geom_data_res is None: + return " -" + geom_data = geom_data_res.get(alt) + if geom_data is None: + return " -" + geom_score = abs(geom_data[0]["score"]) + if geom_score >= 10: color = self.colors["severe"] + else: color = self.colors["outlier"] #implicitly score>=4 + line1 = "{outlier_count} OUTLIERS(S)".format(color=color, outlier_count=len(geom_data)) + line2 = "
worst is {atom1}-{atom2}-{atom3}: {geom_score:.1f} σ".format( + atom1=geom_data[0]["atoms_name"][0].strip(), atom2=geom_data[0]["atoms_name"][1].strip(), atom3=geom_data[0]["atoms_name"][2].strip(), geom_score=geom_score) + return line1+line2+"" + + def ramalyze_cell(self, alt): + #Allowed (0.36%)
General / -156.1,27.4 + rama_data_res = self.validations.get("ramalyze") + if rama_data_res is None: + return " -" + rama_data = rama_data_res.get(alt) + if rama_data is None: + return " -" + #linestart = " " + + def rotalyze_cell(self, alt): + #Allowed (0.4%) p0
chi angles: 41.2,280.7 + rota_data_res = self.validations.get("rotalyze") + if rota_data_res is None: + return " -" + rota_data = rota_data_res.get(alt) + if rota_data is None: + return " -" + + if rota_data["evaluation"] == "Allowed": + linestart = " " + elif rota_data["evaluation"] == "Outlier": + linestart = " " + else: + linestart = " " + + if rota_data["outlier"]: + line1 = "{rota_eval} ({score:.2f}%)".format(rota_eval=rota_data["evaluation"], score=rota_data["score"]) + else: + line1 = "{rota_eval} ({score:.2f}%) {rotamer} ".format(rota_eval=rota_data["evaluation"], score=rota_data["score"], rotamer=rota_data["rotamer_name"]) + + chi_angle_list = [] + for chi in rota_data["chi_angles"]: + if chi is not None: + chi_angle_list.append("%.1f" % chi) + line2 = "
chi angles: {chi_angles}".format(chi_angles=",".join(chi_angle_list)) + return linestart+line1+line2+"" + + def cbetadev_cell(self, alt): + #0.26Å + cbdev_data_res = self.validations.get("cbetadev") + if cbdev_data_res is None: + return " -" + cbdev_data = cbdev_data_res.get(alt) + if cbdev_data is None: + return " -" + if cbdev_data["outlier"]: + line = " {dev_dist:.2f}Å".format(dev_dist=cbdev_data["deviation"]) + else: + line = " {dev_dist:.2f}Å".format(dev_dist=cbdev_data["deviation"]) + return line + + def cablam_cell(self, alt): + # CaBLAM Disfavored (1.671%)
+ cablam_data_res = self.validations.get("cablam") + if cablam_data_res is None: + return " -" + cablam_data = cablam_data_res.get(alt) + if cablam_data is None: + return " -" + + score = cablam_data["scores"]["cablam"] + if cablam_data['outlier_type'] == "CA Geom Outlier": + line1 = " CA Geom Outlier ({score:.3f}%)".format(color=self.colors["severe"], score=score) + elif cablam_data['outlier_type'] == "CaBLAM Outlier": + line1 = " CaBLAM Outlier ({score:.3f}%)".format(color=self.colors["outlier"], score=score) + elif cablam_data['outlier_type'] == "CaBLAM Disfavored": + line1 = " CaBLAM Disfavored ({score:.3f}%)".format(color=self.colors["mild"], score=score) + else: + line1 = " Favored ({score:.3f}%)".format(score=score) + + if cablam_data["feedback"] == "try alpha helix": + line2 = "
alpha helix" + elif cablam_data["feedback"] == "try beta sheet": + line2 = "
beta sheet" + elif cablam_data["feedback"] == "try three-ten": + line2 = "
three-ten" + else: + line2 = "" + return line1+line2+"" + + def omegalyze_cell(self, alt): + omega_data_res = self.validations.get("omegalyze") + if omega_data_res is None: + return " -" + omega_data = omega_data_res.get(alt) + if omega_data is None: + return " -" + + #Cis Pro gets text, but no color + #Cis nonPro gets outlier pink + #Twisted Anything gets severe red + if omega_data["omega_type"] == "Twisted": + linestart = " ".format(color=self.colors["severe"]) + elif omega_data["omega_type"] == "Cis": + if omega_data["resname"] == "PRO": + linestart = " " + else: + linestart = " ".format(color=self.colors["outlier"]) + else: + return " -" + + if omega_data["resname"] == "PRO": + line1 = "{omega_type} PRO".format(omega_type = omega_data["omega_type"]) + else: + line1 = "{omega_type} nonPRO".format(omega_type = omega_data["omega_type"]) + + line2 = "
omega= {omega:.2f}".format(omega=omega_data["omega"]) + return linestart+line1+line2+"" + + def suitename_cell(self, alt): + suite_data_res = self.validations.get("rna_suites") + if suite_data_res is None: + return " -" + suite_data = suite_data_res.get(alt) + if suite_data is None: + return " -" + + if suite_data["outlier"]: + line1 = " OUTLIER".format(color=self.colors["outlier"]) + line2 = "" + else: + line1 = " conformer: {suitename}".format(suitename=suite_data["cluster"]) + line2 = "" + + if suite_data["bin"] == "trig": #i.e. triaged + line2 = "
(triaged {reason})".format(reason = suite_data["reason"]) + elif suite_data["bin"] == "inc": #i.e. incomplete + line2 = "
(incomplete)" + else: #suite_data["bin"] is something like "33 t" or "23 p", representing the two puckers and the m/p/t-staggered gamma dihedral + ddg = suite_data["bin"][0] + "'," + suite_data["bin"][1] + "'," + suite_data["bin"][3] + if suite_data["outlier"]: + line2 = "
δ-1,δ,γ={suite_bin}".format(suite_bin=ddg) + else: + line2 = "
δ-1,δ,γ={suite_bin} ; suiteness={suiteness:.2f}".format(suite_bin=ddg, suiteness=suite_data["suiteness"]) + return line1+line2+"" + + def base_p_perp_cell(self, alt): + pperp_data_res = self.validations.get("rna_puckers") + if pperp_data_res is None: + return " -" + pperp_data = pperp_data_res.get(alt) + if pperp_data is None: + return " -" + + outlier_types = [] + if pperp_data["is_delta_outlier"]: + outlier_types.append("δ") + if pperp_data["is_epsilon_outlier"]: + outlier_types.append("ε") + outlier_type = " & ".join(outlier_types) + + #diagnosis should not be calculated here! Put it in the validation itself! + diagnosis="unknown" + #if pperp_data["is_delta_outlier"] + #if($perpdist < 2.9) //2.9A is dist cutoff for C2' vs C3' endo pucker + # $probpucker = "C2'-endo"; + # else + # $probpucker = "C3'-endo"; + + line1 = " suspect sugar pucker - {outlier_type} outlier".format(color=self.colors["outlier"], outlier_type=outlier_type) + line2 = "
(P-perp distance implies {diagnosis})".format(diagnosis=diagnosis) + return line1+line2+"" + +def loadModel(filename): # from suitename/suites.py + from iotbx.data_manager import DataManager + dm = DataManager() # Initialize the DataManager and call it dm + dm.set_overwrite(True) # tell the DataManager to overwrite files with the same name + model = dm.get_model(filename) + return model +#model.get_hierarchy() + +def read_jsons_from_files(file_list): + #accepts list of file paths + #returns dictionary of jsons + validations = {} + for file_path in file_list: + if not os.path.isfile(file_path): + continue + valfile = open(file_path) + validation = json.load(valfile) + if validation.get("mp_bonds"): + validations["mp_bonds"] = validation["mp_bonds"] + validations["mp_angles"] = validation["mp_angles"] + else: + validations[validation["validation_type"]] = validation + valfile.close() + return validations + +pdbfilepath = sys.argv[1] +model = loadModel(pdbfilepath) +h = model.get_hierarchy() +#merged = make_storage_structure_from_hierarchy(h) +merged = merged_validations(h) + +file_list = sys.argv[2:] +validations = read_jsons_from_files(file_list) + +merged.add_validations(validations.values()) +merged.add_summaries(validations.values()) + +print(merged.html_header()) +merged.make_summary_table("") +merged.make_multicrit_table("", outliers_only=True) + From a2835737039141821e30ef12f418efd50338738b Mon Sep 17 00:00:00 2001 From: Vincent Chen Date: Sun, 3 Mar 2024 21:27:50 -0500 Subject: [PATCH 227/748] bug fix for missing dict initialization --- mmtbx/programs/chiral_validation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmtbx/programs/chiral_validation.py b/mmtbx/programs/chiral_validation.py index baa28f752a..2b0b9a06c1 100644 --- a/mmtbx/programs/chiral_validation.py +++ b/mmtbx/programs/chiral_validation.py @@ -16,6 +16,7 @@ class Program(ProgramTemplate): Options: model=input_file input PDB or mmCIF file + outliers_only=True Only return chiral outliers kinemage=False Create kinemage markup (overrides text output) json=False Outputs results as JSON compatible dictionary help = False Prints this help message if true From e076090012f77ea318647e60d84fd18928215d83 Mon Sep 17 00:00:00 2001 From: Vincent Chen Date: Mon, 4 Mar 2024 18:09:12 -0500 Subject: [PATCH 228/748] swapped is_protein and is_na to faster methods --- mmtbx/validation/mp_validate_bonds.py | 25 +++++++++++-------------- mmtbx/validation/utils.py | 10 ++++++++++ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/mmtbx/validation/mp_validate_bonds.py b/mmtbx/validation/mp_validate_bonds.py index 2c40fbafff..aefcb491f1 100644 --- a/mmtbx/validation/mp_validate_bonds.py +++ b/mmtbx/validation/mp_validate_bonds.py @@ -94,7 +94,7 @@ def as_table_row_phenix(self): # analysis objects class mp_bonds(validation): output_header = "#residue:atom_1:atom_2:num_sigmas" - label = "Backbone bond lenths" + label = "Bond lengths" gui_list_headers = ["Residue", "Atom 1", "Atom 2", "Sigmas"] gui_formats = ["%s", "%s", "%s", "%.2f"] wx_column_widths = [160] * 4 @@ -136,15 +136,14 @@ def __init__(self, pdb_hierarchy, pdb_atoms, geometry_restraints_manager, labels = pdb_atoms[proxy.i_seqs[0]].fetch_labels() model_id = labels.model_id self.n_total += 1 + #iotbx.pdb.common_residue_names_get_class self.n_total_by_model[model_id] += 1 - if pdb_atoms[proxy.i_seqs[0]].parent().parent().parent().is_protein(): - mm_type="PROTEIN" + mm_type = utils.get_mmtype_from_resname(pdb_atoms[proxy.i_seqs[0]].parent().resname) + if mm_type=="PROTEIN": self.n_total_protein_by_model[model_id] += 1 - elif pdb_atoms[proxy.i_seqs[0]].parent().parent().parent().is_na(): - mm_type="NA" + elif mm_type=="NA": self.n_total_na_by_model[model_id] += 1 else: - mm_type="OTHER" self.n_total_other_by_model[model_id] += 1 sigma = sqrt(1 / restraint.weight) num_sigmas = - restraint.delta / sigma @@ -207,7 +206,7 @@ def as_JSON(self, addon_json={}): def show_summary(self, out=sys.stdout, prefix=""): if (self.n_total == 0): - print(prefix + "No atoms found.", file=out) + print(prefix + "No bond lengths found.", file=out) elif (self.n_outliers == 0): print(prefix + "All bonds within 4.0 sigma of ideal values.", file=out) else : @@ -216,7 +215,7 @@ def show_summary(self, out=sys.stdout, prefix=""): class mp_angles(validation): output_header = "#residue:atom_1:atom_2:atom_3:num_sigmas" - label = "Backbone bond angles" + label = "Bond angles" gui_list_headers = ["Residue", "Atom 1", "Atom 2", "Atom 3", "Sigmas"] gui_formats = ["%s", "%s", "%s", "%s", "%.2f"] wx_column_widths = [160] * 5 @@ -257,14 +256,12 @@ def __init__(self, pdb_hierarchy, pdb_atoms, geometry_restraints_manager, model_id = labels.model_id self.n_total += 1 self.n_total_by_model[model_id] += 1 - if pdb_atoms[proxy.i_seqs[0]].parent().parent().parent().is_protein(): - mm_type="PROTEIN" + mm_type = utils.get_mmtype_from_resname(pdb_atoms[proxy.i_seqs[0]].parent().resname) + if mm_type=="PROTEIN": self.n_total_protein_by_model[model_id] += 1 - elif pdb_atoms[proxy.i_seqs[0]].parent().parent().parent().is_na(): - mm_type="NA" + elif mm_type=="NA": self.n_total_na_by_model[model_id] += 1 else: - mm_type="OTHER" self.n_total_other_by_model[model_id] += 1 sigma = sqrt(1 / restraint.weight) num_sigmas = - restraint.delta / sigma @@ -328,7 +325,7 @@ def as_JSON(self, addon_json={}): def show_summary(self, out=sys.stdout, prefix=""): if (self.n_total == 0): - print(prefix + "No backbone atoms found.", file=out) + print(prefix + "No bond angles found.", file=out) elif (self.n_outliers == 0): print(prefix + "All angles within 4.0 sigma of ideal values.", file=out) else : diff --git a/mmtbx/validation/utils.py b/mmtbx/validation/utils.py index 2f077a594c..495da006bd 100644 --- a/mmtbx/validation/utils.py +++ b/mmtbx/validation/utils.py @@ -4,6 +4,7 @@ from libtbx import group_args from libtbx.utils import Sorry from collections import defaultdict +from iotbx.pdb import common_residue_names_get_class import os.path import math import sys @@ -340,6 +341,15 @@ def build_name_hash(pdb_hierarchy): i_seq_name_hash[atom.i_seq]=atom.pdb_label_columns() return i_seq_name_hash +def get_mmtype_from_resname(resname): + class_string = common_residue_names_get_class(resname) + if "amino_acid" in class_string: + return "PROTEIN" + elif "rna_dna" in class_string: + return "NA" + else: + return "OTHER" + def exercise(): from libtbx.test_utils import approx_equal try : From c70ccebee3baa4cbfcf86d42651aa104856a3ec1 Mon Sep 17 00:00:00 2001 From: Vincent Chen Date: Mon, 4 Mar 2024 18:09:40 -0500 Subject: [PATCH 229/748] bug fix for chiral_validation --- mmtbx/validation/restraints.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmtbx/validation/restraints.py b/mmtbx/validation/restraints.py index 966f4eb63e..f8415676f5 100644 --- a/mmtbx/validation/restraints.py +++ b/mmtbx/validation/restraints.py @@ -589,6 +589,7 @@ def get_outliers(self, proxies, unit_cell, sites_cart, pdb_atoms, self.n_pseudochiral_by_model[model_id] = 0 self.n_tetrahedral_by_model[model_id] = 0 self.n_chiral_by_model[model_id] = 0 + self.n_outliers_by_model[model_id] = 0 if not outlier.is_pseudochiral(): self.n_chiral_by_model[model_id] += 1 if (outlier.score > sigma_cutoff): From a4714a58929843bf4b4f1721b29b2a5c049fc9a5 Mon Sep 17 00:00:00 2001 From: Vincent Chen Date: Tue, 5 Mar 2024 19:57:29 -0500 Subject: [PATCH 230/748] modification for omegalyze to deal with d amino acids --- mmtbx/conformation_dependent_library/__init__.py | 9 +++++++++ mmtbx/validation/omegalyze.py | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/mmtbx/conformation_dependent_library/__init__.py b/mmtbx/conformation_dependent_library/__init__.py index f72af4ff15..9c86249a1b 100644 --- a/mmtbx/conformation_dependent_library/__init__.py +++ b/mmtbx/conformation_dependent_library/__init__.py @@ -114,6 +114,7 @@ def generate_residue_tuples(hierarchy, include_non_linked=False, backbone_only=True, include_non_standard_residues=False, + include_d_amino_acids=False, allow_poly_ca=False, # CDL specific cdl_class=False, @@ -145,6 +146,8 @@ def generate_residue_tuples(hierarchy, residue_lookup = ['common_amino_acid'] if include_non_standard_residues: residue_lookup.append('modified_amino_acid') + if include_d_amino_acids: + residue_lookup.append('d_amino_acid') if backbone_only: backbone_asc = hierarchy.atom_selection_cache() backbone_sel = backbone_asc.selection(retain_selection) @@ -222,6 +225,7 @@ def generate_protein_tuples(hierarchy, include_non_linked=False, backbone_only=True, include_non_standard_peptides=False, + include_d_amino_acids=False, allow_poly_ca=False, include_linked_via_restraints_manager=False, # CDL specific @@ -237,6 +241,7 @@ def generate_protein_tuples(hierarchy, include_non_linked=include_non_linked, backbone_only=backbone_only, include_non_standard_residues=include_non_standard_peptides, + include_d_amino_acids=include_d_amino_acids, allow_poly_ca=allow_poly_ca, #include_linked_via_restraints_manager=include_linked_via_restraints_manager, # CDL specific @@ -254,6 +259,7 @@ def generate_protein_threes(hierarchy, include_non_linked=False, backbone_only=True, include_non_standard_peptides=False, + include_d_amino_acids=False, include_linked_via_restraints_manager=False, allow_poly_ca=False, # CDL specific @@ -268,6 +274,7 @@ def generate_protein_threes(hierarchy, include_non_linked=include_non_linked, backbone_only=backbone_only, include_non_standard_peptides=include_non_standard_peptides, + include_d_amino_acids=include_d_amino_acids, allow_poly_ca=allow_poly_ca, # include_linked_via_restraints_manager=include_linked_via_restraints_manager, cdl_class=cdl_class, @@ -283,6 +290,7 @@ def generate_protein_fragments(hierarchy, include_non_linked=False, backbone_only=True, include_non_standard_peptides=False, + include_d_amino_acids=False, allow_poly_ca = False, # include_non_protein_linked=False, # NH2 1KYC # include_linked_via_restraints_manager=False, @@ -295,6 +303,7 @@ def generate_protein_fragments(hierarchy, include_non_linked=include_non_linked, backbone_only=backbone_only, include_non_standard_residues=include_non_standard_peptides, + include_d_amino_acids=include_d_amino_acids, allow_poly_ca=allow_poly_ca, # include_non_protein_linked=include_non_protein_linked, # include_linked_via_restraints_manager=include_linked_via_restraints_manager, diff --git a/mmtbx/validation/omegalyze.py b/mmtbx/validation/omegalyze.py index be1ca9de7b..6c35ccb0b1 100644 --- a/mmtbx/validation/omegalyze.py +++ b/mmtbx/validation/omegalyze.py @@ -303,7 +303,8 @@ def __init__(self, pdb_hierarchy, length=2, geometry=None, - include_non_standard_peptides=True): + include_non_standard_peptides=True, + include_d_amino_acids=True): main_residue = twores[1] #this is the relevant residue for id-ing cis-Pro conf_altloc = get_conformer_altloc(twores) omega_atoms = get_omega_atoms(twores) From 435d6ca86b9b60d973f4eacde4ecb304460666d5 Mon Sep 17 00:00:00 2001 From: Vincent Chen Date: Tue, 12 Mar 2024 13:49:15 -0400 Subject: [PATCH 231/748] add long chain test --- mmtbx/validation/regression/tst_chiral_validation.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mmtbx/validation/regression/tst_chiral_validation.py b/mmtbx/validation/regression/tst_chiral_validation.py index cad6f3403c..82854f5e11 100644 --- a/mmtbx/validation/regression/tst_chiral_validation.py +++ b/mmtbx/validation/regression/tst_chiral_validation.py @@ -4,6 +4,7 @@ from libtbx.easy_pickle import loads from iotbx.data_manager import DataManager from mmtbx.model import manager +from libtbx.test_utils import convert_pdb_to_cif_for_pdb_str import time import json import difflib @@ -157,4 +158,6 @@ def exercise_chiral_json(chiral_list): chiral_list = calculate_results() exercise_chiral_validation(chiral_list) exercise_chiral_json(chiral_list) + convert_pdb_to_cif_for_pdb_str(locals(), chain_addition="ALONGCHAIN", key_str="pdb_") + exercise_chiral_json(chiral_list) print("OK. Time: %8.3f"%(time.time()-t0)) From 139d6486f5c0490aa5559155c7936253d9602021 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 19 Mar 2024 09:43:48 -0600 Subject: [PATCH 232/748] Move LocalAnisoSharpening and AutoSharpen to MapSharpening --- cctbx/command_line/auto_sharpen.py | 11 + cctbx/maptbx/auto_sharpen.py | 404 +++++++++++++------------- cctbx/maptbx/segment_and_split_map.py | 7 +- iotbx/data_manager/common.py | 25 +- 4 files changed, 243 insertions(+), 204 deletions(-) diff --git a/cctbx/command_line/auto_sharpen.py b/cctbx/command_line/auto_sharpen.py index 5165a441d9..f0941ba656 100644 --- a/cctbx/command_line/auto_sharpen.py +++ b/cctbx/command_line/auto_sharpen.py @@ -4,5 +4,16 @@ import sys if (__name__ == "__main__"): + + deprecated = True + for ok in ['--force','force']: + if ok in sys.argv: + sys.argv.remove(ok) + deprecated = False + if deprecated: + from libtbx.utils import Sorry + raise Sorry("phenix.auto_sharpen is replaced by phenix.map_sharpening"+ + " Add the keyword '--force' to use anyway") + from cctbx.maptbx.auto_sharpen import run run(args=sys.argv[1:]) diff --git a/cctbx/maptbx/auto_sharpen.py b/cctbx/maptbx/auto_sharpen.py index be2c01cd5e..9d5c14f703 100644 --- a/cctbx/maptbx/auto_sharpen.py +++ b/cctbx/maptbx/auto_sharpen.py @@ -2,197 +2,9 @@ import sys, os import iotbx.phil from libtbx.utils import Sorry +import libtbx.phil -master_phil = iotbx.phil.parse(""" - - input_files - .style = menu_item auto_align - { - - map_file = None - .type = path - .help = File with CCP4-style map - .short_caption = Map file - .style = file_type:ccp4_map bold input_file - - half_map_file = None - .type = path - .multiple = True - .short_caption = Half map - .style = file_type:ccp4_map bold input_file - .help = Half map (two should be supplied) for FSC calculation. Must \ - have grid identical to map_file - - external_map_file = None - .type = path - .short_caption = External map - .style = file_type:ccp4_map bold input_file - .help = External map to be used to scale map_file (power vs resolution\ - will be matched) - - map_coeffs_file = None - .type = path - .help = Optional file with map coefficients - .short_caption = Map coefficients - .style = bold file_type:hkl input_file process_hkl \ - child:map_labels:map_coeffs_labels \ - child:space_group:space_group child:unit_cell:unit_cell - - map_coeffs_labels = None - .type = str - .input_size = 160 - .help = Optional label specifying which columns of of map coefficients \ - to use - .short_caption = Map coeffs label - .style = renderer:draw_map_arrays_widget - - pdb_file = None - .type = path - .help = If a model is supplied, the map will be adjusted to \ - maximize map-model correlation. This can be used \ - to improve a map in regions where no model is yet \ - built. - .style = file_type:pdb input_file - .short_caption = Model file (optional) - - ncs_file = None - .type = path - .help = File with NCS information (typically point-group NCS with \ - the center specified). Typically in PDB format. \ - Can also be a .ncs_spec file from phenix. \ - Created automatically if symmetry is specified. - .short_caption = NCS info file - - seq_file = None - .type = path - .short_caption = Sequence file - .style = file_type:seq input_file - .help = Sequence file (unique chains only, \ - 1-letter code, chains separated by \ - blank line or greater-than sign.) \ - Can have chains that are DNA/RNA/protein and\ - all can be present in one file. - - input_weight_map_pickle_file = None - .type = path - .short_caption = Input weight map pickle file - .help = Weight map pickle file - - } - - output_files - .style = menu_item auto_align - { - - shifted_map_file = shifted_map.ccp4 - .type = str - .help = Input map file shifted to new origin. - .short_caption = Shifted map file - .style = new_file - - sharpened_map_file = sharpened_map.ccp4 - .type = str - .help = Sharpened input map file. In the same location as input map. - .short_caption = Sharpened map file - .input_size = 400 - .style = new_file - - shifted_sharpened_map_file = None - .type = str - .help = Input map file shifted to place origin at 0,0,0 and sharpened. - .short_caption = Shifted sharpened map file - .input_size = 400 - .style = new_file - - sharpened_map_coeffs_file = sharpened_map_coeffs.mtz - .type = str - .help = Sharpened input map \ - (shifted to new origin if original origin was not 0,0,0), \ - written out as map coefficients - .short_caption = Sharpened map coeffs file - .input_size = 400 - .style = new_file - - output_weight_map_pickle_file = weight_map_pickle_file.pkl - .type = path - .short_caption = Output weight map pickle file - .help = Output weight map pickle file - .style = new_file - - output_directory = None - .type = path - .help = Directory where output files are to be written \ - applied. - .short_caption = Output directory - .style = new_file directory - - } - - crystal_info - .style = menu_item auto_align - { - - is_crystal = None - .type = bool - .short_caption = Is a crystal - .help = Defines whether this is a crystal (or cryo-EM).\ - Default is True if use_sg_symmetry=True and False otherwise. - - resolution = None - .type = float - .short_caption = Resolution - .help = Optional nominal resolution of the map. - .style = resolution - - - solvent_content = None - .type = float - .help = Optional solvent fraction of the cell. - .short_caption = Solvent content - - solvent_content_iterations = 3 - .type = int - .help = Iterations of solvent fraction estimation. Used for ID of \ - solvent content in boxed maps. - .short_caption = Solvent fraction iterations - .style = hidden - - molecular_mass = None - .type = float - .help = Molecular mass of molecule in Da. Used as alternative method \ - of specifying solvent content. - .short_caption = Molecular mass in Da - - ncs_copies = None - .type = int - .help = You can specify ncs copies and seq file to define solvent \ - content - .short_caption = NCS copies - - wang_radius = None - .type = float - .help = Wang radius for solvent identification. \ - Default is 1.5* resolution - .short_caption = Wang radius - - buffer_radius = None - .type = float - .help = Buffer radius for mask smoothing. \ - Default is resolution - .short_caption = Buffer radius - - pseudo_likelihood = None - .type = bool - .help = Use pseudo-likelihood method for half-map sharpening. \ - (In development) - .short_caption = Pseudo-likelihood - .style = hidden - - } - - map_modification - .style = menu_item auto_align - { +map_modification_phil_str = """ b_iso = None .type = float @@ -598,6 +410,7 @@ .type = int .short_caption = Resolution bins .help = Number of resolution bins for sharpening. Default is 20. + .expert_level = 1 regions_to_keep = None .type = int @@ -628,8 +441,207 @@ .help = b_sol value for model map calculation. IGNORED (Not applied) .short_caption = b_sol IGNORED .style = hidden + """ + +output_files = """ + + shifted_map_file = shifted_map.ccp4 + .type = str + .help = Input map file shifted to new origin. + .short_caption = Shifted map file + .style = new_file + + sharpened_map_file = None + .type = str + .help = Sharpened input map file. In the same location as input map. + .short_caption = Sharpened map file + .input_size = 400 + .style = new_file + .expert_level = 1 + + shifted_sharpened_map_file = None + .type = str + .help = Input map file shifted to place origin at 0,0,0 and sharpened. + .short_caption = Shifted sharpened map file + .input_size = 400 + .style = new_file + + sharpened_map_coeffs_file = None + .type = str + .help = Sharpened input map \ + (shifted to new origin if original origin was not 0,0,0), \ + written out as map coefficients + .short_caption = Sharpened map coeffs file + .input_size = 400 + .style = new_file + + output_weight_map_pickle_file = weight_map_pickle_file.pkl + .type = path + .short_caption = Output weight map pickle file + .help = Output weight map pickle file + .style = new_file + + output_directory = None + .type = path + .help = Directory where output files are to be written \ + applied. + .short_caption = Output directory + .style = new_file directory +""" + +crystal_info = """ + is_crystal = None + .type = bool + .short_caption = Is a crystal + .help = Defines whether this is a crystal (or cryo-EM).\ + Default is True if use_sg_symmetry=True and False otherwise. + + resolution = None + .type = float + .short_caption = Resolution + .help = Optional nominal resolution of the map. + .style = resolution + .expert_level = 1 + + + solvent_content = None + .type = float + .help = Optional solvent fraction of the cell. + .short_caption = Solvent content + + solvent_content_iterations = 3 + .type = int + .help = Iterations of solvent fraction estimation. Used for ID of \ + solvent content in boxed maps. + .short_caption = Solvent fraction iterations + .style = hidden + + molecular_mass = None + .type = float + .help = Molecular mass of molecule in Da. Used as alternative method \ + of specifying solvent content. + .short_caption = Molecular mass in Da + + ncs_copies = None + .type = int + .help = You can specify ncs copies and seq file to define solvent \ + content + .short_caption = NCS copies + + wang_radius = None + .type = float + .help = Wang radius for solvent identification. \ + Default is 1.5* resolution + .short_caption = Wang radius + + buffer_radius = None + .type = float + .help = Buffer radius for mask smoothing. \ + Default is resolution + .short_caption = Buffer radius + + pseudo_likelihood = None + .type = bool + .help = Use pseudo-likelihood method for half-map sharpening. \ + (In development) + .short_caption = Pseudo-likelihood + .style = hidden +""" + +master_phil = iotbx.phil.parse(""" + + input_files + .style = menu_item auto_align + { + + map_file = None + .type = path + .help = File with CCP4-style map + .short_caption = Map file + .style = file_type:ccp4_map bold input_file + + half_map_file = None + .type = path + .multiple = True + .short_caption = Half map + .style = file_type:ccp4_map bold input_file + .help = Half map (two should be supplied) for FSC calculation. Must \ + have grid identical to map_file + + external_map_file = None + .type = path + .short_caption = External map + .style = file_type:ccp4_map bold input_file + .help = External map to be used to scale map_file (power vs resolution\ + will be matched) + + map_coeffs_file = None + .type = path + .help = Optional file with map coefficients + .short_caption = Map coefficients + .style = bold file_type:hkl input_file process_hkl \ + child:map_labels:map_coeffs_labels \ + child:space_group:space_group child:unit_cell:unit_cell + + map_coeffs_labels = None + .type = str + .input_size = 160 + .help = Optional label specifying which columns of of map coefficients \ + to use + .short_caption = Map coeffs label + .style = renderer:draw_map_arrays_widget + + pdb_file = None + .type = path + .help = If a model is supplied, the map will be adjusted to \ + maximize map-model correlation. This can be used \ + to improve a map in regions where no model is yet \ + built. + .style = file_type:pdb input_file + .short_caption = Model file (optional) + + ncs_file = None + .type = path + .help = File with NCS information (typically point-group NCS with \ + the center specified). Typically in PDB format. \ + Can also be a .ncs_spec file from phenix. \ + Created automatically if symmetry is specified. + .short_caption = NCS info file + + seq_file = None + .type = path + .short_caption = Sequence file + .style = file_type:seq input_file + .help = Sequence file (unique chains only, \ + 1-letter code, chains separated by \ + blank line or greater-than sign.) \ + Can have chains that are DNA/RNA/protein and\ + all can be present in one file. + + input_weight_map_pickle_file = None + .type = path + .short_caption = Input weight map pickle file + .help = Weight map pickle file + } + output_files + .style = menu_item auto_align + { + %s + } + + crystal_info + .style = menu_item auto_align + { + %s + } + + map_modification { + %s + } + + control .style = menu_item auto_align { @@ -676,7 +688,8 @@ .style = output_dir } -""", process_includes=True) +""" %(output_files, crystal_info, map_modification_phil_str), + process_includes=True) master_params = master_phil def get_params(args,out=sys.stdout): @@ -859,9 +872,9 @@ def get_map_and_model(params=None, if params.input_files.external_map_file and not \ params.map_modification.auto_sharpen_methods==['external_map_sharpening']: - raise Sorry("Please specify external_map_file and "+ - "auto_sharpen_methods=external_map_sharpening or"+ - " neither") + raise Sorry("For external map sharpening, please do not set any other "+ + "options in 'Sharpening methods' (options set: %s)" %( + ", ".join(params.map_modification.auto_sharpen_methods))) if params.map_modification.auto_sharpen_methods==['external_map_sharpening']: @@ -902,7 +915,8 @@ def get_map_and_model(params=None, half_map_data_list.append(half_map_data) if params.crystal_info.resolution is None: - raise Sorry("Need resolution if map is supplied") + raise Sorry("Need resolution for b-sharpening if "+ + "map is supplied and no model is supplied") if params.crystal_info.resolution >= 10: print("\n** WARNING: auto_sharpen is designed for maps at a "+\ diff --git a/cctbx/maptbx/segment_and_split_map.py b/cctbx/maptbx/segment_and_split_map.py index 6f3096e4f2..4b42e1c602 100644 --- a/cctbx/maptbx/segment_and_split_map.py +++ b/cctbx/maptbx/segment_and_split_map.py @@ -2203,7 +2203,8 @@ def update_with_params(self, params = None, self.k_sharpen = None return self - def show_summary(self, verbose = False, out = sys.stdout): + def show_summary(self, verbose = False, list_scale_factors = True, + out = sys.stdout): method_summary_dict = { 'b_iso':"Overall b_iso sharpening", 'b_iso_to_d_cut':"b_iso sharpening to high_resolution cutoff", @@ -2262,7 +2263,7 @@ def show_summary(self, verbose = False, out = sys.stdout): elif self.sharpening_method == "model_sharpening": print("Resolution-dependent model sharpening", file = out) - if self.d_min_list and self.target_scale_factors: + if self.d_min_list and self.target_scale_factors and list_scale_factors: print("Scale vs resolution:", file = out) for d_min, sc in zip( self.d_min_list, @@ -2271,7 +2272,7 @@ def show_summary(self, verbose = False, out = sys.stdout): elif self.sharpening_method == "half_map_sharpening": print("Resolution-dependent half-map sharpening", file = out) - if self.d_min_list and self.target_scale_factors: + if self.d_min_list and self.target_scale_factors and list_scale_factors: print("Scale vs resolution:", file = out) for d_min, sc in zip( self.d_min_list, diff --git a/iotbx/data_manager/common.py b/iotbx/data_manager/common.py index e12a31f676..4cadd91d3e 100644 --- a/iotbx/data_manager/common.py +++ b/iotbx/data_manager/common.py @@ -308,6 +308,7 @@ def get_map_model_manager( map_files=None, from_phil=False, guess_files=True, + files_to_exclude = None, **kwargs): ''' A convenience function for constructing a map_model_manager from the @@ -327,6 +328,9 @@ def get_map_model_manager( If set to True, the model and map names are retrieved from the standard PHIL names. The model_file and map_files parameters must be None if this parameter is set to True. + files_to_exclude: str or list + Any files listed will not be used from data_manager. For example, + this can be used to exclude a file from being considered a half map **kwargs: keyworded arguments Extra keyworded arguments for map_model_manager constructor @@ -361,14 +365,19 @@ def get_map_model_manager( # Catch case where full_map is also present in half_maps as the only # half map - if full_map and (len(half_maps) == 1) and (half_maps[0] == full_map): - half_maps = [] - + maps_to_exclude = [full_map] if full_map else [] + if files_to_exclude: + if isinstance(files_to_exclude,list): + maps_to_exclude += files_to_exclude + else: + maps_to_exclude.append(files_to_exclude) + for fn in (maps_to_exclude if maps_to_exclude else []): + if fn and (len(half_maps) == 1) and (half_maps[0] == fn): + half_maps = [] if half_maps: if len(half_maps) != 2: raise Sorry('Please provide 2 half-maps or one full map.') map_files += half_maps - # If we didn't get anything, try looking directly at the # available maps and models. If there are 1, 2 or 3 maps and 1 model, # take them @@ -379,11 +388,15 @@ def get_map_model_manager( map_model.model = model_file if guess_files and (not map_files) and self.get_real_map_names(): if len(self.get_real_map_names()) == 1: - map_files = self.get_default_real_map_name() + map_files = [self.get_default_real_map_name()] elif len(self.get_real_map_names()) in [2,3]: map_files = self.get_real_map_names() - + new_map_files = [] + for fn in map_files: + if (not files_to_exclude) or (not fn in files_to_exclude): + new_map_files.append(fn) + map_files = new_map_files # check map_files argument mm = None mm_1 = None From ffa283613d1058aba7f7e4549003c7d8b303ece7 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 19 Mar 2024 10:35:25 -0600 Subject: [PATCH 233/748] Allow trimming from ends only --- mmtbx/process_predicted_model.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/mmtbx/process_predicted_model.py b/mmtbx/process_predicted_model.py index 430aa08e1b..d19d3b1e11 100644 --- a/mmtbx/process_predicted_model.py +++ b/mmtbx/process_predicted_model.py @@ -33,6 +33,12 @@ .short_caption = Remove low-confidence residues .expert_level = 3 + continuous_chain = False + .type = bool + .help = When removing low-confidence residues, only trim from ends + .short_caption = Maintain continuous chain + .expert_level = 3 + split_model_by_compact_regions = True .type = bool .help = Split model into compact regions after removing \ @@ -263,6 +269,7 @@ def process_predicted_model( If None, set to True if all plddt are from 0 to 1 remove_low_confidence_residues: remove residues with low confidence (plddt or rmsd as set below) + continuous_chain: if removing low-confidence residues, trim ends only minimum_plddt: minimum plddt to keep residues (on same scale as b_value_field, if not set, calculated from maximum_rmsd). maximum_rmsd: alternative specification of minimum confidence based on rmsd. @@ -419,6 +426,8 @@ def process_predicted_model( # Get selection based on CA/P atoms asc1 = ph.atom_selection_cache() sel1 = asc1.selection('(name ca or name P) and (%s) ' %selection_string) + if p.continuous_chain: # trim ends only + restore_true_except_at_ends(sel1) ca_ph = ph.select(sel1) selection_string_2 = get_selection_for_short_segments(ca_ph,None) @@ -541,6 +550,20 @@ def process_predicted_model( vrms_list = vrms_list, ) +def restore_true_except_at_ends(sel1): + ''' Set all values that are not at ends of sel1 to False (any number + at ends may be False)''' + + values = list(sel1) + if not True in values: + return # nothing to do + first_true = values.index(True) + values.reverse() + last_true_from_end = values.index(True) + last_true = len(values) - last_true_from_end + for i in range(first_true,last_true): + sel1[i] = True + def get_vrms_list(p, model_list): vrms_list = [] for m in model_list: From 1bff6da141656211cc353915a0c19b8dfcbdfc4f Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 19 Mar 2024 09:43:36 -0700 Subject: [PATCH 234/748] Fix assumption that map_files is list --- iotbx/data_manager/common.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/iotbx/data_manager/common.py b/iotbx/data_manager/common.py index 4cadd91d3e..f079d9c178 100644 --- a/iotbx/data_manager/common.py +++ b/iotbx/data_manager/common.py @@ -341,6 +341,9 @@ def get_map_model_manager( # get filenames from PHIL map_model = None + if map_files and (not isinstance(map_files,list)): + map_files = [map_files] + if from_phil: if model_file is not None or map_files is not None: raise Sorry( From abe900a17bf6dab6764738d4d9a822a3844572d8 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 19 Mar 2024 09:45:31 -0700 Subject: [PATCH 235/748] fix typo --- iotbx/data_manager/common.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/iotbx/data_manager/common.py b/iotbx/data_manager/common.py index f079d9c178..e10d232357 100644 --- a/iotbx/data_manager/common.py +++ b/iotbx/data_manager/common.py @@ -395,11 +395,12 @@ def get_map_model_manager( elif len(self.get_real_map_names()) in [2,3]: map_files = self.get_real_map_names() - new_map_files = [] - for fn in map_files: - if (not files_to_exclude) or (not fn in files_to_exclude): - new_map_files.append(fn) - map_files = new_map_files + if isinstance(map_files, list): + new_map_files = [] + for fn in map_files: + if (not files_to_exclude) or (not fn in files_to_exclude): + new_map_files.append(fn) + map_files = new_map_files # check map_files argument mm = None mm_1 = None From df5b1062349507462e381ccdd0d76bd2cac6010b Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 19 Mar 2024 10:20:57 -0700 Subject: [PATCH 236/748] Write out files with old auto_sharpen --- cctbx/maptbx/auto_sharpen.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cctbx/maptbx/auto_sharpen.py b/cctbx/maptbx/auto_sharpen.py index 9d5c14f703..4a550f451a 100644 --- a/cctbx/maptbx/auto_sharpen.py +++ b/cctbx/maptbx/auto_sharpen.py @@ -1124,6 +1124,8 @@ def run(args=None,params=None, if acc is not None: # offset the map to match original if possible offset_map_data.reshape(acc) + if write_output_files and (not params.output_files.sharpened_map_file): + params.output_files.sharpened_map_file = 'sharpened_map_file.ccp4' if write_output_files and params.output_files.sharpened_map_file and \ offset_map_data: output_map_file=os.path.join(params.output_files.output_directory, @@ -1161,6 +1163,8 @@ def run(args=None,params=None, print("\nWrote sharpened map (origin at %s)\nto %s" %( str(new_map_data.origin()),output_map_file), file=out) + if write_output_files and (not params.output_files.sharpened_map_coeffs_file): + params.output_files.sharpened_map_coeffs_file = 'sharpened_map_coeffs.mtz' if write_output_files and params.output_files.sharpened_map_coeffs_file and \ new_map_coeffs: output_map_coeffs_file=os.path.join(params.output_files.output_directory, From 930e0e809e2191f08073553dcbb6e5050c5d21d9 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 19 Mar 2024 10:22:21 -0700 Subject: [PATCH 237/748] Write out files with old auto_sharpen --- cctbx/maptbx/auto_sharpen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cctbx/maptbx/auto_sharpen.py b/cctbx/maptbx/auto_sharpen.py index 4a550f451a..54fc7b19f1 100644 --- a/cctbx/maptbx/auto_sharpen.py +++ b/cctbx/maptbx/auto_sharpen.py @@ -1125,7 +1125,7 @@ def run(args=None,params=None, offset_map_data.reshape(acc) if write_output_files and (not params.output_files.sharpened_map_file): - params.output_files.sharpened_map_file = 'sharpened_map_file.ccp4' + params.output_files.sharpened_map_file = 'sharpened_map.ccp4' if write_output_files and params.output_files.sharpened_map_file and \ offset_map_data: output_map_file=os.path.join(params.output_files.output_directory, From 23207e2f1ab12fa3776e5909ed1b844872c5f590 Mon Sep 17 00:00:00 2001 From: dwmoreau Date: Tue, 19 Mar 2024 11:42:49 -0700 Subject: [PATCH 238/748] Update to the correct file --- .../application/errors/error_modifier_mm24.py | 166 +++++++++++++----- 1 file changed, 118 insertions(+), 48 deletions(-) diff --git a/xfel/merging/application/errors/error_modifier_mm24.py b/xfel/merging/application/errors/error_modifier_mm24.py index 1d36656065..259ca5b7da 100644 --- a/xfel/merging/application/errors/error_modifier_mm24.py +++ b/xfel/merging/application/errors/error_modifier_mm24.py @@ -49,14 +49,14 @@ def modify_errors(self, reflections): self.calculate_intensity_bin_limits() # Once bin limits are determined, assign intensities on each rank to appropriate bin limits self.distribute_differences_over_intensity_bins() - self.initialize_ev11_params() + self.initialize_mm24_params() # Run LBFGSB minimizer # -- only rank0 does minimization but gradients/functionals are calculated using all rank self.run_minimizer() if self.params.merging.error.mm24.do_diagnostics: self.plot_diagnostics(reflections) # Finally update the variances of each reflection as per Eq (10) in Brewster et. al (2019) - reflections['intensity.sum.variance'] = self._get_var_ev11( + reflections['intensity.sum.variance'] = self._get_var_mm24( reflections['intensity.sum.variance'], reflections['biased_mean'], reflections[self.cc_key] @@ -65,6 +65,9 @@ def modify_errors(self, reflections): return reflections def setup_work_arrays(self, reflections): + def pairing(k1, k2): + return int((k1 + k2) * (k1 + k2 + 1) / 2 + k2) + self.work_table = flex.reflection_table() self.refl_biased_means = [] biased_mean = flex.double() # Go with the pairwise differences in self.work_table @@ -98,7 +101,11 @@ def setup_work_arrays(self, reflections): if N > self.params.merging.error.mm24.n_max_differences: # random number generation needs to be consistent between symmetry related reflections # for reproducibility - rng = np.random.default_rng(seed=self.params.merging.error.mm24.random_seed) + hkl = refls[0]['miller_index_asymmetric'] + # Convert hkl to a hash with Cantor's pairing function. + # Add 1000 to keep inputs positive. + hkl_hash = pairing(pairing(hkl[0]+1000, hkl[1]+1000), hkl[2]+1000) + rng = np.random.default_rng(seed=hkl_hash + self.params.merging.error.mm24.random_seed) # Reflections are in different order when run with different numbers of ranks sort_indices = np.argsort(I) rng.shuffle(sort_indices) @@ -188,7 +195,7 @@ def distribute_differences_over_intensity_bins(self): % (number_of_differences_distributed, count) ) - def initialize_ev11_params(self): + def initialize_mm24_params(self): mean_differences = np.zeros(self.number_of_intensity_bins) for bin_index, differences in enumerate(self.intensity_bins): summation = self.mpi_helper.comm.reduce( @@ -198,18 +205,21 @@ def initialize_ev11_params(self): len(differences['pairwise_differences']), op=self.mpi_helper.MPI.SUM, root=0 ) if self.mpi_helper.rank == 0: - mean_differences[bin_index] = summation / counts + if counts > 0: + mean_differences[bin_index] = summation / counts + else: + mean_differences[bin_index] = np.nan if self.mpi_helper.rank == 0: - def fitting_equation(params, y0, return_jac): + def fitting_equation(params, bin_centers, mean_differences_0, return_jac): sf = params[0] sadd = params[1] prefactor = 2 / np.sqrt(np.pi) - arg = sf**2 * (x + sadd**2 * x**2) - curve = prefactor * np.sqrt(arg) + y0 + arg = sf**2 * (bin_centers + sadd**2 * bin_centers**2) + curve = prefactor * np.sqrt(arg) + mean_differences_0 if return_jac: - darg_dsf = 2 * sf * (x + sadd**2 * x**2) - darg_dsadd = 2 * sf**2 * sadd * x**2 + darg_dsf = 2 * sf * (bin_centers + sadd**2 * bin_centers**2) + darg_dsadd = 2 * sf**2 * sadd * bin_centers**2 dcurve_darg = 1/2 * prefactor/np.sqrt(arg) dcurve_dsf = dcurve_darg * darg_dsf dcurve_dsadd = dcurve_darg * darg_dsadd @@ -217,60 +227,61 @@ def fitting_equation(params, y0, return_jac): else: return curve - def target_fun_bfgs(params, x, y): - curve, dcurve_dsf, dcurve_dsadd = fitting_equation(params, y[0], True) - arg = (curve - y) / y - darg_dcurve = 1 / y + def target_fun_bfgs(params, bin_centers, mean_differences): + curve, dcurve_dsf, dcurve_dsadd = fitting_equation(params, bin_centers, mean_differences[0], True) + arg = (curve - mean_differences) / mean_differences + darg_dcurve = 1 / mean_differences loss = 0.5 * np.sum(arg**2) dloss_dsf = np.sum(arg * darg_dcurve * dcurve_dsf) dloss_dsadd = np.sum(arg * darg_dcurve * dcurve_dsadd) return loss, (dloss_dsf, dloss_dsadd) - def target_fun_scalar(sadd, x, y): - curve = fitting_equation([self.expected_sf, sadd], y[0], False) - arg = (curve - y) / y - darg_dcurve = 1 / y + def target_fun_scalar(sadd, bin_centers, mean_differences): + curve = fitting_equation([self.expected_sf, sadd], bin_centers, mean_differences[0], False) + arg = (curve - mean_differences) / mean_differences + darg_dcurve = 1 / mean_differences loss = 0.5 * np.sum(arg**2) return loss bin_centers = (self.intensity_bin_limits[1:] + self.intensity_bin_limits[:-1]) / 2 + good_indices = np.invert(np.isnan(mean_differences)) + bin_centers = bin_centers[good_indices] + mean_differences = mean_differences[good_indices] + positive_indices = bin_centers > 0 - x = bin_centers[positive_indices] - y = mean_differences[positive_indices] - good_indices = np.invert(np.isnan(y)) - x = x[good_indices] - y = y[good_indices] + bin_centers = bin_centers[positive_indices] + mean_differences = mean_differences[positive_indices] self.sadd = [0 for i in range(self.n_coefs)] if self.expected_sf is None: results = scipy.optimize.minimize( target_fun_bfgs, x0=(1, 1), - args=(x, y), + args=(bin_centers, mean_differences), jac=True, method='BFGS' ) self.sfac = abs(float(results.x[0])) self.sadd[0] = abs(float(results.x[1])) - fit_curve = fitting_equation(results.x, y[0], False) + fit_curve = fitting_equation(results.x, bin_centers, mean_differences[0], False) else: results = scipy.optimize.minimize_scalar( target_fun_scalar, bounds=(0, 10), - args=(x, y), + args=(bin_centers, mean_differences), ) self.sfac = self.expected_sf self.sadd[0] = abs(float(results.x)) if self.params.merging.error.mm24.do_diagnostics: import matplotlib.pyplot as plt - fit_curve = fitting_equation([self.sfac, self.sadd[0]], y[0], False) + fit_curve = fitting_equation([self.sfac, self.sadd[0]], bin_centers, mean_differences[0], False) fig, axes = plt.subplots(1, 1, figsize=(5, 3)) axes.plot( bin_centers, mean_differences, linestyle='none', marker='.', color=[0, 0, 0], label='Data' ) - axes.plot(x, fit_curve, color=[0, 0.8, 0], label='Initialization') + axes.plot(bin_centers, fit_curve, color=[0, 0.8, 0], label='Initialization') axes.legend() fig.tight_layout() fig.savefig(os.path.join( @@ -361,7 +372,7 @@ def run_minimizer(self): tuning_param = f'{self.tuning_param:0.3f}' sfac = f'{self.sfac:0.3f}' sadd = [f'{self.sadd[i]:0.3f}' for i in range(self.n_coefs)] - log_out = 'FINAL EV11 VALUES = '\ + log_out = 'FINAL mm24 VALUES = '\ + f'loss: {self.L:.2f} '\ + f'sfac: {sfac} '\ + f'sadd: {sadd} ' @@ -453,7 +464,7 @@ def verify_derivatives(self): + f'analytical {der_wrt_sadd[degree_index]}' ) - def _loss_function_gaus(self, differences, var_i, var_j): + def _loss_function_normal(self, differences, var_i, var_j): var = var_i + var_j z = differences / flex.sqrt(var) dz_dvar = -differences / (2 * var**(3/2)) @@ -482,7 +493,7 @@ def _loss_function_t(self, differences, var_i, var_j): dL_dvar_x = dL1_dvar + dL2_dvar return L, dL_dvar_x - def _loss_function_t_opt(self, differences, var_i, var_j): + def _loss_function_t_v_opt(self, differences, var_i, var_j): v = self.tuning_param var = var_i + var_j z = differences / flex.sqrt(var) @@ -523,7 +534,7 @@ def _get_sadd(self, correlation): dsadd_dsaddi[degree_index] = correlation**degree_index return sadd, dsadd_dsaddi - def _get_var_ev11(self, counting_err, biased_mean, correlation, return_der=False): + def _get_var_mm24(self, counting_err, biased_mean, correlation, return_der=False): sadd, dsadd_dsaddi = self._get_sadd(correlation) var = self.sfac**2 * (counting_err + sadd**2 * biased_mean**2) if return_der: @@ -544,13 +555,13 @@ def calculate_functional(self): for bin_index, differences in enumerate(self.intensity_bins): if len(differences) > 0: - var_i, dvar_i_dsfac, dvar_i_dsadd, dsadd_i_dsaddi = self._get_var_ev11( + var_i, dvar_i_dsfac, dvar_i_dsadd, dsadd_i_dsaddi = self._get_var_mm24( differences['counting_stats_var_i'], differences['biased_mean'], differences['correlation_i'], return_der=True ) - var_j, dvar_j_dsfac, dvar_j_dsadd, dsadd_j_dsaddi = self._get_var_ev11( + var_j, dvar_j_dsfac, dvar_j_dsadd, dsadd_j_dsaddi = self._get_var_mm24( differences['counting_stats_var_j'], differences['biased_mean'], differences['correlation_j'], @@ -558,12 +569,12 @@ def calculate_functional(self): ) if self.params.merging.error.mm24.likelihood == 'normal': - L_in_bin, dL_dvar_x = self._loss_function_gaus( + L_in_bin, dL_dvar_x = self._loss_function_normal( differences['pairwise_differences'], var_i, var_j ) elif self.params.merging.error.mm24.likelihood == 't-dist': if self.params.merging.error.mm24.tuning_param_opt: - L_in_bin, dL_dvar_x, dL_dnu = self._loss_function_t_opt( + L_in_bin, dL_dvar_x, dL_dnu = self._loss_function_t_v_opt( differences['pairwise_differences'], var_i, var_j ) dL_dnu_bin_rank[bin_index] = flex.sum(dL_dnu) @@ -571,6 +582,7 @@ def calculate_functional(self): L_in_bin, dL_dvar_x = self._loss_function_t( differences['pairwise_differences'], var_i, var_j ) + L_bin_rank[bin_index] = flex.sum(L_in_bin) dL_dsfac_bin_rank[bin_index] = flex.sum(dL_dvar_x * (dvar_i_dsfac + dvar_j_dsfac)) for degree_index in range(self.n_coefs): @@ -596,6 +608,7 @@ def calculate_functional(self): self.dL_dnu = flex.sum(self.bin_weighting * dL_dnu_bin) def plot_diagnostics(self, reflections): + I_scale = 100000 def get_rankits(n, down_sample, distribution): prob_level = (np.arange(1, n+1) - 0.5) / n if distribution == 'half normal': @@ -620,7 +633,7 @@ def min_fun_t(c, df): if self.mpi_helper.rank == 0: if self.params.merging.error.mm24.likelihood == 'normal': conversion_factor = 1.1926 - elif self.params.merging.error.mm24.likelihood == 't-dist': + elif self.params.merging.error.mm24.likelihood in ['t-dist']: results = scipy.optimize.minimize_scalar( min_fun_t, bounds=(0.1, 2), @@ -630,6 +643,27 @@ def min_fun_t(c, df): else: conversion_factor = None conversion_factor = self.mpi_helper.comm.bcast(conversion_factor) + + # Setup for the ENCE calculation + variance = self._get_var_mm24( + reflections['intensity.sum.variance'], + reflections['biased_mean'], + reflections[self.cc_key] + ).as_numpy_array() + variance.sort() + lower = self.mpi_helper.comm.gather(variance[int(0.005 * variance.size)]) + upper = self.mpi_helper.comm.gather(variance[int(0.995 * variance.size)]) + n_ENCE_bins = 25 + if self.mpi_helper.rank == 0: + ENCE_bins = np.linspace(np.sqrt(10*np.median(lower)), np.sqrt(np.median(upper)), n_ENCE_bins + 1) + else: + ENCE_bins = np.empty(n_ENCE_bins + 1) + self.mpi_helper.comm.Bcast(ENCE_bins, root=0) + ENCE_centers = (ENCE_bins[1:] + ENCE_bins[:-1]) / 2 + ENCE_counts_rank = np.zeros(n_ENCE_bins, dtype=int) + ENCE_sum_V_rank = np.zeros(n_ENCE_bins) + ENCE_sum_D_rank = np.zeros(n_ENCE_bins) + median_differences = [[] for i in range(self.number_of_intensity_bins)] for refls in reflection_table_utils.get_next_hkl_reflection_table(reflections): number_of_reflections = refls.size() @@ -640,19 +674,57 @@ def min_fun_t(c, df): bin_index = np.searchsorted(self.intensity_bin_limits, biased_mean) - 1 if biased_mean > self.intensity_bin_limits[0] and biased_mean < self.intensity_bin_limits[-1]: I = refls['intensity.sum.value'].as_numpy_array() - var_ev11_flex = self._get_var_ev11( + var_mm24 = self._get_var_mm24( refls['intensity.sum.variance'], flex.double(len(refls), biased_mean), refls[self.cc_key] - ) - var_ev11 = var_ev11_flex.as_numpy_array() + ).as_numpy_array() # calculate the median difference for the pairwise differences differences = np.abs(I[np.newaxis] - I[:, np.newaxis]) - variances = var_ev11[np.newaxis] + var_ev11[:, np.newaxis] + variances = var_mm24[np.newaxis] + var_mm24[:, np.newaxis] median_differences[bin_index].append( np.median(differences / np.sqrt(variances), axis=1) ) + # Calculations for ENCE + triu_indices = np.triu_indices(n=I.size, k=1) + differences = differences[triu_indices[0], triu_indices[1]] + variances = variances[triu_indices[0], triu_indices[1]] + bin_indices = np.searchsorted(ENCE_bins, np.sqrt(variances)) + in_range = np.logical_and(bin_indices >= 0, bin_indices < n_ENCE_bins) + ENCE_counts_rank[bin_indices[in_range]] += 1 + ENCE_sum_V_rank[bin_indices[in_range]] += variances[in_range] + ENCE_sum_D_rank[bin_indices[in_range]] += differences[in_range]**2 + ENCE_counts = np.empty(n_ENCE_bins, dtype=int) + ENCE_sum_V = np.empty(n_ENCE_bins) + ENCE_sum_D = np.empty(n_ENCE_bins) + self.mpi_helper.comm.Reduce(ENCE_counts_rank, ENCE_counts, op=self.mpi_helper.MPI.SUM, root=0) + self.mpi_helper.comm.Reduce(ENCE_sum_V_rank, ENCE_sum_V, op=self.mpi_helper.MPI.SUM, root=0) + self.mpi_helper.comm.Reduce(ENCE_sum_D_rank, ENCE_sum_D, op=self.mpi_helper.MPI.SUM, root=0) + + # Reliability plot and ENCE + if self.mpi_helper.rank == 0: + import matplotlib.pyplot as plt + ENCE_RMV = np.sqrt(ENCE_sum_V / ENCE_counts) / I_scale + ENCE_RMD = np.sqrt(ENCE_sum_D / ENCE_counts) / I_scale + ENCE = np.abs(ENCE_RMV - ENCE_RMD) / ENCE_RMV + good_bins = ENCE_counts > 0 + fig, axes = plt.subplots(2, 1, figsize=(3, 4), sharex=True) + lims = [ENCE_RMV[good_bins].min(), ENCE_RMV[good_bins].max()] + axes[0].plot(lims, lims, color=[0, 0, 0]) + axes[0].plot(ENCE_RMV[good_bins], ENCE_RMD[good_bins]) + axes[1].plot(ENCE_RMV[good_bins], ENCE[good_bins]) + axes[0].set_title(f'ENCE: {ENCE.mean():0.03f}') + axes[0].set_ylabel('Root mean difference\n(x 100,000)') + axes[1].set_ylabel('ENCE') + axes[1].set_xlabel('Root mean variance\n(x 100,000)') + fig.tight_layout() + fig.savefig(os.path.join( + self.params.output.output_dir, + self.params.output.prefix + '_ENCE.png' + )) + plt.close() + binned_scale = np.zeros(self.number_of_intensity_bins) for bin_index in range(self.number_of_intensity_bins): if len(median_differences[bin_index]) > 0: @@ -667,13 +739,13 @@ def min_fun_t(c, df): pairwise_differences = [] for bin_index, differences in enumerate(self.intensity_bins): if len(differences) > 0: - var_i = self._get_var_ev11( + var_i = self._get_var_mm24( differences['counting_stats_var_i'], differences['biased_mean'], differences['correlation_i'], return_der=False ) - var_j = self._get_var_ev11( + var_j = self._get_var_mm24( differences['counting_stats_var_j'], differences['biased_mean'], differences['correlation_j'], @@ -686,11 +758,9 @@ def min_fun_t(c, df): ) if self.mpi_helper.rank == 0: - import matplotlib.pyplot as plt sorted_pairwise_differences = np.sort(all_pairwise_differences) lim = 5 downsample = 10000 - I_scale = 100000 grey1 = np.array([99, 102, 106]) / 255 grey2 = np.array([177, 179, 179]) / 255 @@ -711,7 +781,7 @@ def min_fun_t(c, df): scipy.stats.halfnorm.pdf(pairwise_differences_centers), color=grey1, label='Normal' ) - if self.params.merging.error.mm24.likelihood == 't-dist': + if self.params.merging.error.mm24.likelihood in ['t-dist']: axes[0].plot( pairwise_differences_centers, 2*scipy.stats.t.pdf(pairwise_differences_centers, df=self.tuning_param), @@ -730,7 +800,7 @@ def min_fun_t(c, df): get_rankits(sorted_pairwise_differences.size, downsample, 'half normal'), color=grey1 ) - if self.params.merging.error.mm24.likelihood == 't-dist': + if self.params.merging.error.mm24.likelihood in ['t-dist']: axes[1].plot( sorted_pairwise_differences[::downsample], get_rankits(sorted_pairwise_differences.size, downsample, 'half t-dist'), @@ -748,7 +818,7 @@ def min_fun_t(c, df): intensity_centers = (self.intensity_bin_limits[1:] + self.intensity_bin_limits[:-1]) / 2 x = intensity_centers / I_scale - if self.params.merging.error.mm24.likelihood == 't-dist': + if self.params.merging.error.mm24.likelihood in ['t-dist']: v = self.tuning_param term0 = v / (v - 2) term1 = 4*v / (np.pi * (v - 1)**2) From c66f91c5516a46485a34cf655479574502a3485c Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 19 Mar 2024 12:32:23 -0700 Subject: [PATCH 239/748] Clean clutter --- mmtbx/geometry_restraints/geo_file_parsing.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mmtbx/geometry_restraints/geo_file_parsing.py b/mmtbx/geometry_restraints/geo_file_parsing.py index 25dfd2a9ed..eb451a5065 100644 --- a/mmtbx/geometry_restraints/geo_file_parsing.py +++ b/mmtbx/geometry_restraints/geo_file_parsing.py @@ -1,7 +1,6 @@ from __future__ import division, print_function import re import json -from collections import defaultdict import pandas as pd import numpy as np @@ -349,4 +348,4 @@ def add_i_seq_columns_from_id_str(restraint_dfs,model): i_seq_cols = [col.replace("id_str","i_seq") for col in id_str_cols] for i_seq_col,id_str_col in zip(i_seq_cols,id_str_cols): df[i_seq_col] = df[id_str_col].map(mapping_dict) - return restraint_dfs \ No newline at end of file + return restraint_dfs From 0b1ba83352244dd4cdd41a8fc2a1b31430b20162 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Tue, 19 Mar 2024 12:44:43 -0700 Subject: [PATCH 240/748] libtbx: update test for updated parameters --- libtbx/phil/tst_interface.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libtbx/phil/tst_interface.py b/libtbx/phil/tst_interface.py index 3f2598ab50..542e38988a 100644 --- a/libtbx/phil/tst_interface.py +++ b/libtbx/phil/tst_interface.py @@ -263,8 +263,8 @@ def exercise_2(verbose=False): ) expected_result = [ - ('protein.pdb', 'Input model', 'refinement.gui.migration.refinement.input.pdb.file_name'), - ('ligand.pdb', 'Input model', 'refinement.gui.migration.refinement.input.pdb.file_name'), + ('protein.pdb', 'Input model (X-ray)', 'refinement.gui.migration.refinement.input.pdb.file_name'), + ('ligand.pdb', 'Input model (X-ray)', 'refinement.gui.migration.refinement.input.pdb.file_name'), ('ligand.cif', 'Restraints (CIF)', 'refinement.gui.migration.refinement.input.monomers.file_name')] for f in i.get_input_files(): assert f in expected_result @@ -289,13 +289,15 @@ def exercise_2(verbose=False): assert (style.get_parent_params() == {"file_name" : "file_name"}) file_map = i.get_file_type_map("pdb") expected_result = ['refinement.gui.migration.refinement.input.pdb.file_name', + 'refinement.gui.migration.refinement.input.pdb.electron_file_name', + 'refinement.gui.migration.refinement.input.pdb.neutron_file_name', 'refinement.reference_model.file'] for p in file_map.get_multiple_params(): assert p in expected_result, (p, expected_result) assert len(file_map.get_multiple_params()) == len(expected_result) assert (file_map.get_default_param() == "refinement.gui.migration.refinement.input.pdb.file_name") file_map = i.get_file_type_map("hkl") - assert (file_map.get_overall_max_count() == 5) + assert (file_map.get_overall_max_count() == 7) assert (len(file_map.get_multiple_params()) == 0) assert (file_map.get_max_count("refinement.gui.migration.refinement.input.xray_data.file_name") == 1) menu = i.get_menu_db() From 16877175328bc90cadd2afe2202d7bd7967fca37 Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 19 Mar 2024 14:10:17 -0700 Subject: [PATCH 241/748] Fix test failure --- mmtbx/geometry_restraints/tst_geo_file_parsing.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mmtbx/geometry_restraints/tst_geo_file_parsing.py b/mmtbx/geometry_restraints/tst_geo_file_parsing.py index 432db86b46..0fdc7ce9a1 100644 --- a/mmtbx/geometry_restraints/tst_geo_file_parsing.py +++ b/mmtbx/geometry_restraints/tst_geo_file_parsing.py @@ -1,6 +1,6 @@ from __future__ import division, print_function import json - +import pandas as pd from geo_file_parsing import parse_geo_file @@ -751,6 +751,8 @@ # define comparison functions def get_type(value): + if pd.isna(value): + return None try: f = float(value) if f.is_integer(): @@ -773,6 +775,12 @@ def compare_custom(d1,d2): #print(value1,value2) t1,t2 = get_type(value1), get_type(value2) assert t1==t2, '%s!=%s' % (t1, t2) + + # get all none-like values to be None + if t1 is None: + value1 = None + if t2 is None: + value2 = None assert str(value1)==str(value2), "Invalid comparisons: "+str(value1)+" and "+str(value2) return True From 8021f8f6ae677378a533a12f09bdeece8ecd9c32 Mon Sep 17 00:00:00 2001 From: cschlick Date: Tue, 19 Mar 2024 14:33:21 -0700 Subject: [PATCH 242/748] Switch relative to absolute import --- mmtbx/geometry_restraints/tst_geo_file_parsing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/geometry_restraints/tst_geo_file_parsing.py b/mmtbx/geometry_restraints/tst_geo_file_parsing.py index 0fdc7ce9a1..7a7e53712d 100644 --- a/mmtbx/geometry_restraints/tst_geo_file_parsing.py +++ b/mmtbx/geometry_restraints/tst_geo_file_parsing.py @@ -1,7 +1,7 @@ from __future__ import division, print_function import json import pandas as pd -from geo_file_parsing import parse_geo_file +from mmtbx.geometry_restraints.geo_file_parsing import parse_geo_file """ From e124b829914bfaedb2783e07fc5b7eff1aae3713 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 19 Mar 2024 18:14:33 -0600 Subject: [PATCH 243/748] Add test for restore_true_except_at_ends --- mmtbx/regression/tst_process_predicted_model.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mmtbx/regression/tst_process_predicted_model.py b/mmtbx/regression/tst_process_predicted_model.py index daed85a11b..4f4f554c9b 100644 --- a/mmtbx/regression/tst_process_predicted_model.py +++ b/mmtbx/regression/tst_process_predicted_model.py @@ -284,10 +284,19 @@ def tst_02(log = sys.stdout): print("Segments found: %s" %(" ".join(chainid_list)), file = log) assert len(chainid_list) == 2 +def tst_03(): + from mmtbx.process_predicted_model import restore_true_except_at_ends + from scitbx.array_family import flex + a = flex.bool((0,0,0,1,0,1,1,0,0,0,1,1,1,0,0)) + restore_true_except_at_ends(a) + print(list(a)) + assert list(a) == [False, False, False, True, True, True, True, True, True, True, True, True, True, False, False] + if __name__ == "__main__": t0 = time.time() tst_01() tst_02() + tst_03() print ("Time:", time.time()-t0) print ("OK") From e798a34e024a1bcba20dde2b264432a817699051 Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 20 Mar 2024 09:37:56 -0600 Subject: [PATCH 244/748] Modify comments --- mmtbx/process_predicted_model.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mmtbx/process_predicted_model.py b/mmtbx/process_predicted_model.py index d19d3b1e11..046fda8447 100644 --- a/mmtbx/process_predicted_model.py +++ b/mmtbx/process_predicted_model.py @@ -269,7 +269,9 @@ def process_predicted_model( If None, set to True if all plddt are from 0 to 1 remove_low_confidence_residues: remove residues with low confidence (plddt or rmsd as set below) - continuous_chain: if removing low-confidence residues, trim ends only + continuous_chain: if removing low-confidence residues, trim ends only. Note + that if this is set, only the pae_matrix method of finding domains + will work; the standard method will give a single domain. minimum_plddt: minimum plddt to keep residues (on same scale as b_value_field, if not set, calculated from maximum_rmsd). maximum_rmsd: alternative specification of minimum confidence based on rmsd. From 86c3e4d0b029c7c954cd97cb6c9a371b61aadc5b Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Wed, 20 Mar 2024 11:41:35 -0700 Subject: [PATCH 245/748] Add Gatherv as part of the libtbx.mpi4py simulation --- libtbx/mpi4py.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libtbx/mpi4py.py b/libtbx/mpi4py.py index fea17ab51a..b1189dfacf 100644 --- a/libtbx/mpi4py.py +++ b/libtbx/mpi4py.py @@ -41,6 +41,12 @@ def gather(self, sendobj, root=0): items = [] items.append(sendobj) return items + def Gatherv(self, sendbuf, recvbuf, root=0): + counter = 0 + for i, item in enumerate(sendbuf): + n = len(item) + recvbuf[counter:counter+n] = item + counter += n def Abort(self,errorcode=0): import sys sys.exit() From 54eb0ef47fefb3b8468245fcd1b7e37622d271fb Mon Sep 17 00:00:00 2001 From: David Moreau Date: Thu, 21 Mar 2024 10:51:17 -0700 Subject: [PATCH 246/748] Always retain the correlation coefficient for MM24 error model. (#976) --- .../postrefine/postrefinement_rs.py | 26 +++++++++---------- .../postrefine/postrefinement_rs2.py | 26 +++++++++---------- .../application/scale/experiment_scaler.py | 3 +-- xfel/merging/command_line/merge.py | 12 +++------ 4 files changed, 29 insertions(+), 38 deletions(-) diff --git a/xfel/merging/application/postrefine/postrefinement_rs.py b/xfel/merging/application/postrefine/postrefinement_rs.py index a5b2004614..59aec9bca7 100644 --- a/xfel/merging/application/postrefine/postrefinement_rs.py +++ b/xfel/merging/application/postrefine/postrefinement_rs.py @@ -175,17 +175,17 @@ def run(self, experiments, reflections): assert result_matches.pairs().size() == result_observations_original_index.size() # Calculate the correlation of each frame after corrections. # This is used in the MM24 error model to determine a per frame level of error - if "correlation_after_post" in self.params.input.persistent_refl_cols: - I_observed = result_observations.data() - matches = miller.match_multi_indices( - miller_indices_unique = miller_set.indices(), - miller_indices = result_observations.indices() - ) - I_reference = flex.double([i_model.data()[pair[0]] for pair in matches.pairs()]) - I_invalid = flex.bool([i_model.sigmas()[pair[0]] < 0. for pair in matches.pairs()]) - I_weight = flex.double(len(result_observations.sigmas()), 1.) - I_weight.set_selected(I_invalid, 0.) - SWC_after_post = simple_weighted_correlation(I_weight, I_reference, I_observed) + # These are the added to the reflection table + I_observed = result_observations.data() + matches = miller.match_multi_indices( + miller_indices_unique = miller_set.indices(), + miller_indices = result_observations.indices() + ) + I_reference = flex.double([i_model.data()[pair[0]] for pair in matches.pairs()]) + I_invalid = flex.bool([i_model.sigmas()[pair[0]] < 0. for pair in matches.pairs()]) + I_weight = flex.double(len(result_observations.sigmas()), 1.) + I_weight.set_selected(I_invalid, 0.) + SWC_after_post = simple_weighted_correlation(I_weight, I_reference, I_observed) except (AssertionError, ValueError, RuntimeError) as e: error_detected = True reason = repr(e) @@ -218,9 +218,7 @@ def run(self, experiments, reflections): for key in self.params.input.persistent_refl_cols: if not key in new_exp_reflections.keys() and key in exp_reflections_match_results.keys(): new_exp_reflections[key] = exp_reflections_match_results[key] - if self.params.merging.error.model == 'mm24': - if "correlation_after_post" in self.params.input.persistent_refl_cols: - new_exp_reflections["correlation_after_post"] = flex.double(len(new_exp_reflections), SWC_after_post.corr) + new_exp_reflections["correlation_after_post"] = flex.double(len(new_exp_reflections), SWC_after_post.corr) new_reflections.extend(new_exp_reflections) # report rejected experiments, reflections diff --git a/xfel/merging/application/postrefine/postrefinement_rs2.py b/xfel/merging/application/postrefine/postrefinement_rs2.py index 5194ad387f..e431d413b8 100644 --- a/xfel/merging/application/postrefine/postrefinement_rs2.py +++ b/xfel/merging/application/postrefine/postrefinement_rs2.py @@ -176,17 +176,17 @@ def run(self, experiments, reflections): assert result_matches.pairs().size() == result_observations_original_index.size() # Calculate the correlation of each frame after corrections. # This is used in the MM24 error model to determine a per frame level of error - if "correlation_after_post" in self.params.input.persistent_refl_cols: - I_observed = result_observations.data() - matches = miller.match_multi_indices( - miller_indices_unique = miller_set.indices(), - miller_indices = result_observations.indices() - ) - I_reference = flex.double([i_model.data()[pair[0]] for pair in matches.pairs()]) - I_invalid = flex.bool([i_model.sigmas()[pair[0]] < 0. for pair in matches.pairs()]) - I_weight = flex.double(len(result_observations.sigmas()), 1.) - I_weight.set_selected(I_invalid, 0.) - SWC_after_post = simple_weighted_correlation(I_weight, I_reference, I_observed) + # These are the added to the reflection table + I_observed = result_observations.data() + matches = miller.match_multi_indices( + miller_indices_unique = miller_set.indices(), + miller_indices = result_observations.indices() + ) + I_reference = flex.double([i_model.data()[pair[0]] for pair in matches.pairs()]) + I_invalid = flex.bool([i_model.sigmas()[pair[0]] < 0. for pair in matches.pairs()]) + I_weight = flex.double(len(result_observations.sigmas()), 1.) + I_weight.set_selected(I_invalid, 0.) + SWC_after_post = simple_weighted_correlation(I_weight, I_reference, I_observed) except (AssertionError, ValueError, RuntimeError) as e: error_detected = True reason = repr(e) @@ -219,9 +219,7 @@ def run(self, experiments, reflections): for key in self.params.input.persistent_refl_cols: if key not in new_exp_reflections.keys(): new_exp_reflections[key] = exp_reflections_match_results[key] - if self.params.merging.error.model == 'mm24': - if "correlation_after_post" in self.params.input.persistent_refl_cols: - new_exp_reflections["correlation_after_post"] = flex.double(len(new_exp_reflections), SWC_after_post.corr) + new_exp_reflections["correlation_after_post"] = flex.double(len(new_exp_reflections), SWC_after_post.corr) new_reflections.extend(new_exp_reflections) # report rejected experiments, reflections diff --git a/xfel/merging/application/scale/experiment_scaler.py b/xfel/merging/application/scale/experiment_scaler.py index 8976d72557..0be2c6998e 100644 --- a/xfel/merging/application/scale/experiment_scaler.py +++ b/xfel/merging/application/scale/experiment_scaler.py @@ -91,8 +91,7 @@ def run(self, experiments, reflections): ): exp_reflections['intensity.sum.value'] *= result.slope exp_reflections['intensity.sum.variance'] *= (result.slope**2) - if self.params.merging.error.model == 'mm24': - exp_reflections['correlation'] = flex.double(len(exp_reflections), result.correlation) + exp_reflections['correlation'] = flex.double(len(exp_reflections), result.correlation) new_experiments.append(experiment) new_reflections.extend(exp_reflections) diff --git a/xfel/merging/command_line/merge.py b/xfel/merging/command_line/merge.py index c763fd2263..5aea100ddb 100644 --- a/xfel/merging/command_line/merge.py +++ b/xfel/merging/command_line/merge.py @@ -217,14 +217,10 @@ def _resolve_persistent_columns(self): for key in keysCreatedByMerge: if key not in self.params.input.persistent_refl_cols: self.params.input.persistent_refl_cols.append(key) - - if hasattr(self.params, 'merging') and self.params.merging.error.model == "mm24": - if self.params.merging.error.mm24.cc_after_pr: - if "correlation_after_post" not in self.params.input.persistent_refl_cols: - self.params.input.persistent_refl_cols.append("correlation_after_post") - else: - if "correlation" not in self.params.input.persistent_refl_cols: - self.params.input.persistent_refl_cols.append("correlation") + if "correlation_after_post" not in self.params.input.persistent_refl_cols: + self.params.input.persistent_refl_cols.append("correlation_after_post") + if "correlation" not in self.params.input.persistent_refl_cols: + self.params.input.persistent_refl_cols.append("correlation") if __name__ == '__main__': script = Script() From dc0331cc907ddec24a774ba3afdcc5418c13911f Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 21 Mar 2024 10:54:26 -0700 Subject: [PATCH 247/748] More output on crash. --- mmtbx/geometry_restraints/quantum_restraints_manager.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mmtbx/geometry_restraints/quantum_restraints_manager.py b/mmtbx/geometry_restraints/quantum_restraints_manager.py index a5d059ffd0..b060205e40 100644 --- a/mmtbx/geometry_restraints/quantum_restraints_manager.py +++ b/mmtbx/geometry_restraints/quantum_restraints_manager.py @@ -1078,8 +1078,11 @@ def is_ligand_going_to_be_same_size(qmr): times=[] energy_only=False if not model.restraints_manager_available(): - model.log=null_out() - model.process(make_restraints=True) + model.log=StringIO() + try: + model.process(make_restraints=True) + except Sorry as e: + raise e if quantum_interface.is_quantum_interface_active_this_macro_cycle(params, macro_cycle, energy_only=energy_only, From f22af8235bb205cc6118dcf8e09f752bd698e942 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 21 Mar 2024 11:03:56 -0700 Subject: [PATCH 248/748] Added two output format options --- mmtbx/nci/skew_kurt_plot.py | 70 +++++++++++++++++++++++++++++++++---- mmtbx/programs/hbond.py | 11 +++++- 2 files changed, 73 insertions(+), 8 deletions(-) diff --git a/mmtbx/nci/skew_kurt_plot.py b/mmtbx/nci/skew_kurt_plot.py index 2b2002727e..1fe62e7f26 100644 --- a/mmtbx/nci/skew_kurt_plot.py +++ b/mmtbx/nci/skew_kurt_plot.py @@ -8,6 +8,27 @@ from libtbx.utils import Sorry import os +from matplotlib.ticker import FormatStrFormatter + +import math + +def rotate(origin, point, angle): + """ + Rotate a point counterclockwise by a given angle around a given origin. + + The angle should be given in radians. + """ + ox, oy = origin + px, py = point + + qx = ox + math.cos(angle) * (px - ox) - math.sin(angle) * (py - oy) + qy = oy + math.sin(angle) * (px - ox) + math.cos(angle) * (py - oy) + return qx, qy + +def rotate_translate(origin, point, angle, translate): + x,y = rotate(origin, point, angle) + return x+translate[0], y+translate[1] + def get_filling_data(data, x_nbins, y_nbins, xmin, xmax, ymin, ymax, threshold=2, interpolation='linear'): grid = Grid2D.make_Grid2d(data, x_nbins=x_nbins, y_nbins=y_nbins, @@ -51,7 +72,10 @@ def make_figure( type='all', colorblind_friendly=True, override_palette = {}, - resolution=300): + resolution=300, + do_rotate=False, + do_y_log=False, + ): """ Plots skew-kurtosis plot and saves it to .png file Args: @@ -100,21 +124,43 @@ def make_figure( 'alpha': [-0.14, 0.14], 'beta': [-0.14, 0.14]} + aspect = 0.5 + xmin = -2 xmax = 2 ymin = 0 ymax = 7 + ta = 0.3 + tx = 1. + ty = 0.5 + if do_rotate: + xmin = -1.5 + xmax = 1.5 + if do_y_log: + ymin = 1 + aspect = 2.5 + data = [] for x, y in zip(db[type]['t1o'][0], db['all']['t1o'][1]): + if do_rotate: x,y = rotate_translate((0,0), (x,y), -ta, (-tx,-ty)) data.append([x,y]) for x, y in zip(db[type]['dhao'][0], db['all']['dhao'][1]): - data.append([x,y]) + if do_rotate: x,y = rotate_translate((0,0), (x,y), ta, (tx,-ty)) + data.append([x ,y]) blue_filling = get_filling_data(data, x_nbins=50, y_nbins=50, xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, threshold=1, interpolation='cubic') fig = plt.figure(figsize=(10,10),) ax = plt.subplot(111) + + if do_y_log: + ax.set_xscale('linear') + ax.set_yscale('log') + yax = ax.axes.get_yaxis() + yax.set_major_formatter(FormatStrFormatter('%d')) + yax.set_minor_formatter(FormatStrFormatter('%d')) + ax.set_xlim(xmin, xmax) ax.set_ylim(ymin, ymax) im = ax.imshow( @@ -122,7 +168,7 @@ def make_figure( origin="lower", cmap=plt.get_cmap(color_palette['colormap']), extent=[xmin, xmax, ymin, ymax], - aspect=0.5, + aspect=aspect, # interpolation='bicubic', # norm=norm, ) @@ -135,11 +181,21 @@ def make_figure( ) for theta1_c in theta1_coords: - ax.scatter([theta1_c[0]], [theta1_c[1]], s=dot_size, c=color_palette['theta_color'], edgecolor=color_palette['theta_contour']) + x,y = theta1_c[0], theta1_c[1] + if do_rotate: x,y = rotate_translate((0,0), (x,y), -ta, (-tx,-ty)) + ax.scatter([x], [y], s=dot_size, c=color_palette['theta_color'], edgecolor=color_palette['theta_contour']) for Rha_c in Rha_coords: - ax.scatter([Rha_c[0]], [Rha_c[1]], s=dot_size, c=color_palette['Rha_color'], edgecolor=color_palette['Rha_contour']) - ax.set_xlabel('Skew') - ax.set_ylabel('Kurtosis') + x,y = Rha_c[0], Rha_c[1] + if do_rotate: x,y = rotate_translate((0,0), (x,y), ta, (tx,-ty)) + ax.scatter([x], [y], s=dot_size, c=color_palette['Rha_color'], edgecolor=color_palette['Rha_contour']) + if do_rotate: + xax = ax.axes.get_xaxis() + xax = xax.set_visible(False) + yax = ax.axes.get_yaxis() + yax = yax.set_visible(False) + else: + ax.set_xlabel('Skew') + ax.set_ylabel('Kurtosis') fig.savefig("%s.png" % file_name, dpi=resolution) if __name__ == '__main__': diff --git a/mmtbx/programs/hbond.py b/mmtbx/programs/hbond.py index bbe7592182..5e70c2ea8c 100644 --- a/mmtbx/programs/hbond.py +++ b/mmtbx/programs/hbond.py @@ -28,6 +28,12 @@ class Program(ProgramTemplate): plot_colorblind_friendly = True .type = bool .short_caption = Use colorblind friendly palette for skew-kurtosis plot + do_rotate_translate = False + .type = bool + .style = hidden + do_y_log = False + .type = bool + .style = hidden plot_parameters_override .help = These parameters will override preset values in plots. The values \ will be passed directly to matplotlib functions, so should be valid \ @@ -125,7 +131,10 @@ def run(self): dot_size = self.params.hbond.dot_size, type='all', override_palette = op, - colorblind_friendly=self.params.plot_colorblind_friendly) + colorblind_friendly=self.params.plot_colorblind_friendly, + do_rotate=self.params.do_rotate_translate, + do_y_log=self.params.do_y_log, + ) self._print("\nOutputted plot as %s.png" % fn) # --------------------------------------------------------------------------- From cdf36342f69430d3a9999948c3358eef2b4c1db8 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 21 Mar 2024 11:28:09 -0700 Subject: [PATCH 249/748] added option to add H/D to water --- mmtbx/programs/hydrogenate.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mmtbx/programs/hydrogenate.py b/mmtbx/programs/hydrogenate.py index 27699ca68e..d60df48116 100644 --- a/mmtbx/programs/hydrogenate.py +++ b/mmtbx/programs/hydrogenate.py @@ -19,6 +19,12 @@ .type = choice(multi=False) .help = Mode for placing H3 at terminal nitrogen. +add_h_to_water = False + .type = bool + +add_d_to_water = False + .type = bool + output .style = menu_item auto_align { @@ -72,6 +78,11 @@ def run(self): make_sub_header('Optimize H atoms', out=self.logger) self.model = reduce_hydrogen.optimize(model=self.model) # + if self.params.add_h_to_water: + self.model.add_hydrogens(1., occupancy=1.) + elif self.params.add_d_to_water: + self.model.add_hydrogens(1., element="D", occupancy=1.) + # if(self.params.output.file_name_prefix is not None): base = self.params.output.file_name_prefix else: From fcc6b3b5d0bf0dfa7cbf76b89af96ba0d5c1a6c7 Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Thu, 21 Mar 2024 16:30:47 -0700 Subject: [PATCH 250/748] More libtbx.mpi4py fixes - Add stubs for Barrier and Bcast - Fixed implementation of Gatherv --- libtbx/mpi4py.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/libtbx/mpi4py.py b/libtbx/mpi4py.py index b1189dfacf..1e13c57a84 100644 --- a/libtbx/mpi4py.py +++ b/libtbx/mpi4py.py @@ -23,8 +23,12 @@ def Get_size(self): return 1 def barrier(self): pass + def Barrier(self): + pass def bcast(self, obj, root=0): return obj + def Bcast(self, buf, root=0): + pass def reduce(self, sendobj, op=mpiEmulator.SUM, root=0): if op == mpiEmulator.SUM or op == mpiEmulator.MAX or op == mpiEmulator.MIN: return sendobj @@ -42,11 +46,14 @@ def gather(self, sendobj, root=0): items.append(sendobj) return items def Gatherv(self, sendbuf, recvbuf, root=0): + assert len(recvbuf) == 2, "Other ways of using Gatherv are not implemented" + rbuff, counts = recvbuf + if len(counts) == 1: + sendbuf = (sendbuf,) counter = 0 - for i, item in enumerate(sendbuf): - n = len(item) - recvbuf[counter:counter+n] = item - counter += n + for item, count in zip(sendbuf, counts): + rbuff[counter:counter+count] = item + counter += count def Abort(self,errorcode=0): import sys sys.exit() From 1089c8f6bdd33a6478338876e832153776105fbe Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Mon, 25 Mar 2024 14:34:46 -0700 Subject: [PATCH 251/748] special check for conflicting N-H2 --- mmtbx/hydrogens/reduce_hydrogen.py | 9 ++++-- mmtbx/monomer_library/linking_mixins.py | 3 +- mmtbx/monomer_library/pdb_interpretation.py | 31 +++++++++++++++++++-- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index 19517ff065..d90926f0e8 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -223,6 +223,7 @@ def run(self): p.pdb_interpretation.proceed_with_excessive_length_bonds=True #p.pdb_interpretation.automatic_linking.link_metals = True p.pdb_interpretation.automatic_linking.link_residues = True + p.pdb_interpretation.automatic_linking.exclude_hydrogens_from_bonding_decisions = True t0 = time.time() #p.pdb_interpretation.restraints_library.cdl=False # XXX this triggers a bug !=360 @@ -434,7 +435,7 @@ def validate_electrons(self): # ------------------------------------------------------------------------------ - def exclude_H_on_links(self): + def exclude_H_on_links(self, verbose=False): """Remove H atoms bound to heavy atoms that form a link An exception are HD1 and HE2 of HIS. The mover functionality in reduce will @@ -492,6 +493,10 @@ def exclude_H_on_links(self): removed_dict[j] = exclusion_dict[i] parent_dict[j]=i # remove H atoms NOT to remove - double negative! + if verbose: + print('removed_dict',removed_dict) + for i_seq in sel_remove: + print('remove?',atoms[i_seq].quote()) remove_from_sel_remove=[] for ii, i_seq in reversed(list(enumerate(sel_remove))): j_seq=parent_dict[i_seq] @@ -509,7 +514,7 @@ def exclude_H_on_links(self): sel_remove=list(sel_remove) for r in remove_from_sel_remove: sel_remove.remove(r) - # print('keep',atoms[r].quote()) + if verbose: print('keep',atoms[r].quote()) sel_remove=flex.size_t(sel_remove) # sl_removed = [(atom.id_str().replace('pdb=','').replace('"',''), diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index d1bcbbef5e..77f059ccc0 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -314,6 +314,7 @@ def process_nonbonded_for_links(self, small_molecule_bond_cutoff = 2., include_selections = None, exclude_selections = None, + exclude_hydrogens_from_bonding_decisions = False, log = None, verbose = False, ): @@ -584,7 +585,7 @@ def _nonbonded_pair_generator_geometry_restraints_sort( key.append(str(rt_mx_ji)) key = tuple(key) # hydrogens - if atom1.parent().parent().resseq==atom2.parent().parent().resseq: + if not exclude_hydrogens_from_bonding_decisions: if atom1.element.strip() in hydrogens: done[atom2.id_str()] = atom1.id_str() if atom2.element.strip() in hydrogens: diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index 0b1aff1c08..084bfb248b 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -317,6 +317,8 @@ def __init__(self, residue_name, atom_name, atom_element): .type = float small_molecule_bond_cutoff = 1.98 .type = float + exclude_hydrogens_from_bonding_decisions = False + .type = bool } include_in_automatic_linking .optional = True @@ -1895,20 +1897,44 @@ def get_restraints_loading_flags(params): rc["use_neutron_distances"] = params.use_neutron_distances return rc +def special_dispensation(proxy_label, m_i, m_j, i_seqs): + atoms=[] + for afs in [m_i.pdb_atoms, m_j.pdb_atoms]: + for atom in afs: + if atom.i_seq in i_seqs: + atoms.append(atom) + names=[] + for atom in atoms: + if atom.name not in names: names.append(atom.name) + names.sort() + if names in [ + [' H2 ', ' N '], + ]: + return names + return False + def evaluate_registry_process_result( proxy_label, m_i, m_j, i_seqs, registry_process_result, lines=[]): if (registry_process_result.is_conflicting): - raise Sorry(format_exception_message( + has_special_dispensation = special_dispensation(proxy_label, + m_i, + m_j, + i_seqs) + outl = format_exception_message( m_i=m_i, m_j=m_j, i_seqs=i_seqs, base_message="Conflicting %s restraints:" % proxy_label, source_labels=registry_process_result.conflict_source_labels, show_residue_names=False, - lines=lines)) + lines=lines) + if has_special_dispensation: + print('%s\n%s\n%s\n' %('!'*80, outl, '!'*80)) + else: + raise Sorry(outl) pdb_atoms = m_i.pdb_atoms if (not registry_process_result.is_new and not all_atoms_are_in_main_conf(atoms=[pdb_atoms[i_seq] for i_seq in i_seqs])): @@ -5462,6 +5488,7 @@ def generate_ss_atom_lookup(): second_row_buffer = al_params.buffer_for_second_row_elements, exclude_selections = exclude_selections, include_selections = include_selections, + exclude_hydrogens_from_bonding_decisions = al_params.exclude_hydrogens_from_bonding_decisions, log=log, ) self.geometry_proxy_registries.discard_tables() From 94bc38386fd36b2c1a8b21fdc78a7a96427516b2 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Mon, 25 Mar 2024 16:03:36 -0700 Subject: [PATCH 252/748] Update test --- mmtbx/hydrogens/tst_add_hydrogen_2.py | 141 +++++++++++++------------- 1 file changed, 69 insertions(+), 72 deletions(-) diff --git a/mmtbx/hydrogens/tst_add_hydrogen_2.py b/mmtbx/hydrogens/tst_add_hydrogen_2.py index 31fe30f630..052cbec494 100644 --- a/mmtbx/hydrogens/tst_add_hydrogen_2.py +++ b/mmtbx/hydrogens/tst_add_hydrogen_2.py @@ -6,7 +6,7 @@ def run(): test_000() - #test_001() + test_001() test_002() test_003() test_004() @@ -161,78 +161,75 @@ def test_009(): ATOM 5 CB PRO A 245 13.007 12.541 16.569 1.00 42.50 C ATOM 6 CG PRO A 245 13.795 12.147 17.772 1.00 47.69 C ATOM 7 CD PRO A 245 13.504 10.698 18.006 1.00 45.37 C -REMARK ATOM 8 H2 PRO A 245 12.414 9.635 16.709 1.00 41.32 H -REMARK ATOM 9 H3 PRO A 245 13.938 9.673 16.344 1.00 41.32 H -ATOM 10 HA PRO A 245 12.051 11.211 15.320 1.00 43.09 H -ATOM 11 HB2 PRO A 245 13.452 13.251 16.080 1.00 42.50 H -ATOM 12 HB3 PRO A 245 12.112 12.820 16.817 1.00 42.50 H -ATOM 13 HG2 PRO A 245 14.740 12.283 17.601 1.00 47.69 H -ATOM 14 HG3 PRO A 245 13.515 12.679 18.533 1.00 47.69 H -ATOM 15 HD2 PRO A 245 14.279 10.246 18.375 1.00 45.37 H -ATOM 16 HD3 PRO A 245 12.744 10.590 18.598 1.00 45.37 H -ATOM 17 N LYS A 246 13.611 11.942 13.495 1.00 42.99 N -ATOM 18 CA LYS A 246 14.551 12.132 12.404 1.00 43.44 C -ATOM 19 C LYS A 246 15.633 13.122 12.832 1.00 46.25 C -ATOM 20 O LYS A 246 15.332 14.110 13.510 1.00 45.93 O -ATOM 21 CB LYS A 246 13.837 12.652 11.156 1.00 49.81 C -ATOM 22 CG LYS A 246 12.652 11.809 10.713 1.00 54.70 C -ATOM 23 CD LYS A 246 13.071 10.649 9.829 1.00 62.40 C -ATOM 24 CE LYS A 246 11.928 9.661 9.640 1.00 71.25 C -ATOM 25 NZ LYS A 246 10.594 10.329 9.556 1.00 76.52 N -ATOM 26 H LYS A 246 12.828 12.269 13.355 1.00 42.99 H -ATOM 27 HA LYS A 246 14.966 11.285 12.179 1.00 43.44 H -ATOM 28 HB2 LYS A 246 14.472 12.674 10.423 1.00 49.81 H -ATOM 29 HB3 LYS A 246 13.509 13.547 11.338 1.00 49.81 H -ATOM 30 HG2 LYS A 246 12.208 11.447 11.496 1.00 54.70 H -ATOM 31 HG3 LYS A 246 12.036 12.365 10.210 1.00 54.70 H -ATOM 32 HD2 LYS A 246 13.815 10.182 10.241 1.00 62.40 H -ATOM 33 HD3 LYS A 246 13.332 10.985 8.958 1.00 62.40 H -ATOM 34 HE2 LYS A 246 11.910 9.050 10.393 1.00 71.25 H -ATOM 35 HE3 LYS A 246 12.069 9.168 8.816 1.00 71.25 H -REMARK ATOM 36 HZ1 LYS A 246 9.955 9.720 9.446 1.00 76.52 H -REMARK ATOM 37 HZ2 LYS A 246 10.578 10.892 8.867 1.00 76.52 H -REMARK ATOM 38 HZ3 LYS A 246 10.434 10.784 10.304 1.00 76.52 H -ATOM 39 N PRO A 247 16.897 12.890 12.459 1.00 44.07 N -ATOM 40 CA PRO A 247 17.961 13.810 12.905 1.00 39.69 C -ATOM 41 C PRO A 247 17.659 15.272 12.622 1.00 41.96 C -ATOM 42 O PRO A 247 17.848 16.127 13.497 1.00 43.51 O -ATOM 43 CB PRO A 247 19.188 13.316 12.126 1.00 43.94 C -ATOM 44 CG PRO A 247 18.912 11.884 11.852 1.00 47.67 C -ATOM 45 CD PRO A 247 17.430 11.781 11.650 1.00 44.76 C -ATOM 46 HA PRO A 247 18.124 13.716 13.857 1.00 39.69 H -ATOM 47 HB3 PRO A 247 19.279 13.817 11.300 1.00 43.94 H -ATOM 48 HB2 PRO A 247 19.987 13.419 12.667 1.00 43.94 H -ATOM 49 HG2 PRO A 247 19.193 11.346 12.609 1.00 47.67 H -ATOM 50 HG3 PRO A 247 19.387 11.607 11.053 1.00 47.67 H -ATOM 51 HD2 PRO A 247 17.201 11.896 10.714 1.00 44.76 H -ATOM 52 HD3 PRO A 247 17.097 10.929 11.971 1.00 44.76 H +ATOM 8 HA PRO A 245 12.051 11.211 15.320 1.00 43.09 H +ATOM 9 HB2 PRO A 245 13.452 13.251 16.080 1.00 42.50 H +ATOM 10 HB3 PRO A 245 12.112 12.820 16.817 1.00 42.50 H +ATOM 11 HG2 PRO A 245 14.740 12.283 17.601 1.00 47.69 H +ATOM 12 HG3 PRO A 245 13.515 12.679 18.533 1.00 47.69 H +ATOM 13 HD2 PRO A 245 14.279 10.246 18.375 1.00 45.37 H +ATOM 14 HD3 PRO A 245 12.744 10.590 18.598 1.00 45.37 H +ATOM 15 N LYS A 246 13.611 11.942 13.495 1.00 42.99 N +ATOM 16 CA LYS A 246 14.551 12.132 12.404 1.00 43.44 C +ATOM 17 C LYS A 246 15.633 13.122 12.832 1.00 46.25 C +ATOM 18 O LYS A 246 15.332 14.110 13.510 1.00 45.93 O +ATOM 19 CB LYS A 246 13.837 12.652 11.156 1.00 49.81 C +ATOM 20 CG LYS A 246 12.652 11.809 10.713 1.00 54.70 C +ATOM 21 CD LYS A 246 13.071 10.649 9.829 1.00 62.40 C +ATOM 22 CE LYS A 246 11.928 9.661 9.640 1.00 71.25 C +ATOM 23 NZ LYS A 246 10.594 10.329 9.556 1.00 76.52 N +ATOM 24 H LYS A 246 12.828 12.269 13.355 1.00 42.99 H +ATOM 25 HA LYS A 246 14.966 11.285 12.179 1.00 43.44 H +ATOM 26 HB2 LYS A 246 13.509 13.547 11.338 1.00 49.81 H +ATOM 27 HB3 LYS A 246 14.472 12.674 10.423 1.00 49.81 H +ATOM 28 HG2 LYS A 246 12.208 11.447 11.496 1.00 54.70 H +ATOM 29 HG3 LYS A 246 12.036 12.365 10.210 1.00 54.70 H +ATOM 30 HD2 LYS A 246 13.815 10.182 10.241 1.00 62.40 H +ATOM 31 HD3 LYS A 246 13.332 10.985 8.958 1.00 62.40 H +ATOM 32 HE2 LYS A 246 11.910 9.050 10.393 1.00 71.25 H +ATOM 33 HE3 LYS A 246 12.069 9.168 8.816 1.00 71.25 H +ATOM 34 HZ1 LYS A 246 9.955 9.720 9.446 1.00 76.52 H +ATOM 37 N PRO A 247 16.897 12.890 12.459 1.00 44.07 N +ATOM 38 CA PRO A 247 17.961 13.810 12.905 1.00 39.69 C +ATOM 39 C PRO A 247 17.659 15.272 12.622 1.00 41.96 C +ATOM 40 O PRO A 247 17.848 16.127 13.497 1.00 43.51 O +ATOM 41 CB PRO A 247 19.188 13.316 12.126 1.00 43.94 C +ATOM 42 CG PRO A 247 18.912 11.884 11.852 1.00 47.67 C +ATOM 43 CD PRO A 247 17.430 11.781 11.650 1.00 44.76 C +ATOM 44 HA PRO A 247 18.124 13.716 13.857 1.00 39.69 H +ATOM 45 HB2 PRO A 247 19.987 13.419 12.667 1.00 43.94 H +ATOM 46 HB3 PRO A 247 19.279 13.817 11.300 1.00 43.94 H +ATOM 47 HG2 PRO A 247 19.193 11.346 12.609 1.00 47.67 H +ATOM 48 HG3 PRO A 247 19.387 11.607 11.053 1.00 47.67 H +ATOM 49 HD2 PRO A 247 17.201 11.896 10.714 1.00 44.76 H +ATOM 50 HD3 PRO A 247 17.097 10.929 11.971 1.00 44.76 H TER -HETATM 48 N TAM H 2 9.323 12.496 7.335 1.00 20.00 N -HETATM 49 C TAM H 2 8.060 12.492 8.002 1.00 20.00 C -HETATM 50 C1 TAM H 2 7.540 13.901 8.071 1.00 20.00 C -HETATM 51 C2 TAM H 2 8.386 11.881 9.335 1.00 20.00 C -HETATM 52 C3 TAM H 2 7.035 11.686 7.294 1.00 20.00 C -HETATM 53 C4 TAM H 2 7.128 14.539 6.744 1.00 20.00 C -HETATM 54 C5 TAM H 2 8.930 10.458 9.271 1.00 20.00 C -HETATM 55 C6 TAM H 2 5.660 11.992 7.821 1.00 20.00 C -HETATM 56 O4 TAM H 2 5.710 14.391 6.585 1.00 20.00 O -HETATM 57 O5 TAM H 2 7.872 9.487 9.299 1.00 20.00 O -HETATM 58 O6 TAM H 2 5.714 12.262 9.200 1.00 20.00 O -HETATM 59 H11 TAM H 2 6.779 13.910 8.672 1.00 20.00 H -HETATM 60 H12 TAM H 2 8.223 14.452 8.485 1.00 20.00 H -HETATM 61 H21 TAM H 2 7.589 11.879 9.888 1.00 20.00 H -HETATM 62 H22 TAM H 2 9.038 12.437 9.790 1.00 20.00 H -HETATM 63 H31 TAM H 2 7.225 10.740 7.392 1.00 20.00 H -HETATM 64 H32 TAM H 2 7.071 11.859 6.340 1.00 20.00 H -HETATM 65 H41 TAM H 2 7.600 14.117 6.009 1.00 20.00 H -HETATM 66 H42 TAM H 2 7.377 15.476 6.732 1.00 20.00 H -HETATM 67 H61 TAM H 2 5.264 12.763 7.385 1.00 20.00 H -HETATM 68 H62 TAM H 2 5.044 11.254 7.689 1.00 20.00 H -HETATM 69 HN1 TAM H 2 9.235 12.859 6.527 1.00 20.00 H -HETATM 70 HN2 TAM H 2 9.942 12.134 7.862 1.00 20.00 H -HETATM 71 HO4 TAM H 2 5.529 13.560 6.592 1.00 20.00 H -HETATM 72 HO5 TAM H 2 7.358 9.637 8.639 1.00 20.00 H -HETATM 73 HO6 TAM H 2 6.211 12.942 9.316 1.00 20.00 H +HETATM 51 N TAM H 2 9.323 12.496 7.335 1.00 20.00 N +HETATM 52 C TAM H 2 8.060 12.492 8.002 1.00 20.00 C +HETATM 53 C1 TAM H 2 7.540 13.901 8.071 1.00 20.00 C +HETATM 54 C2 TAM H 2 8.386 11.881 9.335 1.00 20.00 C +HETATM 55 C3 TAM H 2 7.035 11.686 7.294 1.00 20.00 C +HETATM 56 C4 TAM H 2 7.128 14.539 6.744 1.00 20.00 C +HETATM 57 C5 TAM H 2 8.930 10.458 9.271 1.00 20.00 C +HETATM 58 C6 TAM H 2 5.660 11.992 7.821 1.00 20.00 C +HETATM 59 O4 TAM H 2 5.710 14.391 6.585 1.00 20.00 O +HETATM 60 O5 TAM H 2 7.872 9.487 9.299 1.00 20.00 O +HETATM 61 O6 TAM H 2 5.714 12.262 9.200 1.00 20.00 O +HETATM 62 H11 TAM H 2 6.779 13.910 8.672 1.00 20.00 H +HETATM 63 H12 TAM H 2 8.223 14.452 8.485 1.00 20.00 H +HETATM 64 H21 TAM H 2 7.589 11.879 9.888 1.00 20.00 H +HETATM 65 H22 TAM H 2 9.038 12.437 9.790 1.00 20.00 H +HETATM 66 H31 TAM H 2 7.225 10.740 7.392 1.00 20.00 H +HETATM 67 H32 TAM H 2 7.071 11.859 6.340 1.00 20.00 H +HETATM 68 H41 TAM H 2 7.600 14.117 6.009 1.00 20.00 H +HETATM 69 H42 TAM H 2 7.377 15.476 6.732 1.00 20.00 H +HETATM 70 H51 TAM H 2 9.455 10.349 8.462 1.00 20.00 H +HETATM 72 H61 TAM H 2 5.264 12.763 7.385 1.00 20.00 H +HETATM 73 H62 TAM H 2 5.044 11.254 7.689 1.00 20.00 H +HETATM 74 HN1 TAM H 2 9.235 12.859 6.527 1.00 20.00 H +HETATM 75 HN2 TAM H 2 9.942 12.134 7.862 1.00 20.00 H +HETATM 76 HO4 TAM H 2 5.529 13.560 6.592 1.00 20.00 H +HETATM 77 HO5 TAM H 2 7.358 9.637 8.639 1.00 20.00 H +HETATM 78 HO6 TAM H 2 6.211 12.942 9.316 1.00 20.00 H """ pdb_str_002 = """ From 7c1c51f6e98e8ef51fd5877cba06c32c452f6c08 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Mon, 25 Mar 2024 16:36:53 -0700 Subject: [PATCH 253/748] Add comment --- mmtbx/hydrogens/reduce_hydrogen.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index d90926f0e8..e8de77ddf6 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -331,6 +331,7 @@ def run(self): # restraint_objects = ro, # log = null_out()) + # TODO: this should be ideally done *after* reduce optimization if not self.exclude_water: self.model.add_hydrogens(1., occupancy=0.) From 75ead7a742bba8fc700d2fbe9401543bdbd13dfb Mon Sep 17 00:00:00 2001 From: Iris Young Date: Tue, 26 Mar 2024 02:50:36 -0700 Subject: [PATCH 254/748] Add energy (FEE/Ebeam) calibration to the XFEL UI - EnergyTab is a new tab in the GUI where the user can use the FEE calibration tools, generate and view associated plots, and export a phil file with the results. The phil can be imported into rungroups directly, avoiding manual transcription errors. This includes the FEE spectrometer calibration from the notch scan as well as visualizing and calculating the Ebeam offset -- that is, spectrum_eV_offset, spectrum_eV_per_pixel, and wavelength_offset. (Note, we really should consider renaming these and doing all adjustments in eV.) - CalibWorker is a new thread running in the background, executing any requested calibration tasks (so far just for EnergyTab). - ebeam_plotter.py is the plotting tool to replace the command line script thing.py for use in the GUI. - Small necessary changes were made to existing calibration and visualization scripts to make them able to accept an existing matplotlib figure and add plots to it, and to write out results. - Note of caution, window resizing seems to be crash-prone. Not entirely sure why, but given this fact, I haven't put work into making things resize nicely for different screen sizes. This is all optimized for the control room at MFX. --- serialtbx/util/energy_scan_notch_finder.py | 43 +- xfel/command_line/fee_calibration.py | 12 + xfel/ui/components/ebeam_plotter.py | 62 +++ xfel/ui/components/xfel_gui_init.py | 537 ++++++++++++++++++++- 4 files changed, 631 insertions(+), 23 deletions(-) create mode 100644 xfel/ui/components/ebeam_plotter.py diff --git a/serialtbx/util/energy_scan_notch_finder.py b/serialtbx/util/energy_scan_notch_finder.py index 91bfd4aef8..55e22ae6d3 100644 --- a/serialtbx/util/energy_scan_notch_finder.py +++ b/serialtbx/util/energy_scan_notch_finder.py @@ -48,7 +48,7 @@ def find_notch(data_x, data_y, kernel_size, fit_half_range, baseline_cutoff, ref fitted_min_y = notch_shape.__call__(fitted_min_x) return ((fitted_min_x, fitted_min_y), notch_shape, smoothed_y, flattened_y) -def plot_notches(runs, rundata, notches, per_run_plots=False): +def plot_notches(runs, rundata, notches, per_run_plots=False, use_figure=None): """Plot the energy scan, optionally one plot per spectrum for troubleshooting misses when automatically identifying notch positions, and always as an overlay of spectra in the scan with notch positions marked.""" if per_run_plots: for run, data_y, notch in zip(runs, rundata, notches): @@ -64,36 +64,43 @@ def plot_notches(runs, rundata, notches, per_run_plots=False): plt.legend() plt.figure() + fig = use_figure or plt.figure() + ax = fig.subplots() for run, data, notch in zip(runs, rundata, notches): (notch_x, notch_y), notch_shape, smoothed_y, flattened_y = notch - plt.plot(range(len(data)), data, '-', label=f"run {run}: notch at {int(notch_x)} pixels".format()) - plt.plot([notch_x], [notch_y], 'k+', label="_nolegend_") + ax.plot(range(len(data)), data, '-', label=f"run {run}: notch at {int(notch_x)} pixels".format()) + ax.plot([notch_x], [notch_y], 'k+', label="_nolegend_") # repeat last one to add legend - plt.plot([notch_x], [notch_y], 'k+', label="identified notches") + ax.plot([notch_x], [notch_y], 'k+', label="identified notches") - plt.legend() - plt.title("Energy scan") - plt.xlabel("FEE spectrometer pixels") - plt.ylabel("Mean counts") - plt.figure() + ax.legend() + ax.set_title("Energy scan") + ax.set_xlabel("FEE spectrometer pixels") + ax.set_ylabel("Mean counts") -def calibrate_energy(notches, energies): +def calibrate_energy(notches, energies, return_trendline=False, use_figure=None): """Having identified the pixel positions on the FEE spectrometer corresponding to known energy values, get a linear fit of these ordered pairs and report the eV offset and eV per pixel matching the fit.""" pixels = [n[0][0] for n in notches] linear_fit = Poly.fit(pixels, energies, 1).convert() eV_offset, eV_per_pixel = linear_fit.coef print(f"Calibrated eV offset of {eV_offset} and eV per pixel of {eV_per_pixel}".format()) - plt.scatter(pixels, energies, color='k', label="known energy positions") + fig = use_figure or plt.figure() + ax = fig.subplots() + ax.scatter(pixels, energies, color='k', label="known energy positions") px_min = int(min(pixels)) px_max = int(max(pixels)) px_range = px_max - px_min trendline_x = np.arange(px_min-0.1*px_range, px_max+0.1*px_range, int(px_range/10)) trendline_y = linear_fit.__call__(trendline_x) - plt.plot(trendline_x, trendline_y, 'b-', label=f"linear fit: y = {eV_per_pixel:.4f}*x + {eV_offset:.4f}".format()) - plt.xlabel("FEE spectrometer pixels") - plt.ylabel("Energy (eV)") - plt.title("Energy calibration") - plt.legend() - plt.show() - return (eV_offset, eV_per_pixel) + ax.plot(trendline_x, trendline_y, 'b-', label=f"linear fit: y = {eV_per_pixel:.4f}*x + {eV_offset:.4f}".format()) + ax.set_xlabel("FEE spectrometer pixels") + ax.set_ylabel("Energy (eV)") + ax.set_title("Energy calibration") + ax.legend() + if use_figure is None: + plt.show() + if return_trendline: + return ((eV_offset, eV_per_pixel), (linear_fit, trendline_x, trendline_y)) + else: + return (eV_offset, eV_per_pixel) diff --git a/xfel/command_line/fee_calibration.py b/xfel/command_line/fee_calibration.py index 9e8c5e7e3d..718fc292b2 100644 --- a/xfel/command_line/fee_calibration.py +++ b/xfel/command_line/fee_calibration.py @@ -15,6 +15,9 @@ verbose = False .type = bool .help = print all possible output +output_phil = None + .type = path + .help = path where calibrated values should be written as a phil file """ phil_scope = parse(fee_phil_string + notch_phil_string) @@ -97,6 +100,15 @@ def run(args): for data in rundata] plot_notches(runs, rundata, notches, params.per_run_plots) eV_offset, eV_per_pixel = calibrate_energy(notches, energies) + args_str = ' '.join(args) + with open('fee_calib.out', 'a') as outfile: + outfile.write(f'using {args_str}, eV_offset={eV_offset} eV_per_pixel={eV_per_pixel}\n') + print('wrote calibrated values to fee_calib.out') + if params.output_phil: + with open(params.output_phil, 'w') as outfile: + outfile.write(f'spectrum_eV_offset={eV_offset}\n') + outfile.write(f'spectrum_eV_per_pixel={eV_per_pixel}\n') + print(f'wrote calibrated values to {params.output_phil}') if __name__ == "__main__": import sys diff --git a/xfel/ui/components/ebeam_plotter.py b/xfel/ui/components/ebeam_plotter.py new file mode 100644 index 0000000000..f23568b691 --- /dev/null +++ b/xfel/ui/components/ebeam_plotter.py @@ -0,0 +1,62 @@ +from __future__ import division + +import dxtbx +from xfel.cxi.cspad_ana import cspad_tbx +from matplotlib import pyplot as plt +import numpy as np +from simtbx.nanoBragg.utils import ENERGY_CONV + +def compare_ebeams_with_fees(locfiles, runs=None, plot=True, use_figure=None): + if plot: + fig = use_figure or plt.figure() + ax = fig.subplots() + + ebeam_eV_offsets = [] + ebeam_wav_offsets = [] + + for i in range(len(locfiles)): + if locfiles[i] is None: + if plot: + ax.plot([],[], label='No data for run {runs[i]}') + continue + + img = dxtbx.load(locfiles[i]) + n_img = img.get_num_images() + + ebeams_eV = [] + ebeams_wav = [] + fee_coms_eV = [] + fee_coms_wav = [] + + for j in range(n_img): + if not img.get_spectrum(j): + continue # no FEE + ewav = cspad_tbx.evt_wavelength(img._get_event(j)) + if not ewav: + continue # no ebeam + fee_coms_wav.append(fwav:=img.get_beam(j).get_wavelength()) + fee_coms_eV.append(feV:=ENERGY_CONV/fwav) + ebeams_wav.append(ewav) + ebeams_eV.append(eeV:=ENERGY_CONV/ewav) + print(f'{i}: {int(feV)} eV FEE / {int(eeV)} eV Ebeam') + + if plot: + ax.hist(ebeams_eV, alpha=0.5, bins=40, label=f'run {runs[i]} ebeams ({int(eeV)} eV)') + ax.hist(fee_coms_eV, alpha=0.5, bins=40, label=f'run {runs[i]} FEE COMs ({int(feV)} eV)') + + diffs_eV = np.array(fee_coms_eV) - np.array(ebeams_eV) + ebeam_eV_offsets.append(sum(diffs_eV)/len(diffs_eV)) + diffs_wav = np.array(fee_coms_wav) - np.array(ebeams_wav) + ebeam_wav_offsets.append(sum(diffs_wav)/len(diffs_wav)) + + if plot: + ax.legend() + ax.set_xlabel('Energy (eV)') + ax.set_ylabel('Counts') + ax.set_title('Ebeam vs Calibrated FEE') + if not use_figure: + plt.show() + + return (sum(ebeam_eV_offsets)/len(ebeam_eV_offsets), + sum(ebeam_wav_offsets)/len(ebeam_wav_offsets)) + diff --git a/xfel/ui/components/xfel_gui_init.py b/xfel/ui/components/xfel_gui_init.py index 92dbc18265..1f169d70c2 100644 --- a/xfel/ui/components/xfel_gui_init.py +++ b/xfel/ui/components/xfel_gui_init.py @@ -146,6 +146,169 @@ def run(self): self.parent.run_window.run_light.change_status('alert') break + +# ------------------------------ Calib Worker ------------------------------ # + +# Set up events for updating calibration results +tp_EVT_ENERGY_DONE = wx.NewEventType() +EVT_ENERGY_DONE = wx.PyEventBinder(tp_EVT_ENERGY_DONE, 1) + +class CalibWorker(Thread): + ''' Worker thread to execute calibrations in the background without locking + up the GUI''' + + def __init__(self, + parent, + active=True): + Thread.__init__(self) + self.parent = parent + self.active = active + + def post_refresh_energy(self): + evt = RefreshRuns(tp_EVT_ENERGY_DONE, -1) + wx.PostEvent(self.energy_tab, evt) + + def run(self): + # one time setup + self.energy_tab = self.parent.run_window.energy_tab + self.db = xfel_db_application(self.parent.params) + + from serialtbx.util.energy_scan_notch_finder import notch_phil_string + from libtbx.phil import parse + self.fee_params = parse(notch_phil_string).extract() + self.energy_tab.refresh_runs() + + while self.active: + self.parent.run_window.calib_light.change_status('idle') # yellow -- actually means working + try: + if self.energy_tab.fee_calib_stale: + self.run_fee_calib() + self.post_refresh_energy() + if self.energy_tab.ebeam_calib_stale: + self.run_ebeam_calib() + self.post_refresh_energy() + if self.energy_tab.size_stale: + self.resize() + self.parent.run_window.calib_light.change_status('on') # green-- actually means idle + time.sleep(1) + except Exception as e: + print(e) + self.parent.run_window.calib_light.change_status('alert') # red -- means crashed + break + + def resize(self): + #for fig in (self.energy_tab.trendline_figure, self.energy_tab.spectra_figure, self.energy_tab.ebeam_figure): + # fig.set_figwidth(self.energy_tab.plotx) + # fig.set_figheight(self.energy_tab.ploty) + self.energy_tab.Layout() + #self.energy_tab.Fit() + + def run_fee_calib(self): + from serialtbx.util.energy_scan_notch_finder import find_notch, plot_notches, calibrate_energy + from xfel.command_line.fee_calibration import tally_fee_data + + runs = self.energy_tab.fee_runs + energies = self.energy_tab.fee_energies + rundata = tally_fee_data(self.energy_tab.experiment, runs, plot=False, verbose=True) + notches = [find_notch(range(len(data)), + data, + self.fee_params.kernel_size, + self.fee_params.fit_half_range, + self.fee_params.baseline_cutoff) + for data in rundata] + + plot_notches(runs, + rundata, + notches, + per_run_plots=False, + use_figure=self.energy_tab.spectra_figure) + offset, per_px = calibrate_energy(notches, + energies, + use_figure=self.energy_tab.trendline_figure) + self.energy_tab.spectra_figure.canvas.draw_idle() + self.energy_tab.trendline_figure.canvas.draw_idle() + + self.energy_tab.fee_eV_offset = offset + self.energy_tab.fee_eV_per_pixel = per_px + self.energy_tab.eV_offset_text.SetLabel(f'{offset:.4f} eV') + self.energy_tab.eV_per_px_text.SetLabel(f'{per_px:.4f} eV') + self.energy_tab.fee_calib_stale = False + + def run_ebeam_calib(self, source='loc'): + from xfel.ui.components.ebeam_plotter import compare_ebeams_with_fees + + run_strings = self.energy_tab.selected_runs + + if not hasattr(self, 'loc_dir'): + results_dir = self.parent.params.output_folder + energy_dir = os.path.join(results_dir, '..', 'energy') + if os.path.exists(energy_dir): + self.loc_dir = energy_dir + else: + try: + os.mkdir(energy_dir) + self.loc_dir = energy_dir + except Exception: + loc_dir = os.path.join(results_dir, 'locs') + os.mkdir(loc_dir) + self.loc_dir = loc_dir + + loc_parts = [] + if self.energy_tab.experiment is not None: + loc_parts.append(f'experiment={self.energy_tab.experiment}') + loc_parts.append(f'spectrum_eV_offset={self.energy_tab.fee_eV_offset:.2f}') + loc_parts.append(f'spectrum_eV_per_pixel={self.energy_tab.fee_eV_per_pixel:.2f}') + + runs = [run for run in self.db.get_all_runs() if str(run.run) in run_strings] + locfiles = [] + reordered_run_strings = [] + for run in runs: + try: + this_loc_parts = loc_parts[::] + this_loc_parts.append(f'run={run.run}') + try: + rungroup = run.get_rungroups()[-1] + except Exception: + print(f'Run {run.run} does not appear to be in any rungroup. Skipping.') + continue + det_addr = rungroup.detector_address + this_loc_parts.append(f'detector_address={det_addr}') + if 'rayonix' in det_addr: + this_loc_parts.append(f'rayonix.bin_size={rungroup.binning}') + loc_path = os.path.join(self.loc_dir, f'{run.run}.loc') + if not os.path.exists(loc_path): + with open(loc_path, 'w') as locf: + locf.write('\n'.join(this_loc_parts)) + locfiles.append(loc_path) + reordered_run_strings.append(str(run.run)) + except Exception as e: + print('Failed to load ebeam for run {run.run}') + print(e) + continue + + if len(locfiles) == 0: + print('No runs to compare.') + return + + self.energy_tab.ebeam_figure.clear() + ebeam_eV_offset, ebeam_wavelength_offset = compare_ebeams_with_fees( + locfiles, + runs=reordered_run_strings, + plot=True, + use_figure=self.energy_tab.ebeam_figure) + self.energy_tab.ebeam_figure.canvas.draw_idle() + + self.energy_tab.ebeam_eV_offset = ebeam_eV_offset + self.energy_tab.ebeam_wavelength_offset = ebeam_wavelength_offset + ang = u'\u212b' # Angstrom + self.energy_tab.ebeam_offset_text.SetLabel(f'{ebeam_eV_offset:.2f} eV ({ebeam_wavelength_offset:.6f} {ang})') + self.energy_tab.ebeam_calib_stale = False + + #try: + # locfile = os.path.join(db.params.output_folder, f'r{run.run:04d}', f'{trial.trial:03d}_rg{rg.rungroup_id:03d', 'data.loc') + #except ValueError: # in case of non-numeric run names + # locfile = os.path.join(db.params.output_folder, f'r{run.run}', f'{trial.trial:03d}_rg{rg.rungroup_id:03d', 'data.loc') + # ------------------------------- Job Monitor ------------------------------- # # Set up events for and for finishing all cycles @@ -1100,6 +1263,7 @@ def __init__(self, parent, id, title): wx.Frame.__init__(self, parent, id, title, size=(200, 200)) self.run_sentinel = None + self.calib_worker = None self.job_sentinel = None self.job_monitor = None self.spotfinder_sentinel = None @@ -1206,6 +1370,7 @@ def connect_to_db(self, drop_tables = False): def stop_sentinels(self): if not self.params.monitoring_mode: self.stop_run_sentinel() + self.stop_calib_worker() self.stop_job_sentinel() self.stop_job_monitor() #self.stop_spotfinder_sentinel() @@ -1228,6 +1393,18 @@ def stop_run_sentinel(self, block = True): self.run_window.run_light.change_status('off') self.toolbar.SetToolNormalBitmap(self.tb_btn_watch_new_runs.Id, wx.Bitmap('{}/32x32/quick_restart.png'.format(icons))) + def start_calib_worker(self): + self.calib_worker = CalibWorker(self, active=True) + self.calib_worker.start() + self.run_window.calib_light.change_status('on') + + def stop_calib_worker(self, block = True): + if self.calib_worker is not None and self.calib_worker.active: + self.calib_worker.active = False + if block: + self.calib_worker.join() + self.run_window.calib_light.change_status('off') + def start_job_monitor(self): self.job_monitor = JobMonitor(self, active=True) self.job_monitor.start() @@ -1356,11 +1533,11 @@ def onSettings(self, e): def onZoom(self, e): self.high_vis = not self.high_vis - def onCalibration(self, e): - calib_dlg = dlg.CalibrationDialog(self, db=self.db) - calib_dlg.Fit() + # def onCalibration(self, e): + # calib_dlg = dlg.CalibrationDialog(self, db=self.db) + # calib_dlg.Fit() - calib_dlg.ShowModal() + # calib_dlg.ShowModal() def onWatchRuns(self, e): ''' Toggle autosubmit ''' @@ -1382,6 +1559,10 @@ def onTabChange(self, e): if self.job_monitor is None or not self.job_monitor.active: self.start_job_monitor() self.run_window.jmn_light.change_status('on') + elif name == self.run_window.energy_tab.name: + if self.calib_worker is None or not self.calib_worker.active: + self.start_calib_worker() + self.run_window.calib_light.change_status('on') # Disabled #elif name == self.run_window.spotfinder_tab.name: # if self.job_monitor is None or not self.job_monitor.active: @@ -1419,6 +1600,10 @@ def onLeavingTab(self, e): if self.job_monitor.active: self.stop_job_monitor(block = False) self.run_window.jmn_light.change_status('off') + elif name == self.run_window.energy_tab.name: + if self.calib_worker.active: + self.stop_calib_worker(block = False) + self.run_window.calib_light.change_status('off') # Disabled #elif name == self.run_window.spotfinder_tab.name: # if self.job_monitor.active: @@ -1460,6 +1645,7 @@ def __init__(self, parent): self.main_panel = wx.Panel(self) self.main_nbook = wx.Notebook(self.main_panel, style=0) self.runs_tab = RunTab(self.main_nbook, main=self.parent) + self.energy_tab = EnergyTab(self.main_nbook, main=self.parent) self.trials_tab = TrialsTab(self.main_nbook, main=self.parent) self.jobs_tab = JobsTab(self.main_nbook, main=self.parent) #self.spotfinder_tab = SpotfinderTab(self.main_nbook, main=self.parent) # Disabled @@ -1469,6 +1655,7 @@ def __init__(self, parent): #self.merge_tab = MergeTab(self.main_nbook, main=self.parent) self.mergingstats_tab = MergingStatsTab(self.main_nbook, main=self.parent) self.main_nbook.AddPage(self.runs_tab, self.runs_tab.name) + self.main_nbook.AddPage(self.energy_tab, self.energy_tab.name) self.main_nbook.AddPage(self.trials_tab, self.trials_tab.name) self.main_nbook.AddPage(self.jobs_tab, self.jobs_tab.name) #self.main_nbook.AddPage(self.spotfinder_tab, self.spotfinder_tab.name) # Disabled @@ -1478,8 +1665,9 @@ def __init__(self, parent): #self.main_nbook.AddPage(self.merge_tab, self.merge_tab.name) self.main_nbook.AddPage(self.mergingstats_tab, self.mergingstats_tab.name) - self.sentinel_box = wx.FlexGridSizer(1, 6, 0, 20) + self.sentinel_box = wx.FlexGridSizer(1, 7, 0, 20) self.run_light = gctr.SentinelStatus(self.main_panel, label='Run Sentinel') + self.calib_light = gctr.SentinelStatus(self.main_panel, label='Calib Worker') self.job_light = gctr.SentinelStatus(self.main_panel, label='Job Sentinel') self.jmn_light = gctr.SentinelStatus(self.main_panel, label='Job Monitor') #self.spotfinder_light = gctr.SentinelStatus(self.main_panel, label='Spotfinder Sentinel') @@ -1487,6 +1675,7 @@ def __init__(self, parent): self.unitcell_light = gctr.SentinelStatus(self.main_panel, label='Unit Cell Sentinel') self.mergingstats_light = gctr.SentinelStatus(self.main_panel, label='Merging Stats Sentinel') self.sentinel_box.Add(self.run_light) + self.sentinel_box.Add(self.calib_light) self.sentinel_box.Add(self.job_light) self.sentinel_box.Add(self.jmn_light) #self.sentinel_box.Add(self.spotfinder_light) @@ -1506,6 +1695,7 @@ def __init__(self, parent): if self.parent.params.monitoring_mode: self.runs_tab.Hide() + self.energy_tab.Hide() self.trials_tab.Hide() self.jobs_tab.Hide() self.datasets_tab.Hide() @@ -1650,6 +1840,343 @@ def refresh_rows(self, all=False): self.run_panel.SetupScrolling(scrollToTop=False) self.run_panel.Refresh() +class EnergyTab(BaseTab): + def __init__(self, parent, main): + BaseTab.__init__(self, parent=parent) + self.name = 'Energy' + self.main = main + + self.all_runs = [] + self.fee_runs = [] + self.fee_energies = [] + self.ebeam_runs = [] + self.fee_eV_per_pixel = None + self.fee_eV_offset = None + self.ebeam_eV_offset = None + self.ebeam_wavelength_offset = None + + self.fee_calib_stale = False + self.ebeam_calib_stale = False + self.size_stale = False + + self.calib_panel = ScrolledPanel(self) + self.calib_sizer = wx.BoxSizer(wx.VERTICAL) + self.calib_panel.SetSizer(self.calib_sizer) + self.calib_grid_sizer = wx.GridBagSizer(vgap=10, hgap=10) + + import matplotlib as mpl + from matplotlib.backends.backend_wxagg import ( + FigureCanvasWxAgg as FigureCanvas, + NavigationToolbar2WxAgg as NavigationToolbar) + + # FEE scan section + self.scan_runs_panel = ScrolledPanel(self.calib_panel, size=(220, 300)) + self.scan_runs_sizer = wx.BoxSizer(wx.VERTICAL) + self.scan_runs_panel.SetSizer(self.scan_runs_sizer) + + self.scan_runs_panel_label = wx.StaticText(self.scan_runs_panel, label='FEE Energy Scan Description', size=(420, 20)) + self.scan_runs_sizer.Add(self.scan_runs_panel_label, border=10, flag=wx.BOTTOM) + + self.expt_id_panel = wx.Panel(self.scan_runs_panel) + self.expt_id_sizer = wx.BoxSizer(wx.HORIZONTAL) + self.scan_runs_experiment_label = wx.StaticText(self.expt_id_panel, label='Experiment:', size=(80, -1)) + self.scan_runs_experiment = wx.TextCtrl(self.expt_id_panel, size=(118, -1)) + self.expt_id_sizer.Add(self.scan_runs_experiment_label) + self.expt_id_sizer.Add(self.scan_runs_experiment) + self.expt_id_panel.SetSizer(self.expt_id_sizer) + self.scan_runs_sizer.Add(self.expt_id_panel) + + self.scan_runs_list = dlg.EdListCtrl(self.scan_runs_panel, + style=wx.LC_EDIT_LABELS | wx.LC_REPORT, + size=(200,165)) + + self.scan_runs_list.InsertColumn(0, 'Run', width=60) + self.scan_runs_list.InsertColumn(1, 'Notch Energy (eV)', width=140) + self.scan_runs_list.integer_columns = {0} + for i in range(5): + self.scan_runs_list.InsertItem(0, 0) + + self.scan_runs_sizer.Add(self.scan_runs_list, 1) + + self.scan_runs_button_panel = wx.Panel(self.scan_runs_panel) + self.scan_runs_button_sizer = wx.GridBagSizer(0,0) + self.scan_runs_button_add = wx.Button(self.scan_runs_button_panel, + size=(94, -1), + label='Add Row') + self.scan_runs_button_clear = wx.Button(self.scan_runs_button_panel, + size=(94, -1), + label='Clear All') + self.scan_runs_button_run = wx.Button(self.scan_runs_button_panel, + size=(194, -1), + label='Run Calibration') + self.scan_runs_button_sizer.Add(self.scan_runs_button_add, + pos=(0,0), border=3, flag=wx.ALL) + self.scan_runs_button_sizer.Add(self.scan_runs_button_clear, + pos=(0,1), border=3, flag=wx.ALL) + self.scan_runs_button_sizer.Add(self.scan_runs_button_run, + pos=(1,0), span=(1,2), border=3, flag=wx.ALL | wx.EXPAND) + self.scan_runs_button_panel.SetSizer(self.scan_runs_button_sizer) + + self.scan_runs_sizer.Add(self.scan_runs_button_panel, 1) + self.calib_grid_sizer.Add(self.scan_runs_panel, pos=(0, 0)) + + # FEE scan trendline + self.trendline_panel = wx.Panel(self.calib_panel) + self.trendline_sizer = wx.BoxSizer(wx.HORIZONTAL) + self.trendline_panel.SetSizer(self.trendline_sizer) + + self.trendline_figure = mpl.figure.Figure(figsize=(4,2.3)) + self.trendline_canvas = FigureCanvas(self.trendline_panel, -1, self.trendline_figure) + self.trendline_toolbar = NavigationToolbar(self.trendline_canvas) + self.trendline_toolbar.SetWindowStyle(wx.TB_VERTICAL) + self.trendline_toolbar.Realize() + + self.trendline_sizer.Add(self.trendline_canvas, 1, flag=wx.EXPAND | wx.ALL) + self.trendline_sizer.Add(self.trendline_toolbar, 0) + + self.calib_grid_sizer.Add(self.trendline_panel, pos=(0, 1), flag=wx.EXPAND | wx.ALL) + + # FEE scan spectra + self.spectra_panel = wx.Panel(self.calib_panel) + self.spectra_sizer = wx.BoxSizer(wx.HORIZONTAL) + self.spectra_panel.SetSizer(self.spectra_sizer) + + self.spectra_figure = mpl.figure.Figure(figsize=(4,2.3)) + self.spectra_canvas = FigureCanvas(self.spectra_panel, -1, self.spectra_figure) + self.spectra_toolbar = NavigationToolbar(self.spectra_canvas) + self.spectra_toolbar.SetWindowStyle(wx.TB_VERTICAL) + self.spectra_toolbar.Realize() + + self.spectra_sizer.Add(self.spectra_canvas, 1, flag=wx.EXPAND | wx.ALL) + self.spectra_sizer.Add(self.spectra_toolbar, 0) + + self.calib_grid_sizer.Add(self.spectra_panel, pos=(0, 2), flag=wx.EXPAND | wx.ALL) + + # Ebeam calibration section + self.ebeam_runs_panel = ScrolledPanel(self.calib_panel, size=(220, 270)) + self.ebeam_runs_sizer = wx.BoxSizer(wx.VERTICAL) + self.ebeam_runs_panel.SetSizer(self.ebeam_runs_sizer) + + self.ebeam_runs_selection = gctr.CheckListCtrl(self.ebeam_runs_panel, + label='Runs for Ebeam Calibration', + label_size=(200, -1), + label_style='normal', + ctrl_size=(200, 160), + direction='vertical', + choices=[]) + + self.ebeam_runs_sizer.Add(self.ebeam_runs_selection, 1, flag=wx.EXPAND) + + self.ebeam_runs_button_panel = wx.Panel(self.ebeam_runs_panel) + self.ebeam_runs_button_sizer = wx.GridBagSizer(0,0) + self.ebeam_runs_refresh_button = wx.Button(self.ebeam_runs_button_panel, + label='Refresh', + size=(94, -1)) + self.ebeam_runs_clear_button = wx.Button(self.ebeam_runs_button_panel, + label='Clear', + size=(94, -1)) + self.ebeam_runs_launch_button = wx.Button(self.ebeam_runs_button_panel, + label='Run Calibration', + size=(194, -1)) + self.ebeam_runs_button_sizer.Add(self.ebeam_runs_refresh_button, + pos=(0,0), border=3, flag=wx.ALL) + self.ebeam_runs_button_sizer.Add(self.ebeam_runs_clear_button, + pos=(0,1), border=3, flag=wx.ALL) + self.ebeam_runs_button_sizer.Add(self.ebeam_runs_launch_button, + pos=(1,0), span=(1,2), border=3, flag=wx.ALL) + self.ebeam_runs_button_panel.SetSizer(self.ebeam_runs_button_sizer) + + self.ebeam_runs_sizer.Add(self.ebeam_runs_button_panel, 0) + + self.calib_grid_sizer.Add(self.ebeam_runs_panel, pos=(1, 0)) + + # Ebeam vs calibrated FEE spectra overlay + self.ebeam_panel = wx.Panel(self.calib_panel) + self.ebeam_sizer = wx.BoxSizer(wx.HORIZONTAL) + self.ebeam_panel.SetSizer(self.ebeam_sizer) + + self.ebeam_figure = mpl.figure.Figure(figsize=(4,2.3)) + self.ebeam_canvas = FigureCanvas(self.ebeam_panel, -1, self.ebeam_figure) + self.ebeam_toolbar = NavigationToolbar(self.ebeam_canvas) + self.ebeam_toolbar.SetWindowStyle(wx.TB_VERTICAL) + self.ebeam_toolbar.Realize() + + self.ebeam_sizer.Add(self.ebeam_canvas, 1, flag=wx.EXPAND | wx.ALL) + self.ebeam_sizer.Add(self.ebeam_toolbar, 0) + + self.calib_grid_sizer.Add(self.ebeam_panel, pos=(1, 1), flag=wx.EXPAND | wx.ALL) + + # Display and export calibrated values + self.results_panel = wx.Panel(self.calib_panel) + self.results_box = wx.StaticBox(self.results_panel, label='Calibration Results', size=(300, 200)) + self.results_sizer = wx.StaticBoxSizer(self.results_box, wx.VERTICAL) + self.results_panel.SetSizer(self.results_sizer) + self.results_text_sizer = wx.GridBagSizer(3, 3) + + self.results_text_sizer.Add( + wx.StaticText(self.results_box, label='FEE eV per pixel:', size=(120, -1)), + pos=(0,0), border=5, flag=wx.TOP) + self.eV_per_px_text = wx.StaticText(self.results_box, label='', size=(180, -1)) + self.results_text_sizer.Add(self.eV_per_px_text, pos=(0,1), border=5, flag=wx.TOP) + + self.results_text_sizer.Add( + wx.StaticText(self.results_box, label='FEE eV offset:', size=(120, -1)), + pos=(1,0), border=5, flag=wx.TOP) + self.eV_offset_text = wx.StaticText(self.results_box, label='', size=(180, -1)) + self.results_text_sizer.Add(self.eV_offset_text, pos=(1,1), border=5, flag=wx.TOP) + + self.results_text_sizer.Add( + wx.StaticText(self.results_box, label='Ebeam offset:', size=(120, -1)), + pos=(2,0), border=5, flag=wx.TOP) + self.ebeam_offset_text = wx.StaticText(self.results_box, label='', size=(180, -1)) + self.results_text_sizer.Add(self.ebeam_offset_text, pos=(2,1), border=5, flag=wx.TOP) + + self.results_sizer.Add(self.results_text_sizer) + + self.export_button = wx.Button(self.results_box, label='Save calibration', size=(300, -1)) + self.results_sizer.Add(self.export_button) + + self.save_notif_text = wx.StaticText(self.results_box, label='') + self.results_text_sizer.Add(self.save_notif_text, pos=(3,0)) + + self.calib_grid_sizer.Add(self.results_panel, pos=(1,2), flag=wx.ALIGN_CENTER) + + self.calib_sizer.Add(self.calib_grid_sizer, flag=wx.EXPAND | wx.ALL, border=10) + self.main_sizer.Add(self.calib_panel, 1, flag=wx.EXPAND | wx.ALL, border=10) + + # Bindings + self.Bind(wx.EVT_BUTTON, self.onAddScanRuns, self.scan_runs_button_add) + self.Bind(wx.EVT_BUTTON, self.onClearScanRuns, self.scan_runs_button_clear) + self.Bind(wx.EVT_BUTTON, self.onRunFEECalib, self.scan_runs_button_run) + self.Bind(wx.EVT_BUTTON, self.onRunsRefresh, self.ebeam_runs_refresh_button) + self.Bind(wx.EVT_BUTTON, self.onRunsClear, self.ebeam_runs_clear_button) + self.Bind(wx.EVT_BUTTON, self.onRunEbeamCalib, self.ebeam_runs_launch_button) + self.Bind(wx.EVT_BUTTON, self.onSaveCalib, self.export_button) + self.Bind(wx.EVT_SIZE, self.onSize) + + self.Layout() + self.Fit() + self.onSize() + + def onSize(self, e=None): + self.size_stale = True + # Caution: attempting to resize causes frequent core dumps!! + if e is not None: + e.Skip() + + def onAddScanRuns(self, e): + n_rows = self.scan_runs_list.GetItemCount() + self.scan_runs_list.InsertItem(n_rows, 0) + + def onClearScanRuns(self, e): + self.scan_runs_experiment.SetValue('mfxl1028322') + n_rows = self.scan_runs_list.GetItemCount() + self.scan_runs_list.DeleteAllItems() + for i in range(n_rows): + # self.scan_runs_list.InsertItem(0, 0) + self.scan_runs_list.InsertItem(i, str(i+1)) + self.scan_runs_list.SetItem(i, 1, str(10190 + 5*i)) + e.Skip() + + def onRunFEECalib(self, e): + self.clear_FEE_calib() + self.refresh_runs() + fee_runs = [] + fee_energies = [] + + self.experiment = self.scan_runs_experiment.GetValue() + if self.experiment.strip() == '': + if self.main.params.facility.name == 'lcls': + self.experiment = self.main.params.facility.lcls.experiment + else: + self.experiment = None + + #TODO: validation during input instead? + self.fee_runs = [] + self.fee_energies = [] + for row in range(self.scan_runs_list.GetItemCount()): + run = self.scan_runs_list.GetItem(itemIdx=row, col=0).GetText() + if not run in self.all_runs: + dlg = wx.MessageDialog(self, + message=f'Run {run} not recognized.', + caption='Error', + style=wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + return + self.fee_runs.append(run) + + try: + energy = float(self.scan_runs_list.GetItem(itemIdx=row, col=1).GetText()) + except ValueError: + dlg = wx.MessageDialog(self, + message=f'Energy {energy} for run {run} not a float.', + caption='Error', + style=wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + return + self.fee_energies.append(energy) + self.fee_calib_stale = True + e.Skip() + + def onRunEbeamCalib(self, e): + #self.ebeam_offset_text.SetLabel('') + self.selected_runs = self.ebeam_runs_selection.ctr.GetCheckedStrings() + self.ebeam_calib_stale = True + e.Skip() + + def onRunsRefresh(self, e): + self.refresh_runs() + e.Skip() + + def onRunsClear(self, e): + self.ebeam_runs_selection.ctr.SetCheckedItems([]) + self.ebeam_figure.clear() + self.ebeam_offset_text.SetLabel('') + self.save_notif_text.SetLabel('') + e.Skip() + + def onSaveCalib(self, e): + save_dlg = wx.FileDialog(self, + message='Save FEE Calibration', + defaultDir=os.path.join(str(self.main.db.params.output_folder), '..', 'fee'), + defaultFile='fee_calib.phil', + wildcard='*.phil', + style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) + if save_dlg.ShowModal() == wx.ID_OK: + self.write_calib_phil(save_dlg.GetPath()) + e.Skip() + + def refresh_runs(self): + try: + all_runs = self.main.db.get_all_runs() + for run in all_runs: + if run.run not in self.all_runs: + self.ebeam_runs_selection.ctr.Append(str(run.run)) + self.all_runs.append(run.run) + except AttributeError: + print('Unable to find runs') + + def clear_FEE_calib(self): + for figure in (self.trendline_figure, self.spectra_figure, self.ebeam_figure): + figure.clear() + for text in (self.eV_per_px_text, self.eV_offset_text, self.ebeam_offset_text, self.save_notif_text): + text.SetLabel('') + + def write_calib_phil(self, path): + lines = [] + if self.fee_eV_per_pixel is not None: + lines.append(f'spectrum_eV_per_pixel={self.fee_eV_per_pixel}\n') + if self.fee_eV_offset is not None: + lines.append(f'spectrum_eV_offset={self.fee_eV_offset}\n') + if self.ebeam_eV_offset is not None: + lines.append(f'ebeam_eV_offset={self.ebeam_eV_offset}\n') + if self.ebeam_wavelength_offset is not None: + lines.append(f'wavelength_offset={self.ebeam_wavelength_offset}\n') + with open(path, 'w') as outfile: + for line in lines: + outfile.write(line) + print(f'Wrote calibrated values to {path}') + class TrialsTab(BaseTab): def __init__(self, parent, main): BaseTab.__init__(self, parent=parent) From fe54827c8a02fa60e51b07f450ae670e2071d793 Mon Sep 17 00:00:00 2001 From: Iris Young Date: Tue, 26 Mar 2024 03:40:43 -0700 Subject: [PATCH 255/748] add py2 syntax exceptions --- .azure-pipelines/py2_syntax_exceptions.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.azure-pipelines/py2_syntax_exceptions.txt b/.azure-pipelines/py2_syntax_exceptions.txt index 1c33954913..4a70a6bf1c 100644 --- a/.azure-pipelines/py2_syntax_exceptions.txt +++ b/.azure-pipelines/py2_syntax_exceptions.txt @@ -3,6 +3,8 @@ crys3d/hklviewer/xtriage_runner.py crys3d/regression/tst_websocket.py libtbx/auto_build/conda_build/create_custom_bin.py serialtbx/util/energy_scan_notch_finder.py +xfel/ui/components/xfel_gui_init.py +xfel/ui/components/ebeam_plotter.py xfel/ui/db/dxtbx_db.py xfel/euxfel/agipd_from_defs.py xfel/euxfel/agipd_cxigeom2nexus.py From 0c9c2f6d59facf766ca8066a6406b0e6063e344e Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Tue, 26 Mar 2024 09:17:03 -0700 Subject: [PATCH 256/748] CI: add Python 3.7 for syntax exception [skip ci] --- .azure-pipelines/syntax.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.azure-pipelines/syntax.yml b/.azure-pipelines/syntax.yml index 7bc06d474c..a0596e20b2 100644 --- a/.azure-pipelines/syntax.yml +++ b/.azure-pipelines/syntax.yml @@ -42,7 +42,7 @@ jobs: echo Removing $f rm $f; done displayName: Remove Python 3 only files for Python 2 syntax check - condition: eq(variables['PYTHON_VERSION'], '2.7') + condition: or(eq(variables['PYTHON_VERSION'], '2.7'), eq(variables['PYTHON_VERSION'], '3.7')) - script: | source activate py$(PYTHON_VERSION) From 2b5805fc449998671d8b2dcb95cf32e0ca9b9db1 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 26 Mar 2024 14:24:13 -0600 Subject: [PATCH 257/748] Add convert_string_to_cif_long --- iotbx/map_model_manager.py | 14 ++++++-- libtbx/test_utils/__init__.py | 65 ++++++++++++++++++++++++++++++----- 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/iotbx/map_model_manager.py b/iotbx/map_model_manager.py index 6735e299ae..e4079cbe86 100644 --- a/iotbx/map_model_manager.py +++ b/iotbx/map_model_manager.py @@ -4416,7 +4416,7 @@ def external_sharpen(self, kw = self.set_map_id_lists(kw) - print ("Running external map sharpening ", file = self.log) + print ("\nRunning external map sharpening ", file = self.log) kw['map_id_2'] = map_id_external_map kw['is_external_based'] = True @@ -4569,6 +4569,7 @@ def model_sharpen(self, coordinate_shift_to_apply_before_tlso = None, sharpen_all_maps = False, remove_overall_anisotropy = True, + save_model_map = False, ): ''' Scale map_id with scale factors identified from map_id vs model @@ -4652,6 +4653,7 @@ def model_sharpen(self, del kw['optimize_with_model'] # REQUIRED del kw['find_tls_from_model'] # REQUIRED del kw['overall_sharpen_before_and_after_local'] # REQUIRED + del kw['save_model_map'] # REQUIRED # Make a copy of this map_model manager so we can modify it without @@ -4745,6 +4747,15 @@ def model_sharpen(self, working_mmm._sharpen_map(**kw) # And set this map_manager + if save_model_map: + mm = working_mmm.get_map_manager_by_id(map_id_model_map) + if mm: + print("Copying map '%s' in map_manager '%s' to '%s'" %( + map_id_model_map,working_mmm.name,self.name), + file = self.log) + self.add_map_manager_by_id( + map_manager = working_mmm.get_map_manager_by_id(map_id_model_map), + map_id = map_id_model_map) for id in kw['map_id_scaled_list']: if working_mmm.get_map_manager_by_id(id): print("Copying map '%s' in map_manager '%s' to '%s'" %( @@ -5023,7 +5034,6 @@ def _sharpen_map(self, len(direction_vectors)), file = self.log) else: print("Estimating scale factors ", file = self.log) - # Analyze spectrum in map_id (will apply it to map_id_to_be_scaled) scaling_group_info = working_mmm._get_weights_in_shells(n_bins, d_min, diff --git a/libtbx/test_utils/__init__.py b/libtbx/test_utils/__init__.py index d1950c87ff..73967e66d5 100644 --- a/libtbx/test_utils/__init__.py +++ b/libtbx/test_utils/__init__.py @@ -858,12 +858,27 @@ def convert_pdb_to_cif_for_pdb_str(locals, chain_addition = "ZXLONG", for key in keys: if (not key.startswith(key_str)) or (type(locals[key]) != type("abc")): continue - from iotbx.pdb.utils import get_pdb_input + original_string = locals[key] + + new_string = convert_string_to_cif_long(original_string, + chain_addition = chain_addition, + hetatm_name_addition = hetatm_name_addition) + locals[key] = new_string + if print_new_string: + print("\n",79*"=","\n", + "ORIGINAL STRING '%s':\n%s" %(key, original_string)) + print("\n",79*"=","\n", + "MODIFIED STRING '%s':\n%s" %(key, new_string), + "\n",79*"=","\n") + +def convert_string_to_cif_long(original_string, chain_addition = "ZXLONG", + hetatm_name_addition = "ZY"): + from iotbx.pdb.utils import get_pdb_input pdb_inp = get_pdb_input(original_string) ph = pdb_inp.construct_hierarchy() if ph.overall_counts().n_residues < 1: - continue + return "" for model in ph.models(): for chain in model.chains(): chain.id = "%s%s" %(chain.id.strip(),chain_addition) @@ -876,12 +891,44 @@ def convert_pdb_to_cif_for_pdb_str(locals, chain_addition = "ZXLONG", break new_string = ph.as_mmcif_string( crystal_symmetry = pdb_inp.crystal_symmetry()) - locals[key] = new_string - if print_new_string: - print("\n",79*"=","\n", - "ORIGINAL STRING '%s':\n%s" %(key, original_string)) - print("\n",79*"=","\n", - "MODIFIED STRING '%s':\n%s" %(key, new_string), - "\n",79*"=","\n") + return new_string +def tst_convert(): + text = """ +ATOM 1 N VAL A 1 -5.111 0.049 13.245 1.00 9.36 N +""" + assert convert_string_to_cif_long(text).strip() == """ +data_phenix +loop_ + _atom_site.group_PDB + _atom_site.id + _atom_site.label_atom_id + _atom_site.label_alt_id + _atom_site.label_comp_id + _atom_site.auth_asym_id + _atom_site.auth_seq_id + _atom_site.pdbx_PDB_ins_code + _atom_site.Cartn_x + _atom_site.Cartn_y + _atom_site.Cartn_z + _atom_site.occupancy + _atom_site.B_iso_or_equiv + _atom_site.type_symbol + _atom_site.pdbx_formal_charge + _atom_site.label_asym_id + _atom_site.label_entity_id + _atom_site.label_seq_id + _atom_site.pdbx_PDB_model_num + ATOM 1 N . VAL AZXLONG 1 ? -5.11100 0.04900 13.24500 1.000 9.36000 N ? A ? 1 1 + +loop_ + _chem_comp.id + VAL + +loop_ + _struct_asym.id + A +""".strip() + if (__name__ == "__main__"): + tst_convert() exercise() From 938b07f91276afc271a427af319dea0adbcfa5ec Mon Sep 17 00:00:00 2001 From: David Waterman Date: Fri, 22 Mar 2024 13:57:38 +0000 Subject: [PATCH 258/748] label_string() may return None --- cctbx/miller/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cctbx/miller/__init__.py b/cctbx/miller/__init__.py index c48ad9b73d..6dc6731706 100644 --- a/cctbx/miller/__init__.py +++ b/cctbx/miller/__init__.py @@ -3978,7 +3978,7 @@ def __repr__(self): """ mstr = self.crystal_symmetry().__repr__() if self._info: - mstr = mstr + "\n" + self._info.label_string() + mstr = mstr + "\n" + str(self._info.label_string()) mstr = mstr + "\n" + self._data.__repr__() if self._sigmas: mstr = mstr + "\n" + self._sigmas.__repr__() From 65e4c01dbccd41e3e94da5faa48033193862d68a Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 26 Mar 2024 16:50:39 -0700 Subject: [PATCH 259/748] Allow cross special position --- mmtbx/hydrogens/reduce_hydrogen.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index e8de77ddf6..91f0358bec 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -221,6 +221,7 @@ def run(self): p.pdb_interpretation.clash_guard.nonbonded_distance_threshold=None p.pdb_interpretation.use_neutron_distances = self.use_neutron_distances p.pdb_interpretation.proceed_with_excessive_length_bonds=True + p.pdb_interpretation.allow_polymer_cross_special_position=True #p.pdb_interpretation.automatic_linking.link_metals = True p.pdb_interpretation.automatic_linking.link_residues = True p.pdb_interpretation.automatic_linking.exclude_hydrogens_from_bonding_decisions = True From 9eb697ca9cc2fca6f729f018ecc997ead57dbfee Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 28 Mar 2024 12:14:04 -0700 Subject: [PATCH 260/748] Use run_program instead of easy_run --- mmtbx/programs/polder.py | 80 ++++++------- mmtbx/regression/tst_polder.py | 197 ++++++++++++++++++--------------- 2 files changed, 150 insertions(+), 127 deletions(-) diff --git a/mmtbx/programs/polder.py b/mmtbx/programs/polder.py index bfa21af305..99bb6df504 100644 --- a/mmtbx/programs/polder.py +++ b/mmtbx/programs/polder.py @@ -248,33 +248,34 @@ def prepare_fobs_rfree(self, f_obs, r_free_flags): # --------------------------------------------------------------------------- def check_selection(self, pdb_hierarchy): - print("*"*79, file=self.logger) - print('Selecting atoms...\n', file=self.logger) - print('Selection string:', self.params.solvent_exclusion_mask_selection) - - selection_bool = pdb_hierarchy.atom_selection_cache().selection( - string = self.params.solvent_exclusion_mask_selection) - n_selected = selection_bool.count(True) - n_selected_all = pdb_hierarchy.atom_selection_cache().selection( - string = 'all').count(True) - if(n_selected == 0): - raise Sorry("No atoms where selected. Check selection syntax again.") - if (n_selected/n_selected_all > 0.5): - raise Sorry("""More than half of total number of atoms selected. Omit - selection should be smaller, such as one ligand or a few residues.""") - - print('Number of atoms selected:', n_selected, file=self.logger) - pdb_hierarchy_selected = pdb_hierarchy.select(selection_bool) - ligand_str = pdb_hierarchy_selected.as_pdb_string() - print(ligand_str, file=self.logger) - print("*"*79, file=self.logger) - - return selection_bool + print("*"*79, file=self.logger) + print('Selecting atoms...\n', file=self.logger) + print('Selection string:', self.params.solvent_exclusion_mask_selection, + file=self.logger) + + selection_bool = pdb_hierarchy.atom_selection_cache().selection( + string = self.params.solvent_exclusion_mask_selection) + n_selected = selection_bool.count(True) + n_selected_all = pdb_hierarchy.atom_selection_cache().selection( + string = 'all').count(True) + if(n_selected == 0): + raise Sorry("No atoms where selected. Check selection syntax again.") + if (n_selected/n_selected_all > 0.5): + raise Sorry("""More than half of total number of atoms selected. Omit + selection should be smaller, such as one ligand or a few residues.""") + + print('Number of atoms selected:', n_selected, file=self.logger) + pdb_hierarchy_selected = pdb_hierarchy.select(selection_bool) + ligand_str = pdb_hierarchy_selected.as_pdb_string() + print(ligand_str, file=self.logger) + print("*"*79, file=self.logger) + + return selection_bool # --------------------------------------------------------------------------- def broadcast_rfactors(self, r_work, r_free): - print('R_work = %6.4f R_free = %6.4f' % (r_work, r_free)) + print('R_work = %6.4f R_free = %6.4f' % (r_work, r_free), file=self.logger) print ('*'*79, file=self.logger) # --------------------------------------------------------------------------- @@ -327,26 +328,26 @@ def write_files(self, results, f_obs): print('File %s was written.' % polder_file_name, file=self.logger) # --------------------------------------------------------------------------- + def print_validation(self, results): vr = results.validation_results if vr is None: return '' - print('Map 1: calculated Fobs with ligand') - print('Map 2: calculated Fobs without ligand') - print('Map 3: real Fobs data') - print('CC(1,2): %6.4f' % vr.cc12) - print('CC(1,3): %6.4f' % vr.cc13) - print('CC(2,3): %6.4f' % vr.cc23) - print('Peak CC:') - print('CC(1,2): %6.4f' % vr.cc12_peak) - print('CC(1,3): %6.4f' % vr.cc13_peak) - print('CC(2,3): %6.4f' % vr.cc23_peak) - print('q D(1,2) D(1,3) D(2,3)') + print('Map 1: calculated Fobs with ligand', file=self.logger) + print('Map 2: calculated Fobs without ligand', file=self.logger) + print('Map 3: real Fobs data', file=self.logger) + print('CC(1,2): %6.4f' % vr.cc12, file=self.logger) + print('CC(1,3): %6.4f' % vr.cc13, file=self.logger) + print('CC(2,3): %6.4f' % vr.cc23, file=self.logger) + print('Peak CC:', file=self.logger) + print('CC(1,2): %6.4f' % vr.cc12_peak, file=self.logger) + print('CC(1,3): %6.4f' % vr.cc13_peak, file=self.logger) + print('CC(2,3): %6.4f' % vr.cc23_peak, file=self.logger) + print('q D(1,2) D(1,3) D(2,3)', file=self.logger) for c,d12_,d13_,d23_ in zip(vr.cutoffs,vr.d12,vr.d13,vr.d23): - print('%4.2f %6.4f %6.4f %6.4f'%(c,d12_,d13_,d23_)) + print('%4.2f %6.4f %6.4f %6.4f'%(c,d12_,d13_,d23_), file=self.logger) ### if(self.params.debug): - #box_1.write_ccp4_map(file_name="box_1_polder.ccp4") self.write_map_box( box = vr.box_1, filename = "box_1_polder.ccp4") @@ -401,6 +402,10 @@ def run(self): xrs = model.get_xray_structure() selection_bool = self.check_selection(pdb_hierarchy = ph) + #print(self.params.model_file_name) + #print(self.data_manager.get_default_model_name()) + #STOP() + f_obs, r_free_flags = self.get_fobs_rfree(crystal_symmetry = cs) print('Input data...', file=self.logger) print(' Reflection data:', f_obs.info().labels, file=self.logger) @@ -449,4 +454,5 @@ def run(self): def get_results(self): - return group_args(message=self.message) + return group_args( + message=self.message) diff --git a/mmtbx/regression/tst_polder.py b/mmtbx/regression/tst_polder.py index eeb7e0f17d..f984a3315f 100644 --- a/mmtbx/regression/tst_polder.py +++ b/mmtbx/regression/tst_polder.py @@ -1,13 +1,116 @@ from __future__ import absolute_import, division, print_function -from libtbx import easy_run -import time -from libtbx.test_utils import approx_equal +import time, os import iotbx.pdb +from mmtbx.programs import fmodel, polder +from iotbx.cli_parser import run_program from iotbx import reflection_file_reader +from libtbx.test_utils import approx_equal +from libtbx.utils import null_out from cctbx import miller from cctbx import maptbx from scitbx.array_family import flex +# --------------------------------------------------------------------------- + +def get_map(cg, mc): + fft_map = miller.fft_map( + crystal_gridding = cg, + fourier_coefficients = mc) + fft_map.apply_sigma_scaling() + return fft_map.real_map_unpadded() + +def get_map_stats(map, sites_frac): + map_values = flex.double() + for sf in sites_frac: + map_values.append(map.eight_point_interpolation(sf)) + return map_values + +def format_map_stat(m): + return m.min_max_mean().as_tuple(), (m>flex.mean(m)).count(True) + +# --------------------------------------------------------------------------- + +def exercise_00(prefix="tst_polder"): + """ + Test for phenix.polder. + """ + + # save test model as file + model_fn = "tst_polder.pdb" + with open(model_fn, "w") as f: + f.write(pdb_str) + + # create test data with phenix.fmodel + mtz_fn = "tst_polder.mtz" + args = [ + model_fn, + "high_res=2.0", + "type=real", + "label=f-obs", + "k_sol=0.4", + "b_sol=50", + "output.file_name=%s" % mtz_fn] + run_program(program_class=fmodel.Program, args=args, logger=null_out()) + + # run polder on test files + args_polder = [ + model_fn, + mtz_fn, + "sphere_radius=3", + 'solvent_exclusion_mask_selection="chain A" ', + 'debug="True"' + ] + run_program(program_class=polder.Program, args=args_polder, logger=null_out()) + + miller_arrays = reflection_file_reader.any_reflection_file(file_name = + "tst_polder_polder_map_coeffs.mtz").as_miller_arrays() + mc_polder, mc_bias_omit, mc_omit = [None,]*3 + for ma in miller_arrays: + lbl = ma.info().label_string() + if(lbl == "mFo-DFc_polder,PHImFo-DFc_polder"): + mc_polder = ma.deep_copy() + if(lbl == "mFo-DFc_bias_omit,PHImFo-DFc_bias_omit"): + mc_bias_omit = ma.deep_copy() + if(lbl == "mFo-DFc_omit,PHImFo-DFc_omit"): + mc_omit = ma.deep_copy() + assert [mc_polder, mc_bias_omit, mc_omit].count(None)==0 + cg = maptbx.crystal_gridding( + unit_cell = mc_polder.unit_cell(), + d_min = mc_polder.d_min(), + resolution_factor = 0.25, + space_group_info = mc_polder.space_group_info()) + map_polder = get_map(cg=cg, mc=mc_polder) + map_bias_omit = get_map(cg=cg, mc=mc_bias_omit) + map_omit = get_map(cg=cg, mc=mc_omit) + pdb_hierarchy = iotbx.pdb.input( + source_info=None, lines=pdb_str).construct_hierarchy() + sel = pdb_hierarchy.atom_selection_cache().selection(string = "chain A") + sites_cart_lig = pdb_hierarchy.atoms().extract_xyz().select(sel) + sites_frac_lig = mc_polder.unit_cell().fractionalize(sites_cart_lig) + mp = get_map_stats(map=map_polder, sites_frac=sites_frac_lig) + mlo = get_map_stats(map=map_bias_omit, sites_frac=sites_frac_lig) + mo = get_map_stats(map=map_omit, sites_frac=sites_frac_lig) + # + mmm_mp = mp.min_max_mean().as_tuple() + mmm_o = mo.min_max_mean().as_tuple() + #print("Polder map : %7.3f %7.3f %7.3f"%mmm_mp) + #print("Biased map : %7.3f %7.3f %7.3f"%mlo.min_max_mean().as_tuple()) + #print("Omit : %7.3f %7.3f %7.3f"%mmm_o) + # + assert approx_equal(mmm_mp, [0.329, 6.119, 3.333], eps=0.1) + assert approx_equal(mmm_o, [-2.838, 0.901, -1.385], eps=0.1) + + # Clean up files + os.remove(model_fn) + os.remove(mtz_fn) + os.remove("box_1_polder.ccp4") + os.remove("box_2_polder.ccp4") + os.remove("box_3_polder.ccp4") + os.remove("box_polder.pdb") + os.remove("tst_polder_polder_map_coeffs.mtz") + +# --------------------------------------------------------------------------- + pdb_str = """\ CRYST1 28.992 28.409 27.440 90.00 90.00 90.00 P 1 ATOM 1 N ALA E 1 9.731 23.364 9.222 1.00 20.00 N @@ -148,93 +251,7 @@ END """ -def get_map(cg, mc): - fft_map = miller.fft_map( - crystal_gridding = cg, - fourier_coefficients = mc) - fft_map.apply_sigma_scaling() - return fft_map.real_map_unpadded() - -def get_map_stats(map, sites_frac): - map_values = flex.double() - for sf in sites_frac: - map_values.append(map.eight_point_interpolation(sf)) - return map_values - -def format_map_stat(m): - return m.min_max_mean().as_tuple(), (m>flex.mean(m)).count(True) - -def exercise_00(prefix="tst_polder"): - """ - Test for phenix.polder. - """ - f = open("%s.pdb" % prefix, "w") - f.write(pdb_str) - f.close() - cmd = " ".join([ - "phenix.fmodel", - "%s.pdb"%prefix, - "high_res=2.0", - "type=real", - "label=f-obs", - "k_sol=0.4", - "b_sol=50", - "output.file_name=%s.mtz"%prefix, - "&> %s.log"%prefix - ]) - print(cmd) - easy_run.call(cmd) - # - cmd = " ".join([ - "phenix.polder", - "%s.pdb" % prefix, - "%s.mtz" % prefix, - "sphere_radius=3", - 'solvent_exclusion_mask_selection="chain A" ', - 'debug="True"', - "&> %s.log" % prefix - ]) - print(cmd) - assert not easy_run.call(cmd) - # - miller_arrays = reflection_file_reader.any_reflection_file(file_name = - "tst_polder_polder_map_coeffs.mtz").as_miller_arrays() - mc_polder, mc_bias_omit, mc_omit = [None,]*3 - for ma in miller_arrays: - lbl = ma.info().label_string() - if(lbl == "mFo-DFc_polder,PHImFo-DFc_polder"): - mc_polder = ma.deep_copy() - if(lbl == "mFo-DFc_bias_omit,PHImFo-DFc_bias_omit"): - mc_bias_omit = ma.deep_copy() - if(lbl == "mFo-DFc_omit,PHImFo-DFc_omit"): - mc_omit = ma.deep_copy() - assert [mc_polder, mc_bias_omit, mc_omit].count(None)==0 - cg = maptbx.crystal_gridding( - unit_cell = mc_polder.unit_cell(), - d_min = mc_polder.d_min(), - resolution_factor = 0.25, - space_group_info = mc_polder.space_group_info()) - map_polder = get_map(cg=cg, mc=mc_polder) - map_bias_omit = get_map(cg=cg, mc=mc_bias_omit) - map_omit = get_map(cg=cg, mc=mc_omit) - pdb_hierarchy = iotbx.pdb.input( - source_info=None, lines=pdb_str).construct_hierarchy() - sel = pdb_hierarchy.atom_selection_cache().selection(string = "chain A") - sites_cart_lig = pdb_hierarchy.atoms().extract_xyz().select(sel) - sites_frac_lig = mc_polder.unit_cell().fractionalize(sites_cart_lig) - mp = get_map_stats(map=map_polder, sites_frac=sites_frac_lig) - mlo = get_map_stats(map=map_bias_omit, sites_frac=sites_frac_lig) - mo = get_map_stats(map=map_omit, sites_frac=sites_frac_lig) - # - mmm_mp = mp.min_max_mean().as_tuple() - mmm_o = mo.min_max_mean().as_tuple() - print("Polder map : %7.3f %7.3f %7.3f"%mmm_mp) - print("Biased map : %7.3f %7.3f %7.3f"%mlo.min_max_mean().as_tuple()) - print("Omit : %7.3f %7.3f %7.3f"%mmm_o) - # - assert approx_equal(mmm_mp, [0.329, 6.119, 3.333], eps=0.1) - assert approx_equal(mmm_o, [-2.838, 0.901, -1.385], eps=0.1) - +# --------------------------------------------------------------------------- if (__name__ == "__main__"): t0 = time.time() From 9a34ece73088ca0730021ba959e8a020b6bd1fb9 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 28 Mar 2024 14:23:49 -0700 Subject: [PATCH 261/748] polder tests: use data manager, avoid code duplication --- mmtbx/programs/polder.py | 4 +- mmtbx/regression/tst_polder_1.py | 357 ++++++++++++++++--------------- 2 files changed, 187 insertions(+), 174 deletions(-) diff --git a/mmtbx/programs/polder.py b/mmtbx/programs/polder.py index 99bb6df504..1b88ebb85c 100644 --- a/mmtbx/programs/polder.py +++ b/mmtbx/programs/polder.py @@ -325,6 +325,7 @@ def write_files(self, results, f_obs): if (self.params.output_file_name_prefix is not None): polder_file_name = self.params.output_file_name_prefix + "_" + polder_file_name mtz_object.write(file_name = polder_file_name) + self.output_file_name = polder_file_name print('File %s was written.' % polder_file_name, file=self.logger) # --------------------------------------------------------------------------- @@ -455,4 +456,5 @@ def run(self): def get_results(self): return group_args( - message=self.message) + message = self.message, + output_file = self.output_file_name) diff --git a/mmtbx/regression/tst_polder_1.py b/mmtbx/regression/tst_polder_1.py index 12f1fb640e..570d875d67 100644 --- a/mmtbx/regression/tst_polder_1.py +++ b/mmtbx/regression/tst_polder_1.py @@ -1,15 +1,194 @@ from __future__ import absolute_import, division, print_function -from libtbx import easy_run -import time +import time, os from libtbx.test_utils import approx_equal +from iotbx.data_manager import DataManager +from iotbx.cli_parser import run_program import iotbx.pdb +from mmtbx.programs import polder from iotbx import reflection_file_reader -from cctbx import miller from cctbx import maptbx from scitbx.array_family import flex from six.moves import range +from libtbx.utils import null_out +from mmtbx.regression.tst_polder import get_map, get_map_stats -pdb_str = """\ + +def generate_r_free_flags_systematic(miller_array): + result = flex.bool() + for i in range(miller_array.indices().size()): + if(i%10==0): result.append(True) + else: result.append(False) + return miller_array.array(data = result) + +# --------------------------------------------------------------------------- + +def exercise_01(fobs_1, fobs_2, flags_1, flags_2): + ''' + Test reading one mtz with different choices for F and Rfree + ''' + mtz = fobs_1.as_mtz_dataset(column_root_label="FP1") + mtz.add_miller_array(fobs_2, column_root_label="FP2") + mtz.add_miller_array(flags_1, column_root_label="R-free-flags-1") + mtz.add_miller_array(flags_2, column_root_label="R-free-flags-2") + mtz.mtz_object().write("tst_polder_1_1.mtz") + # + selection = "chain A" + + args = [ + "tst_polder_1.pdb", + "tst_polder_1_1.mtz", + "sphere_radius=3", + 'solvent_exclusion_mask_selection="%s"' % selection, + "data_labels=FP1", + "r_free_flags_labels=R-free-flags-1", + "output_file_name_prefix=tst_polder_1_1"] + + r = run_program(program_class=polder.Program, args=args, logger=null_out()) + + check( + tuple_calc=[10.6, 16.0, 13.5], + selection=selection, + filename = r.output_file) + + os.remove("tst_polder_1_1.mtz") + os.remove(r.output_file) + +# --------------------------------------------------------------------------- + +def exercise_02(fobs_1, flags_1): + ''' + Test reading two cns files: one with Fobs, one with Rfree; + without specifying labels --> test automatic machinery + ''' + with open("tst_polder_1_2.cns", "w") as file_object: + fobs_1.export_as_cns_hkl( + file_object=file_object, + file_name="tst_polder_1_2.cns", + info=["calculated structure factors FP1"]) + # + with open("tst_polder_1_2_free.cns", "w") as file_object: + flags_1.export_as_cns_hkl( + file_object=file_object, + file_name="tst_polder_1_2_free.cns", + info=["R-free-flags for FP1"]) + # + selection = "chain E and resseq 14" + args = [ + "tst_polder_1.pdb", + "tst_polder_1_2.cns", + "tst_polder_1_2_free.cns", + "sphere_radius=5", + 'solvent_exclusion_mask_selection="%s"' % selection, + "output_file_name_prefix=tst_polder_1_2"] + + r = run_program(program_class=polder.Program, args=args, logger=null_out()) + + check( + tuple_calc=[10.7, 15.1, 13.4], + selection=selection, + filename = r.output_file) + + os.remove("tst_polder_1_2.cns") + os.remove("tst_polder_1_2_free.cns") + os.remove(r.output_file) + +# --------------------------------------------------------------------------- + +def exercise_03(fobs_2, flags_2): + ''' + Test reading model as cif, Fobs from mtz and Rfree from cns file + ''' + mtz = fobs_2.as_mtz_dataset(column_root_label="FP1") + mtz.mtz_object().write("tst_polder_1_3.mtz") + with open("tst_polder_1_3.cns", "w") as file_object: + flags_2.export_as_cns_hkl( + file_object=file_object, + file_name="tst_polder_1_3.cns", + info=["R-free-flags for FP1"]) + # + selection = "chain E and resseq 7" + args = [ + "tst_polder_1.cif", + "tst_polder_1_3.mtz", + "tst_polder_1_3.cns", + "sphere_radius=5", + 'solvent_exclusion_mask_selection="%s"' % selection, + "output_file_name_prefix=tst_polder_1_3"] + + r = run_program(program_class=polder.Program, args=args, logger=null_out()) + + check( + tuple_calc=[13.7, 20.3, 18.4], + selection=selection, + filename = r.output_file) + + # Clean up files + os.remove('tst_polder_1_3.mtz') + os.remove('tst_polder_1_3.cns') + os.remove(r.output_file) + +# --------------------------------------------------------------------------- + +def exercise(): + """ + Test for phenix.polder: Reading files. + """ + dm = DataManager(['model']) + dm.process_model_str("tst_polder_1.pdb", pdb_str) + model = dm.get_model() + dm.write_model_file(model.model_as_pdb(), + filename = "tst_polder_1.pdb", + overwrite = True) + dm.write_model_file(model.model_as_mmcif(), + filename = "tst_polder_1.cif", + overwrite = True) + xrs = model.get_xray_structure() + + fobs_1 = abs(xrs.structure_factors(d_min=3.0).f_calc()) + fobs_2 = abs(xrs.structure_factors(d_min=2.5).f_calc()) + flags_1 = generate_r_free_flags_systematic(miller_array=fobs_1) + flags_2 = generate_r_free_flags_systematic(miller_array=fobs_2) + + exercise_01(fobs_1, fobs_2, flags_1, flags_2) + exercise_02(fobs_1, flags_1) + exercise_03(fobs_2, flags_2) + + # Clean up files + os.remove('tst_polder_1.pdb') + os.remove('tst_polder_1.cif') + +# --------------------------------------------------------------------------- + +def check(tuple_calc, selection, filename): + miller_arrays = reflection_file_reader.any_reflection_file(file_name = + filename).as_miller_arrays() + mc_polder = None + for ma in miller_arrays: + lbl = ma.info().label_string() + if(lbl == "mFo-DFc_polder,PHImFo-DFc_polder"): + mc_polder = ma.deep_copy() + assert (mc_polder is not None) + cg = maptbx.crystal_gridding( + unit_cell = mc_polder.unit_cell(), + d_min = mc_polder.d_min(), + resolution_factor = 0.25, + space_group_info = mc_polder.space_group_info()) + map_polder = get_map(cg=cg, mc=mc_polder) + pdb_hierarchy = iotbx.pdb.input( + source_info=None, lines=pdb_str).construct_hierarchy() + sel = pdb_hierarchy.atom_selection_cache().selection(string = selection) + sites_cart_lig = pdb_hierarchy.atoms().extract_xyz().select(sel) + sites_frac_lig = mc_polder.unit_cell().fractionalize(sites_cart_lig) + mp = get_map_stats(map=map_polder, sites_frac=sites_frac_lig) + # + mmm_mp = mp.min_max_mean().as_tuple() + #print("Polder map : %7.3f %7.3f %7.3f" % mmm_mp) + assert approx_equal(mmm_mp, tuple_calc, eps=1.0), "\ + calculated is %s and expected is %s" % (mmm_mp, tuple_calc) + +# --------------------------------------------------------------------------- + +pdb_str = """ CRYST1 28.992 28.409 27.440 90.00 90.00 90.00 P 1 ATOM 1 N ALA E 1 9.731 23.364 9.222 1.00 20.00 N ATOM 2 CA ALA E 1 10.928 22.678 9.693 1.00 20.00 C @@ -149,175 +328,7 @@ END """ -def get_map(cg, mc): - fft_map = miller.fft_map( - crystal_gridding = cg, - fourier_coefficients = mc) - fft_map.apply_sigma_scaling() - return fft_map.real_map_unpadded() - -def get_map_stats(map, sites_frac): - map_values = flex.double() - for sf in sites_frac: - map_values.append(map.eight_point_interpolation(sf)) - return map_values - -def format_map_stat(m): - return m.min_max_mean().as_tuple(), (m>flex.mean(m)).count(True) - -def exercise_01(fobs_1, fobs_2, flags_1, flags_2, prefix): - mtz = fobs_1.as_mtz_dataset(column_root_label="FP1") - mtz.add_miller_array(fobs_2, column_root_label="FP2") - mtz.add_miller_array(flags_1, column_root_label="R-free-flags-1") - mtz.add_miller_array(flags_2, column_root_label="R-free-flags-2") - mtz.mtz_object().write(prefix+"_1.mtz") - # - selection = "chain A" - cmd = " ".join([ - "phenix.polder", - "tst_polder_1.pdb", - "%s_1.mtz" % prefix, - "sphere_radius=3", - 'solvent_exclusion_mask_selection="%s"' % selection, - "data_labels=FP1", - "output_file_name_prefix=tst_polder_1_1", - "r_free_flags_labels=R-free-flags-1", - "> %s_1.log" % prefix - ]) - print(cmd) - easy_run.call(cmd) - # - check( - tuple_calc=[10.6, 16.0, 13.5], - selection=selection, - prefix = prefix + '_1_') - -def exercise_02(fobs_1, flags_1, prefix): - with open(prefix+"_2.cns", "w") as file_object: - fobs_1.export_as_cns_hkl( - file_object=file_object, - file_name=prefix+"_2.cns", - info=["calculated structure factors FP1"]) - # - with open(prefix+"_2_free"+".cns", "w") as file_object: - flags_1.export_as_cns_hkl( - file_object=file_object, - file_name=prefix+"_2_free"+".cns", - info=["R-free-flags for FP1"]) - # - selection = "chain E and resseq 14" - cmd = " ".join([ - "phenix.polder", - "tst_polder_1.pdb", - "%s_2.cns" % prefix, - "%s_2_free.cns" % prefix, - "sphere_radius=5", - "output_file_name_prefix=tst_polder_1_2", - 'solvent_exclusion_mask_selection="%s"' % selection, - "> %s_2.log" % prefix - ]) - print(cmd) - easy_run.call(cmd) - check( - tuple_calc=[10.7, 15.1, 13.4], - selection=selection, - prefix = prefix + '_2_') - -def exercise_03(fobs_2, flags_2, prefix): - mtz = fobs_2.as_mtz_dataset(column_root_label="FP1") - mtz.mtz_object().write(prefix+"_3.mtz") - with open(prefix+"_3.cns", "w") as file_object: - flags_2.export_as_cns_hkl( - file_object=file_object, - file_name=prefix+"_3.cns", - info=["R-free-flags for FP1"]) - # - selection = "chain E and resseq 7" - cmd = " ".join([ - "phenix.polder", - "tst_polder_1.cif", - "%s_3.mtz" % prefix, - "%s_3.cns" % prefix, - "sphere_radius=5", - "output_file_name_prefix=tst_polder_1_3", - 'solvent_exclusion_mask_selection="%s"' % selection, - "> %s_3.log" % prefix - ]) - print(cmd) - easy_run.call(cmd) - check( - tuple_calc=[13.7, 20.3, 18.4], - selection=selection, - prefix = prefix + '_3_') - -def exercise(prefix="tst_polder_1"): - """ - Test for phenix.polder: Reading files. - """ - f = open("tst_polder_1.pdb", "w") - f.write(pdb_str) - f.close() - # - pdb_in = iotbx.pdb.input(source_info=None,lines=pdb_str) - xrs = pdb_in.xray_structure_simple() - pdb_hierarchy = iotbx.pdb.input( - source_info=None, lines=pdb_str).construct_hierarchy() - pdb_hierarchy.write_mmcif_file( - file_name="tst_polder_1.cif", crystal_symmetry=xrs.crystal_symmetry()) - # - def generate_r_free_flags_systematic(miller_array): - result = flex.bool() - for i in range(miller_array.indices().size()): - if(i%10==0): result.append(True) - else: result.append(False) - return miller_array.array(data = result) - fobs_1 = abs(xrs.structure_factors(d_min=3.0).f_calc()) - fobs_2 = abs(xrs.structure_factors(d_min=2.5).f_calc()) - flags_1 = generate_r_free_flags_systematic(miller_array=fobs_1) - flags_2 = generate_r_free_flags_systematic(miller_array=fobs_2) - # - print('*'*79) - print('Test reading one mtz with different choices for F and Rfree') - exercise_01(fobs_1, fobs_2, flags_1, flags_2, prefix="tst_polder_1") - print("command success") - print('*'*79) - print('Test reading two cns files: one with Fobs, one with Rfree') - print('Without specifying labels --> test automatic machinery') - exercise_02(fobs_1, flags_1, prefix="tst_polder_1") - print("command success") - print('*'*79) - print('Test reading model as cif, Fobs from mtz and Rfree from cns file') - exercise_03(fobs_2, flags_2, prefix="tst_polder_1") - print("command success") - print('*'*79) - -def check(tuple_calc, selection, prefix): - #print tuple_calc - miller_arrays = reflection_file_reader.any_reflection_file(file_name = - prefix+"polder_map_coeffs.mtz").as_miller_arrays() - mc_polder = None - for ma in miller_arrays: - lbl = ma.info().label_string() - if(lbl == "mFo-DFc_polder,PHImFo-DFc_polder"): - mc_polder = ma.deep_copy() - assert (mc_polder is not None) - cg = maptbx.crystal_gridding( - unit_cell = mc_polder.unit_cell(), - d_min = mc_polder.d_min(), - resolution_factor = 0.25, - space_group_info = mc_polder.space_group_info()) - map_polder = get_map(cg=cg, mc=mc_polder) - pdb_hierarchy = iotbx.pdb.input( - source_info=None, lines=pdb_str).construct_hierarchy() - sel = pdb_hierarchy.atom_selection_cache().selection(string = selection) - sites_cart_lig = pdb_hierarchy.atoms().extract_xyz().select(sel) - sites_frac_lig = mc_polder.unit_cell().fractionalize(sites_cart_lig) - mp = get_map_stats(map=map_polder, sites_frac=sites_frac_lig) - # - mmm_mp = mp.min_max_mean().as_tuple() - print("Polder map : %7.3f %7.3f %7.3f" % mmm_mp) - assert approx_equal(mmm_mp, tuple_calc, eps=1.0), "\ - calculated is %s and expected is %s" % (mmm_mp, tuple_calc) +# --------------------------------------------------------------------------- if (__name__ == "__main__"): t0 = time.time() From 8f38abcb46d53cc6575b09f25b50cc7fd1eae3b7 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 28 Mar 2024 15:00:56 -0700 Subject: [PATCH 262/748] Polder tests: more cleanup (dm, run_program, avoid duplication) --- mmtbx/regression/tst_polder_2.py | 283 +++++++++++++------------------ mmtbx/regression/tst_polder_3.py | 229 ++++++++++++------------- 2 files changed, 229 insertions(+), 283 deletions(-) diff --git a/mmtbx/regression/tst_polder_2.py b/mmtbx/regression/tst_polder_2.py index f80fe3bec4..f450a0b42d 100644 --- a/mmtbx/regression/tst_polder_2.py +++ b/mmtbx/regression/tst_polder_2.py @@ -1,218 +1,173 @@ from __future__ import absolute_import, division, print_function -from libtbx import easy_run -import time -from libtbx.test_utils import approx_equal +import time, os +from iotbx.data_manager import DataManager +from iotbx.cli_parser import run_program +from mmtbx.programs import polder import iotbx.pdb -from iotbx import reflection_file_reader -from cctbx import miller -from cctbx import maptbx +from libtbx.utils import null_out from scitbx.array_family import flex -from six.moves import range +from mmtbx.regression.tst_polder_1 import check, generate_r_free_flags_systematic -pdb_str = """\ -CRYST1 28.992 28.409 27.440 90.00 90.00 90.00 P 1 -ATOM 1 N ALA E 1 9.731 23.364 9.222 0.20 20.00 N -ATOM 2 CA ALA E 1 10.928 22.678 9.693 0.20 20.00 C -ATOM 3 C ALA E 1 10.619 21.229 10.055 0.20 20.00 C -ATOM 4 O ALA E 1 11.301 20.629 10.886 0.20 20.00 O -ATOM 5 CB ALA E 1 11.522 23.409 10.887 0.20 20.00 C -ATOM 6 N HIS E 2 9.586 20.672 9.419 1.00 20.00 N -ATOM 7 CA HIS E 2 9.202 19.291 9.695 1.00 20.00 C -ATOM 8 C HIS E 2 10.295 18.321 9.264 1.00 20.00 C -ATOM 9 O HIS E 2 10.653 17.402 10.010 1.00 20.00 O -ATOM 10 CB HIS E 2 7.882 18.965 8.997 1.00 20.00 C -ATOM 11 CG HIS E 2 6.738 19.828 9.431 1.00 20.00 C -ATOM 12 ND1 HIS E 2 5.915 19.498 10.485 1.00 20.00 N -ATOM 13 CD2 HIS E 2 6.282 21.010 8.953 1.00 20.00 C -ATOM 14 CE1 HIS E 2 5.000 20.438 10.638 1.00 20.00 C -ATOM 15 NE2 HIS E 2 5.200 21.367 9.721 1.00 20.00 N -ATOM 16 N CYS E 3 10.837 18.510 8.058 1.00 20.00 N -ATOM 17 CA CYS E 3 11.937 17.667 7.605 1.00 20.00 C -ATOM 18 C CYS E 3 13.176 17.854 8.470 1.00 20.00 C -ATOM 19 O CYS E 3 13.943 16.905 8.669 1.00 20.00 O -ATOM 20 CB CYS E 3 12.260 17.966 6.141 1.00 20.00 C -ATOM 21 SG CYS E 3 10.887 17.680 5.000 1.00 20.00 S -ATOM 22 N ALA E 4 13.386 19.064 8.995 1.00 20.00 N -ATOM 23 CA ALA E 4 14.520 19.295 9.885 1.00 20.00 C -ATOM 24 C ALA E 4 14.353 18.539 11.196 1.00 20.00 C -ATOM 25 O ALA E 4 15.308 17.933 11.696 1.00 20.00 O -ATOM 26 CB ALA E 4 14.689 20.792 10.142 1.00 20.00 C -TER -ATOM 98 N PHE A 1 9.174 9.310 14.969 0.20 20.00 N -ATOM 99 CA PHE A 1 10.235 8.421 14.508 0.20 20.00 C -ATOM 100 C PHE A 1 11.171 8.048 15.652 0.20 20.00 C -ATOM 101 O PHE A 1 12.391 8.032 15.489 0.20 20.00 O -ATOM 102 CB PHE A 1 11.025 9.073 13.371 0.20 20.00 C -ATOM 103 CG PHE A 1 10.196 9.391 12.160 0.20 20.00 C -ATOM 104 CD1 PHE A 1 10.002 8.444 11.168 0.20 20.00 C -ATOM 105 CD2 PHE A 1 9.611 10.638 12.012 0.20 20.00 C -ATOM 106 CE1 PHE A 1 9.240 8.734 10.052 0.20 20.00 C -ATOM 107 CE2 PHE A 1 8.847 10.934 10.898 0.20 20.00 C -ATOM 108 CZ PHE A 1 8.662 9.980 9.917 0.20 20.00 C -TER -END -""" -def get_map(cg, mc): - fft_map = miller.fft_map( - crystal_gridding = cg, - fourier_coefficients = mc) - fft_map.apply_sigma_scaling() - return fft_map.real_map_unpadded() - -def get_map_stats(map, sites_frac): - map_values = flex.double() - for sf in sites_frac: - map_values.append(map.eight_point_interpolation(sf)) - return map_values def format_map_stat(m): return m.min_max_mean().as_tuple(), (m>flex.mean(m)).count(True) -# Test reading mtz with anomalous arrays for F and Rfree -def exercise_01(fobs_1, flags_1, prefix): +# --------------------------------------------------------------------------- + +def exercise_01(fobs_1, flags_1): + ''' + Test reading mtz with anomalous arrays for F and Rfree + ''' mtz = fobs_1.as_mtz_dataset(column_root_label="FP1") mtz.add_miller_array(flags_1, column_root_label="R-free-flags") - mtz.mtz_object().write(prefix+".mtz") + mtz.mtz_object().write("tst_polder_2_1.mtz") # selection = "chain A" - cmd = " ".join([ - "phenix.polder", + args = [ "tst_polder_2.pdb", - "%s.mtz" % prefix, + "tst_polder_2_1.mtz", "sphere_radius=3", - "output_file_name_prefix=%s" % prefix, 'solvent_exclusion_mask_selection="%s"' % selection, - "&> %s.log" % prefix - ]) - print(cmd) - easy_run.call(cmd) - # exact values: 11.129 16.152 13.006 + "output_file_name_prefix=tst_polder_2_1"] + + r = run_program(program_class=polder.Program, args=args, logger=null_out()) + check( tuple_calc = [10.927, 15.138, 12.849], selection = selection, - prefix = prefix+'_') + filename = r.output_file) -# Test reading mtz with anomalous array for F (no Rfree present) -def exercise_02(fobs_1, prefix): + os.remove("tst_polder_2_1.mtz") + os.remove(r.output_file) + +# --------------------------------------------------------------------------- + +def exercise_02(fobs_1): + ''' + Test reading one mtz with F as anomalous array (no Rfree present) + ''' mtz = fobs_1.as_mtz_dataset(column_root_label="FP1") - mtz.mtz_object().write(prefix+".mtz") + mtz.mtz_object().write("tst_polder_2_2.mtz") # selection = "chain E and resseq 1" - cmd = " ".join([ - "phenix.polder", + args = [ "tst_polder_2.pdb", - "%s.mtz" % prefix, + "tst_polder_2_2.mtz", "sphere_radius=3", - "output_file_name_prefix=%s" % prefix, 'solvent_exclusion_mask_selection="%s"' % selection, - "&> %s.log" % prefix - ]) - print(cmd) - easy_run.call(cmd) + "output_file_name_prefix=tst_polder_2_2"] + + r = run_program(program_class=polder.Program, args=args, logger=null_out()) + check( tuple_calc = [12.7, 22.7, 17.7], selection = selection, - prefix = prefix+'_') + filename = r.output_file) + + os.remove("tst_polder_2_2.mtz") + os.remove(r.output_file) + +# --------------------------------------------------------------------------- -# Mixture: mtz with anomalous F and "normal" Rfree -def exercise_03(fobs_1, flags_1, prefix): +def exercise_03(fobs_1, flags_1): + ''' + Test reading mtz with F as anomalous array and Rfree is usual array + ''' mtz = fobs_1.as_mtz_dataset(column_root_label="FP1") mtz.add_miller_array(flags_1, column_root_label="R-free-flags") - mtz.mtz_object().write(prefix+".mtz") + mtz.mtz_object().write("tst_polder_2_3.mtz") # selection = "chain A" - cmd = " ".join([ - "phenix.polder", + args = [ "tst_polder_2.pdb", - "%s.mtz" % prefix, + "tst_polder_2_3.mtz", "sphere_radius=3", - "output_file_name_prefix=%s" % prefix, 'solvent_exclusion_mask_selection="%s"' % selection, - "&> %s.log" % prefix - ]) - print(cmd) - easy_run.call(cmd) + "output_file_name_prefix=tst_polder_2_3"] + + r = run_program(program_class=polder.Program, args=args, logger=null_out()) + # exact values: 11.129 16.152 13.006 check( tuple_calc = [10.927, 15.138, 12.849], selection = selection, - prefix = prefix+'_') + filename = r.output_file) + + os.remove("tst_polder_2_3.mtz") + os.remove(r.output_file) + +# --------------------------------------------------------------------------- def exercise(): """ Test for phenix.polder: accepting anomalous data labels. """ - f = open("tst_polder_2.pdb", "w") - f.write(pdb_str) - f.close() - # - pdb_in = iotbx.pdb.input(source_info=None,lines=pdb_str) - xrs = pdb_in.xray_structure_simple() - pdb_hierarchy = iotbx.pdb.input( - source_info=None, lines=pdb_str).construct_hierarchy() - # map values are not reproducible if not systematic Rfree! - def generate_r_free_flags_systematic(miller_array): - result = flex.bool() - for i in range(miller_array.indices().size()): - if(i%10==0): result.append(True) - else: result.append(False) - return miller_array.array(data = result) - # generate anomalous and non-anomalous data arrays + dm = DataManager(['model']) + dm.process_model_str("tst_polder_2.pdb", pdb_str) + model = dm.get_model() + dm.write_model_file(model.model_as_pdb(), + filename = "tst_polder_2.pdb", + overwrite = True) + xrs = model.get_xray_structure() + f_anom = abs(xrs.structure_factors(d_min=3.0).f_calc().generate_bijvoet_mates()) f_obs = abs(xrs.structure_factors(d_min=3.0).f_calc()) flags_obs = generate_r_free_flags_systematic(miller_array=f_obs) flags_anom = flags_obs.generate_bijvoet_mates() # - print('*'*79) - print('Test reading one mtz with F and Rfree as anomalous arrays') - exercise_01( - fobs_1 = f_anom, - flags_1 = flags_anom, - prefix = "tst_polder_2_1") - print("OK") - print('*'*79) - print('Test reading one mtz with F as anomalous array (no Rfree present)') - exercise_02( - fobs_1 = f_anom, - prefix = "tst_polder_2_2") - print("OK") - print('*'*79) - print('Test reading mtz with F as anomalous array and Rfree is usual array') - exercise_03( - fobs_1 = f_anom, - flags_1 = flags_obs, - prefix = "tst_polder_2_3") - print("OK") - -def check(tuple_calc, selection, prefix): - miller_arrays = reflection_file_reader.any_reflection_file(file_name = - prefix+"polder_map_coeffs.mtz").as_miller_arrays() - mc_polder = None - for ma in miller_arrays: - lbl = ma.info().label_string() - if(lbl == "mFo-DFc_polder,PHImFo-DFc_polder"): - mc_polder = ma.deep_copy() - assert (mc_polder is not None) - cg = maptbx.crystal_gridding( - unit_cell = mc_polder.unit_cell(), - d_min = mc_polder.d_min(), - resolution_factor = 0.25, - space_group_info = mc_polder.space_group_info()) - map_polder = get_map(cg=cg, mc=mc_polder) - pdb_hierarchy = iotbx.pdb.input( - source_info=None, lines=pdb_str).construct_hierarchy() - sel = pdb_hierarchy.atom_selection_cache().selection(string = selection) - sites_cart_lig = pdb_hierarchy.atoms().extract_xyz().select(sel) - sites_frac_lig = mc_polder.unit_cell().fractionalize(sites_cart_lig) - mp = get_map_stats( - map = map_polder, - sites_frac = sites_frac_lig) - # - mmm_mp = mp.min_max_mean().as_tuple() - print("Polder map : %7.3f %7.3f %7.3f" % mmm_mp) - assert approx_equal(mmm_mp, tuple_calc, eps=1.0), "\ - calculated is %s and expected is %s" % (mmm_mp, tuple_calc) + exercise_01(fobs_1 = f_anom, flags_1 = flags_anom) + exercise_02(fobs_1 = f_anom) + exercise_03(fobs_1 = f_anom, flags_1 = flags_obs) + + os.remove("tst_polder_2.pdb") + +# --------------------------------------------------------------------------- + +pdb_str = """\ +CRYST1 28.992 28.409 27.440 90.00 90.00 90.00 P 1 +ATOM 1 N ALA E 1 9.731 23.364 9.222 0.20 20.00 N +ATOM 2 CA ALA E 1 10.928 22.678 9.693 0.20 20.00 C +ATOM 3 C ALA E 1 10.619 21.229 10.055 0.20 20.00 C +ATOM 4 O ALA E 1 11.301 20.629 10.886 0.20 20.00 O +ATOM 5 CB ALA E 1 11.522 23.409 10.887 0.20 20.00 C +ATOM 6 N HIS E 2 9.586 20.672 9.419 1.00 20.00 N +ATOM 7 CA HIS E 2 9.202 19.291 9.695 1.00 20.00 C +ATOM 8 C HIS E 2 10.295 18.321 9.264 1.00 20.00 C +ATOM 9 O HIS E 2 10.653 17.402 10.010 1.00 20.00 O +ATOM 10 CB HIS E 2 7.882 18.965 8.997 1.00 20.00 C +ATOM 11 CG HIS E 2 6.738 19.828 9.431 1.00 20.00 C +ATOM 12 ND1 HIS E 2 5.915 19.498 10.485 1.00 20.00 N +ATOM 13 CD2 HIS E 2 6.282 21.010 8.953 1.00 20.00 C +ATOM 14 CE1 HIS E 2 5.000 20.438 10.638 1.00 20.00 C +ATOM 15 NE2 HIS E 2 5.200 21.367 9.721 1.00 20.00 N +ATOM 16 N CYS E 3 10.837 18.510 8.058 1.00 20.00 N +ATOM 17 CA CYS E 3 11.937 17.667 7.605 1.00 20.00 C +ATOM 18 C CYS E 3 13.176 17.854 8.470 1.00 20.00 C +ATOM 19 O CYS E 3 13.943 16.905 8.669 1.00 20.00 O +ATOM 20 CB CYS E 3 12.260 17.966 6.141 1.00 20.00 C +ATOM 21 SG CYS E 3 10.887 17.680 5.000 1.00 20.00 S +ATOM 22 N ALA E 4 13.386 19.064 8.995 1.00 20.00 N +ATOM 23 CA ALA E 4 14.520 19.295 9.885 1.00 20.00 C +ATOM 24 C ALA E 4 14.353 18.539 11.196 1.00 20.00 C +ATOM 25 O ALA E 4 15.308 17.933 11.696 1.00 20.00 O +ATOM 26 CB ALA E 4 14.689 20.792 10.142 1.00 20.00 C +TER +ATOM 98 N PHE A 1 9.174 9.310 14.969 0.20 20.00 N +ATOM 99 CA PHE A 1 10.235 8.421 14.508 0.20 20.00 C +ATOM 100 C PHE A 1 11.171 8.048 15.652 0.20 20.00 C +ATOM 101 O PHE A 1 12.391 8.032 15.489 0.20 20.00 O +ATOM 102 CB PHE A 1 11.025 9.073 13.371 0.20 20.00 C +ATOM 103 CG PHE A 1 10.196 9.391 12.160 0.20 20.00 C +ATOM 104 CD1 PHE A 1 10.002 8.444 11.168 0.20 20.00 C +ATOM 105 CD2 PHE A 1 9.611 10.638 12.012 0.20 20.00 C +ATOM 106 CE1 PHE A 1 9.240 8.734 10.052 0.20 20.00 C +ATOM 107 CE2 PHE A 1 8.847 10.934 10.898 0.20 20.00 C +ATOM 108 CZ PHE A 1 8.662 9.980 9.917 0.20 20.00 C +TER +END +""" +# --------------------------------------------------------------------------- if (__name__ == "__main__"): t0 = time.time() diff --git a/mmtbx/regression/tst_polder_3.py b/mmtbx/regression/tst_polder_3.py index 10572396eb..a99ac95616 100644 --- a/mmtbx/regression/tst_polder_3.py +++ b/mmtbx/regression/tst_polder_3.py @@ -1,16 +1,118 @@ from __future__ import absolute_import, division, print_function -from libtbx import easy_run -import time +import time, os from libtbx.test_utils import approx_equal -import iotbx.pdb -import mmtbx.model from iotbx import reflection_file_reader -from cctbx import miller -from scitbx.array_family import flex -from mmtbx.maps.polder import master_params_str +from iotbx.cli_parser import run_program +from libtbx.utils import null_out +from iotbx.data_manager import DataManager +from mmtbx.programs import fmodel import mmtbx.maps.polder +import iotbx.phil from six.moves import range + +def exercise(prefix="tst_polder_3"): + """ + Test for phenix.polder sphere radius and box buffer. + """ + + # save test model as file + model_fn = "tst_polder_3.pdb" + dm = DataManager(['model']) + dm.process_model_str(model_fn, pdb_str+pdb_str_ligand) + model = dm.get_model() + dm.write_model_file(model.model_as_pdb(), + filename = "tst_polder_3.pdb", + overwrite = True) + + # create test data with phenix.fmodel + mtz_fn = "tst_polder_3.mtz" + args = [ + model_fn, + "high_res=2.0", + "type=real", + "label=f-obs", + "k_sol=0.4", + "b_sol=50", + "output.file_name=%s" % mtz_fn] + run_program(program_class=fmodel.Program, args=args, logger=null_out()) + + params_line = mmtbx.maps.polder.master_params_str + params = iotbx.phil.parse( + input_string=params_line, process_includes=True).extract() + + pdb_hierarchy = model.get_hierarchy() + + selection_string = 'chain A' + + miller_arrays = reflection_file_reader.any_reflection_file(file_name = + "tst_polder_3.mtz").as_miller_arrays() + fobs = [None] + for ma in miller_arrays: + if(ma.info().label_string() == "f-obs"): + fobs = ma.deep_copy() + + mmm_list = [] + mask_mmm = [[0.0, 1.0, 0.9083055555555556], + [0.0, 1.0, 0.8901388888888889], + [0.0, 1.0, 0.9083055555555556], + [0.0, 1.0, 0.8583379629629629], + [0.0, 1.0, 0.9083055555555556], + [0.0, 1.0, 0.8025601851851852] ] + + for radius in [3, 5, 7]: + params.polder.sphere_radius = radius + polder_object = mmtbx.maps.polder.compute_polder_map( + f_obs = fobs, + r_free_flags = None, + model = model, + params = params.polder, + selection_string = selection_string) + polder_object.validate() + polder_object.run() + results = polder_object.get_results() + + mmm_list.append(results.mask_data_omit.as_1d().min_max_mean().as_tuple()) + mmm_list.append(results.mask_data_polder.as_1d().min_max_mean().as_tuple()) + + for i in range(6): + assert approx_equal(mask_mmm[i], mmm_list[i], eps = 0.1) + #print mask_mmm[i], mmm_list[i] + + mmm_list = [] + mask_mmm = [ [0.0, 1.0, 0.898712962962963], + [0.0, 1.0, 0.8642268518518519], + [0.0, 1.0, 0.898712962962963], + [0.0, 1.0, 0.7957083333333334], + [0.0, 1.0, 0.898712962962963], + [0.0, 1.0, 0.6772777777777778] ] + + for box_buffer in [3, 5, 7]: + params.polder.box_buffer = box_buffer + params.polder.compute_box = True + polder_object = mmtbx.maps.polder.compute_polder_map( + f_obs = fobs, + r_free_flags = None, + model = model, + params = params.polder, + selection_string = selection_string) + polder_object.validate() + polder_object.run() + results = polder_object.get_results() + + mmm_list.append(results.mask_data_omit.as_1d().min_max_mean().as_tuple()) + mmm_list.append(results.mask_data_polder.as_1d().min_max_mean().as_tuple()) + + for i in range(6): + assert approx_equal(mask_mmm[i], mmm_list[i], eps = 0.1) + #print mask_mmm[i], mmm_list[i] + + # Clean up files + os.remove(model_fn) + os.remove(mtz_fn) + +# --------------------------------------------------------------------------- + pdb_str = """\ CRYST1 28.992 28.409 27.440 90.00 90.00 90.00 P 1 ATOM 1 N ALA E 1 9.731 23.364 9.222 1.00 20.00 N @@ -153,118 +255,7 @@ END """ -def get_map(cg, mc): - fft_map = miller.fft_map( - crystal_gridding = cg, - fourier_coefficients = mc) - fft_map.apply_sigma_scaling() - return fft_map.real_map_unpadded() - -def get_map_stats(map, sites_frac): - map_values = flex.double() - for sf in sites_frac: - map_values.append(map.eight_point_interpolation(sf)) - return map_values - -def exercise(prefix="tst_polder_3"): - """ - Test for phenix.polder sphere radius and box buffer. - """ - f = open("%s.pdb" % prefix, "w") - f.write(pdb_str+pdb_str_ligand) - f.close() - - # get mtz file from model using fmodel - cmd = " ".join([ - "phenix.fmodel", - "%s.pdb" % prefix, - "high_res=2.0", - "type=real", - "label=f-obs", - "k_sol=0.4", - "b_sol=50", - "output.file_name=%s.mtz" % prefix, - "> %s.log" % prefix - ]) - print(cmd) - easy_run.call(cmd) - - params_line = master_params_str - params = iotbx.phil.parse( - input_string=params_line, process_includes=True).extract() - - pdb_inp = iotbx.pdb.input(file_name = 'tst_polder_3.pdb') - model = mmtbx.model.manager(model_input = pdb_inp) - pdb_hierarchy = model.get_hierarchy() - - selection_string = 'chain A' -# selection_bool = pdb_hierarchy.atom_selection_cache().selection( -# string = 'chain A') - - miller_arrays = reflection_file_reader.any_reflection_file(file_name = - "tst_polder_3.mtz").as_miller_arrays() - fobs = [None] - for ma in miller_arrays: - if(ma.info().label_string() == "f-obs"): - fobs = ma.deep_copy() - - mmm_list = [] - mask_mmm = [[0.0, 1.0, 0.9083055555555556], - [0.0, 1.0, 0.8901388888888889], - [0.0, 1.0, 0.9083055555555556], - [0.0, 1.0, 0.8583379629629629], - [0.0, 1.0, 0.9083055555555556], - [0.0, 1.0, 0.8025601851851852] ] - - for radius in [3, 5, 7]: - params.polder.sphere_radius = radius - polder_object = mmtbx.maps.polder.compute_polder_map( - f_obs = fobs, - r_free_flags = None, - model = model, - params = params.polder, - selection_string = selection_string) - polder_object.validate() - polder_object.run() - results = polder_object.get_results() - - mmm_list.append(results.mask_data_omit.as_1d().min_max_mean().as_tuple()) - mmm_list.append(results.mask_data_polder.as_1d().min_max_mean().as_tuple()) - - for i in range(6): - assert approx_equal(mask_mmm[i], mmm_list[i], eps = 0.1) - #print mask_mmm[i], mmm_list[i] - -#------------------------------------------------------------------------- - - mmm_list = [] - mask_mmm = [ [0.0, 1.0, 0.898712962962963], - [0.0, 1.0, 0.8642268518518519], - [0.0, 1.0, 0.898712962962963], - [0.0, 1.0, 0.7957083333333334], - [0.0, 1.0, 0.898712962962963], - [0.0, 1.0, 0.6772777777777778] ] - - for box_buffer in [3, 5, 7]: - params.polder.box_buffer = box_buffer - params.polder.compute_box = True - polder_object = mmtbx.maps.polder.compute_polder_map( - f_obs = fobs, - r_free_flags = None, - model = model, - params = params.polder, - selection_string = selection_string) - polder_object.validate() - polder_object.run() - results = polder_object.get_results() - - mmm_list.append(results.mask_data_omit.as_1d().min_max_mean().as_tuple()) - mmm_list.append(results.mask_data_polder.as_1d().min_max_mean().as_tuple()) - - for i in range(6): - assert approx_equal(mask_mmm[i], mmm_list[i], eps = 0.1) - #print mask_mmm[i], mmm_list[i] - +# --------------------------------------------------------------------------- if (__name__ == "__main__"): t0 = time.time() From 8edc849631d950abf51277ebf17eb43a7458374a Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 28 Mar 2024 15:55:25 -0700 Subject: [PATCH 263/748] Polder tests: more cleanup and improvements --- mmtbx/maps/polder.py | 1 - mmtbx/programs/polder.py | 39 +++---- mmtbx/regression/tst_polder_box.py | 180 ++++++++++++++--------------- mmtbx/regression/tst_polder_ccs.py | 158 +++++++++++++------------ 4 files changed, 189 insertions(+), 189 deletions(-) diff --git a/mmtbx/maps/polder.py b/mmtbx/maps/polder.py index 8119f2a6c1..41228d87c4 100644 --- a/mmtbx/maps/polder.py +++ b/mmtbx/maps/polder.py @@ -53,7 +53,6 @@ def __init__(self, model, params, selection_string): - #selection_bool): self.f_obs = f_obs self.r_free_flags = r_free_flags self.xray_structure = model.get_xray_structure() diff --git a/mmtbx/programs/polder.py b/mmtbx/programs/polder.py index 1b88ebb85c..04d86341d3 100644 --- a/mmtbx/programs/polder.py +++ b/mmtbx/programs/polder.py @@ -280,12 +280,12 @@ def broadcast_rfactors(self, r_work, r_free): # --------------------------------------------------------------------------- - def print_rfactors(self, results): + def print_rfactors(self): print ('*'*79, file=self.logger) - fmodel_input = results.fmodel_input - fmodel_biased = results.fmodel_biased - fmodel_omit = results.fmodel_omit - fmodel_polder = results.fmodel_polder + fmodel_input = self.results.fmodel_input + fmodel_biased = self.results.fmodel_biased + fmodel_omit = self.results.fmodel_omit + fmodel_polder = self.results.fmodel_polder print('R factors for unmodified input model and data:', file=self.logger) self.broadcast_rfactors(fmodel_input.r_work(), fmodel_input.r_free()) if (self.params.debug): @@ -300,9 +300,11 @@ def print_rfactors(self, results): # --------------------------------------------------------------------------- - def write_files(self, results, f_obs): + def write_files(self, f_obs): if (self.params.mask_output): - masks = [results.mask_data_all, results.mask_data_omit, results.mask_data_polder] + masks = [self.results.mask_data_all, + self.results.mask_data_omit, + self.results.mask_data_polder] filenames = ["all", "omit", "polder"] for mask_data, filename in zip(masks, filenames): mrcfile.write_ccp4_map( @@ -311,14 +313,14 @@ def write_files(self, results, f_obs): space_group = f_obs.space_group(), map_data = mask_data, labels = flex.std_string([""])) - mtz_dataset = results.mc_polder.as_mtz_dataset( + mtz_dataset = self.results.mc_polder.as_mtz_dataset( column_root_label = "mFo-DFc_polder") mtz_dataset.add_miller_array( - miller_array = results.mc_omit, + miller_array = self.results.mc_omit, column_root_label = "mFo-DFc_omit") if (self.params.debug): mtz_dataset.add_miller_array( - miller_array = results.mc_biased, + miller_array = self.results.mc_biased, column_root_label = "mFo-DFc_bias_omit") mtz_object = mtz_dataset.mtz_object() polder_file_name = "polder_map_coeffs.mtz" @@ -330,8 +332,8 @@ def write_files(self, results, f_obs): # --------------------------------------------------------------------------- - def print_validation(self, results): - vr = results.validation_results + def print_validation(self): + vr = self.results.validation_results if vr is None: return '' print('Map 1: calculated Fobs with ligand', file=self.logger) @@ -436,24 +438,21 @@ def run(self): model = model, params = self.params.polder, selection_string = self.params.solvent_exclusion_mask_selection) - #selection_bool = selection_bool) + polder_object.validate() polder_object.run() - results = polder_object.get_results() + self.results = polder_object.get_results() - self.print_rfactors(results = results) - self.write_files( - results = results, - f_obs = f_obs) + self.print_rfactors() + self.write_files(f_obs = f_obs) self.message = None if (not self.params.polder.compute_box): - self.message = self.print_validation(results = results) + self.message = self.print_validation() print ('*'*79, file=self.logger) print ('Finished', file=self.logger) # results object not returned because it contains maps - def get_results(self): return group_args( message = self.message, diff --git a/mmtbx/regression/tst_polder_box.py b/mmtbx/regression/tst_polder_box.py index d6cf61c35b..8d3e02cfde 100644 --- a/mmtbx/regression/tst_polder_box.py +++ b/mmtbx/regression/tst_polder_box.py @@ -1,12 +1,92 @@ from __future__ import absolute_import, division, print_function -from libtbx import easy_run -import time +import time, os from libtbx.test_utils import approx_equal -import iotbx.pdb from iotbx import reflection_file_reader -from cctbx import miller from cctbx import maptbx -from scitbx.array_family import flex +from mmtbx.regression.tst_polder import get_map, get_map_stats +from iotbx.data_manager import DataManager +from iotbx.cli_parser import run_program +from mmtbx.programs import fmodel, polder +from libtbx.utils import null_out + +def exercise_00(prefix="tst_polder_box"): + """ + Test for phenix.polder using the compute_box=True option. + """ + dm = DataManager(['model']) + dm.process_model_str('tst_polder_box.pdb', pdb_str) + dm.process_model_str('tst_polder_box_ligand.pdb', pdb_str + pdb_str_ligand) + dm.write_model_file(dm.get_model('tst_polder_box.pdb').model_as_pdb(), + filename = 'tst_polder_box.pdb', + overwrite = True) + dm.write_model_file(dm.get_model('tst_polder_box_ligand.pdb').model_as_pdb(), + filename = 'tst_polder_box_ligand.pdb', + overwrite = True) + + # create test data with phenix.fmodel + mtz_fn = "tst_polder_box.mtz" + args = [ + 'tst_polder_box_ligand.pdb', + "high_res=2.0", + "type=real", + "label=f-obs", + "k_sol=0.4", + "b_sol=50", + "output.file_name=%s" % mtz_fn] + run_program(program_class=fmodel.Program, args=args, logger=null_out()) + + selection = '((resseq 65 and name CG) or (resseq 7 and name OH) or \ + resseq 183 or resseq 95 or (resseq 148 and name CG))' + + args = [ + "tst_polder_box.pdb", + "tst_polder_box.mtz", + "compute_box=True", + 'solvent_exclusion_mask_selection="%s"' % selection] + #'mask_output=True'] + + r = run_program(program_class=polder.Program, args=args, logger=null_out()) + + miller_arrays = reflection_file_reader.any_reflection_file(file_name = + r.output_file).as_miller_arrays() + mc_polder, mc_bias_omit, mc_omit = [None,]*3 + for ma in miller_arrays: + lbl = ma.info().label_string() + if(lbl == "mFo-DFc_polder,PHImFo-DFc_polder"): + mc_polder = ma.deep_copy() + if(lbl == "mFo-DFc_bias_omit,PHImFo-DFc_bias_omit"): + mc_bias_omit = ma.deep_copy() + if(lbl == "mFo-DFc_omit,PHImFo-DFc_omit"): + mc_omit = ma.deep_copy() + assert [mc_polder, mc_omit].count(None)==0 + cg = maptbx.crystal_gridding( + unit_cell = mc_polder.unit_cell(), + d_min = mc_polder.d_min(), + resolution_factor = 0.25, + space_group_info = mc_polder.space_group_info()) + map_polder = get_map(cg=cg, mc=mc_polder) + map_omit = get_map(cg=cg, mc=mc_omit) + pdb_hierarchy = dm.get_model('tst_polder_box.pdb').get_hierarchy() + sel = pdb_hierarchy.atom_selection_cache().selection(string = selection) + sites_cart_lig = pdb_hierarchy.atoms().extract_xyz().select(sel) + sites_frac_lig = mc_polder.unit_cell().fractionalize(sites_cart_lig) + mp = get_map_stats(map=map_polder, sites_frac=sites_frac_lig) + mo = get_map_stats(map=map_omit, sites_frac=sites_frac_lig) + # + mmm_mp = mp.min_max_mean().as_tuple() + mmm_o = mo.min_max_mean().as_tuple() + #print("Polder map : %7.3f %7.3f %7.3f"%mmm_mp) + #print("Omit : %7.3f %7.3f %7.3f"%mmm_o) + # + assert approx_equal(mmm_mp, [-2.051, 1.255, -0.162], eps=0.15) + assert approx_equal(mmm_o, [-0.558, 0.138, -0.068], eps=0.15) + + os.remove('tst_polder_box.pdb') + os.remove('tst_polder_box_ligand.pdb') + os.remove('tst_polder_box.mtz') + os.remove(r.output_file) + +# --------------------------------------------------------------------------- pdb_str = """\ CRYST1 21.830 27.276 27.424 90.00 90.00 90.00 P 1 @@ -114,95 +194,7 @@ HETATM 88 S MES A 88 8.674 10.225 15.261 1.00 59.12 S """ -def get_map(cg, mc): - fft_map = miller.fft_map( - crystal_gridding = cg, - fourier_coefficients = mc) - fft_map.apply_sigma_scaling() - return fft_map.real_map_unpadded() - -def get_map_stats(map, sites_frac): - map_values = flex.double() - for sf in sites_frac: - map_values.append(map.eight_point_interpolation(sf)) - return map_values - -def format_map_stat(m): - return m.min_max_mean().as_tuple(), (m>flex.mean(m)).count(True) - -def exercise_00(prefix="tst_polder_box"): - """ - Test for phenix.polder using the compute_box=True option. - """ - f = open("%s.pdb" % prefix, "w") - f.write(pdb_str) - f.close() - f = open("%s_ligand.pdb" % prefix, "w") - f.write(pdb_str + pdb_str_ligand) - f.close() - cmd = " ".join([ - "phenix.fmodel", - "%s_ligand.pdb" % prefix, - "high_res=2.0", - "type=real", - "label=f-obs", - "k_sol=0.4", - "b_sol=50", - "output.file_name=%s.mtz" % prefix, - "> %s.log" % prefix - ]) - print(cmd) - easy_run.call(cmd) - # - selection_string = '((resseq 65 and name CG) or (resseq 7 and name OH) or \ - resseq 183 or resseq 95 or (resseq 148 and name CG))' - cmd = " ".join([ - "phenix.polder", - "%s.pdb" % prefix, - "%s.mtz" % prefix, - "compute_box=True", - 'solvent_exclusion_mask_selection="%s" ' % selection_string, - 'mask_output=True', - "> %s.log" % prefix - ]) - print(cmd) - easy_run.call(cmd) - # - miller_arrays = reflection_file_reader.any_reflection_file(file_name = - "tst_polder_box_polder_map_coeffs.mtz").as_miller_arrays() - mc_polder, mc_bias_omit, mc_omit = [None,]*3 - for ma in miller_arrays: - lbl = ma.info().label_string() - if(lbl == "mFo-DFc_polder,PHImFo-DFc_polder"): - mc_polder = ma.deep_copy() - if(lbl == "mFo-DFc_bias_omit,PHImFo-DFc_bias_omit"): - mc_bias_omit = ma.deep_copy() - if(lbl == "mFo-DFc_omit,PHImFo-DFc_omit"): - mc_omit = ma.deep_copy() - assert [mc_polder, mc_omit].count(None)==0 - cg = maptbx.crystal_gridding( - unit_cell = mc_polder.unit_cell(), - d_min = mc_polder.d_min(), - resolution_factor = 0.25, - space_group_info = mc_polder.space_group_info()) - map_polder = get_map(cg=cg, mc=mc_polder) - map_omit = get_map(cg=cg, mc=mc_omit) - pdb_hierarchy = iotbx.pdb.input( - source_info=None, lines=pdb_str).construct_hierarchy() - sel = pdb_hierarchy.atom_selection_cache().selection(string = selection_string) - sites_cart_lig = pdb_hierarchy.atoms().extract_xyz().select(sel) - sites_frac_lig = mc_polder.unit_cell().fractionalize(sites_cart_lig) - mp = get_map_stats(map=map_polder, sites_frac=sites_frac_lig) - mo = get_map_stats(map=map_omit, sites_frac=sites_frac_lig) - # - mmm_mp = mp.min_max_mean().as_tuple() - mmm_o = mo.min_max_mean().as_tuple() - print("Polder map : %7.3f %7.3f %7.3f"%mmm_mp) - print("Omit : %7.3f %7.3f %7.3f"%mmm_o) - # - assert approx_equal(mmm_mp, [-2.051, 1.255, -0.162], eps=0.15) - assert approx_equal(mmm_o, [-0.558, 0.138, -0.068], eps=0.15) - +# --------------------------------------------------------------------------- if (__name__ == "__main__"): t0 = time.time() diff --git a/mmtbx/regression/tst_polder_ccs.py b/mmtbx/regression/tst_polder_ccs.py index 9ffb00c9ae..7de33829e3 100644 --- a/mmtbx/regression/tst_polder_ccs.py +++ b/mmtbx/regression/tst_polder_ccs.py @@ -1,13 +1,91 @@ from __future__ import absolute_import, division, print_function -from libtbx import easy_run -import time +import time, os from libtbx.test_utils import approx_equal -import iotbx.pdb +from libtbx.utils import null_out +import iotbx.phil +from iotbx.cli_parser import run_program +from iotbx.data_manager import DataManager from iotbx import reflection_file_reader -import mmtbx.model -from mmtbx.maps.polder import master_params_str +from mmtbx.programs import fmodel import mmtbx.maps.polder + +def exercise(prefix="tst_polder_ccs"): + """ + Test for phenix.polder correlation coefficients. + """ + + # save test model as file + model_fn = "tst_polder_ccs.pdb" + dm = DataManager(['model']) + dm.process_model_str(model_fn, pdb_str) + model = dm.get_model() + dm.write_model_file(model.model_as_pdb(), + filename = "tst_polder_ccs.pdb", + overwrite = True) + + # create test data with phenix.fmodel + mtz_fn = "tst_polder_ccs.mtz" + args = [ + model_fn, + "high_res=2.0", + "type=real", + "label=f-obs", + "k_sol=0.4", + "b_sol=50", + "output.file_name=%s" % mtz_fn] + run_program(program_class=fmodel.Program, args=args, logger=null_out()) + + params_line = mmtbx.maps.polder.master_params_str + params = iotbx.phil.parse( + input_string=params_line, process_includes=True).extract() + + pdb_hierarchy = model.get_hierarchy() + + selection_string = 'resseq 88' + #selection_bool = pdb_hierarchy.atom_selection_cache().selection( + # string = 'resseq 88') + #f_obs = abs(xray_structure.structure_factors(d_min=2).f_calc()) + #mtz = f_obs.as_mtz_dataset(column_root_label = "Fobs") + #mtz.mtz_object().write("bla.mtz") + + miller_arrays = reflection_file_reader.any_reflection_file(file_name = + mtz_fn).as_miller_arrays() + fobs = [None] + for ma in miller_arrays: + if(ma.info().label_string() == "f-obs"): + fobs = ma.deep_copy() + + # Calculate polder map and get results + polder_object = mmtbx.maps.polder.compute_polder_map( + f_obs = fobs, + r_free_flags = None, + model = model, + params = params.polder, + selection_string = selection_string) + polder_object.validate() + polder_object.run() + results = polder_object.get_results() + + #mtz_dataset = results.mc_polder.as_mtz_dataset( + # column_root_label = "mFo-DFc_polder") + #mtz_dataset.add_miller_array( + # miller_array = results.mc_omit, + # column_root_label = "mFo-DFc_omit") + #mtz_object = mtz_dataset.mtz_object() + #mtz_object.write(file_name = "bla.mtz") + + vr = results.validation_results + + assert approx_equal([vr.cc12, vr.cc13, vr.cc23], [0.4153, 0.9980, 0.4213], eps = 0.1) + assert approx_equal([vr.cc12_peak, vr.cc13_peak, vr.cc23_peak], [0.4310, 0.9966, 0.4379], eps = 0.1) + + # Clean up files + os.remove(model_fn) + os.remove(mtz_fn) + +# --------------------------------------------------------------------------- + pdb_str = """\ CRYST1 21.830 27.276 27.424 90.00 90.00 90.00 P 1 SCALE1 0.045809 0.000000 0.000000 0.00000 @@ -111,75 +189,7 @@ HETATM 88 S MES A 88 8.674 10.225 15.261 1.00 59.12 S """ -def exercise(prefix="tst_polder_ccs"): - """ - Test for phenix.polder correlation coefficients. - """ - # write pdb string to file - f = open("%s.pdb" % prefix, "w") - f.write(pdb_str) - f.close() - - # get mtz file from model using fmodel - cmd = " ".join([ - "phenix.fmodel", - "%s.pdb" % prefix, - "high_res=2.0", - "type=real", - "label=f-obs", - "k_sol=0.4", - "b_sol=50", - "output.file_name=%s.mtz" % prefix, - "> %s.log" % prefix - ]) - print(cmd) - easy_run.call(cmd) - - params_line = master_params_str - params = iotbx.phil.parse( - input_string=params_line, process_includes=True).extract() - - pdb_inp = iotbx.pdb.input(file_name = 'tst_polder_ccs.pdb') - model = mmtbx.model.manager(model_input = pdb_inp) - pdb_hierarchy = model.get_hierarchy() - selection_string = 'resseq 88' - #selection_bool = pdb_hierarchy.atom_selection_cache().selection( - # string = 'resseq 88') - #f_obs = abs(xray_structure.structure_factors(d_min=2).f_calc()) - #mtz = f_obs.as_mtz_dataset(column_root_label = "Fobs") - #mtz.mtz_object().write("bla.mtz") - - miller_arrays = reflection_file_reader.any_reflection_file(file_name = - "tst_polder_ccs.mtz").as_miller_arrays() - fobs = [None] - for ma in miller_arrays: - if(ma.info().label_string() == "f-obs"): - fobs = ma.deep_copy() - - # Calculate polder map and get results - polder_object = mmtbx.maps.polder.compute_polder_map( - f_obs = fobs, - r_free_flags = None, - model = model, - params = params.polder, - selection_string = selection_string) - polder_object.validate() - polder_object.run() - results = polder_object.get_results() - - #mtz_dataset = results.mc_polder.as_mtz_dataset( - # column_root_label = "mFo-DFc_polder") - #mtz_dataset.add_miller_array( - # miller_array = results.mc_omit, - # column_root_label = "mFo-DFc_omit") - #mtz_object = mtz_dataset.mtz_object() - #mtz_object.write(file_name = "bla.mtz") - - - vr = results.validation_results - - assert approx_equal([vr.cc12, vr.cc13, vr.cc23], [0.4153, 0.9980, 0.4213], eps = 0.1) - assert approx_equal([vr.cc12_peak, vr.cc13_peak, vr.cc23_peak], [0.4310, 0.9966, 0.4379], eps = 0.1) +# --------------------------------------------------------------------------- if (__name__ == "__main__"): t0 = time.time() From 1b61ddc3535ea00eea62c94a4e771d289a8fcbd3 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Thu, 28 Mar 2024 22:13:14 -0700 Subject: [PATCH 264/748] Bugfix for cases where hierarchy comes in with shuffled atoms' i_seqs. --- mmtbx/geometry_restraints/reference.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmtbx/geometry_restraints/reference.py b/mmtbx/geometry_restraints/reference.py index 609a139fc9..2807a330ee 100644 --- a/mmtbx/geometry_restraints/reference.py +++ b/mmtbx/geometry_restraints/reference.py @@ -25,6 +25,7 @@ def generate_torsion_restraints( from another source (reference model) which is not necessary of the same size as hierarchy. """ + pdb_hierarchy.atoms().reset_i_seq() torsion_proxies = geometry_restraints.shared_dihedral_proxy() if pdb_hierarchy.atoms_size() < 4: return torsion_proxies From 03efeaab63db1bf222738d79f8aee89f0bf6d898 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 29 Mar 2024 14:14:19 -0700 Subject: [PATCH 265/748] Polder: use fmodel from data manager --> reduces phil params and avoids code duplication. Note: will break the GUI. Working on that next. --- mmtbx/programs/polder.py | 127 ++++++++----------------------- mmtbx/regression/tst_polder.py | 86 +++++++++++++++++---- mmtbx/regression/tst_polder_1.py | 4 +- 3 files changed, 103 insertions(+), 114 deletions(-) diff --git a/mmtbx/programs/polder.py b/mmtbx/programs/polder.py index 04d86341d3..24160304db 100644 --- a/mmtbx/programs/polder.py +++ b/mmtbx/programs/polder.py @@ -17,42 +17,11 @@ master_phil_str = ''' include scope libtbx.phil.interface.tracking_params include scope mmtbx.maps.polder.master_params -model_file_name = None - .type = path - .short_caption = Model file - .multiple = False - .help = Model file name - .style = file_type:pdb bold input_file solvent_exclusion_mask_selection = None .type = str .short_caption = Omit selection .help = Atoms around which bulk solvent mask is set to zero .input_size = 400 -reflection_file_name = None - .type = path - .short_caption = Data file - .help = File with experimental data (most of formats: CNS, SHELX, MTZ, etc). - .style = file_type:hkl bold input_file process_hkl child:fobs:data_labels \ - child:rfree:r_free_flags_labels child:d_min:high_resolution \ - child:d_max:low_resolution -data_labels = None - .type = str - .short_caption = Data labels - .help = Labels for experimental data. - .style = renderer:draw_fobs_label_widget parent:file_name:reflection_file_name -r_free_flags_labels = None - .type = str - .short_caption = Rfree labels - .help = Labels for free reflections. - .style = renderer:draw_rfree_label_widget parent:file_name:reflection_file_name -high_resolution = None - .type = float - .short_caption = High resolution - .help = High resolution limit -low_resolution = None - .type = float - .short_caption = Low resolution - .help = Low resolution limit scattering_table = *n_gaussian wk1995 it1992 neutron electron .type = choice .short_caption = Scattering table @@ -140,10 +109,6 @@ def validate(self): self.data_manager.has_miller_arrays(raise_sorry=True) if (len(self.data_manager.get_miller_array_names()) > 2): raise Sorry('Dont input more than 2 reflection files.') - if (self.params.reflection_file_name is None): - self.params.reflection_file_name = self.data_manager.get_default_miller_array_name() - if (self.params.model_file_name is None): - self.params.model_file_name = self.data_manager.get_default_model_name() if (self.params.solvent_exclusion_mask_selection is None): raise Sorry('''Selection for atoms to be omitted is required. @@ -161,6 +126,22 @@ def validate(self): if (self.params.polder.resolution_factor < 0.0): raise Sorry('Use a positive value for the resolution gridding factor.') + self.fmodel = None + try: + self.fmodel = self.data_manager.get_fmodel( + scattering_table = self.params.scattering_table) + except Sorry as s: + if 'previously used R-free flags are available run this command again' in str(s): + #TODO print stuff here to informa that there is no Rfree flag + fmodel_params = self.data_manager.get_fmodel_params() + fmodel_params.xray_data.r_free_flags.required = False + fmodel_params.xray_data.r_free_flags.ignore_r_free_flags = True + self.data_manager.set_fmodel_params(fmodel_params) + self.fmodel = self.data_manager.get_fmodel( + scattering_table = self.params.scattering_table) + if self.fmodel is None: + raise Sorry('Failed to create fmodel. Please submit a bug report.') + # --------------------------------------------------------------------------- def get_crystal_symmetry(self): @@ -198,55 +179,6 @@ def prepare_f_obs_and_flags_if_anomalous(self, f_obs, r_free_flags): # --------------------------------------------------------------------------- - def get_fobs_rfree(self, crystal_symmetry): - f_obs, r_free_flags = None, None - - rfs = self.data_manager.get_reflection_file_server( - filenames = self.data_manager.get_miller_array_names(), - crystal_symmetry = crystal_symmetry, - logger=null_out()) - - parameters = extract_xtal_data.data_and_flags_master_params().extract() - if (self.params.data_labels is not None): - parameters.labels = self.params.data_labels - if (self.params.r_free_flags_labels is not None): - parameters.r_free_flags.label = self.params.r_free_flags_labels - determined_data_and_flags = extract_xtal_data.run( - reflection_file_server = rfs, - parameters = parameters, - keep_going = True, - working_point_group = crystal_symmetry.space_group().build_derived_point_group()) - - f_obs = determined_data_and_flags.f_obs - r_free_flags = determined_data_and_flags.r_free_flags - assert (f_obs is not None) - if (self.params.data_labels is None): - self.params.data_labels = f_obs.info().label_string() - if (r_free_flags is not None): - self.params.r_free_flags_labels = r_free_flags.info().label_string() - - return f_obs, r_free_flags - - # --------------------------------------------------------------------------- - - def prepare_fobs_rfree(self, f_obs, r_free_flags): - f_obs = f_obs.resolution_filter( - d_min = self.params.high_resolution, - d_max = self.params.low_resolution) - if (r_free_flags is not None): - r_free_flags = r_free_flags.resolution_filter( - d_min = self.params.high_resolution, - d_max = self.params.low_resolution) - - if (f_obs.anomalous_flag()): - f_obs, r_free_flags = self.prepare_f_obs_and_flags_if_anomalous( - f_obs = f_obs, - r_free_flags = r_free_flags) - - return f_obs, r_free_flags - - # --------------------------------------------------------------------------- - def check_selection(self, pdb_hierarchy): print("*"*79, file=self.logger) print('Selecting atoms...\n', file=self.logger) @@ -394,7 +326,8 @@ def result_message(self, cc12, cc13, cc23): def run(self): - print('Using model file:', self.params.model_file_name, file=self.logger) + print('Using model file:', self.data_manager.get_default_model_name(), + file=self.logger) print('Using reflection file(s):', self.data_manager.get_miller_array_names(), file=self.logger) @@ -405,32 +338,31 @@ def run(self): xrs = model.get_xray_structure() selection_bool = self.check_selection(pdb_hierarchy = ph) - #print(self.params.model_file_name) - #print(self.data_manager.get_default_model_name()) - #STOP() + f_obs, r_free_flags = self.fmodel.f_obs(), self.fmodel.r_free_flags() - f_obs, r_free_flags = self.get_fobs_rfree(crystal_symmetry = cs) print('Input data...', file=self.logger) print(' Reflection data:', f_obs.info().labels, file=self.logger) - if (r_free_flags is not None): + if (r_free_flags.info() is not None): print(' Free-R flags:', r_free_flags.info().labels, file=self.logger) else: print(' Free-R flags: not present or not found', file=self.logger) print('\nWorking crystal symmetry after inspecting all inputs:', file=self.logger) cs.show_summary(f=self.logger) - f_obs, r_free_flags = self.prepare_fobs_rfree( + if (f_obs.anomalous_flag()): + f_obs, r_free_flags = self.prepare_f_obs_and_flags_if_anomalous( f_obs = f_obs, r_free_flags = r_free_flags) - model_basename = os.path.basename(self.params.model_file_name.split(".")[0]) + model_basename = os.path.basename( + self.data_manager.get_default_model_name().split(".")[0]) if (len(model_basename) > 0 and self.params.output_file_name_prefix is None): self.params.output_file_name_prefix = model_basename - mmtbx.utils.setup_scattering_dictionaries( - scattering_table = self.params.scattering_table, - xray_structure = xrs, - d_min = f_obs.d_min()) + #mmtbx.utils.setup_scattering_dictionaries( + # scattering_table = self.params.scattering_table, + # xray_structure = xrs, + # d_min = f_obs.d_min()) polder_object = mmtbx.maps.polder.compute_polder_map( f_obs = f_obs, @@ -451,9 +383,10 @@ def run(self): print ('*'*79, file=self.logger) print ('Finished', file=self.logger) - # results object not returned because it contains maps + def get_results(self): + # results object not returned because it contains maps return group_args( message = self.message, output_file = self.output_file_name) diff --git a/mmtbx/regression/tst_polder.py b/mmtbx/regression/tst_polder.py index f984a3315f..71f154fe31 100644 --- a/mmtbx/regression/tst_polder.py +++ b/mmtbx/regression/tst_polder.py @@ -40,6 +40,9 @@ def exercise_00(prefix="tst_polder"): with open(model_fn, "w") as f: f.write(pdb_str) + pdb_hierarchy = iotbx.pdb.input( + source_info=None, lines=pdb_str).construct_hierarchy() + # create test data with phenix.fmodel mtz_fn = "tst_polder.mtz" args = [ @@ -60,10 +63,74 @@ def exercise_00(prefix="tst_polder"): 'solvent_exclusion_mask_selection="chain A" ', 'debug="True"' ] - run_program(program_class=polder.Program, args=args_polder, logger=null_out()) + r = run_program(program_class=polder.Program, args=args_polder, logger=null_out()) miller_arrays = reflection_file_reader.any_reflection_file(file_name = - "tst_polder_polder_map_coeffs.mtz").as_miller_arrays() + r.output_file).as_miller_arrays() + mmm_mp, mmm_o = check(miller_arrays, pdb_hierarchy) + assert approx_equal(mmm_mp, [0.329, 6.119, 3.333], eps=0.2) + assert approx_equal(mmm_o, [-2.838, 0.901, -1.385], eps=0.1) + + os.remove("box_1_polder.ccp4") + os.remove("box_2_polder.ccp4") + os.remove("box_3_polder.ccp4") + os.remove("box_polder.pdb") + os.remove(r.output_file) + + # now with high resolution cutoff + args_polder = [ + model_fn, + mtz_fn, + "fmodel.xray_data.high_resolution=2.2", + "sphere_radius=3", + 'solvent_exclusion_mask_selection="chain A" ', + 'output_file_name_prefix=tst_cutoff', + 'debug="True"' + ] + r = run_program(program_class=polder.Program, args=args_polder, logger=null_out()) + + miller_arrays = reflection_file_reader.any_reflection_file(file_name = + r.output_file).as_miller_arrays() + mmm_mp, mmm_o = check(miller_arrays, pdb_hierarchy) + assert approx_equal(mmm_mp, [-0.358, 5.149, 2.882], eps=0.1) + assert approx_equal(mmm_o, [-3.708, -0.734, -2.217], eps=0.1) + + os.remove(r.output_file) + os.remove("box_1_polder.ccp4") + os.remove("box_2_polder.ccp4") + os.remove("box_3_polder.ccp4") + os.remove("box_polder.pdb") + + # now with low resolution cutoff + args_polder = [ + model_fn, + mtz_fn, + "fmodel.xray_data.low_resolution=10", + "sphere_radius=3", + 'solvent_exclusion_mask_selection="chain A" ', + 'output_file_name_prefix=tst_cutoff_low', + 'debug="True"' + ] + r = run_program(program_class=polder.Program, args=args_polder, logger=null_out()) + + miller_arrays = reflection_file_reader.any_reflection_file(file_name = + r.output_file).as_miller_arrays() + mmm_mp, mmm_o = check(miller_arrays, pdb_hierarchy) + assert approx_equal(mmm_mp, [2.547, 12.601, 5.798], eps=0.1) + assert approx_equal(mmm_o, [0.325, 5.589, 2.042], eps=0.1) + + # Clean up files + os.remove(model_fn) + os.remove(mtz_fn) + os.remove(r.output_file) + os.remove("box_1_polder.ccp4") + os.remove("box_2_polder.ccp4") + os.remove("box_3_polder.ccp4") + os.remove("box_polder.pdb") + +# --------------------------------------------------------------------------- + +def check(miller_arrays, pdb_hierarchy): mc_polder, mc_bias_omit, mc_omit = [None,]*3 for ma in miller_arrays: lbl = ma.info().label_string() @@ -82,8 +149,7 @@ def exercise_00(prefix="tst_polder"): map_polder = get_map(cg=cg, mc=mc_polder) map_bias_omit = get_map(cg=cg, mc=mc_bias_omit) map_omit = get_map(cg=cg, mc=mc_omit) - pdb_hierarchy = iotbx.pdb.input( - source_info=None, lines=pdb_str).construct_hierarchy() + sel = pdb_hierarchy.atom_selection_cache().selection(string = "chain A") sites_cart_lig = pdb_hierarchy.atoms().extract_xyz().select(sel) sites_frac_lig = mc_polder.unit_cell().fractionalize(sites_cart_lig) @@ -97,17 +163,7 @@ def exercise_00(prefix="tst_polder"): #print("Biased map : %7.3f %7.3f %7.3f"%mlo.min_max_mean().as_tuple()) #print("Omit : %7.3f %7.3f %7.3f"%mmm_o) # - assert approx_equal(mmm_mp, [0.329, 6.119, 3.333], eps=0.1) - assert approx_equal(mmm_o, [-2.838, 0.901, -1.385], eps=0.1) - - # Clean up files - os.remove(model_fn) - os.remove(mtz_fn) - os.remove("box_1_polder.ccp4") - os.remove("box_2_polder.ccp4") - os.remove("box_3_polder.ccp4") - os.remove("box_polder.pdb") - os.remove("tst_polder_polder_map_coeffs.mtz") + return(mmm_mp, mmm_o) # --------------------------------------------------------------------------- diff --git a/mmtbx/regression/tst_polder_1.py b/mmtbx/regression/tst_polder_1.py index 570d875d67..4df7ac8a83 100644 --- a/mmtbx/regression/tst_polder_1.py +++ b/mmtbx/regression/tst_polder_1.py @@ -39,8 +39,8 @@ def exercise_01(fobs_1, fobs_2, flags_1, flags_2): "tst_polder_1_1.mtz", "sphere_radius=3", 'solvent_exclusion_mask_selection="%s"' % selection, - "data_labels=FP1", - "r_free_flags_labels=R-free-flags-1", + "user_selected_labels=FP1", + "user_selected_labels=R-free-flags-1", "output_file_name_prefix=tst_polder_1_1"] r = run_program(program_class=polder.Program, args=args, logger=null_out()) From 1ee846a437e4c8bfa7bbea35d35bb2ca187496c1 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 29 Mar 2024 14:22:23 -0700 Subject: [PATCH 266/748] Clean clutter :) --- mmtbx/programs/polder.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mmtbx/programs/polder.py b/mmtbx/programs/polder.py index 24160304db..c4a1aa9297 100644 --- a/mmtbx/programs/polder.py +++ b/mmtbx/programs/polder.py @@ -5,14 +5,13 @@ except ImportError: from libtbx.program_template import ProgramTemplate import os -from libtbx.utils import null_out, Sorry +from libtbx.utils import Sorry import mmtbx.maps.polder from iotbx import crystal_symmetry_from_any import mmtbx.utils from iotbx import mrcfile from libtbx import group_args from cctbx.array_family import flex -from iotbx import extract_xtal_data master_phil_str = ''' include scope libtbx.phil.interface.tracking_params From 90ca72cbd20a1970021b2eabceec9ed038fd8386 Mon Sep 17 00:00:00 2001 From: Russell Taylor Date: Fri, 29 Mar 2024 17:49:34 -0400 Subject: [PATCH 267/748] Clashscore2 (#981) * Adding initial copied scaffolding for clashscore as clashscore2. Passing the model rather than the PDB hierarchy down into clashscore2 because we'll need that for Reduce2 * Simplifying by reducing code no longer needed * Removing more code that we don't need for clashscore2 * Remove the keepExistingH parameters from mmtbx.reduce.Optimizers.Optimizer because it no longer has an impact here. The hydrogens are added in a separate step. * Switching clashscore2 over to using mmtbx.reduce from command-line reduce. * Making copies of the total model and then subsetting them for each submodel run of probe2. Fixing up models without crystal symmetry * Removing obsolete calls * Adding back in required variable * Constructing a new model from the hierarchy before copying it in clashscore2 so that all of the model elements are correct. * Trimming some unused code * Changing the plumbing so that we can pass all that we need through the system * Fixing output formatting in probe2 to match probe * Cleaning up calculation * Switching initial call to probe to use probe2 * Using correct command-line argument to determine whether probe2 should print dot count. Clarifying order of operations. * Switching second call to probe into probe2 for clashscore2 * Bumped probe minor version prior to merging into main branch * Replacing remaining calls in clashscore2 to probe program with inspection of the hierarchy * Removing redundant definition of get_results_as_JSON * Removing unused imports from clashscore2 * Removing trailing whitespace from an HTML file I didn't edit so we can pass the clutter check --- mmtbx/command_line/clashscore2.py | 49 +++ mmtbx/programs/clashscore2.py | 133 ++++++ mmtbx/programs/probe2.py | 16 +- mmtbx/programs/reduce2.py | 10 +- mmtbx/reduce/Optimizers.py | 5 +- mmtbx/validation/clashscore2.py | 697 ++++++++++++++++++++++++++++++ 6 files changed, 893 insertions(+), 17 deletions(-) create mode 100644 mmtbx/command_line/clashscore2.py create mode 100644 mmtbx/programs/clashscore2.py create mode 100644 mmtbx/validation/clashscore2.py diff --git a/mmtbx/command_line/clashscore2.py b/mmtbx/command_line/clashscore2.py new file mode 100644 index 0000000000..0356e46b81 --- /dev/null +++ b/mmtbx/command_line/clashscore2.py @@ -0,0 +1,49 @@ +from __future__ import absolute_import, division, print_function +# LIBTBX_SET_DISPATCHER_NAME phenix.clashscore2 +# LIBTBX_SET_DISPATCHER_NAME molprobity.clashscore2 +# LIBTBX_SET_DISPATCHER_NAME mmtbx.clashscore2 +# LIBTBX_PRE_DISPATCHER_INCLUDE_SH export PHENIX_GUI_ENVIRONMENT=1 + +import sys + +from iotbx.cli_parser import CCTBXParser +from libtbx.utils import multi_out, show_total_time +from mmtbx.programs import clashscore2 +from iotbx.cli_parser import run_program + +#============================================================================= +def old_run(args): + + # create parser + logger = multi_out() + logger.register('stderr', sys.stderr) + logger2 = multi_out() + logger2.register('stdout', sys.stdout) + + parser = CCTBXParser( + program_class=clashscore2.Program, + logger=logger) + namespace = parser.parse_args(sys.argv[1:]) + + # start program + print('Starting job', file=logger) + print('='*79, file=logger) + task = clashscore2.Program( + parser.data_manager, parser.working_phil.extract(), logger=logger2) + + # validate inputs + task.validate() + + # run program + task.run() + + # stop timer + print('', file=logger) + print('='*79, file=logger) + print('Job complete', file=logger) + show_total_time(out=logger) + +# ============================================================================= +if __name__ == '__main__': + #run(sys.argv[1:]) + run_program(program_class=clashscore2.Program, hide_parsing_output=True) diff --git a/mmtbx/programs/clashscore2.py b/mmtbx/programs/clashscore2.py new file mode 100644 index 0000000000..ea77a1e821 --- /dev/null +++ b/mmtbx/programs/clashscore2.py @@ -0,0 +1,133 @@ +""" +All-atom contact analysis. +This is a rewrite of the original clashscore. This version uses mmtbx.reduce and +mmtbx.probe to generate the contact information rather than stand-alone programs. +It take the same parameters as the original clashscore (except for time_limit) +and it also takes mmtbx.probe parameters. +""" + +from __future__ import absolute_import, division, print_function + +import os +from mmtbx.validation.clashscore2 import clashscore2 +from libtbx.program_template import ProgramTemplate +from datetime import datetime +from mmtbx.probe import Helpers + +try: + from phenix.program_template import ProgramTemplate +except ImportError: + pass +#from libtbx.utils import Sorry + +class Program(ProgramTemplate): + prog = os.getenv('LIBTBX_DISPATCHER_NAME') + description=""" +%(prog)s file.pdb [params.eff] [options ...] + +Options: + + model=input_file input PDB file + fast = False Produce only clashscore number, without anything else + condensed_probe=False Run probe with -CON parameter + keep_hydrogens=False keep input hydrogen atoms if True, regenerate if False + nuclear=False use nuclear x-H distances and vdW radii + json=False Outputs results as JSON compatible dictionary + verbose=True verbose text output + b_factor_cutoff=40 B factor cutoff for clash analysis + do_flips=False Do flips when adding Hs, overides keep_hydrogens + +Example: + + %(prog)s model=1ubq.pdb keep_hydrogens=True +""" % locals() + + master_phil_str = """ + model = None + .type = path + .optional = False + .help = '''input PDB file''' + + fast = False + .type = bool + .help = ''' Produce only clashscore number, without anything else''' + + condensed_probe = False + .type = bool + .help = ''' Run probe with -CON parameter ''' + + json = False + .type = bool + .help = "Prints results as JSON format dictionary" + + verbose = True + .type = bool + + keep_hydrogens = False + .type = bool + .help = '''Keep hydrogens in input file''' + + do_flips = False + .type = bool + .help = '''Do flips when adding Hsi, overides keep_hydrogens=True''' + + nuclear = False + .type = bool + .help = '''Use nuclear hydrogen positions''' + + b_factor_cutoff = None + .type = int + .help = '''B factor cutoff for use with MolProbity''' + + clash_cutoff = -0.4 + .type = float + .help = '''dummy variable for MolProbity, will be removed after MP update''' +""" + Helpers.probe_phil_parameters + +# Removed time_limit from the phil parameters +# time_limit = 120 +# .type = int +# .help = '''Time limit (sec) for Reduce optimization''' + + datatypes = ['model','phil'] + data_manager_options = ['model_skip_expand_with_mtrix'] + known_article_ids = ['molprobity'] + + def validate(self): + self.data_manager.has_models(raise_sorry=True) + + def run(self, quiet=None): #preserved how quiet was passed to the old run, not sure why + """ + Calculates nonbonded clashscore using MolProbity (PROBE) + + Returns: + When verbose=True the function print detailed results to log + When verbose=False it will print clashscore + """ + # if do_flips, make keep_hydrogens false + if self.params.do_flips : self.params.keep_hydrogens = False + self.info_json = {"model_name":self.data_manager.get_default_model_name(), + "time_analyzed": str(datetime.now())} + self.results = clashscore2( + self.params.probe, + data_manager=self.data_manager, + fast = self.params.fast, + condensed_probe = self.params.condensed_probe, + keep_hydrogens=self.params.keep_hydrogens, + nuclear=self.params.nuclear, + out=self.logger, + verbose=self.params.verbose and not quiet, + b_factor_cutoff=self.params.b_factor_cutoff, + do_flips=self.params.do_flips) + if self.params.json: + print(self.results.as_JSON()) + elif self.params.verbose: + self.results.show_old_output(out=self.logger) + else: + print(round(self.results.get_clashscore(),2), file=self.logger) + + def get_results(self): + return self.results + + def get_results_as_JSON(self): + return self.results.as_JSON(self.info_json) diff --git a/mmtbx/programs/probe2.py b/mmtbx/programs/probe2.py index d4730382f8..de9dbd23cf 100644 --- a/mmtbx/programs/probe2.py +++ b/mmtbx/programs/probe2.py @@ -29,7 +29,7 @@ # @todo See if we can remove the shift and box once reduce_hydrogen is complete from cctbx.maptbx.box import shift_and_box_model -version = "4.0.0" +version = "4.1.0" master_phil_str = ''' profile = False @@ -564,7 +564,7 @@ def Test(): class Program(ProgramTemplate): description = ''' -Probe2 version {} +probe2 version {} This program replaces the original "probe" program from the Richarson lab at Duke University and was developed by them as part of a supplemental award. @@ -920,11 +920,11 @@ def _generate_interaction_dots(self, sourceAtoms, targetSet, spatialQuery, phant # Main branch if we're reporting other than bad clashes if (not spo.only_report_bad_clashes): # We are reporting other than bad clashes, see if our type is being reported - if spo.report_hydrogen_bonds and overlapType == probeExt.OverlapType.HydrogenBond: + if spo.report_hydrogen_bonds and (overlapType == probeExt.OverlapType.HydrogenBond): show = True - elif spo.report_clashes and overlapType == probeExt.OverlapType.Clash: + elif spo.report_clashes and (overlapType == probeExt.OverlapType.Clash): show = True - elif spo.report_vdws and overlapType == probeExt.OverlapType.NoOverlap: + elif spo.report_vdws and (overlapType == probeExt.OverlapType.NoOverlap): show = True else: # We are only reporting bad clashes. See if we're reporting clashes and this is @@ -1130,7 +1130,7 @@ def _writeRawOutput(self, groupName, masterName): chainID = a.parent().parent().parent().id iCode = a.parent().parent().icode alt = a.parent().altloc - ret += "{:>2s}{:>3s} {}{} {}{:1s}:".format(chainID, resID, iCode, resName, a.name, alt) + ret += "{:>2s}{:>4s}{}{} {}{:1s}:".format(chainID, resID, iCode, resName, a.name, alt) # Describe the target atom, if it exists t = node.target @@ -1163,7 +1163,7 @@ def _writeRawOutput(self, groupName, masterName): else: # Hydrogen bond score = hydrogen_bond_weight * sl - if self.params.output.contact_summary: + if self.params.output.condensed: ret += "{}:".format(node.dotCount) ret += "{:.3f}:{:.3f}:{:.3f}:{:.3f}:{:.3f}:{:.3f}:{:.4f}".format(gap, dtgp, @@ -1847,7 +1847,7 @@ def run(self): p.pdb_interpretation.clash_guard.nonbonded_distance_threshold=None p.pdb_interpretation.proceed_with_excessive_length_bonds=True try: - self.model.process(make_restraints=True, pdb_interpretation_params=p) # make restraints + self.model.process(make_restraints=True, pdb_interpretation_params=p, logger=self.logger) # make restraints geometry = self.model.get_restraints_manager().geometry sites_cart = self.model.get_sites_cart() # cartesian coordinates bondProxies, asu = \ diff --git a/mmtbx/programs/reduce2.py b/mmtbx/programs/reduce2.py index a63c843d25..1ce9034e89 100644 --- a/mmtbx/programs/reduce2.py +++ b/mmtbx/programs/reduce2.py @@ -861,7 +861,7 @@ def _AddFlipkinMovers(states, fileBaseName, name, color, model, alts, bondedNeig class Program(ProgramTemplate): description = ''' -Reduce2 version {} +reduce2 version {} Add Hydrogens to a model and optimize their placement by adjusting movable groups and flippable groups of atoms. @@ -1059,6 +1059,7 @@ def _ReinterpretModel(self, make_restraints=True): p.pdb_interpretation.clash_guard.nonbonded_distance_threshold=None p.pdb_interpretation.use_neutron_distances = self.params.use_neutron_distances p.pdb_interpretation.proceed_with_excessive_length_bonds=True + p.pdb_interpretation.disable_uc_volume_vs_n_atoms_check=True # We need to turn this on because without it 1zz0.txt kept flipping the ring # in A TYR 214 every time we re-interpreted. The original interpretation done # by Hydrogen placement will have flipped them, so we don't need to do it again. @@ -1226,7 +1227,6 @@ def run(self): flipStates = self.params.set_flip_states, verbosity=self.params.verbosity, cliqueOutlineFileName=self.params.output.clique_outline_file_name, - keepExistingH = self.params.keep_existing_H, fillAtomDump = self.params.output.print_atom_info) doneOpt = time.time() outString += opt.getInfo() @@ -1476,8 +1476,7 @@ def run(self): nonFlipPreference=self.params.non_flip_preference, skipBondFixup=self.params.skip_bond_fix_up, flipStates = flipStates, - verbosity=3, - keepExistingH = self.params.keep_existing_H) + verbosity=3) print('Results of optimization:', file=self.logger) print(opt.getInfo(), file=self.logger) self._ReinterpretModel() @@ -1598,8 +1597,7 @@ def run(self): nonFlipPreference=self.params.non_flip_preference, skipBondFixup=self.params.skip_bond_fix_up, flipStates = flipStates, - verbosity=3, - keepExistingH = self.params.keep_existing_H) + verbosity=3) print('Results of optimization:', file=self.logger) print(opt.getInfo(), file=self.logger) self._ReinterpretModel() diff --git a/mmtbx/reduce/Optimizers.py b/mmtbx/reduce/Optimizers.py index cafa8d9d35..992ddc3d5c 100644 --- a/mmtbx/reduce/Optimizers.py +++ b/mmtbx/reduce/Optimizers.py @@ -163,7 +163,6 @@ def __init__(self, probePhil, addFlipMovers, model, modelIndex = 0, altID = None flipStates = '', verbosity = 1, cliqueOutlineFileName = None, - keepExistingH = False, fillAtomDump = True ): """Constructor. This is the wrapper class for the C++ OptimizerC and @@ -222,7 +221,6 @@ def __init__(self, probePhil, addFlipMovers, model, modelIndex = 0, altID = None colors as one master. It shows the outlines expanded by the probe radius, with a single color for each clique, as another master. These are useful for determining why the cliques are as they are. - :param keepExistingH: If True, then existing Hydrogens will be kept and not removed. :param fillAtomDump: If true, fill in the atomDump string with the atom information. This can take a long time to do, so the caller may want to turn it off if they don't need it. """ @@ -316,7 +314,7 @@ def __init__(self, probePhil, addFlipMovers, model, modelIndex = 0, altID = None # The command-line parameter matches the name of the model in the model file, which # starts with 1. The internal indexing starts with 0. So we subtract one. startModelIndex = (modelIndex - 1) - stopModelIndex = (modelIndex - 1) + 1 + stopModelIndex = startModelIndex + 1 for mi in range(startModelIndex, stopModelIndex): # Get the specified model from the hierarchy. myModel = model.get_hierarchy().models()[mi] @@ -1381,6 +1379,7 @@ def _optimizeFragment(pdb_raw, bondedNeighborDepth = 4): p.pdb_interpretation.allow_polymer_cross_special_position=True p.pdb_interpretation.clash_guard.nonbonded_distance_threshold=None p.pdb_interpretation.proceed_with_excessive_length_bonds=True + p.pdb_interpretation.disable_uc_volume_vs_n_atoms_check=True model.process(make_restraints=True,pdb_interpretation_params=p) # make restraints # Optimization will place the movers. diff --git a/mmtbx/validation/clashscore2.py b/mmtbx/validation/clashscore2.py new file mode 100644 index 0000000000..714433bc00 --- /dev/null +++ b/mmtbx/validation/clashscore2.py @@ -0,0 +1,697 @@ + +""" +All-atom contact analysis. Calls mmtbx.reduce and mmtbx.probe. +This is a rewrite of the original clashscore that used stand-alone +external reduce and probe programs. +""" + +from __future__ import absolute_import, division, print_function +from mmtbx.validation.clashscore import clash +from cctbx.maptbx.box import shift_and_box_model +from mmtbx.hydrogens import reduce_hydrogen +from mmtbx.reduce import Optimizers +from mmtbx.programs import probe2 +from mmtbx.validation import validation, atoms, atom_info +from libtbx.utils import Sorry, null_out +import iotbx.pdb +import iotbx.cli_parser +import mmtbx +import os +import re +import sys +import six +import json +import copy +import tempfile + +def remove_models_except_index(model_manager, model_index): + hierarchy = model_manager.get_hierarchy() + models = hierarchy.models() + if model_index < len(models): + selected_model = models[model_index] + for model in models: + if model != selected_model: + hierarchy.remove_model(model=model) + return model_manager + +class clashscore2(validation): + __slots__ = validation.__slots__ + [ + "clashscore", + "clashscore_b_cutoff", + "clash_dict", + "clash_dict_b_cutoff", + "list_dict", + "b_factor_cutoff", + "fast", + "condensed_probe", + "probe_file", + "probe_clashscore_manager" + ] + program_description = "Analyze clashscore for protein model" + gui_list_headers = ["Atom 1", "Atom 2", "Overlap"] + gui_formats = ["%s", "%s", ".3f"] + wx_column_widths = [150, 150, 150] #actually set in GUI's Molprobity/Core.py + + def get_result_class(self) : return clash + + def __init__(self, + probe_parameters, + data_manager, + fast = False, # do really fast clashscore, produce only the number + condensed_probe = False, # Use -CON for probe. Reduces output 10x. + keep_hydrogens=True, + nuclear=False, + force_unique_chain_ids=False, + time_limit=120, + b_factor_cutoff=None, + verbose=False, + do_flips=False, + out=sys.stdout): + validation.__init__(self) + self.b_factor_cutoff = b_factor_cutoff + self.fast = fast + self.condensed_probe = condensed_probe + self.clashscore = None + self.clashscore_b_cutoff = None + self.clash_dict = {} + self.clash_dict_b_cutoff = {} + self.list_dict = {} + self.probe_file = None + if verbose: + if not nuclear: + print("\nUsing electron cloud x-H distances and vdW radii") + else: + print("\nUsing nuclear cloud x-H distances and vdW radii") + import iotbx.pdb + from scitbx.array_family import flex + from mmtbx.validation import utils + + data_manager_model = data_manager.get_model() + # Fix up bogus unit cell when it occurs by checking crystal symmetry. + # @todo reduce_hydrogens.py:run() says: TODO temporary fix until the code is moved to model class + cs = data_manager_model.crystal_symmetry() + if (cs is None) or (cs.unit_cell() is None): + data_manager_model = shift_and_box_model(model = data_manager_model) + + # If we've been asked to, add hydrogens to all of the models in the PDB hierarchy + # associated with our data_manager_model. + data_manager_model,_ = check_and_add_hydrogen( + probe_parameters=probe_parameters, + data_manager_model=data_manager_model, + nuclear=nuclear, + verbose=verbose, + keep_hydrogens=keep_hydrogens, + do_flips = do_flips, + log=out) + + # First we must rebuild the model from the new hierarchy so that the copy can succeed. + # Make a copy of the original model to use for submodel processing, we'll trim atoms out + # of it for each submodel. + data_manager_model = mmtbx.model.manager( + model_input = None, + pdb_hierarchy = data_manager_model.get_hierarchy(), + stop_for_unknowns = False, + crystal_symmetry = data_manager_model.crystal_symmetry(), + restraint_objects = None, + log = None) + original_model = data_manager_model.deep_copy() + + pdb_hierarchy = data_manager_model.get_hierarchy() + n_models = len(pdb_hierarchy.models()) + use_segids = utils.use_segids_in_place_of_chainids( + hierarchy=pdb_hierarchy) + for i_mod, model in enumerate(pdb_hierarchy.models()): + + # Select only the current submodel from the hierarchy + submodel = original_model.deep_copy() + remove_models_except_index(submodel, i_mod) + + # Construct a hierarchy for the current submodel + r = iotbx.pdb.hierarchy.root() + mdc = submodel.get_hierarchy().models()[0].detached_copy() + r.append_model(mdc) + + occ_max = flex.max(r.atoms().extract_occ()) + input_str = r.as_pdb_string() + + # Make yet another model for the new hierarchy + subset_model_manager = mmtbx.model.manager( + model_input = None, + pdb_hierarchy = r, + stop_for_unknowns = False, + crystal_symmetry = submodel.crystal_symmetry(), + restraint_objects = None, + log = None) + + self.probe_clashscore_manager = probe_clashscore_manager( + nuclear=nuclear, + fast=self.fast, + condensed_probe=self.condensed_probe, + largest_occupancy=occ_max, + b_factor_cutoff=b_factor_cutoff, + use_segids=use_segids, + verbose=verbose, + model_id=model.id) + self.probe_clashscore_manager.run_probe_clashscore(data_manager, subset_model_manager) + + self.clash_dict[model.id] = self.probe_clashscore_manager.clashscore + self.clash_dict_b_cutoff[model.id] = self.probe_clashscore_manager.\ + clashscore_b_cutoff + self.list_dict[model.id] = self.probe_clashscore_manager.bad_clashes + if (n_models == 1) or (self.clashscore is None): + self.results = self.probe_clashscore_manager.bad_clashes + self.n_outliers = len(self.results) + self.clashscore = self.probe_clashscore_manager.clashscore + self.clashscore_b_cutoff = self.probe_clashscore_manager.\ + clashscore_b_cutoff + + def get_clashscore(self): + return self.clashscore + + def get_clashscore_b_cutoff(self): + return self.clashscore_b_cutoff + + def show_old_output(self, out=sys.stdout, verbose=False): + self.print_clashlist_old(out=out) + self.show_summary(out=out) + + def show_summary(self, out=sys.stdout, prefix=""): + if self.clashscore is None: + raise Sorry("PROBE output is empty. Model is not compatible with PROBE.") + elif (len(self.clash_dict) == 1): + #FIXME indexing keys can break py2/3 compat if more than 1 key + k = list(self.clash_dict.keys())[0] + #catches case where file has 1 model, but also has model/endmdl cards + print(prefix + "clashscore = %.2f" % self.clash_dict[k], file=out) + if self.clash_dict_b_cutoff[k] is not None and self.b_factor_cutoff is not None: + print("clashscore (B factor cutoff = %d) = %f" % \ + (self.b_factor_cutoff, + self.clash_dict_b_cutoff[k]), file=out) + else: + for k in sorted(self.clash_dict.keys()): + print(prefix + "MODEL %s clashscore = %.2f" % (k, + self.clash_dict[k]), file=out) + if self.clash_dict_b_cutoff[k] is not None and self.b_factor_cutoff is not None: + print("MODEL%s clashscore (B factor cutoff = %d) = %f" % \ + (k, self.b_factor_cutoff, self.clash_dict_b_cutoff[k]), file=out) + + def print_clashlist_old(self, out=sys.stdout): + if self.fast: + print("Bad Clashes >= 0.4 Angstrom - not available in fast=True mode", file=out) + return + for k in self.list_dict.keys(): + if k == '': + print("Bad Clashes >= 0.4 Angstrom:", file=out) + for result in self.list_dict[k] : + print(result.format_old(), file=out) + else: + print("Bad Clashes >= 0.4 Angstrom MODEL%s" % k, file=out) + for result in self.list_dict[k] : + print(result.format_old(), file=out) + + def show(self, out=sys.stdout, prefix="", outliers_only=None, verbose=None): + if (len(self.clash_dict) == 1): + for result in self.list_dict[''] : + print(prefix + str(result), file=out) + else : + for k in self.list_dict.keys(): + for result in self.list_dict[k] : + print(prefix + str(result), file=out) + self.show_summary(out=out, prefix=prefix) + + def as_JSON(self, addon_json={}): + if not addon_json: + addon_json = {} + addon_json["validation_type"] = "clashscore" + data = addon_json + flat_results = [] + hierarchical_results = {} + residue_clash_list = [] + summary_results = {} + for k in sorted(self.list_dict.keys()): + for result in self.list_dict[k]: + flat_results.append(json.loads(result.as_JSON())) + hier_result = json.loads(result.as_hierarchical_JSON()) + hierarchical_results = self.merge_dict(hierarchical_results, hier_result) + + data['flat_results'] = flat_results + data['hierarchical_results'] = hierarchical_results + + for k in sorted(self.clash_dict.keys()): + summary_results[k] = {"clashscore": self.clash_dict[k], + "num_clashes": len(self.list_dict[k])} + data['summary_results'] = summary_results + return json.dumps(data, indent=2) + + def as_coot_data(self): + data = [] + for result in self.results : + if result.is_outlier(): + data.append((result.atoms_info[0].id_str(), + result.atoms_info[1].id_str(), result.overlap, result.xyz)) + return data + +class probe_line_info(object): # this is parent + def __init__(self, line, model_id=""): + self.overlap_value = None + self.model_id = model_id + + def is_similar(self, other): + assert type(self) is type(other) + return (self.srcAtom == other.srcAtom and self.targAtom == other.targAtom) + + def as_clash_obj(self, use_segids): + assert self.overlap_value is not None + atom1 = decode_atom_string(self.srcAtom, use_segids, self.model_id) + atom2 = decode_atom_string(self.targAtom, use_segids, self.model_id) + if (self.srcAtom < self.targAtom): + atoms = [ atom1, atom2 ] + else: + atoms = [ atom2, atom1 ] + clash_obj = clash( + atoms_info=atoms, + overlap=self.overlap_value, + probe_type=self.type, + outlier=self.overlap_value <= -0.4, + max_b_factor=max(self.sBval, self.tBval), + xyz=(self.x,self.y,self.z)) + return clash_obj + +class condensed_probe_line_info(probe_line_info): + def __init__(self, line, model_id=""): + super(condensed_probe_line_info, self).__init__(line, model_id) + # What is in line: + # name:pat:type:srcAtom:targAtom:dot-count:mingap:gap:spX:spY:spZ:spikeLen:score:stype:ttype:x:y:z:sBval:tBval: + sp = line.split(":") + self.type = sp[2] + self.srcAtom = sp[3] + self.targAtom = sp[4] + self.min_gap = float(sp[6]) + self.gap = float(sp[7]) + self.x = float(sp[-5]) + self.y = float(sp[-4]) + self.z = float(sp[-3]) + self.sBval = float(sp[-2]) + self.tBval = float(sp[-1]) + self.overlap_value = self.gap + +class raw_probe_line_info(probe_line_info): + def __init__(self, line, model_id=""): + super(raw_probe_line_info, self).__init__(line, model_id) + self.name, self.pat, self.type, self.srcAtom, self.targAtom, self.min_gap, \ + self.gap, self.kissEdge2BullsEye, self.dot2BE, self.dot2SC, self.spike, \ + self.score, self.stype, self.ttype, self.x, self.y, self.z, self.sBval, \ + self.tBval = line.split(":") + self.gap = float(self.gap) + self.x = float(self.x) + self.y = float(self.y) + self.z = float(self.z) + self.sBval = float(self.sBval) + self.tBval = float(self.tBval) + self.overlap_value = self.gap + + +class probe_clashscore_manager(object): + def __init__(self, + fast = False, + condensed_probe=False, + nuclear=False, + largest_occupancy=10, + b_factor_cutoff=None, + use_segids=False, + verbose=False, + model_id=""): + """ + Calculate probe (MolProbity) clashscore + + Args: + nuclear (bool): When True use nuclear cloud x-H distances and vdW radii, + otherwise use electron cloud x-H distances and vdW radii + largest_occupancy (int) + b_factor_cutoff (float) + use_segids (bool) + verbose (bool): verbosity of printout + model_id (str): model ID number, used in json output + """ + if fast and not condensed_probe: + raise Sorry("Incompatible parameters: fast=True and condensed=False:\n"+\ + "There's no way to work fast without using condensed output.") + + self.b_factor_cutoff = b_factor_cutoff + self.fast = fast + self.condensed_probe = condensed_probe + self.use_segids=use_segids + self.model_id = model_id + self.occupancy_frac = 0.1 + if largest_occupancy / 100 < self.occupancy_frac: + self.occupancy_frac = largest_occupancy / 100 + self.nuclear = nuclear + + def put_group_into_dict(self, line_info, clash_hash, hbond_hash): + key = line_info.targAtom+line_info.srcAtom + if (line_info.srcAtom < line_info.targAtom): + key = line_info.srcAtom+line_info.targAtom + if line_info.type == "bo": + if (line_info.overlap_value <= -0.4): + if (key in clash_hash): + if (line_info.overlap_value < clash_hash[key].overlap_value): + clash_hash[key] = line_info + else : + clash_hash[key] = line_info + elif (line_info.type == "hb"): + if self.condensed_probe: + hbond_hash[key] = line_info + else: # not condensed + if (key in hbond_hash): + if (line_info.gap < hbond_hash[key].gap): + hbond_hash[key] = line_info + else : + hbond_hash[key] = line_info + + def filter_dicts(self, new_clash_hash, new_hbond_hash): + temp = [] + for k,v in six.iteritems(new_clash_hash): + if k not in new_hbond_hash: + temp.append(v.as_clash_obj(self.use_segids)) + return temp + + def process_raw_probe_output(self, probe_unformatted): + new_clash_hash = {} + new_hbond_hash = {} + if self.condensed_probe: + for line in probe_unformatted: + try: + line_storage = condensed_probe_line_info(line, self.model_id) + except KeyboardInterrupt: raise + except ValueError: + continue # something else (different from expected) got into output + self.put_group_into_dict(line_storage, new_clash_hash, new_hbond_hash) + else: # not condensed + previous_line = None + for line in probe_unformatted: + processed=False + try: + line_storage = raw_probe_line_info(line, self.model_id) + except KeyboardInterrupt: raise + except ValueError: + continue # something else (different from expected) got into output + + if previous_line is not None: + if line_storage.is_similar(previous_line): + # modify previous line to store this one if needed + previous_line.overlap_value = min(previous_line.overlap_value, line_storage.overlap_value) + else: + # seems like new group of lines, then dump previous and start new + # one + self.put_group_into_dict(previous_line, new_clash_hash, new_hbond_hash) + previous_line = line_storage + else: + previous_line = line_storage + if previous_line is not None: + self.put_group_into_dict(previous_line, new_clash_hash, new_hbond_hash) + return self.filter_dicts(new_clash_hash, new_hbond_hash) + + def get_condensed_clashes(self, lines): + # Standalone faster parsing of output when only clashscore is needed. + def parse_line(line): + sp = line.split(':') + return sp[3], sp[4], float(sp[7]) + def parse_h_line(line): + sp = line.split(':') + return sp[3], sp[4] + + clashes = set() # [(src, targ), (src, targ)] + hbonds = [] # (src, targ), (targ, src) + for l in lines: + rtype = l[6:8] + if rtype == 'bo': + srcAtom, targAtom, gap = parse_line(l) + if gap <= -0.4: + # print l[:43], "good gap, saving", gap + if (srcAtom, targAtom) not in clashes and (targAtom, srcAtom) not in clashes: + clashes.add((srcAtom, targAtom)) + # print (srcAtom, targAtom) + elif rtype == 'hb': + srcAtom, targAtom = parse_h_line(l) + hbonds.append((srcAtom, targAtom)) + hbonds.append((targAtom, srcAtom)) + prev_line = l + hbonds_set = set(hbonds) + n_clashes = 0 + # print "clashes", len(clashes) + # print "hbonds", len(hbonds) + for clash in clashes: + if clash not in hbonds_set: + n_clashes += 1 + # else: + # print "skipping", clash + return n_clashes + + # We have to take both the original data manager, which is from the model + # without hydrogens, and the hydrogenated modified model because we need one + # to construct a Probe2 program and the other to replace its model to run on. + def run_probe_clashscore(self, data_manager, hydrogenated_model): + self.n_clashes = 0 + self.n_clashes_b_cutoff = 0 + self.clashscore_b_cutoff = None + self.bad_clashes = [] + self.clashscore = None + self.n_atoms = 0 + self.natoms_b_cutoff = 0 + + # Construct override parameters and then run probe2 using them and delete the resulting + # temporary file. + tempName = tempfile.mktemp() + parser = iotbx.cli_parser.CCTBXParser(program_class=probe2.Program, logger=null_out()) + args = [ + "source_selection='(occupancy > {}) and not water'".format(self.occupancy_frac), + "target_selection='occupancy > {}'".format(self.occupancy_frac), + "use_neutron_distances={}".format(self.nuclear), + "approach=once", + "output.filename='{}'".format(tempName), + "output.format=raw", + "output.condensed={}".format(self.condensed_probe), + "output.report_vdws=False", + "ignore_lack_of_explicit_hydrogens=True", + ] + parser.parse_args(args) + p2 = probe2.Program(data_manager, parser.working_phil.extract(), + master_phil=parser.master_phil, logger=null_out()) + p2.overrideModel(hydrogenated_model) + dots, output = p2.run() + probe_unformatted = output.splitlines() + os.unlink(tempName) + + # Debugging facility, do not remove! + # import random + # pdb_string = hydrogenated_model.get_hierarchy().as_pdb_string() + # tempdir = "tmp_for_probe_debug_%d" % random.randint(1000,9999) + # while os.path.isdir(tempdir): + # tempdir = "tmp_for_probe_debug_%d" % random.randint(1000,9999) + # os.mkdir(tempdir) + # print ("Dumping info to %s" % tempdir) + # with open(tempdir + os.sep + 'model.pdb', 'w') as f: + # f.write(pdb_string) + # with open(tempdir + os.sep + 'probe_out.txt', 'w') as f: + # f.write('\n'.join(probe_unformatted)) + + if not self.fast: + temp = self.process_raw_probe_output(probe_unformatted) + self.n_clashes = len(temp) + + # If we're not running fast, call probe2 again to get non-condensed output + # including VDW contacts. We make another temporary file for the output and + # then delete it. This option is for printing to file for coot usage. The + # no-VDWOUT option is used to speed up the parsing of the output. + tempName = tempfile.mktemp() + parser = iotbx.cli_parser.CCTBXParser(program_class=probe2.Program, logger=null_out()) + args = [ + "source_selection='(occupancy > {}) and not water'".format(self.occupancy_frac), + "target_selection='occupancy > {}'".format(self.occupancy_frac), + "use_neutron_distances={}".format(self.nuclear), + "approach=once", + "output.filename='{}'".format(tempName), + "output.format=raw", + "ignore_lack_of_explicit_hydrogens=True", + ] + parser.parse_args(args) + p2 = probe2.Program(data_manager, parser.working_phil.extract(), + master_phil=parser.master_phil, logger=null_out()) + p2.overrideModel(hydrogenated_model) + dots, output = p2.run() + self.probe_unformatted = "\n".join(output.splitlines()) + os.unlink(tempName) + else: + self.n_clashes = self.get_condensed_clashes(probe_unformatted) + + # Find the number of non-water atoms that pass the occupancy test + # and then use it to compute the clashscore. + self.n_atoms = 0 + for a in hydrogenated_model.get_hierarchy().atoms(): + isWater = iotbx.pdb.common_residue_names_get_class(name=a.parent().resname) == "common_water" + if a.occ > self.occupancy_frac and not isWater: + self.n_atoms += 1 + if self.n_atoms == 0: + self.clashscore = 0.0 + else: + self.clashscore = (self.n_clashes * 1000) / self.n_atoms + + if not self.fast: + # The rest is not necessary, we already got clashscore + if self.b_factor_cutoff is not None: + clashes_b_cutoff = 0 + for clash_obj in temp: + if clash_obj.max_b_factor < self.b_factor_cutoff: + clashes_b_cutoff += 1 + self.n_clashes_b_cutoff = clashes_b_cutoff + used = [] + + for clash_obj in sorted(temp): + test_key = clash_obj.id_str_no_atom_name() + test_key = clash_obj.id_str() + if test_key not in used: + used.append(test_key) + self.bad_clashes.append(clash_obj) + + if self.b_factor_cutoff is not None: + # Find the number of non-water atoms who pass the B factor test and the occupancy test + self.natoms_b_cutoff = 0 + for a in hydrogenated_model.get_hierarchy().atoms(): + isWater = iotbx.pdb.common_residue_names_get_class(name=a.parent().resname) == "common_water" + if (a.b < self.b_factor_cutoff) and (a.occ > self.occupancy_frac) and not isWater: + self.natoms_b_cutoff += 1 + self.clashscore_b_cutoff = None + if self.natoms_b_cutoff == 0: + self.clashscore_b_cutoff = 0.0 + else : + self.clashscore_b_cutoff = \ + (self.n_clashes_b_cutoff*1000) / self.natoms_b_cutoff + +def decode_atom_string(atom_str, use_segids=False, model_id=""): + # Example: + # ' A 49 LEU HD11B' + if (not use_segids) or (len(atom_str) == 16): + return atom_info( + model_id=model_id, + chain_id=atom_str[0:2], + resseq=atom_str[2:6], + icode=atom_str[6], + resname=atom_str[7:10], + altloc=atom_str[15], + name=atom_str[11:15]) + else: + return atom_info( + model_id=model_id, + chain_id=atom_str[0:4], + resseq=atom_str[4:8], + icode=atom_str[8], + resname=atom_str[9:12], + altloc=atom_str[17], + name=atom_str[13:17]) + +def check_and_add_hydrogen( + probe_parameters=None, + data_manager_model=None, + nuclear=False, + keep_hydrogens=True, + verbose=False, + n_hydrogen_cut_off=0, + do_flips=False, + log=None): + """ + If no hydrogens present, force addition for clashscore calculation. + Use REDUCE to add the hydrogen atoms. + + Args: + data_manager_model : Model from the data_manager + nuclear (bool): When True use nuclear cloud x-H distances and vdW radii, + otherwise use electron cloud x-H distances and vdW radii + keep_hydrogens (bool): when True, if there are hydrogen atoms, keep them + verbose (bool): verbosity of printout + n_hydrogen_cut_off (int): when number of hydrogen atoms < n_hydrogen_cut_off + force keep_hydrogens tp True + + Returns: + (model): Model with hydrogens added + (bool): True when the model was modified/replaced + """ + if not log: log = sys.stdout + assert probe_parameters + assert data_manager_model + if keep_hydrogens: + elements = data_manager_model.get_hierarchy.root().atoms().extract_element() + # strangely the elements can have a space when coming from phenix.clashscore + # but no space when coming from phenix.molprobity + h_count = elements.count('H') + if h_count <= n_hydrogen_cut_off: h_count += elements.count(' H') + if h_count <= n_hydrogen_cut_off: h_count += elements.count('D') + if h_count <= n_hydrogen_cut_off: h_count += elements.count(' D') + if h_count > n_hydrogen_cut_off: + has_hd = True + else: + has_hd = False + if not has_hd: + if verbose: + print("\nNo H/D atoms detected - forcing hydrogen addition!\n", file=log) + keep_hydrogens = False + + # add hydrogen if needed + if not keep_hydrogens: + # Remove hydrogens and add them back in + if verbose: + print("\nTrimming and adding hydrogens...\n") + reduce_add_h_obj = reduce_hydrogen.place_hydrogens( + model = data_manager_model, + use_neutron_distances=nuclear, + n_terminal_charge="residue_one", + exclude_water=True, + stop_for_unknowns=False, + keep_existing_H=False + ) + reduce_add_h_obj.run() + reduce_add_h_obj.show(None) + missed_residues = set(reduce_add_h_obj.no_H_placed_mlq) + if len(missed_residues) > 0: + bad = "" + for res in missed_residues: + bad += " " + res + raise Sorry("Restraints were not found for the following residues:"+bad) + data_manager_model = reduce_add_h_obj.get_model() + + # Optimize H atoms with mmtbx.reduce + if verbose: + print("\nOptimizing H atoms with mmtbx.reduce...\n") + opt = Optimizers.Optimizer(probe_parameters, do_flips, data_manager_model, modelIndex=None, + fillAtomDump = False) + + # Re-process the model because we have removed some atoms that were previously + # bonded. Don't make restraints during the reprocessing. + # We had to do this to keep from crashing on a call to pair_proxies when generating + # mmCIF files, so we always do it for safety. + data_manager_model.get_hierarchy().sort_atoms_in_place() + data_manager_model.get_hierarchy().atoms().reset_serial() + p = mmtbx.model.manager.get_default_pdb_interpretation_params() + p.pdb_interpretation.allow_polymer_cross_special_position=True + p.pdb_interpretation.clash_guard.nonbonded_distance_threshold=None + p.pdb_interpretation.use_neutron_distances = nuclear + p.pdb_interpretation.proceed_with_excessive_length_bonds=True + p.pdb_interpretation.disable_uc_volume_vs_n_atoms_check=True + # We need to turn this on because without it 1zz0.txt kept flipping the ring + # in A TYR 214 every time we re-interpreted. The original interpretation done + # by Hydrogen placement will have flipped them, so we don't need to do it again. + p.pdb_interpretation.flip_symmetric_amino_acids=False + #p.pdb_interpretation.sort_atoms=True + data_manager_model.process(make_restraints=False, pdb_interpretation_params=p) + + return data_manager_model, True + else: + if verbose: + print("\nUsing input model H/D atoms...\n") + return data_manager_model, False + + def show(self, out=sys.stdout, prefix=""): + if (self.n_outliers == 0): + print(prefix+"No backwards Asn/Gln/His sidechains found.", file=out) + else : + for flip in self.results : + print(prefix+flip.as_string(), file=out) From 81b7f5fd10d6d800dda7a801e4e23f4292dafb72 Mon Sep 17 00:00:00 2001 From: terwill Date: Fri, 29 Mar 2024 16:14:37 -0600 Subject: [PATCH 268/748] Allow specifying altloc_to_keep in remove_alt_confs --- iotbx/pdb/hierarchy.py | 26 +++++++++++++++++++----- mmtbx/pdbtools.py | 10 +++++++-- mmtbx/regression/tst_pdbtools.py | 35 ++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 7 deletions(-) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index 41562f7e32..a898489077 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -1942,7 +1942,7 @@ def remove_incomplete_main_chain_protein(self, if (len(chain.residue_groups()) == 0): model.remove_chain(chain=chain) - def remove_alt_confs(self, always_keep_one_conformer): + def remove_alt_confs(self, always_keep_one_conformer, altloc_to_keep = None): hierarchy = self for model in hierarchy.models(): for chain in model.chains(): @@ -1954,19 +1954,35 @@ def remove_alt_confs(self, always_keep_one_conformer): if (len(atom_groups) == 1) and (atom_groups[0].altloc == ''): continue atom_groups_and_occupancies = [] + altlocs_found = [] for atom_group in atom_groups : - if (atom_group.altloc == ''): + if (atom_group.altloc == ''): # always keep '' continue + mean_occ = flex.mean(atom_group.atoms().extract_occ()) atom_groups_and_occupancies.append((atom_group, mean_occ)) - atom_groups_and_occupancies.sort(key=operator.itemgetter(1), reverse=True) - for atom_group, occ in atom_groups_and_occupancies[1:] : + altlocs_found.append(atom_group.altloc) + + if (altloc_to_keep is not None) and (altloc_to_keep in + altlocs_found): # put altloc_to_keep first + for atom_group_and_occupancy in atom_groups_and_occupancies: + if atom_group_and_occupancy[0].altloc == altloc_to_keep: + atom_groups_and_occupancies.remove(atom_group_and_occupancy) + atom_groups_and_occupancies = [atom_group_and_occupancy] + \ + atom_groups_and_occupancies + break + else: # put atom_group with highest occupancy first + atom_groups_and_occupancies.sort(key=operator.itemgetter(1), + reverse=True) + + for atom_group, occ in atom_groups_and_occupancies[1:]: residue_group.remove_atom_group(atom_group=atom_group) single_conf, occ = atom_groups_and_occupancies[0] single_conf.altloc = '' else : for atom_group in atom_groups : - if (not atom_group.altloc in ["", "A"]): + if (not atom_group.altloc in ["", + altloc_to_keep if (altloc_to_keep is not None) else "A"]): residue_group.remove_atom_group(atom_group=atom_group) else : atom_group.altloc = "" diff --git a/mmtbx/pdbtools.py b/mmtbx/pdbtools.py index 337f4db7f7..7fba5b9afe 100644 --- a/mmtbx/pdbtools.py +++ b/mmtbx/pdbtools.py @@ -176,6 +176,12 @@ .help = Modifies behavior of remove_alt_confs so that residues with no \ conformer labeled blank or A are not deleted. Silent if remove_alt_confs \ is False. +altloc_to_keep = None + .type = str + .help = Modifies behavior of remove_alt_confs so that the altloc identifier \ + to keep in addition to blank is this one (instead of 'A'). \ + Silent if remove_alt_confs is False. + .short_caption = Conformer to keep set_chemical_element_simple_if_necessary = None .type = bool .short_caption = Guess element field if necessary @@ -389,9 +395,9 @@ def _move_waters(self): def _remove_alt_confs(self): if(self.params.remove_alt_confs): print("Remove altlocs", file=self.log) - always_keep_one_conformer = self.params.always_keep_one_conformer self.pdb_hierarchy.remove_alt_confs( - always_keep_one_conformer = self.params.always_keep_one_conformer) + always_keep_one_conformer = self.params.always_keep_one_conformer, + altloc_to_keep = self.params.altloc_to_keep) def _truncate_to_poly_gly(self): if(self.params.truncate_to_polygly): diff --git a/mmtbx/regression/tst_pdbtools.py b/mmtbx/regression/tst_pdbtools.py index 94620b281c..63b5a49192 100644 --- a/mmtbx/regression/tst_pdbtools.py +++ b/mmtbx/regression/tst_pdbtools.py @@ -1040,6 +1040,40 @@ def exercise_remove_alt_confs(): """) cmd = "phenix.pdbtools tst_pdbtools_alt_confs.pdb remove_alt_confs=True " +\ "always_keep_one_conformer=True" + print(cmd) + run_command(command=cmd, verbose=False) + with open("tst_pdbtools_alt_confs_modified.pdb") as f: + pdb_new = f.read() + assert (pdb_new == """\ +ATOM 1 O HOH A 2 5.131 5.251 5.823 1.00 10.00 O +ATOM 2 CA LYS A 32 10.574 8.177 11.768 1.00 11.49 C +ATOM 3 CB LYS A 32 9.193 8.732 12.170 1.00 12.23 C +ATOM 4 CA VAL A 33 11.708 5.617 14.332 1.00 11.42 C +ATOM 5 CB VAL A 33 11.101 4.227 14.591 1.00 11.47 C +ATOM 6 O HOH A 3 1.132 5.963 7.065 1.00 15.00 O +ATOM 7 O HOH A 4 4.132 9.963 7.800 1.00 15.00 O +TER +END +""") + cmd = "phenix.pdbtools tst_pdbtools_alt_confs.pdb remove_alt_confs=True altloc_to_keep='B' " + print(cmd) + run_command(command=cmd, verbose=False) + with open("tst_pdbtools_alt_confs_modified.pdb") as f: + pdb_new = f.read() + + assert (pdb_new == """\ +ATOM 1 CA LYS A 32 10.574 8.177 11.768 1.00 11.49 C +ATOM 2 CB LYS A 32 9.193 8.732 12.170 1.00 12.23 C +ATOM 3 CA VAL A 33 11.708 5.617 14.332 1.00 11.42 C +ATOM 4 CB VAL A 33 11.101 4.227 14.591 1.00 11.47 C +ATOM 5 O HOH A 3 1.132 5.963 7.065 1.00 15.00 O +ATOM 6 O HOH A 4 4.132 9.963 7.800 1.00 15.00 O +TER +END +""") + cmd = "phenix.pdbtools tst_pdbtools_alt_confs.pdb remove_alt_confs=True " +\ + "always_keep_one_conformer=True altloc_to_keep='B' " + print(cmd) run_command(command=cmd, verbose=False) with open("tst_pdbtools_alt_confs_modified.pdb") as f: pdb_new = f.read() @@ -1055,6 +1089,7 @@ def exercise_remove_alt_confs(): END """) + def exercise_convert_met_to_semet(): pdb_str_met = """ ATOM 1 N MET B 37 7.525 5.296 6.399 1.00 10.00 N From a6ad995604e0c11e863dd7936a921c2108acdf42 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 29 Mar 2024 17:12:33 -0700 Subject: [PATCH 269/748] Increase tolerance. --- mmtbx/regression/tst_polder.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mmtbx/regression/tst_polder.py b/mmtbx/regression/tst_polder.py index 71f154fe31..68d1472e81 100644 --- a/mmtbx/regression/tst_polder.py +++ b/mmtbx/regression/tst_polder.py @@ -68,8 +68,8 @@ def exercise_00(prefix="tst_polder"): miller_arrays = reflection_file_reader.any_reflection_file(file_name = r.output_file).as_miller_arrays() mmm_mp, mmm_o = check(miller_arrays, pdb_hierarchy) - assert approx_equal(mmm_mp, [0.329, 6.119, 3.333], eps=0.2) - assert approx_equal(mmm_o, [-2.838, 0.901, -1.385], eps=0.1) + assert approx_equal(mmm_mp, [0.329, 6.119, 3.333], eps=0.15) + assert approx_equal(mmm_o, [-2.838, 0.901, -1.385], eps=0.15) os.remove("box_1_polder.ccp4") os.remove("box_2_polder.ccp4") @@ -92,8 +92,8 @@ def exercise_00(prefix="tst_polder"): miller_arrays = reflection_file_reader.any_reflection_file(file_name = r.output_file).as_miller_arrays() mmm_mp, mmm_o = check(miller_arrays, pdb_hierarchy) - assert approx_equal(mmm_mp, [-0.358, 5.149, 2.882], eps=0.1) - assert approx_equal(mmm_o, [-3.708, -0.734, -2.217], eps=0.1) + assert approx_equal(mmm_mp, [-0.358, 5.149, 2.882], eps=0.15) + assert approx_equal(mmm_o, [-3.708, -0.734, -2.217], eps=0.15) os.remove(r.output_file) os.remove("box_1_polder.ccp4") @@ -116,8 +116,8 @@ def exercise_00(prefix="tst_polder"): miller_arrays = reflection_file_reader.any_reflection_file(file_name = r.output_file).as_miller_arrays() mmm_mp, mmm_o = check(miller_arrays, pdb_hierarchy) - assert approx_equal(mmm_mp, [2.547, 12.601, 5.798], eps=0.1) - assert approx_equal(mmm_o, [0.325, 5.589, 2.042], eps=0.1) + assert approx_equal(mmm_mp, [2.547, 12.601, 5.798], eps=0.15) + assert approx_equal(mmm_o, [0.325, 5.589, 2.042], eps=0.15) # Clean up files os.remove(model_fn) From cdb49aee4e5dbb5ad7215e58a0aebd1b6c405d7e Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 29 Mar 2024 17:51:11 -0700 Subject: [PATCH 270/748] Polder: changes for the GUI --- mmtbx/programs/polder.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/mmtbx/programs/polder.py b/mmtbx/programs/polder.py index c4a1aa9297..b9c8d51a12 100644 --- a/mmtbx/programs/polder.py +++ b/mmtbx/programs/polder.py @@ -8,7 +8,6 @@ from libtbx.utils import Sorry import mmtbx.maps.polder from iotbx import crystal_symmetry_from_any -import mmtbx.utils from iotbx import mrcfile from libtbx import group_args from cctbx.array_family import flex @@ -47,6 +46,16 @@ output_dir = None .type = path .style = output_dir + + data_column_label = None + .type = str + .style = noauto renderer:draw_any_label_widget + .input_size = 200 + + free_column_label = None + .type = str + .style = noauto renderer:draw_any_label_widget + .input_size = 200 } ''' @@ -358,11 +367,6 @@ def run(self): if (len(model_basename) > 0 and self.params.output_file_name_prefix is None): self.params.output_file_name_prefix = model_basename - #mmtbx.utils.setup_scattering_dictionaries( - # scattering_table = self.params.scattering_table, - # xray_structure = xrs, - # d_min = f_obs.d_min()) - polder_object = mmtbx.maps.polder.compute_polder_map( f_obs = f_obs, r_free_flags = r_free_flags, @@ -388,4 +392,5 @@ def get_results(self): # results object not returned because it contains maps return group_args( message = self.message, - output_file = self.output_file_name) + output_file = self.output_file_name, + model = self.data_manager.get_default_model_name()) From ae44c81e2e24894aabc11efc26607f9bbd4bdadb Mon Sep 17 00:00:00 2001 From: terwill Date: Sat, 30 Mar 2024 04:38:49 -0600 Subject: [PATCH 271/748] Add altlocs_present --- iotbx/pdb/hierarchy.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index a898489077..f5b97f0970 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -1942,6 +1942,19 @@ def remove_incomplete_main_chain_protein(self, if (len(chain.residue_groups()) == 0): model.remove_chain(chain=chain) + def altlocs_present(self, skip_blank = True): + hierarchy = self + altlocs_present = [] + for model in hierarchy.models(): + for chain in model.chains(): + for residue_group in chain.residue_groups(): + for atom_group in residue_group.atom_groups(): + if skip_blank and (atom_group.altloc.strip() == ''): + continue # ignore blanks + if not atom_group.altloc in altlocs_present: + altlocs_present.append(atom_group.altloc) + return altlocs_present + def remove_alt_confs(self, always_keep_one_conformer, altloc_to_keep = None): hierarchy = self for model in hierarchy.models(): From e173a6c62ec41a2afc960869e0eb76bfa0d771f4 Mon Sep 17 00:00:00 2001 From: Nicholas K Sauter Date: Sun, 31 Mar 2024 14:04:16 -0700 Subject: [PATCH 272/748] Test case for prospective low-memory exascale API. Test passes now, but will later require the API to simulate shoebox pixels with ~10-fold lower memory consumption and thus fail until the fix is in. --- simtbx/run_tests.py | 1 + simtbx/tests/tst_memory_policy.py | 393 ++++++++++++++++++++++++++++++ simtbx/tests/tst_unified.py | 2 +- 3 files changed, 395 insertions(+), 1 deletion(-) create mode 100644 simtbx/tests/tst_memory_policy.py diff --git a/simtbx/run_tests.py b/simtbx/run_tests.py index 7add96ae7c..3d54eec102 100644 --- a/simtbx/run_tests.py +++ b/simtbx/run_tests.py @@ -94,6 +94,7 @@ ["$D/gpu/tst_exafel_api.py","context=kokkos_gpu"],# GPU in kokkos ["$D/tests/tst_unified.py","context=kokkos_gpu"],# GPU, exaFEL full API ["$D/gpu/tst_shoeboxes.py","context=kokkos_gpu"],# GPU, test whitelist API + ["$D/tests/tst_memory_policy.py","context=kokkos_gpu"], ] if OPT.enable_kokkos: if OPT.enable_cxx11 and sys.platform != 'win32': diff --git a/simtbx/tests/tst_memory_policy.py b/simtbx/tests/tst_memory_policy.py new file mode 100644 index 0000000000..95f8755643 --- /dev/null +++ b/simtbx/tests/tst_memory_policy.py @@ -0,0 +1,393 @@ +""" +Extend the previous tests in tst_unified +New tests question if there is a difference between all-pixel vs. shoebox-only calculation +Old style (policy == "large_array"): all-pixel and shoebox-only have identical GPU memory footprint +New style (policy == "small_whitelist"): all-pixel and shoebox-only have very different GPU memory footprint + +Explanation of function: + representation of pixels on GPU: + simulation_kernels.h: + kokkosSpotsKernel: vector_float_t floatimage + debranch_maskall_Kernel: vector_float_t floatimage + + calling pattern for the kernels: + simulation.cpp: add_energy_channel_from_gpu_amplitudes calls kokkosSpotsKernel (not a target) + simulation.cpp: add_energy_channel_mask_allpanel calls debranch_maskall_Kernel, tested by tst_shoeboxes + simulation.cpp: add_energy_multichannel_mask_allpanel calls debranch_maskall_Kernel, tested by tst_unified + each of these calls takes GPU::m_accumulate_floatimage += GPU::m_floatimage + + python calls in gpu_detector that interact with data: + .def("scale_in_place", "Multiply by a scale factor on the GPU") + .def("write_raw_pixels", "Update CPU raw_pixels on host with array from GPU::m_accumulate_floatimage") + .def("get_raw_pixels", "return multipanel detector pixels from GPU::m_accumulate_floatimage as a flex array") + .def("get_whitelist_raw_pixels", "return only the raw pixels of the whitelist selection, as a 1D flex array, from first memory positions in GPU::m_accumulate_floatimage") + +Brief synopsis of this test suite: +1) simple whole-image simulation using add_energy_channel_from_gpu_amplitudes() +2) comparison whole-image simulation using add_energy_multichannel_mask_allpanel() + also includes instrumentation to show CPU & GPU memory consumption +3) repeat step 2, but only using a whitelist of a few thousand pixels +""" +from __future__ import absolute_import, division, print_function +import numpy as np +import dxtbx +from scitbx.array_family import flex +from scitbx.matrix import sqr +from simtbx.nanoBragg import nanoBragg, shapetype +from simtbx.nanoBragg.tst_gauss_argchk import basic_crystal, basic_beam, basic_detector, amplitudes +from simtbx import get_exascale +from simtbx.tests.tst_unified import several_wavelength_case as several_wavelength_case_unified + +import subprocess as sp +import os + +def get_gpu_memory(): + command = "nvidia-smi --query-gpu=memory.free --format=csv" + memory_free_info = sp.check_output(command.split()).decode('ascii').split('\n')[:-1][1:] + memory_free_values = [int(x.split()[0]) for i, x in enumerate(memory_free_info)] + return memory_free_values + +def parse_input(): + from iotbx.phil import parse + master_phil=""" + context = *kokkos_gpu + .type = choice + .optional = False + .help = backend for parallel execution + """ + phil_scope = parse(master_phil) + # The script usage + import libtbx.load_env # implicit import + from dials.util.options import ArgumentParser + # Create the parser + parser = ArgumentParser( + usage="\n libtbx.python tst_policy", + phil=phil_scope, + epilog="test GPU memory policies large_array vs small_whitelist") + # Parse the command line. quick_parse is required for MPI compatibility + params, options = parser.parse_args(show_diff_phil=True,quick_parse=True) + return params,options + +class several_wavelength_case_policy (several_wavelength_case_unified): + + def modularized_exafel_api_for_GPU(self, params, argchk=False, sources=False, scale=None): + """similar to parent class method, but no background, no diffuse, use self.*""" + gpu_channels_type = get_exascale("gpu_energy_channels",params.context) + gpu_channels_singleton = gpu_channels_type (deviceId = 0) + + self.SIM = nanoBragg(self.DETECTOR, self.BEAM, panel_id=0) + self.SIM.adc_offset_adu=0 + self.SIM.device_Id = 0 + + assert gpu_channels_singleton.get_deviceID()==self.SIM.device_Id # API test + assert gpu_channels_singleton.get_nchannels() == 0 # uninitialized + for x in range(len(self.flux)): + gpu_channels_singleton.structure_factors_to_GPU_direct( + x, self.sfall_channels[x].indices(), self.sfall_channels[x].data()) + assert gpu_channels_singleton.get_nchannels() == len(self.flux) #API test + self.SIM.Ncells_abc = (20,20,20) + self.SIM.Amatrix = sqr(self.CRYSTAL.get_A()).transpose() + self.SIM.oversample = 2 + self.SIM.xtal_shape = shapetype.Gauss + self.SIM.interpolate = 0 + # allocate GPU arrays + self.gpu_simulation = get_exascale("exascale_api",params.context)(nanoBragg = self.SIM) + self.gpu_simulation.allocate() + self.gpu_detector = get_exascale("gpu_detector",params.context)( + deviceId=self.SIM.device_Id, detector=self.DETECTOR, beam=self.BEAM) + self.gpu_detector.each_image_allocate() + # self.gpu_detector.show_summary() + + # two completely independent interfaces to loop over energies + if sources is False: # original exascale API, explicit energy loop in Python + for x in range(len(self.flux)): + self.SIM.wavelength_A = self.wavlen[x] + print("USE_EXASCALE_API+++++++++++++ Wavelength %d=%.6f, Flux %.6e, Fluence %.6e"%( + x, self.SIM.wavelength_A, self.SIM.flux, self.SIM.fluence)) + self.gpu_simulation.add_energy_channel_from_gpu_amplitudes( + x, gpu_channels_singleton, self.gpu_detector, + weight = self.frac[x]) + else: # loop in C++; precludes using sources for divergence; uses sources from nanoBragg table + self.set_pythony_beams(self.SIM) + NN = 0 # compute the number of pixels + for panel in self.DETECTOR: + sz = panel.get_image_size() + NN += sz[0]*sz[1] + + #print("GPU detector summary",self.DETECTOR) + from simtbx.diffBragg.utils import memory_report; print(memory_report()) + print(get_gpu_memory()) + self.gpu_simulation.add_energy_multichannel_mask_allpanel( + ichannels = flex.int(range(len(self.flux))), + gpu_amplitudes = gpu_channels_singleton, + gpu_detector = self.gpu_detector, + pixel_active_list_ints = flex.size_t(range(NN)), + weights = self.frac/len(self.frac) + ) + + per_image_scale_factor = self.domains_per_crystal # 1.0 + self.gpu_detector.scale_in_place(per_image_scale_factor) # apply scale directly on GPU + if sources is False: + self.SIM.wavelength_A = self.BEAM.get_wavelength() # return to canonical energy for subsequent background + else: + self.reset_pythony_beams(self.SIM) + + self.gpu_detector.write_raw_pixels(self.SIM) # updates SIM.raw_pixels from GPU + if self.special == 1: #special test breaks encapsulation + self.special_test_case_1(self.SIM,self.gpu_detector,scale) + # testing no garbage collect gpu_detector.each_image_free() + return + self.data_array = self.gpu_detector.get_raw_pixels() + assert self.data_array.focus()[0] == len(self.DETECTOR) # number of panels + if len(self.DETECTOR) == 1: # if one panel, we can assert data are the same both ways + single_size = self.data_array.focus()[1:3] + self.data_array.reshape(flex.grid((single_size[0],single_size[1]))) + assert np.allclose(self.SIM.raw_pixels, self.data_array) + # deallocate GPU arrays afterward + # testing no garbage collect gpu_detector.each_image_free() + return + + def specialized_api_for_whitelist(self, params, whitelist_pixels, argchk=False, sources=True, scale=None): + gpu_channels_type = get_exascale("gpu_energy_channels",params.context) + gpu_channels_singleton = gpu_channels_type (deviceId = 0) + + self.SIM = nanoBragg(self.DETECTOR, self.BEAM, panel_id=0) + self.SIM.adc_offset_adu=0 + self.SIM.device_Id = 0 + + assert gpu_channels_singleton.get_deviceID()==self.SIM.device_Id # API test + assert gpu_channels_singleton.get_nchannels() == 0 # uninitialized + for x in range(len(self.flux)): + gpu_channels_singleton.structure_factors_to_GPU_direct( + x, self.sfall_channels[x].indices(), self.sfall_channels[x].data()) + assert gpu_channels_singleton.get_nchannels() == len(self.flux) #API test + self.SIM.Ncells_abc = (20,20,20) + self.SIM.Amatrix = sqr(self.CRYSTAL.get_A()).transpose() + self.SIM.oversample = 2 + self.SIM.xtal_shape = shapetype.Gauss + self.SIM.interpolate = 0 + # allocate GPU arrays + self.gpu_simulation = get_exascale("exascale_api",params.context)(nanoBragg = self.SIM) + self.gpu_simulation.allocate() + self.gpu_detector = get_exascale("gpu_detector",params.context)( + deviceId=self.SIM.device_Id, detector=self.DETECTOR, beam=self.BEAM) + self.gpu_detector.each_image_allocate() + # self.gpu_detector.show_summary() + + assert sources + self.set_pythony_beams(self.SIM) + from simtbx.diffBragg.utils import memory_report; print(memory_report()) + print(get_gpu_memory()) + self.gpu_simulation.add_energy_multichannel_mask_allpanel( + ichannels = flex.int(range(len(self.flux))), + gpu_amplitudes = gpu_channels_singleton, + gpu_detector = self.gpu_detector, + pixel_active_list_ints = whitelist_pixels, + weights = self.frac/len(self.frac) + ) + + per_image_scale_factor = self.domains_per_crystal # 1.0 + self.gpu_detector.scale_in_place(per_image_scale_factor) # apply scale directly on GPU + self.reset_pythony_beams(self.SIM) + self.whitelist_values = self.gpu_detector.get_whitelist_raw_pixels(whitelist_pixels) + + def specialized_api_for_whitelist_low_memory(self, params, whitelist_pixels, argchk=False, sources=True, scale=None): + gpu_channels_type = get_exascale("gpu_energy_channels",params.context) + gpu_channels_singleton = gpu_channels_type (deviceId = 0) + + self.SIM = nanoBragg(self.DETECTOR, self.BEAM, panel_id=0) + self.SIM.adc_offset_adu=0 + self.SIM.device_Id = 0 + + assert gpu_channels_singleton.get_deviceID()==self.SIM.device_Id # API test + assert gpu_channels_singleton.get_nchannels() == 0 # uninitialized + for x in range(len(self.flux)): + gpu_channels_singleton.structure_factors_to_GPU_direct( + x, self.sfall_channels[x].indices(), self.sfall_channels[x].data()) + assert gpu_channels_singleton.get_nchannels() == len(self.flux) #API test + self.SIM.Ncells_abc = (20,20,20) + self.SIM.Amatrix = sqr(self.CRYSTAL.get_A()).transpose() + self.SIM.oversample = 2 + self.SIM.xtal_shape = shapetype.Gauss + self.SIM.interpolate = 0 + # allocate GPU arrays + self.gpu_simulation = get_exascale("exascale_api",params.context)(nanoBragg = self.SIM) + self.gpu_simulation.allocate() + self.gpu_detector = get_exascale("gpu_detector",params.context)( + deviceId=self.SIM.device_Id, detector=self.DETECTOR, beam=self.BEAM) + self.gpu_detector.each_image_allocate() + # self.gpu_detector.show_summary() + + assert sources + self.set_pythony_beams(self.SIM) + from simtbx.diffBragg.utils import memory_report; print(memory_report()) + print(get_gpu_memory()) + self.gpu_simulation.add_energy_multichannel_mask_allpanel( + ichannels = flex.int(range(len(self.flux))), + gpu_amplitudes = gpu_channels_singleton, + gpu_detector = self.gpu_detector, + pixel_active_list_ints = whitelist_pixels, + weights = self.frac/len(self.frac) + ) + + per_image_scale_factor = self.domains_per_crystal # 1.0 + self.gpu_detector.scale_in_place(per_image_scale_factor) # apply scale directly on GPU + self.reset_pythony_beams(self.SIM) + self.whitelist_values = self.gpu_detector.get_whitelist_raw_pixels(whitelist_pixels) + +def get_whitelist_from_refls(prefix,SIM): + image_size = len(SIM.raw_pixels) + from dials.array_family import flex + from dxtbx.model.experiment_list import ExperimentListFactory + experiments = ExperimentListFactory.from_json_file("%s_imported.expt"%prefix, check_format = False) + reflections = flex.reflection_table.from_file("%s_strong.refl"%prefix) + assert len(experiments)==1 + assert len(experiments[0].detector)==1 + panel = experiments[0].detector[0] + jslow = panel.get_image_size()[0] + shoebox_pixels = flex.size_t() + for iitem in range(len(reflections)): + item = reflections[iitem] + box = item['bbox'] + for islow in range(box[2], box[3]): + for ifast in range(box[0], box[1]): + idx = islow * jslow + ifast + shoebox_pixels.append(idx) + return shoebox_pixels + +def get_refls_from_dials(data,prefix): + os.system( + "dials.import output.experiments=%s_imported.expt output.log=%s_imported.log %s"%(prefix,prefix,data)) + os.system( + "dials.find_spots output.reflections=%s_strong.refl output.log=%s_strong.log %s"%(prefix,prefix,data)) + +def run_all(params): + # make the dxtbx objects + BEAM = basic_beam() + DETECTOR = basic_detector() + CRYSTAL = basic_crystal() + SF_model = amplitudes(CRYSTAL) + # Famp = SF_model.Famp # simple uniform amplitudes + SF_model.random_structure(CRYSTAL) + SF_model.ersatz_correct_to_P1() + + # determine overall scale factor + print("\n# Use case 1 (%s). Monochromatic source"%params.context) + SWC1 = several_wavelength_case_unified(BEAM, DETECTOR, CRYSTAL, SF_model, weights=flex.double([1.])) + SIM1 = SWC1.modularized_exafel_api_for_GPU(params=params, argchk=False, gpu_background=True) + scale = SIM1.get_intfile_scale() # case 1 is the overall scale factor to write all result files + SIM1.to_cbf("test_policy_%s_001.cbf"%(params.context), intfile_scale=scale) + print("Scale is:",scale) + + # compute and save background pixels + print("\n# Use case 0 (%s). Background only"%params.context) + SWC = several_wavelength_case_unified(BEAM, DETECTOR, CRYSTAL, SF_model, weights=flex.double([0.])) + SIM0 = SWC.modularized_exafel_api_for_GPU(params=params, argchk=False, gpu_background=True) + SIM0.to_cbf("test_policy_%s_000.cbf"%(params.context), intfile_scale=scale) + save_background = SIM0.raw_pixels + print(save_background.focus()) + + # treat the case of multichannel API + print("\n# Use case 2 (%s). Monochromatic source using multichannel API"%params.context) + SIM2=SWC1.modularized_exafel_api_for_GPU(params=params,argchk=False,gpu_background=False,sources=True) + # combine Bragg + background + SIM2.raw_pixels = SWC1.data_array + save_background + SIM2.to_cbf("test_policy_%s_002.cbf"%(params.context), intfile_scale=scale) + # Bragg spot intensity should scale exactly with weight, using multichannel API + assert np.allclose(SIM1.raw_pixels, SIM2.raw_pixels) # equate monochromatic, comparing two interfaces + + # Now try to reproduce whole-image sims with persistent and accumulating memory + NTRIALS = 5 + SWCs=[] + for x in range(NTRIALS): + print("All-pixel iteration",x) + SWCs.append(several_wavelength_case_policy(BEAM,DETECTOR,CRYSTAL,SF_model,weights=flex.double([1.]))) + SWCs[-1].modularized_exafel_api_for_GPU(params=params,argchk=False,sources=True) + SWCs[-1].SIM.raw_pixels = SWCs[-1].data_array + save_background + SWCs[-1].SIM.to_cbf("test_policy_trials_%03d.cbf"%(x), intfile_scale=scale) + # Bragg spot intensity should scale exactly with weight, using multichannel API + assert np.allclose(SWCs[-1].SIM.raw_pixels, SIM2.raw_pixels) + + free_gpu_before = get_gpu_memory()[0] + del SWCs + free_gpu_after = get_gpu_memory()[0] + print((free_gpu_after - free_gpu_before)/NTRIALS,"free") + assert (free_gpu_after - free_gpu_before)/NTRIALS >= 72 # old policy uses at least 72 MB per sim., actual value 76.8 MB + + get_refls_from_dials(data="test_policy_%s_002.cbf"%(params.context), + prefix="test_policy_%s"%(params.context)) + whitelist_pixels = get_whitelist_from_refls(SIM=SIM2, + prefix="test_policy_%s"%(params.context)) + print(whitelist_pixels.focus()) + + # simulate the bright spots only with the whitelist mechanism + print("\n# Use case 3 (%s). Whitelist mechanism, old style with large arrays"%params.context) + SWC3 = several_wavelength_case_policy(BEAM,DETECTOR,CRYSTAL,SF_model,weights=flex.double([1.])) + SWC3.specialized_api_for_whitelist(whitelist_pixels=whitelist_pixels, + params=params,argchk=False,sources=True) + SIM3 = SWC3.SIM + # combine Bragg + background + image_size = len(SIM3.raw_pixels) + working_raw_pixels = flex.double(image_size) # blank array + working_raw_pixels.set_selected(whitelist_pixels, SWC3.whitelist_values) + working_raw_pixels.reshape(flex.grid(SIM3.raw_pixels.focus())) + SIM3.raw_pixels = working_raw_pixels + save_background + SIM3.to_cbf("test_policy_%s_003.cbf"%(params.context), intfile_scale=scale) + + # get some quantitative assertion saying that whitelist is a reasonable image + difference_image = SIM2.raw_pixels - SIM3.raw_pixels + assert flex.sum(difference_image) > 0. + print("difference",flex.sum(difference_image)) + large_diffs = (difference_image > 1.).count(True) + print("number of large pixel differences",large_diffs) + assert (large_diffs < 15000) # actual value 10471 + + # Now reproduce whitelist sims showing accumulation of large persistent memory + SWCs=[] + for x in range(NTRIALS): + print("Whitelist-only iteration",x) + SWCs.append(several_wavelength_case_policy(BEAM,DETECTOR,CRYSTAL,SF_model,weights=flex.double([1.]))) + SWCs[-1].specialized_api_for_whitelist(whitelist_pixels=whitelist_pixels,params=params,argchk=False,sources=True) + + reference_whitelist_values = SWCs[-1].whitelist_values + free_gpu_before = get_gpu_memory()[0] + del SWCs + free_gpu_after = get_gpu_memory()[0] + print((free_gpu_after - free_gpu_before)/NTRIALS,"free") + assert (free_gpu_after - free_gpu_before)/NTRIALS >= 50 # old policy uses at least 50 MB per sim., actual value 57.6 MB + + #figure out the minimum change needed to reduce memory consumption by factor of image_size/whitelist_size + #accomplish the same with compile-time polymorphism + #have side-by-side test in same python script + # Reproduce whitelist sims with small-memory mechanism + SWCs=[] + for x in range(NTRIALS): + print("Whitelist-only iteration with small memory",x) + SWCs.append(several_wavelength_case_policy(BEAM,DETECTOR,CRYSTAL,SF_model,weights=flex.double([1.]))) + SWCs[-1].specialized_api_for_whitelist_low_memory(whitelist_pixels=whitelist_pixels,params=params,argchk=False,sources=True) + #produce an output image file for intermediate debugging + working_raw_pixels = flex.double(image_size) # blank array + working_raw_pixels.set_selected(whitelist_pixels, SWCs[-1].whitelist_values) + working_raw_pixels.reshape(flex.grid(SWCs[-1].SIM.raw_pixels.focus())) + SWCs[-1].SIM.raw_pixels = working_raw_pixels + save_background + SWCs[-1].SIM.to_cbf("test_policy_%s_004.cbf"%(params.context), intfile_scale=scale) + + #assert that the two methods give the same answer (whitelist with large memory vs. whitelist with small memory) + assert np.allclose(reference_whitelist_values, SWCs[-1].whitelist_values) + + free_gpu_before = get_gpu_memory()[0] + del SWCs + free_gpu_after = get_gpu_memory()[0] + print((free_gpu_after - free_gpu_before)/NTRIALS,"free") + assert (free_gpu_after - free_gpu_before)/NTRIALS >= 50 # old policy uses at least 50 MB per sim., actual value 57.6 MB + + return + +if __name__=="__main__": + params,options = parse_input() + # Initialize based on GPU context + gpu_instance_type = get_exascale("gpu_instance", params.context) + gpu_instance = gpu_instance_type(deviceId = 0) + + run_all(params) +print("OK") diff --git a/simtbx/tests/tst_unified.py b/simtbx/tests/tst_unified.py index 7cf234a6ac..4a91c68e2e 100644 --- a/simtbx/tests/tst_unified.py +++ b/simtbx/tests/tst_unified.py @@ -97,7 +97,7 @@ def reset_pythony_beams(self,SIM): # for mono-wavelength addition of background 'polarization_normal': (0.0, 1.0, 0.0), 'sigma_divergence': 0.0, 'transmission': 1.0, - 'wavelength': BEAM.get_wavelength()/1.e10} # not sure why this has to be in meters + 'wavelength': basic_beam().get_wavelength()/1.e10} # not sure why this has to be in meters pythony_beams.append(BeamFactory.from_dict(beam_descr)) SIM.xray_beams = pythony_beams From dfe16a9fda0d3205a4b74ec4223769bcea4885bc Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Tue, 26 Mar 2024 13:09:20 -0700 Subject: [PATCH 273/748] gltbx: switch OpenGL imports to pyopengl --- gltbx/gl.py | 9 ++++++--- gltbx/glu.py | 8 +++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/gltbx/gl.py b/gltbx/gl.py index 7b08cb2566..e21cdd52f7 100644 --- a/gltbx/gl.py +++ b/gltbx/gl.py @@ -1,7 +1,10 @@ from __future__ import absolute_import, division, print_function -import boost_adaptbx.boost.python as bp -ext = bp.import_ext("gltbx_gl_ext") -from gltbx_gl_ext import * +# import boost_adaptbx.boost.python as bp +# ext = bp.import_ext("gltbx_gl_ext") +# from gltbx_gl_ext import * +import OpenGL # implicit import +from OpenGL.GLU import * +from OpenGL.GL import * def __function_taking_transposed_matrix(f): def wrapper(m): diff --git a/gltbx/glu.py b/gltbx/glu.py index a053956bb7..4676b1746d 100644 --- a/gltbx/glu.py +++ b/gltbx/glu.py @@ -1,4 +1,6 @@ from __future__ import absolute_import, division, print_function -import boost_adaptbx.boost.python as bp -ext = bp.import_ext("gltbx_glu_ext") -from gltbx_glu_ext import * +# import boost_adaptbx.boost.python as bp +# ext = bp.import_ext("gltbx_glu_ext") +# from gltbx_glu_ext import * +import OpenGL # implicit import +from OpenGL.GLU import * From 433c7655515bfb902c3844028701f5a378e86840 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Tue, 26 Mar 2024 13:09:58 -0700 Subject: [PATCH 274/748] gltbx: remove keywords from argument lists in gl_managed.py --- gltbx/gl_managed.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gltbx/gl_managed.py b/gltbx/gl_managed.py index 7187c6681b..40ceb4824d 100644 --- a/gltbx/gl_managed.py +++ b/gltbx/gl_managed.py @@ -6,10 +6,10 @@ class display_lists_owner: def __init__(self, range_values): self.range_values = range_values - self.list = gl.glGenLists(range_values=range_values) + self.list = gl.glGenLists(range_values) def __del__(self): - try: gl.glDeleteLists(list=self.list, range_values=self.range_values) + try: gl.glDeleteLists(self.list, self.range_values) except RuntimeError as e: if (str(e) != 'OpenGL: invalid operation'): raise # else: apparently the GL context was destroyed already @@ -31,13 +31,13 @@ def compile(self, execute=False): mode = gl.GL_COMPILE_AND_EXECUTE else: mode = gl.GL_COMPILE - gl.glNewList(list=self.gl_index, mode=mode) + gl.glNewList(self.gl_index, mode) def end(self): gl.glEndList() def call(self): - gl.glCallList(list=self.gl_index) + gl.glCallList(self.gl_index) class display_lists: From b9d25de331cd3d33bc8a814c37ba1c202ec3ef98 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Thu, 28 Mar 2024 10:19:37 -0700 Subject: [PATCH 275/748] gltbx: preserve previous behavior if pyopengl is not available --- gltbx/gl.py | 13 +++++++------ gltbx/glu.py | 12 +++++++----- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/gltbx/gl.py b/gltbx/gl.py index e21cdd52f7..fae1e6b942 100644 --- a/gltbx/gl.py +++ b/gltbx/gl.py @@ -1,10 +1,11 @@ from __future__ import absolute_import, division, print_function -# import boost_adaptbx.boost.python as bp -# ext = bp.import_ext("gltbx_gl_ext") -# from gltbx_gl_ext import * -import OpenGL # implicit import -from OpenGL.GLU import * -from OpenGL.GL import * +try: + import OpenGL # implicit import + from OpenGL.GL import * +except ImportError: + import boost_adaptbx.boost.python as bp + ext = bp.import_ext("gltbx_gl_ext") + from gltbx_gl_ext import * def __function_taking_transposed_matrix(f): def wrapper(m): diff --git a/gltbx/glu.py b/gltbx/glu.py index 4676b1746d..85e21ab951 100644 --- a/gltbx/glu.py +++ b/gltbx/glu.py @@ -1,6 +1,8 @@ from __future__ import absolute_import, division, print_function -# import boost_adaptbx.boost.python as bp -# ext = bp.import_ext("gltbx_glu_ext") -# from gltbx_glu_ext import * -import OpenGL # implicit import -from OpenGL.GLU import * +try: + import OpenGL # implicit import + from OpenGL.GLU import * +except ImportError: + import boost_adaptbx.boost.python as bp + ext = bp.import_ext("gltbx_glu_ext") + from gltbx_glu_ext import * From 0c22b22b78777843f7928525acb2be2840a4d7ad Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Mon, 1 Apr 2024 03:45:28 -0700 Subject: [PATCH 276/748] Update CHANGELOG.rst for 2024.3 release [skip ci] --- CHANGELOG.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 213469e3d0..57b7734a4e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,12 @@ +2024.3 +====== + +* Fixed loggraph output in xtriage +* Added initial clashscore2 that uses reduce2 and probe2 +* Clean up MolProbity and clashscore code +* Clean up Polder maps code +* Added option to use pyopengl in gltbx if available + 2024.2 ====== From 1a6aafc26c407ae669cf4554f6fdfc520f44aaaf Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Mon, 1 Apr 2024 17:58:32 -0700 Subject: [PATCH 277/748] Add a way to save SK coordinates (useful if runing on many files which takes forever) and wantto re-run again quickly --- mmtbx/programs/hbond.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/mmtbx/programs/hbond.py b/mmtbx/programs/hbond.py index 5e70c2ea8c..756968f2a9 100644 --- a/mmtbx/programs/hbond.py +++ b/mmtbx/programs/hbond.py @@ -67,13 +67,21 @@ def validate(self): self.data_manager.has_models(raise_sorry=True) # --------------------------------------------------------------------------- +<<<<<<< HEAD def run(self): self._print('Using model: %s' % self.data_manager.get_default_model_name()) +======= + def run(self, save_sk_coordinates=False): + print('Using model: %s' % self.data_manager.get_default_model_name(), + file=self.logger) +>>>>>>> Add a way to save SK coordinates (useful if runing on many files which takes forever) and wantto re-run again quickly inp_models = [] for model_name in self.data_manager.get_model_names(): inp_models.append((model_name, self.data_manager.get_model(model_name))) theta1_data = [] Rha_data = [] + if save_sk_coordinates: + file_names = [] for m_name, model in inp_models: model.set_log(log = null_out()) if self.params.hbond.add_hydrogens_if_absent and not model.has_hd(): @@ -108,6 +116,8 @@ def run(self): if stats.all.get_counts(min_data_size=min_data_size): theta1_data.append(stats.all.get_counts(min_data_size=min_data_size).theta_1) Rha_data.append( stats.all.get_counts(min_data_size=min_data_size).d_HA) + if save_sk_coordinates: + file_names.append(m_name) if self.params.output_skew_kurtosis_plot and len(theta1_data) > 0 and len(Rha_data) > 0: # To use other than 'all' type, nci.hbond.find needs to be called with selected model again, @@ -117,12 +127,24 @@ def run(self): fn += "_cbf" theta1_c = [(x.skew, x.kurtosis) for x in theta1_data] Rha_c = [(x.skew, x.kurtosis) for x in Rha_data] +<<<<<<< HEAD op = {} for param_name in dir(self.params.plot_parameters_override): if not param_name.startswith('__'): param_value = getattr(self.params.plot_parameters_override, param_name) if param_value != None: op[param_name] = param_value +======= + + if save_sk_coordinates: + from libtbx import group_args + from libtbx import easy_pickle + o = group_args( + file_names = file_names, + theta1_coords = theta1_c, + Rha_coords = Rha_c) + easy_pickle.dump(file_name="coords.pkl", obj = o) +>>>>>>> Add a way to save SK coordinates (useful if runing on many files which takes forever) and wantto re-run again quickly mmtbx.nci.skew_kurt_plot.make_figure( file_name=fn, From 8c7a2230ec7350488715057780a659590c5dc299 Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Mon, 1 Apr 2024 18:02:05 -0700 Subject: [PATCH 278/748] Clean up mess (not sure what happened) --- mmtbx/programs/hbond.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/mmtbx/programs/hbond.py b/mmtbx/programs/hbond.py index 756968f2a9..97053367c2 100644 --- a/mmtbx/programs/hbond.py +++ b/mmtbx/programs/hbond.py @@ -67,14 +67,9 @@ def validate(self): self.data_manager.has_models(raise_sorry=True) # --------------------------------------------------------------------------- -<<<<<<< HEAD - def run(self): - self._print('Using model: %s' % self.data_manager.get_default_model_name()) -======= def run(self, save_sk_coordinates=False): print('Using model: %s' % self.data_manager.get_default_model_name(), file=self.logger) ->>>>>>> Add a way to save SK coordinates (useful if runing on many files which takes forever) and wantto re-run again quickly inp_models = [] for model_name in self.data_manager.get_model_names(): inp_models.append((model_name, self.data_manager.get_model(model_name))) @@ -127,14 +122,13 @@ def run(self, save_sk_coordinates=False): fn += "_cbf" theta1_c = [(x.skew, x.kurtosis) for x in theta1_data] Rha_c = [(x.skew, x.kurtosis) for x in Rha_data] -<<<<<<< HEAD + op = {} for param_name in dir(self.params.plot_parameters_override): if not param_name.startswith('__'): param_value = getattr(self.params.plot_parameters_override, param_name) if param_value != None: op[param_name] = param_value -======= if save_sk_coordinates: from libtbx import group_args @@ -144,7 +138,6 @@ def run(self, save_sk_coordinates=False): theta1_coords = theta1_c, Rha_coords = Rha_c) easy_pickle.dump(file_name="coords.pkl", obj = o) ->>>>>>> Add a way to save SK coordinates (useful if runing on many files which takes forever) and wantto re-run again quickly mmtbx.nci.skew_kurt_plot.make_figure( file_name=fn, From a66c5849a3a816e988689a02b5f8fa348755ed69 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 2 Apr 2024 08:23:12 -0700 Subject: [PATCH 279/748] Check for long chain ids --- mmtbx/command_line/secondary_structure_restraints.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mmtbx/command_line/secondary_structure_restraints.py b/mmtbx/command_line/secondary_structure_restraints.py index b29c324528..eb73b1b15d 100644 --- a/mmtbx/command_line/secondary_structure_restraints.py +++ b/mmtbx/command_line/secondary_structure_restraints.py @@ -186,7 +186,10 @@ def run(args, params=None, out=sys.stdout, log=sys.stderr): if (prefix_scope != ""): print("}", file=result_out) elif work_params.format == "pdb": - print(m.actual_sec_str.as_pdb_str(), file=result_out) + if m.actual_sec_str.fits_in_pdb_format(): + print(m.actual_sec_str.as_pdb_str(), file=result_out) + else: + raise Sorry("Annotations could not fit in PDB format.") elif work_params.format == "phenix_bonds" : raise Sorry("Not yet implemented.") elif work_params.format in ["pymol", "refmac", "kinemage", 'csv'] : From 480c9bc05227c4f9152595bcb1647becddf788e3 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 2 Apr 2024 09:53:47 -0700 Subject: [PATCH 280/748] Refactor out some instances of as_pdb_input() --- cctbx/regression/tst_loc_res.py | 3 ++- mmtbx/regression/tst_validation_summary.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cctbx/regression/tst_loc_res.py b/cctbx/regression/tst_loc_res.py index 27bbfa4c2d..0bad513706 100644 --- a/cctbx/regression/tst_loc_res.py +++ b/cctbx/regression/tst_loc_res.py @@ -396,7 +396,8 @@ def make_map_from_pdb(raw_records=None,set_b_iso=None): ph.adopt_xray_structure(xrs) import mmtbx.model model=mmtbx.model.manager( - model_input = ph.as_pdb_input(), + model_input=None, + pdb_hierarchy = ph, crystal_symmetry = crystal_symmetry) return model,map_data,crystal_symmetry diff --git a/mmtbx/regression/tst_validation_summary.py b/mmtbx/regression/tst_validation_summary.py index a0334736a9..b8a691bc18 100644 --- a/mmtbx/regression/tst_validation_summary.py +++ b/mmtbx/regression/tst_validation_summary.py @@ -38,7 +38,8 @@ def exercise(): new_hierarchy.append_model(model) import mmtbx.model model_object = mmtbx.model.manager( - model_input = new_hierarchy.as_pdb_input(), + model_input=None, + pdb_hierarchy = new_hierarchy, crystal_symmetry = pdb_in.crystal_symmetry()) open("tst_validation_summary.pdb", "w").write(model_object.model_as_pdb()) out2 = StringIO() From 043e31685995ce787be7299b7889906f7c0d7d20 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 2 Apr 2024 17:10:33 -0700 Subject: [PATCH 281/748] new electron testing --- mmtbx/ligands/electrons.py | 5 +- mmtbx/ligands/tst_electron_scripting.py | 103 ++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 mmtbx/ligands/tst_electron_scripting.py diff --git a/mmtbx/ligands/electrons.py b/mmtbx/ligands/electrons.py index ac53851ffd..e4d435a007 100644 --- a/mmtbx/ligands/electrons.py +++ b/mmtbx/ligands/electrons.py @@ -851,7 +851,9 @@ def _comp_disallowed(actual, disallowed): rc.setdefault(outl, []) rc[outl].append([atoms[key].quote(), key]) + terminals = {} for atom, charge in charged_atoms: + if atom.name in [' OXT']: terminals[ag.id_str()]=charge ag = atom.parent() if get_class(ag.resname) in ['common_amino_acid']: base = base_amino_acid_charges.get(ag.resname, 0) @@ -874,9 +876,10 @@ def _comp_disallowed(actual, disallowed): for ag in self.hierarchy.atom_groups(): delta = 1 if ag.resname in ['HIS']: delta=2 + terminal_adjust = ag.id_str() in terminals charge = charged_residues.get(ag.id_str(), 0) outl = 'Unlikely charge for %s of %s' % (ag.resname, charge) - if abs(charge-base_amino_acid_charges.get(ag.resname, 0)) > delta: + if abs(charge-base_amino_acid_charges.get(ag.resname, 0)-int(terminal_adjust)) > delta: if raise_if_error: raise Sorry(outl) rc.setdefault(outl, []) rc[outl].append('"%s"' % ag.id_str()) diff --git a/mmtbx/ligands/tst_electron_scripting.py b/mmtbx/ligands/tst_electron_scripting.py new file mode 100644 index 0000000000..70b39f4db1 --- /dev/null +++ b/mmtbx/ligands/tst_electron_scripting.py @@ -0,0 +1,103 @@ +from __future__ import absolute_import, division, print_function + +from iotbx.cli_parser import run_program +from mmtbx.ligands import electrons + +pdb_1x24_modified = ''' +CRYST1 146.891 146.891 146.891 90.00 90.00 90.00 I 21 3 +ATOM 1 N PRO A 9 39.761-121.668 105.645 1.00 65.50 N +ATOM 2 CA PRO A 9 38.280-121.485 105.595 1.00 65.50 C +ATOM 3 C PRO A 9 37.853-120.009 105.641 1.00 65.50 C +ATOM 4 O PRO A 9 37.565-119.454 106.709 1.00 65.50 O +ATOM 5 CB PRO A 9 37.692-122.267 106.767 1.00 82.07 C +ATOM 6 CG PRO A 9 38.901-122.331 107.732 1.00 82.07 C +ATOM 7 CD PRO A 9 40.132-122.487 106.816 1.00 82.07 C +ATOM 8 N VAL A 10 37.821-119.386 104.464 1.00 67.31 N +ATOM 9 CA VAL A 10 37.429-117.984 104.324 1.00 67.31 C +ATOM 10 C VAL A 10 35.942-117.869 103.987 1.00 67.31 C +ATOM 11 O VAL A 10 35.428-118.537 103.086 1.00 67.31 O +ATOM 12 CB VAL A 10 38.256-117.261 103.215 1.00 55.89 C +ATOM 13 CG1 VAL A 10 39.729-117.340 103.529 1.00 55.89 C +ATOM 14 CG2 VAL A 10 37.996-117.887 101.864 1.00 55.89 C +ATOM 15 N GLU A 11 35.257-117.017 104.732 1.00 38.26 N +ATOM 16 CA GLU A 11 33.832-116.787 104.541 1.00 38.26 C +ATOM 17 C GLU A 11 33.661-115.357 104.025 1.00 38.26 C +ATOM 18 O GLU A 11 34.303-114.430 104.515 1.00 38.26 O +ATOM 19 CB GLU A 11 33.113-116.993 105.880 1.00 47.28 C +ATOM 20 CG GLU A 11 31.647-116.714 105.867 1.00 47.28 C +ATOM 21 CD GLU A 11 30.927-117.240 107.101 1.00 47.28 C +ATOM 22 OE1 GLU A 11 31.427-117.062 108.233 1.00 47.28 O +ATOM 23 OE2 GLU A 11 29.834-117.825 106.935 1.00 47.28 O +''' + +pdb_1x24_modified_complete = ''' +CRYST1 146.891 146.891 146.891 90.00 90.00 90.00 I 21 3 +ATOM 1 N PRO A 9 39.761 25.223 105.645 1.00 65.50 N +ATOM 2 CA PRO A 9 38.280 25.406 105.595 1.00 65.50 C +ATOM 3 C PRO A 9 37.853 26.882 105.641 1.00 65.50 C +ATOM 4 O PRO A 9 37.565 27.437 106.709 1.00 65.50 O +ATOM 5 CB PRO A 9 37.692 24.624 106.767 1.00 82.07 C +ATOM 6 CG PRO A 9 38.901 24.560 107.732 1.00 82.07 C +ATOM 7 CD PRO A 9 40.132 24.404 106.816 1.00 82.07 C +ATOM 8 H2 PRO A 9 40.220 26.153 105.717 0.00 65.50 H +ATOM 9 H3 PRO A 9 40.078 24.746 104.777 0.00 65.50 H +ATOM 10 HA PRO A 9 37.908 24.935 104.685 0.00 65.50 H +ATOM 11 HB2 PRO A 9 36.851 25.160 107.207 0.00 82.07 H +ATOM 12 HB3 PRO A 9 37.375 23.631 106.449 0.00 82.07 H +ATOM 13 HG2 PRO A 9 38.962 25.480 108.314 0.00 82.07 H +ATOM 14 HG3 PRO A 9 38.800 23.704 108.399 0.00 82.07 H +ATOM 15 HD2 PRO A 9 41.030 24.792 107.297 0.00 82.07 H +ATOM 16 HD3 PRO A 9 40.281 23.362 106.534 0.00 82.07 H +ATOM 17 N VAL A 10 37.821 27.505 104.464 1.00 67.31 N +ATOM 18 CA VAL A 10 37.429 28.907 104.324 1.00 67.31 C +ATOM 19 C VAL A 10 35.942 29.022 103.987 1.00 67.31 C +ATOM 20 O VAL A 10 35.428 28.354 103.086 1.00 67.31 O +ATOM 21 CB VAL A 10 38.256 29.630 103.215 1.00 55.89 C +ATOM 22 CG1 VAL A 10 39.729 29.551 103.529 1.00 55.89 C +ATOM 23 CG2 VAL A 10 37.996 29.004 101.864 1.00 55.89 C +ATOM 24 H VAL A 10 38.064 27.061 103.578 0.00 67.31 H +ATOM 25 HA VAL A 10 37.621 29.395 105.280 0.00 67.31 H +ATOM 26 HB VAL A 10 37.952 30.676 103.182 0.00 55.89 H +ATOM 27 HG11 VAL A 10 40.287 30.061 102.744 0.00 55.89 H +ATOM 28 HG12 VAL A 10 39.913 30.033 104.489 0.00 55.89 H +ATOM 29 HG13 VAL A 10 40.026 28.503 103.575 0.00 55.89 H +ATOM 30 HG21 VAL A 10 38.585 29.528 101.111 0.00 55.89 H +ATOM 31 HG22 VAL A 10 38.286 27.954 101.898 0.00 55.89 H +ATOM 32 HG23 VAL A 10 36.934 29.089 101.632 0.00 55.89 H +ATOM 33 N GLU A 11 35.257 29.874 104.732 1.00 38.26 N +ATOM 34 CA GLU A 11 33.832 30.104 104.541 1.00 38.26 C +ATOM 35 C GLU A 11 33.661 31.534 104.025 1.00 38.26 C +ATOM 36 O GLU A 11 34.303 32.461 104.515 1.00 38.26 O +ATOM 37 CB GLU A 11 33.113 29.898 105.880 1.00 47.28 C +ATOM 38 CG GLU A 11 31.647 30.177 105.867 1.00 47.28 C +ATOM 39 CD GLU A 11 30.927 29.651 107.101 1.00 47.28 C +ATOM 40 OE1 GLU A 11 31.427 29.829 108.233 1.00 47.28 O +ATOM 41 OE2 GLU A 11 29.834 29.066 106.935 1.00 47.28 O +ATOM 42 OXT GLU A 11 32.873 31.768 103.108 1.00 38.26 O +ATOM 43 H GLU A 11 35.663 30.428 105.486 0.00 38.26 H +ATOM 44 HA GLU A 11 33.384 29.414 103.826 0.00 38.26 H +ATOM 45 HB2 GLU A 11 33.244 28.859 106.184 0.00 47.28 H +ATOM 46 HB3 GLU A 11 33.564 30.562 106.618 0.00 47.28 H +ATOM 47 HG2 GLU A 11 31.493 31.255 105.823 0.00 47.28 H +ATOM 48 HG3 GLU A 11 31.204 29.701 104.992 0.00 47.28 H +''' + +def main(): + f=open('pdb_1x24_modified.pdb', 'w') + f.write(pdb_1x24_modified) + del f + rc = run_program(electrons.Program, args=['pdb_1x24_modified.pdb']) + print('-'*80) + print(rc.keys()) + print(rc) + + f=open('pdb_1x24_modified_complete.pdb', 'w') + f.write(pdb_1x24_modified_complete) + del f + rc = run_program(electrons.Program, args=['pdb_1x24_modified_complete.pdb']) + print('-'*80) + print(rc.keys()) + print(rc) + +if __name__ == '__main__': + main() From cc8c9e28c3f52dfbfecbebcbd53d21f8c71ab3b6 Mon Sep 17 00:00:00 2001 From: "Aaron S. Brewster" Date: Wed, 3 Apr 2024 09:29:13 -0700 Subject: [PATCH 282/748] Simtbx: run test with cuda and dials only --- simtbx/run_tests.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/simtbx/run_tests.py b/simtbx/run_tests.py index 3d54eec102..4af9af765a 100644 --- a/simtbx/run_tests.py +++ b/simtbx/run_tests.py @@ -94,6 +94,9 @@ ["$D/gpu/tst_exafel_api.py","context=kokkos_gpu"],# GPU in kokkos ["$D/tests/tst_unified.py","context=kokkos_gpu"],# GPU, exaFEL full API ["$D/gpu/tst_shoeboxes.py","context=kokkos_gpu"],# GPU, test whitelist API + ] +if OPT.enable_kokkos and sys.platform.startswith('linux') and OPT.enable_cuda and libtbx.env.has_module('dials'): + tst_list_parallel += [ ["$D/tests/tst_memory_policy.py","context=kokkos_gpu"], ] if OPT.enable_kokkos: From 83cbc3c6e4a6a0de29243c8e3dc1b5f8ce2709fb Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Wed, 3 Apr 2024 09:47:10 -0700 Subject: [PATCH 283/748] Fix indentation [skip ci] --- simtbx/run_tests.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/simtbx/run_tests.py b/simtbx/run_tests.py index 4af9af765a..2a677dc246 100644 --- a/simtbx/run_tests.py +++ b/simtbx/run_tests.py @@ -74,7 +74,7 @@ tst_list = nb_tst_list if OPT.enable_cxx11 and sys.platform != 'win32': - tst_list += db_tst_list+db_tst_list_nonCuda + tst_list += db_tst_list+db_tst_list_nonCuda if OPT.enable_cuda: tst_list_parallel += [ @@ -89,26 +89,26 @@ ["$D/nanoBragg/tst_gauss_argchk.py","CPU"], # tests CPU argchk optimization ) if OPT.enable_kokkos and sys.platform.startswith('linux'): - tst_list_parallel += [ - ["$D/gpu/tst_gpu_multisource_background.py","context=kokkos_gpu"],# CPU / GPU background comparison - ["$D/gpu/tst_exafel_api.py","context=kokkos_gpu"],# GPU in kokkos - ["$D/tests/tst_unified.py","context=kokkos_gpu"],# GPU, exaFEL full API - ["$D/gpu/tst_shoeboxes.py","context=kokkos_gpu"],# GPU, test whitelist API - ] + tst_list_parallel += [ + ["$D/gpu/tst_gpu_multisource_background.py","context=kokkos_gpu"],# CPU / GPU background comparison + ["$D/gpu/tst_exafel_api.py","context=kokkos_gpu"],# GPU in kokkos + ["$D/tests/tst_unified.py","context=kokkos_gpu"],# GPU, exaFEL full API + ["$D/gpu/tst_shoeboxes.py","context=kokkos_gpu"],# GPU, test whitelist API + ] if OPT.enable_kokkos and sys.platform.startswith('linux') and OPT.enable_cuda and libtbx.env.has_module('dials'): - tst_list_parallel += [ - ["$D/tests/tst_memory_policy.py","context=kokkos_gpu"], - ] + tst_list_parallel += [ + ["$D/tests/tst_memory_policy.py","context=kokkos_gpu"], + ] if OPT.enable_kokkos: if OPT.enable_cxx11 and sys.platform != 'win32': - for tst in db_tst_list: - if isinstance(tst, str): - par_tst = [tst, "--kokkos"] - else: - par_tst = tst + ["--kokkos"] - tst_list_parallel.append(par_tst) + for tst in db_tst_list: + if isinstance(tst, str): + par_tst = [tst, "--kokkos"] + else: + par_tst = tst + ["--kokkos"] + tst_list_parallel.append(par_tst) - tst_list_parallel += db_tst_list_onlyCuda + tst_list_parallel += db_tst_list_onlyCuda def run(): build_dir = libtbx.env.under_build("simtbx") From 04aa95648e282b74a93044915c6dd8934424cd65 Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 3 Apr 2024 12:07:53 -0600 Subject: [PATCH 284/748] Add holton_geometry_validation tools --- cctbx/geometry_restraints/__init__.py | 164 +++- .../holton_geometry_validation.py | 12 + mmtbx/programs/holton_geometry_validation.py | 70 ++ .../tst_holton_geometry_validation.py | 219 +++++ .../validation/holton_geometry_validation.py | 765 ++++++++++++++++++ 5 files changed, 1211 insertions(+), 19 deletions(-) create mode 100644 mmtbx/command_line/holton_geometry_validation.py create mode 100644 mmtbx/programs/holton_geometry_validation.py create mode 100644 mmtbx/regression/tst_holton_geometry_validation.py create mode 100644 mmtbx/validation/holton_geometry_validation.py diff --git a/cctbx/geometry_restraints/__init__.py b/cctbx/geometry_restraints/__init__.py index f0b882fab5..808dde52f2 100644 --- a/cctbx/geometry_restraints/__init__.py +++ b/cctbx/geometry_restraints/__init__.py @@ -5,6 +5,7 @@ import cctbx.geometry # import dependency from libtbx.test_utils import approx_equal from libtbx.str_utils import show_string +from libtbx import group_args import boost_adaptbx.boost.python as bp from six.moves import range @@ -444,7 +445,15 @@ def _bond_show_sorted_impl(self, f=None, prefix="", max_items=None, - origin_id=None): + origin_id=None, + return_result = False): + if return_result: + result = group_args(group_args_type = 'Bond restraints', + by_value = by_value, + max_items = max_items, + value_list = [], + ) + if unit_cell is None: sorted_table, n_not_shown = self.get_sorted( by_value=by_value, @@ -489,9 +498,25 @@ def _bond_show_sorted_impl(self, if (rt_mx is not None): print(" " + str(rt_mx), end='', file=f) print(file=f) + if return_result: + value = group_args( + group_args_type = + 'Bond distance: ', + labels = labels, + delta = delta, + sigma = sigma, + residual = residual, + ideal = distance_ideal, + model = distance_model,) + result.value_list.append(value) + + if (n_not_shown != 0): print(prefix + "... (remaining %d not shown)" % n_not_shown, file=f) + if return_result: + return result + @bp.inject_into(shared_bond_asu_proxy) class _(): @@ -640,17 +665,19 @@ def show_sorted(self, f=None, prefix="", max_items=None, - origin_id=None): + origin_id=None, + return_result = False): if f is None: f = sys.stdout # print >> f, "%sBond restraints: %d" % (prefix, self.size()) - _bond_show_sorted_impl(self, by_value, + return _bond_show_sorted_impl(self, by_value, sites_cart=sites_cart, site_labels=site_labels, unit_cell=unit_cell, f=f, prefix=prefix, max_items=max_items, - origin_id=origin_id) + origin_id=origin_id, + return_result = return_result) def deltas(self, sites_cart, unit_cell=None): if unit_cell is None: @@ -912,7 +939,8 @@ def show_sorted(self, f=None, prefix="", max_items=None, - origin_id=None): + origin_id=None, + return_result = False,): if f is None: f = sys.stdout # print >> f, "%sBond restraints: %d" % (prefix, self.n_total()) return _bond_show_sorted_impl(self, by_value, @@ -921,7 +949,8 @@ def show_sorted(self, f=f, prefix=prefix, max_items=max_items, - origin_id=origin_id) + origin_id=origin_id, + return_result = return_result) @bp.inject_into(nonbonded_sorted_asu_proxies) class _(): @@ -1092,7 +1121,16 @@ def show_sorted(self, prefix="", max_items=None, suppress_model_minus_vdw_greater_than=0.2, - but_show_all_model_up_to=3.5): + but_show_all_model_up_to=3.5, + return_result = False): + + if return_result: + result = group_args(group_args_type = 'Non-bonded restraints', + by_value = by_value, + max_items = max_items, + value_list = [], + ) + assert by_value in ["delta"] sorted_table, n_not_shown = self.get_sorted( by_value=by_value, @@ -1124,9 +1162,25 @@ def suppress(): if (rt_mx is not None): print(" " + str(rt_mx), end='', file=f) print(file=f) + if return_result: + value = group_args( + group_args_type = + 'Non-bonded distance: ideal is vdw_distance, '+ + 'model is delta (actual)', + labels = labels, + delta = None, + sigma = None, + residual = None, + ideal = vdw_distance, + model = delta,) + result.value_list.append(value) + if (n_not_shown != 0): print(prefix + "... (remaining %d not shown)" % n_not_shown, file=f) + if return_result: + return result + @bp.inject_into(angle) class _(): @@ -1225,14 +1279,16 @@ def show_sorted(self, f=None, prefix="", max_items=None, - origin_id=None): - _show_sorted_impl(O=self, + origin_id=None, + return_result = False): + return _show_sorted_impl(O=self, proxy_type=angle, proxy_label=proxy_label, item_label="angle", by_value=by_value, unit_cell=unit_cell, sites_cart=sites_cart, site_labels=site_labels, f=f, prefix=prefix, max_items=max_items, - origin_id=origin_id) + origin_id=origin_id, + return_result = return_result) def get_sorted(self, by_value, @@ -1316,15 +1372,16 @@ def show_sorted(self, f=None, prefix="", max_items=None, - origin_id=None): - - _show_sorted_impl(O=self, + origin_id=None, + return_result = False): + return _show_sorted_impl(O=self, proxy_type=dihedral, proxy_label=proxy_label, item_label="dihedral", by_value=by_value, unit_cell=unit_cell, sites_cart=sites_cart, site_labels=site_labels, f=f, prefix=prefix, max_items=max_items, - origin_id=origin_id) + origin_id=origin_id, + return_result = return_result) def get_sorted(self, by_value, @@ -1401,14 +1458,18 @@ def show_sorted(self, f=None, prefix="", max_items=None, - origin_id=None): - _show_sorted_impl(O=self, + origin_id=None, + return_result = False, + ): + + return _show_sorted_impl(O=self, proxy_type=chirality, proxy_label=proxy_label, item_label="chirality", by_value=by_value, unit_cell=unit_cell, sites_cart=sites_cart, site_labels=site_labels, f=f, prefix=prefix, max_items=max_items, - origin_id=origin_id) + origin_id=origin_id, + return_result = return_result) def get_sorted(self, by_value, @@ -1514,7 +1575,18 @@ def show_sorted(O, f=None, prefix="", max_items=None, - origin_id=None): + origin_id=None, + return_result = False, + ): + if return_result: + result = group_args(group_args_type = 'Planarity restraints', + by_value = by_value, + max_items = max_items, + value_list = [], + ) + + + assert by_value in ["residual", "rms_deltas"] assert site_labels is None or len(site_labels) == sites_cart.size() if (f is None): f = sys.stdout @@ -1578,6 +1650,20 @@ def show_sorted(O, rdr = "" rdr_spacer = " "*20 s = "" + if return_result: + sigma = weight_as_sigma(weight=weight) + value = group_args( + group_args_type = + 'Planarity restraint (energy for one atom, all atoms: %s)' %( + str(ls)), + labels = [l], + delta = delta, + sigma = sigma, + residual = (delta/max(1.e-10,sigma))**2, + ideal = None, + model = None,) + result.value_list.append(value) + n_not_shown = O.size() - i_proxies_sorted.size() if (n_not_shown != 0): outl += prefix + "... (remaining %d not shown)\n" % n_not_shown @@ -1588,6 +1674,9 @@ def show_sorted(O, print("%sSorted by %s:" % (prefix, by_value), file=f) print(outl[:-1], file=f) + if return_result: + return result + @bp.inject_into(parallelity) class _(): @@ -1896,7 +1985,15 @@ def _show_sorted_impl(O, f, prefix, max_items, - origin_id=None): + origin_id=None, + return_result = False, + ): + if return_result: + result = group_args(group_args_type = '%s restraints' %(proxy_label), + by_value = by_value, + max_items = max_items, + value_list = [],) + if (f is None): f = sys.stdout sorted_table, n_not_shown = _get_sorted_impl(O, proxy_type=proxy_type, @@ -1926,6 +2023,32 @@ def _show_sorted_impl(O, print("%s%s %s" % (prefix, s, l), file=outl) s = item_label_blank restraint._show_sorted_item(f=outl, prefix=prefix) + + if return_result: + def value_from_restraint(restraint, key_ending = None): + for x in dir(restraint): + if not x.startswith("__") and x.endswith(key_ending): + return getattr(restraint,x) + + #angle_ideal, angle_model, delta, variance**0.5, weight, residual + delta = restraint.delta + sigma = weight_as_sigma(weight = restraint.weight) + ideal = value_from_restraint(restraint,'_ideal') + model = value_from_restraint(restraint,'_model') + residual = restraint.residual() + if proxy_label == 'Dihedral angle': + ideal = model + delta + if ideal<-180: ideal+=360 + + value = group_args(group_args_type = '%s result' %proxy_label, + labels = labels, + delta = delta, + sigma = sigma, + ideal = ideal, + model = model, + residual = residual) + result.value_list.append(value) + if (n_not_shown != 0): if (proxy_type is dihedral): n_harmonic = O.count_harmonic() @@ -1938,6 +2061,9 @@ def _show_sorted_impl(O, print("%sSorted by %s:" % (prefix, by_value), file=f) print(outl.getvalue()[:-1], file=f) + if return_result: + return result + class pair_proxies(object): def __init__(self, diff --git a/mmtbx/command_line/holton_geometry_validation.py b/mmtbx/command_line/holton_geometry_validation.py new file mode 100644 index 0000000000..8ceeb61d13 --- /dev/null +++ b/mmtbx/command_line/holton_geometry_validation.py @@ -0,0 +1,12 @@ +from __future__ import absolute_import, division, print_function +# LIBTBX_SET_DISPATCHER_NAME phenix.holton_geometry_validation +# LIBTBX_SET_DISPATCHER_NAME mmtbx.holton_geometry_validation +# LIBTBX_PRE_DISPATCHER_INCLUDE_SH export PHENIX_GUI_ENVIRONMENT=1 + +import sys + +from mmtbx.programs import holton_geometry_validation +from iotbx.cli_parser import run_program + +if __name__ == '__main__': + run_program(program_class=holton_geometry_validation.Program) diff --git a/mmtbx/programs/holton_geometry_validation.py b/mmtbx/programs/holton_geometry_validation.py new file mode 100644 index 0000000000..2a2cf734e3 --- /dev/null +++ b/mmtbx/programs/holton_geometry_validation.py @@ -0,0 +1,70 @@ +""" +Holton geometry validation score calculation. Based on a +script by James Holton (untangle_score.csh). See details in +mmtbx/validation/holton_geometry_validation.py +""" + +from __future__ import absolute_import, division, print_function + +import os +from mmtbx.validation.holton_geometry_validation import \ + holton_geometry_validation +from libtbx.program_template import ProgramTemplate +from datetime import datetime + +try: + from phenix.program_template import ProgramTemplate +except ImportError: + pass + +class Program(ProgramTemplate): + prog = os.getenv('LIBTBX_DISPATCHER_NAME') + description=""" +%(prog)s file.pdb [params.eff] [options ...] + +Options: + + model=input_file input PDB file + +Example: + + %(prog)s model=1ubq.pdb +""" % locals() + + master_phil_str = """ + model = None + .type = path + .optional = False + .help = '''input PDB file''' + +""" + + + datatypes = ['model','phil'] + + def validate(self): + self.set_defaults() + self.data_manager.has_models(raise_sorry=True) + + def set_defaults(self): + + if not self.params.model: + self.data_manager.has_models(raise_sorry=True) + self.params.model = self.data_manager.get_default_model_name() + self.model = self.data_manager.get_model(self.params.model) + print("\nModel read from %s" %(self.params.model), file = self.logger) + + def run(self): + + + self.results = holton_geometry_validation( + dm = self.data_manager, + filename = self.params.model, + model = self.model, + log =self.logger,) + + def get_results(self): + return self.results + + def get_results_as_JSON(self): + return self.results.as_JSON(self.info_json) diff --git a/mmtbx/regression/tst_holton_geometry_validation.py b/mmtbx/regression/tst_holton_geometry_validation.py new file mode 100644 index 0000000000..07da06b48c --- /dev/null +++ b/mmtbx/regression/tst_holton_geometry_validation.py @@ -0,0 +1,219 @@ +from __future__ import absolute_import, division, print_function +from scitbx.array_family import flex +import time + +from mmtbx.programs import holton_geometry_validation +from iotbx.cli_parser import run_program + + + +pdb_str = """ +ATOM 111 N AASP A 8 7.955 -2.855 0.018 0.50 7.81 N +ATOM 112 CA AASP A 8 8.002 -4.252 -0.397 0.50 7.24 C +ATOM 113 C AASP A 8 8.554 -5.084 0.753 0.50 8.19 C +ATOM 114 O AASP A 8 8.480 -4.659 1.910 0.50 7.28 O +ATOM 115 CB AASP A 8 8.775 -4.435 -1.715 0.50 7.27 C +ATOM 116 CG AASP A 8 10.242 -4.030 -1.622 0.50 7.87 C +ATOM 117 OD1AASP A 8 10.746 -3.749 -0.513 0.50 7.71 O +ATOM 118 OD2AASP A 8 10.901 -4.004 -2.686 0.50 7.34 O +ATOM 119 N BASP A 8 7.795 -2.908 0.329 0.50 6.89 N +ATOM 120 CA BASP A 8 7.797 -4.330 0.033 0.50 7.76 C +ATOM 121 C BASP A 8 8.506 -5.085 1.155 0.50 7.71 C +ATOM 122 O BASP A 8 8.982 -4.499 2.132 0.50 8.33 O +ATOM 123 CB BASP A 8 8.401 -4.597 -1.349 0.50 8.40 C +ATOM 124 CG BASP A 8 9.896 -4.295 -1.427 0.50 8.54 C +ATOM 125 OD1BASP A 8 10.507 -3.890 -0.409 0.50 8.52 O +ATOM 126 OD2BASP A 8 10.467 -4.478 -2.524 0.50 8.59 O +ATOM 143 N AVAL A 10 11.698 -5.862 1.272 0.50 7.04 N +ATOM 144 CA AVAL A 10 13.074 -5.505 1.619 0.50 6.68 C +ATOM 145 C AVAL A 10 13.196 -4.022 1.969 0.50 6.97 C +ATOM 146 O AVAL A 10 14.268 -3.427 1.822 0.50 7.19 O +ATOM 147 CB AVAL A 10 14.068 -5.906 0.511 0.50 8.14 C +ATOM 148 CG1AVAL A 10 14.094 -7.426 0.333 0.50 7.45 C +ATOM 149 CG2AVAL A 10 13.711 -5.221 -0.792 0.50 7.14 C +ATOM 150 N BVAL A 10 11.294 -6.157 1.579 0.50 9.47 N +ATOM 151 CA BVAL A 10 12.679 -5.802 1.861 0.50 8.32 C +ATOM 152 C BVAL A 10 12.838 -4.313 2.188 0.50 7.84 C +ATOM 153 O BVAL A 10 13.927 -3.767 2.057 0.50 7.90 O +ATOM 154 CB BVAL A 10 13.639 -6.267 0.749 0.50 8.37 C +ATOM 155 CG1BVAL A 10 13.659 -7.780 0.662 0.50 8.88 C +ATOM 156 CG2BVAL A 10 13.239 -5.655 -0.585 0.50 8.99 C +ATOM 157 N AASN A 11 12.095 -3.409 2.406 0.50 7.18 N +ATOM 158 CA AASN A 11 12.072 -2.046 2.939 0.50 6.24 C +ATOM 159 C AASN A 11 12.158 -0.957 1.869 0.50 6.76 C +ATOM 160 O AASN A 11 12.518 0.183 2.185 0.50 6.62 O +ATOM 161 CB AASN A 11 13.136 -1.843 4.030 0.50 7.10 C +ATOM 162 CG AASN A 11 12.842 -0.668 4.936 0.50 6.86 C +ATOM 163 OD1AASN A 11 11.710 -0.464 5.371 0.50 6.49 O +ATOM 164 ND2AASN A 11 13.876 0.109 5.233 0.50 6.63 N +ATOM 165 N BASN A 11 11.747 -3.647 2.585 0.50 7.49 N +ATOM 166 CA BASN A 11 11.781 -2.275 3.101 0.50 7.01 C +ATOM 167 C BASN A 11 12.007 -1.219 2.016 0.50 7.03 C +ATOM 168 O BASN A 11 12.615 -0.177 2.280 0.50 6.89 O +ATOM 169 CB BASN A 11 12.824 -2.145 4.230 0.50 7.54 C +ATOM 170 CG BASN A 11 12.593 -0.931 5.117 0.50 7.89 C +ATOM 171 OD1BASN A 11 11.461 -0.620 5.482 0.50 6.89 O +ATOM 172 ND2BASN A 11 13.673 -0.244 5.471 0.50 7.51 N +ATOM 173 N ACYS A 12 11.818 -1.258 0.612 0.50 6.26 N +ATOM 174 CA ACYS A 12 11.832 -0.272 -0.466 0.50 5.29 C +ATOM 175 C ACYS A 12 10.434 0.290 -0.679 0.50 5.74 C +ATOM 176 O ACYS A 12 9.456 -0.464 -0.737 0.50 5.92 O +ATOM 177 CB ACYS A 12 12.327 -0.891 -1.776 0.50 5.75 C +ATOM 178 SG ACYS A 12 13.966 -0.380 -2.285 0.50 5.62 S +ATOM 179 N BCYS A 12 11.494 -1.447 0.808 0.50 6.57 N +ATOM 180 CA BCYS A 12 11.622 -0.502 -0.294 0.50 7.46 C +ATOM 181 C BCYS A 12 10.280 0.166 -0.578 0.50 6.92 C +ATOM 182 O BCYS A 12 9.254 -0.511 -0.685 0.50 6.31 O +ATOM 183 CB BCYS A 12 12.112 -1.223 -1.547 0.50 7.67 C +ATOM 184 SG BCYS A 12 13.695 -2.037 -1.328 0.50 8.82 S +ATOM 199 N ATYR A 14 7.322 2.584 -2.627 0.50 6.23 N +ATOM 200 CA ATYR A 14 6.663 2.581 -3.933 0.50 5.87 C +ATOM 201 C ATYR A 14 6.927 3.906 -4.639 0.50 6.21 C +ATOM 202 O ATYR A 14 6.425 4.948 -4.212 0.50 5.65 O +ATOM 203 CB ATYR A 14 5.154 2.434 -3.753 0.50 5.82 C +ATOM 204 CG ATYR A 14 4.624 1.049 -3.457 0.50 5.69 C +ATOM 205 CD1ATYR A 14 4.972 0.371 -2.294 0.50 6.79 C +ATOM 206 CD2ATYR A 14 3.702 0.452 -4.312 0.50 6.13 C +ATOM 207 CE1ATYR A 14 4.446 -0.878 -2.018 0.50 6.09 C +ATOM 208 CE2ATYR A 14 3.177 -0.791 -4.044 0.50 6.42 C +ATOM 209 CZ ATYR A 14 3.548 -1.451 -2.897 0.50 5.51 C +ATOM 210 OH ATYR A 14 3.023 -2.697 -2.637 0.50 6.12 O +ATOM 211 N BTYR A 14 7.325 2.527 -2.608 0.50 6.17 N +ATOM 212 CA BTYR A 14 6.638 2.433 -3.897 0.50 6.72 C +ATOM 213 C BTYR A 14 6.782 3.752 -4.647 0.50 5.79 C +ATOM 214 O BTYR A 14 6.167 4.754 -4.270 0.50 6.16 O +ATOM 215 CB BTYR A 14 5.148 2.159 -3.689 0.50 6.80 C +ATOM 216 CG BTYR A 14 4.761 0.731 -3.368 0.50 6.89 C +ATOM 217 CD1BTYR A 14 5.150 0.132 -2.175 0.50 6.18 C +ATOM 218 CD2BTYR A 14 3.957 -0.005 -4.236 0.50 6.90 C +ATOM 219 CE1BTYR A 14 4.783 -1.175 -1.868 0.50 8.20 C +ATOM 220 CE2BTYR A 14 3.582 -1.312 -3.933 0.50 6.96 C +ATOM 221 CZ BTYR A 14 3.997 -1.890 -2.748 0.50 6.78 C +ATOM 222 OH BTYR A 14 3.625 -3.181 -2.445 0.50 7.07 O +ATOM 337 N ACYS A 22 -1.297 5.808 -6.189 0.50 6.56 N +ATOM 338 CA ACYS A 22 -1.078 5.393 -4.808 0.50 6.42 C +ATOM 339 C ACYS A 22 -2.383 5.027 -4.114 0.50 6.35 C +ATOM 340 O ACYS A 22 -2.398 4.124 -3.271 0.50 6.60 O +ATOM 341 CB ACYS A 22 -0.353 6.485 -4.020 0.50 6.14 C +ATOM 342 SG ACYS A 22 1.349 6.836 -4.545 0.50 5.40 S +ATOM 343 N BCYS A 22 -1.301 5.667 -6.228 0.50 6.21 N +ATOM 344 CA BCYS A 22 -1.071 5.339 -4.825 0.50 6.37 C +ATOM 345 C BCYS A 22 -2.368 5.018 -4.110 0.50 6.36 C +ATOM 346 O BCYS A 22 -2.415 4.102 -3.282 0.50 6.57 O +ATOM 347 CB BCYS A 22 -0.368 6.485 -4.117 0.50 6.21 C +ATOM 348 SG BCYS A 22 1.310 6.624 -4.618 0.50 5.77 S +ATOM 461 N ALYS A 30 -5.499 -2.976 1.528 0.50 9.91 N +ATOM 462 CA ALYS A 30 -6.635 -2.839 2.439 0.50 10.71 C +ATOM 463 C ALYS A 30 -6.628 -1.571 3.288 0.50 9.70 C +ATOM 464 O ALYS A 30 -7.236 -1.549 4.362 0.50 8.81 O +ATOM 465 CB ALYS A 30 -6.820 -4.083 3.317 0.50 10.52 C +ATOM 466 CG ALYS A 30 -7.599 -5.189 2.640 0.50 12.51 C +ATOM 467 CD ALYS A 30 -7.803 -6.365 3.568 0.50 10.25 C +ATOM 468 CE ALYS A 30 -7.876 -7.644 2.765 0.50 10.80 C +ATOM 469 NZ ALYS A 30 -6.655 -7.773 1.930 0.50 10.53 N +ATOM 470 N BLYS A 30 -5.855 -3.072 1.681 0.50 10.64 N +ATOM 471 CA BLYS A 30 -6.946 -2.847 2.624 0.50 9.92 C +ATOM 472 C BLYS A 30 -6.791 -1.543 3.390 0.50 9.35 C +ATOM 473 O BLYS A 30 -7.488 -1.330 4.398 0.50 9.45 O +ATOM 474 CB BLYS A 30 -7.162 -4.032 3.575 0.50 11.35 C +ATOM 475 CG BLYS A 30 -7.228 -5.374 2.860 0.50 11.31 C +ATOM 476 CD BLYS A 30 -8.402 -5.359 1.913 0.50 9.67 C +ATOM 477 CE BLYS A 30 -8.733 -6.731 1.364 0.50 9.32 C +ATOM 478 NZ BLYS A 30 -9.986 -6.662 0.557 0.50 10.04 N +ATOM 487 N AGLU A 32 -7.365 2.739 3.840 0.50 8.10 N +ATOM 488 CA AGLU A 32 -8.473 3.648 3.543 0.50 7.98 C +ATOM 489 C AGLU A 32 -8.288 4.335 2.195 0.50 6.88 C +ATOM 490 O AGLU A 32 -9.216 4.387 1.376 0.50 6.45 O +ATOM 491 CB AGLU A 32 -8.595 4.711 4.634 0.50 7.29 C +ATOM 492 CG AGLU A 32 -9.613 5.805 4.308 0.50 7.60 C +ATOM 493 CD AGLU A 32 -9.391 7.074 5.105 0.50 7.23 C +ATOM 494 OE1AGLU A 32 -8.512 7.868 4.713 0.50 8.01 O +ATOM 495 OE2AGLU A 32 -10.081 7.283 6.122 0.50 7.79 O +ATOM 496 N BGLU A 32 -7.300 2.584 3.633 0.50 6.66 N +ATOM 497 CA BGLU A 32 -8.443 3.417 3.269 0.50 6.75 C +ATOM 498 C BGLU A 32 -8.189 4.186 1.980 0.50 6.70 C +ATOM 499 O BGLU A 32 -8.982 4.121 1.029 0.50 6.92 O +ATOM 500 CB BGLU A 32 -8.718 4.419 4.384 0.50 7.54 C +ATOM 501 CG BGLU A 32 -9.756 5.449 3.995 0.50 6.77 C +ATOM 502 CD BGLU A 32 -9.626 6.748 4.747 0.50 7.18 C +ATOM 503 OE1BGLU A 32 -8.610 7.447 4.548 0.50 7.36 O +ATOM 504 OE2BGLU A 32 -10.546 7.076 5.526 0.50 7.04 O +ATOM 667 N AGLY A 43 12.501 9.989 -2.091 0.50 7.99 N +ATOM 668 CA AGLY A 43 11.943 10.332 -3.372 0.50 8.26 C +ATOM 669 C AGLY A 43 10.431 10.232 -3.337 0.50 7.19 C +ATOM 670 O AGLY A 43 9.797 10.095 -2.281 0.50 6.81 O +ATOM 671 N BGLY A 43 12.410 9.938 -1.840 0.50 7.47 N +ATOM 672 CA BGLY A 43 12.031 10.247 -3.203 0.50 7.28 C +ATOM 673 C BGLY A 43 10.526 10.359 -3.311 0.50 6.96 C +ATOM 674 O BGLY A 43 9.836 10.572 -2.316 0.50 7.68 O +ATOM 701 N ACYS A 46 4.585 6.467 -2.227 0.50 5.36 N +ATOM 702 CA ACYS A 46 3.189 6.387 -1.826 0.50 5.02 C +ATOM 703 C ACYS A 46 3.063 6.397 -0.308 0.50 5.06 C +ATOM 704 O ACYS A 46 3.836 5.742 0.403 0.50 5.83 O +ATOM 705 CB ACYS A 46 2.532 5.126 -2.400 0.50 5.32 C +ATOM 706 SG ACYS A 46 2.338 5.087 -4.206 0.50 4.49 S +ATOM 707 N BCYS A 46 4.534 6.419 -2.240 0.50 5.44 N +ATOM 708 CA BCYS A 46 3.142 6.346 -1.807 0.50 5.05 C +ATOM 709 C BCYS A 46 3.037 6.367 -0.290 0.50 5.09 C +ATOM 710 O BCYS A 46 3.725 5.604 0.403 0.50 5.43 O +ATOM 711 CB BCYS A 46 2.463 5.062 -2.291 0.50 5.52 C +ATOM 712 SG BCYS A 46 2.136 4.845 -4.042 0.50 5.43 S +ATOM 773 N ALYS A 50 -4.766 4.450 7.185 0.50 5.92 N +ATOM 774 CA ALYS A 50 -5.598 3.384 7.750 0.50 6.92 C +ATOM 775 C ALYS A 50 -5.256 1.999 7.200 0.50 6.62 C +ATOM 776 O ALYS A 50 -6.133 1.212 6.829 0.50 6.24 O +ATOM 777 CB ALYS A 50 -7.089 3.703 7.631 0.50 6.66 C +ATOM 778 CG ALYS A 50 -7.476 4.993 8.327 0.50 7.19 C +ATOM 779 CD ALYS A 50 -8.989 5.149 8.428 0.50 7.18 C +ATOM 780 CE ALYS A 50 -9.356 6.389 9.224 0.50 7.39 C +ATOM 781 NZ ALYS A 50 -10.788 6.413 9.617 0.50 7.71 N +ATOM 782 N BLYS A 50 -4.605 4.533 7.317 0.50 6.77 N +ATOM 783 CA BLYS A 50 -5.393 3.489 7.979 0.50 6.78 C +ATOM 784 C BLYS A 50 -5.189 2.100 7.365 0.50 6.66 C +ATOM 785 O BLYS A 50 -6.143 1.382 7.056 0.50 7.37 O +ATOM 786 CB BLYS A 50 -6.873 3.875 8.060 0.50 7.42 C +ATOM 787 CG BLYS A 50 -7.111 5.205 8.763 0.50 6.97 C +ATOM 788 CD BLYS A 50 -8.584 5.462 9.036 0.50 7.73 C +ATOM 789 CE BLYS A 50 -8.793 6.865 9.613 0.50 8.24 C +ATOM 790 NZ BLYS A 50 -8.648 7.937 8.584 0.50 7.95 N +""" +def run(): + filename = 'tst_holton_geometry_validation.pdb' + f = open(filename,'w') + print(pdb_str, file = f) + f.close() + result = run_program(program_class=holton_geometry_validation.Program, + args = [filename]) + # print (result) + expected_worst_table = {'CBETADEV': ['CBETADEV 8.1796 10 | B VAL A 10'], 'CLASH': ['CLASH 1.0814 -0.413 | HB2 A GLU A 32 - HB2 A LYS A 50 '], 'OMEGA': ['OMEGA 4.472084 10 0 171.49 | CA B VAL A 10'], 'RAMA': ['RAMA 3.4214 11 | 0.89 B ASN A 11'], 'ROTA': ['ROTA 5.4138 12 | 0.08 A CYS A 12'], 'ANGLE': ['ANGLE 4.70 -4.99 119.39 114.40 2.3 | CA B CYS A 46 - CB B CYS A 46 - SG B CYS A 46 '], 'BOND': ['BOND 2.42 0.051 1.757 1.808 0.03 | CB B CYS A 22 - SG B CYS A 22 '], 'CHIR': ['CHIR 1.315 0.23 2.28 2.51 0.2 | CA A LYS A 30 - N A LYS A 30 - C A LYS A 30 - CB A LYS A 30'], 'TORSION': ['TORSION 8.9570 -80.78 80.78 0.00 30.0 | CB A GLU A 32 - CG A GLU A 32 - CD A GLU A 32 - OE1 A GLU A 32'], 'NONBOND': ['NONBOND 1.743667 0.513 2.927 3.440 1 | O B VAL A 10 - CB B ASN A 11'], 'PLANE': ['PLANE 1.4400 -0.024 0.024 0 0.02 | CG A TYR A 14']} + + expected_result_table = {'CBETADEV': ['CBETADEV', '20', '3.25', '8.18', '1.0000', '0.7974', '6.5225', '3.2475'], 'CLASH': ['CLASH', '1', '1.08', '2.08', '0.7016', '0.6177', '1.9033', '1.4603'], 'OMEGA': ['OMEGA', '4', '2.16', '4.47', '0.9289', '0.7053', '3.1541', '2.0039'], 'RAMA': ['RAMA', '2', '3.23', '3.42', '0.9604', '0.6856', '2.3459', '3.1020'], 'ROTA': ['ROTA', '20', '0.82', '5.41', '0.3079', '0.6033', '3.2660', '0.2523'], 'ANGLE': ['ANGLE', '172', '0.35', '4.70', '0.0000', '0.2926', '1.3762', '0.0000'], 'BOND': ['BOND', '152', '0.08', '2.42', '0.0000', '0.1309', '0.3163', '0.0000'], 'CHIR': ['CHIR', '22', '0.32', '1.31', '0.0010', '0.1638', '0.2154', '0.0003'], 'TORSION': ['TORSION', '94', '1.57', '8.96', '0.9996', '0.6876', '6.1589', '1.5671'], 'NONBOND': ['NONBOND', '531', '1.05', '1.74', '0.6123', '0.3741', '0.6523', '0.6412'], 'PLANE': ['PLANE', '56', '0.07', '1.44', '0.0000', '0.1139', '0.1640', '0.0000']} + + compare_tables(result.worst_table, expected_worst_table) + compare_tables(result.result_table, expected_result_table) + + +def compare_tables(a,b): + a_keys = list(a.keys()) + b_keys = list(b.keys()) + a_keys.sort() + b_keys.sort() + assert a_keys == b_keys, (a_keys, b_keys) + for key in a_keys: + t1 = a[key] + t2 = b[key] + assert len(t1) == len(t2), (t1, t2) + for x1, x2 in zip(t1, t2): + try: + xx1 = float(x1) + xx2 = float(x2) + except Exception as e: + xx1 = 0 + xx2 = 0 + assert abs(xx1 - xx2) < 0.02, (xx1, xx2) + +if (__name__ == "__main__"): + t0 = time.time() + run() + print("Time: %6.3f"%(time.time()-t0)) + print("OK") diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py new file mode 100644 index 0000000000..7ac66d49e3 --- /dev/null +++ b/mmtbx/validation/holton_geometry_validation.py @@ -0,0 +1,765 @@ +from libtbx.utils import null_out, Sorry +from libtbx import group_args +from cctbx.geometry_restraints.linking_class import linking_class +from libtbx import adopt_init_args +from scitbx.array_family import flex +from scipy.special import erf, erfinv, gammainc +import math +import os, sys + +''' Port of James Holton's untangle_score.py in Python. Header from original +file follows. + + +throw every validation we can at it -James Holton 1-18-24 + + assemble an overall geometry score + "energy" = (deviate/sigma)**2 + + fraction of Gaussian-random events observed with at least one + event above x=deviate/sigma + in any of Nrep trials is: + fracabove = 1-erf(deviate/sigma/sqrt(2))**Nreps + +i.e. you expect to see > 2 sigma deviates ~5% of the time, +unless you look at 10 at a time, in which case 37% of the time you see at least one > 2 sigma deviate + +so, probability that a x-sigma deviate is not noise, given N samples is: +Pnotnoise(deviate,N) = erf(abs(deviate)/sigma/sqrt(2))**N + +final score will be sum of average square sigma deviations for each +validation metric, plus the sum of: + Pnotnoise*(worstdeviate/sigma)^2 + over worst outlier of each validation metric + to avoid overwhelming all other considerations, these outlier quantities + are softened + so that energy values above 10 are substitued with 10+log(energy)-log(10) + also, the worst-clash energy is multiplied by the number of clashes + +sigma level where probability is 0.5 is given by: + sigma_P50 = sqrt(2)*inverf((0.5)**(1./exponent)) + which is reasonably approximated by: + a2 = -0.0341977; a1 = 0.852225 ; a0 = 1.10939 + sigma_P50(log10e) = a2*log10e**2+a1*log10e+a0 + log10e(exponent) = log(exponent)/log(10) + softer scoring function for large exponents is: + Pnotnoise = 1-2**((deviate/sigma_P50)**5) , naturally clipped at [-1:1] + +for rama, rota etc. +convert probability/frequency back to sigma with: + deviate/sigma = inverf(1-probOK)*sqrt(2) + +cbetadev - use 0.05 A as "sigma" + +nonbonds: use Leonard-Jones to convert to energy [-1:inf], but dont +let "worst" or avg be negative + +omega twist: energy=((sin(omega)/0.07)^2+(1+cos(omega))^10)/(proxPRO*2+1) +where proxPRO means a neighboring residue is proline + + ''' + + +def holton_geometry_validation(dm = None, + filename = None, + model = None, + round_numbers = True, + worst_clash_is_one_plus_worst_clash = True, + minimum_nonbond_score_to_be_worst = -0.1, + minimum_nonbond_score_to_be_included_in_average = 0, + clash_added_energy = 1, + ignore_cis_peptides = True, + ignore_h_except_in_nonbond = True, + ignore_arg_h_nonbond = True, + ignore_bond_lengths_with_h = False, + ignore_water_h_bonds = False, + rotalyze_max_energy = 99, + overall_max_energy = 400, + omega_angle_sigma = 4, # Sigma for omega angle + cbetadev_sigma = 0.05, # Sigma for CB position + clashscore_ideal_dist = 3, # Ideal distance in LJ for clashscore result + lj_dist_that_yields_zero = 6, # Distance for modified LJ to cross zero + softPnna_params = group_args(group_args_type = 'softPnna_params', + y0= 1, + a2= -0.0192266, + a1 = 0.751694, + a0 = 1.12482, + mx = 0.21805, + my = 0.736621), + log = sys.stdout, + ): + + # Capture arguments and save in info + O = group_args(group_args_type = 'info') + adopt_init_args(O,locals()) + info = O + + # Read in model and get sequence + get_model(info) + + # Get basic geometry restraints and filter them + get_geometry_results(info) + + add_omega_results(info) + + filter_geometry_results(info) + + # Get CBdev analysis + add_cbetadev_results(info) + + # Get Ramachandran analyses + add_rama_results(info) + + # Get Rotamer analyses + add_rotamer_results(info) + + # Get Molprobity results + add_clashscore_results(info) + + # Sort them all + sort_geometry_results(info) + + # Get worst and average values for each and rescale if desired + analyze_geometry_values(info) + + print_results(info) + + return info + + +def add_clashscore_results(info): + clashscore_result = group_args(group_args_type = 'CLASHSCORE result', + name = 'CLASH', + value_list = []) + info.geometry_results[clashscore_result.name] = clashscore_result + + from mmtbx.validation.clashscore import clashscore + clashes = clashscore( + info.model.get_hierarchy(), + fast = False, + keep_hydrogens=True, + time_limit=120, + save_modified_hierarchy=False, + verbose=False, + do_flips=True, + out=null_out()) + + for r in clashes.results: + if info.round_numbers: + delta = float("%.3f" %(r.overlap)) + else: + delta = r.overlap + + # Convert mmtbx.validation.atom_info to atom_label objects + labels = [atom_label(ai) for ai in r.atoms_info] + + dist = info.clashscore_ideal_dist + delta + energy = lj(dist, info.clashscore_ideal_dist, + dist_that_yields_zero = info.lj_dist_that_yields_zero, + round_numbers = info.round_numbers) + + v = group_args(group_args_type = 'clashscore result as standard value ', + clashscore_result = r, # contains all results + as_string = "CLASH %.4f %.3f | %s - %s " %( + tuple([energy, delta] + [l.as_string() for l in labels])), + resseq = None, + delta = delta, + residual = energy, + ) + clashscore_result.value_list.append(v) + +def add_rotamer_results(info): + rotamer_result = group_args(group_args_type = 'ROTA result', + name = 'ROTA', + value_list = []) + info.geometry_results[rotamer_result.name] = rotamer_result + args = [info.filename] + from iotbx.cli_parser import run_program + from mmtbx.programs import rotalyze + result = run_program(program_class=rotalyze.Program,args=args, + logger = null_out()) + + for r in result.results: + if info.round_numbers: + prob = float("%.1f" %(r.score))/100 + else: + prob = r.score/100 + + prob = min(1.0, max(0.0, prob)) + if prob == 1: + energy = info.rotalyze_max_energy + else: + prob = float("%.35g" %(prob)) -1.0e-16 + energy = energy_from_probability(prob) + energy = min(energy, info.rotalyze_max_energy) + v = group_args(group_args_type = 'rotamer result as standard value ', + rotamer_result = r, # contains resseq, resseq_as_int, resname, chain_id + as_string = "ROTA %.4f %s | %.2f %s %s %s %s" %( + energy, r.resseq, r.score, r.altloc, r.resname, r.chain_id, r.resseq), + resseq= r.resseq, + delta = None, + residual = energy, + ) + rotamer_result.value_list.append(v) + +def add_rama_results(info): + rama_result = group_args(group_args_type = 'RAMA result', + name = 'RAMA', + value_list = []) + info.geometry_results[rama_result.name] = rama_result + args = [info.filename] + from iotbx.cli_parser import run_program + from mmtbx.programs import ramalyze + result = run_program(program_class=ramalyze.Program,args=args, + logger = null_out()) + for r in result.results: + if info.round_numbers: + prob = float("%.2f" %(r.score))/100 + else: + prob = r.score/100 + energy = energy_from_probability(prob) + v = group_args(group_args_type = 'rama result as standard value ', + rama_result = r, # contains resseq, resseq_as_int, resname, chain_id + as_string = "RAMA %.4f %s | %.2f %s %s %s %s" %( + energy, r.resseq, r.score, r.altloc, r.resname, r.chain_id, r.resseq), + resseq= r.resseq, + delta = None, + residual = energy, + ) + rama_result.value_list.append(v) + +def add_cbetadev_results(info): + cbetadev_result = group_args(group_args_type = 'CBETADEV result', + name = 'CBETADEV', + value_list = []) + info.geometry_results[cbetadev_result.name] = cbetadev_result + args = [info.filename] + from iotbx.cli_parser import run_program + from mmtbx.programs import cbetadev + result = run_program(program_class=cbetadev.Program,args=args, + logger = null_out()) + for r in result.results: + if info.round_numbers: + delta = float("%.3f" %(r.deviation)) + else: + delta = r.deviation + energy = (delta/info.cbetadev_sigma)**2 + v = group_args(group_args_type = 'cbetadev result as standard value ', + cbetadev_result = r, # contains resseq, resseq_as_int, resname, chain_id + as_string = "CBETADEV %.4f %s | %s %s %s %s" %( + energy, r.resseq, r.altloc, r.resname, r.chain_id, r.resseq), + resseq= r.resseq, + delta = r.deviation, + residual = energy, + ) + cbetadev_result.value_list.append(v) + +def select_geometry_result(info, name = None, skip_name = None): + result_list = [] + for key in info.geometry_results.keys(): + if name and info.geometry_results[key].name == name: + return info.geometry_results[key] + elif skip_name and info.geometry_results[key].name != skip_name: + result_list.append(info.geometry_results[key]) + return result_list + +def analyze_geometry_values(info): + keys = list(info.geometry_results.keys()) + keys.sort() + sum_energy = 0.0 + for key in keys: + result = info.geometry_results[key] + + if not result.value_list: + result.worst_residual = None + result.average_residual = None + continue + + worst_value = result.value_list[0] + + # Get worst residual value and save it: + + # Some special cases allowed in choosing worst value + + if info.worst_clash_is_one_plus_worst_clash and \ + result.name == 'CLASH': # Special case + result.worst_residual = abs(1 + worst_value.residual) + + elif info.minimum_nonbond_score_to_be_worst is not None and \ + result.name == 'NONBOND' and ( + worst_value.residual < info.minimum_nonbond_score_to_be_worst): + result.worst_residual = None + else: # usual + result.worst_residual = worst_value.residual + + # Get average value and save it too: + value_list = result.value_list + + # Special case: non bond scores with low values may be excluded + if info.minimum_nonbond_score_to_be_included_in_average is not None and \ + result.name == 'NONBOND': + value_list = [] + for v in result.value_list: + if v.residual > info.minimum_nonbond_score_to_be_included_in_average: + value_list.append(v) + + values = flex.double() + for v in value_list: + values.append(v.residual) + result.mean_residual = values.min_max_mean().mean + result.n = values.size() + + energy = max(0, min(info.overall_max_energy, result.worst_residual)) + delta = energy**0.5 + result.pnna = softPnna(delta, result.n, info.softPnna_params) + + # Special case for CLASH + if result.name == "CLASH" and info.clash_added_energy is not None: + energy += info.clash_added_energy + + result.energy = filtered_energy(result.pnna * energy) + sum_energy += result.energy + + # Repeat using mean instead of worst, multiplying mean energy * Chisq + energy_mean = max(0, min(info.overall_max_energy, result.mean_residual)) + ssd = result.mean_residual * result.n + result.chisq = chisq(ssd, result.n) + + # Special case for CLASH + if result.name == "CLASH" and info.clash_added_energy is not None: + energy_mean += info.clash_added_energy + + result.energy_using_mean = filtered_energy( + result.chisq * energy_mean) + sum_energy += result.energy_using_mean + + info.sum_energy = sum_energy + +def sort_geometry_results(info): + keys = list(info.geometry_results.keys()) + keys.sort() + for key in keys: + result = info.geometry_results[key] + result.value_list = sorted( + result.value_list, key = lambda v: + v.residual, reverse = True) + + +def print_results(info): + + print("SUMMARY of Holton geometry validation scoring for %s" %(info.filename), + file = info.log) + print(file = info.log) + print("Overall geometry energy: %.4f" %(info.sum_energy), file = info.log) + + info.result_table = {} + info.result_header_row = [ + 'Category','N','Mean','Worst','Chisq','Pnna','Energy','Using mean'] + fmt = len(info.result_header_row) * " %8s " + print(file = info.log) + print(fmt %(tuple(info.result_header_row)), file = info.log) + print(file = info.log) + + keys = list(info.geometry_results.keys()) + keys.sort() + for key in keys: + result = info.geometry_results[key] + value_list = result.value_list + info.result_table[result.name] = \ + [result.name, + "%s" %str(len(value_list)), + "%.2f" %(result.mean_residual) if result.mean_residual \ + is not None else "None", + "%.2f" %(result.worst_residual) if result.worst_residual \ + is not None else "None", + "%.4f" %(result.chisq) if result.chisq \ + is not None else "None", + "%.4f" %(result.pnna) if result.pnna \ + is not None else "None", + "%.4f" %(result.energy) if result.energy\ + is not None else "None", + "%.4f" %(result.energy_using_mean) if result.energy_using_mean\ + is not None else "None" ] + print(fmt %(tuple(info.result_table[result.name])), + file = info.log) + + info.worst_table = {} + info.worst_header_row = ['Worst in each category'] + fmt = "%s" + print(file = info.log) + print(fmt %(tuple(info.worst_header_row)), file = info.log) + print(file = info.log) + for key in keys: + result = info.geometry_results[key] + value_list = result.value_list + info.worst_table[result.name] = [ + value_list[0].as_string if value_list else ""] + print(fmt %(tuple(info.worst_table[result.name])), + file = info.log) + + if info.ignore_h_except_in_nonbond: + print("\nTotal H interactions (not in non-bonded) removed: %s" %( + info.ignore_h_except_in_nonbond_removed), file = info.log) + if info.ignore_arg_h_nonbond: + print("Total ARG H-nonbond removed: %s" %( + info.ignore_arg_h_nonbond_removed), file = info.log) + if info.ignore_water_h_bonds: + print("Total water H-nonbond removed: %s" %( + info.ignore_water_h_bonds_removed), file = info.log) + if info.ignore_bond_lengths_with_h: + print("Total bonds with H removed: %s" %( + info.ignore_bond_lengths_with_h_removed), file = info.log) + +def filter_geometry_results(info): + + info.ignore_arg_h_nonbond_removed = 0 + info.ignore_water_h_bonds_removed = 0 + info.ignore_bond_lengths_with_h_removed = 0 + info.ignore_h_except_in_nonbond_removed = 0 + + if not True in [info.ignore_arg_h_nonbond, info.ignore_bond_lengths_with_h, + info.ignore_water_h_bonds]: + return # nothing to do + + if info.ignore_h_except_in_nonbond: + # Remove anything with element H except in NONBOND + for result in select_geometry_result(info,skip_name = 'NONBOND'): + for v in result.value_list: + elements = [l.atom.element for l in v.labels] + if 'H' in elements: + result.value_list.remove(v) + info.ignore_h_except_in_nonbond_removed += 1 + continue + + if info.ignore_arg_h_nonbond or info.ignore_water_h_bonds: + nonbond_result = select_geometry_result(info,'NONBOND') + for v in nonbond_result.value_list: + elements = [l.atom.element for l in v.labels] + residues = [l.atom.resname for l in v.labels] + + if info.ignore_arg_h_nonbond: + if elements == ['H','H'] and residues == ['ARG','ARG']: + nonbond_result.value_list.remove(v) + info.ignore_arg_h_nonbond_removed += 1 + continue + + if info.ignore_water_h_bonds: + found = False + for element, res in zip(elements, residues): + if element == 'H' and res in ['WAT','HOH']: + nonbond_result.value_list.remove(v) + found = True + if found: + info.ignore_water_h_bonds_removed += 1 + continue + + if info.ignore_bond_lengths_with_h: + bond_result = select_geometry_result(info,'BOND') + for v in bond_result.value_list: + elements = [l.atom.element for l in v.labels] + if 'H' in elements: + bond_result.value_list.remove(v) + info.ignore_bond_lengths_with_h_removed += 1 + continue + +def add_omega_results(info): + torsion_result = select_geometry_result(info, 'TORSION') + omega_result = group_args(group_args_type = 'OMEGA result', + name = 'OMEGA', + value_list = []) + info.geometry_results[omega_result.name] = omega_result + + degtorad = math.atan2(1,1)/45. + for v in torsion_result.value_list: + atom_names = [l.atom.name for l in v.labels] + if atom_names[0].strip() != 'CA' or atom_names[3].strip() != 'CA': continue + resseq = v.labels[0].atom.resseq.strip() + chain_id = v.labels[0].atom.chain_id + altloc = v.labels[0].atom.altloc + resnam = info.chain_dict[chain_id].sequence_dict.get(resseq) + omega = v.model * degtorad + n_pro = get_n_pro(info, chain_id, resseq) + new_v = group_args(group_args_type = 'OMEGA derived result', + ) + new_v.model = v.model + new_v.n_pro = n_pro + new_v.labels = [v.labels[0]] + # Score function assuming sigma of 4 degrees: 0.07 is sin(4 deg) + sigma = math.sin(info.omega_angle_sigma * degtorad) + if info.round_numbers: + sigma = float("%.3f" %(sigma)) + new_v.residual=((math.sin(omega)/sigma)**2+ + (1+math.cos(omega))**10)/(n_pro+1) + new_v.as_string = "OMEGA %.6f %s %s %.2f | %s" %( + new_v.residual, resseq, new_v.n_pro, new_v.model, + new_v.labels[0].as_string()) + if info.ignore_cis_peptides and math.cos(omega) > 0: + continue # skip it + omega_result.value_list.append(new_v) + + +def get_n_pro(info, chain_id, resseq): + n_pro = 0 + resseq_as_int = int(resseq) + for i in [resseq_as_int - 1, resseq_as_int + 1]: + if info.chain_dict[chain_id].sequence_dict.get(str(i),None) == 'PRO': + n_pro += 1 + return n_pro + +def get_geometry_results(info): + geometry = info.model.get_restraints_manager().geometry + sites_cart= info.model.get_sites_cart() + site_labels = get_site_labels(info.model) + origin_ids = linking_class() + pair_proxies = geometry.pair_proxies(sites_cart=sites_cart) + + name_dict = {'nonbonded': 'NONBOND', + 'angle_proxies': 'ANGLE', + 'bond_proxies': 'BOND', + 'chirality_proxies': 'CHIR', + 'dihedral_proxies': 'TORSION', + 'planarity_proxies': 'PLANE',} + geometry_results = {} + info.geometry_results = geometry_results + + # Non-bonded + if pair_proxies.nonbonded_proxies is not None: + proxy_name = 'nonbonded' + result = pair_proxies.nonbonded_proxies.show_sorted( + by_value="delta", + sites_cart=sites_cart, + site_labels=site_labels, + f=null_out(), + suppress_model_minus_vdw_greater_than = None, + prefix=" ", + max_items=None, + return_result = True) + # Calculate residual from Lennard-Jones potential + for v in result.value_list: + v.residual = lj(v.model,v.ideal, + dist_that_yields_zero = info.lj_dist_that_yields_zero, + round_numbers = info.round_numbers) + v.delta = v.ideal - v.model + v.group_args_type += " residual is LJ(model, ideal)" + v.as_string = "NONBOND %.6f %.3f %.3f %.3f 1 | %s - %s" %( + v.residual, v.delta, v.model, v.ideal, + v.labels[0].as_string(), v.labels[1].as_string()) + geometry_results[proxy_name] = result + + for proxy_name in ['bond_proxies', 'angle_proxies', 'dihedral_proxies', + 'chirality_proxies', 'planarity_proxies']: + proxies = getattr(pair_proxies, proxy_name, + getattr(geometry, proxy_name, + getattr(geometry, proxy_name, None))) + if proxy_name in ['bond_proxies', 'angle_proxies']: + origin_id=origin_ids.get_origin_id('covalent geometry') + else: + origin_id=None + if proxies: + result = proxies.show_sorted( + by_value="residual", + sites_cart=sites_cart, + site_labels=site_labels, + f=null_out(), + origin_id=origin_id, + return_result = True) + geometry_results[proxy_name] = result + if result.group_args_type == 'Bond restraints': + for v in result.value_list: + v.as_string = "BOND %.2f %.3f %.3f %.3f %.2f | %s - %s " %( + v.residual, v.delta, v.model, v.ideal, v.sigma, + v.labels[0].as_string(), v.labels[1].as_string()) + elif result.group_args_type == 'Bond angle restraints': + for v in result.value_list: + v.as_string = "ANGLE %.2f %.2f %.2f %.2f %.1f | %s - %s - %s " %( + v.residual, v.delta, v.model, v.ideal, v.sigma, + v.labels[0].as_string(), v.labels[1].as_string(), + v.labels[2].as_string()) + elif result.group_args_type == 'Dihedral angle restraints': + for v in result.value_list: + v.as_string = \ + "TORSION %.4f %.2f %.2f %.2f %.1f | %s - %s - %s - %s" %( + v.residual, v.delta, v.model, v.ideal, v.sigma, + v.labels[0].as_string(), v.labels[1].as_string(), + v.labels[2].as_string(), v.labels[3].as_string()) + elif result.group_args_type == 'Chirality restraints': + for v in result.value_list: + v.as_string = \ + "CHIR %.3f %.2f %.2f %.2f %.1f | %s - %s - %s - %s" %( + v.residual, v.delta, v.model, v.ideal, v.sigma, + v.labels[0].as_string(), v.labels[1].as_string(), + v.labels[2].as_string(), v.labels[3].as_string()) + elif result.group_args_type == 'Planarity restraints': + for v in result.value_list: + v.residual = energy(v.delta, v.sigma, + round_numbers = info.round_numbers) + v.as_string = \ + "PLANE %.4f %.3f %.3f %.0f %.2f | %s" %( + v.residual, -v.delta, v.delta, 0, v.sigma, + v.labels[0].as_string()) + for key in name_dict.keys(): + geometry_results[key].name = name_dict[key] + +def get_model(info): + if not info.model: + if not info.filename: + raise Sorry("Please supply a filename") + if not os.path.isfile(info.filename): + raise Sorry("The filename %s is missing" %(info.filename)) + if not info.dm: + from iotbx.data_manager import DataManager + info.dm = DataManager() + if not info.model: + info.model = info.dm.get_model(info.filename) + info.model.set_log(null_out()) + info.model.process(make_restraints=True) + info.model = info.model + info.chain_dict = {} + for chain_id in info.model.chain_ids(unique_only = True): + entry = group_args(group_args_type = 'chain entry', ) + info.chain_dict[chain_id] = entry + + entry.chain = info.model.apply_selection_string( + "chain %s and not water" %(chain_id)) + entry.sequence = entry.chain.as_sequence(as_string = True) + entry.sequence_dict = get_sequence_dict(entry.chain) + entry.residue_numbers = list(entry.sequence_dict.keys()) + entry.residue_numbers.sort() + +def get_sequence_dict(m): # Assumes 1 model, one chain, any conformers + sequence_dict = {} + for model in m.get_hierarchy().models()[:1]: + for chain in model.chains()[:1]: + for conformer in chain.conformers()[:1]: + for residue in conformer.residues(): + sequence_dict[residue.resseq.strip()] = residue.resname + return sequence_dict + +def get_site_labels(model): + labels = [] + for at in model.get_hierarchy().atoms_with_labels(): + labels.append(atom_label(at)) + return labels + +class atom_label: + ''' Class to hold an atom_with_labels object and deliver + the same string as model.get_site_labels() and allow right-ward addition + of str representation and length of the str representation. + Used to pass through pdb_interpretation and return the full atom so + that all characteristics are preserved + NOTE: Can be used for mmtbx.validation.atom_info as well + ''' + def __init__(self, atom): + self.atom = atom + + def as_string(self): + ''' Print a longer string that has all fields separated ''' + atom = self.atom + return "%3s %s %3s %2s %4s" %(atom.name,atom.altloc,atom.resname, + atom.chain_id,atom.resseq) + + def __repr__(self): + # pdb=" CG1AVAL A 1 " Mimics model.get_site_labels() + atom = self.atom + return 'pdb="%3s%1s%3s%2s%4s "' %( + atom.name, atom.altloc, atom.resname, atom.chain_id, atom.resseq) + def __len__(self): + return len(self.__repr__()) + def __add__(self, a): + return self.__repr__() + a + def resseq(self): + return self.atom.resseq + +def energy(delta, sigma, round_numbers = None): + if round_numbers: + delta = float("%.3f" %(delta)) + sigma = float("%.3f" %(sigma)) + energy = (delta/max(1.e-10, sigma))**2 + return energy + +def lj0(r, r0, round_numbers = None): + ''' Lennard-Jones potential''' + if round_numbers: + r = float("%.3f" %(r)) + r0 = float("%.3f" %(r0)) + if( r == 0 ): + return 1e40 + else: + return 4*((r0*2**(-1./6)/r)**12-(r0*2**(-1./6)/r)**6) + +def lj(r, r0, dist_that_yields_zero = 6, round_numbers = None): + ''' Modified Lennard-Jones potential with value of dist_that_yields_zero at 6 (A)''' + return lj0(r,r0, round_numbers = round_numbers)- \ + lj0(dist_that_yields_zero,r0, round_numbers = round_numbers) + +def filtered_energy(energy): + if energy <= 0: + return 0 + elif energy <= 10: + return energy + else: + return 10 + math.log(energy) - math.log(10) + + +def softPnna(delta, n, params = None): + return 1 - 2.0**clip( + -abs(delta/asigma_Pnn50(safelog(n), params))**exponent( + delta,safelog(n), params) ,1000) + +def Pnn(delta,n): + return erf(abs(delta)/math.sqrt(2))**n + +def sigma_Pnn50(n): + # sigma deviates that have Pnn=0.5 + return math.sqrt(2)*erfinv((0.5)**(1./n)) + +def asigma_Pnn50(x, params = None): + return (params.a2*x**2+params.a1*x+params.a0) + +def exponent(x, y, params = None): + # exponent to use in approximation + return params.my*y + params.mx*x + params.y0 + +def safelog(x): + if x <= 0: + return 0 + else: + return math.log10(x) + +def s_thresh(x): + return math.sqrt(2)*erfinv((1.e-30)**(1./x)) + +def safePnn(delta,n): + if delta < s_thresh(n): + return 0 + else: + return Pnn(delta,n) + +def clip(x,y): + if x > y: + return y + elif x <= -y: + return -y + else: + return x + +def chisq(x,k): + if k<1: + return 0 + elif k<3200: + return gammainc(k/2.0,x/2.0) + else: + return chisqhi(x,k) + +def chisqhi(x,k): + return 0.5 + 0.5 * erf((x**0.5)-(k**.5)) + +def energy_from_probability(prob): + assert prob >= 0 + assert prob <= 1 + return (erfinv(1-prob))**2 + +if __name__=="__main__": + import sys + filename = sys.argv[1] if len(sys.argv[1:]) > 0 else None + holton_geometry_validation(filename = filename) From 30a9df76a4fc01294f95bd67a1b5fb8e3ca1b00c Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 3 Apr 2024 12:20:26 -0600 Subject: [PATCH 285/748] Add test --- mmtbx/run_tests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index d37bdbbb51..736e3c0253 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -45,6 +45,7 @@ "$D/regression/tls/tst_formula_t_S_10_vs_11_4muy.py", # "$D/regression/tst_angle.py", + "$D/regression/tst_holton_geometry_validation.py", "$D/rotamer/tst_rotamer_eval.py", "$D/rotamer/tst_geostd_vs_sidechain_angles_props.py", "$D/monomer_library/tst_idealized_aa.py", From 7c3a9ceba2fa82cd84473e96b5d9b02f3f5a80da Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Wed, 3 Apr 2024 12:06:27 -0700 Subject: [PATCH 286/748] S --- mmtbx/ligands/electrons.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/ligands/electrons.py b/mmtbx/ligands/electrons.py index e4d435a007..4239e23302 100644 --- a/mmtbx/ligands/electrons.py +++ b/mmtbx/ligands/electrons.py @@ -853,7 +853,7 @@ def _comp_disallowed(actual, disallowed): terminals = {} for atom, charge in charged_atoms: - if atom.name in [' OXT']: terminals[ag.id_str()]=charge + if atom.name in [' OXT']: terminals[atom.parent().id_str()]=charge ag = atom.parent() if get_class(ag.resname) in ['common_amino_acid']: base = base_amino_acid_charges.get(ag.resname, 0) From bcc23d09f419be595403d509998d3aac28b2072e Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 3 Apr 2024 14:46:40 -0600 Subject: [PATCH 287/748] Catch cases of None --- .../validation/holton_geometry_validation.py | 94 ++++++++++++++++++- 1 file changed, 91 insertions(+), 3 deletions(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 7ac66d49e3..3b11f59c8f 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -63,6 +63,7 @@ def holton_geometry_validation(dm = None, filename = None, model = None, + get_individual_residue_scores = False, round_numbers = True, worst_clash_is_one_plus_worst_clash = True, minimum_nonbond_score_to_be_worst = -0.1, @@ -122,6 +123,9 @@ def holton_geometry_validation(dm = None, # Get worst and average values for each and rescale if desired analyze_geometry_values(info) + # Get residue-based scores + get_residue_scores(info) + print_results(info) return info @@ -165,6 +169,7 @@ def add_clashscore_results(info): resseq = None, delta = delta, residual = energy, + labels = labels, ) clashscore_result.value_list.append(v) @@ -199,6 +204,8 @@ def add_rotamer_results(info): resseq= r.resseq, delta = None, residual = energy, + labels = [atom_label_from_info( + r.chain_id, r.resseq, r.altloc, r.resname, 'CA' )], ) rotamer_result.value_list.append(v) @@ -225,6 +232,8 @@ def add_rama_results(info): resseq= r.resseq, delta = None, residual = energy, + labels = [atom_label_from_info( + r.chain_id, r.resseq, r.altloc, r.resname, 'CA' )], ) rama_result.value_list.append(v) @@ -251,6 +260,8 @@ def add_cbetadev_results(info): resseq= r.resseq, delta = r.deviation, residual = energy, + labels = [atom_label_from_info( + r.chain_id, r.resseq, r.altloc, r.resname, 'CA' )], ) cbetadev_result.value_list.append(v) @@ -263,16 +274,82 @@ def select_geometry_result(info, name = None, skip_name = None): result_list.append(info.geometry_results[key]) return result_list +def get_residue_scores(info): + ''' run through all residues, select those results that involve each residue, + recalculate overall score. + ''' + # For now, only one chain_id + info.residue_scores = [] + if not info.get_individual_residue_scores: + return # nothing to do + + for chain_id in list(info.chain_dict.keys())[:1]: # XXX ZZZ CHAIN ID + for resseq in info.chain_dict[chain_id].sequence_dict.keys(): + working_info = select_residue_info(info, chain_id, resseq) + analyze_geometry_values(working_info) + info.residue_scores.append(working_info.sum_energy) + print("Residue score for %s: %.2f" %(resseq, working_info.sum_energy), + file = info.log) + +def select_residue_info(info, chain_id, resseq): + from copy import deepcopy + + log = info.log + dm = info.dm + geometry_results = info.geometry_results + chain_dict = info.chain_dict + model = info.model + + info.log = None + info.dm= None + info.geometry_results = {} + info.chain_dict = {} + info.model = None + + new_info = deepcopy(info) + + info.log = log + info.dm = dm + info.geometry_results = geometry_results + info.chain_dict = chain_dict + info.model = model + + keys = list(info.geometry_results.keys()) + for key in keys: + orig = info.geometry_results[key] + new_info.geometry_results[key] = group_args( + group_args_type = orig.group_args_type, + name = orig.name, + value_list = []) + + for value in info.geometry_results[key].value_list: + if labels_contain(value.labels, chain_id = chain_id, resseq = resseq): + new_info.geometry_results[key].value_list.append(value) + sort_geometry_results(new_info) + return new_info + +def labels_contain(labels, chain_id = None, resseq = None): + for label in labels: + if ((chain_id is None) or (label.chain_id().strip() == chain_id.strip())) and \ + ((resseq is None) or (label.resseq().strip() == resseq.strip())): + return True + + return False + def analyze_geometry_values(info): keys = list(info.geometry_results.keys()) keys.sort() sum_energy = 0.0 for key in keys: result = info.geometry_results[key] + result.pnna = None + result.energy = None + result.chisq = None + result.energy_using_mean = None + result.worst_residual = None + result.mean_residual = None if not result.value_list: - result.worst_residual = None - result.average_residual = None continue worst_value = result.value_list[0] @@ -308,6 +385,9 @@ def analyze_geometry_values(info): values.append(v.residual) result.mean_residual = values.min_max_mean().mean result.n = values.size() + if result.n < 1: + + continue # nothing to do energy = max(0, min(info.overall_max_energy, result.worst_residual)) delta = energy**0.5 @@ -613,7 +693,6 @@ def get_model(info): info.model = info.dm.get_model(info.filename) info.model.set_log(null_out()) info.model.process(make_restraints=True) - info.model = info.model info.chain_dict = {} for chain_id in info.model.chain_ids(unique_only = True): entry = group_args(group_args_type = 'chain entry', ) @@ -641,6 +720,13 @@ def get_site_labels(model): labels.append(atom_label(at)) return labels +class pseudo_atom: + def __init__(self, chain_id, resseq, altloc, resname, name): + adopt_init_args(self,locals()) + +def atom_label_from_info(chain_id, resseq, altloc, resname, name): + return atom_label(pseudo_atom(chain_id, resseq, altloc, resname, name)) + class atom_label: ''' Class to hold an atom_with_labels object and deliver the same string as model.get_site_labels() and allow right-ward addition @@ -669,6 +755,8 @@ def __add__(self, a): return self.__repr__() + a def resseq(self): return self.atom.resseq + def chain_id(self): + return self.atom.chain_id def energy(delta, sigma, round_numbers = None): if round_numbers: From 6c204669ed192e4c33843f0cefefea5c0babd962 Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 3 Apr 2024 14:50:19 -0600 Subject: [PATCH 288/748] Catch small negative number --- mmtbx/validation/holton_geometry_validation.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 3b11f59c8f..d55640238f 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -843,8 +843,7 @@ def chisqhi(x,k): return 0.5 + 0.5 * erf((x**0.5)-(k**.5)) def energy_from_probability(prob): - assert prob >= 0 - assert prob <= 1 + prob = max(0, min(1, prob)) return (erfinv(1-prob))**2 if __name__=="__main__": From 6fa8f18d54f85522ed4ac00d9b3613ab9c823a2e Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 3 Apr 2024 14:34:49 -0700 Subject: [PATCH 289/748] Set new residues partial occupancy (arbitray) so they are refined later --- mmtbx/building/extend_sidechains.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mmtbx/building/extend_sidechains.py b/mmtbx/building/extend_sidechains.py index 9da80e0389..d1a4b5bf02 100644 --- a/mmtbx/building/extend_sidechains.py +++ b/mmtbx/building/extend_sidechains.py @@ -220,6 +220,10 @@ def extend_protein_model( residue = new_residue, mon_lib_srv = mon_lib_srv, ignore_hydrogens = False) + # + size = new_residue.atoms().size() + new_residue.atoms().set_occ(flex.double(size, 0.9)) + # #assert len(missing_atoms) == 0, missing_atoms rg = residue.parent() rg.remove_atom_group(residue) From 6073a85795468a134f55bb258722781d529faf17 Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 3 Apr 2024 15:48:27 -0700 Subject: [PATCH 290/748] Set partial low occupancy to newsly added missing side chains --- mmtbx/building/extend_sidechains.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/mmtbx/building/extend_sidechains.py b/mmtbx/building/extend_sidechains.py index d1a4b5bf02..e73c40a2f9 100644 --- a/mmtbx/building/extend_sidechains.py +++ b/mmtbx/building/extend_sidechains.py @@ -220,9 +220,16 @@ def extend_protein_model( residue = new_residue, mon_lib_srv = mon_lib_srv, ignore_hydrogens = False) - # - size = new_residue.atoms().size() - new_residue.atoms().set_occ(flex.double(size, 0.9)) + # Set occupancy of newly added non-H atoms to small number so they can be + # refined later automatically and also don't 'shock' the data terms by + # coming in in full occupancy! + anames_old = [] + for a in residue.atoms(): + anames_old.append(a.name) + for a in new_residue.atoms(): + if a.element_is_hydrogen(): continue + if a.name in anames_old: continue + a.set_occ(0.1) # #assert len(missing_atoms) == 0, missing_atoms rg = residue.parent() From 66f832ea8477852d85fce00a8cd4920c9320ce12 Mon Sep 17 00:00:00 2001 From: Russell Taylor Date: Thu, 4 Apr 2024 11:13:56 -0400 Subject: [PATCH 291/748] Reduce2 updates (#982) * Factoring out the setting of interpretation parameters into a function within reduce_hydrogen.py so that it can also be called by reduce2.py, re-using any improvements. * Switching reduce2's calling of probe2 to use a cleaner interface for constructing the command-line arguments. * Factoring out the setting of interpretation parameters into a function within reduce_hydrogen.py so that it can also be called by reduce2.py, re-using any improvements. * Switching reduce2's calling of probe2 to use a cleaner interface for constructing the command-line arguments. --- mmtbx/hydrogens/reduce_hydrogen.py | 23 +++-- mmtbx/programs/reduce2.py | 131 ++++++++++++----------------- 2 files changed, 70 insertions(+), 84 deletions(-) diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index 91f0358bec..1c60c9b8b9 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -111,6 +111,20 @@ def mon_lib_query(residue, mon_lib_srv, construct_h_restraints=True): # md.show() return md +# ============================================================================== +def make_interpretation_parameters(use_neutron_distances): + # Fill in the interpretation parameters we want to use. We do this in a + # function so that other programs (reduce2) can use the same parameters. + p = mmtbx.model.manager.get_default_pdb_interpretation_params() + p.pdb_interpretation.clash_guard.nonbonded_distance_threshold=None + p.pdb_interpretation.use_neutron_distances = use_neutron_distances + p.pdb_interpretation.proceed_with_excessive_length_bonds=True + p.pdb_interpretation.allow_polymer_cross_special_position=True + #p.pdb_interpretation.automatic_linking.link_metals = True + p.pdb_interpretation.automatic_linking.link_residues = True + p.pdb_interpretation.automatic_linking.exclude_hydrogens_from_bonding_decisions = True + return p + # ============================================================================== class place_hydrogens(): @@ -217,14 +231,7 @@ def run(self): # f = open("intermediate2.pdb","w") # f.write(self.model.model_as_pdb()) - p = mmtbx.model.manager.get_default_pdb_interpretation_params() - p.pdb_interpretation.clash_guard.nonbonded_distance_threshold=None - p.pdb_interpretation.use_neutron_distances = self.use_neutron_distances - p.pdb_interpretation.proceed_with_excessive_length_bonds=True - p.pdb_interpretation.allow_polymer_cross_special_position=True - #p.pdb_interpretation.automatic_linking.link_metals = True - p.pdb_interpretation.automatic_linking.link_residues = True - p.pdb_interpretation.automatic_linking.exclude_hydrogens_from_bonding_decisions = True + p = make_interpretation_parameters(self.use_neutron_distances) t0 = time.time() #p.pdb_interpretation.restraints_library.cdl=False # XXX this triggers a bug !=360 diff --git a/mmtbx/programs/reduce2.py b/mmtbx/programs/reduce2.py index 1ce9034e89..bbef8d2480 100644 --- a/mmtbx/programs/reduce2.py +++ b/mmtbx/programs/reduce2.py @@ -20,10 +20,10 @@ from libtbx.program_template import ProgramTemplate from libtbx import group_args, phil from libtbx.str_utils import make_sub_header -from libtbx.utils import Sorry +from libtbx.utils import Sorry, null_out import mmtbx from mmtbx.probe import Helpers -from iotbx import pdb +from iotbx import pdb, cli_parser # @todo See if we can remove the shift and box once reduce_hydrogen is complete from cctbx.maptbx.box import shift_and_box_model from mmtbx.hydrogens import reduce_hydrogen @@ -36,7 +36,7 @@ from iotbx.data_manager import DataManager import csv -version = "2.2.0" +version = "2.3.0" master_phil_str = ''' approach = *add remove @@ -960,7 +960,11 @@ def _GetViews(self, movers): return views # ------------------------------------------------------------------------------ - def _MakeProbePhil(self, movers_to_check, temp_output_file_name): + # Create a parser for Probe2 PHIL parameters, overriding specific defaults. + # Use it to parse the parameters we need to change and return the parser so we + # can extract values from it. + def _MakeProbePhilParser(self, movers_to_check, temp_output_file_name, extraArgs = []): + # Determine the source and target selections based on the Movers # that we are checking being tested against everything else. source_selection = 'sidechain and (' @@ -974,51 +978,24 @@ def _MakeProbePhil(self, movers_to_check, temp_output_file_name): source_selection += ')' target_selection = 'all' - # Set default parameters and then only overwrite the ones we need - newParams = copy.deepcopy(self.params) - newParams.__inject__('source_selection', source_selection) # Not default - newParams.__inject__('target_selection', target_selection) # Not default - newParams.approach = 'both' # Not default - newParams.__inject__('excluded_bond_chain_length', self._bondedNeighborDepth) # Not default - newParams.__inject__('minimum_water_hydrogen_occupancy', 0.66) # Not default - newParams.__inject__('maximum_water_hydrogen_b', 40.0) # Not default - newParams.__inject__('include_mainchain_mainchain', True) - newParams.__inject__('include_water_water', False) - newParams.__inject__('keep_unselected_atoms', True) - newParams.__inject__('atom_radius_scale', 1.0) - newParams.__inject__('atom_radius_offset', 0.0) - newParams.__inject__('minimum_occupancy', 0.01) # Not default - newParams.__inject__('overlap_scale_factor', 0.5) - newParams.__inject__('ignore_lack_of_explicit_hydrogens', True) - - newParams.output.filename = temp_output_file_name # Not default - newParams.output.__inject__('dump_file_name', None) - newParams.output.__inject__('format', 'kinemage') - newParams.output.__inject__('contact_summary', False) - newParams.output.__inject__('condensed', False) - newParams.output.__inject__('count_dots', False) - newParams.output.__inject__('hydrogen_bond_output', True) - newParams.output.__inject__('record_added_hydrogens', False) - newParams.output.__inject__('report_hydrogen_bonds', True) - newParams.output.__inject__('report_clashes', True) - newParams.output.__inject__('report_vdws', True) - newParams.output.__inject__('separate_worse_clashes', False) - newParams.output.__inject__('group_name', '') - newParams.output.__inject__('add_group_name_master_line', False) - newParams.output.__inject__('add_group_line', False) # Not default - newParams.output.__inject__('add_kinemage_keyword', False) - newParams.output.__inject__('add_lens_keyword', False) - newParams.output.__inject__('color_by_na_base', False) - newParams.output.__inject__('color_by_gap', True) - newParams.output.__inject__('group_label', '') - newParams.output.__inject__('bin_gaps', False) - newParams.output.__inject__('merge_contacts', True) - newParams.output.__inject__('only_report_bad_clashes', False) - newParams.output.__inject__('atoms_are_masters', False) - newParams.output.__inject__('default_point_color', 'gray') - newParams.output.__inject__('compute_scores', True) - newParams.output.__inject__('altid_as_pointmaster', True) - return newParams + parser = cli_parser.CCTBXParser(program_class=probe2.Program, logger=null_out()) + args = [ + "source_selection='{}'".format(source_selection), + "target_selection='{}'".format(target_selection), + "use_neutron_distances={}".format(self.params.use_neutron_distances), + "approach=both", + "excluded_bond_chain_length={}".format(self._bondedNeighborDepth), + "minimum_water_hydrogen_occupancy=0.66", + "maximum_water_hydrogen_b=40.0", + "minimum_occupancy=0.01", + "output.filename='{}'".format(temp_output_file_name), + "ignore_lack_of_explicit_hydrogens=True", + "output.add_group_line=False" + ] + args.extend(extraArgs) + parser.parse_args(args) + + return parser # ------------------------------------------------------------------------------ @@ -1054,11 +1031,8 @@ def _ReinterpretModel(self, make_restraints=True): # :param make_restraints: Should we compute restraints during the interpretation? self.model.get_hierarchy().sort_atoms_in_place() self.model.get_hierarchy().atoms().reset_serial() - p = mmtbx.model.manager.get_default_pdb_interpretation_params() - p.pdb_interpretation.allow_polymer_cross_special_position=True - p.pdb_interpretation.clash_guard.nonbonded_distance_threshold=None - p.pdb_interpretation.use_neutron_distances = self.params.use_neutron_distances - p.pdb_interpretation.proceed_with_excessive_length_bonds=True + + p = reduce_hydrogen.make_interpretation_parameters(self.params.use_neutron_distances) p.pdb_interpretation.disable_uc_volume_vs_n_atoms_check=True # We need to turn this on because without it 1zz0.txt kept flipping the ring # in A TYR 214 every time we re-interpreted. The original interpretation done @@ -1297,16 +1271,18 @@ def run(self): # filled in with values that we want for our summaries. source = [ m ] tempName = tempfile.mktemp() - newParams = self._MakeProbePhil(source, tempName) - newParams.approach = 'once' # Reduce2/Reduce only check Mover atom to other - newParams.output.format = 'raw' - newParams.output.contact_summary = True - newParams.output.condensed = True - newParams.output.count_dots = True + extraArgs = [ + "approach=once", + "output.format=raw", + "output.contact_summary=True", + "output.condensed=True", + "output.count_dots=True" + ] + probeParser = self._MakeProbePhilParser(source, tempName, extraArgs) # Run Probe2 - p2 = probe2.Program(self.data_manager, newParams, master_phil=probe2.master_phil_str, - logger=self.logger) + p2 = probe2.Program(self.data_manager, probeParser.working_phil.extract(), + master_phil=probeParser.master_phil, logger=self.logger) p2.overrideModel(self.model) dots, output = p2.run() @@ -1335,16 +1311,18 @@ def run(self): # Make the Probe2 Phil parameters, then overwrite the ones that were # filled in with values that we want for our summaries. tempName = tempfile.mktemp() - newParams = self._MakeProbePhil(source, tempName) - newParams.approach = 'once' # Reduce2/Reduce only check Mover atom to other - newParams.output.format = 'raw' - newParams.output.contact_summary = True - newParams.output.condensed = True - newParams.output.count_dots = True + extraArgs = [ + "approach=once", + "output.format=raw", + "output.contact_summary=True", + "output.condensed=True", + "output.count_dots=True" + ] + probeParser = self._MakeProbePhilParser(source, tempName, extraArgs) # Run Probe2 - p2 = probe2.Program(dm, newParams, master_phil=probe2.master_phil_str, - logger=self.logger) + p2 = probe2.Program(self.data_manager, probeParser.working_phil.extract(), + master_phil=probeParser.master_phil, logger=self.logger) p2.overrideModel(dm.get_model(self.params.comparison_file)) dots, output = p2.run() @@ -1507,12 +1485,13 @@ def run(self): # Specify a temporary file for the output of Probe2, which we'll # delete after running. tempName = tempfile.mktemp() - newParams = self._MakeProbePhil(amides, tempName) + probeParser = self._MakeProbePhilParser(amides, tempName) # Run the program and append its Kinemage output to ours, deleting # the temporary file that it produced. - p2 = probe2.Program(self.data_manager, newParams, master_phil=probe2.master_phil_str, - logger=self.logger) + p2 = probe2.Program(self.data_manager, probeParser.working_phil.extract(), + master_phil=probeParser.master_phil, logger=self.logger) + p2.overrideModel(self.model) dots, kinString = p2.run() flipkinText += kinString @@ -1628,12 +1607,12 @@ def run(self): # Specify a temporary file for the output of Probe2, which we'll # delete after running. tempName = tempfile.mktemp() - newParams = self._MakeProbePhil(hists, tempName) + probeParser = self._MakeProbePhilParser(hists, tempName) # Run the program and append its Kinemage output to ours, deleting # the temporary file that it produced. - p2 = probe2.Program(self.data_manager, newParams, master_phil=probe2.master_phil_str, - logger=self.logger) + p2 = probe2.Program(self.data_manager, probeParser.working_phil.extract(), + master_phil=probeParser.master_phil, logger=self.logger) p2.overrideModel(self.model) dots, kinString = p2.run() flipkinText += kinString From f5648c4b4f59acf6312bf4f1dd730226baea9d9f Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 4 Apr 2024 12:07:54 -0700 Subject: [PATCH 292/748] Hydrogenate: keep track of runtime. Cleanup. --- mmtbx/hydrogens/reduce_hydrogen.py | 153 +++++++++++++---------------- mmtbx/programs/hydrogenate.py | 12 ++- 2 files changed, 79 insertions(+), 86 deletions(-) diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index 1c60c9b8b9..8965c653da 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -15,7 +15,7 @@ ext = bp.import_ext("cctbx_geometry_restraints_ext") get_class = iotbx.pdb.common_residue_names_get_class # For development -print_time = False +save_time = True # ============================================================================== @@ -98,6 +98,8 @@ def get_h_restraints(resname, strict=True): period='1')) return comp_comp_id +# ============================================================================== + def mon_lib_query(residue, mon_lib_srv, construct_h_restraints=True): # if get_class(residue.resname) in ['common_rna_dna']: # md = get_h_restraints(residue.resname) @@ -112,10 +114,14 @@ def mon_lib_query(residue, mon_lib_srv, construct_h_restraints=True): return md # ============================================================================== -def make_interpretation_parameters(use_neutron_distances): - # Fill in the interpretation parameters we want to use. We do this in a - # function so that other programs (reduce2) can use the same parameters. + +def get_reduce_pdb_interpretation_params(use_neutron_distances): + ''' + Create pdb_interpretation parameter scope. + Do this in a function so other programs (reduce2) can use the same parameters + ''' p = mmtbx.model.manager.get_default_pdb_interpretation_params() + #p.pdb_interpretation.restraints_library.cdl=False # XXX this triggers a bug !=360 p.pdb_interpretation.clash_guard.nonbonded_distance_threshold=None p.pdb_interpretation.use_neutron_distances = use_neutron_distances p.pdb_interpretation.proceed_with_excessive_length_bonds=True @@ -123,6 +129,7 @@ def make_interpretation_parameters(use_neutron_distances): #p.pdb_interpretation.automatic_linking.link_metals = True p.pdb_interpretation.automatic_linking.link_residues = True p.pdb_interpretation.automatic_linking.exclude_hydrogens_from_bonding_decisions = True + # return p # ============================================================================== @@ -154,7 +161,8 @@ def __init__(self, exclude_water = True, stop_for_unknowns = False, keep_existing_H = False, - validate_e = False): + validate_e = False, + print_time = False): self.model = model self.use_neutron_distances = use_neutron_distances @@ -164,6 +172,7 @@ def __init__(self, self.stop_for_unknowns = stop_for_unknowns self.keep_existing_H = keep_existing_H self.validate_e = validate_e + self.print_time = print_time # self.no_H_placed_mlq = list() self.site_labels_disulfides = list() @@ -187,55 +196,47 @@ def run(self): if (cs is None) or (cs.unit_cell() is None): self.model = shift_and_box_model(model = self.model) model_has_bogus_cs = True + #self.model.add_crystal_symmetry_if_necessary() # Remove existing H if requested + # ------------------------------ self.n_H_initial = self.model.get_hd_selection().count(True) if not self.keep_existing_H: self.model = self.model.select(~self.model.get_hd_selection()) + # Add missing H atoms and place them at bogus position + # ---------------------------------------------------- t0 = time.time() - # Add H atoms and place them at center of coordinates pdb_hierarchy = self.add_missing_H_atoms_at_bogus_position() - if print_time: + if self.print_time: print("add_missing_H_atoms_at_bogus_position:", round(time.time()-t0, 2)) - + self.time_add_missing_H = round(time.time()-t0, 2) + # DEBUG #print(pdb_hierarchy.composition().n_hd) + #f = open("intermediate1.pdb","w") + #f.write(self.model.model_as_pdb()) -# f = open("intermediate1.pdb","w") -# f.write(self.model.model_as_pdb()) - - # place N-terminal propeller hydrogens - # - # FYI PRO is not placed optimally according to the restraints with this routine - # - if self.n_terminal_charge != 'no_charge': - for m in pdb_hierarchy.models(): - for chain in m.chains(): - rgs = chain.residue_groups()[0] - # by default, place NH3 only at residue with resseq 1 - if (self.n_terminal_charge == 'residue_one' and rgs.resseq_as_int() != 1): - continue - elif (self.n_terminal_charge == 'first_in_chain'): - pass - for ag in rgs.atom_groups(): - if (get_class(name=ag.resname) in - ['common_amino_acid', 'modified_amino_acid', 'd_amino_acid']): - if ag.get_atom('H'): - ag.remove_atom(ag.get_atom('H')) - #TODO this places NH3 at #1 even if there is a non-standard residue - rc = add_n_terminal_hydrogens_to_residue_group(rgs) - # rc is always empty list? + # Place N-terminal propeller hydrogens + # TODO double check N-terminal position for PRO residues + # ------------------------------------ + if self.n_terminal_charge in ['residue_one', 'first_in_chain']: + t0 = time.time() + self.place_n_terminal_propeller(pdb_hierarchy = pdb_hierarchy) + if self.print_time: + print('Add N-terminal propeller', round(time.time()-t0, 2)) pdb_hierarchy.sort_atoms_in_place() pdb_hierarchy.atoms().reset_serial() -# f = open("intermediate2.pdb","w") -# f.write(self.model.model_as_pdb()) - p = make_interpretation_parameters(self.use_neutron_distances) + # DEBUG + #f = open("intermediate2.pdb","w") + #f.write(self.model.model_as_pdb()) - t0 = time.time() - #p.pdb_interpretation.restraints_library.cdl=False # XXX this triggers a bug !=360 + # Make new model obj and get restraints manager + # --------------------------------------------- + p = get_reduce_pdb_interpretation_params(self.use_neutron_distances) ro = self.model.get_restraint_objects() + t0 = time.time() self.model = mmtbx.model.manager( model_input = None, pdb_hierarchy = pdb_hierarchy, @@ -245,7 +246,7 @@ def run(self): log = null_out()) self.model.process(pdb_interpretation_params=p, make_restraints=True) - if print_time: + if self.print_time: print("get new model obj and grm:", round(time.time()-t0, 2)) #f = open("intermediate3.pdb","w") @@ -256,8 +257,9 @@ def run(self): if sel_h.count(True) == 0: return - # get rid of isolated H atoms. - #For example when heavy atom is missing, H needs not to be placed + # Remove isolated H atoms + # ----------------------- + # (when heavy atom is missing, H needs not to be placed) sel_isolated = self.model.isolated_atoms_selection() self.sel_lone_H = sel_h & sel_isolated if not self.sel_lone_H.all_eq(False): @@ -277,7 +279,7 @@ def run(self): for atom in self.model.get_hierarchy().atoms().select(sel_h_not_in_para)] # self.model = self.model.select(~sel_h_not_in_para) - if print_time: + if self.print_time: print("set up riding H manager and some cleanup:", round(time.time()-t0, 2)) # f = open("intermediate4.pdb","w") @@ -286,7 +288,7 @@ def run(self): if self.validate_e: t0 = time.time() self.validate_electrons() - if print_time: + if self.print_time: print("validate electrons:", round(time.time()-t0, 2)) t0 = time.time() @@ -294,50 +296,14 @@ def run(self): self.model.reset_adp_for_hydrogens(scale = self.adp_scale) self.model.reset_occupancy_for_hydrogens_simple() self.model.idealize_h_riding() - if print_time: + if self.print_time: print("reset adp, occ; idealize:", round(time.time()-t0, 2)) t0 = time.time() self.exclude_H_on_links() - if print_time: + if self.print_time: print("all links:", round(time.time()-t0, 2)) - # place N-terminal propeller hydrogens -# if self.n_terminal_charge != 'no_charge': -# hierarchy = self.model.get_hierarchy() -# for m in hierarchy.models(): -# for chain in m.chains(): -# rgs = chain.residue_groups()[0] -# # by default, place NH3 only at residue with resseq 1 -# if (self.n_terminal_charge == 'residue_one' and rgs.resseq_as_int() != 1): -# continue -# elif (self.n_terminal_charge == 'first_in_chain'): -# pass -# add_charge = True -# for ag in rgs.atom_groups(): -# if (get_class(name=ag.resname) in -# ['common_amino_acid', 'modified_amino_acid', 'd_amino_acid']): -# if ag.get_atom('N'): -# N = ag.get_atom('N') -# if N.i_seq in self.exclusion_iseqs: -# add_charge = False -# if ag.get_atom('H'): -# H = ag.get_atom('H') -# ag.remove_atom(H) -# H_label = H.id_str().replace('pdb=','').replace('"','') -# if H_label in self.site_labels_no_para: -# self.site_labels_no_para.remove(H_label) -# if add_charge: -# rc = add_n_terminal_hydrogens_to_residue_group(rgs) -# hierarchy.sort_atoms_in_place() -# hierarchy.atoms().reset_serial() -# self.model = mmtbx.model.manager( -# model_input = None, -# pdb_hierarchy = hierarchy, -# stop_for_unknowns = self.stop_for_unknowns, -# crystal_symmetry = self.model.crystal_symmetry(), -# restraint_objects = ro, -# log = null_out()) # TODO: this should be ideally done *after* reduce optimization if not self.exclude_water: @@ -345,10 +311,33 @@ def run(self): self.n_H_final = self.model.get_hd_selection().count(True) -# ------------------------------------------------------------------------------ + # ---------------------------------------------------------------------------- + + def place_n_terminal_propeller(self, pdb_hierarchy): + ''' + Place NH3 at residue #1 or at first residue in chain + Changes hierarchy in place + ''' + for m in pdb_hierarchy.models(): + for chain in m.chains(): + rgs = chain.residue_groups()[0] + # by default, place NH3 only at residue with resseq 1 + if (self.n_terminal_charge == 'residue_one' and rgs.resseq_as_int() != 1): + continue + elif (self.n_terminal_charge == 'first_in_chain'): + pass + for ag in rgs.atom_groups(): + if (get_class(name=ag.resname) in + ['common_amino_acid', 'modified_amino_acid', 'd_amino_acid']): + if ag.get_atom('H'): + ag.remove_atom(ag.get_atom('H')) + rc = add_n_terminal_hydrogens_to_residue_group(rgs) # rc is always empty list? + + # ---------------------------------------------------------------------------- def add_missing_H_atoms_at_bogus_position(self): - '''Add missing H atoms at bogus positions to the pdb_hierarchy + ''' + Add missing H atoms at bogus positions to the pdb_hierarchy This procedure changes the hierarchy in place. All H atoms are placed at center of coordinates + (0.5, 0.5, 0.5) diff --git a/mmtbx/programs/hydrogenate.py b/mmtbx/programs/hydrogenate.py index d60df48116..fb5b37da47 100644 --- a/mmtbx/programs/hydrogenate.py +++ b/mmtbx/programs/hydrogenate.py @@ -25,6 +25,9 @@ add_d_to_water = False .type = bool +print_time = False + .type = bool + output .style = menu_item auto_align { @@ -63,9 +66,10 @@ def run(self): # make_sub_header('Add H atoms', out=self.logger) reduce_add_h_obj = reduce_hydrogen.place_hydrogens( - model = self.model, + model = self.model, use_neutron_distances = self.params.use_neutron_distances, - n_terminal_charge = self.params.n_terminal_charge) + n_terminal_charge = self.params.n_terminal_charge, + print_time = self.params.print_time) #import line_profiler #lp = line_profiler.LineProfiler(reduce_add_h_obj.run) #lp.enable() @@ -75,8 +79,8 @@ def run(self): self.model = reduce_add_h_obj.get_model() reduce_add_h_obj.show(log = self.logger) # - make_sub_header('Optimize H atoms', out=self.logger) - self.model = reduce_hydrogen.optimize(model=self.model) + #make_sub_header('Optimize H atoms', out=self.logger) + #self.model = reduce_hydrogen.optimize(model=self.model) # if self.params.add_h_to_water: self.model.add_hydrogens(1., occupancy=1.) From eea8cbd4ffdf865b1f5d8b9f61ef2c83300ed3ec Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 4 Apr 2024 13:27:04 -0700 Subject: [PATCH 293/748] Reduce2: propagate function name change. --- mmtbx/hydrogens/reduce_hydrogen.py | 36 ++++++++++++++++++++---------- mmtbx/programs/reduce2.py | 3 ++- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index 8965c653da..10daffd825 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -252,26 +252,36 @@ def run(self): #f = open("intermediate3.pdb","w") #f.write(self.model.model_as_pdb()) - # Only keep H that have been parameterized in riding H procedure + # Return if no H have been placed sel_h = self.model.get_hd_selection() - if sel_h.count(True) == 0: - return + if sel_h.count(True) == 0: return # Remove isolated H atoms # ----------------------- # (when heavy atom is missing, H needs not to be placed) + t0 = time.time() sel_isolated = self.model.isolated_atoms_selection() self.sel_lone_H = sel_h & sel_isolated if not self.sel_lone_H.all_eq(False): self.model = self.model.select(~self.sel_lone_H) + if self.print_time: + print("Remove isolated H:", round(time.time()-t0, 2)) - t0 = time.time() - # get riding H manager --> parameterize all H atoms sel_h = self.model.get_hd_selection() + + # Setup riding H manager + # ---------------------- + t0 = time.time() self.model.setup_riding_h_manager(use_ideal_dihedral = True) riding_h_manager = self.model.riding_h_manager if riding_h_manager is None: return + if self.print_time: + print("Setup Riding manager:", round(time.time()-t0, 2)) + + # Remove H that could not be parameterized + # ---------------------------------------- + t0 = time.time() sel_h_in_para = flex.bool( [bool(x) for x in riding_h_manager.h_parameterization]) sel_h_not_in_para = sel_h_in_para.exclusive_or(sel_h) @@ -280,19 +290,21 @@ def run(self): # self.model = self.model.select(~sel_h_not_in_para) if self.print_time: - print("set up riding H manager and some cleanup:", round(time.time()-t0, 2)) + print("Remove H that were not parameterized:", round(time.time()-t0, 2)) # f = open("intermediate4.pdb","w") # f.write(model.model_as_pdb()) - if self.validate_e: - t0 = time.time() - self.validate_electrons() - if self.print_time: - print("validate electrons:", round(time.time()-t0, 2)) +# to be removed; was for curiosity only +# if self.validate_e: +# t0 = time.time() +# self.validate_electrons() +# if self.print_time: +# print("validate electrons:", round(time.time()-t0, 2)) - t0 = time.time() # Reset occupancies, ADPs and idealize H atom positions + # ----------------------------------------------------- + t0 = time.time() self.model.reset_adp_for_hydrogens(scale = self.adp_scale) self.model.reset_occupancy_for_hydrogens_simple() self.model.idealize_h_riding() diff --git a/mmtbx/programs/reduce2.py b/mmtbx/programs/reduce2.py index bbef8d2480..504418f226 100644 --- a/mmtbx/programs/reduce2.py +++ b/mmtbx/programs/reduce2.py @@ -1032,7 +1032,8 @@ def _ReinterpretModel(self, make_restraints=True): self.model.get_hierarchy().sort_atoms_in_place() self.model.get_hierarchy().atoms().reset_serial() - p = reduce_hydrogen.make_interpretation_parameters(self.params.use_neutron_distances) + p = reduce_hydrogen.get_reduce_pdb_interpretation_params( + self.params.use_neutron_distances) p.pdb_interpretation.disable_uc_volume_vs_n_atoms_check=True # We need to turn this on because without it 1zz0.txt kept flipping the ring # in A TYR 214 every time we re-interpreted. The original interpretation done From adad2c7e7650dcdbffa81cc25c30f12ad6e720cd Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Thu, 4 Apr 2024 11:45:20 -0700 Subject: [PATCH 294/748] Clean clutter --- cctbx/geometry_restraints/__init__.py | 4 ++-- mmtbx/command_line/holton_geometry_validation.py | 2 -- mmtbx/programs/holton_geometry_validation.py | 1 - mmtbx/regression/tst_holton_geometry_validation.py | 1 - mmtbx/validation/holton_geometry_validation.py | 1 + 5 files changed, 3 insertions(+), 6 deletions(-) diff --git a/cctbx/geometry_restraints/__init__.py b/cctbx/geometry_restraints/__init__.py index 808dde52f2..742246b86a 100644 --- a/cctbx/geometry_restraints/__init__.py +++ b/cctbx/geometry_restraints/__init__.py @@ -507,7 +507,7 @@ def _bond_show_sorted_impl(self, sigma = sigma, residual = residual, ideal = distance_ideal, - model = distance_model,) + model = distance_model,) result.value_list.append(value) @@ -1172,7 +1172,7 @@ def suppress(): sigma = None, residual = None, ideal = vdw_distance, - model = delta,) + model = delta,) result.value_list.append(value) if (n_not_shown != 0): diff --git a/mmtbx/command_line/holton_geometry_validation.py b/mmtbx/command_line/holton_geometry_validation.py index 8ceeb61d13..a5f82b6666 100644 --- a/mmtbx/command_line/holton_geometry_validation.py +++ b/mmtbx/command_line/holton_geometry_validation.py @@ -3,8 +3,6 @@ # LIBTBX_SET_DISPATCHER_NAME mmtbx.holton_geometry_validation # LIBTBX_PRE_DISPATCHER_INCLUDE_SH export PHENIX_GUI_ENVIRONMENT=1 -import sys - from mmtbx.programs import holton_geometry_validation from iotbx.cli_parser import run_program diff --git a/mmtbx/programs/holton_geometry_validation.py b/mmtbx/programs/holton_geometry_validation.py index 2a2cf734e3..759ed465e1 100644 --- a/mmtbx/programs/holton_geometry_validation.py +++ b/mmtbx/programs/holton_geometry_validation.py @@ -10,7 +10,6 @@ from mmtbx.validation.holton_geometry_validation import \ holton_geometry_validation from libtbx.program_template import ProgramTemplate -from datetime import datetime try: from phenix.program_template import ProgramTemplate diff --git a/mmtbx/regression/tst_holton_geometry_validation.py b/mmtbx/regression/tst_holton_geometry_validation.py index 07da06b48c..84d440241d 100644 --- a/mmtbx/regression/tst_holton_geometry_validation.py +++ b/mmtbx/regression/tst_holton_geometry_validation.py @@ -1,5 +1,4 @@ from __future__ import absolute_import, division, print_function -from scitbx.array_family import flex import time from mmtbx.programs import holton_geometry_validation diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index d55640238f..b19a5912a1 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import, division, print_function from libtbx.utils import null_out, Sorry from libtbx import group_args from cctbx.geometry_restraints.linking_class import linking_class From ab150dae4a89641185ae470777446c90cf3fed11 Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 4 Apr 2024 14:50:39 -0600 Subject: [PATCH 295/748] Fix clash corrections --- .../validation/holton_geometry_validation.py | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index b19a5912a1..9016dd331b 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -66,10 +66,10 @@ def holton_geometry_validation(dm = None, model = None, get_individual_residue_scores = False, round_numbers = True, - worst_clash_is_one_plus_worst_clash = True, + worst_clash_is_one_plus_n_times_worst_clash = True, + clash_energy_add_n = True, minimum_nonbond_score_to_be_worst = -0.1, minimum_nonbond_score_to_be_included_in_average = 0, - clash_added_energy = 1, ignore_cis_peptides = True, ignore_h_except_in_nonbond = True, ignore_arg_h_nonbond = True, @@ -359,9 +359,10 @@ def analyze_geometry_values(info): # Some special cases allowed in choosing worst value - if info.worst_clash_is_one_plus_worst_clash and \ + if info.worst_clash_is_one_plus_n_times_worst_clash and \ result.name == 'CLASH': # Special case - result.worst_residual = abs(1 + worst_value.residual) + result.worst_residual = abs( + 1 + len(result.value_list) * worst_value.residual) elif info.minimum_nonbond_score_to_be_worst is not None and \ result.name == 'NONBOND' and ( @@ -394,11 +395,14 @@ def analyze_geometry_values(info): delta = energy**0.5 result.pnna = softPnna(delta, result.n, info.softPnna_params) + energy = filtered_energy(energy) + # Special case for CLASH - if result.name == "CLASH" and info.clash_added_energy is not None: - energy += info.clash_added_energy + if result.name == "CLASH" and info.clash_energy_add_n: + energy += result.n + + result.energy = result.pnna * energy - result.energy = filtered_energy(result.pnna * energy) sum_energy += result.energy # Repeat using mean instead of worst, multiplying mean energy * Chisq @@ -406,12 +410,14 @@ def analyze_geometry_values(info): ssd = result.mean_residual * result.n result.chisq = chisq(ssd, result.n) + energy_mean = filtered_energy(energy_mean) + # Special case for CLASH - if result.name == "CLASH" and info.clash_added_energy is not None: - energy_mean += info.clash_added_energy + if result.name == "CLASH" and info.clash_energy_add_n: + energy_mean += result.n + + result.energy_using_mean = result.chisq * energy_mean - result.energy_using_mean = filtered_energy( - result.chisq * energy_mean) sum_energy += result.energy_using_mean info.sum_energy = sum_energy @@ -787,7 +793,7 @@ def filtered_energy(energy): elif energy <= 10: return energy else: - return 10 + math.log(energy) - math.log(10) + return 10 + math.log(energy/10) def softPnna(delta, n, params = None): From 0a80f49a85f194128c84203c0bbd68b276518d9c Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 4 Apr 2024 14:18:35 -0700 Subject: [PATCH 296/748] Hydrogenate: test timings (prevent further slow down during development) --- mmtbx/hydrogens/reduce_hydrogen.py | 52 +- mmtbx/hydrogens/tst_add_hydrogen_time.py | 2605 ++++++++++++++++++++++ 2 files changed, 2651 insertions(+), 6 deletions(-) create mode 100644 mmtbx/hydrogens/tst_add_hydrogen_time.py diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index 10daffd825..fdca67f31a 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -182,21 +182,36 @@ def __init__(self, self.n_H_initial = 0 self.n_H_final = 0 + if self.print_time: + self.time_rebox_model = 0 + self.time_add_missing_H = 0 + self.time_terminal_propeller = 0 + self.time_make_grm = 0 + self.time_remove_isolated = 0 + self.time_riding_manager = 0 + self.time_remove_H_nopara = 0 + self.time_reset_idealize = 0 + self.time_remove_H_on_links = 0 + # ------------------------------------------------------------------------------ def run(self): ''' Function that places H atoms ''' - model_has_bogus_cs = False - # TODO temporary fix until the code is moved to model class - # check if box cussion of 5 A is enough to prevent symm contacts + # Create symmetry if necessary + # ------------------------------ + model_has_bogus_cs = False + t0 = time.time() cs = self.model.crystal_symmetry() if (cs is None) or (cs.unit_cell() is None): self.model = shift_and_box_model(model = self.model) model_has_bogus_cs = True - #self.model.add_crystal_symmetry_if_necessary() + #self.model.add_crystal_symmetry_if_necessary() # this is slower than shift_and_box_model!!!! + if self.print_time: + print("Rebox model:", round(time.time()-t0, 2)) + self.time_rebox_model = round(time.time()-t0, 2) # Remove existing H if requested # ------------------------------ @@ -224,6 +239,7 @@ def run(self): self.place_n_terminal_propeller(pdb_hierarchy = pdb_hierarchy) if self.print_time: print('Add N-terminal propeller', round(time.time()-t0, 2)) + self.time_terminal_propeller = round(time.time()-t0, 2) pdb_hierarchy.sort_atoms_in_place() pdb_hierarchy.atoms().reset_serial() @@ -248,6 +264,7 @@ def run(self): make_restraints=True) if self.print_time: print("get new model obj and grm:", round(time.time()-t0, 2)) + self.time_make_grm = round(time.time()-t0, 2) #f = open("intermediate3.pdb","w") #f.write(self.model.model_as_pdb()) @@ -266,6 +283,7 @@ def run(self): self.model = self.model.select(~self.sel_lone_H) if self.print_time: print("Remove isolated H:", round(time.time()-t0, 2)) + self.time_remove_isolated = round(time.time()-t0, 2) sel_h = self.model.get_hd_selection() @@ -278,6 +296,7 @@ def run(self): return if self.print_time: print("Setup Riding manager:", round(time.time()-t0, 2)) + self.time_riding_manager = round(time.time()-t0, 2) # Remove H that could not be parameterized # ---------------------------------------- @@ -291,6 +310,7 @@ def run(self): self.model = self.model.select(~sel_h_not_in_para) if self.print_time: print("Remove H that were not parameterized:", round(time.time()-t0, 2)) + self.time_remove_H_nopara = round(time.time()-t0, 2) # f = open("intermediate4.pdb","w") # f.write(model.model_as_pdb()) @@ -309,12 +329,16 @@ def run(self): self.model.reset_occupancy_for_hydrogens_simple() self.model.idealize_h_riding() if self.print_time: - print("reset adp, occ; idealize:", round(time.time()-t0, 2)) + print("Reset adp, occ; idealize H positions:", round(time.time()-t0, 2)) + self.time_reset_idealize = round(time.time()-t0, 2) + # Remove H atoms that are involved in links (bonds, metal coordination, etc) + # -------------------------------------------------------------------------- t0 = time.time() self.exclude_H_on_links() if self.print_time: - print("all links:", round(time.time()-t0, 2)) + print("Remove H on links:", round(time.time()-t0, 2)) + self.time_remove_H_on_links = round(time.time()-t0, 2) # TODO: this should be ideally done *after* reduce optimization @@ -596,6 +620,8 @@ def show(self, log): def get_model(self): return self.model +# ------------------------------------------------------------------------------ + def get_counts(self): return group_args( number_h_final = self.n_H_final, @@ -603,6 +629,20 @@ def get_counts(self): site_labels_disulfides = self.site_labels_disulfides, site_labels_no_para = self.site_labels_no_para) +# ------------------------------------------------------------------------------ + + def get_times(self): + return group_args( + time_rebox_model = self.time_rebox_model, + time_add_missing_H = self.time_add_missing_H, + time_terminal_propeller = self.time_terminal_propeller, + time_make_grm = self.time_make_grm, + time_remove_isolated = self.time_remove_isolated, + time_riding_manager = self.time_riding_manager, + time_remove_H_nopara = self.time_remove_H_nopara, + time_reset_idealize = self.time_reset_idealize, + time_remove_H_on_links = self.time_remove_H_on_links) + # ============================================================================== # stub for reduce parameters diff --git a/mmtbx/hydrogens/tst_add_hydrogen_time.py b/mmtbx/hydrogens/tst_add_hydrogen_time.py new file mode 100644 index 0000000000..2e7a4bddcc --- /dev/null +++ b/mmtbx/hydrogens/tst_add_hydrogen_time.py @@ -0,0 +1,2605 @@ +from __future__ import absolute_import, division, print_function +import time +import mmtbx.model +import iotbx.pdb +from mmtbx.hydrogens import reduce_hydrogen +from libtbx.utils import null_out + +# ------------------------------------------------------------------------------ + +def run(): + pdb_inp = iotbx.pdb.input(lines=pdb_str.split("\n"), source_info=None) + model = mmtbx.model.manager(model_input = pdb_inp, log = null_out()) + #print(model.get_number_of_atoms()) + model.expand_with_BIOMT_records() + #print(model.get_number_of_atoms()) + + hydro_obj = reduce_hydrogen.place_hydrogens(model = model, print_time=True) + hydro_obj.run() + # + model_h_added = hydro_obj.get_model() + #print(model_h_added.get_number_of_atoms()) + t = hydro_obj.get_times() + assert (t.time_rebox_model < 0.03) + assert (t.time_add_missing_H < 1.45) + assert (t.time_terminal_propeller < 0.01) + assert (t.time_make_grm < 61) + assert (t.time_remove_isolated < 0.15) + assert (t.time_riding_manager < 3) + assert (t.time_remove_H_nopara < 4.2) + assert (t.time_reset_idealize < 2) + assert (t.time_remove_H_on_links < 0.37) + +pdb_str = ''' +REMARK 350 MOLECULE CAN BE GENERATED BY APPLYING BIOMT TRANSFORMATIONS +REMARK 350 BIOMT1 1 1.000000 0.000000 0.000000 0.00000 +REMARK 350 BIOMT2 1 0.000000 1.000000 0.000000 0.00000 +REMARK 350 BIOMT3 1 0.000000 0.000000 1.000000 0.00000 +REMARK 350 BIOMT1 2 0.000000 1.000000 0.000000 0.00000 +REMARK 350 BIOMT2 2 -1.000000 0.000000 0.000000 540.00000 +REMARK 350 BIOMT3 2 0.000000 0.000000 1.000000 -174.60000 +REMARK 350 BIOMT1 3 -0.939693 0.342020 0.000000 431.37157 +REMARK 350 BIOMT2 3 -0.342020 -0.939693 0.000000 616.06245 +REMARK 350 BIOMT3 3 0.000000 0.000000 1.000000 -155.20000 +REMARK 350 BIOMT1 4 -0.642788 -0.766044 0.000000 650.38465 +REMARK 350 BIOMT2 4 0.766044 -0.642788 0.000000 236.72065 +REMARK 350 BIOMT3 4 0.000000 0.000000 1.000000 -135.80000 +REMARK 350 BIOMT1 5 0.500000 -0.866025 0.000000 368.82686 +REMARK 350 BIOMT2 5 0.866025 0.500000 0.000000 -98.82686 +REMARK 350 BIOMT3 5 0.000000 0.000000 1.000000 -116.40000 +REMARK 350 BIOMT1 6 0.984808 0.173648 0.000000 -42.78310 +REMARK 350 BIOMT2 6 -0.173648 0.984808 0.000000 50.98691 +REMARK 350 BIOMT3 6 0.000000 0.000000 1.000000 -97.00000 +REMARK 350 BIOMT1 7 0.173648 0.984808 0.000000 -42.78310 +REMARK 350 BIOMT2 7 -0.984808 0.173648 0.000000 489.01309 +REMARK 350 BIOMT3 7 0.000000 0.000000 1.000000 -77.60000 +REMARK 350 BIOMT1 8 -0.866025 0.500000 0.000000 368.82686 +REMARK 350 BIOMT2 8 -0.500000 -0.866025 0.000000 638.82686 +REMARK 350 BIOMT3 8 0.000000 0.000000 1.000000 -58.20000 +REMARK 350 BIOMT1 9 -0.766044 -0.642788 0.000000 650.38465 +REMARK 350 BIOMT2 9 0.642788 -0.766044 0.000000 303.27935 +REMARK 350 BIOMT3 9 0.000000 0.000000 1.000000 -38.80000 +REMARK 350 BIOMT1 10 0.342020 -0.939693 0.000000 431.37157 +REMARK 350 BIOMT2 10 0.939693 0.342020 0.000000 -76.06245 +REMARK 350 BIOMT3 10 0.000000 0.000000 1.000000 -19.40000 +REMARK 350 BIOMT1 11 0.342020 0.939693 0.000000 -76.06245 +REMARK 350 BIOMT2 11 -0.939693 0.342020 0.000000 431.37157 +REMARK 350 BIOMT3 11 0.000000 0.000000 1.000000 19.40000 +REMARK 350 BIOMT1 12 -0.766044 0.642788 0.000000 303.27935 +REMARK 350 BIOMT2 12 -0.642788 -0.766044 0.000000 650.38465 +REMARK 350 BIOMT3 12 0.000000 0.000000 1.000000 38.80000 +REMARK 350 BIOMT1 13 -0.866025 -0.500000 0.000000 638.82686 +REMARK 350 BIOMT2 13 0.500000 -0.866025 0.000000 368.82686 +REMARK 350 BIOMT3 13 0.000000 0.000000 1.000000 58.20000 +REMARK 350 BIOMT1 14 0.173648 -0.984808 0.000000 489.01309 +REMARK 350 BIOMT2 14 0.984808 0.173648 0.000000 -42.78310 +REMARK 350 BIOMT3 14 0.000000 0.000000 1.000000 77.60000 +REMARK 350 BIOMT1 15 0.984808 -0.173648 0.000000 50.98691 +REMARK 350 BIOMT2 15 0.173648 0.984808 0.000000 -42.78310 +REMARK 350 BIOMT3 15 0.000000 0.000000 1.000000 97.00000 +REMARK 350 BIOMT1 16 0.500000 0.866025 0.000000 -98.82686 +REMARK 350 BIOMT2 16 -0.866025 0.500000 0.000000 368.82686 +REMARK 350 BIOMT3 16 0.000000 0.000000 1.000000 116.40000 +REMARK 350 BIOMT1 17 -0.642788 0.766044 0.000000 236.72065 +REMARK 350 BIOMT2 17 -0.766044 -0.642788 0.000000 650.38465 +REMARK 350 BIOMT3 17 0.000000 0.000000 1.000000 135.80000 +REMARK 350 BIOMT1 18 -0.939693 -0.342020 0.000000 616.06245 +REMARK 350 BIOMT2 18 0.342020 -0.939693 0.000000 431.37157 +REMARK 350 BIOMT3 18 0.000000 0.000000 1.000000 155.20000 +REMARK 350 BIOMT1 19 0.000000 -1.000000 0.000000 540.00000 +REMARK 350 BIOMT2 19 1.000000 0.000000 0.000000 0.00000 +REMARK 350 BIOMT3 19 0.000000 0.000000 1.000000 174.60000 +REMARK 350 BIOMT1 20 0.939693 -0.342020 0.000000 108.62843 +REMARK 350 BIOMT2 20 0.342020 0.939693 0.000000 -76.06245 +REMARK 350 BIOMT3 20 0.000000 0.000000 1.000000 194.00000 +ATOM 1 N SER A 5 320.275 318.898 273.938 1.00 77.65 N +ATOM 2 CA SER A 5 320.746 319.843 274.942 1.00 77.65 C +ATOM 3 C SER A 5 319.646 320.173 275.945 1.00 77.65 C +ATOM 4 O SER A 5 318.778 320.999 275.670 1.00 77.65 O +ATOM 5 CB SER A 5 321.251 321.125 274.278 1.00 77.65 C +ATOM 6 OG SER A 5 322.385 320.865 273.471 1.00 77.65 O +ATOM 7 N PRO A 6 319.678 319.524 277.104 1.00 78.17 N +ATOM 8 CA PRO A 6 318.681 319.803 278.139 1.00 78.17 C +ATOM 9 C PRO A 6 318.851 321.200 278.718 1.00 78.17 C +ATOM 10 O PRO A 6 319.940 321.772 278.737 1.00 78.17 O +ATOM 11 CB PRO A 6 318.962 318.732 279.198 1.00 78.17 C +ATOM 12 CG PRO A 6 320.410 318.430 279.029 1.00 78.17 C +ATOM 13 CD PRO A 6 320.674 318.536 277.552 1.00 78.17 C +ATOM 14 N THR A 7 317.734 321.746 279.191 1.00 82.30 N +ATOM 15 CA THR A 7 317.740 323.065 279.805 1.00 82.30 C +ATOM 16 C THR A 7 318.419 323.016 281.167 1.00 82.30 C +ATOM 17 O THR A 7 318.330 322.019 281.889 1.00 82.30 O +ATOM 18 CB THR A 7 316.314 323.602 279.945 1.00 82.30 C +ATOM 19 OG1 THR A 7 316.354 324.928 280.487 1.00 82.30 O +ATOM 20 CG2 THR A 7 315.479 322.706 280.849 1.00 82.30 C +ATOM 21 N ILE A 8 319.116 324.092 281.506 1.00 79.33 N +ATOM 22 CA ILE A 8 319.819 324.194 282.777 1.00 79.33 C +ATOM 23 C ILE A 8 319.148 325.262 283.625 1.00 79.33 C +ATOM 24 O ILE A 8 318.757 326.328 283.133 1.00 79.33 O +ATOM 25 CB ILE A 8 321.318 324.488 282.571 1.00 79.33 C +ATOM 26 CG1 ILE A 8 321.517 325.780 281.787 1.00 79.33 C +ATOM 27 CG2 ILE A 8 321.983 323.343 281.841 1.00 79.33 C +ATOM 28 CD1 ILE A 8 322.962 326.162 281.640 1.00 79.33 C +ATOM 29 N ASN A 9 319.002 324.969 284.916 1.00 84.33 N +ATOM 30 CA ASN A 9 318.256 325.826 285.821 1.00 84.33 C +ATOM 31 C ASN A 9 319.105 326.498 286.887 1.00 84.33 C +ATOM 32 O ASN A 9 318.591 327.370 287.596 1.00 84.33 O +ATOM 33 CB ASN A 9 317.146 325.028 286.520 1.00 84.33 C +ATOM 34 CG ASN A 9 316.134 324.466 285.550 1.00 84.33 C +ATOM 35 OD1 ASN A 9 315.775 325.111 284.566 1.00 84.33 O +ATOM 36 ND2 ASN A 9 315.661 323.257 285.825 1.00 84.33 N +ATOM 37 N PHE A 10 320.376 326.128 287.029 1.00 80.50 N +ATOM 38 CA PHE A 10 321.162 326.626 288.147 1.00 80.50 C +ATOM 39 C PHE A 10 322.641 326.450 287.849 1.00 80.50 C +ATOM 40 O PHE A 10 323.081 325.354 287.498 1.00 80.50 O +ATOM 41 CB PHE A 10 320.784 325.891 289.437 1.00 80.50 C +ATOM 42 CG PHE A 10 321.452 326.429 290.663 1.00 80.50 C +ATOM 43 CD1 PHE A 10 320.900 327.490 291.357 1.00 80.50 C +ATOM 44 CD2 PHE A 10 322.620 325.862 291.133 1.00 80.50 C +ATOM 45 CE1 PHE A 10 321.511 327.983 292.487 1.00 80.50 C +ATOM 46 CE2 PHE A 10 323.231 326.349 292.261 1.00 80.50 C +ATOM 47 CZ PHE A 10 322.679 327.411 292.939 1.00 80.50 C +ATOM 48 N ILE A 11 323.398 327.535 287.988 1.00 73.41 N +ATOM 49 CA ILE A 11 324.848 327.511 287.858 1.00 73.41 C +ATOM 50 C ILE A 11 325.440 328.358 288.972 1.00 73.41 C +ATOM 51 O ILE A 11 324.923 329.436 289.283 1.00 73.41 O +ATOM 52 CB ILE A 11 325.320 328.042 286.488 1.00 73.41 C +ATOM 53 CG1 ILE A 11 324.650 327.289 285.342 1.00 73.41 C +ATOM 54 CG2 ILE A 11 326.824 327.915 286.362 1.00 73.41 C +ATOM 55 CD1 ILE A 11 324.978 327.871 283.991 1.00 73.41 C +ATOM 56 N ASN A 12 326.519 327.871 289.580 1.00 73.41 N +ATOM 57 CA ASN A 12 327.281 328.686 290.515 1.00 73.41 C +ATOM 58 C ASN A 12 328.668 328.089 290.692 1.00 73.41 C +ATOM 59 O ASN A 12 328.870 326.886 290.519 1.00 73.41 O +ATOM 60 CB ASN A 12 326.584 328.813 291.875 1.00 73.41 C +ATOM 61 CG ASN A 12 326.292 327.474 292.513 1.00 73.41 C +ATOM 62 OD1 ASN A 12 326.540 326.422 291.926 1.00 73.41 O +ATOM 63 ND2 ASN A 12 325.778 327.506 293.734 1.00 73.41 N +ATOM 64 N PHE A 13 329.617 328.949 291.033 1.00 73.41 N +ATOM 65 CA PHE A 13 330.958 328.532 291.394 1.00 73.41 C +ATOM 66 C PHE A 13 330.976 328.016 292.829 1.00 73.41 C +ATOM 67 O PHE A 13 329.999 328.136 293.568 1.00 73.41 O +ATOM 68 CB PHE A 13 331.938 329.694 291.248 1.00 73.41 C +ATOM 69 CG PHE A 13 332.245 330.051 289.828 1.00 73.41 C +ATOM 70 CD1 PHE A 13 333.449 329.687 289.256 1.00 73.41 C +ATOM 71 CD2 PHE A 13 331.324 330.735 289.057 1.00 73.41 C +ATOM 72 CE1 PHE A 13 333.736 330.013 287.950 1.00 73.41 C +ATOM 73 CE2 PHE A 13 331.604 331.060 287.751 1.00 73.41 C +ATOM 74 CZ PHE A 13 332.811 330.696 287.195 1.00 73.41 C +ATOM 75 N ASN A 14 332.104 327.425 293.215 1.00 78.03 N +ATOM 76 CA ASN A 14 332.301 327.105 294.617 1.00 78.03 C +ATOM 77 C ASN A 14 332.773 328.353 295.359 1.00 78.03 C +ATOM 78 O ASN A 14 332.940 329.430 294.780 1.00 78.03 O +ATOM 79 CB ASN A 14 333.284 325.948 294.781 1.00 78.03 C +ATOM 80 CG ASN A 14 334.697 326.307 294.362 1.00 78.03 C +ATOM 81 OD1 ASN A 14 334.950 327.382 293.825 1.00 78.03 O +ATOM 82 ND2 ASN A 14 335.631 325.402 294.622 1.00 78.03 N +ATOM 83 N GLN A 15 333.007 328.202 296.660 1.00 80.13 N +ATOM 84 CA GLN A 15 333.372 329.351 297.478 1.00 80.13 C +ATOM 85 C GLN A 15 334.763 329.879 297.156 1.00 80.13 C +ATOM 86 O GLN A 15 335.116 330.971 297.610 1.00 80.13 O +ATOM 87 CB GLN A 15 333.264 328.986 298.955 1.00 80.13 C +ATOM 88 CG GLN A 15 331.831 328.810 299.434 1.00 80.13 C +ATOM 89 CD GLN A 15 331.204 327.523 298.941 1.00 80.13 C +ATOM 90 OE1 GLN A 15 331.901 326.614 298.498 1.00 80.13 O +ATOM 91 NE2 GLN A 15 329.881 327.444 299.006 1.00 80.13 N +ATOM 92 N THR A 16 335.558 329.136 296.386 1.00 82.41 N +ATOM 93 CA THR A 16 336.863 329.606 295.941 1.00 82.41 C +ATOM 94 C THR A 16 336.902 329.971 294.464 1.00 82.41 C +ATOM 95 O THR A 16 337.871 330.595 294.025 1.00 82.41 O +ATOM 96 CB THR A 16 337.941 328.553 296.221 1.00 82.41 C +ATOM 97 OG1 THR A 16 337.526 327.287 295.695 1.00 82.41 O +ATOM 98 CG2 THR A 16 338.197 328.432 297.710 1.00 82.41 C +ATOM 99 N GLY A 17 335.882 329.603 293.692 1.00 78.20 N +ATOM 100 CA GLY A 17 335.844 329.949 292.287 1.00 78.20 C +ATOM 101 C GLY A 17 336.651 329.055 291.375 1.00 78.20 C +ATOM 102 O GLY A 17 336.877 329.426 290.217 1.00 78.20 O +ATOM 103 N THR A 18 337.101 327.895 291.854 1.00 77.58 N +ATOM 104 CA THR A 18 337.873 326.977 291.028 1.00 77.58 C +ATOM 105 C THR A 18 337.075 325.768 290.562 1.00 77.58 C +ATOM 106 O THR A 18 337.664 324.832 290.014 1.00 77.58 O +ATOM 107 CB THR A 18 339.113 326.490 291.780 1.00 77.58 C +ATOM 108 OG1 THR A 18 338.709 325.713 292.916 1.00 77.58 O +ATOM 109 CG2 THR A 18 339.949 327.669 292.249 1.00 77.58 C +ATOM 110 N CYS A 19 335.763 325.754 290.777 1.00 73.41 N +ATOM 111 CA CYS A 19 334.913 324.658 290.340 1.00 73.41 C +ATOM 112 C CYS A 19 333.603 325.213 289.806 1.00 73.41 C +ATOM 113 O CYS A 19 333.312 326.404 289.935 1.00 73.41 O +ATOM 114 CB CYS A 19 334.638 323.667 291.477 1.00 73.41 C +ATOM 115 SG CYS A 19 336.118 322.907 292.184 1.00 73.41 S +ATOM 116 N ILE A 20 332.818 324.339 289.185 1.00 73.41 N +ATOM 117 CA ILE A 20 331.510 324.689 288.645 1.00 73.41 C +ATOM 118 C ILE A 20 330.502 323.662 289.130 1.00 73.41 C +ATOM 119 O ILE A 20 330.750 322.454 289.051 1.00 73.41 O +ATOM 120 CB ILE A 20 331.515 324.742 287.107 1.00 73.41 C +ATOM 121 CG1 ILE A 20 332.546 325.744 286.598 1.00 73.41 C +ATOM 122 CG2 ILE A 20 330.134 325.106 286.589 1.00 73.41 C +ATOM 123 CD1 ILE A 20 332.216 327.158 286.938 1.00 73.41 C +ATOM 124 N SER A 21 329.372 324.139 289.631 1.00 75.58 N +ATOM 125 CA SER A 21 328.207 323.303 289.867 1.00 75.58 C +ATOM 126 C SER A 21 327.123 323.706 288.882 1.00 75.58 C +ATOM 127 O SER A 21 327.029 324.874 288.495 1.00 75.58 O +ATOM 128 CB SER A 21 327.699 323.441 291.302 1.00 75.58 C +ATOM 129 OG SER A 21 328.660 322.968 292.229 1.00 75.58 O +ATOM 130 N LEU A 22 326.317 322.739 288.462 1.00 76.98 N +ATOM 131 CA LEU A 22 325.313 323.013 287.450 1.00 76.98 C +ATOM 132 C LEU A 22 324.155 322.045 287.617 1.00 76.98 C +ATOM 133 O LEU A 22 324.357 320.884 287.978 1.00 76.98 O +ATOM 134 CB LEU A 22 325.919 322.909 286.046 1.00 76.98 C +ATOM 135 CG LEU A 22 325.045 323.302 284.858 1.00 76.98 C +ATOM 136 CD1 LEU A 22 325.881 324.015 283.821 1.00 76.98 C +ATOM 137 CD2 LEU A 22 324.405 322.074 284.254 1.00 76.98 C +ATOM 138 N GLY A 23 322.946 322.532 287.354 1.00 82.19 N +ATOM 139 CA GLY A 23 321.763 321.704 287.452 1.00 82.19 C +ATOM 140 C GLY A 23 320.893 321.770 286.216 1.00 82.19 C +ATOM 141 O GLY A 23 320.467 322.854 285.808 1.00 82.19 O +ATOM 142 N THR A 24 320.621 320.619 285.611 1.00 85.29 N +ATOM 143 CA THR A 24 319.785 320.518 284.428 1.00 85.29 C +ATOM 144 C THR A 24 318.381 320.086 284.832 1.00 85.29 C +ATOM 145 O THR A 24 318.065 319.943 286.019 1.00 85.29 O +ATOM 146 CB THR A 24 320.393 319.537 283.426 1.00 85.29 C +ATOM 147 OG1 THR A 24 320.373 318.215 283.981 1.00 85.29 O +ATOM 148 CG2 THR A 24 321.824 319.916 283.109 1.00 85.29 C +ATOM 149 N SER A 25 317.523 319.877 283.833 1.00 88.54 N +ATOM 150 CA SER A 25 316.219 319.286 284.096 1.00 88.54 C +ATOM 151 C SER A 25 316.288 317.768 284.162 1.00 88.54 C +ATOM 152 O SER A 25 315.292 317.128 284.515 1.00 88.54 O +ATOM 153 CB SER A 25 315.215 319.716 283.027 1.00 88.54 C +ATOM 154 OG SER A 25 313.950 319.124 283.256 1.00 88.54 O +ATOM 155 N LYS A 26 317.437 317.182 283.826 1.00 89.87 N +ATOM 156 CA LYS A 26 317.637 315.744 283.897 1.00 89.87 C +ATOM 157 C LYS A 26 318.655 315.318 284.942 1.00 89.87 C +ATOM 158 O LYS A 26 318.723 314.125 285.259 1.00 89.87 O +ATOM 159 CB LYS A 26 318.051 315.198 282.518 1.00 89.87 C +ATOM 160 CG LYS A 26 319.385 315.720 281.981 1.00 89.87 C +ATOM 161 CD LYS A 26 320.571 314.850 282.373 1.00 89.87 C +ATOM 162 CE LYS A 26 321.852 315.352 281.726 1.00 89.87 C +ATOM 163 NZ LYS A 26 323.038 314.538 282.110 1.00 89.87 N +ATOM 164 N GLY A 27 319.442 316.242 285.484 1.00 87.83 N +ATOM 165 CA GLY A 27 320.435 315.880 286.477 1.00 87.83 C +ATOM 166 C GLY A 27 321.346 317.053 286.775 1.00 87.83 C +ATOM 167 O GLY A 27 321.048 318.192 286.416 1.00 87.83 O +ATOM 168 N PHE A 28 322.462 316.751 287.433 1.00 83.20 N +ATOM 169 CA PHE A 28 323.434 317.762 287.813 1.00 83.20 C +ATOM 170 C PHE A 28 324.817 317.341 287.342 1.00 83.20 C +ATOM 171 O PHE A 28 325.087 316.161 287.111 1.00 83.20 O +ATOM 172 CB PHE A 28 323.436 318.003 289.330 1.00 83.20 C +ATOM 173 CG PHE A 28 323.987 316.858 290.132 1.00 83.20 C +ATOM 174 CD1 PHE A 28 325.306 316.862 290.555 1.00 83.20 C +ATOM 175 CD2 PHE A 28 323.184 315.783 290.470 1.00 83.20 C +ATOM 176 CE1 PHE A 28 325.814 315.813 291.294 1.00 83.20 C +ATOM 177 CE2 PHE A 28 323.687 314.732 291.206 1.00 83.20 C +ATOM 178 CZ PHE A 28 325.002 314.747 291.621 1.00 83.20 C +ATOM 179 N LYS A 29 325.691 318.331 287.191 1.00 77.31 N +ATOM 180 CA LYS A 29 327.056 318.104 286.743 1.00 77.31 C +ATOM 181 C LYS A 29 327.999 318.942 287.589 1.00 77.31 C +ATOM 182 O LYS A 29 327.604 319.964 288.153 1.00 77.31 O +ATOM 183 CB LYS A 29 327.228 318.459 285.263 1.00 77.31 C +ATOM 184 CG LYS A 29 326.346 317.665 284.319 1.00 77.31 C +ATOM 185 CD LYS A 29 326.542 318.110 282.881 1.00 77.31 C +ATOM 186 CE LYS A 29 325.669 317.303 281.939 1.00 77.31 C +ATOM 187 NZ LYS A 29 324.228 317.630 282.118 1.00 77.31 N +ATOM 188 N ILE A 30 329.251 318.500 287.678 1.00 73.41 N +ATOM 189 CA ILE A 30 330.285 319.218 288.414 1.00 73.41 C +ATOM 190 C ILE A 30 331.514 319.285 287.518 1.00 73.41 C +ATOM 191 O ILE A 30 331.969 318.256 287.012 1.00 73.41 O +ATOM 192 CB ILE A 30 330.630 318.552 289.751 1.00 73.41 C +ATOM 193 CG1 ILE A 30 329.438 318.619 290.702 1.00 73.41 C +ATOM 194 CG2 ILE A 30 331.835 319.225 290.383 1.00 73.41 C +ATOM 195 CD1 ILE A 30 329.716 318.013 292.045 1.00 73.41 C +ATOM 196 N PHE A 31 332.047 320.482 287.320 1.00 73.41 N +ATOM 197 CA PHE A 31 333.179 320.681 286.437 1.00 73.41 C +ATOM 198 C PHE A 31 334.390 321.165 287.227 1.00 73.41 C +ATOM 199 O PHE A 31 334.380 321.218 288.459 1.00 73.41 O +ATOM 200 CB PHE A 31 332.811 321.658 285.317 1.00 73.41 C +ATOM 201 CG PHE A 31 331.777 321.125 284.367 1.00 73.41 C +ATOM 202 CD1 PHE A 31 330.448 321.046 284.738 1.00 73.41 C +ATOM 203 CD2 PHE A 31 332.142 320.687 283.108 1.00 73.41 C +ATOM 204 CE1 PHE A 31 329.501 320.554 283.867 1.00 73.41 C +ATOM 205 CE2 PHE A 31 331.199 320.190 282.233 1.00 73.41 C +ATOM 206 CZ PHE A 31 329.877 320.121 282.615 1.00 73.41 C +ATOM 207 N ASN A 32 335.455 321.505 286.509 1.00 73.41 N +ATOM 208 CA ASN A 32 336.642 322.118 287.084 1.00 73.41 C +ATOM 209 C ASN A 32 337.062 323.247 286.151 1.00 73.41 C +ATOM 210 O ASN A 32 336.565 323.359 285.028 1.00 73.41 O +ATOM 211 CB ASN A 32 337.743 321.075 287.297 1.00 73.41 C +ATOM 212 CG ASN A 32 338.918 321.615 288.083 1.00 73.41 C +ATOM 213 OD1 ASN A 32 340.064 321.253 287.834 1.00 73.41 O +ATOM 214 ND2 ASN A 32 338.635 322.486 289.040 1.00 73.41 N +ATOM 215 N CYS A 33 337.978 324.100 286.607 1.00 74.73 N +ATOM 216 CA CYS A 33 338.216 325.337 285.872 1.00 74.73 C +ATOM 217 C CYS A 33 339.553 325.376 285.142 1.00 74.73 C +ATOM 218 O CYS A 33 339.580 325.559 283.921 1.00 74.73 O +ATOM 219 CB CYS A 33 338.114 326.534 286.819 1.00 74.73 C +ATOM 220 SG CYS A 33 336.431 326.899 287.362 1.00 74.73 S +ATOM 221 N GLU A 34 340.666 325.213 285.854 1.00 78.81 N +ATOM 222 CA GLU A 34 341.959 325.358 285.190 1.00 78.81 C +ATOM 223 C GLU A 34 342.330 324.130 284.360 1.00 78.81 C +ATOM 224 O GLU A 34 342.532 324.288 283.143 1.00 78.81 O +ATOM 225 CB GLU A 34 343.041 325.719 286.217 1.00 78.81 C +ATOM 226 CG GLU A 34 344.298 326.317 285.612 1.00 78.81 C +ATOM 227 CD GLU A 34 345.255 325.264 285.097 1.00 78.81 C +ATOM 228 OE1 GLU A 34 345.273 324.151 285.662 1.00 78.81 O +ATOM 229 OE2 GLU A 34 345.986 325.548 284.126 1.00 78.81 O +ATOM 230 N PRO A 35 342.448 322.907 284.918 1.00 75.47 N +ATOM 231 CA PRO A 35 342.512 321.728 284.050 1.00 75.47 C +ATOM 232 C PRO A 35 341.116 321.205 283.766 1.00 75.47 C +ATOM 233 O PRO A 35 340.675 320.246 284.405 1.00 75.47 O +ATOM 234 CB PRO A 35 343.346 320.733 284.865 1.00 75.47 C +ATOM 235 CG PRO A 35 343.258 321.216 286.302 1.00 75.47 C +ATOM 236 CD PRO A 35 342.481 322.506 286.333 1.00 75.47 C +ATOM 237 N PHE A 36 340.419 321.836 282.819 1.00 75.47 N +ATOM 238 CA PHE A 36 338.981 321.645 282.669 1.00 75.47 C +ATOM 239 C PHE A 36 338.626 320.171 282.533 1.00 75.47 C +ATOM 240 O PHE A 36 339.291 319.416 281.821 1.00 75.47 O +ATOM 241 CB PHE A 36 338.474 322.418 281.451 1.00 74.25 C +ATOM 242 CG PHE A 36 336.995 322.292 281.230 1.00 74.25 C +ATOM 243 CD1 PHE A 36 336.113 323.144 281.868 1.00 74.25 C +ATOM 244 CD2 PHE A 36 336.485 321.319 280.387 1.00 74.25 C +ATOM 245 CE1 PHE A 36 334.751 323.031 281.668 1.00 75.62 C +ATOM 246 CE2 PHE A 36 335.123 321.200 280.186 1.00 75.62 C +ATOM 247 CZ PHE A 36 334.256 322.058 280.825 1.00 75.62 C +ATOM 248 N GLY A 37 337.571 319.767 283.230 1.00 75.62 N +ATOM 249 CA GLY A 37 337.133 318.387 283.207 1.00 75.62 C +ATOM 250 C GLY A 37 335.795 318.244 283.892 1.00 75.62 C +ATOM 251 O GLY A 37 335.298 319.179 284.529 1.00 75.62 O +ATOM 252 N LYS A 38 335.213 317.054 283.748 1.00 75.62 N +ATOM 253 CA LYS A 38 333.912 316.746 284.338 1.00 75.62 C +ATOM 254 C LYS A 38 334.115 315.754 285.480 1.00 77.01 C +ATOM 255 O LYS A 38 334.259 314.546 285.284 1.00 77.01 O +ATOM 256 CB LYS A 38 332.964 316.204 283.278 1.00 77.01 C +ATOM 257 CG LYS A 38 331.527 316.094 283.725 1.00 77.01 C +ATOM 258 CD LYS A 38 330.648 315.631 282.580 1.00 77.01 C +ATOM 259 CE LYS A 38 329.184 315.652 282.968 1.00 77.01 C +ATOM 260 NZ LYS A 38 328.304 315.146 281.879 1.00 77.01 N +ATOM 261 N PHE A 39 334.135 316.289 286.704 1.00 77.01 N +ATOM 262 CA PHE A 39 334.393 315.452 287.871 1.00 77.01 C +ATOM 263 C PHE A 39 333.257 314.481 288.158 1.00 77.01 C +ATOM 264 O PHE A 39 333.507 313.315 288.481 1.00 77.01 O +ATOM 265 CB PHE A 39 334.655 316.321 289.100 1.00 83.28 C +ATOM 266 CG PHE A 39 336.002 316.976 289.100 1.00 83.28 C +ATOM 267 CD1 PHE A 39 336.980 316.573 288.209 1.00 83.28 C +ATOM 268 CD2 PHE A 39 336.291 317.992 289.992 1.00 83.28 C +ATOM 269 CE1 PHE A 39 338.223 317.172 288.206 1.00 83.28 C +ATOM 270 CE2 PHE A 39 337.532 318.596 289.994 1.00 83.28 C +ATOM 271 CZ PHE A 39 338.500 318.186 289.101 1.00 83.28 C +ATOM 272 N TYR A 40 332.009 314.929 288.053 1.00 83.28 N +ATOM 273 CA TYR A 40 330.903 314.078 288.465 1.00 83.28 C +ATOM 274 C TYR A 40 329.652 314.452 287.688 1.00 83.28 C +ATOM 275 O TYR A 40 329.549 315.545 287.129 1.00 83.28 O +ATOM 276 CB TYR A 40 330.647 314.195 289.969 1.00 83.28 C +ATOM 277 CG TYR A 40 329.765 313.106 290.518 1.00 82.37 C +ATOM 278 CD1 TYR A 40 330.169 311.780 290.477 1.00 82.37 C +ATOM 279 CD2 TYR A 40 328.525 313.395 291.066 1.00 82.37 C +ATOM 280 CE1 TYR A 40 329.372 310.775 290.976 1.00 82.37 C +ATOM 281 CE2 TYR A 40 327.718 312.395 291.570 1.00 82.37 C +ATOM 282 CZ TYR A 40 328.147 311.086 291.521 1.00 82.37 C +ATOM 283 OH TYR A 40 327.356 310.077 292.015 1.00 86.06 O +ATOM 284 N SER A 41 328.697 313.523 287.668 1.00 86.06 N +ATOM 285 CA SER A 41 327.417 313.737 287.010 1.00 86.06 C +ATOM 286 C SER A 41 326.470 312.601 287.366 1.00 86.06 C +ATOM 287 O SER A 41 326.891 311.455 287.530 1.00 86.06 O +ATOM 288 CB SER A 41 327.570 313.826 285.490 1.00 86.06 C +ATOM 289 OG SER A 41 326.312 314.014 284.863 1.00 86.06 O +ATOM 290 N GLU A 42 325.185 312.935 287.471 1.00 86.06 N +ATOM 291 CA GLU A 42 324.132 311.942 287.649 1.00 86.06 C +ATOM 292 C GLU A 42 322.897 312.400 286.891 1.00 92.66 C +ATOM 293 O GLU A 42 322.518 313.572 286.975 1.00 92.66 O +ATOM 294 CB GLU A 42 323.782 311.732 289.126 1.00 92.66 C +ATOM 295 CG GLU A 42 324.870 311.093 289.968 1.00 92.66 C +ATOM 296 CD GLU A 42 324.455 310.933 291.416 1.00 92.66 C +ATOM 297 OE1 GLU A 42 323.370 311.434 291.782 1.00 92.66 O +ATOM 298 OE2 GLU A 42 325.205 310.303 292.189 1.00 92.66 O +ATOM 299 N ASP A 43 322.280 311.482 286.154 1.00 92.66 N +ATOM 300 CA ASP A 43 321.022 311.762 285.466 1.00 94.16 C +ATOM 301 C ASP A 43 319.856 311.240 286.307 1.00 94.16 C +ATOM 302 O ASP A 43 319.140 310.310 285.938 1.00 94.16 O +ATOM 303 CB ASP A 43 321.032 311.148 284.070 1.00 94.16 C +ATOM 304 CG ASP A 43 322.140 311.704 283.198 1.00 94.16 C +ATOM 305 OD1 ASP A 43 322.985 312.463 283.719 1.00 94.16 O +ATOM 306 OD2 ASP A 43 322.165 311.386 281.991 1.00 94.52 O +ATOM 307 N SER A 44 319.679 311.873 287.465 1.00 94.52 N +ATOM 308 CA SER A 44 318.652 311.457 288.415 1.00 94.52 C +ATOM 309 C SER A 44 317.312 312.131 288.126 1.00 94.52 C +ATOM 310 O SER A 44 316.301 311.453 287.916 1.00 98.97 O +ATOM 311 CB SER A 44 319.110 311.759 289.846 1.00 98.97 C +ATOM 312 OG SER A 44 320.379 311.184 290.108 1.00 98.97 O +ATOM 313 N GLY A 45 317.294 313.456 288.114 1.00 98.97 N +ATOM 314 CA GLY A 45 316.063 314.174 287.860 1.00 96.48 C +ATOM 315 C GLY A 45 316.311 315.662 287.783 1.00 96.48 C +ATOM 316 O GLY A 45 317.451 316.117 287.684 1.00 96.48 O +ATOM 317 N GLY A 46 315.219 316.419 287.818 1.00 96.48 N +ATOM 318 CA GLY A 46 315.333 317.866 287.811 1.00 96.48 C +ATOM 319 C GLY A 46 315.928 318.379 289.110 1.00 96.48 C +ATOM 320 O GLY A 46 315.501 318.011 290.204 1.00 96.48 O +ATOM 321 N TYR A 47 316.933 319.242 288.982 1.00 96.48 N +ATOM 322 CA TYR A 47 317.589 319.852 290.126 1.00 96.48 C +ATOM 323 C TYR A 47 317.575 321.365 289.982 1.00 96.48 C +ATOM 324 O TYR A 47 317.949 321.902 288.936 1.00 96.48 O +ATOM 325 CB TYR A 47 319.029 319.356 290.276 1.00 96.48 C +ATOM 326 CG TYR A 47 319.124 317.940 290.787 1.00 93.36 C +ATOM 327 CD1 TYR A 47 318.986 317.661 292.136 1.00 93.36 C +ATOM 328 CD2 TYR A 47 319.359 316.884 289.921 1.00 93.36 C +ATOM 329 CE1 TYR A 47 319.071 316.369 292.610 1.00 93.36 C +ATOM 330 CE2 TYR A 47 319.448 315.588 290.385 1.00 93.36 C +ATOM 331 CZ TYR A 47 319.303 315.336 291.730 1.00 88.81 C +ATOM 332 OH TYR A 47 319.391 314.047 292.199 1.00 88.81 O +ATOM 333 N ALA A 48 317.142 322.047 291.041 1.00 88.81 N +ATOM 334 CA ALA A 48 317.070 323.500 291.053 1.00 88.81 C +ATOM 335 C ALA A 48 318.177 324.151 291.864 1.00 88.81 C +ATOM 336 O ALA A 48 318.545 325.293 291.578 1.00 88.81 O +ATOM 337 CB ALA A 48 315.714 323.958 291.599 1.00 88.81 C +ATOM 338 N ILE A 49 318.707 323.460 292.871 1.00 88.81 N +ATOM 339 CA ILE A 49 319.781 324.004 293.694 1.00 85.51 C +ATOM 340 C ILE A 49 320.879 322.962 293.846 1.00 85.51 C +ATOM 341 O ILE A 49 320.673 321.911 294.463 1.00 85.51 O +ATOM 342 CB ILE A 49 319.263 324.454 295.073 1.00 85.51 C +ATOM 343 CG1 ILE A 49 318.222 325.561 294.921 1.00 85.51 C +ATOM 344 CG2 ILE A 49 320.411 324.933 295.942 1.00 85.51 C +ATOM 345 CD1 ILE A 49 317.422 325.808 296.169 1.00 85.51 C +ATOM 346 N VAL A 50 322.052 323.244 293.285 1.00 85.29 N +ATOM 347 CA VAL A 50 323.225 322.390 293.421 1.00 85.29 C +ATOM 348 C VAL A 50 324.363 323.256 293.939 1.00 85.29 C +ATOM 349 O VAL A 50 325.005 323.978 293.165 1.00 85.29 O +ATOM 350 CB VAL A 50 323.600 321.713 292.094 1.00 85.29 C +ATOM 351 CG1 VAL A 50 324.916 320.965 292.230 1.00 85.29 C +ATOM 352 CG2 VAL A 50 322.494 320.771 291.653 1.00 85.29 C +ATOM 353 N GLU A 51 324.612 323.189 295.244 1.00 85.29 N +ATOM 354 CA GLU A 51 325.624 324.011 295.891 1.00 85.29 C +ATOM 355 C GLU A 51 326.688 323.104 296.487 1.00 85.08 C +ATOM 356 O GLU A 51 326.368 322.059 297.061 1.00 85.08 O +ATOM 357 CB GLU A 51 325.006 324.899 296.976 1.00 85.08 C +ATOM 358 CG GLU A 51 326.021 325.685 297.790 1.00 85.08 C +ATOM 359 CD GLU A 51 326.411 326.991 297.131 1.00 85.08 C +ATOM 360 OE1 GLU A 51 325.645 327.477 296.273 1.00 85.08 O +ATOM 361 OE2 GLU A 51 327.486 327.531 297.467 1.00 85.08 O +ATOM 362 N MET A 52 327.949 323.509 296.354 1.00 85.08 N +ATOM 363 CA MET A 52 329.083 322.707 296.784 1.00 80.47 C +ATOM 364 C MET A 52 329.929 323.502 297.764 1.00 80.47 C +ATOM 365 O MET A 52 329.919 324.737 297.739 1.00 80.47 O +ATOM 366 CB MET A 52 329.936 322.276 295.589 1.00 80.47 C +ATOM 367 CG MET A 52 330.605 323.428 294.862 1.00 80.47 C +ATOM 368 SD MET A 52 331.611 322.870 293.477 1.00 80.47 S +ATOM 369 CE MET A 52 332.985 322.125 294.347 1.00 80.47 C +ATOM 370 N LEU A 53 330.648 322.792 298.627 1.00 80.47 N +ATOM 371 CA LEU A 53 331.587 323.398 299.554 1.00 82.05 C +ATOM 372 C LEU A 53 332.958 323.524 298.880 1.00 82.05 C +ATOM 373 O LEU A 53 333.093 323.364 297.665 1.00 82.05 O +ATOM 374 CB LEU A 53 331.643 322.572 300.842 1.00 82.05 C +ATOM 375 CG LEU A 53 332.316 323.087 302.117 1.00 82.05 C +ATOM 376 CD1 LEU A 53 331.703 324.405 302.541 1.00 82.05 C +ATOM 377 CD2 LEU A 53 332.194 322.058 303.225 1.00 82.05 C +ATOM 378 N PHE A 54 333.984 323.809 299.676 1.00 82.05 N +ATOM 379 CA PHE A 54 335.331 323.923 299.134 1.00 82.05 C +ATOM 380 C PHE A 54 335.822 322.547 298.711 1.00 82.05 C +ATOM 381 O PHE A 54 336.570 321.900 299.448 1.00 82.05 O +ATOM 382 CB PHE A 54 336.285 324.495 300.182 1.00 84.50 C +ATOM 383 CG PHE A 54 335.860 325.810 300.759 1.00 84.50 C +ATOM 384 CD1 PHE A 54 336.411 326.988 300.296 1.00 84.50 C +ATOM 385 CD2 PHE A 54 334.925 325.868 301.776 1.00 84.50 C +ATOM 386 CE1 PHE A 54 336.037 328.200 300.830 1.00 84.50 C +ATOM 387 CE2 PHE A 54 334.544 327.077 302.313 1.00 84.50 C +ATOM 388 CZ PHE A 54 335.101 328.244 301.839 1.00 84.50 C +ATOM 389 N SER A 55 335.428 322.119 297.513 1.00 90.97 N +ATOM 390 CA SER A 55 335.637 320.736 297.059 1.00 90.97 C +ATOM 391 C SER A 55 335.046 319.826 298.137 1.00 90.97 C +ATOM 392 O SER A 55 333.833 319.887 298.380 1.00 90.97 O +ATOM 393 CB SER A 55 337.110 320.518 296.744 1.00 90.97 C +ATOM 394 OG SER A 55 337.553 321.407 295.735 1.00 90.97 O +ATOM 395 N THR A 56 335.838 318.977 298.785 1.00 89.53 N +ATOM 396 CA THR A 56 335.478 318.157 299.942 1.00 89.53 C +ATOM 397 C THR A 56 334.308 317.214 299.680 1.00 89.53 C +ATOM 398 O THR A 56 333.794 316.632 300.642 1.00 89.53 O +ATOM 399 CB THR A 56 335.145 318.987 301.193 1.00 89.53 C +ATOM 400 OG1 THR A 56 334.104 319.922 300.893 1.00 89.53 O +ATOM 401 CG2 THR A 56 336.373 319.731 301.686 1.00 89.53 C +ATOM 402 N SER A 57 333.866 317.047 298.434 1.00 89.53 N +ATOM 403 CA SER A 57 332.877 316.026 298.081 1.00 91.53 C +ATOM 404 C SER A 57 331.586 316.166 298.884 1.00 91.53 C +ATOM 405 O SER A 57 331.000 315.174 299.317 1.00 91.53 O +ATOM 406 CB SER A 57 333.465 314.624 298.257 1.00 91.53 C +ATOM 407 OG SER A 57 332.518 313.626 297.928 1.00 91.53 O +ATOM 408 N LEU A 58 331.131 317.399 299.089 1.00 91.53 N +ATOM 409 CA LEU A 58 329.891 317.659 299.809 1.00 91.53 C +ATOM 410 C LEU A 58 328.986 318.521 298.942 1.00 91.53 C +ATOM 411 O LEU A 58 329.430 319.537 298.400 1.00 91.11 O +ATOM 412 CB LEU A 58 330.163 318.347 301.148 1.00 91.11 C +ATOM 413 CG LEU A 58 328.984 318.389 302.119 1.00 91.11 C +ATOM 414 CD1 LEU A 58 328.591 316.981 302.521 1.00 91.11 C +ATOM 415 CD2 LEU A 58 329.326 319.222 303.341 1.00 91.11 C +ATOM 416 N LEU A 59 327.722 318.119 298.817 1.00 94.71 N +ATOM 417 CA LEU A 59 326.777 318.779 297.930 1.00 94.71 C +ATOM 418 C LEU A 59 325.432 318.961 298.617 1.00 94.71 C +ATOM 419 O LEU A 59 325.062 318.191 299.506 1.00 94.71 O +ATOM 420 CB LEU A 59 326.567 317.981 296.639 1.00 94.71 C +ATOM 421 CG LEU A 59 327.775 317.729 295.744 1.00 94.71 C +ATOM 422 CD1 LEU A 59 327.349 316.926 294.532 1.00 94.71 C +ATOM 423 CD2 LEU A 59 328.406 319.039 295.325 1.00 94.71 C +ATOM 424 N ALA A 60 324.700 319.981 298.179 1.00 97.69 N +ATOM 425 CA ALA A 60 323.311 320.191 298.562 1.00 97.69 C +ATOM 426 C ALA A 60 322.446 320.121 297.313 1.00 97.69 C +ATOM 427 O ALA A 60 322.635 320.908 296.380 1.00 97.69 O +ATOM 428 CB ALA A 60 323.119 321.538 299.255 1.00 97.69 C +ATOM 429 N LEU A 61 321.497 319.189 297.300 1.00 97.69 N +ATOM 430 CA LEU A 61 320.692 318.914 296.117 1.00 97.69 C +ATOM 431 C LEU A 61 319.227 319.146 296.445 1.00103.43 C +ATOM 432 O LEU A 61 318.701 318.556 297.395 1.00103.43 O +ATOM 433 CB LEU A 61 320.915 317.481 295.625 1.00103.43 C +ATOM 434 CG LEU A 61 321.972 317.265 294.540 1.00103.43 C +ATOM 435 CD1 LEU A 61 323.316 317.853 294.934 1.00104.40 C +ATOM 436 CD2 LEU A 61 322.112 315.785 294.240 1.00104.40 C +ATOM 437 N VAL A 62 318.572 319.993 295.658 1.00104.40 N +ATOM 438 CA VAL A 62 317.155 320.297 295.815 1.00104.40 C +ATOM 439 C VAL A 62 316.450 319.904 294.527 1.00104.40 C +ATOM 440 O VAL A 62 316.854 320.333 293.438 1.00104.40 O +ATOM 441 CB VAL A 62 316.918 321.778 296.135 1.00104.40 C +ATOM 442 CG1 VAL A 62 315.431 322.075 296.183 1.00104.40 C +ATOM 443 CG2 VAL A 62 317.580 322.149 297.450 1.00109.20 C +ATOM 444 N GLY A 63 315.400 319.096 294.648 1.00109.20 N +ATOM 445 CA GLY A 63 314.654 318.685 293.477 1.00109.20 C +ATOM 446 C GLY A 63 313.918 319.841 292.830 1.00109.20 C +ATOM 447 O GLY A 63 313.628 320.862 293.452 1.00108.50 O +ATOM 448 N ILE A 64 313.618 319.666 291.541 1.00108.50 N +ATOM 449 CA ILE A 64 312.927 320.714 290.793 1.00108.50 C +ATOM 450 C ILE A 64 311.503 320.887 291.303 1.00108.50 C +ATOM 451 O ILE A 64 310.929 321.982 291.227 1.00108.50 O +ATOM 452 CB ILE A 64 312.966 320.408 289.283 1.00108.50 C +ATOM 453 CG1 ILE A 64 312.654 321.669 288.473 1.00108.50 C +ATOM 454 CG2 ILE A 64 312.010 319.278 288.924 1.00108.50 C +ATOM 455 CD1 ILE A 64 313.538 322.846 288.809 1.00105.42 C +ATOM 456 N LEU A 75 315.462 318.936 300.825 1.00101.27 N +ATOM 457 CA LEU A 75 316.888 319.172 300.655 1.00101.27 C +ATOM 458 C LEU A 75 317.632 317.897 301.020 1.00101.27 C +ATOM 459 O LEU A 75 317.363 317.294 302.064 1.00101.27 O +ATOM 460 CB LEU A 75 317.373 320.337 301.518 1.00 99.06 C +ATOM 461 CG LEU A 75 318.886 320.487 301.700 1.00 99.06 C +ATOM 462 CD1 LEU A 75 319.544 321.184 300.517 1.00 99.06 C +ATOM 463 CD2 LEU A 75 319.205 321.216 302.994 1.00 99.06 C +ATOM 464 N ARG A 76 318.555 317.485 300.159 1.00 99.06 N +ATOM 465 CA ARG A 76 319.318 316.258 300.346 1.00 99.06 C +ATOM 466 C ARG A 76 320.801 316.581 300.262 1.00 99.06 C +ATOM 467 O ARG A 76 321.231 317.294 299.349 1.00 99.06 O +ATOM 468 CB ARG A 76 318.929 315.213 299.302 1.00 95.74 C +ATOM 469 CG ARG A 76 319.651 313.896 299.448 1.00 95.74 C +ATOM 470 CD ARG A 76 319.237 312.939 298.353 1.00 95.74 C +ATOM 471 NE ARG A 76 317.830 312.572 298.452 1.00 95.74 N +ATOM 472 CZ ARG A 76 317.186 311.836 297.558 1.00 95.74 C +ATOM 473 NH1 ARG A 76 317.792 311.373 296.478 1.00 95.74 N +ATOM 474 NH2 ARG A 76 315.901 311.559 297.753 1.00 95.74 N +ATOM 475 N ILE A 77 321.575 316.067 301.213 1.00 95.74 N +ATOM 476 CA ILE A 77 323.018 316.270 301.257 1.00 94.80 C +ATOM 477 C ILE A 77 323.686 314.969 300.833 1.00 94.80 C +ATOM 478 O ILE A 77 323.475 313.924 301.457 1.00 94.80 O +ATOM 479 CB ILE A 77 323.486 316.694 302.657 1.00 94.80 C +ATOM 480 CG1 ILE A 77 323.063 318.132 302.957 1.00 94.80 C +ATOM 481 CG2 ILE A 77 324.993 316.571 302.766 1.00 94.80 C +ATOM 482 CD1 ILE A 77 323.921 319.173 302.293 1.00 94.80 C +ATOM 483 N ILE A 78 324.495 315.028 299.777 1.00 94.80 N +ATOM 484 CA ILE A 78 325.097 313.836 299.194 1.00 92.92 C +ATOM 485 C ILE A 78 326.607 314.013 299.119 1.00 92.92 C +ATOM 486 O ILE A 78 327.114 315.070 298.732 1.00 92.92 O +ATOM 487 CB ILE A 78 324.514 313.535 297.798 1.00 92.92 C +ATOM 488 CG1 ILE A 78 323.028 313.191 297.903 1.00 92.92 C +ATOM 489 CG2 ILE A 78 325.268 312.398 297.130 1.00 92.92 C +ATOM 490 CD1 ILE A 78 322.357 313.018 296.563 1.00 92.92 C +ATOM 491 N ASN A 79 327.325 312.959 299.502 1.00 95.33 N +ATOM 492 CA ASN A 79 328.772 312.878 299.348 1.00 95.33 C +ATOM 493 C ASN A 79 329.054 312.171 298.029 1.00 95.33 C +ATOM 494 O ASN A 79 328.761 310.978 297.888 1.00 95.33 O +ATOM 495 CB ASN A 79 329.404 312.131 300.523 1.00 95.33 C +ATOM 496 CG ASN A 79 330.923 312.169 300.501 1.00 95.33 C +ATOM 497 OD1 ASN A 79 331.542 312.389 299.463 1.00 95.33 O +ATOM 498 ND2 ASN A 79 331.532 311.961 301.663 1.00 95.33 N +ATOM 499 N THR A 80 329.617 312.905 297.068 1.00 95.33 N +ATOM 500 CA THR A 80 329.800 312.350 295.733 1.00 95.63 C +ATOM 501 C THR A 80 330.888 311.285 295.684 1.00 95.63 C +ATOM 502 O THR A 80 330.775 310.333 294.904 1.00 95.63 O +ATOM 503 CB THR A 80 330.102 313.465 294.726 1.00 95.63 C +ATOM 504 OG1 THR A 80 330.327 312.891 293.434 1.00 95.63 O +ATOM 505 CG2 THR A 80 331.320 314.273 295.137 1.00 95.63 C +ATOM 506 N LYS A 81 331.943 311.417 296.492 1.00 95.63 N +ATOM 507 CA LYS A 81 332.986 310.397 296.501 1.00 95.63 C +ATOM 508 C LYS A 81 332.477 309.063 297.028 1.00 95.63 C +ATOM 509 O LYS A 81 332.771 308.018 296.441 1.00 94.21 O +ATOM 510 CB LYS A 81 334.180 310.865 297.335 1.00 94.21 C +ATOM 511 CG LYS A 81 335.185 309.766 297.633 1.00 94.21 C +ATOM 512 CD LYS A 81 336.602 310.304 297.680 1.00 94.21 C +ATOM 513 CE LYS A 81 336.894 310.986 299.005 1.00 94.21 C +ATOM 514 NZ LYS A 81 338.327 310.856 299.383 1.00 94.21 N +ATOM 515 N LYS A 82 331.710 309.079 298.115 1.00 94.21 N +ATOM 516 CA LYS A 82 331.178 307.859 298.704 1.00 94.21 C +ATOM 517 C LYS A 82 329.886 307.392 298.050 1.00 94.21 C +ATOM 518 O LYS A 82 329.465 306.257 298.296 1.00 94.21 O +ATOM 519 CB LYS A 82 330.933 308.063 300.203 1.00 97.25 C +ATOM 520 CG LYS A 82 332.167 308.462 300.991 1.00 97.25 C +ATOM 521 CD LYS A 82 333.163 307.321 301.080 1.00 97.25 C +ATOM 522 CE LYS A 82 334.385 307.728 301.883 1.00 97.25 C +ATOM 523 NZ LYS A 82 334.047 307.952 303.316 1.00 97.25 N +ATOM 524 N HIS A 83 329.254 308.237 297.233 1.00 97.25 N +ATOM 525 CA HIS A 83 327.953 307.947 296.628 1.00 99.43 C +ATOM 526 C HIS A 83 326.898 307.618 297.679 1.00 99.43 C +ATOM 527 O HIS A 83 325.978 306.835 297.424 1.00 99.43 O +ATOM 528 CB HIS A 83 328.053 306.818 295.597 1.00 99.43 C +ATOM 529 CG HIS A 83 328.843 307.181 294.379 1.00 99.43 C +ATOM 530 ND1 HIS A 83 330.154 307.600 294.439 1.00 99.43 N +ATOM 531 CD2 HIS A 83 328.506 307.190 293.067 1.00 99.43 C +ATOM 532 CE1 HIS A 83 330.592 307.849 293.218 1.00 99.43 C +ATOM 533 NE2 HIS A 83 329.611 307.609 292.367 1.00100.96 N +ATOM 534 N SER A 84 327.021 308.211 298.861 1.00100.96 N +ATOM 535 CA SER A 84 326.107 307.976 299.969 1.00100.96 C +ATOM 536 C SER A 84 325.309 309.237 300.283 1.00100.96 C +ATOM 537 O SER A 84 325.511 310.301 299.693 1.00100.96 O +ATOM 538 CB SER A 84 326.876 307.505 301.207 1.00100.96 C +ATOM 539 OG SER A 84 327.534 308.589 301.840 1.00100.96 O +ATOM 540 N ILE A 85 324.390 309.102 301.232 1.00100.96 N +ATOM 541 CA ILE A 85 323.518 310.189 301.661 1.00102.82 C +ATOM 542 C ILE A 85 323.852 310.499 303.112 1.00102.82 C +ATOM 543 O ILE A 85 323.680 309.648 303.994 1.00102.82 O +ATOM 544 CB ILE A 85 322.037 309.824 301.502 1.00102.82 C +ATOM 545 CG1 ILE A 85 321.712 309.528 300.037 1.00102.82 C +ATOM 546 CG2 ILE A 85 321.155 310.940 302.037 1.00102.82 C +ATOM 547 CD1 ILE A 85 320.231 309.404 299.752 1.00105.26 C +ATOM 548 N ILE A 86 324.330 311.719 303.370 1.00105.26 N +ATOM 549 CA ILE A 86 324.584 312.139 304.744 1.00105.26 C +ATOM 550 C ILE A 86 323.272 312.307 305.500 1.00105.26 C +ATOM 551 O ILE A 86 323.130 311.853 306.640 1.00105.26 O +ATOM 552 CB ILE A 86 325.419 313.432 304.779 1.00105.26 C +ATOM 553 CG1 ILE A 86 326.820 313.193 304.216 1.00105.26 C +ATOM 554 CG2 ILE A 86 325.507 313.973 306.197 1.00105.26 C +ATOM 555 CD1 ILE A 86 326.930 313.438 302.738 1.00105.26 C +ATOM 556 N CYS A 87 322.291 312.954 304.876 1.00101.96 N +ATOM 557 CA CYS A 87 321.039 313.245 305.559 1.00101.96 C +ATOM 558 C CYS A 87 319.983 313.624 304.535 1.00101.96 C +ATOM 559 O CYS A 87 320.262 313.775 303.342 1.00101.96 O +ATOM 560 CB CYS A 87 321.215 314.369 306.585 1.00101.96 C +ATOM 561 SG CYS A 87 321.586 315.975 305.852 1.00101.96 S +ATOM 562 N GLU A 88 318.756 313.775 305.030 1.00101.96 N +ATOM 563 CA GLU A 88 317.624 314.223 304.233 1.00 96.37 C +ATOM 564 C GLU A 88 316.703 315.031 305.131 1.00 96.37 C +ATOM 565 O GLU A 88 316.273 314.547 306.179 1.00 96.37 O +ATOM 566 CB GLU A 88 316.870 313.038 303.621 1.00 96.37 C +ATOM 567 CG GLU A 88 315.720 313.435 302.718 1.00 96.37 C +ATOM 568 CD GLU A 88 315.032 312.232 302.101 1.00 96.37 C +ATOM 569 OE1 GLU A 88 315.444 311.093 302.396 1.00 96.37 O +ATOM 570 OE2 GLU A 88 314.074 312.424 301.328 1.00 85.90 O +ATOM 571 N VAL A 89 316.397 316.257 304.708 1.00 85.90 N +ATOM 572 CA VAL A 89 315.577 317.172 305.489 1.00 85.90 C +ATOM 573 C VAL A 89 314.521 317.791 304.587 1.00 85.90 C +ATOM 574 O VAL A 89 314.786 318.140 303.433 1.00 85.90 O +ATOM 575 CB VAL A 89 316.423 318.271 306.174 1.00 85.90 C +ATOM 576 CG1 VAL A 89 317.335 317.668 307.230 1.00 85.90 C +ATOM 577 CG2 VAL A 89 317.243 319.029 305.150 1.00 85.90 C +ATOM 578 N THR A 90 313.308 317.911 305.120 1.00 85.90 N +ATOM 579 CA THR A 90 312.201 318.532 304.415 1.00 85.90 C +ATOM 580 C THR A 90 311.870 319.873 305.055 1.00 85.90 C +ATOM 581 O THR A 90 312.239 320.141 306.202 1.00 84.52 O +ATOM 582 CB THR A 90 310.960 317.629 304.411 1.00 84.52 C +ATOM 583 OG1 THR A 90 310.031 318.097 303.427 1.00 84.52 O +ATOM 584 CG2 THR A 90 310.288 317.635 305.775 1.00 84.52 C +ATOM 585 N PHE A 91 311.191 320.718 304.295 1.00 84.52 N +ATOM 586 CA PHE A 91 310.758 322.035 304.731 1.00 84.52 C +ATOM 587 C PHE A 91 309.306 322.238 304.330 1.00 84.52 C +ATOM 588 O PHE A 91 308.834 321.641 303.357 1.00 83.03 O +ATOM 589 CB PHE A 91 311.641 323.134 304.121 1.00 83.03 C +ATOM 590 CG PHE A 91 313.077 323.066 304.559 1.00 83.03 C +ATOM 591 CD1 PHE A 91 313.507 323.771 305.667 1.00 83.03 C +ATOM 592 CD2 PHE A 91 313.990 322.277 303.882 1.00 83.03 C +ATOM 593 CE1 PHE A 91 314.822 323.709 306.080 1.00 83.03 C +ATOM 594 CE2 PHE A 91 315.305 322.210 304.293 1.00 83.03 C +ATOM 595 CZ PHE A 91 315.721 322.925 305.394 1.00 82.15 C +ATOM 596 N PRO A 92 308.561 323.057 305.077 1.00 82.15 N +ATOM 597 CA PRO A 92 307.146 323.263 304.730 1.00 82.15 C +ATOM 598 C PRO A 92 306.937 323.898 303.364 1.00 82.15 C +ATOM 599 O PRO A 92 305.906 323.639 302.731 1.00 82.15 O +ATOM 600 CB PRO A 92 306.632 324.165 305.861 1.00 82.15 C +ATOM 601 CG PRO A 92 307.850 324.825 306.410 1.00 77.29 C +ATOM 602 CD PRO A 92 308.960 323.833 306.263 1.00 77.29 C +ATOM 603 N THR A 93 307.872 324.718 302.890 1.00 77.29 N +ATOM 604 CA THR A 93 307.739 325.400 301.612 1.00 77.29 C +ATOM 605 C THR A 93 308.980 325.158 300.762 1.00 77.29 C +ATOM 606 O THR A 93 309.950 324.532 301.196 1.00 77.29 O +ATOM 607 CB THR A 93 307.511 326.907 301.797 1.00 77.29 C +ATOM 608 OG1 THR A 93 308.696 327.512 302.329 1.00 77.29 O +ATOM 609 CG2 THR A 93 306.347 327.163 302.743 1.00 73.41 C +ATOM 610 N SER A 94 308.936 325.664 299.530 1.00 73.41 N +ATOM 611 CA SER A 94 310.037 325.468 298.597 1.00 73.41 C +ATOM 612 C SER A 94 311.272 326.243 299.041 1.00 73.41 C +ATOM 613 O SER A 94 311.175 327.359 299.556 1.00 73.41 O +ATOM 614 CB SER A 94 309.622 325.906 297.193 1.00 73.41 C +ATOM 615 OG SER A 94 309.837 327.294 297.014 1.00 73.41 O +ATOM 616 N ILE A 95 312.438 325.643 298.831 1.00 73.41 N +ATOM 617 CA ILE A 95 313.705 326.276 299.186 1.00 73.41 C +ATOM 618 C ILE A 95 314.064 327.293 298.115 1.00 73.41 C +ATOM 619 O ILE A 95 313.918 327.028 296.917 1.00 73.41 O +ATOM 620 CB ILE A 95 314.813 325.224 299.341 1.00 73.41 C +ATOM 621 CG1 ILE A 95 314.393 324.150 300.339 1.00 73.41 C +ATOM 622 CG2 ILE A 95 316.108 325.879 299.789 1.00 73.41 C +ATOM 623 CD1 ILE A 95 315.265 322.931 300.293 1.00 73.41 C +ATOM 624 N LEU A 96 314.531 328.464 298.539 1.00 73.41 N +ATOM 625 CA LEU A 96 314.906 329.509 297.597 1.00 73.41 C +ATOM 626 C LEU A 96 316.408 329.698 297.462 1.00 73.41 C +ATOM 627 O LEU A 96 316.867 330.149 296.408 1.00 73.41 O +ATOM 628 CB LEU A 96 314.267 330.843 297.995 1.00 73.41 C +ATOM 629 CG LEU A 96 312.916 331.166 297.352 1.00 73.41 C +ATOM 630 CD1 LEU A 96 311.881 330.089 297.641 1.00 73.41 C +ATOM 631 CD2 LEU A 96 312.425 332.523 297.815 1.00 73.41 C +ATOM 632 N SER A 97 317.187 329.375 298.491 1.00 73.41 N +ATOM 633 CA SER A 97 318.633 329.517 298.402 1.00 73.41 C +ATOM 634 C SER A 97 319.287 328.658 299.472 1.00 73.41 C +ATOM 635 O SER A 97 318.711 328.410 300.533 1.00 73.41 O +ATOM 636 CB SER A 97 319.064 330.978 298.552 1.00 73.41 C +ATOM 637 OG SER A 97 320.473 331.082 298.640 1.00 73.41 O +ATOM 638 N VAL A 98 320.497 328.198 299.168 1.00 73.41 N +ATOM 639 CA VAL A 98 321.309 327.412 300.090 1.00 74.01 C +ATOM 640 C VAL A 98 322.751 327.879 299.958 1.00 74.01 C +ATOM 641 O VAL A 98 323.251 328.039 298.841 1.00 74.01 O +ATOM 642 CB VAL A 98 321.208 325.899 299.808 1.00 74.01 C +ATOM 643 CG1 VAL A 98 322.220 325.133 300.639 1.00 74.01 C +ATOM 644 CG2 VAL A 98 319.801 325.390 300.072 1.00 74.01 C +ATOM 645 N LYS A 99 323.417 328.104 301.085 1.00 74.01 N +ATOM 646 CA LYS A 99 324.820 328.489 301.076 1.00 74.01 C +ATOM 647 C LYS A 99 325.531 327.807 302.232 1.00 75.02 C +ATOM 648 O LYS A 99 324.912 327.419 303.225 1.00 75.02 O +ATOM 649 CB LYS A 99 324.991 330.010 301.163 1.00 75.02 C +ATOM 650 CG LYS A 99 324.682 330.734 299.869 1.00 75.02 C +ATOM 651 CD LYS A 99 325.078 332.195 299.939 1.00 75.02 C +ATOM 652 CE LYS A 99 325.026 332.840 298.566 1.00 75.02 C +ATOM 653 NZ LYS A 99 323.630 332.958 298.063 1.00 75.02 N +ATOM 654 N MET A 100 326.847 327.651 302.092 1.00 75.02 N +ATOM 655 CA MET A 100 327.630 326.988 303.122 1.00 76.98 C +ATOM 656 C MET A 100 328.973 327.674 303.303 1.00 76.98 C +ATOM 657 O MET A 100 329.498 328.314 302.389 1.00 76.98 O +ATOM 658 CB MET A 100 327.893 325.514 302.805 1.00 76.98 C +ATOM 659 CG MET A 100 326.675 324.651 302.620 1.00 76.98 C +ATOM 660 SD MET A 100 327.087 323.234 301.591 1.00 76.98 S +ATOM 661 CE MET A 100 325.531 322.369 301.598 1.00 76.98 C +ATOM 662 N ASN A 101 329.508 327.531 304.509 1.00 76.98 N +ATOM 663 CA ASN A 101 330.930 327.630 304.793 1.00 76.98 C +ATOM 664 C ASN A 101 331.341 326.327 305.464 1.00 73.53 C +ATOM 665 O ASN A 101 330.532 325.407 305.614 1.00 73.53 O +ATOM 666 CB ASN A 101 331.251 328.853 305.664 1.00 73.53 C +ATOM 667 CG ASN A 101 330.415 328.910 306.928 1.00 73.53 C +ATOM 668 OD1 ASN A 101 329.731 327.952 307.284 1.00 73.53 O +ATOM 669 ND2 ASN A 101 330.468 330.044 307.616 1.00 73.53 N +ATOM 670 N LYS A 102 332.599 326.235 305.879 1.00 73.41 N +ATOM 671 CA LYS A 102 333.053 325.014 306.534 1.00 73.41 C +ATOM 672 C LYS A 102 332.589 324.910 307.982 1.00 73.41 C +ATOM 673 O LYS A 102 333.079 324.043 308.711 1.00 73.41 O +ATOM 674 CB LYS A 102 334.579 324.905 306.459 1.00 73.41 C +ATOM 675 CG LYS A 102 335.324 326.086 307.038 1.00 73.41 C +ATOM 676 CD LYS A 102 336.823 325.844 307.031 1.00 73.41 C +ATOM 677 CE LYS A 102 337.361 325.753 305.616 1.00 73.41 C +ATOM 678 NZ LYS A 102 338.824 325.480 305.601 1.00 73.41 N +ATOM 679 N SER A 103 331.658 325.762 308.410 1.00 73.41 N +ATOM 680 CA SER A 103 331.129 325.737 309.766 1.00 73.41 C +ATOM 681 C SER A 103 329.611 325.665 309.842 1.00 73.41 C +ATOM 682 O SER A 103 329.090 324.981 310.724 1.00 73.41 O +ATOM 683 CB SER A 103 331.595 326.975 310.544 1.00 73.41 C +ATOM 684 OG SER A 103 331.040 326.996 311.847 1.00 73.41 O +ATOM 685 N ARG A 104 328.890 326.337 308.947 1.00 73.41 N +ATOM 686 CA ARG A 104 327.443 326.450 309.058 1.00 73.41 C +ATOM 687 C ARG A 104 326.785 326.169 307.716 1.00 73.41 C +ATOM 688 O ARG A 104 327.394 326.333 306.657 1.00 73.41 O +ATOM 689 CB ARG A 104 327.026 327.842 309.545 1.00 73.41 C +ATOM 690 CG ARG A 104 327.461 328.164 310.960 1.00 73.41 C +ATOM 691 CD ARG A 104 326.647 327.395 311.976 1.00 73.41 C +ATOM 692 NE ARG A 104 326.868 327.892 313.327 1.00 73.41 N +ATOM 693 CZ ARG A 104 327.785 327.418 314.159 1.00 73.41 C +ATOM 694 NH1 ARG A 104 328.588 326.428 313.810 1.00 73.41 N +ATOM 695 NH2 ARG A 104 327.900 327.952 315.370 1.00 73.41 N +ATOM 696 N LEU A 105 325.525 325.744 307.779 1.00 73.41 N +ATOM 697 CA LEU A 105 324.694 325.514 306.606 1.00 73.41 C +ATOM 698 C LEU A 105 323.409 326.316 306.747 1.00 73.41 C +ATOM 699 O LEU A 105 322.737 326.244 307.780 1.00 73.41 O +ATOM 700 CB LEU A 105 324.376 324.023 306.449 1.00 73.41 C +ATOM 701 CG LEU A 105 323.587 323.528 305.236 1.00 73.41 C +ATOM 702 CD1 LEU A 105 324.018 322.116 304.907 1.00 73.41 C +ATOM 703 CD2 LEU A 105 322.094 323.558 305.493 1.00 73.41 C +ATOM 704 N VAL A 106 323.061 327.067 305.705 1.00 73.41 N +ATOM 705 CA VAL A 106 321.909 327.962 305.730 1.00 73.41 C +ATOM 706 C VAL A 106 320.929 327.560 304.640 1.00 73.41 C +ATOM 707 O VAL A 106 321.315 327.403 303.478 1.00 73.41 O +ATOM 708 CB VAL A 106 322.324 329.433 305.560 1.00 73.41 C +ATOM 709 CG1 VAL A 106 321.099 330.304 305.476 1.00 73.41 C +ATOM 710 CG2 VAL A 106 323.154 329.864 306.744 1.00 73.41 C +ATOM 711 N VAL A 107 319.665 327.401 305.019 1.00 73.41 N +ATOM 712 CA VAL A 107 318.572 327.150 304.090 1.00 73.41 C +ATOM 713 C VAL A 107 317.556 328.268 304.244 1.00 73.41 C +ATOM 714 O VAL A 107 317.091 328.538 305.358 1.00 73.41 O +ATOM 715 CB VAL A 107 317.916 325.783 304.341 1.00 73.41 C +ATOM 716 CG1 VAL A 107 316.696 325.622 303.457 1.00 73.41 C +ATOM 717 CG2 VAL A 107 318.907 324.671 304.098 1.00 73.41 C +ATOM 718 N LEU A 108 317.204 328.909 303.137 1.00 73.41 N +ATOM 719 CA LEU A 108 316.272 330.029 303.141 1.00 74.21 C +ATOM 720 C LEU A 108 314.984 329.645 302.430 1.00 74.21 C +ATOM 721 O LEU A 108 315.011 329.195 301.280 1.00 74.21 O +ATOM 722 CB LEU A 108 316.894 331.263 302.490 1.00 74.21 C +ATOM 723 CG LEU A 108 316.018 332.516 302.487 1.00 74.21 C +ATOM 724 CD1 LEU A 108 316.817 333.756 302.752 1.00 74.21 C +ATOM 725 CD2 LEU A 108 315.360 332.649 301.128 1.00 74.21 C +ATOM 726 N LEU A 109 313.864 329.834 303.115 1.00 74.21 N +ATOM 727 CA LEU A 109 312.548 329.841 302.501 1.00 74.21 C +ATOM 728 C LEU A 109 312.091 331.285 302.343 1.00 74.00 C +ATOM 729 O LEU A 109 312.787 332.221 302.738 1.00 74.00 O +ATOM 730 CB LEU A 109 311.540 329.043 303.333 1.00 74.00 C +ATOM 731 CG LEU A 109 312.029 327.682 303.829 1.00 74.00 C +ATOM 732 CD1 LEU A 109 310.974 327.007 304.685 1.00 74.00 C +ATOM 733 CD2 LEU A 109 312.415 326.799 302.660 1.00 74.00 C +ATOM 734 N GLN A 110 310.899 331.457 301.769 1.00 74.00 N +ATOM 735 CA GLN A 110 310.445 332.793 301.398 1.00 74.00 C +ATOM 736 C GLN A 110 310.335 333.711 302.610 1.00 74.00 C +ATOM 737 O GLN A 110 310.543 334.925 302.499 1.00 73.41 O +ATOM 738 CB GLN A 110 309.102 332.723 300.662 1.00 73.41 C +ATOM 739 CG GLN A 110 307.978 331.981 301.388 1.00 73.41 C +ATOM 740 CD GLN A 110 308.228 330.495 301.536 1.00 73.41 C +ATOM 741 OE1 GLN A 110 308.547 329.805 300.568 1.00 73.41 O +ATOM 742 NE2 GLN A 110 308.095 329.994 302.759 1.00 73.41 N +ATOM 743 N GLU A 111 310.013 333.152 303.780 1.00 73.41 N +ATOM 744 CA GLU A 111 309.837 333.949 304.988 1.00 73.41 C +ATOM 745 C GLU A 111 310.643 333.436 306.176 1.00 73.41 C +ATOM 746 O GLU A 111 310.584 334.040 307.252 1.00 73.41 O +ATOM 747 CB GLU A 111 308.355 334.019 305.376 1.00 73.41 C +ATOM 748 CG GLU A 111 307.440 334.508 304.270 1.00 73.41 C +ATOM 749 CD GLU A 111 305.986 334.538 304.694 1.00 73.41 C +ATOM 750 OE1 GLU A 111 305.651 333.898 305.713 1.00 73.41 O +ATOM 751 OE2 GLU A 111 305.179 335.201 304.009 1.00 73.41 O +ATOM 752 N GLN A 112 311.393 332.347 306.018 1.00 73.41 N +ATOM 753 CA GLN A 112 312.104 331.751 307.139 1.00 73.41 C +ATOM 754 C GLN A 112 313.540 331.459 306.737 1.00 73.41 C +ATOM 755 O GLN A 112 313.827 331.156 305.577 1.00 73.41 O +ATOM 756 CB GLN A 112 311.422 330.462 307.611 1.00 73.41 C +ATOM 757 CG GLN A 112 310.006 330.660 308.117 1.00 73.41 C +ATOM 758 CD GLN A 112 309.163 329.411 307.978 1.00 73.41 C +ATOM 759 OE1 GLN A 112 309.364 328.612 307.064 1.00 73.41 O +ATOM 760 NE2 GLN A 112 308.210 329.235 308.885 1.00 73.41 N +ATOM 761 N ILE A 113 314.440 331.550 307.712 1.00 73.41 N +ATOM 762 CA ILE A 113 315.846 331.208 307.539 1.00 73.41 C +ATOM 763 C ILE A 113 316.191 330.119 308.544 1.00 73.41 C +ATOM 764 O ILE A 113 315.946 330.277 309.744 1.00 73.41 O +ATOM 765 CB ILE A 113 316.761 332.431 307.725 1.00 73.41 C +ATOM 766 CG1 ILE A 113 316.657 333.363 306.522 1.00 73.41 C +ATOM 767 CG2 ILE A 113 318.200 331.998 307.938 1.00 73.41 C +ATOM 768 CD1 ILE A 113 317.221 334.737 306.772 1.00 73.41 C +ATOM 769 N TYR A 114 316.752 329.021 308.055 1.00 73.41 N +ATOM 770 CA TYR A 114 317.192 327.917 308.893 1.00 73.41 C +ATOM 771 C TYR A 114 318.709 327.838 308.844 1.00 73.41 C +ATOM 772 O TYR A 114 319.299 327.879 307.761 1.00 73.41 O +ATOM 773 CB TYR A 114 316.582 326.594 308.428 1.00 73.41 C +ATOM 774 CG TYR A 114 315.099 326.464 308.685 1.00 73.41 C +ATOM 775 CD1 TYR A 114 314.178 327.190 307.945 1.00 73.41 C +ATOM 776 CD2 TYR A 114 314.620 325.597 309.654 1.00 73.41 C +ATOM 777 CE1 TYR A 114 312.822 327.065 308.173 1.00 73.41 C +ATOM 778 CE2 TYR A 114 313.268 325.464 309.890 1.00 73.41 C +ATOM 779 CZ TYR A 114 312.373 326.201 309.148 1.00 73.41 C +ATOM 780 OH TYR A 114 311.025 326.072 309.381 1.00 73.41 O +ATOM 781 N ILE A 115 319.337 327.725 310.009 1.00 73.41 N +ATOM 782 CA ILE A 115 320.788 327.637 310.107 1.00 73.41 C +ATOM 783 C ILE A 115 321.139 326.299 310.736 1.00 73.41 C +ATOM 784 O ILE A 115 320.623 325.959 311.809 1.00 73.41 O +ATOM 785 CB ILE A 115 321.385 328.793 310.924 1.00 73.41 C +ATOM 786 CG1 ILE A 115 321.062 330.129 310.261 1.00 75.06 C +ATOM 787 CG2 ILE A 115 322.883 328.623 311.057 1.00 75.06 C +ATOM 788 CD1 ILE A 115 321.355 331.321 311.134 1.00 75.06 C +ATOM 789 N TYR A 116 322.007 325.544 310.073 1.00 75.06 N +ATOM 790 CA TYR A 116 322.435 324.235 310.535 1.00 75.06 C +ATOM 791 C TYR A 116 323.945 324.221 310.721 1.00 75.06 C +ATOM 792 O TYR A 116 324.687 324.915 310.020 1.00 75.06 O +ATOM 793 CB TYR A 116 322.034 323.136 309.544 1.00 75.06 C +ATOM 794 CG TYR A 116 320.560 322.816 309.523 1.00 76.98 C +ATOM 795 CD1 TYR A 116 319.644 323.698 308.972 1.00 76.98 C +ATOM 796 CD2 TYR A 116 320.087 321.620 310.037 1.00 76.98 C +ATOM 797 CE1 TYR A 116 318.298 323.403 308.948 1.00 76.98 C +ATOM 798 CE2 TYR A 116 318.743 321.316 310.016 1.00 76.98 C +ATOM 799 CZ TYR A 116 317.853 322.210 309.472 1.00 76.98 C +ATOM 800 OH TYR A 116 316.511 321.907 309.450 1.00 76.98 O +ATOM 801 N ASP A 117 324.396 323.425 311.687 1.00 76.98 N +ATOM 802 CA ASP A 117 325.821 323.173 311.863 1.00 79.30 C +ATOM 803 C ASP A 117 326.241 322.173 310.795 1.00 79.30 C +ATOM 804 O ASP A 117 325.593 321.139 310.619 1.00 79.30 O +ATOM 805 CB ASP A 117 326.108 322.644 313.265 1.00 79.30 C +ATOM 806 CG ASP A 117 327.581 322.700 313.622 1.00 79.30 C +ATOM 807 OD1 ASP A 117 328.426 322.703 312.702 1.00 79.30 O +ATOM 808 OD2 ASP A 117 327.898 322.738 314.829 1.00 79.30 O +ATOM 809 N ILE A 118 327.317 322.478 310.067 1.00 79.30 N +ATOM 810 CA ILE A 118 327.696 321.620 308.950 1.00 76.57 C +ATOM 811 C ILE A 118 328.131 320.243 309.441 1.00 76.57 C +ATOM 812 O ILE A 118 327.877 319.233 308.775 1.00 76.57 O +ATOM 813 CB ILE A 118 328.783 322.297 308.091 1.00 76.57 C +ATOM 814 CG1 ILE A 118 328.971 321.531 306.784 1.00 76.57 C +ATOM 815 CG2 ILE A 118 330.099 322.396 308.842 1.00 76.57 C +ATOM 816 CD1 ILE A 118 327.731 321.493 305.924 1.00 76.57 C +ATOM 817 N ASN A 119 328.775 320.171 310.605 1.00 76.27 N +ATOM 818 CA ASN A 119 329.294 318.907 311.111 1.00 76.27 C +ATOM 819 C ASN A 119 328.195 318.057 311.738 1.00 76.27 C +ATOM 820 O ASN A 119 327.913 316.951 311.267 1.00 76.27 O +ATOM 821 CB ASN A 119 330.403 319.162 312.132 1.00 76.27 C +ATOM 822 CG ASN A 119 331.528 320.007 311.570 1.00 76.27 C +ATOM 823 OD1 ASN A 119 331.790 321.110 312.048 1.00 76.27 O +ATOM 824 ND2 ASN A 119 332.195 319.496 310.544 1.00 76.27 N +ATOM 825 N THR A 120 327.565 318.569 312.797 1.00 74.64 N +ATOM 826 CA THR A 120 326.595 317.770 313.538 1.00 74.64 C +ATOM 827 C THR A 120 325.271 317.658 312.790 1.00 74.64 C +ATOM 828 O THR A 120 324.535 316.680 312.964 1.00 74.64 O +ATOM 829 CB THR A 120 326.380 318.368 314.928 1.00 74.64 C +ATOM 830 OG1 THR A 120 325.677 319.610 314.811 1.00 74.64 O +ATOM 831 CG2 THR A 120 327.715 318.612 315.611 1.00 74.64 C +ATOM 832 N MET A 121 324.943 318.660 311.974 1.00 74.64 N +ATOM 833 CA MET A 121 323.755 318.736 311.119 1.00 74.64 C +ATOM 834 C MET A 121 322.497 318.969 311.951 1.00 74.64 C +ATOM 835 O MET A 121 321.385 319.006 311.403 1.00 74.64 O +ATOM 836 CB MET A 121 323.628 317.492 310.225 1.00 73.41 C +ATOM 837 CG MET A 121 322.504 317.506 309.194 1.00 73.41 C +ATOM 838 SD MET A 121 322.725 318.816 307.973 1.00 73.41 S +ATOM 839 CE MET A 121 324.094 318.174 307.014 1.00 73.41 C +ATOM 840 N ARG A 122 322.628 319.161 313.260 1.00 73.41 N +ATOM 841 CA ARG A 122 321.476 319.531 314.068 1.00 73.41 C +ATOM 842 C ARG A 122 321.132 321.003 313.863 1.00 73.41 C +ATOM 843 O ARG A 122 322.000 321.837 313.595 1.00 73.41 O +ATOM 844 CB ARG A 122 321.739 319.257 315.550 1.00 73.41 C +ATOM 845 CG ARG A 122 322.826 320.124 316.164 1.00 73.41 C +ATOM 846 CD ARG A 122 322.978 319.847 317.651 1.00 73.41 C +ATOM 847 NE ARG A 122 321.827 320.327 318.408 1.00 73.41 N +ATOM 848 CZ ARG A 122 321.738 321.529 318.957 1.00 73.41 C +ATOM 849 NH1 ARG A 122 322.726 322.405 318.868 1.00 73.41 N +ATOM 850 NH2 ARG A 122 320.630 321.863 319.610 1.00 73.41 N +ATOM 851 N LEU A 123 319.844 321.315 313.989 1.00 73.41 N +ATOM 852 CA LEU A 123 319.389 322.690 313.826 1.00 73.41 C +ATOM 853 C LEU A 123 319.907 323.557 314.967 1.00 73.41 C +ATOM 854 O LEU A 123 319.884 323.153 316.134 1.00 73.41 O +ATOM 855 CB LEU A 123 317.862 322.738 313.775 1.00 73.41 C +ATOM 856 CG LEU A 123 317.189 324.035 313.317 1.00 73.41 C +ATOM 857 CD1 LEU A 123 315.878 323.723 312.618 1.00 73.41 C +ATOM 858 CD2 LEU A 123 316.950 324.981 314.483 1.00 73.41 C +ATOM 859 N LEU A 124 320.373 324.755 314.629 1.00 73.41 N +ATOM 860 CA LEU A 124 320.902 325.687 315.618 1.00 73.41 C +ATOM 861 C LEU A 124 320.016 326.896 315.857 1.00 73.41 C +ATOM 862 O LEU A 124 319.867 327.324 317.001 1.00 73.41 O +ATOM 863 CB LEU A 124 322.294 326.172 315.204 1.00 73.41 C +ATOM 864 CG LEU A 124 323.350 325.100 314.961 1.00 73.41 C +ATOM 865 CD1 LEU A 124 324.648 325.744 314.525 1.00 73.41 C +ATOM 866 CD2 LEU A 124 323.555 324.274 316.213 1.00 73.41 C +ATOM 867 N HIS A 125 319.424 327.462 314.809 1.00 73.41 N +ATOM 868 CA HIS A 125 318.673 328.700 314.958 1.00 73.41 C +ATOM 869 C HIS A 125 317.637 328.790 313.850 1.00 73.41 C +ATOM 870 O HIS A 125 317.725 328.101 312.832 1.00 73.41 O +ATOM 871 CB HIS A 125 319.602 329.917 314.931 1.00 73.41 C +ATOM 872 CG HIS A 125 318.976 331.169 315.458 1.00 73.41 C +ATOM 873 ND1 HIS A 125 318.475 332.154 314.635 1.00 73.41 N +ATOM 874 CD2 HIS A 125 318.771 331.597 316.725 1.00 73.41 C +ATOM 875 CE1 HIS A 125 317.988 333.135 315.374 1.00 73.41 C +ATOM 876 NE2 HIS A 125 318.155 332.823 316.645 1.00 73.41 N +ATOM 877 N THR A 126 316.646 329.649 314.071 1.00 73.56 N +ATOM 878 CA THR A 126 315.624 329.949 313.080 1.00 73.56 C +ATOM 879 C THR A 126 315.320 331.433 313.157 1.00 73.56 C +ATOM 880 O THR A 126 315.184 331.980 314.253 1.00 73.56 O +ATOM 881 CB THR A 126 314.352 329.128 313.321 1.00 73.56 C +ATOM 882 OG1 THR A 126 314.631 327.740 313.111 1.00 73.56 O +ATOM 883 CG2 THR A 126 313.249 329.559 312.369 1.00 73.56 C +ATOM 884 N ILE A 127 315.227 332.087 312.004 1.00 73.56 N +ATOM 885 CA ILE A 127 314.946 333.515 311.928 1.00 73.56 C +ATOM 886 C ILE A 127 313.656 333.714 311.148 1.00 73.41 C +ATOM 887 O ILE A 127 313.502 333.185 310.041 1.00 73.41 O +ATOM 888 CB ILE A 127 316.105 334.287 311.277 1.00 73.41 C +ATOM 889 CG1 ILE A 127 317.406 334.028 312.034 1.00 73.41 C +ATOM 890 CG2 ILE A 127 315.802 335.772 311.239 1.00 73.41 C +ATOM 891 CD1 ILE A 127 318.626 334.534 311.314 1.00 73.41 C +ATOM 892 N GLU A 128 312.727 334.469 311.729 1.00 73.41 N +ATOM 893 CA GLU A 128 311.485 334.836 311.060 1.00 73.41 C +ATOM 894 C GLU A 128 311.669 336.214 310.439 1.00 73.41 C +ATOM 895 O GLU A 128 311.717 337.223 311.153 1.00 73.41 O +ATOM 896 CB GLU A 128 310.318 334.823 312.040 1.00 73.41 C +ATOM 897 CG GLU A 128 309.991 333.454 312.602 1.00 73.41 C +ATOM 898 CD GLU A 128 309.203 332.604 311.630 1.00 73.41 C +ATOM 899 OE1 GLU A 128 308.421 333.174 310.842 1.00 73.41 O +ATOM 900 OE2 GLU A 128 309.366 331.367 311.654 1.00 73.41 O +ATOM 901 N THR A 129 311.773 336.259 309.119 1.00 73.41 N +ATOM 902 CA THR A 129 312.003 337.499 308.397 1.00 73.41 C +ATOM 903 C THR A 129 310.796 337.854 307.539 1.00 73.41 C +ATOM 904 O THR A 129 309.942 337.016 307.241 1.00 73.41 O +ATOM 905 CB THR A 129 313.251 337.394 307.516 1.00 73.41 C +ATOM 906 OG1 THR A 129 313.529 338.668 306.922 1.00 73.41 O +ATOM 907 CG2 THR A 129 313.043 336.362 306.415 1.00 73.41 C +ATOM 908 N ASN A 130 310.735 339.122 307.149 1.00 73.41 N +ATOM 909 CA ASN A 130 309.721 339.560 306.211 1.00 73.41 C +ATOM 910 C ASN A 130 309.952 338.880 304.862 1.00 73.41 C +ATOM 911 O ASN A 130 311.090 338.546 304.518 1.00 73.41 O +ATOM 912 CB ASN A 130 309.763 341.075 306.056 1.00 73.41 C +ATOM 913 CG ASN A 130 309.264 341.796 307.291 1.00 73.41 C +ATOM 914 OD1 ASN A 130 308.280 341.388 307.905 1.00 73.41 O +ATOM 915 ND2 ASN A 130 309.947 342.870 307.665 1.00 73.41 N +ATOM 916 N PRO A 131 308.886 338.650 304.084 1.00 73.41 N +ATOM 917 CA PRO A 131 309.009 337.807 302.886 1.00 73.41 C +ATOM 918 C PRO A 131 310.083 338.257 301.908 1.00 73.41 C +ATOM 919 O PRO A 131 310.221 339.448 301.614 1.00 73.41 O +ATOM 920 CB PRO A 131 307.614 337.905 302.257 1.00 73.41 C +ATOM 921 CG PRO A 131 306.711 338.138 303.413 1.00 73.41 C +ATOM 922 CD PRO A 131 307.486 339.019 304.356 1.00 73.41 C +ATOM 923 N ASN A 132 310.854 337.293 301.407 1.00 73.41 N +ATOM 924 CA ASN A 132 311.867 337.517 300.376 1.00 73.41 C +ATOM 925 C ASN A 132 311.590 336.575 299.216 1.00 73.41 C +ATOM 926 O ASN A 132 312.119 335.459 299.161 1.00 73.41 O +ATOM 927 CB ASN A 132 313.281 337.306 300.918 1.00 73.41 C +ATOM 928 CG ASN A 132 313.836 338.537 301.595 1.00 73.41 C +ATOM 929 OD1 ASN A 132 313.626 339.658 301.136 1.00 73.41 O +ATOM 930 ND2 ASN A 132 314.560 338.334 302.688 1.00 73.41 N +ATOM 931 N PRO A 133 310.745 336.991 298.269 1.00 73.41 N +ATOM 932 CA PRO A 133 310.474 336.141 297.100 1.00 73.41 C +ATOM 933 C PRO A 133 311.683 335.931 296.207 1.00 73.41 C +ATOM 934 O PRO A 133 311.688 334.974 295.422 1.00 73.41 O +ATOM 935 CB PRO A 133 309.369 336.905 296.367 1.00 73.41 C +ATOM 936 CG PRO A 133 309.614 338.333 296.734 1.00 73.41 C +ATOM 937 CD PRO A 133 310.097 338.308 298.158 1.00 73.41 C +ATOM 938 N ARG A 134 312.698 336.785 296.300 1.00 73.41 N +ATOM 939 CA ARG A 134 313.876 336.681 295.450 1.00 73.41 C +ATOM 940 C ARG A 134 314.948 335.755 296.011 1.00 73.41 C +ATOM 941 O ARG A 134 315.911 335.456 295.298 1.00 73.41 O +ATOM 942 CB ARG A 134 314.467 338.074 295.211 1.00 73.41 C +ATOM 943 CG ARG A 134 314.240 338.597 293.806 1.00 73.41 C +ATOM 944 CD ARG A 134 314.688 340.040 293.664 1.00 73.41 C +ATOM 945 NE ARG A 134 313.733 340.968 294.258 1.00 73.41 N +ATOM 946 CZ ARG A 134 313.937 342.271 294.386 1.00 73.41 C +ATOM 947 NH1 ARG A 134 315.059 342.837 293.975 1.00 73.41 N +ATOM 948 NH2 ARG A 134 312.992 343.024 294.939 1.00 73.41 N +ATOM 949 N GLY A 135 314.809 335.291 297.251 1.00 73.41 N +ATOM 950 CA GLY A 135 315.755 334.348 297.818 1.00 73.41 C +ATOM 951 C GLY A 135 317.176 334.870 297.891 1.00 73.41 C +ATOM 952 O GLY A 135 318.115 334.188 297.472 1.00 73.41 O +ATOM 953 N LEU A 136 317.348 336.076 298.421 1.00 73.41 N +ATOM 954 CA LEU A 136 318.636 336.756 298.423 1.00 73.41 C +ATOM 955 C LEU A 136 319.320 336.592 299.774 1.00 73.41 C +ATOM 956 O LEU A 136 318.697 336.804 300.818 1.00 73.41 O +ATOM 957 CB LEU A 136 318.450 338.240 298.116 1.00 73.41 C +ATOM 958 CG LEU A 136 317.880 338.579 296.742 1.00 73.41 C +ATOM 959 CD1 LEU A 136 317.580 340.059 296.660 1.00 73.41 C +ATOM 960 CD2 LEU A 136 318.844 338.166 295.650 1.00 73.41 C +ATOM 961 N MET A 137 320.599 336.222 299.748 1.00 73.41 N +ATOM 962 CA MET A 137 321.437 336.213 300.942 1.00 73.41 C +ATOM 963 C MET A 137 322.863 336.547 300.541 1.00 73.41 C +ATOM 964 O MET A 137 323.144 336.900 299.394 1.00 73.41 O +ATOM 965 CB MET A 137 321.433 334.866 301.672 1.00 73.41 C +ATOM 966 CG MET A 137 320.135 334.458 302.298 1.00 73.41 C +ATOM 967 SD MET A 137 320.297 332.896 303.180 1.00 73.41 S +ATOM 968 CE MET A 137 320.386 331.739 301.824 1.00 73.41 C +ATOM 969 N ALA A 138 323.754 336.439 301.519 1.00 73.41 N +ATOM 970 CA ALA A 138 325.190 336.472 301.306 1.00 73.41 C +ATOM 971 C ALA A 138 325.856 335.832 302.512 1.00 73.41 C +ATOM 972 O ALA A 138 325.559 336.191 303.652 1.00 73.41 O +ATOM 973 CB ALA A 138 325.701 337.897 301.096 1.00 78.14 C +ATOM 974 N MET A 139 326.746 334.882 302.254 1.00 78.14 N +ATOM 975 CA MET A 139 327.389 334.099 303.298 1.00 78.14 C +ATOM 976 C MET A 139 328.895 334.291 303.238 1.00 78.14 C +ATOM 977 O MET A 139 329.506 334.117 302.180 1.00 78.14 O +ATOM 978 CB MET A 139 327.071 332.614 303.147 1.00 78.14 C +ATOM 979 CG MET A 139 327.879 331.732 304.069 1.00 78.14 C +ATOM 980 SD MET A 139 327.013 331.326 305.583 1.00 77.59 S +ATOM 981 CE MET A 139 326.138 329.867 305.047 1.00 77.59 C +ATOM 982 N SER A 140 329.489 334.641 304.365 1.00 77.59 N +ATOM 983 CA SER A 140 330.940 334.705 304.431 1.00 77.59 C +ATOM 984 C SER A 140 331.501 333.293 304.534 1.00 77.59 C +ATOM 985 O SER A 140 331.098 332.536 305.424 1.00 77.59 O +ATOM 986 CB SER A 140 331.396 335.541 305.618 1.00 75.47 C +ATOM 987 OG SER A 140 332.751 335.270 305.923 1.00 75.47 O +ATOM 988 N PRO A 141 332.424 332.898 303.653 1.00 75.47 N +ATOM 989 CA PRO A 141 332.910 331.514 303.647 1.00 75.47 C +ATOM 990 C PRO A 141 333.994 331.212 304.671 1.00 75.47 C +ATOM 991 O PRO A 141 334.361 330.041 304.823 1.00 75.47 O +ATOM 992 CB PRO A 141 333.445 331.360 302.219 1.00 75.47 C +ATOM 993 CG PRO A 141 333.913 332.724 301.857 1.00 78.40 C +ATOM 994 CD PRO A 141 333.012 333.701 302.569 1.00 78.40 C +ATOM 995 N SER A 142 334.513 332.210 305.378 1.00 78.40 N +ATOM 996 CA SER A 142 335.568 332.009 306.363 1.00 78.40 C +ATOM 997 C SER A 142 334.961 331.920 307.755 1.00 78.40 C +ATOM 998 O SER A 142 334.030 332.664 308.078 1.00 74.52 O +ATOM 999 CB SER A 142 336.592 333.143 306.302 1.00 74.52 C +ATOM 1000 OG SER A 142 335.961 334.404 306.431 1.00 74.52 O +ATOM 1001 N VAL A 143 335.488 331.008 308.575 1.00 74.52 N +ATOM 1002 CA VAL A 143 334.945 330.812 309.917 1.00 74.52 C +ATOM 1003 C VAL A 143 335.379 331.929 310.858 1.00 74.52 C +ATOM 1004 O VAL A 143 334.746 332.151 311.897 1.00 74.52 O +ATOM 1005 CB VAL A 143 335.360 329.437 310.465 1.00 74.52 C +ATOM 1006 CG1 VAL A 143 334.701 328.341 309.668 1.00 73.41 C +ATOM 1007 CG2 VAL A 143 336.872 329.290 310.427 1.00 73.41 C +ATOM 1008 N ALA A 144 336.459 332.640 310.525 1.00 73.41 N +ATOM 1009 CA ALA A 144 336.914 333.727 311.384 1.00 73.41 C +ATOM 1010 C ALA A 144 335.887 334.848 311.445 1.00 73.41 C +ATOM 1011 O ALA A 144 335.676 335.452 312.503 1.00 73.41 O +ATOM 1012 CB ALA A 144 338.261 334.258 310.892 1.00 73.41 C +ATOM 1013 N ASN A 145 335.237 335.141 310.320 1.00 73.41 N +ATOM 1014 CA ASN A 145 334.266 336.225 310.257 1.00 73.41 C +ATOM 1015 C ASN A 145 332.942 335.733 309.690 1.00 73.41 C +ATOM 1016 O ASN A 145 332.385 336.349 308.777 1.00 73.41 O +ATOM 1017 CB ASN A 145 334.817 337.376 309.418 1.00 73.41 C +ATOM 1018 CG ASN A 145 336.059 337.991 310.024 1.00 73.41 C +ATOM 1019 OD1 ASN A 145 336.037 338.477 311.155 1.00 73.41 O +ATOM 1020 ND2 ASN A 145 337.157 337.965 309.279 1.00 73.41 N +ATOM 1021 N SER A 146 332.435 334.621 310.219 1.00 73.41 N +ATOM 1022 CA SER A 146 331.221 333.987 309.709 1.00 73.41 C +ATOM 1023 C SER A 146 330.036 334.915 309.938 1.00 73.41 C +ATOM 1024 O SER A 146 329.545 335.069 311.055 1.00 73.41 O +ATOM 1025 CB SER A 146 331.003 332.640 310.385 1.00 73.41 C +ATOM 1026 OG SER A 146 329.808 332.035 309.933 1.00 73.41 O +ATOM 1027 N TYR A 147 329.565 335.537 308.858 1.00 73.41 N +ATOM 1028 CA TYR A 147 328.436 336.453 308.900 1.00 73.41 C +ATOM 1029 C TYR A 147 327.413 336.080 307.840 1.00 73.41 C +ATOM 1030 O TYR A 147 327.768 335.614 306.755 1.00 73.41 O +ATOM 1031 CB TYR A 147 328.886 337.899 308.685 1.00 73.41 C +ATOM 1032 CG TYR A 147 329.641 338.485 309.851 1.00 73.41 C +ATOM 1033 CD1 TYR A 147 329.046 338.604 311.098 1.00 73.41 C +ATOM 1034 CD2 TYR A 147 330.946 338.928 309.705 1.00 73.41 C +ATOM 1035 CE1 TYR A 147 329.731 339.139 312.167 1.00 73.41 C +ATOM 1036 CE2 TYR A 147 331.637 339.466 310.768 1.00 73.41 C +ATOM 1037 CZ TYR A 147 331.026 339.571 311.995 1.00 73.41 C +ATOM 1038 OH TYR A 147 331.715 340.108 313.055 1.00 73.41 O +ATOM 1039 N LEU A 148 326.142 336.288 308.164 1.00 73.41 N +ATOM 1040 CA LEU A 148 325.040 336.137 307.224 1.00 73.41 C +ATOM 1041 C LEU A 148 324.264 337.443 307.177 1.00 73.41 C +ATOM 1042 O LEU A 148 323.991 338.039 308.222 1.00 73.41 O +ATOM 1043 CB LEU A 148 324.120 334.989 307.636 1.00 73.41 C +ATOM 1044 CG LEU A 148 322.820 334.847 306.846 1.00 73.41 C +ATOM 1045 CD1 LEU A 148 323.107 334.521 305.396 1.00 73.41 C +ATOM 1046 CD2 LEU A 148 321.939 333.782 307.469 1.00 73.41 C +ATOM 1047 N VAL A 149 323.916 337.893 305.974 1.00 73.41 N +ATOM 1048 CA VAL A 149 323.136 339.110 305.797 1.00 73.41 C +ATOM 1049 C VAL A 149 321.928 338.797 304.926 1.00 73.41 C +ATOM 1050 O VAL A 149 322.046 338.121 303.900 1.00 73.41 O +ATOM 1051 CB VAL A 149 323.978 340.255 305.194 1.00 73.41 C +ATOM 1052 CG1 VAL A 149 325.053 340.683 306.170 1.00 73.41 C +ATOM 1053 CG2 VAL A 149 324.610 339.833 303.894 1.00 73.41 C +ATOM 1054 N TYR A 150 320.760 339.269 305.354 1.00 73.41 N +ATOM 1055 CA TYR A 150 319.512 339.047 304.640 1.00 73.41 C +ATOM 1056 C TYR A 150 318.691 340.324 304.689 1.00 73.41 C +ATOM 1057 O TYR A 150 318.763 341.063 305.678 1.00 73.41 O +ATOM 1058 CB TYR A 150 318.723 337.874 305.245 1.00 73.41 C +ATOM 1059 CG TYR A 150 318.286 338.096 306.675 1.00 73.41 C +ATOM 1060 CD1 TYR A 150 317.007 338.543 306.970 1.00 73.41 C +ATOM 1061 CD2 TYR A 150 319.156 337.861 307.729 1.00 73.41 C +ATOM 1062 CE1 TYR A 150 316.606 338.747 308.275 1.00 73.41 C +ATOM 1063 CE2 TYR A 150 318.764 338.062 309.036 1.00 73.41 C +ATOM 1064 CZ TYR A 150 317.488 338.506 309.304 1.00 73.41 C +ATOM 1065 OH TYR A 150 317.095 338.708 310.605 1.00 73.41 O +ATOM 1066 N PRO A 151 317.908 340.615 303.653 1.00 73.41 N +ATOM 1067 CA PRO A 151 317.151 341.870 303.634 1.00 73.41 C +ATOM 1068 C PRO A 151 315.933 341.817 304.543 1.00 73.41 C +ATOM 1069 O PRO A 151 315.339 340.759 304.769 1.00 73.41 O +ATOM 1070 CB PRO A 151 316.738 342.012 302.166 1.00 73.41 C +ATOM 1071 CG PRO A 151 316.691 340.623 301.655 1.00 73.41 C +ATOM 1072 CD PRO A 151 317.662 339.799 302.450 1.00 73.41 C +ATOM 1073 N SER A 152 315.560 342.985 305.061 1.00 73.41 N +ATOM 1074 CA SER A 152 314.405 343.125 305.949 1.00 73.41 C +ATOM 1075 C SER A 152 313.527 344.266 305.461 1.00 73.41 C +ATOM 1076 O SER A 152 313.665 345.413 305.903 1.00 73.41 O +ATOM 1077 CB SER A 152 314.847 343.355 307.396 1.00 73.41 C +ATOM 1078 OG SER A 152 313.749 343.241 308.282 1.00 73.41 O +ATOM 1079 N PRO A 153 312.615 343.990 304.536 1.00 73.41 N +ATOM 1080 CA PRO A 153 311.701 345.026 304.061 1.00 73.41 C +ATOM 1081 C PRO A 153 310.547 345.214 305.029 1.00 73.41 C +ATOM 1082 O PRO A 153 310.175 344.274 305.749 1.00 73.41 O +ATOM 1083 CB PRO A 153 311.217 344.467 302.719 1.00 73.41 C +ATOM 1084 CG PRO A 153 311.217 342.990 302.941 1.00 73.41 C +ATOM 1085 CD PRO A 153 312.376 342.697 303.868 1.00 73.41 C +ATOM 1086 N PRO A 154 309.958 346.405 305.086 1.00 73.41 N +ATOM 1087 CA PRO A 154 308.764 346.597 305.914 1.00 73.41 C +ATOM 1088 C PRO A 154 307.612 345.730 305.442 1.00 73.41 C +ATOM 1089 O PRO A 154 307.421 345.495 304.247 1.00 73.41 O +ATOM 1090 CB PRO A 154 308.439 348.086 305.742 1.00 73.41 C +ATOM 1091 CG PRO A 154 309.167 348.525 304.536 1.00 73.41 C +ATOM 1092 CD PRO A 154 310.346 347.624 304.358 1.00 73.41 C +ATOM 1093 N LYS A 155 306.838 345.248 306.409 1.00 73.41 N +ATOM 1094 CA LYS A 155 305.699 344.388 306.114 1.00 75.33 C +ATOM 1095 C LYS A 155 304.459 345.242 305.882 1.00 75.33 C +ATOM 1096 O LYS A 155 304.144 346.123 306.691 1.00 75.33 O +ATOM 1097 CB LYS A 155 305.467 343.396 307.251 1.00 75.33 C +ATOM 1098 CG LYS A 155 304.382 342.378 306.961 1.00 75.33 C +ATOM 1099 CD LYS A 155 304.298 341.332 308.057 1.00 75.33 C +ATOM 1100 CE LYS A 155 303.204 340.320 307.763 1.00 75.33 C +ATOM 1101 NZ LYS A 155 303.117 339.270 308.813 1.00 75.33 N +ATOM 1102 N VAL A 156 303.761 344.984 304.783 1.00 73.41 N +ATOM 1103 CA VAL A 156 302.559 345.734 304.445 1.00 73.41 C +ATOM 1104 C VAL A 156 301.318 344.884 304.692 1.00 73.41 C +ATOM 1105 O VAL A 156 301.402 343.660 304.794 1.00 73.41 O +ATOM 1106 CB VAL A 156 302.602 346.223 302.988 1.00 73.41 C +ATOM 1107 CG1 VAL A 156 302.619 345.039 302.034 1.00 73.41 C +ATOM 1108 CG2 VAL A 156 301.415 347.127 302.702 1.00 73.41 C +ATOM 1109 N ILE A 222 312.280 356.102 302.625 1.00 73.41 N +ATOM 1110 CA ILE A 222 311.156 355.180 302.531 1.00 73.41 C +ATOM 1111 C ILE A 222 311.483 353.918 303.323 1.00 73.41 C +ATOM 1112 O ILE A 222 310.593 353.259 303.862 1.00 73.41 O +ATOM 1113 CB ILE A 222 310.825 354.855 301.065 1.00 73.41 C +ATOM 1114 CG1 ILE A 222 310.680 356.145 300.257 1.00 73.41 C +ATOM 1115 CG2 ILE A 222 309.535 354.059 300.973 1.00 73.41 C +ATOM 1116 CD1 ILE A 222 310.573 355.922 298.766 1.00 73.41 C +ATOM 1117 N LYS A 223 312.776 353.600 303.382 1.00 73.41 N +ATOM 1118 CA LYS A 223 313.296 352.491 304.187 1.00 73.41 C +ATOM 1119 C LYS A 223 312.741 351.143 303.729 1.00 73.41 C +ATOM 1120 O LYS A 223 312.125 350.409 304.503 1.00 73.41 O +ATOM 1121 CB LYS A 223 313.030 352.709 305.681 1.00 73.41 C +ATOM 1122 CG LYS A 223 313.561 354.026 306.278 1.00 73.41 C +ATOM 1123 CD LYS A 223 314.876 354.544 305.672 1.00 73.41 C +ATOM 1124 CE LYS A 223 316.032 353.543 305.753 1.00 73.41 C +ATOM 1125 NZ LYS A 223 317.220 354.021 304.997 1.00 73.41 N +ATOM 1126 N ASN A 224 312.966 350.815 302.459 1.00 73.41 N +ATOM 1127 CA ASN A 224 312.699 349.483 301.933 1.00 73.41 C +ATOM 1128 C ASN A 224 313.952 348.624 301.865 1.00 73.41 C +ATOM 1129 O ASN A 224 313.871 347.398 301.984 1.00 73.41 O +ATOM 1130 CB ASN A 224 312.063 349.575 300.539 1.00 73.41 C +ATOM 1131 CG ASN A 224 310.609 349.984 300.587 1.00 73.41 C +ATOM 1132 OD1 ASN A 224 310.241 351.067 300.132 1.00 73.41 O +ATOM 1133 ND2 ASN A 224 309.767 349.115 301.132 1.00 73.41 N +ATOM 1134 N GLY A 225 315.115 349.241 301.671 1.00 73.41 N +ATOM 1135 CA GLY A 225 316.352 348.500 301.543 1.00 73.41 C +ATOM 1136 C GLY A 225 317.102 348.307 302.844 1.00 73.41 C +ATOM 1137 O GLY A 225 318.296 348.607 302.924 1.00 73.41 O +ATOM 1138 N ASP A 226 316.416 347.821 303.872 1.00 73.41 N +ATOM 1139 CA ASP A 226 317.078 347.483 305.120 1.00 73.41 C +ATOM 1140 C ASP A 226 317.542 346.034 305.100 1.00 73.41 C +ATOM 1141 O ASP A 226 316.803 345.125 304.712 1.00 73.41 O +ATOM 1142 CB ASP A 226 316.149 347.716 306.312 1.00 73.41 C +ATOM 1143 CG ASP A 226 316.069 349.175 306.708 1.00 73.41 C +ATOM 1144 OD1 ASP A 226 316.867 349.978 306.178 1.00 73.41 O +ATOM 1145 OD2 ASP A 226 315.214 349.517 307.552 1.00 73.41 O +ATOM 1146 N VAL A 227 318.784 345.824 305.529 1.00 73.41 N +ATOM 1147 CA VAL A 227 319.402 344.506 305.538 1.00 73.41 C +ATOM 1148 C VAL A 227 319.905 344.220 306.947 1.00 73.41 C +ATOM 1149 O VAL A 227 320.371 345.125 307.647 1.00 73.41 O +ATOM 1150 CB VAL A 227 320.542 344.410 304.498 1.00 73.41 C +ATOM 1151 CG1 VAL A 227 321.725 345.277 304.895 1.00 73.41 C +ATOM 1152 CG2 VAL A 227 320.962 342.968 304.293 1.00 73.41 C +ATOM 1153 N ILE A 228 319.779 342.966 307.373 1.00 73.41 N +ATOM 1154 CA ILE A 228 320.111 342.546 308.729 1.00 73.41 C +ATOM 1155 C ILE A 228 321.444 341.817 308.705 1.00 73.41 C +ATOM 1156 O ILE A 228 321.592 340.807 308.008 1.00 73.41 O +ATOM 1157 CB ILE A 228 319.015 341.640 309.316 1.00 73.41 C +ATOM 1158 CG1 ILE A 228 317.698 342.399 309.457 1.00 73.41 C +ATOM 1159 CG2 ILE A 228 319.447 341.092 310.659 1.00 73.41 C +ATOM 1160 CD1 ILE A 228 317.837 343.731 310.136 1.00 73.41 C +ATOM 1161 N VAL A 229 322.407 342.310 309.476 1.00 73.41 N +ATOM 1162 CA VAL A 229 323.715 341.679 309.609 1.00 73.41 C +ATOM 1163 C VAL A 229 323.639 340.694 310.767 1.00 73.41 C +ATOM 1164 O VAL A 229 323.512 341.099 311.928 1.00 73.41 O +ATOM 1165 CB VAL A 229 324.827 342.713 309.838 1.00 73.41 C +ATOM 1166 CG1 VAL A 229 326.152 342.015 310.052 1.00 73.41 C +ATOM 1167 CG2 VAL A 229 324.909 343.670 308.665 1.00 73.41 C +ATOM 1168 N PHE A 230 323.722 339.407 310.454 1.00 73.41 N +ATOM 1169 CA PHE A 230 323.538 338.338 311.426 1.00 73.41 C +ATOM 1170 C PHE A 230 324.843 337.577 311.587 1.00 73.41 C +ATOM 1171 O PHE A 230 325.468 337.195 310.593 1.00 73.41 O +ATOM 1172 CB PHE A 230 322.418 337.395 310.983 1.00 73.41 C +ATOM 1173 CG PHE A 230 322.009 336.401 312.025 1.00 73.41 C +ATOM 1174 CD1 PHE A 230 321.010 336.701 312.929 1.00 73.41 C +ATOM 1175 CD2 PHE A 230 322.611 335.159 312.089 1.00 73.41 C +ATOM 1176 CE1 PHE A 230 320.626 335.786 313.889 1.00 73.41 C +ATOM 1177 CE2 PHE A 230 322.230 334.239 313.042 1.00 73.41 C +ATOM 1178 CZ PHE A 230 321.235 334.551 313.944 1.00 73.41 C +ATOM 1179 N ASN A 231 325.253 337.359 312.833 1.00 73.41 N +ATOM 1180 CA ASN A 231 326.479 336.631 313.129 1.00 73.41 C +ATOM 1181 C ASN A 231 326.139 335.164 313.362 1.00 73.41 C +ATOM 1182 O ASN A 231 325.331 334.840 314.237 1.00 73.41 O +ATOM 1183 CB ASN A 231 327.183 337.223 314.345 1.00 73.41 C +ATOM 1184 CG ASN A 231 328.604 336.721 314.498 1.00 73.41 C +ATOM 1185 OD1 ASN A 231 328.940 335.622 314.059 1.00 73.41 O +ATOM 1186 ND2 ASN A 231 329.450 337.527 315.125 1.00 73.41 N +ATOM 1187 N LEU A 232 326.753 334.283 312.573 1.00 73.41 N +ATOM 1188 CA LEU A 232 326.457 332.858 312.675 1.00 73.41 C +ATOM 1189 C LEU A 232 327.144 332.215 313.870 1.00 73.41 C +ATOM 1190 O LEU A 232 326.637 331.230 314.417 1.00 73.41 O +ATOM 1191 CB LEU A 232 326.873 332.151 311.387 1.00 73.41 C +ATOM 1192 CG LEU A 232 326.005 332.473 310.175 1.00 73.41 C +ATOM 1193 CD1 LEU A 232 326.822 332.359 308.915 1.00 73.41 C +ATOM 1194 CD2 LEU A 232 324.813 331.545 310.123 1.00 73.41 C +ATOM 1195 N GLU A 233 328.298 332.744 314.278 1.00 73.41 N +ATOM 1196 CA GLU A 233 329.057 332.131 315.363 1.00 73.41 C +ATOM 1197 C GLU A 233 328.277 332.158 316.671 1.00 73.41 C +ATOM 1198 O GLU A 233 328.107 331.124 317.326 1.00 73.41 O +ATOM 1199 CB GLU A 233 330.398 332.844 315.521 1.00 73.41 C +ATOM 1200 CG GLU A 233 331.379 332.135 316.426 1.00 73.41 C +ATOM 1201 CD GLU A 233 332.678 332.897 316.567 1.00 73.41 C +ATOM 1202 OE1 GLU A 233 332.783 334.003 315.997 1.00 73.41 O +ATOM 1203 OE2 GLU A 233 333.596 332.392 317.246 1.00 73.41 O +ATOM 1204 N THR A 234 327.790 333.332 317.064 1.00 73.41 N +ATOM 1205 CA THR A 234 327.047 333.493 318.305 1.00 73.41 C +ATOM 1206 C THR A 234 325.538 333.426 318.113 1.00 73.41 C +ATOM 1207 O THR A 234 324.804 333.443 319.105 1.00 73.41 O +ATOM 1208 CB THR A 234 327.416 334.821 318.968 1.00 73.41 C +ATOM 1209 OG1 THR A 234 326.968 335.905 318.146 1.00 73.41 O +ATOM 1210 CG2 THR A 234 328.919 334.923 319.135 1.00 73.41 C +ATOM 1211 N LEU A 235 325.066 333.345 316.871 1.00 73.41 N +ATOM 1212 CA LEU A 235 323.641 333.290 316.543 1.00 73.41 C +ATOM 1213 C LEU A 235 322.884 334.479 317.144 1.00 73.41 C +ATOM 1214 O LEU A 235 321.840 334.340 317.779 1.00 73.41 O +ATOM 1215 CB LEU A 235 323.025 331.964 316.995 1.00 73.41 C +ATOM 1216 CG LEU A 235 323.522 330.712 316.274 1.00 73.41 C +ATOM 1217 CD1 LEU A 235 322.869 329.470 316.850 1.00 73.41 C +ATOM 1218 CD2 LEU A 235 323.254 330.817 314.789 1.00 73.41 C +ATOM 1219 N GLN A 236 323.448 335.668 316.916 1.00 73.41 N +ATOM 1220 CA GLN A 236 322.776 336.895 317.320 1.00 73.41 C +ATOM 1221 C GLN A 236 323.060 337.964 316.282 1.00 73.41 C +ATOM 1222 O GLN A 236 324.192 338.038 315.784 1.00 73.41 O +ATOM 1223 CB GLN A 236 323.227 337.361 318.711 1.00 73.41 C +ATOM 1224 CG GLN A 236 324.532 338.141 318.746 1.00 73.41 C +ATOM 1225 CD GLN A 236 324.935 338.546 320.146 1.00 73.41 C +ATOM 1226 OE1 GLN A 236 325.530 337.764 320.883 1.00 73.41 O +ATOM 1227 NE2 GLN A 236 324.614 339.777 320.520 1.00 73.41 N +ATOM 1228 N PRO A 237 322.071 338.770 315.900 1.00 73.41 N +ATOM 1229 CA PRO A 237 322.335 339.861 314.956 1.00 73.41 C +ATOM 1230 C PRO A 237 323.265 340.900 315.559 1.00 73.41 C +ATOM 1231 O PRO A 237 323.276 341.125 316.772 1.00 73.41 O +ATOM 1232 CB PRO A 237 320.944 340.445 314.685 1.00 73.41 C +ATOM 1233 CG PRO A 237 320.104 339.996 315.822 1.00 73.41 C +ATOM 1234 CD PRO A 237 320.650 338.677 316.262 1.00 73.41 C +ATOM 1235 N THR A 238 324.056 341.530 314.699 1.00 73.41 N +ATOM 1236 CA THR A 238 325.022 342.528 315.138 1.00 73.41 C +ATOM 1237 C THR A 238 324.558 343.957 314.908 1.00 73.41 C +ATOM 1238 O THR A 238 324.649 344.778 315.826 1.00 73.41 O +ATOM 1239 CB THR A 238 326.363 342.319 314.428 1.00 73.41 C +ATOM 1240 OG1 THR A 238 326.863 341.012 314.728 1.00 73.41 O +ATOM 1241 CG2 THR A 238 327.377 343.354 314.888 1.00 73.41 C +ATOM 1242 N MET A 239 324.058 344.278 313.718 1.00 73.41 N +ATOM 1243 CA MET A 239 323.613 345.634 313.425 1.00 73.41 C +ATOM 1244 C MET A 239 322.665 345.588 312.235 1.00 73.41 C +ATOM 1245 O MET A 239 322.566 344.578 311.534 1.00 73.41 O +ATOM 1246 CB MET A 239 324.794 346.563 313.147 1.00 73.41 C +ATOM 1247 CG MET A 239 325.629 346.162 311.953 1.00 73.41 C +ATOM 1248 SD MET A 239 327.376 346.496 312.224 1.00 73.41 S +ATOM 1249 CE MET A 239 327.383 348.281 312.144 1.00 73.41 C +ATOM 1250 N VAL A 240 321.967 346.701 312.023 1.00 76.84 N +ATOM 1251 CA VAL A 240 321.039 346.866 310.912 1.00 76.84 C +ATOM 1252 C VAL A 240 321.583 347.964 310.013 1.00 76.84 C +ATOM 1253 O VAL A 240 321.881 349.068 310.487 1.00 76.84 O +ATOM 1254 CB VAL A 240 319.622 347.206 311.392 1.00 76.84 C +ATOM 1255 CG1 VAL A 240 318.669 347.261 310.218 1.00 76.84 C +ATOM 1256 CG2 VAL A 240 319.154 346.184 312.407 1.00 76.84 C +ATOM 1257 N ILE A 241 321.717 347.664 308.725 1.00 76.84 N +ATOM 1258 CA ILE A 241 322.300 348.584 307.756 1.00 76.84 C +ATOM 1259 C ILE A 241 321.191 349.134 306.875 1.00 73.41 C +ATOM 1260 O ILE A 241 320.451 348.371 306.241 1.00 73.41 O +ATOM 1261 CB ILE A 241 323.381 347.894 306.909 1.00 73.41 C +ATOM 1262 CG1 ILE A 241 324.499 347.350 307.795 1.00 73.41 C +ATOM 1263 CG2 ILE A 241 323.963 348.869 305.908 1.00 73.41 C +ATOM 1264 CD1 ILE A 241 325.217 348.418 308.586 1.00 73.41 C +ATOM 1265 N GLU A 242 321.071 350.461 306.839 1.00 73.41 N +ATOM 1266 CA GLU A 242 320.146 351.140 305.935 1.00 73.41 C +ATOM 1267 C GLU A 242 320.836 351.256 304.580 1.00 73.41 C +ATOM 1268 O GLU A 242 321.432 352.277 304.227 1.00 73.41 O +ATOM 1269 CB GLU A 242 319.748 352.499 306.490 1.00 73.41 C +ATOM 1270 CG GLU A 242 318.994 352.428 307.807 1.00 73.41 C +ATOM 1271 CD GLU A 242 318.677 353.797 308.374 1.00 73.41 C +ATOM 1272 OE1 GLU A 242 319.024 354.805 307.726 1.00 73.41 O +ATOM 1273 OE2 GLU A 242 318.077 353.861 309.469 1.00 73.41 O +ATOM 1274 N ALA A 243 320.747 350.172 303.808 1.00 73.41 N +ATOM 1275 CA ALA A 243 321.537 350.071 302.586 1.00 73.41 C +ATOM 1276 C ALA A 243 321.028 351.019 301.508 1.00 73.41 C +ATOM 1277 O ALA A 243 321.748 351.927 301.078 1.00 73.41 O +ATOM 1278 CB ALA A 243 321.529 348.628 302.082 1.00 73.41 C +ATOM 1279 N HIS A 244 319.787 350.833 301.066 1.00 73.41 N +ATOM 1280 CA HIS A 244 319.268 351.574 299.927 1.00 73.41 C +ATOM 1281 C HIS A 244 317.837 352.010 300.194 1.00 73.41 C +ATOM 1282 O HIS A 244 317.181 351.538 301.126 1.00 73.41 O +ATOM 1283 CB HIS A 244 319.323 350.743 298.638 1.00 73.41 C +ATOM 1284 CG HIS A 244 320.691 350.643 298.041 1.00 73.41 C +ATOM 1285 ND1 HIS A 244 321.462 349.505 298.136 1.00 73.41 N +ATOM 1286 CD2 HIS A 244 321.432 351.543 297.353 1.00 73.41 C +ATOM 1287 CE1 HIS A 244 322.616 349.705 297.524 1.00 73.41 C +ATOM 1288 NE2 HIS A 244 322.622 350.935 297.041 1.00 73.41 N +ATOM 1289 N LYS A 245 317.363 352.935 299.357 1.00 73.41 N +ATOM 1290 CA LYS A 245 315.978 353.377 299.410 1.00 73.41 C +ATOM 1291 C LYS A 245 315.013 352.359 298.820 1.00 73.41 C +ATOM 1292 O LYS A 245 313.906 352.197 299.344 1.00 73.41 O +ATOM 1293 CB LYS A 245 315.829 354.711 298.677 1.00 73.41 C +ATOM 1294 CG LYS A 245 314.469 355.359 298.827 1.00 73.41 C +ATOM 1295 CD LYS A 245 314.361 356.609 297.973 1.00 73.41 C +ATOM 1296 CE LYS A 245 315.278 357.705 298.489 1.00 73.41 C +ATOM 1297 NZ LYS A 245 315.507 358.757 297.463 1.00 73.41 N +ATOM 1298 N GLY A 246 315.408 351.663 297.749 1.00 73.41 N +ATOM 1299 CA GLY A 246 314.580 350.654 297.132 1.00 73.41 C +ATOM 1300 C GLY A 246 314.981 349.260 297.588 1.00 73.41 C +ATOM 1301 O GLY A 246 315.945 349.076 298.338 1.00 73.41 O +ATOM 1302 N GLU A 247 314.224 348.272 297.115 1.00 73.41 N +ATOM 1303 CA GLU A 247 314.454 346.892 297.510 1.00 73.41 C +ATOM 1304 C GLU A 247 315.833 346.419 297.069 1.00 73.41 C +ATOM 1305 O GLU A 247 316.344 346.827 296.025 1.00 73.41 O +ATOM 1306 CB GLU A 247 313.377 345.982 296.915 1.00 73.41 C +ATOM 1307 CG GLU A 247 312.055 346.012 297.657 1.00 73.41 C +ATOM 1308 CD GLU A 247 311.103 344.928 297.192 1.00 73.41 C +ATOM 1309 OE1 GLU A 247 311.479 344.150 296.292 1.00 73.41 O +ATOM 1310 OE2 GLU A 247 309.977 344.853 297.725 1.00 73.41 O +ATOM 1311 N ILE A 248 316.438 345.559 297.888 1.00 73.41 N +ATOM 1312 CA ILE A 248 317.736 344.984 297.559 1.00 73.41 C +ATOM 1313 C ILE A 248 317.566 343.917 296.487 1.00 73.41 C +ATOM 1314 O ILE A 248 316.623 343.115 296.527 1.00 73.41 O +ATOM 1315 CB ILE A 248 318.398 344.412 298.824 1.00 73.41 C +ATOM 1316 CG1 ILE A 248 318.625 345.523 299.847 1.00 73.41 C +ATOM 1317 CG2 ILE A 248 319.710 343.739 298.490 1.00 73.41 C +ATOM 1318 CD1 ILE A 248 319.508 346.637 299.342 1.00 73.41 C +ATOM 1319 N ALA A 249 318.474 343.910 295.509 1.00 73.41 N +ATOM 1320 CA ALA A 249 318.410 342.960 294.407 1.00 73.41 C +ATOM 1321 C ALA A 249 319.543 341.945 294.388 1.00 73.41 C +ATOM 1322 O ALA A 249 319.366 340.867 293.811 1.00 73.41 O +ATOM 1323 CB ALA A 249 318.392 343.704 293.063 1.00 73.41 C +ATOM 1324 N ALA A 250 320.690 342.250 294.990 1.00 73.41 N +ATOM 1325 CA ALA A 250 321.803 341.311 295.003 1.00 73.41 C +ATOM 1326 C ALA A 250 322.743 341.653 296.150 1.00 73.41 C +ATOM 1327 O ALA A 250 322.961 342.827 296.461 1.00 73.41 O +ATOM 1328 CB ALA A 250 322.559 341.320 293.672 1.00 73.41 C +ATOM 1329 N MET A 251 323.305 340.614 296.766 1.00 73.41 N +ATOM 1330 CA MET A 251 324.207 340.775 297.896 1.00 73.41 C +ATOM 1331 C MET A 251 325.407 339.855 297.723 1.00 73.41 C +ATOM 1332 O MET A 251 325.282 338.744 297.204 1.00 73.41 O +ATOM 1333 CB MET A 251 323.504 340.471 299.223 1.00 73.41 C +ATOM 1334 CG MET A 251 322.837 341.671 299.862 1.00 73.41 C +ATOM 1335 SD MET A 251 321.694 341.198 301.166 1.00 75.35 S +ATOM 1336 CE MET A 251 320.713 339.976 300.304 1.00 75.35 C +ATOM 1337 N ALA A 252 326.569 340.326 298.174 1.00 75.35 N +ATOM 1338 CA ALA A 252 327.800 339.557 298.078 1.00 75.35 C +ATOM 1339 C ALA A 252 328.733 339.924 299.223 1.00 75.35 C +ATOM 1340 O ALA A 252 328.883 341.100 299.566 1.00 75.35 O +ATOM 1341 CB ALA A 252 328.507 339.795 296.742 1.00 82.15 C +ATOM 1342 N ILE A 253 329.371 338.905 299.798 1.00 82.15 N +ATOM 1343 CA ILE A 253 330.326 339.066 300.889 1.00 82.15 C +ATOM 1344 C ILE A 253 331.680 338.541 300.435 1.00 82.15 C +ATOM 1345 O ILE A 253 331.763 337.472 299.820 1.00 82.15 O +ATOM 1346 CB ILE A 253 329.872 338.336 302.169 1.00 82.15 C +ATOM 1347 CG1 ILE A 253 328.618 338.980 302.742 1.00 82.15 C +ATOM 1348 CG2 ILE A 253 330.968 338.343 303.214 1.00 82.15 C +ATOM 1349 CD1 ILE A 253 328.047 338.227 303.906 1.00 82.15 C +ATOM 1350 N SER A 254 332.736 339.289 300.745 1.00 82.15 N +ATOM 1351 CA SER A 254 334.080 338.889 300.362 1.00 82.15 C +ATOM 1352 C SER A 254 334.463 337.570 301.026 1.00 79.38 C +ATOM 1353 O SER A 254 333.762 337.048 301.897 1.00 79.38 O +ATOM 1354 CB SER A 254 335.092 339.971 300.732 1.00 79.38 C +ATOM 1355 OG SER A 254 334.843 340.468 302.032 1.00 79.38 O +ATOM 1356 N PHE A 255 335.606 337.030 300.595 1.00 79.38 N +ATOM 1357 CA PHE A 255 336.040 335.721 301.072 1.00 79.38 C +ATOM 1358 C PHE A 255 336.312 335.726 302.571 1.00 79.38 C +ATOM 1359 O PHE A 255 335.973 334.762 303.265 1.00 79.38 O +ATOM 1360 CB PHE A 255 337.285 335.279 300.302 1.00 76.22 C +ATOM 1361 CG PHE A 255 337.632 333.832 300.490 1.00 76.22 C +ATOM 1362 CD1 PHE A 255 336.896 332.844 299.862 1.00 76.22 C +ATOM 1363 CD2 PHE A 255 338.700 333.461 301.286 1.00 76.22 C +ATOM 1364 CE1 PHE A 255 337.213 331.513 300.030 1.00 77.24 C +ATOM 1365 CE2 PHE A 255 339.019 332.130 301.457 1.00 77.24 C +ATOM 1366 CZ PHE A 255 338.274 331.156 300.827 1.00 77.24 C +ATOM 1367 N ASP A 256 336.913 336.794 303.087 1.00 77.24 N +ATOM 1368 CA ASP A 256 337.268 336.882 304.495 1.00 77.24 C +ATOM 1369 C ASP A 256 336.127 337.388 305.369 1.00 77.24 C +ATOM 1370 O ASP A 256 336.295 337.483 306.588 1.00 77.24 O +ATOM 1371 CB ASP A 256 338.488 337.788 304.672 1.00 73.81 C +ATOM 1372 CG ASP A 256 338.308 339.139 304.016 1.00 73.81 C +ATOM 1373 OD1 ASP A 256 337.327 339.311 303.263 1.00 73.81 O +ATOM 1374 OD2 ASP A 256 339.145 340.034 304.253 1.00 73.81 O +ATOM 1375 N GLY A 257 334.978 337.714 304.782 1.00 73.81 N +ATOM 1376 CA GLY A 257 333.865 338.224 305.557 1.00 73.81 C +ATOM 1377 C GLY A 257 334.018 339.649 306.034 1.00 73.81 C +ATOM 1378 O GLY A 257 333.361 340.042 306.999 1.00 73.81 O +ATOM 1379 N THR A 258 334.870 340.438 305.385 1.00 73.41 N +ATOM 1380 CA THR A 258 335.133 341.808 305.805 1.00 73.41 C +ATOM 1381 C THR A 258 334.126 342.796 305.222 1.00 73.41 C +ATOM 1382 O THR A 258 333.651 343.690 305.928 1.00 73.41 O +ATOM 1383 CB THR A 258 336.555 342.213 305.406 1.00 73.41 C +ATOM 1384 OG1 THR A 258 337.499 341.415 306.128 1.00 73.41 O +ATOM 1385 CG2 THR A 258 336.806 343.680 305.707 1.00 73.41 C +ATOM 1386 N LEU A 259 333.788 342.649 303.944 1.00 73.41 N +ATOM 1387 CA LEU A 259 332.956 343.608 303.237 1.00 73.41 C +ATOM 1388 C LEU A 259 331.663 342.954 302.767 1.00 73.41 C +ATOM 1389 O LEU A 259 331.569 341.731 302.638 1.00 73.41 O +ATOM 1390 CB LEU A 259 333.703 344.200 302.038 1.00 73.41 C +ATOM 1391 CG LEU A 259 335.112 344.694 302.353 1.00 73.41 C +ATOM 1392 CD1 LEU A 259 335.902 344.921 301.083 1.00 73.41 C +ATOM 1393 CD2 LEU A 259 335.046 345.965 303.173 1.00 73.41 C +ATOM 1394 N MET A 260 330.659 343.792 302.525 1.00 73.41 N +ATOM 1395 CA MET A 260 329.394 343.372 301.943 1.00 73.41 C +ATOM 1396 C MET A 260 328.984 344.375 300.877 1.00 73.41 C +ATOM 1397 O MET A 260 329.081 345.586 301.090 1.00 73.41 O +ATOM 1398 CB MET A 260 328.293 343.265 303.001 1.00 73.41 C +ATOM 1399 CG MET A 260 326.904 343.034 302.428 1.00 73.41 C +ATOM 1400 SD MET A 260 325.588 343.458 303.581 1.00 73.41 S +ATOM 1401 CE MET A 260 326.170 345.039 304.185 1.00 73.41 C +ATOM 1402 N ALA A 261 328.521 343.872 299.735 1.00 73.41 N +ATOM 1403 CA ALA A 261 328.089 344.710 298.626 1.00 73.41 C +ATOM 1404 C ALA A 261 326.618 344.452 298.329 1.00 73.41 C +ATOM 1405 O ALA A 261 326.164 343.306 298.352 1.00 73.41 O +ATOM 1406 CB ALA A 261 328.926 344.450 297.376 1.00 73.41 C +ATOM 1407 N THR A 262 325.881 345.526 298.040 1.00 73.41 N +ATOM 1408 CA THR A 262 324.442 345.452 297.842 1.00 73.41 C +ATOM 1409 C THR A 262 324.065 346.167 296.554 1.00 73.41 C +ATOM 1410 O THR A 262 324.766 347.068 296.090 1.00 73.41 O +ATOM 1411 CB THR A 262 323.673 346.072 299.018 1.00 73.41 C +ATOM 1412 OG1 THR A 262 324.294 347.304 299.401 1.00 73.41 O +ATOM 1413 CG2 THR A 262 323.653 345.131 300.204 1.00 73.41 C +ATOM 1414 N ALA A 263 322.934 345.756 295.984 1.00 73.41 N +ATOM 1415 CA ALA A 263 322.444 346.342 294.746 1.00 73.41 C +ATOM 1416 C ALA A 263 320.936 346.505 294.825 1.00 73.41 C +ATOM 1417 O ALA A 263 320.212 345.560 295.147 1.00 73.41 O +ATOM 1418 CB ALA A 263 322.813 345.484 293.534 1.00 73.41 C +ATOM 1419 N SER A 264 320.470 347.710 294.512 1.00 73.41 N +ATOM 1420 CA SER A 264 319.051 348.023 294.503 1.00 73.41 C +ATOM 1421 C SER A 264 318.394 347.389 293.280 1.00 73.41 C +ATOM 1422 O SER A 264 319.060 346.876 292.380 1.00 73.41 O +ATOM 1423 CB SER A 264 318.839 349.537 294.524 1.00 73.41 C +ATOM 1424 OG SER A 264 319.187 350.115 293.279 1.00 73.41 O +ATOM 1425 N ASP A 265 317.061 347.423 293.251 1.00 73.41 N +ATOM 1426 CA ASP A 265 316.331 346.820 292.142 1.00 73.41 C +ATOM 1427 C ASP A 265 316.517 347.568 290.832 1.00 73.41 C +ATOM 1428 O ASP A 265 316.258 346.991 289.769 1.00 73.41 O +ATOM 1429 CB ASP A 265 314.842 346.729 292.480 1.00 73.41 C +ATOM 1430 CG ASP A 265 314.234 348.077 292.800 1.00 73.41 C +ATOM 1431 OD1 ASP A 265 314.997 349.054 292.953 1.00 73.41 O +ATOM 1432 OD2 ASP A 265 312.993 348.158 292.908 1.00 73.41 O +ATOM 1433 N LYS A 266 316.959 348.822 290.873 1.00 73.41 N +ATOM 1434 CA LYS A 266 317.232 349.584 289.664 1.00 73.41 C +ATOM 1435 C LYS A 266 318.637 349.362 289.125 1.00 73.41 C +ATOM 1436 O LYS A 266 318.903 349.708 287.972 1.00 73.41 O +ATOM 1437 CB LYS A 266 317.013 351.076 289.923 1.00 73.41 C +ATOM 1438 CG LYS A 266 315.555 351.455 290.033 1.00 73.41 C +ATOM 1439 CD LYS A 266 315.389 352.859 290.565 1.00 73.41 C +ATOM 1440 CE LYS A 266 313.937 353.295 290.500 1.00 73.41 C +ATOM 1441 NZ LYS A 266 313.032 352.283 291.111 1.00 73.41 N +ATOM 1442 N GLY A 267 319.537 348.800 289.927 1.00 73.41 N +ATOM 1443 CA GLY A 267 320.862 348.450 289.461 1.00 73.41 C +ATOM 1444 C GLY A 267 321.719 349.619 289.027 1.00 73.41 C +ATOM 1445 O GLY A 267 322.730 349.426 288.348 1.00 73.41 O +ATOM 1446 N THR A 268 321.340 350.835 289.409 1.00 73.41 N +ATOM 1447 CA THR A 268 322.119 352.003 289.025 1.00 73.41 C +ATOM 1448 C THR A 268 323.248 352.309 289.995 1.00 73.41 C +ATOM 1449 O THR A 268 324.305 352.789 289.569 1.00 73.41 O +ATOM 1450 CB THR A 268 321.217 353.231 288.905 1.00 73.41 C +ATOM 1451 OG1 THR A 268 320.412 353.349 290.084 1.00 73.41 O +ATOM 1452 CG2 THR A 268 320.317 353.104 287.699 1.00 73.41 C +ATOM 1453 N ILE A 269 323.057 352.042 291.282 1.00 73.41 N +ATOM 1454 CA ILE A 269 324.057 352.333 292.302 1.00 73.41 C +ATOM 1455 C ILE A 269 324.451 351.033 292.982 1.00 73.41 C +ATOM 1456 O ILE A 269 323.586 350.283 293.450 1.00 73.41 O +ATOM 1457 CB ILE A 269 323.544 353.348 293.339 1.00 73.41 C +ATOM 1458 CG1 ILE A 269 323.507 354.752 292.746 1.00 73.41 C +ATOM 1459 CG2 ILE A 269 324.420 353.333 294.573 1.00 73.41 C +ATOM 1460 CD1 ILE A 269 322.623 355.696 293.514 1.00 73.41 C +ATOM 1461 N ILE A 270 325.753 350.769 293.032 1.00 73.41 N +ATOM 1462 CA ILE A 270 326.313 349.637 293.760 1.00 73.41 C +ATOM 1463 C ILE A 270 326.986 350.177 295.010 1.00 73.41 C +ATOM 1464 O ILE A 270 327.852 351.057 294.926 1.00 73.41 O +ATOM 1465 CB ILE A 270 327.307 348.843 292.898 1.00 73.56 C +ATOM 1466 CG1 ILE A 270 326.593 348.229 291.697 1.00 73.56 C +ATOM 1467 CG2 ILE A 270 327.980 347.766 293.725 1.00 73.56 C +ATOM 1468 CD1 ILE A 270 325.822 346.982 292.027 1.00 73.56 C +ATOM 1469 N ARG A 271 326.583 349.663 296.165 1.00 73.56 N +ATOM 1470 CA ARG A 271 327.106 350.108 297.444 1.00 73.56 C +ATOM 1471 C ARG A 271 327.744 348.940 298.176 1.00 73.56 C +ATOM 1472 O ARG A 271 327.181 347.844 298.241 1.00 77.36 O +ATOM 1473 CB ARG A 271 326.002 350.728 298.307 1.00 77.36 C +ATOM 1474 CG ARG A 271 325.632 352.144 297.914 1.00 77.36 C +ATOM 1475 CD ARG A 271 324.654 352.752 298.904 1.00 77.36 C +ATOM 1476 NE ARG A 271 324.191 354.065 298.474 1.00 77.36 N +ATOM 1477 CZ ARG A 271 323.013 354.583 298.787 1.00 77.36 C +ATOM 1478 NH1 ARG A 271 322.138 353.918 299.524 1.00 77.36 N +ATOM 1479 NH2 ARG A 271 322.703 355.801 298.349 1.00 77.36 N +ATOM 1480 N VAL A 272 328.930 349.184 298.722 1.00 77.36 N +ATOM 1481 CA VAL A 272 329.660 348.193 299.500 1.00 77.36 C +ATOM 1482 C VAL A 272 329.850 348.753 300.904 1.00 77.36 C +ATOM 1483 O VAL A 272 330.226 349.920 301.067 1.00 82.18 O +ATOM 1484 CB VAL A 272 331.009 347.825 298.851 1.00 82.18 C +ATOM 1485 CG1 VAL A 272 331.943 349.024 298.786 1.00 82.18 C +ATOM 1486 CG2 VAL A 272 331.666 346.672 299.588 1.00 82.18 C +ATOM 1487 N PHE A 273 329.543 347.943 301.912 1.00 82.18 N +ATOM 1488 CA PHE A 273 329.670 348.354 303.298 1.00 82.18 C +ATOM 1489 C PHE A 273 330.699 347.489 304.011 1.00 82.18 C +ATOM 1490 O PHE A 273 330.878 346.311 303.698 1.00 82.18 O +ATOM 1491 CB PHE A 273 328.334 348.267 304.048 1.00 78.36 C +ATOM 1492 CG PHE A 273 327.203 348.978 303.369 1.00 78.36 C +ATOM 1493 CD1 PHE A 273 326.328 348.292 302.548 1.00 78.36 C +ATOM 1494 CD2 PHE A 273 327.015 350.337 303.554 1.00 78.36 C +ATOM 1495 CE1 PHE A 273 325.286 348.947 301.927 1.00 78.36 C +ATOM 1496 CE2 PHE A 273 325.978 350.996 302.933 1.00 78.36 C +ATOM 1497 CZ PHE A 273 325.112 350.301 302.119 1.00 78.36 C +ATOM 1498 N ASP A 274 331.374 348.099 304.981 1.00 78.36 N +ATOM 1499 CA ASP A 274 332.293 347.391 305.859 1.00 83.51 C +ATOM 1500 C ASP A 274 331.486 346.799 307.008 1.00 83.51 C +ATOM 1501 O ASP A 274 330.876 347.539 307.787 1.00 83.51 O +ATOM 1502 CB ASP A 274 333.377 348.340 306.366 1.00 83.51 C +ATOM 1503 CG ASP A 274 334.455 347.631 307.152 1.00 83.51 C +ATOM 1504 OD1 ASP A 274 335.265 346.910 306.537 1.00 83.51 O +ATOM 1505 OD2 ASP A 274 334.498 347.808 308.384 1.00 83.51 O +ATOM 1506 N ILE A 275 331.476 345.468 307.110 1.00 83.51 N +ATOM 1507 CA ILE A 275 330.467 344.793 307.924 1.00 83.51 C +ATOM 1508 C ILE A 275 330.704 345.032 309.413 1.00 86.46 C +ATOM 1509 O ILE A 275 329.752 345.083 310.200 1.00 86.46 O +ATOM 1510 CB ILE A 275 330.422 343.292 307.582 1.00 86.46 C +ATOM 1511 CG1 ILE A 275 329.121 342.672 308.083 1.00 86.46 C +ATOM 1512 CG2 ILE A 275 331.603 342.558 308.180 1.00 86.46 C +ATOM 1513 CD1 ILE A 275 328.812 341.342 307.447 1.00 86.46 C +ATOM 1514 N GLU A 276 331.964 345.170 309.830 1.00 86.46 N +ATOM 1515 CA GLU A 276 332.240 345.316 311.257 1.00 88.10 C +ATOM 1516 C GLU A 276 331.918 346.724 311.746 1.00 88.10 C +ATOM 1517 O GLU A 276 331.405 346.906 312.856 1.00 88.10 O +ATOM 1518 CB GLU A 276 333.694 344.946 311.559 1.00 88.10 C +ATOM 1519 CG GLU A 276 334.739 345.769 310.830 1.00 89.98 C +ATOM 1520 CD GLU A 276 335.189 345.123 309.538 1.00 89.98 C +ATOM 1521 OE1 GLU A 276 334.460 344.247 309.027 1.00 89.98 O +ATOM 1522 OE2 GLU A 276 336.270 345.491 309.033 1.00 89.98 O +ATOM 1523 N THR A 277 332.204 347.738 310.929 1.00 89.98 N +ATOM 1524 CA THR A 277 331.941 349.113 311.342 1.00 89.98 C +ATOM 1525 C THR A 277 330.570 349.580 310.871 1.00 89.98 C +ATOM 1526 O THR A 277 329.888 350.333 311.573 1.00 89.98 O +ATOM 1527 CB THR A 277 333.030 350.045 310.810 1.00 81.18 C +ATOM 1528 OG1 THR A 277 332.971 350.083 309.379 1.00 81.18 O +ATOM 1529 CG2 THR A 277 334.404 349.559 311.239 1.00 81.18 C +ATOM 1530 N GLY A 278 330.155 349.148 309.682 1.00 81.18 N +ATOM 1531 CA GLY A 278 328.881 349.537 309.118 1.00 81.18 C +ATOM 1532 C GLY A 278 328.929 350.722 308.181 1.00 81.18 C +ATOM 1533 O GLY A 278 327.896 351.060 307.590 1.00 81.18 O +ATOM 1534 N ASP A 279 330.084 351.358 308.020 1.00 81.18 N +ATOM 1535 CA ASP A 279 330.176 352.536 307.170 1.00 81.18 C +ATOM 1536 C ASP A 279 330.277 352.135 305.705 1.00 82.21 C +ATOM 1537 O ASP A 279 330.972 351.176 305.359 1.00 82.21 O +ATOM 1538 CB ASP A 279 331.383 353.383 307.569 1.00 82.21 C +ATOM 1539 CG ASP A 279 331.204 354.052 308.917 1.00 82.21 C +ATOM 1540 OD1 ASP A 279 330.220 353.729 309.615 1.00 82.21 O +ATOM 1541 OD2 ASP A 279 332.047 354.901 309.278 1.00 82.21 O +ATOM 1542 N LYS A 280 329.581 352.873 304.844 1.00 82.21 N +ATOM 1543 CA LYS A 280 329.701 352.672 303.408 1.00 82.21 C +ATOM 1544 C LYS A 280 331.061 353.173 302.943 1.00 77.83 C +ATOM 1545 O LYS A 280 331.395 354.347 303.132 1.00 77.83 O +ATOM 1546 CB LYS A 280 328.581 353.407 302.678 1.00 77.83 C +ATOM 1547 CG LYS A 280 328.749 353.449 301.173 1.00 77.83 C +ATOM 1548 CD LYS A 280 327.650 354.266 300.519 1.00 77.83 C +ATOM 1549 CE LYS A 280 327.788 355.739 300.855 1.00 77.83 C +ATOM 1550 NZ LYS A 280 327.119 356.599 299.846 1.00 77.83 N +ATOM 1551 N ILE A 281 331.848 352.289 302.333 1.00 77.83 N +ATOM 1552 CA ILE A 281 333.223 352.619 301.980 1.00 77.83 C +ATOM 1553 C ILE A 281 333.286 353.130 300.547 1.00 77.83 C +ATOM 1554 O ILE A 281 333.858 354.192 300.283 1.00 77.83 O +ATOM 1555 CB ILE A 281 334.151 351.408 302.171 1.00 77.83 C +ATOM 1556 CG1 ILE A 281 333.969 350.812 303.565 1.00 75.34 C +ATOM 1557 CG2 ILE A 281 335.595 351.825 301.983 1.00 75.34 C +ATOM 1558 CD1 ILE A 281 334.113 351.822 304.681 1.00 75.34 C +ATOM 1559 N TYR A 282 332.700 352.381 299.613 1.00 75.34 N +ATOM 1560 CA TYR A 282 332.712 352.757 298.208 1.00 75.34 C +ATOM 1561 C TYR A 282 331.296 352.735 297.656 1.00 75.34 C +ATOM 1562 O TYR A 282 330.443 351.973 298.116 1.00 75.34 O +ATOM 1563 CB TYR A 282 333.592 351.829 297.363 1.00 75.34 C +ATOM 1564 CG TYR A 282 334.985 351.613 297.900 1.00 75.34 C +ATOM 1565 CD1 TYR A 282 335.959 352.591 297.770 1.00 73.41 C +ATOM 1566 CD2 TYR A 282 335.331 350.421 298.521 1.00 73.41 C +ATOM 1567 CE1 TYR A 282 337.235 352.394 298.256 1.00 73.41 C +ATOM 1568 CE2 TYR A 282 336.605 350.214 299.006 1.00 73.41 C +ATOM 1569 CZ TYR A 282 337.553 351.204 298.872 1.00 73.41 C +ATOM 1570 OH TYR A 282 338.823 351.002 299.356 1.00 73.41 O +ATOM 1571 N GLN A 283 331.062 353.581 296.655 1.00 73.41 N +ATOM 1572 CA GLN A 283 329.785 353.644 295.954 1.00 73.41 C +ATOM 1573 C GLN A 283 330.070 353.693 294.463 1.00 73.41 C +ATOM 1574 O GLN A 283 330.809 354.570 294.002 1.00 73.41 O +ATOM 1575 CB GLN A 283 328.976 354.868 296.390 1.00 73.41 C +ATOM 1576 CG GLN A 283 327.537 354.873 295.915 1.00 73.41 C +ATOM 1577 CD GLN A 283 326.708 355.929 296.613 1.00 73.41 C +ATOM 1578 OE1 GLN A 283 327.241 356.790 297.312 1.00 73.41 O +ATOM 1579 NE2 GLN A 283 325.396 355.867 296.433 1.00 73.41 N +ATOM 1580 N PHE A 284 329.497 352.758 293.711 1.00 73.41 N +ATOM 1581 CA PHE A 284 329.745 352.652 292.284 1.00 73.41 C +ATOM 1582 C PHE A 284 328.484 352.945 291.485 1.00 73.41 C +ATOM 1583 O PHE A 284 327.383 352.521 291.848 1.00 73.41 O +ATOM 1584 CB PHE A 284 330.266 351.261 291.909 1.00 73.41 C +ATOM 1585 CG PHE A 284 331.399 350.776 292.767 1.00 73.41 C +ATOM 1586 CD1 PHE A 284 332.638 351.387 292.710 1.00 73.41 C +ATOM 1587 CD2 PHE A 284 331.232 349.690 293.604 1.00 73.41 C +ATOM 1588 CE1 PHE A 284 333.678 350.939 293.487 1.00 73.41 C +ATOM 1589 CE2 PHE A 284 332.270 349.238 294.382 1.00 73.41 C +ATOM 1590 CZ PHE A 284 333.494 349.864 294.323 1.00 73.41 C +ATOM 1591 N ARG A 285 328.662 353.668 290.384 1.00 73.41 N +ATOM 1592 CA ARG A 285 327.617 353.872 289.392 1.00 73.41 C +ATOM 1593 C ARG A 285 327.757 352.816 288.307 1.00 73.41 C +ATOM 1594 O ARG A 285 328.859 352.565 287.811 1.00 73.41 O +ATOM 1595 CB ARG A 285 327.706 355.266 288.767 1.00 73.41 C +ATOM 1596 CG ARG A 285 327.488 356.410 289.731 1.00 73.41 C +ATOM 1597 CD ARG A 285 327.468 357.731 288.982 1.00 73.41 C +ATOM 1598 NE ARG A 285 327.255 358.869 289.864 1.00 73.41 N +ATOM 1599 CZ ARG A 285 327.249 360.133 289.462 1.00 73.41 C +ATOM 1600 NH1 ARG A 285 327.437 360.454 288.193 1.00 73.41 N +ATOM 1601 NH2 ARG A 285 327.047 361.097 290.354 1.00 73.41 N +ATOM 1602 N ARG A 286 326.641 352.197 287.940 1.00 73.41 N +ATOM 1603 CA ARG A 286 326.645 351.081 287.006 1.00 73.41 C +ATOM 1604 C ARG A 286 325.885 351.438 285.740 1.00 73.41 C +ATOM 1605 O ARG A 286 324.681 351.699 285.786 1.00 73.41 O +ATOM 1606 CB ARG A 286 326.033 349.840 287.650 1.00 73.41 C +ATOM 1607 CG ARG A 286 325.950 348.659 286.721 1.00 73.41 C +ATOM 1608 CD ARG A 286 325.163 347.546 287.358 1.00 73.41 C +ATOM 1609 NE ARG A 286 324.714 346.579 286.370 1.00 73.41 N +ATOM 1610 CZ ARG A 286 323.464 346.483 285.947 1.00 73.41 C +ATOM 1611 NH1 ARG A 286 322.513 347.268 286.420 1.00 73.41 N +ATOM 1612 NH2 ARG A 286 323.159 345.575 285.027 1.00 73.41 N +ATOM 1613 N GLY A 287 326.586 351.418 284.610 1.00 73.41 N +ATOM 1614 CA GLY A 287 325.962 351.645 283.320 1.00 73.41 C +ATOM 1615 C GLY A 287 325.487 353.062 283.084 1.00 73.41 C +ATOM 1616 O GLY A 287 326.071 354.019 283.604 1.00 73.41 O +ATOM 1617 N THR A 288 324.445 353.211 282.265 1.00 73.41 N +ATOM 1618 CA THR A 288 323.832 354.503 281.984 1.00 73.41 C +ATOM 1619 C THR A 288 322.384 354.557 282.452 1.00 73.41 C +ATOM 1620 O THR A 288 322.003 355.485 283.166 1.00 73.41 O +ATOM 1621 CB THR A 288 323.924 354.821 280.487 1.00 73.41 C +ATOM 1622 OG1 THR A 288 323.105 353.905 279.753 1.00 73.41 O +ATOM 1623 CG2 THR A 288 325.361 354.711 280.007 1.00 73.41 C +ATOM 1624 N TYR A 289 321.563 353.583 282.072 1.00 73.41 N +ATOM 1625 CA TYR A 289 320.177 353.534 282.511 1.00 73.41 C +ATOM 1626 C TYR A 289 319.939 352.343 283.432 1.00 73.41 C +ATOM 1627 O TYR A 289 320.752 351.419 283.512 1.00 73.41 O +ATOM 1628 CB TYR A 289 319.228 353.468 281.315 1.00 73.41 C +ATOM 1629 CG TYR A 289 319.566 352.396 280.308 1.00 73.41 C +ATOM 1630 CD1 TYR A 289 319.079 351.106 280.449 1.00 73.41 C +ATOM 1631 CD2 TYR A 289 320.359 352.678 279.207 1.00 73.41 C +ATOM 1632 CE1 TYR A 289 319.381 350.128 279.530 1.00 73.41 C +ATOM 1633 CE2 TYR A 289 320.666 351.705 278.283 1.00 73.41 C +ATOM 1634 CZ TYR A 289 320.175 350.432 278.448 1.00 73.41 C +ATOM 1635 OH TYR A 289 320.477 349.456 277.529 1.00 73.41 O +ATOM 1636 N ALA A 290 318.813 352.382 284.139 1.00 73.41 N +ATOM 1637 CA ALA A 290 318.488 351.332 285.096 1.00 73.41 C +ATOM 1638 C ALA A 290 318.191 350.020 284.386 1.00 73.41 C +ATOM 1639 O ALA A 290 317.479 349.992 283.379 1.00 73.41 O +ATOM 1640 CB ALA A 290 317.291 351.751 285.945 1.00 73.41 C +ATOM 1641 N THR A 291 318.739 348.931 284.916 1.00 73.41 N +ATOM 1642 CA THR A 291 318.475 347.595 284.406 1.00 73.41 C +ATOM 1643 C THR A 291 318.766 346.568 285.492 1.00 73.41 C +ATOM 1644 O THR A 291 319.478 346.840 286.462 1.00 73.41 O +ATOM 1645 CB THR A 291 319.299 347.296 283.147 1.00 73.41 C +ATOM 1646 OG1 THR A 291 318.854 346.067 282.562 1.00 73.41 O +ATOM 1647 CG2 THR A 291 320.774 347.197 283.479 1.00 73.41 C +ATOM 1648 N ARG A 292 318.207 345.374 285.315 1.00 73.41 N +ATOM 1649 CA ARG A 292 318.266 344.346 286.344 1.00 73.41 C +ATOM 1650 C ARG A 292 319.693 343.844 286.536 1.00 73.41 C +ATOM 1651 O ARG A 292 320.515 343.867 285.616 1.00 73.41 O +ATOM 1652 CB ARG A 292 317.337 343.188 285.975 1.00 73.41 C +ATOM 1653 CG ARG A 292 317.178 342.123 287.045 1.00 73.41 C +ATOM 1654 CD ARG A 292 316.046 341.172 286.697 1.00 73.41 C +ATOM 1655 NE ARG A 292 315.850 340.149 287.719 1.00 73.41 N +ATOM 1656 CZ ARG A 292 316.396 338.943 287.687 1.00 73.41 C +ATOM 1657 NH1 ARG A 292 317.167 338.560 286.681 1.00 73.41 N +ATOM 1658 NH2 ARG A 292 316.158 338.096 288.683 1.00 73.41 N +ATOM 1659 N ILE A 293 319.991 343.402 287.756 1.00 73.41 N +ATOM 1660 CA ILE A 293 321.288 342.838 288.115 1.00 73.41 C +ATOM 1661 C ILE A 293 321.085 341.378 288.488 1.00 73.41 C +ATOM 1662 O ILE A 293 320.179 341.050 289.262 1.00 73.41 O +ATOM 1663 CB ILE A 293 321.943 343.608 289.274 1.00 73.41 C +ATOM 1664 CG1 ILE A 293 322.429 344.971 288.799 1.00 73.41 C +ATOM 1665 CG2 ILE A 293 323.106 342.824 289.840 1.00 73.41 C +ATOM 1666 CD1 ILE A 293 323.231 345.706 289.833 1.00 73.41 C +ATOM 1667 N TYR A 294 321.924 340.503 287.937 1.00 73.41 N +ATOM 1668 CA TYR A 294 321.784 339.074 288.189 1.00 73.41 C +ATOM 1669 C TYR A 294 322.528 338.620 289.437 1.00 73.41 C +ATOM 1670 O TYR A 294 321.941 337.948 290.291 1.00 73.41 O +ATOM 1671 CB TYR A 294 322.274 338.273 286.985 1.00 73.41 C +ATOM 1672 CG TYR A 294 321.491 338.532 285.725 1.00 73.41 C +ATOM 1673 CD1 TYR A 294 320.175 338.121 285.603 1.00 73.41 C +ATOM 1674 CD2 TYR A 294 322.078 339.172 284.646 1.00 73.41 C +ATOM 1675 CE1 TYR A 294 319.461 338.354 284.449 1.00 73.41 C +ATOM 1676 CE2 TYR A 294 321.374 339.398 283.493 1.00 73.41 C +ATOM 1677 CZ TYR A 294 320.068 338.996 283.397 1.00 73.41 C +ATOM 1678 OH TYR A 294 319.377 339.235 282.235 1.00 73.41 O +ATOM 1679 N SER A 295 323.810 338.961 289.561 1.00 73.41 N +ATOM 1680 CA SER A 295 324.598 338.512 290.698 1.00 73.41 C +ATOM 1681 C SER A 295 325.816 339.405 290.877 1.00 73.41 C +ATOM 1682 O SER A 295 326.252 340.083 289.944 1.00 73.41 O +ATOM 1683 CB SER A 295 325.046 337.059 290.525 1.00 73.41 C +ATOM 1684 OG SER A 295 326.108 336.970 289.592 1.00 73.41 O +ATOM 1685 N ILE A 296 326.361 339.391 292.091 1.00 73.41 N +ATOM 1686 CA ILE A 296 327.583 340.103 292.434 1.00 73.41 C +ATOM 1687 C ILE A 296 328.539 339.114 293.085 1.00 73.41 C +ATOM 1688 O ILE A 296 328.103 338.180 293.768 1.00 73.41 O +ATOM 1689 CB ILE A 296 327.314 341.296 293.378 1.00 73.41 C +ATOM 1690 CG1 ILE A 296 326.065 342.056 292.946 1.00 73.41 C +ATOM 1691 CG2 ILE A 296 328.488 342.246 293.396 1.00 73.41 C +ATOM 1692 CD1 ILE A 296 325.723 343.201 293.858 1.00 73.41 C +ATOM 1693 N SER A 297 329.838 339.307 292.868 1.00 73.41 N +ATOM 1694 CA SER A 297 330.837 338.424 293.453 1.00 73.41 C +ATOM 1695 C SER A 297 332.152 339.173 293.605 1.00 79.14 C +ATOM 1696 O SER A 297 332.522 339.966 292.735 1.00 79.14 O +ATOM 1697 CB SER A 297 331.037 337.174 292.594 1.00 79.14 C +ATOM 1698 OG SER A 297 331.643 337.501 291.357 1.00 79.14 O +ATOM 1699 N PHE A 298 332.848 338.913 294.708 1.00 79.14 N +ATOM 1700 CA PHE A 298 334.138 339.535 294.969 1.00 79.14 C +ATOM 1701 C PHE A 298 335.266 338.703 294.380 1.00 85.05 C +ATOM 1702 O PHE A 298 335.077 337.542 294.010 1.00 85.05 O +ATOM 1703 CB PHE A 298 334.362 339.692 296.471 1.00 85.05 C +ATOM 1704 CG PHE A 298 333.610 340.827 297.089 1.00 85.05 C +ATOM 1705 CD1 PHE A 298 334.188 342.078 297.198 1.00 85.05 C +ATOM 1706 CD2 PHE A 298 332.330 340.642 297.575 1.00 85.05 C +ATOM 1707 CE1 PHE A 298 333.503 343.121 297.768 1.00 85.05 C +ATOM 1708 CE2 PHE A 298 331.640 341.680 298.149 1.00 85.05 C +ATOM 1709 CZ PHE A 298 332.228 342.923 298.246 1.00 85.05 C +ATOM 1710 N SER A 299 336.447 339.307 294.295 1.00 86.05 N +ATOM 1711 CA SER A 299 337.649 338.539 294.020 1.00 86.05 C +ATOM 1712 C SER A 299 338.116 337.835 295.291 1.00 86.05 C +ATOM 1713 O SER A 299 337.645 338.114 296.396 1.00 86.05 O +ATOM 1714 CB SER A 299 338.755 339.441 293.483 1.00 86.05 C +ATOM 1715 OG SER A 299 339.241 340.304 294.496 1.00 86.05 O +ATOM 1716 N GLU A 300 339.053 336.900 295.121 1.00 86.05 N +ATOM 1717 CA GLU A 300 339.599 336.194 296.276 1.00 86.05 C +ATOM 1718 C GLU A 300 340.342 337.145 297.203 1.00 82.95 C +ATOM 1719 O GLU A 300 340.256 337.022 298.430 1.00 82.95 O +ATOM 1720 CB GLU A 300 340.515 335.063 295.816 1.00 82.95 C +ATOM 1721 CG GLU A 300 339.787 333.940 295.107 1.00 82.95 C +ATOM 1722 CD GLU A 300 338.719 333.305 295.975 1.00 82.95 C +ATOM 1723 OE1 GLU A 300 338.990 333.063 297.170 1.00 82.95 O +ATOM 1724 OE2 GLU A 300 337.608 333.052 295.465 1.00 80.50 O +ATOM 1725 N ASP A 301 341.073 338.100 296.637 1.00 80.50 N +ATOM 1726 CA ASP A 301 341.834 339.069 297.409 1.00 80.50 C +ATOM 1727 C ASP A 301 341.081 340.376 297.620 1.00 80.50 C +ATOM 1728 O ASP A 301 341.691 341.368 298.035 1.00 80.50 O +ATOM 1729 CB ASP A 301 343.176 339.343 296.727 1.00 80.50 C +ATOM 1730 CG ASP A 301 343.030 339.623 295.243 1.00 80.50 C +ATOM 1731 OD1 ASP A 301 341.929 339.394 294.699 1.00 80.50 O +ATOM 1732 OD2 ASP A 301 344.018 340.062 294.620 1.00 80.50 O +ATOM 1733 N SER A 302 339.780 340.402 297.336 1.00 75.70 N +ATOM 1734 CA SER A 302 338.927 341.579 297.479 1.00 75.70 C +ATOM 1735 C SER A 302 339.435 342.770 296.682 1.00 75.70 C +ATOM 1736 O SER A 302 339.212 343.919 297.083 1.00 75.70 O +ATOM 1737 CB SER A 302 338.749 341.973 298.950 1.00 75.70 C +ATOM 1738 OG SER A 302 338.078 340.955 299.673 1.00 75.70 O +ATOM 1739 N GLN A 303 340.131 342.527 295.571 1.00 75.70 N +ATOM 1740 CA GLN A 303 340.651 343.627 294.764 1.00 75.70 C +ATOM 1741 C GLN A 303 339.596 344.149 293.795 1.00 75.70 C +ATOM 1742 O GLN A 303 339.516 345.354 293.539 1.00 75.70 O +ATOM 1743 CB GLN A 303 341.899 343.170 294.009 1.00 75.70 C +ATOM 1744 CG GLN A 303 342.757 344.300 293.472 1.00 75.70 C +ATOM 1745 CD GLN A 303 343.512 345.023 294.563 1.00 73.41 C +ATOM 1746 OE1 GLN A 303 343.105 346.093 295.008 1.00 73.41 O +ATOM 1747 NE2 GLN A 303 344.622 344.442 294.998 1.00 73.41 N +ATOM 1748 N TYR A 304 338.776 343.256 293.247 1.00 73.41 N +ATOM 1749 CA TYR A 304 337.810 343.618 292.222 1.00 73.41 C +ATOM 1750 C TYR A 304 336.439 343.060 292.573 1.00 73.41 C +ATOM 1751 O TYR A 304 336.311 342.085 293.318 1.00 73.41 O +ATOM 1752 CB TYR A 304 338.237 343.103 290.840 1.00 73.41 C +ATOM 1753 CG TYR A 304 339.676 343.393 290.488 1.00 73.41 C +ATOM 1754 CD1 TYR A 304 340.038 344.591 289.894 1.00 73.41 C +ATOM 1755 CD2 TYR A 304 340.672 342.465 290.748 1.00 73.41 C +ATOM 1756 CE1 TYR A 304 341.352 344.858 289.571 1.00 73.41 C +ATOM 1757 CE2 TYR A 304 341.987 342.724 290.428 1.00 73.41 C +ATOM 1758 CZ TYR A 304 342.323 343.921 289.840 1.00 73.41 C +ATOM 1759 OH TYR A 304 343.633 344.182 289.522 1.00 73.41 O +ATOM 1760 N LEU A 305 335.409 343.698 292.019 1.00 73.41 N +ATOM 1761 CA LEU A 305 334.021 343.299 292.221 1.00 73.41 C +ATOM 1762 C LEU A 305 333.347 343.169 290.864 1.00 73.41 C +ATOM 1763 O LEU A 305 333.463 344.066 290.024 1.00 73.41 O +ATOM 1764 CB LEU A 305 333.277 344.317 293.090 1.00 73.41 C +ATOM 1765 CG LEU A 305 331.841 343.961 293.466 1.00 73.41 C +ATOM 1766 CD1 LEU A 305 331.842 342.711 294.310 1.00 73.41 C +ATOM 1767 CD2 LEU A 305 331.174 345.104 294.207 1.00 73.41 C +ATOM 1768 N ALA A 306 332.634 342.065 290.657 1.00 73.41 N +ATOM 1769 CA ALA A 306 332.042 341.754 289.364 1.00 73.41 C +ATOM 1770 C ALA A 306 330.521 341.751 289.448 1.00 73.41 C +ATOM 1771 O ALA A 306 329.940 341.084 290.309 1.00 73.41 O +ATOM 1772 CB ALA A 306 332.528 340.396 288.860 1.00 73.41 C +ATOM 1773 N VAL A 307 329.883 342.488 288.542 1.00 73.41 N +ATOM 1774 CA VAL A 307 328.427 342.534 288.447 1.00 73.41 C +ATOM 1775 C VAL A 307 328.030 342.198 287.016 1.00 73.41 C +ATOM 1776 O VAL A 307 328.734 342.564 286.068 1.00 73.41 O +ATOM 1777 CB VAL A 307 327.852 343.904 288.860 1.00 73.41 C +ATOM 1778 CG1 VAL A 307 328.333 344.291 290.244 1.00 73.41 C +ATOM 1779 CG2 VAL A 307 328.212 344.971 287.850 1.00 73.41 C +ATOM 1780 N THR A 308 326.924 341.479 286.861 1.00 73.41 N +ATOM 1781 CA THR A 308 326.394 341.113 285.557 1.00 73.41 C +ATOM 1782 C THR A 308 324.926 341.497 285.483 1.00 73.41 C +ATOM 1783 O THR A 308 324.168 341.261 286.427 1.00 73.41 O +ATOM 1784 CB THR A 308 326.544 339.614 285.293 1.00 73.41 C +ATOM 1785 OG1 THR A 308 325.475 338.911 285.936 1.00 73.41 O +ATOM 1786 CG2 THR A 308 327.867 339.098 285.826 1.00 73.41 C +ATOM 1787 N GLY A 309 324.522 342.072 284.352 1.00 73.41 N +ATOM 1788 CA GLY A 309 323.161 342.553 284.214 1.00 73.41 C +ATOM 1789 C GLY A 309 322.510 342.216 282.892 1.00 73.41 C +ATOM 1790 O GLY A 309 323.118 341.555 282.047 1.00 73.41 O +ATOM 1791 N SER A 310 321.271 342.664 282.702 1.00 73.41 N +ATOM 1792 CA SER A 310 320.478 342.292 281.537 1.00 73.41 C +ATOM 1793 C SER A 310 320.943 342.979 280.263 1.00 73.41 C +ATOM 1794 O SER A 310 320.430 342.661 279.184 1.00 73.41 O +ATOM 1795 CB SER A 310 319.000 342.606 281.780 1.00 73.41 C +ATOM 1796 OG SER A 310 318.719 343.969 281.515 1.00 73.41 O +ATOM 1797 N SER A 311 321.894 343.902 280.358 1.00 73.41 N +ATOM 1798 CA SER A 311 322.465 344.553 279.189 1.00 73.41 C +ATOM 1799 C SER A 311 323.484 343.683 278.471 1.00 73.41 C +ATOM 1800 O SER A 311 324.177 344.179 277.578 1.00 73.41 O +ATOM 1801 CB SER A 311 323.117 345.881 279.591 1.00 73.41 C +ATOM 1802 OG SER A 311 324.076 345.683 280.614 1.00 73.41 O +ATOM 1803 N LYS A 312 323.600 342.408 278.849 1.00 73.41 N +ATOM 1804 CA LYS A 312 324.548 341.470 278.252 1.00 73.41 C +ATOM 1805 C LYS A 312 325.987 341.952 278.399 1.00 73.41 C +ATOM 1806 O LYS A 312 326.860 341.590 277.603 1.00 73.41 O +ATOM 1807 CB LYS A 312 324.197 341.209 276.780 1.00 73.41 C +ATOM 1808 CG LYS A 312 324.775 339.941 276.176 1.00 73.41 C +ATOM 1809 CD LYS A 312 324.255 339.739 274.762 1.00 73.41 C +ATOM 1810 CE LYS A 312 324.717 340.852 273.838 1.00 73.41 C +ATOM 1811 NZ LYS A 312 326.192 340.871 273.677 1.00 73.41 N +ATOM 1812 N THR A 313 326.251 342.776 279.408 1.00 73.41 N +ATOM 1813 CA THR A 313 327.576 343.310 279.676 1.00 73.41 C +ATOM 1814 C THR A 313 327.924 343.094 281.142 1.00 73.41 C +ATOM 1815 O THR A 313 327.078 343.274 282.023 1.00 73.41 O +ATOM 1816 CB THR A 313 327.649 344.800 279.331 1.00 73.41 C +ATOM 1817 OG1 THR A 313 327.301 344.989 277.955 1.00 73.41 O +ATOM 1818 CG2 THR A 313 329.048 345.345 279.569 1.00 73.41 C +ATOM 1819 N VAL A 314 329.171 342.709 281.395 1.00 73.41 N +ATOM 1820 CA VAL A 314 329.670 342.450 282.739 1.00 73.41 C +ATOM 1821 C VAL A 314 330.671 343.541 283.082 1.00 73.41 C +ATOM 1822 O VAL A 314 331.584 343.821 282.295 1.00 73.41 O +ATOM 1823 CB VAL A 314 330.313 341.059 282.850 1.00 73.41 C +ATOM 1824 CG1 VAL A 314 330.899 340.857 284.233 1.00 73.41 C +ATOM 1825 CG2 VAL A 314 329.292 339.983 282.538 1.00 73.41 C +ATOM 1826 N HIS A 315 330.500 344.158 284.246 1.00 73.41 N +ATOM 1827 CA HIS A 315 331.357 345.243 284.697 1.00 73.41 C +ATOM 1828 C HIS A 315 332.252 344.766 285.832 1.00 73.41 C +ATOM 1829 O HIS A 315 331.864 343.898 286.620 1.00 73.41 O +ATOM 1830 CB HIS A 315 330.531 346.441 285.166 1.00 73.41 C +ATOM 1831 CG HIS A 315 329.749 347.101 284.077 1.00 73.41 C +ATOM 1832 ND1 HIS A 315 330.289 348.061 283.251 1.00 73.41 N +ATOM 1833 CD2 HIS A 315 328.464 346.944 283.680 1.00 73.41 C +ATOM 1834 CE1 HIS A 315 329.373 348.466 282.390 1.00 73.41 C +ATOM 1835 NE2 HIS A 315 328.256 347.803 282.628 1.00 73.41 N +ATOM 1836 N ILE A 316 333.450 345.335 285.908 1.00 73.41 N +ATOM 1837 CA ILE A 316 334.388 345.066 286.989 1.00 73.41 C +ATOM 1838 C ILE A 316 334.698 346.379 287.690 1.00 73.41 C +ATOM 1839 O ILE A 316 335.138 347.342 287.049 1.00 73.41 O +ATOM 1840 CB ILE A 316 335.677 344.410 286.476 1.00 76.75 C +ATOM 1841 CG1 ILE A 316 335.350 343.130 285.711 1.00 76.75 C +ATOM 1842 CG2 ILE A 316 336.601 344.111 287.637 1.00 76.75 C +ATOM 1843 CD1 ILE A 316 334.665 342.091 286.551 1.00 76.75 C +ATOM 1844 N PHE A 317 334.481 346.413 289.000 1.00 76.75 N +ATOM 1845 CA PHE A 317 334.782 347.574 289.821 1.00 76.75 C +ATOM 1846 C PHE A 317 336.002 347.282 290.682 1.00 76.75 C +ATOM 1847 O PHE A 317 336.068 346.243 291.346 1.00 76.75 O +ATOM 1848 CB PHE A 317 333.594 347.944 290.710 1.00 76.75 C +ATOM 1849 CG PHE A 317 332.318 348.175 289.955 1.00 77.82 C +ATOM 1850 CD1 PHE A 317 332.068 349.390 289.343 1.00 77.82 C +ATOM 1851 CD2 PHE A 317 331.359 347.184 289.873 1.00 77.82 C +ATOM 1852 CE1 PHE A 317 330.891 349.604 288.656 1.00 77.82 C +ATOM 1853 CE2 PHE A 317 330.183 347.396 289.192 1.00 77.82 C +ATOM 1854 CZ PHE A 317 329.949 348.606 288.580 1.00 77.82 C +ATOM 1855 N LYS A 318 336.962 348.199 290.673 1.00 77.82 N +ATOM 1856 CA LYS A 318 338.214 348.041 291.401 1.00 77.82 C +ATOM 1857 C LYS A 318 338.029 348.561 292.819 1.00 85.53 C +ATOM 1858 O LYS A 318 337.698 349.735 293.015 1.00 85.53 O +ATOM 1859 CB LYS A 318 339.350 348.785 290.700 1.00 85.53 C +ATOM 1860 CG LYS A 318 340.619 348.892 291.519 1.00 85.53 C +ATOM 1861 CD LYS A 318 341.741 349.522 290.716 1.00 73.41 C +ATOM 1862 CE LYS A 318 342.616 348.472 290.065 1.00 73.41 C +ATOM 1863 NZ LYS A 318 343.769 348.118 290.933 1.00 73.41 N +ATOM 1864 N LEU A 319 338.247 347.689 293.804 1.00 73.41 N +ATOM 1865 CA LEU A 319 338.142 348.047 295.212 1.00 73.41 C +ATOM 1866 C LEU A 319 339.499 348.362 295.828 1.00 73.41 C +ATOM 1867 O LEU A 319 339.643 348.334 297.055 1.00 73.41 O +ATOM 1868 CB LEU A 319 337.452 346.931 295.996 1.00 73.41 C +ATOM 1869 CG LEU A 319 335.986 346.655 295.656 1.00 73.41 C +ATOM 1870 CD1 LEU A 319 335.652 345.189 295.833 1.00 73.41 C +ATOM 1871 CD2 LEU A 319 335.082 347.506 296.521 1.00 73.41 C +ATOM 1872 N GLY A 320 340.503 348.653 295.002 1.00 73.41 N +ATOM 1873 CA GLY A 320 341.817 348.965 295.538 1.00 73.41 C +ATOM 1874 C GLY A 320 341.911 350.376 296.084 1.00 73.41 C +ATOM 1875 O GLY A 320 342.917 350.750 296.693 1.00 73.41 O +ATOM 1876 N HIS A 321 340.872 351.178 295.870 1.00 73.41 N +ATOM 1877 CA HIS A 321 340.868 352.572 296.299 1.00 73.41 C +ATOM 1878 C HIS A 321 340.981 352.688 297.817 1.00 73.41 C +ATOM 1879 O HIS A 321 341.492 353.679 298.336 1.00 73.41 O +ATOM 1880 CB HIS A 321 339.599 353.276 295.818 1.00 73.41 C +ATOM 1881 CG HIS A 321 339.414 353.244 294.334 1.00 73.41 C +ATOM 1882 ND1 HIS A 321 340.149 354.030 293.473 1.00 73.41 N +ATOM 1883 CD2 HIS A 321 338.570 352.525 293.557 1.00 73.41 C +ATOM 1884 CE1 HIS A 321 339.771 353.793 292.231 1.00 73.41 C +ATOM 1885 NE2 HIS A 321 338.812 352.884 292.254 1.00 73.41 N +ATOM 1886 N SER A 409 332.578 354.434 291.857 1.00 73.41 N +ATOM 1887 CA SER A 409 332.497 355.341 290.720 1.00 73.41 C +ATOM 1888 C SER A 409 332.209 354.580 289.431 1.00 77.82 C +ATOM 1889 O SER A 409 331.394 353.660 289.411 1.00 77.82 O +ATOM 1890 CB SER A 409 333.793 356.140 290.580 1.00 77.82 C +ATOM 1891 OG SER A 409 334.890 355.288 290.300 1.00 77.82 O +ATOM 1892 N ARG A 410 332.880 354.979 288.356 1.00 77.82 N +ATOM 1893 CA ARG A 410 332.702 354.312 287.076 1.00 77.82 C +ATOM 1894 C ARG A 410 333.345 352.932 287.101 1.00 77.82 C +ATOM 1895 O ARG A 410 334.330 352.702 287.807 1.00 77.82 O +ATOM 1896 CB ARG A 410 333.307 355.155 285.952 1.00 77.82 C +ATOM 1897 CG ARG A 410 332.544 356.434 285.659 1.00 77.82 C +ATOM 1898 CD ARG A 410 331.271 356.148 284.887 1.00 77.82 C +ATOM 1899 NE ARG A 410 331.551 355.610 283.561 1.00 74.50 N +ATOM 1900 CZ ARG A 410 330.638 355.074 282.764 1.00 74.50 C +ATOM 1901 NH1 ARG A 410 329.369 354.984 283.128 1.00 74.50 N +ATOM 1902 NH2 ARG A 410 331.007 354.616 281.571 1.00 74.50 N +ATOM 1903 N HIS A 411 332.776 352.008 286.327 1.00 74.50 N +ATOM 1904 CA HIS A 411 333.319 350.659 286.251 1.00 73.41 C +ATOM 1905 C HIS A 411 334.742 350.687 285.709 1.00 73.41 C +ATOM 1906 O HIS A 411 335.052 351.394 284.747 1.00 73.41 O +ATOM 1907 CB HIS A 411 332.435 349.777 285.367 1.00 73.41 C +ATOM 1908 CG HIS A 411 332.230 350.318 283.986 1.00 73.41 C +ATOM 1909 ND1 HIS A 411 333.117 350.090 282.958 1.00 73.41 N +ATOM 1910 CD2 HIS A 411 331.237 351.076 283.465 1.00 73.41 C +ATOM 1911 CE1 HIS A 411 332.682 350.686 281.862 1.00 73.41 C +ATOM 1912 NE2 HIS A 411 331.541 351.291 282.143 1.00 73.41 N +ATOM 1913 N PHE A 412 335.616 349.909 286.347 1.00 73.41 N +ATOM 1914 CA PHE A 412 337.015 349.876 285.936 1.00 73.41 C +ATOM 1915 C PHE A 412 337.203 349.215 284.579 1.00 73.41 C +ATOM 1916 O PHE A 412 337.884 349.775 283.712 1.00 73.41 O +ATOM 1917 CB PHE A 412 337.852 349.151 286.988 1.00 73.41 C +ATOM 1918 CG PHE A 412 339.313 349.096 286.665 1.00 73.41 C +ATOM 1919 CD1 PHE A 412 339.973 350.219 286.199 1.00 73.41 C +ATOM 1920 CD2 PHE A 412 340.027 347.924 286.830 1.00 73.41 C +ATOM 1921 CE1 PHE A 412 341.315 350.173 285.903 1.00 73.41 C +ATOM 1922 CE2 PHE A 412 341.370 347.873 286.536 1.00 73.41 C +ATOM 1923 CZ PHE A 412 342.014 348.999 286.072 1.00 73.41 C +ATOM 1924 N ALA A 413 336.611 348.043 284.372 1.00 73.41 N +ATOM 1925 CA ALA A 413 336.750 347.322 283.116 1.00 73.41 C +ATOM 1926 C ALA A 413 335.423 346.655 282.795 1.00 73.41 C +ATOM 1927 O ALA A 413 334.660 346.287 283.691 1.00 73.41 O +ATOM 1928 CB ALA A 413 337.883 346.295 283.184 1.00 73.41 C +ATOM 1929 N SER A 414 335.163 346.490 281.502 1.00 73.41 N +ATOM 1930 CA SER A 414 333.884 345.970 281.048 1.00 73.41 C +ATOM 1931 C SER A 414 334.119 344.743 280.183 1.00 73.41 C +ATOM 1932 O SER A 414 335.067 344.691 279.398 1.00 73.41 O +ATOM 1933 CB SER A 414 333.097 347.022 280.261 1.00 73.41 C +ATOM 1934 OG SER A 414 333.644 347.194 278.967 1.00 73.41 O +ATOM 1935 N LEU A 415 333.237 343.758 280.334 1.00 73.41 N +ATOM 1936 CA LEU A 415 333.307 342.511 279.585 1.00 73.41 C +ATOM 1937 C LEU A 415 332.163 342.483 278.586 1.00 73.41 C +ATOM 1938 O LEU A 415 330.993 342.463 278.979 1.00 73.41 O +ATOM 1939 CB LEU A 415 333.227 341.301 280.518 1.00 73.41 C +ATOM 1940 CG LEU A 415 334.125 341.277 281.754 1.00 73.41 C +ATOM 1941 CD1 LEU A 415 334.131 339.889 282.367 1.00 73.41 C +ATOM 1942 CD2 LEU A 415 335.536 341.711 281.411 1.00 73.41 C +ATOM 1943 N LYS A 416 332.496 342.482 277.301 1.00 73.41 N +ATOM 1944 CA LYS A 416 331.503 342.434 276.239 1.00 73.41 C +ATOM 1945 C LYS A 416 331.506 341.042 275.624 1.00 73.41 C +ATOM 1946 O LYS A 416 332.500 340.626 275.021 1.00 73.41 O +ATOM 1947 CB LYS A 416 331.785 343.496 275.178 1.00 73.41 C +ATOM 1948 CG LYS A 416 332.181 344.842 275.754 1.00 73.41 C +ATOM 1949 CD LYS A 416 331.850 345.974 274.803 1.00 73.41 C +ATOM 1950 CE LYS A 416 332.108 347.323 275.451 1.00 73.41 C +ATOM 1951 NZ LYS A 416 330.843 347.999 275.847 1.00 73.41 N +ATOM 1952 N LEU A 417 330.395 340.328 275.779 1.00 73.41 N +ATOM 1953 CA LEU A 417 330.273 339.003 275.206 1.00 73.41 C +ATOM 1954 C LEU A 417 330.170 339.099 273.684 1.00 73.41 C +ATOM 1955 O LEU A 417 329.864 340.163 273.141 1.00 73.41 O +ATOM 1956 CB LEU A 417 329.053 338.291 275.781 1.00 73.41 C +ATOM 1957 CG LEU A 417 329.068 338.042 277.289 1.00 73.41 C +ATOM 1958 CD1 LEU A 417 328.050 336.983 277.665 1.00 73.41 C +ATOM 1959 CD2 LEU A 417 330.454 337.637 277.749 1.00 73.41 C +ATOM 1960 N PRO A 418 330.446 338.006 272.972 1.00 73.41 N +ATOM 1961 CA PRO A 418 330.297 338.024 271.515 1.00 73.41 C +ATOM 1962 C PRO A 418 328.867 338.344 271.102 1.00 73.41 C +ATOM 1963 O PRO A 418 327.907 338.010 271.797 1.00 73.41 O +ATOM 1964 CB PRO A 418 330.702 336.604 271.097 1.00 73.41 C +ATOM 1965 CG PRO A 418 330.685 335.800 272.355 1.00 73.41 C +ATOM 1966 CD PRO A 418 331.056 336.752 273.435 1.00 73.41 C +ATOM 1967 N VAL A 419 328.743 339.003 269.947 1.00 73.41 N +ATOM 1968 CA VAL A 419 327.462 339.564 269.522 1.00 73.41 C +ATOM 1969 C VAL A 419 326.430 338.463 269.307 1.00 73.41 C +ATOM 1970 O VAL A 419 325.238 338.649 269.577 1.00 73.41 O +ATOM 1971 CB VAL A 419 327.654 340.414 268.253 1.00 73.41 C +ATOM 1972 CG1 VAL A 419 326.325 340.948 267.757 1.00 73.41 C +ATOM 1973 CG2 VAL A 419 328.622 341.552 268.525 1.00 73.41 C +ATOM 1974 N GLU A 420 326.870 337.297 268.833 1.00 73.41 N +ATOM 1975 CA GLU A 420 325.928 336.235 268.490 1.00 73.41 C +ATOM 1976 C GLU A 420 325.220 335.677 269.718 1.00 73.41 C +ATOM 1977 O GLU A 420 324.242 334.932 269.583 1.00 73.41 O +ATOM 1978 CB GLU A 420 326.651 335.111 267.744 1.00 73.41 C +ATOM 1979 CG GLU A 420 327.591 335.582 266.643 1.00 73.41 C +ATOM 1980 CD GLU A 420 328.977 335.922 267.156 1.00 73.41 C +ATOM 1981 OE1 GLU A 420 329.827 336.348 266.346 1.00 73.41 O +ATOM 1982 OE2 GLU A 420 329.218 335.760 268.369 1.00 73.41 O +ATOM 1983 N THR A 421 325.696 336.011 270.915 1.00 73.41 N +ATOM 1984 CA THR A 421 325.092 335.497 272.137 1.00 73.41 C +ATOM 1985 C THR A 421 323.679 336.038 272.314 1.00 73.41 C +ATOM 1986 O THR A 421 323.405 337.206 272.018 1.00 73.41 O +ATOM 1987 CB THR A 421 325.947 335.871 273.346 1.00 73.41 C +ATOM 1988 OG1 THR A 421 326.142 337.290 273.373 1.00 73.41 O +ATOM 1989 CG2 THR A 421 327.293 335.185 273.272 1.00 73.41 C +ATOM 1990 N ASN A 422 322.784 335.183 272.800 1.00 73.41 N +ATOM 1991 CA ASN A 422 321.422 335.604 273.090 1.00 73.41 C +ATOM 1992 C ASN A 422 321.428 336.652 274.195 1.00 73.41 C +ATOM 1993 O ASN A 422 322.249 336.592 275.115 1.00 73.41 O +ATOM 1994 CB ASN A 422 320.576 334.401 273.503 1.00 73.41 C +ATOM 1995 CG ASN A 422 319.093 334.690 273.453 1.00 73.41 C +ATOM 1996 OD1 ASN A 422 318.678 335.826 273.226 1.00 73.41 O +ATOM 1997 ND2 ASN A 422 318.282 333.662 273.668 1.00 73.41 N +ATOM 1998 N SER A 423 320.521 337.625 274.097 1.00 73.41 N +ATOM 1999 CA SER A 423 320.455 338.676 275.105 1.00 73.41 C +ATOM 2000 C SER A 423 319.771 338.220 276.389 1.00 73.41 C +ATOM 2001 O SER A 423 320.067 338.763 277.457 1.00 73.41 O +ATOM 2002 CB SER A 423 319.738 339.900 274.538 1.00 73.41 C +ATOM 2003 OG SER A 423 320.492 340.493 273.497 1.00 73.41 O +ATOM 2004 N HIS A 424 318.871 337.240 276.310 1.00 73.41 N +ATOM 2005 CA HIS A 424 318.100 336.792 277.471 1.00 73.41 C +ATOM 2006 C HIS A 424 318.806 335.610 278.137 1.00 73.41 C +ATOM 2007 O HIS A 424 318.317 334.479 278.167 1.00 73.41 O +ATOM 2008 CB HIS A 424 316.685 336.418 277.052 1.00 73.41 C +ATOM 2009 CG HIS A 424 315.924 337.537 276.414 1.00 73.41 C +ATOM 2010 ND1 HIS A 424 315.381 338.577 277.136 1.00 73.41 N +ATOM 2011 CD2 HIS A 424 315.610 337.775 275.119 1.00 73.41 C +ATOM 2012 CE1 HIS A 424 314.767 339.407 276.314 1.00 73.41 C +ATOM 2013 NE2 HIS A 424 314.892 338.945 275.083 1.00 73.41 N +ATOM 2014 N VAL A 425 319.983 335.890 278.692 1.00 73.41 N +ATOM 2015 CA VAL A 425 320.808 334.861 279.317 1.00 73.41 C +ATOM 2016 C VAL A 425 321.187 335.310 280.721 1.00 73.41 C +ATOM 2017 O VAL A 425 321.672 336.433 280.911 1.00 73.41 O +ATOM 2018 CB VAL A 425 322.065 334.540 278.489 1.00 73.41 C +ATOM 2019 CG1 VAL A 425 321.686 333.804 277.215 1.00 73.41 C +ATOM 2020 CG2 VAL A 425 322.839 335.808 278.157 1.00 73.41 C +ATOM 2021 N MET A 426 320.954 334.444 281.703 1.00 73.41 N +ATOM 2022 CA MET A 426 321.497 334.654 283.034 1.00 73.41 C +ATOM 2023 C MET A 426 323.007 334.457 282.997 1.00 73.41 C +ATOM 2024 O MET A 426 323.505 333.426 282.543 1.00 73.41 O +ATOM 2025 CB MET A 426 320.878 333.670 284.029 1.00 73.41 C +ATOM 2026 CG MET A 426 319.465 333.209 283.684 1.00 73.41 C +ATOM 2027 SD MET A 426 318.205 334.494 283.717 1.00 73.41 S +ATOM 2028 CE MET A 426 318.482 335.164 285.350 1.00 73.41 C +ATOM 2029 N THR A 427 323.744 335.453 283.481 1.00 73.41 N +ATOM 2030 CA THR A 427 325.201 335.393 283.418 1.00 73.41 C +ATOM 2031 C THR A 427 325.775 335.603 284.807 1.00 73.41 C +ATOM 2032 O THR A 427 325.507 336.627 285.440 1.00 73.41 O +ATOM 2033 CB THR A 427 325.764 336.436 282.450 1.00 73.41 C +ATOM 2034 OG1 THR A 427 325.386 337.746 282.881 1.00 73.41 O +ATOM 2035 CG2 THR A 427 325.239 336.201 281.045 1.00 73.41 C +ATOM 2036 N ILE A 428 326.560 334.640 285.271 1.00 73.41 N +ATOM 2037 CA ILE A 428 327.316 334.758 286.509 1.00 73.41 C +ATOM 2038 C ILE A 428 328.793 334.714 286.164 1.00 73.41 C +ATOM 2039 O ILE A 428 329.198 334.122 285.158 1.00 76.91 O +ATOM 2040 CB ILE A 428 326.942 333.644 287.505 1.00 76.91 C +ATOM 2041 CG1 ILE A 428 327.280 332.284 286.913 1.00 76.91 C +ATOM 2042 CG2 ILE A 428 325.465 333.706 287.839 1.00 76.91 C +ATOM 2043 CD1 ILE A 428 327.193 331.166 287.898 1.00 81.59 C +ATOM 2044 N SER A 429 329.613 335.350 286.994 1.00 81.59 N +ATOM 2045 CA SER A 429 331.035 335.455 286.710 1.00 81.59 C +ATOM 2046 C SER A 429 331.836 335.155 287.966 1.00 81.59 C +ATOM 2047 O SER A 429 331.285 334.935 289.046 1.00 81.59 O +ATOM 2048 CB SER A 429 331.404 336.842 286.179 1.00 81.59 C +ATOM 2049 OG SER A 429 331.423 337.795 287.223 1.00 85.64 O +ATOM 2050 N SER A 430 333.155 335.140 287.801 1.00 85.64 N +ATOM 2051 CA SER A 430 334.080 334.960 288.909 1.00 85.64 C +ATOM 2052 C SER A 430 335.427 335.529 288.500 1.00 85.64 C +ATOM 2053 O SER A 430 335.751 335.569 287.313 1.00 85.64 O +ATOM 2054 CB SER A 430 334.224 333.487 289.292 1.00 85.64 C +ATOM 2055 OG SER A 430 334.869 332.771 288.257 1.00 85.64 O +ATOM 2056 N ILE A 431 336.203 335.968 289.482 1.00 90.60 N +ATOM 2057 CA ILE A 431 337.523 336.543 289.240 1.00 90.60 C +ATOM 2058 C ILE A 431 338.560 335.675 289.937 1.00 90.60 C +ATOM 2059 O ILE A 431 338.428 335.369 291.129 1.00 90.60 O +ATOM 2060 CB ILE A 431 337.595 337.998 289.723 1.00 90.60 C +ATOM 2061 CG1 ILE A 431 336.563 338.849 288.987 1.00 90.60 C +ATOM 2062 CG2 ILE A 431 338.986 338.559 289.522 1.00 90.60 C +ATOM 2063 CD1 ILE A 431 336.481 340.265 289.486 1.00 90.60 C +ATOM 2064 N GLY A 432 339.592 335.275 289.197 1.00 97.31 N +ATOM 2065 CA GLY A 432 340.649 334.449 289.734 1.00 97.31 C +ATOM 2066 C GLY A 432 341.929 335.232 289.988 1.00 97.31 C +ATOM 2067 O GLY A 432 342.064 336.396 289.626 1.00 97.31 O +ATOM 2068 N SER A 433 342.875 334.556 290.630 1.00 97.31 N +ATOM 2069 CA SER A 433 344.151 335.176 290.941 1.00 97.31 C +ATOM 2070 C SER A 433 344.954 335.408 289.662 1.00 97.31 C +ATOM 2071 O SER A 433 344.844 334.640 288.703 1.00 97.31 O +ATOM 2072 CB SER A 433 344.948 334.303 291.905 1.00 96.71 C +ATOM 2073 OG SER A 433 344.515 334.496 293.238 1.00 96.71 O +ATOM 2074 N PRO A 434 345.765 336.465 289.621 1.00 96.71 N +ATOM 2075 CA PRO A 434 346.547 336.748 288.412 1.00 96.71 C +ATOM 2076 C PRO A 434 347.501 335.612 288.077 1.00 96.71 C +ATOM 2077 O PRO A 434 348.083 334.981 288.961 1.00 96.71 O +ATOM 2078 CB PRO A 434 347.304 338.033 288.771 1.00 96.71 C +ATOM 2079 CG PRO A 434 347.280 338.092 290.263 1.00 96.71 C +ATOM 2080 CD PRO A 434 345.978 337.480 290.665 1.00 99.41 C +ATOM 2081 N ILE A 435 347.651 335.355 286.777 1.00 99.41 N +ATOM 2082 CA ILE A 435 348.493 334.281 286.270 1.00 99.41 C +ATOM 2083 C ILE A 435 349.352 334.825 285.137 1.00 99.41 C +ATOM 2084 O ILE A 435 349.089 335.894 284.581 1.00 99.41 O +ATOM 2085 CB ILE A 435 347.671 333.073 285.777 1.00 99.41 C +ATOM 2086 CG1 ILE A 435 346.769 333.488 284.615 1.00 99.41 C +ATOM 2087 CG2 ILE A 435 346.855 332.477 286.914 1.00 99.41 C +ATOM 2088 CD1 ILE A 435 346.111 332.328 283.917 1.00 99.58 C +ATOM 2089 N ASP A 436 350.388 334.066 284.795 1.00 99.58 N +ATOM 2090 CA ASP A 436 351.306 334.419 283.720 1.00 99.58 C +ATOM 2091 C ASP A 436 350.776 333.883 282.399 1.00 99.58 C +ATOM 2092 O ASP A 436 350.446 332.698 282.293 1.00 99.58 O +ATOM 2093 CB ASP A 436 352.705 333.864 283.990 1.00 99.58 C +ATOM 2094 CG ASP A 436 353.406 334.577 285.125 1.00 99.58 C +ATOM 2095 OD1 ASP A 436 353.133 335.776 285.333 1.00 95.91 O +ATOM 2096 OD2 ASP A 436 354.234 333.939 285.811 1.00 95.91 O +ATOM 2097 N ILE A 437 350.702 334.755 281.396 1.00 95.91 N +ATOM 2098 CA ILE A 437 350.227 334.393 280.068 1.00 95.91 C +ATOM 2099 C ILE A 437 351.249 334.879 279.047 1.00 95.91 C +ATOM 2100 O ILE A 437 351.909 335.904 279.256 1.00 95.91 O +ATOM 2101 CB ILE A 437 348.827 334.979 279.785 1.00 89.79 C +ATOM 2102 CG1 ILE A 437 348.229 334.375 278.514 1.00 89.79 C +ATOM 2103 CG2 ILE A 437 348.881 336.490 279.679 1.00 89.79 C +ATOM 2104 CD1 ILE A 437 346.759 334.662 278.345 1.00 89.79 C +ATOM 2105 N ASP A 438 351.396 334.132 277.956 1.00 89.79 N +ATOM 2106 CA ASP A 438 352.415 334.429 276.957 1.00 89.79 C +ATOM 2107 C ASP A 438 351.875 335.430 275.944 1.00 89.79 C +ATOM 2108 O ASP A 438 350.850 335.181 275.302 1.00 89.79 O +ATOM 2109 CB ASP A 438 352.865 333.148 276.261 1.00 89.79 C +ATOM 2110 CG ASP A 438 354.282 333.237 275.732 1.00 87.18 C +ATOM 2111 OD1 ASP A 438 354.626 334.272 275.123 1.00 87.18 O +ATOM 2112 OD2 ASP A 438 355.051 332.274 275.927 1.00 87.18 O +ATOM 2113 N THR A 439 352.573 336.559 275.792 1.00 87.18 N +ATOM 2114 CA THR A 439 352.138 337.572 274.836 1.00 87.18 C +ATOM 2115 C THR A 439 352.554 337.211 273.416 1.00 87.18 C +ATOM 2116 O THR A 439 352.052 337.794 272.448 1.00 87.18 O +ATOM 2117 CB THR A 439 352.698 338.940 275.222 1.00 87.18 C +ATOM 2118 OG1 THR A 439 354.128 338.911 275.144 1.00 87.18 O +ATOM 2119 CG2 THR A 439 352.280 339.303 276.634 1.00 87.18 C +ATOM 2120 N SER A 440 353.485 336.266 273.269 1.00 87.18 N +ATOM 2121 CA SER A 440 353.876 335.831 271.932 1.00 87.18 C +ATOM 2122 C SER A 440 352.707 335.178 271.208 1.00 89.37 C +ATOM 2123 O SER A 440 352.496 335.415 270.012 1.00 89.37 O +ATOM 2124 CB SER A 440 355.062 334.871 272.014 1.00 89.37 C +ATOM 2125 OG SER A 440 354.624 333.544 272.238 1.00 89.37 O +ATOM 2126 N GLU A 441 351.934 334.353 271.916 1.00 89.37 N +ATOM 2127 CA GLU A 441 350.761 333.735 271.309 1.00 89.37 C +ATOM 2128 C GLU A 441 349.633 334.742 271.127 1.00 89.37 C +ATOM 2129 O GLU A 441 348.963 334.753 270.087 1.00 91.36 O +ATOM 2130 CB GLU A 441 350.294 332.554 272.160 1.00 91.36 C +ATOM 2131 CG GLU A 441 348.901 332.038 271.823 1.00 91.36 C +ATOM 2132 CD GLU A 441 348.785 331.507 270.408 1.00 91.36 C +ATOM 2133 OE1 GLU A 441 349.818 331.113 269.826 1.00 91.36 O +ATOM 2134 OE2 GLU A 441 347.655 331.475 269.879 1.00 91.36 O +ATOM 2135 N TYR A 442 349.409 335.597 272.122 1.00 91.36 N +ATOM 2136 CA TYR A 442 348.300 336.531 272.107 1.00 91.36 C +ATOM 2137 C TYR A 442 348.804 337.949 271.873 1.00 91.36 C +ATOM 2138 O TYR A 442 349.445 338.525 272.762 1.00111.57 O +ATOM 2139 CB TYR A 442 347.519 336.473 273.429 1.00111.57 C +ATOM 2140 CG TYR A 442 346.723 335.204 273.631 1.00111.57 C +ATOM 2141 CD1 TYR A 442 345.542 334.986 272.938 1.00111.57 C +ATOM 2142 CD2 TYR A 442 347.143 334.231 274.529 1.00111.57 C +ATOM 2143 CE1 TYR A 442 344.807 333.832 273.123 1.00111.57 C +ATOM 2144 CE2 TYR A 442 346.413 333.075 274.721 1.00111.57 C +ATOM 2145 CZ TYR A 442 345.245 332.881 274.015 1.00107.07 C +ATOM 2146 OH TYR A 442 344.510 331.733 274.197 1.00107.07 O +ATOM 2147 N PRO A 443 348.529 338.550 270.715 1.00107.07 N +ATOM 2148 CA PRO A 443 348.929 339.946 270.494 1.00107.07 C +ATOM 2149 C PRO A 443 348.040 340.919 271.254 1.00107.07 C +ATOM 2150 O PRO A 443 347.060 341.434 270.708 1.00107.07 O +ATOM 2151 CB PRO A 443 348.790 340.115 268.977 1.00107.07 C +ATOM 2152 CG PRO A 443 347.751 339.123 268.588 1.00 99.96 C +ATOM 2153 CD PRO A 443 347.901 337.954 269.523 1.00 99.96 C +ATOM 2154 N GLU A 444 348.373 341.158 272.525 1.00 99.96 N +ATOM 2155 CA GLU A 444 347.536 342.006 273.369 1.00 99.96 C +ATOM 2156 C GLU A 444 347.460 343.430 272.836 1.00 99.96 C +ATOM 2157 O GLU A 444 346.386 344.042 272.836 1.00 99.96 O +ATOM 2158 CB GLU A 444 348.068 342.004 274.802 1.00 99.96 C +ATOM 2159 CG GLU A 444 348.131 340.630 275.442 1.00 99.96 C +ATOM 2160 CD GLU A 444 346.765 340.012 275.628 1.00 93.82 C +ATOM 2161 OE1 GLU A 444 345.792 340.762 275.846 1.00 93.82 O +ATOM 2162 OE2 GLU A 444 346.662 338.770 275.557 1.00 93.82 O +ATOM 2163 N LEU A 445 348.589 343.973 272.384 1.00 93.82 N +ATOM 2164 CA LEU A 445 348.672 345.350 271.894 1.00 93.82 C +ATOM 2165 C LEU A 445 348.207 346.355 272.946 1.00 93.82 C +ATOM 2166 O LEU A 445 348.297 346.100 274.147 1.00 93.82 O +ATOM 2167 CB LEU A 445 347.855 345.526 270.612 1.00 93.82 C +ATOM 2168 CG LEU A 445 348.327 344.753 269.380 1.00 93.82 C +ATOM 2169 CD1 LEU A 445 347.372 344.972 268.218 1.00 85.24 C +ATOM 2170 CD2 LEU A 445 349.743 345.154 269.004 1.00 85.24 C +ATOM 2171 N HIS A 458 356.624 344.592 273.962 1.00 85.24 N +ATOM 2172 CA HIS A 458 355.872 343.501 274.571 1.00 85.24 C +ATOM 2173 C HIS A 458 356.794 342.430 275.139 1.00 85.24 C +ATOM 2174 O HIS A 458 357.490 341.738 274.397 1.00 85.24 O +ATOM 2175 CB HIS A 458 354.917 342.875 273.554 1.00 85.24 C +ATOM 2176 CG HIS A 458 353.686 343.686 273.299 1.00 85.24 C +ATOM 2177 ND1 HIS A 458 353.663 344.749 272.423 1.00 76.05 N +ATOM 2178 CD2 HIS A 458 352.435 343.589 273.807 1.00 76.05 C +ATOM 2179 CE1 HIS A 458 352.450 345.272 272.402 1.00 76.05 C +ATOM 2180 NE2 HIS A 458 351.686 344.587 273.232 1.00 76.05 N +ATOM 2181 N GLU A 459 356.796 342.303 276.463 1.00 76.05 N +ATOM 2182 CA GLU A 459 357.567 341.267 277.136 1.00 76.05 C +ATOM 2183 C GLU A 459 356.938 339.904 276.860 1.00 76.05 C +ATOM 2184 O GLU A 459 355.741 339.828 276.560 1.00 73.41 O +ATOM 2185 CB GLU A 459 357.640 341.547 278.637 1.00 73.41 C +ATOM 2186 CG GLU A 459 358.438 342.791 278.987 1.00 73.41 C +ATOM 2187 CD GLU A 459 358.479 343.059 280.477 1.00 73.41 C +ATOM 2188 OE1 GLU A 459 357.716 342.407 281.221 1.00 73.41 O +ATOM 2189 OE2 GLU A 459 359.274 343.921 280.905 1.00 73.41 O +ATOM 2190 N PRO A 460 357.710 338.814 276.932 1.00 73.41 N +ATOM 2191 CA PRO A 460 357.136 337.496 276.605 1.00 73.41 C +ATOM 2192 C PRO A 460 355.955 337.101 277.474 1.00 73.41 C +ATOM 2193 O PRO A 460 355.019 336.464 276.978 1.00 73.41 O +ATOM 2194 CB PRO A 460 358.328 336.544 276.796 1.00 73.41 C +ATOM 2195 CG PRO A 460 359.277 337.289 277.684 1.00 73.41 C +ATOM 2196 CD PRO A 460 359.138 338.719 277.275 1.00 73.41 C +ATOM 2197 N VAL A 461 355.968 337.454 278.757 1.00 73.41 N +ATOM 2198 CA VAL A 461 354.901 337.090 279.680 1.00 73.41 C +ATOM 2199 C VAL A 461 354.531 338.298 280.527 1.00 73.41 C +ATOM 2200 O VAL A 461 355.400 339.084 280.923 1.00 73.41 O +ATOM 2201 CB VAL A 461 355.296 335.898 280.578 1.00 73.41 C +ATOM 2202 CG1 VAL A 461 355.330 334.613 279.768 1.00 73.41 C +ATOM 2203 CG2 VAL A 461 356.642 336.149 281.238 1.00 73.41 C +ATOM 2204 N MET A 462 353.236 338.454 280.790 1.00 73.41 N +ATOM 2205 CA MET A 462 352.715 339.496 281.663 1.00 73.41 C +ATOM 2206 C MET A 462 351.527 338.939 282.438 1.00 73.41 C +ATOM 2207 O MET A 462 350.751 338.142 281.901 1.00 73.41 O +ATOM 2208 CB MET A 462 352.322 340.742 280.861 1.00 73.41 C +ATOM 2209 CG MET A 462 350.924 340.718 280.266 1.00 73.41 C +ATOM 2210 SD MET A 462 350.691 341.978 278.996 1.00 73.41 S +ATOM 2211 CE MET A 462 351.289 343.433 279.849 1.00 73.41 C +ATOM 2212 N LYS A 463 351.411 339.329 283.706 1.00 73.41 N +ATOM 2213 CA LYS A 463 350.313 338.848 284.532 1.00 73.41 C +ATOM 2214 C LYS A 463 349.000 339.489 284.107 1.00 73.41 C +ATOM 2215 O LYS A 463 348.899 340.713 283.979 1.00 73.41 O +ATOM 2216 CB LYS A 463 350.583 339.144 286.007 1.00 73.41 C +ATOM 2217 CG LYS A 463 351.685 338.306 286.620 1.00 73.41 C +ATOM 2218 CD LYS A 463 351.848 338.611 288.099 1.00 73.41 C +ATOM 2219 CE LYS A 463 352.897 337.716 288.735 1.00 73.41 C +ATOM 2220 NZ LYS A 463 353.053 337.999 290.188 1.00 73.41 N +ATOM 2221 N MET A 464 347.984 338.654 283.891 1.00 73.41 N +ATOM 2222 CA MET A 464 346.655 339.128 283.511 1.00 73.41 C +ATOM 2223 C MET A 464 345.625 338.352 284.319 1.00 73.41 C +ATOM 2224 O MET A 464 345.686 337.121 284.387 1.00 73.41 O +ATOM 2225 CB MET A 464 346.406 338.970 282.010 1.00 73.41 C +ATOM 2226 CG MET A 464 347.526 339.503 281.135 1.00 73.41 C +ATOM 2227 SD MET A 464 347.253 341.195 280.583 1.00 73.41 S +ATOM 2228 CE MET A 464 345.759 341.002 279.620 1.00 73.41 C +ATOM 2229 N VAL A 465 344.686 339.071 284.922 1.00 73.41 N +ATOM 2230 CA VAL A 465 343.660 338.478 285.772 1.00 73.41 C +ATOM 2231 C VAL A 465 342.674 337.697 284.911 1.00 73.41 C +ATOM 2232 O VAL A 465 342.038 338.278 284.023 1.00 73.41 O +ATOM 2233 CB VAL A 465 342.932 339.557 286.588 1.00 73.41 C +ATOM 2234 CG1 VAL A 465 341.985 338.919 287.579 1.00 73.41 C +ATOM 2235 CG2 VAL A 465 343.936 340.453 287.290 1.00 73.41 C +ATOM 2236 N PRO A 466 342.510 336.398 285.134 1.00 73.41 N +ATOM 2237 CA PRO A 466 341.551 335.630 284.338 1.00 73.41 C +ATOM 2238 C PRO A 466 340.149 335.711 284.917 1.00 73.41 C +ATOM 2239 O PRO A 466 339.949 335.633 286.132 1.00 73.41 O +ATOM 2240 CB PRO A 466 342.100 334.202 284.420 1.00 73.41 C +ATOM 2241 CG PRO A 466 342.752 334.154 285.757 1.00 73.41 C +ATOM 2242 CD PRO A 466 343.297 335.537 286.032 1.00 73.41 C +ATOM 2243 N ILE A 467 339.173 335.864 284.030 1.00 73.41 N +ATOM 2244 CA ILE A 467 337.770 335.972 284.406 1.00 73.41 C +ATOM 2245 C ILE A 467 336.995 334.890 283.677 1.00 73.41 C +ATOM 2246 O ILE A 467 337.147 334.723 282.461 1.00 73.41 O +ATOM 2247 CB ILE A 467 337.189 337.358 284.075 1.00 73.41 C +ATOM 2248 CG1 ILE A 467 338.123 338.465 284.556 1.00 73.41 C +ATOM 2249 CG2 ILE A 467 335.812 337.515 284.685 1.00 73.41 C +ATOM 2250 CD1 ILE A 467 337.699 339.833 284.105 1.00 73.41 C +ATOM 2251 N ARG A 468 336.170 334.158 284.411 1.00 73.41 N +ATOM 2252 CA ARG A 468 335.336 333.108 283.854 1.00 73.41 C +ATOM 2253 C ARG A 468 333.880 333.527 283.954 1.00 73.41 C +ATOM 2254 O ARG A 468 333.386 333.819 285.046 1.00 73.41 O +ATOM 2255 CB ARG A 468 335.557 331.793 284.599 1.00 73.41 C +ATOM 2256 CG ARG A 468 336.983 331.292 284.525 1.00 73.41 C +ATOM 2257 CD ARG A 468 337.197 330.075 285.400 1.00 73.41 C +ATOM 2258 NE ARG A 468 338.591 329.650 285.374 1.00 73.41 N +ATOM 2259 CZ ARG A 468 339.531 330.133 286.175 1.00 73.41 C +ATOM 2260 NH1 ARG A 468 339.259 331.059 287.079 1.00 73.41 N +ATOM 2261 NH2 ARG A 468 340.776 329.680 286.062 1.00 73.41 N +ATOM 2262 N VAL A 469 333.194 333.560 282.817 1.00 73.41 N +ATOM 2263 CA VAL A 469 331.804 333.994 282.758 1.00 73.41 C +ATOM 2264 C VAL A 469 330.990 332.883 282.121 1.00 73.41 C +ATOM 2265 O VAL A 469 331.076 332.666 280.909 1.00 73.41 O +ATOM 2266 CB VAL A 469 331.643 335.300 281.965 1.00 73.41 C +ATOM 2267 CG1 VAL A 469 330.181 335.680 281.873 1.00 73.41 C +ATOM 2268 CG2 VAL A 469 332.446 336.413 282.610 1.00 73.41 C +ATOM 2269 N VAL A 470 330.198 332.188 282.928 1.00 73.41 N +ATOM 2270 CA VAL A 470 329.327 331.127 282.443 1.00 73.41 C +ATOM 2271 C VAL A 470 327.907 331.668 282.380 1.00 73.41 C +ATOM 2272 O VAL A 470 327.445 332.336 283.310 1.00 73.41 O +ATOM 2273 CB VAL A 470 329.406 329.862 283.322 1.00 73.41 C +ATOM 2274 CG1 VAL A 470 330.778 329.240 283.218 1.00 73.41 C +ATOM 2275 CG2 VAL A 470 329.121 330.195 284.761 1.00 73.41 C +ATOM 2276 N SER A 471 327.227 331.400 281.274 1.00 73.41 N +ATOM 2277 CA SER A 471 325.893 331.925 281.040 1.00 73.41 C +ATOM 2278 C SER A 471 324.869 330.799 281.030 1.00 73.41 C +ATOM 2279 O SER A 471 325.209 329.618 280.943 1.00 73.41 O +ATOM 2280 CB SER A 471 325.840 332.703 279.725 1.00 73.41 C +ATOM 2281 OG SER A 471 326.254 331.892 278.644 1.00 73.41 O +ATOM 2282 N SER A 472 323.596 331.188 281.121 1.00 73.41 N +ATOM 2283 CA SER A 472 322.527 330.203 281.257 1.00 73.41 C +ATOM 2284 C SER A 472 322.280 329.451 279.956 1.00 73.41 C +ATOM 2285 O SER A 472 321.574 328.437 279.947 1.00 73.41 O +ATOM 2286 CB SER A 472 321.244 330.883 281.725 1.00 73.41 C +ATOM 2287 OG SER A 472 320.774 331.807 280.760 1.00 73.41 O +ATOM 2288 N ASP A 473 322.826 329.940 278.844 1.00 73.41 N +ATOM 2289 CA ASP A 473 322.709 329.194 277.598 1.00 73.41 C +ATOM 2290 C ASP A 473 323.621 327.978 277.563 1.00 73.41 C +ATOM 2291 O ASP A 473 323.398 327.079 276.746 1.00 73.41 O +ATOM 2292 CB ASP A 473 322.990 330.113 276.407 1.00 73.41 C +ATOM 2293 CG ASP A 473 324.392 330.679 276.424 1.00 73.41 C +ATOM 2294 OD1 ASP A 473 325.081 330.534 277.454 1.00 73.41 O +ATOM 2295 OD2 ASP A 473 324.803 331.282 275.411 1.00 73.41 O +ATOM 2296 N GLY A 474 324.628 327.924 278.428 1.00 73.41 N +ATOM 2297 CA GLY A 474 325.494 326.776 278.537 1.00 73.41 C +ATOM 2298 C GLY A 474 326.884 326.941 277.973 1.00 73.41 C +ATOM 2299 O GLY A 474 327.428 325.975 277.430 1.00 73.41 O +ATOM 2300 N TYR A 475 327.478 328.125 278.077 1.00 73.41 N +ATOM 2301 CA TYR A 475 328.811 328.376 277.551 1.00 73.41 C +ATOM 2302 C TYR A 475 329.669 329.065 278.597 1.00 73.41 C +ATOM 2303 O TYR A 475 329.167 329.803 279.447 1.00 73.41 O +ATOM 2304 CB TYR A 475 328.769 329.237 276.284 1.00 73.41 C +ATOM 2305 CG TYR A 475 328.057 328.598 275.113 1.00 73.41 C +ATOM 2306 CD1 TYR A 475 326.672 328.544 275.060 1.00 79.97 C +ATOM 2307 CD2 TYR A 475 328.771 328.052 274.057 1.00 79.97 C +ATOM 2308 CE1 TYR A 475 326.019 327.964 273.995 1.00 79.97 C +ATOM 2309 CE2 TYR A 475 328.128 327.469 272.989 1.00 79.97 C +ATOM 2310 CZ TYR A 475 326.752 327.429 272.963 1.00 79.97 C +ATOM 2311 OH TYR A 475 326.099 326.850 271.901 1.00 79.97 O +ATOM 2312 N LEU A 476 330.973 328.821 278.524 1.00 79.97 N +ATOM 2313 CA LEU A 476 331.949 329.458 279.391 1.00 79.97 C +ATOM 2314 C LEU A 476 332.826 330.377 278.557 1.00 84.71 C +ATOM 2315 O LEU A 476 333.253 330.012 277.460 1.00 84.71 O +ATOM 2316 CB LEU A 476 332.805 328.412 280.113 1.00 84.71 C +ATOM 2317 CG LEU A 476 333.781 328.866 281.202 1.00 84.71 C +ATOM 2318 CD1 LEU A 476 334.001 327.739 282.193 1.00 84.71 C +ATOM 2319 CD2 LEU A 476 335.111 329.315 280.629 1.00 84.71 C +ATOM 2320 N TYR A 477 333.097 331.566 279.080 1.00 84.71 N +ATOM 2321 CA TYR A 477 333.909 332.559 278.396 1.00 84.71 C +ATOM 2322 C TYR A 477 335.065 332.968 279.295 1.00 83.84 C +ATOM 2323 O TYR A 477 334.861 333.298 280.466 1.00 83.84 O +ATOM 2324 CB TYR A 477 333.085 333.799 278.012 1.00 83.84 C +ATOM 2325 CG TYR A 477 331.805 333.509 277.258 1.00 83.84 C +ATOM 2326 CD1 TYR A 477 330.701 332.979 277.905 1.00 83.84 C +ATOM 2327 CD2 TYR A 477 331.698 333.773 275.905 1.00 83.84 C +ATOM 2328 CE1 TYR A 477 329.534 332.715 277.231 1.00 83.84 C +ATOM 2329 CE2 TYR A 477 330.533 333.511 275.219 1.00 86.13 C +ATOM 2330 CZ TYR A 477 329.454 332.981 275.889 1.00 86.13 C +ATOM 2331 OH TYR A 477 328.285 332.713 275.222 1.00 86.13 O +ATOM 2332 N ASN A 478 336.274 332.952 278.746 1.00 86.13 N +ATOM 2333 CA ASN A 478 337.478 333.294 279.490 1.00 86.13 C +ATOM 2334 C ASN A 478 337.987 334.646 279.015 1.00 86.13 C +ATOM 2335 O ASN A 478 338.205 334.842 277.817 1.00 86.13 O +ATOM 2336 CB ASN A 478 338.554 332.225 279.310 1.00 86.13 C +ATOM 2337 CG ASN A 478 338.195 330.918 279.984 1.00 86.13 C +ATOM 2338 OD1 ASN A 478 338.052 330.852 281.202 1.00 84.91 O +ATOM 2339 ND2 ASN A 478 338.046 329.867 279.191 1.00 84.91 N +ATOM 2340 N PHE A 479 338.179 335.569 279.951 1.00 84.91 N +ATOM 2341 CA PHE A 479 338.689 336.898 279.657 1.00 84.91 C +ATOM 2342 C PHE A 479 339.974 337.145 280.432 1.00 84.91 C +ATOM 2343 O PHE A 479 340.356 336.370 281.311 1.00 84.91 O +ATOM 2344 CB PHE A 479 337.666 337.982 280.008 1.00 84.91 C +ATOM 2345 CG PHE A 479 336.415 337.946 279.174 1.00 84.91 C +ATOM 2346 CD1 PHE A 479 335.428 337.009 279.417 1.00 84.91 C +ATOM 2347 CD2 PHE A 479 336.221 338.864 278.160 1.00 84.91 C +ATOM 2348 CE1 PHE A 479 334.279 336.983 278.656 1.00 84.91 C +ATOM 2349 CE2 PHE A 479 335.073 338.838 277.397 1.00 79.49 C +ATOM 2350 CZ PHE A 479 334.102 337.897 277.646 1.00 79.49 C +ATOM 2351 N VAL A 480 340.644 338.241 280.089 1.00 79.49 N +ATOM 2352 CA VAL A 480 341.812 338.715 280.820 1.00 79.49 C +ATOM 2353 C VAL A 480 341.716 340.225 280.977 1.00 73.71 C +ATOM 2354 O VAL A 480 341.303 340.935 280.054 1.00 73.71 O +ATOM 2355 CB VAL A 480 343.135 338.326 280.125 1.00 73.71 C +ATOM 2356 CG1 VAL A 480 343.370 336.840 280.236 1.00 73.71 C +ATOM 2357 CG2 VAL A 480 343.108 338.739 278.665 1.00 73.41 C +ATOM 2358 N MET A 481 342.088 340.713 282.155 1.00 73.41 N +ATOM 2359 CA MET A 481 342.104 342.136 282.453 1.00 73.41 C +ATOM 2360 C MET A 481 343.510 342.563 282.841 1.00 73.41 C +ATOM 2361 O MET A 481 344.181 341.884 283.623 1.00 73.41 O +ATOM 2362 CB MET A 481 341.142 342.473 283.592 1.00 73.41 C +ATOM 2363 CG MET A 481 341.091 343.956 283.933 1.00 73.41 C +ATOM 2364 SD MET A 481 340.075 344.322 285.374 1.00 73.41 S +ATOM 2365 CE MET A 481 339.025 342.879 285.404 1.00 73.41 C +ATOM 2366 N ASP A 482 343.951 343.692 282.300 1.00 73.41 N +ATOM 2367 CA ASP A 482 345.225 344.264 282.704 1.00 73.41 C +ATOM 2368 C ASP A 482 344.991 345.178 283.898 1.00 73.41 C +ATOM 2369 O ASP A 482 344.290 346.189 283.760 1.00 73.41 O +ATOM 2370 CB ASP A 482 345.854 345.039 281.558 1.00 73.41 C +ATOM 2371 CG ASP A 482 347.346 345.239 281.740 1.00 73.41 C +ATOM 2372 OD1 ASP A 482 347.903 344.727 282.733 1.00 73.41 O +ATOM 2373 OD2 ASP A 482 347.962 345.907 280.885 1.00 73.41 O +ATOM 2374 N PRO A 483 345.544 344.869 285.074 1.00 73.41 N +ATOM 2375 CA PRO A 483 345.205 345.647 286.278 1.00 73.41 C +ATOM 2376 C PRO A 483 345.521 347.128 286.173 1.00 73.41 C +ATOM 2377 O PRO A 483 344.831 347.937 286.805 1.00 73.41 O +ATOM 2378 CB PRO A 483 346.038 344.975 287.375 1.00 73.41 C +ATOM 2379 CG PRO A 483 346.268 343.592 286.874 1.00 73.41 C +ATOM 2380 CD PRO A 483 346.395 343.711 285.386 1.00 73.41 C +ATOM 2381 N GLU A 484 346.539 347.516 285.410 1.00 73.41 N +ATOM 2382 CA GLU A 484 346.842 348.927 285.210 1.00 73.41 C +ATOM 2383 C GLU A 484 346.011 349.542 284.094 1.00 73.41 C +ATOM 2384 O GLU A 484 345.392 350.593 284.287 1.00 73.41 O +ATOM 2385 CB GLU A 484 348.335 349.115 284.913 1.00 73.41 C +ATOM 2386 CG GLU A 484 349.259 348.545 285.976 1.00 73.41 C +ATOM 2387 CD GLU A 484 349.941 347.267 285.535 1.00 73.41 C +ATOM 2388 OE1 GLU A 484 349.667 346.805 284.410 1.00 73.41 O +ATOM 2389 OE2 GLU A 484 350.755 346.728 286.314 1.00 73.41 O +ATOM 2390 N ARG A 485 345.982 348.906 282.923 1.00 73.41 N +ATOM 2391 CA ARG A 485 345.222 349.452 281.803 1.00 73.41 C +ATOM 2392 C ARG A 485 343.721 349.331 282.035 1.00 73.41 C +ATOM 2393 O ARG A 485 342.971 350.281 281.781 1.00 73.41 O +ATOM 2394 CB ARG A 485 345.623 348.750 280.505 1.00 73.41 C +ATOM 2395 CG ARG A 485 346.807 349.382 279.787 1.00 73.41 C +ATOM 2396 CD ARG A 485 348.109 349.180 280.547 1.00 73.41 C +ATOM 2397 NE ARG A 485 349.259 349.657 279.787 1.00 73.41 N +ATOM 2398 CZ ARG A 485 350.496 349.722 280.260 1.00 73.41 C +ATOM 2399 NH1 ARG A 485 350.785 349.344 281.494 1.00 73.41 N +ATOM 2400 NH2 ARG A 485 351.468 350.180 279.476 1.00 73.41 N +ATOM 2401 N GLY A 486 343.267 348.186 282.531 1.00 73.41 N +ATOM 2402 CA GLY A 486 341.837 347.958 282.634 1.00 73.41 C +ATOM 2403 C GLY A 486 341.198 347.989 281.261 1.00 73.41 C +ATOM 2404 O GLY A 486 341.688 347.372 280.309 1.00 73.41 O +ATOM 2405 N GLY A 487 340.089 348.713 281.146 1.00 73.41 N +ATOM 2406 CA GLY A 487 339.432 348.890 279.867 1.00 73.41 C +ATOM 2407 C GLY A 487 338.733 347.635 279.387 1.00 73.41 C +ATOM 2408 O GLY A 487 338.544 346.659 280.114 1.00 73.41 O +ATOM 2409 N ASP A 488 338.338 347.672 278.115 1.00 73.41 N +ATOM 2410 CA ASP A 488 337.677 346.531 277.497 1.00 73.41 C +ATOM 2411 C ASP A 488 338.607 345.326 277.490 1.00 73.41 C +ATOM 2412 O ASP A 488 339.792 345.441 277.165 1.00 73.41 O +ATOM 2413 CB ASP A 488 337.247 346.887 276.072 1.00 73.41 C +ATOM 2414 CG ASP A 488 336.250 345.899 275.495 1.00 73.41 C +ATOM 2415 OD1 ASP A 488 336.157 344.762 276.004 1.00 73.41 O +ATOM 2416 OD2 ASP A 488 335.554 346.263 274.524 1.00 73.41 O +ATOM 2417 N CYS A 489 338.063 344.167 277.846 1.00 73.41 N +ATOM 2418 CA CYS A 489 338.865 342.969 278.033 1.00 73.41 C +ATOM 2419 C CYS A 489 338.793 342.051 276.820 1.00 73.41 C +ATOM 2420 O CYS A 489 337.736 341.868 276.211 1.00 73.41 O +ATOM 2421 CB CYS A 489 338.413 342.212 279.280 1.00 73.41 C +ATOM 2422 SG CYS A 489 338.825 343.036 280.829 1.00 73.41 S +ATOM 2423 N LEU A 490 339.940 341.475 276.478 1.00 73.41 N +ATOM 2424 CA LEU A 490 340.039 340.504 275.400 1.00 73.41 C +ATOM 2425 C LEU A 490 339.515 339.146 275.852 1.00 73.41 C +ATOM 2426 O LEU A 490 339.586 338.791 277.032 1.00 73.41 O +ATOM 2427 CB LEU A 490 341.493 340.391 274.937 1.00 73.41 C +ATOM 2428 CG LEU A 490 341.857 339.571 273.699 1.00 73.41 C +ATOM 2429 CD1 LEU A 490 343.020 340.217 272.973 1.00 73.41 C +ATOM 2430 CD2 LEU A 490 342.226 338.161 274.101 1.00 73.41 C +ATOM 2431 N ILE A 491 338.985 338.384 274.901 1.00 73.41 N +ATOM 2432 CA ILE A 491 338.445 337.053 275.159 1.00 73.41 C +ATOM 2433 C ILE A 491 339.406 336.046 274.541 1.00 73.41 C +ATOM 2434 O ILE A 491 339.823 336.188 273.387 1.00 73.41 O +ATOM 2435 CB ILE A 491 337.020 336.892 274.616 1.00 73.41 C +ATOM 2436 CG1 ILE A 491 336.527 335.463 274.842 1.00 73.41 C +ATOM 2437 CG2 ILE A 491 336.941 337.289 273.151 1.00 73.41 C +ATOM 2438 CD1 ILE A 491 335.051 335.284 274.617 1.00 73.41 C +ATOM 2439 N LEU A 492 339.777 335.026 275.318 1.00 73.41 N +ATOM 2440 CA LEU A 492 340.737 334.042 274.828 1.00 73.41 C +ATOM 2441 C LEU A 492 340.039 332.843 274.201 1.00 73.41 C +ATOM 2442 O LEU A 492 340.308 332.496 273.046 1.00 73.41 O +ATOM 2443 CB LEU A 492 341.653 333.591 275.962 1.00 73.41 C +ATOM 2444 CG LEU A 492 342.237 334.695 276.837 1.00 73.41 C +ATOM 2445 CD1 LEU A 492 342.749 334.106 278.124 1.00 73.41 C +ATOM 2446 CD2 LEU A 492 343.348 335.419 276.110 1.00 73.41 C +ATOM 2447 N SER A 493 339.139 332.200 274.936 1.00 73.41 N +ATOM 2448 CA SER A 493 338.574 330.945 274.468 1.00 73.41 C +ATOM 2449 C SER A 493 337.139 330.812 274.947 1.00 73.41 C +ATOM 2450 O SER A 493 336.686 331.539 275.832 1.00 73.41 O +ATOM 2451 CB SER A 493 339.395 329.754 274.953 1.00 73.41 C +ATOM 2452 OG SER A 493 339.309 329.634 276.360 1.00 73.41 O +ATOM 2453 N GLN A 494 336.434 329.861 274.343 1.00 73.41 N +ATOM 2454 CA GLN A 494 335.053 329.550 274.694 1.00 73.41 C +ATOM 2455 C GLN A 494 334.861 328.044 274.636 1.00 73.41 C +ATOM 2456 O GLN A 494 335.083 327.432 273.588 1.00 73.41 O +ATOM 2457 CB GLN A 494 334.072 330.237 273.752 1.00 73.41 C +ATOM 2458 CG GLN A 494 332.633 329.970 274.118 1.00 76.73 C +ATOM 2459 CD GLN A 494 331.663 330.682 273.213 1.00 76.73 C +ATOM 2460 OE1 GLN A 494 330.450 330.592 273.397 1.00 76.73 O +ATOM 2461 NE2 GLN A 494 332.186 331.401 272.228 1.00 76.73 N +ATOM 2462 N TYR A 495 334.440 327.448 275.742 1.00 76.73 N +ATOM 2463 CA TYR A 495 334.015 326.059 275.744 1.00 76.73 C +ATOM 2464 C TYR A 495 332.502 325.995 275.607 1.00 76.73 C +ATOM 2465 O TYR A 495 331.833 326.991 275.326 1.00 81.87 O +ATOM 2466 CB TYR A 495 334.469 325.340 277.017 1.00 81.87 C +ATOM 2467 CG TYR A 495 335.826 325.770 277.507 1.00 81.87 C +ATOM 2468 CD1 TYR A 495 336.949 325.620 276.715 1.00 81.87 C +ATOM 2469 CD2 TYR A 495 335.985 326.302 278.775 1.00 81.87 C +ATOM 2470 CE1 TYR A 495 338.191 326.009 277.163 1.00 81.87 C +ATOM 2471 CE2 TYR A 495 337.221 326.692 279.231 1.00 81.87 C +ATOM 2472 CZ TYR A 495 338.322 326.542 278.422 1.00 81.87 C +ATOM 2473 OH TYR A 495 339.559 326.928 278.876 1.00 81.87 O +ATOM 2474 N SER A 496 331.962 324.801 275.803 1.00 81.87 N +ATOM 2475 CA SER A 496 330.524 324.585 275.796 1.00 81.87 C +ATOM 2476 C SER A 496 330.184 323.552 276.854 1.00 81.87 C +ATOM 2477 O SER A 496 330.419 322.355 276.654 1.00 81.87 O +ATOM 2478 CB SER A 496 330.032 324.128 274.424 1.00 81.87 C +ATOM 2479 OG SER A 496 328.639 323.875 274.452 1.00 81.87 O +ATOM 2480 N ILE A 497 329.642 324.014 277.977 1.00 86.58 N +ATOM 2481 CA ILE A 497 329.156 323.093 278.987 1.00 86.58 C +ATOM 2482 C ILE A 497 328.003 322.277 278.406 1.00 86.58 C +ATOM 2483 O ILE A 497 327.293 322.717 277.494 1.00 86.58 O +ATOM 2484 CB ILE A 497 328.734 323.872 280.243 1.00 86.58 C +ATOM 2485 CG1 ILE A 497 329.920 324.670 280.781 1.00 86.58 C +ATOM 2486 CG2 ILE A 497 328.253 322.943 281.332 1.00 86.58 C +ATOM 2487 CD1 ILE A 497 331.090 323.821 281.188 1.00 86.58 C +ATOM 2488 N LEU A 498 327.838 321.060 278.925 1.00 88.68 N +ATOM 2489 CA LEU A 498 326.927 320.012 278.458 1.00 88.68 C +ATOM 2490 C LEU A 498 327.483 319.322 277.217 1.00 88.68 C +ATOM 2491 O LEU A 498 326.729 318.621 276.531 1.00 88.68 O +ATOM 2492 CB LEU A 498 325.503 320.508 278.144 1.00 88.68 C +ATOM 2493 CG LEU A 498 324.523 320.811 279.279 1.00 88.68 C +ATOM 2494 CD1 LEU A 498 324.975 322.008 280.095 1.00 88.68 C +ATOM 2495 CD2 LEU A 498 323.128 321.041 278.723 1.00 88.68 C +ATOM 2496 N MET A 499 328.763 319.495 276.903 1.00 88.68 N +ATOM 2497 CA MET A 499 329.357 318.871 275.729 1.00 88.68 C +ATOM 2498 C MET A 499 330.857 318.679 275.921 1.00 88.68 C +ATOM 2499 O MET A 499 331.595 319.640 276.137 1.00 78.11 O +ATOM 2500 CB MET A 499 329.080 319.713 274.480 1.00 78.11 C +ATOM 2501 CG MET A 499 329.830 319.265 273.235 1.00 78.11 C +ATOM 2502 SD MET A 499 331.376 320.157 272.973 1.00 78.11 S +ATOM 2503 CE MET A 499 330.823 321.490 271.914 1.00 78.11 C +TER +END +''' + +if (__name__ == "__main__"): + t0 = time.time() + run() + print("OK. Time: %8.3f"%(time.time()-t0)) From 1ec955094d0f1691baa182aafe52b40ae0be9a79 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Thu, 4 Apr 2024 16:01:44 -0700 Subject: [PATCH 297/748] README: update Python 3.12 test URLs [skip ci] --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 6d3b9f8c56..486d6d1cb4 100644 --- a/README.md +++ b/README.md @@ -154,13 +154,13 @@ A subset of tests is run on the current `cctbx-base` packages every night (10 pm Linux Python 3.12 - + + variant + - - variant + + variant @@ -226,13 +226,13 @@ A subset of tests is run on the current `cctbx-base` packages every night (10 pm macOS (Intel) Python 3.12 - + - - variant + + variant @@ -286,9 +286,9 @@ A subset of tests is run on the current `cctbx-base` packages every night (10 pm macOS (Apple Silicon) Python 3.12 - + + variant + @@ -358,13 +358,13 @@ A subset of tests is run on the current `cctbx-base` packages every night (10 pm Windows Python 3.12 - + - - variant + + variant From 5f85a0555f4a1bad338e4153cf62b38d34e27625 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 4 Apr 2024 16:56:44 -0700 Subject: [PATCH 298/748] Hydrogenate: adapt test timings to anaconda --- mmtbx/hydrogens/tst_add_hydrogen_time.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mmtbx/hydrogens/tst_add_hydrogen_time.py b/mmtbx/hydrogens/tst_add_hydrogen_time.py index 2e7a4bddcc..2930beea89 100644 --- a/mmtbx/hydrogens/tst_add_hydrogen_time.py +++ b/mmtbx/hydrogens/tst_add_hydrogen_time.py @@ -20,15 +20,15 @@ def run(): model_h_added = hydro_obj.get_model() #print(model_h_added.get_number_of_atoms()) t = hydro_obj.get_times() - assert (t.time_rebox_model < 0.03) - assert (t.time_add_missing_H < 1.45) + assert (t.time_rebox_model < 0.06) + assert (t.time_add_missing_H < 2.70) assert (t.time_terminal_propeller < 0.01) - assert (t.time_make_grm < 61) - assert (t.time_remove_isolated < 0.15) - assert (t.time_riding_manager < 3) - assert (t.time_remove_H_nopara < 4.2) - assert (t.time_reset_idealize < 2) - assert (t.time_remove_H_on_links < 0.37) + assert (t.time_make_grm < 160) + assert (t.time_remove_isolated < 0.27) + assert (t.time_riding_manager < 6.5) + assert (t.time_remove_H_nopara < 11.5) + assert (t.time_reset_idealize < 5) + assert (t.time_remove_H_on_links < 2) pdb_str = ''' REMARK 350 MOLECULE CAN BE GENERATED BY APPLYING BIOMT TRANSFORMATIONS From 1fb3c377cca66f9e879cd1d9319160f2a50c7720 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 4 Apr 2024 16:58:28 -0700 Subject: [PATCH 299/748] Hydrogenate: activate test --- mmtbx/run_tests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index 736e3c0253..e547d7a27f 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -150,6 +150,7 @@ "$D/hydrogens/tst_add_hydrogen.py", "$D/hydrogens/tst_add_hydrogen_2.py", "$D/hydrogens/tst_add_hydrogen_3.py", + "$D/hydrogens/tst_add_hydrogen_time.py", "$D/hydrogens/tst_validate_H.py", "$D/hydrogens/tst_connectivity.py", "$D/hydrogens/tst_riding_coefficients.py", From 03501d08f0650590e87b7672de9ea9bdecab1da5 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 4 Apr 2024 21:19:46 -0700 Subject: [PATCH 300/748] Needs more adjustment. --- mmtbx/run_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index e547d7a27f..5eb01979f8 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -150,7 +150,7 @@ "$D/hydrogens/tst_add_hydrogen.py", "$D/hydrogens/tst_add_hydrogen_2.py", "$D/hydrogens/tst_add_hydrogen_3.py", - "$D/hydrogens/tst_add_hydrogen_time.py", + #"$D/hydrogens/tst_add_hydrogen_time.py", "$D/hydrogens/tst_validate_H.py", "$D/hydrogens/tst_connectivity.py", "$D/hydrogens/tst_riding_coefficients.py", From 690a86bb5287f4f8fd0282aad5f07955aaa4e3c1 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 5 Apr 2024 10:03:14 -0700 Subject: [PATCH 301/748] Hydrogenate: Better output --- mmtbx/hydrogens/reduce_hydrogen.py | 189 ++++++++++++++--------------- 1 file changed, 91 insertions(+), 98 deletions(-) diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index fdca67f31a..5ebf209b0f 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -14,8 +14,6 @@ ext = bp.import_ext("cctbx_geometry_restraints_ext") get_class = iotbx.pdb.common_residue_names_get_class -# For development -save_time = True # ============================================================================== @@ -177,21 +175,21 @@ def __init__(self, self.no_H_placed_mlq = list() self.site_labels_disulfides = list() self.site_labels_no_para = list() - self.charged_atoms = list() + #self.charged_atoms = list() self.sl_removed = list() self.n_H_initial = 0 self.n_H_final = 0 if self.print_time: - self.time_rebox_model = 0 - self.time_add_missing_H = 0 - self.time_terminal_propeller = 0 - self.time_make_grm = 0 - self.time_remove_isolated = 0 - self.time_riding_manager = 0 - self.time_remove_H_nopara = 0 - self.time_reset_idealize = 0 - self.time_remove_H_on_links = 0 + self.time_rebox_model = None + self.time_add_missing_H = None + self.time_terminal_propeller = None + self.time_make_grm = None + self.time_remove_isolated = None + self.time_riding_manager = None + self.time_remove_H_nopara = None + self.time_reset_idealize = None + self.time_remove_H_on_links = None # ------------------------------------------------------------------------------ @@ -209,9 +207,7 @@ def run(self): self.model = shift_and_box_model(model = self.model) model_has_bogus_cs = True #self.model.add_crystal_symmetry_if_necessary() # this is slower than shift_and_box_model!!!! - if self.print_time: - print("Rebox model:", round(time.time()-t0, 2)) - self.time_rebox_model = round(time.time()-t0, 2) + self.time_rebox_model = round(time.time()-t0, 2) # Remove existing H if requested # ------------------------------ @@ -223,9 +219,7 @@ def run(self): # ---------------------------------------------------- t0 = time.time() pdb_hierarchy = self.add_missing_H_atoms_at_bogus_position() - if self.print_time: - print("add_missing_H_atoms_at_bogus_position:", round(time.time()-t0, 2)) - self.time_add_missing_H = round(time.time()-t0, 2) + self.time_add_missing_H = round(time.time()-t0, 2) # DEBUG #print(pdb_hierarchy.composition().n_hd) #f = open("intermediate1.pdb","w") @@ -237,9 +231,7 @@ def run(self): if self.n_terminal_charge in ['residue_one', 'first_in_chain']: t0 = time.time() self.place_n_terminal_propeller(pdb_hierarchy = pdb_hierarchy) - if self.print_time: - print('Add N-terminal propeller', round(time.time()-t0, 2)) - self.time_terminal_propeller = round(time.time()-t0, 2) + self.time_terminal_propeller = round(time.time()-t0, 2) pdb_hierarchy.sort_atoms_in_place() pdb_hierarchy.atoms().reset_serial() @@ -260,11 +252,8 @@ def run(self): crystal_symmetry = self.model.crystal_symmetry(), restraint_objects = ro, log = null_out()) - self.model.process(pdb_interpretation_params=p, - make_restraints=True) - if self.print_time: - print("get new model obj and grm:", round(time.time()-t0, 2)) - self.time_make_grm = round(time.time()-t0, 2) + self.model.process(pdb_interpretation_params=p, make_restraints=True) + self.time_make_grm = round(time.time()-t0, 2) #f = open("intermediate3.pdb","w") #f.write(self.model.model_as_pdb()) @@ -281,9 +270,7 @@ def run(self): self.sel_lone_H = sel_h & sel_isolated if not self.sel_lone_H.all_eq(False): self.model = self.model.select(~self.sel_lone_H) - if self.print_time: - print("Remove isolated H:", round(time.time()-t0, 2)) - self.time_remove_isolated = round(time.time()-t0, 2) + self.time_remove_isolated = round(time.time()-t0, 2) sel_h = self.model.get_hd_selection() @@ -294,9 +281,7 @@ def run(self): riding_h_manager = self.model.riding_h_manager if riding_h_manager is None: return - if self.print_time: - print("Setup Riding manager:", round(time.time()-t0, 2)) - self.time_riding_manager = round(time.time()-t0, 2) + self.time_riding_manager = round(time.time()-t0, 2) # Remove H that could not be parameterized # ---------------------------------------- @@ -306,11 +291,8 @@ def run(self): sel_h_not_in_para = sel_h_in_para.exclusive_or(sel_h) self.site_labels_no_para = [atom.id_str().replace('pdb=','').replace('"','') for atom in self.model.get_hierarchy().atoms().select(sel_h_not_in_para)] - # self.model = self.model.select(~sel_h_not_in_para) - if self.print_time: - print("Remove H that were not parameterized:", round(time.time()-t0, 2)) - self.time_remove_H_nopara = round(time.time()-t0, 2) + self.time_remove_H_nopara = round(time.time()-t0, 2) # f = open("intermediate4.pdb","w") # f.write(model.model_as_pdb()) @@ -328,17 +310,13 @@ def run(self): self.model.reset_adp_for_hydrogens(scale = self.adp_scale) self.model.reset_occupancy_for_hydrogens_simple() self.model.idealize_h_riding() - if self.print_time: - print("Reset adp, occ; idealize H positions:", round(time.time()-t0, 2)) - self.time_reset_idealize = round(time.time()-t0, 2) + self.time_reset_idealize = round(time.time()-t0, 2) # Remove H atoms that are involved in links (bonds, metal coordination, etc) # -------------------------------------------------------------------------- t0 = time.time() self.exclude_H_on_links() - if self.print_time: - print("Remove H on links:", round(time.time()-t0, 2)) - self.time_remove_H_on_links = round(time.time()-t0, 2) + self.time_remove_H_on_links = round(time.time()-t0, 2) # TODO: this should be ideally done *after* reduce optimization @@ -347,6 +325,9 @@ def run(self): self.n_H_final = self.model.get_hd_selection().count(True) + if self.print_time: + self.print_times() + # ---------------------------------------------------------------------------- def place_n_terminal_propeller(self, pdb_hierarchy): @@ -453,19 +434,16 @@ def add_missing_H_atoms_at_bogus_position(self): return pdb_hierarchy # ------------------------------------------------------------------------------ - - def validate_electrons(self): - #TODO maybe do this only for special places? Metal coordination or linking? - from elbow.quantum import electrons - atom_valences = electrons.electron_distribution( - # XXX How do we get this working on models with alternate locations? - self.model.get_hierarchy(), # needs to be altloc free - self.model.get_restraints_manager().geometry, - verbose=False, - ) - atom_valences.validate(ignore_water=True, - raise_if_error=False) - self.charged_atoms = atom_valences.get_charged_atoms() +# +# def validate_electrons(self): +# from elbow.quantum import electrons +# atom_valences = electrons.electron_distribution( +# self.model.get_hierarchy(), # needs to be altloc free +# self.model.get_restraints_manager().geometry, +# verbose=False, +# ) +# atom_valences.validate(ignore_water=True, raise_if_error=False) +# self.charged_atoms = atom_valences.get_charged_atoms() # ------------------------------------------------------------------------------ @@ -599,15 +577,15 @@ def show(self, log): print(msg, file=log) for label in self.site_labels_no_para: print(label) - if self.charged_atoms: - msg = ''' -The following heavy atom have an unusual electron count. This could be because -heavy atoms or H atoms are missing.''' - print(msg, file=log) - for item in self.charged_atoms: - idstr = item[0].id_str().replace('pdb=','').replace('"','') - if 'HOH' in idstr: continue - print(idstr, item[1]) +# if self.charged_atoms: +# msg = ''' +#The following heavy atom have an unusual electron count. This could be because +#heavy atoms or H atoms are missing.''' +# print(msg, file=log) +# for item in self.charged_atoms: +# idstr = item[0].id_str().replace('pdb=','').replace('"','') +# if 'HOH' in idstr: continue +# print(idstr, item[1]) if self.sl_removed: print() @@ -643,39 +621,54 @@ def get_times(self): time_reset_idealize = self.time_reset_idealize, time_remove_H_on_links = self.time_remove_H_on_links) -# ============================================================================== +# ------------------------------------------------------------------------------ -# stub for reduce parameters -# TODO can be parameters or phil, depending on how many options are really needed -reduce_master_params_str = """ -flip_NQH = True - .type = bool - .help = add H and rotate and flip NQH groups -search_time_limit = 600 - .type = int - .help = max seconds to spend in exhaustive search (default=600) -""" - -def optimize(model): - """ - Carry out reduce optimization + def print_times(self): + print('Detailed timings:') + print("Rebox model:", self.time_rebox_model) + print("Add_missing_H_atoms_at_bogus_position:", self.time_add_missing_H) + print('Add N-terminal propeller', self.time_terminal_propeller) + print("Get new model obj and grm:", self.time_make_grm ) + print("Remove isolated H:", self.time_remove_isolated) + print("Setup Riding manager:", self.time_riding_manager) + print("Remove H that were not parameterized:", self.time_remove_H_nopara) + print("Reset adp, occ; idealize H positions:", self.time_reset_idealize) + print("Remove H on links:", self.time_remove_H_on_links) + print() - Parameters - ---------- - model - mmtbx model object that contains H atoms - H atoms should be at approprite distances - - Returns - ------- - model - mmtbx model object with optimized H atoms - """ - # hierarchy object --> has hierarchy of structure - pdb_hierarchy = model.get_hierarchy() - # geometry restraints manager --> info about ideal bonds, angles; what atoms are bonded, etc. - grm = model.get_restraints_manager() - - print("Reduce optimization happens here") - - return model +# ============================================================================== + +## stub for reduce parameters +## TODO can be parameters or phil, depending on how many options are really needed +#reduce_master_params_str = """ +#flip_NQH = True +# .type = bool +# .help = add H and rotate and flip NQH groups +#search_time_limit = 600 +# .type = int +# .help = max seconds to spend in exhaustive search (default=600) +#""" +# +#def optimize(model): +# """ +# Carry out reduce optimization +# +# Parameters +# ---------- +# model +# mmtbx model object that contains H atoms +# H atoms should be at approprite distances +# +# Returns +# ------- +# model +# mmtbx model object with optimized H atoms +# """ +# # hierarchy object --> has hierarchy of structure +# pdb_hierarchy = model.get_hierarchy() +# # geometry restraints manager --> info about ideal bonds, angles; what atoms are bonded, etc. +# grm = model.get_restraints_manager() +# +# print("Reduce optimization happens here") +# +# return model From b1c44f538febc97039041c3b6235a4028ae01bb0 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 5 Apr 2024 11:36:02 -0700 Subject: [PATCH 302/748] Reduce: Better output file handling --- mmtbx/programs/hydrogenate.py | 69 +++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/mmtbx/programs/hydrogenate.py b/mmtbx/programs/hydrogenate.py index fb5b37da47..dc190c0192 100644 --- a/mmtbx/programs/hydrogenate.py +++ b/mmtbx/programs/hydrogenate.py @@ -28,15 +28,6 @@ print_time = False .type = bool -output - .style = menu_item auto_align -{ - file_name_prefix = None - .type = path - .short_caption = Prefix for file name - .help = Prefix for file name - .input_size = 400 -} ''' # ------------------------------------------------------------------------------ @@ -57,7 +48,10 @@ class Program(ProgramTemplate): # ------------------------------------------------------------------------------ def validate(self): - self.data_manager.has_models(raise_sorry=True) + self.data_manager.has_models( + raise_sorry = True, + expected_n = 1, + exact_count = True) # ------------------------------------------------------------------------------ @@ -65,7 +59,7 @@ def run(self): self.model = self.data_manager.get_model() # make_sub_header('Add H atoms', out=self.logger) - reduce_add_h_obj = reduce_hydrogen.place_hydrogens( + hydrogenate_obj = reduce_hydrogen.place_hydrogens( model = self.model, use_neutron_distances = self.params.use_neutron_distances, n_terminal_charge = self.params.n_terminal_charge, @@ -73,31 +67,50 @@ def run(self): #import line_profiler #lp = line_profiler.LineProfiler(reduce_add_h_obj.run) #lp.enable() - reduce_add_h_obj.run() + hydrogenate_obj.run() #lp.disable() #lp.print_stats() - self.model = reduce_add_h_obj.get_model() - reduce_add_h_obj.show(log = self.logger) - # - #make_sub_header('Optimize H atoms', out=self.logger) - #self.model = reduce_hydrogen.optimize(model=self.model) - # + self.model = hydrogenate_obj.get_model() + hydrogenate_obj.show(log = self.logger) + + # Why is this done here and in the class? if self.params.add_h_to_water: self.model.add_hydrogens(1., occupancy=1.) elif self.params.add_d_to_water: self.model.add_hydrogens(1., element="D", occupancy=1.) - # - if(self.params.output.file_name_prefix is not None): - base = self.params.output.file_name_prefix + + + if self.params.output.prefix is None: + self.params.output.prefix = os.path.split(os.path.splitext( + self.data_manager.get_default_model_name())[0])[1] + + + if self.data_manager.get_model().input_model_format_cif(): + self.output_file_name = self.params.output.prefix+"_hydrogenate.cif" + self.data_manager.write_model_file( + model_str = self.model.model_as_mmcif(), + filename = self.output_file_name) else: - fp = self.data_manager.get_default_model_name() - base = os.path.splitext(os.path.basename(fp))[0] - of = open("%s_hydrogenate.pdb"%base,"w") - of.write(self.model.model_as_pdb()) - of.close() + self.output_file_name = self.params.output.prefix+"_hydrogenate.pdb" + self.data_manager.write_model_file( + model_str = self.model.model_as_pdb(), + filename = self.output_file_name) -# ------------------------------------------------------------------------------ + print("Wrote file: %s" % self.output_file_name, file=self.logger) def get_results(self): - return group_args(model = self.model) + return group_args( + output_file_name=self.output_file_name) + + +# ------------------------------------------------------------------------------ + +# def get_results(self): +# return group_args(model = self.model) +# def get_results(self): +# # results object not returned because it contains maps +# return group_args( +# message = self.message, +# output_file = self.output_file_name, +# model = self.data_manager.get_default_model_name()) From 5db2e0f236670457569a782f509b8ae2c48535ae Mon Sep 17 00:00:00 2001 From: Pavel Date: Fri, 5 Apr 2024 18:15:10 -0700 Subject: [PATCH 303/748] Example of using full chi-angle sampling to fit residue side-chain (by TomT request) --- mmtbx/model/model.py | 5 + .../tst_fit_residue_full_sampling.py | 273 ++++++++++++++++++ mmtbx/run_tests.py | 1 + 3 files changed, 279 insertions(+) create mode 100644 mmtbx/refinement/real_space/tst_fit_residue_full_sampling.py diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index 3d40c4ba25..73f873e0ec 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -1493,6 +1493,11 @@ def get_ener_lib(self): self._ener_lib = mmtbx.monomer_library.server.ener_lib() return self._ener_lib + def get_states_collector(self): + return mmtbx.utils.states( + xray_structure = self.get_xray_structure(), + pdb_hierarchy = self.get_hierarchy()) + def rotamer_outlier_selection(self): rm = self.get_rotamer_manager() result = flex.bool(self.size(), False) diff --git a/mmtbx/refinement/real_space/tst_fit_residue_full_sampling.py b/mmtbx/refinement/real_space/tst_fit_residue_full_sampling.py new file mode 100644 index 0000000000..225594de69 --- /dev/null +++ b/mmtbx/refinement/real_space/tst_fit_residue_full_sampling.py @@ -0,0 +1,273 @@ +from __future__ import absolute_import, division, print_function +import time +import mmtbx.refinement.real_space +import iotbx.pdb +from libtbx.utils import null_out +from scitbx.matrix import rotate_point_around_axis +from mmtbx.rotamer.rotamer_eval import RotamerEval +from mmtbx.idealized_aa_residues import sample_rotamers +from cctbx import maptbx +from scitbx.array_family import flex + +pdb_good = """\ +CRYST1 21.207 17.255 22.844 90.00 90.00 90.00 P 1 +ATOM 1 N TRP L 148 14.260 10.871 17.844 1.00 22.69 N +ATOM 2 CA TRP L 148 14.094 10.389 16.478 1.00 19.52 C +ATOM 3 C TRP L 148 14.872 9.095 16.265 1.00 21.40 C +ATOM 4 O TRP L 148 15.903 8.867 16.898 1.00 21.95 O +ATOM 5 CB TRP L 148 14.553 11.451 15.476 1.00 18.93 C +ATOM 6 CG TRP L 148 14.396 11.033 14.046 1.00 16.05 C +ATOM 7 CD1 TRP L 148 15.328 10.415 13.265 1.00 15.60 C +ATOM 8 CD2 TRP L 148 13.234 11.204 13.225 1.00 15.47 C +ATOM 9 NE1 TRP L 148 14.819 10.190 12.008 1.00 17.97 N +ATOM 10 CE2 TRP L 148 13.535 10.665 11.958 1.00 16.42 C +ATOM 11 CE3 TRP L 148 11.968 11.759 13.437 1.00 16.97 C +ATOM 12 CZ2 TRP L 148 12.618 10.666 10.909 1.00 15.78 C +ATOM 13 CZ3 TRP L 148 11.059 11.759 12.395 1.00 17.54 C +ATOM 14 CH2 TRP L 148 11.389 11.216 11.147 1.00 17.61 C +ATOM 15 HA TRP L 148 13.155 10.207 16.317 1.00 19.52 H +ATOM 16 HB2 TRP L 148 14.028 12.255 15.610 1.00 18.93 H +ATOM 17 HB3 TRP L 148 15.492 11.640 15.629 1.00 18.93 H +ATOM 18 HD1 TRP L 148 16.184 10.180 13.542 1.00 15.60 H +ATOM 19 HE1 TRP L 148 15.239 9.813 11.359 1.00 17.97 H +ATOM 20 HE3 TRP L 148 11.742 12.122 14.264 1.00 16.97 H +ATOM 21 HZ2 TRP L 148 12.834 10.306 10.079 1.00 15.78 H +ATOM 22 HZ3 TRP L 148 10.215 12.126 12.525 1.00 17.54 H +ATOM 23 HH2 TRP L 148 10.757 11.230 10.464 1.00 17.61 H +ATOM 24 N TYR L 192 11.041 5.312 9.916 1.00 20.96 N +ATOM 25 CA TYR L 192 11.151 6.712 10.309 1.00 18.77 C +ATOM 26 C TYR L 192 9.991 7.112 11.214 1.00 20.42 C +ATOM 27 O TYR L 192 8.825 6.971 10.844 1.00 20.12 O +ATOM 28 CB TYR L 192 11.189 7.614 9.074 1.00 15.79 C +ATOM 29 CG TYR L 192 12.351 7.332 8.148 1.00 19.38 C +ATOM 30 CD1 TYR L 192 12.232 6.414 7.112 1.00 18.58 C +ATOM 31 CD2 TYR L 192 13.566 7.984 8.308 1.00 13.17 C +ATOM 32 CE1 TYR L 192 13.291 6.154 6.263 1.00 17.30 C +ATOM 33 CE2 TYR L 192 14.631 7.730 7.464 1.00 19.20 C +ATOM 34 CZ TYR L 192 14.487 6.814 6.444 1.00 19.28 C +ATOM 35 OH TYR L 192 15.544 6.558 5.601 1.00 22.20 O +ATOM 36 HA TYR L 192 11.976 6.840 10.802 1.00 18.77 H +ATOM 37 HB2 TYR L 192 10.370 7.488 8.569 1.00 15.79 H +ATOM 38 HB3 TYR L 192 11.258 8.537 9.363 1.00 15.79 H +ATOM 39 HD1 TYR L 192 11.426 5.967 6.988 1.00 18.58 H +ATOM 40 HD2 TYR L 192 13.666 8.602 8.996 1.00 13.17 H +ATOM 41 HE1 TYR L 192 13.196 5.536 5.574 1.00 17.30 H +ATOM 42 HE2 TYR L 192 15.439 8.174 7.584 1.00 19.20 H +ATOM 43 HH TYR L 192 16.207 7.024 5.821 1.00 22.20 H +ATOM 44 N PHE L 209 6.405 6.669 9.777 1.00 21.36 N +ATOM 45 CA PHE L 209 5.861 6.089 8.555 1.00 22.67 C +ATOM 46 C PHE L 209 6.783 5.000 8.016 1.00 26.96 C +ATOM 47 O PHE L 209 7.997 5.049 8.212 1.00 22.94 O +ATOM 48 CB PHE L 209 5.650 7.172 7.495 1.00 24.63 C +ATOM 49 CG PHE L 209 6.906 7.909 7.122 1.00 23.08 C +ATOM 50 CD1 PHE L 209 7.686 7.482 6.060 1.00 22.08 C +ATOM 51 CD2 PHE L 209 7.306 9.027 7.834 1.00 22.40 C +ATOM 52 CE1 PHE L 209 8.841 8.158 5.715 1.00 26.03 C +ATOM 53 CE2 PHE L 209 8.460 9.707 7.493 1.00 21.71 C +ATOM 54 CZ PHE L 209 9.229 9.271 6.433 1.00 20.59 C +ATOM 55 HA PHE L 209 5.000 5.686 8.750 1.00 22.67 H +ATOM 56 HB2 PHE L 209 5.299 6.759 6.691 1.00 24.63 H +ATOM 57 HB3 PHE L 209 5.015 7.822 7.835 1.00 24.63 H +ATOM 58 HD1 PHE L 209 7.430 6.732 5.574 1.00 22.08 H +ATOM 59 HD2 PHE L 209 6.792 9.325 8.549 1.00 22.40 H +ATOM 60 HE1 PHE L 209 9.357 7.862 5.000 1.00 26.03 H +ATOM 61 HE2 PHE L 209 8.719 10.457 7.979 1.00 21.71 H +ATOM 62 HZ PHE L 209 10.006 9.727 6.202 1.00 20.59 H +TER +END +""" + +pdb_poor = """\ +CRYST1 21.207 17.255 22.844 90.00 90.00 90.00 P 1 +ATOM 1 N TRP L 148 14.260 10.871 17.844 1.00 22.69 N +ATOM 2 CA TRP L 148 14.094 10.389 16.478 1.00 19.52 C +ATOM 3 C TRP L 148 14.872 9.095 16.265 1.00 21.40 C +ATOM 4 O TRP L 148 15.903 8.867 16.898 1.00 21.95 O +ATOM 5 CB TRP L 148 14.553 11.451 15.476 1.00 18.93 C +ATOM 6 CG TRP L 148 14.396 11.033 14.046 1.00 16.05 C +ATOM 7 CD1 TRP L 148 15.328 10.415 13.265 1.00 15.60 C +ATOM 8 CD2 TRP L 148 13.234 11.204 13.225 1.00 15.47 C +ATOM 9 NE1 TRP L 148 14.819 10.190 12.008 1.00 17.97 N +ATOM 10 CE2 TRP L 148 13.535 10.665 11.958 1.00 16.42 C +ATOM 11 CE3 TRP L 148 11.968 11.759 13.437 1.00 16.97 C +ATOM 12 CZ2 TRP L 148 12.618 10.666 10.909 1.00 15.78 C +ATOM 13 CZ3 TRP L 148 11.059 11.759 12.395 1.00 17.54 C +ATOM 14 CH2 TRP L 148 11.389 11.216 11.147 1.00 17.61 C +ATOM 15 HA TRP L 148 13.155 10.207 16.317 1.00 19.52 H +ATOM 16 HB2 TRP L 148 14.028 12.255 15.610 1.00 18.93 H +ATOM 17 HB3 TRP L 148 15.492 11.640 15.629 1.00 18.93 H +ATOM 18 HD1 TRP L 148 16.184 10.180 13.542 1.00 15.60 H +ATOM 19 HE1 TRP L 148 15.239 9.813 11.359 1.00 17.97 H +ATOM 20 HE3 TRP L 148 11.742 12.122 14.264 1.00 16.97 H +ATOM 21 HZ2 TRP L 148 12.834 10.306 10.079 1.00 15.78 H +ATOM 22 HZ3 TRP L 148 10.215 12.126 12.525 1.00 17.54 H +ATOM 23 HH2 TRP L 148 10.757 11.230 10.464 1.00 17.61 H +ATOM 24 N TYR L 192 11.041 5.312 9.916 1.00 20.96 N +ATOM 25 CA TYR L 192 11.151 6.712 10.309 1.00 18.77 C +ATOM 26 C TYR L 192 9.991 7.112 11.214 1.00 20.42 C +ATOM 27 O TYR L 192 8.825 6.971 10.844 1.00 20.12 O +ATOM 28 CB TYR L 192 11.189 7.614 9.074 1.00 15.79 C +ATOM 29 CG TYR L 192 12.585 7.885 8.559 1.00 19.38 C +ATOM 30 CD1 TYR L 192 12.786 8.551 7.356 1.00 18.58 C +ATOM 31 CD2 TYR L 192 13.702 7.478 9.276 1.00 13.17 C +ATOM 32 CE1 TYR L 192 14.060 8.801 6.883 1.00 17.30 C +ATOM 33 CE2 TYR L 192 14.980 7.724 8.810 1.00 19.20 C +ATOM 34 CZ TYR L 192 15.152 8.386 7.613 1.00 19.28 C +ATOM 35 OH TYR L 192 16.422 8.633 7.145 1.00 22.20 O +ATOM 36 HA TYR L 192 11.976 6.840 10.802 1.00 18.77 H +ATOM 37 HB2 TYR L 192 10.687 7.189 8.360 1.00 15.79 H +ATOM 38 HB3 TYR L 192 10.785 8.467 9.297 1.00 15.79 H +ATOM 39 HD1 TYR L 192 12.050 8.832 6.862 1.00 18.58 H +ATOM 40 HD2 TYR L 192 13.589 7.030 10.083 1.00 13.17 H +ATOM 41 HE1 TYR L 192 14.178 9.248 6.075 1.00 17.30 H +ATOM 42 HE2 TYR L 192 15.718 7.444 9.300 1.00 19.20 H +ATOM 43 HH TYR L 192 16.991 8.329 7.682 1.00 22.20 H +ATOM 44 N PHE L 209 6.405 6.669 9.777 1.00 21.36 N +ATOM 45 CA PHE L 209 5.861 6.089 8.555 1.00 22.67 C +ATOM 46 C PHE L 209 6.783 5.000 8.016 1.00 26.96 C +ATOM 47 O PHE L 209 7.997 5.049 8.212 1.00 22.94 O +ATOM 48 CB PHE L 209 5.650 7.172 7.495 1.00 24.63 C +ATOM 49 CG PHE L 209 6.906 7.909 7.122 1.00 23.08 C +ATOM 50 CD1 PHE L 209 7.686 7.482 6.060 1.00 22.08 C +ATOM 51 CD2 PHE L 209 7.306 9.027 7.834 1.00 22.40 C +ATOM 52 CE1 PHE L 209 8.841 8.158 5.715 1.00 26.03 C +ATOM 53 CE2 PHE L 209 8.460 9.707 7.493 1.00 21.71 C +ATOM 54 CZ PHE L 209 9.229 9.271 6.433 1.00 20.59 C +ATOM 55 HA PHE L 209 5.000 5.686 8.750 1.00 22.67 H +ATOM 56 HB2 PHE L 209 5.299 6.759 6.691 1.00 24.63 H +ATOM 57 HB3 PHE L 209 5.015 7.822 7.835 1.00 24.63 H +ATOM 58 HD1 PHE L 209 7.430 6.732 5.574 1.00 22.08 H +ATOM 59 HD2 PHE L 209 6.792 9.325 8.549 1.00 22.40 H +ATOM 60 HE1 PHE L 209 9.357 7.862 5.000 1.00 26.03 H +ATOM 61 HE2 PHE L 209 8.719 10.457 7.979 1.00 21.71 H +ATOM 62 HZ PHE L 209 10.006 9.727 6.202 1.00 20.59 H +TER 63 PHE L 209 +END +""" + +def main(use_mask): + # + # SETUP INPUTS: read good model, compute map from it + # + pdb_inp = iotbx.pdb.input(source_info=None, lines=pdb_good) + model_good = mmtbx.model.manager(model_input=pdb_inp, log=null_out()) + mon_lib_srv = model_good.get_mon_lib_srv() + with open("model_good.pdb", "w") as fo: + fo.write(model_good.model_as_pdb()) + xrs_good = model_good.get_xray_structure() + f_calc = xrs_good.structure_factors(d_min = 2).f_calc() + crystal_gridding = maptbx.crystal_gridding( + unit_cell = xrs_good.unit_cell(), + space_group_info = xrs_good.space_group_info(), + symmetry_flags = maptbx.use_space_group_symmetry, + step = 0.5) + fft_map = f_calc.fft_map(crystal_gridding=crystal_gridding) + fft_map.apply_sigma_scaling() + target_map = fft_map.real_map_unpadded() + # + # Read poor model (same as good model except one residue side chain) + # + pdb_inp = iotbx.pdb.input(source_info=None, lines=pdb_poor) + model_poor = mmtbx.model.manager(model_input=pdb_inp, log=null_out()) + with open("model_poor.pdb", "w") as fo: + fo.write(model_poor.model_as_pdb()) + h_poor = model_poor.get_hierarchy() + sites_cart_all = model_poor.get_sites_cart() + uc = model_poor.crystal_symmetry().unit_cell() + # + # Track states + # + states = model_poor.get_states_collector() + # + # This is the residue (number 192) we will be working on (sampling rotamers) + # + for m in h_poor.models(): + for c in m.chains(): + for r in c.residues(): + if int(r.resseq)==192: + residue = r + selection = r.atoms().extract_i_seq() + break + # + # Mask neighjbors. If any trial rotamer atom hits mask value 0 it will be + # rejected. + # + if(use_mask): + sel_to_mask = ~flex.bool(model_poor.size(), selection) + mask = maptbx.mask( + xray_structure = model_poor.get_xray_structure().select(sel_to_mask), + n_real = crystal_gridding.n_real(), + mask_value_inside_molecule = 0, + mask_value_outside_molecule = 1, + solvent_radius = 0, + atom_radius = None) + # + # Sample all rotamers + # + clusters = mmtbx.refinement.real_space.aa_residue_axes_and_clusters( + residue = residue, + mon_lib_srv = mon_lib_srv, + backbone_sample = False).clusters + rotamer_eval = RotamerEval() + nested_loop = sample_rotamers.get_nested_loop( + n=len(clusters), fine=False, start=0, end=360) + sites_cart = residue.atoms().extract_xyz() + score_best = -1.e9 + sites_cart_best = None + for angles in nested_loop: + sites_cart_moved = sites_cart.deep_copy() + score=0 + for i, angle in enumerate(angles): + cl = clusters[i] + for atom_to_rotate in cl.atoms_to_rotate: + new_site_cart = rotate_point_around_axis( + axis_point_1 = sites_cart_moved[cl.axis[0]], + axis_point_2 = sites_cart_moved[cl.axis[1]], + point = sites_cart_moved[atom_to_rotate], + angle = angle, + deg = True) + sites_cart_moved[atom_to_rotate] = new_site_cart + residue.atoms().set_xyz(sites_cart_moved) + sites_frac_moved = uc.fractionalize(sites_cart_moved) + # Check if trial rotamer bumps into neighor atoms + hit_neighbour = False + if(use_mask): + for site_frac in sites_frac_moved: + mv = mask.value_at_closest_grid_point(site_frac) + if abs(mv)<1.e-6: hit_neighbour = True + score += target_map.eight_point_interpolation(site_frac) + # Evaluate rotemeric state + fl = str(rotamer_eval.evaluate_residue_2(residue = residue)).strip().upper() + # Accept rotamer if it is not OUTLIER and does not clash with neighbours + if(fl in ["ALLOWED", "FAVORED"] and not hit_neighbour): + tmp = sites_cart_all.deep_copy() + tmp = tmp.set_selected(selection, sites_cart_moved) + states.add(sites_cart=tmp) + if(score > score_best): + score_best = score + sites_cart_best = sites_cart_moved.deep_copy() + # + # Write multi-model file that contains all accepted rotamers + # + states.write(file_name="all_states_UseMask%s.pdb"%str(use_mask), + crystal_symmetry=model_poor.crystal_symmetry()) + # + # Set best fitting rotamer and write final model + # + residue.atoms().set_xyz(sites_cart_best) + with open("model_fitted.pdb", "w") as fo: + fo.write(model_poor.model_as_pdb()) + # + # Assert fitted model matches the answer + # + if use_mask: + s1 = model_good.get_sites_cart() + s2 = model_poor.get_sites_cart() + max_dist = flex.max(flex.sqrt((s1 - s2).dot())) + assert max_dist < 0.1 + +if(__name__ == "__main__"): + t0 = time.time() + for use_mask in [True, False]: + main(use_mask = use_mask) + print(time.time()-t0) diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index 5eb01979f8..f76686414a 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -225,6 +225,7 @@ "$D/regression/tst_schrodinger_interface.py", # real-space tools "$D/refinement/real_space/tst_aa_residue_axes_and_clusters.py", + "$D/refinement/real_space/tst_fit_residue_full_sampling.py", "$D/refinement/real_space/tst_fit_residue_0.py", "$D/refinement/real_space/tst_fit_residue_0H.py", "$D/refinement/real_space/tst_fit_residue_1.py", From 9a7c8ad43cfdaf1475d37457706dd8f98f94c5bb Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Mon, 8 Apr 2024 10:57:11 -0700 Subject: [PATCH 304/748] libtbx: catch ValueError as well for rebuilding caches --- libtbx/dlite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libtbx/dlite.py b/libtbx/dlite.py index f8c7e83e09..ef6ca115e1 100644 --- a/libtbx/dlite.py +++ b/libtbx/dlite.py @@ -29,7 +29,7 @@ def try_loading_db(file_name): db = None try: db = target_db(file_name) - except Sorry as s: + except (Sorry, ValueError) as s: if 'unsupported pickle protocol' in str(s): os.remove(file_name) db = target_db(file_name) From 068c97a4821cf94dc1c90d960c493127ffd3f25a Mon Sep 17 00:00:00 2001 From: Pavel Date: Mon, 8 Apr 2024 11:16:21 -0700 Subject: [PATCH 305/748] Adjust expectation --- mmtbx/building/tst_extend_sidechains.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/building/tst_extend_sidechains.py b/mmtbx/building/tst_extend_sidechains.py index 65d0c6f8d0..52b6f275b9 100644 --- a/mmtbx/building/tst_extend_sidechains.py +++ b/mmtbx/building/tst_extend_sidechains.py @@ -31,7 +31,7 @@ def exercise_model_only(): ATOM 6 CG LYS A 7 4.366 7.205 0.850 1.00 33.58 C ATOM 7 CD LYS A 7 3.241 7.559 -0.109 1.00 41.39 C ATOM 8 CE LYS A 7 3.011 6.457 -1.129 1.00 48.81 C -ATOM 9 NZ LYS A 7 1.911 6.790 -2.075 1.00 26.71 N +ATOM 9 NZ LYS A 7 1.911 6.790 -2.075 0.10 26.71 N TER """) From 922a961d65968c576bc030f9181b5e8aadc150f2 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Mon, 8 Apr 2024 13:16:39 -0700 Subject: [PATCH 306/748] Tidy up Phenix tools: remove mmtbx.analyze_static_disorder --- mmtbx/command_line/analyze_static_disorder.py | 70 ------------------- 1 file changed, 70 deletions(-) delete mode 100644 mmtbx/command_line/analyze_static_disorder.py diff --git a/mmtbx/command_line/analyze_static_disorder.py b/mmtbx/command_line/analyze_static_disorder.py deleted file mode 100644 index 490231ebdd..0000000000 --- a/mmtbx/command_line/analyze_static_disorder.py +++ /dev/null @@ -1,70 +0,0 @@ -# LIBTBX_SET_DISPATCHER_NAME mmtbx.analyze_static_disorder - -from __future__ import absolute_import, division, print_function -from libtbx.str_utils import make_header, make_sub_header -from libtbx import easy_pickle -import os.path -import sys - -def master_phil(): - from mmtbx.command_line import generate_master_phil_with_inputs - return generate_master_phil_with_inputs( - enable_stop_for_unknowns=False, - enable_pdb_interpretation_params=True, - phil_string=""" -ignore_inconsistent_occupancy = True - .type = bool -pickle = False - .type = bool -verbose = False - .type = bool -""") - -def run(args, out=sys.stdout): - from mmtbx.disorder import analyze_model - import mmtbx.validation.molprobity - import mmtbx.command_line - cmdline = mmtbx.command_line.load_model_and_data( - args=args, - master_phil=master_phil(), - require_data=False, - create_fmodel=True, - process_pdb_file=True, - usage_string="mmtbx.analyze_static_disorder model.pdb", - out=out) - hierarchy = cmdline.pdb_hierarchy - params = cmdline.params - validation = mmtbx.validation.molprobity.molprobity( - pdb_hierarchy=hierarchy, - xray_structure=cmdline.xray_structure, - fmodel=cmdline.fmodel, - crystal_symmetry=cmdline.crystal_symmetry, - geometry_restraints_manager=cmdline.geometry, - header_info=None, - keep_hydrogens=False, - outliers_only=False, - nuclear=False) - segments = [] - make_header("Analyzing model", out=out) - if (params.ignore_inconsistent_occupancy): - print("Discontinuous occupancies will be ignored.", file=out) - process = analyze_model.process_pdb_hierarchy( - pdb_hierarchy=hierarchy, - validation=validation, - ignore_inconsistent_occupancy=params.ignore_inconsistent_occupancy, - log=out) - make_sub_header("MolProbity validation", out=out) - validation.show_summary(out=out) - make_sub_header("Disorder analysis", out=out) - if (process.n_disordered == 0): - print("No alternate conformations found.", file=out) - else : - process.show(out=out, verbose=params.verbose) - if (params.pickle): - file_name = os.path.basename( - os.path.splitext(params.input.pdb.file_name[0])[0]) + ".pkl" - easy_pickle.dump(file_name, process) - return process - -if (__name__ == "__main__"): - run(sys.argv[1:]) From 0b541ba8ea38d95abd570bbf0fa905c4da93e48a Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 9 Apr 2024 11:38:22 -0700 Subject: [PATCH 307/748] Tidy up Phenix: remove fix_rotamer_outliers --- mmtbx/command_line/fix_rotamer_outliers.py | 94 ------------ mmtbx/regression/tst_fix_rotamer_outliers.py | 148 ------------------- 2 files changed, 242 deletions(-) delete mode 100644 mmtbx/command_line/fix_rotamer_outliers.py delete mode 100644 mmtbx/regression/tst_fix_rotamer_outliers.py diff --git a/mmtbx/command_line/fix_rotamer_outliers.py b/mmtbx/command_line/fix_rotamer_outliers.py deleted file mode 100644 index cff5b41793..0000000000 --- a/mmtbx/command_line/fix_rotamer_outliers.py +++ /dev/null @@ -1,94 +0,0 @@ -from __future__ import absolute_import, division, print_function -# LIBTBX_SET_DISPATCHER_NAME mmtbx.fix_rotamer_outliers - -import sys -import iotbx.pdb -import iotbx.phil -import iotbx.pdb -import mmtbx.model -import scitbx.math -import mmtbx.idealized_aa_residues.rotamer_manager -import mmtbx.refinement.real_space.fit_residues - -master_phil_str = """ -show_all_params = False - .type = bool - .style = hidden -radius = 5. - .type = float - .help = radius for determining surrounding atoms around the residue - .style = hidden -output_prefix = rotamer_fixed - .type = str -file_name = None - .type = path - .optional = True - .style = hidden -""" - -master_phil = iotbx.phil.parse(master_phil_str, process_includes=True) - -def show_usage(): - help_msg = """\ -phenix.fix_rotamer_outliers: tool for fixing rotamer outliers. - For every rotamer outlier it will choose the rotamer with minimum - clashes with surrounding atoms. - -Usage examples: - mmtbx.fix_rotamer_outliers model.pdb - mmtbx.fix_rotamer_outliers model.pdb - mmtbx.fix_rotamer_outliers model.pdb ligands.cif output_prefix=rot_fixed - -Full scope of parameters: - """ - print(help_msg) - master_phil.show() - -def run(args, params=None, out=sys.stdout, model=None): - if model is None: - if ( ((len(args) == 0) and (params is None)) or - ((len(args) > 0) and ((args[0] == "-h") or (args[0] == "--help"))) ): - show_usage() - return - - if (params is None): - pcl = iotbx.phil.process_command_line_with_files( - args=args, - master_phil_string=master_phil_str, - pdb_file_def="file_name") - work_params = pcl.work.extract() - # or use parameters defined by GUI - else: - work_params = params - pdb_inp = iotbx.pdb.input(file_name=work_params.file_name) - - pdb_int_params = mmtbx.model.manager.get_default_pdb_interpretation_params() - pdb_int_params.pdb_interpretation.clash_guard.nonbonded_distance_threshold=None - model = mmtbx.model.manager(model_input = pdb_inp) - model.process(pdb_interpretation_params=pdb_int_params, - make_restraints=True) - else: - work_params = params - if params is None: - work_params = master_phil.extract() - - result = mmtbx.refinement.real_space.fit_residues.run( - pdb_hierarchy = model.get_hierarchy(), - crystal_symmetry = model.crystal_symmetry(), - map_data = None, - rotamer_manager = mmtbx.idealized_aa_residues.rotamer_manager.load( - rotamers="favored_allowed"), - sin_cos_table = scitbx.math.sin_cos_table(n=10000), - backbone_sample = False, - rotatable_hd = model.rotatable_hd_selection(iselection=False), - mon_lib_srv = model.get_mon_lib_srv(), - log = out) - model.set_sites_cart( - sites_cart = result.pdb_hierarchy.atoms().extract_xyz()) - res_pdb_str = model.model_as_pdb() - with open("%s.pdb" % work_params.output_prefix, "w") as f: - f.write(res_pdb_str) - return model - -if (__name__ == "__main__"): - run(sys.argv[1:]) diff --git a/mmtbx/regression/tst_fix_rotamer_outliers.py b/mmtbx/regression/tst_fix_rotamer_outliers.py deleted file mode 100644 index 0dc0a63230..0000000000 --- a/mmtbx/regression/tst_fix_rotamer_outliers.py +++ /dev/null @@ -1,148 +0,0 @@ -from __future__ import absolute_import, division, print_function - -from mmtbx.command_line.fix_rotamer_outliers import run -import iotbx.pdb -import mmtbx.model - -pdb_str_1 = """\ -CRYST1 18.486 29.189 16.919 90.00 90.00 90.00 P 1 -ATOM 1 N TYR A 58 6.848 19.603 11.185 1.00 7.73 N -ATOM 2 CA TYR A 58 7.439 18.674 10.233 1.00 8.65 C -ATOM 3 C TYR A 58 7.228 17.251 10.706 1.00 9.84 C -ATOM 4 O TYR A 58 7.212 16.994 11.919 1.00 8.58 O -ATOM 5 CB TYR A 58 8.929 18.959 10.045 1.00 20.00 C -ATOM 6 CG TYR A 58 9.344 20.355 10.457 1.00 20.00 C -ATOM 7 CD1 TYR A 58 8.393 21.339 10.700 1.00 20.00 C -ATOM 8 CD2 TYR A 58 10.683 20.685 10.603 1.00 20.00 C -ATOM 9 CE1 TYR A 58 8.768 22.614 11.076 1.00 20.00 C -ATOM 10 CE2 TYR A 58 11.068 21.959 10.980 1.00 20.00 C -ATOM 11 CZ TYR A 58 10.107 22.918 11.215 1.00 20.00 C -ATOM 12 OH TYR A 58 10.483 24.189 11.588 1.00 20.00 O -ATOM 13 N SER A 59 7.076 16.327 9.756 1.00 9.65 N -ATOM 14 CA SER A 59 6.909 14.912 10.080 1.00 5.80 C -ATOM 15 C SER A 59 7.795 14.069 9.169 1.00 10.35 C -ATOM 16 O SER A 59 8.161 14.502 8.075 1.00 10.56 O -ATOM 17 CB SER A 59 5.446 14.487 9.943 1.00 20.00 C -ATOM 18 OG SER A 59 5.000 14.619 8.604 1.00 20.00 O -""" - -pdb_str_2 = """\ -CRYST1 130.848 130.848 149.639 90.00 90.00 120.00 P 64 2 2 12 -ATOM 95 N ARG A 30 -18.833 17.433 -14.879 1.00191.24 N -ATOM 96 CA ARG A 30 -18.615 17.619 -16.290 1.00191.04 C -ATOM 97 C ARG A 30 -18.032 19.002 -16.408 1.00190.51 C -ATOM 98 O ARG A 30 -18.720 19.978 -16.161 1.00190.07 O -ATOM 99 CB ARG A 30 -19.941 17.558 -17.076 1.00191.84 C -ATOM 100 CG ARG A 30 -20.909 16.521 -16.584 1.00192.91 C -ATOM 101 CD ARG A 30 -22.176 16.530 -17.408 1.00193.90 C -ATOM 102 NE ARG A 30 -23.271 15.875 -16.703 1.00195.21 N -ATOM 103 CZ ARG A 30 -24.498 15.744 -17.196 1.00195.78 C -ATOM 104 NH1 ARG A 30 -24.776 16.224 -18.399 1.00196.03 N -ATOM 105 NH2 ARG A 30 -25.449 15.149 -16.488 1.00195.90 N -ATOM 106 N LYS A 31 -16.776 19.084 -16.815 1.00190.39 N -ATOM 107 CA LYS A 31 -16.164 20.381 -17.016 1.00190.65 C -ATOM 108 C LYS A 31 -17.139 21.024 -18.016 1.00191.02 C -ATOM 109 O LYS A 31 -17.240 22.238 -18.137 1.00190.75 O -ATOM 110 CB LYS A 31 -14.782 20.200 -17.673 1.00190.39 C -ATOM 111 CG LYS A 31 -13.794 21.338 -17.444 1.00189.92 C -ATOM 112 CD LYS A 31 -12.448 20.983 -18.063 1.00189.44 C -ATOM 113 CE LYS A 31 -11.369 21.951 -17.632 1.00189.51 C -ATOM 114 NZ LYS A 31 -10.046 21.567 -18.180 1.00189.58 N -ATOM 115 N ASP A 32 -17.885 20.148 -18.681 1.00192.02 N -ATOM 116 CA ASP A 32 -18.842 20.462 -19.742 1.00192.58 C -ATOM 117 C ASP A 32 -19.950 21.497 -19.544 1.00191.35 C -ATOM 118 O ASP A 32 -20.097 22.367 -20.384 1.00191.52 O -ATOM 119 CB ASP A 32 -19.488 19.164 -20.226 1.00195.14 C -ATOM 120 CG ASP A 32 -18.506 17.994 -20.259 1.00197.19 C -ATOM 121 OD1 ASP A 32 -18.792 16.987 -20.944 1.00197.86 O -ATOM 122 OD2 ASP A 32 -17.446 18.072 -19.596 1.00198.95 O -ATOM 123 N ILE A 33 -20.744 21.422 -18.481 1.00189.52 N -ATOM 124 CA ILE A 33 -21.803 22.408 -18.347 1.00187.36 C -ATOM 125 C ILE A 33 -21.351 23.724 -17.684 1.00186.08 C -ATOM 126 O ILE A 33 -22.173 24.531 -17.271 1.00185.90 O -ATOM 127 CB ILE A 33 -23.073 21.768 -17.669 1.00186.97 C -ATOM 128 CG1 ILE A 33 -22.681 20.853 -16.498 1.00186.29 C -ATOM 129 CG2 ILE A 33 -23.832 20.928 -18.700 1.00186.44 C -ATOM 130 CD1 ILE A 33 -23.867 20.142 -15.833 1.00184.51 C -ATOM 131 N SER A 34 -20.030 23.933 -17.618 1.00184.40 N -ATOM 132 CA SER A 34 -19.424 25.157 -17.069 1.00182.95 C -ATOM 133 C SER A 34 -19.038 25.962 -18.306 1.00182.29 C -ATOM 134 O SER A 34 -18.590 25.403 -19.300 1.00182.43 O -ATOM 135 CB SER A 34 -18.199 24.839 -16.225 1.00182.36 C -ATOM 136 OG SER A 34 -16.990 25.070 -16.946 1.00182.11 O -ATOM 137 N GLU A 35 -19.219 27.269 -18.236 1.00181.35 N -ATOM 138 CA GLU A 35 -19.013 28.138 -19.394 1.00180.75 C -ATOM 139 C GLU A 35 -17.702 28.735 -19.927 1.00179.75 C -ATOM 140 O GLU A 35 -16.588 28.226 -19.772 1.00178.29 O -ATOM 141 CB GLU A 35 -19.990 29.296 -19.259 1.00181.98 C -ATOM 142 CG GLU A 35 -21.338 29.024 -19.904 1.00183.50 C -ATOM 143 CD GLU A 35 -21.656 27.558 -20.136 1.00184.28 C -ATOM 144 OE1 GLU A 35 -21.062 26.961 -21.059 1.00183.95 O -ATOM 145 OE2 GLU A 35 -22.521 27.021 -19.411 1.00185.10 O -ATOM 146 N ASN A 36 -17.914 29.823 -20.663 1.00179.92 N -ATOM 147 CA ASN A 36 -16.844 30.610 -21.229 1.00180.62 C -ATOM 148 C ASN A 36 -16.281 31.058 -19.926 1.00181.23 C -ATOM 149 O ASN A 36 -15.103 31.341 -19.819 1.00181.62 O -ATOM 150 CB ASN A 36 -17.388 31.832 -21.941 1.00180.82 C -ATOM 151 CG ASN A 36 -17.645 31.611 -23.392 1.00182.08 C -ATOM 152 OD1 ASN A 36 -16.729 31.377 -24.171 1.00182.92 O -ATOM 153 ND2 ASN A 36 -18.907 31.705 -23.778 1.00183.27 N -ATOM 154 N ALA A 37 -17.158 31.116 -18.928 1.00181.85 N -ATOM 155 CA ALA A 37 -16.773 31.516 -17.583 1.00182.29 C -ATOM 156 C ALA A 37 -15.531 30.754 -17.159 1.00182.76 C -ATOM 157 O ALA A 37 -14.583 31.328 -16.615 1.00182.32 O -ATOM 158 CB ALA A 37 -17.923 31.251 -16.606 1.00181.85 C -ATOM 159 N LEU A 38 -15.547 29.456 -17.435 1.00183.67 N -ATOM 160 CA LEU A 38 -14.427 28.579 -17.111 1.00184.12 C -ATOM 161 C LEU A 38 -13.148 29.073 -17.763 1.00184.05 C -ATOM 162 O LEU A 38 -12.040 28.809 -17.283 1.00183.42 O -ATOM 163 CB LEU A 38 -14.738 27.147 -17.572 1.00184.55 C -ATOM 164 CG LEU A 38 -13.625 26.095 -17.588 1.00184.94 C -ATOM 165 CD1 LEU A 38 -14.247 24.709 -17.608 1.00185.45 C -ATOM 166 CD2 LEU A 38 -12.721 26.297 -18.797 1.00184.46 C -ATOM 167 N LYS A 39 -13.327 29.801 -18.859 1.00184.14 N -ATOM 168 CA LYS A 39 -12.226 30.363 -19.628 1.00183.59 C -ATOM 169 C LYS A 39 -11.302 31.159 -18.711 1.00182.98 C -ATOM 170 O LYS A 39 -10.093 30.912 -18.655 1.00183.18 O -ATOM 171 CB LYS A 39 -12.790 31.263 -20.749 1.00183.64 C -ATOM 172 CG LYS A 39 -11.851 31.587 -21.912 1.00184.17 C -ATOM 173 CD LYS A 39 -12.620 32.210 -23.080 1.00184.66 C -ATOM 174 CE LYS A 39 -11.678 32.675 -24.183 1.00185.01 C -ATOM 175 NZ LYS A 39 -12.408 33.271 -25.337 1.00185.25 N -""" - -def get_necessary_inputs(pdb_str): - pdb_inp = iotbx.pdb.input(lines=pdb_str, source_info=None) - model = mmtbx.model.manager(model_input = pdb_inp) - model.process(make_restraints=True) - return model - -def exercise_1(): - """ 58 is outlier """ - model = get_necessary_inputs(pdb_str_1) - # pdb_h.write_pdb_file("fix_rot_out_ex1_start.pdb") - model = run( - args=[], - model=model) - rotamers = [] - # pdb_h.write_pdb_file("fix_rot_out_ex1_end.pdb") - for res in model.get_hierarchy().only_chain().only_conformer().residues(): - rotamers.append(model.get_rotamer_manager().evaluate_residue(res)) - # print rotamers - assert rotamers == ['m-80', 'p'], rotamers - -def exercise_2(): - model = get_necessary_inputs(pdb_str_2) - model = run( - args=[], - model = model) - rotamers = [] - for res in model.get_hierarchy().only_chain().only_conformer().residues(): - rotamers.append(model.get_rotamer_manager().evaluate_residue(res)) - assert rotamers == ['mtt180', 'tttt', 'm-30', 'pt', 'p', 'mm-30', 'm-40', - 'EXCEPTION', 'tt', 'tttt'], rotamers - -if (__name__ == "__main__"): - exercise_1() - exercise_2() - print("OK") From d4a91d626d7b9021f184028d83ec1df9adbb6eb1 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 9 Apr 2024 12:02:00 -0700 Subject: [PATCH 308/748] Tidy-up Phenix: remove ssm_rmsd_for_chains --- mmtbx/command_line/ssm_rmsd_for_chains.py | 54 ----------------------- 1 file changed, 54 deletions(-) delete mode 100644 mmtbx/command_line/ssm_rmsd_for_chains.py diff --git a/mmtbx/command_line/ssm_rmsd_for_chains.py b/mmtbx/command_line/ssm_rmsd_for_chains.py deleted file mode 100644 index 8a7e9404a6..0000000000 --- a/mmtbx/command_line/ssm_rmsd_for_chains.py +++ /dev/null @@ -1,54 +0,0 @@ -# LIBTBX_SET_DISPATCHER_NAME mmtbx.ssm_rmsd_for_chains -from __future__ import absolute_import, division, print_function -import sys -from mmtbx.geometry_restraints.torsion_restraints import utils -from libtbx.utils import Sorry - -def run(args): - if len(args) != 2: - raise Sorry("mmtbx.ssm_rmsd_for_chains requires two PDB files as input") - file1 = args[0] - file2 = args[1] - import iotbx.pdb - pdb1 = iotbx.pdb.input(file_name=file1).construct_hierarchy() - pdb2 = iotbx.pdb.input(file_name=file2).construct_hierarchy() - chains1 = [] - chains2 = [] - - for model in pdb1.models(): - for i, chain_i in enumerate(model.chains()): - if not chain_i.is_protein() and not chain_i.is_na(): - continue - chains1.append(chain_i) - - for model in pdb2.models(): - for i, chain_i in enumerate(model.chains()): - if not chain_i.is_protein() and not chain_i.is_na(): - continue - chains2.append(chain_i) - - print("### SSM RMSD for chains") - print() - print("PDB_1 = %s" % file1) - print("PDB_2 = %s" % file2) - print() - print("PDB_1 chainID PDB_2 chainID SSM RMSD") - print("--------------------------------------------") - for i, chain_i in enumerate(chains1): - for j, chain_j in enumerate(chains2): - ssm = None - try: #do SSM alignment - ssm, ssm_align = utils._ssm_align( - reference_chain = chain_i, - moving_chain = chain_j) - except RuntimeError as e: - if (str(e) != "can't make graph for first structure" and \ - str(e) != "secondary structure does not match"): - raise e - if ssm is not None: - print("%13s"%chain_i.id, "%17s"%chain_j.id, "%12.3f"%ssm.ssm.rmsd) - else: - print("%13s"%chain_i.id, "%17s"%chain_j.id, "%12s"% ("None")) - -if __name__ == "__main__": - run(args=sys.argv[1:]) From 11d8092fb89ab70940164630695284d7022b9eca Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 9 Apr 2024 12:09:44 -0700 Subject: [PATCH 309/748] Tidy-up Phenix: remove mmtbx/water_screen --- mmtbx/command_line/water_screen.py | 85 ------------------------------ 1 file changed, 85 deletions(-) delete mode 100644 mmtbx/command_line/water_screen.py diff --git a/mmtbx/command_line/water_screen.py b/mmtbx/command_line/water_screen.py deleted file mode 100644 index d7506e0334..0000000000 --- a/mmtbx/command_line/water_screen.py +++ /dev/null @@ -1,85 +0,0 @@ - -from __future__ import absolute_import, division, print_function -from libtbx.str_utils import make_header -from libtbx.utils import Sorry -from libtbx import Auto -import sys - -def master_phil(): - from mmtbx.command_line import generate_master_phil_with_inputs - return generate_master_phil_with_inputs( - enable_automatic_twin_detection=True, - enable_pdb_interpretation_params=True, - enable_stop_for_unknowns=False, - phil_string=""" -include scope mmtbx.ions.identify.ion_master_phil -include scope mmtbx.ions.svm.svm_phil_str -debug = True - .type = bool -elements = Auto - .type = str -use_svm = False - .type = bool -nproc = Auto - .type = int -""") - -def run(args, out=sys.stdout): - usage_string = """ -mmtbx.water_screen model.pdb data.mtz [options ...] - -Utility to flag waters that may actually be elemental ions, based on local -environment, electron density maps, and atomic properties. -""" - import mmtbx.ions.identify - import mmtbx.command_line - cmdline = mmtbx.command_line.load_model_and_data( - args=args, - master_phil=master_phil(), - out=out, - process_pdb_file=True, - set_wavelength_from_model_header=True, - set_inelastic_form_factors="sasaki", - create_fmodel=True, - prefer_anomalous=True) - fmodel = cmdline.fmodel - xray_structure = cmdline.xray_structure - params = cmdline.params - if (params.use_svm): - if (params.elements is Auto): - raise Sorry("You must specify elements to consider when using the SVM "+ - "prediction method.") - pdb_hierarchy = cmdline.pdb_hierarchy - geometry = cmdline.geometry - make_header("Inspecting water molecules", out=out) - manager_class = None - if (params.use_svm): - manager_class = mmtbx.ions.svm.manager - manager = mmtbx.ions.identify.create_manager( - pdb_hierarchy = pdb_hierarchy, - fmodel = fmodel, - geometry_restraints_manager = geometry, - wavelength = params.input.wavelength, - params = params, - verbose = params.debug, - nproc = params.nproc, - log = out, - manager_class = manager_class) - manager.show_current_scattering_statistics(out=out) - candidates = Auto - if (params.elements is not Auto) and (params.elements is not None): - from cctbx.eltbx import chemical_elements - lu = chemical_elements.proper_upper_list() - elements = params.elements.replace(",", " ") - candidates = elements.split() - for elem in candidates : - if (elem.upper() not in lu): - raise Sorry("Unrecognized element '%s'" % elem) - results = manager.analyze_waters( - out = out, - debug = params.debug, - candidates = candidates) - return results, pdb_hierarchy - -if (__name__ == "__main__"): - run(sys.argv[1:]) From 0ce29948d64ed6f1d9aea7a6619708daaad7d528 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 9 Apr 2024 14:38:11 -0600 Subject: [PATCH 310/748] Tidy formatting --- mmtbx/validation/holton_geometry_validation.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 9016dd331b..c9fe822143 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -434,10 +434,9 @@ def sort_geometry_results(info): def print_results(info): - print("SUMMARY of Holton geometry validation scoring for %s" %(info.filename), - file = info.log) + print("\nSUMMARY of Holton geometry validation scoring for %s" %( + info.filename), file = info.log) print(file = info.log) - print("Overall geometry energy: %.4f" %(info.sum_energy), file = info.log) info.result_table = {} info.result_header_row = [ @@ -496,6 +495,8 @@ def print_results(info): if info.ignore_bond_lengths_with_h: print("Total bonds with H removed: %s" %( info.ignore_bond_lengths_with_h_removed), file = info.log) + print("\nOverall geometry energy for %s: %.4f\n" %(info.filename, + info.sum_energy), file = info.log) def filter_geometry_results(info): From 79328994e3a55b21399d76389ec9e728adf5cb0f Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 9 Apr 2024 14:07:24 -0700 Subject: [PATCH 311/748] It is actually used in ion vpn --- mmtbx/command_line/water_screen.py | 85 ++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 mmtbx/command_line/water_screen.py diff --git a/mmtbx/command_line/water_screen.py b/mmtbx/command_line/water_screen.py new file mode 100644 index 0000000000..d7506e0334 --- /dev/null +++ b/mmtbx/command_line/water_screen.py @@ -0,0 +1,85 @@ + +from __future__ import absolute_import, division, print_function +from libtbx.str_utils import make_header +from libtbx.utils import Sorry +from libtbx import Auto +import sys + +def master_phil(): + from mmtbx.command_line import generate_master_phil_with_inputs + return generate_master_phil_with_inputs( + enable_automatic_twin_detection=True, + enable_pdb_interpretation_params=True, + enable_stop_for_unknowns=False, + phil_string=""" +include scope mmtbx.ions.identify.ion_master_phil +include scope mmtbx.ions.svm.svm_phil_str +debug = True + .type = bool +elements = Auto + .type = str +use_svm = False + .type = bool +nproc = Auto + .type = int +""") + +def run(args, out=sys.stdout): + usage_string = """ +mmtbx.water_screen model.pdb data.mtz [options ...] + +Utility to flag waters that may actually be elemental ions, based on local +environment, electron density maps, and atomic properties. +""" + import mmtbx.ions.identify + import mmtbx.command_line + cmdline = mmtbx.command_line.load_model_and_data( + args=args, + master_phil=master_phil(), + out=out, + process_pdb_file=True, + set_wavelength_from_model_header=True, + set_inelastic_form_factors="sasaki", + create_fmodel=True, + prefer_anomalous=True) + fmodel = cmdline.fmodel + xray_structure = cmdline.xray_structure + params = cmdline.params + if (params.use_svm): + if (params.elements is Auto): + raise Sorry("You must specify elements to consider when using the SVM "+ + "prediction method.") + pdb_hierarchy = cmdline.pdb_hierarchy + geometry = cmdline.geometry + make_header("Inspecting water molecules", out=out) + manager_class = None + if (params.use_svm): + manager_class = mmtbx.ions.svm.manager + manager = mmtbx.ions.identify.create_manager( + pdb_hierarchy = pdb_hierarchy, + fmodel = fmodel, + geometry_restraints_manager = geometry, + wavelength = params.input.wavelength, + params = params, + verbose = params.debug, + nproc = params.nproc, + log = out, + manager_class = manager_class) + manager.show_current_scattering_statistics(out=out) + candidates = Auto + if (params.elements is not Auto) and (params.elements is not None): + from cctbx.eltbx import chemical_elements + lu = chemical_elements.proper_upper_list() + elements = params.elements.replace(",", " ") + candidates = elements.split() + for elem in candidates : + if (elem.upper() not in lu): + raise Sorry("Unrecognized element '%s'" % elem) + results = manager.analyze_waters( + out = out, + debug = params.debug, + candidates = candidates) + return results, pdb_hierarchy + +if (__name__ == "__main__"): + run(sys.argv[1:]) From c7589dead69eebc968b7830f30c8e268d4666c8e Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 10 Apr 2024 11:48:04 -0600 Subject: [PATCH 312/748] allow generation of residue dict; regenerate H atoms in holton_geometry_validation.py --- iotbx/pdb/hierarchy.py | 19 ++++++++++- iotbx/pdb/tst_hierarchy.py | 2 +- .../validation/holton_geometry_validation.py | 33 ++++++++++++++----- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index f5b97f0970..21dd218c59 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -1007,7 +1007,16 @@ def as_model_manager(self, crystal_symmetry, return mm - def as_dict_of_resseq_as_int_residue_names(self): + def as_dict_of_chain_id_resseq_residue_names(self): + max_models = 1 + dd = {} + for m in self.models()[:max_models]: + for c in m.chains(): + new_dd = c.as_dict_of_resseq_residue_names() + dd[c.id] = new_dd + return dd + + def as_dict_of_chain_id_resseq_as_int_residue_names(self): max_models = 1 dd = {} for m in self.models()[:max_models]: @@ -2846,6 +2855,14 @@ def as_list_of_residue_names(self): break return sequence + def as_dict_of_resseq_residue_names(self): + dd = {} + for rg in self.residue_groups(): + for atom_group in rg.atom_groups(): + dd[rg.resseq] = atom_group.resname + break + return dd + def as_dict_of_resseq_as_int_residue_names(self): dd = {} for rg in self.residue_groups(): diff --git a/iotbx/pdb/tst_hierarchy.py b/iotbx/pdb/tst_hierarchy.py index b895b9ffbb..f0b9db7d62 100644 --- a/iotbx/pdb/tst_hierarchy.py +++ b/iotbx/pdb/tst_hierarchy.py @@ -5960,7 +5960,7 @@ def exercise_other(): assert not pdb_hierarchy.contains_dna() assert pdb_hierarchy.as_sequence() == ['G', 'N', 'N', 'Q', 'Q', 'N', 'Y'] assert pdb_hierarchy.as_sequence(as_string = True) == 'GNNQQNY' - dd = pdb_hierarchy.as_dict_of_resseq_as_int_residue_names() + dd = pdb_hierarchy.as_dict_of_chain_id_resseq_as_int_residue_names() keys = list(dd.keys()) keys.sort() values = [dd[key] for key in keys] diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index c9fe822143..8868321cea 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -64,12 +64,13 @@ def holton_geometry_validation(dm = None, filename = None, model = None, - get_individual_residue_scores = False, + get_individual_residue_scores = None, round_numbers = True, worst_clash_is_one_plus_n_times_worst_clash = True, clash_energy_add_n = True, minimum_nonbond_score_to_be_worst = -0.1, minimum_nonbond_score_to_be_included_in_average = 0, + keep_hydrogens = False, # redo the hydrogens ignore_cis_peptides = True, ignore_h_except_in_nonbond = True, ignore_arg_h_nonbond = True, @@ -279,21 +280,25 @@ def get_residue_scores(info): ''' run through all residues, select those results that involve each residue, recalculate overall score. ''' - # For now, only one chain_id info.residue_scores = [] if not info.get_individual_residue_scores: return # nothing to do - for chain_id in list(info.chain_dict.keys())[:1]: # XXX ZZZ CHAIN ID + # For now, only one chain_id + assert len(list(info.chain_dict.keys())) == 1 # only one chain for residue_scores + base_info = get_base_info(info) + + for chain_id in list(info.chain_dict.keys()): for resseq in info.chain_dict[chain_id].sequence_dict.keys(): - working_info = select_residue_info(info, chain_id, resseq) + working_info = select_residue_info(info, base_info, chain_id, resseq) analyze_geometry_values(working_info) info.residue_scores.append(working_info.sum_energy) print("Residue score for %s: %.2f" %(resseq, working_info.sum_energy), file = info.log) -def select_residue_info(info, chain_id, resseq): - from copy import deepcopy + +def get_base_info(info): + ''' just get everything except geometry''' log = info.log dm = info.dm @@ -307,13 +312,18 @@ def select_residue_info(info, chain_id, resseq): info.chain_dict = {} info.model = None - new_info = deepcopy(info) + from copy import deepcopy + base_info = deepcopy(info) info.log = log info.dm = dm info.geometry_results = geometry_results info.chain_dict = chain_dict info.model = model + return base_info + +def select_residue_info(info, base_info, chain_id, resseq): + new_info = base_info # overwrite base_info each time keys = list(info.geometry_results.keys()) for key in keys: @@ -689,9 +699,9 @@ def get_geometry_results(info): geometry_results[key].name = name_dict[key] def get_model(info): + if not info.filename: + raise Sorry("Please supply a filename even if a model object is supplied") if not info.model: - if not info.filename: - raise Sorry("Please supply a filename") if not os.path.isfile(info.filename): raise Sorry("The filename %s is missing" %(info.filename)) if not info.dm: @@ -699,7 +709,12 @@ def get_model(info): info.dm = DataManager() if not info.model: info.model = info.dm.get_model(info.filename) + if not os.path.isfile(info.filename): # write to it + info.dm.write_model_file(info.model, info.filename) info.model.set_log(null_out()) + if (not info.keep_hydrogens): + info.model.add_crystal_symmetry_if_necessary() + info.model = info.model.apply_selection_string("not element H") info.model.process(make_restraints=True) info.chain_dict = {} for chain_id in info.model.chain_ids(unique_only = True): From d2a453f59900730bfc102674e002dc3c4291d3b9 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 10 Apr 2024 10:55:05 -0700 Subject: [PATCH 313/748] Tidy-up Phenix: Remove tst fix_rotamer_outliers from list. Remove analyze_peptides command line program. --- mmtbx/command_line/analyze_peptides.py | 9 --------- mmtbx/run_tests.py | 1 - mmtbx/validation/analyze_peptides.py | 25 ------------------------- 3 files changed, 35 deletions(-) delete mode 100644 mmtbx/command_line/analyze_peptides.py diff --git a/mmtbx/command_line/analyze_peptides.py b/mmtbx/command_line/analyze_peptides.py deleted file mode 100644 index 2564a6bf8c..0000000000 --- a/mmtbx/command_line/analyze_peptides.py +++ /dev/null @@ -1,9 +0,0 @@ -# LIBTBX_SET_DISPATCHER_NAME mmtbx.analyze_peptides - -from __future__ import absolute_import, division, print_function -import sys -from mmtbx.validation import analyze_peptides - -if __name__ == "__main__": - analyze_peptides.run(args=sys.argv[1:]) - diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index f76686414a..705b71610a 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -209,7 +209,6 @@ "$D/conformation_dependent_library/tst_mcl_03.py", "$D/regression/tst_find_ss_structure.py", "$D/regression/tst_find_ss_structure_cif.py", - "$D/regression/tst_fix_rotamer_outliers.py", "$D/regression/tst_chain_comparison.py", "$D/regression/tst_chain_comparison_cif.py", "$D/regression/tst_regularize_from_pdb.py", diff --git a/mmtbx/validation/analyze_peptides.py b/mmtbx/validation/analyze_peptides.py index ed8c713614..b834cc7a54 100644 --- a/mmtbx/validation/analyze_peptides.py +++ b/mmtbx/validation/analyze_peptides.py @@ -151,28 +151,3 @@ def get_sort_key(pair): for line in print_list: print(line, file=log) -def run(args): - if (len(args) == 0 or "--help" in args or "--h" in args or "-h" in args): - raise Usage(usage()) - import iotbx.pdb - import iotbx.phil - master_phil = get_master_phil() - args = list(args) - input_objects = iotbx.phil.process_command_line_with_files( - args=args, - master_phil=master_phil, - pdb_file_def="analyze_peptides.pdb") - work_params = input_objects.work.extract() - if len(work_params.analyze_peptides.pdb) != 1: - raise Usage(usage()) - file_name = work_params.analyze_peptides.pdb[0] - pdb_io = iotbx.pdb.input(file_name) - pdb_hierarchy = pdb_io.construct_hierarchy() - pdb_hierarchy.reset_i_seq_if_necessary() - cis_peptides, trans_peptides, outliers = \ - analyze(pdb_hierarchy=pdb_hierarchy) - show(cis_peptides=cis_peptides, - trans_peptides=trans_peptides, - outliers=outliers, - cis_only=work_params.analyze_peptides.cis_only) - From 877314dc3abffb7d4a6f99ba0c7737a04864800e Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 10 Apr 2024 11:03:18 -0700 Subject: [PATCH 314/748] Tidy-up Phenix: remove mmtbx/anneal_real_space --- mmtbx/command_line/anneal_real_space.py | 106 ------------------------ 1 file changed, 106 deletions(-) delete mode 100644 mmtbx/command_line/anneal_real_space.py diff --git a/mmtbx/command_line/anneal_real_space.py b/mmtbx/command_line/anneal_real_space.py deleted file mode 100644 index 4b0b409857..0000000000 --- a/mmtbx/command_line/anneal_real_space.py +++ /dev/null @@ -1,106 +0,0 @@ - -from __future__ import absolute_import, division, print_function -from libtbx.utils import Sorry -import os.path -import sys - -def get_master_phil(): - from mmtbx.command_line import generate_master_phil_with_inputs - return generate_master_phil_with_inputs( - enable_twin_law=True, - enable_experimental_phases=True, - enable_pdb_interpretation_params=True, - enable_stop_for_unknowns=False, - enable_full_geometry_params=True, - phil_string=""" -selection = None - .type = atom_selection -target_map = 2mFo-DFc - .type = str -rsr_after_anneal = False - .type = bool -resolution_factor = 0.25 - .type = float -reference_sigma = 0.5 - .type = float - .help = Sigma for harmonic restraints for neighboring atoms not included \ - in the selection of interest. -output { - file_name = annealed.pdb - .type = path - save_map_coeffs = False - .type = path - verbose = False - .type = bool - debug = False - .type = bool -} -simulated_annealing { - include scope mmtbx.dynamics.simulated_annealing.master_params -} -""") - -def run(args, out=sys.stdout): - import mmtbx.command_line - import mmtbx.building - cmdline = mmtbx.command_line.load_model_and_data( - args=args, - master_phil=get_master_phil(), - process_pdb_file=True, - create_fmodel=True, - out=out, - usage_string="""\ -mmtbx.anneal_real_space model.pdb data.mtz selection="resname ATP" - -Perform simulatead annealing against a real-space (map) target for a selection -of atoms. For development purposes and experimentation only. -""") - params = cmdline.params - fmodel = cmdline.fmodel - validate_params(params) - pdb_hierarchy = cmdline.pdb_hierarchy - a_c_p = cmdline.processed_pdb_file.all_chain_proxies - selection = a_c_p.selection(params.selection) - assert selection.count(True) > 0 - map_coeffs = fmodel.map_coefficients( - map_type=params.target_map, - exclude_free_r_reflections=True) - if (params.output.save_map_coeffs): - file_base = os.path.basename(os.path.splitext(params.output.file_name)[0]) - map_file = file_base + "_%s.mtz" % params.target_map - mtz = map_coeffs.as_mtz_dataset(column_root_label=params.target_map) - mtz.mtz_object().write(map_file) - print("Wrote map coefficients to %s" % map_file, file=out) - map = map_coeffs.fft_map(resolution_factor=params.resolution_factor - ).apply_sigma_scaling().real_map_unpadded() - sites_ref = pdb_hierarchy.atoms().extract_xyz().deep_copy() - sites_updated = mmtbx.building.run_real_space_annealing( - xray_structure=fmodel.xray_structure, - pdb_hierarchy=pdb_hierarchy, - selection=selection, - target_map=map, - d_min=fmodel.f_obs().d_min(), - processed_pdb_file=cmdline.processed_pdb_file, - cif_objects=(), - resolution_factor=params.resolution_factor, - params=params.simulated_annealing, - rsr_after_anneal=params.rsr_after_anneal, - out=out, - debug=params.output.debug) - pdb_hierarchy.atoms().set_xyz(sites_updated) - rmsd = sites_updated.select(selection).rms_difference( - sites_ref.select(selection)) - print("RMSD (selected atoms) = %.3f" % rmsd, file=out) - f = open(params.output.file_name, "w") - f.write(pdb_hierarchy.as_pdb_string( - crystal_symmetry=fmodel.xray_structure)) - f.close() - print("Wrote annealed model to %s" % params.output.file_name, file=out) - return rmsd - -def validate_params(params): - if (params.selection is None): - raise Sorry("You must specificy an atom selection to anneal.") - -if (__name__ == "__main__"): - run(sys.argv[1:]) From 33293589b57598d8cb86310afce26c1cfd5fecb9 Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 10 Apr 2024 12:35:54 -0600 Subject: [PATCH 315/748] Fix renmove H to remove_hd; use only_model() to require single model --- iotbx/pdb/hierarchy.py | 3 +-- mmtbx/validation/holton_geometry_validation.py | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index 21dd218c59..1b255b9bfe 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -1008,9 +1008,8 @@ def as_model_manager(self, crystal_symmetry, def as_dict_of_chain_id_resseq_residue_names(self): - max_models = 1 dd = {} - for m in self.models()[:max_models]: + for m in self.only_model(): for c in m.chains(): new_dd = c.as_dict_of_resseq_residue_names() dd[c.id] = new_dd diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 8868321cea..9529aba92e 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -714,7 +714,8 @@ def get_model(info): info.model.set_log(null_out()) if (not info.keep_hydrogens): info.model.add_crystal_symmetry_if_necessary() - info.model = info.model.apply_selection_string("not element H") + if info.model.has_hd(): + info.model.remove_hd(reset_i_seq=True) info.model.process(make_restraints=True) info.chain_dict = {} for chain_id in info.model.chain_ids(unique_only = True): From 3ee0436ad6fd20e61c125e3e8aee590c6307947f Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 10 Apr 2024 11:37:39 -0700 Subject: [PATCH 316/748] Tidy-up Phenix: cdl_lookup --- mmtbx/command_line/cdl_lookup.py | 74 -------------------------------- 1 file changed, 74 deletions(-) delete mode 100644 mmtbx/command_line/cdl_lookup.py diff --git a/mmtbx/command_line/cdl_lookup.py b/mmtbx/command_line/cdl_lookup.py deleted file mode 100644 index c500eca3fd..0000000000 --- a/mmtbx/command_line/cdl_lookup.py +++ /dev/null @@ -1,74 +0,0 @@ -from __future__ import absolute_import, division, print_function - -# XXX most of this code is unused when run from the command line, but the -# PHENIX GUI includes a simple frontend that uses the phil interface. - -import libtbx.phil -import libtbx.phil.command_line -from libtbx.utils import Sorry -#from libtbx import easy_run -import sys -import os - -from mmtbx import conformation_dependent_library -from mmtbx.conformation_dependent_library import cdl_utils -from mmtbx.conformation_dependent_library.cdl_database import cdl_database - -master_phil = libtbx.phil.parse(""" -cdl_lookup - .caption = CDL -{ - residue_names = None - .type = str - residue_group_class = None - .type = choice - phi_psi_angles = None - .type = str -}""") - -def run2(args=(), out=sys.stdout): - argument_interpreter = libtbx.phil.command_line.argument_interpreter( - master_phil=master_phil, - home_scope="cdl_lookup") - phils = [] - phil_args = [] - pdbs = [] - for arg in args: - if os.path.isfile(arg): - if iotbx.pdb.is_pdb_file(arg): - pdbs.append(arg) - continue - try : - file_phil = phil.parse(file_name=arg) - except RuntimeError : - pass - else : - phils.append(file_phil) - else : - phil_args.append(arg) - phils.append(argument_interpreter.process(arg)) - working_phil = master_phil.fetch(sources=phils) - working_phil.show() - working_params = working_phil.extract() - - if working_params.cdl_lookup.residue_group_class is None: - working_params.cdl_lookup.residue_group_class = cdl_utils.get_res_type_group( - *tuple(working_params.cdl_lookup.residue_names.split(",")[1:]) - ) - print("\nPeptide triplet class : %s" % working_params.cdl_lookup.residue_group_class) - key = working_params.cdl_lookup.phi_psi_angles.split(",") - key[0] = int(key[0]) - key[1] = int(key[1]) - key = tuple(key) - restraints_values = cdl_database[working_params.cdl_lookup.residue_group_class][key] - outl = conformation_dependent_library.restraints_show(restraints_values) - print("\nCDL values\n%s" % outl) - return restraints_values - -def validate_params(params): - if (params.fetch_pdb.pdb_ids is None) or (len(params.fetch_pdb.pdb_ids)==0): - raise Sorry("No PDB IDs specified!") - return True - -if __name__ == "__main__" : - run2(sys.argv[1:]) From e0b50d995366261a8b48d5ebf4e1179868ec70d2 Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 10 Apr 2024 11:47:59 -0700 Subject: [PATCH 317/748] fix typo --- iotbx/pdb/hierarchy.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index 1b255b9bfe..4ac7ae7aaf 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -1009,10 +1009,10 @@ def as_model_manager(self, crystal_symmetry, def as_dict_of_chain_id_resseq_residue_names(self): dd = {} - for m in self.only_model(): - for c in m.chains(): - new_dd = c.as_dict_of_resseq_residue_names() - dd[c.id] = new_dd + m = self.only_model() + for c in m.chains(): + new_dd = c.as_dict_of_resseq_residue_names() + dd[c.id] = new_dd return dd def as_dict_of_chain_id_resseq_as_int_residue_names(self): From 9365c718bfd74c503cb75744443c3114e822384e Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 10 Apr 2024 11:50:16 -0700 Subject: [PATCH 318/748] CI: start testing conda packages with GitHub Actions [skip ci] --- .github/workflows/nightly_tests.yml | 34 +++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/nightly_tests.yml diff --git a/.github/workflows/nightly_tests.yml b/.github/workflows/nightly_tests.yml new file mode 100644 index 0000000000..25cab66c69 --- /dev/null +++ b/.github/workflows/nightly_tests.yml @@ -0,0 +1,34 @@ +# Test current conda packages on the conda-forge and cctbx-nightly +# channels. This is for testing for any breaking changes in the +# dependencies. +# +# macos-13 will test the x86-64 packages +# macos-14 will test the Apple Silicon packages + +name: Nightly conda package tests +on: + schedule: + - cron: '0 5 * * *' + +jobs: + test_conda_packages: + if: github.repository == 'cctbx/cctbx_project' + + strategy: + matrix: + channel: [conda-forge, cctbx-nightly] + os: [ubuntu-latest, macos-14, macos-13, windows-latest] + python_version: [3.8, 3.9, 3.10, 3.11, 3.12] + + name: Testing (${{ channel }} ${{ matrix.os }}) + runs-on: ${{ matrix.os }} + steps: + - uses: conda-incubator/setup-miniconda@v3 + with: + auto-update-conda: true + python-version: ${{ matrix.python_version }} + activate-environment: test + - name: Environment info + run: | + conda info + conda list From b8b57fac049dc5941778b0d880003758a5b1c220 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 10 Apr 2024 11:55:34 -0700 Subject: [PATCH 319/748] CI: change trigger for testing [skip ci] --- .github/workflows/nightly_tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/nightly_tests.yml b/.github/workflows/nightly_tests.yml index 25cab66c69..cac554a3e5 100644 --- a/.github/workflows/nightly_tests.yml +++ b/.github/workflows/nightly_tests.yml @@ -6,9 +6,9 @@ # macos-14 will test the Apple Silicon packages name: Nightly conda package tests -on: - schedule: - - cron: '0 5 * * *' +on: workflow_dispatch + # schedule: + # - cron: '0 5 * * *' jobs: test_conda_packages: From a109d155d5e73afb965a4a1407b1469cb93c4485 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 10 Apr 2024 12:17:14 -0700 Subject: [PATCH 320/748] Tidy-up Phenix: remove mmtbx/command_line/compare_ligands.py. --- mmtbx/command_line/compare_ligands.py | 55 --------------------------- 1 file changed, 55 deletions(-) delete mode 100644 mmtbx/command_line/compare_ligands.py diff --git a/mmtbx/command_line/compare_ligands.py b/mmtbx/command_line/compare_ligands.py deleted file mode 100644 index 9541e358e9..0000000000 --- a/mmtbx/command_line/compare_ligands.py +++ /dev/null @@ -1,55 +0,0 @@ - -from __future__ import absolute_import, division, print_function -from libtbx.utils import Usage, Sorry -import sys - -master_phil = """ - pdb_file = None - .type = path - .multiple = True - ligand_code = None - .type = str - max_distance_between_centers_of_mass = 8.0 - .type = float - exclude_hydrogens = True - .type = bool - verbose = False - .type = bool -""" - -def run(args, out=sys.stdout): - if (len(args) == 0) or ("--help" in args): - raise Usage("""\ -mmtbx.compare_ligands model1.pdb model2.pdb ligand_code=LIG - -Given a pair of PDB files and a ligand ID, identifies equivalent copies of the -ligand in each model and calculates RMSDs between them. Used for validating -ligand fitting tools in Phenix.""") - - import iotbx.phil - class _cmdline(iotbx.phil.process_command_line_with_files): - def process_other(self, arg): - if (len(arg) <= 3) and (arg.isalnum()): - return iotbx.phil.parse("""ligand_code=%s""" % arg) - cmdline = _cmdline( - args=args, - master_phil_string=master_phil, - pdb_file_def="pdb_file") - params = cmdline.work.extract() - if (len(params.pdb_file) != 2): - raise Sorry("Exactly two PDB files required as input.") - if (params.ligand_code is None): - raise Sorry("Must specify ligand ID (ligand_code=LIG)") - from mmtbx.validation import ligands - rmsds, pbss = ligands.compare_ligands( - ligand_code=params.ligand_code, - pdb_file_1=params.pdb_file[0], - pdb_file_2=params.pdb_file[1], - exclude_hydrogens=params.exclude_hydrogens, - verbose=params.verbose, - out=out) - if (len(rmsds) == 0): - raise Sorry("No matching ligands found!") - -if (__name__ == "__main__"): - run(args=sys.argv[1:]) From e8e0e4dec584c5a0548f6bad3983b478f0df239d Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 10 Apr 2024 12:36:14 -0700 Subject: [PATCH 321/748] Tidy-up Phenix: remove mmtbx/command_line/fix_rama_outliers.py --- mmtbx/command_line/fix_rama_outliers.py | 51 ------------------------- 1 file changed, 51 deletions(-) delete mode 100644 mmtbx/command_line/fix_rama_outliers.py diff --git a/mmtbx/command_line/fix_rama_outliers.py b/mmtbx/command_line/fix_rama_outliers.py deleted file mode 100644 index 6dbe2ac90b..0000000000 --- a/mmtbx/command_line/fix_rama_outliers.py +++ /dev/null @@ -1,51 +0,0 @@ -from __future__ import absolute_import, division, print_function -import iotbx.pdb -import sys -from scitbx.array_family import flex -from mmtbx.building.loop_idealization import loop_idealization, master_phil - -import mmtbx.utils -from libtbx.utils import Sorry - - - -def run(args, log=sys.stdout): - # print "args", args - - inputs = mmtbx.utils.process_command_line_args(args=args, - master_params=master_phil) - work_params = inputs.params.extract() - inputs.params.show(prefix=" ", out=log) - pdb_file_names = list(inputs.pdb_file_names) - if len(pdb_file_names) == 0: - raise Sorry("No PDB file specified") - work_params.loop_idealization.enabled=True - work_params.loop_idealization.number_of_ccd_trials=1 - work_params.loop_idealization.minimize_whole=False - work_params.loop_idealization.variant_search_level=1 - # print work_params.loop_idealization.output_prefix - # STOP() - # work_params.ss_idealization.file_name_before_regularization="before.pdb" - pdb_combined = iotbx.pdb.combine_unique_pdb_files(file_names=pdb_file_names) - pdb_input = iotbx.pdb.input(source_info=None, - lines=flex.std_string(pdb_combined.raw_records)) - pdb_h = pdb_input.construct_hierarchy() - - - loop_ideal = loop_idealization( - pdb_hierarchy=pdb_h, - params=work_params.loop_idealization, - log=log) - loop_ideal.resulting_pdb_h.write_pdb_file( - file_name="%s_very_final.pdb" % work_params.loop_idealization.output_prefix) - print("Outlier percentages: initial, after ccd, after minimization, berkeley after ccd, berkeley after minimization:", file=log) - print(loop_ideal.p_initial_rama_outliers, end=' ', file=log) - print(loop_ideal.p_before_minimization_rama_outliers, end=' ', file=log) - print(loop_ideal.p_after_minimiaztion_rama_outliers, end=' ', file=log) - print(loop_ideal.berkeley_p_before_minimization_rama_outliers, end=' ', file=log) - print(loop_ideal.berkeley_p_after_minimiaztion_rama_outliers, file=log) - - - -if (__name__ == "__main__"): - run(sys.argv[1:]) From 1b5cf77bc347f6894ce24f3f381b6db957b525df Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 10 Apr 2024 12:45:47 -0700 Subject: [PATCH 322/748] Tidy-up Phenix: remove mmtbx/command_line/get_related_ensemble.py --- mmtbx/command_line/get_related_ensemble.py | 104 --------------------- 1 file changed, 104 deletions(-) delete mode 100644 mmtbx/command_line/get_related_ensemble.py diff --git a/mmtbx/command_line/get_related_ensemble.py b/mmtbx/command_line/get_related_ensemble.py deleted file mode 100644 index 454dd6f5a2..0000000000 --- a/mmtbx/command_line/get_related_ensemble.py +++ /dev/null @@ -1,104 +0,0 @@ - -from __future__ import absolute_import, division, print_function -from libtbx.str_utils import make_sub_header -from libtbx.utils import null_out -import sys - -master_phil_str = """ -model = None - .type = path -chain_id = None - .type = str -sequence = None - .type = path -search_directory = None - .type = path -output_file = ensemble.pdb - .type = path -nproc = Auto - .type = int -include scope mmtbx.building.make_library.master_phil -exclude_ids = None - .type = strings -dry_run = False - .type = bool -""" - -def run(args, out=sys.stdout): - from mmtbx.building import make_library - import iotbx.phil - cmdline = iotbx.phil.process_command_line_with_files( - args=args, - master_phil_string=master_phil_str, - pdb_file_def="model", - seq_file_def="sequence", - directory_def="search_directory", - usage_string="mmtbx.get_related_ensemble [model.pdb] [seq.fa] [...]") - params = cmdline.work.extract() - sequence = None - if (params.model is None): - raise Sorry("No model (PDB or mmCIF file) was specified.") - if (params.sequence is not None): - seq_file = cmdline.get_file(params.sequence, force_type="seq") - n_seqs = len(seq_file.file_object) - if (n_seqs > 1): - print("%d sequences in file - will only use the first" % n_seqs, file=out) - sequence = seq_file.file_object[0].sequence - pdb_file = cmdline.get_file(params.model, force_type="pdb") - hierarchy = pdb_file.file_object.hierarchy - reference_hierarchy = iotbx.pdb.hierarchy.root() - model = iotbx.pdb.hierarchy.model() - reference_hierarchy.append_model(model) - for chain in hierarchy.models()[0].chains(): - if (params.chain_id is None) or (chain.id == params.chain_id): - if (not chain.is_protein()): - if (chain.id == params.chain_id): - print("warning: matching chain '%s' is not protein, skipping" % \ - chain.id, file=out) - continue - else : - # TODO select based on sequence if provided - new_chain = iotbx.pdb.hierarchy.chain(id=chain.id) - model.append_chain(new_chain) - # get rid of alternate conformations - for residue_group in chain.residue_groups(): - atom_group = residue_group.atom_groups()[0] - if (not atom_group.altloc.strip() in ['', 'A']): - continue - new_rg = iotbx.pdb.hierarchy.residue_group( - resseq=residue_group.resseq, - icode=residue_group.icode) - new_ag = atom_group.detached_copy() - new_ag.altloc = '' - new_rg.append_atom_group(new_ag) - new_chain.append_residue_group(new_rg) - if (sequence is None): - sequence = chain.as_padded_sequence(pad='X') - print("Using sequence of chain '%s' (approx. %d residues)" % \ - (chain.id, len(sequence)), file=out) - break - if (sequence is None): - raise Sorry("No protein sequence could be extracted based on these inputs.") - make_sub_header("Finding related models and generating ensemble", out=out) - ensemble = make_library.extract_and_superpose( - reference_hierarchy=reference_hierarchy, - search_directory=params.search_directory, - sequence=sequence, - params=params, - out=out) - f = null_out() - if (params.output_file is not None): - f = open(params.output_file, "w") - print("Assembling moved models:", file=out) - ensemble_hierarchy = ensemble.as_multi_model_hierarchy() - for k in ensemble.selection_moved : - source_info = ensemble.related_chains[k].source_info - print(" Model %d: %s:%s" % (k+1, source_info, - ensemble.related_chains[k].chain_id), file=out) - f.write("REMARK model %d is from %s\n" % (k+1, source_info)) - f.write(ensemble_hierarchy.as_pdb_string()) - f.close() - return ensemble_hierarchy - -if (__name__ == "__main__"): - run(args=sys.argv[1:]) From 34b71832c6eb7ba179efbe2a7a8a930176a87c5e Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 10 Apr 2024 14:47:12 -0600 Subject: [PATCH 323/748] Put suggestions for inverting map in dock_in_map, predict_and_build, dock_and_rebuild, map_to_model and map_box --- mmtbx/command_line/map_box.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mmtbx/command_line/map_box.py b/mmtbx/command_line/map_box.py index 97b7d9518f..f71b11a405 100644 --- a/mmtbx/command_line/map_box.py +++ b/mmtbx/command_line/map_box.py @@ -375,7 +375,8 @@ .type = bool .help = Just before writing out the map, swap the order of all sections \ in Z. This will change the hand of the map. Note that this\ - removes any correspondence to models (these are not inverted). + removes any correspondence to models (these are not inverted). \ + If you use this, be sure to apply it to all your starting maps.\ .short_caption = Invert hand of map gui From ebad5be4743dffadabfc862a2aeed283891bd74a Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 10 Apr 2024 13:59:45 -0700 Subject: [PATCH 324/748] Tidy-up Phenix: remove mmtbx/command_line/fmodel_simple.py; this is a wrapper, so mmtbx/utils/fmodel_simple remains available. --- mmtbx/command_line/fmodel_simple.py | 31 ----------------------------- 1 file changed, 31 deletions(-) delete mode 100644 mmtbx/command_line/fmodel_simple.py diff --git a/mmtbx/command_line/fmodel_simple.py b/mmtbx/command_line/fmodel_simple.py deleted file mode 100644 index 50560c9766..0000000000 --- a/mmtbx/command_line/fmodel_simple.py +++ /dev/null @@ -1,31 +0,0 @@ - -from __future__ import absolute_import, division, print_function -from libtbx import easy_pickle -import sys - -def master_phil(): - from mmtbx.command_line import generate_master_phil_with_inputs - return generate_master_phil_with_inputs( - enable_automatic_twin_detection=True, - phil_string="""\ -output_file = fmodel.pkl - .type = path -""") - -def run(args, out=sys.stdout): - import mmtbx.command_line - cmdline = mmtbx.command_line.load_model_and_data( - args=args, - master_phil=master_phil(), - process_pdb_file=False, - out=out, - usage_string="mmtbx.fmodel_simple model.pdb data.mtz [options]") - fmodel = cmdline.fmodel - fmodel_info = fmodel.info() - fmodel_info.show_rfactors_targets_scales_overall(out=out) - easy_pickle.dump(cmdline.params.output_file, fmodel) - print("Wrote fmodel to %s" % cmdline.params.output_file, file=out) - return fmodel - -if (__name__ == "__main__"): - run(sys.argv[1:]) From a531f9ea9c4367a5714d2d242769f1d6e9e65339 Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 10 Apr 2024 15:12:03 -0700 Subject: [PATCH 325/748] Add option to keep original occupancy value --- iotbx/pdb/hierarchy.py | 10 ++++++---- mmtbx/pdbtools.py | 3 +++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index 4ac7ae7aaf..8b99dbaef0 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -1963,7 +1963,8 @@ def altlocs_present(self, skip_blank = True): altlocs_present.append(atom_group.altloc) return altlocs_present - def remove_alt_confs(self, always_keep_one_conformer, altloc_to_keep = None): + def remove_alt_confs(self, always_keep_one_conformer, altloc_to_keep = None, + keep_occupancy = False): hierarchy = self for model in hierarchy.models(): for chain in model.chains(): @@ -2017,9 +2018,10 @@ def remove_alt_confs(self, always_keep_one_conformer, altloc_to_keep = None): residue_group.remove_atom_group(ags[i]) if (len(chain.residue_groups()) == 0): model.remove_chain(chain=chain) - atoms = hierarchy.atoms() - new_occ = flex.double(atoms.size(), 1.0) - atoms.set_occ(new_occ) + if not keep_occupancy: + atoms = hierarchy.atoms() + new_occ = flex.double(atoms.size(), 1.0) + atoms.set_occ(new_occ) def rename_chain_id(self, old_id, new_id): for model in self.models(): diff --git a/mmtbx/pdbtools.py b/mmtbx/pdbtools.py index 7fba5b9afe..85f75b0389 100644 --- a/mmtbx/pdbtools.py +++ b/mmtbx/pdbtools.py @@ -176,6 +176,9 @@ .help = Modifies behavior of remove_alt_confs so that residues with no \ conformer labeled blank or A are not deleted. Silent if remove_alt_confs \ is False. +keep_occupancy = False + .type = bool + .help = Do not reset occupancy to 1 after removing altlocs altloc_to_keep = None .type = str .help = Modifies behavior of remove_alt_confs so that the altloc identifier \ From 8736203e15ef54b05614a52ec1fc0d576f98ca0c Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 10 Apr 2024 15:25:41 -0700 Subject: [PATCH 326/748] Tidy-up Phenix: Remove mmtbx/command_line/flipbase.py and mmtbx/refinement/real_space/flipbase.py. It is not used anywhere. --- mmtbx/command_line/flipbase.py | 7 - mmtbx/refinement/real_space/flipbase.py | 231 -------------------- mmtbx/refinement/real_space/tst_flipbase.py | 187 ---------------- mmtbx/run_tests.py | 1 - 4 files changed, 426 deletions(-) delete mode 100644 mmtbx/command_line/flipbase.py delete mode 100644 mmtbx/refinement/real_space/flipbase.py delete mode 100644 mmtbx/refinement/real_space/tst_flipbase.py diff --git a/mmtbx/command_line/flipbase.py b/mmtbx/command_line/flipbase.py deleted file mode 100644 index cb18c13890..0000000000 --- a/mmtbx/command_line/flipbase.py +++ /dev/null @@ -1,7 +0,0 @@ -from __future__ import absolute_import, division, print_function - -import sys -from mmtbx.refinement.real_space import flipbase - -if __name__ == "__main__": - flipbase.run(sys.argv[1:]) diff --git a/mmtbx/refinement/real_space/flipbase.py b/mmtbx/refinement/real_space/flipbase.py deleted file mode 100644 index 1a399bb582..0000000000 --- a/mmtbx/refinement/real_space/flipbase.py +++ /dev/null @@ -1,231 +0,0 @@ -from __future__ import absolute_import, division, print_function -import os,sys -from iotbx import pdb -from iotbx import reflection_file_reader -from iotbx import file_reader -from mmtbx.refinement.real_space import individual_sites -import mmtbx -import libtbx.phil.command_line -from six.moves import range - -master_phil = libtbx.phil.parse(""" -flip_base { - pdb_file = None - .type = path - .help = '''input PDB file''' - reflection_file = None - .type = path - .help = '''Reflection file''' - out_pdb_file = None - .type = str - .help = '''input PDB file''' - chain = None - .type = str - .help = '''Chain of the residue that is to be flipped''' - alt_loc = None - .type = str - .help = '''Alternate location of the residue that is to be flipped''' - res_num = None - .type = int - .help = '''Residue number of the residue that is to be flipped''' - n_refine_cycles = 3 - .type = int - .help = '''Number of real-space refinement cycles''' - help = False - .type = bool - .help = '''Show help message''' -} -""", process_includes=True) - -def usage(msg='', log=sys.stderr): - s = ''' -****************************************************************************** -Usage : - python.phenix flipbase.py xxxx.mtz yyyy.pdb chain=A res_num=1 - -Will flip base of chain A residue 1 of yyyy.pdb and do a real-space -refinement using xxxx.mtz. - -Required : - pdb_file input PDB file - reflection_file Reflection file - chain Chain of the residue that is to be flipped - res_num Residue number of the residue that is to be flipped - -Options : - out_pdb_file input PDB file - alt_loc Alternate location of the residue that is to be flipped - n_refine_cycles Number of real-space refinement cycles - help Show help message -****************************************************************************** - -''' - if msg != '' : - s = '*'*79 + '\n\n!!!!! %s !!!!!\n' % msg + s - print(s);sys.exit() - -base_rotation_axes = { - "A" : ["C1'", "N9"], - "G" : ["C1'", "N9"], - "C" : ["C1'", "N1"], - "T" : ["C1'", "N1"], - "U" : ["C1'", "N1"], -} -base_rotatable_atoms = { - "A" : ["N1", "C2", "H2", "N3", "C4", "C5", "C6", "N6", "H61", "H62", "N7", - "C8", "H8"], - "G" : ["N1", "H1", "C2", "N2", "H21", "H22", "N3", "C4", "C5", "C6", "O6", - "N7", "C8", "H8"], - "C" : ["C2", "O2", "N3", "C4", "N4", "H41", "H42", "C5", "H5", "C6", "H6"], - "T" : ["C2", "O2", "N3", "H3", "C4", "O4", "C5", "C7", "H71", "H72", "H73", - "C6", "H6"], - "U" : ["C2", "O2", "N3", "H3", "C4", "O4", "C5", "H5", "C6", "H6"], -} - -def flip_base(atom_group, angle=180): - import scitbx.matrix - axis_point_1 = axis_point_2 = None - rotateable_atoms = [] - base_name = atom_group.resname.strip() - if ("r" in base_name): - base_name = base_name.replace("r") - elif (base_name.startswith("D") and len(base_name) == 2): - base_name = base_name[1] - assert base_name in base_rotation_axes, base_name - for atom in atom_group.atoms(): - atom_name = atom.name.strip() - if (atom_name == base_rotation_axes[base_name][0]): - axis_point_1 = atom.xyz - elif (atom_name == base_rotation_axes[base_name][1]): - axis_point_2 = atom.xyz - elif (atom_name in base_rotatable_atoms[base_name]): - rotateable_atoms.append(atom) - if (None in [axis_point_1, axis_point_2]): - raise RuntimeError("Missing atom(s) for rotateable axis.") - elif (len(rotateable_atoms) == 0): - raise RuntimeError("Missing nucleotide base.") - for atom in rotateable_atoms : - atom.xyz = scitbx.matrix.rotate_point_around_axis( - axis_point_1=axis_point_1, - axis_point_2=axis_point_2, - point=atom.xyz, - angle=angle, - deg=True) - -def get_target_map(reflection_file_name, log=sys.stderr): - miller_arrays = reflection_file_reader.any_reflection_file(file_name = - reflection_file_name).as_miller_arrays() - ma = miller_arrays[0] - fft_map = ma.fft_map(resolution_factor=0.25) - fft_map.apply_sigma_scaling() - print("\nUsing sigma scaled map.\n", file=log) - target_map = fft_map.real_map_unpadded() - return target_map - -def flip_and_refine(pdb_hierarchy, - xray_structure, - target_map, - geometry_restraints_manager, - chain, - res_num, - alt_loc = None, - n_refine_cycles = 3, - log = sys.stdout): - sites_cart = xray_structure.sites_cart() - ero = False - for ch in pdb_hierarchy.chains(): - if ch.id.strip() != chain : continue - for rg in ch.residue_groups(): - if rg.resseq_as_int() != res_num : continue - if rg.have_conformers() and not alt_loc : - s = 'Specified residue has alternate conformations. Please specify ' - raise RuntimeError(s + 'alt_loc on the command line') - for residue in rg.atom_groups(): - if alt_loc and alt_loc != residue.altloc.strip(): - continue - flip_base(residue, angle=180) - - sites_cart.set_selected(residue.atoms().extract_i_seq(), - residue.atoms().extract_xyz()) - xray_structure = xray_structure.replace_sites_cart(sites_cart) - sele = residue.atoms().extract_i_seq() - print('real-space refinement BEGIN'.center(79,'*'), file=log) - for i in range(n_refine_cycles): - print('real-space refinement cycle %i...' % (i + 1), file=log) - ero = individual_sites.easy( - map_data = target_map, - xray_structure = xray_structure, - pdb_hierarchy = pdb_hierarchy, - geometry_restraints_manager = geometry_restraints_manager, - selection = sele) - print('real-space refinement FINISHED'.center(79,'*'), file=log) - if not ero : raise RuntimeError('Specified residue not found') - return ero.pdb_hierarchy - -def run(args): - - # phil parsing---------------------------------------------------------- - interpreter = libtbx.phil.command_line.argument_interpreter(master_phil=master_phil) - sources = [] - for arg in args: - if os.path.isfile(arg): #Handles loose filenames - input_file = file_reader.any_file(arg) - if (input_file.file_type == "pdb"): - sources.append(interpreter.process(arg="pdb_file=\"%s\"" % arg)) - if (input_file.file_type == "hkl"): - sources.append(interpreter.process(arg="reflection_file=\"%s\"" % arg)) - elif (input_file.file_type == "phil"): - sources.append(input_file.file_object) - else: #Handles arguments with xxx=yyy formatting - arg_phil = interpreter.process(arg=arg) - sources.append(arg_phil) - work_phil = master_phil.fetch(sources=sources) - work_params = work_phil.extract() - params = work_params.flip_base - if work_params.flip_base.pdb_file == None : - usage('PDB file not provided!') - if work_params.flip_base.reflection_file == None : - usage('Reflection file not provided!') - if work_params.flip_base.chain == None : - usage('chain not provided!') - if work_params.flip_base.res_num == None : - usage('res_num file not provided!') - if work_params.flip_base.out_pdb_file == None : - fn = work_params.flip_base.pdb_file.replace('.pdb','_baseflip.pdb') - work_params.flip_base.out_pdb_file = fn - #usage('out_pdb_file file not provided!') - params = work_params.flip_base - - if params.help: - usage() - sys.exit() - # end phil parsing ------------------------------------------------------ - - pdb_file_name = params.pdb_file - reflection_file_name = params.reflection_file - log = sys.stdout - print('\ngettinsg target_map...\n', file=log) - target_map = get_target_map(reflection_file_name, log) - ppf = mmtbx.utils.process_pdb_file_srv(log=False).process_pdb_files( - [pdb_file_name])[0] - grm = mmtbx.restraints.manager( - geometry = ppf.geometry_restraints_manager(show_energies = False), - normalization = True) - pdb_hierarchy = ppf.all_chain_proxies.pdb_hierarchy - pdb_hierarchy.atoms().reset_i_seq() - xray_structure = ppf.xray_structure(show_summary = False) - flip_hierarchy = flip_and_refine(pdb_hierarchy, - xray_structure, - target_map = target_map, - geometry_restraints_manager = grm, - chain = params.chain, - res_num = params.res_num, - alt_loc = params.alt_loc, - n_refine_cycles = params.n_refine_cycles, - log= log) - - flip_hierarchy.write_pdb_file(params.out_pdb_file) - print('\nOut written to %s' % params.out_pdb_file, file=log) - -if __name__ == "__main__": - run(sys.argv[1:]) diff --git a/mmtbx/refinement/real_space/tst_flipbase.py b/mmtbx/refinement/real_space/tst_flipbase.py deleted file mode 100644 index 1b2f14b59e..0000000000 --- a/mmtbx/refinement/real_space/tst_flipbase.py +++ /dev/null @@ -1,187 +0,0 @@ -from __future__ import absolute_import, division, print_function -from scitbx.array_family import flex -from libtbx import group_args -from libtbx.utils import user_plus_sys_time -from mmtbx.refinement.real_space import individual_sites, flipbase -import mmtbx -import iotbx -from libtbx.test_utils import approx_equal -from six.moves import range - -pdb_str_answer = """\ -CRYST1 23.136 23.980 28.180 90.00 90.00 90.00 P 1 -ATOM 1240 P DG B 40 0.649 2.161 -36.081 0.50 17.21 P -ATOM 1241 OP1 DG B 40 1.754 3.055 -35.664 0.50 19.03 O -ATOM 1242 OP2 DG B 40 -0.231 2.567 -37.203 0.50 13.93 O -ATOM 1243 O5' DG B 40 1.316 0.741 -36.417 0.50 17.66 O -ATOM 1244 C5' DG B 40 2.224 0.095 -35.507 0.50 17.29 C -ATOM 1245 C4' DG B 40 2.673 -1.267 -36.015 0.50 18.14 C -ATOM 1246 O4' DG B 40 1.657 -2.274 -35.767 0.50 18.54 O -ATOM 1247 C3' DG B 40 2.981 -1.325 -37.503 0.50 18.42 C -ATOM 1248 O3' DG B 40 4.381 -1.282 -37.640 0.50 18.86 O -ATOM 1249 C2' DG B 40 2.435 -2.669 -37.974 0.50 19.35 C -ATOM 1250 C1' DG B 40 1.386 -3.034 -36.928 0.50 20.27 C -ATOM 1251 N9 DG B 40 0.023 -2.677 -37.316 0.50 21.30 N -ATOM 1252 C8 DG B 40 -0.406 -1.445 -37.759 0.50 21.71 C -ATOM 1253 N7 DG B 40 -1.676 -1.380 -38.029 0.50 22.28 N -ATOM 1254 C5 DG B 40 -2.128 -2.655 -37.739 0.50 21.94 C -ATOM 1255 C6 DG B 40 -3.437 -3.178 -37.849 0.50 20.86 C -ATOM 1256 O6 DG B 40 -4.476 -2.610 -38.224 0.50 22.01 O -ATOM 1257 N1 DG B 40 -3.477 -4.511 -37.466 0.50 20.98 N -ATOM 1258 C2 DG B 40 -2.385 -5.232 -37.045 0.50 21.41 C -ATOM 1259 N2 DG B 40 -2.658 -6.493 -36.734 0.50 22.19 N -ATOM 1260 N3 DG B 40 -1.143 -4.774 -36.928 0.50 20.66 N -ATOM 1261 C4 DG B 40 -1.093 -3.469 -37.297 0.50 20.70 C -TER -END -""" - -pdb_str_poor = """\ -CRYST1 23.136 23.980 28.180 90.00 90.00 90.00 P 1 -ATOM 1240 P DG B 40 0.612 2.104 -36.129 0.50 17.21 P -ATOM 1241 OP1 DG B 40 1.718 3.006 -35.787 0.50 19.03 O -ATOM 1242 OP2 DG B 40 -0.331 2.457 -37.202 0.50 13.93 O -ATOM 1243 O5' DG B 40 1.193 0.664 -36.476 0.50 17.66 O -ATOM 1244 C5' DG B 40 2.139 0.076 -35.623 0.50 17.29 C -ATOM 1245 C4' DG B 40 2.467 -1.338 -36.039 0.50 18.14 C -ATOM 1246 O4' DG B 40 1.323 -2.180 -35.893 0.50 18.54 O -ATOM 1247 C3' DG B 40 2.890 -1.504 -37.491 0.50 18.42 C -ATOM 1248 O3' DG B 40 4.284 -1.545 -37.594 0.50 18.86 O -ATOM 1249 C2' DG B 40 2.227 -2.815 -37.926 0.50 19.35 C -ATOM 1250 C1' DG B 40 1.572 -3.325 -36.650 0.50 20.27 C -ATOM 1251 N9 DG B 40 0.318 -4.068 -36.831 0.50 21.30 N -ATOM 1252 C8 DG B 40 0.099 -5.410 -36.618 0.50 21.71 C -ATOM 1253 N7 DG B 40 -1.128 -5.780 -36.836 0.50 22.28 N -ATOM 1254 C5 DG B 40 -1.761 -4.618 -37.199 0.50 21.94 C -ATOM 1255 C6 DG B 40 -3.099 -4.399 -37.545 0.50 20.86 C -ATOM 1256 O6 DG B 40 -4.016 -5.216 -37.606 0.50 22.01 O -ATOM 1257 N1 DG B 40 -3.326 -3.075 -37.841 0.50 20.98 N -ATOM 1258 C2 DG B 40 -2.364 -2.095 -37.807 0.50 21.41 C -ATOM 1259 N2 DG B 40 -2.755 -0.882 -38.105 0.50 22.19 N -ATOM 1260 N3 DG B 40 -1.117 -2.287 -37.484 0.50 20.66 N -ATOM 1261 C4 DG B 40 -0.884 -3.558 -37.193 0.50 20.70 C -TER -END -""" - -def get_pdb_inputs(pdb_str, restraints): - ppf = mmtbx.utils.process_pdb_file_srv(log=False).process_pdb_files( - raw_records=pdb_str.splitlines())[0] - xrs = ppf.xray_structure(show_summary = False) - restraints_manager=None - if(restraints): - restraints_manager = mmtbx.restraints.manager( - geometry = ppf.geometry_restraints_manager(show_energies = False), - normalization = True) - return group_args( - ph = ppf.all_chain_proxies.pdb_hierarchy, - grm = restraints_manager, - xrs = xrs) - -def get_map(xrs): - f_calc = xrs.structure_factors(d_min = 1.2).f_calc() - fft_map = f_calc.fft_map(resolution_factor=0.25) - fft_map.apply_sigma_scaling() - return fft_map.real_map_unpadded() - -def exercise(): - """ - Exercise refine "easy" with DNA/RNA. - """ - pi_good = get_pdb_inputs(pdb_str=pdb_str_answer, restraints=False) - map_data = get_map(xrs=pi_good.xrs) - xrs_good = pi_good.xrs.deep_copy_scatterers() - pi_good.ph.write_pdb_file(file_name="answer.pdb", - crystal_symmetry=xrs_good.crystal_symmetry()) - # - pi_poor = get_pdb_inputs(pdb_str=pdb_str_poor, restraints=True) - pi_poor.ph.write_pdb_file(file_name="poor.pdb") - xrs_poor = pi_poor.xrs.deep_copy_scatterers() - # - d = xrs_good.distances(other=xrs_poor) - print(d.min_max_mean().as_tuple()) - assert flex.max(d)>3 - assert flex.mean(d)>1 - - chain = 'B' - res_num = 40 - alt_loc = None - ero = False - n_refine_cycles = 3 - target_map = get_map(xrs=pi_good.xrs) - sites_cart = xrs_poor.sites_cart() - for ch in pi_poor.ph.chains(): - if ch.id.strip() != chain : continue - print('chain') - for rg in ch.residue_groups(): - if rg.resseq_as_int() != res_num : continue - print("res#") - if rg.have_conformers() and not alt_loc : - s = 'Specified residue has alternate conformations. Please specify ' - raise RuntimeError(s + 'alt_loc on the command line') - for residue in rg.atom_groups(): - if alt_loc and alt_loc != residue.altloc.strip(): - continue - flipbase.flip_base(residue, angle=180) - - sites_cart.set_selected(residue.atoms().extract_i_seq(), - residue.atoms().extract_xyz()) - xray_structure = xrs_poor.replace_sites_cart(sites_cart) - sele = residue.atoms().extract_i_seq() - print('real-space refinement BEGIN'.center(79,'*')) - for i in range(n_refine_cycles): - print('real-space refinement cycle %i...' % (i + 1)) - ero = individual_sites.easy( - map_data = target_map, - xray_structure = xray_structure, - pdb_hierarchy = pi_poor.ph, - geometry_restraints_manager = pi_poor.grm, - selection = sele) - print('real-space refinement FINISHED'.center(79,'*')) - xrs_refined = ero.xray_structure - if not ero : raise RuntimeError('Specified residue not found') - d = xrs_good.distances(other=xrs_refined) - print(d.min_max_mean().as_tuple()) - assert flex.max(d)<0.072, flex.max(d) - assert flex.mean(d)<0.04, flex.mean(d) - ero.pdb_hierarchy.write_pdb_file(file_name="refined.pdb", - crystal_symmetry=xrs_good.crystal_symmetry()) - -def exercise2(): - pdb_in = iotbx.pdb.input(source_info=None, lines="""\ -ATOM 3988 P DA G 10 2.095 -23.407 14.671 1.00 24.76 P -ATOM 3989 OP1 DA G 10 2.702 -22.768 13.479 1.00 24.54 O -ATOM 3990 OP2 DA G 10 1.098 -22.688 15.497 1.00 26.02 O -ATOM 3991 O5' DA G 10 3.272 -23.890 15.629 1.00 22.57 O -ATOM 3992 C5' DA G 10 2.981 -24.494 16.871 1.00 21.71 C -ATOM 3993 C4' DA G 10 4.289 -24.903 17.501 1.00 21.29 C -ATOM 3994 O4' DA G 10 4.850 -25.979 16.721 1.00 20.23 O -ATOM 3995 C3' DA G 10 5.340 -23.803 17.483 1.00 20.46 C -ATOM 3996 O3' DA G 10 5.492 -23.313 18.807 1.00 20.49 O -ATOM 3997 C2' DA G 10 6.602 -24.471 16.925 1.00 18.76 C -ATOM 3998 C1' DA G 10 6.243 -25.951 16.910 1.00 17.49 C -ATOM 3999 N9 DA G 10 6.839 -26.749 15.842 1.00 14.88 N -ATOM 4000 C8 DA G 10 6.713 -26.565 14.492 1.00 15.01 C -ATOM 4001 N7 DA G 10 7.363 -27.452 13.774 1.00 15.05 N -ATOM 4002 C5 DA G 10 7.945 -28.283 14.718 1.00 13.74 C -ATOM 4003 C6 DA G 10 8.766 -29.426 14.610 1.00 12.94 C -ATOM 4004 N6 DA G 10 9.149 -29.944 13.443 1.00 13.28 N -ATOM 4005 N1 DA G 10 9.181 -30.024 15.746 1.00 12.16 N -ATOM 4006 C2 DA G 10 8.797 -29.503 16.921 1.00 14.06 C -ATOM 4007 N3 DA G 10 8.029 -28.435 17.152 1.00 13.57 N -ATOM 4008 C4 DA G 10 7.629 -27.865 15.998 1.00 13.67 C -""") - #open("tmp1.pdb", "w").write(pdb_in.hierarchy.as_pdb_string()) - base = pdb_in.construct_hierarchy().only_atom_group() - xyz = base.atoms().extract_xyz().deep_copy() - flipbase.flip_base(base, angle=180) - xyz_new = base.atoms().extract_xyz() - assert approx_equal(xyz_new.rms_difference(xyz), 2.45942) - #open("tmp2.pdb", "w").write(pdb_in.hierarchy.as_pdb_string()) - -if(__name__ == "__main__"): - timer = user_plus_sys_time() - exercise() - exercise2() - print("Time: %6.2f" % timer.elapsed()) - print("OK") diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index 705b71610a..18e4cff4a8 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -244,7 +244,6 @@ "$D/refinement/real_space/tst_fit_residues_6.py", "$D/refinement/real_space/tst_fit_residues_selection.py", "$D/refinement/real_space/tst_fit_water.py", - "$D/refinement/real_space/tst_flipbase.py", "$D/refinement/real_space/tst_individual_sites_1.py", "$D/refinement/real_space/tst_individual_sites_2.py", "$D/refinement/real_space/tst_individual_sites_3.py", From d4501855459d617a3f7be8ac02719ab3ee249b43 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 10 Apr 2024 15:58:25 -0700 Subject: [PATCH 327/748] Tidy-up Phenix: remove mmtbx/command_line/partial_omit_map.py --- mmtbx/command_line/partial_omit_map.py | 215 ------------------------- 1 file changed, 215 deletions(-) delete mode 100644 mmtbx/command_line/partial_omit_map.py diff --git a/mmtbx/command_line/partial_omit_map.py b/mmtbx/command_line/partial_omit_map.py deleted file mode 100644 index 890579a8de..0000000000 --- a/mmtbx/command_line/partial_omit_map.py +++ /dev/null @@ -1,215 +0,0 @@ - -from __future__ import absolute_import, division, print_function -from libtbx import Auto, adopt_init_args -from libtbx import easy_mp -import os.path -import sys - -master_phil_str = """ -selection = all - .type = atom_selection -map_type = mFo-DFc - .type = str -occ = 0.5 - .type = float -remove_waters = True - .type = bool -omit_fraction = 0.02 - .type = float -optimize_binning = True - .type = bool -box_cushion_radius = 2.5 - .type = float -fill_missing_f_obs = False - .type = bool -exclude_free_r_reflections = True - .type = bool -resolution_factor = 0.25 - .type = float -flatten_background = False - .type = bool -nproc = Auto - .type = int -output { - mtz_file = partial_omit_coeffs.mtz - .type = path - ccp4_map = None - .type = path - verbose = False - .type = bool -} -""" - -map_type_labels = { - "2mFo-DFc" : "2FOFCWT", - "mFo-DFc" : "FOFCWT", - "anom" : "ANOM", - "anom_residual" : "ANOM_DIFF", - "llg" : "LLG", -} - -def master_phil(): - from mmtbx.command_line import generate_master_phil_with_inputs - return generate_master_phil_with_inputs( - phil_string=master_phil_str, - enable_automatic_twin_detection=True) - -class partial_omit_map(object): - def __init__(self, - fmodel, - selection, - occupancy, - map_type="mFo-DFc", - omit_fraction=0.02, - selection_delete=None, - fill_missing_f_obs=False, - exclude_free_r_reflections=False, - optimize_binning=True, - box_cushion_radius=2.5, - nproc=Auto, - out=sys.stdout): - adopt_init_args(self, locals()) - import mmtbx.maps.composite_omit_map - occ_saved = fmodel.xray_structure.scatterers().extract_occupancies() - if (omit_fraction == 1.0): - self.omit_groups = [ mmtbx.maps.composite_omit_map.omit_regions( - serial=1, - selection=selection) ] - else : - self.omit_groups = mmtbx.maps.composite_omit_map.create_omit_regions( - xray_structure=fmodel.xray_structure, - selection=selection, - fraction_omit=self.omit_fraction, - optimize_binning=optimize_binning, - box_cushion_radius=box_cushion_radius, - log=out) - for group in self.omit_groups : - group.show(out=out) - self.omit_map_coeffs = easy_mp.pool_map( - fixed_func=self, - iterable=self.omit_groups, - processes=nproc) - fmodel.xray_structure.scatterers().set_occupancies(occ_saved) - fmodel.update_xray_structure(update_f_calc=True) - - def combine_maps(self, - flatten_background=False, - sigma_scaling=False, - resolution_factor=0.25): - if (self.omit_fraction == 1.0): - self.map_coeffs = self.omit_map_coeffs[0] - fft_map = self.map_coeffs.fft_map( - resolution_factor=resolution_factor).apply_volume_scaling() - if (sigma_scaling): - fft_map.apply_sigma_scaling() - self.composite_map = fft_map.real_map_unpadded() - else : - import mmtbx.maps.composite_omit_map - background_map_coeffs = self.fmodel.map_coefficients( - map_type=self.map_type, - fill_missing=self.fill_missing_f_obs, - exclude_free_r_reflections=self.exclude_free_r_reflections, - merge_anomalous=True) - self.composite_map = mmtbx.maps.composite_omit_map.combine_maps( - map_arrays=self.omit_map_coeffs, - omit_groups=self.omit_groups, - background_map_coeffs=background_map_coeffs, - flatten_background=flatten_background, - resolution_factor=resolution_factor, - sigma_scaling=sigma_scaling) - composite_map_coeffs = background_map_coeffs.structure_factors_from_map( - map=self.composite_map, - use_sg=True) - self.map_coeffs = composite_map_coeffs - return self.map_coeffs - - def __call__(self, omit_group): - from scitbx.array_family import flex - fmodel_tmp = self.fmodel.deep_copy() - xrs_omit = fmodel_tmp.xray_structure.deep_copy_scatterers() - xrs_omit.set_occupancies(self.occupancy, selection=omit_group.selection) - if (self.selection_delete is not None): - selection_partial = flex.bool(xrs_omit.scatterers().size(), False) - selection_partial.set_selected(omit_group.selection, True) - selection_delete = selection_partial & self.selection_delete - n_del = selection_delete.count(True) - if (n_del > 0): - #print "setting %d waters to zero occupancy" % n_del - xrs_omit.set_occupancies(0., selection=selection_delete) - fmodel_tmp.update_xray_structure(xrs_omit, - update_f_mask=False, - update_f_calc=True) - return fmodel_tmp.map_coefficients( - map_type=self.map_type, - fill_missing=self.fill_missing_f_obs, - exclude_free_r_reflections=self.exclude_free_r_reflections, - merge_anomalous=True) - -def run(args, out=sys.stdout): - import mmtbx.command_line - import iotbx.map_tools - from scitbx.array_family import flex - usage_string = """\ -mmtbx.partial_omit_map model.pdb data.mtz [occ=0.5] [omit_fraction=0.02] [...] - -Generate a simple (un-refined) composite omit map with atoms at reduced rather -than zero occupancy. Intended for use in the analysis of static disorder - -note that no treatment of phase bias is performed. -""" - cmdline = mmtbx.command_line.load_model_and_data( - args=args, - master_phil=master_phil(), - process_pdb_file=False, - prefer_anomalous=True, - usage_string=usage_string, - set_wavelength_from_model_header=True, - set_inelastic_form_factors="sasaki", - out=out) - fmodel = cmdline.fmodel - xray_structure = fmodel.xray_structure - pdb_hierarchy = cmdline.pdb_hierarchy - params = cmdline.params - sel_cache = pdb_hierarchy.atom_selection_cache() - selection = sel_cache.selection(params.selection) - assert (selection.count(True) > 0) - selection_delete = flex.bool(selection.size(), False) - if (params.remove_waters): - selection_delete = sel_cache.selection("resname HOH") - map_driver = partial_omit_map( - fmodel=fmodel, - selection=selection, - selection_delete=selection_delete, - occupancy=params.occ, - map_type=params.map_type, - omit_fraction=params.omit_fraction, - fill_missing_f_obs=params.fill_missing_f_obs, - exclude_free_r_reflections=params.exclude_free_r_reflections, - optimize_binning=params.optimize_binning, - box_cushion_radius=params.box_cushion_radius, - nproc=params.nproc, - out=out) - if (params.output.mtz_file is not None): - map_coeffs = map_driver.combine_maps( - flatten_background=params.flatten_background, - sigma_scaling=False, - resolution_factor=params.resolution_factor) - iotbx.map_tools.write_map_coefficients_generic( - map_coeffs=[map_coeffs], - map_types=[params.map_type], - file_name=params.output.mtz_file) - print("Wrote map coefficients to %s" % params.output.mtz_file, file=out) - if (params.output.ccp4_map is not None): - map_driver.combine_maps( - flatten_background=params.flatten_background, - sigma_scaling=True, - resolution_factor=params.resolution_factor) - iotbx.map_tools.write_ccp4_map( - sites_cart=fmodel.xray_structure.sites_cart(), - unit_cell=fmodel.xray_structure.unit_cell(), - map_data=map_driver.composite_map, - n_real=map_driver.composite_map.focus(), - file_name=params.output.ccp4_map) - print("Wrote CCP4 map to %s" % params.output.ccp4_map, file=out) - -if (__name__ == "__main__"): - run(sys.argv[1:]) From 50d105821c56153a3915e703a0f9e01b40a8f83b Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 10 Apr 2024 16:15:46 -0700 Subject: [PATCH 328/748] Check going back and forth does not accumulate errors. --- .../tst_model_set_hydrogen_bond_length.py | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/mmtbx/regression/model/tst_model_set_hydrogen_bond_length.py b/mmtbx/regression/model/tst_model_set_hydrogen_bond_length.py index a79f116ddd..170c9043db 100644 --- a/mmtbx/regression/model/tst_model_set_hydrogen_bond_length.py +++ b/mmtbx/regression/model/tst_model_set_hydrogen_bond_length.py @@ -4,8 +4,7 @@ import iotbx.pdb from libtbx.utils import null_out from libtbx.test_utils import approx_equal - - +from scitbx.array_family import flex def compare_XH_bond_length_to_ideal(model): geometry = model.get_restraints_manager().geometry @@ -20,6 +19,37 @@ def compare_XH_bond_length_to_ideal(model): assert approx_equal(atoms[i].distance(atoms[j]), bp.distance_ideal, eps=0.001) +def get_dist(s1, s2): + return flex.sqrt((s1 - s2).dot()) + +def tst_0(): + """ + Check going back and forth does not accumulate errors. + """ + pdb_inp = iotbx.pdb.input(lines=pdb_str1, source_info=None) + model = mmtbx.model.manager( + model_input = pdb_inp, + log = null_out()) + model.set_hydrogen_bond_length( + use_neutron_distances=True, show=False, log=null_out) + sites_cart_n = model.get_sites_cart() + model.set_hydrogen_bond_length( + use_neutron_distances=False, show=False, log=null_out) + sites_cart_x = model.get_sites_cart() + dist_mean = flex.mean(get_dist(sites_cart_n, sites_cart_x)) + assert dist_mean > 0.07 + # + model.set_hydrogen_bond_length( + use_neutron_distances=True, show=False, log=null_out) + sites_cart_n1 = model.get_sites_cart() + dist_mean = flex.mean(get_dist(sites_cart_n, sites_cart_n1)) + assert approx_equal(dist_mean, 0) + # + model.set_hydrogen_bond_length( + use_neutron_distances=False, show=False, log=null_out) + sites_cart_x1 = model.get_sites_cart() + dist_mean = flex.mean(get_dist(sites_cart_x, sites_cart_x1)) + assert approx_equal(dist_mean, 0) #------------------------------------------------------------------------------- @@ -358,6 +388,7 @@ def tst_3(): if (__name__ == "__main__"): t0 = time.time() + tst_0() tst_1() tst_2() tst_3() From 6527ae7bc1eb8335ad962db3d6e56da0d59de07f Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 10 Apr 2024 16:21:53 -0700 Subject: [PATCH 329/748] Check going back and forth does not accumulate errors. One extra check: the operation is irreversible. --- .../regression/model/tst_model_set_hydrogen_bond_length.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mmtbx/regression/model/tst_model_set_hydrogen_bond_length.py b/mmtbx/regression/model/tst_model_set_hydrogen_bond_length.py index 170c9043db..9aa7b95659 100644 --- a/mmtbx/regression/model/tst_model_set_hydrogen_bond_length.py +++ b/mmtbx/regression/model/tst_model_set_hydrogen_bond_length.py @@ -25,11 +25,13 @@ def get_dist(s1, s2): def tst_0(): """ Check going back and forth does not accumulate errors. + Also, confirm: the change cannot be undone. """ pdb_inp = iotbx.pdb.input(lines=pdb_str1, source_info=None) model = mmtbx.model.manager( model_input = pdb_inp, log = null_out()) + sites_cart_o = model.get_sites_cart() model.set_hydrogen_bond_length( use_neutron_distances=True, show=False, log=null_out) sites_cart_n = model.get_sites_cart() @@ -50,6 +52,10 @@ def tst_0(): sites_cart_x1 = model.get_sites_cart() dist_mean = flex.mean(get_dist(sites_cart_x, sites_cart_x1)) assert approx_equal(dist_mean, 0) + # This is irreversible + for sites_cart in [sites_cart_n, sites_cart_n1, sites_cart_x, sites_cart_x1]: + dist_mean = flex.mean(get_dist(sites_cart, sites_cart_o)) + assert dist_mean > 0.005 #------------------------------------------------------------------------------- From 10585296b11c4183f51c410989f013d41af65316 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 11 Apr 2024 11:23:43 -0700 Subject: [PATCH 330/748] Hydrogenate: disable check for unit cell content, so NMR models can be processed. --- mmtbx/hydrogens/reduce_hydrogen.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index 5ebf209b0f..75fafb0d5f 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -121,6 +121,7 @@ def get_reduce_pdb_interpretation_params(use_neutron_distances): p = mmtbx.model.manager.get_default_pdb_interpretation_params() #p.pdb_interpretation.restraints_library.cdl=False # XXX this triggers a bug !=360 p.pdb_interpretation.clash_guard.nonbonded_distance_threshold=None + p.pdb_interpretation.disable_uc_volume_vs_n_atoms_check=True p.pdb_interpretation.use_neutron_distances = use_neutron_distances p.pdb_interpretation.proceed_with_excessive_length_bonds=True p.pdb_interpretation.allow_polymer_cross_special_position=True From 246c6b9afbb79517cd32dc6248252a6ad77d21db Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Thu, 11 Apr 2024 12:05:35 -0700 Subject: [PATCH 331/748] README: switch nighly conda package tests to GitHub Actions - Move workflow to repository with Azure Pipelines tests - Start testing Apple Silicon packages with macos-14 runner - Update recommended conda installation to miniforge3 - Clean clutter [skip ci] --- .github/workflows/nightly_tests.yml | 34 --- README.md | 301 +-------------------------- mmtbx/validation/analyze_peptides.py | 3 +- 3 files changed, 8 insertions(+), 330 deletions(-) delete mode 100644 .github/workflows/nightly_tests.yml diff --git a/.github/workflows/nightly_tests.yml b/.github/workflows/nightly_tests.yml deleted file mode 100644 index cac554a3e5..0000000000 --- a/.github/workflows/nightly_tests.yml +++ /dev/null @@ -1,34 +0,0 @@ -# Test current conda packages on the conda-forge and cctbx-nightly -# channels. This is for testing for any breaking changes in the -# dependencies. -# -# macos-13 will test the x86-64 packages -# macos-14 will test the Apple Silicon packages - -name: Nightly conda package tests -on: workflow_dispatch - # schedule: - # - cron: '0 5 * * *' - -jobs: - test_conda_packages: - if: github.repository == 'cctbx/cctbx_project' - - strategy: - matrix: - channel: [conda-forge, cctbx-nightly] - os: [ubuntu-latest, macos-14, macos-13, windows-latest] - python_version: [3.8, 3.9, 3.10, 3.11, 3.12] - - name: Testing (${{ channel }} ${{ matrix.os }}) - runs-on: ${{ matrix.os }} - steps: - - uses: conda-incubator/setup-miniconda@v3 - with: - auto-update-conda: true - python-version: ${{ matrix.python_version }} - activate-environment: test - - name: Environment info - run: | - conda info - conda list diff --git a/README.md b/README.md index 486d6d1cb4..750f530813 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,12 @@ # Computational Crystallography Toolbox -[![Build Status](https://dev.azure.com/cctbx/cctbx_project/_apis/build/status/Updates/Update%20build%20cache?branchName=master)](https://dev.azure.com/cctbx/cctbx_project/_build/latest?definitionId=8&branchName=master) [![Conda Version](https://img.shields.io/conda/vn/conda-forge/cctbx-base.svg)](https://anaconda.org/conda-forge/cctbx-base) [![Conda Platforms](https://anaconda.org/conda-forge/cctbx-base/badges/platforms.svg)](https://anaconda.org/conda-forge/cctbx-base) [![DOI](https://img.shields.io/badge/DOI-10.1107/S0021889801017824-blue.svg)](https://doi.org/10.1107/S0021889801017824) +[![Build Status](https://dev.azure.com/cctbx/cctbx_project/_apis/build/status/Updates/Update%20build%20cache?branchName=master)](https://dev.azure.com/cctbx/cctbx_project/_build/latest?definitionId=8&branchName=master) [![Conda Version](https://img.shields.io/conda/vn/conda-forge/cctbx-base.svg)](https://anaconda.org/conda-forge/cctbx-base) [![Nightly conda package tests](https://github.com/cctbx/cctbx/actions/workflows/nightly_tests.yml/badge.svg?event=schedule)](https://github.com/cctbx/cctbx/actions/workflows/nightly_tests.yml) [![Conda Platforms](https://anaconda.org/conda-forge/cctbx-base/badges/platforms.svg)](https://anaconda.org/conda-forge/cctbx-base) [![DOI](https://img.shields.io/badge/DOI-10.1107/S0021889801017824-blue.svg)](https://doi.org/10.1107/S0021889801017824) ##### Table of Contents - [Introduction](#introduction) - [Installation](#install) - [Building a development version](#developmentversion) - [Contributing to the cctbx](#contributing) -- [Nightly builds](#nightlybuilds) -- [Checks of nightly builds](#nightlychecks) +- [Nightly builds and tests](#nightlybuilds) @@ -31,9 +30,9 @@ Use of the Python interfaces is highly recommended, but optional. The cctbx can ## Installation -The easiest way to install cctbx is through the [Conda package manager](https://docs.conda.io/en/latest/). You can get a full environment from [Anaconda](https://www.anaconda.com) or just the `conda` package manager with the [Miniconda installer](https://docs.conda.io/en/latest/miniconda.html). +The easiest way to install cctbx is through the [Conda package manager](https://docs.conda.io/en/latest/). We recommend the [Miniforge installers](https://github.com/conda-forge/miniforge?tab=readme-ov-file#miniforge3) since they provide a minimal environment and default to the `conda-forge` channel. -There are two packages available, `cctbx` and `cctbx-base`. The `cctbx` package is `cctbx-base` with some additional packages (`wxpython`, `pyside2`, `ipython`). +There are two packages available, `cctbx` and `cctbx-base`. The `cctbx` package is `cctbx-base` with some additional GUI packages (e.g. `wxpython`, `pyside2`, `ipython`). With the `conda` command available, a new `cctbx-base` environment named `my_env` can be created with ``` @@ -72,8 +71,8 @@ For a more detailed description on how to contribute to the cctbx please visit o -## Nightly builds - [![Build Status](https://dev.azure.com/cctbx-release/feedstock-builds/_apis/build/status/nightly-feedstock?branchName=main)](https://dev.azure.com/cctbx-release/feedstock-builds/_build/latest?definitionId=11&branchName=main) [![Conda Version](https://img.shields.io/conda/vn/cctbx-nightly/cctbx-base.svg)](https://anaconda.org/cctbx-nightly/cctbx-base) [![Conda Platforms](https://anaconda.org/cctbx-nightly/cctbx-base/badges/platforms.svg)](https://anaconda.org/cctbx-nightly/cctbx-base) +## Nightly builds and tests +[![Build Status](https://dev.azure.com/cctbx-release/feedstock-builds/_apis/build/status/nightly-feedstock?branchName=main)](https://dev.azure.com/cctbx-release/feedstock-builds/_build/latest?definitionId=11&branchName=main) [![Conda Version](https://img.shields.io/conda/vn/cctbx-nightly/cctbx-base.svg)](https://anaconda.org/cctbx-nightly/cctbx-base) [![Conda Platforms](https://anaconda.org/cctbx-nightly/cctbx-base/badges/platforms.svg)](https://anaconda.org/cctbx-nightly/cctbx-base) A nightly build of the `conda` packages are available on the [`cctbx-nightly` channel](https://anaconda.org/cctbx-nightly/repo). To use these packages, prepend `-c cctbx-nightly` as a channel to the commands above. For example, the command to create a new `my_env` environment would become

@@ -83,290 +82,4 @@ This will use the `cctbx-base` package from the `cctbx-nightly` channel, but pul
 
 Nightly builds are only updated if there are additional commits from the previous build.
 
-
-
-## Nightly checks of current release and nightly builds (except for Apple Silicon)
-
-A subset of tests is run on the current `cctbx-base` packages every night (10 pm Pacific) to test compatibility with the latest packages from `conda-forge`. Additional source files for `fable` and `antlr3` are needed for the tests.
-
-
-  
-  
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-      
-      
-      
-    
-  
-
Variantconda-forgecctbx-nightly
Linux Python 3.7 - - variant - - - - variant - -
Linux Python 3.8 - - variant - - - - variant - -
Linux Python 3.9 - - variant - - - - variant - -
Linux Python 3.10 - - variant - - - - variant - -
Linux Python 3.11 - - variant - - - - variant - -
Linux Python 3.12 - - variant - - - - variant - -
macOS (Intel) Python 3.7 - - variant - - - - variant - -
macOS (Intel) Python 3.8 - - variant - - - - variant - -
macOS (Intel) Python 3.9 - - variant - - - - variant - -
macOS (Intel) Python 3.10 - - variant - - - - variant - -
macOS (Intel) Python 3.11 - - variant - - - - variant - -
macOS (Intel) Python 3.12 - - variant - - - - variant - -
macOS (Apple Silicon) Python 3.8 - - variant - - - - variant - -
macOS (Apple Silicon) Python 3.9 - - variant - - - - variant - -
macOS (Apple Silicon) Python 3.10 - - variant - - - - variant - -
macOS (Apple Silicon) Python 3.11 - - variant - - - - variant - -
macOS (Apple Silicon) Python 3.12 - - variant - - - - variant - -
Windows Python 3.7 - - variant - - - - variant - -
Windows Python 3.8 - - variant - - - - variant - -
Windows Python 3.9 - - variant - - - - variant - -
Windows Python 3.10 - - variant - - - - variant - -
Windows Python 3.11 - - variant - - - - variant - -
Windows Python 3.12 - - variant - - - - variant - -
+A subset of tests is run on the current `cctbx-base` packages from the `conda-forge` and `cctbx-nightly` channels every night (10 pm Pacific) to test compatibility with the latest packages from `conda-forge`. Additional source files for `fable` and `antlr3` are needed for the tests. The nightly test details can be viewed by clicking the "Nightly conda package tests" badge near the beginning of this README. diff --git a/mmtbx/validation/analyze_peptides.py b/mmtbx/validation/analyze_peptides.py index b834cc7a54..660a7af629 100644 --- a/mmtbx/validation/analyze_peptides.py +++ b/mmtbx/validation/analyze_peptides.py @@ -1,7 +1,7 @@ from __future__ import absolute_import, division, print_function import sys import mmtbx.rotamer -from libtbx.utils import Sorry, Usage +from libtbx.utils import Sorry def get_master_phil(): import libtbx.phil @@ -150,4 +150,3 @@ def get_sort_key(pair): print("residue1:residue2:classification", file=log) for line in print_list: print(line, file=log) - From 7ff9a3c1c94010c77c28814de512c4e31c0a60b4 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 11 Apr 2024 12:19:01 -0700 Subject: [PATCH 332/748] Tidy-up Phenix: remove mmtbx/command_line/validate_waters.py and refactor test mmtbx/validation/regression/tst_waters.py --- mmtbx/command_line/validate_waters.py | 25 ----------------- mmtbx/validation/regression/tst_waters.py | 33 +++++++++++++++-------- 2 files changed, 22 insertions(+), 36 deletions(-) delete mode 100644 mmtbx/command_line/validate_waters.py diff --git a/mmtbx/command_line/validate_waters.py b/mmtbx/command_line/validate_waters.py deleted file mode 100644 index fcb041c287..0000000000 --- a/mmtbx/command_line/validate_waters.py +++ /dev/null @@ -1,25 +0,0 @@ - -from __future__ import absolute_import, division, print_function -from libtbx.str_utils import make_sub_header -import sys - -def run(args, out=sys.stdout): - from mmtbx.validation import waters - import mmtbx.command_line - master_phil = mmtbx.command_line.generate_master_phil_with_inputs("") - cmdline = mmtbx.command_line.load_model_and_data( - args=args, - master_phil=master_phil, - process_pdb_file=False, - out=out) - result = waters.waters( - pdb_hierarchy=cmdline.pdb_hierarchy, - xray_structure=cmdline.xray_structure, - fmodel=cmdline.fmodel, - collect_all=True) - make_sub_header("Solvent analysis", out=out) - result.show(out=out) - return result - -if (__name__ == "__main__"): - run(sys.argv[1:]) diff --git a/mmtbx/validation/regression/tst_waters.py b/mmtbx/validation/regression/tst_waters.py index 97643af9b0..54307ba8d6 100644 --- a/mmtbx/validation/regression/tst_waters.py +++ b/mmtbx/validation/regression/tst_waters.py @@ -5,12 +5,15 @@ from libtbx.utils import null_out from libtbx import easy_pickle from libtbx import group_args +from iotbx.data_manager import DataManager +from mmtbx.regression import make_fake_anomalous_data +import mmtbx.ions.utils +import iotbx.pdb +import mmtbx.model +from mmtbx.validation import waters def exercise_heavy(): - from mmtbx.regression import make_fake_anomalous_data - from mmtbx.command_line import validate_waters - import mmtbx.ions.utils - import iotbx.pdb + file_base = "tst_validate_waters_1" pdb_file = make_fake_anomalous_data.write_pdb_input_cd_cl(file_base=file_base) mtz_file = make_fake_anomalous_data.generate_mtz_file( @@ -20,14 +23,22 @@ def exercise_heavy(): group_args(selection="element CD", fp=-0.29, fdp=2.676), group_args(selection="element CL", fp=0.256, fdp=0.5), ]) + pdb_in = iotbx.pdb.input(pdb_file) - hierarchy = pdb_in.construct_hierarchy() - hierarchy, n = mmtbx.ions.utils.anonymize_ions(hierarchy, log=null_out()) - hierarchy.write_pdb_file("%s_start.pdb" % file_base, - crystal_symmetry=pdb_in.crystal_symmetry()) - args = ["tst_validate_waters_1_start.pdb", "tst_validate_waters_1.mtz", - "skip_twin_detection=True"] - results = validate_waters.run(args=args, out=null_out()) + m1 = mmtbx.model.manager(model_input = pdb_in, log = null_out()) + hierarchy, n = mmtbx.ions.utils.anonymize_ions(m1.get_hierarchy(), + log=null_out()) + fn_anonymized = file_base + '_start.pdb' + hierarchy.write_pdb_file(fn_anonymized,crystal_symmetry=m1.crystal_symmetry()) + dm = DataManager() + m = dm.get_model(fn_anonymized) + ma = dm.get_miller_arrays(filename = mtz_file) + fmo = dm.get_fmodel(scattering_table="n_gaussian") + results = waters.waters( + pdb_hierarchy=m.get_hierarchy(), + xray_structure=m.get_xray_structure(), + fmodel=fmo, + collect_all=True) out = StringIO() results.show(out=out) s = easy_pickle.dumps(results) From ee29c1741d51ff1c1c1b3680eb9142e48cfbb431 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 11 Apr 2024 12:39:28 -0700 Subject: [PATCH 333/748] Tidy-up Phenix: remove mmtbx/command_line/strip_model.py. It is a simple wrapper for mmtbx.refinement.select_best_starting_model.strip_model --- mmtbx/command_line/strip_model.py | 48 ------------------------------- 1 file changed, 48 deletions(-) delete mode 100644 mmtbx/command_line/strip_model.py diff --git a/mmtbx/command_line/strip_model.py b/mmtbx/command_line/strip_model.py deleted file mode 100644 index 5fede61c5f..0000000000 --- a/mmtbx/command_line/strip_model.py +++ /dev/null @@ -1,48 +0,0 @@ - -from __future__ import absolute_import, division, print_function -from libtbx.utils import Sorry -import os.path -import sys - -master_phil = """ - model = None - .type = path - include scope mmtbx.refinement.select_best_starting_model.strip_model_params - preserve_remarks = False - .type = bool - preserve_symmetry = True - .type = bool - output_file = None - .type = bool -""" - -def run(args, out=sys.stdout): - import iotbx.phil - cmdline = iotbx.phil.process_command_line_with_files( - args=args, - master_phil_string=master_phil, - pdb_file_def="model", - usage_string="""\ -mmtbx.strip_model model.pdb [options] - -Prepare a model for use in MR or isomorphous substitution. See also -phenix.pdbtools, which overlaps considerably in functionality. -""") - params = cmdline.work.extract() - if (params.model is None): - raise Sorry("No model specified.") - from mmtbx.refinement import select_best_starting_model - output_file = params.output_file - if (output_file is None): - output_file = os.path.basename(os.path.splitext(params.model)[0]) + \ - "_modified.pdb" - select_best_starting_model.strip_model( - file_name=params.model, - params=params, - preserve_remarks=params.preserve_remarks, - preserve_symmetry=params.preserve_symmetry, - output_file=output_file, - log=out) - -if (__name__ == "__main__"): - run(sys.argv[1:]) From 80feb5329784483d5df36a305c0af5ce61964e1d Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 11 Apr 2024 12:47:58 -0700 Subject: [PATCH 334/748] Clean up output --- mmtbx/validation/holton_geometry_validation.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 9529aba92e..ee7c49b8b4 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -89,6 +89,7 @@ def holton_geometry_validation(dm = None, a0 = 1.12482, mx = 0.21805, my = 0.736621), + verbose = False, log = sys.stdout, ): @@ -293,8 +294,9 @@ def get_residue_scores(info): working_info = select_residue_info(info, base_info, chain_id, resseq) analyze_geometry_values(working_info) info.residue_scores.append(working_info.sum_energy) - print("Residue score for %s: %.2f" %(resseq, working_info.sum_energy), - file = info.log) + if info.verbose: + print("Residue score for %s: %.2f" %(resseq, working_info.sum_energy), + file = info.log) def get_base_info(info): From 0bb39bf80345c334a4ab302f85861964b4f30250 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 11 Apr 2024 13:03:49 -0700 Subject: [PATCH 335/748] Tidy-up Phenix: remove mmtbx/command_line/simulate_low_res_data.py --- mmtbx/command_line/simulate_low_res_data.py | 857 -------------------- 1 file changed, 857 deletions(-) delete mode 100644 mmtbx/command_line/simulate_low_res_data.py diff --git a/mmtbx/command_line/simulate_low_res_data.py b/mmtbx/command_line/simulate_low_res_data.py deleted file mode 100644 index d739a35853..0000000000 --- a/mmtbx/command_line/simulate_low_res_data.py +++ /dev/null @@ -1,857 +0,0 @@ -from __future__ import absolute_import, division, print_function -import iotbx.phil -import libtbx.load_env -from libtbx.str_utils import make_header -from libtbx.math_utils import ifloor -from libtbx.utils import Sorry -from libtbx import easy_pickle -from libtbx import adopt_init_args -from iotbx import file_reader -import iotbx.pdb -import random -import math -import os -import sys -from six.moves import zip -from six.moves import range - -master_phil = iotbx.phil.parse(""" -simulate_data { - pdb_file = None - .type = path - .help = Model file. If no reflections file is given, data will be \ - generated starting from F(model). Otherwise it will only be used \ - to report scaling statistics. - hkl_file = None - .type = path - .help = Data file. If defined, the extracted amplitudes will be \ - truncated. Any R-free flags will be propagated to the output file. - data_label = None - .type = str - .help = Label for amplitudes or intensities in hkl_file (optional). - d_min = 3.0 - .type = float - .help = Resolution cutoff of output data. - random_seed = 90125714 - .type = int - output_file = None - .type = path - write_modified_pdb = True - .type = bool - r_free_flags { - file_name = None - .type = path - .help = File containing R-free flags. Can be left blank if hkl_file is \ - defined and contains R-free flags. - label = None - .type = str - .help = Label for R-free flags in r_free_file (or hkl_file). - fraction = 0.05 - .type = float - .help = Percent of reflections to flag for R-free (ignored if already \ - available). - missing_flags = *extend discard - .type = choice(multi=False) - .help = Handling of reflections for which R-free flags are not present. - } - crystal_symmetry { - space_group = None - .type = space_group - .help = Space group of output data. Ignored if reflections are used \ - as input. - unit_cell = None - .type = unit_cell - .help = Unit cell of output data. Ignored if reflections are used as \ - input. - } - modify_pdb { - remove_waters = True - .type = bool - .help = Strip waters from input model. - remove_alt_confs = False - .type = bool - .help = Strip alternate sidechains (and reset occupancy to 1). - convert_to_isotropic = False - .type = bool - .help = Convert all atoms to isotropic before calculating F(model). - set_mean_b_iso = None - .type = float - .help = Scale atomic B-factors to have this mean value. - set_wilson_b = False - .type = bool - .help = Scale atomic B-factors to have a mean equal to the mean \ - Wilson B-factor for this resolution (+/- 0.2A) - } - truncate - .help = Options for data truncation at lower resolution. - { - add_b_iso = None - .type = float - .help = Isotropic B-factor to be added to data. - add_b_aniso = 0 0 0 0 0 0 - .type = floats(size=6) - .help = Anisotropic B-factor to be added to data. Severely anisotropic \ - data might have an anisotropic B of 80,80,200,0,0,0. - apply_b_to_sigmas = True - .type = bool - .help = If True, the B-factor scaling will be done on experimental \ - sigmas (if present) as well as amplitudes. - add_random_error_percent = None - .type = float - .help = Adds random noise as a percentage of amplitude, evenly across \ - all resolutions. This is probably inferior to the sigma-based \ - noise generation. - remove_cone_around_axis = None - .type = float - .help = Radius in degrees of cone of missing data around the axis of \ - rotation (data collection pathology). If specified, axis_of_rotation \ - must be defined. - axis_of_rotation = None - .type = ints(size=3) - .help = Axis of rotation (as Miller indices, i.e. three integers) of \ - crystal during data collection. Only used if remove_cone_around_axis \ - is defined. - elliptical_truncation = False - .type = bool - .help = Truncate data anisotropically, using the overall anisotropic \ - B-factor plus ellipse_scale to set the ellipse dimensions. - ellipse_scale = 1.0 - .type = float - ellipse_target_completeness = None - .type = float - .help = Target completeness of data (as percent, max=100) after \ - elliptical truncation - } - generate_noise { - add_noise = False - .type = bool - noise_profile_file = None - .type = path - profile_model_file = None - .type = path - profile_data_label = None - .type = str - scale_noise = 1.0 - .type = float - n_resolution_bins = 20 - .type = int - n_intensity_bins = 20 - .type = int - } - fake_data_from_fmodel - .help = Options for generating model-based reflections using phenix.fmodel. - { - include scope mmtbx.programs.fmodel.fmodel_from_xray_structure_params - } -} -""", process_includes=True) - -def run(args, out=None): - if (out is None): - out = sys.stdout - make_header("mmtbx.simulate_low_res_data", out=out) - print(""" - For generation of realistic data (model-based, or using real - high-resolution data) for methods development. - -*********************************** WARNING: *********************************** - this is an experimental program - definitely NOT bug-free. - Use at your own risk! - - Usage: - mmtbx.simulate_low_res_data model.pdb [options...] - (generate data from a PDB file) - - mmtbx.simulate_low_res_data highres.mtz [model.pdb] [options...] - (truncate high-resolution data) - - mmtbx.simulate_low_res_data --help - (print full parameters with additional info) -""", file=out) - if (len(args) == 0) or ("--help" in args): - print("# full parameters:", file=out) - if ("--help" in args): - master_phil.show(attributes_level=1) - else : - master_phil.show() - return - interpreter = master_phil.command_line_argument_interpreter( - home_scope="simulate_data") - pdb_in = None - pdb_hierarchy = None - hkl_in = None - user_phil = [] - for arg in args : - if os.path.isfile(arg): - f = file_reader.any_file(arg) - if (f.file_type == "pdb"): - pdb_in = iotbx.pdb.input(arg) - user_phil.append(interpreter.process(arg="pdb_file=%s" % f.file_name)) - elif (f.file_type == "hkl"): - hkl_in = f.file_object - user_phil.append(interpreter.process(arg="hkl_file=%s" % f.file_name)) - elif (f.file_type == "phil"): - user_phil.append(f.file_object) - else : - try : - arg_phil = interpreter.process(arg=arg) - except RuntimeError : - print("ignoring uninterpretable argument '%s'" % arg, file=out) - else : - user_phil.append(arg_phil) - working_phil = master_phil.fetch(sources=user_phil) - make_header("Working parameters", out=out) - working_phil.show(prefix=" ") - params_ = working_phil.extract() - params = params_.simulate_data - prepare_data( - params=params, - hkl_in=hkl_in, - pdb_in=pdb_in, - out=out) - -class prepare_data(object): - def __init__(self, params, hkl_in=None, pdb_in=None, out=sys.stdout): - adopt_init_args(self, locals()) - self.params = params - self.out = out - self.pdb_hierarchy = None - if (params.pdb_file is None) and (params.hkl_file is None): - raise Sorry("No PDB file specified.") - if (params.generate_noise.add_noise) and (params.hkl_file is None): - if (params.generate_noise.noise_profile_file is None): - raise Sorry("noise_profile_file required when add_noise=True and " - "hkl_file is undefined.") - if (pdb_in is None) and (params.pdb_file is not None): - self.pdb_in = iotbx.pdb.input(params.pdb_file) - if (self.hkl_in is None) and (params.hkl_file is not None): - f = file_reader.any_file(params.hkl_File, force_type="hkl") - f.assert_file_type("hkl") - self.hkl_in = f.file_object - if (self.pdb_in is not None): - self.pdb_hierarchy = self.pdb_in.construct_hierarchy() - if (self.hkl_in is not None): - make_header("Extracting experimental data", out=sys.stdout) - f_raw, r_free = self.from_hkl() - elif (self.pdb_in is not None): - make_header("Generating fake data with phenix.fmodel", out=sys.stdout) - f_raw, r_free = self.from_pdb() - if (params.r_free_flags.file_name is not None): - f_raw, r_free = self.import_r_free_flags(f_raw) - self.r_free = r_free - make_header("Applying low-resolution filtering", out=sys.stdout) - print(" Target resolution: %.2f A" % params.d_min, file=out) - self.n_residues, self.n_bases = None, None - if (self.pdb_in is not None): - self.n_residues, self.n_bases = get_counts(self.pdb_hierarchy) - #if (params.auto_adjust): - # if (pdb_in is None): - # raise Sorry("You must supply a PDB file when auto_adjust=True.") - self.f_out = self.truncate_data(f_raw) - if (params.generate_noise.add_noise): - make_header("Adding noise using sigma profile", out=sys.stdout) - if (self.f_out.sigmas() is None): - if (self.pdb_in is not None): - iso_scale, aniso_scale = wilson_scaling(self.f_out, self.n_residues, - self.n_bases) - i_obs = create_sigmas( - f_obs=self.f_out, - params=params.generate_noise, - wilson_b=iso_scale.b_wilson, - return_as_amplitudes=False) - apply_sigma_noise(i_obs) - self.f_out = i_obs.f_sq_as_f() - make_header("Done processing", out=sys.stdout) - print(" Completeness after processing: %.2f%%" % ( - self.f_out.completeness() * 100.), file=out) - print(" Final resolution: %.2f A" % self.f_out.d_min(), file=out) - if (self.pdb_in is not None): - iso_scale, aniso_scale = wilson_scaling(self.f_out, self.n_residues, - self.n_bases) - print("", file=out) - print(" Scaling statistics for output data:", file=out) - show_b_factor_info(iso_scale, aniso_scale, out=out) - print("", file=out) - self.write_output() - - def write_output(self): - f_out = self.f_out - params = self.params - out = self.out - if (f_out.sigmas() is not None): - mtz_dataset = f_out.as_mtz_dataset( - column_root_label="F", - column_types="FQ") - else : - mtz_dataset = f_out.as_mtz_dataset( - column_root_label="F", - column_types="F") - if (self.r_free is not None): - r_free = self.r_free.common_set(f_out) - mtz_dataset.add_miller_array( - miller_array=r_free, - column_root_label="FreeR_flag", - column_types="I") - mtz_object = mtz_dataset.mtz_object() - if (params.output_file is None): - if (params.hkl_file is not None): - base_name = os.path.splitext(os.path.basename(params.hkl_file))[0] - else : - base_name = os.path.splitext(os.path.basename(params.pdb_file))[0] - params.output_file = base_name + "_low_res.mtz" - mtz_object.write(file_name=params.output_file) - print(" Wrote %s" % params.output_file, file=out) - if (self.pdb_hierarchy is not None) and (params.write_modified_pdb): - pdb_out = os.path.splitext(params.output_file)[0] + ".pdb" - f = open(pdb_out, "w") - f.write("%s\n" % "\n".join(self.pdb_in.crystallographic_section())) - f.write(self.pdb_hierarchy.as_pdb_string()) - f.close() - print(" Wrote modified model to %s" % pdb_out, file=out) - - def from_pdb(self): - out = self.out - params = self.params - pdb_hierarchy = self.pdb_hierarchy - pdb_sg, pdb_uc = None, None - pdb_symm = self.pdb_in.crystal_symmetry() - if (pdb_symm is not None): - pdb_sg = pdb_symm.space_group_info() - pdb_uc = pdb_symm.unit_cell() - apply_sg = pdb_sg - apply_uc = pdb_uc - if (params.crystal_symmetry.space_group is not None): - apply_sg = params.crystal_symmetry.space_group - else : - params.crystal_symmetry.space_group = pdb_sg - if (params.crystal_symmetry.unit_cell is not None): - apply_uc = params.crystal_symmetry.unit_cell - else : - params.crystal_symmetry.unit_cell = pdb_uc - if (apply_sg is None) or (apply_uc is None): - raise Sorry("Incomplete symmetry information - please specify a space "+ - "group and unit cell for this structure.") - from cctbx import crystal, adptbx - from scitbx.array_family import flex - apply_symm = crystal.symmetry( - unit_cell=apply_uc, - space_group_info=apply_sg) - if (params.modify_pdb.remove_waters): - print(" Removing solvent atoms...", file=out) - for model in pdb_hierarchy.models(): - for chain in model.chains(): - for residue_group in chain.residue_groups(): - for atom_group in residue_group.atom_groups(): - if (atom_group.resname in ["HOH", "WAT"]): - residue_group.remove_atom_group(atom_group=atom_group) - if (len(residue_group.atom_groups()) == 0): - chain.remove_residue_group(residue_group=residue_group) - if (len(chain.atoms()) == 0): - model.remove_chain(chain=chain) - if (params.modify_pdb.remove_alt_confs): - print(" Removing all alternate conformations and resetting occupancies...", file=out) - from mmtbx import pdbtools - pdbtools.remove_alt_confs(hierarchy=pdb_hierarchy) - xray_structure = self.pdb_in.xray_structure_simple( - crystal_symmetry=apply_symm) - sctr_keys = xray_structure.scattering_type_registry().type_count_dict() - hd_selection = xray_structure.hd_selection() - if (not (("H" in sctr_keys) or ("D" in sctr_keys))): - print(" WARNING: this model does not contain hydrogen atoms!", file=out) - print(" strongly recommend running phenix.ready_set or", file=out) - print(" equivalent to ensure realistic simulated data.", file=out) - print("", file=out) - if (params.modify_pdb.convert_to_isotropic): - xray_structure.convert_to_isotropic() - set_b = None - if (params.modify_pdb.set_mean_b_iso is not None): - assert (not params.modify_pdb.set_wilson_b) - print(" Scaling B-factors to have mean of %.2f" % \ - params.modify_pdb.set_mean_b_iso, file=out) - assert (params.modify_pdb.set_mean_b_iso > 0) - set_b = params.modify_pdb.set_mean_b_iso - elif (params.modify_pdb.set_wilson_b): - print(" Scaling B-factors to match mean Wilson B for this resolution", file=out) - set_b = get_mean_statistic_for_resolution( - d_min=params.d_min, - stat_type="wilson_b") - print("", file=out) - if (set_b is not None): - u_iso = xray_structure.extract_u_iso_or_u_equiv() - u_iso = u_iso.select(~hd_selection) - u_mean = flex.mean(u_iso) - b_mean = adptbx.u_as_b(u_mean) - scale = set_b / b_mean - xray_structure.scale_adps(scale) - pdb_hierarchy.atoms().set_adps_from_scatterers( - scatterers=xray_structure.scatterers(), - unit_cell=xray_structure.unit_cell()) - import mmtbx.programs.fmodel - from mmtbx import utils - fmodel_params = mmtbx.programs.fmodel.master_phil.extract() - fmodel_params.high_resolution = params.d_min - fake_data = params.fake_data_from_fmodel - fmodel_params.fmodel = fake_data.fmodel - if (fmodel_params.fmodel.b_sol == 0): - print(" b_sol is zero - will use mean value for d_min +/- 0.2A", file=out) - print(" (this is not strongly correlated with resolution, but", file=out) - print(" it is preferrable to use a real value instead of leaving", file=out) - print(" it set to 0)", file=out) - fmodel_params.fmodel.b_sol = 46.0 - print("", file=out) - if (fmodel_params.fmodel.k_sol == 0): - print(" k_sol is zero - will use mean value for d_min +/- 0.2A", file=out) - print(" (this is not strongly correlated with resolution, but", file=out) - print(" it is preferrable to use a real value instead of leaving", file=out) - print(" it set to 0)", file=out) - fmodel_params.fmodel.k_sol = 0.35 - print("", file=out) - fmodel_params.structure_factors_accuracy = fake_data.structure_factors_accuracy - fmodel_params.mask = fake_data.mask - fmodel_params.r_free_flags_fraction = params.r_free_flags.fraction - fmodel_params.add_sigmas = False - fmodel_params.output.type = "real" - fmodel_ = utils.fmodel_from_xray_structure( - xray_structure=xray_structure, - params=fmodel_params) - f_model = fmodel_.f_model - r_free_flags = fmodel_.r_free_flags - return (f_model, r_free_flags) - - def from_hkl(self): - params = self.params - out = self.out - miller_arrays = self.hkl_in.as_miller_arrays() - f_obs = None - r_free = None - for array in miller_arrays : - if (params.data_label is not None): - if (array.info().label_string() == params.data_label): - f_obs = array.map_to_asu() - elif (array.is_xray_amplitude_array()): - f_obs = array.map_to_asu() - params.data_label = array.info().label_string() - print(" F-obs: %s" % params.data_label, file=out) - elif (array.is_xray_intensity_array()): - f_obs = array.f_sq_as_f().map_to_asu() - params.data_label = array.info().label_string() - print(" I-obs: %s" % params.data_label, file=out) - if (params.r_free_flags.label is not None): - if (array.info().label_string() == params.r_free_flags.label): - r_free = array.map_to_asu() - print(" R-free: %s" % array.info().label_string(), file=out) - elif (array.info().label_string() in ["FreeR_flag", "FREE"]): - r_free = array.map_to_asu() - print(" R-free: %s" % array.info().label_string(), file=out) - f_obs = f_obs.resolution_filter(d_min=params.d_min) - if (r_free is not None): - r_free = r_free.common_set(f_obs) - return f_obs, r_free - - def import_r_free_flags(self, F): - params = self.params.r_free_flags - out = self.out - rfree_in = file_reader.any_file(params.file_name) - rfree_in.assert_file_type("hkl") - hkl_server = rfree_in.file_server - r_free_raw, flag_value = hkl_server.get_r_free_flags( - file_name=None, - label=params.label, - test_flag_value=None, - parameter_scope="simulate_data.r_free_flags", - disable_suitability_test=False) - r_free = r_free_raw.customized_copy(data=r_free_raw.data() == flag_value) - r_free = r_free.map_to_asu().common_set(F) - print(" Using R-free flags from %s:%s" % (rfree_in.file_name, - r_free_raw.info().label_string()), file=out) - if (F.data().size() != r_free.data().size()): - n_missing = F.data().size() - r_free.data().size() - assert (n_missing > 0) - if (params.missing_flags == "discard"): - print(" discarding %d amplitudes without R-free flags" % \ - n_missing, file=out) - F = F.common_set(r_free) - else : - print(" generating missing R-free flags for %d reflections" %\ - n_missing, file=out) - missing_set = F.lone_set(r_free) - missing_flags = missing_set.generate_r_free_flags( - fraction=r_free.data().count(True) / r_free.data().size(), - max_free=None, - use_lattice_symmetry=True) - r_free = r_free.concatenate(other=missing_flags) - assert (F.data().size() == r_free.data().size()) - return F, r_free - - def truncate_data(self, F): - params = self.params - out = self.out - from scitbx.array_family import flex - if (params.truncate.add_b_iso is not None): - print(" Applying isotropic B-factor of %.2f A^2" % ( - params.truncate.add_b_iso), file=out) - F = F.apply_debye_waller_factors( - b_iso=params.truncate.add_b_iso, - apply_to_sigmas=params.truncate.apply_b_to_sigmas) - if (params.truncate.add_b_aniso != [0,0,0,0,0,0]): - print(" Adding anisotropy...", file=out) - F = F.apply_debye_waller_factors( - b_cart=params.truncate.add_b_aniso, - apply_to_sigmas=params.truncate.apply_b_to_sigmas) - if (params.truncate.add_random_error_percent is not None): - print(" Adding random error as percent of amplitude...", file=out) - F = add_random_error(f_obs=F, - error_percent=params.truncate.add_random_error_percent) - if (params.truncate.remove_cone_around_axis is not None): - print(" Removing cone of data around axis of rotation...", file=out) - print(" radius = %.1f degrees" % \ - params.truncate.remove_cone_around_axis, file=out) - assert (params.truncate.axis_of_rotation is not None) - n_hkl, delta_n_hkl = remove_cone_around_axis( - array=F, - axis=params.truncate.axis_of_rotation, - cone_radius=params.truncate.remove_cone_around_axis) - print(" removed %d reflections (out of %d)" %(delta_n_hkl, - n_hkl), file=out) - if (params.truncate.elliptical_truncation): - print(" Truncating the data elliptically...", file=out) - target_completeness = params.truncate.ellipse_target_completeness - completeness_start = F.completeness() * 100.0 - # XXX temp fix for python3 failure: comparison is undefined if - # target_completeness is None. Substituting python 2 result (False) - if (target_completeness is not None and - completeness_start < target_completeness): - print(" completeness is already less than target value:", file=out) - print(" %.2f versus %.2f", file=out) - print(" elliptical truncation will be skipped.", file=out) - else : - print(" using overall anisotropic B as a guide.", file=out) - iso_scale, aniso_scale = wilson_scaling( - F=F, - n_residues=self.n_residues, - n_bases=self.n_bases) - n_hkl, delta_n_hkl = elliptical_truncation( - array=F, - b_cart=aniso_scale.b_cart, - scale_factor=params.truncate.ellipse_scale, - target_completeness=target_completeness) - print(" removed %d reflections (out of %d)" %(delta_n_hkl, - n_hkl), file=out) - return F - -def get_counts(hierarchy): - n_residues = 0 - n_bases = 0 - for chain in hierarchy.models()[0].chains(): - if chain.is_protein(): - n_residues += len(chain.residue_groups()) - elif chain.is_na(): - n_bases += len(chain.residue_groups()) - return n_residues, n_bases - -def wilson_scaling(F, n_residues, n_bases): - from mmtbx.scaling import absolute_scaling - iso_scale = absolute_scaling.ml_iso_absolute_scaling( - miller_array=F, - n_residues=n_residues, - n_bases=n_bases) - aniso_scale = absolute_scaling.ml_aniso_absolute_scaling( - miller_array=F, - n_residues=n_residues, - n_bases=n_bases) - return iso_scale, aniso_scale - -def show_b_factor_info(iso_scale, aniso_scale, out): - b_cart = aniso_scale.b_cart - print(" overall isotropic B-factor: %6.2f" % iso_scale.b_wilson, file=out) - print(" overall anisotropic B-factor: %6.2f, %6.2f, %6.2f" % ( - b_cart[0], b_cart[3], b_cart[4]), file=out) - print(" %14.2f, %6.2f" % ( - b_cart[1], b_cart[5]), file=out) - print(" %22.2f" % b_cart[2], file=out) - -def add_random_error(f_obs, error_percent): - from scitbx.array_family import flex - assert (100 > error_percent > 0) - data = f_obs.data() - fr = F.data() * error_percent / 100. - ri = flex.double() - for trial in range(data.size()): - r = random.randint(0,1) - if(r == 0): r = -1 - ri.append(r) - data = data + ri*fr - return f_obs.customized_copy(data=data) - -def elliptical_truncation(array, - b_cart, - scale_factor=1.0, - target_completeness=None): - from cctbx import adptbx - from scitbx.array_family import flex - indices = array.indices() - axis_index = -1 - min_b_directional = sys.maxsize - for n, b_index in enumerate(b_cart[0:3]): - if (b_index < min_b_directional): - min_b_directional = b_index - axis_index = n - assert (0 <= axis_index <= 3) - max_index_along_axis = [0,0,0] - for hkl in indices : - if (hkl[axis_index] > max_index_along_axis[axis_index]): - max_index_along_axis[axis_index] = hkl[axis_index] - assert (max_index_along_axis != [0,0,0]) - scale_cutoff = array.unit_cell().debye_waller_factor( - miller_index=max_index_along_axis, b_cart=b_cart) * scale_factor - scale = array.debye_waller_factors(b_cart=b_cart).data() - if (target_completeness is not None): - assert (target_completeness > 0) and (target_completeness <= 100) - completeness_start = array.completeness() * 100.0 - assert (completeness_start > target_completeness) - scale_srt = sorted(scale) - i_max = ifloor(len(scale_srt)*(completeness_start-target_completeness)/100) - scale_cutoff = scale_srt[i_max] - data = array.data() - sigmas = array.sigmas() - n_hkl = indices.size() - i = 0 - while (i < len(indices)): - if (scale[i] < scale_cutoff): - del indices[i] - del data[i] - del scale[i] - if (sigmas is not None): - del sigmas[i] - else : - i += 1 - delta_n_hkl = n_hkl - indices.size() - return (n_hkl, delta_n_hkl) - -def remove_cone_around_axis(array, axis, cone_radius): - assert (cone_radius < 90) and (cone_radius >= 0) - from scitbx.matrix import rec - unit_cell = array.unit_cell() - indices = array.indices() - rc_vectors = unit_cell.reciprocal_space_vector(indices) - v1 = rec(unit_cell.reciprocal_space_vector(tuple(axis)), (3,1)) - n_hkl = indices.size() - data = array.data() - sigmas = array.sigmas() - angle_high = 180 - cone_radius - i = 0 - while (i < len(indices)): - v2 = rec(rc_vectors[i], (3,1)) - #print v1, v2 - angle = math.degrees(v1.angle(v2)) - if (angle <= cone_radius) or (angle >= angle_high): - del rc_vectors[i] - del indices[i] - del data[i] - if (sigmas is not None): - del sigmas[i] - else : - i += 1 - delta_n_hkl = n_hkl - indices.size() - return (n_hkl, delta_n_hkl) - -stat_names = { - 'wilson_b' : 'Wilson B-factor', - 'k_sol' : 'Bulk solvent scale factor (k_sol)', - 'b_sol' : 'Bulk solvent B-factor (b_sol)', -} - -def get_mean_statistic_for_resolution(d_min, stat_type, range_value=0.2, out=None): - if (out is None): - out = sys.stdout - from scitbx.array_family import flex - pkl_file = libtbx.env.find_in_repositories( - relative_path = "chem_data/polygon_data/all_mvd.pickle", - test = os.path.isfile) - db = easy_pickle.load(pkl_file) - all_d_min = db['high_resolution'] - stat_values = db[stat_type] - values_for_range = flex.double() - for (d_, v_) in zip(all_d_min, stat_values): - try : - d = float(d_) - v = float(v_) - except ValueError : continue - else : - if (d > (d_min - range_value)) and (d < (d_min + range_value)): - values_for_range.append(v) - h = flex.histogram(values_for_range, n_slots=10) - print(" %s for d_min = %.3f - %.3f A" % (stat_names[stat_type], d_min-range_value, - d_min+range_value), file=out) - min = flex.min(values_for_range) - max = flex.max(values_for_range) - mean = flex.mean(values_for_range) - print(" count: %d" % values_for_range.size(), file=out) - print(" min: %.2f" % min, file=out) - print(" max: %.2f" % max, file=out) - print(" mean: %.2f" % mean, file=out) - print(" histogram of values:", file=out) - h.show(prefix=" ") - return mean - -def create_sigmas(f_obs, params, wilson_b=None, return_as_amplitudes=False): - assert (f_obs.sigmas() is None) - from scitbx.array_family import flex - i_obs = f_obs.f_as_f_sq() - i_norm = i_obs.data() / flex.mean(i_obs.data()) - profiler = profile_sigma_generator( - mtz_file=params.noise_profile_file, - pdb_file=params.profile_model_file, - wilson_b=wilson_b, - data_label=params.profile_data_label, - n_resolution_bins=params.n_resolution_bins, - n_intensity_bins=params.n_intensity_bins) - sigmas = flex.double(i_norm.size(), 0.0) - i_obs.setup_binner(n_bins=params.n_resolution_bins) - for j_bin in i_obs.binner().range_used(): - bin_sel = i_obs.binner().selection(j_bin) - shell_profile = profiler.get_noise_profile_for_shell(j_bin) - for k in bin_sel.iselection(): - i_over_sigma = shell_profile.get_i_over_sigma(i_norm[k]) - sigmas[k] = i_obs.data()[k] / i_over_sigma - i_new = i_obs.customized_copy(sigmas=sigmas) - if (return_as_amplitudes): - return i_new.f_as_f_sq() - else : - return i_new - -def apply_sigma_noise(i_obs): - assert (i_obs.is_xray_intensity_array()) - assert (i_obs.sigmas() is not None) - data = i_obs.data() - for i, sigma in enumerate(i_obs.sigmas()): - data[i] = random.gauss(data[i], sigma) - -class profile_sigma_generator(object): - def __init__(self, - mtz_file, - pdb_file, - wilson_b=None, - data_label=None, - n_resolution_bins=20, - n_intensity_bins=20, - out=None): - if (out is None): - out = sys.stdout - if (wilson_b is None) or (pdb_file is None): - print("""\ - WARNING: missing desired Wilson B-factor and/or PDB file - for noise profile data. Without this information - the intensity falloff with resolution will probably - not be the same for your synthetic data and the - data used to generate sigmas. -""", file=out) - self._resolution_bins = [] - from iotbx.file_reader import any_file - from scitbx.array_family import flex - f = any_file(mtz_file, force_type="hkl") - f.assert_file_type("hkl") - miller_arrays = f.file_server.miller_arrays - f_obs = None - i_obs = None - for array in miller_arrays : - if (array.info().label_string() == data_label) or (data_label is None): - if (array.is_xray_amplitude_array()) and (f_obs is None): - f_obs = array - elif (array.is_xray_intensity_array()) and (i_obs is None): - i_obs = array - if (i_obs is None): - assert (f_obs is not None) and (f_obs.sigmas() is not None) - i_obs = f_obs.f_as_f_sq() - assert (i_obs.sigmas() is not None) - if (wilson_b is not None) and (pdb_file is not None): - print(" Correcting reference data intensity falloff...", file=out) - f_obs = i_obs.f_sq_as_f() - pdb_hierarchy = iotbx.pdb.input(pdb_file).construct_hierarchy() - n_residues, n_bases = get_counts(pdb_hierarchy) - iso_scale, aniso_scale = wilson_scaling( - F=f_obs, - n_residues=n_residues, - n_bases=n_bases) - # TODO anisotropic? - print(" Scaling statistics for unmodified reference data:", file=out) - show_b_factor_info(iso_scale, aniso_scale, out=out) - delta_b = wilson_b - iso_scale.b_wilson - f_obs = f_obs.apply_debye_waller_factors(b_iso=delta_b) - i_obs = f_obs.f_as_f_sq() - i_mean = flex.max(i_obs.data()) - i_norm = i_obs.customized_copy( - data=i_obs.data() / i_mean, - sigmas=i_obs.sigmas() / i_mean) - i_norm.setup_binner(n_bins=20) - i_over_sigma = i_obs.data() / i_obs.sigmas() - for i_bin in i_norm.binner().range_used(): - sel = i_norm.binner().selection(i_bin) - i_shell = i_norm.select(sel) - sn_shell = i_over_sigma.select(sel) - noise_bins = shell_intensity_bins( - i_norm=i_shell, - i_over_sigma=sn_shell, - n_bins=n_intensity_bins) - self._resolution_bins.append(noise_bins) - - def get_noise_profile_for_shell(self, i_bin): - return self._resolution_bins[i_bin-1] - -class shell_intensity_bins(object): - def __init__(self, i_norm, i_over_sigma, n_bins=20): - self._binner = bin_by_intensity(i_norm.data(), n_bins) - self._sn_bins = [] - self._i_bins = [] - for n in range(n_bins): - bin_sel = self._binner.get_bin_selection(n) - sn_bin = i_over_sigma.select(bin_sel) - i_bin = i_norm.select(bin_sel) - assert (sn_bin.size() == i_bin.size()) - self._sn_bins.append(sn_bin) - self._i_bins.append(i_bin) - - def get_i_over_sigma(self, I): - assert (I <= 1) - if (I == 0) : return 1 # FIXME add French-Wilson before getting here - k = self._binner.get_bin(I) - sn_profile = self._sn_bins[k] - for j, i_ref in enumerate(self._i_bins[k]): - if (i_ref >= I): - return sn_profile[j] - return sn_profile[-1] - -class bin_by_intensity(object): - def __init__(self, data, n_bins=20): - from scitbx.array_family import flex - self._bin_limits = [] - self._bins = flex.int(data.size(), -1) - sorted_data = sorted(data) - bin_size = data.size() // n_bins - for n in range(n_bins): - bin_limit = bin_size * (n+1) - if (bin_limit >= data.size()): - bin_limit = data.size() - 1 - i_max = sorted_data[bin_limit] - self._bin_limits.append(i_max) - for k, I in enumerate(data): - bin = self.get_bin(I) - self._bins[k] = bin - - def get_bin(self, I): - assert (I >= 0) - for k, limit in enumerate(self._bin_limits): - if (I < limit): - return k - return len(self._bin_limits) - 1 - - def get_bin_selection(self, bin): - from scitbx.array_family import flex - sel = flex.bool(self._bins.size(), False) - for k, n in enumerate(self._bins): - if (n == bin): - sel[k] = True - return sel - -if (__name__ == "__main__"): - run(sys.argv[1:]) From 94500431a50d6458d28164cfcb656972f599fbcb Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 11 Apr 2024 13:50:38 -0700 Subject: [PATCH 336/748] Tidy-up Phenix: remove mmtbx/command_line/show_suspicious_residues.py --- .../command_line/show_suspicious_residues.py | 107 ------------------ 1 file changed, 107 deletions(-) delete mode 100644 mmtbx/command_line/show_suspicious_residues.py diff --git a/mmtbx/command_line/show_suspicious_residues.py b/mmtbx/command_line/show_suspicious_residues.py deleted file mode 100644 index 479f2bbd98..0000000000 --- a/mmtbx/command_line/show_suspicious_residues.py +++ /dev/null @@ -1,107 +0,0 @@ - -from __future__ import absolute_import, division, print_function -import libtbx.load_env -from libtbx import Auto -import sys -import os - -def master_phil(): - from mmtbx.command_line import generate_master_phil_with_inputs - return generate_master_phil_with_inputs( - enable_automatic_twin_detection=True, - phil_string=""" -hetatms_only = True - .type = bool -skip_xtal_solution_mols = False - .type = bool - .help = If True, common crystallization components such as sulfate or \ - glycerol will be ignored. -skip_single_atoms = True - .type = bool -skip_alt_confs = True - .type = bool -min_acceptable_cc = 0.8 - .type = float -min_acceptable_2fofc = 1.0 - .type = float -max_frac_atoms_below_min = 0.5 - .type = float -write_coot_script = True - .type = bool -write_maps = Auto - .type = bool -""") - -common_xtal_mols = [ - "SO4", "GOL", "EDO", "PEG", "ACT", "BME", -] - -def run(args, out=sys.stdout): - usage_string = """\ -mmtbx.show_suspicious_residues [model] [data] [options...] - -Flag bad residues based on fit to electron density. By default, only HETATM -records will be inspected. -""" - from mmtbx import real_space_correlation - from mmtbx.command_line import load_model_and_data - cmdline = load_model_and_data( - args=args, - master_phil=master_phil(), - out=out, - process_pdb_file=False, - usage_string=usage_string) - params = cmdline.params - ignore_list = [] - if (params.skip_xtal_solution_mols): - ignore_list = common_xtal_mols - outliers = real_space_correlation.find_suspicious_residues( - fmodel=cmdline.fmodel, - pdb_hierarchy=cmdline.pdb_hierarchy, - hetatms_only=params.hetatms_only, - skip_single_atoms=params.skip_single_atoms, - skip_alt_confs=params.skip_alt_confs, - ignore_resnames=ignore_list, - min_acceptable_cc=params.min_acceptable_cc, - min_acceptable_2fofc=params.min_acceptable_2fofc, - max_frac_atoms_below_min=params.max_frac_atoms_below_min, - log=out) - map_file = None - if ((params.write_maps == True) or - ((len(outliers) > 0) and (params.write_maps in [Auto, True]))): - import mmtbx.maps.utils - import iotbx.map_tools - f_map, diff_map = mmtbx.maps.utils.get_maps_from_fmodel(cmdline.fmodel) - anom_map = None - if (cmdline.fmodel.f_obs().anomalous_flag()): - anom_map = mmtbx.maps.utils.get_anomalous_map(cmdline.fmodel) - base_name = os.path.basename( - os.path.splitext(params.input.xray_data.file_name)[0]) - map_file = base_name + "_maps.mtz" - iotbx.map_tools.write_map_coeffs( - fwt_coeffs=f_map, - delfwt_coeffs=diff_map, - file_name=map_file, - anom_coeffs=anom_map) - print("Wrote maps to %s" % map_file) - if (len(outliers) > 0) and (params.write_coot_script): - zoom_list_base = libtbx.env.find_in_repositories( - relative_path="cctbx_project/cootbx/simple_zoom_list.py", - test=os.path.isfile) - script = open("coot_bad_residues.py", "w") - script.write(open(zoom_list_base).read()) - script.write("\n") - for file_name in params.input.pdb.file_name : - script.write("""read_pdb("%s")\n""" % file_name) - if (map_file is not None): - script.write("auto_read_make_and_draw_maps(\"%s\")\n" % map_file) - script.write(""" -draw_simple_zoom_list( - title="Residues in suspicious density", - items=%s) -""" % str(outliers)) - script.close() - print("Coot script is coot_bad_residues.py") - -if (__name__ == "__main__"): - run(sys.argv[1:]) From 2ce7651c6e41ac8dc4cf2c8c78cdfa8e800465d9 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 11 Apr 2024 15:08:23 -0700 Subject: [PATCH 337/748] Tidy-up Phenix: remove mmtbx/command_line/pdb_view_ad_hoc.py --- mmtbx/command_line/pdb_view_ad_hoc.py | 135 -------------------------- 1 file changed, 135 deletions(-) delete mode 100644 mmtbx/command_line/pdb_view_ad_hoc.py diff --git a/mmtbx/command_line/pdb_view_ad_hoc.py b/mmtbx/command_line/pdb_view_ad_hoc.py deleted file mode 100644 index 0800077f07..0000000000 --- a/mmtbx/command_line/pdb_view_ad_hoc.py +++ /dev/null @@ -1,135 +0,0 @@ -from __future__ import absolute_import, division, print_function -# LIBTBX_PRE_DISPATCHER_INCLUDE_SH PHENIX_GUI_ENVIRONMENT=1 -# LIBTBX_PRE_DISPATCHER_INCLUDE_SH export PHENIX_GUI_ENVIRONMENT - -from gltbx import wx_viewer -from libtbx.option_parser import libtbx_option_parser -import wx -import sys -from six.moves import range - -class viewer(wx_viewer.show_points_and_lines_mixin): - - def set_points_and_lines( - O, - app, - minimum_covering_sphere_view_scale=1.3): - pdb_atoms = app.pdb_atoms - pdb_atoms.set_chemical_element_simple_if_necessary() - atom_tmp_sentinel = pdb_atoms.reset_tmp(first_value=0, increment=0) - for i,rg in enumerate(app.pdb_hierarchy.residue_groups()): - for atom in rg.atoms(): - atom.tmp = i - O.points = pdb_atoms.extract_xyz() - if (app.co.serial_labels): - m = "" - need_m = (app.pdb_hierarchy.models_size() != 1) - for mdl in app.pdb_hierarchy.models(): - if (need_m): m = mdl.id.strip() + ":" - for i in range(mdl.atoms_size()): - O.labels.append(m+str(i)) - assert len(O.labels) == O.points.size() - else: - rg_done = set() - for atom in pdb_atoms: - i = atom.tmp - if (i not in rg_done): - rg_done.add(i) - l = atom.id_str() - else: - l = atom.name - O.labels.append(l) - from cctbx.crystal.distance_based_connectivity import \ - build_simple_two_way_bond_sets - bond_sets = build_simple_two_way_bond_sets( - sites_cart=O.points, - elements=pdb_atoms.extract_element()) - for i,bond_set in enumerate(bond_sets): - for j in bond_set: - if (i < j): - line = (i,j) - ai, aj = [pdb_atoms[_] for _ in line] - if (ai.is_in_same_conformer_as(aj)): - O.line_i_seqs.append(line) - if (ai.tmp == aj.tmp): - if (ai.tmp % 2 == 0): - color = (0,0,1) - else: - color = (0,1,0) - else: - color = (1,0,0) - O.line_colors[line] = color - del atom_tmp_sentinel - from scitbx.math import minimum_covering_sphere, sphere_3d - mcs = minimum_covering_sphere(O.points, epsilon=1.e-2) - O.minimum_covering_sphere = sphere_3d( - center=mcs.center(), - radius=mcs.radius()*minimum_covering_sphere_view_scale) - O.flag_show_minimum_covering_sphere = False - O.flag_show_rotation_center = False - _ = app.co.labels_threshold - O.flag_show_labels = (_ == 0 or len(O.points) <= _) - O.labels_display_list = None - O.lines_display_list = None - O.points_display_list = None - -class App(wx_viewer.App): - - def __init__(O, args): - import libtbx.load_env - command_line = (libtbx_option_parser( - usage="%s [options] pdb_file" % libtbx.env.dispatcher_name) - .option(None, "--model_id", - action="store", - type="str", - default=None, - help="only show model with given id", - metavar="STR") - .option(None, "--labels_threshold", - action="store", - type="int", - default=20, - help="do not show atom labels if more than given number of atoms", - metavar="INT") - .option(None, "--serial_labels", - action="store_true", - default=False) - ).process(args=args, nargs=1) - O.co = command_line.options - file_name = command_line.args[0] - import iotbx.pdb - O.pdb_inp = iotbx.pdb.input(file_name=file_name) - O.pdb_hierarchy = O.pdb_inp.construct_hierarchy() - O.pdb_atoms = O.pdb_hierarchy.atoms() - print(file_name) - print(" number of models:", O.pdb_hierarchy.models_size()) - print(" number of atoms:", O.pdb_atoms.size()) - if (O.co.model_id is not None): - mid = O.co.model_id.strip() - from libtbx.str_utils import show_string - print("Selecting model with id %s" % show_string(mid)) - for mdl in O.pdb_hierarchy.models(): - if (mdl.id.strip() == mid): - O.pdb_hierarchy = iotbx.pdb.hierarchy.root() - O.pdb_hierarchy.append_model(mdl) - O.pdb_atoms = O.pdb_hierarchy.atoms() - print(" number of atoms:", O.pdb_atoms.size()) - break - else: - raise RuntimeError( - "--model-id=%s is not in the pdb file." % show_string(mid)) - super(App, O).__init__(title=libtbx.env.dispatcher_name) - - def init_view_objects(O): - box = wx.BoxSizer(wx.VERTICAL) - O.view_objects = viewer(O.frame, size=(600,600)) - O.view_objects.set_points_and_lines(O) - box.Add(O.view_objects, wx.EXPAND, wx.EXPAND) - O.frame.SetSizer(box) - box.SetSizeHints(O.frame) - -def run(args): - App(args).MainLoop() - -if (__name__ == "__main__"): - run(sys.argv[1:]) From 1921ef3b7f6cfd6915d18803776f717235858967 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 12 Apr 2024 10:58:56 -0700 Subject: [PATCH 338/748] Tidy-up Phenix: remove mmtbx/command_line/extend_sidechains.py. Refactor associated test. --- mmtbx/building/tst_extend_sidechains.py | 113 ++++++++++++++++++------ mmtbx/command_line/extend_sidechains.py | 69 --------------- 2 files changed, 86 insertions(+), 96 deletions(-) delete mode 100644 mmtbx/command_line/extend_sidechains.py diff --git a/mmtbx/building/tst_extend_sidechains.py b/mmtbx/building/tst_extend_sidechains.py index 52b6f275b9..e098b8cc19 100644 --- a/mmtbx/building/tst_extend_sidechains.py +++ b/mmtbx/building/tst_extend_sidechains.py @@ -2,6 +2,14 @@ from six.moves import cStringIO as StringIO import os.path import iotbx.pdb.hierarchy +from mmtbx.command_line import extend_sidechains +from mmtbx.regression import model_1yjp +from iotbx.data_manager import DataManager +from libtbx.utils import null_out +import mmtbx.model +from mmtbx.building.extend_sidechains import master_params +import iotbx.pdb +from mmtbx.validation import rotalyze from six.moves import zip @@ -36,48 +44,99 @@ def exercise_model_only(): """) def exercise_cmdline(): - from mmtbx.command_line import extend_sidechains - from mmtbx.regression import model_1yjp - pdb_file = "tst_extend_sidechains.pdb" - mtz_file = "tst_extend_sidechains.mtz" + # + params = iotbx.phil.parse(input_string = master_params).extract() + # pdb_in = iotbx.pdb.input(source_info=None, lines=model_1yjp) - xrs = pdb_in.xray_structure_simple() - h_in = pdb_in.construct_hierarchy() + m1 = mmtbx.model.manager(model_input = pdb_in, log = null_out()) + h_in = m1.get_hierarchy() + # + mtz_file = "tst_extend_sidechains.mtz" + xrs = m1.get_xray_structure() f_calc = abs(xrs.structure_factors(d_min=1.5).f_calc()) - sel = h_in.atom_selection_cache().selection( - "not (resname TYR and not (name c or name o or name n or name oxt or name ca or name cb))") - hierarchy = h_in.select(sel) - f = open(pdb_file, "w") - f.write(hierarchy.as_pdb_string(crystal_symmetry=xrs)) - f.close() flags = f_calc.generate_r_free_flags(fraction=0.1) mtz = f_calc.as_mtz_dataset(column_root_label="F") mtz.add_miller_array(flags, column_root_label="FreeR_flag") mtz.mtz_object().write(mtz_file) + sel_str = "not (resname TYR and not (name c or name o or name n or name oxt or name ca or name cb))" + sel = m1.selection(sel_str) + h_trimmed = h_in.select(sel) + + pdb_file = "tst_extend_sidechains.pdb" + h_trimmed.write_pdb_file(pdb_file) + pdb_out = "tst_extend_sidechains_out.pdb" - if os.path.isfile(pdb_out): - os.remove(pdb_out) - out = StringIO() - extend_sidechains.run( - args=[pdb_file, mtz_file, "output_model=%s" % pdb_out], - out=out) - assert ("1 sidechains extended." in out.getvalue()), out.getvalue() - from mmtbx.validation import rotalyze + prefix=os.path.splitext(os.path.basename(pdb_out))[0] + + dm = DataManager() + m3 = dm.get_model(pdb_file) + ma = dm.get_miller_arrays(filename = mtz_file) + fmo3 = dm.get_fmodel(scattering_table="n_gaussian") + out1 = StringIO() + mmtbx.building.extend_sidechains.extend_and_refine( + pdb_hierarchy=m3.get_hierarchy(), + xray_structure=m3.get_xray_structure(), + fmodel=fmo3, + params=params, + prefix=prefix, + out=out1, + output_model=pdb_out) + + assert ("1 sidechains extended." in out1.getvalue()), out1.getvalue() + pdb_new = iotbx.pdb.input(file_name=pdb_out) h_new = pdb_new.construct_hierarchy() r1 = rotalyze.rotalyze(pdb_hierarchy=h_in, outliers_only=False) r2 = rotalyze.rotalyze(pdb_hierarchy=h_new, outliers_only=False) for o1, o2 in zip(r1.results, r2.results): assert o1.rotamer_name == o2.rotamer_name + # Cleanup + if os.path.isfile(pdb_out): os.remove(pdb_out) + if os.path.isfile(pdb_file): os.remove(pdb_file) + if os.path.isfile(prefix+'_maps.mtz'): os.remove(prefix+'_maps.mtz') + # # Part 2: with sequence corrections - seq_file = "tst_extend_sidechains.fa" - with open(seq_file, "w") as f: - f.write(">1yjp_new\nGNDQQNY") + # + out2 = StringIO() + #seq_file = "tst_extend_sidechains.fa" + #with open(seq_file, "w") as f: + # f.write(">1yjp_new\nGNDQQNY") + + sequences = [iotbx.bioinformatics.sequence("GNDQQNY")] + h_in_mod = h_trimmed.deep_copy() + n_changed = mmtbx.building.extend_sidechains.correct_sequence( + pdb_hierarchy=h_in_mod, + sequences=sequences, + out=out2) + #print(h_in.as_sequence()) + #print(h_in_mod.as_sequence()) + + pdb_file = "tst_extend_sidechains_2.pdb" + h_in_mod.write_pdb_file(pdb_file) + + dm = DataManager() + m4 = dm.get_model(pdb_file) + ma = dm.get_miller_arrays(filename = mtz_file) + fmo4 = dm.get_fmodel(scattering_table="n_gaussian") + pdb_out = "tst_extend_sidechains_out2.pdb" - extend_sidechains.run( - args=[pdb_file, mtz_file, seq_file, "output_model=%s" % pdb_out], - out=out) - assert ("1 sidechains extended." in out.getvalue()) + prefix=os.path.splitext(os.path.basename(pdb_out))[0] + + mmtbx.building.extend_sidechains.extend_and_refine( + pdb_hierarchy=m4.get_hierarchy(), + xray_structure=m4.get_xray_structure(), + fmodel=fmo4, + params=params, + prefix=prefix, + out=out2, + output_model=pdb_out) + + assert ("2 sidechains extended." in out2.getvalue()), out2.getvalue() + # Cleanup + if os.path.isfile(pdb_out): os.remove(pdb_out) + if os.path.isfile(pdb_file): os.remove(pdb_file) + if os.path.isfile(prefix+'_map.mtz'): os.remove(prefix+'_map.mtz') + if os.path.isfile(mtz_file): os.remove(mtz_file) def exercise_correct_sequence(): from mmtbx.building import extend_sidechains diff --git a/mmtbx/command_line/extend_sidechains.py b/mmtbx/command_line/extend_sidechains.py deleted file mode 100644 index e20ee7a8de..0000000000 --- a/mmtbx/command_line/extend_sidechains.py +++ /dev/null @@ -1,69 +0,0 @@ - -from __future__ import absolute_import, division, print_function -from libtbx.str_utils import make_sub_header -from libtbx.utils import null_out -import os.path -import sys - -extend_master_phil = """ -include scope mmtbx.building.extend_sidechains.master_params -output_model = None - .type = path -output_map_coeffs = None - .type = path -""" - -def get_master_phil(): - from mmtbx.command_line import generate_master_phil_with_inputs - return generate_master_phil_with_inputs(phil_string=extend_master_phil, - enable_automatic_twin_detection=True) - -def run(args, out=sys.stdout, verbose=True): - import mmtbx.building.extend_sidechains - import mmtbx.command_line - input_out = out - if (not verbose): - input_out = null_out() - cmdline = mmtbx.command_line.load_model_and_data( - args=args, - master_phil=get_master_phil(), - process_pdb_file=False, - out=input_out, - usage_string="""\ -mmtbx.extend_sidechains model.pdb data.mtz [restraints.cif] [options] - -Rebuild sidechains with missing non-hydrogen atoms. Includes real-space -refinement (but needs work).""") - params = cmdline.params - prefix = os.path.splitext(os.path.basename(params.input.pdb.file_name[0]))[0] - pdb_hierarchy = cmdline.pdb_hierarchy - xray_structure = cmdline.xray_structure - if (cmdline.params.input.sequence is not None): - from iotbx.bioinformatics import any_sequence_format - sequences, nc = any_sequence_format(cmdline.params.input.sequence) - make_sub_header("Correcting model sequence", out=out) - n_changed = mmtbx.building.extend_sidechains.correct_sequence( - pdb_hierarchy=pdb_hierarchy, - sequences=sequences, - out=out) - if (n_changed == 0): - print(" No modifications required.", file=out) - else : - xray_structure = pdb_hierarchy.extract_xray_structure( - crystal_symmetry=xray_structure.crystal_symmetry()) - cmdline.fmodel.update_xray_structure(xray_structure, - update_f_calc=True) - return mmtbx.building.extend_sidechains.extend_and_refine( - pdb_hierarchy=pdb_hierarchy, - xray_structure=xray_structure, - fmodel=cmdline.fmodel, - params=params, - prefix=prefix, - cif_objects=[ co for fn, co in cmdline.cif_objects ], - out=out, - verbose=verbose, - output_model=params.output_model, - output_map_coeffs=params.output_map_coeffs) - -if (__name__ == "__main__"): - run(sys.argv[1:]) From da74948e79a15e2efc3c47710484526a14aaba0a Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 12 Apr 2024 12:01:04 -0700 Subject: [PATCH 339/748] Remove obsolete import --- mmtbx/building/tst_extend_sidechains.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mmtbx/building/tst_extend_sidechains.py b/mmtbx/building/tst_extend_sidechains.py index e098b8cc19..29405d8f8c 100644 --- a/mmtbx/building/tst_extend_sidechains.py +++ b/mmtbx/building/tst_extend_sidechains.py @@ -2,7 +2,6 @@ from six.moves import cStringIO as StringIO import os.path import iotbx.pdb.hierarchy -from mmtbx.command_line import extend_sidechains from mmtbx.regression import model_1yjp from iotbx.data_manager import DataManager from libtbx.utils import null_out From 5f69e3158c482640028fa39cc4273fbd12b2c221 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 12 Apr 2024 12:04:48 -0700 Subject: [PATCH 340/748] Tidy-up Phenix: Remove mmtbx/command_line/compute_map_coefficients.py and associated test. --- .../command_line/compute_map_coefficients.py | 79 ------------------- mmtbx/regression/tst_map_coeffs_simple.py | 24 ------ mmtbx/run_tests.py | 1 - 3 files changed, 104 deletions(-) delete mode 100644 mmtbx/command_line/compute_map_coefficients.py delete mode 100644 mmtbx/regression/tst_map_coeffs_simple.py diff --git a/mmtbx/command_line/compute_map_coefficients.py b/mmtbx/command_line/compute_map_coefficients.py deleted file mode 100644 index 99d6c184c8..0000000000 --- a/mmtbx/command_line/compute_map_coefficients.py +++ /dev/null @@ -1,79 +0,0 @@ - -from __future__ import absolute_import, division, print_function -from libtbx import Auto -import os.path -import sys - -master_phil_str = """ -map_type = *2mFo-DFc mFo-DFc anom anom_residual llg - .type = choice -exclude_free_r_reflections = True - .type = bool -fill_missing_f_obs = False - .type = bool -b_sharp = None - .type = float -output_file = Auto - .type = path -""" - -map_type_labels = { - "2mFo-DFc" : "2FOFCWT", - "mFo-DFc" : "FOFCWT", - "anom" : "ANOM", - "anom_residual" : "ANOM_DIFF", - "llg" : "LLG", -} - -def master_phil(): - from mmtbx.command_line import generate_master_phil_with_inputs - return generate_master_phil_with_inputs( - phil_string=master_phil_str, - enable_automatic_twin_detection=True) - -def run(args, out=sys.stdout): - master_params = master_phil() - usage_string = """\ -mmtbx.compute_map_coefficients model.pdb data.mtz map_type=MAP_TYPE [options] - -Utility to compute a single set of map coefficients with minimal input. -""" - import mmtbx.command_line - from mmtbx import map_tools - import iotbx.mtz - cmdline = mmtbx.command_line.load_model_and_data( - args=args, - master_phil=master_params, - process_pdb_file=False, - prefer_anomalous=True, - usage_string=usage_string, - set_wavelength_from_model_header=True, - set_inelastic_form_factors="sasaki", - out=out) - fmodel = cmdline.fmodel - xray_structure = fmodel.xray_structure - params = cmdline.params - map_coeffs = fmodel.map_coefficients( - map_type=params.map_type, - exclude_free_r_reflections=params.exclude_free_r_reflections, - fill_missing=params.fill_missing_f_obs) - if (params.b_sharp is not None): - if (params.b_sharp is Auto): - params.b_sharp = - map_coeffs.d_min() * 10 - map_coeffs = map_tools.sharp_map( - sites_frac=None, - map_coeffs=map_coeffs, - b_sharp=b_sharp) - dec = iotbx.mtz.label_decorator(phases_prefix="PH") - mtz_dataset = map_coeffs.as_mtz_dataset( - column_root_label=map_type_labels[params.map_type], - label_decorator=dec) - if (params.output_file is Auto): - pdb_file = os.path.basename(params.input.pdb.file_name[0]) - params.output_file = os.path.splitext(pdb_file)[0] + "_%s.mtz" % \ - params.map_type - mtz_dataset.mtz_object().write(params.output_file) - print("Wrote %s" % params.output_file, file=out) - -if (__name__ == "__main__"): - run(sys.argv[1:]) diff --git a/mmtbx/regression/tst_map_coeffs_simple.py b/mmtbx/regression/tst_map_coeffs_simple.py deleted file mode 100644 index 49fd88b800..0000000000 --- a/mmtbx/regression/tst_map_coeffs_simple.py +++ /dev/null @@ -1,24 +0,0 @@ - -from __future__ import absolute_import, division, print_function -from six.moves import cStringIO as StringIO -import os - -def exercise(): - from mmtbx.command_line import compute_map_coefficients - from mmtbx.regression.make_fake_anomalous_data import generate_cd_cl_inputs - from iotbx import file_reader - mtz_file, pdb_file = generate_cd_cl_inputs( - file_base="tst_map_coeffs_simple") - args = [mtz_file, pdb_file, "map_type=anom_residual", - "skip_twin_detection=True"] - out = StringIO() - compute_map_coefficients.run(args=args, out=out) - assert """Using wavelength = 1.116 from PDB header""" in out.getvalue() - assert os.path.isfile("tst_map_coeffs_simple_anom_residual.mtz") - mtz_in = file_reader.any_file("tst_map_coeffs_simple_anom_residual.mtz") - assert (mtz_in.file_server.miller_arrays[0].info().label_string() == - "ANOM_DIFF,PHANOM_DIFF") - print("OK") - -if (__name__ == "__main__"): - exercise() diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index 18e4cff4a8..2c09aba050 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -256,7 +256,6 @@ "$D/regression/tst_validation_summary.py", "$D/regression/tst_maps_misc.py", "$D/regression/tst_anomalous_substructure.py", - "$D/regression/tst_map_coeffs_simple.py", # "$D/regression/tst_fmodel_no_cryst1.py", "$D/regression/tst_fmodel_misc.py", From 38ea75ada57c7d2d764eb2ec55df9801d1d111e8 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 12 Apr 2024 12:52:45 -0700 Subject: [PATCH 341/748] Make sure all tst files are removed after run. --- mmtbx/building/tst_extend_sidechains.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/building/tst_extend_sidechains.py b/mmtbx/building/tst_extend_sidechains.py index 29405d8f8c..4297338cd2 100644 --- a/mmtbx/building/tst_extend_sidechains.py +++ b/mmtbx/building/tst_extend_sidechains.py @@ -134,7 +134,7 @@ def exercise_cmdline(): # Cleanup if os.path.isfile(pdb_out): os.remove(pdb_out) if os.path.isfile(pdb_file): os.remove(pdb_file) - if os.path.isfile(prefix+'_map.mtz'): os.remove(prefix+'_map.mtz') + if os.path.isfile(prefix+'_maps.mtz'): os.remove(prefix+'_maps.mtz') if os.path.isfile(mtz_file): os.remove(mtz_file) def exercise_correct_sequence(): From 1197426b5a1bbd88bbe8556d4ce5e74e49a4be4c Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 12 Apr 2024 13:12:07 -0700 Subject: [PATCH 342/748] Tidy-up Phenix: remove mmtbx/command_line/afitt_fd.py --- mmtbx/command_line/afitt_fd.py | 152 --------------------------------- 1 file changed, 152 deletions(-) delete mode 100644 mmtbx/command_line/afitt_fd.py diff --git a/mmtbx/command_line/afitt_fd.py b/mmtbx/command_line/afitt_fd.py deleted file mode 100644 index aa9e97cd16..0000000000 --- a/mmtbx/command_line/afitt_fd.py +++ /dev/null @@ -1,152 +0,0 @@ -from __future__ import absolute_import, division, print_function -from mmtbx.geometry_restraints.afitt import finite_difference_test - -pdb_lines = """ -CRYST1 94.100 94.100 131.400 90.00 90.00 120.00 P 61 2 2 -ATOM 890 N ALA E 113 32.525 39.841 -1.660 1.00 15.64 N -ATOM 891 CA ALA E 113 31.553 40.901 -1.907 1.00 15.53 C -ATOM 893 C ALA E 113 31.742 41.398 -3.334 1.00 15.47 C -ATOM 894 O ALA E 113 32.873 41.486 -3.811 1.00 15.46 O -ATOM 892 CB ALA E 113 31.740 42.036 -0.918 1.00 15.53 C -ATOM 2602 ZN ZN F 5 36.912 44.685 -7.131 1.00 13.76 ZN -ATOM 2606 P1 LEP X 1 35.374 42.336 -6.280 1.00 14.03 P -ATOM 2607 O2 LEP X 1 34.629 43.616 -5.992 1.00 14.13 O -ATOM 2608 O3 LEP X 1 36.737 42.562 -6.884 1.00 13.72 O -ATOM 2609 O4 LEP X 1 34.549 41.267 -6.954 1.00 14.26 O -ATOM 2610 N5 LEP X 1 35.736 41.643 -4.701 1.00 14.42 N -ATOM 2611 C6 LEP X 1 36.701 42.323 -3.815 1.00 14.69 C -ATOM 2612 C7 LEP X 1 37.996 41.614 -4.069 1.00 14.79 C -ATOM 2613 O8 LEP X 1 39.062 42.207 -4.117 1.00 15.05 O -ATOM 2614 C9 LEP X 1 36.278 42.128 -2.373 1.00 14.85 C -ATOM 2615 C10 LEP X 1 37.233 42.793 -1.403 1.00 15.12 C -ATOM 2616 C11 LEP X 1 37.112 44.297 -1.488 1.00 15.24 C -ATOM 2617 C12 LEP X 1 36.866 42.344 -0.010 1.00 15.23 C -ATOM 2618 N13 LEP X 1 37.835 40.262 -4.227 1.00 14.73 N -ATOM 2632 H1 LEP X 1 35.374 42.336 -6.280 1.00 20.00 H -ATOM 2633 H2 LEP X 1 35.163 44.358 -6.248 1.00 20.00 H -ATOM 2619 H5 LEP X 1 34.776 41.783 -4.384 1.00 14.42 H -ATOM 2620 H6 LEP X 1 36.777 43.375 -4.099 1.00 14.69 H -ATOM 2623 H10 LEP X 1 38.271 42.498 -1.590 1.00 15.12 H -ATOM 2624 H111 LEP X 1 37.719 44.781 -0.714 1.00 15.24 H -ATOM 2625 H112 LEP X 1 37.468 44.680 -2.449 1.00 15.24 H -ATOM 2626 H113 LEP X 1 36.078 44.634 -1.353 1.00 15.24 H -ATOM 2627 H121 LEP X 1 36.971 41.259 0.097 1.00 15.23 H -ATOM 2628 H122 LEP X 1 37.521 42.806 0.737 1.00 15.23 H -ATOM 2629 H123 LEP X 1 35.834 42.607 0.247 1.00 15.23 H -ATOM 2630 H131 LEP X 1 38.608 39.742 -4.600 1.00 14.73 H -ATOM 2631 H132 LEP X 1 36.892 40.088 -4.602 1.00 14.73 H -ATOM 2621 H92 LEP X 1 35.260 42.517 -2.233 1.00 14.85 H -ATOM 2622 H93 LEP X 1 36.213 41.054 -2.148 1.00 14.85 H -""" -cif_lines = """ -data_comp_list -loop_ -_chem_comp.id -_chem_comp.three_letter_code -_chem_comp.name -_chem_comp.group -_chem_comp.number_atoms_all -_chem_comp.number_atoms_nh -LEP LEP '(2S)-2-[(hydroxy-oxido-oxo-$l^{6}-phosphanyl)amino]-4-methyl-pentanamide' non-polymer 28 13 -data_comp_LEP -loop_ -_chem_comp_atom.comp_id -_chem_comp_atom.atom_id -_chem_comp_atom.type_symbol -_chem_comp_atom.type_energy -_chem_comp_atom.partial_charge -LEP P1 P 'P1 ' 0.000 -LEP O2 O 'OP ' 0.000 -LEP O3 O 'OP ' 0.000 -LEP O4 O 'OP ' 0.000 -LEP N5 N 'NT1 ' 0.000 -LEP C6 C 'CH1 ' 0.000 -LEP C7 C 'C ' 0.000 -LEP O8 O 'O ' 0.000 -LEP C9 C 'CH2 ' 0.000 -LEP C10 C 'CH1 ' 0.000 -LEP C11 C 'CH3 ' 0.000 -LEP C12 C 'CH3 ' 0.000 -LEP N13 N 'NH2 ' 0.000 -LEP H1 H 'HCH ' 0.000 -LEP H2 H 'HOH1' 0.000 -LEP H5 H 'HNH1' 0.000 -LEP H6 H 'HCH1' 0.000 -LEP H10 H 'HCH1' 0.000 -LEP H111 H 'HCH3' 0.000 -LEP H112 H 'HCH3' 0.000 -LEP H113 H 'HCH3' 0.000 -LEP H121 H 'HCH3' 0.000 -LEP H122 H 'HCH3' 0.000 -LEP H123 H 'HCH3' 0.000 -LEP H131 H 'HNH2' 0.000 -LEP H132 H 'HNH2' 0.000 -LEP H92 H 'HCH2' 0.000 -LEP H93 H 'HCH2' 0.000 -loop_ -_chem_comp_bond.comp_id -_chem_comp_bond.atom_id_1 -_chem_comp_bond.atom_id_2 -_chem_comp_bond.type -_chem_comp_bond.value_dist -_chem_comp_bond.value_dist_esd -LEP P1 O2 single 1.630 0.020 -LEP P1 O3 single 1.510 0.020 -LEP P1 O4 double 1.510 0.015 -LEP P1 N5 single 1.762 0.020 -LEP N5 C6 single 1.472 0.020 -LEP N5 H5 single 1.028 0.020 -LEP C6 C7 single 1.492 0.020 -LEP C6 C9 single 1.508 0.020 -LEP C6 H6 single 1.093 0.020 -LEP C7 O8 double 1.222 0.015 -LEP C7 N13 single 1.369 0.020 -LEP C9 C10 single 1.508 0.020 -LEP C9 H92 single 1.093 0.020 -LEP C9 H93 single 1.093 0.020 -LEP C10 C11 single 1.508 0.020 -LEP C10 C12 single 1.508 0.020 -LEP C10 H10 single 1.093 0.020 -LEP C11 H111 single 1.093 0.020 -LEP C11 H112 single 1.093 0.020 -LEP C11 H113 single 1.093 0.020 -LEP C12 H121 single 1.093 0.020 -LEP C12 H122 single 1.093 0.020 -LEP C12 H123 single 1.093 0.020 -LEP N13 H131 single 1.015 0.020 -LEP N13 H132 single 1.015 0.020 -LEP P1 H1 single 1.411 0.020 -LEP O2 H2 single 0.981 0.020 -""" - -def run(pdb_file, cif_file, ligand_names,atom,scale,verbose): - finite_difference_test(pdb_file, cif_file, ligand_names,atom,scale,verbose) - -if (__name__ == "__main__"): - import sys - if len(sys.argv)==1: - f=open("afitt_fd.pdb", "w") - f.write(pdb_lines) - f.close() - f=open("afitt_fd.cif", "w") - f.write(cif_lines) - f.close() - run("afitt_fd.pdb", 'afitt_fd.cif', ["LEP"], 7, 1, True) - - else: - import argparse - parser = argparse.ArgumentParser() - parser.add_argument("pdb_file", help="pdb file") - parser.add_argument("cif_file", help="cif file", default=0) - parser.add_argument("ligand_names", help="3-letter ligand names separated by commas") - parser.add_argument("atom", help="i_seq of atom whose x-coord will be " - "modified (to test AFITT this should " - "be a ligand atom)") - parser.add_argument( "-s", "--scale", default=1, help="weight applied" \ - "to AFITT gradient/traget", type=float) - parser.add_argument('-v', dest='verbose', action='store_true', help="verbose output") - parser.epilog='Example: phenix.python afitt_fd.py vAla3.pdb vAla3.cif NME 37' - args = parser.parse_args() - ligand_names=args.ligand_names.split(',') - run(args.pdb_file, args.cif_file, ligand_names, int(args.atom), - args.scale, args.verbose) From 61d1399843cb2bbe9472f7d6406946fc1428cdc6 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 12 Apr 2024 15:35:03 -0700 Subject: [PATCH 343/748] Tidy-up Phenix: remove mmtbx/command_line/afitt.py --- mmtbx/command_line/afitt.py | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 mmtbx/command_line/afitt.py diff --git a/mmtbx/command_line/afitt.py b/mmtbx/command_line/afitt.py deleted file mode 100644 index dd369996d8..0000000000 --- a/mmtbx/command_line/afitt.py +++ /dev/null @@ -1,22 +0,0 @@ -# LIBTBX_SET_DISPATCHER_NAME mmtbx.afitt - -from __future__ import absolute_import, division, print_function -import sys -from mmtbx.geometry_restraints import afitt - -if __name__ == "__main__": - if len(sys.argv[1:])<3: - print(''' -usage: mmtbx.afitt [-h] [-ff FF] pdb_file cif_file ligand_names - -positional arguments: - pdb_file pdb file - cif_file cif file - ligand_names 3-letter ligand names separated by commas - -optional arguments: - -h, --help show this help message and exit - -ff FF afitt theory: mmff94, mmff94s pm3 or am1 - ''') - else: - afitt.run2() From fa9cb79fcf52b4d239680a382e25c32307b08a6d Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 12 Apr 2024 15:54:52 -0700 Subject: [PATCH 344/748] Tidy-up Phenix: remove mmtbx/command_line/monomer_library.comp_as_motif.py --- .../command_line/monomer_library.comp_as_motif.py | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 mmtbx/command_line/monomer_library.comp_as_motif.py diff --git a/mmtbx/command_line/monomer_library.comp_as_motif.py b/mmtbx/command_line/monomer_library.comp_as_motif.py deleted file mode 100644 index 8171e42399..0000000000 --- a/mmtbx/command_line/monomer_library.comp_as_motif.py +++ /dev/null @@ -1,14 +0,0 @@ -from __future__ import absolute_import, division, print_function -from mmtbx.monomer_library import server -import sys - -def run(args): - list_cif = server.mon_lib_list_cif() - srv = server.server(list_cif=list_cif) - for comp_id in args: - comp_comp_id = srv.get_comp_comp_id_direct(comp_id=comp_id) - motif = comp_comp_id.as_geometry_restraints_motif() - motif.show() - -if (__name__ == "__main__"): - run(sys.argv[1:]) From 5278cbc5bcc9057dbf1fde6fca5a430e02f120e8 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Sat, 13 Apr 2024 10:53:57 -0700 Subject: [PATCH 345/748] Tidy-up Phenix: refactor test to avoid calling validate_ions cl tool. --- mmtbx/ions/tst_validate_mg.py | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/mmtbx/ions/tst_validate_mg.py b/mmtbx/ions/tst_validate_mg.py index 56396c7a26..cec1ab3aec 100644 --- a/mmtbx/ions/tst_validate_mg.py +++ b/mmtbx/ions/tst_validate_mg.py @@ -1,19 +1,36 @@ from __future__ import absolute_import, division, print_function -import os -from libtbx import easy_run -import time +import os, time +from six.moves import cStringIO as StringIO +from iotbx.data_manager import DataManager +from mmtbx.regression.make_fake_anomalous_data import generate_magnessium_inputs +import iotbx.phil +import mmtbx.ions.identify def exercise(): - from mmtbx.regression.make_fake_anomalous_data import generate_magnessium_inputs base = "tst_validate_mg" mtz_file, pdb_file = generate_magnessium_inputs(file_base=base, anonymize=False) time.sleep(2) - args = ["\"%s\"" % pdb_file, "\"%s\"" % mtz_file, "nproc=1"] - result = easy_run.fully_buffered("mmtbx.validate_ions %s" % " ".join(args) - ).raise_if_errors() + dm = DataManager() + m = dm.get_model(pdb_file) + m.process(make_restraints=True) + grm = m.get_restraints_manager() + ma = dm.get_miller_arrays(filename = mtz_file) + fmo = dm.get_fmodel(scattering_table="n_gaussian") + from mmtbx.ions.identify import ion_identification_phil_str + params = iotbx.phil.parse(input_string = ion_identification_phil_str).extract() + out = StringIO() + manager = mmtbx.ions.identify.create_manager( + pdb_hierarchy = m.get_hierarchy(), + fmodel=fmo, + geometry_restraints_manager=grm.geometry, + wavelength=None, + params=params, + nproc = 1, + log= out) + result = manager.validate_ions(out = out) n_mg, n_bad = 0, 0 - for line in result.stdout_lines : + for line in out.getvalue().splitlines(): if "| MG" in line: n_mg += 1 if "!!!" in line: From b55386d44fbb387628f4c47702515ab35259047c Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Sat, 13 Apr 2024 11:10:57 -0700 Subject: [PATCH 346/748] Tidy-up Phenix: remove mmtbx/command_line/validate_ions.py. Refactor test. --- mmtbx/command_line/validate_ions.py | 58 ----------------------------- mmtbx/ions/tst_validate_ca.py | 45 ++++++++++++++-------- 2 files changed, 30 insertions(+), 73 deletions(-) delete mode 100644 mmtbx/command_line/validate_ions.py diff --git a/mmtbx/command_line/validate_ions.py b/mmtbx/command_line/validate_ions.py deleted file mode 100644 index 21fa82f261..0000000000 --- a/mmtbx/command_line/validate_ions.py +++ /dev/null @@ -1,58 +0,0 @@ - -from __future__ import absolute_import, division, print_function -from libtbx.str_utils import make_header -from libtbx import Auto -import sys - -def master_phil(): - from mmtbx.command_line import generate_master_phil_with_inputs - return generate_master_phil_with_inputs( - enable_automatic_twin_detection=True, - enable_pdb_interpretation_params=True, - enable_stop_for_unknowns=False, - phil_string=""" -include scope mmtbx.ions.identify.ion_master_phil -debug = True - .type = bool -nproc = Auto - .type = int -""") - -def run(args, out=sys.stdout): - usage_string="""\ -mmtbx.validate_ions model.pdb data.mtz [options ...] - -Utility to validate ions that have been built into a model, based on local -environment, electron density maps, and atomic properties. -""" - import mmtbx.ions.identify - import mmtbx.command_line - cmdline = mmtbx.command_line.load_model_and_data( - args=args, - master_phil=master_phil(), - out=out, - process_pdb_file=True, - create_fmodel=True, - set_wavelength_from_model_header=True, - set_inelastic_form_factors="sasaki", - prefer_anomalous=True) - fmodel = cmdline.fmodel - xray_structure = cmdline.xray_structure - params = cmdline.params - pdb_hierarchy = cmdline.pdb_hierarchy - geometry = cmdline.geometry - make_header("Inspecting ions", out=out) - manager = mmtbx.ions.identify.create_manager( - pdb_hierarchy = pdb_hierarchy, - fmodel=fmodel, - geometry_restraints_manager=geometry, - wavelength=params.input.wavelength, - params=params, - verbose = params.debug, - nproc = params.nproc, - log=out) - manager.show_current_scattering_statistics(out=out) - return manager.validate_ions(out = out, debug = params.debug) - -if (__name__ == "__main__"): - run(sys.argv[1:]) diff --git a/mmtbx/ions/tst_validate_ca.py b/mmtbx/ions/tst_validate_ca.py index d848124614..8689e327e5 100644 --- a/mmtbx/ions/tst_validate_ca.py +++ b/mmtbx/ions/tst_validate_ca.py @@ -1,20 +1,36 @@ from __future__ import absolute_import, division, print_function -import os -from libtbx import easy_run -import time +import os, time +from six.moves import cStringIO as StringIO +from iotbx.data_manager import DataManager +from mmtbx.regression.make_fake_anomalous_data import generate_calcium_inputs +import iotbx.phil +import mmtbx.ions.identify def exercise(): - from mmtbx.regression.make_fake_anomalous_data import generate_calcium_inputs base = "tst_validate_ca" mtz_file, pdb_file = generate_calcium_inputs(file_base=base, anonymize=False) time.sleep(2) - args = ["\"%s\"" % pdb_file, "\"%s\"" % mtz_file, "wavelength=1.12", - "nproc=1"] - result = easy_run.fully_buffered("mmtbx.validate_ions %s" % " ".join(args) - ).raise_if_errors() + dm = DataManager() + m = dm.get_model(pdb_file) + m.process(make_restraints=True) + grm = m.get_restraints_manager() + ma = dm.get_miller_arrays(filename = mtz_file) + fmo = dm.get_fmodel(scattering_table="n_gaussian") + from mmtbx.ions.identify import ion_identification_phil_str + params = iotbx.phil.parse(input_string = ion_identification_phil_str).extract() + out = StringIO() + manager = mmtbx.ions.identify.create_manager( + pdb_hierarchy = m.get_hierarchy(), + fmodel=fmo, + geometry_restraints_manager=grm.geometry, + wavelength=1.12, + params=params, + nproc = 1, + log= out) + result = manager.validate_ions(out = out) n_ca, n_bad = 0, 0 - for line in result.stdout_lines: + for line in out.getvalue().splitlines(): if "| CA" in line: n_ca += 1 if "!!!" in line: @@ -25,9 +41,8 @@ def exercise(): print("OK") if (__name__ == "__main__"): - print("WARNING: TEST TOO SLOW. MAKE IT RUN UNDER 300s AND ENABLE BACK.") - if 0: #XXX FIXME disabled - t0 = time.time() - exercise() - print("Time: %6.2f"%(time.time()-t0)) - print("OK") + #print("WARNING: TEST TOO SLOW. MAKE IT RUN UNDER 300s AND ENABLE BACK.") + t0 = time.time() + exercise() + print("Time: %6.2f"%(time.time()-t0)) + print("OK") From 8125acfc13913a208046cdba907252ca9086314f Mon Sep 17 00:00:00 2001 From: terwill Date: Mon, 15 Apr 2024 10:11:44 -0700 Subject: [PATCH 347/748] Allow multi-chain models with gaps; remove unused function --- iotbx/pdb/hierarchy.py | 29 ++++++++++--------- .../validation/holton_geometry_validation.py | 7 +++-- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index 8b99dbaef0..b92600fb99 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -1006,24 +1006,14 @@ def as_model_manager(self, crystal_symmetry, shift_cart = shift_cart) return mm - - def as_dict_of_chain_id_resseq_residue_names(self): + def as_dict_of_chain_id_resseq_as_int_residue_names(self): dd = {} m = self.only_model() for c in m.chains(): - new_dd = c.as_dict_of_resseq_residue_names() + new_dd = c.as_dict_of_resseq_as_int_residue_names() dd[c.id] = new_dd return dd - def as_dict_of_chain_id_resseq_as_int_residue_names(self): - max_models = 1 - dd = {} - for m in self.models()[:max_models]: - for c in m.chains(): - new_dd = c.as_dict_of_resseq_as_int_residue_names() - dd[c.id] = new_dd - return dd - def as_sequence(self, substitute_unknown='X', substitute_unknown_na = 'N', @@ -2529,6 +2519,13 @@ def last_resseq_as_int(self, chain_id = None): return last_resno + def has_icodes(self): + for m in self.models(): + for chain in m.chains(): + for rg in chain.residue_groups(): + if rg.icode and rg.icode != ' ': + return True + def chain_ids(self, unique_only = False): ''' Get list of chain IDS, return unique set if unique_only=True''' chain_ids=[] @@ -2856,11 +2853,15 @@ def as_list_of_residue_names(self): break return sequence - def as_dict_of_resseq_residue_names(self): + def as_dict_of_resseq_residue_names(self, strip_resseq = True): dd = {} for rg in self.residue_groups(): for atom_group in rg.atom_groups(): - dd[rg.resseq] = atom_group.resname + if strip_resseq: + resseq = rg.resseq.strip() + else: + resseq = rg.resseq + dd[resseq] = atom_group.resname break return dd diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index ee7c49b8b4..7779069983 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -286,7 +286,6 @@ def get_residue_scores(info): return # nothing to do # For now, only one chain_id - assert len(list(info.chain_dict.keys())) == 1 # only one chain for residue_scores base_info = get_base_info(info) for chain_id in list(info.chain_dict.keys()): @@ -767,8 +766,8 @@ def __init__(self, atom): def as_string(self): ''' Print a longer string that has all fields separated ''' atom = self.atom - return "%3s %s %3s %2s %4s" %(atom.name,atom.altloc,atom.resname, - atom.chain_id,atom.resseq) + return "%3s %s %3s %2s %4s%s" %(atom.name,atom.altloc,atom.resname, + atom.chain_id,atom.resseq,atom.icode) def __repr__(self): # pdb=" CG1AVAL A 1 " Mimics model.get_site_labels() @@ -783,6 +782,8 @@ def resseq(self): return self.atom.resseq def chain_id(self): return self.atom.chain_id + def icode(self): + return self.atom.icode def energy(delta, sigma, round_numbers = None): if round_numbers: From 7d38668052f2a576399d9c2a3e0fb8ede7f607ec Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Mon, 15 Apr 2024 11:56:12 -0700 Subject: [PATCH 348/748] Refactor test --- mmtbx/ions/tst_symmetry_axis.py | 64 +++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/mmtbx/ions/tst_symmetry_axis.py b/mmtbx/ions/tst_symmetry_axis.py index f64020e022..83207e3f0b 100644 --- a/mmtbx/ions/tst_symmetry_axis.py +++ b/mmtbx/ions/tst_symmetry_axis.py @@ -4,7 +4,25 @@ from libtbx.utils import null_out from libtbx import group_args import iotbx.pdb +from libtbx import Auto +import iotbx.phil from six.moves import cStringIO as StringIO +import mmtbx.ions.identify +from iotbx.data_manager import DataManager + +water_screen_master_phil = ''' +include scope mmtbx.ions.identify.ion_master_phil +include scope mmtbx.ions.svm.svm_phil_str +debug = True + .type = bool +elements = Auto + .type = str +use_svm = False + .type = bool +nproc = Auto + .type = int +''' + def exercise(): from mmtbx.regression import make_fake_anomalous_data @@ -124,17 +142,18 @@ def exercise(): selection="element CA", fp=0.0, fdp=0.4)]) - args = [ - file_base + "_in.pdb", - file_base + ".mtz", - "wavelength=0.9792", - "use_phaser=False", - "nproc=1", - "skip_twin_test=True", - "elements=CA", - ] + + dm = DataManager() + m = dm.get_model(file_base + "_in.pdb") + ma = dm.get_miller_arrays(filename = file_base + ".mtz") + fmo = dm.get_fmodel(scattering_table="n_gaussian") + params = iotbx.phil.parse(input_string = water_screen_master_phil, + process_includes=True).extract() + params.use_phaser=False + #params.skip_twin_test=True + params.elements='CA' out = StringIO() - mmtbx.command_line.water_screen.run(args=args, out=out) + results = get_analyze_waters_result(m,fmo,params,out) assert "Valence sum: 1.916" in out.getvalue() assert out.getvalue().count("Probable cation: CA+2") >= 1 os.remove(file_base + ".pdb") @@ -142,6 +161,31 @@ def exercise(): os.remove(file_base + ".mtz") os.remove(file_base + "_fmodel.eff") + +def get_analyze_waters_result(m,fmo,params,out): + m.process(make_restraints=True) + grm = m.get_restraints_manager() + manager = mmtbx.ions.identify.create_manager( + pdb_hierarchy = m.get_hierarchy(), + fmodel = fmo, + geometry_restraints_manager = grm.geometry, + wavelength = 0.9792, + params = params, + log = out, + manager_class = None) + candidates = Auto + from cctbx.eltbx import chemical_elements + lu = chemical_elements.proper_upper_list() + elements = params.elements.replace(",", " ") + candidates = elements.split() + for elem in candidates : + if (elem.upper() not in lu): + raise Sorry("Unrecognized element '%s'" % elem) + results = manager.analyze_waters( + out = out, + candidates = candidates) + return results + if (__name__ == "__main__"): exercise() print("OK") From 1645c825aa7464c72cf8e93f55d7ec6f586ec7e3 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Mon, 15 Apr 2024 11:57:27 -0700 Subject: [PATCH 349/748] Clean clutter. --- mmtbx/ions/tst_symmetry_axis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mmtbx/ions/tst_symmetry_axis.py b/mmtbx/ions/tst_symmetry_axis.py index 83207e3f0b..1dd9f36173 100644 --- a/mmtbx/ions/tst_symmetry_axis.py +++ b/mmtbx/ions/tst_symmetry_axis.py @@ -26,7 +26,6 @@ def exercise(): from mmtbx.regression import make_fake_anomalous_data - import mmtbx.command_line.water_screen import mmtbx.ions.utils pdb_in = """\ CRYST1 51.491 51.491 35.389 90.00 90.00 120.00 P 31 2 1 From 5996cadf381d86d789636edbee43375c090da4b0 Mon Sep 17 00:00:00 2001 From: Pavel Date: Mon, 15 Apr 2024 12:55:30 -0700 Subject: [PATCH 350/748] add option to save SK coordinates --- mmtbx/programs/hbond.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mmtbx/programs/hbond.py b/mmtbx/programs/hbond.py index 97053367c2..fb49f8a0c4 100644 --- a/mmtbx/programs/hbond.py +++ b/mmtbx/programs/hbond.py @@ -34,6 +34,8 @@ class Program(ProgramTemplate): do_y_log = False .type = bool .style = hidden + output_sk_coordinates = False + .type = bool plot_parameters_override .help = These parameters will override preset values in plots. The values \ will be passed directly to matplotlib functions, so should be valid \ @@ -67,7 +69,7 @@ def validate(self): self.data_manager.has_models(raise_sorry=True) # --------------------------------------------------------------------------- - def run(self, save_sk_coordinates=False): + def run(self): print('Using model: %s' % self.data_manager.get_default_model_name(), file=self.logger) inp_models = [] @@ -130,14 +132,14 @@ def run(self, save_sk_coordinates=False): if param_value != None: op[param_name] = param_value - if save_sk_coordinates: + if self.params.output_sk_coordinates: from libtbx import group_args from libtbx import easy_pickle o = group_args( file_names = file_names, theta1_coords = theta1_c, Rha_coords = Rha_c) - easy_pickle.dump(file_name="coords.pkl", obj = o) + easy_pickle.dump(file_name="%s_coords.pkl"%prefix, obj = o) mmtbx.nci.skew_kurt_plot.make_figure( file_name=fn, From 242812a44ba9381a3bc78cdd6b2d615e3e714068 Mon Sep 17 00:00:00 2001 From: Pavel Date: Mon, 15 Apr 2024 13:08:57 -0700 Subject: [PATCH 351/748] bugfix --- mmtbx/programs/hbond.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mmtbx/programs/hbond.py b/mmtbx/programs/hbond.py index fb49f8a0c4..cb0704fa79 100644 --- a/mmtbx/programs/hbond.py +++ b/mmtbx/programs/hbond.py @@ -77,7 +77,7 @@ def run(self): inp_models.append((model_name, self.data_manager.get_model(model_name))) theta1_data = [] Rha_data = [] - if save_sk_coordinates: + if self.params.output_sk_coordinates: file_names = [] for m_name, model in inp_models: model.set_log(log = null_out()) @@ -113,7 +113,7 @@ def run(self): if stats.all.get_counts(min_data_size=min_data_size): theta1_data.append(stats.all.get_counts(min_data_size=min_data_size).theta_1) Rha_data.append( stats.all.get_counts(min_data_size=min_data_size).d_HA) - if save_sk_coordinates: + if self.params.output_sk_coordinates: file_names.append(m_name) if self.params.output_skew_kurtosis_plot and len(theta1_data) > 0 and len(Rha_data) > 0: From 2b80a5b457c076d07c2fa3a7900d3b514b88f272 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Mon, 15 Apr 2024 14:42:48 -0700 Subject: [PATCH 352/748] Tidy-up Phenix: refactor test --- mmtbx/ions/tst_pickle.py | 57 ++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/mmtbx/ions/tst_pickle.py b/mmtbx/ions/tst_pickle.py index fd1cec19ef..9b80eede7a 100644 --- a/mmtbx/ions/tst_pickle.py +++ b/mmtbx/ions/tst_pickle.py @@ -1,60 +1,53 @@ - # -*- coding: utf-8; py-indent-offset: 2 -*- - from __future__ import absolute_import, division, print_function - import os from pickle import loads, dumps from types import MethodType - import libtbx -from mmtbx.command_line.water_screen import master_phil -import mmtbx.command_line from mmtbx import ions from mmtbx.ions import environment from mmtbx.regression.make_fake_anomalous_data import generate_zinc_inputs import mmtbx.utils +import iotbx.phil +from iotbx.data_manager import DataManager def exercise(): wavelength = 1.025 mtz_file, pdb_file = generate_zinc_inputs(anonymize = False) null_out = libtbx.utils.null_out() - cmdline = mmtbx.command_line.load_model_and_data( - args = [pdb_file, mtz_file, "wavelength={}".format(wavelength), - "use_phaser=False"], - master_phil = master_phil(), - out = null_out, - process_pdb_file = True, - create_fmodel = True, - prefer_anomalous = True - ) + dm = DataManager() + m = dm.get_model(pdb_file) + xrs = m.get_xray_structure() + dm.process_miller_array_file(mtz_file) + fmo = dm.get_fmodel(scattering_table="n_gaussian") os.remove(pdb_file) os.remove(mtz_file) - cmdline.xray_structure.set_inelastic_form_factors( - photon = cmdline.params.input.wavelength, - table = "sasaki" - ) + xrs.set_inelastic_form_factors(photon = wavelength, table = "sasaki") - cmdline.fmodel.update_xray_structure( - cmdline.xray_structure, - update_f_calc = True - ) + + fmo.update_xray_structure(xrs, update_f_calc = True) + m.process(make_restraints=True) + + phil_str = ''' +include scope mmtbx.ions.identify.ion_master_phil +include scope mmtbx.ions.svm.svm_phil_str +''' + params = iotbx.phil.parse(input_string = phil_str, + process_includes=True).extract() manager = ions.identify.create_manager( - pdb_hierarchy = cmdline.pdb_hierarchy, - fmodel = cmdline.fmodel, - geometry_restraints_manager = cmdline.geometry, - wavelength = cmdline.params.input.wavelength, - params = cmdline.params, - nproc = cmdline.params.nproc, + pdb_hierarchy = m.get_hierarchy(), + fmodel = fmo, + geometry_restraints_manager = m.get_restraints_manager().geometry, + wavelength = wavelength, + params = params, + nproc = 1, log = null_out ) - manager.validate_ions( - out = null_out - ) + manager.validate_ions(out = null_out) fo_map = manager.get_map("mFo") fofc_map = manager.get_map("mFo-DFc") From cb1642ecbb3f100b96c9b901e93a39360825beab Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Mon, 15 Apr 2024 14:55:00 -0700 Subject: [PATCH 353/748] Tidy-up Phenix: refactor code and test. --- mmtbx/ions/svm/dump_sites.py | 21 ++++++++++++++++++++- mmtbx/ions/svm/tst_classifier.py | 4 ++-- mmtbx/ions/tst_pickle.py | 1 - 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/mmtbx/ions/svm/dump_sites.py b/mmtbx/ions/svm/dump_sites.py index 2a04a8c823..6d8a83c3ad 100644 --- a/mmtbx/ions/svm/dump_sites.py +++ b/mmtbx/ions/svm/dump_sites.py @@ -20,7 +20,26 @@ from mmtbx.ions.identify import WATER_RES_NAMES from mmtbx.ions.svm.utils import iterate_sites from mmtbx.command_line import load_model_and_data -from mmtbx.command_line.water_screen import master_phil +#from mmtbx.command_line.water_screen import master_phil + +def master_phil(): + from mmtbx.command_line import generate_master_phil_with_inputs + return generate_master_phil_with_inputs( + enable_automatic_twin_detection=True, + enable_pdb_interpretation_params=True, + enable_stop_for_unknowns=False, + phil_string=""" +include scope mmtbx.ions.identify.ion_master_phil +include scope mmtbx.ions.svm.svm_phil_str +debug = True + .type = bool +elements = Auto + .type = str +use_svm = False + .type = bool +nproc = Auto + .type = int +""") def _main(args, out=sys.stdout): """ diff --git a/mmtbx/ions/svm/tst_classifier.py b/mmtbx/ions/svm/tst_classifier.py index 55cff25ee1..689598f1d1 100644 --- a/mmtbx/ions/svm/tst_classifier.py +++ b/mmtbx/ions/svm/tst_classifier.py @@ -1,7 +1,7 @@ # -*- coding: utf-8; py-indent-offset: 2 -*- from __future__ import absolute_import, division, print_function -from mmtbx.command_line.water_screen import master_phil +from mmtbx.ions.svm.dump_sites import master_phil from mmtbx.ions.environment import ChemicalEnvironment, ScatteringEnvironment from mmtbx import ions from mmtbx.ions.identify import WATER_RES_NAMES, AtomProperties @@ -114,7 +114,7 @@ def exercise(): warnings.warn("libsvm not available, skipping this test") else : print("WARNING: TEST TOO SLOW. MAKE IT RUN UNDER 300s AND ENABLE BACK.") - if 0: #XXX FIXME disabled + if 1: #XXX FIXME disabled t0 = time.time() exercise() print("Time: %6.2f"%(time.time()-t0)) diff --git a/mmtbx/ions/tst_pickle.py b/mmtbx/ions/tst_pickle.py index 9b80eede7a..d55f8062df 100644 --- a/mmtbx/ions/tst_pickle.py +++ b/mmtbx/ions/tst_pickle.py @@ -26,7 +26,6 @@ def exercise(): xrs.set_inelastic_form_factors(photon = wavelength, table = "sasaki") - fmo.update_xray_structure(xrs, update_f_calc = True) m.process(make_restraints=True) From f0f7d89135f9324bd7dfaf948d041f7b400b8965 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 16 Apr 2024 04:41:01 -0700 Subject: [PATCH 354/748] Fix typo --- mmtbx/validation/holton_geometry_validation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 7779069983..a72aab0a87 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -716,7 +716,7 @@ def get_model(info): if (not info.keep_hydrogens): info.model.add_crystal_symmetry_if_necessary() if info.model.has_hd(): - info.model.remove_hd(reset_i_seq=True) + info.model.get_hierarchy().remove_hd(reset_i_seq=True) info.model.process(make_restraints=True) info.chain_dict = {} for chain_id in info.model.chain_ids(unique_only = True): From ae942b5f528b578187321273237023508c00c83d Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 16 Apr 2024 10:18:51 -0700 Subject: [PATCH 355/748] Tidy-up Phenix: refactor tests --- mmtbx/ions/svm/dump_sites.py | 1 - mmtbx/ions/tst_pick_approx_zn.py | 32 ++++++++++++++------ mmtbx/ions/tst_pick_ca.py | 30 +++++++++++++------ mmtbx/ions/tst_pick_ca_svm.py | 36 ++++++++++++++++++----- mmtbx/ions/tst_pick_k.py | 20 +++++++++++-- mmtbx/ions/tst_pick_mg.py | 26 ++++++++++++----- mmtbx/ions/tst_pickle.py | 1 - mmtbx/ions/tst_symmetry_axis.py | 50 +++++++++++++------------------- mmtbx/ions/tst_validate_ca.py | 2 +- 9 files changed, 130 insertions(+), 68 deletions(-) diff --git a/mmtbx/ions/svm/dump_sites.py b/mmtbx/ions/svm/dump_sites.py index 6d8a83c3ad..968766b400 100644 --- a/mmtbx/ions/svm/dump_sites.py +++ b/mmtbx/ions/svm/dump_sites.py @@ -20,7 +20,6 @@ from mmtbx.ions.identify import WATER_RES_NAMES from mmtbx.ions.svm.utils import iterate_sites from mmtbx.command_line import load_model_and_data -#from mmtbx.command_line.water_screen import master_phil def master_phil(): from mmtbx.command_line import generate_master_phil_with_inputs diff --git a/mmtbx/ions/tst_pick_approx_zn.py b/mmtbx/ions/tst_pick_approx_zn.py index 0cc1a7e5f6..9cb1dbfd3d 100644 --- a/mmtbx/ions/tst_pick_approx_zn.py +++ b/mmtbx/ions/tst_pick_approx_zn.py @@ -1,24 +1,38 @@ from __future__ import absolute_import, division, print_function -import os -from libtbx import easy_run -import time +import os, time +from six.moves import cStringIO as StringIO +from mmtbx.ions.svm.dump_sites import master_phil +from mmtbx.ions.tst_symmetry_axis import get_analyze_waters_result +from iotbx.data_manager import DataManager def exercise(): from mmtbx.regression.make_fake_anomalous_data import generate_zinc_inputs base = "tst_pick_approx_zn" mtz_file, pdb_file = generate_zinc_inputs(file_base=base, anonymize = True) time.sleep(2) - args = ["\"%s\"" % pdb_file, "\"%s\"" % mtz_file, "wavelength=1.54", - "nproc=1", "elements=CA,ZN", "use_phaser=False"] - result = easy_run.fully_buffered("mmtbx.water_screen %s" % " ".join(args) - ).raise_if_errors() + + dm = DataManager() + m = dm.get_model(pdb_file) + dm.process_miller_array_file(mtz_file) + fmo = dm.get_fmodel(scattering_table="n_gaussian") + xrs = m.get_xray_structure() + xrs.set_inelastic_form_factors(photon = 1.54, table = "sasaki") + fmo.update_xray_structure(xrs, update_f_calc = True) + params = master_phil().extract() + params.input.wavelength = 1.54 + params.use_phaser=False + params.elements='CA,ZN' + params.nproc=1 + out = StringIO() + result = get_analyze_waters_result(m,fmo,params,out) + n_zn = 0 - for line in result.stdout_lines: + for line in out.getvalue().splitlines(): if "Probable cation: ZN+2" in line: n_zn += 1 if n_zn != 1: - print("\n".join(result.stdout_lines)) + print(out.getvalue().splitlines()) raise RuntimeError("Expected 1 ZN+2, found %d" % n_zn) os.remove(pdb_file) os.remove(mtz_file) diff --git a/mmtbx/ions/tst_pick_ca.py b/mmtbx/ions/tst_pick_ca.py index 02ffecd1c9..982defec72 100644 --- a/mmtbx/ions/tst_pick_ca.py +++ b/mmtbx/ions/tst_pick_ca.py @@ -1,24 +1,36 @@ from __future__ import absolute_import, division, print_function -import os -from libtbx import easy_run -import time +import os,time +from six.moves import cStringIO as StringIO +from mmtbx.ions.svm.dump_sites import master_phil +from mmtbx.ions.tst_symmetry_axis import get_analyze_waters_result +from iotbx.data_manager import DataManager def exercise(): from mmtbx.regression.make_fake_anomalous_data import generate_calcium_inputs base = "tst_pick_ca" mtz_file, pdb_file = generate_calcium_inputs(file_base=base, anonymize=True) time.sleep(2) - args = ["\"%s\"" % pdb_file, "\"%s\"" % mtz_file, "wavelength=1.1", - "nproc=1", "use_phaser=False", "fpp_ratio_max=1.2"] - result = easy_run.fully_buffered("mmtbx.water_screen %s" % " ".join(args) - ).raise_if_errors() + + wavelength = 1.1 + dm = DataManager() + m = dm.get_model(pdb_file) + dm.process_miller_array_file(mtz_file) + fmo = dm.get_fmodel(scattering_table="n_gaussian") + params = master_phil().extract() + params.input.wavelength = 1.1 + params.phaser.fpp_ratio_max=1.2 + params.use_phaser=False + params.nproc=1 + out = StringIO() + result = get_analyze_waters_result(m,fmo,params,out) + n_ca = 0 - for line in result.stdout_lines: + for line in out.getvalue().splitlines(): if "Probable cation: CA+2" in line: n_ca += 1 if (n_ca != 1): - print("\n".join(result.stdout_lines)) + print(out.getvalue().splitlines()) raise RuntimeError("Expected 1 Ca2+, found %d" % n_ca) os.remove(pdb_file) os.remove(mtz_file) diff --git a/mmtbx/ions/tst_pick_ca_svm.py b/mmtbx/ions/tst_pick_ca_svm.py index 4cc36f1bbb..edd4e99cd2 100644 --- a/mmtbx/ions/tst_pick_ca_svm.py +++ b/mmtbx/ions/tst_pick_ca_svm.py @@ -1,7 +1,11 @@ from __future__ import absolute_import, division, print_function import os -from libtbx import easy_run +from six.moves import cStringIO as StringIO +from mmtbx.ions.svm.dump_sites import master_phil +from mmtbx.ions.tst_symmetry_axis import get_analyze_waters_result +from iotbx.data_manager import DataManager +import mmtbx.ions.svm def exercise(): try : @@ -13,21 +17,39 @@ def exercise(): from mmtbx.regression.make_fake_anomalous_data import generate_calcium_inputs base = "tst_pick_ca_svm" mtz_file, pdb_file = generate_calcium_inputs(file_base=base, anonymize=True) - args = ["\"%s\"" % pdb_file, "\"%s\"" % mtz_file, "wavelength=1.1", - "nproc=1", "use_phaser=False", "use_svm=True", "elements=CA,ZN"] - result = easy_run.fully_buffered("mmtbx.water_screen %s" % " ".join(args) - ).raise_if_errors() + + wavelength = 1.1 + dm = DataManager() + m = dm.get_model(pdb_file) + dm.process_miller_array_file(mtz_file) + fmo = dm.get_fmodel(scattering_table="n_gaussian") + xrs = m.get_xray_structure() + xrs.set_inelastic_form_factors(photon = 1.54, table = "sasaki") + fmo.update_xray_structure(xrs, update_f_calc = True) + params = master_phil().extract() + params.input.wavelength = wavelength + params.use_svm=True + params.elements='CA,ZN' + params.use_phaser=False + params.nproc=1 + manager_class = mmtbx.ions.svm.manager + + out = StringIO() + result = get_analyze_waters_result(m,fmo,params,out, + manager_class = manager_class) + os.remove(pdb_file) os.remove(mtz_file) # "zn_frag_hoh.pdb" => "zn_frag_fmodel.eff" os.remove(os.path.splitext(pdb_file)[0][:-4] + ".pdb") os.remove(os.path.splitext(pdb_file)[0][:-4] + "_fmodel.eff") + n_ca = 0 - for line in result.stdout_lines: + for line in out.getvalue().splitlines(): if ("Final choice: CA" in line): n_ca += 1 if (n_ca != 1): - print("\n".join(result.stdout_lines)) + print(out.getvalue().splitlines()) raise RuntimeError("Expected 1 Ca2+, found %d" % n_ca) print("OK") diff --git a/mmtbx/ions/tst_pick_k.py b/mmtbx/ions/tst_pick_k.py index 645dd6fe85..5e9a99bdeb 100644 --- a/mmtbx/ions/tst_pick_k.py +++ b/mmtbx/ions/tst_pick_k.py @@ -1,17 +1,33 @@ from __future__ import absolute_import, division, print_function -import os +import os, time from libtbx import easy_run -import time +from six.moves import cStringIO as StringIO +from mmtbx.ions.svm.dump_sites import master_phil +from mmtbx.ions.tst_symmetry_axis import get_analyze_waters_result +from iotbx.data_manager import DataManager def exercise(): # FIXME print("Temporarily disabled, skipping") return + # the function below does not exist???? from mmtbx.regression.make_fake_anomalous_data import generate_potassium_inputs base = "tst_pick_k" mtz_file, pdb_file = generate_potassium_inputs(file_base=base, anonymize=True) time.sleep(2) + +# dm = DataManager() +# m = dm.get_model(pdb_file) +# dm.process_miller_array_file(mtz_file) +# fmo = dm.get_fmodel(scattering_table="n_gaussian") +# params = master_phil().extract() +# params.elements='K,MG' +# params.use_phaser=False +# params.nproc=1 +# out = StringIO() +# result = get_analyze_waters_result(m,fmo,params,out) + args = [pdb_file, mtz_file, "nproc=1", "elements=K,MG", "use_phaser=False"] result = easy_run.fully_buffered("mmtbx.water_screen %s" % " ".join(args) ).raise_if_errors() diff --git a/mmtbx/ions/tst_pick_mg.py b/mmtbx/ions/tst_pick_mg.py index c6b5713fe7..26ad19d4e8 100644 --- a/mmtbx/ions/tst_pick_mg.py +++ b/mmtbx/ions/tst_pick_mg.py @@ -1,20 +1,30 @@ from __future__ import absolute_import, division, print_function -import os -from libtbx import easy_run -import time +import os, time +from six.moves import cStringIO as StringIO +from mmtbx.ions.svm.dump_sites import master_phil +from mmtbx.ions.tst_symmetry_axis import get_analyze_waters_result +from iotbx.data_manager import DataManager + def exercise(): from mmtbx.regression.make_fake_anomalous_data import generate_magnessium_inputs base = "tst_pick_mg" mtz_file, pdb_file = generate_magnessium_inputs(file_base=base, anonymize=True) time.sleep(2) - args = [ "\"%s\"" % pdb_file, "\"%s\"" % mtz_file, "nproc=1", - "use_phaser=False", "elements=MG" ] - result = easy_run.fully_buffered("mmtbx.water_screen %s" % " ".join(args) - ).raise_if_errors() + + dm = DataManager() + m = dm.get_model(pdb_file) + dm.process_miller_array_file(mtz_file) + fmo = dm.get_fmodel(scattering_table="n_gaussian") + params = master_phil().extract() + params.use_phaser=False + params.elements='MG' + out = StringIO() + result = get_analyze_waters_result(m,fmo,params,out) + n_mg = 0 - for line in result.stdout_lines : + for line in out.getvalue().splitlines(): if ("Probable cation: MG+2" in line): n_mg += 1 if n_mg != 2: diff --git a/mmtbx/ions/tst_pickle.py b/mmtbx/ions/tst_pickle.py index d55f8062df..017f058d97 100644 --- a/mmtbx/ions/tst_pickle.py +++ b/mmtbx/ions/tst_pickle.py @@ -25,7 +25,6 @@ def exercise(): os.remove(mtz_file) xrs.set_inelastic_form_factors(photon = wavelength, table = "sasaki") - fmo.update_xray_structure(xrs, update_f_calc = True) m.process(make_restraints=True) diff --git a/mmtbx/ions/tst_symmetry_axis.py b/mmtbx/ions/tst_symmetry_axis.py index 1dd9f36173..4fbaa57306 100644 --- a/mmtbx/ions/tst_symmetry_axis.py +++ b/mmtbx/ions/tst_symmetry_axis.py @@ -1,28 +1,14 @@ from __future__ import absolute_import, division, print_function import os +from six.moves import cStringIO as StringIO from libtbx.utils import null_out -from libtbx import group_args +from libtbx import group_args, Auto import iotbx.pdb -from libtbx import Auto -import iotbx.phil -from six.moves import cStringIO as StringIO import mmtbx.ions.identify +from mmtbx.ions.svm.dump_sites import master_phil from iotbx.data_manager import DataManager -water_screen_master_phil = ''' -include scope mmtbx.ions.identify.ion_master_phil -include scope mmtbx.ions.svm.svm_phil_str -debug = True - .type = bool -elements = Auto - .type = str -use_svm = False - .type = bool -nproc = Auto - .type = int -''' - def exercise(): from mmtbx.regression import make_fake_anomalous_data @@ -144,13 +130,13 @@ def exercise(): dm = DataManager() m = dm.get_model(file_base + "_in.pdb") - ma = dm.get_miller_arrays(filename = file_base + ".mtz") + dm.process_miller_array_file(mtz_file) fmo = dm.get_fmodel(scattering_table="n_gaussian") - params = iotbx.phil.parse(input_string = water_screen_master_phil, - process_includes=True).extract() + params = master_phil().extract() params.use_phaser=False #params.skip_twin_test=True params.elements='CA' + params.input.wavelength = 0.9792 out = StringIO() results = get_analyze_waters_result(m,fmo,params,out) assert "Valence sum: 1.916" in out.getvalue() @@ -161,28 +147,32 @@ def exercise(): os.remove(file_base + "_fmodel.eff") -def get_analyze_waters_result(m,fmo,params,out): +def get_analyze_waters_result(m,fmo,params,out,manager_class = None): m.process(make_restraints=True) grm = m.get_restraints_manager() manager = mmtbx.ions.identify.create_manager( pdb_hierarchy = m.get_hierarchy(), fmodel = fmo, geometry_restraints_manager = grm.geometry, - wavelength = 0.9792, + wavelength = params.input.wavelength, params = params, + nproc = params.nproc, log = out, - manager_class = None) + manager_class = manager_class) candidates = Auto - from cctbx.eltbx import chemical_elements - lu = chemical_elements.proper_upper_list() - elements = params.elements.replace(",", " ") - candidates = elements.split() - for elem in candidates : - if (elem.upper() not in lu): - raise Sorry("Unrecognized element '%s'" % elem) + if (params.elements is not Auto) and (params.elements is not None): + from cctbx.eltbx import chemical_elements + lu = chemical_elements.proper_upper_list() + elements = params.elements.replace(",", " ") + candidates = elements.split() + for elem in candidates : + if (elem.upper() not in lu): + raise Sorry("Unrecognized element '%s'" % elem) + results = manager.analyze_waters( out = out, candidates = candidates) + return results if (__name__ == "__main__"): diff --git a/mmtbx/ions/tst_validate_ca.py b/mmtbx/ions/tst_validate_ca.py index 8689e327e5..6105cf0acc 100644 --- a/mmtbx/ions/tst_validate_ca.py +++ b/mmtbx/ions/tst_validate_ca.py @@ -15,7 +15,7 @@ def exercise(): m = dm.get_model(pdb_file) m.process(make_restraints=True) grm = m.get_restraints_manager() - ma = dm.get_miller_arrays(filename = mtz_file) + dm.process_miller_array_file(mtz_file) fmo = dm.get_fmodel(scattering_table="n_gaussian") from mmtbx.ions.identify import ion_identification_phil_str params = iotbx.phil.parse(input_string = ion_identification_phil_str).extract() From 922988aa061971010607a1a9a05975974cd083dc Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 16 Apr 2024 10:38:19 -0700 Subject: [PATCH 356/748] Tidy-up Phenix: remove mmtbx/command_line/water_screen.py. --- mmtbx/command_line/water_screen.py | 85 ------------------------------ 1 file changed, 85 deletions(-) delete mode 100644 mmtbx/command_line/water_screen.py diff --git a/mmtbx/command_line/water_screen.py b/mmtbx/command_line/water_screen.py deleted file mode 100644 index d7506e0334..0000000000 --- a/mmtbx/command_line/water_screen.py +++ /dev/null @@ -1,85 +0,0 @@ - -from __future__ import absolute_import, division, print_function -from libtbx.str_utils import make_header -from libtbx.utils import Sorry -from libtbx import Auto -import sys - -def master_phil(): - from mmtbx.command_line import generate_master_phil_with_inputs - return generate_master_phil_with_inputs( - enable_automatic_twin_detection=True, - enable_pdb_interpretation_params=True, - enable_stop_for_unknowns=False, - phil_string=""" -include scope mmtbx.ions.identify.ion_master_phil -include scope mmtbx.ions.svm.svm_phil_str -debug = True - .type = bool -elements = Auto - .type = str -use_svm = False - .type = bool -nproc = Auto - .type = int -""") - -def run(args, out=sys.stdout): - usage_string = """ -mmtbx.water_screen model.pdb data.mtz [options ...] - -Utility to flag waters that may actually be elemental ions, based on local -environment, electron density maps, and atomic properties. -""" - import mmtbx.ions.identify - import mmtbx.command_line - cmdline = mmtbx.command_line.load_model_and_data( - args=args, - master_phil=master_phil(), - out=out, - process_pdb_file=True, - set_wavelength_from_model_header=True, - set_inelastic_form_factors="sasaki", - create_fmodel=True, - prefer_anomalous=True) - fmodel = cmdline.fmodel - xray_structure = cmdline.xray_structure - params = cmdline.params - if (params.use_svm): - if (params.elements is Auto): - raise Sorry("You must specify elements to consider when using the SVM "+ - "prediction method.") - pdb_hierarchy = cmdline.pdb_hierarchy - geometry = cmdline.geometry - make_header("Inspecting water molecules", out=out) - manager_class = None - if (params.use_svm): - manager_class = mmtbx.ions.svm.manager - manager = mmtbx.ions.identify.create_manager( - pdb_hierarchy = pdb_hierarchy, - fmodel = fmodel, - geometry_restraints_manager = geometry, - wavelength = params.input.wavelength, - params = params, - verbose = params.debug, - nproc = params.nproc, - log = out, - manager_class = manager_class) - manager.show_current_scattering_statistics(out=out) - candidates = Auto - if (params.elements is not Auto) and (params.elements is not None): - from cctbx.eltbx import chemical_elements - lu = chemical_elements.proper_upper_list() - elements = params.elements.replace(",", " ") - candidates = elements.split() - for elem in candidates : - if (elem.upper() not in lu): - raise Sorry("Unrecognized element '%s'" % elem) - results = manager.analyze_waters( - out = out, - debug = params.debug, - candidates = candidates) - return results, pdb_hierarchy - -if (__name__ == "__main__"): - run(sys.argv[1:]) From 4381b35adee251493c5f7d1611b7af0fd6d42f25 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 16 Apr 2024 10:46:19 -0700 Subject: [PATCH 357/748] rename dispatcher --- mmtbx/command_line/validate_ligands.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/command_line/validate_ligands.py b/mmtbx/command_line/validate_ligands.py index da48396906..b63d806355 100644 --- a/mmtbx/command_line/validate_ligands.py +++ b/mmtbx/command_line/validate_ligands.py @@ -1,5 +1,5 @@ from __future__ import absolute_import, division, print_function - +# LIBTBX_SET_DISPATCHER_NAME mmtbx.development.validate_ligands from iotbx.cli_parser import run_program from mmtbx.programs import validate_ligands From 54643b8351c11ed9fadc9c8b65c43dddfeb14859 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 16 Apr 2024 11:40:12 -0700 Subject: [PATCH 358/748] Tidy-up Phenix: Fix mmtbx/command-line/matthews.py. --- mmtbx/command_line/matthews.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/mmtbx/command_line/matthews.py b/mmtbx/command_line/matthews.py index 7884778225..9c70bc2300 100644 --- a/mmtbx/command_line/matthews.py +++ b/mmtbx/command_line/matthews.py @@ -1,13 +1,11 @@ -# TODO tests - from __future__ import absolute_import, division, print_function +import sys from iotbx import crystal_symmetry_from_any import iotbx.bioinformatics -import iotbx.phil from cctbx import crystal from libtbx.utils import Sorry -import sys +import iotbx.phil master_phil_str = """ data = None @@ -31,6 +29,8 @@ """ def run(args, out=sys.stdout): + import iotbx.phil + # this crashes without the import being on the previous line. why? cmdline = iotbx.phil.process_command_line_with_files( args=args, master_phil_string=master_phil_str, @@ -91,12 +91,13 @@ def run(args, out=sys.stdout): params.n_bases += chain.residue_groups_size() print("Space group: %s" % params.space_group, file=out) print("Unit cell: %s" % params.unit_cell, file=out) - if (params.n_residues > 0): + if (params.n_residues is not None): print("Number of residues: %d" % params.n_residues, file=out) - if (params.n_bases > 0): + if (params.n_bases is not None): print("Number of bases: %d" % params.n_bases, file=out) + symm = crystal.symmetry( - space_group_info=params.space_group, + space_group_info=params.space_group.info(), unit_cell=params.unit_cell) from mmtbx.scaling import matthews result = matthews.matthews_rupp( From c08b89ff22b70ea1bfd9377b4805e30802a4b9c8 Mon Sep 17 00:00:00 2001 From: Ben Williams Date: Wed, 17 Apr 2024 12:00:52 +0100 Subject: [PATCH 359/748] MMTBX: remove comparison of int with NoneType (#969) * Do not compare NoneType to int If twin_results_interpretation is instantiated with translational_pseudo_symmetry is None, then self.patterson_height is also None. Therefore do not try to compare self.patterson_height to an integer unless we know it has a numeric value. * Again, do not compare NoneType to int self.low_resolution_completeness_overall is initially given the value None and only conditionally given a numeric value. We should not compare self.low_resolution_completeness_overall to a numeric value if it is None. --- mmtbx/scaling/data_statistics.py | 4 ++-- mmtbx/scaling/twin_analyses.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mmtbx/scaling/data_statistics.py b/mmtbx/scaling/data_statistics.py index 30b07a3c10..1b3851e7b6 100644 --- a/mmtbx/scaling/data_statistics.py +++ b/mmtbx/scaling/data_statistics.py @@ -862,10 +862,10 @@ def summarize_issues(self): issues.append((0, "The resolution cutoff appears to be similar in all directions.", "Analysis of resolution limits")) - if (0 < self.low_resolution_completeness_overall < 0.75): + if self.low_resolution_completeness_overall and 0 < self.low_resolution_completeness_overall < 0.75: issues.append((2, "The overall completeness in low-resolution shells "+ "is less than 90%.", "Low resolution completeness analyses")) - elif (0.75 <= self.low_resolution_completeness_overall < 0.9): + elif self.low_resolution_completeness_overall and 0.75 <= self.low_resolution_completeness_overall < 0.9: issues.append((1, "The overall completeness in low-resolution shells "+ "is less than 90%.", "Low resolution completeness analyses")) else : diff --git a/mmtbx/scaling/twin_analyses.py b/mmtbx/scaling/twin_analyses.py index 20a765c5c7..ff14141534 100644 --- a/mmtbx/scaling/twin_analyses.py +++ b/mmtbx/scaling/twin_analyses.py @@ -2198,11 +2198,11 @@ def summarize_issues(self): "data has a higher "+ "crystallographic symmetry (%s)." % str(self.suspected_point_group), "Point group and R-factor analysis")) - if (self.patterson_height > 75): + if self.patterson_height and self.patterson_height > 75: issues.append((2, "Translational NCS is present at a level that might "+ "be a result of a missed centering operation (one or more peaks "+ "greater than 75% of the origin).", "Patterson analyses")) - elif (self.patterson_height > 20): + elif self.patterson_height and self.patterson_height > 20: issues.append((2, "Translational NCS is present at a level that may "+ "complicate refinement (one or more peaks greater than 20% of the "+ "origin)", "Patterson analyses")) From 76bc51517707bf0883fa88b2d7709456d17aab44 Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 17 Apr 2024 10:48:08 -0600 Subject: [PATCH 360/748] Catch None --- mmtbx/validation/holton_geometry_validation.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index a72aab0a87..328d90ea78 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -620,6 +620,10 @@ def get_geometry_results(info): 'planarity_proxies': 'PLANE',} geometry_results = {} info.geometry_results = geometry_results + for key in name_dict.keys(): + geometry_results[key] = group_args(group_args_type = '%s result' %(key), + name = key, + value_list = []) # Non-bonded if pair_proxies.nonbonded_proxies is not None: From 68206dea28cea4ceda6ec2b9848107550676c249 Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Wed, 17 Apr 2024 13:20:20 -0700 Subject: [PATCH 361/748] Make sure all output goes to logs --- .../geometry_restraints/torsion_restraints/reference_model.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mmtbx/geometry_restraints/torsion_restraints/reference_model.py b/mmtbx/geometry_restraints/torsion_restraints/reference_model.py index 766041becf..3f6fa1d3f1 100644 --- a/mmtbx/geometry_restraints/torsion_restraints/reference_model.py +++ b/mmtbx/geometry_restraints/torsion_restraints/reference_model.py @@ -172,6 +172,7 @@ def __init__(self, reference_file_list].count(None) == 1 if(log is None): log = sys.stdout + self.log=log # self.model = model self.params = params self.selection = selection @@ -285,7 +286,8 @@ def _make_matching_and_fill_dictionaries(self, model_h, ref_h, fn, # combined_h.write_pdb_file(fn+"_combined.pdb") ncs_obj = iotbx.ncs.input( hierarchy=temp_h, - params = self.params.search_options) + params = self.params.search_options, + log = self.log) # For each found NCS group we going to do matching procedure between # copies for group_list in ncs_obj.get_ncs_restraints_group_list(): From 9f226d33d2028767f72584f54348e252bb719449 Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 17 Apr 2024 15:15:21 -0600 Subject: [PATCH 362/748] Clean up output --- .../validation/holton_geometry_validation.py | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 328d90ea78..6591e2d671 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -167,7 +167,7 @@ def add_clashscore_results(info): v = group_args(group_args_type = 'clashscore result as standard value ', clashscore_result = r, # contains all results - as_string = "CLASH %.4f %.3f | %s - %s " %( + as_string = "CLASH: Energy = %.4f dev = %.3f \n Atom 1: %s \n Atom 2: %s " %( tuple([energy, delta] + [l.as_string() for l in labels])), resseq = None, delta = delta, @@ -202,8 +202,8 @@ def add_rotamer_results(info): energy = min(energy, info.rotalyze_max_energy) v = group_args(group_args_type = 'rotamer result as standard value ', rotamer_result = r, # contains resseq, resseq_as_int, resname, chain_id - as_string = "ROTA %.4f %s | %.2f %s %s %s %s" %( - energy, r.resseq, r.score, r.altloc, r.resname, r.chain_id, r.resseq), + as_string = "ROTA: Energy = %.4f \n Residue: %s %s %s %s" %( + energy, r.altloc, r.resname, r.chain_id, r.resseq), resseq= r.resseq, delta = None, residual = energy, @@ -230,8 +230,8 @@ def add_rama_results(info): energy = energy_from_probability(prob) v = group_args(group_args_type = 'rama result as standard value ', rama_result = r, # contains resseq, resseq_as_int, resname, chain_id - as_string = "RAMA %.4f %s | %.2f %s %s %s %s" %( - energy, r.resseq, r.score, r.altloc, r.resname, r.chain_id, r.resseq), + as_string = "RAMA: Energy = %.4f \n Residue: %s %s %s %s" %( + energy, r.altloc, r.resname, r.chain_id, r.resseq), resseq= r.resseq, delta = None, residual = energy, @@ -258,8 +258,9 @@ def add_cbetadev_results(info): energy = (delta/info.cbetadev_sigma)**2 v = group_args(group_args_type = 'cbetadev result as standard value ', cbetadev_result = r, # contains resseq, resseq_as_int, resname, chain_id - as_string = "CBETADEV %.4f %s | %s %s %s %s" %( - energy, r.resseq, r.altloc, r.resname, r.chain_id, r.resseq), + as_string = + "CBETADEV: Energy = %.4f dev = %.3f A \n Residue: %s %s %s %s" %( + energy, r.deviation, r.altloc, r.resname, r.chain_id, r.resseq), resseq= r.resseq, delta = r.deviation, residual = energy, @@ -452,7 +453,7 @@ def print_results(info): info.result_table = {} info.result_header_row = [ 'Category','N','Mean','Worst','Chisq','Pnna','Energy','Using mean'] - fmt = len(info.result_header_row) * " %8s " + fmt = len(info.result_header_row) * "%8s " print(file = info.log) print(fmt %(tuple(info.result_header_row)), file = info.log) print(file = info.log) @@ -481,7 +482,7 @@ def print_results(info): file = info.log) info.worst_table = {} - info.worst_header_row = ['Worst in each category'] + info.worst_header_row = [' ----- Worst deviation in each category -----'] fmt = "%s" print(file = info.log) print(fmt %(tuple(info.worst_header_row)), file = info.log) @@ -589,9 +590,11 @@ def add_omega_results(info): sigma = float("%.3f" %(sigma)) new_v.residual=((math.sin(omega)/sigma)**2+ (1+math.cos(omega))**10)/(n_pro+1) - new_v.as_string = "OMEGA %.6f %s %s %.2f | %s" %( - new_v.residual, resseq, new_v.n_pro, new_v.model, - new_v.labels[0].as_string()) + at = new_v.labels[0].atom + new_v.as_string = "OMEGA: Energy = "+\ + "%.6f (%s Proline) Angle: %.2f deg\n Residue: %s %s %s %s" %( + new_v.residual, new_v.n_pro, new_v.model, + at.altloc, at.resname, at.chain_id, at.resseq) if info.ignore_cis_peptides and math.cos(omega) > 0: continue # skip it omega_result.value_list.append(new_v) @@ -644,7 +647,7 @@ def get_geometry_results(info): round_numbers = info.round_numbers) v.delta = v.ideal - v.model v.group_args_type += " residual is LJ(model, ideal)" - v.as_string = "NONBOND %.6f %.3f %.3f %.3f 1 | %s - %s" %( + v.as_string = "NONBOND: Energy = %.6f dev = %.3f A obs = %.3f target = %.3f\n Atom 1: %s\n Atom 2: %s" %( v.residual, v.delta, v.model, v.ideal, v.labels[0].as_string(), v.labels[1].as_string()) geometry_results[proxy_name] = result @@ -669,26 +672,27 @@ def get_geometry_results(info): geometry_results[proxy_name] = result if result.group_args_type == 'Bond restraints': for v in result.value_list: - v.as_string = "BOND %.2f %.3f %.3f %.3f %.2f | %s - %s " %( + v.as_string = "BOND: Energy = %.2f dev = %.3f A obs = %.3f target = %.3f sigma = %.2f\n Atom 1: %s\n Atom 2: %s " %( v.residual, v.delta, v.model, v.ideal, v.sigma, v.labels[0].as_string(), v.labels[1].as_string()) elif result.group_args_type == 'Bond angle restraints': for v in result.value_list: - v.as_string = "ANGLE %.2f %.2f %.2f %.2f %.1f | %s - %s - %s " %( + v.as_string = "ANGLE: Energy = "+\ + "%.2f dev = %.2f deg obs = %.2f target = %.2f sigma = %.1f\n Atom 1: %s\n Atom 2: %s\n Atom 3: %s " %( v.residual, v.delta, v.model, v.ideal, v.sigma, v.labels[0].as_string(), v.labels[1].as_string(), v.labels[2].as_string()) elif result.group_args_type == 'Dihedral angle restraints': for v in result.value_list: v.as_string = \ - "TORSION %.4f %.2f %.2f %.2f %.1f | %s - %s - %s - %s" %( + "TORSION: Energy = %.4f dev = %.1f deg obs = %.1f target = %.0f sigma = %.1f\n Atom 1: %s\n Atom 2: %s\n Atom 3: %s\n Atom 4: %s" %( v.residual, v.delta, v.model, v.ideal, v.sigma, v.labels[0].as_string(), v.labels[1].as_string(), v.labels[2].as_string(), v.labels[3].as_string()) elif result.group_args_type == 'Chirality restraints': for v in result.value_list: v.as_string = \ - "CHIR %.3f %.2f %.2f %.2f %.1f | %s - %s - %s - %s" %( + "CHIR: Energy = %.3f delta = %.2f A**3 obs = %.2f target = %.2f sigma = %.1f\n Atom 1: %s\n Atom 2: %s\n Atom 3: %s\n Atom 4: %s" %( v.residual, v.delta, v.model, v.ideal, v.sigma, v.labels[0].as_string(), v.labels[1].as_string(), v.labels[2].as_string(), v.labels[3].as_string()) @@ -697,9 +701,12 @@ def get_geometry_results(info): v.residual = energy(v.delta, v.sigma, round_numbers = info.round_numbers) v.as_string = \ - "PLANE %.4f %.3f %.3f %.0f %.2f | %s" %( - v.residual, -v.delta, v.delta, 0, v.sigma, - v.labels[0].as_string()) + "PLANE: Energy = %.4f dev = %.3f A sigma = %.2f" %( + v.residual, -v.delta, v.sigma) + i_at = 0 + for x in v.labels: + i_at += 1 + v.as_string += "\n Atom %s: %s" %(i_at, x.as_string()) for key in name_dict.keys(): geometry_results[key].name = name_dict[key] From 2dd676024f07f91f6e03ddfdeb5e5b3bc188851d Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 17 Apr 2024 16:26:46 -0700 Subject: [PATCH 363/748] Reduce2: rename only AA with v3 names --- mmtbx/hydrogens/reduce_hydrogen.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index 75fafb0d5f..f11a8a9352 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -254,6 +254,8 @@ def run(self): restraint_objects = ro, log = null_out()) self.model.process(pdb_interpretation_params=p, make_restraints=True) + #self.model.idealize_h_minimization() + #STOP() self.time_make_grm = round(time.time()-t0, 2) #f = open("intermediate3.pdb","w") @@ -345,6 +347,7 @@ def place_n_terminal_propeller(self, pdb_hierarchy): elif (self.n_terminal_charge == 'first_in_chain'): pass for ag in rgs.atom_groups(): + #if ag.resname == 'AYA': return if (get_class(name=ag.resname) in ['common_amino_acid', 'modified_amino_acid', 'd_amino_acid']): if ag.get_atom('H'): @@ -396,18 +399,25 @@ def add_missing_H_atoms_at_bogus_position(self): self.no_H_placed_mlq.append(ag.resname) continue - expected_h = list() + expected_h = [] + #expected_ha = [] atom_dict = mlq.atom_dict() for k, v in six.iteritems(atom_dict): if(v.type_symbol=="H"): expected_h.append(k) + #else: + # expected_ha.append(k) # TODO start: temporary fix until v3 names are in mon lib - for altname in alternative_names: - if (altname[0] in expected_h and altname[1] in expected_h): - if (atom_dict[altname[0]].type_energy == 'HCH2' and - atom_dict[altname[1]].type_energy == 'HCH2'): - expected_h.append(altname[2]) - expected_h.remove(altname[0]) + #print('expected H', expected_h) + if (get_class(name=ag.resname) in + ['common_amino_acid', 'modified_amino_acid', 'd_amino_acid']): + for altname in alternative_names: + if (altname[0] in expected_h and altname[1] in expected_h): + if (atom_dict[altname[0]].type_energy == 'HCH2' and + atom_dict[altname[1]].type_energy == 'HCH2'): + expected_h.append(altname[2]) + expected_h.remove(altname[0]) + #print('renamed %s to %s' % (altname[0], altname[2])) # TODO end missing_h = list(set(expected_h).difference(set(actual))) if 0: print(ag.resname, missing_h) @@ -420,6 +430,7 @@ def add_missing_H_atoms_at_bogus_position(self): segid = ag.atoms()[0].segid for mh in missing_h: + #if ag.resname == 'PTR' and mh == 'HN2': continue # TODO: this should be probably in a central place # NWM: I have something like this in ready_set_utils if len(mh) < 4: mh = (' ' + mh).ljust(4) From ff63b66d809e5c91aa60ebe366be275f38260155 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 18 Apr 2024 09:46:29 -0700 Subject: [PATCH 364/748] Reduce 2: Bugfix. Don't rename ligand atoms from v2-v3. Then these H atoms are considered missing. pH dependend restraints will kick in and make nonsensical restraints. Maybe this only happens for ligands in alt conf. --- mmtbx/hydrogens/tst_add_hydrogen.py | 5 +- mmtbx/hydrogens/tst_add_hydrogen_3.py | 141 ++++++++++++++++++++++++++ 2 files changed, 145 insertions(+), 1 deletion(-) diff --git a/mmtbx/hydrogens/tst_add_hydrogen.py b/mmtbx/hydrogens/tst_add_hydrogen.py index 97cbf0c7f2..738c3abb11 100644 --- a/mmtbx/hydrogens/tst_add_hydrogen.py +++ b/mmtbx/hydrogens/tst_add_hydrogen.py @@ -50,7 +50,10 @@ def compare_models(pdb_str, #model_h_added = reduce.add(model = model_without_h) # place H atoms again reduce_add_h_obj = reduce_hydrogen.place_hydrogens(model = model_without_h) - reduce_add_h_obj.run() + try: + reduce_add_h_obj.run() + except Exception as e: + assert 0 # model_h_added = reduce_add_h_obj.get_model() hd_sel_h_added = model_h_added.get_hd_selection() diff --git a/mmtbx/hydrogens/tst_add_hydrogen_3.py b/mmtbx/hydrogens/tst_add_hydrogen_3.py index 143fcf64a0..909cb96d6c 100644 --- a/mmtbx/hydrogens/tst_add_hydrogen_3.py +++ b/mmtbx/hydrogens/tst_add_hydrogen_3.py @@ -15,6 +15,7 @@ def run(): test_003() test_004() test_005() + test_006() # ------------------------------------------------------------------------------ @@ -128,6 +129,17 @@ def test_005(): # ------------------------------------------------------------------------------ +def test_006(): + ''' + Ligand in double conformation. If atom v3 naming is not restricted to aa's, + then two atoms in the ligand will be renamed, leading to seemingly missing + atoms; then pH dependent restraints kick in and they will create + nonsensical restraints involving A and B conformers, which throws off riding H. + ''' + compare_models(pdb_str = pdb_str_006) + +# ------------------------------------------------------------------------------ + pdb_str_000 = """ REMARK Make sure reduce does not crash for single_atom_residue models CRYST1 22.029 33.502 24.035 90.00 90.00 90.00 P 1 @@ -598,6 +610,135 @@ def test_005(): END """ +pdb_str_006 = ''' +CRYST1 56.620 56.620 181.790 90.00 90.00 90.00 P 41 21 2 +SCALE1 0.017662 0.000000 0.000000 0.00000 +SCALE2 0.000000 0.017662 0.000000 0.00000 +SCALE3 0.000000 0.000000 0.005501 0.00000 +HETATM 1 CB1ACNZ A 301 21.699 31.831 83.042 0.42 31.90 C +HETATM 2 CB2ACNZ A 301 20.840 35.774 78.508 0.42 36.67 C +HETATM 3 CG1ACNZ A 301 20.748 32.695 82.223 0.42 32.30 C +HETATM 4 SG2ACNZ A 301 21.831 34.484 77.712 0.42 38.01 S +HETATM 5 CD1ACNZ A 301 21.433 33.671 81.296 0.42 32.98 C +HETATM 6 OE1ACNZ A 301 22.657 33.747 81.222 0.42 32.67 O +HETATM 7 C1 ACNZ A 301 20.264 29.771 83.305 0.42 30.73 C +HETATM 8 C13ACNZ A 301 23.480 35.240 77.602 0.42 38.76 C +HETATM 9 C14ACNZ A 301 24.306 34.544 76.542 0.42 39.44 C +HETATM 10 C2 ACNZ A 301 20.164 36.824 80.647 0.42 35.25 C +HETATM 11 C3 ACNZ A 301 20.811 40.295 81.232 0.42 36.72 C +HETATM 12 CA1ACNZ A 301 20.988 30.898 84.024 0.42 31.32 C +HETATM 13 CA2ACNZ A 301 21.019 35.721 80.028 0.42 35.21 C +HETATM 14 CA3ACNZ A 301 20.125 39.024 81.660 0.42 36.22 C +HETATM 15 CB4ACNZ A 301 30.740 35.079 78.050 0.42 38.90 C +HETATM 16 CB5ACNZ A 301 27.945 33.837 75.863 0.42 38.95 C +HETATM 17 CD4ACNZ A 301 32.849 34.182 77.341 0.42 38.95 C +HETATM 18 CD5ACNZ A 301 25.785 34.478 76.724 0.42 39.23 C +HETATM 19 CE4ACNZ A 301 32.199 33.407 76.406 0.42 38.70 C +HETATM 20 CE5ACNZ A 301 26.419 34.990 77.854 0.42 39.19 C +HETATM 21 CG4ACNZ A 301 32.120 35.018 78.161 0.42 39.01 C +HETATM 22 CG5ACNZ A 301 26.569 33.894 75.734 0.42 39.12 C +HETATM 23 CH4ACNZ A 301 30.067 34.300 77.110 0.42 38.71 C +HETATM 24 CH5ACNZ A 301 28.589 34.355 76.985 0.42 38.89 C +HETATM 25 CZ4ACNZ A 301 30.821 33.462 76.288 0.42 38.64 C +HETATM 26 CZ5ACNZ A 301 27.797 34.927 77.981 0.42 39.11 C +HETATM 27 N1 ACNZ A 301 21.971 30.290 84.963 0.42 31.34 N +HETATM 28 N2 ACNZ A 301 20.617 34.430 80.560 0.42 33.98 N +HETATM 29 N3 ACNZ A 301 20.820 37.838 81.211 0.42 35.82 N +HETATM 30 O11ACNZ A 301 18.995 30.026 83.078 0.42 30.27 O +HETATM 31 O12ACNZ A 301 20.816 28.737 83.002 0.42 30.57 O +HETATM 32 O2 ACNZ A 301 18.939 36.766 80.595 0.42 34.92 O +HETATM 33 O31ACNZ A 301 21.252 40.487 80.111 0.42 36.85 O +HETATM 34 O32ACNZ A 301 20.885 41.163 82.211 0.42 36.84 O +HETATM 35 O5 ACNZ A 301 23.775 34.065 75.554 0.42 39.70 O +HETATM 36 H1 ACNZ A 301 22.793 30.250 84.624 0.42 31.34 H +HETATM 37 H2 ACNZ A 301 19.822 34.147 80.392 0.42 33.98 H +HETATM 38 H3 ACNZ A 301 21.672 37.827 81.328 0.42 35.82 H +HETATM 39 HA1ACNZ A 301 20.347 31.361 84.585 0.42 31.32 H +HETATM 40 HA2ACNZ A 301 21.958 35.873 80.218 0.42 35.21 H +HETATM 41 HA31ACNZ A 301 20.051 39.024 82.627 0.42 36.22 H +HETATM 42 HA32ACNZ A 301 19.218 39.033 81.316 0.42 36.22 H +HETATM 43 HB11ACNZ A 301 22.306 32.400 83.541 0.42 31.90 H +HETATM 44 HB12ACNZ A 301 22.245 31.294 82.446 0.42 31.90 H +HETATM 45 HB21ACNZ A 301 21.113 36.646 78.181 0.42 36.67 H +HETATM 46 HB22ACNZ A 301 19.903 35.650 78.289 0.42 36.67 H +HETATM 47 HG11ACNZ A 301 20.164 33.218 82.794 0.42 32.30 H +HETATM 48 HG12ACNZ A 301 20.163 32.153 81.671 0.42 32.30 H +HETATM 49 HB4ACNZ A 301 30.261 35.647 78.610 0.42 38.90 H +HETATM 50 HB5ACNZ A 301 28.443 33.444 75.183 0.42 38.95 H +HETATM 51 HD4ACNZ A 301 33.775 34.142 77.419 0.42 38.95 H +HETATM 52 HE4ACNZ A 301 32.685 32.843 75.849 0.42 38.70 H +HETATM 53 HE5ACNZ A 301 25.931 35.382 78.542 0.42 39.19 H +HETATM 54 HG4ACNZ A 301 32.553 35.545 78.793 0.42 39.01 H +HETATM 55 HG5ACNZ A 301 26.167 33.537 74.975 0.42 39.12 H +HETATM 56 HZ4ACNZ A 301 30.397 32.932 75.652 0.42 38.64 H +HETATM 57 HZ5ACNZ A 301 28.195 35.274 78.747 0.42 39.11 H +HETATM 58 H11NACNZ A 301 22.044 30.742 85.726 0.42 31.34 H +HETATM 59 H12NACNZ A 301 21.760 29.456 85.192 0.42 31.34 H +HETATM 60 H131ACNZ A 301 23.934 35.181 78.457 0.42 38.76 H +HETATM 61 H132ACNZ A 301 23.403 36.183 77.386 0.42 38.76 H +HETATM 62 CB1BCNZ A 301 21.628 31.747 83.072 0.58 24.44 C +HETATM 63 CB2BCNZ A 301 20.928 35.615 78.523 0.58 32.96 C +HETATM 64 CG1BCNZ A 301 20.751 32.485 82.072 0.58 25.13 C +HETATM 65 SG2BCNZ A 301 21.870 34.251 77.786 0.58 35.21 S +HETATM 66 CD1BCNZ A 301 21.399 33.719 81.489 0.58 26.54 C +HETATM 67 OE1BCNZ A 301 22.558 34.030 81.757 0.58 26.24 O +HETATM 68 C1 BCNZ A 301 20.084 29.772 83.397 0.58 21.85 C +HETATM 69 C13BCNZ A 301 23.611 34.725 78.008 0.58 36.08 C +HETATM 70 C14BCNZ A 301 24.428 34.553 76.745 0.58 36.66 C +HETATM 71 C2 BCNZ A 301 20.268 36.859 80.558 0.58 31.00 C +HETATM 72 C3 BCNZ A 301 20.953 40.442 81.245 0.58 35.20 C +HETATM 73 CA1BCNZ A 301 20.838 30.909 84.075 0.58 23.32 C +HETATM 74 CA2BCNZ A 301 21.083 35.672 80.046 0.58 30.56 C +HETATM 75 CA3BCNZ A 301 20.362 39.080 81.531 0.58 33.89 C +HETATM 76 CB4BCNZ A 301 29.376 30.173 77.597 0.58 27.67 C +HETATM 77 CB5BCNZ A 301 26.920 32.007 75.501 0.58 33.10 C +HETATM 78 CD4BCNZ A 301 30.221 28.218 76.489 0.58 26.53 C +HETATM 79 CD5BCNZ A 301 25.519 33.534 76.736 0.58 35.16 C +HETATM 80 CE4BCNZ A 301 29.225 28.329 75.545 0.58 26.68 C +HETATM 81 CE5BCNZ A 301 26.041 33.009 77.917 0.58 34.37 C +HETATM 82 CG4BCNZ A 301 30.291 29.135 77.520 0.58 26.89 C +HETATM 83 CG5BCNZ A 301 25.993 33.034 75.528 0.58 34.22 C +HETATM 84 CH4BCNZ A 301 28.371 30.309 76.639 0.58 28.91 C +HETATM 85 CH5BCNZ A 301 27.424 31.454 76.677 0.58 31.80 C +HETATM 86 CZ4BCNZ A 301 28.306 29.363 75.614 0.58 27.81 C +HETATM 87 CZ5BCNZ A 301 26.976 31.988 77.885 0.58 33.11 C +HETATM 88 N1 BCNZ A 301 21.748 30.353 85.116 0.58 23.71 N +HETATM 89 N2 BCNZ A 301 20.625 34.442 80.675 0.58 28.24 N +HETATM 90 N3 BCNZ A 301 20.934 38.001 80.752 0.58 32.37 N +HETATM 91 O11BCNZ A 301 20.774 28.662 83.286 0.58 21.59 O +HETATM 92 O12BCNZ A 301 18.936 29.904 82.989 0.58 20.54 O +HETATM 93 O2 BCNZ A 301 19.059 36.753 80.739 0.58 30.28 O +HETATM 94 O31BCNZ A 301 20.309 41.472 81.325 0.58 35.67 O +HETATM 95 O32BCNZ A 301 22.229 40.420 80.923 0.58 35.87 O +HETATM 96 O5 BCNZ A 301 24.172 35.209 75.746 0.58 37.96 O +HETATM 97 H1 BCNZ A 301 22.583 30.252 84.826 0.58 23.71 H +HETATM 98 H2 BCNZ A 301 19.824 34.173 80.514 0.58 28.24 H +HETATM 99 H3 BCNZ A 301 21.718 38.138 80.426 0.58 32.37 H +HETATM 100 HA1BCNZ A 301 20.186 31.424 84.576 0.58 23.32 H +HETATM 101 HA2BCNZ A 301 22.025 35.797 80.242 0.58 30.56 H +HETATM 102 HA31BCNZ A 301 20.474 38.898 82.477 0.58 33.89 H +HETATM 103 HA32BCNZ A 301 19.406 39.129 81.373 0.58 33.89 H +HETATM 104 HB11BCNZ A 301 22.242 31.164 82.598 0.58 24.44 H +HETATM 105 HB12BCNZ A 301 22.170 32.385 83.562 0.58 24.44 H +HETATM 106 HB21BCNZ A 301 21.231 36.455 78.144 0.58 32.96 H +HETATM 107 HB22BCNZ A 301 19.988 35.509 78.306 0.58 32.96 H +HETATM 108 HG11BCNZ A 301 20.506 31.917 81.325 0.58 25.13 H +HETATM 109 HG12BCNZ A 301 19.915 32.770 82.473 0.58 25.13 H +HETATM 110 HB4BCNZ A 301 29.436 30.783 78.296 0.58 27.67 H +HETATM 111 HB5BCNZ A 301 27.207 31.685 74.677 0.58 33.10 H +HETATM 112 HD4BCNZ A 301 30.844 27.529 76.433 0.58 26.53 H +HETATM 113 HE4BCNZ A 301 29.166 27.708 74.855 0.58 26.68 H +HETATM 114 HE5BCNZ A 301 25.772 33.333 78.746 0.58 34.37 H +HETATM 115 HG4BCNZ A 301 30.954 29.059 78.168 0.58 26.89 H +HETATM 116 HG5BCNZ A 301 25.686 33.391 74.726 0.58 34.22 H +HETATM 117 HZ4BCNZ A 301 27.640 29.424 74.968 0.58 27.81 H +HETATM 118 HZ5BCNZ A 301 27.307 31.657 78.688 0.58 33.11 H +HETATM 119 H11NBCNZ A 301 21.801 30.869 85.839 0.58 23.71 H +HETATM 120 H12NBCNZ A 301 21.491 29.552 85.406 0.58 23.71 H +HETATM 121 H131BCNZ A 301 24.007 34.190 78.713 0.58 36.08 H +HETATM 122 H132BCNZ A 301 23.663 35.651 78.292 0.58 36.08 H +END''' + # ------------------------------------------------------------------------------ if (__name__ == "__main__"): From 47336b5b30c36b220203ac627c3c4b66c0387f06 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 18 Apr 2024 11:45:30 -0700 Subject: [PATCH 365/748] update --- mmtbx/monomer_library/idealized_aa.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/mmtbx/monomer_library/idealized_aa.py b/mmtbx/monomer_library/idealized_aa.py index 3e857162ba..5be5dd94b7 100644 --- a/mmtbx/monomer_library/idealized_aa.py +++ b/mmtbx/monomer_library/idealized_aa.py @@ -783,16 +783,14 @@ ATOM 6 CG UNK A 1 5.756 6.902 6.474 1.00 20.00 A C ATOM 7 OXT UNK A 1 10.213 6.660 5.218 1.00 20.00 A O-1 ATOM 8 H UNK A 1 7.976 8.561 5.778 1.00 20.00 A H -ATOM 9 H2 UNK A 1 8.151 8.678 7.192 1.00 20.00 A H ATOM 10 HA UNK A 1 8.236 6.623 7.589 1.00 20.00 A H ATOM 11 HB1 UNK A 1 7.112 6.478 5.000 1.00 20.00 A H ATOM 12 HB2 UNK A 1 7.004 5.329 6.074 1.00 20.00 A H ATOM 13 HG1 UNK A 1 5.000 6.517 6.003 1.00 20.00 A H ATOM 14 HG2 UNK A 1 5.673 6.717 7.423 1.00 20.00 A H ATOM 15 HG3 UNK A 1 5.771 7.861 6.332 1.00 20.00 A H -TER -END """ +#ATOM 9 H2 UNK A 1 8.151 8.678 7.192 1.00 20.00 A H unk = """ CRYST1 15.213 13.678 12.589 90.00 90.00 90.00 P 1 @@ -803,8 +801,6 @@ ATOM 5 CB UNK A 1 7.045 6.291 5.950 1.00 20.00 A C ATOM 6 CG UNK A 1 5.756 6.902 6.474 1.00 20.00 A C ATOM 7 OXT UNK A 1 10.213 6.660 5.218 1.00 20.00 A O-1 -TER -END """ sec_h = ''' @@ -816,12 +812,12 @@ ATOM 5 CB SEC A 1 7.262 7.371 7.286 1.00 20.00 A C ATOM 6 SE SEC A 1 9.115 6.677 7.432 1.00 20.00 A Se ATOM 7 H SEC A 1 5.000 7.509 5.000 1.00 20.00 A H -ATOM 8 H2 SEC A 1 5.092 8.078 6.245 1.00 20.00 A H ATOM 9 HA SEC A 1 7.108 8.130 5.423 1.00 20.00 A H ATOM 10 HB2 SEC A 1 6.720 6.820 7.820 1.00 20.00 A H ATOM 11 HB3 SEC A 1 7.248 8.247 7.624 1.00 20.00 A H ATOM 12 HE SEC A 1 9.413 7.295 8.703 1.00 20.00 A H ''' +#ATOM 8 H2 SEC A 1 5.092 8.078 6.245 1.00 20.00 A H sec = ''' CRYST1 14.413 13.247 13.703 90.00 90.00 90.00 P 1 @@ -853,7 +849,6 @@ ATOM 16 N2 PYL A 1 8.406 7.731 15.274 1.00 20.00 A N ATOM 17 O2 PYL A 1 9.157 5.629 13.065 1.00 20.00 A O ATOM 18 H PYL A 1 12.576 10.034 5.952 1.00 20.00 A H -ATOM 19 H2 PYL A 1 12.574 8.911 6.743 1.00 20.00 A H ATOM 20 HA PYL A 1 10.759 8.389 6.051 1.00 20.00 A H ATOM 21 HA2 PYL A 1 7.039 7.718 13.840 1.00 20.00 A H ATOM 22 HB12 PYL A 1 5.037 5.890 13.932 1.00 20.00 A H @@ -873,6 +868,7 @@ ATOM 36 HE3 PYL A 1 9.075 6.458 10.373 1.00 20.00 A H ATOM 37 HZ PYL A 1 8.115 8.238 12.051 1.00 20.00 A H ''' +#ATOM 19 H2 PYL A 1 12.574 8.911 6.743 1.00 20.00 A H pyl = ''' CRYST1 17.576 16.310 22.096 90.00 90.00 90.00 P 1 From c22ee1beaafba14d7fbc01a143f151539476fe22 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 19 Apr 2024 13:49:07 -0700 Subject: [PATCH 366/748] Reduce2: Handle element X. Provisional. --- mmtbx/hydrogens/reduce_hydrogen.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index f11a8a9352..83aa0acf82 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -183,6 +183,7 @@ def __init__(self, if self.print_time: self.time_rebox_model = None + self.time_remove_element_X = None self.time_add_missing_H = None self.time_terminal_propeller = None self.time_make_grm = None @@ -210,8 +211,19 @@ def run(self): #self.model.add_crystal_symmetry_if_necessary() # this is slower than shift_and_box_model!!!! self.time_rebox_model = round(time.time()-t0, 2) + + # Don't stop if model contains element X atoms + # This needs more discussion before being made final + # --------------------------------------------- + t0 = time.time() + if ' X' in self.model.get_hierarchy().atoms().extract_element(): + self.model = self.model.select(~self.model.selection('element X')) + self.time_remove_element_X = round(time.time()-t0, 2) + + # Remove existing H if requested # ------------------------------ + self.model.get_xray_structure() self.n_H_initial = self.model.get_hd_selection().count(True) if not self.keep_existing_H: self.model = self.model.select(~self.model.get_hd_selection()) @@ -352,6 +364,9 @@ def place_n_terminal_propeller(self, pdb_hierarchy): ['common_amino_acid', 'modified_amino_acid', 'd_amino_acid']): if ag.get_atom('H'): ag.remove_atom(ag.get_atom('H')) + # TODO make the function below smart, so it + # 1) knows when to add H1H2H3 or not + # 2) renames H to H1 (so no need to remove it beforehand) rc = add_n_terminal_hydrogens_to_residue_group(rgs) # rc is always empty list? # ---------------------------------------------------------------------------- @@ -624,6 +639,7 @@ def get_counts(self): def get_times(self): return group_args( time_rebox_model = self.time_rebox_model, + time_remove_element_X = self.time_remove_element_X, time_add_missing_H = self.time_add_missing_H, time_terminal_propeller = self.time_terminal_propeller, time_make_grm = self.time_make_grm, @@ -638,6 +654,7 @@ def get_times(self): def print_times(self): print('Detailed timings:') print("Rebox model:", self.time_rebox_model) + print('Remove element X:', self.time_remove_element_X) print("Add_missing_H_atoms_at_bogus_position:", self.time_add_missing_H) print('Add N-terminal propeller', self.time_terminal_propeller) print("Get new model obj and grm:", self.time_make_grm ) From 2cb152daa0c2731cce5ba4a8ea974337e051aaea Mon Sep 17 00:00:00 2001 From: terwill Date: Sun, 21 Apr 2024 06:03:17 -0700 Subject: [PATCH 367/748] Fix tst_grm_pickling.py by not using creating reference model with multi_out which cannot be pickled --- cctbx/regression/tst_grm_pickling.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cctbx/regression/tst_grm_pickling.py b/cctbx/regression/tst_grm_pickling.py index 08eab37ef4..a55c47a893 100644 --- a/cctbx/regression/tst_grm_pickling.py +++ b/cctbx/regression/tst_grm_pickling.py @@ -437,7 +437,7 @@ def test_reference_model(mon_lib_srv, ener_lib, prefix="tst_reference_model"): model = model, reference_hierarchy_list=reference_hierarchy_list, params=work_params.reference_model, - log=mstream) + log=null_out()) # XXX changed from mstream which cannot be pickled assert rm.get_n_proxies() == 5, "Got %d, expected 5" % rm.get_n_proxies() geometry, xrs = make_initial_grm(mon_lib_srv, ener_lib, model_raw_records) geometry.adopt_reference_dihedral_manager(rm) From 800626ee1424a360d60c7a16b2090be98844e974 Mon Sep 17 00:00:00 2001 From: Russell Taylor Date: Mon, 22 Apr 2024 13:59:30 -0400 Subject: [PATCH 368/748] Version 2.4.0 of Reduce2 only outputs a single model if it is only optimizing a single model. It removes all other models before hydrogen addition, which is much faster. (#986) --- mmtbx/programs/reduce2.py | 55 ++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/mmtbx/programs/reduce2.py b/mmtbx/programs/reduce2.py index 504418f226..bd7f4c40cf 100644 --- a/mmtbx/programs/reduce2.py +++ b/mmtbx/programs/reduce2.py @@ -36,7 +36,7 @@ from iotbx.data_manager import DataManager import csv -version = "2.3.0" +version = "2.4.0" master_phil_str = ''' approach = *add remove @@ -66,7 +66,7 @@ model_id = None .type = int .short_caption = Model ID to optimize - .help = Model ID to optimize. The default is to optimize all of them. + .help = Model ID to optimize. The default is to optimize all of them. If one is selected, the others are removed from the output file. add_flip_movers = False .type = bool .short_caption = Add flip movers @@ -857,6 +857,16 @@ def _AddFlipkinMovers(states, fileBaseName, name, color, model, alts, bondedNeig return ret +def _RemoveModelsExceptIndex(model_manager, model_index): + hierarchy = model_manager.get_hierarchy() + models = hierarchy.models() + if model_index < len(models): + selected_model = models[model_index] + for model in models: + if model != selected_model: + hierarchy.remove_model(model=model) + return model_manager + # ------------------------------------------------------------------------------ class Program(ProgramTemplate): @@ -1124,7 +1134,7 @@ def _DescribeLockdown(self, flipMover, invertFlip, fixedUp): return '{} {} {} {} {}{} {} {}'.format(flipMover.modelId+1, altId.lower(), flipMover.chain, flipMover.resName, flipMover.resId, flipMover.iCode, flipStateString, adjustedString) -# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ def validate(self): # Set the default output file name if one has not been given. @@ -1156,7 +1166,7 @@ def validate(self): self._pr = cProfile.Profile() self._pr.enable() -# ------------------------------------------------------------------------------ + # ------------------------------------------------------------------------------ def run(self): @@ -1180,6 +1190,31 @@ def run(self): if (cs is None) or (cs.unit_cell() is None): self.model = shift_and_box_model(model = self.model) + # If we've been asked to only to a single model index from the file, strip the model down to + # only that index. + if self.params.model_id is not None: + make_sub_header('Selecting Model ID ' + str(self.params.model_id), out=self.logger) + + # Select only the current submodel from the hierarchy + submodel = self.model.deep_copy() + _RemoveModelsExceptIndex(submodel, self.params.model_id) + + # Construct a hierarchy for the current submodel + r = pdb.hierarchy.root() + mdc = submodel.get_hierarchy().models()[0].detached_copy() + r.append_model(mdc) + + # Make yet another model for the new hierarchy + subset_model_manager = mmtbx.model.manager( + model_input = None, + pdb_hierarchy = r, + stop_for_unknowns = False, + crystal_symmetry = submodel.crystal_symmetry(), + restraint_objects = None, + log = None) + + self.model = subset_model_manager + # Stores the initial coordinates for all of the atoms and the rest of the information # about the original model for use by Kinemages. initialModel = self.model.deep_copy() @@ -1191,10 +1226,12 @@ def run(self): self._AddHydrogens() doneAdd = time.time() + # NOTE: We always optimize all models (leave modelIndex alone) because we've removed all + # but the desired model ID structure from the model. make_sub_header('Optimizing', out=self.logger) startOpt = time.time() opt = Optimizers.Optimizer(self.params.probe, self.params.add_flip_movers, - self.model, altID=self.params.alt_id, modelIndex=self.params.model_id, + self.model, altID=self.params.alt_id, preferenceMagnitude=self.params.preference_magnitude, bondedNeighborDepth = self._bondedNeighborDepth, nonFlipPreference=self.params.non_flip_preference, @@ -1449,8 +1486,10 @@ def run(self): # Optimize the model and then reinterpret it so that we can get all of the information we # need for the resulting set of atoms (which may be fewer after Hydrogen removal). + # NOTE: We always optimize all models (leave modelIndex alone) because we've removed all + # but the desired model ID structure from the model. opt = Optimizers.Optimizer(self.params.probe, self.params.add_flip_movers, - self.model, altID=self.params.alt_id, modelIndex=self.params.model_id, + self.model, altID=self.params.alt_id, preferenceMagnitude=self.params.preference_magnitude, nonFlipPreference=self.params.non_flip_preference, skipBondFixup=self.params.skip_bond_fix_up, @@ -1571,8 +1610,10 @@ def run(self): # Optimize the model and then reinterpret it so that we can get all of the information we # need for the resulting set of atoms (which may be fewer after Hydrogen removal). + # NOTE: We always optimize all models (leave modelIndex alone) because we've removed all + # but the desired model ID structure from the model. opt = Optimizers.Optimizer(self.params.probe, self.params.add_flip_movers, - self.model, altID=self.params.alt_id, modelIndex=self.params.model_id, + self.model, altID=self.params.alt_id, preferenceMagnitude=self.params.preference_magnitude, nonFlipPreference=self.params.non_flip_preference, skipBondFixup=self.params.skip_bond_fix_up, From 107afe207fb720eda50db4e3969488af5c009aa6 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Fri, 19 Apr 2024 15:29:14 -0700 Subject: [PATCH 369/748] move to development --- mmtbx/command_line/electrons.py | 2 +- mmtbx/command_line/water_b_factors.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mmtbx/command_line/electrons.py b/mmtbx/command_line/electrons.py index 8f9c98c87d..5a7797c684 100644 --- a/mmtbx/command_line/electrons.py +++ b/mmtbx/command_line/electrons.py @@ -1,5 +1,5 @@ -# LIBTBX_SET_DISPATCHER_NAME mmtbx.electrons from __future__ import absolute_import, division, print_function +# LIBTBX_SET_DISPATCHER_NAME mmtbx.development.electrons from iotbx.cli_parser import run_program from mmtbx.ligands import electrons diff --git a/mmtbx/command_line/water_b_factors.py b/mmtbx/command_line/water_b_factors.py index afe7a5dde0..c74fc8ca26 100644 --- a/mmtbx/command_line/water_b_factors.py +++ b/mmtbx/command_line/water_b_factors.py @@ -1,4 +1,5 @@ from __future__ import absolute_import, division, print_function +# LIBTBX_SET_DISPATCHER_NAME phenix.development.water_b_factors from iotbx.cli_parser import run_program from mmtbx.programs.water_b_factors import Program From a2847d71dc7b58ad86358cd14ae4bed0628f0428 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Fri, 19 Apr 2024 15:29:56 -0700 Subject: [PATCH 370/748] electron validation --- mmtbx/ligands/electrons.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mmtbx/ligands/electrons.py b/mmtbx/ligands/electrons.py index 4239e23302..21e3f914c6 100644 --- a/mmtbx/ligands/electrons.py +++ b/mmtbx/ligands/electrons.py @@ -27,7 +27,7 @@ 'HOH' : 0, } disallowed_element_charges = { - 'N' : 2, + 'N' : 1, 'O' : -1, 'C' : 1, } @@ -889,7 +889,7 @@ def report(self, ignore_water=False, show_detailed=False): answers = { 'Residue HOH has a problem with the charge : 2!=0' : \ 'Hydrogen atoms not added to water', - 'Element has strange number of electrons N : 2' : \ + 'Element has strange number of electrons N : 1' : \ 'N terminal (or break) missing hydrogen atoms', 'Element has strange number of electrons O : -1' : \ 'C terminal (or break) missing oxygen atoms', From 471f4b8a07f1bf64a2d82fc14cb429cc54b5b74c Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Mon, 22 Apr 2024 12:07:45 -0700 Subject: [PATCH 371/748] Better output and added final strain energy --- mmtbx/chemical_components/__init__.py | 8 +-- .../quantum_restraints_manager.py | 24 +++++---- mmtbx/programs/quantum_interface.py | 53 ++++++++++++++----- mmtbx/refinement/energy_monitor.py | 6 +-- 4 files changed, 61 insertions(+), 30 deletions(-) diff --git a/mmtbx/chemical_components/__init__.py b/mmtbx/chemical_components/__init__.py index 2444e8f7ff..05129ba494 100644 --- a/mmtbx/chemical_components/__init__.py +++ b/mmtbx/chemical_components/__init__.py @@ -1,4 +1,3 @@ - from __future__ import absolute_import, division, print_function from mmtbx.chemical_components import cif_parser from libtbx.utils import Sorry @@ -310,7 +309,7 @@ def get_group(code, split_rna_dna=False, split_l_d=False, verbose=False): assert not split_l_d return 'non-alpha peptide' elif t in terminii: - assert not split_l_d + # assert not split_l_d return 'amino_acid_terminal' elif t in rna_dna_types: # assert not split_rna_dna @@ -338,8 +337,9 @@ def get_restraints_group(code, split_rna_dna=True, split_l_d=True): 'RNA', 'DNA', ]: return g - return {'amino_acid' : 'peptide', - 'non-polymer': 'ligand', + return {'amino_acid' : 'peptide', + 'amino_acid_terminal' : 'peptide', + 'non-polymer' : 'ligand', # 'saccharide' : 'pyranose', }[g] assert 0 diff --git a/mmtbx/geometry_restraints/quantum_restraints_manager.py b/mmtbx/geometry_restraints/quantum_restraints_manager.py index b060205e40..8bea4520dd 100644 --- a/mmtbx/geometry_restraints/quantum_restraints_manager.py +++ b/mmtbx/geometry_restraints/quantum_restraints_manager.py @@ -637,7 +637,7 @@ def update_bond_restraints(ligand_model, if not(i_atom.tmp in ligand_i_seqs and j_atom.tmp in ligand_i_seqs): continue Z=(distance_model-bond.distance_ideal)/sigma - print(' %-2d %s - %s %5.3f ~> %5.3f (Z=%4.1f)' % ( + print(' %-5d %s - %s %5.3f ~> %5.3f (Z=%4.1f)' % ( i, i_atom.id_str().replace('pdb=',''), j_atom.id_str().replace('pdb=',''), @@ -651,7 +651,7 @@ def update_bond_restraints(ligand_model, else: if ( i_atom.element_is_hydrogen() or j_atom.element_is_hydrogen()): if distance_model>1.5: - print(' %-2d %s - %s %5.3f ~> %5.3f' % ( + print(' %-5d %s - %s %5.3f ~> %5.3f' % ( i, i_atom.id_str().replace('pdb=',''), j_atom.id_str().replace('pdb=',''), @@ -734,7 +734,7 @@ def update_angle_restraints(ligand_model, # key = (int(i_seqs[0]), int(i_seqs[1]), int(i_seqs[2])) i+=1 Z=(angle_model-angle_ideal)/sigma - print(' %-2d %s - %s - %s %5.1f ~> %5.1f (Z=%4.1f)' % ( + print(' %-5d %s - %s - %s %5.1f ~> %5.1f (Z=%4.1f)' % ( i, i_atom.id_str().replace('pdb=',''), j_atom.id_str().replace('pdb=',''), @@ -831,7 +831,7 @@ def update_dihedral_restraints( ligand_model, else: if len(intersect)!=4: continue i+=1 - print(' %-2d %s - %s - %s - %s %5.1f ~> %5.1f' % ( + print(' %-5d %s - %s - %s - %s %6.1f ~> %6.1f' % ( i, i_atom.id_str().replace('pdb=',''), j_atom.id_str().replace('pdb=',''), @@ -911,14 +911,15 @@ def setup_qm_jobs(model, number_of_macro_cycles = 1 if hasattr(params, 'main'): number_of_macro_cycles = params.main.number_of_macro_cycles + if macro_cycle==99: number_of_macro_cycles = 99 if macro_cycle is not None and not running_this_macro_cycle( qmr, macro_cycle, energy_only=energy_only, number_of_macro_cycles=number_of_macro_cycles, pre_refinement=pre_refinement): - # print(' Skipping this selection in this macro_cycle : %s' % qmr.selection, - # file=log) + print(' Skipping this selection in this macro_cycle : %s' % qmr.selection, + file=log) continue # # get ligand and buffer region models @@ -1041,16 +1042,20 @@ def run_energies(model, # # run jobs # + working_dir = quantum_interface.get_working_directory(model, params) + if not os.path.exists(working_dir): + try: os.mkdir(working_dir) + except Exception as e: pass + os.chdir(working_dir) xyzs, xyzs_buffer, energies, units = run_jobs(objects, macro_cycle=macro_cycle, nproc=nproc, log=log) + os.chdir('..') print(' Total time for QM energies: %0.1fs' % (time.time()-t0), file=log) print('%s%s' % ('<'*40, '>'*40), file=log) return group_args(energies=energies, units=units, - # rmsds=rmsds, - # times=times, ) def update_restraints(model, @@ -1098,6 +1103,7 @@ def is_ligand_going_to_be_same_size(qmr): # assert objects if not objects: return None + cwd_dir = os.getcwd() working_dir = quantum_interface.get_working_directory(model, params) if not os.path.exists(working_dir): try: os.mkdir(working_dir) @@ -1236,7 +1242,7 @@ def is_ligand_going_to_be_same_size(qmr): if qmr.restraints_filename is not Auto: tmp_cif_filename = qmr.restraints_filename else: - tmp_cif_filename = '%s.cif' % qmm.preamble + tmp_cif_filename = os.path.join(cwd_dir, '%s.cif' % qmm.preamble) if not tmp_cif_filename.endswith('.cif'): tmp_cif_filename = '%s.cif' % tmp_cif_filename write_restraints(ligand_model, diff --git a/mmtbx/programs/quantum_interface.py b/mmtbx/programs/quantum_interface.py index fc088bf68e..fcddc4d6d3 100644 --- a/mmtbx/programs/quantum_interface.py +++ b/mmtbx/programs/quantum_interface.py @@ -245,7 +245,6 @@ def qm_restraints_has_selection(params): bc=0 if not params.qi.selection: for i, boolean in enumerate(bools): - print(i, boolean) if boolean: bc+=1 else: return False @@ -407,21 +406,11 @@ def run(self, log=None): include_amino_acids=[include_amino_acids] rc = should_get_selection_from_user(self.params) - print(dir(self.params)) - print('rc',rc) if rc: - # if (not self.params.qi.selection and - # len(self.params.qi.qm_restraints)==0 and - # not self.params.qi.each_amino_acid and - # not self.params.qi.each_water and - # not self.params.qi.merge_water - # ): rc = get_selection_from_user(model.get_hierarchy(), include_amino_acids=include_amino_acids) - print('rc',rc) self.params.qi.selection = rc if len(self.params.qi.qm_restraints)!=0: - print(self.params.qi.qm_restraints) for attr, item in self.params.qi.qm_restraints[0].__dict__.items(): print(attr, item) # print(self.params.qi.selection) @@ -545,7 +534,7 @@ def run(self, log=None): else: rc = self.run_qmr(self.params.qi.format) - print(rc) + rc=rc[0] args = [] for filenames in rc.final_pdbs: print(filenames) @@ -625,7 +614,15 @@ def run(self, log=None): not (self.params.qi.iterate_NQH or self.params.qi.iterate_metals)): self.params.qi.qm_restraints.selection=self.params.qi.selection - self.run_qmr(self.params.qi.format) + rcs = self.run_qmr(self.params.qi.format) + cmd = '\n\n\tphenix.start_coot %s' % self.data_manager.get_default_model_name() + for rc in rcs: + filenames = getattr(rc, 'final_pdbs', []) + if filenames: + for f in filenames: + for g in f: + cmd += ' %s' % os.path.join('qm_work_dir', g) + print('%s\n\n' % cmd) if self.params.qi.iterate_NQH: print('"%s"' % self.params.qi.iterate_NQH, file=self.logger) @@ -1113,6 +1110,7 @@ def run_qmr(self, format, log=None): qmr = self.params.qi.qm_restraints[0] checks = 'starting_strain starting_energy starting_bound' energies = None + rcs=[] if any(item in checks for item in qmr.calculate): rc = run_energies( model, @@ -1125,6 +1123,7 @@ def run_qmr(self, format, log=None): energies = digest_return_energy_object(rc, 1, energy_only=True) outl = energies.as_string() print(outl, file=self.logger) + rcs.append(rc) # # minimise ligands geometry # @@ -1132,13 +1131,39 @@ def run_qmr(self, format, log=None): self.params, log=log, ) + rcs.append(rc) if energies is None: energies = digest_return_energy_object(rc, 1, energy_only=False) else: digest_return_energy_object(rc, 1, False, energies) outl = energies.as_string() print(outl, file=self.logger) - return rc + # + cannot_run_final_energies=False + if len(rc.final_pdbs)>1: + cannot_run_final_energies=True + checks = 'final_strain final_energy final_bound' + fn = os.path.join('qm_work_dir', rc.final_pdbs[0][0]) + self.data_manager.process_model_file(fn) + model = self.data_manager.get_model(fn) + if any(item in checks for item in qmr.calculate): + if cannot_run_final_energies: + print('Cannot run final energies. Restart with only one ligand selection.', + file=self.logger) + else: + rc = run_energies( + model, + self.params, + macro_cycle=99, + pre_refinement=False, + nproc=self.params.qi.nproc, + log=log, + ) + energies = digest_return_energy_object(rc, 99, True, energies) + outl = energies.as_string() + print(outl, file=self.logger) + rcs.append(rc) + return rcs def get_single_qm_restraints_scope(self, selection): qi_phil_string = get_qm_restraints_scope() diff --git a/mmtbx/refinement/energy_monitor.py b/mmtbx/refinement/energy_monitor.py index 52df247383..4ad4611981 100644 --- a/mmtbx/refinement/energy_monitor.py +++ b/mmtbx/refinement/energy_monitor.py @@ -6,9 +6,9 @@ def _print_energy_in_kcal(e, units): if units.lower() in to_kcal_mol: - return '%15.3f %s' % (e*to_kcal_mol[units.lower()], 'kcal/mol') + return '%15.1f %s' % (e*to_kcal_mol[units.lower()], 'kcal/mol') else: - return '%15.3f %s' % (e, units) + return '%15.1f %s' % (e, units) def print_energy_in_kcal(ga): s=[] @@ -75,7 +75,7 @@ def _add_dE(e1, e2, units): b1=e1[2]==e2[2] if b1: de = e2[1]-e1[1] - s+='%s%-12s %s\n' % (' '*6, + s+='%s%-22s %s\n' % (' '*6, '%s dE' % e2[0], _print_energy_in_kcal(e2[1]-e1[1],units)) return s From bbb7ff56cdc341caf9ba2f37d0be32defca0715f Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Mon, 22 Apr 2024 16:37:16 -0700 Subject: [PATCH 372/748] Reduce 2: adapt test to new restraint targets in ligand SIN. --- mmtbx/hydrogens/tst_add_hydrogen_3.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mmtbx/hydrogens/tst_add_hydrogen_3.py b/mmtbx/hydrogens/tst_add_hydrogen_3.py index 909cb96d6c..7bcdec874b 100644 --- a/mmtbx/hydrogens/tst_add_hydrogen_3.py +++ b/mmtbx/hydrogens/tst_add_hydrogen_3.py @@ -272,10 +272,10 @@ def test_006(): ANISOU 23 O3 SIN A 0 3949 3621 1603 176 -78 -76 O HETATM 24 O4 SIN A 0 10.281 28.844 2.062 1.00 -1.00 O ANISOU 24 O4 SIN A 0 3699 3930 2011 285 2 -324 O -HETATM 25 H21 SIN A 0 11.127 26.627 0.725 1.00 21.62 H -HETATM 26 H22 SIN A 0 12.626 25.858 1.243 1.00 21.62 H -HETATM 27 H31 SIN A 0 13.002 27.899 2.729 1.00 22.69 H -HETATM 28 H32 SIN A 0 13.190 28.117 0.990 1.00 22.69 H +HETATM 25 H21 SIN A 0 11.207 26.621 0.815 1.00 21.62 H +HETATM 26 H22 SIN A 0 12.541 25.936 1.276 1.00 21.62 H +HETATM 27 H31 SIN A 0 12.954 27.930 2.619 1.00 22.69 H +HETATM 28 H32 SIN A 0 13.119 28.122 1.092 1.00 22.69 H END """ From a90a4f3bc54ec11d5d3131b82fd375e29a3869e9 Mon Sep 17 00:00:00 2001 From: Vincent Chen Date: Tue, 23 Apr 2024 10:49:04 -0400 Subject: [PATCH 373/748] bug fix for pdb remediator for RNA --- iotbx/pdb/remediation/remediator.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iotbx/pdb/remediation/remediator.py b/iotbx/pdb/remediation/remediator.py index cbd3ae816f..17d534e443 100644 --- a/iotbx/pdb/remediation/remediator.py +++ b/iotbx/pdb/remediation/remediator.py @@ -204,8 +204,8 @@ def build_hash_from_chem_components(self, residue_name, convert_to_new=True, bui atom_exch[old_atom+" "+residue_name] = new_atom+" "+residue_name else: atom_exch[new_atom+" "+residue_name] = old_atom+" "+residue_name - na_old_atom_name_exceptions = ["H5T ","5HO*", "H3T "] # it's difficult in 2020 to figure out the proper spacing for this old style atom name - na_new_atom_name_exceptions = ["HO5'","HO5'", "HO3'"] # old remediator uses 5HO* but other examples on the web use H5T for HO5' + na_old_atom_name_exceptions = ["H5T ","5HO*", "H3T ", "3HO*"] # it's difficult in 2020 to figure out the proper spacing for this old style atom name + na_new_atom_name_exceptions = ["HO5'","HO5'", "HO3'", "HO3'"] # old remediator uses 5HO* but other examples on the web use H5T for HO5' residues_to_test = [ residue_name ] if (residue_name in self.na_bases) or (residue_name in self.dna_bases): if (residue_name in self.na_bases): @@ -384,7 +384,7 @@ def remediate(filename, remediated_out, f=None): remark_flag = True if previous == current: print_line += line + "\n" - elif previous != current: # appears to check an entire residue for dna residue/atom names + elif previous != None and previous != current: # appears to check an entire residue for dna residue/atom names if re.search(r'^.{12}.\S.. .[ACTGIU]',print_line): if re.search(r'O2[\'|\*] .',print_line) == None: DNA_base = previous[1] From 57a747ad1854a25bfb3657f9e7796f992ca78d78 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 24 Apr 2024 15:53:48 -0700 Subject: [PATCH 374/748] Tidy-up Phenix: refactor mmtbx/command_line/matthews.py. Use program template. --- mmtbx/command_line/matthews.py | 130 ++--------------------------- mmtbx/programs/matthews.py | 145 +++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 125 deletions(-) create mode 100644 mmtbx/programs/matthews.py diff --git a/mmtbx/command_line/matthews.py b/mmtbx/command_line/matthews.py index 9c70bc2300..ea0b13abdf 100644 --- a/mmtbx/command_line/matthews.py +++ b/mmtbx/command_line/matthews.py @@ -1,128 +1,8 @@ - +# LIBTBX_SET_DISPATCHER_NAME mmtbx.matthews from __future__ import absolute_import, division, print_function -import sys -from iotbx import crystal_symmetry_from_any -import iotbx.bioinformatics -from cctbx import crystal -from libtbx.utils import Sorry -import iotbx.phil - -master_phil_str = """ -data = None - .type = path -labels = None - .type = str -sequence = None - .type = path -model = None - .type = path -space_group = None - .type = space_group -unit_cell = None - .type = unit_cell -n_residues = None - .type = int(value_min=1) - .optional = True -n_bases = None - .type = int(value_min=1) - .optional = True -""" - -def run(args, out=sys.stdout): - import iotbx.phil - # this crashes without the import being on the previous line. why? - cmdline = iotbx.phil.process_command_line_with_files( - args=args, - master_phil_string=master_phil_str, - pdb_file_def="model", - reflection_file_def="data", - seq_file_def="sequence", - space_group_def="space_group", - unit_cell_def="unit_cell", - integer_def="n_residues", - usage_string="""\ -phenix.matthews [data.hkl] [space_group] [unit_cel] [sequence] [n_residues] ... - -Calculate the expected Matthews coefficient given the crystal symmetry and -crystallized molecule(s). -""") - params = cmdline.work.extract() - if (params.space_group is None) or (params.unit_cell is None): - if (params.data is None): - raise Sorry("You must supply both a space group and a unit cell (or "+ - "a data file containing this information).") - else : - symm = crystal_symmetry_from_any.extract_from(file_name=params.data) - space_group_from_file = symm.space_group() - if (params.space_group is None): - if (space_group_from_file is not None): - params.space_group = symm.space_group() - elif (space_group_from_file is not None): - if (space_group_from_file != params.space_group): - print("WARNING: space group mismatch between command line "+\ - "and file:", file=out) - print(" %s (cmdline), %s (file)" % (params.space_group, - space_group_from_file), file=out) - if (params.unit_cell is None): - params.unit_cell = symm.unit_cell() - validate_params(params, check_symmetry=True) - if (params.sequence is not None): - assert (params.n_residues == params.n_bases == None) - seq_comp = iotbx.bioinformatics.composition_from_sequence_file( - file_name=params.sequence, - log=out) - if (seq_comp is not None): - params.n_residues = seq_comp.n_residues - params.n_bases = seq_comp.n_bases - else : - raise Sorry("No composition information could be obtained from the "+ - "sequence file.") - elif (params.model is not None): - assert (params.n_residues == params.n_bases == None) - import iotbx.pdb - params.n_residues = 0 - params.n_bases = 0 - pdb_in = iotbx.pdb.input(params.model) - hierarchy = pdb_in.construct_hierarchy() - for chain in hierarchy.models()[0].chains(): - if chain.is_protein(): - params.n_residues += chain.residue_groups_size() - elif chain.is_na(): - params.n_bases += chain.residue_groups_size() - print("Space group: %s" % params.space_group, file=out) - print("Unit cell: %s" % params.unit_cell, file=out) - if (params.n_residues is not None): - print("Number of residues: %d" % params.n_residues, file=out) - if (params.n_bases is not None): - print("Number of bases: %d" % params.n_bases, file=out) - - symm = crystal.symmetry( - space_group_info=params.space_group.info(), - unit_cell=params.unit_cell) - from mmtbx.scaling import matthews - result = matthews.matthews_rupp( - crystal_symmetry=symm, - n_residues=params.n_residues, - n_bases=params.n_bases) - result.show(out=out) - return result -def validate_params(params, check_symmetry=False): - if (params.sequence is None) and (params.model is None): - if (params.n_residues is None) and (params.n_bases is None): - pass - #raise Sorry("You must specify the composition of the crystallized "+ - # "entity - either a sequence, a partial model, or the number of "+ - # "protein residues or nucleic acid bases.") - else : - if (params.n_residues is not None) or (params.n_bases is not None): - raise Sorry("You may only specify a sequence file OR a partial model "+ - "OR the numbers of residues and/or bases.") - if (check_symmetry): - if (params.space_group is None) or (params.unit_cell is None): - raise Sorry("You must supply both a space group and a unit cell (or "+ - "a data file containing this information).") - return True +from iotbx.cli_parser import run_program +from mmtbx.programs import matthews -if (__name__ == "__main__"): - run(sys.argv[1:]) +if __name__ == '__main__': + run_program(program_class=matthews.Program) diff --git a/mmtbx/programs/matthews.py b/mmtbx/programs/matthews.py new file mode 100644 index 0000000000..0c92f3eede --- /dev/null +++ b/mmtbx/programs/matthews.py @@ -0,0 +1,145 @@ +from __future__ import absolute_import, division, print_function +try: + from phenix.program_template import ProgramTemplate +except ImportError: + from libtbx.program_template import ProgramTemplate +from iotbx import crystal_symmetry_from_any +import iotbx.bioinformatics +from cctbx import crystal +from libtbx.utils import Sorry + +master_phil_str = """ +space_group = None + .type = space_group +unit_cell = None + .type = unit_cell +n_residues = None + .type = int(value_min=1) + .optional = True +n_bases = None + .type = int(value_min=1) + .optional = True +""" + +# ============================================================================= + +class Program(ProgramTemplate): + + description = ''' +Calculate the expected Matthews coefficient given the crystal symmetry and +crystallized molecule(s). + +phenix.matthews [data.hkl] [space_group] [unit_cel] [sequence] [n_residues] ... +''' + + datatypes = ['model', 'phil', 'miller_array', 'sequence'] + + master_phil_str = master_phil_str + + # --------------------------------------------------------------------------- + + def validate(self): + ''' + Make sure there is correct amount of inputs + ''' + print('Validating inputs...\n', file=self.logger) + # + # number of files + if len(self.data_manager.get_miller_array_names()) > 1: + raise Sorry('Supply at most one reflection file.') + if len(self.data_manager.get_model_names()) > 1: + raise Sorry('Supply at most one model file.') + if len(self.data_manager.get_sequence_names()) > 1: + raise Sorry('Supply at most one model file.') + # Space group & unit cell - either from data file or from command line + if (self.params.space_group is None) and (self.params.unit_cell is None): + if not self.data_manager.has_miller_arrays(): + raise Sorry('You must supply both a space group and a unit cell, ' + + 'either via the command line or a data file).') + elif (self.params.space_group is None) or (self.params.unit_cell is None): + raise Sorry('Supply the space group and a unit cell either via the '+ + 'command line or a data file.') + else: + if self.data_manager.has_miller_arrays(): + raise Sorry('No need to use a data file if space group and unit cell '+ + 'are supplied.') + # composition: either from sequence, model or command line + if self.data_manager.has_models() and self.data_manager.has_sequences(): + raise Sorry('Supply either a model file or a sequence.') + if not self.data_manager.has_sequences() and not self.data_manager.has_models(): + if (self.params.n_residues is None) and (self.params.n_bases is None): + raise Sorry('You must specify the composition of the crystallized '+ + 'entity - either a sequence, a partial model, or the number of '+ + 'protein residues or nucleic acid bases.') + else : + if (self.params.n_residues is not None) or (self.params.n_bases is not None): + raise Sorry('You may only specify a sequence file OR a partial model '+ + 'OR the numbers of residues and/or bases.') + + # --------------------------------------------------------------------------- + + def run(self): + ''' + Calculate Matthews coefficient and print the results + ''' + # space group + print('Space group and unit cell:', file=self.logger) + if (self.params.space_group is None) and (self.params.unit_cell is None): + data_fn = self.data_manager.get_miller_array_names()[0] + print('From data file ', data_fn, file=self.logger) + cs = crystal_symmetry_from_any.extract_from(file_name=data_fn) + if cs is not None: + sg_from_file = cs.space_group_info() + if sg_from_file is not None: + self.params.space_group = cs.space_group_info() + uc_from_file = cs.unit_cell() + if uc_from_file is not None: + self.params.unit_cell = uc_from_file + else: + print('From command line inputs', file=self.logger) + print('Space group:', self.params.space_group, file=self.logger) + print('Unit cell:', self.params.unit_cell, file=self.logger) + + print('\nComposition:', file=self.logger) + + # composition from sequence + if self.data_manager.has_sequences(): + print('Using sequence file ', + self.data_manager.get_default_sequence_name(), file=self.logger) + assert (self.params.n_residues == self.params.n_bases == None) + seq_object = self.data_manager.get_sequence()[0] + n_residues, n_bases = iotbx.bioinformatics.composition_from_sequence( + sequence=seq_object.sequence) + self.params.n_residues = n_residues + self.params.n_bases = n_bases + #else : + # raise Sorry("No composition information could be obtained from the "+ + # "sequence file.") + + # composition from model file + if self.data_manager.has_models(): + print('Using model file ', + self.data_manager.get_default_model_name(), file=self.logger) + assert (self.params.n_residues == self.params.n_bases == None) + model = self.data_manager.get_model() + self.params.n_residues = 0 + self.params.n_bases = 0 + hierarchy = model.get_hierarchy() + comp = hierarchy.composition() + self.params.n_residues = comp.n_protein + self.params.n_bases = comp.n_nucleotide + if (self.params.n_residues): + print('Number of residues: %d' % self.params.n_residues, file=self.logger) + if (self.params.n_bases): + print('Number of bases: %d' % self.params.n_bases, file=self.logger) + + symm = crystal.symmetry( + space_group_info=self.params.space_group, + unit_cell=self.params.unit_cell) + from mmtbx.scaling import matthews + result = matthews.matthews_rupp( + crystal_symmetry=symm, + n_residues=self.params.n_residues, + n_bases=self.params.n_bases) + result.show(out=self.logger) + return result From 05b6df141b21302033e4404a8ffbb27678dac6bf Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 25 Apr 2024 03:03:15 -0600 Subject: [PATCH 375/748] Catch None --- mmtbx/secondary_structure/find_ss_from_ca.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/mmtbx/secondary_structure/find_ss_from_ca.py b/mmtbx/secondary_structure/find_ss_from_ca.py index c954edf229..32c7c0a153 100644 --- a/mmtbx/secondary_structure/find_ss_from_ca.py +++ b/mmtbx/secondary_structure/find_ss_from_ca.py @@ -1770,6 +1770,8 @@ def get_sites(self,start_res=None,end_res=None): def get_centroid(self,start_res=None,end_res=None): # get centroid of residues from start_res to end_res sites=self.get_sites(start_res=start_res,end_res=end_res) + if sites.size() < 1: + return None return sites.mean() class helix(segment): # Methods specific to helices @@ -1842,8 +1844,10 @@ def get_orientation_points(self,start_res=None,end_res=None): im=(start_res+end_res)//2 # middle residue cm1=self.get_centroid(start_res=im-2,end_res=im+1) cm2=self.get_centroid(start_res=im-1,end_res=im+2) - center_middle=0.5*(matrix.col(cm1)+matrix.col(cm2)) - + if (cm1 is not None) and (cm2 is not None): + center_middle=0.5*(matrix.col(cm1)+matrix.col(cm2)) + else: + return None # cannot do it center_1=self.get_centroid(start_res=start_res,end_res=start_res+3) center_2=self.get_centroid(start_res=end_res-3,end_res=end_res) ca_1=self.get_site(resno=start_res) @@ -1917,7 +1921,9 @@ def get_orientation_points(self,start_res=None,end_res=None): # for strand else: # odd number of residues average just before and after im=(start_res+end_res)//2 # middle residue cm1=self.get_centroid(start_res=im-1,end_res=im) + if cm1 is None: return None cm2=self.get_centroid(start_res=im,end_res=im+1) + if cm2 is None: return None center_middle=0.5*(matrix.col(cm1)+matrix.col(cm2)) center_1=self.get_centroid(start_res=start_res,end_res=start_res+1) @@ -2082,7 +2088,7 @@ def setup(self,params=None,model=None,segment_type='helix', overall_start_res=i overall_end_res=segment_dict[i]+self.last_residue_offset overall_length=overall_end_res-overall_start_res+1 - optimal_delta_length=optimal_delta_length_dict[overall_start_res] + optimal_delta_length=optimal_delta_length_dict.get(overall_start_res, 0) if (optimal_delta_length > 0 and not self.allow_insertions) or \ (optimal_delta_length < 0 and not self.allow_deletions): optimal_delta_length=0 @@ -2144,7 +2150,8 @@ def extract_segment(self,params=None,start_res=None,end_res=None,sites=None, else: is_c_terminus=False - assert len(sites)>=end_res # make sure we are in bounds + if len(sites) < end_res: # make sure we are in bounds + return False # get the hierarchy if necessary if self.extract_segments_from_pdb or self.model_as_segment: From fd6731d7476f22076af844a6371c13f31efa503c Mon Sep 17 00:00:00 2001 From: Russell Taylor Date: Thu, 25 Apr 2024 07:09:02 -0400 Subject: [PATCH 376/748] Undowser2 (#988) * Removed leftover conversion * Adding undowser2_validation command-line program that uses undowser2.py validation that uses reduce2 and probe2 * Cleaning up clutter * Cleaning up undowser2 programs so that they call each other properly * Always want condensed output in undowser2 * Adjusting log settings for undowser2 so it doesn't print extra information * More verbose error message when finding a hydrogen with more than 1 neighbor * Requiring >0 bonded neighbors rather than exactly 1 for hydrogens in Probe2 and Reduce2 * Removing superfluous and duplicate PHIL parameter from Probe2. Fixing tags on Probe2 Kinemage output for point masters. Explicitly removing hydrogen-bond reporting for undowser2. * Fixing test case to match adjusted Probe2 output. * Adding checking of compatible alternate locations in probe2 C++ code. * Adding alternate to test code for ExtraAtomInfo * Bumping probe2 and reduce2 version numbers to indicate that they have changed * Fixing call in clashscore2.py when we're keeping the hydrogens * Fixing tst_undowser.py to have correct strings to compare against * Adding tst_undowser2.py * Removed unused import * Switching to old-school C++-98 initializers to pass the automatic tests * Adding Undowser2 test to run_tests.py in mmtbx --- mmtbx/command_line/undowser2.py | 49 ++ mmtbx/probe/Helpers.py | 44 +- mmtbx/probe/Scoring.cpp | 108 ++- mmtbx/probe/Scoring.h | 23 +- mmtbx/probe/boost_python/probe_bpl.cpp | 3 +- mmtbx/programs/probe2.py | 39 +- mmtbx/programs/reduce2.py | 9 +- mmtbx/programs/undowser2.py | 78 ++ .../regression/kins/Fe_1brf_snip_reduced.kin | 8 +- mmtbx/run_tests.py | 1 + mmtbx/validation/clashscore2.py | 5 +- mmtbx/validation/regression/tst_undowser.py | 6 +- mmtbx/validation/regression/tst_undowser2.py | 282 ++++++++ mmtbx/validation/undowser2.py | 664 ++++++++++++++++++ 14 files changed, 1262 insertions(+), 57 deletions(-) create mode 100644 mmtbx/command_line/undowser2.py create mode 100644 mmtbx/programs/undowser2.py create mode 100644 mmtbx/validation/regression/tst_undowser2.py create mode 100644 mmtbx/validation/undowser2.py diff --git a/mmtbx/command_line/undowser2.py b/mmtbx/command_line/undowser2.py new file mode 100644 index 0000000000..e0f68041c2 --- /dev/null +++ b/mmtbx/command_line/undowser2.py @@ -0,0 +1,49 @@ +from __future__ import absolute_import, division, print_function +# LIBTBX_SET_DISPATCHER_NAME phenix.undowser2_validation +# LIBTBX_SET_DISPATCHER_NAME mmtbx.undowser2_validation +# LIBTBX_SET_DISPATCHER_NAME molprobity.undowser2_validation +# LIBTBX_PRE_DISPATCHER_INCLUDE_SH export PHENIX_GUI_ENVIRONMENT=1 + +import sys + +from iotbx.cli_parser import CCTBXParser +from libtbx.utils import multi_out, show_total_time +from mmtbx.programs import undowser2 +from iotbx.cli_parser import run_program + +# ============================================================================= +def old_run(args): + + # create parser + logger = multi_out() + logger.register('stderr', sys.stderr) + logger2 = multi_out() + logger2.register('stdout', sys.stdout) + + parser = CCTBXParser( + program_class=undowser2.Program, + logger=logger) + namespace = parser.parse_args(sys.argv[1:]) + + # start program + print('Starting job', file=logger) + print('='*79, file=logger) + task = undowser2.Program( + parser.data_manager, parser.working_phil.extract(), logger=logger2) + + # validate inputs + task.validate() + + # run program + task.run() + + # stop timer + print('', file=logger) + print('='*79, file=logger) + print('Job complete', file=logger) + show_total_time(out=logger) + +# ============================================================================= +if __name__ == '__main__': + #run(sys.argv[1:]) + run_program(program_class=undowser2.Program, hide_parsing_output=True) diff --git a/mmtbx/probe/Helpers.py b/mmtbx/probe/Helpers.py index eb5e0b54d9..782403fe7a 100644 --- a/mmtbx/probe/Helpers.py +++ b/mmtbx/probe/Helpers.py @@ -386,6 +386,12 @@ def getExtraAtomInfo(model, bondedNeighborLists, useNeutronDistances = False, pr if hb_type == "D" or hb_type == "B": extra.isDonor = True + # Get the first non-blank character of the alternate for this atom. + # If there is none, set the value to the empty string. If there is, set + # it to a string with just that character. + alt = a.parent().altloc.strip() + extra.altLoc = alt + extra.charge = probeExt.atom_charge(a) # For ions, the Richardsons determined in discussion with @@ -848,7 +854,7 @@ def Test(inFileName = None): ATOM 445 O HIS A 61 29.744 32.217 7.397 1.00 9.97 O ATOM 446 CB HIS A 61 27.707 33.547 5.385 1.00 9.38 C ATOM 447 CG HIS A 61 26.382 33.956 4.808 1.00 8.78 C -ATOM 448 ND1 HIS A 61 26.168 34.981 3.980 1.00 9.06 N +ATOM 448 ND1AHIS A 61 26.168 34.981 3.980 1.00 9.06 N ATOM 449 CD2 HIS A 61 25.174 33.397 5.004 1.00 11.08 C ATOM 450 CE1 HIS A 61 24.867 35.060 3.688 1.00 12.84 C ATOM 451 NE2 HIS A 61 24.251 34.003 4.297 1.00 11.66 N @@ -905,24 +911,24 @@ def __init__(self): # Spot check the values on the atoms for standard, neutron distances, # and original Probe results. standardChecks = [ - # Name, vdwRadius, isAcceptor, isDonor, isIon - ["CU", 0.72, False, False, True], - ["N", 1.55, False, True, False], - ["ND1", 1.55, False, True, False], - ["C", 1.65, False, False, False], - ["CB", 1.7, False, False, False], - ["O", 1.4, True, False, False], - ["CD2", 1.75, False, False, False] + # Name, vdwRadius, isAcceptor, isDonor, isDummyHydrogen, isIon, charge, altLoc + ["CU", 0.72, False, False, False, True, 0, ''], + ["N", 1.55, False, True, False, False, 0, ''], + ["ND1", 1.55, False, True, False, False, 0, 'A'], + ["C", 1.65, False, False, False, False, 0, ''], + ["CB", 1.7, False, False, False, False, 0, ''], + ["O", 1.4, True, False, False, False, 0, ''], + ["CD2", 1.75, False, False, False, False, 0, ''] ] neutronChecks = [ - # Name, vdwRadius, isAcceptor, isDonor, isIon - ["CU", 0.72, False, False, True], - ["N", 1.55, False, True, False], - ["ND1", 1.55, False, True, False], - ["C", 1.65, False, False, False], - ["CB", 1.7, False, False, False], - ["O", 1.4, True, False, False], - ["CD2", 1.75, False, False, False] + # Name, vdwRadius, isAcceptor, isDummyHydrogen, isDonor, isIon, charge, altLoc + ["CU", 0.72, False, False, False, True, 0, ''], + ["N", 1.55, False, True, False, False, 0, ''], + ["ND1", 1.55, False, True, False, False, 0, 'A'], + ["C", 1.65, False, False, False, False, 0, ''], + ["CB", 1.7, False, False, False, False, 0, ''], + ["O", 1.4, True, False, False, False, 0, ''], + ["CD2", 1.75, False, False, False, False, 0, ''] ] # Situations to run the test in and expected results: @@ -979,7 +985,9 @@ def __init__(self): assert e.isDummyHydrogen == False, "Helpers.Test(): Bad Dummy Hydrogen status for "+a.name+runType e.isDummyHydrogen = True assert e.isDummyHydrogen == True, "Helpers.Test(): Can't set DummyHydrogen status for "+a.name+runType - assert e.isIon == c[4], "Helpers.Test(): Bad Ion status for "+a.name+": "+str(e.isIon)+runType + assert e.isIon == c[5], "Helpers.Test(): Bad Ion status for "+a.name+": "+str(e.isIon)+runType + assert e.charge == c[6], "Helpers.Test(): Bad charge for "+a.name+": "+str(e.charge)+runType + assert e.altLoc == c[7], "Helpers.Test(): Bad altLoc for "+a.name+": "+str(e.altLoc)+", wanted "+str(c[7])+runType #======================================================================== # Run unit test on getPhantomHydrogensFor(). diff --git a/mmtbx/probe/Scoring.cpp b/mmtbx/probe/Scoring.cpp index 9cd410aa6b..6a750d3fd4 100644 --- a/mmtbx/probe/Scoring.cpp +++ b/mmtbx/probe/Scoring.cpp @@ -168,6 +168,11 @@ DotScorer::CheckDotResult DotScorer::check_dot( continue; } + // If we're in incompatible conformations, then we can't interact. + if (!compatible_conformations(sourceExtra.getAltLoc(), bExtra.getAltLoc())) { + continue; + } + // At this point, we are within the probe radius past the edge, so we're in contention // to be the nearest atom. Find the distance from the dot rather than from the probe // to check our actual interaction behavior. @@ -509,6 +514,14 @@ unsigned DotScorer::count_surface_dots(iotbx::pdb::hierarchy::atom const &source return ret; } +bool DotScorer::compatible_conformations(std::string const& a1, std::string const& a2) +{ + if (a1.size() == 0 || a1[0] == ' ' || a2.size() == 0 || a2[0] == ' ') { + return true; + } + return a1 == a2; +} + //=========================================================================================================== // Testing code below here @@ -521,6 +534,34 @@ std::string DotScorer::test() { /// @todo Check the annular-dots behavior. + // Check compatible_conformations() for all combinations of altlocs. + { + if (!compatible_conformations("", "")) { + return "DotScorer::test(): Compatible conformations failed for both nul"; + } + if (!compatible_conformations("A", "")) { + return "DotScorer::test(): Compatible conformations failed for A and nul"; + } + if (!compatible_conformations("", "A")) { + return "DotScorer::test(): Compatible conformations failed for nul and A"; + } + if (!compatible_conformations(" ", " ")) { + return "DotScorer::test(): Compatible conformations failed for both blank"; + } + if (!compatible_conformations("A", " ")) { + return "DotScorer::test(): Compatible conformations failed for A and blank"; + } + if (!compatible_conformations(" ", "A")) { + return "DotScorer::test(): Compatible conformations failed for blank and A"; + } + if (!compatible_conformations("A", "A")) { + return "DotScorer::test(): Compatible conformations failed for both A"; + } + if (compatible_conformations("A", "B")) { + return "DotScorer::test(): Compatible conformations falsely succeeded for A and B"; + } + } + // Check trim_dots(), which along with check_dot() will also check point_inside_atoms(). { double targetRad = 1.5, sourceRad = 1.0; @@ -578,6 +619,71 @@ std::string DotScorer::test() } } + // Test the check_dot() function for atoms in different alternate conformations + { + double targetRad = 1.5, sourceRad = 1.0, probeRad = 0.25; + DotSphere ds(sourceRad, 200); + unsigned int atomSeq = 0; + + // Construct and fill the SpatialQuery information + // with a vector of a single target atom, including its extra info. + iotbx::pdb::hierarchy::atom a; + a.set_xyz(vec3(0, 0, 0)); + a.set_occ(1.0); + a.data->i_seq = atomSeq++; + scitbx::af::shared atoms; + atoms.push_back(a); + SpatialQuery sq(atoms); + ExtraAtomInfo e(targetRad, true); + + // Construct an empty exclusion list. + scitbx::af::shared exclude; + + // Construct a source atom, including its extra info. + // This will be a hydrogen but not a donor. + iotbx::pdb::hierarchy::atom source; + source.set_occ(1.0); + source.data->i_seq = atomSeq++; + ExtraAtomInfo se(sourceRad); + atoms.push_back(source); + ScoreDotsResult res; + + // Check the source atom just overlapping with the target. + source.set_xyz(vec3(targetRad + sourceRad - 0.1, 0, 0)); + + std::vector altlocs; + altlocs.push_back(""); + altlocs.push_back(" "); + altlocs.push_back("A"); + altlocs.push_back("B"); + for (size_t i = 0; i < altlocs.size(); i++) { + e.setAltLoc(altlocs[i]); + + for (size_t j = 0; j < altlocs.size(); j++) { + se.setAltLoc(altlocs[j]); + + // Make the extra atom info map match the new state. + scitbx::af::shared infos; + infos.push_back(e); + infos.push_back(se); + + // Construct the scorer with updated information. + DotScorer as(ExtraAtomInfoMap(atoms, infos)); + + res = as.score_dots(source, 1, sq, sourceRad + targetRad, + probeRad, exclude, ds.dots(), ds.density(), false); + if (!res.valid) { + return "DotScorer::test(): Could not score dots for alternate conformation test case"; + } + bool zero = res.totalScore() == 0; + if (zero != !DotScorer::compatible_conformations(e.getAltLoc(), se.getAltLoc())) { + return "DotScorer::test(): Unexpected nonzero value for alternate conformation test case '" + e.getAltLoc() + + "' vs. '" + se.getAltLoc() + "'"; + } + } + } + } + // Test the check_dot() function to make sure that it gets correct interaction types for // all ranges of interaction. Also check the cause. { @@ -1421,7 +1527,7 @@ std::string DotScorer::test() unsigned int atomSeq = 0; // Construct and fill the SpatialQuery information - // with a vector of a single target atom, including its extra info looked up by + // with a vector of a single target atom, including its extra info. iotbx::pdb::hierarchy::atom a; a.set_xyz(vec3( 0,0,0 )); a.set_occ(1); diff --git a/mmtbx/probe/Scoring.h b/mmtbx/probe/Scoring.h index b305e44ac9..1737d6b4fb 100644 --- a/mmtbx/probe/Scoring.h +++ b/mmtbx/probe/Scoring.h @@ -88,13 +88,15 @@ namespace molprobity { public: /// @brief Constructor with default parameters ExtraAtomInfo(double vdwRadius = 0, bool isAcceptor = false, bool isDonor = false, - bool isDummyHydrogen = false, bool isIon = false, int charge = 0) + bool isDummyHydrogen = false, bool isIon = false, int charge = 0, std::string altLoc = " ") : m_vdwRadius(vdwRadius), m_isAcceptor(isAcceptor), m_isDonor(isDonor) - , m_isDummyHydrogen(isDummyHydrogen), m_isIon(isIon), m_charge(charge) {} + , m_isDummyHydrogen(isDummyHydrogen), m_isIon(isIon), m_charge(charge) + , m_altLoc(altLoc) {} /// @brief Constructor from another ExtraAtomInfo ExtraAtomInfo(const ExtraAtomInfo &e) : m_vdwRadius(e.m_vdwRadius), m_isAcceptor(e.m_isAcceptor), m_isDonor(e.m_isDonor) - , m_isDummyHydrogen(e.m_isDummyHydrogen), m_isIon(e.m_isIon), m_charge(e.m_charge) {} + , m_isDummyHydrogen(e.m_isDummyHydrogen), m_isIon(e.m_isIon), m_charge(e.m_charge) + , m_altLoc(e.m_altLoc) {} /// @brief Get and set methods double getVdwRadius() const { return m_vdwRadius; } @@ -102,15 +104,22 @@ namespace molprobity { bool getIsAcceptor() const { return m_isAcceptor; } void setIsAcceptor(bool val) { m_isAcceptor = val; } + bool getIsDonor() const { return m_isDonor; } void setIsDonor(bool val) { m_isDonor = val; } + bool getIsDummyHydrogen() const { return m_isDummyHydrogen; } void setIsDummyHydrogen(bool val) { m_isDummyHydrogen = val; } + bool getIsIon() const { return m_isIon; } void setIsIon(bool val) { m_isIon = val; } + int getCharge() const { return m_charge; } void setCharge(int val) { m_charge = val; } + std::string getAltLoc() const { return m_altLoc; } + void setAltLoc(std::string val) { m_altLoc = val; } + /// @brief == operator is required so that we can wrap the standard vector operators in Boost::Python bool operator ==(ExtraAtomInfo const& o) { return ((getVdwRadius() == o.getVdwRadius()) @@ -119,6 +128,7 @@ namespace molprobity { && (getIsDummyHydrogen() == o.getIsDummyHydrogen()) && (getIsIon() == o.getIsIon()) && (getCharge() == o.getCharge()) + && (getAltLoc() == o.getAltLoc()) ); } bool operator !=(ExtraAtomInfo const& o) { return !(*this == o); } @@ -131,6 +141,7 @@ namespace molprobity { /// hydrogen bonds to nearby acceptors. bool m_isIon; ///< Is this an ion? int m_charge; ///< The integer charge of the atom: -2, -1, 0, 1, 2 + std::string m_altLoc; ///< The alternate location indicator for the atom }; //===================================================================================================== @@ -387,6 +398,12 @@ namespace molprobity { //=========================================================================== // Seldom-used methods below here. + /// @brief See if the two atoms are in compatible conformations. + /// @param [in] a1 First atom altloc to compare + /// @param [in] a2 Second atom altloc to compare + /// @return True if the atoms are in compatible conformations, false otherwise. + static bool compatible_conformations(std::string const& a1, std::string const& a2); + /// @brief Test method to verify that the class is behaving as intended. /// @return Empty string on success, string telling what went wrong on failure. static std::string test(); diff --git a/mmtbx/probe/boost_python/probe_bpl.cpp b/mmtbx/probe/boost_python/probe_bpl.cpp index 100742e859..b53e473f71 100644 --- a/mmtbx/probe/boost_python/probe_bpl.cpp +++ b/mmtbx/probe/boost_python/probe_bpl.cpp @@ -58,7 +58,7 @@ BOOST_PYTHON_MODULE(mmtbx_probe_ext) ; class_("ExtraAtomInfo") - .def(init< optional >()) + .def(init< optional >()) .def(init()) .add_property("vdwRadius", &ExtraAtomInfo::getVdwRadius, &ExtraAtomInfo::setVdwRadius) .add_property("isAcceptor", &ExtraAtomInfo::getIsAcceptor, &ExtraAtomInfo::setIsAcceptor) @@ -66,6 +66,7 @@ BOOST_PYTHON_MODULE(mmtbx_probe_ext) .add_property("isDummyHydrogen", &ExtraAtomInfo::getIsDummyHydrogen, &ExtraAtomInfo::setIsDummyHydrogen) .add_property("isIon", &ExtraAtomInfo::getIsIon, &ExtraAtomInfo::setIsIon) .add_property("charge", &ExtraAtomInfo::getCharge, &ExtraAtomInfo::setCharge) + .add_property("altLoc", &ExtraAtomInfo::getAltLoc, &ExtraAtomInfo::setAltLoc) ; // Define the flex array wrapping for this class because we take it as a parameter. scitbx::boost_python::container_conversions::tuple_mapping_variable_capacity< diff --git a/mmtbx/programs/probe2.py b/mmtbx/programs/probe2.py index de9dbd23cf..113bd73501 100644 --- a/mmtbx/programs/probe2.py +++ b/mmtbx/programs/probe2.py @@ -29,7 +29,7 @@ # @todo See if we can remove the shift and box once reduce_hydrogen is complete from cctbx.maptbx.box import shift_and_box_model -version = "4.1.0" +version = "4.2.0" master_phil_str = ''' profile = False @@ -145,11 +145,6 @@ .short_caption = Count dots, don't list .help = Count dots rather than listing all contacts (-countdots in probe) - hydrogen_bond_output = True - .type = bool - .short_caption = Output hydrogen-bond contacts - .help = Output hydrogen-bond contacts (-nohbout in probe) - record_added_hydrogens = False .type = bool .short_caption = Record Phantom Hydrogens @@ -700,6 +695,15 @@ def _scaled_atom_radius(self, a): raise Sorry("Invalid radius for atom look-up: "+myFullName+"; rad = "+str(rad)) return self.params.atom_radius_offset + (rad * self.params.atom_radius_scale) + + def _describe_atom_for_debug(self, a): + resName = a.parent().resname.strip().upper() + resID = str(a.parent().parent().resseq_as_int()) + chainID = a.parent().parent().parent().id + iCode = a.parent().parent().icode + alt = a.parent().altloc + return "{:>2s}{:>4s}{}{} {}{:1s}".format(chainID, resID, iCode, resName, a.name, alt) + # ------------------------------------------------------------------------------ def _atom_class_for(self, a): @@ -1242,13 +1246,13 @@ def _writeOutput(self, groupName, masterName): # Report count legend if any counts are nonzero. if _totalInteractionCount(self._MCMCCount) > 0: - ret += "@pointmaster 'M' {{McMc contacts}}\n" + ret += "@pointmaster 'M' {McMc contacts}\n" if _totalInteractionCount(self._SCSCCount) > 0: - ret += "@pointmaster 'S' {{ScSc contacts}}\n" + ret += "@pointmaster 'S' {ScSc contacts}\n" if _totalInteractionCount(self._MCSCCount) > 0: - ret += "@pointmaster 'P' {{McSc contacts}}\n" + ret += "@pointmaster 'P' {McSc contacts}\n" if _totalInteractionCount(self._otherCount) > 0: - ret += "@pointmaster 'O' {{Hets contacts}}\n" + ret += "@pointmaster 'O' {Hets contacts}\n" # Report binned gap legend if we're binning gaps if self.params.output.bin_gaps: @@ -1911,9 +1915,8 @@ def run(self): self._atomClasses[a] = self._atom_class_for(a) else: # For hydrogen, assign based on what it is bonded to. - if len(self._allBondedNeighborLists[a]) != 1: - raise Sorry("Found Hydrogen with number of bonds other than 1: "+ - str(len(self._allBondedNeighborLists[a]))) + if len(self._allBondedNeighborLists[a]) < 1: + raise Sorry("Found Hydrogen with no neigbors: " + self._describe_atom_for_debug(a)) else: self._atomClasses[a] = self._atom_class_for(self._allBondedNeighborLists[a][0]) @@ -1934,9 +1937,8 @@ def run(self): self._inMainChain[a] = mainchain_sel[a.i_seq] else: # Check our bonded neighbor to see if it is on the mainchain if we are a Hydrogen - if len(self._allBondedNeighborLists[a]) != 1: - raise Sorry("Found Hydrogen with number of neigbors other than 1: "+ - str(len(self._allBondedNeighborLists[a]))) + if len(self._allBondedNeighborLists[a]) < 1: + raise Sorry("Found Hydrogen with no neigbors: " + self._describe_atom_for_debug(a)) else: self._inMainChain[a] = mainchain_sel[self._allBondedNeighborLists[a][0].i_seq] self._inSideChain[a] = sidechain_sel[a.i_seq] @@ -1951,9 +1953,8 @@ def run(self): if Helpers.isPolarHydrogen(a, self._allBondedNeighborLists): foundPolar = True elif a.element_is_hydrogen(): - if len(self._allBondedNeighborLists[a]) != 1: - raise Sorry("Found Hydrogen with number of neighbors other than 1: "+ - str(len(self._allBondedNeighborLists[a]))) + if len(self._allBondedNeighborLists[a]) < 1: + raise Sorry("Found Hydrogen with no neigbors: " + self._describe_atom_for_debug(a)) else: neighbor = self._allBondedNeighborLists[a][0] if neighbor.element == 'C': diff --git a/mmtbx/programs/reduce2.py b/mmtbx/programs/reduce2.py index bd7f4c40cf..e1e223202d 100644 --- a/mmtbx/programs/reduce2.py +++ b/mmtbx/programs/reduce2.py @@ -36,7 +36,7 @@ from iotbx.data_manager import DataManager import csv -version = "2.4.0" +version = "2.5.0" master_phil_str = ''' approach = *add remove @@ -1019,7 +1019,7 @@ def _AddHydrogens(self): keep_existing_H=self.params.keep_existing_H ) reduce_add_h_obj.run() - reduce_add_h_obj.show(None) + reduce_add_h_obj.show(self.logger) missed_residues = set(reduce_add_h_obj.no_H_placed_mlq) if len(missed_residues) > 0: bad = "" @@ -1076,9 +1076,8 @@ def _GetAtomCharacteristics(self, bondedNeighborLists): inMainChain[a] = mainchain_sel[a.i_seq] else: # Check our bonded neighbor to see if it is on the mainchain if we are a Hydrogen - if len(bondedNeighborLists[a]) != 1: - raise Sorry("Found Hydrogen with number of neigbors other than 1: "+ - str(len(bondedNeighborLists[a]))) + if len(bondedNeighborLists[a]) < 1: + raise Sorry("Found Hydrogen with no neigbors.") else: inMainChain[a] = mainchain_sel[bondedNeighborLists[a][0].i_seq] inSideChain[a] = sidechain_sel[a.i_seq] diff --git a/mmtbx/programs/undowser2.py b/mmtbx/programs/undowser2.py new file mode 100644 index 0000000000..ff2145e291 --- /dev/null +++ b/mmtbx/programs/undowser2.py @@ -0,0 +1,78 @@ +""" +Water-atom clash analysis. +This is a rewrite of the original undowser. This version uses mmtbx.reduce and +mmtbx.probe to generate the contact information rather than stand-alone programs. +It take the same parameters as the original clashscore (except for time_limit) +and it also takes mmtbx.probe parameters. +""" + +from __future__ import absolute_import, division, print_function + +import os +from mmtbx.validation.undowser2 import undowserlyze +from libtbx.program_template import ProgramTemplate +from datetime import datetime +from mmtbx.probe import Helpers + +class Program(ProgramTemplate): + prog = os.getenv('LIBTBX_DISPATCHER_NAME') + description="""\ +%(prog)s file.pdb [params.eff] [options ...] + +Options: + + model=input_file input PDB file + outliers_only=False only print outliers + keep_hydrogens=False keep input hydrogen atoms if True, regenerate if False + nuclear=False use nuclear x-H distances and vdW radii + json=False Outputs results as JSON compatible dictionary + verbose=False verbose text output + +Example: + + %(prog)s model=1ubq.pdb outliers_only=True +""" % locals() + + master_phil_str = """ + include scope mmtbx.validation.molprobity_cmdline_phil_str + show_errors = False + .type = bool + .help = '''Print out errors''' + keep_hydrogens = False + .type = bool + .help = '''Keep hydrogens in input file''' + nuclear = False + .type = bool + .help = '''Use nuclear hydrogen positions''' + json = False + .type = bool + .help = "Prints results as JSON format dictionary" + use_parent = False + .type = bool + """ + Helpers.probe_phil_parameters + datatypes = ['model','phil'] + data_manager_options = ['model_skip_expand_with_mtrix'] + known_article_ids = ['molprobity'] + + def validate(self): + self.data_manager.has_models(raise_sorry=True) + + def run(self): + self.info_json = {"model_name":self.data_manager.get_default_model_name(), + "time_analyzed": str(datetime.now())} + self.results = undowserlyze( + self.params.probe, + data_manager=self.data_manager, + keep_hydrogens=self.params.keep_hydrogens, + nuclear=self.params.nuclear, + outliers_only=self.params.outliers_only,) + if self.params.json: + print(self.results.as_JSON(), file=self.logger) + else: + print(self.results.as_HTML()) + + def get_results(self): + return self.results + + def get_results_as_JSON(self): + return self.results.as_JSON(self.info_json) diff --git a/mmtbx/regression/kins/Fe_1brf_snip_reduced.kin b/mmtbx/regression/kins/Fe_1brf_snip_reduced.kin index 76d176c700..9f9af1a882 100644 --- a/mmtbx/regression/kins/Fe_1brf_snip_reduced.kin +++ b/mmtbx/regression/kins/Fe_1brf_snip_reduced.kin @@ -8,10 +8,10 @@ @master {bad overlap} @master {worse overlap} @master {H-bond} -@pointmaster 'M' {{McMc contacts}} -@pointmaster 'S' {{ScSc contacts}} -@pointmaster 'P' {{McSc contacts}} -@pointmaster 'O' {{Hets contacts}} +@pointmaster 'M' {McMc contacts} +@pointmaster 'S' {ScSc contacts} +@pointmaster 'P' {McSc contacts} +@pointmaster 'O' {Hets contacts} @dotlist {x} color=white master={vdw contact} { CA ALA 1 A}sky 'O' 22.726,-1.645,3.714 {"}sky 'O' 22.641,-1.401,3.725 diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index 2c09aba050..279d93b686 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -290,6 +290,7 @@ "$D/validation/regression/tst_symmetry_SS.py", "$D/validation/regression/tst_do_flips_clashscore.py", "$D/validation/regression/tst_find_region_max_value.py", + "$D/validation/regression/tst_undowser2.py", # "$D/refinement/tst_select_best_starting_model.py", "$D/regression/tst_refine_anomalous_substructure.py", diff --git a/mmtbx/validation/clashscore2.py b/mmtbx/validation/clashscore2.py index 714433bc00..553c0cd965 100644 --- a/mmtbx/validation/clashscore2.py +++ b/mmtbx/validation/clashscore2.py @@ -132,7 +132,6 @@ def __init__(self, r.append_model(mdc) occ_max = flex.max(r.atoms().extract_occ()) - input_str = r.as_pdb_string() # Make yet another model for the new hierarchy subset_model_manager = mmtbx.model.manager( @@ -619,7 +618,7 @@ def check_and_add_hydrogen( assert probe_parameters assert data_manager_model if keep_hydrogens: - elements = data_manager_model.get_hierarchy.root().atoms().extract_element() + elements = data_manager_model.get_hierarchy().atoms().extract_element() # strangely the elements can have a space when coming from phenix.clashscore # but no space when coming from phenix.molprobity h_count = elements.count('H') @@ -649,7 +648,7 @@ def check_and_add_hydrogen( keep_existing_H=False ) reduce_add_h_obj.run() - reduce_add_h_obj.show(None) + reduce_add_h_obj.show(log) missed_residues = set(reduce_add_h_obj.no_H_placed_mlq) if len(missed_residues) > 0: bad = "" diff --git a/mmtbx/validation/regression/tst_undowser.py b/mmtbx/validation/regression/tst_undowser.py index 9b6bf7b3e0..c46e3f86f8 100644 --- a/mmtbx/validation/regression/tst_undowser.py +++ b/mmtbx/validation/regression/tst_undowser.py @@ -175,11 +175,11 @@

Clash with polar - HOH that clashes with polar groups may actually be a coordinated ion.
-Clash with nonpolar - HOH that clashes with nonpolar groups may be a missing or displaced atom*. +Clash with nonpolar - HOH that clashes with nonpolar groups may be a missing or displaced atom*. Or it may be the first atom of an unmodeled alternate.
Clash with both polar and nonpolar - HOH that clashes with both polar and non-polar groups is unlikely to be an ion. If clashes are severe, a displaced atom is likely. If clashes and map are weak, the HOH may be entirely removable.
-Clash with water - HOH-HOH clashes may be real waters that need to be modeled as alternates of compatible occupancy. Or they may indicate missing or displaced atoms. +Clash with water - HOH-HOH clashes may be real waters that need to be modeled as alternates of compatible occupancy. Or they may be in the density of a sidechain alternate or a larger ligand.
Clash with altloc - HOH clashes involving one or more alternate conformations may be resolved by renaming some of the alternates.

@@ -191,7 +191,7 @@
Missing atoms have been entirely replaced by HOH. Removed atoms may be restored by modeling alternate conformations (especially sidechains), modeling ligands, or continuing a macromolecular mainchain.

-These categories are general suggestions. Check your electron density; trust your intuition and experience. +These categories are general suggestions. Check your electron density; trust your intuition and experience. Prisant 2020 Prot Sci 29:315 (
https://doi.org/10.1002/pro.3786) illustrates 10 examples of clashing HOH cases.


diff --git a/mmtbx/validation/regression/tst_undowser2.py b/mmtbx/validation/regression/tst_undowser2.py new file mode 100644 index 0000000000..4b4f94cd08 --- /dev/null +++ b/mmtbx/validation/regression/tst_undowser2.py @@ -0,0 +1,282 @@ +from __future__ import absolute_import, division, print_function +from mmtbx.validation import undowser2 +from libtbx.easy_pickle import loads +from iotbx.data_manager import DataManager +import libtbx.load_env +from libtbx.utils import null_out +import iotbx +from mmtbx.programs import probe2 +import time +import json +import difflib + +pdb_1lpl_str = """MODEL 1 +ATOM 85 N ILE A 146 4.850 13.830 60.452 1.00 31.46 N +ATOM 86 CA ILE A 146 5.654 15.038 60.565 1.00 28.74 C +ATOM 87 C ILE A 146 5.963 15.310 62.021 1.00 27.82 C +ATOM 88 O ILE A 146 5.062 15.510 62.825 1.00 28.89 O +ATOM 89 CB ILE A 146 4.956 16.280 59.905 1.00 27.45 C +ATOM 90 CG1 ILE A 146 4.674 15.994 58.416 1.00 25.50 C +ATOM 91 CG2 ILE A 146 5.850 17.543 60.072 1.00 23.19 C +ATOM 92 CD1 ILE A 146 3.970 17.121 57.673 1.00 27.89 C +ATOM 0 H ILE A 146 4.003 13.950 60.365 1.00 31.46 H new +ATOM 0 HA ILE A 146 6.481 14.891 60.080 1.00 28.74 H new +ATOM 0 HB ILE A 146 4.110 16.447 60.348 1.00 27.45 H new +ATOM 0 HG12 ILE A 146 5.515 15.805 57.971 1.00 25.50 H new +ATOM 0 HG13 ILE A 146 4.132 15.192 58.350 1.00 25.50 H new +ATOM 0 HG21 ILE A 146 5.413 18.306 59.662 1.00 23.19 H new +ATOM 0 HG22 ILE A 146 5.989 17.719 61.016 1.00 23.19 H new +ATOM 0 HG23 ILE A 146 6.707 17.393 59.642 1.00 23.19 H new +ATOM 0 HD11 ILE A 146 3.831 16.862 56.749 1.00 27.89 H new +ATOM 0 HD12 ILE A 146 3.113 17.299 58.091 1.00 27.89 H new +ATOM 0 HD13 ILE A 146 4.517 17.921 57.705 1.00 27.89 H new +ATOM 137 N GLU A 153 11.342 19.816 53.414 1.00 18.86 N +ATOM 138 CA GLU A 153 11.328 20.597 52.204 1.00 20.88 C +ATOM 139 C GLU A 153 9.887 21.060 51.996 1.00 20.14 C +ATOM 140 O GLU A 153 8.976 20.225 51.945 1.00 18.33 O +ATOM 141 CB GLU A 153 11.771 19.754 51.024 1.00 20.67 C +ATOM 142 CG GLU A 153 11.890 20.570 49.780 1.00 28.25 C +ATOM 143 CD GLU A 153 12.021 19.708 48.543 1.00 35.57 C +ATOM 144 OE1 GLU A 153 11.164 18.803 48.342 1.00 39.43 O +ATOM 145 OE2 GLU A 153 12.981 19.939 47.779 1.00 36.90 O +ATOM 0 H GLU A 153 10.727 19.216 53.448 1.00 18.86 H new +ATOM 0 HA GLU A 153 11.935 21.350 52.274 1.00 20.88 H new +ATOM 0 HB2 GLU A 153 12.625 19.340 51.224 1.00 20.67 H new +ATOM 0 HB3 GLU A 153 11.135 19.036 50.881 1.00 20.67 H new +ATOM 0 HG2 GLU A 153 11.111 21.141 49.694 1.00 28.25 H new +ATOM 0 HG3 GLU A 153 12.662 21.153 49.850 1.00 28.25 H new +ATOM 618 N VAL A 216 4.506 19.838 52.802 1.00 21.99 N +ATOM 619 CA VAL A 216 5.738 19.509 53.507 1.00 24.27 C +ATOM 620 C VAL A 216 6.150 18.056 53.346 1.00 26.17 C +ATOM 621 O VAL A 216 5.340 17.143 53.546 1.00 26.47 O +ATOM 622 CB VAL A 216 5.593 19.757 55.039 1.00 25.53 C +ATOM 623 CG1 VAL A 216 6.935 19.548 55.734 1.00 23.77 C +ATOM 624 CG2 VAL A 216 5.055 21.160 55.299 1.00 22.33 C +ATOM 0 H VAL A 216 3.828 19.373 53.053 1.00 21.99 H new +ATOM 0 HA VAL A 216 6.410 20.085 53.111 1.00 24.27 H new +ATOM 0 HB VAL A 216 4.960 19.119 55.404 1.00 25.53 H new +ATOM 0 HG11 VAL A 216 6.834 19.705 56.686 1.00 23.77 H new +ATOM 0 HG12 VAL A 216 7.238 18.638 55.586 1.00 23.77 H new +ATOM 0 HG13 VAL A 216 7.587 20.168 55.372 1.00 23.77 H new +ATOM 0 HG21 VAL A 216 4.969 21.302 56.255 1.00 22.33 H new +ATOM 0 HG22 VAL A 216 5.667 21.815 54.929 1.00 22.33 H new +ATOM 0 HG23 VAL A 216 4.186 21.256 54.879 1.00 22.33 H new +ATOM 634 N VAL A 218 9.047 15.495 54.747 1.00 24.30 N +ATOM 635 CA VAL A 218 9.980 15.425 55.854 1.00 25.59 C +ATOM 636 C VAL A 218 11.043 14.371 55.566 1.00 25.70 C +ATOM 637 O VAL A 218 10.781 13.407 54.869 1.00 25.17 O +ATOM 638 CB VAL A 218 9.161 15.143 57.136 1.00 26.71 C +ATOM 639 CG1 VAL A 218 9.460 13.782 57.688 1.00 28.12 C +ATOM 640 CG2 VAL A 218 9.374 16.262 58.126 1.00 28.81 C +ATOM 0 H VAL A 218 8.514 14.824 54.675 1.00 24.30 H new +ATOM 0 HA VAL A 218 10.460 16.258 55.979 1.00 25.59 H new +ATOM 0 HB VAL A 218 8.215 15.126 56.923 1.00 26.71 H new +ATOM 0 HG11 VAL A 218 8.933 13.635 58.489 1.00 28.12 H new +ATOM 0 HG12 VAL A 218 9.237 13.108 57.027 1.00 28.12 H new +ATOM 0 HG13 VAL A 218 10.403 13.721 57.906 1.00 28.12 H new +ATOM 0 HG21 VAL A 218 8.861 16.085 58.930 1.00 28.81 H new +ATOM 0 HG22 VAL A 218 10.316 16.321 58.351 1.00 28.81 H new +ATOM 0 HG23 VAL A 218 9.083 17.100 57.735 1.00 28.81 H new +TER 728 ILE A 218 +HETATM 731 O HOH A 503 7.663 18.549 58.083 1.00 71.06 O +HETATM 758 O HOH A 530 20.116 27.095 51.665 1.00 24.67 O +HETATM 765 O HOH A 537 14.778 21.226 48.211 1.00 27.98 O +HETATM 772 O HOH A 544 -5.198 25.804 53.682 1.00 21.10 O +HETATM 800 O HOH A 572 -6.768 26.204 53.124 1.00 14.71 O +HETATM 805 O HOH A 577 21.563 28.198 52.938 1.00 31.45 O +HETATM 812 O HOH A 585 -6.264 27.663 53.754 1.00 21.56 O +ENDMDL +MODEL 2 +ATOM 85 N ILE A 146 4.850 13.830 60.452 1.00 31.46 N +ATOM 86 CA ILE A 146 5.654 15.038 60.565 1.00 28.74 C +ATOM 87 C ILE A 146 5.963 15.310 62.021 1.00 27.82 C +ATOM 88 O ILE A 146 5.062 15.510 62.825 1.00 28.89 O +ATOM 89 CB ILE A 146 4.956 16.280 59.905 1.00 27.45 C +ATOM 90 CG1 ILE A 146 4.674 15.994 58.416 1.00 25.50 C +ATOM 91 CG2 ILE A 146 5.850 17.543 60.072 1.00 23.19 C +ATOM 92 CD1 ILE A 146 3.970 17.121 57.673 1.00 27.89 C +ATOM 0 H ILE A 146 4.003 13.950 60.365 1.00 31.46 H new +ATOM 0 HA ILE A 146 6.481 14.891 60.080 1.00 28.74 H new +ATOM 0 HB ILE A 146 4.110 16.447 60.348 1.00 27.45 H new +ATOM 0 HG12 ILE A 146 5.515 15.805 57.971 1.00 25.50 H new +ATOM 0 HG13 ILE A 146 4.132 15.192 58.350 1.00 25.50 H new +ATOM 0 HG21 ILE A 146 5.413 18.306 59.662 1.00 23.19 H new +ATOM 0 HG22 ILE A 146 5.989 17.719 61.016 1.00 23.19 H new +ATOM 0 HG23 ILE A 146 6.707 17.393 59.642 1.00 23.19 H new +ATOM 0 HD11 ILE A 146 3.831 16.862 56.749 1.00 27.89 H new +ATOM 0 HD12 ILE A 146 3.113 17.299 58.091 1.00 27.89 H new +ATOM 0 HD13 ILE A 146 4.517 17.921 57.705 1.00 27.89 H new +ATOM 137 N GLU A 153 11.342 19.816 53.414 1.00 18.86 N +ATOM 138 CA GLU A 153 11.328 20.597 52.204 1.00 20.88 C +ATOM 139 C GLU A 153 9.887 21.060 51.996 1.00 20.14 C +ATOM 140 O GLU A 153 8.976 20.225 51.945 1.00 18.33 O +ATOM 141 CB GLU A 153 11.771 19.754 51.024 1.00 20.67 C +ATOM 142 CG GLU A 153 11.890 20.570 49.780 1.00 28.25 C +ATOM 143 CD GLU A 153 12.021 19.708 48.543 1.00 35.57 C +ATOM 144 OE1 GLU A 153 11.164 18.803 48.342 1.00 39.43 O +ATOM 145 OE2 GLU A 153 12.981 19.939 47.779 1.00 36.90 O +ATOM 0 H GLU A 153 10.727 19.216 53.448 1.00 18.86 H new +ATOM 0 HA GLU A 153 11.935 21.350 52.274 1.00 20.88 H new +ATOM 0 HB2 GLU A 153 12.625 19.340 51.224 1.00 20.67 H new +ATOM 0 HB3 GLU A 153 11.135 19.036 50.881 1.00 20.67 H new +ATOM 0 HG2 GLU A 153 11.111 21.141 49.694 1.00 28.25 H new +ATOM 0 HG3 GLU A 153 12.662 21.153 49.850 1.00 28.25 H new +ATOM 618 N VAL A 216 4.506 19.838 52.802 1.00 21.99 N +ATOM 619 CA VAL A 216 5.738 19.509 53.507 1.00 24.27 C +ATOM 620 C VAL A 216 6.150 18.056 53.346 1.00 26.17 C +ATOM 621 O VAL A 216 5.340 17.143 53.546 1.00 26.47 O +ATOM 622 CB VAL A 216 5.593 19.757 55.039 1.00 25.53 C +ATOM 623 CG1 VAL A 216 6.935 19.548 55.734 1.00 23.77 C +ATOM 624 CG2 VAL A 216 5.055 21.160 55.299 1.00 22.33 C +ATOM 0 H VAL A 216 3.828 19.373 53.053 1.00 21.99 H new +ATOM 0 HA VAL A 216 6.410 20.085 53.111 1.00 24.27 H new +ATOM 0 HB VAL A 216 4.960 19.119 55.404 1.00 25.53 H new +ATOM 0 HG11 VAL A 216 6.834 19.705 56.686 1.00 23.77 H new +ATOM 0 HG12 VAL A 216 7.238 18.638 55.586 1.00 23.77 H new +ATOM 0 HG13 VAL A 216 7.587 20.168 55.372 1.00 23.77 H new +ATOM 0 HG21 VAL A 216 4.969 21.302 56.255 1.00 22.33 H new +ATOM 0 HG22 VAL A 216 5.667 21.815 54.929 1.00 22.33 H new +ATOM 0 HG23 VAL A 216 4.186 21.256 54.879 1.00 22.33 H new +ATOM 634 N VAL A 218 9.047 15.495 54.747 1.00 24.30 N +ATOM 635 CA VAL A 218 9.980 15.425 55.854 1.00 25.59 C +ATOM 636 C VAL A 218 11.043 14.371 55.566 1.00 25.70 C +ATOM 637 O VAL A 218 10.781 13.407 54.869 1.00 25.17 O +ATOM 638 CB VAL A 218 9.161 15.143 57.136 1.00 26.71 C +ATOM 639 CG1 VAL A 218 9.460 13.782 57.688 1.00 28.12 C +ATOM 640 CG2 VAL A 218 9.374 16.262 58.126 1.00 28.81 C +ATOM 0 H VAL A 218 8.514 14.824 54.675 1.00 24.30 H new +ATOM 0 HA VAL A 218 10.460 16.258 55.979 1.00 25.59 H new +ATOM 0 HB VAL A 218 8.215 15.126 56.923 1.00 26.71 H new +ATOM 0 HG11 VAL A 218 8.933 13.635 58.489 1.00 28.12 H new +ATOM 0 HG12 VAL A 218 9.237 13.108 57.027 1.00 28.12 H new +ATOM 0 HG13 VAL A 218 10.403 13.721 57.906 1.00 28.12 H new +ATOM 0 HG21 VAL A 218 8.861 16.085 58.930 1.00 28.81 H new +ATOM 0 HG22 VAL A 218 10.316 16.321 58.351 1.00 28.81 H new +ATOM 0 HG23 VAL A 218 9.083 17.100 57.735 1.00 28.81 H new +TER 728 ILE A 218 +HETATM 731 O HOH A 503 7.663 18.549 58.083 1.00 71.06 O +HETATM 758 O HOH A 530 20.116 27.095 51.665 1.00 24.67 O +HETATM 765 O HOH A 537 14.778 21.226 48.211 1.00 27.98 O +HETATM 772 O HOH A 544 -5.198 25.804 53.682 1.00 21.10 O +HETATM 805 O HOH A 577 21.563 28.198 52.938 1.00 31.45 O +HETATM 812 O HOH A 585 -6.264 27.663 53.754 1.00 21.56 O +ENDMDL +END +""" + +expected_undowser_html = """ + + Summary table of water clashes + + + + +
+This table lists all HOH "waters" in the structure that have steric clashes. HOH are classified into common categories based on the atom they clash with. +

+A clashing HOH is very unlikely be be a real water, unless the clashing atom position is incorrect. The following categories provide guidance for correcting false HOH. +

+Clash with polar - HOH that clashes with polar groups may actually be a coordinated ion. +
+Clash with nonpolar - HOH that clashes with nonpolar groups may be a missing or displaced atom*. Or it may be the first atom of an unmodeled alternate. +
+Clash with both polar and nonpolar - HOH that clashes with both polar and non-polar groups is unlikely to be an ion. If clashes are severe, a displaced atom is likely. If clashes and map are weak, the HOH may be entirely removable. +
+Clash with water - HOH-HOH clashes may be real waters that need to be modeled as alternates of compatible occupancy. Or they may be in the density of a sidechain alternate or a larger ligand. +
+Clash with altloc - HOH clashes involving one or more alternate conformations may be resolved by renaming some of the alternates. +

+High B-factor - HOH with clashes and minimal support in the map should be removed from the model. This table does not report map data directly, but a high B-factor is a likely warning sign that an HOH is a poor fit to the map. +
+Severe clash - HOH with severe clash overlap but good map support is likely to be a position where an atom is displaced. +

+*Displaced atom indicates that a structural atom has been moved from its proper place in the model and replaced by HOH. Displaced sidechains are common. Moved atoms may be restored by local rebuilding. +
+Missing atoms have been entirely replaced by HOH. Removed atoms may be restored by modeling alternate conformations (especially sidechains), modeling ligands, or continuing a macromolecular mainchain. +

+These categories are general suggestions. Check your electron density; trust your intuition and experience. Prisant 2020 Prot Sci 29:315 (https://doi.org/10.1002/pro.3786) illustrates 10 examples of clashing HOH cases. +
+
+
+SUMMARY: 7 waters out of 7 have clashes (100.00%) +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Water IDClashes withWater BContact BClash
Severity
Clash with Polar
May be ion
Clash with non-polar
Unmodeled alt or noise
Clash with water
Occ <1 or ligand
Clash with altloc
Add or rename alts
A: 572 :HOH: 
 O   of A: 585 :HOH: 
14.7121.561.133×
 O   of A: 544 :HOH: 
14.7121.101.086×
A: 585 :HOH: 
 O   of A: 572 :HOH: 
21.5614.711.133×
 O   of A: 544 :HOH: 
21.5621.100.656×
A: 544 :HOH: 
 O   of A: 572 :HOH: 
21.1014.711.086×
 O   of A: 585 :HOH: 
21.1021.560.656×
A: 503 :HOH: 
HG11 of A: 216 :VAL: 
71.0623.770.626×
HG23 of A: 218 :VAL: 
71.0628.810.562×
HG23 of A: 146 :ILE: 
71.0623.190.456×
 CG1 of A: 216 :VAL: 
71.0623.770.446×
A: 530 :HOH: 
 O   of A: 577 :HOH: 
24.6731.450.579×
A: 577 :HOH: 
 O   of A: 530 :HOH: 
31.4524.670.579×
A: 537 :HOH: 
 OE2 of A: 153 :GLU: 
27.9836.900.548+ ion
+""" + +def exercise_undowser(probe_params): + dm = DataManager() + #print(help(dm)) + dm.process_model_str("1",pdb_1lpl_str) + m = dm.get_model("1") + uz = undowser2.undowserlyze(probe_params, dm) + undowser_html = uz.as_HTML() + diff = difflib.unified_diff(undowser_html.splitlines(), expected_undowser_html.splitlines(), fromfile="testvalue", tofile="expectedvalue") + changed_lines = "" + for line in diff: + if line.startswith("-") or line.startswith("+"): + changed_lines = changed_lines+"\n"+line + assert changed_lines == "", "undowser html output changed, at the following lines: "+changed_lines + +def exercise_undowser_json(probe_params): + dm = DataManager() + #print(help(dm)) + dm.process_model_str("1",pdb_1lpl_str) + m = dm.get_model("1") + uz = undowser2.undowserlyze(probe_params, dm) + uz_dict = json.loads(uz.as_JSON()) + #import pprint + #pprint.pprint(csjson_dict) + assert len(uz_dict['flat_results']) == 13, "tst_undowser2 json output not returning correct number of water clashes, now: "+str(len(uz_dict['flat_results'])) + assert uz_dict['flat_results'][0]["src_atom_id"] == " A 503 HOH O ", "tst_undowser2 json output first src_atom_id value changed, now: "+uz_dict['flat_results'][0]["src_atom_id"] + from mmtbx.validation import test_utils + assert test_utils.count_dict_values(uz_dict['hierarchical_results'], "water clash")==12, "tst_undowser2 json hierarchical output total number of water clashes changed, now: "+str(test_utils.count_dict_values(uz_dict['hierarchical_results'], "water clash")) + assert test_utils.count_dict_values(uz_dict['hierarchical_results'], "nonpolar clash")==8, "tst_undowser2 json hierarchical output total number of nonpolar clashes changed, now: "+str(test_utils.count_dict_values(uz_dict['hierarchical_results'], "nonpolar clash")) + assert test_utils.count_dict_values(uz_dict['hierarchical_results'], "polar clash")==2, "tst_undowser2 json hierarchical output total number of polar clashes changed, now: "+str(test_utils.count_dict_values(uz_dict['hierarchical_results'], "polar clash")) + assert uz_dict['summary_results'][" 1"]["num_outliers"] == 7, "tst_undowser2 json summary output total number of water clashes changed, now: "+str(uz_dict['summary_results'][" 1"]["num_outliers"]) + assert uz_dict['summary_results'][" 1"]["num_waters"] == 7, "tst_undowser2 json summary output total number of waters changed" + +if (__name__ == "__main__"): + if (not libtbx.env.has_module(name="probe")): + print("Skipping exercise_undowser(): probe not configured") + print("OK") + else: + parser = iotbx.cli_parser.CCTBXParser(program_class=probe2.Program, logger=null_out()) + args = [ 'approach=once' ] + parser.parse_args(args) + probe_params = parser.working_phil.extract() + t0 = time.time() + exercise_undowser(probe_params) + exercise_undowser_json(probe_params) + print("OK. Time: %8.3f"%(time.time()-t0)) diff --git a/mmtbx/validation/undowser2.py b/mmtbx/validation/undowser2.py new file mode 100644 index 0000000000..54323279b9 --- /dev/null +++ b/mmtbx/validation/undowser2.py @@ -0,0 +1,664 @@ +from __future__ import absolute_import, division, print_function + +import sys +from mmtbx.programs import probe2 +from cctbx.maptbx.box import shift_and_box_model +from mmtbx.validation import validation, atoms, residue, atom_info +from mmtbx.validation.clashscore2 import check_and_add_hydrogen, probe_clashscore_manager +from mmtbx.validation.clashscore2 import remove_models_except_index +from libtbx.utils import null_out +import json +import iotbx.cli_parser +import mmtbx +import os +import tempfile + +class ud_water(residue): + __ud_water_attr__ = [ + "contacts", + "model_id", + "src_atom_id" + #"max_b_factor", + ] + __slots__ = residue.__slots__ + __ud_water_attr__ + + @staticmethod + def header(): + return "%-20s %-20s %7s %7s %7s %-20s" % ("Water ID", "Clashes with", "Water B", "Contact B", "Clash severity", "Category") + + def as_JSON(self): + serializable_slots = [s for s in self.__slots__ if s != "contacts" and hasattr(self, s) ] + slots_as_dict = ({s: getattr(self, s) for s in serializable_slots}) + wc_list = [] + for wc in self.contacts: + wc_slots_list = [s for s in wc.__slots__ if s != "atoms_info" and s != "src_atom_id"] + wc_slots_as_dict = {s: getattr(wc, s) for s in wc_slots_list if s != 'xyz' and s != "atom_selection"} + wc_list.append(wc_slots_as_dict) + slots_as_dict["water_contacts"] = wc_list + #print({**slots_as_dict, **atom0_slots_as_dict}) + return json.dumps(slots_as_dict, indent=2) + + def as_hierarchical_JSON(self): + hierarchical_dict = {} + hierarchy_nest_list = ['model_id', 'chain_id', 'resid', 'altloc'] + return json.dumps(self.nest_dict(hierarchy_nest_list, hierarchical_dict), indent=2) + + def as_string(self): + return "%-20s %-20s %7.3f" % (self.atoms_info[0].id_str(), + self.atoms_info[1].id_str(), abs(self.overlap)) + + def as_table_row_phenix(self): + rows = [] + for wc in self.contacts: + rows.append([self.id_str(), wc.atoms_info[1].id_str(), wc.src_b, wc.trg_b, wc.mingap, wc.get_category()]) + return rows + + def get_contacts(self): + return self.contacts + +#-u -q -mc -het -once -NOVDWOUT %s %s' % (probe_command, condensed_flag, nuclear_flag) "ogt%d not water" "ogt%d" -' % (ogt, ogt) +# phenix.probe -4H -quiet -noticks -nogroup -dotmaster -mc -het -once -wat2wat 'water' 'water' + +class undowserlyze(validation): + __slots__ = validation.__slots__ + [ + "fast", + "condensed_probe", + "probe_file", + "probe_undowser_manager", + "water_count", + "results_by_model" + ] + program_description = "Analyze waters for model" + gui_list_headers = ["Water ID", "Clashes with", "Water B", "Contact B", "Clash severity", "Category"] + gui_formats = ["%s", "%s", ".2f", ".2f", ".3f", "%s"] + wx_column_widths = [150, 150, 150, 150, 150, 300] #actually set in GUI's Molprobity/Core.py + html_header = """ + + Summary table of water clashes + + + + +
+This table lists all HOH "waters" in the structure that have steric clashes. HOH are classified into common categories based on the atom they clash with. +

+A clashing HOH is very unlikely be be a real water, unless the clashing atom position is incorrect. The following categories provide guidance for correcting false HOH. +

+Clash with polar - HOH that clashes with polar groups may actually be a coordinated ion. +
+Clash with nonpolar - HOH that clashes with nonpolar groups may be a missing or displaced atom*. Or it may be the first atom of an unmodeled alternate. +
+Clash with both polar and nonpolar - HOH that clashes with both polar and non-polar groups is unlikely to be an ion. If clashes are severe, a displaced atom is likely. If clashes and map are weak, the HOH may be entirely removable. +
+Clash with water - HOH-HOH clashes may be real waters that need to be modeled as alternates of compatible occupancy. Or they may be in the density of a sidechain alternate or a larger ligand. +
+Clash with altloc - HOH clashes involving one or more alternate conformations may be resolved by renaming some of the alternates. +

+High B-factor - HOH with clashes and minimal support in the map should be removed from the model. This table does not report map data directly, but a high B-factor is a likely warning sign that an HOH is a poor fit to the map. +
+Severe clash - HOH with severe clash overlap but good map support is likely to be a position where an atom is displaced. +

+*Displaced atom indicates that a structural atom has been moved from its proper place in the model and replaced by HOH. Displaced sidechains are common. Moved atoms may be restored by local rebuilding. +
+Missing atoms have been entirely replaced by HOH. Removed atoms may be restored by modeling alternate conformations (especially sidechains), modeling ligands, or continuing a macromolecular mainchain. +

+These categories are general suggestions. Check your electron density; trust your intuition and experience. Prisant 2020 Prot Sci 29:315 (https://doi.org/10.1002/pro.3786) illustrates 10 examples of clashing HOH cases. +
+
+
+""" + + html_table = """ +

+
+
+ + + + + + + + + + +""" + + def get_result_class(self): + return ud_water + + def __init__(self, + probe_parameters, + data_manager, + keep_hydrogens=True, + nuclear=False, + outliers_only=False, + force_unique_chain_ids=False, + b_factor_cutoff=None, + save_modified_hierarchy=False, + verbose=False, + do_flips=False, + out=sys.stdout): + validation.__init__(self) + if verbose: + if not nuclear: + print("\nUsing electron cloud x-H distances and vdW radii") + else: + print("\nUsing nuclear cloud x-H distances and vdW radii") + import iotbx.pdb + from scitbx.array_family import flex + from mmtbx.validation import utils + + data_manager_model = data_manager.get_model() + # Fix up bogus unit cell when it occurs by checking crystal symmetry. + # @todo reduce_hydrogens.py:run() says: TODO temporary fix until the code is moved to model class + cs = data_manager_model.crystal_symmetry() + if (cs is None) or (cs.unit_cell() is None): + data_manager_model = shift_and_box_model(model = data_manager_model) + + # If we've been asked to, add hydrogens to all of the models in the PDB hierarchy + # associated with our data_manager_model. + data_manager_model,_ = check_and_add_hydrogen( + probe_parameters=probe_parameters, + data_manager_model=data_manager_model, + nuclear=nuclear, + verbose=verbose, + keep_hydrogens=keep_hydrogens, + do_flips = do_flips, + log=null_out()) + + # First we must rebuild the model from the new hierarchy so that the copy can succeed. + # Make a copy of the original model to use for submodel processing, we'll trim atoms out + # of it for each submodel. + data_manager_model = mmtbx.model.manager( + model_input = None, + pdb_hierarchy = data_manager_model.get_hierarchy(), + stop_for_unknowns = False, + crystal_symmetry = data_manager_model.crystal_symmetry(), + restraint_objects = None, + log = null_out()) + original_model = data_manager_model.deep_copy() + + pdb_hierarchy = data_manager_model.get_hierarchy() + n_models = len(pdb_hierarchy.models()) + use_segids = utils.use_segids_in_place_of_chainids( + hierarchy=pdb_hierarchy) + + # Get information about the waters in the model + sel_cache = pdb_hierarchy.atom_selection_cache() + water_sel= sel_cache.selection("water") + hierarchy_waters = pdb_hierarchy.select(water_sel) + self.water_count = len(list(hierarchy_waters.residue_groups())) + water_xyzs = {} + self.results_by_model = {} + for atom in hierarchy_waters.atoms(): + if atom.name == " O ": + water_xyzs[atom.parent().parent().resid()] = atom.xyz + model_id = atom.parent().parent().parent().parent().id + if model_id not in self.n_total_by_model: + self.n_total_by_model[model_id] = 0 + self.n_total_by_model[model_id] += 1 + + for i_mod, model in enumerate(pdb_hierarchy.models()): + if model.id not in self.results_by_model: + self.results_by_model[model.id] = [] + self.n_outliers_by_model[model.id] = 0 + # Select only the current submodel from the hierarchy + submodel = original_model.deep_copy() + remove_models_except_index(submodel, i_mod) + + # Construct a hierarchy for the current submodel + r = iotbx.pdb.hierarchy.root() + mdc = submodel.get_hierarchy().models()[0].detached_copy() + r.append_model(mdc) + + occ_max = flex.max(r.atoms().extract_occ()) + + # Make yet another model for the new hierarchy + subset_model_manager = mmtbx.model.manager( + model_input = None, + pdb_hierarchy = r, + stop_for_unknowns = False, + crystal_symmetry = submodel.crystal_symmetry(), + restraint_objects = None, + log = null_out()) + + self.probe_undowser_manager = probe_undowser_manager( + nuclear=nuclear, + verbose=verbose, + model_id=model.id) + self.probe_undowser_manager.run_probe_undowser(data_manager, subset_model_manager) + water_contacts = self.probe_undowser_manager.get_water_contacts() + for src_atom_id, wc_list in water_contacts.items(): + src_chain_id=probe_undowser_manager.get_chain_probe_atom_id(src_atom_id) + src_resseq=probe_undowser_manager.get_resseq_probe_atom_id(src_atom_id) + src_icode=probe_undowser_manager.get_icode_probe_atom_id(src_atom_id) + src_resname=probe_undowser_manager.get_resname_probe_atom_id(src_atom_id) + src_altloc=probe_undowser_manager.get_altloc_probe_atom_id(src_atom_id) + #selection_string = "model {} and chain {} and resseq '{}' and altid '{}' and name O".format(model.id, src_chain_id, src_resseq, src_altloc) + result = ud_water( + outlier=True, + src_atom_id=src_atom_id, + model_id=model.id, + chain_id=src_chain_id, + resseq=src_resseq, + icode=src_icode, + resname=src_resname, + altloc=src_altloc, + segid=None, # XXX ??? + xyz=water_xyzs[src_resseq+src_icode], + contacts=wc_list, + ) + #if (not outliers_only or is_outlier): + self.results.append(result) + self.results_by_model[model.id].append(result) + self.n_outliers_by_model[model.id] += 1 + + def as_JSON(self, addon_json={}): + if not addon_json: + addon_json = {} + addon_json["validation_type"] = "undowser" + data = addon_json + flat_results = [] + hierarchical_results = {} + summary_results = {} + for result in self.results: + flat_results.append(json.loads(result.as_JSON())) + hier_result = json.loads(result.as_hierarchical_JSON()) + hierarchical_results = self.merge_dict(hierarchical_results, hier_result) + + data['flat_results'] = flat_results + data['hierarchical_results'] = hierarchical_results + + for model_id in self.n_total_by_model.keys(): + summary_results[model_id] = { "num_outliers" : self.n_outliers_by_model[model_id], + "num_waters" : self.n_total_by_model[model_id], + } + data['summary_results'] = summary_results + return json.dumps(data, indent=2) + + def as_HTML(self): + return self.as_html_table() + + #defaults to returning table corresponding to the first model, even if model_id isn't a valid input + def as_html_table(self, model_id=""): + if model_id not in self.results_by_model: + model_id = sorted(self.results_by_model.keys())[0] + model_results = self.results_by_model[model_id] + #this could probably be more efficient, this recreates a "water_contacts" object to avoid changing CJW's original HTML code + water_contacts = {} + for ud_water in model_results: + water_contacts[ud_water.src_atom_id]=ud_water.get_contacts() + + #water_contacts = self.probe_undowser_manager.get_water_contacts() + html_string = self.html_header + if self.water_count == 0: + html_string = html_string+"SUMMARY: %i waters out of %i have clashes (%.2f%%)" % (0, 0, 0) + else: + html_string = html_string+"SUMMARY: %i waters out of %i have clashes (%.2f%%)" % (len(water_contacts), self.n_total_by_model[model_id], len(water_contacts)/self.n_total_by_model[model_id]*100) + html_string = html_string + self.html_table + + contact_keys = sorted(water_contacts, key=lambda c: (-1*cumulative_severity(c, water_contacts))) + #simple reverse sorting may put waters with the same cumulative severity in reverse sequence order + + row_number = 0 + row_color = ['#eaeaea','#ffffff'] + for contact_key in contact_keys: + water = water_contacts[contact_key] + water.sort(key=lambda w: (-1*float(w.mingap))) + bgcolor = row_color[row_number%2] + html_string = html_string+"\n" % (bgcolor,len(water),water[0].format_src_id_str()) + row_number+=1 + clashcount = 0 + for clash in water: + if clashcount: html_string = html_string+'' % bgcolor + clashcount+=1 + html_string = html_string+"%s%s%s%s%s%s\n" % (clash.format_trg_id_str(), clash.write_b_cell(clash.src_b), clash.write_b_cell(clash.trg_b), clash.color_clash_severity(), clash.mingap, clash.write_polar_cell(), clash.write_nonpolar_cell(), clash.write_other_water_cell(), clash.write_altloc_cell()) + html_string = html_string+"
Water IDClashes withWater BContact BClash
Severity
Clash with Polar
May be ion
Clash with non-polar
Unmodeled alt or noise
Clash with water
Occ <1 or ligand
Clash with altloc
Add or rename alts
%s
%s
%s
" + return html_string + #out.write("%s%s%s%s%s%s\n" % (clash.format_trg_id_str(), clash.color_clash_severity(), clash.mingap, clash.does_it_clash_with_altloc(), clash.does_it_clash_with_polar(), clash.does_it_clash_with_nonpolar(), clash.does_it_clash_with_other_water())) + #out.write("%s%s\n" % (clash.format_trg_id_str(), clash.color_clash_severity(), clash.mingap, color_cell(clash.does_it_clash_with_polar()), color_cell(clash.does_it_clash_with_nonpolar()), color_cell(clash.does_it_clash_with_other_water()), color_cell(clash.does_it_clash_with_altloc()) )) + + #tr-level bgcolors for alternating table stripes + #bgcolor='#9999cc' (blue for column headers) + #bgcolor='#ffffff' (white background) + #bgcolor='#f0f0f0' (original gray for stripes) + #bgcolor='#eaeaea' (slightly darker gray for stripes) + +class water_contact(atoms): + wc_slots = ["model_id", + "src_atom_id", + "src_chain", + "src_resseq", + "src_icode", + "src_resname", + "src_atom", + "src_altloc", + "trg_heavy_atom", + "trg_chain", + "trg_resseq", + "trg_icode", + "trg_resname", + "trg_atom", + "trg_altloc", + "mingap", + "src_b", + "trg_b", + "category", + ] + + __slots__ = atoms.__slots__ + wc_slots + + def __init__(self, model_id, src_atom_id, trg_atom_id, trg_heavy_atom, mingap, src_b, trg_b): + self.model_id = model_id + self.src_atom_id = src_atom_id + #self.trg_atom_id = trg_atom_id + self.trg_heavy_atom = trg_heavy_atom + # A2778 HOH O A + self.atoms_info = [] + #ccnnnnirrr?aaaal + self.src_chain = probe_undowser_manager.get_chain_probe_atom_id(src_atom_id) + self.src_resseq = probe_undowser_manager.get_resseq_probe_atom_id(src_atom_id) + self.src_icode = probe_undowser_manager.get_icode_probe_atom_id(src_atom_id) + self.src_resname = probe_undowser_manager.get_resname_probe_atom_id(src_atom_id) + self.src_atom = probe_undowser_manager.get_atom_probe_atom_id(src_atom_id) + self.src_altloc = probe_undowser_manager.get_altloc_probe_atom_id(src_atom_id) + self.atoms_info.append(atom_info( + model_id=model_id, + chain_id=self.src_chain, + resseq=self.src_resseq, + icode=self.src_icode, + resname=self.src_resname, + altloc=self.src_altloc, + name=self.src_atom) + ) + + self.trg_chain = probe_undowser_manager.get_chain_probe_atom_id(trg_atom_id) + self.trg_resseq = probe_undowser_manager.get_resseq_probe_atom_id(trg_atom_id) + self.trg_icode = probe_undowser_manager.get_icode_probe_atom_id(trg_atom_id) + self.trg_resname = probe_undowser_manager.get_resname_probe_atom_id(trg_atom_id) + self.trg_atom = probe_undowser_manager.get_atom_probe_atom_id(trg_atom_id) + self.trg_altloc = probe_undowser_manager.get_altloc_probe_atom_id(trg_atom_id) + self.atoms_info.append(atom_info( + model_id=model_id, + chain_id=self.trg_chain, + resseq=self.trg_resseq, + icode=self.trg_icode, + resname=self.trg_resname, + altloc=self.trg_altloc, + name=self.trg_atom) + ) + + self.mingap = mingap.lstrip('-') + #main table lists all overlaps as positive + #the simple strip works as long as we only look at clashes + + self.src_b = float(src_b) + self.trg_b = float(trg_b) + self.outlier = True + self.score = 0.0 + self.category = self.get_category() + + def get_category(self): + category = "uncategorized" + if self.does_it_clash_with_polar(): + category = "polar clash" + if self.does_it_clash_with_nonpolar(): + category = "nonpolar clash" + if self.does_it_clash_with_other_water(): + category = "water clash" + if self.does_it_clash_with_altloc(): + if category != "uncategorized": + category = category + ", altloc clash" + else: + category = "altloc clash" + return category + + def trg_is_H(self): + if self.trg_atom.strip().startswith('H'): return True + else: return False + + def trg_is_charged_N(self): + #what N's can be charged in nucleic acids? + #how to handle the great variety of ligands? + if self.trg_resname == 'LYS' and self.trg_atom == ' NZ ': + return True + elif self.trg_resname == 'ARG' and self.trg_atom in [' NH1',' NH2']: + return True + elif self.trg_resname == 'HIS' and self.trg_atom in [' ND1',' NE2']: + return True + else: + return False + + def format_src_id_str(self): + return ":".join([self.src_chain,self.src_resseq+self.src_icode,self.src_resname,self.src_altloc]) + + def format_trg_id_str(self): + #return self.trg_heavy_atom+" of "+":".join([self.trg_chain,self.trg_resseq+self.trg_icode,self.trg_resname,self.trg_altloc]) + return self.trg_atom+" of "+":".join([self.trg_chain,self.trg_resseq+self.trg_icode,self.trg_resname,self.trg_altloc]) + + def color_clash_severity(self): + mingap = float(self.mingap) + if mingap < 0.5: return '#ffb3cc' + elif mingap > 0.9: return '#ee4d4d' + else: return '#ff76a9' + + def does_it_clash_with_polar(self): + #Polar atoms in proteins are O, N, and S + #Nucleic acids also have P, but that appears completely shielded by O's + #All O are polar. Are any N sufficiently non-polar that they wouldn't coordinate with metal? + #Another water does not count as polar for these purposes + #Not currently considering what polar atoms might be in ligands + if self.trg_resname == "HOH": + return '' + if self.trg_heavy_atom in ['O','S']: + return True + if self.trg_heavy_atom == 'N': + if self.trg_is_H(): + return True #H on N is polar + elif self.trg_is_charged_N(): + return True + return '' + + def does_it_clash_with_altloc(self): + #Goal is to find any clashes that might be resolved by different altloc naming + #A-A clashes, A-_ clashes, and _-A clashes + #Probe should automatically ignore any A-B contacts, since those are in fully different alts + if self.src_altloc.strip() or self.trg_altloc.strip(): + return True + else: + return '' + + def does_it_clash_with_other_water(self): + if self.trg_resname == "HOH": + return True + else: + return '' + + def does_it_clash_with_nonpolar(self): + #This is the most complex one and will likely receive iterations + #Start with simple check for non-polars + if self.trg_heavy_atom in ['C']: + return True + elif self.trg_is_H(): + if self.trg_heavy_atom in ['O','N','S']: + return '' + else: + return True + elif self.trg_heavy_atom in ['N']: + if not self.trg_is_charged_N(): + return True + return '' + + def write_polar_cell(self): + if self.does_it_clash_with_polar(): + trg_element = self.trg_atom.strip()[0:1] + if trg_element == 'H': + return "− ion" % self.color_clash_severity() + elif trg_element in ['O','S']: + return "+ ion" % self.color_clash_severity() + elif trg_element == 'N': + return "− ion" % self.color_clash_severity() + else: + return "*" % self.color_clash_severity() + else: + return "" + + def write_nonpolar_cell(self): + if self.does_it_clash_with_nonpolar(): + return "×" % self.color_clash_severity() + else: + return "" + + def write_altloc_cell(self): + if self.does_it_clash_with_altloc(): + if self.does_it_clash_with_other_water(): + return "alt water" % self.color_clash_severity() + elif self.src_altloc.strip() and self.trg_altloc.strip(): + return "alt both sides" % self.color_clash_severity() + elif self.src_altloc.strip(): + return "alt water" % self.color_clash_severity() + else: + return "alt partner atom" % self.color_clash_severity() + #return "×" % self.color_clash_severity() + else: + return "" + + def write_other_water_cell(self): + if self.does_it_clash_with_other_water(): + return "×" % self.color_clash_severity() + else: + return "" + + def write_b_cell(self, b): + return "%.2f" % b + +def cumulative_severity(contact_key, water_contacts): + cumulative_severity = 0 + water = water_contacts[contact_key] + for clash in water: + weighted_severity = float(clash.mingap) - 0.2 + cumulative_severity += weighted_severity + return cumulative_severity + +def color_cell(clash_check): + if clash_check: return 'bgcolor=#ff76a9' + else: return '' + +def count_waters(pdb_string): +#deprecated +#this is fragile and dependent on pdb format, but faster than hierarchy read-in + water_count = 0 + for line in pdb_string: + if line.startswith("HETATM") and line[17:20]=="HOH": + water_count += 1 + return water_count + +#this subclasses probe_clashscore_manager but doesn't really use most of it. It's mainly to reuse the code for checking for probe existance +class probe_undowser_manager(probe_clashscore_manager): + def __init__(self, + nuclear=False, + verbose=False, + model_id=""): + super().__init__( + fast = False, + condensed_probe=False, + nuclear=nuclear, + largest_occupancy=10, + b_factor_cutoff=None, + use_segids=False, + verbose=verbose, + model_id=model_id) + self.water_contacts = {} + + def run_probe_undowser(self, data_manager, hydrogenated_model): + + # Construct override parameters and then run probe2 using them and delete the resulting + # temporary file. + tempName = tempfile.mktemp() + parser = iotbx.cli_parser.CCTBXParser(program_class=probe2.Program, logger=null_out()) + #self.probe_command = "%s -u -q -mc -het -con -once -wat2wat -stdbonds -onlybadout 'water' 'all' -" % (self.probe_command) + args = [ + "source_selection='water'".format(self.occupancy_frac), + "target_selection='all'".format(self.occupancy_frac), + "use_neutron_distances={}".format(self.nuclear), + "approach=once", + "include_water_water=True", + "output.filename='{}'".format(tempName), + "output.format=raw", + "output.condensed=True", + "output.report_vdws=False", + "output.report_hydrogen_bonds=False", + "output.only_report_bad_clashes=True", + "ignore_lack_of_explicit_hydrogens=True", + ] + parser.parse_args(args) + p2 = probe2.Program(data_manager, parser.working_phil.extract(), + master_phil=parser.master_phil, logger=null_out()) + p2.overrideModel(hydrogenated_model) + dots, output = p2.run() + probe_unformatted = output.splitlines() + os.unlink(tempName) + #print("probe unformatted:"+str(probe_unformatted)) + + for line in probe_unformatted: +#>>name:pat:type:srcAtom:targAtom:dot-count:min-gap:gap:spX:spY:spZ:spikeLen:score:stype:ttype:x:y:z:sBval:tBval +#SelfIntersect +#:1->2:bo: A2778 HOH O A: A 464 ARG HD3 : 8:-0.581:-0.475: 36.509: 0.601: 18.650:0.238:-0.1485:O:C:36.622:0.786:18.552:30.97:17.73 +#:1->2:bo: A2001 HOH O A: A2013 HOH O A:14:-0.792:-0.442:-12.858:17.914:-23.935:0.221:-0.1381:O:O:-12.726:18.090:-23.907:21.07:14.91 + n = line.split(':') + contact_type = n[2] + src_atom_id = n[3] + trg_atom_id = n[4] + dotcount = n[5] + mingap = n[6] + #src_heavy_atom = n[13] #always the water O + trg_heavy_atom = n[14] #parent heavy atom of a clashing H + #gap = n[7] #meaningless in -condensed mode, use mingap instead + src_b = n[18] + trg_b = n[19].strip() + clash = water_contact(self.model_id, src_atom_id, trg_atom_id, trg_heavy_atom, mingap, src_b, trg_b) + + #sys.stdout.write(line) + #sys.stdout.write('\n') + polar_clash = clash.does_it_clash_with_polar() + alt_clash = clash.does_it_clash_with_altloc() + water_clash = clash.does_it_clash_with_other_water() + nonpolar_clash = clash.does_it_clash_with_nonpolar() + + if src_atom_id not in self.water_contacts: + self.water_contacts[src_atom_id] = [] + self.water_contacts[src_atom_id].append(clash) + + @staticmethod + def get_chain_probe_atom_id(atom_id): + if len(atom_id) == 16: + return atom_id[0:2].strip() + + @staticmethod + def get_resseq_probe_atom_id(atom_id): + if len(atom_id) == 16: + return atom_id[2:6] + + @staticmethod + def get_icode_probe_atom_id(atom_id): + if len(atom_id) == 16: + return atom_id[6:7] + + @staticmethod + def get_resname_probe_atom_id(atom_id): + if len(atom_id) == 16: + return atom_id[7:10] + + @staticmethod + def get_atom_probe_atom_id(atom_id): + if len(atom_id) == 16: + return atom_id[11:15] + + @staticmethod + def get_altloc_probe_atom_id(atom_id): + if len(atom_id) == 16: + return atom_id[15:16] + + def get_water_contacts(self): + return self.water_contacts From e7fab010de13d48c968f79d914c431f19d3e3561 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 25 Apr 2024 10:46:23 -0700 Subject: [PATCH 377/748] Tidy-up Phenix: remove cctbx dispatcher for phenix.diffuse --- cctbx/command_line/diffuse.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cctbx/command_line/diffuse.py b/cctbx/command_line/diffuse.py index d164b8fdca..d84ce989c6 100644 --- a/cctbx/command_line/diffuse.py +++ b/cctbx/command_line/diffuse.py @@ -1,4 +1,3 @@ -# LIBTBX_SET_DISPATCHER_NAME cctbx.diffuse # LIBTBX_SET_DISPATCHER_NAME phenix.diffuse from __future__ import absolute_import, division, print_function From f934f66f79b25f3e0b513cd8066c52c45997b646 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Thu, 25 Apr 2024 12:50:15 -0700 Subject: [PATCH 378/748] Bugfix: check all angles instead of just last one and add them one by one based on selection instead of discarding whole residue. --- mmtbx/geometry_restraints/reference.py | 1 + mmtbx/rotamer/sidechain_angles.py | 10 +++------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/mmtbx/geometry_restraints/reference.py b/mmtbx/geometry_restraints/reference.py index 2807a330ee..cb43812548 100644 --- a/mmtbx/geometry_restraints/reference.py +++ b/mmtbx/geometry_restraints/reference.py @@ -33,6 +33,7 @@ def generate_torsion_restraints( bool_pdbh_selection = flex.bool(pdb_hierarchy.atoms_size(), False) if (selection is not None): if (isinstance(selection, flex.bool)): + assert len(selection) == pdb_hierarchy.atoms_size() bool_pdbh_selection = selection elif (isinstance(selection, flex.size_t)): bool_pdbh_selection.set_selected(selection, True) diff --git a/mmtbx/rotamer/sidechain_angles.py b/mmtbx/rotamer/sidechain_angles.py index 23b70774ed..022c99e16d 100644 --- a/mmtbx/rotamer/sidechain_angles.py +++ b/mmtbx/rotamer/sidechain_angles.py @@ -236,13 +236,9 @@ def collect_sidechain_chi_angles(pdb_hierarchy, atom_selection=None): pass else : i_seqs = [ atom.i_seq for atom in atoms ] - chis.append(group_args(chi_id=i, i_seqs=i_seqs)) - atoms_in_selection = True - for i_seq in i_seqs: - if not actual_selection[i_seq]: - atoms_in_selection = False - break - if len(chis) > 0 and atoms_in_selection: + if actual_selection.select(flex.size_t(i_seqs)).all_eq(True): + chis.append(group_args(chi_id=i, i_seqs=i_seqs)) + if len(chis) > 0: residue_info = group_args( residue_name=residue.resname, chain_id=chain.id, From 8abacb35f2c5bb8bbcfc7d54b20f9b64849880a1 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Thu, 25 Apr 2024 17:04:33 -0700 Subject: [PATCH 379/748] Start testing annotation class with long chain/residue names --- .../tst_annotation_long.py | 100 ++++++++++++++++++ iotbx/run_tests.py | 1 + 2 files changed, 101 insertions(+) create mode 100644 iotbx/regression/secondary_structure/tst_annotation_long.py diff --git a/iotbx/regression/secondary_structure/tst_annotation_long.py b/iotbx/regression/secondary_structure/tst_annotation_long.py new file mode 100644 index 0000000000..881f072298 --- /dev/null +++ b/iotbx/regression/secondary_structure/tst_annotation_long.py @@ -0,0 +1,100 @@ +from __future__ import absolute_import, division, print_function +import time +from iotbx.pdb.secondary_structure import annotation +import iotbx +import iotbx.cif +from libtbx.test_utils import show_diff + +cif_one_helix = """\ +# +_struct_conf.conf_type_id HELX_P +_struct_conf.id HELX_P1 +_struct_conf.pdbx_PDB_helix_id AA1 +_struct_conf.beg_label_comp_id longGLN +_struct_conf.beg_label_asym_id longA +_struct_conf.beg_label_seq_id 149 +_struct_conf.pdbx_beg_PDB_ins_code ? +_struct_conf.end_label_comp_id longGLY +_struct_conf.end_label_asym_id longA +_struct_conf.end_label_seq_id 160 +_struct_conf.pdbx_end_PDB_ins_code ? +_struct_conf.beg_auth_comp_id alongGLN +_struct_conf.beg_auth_asym_id alongA +_struct_conf.beg_auth_seq_id 212 +_struct_conf.end_auth_comp_id alongGLY +_struct_conf.end_auth_asym_id alongA +_struct_conf.end_auth_seq_id 223 +_struct_conf.pdbx_PDB_helix_class 1 +_struct_conf.details ? +_struct_conf.pdbx_PDB_helix_length 12 +# +_struct_conf_type.id HELX_P +_struct_conf_type.criteria ? +_struct_conf_type.reference ? +""" + +def tst_helix_interface(): + cif_str = "data_1UCS" + cif_one_helix + cif_model = iotbx.cif.reader(input_string=cif_str).model() + cif_block = list(cif_model.values())[0] + ann = annotation.from_cif_block(cif_block) + h = ann.helices[0] + # + # !!! Note, here we got info from *auth* fields. + # + assert h.serial == 1 + assert h.helix_id == 'AA1', h.helix_id + assert h.start_resname == 'alongGLN', h.start_resname + assert h.start_chain_id == 'alongA' + assert h.start_resseq == ' 212', h.start_resseq + assert h.start_icode == ' ' + assert h.end_resname == 'alongGLY' + assert h.end_chain_id == 'alongA' + assert h.end_resseq == ' 223' + assert h.end_icode == ' ' + assert h.helix_class == 'alpha' + assert h.comment == '', "'%s'" % h.comment + assert h.length == 12, h.length + assert h.hbond_list == [] + assert h.helix_selection == None + assert h.enabled == True + assert h.sigma ==0.05 + assert h.slack ==0 + assert h.top_out == False + + assert h.get_start_resseq_as_int() == 212 + assert h.get_end_resseq_as_int() == 223 + assert not h.fits_in_pdb_format() + assert not ann.fits_in_pdb_format() + # print (h.as_pdb_or_mmcif_str()) + assert not show_diff(h.as_mmcif_str(), +"""data_phenix +loop_ + _struct_conf.conf_type_id + _struct_conf.id + _struct_conf.pdbx_PDB_helix_id + _struct_conf.beg_label_comp_id + _struct_conf.beg_label_asym_id + _struct_conf.beg_label_seq_id + _struct_conf.pdbx_beg_PDB_ins_code + _struct_conf.end_label_comp_id + _struct_conf.end_label_asym_id + _struct_conf.end_label_seq_id + _struct_conf.pdbx_end_PDB_ins_code + _struct_conf.pdbx_PDB_helix_class + _struct_conf.details + _struct_conf.pdbx_PDB_helix_length + HELX_P 1 AA1 alongGLN alongA 212 ? alongGLY alongA 223 ? 1 ? 12 + +loop_ + _struct_conf_type.id + _struct_conf_type.criteria + _struct_conf_type.reference + HELX_P ? ? + +""") + +if (__name__ == "__main__"): + t0 = time.time() + tst_helix_interface() + print("OK time =%8.3f"%(time.time() - t0)) diff --git a/iotbx/run_tests.py b/iotbx/run_tests.py index 43dbb473ce..652964b5a6 100644 --- a/iotbx/run_tests.py +++ b/iotbx/run_tests.py @@ -62,6 +62,7 @@ "$D/pdb/modified_rna_dna_names.py", "$D/regression/secondary_structure/tst_sheet.py", "$D/regression/secondary_structure/tst_annotation.py", + "$D/regression/secondary_structure/tst_annotation_long.py", "$D/pdb/secondary_structure.py", "$D/pdb/tst_atom_selection_string.py", "$D/pdb/tst_secondary_structure.py", From db52a2a3241045c87022b02d61d47af04f50d420 Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Fri, 26 Apr 2024 09:49:20 -0700 Subject: [PATCH 380/748] Fix test --- cctbx/regression/tst_diffuse.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cctbx/regression/tst_diffuse.py b/cctbx/regression/tst_diffuse.py index a034a91bc0..d78f8a3ff6 100644 --- a/cctbx/regression/tst_diffuse.py +++ b/cctbx/regression/tst_diffuse.py @@ -100,13 +100,13 @@ ENDMDL END """ -#cctbx.diffuse pdb=m.pdb probabilities=0.5,0.5 resolution=4.0 prefix=tst +#phenix.diffuse pdb=m.pdb probabilities=0.5,0.5 resolution=4.0 prefix=tst def exercise(): fo = open("tst_diffuse.pdb","w") print(pdb_str, file=fo) fo.close() cmd = " ".join([ - "cctbx.diffuse", + "phenix.diffuse", "pdb=tst_diffuse.pdb", "probabilities=0.5,0.5", "resolution=4.0", From 669ff59d9b9791c5f337caeef7b996e9dc36494a Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Fri, 26 Apr 2024 12:24:56 -0700 Subject: [PATCH 381/748] Test for sheet with long ids. --- .../tst_annotation_long.py | 148 ++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/iotbx/regression/secondary_structure/tst_annotation_long.py b/iotbx/regression/secondary_structure/tst_annotation_long.py index 881f072298..1268744d4e 100644 --- a/iotbx/regression/secondary_structure/tst_annotation_long.py +++ b/iotbx/regression/secondary_structure/tst_annotation_long.py @@ -33,6 +33,64 @@ _struct_conf_type.reference ? """ +cif_one_sheet = """\ +# +_struct_sheet.id A +_struct_sheet.type ? +_struct_sheet.number_strands 2 +_struct_sheet.details ? +# +_struct_sheet_order.sheet_id A +_struct_sheet_order.range_id_1 1 +_struct_sheet_order.range_id_2 2 +_struct_sheet_order.offset ? +_struct_sheet_order.sense anti-parallel +# +loop_ +_struct_sheet_range.sheet_id +_struct_sheet_range.id +_struct_sheet_range.beg_label_comp_id +_struct_sheet_range.beg_label_asym_id +_struct_sheet_range.beg_label_seq_id +_struct_sheet_range.pdbx_beg_PDB_ins_code +_struct_sheet_range.end_label_comp_id +_struct_sheet_range.end_label_asym_id +_struct_sheet_range.end_label_seq_id +_struct_sheet_range.pdbx_end_PDB_ins_code +_struct_sheet_range.symmetry +_struct_sheet_range.beg_auth_comp_id +_struct_sheet_range.beg_auth_asym_id +_struct_sheet_range.beg_auth_seq_id +_struct_sheet_range.end_auth_comp_id +_struct_sheet_range.end_auth_asym_id +_struct_sheet_range.end_auth_seq_id +A 1 longSER longA 4 ? longALA longA 7 ? ? alongSER alongA 4 alongALA alongA 7 +A 2 longMET longA 22 ? longGLU longA 25 ? ? alongMET alongA 22 alongGLU alongA 25 +# +_pdbx_struct_sheet_hbond.sheet_id A +_pdbx_struct_sheet_hbond.range_id_1 1 +_pdbx_struct_sheet_hbond.range_id_2 2 +_pdbx_struct_sheet_hbond.range_1_label_atom_id N +_pdbx_struct_sheet_hbond.range_1_label_comp_id longSER +_pdbx_struct_sheet_hbond.range_1_label_asym_id longA +_pdbx_struct_sheet_hbond.range_1_label_seq_id 4 +_pdbx_struct_sheet_hbond.range_1_PDB_ins_code ? +_pdbx_struct_sheet_hbond.range_1_auth_atom_id N +_pdbx_struct_sheet_hbond.range_1_auth_comp_id alongSER +_pdbx_struct_sheet_hbond.range_1_auth_asym_id alongA +_pdbx_struct_sheet_hbond.range_1_auth_seq_id 4 +_pdbx_struct_sheet_hbond.range_2_label_atom_id O +_pdbx_struct_sheet_hbond.range_2_label_comp_id longGLU +_pdbx_struct_sheet_hbond.range_2_label_asym_id longA +_pdbx_struct_sheet_hbond.range_2_label_seq_id 25 +_pdbx_struct_sheet_hbond.range_2_PDB_ins_code ? +_pdbx_struct_sheet_hbond.range_2_auth_atom_id O +_pdbx_struct_sheet_hbond.range_2_auth_comp_id alongGLU +_pdbx_struct_sheet_hbond.range_2_auth_asym_id alongA +_pdbx_struct_sheet_hbond.range_2_auth_seq_id 25 +# +""" + def tst_helix_interface(): cif_str = "data_1UCS" + cif_one_helix cif_model = iotbx.cif.reader(input_string=cif_str).model() @@ -94,7 +152,97 @@ def tst_helix_interface(): """) +def tst_sheet_interface(): + cif_str = "data_1UCS" + cif_one_sheet + cif_model = iotbx.cif.reader(input_string=cif_str).model() + cif_block = list(cif_model.values())[0] + ann = annotation.from_cif_block(cif_block) + + sh = ann.sheets[0] + st = sh.strands[1] + reg = sh.registrations[1] + + # + # !!! Note, here we got info from *auth* fields. + # + + assert reg.cur_atom == ' O ' + assert reg.cur_resname == 'alongGLU', reg.cur_resname + assert reg.cur_chain_id == 'alongA' + assert reg.cur_resseq == ' 25' + assert reg.cur_icode == ' ' + assert reg.prev_atom == ' N ' + assert reg.prev_resname == 'alongSER' + assert reg.prev_chain_id == 'alongA' + assert reg.prev_resseq == ' 4' + assert reg.prev_icode == ' ' + + assert st.sheet_id == 'A', st.sheet_id + assert st.strand_id == 2, st.strand_id + assert st.start_resname == 'alongMET',st.start_resname + assert st.start_chain_id == 'alongA' + assert st.start_resseq == ' 22', st.start_resseq + assert st.start_icode == ' ' + assert st.end_resname == 'alongGLU' + assert st.end_chain_id == 'alongA' + assert st.end_resseq == ' 25' + assert st.end_icode == ' ' + assert st.sense == -1 + + assert not sh.fits_in_pdb_format() + assert not ann.fits_in_pdb_format() + # print (sh.as_pdb_or_mmcif_str()) + assert not show_diff(sh.as_mmcif_str(), +"""data_phenix +loop_ + _struct_sheet.id + _struct_sheet.type + _struct_sheet.number_strands + _struct_sheet.details + A ? 2 ? + +loop_ + _struct_sheet_order.sheet_id + _struct_sheet_order.range_id_1 + _struct_sheet_order.range_id_2 + _struct_sheet_order.offset + _struct_sheet_order.sense + A 1 2 ? anti-parallel + +loop_ + _struct_sheet_range.sheet_id + _struct_sheet_range.id + _struct_sheet_range.beg_label_comp_id + _struct_sheet_range.beg_label_asym_id + _struct_sheet_range.beg_label_seq_id + _struct_sheet_range.pdbx_beg_PDB_ins_code + _struct_sheet_range.end_label_comp_id + _struct_sheet_range.end_label_asym_id + _struct_sheet_range.end_label_seq_id + _struct_sheet_range.pdbx_end_PDB_ins_code + A 1 alongSER alongA 4 ? alongALA alongA 7 ? + A 2 alongMET alongA 22 ? alongGLU alongA 25 ? + +loop_ + _pdbx_struct_sheet_hbond.sheet_id + _pdbx_struct_sheet_hbond.range_id_1 + _pdbx_struct_sheet_hbond.range_id_2 + _pdbx_struct_sheet_hbond.range_1_label_atom_id + _pdbx_struct_sheet_hbond.range_1_label_comp_id + _pdbx_struct_sheet_hbond.range_1_label_asym_id + _pdbx_struct_sheet_hbond.range_1_label_seq_id + _pdbx_struct_sheet_hbond.range_1_PDB_ins_code + _pdbx_struct_sheet_hbond.range_2_label_atom_id + _pdbx_struct_sheet_hbond.range_2_label_comp_id + _pdbx_struct_sheet_hbond.range_2_label_asym_id + _pdbx_struct_sheet_hbond.range_2_label_seq_id + _pdbx_struct_sheet_hbond.range_2_PDB_ins_code + A 1 2 N alongSER alongA 4 ? O alongGLU alongA 25 ? + +""") + if (__name__ == "__main__"): t0 = time.time() tst_helix_interface() + tst_sheet_interface() print("OK time =%8.3f"%(time.time() - t0)) From 656104a2c52a74f02273b13f7e3ce5c3fda655d8 Mon Sep 17 00:00:00 2001 From: terwill Date: Fri, 26 Apr 2024 18:36:41 -0600 Subject: [PATCH 382/748] Match holton scoring script --- mmtbx/validation/holton_geometry_validation.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 6591e2d671..bfa2be260c 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -71,7 +71,7 @@ def holton_geometry_validation(dm = None, minimum_nonbond_score_to_be_worst = -0.1, minimum_nonbond_score_to_be_included_in_average = 0, keep_hydrogens = False, # redo the hydrogens - ignore_cis_peptides = True, + ignore_cis_peptides = False, ignore_h_except_in_nonbond = True, ignore_arg_h_nonbond = True, ignore_bond_lengths_with_h = False, @@ -148,7 +148,7 @@ def add_clashscore_results(info): time_limit=120, save_modified_hierarchy=False, verbose=False, - do_flips=True, + do_flips=False, out=null_out()) for r in clashes.results: @@ -373,8 +373,8 @@ def analyze_geometry_values(info): if info.worst_clash_is_one_plus_n_times_worst_clash and \ result.name == 'CLASH': # Special case - result.worst_residual = abs( - 1 + len(result.value_list) * worst_value.residual) + result.worst_residual = \ + 1 + (len(result.value_list) * worst_value.residual) elif info.minimum_nonbond_score_to_be_worst is not None and \ result.name == 'NONBOND' and ( @@ -589,7 +589,7 @@ def add_omega_results(info): if info.round_numbers: sigma = float("%.3f" %(sigma)) new_v.residual=((math.sin(omega)/sigma)**2+ - (1+math.cos(omega))**10)/(n_pro+1) + (1+math.cos(omega))**10)/(n_pro*2+1) at = new_v.labels[0].atom new_v.as_string = "OMEGA: Energy = "+\ "%.6f (%s Proline) Angle: %.2f deg\n Residue: %s %s %s %s" %( From ec70db6ed1c0455e31c5062cb7d03fdec5b72c21 Mon Sep 17 00:00:00 2001 From: Pavel Date: Fri, 26 Apr 2024 18:15:13 -0700 Subject: [PATCH 383/748] Add altloc aware filtering of newly added water and re-setting conformer_indices --- mmtbx/utils/utils.h | 146 ++++++++++++++++++++++++++++++++++++++ mmtbx/utils/utils_ext.cpp | 22 ++++++ 2 files changed, 168 insertions(+) diff --git a/mmtbx/utils/utils.h b/mmtbx/utils/utils.h index 95b39ae772..c394530214 100644 --- a/mmtbx/utils/utils.h +++ b/mmtbx/utils/utils.h @@ -138,6 +138,152 @@ class density_distribution_per_atom af::shared map_values_; }; +template +af::shared + filter_water_fsr( + af::shared const& interaction_selection, + af::shared > const& sites_frac, + af::shared const& solvent_selection, + af::shared const& skip_selection, + af::ref conformer_indices, + FloatType const& dist_max, + FloatType const& dist_min, + FloatType const& dist_min_altloc, + cctbx::uctbx::unit_cell const& unit_cell) +{ + af::shared result; + af::shared first_shell; + af::shared second_shell; + MMTBX_ASSERT(interaction_selection.size()==sites_frac.size()); + MMTBX_ASSERT(solvent_selection.size() ==sites_frac.size()); + MMTBX_ASSERT(conformer_indices.size() ==sites_frac.size()); + // Select water that a) do not clash with any of non-water atom and b) are + // within prescribed limits (first_shell). + // Set aside others non-clashing (second_shell). + + for(std::size_t i=0; i sfw = sites_frac[i]; // water + bool skip = false; + std::size_t ci = conformer_indices[i]; + for(std::size_t j=0; j sfo = sites_frac[j]; // other than water + FloatType dist = unit_cell.distance(sfo, sfw); + if(dist=dist_min); + } + if(dist_closest_int>=dist_min) { + first_shell.push_back(i); + } + else { + if(dist_closest_int>=dist_min_altloc) { + first_shell.push_back(i); + MMTBX_ASSERT(cj_closest>0); + if(ci==cj_closest || ci==0) { + if(cj_closest==1) { + conformer_indices[i] = cj_closest+1; + } + else { + conformer_indices[i] = cj_closest-1; + } + } + } + } + } + else { // This may need a more carefull re-thinking.. Not sure what ends up here. + second_shell.push_back(i); + } + } + // Now check those set aside (second_shell) and fill into result + for(std::size_t i=0; i sfi = sites_frac[second_shell[i]]; + bool skip = false; + for(std::size_t j=0; j sfj = sites_frac[first_shell[j]]; + FloatType dist = unit_cell.distance(sfi, sfj); + if(dist=dist_min) { + result.push_back(second_shell[i]); + } + } + // Add first shell into result + for(std::size_t i=0; i sfii = sites_frac[ii]; + FloatType dist_best = 1.e+9; + std::size_t jj_best = -1; + for(std::size_t j=0; j sfjj = sites_frac[jj]; + FloatType dist = unit_cell.distance(sfii, sfjj); + if(dist < dist_best) { + dist_best = dist; + jj_best = jj; + } + } + if(dist_best=dist_min_altloc) { + std::size_t cii = conformer_indices[ii]; + std::size_t cjj = conformer_indices[jj_best]; + + if(cii==cjj) { // both are the same + if(cii==0) { // both are zero + conformer_indices[ii]=1; + conformer_indices[jj_best]=2; + } + else { // both are the same and not zero + if(cii==1) conformer_indices[jj_best]=cii+1; + else conformer_indices[jj_best]=cii-1; + } + } + else { // not the same + if(cii==0) { + if(cjj==1) conformer_indices[ii]=cjj+1; + else conformer_indices[ii]=cjj-1; + } + else { + if(cii==1) conformer_indices[jj_best]=cii+1; + else conformer_indices[jj_best]=cii-1; + } + } + } + } + return result; +} + template af::shared filter_water( diff --git a/mmtbx/utils/utils_ext.cpp b/mmtbx/utils/utils_ext.cpp index d64744789f..9e82c3db50 100644 --- a/mmtbx/utils/utils_ext.cpp +++ b/mmtbx/utils/utils_ext.cpp @@ -54,6 +54,28 @@ namespace { ; // + def("filter_water_fsr", + (af::shared(*) + (af::shared const&, + af::shared > const&, + af::shared const&, + af::shared const&, + af::ref, + double const&, + double const&, + double const&, + cctbx::uctbx::unit_cell const&)) filter_water_fsr, + (arg("interaction_selection"), + arg("sites_frac"), + arg("solvent_selection"), + arg("skip_selection"), + arg("conformer_indices"), + arg("dist_max"), + arg("dist_min"), + arg("dist_min_altloc"), + arg("unit_cell"))) + ; + def("filter_water", (af::shared(*) (af::shared const&, From 95836fdc4608137ec715457b0c6e37bef8319e22 Mon Sep 17 00:00:00 2001 From: Pavel Date: Fri, 26 Apr 2024 18:16:38 -0700 Subject: [PATCH 384/748] Keep track of relationshipt between altloc ID (letter) and conformer indices --- iotbx/pdb/hierarchy.py | 10 ++++++++-- mmtbx/ligands/electrons.py | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index b92600fb99..172653a846 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -1830,10 +1830,16 @@ def get_conformer_indices(self): if ("" in altloc_indices): p = 0 else: p = 1 altlocs = sorted(altloc_indices.keys()) + index_altloc_mapping = {} for i,altloc in enumerate(altlocs): - if (altloc == ""): continue + if (altloc == ""): + index_altloc_mapping[altloc]=0 + continue conformer_indices.set_selected(altloc_indices[altloc], i+p) - return conformer_indices + index_altloc_mapping[altloc]=i+p + return group_args( + conformer_indices = conformer_indices, + index_altloc_mapping = index_altloc_mapping) def sort_chains_by_id(self): chain_ids = self.chain_ids() diff --git a/mmtbx/ligands/electrons.py b/mmtbx/ligands/electrons.py index 21e3f914c6..e04a1966fe 100644 --- a/mmtbx/ligands/electrons.py +++ b/mmtbx/ligands/electrons.py @@ -128,7 +128,7 @@ def __init__(self, else: self.logger = log self.verbose=verbose - if [_f for _f in hierarchy.get_conformer_indices() if _f]: + if [_f for _f in hierarchy.get_conformer_indices().conformer_indices if _f]: assert (alternative_location_id is not None or alternative_location_index is not None) for atom in self.atoms: From 8c2808e23df3f14cbd8e367f5a7528955486603b Mon Sep 17 00:00:00 2001 From: Pavel Date: Fri, 26 Apr 2024 18:18:59 -0700 Subject: [PATCH 385/748] Do not compute map internally (this is very dirty) --- mmtbx/find_peaks.py | 92 ++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 51 deletions(-) diff --git a/mmtbx/find_peaks.py b/mmtbx/find_peaks.py index f3dee58aa7..247ce6f71c 100644 --- a/mmtbx/find_peaks.py +++ b/mmtbx/find_peaks.py @@ -101,56 +101,48 @@ def sort(self, reverse=False): class manager(object): def __init__(self, - fmodel, - map_type, map_cutoff, + xray_structure, params = None, log = None, - use_all_data = True, - silent = False, - map_coeffs=None + # Fourier map or... + map_coeffs=None, + # ...real-space map or... + map_data = None, ): adopt_init_args(self, locals()) - assert (map_type is not None) or (map_coeffs is not None) + # Make sure unique only-needed maps or map source is given + assert [map_coeffs, map_data].count(None) == 1 + # self.mapped = False self.peaks_ = None if(self.log is None): self.log = sys.stdout if(self.params is None): self.params = master_params.extract() - self.crystal_symmetry = self.fmodel.xray_structure.crystal_symmetry() - self.crystal_gridding = maptbx.crystal_gridding( - unit_cell = self.crystal_symmetry.unit_cell(), - space_group_info = self.crystal_symmetry.space_group_info(), + # + crystal_symmetry = xray_structure.crystal_symmetry() + crystal_gridding = maptbx.crystal_gridding( + unit_cell = crystal_symmetry.unit_cell(), + space_group_info = crystal_symmetry.space_group_info(), symmetry_flags = maptbx.use_space_group_symmetry, step = self.params.grid_step) - if (map_coeffs is not None): + crystal_gridding_tags = maptbx.crystal_gridding_tags( + gridding = crystal_gridding) + # + if(map_coeffs is not None): fft_map = map_coeffs.fft_map( - crystal_gridding = self.crystal_gridding, + crystal_gridding = crystal_gridding, symmetry_flags=maptbx.use_space_group_symmetry) if(self.params.use_sigma_scaled_maps): fft_map.apply_sigma_scaling() - map_units = "sigma" else: fft_map.apply_volume_scaling() - map_units = "e/A**3" fft_map_data = fft_map.real_map_unpadded() - else: - fft_map = self.fmodel.electron_density_map().map_coefficients( - map_type = self.map_type, - fill_missing = False, - isotropize = True).fft_map( - crystal_gridding = self.crystal_gridding, - symmetry_flags=maptbx.use_space_group_symmetry) - if(self.params.use_sigma_scaled_maps): - fft_map.apply_sigma_scaling() - map_units = "sigma" - else: - fft_map.apply_volume_scaling() - map_units = "e/A**3" - fft_map_data = fft_map.real_map_unpadded() - crystal_gridding_tags = fft_map.tags() + elif(map_data is not None): + fft_map_data = map_data + # max_number_of_peaks = self.params.max_number_of_peaks if(self.params.max_number_of_peaks is None): - max_number_of_peaks = self.fmodel.xray_structure.scatterers().size() * 5 + max_number_of_peaks = self.xray_structure.scatterers().size() * 5 negative = False if(self.map_cutoff < 0): self.map_cutoff *= -1 @@ -158,8 +150,7 @@ def __init__(self, fft_map_data *= -1 min_distance_sym_equiv = self.params.peak_search.min_distance_sym_equiv if(min_distance_sym_equiv is None): - min_distance_sym_equiv = \ - self.fmodel.xray_structure.min_distance_sym_equiv() + min_distance_sym_equiv = self.xray_structure.min_distance_sym_equiv() peak_search_parameters = maptbx.peak_search_parameters( peak_search_level = self.params.peak_search.peak_search_level, max_peaks = self.params.peak_search.max_peaks, @@ -169,19 +160,18 @@ def __init__(self, general_positions_only = self.params.peak_search.general_positions_only, min_cross_distance = self.params.peak_search.min_cross_distance, min_cubicle_edge = self.params.peak_search.min_cubicle_edge) - if(self.fmodel.r_work() > 0.00001 and self.fmodel.r_free() > 0.00001): - cluster_analysis = crystal_gridding_tags.peak_search( - parameters = peak_search_parameters, - map = fft_map_data).all(max_clusters = max_number_of_peaks) - heights = cluster_analysis.heights() - if(negative): - heights *= -1. - self.peaks_ = peaks_holder(heights = heights, - sites = cluster_analysis.sites()) - if(not self.silent): - print("Number of peaks found at %s map (map cutoff=%s %s)= %s"%( - self.map_type, format_value("%-5.2f", self.map_cutoff).strip(), - map_units, format_value("%-12d", self.peaks_.sites.size())), file=self.log) + cluster_analysis = crystal_gridding_tags.peak_search( + parameters = peak_search_parameters, + map = fft_map_data).all(max_clusters = max_number_of_peaks) + heights = cluster_analysis.heights() + if(negative): + heights *= -1. + self.peaks_ = peaks_holder(heights = heights, + sites = cluster_analysis.sites()) + if(self.log is not None): + print("Number of peaks found (map cutoff=%s)= %s"%( + format_value("%-5.2f", self.map_cutoff).strip(), + format_value("%-12d", self.peaks_.sites.size())), file=self.log) def peaks(self): return self.peaks_ @@ -195,12 +185,12 @@ def peaks_mapped(self): min_dist = 0. if (max_dist is None): max_dist = float(sys.maxsize) - xray_structure = self.fmodel.xray_structure.deep_copy_scatterers() + xray_structure = self.xray_structure.deep_copy_scatterers() use_selection = None if(not self.params.map_next_to_model.use_hydrogens): use_selection = ~xray_structure.hd_selection() initial_number_of_sites = self.peaks_.sites.size() - if(not self.silent): + if(self.log is not None): print("Filter by distance & map next to the model:", file=self.log) result = xray_structure.closest_distances(sites_frac = self.peaks_.sites, distance_cutoff = max_dist, use_selection = use_selection) @@ -218,7 +208,7 @@ def peaks_mapped(self): sd = flex.sqrt(smallest_distances_sq.select(in_box)) d_min = flex.min_default(sd, 0) d_max = flex.max_default(sd, 0) - if(not self.silent): + if(self.log is not None): print(" mapped sites are within: %5.3f - %5.3f"%(d_min,d_max), file=self.log) print(" number of sites selected in [dist_min=%5.2f, " \ "dist_max=%5.2f]: %d from: %d" % (min_dist, max_dist, peaks.sites.size(), @@ -226,7 +216,7 @@ def peaks_mapped(self): smallest_distances = flex.sqrt(smallest_distances_sq.select(selection)) d_min = flex.min_default(smallest_distances, 0) d_max = flex.max_default(smallest_distances, 0) - if(not self.silent): + if(self.log is not None): print(" mapped sites are within: %5.3f - %5.3f"%(d_min,d_max), file=self.log) self.mapped = True self.peaks_ = peaks @@ -237,12 +227,12 @@ def show_mapped(self, pdb_atoms): peaks = self.peaks() if(peaks.iseqs_of_closest_atoms is None): raise RuntimeError("iseqs_of_closest_atoms is None") - scatterers = self.fmodel.xray_structure.scatterers() + scatterers = self.xray_structure.scatterers() assert scatterers.size() == pdb_atoms.size() assert peaks.sites.size() == peaks.heights.size() assert peaks.heights.size() == peaks.iseqs_of_closest_atoms.size() print(file=self.log) - dist = self.fmodel.xray_structure.unit_cell().distance + dist = self.xray_structure.unit_cell().distance for i in flex.sort_permutation(data=peaks.iseqs_of_closest_atoms): s = peaks.sites[i] h = peaks.heights[i] From fbf98da9eed8520b19aafe2b476958ecf8261078 Mon Sep 17 00:00:00 2001 From: Pavel Date: Fri, 26 Apr 2024 18:20:35 -0700 Subject: [PATCH 386/748] Enable adding water with altlocs --- mmtbx/model/model.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index 73f873e0ec..f0ddd495c8 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -3712,6 +3712,7 @@ def show_occupancy_statistics(self, out=None, text=""): time_model_show += timer.elapsed() def add_solvent(self, solvent_xray_structure, + conformer_indices, atom_name = "O", residue_name = "HOH", chain_id = " ", @@ -3729,6 +3730,7 @@ def add_solvent(self, solvent_xray_structure, if (i_seq is None or i_seq < 0): i_seq = 0 self.append_single_atoms( new_xray_structure=solvent_xray_structure, + conformer_indices=conformer_indices, atom_names=atom_names, residue_names=residue_names, nonbonded_types=nonbonded_types, @@ -3744,6 +3746,7 @@ def add_solvent(self, solvent_xray_structure, def append_single_atoms(self, new_xray_structure, + conformer_indices, atom_names, residue_names, nonbonded_types, @@ -3763,11 +3766,13 @@ def append_single_atoms(self, number_of_new_atoms = new_xray_structure.scatterers().size() self._xray_structure = \ self._xray_structure.concatenate(new_xray_structure) + # Occupancy occupancy_flags = None if(refine_occupancies): occupancy_flags = [] for i in range(1, new_xray_structure.scatterers().size()+1): occupancy_flags.append([flex.size_t([ms+i-1])]) + # if(self.refinement_flags is not None and self.refinement_flags.individual_sites): ssites = flex.bool(new_xray_structure.scatterers().size(), True) @@ -3804,23 +3809,23 @@ def append_single_atoms(self, # self._append_pdb_atoms( new_xray_structure=new_xray_structure, + conformer_indices=conformer_indices, atom_names=atom_names, residue_names=residue_names, chain_id=chain_id, segids=segids, i_seq_start=i_seq_start, reset_labels=reset_labels) - # if(self.restraints_manager is not None): geometry = self.restraints_manager.geometry if (geometry.model_indices is None): model_indices = None else: model_indices = flex.size_t(number_of_new_atoms, 0) - if (geometry.conformer_indices is None): + if(geometry.conformer_indices is None): conformer_indices = None else: - conformer_indices = flex.size_t(number_of_new_atoms, 0) + assert conformer_indices.conformer_indices.size() == number_of_new_atoms if (geometry.sym_excl_indices is None): sym_excl_indices = None else: @@ -3834,7 +3839,7 @@ def append_single_atoms(self, geometry = geometry.new_including_isolated_sites( n_additional_sites =number_of_new_atoms, model_indices=model_indices, - conformer_indices=conformer_indices, + conformer_indices=conformer_indices.conformer_indices, sym_excl_indices=sym_excl_indices, donor_acceptor_excl_groups=donor_acceptor_excl_groups, site_symmetry_table=new_xray_structure.site_symmetry_table(), @@ -3860,6 +3865,7 @@ def append_single_atoms(self, def _append_pdb_atoms(self, new_xray_structure, + conformer_indices, atom_names, residue_names, chain_id, @@ -3877,6 +3883,11 @@ def _append_pdb_atoms(self, i_seq = i_seq_start for j_seq, sc in enumerate(new_xray_structure.scatterers()): i_seq += 1 + + ci = conformer_indices.conformer_indices[j_seq] + cm = conformer_indices.index_altloc_mapping + altloc = list(cm.keys())[list(cm.values()).index(ci)] + element, charge = sc.element_and_charge_symbols() new_atom = (iotbx.pdb.hierarchy.atom() .set_serial(new_serial=iotbx.pdb.hy36encode(width=5, value=n_seq+i_seq)) @@ -3889,7 +3900,7 @@ def _append_pdb_atoms(self, .set_hetero(new_hetero=True)) if (segids is not None): new_atom.segid = segids[j_seq] - new_atom_group = iotbx.pdb.hierarchy.atom_group(altloc="", + new_atom_group = iotbx.pdb.hierarchy.atom_group(altloc=altloc, resname=residue_names[j_seq]) new_atom_group.append_atom(atom=new_atom) new_residue_group = iotbx.pdb.hierarchy.residue_group( From a396fc6e76d40e8964ad738a92c9c8cba76c702b Mon Sep 17 00:00:00 2001 From: Pavel Date: Fri, 26 Apr 2024 18:21:31 -0700 Subject: [PATCH 387/748] make plots more transparent --- mmtbx/nci/skew_kurt_plot.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmtbx/nci/skew_kurt_plot.py b/mmtbx/nci/skew_kurt_plot.py index 1fe62e7f26..c3532bba2e 100644 --- a/mmtbx/nci/skew_kurt_plot.py +++ b/mmtbx/nci/skew_kurt_plot.py @@ -171,6 +171,7 @@ def make_figure( aspect=aspect, # interpolation='bicubic', # norm=norm, + alpha=0.5 ) plt.contour( blue_filling, contours[type], origin="lower", From a479862b676b54b03c4d185cdae22f62e35834c8 Mon Sep 17 00:00:00 2001 From: Pavel Date: Fri, 26 Apr 2024 18:28:18 -0700 Subject: [PATCH 388/748] Enable adding water with alternative conformatons (first draft). --- mmtbx/solvent/ordered_solvent.py | 127 +++++++++++++++++++++++-------- 1 file changed, 95 insertions(+), 32 deletions(-) diff --git a/mmtbx/solvent/ordered_solvent.py b/mmtbx/solvent/ordered_solvent.py index 257d723f72..e6234025dc 100644 --- a/mmtbx/solvent/ordered_solvent.py +++ b/mmtbx/solvent/ordered_solvent.py @@ -15,6 +15,7 @@ from six.moves import range from libtbx.utils import user_plus_sys_time from libtbx.utils import null_out +from mmtbx.solvent import map_to_water output_params_str = """ output_residue_name = HOH @@ -46,6 +47,8 @@ .type = float .short_caption = Maximum H-bond length .expert_level = 1 + dist_min_altloc = 0.8 + .type = float """ adp_occ_params_str = """ @@ -104,6 +107,9 @@ keep_existing = False .type = bool .help = Keep existing in the model water + include_altlocs = False + .type = bool + .help = Search for water with altlocs n_cycles = 3 .type = int .short_caption = Number of cycles @@ -185,7 +191,8 @@ def master_params(): return iotbx.phil.parse(master_params_str) class maps(object): - def __init__(self, fmodel, map_1_type, map_2_type, grid_step=0.6, radius=2.0): + def __init__(self, fmodel, map_0_type, map_1_type, map_2_type, + grid_step=0.6, radius=2.0): self.radius = radius self.e_map = fmodel.electron_density_map() self.crystal_symmetry = fmodel.xray_structure.crystal_symmetry() @@ -194,6 +201,7 @@ def __init__(self, fmodel, map_1_type, map_2_type, grid_step=0.6, radius=2.0): space_group_info = self.crystal_symmetry.space_group_info(), symmetry_flags = maptbx.use_space_group_symmetry, step = grid_step) + self.map_0 = self._get_real_map(map_type = map_0_type) self.map_1 = self._get_real_map(map_type = map_1_type) self.map_2 = self._get_real_map(map_type = map_2_type) @@ -232,6 +240,14 @@ def __init__(self, fmodel, find_peaks_params = None, log = sys.stdout): adopt_init_args(self, locals()) + + # XXX Rationalize this: + + if self.params.include_altlocs: + self.find_peaks_params.peak_search.min_cross_distance=0.5 + self.find_peaks_params.map_next_to_model.min_model_peak_dist=0.5 + self.find_peaks_params.map_next_to_model.min_peak_peak_dist=0.5 + self.ma = msg_accumulator(log = self.log) self.total_time = 0 self._maps = None @@ -246,6 +262,7 @@ def __init__(self, fmodel, self._call(msg="Compute maps", func=self._get_maps) self._call(msg="Filter", func=self._filter_solvent) self._call(msg="Find peaks", func=self._find_peaks) + self._call(msg="Filter raw peaks", func=self._filter_raw_peaks) self._call(msg="Add new water", func=self._add_new_solvent) self._call(msg="Refine new water", func=self._refine) self._call(msg="Compute maps", func=self._get_maps) @@ -279,26 +296,34 @@ def _assert_same_model(self): def _get_maps(self): self._maps = maps( fmodel = self.fmodel, + map_0_type = self.params.primary_map_type, map_1_type = self.params.secondary_map_and_map_cc_filter.cc_map_1_type, map_2_type = self.params.secondary_map_and_map_cc_filter.cc_map_2_type) def _filter_solvent(self): sol_sel = self.model.solvent_selection(offset = self.existing_solvent) - hd_sel = self.model.get_hd_selection() n_sol_start = self.n_water mfp = self.params.secondary_map_and_map_cc_filter # Select by distance - distance_iselection = mmtbx.utils.select_water_by_distance( - sites_frac_all = self.model.get_xray_structure().sites_frac(), - element_symbols_all = self.model.get_xray_structure().scattering_types(), - water_selection_o = sol_sel.set_selected(hd_sel, False).iselection(), - dist_max = self.params.h_bond_max, - dist_min_mac = self.params.h_bond_min_mac, - dist_min_sol = self.params.h_bond_min_sol, - unit_cell = self.model.get_xray_structure().unit_cell()) - distance_selection = flex.bool(self.model.size(), distance_iselection) - selection = distance_selection.set_selected(~sol_sel, True) + interaction_selection = self.model.selection( + map_to_water.selection_string_interaction) + cis = self.model.get_hierarchy().get_conformer_indices() + distance_iselection = mmtbx.utils.filter_water_fsr( + interaction_selection = interaction_selection, + sites_frac = self.model.get_sites_frac(), + solvent_selection = sol_sel, + skip_selection = self.model.get_hd_selection(), + conformer_indices = cis.conformer_indices, # Will be changed inplace + dist_max = self.params.h_bond_max, + dist_min = self.params.h_bond_min_mac, + dist_min_altloc = self.params.dist_min_altloc, + unit_cell = self.model.crystal_symmetry().unit_cell()) + + all_selection = (~sol_sel).iselection() + all_selection.extend(distance_iselection) + self.model = self.model.select(all_selection) # Select by attributes + selection = flex.bool(self.model.size(), True) get_class = iotbx.pdb.common_residue_names_get_class scatterers = self.model.get_xray_structure().scatterers() occ = scatterers.extract_occupancies() @@ -313,12 +338,13 @@ def _filter_solvent(self): if(not get_class(name=r.resname) == "common_water"): continue i_seqs = r.atoms().extract_i_seq() keep = True + has_oxygen = False # catch only H/D with no O water for atom in r.atoms(): + if(atom.element.strip().upper()=="O"): has_oxygen = True if(atom.element_is_hydrogen()): continue i_seq = atom.i_seq if(self.params.keep_existing and i_seq in self.existing_solvent): continue - if(not distance_selection[i_seq]): keep = False if(atom.occ > self.params.occupancy_max or atom.occ < self.params.occupancy_min): keep = False assert approx_equal(atom.occ, occ[i_seq], 1.e-3) @@ -331,18 +357,9 @@ def _filter_solvent(self): min_value = mfp.poor_map_value_threshold) if(not good_map): keep = False - # - # XXX It does not work for 1f8t. WHY? XXX - # - #o = maptbx.sphericity_by_heuristics( - # map_data = self._maps.map_2, - # unit_cell = self.model.get_xray_structure().unit_cell(), - # center_cart = atom.xyz, - # radius = 1.0) - #if(o.ccs[0] < 0.1): keep = False - # - if(not keep): - selection = selection.set_selected(i_seqs, False) + if(not has_oxygen): keep=False + if(not keep): + selection = selection.set_selected(i_seqs, False) # Apply selection self.model = self.model.select(selection) n_sol_final = self.model.solvent_selection().count(True) @@ -366,11 +383,56 @@ def _find_peaks(self): self.find_peaks_params.max_number_of_peaks=self.model.get_number_of_atoms() assert self.params.primary_map_type is not None self._peaks = find_peaks.manager( - fmodel = self.fmodel, - map_type = self.params.primary_map_type, - map_cutoff = self.params.primary_map_cutoff, - params = self.find_peaks_params, - log = null_out()).peaks_mapped() + xray_structure = self.fmodel.xray_structure, + map_data = self._maps.map_0, # diff-map + map_cutoff = self.params.primary_map_cutoff, + params = self.find_peaks_params, + log = null_out()).peaks_mapped() + + def _write_pdb_file(self, sites_frac): + fmt = "ATOM %5d O HOH S%4d %8.3f%8.3f%8.3f 1.00 0.00 O" + uc = self.fmodel.xray_structure.crystal_symmetry().unit_cell() + with open("zz.pdb", "w") as fo: + for i, sf in enumerate(sites_frac): + sc = uc.orthogonalize(sf) + print(fmt%(i,i,sc[0],sc[1],sc[2]), file=fo) + + def _filter_raw_peaks(self): + if self._peaks is None: return + sites, heights = self._peaks.sites, self._peaks.heights + # + interaction_selection = self.model.selection( + map_to_water.selection_string_interaction) + interaction_selection.extend( flex.bool(sites.size(), True) ) + + sites_frac = self.model.get_sites_frac() + sites_frac.extend(sites) + + skip_selection = self.model.get_hd_selection() + skip_selection.extend( flex.bool(sites.size(), False) ) + + cis = self.model.get_hierarchy().get_conformer_indices() + cis.conformer_indices.extend( flex.size_t(sites.size(), 0) ) + + peaks_selection = flex.bool(self.model.size(), False) + peaks_selection.extend( flex.bool(sites.size(), True) ) + + distance_iselection = mmtbx.utils.filter_water_fsr( + interaction_selection = interaction_selection, + sites_frac = sites_frac, + solvent_selection = peaks_selection, + skip_selection = skip_selection, + conformer_indices = cis.conformer_indices, # Will be changed inplace + dist_max = self.params.h_bond_max, + dist_min = self.params.h_bond_min_mac, + dist_min_altloc = self.params.dist_min_altloc, + unit_cell = self.model.crystal_symmetry().unit_cell()) + # + cis.conformer_indices = cis.conformer_indices.select(peaks_selection) + # + self._peaks.sites = sites_frac.select(peaks_selection) + self._peaks.heights = None + self._peaks.conformer_indices = cis def _add_new_solvent(self): if(self._peaks is None): return @@ -405,6 +467,7 @@ def _add_new_solvent(self): scatterers = new_scatterers) self.model.add_solvent( solvent_xray_structure = solvent_xray_structure, + conformer_indices = self._peaks.conformer_indices, residue_name = self.params.output_residue_name, atom_name = self.params.output_atom_name, chain_id = self.params.output_chain_id, @@ -488,8 +551,8 @@ def _correct_drifted_waters(self): find_peaks_params_drifted.map_next_to_model.max_model_peak_dist=0.5 find_peaks_params_drifted.peak_search.min_cross_distance=0.5 peaks = find_peaks.manager( - fmodel = self.fmodel, - map_type = "2mFobs-DFmodel", + xray_structure = self.fmodel.xray_structure, + map_data = self._maps.map_2, map_cutoff = map_cutoff, params = find_peaks_params_drifted, log = null_out()).peaks_mapped() From ac041f3ab8b117afc54838e6ef92b55e960dfade Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Fri, 26 Apr 2024 19:11:42 -0700 Subject: [PATCH 389/748] Correctly access conformer_indices --- iotbx/pdb/hierarchy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index 172653a846..bf71acd0bd 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -2391,7 +2391,7 @@ def distance_based_simple_two_way_bond_sets(self, atoms.set_chemical_element_simple_if_necessary() sites_cart = atoms.extract_xyz() elements = atoms.extract_element() - conformer_indices = self.get_conformer_indices() + conformer_indices = self.get_conformer_indices().conformer_indices return distance_based_connectivity.build_simple_two_way_bond_sets( sites_cart=sites_cart, elements=elements, From 6a1e16cec65fafb4c61c1da499568879d768a47c Mon Sep 17 00:00:00 2001 From: Vincent Chen Date: Fri, 26 Apr 2024 23:53:52 -0400 Subject: [PATCH 390/748] fixes for remediator and improvements to test code --- iotbx/pdb/remediation/remediator.py | 4 ++-- iotbx/pdb/remediation/tst/dna-rna-test.pdb | 1 + iotbx/pdb/remediation/tst/dna-rna-testv23.pdb | 4 ++-- iotbx/pdb/remediation/tst_remediator.py | 19 +++++++++++++++++++ 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/iotbx/pdb/remediation/remediator.py b/iotbx/pdb/remediation/remediator.py index 17d534e443..91a10549f4 100644 --- a/iotbx/pdb/remediation/remediator.py +++ b/iotbx/pdb/remediation/remediator.py @@ -384,9 +384,9 @@ def remediate(filename, remediated_out, f=None): remark_flag = True if previous == current: print_line += line + "\n" - elif previous != None and previous != current: # appears to check an entire residue for dna residue/atom names + elif previous != current: # appears to check an entire residue for dna residue/atom names if re.search(r'^.{12}.\S.. .[ACTGIU]',print_line): - if re.search(r'O2[\'|\*] .',print_line) == None: + if re.search(r'O2[\'|\*] .',print_line) == None and previous != None: DNA_base = previous[1] if remediated_out == True: print_line = re.sub(r'(?m)(^.{12}.\S..) '+DNA_base+' ',r'\g<1> D'+DNA_base+' ',print_line) diff --git a/iotbx/pdb/remediation/tst/dna-rna-test.pdb b/iotbx/pdb/remediation/tst/dna-rna-test.pdb index b22e5fa5a4..d0f3ecead1 100644 --- a/iotbx/pdb/remediation/tst/dna-rna-test.pdb +++ b/iotbx/pdb/remediation/tst/dna-rna-test.pdb @@ -7,6 +7,7 @@ ORIGX3 0.000000 0.000000 1.000000 0.00000 SCALE1 0.038880 0.000000 0.000000 0.00000 SCALE2 0.000000 0.021954 0.000000 0.00000 SCALE3 0.000000 0.000000 0.020916 0.00000 +REMARK 4 REMEDIATOR VALIDATED PDB VERSION 3.2 COMPLIANT ATOM 1 O5' G A 1 -3.485 14.950 6.955 1.00 28.70 O ATOM 2 C5' G A 1 -2.451 14.461 7.861 1.00 25.35 C ATOM 3 C4' G A 1 -1.631 15.715 8.171 1.00 24.57 C diff --git a/iotbx/pdb/remediation/tst/dna-rna-testv23.pdb b/iotbx/pdb/remediation/tst/dna-rna-testv23.pdb index 802afa9c13..2ec662312d 100644 --- a/iotbx/pdb/remediation/tst/dna-rna-testv23.pdb +++ b/iotbx/pdb/remediation/tst/dna-rna-testv23.pdb @@ -97,9 +97,9 @@ ATOM 0 1H5* C A 10 5.011 -10.728 0.664 1.00 19.77 H ATOM 0 2H5* C A 10 5.628 -11.698 -0.390 1.00 19.77 H new ATOM 0 H4* C A 10 5.189 -9.874 -1.516 1.00 20.18 H new ATOM 0 H3* C A 10 8.040 -9.882 -0.975 1.00 21.99 H new +ATOM 0 H3T C A 10 8.054 -10.576 -3.004 1.00 25.75 H new ATOM 0 H2* C A 10 8.180 -7.894 -2.365 1.00 21.56 H new ATOM 0 2HO* C A 10 6.390 -8.882 -3.578 1.00 21.54 H new -ATOM 0 H3T C A 10 8.054 -10.576 -3.004 1.00 25.75 H new ATOM 0 H1* C A 10 6.277 -6.735 -1.128 1.00 20.62 H new ATOM 0 1H4 C A 10 11.077 -6.158 3.083 1.00 19.38 H new ATOM 0 2H4 C A 10 11.143 -5.028 2.115 1.00 19.38 H new @@ -192,9 +192,9 @@ ATOM 0 1H5* C B 20 3.714 16.047 23.379 1.00 23.15 H ATOM 0 2H5* C B 20 3.618 17.288 24.318 1.00 23.15 H new ATOM 0 H4* C B 20 3.943 18.095 22.334 1.00 22.65 H new ATOM 0 H3* C B 20 1.690 19.060 23.394 1.00 22.17 H new +ATOM 0 H3T C B 20 2.147 20.678 21.945 1.00 20.87 H new ATOM 0 1H2* C B 20 0.187 17.931 22.069 1.00 21.25 H new ATOM 0 2H2* C B 20 0.412 19.193 21.181 1.00 21.25 H new -ATOM 0 H3T C B 20 2.147 20.678 21.945 1.00 20.87 H new ATOM 0 H1* C B 20 1.813 18.074 19.741 1.00 20.04 H new ATOM 0 1H4 C B 20 -2.382 13.325 18.809 1.00 11.97 H new ATOM 0 2H4 C B 20 -1.978 13.830 17.467 1.00 11.97 H new diff --git a/iotbx/pdb/remediation/tst_remediator.py b/iotbx/pdb/remediation/tst_remediator.py index bda2fc0974..931bd044ba 100644 --- a/iotbx/pdb/remediation/tst_remediator.py +++ b/iotbx/pdb/remediation/tst_remediator.py @@ -7,6 +7,7 @@ import iotbx.pdb import libtbx from iotbx.data_manager import DataManager +from libtbx import easy_run multimodel_tst_str = """MODEL 1 ATOM 21 P A C 2 33.564 25.095 49.676 0.50 58.86 P @@ -202,7 +203,25 @@ def get_regression_folder_file_path(file_name): assert os.path.isfile(file_path), file_name + " test file is missing from " + regression_folder return file_path +def test_full_str_convert(old_file, new_file): + print("testing full file remediation") + prefix = os.path.basename(__file__).replace(".py","") + easy_run.call("iotbx.pdb_remediator %s > %s.pdb"%(old_file, prefix)) + with open(prefix+".pdb") as file: + remediated_list = [line.rstrip() for line in file] + remediated_pdb = "\n".join(remediated_list) + with open(new_file) as file: + new_list = [line.rstrip() for line in file] + new_pdb = "\n".join(new_list) + if new_pdb != remediated_pdb: + + diff = list(difflib.unified_diff(new_pdb.splitlines(), remediated_pdb.splitlines())) + assert False, "remediation test of "+old_file+" to v3 failed with these differences:\n" + '\n'.join(diff) + + print("OK") + def run_tests(): + test_full_str_convert(get_regression_folder_file_path("dna-rna-testv23.pdb"), get_regression_folder_file_path("dna-rna-test.pdb")) test_pdb_to_v3(get_regression_folder_file_path("protein-dna-testv23.pdb"), get_regression_folder_file_path("protein-dna-test.pdb")) test_pdb_to_v3(get_regression_folder_file_path("dna-rna-testv23.pdb"), get_regression_folder_file_path("dna-rna-test.pdb")) From 0bc8b0bff2d1b19b09eba9f106d4a0ae8e2fff48 Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Fri, 26 Apr 2024 21:25:31 -0700 Subject: [PATCH 391/748] Multiple fixes for t96 --- mmtbx/find_peaks.py | 22 ++++++++++++++++++++-- mmtbx/hydrogens/find.py | 21 +++++++++++++++++++-- mmtbx/model/model.py | 22 +++++++++++++--------- mmtbx/solvent/ensemble_ordered_solvent.py | 23 +++++++++++++++++++---- mmtbx/solvent/map_to_water.py | 1 + mmtbx/solvent/ordered_solvent.py | 7 +++++-- 6 files changed, 77 insertions(+), 19 deletions(-) diff --git a/mmtbx/find_peaks.py b/mmtbx/find_peaks.py index 247ce6f71c..758af24c68 100644 --- a/mmtbx/find_peaks.py +++ b/mmtbx/find_peaks.py @@ -261,8 +261,26 @@ def show_highest_peaks_and_deepest_holes(fmodel, fp_params.map_next_to_model.use_hydrogens = True for par in [(map_cutoff_plus,"peaks"), (map_cutoff_minus,"holes")]: print_statistics.make_sub_header(par[1], out = log) - result = manager(fmodel = fmodel, - map_type = "mFobs-DFmodel", + # + from cctbx import maptbx + e_map = fmodel.electron_density_map() + crystal_symmetry = fmodel.xray_structure.crystal_symmetry() + crystal_gridding = maptbx.crystal_gridding( + unit_cell = crystal_symmetry.unit_cell(), + space_group_info = crystal_symmetry.space_group_info(), + symmetry_flags = maptbx.use_space_group_symmetry, + step = 0.6) + coeffs = e_map.map_coefficients( + map_type = "mFobs-DFmodel", + fill_missing = False, + isotropize = True) + fft_map = coeffs.fft_map(crystal_gridding = crystal_gridding) + fft_map.apply_sigma_scaling() + map_data = fft_map.real_map_unpadded() + # + + result = manager(map_data = map_data, + xray_structure = fmodel.xray_structure, map_cutoff = par[0], params = fp_params, log = log) diff --git a/mmtbx/hydrogens/find.py b/mmtbx/hydrogens/find.py index 61a7cdacf1..1a6a7afa7c 100644 --- a/mmtbx/hydrogens/find.py +++ b/mmtbx/hydrogens/find.py @@ -113,8 +113,25 @@ def find_hydrogen_peaks(fmodel, pdb_atoms, params, log): - fp_manager = find_peaks.manager(fmodel = fmodel, - map_type = params.map_type, + # + from cctbx import maptbx + e_map = fmodel.electron_density_map() + crystal_symmetry = fmodel.xray_structure.crystal_symmetry() + crystal_gridding = maptbx.crystal_gridding( + unit_cell = crystal_symmetry.unit_cell(), + space_group_info = crystal_symmetry.space_group_info(), + symmetry_flags = maptbx.use_space_group_symmetry, + step = 0.6) + coeffs = e_map.map_coefficients( + map_type = params.map_type, + fill_missing = False, + isotropize = True) + fft_map = coeffs.fft_map(crystal_gridding = crystal_gridding) + fft_map.apply_sigma_scaling() + map_data = fft_map.real_map_unpadded() + # + fp_manager = find_peaks.manager(map_data = map_data, + xray_structure = fmodel.xray_structure, map_cutoff = params.map_cutoff, params = params, log = log) diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index f0ddd495c8..a5c9986bd2 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -3712,7 +3712,7 @@ def show_occupancy_statistics(self, out=None, text=""): time_model_show += timer.elapsed() def add_solvent(self, solvent_xray_structure, - conformer_indices, + conformer_indices=None, atom_name = "O", residue_name = "HOH", chain_id = " ", @@ -3825,7 +3825,11 @@ def append_single_atoms(self, if(geometry.conformer_indices is None): conformer_indices = None else: - assert conformer_indices.conformer_indices.size() == number_of_new_atoms + if conformer_indices is not None: + assert conformer_indices.conformer_indices.size() == number_of_new_atoms + conformer_indices = conformer_indices.conformer_indices + else: + conformer_indices = flex.size_t(number_of_new_atoms, 0) if (geometry.sym_excl_indices is None): sym_excl_indices = None else: @@ -3839,7 +3843,7 @@ def append_single_atoms(self, geometry = geometry.new_including_isolated_sites( n_additional_sites =number_of_new_atoms, model_indices=model_indices, - conformer_indices=conformer_indices.conformer_indices, + conformer_indices=conformer_indices, sym_excl_indices=sym_excl_indices, donor_acceptor_excl_groups=donor_acceptor_excl_groups, site_symmetry_table=new_xray_structure.site_symmetry_table(), @@ -3865,10 +3869,10 @@ def append_single_atoms(self, def _append_pdb_atoms(self, new_xray_structure, - conformer_indices, atom_names, residue_names, chain_id, + conformer_indices=None, segids=None, i_seq_start=0, reset_labels=False): @@ -3883,11 +3887,11 @@ def _append_pdb_atoms(self, i_seq = i_seq_start for j_seq, sc in enumerate(new_xray_structure.scatterers()): i_seq += 1 - - ci = conformer_indices.conformer_indices[j_seq] - cm = conformer_indices.index_altloc_mapping - altloc = list(cm.keys())[list(cm.values()).index(ci)] - + altloc="" + if conformer_indices is not None: + ci = conformer_indices.conformer_indices[j_seq] + cm = conformer_indices.index_altloc_mapping + altloc = list(cm.keys())[list(cm.values()).index(ci)] element, charge = sc.element_and_charge_symbols() new_atom = (iotbx.pdb.hierarchy.atom() .set_serial(new_serial=iotbx.pdb.hy36encode(width=5, value=n_seq+i_seq)) diff --git a/mmtbx/solvent/ensemble_ordered_solvent.py b/mmtbx/solvent/ensemble_ordered_solvent.py index 67140c6477..92e32108c1 100644 --- a/mmtbx/solvent/ensemble_ordered_solvent.py +++ b/mmtbx/solvent/ensemble_ordered_solvent.py @@ -380,12 +380,27 @@ def find_peaks(self, map_type, map_cutoff): if self.verbose > 0: silent = False else: silent = True - return find_peaks.manager(fmodel = self.fmodel, - map_type = map_type, + # + from cctbx import maptbx + e_map = self.fmodel.electron_density_map() + crystal_symmetry = self.fmodel.xray_structure.crystal_symmetry() + crystal_gridding = maptbx.crystal_gridding( + unit_cell = crystal_symmetry.unit_cell(), + space_group_info = crystal_symmetry.space_group_info(), + symmetry_flags = maptbx.use_space_group_symmetry, + step = 0.6) + coeffs = e_map.map_coefficients( + map_type = map_type, + fill_missing = False, + isotropize = True) + fft_map = coeffs.fft_map(crystal_gridding = crystal_gridding) + fft_map.apply_sigma_scaling() + map_data = fft_map.real_map_unpadded() + # + return find_peaks.manager(map_data = map_data, + xray_structure = self.fmodel.xray_structure, map_cutoff = map_cutoff, params = self.fpp, - use_all_data = False, - silent = silent, log = self.log) def add_new_solvent(self): diff --git a/mmtbx/solvent/map_to_water.py b/mmtbx/solvent/map_to_water.py index cdcbf56bbc..f2eb547a81 100644 --- a/mmtbx/solvent/map_to_water.py +++ b/mmtbx/solvent/map_to_water.py @@ -660,6 +660,7 @@ def _append_to_model(self): # self.model.add_solvent( solvent_xray_structure = self.xrs_water, + conformer_indices = None, atom_name = "O", residue_name = "HOH", chain_id = solvent_chain, diff --git a/mmtbx/solvent/ordered_solvent.py b/mmtbx/solvent/ordered_solvent.py index e6234025dc..987c131a2d 100644 --- a/mmtbx/solvent/ordered_solvent.py +++ b/mmtbx/solvent/ordered_solvent.py @@ -349,8 +349,11 @@ def _filter_solvent(self): atom.occ < self.params.occupancy_min): keep = False assert approx_equal(atom.occ, occ[i_seq], 1.e-3) if(anisotropy[i_seq] < self.params.anisotropy_min): keep = False - if(b_isos[i_seq] < self.params.b_iso_min or - b_isos[i_seq] > self.params.b_iso_max): keep = False + + print(b_isos[i_seq], self.params.b_iso_min, self.params.b_iso_max) + + #if(b_isos[i_seq] < self.params.b_iso_min or + # b_isos[i_seq] > self.params.b_iso_max): keep = False good_map = self._maps.score_atom( atom = atom, min_cc = mfp.poor_cc_threshold, From b8296ed847485e20fb03c4322371534d82d7d66e Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Fri, 26 Apr 2024 21:30:23 -0700 Subject: [PATCH 392/748] remove loftover comments --- mmtbx/solvent/ordered_solvent.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/mmtbx/solvent/ordered_solvent.py b/mmtbx/solvent/ordered_solvent.py index 987c131a2d..e6234025dc 100644 --- a/mmtbx/solvent/ordered_solvent.py +++ b/mmtbx/solvent/ordered_solvent.py @@ -349,11 +349,8 @@ def _filter_solvent(self): atom.occ < self.params.occupancy_min): keep = False assert approx_equal(atom.occ, occ[i_seq], 1.e-3) if(anisotropy[i_seq] < self.params.anisotropy_min): keep = False - - print(b_isos[i_seq], self.params.b_iso_min, self.params.b_iso_max) - - #if(b_isos[i_seq] < self.params.b_iso_min or - # b_isos[i_seq] > self.params.b_iso_max): keep = False + if(b_isos[i_seq] < self.params.b_iso_min or + b_isos[i_seq] > self.params.b_iso_max): keep = False good_map = self._maps.score_atom( atom = atom, min_cc = mfp.poor_cc_threshold, From 679b3c7dbe8be79d1476d09bdab277bdb5cabb4b Mon Sep 17 00:00:00 2001 From: terwill Date: Sat, 27 Apr 2024 06:14:46 -0600 Subject: [PATCH 393/748] Continue with unknowns --- mmtbx/validation/holton_geometry_validation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index bfa2be260c..3844a9d291 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -728,6 +728,7 @@ def get_model(info): info.model.add_crystal_symmetry_if_necessary() if info.model.has_hd(): info.model.get_hierarchy().remove_hd(reset_i_seq=True) + info.model.set_stop_for_unknowns(False) info.model.process(make_restraints=True) info.chain_dict = {} for chain_id in info.model.chain_ids(unique_only = True): From 05b56992b961b1644206538e9a0f0d2e81ebc8dc Mon Sep 17 00:00:00 2001 From: terwill Date: Sat, 27 Apr 2024 05:29:59 -0700 Subject: [PATCH 394/748] Only one model --- mmtbx/validation/holton_geometry_validation.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 3844a9d291..7d73da2a2b 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -721,13 +721,15 @@ def get_model(info): info.dm = DataManager() if not info.model: info.model = info.dm.get_model(info.filename) - if not os.path.isfile(info.filename): # write to it - info.dm.write_model_file(info.model, info.filename) info.model.set_log(null_out()) if (not info.keep_hydrogens): info.model.add_crystal_symmetry_if_necessary() if info.model.has_hd(): info.model.get_hierarchy().remove_hd(reset_i_seq=True) + for m in list(info.model.get_hierarchy().models())[1:]: + info.model.get_hierarchy().remove_model(m) + if not os.path.isfile(info.filename): # write to it + info.dm.write_model_file(info.model, info.filename) info.model.set_stop_for_unknowns(False) info.model.process(make_restraints=True) info.chain_dict = {} From 86d0318abd17d578e579de72cbdcf64afb682e36 Mon Sep 17 00:00:00 2001 From: terwill Date: Sat, 27 Apr 2024 08:01:46 -0600 Subject: [PATCH 395/748] Matching holton script --- mmtbx/validation/holton_geometry_validation.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 7d73da2a2b..cf2398a47a 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -70,7 +70,7 @@ def holton_geometry_validation(dm = None, clash_energy_add_n = True, minimum_nonbond_score_to_be_worst = -0.1, minimum_nonbond_score_to_be_included_in_average = 0, - keep_hydrogens = False, # redo the hydrogens + keep_hydrogens = True, # keep the hydrogens (but add any nec riding H) ignore_cis_peptides = False, ignore_h_except_in_nonbond = True, ignore_arg_h_nonbond = True, @@ -144,7 +144,7 @@ def add_clashscore_results(info): clashes = clashscore( info.model.get_hierarchy(), fast = False, - keep_hydrogens=True, + keep_hydrogens=False, # redo them here even if supplied time_limit=120, save_modified_hierarchy=False, verbose=False, @@ -722,16 +722,17 @@ def get_model(info): if not info.model: info.model = info.dm.get_model(info.filename) info.model.set_log(null_out()) + for m in list(info.model.get_hierarchy().models())[1:]: + info.model.get_hierarchy().remove_model(m) if (not info.keep_hydrogens): info.model.add_crystal_symmetry_if_necessary() if info.model.has_hd(): info.model.get_hierarchy().remove_hd(reset_i_seq=True) - for m in list(info.model.get_hierarchy().models())[1:]: - info.model.get_hierarchy().remove_model(m) if not os.path.isfile(info.filename): # write to it info.dm.write_model_file(info.model, info.filename) info.model.set_stop_for_unknowns(False) info.model.process(make_restraints=True) + info.model.setup_riding_h_manager(idealize=True) info.chain_dict = {} for chain_id in info.model.chain_ids(unique_only = True): entry = group_args(group_args_type = 'chain entry', ) From 8af474842b68972ac523a9ebb018973a0910adeb Mon Sep 17 00:00:00 2001 From: terwill Date: Sat, 27 Apr 2024 08:46:11 -0600 Subject: [PATCH 396/748] Remove max energy --- mmtbx/validation/holton_geometry_validation.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index cf2398a47a..2a169e8a14 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -77,7 +77,7 @@ def holton_geometry_validation(dm = None, ignore_bond_lengths_with_h = False, ignore_water_h_bonds = False, rotalyze_max_energy = 99, - overall_max_energy = 400, + overall_max_energy = None, omega_angle_sigma = 4, # Sigma for omega angle cbetadev_sigma = 0.05, # Sigma for CB position clashscore_ideal_dist = 3, # Ideal distance in LJ for clashscore result @@ -403,7 +403,10 @@ def analyze_geometry_values(info): continue # nothing to do - energy = max(0, min(info.overall_max_energy, result.worst_residual)) + if info.overall_max_energy is not None: + energy = max(0, min(info.overall_max_energy, result.worst_residual)) + else: + energy = max(0, result.worst_residual) delta = energy**0.5 result.pnna = softPnna(delta, result.n, info.softPnna_params) @@ -418,7 +421,10 @@ def analyze_geometry_values(info): sum_energy += result.energy # Repeat using mean instead of worst, multiplying mean energy * Chisq - energy_mean = max(0, min(info.overall_max_energy, result.mean_residual)) + if info.overall_max_energy is not None: + energy_mean = max(0, min(info.overall_max_energy, result.mean_residual)) + else: + energy_mean = max(0, result.mean_residual) ssd = result.mean_residual * result.n result.chisq = chisq(ssd, result.n) From b0e20496c8f4e49500ae58fae4138f7760e90d80 Mon Sep 17 00:00:00 2001 From: terwill Date: Sat, 27 Apr 2024 12:13:44 -0600 Subject: [PATCH 397/748] Catch additional geo restraints --- mmtbx/validation/holton_geometry_validation.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 2a169e8a14..96aeb952a8 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -656,18 +656,21 @@ def get_geometry_results(info): v.as_string = "NONBOND: Energy = %.6f dev = %.3f A obs = %.3f target = %.3f\n Atom 1: %s\n Atom 2: %s" %( v.residual, v.delta, v.model, v.ideal, v.labels[0].as_string(), v.labels[1].as_string()) - geometry_results[proxy_name] = result + geometry_results[proxy_name].value_list += result.value_list for proxy_name in ['bond_proxies', 'angle_proxies', 'dihedral_proxies', 'chirality_proxies', 'planarity_proxies']: proxies = getattr(pair_proxies, proxy_name, getattr(geometry, proxy_name, getattr(geometry, proxy_name, None))) + + origin_id_list = [] if proxy_name in ['bond_proxies', 'angle_proxies']: - origin_id=origin_ids.get_origin_id('covalent geometry') + for key in origin_ids.get_bond_origin_id_labels(): + origin_id_list.append(origin_ids.get_origin_id(key)) else: - origin_id=None - if proxies: + origin_id_list.append(None) + for origin_id in origin_id_list: result = proxies.show_sorted( by_value="residual", sites_cart=sites_cart, @@ -675,7 +678,7 @@ def get_geometry_results(info): f=null_out(), origin_id=origin_id, return_result = True) - geometry_results[proxy_name] = result + if not result: continue if result.group_args_type == 'Bond restraints': for v in result.value_list: v.as_string = "BOND: Energy = %.2f dev = %.3f A obs = %.3f target = %.3f sigma = %.2f\n Atom 1: %s\n Atom 2: %s " %( @@ -713,6 +716,10 @@ def get_geometry_results(info): for x in v.labels: i_at += 1 v.as_string += "\n Atom %s: %s" %(i_at, x.as_string()) + else: + print("Unknown result type:",result.group_args_type) + raise Sorry("Unknown result type: %s" %result.group_args_type) + geometry_results[proxy_name].value_list += result.value_list for key in name_dict.keys(): geometry_results[key].name = name_dict[key] From b08f8edea7b399aaec21fc79963969b66a94d112 Mon Sep 17 00:00:00 2001 From: terwill Date: Sat, 27 Apr 2024 14:36:42 -0700 Subject: [PATCH 398/748] Update expected output --- mmtbx/regression/tst_holton_geometry_validation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/regression/tst_holton_geometry_validation.py b/mmtbx/regression/tst_holton_geometry_validation.py index 84d440241d..5d2f443b3a 100644 --- a/mmtbx/regression/tst_holton_geometry_validation.py +++ b/mmtbx/regression/tst_holton_geometry_validation.py @@ -186,7 +186,7 @@ def run(): # print (result) expected_worst_table = {'CBETADEV': ['CBETADEV 8.1796 10 | B VAL A 10'], 'CLASH': ['CLASH 1.0814 -0.413 | HB2 A GLU A 32 - HB2 A LYS A 50 '], 'OMEGA': ['OMEGA 4.472084 10 0 171.49 | CA B VAL A 10'], 'RAMA': ['RAMA 3.4214 11 | 0.89 B ASN A 11'], 'ROTA': ['ROTA 5.4138 12 | 0.08 A CYS A 12'], 'ANGLE': ['ANGLE 4.70 -4.99 119.39 114.40 2.3 | CA B CYS A 46 - CB B CYS A 46 - SG B CYS A 46 '], 'BOND': ['BOND 2.42 0.051 1.757 1.808 0.03 | CB B CYS A 22 - SG B CYS A 22 '], 'CHIR': ['CHIR 1.315 0.23 2.28 2.51 0.2 | CA A LYS A 30 - N A LYS A 30 - C A LYS A 30 - CB A LYS A 30'], 'TORSION': ['TORSION 8.9570 -80.78 80.78 0.00 30.0 | CB A GLU A 32 - CG A GLU A 32 - CD A GLU A 32 - OE1 A GLU A 32'], 'NONBOND': ['NONBOND 1.743667 0.513 2.927 3.440 1 | O B VAL A 10 - CB B ASN A 11'], 'PLANE': ['PLANE 1.4400 -0.024 0.024 0 0.02 | CG A TYR A 14']} - expected_result_table = {'CBETADEV': ['CBETADEV', '20', '3.25', '8.18', '1.0000', '0.7974', '6.5225', '3.2475'], 'CLASH': ['CLASH', '1', '1.08', '2.08', '0.7016', '0.6177', '1.9033', '1.4603'], 'OMEGA': ['OMEGA', '4', '2.16', '4.47', '0.9289', '0.7053', '3.1541', '2.0039'], 'RAMA': ['RAMA', '2', '3.23', '3.42', '0.9604', '0.6856', '2.3459', '3.1020'], 'ROTA': ['ROTA', '20', '0.82', '5.41', '0.3079', '0.6033', '3.2660', '0.2523'], 'ANGLE': ['ANGLE', '172', '0.35', '4.70', '0.0000', '0.2926', '1.3762', '0.0000'], 'BOND': ['BOND', '152', '0.08', '2.42', '0.0000', '0.1309', '0.3163', '0.0000'], 'CHIR': ['CHIR', '22', '0.32', '1.31', '0.0010', '0.1638', '0.2154', '0.0003'], 'TORSION': ['TORSION', '94', '1.57', '8.96', '0.9996', '0.6876', '6.1589', '1.5671'], 'NONBOND': ['NONBOND', '531', '1.05', '1.74', '0.6123', '0.3741', '0.6523', '0.6412'], 'PLANE': ['PLANE', '56', '0.07', '1.44', '0.0000', '0.1139', '0.1640', '0.0000']} + expected_result_table = {'CBETADEV': ['CBETADEV', '20', '3.25', '8.18', '1.0000', '0.7974', '6.5225', '3.2475'], 'CLASH': ['CLASH', '1', '1.08', '2.08', '0.7016', '0.6177', '1.9033', '1.4603'], 'OMEGA': ['OMEGA', '4', '2.16', '4.47', '0.9289', '0.7053', '3.1541', '2.0039'], 'RAMA': ['RAMA', '2', '3.23', '3.42', '0.9604', '0.6856', '2.3459', '3.1020'], 'ROTA': ['ROTA', '20', '0.82', '5.41', '0.3079', '0.6033', '3.2660', '0.2523'], 'ANGLE': ['ANGLE', '176', '0.35', '4.70', '0.0000', '0.2904', '1.3655', '0.0000'], 'BOND': ['BOND', '154', '0.08', '2.42', '0.0000', '0.1301', '0.3144', '0.0000'], 'CHIR': ['CHIR', '22', '0.32', '1.31', '0.0010', '0.1638', '0.2154', '0.0003'], 'TORSION': ['TORSION', '94', '1.57', '8.96', '0.9996', '0.6876', '6.1589', '1.5671'], 'NONBOND': ['NONBOND', '531', '1.05', '1.74', '0.6123', '0.3741', '0.6523', '0.6412'], 'PLANE': ['PLANE', '56', '0.07', '1.44', '0.0000', '0.1139', '0.1640', '0.0000']} compare_tables(result.worst_table, expected_worst_table) compare_tables(result.result_table, expected_result_table) From cab4d6faadc9ca58d36661caf900868a8c2c737b Mon Sep 17 00:00:00 2001 From: terwill Date: Sun, 28 Apr 2024 07:36:08 -0700 Subject: [PATCH 399/748] Catch inf --- mmtbx/validation/holton_geometry_validation.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 96aeb952a8..85184a32cc 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -76,7 +76,7 @@ def holton_geometry_validation(dm = None, ignore_arg_h_nonbond = True, ignore_bond_lengths_with_h = False, ignore_water_h_bonds = False, - rotalyze_max_energy = 99, + rotalyze_ramalyze_max_energy = 99, overall_max_energy = None, omega_angle_sigma = 4, # Sigma for omega angle cbetadev_sigma = 0.05, # Sigma for CB position @@ -195,11 +195,11 @@ def add_rotamer_results(info): prob = min(1.0, max(0.0, prob)) if prob == 1: - energy = info.rotalyze_max_energy + energy = info.rotalyze_ramalyze_max_energy else: prob = float("%.35g" %(prob)) -1.0e-16 energy = energy_from_probability(prob) - energy = min(energy, info.rotalyze_max_energy) + energy = min(energy, info.rotalyze_ramalyze_max_energy) v = group_args(group_args_type = 'rotamer result as standard value ', rotamer_result = r, # contains resseq, resseq_as_int, resname, chain_id as_string = "ROTA: Energy = %.4f \n Residue: %s %s %s %s" %( @@ -227,7 +227,13 @@ def add_rama_results(info): prob = float("%.2f" %(r.score))/100 else: prob = r.score/100 - energy = energy_from_probability(prob) + + if prob == 1: + energy = info.rotalyze_ramalyze_max_energy + else: + prob = float("%.35g" %(prob)) -1.0e-16 + energy = energy_from_probability(prob) + energy = min(energy, info.rotalyze_ramalyze_max_energy) v = group_args(group_args_type = 'rama result as standard value ', rama_result = r, # contains resseq, resseq_as_int, resname, chain_id as_string = "RAMA: Energy = %.4f \n Residue: %s %s %s %s" %( From 5b289829c44c27257c059a67ba687e6592809ab3 Mon Sep 17 00:00:00 2001 From: terwill Date: Sun, 28 Apr 2024 11:57:45 -0600 Subject: [PATCH 400/748] Catch very large values --- mmtbx/validation/holton_geometry_validation.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 85184a32cc..3fb7d499a4 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -850,10 +850,13 @@ def filtered_energy(energy): return 10 + math.log(energy/10) -def softPnna(delta, n, params = None): - return 1 - 2.0**clip( - -abs(delta/asigma_Pnn50(safelog(n), params))**exponent( - delta,safelog(n), params) ,1000) +def softPnna(delta, n, params = None, max_value = 1000): + try: + value = -abs(delta/asigma_Pnn50(safelog(n), params))**exponent( + delta,safelog(n), params) + except Exception as e: + value = -max_value + return 1 - 2.0**clip(value, max_value) def Pnn(delta,n): return erf(abs(delta)/math.sqrt(2))**n From d82ffc8950e0255f6f0ffa65016618ba6112e6dd Mon Sep 17 00:00:00 2001 From: terwill Date: Mon, 29 Apr 2024 06:55:25 -0600 Subject: [PATCH 401/748] Add full_nonbonded category --- .../tst_holton_geometry_validation.py | 4 +- .../validation/holton_geometry_validation.py | 77 ++++++++++++------- 2 files changed, 50 insertions(+), 31 deletions(-) diff --git a/mmtbx/regression/tst_holton_geometry_validation.py b/mmtbx/regression/tst_holton_geometry_validation.py index 5d2f443b3a..c43c5132bd 100644 --- a/mmtbx/regression/tst_holton_geometry_validation.py +++ b/mmtbx/regression/tst_holton_geometry_validation.py @@ -186,7 +186,7 @@ def run(): # print (result) expected_worst_table = {'CBETADEV': ['CBETADEV 8.1796 10 | B VAL A 10'], 'CLASH': ['CLASH 1.0814 -0.413 | HB2 A GLU A 32 - HB2 A LYS A 50 '], 'OMEGA': ['OMEGA 4.472084 10 0 171.49 | CA B VAL A 10'], 'RAMA': ['RAMA 3.4214 11 | 0.89 B ASN A 11'], 'ROTA': ['ROTA 5.4138 12 | 0.08 A CYS A 12'], 'ANGLE': ['ANGLE 4.70 -4.99 119.39 114.40 2.3 | CA B CYS A 46 - CB B CYS A 46 - SG B CYS A 46 '], 'BOND': ['BOND 2.42 0.051 1.757 1.808 0.03 | CB B CYS A 22 - SG B CYS A 22 '], 'CHIR': ['CHIR 1.315 0.23 2.28 2.51 0.2 | CA A LYS A 30 - N A LYS A 30 - C A LYS A 30 - CB A LYS A 30'], 'TORSION': ['TORSION 8.9570 -80.78 80.78 0.00 30.0 | CB A GLU A 32 - CG A GLU A 32 - CD A GLU A 32 - OE1 A GLU A 32'], 'NONBOND': ['NONBOND 1.743667 0.513 2.927 3.440 1 | O B VAL A 10 - CB B ASN A 11'], 'PLANE': ['PLANE 1.4400 -0.024 0.024 0 0.02 | CG A TYR A 14']} - expected_result_table = {'CBETADEV': ['CBETADEV', '20', '3.25', '8.18', '1.0000', '0.7974', '6.5225', '3.2475'], 'CLASH': ['CLASH', '1', '1.08', '2.08', '0.7016', '0.6177', '1.9033', '1.4603'], 'OMEGA': ['OMEGA', '4', '2.16', '4.47', '0.9289', '0.7053', '3.1541', '2.0039'], 'RAMA': ['RAMA', '2', '3.23', '3.42', '0.9604', '0.6856', '2.3459', '3.1020'], 'ROTA': ['ROTA', '20', '0.82', '5.41', '0.3079', '0.6033', '3.2660', '0.2523'], 'ANGLE': ['ANGLE', '176', '0.35', '4.70', '0.0000', '0.2904', '1.3655', '0.0000'], 'BOND': ['BOND', '154', '0.08', '2.42', '0.0000', '0.1301', '0.3144', '0.0000'], 'CHIR': ['CHIR', '22', '0.32', '1.31', '0.0010', '0.1638', '0.2154', '0.0003'], 'TORSION': ['TORSION', '94', '1.57', '8.96', '0.9996', '0.6876', '6.1589', '1.5671'], 'NONBOND': ['NONBOND', '531', '1.05', '1.74', '0.6123', '0.3741', '0.6523', '0.6412'], 'PLANE': ['PLANE', '56', '0.07', '1.44', '0.0000', '0.1139', '0.1640', '0.0000']} + expected_result_table = {'CBETADEV': ['CBETADEV', '20', '3.25', '8.18', '1.0000', '0.7974', '6.5225', '3.2475'], 'CLASH': ['CLASH', '1', '1.08', '2.08', '0.7016', '0.6177', '1.9033', '1.4603'], 'OMEGA': ['OMEGA', '4', '2.16', '4.47', '0.9289', '0.7053', '3.1541', '2.0039'], 'RAMA': ['RAMA', '2', '3.23', '3.42', '0.9604', '0.6856', '2.3459', '3.1020'], 'ROTA': ['ROTA', '20', '0.82', '5.41', '0.3079', '0.6033', '3.2660', '0.2523'], 'ANGLE': ['ANGLE', '176', '0.35', '4.70', '0.0000', '0.2904', '1.3655', '0.0000'], 'BOND': ['BOND', '154', '0.08', '2.42', '0.0000', '0.1301', '0.3144', '0.0000'], 'CHIR': ['CHIR', '22', '0.32', '1.31', '0.0010', '0.1638', '0.2154', '0.0003'], 'TORSION': ['TORSION', '94', '1.57', '8.96', '0.9996', '0.6876', '6.1589', '1.5671'], 'FULL_NONBOND': ['FULL_NONBOND', '531', '-0.45', 'None', '0.0000', '0.0000', '0.0000', '0.0000'], 'NONBOND': ['NONBOND', '531', '1.05', '1.74', '0.6123', '0.3741', '0.6523', '0.6412'], 'PLANE': ['PLANE', '56', '0.07', '1.44', '0.0000', '0.1139', '0.1640', '0.0000']} compare_tables(result.worst_table, expected_worst_table) compare_tables(result.result_table, expected_result_table) @@ -209,7 +209,7 @@ def compare_tables(a,b): except Exception as e: xx1 = 0 xx2 = 0 - assert abs(xx1 - xx2) < 0.02, (xx1, xx2) + assert abs(xx1 - xx2) < 0.02, (xx1, xx2, x1,x2) if (__name__ == "__main__"): t0 = time.time() diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 3fb7d499a4..c972f103b3 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -70,6 +70,7 @@ def holton_geometry_validation(dm = None, clash_energy_add_n = True, minimum_nonbond_score_to_be_worst = -0.1, minimum_nonbond_score_to_be_included_in_average = 0, + include_full_nonbond_score = True, keep_hydrogens = True, # keep the hydrogens (but add any nec riding H) ignore_cis_peptides = False, ignore_h_except_in_nonbond = True, @@ -275,12 +276,13 @@ def add_cbetadev_results(info): ) cbetadev_result.value_list.append(v) -def select_geometry_result(info, name = None, skip_name = None): +def select_geometry_result(info, name = None, skip_name_list = None): result_list = [] for key in info.geometry_results.keys(): if name and info.geometry_results[key].name == name: return info.geometry_results[key] - elif skip_name and info.geometry_results[key].name != skip_name: + elif skip_name_list and ( + not info.geometry_results[key].name in skip_name_list): result_list.append(info.geometry_results[key]) return result_list @@ -349,7 +351,8 @@ def select_residue_info(info, base_info, chain_id, resseq): def labels_contain(labels, chain_id = None, resseq = None): for label in labels: - if ((chain_id is None) or (label.chain_id().strip() == chain_id.strip())) and \ + if ((chain_id is None) or \ + (label.chain_id().strip() == chain_id.strip())) and \ ((resseq is None) or (label.resseq().strip() == resseq.strip())): return True @@ -386,6 +389,8 @@ def analyze_geometry_values(info): result.name == 'NONBOND' and ( worst_value.residual < info.minimum_nonbond_score_to_be_worst): result.worst_residual = None + elif result.name == 'FULL_NONBOND': + result.worst_residual = None # do not include worst for FULL_NONBOND else: # usual result.worst_residual = worst_value.residual @@ -393,6 +398,7 @@ def analyze_geometry_values(info): value_list = result.value_list # Special case: non bond scores with low values may be excluded + # Note: FULL_NONBOND does include these if info.minimum_nonbond_score_to_be_included_in_average is not None and \ result.name == 'NONBOND': value_list = [] @@ -411,8 +417,10 @@ def analyze_geometry_values(info): if info.overall_max_energy is not None: energy = max(0, min(info.overall_max_energy, result.worst_residual)) - else: + elif result.worst_residual is not None: energy = max(0, result.worst_residual) + else: + energy = 0 delta = energy**0.5 result.pnna = softPnna(delta, result.n, info.softPnna_params) @@ -429,9 +437,11 @@ def analyze_geometry_values(info): # Repeat using mean instead of worst, multiplying mean energy * Chisq if info.overall_max_energy is not None: energy_mean = max(0, min(info.overall_max_energy, result.mean_residual)) - else: + elif result.mean_residual is not None: energy_mean = max(0, result.mean_residual) - ssd = result.mean_residual * result.n + else: + energy_mean = 0 + ssd = energy_mean * result.n result.chisq = chisq(ssd, result.n) energy_mean = filtered_energy(energy_mean) @@ -500,6 +510,7 @@ def print_results(info): print(fmt %(tuple(info.worst_header_row)), file = info.log) print(file = info.log) for key in keys: + if key == 'full_nonbonded': continue # duplicate of nonbonded result = info.geometry_results[key] value_list = result.value_list info.worst_table[result.name] = [ @@ -534,8 +545,9 @@ def filter_geometry_results(info): return # nothing to do if info.ignore_h_except_in_nonbond: - # Remove anything with element H except in NONBOND - for result in select_geometry_result(info,skip_name = 'NONBOND'): + # Remove anything with element H except in NONBOND and FULL_NONBOND + for result in select_geometry_result(info,skip_name_list = [ + 'NONBOND', 'FULL_NONBOND']): for v in result.value_list: elements = [l.atom.element for l in v.labels] if 'H' in elements: @@ -544,26 +556,27 @@ def filter_geometry_results(info): continue if info.ignore_arg_h_nonbond or info.ignore_water_h_bonds: - nonbond_result = select_geometry_result(info,'NONBOND') - for v in nonbond_result.value_list: - elements = [l.atom.element for l in v.labels] - residues = [l.atom.resname for l in v.labels] - - if info.ignore_arg_h_nonbond: - if elements == ['H','H'] and residues == ['ARG','ARG']: - nonbond_result.value_list.remove(v) - info.ignore_arg_h_nonbond_removed += 1 - continue + for category in ['NONBOND','FULL_NONBOND']: + nonbond_result = select_geometry_result(info,category) + for v in nonbond_result.value_list: + elements = [l.atom.element for l in v.labels] + residues = [l.atom.resname for l in v.labels] - if info.ignore_water_h_bonds: - found = False - for element, res in zip(elements, residues): - if element == 'H' and res in ['WAT','HOH']: + if info.ignore_arg_h_nonbond: + if elements == ['H','H'] and residues == ['ARG','ARG']: nonbond_result.value_list.remove(v) - found = True - if found: - info.ignore_water_h_bonds_removed += 1 - continue + info.ignore_arg_h_nonbond_removed += 1 + continue + + if info.ignore_water_h_bonds: + found = False + for element, res in zip(elements, residues): + if element == 'H' and res in ['WAT','HOH']: + nonbond_result.value_list.remove(v) + found = True + if found: + info.ignore_water_h_bonds_removed += 1 + continue if info.ignore_bond_lengths_with_h: bond_result = select_geometry_result(info,'BOND') @@ -627,7 +640,9 @@ def get_geometry_results(info): origin_ids = linking_class() pair_proxies = geometry.pair_proxies(sites_cart=sites_cart) - name_dict = {'nonbonded': 'NONBOND', + name_dict = { + 'nonbonded': 'NONBOND', + 'full_nonbonded': 'FULL_NONBOND', 'angle_proxies': 'ANGLE', 'bond_proxies': 'BOND', 'chirality_proxies': 'CHIR', @@ -642,7 +657,10 @@ def get_geometry_results(info): # Non-bonded if pair_proxies.nonbonded_proxies is not None: - proxy_name = 'nonbonded' + # Note: make two copies if full_nonbonded is going to be used + proxy_name_list = ['nonbonded'] + if info.include_full_nonbond_score: + proxy_name_list.append('full_nonbonded') result = pair_proxies.nonbonded_proxies.show_sorted( by_value="delta", sites_cart=sites_cart, @@ -662,7 +680,8 @@ def get_geometry_results(info): v.as_string = "NONBOND: Energy = %.6f dev = %.3f A obs = %.3f target = %.3f\n Atom 1: %s\n Atom 2: %s" %( v.residual, v.delta, v.model, v.ideal, v.labels[0].as_string(), v.labels[1].as_string()) - geometry_results[proxy_name].value_list += result.value_list + for proxy_name in proxy_name_list: + geometry_results[proxy_name].value_list += result.value_list for proxy_name in ['bond_proxies', 'angle_proxies', 'dihedral_proxies', 'chirality_proxies', 'planarity_proxies']: From 29be6611db2f7856933c4b5a305a19738f5029e1 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Mon, 29 Apr 2024 10:55:37 -0700 Subject: [PATCH 402/748] cctbx: adjust tst_diffuse.py to run if dispatcher is not available --- cctbx/regression/tst_diffuse.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/cctbx/regression/tst_diffuse.py b/cctbx/regression/tst_diffuse.py index d78f8a3ff6..1ac8d8857f 100644 --- a/cctbx/regression/tst_diffuse.py +++ b/cctbx/regression/tst_diffuse.py @@ -1,8 +1,9 @@ from __future__ import absolute_import, division, print_function from libtbx import easy_run +import libtbx.load_env import iotbx.mtz from libtbx.test_utils import approx_equal -import time +import os, time pdb_str = """ CRYST1 50.840 42.770 28.950 90.00 90.00 90.00 P 21 21 21 @@ -105,12 +106,22 @@ def exercise(): fo = open("tst_diffuse.pdb","w") print(pdb_str, file=fo) fo.close() - cmd = " ".join([ - "phenix.diffuse", + cmd_list = [ "pdb=tst_diffuse.pdb", "probabilities=0.5,0.5", "resolution=4.0", - "prefix=tst_diffuse"]) + "prefix=tst_diffuse"] + file_location = os.path.join(abs(libtbx.env.bin_path), 'phenix.diffuse') + if os.path.isfile(file_location): + cmd_list.insert(0, 'phenix.diffuse') + else: + import cctbx + file_location = os.path.join( + os.path.dirname(cctbx.__file__), + 'command_line', + 'diffuse.py') + cmd_list.insert(0, 'python %s ' % file_location) + cmd = " ".join(cmd_list) if 0: print(cmd) easy_run.call(cmd) mas = iotbx.mtz.object(file_name="tst_diffuse.mtz").as_miller_arrays() From 876171abf02457db5e3d7834cb8065448fce4cf1 Mon Sep 17 00:00:00 2001 From: terwill Date: Mon, 29 Apr 2024 16:29:53 -0600 Subject: [PATCH 403/748] Fix energy_from_probability for prob=1 vs 0 --- mmtbx/validation/holton_geometry_validation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index c972f103b3..9a79102790 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -195,7 +195,7 @@ def add_rotamer_results(info): prob = r.score/100 prob = min(1.0, max(0.0, prob)) - if prob == 1: + if prob == 0: energy = info.rotalyze_ramalyze_max_energy else: prob = float("%.35g" %(prob)) -1.0e-16 @@ -229,7 +229,7 @@ def add_rama_results(info): else: prob = r.score/100 - if prob == 1: + if prob == 0: energy = info.rotalyze_ramalyze_max_energy else: prob = float("%.35g" %(prob)) -1.0e-16 From 32e26ba2bb54aeb92dbd0e3e177c1218eee490d8 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Mon, 29 Apr 2024 15:54:47 -0700 Subject: [PATCH 404/748] Tidy-up Phenix: remove call of mmtbx.fmodel_simple (nothing was actually tested). --- mmtbx/regression/tst_fmodel_misc.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/mmtbx/regression/tst_fmodel_misc.py b/mmtbx/regression/tst_fmodel_misc.py index db38879017..be6e4f7695 100644 --- a/mmtbx/regression/tst_fmodel_misc.py +++ b/mmtbx/regression/tst_fmodel_misc.py @@ -1,5 +1,6 @@ from __future__ import absolute_import, division, print_function +import os from mmtbx.regression import make_fake_anomalous_data from mmtbx.programs import fmodel from iotbx.cli_parser import run_program @@ -8,9 +9,8 @@ from scitbx.array_family import flex from libtbx.test_utils import approx_equal, Exception_expected from libtbx.utils import null_out, Sorry -from libtbx import easy_run import iotbx.pdb -import os + def exercise(): if (os.path.isfile("tst_fmodel_anomalous.mtz")): @@ -34,11 +34,9 @@ def exercise(): assert (array.anomalous_flag()) anom_diffs = array.anomalous_differences() assert approx_equal(flex.max(anom_diffs.data()), 5.72, eps=0.01) - # mmtbx.fmodel_simple - result = easy_run.call( - "mmtbx.fmodel_simple \"%s\" tst_fmodel_anomalous.mtz high_resolution=2.0" - % pdb_file) print("OK") + os.remove('tst_fmodel_anomalous.mtz') + os.remove('tst_fmodel_anomalous.pdb') def exercise_intensity_output(): if (os.path.isfile("tst_fmodel_anomalous.mtz")): @@ -74,6 +72,8 @@ def exercise_intensity_output(): else : raise Exception_expected + os.remove('tst_fmodel_intensity.mtz') + def exercise_selection_consistency(): """ Test that the atom selections for anomalous scatterers actually correspond @@ -147,6 +147,11 @@ def exercise_selection_consistency(): map_val = real_map.eight_point_interpolation(site) assert (map_val < 5) + os.remove('tst_fmodel_misc.mtz') + os.remove('tst_fmodel_misc.pdb') + os.remove('tst_fmodel_misc.eff') + os.remove('anom.mtz') + if (__name__ == "__main__"): exercise_intensity_output() exercise_selection_consistency() From 66715ddb1f9187ee87888c7089970224863ffec8 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 30 Apr 2024 08:01:53 -0600 Subject: [PATCH 405/748] Catch None --- .../validation/holton_geometry_validation.py | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 9a79102790..623cca5368 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -671,17 +671,18 @@ def get_geometry_results(info): max_items=None, return_result = True) # Calculate residual from Lennard-Jones potential - for v in result.value_list: - v.residual = lj(v.model,v.ideal, - dist_that_yields_zero = info.lj_dist_that_yields_zero, - round_numbers = info.round_numbers) - v.delta = v.ideal - v.model - v.group_args_type += " residual is LJ(model, ideal)" - v.as_string = "NONBOND: Energy = %.6f dev = %.3f A obs = %.3f target = %.3f\n Atom 1: %s\n Atom 2: %s" %( - v.residual, v.delta, v.model, v.ideal, - v.labels[0].as_string(), v.labels[1].as_string()) - for proxy_name in proxy_name_list: - geometry_results[proxy_name].value_list += result.value_list + if result: + for v in result.value_list: + v.residual = lj(v.model,v.ideal, + dist_that_yields_zero = info.lj_dist_that_yields_zero, + round_numbers = info.round_numbers) + v.delta = v.ideal - v.model + v.group_args_type += " residual is LJ(model, ideal)" + v.as_string = "NONBOND: Energy = %.6f dev = %.3f A obs = %.3f target = %.3f\n Atom 1: %s\n Atom 2: %s" %( + v.residual, v.delta, v.model, v.ideal, + v.labels[0].as_string(), v.labels[1].as_string()) + for proxy_name in proxy_name_list: + geometry_results[proxy_name].value_list += result.value_list for proxy_name in ['bond_proxies', 'angle_proxies', 'dihedral_proxies', 'chirality_proxies', 'planarity_proxies']: From 199ba5228f329e13b713704956b15014ba51e574 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 30 Apr 2024 10:58:35 -0700 Subject: [PATCH 406/748] Tidy-up Phenix: remove mmtbx/command_line/ntc_validation.py (dispatcher was cctbx.development.ntc_validation) --- mmtbx/command_line/ntc_validation.py | 11 -- mmtbx/programs/ntc_validation.py | 198 --------------------------- 2 files changed, 209 deletions(-) delete mode 100644 mmtbx/command_line/ntc_validation.py delete mode 100644 mmtbx/programs/ntc_validation.py diff --git a/mmtbx/command_line/ntc_validation.py b/mmtbx/command_line/ntc_validation.py deleted file mode 100644 index f731b1ea9b..0000000000 --- a/mmtbx/command_line/ntc_validation.py +++ /dev/null @@ -1,11 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, division, print_function -# LIBTBX_SET_DISPATCHER_NAME cctbx.development.ntc_validation - -from iotbx.cli_parser import run_program -from mmtbx.programs.ntc_validation import Program - -# ============================================================================= - -if (__name__ == '__main__'): - results = run_program(program_class=Program) diff --git a/mmtbx/programs/ntc_validation.py b/mmtbx/programs/ntc_validation.py deleted file mode 100644 index 298fcdfff2..0000000000 --- a/mmtbx/programs/ntc_validation.py +++ /dev/null @@ -1,198 +0,0 @@ -from __future__ import absolute_import, division, print_function -# -import requests #, json -from operator import itemgetter -from phenix.program_template import ProgramTemplate - -dnatco_assign_cgi = "https://www.dnatco.org/cgi-bin/assign_from_torsions_34.py" -dnatco_nearest_cgi = "https://www.dnatco.org/cgi-bin/nearest_from_torsions_34.py" - -# ============================================================================= -class Program(ProgramTemplate): - - description = ''' -Program for validating DNA/RNA from NtC web-service - -Minimum required inputs: - Model file - -''' - - datatypes = ['model', 'phil'] - - master_phil_str = ''' -input { - nproc = Auto - .type = int -} -action { - query_type = *angles xyz - .type = choice(multi=False) - outliers_only = False - .type = bool - .help = Print only the outliers -} -''' - - def validate(self): - pass - - @staticmethod - def get_validation_via_angles(query): - query1 = {'ch': '271.6', - 'g1': '44.6', - 'CC': '5.0', - 'a1': '287.8', - 'P': '156.3', - 'P1': '116.9', - 'b1': '138.5', - 'step_id': '0_B_DG_22_DC_23', - 'd1': '112.8', - 'NCCN': '34.3', - 'e': '259.9', - 'd': '149.7', - 'NN': '4.7', - 'ch1': '234.7', - 'z': '171.6'} - r1 = requests.post(dnatco_assign_cgi, json=query) - r2 = requests.post(dnatco_nearest_cgi, json=query) - return r1,r2 - - @staticmethod - def get_validation_via_coordinates(query): - query1 = {"step_id":"102d_A_DC_1_DG_2", - "C5pa":["18.939","34.713","89.428"], - "C4pa":["20.086","33.755","89.286"], - "O4pa":["19.617","32.539","89.905"], - "C3pa":["20.434","33.382","87.819"], - "O3pa":["21.831","32.949","87.719"], - "C2pa":["19.488","32.196","87.629"], - "C1pa":["19.521","31.485","88.974"], - "N19a":["18.313","30.732","89.375"], - "C24a":["18.488","29.453","89.907"], - "Pb":["22.636","32.521","86.331"], - "O5pb":["22.776","30.956","86.326"], - "C5pb":["23.239","30.276","87.446"], - "C4pb":["23.441","28.853","87.109"], - "O4pb":["22.221","28.177","87.390"], - "C3pb":["23.649","28.619","85.571"], - "O3pb":["24.497","27.474","85.326"], - "C2pb":["22.244","28.333","85.091"], - "C1pb":["21.634","27.584","86.246"], - "N19b":["20.190","27.715","86.370"], - "C24b":["19.318","26.753","86.864"]} - import json - dnatco_cgi = "https://www.dnatco.org/cgi-bin/assign_from_coords_34.py" - query = json.dumps(query) - - try: - r = requests.post(dnatco_cgi, json=json.loads(query)) - jsonres = r.json() - except Exception as e: - print(repr(e)) - sys.exit() - - if 1: - if (jsonres["error"] == ""): - #print(jsonres["result"]["NtC"], jsonres["result"].get("confal", None)) - print(jsonres) - else: - print(jsonres["error"]) - return r,r - - def print_validation(self, r1, r2): - jsonres = r1.json() - if (jsonres["error"] == ""): - print(jsonres["result"]["step_id"], jsonres["result"]["NtC"], jsonres["result"]["confalH"]) - else: - print(jsonres["error"]) - - jsonres = r2.json() - nearest = [] - if (jsonres["error"] == ""): - for ntc in jsonres["result"]: - # nearest.append( [str(ntc), float(jsonres["result"][ntc]["confalH"]), float(jsonres["result"][ntc]["confalA"]), float(jsonres["result"][ntc]["confalG"]), float(jsonres["result"][ntc]["bb_rmsd"]) ] + [float(i) for i in jsonres["result"][ntc]["confals"]] + [float(d) for d in ["%.2f" % float(i) for i in jsonres["result"][ntc]["distances"]]] ) - try: - nearest.append( [ str(ntc), - float(jsonres["result"][ntc]["confalH"]), - float(jsonres["result"][ntc]["bb_rmsd"]) ]) - except Exception as e: - pass - # nearest.sort(key = itemgetter(2), reverse=True) - nearest.sort(key = itemgetter(2), reverse=False) - for record in nearest: - if (record[1] != 0.0): - print(record) - else: - print(jsonres["error"]) - - def run(self, - log=None, - verbose=False): - assert log is None - if log is None: log=sys.stdout - print('Using model: %s' % self.data_manager.get_default_model_name()) - model = self.data_manager.get_model() - - from mmtbx.conformation_dependent_library import generate_dna_rna_fragments - import time - import psutil - from libtbx import easy_mp - from libtbx import Auto - - if self.params.action.query_type=='angles': - validation_function = self.get_validation_via_angles - query_attr = 'get_ntc_angles' - elif self.params.action.query_type=='xyz': - validation_function = self.get_validation_via_coordinates - query_attr = 'get_ntc_coordinates' - else: - assert 0 - - t0=time.time() - - if self.params.input.nproc==Auto: - self.params.input.nproc=psutil.cpu_count() - from collections import OrderedDict - self.results = OrderedDict() - argss = [] - for dna_rna_pairs in generate_dna_rna_fragments( - model.get_hierarchy(), - model.get_restraints_manager().geometry, - length=2, - ): - print(dna_rna_pairs) - query_function = getattr(dna_rna_pairs, query_attr) - query = query_function() - #print(query) - argss.append([query]) - self.results[query['step_id']] = None - - print('\nUsing %d nprocs for %s suites\n' % (self.params.input.nproc, - len(argss))) - for args, res, err_str in easy_mp.multi_core_run(validation_function, - argss, - self.params.input.nproc, - ): - print('%sTotal time: %6.2f (s) for %s' % (' '*7, - time.time()-t0, - args[0]['step_id'] - ), - ) - if err_str: - print('Error output from %s' % args[0]['step_id']) - print(err_str) - print('_'*80) - self.results[args[0]['step_id']] = [args, res, err_str] - - for step_id, (query, res, err_str) in self.results.items(): - print('-'*80) - if res: - self.print_validation(res[0], res[1]) - else: - print('no results') - - return self.results - - def get_results(self): - return self.results From da8d9abb86cc8f638f882fded66378a7b41ebce8 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 30 Apr 2024 12:28:23 -0600 Subject: [PATCH 407/748] Fix ignore_h_except_in_nonbond_removed --- mmtbx/validation/holton_geometry_validation.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 623cca5368..6ae9f85d62 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -519,7 +519,7 @@ def print_results(info): file = info.log) if info.ignore_h_except_in_nonbond: - print("\nTotal H interactions (not in non-bonded) removed: %s" %( + print("\nTotal H interactions removed: %s (not removed from nonbonded)" %( info.ignore_h_except_in_nonbond_removed), file = info.log) if info.ignore_arg_h_nonbond: print("Total ARG H-nonbond removed: %s" %( @@ -546,14 +546,22 @@ def filter_geometry_results(info): if info.ignore_h_except_in_nonbond: # Remove anything with element H except in NONBOND and FULL_NONBOND + max_removed = 0 for result in select_geometry_result(info,skip_name_list = [ 'NONBOND', 'FULL_NONBOND']): + remove_list = [] for v in result.value_list: elements = [l.atom.element for l in v.labels] - if 'H' in elements: - result.value_list.remove(v) - info.ignore_h_except_in_nonbond_removed += 1 + if 'H' in elements and (not v in remove_list): + remove_list.append(v) continue + n = 0 + for v in remove_list: + if v in result.value_list: + result.value_list.remove(v) + n += 1 + max_removed = max(max_removed, n) + info.ignore_h_except_in_nonbond_removed += max_removed if info.ignore_arg_h_nonbond or info.ignore_water_h_bonds: for category in ['NONBOND','FULL_NONBOND']: From 94e8e44a876df4de21b7ee52fce0e85690a5f135 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 30 Apr 2024 13:29:43 -0600 Subject: [PATCH 408/748] Allow user to set params --- mmtbx/programs/holton_geometry_validation.py | 149 ++++++++++++++++++- 1 file changed, 144 insertions(+), 5 deletions(-) diff --git a/mmtbx/programs/holton_geometry_validation.py b/mmtbx/programs/holton_geometry_validation.py index 759ed465e1..e362f0e9ce 100644 --- a/mmtbx/programs/holton_geometry_validation.py +++ b/mmtbx/programs/holton_geometry_validation.py @@ -32,9 +32,126 @@ class Program(ProgramTemplate): master_phil_str = """ model = None - .type = path - .optional = False - .help = '''input PDB file''' + .type = path + .optional = False + .help = '''input PDB file''' + + get_individual_residue_scores = None + .type = bool + .short_caption = Residue scores + .help = Calculate individual residue scores in addition to overall score + + round_numbers = True + .type = bool + .short_caption = Round numbers + .help = Round numbers before calculation + + worst_clash_is_one_plus_n_times_worst_clash = True + .type = bool + .short_caption = Scale clashes + .help = Scale worst clash score by (1 + n) where n is total clashes + + clash_energy_add_n = True + .type = bool + .short_caption = Add N to clash energy + .help = Add number of clashes to clash energy score + + minimum_nonbond_score_to_be_worst = -0.1 + .type = float + .short_caption = Minimum worst nonbond_score + .help = Only include worst nonbond score if it is at least this value + + minimum_nonbond_score_to_be_included_in_average = 0 + .type = float + .short_caption = Minimum nonbond_score + .help = Only include nonbond score in average if it is at least this value + + include_full_nonbond_score = True + .type = bool + .short_caption = Include full nonbond score + .help = If set, add additional scoring term in which all nonbond \ + values (even those less than the minimums) are included + + keep_hydrogens = True + .type = bool + .short_caption = Keep hydrogens + .help = If set, keep input hydrogens, but add any necessary riding H. + + ignore_cis_peptides = False + .type = bool + .short_caption = Ignore cis peptides + .help = If set, ignore cis peptides. Otherwise (if False), penalize them. + + ignore_h_except_in_nonbond = True + .type = bool + .short_caption = Ignore H except in nonbond + .help = If set, ignore H atoms except in nonbond term + + ignore_arg_h_nonbond = True + .type = bool + .short_caption = Ignore H in Arg + .help = If set, ignore H atoms in Arginine + + ignore_bond_lengths_with_h = False + .type = bool + .short_caption = Ignore bond lengths with H + .help = If set, ignore bond lengths involving H atoms + + ignore_water_h_bonds = False + .type = bool + .short_caption = Ignore water H bonds + .help = If set, ignore H-bonds involving water + + rotalyze_ramalyze_max_energy = 99 + .type = float + .short_caption = Maximum ramalyze/rotalyze energy + .help = Maximum value of energy for a bad rotamer or phi-psi combination + + overall_max_energy = None + .type = float + .short_caption = Maximum overall energy + .help = Maximum value of energy + + omega_angle_sigma = 4 + .type = float + .short_caption = Omega angle sigma + .help = Sigma for omega angle + cbetadev_sigma = 0.05 + .type = float + .short_caption = CB position sigma + .help = Sigma for CB position + + clashscore_ideal_dist = 3 + .type = float + .short_caption = Clashscore ideal distance + .help = Ideal distance in Lennard-Jones potential for clashscore result + + lj_dist_that_yields_zero = 6 # Distance for modified LJ to cross zero + .type = float + .short_caption = LJ distance yielding zero + .help = Distance at which modified Lennard-Jones potential crosses zero + + softPnna_params { + y0 = 1 + .type = float + .help = Parameter y0 for softPnna calculation + a2 = -0.0192266 + .type = float + .help = Parameter a2 for softPnna calculation + a1 = 0.751694 + .type = float + .help = Parameter a1 for softPnna calculation + a0 = 1.12482 + .type = float + .help = Parameter a0 for softPnna calculation + mx = 0.21805 + .type = float + .help = Parameter mx for softPnna calculation + my = 0.736621 + .type = float + .help = Parameter my for softPnna calculation + } + """ @@ -55,12 +172,34 @@ def set_defaults(self): def run(self): - self.results = holton_geometry_validation( dm = self.data_manager, filename = self.params.model, model = self.model, - log =self.logger,) + get_individual_residue_scores = self.params.get_individual_residue_scores, + round_numbers = self.params.round_numbers, + worst_clash_is_one_plus_n_times_worst_clash = + self.params.worst_clash_is_one_plus_n_times_worst_clash, + clash_energy_add_n = self.params.clash_energy_add_n, + minimum_nonbond_score_to_be_worst = + self.params.minimum_nonbond_score_to_be_worst, + minimum_nonbond_score_to_be_included_in_average = + self.params.minimum_nonbond_score_to_be_included_in_average, + include_full_nonbond_score = self.params.include_full_nonbond_score, + keep_hydrogens = self.params.keep_hydrogens, + ignore_cis_peptides = self.params.ignore_cis_peptides, + ignore_h_except_in_nonbond = self.params.ignore_h_except_in_nonbond, + ignore_arg_h_nonbond = self.params.ignore_arg_h_nonbond, + ignore_bond_lengths_with_h = self.params.ignore_bond_lengths_with_h, + ignore_water_h_bonds = self.params.ignore_water_h_bonds, + rotalyze_ramalyze_max_energy = self.params.rotalyze_ramalyze_max_energy, + overall_max_energy = self.params.overall_max_energy, + omega_angle_sigma = self.params.omega_angle_sigma, + cbetadev_sigma = self.params.cbetadev_sigma, + clashscore_ideal_dist = self.params.clashscore_ideal_dist, + lj_dist_that_yields_zero = self.params.lj_dist_that_yields_zero, + softPnna_params = self.params.softPnna_params, + log =self.logger) def get_results(self): return self.results From 24842fed36eb9a854b14b1a9e8cde4a93c6b960b Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 30 Apr 2024 15:44:14 -0700 Subject: [PATCH 409/748] Tidy-up Phenix: remove cctbx/command_line/xray_structure.show.py (a very simple wrapper) --- cctbx/command_line/xray_structure.show.py | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 cctbx/command_line/xray_structure.show.py diff --git a/cctbx/command_line/xray_structure.show.py b/cctbx/command_line/xray_structure.show.py deleted file mode 100644 index 9b316e99f2..0000000000 --- a/cctbx/command_line/xray_structure.show.py +++ /dev/null @@ -1,16 +0,0 @@ -from __future__ import absolute_import, division, print_function -from cctbx import xray -from libtbx import easy_pickle -import sys - -def run(args): - for file_name in args: - structures = easy_pickle.load(file_name) - if (isinstance(structures, xray.structure)): - structures = [structures] - for structure in structures: - structure.show_summary().show_scatterers() - print() - -if (__name__ == "__main__"): - run(sys.argv[1:]) From 0b0c262ba8e3d96dd96608e5377bf5b4276278c0 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 30 Apr 2024 16:47:24 -0600 Subject: [PATCH 410/748] Fix formatting --- mmtbx/programs/holton_geometry_validation.py | 7 ++++++- mmtbx/validation/holton_geometry_validation.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/mmtbx/programs/holton_geometry_validation.py b/mmtbx/programs/holton_geometry_validation.py index e362f0e9ce..7475ab5fc3 100644 --- a/mmtbx/programs/holton_geometry_validation.py +++ b/mmtbx/programs/holton_geometry_validation.py @@ -30,6 +30,7 @@ class Program(ProgramTemplate): %(prog)s model=1ubq.pdb """ % locals() + master_phil_str = """ model = None .type = path @@ -100,7 +101,7 @@ class Program(ProgramTemplate): ignore_water_h_bonds = False .type = bool .short_caption = Ignore water H bonds - .help = If set, ignore H-bonds involving water + .help = If set, ignore nonbonded contacts with water hydrogens rotalyze_ramalyze_max_energy = 99 .type = float @@ -206,3 +207,7 @@ def get_results(self): def get_results_as_JSON(self): return self.results.as_JSON(self.info_json) + +# ============================================================================= +# for reference documentation keywords +master_phil_str = Program.master_phil_str diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 6ae9f85d62..5d954ea67e 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -475,7 +475,7 @@ def print_results(info): info.result_table = {} info.result_header_row = [ 'Category','N','Mean','Worst','Chisq','Pnna','Energy','Using mean'] - fmt = len(info.result_header_row) * "%8s " + fmt = "%12s " + (len(info.result_header_row)-1) * "%8s " print(file = info.log) print(fmt %(tuple(info.result_header_row)), file = info.log) print(file = info.log) From 3d76b98489f6bf35542aec48a9065767ef2100d1 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 1 May 2024 10:08:29 -0700 Subject: [PATCH 411/748] Update CHANGELOG.rst for 2024.4 release [skip ci] --- CHANGELOG.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 57b7734a4e..1ecf553ead 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,11 @@ +2024.4 +====== + +* Added mmtbx.holton_geometry_validation tool +* Removed unused or not maintained tools in mmtbx +* Fixed bug in PDB remediator for RNA +* Added ability to add water with alternative conformations + 2024.3 ====== From a7a290da82d447a7f27078440f18b85dd00b9b43 Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 1 May 2024 13:46:49 -0600 Subject: [PATCH 412/748] Catch None --- cctbx/maptbx/segment_and_split_map.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cctbx/maptbx/segment_and_split_map.py b/cctbx/maptbx/segment_and_split_map.py index 4b42e1c602..7a46a70e7c 100644 --- a/cctbx/maptbx/segment_and_split_map.py +++ b/cctbx/maptbx/segment_and_split_map.py @@ -10218,7 +10218,7 @@ def run_local_sharpening(si = None, return_bsi = True, # just return the bsi of sharpened data out = out) - if not bsi.map_data: + if not bsi or not bsi.map_data: print("\nNo result for local map %s ...skipping" %(i), file = out) continue @@ -11385,7 +11385,8 @@ def run_auto_sharpen( print("This is the current best score\n", file = out) if (best_si.score is not None ) and ( - not best_si.is_model_sharpening() ) and (not best_si.is_half_map_sharpening()): + not best_si.is_model_sharpening() ) and ( + not best_si.is_half_map_sharpening()): print("\nOverall best sharpening method: %s Score: %7.3f\n" %( best_si.sharpening_method, best_si.score), file = out) best_si.show_summary(out = out) @@ -11397,6 +11398,8 @@ def run_auto_sharpen( print("Did not improve score with sharpening...", file = out) if return_bsi: map_data = best_map_and_b.map_data + if not map_data: # no result + return None map_data = set_mean_sd_of_map(map_data = map_data, target_mean = starting_mean, target_sd = starting_sd) box_sharpening_info_obj.map_data = map_data From 6108377d47d8cf7b9a8b3df4823d9495216a0eb3 Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 2 May 2024 12:01:58 -0600 Subject: [PATCH 413/748] Add expected values --- .../tst_holton_geometry_validation.py | 6 + .../validation/holton_geometry_validation.py | 201 +++++++++++++++++- 2 files changed, 197 insertions(+), 10 deletions(-) diff --git a/mmtbx/regression/tst_holton_geometry_validation.py b/mmtbx/regression/tst_holton_geometry_validation.py index c43c5132bd..5b682d2ccd 100644 --- a/mmtbx/regression/tst_holton_geometry_validation.py +++ b/mmtbx/regression/tst_holton_geometry_validation.py @@ -188,7 +188,13 @@ def run(): expected_result_table = {'CBETADEV': ['CBETADEV', '20', '3.25', '8.18', '1.0000', '0.7974', '6.5225', '3.2475'], 'CLASH': ['CLASH', '1', '1.08', '2.08', '0.7016', '0.6177', '1.9033', '1.4603'], 'OMEGA': ['OMEGA', '4', '2.16', '4.47', '0.9289', '0.7053', '3.1541', '2.0039'], 'RAMA': ['RAMA', '2', '3.23', '3.42', '0.9604', '0.6856', '2.3459', '3.1020'], 'ROTA': ['ROTA', '20', '0.82', '5.41', '0.3079', '0.6033', '3.2660', '0.2523'], 'ANGLE': ['ANGLE', '176', '0.35', '4.70', '0.0000', '0.2904', '1.3655', '0.0000'], 'BOND': ['BOND', '154', '0.08', '2.42', '0.0000', '0.1301', '0.3144', '0.0000'], 'CHIR': ['CHIR', '22', '0.32', '1.31', '0.0010', '0.1638', '0.2154', '0.0003'], 'TORSION': ['TORSION', '94', '1.57', '8.96', '0.9996', '0.6876', '6.1589', '1.5671'], 'FULL_NONBOND': ['FULL_NONBOND', '531', '-0.45', 'None', '0.0000', '0.0000', '0.0000', '0.0000'], 'NONBOND': ['NONBOND', '531', '1.05', '1.74', '0.6123', '0.3741', '0.6523', '0.6412'], 'PLANE': ['PLANE', '56', '0.07', '1.44', '0.0000', '0.1139', '0.1640', '0.0000']} + if 0: + print(result.worst_table) + print(expected_worst_table) compare_tables(result.worst_table, expected_worst_table) + if 0: + print(result.result_table) + print(expected_result_table) compare_tables(result.result_table, expected_result_table) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 5d954ea67e..61fbce2f5e 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -5,8 +5,11 @@ from libtbx import adopt_init_args from scitbx.array_family import flex from scipy.special import erf, erfinv, gammainc +from scipy.stats import poisson import math +import random import os, sys +from copy import deepcopy ''' Port of James Holton's untangle_score.py in Python. Header from original file follows. @@ -83,6 +86,7 @@ def holton_geometry_validation(dm = None, cbetadev_sigma = 0.05, # Sigma for CB position clashscore_ideal_dist = 3, # Ideal distance in LJ for clashscore result lj_dist_that_yields_zero = 6, # Distance for modified LJ to cross zero + n_random = 20, softPnna_params = group_args(group_args_type = 'softPnna_params', y0= 1, a2= -0.0192266, @@ -124,10 +128,14 @@ def holton_geometry_validation(dm = None, # Sort them all sort_geometry_results(info) + # Get expected values for a structure that has a normal distribution of + # everything + analyze_geometry_values_random(info) + # Get worst and average values for each and rescale if desired analyze_geometry_values(info) - # Get residue-based scores + # Get residue-based scores if desired get_residue_scores(info) print_results(info) @@ -322,7 +330,6 @@ def get_base_info(info): info.chain_dict = {} info.model = None - from copy import deepcopy base_info = deepcopy(info) info.log = log @@ -358,7 +365,135 @@ def labels_contain(labels, chain_id = None, resseq = None): return False -def analyze_geometry_values(info): +def analyze_geometry_values_random(info): + keys = list(info.geometry_results.keys()) + original_result_dict = {} + average_dict = {} + for key in keys: + average_dict[key] = {} + average_dict[key]['pnna'] = flex.double() + average_dict[key]['energy'] = flex.double() + average_dict[key]['chisq'] = flex.double() + average_dict[key]['energy_using_mean'] = flex.double() + average_dict[key]['worst_residual'] = flex.double() + average_dict[key]['mean_residual'] = flex.double() + + for key in keys: + original_result_dict[key] = deepcopy(info.geometry_results[key]) + + for i in range(info.n_random): + analyze_geometry_values(info, randomize = True) + for key in keys: + if info.geometry_results[key].pnna is not None: + average_dict[key]['pnna'].append(info.geometry_results[key].pnna) + else: + average_dict[key]['pnna'].append(0) + + if info.geometry_results[key].energy is not None: + average_dict[key]['energy'].append(info.geometry_results[key].energy) + else: + average_dict[key]['energy'].append(0) + + if info.geometry_results[key].chisq is not None: + average_dict[key]['chisq'].append(info.geometry_results[key].chisq) + else: + average_dict[key]['chisq'].append(0) + + if info.geometry_results[key].energy_using_mean is not None: + average_dict[key]['energy_using_mean'].append( + info.geometry_results[key].energy_using_mean) + else: + average_dict[key]['energy_using_mean'].append(0) + + if info.geometry_results[key].worst_residual is not None: + average_dict[key]['worst_residual'].append( + info.geometry_results[key].worst_residual) + else: + average_dict[key]['worst_residual'].append(0) + + # Print out results for randomized value + print( "\n"+79*"=", + "\n VALUES EXPECTED FOR IDEAL STRUCTURE WITH NORMAL DIST OF ERRORS", + "\n"+79*"=", file = info.log) + + for key in keys: + info.geometry_results[key].pnna = average_dict[key]['pnna' + ].min_max_mean().mean + + info.geometry_results[key].energy = average_dict[key]['energy' + ].min_max_mean().mean + + info.geometry_results[key].chisq = average_dict[key]['chisq' + ].min_max_mean().mean + + info.geometry_results[key].energy_using_mean = \ + average_dict[key]['energy_using_mean'].min_max_mean().mean + + info.geometry_results[key].worst_residual = \ + average_dict[key]['worst_residual'].min_max_mean().mean + + sum_random_energy = 0 + for key in keys: + for x in (info.geometry_results[key].energy, + info.geometry_results[key].energy_using_mean): + if x is not None: + sum_random_energy += x + + print_results(info, by_category_only = True ) + + print("\n EXPECTED STANDARD DEVIATIONS OF VALUES ", + file = info.log) + + # Copy over SD instead: + for key in keys: + info.geometry_results[key].pnna = average_dict[key]['pnna' + ].standard_deviation_of_the_sample() + + info.geometry_results[key].energy = average_dict[key]['energy' + ].standard_deviation_of_the_sample() + + info.geometry_results[key].chisq = average_dict[key]['chisq' + ].standard_deviation_of_the_sample() + + info.geometry_results[key].energy_using_mean = \ + average_dict[key]['energy_using_mean' + ].standard_deviation_of_the_sample() + + info.geometry_results[key].worst_residual = \ + average_dict[key]['worst_residual' + ].standard_deviation_of_the_sample() + + print_results(info, by_category_only = True ) + + sum_random_energy_sd_list = flex.double() + for key in keys: + for x in (info.geometry_results[key].energy, + info.geometry_results[key].energy_using_mean): + if x is not None: + sum_random_energy_sd_list.append(x**2) + n = sum_random_energy_sd_list.size() + if n > 0: # sum of squares ** 0.5 + random_energy_sd = (sum_random_energy_sd_list.min_max_mean().mean * n)**0.5 + else: + random_energy_sd = None + + if sum_random_energy and random_energy_sd: + print("\nExpected total energy for ideal structure: %.2f +/- %.2f" %( + sum_random_energy, random_energy_sd), file = info.log) + else: + print("Expected total energy for ideal structure: None +/- None", + file = info.log) + print( "\n"+79*"=", + "\n END OF EXPECTATIONS FOR IDEAL STRUCTURE WITH NORMAL DIST OF ERRORS", + "\n"+79*"=", file = info.log) + info.sum_random_energy = sum_random_energy + info.random_energy_sd = random_energy_sd + + # Restore original + for key in keys: + info.geometry_results[key] = deepcopy(original_result_dict[key]) + +def analyze_geometry_values(info, randomize = False): keys = list(info.geometry_results.keys()) keys.sort() sum_energy = 0.0 @@ -371,6 +506,10 @@ def analyze_geometry_values(info): result.worst_residual = None result.mean_residual = None + + if randomize: + randomize_result(info, result) + if not result.value_list: continue @@ -427,7 +566,7 @@ def analyze_geometry_values(info): energy = filtered_energy(energy) # Special case for CLASH - if result.name == "CLASH" and info.clash_energy_add_n: + if result.name == 'CLASH' and info.clash_energy_add_n: energy += result.n result.energy = result.pnna * energy @@ -447,7 +586,7 @@ def analyze_geometry_values(info): energy_mean = filtered_energy(energy_mean) # Special case for CLASH - if result.name == "CLASH" and info.clash_energy_add_n: + if result.name == 'CLASH' and info.clash_energy_add_n: energy_mean += result.n result.energy_using_mean = result.chisq * energy_mean @@ -456,6 +595,37 @@ def analyze_geometry_values(info): info.sum_energy = sum_energy +def randomize_result(info, result): + if result.name == 'CLASH': + randomize_clash(info, result) + else: # usual + for v in result.value_list: + x = random.gauss(0,1) + r = x**2 + v.residual = r + + result.value_list = sorted(result.value_list, key = lambda v: v.residual, + reverse = True) + result.worst_residual = result.value_list[0].residual \ + if result.value_list else None + +def randomize_clash(info, result): + r = flex.double( + poisson.rvs(0.001, size=info.model.get_sites_cart().size())) + sel = (r > 0) + nn = sel.count(True) + result.value_list = [] + for i in range(nn): + clash_overlap = -0.4 + delta = clash_overlap + dist = info.clashscore_ideal_dist + delta + energy = lj(dist, info.clashscore_ideal_dist, + dist_that_yields_zero = info.lj_dist_that_yields_zero, + round_numbers = info.round_numbers) + value = group_args(group_args_type = 'dummy value', + residual=energy, as_string="None") + result.value_list.append(value) + def sort_geometry_results(info): keys = list(info.geometry_results.keys()) keys.sort() @@ -466,11 +636,12 @@ def sort_geometry_results(info): v.residual, reverse = True) -def print_results(info): +def print_results(info, by_category_only = False): - print("\nSUMMARY of Holton geometry validation scoring for %s" %( - info.filename), file = info.log) - print(file = info.log) + if (not by_category_only): + print("\nSUMMARY of Holton geometry validation scoring for %s" %( + info.filename), file = info.log) + print(file = info.log) info.result_table = {} info.result_header_row = [ @@ -503,6 +674,9 @@ def print_results(info): print(fmt %(tuple(info.result_table[result.name])), file = info.log) + if (by_category_only): + return # done + info.worst_table = {} info.worst_header_row = [' ----- Worst deviation in each category -----'] fmt = "%s" @@ -530,7 +704,14 @@ def print_results(info): if info.ignore_bond_lengths_with_h: print("Total bonds with H removed: %s" %( info.ignore_bond_lengths_with_h_removed), file = info.log) - print("\nOverall geometry energy for %s: %.4f\n" %(info.filename, + + print(file = info.log) + if hasattr(info,'sum_random_energy'): + print("Expected energy for ideal structure with normal dist "+ + "of errors: %.1f +/- %.1f" %( + info.sum_random_energy, info.random_energy_sd), file = info.log) + + print("Overall geometry energy for %s: %.4f\n" %(info.filename, info.sum_energy), file = info.log) def filter_geometry_results(info): From 56944993d141ee194f5152067ee5b1d540bc7f13 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 2 May 2024 13:16:07 -0700 Subject: [PATCH 414/748] Reduce2: ignore UNL residues (unknown ligand) --- mmtbx/hydrogens/reduce_hydrogen.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index 83aa0acf82..5002cf41bf 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -103,6 +103,8 @@ def mon_lib_query(residue, mon_lib_srv, construct_h_restraints=True): # md = get_h_restraints(residue.resname) # return md # if print_time: print(residue.resname, get_class(residue.resname)) + if residue.resname == 'UNL': + return None md, ani = mon_lib_srv.get_comp_comp_id_and_atom_name_interpretation( residue_name=residue.resname, atom_names=residue.atoms().extract_name()) From baa56f5d5fdcec4357b56752447904e1ef2198bc Mon Sep 17 00:00:00 2001 From: Derek Mendez Date: Sat, 4 May 2024 07:54:45 -0700 Subject: [PATCH 415/748] fixes geometry refinement (#990) * fixes geometry refinement * print function future * update README * updated README * updated readme * updated readme --- simtbx/command_line/complete_an_F.py | 6 +- simtbx/command_line/geometry_refiner.py | 1099 +---------------------- simtbx/command_line/hopper_process.py | 58 +- simtbx/diffBragg/README.md | 196 ++-- simtbx/diffBragg/refiners/geometry.py | 1067 ++++++++++++++++++++++ simtbx/modeling/forward_models.py | 2 +- simtbx/modeling/predictions.py | 2 +- simtbx/nanoBragg/nanoBragg_crystal.py | 2 +- 8 files changed, 1248 insertions(+), 1184 deletions(-) create mode 100644 simtbx/diffBragg/refiners/geometry.py diff --git a/simtbx/command_line/complete_an_F.py b/simtbx/command_line/complete_an_F.py index 1bf34dad3e..050fa4aaab 100644 --- a/simtbx/command_line/complete_an_F.py +++ b/simtbx/command_line/complete_an_F.py @@ -14,15 +14,15 @@ from cctbx import miller F = any_reflection_file(args.mtzin).as_miller_arrays()[0] -F = F.as_amplitude_array() if not F.is_xray_amplitude_array(): - F = F.set_observation_type_xray_amplitude() + F = F.as_amplitude_array() +assert F.is_xray_amplitude_array() print("Bin-ID Res-range Completeness #ASU-indices") F.show_completeness() d_max,d_min = F.resolution_range() print("d_min, d_max (Angstrom): ", d_min, d_max) -mset_full = F.build_miller_set(False, d_min=d_min) +mset_full = F.build_miller_set(True, d_min=d_min) mset_full_d = {h: d for h,d in zip(mset_full.d_spacings().indices(), mset_full.d_spacings().data())} Fmap = {h:val for h,val in zip(F.indices(), F.data())} xvals = np.array(F.d_spacings().data()) diff --git a/simtbx/command_line/geometry_refiner.py b/simtbx/command_line/geometry_refiner.py index 4cf4f82809..6c0c750d9a 100644 --- a/simtbx/command_line/geometry_refiner.py +++ b/simtbx/command_line/geometry_refiner.py @@ -1,1083 +1,42 @@ from __future__ import print_function, division # LIBTBX_SET_DISPATCHER_NAME diffBragg.geometry_refiner +from argparse import ArgumentParser +parser = ArgumentParser() +parser.add_argument("--phil", type=str, required=True, help="path to a phil string") +parser.add_argument("--cmdlinePhil", nargs="+", default=None, type=str, help="command line phil params") +progargs = parser.parse_args() -import numpy as np import sys -import time -from simtbx.diffBragg.hopper_io import single_expt_pandas -from copy import deepcopy -import os -from libtbx.mpi4py import MPI -from dials.array_family import flex -COMM = MPI.COMM_WORLD - -import logging -MAIN_LOGGER = logging.getLogger("diffBragg.main") - -from dxtbx.model import Experiment, ExperimentList -from dxtbx.model import Detector, Panel -from simtbx.diffBragg import hopper_utils, ensemble_refine_launcher -from simtbx.diffBragg.refiners.parameters import RangedParameter, Parameters -import pandas -import glob -from pylab import plt -from scipy.optimize import basinhopping -if COMM.rank > 0: - sys.tracebacklimit = 0 -from simtbx.diffBragg import psf - -# diffBragg internal indices for derivative manager -ROTXYZ_ID = hopper_utils.ROTXYZ_IDS -PAN_O_ID = 14 -PAN_F_ID = 17 -PAN_S_ID = 18 -PAN_X_ID = 15 -PAN_Y_ID = 16 -PAN_Z_ID = 10 -PAN_OFS_IDS = PAN_O_ID, PAN_F_ID, PAN_S_ID -PAN_XYZ_IDS = PAN_X_ID, PAN_Y_ID, PAN_Z_ID - -DEG_TO_PI = np.pi/180. - - -def convolve_model_with_psf(model_pix, SIM, pan_fast_slow, roi_id_slices, roi_id_unique): - - if not SIM.use_psf: - return model_pix - PSF = SIM.PSF - psf_args = SIM.psf_args - - coords = pan_fast_slow.as_numpy_array() - fid = coords[1::3] - sid = coords[2::3] - - for i in roi_id_unique: - for slc in roi_id_slices[i]: - fvals = fid[slc] - svals = sid[slc] - f0 = fvals.min() - s0 = svals.min() - f1 = fvals.max() - s1 = svals.max() - fdim = int(f1-f0+1) - sdim = int(s1-s0+1) - img = model_pix[slc].reshape((sdim, fdim)) - img = psf.convolve_with_psf(img, psf=PSF, **psf_args) - model_pix[slc] = img.ravel() - - return model_pix - - -def get_dist_from_R(R): - """ returns prediction offset, R is reflection table""" - x, y, _ = R['xyzobs.px.value'].parts() - x2, y2, _ = R['xyzcal.px'].parts() - dist = np.sqrt((x - x2) ** 2 + (y - y2) ** 2) - return dist - - -class BeamParameters: - def __init__(self, phil_params, data_modelers): - self.parameters = [] - # initialize as the median of all lam0, lam1 values - all_lam0 = [] - all_lam1 = [] - for i_m in data_modelers: - m = data_modelers[i_m] - spec0, spec1 = m.PAR.spec_coef - lam0, lam1 = spec0.init, spec1.init - all_lam0.append(lam0) - all_lam1.append(lam1) - all_lam0 = COMM.reduce(all_lam0) - all_lam1 = COMM.reduce(all_lam1) - global_lam0 = global_lam1 = None - if COMM.rank==0: - global_lam0 = np.median(all_lam0) - global_lam1 = np.median(all_lam1) - global_lam0 = COMM.bcast(global_lam0) - global_lam1 = COMM.bcast(global_lam1) - - for i_p, init_val in enumerate((global_lam0, global_lam1)): - p = RangedParameter(name="lambda%d" % i_p, - init=init_val, - sigma=phil_params.sigmas.spec[i_p], - minval=phil_params.mins.spec[i_p], - maxval=phil_params.maxs.spec[i_p], - fix=phil_params.fix.spec, - center=phil_params.centers.spec[i_p], - beta=phil_params.betas.spec[i_p], - is_global=True) - self.parameters.append(p) - - -class DetectorParameters: - - def __init__(self, phil_params, panel_groups_refined, num_panel_groups): - - self.parameters = [] - GEO = phil_params.geometry - for i_group in range(num_panel_groups): - group_has_data = i_group in panel_groups_refined - if not group_has_data: - continue - vary_rots = [not fixed_flag and group_has_data for fixed_flag in GEO.fix.panel_rotations] - #vary_rots = [True]*3 - - o = RangedParameter(name="group%d_RotOrth" % i_group, - init=0, - sigma=100, # TODO - minval=GEO.min.panel_rotations[0]*DEG_TO_PI, - maxval=GEO.max.panel_rotations[0]*DEG_TO_PI, - fix=not vary_rots[0], center=0, beta=GEO.betas.panel_rot[0], is_global=True) - - f = RangedParameter(name="group%d_RotFast" % i_group, - init=0, - sigma=100, # TODO - minval=GEO.min.panel_rotations[1]*DEG_TO_PI, - maxval=GEO.max.panel_rotations[1]*DEG_TO_PI, - fix=not vary_rots[1], center=0, beta=GEO.betas.panel_rot[1], - is_global=True) - - s = RangedParameter(name="group%d_RotSlow" % i_group, - init=0, - sigma=100, # TODO - minval=GEO.min.panel_rotations[2]*DEG_TO_PI, - maxval=GEO.max.panel_rotations[2]*DEG_TO_PI, - fix=not vary_rots[2], center=0, beta=GEO.betas.panel_rot[2], - is_global=True) - - vary_shifts = [not fixed_flag and group_has_data for fixed_flag in GEO.fix.panel_translations] - #vary_shifts = [True]*3 - x = RangedParameter(name="group%d_ShiftX" % i_group, init=0, - sigma=100, - minval=GEO.min.panel_translations[0]*1e-3, maxval=GEO.max.panel_translations[0]*1e-3, - fix=not vary_shifts[0], center=0, beta=GEO.betas.panel_xyz[0], - is_global=True) - y = RangedParameter(name="group%d_ShiftY" % i_group, init=0, - sigma=100, - minval=GEO.min.panel_translations[1]*1e-3, maxval=GEO.max.panel_translations[1]*1e-3, - fix=not vary_shifts[1], center=0, beta=GEO.betas.panel_xyz[1], - is_global=True) - z = RangedParameter(name="group%d_ShiftZ" % i_group, init=0, - sigma=100, - minval=GEO.min.panel_translations[2]*1e-3, maxval=GEO.max.panel_translations[2]*1e-3, - fix=not vary_shifts[2], center=0, beta=GEO.betas.panel_xyz[2], - is_global=True) - - self.parameters += [o, f, s, x, y, z] - - - -class CrystalParameters: - - def __init__(self, phil_params, data_modelers): - self.phil = phil_params - self.parameters = [] - for i_shot in data_modelers: - Mod = data_modelers[i_shot] - - # set the per-spot scale factors, per pixel... - Mod.set_slices("roi_id") - Mod.per_roi_scales_per_pix = np.ones_like(Mod.all_data) - for roi_id, ref_idx in enumerate(Mod.refls_idx): - if "scale_factor" in list(Mod.refls[0].keys()): - slcs = Mod.roi_id_slices[roi_id] - assert len(slcs)==1 - slc = slcs[0] - init_scale = Mod.refls[ref_idx]["scale_factor"] - Mod.per_roi_scales_per_pix[slc] =init_scale - else: - init_scale = 1 - - p = RangedParameter(name="rank%d_shot%d_scale_roi%d" % (COMM.rank, i_shot, roi_id), - minval=0, maxval=1e12, fix=self.phil.fix.perRoiScale, - center=1, beta=1e12, init=init_scale) - self.parameters.append(p) - - for i_N in range(3): - p = Mod.PAR.Nabc[i_N] - ref_p = RangedParameter(name="rank%d_shot%d_Nabc%d" % (COMM.rank, i_shot, i_N), - minval=p.minval, maxval=p.maxval, fix=self.phil.fix.Nabc, init=p.init, - center=p.center, beta=p.beta) - self.parameters.append(ref_p) - - for i_N in range(3): - p = Mod.PAR.Ndef[i_N] - ref_p = RangedParameter(name="rank%d_shot%d_Ndef%d" % (COMM.rank, i_shot, i_N), - minval=p.minval, maxval=p.maxval, fix=self.phil.fix.Ndef, init=p.init, - center=p.center, beta=p.beta) - self.parameters.append(ref_p) - - for i_eta in range(3): - p = Mod.PAR.eta[i_eta] - ref_p = RangedParameter(name="rank%d_shot%d_eta%d" % (COMM.rank, i_shot, i_eta), - minval=p.minval, maxval=p.maxval, fix=self.phil.fix.eta_abc, init=p.init, - center=p.center, beta=p.beta) - self.parameters.append(ref_p) - - for i_rot in range(3): - p = Mod.PAR.RotXYZ_params[i_rot] - ref_p = RangedParameter(name="rank%d_shot%d_RotXYZ%d" % (COMM.rank, i_shot, i_rot), - minval=p.minval, maxval=p.maxval, fix=self.phil.fix.RotXYZ, init=p.init, - center=p.center, beta=p.beta) - self.parameters.append(ref_p) - - p = Mod.PAR.Scale - ref_p = RangedParameter(name="rank%d_shot%d_Scale" % (COMM.rank, i_shot), - minval=p.minval, maxval=p.maxval, fix=self.phil.fix.G, init=p.init, - center=p.center, beta=p.beta) - self.parameters.append(ref_p) - - for i_uc in range(len(Mod.PAR.ucell)): - p = Mod.PAR.ucell[i_uc] - ref_p = RangedParameter(name="rank%d_shot%d_Ucell%d" % (COMM.rank, i_shot, i_uc), - minval=p.minval, maxval=p.maxval, fix=self.phil.fix.ucell, init=p.init, - center=p.center, beta=p.beta) - self.parameters.append(ref_p) - - -class Target: - def __init__(self, ref_params, save_state_freq=500, overwrite_state=True, plot=False): - """ - - :param ref_params: instance of refinement Parameters (LMP in code below) - :param save_state_freq: how often to save all models (will be overwritten each time) - """ - num_params = len(ref_params) - self.vary = np.zeros(num_params).astype(bool) - for p in ref_params.values(): - self.vary[p.xpos] = not p.fix - self.x0 = np.ones(num_params) - self.g = None - self.ref_params = ref_params - self.iternum = 0 - self.all_times = [] - self.save_state_freq = save_state_freq - self.overwrite_state = overwrite_state - self.med_offsets = [] # median prediction offsets(new number gets added everytime write_output_files is called) - self.med_iternums = [] - self.plot = plot and COMM.rank==0 - if self.plot: - self.fig = plt.figure() - self.ax = plt.gca() - plt.draw() - plt.pause(0.1) - - def __call__(self, x, *args, **kwargs): - self.iternum += 1 - t = time.time() - self.x0[self.vary] = x - #time_per_iter = (time.time()-self.tstart) / self.iternum - - f, self.g, self.sigmaZ = target_and_grad(self.x0, self.ref_params, *args, **kwargs) - t = time.time()-t - if COMM.rank==0: - self.all_times.append(t) - time_per_iter = np.mean(self.all_times) - pred_offset_str = ", ".join(map(lambda x: "%.4f" %x, self.med_offsets)) - print("Iteration %d:\n\tResid=%f, sigmaZ %f, t-per-iter=%.4f sec, pred_offsets=%s" - % (self.iternum, f, self.sigmaZ, time_per_iter, pred_offset_str), flush=True) - if self.iternum % self.save_state_freq==0 and self.iternum >0: - if not self.overwrite_state: - params = args[-1] # phil params - temp_pandas_dir = params.geometry.pandas_dir - params.geometry.pandas_dir=params.geometry.pandas_dir + "-iter%d" % self.iternum - med_offset = write_output_files(self.x0, self.ref_params, *args, **kwargs) - self.med_offsets.append(med_offset) - self.med_iternums.append(self.iternum) - if self.plot: - self.ax.clear() - self.ax.plot(self.med_iternums, self.med_offsets) - self.ax.set_ylabel("median |xobs-xcal| (pixels)") - self.ax.set_xlabel("iteration #") - plt.draw() - plt.pause(0.01) - if not self.overwrite_state: - params.geometry.pandas_dir=temp_pandas_dir - return f - - def jac(self, x, *args): - if self.g is not None: - return self.g[self.vary] - - def at_min_callback(self, x, f, accept): - if COMM.rank==0: - print("Final Iteration %d:\n\tResid=%f, sigmaZ %f" % (self.iternum, f, self.sigmaZ)) - - -def model(x, ref_params, i_shot, Modeler, SIM, return_bragg_model=False): - """ - - :param x: rescaled parameter array (global) - :param ref_params: simtbx.diffBragg.refiners.parameters.Parameters() instance - :param i_shot: shot index for this data model, - the simtbx.diffBragg.refiners.parameters.RangerParameter objs stored in ref_params - have names which include i_shot - :param Modeler: DataModeler for i_shot - :param SIM: instance of sim_data.SimData - :param return_bragg_model: if true, bypass the latter half of the method and return the Bragg scattering model - :return: either the Bragg scattering model (if return_model), or else a 3-tuple of - (float, dict of float, float) - (negative log likelihood, gradient of negative log likelihood, average sigmaZ for the shot) - """ - - rotX = ref_params["rank%d_shot%d_RotXYZ%d" % (COMM.rank, i_shot, 0)] - rotY = ref_params["rank%d_shot%d_RotXYZ%d" % (COMM.rank, i_shot, 1)] - rotZ = ref_params["rank%d_shot%d_RotXYZ%d" % (COMM.rank, i_shot, 2)] - Na = ref_params["rank%d_shot%d_Nabc%d" % (COMM.rank, i_shot, 0)] - Nb = ref_params["rank%d_shot%d_Nabc%d" % (COMM.rank, i_shot, 1)] - Nc = ref_params["rank%d_shot%d_Nabc%d" % (COMM.rank, i_shot, 2)] - Nd = ref_params["rank%d_shot%d_Ndef%d" % (COMM.rank, i_shot, 0)] - Ne = ref_params["rank%d_shot%d_Ndef%d" % (COMM.rank, i_shot, 1)] - Nf = ref_params["rank%d_shot%d_Ndef%d" % (COMM.rank, i_shot, 2)] - eta_a = ref_params["rank%d_shot%d_eta%d" % (COMM.rank, i_shot, 0)] - eta_b = ref_params["rank%d_shot%d_eta%d" % (COMM.rank, i_shot, 1)] - eta_c = ref_params["rank%d_shot%d_eta%d" % (COMM.rank, i_shot, 2)] - G = ref_params["rank%d_shot%d_Scale" % (COMM.rank, i_shot)] - num_uc_p = len(Modeler.ucell_man.variables) - ucell_pars = [ref_params["rank%d_shot%d_Ucell%d" % (COMM.rank, i_shot, i_uc)] for i_uc in range(num_uc_p)] - lam0 = ref_params["lambda0"] - lam1 = ref_params["lambda1"] - - # update the rotational mosaicity here - # update the mosaicity here - eta_params = [eta_a, eta_b, eta_c] - if SIM.umat_maker is not None: - # we are modeling mosaic spread - eta_abc = [p.get_val(x[p.xpos]) for p in eta_params] - #if not SIM.D.has_anisotropic_mosaic_spread: - # eta_abc = eta_abc[0] - SIM.update_umats_for_refinement(eta_abc) - - # update the photon energy spectrum for this shot - SIM.beam.spectrum = Modeler.spectra - SIM.D.xray_beams = SIM.beam.xray_beams - # update the lambda coeff - lambda_coef = lam0.get_val(x[lam0.xpos]), lam1.get_val(x[lam1.xpos]) - SIM.D.lambda_coefficients = lambda_coef - - # update the Bmatrix - Modeler.ucell_man.variables = [p.get_val(x[p.xpos]) for p in ucell_pars] - Bmatrix = Modeler.ucell_man.B_recipspace - SIM.D.Bmatrix = Bmatrix - for i_ucell in range(len(ucell_pars)): - SIM.D.set_ucell_derivative_matrix( - i_ucell + hopper_utils.UCELL_ID_OFFSET, - Modeler.ucell_man.derivative_matrices[i_ucell]) - eta_a = ref_params["rank%d_shot%d_eta%d" % (COMM.rank, i_shot, 0)] - eta_b = ref_params["rank%d_shot%d_eta%d" % (COMM.rank, i_shot, 1)] - eta_c = ref_params["rank%d_shot%d_eta%d" % (COMM.rank, i_shot, 2)] - G = ref_params["rank%d_shot%d_Scale" % (COMM.rank, i_shot)] - num_uc_p = len(Modeler.ucell_man.variables) - ucell_pars = [ref_params["rank%d_shot%d_Ucell%d" % (COMM.rank, i_shot, i_uc)] for i_uc in range(num_uc_p)] - - # update the rotational mosaicity here - # update the mosaicity here - eta_params = [eta_a, eta_b, eta_c] - if SIM.umat_maker is not None: - # we are modeling mosaic spread - eta_abc = [p.get_val(x[p.xpos]) for p in eta_params] - #if not SIM.D.has_anisotropic_mosaic_spread: - # eta_abc = eta_abc[0] - SIM.update_umats_for_refinement(eta_abc) - - # update the photon energy spectrum for this shot - SIM.beam.spectrum = Modeler.spectra - SIM.D.xray_beams = SIM.beam.xray_beams - - # update the Bmatrix - Modeler.ucell_man.variables = [p.get_val(x[p.xpos]) for p in ucell_pars] - Bmatrix = Modeler.ucell_man.B_recipspace - SIM.D.Bmatrix = Bmatrix - for i_ucell in range(len(ucell_pars)): - SIM.D.set_ucell_derivative_matrix( - i_ucell + hopper_utils.UCELL_ID_OFFSET, - Modeler.ucell_man.derivative_matrices[i_ucell]) - - # update the Umat rotation matrix and the RotXYZ perturbation - SIM.D.Umatrix = Modeler.PAR.Umatrix - SIM.D.set_value(hopper_utils.ROTX_ID, rotX.get_val(x[rotX.xpos])) - SIM.D.set_value(hopper_utils.ROTY_ID, rotY.get_val(x[rotY.xpos])) - SIM.D.set_value(hopper_utils.ROTZ_ID, rotZ.get_val(x[rotZ.xpos])) - - # update the mosaic block size - SIM.D.set_ncells_values((Na.get_val(x[Na.xpos]), - Nb.get_val(x[Nb.xpos]), - Nc.get_val(x[Nc.xpos]))) - SIM.D.Ncells_def = (Nd.get_val(x[Nd.xpos]), - Ne.get_val(x[Ne.xpos]), - Nf.get_val(x[Nf.xpos])) - - npix = int(len(Modeler.pan_fast_slow)/3.) - - # calculate the forward Bragg scattering and gradients - SIM.D.add_diffBragg_spots(Modeler.pan_fast_slow) - - # set the scale factors per ROI - perRoiScaleFactors = {} - for roi_id, ref_idx in enumerate(Modeler.refls_idx): - p = ref_params["rank%d_shot%d_scale_roi%d" % (COMM.rank, i_shot, roi_id )] - slc = Modeler.roi_id_slices[roi_id][0] # Note, there's always just one slice for roi_id - if not p.refine: - break - scale_fac = p.get_val(x[p.xpos]) - Modeler.per_roi_scales_per_pix[slc] = scale_fac - perRoiScaleFactors[roi_id] = (scale_fac, p) - - bragg_no_scale = (SIM.D.raw_pixels_roi[:npix]).as_numpy_array() - - # get the per-shot scale factor - scale = G.get_val(x[G.xpos]) - - #combined the per-shot scale factor with the per-roi scale factors - all_bragg_scales = scale*Modeler.per_roi_scales_per_pix - - # scale the bragg scattering - bragg = all_bragg_scales*bragg_no_scale - if return_bragg_model: - return bragg - - # this is the total forward model: - model_pix = bragg + Modeler.all_background - if SIM.use_psf: - model_pix = convolve_model_with_psf(model_pix, SIM, Modeler.pan_fast_slow, roi_id_slices=Modeler.roi_id_slices, roi_id_unique=Modeler.roi_id_unique) - - - # compute the negative log Likelihood - resid = (Modeler.all_data - model_pix) - resid_square = resid ** 2 - V = model_pix + Modeler.nominal_sigma_rdout ** 2 - neg_LL = (.5*(np.log(2*np.pi*V) + resid_square / V))[Modeler.all_trusted].sum() - - # compute the z-score sigma as a diagnostic - zscore_sigma = np.std((resid / np.sqrt(V))[Modeler.all_trusted]) - - # store the gradients - J = {} - # this term is a common factor in all of the gradients - common_grad_term = (0.5 / V * (1 - 2 * resid - resid_square / V)) - - if perRoiScaleFactors: - # the gradient in this case is the bragg scattering, scaled by only the total shot scale (G in the literature) - bragg_no_roi = bragg_no_scale*scale - - for roi_id in perRoiScaleFactors: - scale_fac, p = perRoiScaleFactors[roi_id] - slc = Modeler.roi_id_slices[roi_id][0] # theres just one slice for each roi_id - d = p.get_deriv(x[p.xpos], bragg_no_roi[slc]) - - if SIM.use_psf: - x1,x2,y1,y2 = Modeler.rois[roi_id] - sdim, fdim = y2-y1, x2-x1 - d_img = d.reshape((sdim, fdim)) - d_img = psf.convolve_with_psf(d_img, psf=SIM.PSF, **SIM.psf_args) - d = d_img.ravel() - - d_trusted = Modeler.all_trusted[slc] - common_term_slc = common_grad_term[slc] - J[p.name] = (common_term_slc*d)[d_trusted].sum() - - # scale factor gradients - conv_args = {"SIM": SIM, "pan_fast_slow": Modeler.pan_fast_slow, "roi_id_slices": Modeler.roi_id_slices, "roi_id_unique": Modeler.roi_id_unique} - if not G.fix: - bragg_no_roi_scale = bragg_no_scale*Modeler.per_roi_scales_per_pix - scale_grad = G.get_deriv(x[G.xpos], bragg_no_roi_scale) - scale_grad = convolve_model_with_psf(scale_grad, **conv_args) - J[G.name] = (common_grad_term*scale_grad)[Modeler.all_trusted].sum() - - # Umat gradients - for i_rot, rot in enumerate([rotX, rotY, rotZ]): - if not rot.fix: - rot_db_id = ROTXYZ_ID[i_rot] - rot_grad = scale*SIM.D.get_derivative_pixels(rot_db_id).as_numpy_array()[:npix] - rot_grad = rot.get_deriv(x[rot.xpos], rot_grad) - rot_grad = convolve_model_with_psf(rot_grad, **conv_args) - J[rot.name] = (common_grad_term*rot_grad)[Modeler.all_trusted].sum() - - # mosaic block size gradients - if not Na.fix: - Nabc_grad = SIM.D.get_ncells_derivative_pixels() - for i_N, N in enumerate([Na, Nb, Nc]): - N_grad = scale*(Nabc_grad[i_N][:npix].as_numpy_array()) - N_grad = N.get_deriv(x[N.xpos], N_grad) - N_grad = convolve_model_with_psf(N_grad, **conv_args) - J[N.name] = (common_grad_term*N_grad)[Modeler.all_trusted].sum() - - if not Nd.fix: - Ndef_grad = SIM.D.get_ncells_def_derivative_pixels() - for i_N, N in enumerate([Nf, Ne, Nf]): - N_grad = scale*(Ndef_grad[i_N][:npix].as_numpy_array()) - N_grad = N.get_deriv(x[N.xpos], N_grad) - N_grad = convolve_model_with_psf(N_grad, **conv_args) - J[N.name] = (common_grad_term*N_grad)[Modeler.all_trusted].sum() - - if not eta_a.fix: - if SIM.D.has_anisotropic_mosaic_spread: - eta_abc_derivs = SIM.D.get_aniso_eta_deriv_pixels() - else: - eta_abc_derivs = [SIM.D.get_derivative_pixels(hopper_utils.ETA_ID)] - for i_eta, eta in enumerate(eta_params): - eta_grad = scale*(eta_abc_derivs[i_eta][:npix].as_numpy_array()) - eta_grad = eta.get_deriv(x[eta.xpos], eta_grad) - eta_grad = convolve_model_with_psf(eta_grad, **conv_args) - J[eta.name] = (common_grad_term*eta_grad)[Modeler.all_trusted].sum() - if not SIM.D.has_anisotropic_mosaic_spread: - break - - # unit cell gradients - if not ucell_pars[0].fix: - for i_ucell, uc_p in enumerate(ucell_pars): - d = scale*SIM.D.get_derivative_pixels(hopper_utils.UCELL_ID_OFFSET+i_ucell).as_numpy_array()[:npix] - d = uc_p.get_deriv(x[uc_p.xpos], d) - d = convolve_model_with_psf(d, **conv_args) - J[ucell_pars[i_ucell].name] = (common_grad_term*d)[Modeler.all_trusted].sum() - - if not lam0.fix: - lambda_derivs = SIM.D.get_lambda_derivative_pixels() - lam_params = lam0, lam1 - for d, pr in zip(lambda_derivs, lam_params): - d = d.as_numpy_array()[:npix] - d = pr.get_deriv(x[pr.xpos], d) - d = convolve_model_with_psf(d, **conv_args) - J[pr.name] = (common_grad_term*d)[Modeler.all_trusted].sum() - # detector model gradients - detector_derivs = [] - for diffbragg_parameter_id in PAN_OFS_IDS+PAN_XYZ_IDS: - try: - d = SIM.D.get_derivative_pixels(diffbragg_parameter_id).as_numpy_array()[:npix] - d = convolve_model_with_psf(d, **conv_args) - d = common_grad_term*scale*d - except ValueError: - d = None - detector_derivs.append(d) - names = "RotOrth", "RotFast", "RotSlow", "ShiftX", "ShiftY", "ShiftZ" - for group_id in Modeler.unique_panel_group_ids: - for name in names: - J["group%d_%s" % (group_id, name)] = 0 - for pixel_rng in Modeler.group_id_slices[group_id]: - trusted_pixels = Modeler.all_trusted[pixel_rng] - for i_name, name in enumerate(names): - par_name = "group%d_%s" % (group_id, name) - det_param = ref_params[par_name] - if det_param.fix: - continue - pixderivs = detector_derivs[i_name][pixel_rng][trusted_pixels] - pixderivs = det_param.get_deriv(x[det_param.xpos], pixderivs) - J[par_name] += pixderivs.sum() +from libtbx.mpi4py import MPI +from libtbx.phil import parse +from simtbx.diffBragg.device import DeviceWrapper +from simtbx.diffBragg.phil import philz, hopper_phil - return neg_LL, J, model_pix, zscore_sigma - - -def set_group_id_slices(Modeler, group_id_from_panel_id): - """finds the boundaries for each panel group ID in the 1-D array of per-shot data - Modeler: DataModeler instance with loaded data - group_id_from_panel_id : dict where key is panel id and value is group id - """ - Modeler.all_group_id = [group_id_from_panel_id[pid] for pid in Modeler.all_pid] - splitter = np.where(np.diff(Modeler.all_group_id) != 0)[0]+1 - npix = len(Modeler.all_data) - slices = [slice(V[0], V[-1]+1, 1) for V in np.split(np.arange(npix), splitter)] - group_ids = [V[0] for V in np.split(np.array(Modeler.all_group_id), splitter)] - group_id_slices = {} - for i_group, slc in zip(group_ids, slices): - if i_group not in group_id_slices: - group_id_slices[i_group] = [slc] - else: - group_id_slices[i_group].append(slc) - Modeler.unique_panel_group_ids = set(Modeler.all_group_id) - logging.debug("Modeler has data on %d unique panel groups" % (len(Modeler.unique_panel_group_ids))) - Modeler.group_id_slices = group_id_slices - - -def update_detector(x, ref_params, SIM, save=None): - """ - Update the internal geometry of the diffBragg instance - :param x: refinement parameters as seen by scipy.optimize (e.g. rescaled floats) - :param ref_params: diffBragg.refiners.Parameters (dict of RangedParameters) - :param SIM: SIM instance (instance of nanoBragg.sim_data.SimData) - :param save: optional name to save the detector - """ - det = SIM.detector - if save is not None: - new_det = Detector() - for pid in range(len(det)): - panel = det[pid] - panel_dict = panel.to_dict() - - group_id = SIM.panel_group_from_id[pid] - if group_id not in SIM.panel_groups_refined: - fdet = panel.get_fast_axis() - sdet = panel.get_slow_axis() - origin = panel.get_origin() - else: - - Oang_p = ref_params["group%d_RotOrth" % group_id] - Fang_p = ref_params["group%d_RotFast" % group_id] - Sang_p = ref_params["group%d_RotSlow" % group_id] - Xdist_p = ref_params["group%d_ShiftX" % group_id] - Ydist_p = ref_params["group%d_ShiftY" % group_id] - Zdist_p = ref_params["group%d_ShiftZ" % group_id] - - Oang = Oang_p.get_val(x[Oang_p.xpos]) - Fang = Fang_p.get_val(x[Fang_p.xpos]) - Sang = Sang_p.get_val(x[Sang_p.xpos]) - Xdist = Xdist_p.get_val(x[Xdist_p.xpos]) - Ydist = Ydist_p.get_val(x[Ydist_p.xpos]) - Zdist = Zdist_p.get_val(x[Zdist_p.xpos]) - - origin_of_rotation = SIM.panel_reference_from_id[pid] - SIM.D.reference_origin = origin_of_rotation - SIM.D.update_dxtbx_geoms(det, SIM.beam.nanoBragg_constructor_beam, pid, - Oang, Fang, Sang, Xdist, Ydist, Zdist, - force=False) - fdet = SIM.D.fdet_vector - sdet = SIM.D.sdet_vector - origin = SIM.D.get_origin() - - if save is not None: - panel_dict["fast_axis"] = fdet - panel_dict["slow_axis"] = sdet - panel_dict["origin"] = origin - new_det.add_panel(Panel.from_dict(panel_dict)) - - if save is not None and COMM.rank==0: - t = time.time() - El = ExperimentList() - E = Experiment() - E.detector = new_det - El.append(E) - El.as_file(save) - t = time.time()-t - #print("Saved detector model to %s (took %.4f sec)" % (save, t), flush=True ) - - -def target_and_grad(x, ref_params, data_modelers, SIM, params): - """ - Returns the target functional and the gradients - :param x: float array of parameter values as seen by scipt.optimize (rescaled) - :param ref_params: refinement parameter objects (diffBragg.refiners.parameters.Parameters() ) - :param data_modelers: dict of data modelers (one per experiment) - :param SIM: sim_data instance - :param params: phil parameters - :return: 2-tuple, target and gradients - """ - target_functional = 0 - grad = np.zeros(len(x)) - - save_name = params.geometry.optimized_detector_name - update_detector(x, ref_params, SIM, save_name) - - all_shot_sigZ = [] - for i_shot in data_modelers: - Modeler = data_modelers[i_shot] - - neg_LL, neg_LL_grad, model_pix, per_shot_sigZ = model(x, ref_params, i_shot, Modeler, SIM) - all_shot_sigZ.append(per_shot_sigZ) - - # accumulate the target functional for this rank/shot - target_functional += neg_LL - - if params.use_restraints: - for name in ref_params: - if name.startswith("Fhkl"): - continue - par = ref_params[name] - if not par.is_global and not par.fix: - val = par.get_restraint_val(x[par.xpos]) - target_functional += val - - # accumulate the gradients for this rank/shot - for name in ref_params: - if name in neg_LL_grad: - par = ref_params[name] - grad[par.xpos] += neg_LL_grad[name] - # for restraints only update the per-shot restraint gradients here - if params.use_restraints and not par.is_global and not par.fix: - grad[par.xpos] += par.get_restraint_deriv(x[par.xpos]) - - # sum the target functional and the gradients across all ranks - target_functional = COMM.bcast(COMM.reduce(target_functional)) - grad = COMM.bcast(COMM.reduce(grad)) - - if params.use_restraints and params.geometry.betas.close_distances is not None: - target_functional += np.std(SIM.D.close_distances) / params.geometry.betas.close_distances - - ## add in the detector parameter restraints - if params.use_restraints: - for name in ref_params: - if name.startswith("Fhkl"): - continue - par = ref_params[name] - if par.is_global and not par.fix: - target_functional += par.get_restraint_val(x[par.xpos]) - grad[par.xpos] += par.get_restraint_deriv(x[par.xpos]) - - all_shot_sigZ = COMM.reduce(all_shot_sigZ) - if COMM.rank == 0: - all_shot_sigZ = np.median(all_shot_sigZ) - - return target_functional, grad, all_shot_sigZ - - -def geom_min(params): - """ - :param params: phil parameters (simtbx/diffBragg/phil.py) - """ - - launcher = ensemble_refine_launcher.RefineLauncher(params) - if params.geometry.input_pkl is not None: - df = pandas.read_pickle(params.geometry.input_pkl) - else: - assert params.geometry.input_pkl_glob is not None - fnames = glob.glob(params.geometry.input_pkl_glob) - dfs = [] - for i_f, f in enumerate(fnames): - if i_f % COMM.size != COMM.rank: - continue - if COMM.rank==0: - print("Loaing hopper pkl %d / %d" %(i_f+1, len(fnames)), flush=True) - df_i = pandas.read_pickle(f) - dfs.append(df_i) - dfs = COMM.reduce(dfs) - if COMM.rank==0: - df = pandas.concat(dfs) - else: - df = None - df = COMM.bcast(df) - - if params.skip is not None: - df = df.iloc[params.skip:] - if params.first_n is not None: - df = df.iloc[:params.first_n] - - pdir = params.geometry.pandas_dir - assert pdir is not None, "provide a pandas_dir where output files will be generated" - params.geometry.optimized_detector_name = os.path.join(pdir, os.path.basename(params.geometry.optimized_detector_name)) - if COMM.rank==0: - if not os.path.exists(pdir): - os.makedirs(pdir) - if COMM.rank == 0: - print("Will optimize using %d experiments" %len(df)) - - from simtbx.diffBragg import mpi_logger - mpi_logger.setup_logging_from_params(params) - - launcher.load_inputs(df, refls_key=params.geometry.refls_key) - - for i_shot in launcher.Modelers: - Modeler = launcher.Modelers[i_shot] - set_group_id_slices(Modeler, launcher.panel_group_from_id) - - # same on every rank: - det_params = DetectorParameters(params, launcher.panel_groups_refined, launcher.n_panel_groups) - - beam_params = BeamParameters(params, launcher.Modelers) - - # different on each rank - crystal_params = CrystalParameters(params,launcher.Modelers) - crystal_params.parameters = COMM.bcast(COMM.reduce(crystal_params.parameters)) - - LMP = Parameters() - for p in crystal_params.parameters + det_params.parameters + beam_params.parameters: - LMP.add(p) - - # use spectrum coefficients - launcher.SIM.D.use_lambda_coefficients = True - launcher.SIM.D.lambda_coefficients = LMP["lambda0"].init, LMP["lambda1"].init - - # attached some objects to SIM for convenience - launcher.SIM.panel_reference_from_id = launcher.panel_reference_from_id - launcher.SIM.panel_group_from_id = launcher.panel_group_from_id - launcher.SIM.panel_groups_refined = launcher.panel_groups_refined - - # set the GPU device - launcher.SIM.D.device_Id = COMM.rank % params.refiner.num_devices - npx_str = "(rnk%d, dev%d): %d pix" %(COMM.rank, launcher.SIM.D.device_Id, launcher.NPIX_TO_ALLOC) - npx_str = COMM.gather(npx_str) - if COMM.rank==0: - print("How many pixels each rank will allocate for on its device:") - print("; ".join(npx_str)) - launcher.SIM.D.Npix_to_allocate = launcher.NPIX_TO_ALLOC - - # configure diffBragg instance for gradient computation - if not params.fix.RotXYZ: - for i_rot in range(3): - launcher.SIM.D.refine(ROTXYZ_ID[i_rot]) - if not params.fix.spec: - launcher.SIM.D.refine(hopper_utils.LAMBDA_IDS[0]) - launcher.SIM.D.refine(hopper_utils.LAMBDA_IDS[1]) - if not params.fix.eta_abc: - launcher.SIM.D.refine(hopper_utils.ETA_ID) - if not params.fix.Nabc: - launcher.SIM.D.refine(hopper_utils.NCELLS_ID) - if not params.fix.Ndef: - launcher.SIM.D.refine(hopper_utils.NCELLS_ID_OFFDIAG) - if not params.fix.ucell: - for i_ucell in range(launcher.SIM.num_ucell_param): - launcher.SIM.D.refine(hopper_utils.UCELL_ID_OFFSET + i_ucell) - for i, diffbragg_id in enumerate(PAN_OFS_IDS): - if not params.geometry.fix.panel_rotations[i]: - launcher.SIM.D.refine(diffbragg_id) - - for i, diffbragg_id in enumerate(PAN_XYZ_IDS): - if not params.geometry.fix.panel_translations[i]: - launcher.SIM.D.refine(diffbragg_id) - - # do a barrel roll! - target = Target(LMP, save_state_freq=params.geometry.save_state_freq, overwrite_state=params.geometry.save_state_overwrite) - fcn_args = (launcher.Modelers, launcher.SIM, params) - lbfgs_kws = {"jac": target.jac, - "method": "L-BFGS-B", - "args": fcn_args, - "options": {"ftol": params.ftol, "gtol": 1e-10, "maxfun":1e5, "maxiter":params.lbfgs_maxiter}} - - result = basinhopping(target, target.x0[target.vary], - niter=params.niter, - minimizer_kwargs=lbfgs_kws, - T=params.temp, - callback=target.at_min_callback, - disp=False, - stepsize=params.stepsize) - - target.x0[target.vary] = result.x - Xopt = target.x0 # optimized, rescaled parameters - - if params.geometry.optimized_results_tag is not None: - write_output_files(Xopt, LMP, launcher.Modelers, launcher.SIM, params) - - if COMM.rank == 0: - save_opt_det(params, target.x0, target.ref_params, launcher.SIM) - - -def write_output_files(Xopt, LMP, Modelers, SIM, params): - """ - Writes refl and exper files for each experiment modeled during - the ensemble refiner - :param Xopt: float array of optimized rescaled parameter values - :param LMP: simtbx.diffBragg.refiners.parameters.Parameters() object - :param Modelers: data modelers (launcher.Modleers - :param SIM: instance of sim_data (launcher.SIM) - :param params: phil params, simtbx.diffBragg.phil.py - """ - opt_det = get_optimized_detector(Xopt, LMP, SIM) - - if params.geometry.pandas_dir is not None and COMM.rank == 0: - if not os.path.exists(params.geometry.pandas_dir): - os.makedirs(params.geometry.pandas_dir) - refdir = os.path.join(params.geometry.pandas_dir, "refls") - expdir = os.path.join(params.geometry.pandas_dir, "expts") - for dname in [refdir, expdir]: - if not os.path.exists(dname): - os.makedirs(dname) - - lam0_lam1 = [] - for i_lam in [0,1]: - lam_p = LMP["lambda%d"% i_lam] - val = lam_p.get_val(Xopt[lam_p.xpos]) - lam0_lam1.append(val) - - all_shot_pred_offsets = [] - for i_shot in Modelers: - Modeler = Modelers[i_shot] - # these are in simtbx.diffBragg.refiners.parameters.RangedParameter objects - rotX = LMP["rank%d_shot%d_RotXYZ%d" % (COMM.rank, i_shot, 0)] - rotY = LMP["rank%d_shot%d_RotXYZ%d" % (COMM.rank, i_shot, 1)] - rotZ = LMP["rank%d_shot%d_RotXYZ%d" % (COMM.rank, i_shot, 2)] - num_uc_p = len(Modeler.ucell_man.variables) - ucell_pars = [LMP["rank%d_shot%d_Ucell%d" % (COMM.rank, i_shot, i_uc)] for i_uc in range(num_uc_p)] - - # convert rotation angles back to radians (thats what the parameters.RangedParamter.get_val method does) - rotXYZ = rotX.get_val(Xopt[rotX.xpos]),\ - rotY.get_val(Xopt[rotY.xpos]),\ - rotZ.get_val(Xopt[rotZ.xpos]) - - # ucell_man is an instance of - # simtbx.diffBragg.refiners.crystal_systems.manager.Manager() - # (for the correct xtal system) - Modeler.ucell_man.variables = [p.get_val(Xopt[p.xpos]) for p in ucell_pars] - ucpar = Modeler.ucell_man.unit_cell_parameters - - new_crystal = hopper_utils.new_cryst_from_rotXYZ_and_ucell(rotXYZ, ucpar, Modeler.E.crystal) - new_exp = deepcopy(Modeler.E) - new_exp.crystal = new_crystal - wave, wt = map(np.array, zip(*Modeler.spectra)) - ave_wave = (wave*wt).sum()/wt.sum() - new_exp.beam.set_wavelength(ave_wave) - new_exp.detector = opt_det - - Modeler.best_model = model(Xopt, LMP, i_shot, Modeler, SIM, return_bragg_model=True) - Modeler.best_model_includes_background = False - - # store the updated per-roi scale factors in the new refl table - roi_scale_factor = flex.double(len(Modeler.refls), 1) - for roi_id in Modeler.roi_id_unique: - p = LMP["rank%d_shot%d_scale_roi%d" % (COMM.rank, i_shot, roi_id)] - scale_fac = p.get_val(Xopt[p.xpos]) - test_refl_idx = Modeler.refls_idx[roi_id] - slc = Modeler.roi_id_slices[roi_id][0] - roi_refl_ids = Modeler.all_refls_idx[slc] - # NOTE, just a sanity check: - assert len(np.unique(roi_refl_ids))==1, "unique refl ids" - refl_idx = roi_refl_ids[0] - assert test_refl_idx==refl_idx - roi_scale_factor[refl_idx] = scale_fac - Modeler.refls["scale_factor"] = roi_scale_factor - - # get the new refls - new_refl = hopper_utils.get_new_xycalcs(Modeler, new_exp, old_refl_tag="before_geom_ref") - - new_refl_fname, refl_ext = os.path.splitext(Modeler.refl_name) - new_refl_fname = "rank%d_%s_%s%s" % (COMM.rank, os.path.basename(new_refl_fname), params.geometry.optimized_results_tag, refl_ext) - if not new_refl_fname.endswith(".refl"): - new_refl_fname += ".refl" - new_refl_fname = os.path.join(params.geometry.pandas_dir,"refls", new_refl_fname) - new_refl.as_file(new_refl_fname) - shot_pred_offsets = get_dist_from_R(new_refl) - all_shot_pred_offsets += list(shot_pred_offsets) - - new_expt_fname, expt_ext = os.path.splitext(Modeler.exper_name) - new_expt_fname = "rank%d_%s_%s%s" % (COMM.rank, os.path.basename(new_expt_fname), params.geometry.optimized_results_tag, expt_ext) - - if not new_expt_fname.endswith(".expt"): - new_expt_fname += ".expt" - - new_expt_fname = os.path.join(params.geometry.pandas_dir,"expts", new_expt_fname) - new_exp_lst = ExperimentList() - new_exp_lst.append(new_exp) - new_exp_lst.as_file(new_expt_fname) - - if params.geometry.pandas_dir is not None: - a,b,c,al,be,ga = ucpar - ncells_p = [LMP["rank%d_shot%d_Nabc%d" % (COMM.rank, i_shot, i)] for i in range(3)] - ncells_def_p = [LMP["rank%d_shot%d_Ndef%d" % (COMM.rank, i_shot, i)] for i in range(3)] - Na,Nb,Nc = [p.get_val(Xopt[p.xpos]) for p in ncells_p] - Nd,Ne,Nf = [p.get_val(Xopt[p.xpos]) for p in ncells_def_p] - - eta_p = [LMP["rank%d_shot%d_eta%d" % (COMM.rank, i_shot, i)] for i in range(3)] - eta_abc = tuple([p.get_val(Xopt[p.xpos]) for p in eta_p]) - - scale_p = LMP["rank%d_shot%d_Scale" %(COMM.rank, i_shot)] - scale = scale_p.get_val(Xopt[scale_p.xpos]) - - _,fluxes = zip(*SIM.beam.spectrum) - # TODO OUTPUTDEF and LAM0, LAM1 - df= single_expt_pandas(xtal_scale=scale, Amat=new_crystal.get_A(), - ncells_abc=(Na, Nb, Nc), ncells_def=(Nd, Ne, Nf), - eta_abc=eta_abc, - diff_gamma=(np.nan, np.nan, np.nan), - diff_sigma=(np.nan, np.nan, np.nan), - detz_shift=0, - use_diffuse=params.use_diffuse_models, - gamma_miller_units=params.gamma_miller_units, - eta=np.nan, - rotXYZ=tuple(rotXYZ), - ucell_p = (a,b,c,al,be,ga), - ucell_p_init=(np.nan, np.nan, np.nan, np.nan, np.nan, np.nan), - lam0_lam1 = lam0_lam1, - spec_file=Modeler.spec_name, - spec_stride=params.simulator.spectrum.stride, - flux=sum(fluxes), beamsize_mm=SIM.beam.size_mm, - orig_exp_name=Modeler.exper_name, - opt_exp_name=os.path.abspath(new_expt_fname), - spec_from_imageset=params.spectrum_from_imageset, - oversample=SIM.D.oversample, - opt_det=params.opt_det, stg1_refls=Modeler.refl_name, stg1_img_path=None) - pandas_name = os.path.splitext(os.path.basename(new_expt_fname))[0] + ".pkl" - pandas_name = os.path.join(params.geometry.pandas_dir, pandas_name) - df.to_pickle(pandas_name) - modeler_name = pandas_name.replace(".pkl", ".npy") - np.save(modeler_name, Modeler) - #print("Wrote files %s and %s" % (new_refl_fname, new_expt_fname)) - - all_shot_pred_offsets = COMM.reduce(all_shot_pred_offsets) - if COMM.rank==0: - median_pred_offset = np.median(all_shot_pred_offsets) - else: - median_pred_offset = None - median_pred_offset = COMM.bcast(median_pred_offset) - - return median_pred_offset - - -def save_opt_det(phil_params, x, ref_params, SIM): - opt_det = get_optimized_detector(x, ref_params, SIM) - El = ExperimentList() - E = Experiment() - E.detector = opt_det - El.append(E) - El.as_file(phil_params.geometry.optimized_detector_name) - print("Saved detector model to %s" % phil_params.geometry.optimized_detector_name ) - - -def get_optimized_detector(x, ref_params, SIM): - new_det = Detector() - for pid in range(len(SIM.detector)): - panel = SIM.detector[pid] - panel_dict = panel.to_dict() - group_id = SIM.panel_group_from_id[pid] - if group_id in SIM.panel_groups_refined: - - Oang_p = ref_params["group%d_RotOrth" % group_id] - Fang_p = ref_params["group%d_RotFast" % group_id] - Sang_p = ref_params["group%d_RotSlow" % group_id] - Xdist_p = ref_params["group%d_ShiftX" % group_id] - Ydist_p = ref_params["group%d_ShiftY" % group_id] - Zdist_p = ref_params["group%d_ShiftZ" % group_id] - - Oang = Oang_p.get_val(x[Oang_p.xpos]) - Fang = Fang_p.get_val(x[Fang_p.xpos]) - Sang = Sang_p.get_val(x[Sang_p.xpos]) - Xdist = Xdist_p.get_val(x[Xdist_p.xpos]) - Ydist = Ydist_p.get_val(x[Ydist_p.xpos]) - Zdist = Zdist_p.get_val(x[Zdist_p.xpos]) - - origin_of_rotation = SIM.panel_reference_from_id[pid] - SIM.D.reference_origin = origin_of_rotation - SIM.D.update_dxtbx_geoms(SIM.detector, SIM.beam.nanoBragg_constructor_beam, pid, - Oang, Fang, Sang, Xdist, Ydist, Zdist, - force=False) - fdet = SIM.D.fdet_vector - sdet = SIM.D.sdet_vector - origin = SIM.D.get_origin() - else: - fdet = panel.get_fast_axis() - sdet = panel.get_slow_axis() - origin = panel.get_origin() - panel_dict["fast_axis"] = fdet - panel_dict["slow_axis"] = sdet - panel_dict["origin"] = origin - - new_det.add_panel(Panel.from_dict(panel_dict)) - - return new_det - - -if __name__ == "__main__": - from argparse import ArgumentParser - from libtbx.phil import parse - from simtbx.diffBragg.phil import philz, hopper_phil - - parser = ArgumentParser() - parser.add_argument("--phil", type=str, required=True, help="path to a phil string") - parser.add_argument("--cmdlinePhil", nargs="+", default=None, type=str, help="command line phil params") - progargs = parser.parse_args() +COMM = MPI.COMM_WORLD - phil_scope = parse(philz+hopper_phil) - arg_interp = phil_scope.command_line_argument_interpreter(home_scope="") +phil_scope = parse(philz + hopper_phil) +arg_interp = phil_scope.command_line_argument_interpreter(home_scope="") - phil_file = open(progargs.phil, "r").read() - user_phil = parse(phil_file) - phil_sources = [user_phil] +phil_file = open(progargs.phil, "r").read() +user_phil = parse(phil_file) +phil_sources = [user_phil] - if progargs.cmdlinePhil is not None: - command_line_phils = [arg_interp.process(phil) for phil in progargs.cmdlinePhil] - phil_sources += command_line_phils +if progargs.cmdlinePhil is not None: + command_line_phils = [arg_interp.process(phil) for phil in progargs.cmdlinePhil] + phil_sources += command_line_phils - working_phil, unused = phil_scope.fetch(sources=phil_sources, track_unused_definitions=True) - for loc in unused: - print("WARNING: unused phil:", loc) +working_phil, unused = phil_scope.fetch(sources=phil_sources, track_unused_definitions=True) +for loc in unused: + print("WARNING: unused phil:", loc) +params = working_phil.extract() +device_Id = COMM.rank % params.refiner.num_devices +with DeviceWrapper(device_Id) as _: + from simtbx.diffBragg.refiners.geometry import geom_min + from simtbx.diffBragg.utils import find_diffBragg_instances - params = working_phil.extract() + if COMM.rank > 0: + sys.tracebacklimit = 0 geom_min(params) + for name in find_diffBragg_instances(globals()): del globals()[name] diff --git a/simtbx/command_line/hopper_process.py b/simtbx/command_line/hopper_process.py index f170c89018..fca702457f 100644 --- a/simtbx/command_line/hopper_process.py +++ b/simtbx/command_line/hopper_process.py @@ -2,13 +2,14 @@ import time import sys +# LIBTBX_SET_DISPATCHER_NAME diffBragg.stills_process # LIBTBX_SET_DISPATCHER_NAME diffBragg.hopper_process from dials.command_line.stills_process import Processor from xfel.small_cell.small_cell import small_cell_index_detail from simtbx.diffBragg import hopper_utils from dials.array_family import flex -from simtbx.command_line.hopper import save_to_pandas +from simtbx.diffBragg.hopper_io import save_to_pandas from dxtbx.model import ExperimentList import numpy as np import socket @@ -44,9 +45,6 @@ partial_correct = False .type = bool .help = if True, compute partialities from the prediction models and use them to normalize measurements -save_modelers = False - .type = bool - .help = if True, save the data modelers after running refinement. The file includes model values, errors, and useful information .help = for examining the modeling results, can be loaded using modeler = np.load(fname, allow_pickle=True)[()] refspec = None .type = str @@ -89,6 +87,7 @@ def __init__(self, *args, **kwargs): self.stage1_modeler = None # the data modeler used during stage 1 refinement self.modeler_dir = None # path for writing the data modelers self.known_crystal_models = None # default flag, should be defined in stills_process init + self.SIM = None # place holder for simtbx/nanoBragg/sim_data.SimData instance if self.params.silence_dials_loggers: #dials.algorithms.indexing.indexer: model @@ -124,11 +123,12 @@ def index(self, experiments, reflections): def _create_modeler_dir(self): """makes the directory where data modelers, logs, and spectra files will be written""" - self.modeler_dir = os.path.join(self.params.output.output_dir, "modelers") - if COMM.rank == 0: - if not os.path.exists(self.modeler_dir): - os.makedirs(self.modeler_dir) - COMM.barrier() + if self.params.diffBragg.debug_mode: + self.modeler_dir = os.path.join(self.params.output.output_dir, "modelers") + if COMM.rank == 0: + if not os.path.exists(self.modeler_dir): + os.makedirs(self.modeler_dir) + COMM.barrier() @property def device_id(self): @@ -187,7 +187,7 @@ def refine(self, exps, ref, refining_predictions=False, best=None): if self.params.reidx_obs: exps, ref = self._reindex_obs(exps, self.observed) - exp, ref, self.stage1_modeler, x = hopper_utils.refine(exps[0], ref, + exp, ref, self.stage1_modeler, self.SIM, x = hopper_utils.refine(exps[0], ref, self.params.diffBragg, spec=self.params.refspec, gpu_device=self.device_id, return_modeler=True, best=best) @@ -195,8 +195,12 @@ def refine(self, exps, ref, refining_predictions=False, best=None): refls_name = os.path.abspath(self.params.output.indexed_filename) self.params.diffBragg.outdir = self.params.output.output_dir # TODO: what about composite mode ? - self.stage1_df = save_to_pandas(x, self.stage1_modeler.SIM, orig_exp_name, self.params.diffBragg, - self.stage1_modeler.E, 0, refls_name, None) + + #def save_to_pandas(x, Mod, SIM, orig_exp_name, params, expt, rank_exp_idx, stg1_refls, stg1_img_path=None, + # rank=0, write_expt=True, write_pandas=True, exp_idx=0): + self.stage1_df = save_to_pandas(x, self.stage1_modeler, self.SIM, orig_exp_name, self.params.diffBragg, + self.stage1_modeler.E, rank_exp_idx=0, stg1_refls=refls_name, stg1_img_path=None, rank=COMM.rank, + write_expt=False, write_pandas=True, exp_idx=0) exps_out = ExperimentList() exps_out.append(exp) @@ -228,14 +232,16 @@ def _reindex_obs(self, exps, ref): return exps, ref def _save_modeler_info(self, basename): - APATH = lambda x: os.path.abspath(os.path.join(self.modeler_dir, x)) - if self.params.save_modelers: - modeler_fname = APATH("%s_%s" % (basename, "modeler.npy")) + if self.params.diffBragg.debug_mode: + modeler_fname = "%s_%s" % (basename, "modeler.npy") + modeler_fname = os.path.abspath(os.path.join(self.modeler_dir, modeler_fname)) np.save(modeler_fname, self.stage1_modeler) # pickle the modeler, set __setstate__ - spectra_fname = APATH("%s_%s" % (basename, "spectrum.lam")) - SIM_state_fname = APATH("%s_%s" % (basename, "SimState.txt")) - hopper_utils.write_SIM_logs(self.stage1_modeler.SIM, log=SIM_state_fname, lam=spectra_fname) + spectra_fname = "%s_%s" % (basename, "spectra.npy") + spectra_fname = os.path.abspath(os.path.join(self.modeler_dir, spectra_fname)) + SIM_state_fname = "%s_%s" % (basename, "SIM_state.npy") + SIM_state_fname = os.path.abspath(os.path.join(self.modeler_dir, SIM_state_fname)) + hopper_utils.write_SIM_logs(self.SIM, log=SIM_state_fname, lam=spectra_fname) def integrate(self, experiments, indexed): if self.params.skip_hopper: @@ -256,7 +262,7 @@ def integrate(self, experiments, indexed): ) if self.params.dispatch.coset: - from xfel.util.sublattice_helper import integrate_coset + from dials.algorithms.integration.sublattice_helper import integrate_coset integrate_coset(self, experiments, indexed) @@ -305,14 +311,14 @@ def integrate(self, experiments, indexed): predicted, model = predictions.get_predicted_from_pandas( self.stage1_df, self.params.diffBragg, self.observed, experiments[0].identifier, self.device_id, - spectrum_override=self.stage1_modeler.SIM.beam.spectrum) + spectrum_override=self.SIM.beam.spectrum) if self.params.refine_predictions: experiments, rnd2_refls = self.refine(experiments, predicted, refining_predictions=True, best=self.stage1_df) # TODO: match rnd2_refls with indexed.refl and re-save indexed.refl predicted, model = predictions.get_predicted_from_pandas( self.stage1_df, self.params.diffBragg, self.observed, experiments[0].identifier, self.device_id, - spectrum_override=self.stage1_modeler.SIM.beam.spectrum) + spectrum_override=self.SIM.beam.spectrum) predicted.match_with_reference(indexed) integrator = create_integrator(self.params, experiments, predicted) @@ -450,7 +456,15 @@ def run(args=None): stills_process.Processor = Hopper_Processor stills_process.phil_scope = phil_scope script = stills_process.Script() - script.run(args) + from simtbx.diffBragg.device import DeviceWrapper + params, options, all_paths = script.parser.parse_args( + args, show_diff_phil=True, return_unhandled=True, quick_parse=True + ) + if params.output.composite_output: + raise NotImplementedError("diffBragg.stills_process currently does not support composite_output mode") + dev = COMM.rank % params.diffBragg.refiner.num_devices + with DeviceWrapper(dev) as _: + script.run(args) return script diff --git a/simtbx/diffBragg/README.md b/simtbx/diffBragg/README.md index a63a22204e..491f2ac1dd 100644 --- a/simtbx/diffBragg/README.md +++ b/simtbx/diffBragg/README.md @@ -3,9 +3,8 @@ * [Acquiring test data](#testdata) * [Simulating test data](#simulating) * [Creating structure factor input](#sf) -* [Per-image refinement of crystal models with `diffBragg.hopper_process`](#hopper_process) +* [Per-image refinement of crystal models with `diffBragg.stills_process`](#hopper_process) * [X-ray energy spectra](#spectra) - * [Monochromatic model refinement](#mono) * [Polychromatic model refinement](#poly) * [Multi-image refinement of detector models with `diffBragg.geometry_refine`](#geometry) * [API FAQ](#apifaq) @@ -13,7 +12,7 @@ # setup test data -These instructions assume you have a working CCTBX environment, and that the command `libtbx.python` is in your path. Also, this tutorial will assume you are using NERSC (instructions for private linux clusters will be provided in due time). +These instructions assume you have a working CCTBX environment, and that the command `libtbx.python` is in your path. Also, this tutorial will assume you are using an MPI environment with `mpirun` or `slurm` installed. Start by navigating to your CCTBX build's modules folder on your computer. If you are unsure where this is, try issuing the following command @@ -48,11 +47,11 @@ The first step in simulating data using `cxid9114` is to create a background ima libtbx.python $MOD/cxid9114/sim/d9114_mpi_sims.py -odir . --bg-name mybackground.h5 --make-background --sad ``` -To view the background image, install the proper image format provided in the repository. +To view the background image, install the proper image format reader provided in the repository. ``` dxtbx.install_format -u $MOD/cxid9114/format/FormatD9114.py -dials.image_viewer mybackground.h5 +dials.image_viewer mybackground.h5 brightness=75 ``` should produce the image: @@ -65,13 +64,13 @@ Now, we can simulate the diffraction using this image as background. The command ``` -srun -n8 -c2 libtbx.python $MOD/cxid9114/sim/d9114_mpi_sims.py -o test -odir poly_images --add-bg --add-noise --profile gauss --bg-name mybackground.h5 -trials 13 --oversample 0 --Ncells 10 --xtal_size_mm 0.00015 --mos_doms 1 --mos_spread_deg 0.01 --saveh5 --readout --masterscale 1150 --sad --bs7real --masterscalejitter 115 --overwrite --gpu -g 8 +srun -c2 libtbx.python $MOD/cxid9114/sim/d9114_mpi_sims.py -o test -odir poly_images --add-bg --add-noise --profile gauss --bg-name mybackground.h5 -trials 13 --oversample 0 --Ncells 10 --xtal_size_mm 0.00015 --mos_doms 1 --mos_spread_deg 0.01 --saveh5 --readout --masterscale 1150 --sad --bs7real --masterscalejitter 115 --overwrite --gpu -g 4 ``` -the above command will simulate 13 diffraction patterns per rank from randomly oriented crystals. If you are not on NERSC, then drop the `srun -n8 -c2` prefix , and if you do not have GPU support, drop the `--gpu -g8` flags at the end of the command, and instead add the flag `--force-mono` in order to only simulate a single wavelength per pattern. The images can also be opened with the image viewer: +the above command will simulate 13 diffraction patterns per rank from randomly oriented crystals. If you are not on NERSC, then drop the `srun -c2` prefix or use `mpirun` , and if you do not have GPU support, drop the `--gpu -g4` flags at the end of the command, and instead add the flag `--force-mono` in order to only simulate a single wavelength per pattern. The images can also be opened with the image viewer: ``` -dials.image_viewer poly_images/job0/test_rank0_data0_fluence0.h5 +dials.image_viewer poly_images/job0/test_rank0_data0_fluence0.h5 brightness=75 ```

@@ -79,7 +78,7 @@ dials.image_viewer poly_images/job0/test_rank0_data0_fluence0.h5

-Now that we have patterns, we can process them using the diffBragg wrapper script `diffBragg.hopper_process`. +Now that we have patterns, we can process them using `diffBragg.stills_process`. ## Structure factors @@ -94,12 +93,12 @@ cd $MOD/cxid9114 iotbx.reflection_file_converter --unit_cell="79.09619904, 79.09619904, 38.41749954, 90, 90, 90" --space_group=P43212 --mtz=iobs_all.mtz --mtz_root_label=I iobs_all.hkl=intensities ``` -and then note the location so it can be included in your processing configuration files below, described below. +and then note the location so it can be included in your processing configuration files, described below. -# Using `diffBragg.hopper_process` +# Using `diffBragg.stills_process` -We have simulated 104 images, and now we shall process them using the command line tool `diffBragg.hopper_process`, a child program of `dials.stills_process`. Crucially, we will be disabling outlier rejection and all forms of refinement that are usually done during `dials.stills_process` analysis, in favor of the pixel refinement tools in diffBragg, which are wrapped in `diffBragg.hopper_process`. +We have simulated 104 images, and now we shall process them using the command line tool `diffBragg.stills_process`, a version of `dials.stills_process` which optionally uses `diffBragg` refinement. Crucially, we will be disabling outlier rejection and all forms of refinement that are usually done during `dials.stills_process` analysis, in favor of the pixel refinement tools in diffBragg, which are wrapped in `diffBragg.stills_process`. ## X-ray spectra @@ -108,7 +107,7 @@ If X-ray spectra are available for your data, then they should be encoded in the ```python import h5py h = h5py.File("poly_images/job0/test_rank0_data0_fluence0.h5", "r") -a,b = h['wavelengths'][()], h['spectrum'][()]. # `spectrum` was a poor choice of name here, these are just the spectrum weights +a,b = h['wavelengths'][()], h['spectrum'][()] # `spectrum` was a poor choice of name here, these are just the spectrum weights h.close() import pylab as plt @@ -131,16 +130,14 @@ plt.show() The spectra are encoded in the format class `FormatD9114.py` which was installed above using `dxtbx`. - -## Monochromatic `hopper_process` + +## Running `diffBragg.stills_process` -Let's assume that we do not have spectra - we can still run `hopper_process` using the wavelength associated with each image (e.g. a weighted mean). To do that, execute the following command +Run `diffBragg.stills_process` in the same way you would run `dials.stills_process`. If you have a kokkos or a cuda build, and are working on a machine with configured GPU devices, add the flags `DIFFBRAGG_USE_CUDA=1` or `DIFFBRAGG_USE_KOKKOS=1` (NOTE: these flags can be set to anything, you could equally set `DIFFBRAGG_USE_CUDA=0`, so long as they are present in the environment, the corresponding kernels will be triggered!). And if using an MPI environment with `mpi4py` installed, use the correct wrapper (mpirun for openmpi, srun for SLURM). For example, on a Perlmutter allocation (NERSC), the following would work (where each compute node has 4 GPUs , hence the `num_devices=4`. Before running, download the processing config file ``` -DIFFBRAGG_USE_CUDA=1 srun -n 8 -c2 diffBragg.hopper_process process.phil "poly_images/job*/*.h5" mp.method=mpi mp.nproc=8 num_devices=8 dispatch.integrate=True spectrum_from_imageset=False output.output_dir=poly_images/procMono -``` - -The configuration file `process.phil` contains +wget https://smb.slac.stanford.edu/~dermen/diffBragg/process.phil +```
Example process.phil @@ -170,14 +167,15 @@ indexing { integration.summation.detector_gain=28 input.sync_reference_geom = False output.composite_output = False +dispatch.hit_finder.enable=False # hopper process config: -save_modelers=True silence_dials_loggers=True partial_correct=False -reidx_obs=False +reidx_obs=False diffBragg { + debug_mode=True no_Nabc_scale=False method="L-BFGS-B" use_restraints=False @@ -232,12 +230,22 @@ diffBragg { ```
-however command line parameters supersede whats in the PHIL file. Notice the command line argument `spectrum_from_imageset=False`. This tells `diffBrag.hopper_process` to use a single nominal wavelength, and ignore any X-ray spectra that might be present in the data. By setting this flag, a monochromatic diffraction model is refined for each shot. The command takes 71 seconds to run on a single NERSC compute node utilizing 8 GPUs and 8 processors (1 GPU per process), and optimizing models for 104 shots. We have prepared a simple script called `quick_detresid.py` for analyzing the results +and run the command, noting that command line parameters supersede whats in the PHIL file: +``` +DIFFBRAGG_USE_CUDA=1 srun -c2 diffBragg.stills_process process.phil "poly_images/job*/*.h5" mp.method=mpi num_devices=4 dispatch.integrate=True output.output_dir=poly_images/procPoly +``` + +We have prepared a simple script called `quick_detresid.py` for analyzing the results. Grab the script using + +``` +wget https://smb.slac.stanford.edu/~dermen/diffBragg/quick_detresid.py +```
quick_detresid.py - + + ```python """quick_detresid.py""" import glob @@ -335,29 +343,6 @@ os.system("cctbx.xfel.detector_residuals %s/comb.* _detresid.phil" % dirname) It simply combines the relevant outputs and wraps the command line program `cctbx.xfel.detector_residuals`. We are interested at this point to see how well the refined model predicts the strong spot observations. Issue the command ``` -libtbx.python quick_detresid.py poly_images/procMono -``` - -and you will see an image display, as well as some numbers print to the screen indicating how well the monochromatic model predicts the data: - -``` -RMSD (microns) 94.76634677545071 -Overall radial RMSD (microns) 65.9469202178172 -Overall transverse RMSD (microns) 68.05633104237863 -``` - -

- -

- -The image is referred to as the detector residuals, where each point represents an observed reflection, and the color represents the distance to its corresponding predicted reflection according to the optimized model. Not bad for a CSPAD with 110 micron pixels. - - -## Polychromatic `hopper_process` -Can a polychromatic model predict spots more accurately? To use the spectra associated with each image, drop the flag ```spectrum_from_imageset=False``` from the command line (it's set to `True` in ```process.phil```): - -``` -DIFFBRAGG_USE_CUDA=1 srun -n 8 -c2 diffBragg.hopper_process process.phil "poly_images/job*/*.h5" mp.method=mpi mp.nproc=8 num_devices=8 dispatch.integrate=True output.output_dir=poly_images/procPoly libtbx.python quick_detresid.py poly_images/procPoly #RMSD (microns) 61.79812988365175 @@ -365,15 +350,17 @@ libtbx.python quick_detresid.py poly_images/procPoly #Overall transverse RMSD (microns) 40.285340970907185 ``` +and you will see an image display, as well as some numbers print to the screen indicating how well the model predicts the data: +

-These new numbers indicate a more accurate model, owing to the fact that we used a polychromatic energy spread. In fact these numbers represent the best we can do when we know our detector geometry perfectly. This time, the command took 200 seconds to process, as more photon energies were simulated per shot. +The image is referred to as the detector residuals, where each point represents an observed reflection, and the color represents the distance to its corresponding predicted reflection according to the optimized model. Not bad for a CSPAD with 110 micron pixels. ## Output files -In addition to the files provided by `stills_process`, `hopper_process` creates some output data. +In addition to the files provided by `dials.stills_process`, `diffBragg.stills_process` creates a pandas dataframe, stored in a python pickle format. The files can be read using the method `pandas.read_pickle` and contain relevant simulation parameters. ### pandas dataframes @@ -387,7 +374,7 @@ df = pandas.concat([pandas.read_pickle(f) for f in fnames]) df.to_pickle("poly_images/procBad/hopper_process_summary.pkl") # for example ``` -You can examine the spread of parameters to provide key insights into e.g restraints settings for reprocessing (`hopper_process` has a restraints framework explained [TODO: HERE]). Here is an example script which reports on some of the main model parameters: +You can examine the spread of parameters to provide key insights into e.g restraints settings for reprocessing (`diffBragg.stills_process` has a restraints framework explained [TODO: HERE]). Here is an example script which reports on some of the main model parameters: ```python import pandas @@ -447,24 +434,40 @@ The previous script produces histograms of the unit cell parameters, as well as For a full description of the pandas output file see [TODO]. ### modelers folder -For every shot, up to 3 files are written to the modelers folder. These are +For every shot, if the PHIL parameter `diffBragg.debug_mode` is `True`, 3 more files are written to the modelers folder. These are * The simulator state file (`*SimState.txt`), showing the values of almost every diffBragg attribute. This is useful for reproducing the results * The `*.lam` file, which is a 2-column text file containing the spectrum that was used by the refiner. It can be loaded using `diffBragg/utils.py:load_spectra_file` -* if the flag `save_modelers=True` was passed, then a data modeler file will be written containing the pixel data that was used during refinement (final model values, data, mask, background, etc). These files can be loaded using `mod=np.load("modeler.npy", allow_pickle=True)[()]`. The phil parameters are also stored in this pickle as well, for reference. See the class `DataModeler` defined in `diffBragg/hopper_utils.py` for more details. +* A data modeler file containing the pixel data that was used during refinement (final model values, data, mask, background, etc). These files can be loaded using + +``` +from simtbx.diffBragg import hopper_utils # necessary import +mod=np.load("modeler.npy", allow_pickle=True)[()]`. +``` +The phil parameters are also stored in this pickle as well, for reference. See the class `DataModeler` defined in `diffBragg/hopper_utils.py` for more details. # Correcting a faulty geometry with `diffBragg.geometry_refiner` ->:warning: Geometry refinement is currently using the `lmfit` module.
Install it using pip: +>:known issue: If running the kokkos kernel (by setting `DIFFBRAGG_USE_KOKKOS=1` in a kokkos build) , geometry refinement will print out an error message upon termination... It can safely be disregarded!
: ``` -libtbx.python -m pip install lmfit +terminate called after throwing an instance of 'std::runtime_error' + what(): Kokkos allocation "m_Fhkl_scale_deriv" is being deallocated after Kokkos::finalize was called ``` ## Getting the faulty geometry -We have prepared a faulty experimental geometry with which to process the data, derived from real experimental errors associated with the CSPAD geometry. We can use diffBragg to optimize the geometry using polychromatic pixel refinement, therefore extending geometry refinement to more complex scenarios (e.g. Laue or two-color diffraction). One must extract the faulty geometry from a raw form and write it to disk, using the following simple script: +We have prepared a faulty experimental geometry with which to process the data, derived from real experimental errors associated with the CSPAD geometry. We can use diffBragg to optimize the geometry using polychromatic pixel refinement, therefore extending geometry refinement to more complex scenarios (e.g. Laue or two-color diffraction). Get the faulty geometry here: + +``` +wget https://smb.slac.stanford.edu/~dermen/diffBragg/badGeo.expt +``` + +or, alternatively, grab it from the `cxid9114` respository: + +
+ get badGeo.expt from cxid9114 ```python from cxid9114.geom.multi_panel import CSPAD2 @@ -475,14 +478,14 @@ E.detector = CSPAD2 El.append(E) El.as_json("badGeo.expt") ``` +
### Processing with a faulty geometry Now, we can process the simulated images using the faulty geometry and observe the effect it has on the prediction offsets (they should get worse!). Issue the command ``` -DIFFBRAGG_USE_CUDA=1 srun -n 8 -c2 -diffBragg.hopper_process process.phil "poly_images/job*/*.h5" mp.method=mpi mp.nproc=8 num_devices=8 dispatch.integrate=True output.output_dir=poly_images/procBad reference_geometry=badGeo.expt +DIFFBRAGG_USE_CUDA=1 srun -c2 diffBragg.stills_process process.phil "poly_images/job*/*.h5" mp.method=mpi num_devices=4 dispatch.integrate=True output.output_dir=poly_images/procBad reference_geometry=badGeo.expt ``` The flag `reference_geometry=badGeo.expt` forces the geometry file stored in `badGeo.expt` to override the geometry defined by the image format. In this way, all models we optimize are subject to the errors in the geometry. Indeed we find that the prediction errors are much worse when using a faulty geometry @@ -501,10 +504,19 @@ libtbx.python quick_detresid.py poly_images/procBad ## Optimizing the faulty geometry -Whereas `diffBragg.hopper_process` operates on single images, `diffBragg.geometry_refiner` operates on multiple images together that all share the same detector model. +Whereas `diffBragg.stills_process` operates on single images, `diffBragg.geometry_refiner` operates on multiple images together that all share the same detector model. ### panel groups -`diffBragg` does not currently understand the `dxtbx` detector hierarchy models, so it is up to the user to provide a panel group mapping in the form of a 2-column text file (the first column specifies the panel number, and the second column specifies its group number). In order to create a panel group file, one needs to know the panel numbering visually. The detector residuals plots shown above display this information, and there is also the program `dxtbx.plot_detector_models` which takes experiment list files as arguments and plots the detector with its panel numbers displayed. Also, the image viewer displays the panel numbers as you hover over pixels (look for the value readout in the pixel info underbar). The following shows how to create three different panel grouping files for the CSPAD which are understood by `geometry_refiner`: +`diffBragg` does not currently understand the `dxtbx` detector hierarchy models, so it is up to the user to provide a panel group mapping in the form of a 2-column text file (the first column specifies the panel number, and the second column specifies its group number). In order to create a panel group file, one needs to know the panel numbering visually. The detector residuals plots shown above display this information, and there is also the program `dxtbx.plot_detector_models` which takes experiment list files as arguments and plots the detector with its panel numbers displayed., e.g. `dxtbx.plot_detector_models badGeo.expt`. Also, the image viewer displays the panel numbers as you hover over pixels with the mouse pointer (look for the updating value for `readout` in the lower right of the window). Grab the panel group file for this detector here: + +``` +wget https://smb.slac.stanford.edu/~dermen/diffBragg/cspad_32panel.txt +``` + +Alternatively, create the panel group file yourself in Python: + +
+ examples of making panel group files ```python with open("single_panel.txt", "w") as o: @@ -514,25 +526,25 @@ with open("single_panel.txt", "w") as o: with open("cspad_32panel.txt", "w") as o: for pid in range(64): groupid = int(pid/2) - o.write("%d %d\n" % (pid, group_id)) + o.write("%d %d\n" % (pid, groupid)) with open("cspad_quads.txt", "w") as o: for pid in range(64): groupid = int(pid/16) - o.write("%d %d\n" % (pid, group_id)) + o.write("%d %d\n" % (pid, groupid)) ``` +
+ -Here, we will use the 32 panel model. +Here, we will use the 32-panel model (moving all 32 panels separately). ### Running geometry refiner -To run geometry refinement, we must provide a hopper process summary file (see above), as it points to all of the experiments and their optimized models. Issue the command +To run geometry refinement, we must provide as input the saved models from `diffBragg.stills_process`, which are stored in the pandas pickles. For multiple image refinement, proviuded a concatenated version of the pandas pickles. If the program `diffBragg.stills_process` ran to completion, this will be written to the output folder (`hopper_process_summery.pkl`). With that, to run geometry refinement, grad the config file ``` -DIFFBRAGG_USE_CUDA=1 srun -n8 -c2 diffBragg.geometry_refiner --phil geom.phil --cmdlinePhil optimized_detector_name=optGeo.expt input_pkl=poly_images/procBad/hopper_process_summary.pkl lbfgs_maxiter=2000 num_devices=8 geometry.first_n=80 +wget https://smb.slac.stanford.edu/~dermen/diffBragg/geom.phil ``` -The configuration file contains: -
geom.phil @@ -607,15 +619,23 @@ geometry { ```
+and issue the command + +``` +DIFFBRAGG_USE_CUDA=1 srun -c2 diffBragg.geometry_refiner --phil geom.phil --cmdlinePhil optimized_detector_name=optGeo.expt input_pkl=poly_images/procBad/hopper_process_summary.pkl lbfgs_maxiter=2000 num_devices=4 max_process=20 outdir=geom +``` + +The `optimized_detector_name` specifies the name of the geometry file that will be created, `lbfgs_maxiter` specifies the maximum number of L-BFGS iterations, `max_process` specifies the total number of images to read from the `input_pkl`, and the `outdir` is where results will be stored (the folder will be created if it doesn't already exist). + ### optional restraints Geometry refinement supports restraints on the misorientation matrices, as well as the panel geometries. Panel geometry corrections come in the form of (x,y,z) perturbations (about the panel group's 3 lab-frame coordinates) and rotational perturbations (about the panel group's orthogonal axis, fast-scan axis, and slow-scan axis). By default, all of these perturbations are initialized to 0, and the restraint target for each perturbation is also set to 0. The configuration parameter beta specifies the variance of the parameter that's expected during refinement. In practice you will need to experiment with these values in order to achieve optimal results. Looking at distriubtions of unrestrained parameters (as shown [here](#pandas)) can help you estimate beta. ### Reprocess data with refined geometry -Now, we can re-run `hopper_process` using this optimized geometry by adding the flag `reference_geometry=optGeo.expt`: +Now, we can re-run `diffBragg.stills_process` using this optimized geometry by adding the flag `reference_geometry=optGeo.expt`: ``` -DIFFBRAGG_USE_CUDA=1 srun -n 8 -c2 diffBragg.hopper_process process.phil "poly_images/job*/*.h5" mp.method=mpi mp.nproc=8 num_devices=8 dispatch.integrate=True output.output_dir=poly_images/procOpt reference_geometry=optGeo.expt +DIFFBRAGG_USE_CUDA=1 srun -c2 diffBragg.stills_process process.phil "poly_images/job*/*.h5" mp.method=mpi num_devices=4 dispatch.integrate=True output.output_dir=poly_images/procOpt reference_geometry=geom/optGeo.expt libtbx.python quick_detresid.py poly_images/procOpt #RMSD (microns) 66.94415897822252 @@ -627,9 +647,13 @@ libtbx.python quick_detresid.py poly_images/procOpt

-The result shows significant improvement with the optimized geometry, more so than even the monochromatic models that were subjected to zero detector inaccuracy! +The result shows significant improvement with the optimized geometry! -This particular dataset has rather fat spots that are dominated by the mosaic domain size as opposed to the spot spectra, but nonetheless we get better results using polychromatic models. Plotting the average prediction offset as a function of resolution shows this readily. The script +This particular dataset has rather fat spots that are dominated by the mosaic domain size as opposed to the spot spectra, but nonetheless we get better results using polychromatic models. Plotting the average prediction offset as a function of resolution shows this readily. We provide a script for doing this here: + +``` +wget https://smb.slac.stanford.edu/~dermen/diffBragg/pred_offsets.py +```
pred_offsets.py @@ -645,7 +669,7 @@ from joblib import Parallel, delayed from argparse import ArgumentParser parser = ArgumentParser() -parser.add_argument("dirnames", type=str, nargs="+", help="hopper_process output folders") +parser.add_argument("dirnames", type=str, nargs="+", help="diffBragg.stills_process output folders") parser.add_argument("-j", type=int, default=1, help="number of procs") parser.add_argument("-nbins", type=int, default=10, help="number of resolution bins") args = parser.parse_args() @@ -781,7 +805,7 @@ show()
``` -libtbx.python pred_offsets.py poly_images/procMono/ poly_images/procPoly/ poly_images/procBad/ poly_images/procOpt/ +libtbx.python pred_offsets.py poly_images/procPoly/ poly_images/procBad/ poly_images/procOpt/ ```

@@ -798,12 +822,12 @@ libtbx.python pred_offsets.py poly_images/procMono/ poly_images/procPoly/ poly_ -# more on `hopper_process` +# more on `diffBragg.stills_process` -The script runs dials.stills_process with a few alterations +The script runs `dials.stills_process` with a few alterations * diffBragg refinement is performed after indexing, unless `skip_hopper=False` is set. -* `reidx_obs=True` will re-index the strong spot observations after running the normal stills indexing algorithm, *prior* to running refinement. This is useful when obtaining an indexing solution warrants using a high-res cutoff. In such a case, one can detect strong spots out to the corners of the detector, use the indexing_refinement phil param [TODO lookup name] to limit the spots which are fed into indexing, and then re-index the strong spots out to the corners of the camera to grab more spots for diffBragg refinement. +* `reidx_obs=True` will re-index the strong spot observations after running the normal stills indexing algorithm, *prior* to running refinement. This is useful when obtaining an indexing solution warrants using a high-res cutoff. In such a case, one can detect strong spots out to the corners of the detector, use the `indexing_refinement` phil param [TODO lookup name] to limit the spots which are fed into indexing, and then re-index the strong spots out to the corners of the camera to grab more spots for diffBragg refinement. * After refinement, the diffBragg model is used to predict integration positions on the detector, and then the dials integration program is used to compute integrated spot intensities. @@ -840,13 +864,13 @@ To ensure usage of the GPU, set the environment variable `DIFFBRAGG_USE_CUDA=1`. Setting verbose>0 on the diffBragg object itself will show a printout indicating whether GPU executed the kernel, however direct calls to hopper_utils.refine() apparently dont expose this verbose flag. -Calls to `hopper_utils.refine` can optionally return the data modeler object used, and from the modeler, you can inspect whether the GPU kernel was exectued: +Calls to `hopper_utils.refine` can optionally return the simulator object used (`SIM` below), and from that, you can inspect whether the GPU kernel was exectued: ```python # the following line of code is taken from diffBragg/tests/tst_diffBragg_hopper_refined.py -Eopt,_, Mod, x = hopper_utils.refine(E, refls, P, return_modeler=True) +Eopt,_, Mod, SIM, x = hopper_utils.refine(E, refls, P, return_modeler=True) -if Mod.SIM.D.most_recent_kernel_used_GPU: +if SIM.D.most_recent_kernel_used_GPU: print("Kernel ran on GPU") else: print("Kernel ran on CPU") @@ -876,9 +900,9 @@ Check the diffBragg attribute `use_diffuse`: ```python # the following line of code is taken from diffBragg/tests/tst_diffBragg_hopper_refined.py -Eopt,_, Mod, x = hopper_utils.refine(E, refls, P, return_modeler=True) +Eopt,_, Mod, SIM, x = hopper_utils.refine(E, refls, P, return_modeler=True) -if Mod.SIM.D.use_diffuse: +if SIM.D.use_diffuse: print("used diffuse models") else: print("did not use diffuse models") @@ -918,9 +942,9 @@ For mosaic rotations, look for e.g. `refining eta 0` . To verify whether these g ```python # the following line of code is taken from diffBragg/tests/tst_diffBragg_hopper_refined.py -Eopt,_, Mod, x = hopper_utils.refine(E, refls, P, return_modeler=True) +Eopt,_, Mod, SIM, x = hopper_utils.refine(E, refls, P, return_modeler=True) -eta_a = Mod.SIM.P["eta_abc0"] +eta_a = Mod.P["eta_abc0"] init = eta_a.init curr = eta_a.get_val( x[eta_a.xpos]) if not eta_a.refine: @@ -944,8 +968,8 @@ In all cases, to verify the spectrum that was actually used during refinement, c ```python # the following line of code is taken from diffBragg/tests/tst_diffBragg_hopper_refined.py -Eopt,_, Mod, x = hopper_utils.refine(E, refls, P, return_modeler=True) -print(Mod.SIM.beam.spectrum) +Eopt,_, Mod, SIM, x = hopper_utils.refine(E, refls, P, return_modeler=True) +print(SIM.beam.spectrum) [(1.8, 1000000000000.0)] # list of (wavelength, fluence) print("Number of energy channels: %d" % len(Mod.SIM.beam.spectrum)) ``` @@ -972,7 +996,7 @@ This is done through PHIL, e.g. params.simulator.crystal.num_mosaicity_samples = 50 ``` -## Can I verify that the output reflection table has the diffBragg model centroid position as xyzcal? +## Can I verify that the output reflection table has for the `xyzcal` column the diffBragg model centroid positions? -If one calls `hopper_utils.refine`, the returned reflection table will contain an `xyzcal.px` column that includes the diffBragg model dervied centroids. Look for a call to `get_new_xycalcs` in the source code of `hopper_utils.refine` for details. If the refl table passed to `hopper_utils.refine` already contained `xyzcal.px` (e.g. indexed refls), then this column will be renamed to `dials.xyzcal.px`. (same for `xyzcal.mm` and `xyzobs.mm.value`). +If one calls `hopper_utils.refine`, the returned reflection table will contain an `xyzcal.px` column that includes the diffBragg model dervied centroids. Look for a call to `get_new_xycalcs` in the source code of `hopper_utils.refine` for details. If the refl table passed to `hopper_utils.refine` already contains `xyzcal.px` (e.g. indexed refls), then this column will be renamed to `dials.xyzcal.px`. (same for `xyzcal.mm` and `xyzobs.mm.value`). diff --git a/simtbx/diffBragg/refiners/geometry.py b/simtbx/diffBragg/refiners/geometry.py new file mode 100644 index 0000000000..74c4c8c915 --- /dev/null +++ b/simtbx/diffBragg/refiners/geometry.py @@ -0,0 +1,1067 @@ +from __future__ import division, print_function +import time +from copy import deepcopy +import os +import numpy as np +import pandas +import glob +from pylab import plt +from scipy.optimize import basinhopping +import logging +MAIN_LOGGER = logging.getLogger("diffBragg.main") + +from libtbx.mpi4py import MPI +COMM = MPI.COMM_WORLD +from dials.array_family import flex +from dxtbx.model import Experiment, ExperimentList +from dxtbx.model import Detector, Panel +from simtbx.diffBragg.hopper_io import single_expt_pandas +from simtbx.diffBragg import hopper_utils, ensemble_refine_launcher +from simtbx.diffBragg.refiners.parameters import RangedParameter, Parameters +from simtbx.diffBragg import psf + +# diffBragg internal indices for derivative manager +ROTXYZ_ID = 0, 1, 2 +PAN_O_ID = 14 +PAN_F_ID = 17 +PAN_S_ID = 18 +PAN_X_ID = 15 +PAN_Y_ID = 16 +PAN_Z_ID = 10 +PAN_OFS_IDS = PAN_O_ID, PAN_F_ID, PAN_S_ID +PAN_XYZ_IDS = PAN_X_ID, PAN_Y_ID, PAN_Z_ID +DEG_TO_PI = np.pi / 180. + +def convolve_model_with_psf(model_pix, SIM, pan_fast_slow, roi_id_slices, roi_id_unique): + + if not SIM.use_psf: + return model_pix + PSF = SIM.PSF + psf_args = SIM.psf_args + + coords = pan_fast_slow.as_numpy_array() + fid = coords[1::3] + sid = coords[2::3] + + for i in roi_id_unique: + for slc in roi_id_slices[i]: + fvals = fid[slc] + svals = sid[slc] + f0 = fvals.min() + s0 = svals.min() + f1 = fvals.max() + s1 = svals.max() + fdim = int(f1-f0+1) + sdim = int(s1-s0+1) + img = model_pix[slc].reshape((sdim, fdim)) + img = psf.convolve_with_psf(img, psf=PSF, **psf_args) + model_pix[slc] = img.ravel() + + return model_pix + + +def get_dist_from_R(R): + """ returns prediction offset, R is reflection table""" + x, y, _ = R['xyzobs.px.value'].parts() + x2, y2, _ = R['xyzcal.px'].parts() + dist = np.sqrt((x - x2) ** 2 + (y - y2) ** 2) + return dist + + +class BeamParameters: + def __init__(self, phil_params, data_modelers): + self.parameters = [] + # initialize as the median of all lam0, lam1 values + all_lam0 = [] + all_lam1 = [] + for i_m in data_modelers: + m = data_modelers[i_m] + spec0, spec1 = m.PAR.spec_coef + lam0, lam1 = spec0.init, spec1.init + all_lam0.append(lam0) + all_lam1.append(lam1) + all_lam0 = COMM.reduce(all_lam0) + all_lam1 = COMM.reduce(all_lam1) + global_lam0 = global_lam1 = None + if COMM.rank==0: + global_lam0 = np.median(all_lam0) + global_lam1 = np.median(all_lam1) + global_lam0 = COMM.bcast(global_lam0) + global_lam1 = COMM.bcast(global_lam1) + + for i_p, init_val in enumerate((global_lam0, global_lam1)): + cent = phil_params.centers.spec + if cent is not None: + cent = cent[i_p] + beta = phil_params.betas.spec + if beta is not None: + beta = cent[i_p] + p = RangedParameter(name="lambda%d" % i_p, + init=init_val, + sigma=phil_params.sigmas.spec[i_p], + minval=phil_params.mins.spec[i_p], + maxval=phil_params.maxs.spec[i_p], + fix=phil_params.fix.spec, + center=cent, + beta=beta, + is_global=True) + self.parameters.append(p) + + +class DetectorParameters: + + def __init__(self, phil_params, panel_groups_refined, num_panel_groups): + + self.parameters = [] + GEO = phil_params.geometry + for i_group in range(num_panel_groups): + group_has_data = i_group in panel_groups_refined + if not group_has_data: + continue + vary_rots = [not fixed_flag and group_has_data for fixed_flag in GEO.fix.panel_rotations] + #vary_rots = [True]*3 + + o = RangedParameter(name="group%d_RotOrth" % i_group, + init=0, + sigma=100, # TODO + minval=GEO.min.panel_rotations[0]*DEG_TO_PI, + maxval=GEO.max.panel_rotations[0]*DEG_TO_PI, + fix=not vary_rots[0], center=0, beta=GEO.betas.panel_rot[0], is_global=True) + + f = RangedParameter(name="group%d_RotFast" % i_group, + init=0, + sigma=100, # TODO + minval=GEO.min.panel_rotations[1]*DEG_TO_PI, + maxval=GEO.max.panel_rotations[1]*DEG_TO_PI, + fix=not vary_rots[1], center=0, beta=GEO.betas.panel_rot[1], + is_global=True) + + s = RangedParameter(name="group%d_RotSlow" % i_group, + init=0, + sigma=100, # TODO + minval=GEO.min.panel_rotations[2]*DEG_TO_PI, + maxval=GEO.max.panel_rotations[2]*DEG_TO_PI, + fix=not vary_rots[2], center=0, beta=GEO.betas.panel_rot[2], + is_global=True) + + vary_shifts = [not fixed_flag and group_has_data for fixed_flag in GEO.fix.panel_translations] + #vary_shifts = [True]*3 + x = RangedParameter(name="group%d_ShiftX" % i_group, init=0, + sigma=100, + minval=GEO.min.panel_translations[0]*1e-3, maxval=GEO.max.panel_translations[0]*1e-3, + fix=not vary_shifts[0], center=0, beta=GEO.betas.panel_xyz[0], + is_global=True) + y = RangedParameter(name="group%d_ShiftY" % i_group, init=0, + sigma=100, + minval=GEO.min.panel_translations[1]*1e-3, maxval=GEO.max.panel_translations[1]*1e-3, + fix=not vary_shifts[1], center=0, beta=GEO.betas.panel_xyz[1], + is_global=True) + z = RangedParameter(name="group%d_ShiftZ" % i_group, init=0, + sigma=100, + minval=GEO.min.panel_translations[2]*1e-3, maxval=GEO.max.panel_translations[2]*1e-3, + fix=not vary_shifts[2], center=0, beta=GEO.betas.panel_xyz[2], + is_global=True) + + self.parameters += [o, f, s, x, y, z] + + + +class CrystalParameters: + + def __init__(self, phil_params, data_modelers): + self.phil = phil_params + self.parameters = [] + for i_shot in data_modelers: + Mod = data_modelers[i_shot] + + # set the per-spot scale factors, per pixel... + Mod.set_slices("roi_id") + Mod.per_roi_scales_per_pix = np.ones_like(Mod.all_data) + for roi_id, ref_idx in enumerate(Mod.refls_idx): + if "scale_factor" in list(Mod.refls[0].keys()): + slcs = Mod.roi_id_slices[roi_id] + assert len(slcs)==1 + slc = slcs[0] + init_scale = Mod.refls[ref_idx]["scale_factor"] + Mod.per_roi_scales_per_pix[slc] =init_scale + else: + init_scale = 1 + + p = RangedParameter(name="rank%d_shot%d_scale_roi%d" % (COMM.rank, i_shot, roi_id), + minval=0, maxval=1e12, fix=self.phil.fix.perRoiScale, + center=1, beta=1e12, init=init_scale) + self.parameters.append(p) + + for i_N in range(3): + p = Mod.PAR.Nabc[i_N] + ref_p = RangedParameter(name="rank%d_shot%d_Nabc%d" % (COMM.rank, i_shot, i_N), + minval=p.minval, maxval=p.maxval, fix=self.phil.fix.Nabc, init=p.init, + center=p.center, beta=p.beta) + self.parameters.append(ref_p) + + for i_N in range(3): + p = Mod.PAR.Ndef[i_N] + ref_p = RangedParameter(name="rank%d_shot%d_Ndef%d" % (COMM.rank, i_shot, i_N), + minval=p.minval, maxval=p.maxval, fix=self.phil.fix.Ndef, init=p.init, + center=p.center, beta=p.beta) + self.parameters.append(ref_p) + + for i_eta in range(3): + p = Mod.PAR.eta[i_eta] + ref_p = RangedParameter(name="rank%d_shot%d_eta%d" % (COMM.rank, i_shot, i_eta), + minval=p.minval, maxval=p.maxval, fix=self.phil.fix.eta_abc, init=p.init, + center=p.center, beta=p.beta) + self.parameters.append(ref_p) + + for i_rot in range(3): + p = Mod.PAR.RotXYZ_params[i_rot] + ref_p = RangedParameter(name="rank%d_shot%d_RotXYZ%d" % (COMM.rank, i_shot, i_rot), + minval=p.minval, maxval=p.maxval, fix=self.phil.fix.RotXYZ, init=p.init, + center=p.center, beta=p.beta) + self.parameters.append(ref_p) + + p = Mod.PAR.Scale + ref_p = RangedParameter(name="rank%d_shot%d_Scale" % (COMM.rank, i_shot), + minval=p.minval, maxval=p.maxval, fix=self.phil.fix.G, init=p.init, + center=p.center, beta=p.beta) + self.parameters.append(ref_p) + + for i_uc in range(len(Mod.PAR.ucell)): + p = Mod.PAR.ucell[i_uc] + ref_p = RangedParameter(name="rank%d_shot%d_Ucell%d" % (COMM.rank, i_shot, i_uc), + minval=p.minval, maxval=p.maxval, fix=self.phil.fix.ucell, init=p.init, + center=p.center, beta=p.beta) + self.parameters.append(ref_p) + + +class Target: + def __init__(self, ref_params, save_state_freq=500, overwrite_state=True, plot=False): + """ + + :param ref_params: instance of refinement Parameters (LMP in code below) + :param save_state_freq: how often to save all models (will be overwritten each time) + """ + num_params = len(ref_params) + self.vary = np.zeros(num_params).astype(bool) + for p in ref_params.values(): + self.vary[p.xpos] = not p.fix + self.x0 = np.ones(num_params) + self.g = None + self.ref_params = ref_params + self.iternum = 0 + self.all_times = [] + self.save_state_freq = save_state_freq + self.overwrite_state = overwrite_state + self.med_offsets = [] # median prediction offsets(new number gets added everytime write_output_files is called) + self.med_iternums = [] + self.plot = plot and COMM.rank==0 + if self.plot: + self.fig = plt.figure() + self.ax = plt.gca() + plt.draw() + plt.pause(0.1) + + def __call__(self, x, *args, **kwargs): + self.iternum += 1 + t = time.time() + self.x0[self.vary] = x + #time_per_iter = (time.time()-self.tstart) / self.iternum + + f, self.g, self.sigmaZ = target_and_grad(self.x0, self.ref_params, *args, **kwargs) + t = time.time()-t + if COMM.rank==0: + self.all_times.append(t) + time_per_iter = np.mean(self.all_times) + pred_offset_str = ", ".join(map(lambda x: "%.4f" %x, self.med_offsets)) + print("Iteration %d:\n\tResid=%f, sigmaZ %f, t-per-iter=%.4f sec, pred_offsets=%s" + % (self.iternum, f, self.sigmaZ, time_per_iter, pred_offset_str), flush=True) + if self.iternum % self.save_state_freq==0 and self.iternum >0: + if not self.overwrite_state: + params = args[-1] # phil params + temp_pandas_dir = params.outdir + params.outdir=params.outdir + "-iter%d" % self.iternum + med_offset = write_output_files(self.x0, self.ref_params, *args, **kwargs) + self.med_offsets.append(med_offset) + self.med_iternums.append(self.iternum) + if self.plot: + self.ax.clear() + self.ax.plot(self.med_iternums, self.med_offsets) + self.ax.set_ylabel("median |xobs-xcal| (pixels)") + self.ax.set_xlabel("iteration #") + plt.draw() + plt.pause(0.01) + if not self.overwrite_state: + params.outdir=temp_pandas_dir + return f + + def jac(self, x, *args): + if self.g is not None: + return self.g[self.vary] + + def at_min_callback(self, x, f, accept): + if COMM.rank==0: + print("Final Iteration %d:\n\tResid=%f, sigmaZ %f" % (self.iternum, f, self.sigmaZ)) + + +def model(x, ref_params, i_shot, Modeler, SIM, return_bragg_model=False): + """ + + :param x: rescaled parameter array (global) + :param ref_params: simtbx.diffBragg.refiners.parameters.Parameters() instance + :param i_shot: shot index for this data model, + the simtbx.diffBragg.refiners.parameters.RangerParameter objs stored in ref_params + have names which include i_shot + :param Modeler: DataModeler for i_shot + :param SIM: instance of sim_data.SimData + :param return_bragg_model: if true, bypass the latter half of the method and return the Bragg scattering model + :return: either the Bragg scattering model (if return_model), or else a 3-tuple of + (float, dict of float, float) + (negative log likelihood, gradient of negative log likelihood, average sigmaZ for the shot) + """ + + rotX = ref_params["rank%d_shot%d_RotXYZ%d" % (COMM.rank, i_shot, 0)] + rotY = ref_params["rank%d_shot%d_RotXYZ%d" % (COMM.rank, i_shot, 1)] + rotZ = ref_params["rank%d_shot%d_RotXYZ%d" % (COMM.rank, i_shot, 2)] + Na = ref_params["rank%d_shot%d_Nabc%d" % (COMM.rank, i_shot, 0)] + Nb = ref_params["rank%d_shot%d_Nabc%d" % (COMM.rank, i_shot, 1)] + Nc = ref_params["rank%d_shot%d_Nabc%d" % (COMM.rank, i_shot, 2)] + Nd = ref_params["rank%d_shot%d_Ndef%d" % (COMM.rank, i_shot, 0)] + Ne = ref_params["rank%d_shot%d_Ndef%d" % (COMM.rank, i_shot, 1)] + Nf = ref_params["rank%d_shot%d_Ndef%d" % (COMM.rank, i_shot, 2)] + eta_a = ref_params["rank%d_shot%d_eta%d" % (COMM.rank, i_shot, 0)] + eta_b = ref_params["rank%d_shot%d_eta%d" % (COMM.rank, i_shot, 1)] + eta_c = ref_params["rank%d_shot%d_eta%d" % (COMM.rank, i_shot, 2)] + G = ref_params["rank%d_shot%d_Scale" % (COMM.rank, i_shot)] + num_uc_p = len(Modeler.ucell_man.variables) + ucell_pars = [ref_params["rank%d_shot%d_Ucell%d" % (COMM.rank, i_shot, i_uc)] for i_uc in range(num_uc_p)] + lam0 = ref_params["lambda0"] + lam1 = ref_params["lambda1"] + + # update the rotational mosaicity here + # update the mosaicity here + eta_params = [eta_a, eta_b, eta_c] + if SIM.umat_maker is not None: + # we are modeling mosaic spread + eta_abc = [p.get_val(x[p.xpos]) for p in eta_params] + #if not SIM.D.has_anisotropic_mosaic_spread: + # eta_abc = eta_abc[0] + SIM.update_umats_for_refinement(eta_abc) + + # update the photon energy spectrum for this shot + SIM.beam.spectrum = Modeler.spectra + SIM.D.xray_beams = SIM.beam.xray_beams + # update the lambda coeff + lambda_coef = lam0.get_val(x[lam0.xpos]), lam1.get_val(x[lam1.xpos]) + SIM.D.lambda_coefficients = lambda_coef + + # update the Bmatrix + Modeler.ucell_man.variables = [p.get_val(x[p.xpos]) for p in ucell_pars] + Bmatrix = Modeler.ucell_man.B_recipspace + SIM.D.Bmatrix = Bmatrix + for i_ucell in range(len(ucell_pars)): + SIM.D.set_ucell_derivative_matrix( + i_ucell + hopper_utils.UCELL_ID_OFFSET, + Modeler.ucell_man.derivative_matrices[i_ucell]) + eta_a = ref_params["rank%d_shot%d_eta%d" % (COMM.rank, i_shot, 0)] + eta_b = ref_params["rank%d_shot%d_eta%d" % (COMM.rank, i_shot, 1)] + eta_c = ref_params["rank%d_shot%d_eta%d" % (COMM.rank, i_shot, 2)] + G = ref_params["rank%d_shot%d_Scale" % (COMM.rank, i_shot)] + num_uc_p = len(Modeler.ucell_man.variables) + ucell_pars = [ref_params["rank%d_shot%d_Ucell%d" % (COMM.rank, i_shot, i_uc)] for i_uc in range(num_uc_p)] + + # update the rotational mosaicity here + # update the mosaicity here + eta_params = [eta_a, eta_b, eta_c] + if SIM.umat_maker is not None: + # we are modeling mosaic spread + eta_abc = [p.get_val(x[p.xpos]) for p in eta_params] + #if not SIM.D.has_anisotropic_mosaic_spread: + # eta_abc = eta_abc[0] + SIM.update_umats_for_refinement(eta_abc) + + # update the photon energy spectrum for this shot + SIM.beam.spectrum = Modeler.spectra + SIM.D.xray_beams = SIM.beam.xray_beams + + # update the Bmatrix + Modeler.ucell_man.variables = [p.get_val(x[p.xpos]) for p in ucell_pars] + Bmatrix = Modeler.ucell_man.B_recipspace + SIM.D.Bmatrix = Bmatrix + for i_ucell in range(len(ucell_pars)): + SIM.D.set_ucell_derivative_matrix( + i_ucell + hopper_utils.UCELL_ID_OFFSET, + Modeler.ucell_man.derivative_matrices[i_ucell]) + + # update the Umat rotation matrix and the RotXYZ perturbation + SIM.D.Umatrix = Modeler.PAR.Umatrix + SIM.D.set_value(hopper_utils.ROTX_ID, rotX.get_val(x[rotX.xpos])) + SIM.D.set_value(hopper_utils.ROTY_ID, rotY.get_val(x[rotY.xpos])) + SIM.D.set_value(hopper_utils.ROTZ_ID, rotZ.get_val(x[rotZ.xpos])) + + # update the mosaic block size + SIM.D.set_ncells_values((Na.get_val(x[Na.xpos]), + Nb.get_val(x[Nb.xpos]), + Nc.get_val(x[Nc.xpos]))) + SIM.D.Ncells_def = (Nd.get_val(x[Nd.xpos]), + Ne.get_val(x[Ne.xpos]), + Nf.get_val(x[Nf.xpos])) + + npix = int(len(Modeler.pan_fast_slow)/3.) + + # calculate the forward Bragg scattering and gradients + SIM.D.add_diffBragg_spots(Modeler.pan_fast_slow) + + # set the scale factors per ROI + perRoiScaleFactors = {} + for roi_id, ref_idx in enumerate(Modeler.refls_idx): + p = ref_params["rank%d_shot%d_scale_roi%d" % (COMM.rank, i_shot, roi_id )] + slc = Modeler.roi_id_slices[roi_id][0] # Note, there's always just one slice for roi_id + if not p.refine: + break + scale_fac = p.get_val(x[p.xpos]) + Modeler.per_roi_scales_per_pix[slc] = scale_fac + perRoiScaleFactors[roi_id] = (scale_fac, p) + + bragg_no_scale = (SIM.D.raw_pixels_roi[:npix]).as_numpy_array() + + # get the per-shot scale factor + scale = G.get_val(x[G.xpos]) + + #combined the per-shot scale factor with the per-roi scale factors + all_bragg_scales = scale*Modeler.per_roi_scales_per_pix + + # scale the bragg scattering + bragg = all_bragg_scales*bragg_no_scale + if return_bragg_model: + return bragg + + # this is the total forward model: + model_pix = bragg + Modeler.all_background + if SIM.use_psf: + model_pix = convolve_model_with_psf(model_pix, SIM, Modeler.pan_fast_slow, roi_id_slices=Modeler.roi_id_slices, roi_id_unique=Modeler.roi_id_unique) + + + # compute the negative log Likelihood + resid = (Modeler.all_data - model_pix) + resid_square = resid ** 2 + V = model_pix + Modeler.nominal_sigma_rdout ** 2 + neg_LL = (.5*(np.log(2*np.pi*V) + resid_square / V))[Modeler.all_trusted].sum() + + # compute the z-score sigma as a diagnostic + zscore_sigma = np.std((resid / np.sqrt(V))[Modeler.all_trusted]) + + # store the gradients + J = {} + # this term is a common factor in all of the gradients + common_grad_term = (0.5 / V * (1 - 2 * resid - resid_square / V)) + + if perRoiScaleFactors: + # the gradient in this case is the bragg scattering, scaled by only the total shot scale (G in the literature) + bragg_no_roi = bragg_no_scale*scale + + for roi_id in perRoiScaleFactors: + scale_fac, p = perRoiScaleFactors[roi_id] + slc = Modeler.roi_id_slices[roi_id][0] # theres just one slice for each roi_id + d = p.get_deriv(x[p.xpos], bragg_no_roi[slc]) + + if SIM.use_psf: + x1,x2,y1,y2 = Modeler.rois[roi_id] + sdim, fdim = y2-y1, x2-x1 + d_img = d.reshape((sdim, fdim)) + d_img = psf.convolve_with_psf(d_img, psf=SIM.PSF, **SIM.psf_args) + d = d_img.ravel() + + d_trusted = Modeler.all_trusted[slc] + common_term_slc = common_grad_term[slc] + J[p.name] = (common_term_slc*d)[d_trusted].sum() + + # scale factor gradients + conv_args = {"SIM": SIM, "pan_fast_slow": Modeler.pan_fast_slow, "roi_id_slices": Modeler.roi_id_slices, "roi_id_unique": Modeler.roi_id_unique} + if not G.fix: + bragg_no_roi_scale = bragg_no_scale*Modeler.per_roi_scales_per_pix + scale_grad = G.get_deriv(x[G.xpos], bragg_no_roi_scale) + scale_grad = convolve_model_with_psf(scale_grad, **conv_args) + J[G.name] = (common_grad_term*scale_grad)[Modeler.all_trusted].sum() + + # Umat gradients + for i_rot, rot in enumerate([rotX, rotY, rotZ]): + if not rot.fix: + rot_db_id = ROTXYZ_ID[i_rot] + rot_grad = scale*SIM.D.get_derivative_pixels(rot_db_id).as_numpy_array()[:npix] + rot_grad = rot.get_deriv(x[rot.xpos], rot_grad) + rot_grad = convolve_model_with_psf(rot_grad, **conv_args) + J[rot.name] = (common_grad_term*rot_grad)[Modeler.all_trusted].sum() + + # mosaic block size gradients + if not Na.fix: + Nabc_grad = SIM.D.get_ncells_derivative_pixels() + for i_N, N in enumerate([Na, Nb, Nc]): + N_grad = scale*(Nabc_grad[i_N][:npix].as_numpy_array()) + N_grad = N.get_deriv(x[N.xpos], N_grad) + N_grad = convolve_model_with_psf(N_grad, **conv_args) + J[N.name] = (common_grad_term*N_grad)[Modeler.all_trusted].sum() + + if not Nd.fix: + Ndef_grad = SIM.D.get_ncells_def_derivative_pixels() + for i_N, N in enumerate([Nf, Ne, Nf]): + N_grad = scale*(Ndef_grad[i_N][:npix].as_numpy_array()) + N_grad = N.get_deriv(x[N.xpos], N_grad) + N_grad = convolve_model_with_psf(N_grad, **conv_args) + J[N.name] = (common_grad_term*N_grad)[Modeler.all_trusted].sum() + + if not eta_a.fix: + if SIM.D.has_anisotropic_mosaic_spread: + eta_abc_derivs = SIM.D.get_aniso_eta_deriv_pixels() + else: + eta_abc_derivs = [SIM.D.get_derivative_pixels(hopper_utils.ETA_ID)] + for i_eta, eta in enumerate(eta_params): + eta_grad = scale*(eta_abc_derivs[i_eta][:npix].as_numpy_array()) + eta_grad = eta.get_deriv(x[eta.xpos], eta_grad) + eta_grad = convolve_model_with_psf(eta_grad, **conv_args) + J[eta.name] = (common_grad_term*eta_grad)[Modeler.all_trusted].sum() + if not SIM.D.has_anisotropic_mosaic_spread: + break + + # unit cell gradients + if not ucell_pars[0].fix: + for i_ucell, uc_p in enumerate(ucell_pars): + d = scale*SIM.D.get_derivative_pixels(hopper_utils.UCELL_ID_OFFSET+i_ucell).as_numpy_array()[:npix] + d = uc_p.get_deriv(x[uc_p.xpos], d) + d = convolve_model_with_psf(d, **conv_args) + J[ucell_pars[i_ucell].name] = (common_grad_term*d)[Modeler.all_trusted].sum() + + if not lam0.fix: + lambda_derivs = SIM.D.get_lambda_derivative_pixels() + lam_params = lam0, lam1 + for d, pr in zip(lambda_derivs, lam_params): + d = d.as_numpy_array()[:npix] + d = pr.get_deriv(x[pr.xpos], d) + d = convolve_model_with_psf(d, **conv_args) + J[pr.name] = (common_grad_term*d)[Modeler.all_trusted].sum() + + # detector model gradients + detector_derivs = [] + for diffbragg_parameter_id in PAN_OFS_IDS+PAN_XYZ_IDS: + try: + d = SIM.D.get_derivative_pixels(diffbragg_parameter_id).as_numpy_array()[:npix] + d = convolve_model_with_psf(d, **conv_args) + d = common_grad_term*scale*d + except ValueError: + d = None + detector_derivs.append(d) + names = "RotOrth", "RotFast", "RotSlow", "ShiftX", "ShiftY", "ShiftZ" + for group_id in Modeler.unique_panel_group_ids: + for name in names: + J["group%d_%s" % (group_id, name)] = 0 + for pixel_rng in Modeler.group_id_slices[group_id]: + trusted_pixels = Modeler.all_trusted[pixel_rng] + for i_name, name in enumerate(names): + par_name = "group%d_%s" % (group_id, name) + det_param = ref_params[par_name] + if det_param.fix: + continue + pixderivs = detector_derivs[i_name][pixel_rng][trusted_pixels] + pixderivs = det_param.get_deriv(x[det_param.xpos], pixderivs) + J[par_name] += pixderivs.sum() + + return neg_LL, J, model_pix, zscore_sigma + + +def set_group_id_slices(Modeler, group_id_from_panel_id): + """finds the boundaries for each panel group ID in the 1-D array of per-shot data + Modeler: DataModeler instance with loaded data + group_id_from_panel_id : dict where key is panel id and value is group id + """ + Modeler.all_group_id = [group_id_from_panel_id[pid] for pid in Modeler.all_pid] + splitter = np.where(np.diff(Modeler.all_group_id) != 0)[0]+1 + npix = len(Modeler.all_data) + slices = [slice(V[0], V[-1]+1, 1) for V in np.split(np.arange(npix), splitter)] + group_ids = [V[0] for V in np.split(np.array(Modeler.all_group_id), splitter)] + group_id_slices = {} + for i_group, slc in zip(group_ids, slices): + if i_group not in group_id_slices: + group_id_slices[i_group] = [slc] + else: + group_id_slices[i_group].append(slc) + Modeler.unique_panel_group_ids = set(Modeler.all_group_id) + logging.debug("Modeler has data on %d unique panel groups" % (len(Modeler.unique_panel_group_ids))) + Modeler.group_id_slices = group_id_slices + + +def update_detector(x, ref_params, SIM, save=None): + """ + Update the internal geometry of the diffBragg instance + :param x: refinement parameters as seen by scipy.optimize (e.g. rescaled floats) + :param ref_params: diffBragg.refiners.Parameters (dict of RangedParameters) + :param SIM: SIM instance (instance of nanoBragg.sim_data.SimData) + :param save: optional name to save the detector + """ + det = SIM.detector + if save is not None: + new_det = Detector() + for pid in range(len(det)): + panel = det[pid] + panel_dict = panel.to_dict() + + group_id = SIM.panel_group_from_id[pid] + if group_id not in SIM.panel_groups_refined: + fdet = panel.get_fast_axis() + sdet = panel.get_slow_axis() + origin = panel.get_origin() + else: + + Oang_p = ref_params["group%d_RotOrth" % group_id] + Fang_p = ref_params["group%d_RotFast" % group_id] + Sang_p = ref_params["group%d_RotSlow" % group_id] + Xdist_p = ref_params["group%d_ShiftX" % group_id] + Ydist_p = ref_params["group%d_ShiftY" % group_id] + Zdist_p = ref_params["group%d_ShiftZ" % group_id] + + Oang = Oang_p.get_val(x[Oang_p.xpos]) + Fang = Fang_p.get_val(x[Fang_p.xpos]) + Sang = Sang_p.get_val(x[Sang_p.xpos]) + Xdist = Xdist_p.get_val(x[Xdist_p.xpos]) + Ydist = Ydist_p.get_val(x[Ydist_p.xpos]) + Zdist = Zdist_p.get_val(x[Zdist_p.xpos]) + + origin_of_rotation = SIM.panel_reference_from_id[pid] + SIM.D.reference_origin = origin_of_rotation + SIM.D.update_dxtbx_geoms(det, SIM.beam.nanoBragg_constructor_beam, pid, + Oang, Fang, Sang, Xdist, Ydist, Zdist, + force=False) + fdet = SIM.D.fdet_vector + sdet = SIM.D.sdet_vector + origin = SIM.D.get_origin() + + if save is not None: + panel_dict["fast_axis"] = fdet + panel_dict["slow_axis"] = sdet + panel_dict["origin"] = origin + new_det.add_panel(Panel.from_dict(panel_dict)) + + if save is not None and COMM.rank==0: + t = time.time() + El = ExperimentList() + E = Experiment() + E.detector = new_det + El.append(E) + El.as_file(save) + t = time.time()-t + #print("Saved detector model to %s (took %.4f sec)" % (save, t), flush=True ) + + +def target_and_grad(x, ref_params, data_modelers, SIM, params): + """ + Returns the target functional and the gradients + :param x: float array of parameter values as seen by scipt.optimize (rescaled) + :param ref_params: refinement parameter objects (diffBragg.refiners.parameters.Parameters() ) + :param data_modelers: dict of data modelers (one per experiment) + :param SIM: sim_data instance + :param params: phil parameters + :return: 2-tuple, target and gradients + """ + target_functional = 0 + grad = np.zeros(len(x)) + + save_name = params.geometry.optimized_detector_name + update_detector(x, ref_params, SIM, save_name) + + all_shot_sigZ = [] + for i_shot in data_modelers: + Modeler = data_modelers[i_shot] + + neg_LL, neg_LL_grad, model_pix, per_shot_sigZ = model(x, ref_params, i_shot, Modeler, SIM) + all_shot_sigZ.append(per_shot_sigZ) + + # accumulate the target functional for this rank/shot + target_functional += neg_LL + + if params.use_restraints: + for name in ref_params: + if name.startswith("Fhkl"): + continue + par = ref_params[name] + if not par.is_global and not par.fix and par.beta is not None: + val = par.get_restraint_val(x[par.xpos]) + target_functional += val + + # accumulate the gradients for this rank/shot + for name in ref_params: + if name in neg_LL_grad: + par = ref_params[name] + grad[par.xpos] += neg_LL_grad[name] + # for restraints only update the per-shot restraint gradients here + if params.use_restraints and not par.is_global and not par.fix and par.beta is not None: + grad[par.xpos] += par.get_restraint_deriv(x[par.xpos]) + + # sum the target functional and the gradients across all ranks + target_functional = COMM.bcast(COMM.reduce(target_functional)) + grad = COMM.bcast(COMM.reduce(grad)) + + if params.use_restraints and params.geometry.betas.close_distances is not None: + target_functional += np.std(SIM.D.close_distances) / params.geometry.betas.close_distances + + ## add in the detector parameter restraints + if params.use_restraints: + for name in ref_params: + if name.startswith("Fhkl"): + continue + par = ref_params[name] + if par.is_global and not par.fix and par.beta is not None: + target_functional += par.get_restraint_val(x[par.xpos]) + grad[par.xpos] += par.get_restraint_deriv(x[par.xpos]) + + all_shot_sigZ = COMM.reduce(all_shot_sigZ) + if COMM.rank == 0: + all_shot_sigZ = np.median(all_shot_sigZ) + + return target_functional, grad, all_shot_sigZ + + +def geom_min(params): + """ + :param params: phil parameters (simtbx/diffBragg/phil.py) + """ + + launcher = ensemble_refine_launcher.RefineLauncher(params) + if params.geometry.input_pkl is not None: + df = pandas.read_pickle(params.geometry.input_pkl) + else: + assert params.geometry.input_pkl_glob is not None + fnames = glob.glob(params.geometry.input_pkl_glob) + dfs = [] + for i_f, f in enumerate(fnames): + if i_f % COMM.size != COMM.rank: + continue + if COMM.rank==0: + print("Loaing hopper pkl %d / %d" %(i_f+1, len(fnames)), flush=True) + df_i = pandas.read_pickle(f) + dfs.append(df_i) + dfs = COMM.reduce(dfs) + if COMM.rank==0: + df = pandas.concat(dfs) + else: + df = None + df = COMM.bcast(df) + + if params.skip is not None: + df = df.iloc[params.skip:] + if params.max_process is not None: + df = df.iloc[:params.max_process] + + pdir = params.outdir + assert pdir is not None, "provide a pandas_dir where output files will be generated" + params.geometry.optimized_detector_name = os.path.join(pdir, os.path.basename(params.geometry.optimized_detector_name)) + if COMM.rank==0: + if not os.path.exists(pdir): + os.makedirs(pdir) + if COMM.rank == 0: + print("Will optimize using %d experiments" %len(df)) + + from simtbx.diffBragg import mpi_logger + mpi_logger.setup_logging_from_params(params) + df.reset_index(drop=True, inplace=True) + launcher.load_inputs(df, refls_key=params.geometry.refls_key) + + for i_shot in launcher.Modelers: + Modeler = launcher.Modelers[i_shot] + set_group_id_slices(Modeler, launcher.panel_group_from_id) + + # same on every rank: + det_params = DetectorParameters(params, launcher.panel_groups_refined, launcher.n_panel_groups) + + beam_params = BeamParameters(params, launcher.Modelers) + + # different on each rank + crystal_params = CrystalParameters(params,launcher.Modelers) + crystal_params.parameters = COMM.bcast(COMM.reduce(crystal_params.parameters)) + + LMP = Parameters() + for p in crystal_params.parameters + det_params.parameters + beam_params.parameters: + LMP.add(p) + + # use spectrum coefficients + launcher.SIM.D.use_lambda_coefficients = True + launcher.SIM.D.lambda_coefficients = LMP["lambda0"].init, LMP["lambda1"].init + + # attached some objects to SIM for convenience + launcher.SIM.panel_reference_from_id = launcher.panel_reference_from_id + launcher.SIM.panel_group_from_id = launcher.panel_group_from_id + launcher.SIM.panel_groups_refined = launcher.panel_groups_refined + + # set the GPU device + launcher.SIM.D.device_Id = COMM.rank % params.refiner.num_devices + npx_str = "(rnk%d, dev%d): %d pix" %(COMM.rank, launcher.SIM.D.device_Id, launcher.NPIX_TO_ALLOC) + npx_str = COMM.gather(npx_str) + if COMM.rank==0: + print("How many pixels each rank will allocate for on its device:") + print("; ".join(npx_str)) + launcher.SIM.D.Npix_to_allocate = launcher.NPIX_TO_ALLOC + + # configure diffBragg instance for gradient computation + if not params.fix.RotXYZ: + for i_rot in range(3): + launcher.SIM.D.refine(ROTXYZ_ID[i_rot]) + if not params.fix.spec: + launcher.SIM.D.refine(hopper_utils.LAMBDA_IDS[0]) + launcher.SIM.D.refine(hopper_utils.LAMBDA_IDS[1]) + if not params.fix.eta_abc: + launcher.SIM.D.refine(hopper_utils.ETA_ID) + if not params.fix.Nabc: + launcher.SIM.D.refine(hopper_utils.NCELLS_ID) + if not params.fix.Ndef: + launcher.SIM.D.refine(hopper_utils.NCELLS_ID_OFFDIAG) + if not params.fix.ucell: + for i_ucell in range(launcher.SIM.num_ucell_param): + launcher.SIM.D.refine(hopper_utils.UCELL_ID_OFFSET + i_ucell) + for i, diffbragg_id in enumerate(PAN_OFS_IDS): + if not params.geometry.fix.panel_rotations[i]: + launcher.SIM.D.refine(diffbragg_id) + + for i, diffbragg_id in enumerate(PAN_XYZ_IDS): + if not params.geometry.fix.panel_translations[i]: + launcher.SIM.D.refine(diffbragg_id) + + # do a barrel roll! + target = Target(LMP, save_state_freq=params.geometry.save_state_freq, overwrite_state=params.geometry.save_state_overwrite) + fcn_args = (launcher.Modelers, launcher.SIM, params) + lbfgs_kws = {"jac": target.jac, + "method": "L-BFGS-B", + "args": fcn_args, + "options": {"ftol": params.ftol, "gtol": 1e-10, "maxfun":1e5, "maxiter":params.lbfgs_maxiter}} + + result = basinhopping(target, target.x0[target.vary], + niter=params.niter, + minimizer_kwargs=lbfgs_kws, + T=params.temp, + callback=target.at_min_callback, + disp=False, + stepsize=params.stepsize) + + target.x0[target.vary] = result.x + Xopt = target.x0 # optimized, rescaled parameters + + if params.geometry.optimized_results_tag is not None: + write_output_files(Xopt, LMP, launcher.Modelers, launcher.SIM, params) + + if COMM.rank == 0: + save_opt_det(params, target.x0, target.ref_params, launcher.SIM) + + +def write_output_files(Xopt, LMP, Modelers, SIM, params): + """ + Writes refl and exper files for each experiment modeled during + the ensemble refiner + :param Xopt: float array of optimized rescaled parameter values + :param LMP: simtbx.diffBragg.refiners.parameters.Parameters() object + :param Modelers: data modelers (launcher.Modleers + :param SIM: instance of sim_data (launcher.SIM) + :param params: phil params, simtbx.diffBragg.phil.py + """ + opt_det = get_optimized_detector(Xopt, LMP, SIM) + if COMM.rank==0: + temp = params.geometry.optimized_detector_name + params.geometry.optimized_detector_name = os.path.splitext(temp)[0] + "_current.expt" + save_opt_det(params, Xopt, LMP, SIM) + params.geometry.optimized_detector_name = temp + + if params.outdir is not None and COMM.rank == 0: + if not os.path.exists(params.outdir): + os.makedirs(params.outdir) + if params.debug_mode: + refdir = os.path.join(params.outdir, "refls") + expdir = os.path.join(params.outdir, "expts") + moddir = os.path.join(params.outdir, "modelers") + for dname in [refdir, expdir, moddir]: + if not os.path.exists(dname): + os.makedirs(dname) + + COMM.barrier() + lam0_lam1 = [] + for i_lam in [0,1]: + lam_p = LMP["lambda%d"% i_lam] + val = lam_p.get_val(Xopt[lam_p.xpos]) + lam0_lam1.append(val) + + all_shot_pred_offsets = [] + all_dfs = [] + for i_shot in Modelers: + Modeler = Modelers[i_shot] + # these are in simtbx.diffBragg.refiners.parameters.RangedParameter objects + rotX = LMP["rank%d_shot%d_RotXYZ%d" % (COMM.rank, i_shot, 0)] + rotY = LMP["rank%d_shot%d_RotXYZ%d" % (COMM.rank, i_shot, 1)] + rotZ = LMP["rank%d_shot%d_RotXYZ%d" % (COMM.rank, i_shot, 2)] + num_uc_p = len(Modeler.ucell_man.variables) + ucell_pars = [LMP["rank%d_shot%d_Ucell%d" % (COMM.rank, i_shot, i_uc)] for i_uc in range(num_uc_p)] + + # convert rotation angles back to radians (thats what the parameters.RangedParamter.get_val method does) + rotXYZ = rotX.get_val(Xopt[rotX.xpos]), \ + rotY.get_val(Xopt[rotY.xpos]), \ + rotZ.get_val(Xopt[rotZ.xpos]) + + # ucell_man is an instance of + # simtbx.diffBragg.refiners.crystal_systems.manager.Manager() + # (for the correct xtal system) + Modeler.ucell_man.variables = [p.get_val(Xopt[p.xpos]) for p in ucell_pars] + ucpar = Modeler.ucell_man.unit_cell_parameters + + new_crystal = hopper_utils.new_cryst_from_rotXYZ_and_ucell(rotXYZ, ucpar, Modeler.E.crystal) + new_exp = deepcopy(Modeler.E) + new_exp.crystal = new_crystal + wave, wt = map(np.array, zip(*Modeler.spectra)) + ave_wave = (wave*wt).sum()/wt.sum() + new_exp.beam.set_wavelength(ave_wave) + new_exp.detector = opt_det + + Modeler.best_model = model(Xopt, LMP, i_shot, Modeler, SIM, return_bragg_model=True) + Modeler.best_model_includes_background = False + + # store the updated per-roi scale factors in the new refl table + roi_scale_factor = flex.double(len(Modeler.refls), 1) + for roi_id in Modeler.roi_id_unique: + p = LMP["rank%d_shot%d_scale_roi%d" % (COMM.rank, i_shot, roi_id)] + scale_fac = p.get_val(Xopt[p.xpos]) + test_refl_idx = Modeler.refls_idx[roi_id] + slc = Modeler.roi_id_slices[roi_id][0] + roi_refl_ids = Modeler.all_refls_idx[slc] + # NOTE, just a sanity check: + assert len(np.unique(roi_refl_ids))==1, "unique refl ids" + refl_idx = roi_refl_ids[0] + assert test_refl_idx==refl_idx + roi_scale_factor[refl_idx] = scale_fac + Modeler.refls["scale_factor"] = roi_scale_factor + + # get the new refls + new_refl = hopper_utils.get_new_xycalcs(Modeler, new_exp, old_refl_tag="before_geom_ref") + + new_refl_fname, refl_ext = os.path.splitext(Modeler.refl_name) + new_refl_fname = "rank%d_%s_%s%s" % (COMM.rank, os.path.basename(new_refl_fname), params.geometry.optimized_results_tag, refl_ext) + if not new_refl_fname.endswith(".refl"): + new_refl_fname += ".refl" + new_refl_fname = os.path.join(params.outdir,"refls", new_refl_fname) + if params.debug_mode: + new_refl.as_file(new_refl_fname) + shot_pred_offsets = get_dist_from_R(new_refl) + all_shot_pred_offsets += list(shot_pred_offsets) + + new_expt_fname, expt_ext = os.path.splitext(Modeler.exper_name) + new_expt_fname = "rank%d_%s_%s%s" % (COMM.rank, os.path.basename(new_expt_fname), params.geometry.optimized_results_tag, expt_ext) + + if not new_expt_fname.endswith(".expt"): + new_expt_fname += ".expt" + + new_expt_fname = os.path.join(params.outdir,"expts", new_expt_fname) + new_exp_lst = ExperimentList() + new_exp_lst.append(new_exp) + if params.debug_mode: + new_exp_lst.as_file(new_expt_fname) + + if params.outdir is not None: + a,b,c,al,be,ga = ucpar + ncells_p = [LMP["rank%d_shot%d_Nabc%d" % (COMM.rank, i_shot, i)] for i in range(3)] + ncells_def_p = [LMP["rank%d_shot%d_Ndef%d" % (COMM.rank, i_shot, i)] for i in range(3)] + Na,Nb,Nc = [p.get_val(Xopt[p.xpos]) for p in ncells_p] + Nd,Ne,Nf = [p.get_val(Xopt[p.xpos]) for p in ncells_def_p] + + eta_p = [LMP["rank%d_shot%d_eta%d" % (COMM.rank, i_shot, i)] for i in range(3)] + eta_abc = tuple([p.get_val(Xopt[p.xpos]) for p in eta_p]) + + scale_p = LMP["rank%d_shot%d_Scale" %(COMM.rank, i_shot)] + scale = scale_p.get_val(Xopt[scale_p.xpos]) + + _,fluxes = zip(*SIM.beam.spectrum) + # TODO OUTPUTDEF and LAM0, LAM1 + df= single_expt_pandas(xtal_scale=scale, Amat=new_crystal.get_A(), + ncells_abc=(Na, Nb, Nc), ncells_def=(Nd, Ne, Nf), + eta_abc=eta_abc, + diff_gamma=(np.nan, np.nan, np.nan), + diff_sigma=(np.nan, np.nan, np.nan), + detz_shift=0, + use_diffuse=params.use_diffuse_models, + gamma_miller_units=params.gamma_miller_units, + eta=np.nan, + rotXYZ=tuple(rotXYZ), + ucell_p = (a,b,c,al,be,ga), + ucell_p_init=(np.nan, np.nan, np.nan, np.nan, np.nan, np.nan), + lam0_lam1 = lam0_lam1, + spec_file=Modeler.spec_name, + spec_stride=params.simulator.spectrum.stride, + flux=sum(fluxes), beamsize_mm=SIM.beam.size_mm, + orig_exp_name=Modeler.exper_name, + opt_exp_name=os.path.abspath(new_expt_fname), + spec_from_imageset=params.spectrum_from_imageset, + oversample=SIM.D.oversample, + opt_det=params.opt_det, stg1_refls=Modeler.refl_name, stg1_img_path=None) + all_dfs.append(df) + + # optionally save the modeler file + if params.debug_mode: + mod_name = os.path.splitext(os.path.basename(new_expt_fname))[0] + ".npy" + mod_name = os.path.join(params.outdir, "modelers", mod_name) + np.save(mod_name, Modeler) + + rank_df = pandas.concat(all_dfs) + pandas_name = os.path.join(params.outdir, "models_rank%d.pkl" % COMM.rank) + rank_df.to_pickle(pandas_name) + + all_shot_pred_offsets = COMM.reduce(all_shot_pred_offsets) + if COMM.rank==0: + median_pred_offset = np.median(all_shot_pred_offsets) + else: + median_pred_offset = None + median_pred_offset = COMM.bcast(median_pred_offset) + + return median_pred_offset + + +def save_opt_det(phil_params, x, ref_params, SIM): + opt_det = get_optimized_detector(x, ref_params, SIM) + El = ExperimentList() + E = Experiment() + E.detector = opt_det + El.append(E) + El.as_file(phil_params.geometry.optimized_detector_name) + print("Saved detector model to %s" % phil_params.geometry.optimized_detector_name ) + + +def get_optimized_detector(x, ref_params, SIM): + new_det = Detector() + for pid in range(len(SIM.detector)): + panel = SIM.detector[pid] + panel_dict = panel.to_dict() + group_id = SIM.panel_group_from_id[pid] + if group_id in SIM.panel_groups_refined: + + Oang_p = ref_params["group%d_RotOrth" % group_id] + Fang_p = ref_params["group%d_RotFast" % group_id] + Sang_p = ref_params["group%d_RotSlow" % group_id] + Xdist_p = ref_params["group%d_ShiftX" % group_id] + Ydist_p = ref_params["group%d_ShiftY" % group_id] + Zdist_p = ref_params["group%d_ShiftZ" % group_id] + + Oang = Oang_p.get_val(x[Oang_p.xpos]) + Fang = Fang_p.get_val(x[Fang_p.xpos]) + Sang = Sang_p.get_val(x[Sang_p.xpos]) + Xdist = Xdist_p.get_val(x[Xdist_p.xpos]) + Ydist = Ydist_p.get_val(x[Ydist_p.xpos]) + Zdist = Zdist_p.get_val(x[Zdist_p.xpos]) + + origin_of_rotation = SIM.panel_reference_from_id[pid] + SIM.D.reference_origin = origin_of_rotation + SIM.D.update_dxtbx_geoms(SIM.detector, SIM.beam.nanoBragg_constructor_beam, pid, + Oang, Fang, Sang, Xdist, Ydist, Zdist, + force=False) + fdet = SIM.D.fdet_vector + sdet = SIM.D.sdet_vector + origin = SIM.D.get_origin() + else: + fdet = panel.get_fast_axis() + sdet = panel.get_slow_axis() + origin = panel.get_origin() + panel_dict["fast_axis"] = fdet + panel_dict["slow_axis"] = sdet + panel_dict["origin"] = origin + + new_det.add_panel(Panel.from_dict(panel_dict)) + + return new_det diff --git a/simtbx/modeling/forward_models.py b/simtbx/modeling/forward_models.py index 16abe1cfab..090290e8fc 100644 --- a/simtbx/modeling/forward_models.py +++ b/simtbx/modeling/forward_models.py @@ -197,7 +197,7 @@ def model_spots_from_pandas(pandas_frame, rois_per_panel=None, if "num_mosaicity_samples" in list(df): mos_dom = int(df.num_mosaicity_samples.values[0]) eta_abc = df.eta_abc.values[0] - LOGGER.debug("Num mos samples=%d, eta_abc=" % mos_dom, eta_abc) + LOGGER.debug("Num mos samples=%d, eta_abc=%f %f %f" % ((mos_dom,)+ eta_abc ) ) LOGGER.debug("Num energy channels=%d" % len(energies)) results = diffBragg_forward(CRYSTAL=expt.crystal, DETECTOR=expt.detector, BEAM=expt.beam, Famp=Famp, fluxes=fluxes, energies=energies, beamsize_mm=beamsize_mm, diff --git a/simtbx/modeling/predictions.py b/simtbx/modeling/predictions.py index a1aa37236f..1e8372a207 100644 --- a/simtbx/modeling/predictions.py +++ b/simtbx/modeling/predictions.py @@ -198,7 +198,7 @@ def label_weak_spots_for_integration(fraction, predictions, num_res_bins=10): res_sort = np.sort(res) res_bins = [rb[0]-1e-6 for rb in np.array_split( res_sort, num_res_bins)] + [res_sort[-1]+1e-6] res_bin_assigments = np.digitize(res, res_bins) - is_weak_but_integratable = np.zeros(len(predictions)).astype(np.bool) + is_weak_but_integratable = np.zeros(len(predictions)).astype(bool) for i_res in range(1, num_res_bins+1): # grab weak spots in this res bin is_weak_and_in_bin = logi_and(res_bin_assigments == i_res, predictions["is_weak"]) diff --git a/simtbx/nanoBragg/nanoBragg_crystal.py b/simtbx/nanoBragg/nanoBragg_crystal.py index a580b4e238..397c0fcb2e 100644 --- a/simtbx/nanoBragg/nanoBragg_crystal.py +++ b/simtbx/nanoBragg/nanoBragg_crystal.py @@ -103,7 +103,7 @@ def miller_array(self, val): self.miller_is_complex = True else: self.miller_is_complex = False - if str(val.observation_type) == "xray.intensity": + if str(val.observation_type()) == "xray.intensity": val = val.as_amplitude_array() self.cb_op = val.space_group_info().change_of_basis_op_to_primitive_setting() val = val.expand_to_p1() From 18fd9107d779713037a947e97b7532c356c992ce Mon Sep 17 00:00:00 2001 From: Pavel Date: Sun, 5 May 2024 18:21:51 -0700 Subject: [PATCH 416/748] Almost complete rewrite of water picking procedure to enable dealing with alternative conformations --- mmtbx/find_peaks.py | 2 +- mmtbx/model/model.py | 4 +- mmtbx/solvent/ordered_solvent.py | 512 +++++++++++++++++++------------ 3 files changed, 321 insertions(+), 197 deletions(-) diff --git a/mmtbx/find_peaks.py b/mmtbx/find_peaks.py index 758af24c68..659643c1ed 100644 --- a/mmtbx/find_peaks.py +++ b/mmtbx/find_peaks.py @@ -45,7 +45,7 @@ min_model_peak_dist = 1.8 .type=float .short_caption = Minimum distance from model - max_model_peak_dist = 6.0 + max_model_peak_dist = 3.2 .type=float .short_caption = Maximum distance from model min_peak_peak_dist = 1.8 diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index a5c9986bd2..aea6ef32c4 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -3891,7 +3891,9 @@ def _append_pdb_atoms(self, if conformer_indices is not None: ci = conformer_indices.conformer_indices[j_seq] cm = conformer_indices.index_altloc_mapping - altloc = list(cm.keys())[list(cm.values()).index(ci)] + if not ci in cm.values() and ci==0: altloc = "" + else: + altloc = list(cm.keys())[list(cm.values()).index(ci)] element, charge = sc.element_and_charge_symbols() new_atom = (iotbx.pdb.hierarchy.atom() .set_serial(new_serial=iotbx.pdb.hy36encode(width=5, value=n_seq+i_seq)) diff --git a/mmtbx/solvent/ordered_solvent.py b/mmtbx/solvent/ordered_solvent.py index e6234025dc..ac587e3750 100644 --- a/mmtbx/solvent/ordered_solvent.py +++ b/mmtbx/solvent/ordered_solvent.py @@ -7,8 +7,6 @@ import iotbx.xplor.map import iotbx.phil from mmtbx import find_peaks -from mmtbx.refinement import minimization -import scitbx.lbfgs import mmtbx.utils from cctbx import maptbx from libtbx.test_utils import approx_equal @@ -16,6 +14,13 @@ from libtbx.utils import user_plus_sys_time from libtbx.utils import null_out from mmtbx.solvent import map_to_water +from libtbx import group_args +import string + +def get_unique_altloc(exclude): + for l in string.ascii_uppercase: + if not l in exclude: + return l output_params_str = """ output_residue_name = HOH @@ -35,19 +40,15 @@ """ h_bond_params_str = """ - h_bond_min_mac = 1.8 - .type = float - .short_caption = H-bond minimum for solvent-model - .expert_level = 1 - h_bond_min_sol = 1.8 + dist_min = 1.8 .type = float - .short_caption = H-bond minimum for solvent-solvent + .short_caption = Min distance between water and any atom .expert_level = 1 - h_bond_max = 3.2 + dist_max = 3.2 .type = float - .short_caption = Maximum H-bond length + .short_caption = Max distance between water and any atom .expert_level = 1 - dist_min_altloc = 0.8 + dist_min_altloc = 0.5 .type = float """ @@ -73,12 +74,7 @@ .help = For solvent refined as anisotropic: remove is less than this value .short_caption = Minimum anisotropic B-factor .expert_level = 1 - b_iso = None - .type=float - .help = Initial B-factor value for newly added water - .short_caption = Initial B-factor value - .expert_level = 1 - occupancy_min = 0.1 + occupancy_min = 0.2 .type=float .help = Minimum occupancy value, waters with smaller value will be rejected .short_caption = Minimum occupancy @@ -110,7 +106,7 @@ include_altlocs = False .type = bool .help = Search for water with altlocs - n_cycles = 3 + n_cycles = 1 .type = int .short_caption = Number of cycles %s @@ -118,7 +114,7 @@ .type=str .help = Map used to identify candidate water sites - by default this is \ the standard difference map. - primary_map_cutoff = 3.0 + primary_map_cutoff = 3. .type=float .short_caption = Primary map cutoff (sigma) secondary_map_and_map_cc_filter @@ -131,20 +127,25 @@ cc_map_2_type = 2mFo-DFmodel .type = str .short_caption = Experimental map type for CC calculation - poor_cc_threshold = 0.7 + poor_cc_threshold = 0.50 .type = float .short_caption = Minimum map correlation - poor_map_value_threshold = 0.7 + poor_map_value_threshold = 1.0 .type = float .short_caption = Minimum map value (sigma) } %s + refine_oat = False + .type = bool + .help = Q & B coarse grid search. + .short_caption = Refine new solvent ADPs + .expert_level = 1 refine_adp = True .type = bool .help = Refine ADP for newly placed solvent. .short_caption = Refine new solvent ADPs .expert_level = 1 - refine_occupancies = False + refine_occupancies = True .type = bool .help = Refine solvent occupancies. .expert_level = 1 @@ -194,6 +195,7 @@ class maps(object): def __init__(self, fmodel, map_0_type, map_1_type, map_2_type, grid_step=0.6, radius=2.0): self.radius = radius + self.fmodel = fmodel self.e_map = fmodel.electron_density_map() self.crystal_symmetry = fmodel.xray_structure.crystal_symmetry() self.crystal_gridding = maptbx.crystal_gridding( @@ -204,6 +206,7 @@ def __init__(self, fmodel, map_0_type, map_1_type, map_2_type, self.map_0 = self._get_real_map(map_type = map_0_type) self.map_1 = self._get_real_map(map_type = map_1_type) self.map_2 = self._get_real_map(map_type = map_2_type) + #self._estimate_diff_map_cutoff() def _get_real_map(self, map_type): coeffs = self.e_map.map_coefficients( @@ -229,7 +232,151 @@ def score_atom(self, atom, min_cc, min_value): y=self.map_2.select(sel)).coefficient() value_2 = self.map_2.eight_point_interpolation(site_frac) result = cc > min_cc and value_2 > min_value*atom.occ - return result + return group_args(result = result, cc=cc, value_2=value_2) + + def _estimate_diff_map_cutoff(self): + scatterers = self.fmodel.xray_structure.scatterers() + sel = flex.random_bool(scatterers.size(), 0.1) + result = flex.double() + cntr=0 + for s, sc in zip(sel, scatterers): + if not s: continue + print(self.fmodel.r_work()) + occ = sc.occupancy + sc.occupancy=0 + self.fmodel.update_xray_structure(update_f_calc=True) + + coeffs = self.fmodel.electron_density_map().map_coefficients( + map_type = "mFo-DFmodel", + fill_missing = False, + isotropize = True) + fft_map = coeffs.fft_map(crystal_gridding = self.crystal_gridding) + fft_map.apply_sigma_scaling() + map_data = fft_map.real_map_unpadded() + mv = map_data.tricubic_interpolation(sc.site) + result.append(mv) + + print(self.fmodel.r_work(), mv) + sc.occupancy=occ + self.fmodel.update_xray_structure(update_f_calc=True) + print(self.fmodel.r_work()) + print() + if cntr>100: break + cntr+=1 + mean = flex.mean(result) + if mean/2 > 3: cutoff = 3 + +def fix_altlocs_and_filter(model, dist_min=1.8, fix_only=False): + sps = model.crystal_symmetry().special_position_settings() + get_class = iotbx.pdb.common_residue_names_get_class + only_model = model.get_hierarchy().only_model() + eps = 1.e-3 + dist_min = dist_min-eps + sites_cart = model.get_sites_cart() + atoms = only_model.atoms() + remove_sel = flex.size_t() + for agi in only_model.atom_groups(): # loop over water + if(not get_class(name=agi.resname) == "common_water"): continue + for ai in agi.atoms(): + if ai.element_is_hydrogen(): continue # skip water H + # + selection_around_ai = get_sphere_selection( + sites_cart_all=sites_cart, special_position_settings=sps, + radius=dist_min, i_seq=ai.i_seq) + if len(selection_around_ai) == 0: continue + # + altlocs_inside = [] + for j in selection_around_ai: + altlocs_inside.append( atoms[j].parent().altloc ) + # + skip = False + for j in selection_around_ai: + agj = atoms[j].parent() + if(agj.altloc in [' ', '']): + if(get_class(name=agj.resname) != "common_water"): + remove_sel.extend(agi.atoms().extract_i_seq()) + skip=True + else: + new_altloc = get_unique_altloc(exclude=altlocs_inside+[agi.altloc]) + agj.altloc = new_altloc + if skip: continue + # + altlocs_inside = [] + for j in selection_around_ai: + altlocs_inside.append( atoms[j].parent().altloc ) + # + if agi.altloc in altlocs_inside or agi.altloc in [' ', '']: + #print(ai.i_seq, selection_around_ai, altlocs_inside, [agi.altloc]) + new_altloc = get_unique_altloc(exclude=altlocs_inside+[agi.altloc]) + agi.altloc = new_altloc + # + if remove_sel.size() > 0 and not fix_only: + remove_sel = ~flex.bool(model.size(), remove_sel) + model = model.select(selection = remove_sel) + return model + +def get_sphere_selection( + sites_cart_all, special_position_settings, radius, i_seq): + sel = flex.bool(sites_cart_all.size(), False) + sel[i_seq] = True + selection_around_i_seq = special_position_settings.pair_generator( + sites_cart = sites_cart_all, + distance_cutoff = radius + ).neighbors_of(primary_selection = sel).iselection() + selection_around_i_seq = list(selection_around_i_seq) + if len(selection_around_i_seq) > 0: + selection_around_i_seq.remove(i_seq) + return selection_around_i_seq + +def filter_by_distance(model, dist_min=1.8, dist_max=3.2): + interaction_selection = model.selection( + map_to_water.selection_string_interaction) + sps = model.crystal_symmetry().special_position_settings() + get_class = iotbx.pdb.common_residue_names_get_class + only_model = model.get_hierarchy().only_model() + sites_cart = model.get_sites_cart() + atoms = only_model.atoms() + remove_sel = flex.size_t() + for agi in only_model.atom_groups(): # loop over water + if(not get_class(name=agi.resname) == "common_water"): continue + for ai in agi.atoms(): + if ai.element_is_hydrogen(): continue # skip water H + # Get selections + selection_around_ai_min = get_sphere_selection( + sites_cart_all=sites_cart, special_position_settings=sps, + radius=dist_min, i_seq=ai.i_seq) + selection_around_ai_max = get_sphere_selection( + sites_cart_all=sites_cart, special_position_settings=sps, + radius=dist_max, i_seq=ai.i_seq) + selection_shell = list( set(selection_around_ai_max) - + set(selection_around_ai_min) ) + # + altloc_i = ai.parent().altloc.strip() + # Make sure anything inside smaller sphere are altlocs + for j in selection_around_ai_min: + aj = atoms[j] + altloc_j = aj.parent().altloc + d = ai.distance(aj) + if(d0 and len(altloc_j)>0 + # Check water inside shell dist_min < dist < dist_max + found = False + for j in selection_shell: + if not interaction_selection[j]: continue + aj = atoms[j] + agj = aj.parent() + altloc_j = agj.altloc.strip() + if altloc_i=="" or altloc_j=="": found = True + if altloc_i==altloc_j and altloc_i!="": found = True + if get_class(name=agj.resname) == "common_water": + if altloc_i!="" and altloc_j!="": found = True + if not found: + remove_sel.extend(agi.atoms().extract_i_seq()) + # + if remove_sel.size() > 0: + remove_sel = ~flex.bool(model.size(), remove_sel) + model = model.select(selection = remove_sel) + return model class manager(object): def __init__(self, fmodel, @@ -243,6 +390,7 @@ def __init__(self, fmodel, # XXX Rationalize this: + self.find_peaks_params.map_next_to_model.min_peak_peak_dist=self.params.dist_max if self.params.include_altlocs: self.find_peaks_params.peak_search.min_cross_distance=0.5 self.find_peaks_params.map_next_to_model.min_model_peak_dist=0.5 @@ -254,44 +402,54 @@ def __init__(self, fmodel, self._peaks = None self.n_water = None self.model_size_init = self.model.size() + self.new_solvent_selection = None self.existing_solvent = None if(self.params.keep_existing): self.existing_solvent = self.model.solvent_selection().iselection() # - self._call(msg="Start") + self._call(msg="Start", func=None) + self._call(msg="Filter (dist)", func=self._filter_dist_fix_altlocs) + self._call(msg="Filter (q & B)", func=self._filter_q_b) self._call(msg="Compute maps", func=self._get_maps) - self._call(msg="Filter", func=self._filter_solvent) + self._call(msg="Filter (map)", func=self._filter_map) self._call(msg="Find peaks", func=self._find_peaks) - self._call(msg="Filter raw peaks", func=self._filter_raw_peaks) self._call(msg="Add new water", func=self._add_new_solvent) self._call(msg="Refine new water", func=self._refine) - self._call(msg="Compute maps", func=self._get_maps) - self._call(msg="Filter", func=self._filter_solvent) - self._call(msg="Correct drifted", func=self._correct_drifted_waters) + self._call(msg="Filter (q & B)", func=self._filter_q_b) + #self._call(msg="Correct drifted", func=self._correct_drifted_waters) def _call(self, msg, func = None): timer = user_plus_sys_time() self.ma.add(msg) self._assert_same_model() if(func is not None): func() - self._get_and_set_n_water() - rs="r_work=%6.4f r_free=%6.4f"%(self.fmodel.r_work(), self.fmodel.r_free()) - nw="n_water=%3d"%(self.n_water) + self._get_and_set_n_water_and_sync_fmodel_and_model_and_update_maps() + self._assert_same_model() t = timer.elapsed() self.total_time += t + self._add_to_message(this_step_time=t) + + def _add_to_message(self, this_step_time): + rs="r_work=%6.4f r_free=%6.4f"%(self.fmodel.r_work(), self.fmodel.r_free()) + nw="n_water=%3d"%(self.n_water) self.ma.add(" %s | %s | time (s): %s (total time: %s)"%(rs, nw, - ("%8.3f"%t).strip(), ("%8.3f"%self.total_time).strip())) + ("%8.3f"%this_step_time).strip(), ("%8.3f"%self.total_time).strip())) - def _get_and_set_n_water(self): - self.n_water = self.model.solvent_selection().count(True) + def _get_and_set_n_water_and_sync_fmodel_and_model_and_update_maps(self): + n_water = self.model.solvent_selection().count(True) + if n_water!=self.n_water: + self.fmodel.update_xray_structure( + xray_structure = self.model.get_xray_structure(), + update_f_calc = True, + update_f_mask = True) + self._get_maps() + self.n_water = n_water def _assert_same_model(self): - #assert self.model.get_xray_structure() is self.fmodel.xray_structure - mmtbx.utils.assert_xray_structures_equal( + mmtbx.utils.assert_xray_structures_equal( # XXX MAKE METHOD OF XRS x1 = self.model.get_xray_structure(), x2 = self.fmodel.xray_structure, eps=1.e-3) - self.model.is_same_model(other=self.model) def _get_maps(self): self._maps = maps( @@ -300,29 +458,27 @@ def _get_maps(self): map_1_type = self.params.secondary_map_and_map_cc_filter.cc_map_1_type, map_2_type = self.params.secondary_map_and_map_cc_filter.cc_map_2_type) - def _filter_solvent(self): - sol_sel = self.model.solvent_selection(offset = self.existing_solvent) - n_sol_start = self.n_water + def _filter_dist_fix_altlocs(self): + if self.params.include_altlocs: + self.model = fix_altlocs_and_filter( + model = self.model, + dist_min = self.params.dist_min) + self.model = filter_by_distance( + model = self.model, + dist_min = self.params.dist_min, + dist_max = self.params.dist_max) + + def _filter_q_b(self): + self._filter(filter_occ=True, filter_adp=True) + + def _filter_map(self): + self._filter(filter_map=True) + + def _filter(self, + filter_map=False, + filter_occ=False, + filter_adp=False): mfp = self.params.secondary_map_and_map_cc_filter - # Select by distance - interaction_selection = self.model.selection( - map_to_water.selection_string_interaction) - cis = self.model.get_hierarchy().get_conformer_indices() - distance_iselection = mmtbx.utils.filter_water_fsr( - interaction_selection = interaction_selection, - sites_frac = self.model.get_sites_frac(), - solvent_selection = sol_sel, - skip_selection = self.model.get_hd_selection(), - conformer_indices = cis.conformer_indices, # Will be changed inplace - dist_max = self.params.h_bond_max, - dist_min = self.params.h_bond_min_mac, - dist_min_altloc = self.params.dist_min_altloc, - unit_cell = self.model.crystal_symmetry().unit_cell()) - - all_selection = (~sol_sel).iselection() - all_selection.extend(distance_iselection) - self.model = self.model.select(all_selection) - # Select by attributes selection = flex.bool(self.model.size(), True) get_class = iotbx.pdb.common_residue_names_get_class scatterers = self.model.get_xray_structure().scatterers() @@ -345,36 +501,34 @@ def _filter_solvent(self): i_seq = atom.i_seq if(self.params.keep_existing and i_seq in self.existing_solvent): continue - if(atom.occ > self.params.occupancy_max or - atom.occ < self.params.occupancy_min): keep = False - assert approx_equal(atom.occ, occ[i_seq], 1.e-3) - if(anisotropy[i_seq] < self.params.anisotropy_min): keep = False - if(b_isos[i_seq] < self.params.b_iso_min or - b_isos[i_seq] > self.params.b_iso_max): keep = False - good_map = self._maps.score_atom( - atom = atom, - min_cc = mfp.poor_cc_threshold, - min_value = mfp.poor_map_value_threshold) - if(not good_map): - keep = False + # Occupancy + if filter_occ: + if(atom.occ > self.params.occupancy_max or + atom.occ < self.params.occupancy_min): keep = False + assert approx_equal(atom.occ, occ[i_seq], 1.e-3) + # ADP + if filter_adp: + if(anisotropy[i_seq] < self.params.anisotropy_min): keep = False + if(b_isos[i_seq] < self.params.b_iso_min or + b_isos[i_seq] > self.params.b_iso_max): keep = False + # + if filter_map: + good_map = self._maps.score_atom( + atom = atom, + min_cc = mfp.poor_cc_threshold, + min_value = mfp.poor_map_value_threshold) + if(not good_map.result): + keep = False if(not has_oxygen): keep=False if(not keep): selection = selection.set_selected(i_seqs, False) - # Apply selection - self.model = self.model.select(selection) - n_sol_final = self.model.solvent_selection().count(True) - if(n_sol_final != n_sol_start): - self.fmodel.update_xray_structure( - xray_structure = self.model.get_xray_structure(), - update_f_calc = True, - update_f_mask = True) + self.model = self.model.select(selection) def _refine(self): if(self.params.mode == "filter_only"): return if(self.model.size() == self.model_size_init or self.n_water==0): return for i in range(self.params.n_cycles): - self.refine_adp() - self.refine_occupancies() + self.refine_oat() def _find_peaks(self): if(self.params.mode == "filter_only"): return @@ -389,66 +543,38 @@ def _find_peaks(self): params = self.find_peaks_params, log = null_out()).peaks_mapped() - def _write_pdb_file(self, sites_frac): - fmt = "ATOM %5d O HOH S%4d %8.3f%8.3f%8.3f 1.00 0.00 O" - uc = self.fmodel.xray_structure.crystal_symmetry().unit_cell() - with open("zz.pdb", "w") as fo: - for i, sf in enumerate(sites_frac): - sc = uc.orthogonalize(sf) - print(fmt%(i,i,sc[0],sc[1],sc[2]), file=fo) - - def _filter_raw_peaks(self): - if self._peaks is None: return - sites, heights = self._peaks.sites, self._peaks.heights - # - interaction_selection = self.model.selection( - map_to_water.selection_string_interaction) - interaction_selection.extend( flex.bool(sites.size(), True) ) - - sites_frac = self.model.get_sites_frac() - sites_frac.extend(sites) - - skip_selection = self.model.get_hd_selection() - skip_selection.extend( flex.bool(sites.size(), False) ) - - cis = self.model.get_hierarchy().get_conformer_indices() - cis.conformer_indices.extend( flex.size_t(sites.size(), 0) ) - - peaks_selection = flex.bool(self.model.size(), False) - peaks_selection.extend( flex.bool(sites.size(), True) ) - - distance_iselection = mmtbx.utils.filter_water_fsr( - interaction_selection = interaction_selection, - sites_frac = sites_frac, - solvent_selection = peaks_selection, - skip_selection = skip_selection, - conformer_indices = cis.conformer_indices, # Will be changed inplace - dist_max = self.params.h_bond_max, - dist_min = self.params.h_bond_min_mac, - dist_min_altloc = self.params.dist_min_altloc, - unit_cell = self.model.crystal_symmetry().unit_cell()) - # - cis.conformer_indices = cis.conformer_indices.select(peaks_selection) - # - self._peaks.sites = sites_frac.select(peaks_selection) - self._peaks.heights = None - self._peaks.conformer_indices = cis + def _write_pdb_file(self, file_name="tmp.pdb", sites_frac=None): + if sites_frac is not None: + fmt = "ATOM %5d O HOH S%4d %8.3f%8.3f%8.3f 1.00 0.00 O" + uc = self.fmodel.xray_structure.crystal_symmetry().unit_cell() + with open(file_name, "w") as fo: + for i, sf in enumerate(sites_frac): + sc = uc.orthogonalize(sf) + print(fmt%(i,i,sc[0],sc[1],sc[2]), file=fo) + else: + with open(file_name, "w") as fo: + fo.write(self.model.model_as_pdb()) def _add_new_solvent(self): if(self._peaks is None): return sites, heights = self._peaks.sites, self._peaks.heights if(sites.size()==0): return if(self.params.mode == "filter_only"): return - if(self.params.b_iso is None): - b_solv = min(max( - self.params.b_iso_min, flex.mean(self.model.get_b_iso())), - self.params.b_iso_max) + + self.new_solvent_selection = flex.bool(self.model.size(), False) + self.new_solvent_selection.extend(flex.bool(sites.size(), True)) + + if self.params.refine_oat: + b_solv = 0 + occ = 0. else: - b_solv = self.params.b_iso + b_solv = 20 + occ = 0.004 + if(self.params.new_solvent == "isotropic"): new_scatterers = flex.xray_scatterer( sites.size(), - xray.scatterer(occupancy = self.params.occupancy, + xray.scatterer(occupancy = occ, b = b_solv, scattering_type = self.params.scattering_type)) elif(self.params.new_solvent == "anisotropic"): @@ -457,7 +583,7 @@ def _add_new_solvent(self): new_scatterers = flex.xray_scatterer( sites.size(), xray.scatterer( - occupancy = self.params.occupancy, + occupancy = occ, u = u_star, scattering_type = self.params.scattering_type)) else: raise RuntimeError @@ -467,75 +593,75 @@ def _add_new_solvent(self): scatterers = new_scatterers) self.model.add_solvent( solvent_xray_structure = solvent_xray_structure, - conformer_indices = self._peaks.conformer_indices, + conformer_indices = None, #self._peaks.conformer_indices, residue_name = self.params.output_residue_name, atom_name = self.params.output_atom_name, chain_id = self.params.output_chain_id, refine_occupancies = self.params.refine_occupancies, refine_adp = self.params.new_solvent) - self.fmodel.update_xray_structure( - xray_structure = self.model.get_xray_structure(), - update_f_calc = True, - update_f_mask = True) - - def refine_adp(self): - if(self.params.refine_adp #and - #self.model.refinement_flags.individual_adp and - ): - hd_sel = self.model.get_hd_selection() - not_hd_sel = ~hd_sel - sol_sel = self.model.solvent_selection(offset=self.existing_solvent) - not_sol_sel= ~sol_sel - selection_aniso = self.model.get_xray_structure().use_u_aniso().deep_copy() - if(self.params.new_solvent == "anisotropic"): - selection_aniso.set_selected(sol_sel, True) - selection_iso = self.model.get_xray_structure().use_u_iso().deep_copy() - selection_aniso.set_selected(not_sol_sel, False) - selection_iso .set_selected(not_sol_sel, False) - if(not self.is_neutron_scat_table): - selection_aniso.set_selected(hd_sel, False) - selection_iso.set_selected(hd_sel, False) - selection_aniso.set_selected(selection_iso, False) - selection_iso.set_selected(selection_aniso, False) - self.model.set_refine_individual_adp( - selection_aniso = selection_aniso, selection_iso = selection_iso) - lbfgs_termination_params = scitbx.lbfgs.termination_parameters( - max_iterations = 50) - minimized = minimization.lbfgs( - restraints_manager = None, - fmodels = self.fmodels, - model = self.model, - is_neutron_scat_table = self.is_neutron_scat_table, - refine_adp = True, - lbfgs_termination_params = lbfgs_termination_params) + #### + # This is an ugly work-around to set altlocs and conformer_indices + #### + if self.params.include_altlocs: + self.model = fix_altlocs_and_filter(model=self.model, fix_only=True) + ss = self.model.solvent_selection() + ms = self.model.select(ss) + self.model = self.model.select(~ss) + self.model.add_solvent( + solvent_xray_structure = ms.get_xray_structure(), + conformer_indices = ms.get_hierarchy().get_conformer_indices(), + residue_name = self.params.output_residue_name, + atom_name = self.params.output_atom_name, + chain_id = self.params.output_chain_id, + refine_occupancies = self.params.refine_occupancies, + refine_adp = self.params.new_solvent) + ### + + def refine_oat(self): + if(self.params.refine_oat and self.new_solvent_selection.count(True)>0): + from phenix.programs import oat + from cctbx import adptbx + atoms = self.model.get_hierarchy().atoms() + scatterers = self.fmodel.xray_structure.scatterers() + for i, sel in enumerate(self.new_solvent_selection): + if not sel: continue + r_start = self.fmodel.r_work() + scatterers[i].occupancy=0 + scatterers[i].u_iso=0 + self.fmodel.update_xray_structure(update_f_calc=True) + r_omit = self.fmodel.r_work() + fmodel_dc = self.fmodel.deep_copy() + oo = oat.loop( + fmodel = fmodel_dc, + site = atoms[i].xyz, + label = "O", + qs = flex.double([0.3, 0.6, 0.9]), + bs = flex.double([10, 30, 60]) + ) + scatterers[i].occupancy = oo.o_best + scatterers[i].u_iso = adptbx.b_as_u(oo.b_best) + self.fmodel.update_xray_structure(update_f_calc=True) + r_final = self.fmodel.r_work() + #print(atoms[i].quote(), "%8.6f %8.6f %8.6f %8.6f"%( + # r_start, r_omit, r_final, oo.rw_best), "|", oo.o_best, oo.b_best) self.model.adopt_xray_structure( xray_structure = self.fmodel.xray_structure) print(" ADP (water only), final r_work=%6.4f r_free=%6.4f"%( self.fmodel.r_work(), self.fmodel.r_free()), file=self.log) - - def refine_occupancies(self): - if(self.params.refine_occupancies #and - #self.model.refinement_flags.occupancies and - ): - self.fmodels.fmodel_xray().xray_structure.scatterers().flags_set_grads( - state = False) - i_selection = self.model.solvent_selection( - offset=self.existing_solvent).iselection() - self.fmodels.fmodel_xray().xray_structure.scatterers( - ).flags_set_grad_occupancy(iselection = i_selection) - lbfgs_termination_params = scitbx.lbfgs.termination_parameters( - max_iterations = 50) - minimized = mmtbx.refinement.minimization.lbfgs( - restraints_manager = None, - fmodels = self.fmodels, - model = self.model, - is_neutron_scat_table = self.is_neutron_scat_table, - lbfgs_termination_params = lbfgs_termination_params) # + if(self.params.refine_adp and self.params.refine_occupancies and + self.new_solvent_selection.count(True)>0): + from mmtbx.refinement import wrappers + o = wrappers.unrestrained_qb_fsr( + fmodel = self.fmodel, + selection = self.new_solvent_selection, + q_min = 0.004, + b_max = 60, + log = self.log) self.model.adopt_xray_structure( - xray_structure = self.fmodel.xray_structure) - print(" occ (water only), start r_work=%6.4f r_free=%6.4f"%( - self.fmodel.r_work(), self.fmodel.r_free()), file=self.log) + xray_structure = self.fmodel.xray_structure) + print(" ADP (water only), final r_work=%6.4f r_free=%6.4f"%( + self.fmodel.r_work(), self.fmodel.r_free()), file=self.log) def _correct_drifted_waters(self): if(self.params.mode != "filter_only"): return @@ -566,7 +692,3 @@ def _correct_drifted_waters(self): water_selection = solvent_selection, unit_cell = self.model.get_xray_structure().unit_cell()) self.model.get_xray_structure().set_sites_frac(sites_frac = model_sites_frac) - self.fmodel.update_xray_structure( - xray_structure = self.model.get_xray_structure(), - update_f_calc = True, - update_f_mask = True) From a86cf234aafdfa13e045b4545bfaa945ea93045c Mon Sep 17 00:00:00 2001 From: Pavel Date: Sun, 5 May 2024 18:24:01 -0700 Subject: [PATCH 417/748] Towards generalizing the use of LBFGS and switching to LBFGS-B --- mmtbx/refinement/calculators.py | 44 ++++++++++++++++++++++ mmtbx/refinement/data.py | 54 +++++++++++++++++++++++++++ mmtbx/refinement/wrappers.py | 66 +++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+) create mode 100644 mmtbx/refinement/calculators.py create mode 100644 mmtbx/refinement/data.py create mode 100644 mmtbx/refinement/wrappers.py diff --git a/mmtbx/refinement/calculators.py b/mmtbx/refinement/calculators.py new file mode 100644 index 0000000000..8cb2a6bba1 --- /dev/null +++ b/mmtbx/refinement/calculators.py @@ -0,0 +1,44 @@ +from __future__ import division +from libtbx import adopt_init_args + +class individual(object): + def __init__(self, + data, + x, + data_weight=1, + restraints=None, + restraints_weight=None, + lower_bound=None, + upper_bound=None, + bound_flags=None): + adopt_init_args(self, locals()) + self.t = None + self.g = None + self.d = None + self.use_curvatures=False + self.n = x.size() + # + self.update(x = self.x) + self.f_start = self.t + + def __call__(self): + f, g = self.target_and_gradients() + return self.x, f, g + + def update(self, x): + self.data.update(x = x) + self.x = x + self.t, self.g = 0, 0 + for p in [[self.data, self.data_weight], + [self.restraints, self.restraints_weight]]: + source, weight = p + if source is not None: + self.t += source.target()*weight + self.g += source.gradients()*weight + + def target_and_gradients(self): + self.update(x = self.x) + return self.t, self.g + + def compute_functional_and_gradients(self): + return self.target_and_gradients() diff --git a/mmtbx/refinement/data.py b/mmtbx/refinement/data.py new file mode 100644 index 0000000000..a759d99eea --- /dev/null +++ b/mmtbx/refinement/data.py @@ -0,0 +1,54 @@ +from __future__ import absolute_import, division +from cctbx.array_family import flex +from libtbx import adopt_init_args + +class fs(object): + """ + Fourier (reciprocal) space target and gradinets manager. + 'selection' selects parameters to be refined. + """ + def __init__(self, + fmodel, + sites_cart = False, + u_iso = False, + occupancy = False, + selection = None): + adopt_init_args(self, locals()) + self.target_functor_xray = fmodel.target_functor( + alpha_beta = None # XXX Check what that means + ) + self.fmodel.xray_structure.scatterers().flags_set_grads(state=False) + if selection is None: + selection = self.fmodel.xray_structure.all_selection().iselection() + if isinstance(selection, flex.bool): + selection = selection.iselection() + sc = self.fmodel.xray_structure.scatterers() + self.size = sc.size() + if (self.sites_cart): sc.flags_set_grad_site(iselection = selection) + elif(self.u_iso): sc.flags_set_grad_u_iso(iselection = selection) + elif(self.occupancy): sc.flags_set_grad_occupancy(iselection = selection) + + def update(self, x): + if (self.sites_cart): + pass + elif(self.u_iso): + self.fmodel.xray_structure.set_u_iso(values = x) + elif(self.occupancy): + self.fmodel.xray_structure.set_occupancies(value=x) + self.fmodel.update_xray_structure(update_f_calc = True) + self.tg = self.target_functor_xray(compute_gradients = True) + + def target(self): + return self.tg.target_work() + + def gradients(self): + if self.selection is None: + return self.tg.gradients_wrt_atomic_parameters().packed() + else: + g = self.tg.gradients_wrt_atomic_parameters().packed() + if not self.sites_cart: + result = flex.double(self.size, 0) + result.set_selected(self.selection, g) + else: + assert 0 # not implemented + return result diff --git a/mmtbx/refinement/wrappers.py b/mmtbx/refinement/wrappers.py new file mode 100644 index 0000000000..93dd72fe06 --- /dev/null +++ b/mmtbx/refinement/wrappers.py @@ -0,0 +1,66 @@ +from __future__ import division +from libtbx import adopt_init_args +from scitbx import minimizers +from scitbx.array_family import flex +import mmtbx.refinement.data +from mmtbx.refinement import calculators +from cctbx import adptbx + +class unrestrained_qb_fsr(object): + """ + Unrestrained sequential occupancy (q) and isotropic ADP (b) refinement. + Use example: refinement of ocupancy and B-factors of newly placed water only. + Input fmodel is changed in-place. + """ + def __init__(self, + fmodel, + selection, + macro_cycles=3, + max_iterations=50, + q_min = 0., + q_max = 1, + b_min = 5, + b_max = 45, + log = None): + adopt_init_args(self, locals()) + for micro_cycle in range(macro_cycles): + # Occupancy + data = mmtbx.refinement.data.fs( + fmodel = fmodel, occupancy=True, selection=selection) + x = fmodel.xray_structure.scatterers().extract_occupancies() + lower_bound = x.deep_copy() + lower_bound.set_selected(selection, q_min) + upper_bound = x.deep_copy() + upper_bound.set_selected(selection, q_max) + calculator = calculators.individual( + data = data, + x = x, + lower_bound = lower_bound, + upper_bound = upper_bound, + bound_flags = flex.int(x.size(), 2)) + minimized = minimizers.lbfgsb( + calculator = calculator, + max_iterations = max_iterations) + if log is not None: + print("occ: r_work=%6.4f r_free=%6.4f"%( + fmodel.r_work(), fmodel.r_free()), file = log) + # ADP + data = mmtbx.refinement.data.fs( + fmodel = fmodel, u_iso=True, selection=selection) + x = fmodel.xray_structure.extract_u_iso_or_u_equiv() + lower_bound = x.deep_copy() + lower_bound.set_selected(selection, adptbx.b_as_u(b_min)) + upper_bound = x.deep_copy() + upper_bound.set_selected(selection, adptbx.b_as_u(b_max)) + calculator = calculators.individual( + data = data, + x = x, + lower_bound = lower_bound, + upper_bound = upper_bound, + bound_flags = flex.int(x.size(), 2)) + minimized = minimizers.lbfgsb( + calculator = calculator, + max_iterations = max_iterations) + if log is not None: + print("adp: r_work=%6.4f r_free=%6.4f"%( + fmodel.r_work(), fmodel.r_free()), file = log) From 6d1434286870cf13e64462ed3d7e52a202852d24 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sun, 5 May 2024 18:38:10 -0700 Subject: [PATCH 418/748] Test for mmtbx/refinement/wrappers.py --- .../tst_mmtbx_refinement_wrappers.py | 118 ++++++++++++++++++ mmtbx/run_tests.py | 2 + 2 files changed, 120 insertions(+) create mode 100644 mmtbx/regression/tst_mmtbx_refinement_wrappers.py diff --git a/mmtbx/regression/tst_mmtbx_refinement_wrappers.py b/mmtbx/regression/tst_mmtbx_refinement_wrappers.py new file mode 100644 index 0000000000..bad980d825 --- /dev/null +++ b/mmtbx/regression/tst_mmtbx_refinement_wrappers.py @@ -0,0 +1,118 @@ +from __future__ import division +import iotbx.pdb +import mmtbx.model +import mmtbx.f_model +from scitbx.array_family import flex +import sys, time + +from mmtbx.refinement import wrappers + +import random +random.seed(0) +flex.set_random_seed(0) + +pdb_str = """ +CRYST1 21.937 4.866 23.477 90.00 107.08 90.00 P 1 21 1 2 +ATOM 1 N GLY A 1 -9.009 4.612 6.102 1.00 16.77 N +ATOM 2 CA GLY A 1 -9.052 4.207 4.651 1.00 16.57 C +ATOM 3 C GLY A 1 -8.015 3.140 4.419 1.00 16.16 C +ATOM 4 O GLY A 1 -7.523 2.521 5.381 1.00 16.78 O +ATOM 5 N ASN A 2 -7.656 2.923 3.155 1.00 15.02 N +ATOM 6 CA ASN A 2 -6.522 2.038 2.831 1.00 14.10 C +ATOM 7 C ASN A 2 -5.241 2.537 3.427 1.00 13.13 C +ATOM 8 O ASN A 2 -4.978 3.742 3.426 1.00 11.91 O +ATOM 9 CB ASN A 2 -6.346 1.881 1.341 1.00 15.38 C +ATOM 10 CG ASN A 2 -7.584 1.342 0.692 1.00 14.08 C +ATOM 11 OD1 ASN A 2 -8.025 0.227 1.016 1.00 17.46 O +ATOM 12 ND2 ASN A 2 -8.204 2.155 -0.169 1.00 11.72 N +ATOM 13 N ASN A 3 -4.438 1.590 3.905 1.00 12.26 N +ATOM 14 CA ASN A 3 -3.193 1.904 4.589 1.00 11.74 C +ATOM 15 C ASN A 3 -1.955 1.332 3.895 1.00 11.10 C +ATOM 16 O ASN A 3 -1.872 0.119 3.648 1.00 10.42 O +ATOM 17 CB ASN A 3 -3.259 1.378 6.042 1.00 12.15 C +ATOM 18 CG ASN A 3 -2.006 1.739 6.861 1.00 12.82 C +ATOM 19 OD1 ASN A 3 -1.702 2.925 7.072 1.00 15.05 O +ATOM 20 ND2 ASN A 3 -1.271 0.715 7.306 1.00 13.48 N +ATOM 21 N GLN A 4 -1.005 2.228 3.598 1.00 10.29 N +ATOM 22 CA GLN A 4 0.384 1.888 3.199 1.00 10.53 C +ATOM 23 C GLN A 4 1.435 2.606 4.088 1.00 10.24 C +ATOM 24 O GLN A 4 1.547 3.843 4.115 1.00 8.86 O +ATOM 25 CB GLN A 4 0.656 2.148 1.711 1.00 9.80 C +ATOM 26 CG GLN A 4 1.944 1.458 1.213 1.00 10.25 C +ATOM 27 CD GLN A 4 2.504 2.044 -0.089 1.00 12.43 C +ATOM 28 OE1 GLN A 4 2.744 3.268 -0.190 1.00 14.62 O +ATOM 29 NE2 GLN A 4 2.750 1.161 -1.091 1.00 9.05 N +ATOM 30 N GLN A 5 2.154 1.821 4.871 1.00 10.38 N +ATOM 31 CA GLN A 5 3.270 2.361 5.640 1.00 11.39 C +ATOM 32 C GLN A 5 4.594 1.768 5.172 1.00 11.52 C +ATOM 33 O GLN A 5 4.768 0.546 5.054 1.00 12.05 O +ATOM 34 CB GLN A 5 3.056 2.183 7.147 1.00 11.96 C +ATOM 35 CG GLN A 5 1.829 2.950 7.647 1.00 10.81 C +ATOM 36 CD GLN A 5 1.344 2.414 8.954 1.00 13.10 C +ATOM 37 OE1 GLN A 5 0.774 1.325 9.002 1.00 10.65 O +ATOM 38 NE2 GLN A 5 1.549 3.187 10.039 1.00 12.30 N +ATOM 39 N ASN A 6 5.514 2.664 4.856 1.00 11.99 N +ATOM 40 CA ASN A 6 6.831 2.310 4.318 1.00 12.30 C +ATOM 41 C ASN A 6 7.854 2.761 5.324 1.00 13.40 C +ATOM 42 O ASN A 6 8.219 3.943 5.374 1.00 13.92 O +ATOM 43 CB ASN A 6 7.065 3.016 2.993 1.00 12.13 C +ATOM 44 CG ASN A 6 5.961 2.735 2.003 1.00 12.77 C +ATOM 45 OD1 ASN A 6 5.798 1.604 1.551 1.00 14.27 O +ATOM 46 ND2 ASN A 6 5.195 3.747 1.679 1.00 10.07 N +ATOM 47 N TYR A 7 8.292 1.817 6.147 1.00 14.70 N +ATOM 48 CA TYR A 7 9.159 2.144 7.299 1.00 15.18 C +ATOM 49 C TYR A 7 10.603 2.331 6.885 1.00 15.91 C +ATOM 50 O TYR A 7 11.041 1.811 5.855 1.00 15.76 O +ATOM 51 CB TYR A 7 9.061 1.065 8.369 1.00 15.35 C +ATOM 52 CG TYR A 7 7.665 0.929 8.902 1.00 14.45 C +ATOM 53 CD1 TYR A 7 6.771 0.021 8.327 1.00 15.68 C +ATOM 54 CD2 TYR A 7 7.210 1.756 9.920 1.00 14.80 C +ATOM 55 CE1 TYR A 7 5.480 -0.094 8.796 1.00 13.46 C +ATOM 56 CE2 TYR A 7 5.904 1.649 10.416 1.00 14.33 C +ATOM 57 CZ TYR A 7 5.047 0.729 9.831 1.00 15.09 C +ATOM 58 OH TYR A 7 3.766 0.589 10.291 1.00 14.39 O +ATOM 59 OXT TYR A 7 11.358 2.999 7.612 1.00 17.49 O +TER 60 TYR A 7 +HETATM 61 O HOH A 8 -6.471 5.227 7.124 1.00 22.62 O +HETATM 62 O HOH A 9 10.431 1.858 3.216 1.00 19.71 O +HETATM 63 O HOH A 10 -11.286 1.756 -1.468 1.00 17.08 O +HETATM 64 O HOH A 11 11.808 4.179 9.970 1.00 23.99 O +HETATM 65 O HOH A 12 13.605 1.327 9.198 1.00 26.17 O +HETATM 66 O HOH A 13 -2.749 3.429 10.024 1.00 39.15 O +HETATM 67 O HOH A 14 -1.500 0.682 10.967 1.00 43.49 O +END +""" + +def run(): + pdb_inp = iotbx.pdb.input(source_info=None, lines=pdb_str) + model = mmtbx.model.manager(model_input = pdb_inp) + xrs = model.get_xray_structure() + sel = model.selection(string="water") + # + f_obs = abs(xrs.structure_factors(d_min=1.0, algorithm="direct").f_calc()) + flags = f_obs.generate_r_free_flags() + sfg_params = mmtbx.f_model.sf_and_grads_accuracy_master_params.extract() + sfg_params.algorithm="direct" + # + xrs.shake_occupancies(selection = sel) + xrs.shake_adp(selection = sel) + # + fmodel = mmtbx.f_model.manager( + f_obs = f_obs, + target_name = "ls_wunit_kunit", + xray_structure = xrs, + sf_and_grads_accuracy_params = sfg_params) + print("r_work=%6.4f r_free=%6.4f"%(fmodel.r_work(), fmodel.r_free())) + # + o = wrappers.unrestrained_qb_fsr( + fmodel = fmodel, + selection = sel, + log = sys.stdout, + macro_cycles = 20) + print("Final: r_work=%6.4f r_free=%6.4f"%(fmodel.r_work(), fmodel.r_free())) + assert fmodel.r_work() < 0.0005 + +if(__name__ == "__main__"): + t0 = time.time() + run() + print("Time: %6.4f"%(time.time()-t0)) diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index 279d93b686..8be45b46ca 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -44,6 +44,8 @@ "$D/regression/tls/tst_formula_t_S_10_vs_11_2igd.py", "$D/regression/tls/tst_formula_t_S_10_vs_11_4muy.py", # + "$D/regression/tst_mmtbx_refinement_wrappers.py", + # "$D/regression/tst_angle.py", "$D/regression/tst_holton_geometry_validation.py", "$D/rotamer/tst_rotamer_eval.py", From 635dc5998c5530ca0909e4c3974fedd495dd3857 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Mon, 6 May 2024 09:52:24 -0700 Subject: [PATCH 419/748] mmtbx: add print_function import --- mmtbx/refinement/wrappers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/refinement/wrappers.py b/mmtbx/refinement/wrappers.py index 93dd72fe06..27077da672 100644 --- a/mmtbx/refinement/wrappers.py +++ b/mmtbx/refinement/wrappers.py @@ -1,4 +1,4 @@ -from __future__ import division +from __future__ import division, print_function from libtbx import adopt_init_args from scitbx import minimizers from scitbx.array_family import flex From 80cbf5239cf4aa231c09c3c706780ed59b156e3b Mon Sep 17 00:00:00 2001 From: Pavel Date: Mon, 6 May 2024 13:55:06 -0700 Subject: [PATCH 420/748] Clarify map names, add main chain masking, handle H correctly --- mmtbx/masks/__init__.py | 6 +- mmtbx/solvent/ordered_solvent.py | 94 +++++++++++++++++++++++++------- 2 files changed, 79 insertions(+), 21 deletions(-) diff --git a/mmtbx/masks/__init__.py b/mmtbx/masks/__init__.py index e48e081bcc..8be2b48c2b 100644 --- a/mmtbx/masks/__init__.py +++ b/mmtbx/masks/__init__.py @@ -394,6 +394,7 @@ def __init__( for_structure_factors, n_real, atom_radii=None, + atom_radius=None, solvent_radius=None, shrink_truncation_radius=None, in_asu=False, @@ -406,8 +407,11 @@ def __init__( xrs = xray_structure sgt = xrs.space_group().type() # must be BEFORE going to P1, obviously! if(p1): xrs = xrs.expand_to_p1(sites_mod_positive=True) - if(atom_radii is None): + if([atom_radii,atom_radius].count(None)==2): atom_radii = vdw_radii_from_xray_structure(xray_structure = xrs) + elif atom_radius is not None: + assert atom_radii is None + atom_radii = flex.double(xrs.scatterers().size(), atom_radius) if(rad_extra is not None): atom_radii = atom_radii+rad_extra self.asu_mask = mmtbx.masks.atom_mask( diff --git a/mmtbx/solvent/ordered_solvent.py b/mmtbx/solvent/ordered_solvent.py index ac587e3750..0572e72548 100644 --- a/mmtbx/solvent/ordered_solvent.py +++ b/mmtbx/solvent/ordered_solvent.py @@ -100,6 +100,9 @@ def get_unique_altloc(exclude): after ferst few macro-cycles, filter_only - remove water only, \ every_macro_cycle - do water update every macro-cycle .short_caption = Mode + mask_atoms_selection = protein and (name CA or name CB or name N or name C or name O) + .type = str + .help = Mask macromolecule atoms in peak picking map keep_existing = False .type = bool .help = Keep existing in the model water @@ -127,7 +130,7 @@ def get_unique_altloc(exclude): cc_map_2_type = 2mFo-DFmodel .type = str .short_caption = Experimental map type for CC calculation - poor_cc_threshold = 0.50 + poor_cc_threshold = 0.70 .type = float .short_caption = Minimum map correlation poor_map_value_threshold = 1.0 @@ -192,10 +195,18 @@ def master_params(): return iotbx.phil.parse(master_params_str) class maps(object): - def __init__(self, fmodel, map_0_type, map_1_type, map_2_type, - grid_step=0.6, radius=2.0): + def __init__(self, + fmodel, + model, + mask_atoms_selection, + difference_map_type, + model_map_type, + data_map_type, + grid_step=0.6, + radius=2.0): self.radius = radius self.fmodel = fmodel + self.model = model self.e_map = fmodel.electron_density_map() self.crystal_symmetry = fmodel.xray_structure.crystal_symmetry() self.crystal_gridding = maptbx.crystal_gridding( @@ -203,10 +214,47 @@ def __init__(self, fmodel, map_0_type, map_1_type, map_2_type, space_group_info = self.crystal_symmetry.space_group_info(), symmetry_flags = maptbx.use_space_group_symmetry, step = grid_step) - self.map_0 = self._get_real_map(map_type = map_0_type) - self.map_1 = self._get_real_map(map_type = map_1_type) - self.map_2 = self._get_real_map(map_type = map_2_type) + self.difference_map = self._get_real_map(map_type = difference_map_type) + self.model_map = self._get_real_map(map_type = model_map_type) + self.data_map = self._get_real_map(map_type = data_map_type) #self._estimate_diff_map_cutoff() + # Compute mask in P1 to mask out desired regions + if mask_atoms_selection is not None: + bb_sel = self.model.selection(string=mask_atoms_selection) + if bb_sel.count(True)>0: + xrs = fmodel.xray_structure.select(bb_sel) + # + # Both ways to compute mask should be the same, but they are slighly not, + # expectedly. + # + mask_p1 = mmtbx.masks.mask_from_xray_structure( + xray_structure = xrs, + p1 = True, + for_structure_factors = True, + solvent_radius = 0, + shrink_truncation_radius = 0, + atom_radius = 1.2, + n_real = self.crystal_gridding.n_real(), + in_asu = False).mask_data + maptbx.unpad_in_place(map=mask_p1) + sel0 = mask_p1 > 0.1 + mask_p1 = mask_p1.set_selected(sel0, 1) + mask_p1 = mask_p1.set_selected(~sel0, 0) + + #xrs = xrs.expand_to_p1() + #import boost_adaptbx.boost.python as bp + #cctbx_maptbx_ext = bp.import_ext("cctbx_maptbx_ext") + #radii = flex.double(xrs.scatterers().size(), 1.2) + #mask_p1 = cctbx_maptbx_ext.mask( + # sites_frac = xrs.sites_frac(), + # unit_cell = xrs.unit_cell(), + # n_real = self.crystal_gridding.n_real(), + # mask_value_inside_molecule = 0, + # mask_value_outside_molecule = 1, + # radii = radii, + # wrapping = True) + + self.difference_map = self.difference_map * mask_p1 def _get_real_map(self, map_type): coeffs = self.e_map.map_coefficients( @@ -223,14 +271,14 @@ def score_atom(self, atom, min_cc, min_value): site_frac = uc.fractionalize(site_cart) sel = maptbx.grid_indices_around_sites( unit_cell = uc, - fft_n_real = self.map_1.focus(), - fft_m_real = self.map_1.all(), + fft_n_real = self.model_map.focus(), + fft_m_real = self.model_map.all(), sites_cart = flex.vec3_double([site_cart]), site_radii = flex.double([self.radius])) cc = flex.linear_correlation( - x=self.map_1.select(sel), - y=self.map_2.select(sel)).coefficient() - value_2 = self.map_2.eight_point_interpolation(site_frac) + x=self.model_map.select(sel), + y=self.data_map.select(sel)).coefficient() + value_2 = self.data_map.eight_point_interpolation(site_frac) result = cc > min_cc and value_2 > min_value*atom.occ return group_args(result = result, cc=cc, value_2=value_2) @@ -291,7 +339,9 @@ def fix_altlocs_and_filter(model, dist_min=1.8, fix_only=False): # skip = False for j in selection_around_ai: - agj = atoms[j].parent() + aj = atoms[j] + if aj.element_is_hydrogen(): continue + agj = aj.parent() if(agj.altloc in [' ', '']): if(get_class(name=agj.resname) != "common_water"): remove_sel.extend(agi.atoms().extract_i_seq()) @@ -364,6 +414,7 @@ def filter_by_distance(model, dist_min=1.8, dist_max=3.2): for j in selection_shell: if not interaction_selection[j]: continue aj = atoms[j] + if aj.element_is_hydrogen(): continue agj = aj.parent() altloc_j = agj.altloc.strip() if altloc_i=="" or altloc_j=="": found = True @@ -452,11 +503,14 @@ def _assert_same_model(self): eps=1.e-3) def _get_maps(self): + p = self.params self._maps = maps( - fmodel = self.fmodel, - map_0_type = self.params.primary_map_type, - map_1_type = self.params.secondary_map_and_map_cc_filter.cc_map_1_type, - map_2_type = self.params.secondary_map_and_map_cc_filter.cc_map_2_type) + fmodel = self.fmodel, + model = self.model, + mask_atoms_selection = p.mask_atoms_selection, + difference_map_type = p.primary_map_type, + model_map_type = p.secondary_map_and_map_cc_filter.cc_map_1_type, + data_map_type = p.secondary_map_and_map_cc_filter.cc_map_2_type) def _filter_dist_fix_altlocs(self): if self.params.include_altlocs: @@ -538,7 +592,7 @@ def _find_peaks(self): assert self.params.primary_map_type is not None self._peaks = find_peaks.manager( xray_structure = self.fmodel.xray_structure, - map_data = self._maps.map_0, # diff-map + map_data = self._maps.difference_map, # diff-map map_cutoff = self.params.primary_map_cutoff, params = self.find_peaks_params, log = null_out()).peaks_mapped() @@ -646,7 +700,7 @@ def refine_oat(self): # r_start, r_omit, r_final, oo.rw_best), "|", oo.o_best, oo.b_best) self.model.adopt_xray_structure( xray_structure = self.fmodel.xray_structure) - print(" ADP (water only), final r_work=%6.4f r_free=%6.4f"%( + print(" ADP+occupancy (water only), OAT, final r_work=%6.4f r_free=%6.4f"%( self.fmodel.r_work(), self.fmodel.r_free()), file=self.log) # if(self.params.refine_adp and self.params.refine_occupancies and @@ -660,7 +714,7 @@ def refine_oat(self): log = self.log) self.model.adopt_xray_structure( xray_structure = self.fmodel.xray_structure) - print(" ADP (water only), final r_work=%6.4f r_free=%6.4f"%( + print(" ADP+occupancy (water only), MIN, final r_work=%6.4f r_free=%6.4f"%( self.fmodel.r_work(), self.fmodel.r_free()), file=self.log) def _correct_drifted_waters(self): @@ -678,7 +732,7 @@ def _correct_drifted_waters(self): find_peaks_params_drifted.peak_search.min_cross_distance=0.5 peaks = find_peaks.manager( xray_structure = self.fmodel.xray_structure, - map_data = self._maps.map_2, + map_data = self._maps.data_map, map_cutoff = map_cutoff, params = find_peaks_params_drifted, log = null_out()).peaks_mapped() From 270ce72886e92441b00f3c1d442098c98eaa5232 Mon Sep 17 00:00:00 2001 From: terwill Date: Mon, 6 May 2024 16:19:17 -0600 Subject: [PATCH 421/748] Add estimate of ratio of deviations to sigmas --- .../validation/holton_geometry_validation.py | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 61fbce2f5e..85f3b31ca3 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -87,6 +87,7 @@ def holton_geometry_validation(dm = None, clashscore_ideal_dist = 3, # Ideal distance in LJ for clashscore result lj_dist_that_yields_zero = 6, # Distance for modified LJ to cross zero n_random = 20, + sd_to_use = 3, softPnna_params = group_args(group_args_type = 'softPnna_params', y0= 1, a2= -0.0192266, @@ -497,6 +498,7 @@ def analyze_geometry_values(info, randomize = False): keys = list(info.geometry_results.keys()) keys.sort() sum_energy = 0.0 + dev_list = flex.double() for key in keys: result = info.geometry_results[key] result.pnna = None @@ -554,6 +556,10 @@ def analyze_geometry_values(info, randomize = False): continue # nothing to do + if result.name not in ['NONBOND']: + # leave NONBOND out because FULL_NONBOND has all + dev_list.extend(flex.sqrt(values.select(values > 0))) + if info.overall_max_energy is not None: energy = max(0, min(info.overall_max_energy, result.worst_residual)) elif result.worst_residual is not None: @@ -595,6 +601,18 @@ def analyze_geometry_values(info, randomize = False): info.sum_energy = sum_energy + # Get percentile-based spread + from libtbx.math_utils import percentile_based_spread + if info.sd_to_use == 3: + info.pbs_included = 0.9974 + elif info.sd_to_use == 2: + info.pbs_included = 0.95 + else: + info.sd_to_use = 1 + info.pbs_included = 0.68 + info.pbs = percentile_based_spread(dev_list, + pbs_fraction = info.pbs_included) / info.sd_to_use + def randomize_result(info, result): if result.name == 'CLASH': randomize_clash(info, result) @@ -706,12 +724,20 @@ def print_results(info, by_category_only = False): info.ignore_bond_lengths_with_h_removed), file = info.log) print(file = info.log) + + dev_to_sigma = info.pbs if info.pbs else None + if dev_to_sigma: + print("Ratio of geometry deviations to sigmas (excluding worst "+ + "%.1f%%): %.2f " %( + 100*(1.-info.pbs_included),dev_to_sigma), file = info.log) + if hasattr(info,'sum_random_energy'): print("Expected energy for ideal structure with normal dist "+ - "of errors: %.1f +/- %.1f" %( + "of errors: %.2f +/- %.2f" %( info.sum_random_energy, info.random_energy_sd), file = info.log) - print("Overall geometry energy for %s: %.4f\n" %(info.filename, + + print("Overall geometry energy: %10.2f\n" %( info.sum_energy), file = info.log) def filter_geometry_results(info): From c7b9e30483f103f9a2604d38b06628f5a49c822c Mon Sep 17 00:00:00 2001 From: Pavel Date: Mon, 6 May 2024 18:01:50 -0700 Subject: [PATCH 422/748] Work on altlocs conditionally --- mmtbx/solvent/ordered_solvent.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/mmtbx/solvent/ordered_solvent.py b/mmtbx/solvent/ordered_solvent.py index 0572e72548..bc33d29f65 100644 --- a/mmtbx/solvent/ordered_solvent.py +++ b/mmtbx/solvent/ordered_solvent.py @@ -378,7 +378,8 @@ def get_sphere_selection( selection_around_i_seq.remove(i_seq) return selection_around_i_seq -def filter_by_distance(model, dist_min=1.8, dist_max=3.2): +def filter_by_distance(model, fix_altlocs_and_filter_was_run, dist_min=1.8, + dist_max=3.2): interaction_selection = model.selection( map_to_water.selection_string_interaction) sps = model.crystal_symmetry().special_position_settings() @@ -407,8 +408,9 @@ def filter_by_distance(model, dist_min=1.8, dist_max=3.2): aj = atoms[j] altloc_j = aj.parent().altloc d = ai.distance(aj) - if(d0 and len(altloc_j)>0 + if fix_altlocs_and_filter_was_run: + if(d0 and len(altloc_j)>0 # Check water inside shell dist_min < dist < dist_max found = False for j in selection_shell: @@ -518,9 +520,10 @@ def _filter_dist_fix_altlocs(self): model = self.model, dist_min = self.params.dist_min) self.model = filter_by_distance( - model = self.model, - dist_min = self.params.dist_min, - dist_max = self.params.dist_max) + model = self.model, + fix_altlocs_and_filter_was_run = self.params.include_altlocs, + dist_min = self.params.dist_min, + dist_max = self.params.dist_max) def _filter_q_b(self): self._filter(filter_occ=True, filter_adp=True) @@ -672,6 +675,7 @@ def _add_new_solvent(self): ### def refine_oat(self): + if self.new_solvent_selection is None: return if(self.params.refine_oat and self.new_solvent_selection.count(True)>0): from phenix.programs import oat from cctbx import adptbx From 1a4dfda1ba88a0fdfefe25dc8b5b2ae18a539314 Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Mon, 6 May 2024 18:03:47 -0700 Subject: [PATCH 423/748] This parameter does not exist any more --- mmtbx/solvent/ensemble_ordered_solvent.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mmtbx/solvent/ensemble_ordered_solvent.py b/mmtbx/solvent/ensemble_ordered_solvent.py index 92e32108c1..1582a4dfe8 100644 --- a/mmtbx/solvent/ensemble_ordered_solvent.py +++ b/mmtbx/solvent/ensemble_ordered_solvent.py @@ -263,7 +263,7 @@ def __init__(self, fmodel, new_scatterers = flex.xray_scatterer( peaks_fo_fc.sites.size(), xray.scatterer(occupancy = self.params.occupancy, - b = self.params.b_iso, + b = 20, scattering_type = self.params.scattering_type, label = 'HOH')) new_scatterers.set_sites(peaks_fo_fc.sites) @@ -404,7 +404,7 @@ def find_peaks(self, map_type, map_cutoff): log = self.log) def add_new_solvent(self): - b_solv = self.params.b_iso + b_solv = 20 new_scatterers = flex.xray_scatterer( self.sites.size(), xray.scatterer(occupancy = self.params.occupancy, From 38c81ffbc93437255617cf8723755cb8abed8342 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 6 May 2024 15:52:05 -0700 Subject: [PATCH 424/748] New test and safeguarding. --- iotbx/pdb/mmcif.py | 6 +++- iotbx/regression/tst_mmcif_input.py | 55 +++++++++++++++++++++++++++++ iotbx/run_tests.py | 1 + 3 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 iotbx/regression/tst_mmcif_input.py diff --git a/iotbx/pdb/mmcif.py b/iotbx/pdb/mmcif.py index 3d78b04086..2455a88954 100644 --- a/iotbx/pdb/mmcif.py +++ b/iotbx/pdb/mmcif.py @@ -473,7 +473,11 @@ def title_section(self): def extract_header_year(self): yyyymmdd = self.deposition_date() if yyyymmdd is not None: - return int(yyyymmdd[:4]) + try: + return int(yyyymmdd[:4]) + except ValueError: + raise Sorry("Cannot extract year of deposition from mmCIF file: '%s'" % yyyymmdd ) + def deposition_date(self, us_style=True): # date format: yyyy-mm-dd diff --git a/iotbx/regression/tst_mmcif_input.py b/iotbx/regression/tst_mmcif_input.py new file mode 100644 index 0000000000..769de20c0c --- /dev/null +++ b/iotbx/regression/tst_mmcif_input.py @@ -0,0 +1,55 @@ +from __future__ import absolute_import, division, print_function +import iotbx.pdb + +cif_str = """\ +data_1YJP +_cell.entry_id 1YJP +_cell.length_a 21.937 +_cell.length_b 4.866 +_cell.length_c 23.477 +_cell.angle_alpha 90.00 +_cell.angle_beta 107.08 +_cell.angle_gamma 90.00 +_cell.Z_PDB 2 +_cell.pdbx_unique_axis ? +_pdbx_database_status.recvd_initial_deposition_date 2005-01-15 +# _pdbx_database_status.recvd_initial_deposition_date ? +loop_ +_atom_site.group_PDB +_atom_site.id +_atom_site.type_symbol +_atom_site.label_atom_id +_atom_site.label_alt_id +_atom_site.label_comp_id +_atom_site.label_asym_id +_atom_site.label_entity_id +_atom_site.label_seq_id +_atom_site.pdbx_PDB_ins_code +_atom_site.Cartn_x +_atom_site.Cartn_y +_atom_site.Cartn_z +_atom_site.occupancy +_atom_site.B_iso_or_equiv +_atom_site.pdbx_formal_charge +_atom_site.auth_seq_id +_atom_site.auth_comp_id +_atom_site.auth_asym_id +_atom_site.auth_atom_id +_atom_site.pdbx_PDB_model_num +ATOM 1 N N . GLY A 1 1 ? -9.009 4.612 6.102 1.00 16.77 ? 1 GLY A N 1 +ATOM 2 C CA . GLY A 1 1 ? -9.052 4.207 4.651 1.00 16.57 ? 1 GLY A CA 1 +ATOM 3 C C . GLY A 1 1 ? -8.015 3.140 4.419 1.00 16.16 ? 1 GLY A C 1 +ATOM 4 O O . GLY A 1 1 ? -7.523 2.521 5.381 1.00 16.78 ? 1 GLY A O 1 +""" + + +def exercise_extract_header_year(prefix="iotbx_tst_mmcif_segids"): + cif_inp = iotbx.pdb.input(lines=cif_str, source_info=None) + # print(cif_inp.deposition_date()) + # print(cif_inp.extract_header_year()) + assert cif_inp.deposition_date() == "2005-01-15" + assert cif_inp.extract_header_year() == 2005 + + +if __name__ == "__main__": + exercise_extract_header_year() diff --git a/iotbx/run_tests.py b/iotbx/run_tests.py index 652964b5a6..55e290475d 100644 --- a/iotbx/run_tests.py +++ b/iotbx/run_tests.py @@ -99,6 +99,7 @@ "$D/regression/tst_bioinformatics.py", "$D/regression/tst_box_around_molecule.py", "$D/regression/tst_mmcif_segids.py", + "$D/regression/tst_mmcif_input.py", "$D/regression/tst_hierarchy_forward_compatible_pdb.py", "$D/regression/tst_map_model_manager_cif.py", "$D/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry_cif.py", From 2f88f5b8e9458a95ae2584f9a19a1911b44b7143 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 7 May 2024 10:36:53 -0700 Subject: [PATCH 425/748] More permissive behavior with test --- iotbx/pdb/mmcif.py | 3 ++- iotbx/regression/tst_mmcif_input.py | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/iotbx/pdb/mmcif.py b/iotbx/pdb/mmcif.py index 2455a88954..cc2712c869 100644 --- a/iotbx/pdb/mmcif.py +++ b/iotbx/pdb/mmcif.py @@ -476,7 +476,8 @@ def extract_header_year(self): try: return int(yyyymmdd[:4]) except ValueError: - raise Sorry("Cannot extract year of deposition from mmCIF file: '%s'" % yyyymmdd ) + pass + return None def deposition_date(self, us_style=True): diff --git a/iotbx/regression/tst_mmcif_input.py b/iotbx/regression/tst_mmcif_input.py index 769de20c0c..650a5c6d23 100644 --- a/iotbx/regression/tst_mmcif_input.py +++ b/iotbx/regression/tst_mmcif_input.py @@ -13,7 +13,6 @@ _cell.Z_PDB 2 _cell.pdbx_unique_axis ? _pdbx_database_status.recvd_initial_deposition_date 2005-01-15 -# _pdbx_database_status.recvd_initial_deposition_date ? loop_ _atom_site.group_PDB _atom_site.id @@ -50,6 +49,14 @@ def exercise_extract_header_year(prefix="iotbx_tst_mmcif_segids"): assert cif_inp.deposition_date() == "2005-01-15" assert cif_inp.extract_header_year() == 2005 + # now the same but with ? + + cif_str_2 = cif_str.replace('2005-01-15', '?') + cif_inp_2 = iotbx.pdb.input(lines=cif_str_2, source_info=None) + # print(cif_inp_2.deposition_date()) + # print(cif_inp_2.extract_header_year()) + assert cif_inp_2.deposition_date() == '?' + assert cif_inp_2.extract_header_year() == None if __name__ == "__main__": exercise_extract_header_year() From 80de27e7e1fab29c6cd51e1f9ca30b9a18558a33 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 7 May 2024 15:02:57 -0600 Subject: [PATCH 426/748] Add get_model to match get_pdb_hierarchy --- iotbx/pdb/utils.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/iotbx/pdb/utils.py b/iotbx/pdb/utils.py index 7dbadde321..ec2455a5d4 100644 --- a/iotbx/pdb/utils.py +++ b/iotbx/pdb/utils.py @@ -320,7 +320,7 @@ def check_for_missing_elements(hierarchy, file_name = None): "Up to 10 listed below: \n%s" % ("\n".join(missing_list[:10]))) def get_pdb_info(text = None, file_name = None, lines = None, - check_pseudo = False, return_pdb_hierarchy = False, + check_pseudo = False, return_group_args = False, allow_incorrect_spacing = False): ''' Get a pdb_input object from pdb or mmcif file, construct a @@ -353,9 +353,20 @@ def get_pdb_hierarchy(text=None, file_name = None, check_pseudo = check_pseudo, return_pdb_hierarchy = True, allow_incorrect_spacing = allow_incorrect_spacing) +def get_model(text=None, file_name = None, + lines = None, check_pseudo = None, + allow_incorrect_spacing = False): + ''' Get pdb_input object and construct model object. + ''' + return get_pdb_input(text = text, file_name = file_name, lines = lines, + check_pseudo = check_pseudo, return_model= True, + allow_incorrect_spacing = allow_incorrect_spacing) + def get_pdb_input(text = None, file_name = None, lines = None, - check_pseudo = False, return_pdb_hierarchy = False, + check_pseudo = False, + return_pdb_hierarchy = False, + return_model = False, return_group_args = False, allow_incorrect_spacing = False): @@ -401,9 +412,13 @@ def get_pdb_input(text = None, file_name = None, lines = None, elif return_pdb_hierarchy: return ph + elif return_model: + return ph.as_model_manager(crystal_symmetry = pdb_inp.crystal_symmetry()) else: return pdb_inp + + def set_element_ignoring_spacings(hierarchy): ''' Set missing elements ignoring spacings. This allows reading a PDB file where there are no elements given and the From 1ca52a5fd950fbfe72d7e2d4bb9c6f5705b3e54f Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Tue, 7 May 2024 15:12:53 -0700 Subject: [PATCH 427/748] bug fix in data.py (update only selected); redo test for occ refinement, extend to updated water --- mmtbx/refinement/data.py | 11 +++++------ mmtbx/refinement/occupancies.py | 25 ++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/mmtbx/refinement/data.py b/mmtbx/refinement/data.py index a759d99eea..5e4627659e 100644 --- a/mmtbx/refinement/data.py +++ b/mmtbx/refinement/data.py @@ -24,17 +24,16 @@ def __init__(self, selection = selection.iselection() sc = self.fmodel.xray_structure.scatterers() self.size = sc.size() - if (self.sites_cart): sc.flags_set_grad_site(iselection = selection) - elif(self.u_iso): sc.flags_set_grad_u_iso(iselection = selection) + if (self.sites_cart): sc.flags_set_grad_site( iselection = selection) + elif(self.u_iso): sc.flags_set_grad_u_iso( iselection = selection) elif(self.occupancy): sc.flags_set_grad_occupancy(iselection = selection) def update(self, x): + xrs = self.fmodel.xray_structure if (self.sites_cart): pass - elif(self.u_iso): - self.fmodel.xray_structure.set_u_iso(values = x) - elif(self.occupancy): - self.fmodel.xray_structure.set_occupancies(value=x) + elif(self.u_iso): xrs.set_u_iso( values=x, selection=self.selection) + elif(self.occupancy): xrs.set_occupancies(value =x, selection=self.selection) self.fmodel.update_xray_structure(update_f_calc = True) self.tg = self.target_functor_xray(compute_gradients = True) diff --git a/mmtbx/refinement/occupancies.py b/mmtbx/refinement/occupancies.py index 6a060305e2..d2f97608a5 100644 --- a/mmtbx/refinement/occupancies.py +++ b/mmtbx/refinement/occupancies.py @@ -438,13 +438,36 @@ def occupancy_selections( iselection = True, allow_empty_selection = True, one_selection_array = True) + def flatten(lst): + flat_list = [] + for item in lst: + if isinstance(item, list): + flat_list.extend(flatten(item)) + else: + flat_list.append(item) + return flat_list + occ_groups_of_more_than_one = [] + for g in result: + if len(g)>1: + occ_groups_of_more_than_one.extend( flatten(g) ) + water_selection = list(water_selection) + wocc = model.get_hierarchy().atoms().extract_occ() + wsel = model.solvent_selection().iselection() + wremove = [] + for i in wsel: + if wocc[i]<1.e-6: + water_selection.remove(i) + if i in occ_groups_of_more_than_one: + water_selection.remove(i) result = add_occupancy_selection( result = result, size = model.get_number_of_atoms(), - selection = water_selection, + selection = flex.size_t(water_selection), hd_special = None) + list_3d_as_bool_selection( list_3d=result, size=model.get_number_of_atoms()) + if(len(result) == 0): result = None if(as_flex_arrays and result is not None): result_ = [] From 3ad1922ced69a94fa9cd7e406dbe20b132ef3feb Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Tue, 7 May 2024 19:22:48 -0700 Subject: [PATCH 428/748] More tweaking to accomodate changes in water picking --- mmtbx/refinement/tst_occupancy_selections.py | 6 +- mmtbx/refinement/wrappers.py | 80 ++++++++++---------- mmtbx/solvent/ordered_solvent.py | 1 + 3 files changed, 46 insertions(+), 41 deletions(-) diff --git a/mmtbx/refinement/tst_occupancy_selections.py b/mmtbx/refinement/tst_occupancy_selections.py index 96a2d60475..6a52d3d5ae 100644 --- a/mmtbx/refinement/tst_occupancy_selections.py +++ b/mmtbx/refinement/tst_occupancy_selections.py @@ -82,7 +82,7 @@ def exercise_00(verbose): as_flex_arrays = False) res = extract_serials(model.get_atoms(), res) base_21_23 = target[:] - target.extend([[[18]], [[19]], [[20]], [[22]]]) + target.extend([[[18]], [[19]], [[20]]]) assert approx_equal(res, target) # 1 res = occupancy_selections( @@ -99,7 +99,7 @@ def exercise_00(verbose): as_flex_arrays = False, other_individual_selection_strings = ['resseq 0 and not (altloc A or altloc B)']) res = extract_serials(model.get_atoms(), res) - target.extend([[[18]], [[19]], [[20]], [[22]]]) + target.extend([[[18]], [[19]], [[20]]]) assert approx_equal(res, target) # 2 other_constrained_groups = make_up_other_constrained_groups_obj( @@ -120,7 +120,7 @@ def exercise_00(verbose): as_flex_arrays = False, other_constrained_groups = other_constrained_groups) res = extract_serials(model.get_atoms(), res) - target.extend([[[18]], [[19]], [[20]], [[22]]]) + target.extend([[[18]], [[19]], [[20]]]) assert approx_equal(res, target) # 3 other_constrained_groups = make_up_other_constrained_groups_obj( diff --git a/mmtbx/refinement/wrappers.py b/mmtbx/refinement/wrappers.py index 27077da672..9f3c92271d 100644 --- a/mmtbx/refinement/wrappers.py +++ b/mmtbx/refinement/wrappers.py @@ -15,6 +15,8 @@ class unrestrained_qb_fsr(object): def __init__(self, fmodel, selection, + refine_q = True, + refine_b = True, macro_cycles=3, max_iterations=50, q_min = 0., @@ -25,42 +27,44 @@ def __init__(self, adopt_init_args(self, locals()) for micro_cycle in range(macro_cycles): # Occupancy - data = mmtbx.refinement.data.fs( - fmodel = fmodel, occupancy=True, selection=selection) - x = fmodel.xray_structure.scatterers().extract_occupancies() - lower_bound = x.deep_copy() - lower_bound.set_selected(selection, q_min) - upper_bound = x.deep_copy() - upper_bound.set_selected(selection, q_max) - calculator = calculators.individual( - data = data, - x = x, - lower_bound = lower_bound, - upper_bound = upper_bound, - bound_flags = flex.int(x.size(), 2)) - minimized = minimizers.lbfgsb( - calculator = calculator, - max_iterations = max_iterations) - if log is not None: - print("occ: r_work=%6.4f r_free=%6.4f"%( - fmodel.r_work(), fmodel.r_free()), file = log) + if refine_q: + data = mmtbx.refinement.data.fs( + fmodel = fmodel, occupancy=True, selection=selection) + x = fmodel.xray_structure.scatterers().extract_occupancies() + lower_bound = x.deep_copy() + lower_bound.set_selected(selection, q_min) + upper_bound = x.deep_copy() + upper_bound.set_selected(selection, q_max) + calculator = calculators.individual( + data = data, + x = x, + lower_bound = lower_bound, + upper_bound = upper_bound, + bound_flags = flex.int(x.size(), 2)) + minimized = minimizers.lbfgsb( + calculator = calculator, + max_iterations = max_iterations) + if log is not None: + print("occ: r_work=%6.4f r_free=%6.4f"%( + fmodel.r_work(), fmodel.r_free()), file = log) # ADP - data = mmtbx.refinement.data.fs( - fmodel = fmodel, u_iso=True, selection=selection) - x = fmodel.xray_structure.extract_u_iso_or_u_equiv() - lower_bound = x.deep_copy() - lower_bound.set_selected(selection, adptbx.b_as_u(b_min)) - upper_bound = x.deep_copy() - upper_bound.set_selected(selection, adptbx.b_as_u(b_max)) - calculator = calculators.individual( - data = data, - x = x, - lower_bound = lower_bound, - upper_bound = upper_bound, - bound_flags = flex.int(x.size(), 2)) - minimized = minimizers.lbfgsb( - calculator = calculator, - max_iterations = max_iterations) - if log is not None: - print("adp: r_work=%6.4f r_free=%6.4f"%( - fmodel.r_work(), fmodel.r_free()), file = log) + if refine_b: + data = mmtbx.refinement.data.fs( + fmodel = fmodel, u_iso=True, selection=selection) + x = fmodel.xray_structure.extract_u_iso_or_u_equiv() + lower_bound = x.deep_copy() + lower_bound.set_selected(selection, adptbx.b_as_u(b_min)) + upper_bound = x.deep_copy() + upper_bound.set_selected(selection, adptbx.b_as_u(b_max)) + calculator = calculators.individual( + data = data, + x = x, + lower_bound = lower_bound, + upper_bound = upper_bound, + bound_flags = flex.int(x.size(), 2)) + minimized = minimizers.lbfgsb( + calculator = calculator, + max_iterations = max_iterations) + if log is not None: + print("adp: r_work=%6.4f r_free=%6.4f"%( + fmodel.r_work(), fmodel.r_free()), file = log) diff --git a/mmtbx/solvent/ordered_solvent.py b/mmtbx/solvent/ordered_solvent.py index bc33d29f65..a7af6b177e 100644 --- a/mmtbx/solvent/ordered_solvent.py +++ b/mmtbx/solvent/ordered_solvent.py @@ -715,6 +715,7 @@ def refine_oat(self): selection = self.new_solvent_selection, q_min = 0.004, b_max = 60, + b_min = self.params.b_iso_min, log = self.log) self.model.adopt_xray_structure( xray_structure = self.fmodel.xray_structure) From c7dc5de7d17177340393749077c71af8ba233846 Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Wed, 8 May 2024 09:40:23 -0700 Subject: [PATCH 429/748] Updates to match new water picking --- mmtbx/refinement/occupancies.py | 14 ++++++++------ mmtbx/refinement/tst_occupancy_selections.py | 2 +- mmtbx/solvent/ordered_solvent.py | 10 +--------- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/mmtbx/refinement/occupancies.py b/mmtbx/refinement/occupancies.py index d2f97608a5..98a4bac6e6 100644 --- a/mmtbx/refinement/occupancies.py +++ b/mmtbx/refinement/occupancies.py @@ -432,6 +432,14 @@ def occupancy_selections( if(len(cg_sel) > 0): result.append(cg_sel) if(add_water): + + if (constrain_correlated_3d_groups) and (len(result) > 0): + result = assemble_constraint_groups_3d( + xray_structure=model.get_xray_structure(), + pdb_atoms=model.get_atoms(), + constraint_groups=result, + log=log) + water_selection = get_atom_selections( model = model, selection_strings = ['water'], @@ -477,12 +485,6 @@ def flatten(lst): result__.append(flex.size_t(sel)) result_.append(result__) result = result_ - if (constrain_correlated_3d_groups) and (len(result) > 0): - result = assemble_constraint_groups_3d( - xray_structure=model.get_xray_structure(), - pdb_atoms=model.get_atoms(), - constraint_groups=result, - log=log) return result def occupancy_regroupping(pdb_hierarchy, cgs): diff --git a/mmtbx/refinement/tst_occupancy_selections.py b/mmtbx/refinement/tst_occupancy_selections.py index 6a52d3d5ae..da4a26e17c 100644 --- a/mmtbx/refinement/tst_occupancy_selections.py +++ b/mmtbx/refinement/tst_occupancy_selections.py @@ -1205,7 +1205,7 @@ def prepare_correlated_occupancy_inputs( HETATM 84 O HOH A 9 10.431 1.858 3.216 1.00 19.71 O HETATM 85 O HOH A 10 -11.286 1.756 -1.468 1.00 17.08 O HETATM 86 O AHOH A 11 11.808 4.179 9.970 0.60 23.99 O -HETATM 87 O HOH A 12 13.605 1.327 9.198 1.00 26.17 O +HETATM 87 O AHOH A 12 13.605 1.327 9.198 0.60 26.17 O HETATM 88 O HOH A 13 -2.749 3.429 10.024 1.00 39.15 O HETATM 89 O HOH A 14 -1.500 0.682 10.967 1.00 43.49 O TER diff --git a/mmtbx/solvent/ordered_solvent.py b/mmtbx/solvent/ordered_solvent.py index a7af6b177e..9f5ffdea89 100644 --- a/mmtbx/solvent/ordered_solvent.py +++ b/mmtbx/solvent/ordered_solvent.py @@ -103,9 +103,6 @@ def get_unique_altloc(exclude): mask_atoms_selection = protein and (name CA or name CB or name N or name C or name O) .type = str .help = Mask macromolecule atoms in peak picking map - keep_existing = False - .type = bool - .help = Keep existing in the model water include_altlocs = False .type = bool .help = Search for water with altlocs @@ -456,9 +453,6 @@ def __init__(self, fmodel, self.n_water = None self.model_size_init = self.model.size() self.new_solvent_selection = None - self.existing_solvent = None - if(self.params.keep_existing): - self.existing_solvent = self.model.solvent_selection().iselection() # self._call(msg="Start", func=None) self._call(msg="Filter (dist)", func=self._filter_dist_fix_altlocs) @@ -556,8 +550,6 @@ def _filter(self, if(atom.element.strip().upper()=="O"): has_oxygen = True if(atom.element_is_hydrogen()): continue i_seq = atom.i_seq - if(self.params.keep_existing and i_seq in self.existing_solvent): - continue # Occupancy if filter_occ: if(atom.occ > self.params.occupancy_max or @@ -725,7 +717,7 @@ def refine_oat(self): def _correct_drifted_waters(self): if(self.params.mode != "filter_only"): return if(not self.params.correct_drifted_waters): return - sol_sel = self.model.solvent_selection(offset=self.existing_solvent) + sol_sel = self.model.solvent_selection() hd_sel = self.model.get_hd_selection() hd_sol = sol_sel & hd_sel if(hd_sol.count(True)>0): return From aba8ae5e702bc1011eaca60e86aed54b06d912af Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 8 May 2024 10:07:50 -0700 Subject: [PATCH 430/748] Check for nan when reading in mrc maps --- iotbx/mrcfile/__init__.py | 6 +++++- iotbx/regression/tst_mrc_io.py | 25 +++++++++++++++++++++++++ iotbx/run_tests.py | 1 + 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 iotbx/regression/tst_mrc_io.py diff --git a/iotbx/mrcfile/__init__.py b/iotbx/mrcfile/__init__.py index f3f4d6d26c..ad0738f7d9 100644 --- a/iotbx/mrcfile/__init__.py +++ b/iotbx/mrcfile/__init__.py @@ -11,7 +11,7 @@ import numpy as np from six.moves import range from six.moves import zip - +import math # ====== HARD-WIRED DEFAULTS SEE DOC STRINGS BELOW FOR INFO ===== @@ -230,6 +230,10 @@ def read_map_file(self, file_name=None, map_all=self.data.all() + # Check if self.data contains 'nan' + if math.isnan(flex.sum(self.data)): + raise Sorry("Input map file contains 'nan': not a valid map file") + # Set self._crystal_symmetry which is crystal symmetry of part of map # that is present diff --git a/iotbx/regression/tst_mrc_io.py b/iotbx/regression/tst_mrc_io.py new file mode 100644 index 0000000000..4cc44666df --- /dev/null +++ b/iotbx/regression/tst_mrc_io.py @@ -0,0 +1,25 @@ +from __future__ import absolute_import, division, print_function +import iotbx.mrcfile +from cctbx.array_family import flex +from cctbx import crystal +from libtbx.utils import Sorry +import math + +def run(): + m = flex.double(flex.grid(10,20,30), 1) + m[1,2,3] = float('nan') + assert math.isnan(m[1,2,3]) + cs = crystal.symmetry((10,20,30, 90,90,90), "P1") + iotbx.mrcfile.write_ccp4_map( + file_name = "map_with_nan.mrc", + unit_cell = cs.unit_cell(), + space_group = cs.space_group(), + map_data = m, + labels = flex.std_string(["Some text"])) + exception = None + try: o = iotbx.mrcfile.map_reader(file_name="map_with_nan.mrc") + except Sorry as e: exception = str(e) + assert exception == "Input map file contains 'nan': not a valid map file" + +if(__name__ == "__main__"): + run() diff --git a/iotbx/run_tests.py b/iotbx/run_tests.py index 55e290475d..b0844df288 100644 --- a/iotbx/run_tests.py +++ b/iotbx/run_tests.py @@ -4,6 +4,7 @@ import libtbx.load_env tst_list_base = [ + "$D/regression/tst_mrc_io.py", "$D/regression/tst_wildcard.py", "$D/gui_tools/tst.py", "$D/regression/tst_simple_parser.py", From b28804ff47859c3546e82404dcf1a1cc9e47017b Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Wed, 8 May 2024 10:30:24 -0700 Subject: [PATCH 431/748] fix occupancy groupping for 3D case (Nat's code) --- mmtbx/refinement/occupancies.py | 4 +-- mmtbx/refinement/tst_occupancy_selections.py | 33 +++++++++++--------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/mmtbx/refinement/occupancies.py b/mmtbx/refinement/occupancies.py index 98a4bac6e6..cb08395d74 100644 --- a/mmtbx/refinement/occupancies.py +++ b/mmtbx/refinement/occupancies.py @@ -431,15 +431,15 @@ def occupancy_selections( cg_sel.append(list(sel)) if(len(cg_sel) > 0): result.append(cg_sel) - if(add_water): - if (constrain_correlated_3d_groups) and (len(result) > 0): + if (constrain_correlated_3d_groups) and (len(result) > 0): result = assemble_constraint_groups_3d( xray_structure=model.get_xray_structure(), pdb_atoms=model.get_atoms(), constraint_groups=result, log=log) + if(add_water): water_selection = get_atom_selections( model = model, selection_strings = ['water'], diff --git a/mmtbx/refinement/tst_occupancy_selections.py b/mmtbx/refinement/tst_occupancy_selections.py index da4a26e17c..df157df8fa 100644 --- a/mmtbx/refinement/tst_occupancy_selections.py +++ b/mmtbx/refinement/tst_occupancy_selections.py @@ -1245,23 +1245,26 @@ def exercise_regroup_3d(verbose): "tst_group_correlated_occupancy_start.pdb", "tst_group_correlated_occupancy_in.pdb", ] - for i_file, pdb_file in enumerate(pdb_files): - model = get_model(pdb_file, log) - try : - constraint_groups = occupancy_selections( - model = model, + # + constraint_groups = occupancy_selections( + model = get_model("tst_group_correlated_occupancy_start.pdb", log), constrain_correlated_3d_groups=True, log=null_out()) - except Sorry as s : - if (i_file == 0): - raise - else : - assert ("Inconsistent occupancies" in str(s)), str(s) - else : - if (i_file == 1): - raise Exception_expected - else : - assert (len(constraint_groups) == 1) + for g in constraint_groups: + assert [ [ggg for ggg in gg] for gg in g ] == \ + [[29, 30, 31, 32, 33, 34, 35, 36, 37, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 84, 85], + [38, 39, 40, 41, 42, 43, 44, 45, 46, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80]] + # + sorry_found = False + try: + constraint_groups = occupancy_selections( + model = get_model("tst_group_correlated_occupancy_in.pdb", log), + constrain_correlated_3d_groups=True, + log=null_out()) + except Sorry as s: + assert ("Inconsistent occupancies" in str(s)), str(s) + sorry_found = True + assert sorry_found def run(): verbose = "--verbose" in sys.argv[1:] From 9e388b8d26c90c8977fa09b73bb1f877d1dd2a5b Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Wed, 8 May 2024 10:42:45 -0700 Subject: [PATCH 432/748] remove unused imports --- mmtbx/refinement/tst_occupancy_selections.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/refinement/tst_occupancy_selections.py b/mmtbx/refinement/tst_occupancy_selections.py index df157df8fa..99bd23e6ef 100644 --- a/mmtbx/refinement/tst_occupancy_selections.py +++ b/mmtbx/refinement/tst_occupancy_selections.py @@ -6,7 +6,7 @@ import mmtbx.model import iotbx.pdb import iotbx.phil -from libtbx.test_utils import approx_equal, Exception_expected +from libtbx.test_utils import approx_equal from libtbx.utils import format_cpu_times, null_out, Sorry import libtbx.load_env from six.moves import cStringIO as StringIO From 16349918a3b2f3357af6f52682fbb70e1c7c9865 Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 8 May 2024 15:19:47 -0600 Subject: [PATCH 433/748] Allow cif as wildcard without breaking entire mapping of extensions to file types by duplicating cif --- iotbx/file_reader.py | 6 ++++++ iotbx/regression/tst_file_reader.py | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/iotbx/file_reader.py b/iotbx/file_reader.py index 7f6feaf21f..d05b64b15c 100644 --- a/iotbx/file_reader.py +++ b/iotbx/file_reader.py @@ -94,6 +94,12 @@ def get_wildcard_string(format): assert (format in standard_file_extensions), format wildcards = [ "*.%s" % ext for ext in standard_file_extensions[format] ] + # Add wildcard without breaking other features by having cif in two places + if format == 'pdb': + cif_format = "*.%s" % "cif" + if not cif_format in wildcards: + wildcards.append(cif_format) + wildcard_str = "%s file (%s)|%s" % (standard_file_descriptions[format], ", ".join(wildcards), ";".join(wildcards)) return wildcard_str diff --git a/iotbx/regression/tst_file_reader.py b/iotbx/regression/tst_file_reader.py index 788e5e9ffa..6bd60fdba8 100644 --- a/iotbx/regression/tst_file_reader.py +++ b/iotbx/regression/tst_file_reader.py @@ -449,7 +449,7 @@ def exercise_misc(): assert (file_names == ['foo.pdb','bar.pdb','foo.mtz','bar.mtz','seq.dat']) wc = file_reader.get_wildcard_strings(["hkl","pdb","seq"]) if (sys.platform == "darwin"): - assert (wc == """Reflections file (*.mtz, *.hkl, *.sca, *.cns, *.xplor, *.cv, *.ref, *.fobs)|*.mtz;*.hkl;*.sca;*.cns;*.xplor;*.cv;*.ref;*.fobs|Model file (*.pdb, *.ent)|*.pdb;*.ent|Sequence file (*.fa, *.faa, *.seq, *.pir, *.dat, *.fasta)|*.fa;*.faa;*.seq;*.pir;*.dat;*.fasta|All files (*.*)|*.*""") + assert (wc == """Reflections file (*.mtz, *.hkl, *.sca, *.cns, *.xplor, *.cv, *.ref, *.fobs)|*.mtz;*.hkl;*.sca;*.cns;*.xplor;*.cv;*.ref;*.fobs|Model file (*.pdb, *.ent, *.cif)|*.pdb;*.ent;*.cif|Sequence file (*.fa, *.faa, *.seq, *.pir, *.dat, *.fasta)|*.fa;*.faa;*.seq;*.pir;*.dat;*.fasta|All files (*.*)|*.*""") wc = file_reader.get_wildcard_strings([]) assert (wc == """All files (*.*)|*.*""") From 355f109564ed56826248ef436aa2d5fdfa579f5e Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 8 May 2024 15:05:03 -0700 Subject: [PATCH 434/748] Set file name --- iotbx/pdb/hierarchy.py | 1 + 1 file changed, 1 insertion(+) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index bf71acd0bd..e6f912c1e3 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -1004,6 +1004,7 @@ def as_model_manager(self, crystal_symmetry, mm.set_unit_cell_crystal_symmetry_and_shift_cart( unit_cell_crystal_symmetry = unit_cell_crystal_symmetry, shift_cart = shift_cart) + mm.info().file_name = None return mm def as_dict_of_chain_id_resseq_as_int_residue_names(self): From 9636f3b7e7a983327c0ddcdb24e72d305e195b48 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 23 Apr 2024 10:28:38 -0700 Subject: [PATCH 435/748] water b factors may not be any use --- mmtbx/command_line/water_b_factors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/command_line/water_b_factors.py b/mmtbx/command_line/water_b_factors.py index c74fc8ca26..8a8ed783bc 100644 --- a/mmtbx/command_line/water_b_factors.py +++ b/mmtbx/command_line/water_b_factors.py @@ -1,5 +1,5 @@ from __future__ import absolute_import, division, print_function -# LIBTBX_SET_DISPATCHER_NAME phenix.development.water_b_factors +# LIBTBX_SET_DISPATCHER_NAME mmtbx.development.water_b_factors from iotbx.cli_parser import run_program from mmtbx.programs.water_b_factors import Program From 6a3a67bd16bc14af0a5d8033c738d0a2c9686f3b Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Wed, 8 May 2024 17:20:28 -0700 Subject: [PATCH 436/748] new round of CC including first big batch of 5-letter codes --- iotbx/pdb/modified_aa_names.h | 18 +++++++++++++++++- iotbx/pdb/modified_aa_names.py | 18 +++++++++++++++++- iotbx/pdb/modified_rna_dna_names.h | 7 ++++++- iotbx/pdb/modified_rna_dna_names.py | 7 ++++++- 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/iotbx/pdb/modified_aa_names.h b/iotbx/pdb/modified_aa_names.h index b60c99a137..2966a40e5d 100644 --- a/iotbx/pdb/modified_aa_names.h +++ b/iotbx/pdb/modified_aa_names.h @@ -5,7 +5,7 @@ This file is generated by the following procedure: phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Thu Jan 11 09:02:01 2024 +The date of file generation: Wed May 8 17:01:20 2024 */ #include @@ -471,6 +471,9 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "A02", "A03", "A0G", + "A1ADW", + "A1ADY", + "A1ADZ", "A5R", "A66", "A67", @@ -936,6 +939,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "SAO", "SBD", "SC2", + "SD0", "SD2", "SDR", "SFE", @@ -1044,6 +1048,8 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "YEN", "YNM", "YYA", + "Z50", + "Z9J", "ZAE", "ZAL", "ZFB", @@ -1053,6 +1059,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "ZPR", "ZRA", "ZRG", + "ZRJ", "ZSN", "ZT9", "ZTC", @@ -1251,6 +1258,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "PAS", "PHD", "TAV", + "ZJU", "03Y", // parent is CYS "07O", "08P", @@ -1272,6 +1280,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "85F", "85L", "8JB", + "A1D64", "AEA", "AGT", "BB6", @@ -1393,7 +1402,9 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "VI3", "XCN", "YCM", + "YRV", "ZBZ", + "ZLF", "ZZD", "V53", // parent is ES1 "65T", // parent is FB2 @@ -1410,6 +1421,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "QMM", "QQ8", "YTF", + "ZKO", "11W", // parent is GLU "3GL", "3O3", @@ -1588,6 +1600,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "9TU", "9TX", "9U0", + "A1LWV", "ALY", "API", "APK", @@ -1729,6 +1742,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "7W2", "7XC", "9NF", + "A1H2H", "A3U", "B1F", "B2F", @@ -1977,6 +1991,8 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "54C", "5CW", "6CW", + "A1H2I", + "A1H45", "BTR", "CTE", "E9M", diff --git a/iotbx/pdb/modified_aa_names.py b/iotbx/pdb/modified_aa_names.py index 2cbc1d2137..23ecf4c880 100644 --- a/iotbx/pdb/modified_aa_names.py +++ b/iotbx/pdb/modified_aa_names.py @@ -7,7 +7,7 @@ phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Thu Jan 11 09:02:01 2024 +The date of file generation: Wed May 8 17:01:20 2024 """ from __future__ import absolute_import, division, print_function @@ -469,6 +469,9 @@ "A02" : "?", "A03" : "?", "A0G" : "?", + "A1ADW" : "?", + "A1ADY" : "?", + "A1ADZ" : "?", "A5R" : "?", "A66" : "?", "A67" : "?", @@ -934,6 +937,7 @@ "SAO" : "?", "SBD" : "?", "SC2" : "?", + "SD0" : "?", "SD2" : "?", "SDR" : "?", "SFE" : "?", @@ -1042,6 +1046,8 @@ "YEN" : "?", "YNM" : "?", "YYA" : "?", + "Z50" : "?", + "Z9J" : "?", "ZAE" : "?", "ZAL" : "?", "ZFB" : "?", @@ -1051,6 +1057,7 @@ "ZPR" : "?", "ZRA" : "?", "ZRG" : "?", + "ZRJ" : "?", "ZSN" : "?", "ZT9" : "?", "ZTC" : "?", @@ -1248,6 +1255,7 @@ "PAS" : "D", "PHD" : "D", "TAV" : "D", + "ZJU" : "D", "03Y" : "C", "07O" : "C", "08P" : "C", @@ -1269,6 +1277,7 @@ "85F" : "C", "85L" : "C", "8JB" : "C", + "A1D64" : "C", "AEA" : "C", "AGT" : "C", "BB6" : "C", @@ -1390,7 +1399,9 @@ "VI3" : "C", "XCN" : "C", "YCM" : "C", + "YRV" : "C", "ZBZ" : "C", + "ZLF" : "C", "ZZD" : "C", "ECC" : "Q", "GHG" : "Q", @@ -1405,6 +1416,7 @@ "QMM" : "Q", "QQ8" : "Q", "YTF" : "Q", + "ZKO" : "Q", "11W" : "E", "3GL" : "E", "3O3" : "E", @@ -1582,6 +1594,7 @@ "9TU" : "K", "9TX" : "K", "9U0" : "K", + "A1LWV" : "K", "ALY" : "K", "API" : "K", "APK" : "K", @@ -1723,6 +1736,7 @@ "7W2" : "F", "7XC" : "F", "9NF" : "F", + "A1H2H" : "F", "A3U" : "F", "B1F" : "F", "B2F" : "F", @@ -1970,6 +1984,8 @@ "54C" : "W", "5CW" : "W", "6CW" : "W", + "A1H2I" : "W", + "A1H45" : "W", "BTR" : "W", "CTE" : "W", "E9M" : "W", diff --git a/iotbx/pdb/modified_rna_dna_names.h b/iotbx/pdb/modified_rna_dna_names.h index aa340dc74d..8e502c1e90 100644 --- a/iotbx/pdb/modified_rna_dna_names.h +++ b/iotbx/pdb/modified_rna_dna_names.h @@ -5,7 +5,7 @@ This file is generated by the following procedure: phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Thu Jan 11 09:02:01 2024 +The date of file generation: Wed May 8 17:01:21 2024 */ #include @@ -112,6 +112,8 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "XNY", "Y5P", "YA4", + "YWQ", + "ZF9", "ZHP", "02I", "0DA", @@ -256,6 +258,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "US4", "VET", "WC7", + "WVQ", "X4A", "XAE", "XAR", @@ -344,6 +347,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "LC", "LHH", "LV2", + "M3X", "M4C", "M5M", "MMX", @@ -372,6 +376,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "6HB", "7DA", "8BA", + "A1H3G", "A34", "A35", "A38", diff --git a/iotbx/pdb/modified_rna_dna_names.py b/iotbx/pdb/modified_rna_dna_names.py index 8bf24fdf71..d16d4a472d 100644 --- a/iotbx/pdb/modified_rna_dna_names.py +++ b/iotbx/pdb/modified_rna_dna_names.py @@ -7,7 +7,7 @@ phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Thu Jan 11 09:02:01 2024 +The date of file generation: Wed May 8 17:01:21 2024 """ from __future__ import absolute_import, division, print_function @@ -110,6 +110,8 @@ "XNY" : "?", "Y5P" : "?", "YA4" : "?", + "YWQ" : "?", + "ZF9" : "?", "ZHP" : "?", "02I" : "?", "0DA" : "?", @@ -254,6 +256,7 @@ "US4" : "?", "VET" : "?", "WC7" : "?", + "WVQ" : "?", "X4A" : "?", "XAE" : "?", "XAR" : "?", @@ -342,6 +345,7 @@ "LC" : "C", "LHH" : "C", "LV2" : "C", + "M3X" : "C", "M4C" : "C", "M5M" : "C", "MMX" : "C", @@ -370,6 +374,7 @@ "6HB" : "DA", "7DA" : "DA", "8BA" : "DA", + "A1H3G" : "DA", "A34" : "DA", "A35" : "DA", "A38" : "DA", From 4f1f2294219a439262baaa841a6708256d51f509 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Wed, 8 May 2024 17:23:00 -0700 Subject: [PATCH 437/748] Energy monitor takes charge also --- mmtbx/chemical_components/__init__.py | 2 ++ mmtbx/refinement/energy_monitor.py | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/mmtbx/chemical_components/__init__.py b/mmtbx/chemical_components/__init__.py index 05129ba494..3c351f8dda 100644 --- a/mmtbx/chemical_components/__init__.py +++ b/mmtbx/chemical_components/__init__.py @@ -325,6 +325,8 @@ def get_group(code, split_rna_dna=False, split_l_d=False, verbose=False): 'PEPTIDE-LIKE', ]: return t.lower() + elif t in ['OTHER']: + return t.lower() print(t) assert 0 diff --git a/mmtbx/refinement/energy_monitor.py b/mmtbx/refinement/energy_monitor.py index 4ad4611981..21967c0365 100644 --- a/mmtbx/refinement/energy_monitor.py +++ b/mmtbx/refinement/energy_monitor.py @@ -13,12 +13,12 @@ def _print_energy_in_kcal(e, units): def print_energy_in_kcal(ga): s=[] if ga is None: return s - for d, e, l, b in ga.energies: + for d, e, l, b, c in ga.energies: units=ga.units.lower() if d in ['opt', 'bound']: atoms=b elif d in ['energy', 'strain']: atoms=l - s.append('%-22s %s (atoms %4d) ' % (d, - _print_energy_in_kcal(e, units), atoms)) + s.append('%-22s %s (atoms %4d, charge %2d) ' % (d, + _print_energy_in_kcal(e, units), atoms, c)) return s class energies(list): @@ -42,7 +42,7 @@ def as_string(self, verbose=False): for j, ga in enumerate(gas): if ga: units=ga.units - for d, e, l, b in ga.energies: + for d, e, l, b, c in ga.energies: tmp[i][d]=e t_atoms[i][d]=b rc = print_energy_in_kcal(ga) From 965a4e801c11049821eaba40620fb3f5e2a80917 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Wed, 8 May 2024 17:25:35 -0700 Subject: [PATCH 438/748] Including charge in output, freeze dihedrals on HIS HD1.HE2 --- mmtbx/geometry_restraints/base_qm_manager.py | 30 ++++++- mmtbx/geometry_restraints/mopac_manager.py | 85 ++++++++++--------- .../quantum_restraints_manager.py | 8 +- mmtbx/programs/quantum_interface.py | 40 +++++++-- 4 files changed, 110 insertions(+), 53 deletions(-) diff --git a/mmtbx/geometry_restraints/base_qm_manager.py b/mmtbx/geometry_restraints/base_qm_manager.py index c40b017859..5e9b1e4742 100644 --- a/mmtbx/geometry_restraints/base_qm_manager.py +++ b/mmtbx/geometry_restraints/base_qm_manager.py @@ -232,9 +232,21 @@ def get_opt(self, *args, **kwds): rc=tmp return flex.vec3_double(rc), flex.vec3_double(rc_buffer) + def get_gradients(self): + assert 0 + def get_timings(self, energy=False): return '-' + def get_lines(self, filename=None): + if filename is None: + filename = self.get_log_filename() + assert os.path.exists(filename), 'filename not found %s' % filename + f=open(filename, 'r') + lines=f.read() + del f + return lines + class base_qm_manager(base_manager): def write_input(self, outl): @@ -407,6 +419,9 @@ def get_bound(self, self.preamble = old_preamble return energy, units + def get_gradients(self): + assert 0 + def get_timings(self, energy=None): if not self.times: return '-' f=' Timings : %0.2fs (%ss)' % ( @@ -425,7 +440,7 @@ def _is_atom_for_opt(self, i, atom, optimise_ligand=True, optimise_h=True): opt=0 else: opt=0 - if optimise_h and atom.element in ['H', 'D']: + if optimise_h and atom.element_is_hydrogen(): opt=1 return opt @@ -436,7 +451,14 @@ def guess_bonds(self): for j, atom2 in enumerate(self.atoms): if i==j: continue d2 = dist2(atom1.xyz, atom2.xyz) - if d2<2.5: + d2_limit=2.5 + if atom1.element_is_hydrogen() and atom2.element_is_hydrogen(): + continue + elif atom1.element_is_hydrogen() or atom2.element_is_hydrogen(): + d2_limit=1.3 + elif atom1.element in ['P'] or atom2.element in ['P']: + d2_limit=4 + if d2-1: - read_xyz=True - return rc - def get_cmd(self): cmd = '%s mopac_%s' % ( get_exe(), @@ -164,23 +161,29 @@ def run_cmd(self, redirect_output=False, log=None): ) self.times.append(time.time()-t0) - def read_energy(self, filename=None): - if filename is None: - filename = self.get_log_filename() - f=open(filename, 'r') - lines=f.read() - del f + lines = self.get_lines(filename=filename) # FINAL HEAT OF FORMATION = -132.17152 KCAL/MOL = -553.00562 KJ/MOL for line in lines.splitlines(): if line.find('FINAL HEAT OF FORMATION = ')>-1: self.energy = float(line.split()[5]) self.units = line.split()[6].lower() - # if line.find('TOTAL ENERGY =')>-1: - # self.energy = float(line.split()[3]) - # self.units = line.split()[4] return self.energy, self.units + def read_charge(self, filename=None): + lines = self.get_lines(filename=filename) + # CHARGE ON SYSTEM = + for line in lines.splitlines(): + if line.find('CHARGE ON SYSTEM = ')>-1: + self.charge = float(line.split()[5]) + break + return self.charge + + def read_gradients(self, filename=None): + lines = self.get_lines(filename=filename) + print(lines) + assert 0 + def cleanup(self, level=None, verbose=False): if level=='all': assert 0 diff --git a/mmtbx/geometry_restraints/quantum_restraints_manager.py b/mmtbx/geometry_restraints/quantum_restraints_manager.py index 8bea4520dd..baaec97399 100644 --- a/mmtbx/geometry_restraints/quantum_restraints_manager.py +++ b/mmtbx/geometry_restraints/quantum_restraints_manager.py @@ -976,6 +976,7 @@ def run_jobs(objects, macro_cycle, nproc=1, log=StringIO()): units='' if qmm.program_goal in ['opt']: energy, units = qmm.read_energy() + charge = qmm.read_charge() if 0 : #os.getlogin()=='NWMoriarty': from mmtbx.geometry_restraints import curve_fit_3d key = (ligand_model.get_number_of_atoms(), @@ -987,13 +988,18 @@ def run_jobs(objects, macro_cycle, nproc=1, log=StringIO()): units=xyz_buffer xyz=None xyz_buffer=None + qmm.preamble += '_%s' % qmm.program_goal + if qmm.program_goal in ['bound']: qmm.preamble += '_energy' + charge = qmm.read_charge() + # except: charge=-99 else: assert 0, 'program_goal %s not in list' % qmm.program_goal energies.setdefault(qmr.selection,[]) energies[qmr.selection].append([qmm.program_goal, energy, ligand_model.get_number_of_atoms(), - buffer_model.get_number_of_atoms() + buffer_model.get_number_of_atoms(), + charge, ]) xyzs.append(xyz) xyzs_buffer.append(xyz_buffer) diff --git a/mmtbx/programs/quantum_interface.py b/mmtbx/programs/quantum_interface.py index fcddc4d6d3..6cb16d8f87 100644 --- a/mmtbx/programs/quantum_interface.py +++ b/mmtbx/programs/quantum_interface.py @@ -253,6 +253,9 @@ def qm_restraints_has_selection(params): def get_selection_from_user(hierarchy, include_amino_acids=None, log=None): j=0 opts = [] + if include_amino_acids is not None: + for a,b in enumerate(include_amino_acids): + include_amino_acids[a]=b.upper() for residue_group in hierarchy.residue_groups(): atom_group = residue_group.atom_groups()[0] rc = get_class(atom_group.resname) @@ -382,8 +385,15 @@ def run(self, log=None): self.logger = multi_out() self.logger.register("stdout", sys.stdout) log_filename = '%s.log' % self.data_manager.get_default_output_filename() - log_file = open(log_filename, 'w') - self.logger.register('logfile', log_file) + if self.params.qi.run_qmr: + if os.path.exists(log_filename): + for i in range(1,1000): + tf = log_filename.replace('000', '%03d'% i) + if not os.path.exists(tf): + log_filename=tf + break + log_file = open(log_filename, 'w') + self.logger.register('logfile', log_file) model = self.data_manager.get_model() self.restraint_filenames = [] rc = self.data_manager.get_restraint_names() @@ -536,11 +546,12 @@ def run(self, log=None): rc = self.run_qmr(self.params.qi.format) rc=rc[0] args = [] + cmd = '\n\tphenix.start_coot' for filenames in rc.final_pdbs: print(filenames) args.append(filenames[-1]) - print('args'*10) - print(args) + cmd += ' %s' % args[-1] + print(cmd) os.chdir(qm_work_dir) merge_water(args) return @@ -615,13 +626,19 @@ def run(self, log=None): self.params.qi.iterate_metals)): self.params.qi.qm_restraints.selection=self.params.qi.selection rcs = self.run_qmr(self.params.qi.format) - cmd = '\n\n\tphenix.start_coot %s' % self.data_manager.get_default_model_name() + dmn = self.data_manager.get_default_model_name() + cmd = '\n\n\tphenix.start_coot %s' % dmn for rc in rcs: filenames = getattr(rc, 'final_pdbs', []) if filenames: for f in filenames: for g in f: cmd += ' %s' % os.path.join('qm_work_dir', g) + for r in ['.pdb', '.updated.pdb']: + mf = dmn.replace(r, '_map_coeffs.mtz') + if os.path.exists(mf): + cmd += ' --auto=%s' % mf + break print('%s\n\n' % cmd) if self.params.qi.iterate_NQH: @@ -641,7 +658,7 @@ def run(self, log=None): model = self.data_manager.get_model() fn=self.data_manager.get_default_model_name() self.data_manager.write_model_file(model, - fn.replace('.pdb', '_flipped.pdb'), + fn.replace('.pdb', '_best.pdb'), overwrite=True) if self.params.qi.iterate_metals: @@ -929,13 +946,14 @@ def process_flipped_jobs(self, resname, rc, protonation=None, id_str=None, nproc for i, res in enumerate(rc): for selection, te in res.energies.items(): pass te=te[0] - print(' Energy %d %s : %9.1f %s # ligand atoms : %d # cluster atoms : %d' % ( + print(' Energy %d %s : %9.1f %s # ligand atoms : %d # cluster atoms : %d cluster charge :%3d' % ( i+1, te[0], te[1], res.units, te[2], te[3], + te[4], ), file=self.logger) energies.append(te) units=res.units @@ -973,6 +991,7 @@ def process_flipped_jobs(self, resname, rc, protonation=None, id_str=None, nproc close_result=[] outl = ' %i. %-20s : %12.3f %s ~> %10.2f kcal/mol. H-Bonds : %2d rmsd : %7.2f rotamer "%s"' # outl = '%i|%-20s|%7.5f|%s|%10.2f|%2d|%7.2f|%s' + min_i=None for i, filename in enumerate(filenames): assert os.path.exists(filename), '"%s"' % filename if self.params.qi.run_directory: @@ -1008,6 +1027,7 @@ def process_flipped_jobs(self, resname, rc, protonation=None, id_str=None, nproc update=False if de<1e-3: final_result = outl % args + min_i=i tmp = protonation[i] tmp=tmp.replace('only','') # tmp=tmp.replace('flipped', '') @@ -1022,12 +1042,16 @@ def process_flipped_jobs(self, resname, rc, protonation=None, id_str=None, nproc else: update=i j=i - elif de<6.: + elif de<5.: close_result.append(outl % args) if units.lower()=='dirac': raise Sorry('MOPAC not installed! Please install or update to Python3.') + import shutil + nf = filenames[min_i].replace('%02d_cluster' % (min_i+1), 'best_cluster') + shutil.copy(filenames[min_i], nf) + cmd += '\n\n' print(cmd, file=self.logger) print(pymols, file=self.logger) From 7ddf7699aee544c1bd580f9b553ab52cc9aedfb7 Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Wed, 8 May 2024 17:30:43 -0700 Subject: [PATCH 439/748] simplify weights object --- mmtbx/refinement/minimization.py | 7 +------ mmtbx/refinement/occupancies.py | 7 +------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/mmtbx/refinement/minimization.py b/mmtbx/refinement/minimization.py index b5b1893ac5..34ec9cf4f8 100644 --- a/mmtbx/refinement/minimization.py +++ b/mmtbx/refinement/minimization.py @@ -62,12 +62,7 @@ def __init__(self, fmodels, from phenix.refinement import weight_xray_chem self.weights = weight_xray_chem.weights(wx = 1, wx_scale = 1, - angle_x = None, - wn = 1, - wn_scale = 1, - angle_n = None, - w = 0, - wxn = 1) + w = 0) if(self.collect_monitor): self.monitor = monitor( weights = self.weights, diff --git a/mmtbx/refinement/occupancies.py b/mmtbx/refinement/occupancies.py index cb08395d74..336253d147 100644 --- a/mmtbx/refinement/occupancies.py +++ b/mmtbx/refinement/occupancies.py @@ -135,12 +135,7 @@ def __init__(self, from phenix.refinement import weight_xray_chem self.weights = weight_xray_chem.weights(wx = 1, wx_scale = 1, - angle_x = None, - wn = 1, - wn_scale = 1, - angle_n = None, - w = 0, - wxn = 1) # XXX + w = 0) # XXX self.par_min = self.par_initial.deep_copy() self.x = self.pack(self.par_min) self.n = self.x.size() From c4c68aa44a713dbfdd02270600b306ba8e693d2b Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 8 May 2024 20:03:54 -0700 Subject: [PATCH 440/748] Continue templating and abstracting minimizers --- mmtbx/refinement/calculators.py | 80 +++++++++++++++++++ mmtbx/refinement/data.py | 67 ++++++++++++---- mmtbx/refinement/wrappers.py | 52 ++++++------ .../tst_mmtbx_refinement_wrappers.py | 1 + 4 files changed, 156 insertions(+), 44 deletions(-) diff --git a/mmtbx/refinement/calculators.py b/mmtbx/refinement/calculators.py index 8cb2a6bba1..3e17f18296 100644 --- a/mmtbx/refinement/calculators.py +++ b/mmtbx/refinement/calculators.py @@ -1,5 +1,6 @@ from __future__ import division from libtbx import adopt_init_args +from scitbx.array_family import flex class individual(object): def __init__(self, @@ -42,3 +43,82 @@ def target_and_gradients(self): def compute_functional_and_gradients(self): return self.target_and_gradients() + +class xyz(object): + def __init__(self, + data = None, + restraints = None, + selection = None, + data_weight = 1, + restraints_weight = None, + max_shift = None): + adopt_init_args(self, locals()) + assert isinstance(max_shift, float) + data.set_refine_sites(selection = selection) + x = flex.vec3_double(data.get_x()) + shift = flex.vec3_double(x.size(), [max_shift, max_shift, max_shift]) + lower_bound = x.deep_copy() + lower_bound.set_selected(selection, x-shift) + upper_bound = x.deep_copy() + upper_bound.set_selected(selection, x+shift) + self._calculator = individual( + data = data, + x = x.as_double(), + lower_bound = lower_bound.as_double(), + upper_bound = upper_bound.as_double(), + bound_flags = flex.int(x.size()*3, 2)) + + def calculator(self): + return self._calculator + +class adp(object): + def __init__(self, + data = None, + restraints = None, + selection = None, + data_weight = 1, + restraints_weight = None, + u_min = None, + u_max = None): + adopt_init_args(self, locals()) + data.set_refine_u_iso(selection = selection) + x = data.get_x() + lower_bound = x.deep_copy() + lower_bound.set_selected(selection, u_min) + upper_bound = x.deep_copy() + upper_bound.set_selected(selection, u_max) + self._calculator = individual( + data = data, + x = x, + lower_bound = lower_bound, + upper_bound = upper_bound, + bound_flags = flex.int(x.size(), 2)) + + def calculator(self): + return self._calculator + +class occ(object): + def __init__(self, + data = None, + restraints = None, + selection = None, + data_weight = 1, + restraints_weight = None, + q_min = None, + q_max = None): + adopt_init_args(self, locals()) + data.set_refine_occupancy(selection = selection) + x = data.get_x() + lower_bound = x.deep_copy() + lower_bound.set_selected(selection, q_min) + upper_bound = x.deep_copy() + upper_bound.set_selected(selection, q_max) + self._calculator = individual( + data = data, + x = x, + lower_bound = lower_bound, + upper_bound = upper_bound, + bound_flags = flex.int(x.size(), 2)) + + def calculator(self): + return self._calculator diff --git a/mmtbx/refinement/data.py b/mmtbx/refinement/data.py index 5e4627659e..ad6f99552a 100644 --- a/mmtbx/refinement/data.py +++ b/mmtbx/refinement/data.py @@ -14,26 +14,55 @@ def __init__(self, occupancy = False, selection = None): adopt_init_args(self, locals()) + self.scatterers = self.fmodel.xray_structure.scatterers() + self.size = self.scatterers.size() self.target_functor_xray = fmodel.target_functor( alpha_beta = None # XXX Check what that means ) - self.fmodel.xray_structure.scatterers().flags_set_grads(state=False) - if selection is None: - selection = self.fmodel.xray_structure.all_selection().iselection() - if isinstance(selection, flex.bool): - selection = selection.iselection() - sc = self.fmodel.xray_structure.scatterers() - self.size = sc.size() - if (self.sites_cart): sc.flags_set_grad_site( iselection = selection) - elif(self.u_iso): sc.flags_set_grad_u_iso( iselection = selection) - elif(self.occupancy): sc.flags_set_grad_occupancy(iselection = selection) + self.scatterers.flags_set_grads(state=False) + all_selection = self.fmodel.xray_structure.all_selection() + self.selection = all_selection + self.sites_cart, self.u_iso, self.occupancy = None, None, None + + def get_x(self): + assert [self.sites_cart, self.u_iso, self.occupancy].count(True) == 1 + xrs = self.fmodel.xray_structure + if self.sites_cart: return xrs.sites_cart().as_double() + elif self.u_iso: return xrs.extract_u_iso_or_u_equiv() + elif self.occupancy: return self.scatterers.extract_occupancies() + else: assert 0 + + def _set_flags(self, scf, selection): + assert [self.sites_cart, self.u_iso, self.occupancy].count(True) == 1 + self.scatterers.flags_set_grads(state=False) + if selection is not None: + assert isinstance(selection, flex.bool) + self.selection = selection + scf(iselection = self.selection.iselection()) + + def set_refine_occupancy(self, selection = None): + self.sites_cart, self.u_iso, self.occupancy = False, False, True + self._set_flags( + scf = self.scatterers.flags_set_grad_occupancy, + selection = selection) + + def set_refine_u_iso(self, selection = None): + self.sites_cart, self.u_iso, self.occupancy = False, True, False + self._set_flags( + scf = self.scatterers.flags_set_grad_u_iso, + selection = selection) + + def set_refine_sites(self, selection = None): + self.sites_cart, self.u_iso, self.occupancy = True, False, False + self._set_flags( + scf = self.scatterers.flags_set_grad_site, + selection = selection) def update(self, x): xrs = self.fmodel.xray_structure - if (self.sites_cart): - pass - elif(self.u_iso): xrs.set_u_iso( values=x, selection=self.selection) - elif(self.occupancy): xrs.set_occupancies(value =x, selection=self.selection) + if (self.sites_cart): xrs.set_sites_cart(sites_cart = flex.vec3_double(x)) + elif(self.u_iso): xrs.set_u_iso(values=x, selection=self.selection) + elif(self.occupancy): xrs.set_occupancies(value=x, selection=self.selection) self.fmodel.update_xray_structure(update_f_calc = True) self.tg = self.target_functor_xray(compute_gradients = True) @@ -43,11 +72,15 @@ def target(self): def gradients(self): if self.selection is None: return self.tg.gradients_wrt_atomic_parameters().packed() + assert 0 else: - g = self.tg.gradients_wrt_atomic_parameters().packed() if not self.sites_cart: + g = self.tg.gradients_wrt_atomic_parameters().packed() result = flex.double(self.size, 0) result.set_selected(self.selection, g) + return result else: - assert 0 # not implemented - return result + g = self.tg.d_target_d_site_cart() + result = flex.vec3_double(self.size, [0,0,0]) + result.set_selected(self.selection, g) + return result.as_double() diff --git a/mmtbx/refinement/wrappers.py b/mmtbx/refinement/wrappers.py index 9f3c92271d..0d8cd5c1f2 100644 --- a/mmtbx/refinement/wrappers.py +++ b/mmtbx/refinement/wrappers.py @@ -1,7 +1,6 @@ from __future__ import division, print_function from libtbx import adopt_init_args from scitbx import minimizers -from scitbx.array_family import flex import mmtbx.refinement.data from mmtbx.refinement import calculators from cctbx import adptbx @@ -17,30 +16,25 @@ def __init__(self, selection, refine_q = True, refine_b = True, + refine_xyz = True, macro_cycles=3, max_iterations=50, q_min = 0., q_max = 1, b_min = 5, b_max = 45, + max_xyz_shift = 0.5, log = None): adopt_init_args(self, locals()) + data = mmtbx.refinement.data.fs(fmodel = fmodel) for micro_cycle in range(macro_cycles): # Occupancy if refine_q: - data = mmtbx.refinement.data.fs( - fmodel = fmodel, occupancy=True, selection=selection) - x = fmodel.xray_structure.scatterers().extract_occupancies() - lower_bound = x.deep_copy() - lower_bound.set_selected(selection, q_min) - upper_bound = x.deep_copy() - upper_bound.set_selected(selection, q_max) - calculator = calculators.individual( - data = data, - x = x, - lower_bound = lower_bound, - upper_bound = upper_bound, - bound_flags = flex.int(x.size(), 2)) + calculator = calculators.occ( + data = data, + selection = selection, + q_min = q_min, + q_max = q_max).calculator() minimized = minimizers.lbfgsb( calculator = calculator, max_iterations = max_iterations) @@ -49,22 +43,26 @@ def __init__(self, fmodel.r_work(), fmodel.r_free()), file = log) # ADP if refine_b: - data = mmtbx.refinement.data.fs( - fmodel = fmodel, u_iso=True, selection=selection) - x = fmodel.xray_structure.extract_u_iso_or_u_equiv() - lower_bound = x.deep_copy() - lower_bound.set_selected(selection, adptbx.b_as_u(b_min)) - upper_bound = x.deep_copy() - upper_bound.set_selected(selection, adptbx.b_as_u(b_max)) - calculator = calculators.individual( - data = data, - x = x, - lower_bound = lower_bound, - upper_bound = upper_bound, - bound_flags = flex.int(x.size(), 2)) + calculator = calculators.adp( + data = data, + selection = selection, + u_min = adptbx.b_as_u(b_min), + u_max = adptbx.b_as_u(b_max)).calculator() minimized = minimizers.lbfgsb( calculator = calculator, max_iterations = max_iterations) if log is not None: print("adp: r_work=%6.4f r_free=%6.4f"%( fmodel.r_work(), fmodel.r_free()), file = log) + # XYZ + if refine_xyz: + calculator = calculators.xyz( + data = data, + selection = selection, + max_shift = max_xyz_shift).calculator() + minimized = minimizers.lbfgsb( + calculator = calculator, + max_iterations = max_iterations) + if log is not None: + print("xyz: r_work=%6.4f r_free=%6.4f"%( + fmodel.r_work(), fmodel.r_free()), file = log) diff --git a/mmtbx/regression/tst_mmtbx_refinement_wrappers.py b/mmtbx/regression/tst_mmtbx_refinement_wrappers.py index bad980d825..3ed4ae6f4e 100644 --- a/mmtbx/regression/tst_mmtbx_refinement_wrappers.py +++ b/mmtbx/regression/tst_mmtbx_refinement_wrappers.py @@ -96,6 +96,7 @@ def run(): # xrs.shake_occupancies(selection = sel) xrs.shake_adp(selection = sel) + xrs.shake_sites_in_place(mean_distance=0.3, selection=sel) # fmodel = mmtbx.f_model.manager( f_obs = f_obs, From fc887323befbd63bea75c5d35ce7ac378e194f4d Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Wed, 8 May 2024 20:05:59 -0700 Subject: [PATCH 441/748] clean weights --- mmtbx/refinement/minimization.py | 6 ++---- mmtbx/refinement/occupancies.py | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/mmtbx/refinement/minimization.py b/mmtbx/refinement/minimization.py index 34ec9cf4f8..ad361c69f9 100644 --- a/mmtbx/refinement/minimization.py +++ b/mmtbx/refinement/minimization.py @@ -59,10 +59,8 @@ def __init__(self, fmodels, elif(refine_adp and target_weights is not None): self.weights = target_weights.adp_weights_result else: - from phenix.refinement import weight_xray_chem - self.weights = weight_xray_chem.weights(wx = 1, - wx_scale = 1, - w = 0) + from phenix.refinement import weights + self.weights = weights.weights(wx = 1, wx_scale = 1, w = 0) if(self.collect_monitor): self.monitor = monitor( weights = self.weights, diff --git a/mmtbx/refinement/occupancies.py b/mmtbx/refinement/occupancies.py index 336253d147..1f6b65a194 100644 --- a/mmtbx/refinement/occupancies.py +++ b/mmtbx/refinement/occupancies.py @@ -132,10 +132,8 @@ def __init__(self, adopt_init_args(self, locals()) self.fmodels.create_target_functors() self.fmodels.prepare_target_functors_for_minimization() - from phenix.refinement import weight_xray_chem - self.weights = weight_xray_chem.weights(wx = 1, - wx_scale = 1, - w = 0) # XXX + from phenix.refinement import weights + self.weights = weights.weights(wx = 1, wx_scale = 1, w = 0) self.par_min = self.par_initial.deep_copy() self.x = self.pack(self.par_min) self.n = self.x.size() From 2af1489b3c3582238bc4d0dca177103e3321ea9f Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 9 May 2024 12:31:32 -0700 Subject: [PATCH 442/748] Improve test behavior: use assert not easy_run.call() --- cctbx/regression/tst_diffuse.py | 2 +- cctbx/regression/tst_mem_2.py | 2 +- fable/test/tst_separate_files.py | 4 ++-- iotbx/pdb/remediation/tst_remediator.py | 2 +- iotbx/regression/ncs/tst_mtrix_biomt_cmdl.py | 16 ++++++++-------- iotbx/regression/tst_sort_atoms.py | 2 +- libtbx/tst_runtime_utils.py | 2 +- mmtbx/atomic_environment_vectors/tst.py | 2 +- mmtbx/conformation_dependent_library/tst_hpdl.py | 2 +- mmtbx/conformation_dependent_library/tst_rdl.py | 4 ++-- 10 files changed, 19 insertions(+), 19 deletions(-) diff --git a/cctbx/regression/tst_diffuse.py b/cctbx/regression/tst_diffuse.py index 1ac8d8857f..06e0a6cd48 100644 --- a/cctbx/regression/tst_diffuse.py +++ b/cctbx/regression/tst_diffuse.py @@ -123,7 +123,7 @@ def exercise(): cmd_list.insert(0, 'python %s ' % file_location) cmd = " ".join(cmd_list) if 0: print(cmd) - easy_run.call(cmd) + assert not easy_run.call(cmd) mas = iotbx.mtz.object(file_name="tst_diffuse.mtz").as_miller_arrays() assert len(mas) == 1 ma = mas[0] diff --git a/cctbx/regression/tst_mem_2.py b/cctbx/regression/tst_mem_2.py index c64dde584f..9ca80a291b 100644 --- a/cctbx/regression/tst_mem_2.py +++ b/cctbx/regression/tst_mem_2.py @@ -18,7 +18,7 @@ def run(): mtz_object.write(file_name = "tst_mem_2.mtz") assert fc.anomalous_flag() cmd = "phenix.maximum_entropy_map tst_mem_2.mtz > tst_mem_2.log" - easy_run.call(cmd) + assert not easy_run.call(cmd) o = mtz.object(file_name="tst_mem_2_mem.mtz") mas = o.as_miller_arrays() assert len(mas) == 2 diff --git a/fable/test/tst_separate_files.py b/fable/test/tst_separate_files.py index 69544be643..3575754341 100644 --- a/fable/test/tst_separate_files.py +++ b/fable/test/tst_separate_files.py @@ -37,7 +37,7 @@ def exercise( remove_file_if_necessary(file_name=obj) cmd = comp_env.compilation_command(file_name_cpp=file_name_cpp) if (verbose): print(cmd) - easy_run.call(command=cmd) + assert not easy_run.call(command=cmd) assert op.exists(obj) file_names_obj.append(obj) exe_root = "tst_separate_files" @@ -45,7 +45,7 @@ def exercise( remove_file_if_necessary(file_name=exe) cmd = comp_env.link_command(file_names_obj=file_names_obj, exe_root=exe_root) if (verbose): print(cmd) - easy_run.call(command=cmd) + assert not easy_run.call(command=cmd) cmd = op.join(".", exe) if (verbose): print(cmd) assert op.exists(cmd) diff --git a/iotbx/pdb/remediation/tst_remediator.py b/iotbx/pdb/remediation/tst_remediator.py index 931bd044ba..03c92e06c8 100644 --- a/iotbx/pdb/remediation/tst_remediator.py +++ b/iotbx/pdb/remediation/tst_remediator.py @@ -206,7 +206,7 @@ def get_regression_folder_file_path(file_name): def test_full_str_convert(old_file, new_file): print("testing full file remediation") prefix = os.path.basename(__file__).replace(".py","") - easy_run.call("iotbx.pdb_remediator %s > %s.pdb"%(old_file, prefix)) + assert not easy_run.call("iotbx.pdb_remediator %s > %s.pdb"%(old_file, prefix)) with open(prefix+".pdb") as file: remediated_list = [line.rstrip() for line in file] remediated_pdb = "\n".join(remediated_list) diff --git a/iotbx/regression/ncs/tst_mtrix_biomt_cmdl.py b/iotbx/regression/ncs/tst_mtrix_biomt_cmdl.py index ca43e789c2..361fb2354b 100644 --- a/iotbx/regression/ncs/tst_mtrix_biomt_cmdl.py +++ b/iotbx/regression/ncs/tst_mtrix_biomt_cmdl.py @@ -540,11 +540,11 @@ def exercise_000(file_name="tst_mtrix_biomt_cmdl_000.pdb"): print(pdb_str_0, file=of) of.close() # template when pdb_as_cif will handle BIOMT records as well... - # easy_run.call("phenix.pdb_as_cif %s"%file_name) + # assert not easy_run.call("phenix.pdb_as_cif %s"%file_name) # for file_type in ['pdb', 'cif']: for file_type in ['pdb']: print("file_type:", file_type) - easy_run.call("phenix.pdb.biomt_reconstruction %s.%s" % (file_name[:-4], file_type)) + assert not easy_run.call("phenix.pdb.biomt_reconstruction %s.%s" % (file_name[:-4], file_type)) pdb_inp = iotbx.pdb.input( file_name="%s_BIOMT_expanded.%s" % (file_name[:-4], file_type)) a = pdb_inp.extract_secondary_structure() @@ -575,7 +575,7 @@ def exercise_001(file_name="tst_mtrix_biomt_cmdl_001.pdb"): of = open(file_name,"w") print(pdb_str_2b, file=of) of.close() - easy_run.call("phenix.pdb.mtrix_reconstruction %s"%file_name) + assert not easy_run.call("phenix.pdb.mtrix_reconstruction %s"%file_name) pdb_inp = iotbx.pdb.input( file_name="tst_mtrix_biomt_cmdl_001_MTRIX_expanded.pdb") a = pdb_inp.extract_secondary_structure() @@ -605,7 +605,7 @@ def exercise_002(file_name="tst_mtrix_biomt_cmdl_002.pdb"): of = open(file_name,"w") print(pdb_str_0, file=of) of.close() - easy_run.call("phenix.pdb.mtrix_reconstruction %s"%file_name) + assert not easy_run.call("phenix.pdb.mtrix_reconstruction %s"%file_name) pdb_inp = iotbx.pdb.input( file_name="tst_mtrix_biomt_cmdl_002_MTRIX_expanded.pdb") a = pdb_inp.extract_secondary_structure() @@ -634,7 +634,7 @@ def exercise_003(file_name="tst_mtrix_biomt_cmdl_003.pdb"): of = open(file_name,"w") print(pdb_str_2b, file=of) of.close() - easy_run.call("phenix.pdb.biomt_reconstruction %s"%file_name) + assert not easy_run.call("phenix.pdb.biomt_reconstruction %s"%file_name) pdb_inp = iotbx.pdb.input( file_name="tst_mtrix_biomt_cmdl_003_BIOMT_expanded.pdb") a = pdb_inp.extract_secondary_structure() @@ -663,7 +663,7 @@ def exercise_01(file_name="tst_mtrix_biomt_cmdl_01.pdb"): of = open(file_name,"w") print(pdb_str_1, file=of) of.close() - easy_run.call("phenix.pdb.mtrix_reconstruction %s"%file_name) + assert not easy_run.call("phenix.pdb.mtrix_reconstruction %s"%file_name) pdb_inp1 = iotbx.pdb.input( file_name="tst_mtrix_biomt_cmdl_01_MTRIX_expanded.pdb") pdb_inp2 = iotbx.pdb.input(source_info=None, lines=pdb_str_1a) @@ -684,7 +684,7 @@ def exercise_02(file_name="tst_mtrix_biomt_cmdl_02.pdb"): of = open(file_name,"w") print(pdb_str_2, file=of) of.close() - easy_run.call("phenix.pdb.mtrix_reconstruction %s"%file_name) + assert not easy_run.call("phenix.pdb.mtrix_reconstruction %s"%file_name) pdb_inp1 = iotbx.pdb.input( file_name="tst_mtrix_biomt_cmdl_02_MTRIX_expanded.pdb") pdb_inp2 = iotbx.pdb.input(source_info=None, lines=pdb_str_2a) @@ -701,7 +701,7 @@ def exercise_03(file_name="tst_mtrix_biomt_cmdl_03.cif"): of = open(file_name,"w") print(pdb_str_3, file=of) of.close() - easy_run.call("phenix.pdb.mtrix_reconstruction %s"%file_name) + assert not easy_run.call("phenix.pdb.mtrix_reconstruction %s"%file_name) pdb_inp1 = iotbx.pdb.input( file_name="tst_mtrix_biomt_cmdl_03_MTRIX_expanded.cif") pdb_inp2 = iotbx.pdb.input(source_info=None, lines=pdb_str_3a) diff --git a/iotbx/regression/tst_sort_atoms.py b/iotbx/regression/tst_sort_atoms.py index f8d16bb925..edd469d03e 100644 --- a/iotbx/regression/tst_sort_atoms.py +++ b/iotbx/regression/tst_sort_atoms.py @@ -803,7 +803,7 @@ def exercise_1(prefix="tst_sort_atoms_1"): "%s.pdb" % prefix, ]) print(cmd) - easy_run.call(cmd) + assert not easy_run.call(cmd) assert os.path.isfile("%s_sorted.pdb" % prefix) out_f = open("%s_sorted.pdb" % prefix, 'r') out_str = out_f.read() diff --git a/libtbx/tst_runtime_utils.py b/libtbx/tst_runtime_utils.py index 65f59b7c8a..b6cb8a5d35 100644 --- a/libtbx/tst_runtime_utils.py +++ b/libtbx/tst_runtime_utils.py @@ -27,7 +27,7 @@ def exercise(): with open(eff_file, "w") as f: working_phil.show(out=f) easy_pickle.dump(params.run_file, run) - easy_run.call("libtbx.start_process %s &" % eff_file) #params.run_file) + assert not easy_run.call("libtbx.start_process %s &" % eff_file) #params.run_file) client = runtime_utils.simple_client(params) client.run() assert (client.out.getvalue() == """\ diff --git a/mmtbx/atomic_environment_vectors/tst.py b/mmtbx/atomic_environment_vectors/tst.py index 9131e838ca..683e81b1a0 100644 --- a/mmtbx/atomic_environment_vectors/tst.py +++ b/mmtbx/atomic_environment_vectors/tst.py @@ -87,7 +87,7 @@ def run(): if 0: with open("development.aev.pdb", "w") as fo: fo.write(pdb_str) - easy_run.call("mmtbx.development.aev development.aev.pdb 0.9") + assert not easy_run.call("mmtbx.development.aev development.aev.pdb 0.9") if __name__ == '__main__': run() diff --git a/mmtbx/conformation_dependent_library/tst_hpdl.py b/mmtbx/conformation_dependent_library/tst_hpdl.py index 0fe74a7745..20c683e909 100644 --- a/mmtbx/conformation_dependent_library/tst_hpdl.py +++ b/mmtbx/conformation_dependent_library/tst_hpdl.py @@ -133,7 +133,7 @@ def run(filename=None): f.close() cmd = "phenix.pdb_interpretation %s write_geo=1 hpdl=%s" % (filename, True) print(cmd) - easy_run.call(cmd) + assert not easy_run.call(cmd) if filename.find("his_double")>-1: key="ND1 and NE2 protonated" elif filename.find("his_nd1")>-1: key="Only ND1 protonated" elif filename.find("his_ne2")>-1: key="Only NE2 protonated" diff --git a/mmtbx/conformation_dependent_library/tst_rdl.py b/mmtbx/conformation_dependent_library/tst_rdl.py index e9987732ef..39363b7731 100644 --- a/mmtbx/conformation_dependent_library/tst_rdl.py +++ b/mmtbx/conformation_dependent_library/tst_rdl.py @@ -117,10 +117,10 @@ def run(filename): f.close() cmd="phenix.pdb_interpretation rdl=True write_geo=1 mse.pdb" print(cmd) - easy_run.call(cmd) + assert not easy_run.call(cmd) cmd="phenix.pdb_interpretation rdl=True write_geo=1 met.pdb" print(cmd) - easy_run.call(cmd) + assert not easy_run.call(cmd) # pdb_inp = pdb.input(filename) pdb_hierarchy = pdb_inp.construct_hierarchy() From 82deb0fb183f95f66203686ad1e329d5a94fe210 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 9 May 2024 12:59:07 -0700 Subject: [PATCH 443/748] Improve test behavior: use assert not easy_run.call(). Part 2. --- mmtbx/monomer_library/tst_chg.py | 2 +- mmtbx/monomer_library/tst_pdb_interpretation_3.py | 2 +- mmtbx/regression/tst_altloc_chain_break.py | 2 +- mmtbx/regression/tst_altloc_remediate.py | 2 +- mmtbx/regression/tst_fmodel_2.py | 2 +- mmtbx/regression/tst_helix_sheet_recs_as_pdb_files.py | 2 +- mmtbx/regression/tst_map_model_cc.py | 2 +- mmtbx/regression/tst_model_map.py | 2 +- mmtbx/regression/tst_models_to_from_chains.py | 4 ++-- mmtbx/regression/tst_rank_scale_map.py | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/mmtbx/monomer_library/tst_chg.py b/mmtbx/monomer_library/tst_chg.py index 233d56ae04..c7f3f4f1f0 100644 --- a/mmtbx/monomer_library/tst_chg.py +++ b/mmtbx/monomer_library/tst_chg.py @@ -329,7 +329,7 @@ def run(): ero.show_stdout(out=err) cmd = "phenix.fmodel high_res=4.5 format=mtz label=FOBS type=real r_free=0.1 l1r.pdb generate_fake_p1_symmetry=1" - easy_run.call(cmd) + assert not easy_run.call(cmd) cmd = 'phenix.refine' cmd += " l1r.pdb l1r.pdb.mtz l1r.cif" cmd += " main.number_of_macro_cycles=1" diff --git a/mmtbx/monomer_library/tst_pdb_interpretation_3.py b/mmtbx/monomer_library/tst_pdb_interpretation_3.py index de99904b63..127bcd6915 100644 --- a/mmtbx/monomer_library/tst_pdb_interpretation_3.py +++ b/mmtbx/monomer_library/tst_pdb_interpretation_3.py @@ -223,7 +223,7 @@ def _run_and_get_target(pdb_str): file_name_prefix = "tst_pdb_interpretation_3" with open("%s.pdb"%file_name_prefix, "w") as fo: fo.write(pdb_str) - easy_run.call("phenix.pdb_interpretation %s.pdb > %s.log"%( + assert not easy_run.call("phenix.pdb_interpretation %s.pdb > %s.log"%( file_name_prefix,file_name_prefix)) with open("%s.log"%file_name_prefix, "r") as fo: for l in fo.readlines(): diff --git a/mmtbx/regression/tst_altloc_chain_break.py b/mmtbx/regression/tst_altloc_chain_break.py index d412e99a75..104b263ce5 100644 --- a/mmtbx/regression/tst_altloc_chain_break.py +++ b/mmtbx/regression/tst_altloc_chain_break.py @@ -58,7 +58,7 @@ def exercise(args): "tmp_altloc_chain_break.pdb", "pdb_interpretation.nonbonded_weight=16", ">tmp_altloc_chain_break.zlog"]) - easy_run.call(command=command) + assert not easy_run.call(command=command) target_values = [] for line in open("tmp_altloc_chain_break.zlog","r").readlines(): line = line.strip() diff --git a/mmtbx/regression/tst_altloc_remediate.py b/mmtbx/regression/tst_altloc_remediate.py index 4b56b2a9ce..5943195a92 100644 --- a/mmtbx/regression/tst_altloc_remediate.py +++ b/mmtbx/regression/tst_altloc_remediate.py @@ -568,7 +568,7 @@ def run(): f.close() cmd = "mmtbx.altloc_remediate %s" % "%s.pdb" % preamble print(cmd) - easy_run.call(cmd) + assert not easy_run.call(cmd) f=open("%s_correct.pdb" % preamble, "r") lines = f.read() f.close() diff --git a/mmtbx/regression/tst_fmodel_2.py b/mmtbx/regression/tst_fmodel_2.py index 5852a844a5..f4d289dd62 100644 --- a/mmtbx/regression/tst_fmodel_2.py +++ b/mmtbx/regression/tst_fmodel_2.py @@ -1024,7 +1024,7 @@ def run(prefix="tst_fmodel_2"): "type=real", "high_res=1.0", "> %s.zlog"%prefix]) - easy_run.call(cmd) + assert not easy_run.call(cmd) miller_arrays = reflection_file_reader.any_reflection_file(file_name = "tst_fmodel_2.pdb.mtz").as_miller_arrays() for ma in miller_arrays: diff --git a/mmtbx/regression/tst_helix_sheet_recs_as_pdb_files.py b/mmtbx/regression/tst_helix_sheet_recs_as_pdb_files.py index 6d8a99dab2..23c006a7a6 100644 --- a/mmtbx/regression/tst_helix_sheet_recs_as_pdb_files.py +++ b/mmtbx/regression/tst_helix_sheet_recs_as_pdb_files.py @@ -136,7 +136,7 @@ def exercise(prefix="tst_helix_sheet_recs_as_pdb_files"): print(pdb_str, file=of) of.close() xrs1 = iotbx.pdb.input(file_name=prefix+".pdb").xray_structure_simple() - easy_run.call("phenix.helix_sheet_recs_as_pdb_files %s"%(prefix+".pdb")) + assert not easy_run.call("phenix.helix_sheet_recs_as_pdb_files %s"%(prefix+".pdb")) xrs2 = iotbx.pdb.input( file_name="HELIX_1_1_ALA_E_1_ALA_E_16_1_16.pdb").xray_structure_simple(crystal_symmetry=xrs1.crystal_symmetry()) fc1 = xrs1.structure_factors(d_min=3).f_calc() diff --git a/mmtbx/regression/tst_map_model_cc.py b/mmtbx/regression/tst_map_model_cc.py index 99fcb6ab54..8c517fa3dc 100644 --- a/mmtbx/regression/tst_map_model_cc.py +++ b/mmtbx/regression/tst_map_model_cc.py @@ -90,7 +90,7 @@ def run(prefix="tst_map_model_cc"): "> %s.zlog"%prefix ]) print(cmd) - easy_run.call(cmd) + assert not easy_run.call(cmd) # check results fo = open("%s.zlog"%prefix,"r") for l in fo.readlines(): diff --git a/mmtbx/regression/tst_model_map.py b/mmtbx/regression/tst_model_map.py index 3c75a39330..9f08bc9160 100644 --- a/mmtbx/regression/tst_model_map.py +++ b/mmtbx/regression/tst_model_map.py @@ -89,7 +89,7 @@ def run(prefix="tst_model_map"): xrs = pdb_inp.xray_structure_simple() fc0 = xrs.structure_factors(d_min=3.0).f_calc() # - easy_run.call("phenix.model_map %s.pdb output_file_name_prefix=%s"%( + assert not easy_run.call("phenix.model_map %s.pdb output_file_name_prefix=%s"%( prefix, prefix)) m1 = iotbx.mrcfile.map_reader(file_name="%s.ccp4"%prefix).data.as_double() m2 = iotbx.xplor.map.reader(file_name="%s.xplor"%prefix).data diff --git a/mmtbx/regression/tst_models_to_from_chains.py b/mmtbx/regression/tst_models_to_from_chains.py index 4e68da0c15..5ed90afcdb 100644 --- a/mmtbx/regression/tst_models_to_from_chains.py +++ b/mmtbx/regression/tst_models_to_from_chains.py @@ -86,7 +86,7 @@ def exercise(prefix="tst_models_to_from_chains"): fc = complete_set.structure_factors_from_scatterers( xray_structure=xrs).f_calc() # models -> chains - easy_run.call("phenix.models_as_chains %s"%input_file_name) + assert not easy_run.call("phenix.models_as_chains %s"%input_file_name) pdb_inp = iotbx.pdb.input(file_name="chains_"+input_file_name) h = pdb_inp.construct_hierarchy() assert len(list(h.chains()))==expected_n @@ -95,7 +95,7 @@ def exercise(prefix="tst_models_to_from_chains"): fc_c = complete_set.structure_factors_from_scatterers( xray_structure=xrs_c).f_calc() # - easy_run.call("phenix.chains_as_models chains_%s"%input_file_name) + assert not easy_run.call("phenix.chains_as_models chains_%s"%input_file_name) pdb_inp = iotbx.pdb.input(file_name="models_chains_"+input_file_name) h = pdb_inp.construct_hierarchy() assert len(list(h.chains()))==expected_n diff --git a/mmtbx/regression/tst_rank_scale_map.py b/mmtbx/regression/tst_rank_scale_map.py index d3bfd5ebc5..7b03f3eeb4 100644 --- a/mmtbx/regression/tst_rank_scale_map.py +++ b/mmtbx/regression/tst_rank_scale_map.py @@ -24,7 +24,7 @@ def exercise_00(prefix="tst_rank_scale_map"): #gridding_last=n_real, # This causes a bug (map gets shifted) map_data=m, labels=flex.std_string([""])) - easy_run.call("phenix.rank_scale_map %s.ccp4"%prefix) + assert not easy_run.call("phenix.rank_scale_map %s.ccp4"%prefix) # ccp4_map = iotbx.mrcfile.map_reader( file_name="%s.ccp4_rank_scaled.ccp4"%prefix) From f1251da550b82e72bf930d9e0fa86b656cc295b2 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 9 May 2024 13:26:35 -0700 Subject: [PATCH 444/748] bug fix in QI --- mmtbx/geometry_restraints/base_qm_manager.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mmtbx/geometry_restraints/base_qm_manager.py b/mmtbx/geometry_restraints/base_qm_manager.py index 5e9b1e4742..7dfce73670 100644 --- a/mmtbx/geometry_restraints/base_qm_manager.py +++ b/mmtbx/geometry_restraints/base_qm_manager.py @@ -212,6 +212,8 @@ def get_energy(self, *args, **kwds): return 0, 'dirac' def read_energy(self, *args, **kwds): return 0, 'dirac' + def read_charge(self, *args, **kwds): return 99 + def get_strain(self, *args, **kwds): return 0, 'dirac' def get_bound(self, *args, **kwds): return 0, 'dirac' From 3aa46810307a85e3890cc3030d18b0b7a1c3a2ab Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 9 May 2024 13:50:27 -0700 Subject: [PATCH 445/748] Improve test behavior: use assert not easy_run.call(). Part 3. --- mmtbx/regression/model_idealization/tst_ext_map_01.py | 4 ++-- mmtbx/regression/tls/tst_tls_as_xyz.py | 2 +- mmtbx/regression/tst_ringer.py | 2 +- mmtbx/validation/regression/tst_cablam_2.py | 2 +- mmtbx/validation/regression/tst_molprobity_3.py | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/mmtbx/regression/model_idealization/tst_ext_map_01.py b/mmtbx/regression/model_idealization/tst_ext_map_01.py index d4432f360b..99b9f4eca2 100644 --- a/mmtbx/regression/model_idealization/tst_ext_map_01.py +++ b/mmtbx/regression/model_idealization/tst_ext_map_01.py @@ -135,13 +135,13 @@ def exercise_01(prefix="tst_mi_ext_map_test_01"): # "generate_fake_p1_symmetry=True", ]) print(fmodel_cmd) - easy_run.call(fmodel_cmd) + assert not easy_run.call(fmodel_cmd) mtz2map_cmd = " ".join([ "phenix.mtz2map", "%s_start.pdb.mtz" % prefix, "include_fmodel=True"]) print(mtz2map_cmd) - easy_run.call(mtz2map_cmd) + assert not easy_run.call(mtz2map_cmd) # STOP() cmd = " ".join([ "phenix.model_idealization", diff --git a/mmtbx/regression/tls/tst_tls_as_xyz.py b/mmtbx/regression/tls/tst_tls_as_xyz.py index 9206a61811..96ba300fa4 100644 --- a/mmtbx/regression/tls/tst_tls_as_xyz.py +++ b/mmtbx/regression/tls/tst_tls_as_xyz.py @@ -166,7 +166,7 @@ def run(file_name = "tst_tls_as_xyz.pdb"): uc = iotbx.pdb.input(file_name=file_name).crystal_symmetry().unit_cell() #for n in range(10,100,10)+range(100,1000,100)+range(1000,10001,1000)+[15000,20000]: for n in [1000,]: - easy_run.call("phenix.tls_as_xyz %s n_models=%s > tst_tls_as_xyz.log"%( + assert not easy_run.call("phenix.tls_as_xyz %s n_models=%s > tst_tls_as_xyz.log"%( file_name,str(n))) for i in [0,1]: u1 = iotbx.pdb.input(file_name= diff --git a/mmtbx/regression/tst_ringer.py b/mmtbx/regression/tst_ringer.py index bd2f97323e..b41b3b337d 100644 --- a/mmtbx/regression/tst_ringer.py +++ b/mmtbx/regression/tst_ringer.py @@ -210,7 +210,7 @@ def exercise(): "output.file_name=%s" % mtz_file, ]) print(cmd) - easy_run.call(cmd) + assert not easy_run.call(cmd) result = easy_run.fully_buffered( "phenix.maps \"%s\" \"%s\" output.prefix=tmp_ringer" % (pdb_file, mtz_file)).raise_if_errors() diff --git a/mmtbx/validation/regression/tst_cablam_2.py b/mmtbx/validation/regression/tst_cablam_2.py index 43e682068e..33f17860a3 100644 --- a/mmtbx/validation/regression/tst_cablam_2.py +++ b/mmtbx/validation/regression/tst_cablam_2.py @@ -4,7 +4,7 @@ import libtbx.load_env def exercise_01(): - easy_run.call("phenix.fetch_pdb 5o61 -c") + assert not easy_run.call("phenix.fetch_pdb 5o61 -c") fb = easy_run.fully_buffered("phenix.cablam 5o61.cif") assert fb.return_code == 0, fb.return_code diff --git a/mmtbx/validation/regression/tst_molprobity_3.py b/mmtbx/validation/regression/tst_molprobity_3.py index 4868c86735..a65cd3231e 100644 --- a/mmtbx/validation/regression/tst_molprobity_3.py +++ b/mmtbx/validation/regression/tst_molprobity_3.py @@ -70,9 +70,9 @@ def exercise_00(prefix="tst_molprobity_3_exercise_00"): "type=real r_free=0.1 label=F-obs", "output.file_name=%s_%d.mtz" % (prefix, i), "> %s.zlog"%prefix]) - easy_run.call(cmd) + assert not easy_run.call(cmd) cmd = "phenix.molprobity %s.pdb %s_%d.mtz > %s.zlog"%(prefix,prefix,i,prefix) - easy_run.call(cmd) + assert not easy_run.call(cmd) def exercise_01(prefix="tst_molprobity_3_exercise_01"): of = open("%s.pdb"%prefix, "w") From f859d1f6aa6f0709d72b4e6b28efd157ddb7a457 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Thu, 9 May 2024 14:39:18 -0700 Subject: [PATCH 446/748] libtbx: add option to preserve previous PHIL parsing behavior of no assumptions - Test added to verify behaviors --- libtbx/phil/__init__.py | 6 ++-- libtbx/phil/command_line.py | 20 ++++++----- libtbx/phil/tst.py | 72 +++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 10 deletions(-) diff --git a/libtbx/phil/__init__.py b/libtbx/phil/__init__.py index 5d1efd0322..76b8466774 100644 --- a/libtbx/phil/__init__.py +++ b/libtbx/phil/__init__.py @@ -2019,12 +2019,14 @@ def unique(self): def command_line_argument_interpreter(self, home_scope=None, - argument_description=None): + argument_description=None, + assume_when_ambigious=True): from libtbx.phil.command_line import argument_interpreter as _ return _( master_phil=self, home_scope=home_scope, - argument_description=argument_description) + argument_description=argument_description, + assume_when_ambigious=assume_when_ambigious) def process_include_scope( converter_registry, diff --git a/libtbx/phil/command_line.py b/libtbx/phil/command_line.py index 71f3d00ffe..c47751ee83 100644 --- a/libtbx/phil/command_line.py +++ b/libtbx/phil/command_line.py @@ -11,7 +11,8 @@ def __init__(self, master_phil=None, home_scope=None, argument_description=None, - master_params=None): + master_params=None, + assume_when_ambigious=True): if (argument_description is None): argument_description = "command line " assert [master_params, master_phil].count(None) == 1 @@ -27,6 +28,7 @@ def __init__(self, self.home_scope = home_scope self.argument_description = argument_description self.target_paths = None + self.assume_when_ambigious = assume_when_ambigious def get_path_score(self, source_path, target_path): i = target_path.find(source_path) @@ -90,14 +92,16 @@ def parent_expert_level(obj): if (score == max_score): error.append(" " + target_path) - # Calculate and apply tie-breaker value depending on expert level. - # Arguments with lower expert level are preferentially - # chosen if otherwise they would be ambiguous. - scores = [ score - (exp_lvl / 100) for score, exp_lvl in zip(scores, expert_level) ] - max_score = max(scores) - if (scores.count(max_score) > 1): + if self.assume_when_ambigious: + # Calculate and apply tie-breaker value depending on expert level. + # Arguments with lower expert level are preferentially + # chosen if otherwise they would be ambiguous. + scores = [ score - (exp_lvl / 100) for score, exp_lvl in zip(scores, expert_level) ] + max_score = max(scores) + if (scores.count(max_score) > 1): # if there is still a tie, a Sorry is still raised raise Sorry("\n".join(error)) - print("Warning: " + "\n".join(error) + "\nAssuming %s was intended." % self.target_paths[scores.index(max_score)]) + if self.assume_when_ambigious: + print("Warning: " + "\n".join(error) + "\nAssuming %s was intended." % self.target_paths[scores.index(max_score)]) complete_definitions += object.customized_copy( name=self.target_paths[scores.index(max_score)]).as_str() diff --git a/libtbx/phil/tst.py b/libtbx/phil/tst.py index b5a9de511f..60a2a523e3 100644 --- a/libtbx/phil/tst.py +++ b/libtbx/phil/tst.py @@ -5343,6 +5343,77 @@ def custom_processor(arg): params = master_phil.fetch(sources=user_phil).extract() assert (params.sites == 2) +def exercise_command_line_assume(): + master_string = """\ +foo { + min=0 + max=10 + .expert_level = 0 + index=3 + limit=6 +} +bar { + max=5 + .expert_level = 1 + sub { + limit=8 + } + flag=None +} +""" + master_phil = phil.parse(input_string=master_string) + # do not assume + itpr_neutral = master_phil.command_line_argument_interpreter(assume_when_ambigious=False) + try: assert itpr_neutral.process(arg="max=5") + except Sorry as e: + assert not show_diff(str(e), """\ +Ambiguous parameter definition: max = 5 +Best matches: + foo.max + bar.max""") + else: raise Exception_expected + # assume with different expert levels + itpr_neutral = master_phil.command_line_argument_interpreter(assume_when_ambigious=True) + old_stdout = sys.stdout + output = StringIO() + sys.stdout = output + itpr_neutral.process(arg="max=5") + sys.stdout = old_stdout + output = output.getvalue() + assert '''\ +Best matches: + foo.max + bar.max +Assuming foo.max was intended.''' in output + # assume with the same expert levels (same as do not assume) + master_string = """\ +foo { + min=0 + max=10 + .expert_level = 2 + index=3 + limit=6 +} +bar { + max=5 + .expert_level = 2 + sub { + limit=8 + } + flag=None +} +""" + master_phil = phil.parse(input_string=master_string) + itpr_neutral = master_phil.command_line_argument_interpreter(assume_when_ambigious=True) + try: assert itpr_neutral.process(arg="max=5") + except Sorry as e: + assert not show_diff(str(e), """\ +Ambiguous parameter definition: max = 5 +Best matches: + foo.max + bar.max""") + else: raise Exception_expected + def exercise_choice_multi_plus_support(): master_phil = libtbx.phil.parse("""\ u = a b c @@ -5945,6 +6016,7 @@ def exercise(): exercise_ints_and_floats() exercise_definition_validate_etc() exercise_command_line() + exercise_command_line_assume() exercise_choice_multi_plus_support() exercise_deprecation() exercise_change_default() From 32e181a69f6eb160ea2659b1eacfbc3540ce8d10 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Thu, 9 May 2024 14:43:30 -0700 Subject: [PATCH 447/748] ProgramTemplate: add option to control how ambigious PHIL parameters are processed --- iotbx/cli_parser.py | 6 ++++-- libtbx/program_template.py | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/iotbx/cli_parser.py b/iotbx/cli_parser.py index 2ff0c55238..0d8b6b6ed1 100644 --- a/iotbx/cli_parser.py +++ b/iotbx/cli_parser.py @@ -511,8 +511,10 @@ def process_phil(self, phil_list): # command-line PHIL arguments override any previous settings and are # processed in given order if len(phil_list) > 0: - interpreter = self.master_phil.command_line_argument_interpreter() - data_manager_interpreter = self.data_manager.master_phil.command_line_argument_interpreter() + interpreter = self.master_phil.command_line_argument_interpreter( + assume_when_ambigious=self.program_class.assume_when_ambigious) + data_manager_interpreter = self.data_manager.master_phil.command_line_argument_interpreter( + assume_when_ambigious=self.program_class.assume_when_ambigious) print(' Adding command-line PHIL:', file=self.logger) print(' -------------------------', file=self.logger) for phil in phil_list: diff --git a/libtbx/program_template.py b/libtbx/program_template.py index e8bd39297f..4b0b1ce160 100644 --- a/libtbx/program_template.py +++ b/libtbx/program_template.py @@ -79,6 +79,9 @@ class ProgramTemplate(object): } ''' + # control PHIL parsing behavior when parameters are ambigious + assume_when_ambigious = False + # the DataManager scope includes some shared PHIL parameters # set this to true if the DataManager scope should be shown by default show_data_manager_scope_by_default = False From b2452169a6880df36a869fb6c236320708f56f52 Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Thu, 9 May 2024 22:23:42 -0700 Subject: [PATCH 448/748] One more version of logging, more calculators for refinement using lbfgsb --- libtbx/log.py | 29 +++ mmtbx/model/model.py | 8 + mmtbx/refinement/calculators.py | 98 +++++----- mmtbx/refinement/data.py | 7 +- mmtbx/refinement/minimization.py | 2 +- mmtbx/refinement/occupancies.py | 2 +- mmtbx/refinement/wrappers.py | 185 ++++++++++++++++-- .../tst_mmtbx_refinement_wrappers.py | 3 +- mmtbx/solvent/ordered_solvent.py | 38 +--- 9 files changed, 280 insertions(+), 92 deletions(-) diff --git a/libtbx/log.py b/libtbx/log.py index 90425b689a..c446037d10 100644 --- a/libtbx/log.py +++ b/libtbx/log.py @@ -3,6 +3,35 @@ import logging import sys +class manager(object): + def __init__(self, log=None): + self.log = log + self.messages = [] + self.prefix = "" + + def set_prefix(self, prefix): + self.prefix=prefix + + def add(self, msg): + msg = "%s%s"%(self.prefix, msg) + self.messages.append(msg) + + def add_and_show(self, msg): + self.add(msg) + self.show_last() + + def show(self): + print(msg, file=self.log) + + def show_last(self): + if len(self.messages)>0: + print(self.messages[-1], file=self.log) + + def show_all(self): + for msg in self.messages: + print(msg, file=self.log) + + class logger(object): """A basic wrapper over Python standard library logging module. diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index aea6ef32c4..9062ea7a93 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -1062,6 +1062,9 @@ def _shift_back(self, pdb_hierarchy): def set_refinement_flags(self, flags): self.refinement_flags = flags + def get_refinement_flags(self): + return self.refinement_flags + def get_number_of_atoms(self): return self.get_hierarchy().atoms().size() @@ -4118,7 +4121,12 @@ def show_adp_statistics(self, self.adp_statistics().show(log = out, prefix = prefix) def energies_adp(self, iso_restraints, compute_gradients, use_hd): + if self.restraints_manager is None: return None assert self.refinement_flags is not None + if iso_restraints is None: + import mmtbx.refinement.adp_refinement + iso_restraints = mmtbx.refinement.adp_refinement.\ + adp_restraints_master_params.extract().iso xrs = self._xray_structure sel_ = xrs.use_u_iso() | xrs.use_u_aniso() selection = sel_ diff --git a/mmtbx/refinement/calculators.py b/mmtbx/refinement/calculators.py index 3e17f18296..e57099554a 100644 --- a/mmtbx/refinement/calculators.py +++ b/mmtbx/refinement/calculators.py @@ -1,6 +1,6 @@ from __future__ import division from libtbx import adopt_init_args -from scitbx.array_family import flex +from cctbx import adptbx class individual(object): def __init__(self, @@ -8,16 +8,16 @@ def __init__(self, x, data_weight=1, restraints=None, - restraints_weight=None, - lower_bound=None, - upper_bound=None, - bound_flags=None): + restraints_weight=None): adopt_init_args(self, locals()) self.t = None self.g = None self.d = None self.use_curvatures=False self.n = x.size() + self.lower_bound = restraints.lower_bound() + self.upper_bound = restraints.upper_bound() + self.bound_flags = restraints.bound_flags() # self.update(x = self.x) self.f_start = self.t @@ -33,9 +33,11 @@ def update(self, x): for p in [[self.data, self.data_weight], [self.restraints, self.restraints_weight]]: source, weight = p - if source is not None: - self.t += source.target()*weight - self.g += source.gradients()*weight + if not None in [source, weight]: + t,g = source.target(), source.gradients() + if t is not None: + self.t += t*weight + self.g += g*weight def target_and_gradients(self): self.update(x = self.x) @@ -49,24 +51,24 @@ def __init__(self, data = None, restraints = None, selection = None, - data_weight = 1, - restraints_weight = None, + data_weight = 1., + restraints_weight = 1., max_shift = None): adopt_init_args(self, locals()) assert isinstance(max_shift, float) - data.set_refine_sites(selection = selection) - x = flex.vec3_double(data.get_x()) - shift = flex.vec3_double(x.size(), [max_shift, max_shift, max_shift]) - lower_bound = x.deep_copy() - lower_bound.set_selected(selection, x-shift) - upper_bound = x.deep_copy() - upper_bound.set_selected(selection, x+shift) + assert [data, restraints].count(None) != 2 + if data is not None: + data.set_refine_sites(selection = selection) + x = data.get_x() + if restraints is not None: + restraints.set_use_xyz(selection = selection, max_shift = max_shift) + x = restraints.get_x() self._calculator = individual( - data = data, - x = x.as_double(), - lower_bound = lower_bound.as_double(), - upper_bound = upper_bound.as_double(), - bound_flags = flex.int(x.size()*3, 2)) + data = data, + restraints = restraints, + data_weight = data_weight, + restraints_weight = restraints_weight, + x = x) def calculator(self): return self._calculator @@ -81,18 +83,22 @@ def __init__(self, u_min = None, u_max = None): adopt_init_args(self, locals()) - data.set_refine_u_iso(selection = selection) - x = data.get_x() - lower_bound = x.deep_copy() - lower_bound.set_selected(selection, u_min) - upper_bound = x.deep_copy() - upper_bound.set_selected(selection, u_max) + assert [data, restraints].count(None) != 2 + if data is not None: + data.set_refine_u_iso(selection = selection) + x = data.get_x() + if restraints is not None: + restraints.set_use_adp( + selection = selection, + b_min = adptbx.u_as_b(u_min), + b_max = adptbx.u_as_b(u_max)) + x = restraints.get_x() self._calculator = individual( - data = data, - x = x, - lower_bound = lower_bound, - upper_bound = upper_bound, - bound_flags = flex.int(x.size(), 2)) + data = data, + restraints = restraints, + data_weight = data_weight, + restraints_weight = restraints_weight, + x = x) def calculator(self): return self._calculator @@ -107,18 +113,22 @@ def __init__(self, q_min = None, q_max = None): adopt_init_args(self, locals()) - data.set_refine_occupancy(selection = selection) - x = data.get_x() - lower_bound = x.deep_copy() - lower_bound.set_selected(selection, q_min) - upper_bound = x.deep_copy() - upper_bound.set_selected(selection, q_max) + assert [data, restraints].count(None) != 2 + if data is not None: + data.set_refine_occupancy(selection = selection) + x = data.get_x() + if restraints is not None: + restraints.set_use_occ( + selection = selection, + q_min = q_min, + q_max = q_max) + x = restraints.get_x() self._calculator = individual( - data = data, - x = x, - lower_bound = lower_bound, - upper_bound = upper_bound, - bound_flags = flex.int(x.size(), 2)) + data = data, + restraints = restraints, + data_weight = data_weight, + restraints_weight = restraints_weight, + x = x) def calculator(self): return self._calculator diff --git a/mmtbx/refinement/data.py b/mmtbx/refinement/data.py index ad6f99552a..f1fa592810 100644 --- a/mmtbx/refinement/data.py +++ b/mmtbx/refinement/data.py @@ -11,8 +11,7 @@ def __init__(self, fmodel, sites_cart = False, u_iso = False, - occupancy = False, - selection = None): + occupancy = False): adopt_init_args(self, locals()) self.scatterers = self.fmodel.xray_structure.scatterers() self.size = self.scatterers.size() @@ -34,7 +33,11 @@ def get_x(self): def _set_flags(self, scf, selection): assert [self.sites_cart, self.u_iso, self.occupancy].count(True) == 1 + + #self.scatterers = self.fmodel.xray_structure.scatterers() + self.scatterers.flags_set_grads(state=False) + if selection is not None: assert isinstance(selection, flex.bool) self.selection = selection diff --git a/mmtbx/refinement/minimization.py b/mmtbx/refinement/minimization.py index ad361c69f9..3b3db5bf41 100644 --- a/mmtbx/refinement/minimization.py +++ b/mmtbx/refinement/minimization.py @@ -59,7 +59,7 @@ def __init__(self, fmodels, elif(refine_adp and target_weights is not None): self.weights = target_weights.adp_weights_result else: - from phenix.refinement import weights + from mmtbx.refinement import weights self.weights = weights.weights(wx = 1, wx_scale = 1, w = 0) if(self.collect_monitor): self.monitor = monitor( diff --git a/mmtbx/refinement/occupancies.py b/mmtbx/refinement/occupancies.py index 1f6b65a194..3b9d52495b 100644 --- a/mmtbx/refinement/occupancies.py +++ b/mmtbx/refinement/occupancies.py @@ -132,7 +132,7 @@ def __init__(self, adopt_init_args(self, locals()) self.fmodels.create_target_functors() self.fmodels.prepare_target_functors_for_minimization() - from phenix.refinement import weights + from mmtbx.refinement import weights self.weights = weights.weights(wx = 1, wx_scale = 1, w = 0) self.par_min = self.par_initial.deep_copy() self.x = self.pack(self.par_min) diff --git a/mmtbx/refinement/wrappers.py b/mmtbx/refinement/wrappers.py index 0d8cd5c1f2..b3c1a4d326 100644 --- a/mmtbx/refinement/wrappers.py +++ b/mmtbx/refinement/wrappers.py @@ -4,8 +4,17 @@ import mmtbx.refinement.data from mmtbx.refinement import calculators from cctbx import adptbx +from libtbx.utils import user_plus_sys_time +from libtbx.str_utils import format_value +import sys +import libtbx.log +from scitbx.array_family import flex +import mmtbx.refinement.restraints +import mmtbx.refinement.weights +from libtbx import group_args +import mmtbx.refinement.refinement_flags -class unrestrained_qb_fsr(object): +class unrestrained_qbr_fsr(object): """ Unrestrained sequential occupancy (q) and isotropic ADP (b) refinement. Use example: refinement of ocupancy and B-factors of newly placed water only. @@ -13,6 +22,7 @@ class unrestrained_qb_fsr(object): """ def __init__(self, fmodel, + model, selection, refine_q = True, refine_b = True, @@ -27,14 +37,27 @@ def __init__(self, log = None): adopt_init_args(self, locals()) data = mmtbx.refinement.data.fs(fmodel = fmodel) + restraints = mmtbx.refinement.restraints.manager(model = model) + # + rt_old = model.get_refinement_flags() + rf = mmtbx.refinement.refinement_flags.manager( # This is ugly!! + individual_sites = True, + individual_adp = True, + occupancies = True, + sites_individual = flex.bool(model.size(), True), + adp_individual_iso = flex.bool(model.size(), True), + s_occupancies = flex.bool(model.size(), True)) + model.set_refinement_flags(flags = rf) + # for micro_cycle in range(macro_cycles): # Occupancy if refine_q: calculator = calculators.occ( - data = data, - selection = selection, - q_min = q_min, - q_max = q_max).calculator() + data = data, + restraints = restraints, + selection = selection, + q_min = q_min, + q_max = q_max).calculator() minimized = minimizers.lbfgsb( calculator = calculator, max_iterations = max_iterations) @@ -44,10 +67,11 @@ def __init__(self, # ADP if refine_b: calculator = calculators.adp( - data = data, - selection = selection, - u_min = adptbx.b_as_u(b_min), - u_max = adptbx.b_as_u(b_max)).calculator() + data = data, + restraints = restraints, + selection = selection, + u_min = adptbx.b_as_u(b_min), + u_max = adptbx.b_as_u(b_max)).calculator() minimized = minimizers.lbfgsb( calculator = calculator, max_iterations = max_iterations) @@ -57,12 +81,149 @@ def __init__(self, # XYZ if refine_xyz: calculator = calculators.xyz( - data = data, - selection = selection, - max_shift = max_xyz_shift).calculator() + data = data, + restraints = restraints, + selection = selection, + max_shift = max_xyz_shift).calculator() minimized = minimizers.lbfgsb( calculator = calculator, max_iterations = max_iterations) if log is not None: print("xyz: r_work=%6.4f r_free=%6.4f"%( fmodel.r_work(), fmodel.r_free()), file = log) + # UGLY. Make sure to re-store flags + model.set_refinement_flags(flags = rt_old) + +class simple_fsr(object): + def __init__(self, + model, + fmodel, + sites_cart_list, + refine_xyz = True, + refine_adp = True, + twin_laws = [None,], + macro_cycles = 3, + max_iterations = 25, + update_all_scales = True, + update_mask = True, + max_xyz_shift = 5., + b_min = 1, + b_max = 200, + log = sys.stdout): + adopt_init_args(self, locals()) + self.ma = libtbx.log.manager(log = self.log) + self.total_time = 0 + self.r_work = None + self.r_free = None + self.data = None + self.u_iso_start = None + self.xyz_restraints = False + self.weights = None + self.results = [] + self._call(msg="Check and setup", func=self._check_and_setup) + + def _check_and_setup(self): + assert self.model.get_xray_structure() == self.fmodel.xray_structure + self.data = mmtbx.refinement.data.fs(fmodel = self.fmodel) + assert len(self.sites_cart_list)>0 and isinstance( + self.sites_cart_list[0], flex.vec3_double) + assert len(set([_.size() for _ in self.sites_cart_list])) == 1 + assert self.model.size() == self.sites_cart_list[0].size() + assert self.model.get_xray_structure().is_similar(self.fmodel.xray_structure) + self.u_iso_start = \ + self.fmodel.xray_structure.extract_u_iso_or_u_equiv().deep_copy() + self.restraints = mmtbx.refinement.restraints.manager(model = self.model) + self._update_r_factors() + + def run(self): + n = len(self.sites_cart_list) + for i, sites_cart in enumerate(self.sites_cart_list): + self._call( + msg="Refining sites %d out of %d"%(i,n), func=None) + self._call(msg="set sites ", func=self._set_sites_cart, args=sites_cart) + self._call(msg="weights ", func=self._compute_weights) + self._macrocycle() + self.results.append( + group_args( + sites_cart_start = sites_cart, + sites_cart_final = self.fmodel.xray_structure.sites_cart(), + r_work = self.fmodel.r_work(), + r_free = self.fmodel.r_free() + ) + ) + + def _macrocycle(self): + for mc in range(self.macro_cycles): + self._call(msg="refine xyz", func=self._refine_xyz) + self._call(msg="refine adp", func=self._refine_adp) + + def _call(self, msg, func = None, args=None): + timer = user_plus_sys_time() + if(func is not None): + if args is None: func() + else: func(args) + assert self.model.get_xray_structure() == self.fmodel.xray_structure + self._update_r_factors() + t = timer.elapsed() + self.total_time += t + self.ma.add_and_show( self._format_msg(m=msg, t=t) ) + + def _format_msg(self, m, t): + m1 = "r_work: %6s r_free: %6s"%(format_value("%6.4f",self.r_work), + format_value("%6.4f",self.r_free)) + m2 = "time: %6.3f total time: %6.3f"%(t, self.total_time) + l = "%s | %s | %s"%(m, m1, m2) + return l + + def _compute_weights(self): + params = mmtbx.refinement.weights.master_params.extract() + self.weights = mmtbx.refinement.weights.weight( + fmodel = self.fmodel, + model = self.model, + correct_special_position_tolerance = 1.0, + target_weights_params = params, + macro_cycle = 2, + show_summary = False, + log = self.log) + + def _update_r_factors(self): + self.r_work, self.r_free = self.fmodel.r_work(), self.fmodel.r_free() + + def _set_sites_cart(self, sites_cart): + self.model.set_sites_cart(sites_cart = sites_cart) + self.model.set_b_iso(values = self.u_iso_start * adptbx.u_as_b(1)) + self.fmodel.update_xray_structure( + xray_structure = self.model.get_xray_structure(), + update_f_calc = True, + update_f_mask = self.update_mask) + if(self.update_all_scales): + self.fmodel.update_all_scales(remove_outliers=False) + + def _refine_xyz(self): + if not self.refine_xyz: return + weights = self.weights.xyz_weights_result + wx = weights.wx * weights.wx_scale + calculator = calculators.xyz( + data = self.data, + data_weight = wx, + restraints_weight = weights.w, + restraints = self.restraints, + max_shift = self.max_xyz_shift).calculator() + minimized = minimizers.lbfgsb( + calculator = calculator, + max_iterations = self.max_iterations) + + def _refine_adp(self): + if not self.refine_adp: return + weights = self.weights.adp_weights_result + wx = weights.wx * weights.wx_scale + calculator = calculators.adp( + data = self.data, + data_weight = wx, + restraints_weight = weights.w, + restraints = self.restraints, + u_min = adptbx.b_as_u(self.b_min), + u_max = adptbx.b_as_u(self.b_max)).calculator() + minimized = minimizers.lbfgsb( + calculator = calculator, + max_iterations = self.max_iterations) diff --git a/mmtbx/regression/tst_mmtbx_refinement_wrappers.py b/mmtbx/regression/tst_mmtbx_refinement_wrappers.py index 3ed4ae6f4e..646992e5c0 100644 --- a/mmtbx/regression/tst_mmtbx_refinement_wrappers.py +++ b/mmtbx/regression/tst_mmtbx_refinement_wrappers.py @@ -105,8 +105,9 @@ def run(): sf_and_grads_accuracy_params = sfg_params) print("r_work=%6.4f r_free=%6.4f"%(fmodel.r_work(), fmodel.r_free())) # - o = wrappers.unrestrained_qb_fsr( + o = wrappers.unrestrained_qbr_fsr( fmodel = fmodel, + model = model, selection = sel, log = sys.stdout, macro_cycles = 20) diff --git a/mmtbx/solvent/ordered_solvent.py b/mmtbx/solvent/ordered_solvent.py index 9f5ffdea89..f15fecb42b 100644 --- a/mmtbx/solvent/ordered_solvent.py +++ b/mmtbx/solvent/ordered_solvent.py @@ -16,6 +16,7 @@ from mmtbx.solvent import map_to_water from libtbx import group_args import string +import libtbx.log def get_unique_altloc(exclude): for l in string.ascii_uppercase: @@ -161,33 +162,6 @@ def get_unique_altloc(exclude): .expert_level=2 """ % (output_params_str, h_bond_params_str, adp_occ_params_str) -# XXX -# XXX Consolidate with phenix.douse and may be more -# XXX -class msg_accumulator(object): - def __init__(self, log=None): - self.log = log - self.messages = [] - self.prefix="" - - def set_prefix(self, prefix): - self.prefix=prefix - - def add(self, msg): - msg = "%s%s"%(self.prefix, msg) - self.messages.append(msg) - if(self.log is not None): print(msg, file=self.log) - - def show(self, log=None): - assert [self.log, log].count(None) == 1 - if(log is not None): - assert self.log is None - else: - assert self.log is not None - log = self.log - for msg in self.messages: - print(msg, file=log) - def master_params(): return iotbx.phil.parse(master_params_str) @@ -446,7 +420,7 @@ def __init__(self, fmodel, self.find_peaks_params.map_next_to_model.min_model_peak_dist=0.5 self.find_peaks_params.map_next_to_model.min_peak_peak_dist=0.5 - self.ma = msg_accumulator(log = self.log) + self.ma = libtbx.log.manager(log = self.log) self.total_time = 0 self._maps = None self._peaks = None @@ -467,7 +441,7 @@ def __init__(self, fmodel, def _call(self, msg, func = None): timer = user_plus_sys_time() - self.ma.add(msg) + self.ma.add_and_show(msg) self._assert_same_model() if(func is not None): func() self._get_and_set_n_water_and_sync_fmodel_and_model_and_update_maps() @@ -479,7 +453,7 @@ def _call(self, msg, func = None): def _add_to_message(self, this_step_time): rs="r_work=%6.4f r_free=%6.4f"%(self.fmodel.r_work(), self.fmodel.r_free()) nw="n_water=%3d"%(self.n_water) - self.ma.add(" %s | %s | time (s): %s (total time: %s)"%(rs, nw, + self.ma.add_and_show(" %s | %s | time (s): %s (total time: %s)"%(rs, nw, ("%8.3f"%this_step_time).strip(), ("%8.3f"%self.total_time).strip())) def _get_and_set_n_water_and_sync_fmodel_and_model_and_update_maps(self): @@ -702,8 +676,10 @@ def refine_oat(self): if(self.params.refine_adp and self.params.refine_occupancies and self.new_solvent_selection.count(True)>0): from mmtbx.refinement import wrappers - o = wrappers.unrestrained_qb_fsr( + o = wrappers.unrestrained_qbr_fsr( fmodel = self.fmodel, + model = self.model, + refine_xyz = True, selection = self.new_solvent_selection, q_min = 0.004, b_max = 60, From 4b1543853a1821206e68090a101d1a59fe862a03 Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Thu, 9 May 2024 22:28:59 -0700 Subject: [PATCH 449/748] More calculators for new refinement moduli that use lbfgsb and tests --- mmtbx/refinement/restraints.py | 120 +++++ mmtbx/refinement/weights.py | 496 ++++++++++++++++++ .../tst_mmtbx_refinement_wrappers_1.py | 140 +++++ mmtbx/run_tests.py | 1 + 4 files changed, 757 insertions(+) create mode 100644 mmtbx/refinement/restraints.py create mode 100644 mmtbx/refinement/weights.py create mode 100644 mmtbx/regression/tst_mmtbx_refinement_wrappers_1.py diff --git a/mmtbx/refinement/restraints.py b/mmtbx/refinement/restraints.py new file mode 100644 index 0000000000..73fa124242 --- /dev/null +++ b/mmtbx/refinement/restraints.py @@ -0,0 +1,120 @@ +from __future__ import absolute_import, division +from cctbx.array_family import flex +from libtbx import adopt_init_args +from cctbx import adptbx + +class manager(object): + """ + Refinement restraints: restraints manager + refinable parameter limits + """ + def __init__(self, + model): + adopt_init_args(self, locals()) + self._restraints = None + self._lower_bound = None + self._upper_bound = None + self._bound_flags = None + self._use_xyz = None + self._use_adp = None + self._use_occ = None + + def set_flags(self, use_xyz=False, use_adp=False, use_occ=False): + self._use_xyz = use_xyz + self._use_adp = use_adp + self._use_occ = use_occ + + def check_flags(self): + assert [self._use_xyz, self._use_adp, self._use_occ].count(True) == 1 + + def check_selection(self, selection): + if selection is not None: + assert isinstance(selection, flex.bool) + assert self.model.size() == selection.size() + + def set_use_xyz(self, selection = None, max_shift = 3.0): + self.set_flags(use_xyz=True) + self.check_selection(selection) + x = flex.vec3_double( self.get_x() ) + max_shift = flex.vec3_double(x.size(), [max_shift, max_shift, max_shift]) + self._lower_bound = x.deep_copy() + self._upper_bound = x.deep_copy() + if selection is not None: + self._lower_bound.set_selected(selection, x-max_shift) + self._upper_bound.set_selected(selection, x+max_shift) + else: + self._lower_bound = x-max_shift + self._upper_bound = x+max_shift + self.x = x.as_double() + self._lower_bound = self._lower_bound.as_double() + self._upper_bound = self._upper_bound.as_double() + self._bound_flags = flex.int(x.size()*3, 2) + self._restraints = self.model.restraints_manager_energies_sites( + compute_gradients=True) + + def get_x(self): + self.check_flags() + xrs = self.model.get_xray_structure() + if self._use_xyz: return xrs.sites_cart().as_double() + elif self._use_adp: return xrs.extract_u_iso_or_u_equiv() + elif self._use_occ: return xrs.scatterers().extract_occupancies() + else: assert 0 + + def set_use_adp(self, selection=None, b_min=1, b_max=200): + self.set_flags(use_adp=True) + self.check_selection(selection) + x = self.get_x() + u_min, u_max = adptbx.b_as_u(b_min), adptbx.b_as_u(b_max) + self._lower_bound = x.deep_copy() + self._upper_bound = x.deep_copy() + if selection is not None: + self._lower_bound.set_selected(selection, u_min) + self._upper_bound.set_selected(selection, u_max) + else: + self._lower_bound = flex.double(x.size(), u_min) + self._upper_bound = flex.double(x.size(), u_max) + self._bound_flags = flex.int(x.size(), 2) + self._restraints = self.model.energies_adp( + iso_restraints = None, + use_hd = self.model.is_neutron(), + compute_gradients = True) + + def set_use_occ(self, selection=None, q_min=0.004, q_max=1.0): + self.set_flags(use_occ=True) + self.check_selection(selection) + x = self.get_x() + self._lower_bound = x.deep_copy() + self._upper_bound = x.deep_copy() + if selection is not None: + self._lower_bound.set_selected(selection, q_min) + self._upper_bound.set_selected(selection, q_max) + else: + self._lower_bound = flex.double(x.size(), q_min) + self._upper_bound = flex.double(x.size(), q_max) + self._bound_flags = flex.int(x.size(), 2) + self._restraints = None + + def lower_bound(self): + return self._lower_bound + + def upper_bound(self): + return self._upper_bound + + def bound_flags(self): + return self._bound_flags + + def update(self, x): + assert 0 + + def target(self): + if self._restraints is None: return None + if self._use_xyz: return self._restraints.target + elif self._use_adp: return self._restraints.target + elif self._use_occ: return None + else: assert 0 + + def gradients(self): + if self._restraints is None: return None + if self._use_xyz: return self._restraints.gradients.as_double() + elif self._use_adp: return self._restraints.u_iso_gradients + elif self._use_occ: return None + else: assert 0 diff --git a/mmtbx/refinement/weights.py b/mmtbx/refinement/weights.py new file mode 100644 index 0000000000..e93a054131 --- /dev/null +++ b/mmtbx/refinement/weights.py @@ -0,0 +1,496 @@ +from __future__ import division, print_function +from mmtbx.refinement import print_statistics +from cctbx.array_family import flex +from libtbx import adopt_init_args +import math +import sys +from libtbx.utils import Sorry, user_plus_sys_time +from libtbx.str_utils import format_value +import iotbx.phil + + +time_weights_xray_chem_py = 0.0 + +core_params_str = """ + optimize_xyz_weight = False + .alias = optimise_xyz_weight + .type = bool + .short_caption = Optimize X-ray/stereochemistry weight + .style = bold noauto + optimize_adp_weight = False + .alias = optimise_adp_weight + .type = bool + .short_caption = Optimize X-ray/ADP weight + .style = bold noauto + wxc_scale = 0.5 + .type = float + .optional = False + .short_caption = Scale factor for X-ray/stereochemistry weight (wxc_scale) + wxu_scale = 1.0 + .type = float + .optional = False + .short_caption = Scale factor for X-ray/ADP weight (wxu_scale) + wc = 1.0 + .type = float + .optional = False + .short_caption = Stereochemistry weight scale (wc) + wu = 1.0 + .type = float + .optional = False + .short_caption = ADP weight scale (wu) + fix_wxc = None + .type = float + .short_caption = Fix X-ray/stereochemistry weight (wxc) + fix_wxu = None + .type = float + .short_caption = Fix X-ray/ADP weight (wxu) + shake_sites = True + .type = bool + .expert_level=3 + shake_adp = 10.0 + .type = float + .short_caption = Shake ADPs + .expert_level=3 + regularize_ncycles = 50 + .type = int + .expert_level=3 + .short_caption = Number of regularization cycles + verbose = 1 + .type = int + wnc_scale = 0.5 + .type = float + .optional = False + .short_caption = Scale factor for neutron/stereochemistry weight (wnc_scale) + wnu_scale = 1.0 + .type = float + .optional = False + .short_caption = Scale factor for neutron/ADP weight (wnu_scale) + rmsd_cutoff_for_gradient_filtering = 3.0 + .type = float + .expert_level=3 + .short_caption = RMSD cutoff for gradient filtering + force_optimize_weights = False + .type = bool + .expert_level = 3 + .style = hidden +""" + +master_params_str = """\ +%s + weight_selection_criteria + .style = box + { + bonds_rmsd = None + .type=float + .short_caption = RMS(bonds) + angles_rmsd = None + .type=float + .short_caption = RMS(angles) + r_free_minus_r_work = None + .type=float + .short_caption = R_free - R_work + r_free_range_width = None + .type = float + .short_caption = R-free range width + mean_diff_b_iso_bonded_fraction = None + .type = float + min_diff_b_iso_bonded = None + .type = float + } +"""%core_params_str + +master_params = iotbx.phil.parse(master_params_str) + +class weights(object): + def __init__(self, + wx = None, + wx_scale = None, + angle_x = None, + wn = None, + wn_scale = None, + angle_n = None, + w = None, + wxn = None, + angle_xn = None, + angle_xnr = None): + adopt_init_args(self, locals()) + +class show(object): + def __init__(self, adp = None, xyz = None, log = None): + if(log is None): log = sys.stdout + if([xyz, adp].count(None)==0): + print("|"+"-"*77+"|", file=log) + if(xyz is not None): + if(xyz.wn is not None): + print("| XYZ refinement: T = (Exray*wxc_scale + Eneutron*wnc_scale)*wxnc + Echem*wc |", file=log) + print("| wxnc = %s wxc scale = %s wnc scale = %s wc = %s |" % self.format_4_values(obj = xyz), file=log) + print("|-----------------------------------------------------------------------------|", file=log) + else: + print("| XYZ refinement: T = Eexperimental * wxc * wxc_scale + Echem * wc"+" "*12+"|", file=log) + print("| wxc = %s wxc_scale = %s wc = %s |" % self.format_3_values(obj = xyz), file=log) + if(adp is not None): + if(adp.wn is not None): + print("| ADP refinement: T = (Exray*wxu_scale + Eneutron*wnu_scale)*wxnu + Eadp *wu |", file=log) + print("| wxnu = %s wxu scale = %s wnu scale = %s wu = %s |" % self.format_4_values(obj = adp), file=log) + else: + if(xyz is not None): print("|"+" "*77+"|", file=log) + print("| ADP refinement: T = Eexperimental * wxu * wxu_scale + Eadp * wu"+" "*12+"|", file=log) + print("| wxu = %s wxu_scale = %s wu = %s |" % self.format_3_values(obj = adp), file=log) + print("|"+"-"*77+"|", file=log) + print(file=log) + + def format_3_values(self, obj): + return (format_value("%-15.6f",obj.wx), + format_value("%-10.3f",obj.wx_scale), + format_value("%-10.3f",obj.w)) + + def format_4_values(self, obj): + return (format_value("%-8.6f",obj.wxn), + format_value("%-8.3f",obj.wx_scale), + format_value("%-8.3f",obj.wn_scale), + format_value("%-6.3f",obj.w)) + +class adp_gradients(object): + def __init__(self, fmodel, + model, + iso_restraints, + shake): + fmodel_dc = fmodel.deep_copy() + xray_structure = fmodel_dc.xray_structure + sel_i = model.refinement_flags.adp_individual_iso + sel_a = model.refinement_flags.adp_individual_aniso + if model.ias_manager is not None: + ias_selection = model.ias_manager.get_ias_selection() + if ias_selection is not None: + xray_structure = xray_structure.select(~ias_selection) + sel_i = sel_i.select(~ias_selection) + sel_a = sel_a.select(~ias_selection) + restraints_manager = model.restraints_manager + hd_sel = xray_structure.hd_selection() + if(hd_sel.count(True) > 0 and hd_sel.count(True) != hd_sel.size()): + if(sel_i is not None): + sel_i = sel_i.select(~hd_sel) + if(sel_a is not None): + sel_a = sel_a.select(~hd_sel) + xray_structure = xray_structure.select(~hd_sel) + restraints_manager = model.restraints_manager.select(~hd_sel) + pp = restraints_manager.geometry.pair_proxies(sites_cart = + xray_structure.sites_cart()) + xray_structure.shake_adp_if_all_equal(b_iso_tolerance = 1.e-3) + if(shake): + xray_structure.shake_adp(spread=shake, keep_anisotropic= False) + scatterers = xray_structure.scatterers() + scatterers.flags_set_grads(state=False) + # heavy atoms may overwhelm gradients + scat_types = xray_structure.scatterers().extract_scattering_types() + sel_use = (scat_types == "C") | (scat_types == "N") | (scat_types == "O") |\ + (scat_types == "S") | (scat_types == "P") + if(sel_i is not None): + if((sel_i & sel_use).count(True)>0): + sel_i = sel_i & sel_use + scatterers.flags_set_grad_u_iso(iselection = sel_i.iselection()) + if(sel_a is not None): + if((sel_a & sel_use).count(True)>0): + sel_a = sel_a & sel_use + scatterers.flags_set_grad_u_aniso(iselection = sel_a.iselection()) + fmodel_dc.update_xray_structure(xray_structure = xray_structure, + update_f_calc = True) + gxu = fmodel_dc.one_time_gradients_wrt_atomic_parameters().packed() + gu = None + if(sel_a is None or sel_a.count(True) == 0): + restraints_manager.geometry.pair_proxies(sites_cart = + xray_structure.sites_cart()) + energies_adp = restraints_manager.energies_adp_iso( + xray_structure = xray_structure, + parameters = iso_restraints, + use_u_local_only = iso_restraints.use_u_local_only, + use_hd = model.is_neutron(), + compute_gradients = True) + if(sel_i is not None): + gu = energies_adp.gradients.as_double().select(sel_i) + else: + restraints_manager.geometry.pair_proxies(sites_cart = + xray_structure.sites_cart()) + energies_adp = restraints_manager.energies_adp_aniso( + xray_structure = xray_structure, + compute_gradients = True) + gu_i = None + if(sel_a is not None): + gu = energies_adp.gradients_aniso_star.select(sel_a).as_double() + gu_i = energies_adp.gradients_iso + if(gu_i is not None): + if(sel_i is not None): + gu_i = gu_i.select(sel_i).as_double() + gu.extend(gu_i) + self.gu = gu + self.gxu = gxu + if([self.gu,self.gxu].count(None)==0): + assert self.gu.size() == self.gxu.size() + +class site_gradients(object): + def __init__(self, fmodel, + model, + correct_special_position_tolerance, + cartesian_dynamics_parameters, + shake, + regularize_ncycles, + rmsd_cutoff_for_gradient_filtering, + gradient_filtering = False, + log=None): + fmodel_dc = fmodel.deep_copy() + xray_structure = fmodel_dc.xray_structure + sel_si = model.refinement_flags.sites_individual + sel_sta = model.refinement_flags.sites_torsion_angles + sel_count = [sel_si, sel_sta].count(None) + assert sel_count != 2 + if (sel_count == 0): + if (not sel_si.all_eq(sel_sta)): + raise Sorry( + "Not implemented: support for different sites.individual" + " and sites.torsion_angles selections.") + sel = sel_si + elif (sel_si is not None): + sel = sel_si + else: + sel = sel_sta + if model.ias_manager is not None: + ias_selection = model.ias_manager.get_ias_selection() + if ias_selection is not None: + xray_structure = xray_structure.select(~ias_selection) + sel = sel.select(~ias_selection) + assert sel.count(True) > 0 + restraints_manager = model.restraints_manager + if(shake): + from phenix.refinement import memory_eraser + geometry = getattr(restraints_manager, "geometry", None) + xray_structure = memory_eraser.shake_sites( + cartesian_dynamics_parameters = cartesian_dynamics_parameters, + restraints_manager = geometry, + xray_structure = xray_structure, + max_iterations = regularize_ncycles, + neutron = model.is_neutron(), + log=log, + verbose=0) + scatterers = xray_structure.scatterers() + scatterers.flags_set_grads(state=False) + scatterers.flags_set_grad_site(iselection = sel.iselection()) + fmodel_dc.update_xray_structure(xray_structure = xray_structure, + update_f_calc = True, update_f_mask = True) + gxc = flex.vec3_double( + fmodel_dc.one_time_gradients_wrt_atomic_parameters(site = True).packed()) + gco = restraints_manager.energies_sites( + sites_cart = xray_structure.sites_cart(), + compute_gradients = True, + hd_selection = xray_structure.hd_selection(), # need for afitt + ) + gc=gco.gradients + self.gc = gc.select(sel) + self.gxc = gxc + assert self.gc.size() == self.gxc.size() + assert self.gc.size() == self.gxc.size() + self.gc_filtered = None + self.gxc_filtered = None + if(gradient_filtering): + self.gc_filtered = flex.sqrt(self.gc.dot()) + gxc_f = flex.sqrt(self.gxc.dot()) + gxc_f_mean = flex.mean(gxc_f) + #gxc_rms = math.sqrt(flex.mean(self.gxc.dot())) + if(rmsd_cutoff_for_gradient_filtering is None): + raise Sorry("rmsd_cutoff_for_gradient_filtering is set to None but a number is expected.") + gxc_f_selection = (gxc_f < gxc_f_mean*rmsd_cutoff_for_gradient_filtering) + self.gxc_filtered = gxc_f.select(gxc_f_selection) + +class weight: + def __init__(self, fmodel, + model, + correct_special_position_tolerance, + target_weights_params, + macro_cycle, + cartesian_dynamics_parameters = None, + iso_restraints = None, + amber_params = None, + log = None, + show_summary = True): + global time_weights_xray_chem_py + timer = user_plus_sys_time() + adopt_init_args(self, locals()) + self.compute_wxc = self.model.refinement_flags.individual_sites \ + or self.model.refinement_flags.torsion_angles + self.compute_wxu = self.model.refinement_flags.individual_adp + self.twp = self.target_weights_params + + if self.iso_restraints is None: + import mmtbx.refinement.adp_refinement + self.iso_restraints = mmtbx.refinement.adp_refinement.\ + adp_restraints_master_params.extract().iso + + self.special_case = False + d_min = self.fmodel.f_obs().d_min() + if(self.macro_cycle>1 and self.twp.fix_wxc is None and + d_min>=3.5 and d_min<=4.5): + self.special_case = True + + + if(self.log is None): self.log = sys.stdout + gxc = None + gxu = None + gc = None + gu = None + self.adp_weights_result = self.adp_weights() + wxu = self.adp_weights_result.wx + wu = self.adp_weights_result.w + self.xyz_weights_result = self.xyz_weights(log=log) + wxc = self.xyz_weights_result.wx + wc = self.xyz_weights_result.w + if(show_summary): + show(xyz = self.xyz_weights_result, adp = self.adp_weights_result, + log = self.log) + time_weights_xray_chem_py += timer.elapsed() + + def xyz_weights(self, log=None): + wxc = None + wxc_scale = self.twp.wxc_scale#None + angle_xc = None + wc = None + if(self.compute_wxc and self.model.restraints_manager is not None): + wc = self.twp.wc + if(self.twp.wxc_scale != 0.0 and + self.twp.fix_wxc is None and + self.twp.wc != 0.0 + ): + if self.special_case: + result_a = site_gradients( + fmodel = self.fmodel, + model = self.model, + correct_special_position_tolerance=self.correct_special_position_tolerance, + cartesian_dynamics_parameters = self.cartesian_dynamics_parameters, + shake = False, + regularize_ncycles = self.twp.regularize_ncycles, + rmsd_cutoff_for_gradient_filtering = self.twp.rmsd_cutoff_for_gradient_filtering, + gradient_filtering = False, + log=self.log) + angle_xc = self.angle(result_a.gxc, result_a.gc) + result = site_gradients( + fmodel = self.fmodel, + model = self.model, + correct_special_position_tolerance=self.correct_special_position_tolerance, + cartesian_dynamics_parameters = self.cartesian_dynamics_parameters, + regularize_ncycles = self.twp.regularize_ncycles, + shake = self.twp.shake_sites, + rmsd_cutoff_for_gradient_filtering = self.twp.rmsd_cutoff_for_gradient_filtering, + gradient_filtering = True, + log=self.log) + gc = result.gc_filtered + gxc = result.gxc_filtered + gc_norm = gc.norm() + gxc_norm = gxc.norm() + if math.isnan(gc_norm): raise Sorry("Norm of gc gradients is %s" % gc_norm) + if math.isnan(gxc_norm): raise Sorry("Norm of gxc gradients is %s" % gxc_norm) + if(gxc_norm != 0.0): + wxc = gc_norm / gxc_norm + else: + wxc = 1.0 + if self.amber_params and self.amber_params.use_amber: + if wxc > 1000: raise Sorry("wxc is too high: wxc=%f" %wxc) + print(" Setting wxc_scale using amber.wxc_factor : %0.3f * %0.3f = %0.3f" % ( + wxc_scale, + self.amber_params.wxc_factor, + wxc_scale*self.amber_params.wxc_factor, + ), file=log) + wxc_scale *= self.amber_params.wxc_factor + elif(self.twp.fix_wxc is not None): + wxc = self.twp.fix_wxc + wxc_scale = 1.0 + elif(self.twp.wxc_scale == 0.0): + wxc = 0.0 + elif(self.twp.wc == 0.0): + wxc = 1.0 + wc = 0.0 + wnc = 1.0 + wxnc = 1.0 + wxc_scale = 1.0 + else: + raise Sorry("Wrong parameter type, value or combination for "+ + "stereochemistry/X-ray weighting.") + else: + wxc = 1.0 + wc = 0.0 + # case-specific: resolutions 3.5-4.5A + if(self.special_case and angle_xc is not None): + wxc_scale_ = math.cos((180-angle_xc)*math.pi/180) + if(wxc_scale_<=0): wxc_scale_=wxc_scale + wxc_scale_ = 0.0204 * math.exp(3.7444*wxc_scale_) + if(wxc_scale_>0): wxc_scale = wxc_scale_ + # + return weights(wx = wxc, + wx_scale = wxc_scale, + w = wc) + + + def adp_weights(self): + wxu = None + wxu_scale = None + wu = None + if(self.compute_wxu): + wu = self.twp.wu + if(self.twp.wxu_scale != 0.0 and self.twp.fix_wxu is None and + self.twp.wu != 0.0): + result = adp_gradients( + fmodel = self.fmodel, + model = self.model, + iso_restraints = self.iso_restraints, + shake = self.twp.shake_adp) + gu = result.gu + gxu = result.gxu + gu_norm = gu.norm() + gxu_norm = gxu.norm() + if(gxu_norm != 0.0): + if(gu_norm != 0): + wxu = gu_norm / gxu_norm + else: + wxu = 1.0 + else: + wxu = 1.0 + elif(self.twp.fix_wxu is not None): + wxu = self.twp.fix_wxu + elif(self.twp.wxu_scale == 0.0): + wxu = 0.0 + elif(self.twp.wu == 0.0): + wxu = 1.0 + wu = 0.0 + else: + raise Sorry("Wrong parameter type, value or combination for "+ + "ADP/X-ray weighting.") + else: + wxu = 1.0 + wu = 0.0 + return weights(wx = wxu, + wx_scale = self.twp.wxu_scale, + w = wu) + + def angle(self, a, b): + if([a,b].count(None) > 0): return None + result = a.as_double().angle(b.as_double()) + if(result is None): return None + return result * 180 / math.pi + +def run( + params, + fmodels, + model, + macro_cycle, + prefix, + log): + print_statistics.make_header(prefix, out = log) + result = weight( + fmodel = fmodels.fmodel_xray(), + model = model, + correct_special_position_tolerance = + params.main.correct_special_position_tolerance, + cartesian_dynamics_parameters = params.cartesian_dynamics, + target_weights_params = params.target_weights, + iso_restraints = params.adp_restraints.iso, + macro_cycle = macro_cycle, + amber_params = getattr(params, "amber", None), + log = log) + return result diff --git a/mmtbx/regression/tst_mmtbx_refinement_wrappers_1.py b/mmtbx/regression/tst_mmtbx_refinement_wrappers_1.py new file mode 100644 index 0000000000..c28acac6db --- /dev/null +++ b/mmtbx/regression/tst_mmtbx_refinement_wrappers_1.py @@ -0,0 +1,140 @@ +from __future__ import division +import iotbx.pdb +import mmtbx.model +import mmtbx.f_model +from scitbx.array_family import flex +import sys, time +from libtbx.utils import null_out +from mmtbx.refinement import wrappers +import mmtbx.refinement.refinement_flags + +import random +random.seed(0) +flex.set_random_seed(0) + +pdb_str = """ +CRYST1 21.937 4.866 23.477 90.00 107.08 90.00 P 1 21 1 2 +ATOM 1 N GLY A 1 -9.009 4.612 6.102 1.00 20.00 N +ATOM 2 CA GLY A 1 -9.052 4.207 4.651 1.00 20.00 C +ATOM 3 C GLY A 1 -8.015 3.140 4.419 1.00 20.00 C +ATOM 4 O GLY A 1 -7.523 2.521 5.381 1.00 20.00 O +ATOM 5 N ASN A 2 -7.656 2.923 3.155 1.00 20.00 N +ATOM 6 CA ASN A 2 -6.522 2.038 2.831 1.00 20.00 C +ATOM 7 C ASN A 2 -5.241 2.537 3.427 1.00 20.00 C +ATOM 8 O ASN A 2 -4.978 3.742 3.426 1.00 20.00 O +ATOM 9 CB ASN A 2 -6.346 1.881 1.341 1.00 20.00 C +ATOM 10 CG ASN A 2 -7.584 1.342 0.692 1.00 20.00 C +ATOM 11 OD1 ASN A 2 -8.025 0.227 1.016 1.00 20.00 O +ATOM 12 ND2 ASN A 2 -8.204 2.155 -0.169 1.00 20.00 N +ATOM 13 N ASN A 3 -4.438 1.590 3.905 1.00 20.00 N +ATOM 14 CA ASN A 3 -3.193 1.904 4.589 1.00 20.00 C +ATOM 15 C ASN A 3 -1.955 1.332 3.895 1.00 20.00 C +ATOM 16 O ASN A 3 -1.872 0.119 3.648 1.00 20.00 O +ATOM 17 CB ASN A 3 -3.259 1.378 6.042 1.00 20.00 C +ATOM 18 CG ASN A 3 -2.006 1.739 6.861 1.00 20.00 C +ATOM 19 OD1 ASN A 3 -1.702 2.925 7.072 1.00 20.00 O +ATOM 20 ND2 ASN A 3 -1.271 0.715 7.306 1.00 20.00 N +ATOM 21 N GLN A 4 -1.005 2.228 3.598 1.00 20.00 N +ATOM 22 CA GLN A 4 0.384 1.888 3.199 1.00 20.00 C +ATOM 23 C GLN A 4 1.435 2.606 4.088 1.00 20.00 C +ATOM 24 O GLN A 4 1.547 3.843 4.115 1.00 20.00 O +ATOM 25 CB GLN A 4 0.656 2.148 1.711 1.00 20.00 C +ATOM 26 CG GLN A 4 1.944 1.458 1.213 1.00 20.00 C +ATOM 27 CD GLN A 4 2.504 2.044 -0.089 1.00 20.00 C +ATOM 28 OE1 GLN A 4 2.744 3.268 -0.190 1.00 20.00 O +ATOM 29 NE2 GLN A 4 2.750 1.161 -1.091 1.00 20.00 N +ATOM 30 N GLN A 5 2.154 1.821 4.871 1.00 20.00 N +ATOM 31 CA GLN A 5 3.270 2.361 5.640 1.00 20.00 C +ATOM 32 C GLN A 5 4.594 1.768 5.172 1.00 20.00 C +ATOM 33 O GLN A 5 4.768 0.546 5.054 1.00 20.00 O +ATOM 34 CB GLN A 5 3.056 2.183 7.147 1.00 20.00 C +ATOM 35 CG GLN A 5 1.829 2.950 7.647 1.00 20.00 C +ATOM 36 CD GLN A 5 1.344 2.414 8.954 1.00 20.00 C +ATOM 37 OE1 GLN A 5 0.774 1.325 9.002 1.00 20.00 O +ATOM 38 NE2 GLN A 5 1.549 3.187 10.039 1.00 20.00 N +ATOM 39 N ASN A 6 5.514 2.664 4.856 1.00 20.00 N +ATOM 40 CA ASN A 6 6.831 2.310 4.318 1.00 20.00 C +ATOM 41 C ASN A 6 7.854 2.761 5.324 1.00 20.00 C +ATOM 42 O ASN A 6 8.219 3.943 5.374 1.00 20.00 O +ATOM 43 CB ASN A 6 7.065 3.016 2.993 1.00 20.00 C +ATOM 44 CG ASN A 6 5.961 2.735 2.003 1.00 20.00 C +ATOM 45 OD1 ASN A 6 5.798 1.604 1.551 1.00 20.00 O +ATOM 46 ND2 ASN A 6 5.195 3.747 1.679 1.00 20.00 N +ATOM 47 N TYR A 7 8.292 1.817 6.147 1.00 20.00 N +ATOM 48 CA TYR A 7 9.159 2.144 7.299 1.00 20.00 C +ATOM 49 C TYR A 7 10.603 2.331 6.885 1.00 20.00 C +ATOM 50 O TYR A 7 11.041 1.811 5.855 1.00 20.00 O +ATOM 51 CB TYR A 7 9.061 1.065 8.369 1.00 20.00 C +ATOM 52 CG TYR A 7 7.665 0.929 8.902 1.00 20.00 C +ATOM 53 CD1 TYR A 7 6.771 0.021 8.327 1.00 20.00 C +ATOM 54 CD2 TYR A 7 7.210 1.756 9.920 1.00 20.00 C +ATOM 55 CE1 TYR A 7 5.480 -0.094 8.796 1.00 20.00 C +ATOM 56 CE2 TYR A 7 5.904 1.649 10.416 1.00 20.00 C +ATOM 57 CZ TYR A 7 5.047 0.729 9.831 1.00 20.00 C +ATOM 58 OH TYR A 7 3.766 0.589 10.291 1.00 20.00 O +ATOM 59 OXT TYR A 7 11.358 2.999 7.612 1.00 20.00 O +TER 60 TYR A 7 +HETATM 61 O HOH A 8 -6.471 5.227 7.124 1.00 20.00 O +HETATM 62 O HOH A 9 10.431 1.858 3.216 1.00 20.00 O +HETATM 63 O HOH A 10 -11.286 1.756 -1.468 1.00 20.00 O +HETATM 64 O HOH A 11 11.808 4.179 9.970 1.00 20.00 O +HETATM 65 O HOH A 12 13.605 1.327 9.198 1.00 20.00 O +HETATM 66 O HOH A 13 -2.749 3.429 10.024 1.00 20.00 O +HETATM 67 O HOH A 14 -1.500 0.682 10.967 1.00 20.00 O +END +""" + +def run(): + # Ground truth model + pdb_inp = iotbx.pdb.input(source_info=None, lines=pdb_str) + model = mmtbx.model.manager(model_input = pdb_inp, log = null_out()) + model.process(make_restraints = True) + xrs = model.get_xray_structure() + # Fobs from ground truth model + f_obs = abs(xrs.structure_factors(d_min=1.0).f_calc()) + r_free_flags = f_obs.generate_r_free_flags() + # Generate list of trial sites_cart and shake B factors + sites_cart_list = [] + for it in range(3): + xrs_dc = xrs.deep_copy_scatterers() + xrs_dc.shake_sites_in_place(mean_distance=0.3) + sites_cart_list.append(xrs_dc.sites_cart()) + xrs_dc.shake_adp() + model.set_xray_structure(xrs_dc) + # Set refinement flags + rf = mmtbx.refinement.refinement_flags.manager( + individual_sites = True, + individual_adp = True, + sites_individual = flex.bool(model.size(), True), + adp_individual_iso = flex.bool(model.size(), True)) + model.set_refinement_flags(flags = rf) + # + fmodel = mmtbx.f_model.manager( + f_obs = f_obs, + r_free_flags = r_free_flags, + target_name="ls_wunit_k1", + xray_structure = xrs_dc) + fmodel.update_all_scales() + print("r_work=%6.4f r_free=%6.4f"%(fmodel.r_work(), fmodel.r_free())) + assert model.get_xray_structure() == fmodel.xray_structure + # + # Run refinement + # + o = wrappers.simple_fsr( + model = model, + fmodel = fmodel, + sites_cart_list = sites_cart_list, + log = sys.stdout) + o.run() + # Results + for result in o.results: + print() + print("start xyz:", result.sites_cart_start) + print("final xyz:", result.sites_cart_final) + print("final r_work, r_free:", result.r_work, result.r_free) + print() + +if(__name__ == "__main__"): + t0 = time.time() + run() + print("Time: %6.4f"%(time.time()-t0)) diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index 8be45b46ca..5666db8c38 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -45,6 +45,7 @@ "$D/regression/tls/tst_formula_t_S_10_vs_11_4muy.py", # "$D/regression/tst_mmtbx_refinement_wrappers.py", + "$D/regression/tst_mmtbx_refinement_wrappers_1.py", # "$D/regression/tst_angle.py", "$D/regression/tst_holton_geometry_validation.py", From 4959621180ed252c2fa8d91c2ed375ee71855db3 Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Fri, 10 May 2024 11:03:48 -0700 Subject: [PATCH 450/748] Add 3D filtering and augmentation to cctbx.xfel.powder_from_spots Augmentation: adds pairwise 3D spot distances to the d-spacing histogram. This allows recovery of un-observed peaks (such as low resolution peaks in the beam stop) Filtering: instead of counts, plot the likelihood that a d-spacing is observed together with a reference peak identified by filter.d_max and filter.d_min. This allows removing contaminants in silico. Co-authored-by: Daniel Paley Co-authored-by: David Moreau Co-authored-by: Tess Smidt --- .../command_line/powder_from_spots.py | 16 +++ xfel/small_cell/powder_util.py | 107 +++++++++++++++++- xfel/small_cell/small_cell.py | 4 +- 3 files changed, 121 insertions(+), 6 deletions(-) diff --git a/xfel/small_cell/command_line/powder_from_spots.py b/xfel/small_cell/command_line/powder_from_spots.py index a84e031148..1eff39b0e5 100644 --- a/xfel/small_cell/command_line/powder_from_spots.py +++ b/xfel/small_cell/command_line/powder_from_spots.py @@ -77,6 +77,9 @@ split_panels = False .type = bool .help = Plot a pattern for each detector panel. + augment = False + .type = bool + .help = Plot an additional augmented pattern. xyz_offset = 0. 0. 0. .type = floats .help = origin offset in millimeters @@ -88,6 +91,19 @@ .type = space_group .help = Show positions of miller indices from this unit_cell and space \ group. Not implemented. +filter { + enable = False + .type = bool + .help = Instead of counts, plot the likelihood that a d-spacing is observed \ + together with a reference peak identified by filter.d_max and \ + filter.d_min. + d_max = None + .type = float + .help = Max resolution of the peak to filter on + d_min = None + .type = float + .help = Min resolution of the peak to filter on +} output { log = dials.powder_from_spots.log .type = str diff --git a/xfel/small_cell/powder_util.py b/xfel/small_cell/powder_util.py index df72edf9e9..05f1cb1370 100644 --- a/xfel/small_cell/powder_util.py +++ b/xfel/small_cell/powder_util.py @@ -17,23 +17,37 @@ def __init__(self, experiments, reflections, params): self.reflections = reflections self.experiments = experiments self.params = params - n_panels = len(experiments[0].detector) - self.panelsums = [np.zeros(params.n_bins) for _ in range(n_panels)] + self.n_panels = len(experiments[0].detector) + self.panelsums = [np.zeros(params.n_bins) for _ in range(self.n_panels)] + self.filtered_panelsums = [ + np.zeros(params.n_bins) for _ in range(self.n_panels) + ] + self.antifiltered_panelsums = [ + np.zeros(params.n_bins) for _ in range(self.n_panels) + ] + self.expt_count = 0 + self.filtered_expt_count = 0 + self.antifiltered_expt_count = 0 def _process_pixel(self, i_panel, s0, panel, xy, value): value -= self.params.downweight_weak d_max_inv = 1/self.params.d_max d_min_inv = 1/self.params.d_min res_inv = 1 / panel.get_resolution_at_pixel(s0, xy) + res = 1/res_inv + if self.params.filter.enable: + if self.params.filter.d_max > res > self.params.filter.d_min: + self.filter_counts += 1 n_bins = self.params.n_bins i_bin = int( n_bins * (res_inv - d_max_inv ) / (d_min_inv - d_max_inv) ) if i_bin < 0 or i_bin >= n_bins: return - self.panelsums[i_panel][i_bin] += value + self.current_panelsums[i_panel][i_bin] += value def _nearest_peak(self, x, xvalues, yvalues): i = np.searchsorted(xvalues, x, side="left") + #Exclude (before) first and (after) last points if i < 1 or i >= len(xvalues): print ("Not a valid peak.") @@ -82,6 +96,15 @@ def calculate(self): expt.detector = detector for i, expt in enumerate(expts): + self.current_panelsums = [ + np.zeros(params.n_bins) for _ in range(self.n_panels) + ] + self.filter_counts = 0 + if self.params.filter.d_max is not None: + assert self.params.filter.d_min is not None + self.use_current_expt = False + else: + self.use_current_expt = True if i % 1000 == 0: print("experiment ", i) s0 = expt.beam.get_s0() sel = refls['id'] == i @@ -92,6 +115,7 @@ def calculate(self): shoeboxes = refls_sel['shoebox'] for i_refl in range(len(refls_sel)): + self.expt_count += 1 i_panel = panels[i_refl] panel = expt.detector[i_panel] @@ -108,6 +132,22 @@ def calculate(self): sbpixels = zip(sb.coords(), sb.values()) for (x,y,_), value in sbpixels: self._process_pixel(i_panel, s0, panel, (x,y), value) + for i in range(len(self.panelsums)): + self.panelsums[i] = self.panelsums[i] + self.current_panelsums[i] + if self.params.filter.enable: + use_current_expt = self.filter_counts >= 1 + else: + use_current_expt = True + if use_current_expt: + self.filtered_expt_count += 1 + for i in range(len(self.panelsums)): + self.filtered_panelsums[i] = \ + self.filtered_panelsums[i] + self.current_panelsums[i] + else: + self.antifiltered_expt_count += 1 + for i in range(len(self.panelsums)): + self.antifiltered_panelsums[i] = \ + self.antifiltered_panelsums[i] + self.current_panelsums[i] def plot(self): @@ -125,9 +165,20 @@ def plot(self): for i_sums, sums in enumerate(self.panelsums): yvalues = np.array(sums) plt.plot(xvalues, yvalues+0.5*i_sums*offset) + elif params.filter.enable: + for x in self.filtered_panelsums: + x /= self.filtered_expt_count + for x in self.antifiltered_panelsums: + x /= self.antifiltered_expt_count + yvalues = sum(self.filtered_panelsums) - sum(self.antifiltered_panelsums) + plt.plot(xvalues, yvalues) + else: - yvalues = sum(self.panelsums) + yvalues = sum(self.filtered_panelsums) plt.plot(xvalues, yvalues) + + if params.augment: + plt.plot(*augment(self.experiments, self.reflections, params.d_min, params.d_max)) ax.set_xlim(d_max_inv, d_min_inv) ax.get_xaxis().set_major_formatter(tick.FuncFormatter( lambda x, _: "{:.3f}".format(1/x))) @@ -289,3 +340,51 @@ def search_step(self, step_px, nsteps=3, update=True): print(f'end: {width_end:.5f}') print(f'net shift: {self.net_origin_shift}') return width_start, width_end, self.net_origin_shift + +def augment(expts, refls, d_min, d_max): + """ Add pairwise 3D spot distances to the d-spacing histogram """ + lab = flex.vec3_double() + det = expts[0].detector + filtered = flex.reflection_table() + for panel_id, panel in enumerate(det): + print("Processing panel", panel_id) + subset = refls.select(refls['panel'] == panel_id) + mm = panel.pixel_to_millimeter(flex.vec2_double(*subset['xyzobs.px.value'].parts()[0:2])) + lab.extend(panel.get_lab_coord(mm)) + filtered.extend(subset) + refls = filtered + + s0 = flex.vec3_double(len(refls)) + for expt_id, expt in enumerate(expts): + if expt_id % 500 == 0: + print("Processing experiment", expt_id) + sel = refls['id'] == expt_id + s0.set_selected(sel, expt.beam.get_s0()) + + s1 = lab / lab.norms() * s0.norms() + rlp = s1 - s0 + + refls['rlp'] = rlp + refls['d'] = 1/rlp.norms() + + sel = (refls['d'] >= d_min) & (refls['d'] <= d_max) + refls = refls.select(sel) + print("After filtering by resolution,", len(refls), "reflections remain") + + _, x_sf = np.histogram((1/refls['d']).as_numpy_array(), bins=2000, range = (1/d_max,1/d_min)) + y = None + + for expt_id, expt in enumerate(expts): + if expt_id % 500 == 0: + print("Processing experiment", expt_id) + subset = refls.select(refls['id'] == expt_id) + if len(subset) <= 1: continue + for i in range(len(subset)): + diffs = 1/(subset['rlp']-flex.vec3_double(len(subset), subset['rlp'][i])).norms() + if y is None: + y = np.histogram((1/diffs).as_numpy_array(), bins=2000, range = (1/d_max,1/d_min))[0] + else: + y += np.histogram((1/diffs).as_numpy_array(), bins=2000, range = (1/d_max,1/d_min))[0] + + return x_sf[:-1], y + diff --git a/xfel/small_cell/small_cell.py b/xfel/small_cell/small_cell.py index 3d136c251b..cc218f2f73 100644 --- a/xfel/small_cell/small_cell.py +++ b/xfel/small_cell/small_cell.py @@ -457,8 +457,8 @@ def small_cell_index_lattice_detail(experiments, reflections, horiz_phil): for spot in all_spots: dist = col(spot.spot_dict['radial_lab']).length() - inner = dist - (spot.spot_dict['radial_size']/2) - outer = dist + (spot.spot_dict['radial_size']/2) + inner = dist - (spot.spot_dict['radial_size']/2) # try changing this tolerance? + outer = dist + (spot.spot_dict['radial_size']/2) # try changing this tolerance? # L = 2dsinT inner_angle = math.atan2(inner, col(spot.spot_dict['s0_proj']).length()) From 5700051b2feefa50fe27ad2e70b7d3f277ea3438 Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Fri, 10 May 2024 12:05:33 -0700 Subject: [PATCH 451/748] xfel.fee_calibration: add max_events Also add an extra try/except and a plt.show for command line use --- xfel/command_line/fee_calibration.py | 38 ++++++++++++++++++---------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/xfel/command_line/fee_calibration.py b/xfel/command_line/fee_calibration.py index 718fc292b2..76d896200d 100644 --- a/xfel/command_line/fee_calibration.py +++ b/xfel/command_line/fee_calibration.py @@ -18,11 +18,14 @@ output_phil = None .type = path .help = path where calibrated values should be written as a phil file +max_events = 1000 + .type = int + .help = use at most max_events per run """ phil_scope = parse(fee_phil_string + notch_phil_string) -def tally_fee_data(experiment, runs, plot=True, verbose=True): +def tally_fee_data(experiment, runs, plot=True, verbose=True, max_events=None): """Check each event of each requested run in the specified experiment for a FEE spectrometer event. Report how many events are missing. Return spectrometer data if present.""" good = 0 bad = 0 @@ -37,7 +40,11 @@ def tally_fee_data(experiment, runs, plot=True, verbose=True): times = pr.times() data = None total = 0 - for i in range(len(times)): + if max_events is None: + iterable = range(len(times)) + else: + iterable = range(min(len(times), max_events)) + for i in iterable: e = pr.event(times[i]) f = d.get(e) if f: @@ -90,7 +97,7 @@ def run(args): raise Sorry("Run numbers and known energies must be supplied as colon-separated pairs (without spaces), e.g. \"5:9415 6:9405 7:9395\"") params = phil_scope.fetch(sources=user_phil).extract() - rundata = tally_fee_data(params.experiment, runs, verbose=params.verbose) + rundata = tally_fee_data(params.experiment, runs, verbose=params.verbose, max_events=params.max_events) notches = [find_notch(range(len(data)), data, params.kernel_size, @@ -99,16 +106,21 @@ def run(args): ref_spectrum=params.reference_spectrum) for data in rundata] plot_notches(runs, rundata, notches, params.per_run_plots) - eV_offset, eV_per_pixel = calibrate_energy(notches, energies) - args_str = ' '.join(args) - with open('fee_calib.out', 'a') as outfile: - outfile.write(f'using {args_str}, eV_offset={eV_offset} eV_per_pixel={eV_per_pixel}\n') - print('wrote calibrated values to fee_calib.out') - if params.output_phil: - with open(params.output_phil, 'w') as outfile: - outfile.write(f'spectrum_eV_offset={eV_offset}\n') - outfile.write(f'spectrum_eV_per_pixel={eV_per_pixel}\n') - print(f'wrote calibrated values to {params.output_phil}') + try: + eV_offset, eV_per_pixel = calibrate_energy(notches, energies) + args_str = ' '.join(args) + with open('fee_calib.out', 'a') as outfile: + outfile.write(f'using {args_str}, eV_offset={eV_offset} eV_per_pixel={eV_per_pixel}\n') + print('wrote calibrated values to fee_calib.out') + if params.output_phil: + with open(params.output_phil, 'w') as outfile: + outfile.write(f'spectrum_eV_offset={eV_offset}\n') + outfile.write(f'spectrum_eV_per_pixel={eV_per_pixel}\n') + print(f'wrote calibrated values to {params.output_phil}') + except SystemError as e: + print(e) + if params.per_run_plots: + plt.show() if __name__ == "__main__": import sys From 91e49cb595eae7c21b22b366d2b97b2647bc8faf Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Fri, 10 May 2024 12:09:48 -0700 Subject: [PATCH 452/748] Add fiducials to logging for XTC For use in event matching for radial averages --- xfel/ui/db/frame_logging.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/xfel/ui/db/frame_logging.py b/xfel/ui/db/frame_logging.py index 17b09b9832..2ec660d2fd 100644 --- a/xfel/ui/db/frame_logging.py +++ b/xfel/ui/db/frame_logging.py @@ -107,10 +107,15 @@ def get_run_and_timestamp(self, obj): assert len(imageset) == 1 format_obj = imageset.data().reader().format_class._current_instance_ # XXX try: # XTC specific version - run = str(format_obj.get_run_from_index(imageset.indices()[0])) + import psana + run = str(format_obj.get_run_from_index(imageset.indices()[0]).run()) timestamp = format_obj.get_psana_timestamp(imageset.indices()[0]) - return run.run(), timestamp - except AttributeError: # General version + evt = format_obj._get_event(imageset.indices()[0]) + if evt: + fid = evt.get(psana.EventId).fiducials() + timestamp += ", fid:" + str(fid) + return run, timestamp + except (ImportError, AttributeError): # General version run = self.params.input.run_num timestamp = self.tag return run, timestamp @@ -124,7 +129,10 @@ def pre_process(self, experiments): if self.params.radial_average.verbose: run, timestamp = self.get_run_and_timestamp(experiments) - print("Radial average of run %s, timestamp %s"%(str(run), timestamp)) + if timestamp == self.tag: + print("Radial average of run %s, timestamp %s"%(str(run), self.tag)) + else: + print("Radial average of run %s, tag %s, timestamp %s"%(str(run), self.tag, timestamp)) imageset = experiments.imagesets()[0] two_thetas, radial_average_values = radial_run(self.params.radial_average, imageset = imageset) From ed334c3748dff558937879cf9f2d955f1ffb79a4 Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Fri, 10 May 2024 16:14:12 -0700 Subject: [PATCH 453/748] XFEL GUI: tweaks to energy tab - Set max events to 100 - Fixes for running fee vs ebeam before fee calibration - Change reset to full clear, and initialize to empty list --- xfel/ui/components/ebeam_plotter.py | 4 +++- xfel/ui/components/xfel_gui_init.py | 33 ++++++++++++++++------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/xfel/ui/components/ebeam_plotter.py b/xfel/ui/components/ebeam_plotter.py index f23568b691..d52b942e56 100644 --- a/xfel/ui/components/ebeam_plotter.py +++ b/xfel/ui/components/ebeam_plotter.py @@ -6,7 +6,7 @@ import numpy as np from simtbx.nanoBragg.utils import ENERGY_CONV -def compare_ebeams_with_fees(locfiles, runs=None, plot=True, use_figure=None): +def compare_ebeams_with_fees(locfiles, runs=None, plot=True, use_figure=None, max_events=None): if plot: fig = use_figure or plt.figure() ax = fig.subplots() @@ -22,6 +22,8 @@ def compare_ebeams_with_fees(locfiles, runs=None, plot=True, use_figure=None): img = dxtbx.load(locfiles[i]) n_img = img.get_num_images() + if max_events is not None: + n_img = min(n_img, max_events) ebeams_eV = [] ebeams_wav = [] diff --git a/xfel/ui/components/xfel_gui_init.py b/xfel/ui/components/xfel_gui_init.py index 1f169d70c2..bdcf0fa8c1 100644 --- a/xfel/ui/components/xfel_gui_init.py +++ b/xfel/ui/components/xfel_gui_init.py @@ -174,8 +174,10 @@ def run(self): self.db = xfel_db_application(self.parent.params) from serialtbx.util.energy_scan_notch_finder import notch_phil_string + from xfel.command_line.fee_calibration import fee_phil_string from libtbx.phil import parse - self.fee_params = parse(notch_phil_string).extract() + self.fee_params = parse(notch_phil_string + fee_phil_string).extract() + self.fee_params.max_events=100 self.energy_tab.refresh_runs() while self.active: @@ -209,7 +211,7 @@ def run_fee_calib(self): runs = self.energy_tab.fee_runs energies = self.energy_tab.fee_energies - rundata = tally_fee_data(self.energy_tab.experiment, runs, plot=False, verbose=True) + rundata = tally_fee_data(self.energy_tab.experiment, runs, plot=False, verbose=True, max_events=self.fee_params.max_events) notches = [find_notch(range(len(data)), data, self.fee_params.kernel_size, @@ -254,8 +256,14 @@ def run_ebeam_calib(self, source='loc'): self.loc_dir = loc_dir loc_parts = [] - if self.energy_tab.experiment is not None: - loc_parts.append(f'experiment={self.energy_tab.experiment}') + if self.energy_tab.experiment is None: + print("Experiment not set") + return + loc_parts.append(f'experiment={self.energy_tab.experiment}') + if self.energy_tab.fee_eV_offset is None: + print("Calibrate spectrometer first") + return + loc_parts.append(f'spectrum_eV_offset={self.energy_tab.fee_eV_offset:.2f}') loc_parts.append(f'spectrum_eV_per_pixel={self.energy_tab.fee_eV_per_pixel:.2f}') @@ -276,9 +284,8 @@ def run_ebeam_calib(self, source='loc'): if 'rayonix' in det_addr: this_loc_parts.append(f'rayonix.bin_size={rungroup.binning}') loc_path = os.path.join(self.loc_dir, f'{run.run}.loc') - if not os.path.exists(loc_path): - with open(loc_path, 'w') as locf: - locf.write('\n'.join(this_loc_parts)) + with open(loc_path, 'w') as locf: + locf.write('\n'.join(this_loc_parts)) locfiles.append(loc_path) reordered_run_strings.append(str(run.run)) except Exception as e: @@ -295,7 +302,8 @@ def run_ebeam_calib(self, source='loc'): locfiles, runs=reordered_run_strings, plot=True, - use_figure=self.energy_tab.ebeam_figure) + use_figure=self.energy_tab.ebeam_figure, + max_events=100) self.energy_tab.ebeam_figure.canvas.draw_idle() self.energy_tab.ebeam_eV_offset = ebeam_eV_offset @@ -1858,6 +1866,7 @@ def __init__(self, parent, main): self.fee_calib_stale = False self.ebeam_calib_stale = False self.size_stale = False + self.experiment = main.params.facility.lcls.experiment self.calib_panel = ScrolledPanel(self) self.calib_sizer = wx.BoxSizer(wx.VERTICAL) @@ -1883,6 +1892,7 @@ def __init__(self, parent, main): self.scan_runs_experiment = wx.TextCtrl(self.expt_id_panel, size=(118, -1)) self.expt_id_sizer.Add(self.scan_runs_experiment_label) self.expt_id_sizer.Add(self.scan_runs_experiment) + self.scan_runs_experiment.SetValue(self.experiment) self.expt_id_panel.SetSizer(self.expt_id_sizer) self.scan_runs_sizer.Add(self.expt_id_panel) @@ -1893,8 +1903,6 @@ def __init__(self, parent, main): self.scan_runs_list.InsertColumn(0, 'Run', width=60) self.scan_runs_list.InsertColumn(1, 'Notch Energy (eV)', width=140) self.scan_runs_list.integer_columns = {0} - for i in range(5): - self.scan_runs_list.InsertItem(0, 0) self.scan_runs_sizer.Add(self.scan_runs_list, 1) @@ -2069,13 +2077,8 @@ def onAddScanRuns(self, e): self.scan_runs_list.InsertItem(n_rows, 0) def onClearScanRuns(self, e): - self.scan_runs_experiment.SetValue('mfxl1028322') n_rows = self.scan_runs_list.GetItemCount() self.scan_runs_list.DeleteAllItems() - for i in range(n_rows): - # self.scan_runs_list.InsertItem(0, 0) - self.scan_runs_list.InsertItem(i, str(i+1)) - self.scan_runs_list.SetItem(i, 1, str(10190 + 5*i)) e.Skip() def onRunFEECalib(self, e): From 199a9ff791cfea04dc2dd3993d364c247a9df654 Mon Sep 17 00:00:00 2001 From: terwill Date: Sat, 11 May 2024 08:36:39 -0700 Subject: [PATCH 454/748] fix typo in ambiguous --- iotbx/cli_parser.py | 4 ++-- libtbx/phil/command_line.py | 8 ++++---- libtbx/phil/tst.py | 6 +++--- libtbx/program_template.py | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/iotbx/cli_parser.py b/iotbx/cli_parser.py index 0d8b6b6ed1..275dc39acf 100644 --- a/iotbx/cli_parser.py +++ b/iotbx/cli_parser.py @@ -512,9 +512,9 @@ def process_phil(self, phil_list): # processed in given order if len(phil_list) > 0: interpreter = self.master_phil.command_line_argument_interpreter( - assume_when_ambigious=self.program_class.assume_when_ambigious) + assume_when_ambiguous=self.program_class.assume_when_ambiguous) data_manager_interpreter = self.data_manager.master_phil.command_line_argument_interpreter( - assume_when_ambigious=self.program_class.assume_when_ambigious) + assume_when_ambiguous=self.program_class.assume_when_ambiguous) print(' Adding command-line PHIL:', file=self.logger) print(' -------------------------', file=self.logger) for phil in phil_list: diff --git a/libtbx/phil/command_line.py b/libtbx/phil/command_line.py index c47751ee83..110efbe86d 100644 --- a/libtbx/phil/command_line.py +++ b/libtbx/phil/command_line.py @@ -12,7 +12,7 @@ def __init__(self, home_scope=None, argument_description=None, master_params=None, - assume_when_ambigious=True): + assume_when_ambiguous=True): if (argument_description is None): argument_description = "command line " assert [master_params, master_phil].count(None) == 1 @@ -28,7 +28,7 @@ def __init__(self, self.home_scope = home_scope self.argument_description = argument_description self.target_paths = None - self.assume_when_ambigious = assume_when_ambigious + self.assume_when_ambiguous = assume_when_ambiguous def get_path_score(self, source_path, target_path): i = target_path.find(source_path) @@ -92,7 +92,7 @@ def parent_expert_level(obj): if (score == max_score): error.append(" " + target_path) - if self.assume_when_ambigious: + if self.assume_when_ambiguous: # Calculate and apply tie-breaker value depending on expert level. # Arguments with lower expert level are preferentially # chosen if otherwise they would be ambiguous. @@ -100,7 +100,7 @@ def parent_expert_level(obj): max_score = max(scores) if (scores.count(max_score) > 1): # if there is still a tie, a Sorry is still raised raise Sorry("\n".join(error)) - if self.assume_when_ambigious: + if self.assume_when_ambiguous: print("Warning: " + "\n".join(error) + "\nAssuming %s was intended." % self.target_paths[scores.index(max_score)]) complete_definitions += object.customized_copy( diff --git a/libtbx/phil/tst.py b/libtbx/phil/tst.py index 60a2a523e3..5286171c05 100644 --- a/libtbx/phil/tst.py +++ b/libtbx/phil/tst.py @@ -5363,7 +5363,7 @@ def exercise_command_line_assume(): """ master_phil = phil.parse(input_string=master_string) # do not assume - itpr_neutral = master_phil.command_line_argument_interpreter(assume_when_ambigious=False) + itpr_neutral = master_phil.command_line_argument_interpreter(assume_when_ambiguous=False) try: assert itpr_neutral.process(arg="max=5") except Sorry as e: assert not show_diff(str(e), """\ @@ -5373,7 +5373,7 @@ def exercise_command_line_assume(): bar.max""") else: raise Exception_expected # assume with different expert levels - itpr_neutral = master_phil.command_line_argument_interpreter(assume_when_ambigious=True) + itpr_neutral = master_phil.command_line_argument_interpreter(assume_when_ambiguous=True) old_stdout = sys.stdout output = StringIO() sys.stdout = output @@ -5404,7 +5404,7 @@ def exercise_command_line_assume(): } """ master_phil = phil.parse(input_string=master_string) - itpr_neutral = master_phil.command_line_argument_interpreter(assume_when_ambigious=True) + itpr_neutral = master_phil.command_line_argument_interpreter(assume_when_ambiguous=True) try: assert itpr_neutral.process(arg="max=5") except Sorry as e: assert not show_diff(str(e), """\ diff --git a/libtbx/program_template.py b/libtbx/program_template.py index 4b0b1ce160..526432ae65 100644 --- a/libtbx/program_template.py +++ b/libtbx/program_template.py @@ -79,8 +79,8 @@ class ProgramTemplate(object): } ''' - # control PHIL parsing behavior when parameters are ambigious - assume_when_ambigious = False + # control PHIL parsing behavior when parameters are ambiguous + assume_when_ambiguous = False # the DataManager scope includes some shared PHIL parameters # set this to true if the DataManager scope should be shown by default From 33889acb7767299c81fb47e2608ab1a27f4c3a28 Mon Sep 17 00:00:00 2001 From: terwill Date: Sat, 11 May 2024 08:47:19 -0700 Subject: [PATCH 455/748] fix typo --- libtbx/phil/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libtbx/phil/__init__.py b/libtbx/phil/__init__.py index 76b8466774..23ee5d8aa8 100644 --- a/libtbx/phil/__init__.py +++ b/libtbx/phil/__init__.py @@ -2020,13 +2020,13 @@ def unique(self): def command_line_argument_interpreter(self, home_scope=None, argument_description=None, - assume_when_ambigious=True): + assume_when_ambiguous=True): from libtbx.phil.command_line import argument_interpreter as _ return _( master_phil=self, home_scope=home_scope, argument_description=argument_description, - assume_when_ambigious=assume_when_ambigious) + assume_when_ambiguous=assume_when_ambiguous) def process_include_scope( converter_registry, From 8321c653e9472f817c036971131e0e0c9719f9a3 Mon Sep 17 00:00:00 2001 From: terwill Date: Mon, 13 May 2024 15:16:39 -0600 Subject: [PATCH 456/748] Add top_hat method for FFT convolution; fix g_function and local_resolution_map which missed f000 term; force_type in any_file for ccp4 and mrc maps --- cctbx/maptbx/__init__.py | 47 +++++++++++++++++++++++++++++++++++++--- cctbx/miller/__init__.py | 16 +++++++++----- iotbx/file_reader.py | 18 +++++++++++++++ 3 files changed, 72 insertions(+), 9 deletions(-) diff --git a/cctbx/maptbx/__init__.py b/cctbx/maptbx/__init__.py index 18690a4bf1..b35c7b34c5 100644 --- a/cctbx/maptbx/__init__.py +++ b/cctbx/maptbx/__init__.py @@ -52,19 +52,20 @@ def get_blobs_boundaries_tuples(self): def smooth_map(map, crystal_symmetry, rad_smooth, method = "exp", non_negative = True): from cctbx import miller - assert method in ["exp", "box_average"] + assert method in ["exp", "box_average", "top_hat"] map_smooth = None - if(method == "exp"): + if (method == "exp"): f_map = miller.structure_factor_box_from_map( map = map, crystal_symmetry = crystal_symmetry, include_000 = True) ddd = f_map.d_spacings().data() - ddd.set_selected(ddd == -1 , 1.e+10) # d_spacing for (0, 0, 0) was set to -1 + ddd.set_selected(ddd == -1 , 1.e+10) # d for (0, 0, 0) was set to -1 ss = 1./flex.pow2(ddd) / 4. b_smooth = 8*math.pi**2*rad_smooth**2 smooth_scale = flex.exp(-b_smooth*ss) f_map = f_map.array(data = f_map.data()*smooth_scale) + from cctbx.maptbx import crystal_gridding cg = crystal_gridding( unit_cell = crystal_symmetry.unit_cell(), space_group_info = crystal_symmetry.space_group_info(), @@ -76,6 +77,46 @@ def smooth_map(map, crystal_symmetry, rad_smooth, method = "exp", map_smooth = fft_map.real_map_unpadded() if non_negative: map_smooth = map_smooth.set_selected(map_smooth<0., 0) + + elif(method == "top_hat"): + + # use same grid as original + from cctbx.maptbx import crystal_gridding + cg = crystal_gridding( + unit_cell = crystal_symmetry.unit_cell(), + space_group_info = crystal_symmetry.space_group_info(), + pre_determined_n_real = map.all()) + + average_value = map.as_1d().min_max_mean().mean + + # Get structure factors with f_000 + f_map = miller.structure_factor_box_from_map( + map = map, + crystal_symmetry = crystal_symmetry, + include_000 = True) + + # The d_spacings get a value of -1 for the f000 term. Set it to a big number + ddd = f_map.d_spacings().data() + ddd.set_selected(ddd < 0, 1.e+10) + d_min = f_map.d_min() + + # G-function for top hat (FT of top hat) + #complete_set = f_map.complete_set(include_f000 = True) + sphere_reciprocal = f_map.g_function(R=rad_smooth, # top hat function + s=f_map.d_spacings().data(), volume_scale=True) + + # FT (map) * FT(top hat) = FT (convolution of map and top hat) + fourier_coeff = f_map.array(data=f_map.data()*sphere_reciprocal) + + # Convolution of map and top hat + fft_map = fourier_coeff.fft_map(d_min = d_min, crystal_gridding = cg) + fft_map.apply_volume_scaling() + map_smooth = fft_map.real_map_unpadded() + + + if non_negative: + map_smooth = map_smooth.set_selected(map_smooth<0., 0) + elif(method == "box_average"): # assume 0/1 binary map assert abs(flex.max(map)-1.)<1.e-6 mmin = flex.min(map) diff --git a/cctbx/miller/__init__.py b/cctbx/miller/__init__.py index 6dc6731706..7f9d1f2331 100644 --- a/cctbx/miller/__init__.py +++ b/cctbx/miller/__init__.py @@ -2352,12 +2352,13 @@ def regularize(self): def g_function(self, R, s=None, volume_scale=False): # reciprocal sphere if s is None: - s = 1./self.d_spacings().data() + s = 1./self.d_spacings().data() # Note f000 term will get s = -1 else: s = 1./s arg = 2*math.pi*s*R vol=1 if(volume_scale): vol = 4*math.pi*R**3/3 + arg.set_selected(arg < 1.e-5, 1.e-5) # calculation below fails for f000 term return vol*3*(flex.sin(arg) - arg*flex.cos(arg))/(arg)**3 def as_double(self): @@ -4583,8 +4584,6 @@ def local_standard_deviation_map(self, radius, # J. P. Abrahams and A. G. W. Leslie, Acta Cryst. (1996). D52, 30-42 # This should really have been called "local_variance_map" because the # square root is not taken after local averaging of density-squared - complete_set = self.complete_set() - sphere_reciprocal = self.g_function(R=radius, s=complete_set.d_spacings().data()) fft = self.fft_map( resolution_factor=resolution_factor, d_min=d_min, @@ -4595,9 +4594,14 @@ def local_standard_deviation_map(self, radius, assert_shannon_sampling=assert_shannon_sampling, f_000=f_000) fft.apply_volume_scaling() - temp = complete_set.structure_factors_from_map( - flex.pow2(fft.real_map_unpadded()-mean_solvent_density)) - fourier_coeff = complete_set.array(data=temp.data()*sphere_reciprocal) + from cctbx import miller + temp = miller.structure_factor_box_from_map( + map = flex.pow2(fft.real_map_unpadded()-mean_solvent_density), + crystal_symmetry = self.crystal_symmetry(), + include_000 = True) + + sphere_reciprocal = self.g_function(R=radius, s=temp.d_spacings().data()) + fourier_coeff = temp.array(data=temp.data()*sphere_reciprocal) fft = fft_map( crystal_gridding=self.crystal_gridding( d_min=d_min, diff --git a/iotbx/file_reader.py b/iotbx/file_reader.py index d05b64b15c..434dcfee67 100644 --- a/iotbx/file_reader.py +++ b/iotbx/file_reader.py @@ -91,6 +91,9 @@ ascii_types = ["hkl","xplor_map","pdb","cif","phil","hhr", "ncs", "aln", "a3m", "seq", "xml", "txt"] +# Try files with these extensions only with their associated file types +extensions_absolutely_defining_type = ['ccp4','mrc'] + def get_wildcard_string(format): assert (format in standard_file_extensions), format wildcards = [ "*.%s" % ext for ext in standard_file_extensions[format] ] @@ -185,6 +188,8 @@ def _sort(f1, f2): def any_file(file_name, get_processed_file=False, valid_types=supported_file_types, + extensions_absolutely_defining_type= + extensions_absolutely_defining_type, allow_directories=False, force_type=None, input_class=None, @@ -204,12 +209,25 @@ def any_file(file_name, with force_type) :param raise_sorry_if_not_expected_format: raise a Sorry exception if the file extension does not match the parsed file type + :param extensions_absolutely_defining_type: if the file has one of these + extensions, only try the associated file type :returns: any_file_input object, or an instance of the input_class param """ file_name_raw = file_name file_name = strip_shelx_format_extension(file_name) if (file_name != file_name_raw) and (force_type is None): force_type = "hkl" + # See if extension is in extensions_absolutely_defining_type + _, ext = os.path.splitext(file_name_raw) + ext = ext[1:] # remove . in .ccp4 + if (force_type is None) and extensions_absolutely_defining_type and ( + ext in extensions_absolutely_defining_type): + for ft in supported_file_types: + if ext in standard_file_extensions[ft]: + force_type = ft + break + assert force_type is not None + if not os.path.exists(file_name): raise Sorry("Couldn't find the file %s" % file_name) elif os.path.isdir(file_name): From 0e182895000867f6b2b156b496220607b4d2054a Mon Sep 17 00:00:00 2001 From: terwill Date: Mon, 13 May 2024 15:39:49 -0700 Subject: [PATCH 457/748] Fix missing d_min --- cctbx/miller/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cctbx/miller/__init__.py b/cctbx/miller/__init__.py index 7f9d1f2331..add53a6e73 100644 --- a/cctbx/miller/__init__.py +++ b/cctbx/miller/__init__.py @@ -4598,6 +4598,7 @@ def local_standard_deviation_map(self, radius, temp = miller.structure_factor_box_from_map( map = flex.pow2(fft.real_map_unpadded()-mean_solvent_density), crystal_symmetry = self.crystal_symmetry(), + d_min = self.d_min(), include_000 = True) sphere_reciprocal = self.g_function(R=radius, s=temp.d_spacings().data()) From 8c09199db624d0507995e9d58a697b24846ca192 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 14 May 2024 10:01:08 -0700 Subject: [PATCH 458/748] Bugfix t96: fobs_minus_fobs (resulting from refactoring of mmmtbx/find_peaks.py) --- mmtbx/maps/fobs_minus_fobs_map.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/mmtbx/maps/fobs_minus_fobs_map.py b/mmtbx/maps/fobs_minus_fobs_map.py index 562e700ca0..ed033d8b33 100644 --- a/mmtbx/maps/fobs_minus_fobs_map.py +++ b/mmtbx/maps/fobs_minus_fobs_map.py @@ -290,20 +290,18 @@ def phases(self, root_label, anomalous_sign=None): if (self.silent) : peak_search_log = null_out() fmodel = self.fmodel peaks = find_peaks.manager( - fmodel=fmodel, - map_type=None, - map_coeffs=self.map_coeff, - map_cutoff=self.map_cutoff, - params=self.peak_search_params, - log=peak_search_log).peaks_mapped() + map_cutoff = self.map_cutoff, + xray_structure = fmodel.xray_structure, + params = self.peak_search_params, + log = peak_search_log, + map_coeffs = self.map_coeff).peaks_mapped() peaks.sites = fmodel.xray_structure.unit_cell().orthogonalize(peaks.sites) holes = find_peaks.manager( - fmodel=fmodel, - map_type=None, - map_coeffs=self.map_coeff, - map_cutoff=-self.map_cutoff, - params=self.peak_search_params, - log=peak_search_log).peaks_mapped() + map_cutoff = -self.map_cutoff, + xray_structure = fmodel.xray_structure, + params = self.peak_search_params, + log = peak_search_log, + map_coeffs = self.map_coeff).peaks_mapped() holes.sites = fmodel.xray_structure.unit_cell().orthogonalize(holes.sites) result = find_peaks_holes.peaks_holes_container( peaks=peaks, From fe3b2d01a11f2a34a509d7daddf5fa0d64983ccd Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 14 May 2024 12:11:43 -0700 Subject: [PATCH 459/748] Tidy-up Phenix: remove iotbx/command_line/isomorphous_difference_patterson.py --- .../isomorphous_difference_patterson.py | 137 ------------------ iotbx/regression/tst_patterson.py | 40 ----- 2 files changed, 177 deletions(-) delete mode 100644 iotbx/command_line/isomorphous_difference_patterson.py diff --git a/iotbx/command_line/isomorphous_difference_patterson.py b/iotbx/command_line/isomorphous_difference_patterson.py deleted file mode 100644 index 268e3def46..0000000000 --- a/iotbx/command_line/isomorphous_difference_patterson.py +++ /dev/null @@ -1,137 +0,0 @@ -# LIBTBX_SET_DISPATCHER_NAME cctbx.isomorphous_difference_patterson - -from __future__ import absolute_import, division, print_function -from libtbx.utils import Sorry, Usage, show_development_warning -import libtbx.callbacks # import dependency -import libtbx.phil -from six.moves import cStringIO as StringIO -import os -import sys - -master_phil = libtbx.phil.parse(""" -data_file_1 = None - .type = path -data_file_2 = None - .type = path -labels_1 = None - .type = str -labels_2 = None - .type = str -include scope iotbx.command_line.patterson_map.patterson_map_phil_str -relative_diff_limit = 0.1 - .type = float -map_file_name = iso_diff.ccp4 - .type = path -""", process_includes=True) - -def run(args, out=sys.stdout): - show_development_warning(out=out) - if (len(args) == 0) or ("--help" in args): - raise Usage("""\ -cctbx.isomorphous_difference_patterson xtal1.mtz xtal2.mtz [options] - -Calculate an isomorphous difference Patterson map from two datasets. You may -specify both in a single MTZ file if you want, but you must manually specify -the data_file_1 and data_file_2 parameters. Output is a CCP4-format map. - -Full parameters: -%s -""" % master_phil.as_str(prefix=" ")) - from iotbx.command_line import patterson_map - from iotbx import file_reader - import iotbx.symmetry - sources = [] - data_file_1 = data_file_2 = None - for arg in args : - if (os.path.isfile(arg)): - f = file_reader.any_file(arg) - if (f.file_type == "phil"): - sources.append(f.file_object) - elif (f.file_type == "hkl"): - if (data_file_1 is None): - data_file_1 = f - elif (data_file_2 is None): - data_file_2 = f - else : - raise Sorry("No more than two reflection files are supported.") - else : - raise Sorry("The file format for '%s' is not a supported input." % arg) - else : - try : - sources.append(libtbx.phil.parse(arg)) - except RuntimeError as e : - raise Sorry("Unrecognized argument '%s'.") - params = master_phil.fetch(sources=sources).extract() - if (params.data_file_1 is not None): - data_file_1 = file_reader.any_file(params.data_file_1) - if (params.data_file_2 is not None): - data_file_2 = file_reader.any_file(params.data_file_2) - if (None in [data_file_1, data_file_2]): - raise Sorry("You must provide two datasets for this program to run. If "+ - "they are different arrays within a specific file, you need to specify "+ - "the parameters explicitly, i.e. 'data_file_1=NAME data_file_2=NAME'.") - symm_manager = iotbx.symmetry.manager() - sg_err_1, uc_err_1 = symm_manager.process_reflections_file(data_file_1) - sg_err_2, uc_err_2 = symm_manager.process_reflections_file(data_file_2) - out_tmp = StringIO() - symm_manager.show(out=out_tmp) - if (sg_err_1) or (sg_err_2): - raise Sorry(("Incompatible space groups in input files:\n%s\nAll files "+ - "must have the same point group (and ideally the same space group). ") % - out_tmp.getvalue()) - elif (uc_err_1) or (uc_err_2): - libtbx.call_back(message="warn", - data=("Crystal symmetry mismatch:\n%s\nCalculations will continue "+ - "using the symmetry in the PDB file first reflection file, but the "+ - "maps should be treated with some suspicion.") % out_tmp.getvalue()) - obs_1 = patterson_map.extract_data( - file_name=None, - hkl_in=data_file_1, - expected_labels=params.labels_1, - out=out) - obs_2 = patterson_map.extract_data( - file_name=None, - hkl_in=data_file_2, - expected_labels=params.labels_2, - out=out) - assert (not None in [obs_1, obs_2]) - print("", file=out) - print("Data array #1 (will use symmetry from here):", file=out) - obs_1.show_summary(f=out, prefix=" ") - print("", file=out) - print("Data array #2:", file=out) - obs_2.show_summary(f=out, prefix=" ") - print("", file=out) - obs_2 = obs_2.customized_copy(crystal_symmetry=obs_1) - f_obs_1 = patterson_map.prepare_f_obs(obs_1, params).average_bijvoet_mates() - f_obs_2 = patterson_map.prepare_f_obs(obs_2, params).average_bijvoet_mates() - f_obs_1, f_obs_2 = f_obs_1.common_sets(other=f_obs_2) - # XXX will this work as expected? - print("Scaling second dataset...", file=out) - f_obs_2 = f_obs_1.multiscale(other=f_obs_2) - from scitbx.array_family import flex - print(" max(F1) = %.2f max(F2) = %.2f" % (flex.max(f_obs_1.data()), - flex.max(f_obs_2.data())), file=out) - delta_f = f_obs_1.customized_copy(data=f_obs_1.data()-f_obs_2.data()) - if (params.relative_diff_limit is not None): - f_obs_1_non_zero = f_obs_1.select(f_obs_1.data() > 0) - delta_f_non_zero = delta_f.common_set(other=f_obs_1_non_zero) - relative_diff = delta_f_non_zero.customized_copy( - data=delta_f_non_zero.data()/f_obs_1_non_zero.data()) - delta_f = delta_f_non_zero.select( - relative_diff.data() < params.relative_diff_limit) - n_discarded = len(delta_f_non_zero.data()) - len(delta_f.data()) - if (n_discarded > 0): - print("Discarded %d reflections with excessive differences." % \ - n_discarded, file=out) - print(" max(delta_F) = %.2f" % flex.max(delta_f.data()), file=out) - map = patterson_map.calculate_patterson_map(data=delta_f, params=params, - normalize=False) - if (params.map_file_name is None): - params.map_file_name = "iso_diff.ccp4" - map.as_ccp4_map( - file_name=params.map_file_name) - print("Wrote %s" % params.map_file_name, file=out) - -if (__name__ == "__main__"): - run(sys.argv[1:]) diff --git a/iotbx/regression/tst_patterson.py b/iotbx/regression/tst_patterson.py index 775abd9724..0e3dff48b7 100644 --- a/iotbx/regression/tst_patterson.py +++ b/iotbx/regression/tst_patterson.py @@ -16,46 +16,6 @@ def exercise_simple(): ).raise_if_errors() assert (result.return_code == 0) -def exercise_isomorphous(): - import iotbx.pdb.hierarchy - pdb_in = iotbx.pdb.input(source_info=None, lines="""\ -ATOM 47 N TYR A 7 8.292 1.817 6.147 1.00 14.70 N -ATOM 48 CA TYR A 7 9.159 2.144 7.299 1.00 15.18 C -ATOM 49 C TYR A 7 10.603 2.331 6.885 1.00 15.91 C -ATOM 50 O TYR A 7 11.041 1.811 5.855 1.00 15.76 O -ATOM 51 CB TYR A 7 9.061 1.065 8.369 1.00 15.35 C -ATOM 52 CG TYR A 7 7.665 0.929 8.902 1.00 14.45 C -ATOM 53 CD1 TYR A 7 6.771 0.021 8.327 1.00 15.68 C -ATOM 54 CD2 TYR A 7 7.210 1.756 9.920 1.00 14.80 C -ATOM 55 CE1 TYR A 7 5.480 -0.094 8.796 1.00 13.46 C -ATOM 56 CE2 TYR A 7 5.904 1.649 10.416 1.00 14.33 C -ATOM 57 CZ TYR A 7 5.047 0.729 9.831 1.00 15.09 C -ATOM 58 OH TYR A 7 3.766 0.589 10.291 1.00 14.39 O -ATOM 59 OXT TYR A 7 11.358 2.999 7.612 1.00 17.49 O -ATOM 100 CL CL B 1 12.000 5.000 10.000 1.00 10.00 CL -""") - xrs_1 = pdb_in.xray_structure_simple() - hierarchy = pdb_in.construct_hierarchy() - sel = hierarchy.atom_selection_cache().selection("not resname CL") - assert (sel.count(False) == 1) - pdb_in_2 = iotbx.pdb.input(source_info=None, - lines=hierarchy.select(sel).as_pdb_string( - crystal_symmetry=xrs_1)) - xrs_2 = pdb_in_2.xray_structure_simple() - fc1 = abs(xrs_1.structure_factors(d_min=1.5).f_calc()) - fc2 = abs(xrs_2.structure_factors(d_min=1.5).f_calc()) - ic1 = fc1.f_as_f_sq().set_observation_type_xray_intensity() - #ic1 = ic1.customized_copy(data=ic1.data()*5) - ic1.as_mtz_dataset( - column_root_label="I").mtz_object().write("tmp_patterson_1.mtz") - fc2.as_mtz_dataset( - column_root_label="F").mtz_object().write("tmp_patterson_2.mtz") - args = ["tmp_patterson_1.mtz", "tmp_patterson_2.mtz"] - result = easy_run.fully_buffered("cctbx.isomorphous_difference_patterson %s" % - " ".join(args)).raise_if_errors() - assert (result.return_code == 0) - if (__name__ == "__main__"): exercise_simple() - exercise_isomorphous() print("OK") From 9ff66f4067e336e2c0ba120d96321932552aede4 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 14 May 2024 12:12:48 -0700 Subject: [PATCH 460/748] Clean clutter :) --- iotbx/regression/tst_patterson.py | 1 - 1 file changed, 1 deletion(-) diff --git a/iotbx/regression/tst_patterson.py b/iotbx/regression/tst_patterson.py index 0e3dff48b7..a1e6f88659 100644 --- a/iotbx/regression/tst_patterson.py +++ b/iotbx/regression/tst_patterson.py @@ -1,6 +1,5 @@ from __future__ import absolute_import, division, print_function -from iotbx.pdb import hierarchy from libtbx import easy_run import libtbx.load_env import os From d5c18d0e20eb40397387247cbcd37884a3d93827 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 14 May 2024 15:47:51 -0700 Subject: [PATCH 461/748] Restore average_maps.py and use local_resolution_map in map_model_manager --- cctbx/maptbx/segment_and_split_map.py | 44 ++++++++ cctbx/miller/__init__.py | 19 ++++ iotbx/map_model_manager.py | 104 ++++++++++++++++++ ...st_map_model_manager_model_sharpening_5.py | 32 ++++-- 4 files changed, 187 insertions(+), 12 deletions(-) diff --git a/cctbx/maptbx/segment_and_split_map.py b/cctbx/maptbx/segment_and_split_map.py index 7a46a70e7c..fbdf11299e 100644 --- a/cctbx/maptbx/segment_and_split_map.py +++ b/cctbx/maptbx/segment_and_split_map.py @@ -4398,6 +4398,50 @@ def apply_soft_mask(map_data = None, out = out) return masked_map, smoothed_mask_data +def smooth_one_map(map_data, crystal_symmetry = None, smoothing_radius = None, + non_negative = False, method = 'exp'): + from cctbx.maptbx import smooth_map, unpad_in_place + unpad_in_place(map = map_data.deep_copy()) + smoothed_map = smooth_map( + map = map_data, + crystal_symmetry = crystal_symmetry, + rad_smooth = smoothing_radius, + non_negative = non_negative, + method = method) + return smoothed_map + +def get_smoothed_cc_map(map_data_1, map_data_2, + crystal_symmetry = None, weighting_radius = None, + method = 'top_hat'): + avg1 = map_data_1.as_1d().min_max_mean().mean + avg2 = map_data_2.as_1d().min_max_mean().mean + map_data_1 = map_data_1.deep_copy() - avg1 + map_data_2 = map_data_2.deep_copy() - avg2 + avg_product_map = smooth_one_map(map_data_1 * map_data_2, + crystal_symmetry = crystal_symmetry, + smoothing_radius = weighting_radius, + non_negative = True, method = method) + + squared_map_1 = flex.pow2(map_data_1) + squared_map_2 = flex.pow2(map_data_2) + sm1 = smooth_one_map(squared_map_1, + crystal_symmetry = crystal_symmetry, + smoothing_radius = weighting_radius, + non_negative = True, method = method) + sm2 = smooth_one_map(squared_map_2, + crystal_symmetry = crystal_symmetry, + smoothing_radius = weighting_radius, + non_negative = True, method = method) + sm = flex.sqrt(sm1) * flex.sqrt(sm2) + diffs = (squared_map_1 - squared_map_2) + sm.as_1d().set_selected(sm.as_1d() <0.001, 0.001) + cc_map = avg_product_map/sm + cc_map.as_1d().set_selected(cc_map.as_1d() < 0, 0) + cc_map.as_1d().set_selected(cc_map.as_1d() > 1, 1) + + return cc_map + + def smooth_mask_data(mask_data = None, crystal_symmetry = None, threshold = None, diff --git a/cctbx/miller/__init__.py b/cctbx/miller/__init__.py index add53a6e73..22ab834208 100644 --- a/cctbx/miller/__init__.py +++ b/cctbx/miller/__init__.py @@ -1653,6 +1653,25 @@ def setup_binner(self, d_max=0, d_min=0, binning=binning(self.unit_cell(), n_bins, self.indices(), d_max, d_min)) return self.binner() + def safe_setup_binner(self, n_bins = None, d_max = None, d_min = None, + min_in_bin = 10): + # purpose: make sure there are data in all bins + # Returns: actual n_bins created + + while n_bins >= 1: + self.setup_binner(n_bins = n_bins, d_max = d_max, d_min = d_min) + ok = True + for i_bin in self.binner().range_used(): + sel = self.binner().selection(i_bin) + if sel.count(True)= fsc_cutoff) & ( + just_above_dmin.as_1d() > local_d_mean) + just_above_dmin.as_1d().set_selected(ss, local_d_mean) + just_above_cc.as_1d().set_selected(ss, local_cc_map.as_1d()) + + ss = (local_cc_map.as_1d() < fsc_cutoff) & ( + just_below_dmin.as_1d() < local_d_mean) + just_below_dmin.as_1d().set_selected(ss, local_d_mean) + just_below_cc.as_1d().set_selected(ss, local_cc_map.as_1d()) + + # All set + + # just_above_cc = smallest resolution (d-spacing) where cc >= fsc_cutoff + # just_below_cc = largest resolution where cc < fsc_cutoff + + delta = just_above_cc - just_below_cc + ss_neg = (delta.as_1d() <= 1.e-10) + # smallest d-spacing with cc >= fsc_cutoff is + # less than largest d_spacing with cc < fsc_cutoff + # happens if cc vs resolution is noisy + + delta.as_1d().set_selected(delta.as_1d() < 1.e-10, 1.e-10) + frac = fsc_cutoff - just_below_cc + w1 = frac / delta + w1.as_1d().set_selected(w1.as_1d() < 0, 0) + w1.as_1d().set_selected(w1.as_1d() > 1, 1) + + w1.as_1d().set_selected(ss_neg, 0.5) # just average if overlap + w2 = 1 - w1 + map_data = (w1 * just_below_dmin) + (w2 * just_above_dmin) + m.set_map_data(map_data) + + return m + def map_map_fsc(self, map_id_1 = 'map_manager_1', diff --git a/iotbx/regression/tst_map_model_manager_model_sharpening_5.py b/iotbx/regression/tst_map_model_manager_model_sharpening_5.py index 16f84d74b0..808c79afc6 100644 --- a/iotbx/regression/tst_map_model_manager_model_sharpening_5.py +++ b/iotbx/regression/tst_map_model_manager_model_sharpening_5.py @@ -50,18 +50,26 @@ def test_01(method = 'model_sharpen', sharpen_method = getattr(mmm,method) # sharpen by method (can be model_sharpen, half_map_sharpen or - # external_sharpen) - - sharpen_method(anisotropic_sharpen = False, n_bins=10) - assert mmm.map_model_cc() > 0.9 - sharpen_method(anisotropic_sharpen = False, n_bins=10, - local_sharpen = True) - assert mmm.map_model_cc() > 0.9 - sharpen_method(anisotropic_sharpen = True, n_bins=10) - assert mmm.map_model_cc() > 0.9 - sharpen_method(anisotropic_sharpen = True, n_bins=10, - local_sharpen = True, n_boxes = 1) - assert mmm.map_model_cc() > 0.9 + # external_sharpen and also local_resolution_map) + + if method == 'local_resolution_map': + mm = sharpen_method() + x = mm.map_data().as_1d().min_max_mean() + from libtbx.test_utils import approx_equal + assert approx_equal((x.min,x.max,x.mean), + (1.850492557716066,2.159605614905797,2.0194400724786665), eps = 0.01) + + else: # usual + sharpen_method(anisotropic_sharpen = False, n_bins=10) + assert mmm.map_model_cc() > 0.9 + sharpen_method(anisotropic_sharpen = False, n_bins=10, + local_sharpen = True) + assert mmm.map_model_cc() > 0.9 + sharpen_method(anisotropic_sharpen = True, n_bins=10) + assert mmm.map_model_cc() > 0.9 + sharpen_method(anisotropic_sharpen = True, n_bins=10, + local_sharpen = True, n_boxes = 1) + assert mmm.map_model_cc() > 0.9 # ---------------------------------------------------------------------------- From b0e5c9e50cb60e78939a906709daa76b47b8ca73 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 14 May 2024 15:55:43 -0700 Subject: [PATCH 462/748] Add test --- .../tst_map_model_manager_local_resolution_10.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 iotbx/regression/tst_map_model_manager_local_resolution_10.py diff --git a/iotbx/regression/tst_map_model_manager_local_resolution_10.py b/iotbx/regression/tst_map_model_manager_local_resolution_10.py new file mode 100644 index 0000000000..12e7708c52 --- /dev/null +++ b/iotbx/regression/tst_map_model_manager_local_resolution_10.py @@ -0,0 +1,12 @@ +from __future__ import absolute_import, division, print_function +import libtbx.load_env +from iotbx.regression.tst_map_model_manager_model_sharpening_5 import test_01 +# ---------------------------------------------------------------------------- + +if (__name__ == '__main__'): + if libtbx.env.find_in_repositories(relative_path='chem_data') is not None: + test_01(method = 'local_resolution_map') + else: + print('Skip test_01, chem_data not available') + print ("OK") + From df740de95a4ba12271a90a1b437d616c4e4492d7 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 14 May 2024 16:59:20 -0600 Subject: [PATCH 463/748] Add map_model_manager tests --- iotbx/run_tests.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/iotbx/run_tests.py b/iotbx/run_tests.py index b0844df288..2fcc64d4c8 100644 --- a/iotbx/run_tests.py +++ b/iotbx/run_tests.py @@ -18,10 +18,15 @@ "$D/regression/tst_map_model_manager_3.py", "$D/regression/tst_map_model_manager_4.py", "$D/regression/tst_map_model_manager_model_sharpening_5.py", + "$D/regression/tst_map_model_manager_model_sharpening_5_cif.py", "$D/regression/tst_map_model_manager_call_consistency.py", "$D/regression/tst_map_model_manager_external_sharpening_7.py", "$D/regression/tst_map_model_manager_half_map_sharpening_6.py", "$D/regression/tst_map_model_manager_tls_from_map_8.py", + "$D/regression/tst_map_model_manager_cif.py", + "$D/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry.py", + "$D/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry_cif.py", + "$D/regression/tst_map_model_manager_local_resolution_10.py, "$D/regression/tst_map_tools.py", "$D/regression/tst_patterson.py", "$D/regression/tst_restraints_merge.py", @@ -102,9 +107,6 @@ "$D/regression/tst_mmcif_segids.py", "$D/regression/tst_mmcif_input.py", "$D/regression/tst_hierarchy_forward_compatible_pdb.py", - "$D/regression/tst_map_model_manager_cif.py", - "$D/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry_cif.py", - "$D/regression/tst_map_model_manager_model_sharpening_5_cif.py", "$D/regression/tst_mmcif_multimodel.py", "$D/regression/tst_add_conformations.py", "$D/regression/tst_symmetry.py", From 48a50eedf28229c55b047c899f70c665c95e82fe Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 14 May 2024 16:00:54 -0700 Subject: [PATCH 464/748] clean clutter --- iotbx/map_model_manager.py | 1 - 1 file changed, 1 deletion(-) diff --git a/iotbx/map_model_manager.py b/iotbx/map_model_manager.py index 42435302ba..df21da0793 100644 --- a/iotbx/map_model_manager.py +++ b/iotbx/map_model_manager.py @@ -7628,7 +7628,6 @@ def local_resolution_map(self, smoothing_radius_ratio = 2): - from cctbx.maptbx.segment_and_split_map import smooth_one_map from cctbx.maptbx.segment_and_split_map import get_smoothed_cc_map hm1 = self.get_map_manager_by_id(map_id_1) From 3d206eddf819d5d3db232f79b573fab3512b4388 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 14 May 2024 16:09:30 -0700 Subject: [PATCH 465/748] fix typo --- iotbx/run_tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iotbx/run_tests.py b/iotbx/run_tests.py index 2fcc64d4c8..b5baaf9e4e 100644 --- a/iotbx/run_tests.py +++ b/iotbx/run_tests.py @@ -26,7 +26,7 @@ "$D/regression/tst_map_model_manager_cif.py", "$D/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry.py", "$D/regression/tst_map_model_manager_9_remove_origin_shift_and_unit_cell_crystal_symmetry_cif.py", - "$D/regression/tst_map_model_manager_local_resolution_10.py, + "$D/regression/tst_map_model_manager_local_resolution_10.py", "$D/regression/tst_map_tools.py", "$D/regression/tst_patterson.py", "$D/regression/tst_restraints_merge.py", From 571e1c69d4cb2b722ecd6459ffb95c38034f1e8e Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Wed, 15 May 2024 13:27:42 -0700 Subject: [PATCH 466/748] splitting the test, removing double-run, defining prefix to avoid race conditions in different tests. --- mmtbx/ions/svm/tst_classifier.py | 122 ---------------------------- mmtbx/ions/svm/tst_classifier_01.py | 117 ++++++++++++++++++++++++++ mmtbx/ions/svm/tst_classifier_02.py | 117 ++++++++++++++++++++++++++ mmtbx/ions/tst_pickle.py | 6 +- mmtbx/run_tests.py | 3 +- 5 files changed, 240 insertions(+), 125 deletions(-) delete mode 100644 mmtbx/ions/svm/tst_classifier.py create mode 100644 mmtbx/ions/svm/tst_classifier_01.py create mode 100644 mmtbx/ions/svm/tst_classifier_02.py diff --git a/mmtbx/ions/svm/tst_classifier.py b/mmtbx/ions/svm/tst_classifier.py deleted file mode 100644 index 689598f1d1..0000000000 --- a/mmtbx/ions/svm/tst_classifier.py +++ /dev/null @@ -1,122 +0,0 @@ - # -*- coding: utf-8; py-indent-offset: 2 -*- - -from __future__ import absolute_import, division, print_function -from mmtbx.ions.svm.dump_sites import master_phil -from mmtbx.ions.environment import ChemicalEnvironment, ScatteringEnvironment -from mmtbx import ions -from mmtbx.ions.identify import WATER_RES_NAMES, AtomProperties -from mmtbx.ions.svm import ion_class, predict_ion -from mmtbx.regression.make_fake_anomalous_data import generate_zinc_inputs, \ - generate_calcium_inputs -import mmtbx.command_line -import libtbx.load_env -import warnings -import os -import sys -import time -from six.moves import zip - -def exercise(): - fns = [generate_calcium_inputs, generate_zinc_inputs] - wavelengths = [1.025, 1.54] - - for fn, wavelength in zip(fns, wavelengths): - mtz_file, pdb_file = fn(anonymize = True) - null_out = libtbx.utils.null_out() - - cmdline = mmtbx.command_line.load_model_and_data( - args = [pdb_file, mtz_file, "wavelength={}".format(wavelength), - "use_phaser=True", "use_svm=True"], - master_phil = master_phil(), - out = null_out, - process_pdb_file = True, - create_fmodel = True, - prefer_anomalous = True, - set_inelastic_form_factors = "sasaki", - ) - - os.remove(pdb_file) - os.remove(mtz_file) - os.remove(os.path.splitext(mtz_file)[0] + "_fmodel.eff") - os.remove(os.path.splitext(mtz_file)[0] + ".pdb") - - manager = ions.identify.create_manager( - pdb_hierarchy = cmdline.pdb_hierarchy, - fmodel = cmdline.fmodel, - geometry_restraints_manager = cmdline.geometry, - wavelength = cmdline.params.input.wavelength, - params = cmdline.params, - nproc = cmdline.params.nproc, - log = null_out, - manager_class = ions.svm.manager, - ) - - # Build a list of properties of each water / ion site - waters = [] - for chain in manager.pdb_hierarchy.only_model().chains(): - for residue_group in chain.residue_groups(): - atom_groups = residue_group.atom_groups() - if (len(atom_groups) > 1) : # alt conf, skip - continue - for atom_group in atom_groups : - # Check for non standard atoms in the residue - # Or a label indicating the residue is a water - resname = atom_group.resname.strip().upper() - - if (resname in WATER_RES_NAMES): - atoms = atom_group.atoms() - if (len(atoms) == 1) : # otherwise it probably has hydrogens, skip - waters.append(atoms[0].i_seq) - - assert len(waters) > 0 - - atom_props = [AtomProperties(i_seq, manager) for i_seq in waters] - - for atom_prop in atom_props: - i_seq = atom_prop.i_seq - chem_env = ChemicalEnvironment( - i_seq, - manager.find_nearby_atoms(i_seq, far_distance_cutoff = 3.5), - manager, - ) - scatter_env = ScatteringEnvironment( - i_seq, manager, - fo_density = manager.get_map_gaussian_fit("mFo", i_seq), - fofc_density = manager.get_map_gaussian_fit("mFo-DFc", i_seq), - anom_density = manager.get_map_gaussian_fit("anom", i_seq), - ) - resname = ion_class(chem_env) - assert resname != "" - - predictions = predict_ion(chem_env, scatter_env, - elements = ["HOH", "ZN", "CA"]) - if predictions is None: - print("Could not load SVM classifier") - print("Skipping {}".format(os.path.split(__file__)[1])) - return - - if resname != predictions[0][0]: - print("Prediction ({}) did not match expected: {}" \ - .format(predictions[0][0], resname)) - for element, prob in predictions: - print(" {}: {:.2f}".format(element, prob)) - sys.exit() - - print("OK") - -if __name__ == "__main__": - if (not libtbx.env.find_in_repositories("chem_data")): - warnings.warn("chem_data not available, skipping this test") - else : - try : - import svm - except ImportError : - warnings.warn("libsvm not available, skipping this test") - else : - print("WARNING: TEST TOO SLOW. MAKE IT RUN UNDER 300s AND ENABLE BACK.") - if 1: #XXX FIXME disabled - t0 = time.time() - exercise() - print("Time: %6.2f"%(time.time()-t0)) - print("OK") - exercise() diff --git a/mmtbx/ions/svm/tst_classifier_01.py b/mmtbx/ions/svm/tst_classifier_01.py new file mode 100644 index 0000000000..4093d6dd74 --- /dev/null +++ b/mmtbx/ions/svm/tst_classifier_01.py @@ -0,0 +1,117 @@ + # -*- coding: utf-8; py-indent-offset: 2 -*- + +from __future__ import absolute_import, division, print_function +from mmtbx.ions.svm.dump_sites import master_phil +from mmtbx.ions.environment import ChemicalEnvironment, ScatteringEnvironment +from mmtbx import ions +from mmtbx.ions.identify import WATER_RES_NAMES, AtomProperties +from mmtbx.ions.svm import ion_class, predict_ion +from mmtbx.regression.make_fake_anomalous_data import generate_calcium_inputs +import mmtbx.command_line +import libtbx.load_env +import warnings +import os +import sys +import time +from six.moves import zip + +def exercise(prefix="ions_svm_classifier_01"): + wavelength = 1.025 + mtz_file, pdb_file = generate_calcium_inputs( + file_base=prefix, + anonymize = True) + null_out = libtbx.utils.null_out() + + cmdline = mmtbx.command_line.load_model_and_data( + args = [pdb_file, mtz_file, "wavelength={}".format(wavelength), + "use_phaser=True", "use_svm=True"], + master_phil = master_phil(), + out = null_out, + process_pdb_file = True, + create_fmodel = True, + prefer_anomalous = True, + set_inelastic_form_factors = "sasaki", + ) + + os.remove(pdb_file) + os.remove(mtz_file) + os.remove(os.path.splitext(mtz_file)[0] + "_fmodel.eff") + os.remove(os.path.splitext(mtz_file)[0] + ".pdb") + + manager = ions.identify.create_manager( + pdb_hierarchy = cmdline.pdb_hierarchy, + fmodel = cmdline.fmodel, + geometry_restraints_manager = cmdline.geometry, + wavelength = cmdline.params.input.wavelength, + params = cmdline.params, + nproc = cmdline.params.nproc, + log = null_out, + manager_class = ions.svm.manager, + ) + + # Build a list of properties of each water / ion site + waters = [] + for chain in manager.pdb_hierarchy.only_model().chains(): + for residue_group in chain.residue_groups(): + atom_groups = residue_group.atom_groups() + if (len(atom_groups) > 1) : # alt conf, skip + continue + for atom_group in atom_groups : + # Check for non standard atoms in the residue + # Or a label indicating the residue is a water + resname = atom_group.resname.strip().upper() + + if (resname in WATER_RES_NAMES): + atoms = atom_group.atoms() + if (len(atoms) == 1) : # otherwise it probably has hydrogens, skip + waters.append(atoms[0].i_seq) + + assert len(waters) > 0 + + atom_props = [AtomProperties(i_seq, manager) for i_seq in waters] + + for atom_prop in atom_props: + i_seq = atom_prop.i_seq + chem_env = ChemicalEnvironment( + i_seq, + manager.find_nearby_atoms(i_seq, far_distance_cutoff = 3.5), + manager, + ) + scatter_env = ScatteringEnvironment( + i_seq, manager, + fo_density = manager.get_map_gaussian_fit("mFo", i_seq), + fofc_density = manager.get_map_gaussian_fit("mFo-DFc", i_seq), + anom_density = manager.get_map_gaussian_fit("anom", i_seq), + ) + resname = ion_class(chem_env) + assert resname != "" + + predictions = predict_ion(chem_env, scatter_env, + elements = ["HOH", "ZN", "CA"]) + if predictions is None: + print("Could not load SVM classifier") + print("Skipping {}".format(os.path.split(__file__)[1])) + return + + if resname != predictions[0][0]: + print("Prediction ({}) did not match expected: {}" \ + .format(predictions[0][0], resname)) + for element, prob in predictions: + print(" {}: {:.2f}".format(element, prob)) + sys.exit() + + print("OK") + +if __name__ == "__main__": + if (not libtbx.env.find_in_repositories("chem_data")): + warnings.warn("chem_data not available, skipping this test") + else : + try : + import svm + except ImportError : + warnings.warn("libsvm not available, skipping this test") + else : + t0 = time.time() + exercise() + print("Time: %6.2f"%(time.time()-t0)) + print("OK") diff --git a/mmtbx/ions/svm/tst_classifier_02.py b/mmtbx/ions/svm/tst_classifier_02.py new file mode 100644 index 0000000000..440ff37877 --- /dev/null +++ b/mmtbx/ions/svm/tst_classifier_02.py @@ -0,0 +1,117 @@ + # -*- coding: utf-8; py-indent-offset: 2 -*- + +from __future__ import absolute_import, division, print_function +from mmtbx.ions.svm.dump_sites import master_phil +from mmtbx.ions.environment import ChemicalEnvironment, ScatteringEnvironment +from mmtbx import ions +from mmtbx.ions.identify import WATER_RES_NAMES, AtomProperties +from mmtbx.ions.svm import ion_class, predict_ion +from mmtbx.regression.make_fake_anomalous_data import generate_zinc_inputs +import mmtbx.command_line +import libtbx.load_env +import warnings +import os +import sys +import time +from six.moves import zip + +def exercise(prefix="tst_classifier_02"): + wavelength = 1.54 + mtz_file, pdb_file = generate_zinc_inputs( + file_base=prefix, + anonymize = True) + null_out = libtbx.utils.null_out() + + cmdline = mmtbx.command_line.load_model_and_data( + args = [pdb_file, mtz_file, "wavelength={}".format(wavelength), + "use_phaser=True", "use_svm=True"], + master_phil = master_phil(), + out = null_out, + process_pdb_file = True, + create_fmodel = True, + prefer_anomalous = True, + set_inelastic_form_factors = "sasaki", + ) + + os.remove(pdb_file) + os.remove(mtz_file) + os.remove(os.path.splitext(mtz_file)[0] + "_fmodel.eff") + os.remove(os.path.splitext(mtz_file)[0] + ".pdb") + + manager = ions.identify.create_manager( + pdb_hierarchy = cmdline.pdb_hierarchy, + fmodel = cmdline.fmodel, + geometry_restraints_manager = cmdline.geometry, + wavelength = cmdline.params.input.wavelength, + params = cmdline.params, + nproc = cmdline.params.nproc, + log = null_out, + manager_class = ions.svm.manager, + ) + + # Build a list of properties of each water / ion site + waters = [] + for chain in manager.pdb_hierarchy.only_model().chains(): + for residue_group in chain.residue_groups(): + atom_groups = residue_group.atom_groups() + if (len(atom_groups) > 1) : # alt conf, skip + continue + for atom_group in atom_groups : + # Check for non standard atoms in the residue + # Or a label indicating the residue is a water + resname = atom_group.resname.strip().upper() + + if (resname in WATER_RES_NAMES): + atoms = atom_group.atoms() + if (len(atoms) == 1) : # otherwise it probably has hydrogens, skip + waters.append(atoms[0].i_seq) + + assert len(waters) > 0 + + atom_props = [AtomProperties(i_seq, manager) for i_seq in waters] + + for atom_prop in atom_props: + i_seq = atom_prop.i_seq + chem_env = ChemicalEnvironment( + i_seq, + manager.find_nearby_atoms(i_seq, far_distance_cutoff = 3.5), + manager, + ) + scatter_env = ScatteringEnvironment( + i_seq, manager, + fo_density = manager.get_map_gaussian_fit("mFo", i_seq), + fofc_density = manager.get_map_gaussian_fit("mFo-DFc", i_seq), + anom_density = manager.get_map_gaussian_fit("anom", i_seq), + ) + resname = ion_class(chem_env) + assert resname != "" + + predictions = predict_ion(chem_env, scatter_env, + elements = ["HOH", "ZN", "CA"]) + if predictions is None: + print("Could not load SVM classifier") + print("Skipping {}".format(os.path.split(__file__)[1])) + return + + if resname != predictions[0][0]: + print("Prediction ({}) did not match expected: {}" \ + .format(predictions[0][0], resname)) + for element, prob in predictions: + print(" {}: {:.2f}".format(element, prob)) + sys.exit() + + print("OK") + +if __name__ == "__main__": + if (not libtbx.env.find_in_repositories("chem_data")): + warnings.warn("chem_data not available, skipping this test") + else : + try : + import svm + except ImportError : + warnings.warn("libsvm not available, skipping this test") + else : + t0 = time.time() + exercise() + print("Time: %6.2f"%(time.time()-t0)) + print("OK") diff --git a/mmtbx/ions/tst_pickle.py b/mmtbx/ions/tst_pickle.py index 017f058d97..6ede826add 100644 --- a/mmtbx/ions/tst_pickle.py +++ b/mmtbx/ions/tst_pickle.py @@ -10,9 +10,11 @@ import iotbx.phil from iotbx.data_manager import DataManager -def exercise(): +def exercise(prefix="mmtbx_ions_tst_pickle"): wavelength = 1.025 - mtz_file, pdb_file = generate_zinc_inputs(anonymize = False) + mtz_file, pdb_file = generate_zinc_inputs( + file_base=prefix, + anonymize = False) null_out = libtbx.utils.null_out() dm = DataManager() diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index 5666db8c38..f34a0e4b90 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -16,7 +16,8 @@ "$D/pair_interaction/tst_04.py", "$D/pair_interaction/tst_05.py", # ions SVM - "$D/ions/svm/tst_classifier.py", + "$D/ions/svm/tst_classifier_01.py", + "$D/ions/svm/tst_classifier_02.py", "$D/ions/tst_pick_ca_svm.py", "$D/ions/tst_pickle.py", # ion picking From cbdcd331c883f4099e5c89351d2da0218a971fa0 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Wed, 15 May 2024 13:44:23 -0700 Subject: [PATCH 467/748] unused imports --- mmtbx/ions/svm/tst_classifier_01.py | 1 - mmtbx/ions/svm/tst_classifier_02.py | 1 - 2 files changed, 2 deletions(-) diff --git a/mmtbx/ions/svm/tst_classifier_01.py b/mmtbx/ions/svm/tst_classifier_01.py index 4093d6dd74..b938f640ce 100644 --- a/mmtbx/ions/svm/tst_classifier_01.py +++ b/mmtbx/ions/svm/tst_classifier_01.py @@ -13,7 +13,6 @@ import os import sys import time -from six.moves import zip def exercise(prefix="ions_svm_classifier_01"): wavelength = 1.025 diff --git a/mmtbx/ions/svm/tst_classifier_02.py b/mmtbx/ions/svm/tst_classifier_02.py index 440ff37877..25dcb7148b 100644 --- a/mmtbx/ions/svm/tst_classifier_02.py +++ b/mmtbx/ions/svm/tst_classifier_02.py @@ -13,7 +13,6 @@ import os import sys import time -from six.moves import zip def exercise(prefix="tst_classifier_02"): wavelength = 1.54 From 465c149e097c2b2cc52da0e3e83ebd5d133101b9 Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 15 May 2024 15:44:56 -0600 Subject: [PATCH 468/748] Use local_resolution_map instead of local_fsc --- cctbx/maptbx/__init__.py | 4 +-- cctbx/maptbx/segment_and_split_map.py | 13 +++----- iotbx/map_model_manager.py | 47 +++++++++++++++++++++++---- 3 files changed, 47 insertions(+), 17 deletions(-) diff --git a/cctbx/maptbx/__init__.py b/cctbx/maptbx/__init__.py index b35c7b34c5..1995d8cef7 100644 --- a/cctbx/maptbx/__init__.py +++ b/cctbx/maptbx/__init__.py @@ -78,7 +78,7 @@ def smooth_map(map, crystal_symmetry, rad_smooth, method = "exp", if non_negative: map_smooth = map_smooth.set_selected(map_smooth<0., 0) - elif(method == "top_hat"): + elif (method == "top_hat"): # use same grid as original from cctbx.maptbx import crystal_gridding @@ -103,7 +103,7 @@ def smooth_map(map, crystal_symmetry, rad_smooth, method = "exp", # G-function for top hat (FT of top hat) #complete_set = f_map.complete_set(include_f000 = True) sphere_reciprocal = f_map.g_function(R=rad_smooth, # top hat function - s=f_map.d_spacings().data(), volume_scale=True) + s=f_map.d_spacings().data(), volume_scale=False) # FT (map) * FT(top hat) = FT (convolution of map and top hat) fourier_coeff = f_map.array(data=f_map.data()*sphere_reciprocal) diff --git a/cctbx/maptbx/segment_and_split_map.py b/cctbx/maptbx/segment_and_split_map.py index fbdf11299e..6efe57d0d3 100644 --- a/cctbx/maptbx/segment_and_split_map.py +++ b/cctbx/maptbx/segment_and_split_map.py @@ -4415,26 +4415,21 @@ def get_smoothed_cc_map(map_data_1, map_data_2, method = 'top_hat'): avg1 = map_data_1.as_1d().min_max_mean().mean avg2 = map_data_2.as_1d().min_max_mean().mean - map_data_1 = map_data_1.deep_copy() - avg1 - map_data_2 = map_data_2.deep_copy() - avg2 - avg_product_map = smooth_one_map(map_data_1 * map_data_2, + avg_product_map = smooth_one_map((map_data_1 - avg1) * (map_data_2 - avg2), crystal_symmetry = crystal_symmetry, smoothing_radius = weighting_radius, non_negative = True, method = method) - squared_map_1 = flex.pow2(map_data_1) - squared_map_2 = flex.pow2(map_data_2) - sm1 = smooth_one_map(squared_map_1, + sm1 = smooth_one_map (flex.pow2(map_data_1 - avg1), crystal_symmetry = crystal_symmetry, smoothing_radius = weighting_radius, non_negative = True, method = method) - sm2 = smooth_one_map(squared_map_2, + sm2 = smooth_one_map(flex.pow2(map_data_2 - avg2), crystal_symmetry = crystal_symmetry, smoothing_radius = weighting_radius, non_negative = True, method = method) sm = flex.sqrt(sm1) * flex.sqrt(sm2) - diffs = (squared_map_1 - squared_map_2) - sm.as_1d().set_selected(sm.as_1d() <0.001, 0.001) + sm.as_1d().set_selected(sm.as_1d() < 1.e-20, 1.e-20) cc_map = avg_product_map/sm cc_map.as_1d().set_selected(cc_map.as_1d() < 0, 0) cc_map.as_1d().set_selected(cc_map.as_1d() > 1, 1) diff --git a/iotbx/map_model_manager.py b/iotbx/map_model_manager.py index df21da0793..0d191e0ddc 100644 --- a/iotbx/map_model_manager.py +++ b/iotbx/map_model_manager.py @@ -7625,16 +7625,40 @@ def local_resolution_map(self, n_bins = 20, fsc_cutoff = 0.143, smoothing_radius = None, - smoothing_radius_ratio = 2): + smoothing_radius_ratio = 1, + smooth_at_end = True): + """ + Calculate local resolution map by finding resolution where local + map correlation is fsc_cutoff at each point in the map. + Method: calculate local map correlation in resolution shells, + at each point in map find the resolution where this local map + correlation drops below fsc_cutoff. + + parameter: map_id_1: ID of one half-map + parameter: map_id_2: ID of other half-map + parameter: d_min: Finest resolution at which to calculate correlations + parameter: n_bins: Number of resolution bins + parameter: fsc_cutoff : value of correlation corresponding to + an estimated average map correlation to true map + of 0.5 (normally 0.143 is used) + parameter: smoothing_radius: radius for local correlation calculation + parameter: smoothing_radius_ratio: Ratio of smoothing_radius to map + resolution (NOTE: to map + resolution as specified in + self.resolution, not to d_min). + Used if smoothing_radius is None. + parameter: smooth_at_end: smooth final local resolution map + """ from cctbx.maptbx.segment_and_split_map import get_smoothed_cc_map + from cctbx.maptbx.segment_and_split_map import smooth_one_map hm1 = self.get_map_manager_by_id(map_id_1) hm2 = self.get_map_manager_by_id(map_id_2) assert hm1 and hm2 + resolution = self.resolution() if d_min is None: - resolution = self.resolution() d_min = self._get_d_min_from_resolution(resolution) if smoothing_radius is None: smoothing_radius = smoothing_radius_ratio * self.resolution() @@ -7666,11 +7690,14 @@ def local_resolution_map(self, just_above_cc = just_above_dmin.deep_copy() just_below_dmin = just_above_dmin.deep_copy() just_below_cc = just_above_dmin.deep_copy() - just_above_dmin += 999 # all 999 + sel = base_map_coeffs.binner().selection(all_bins[0]) + dd = dsd.select(sel) + local_d_mean = dd.min_max_mean().mean + just_above_dmin += local_d_mean # all at high end + just_below_dmin += d_min # all at low end m = hm1.deep_copy() n_real = hm1.map_data().all() - for i_bin in all_bins: sel = base_map_coeffs.binner().selection(i_bin) dd = dsd.select(sel) @@ -7687,8 +7714,8 @@ def local_resolution_map(self, local_cc_map = get_smoothed_cc_map( map_data_1, map_data_2, - crystal_symmetry = crystal_symmetry, weighting_radius = smoothing_radius) - + crystal_symmetry = crystal_symmetry, + weighting_radius = smoothing_radius) ss = (local_cc_map.as_1d() >= fsc_cutoff) & ( just_above_dmin.as_1d() > local_d_mean) just_above_dmin.as_1d().set_selected(ss, local_d_mean) @@ -7719,6 +7746,14 @@ def local_resolution_map(self, w1.as_1d().set_selected(ss_neg, 0.5) # just average if overlap w2 = 1 - w1 map_data = (w1 * just_below_dmin) + (w2 * just_above_dmin) + + if smooth_at_end: + # Finally, smooth the local resolution map + map_data = smooth_one_map(map_data, + crystal_symmetry = crystal_symmetry, + smoothing_radius = smoothing_radius, + method='exp') + m.set_map_data(map_data) return m From 1618a50df11b7dfc0b831f11dcc67b6e21c7e1e0 Mon Sep 17 00:00:00 2001 From: terwill Date: Wed, 15 May 2024 15:51:13 -0600 Subject: [PATCH 469/748] Update test --- .../tst_map_model_manager_model_sharpening_5.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/iotbx/regression/tst_map_model_manager_model_sharpening_5.py b/iotbx/regression/tst_map_model_manager_model_sharpening_5.py index 808c79afc6..661aa37914 100644 --- a/iotbx/regression/tst_map_model_manager_model_sharpening_5.py +++ b/iotbx/regression/tst_map_model_manager_model_sharpening_5.py @@ -42,7 +42,11 @@ def test_01(method = 'model_sharpen', wrapping = False) mmm.add_map_manager_by_id( map_id='external_map',map_manager=mmm.map_manager().deep_copy()) - mmm.set_resolution(3) + if method == 'local_resolution_map': + mmm.generate_map(map_id = 'map_manager_2') + dd = mmm.resolution() + else: + mmm.set_resolution(3) mmm.set_log(sys.stdout) dc = mmm.deep_copy() @@ -57,7 +61,8 @@ def test_01(method = 'model_sharpen', x = mm.map_data().as_1d().min_max_mean() from libtbx.test_utils import approx_equal assert approx_equal((x.min,x.max,x.mean), - (1.850492557716066,2.159605614905797,2.0194400724786665), eps = 0.01) + (1.9835316316768663, 2.3146054110530336, 2.1600110833032353), + eps = 0.01) else: # usual sharpen_method(anisotropic_sharpen = False, n_bins=10) From 94917a9ab29139a789bd8aebc04c2fc67e5d33ff Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Thu, 16 May 2024 13:49:31 -0700 Subject: [PATCH 470/748] do not refine xyz of new water; clarify scope for HL coefficients --- iotbx/extract_xtal_data.py | 4 +++- mmtbx/solvent/ordered_solvent.py | 16 ++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/iotbx/extract_xtal_data.py b/iotbx/extract_xtal_data.py index 0ac2e8372c..8e3d97d372 100644 --- a/iotbx/extract_xtal_data.py +++ b/iotbx/extract_xtal_data.py @@ -336,7 +336,7 @@ def __init__(self, if extract_experimental_phases: self.experimental_phases = self._determine_experimental_phases( parameters = experimental_phases_params, - parameter_scope = "") + parameter_scope = 'miller_array.labels.name') # Fill in log self._show_summary() @@ -454,8 +454,10 @@ def _determine_experimental_phases( file_name = file_name, labels = labels, raise_no_array = False, + parameter_name = "", ignore_all_zeros = ignore_all_zeros, parameter_scope = parameter_scope) + if(experimental_phases is None): return None except reflection_file_utils.Sorry_No_array_of_the_required_type: experimental_phases = None diff --git a/mmtbx/solvent/ordered_solvent.py b/mmtbx/solvent/ordered_solvent.py index f15fecb42b..2e18dce525 100644 --- a/mmtbx/solvent/ordered_solvent.py +++ b/mmtbx/solvent/ordered_solvent.py @@ -677,14 +677,14 @@ def refine_oat(self): self.new_solvent_selection.count(True)>0): from mmtbx.refinement import wrappers o = wrappers.unrestrained_qbr_fsr( - fmodel = self.fmodel, - model = self.model, - refine_xyz = True, - selection = self.new_solvent_selection, - q_min = 0.004, - b_max = 60, - b_min = self.params.b_iso_min, - log = self.log) + fmodel = self.fmodel, + model = self.model, + refine_xyz = False, + selection = self.new_solvent_selection, + q_min = 0.004, + b_max = 60, + b_min = self.params.b_iso_min, + log = self.log) self.model.adopt_xray_structure( xray_structure = self.fmodel.xray_structure) print(" ADP+occupancy (water only), MIN, final r_work=%6.4f r_free=%6.4f"%( From ab2a59449b632ff2450da715de804fc1a43852b7 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 16 May 2024 14:39:45 -0700 Subject: [PATCH 471/748] hide some print statements in rdkit_utils.py --- mmtbx/ligands/rdkit_utils.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/mmtbx/ligands/rdkit_utils.py b/mmtbx/ligands/rdkit_utils.py index c252d08c95..32b3519be3 100644 --- a/mmtbx/ligands/rdkit_utils.py +++ b/mmtbx/ligands/rdkit_utils.py @@ -67,7 +67,7 @@ def read_chemical_component_filename(filename): # if atom is None: continue conformer = Chem.Conformer(atom.n_rows()) for j, tmp in enumerate(atom.iterrows()): - print(tmp) + #print(tmp) new = Chem.Atom(tmp.get('_chem_comp_atom.type_symbol').capitalize()) new.SetFormalCharge(int(tmp.get('_chem_comp_atom.charge'))) for prop in ['atom_id', 'type_symbol']: @@ -85,24 +85,24 @@ def read_chemical_component_filename(filename): atom2 = lookup.get(atom2) order = tmp.get('_chem_comp_bond.value_order') order = bond_order_ccd[order] - print('---') + #print('---') rwmol.AddBond(atom1, atom2, order) rwmol.AddConformer(conformer) Chem.SanitizeMol(rwmol) # from rdkit.Chem.PropertyMol import PropertyMol molecule = rwmol.GetMol() # molecule = PropertyMol(molecule) - print(dir(molecule)) - print(desc) - print(dir(desc)) - for key, item in desc.items(): - key = key.split('.')[1] - print(key,list(item)) - molecule.SetProp(key,item[0]) - print(molecule.HasProp(key)) - print(molecule.GetProp(key)) - print(dir(molecule.GetPropNames())) - print(molecule.GetPropsAsDict()) +# print(dir(molecule)) +# print(desc) +# print(dir(desc)) +# for key, item in desc.items(): +# key = key.split('.')[1] +# print(key,list(item)) +# molecule.SetProp(key,item[0]) +# print(molecule.HasProp(key)) +# print(molecule.GetProp(key)) +# print(dir(molecule.GetPropNames())) +# print(molecule.GetPropsAsDict()) # print(dir(rwmol)) return molecule From 38b21884fd6fbf3391b8679cd1add46363df5b0f Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 16 May 2024 15:59:26 -0700 Subject: [PATCH 472/748] Reduce2: bugfixes --- mmtbx/hydrogens/reduce_hydrogen.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index 5002cf41bf..9d9ea68a59 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -24,7 +24,11 @@ def get_h_restraints(resname, strict=True): from mmtbx.ligands.rdkit_utils import read_chemical_component_filename filename = get_cif_filename(resname) if not os.path.exists(filename): return None - molecule = read_chemical_component_filename(filename) + try: + molecule = read_chemical_component_filename(filename) + except Exception as e: + print(e) + return None cc_cif = get_cif_dictionary(resname) cc = cc_cif['_chem_comp'][0] hs = [] @@ -526,14 +530,17 @@ def exclude_H_on_links(self, verbose=False): if (atoms[j].parent().resname == 'HIS' and atoms[j].name.strip() in ['HD1','DD1', 'HE2', 'DE2']): continue if(elements[i] in ["H","D"] and j in exclusion_iseqs): - sel_remove.append(i) - removed_dict[i] = exclusion_dict[j] - parent_dict[i]=j + if i not in sel_remove: + sel_remove.append(i) + removed_dict[i] = exclusion_dict[j] + parent_dict[i]=j if(elements[j] in ["H","D"] and i in exclusion_iseqs): - sel_remove.append(j) - removed_dict[j] = exclusion_dict[i] - parent_dict[j]=i + if j not in sel_remove: + sel_remove.append(j) + removed_dict[j] = exclusion_dict[i] + parent_dict[j]=i # remove H atoms NOT to remove - double negative! + #verbose=True if verbose: print('removed_dict',removed_dict) for i_seq in sel_remove: From 669f81d182517da9230702cb0f5b89fec8d95cc3 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 16 May 2024 16:37:38 -0700 Subject: [PATCH 473/748] Consolidate code for G function, add a test, make sure s=-1 is handled. --- cctbx/miller/__init__.py | 13 +++---------- cctbx/regression/tst_miller.py | 15 +++++++++++++-- scitbx/math/boost_python/math_ext.cpp | 4 ++++ scitbx/math/g_function.h | 26 +++++++++++++++++++++++--- 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/cctbx/miller/__init__.py b/cctbx/miller/__init__.py index 22ab834208..caadc828b4 100644 --- a/cctbx/miller/__init__.py +++ b/cctbx/miller/__init__.py @@ -2369,16 +2369,9 @@ def regularize(self): return result.set_info(info) def g_function(self, R, s=None, volume_scale=False): - # reciprocal sphere if s is None: s = 1./self.d_spacings().data() # Note f000 term will get s = -1 - else: - s = 1./s - arg = 2*math.pi*s*R - vol=1 - if(volume_scale): vol = 4*math.pi*R**3/3 - arg.set_selected(arg < 1.e-5, 1.e-5) # calculation below fails for f000 term - return vol*3*(flex.sin(arg) - arg*flex.cos(arg))/(arg)**3 + return scitbx.math.g_function(s, R, volume_scale) def as_double(self): """ @@ -4620,7 +4613,7 @@ def local_standard_deviation_map(self, radius, d_min = self.d_min(), include_000 = True) - sphere_reciprocal = self.g_function(R=radius, s=temp.d_spacings().data()) + sphere_reciprocal = self.g_function(R=radius, s=1./temp.d_spacings().data()) fourier_coeff = temp.array(data=temp.data()*sphere_reciprocal) fft = fft_map( crystal_gridding=self.crystal_gridding( @@ -4647,7 +4640,7 @@ def local_overlap_map(self, other, radius, assert self.crystal_symmetry().unit_cell().is_similar_to( other.crystal_symmetry().unit_cell()) complete_set = self.complete_set() - sphere_reciprocal = self.g_function(R=radius, s=complete_set.d_spacings().data()) + sphere_reciprocal = self.g_function(R=radius, s=1./complete_set.d_spacings().data()) if d_min is None: d_min=self.d_min() fft = self.fft_map( diff --git a/cctbx/regression/tst_miller.py b/cctbx/regression/tst_miller.py index 5b7437ee51..d0d4d0718a 100644 --- a/cctbx/regression/tst_miller.py +++ b/cctbx/regression/tst_miller.py @@ -1791,8 +1791,7 @@ def exercise_lsd_map(): shrink_truncation_radius=1) corr = flex.linear_correlation( mask.as_double().as_1d(), m1.data.as_double().as_1d()) - assert corr.coefficient() > 0.90 - + assert corr.coefficient() > 0.90, corr.coefficient() def exercise_phased_translation_coeff(d_min = 1.0, algorithm = "direct", @@ -2394,6 +2393,18 @@ def exercise_permute(): assert fc.indices().all_eq(fc_perm.indices()) assert fc_other.data().all_eq(fc_perm_other.data()) assert not fc_high.data().all_eq(fc_perm_high.data()) + # + # Ad hoc test for G-function + # + fc_high._data.append(123) + fc_high._indices.append([0,0,0]) + s = 1./fc_high.d_spacings().data() + sel = flex.sort_permutation(s, reverse=False) + s = s.select(sel) + assert approx_equal(s[0], -1) + fc_high=fc_high.select(sel) + vals = fc_high.g_function(R=3, volume_scale=False) + assert approx_equal(vals[:3], [1.0, 0.000863211, 0.0008627407]) def exercise_diagnostics(): xs = crystal.symmetry((30,40,50), "P 2 2 2") diff --git a/scitbx/math/boost_python/math_ext.cpp b/scitbx/math/boost_python/math_ext.cpp index be2ee7bb1e..dc135e4d8e 100644 --- a/scitbx/math/boost_python/math_ext.cpp +++ b/scitbx/math/boost_python/math_ext.cpp @@ -321,6 +321,10 @@ namespace { def("GfuncOfRSsqr_approx", (double(*)(double)) g_function::GfuncOfRSsqr_approx); + def("g_function", (scitbx::af::shared(*)( + af::const_ref const&, double const&, bool const&)) + g_function::Gfunction); + def("bessel_i1_over_i0", (double(*)(double const&)) bessel::i1_over_i0); def("bessel_i1_over_i0", (scitbx::af::shared(*)(scitbx::af::const_ref const&)) diff --git a/scitbx/math/g_function.h b/scitbx/math/g_function.h index 69958224a2..9a624cb012 100644 --- a/scitbx/math/g_function.h +++ b/scitbx/math/g_function.h @@ -15,10 +15,30 @@ FloatType Gfunction(FloatType twoPiRS) { // G-function (Fourier transform of a sphere of radius r at resolution s). static FloatType EPS(0.001); - if(std::abs(twoPiRS) > EPS) + if(twoPiRS > EPS) { return 3*(std::sin(twoPiRS)-twoPiRS*std::cos(twoPiRS))/fn::pow3(twoPiRS); - else - return 1-fn::pow2(twoPiRS)/10; + } + else { + if(twoPiRS > 0) return 1-fn::pow2(twoPiRS)/10; + else return 1; + } +} + +template +af::shared Gfunction(af::const_ref const& s, + FloatType const& R, + bool const& volume_scale) +{ + // G-function (Fourier transform of a sphere of radius R at resolution s). + static FloatType EPS(0.001); + af::shared r(s.size()); + FloatType volume=1; + if(volume_scale) volume = 4*scitbx::constants::pi*fn::pow3(R)/3; + for(std::size_t i = 0; i < s.size(); i++) { + FloatType twoPiRS = scitbx::constants::two_pi*s[i]*R; + r[i] = volume * Gfunction(twoPiRS); + } + return r; } template From db4a05c878f375ae0cd63968274613bddb8906ca Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Thu, 16 May 2024 20:27:13 -0700 Subject: [PATCH 474/748] CI: switch to an earlier version of git - git-lfs checkouts are failing with git > 2.45 [skip ci] --- .azure-pipelines/xfel/download-source.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.azure-pipelines/xfel/download-source.yml b/.azure-pipelines/xfel/download-source.yml index 7c2b32d412..c7fe9a380f 100644 --- a/.azure-pipelines/xfel/download-source.yml +++ b/.azure-pipelines/xfel/download-source.yml @@ -13,12 +13,28 @@ jobs: - checkout: self path: ./modules/cctbx_project + # add conda to path + # https://docs.microsoft.com/en-us/azure/devops/pipelines/ecosystems/anaconda?view=azure-devops&tabs=ubuntu-16-04#add-conda-to-your-system-path + - bash: echo "##vso[task.prependpath]$CONDA/bin" + displayName: Add conda to PATH + + # create environment with earlier version of git + # https://github.com/git-lfs/git-lfs/issues/5749 + - script: | + set -xe + conda create -n git -c conda-forge -y git=2.44 + displayName: Create environment with git + retryCountOnTaskFailure: 3 + - script: | cd $(Pipeline.Workspace) ln -s modules/cctbx_project/libtbx/auto_build/bootstrap.py displayName: Link bootstrap.py - script: | + set -xe + source $(CONDA)/etc/profile.d/conda.sh + conda activate git cd $(Pipeline.Workspace) python bootstrap.py hot update --builder=xfel --python=39 --no-boost-src cd modules From 31707132697c93d3226b1ab329dcc2bdb6421bf1 Mon Sep 17 00:00:00 2001 From: terwill Date: Fri, 17 May 2024 07:00:38 -0600 Subject: [PATCH 475/748] Fix g_function call --- cctbx/maptbx/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cctbx/maptbx/__init__.py b/cctbx/maptbx/__init__.py index 1995d8cef7..6a3283a2a7 100644 --- a/cctbx/maptbx/__init__.py +++ b/cctbx/maptbx/__init__.py @@ -102,8 +102,7 @@ def smooth_map(map, crystal_symmetry, rad_smooth, method = "exp", # G-function for top hat (FT of top hat) #complete_set = f_map.complete_set(include_f000 = True) - sphere_reciprocal = f_map.g_function(R=rad_smooth, # top hat function - s=f_map.d_spacings().data(), volume_scale=False) + sphere_reciprocal = f_map.g_function(R=rad_smooth) # top hat function # FT (map) * FT(top hat) = FT (convolution of map and top hat) fourier_coeff = f_map.array(data=f_map.data()*sphere_reciprocal) From a5d3370832ea1166e7231daf8bfeaa64ba9db6f9 Mon Sep 17 00:00:00 2001 From: terwill Date: Fri, 17 May 2024 13:50:22 -0600 Subject: [PATCH 476/748] Allow specification of tests to run based on changed files in github --- libtbx/command_line/run_tests_parallel.py | 87 ++++++++++++----------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/libtbx/command_line/run_tests_parallel.py b/libtbx/command_line/run_tests_parallel.py index 9ac52df989..c48dfb2430 100755 --- a/libtbx/command_line/run_tests_parallel.py +++ b/libtbx/command_line/run_tests_parallel.py @@ -46,7 +46,8 @@ def run(args, start_test=None, tests_to_skip=None, expected_failures_from_phenix_regression=[], - unstables_from_phenix_regression = []): + unstables_from_phenix_regression = [], + supplied_list_of_tests = None): if (len(args) == 0): raise Usage("""libtbx.run_tests_parallel [module=NAME] [directory=path]""") @@ -81,49 +82,54 @@ def run(args, expected_failure_list = [] expected_unstable_list = [] parallel_list = [] - if not return_list_of_tests: # (this fails with return_list_of_tests) + if (not return_list_of_tests) and (not supplied_list_of_tests): # (this + #fails with return_list_of_tests) all_tests.extend(libtbx.test_utils.parallel.make_commands(params.script, python_keyword_text=python_keyword_text)) - for dir_name in params.directory : - if os.path.split(dir_name)[-1].find("cctbx_project")>-1: - print('DANGER '*10) - print('Using the directory option in cctbx_project can be very time consuming') - print('DANGER '*10) - dir_tests = libtbx.test_utils.parallel.find_tests(dir_name) - all_tests.extend(libtbx.test_utils.parallel.make_commands(dir_tests, - python_keyword_text=python_keyword_text)) - for module_name in params.module : - module_tests = libtbx.test_utils.parallel.get_module_tests(module_name, - slow_tests = params.slow_tests, - python_keyword_text=python_keyword_text, - skip_missing = params.skip_missing) - fail_tests = libtbx.test_utils.parallel.\ - get_module_expected_test_failures(module_name, - skip_missing = params.skip_missing) - unstable_tests = libtbx.test_utils.\ - parallel.get_module_expected_unstable_tests(module_name, - skip_missing = params.skip_missing) - parallel_tests = libtbx.test_utils.parallel.\ - get_module_parallel_tests(module_name, - skip_missing = params.skip_missing) - all_tests.extend(module_tests) - all_tests.extend(fail_tests) - all_tests.extend(unstable_tests) - expected_failure_list.extend(fail_tests) - expected_unstable_list.extend(unstable_tests) - parallel_list.extend(parallel_tests) + if (supplied_list_of_tests): + all_tests = libtbx.test_utils.parallel.make_commands(supplied_list_of_tests, + python_keyword_text=python_keyword_text) + else: # usual + for dir_name in params.directory : + if os.path.split(dir_name)[-1].find("cctbx_project")>-1: + print('DANGER '*10) + print('Using the directory option in cctbx_project can be very time consuming') + print('DANGER '*10) + dir_tests = libtbx.test_utils.parallel.find_tests(dir_name) + all_tests.extend(libtbx.test_utils.parallel.make_commands(dir_tests, + python_keyword_text=python_keyword_text)) + for module_name in params.module : + module_tests = libtbx.test_utils.parallel.get_module_tests(module_name, + slow_tests = params.slow_tests, + python_keyword_text=python_keyword_text, + skip_missing = params.skip_missing) + fail_tests = libtbx.test_utils.parallel.\ + get_module_expected_test_failures(module_name, + skip_missing = params.skip_missing) + unstable_tests = libtbx.test_utils.\ + parallel.get_module_expected_unstable_tests(module_name, + skip_missing = params.skip_missing) + parallel_tests = libtbx.test_utils.parallel.\ + get_module_parallel_tests(module_name, + skip_missing = params.skip_missing) + all_tests.extend(module_tests) + all_tests.extend(fail_tests) + all_tests.extend(unstable_tests) + expected_failure_list.extend(fail_tests) + expected_unstable_list.extend(unstable_tests) + parallel_list.extend(parallel_tests) - # add expected failures from phenix regression - for ef in expected_failures_from_phenix_regression: - for t in all_tests: - if t.find(ef) > -1: - expected_failure_list.append(t) + # add expected failures from phenix regression + for ef in expected_failures_from_phenix_regression: + for t in all_tests: + if t.find(ef) > -1: + expected_failure_list.append(t) - # add unstables from phenix regression - for u in unstables_from_phenix_regression: - for t in all_tests: - if t.find(u) > -1: - expected_unstable_list.append(t) + # add unstables from phenix regression + for u in unstables_from_phenix_regression: + for t in all_tests: + if t.find(u) > -1: + expected_unstable_list.append(t) # remove any specified tests: if tests_to_skip: @@ -138,7 +144,6 @@ def run(args, else: print ("Skipping the test %s" %(t)) all_tests=new_tests - # check that test lists are unique seen = set() duplicates = set() From 64546a72de34fbcfaa90b4c7080b280df0fbc91f Mon Sep 17 00:00:00 2001 From: terwill Date: Fri, 17 May 2024 13:54:27 -0600 Subject: [PATCH 477/748] Allow specification of tests to run based on changed files in github --- libtbx/command_line/run_tests_parallel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libtbx/command_line/run_tests_parallel.py b/libtbx/command_line/run_tests_parallel.py index c48dfb2430..4500993eb6 100755 --- a/libtbx/command_line/run_tests_parallel.py +++ b/libtbx/command_line/run_tests_parallel.py @@ -82,11 +82,11 @@ def run(args, expected_failure_list = [] expected_unstable_list = [] parallel_list = [] - if (not return_list_of_tests) and (not supplied_list_of_tests): # (this + if (not return_list_of_tests) and (supplied_list_of_tests is None): # (this #fails with return_list_of_tests) all_tests.extend(libtbx.test_utils.parallel.make_commands(params.script, python_keyword_text=python_keyword_text)) - if (supplied_list_of_tests): + if (supplied_list_of_tests is not None): all_tests = libtbx.test_utils.parallel.make_commands(supplied_list_of_tests, python_keyword_text=python_keyword_text) else: # usual From d3345800bb2590348ab74db8fd42ecd13e115369 Mon Sep 17 00:00:00 2001 From: terwill Date: Fri, 17 May 2024 13:58:42 -0600 Subject: [PATCH 478/748] Allow specification of tests to run based on changed files in github --- libtbx/command_line/run_tests_parallel.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libtbx/command_line/run_tests_parallel.py b/libtbx/command_line/run_tests_parallel.py index 4500993eb6..03276961b3 100755 --- a/libtbx/command_line/run_tests_parallel.py +++ b/libtbx/command_line/run_tests_parallel.py @@ -163,7 +163,10 @@ def run(args, if return_list_of_tests: return all_tests if (len(all_tests) == 0): - raise Sorry("No test scripts found in %s." % params.directory) + if (supplied_list_of_tests is not None): + raise Sorry("No tests to run") + else: # usual + raise Sorry("No test scripts found in %s." % params.directory) if (params.shuffle): random.shuffle(all_tests) if (params.quiet): From bde6203e63949507ee237d83b0b7d4cf5f77c762 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sun, 19 May 2024 18:51:29 -0700 Subject: [PATCH 479/748] Bug fix revealed by qr.refine --- mmtbx/model/model.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index 9062ea7a93..f7aca3dbd7 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -1083,11 +1083,11 @@ def get_site_symmetry_table(self): return self._site_symmetry_table def altlocs_present(self): - result = False - conformer_indices = self.get_hierarchy().get_conformer_indices() + conformer_indices = \ + self.get_hierarchy().get_conformer_indices().conformer_indices if(len(list(set(list(conformer_indices))))>1): result = True - return result + return False def aa_residues_with_bound_sidechains(self): """ From cb4355e94debc9a6d85ccf1c1b3b40a04238ad63 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 20 May 2024 09:20:07 -0700 Subject: [PATCH 480/748] New test showcasign the different empty altlocs - no characters and whitespace. --- iotbx/regression/tst_hierarchy_altlocs.py | 58 +++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 iotbx/regression/tst_hierarchy_altlocs.py diff --git a/iotbx/regression/tst_hierarchy_altlocs.py b/iotbx/regression/tst_hierarchy_altlocs.py new file mode 100644 index 0000000000..b3b3073e8e --- /dev/null +++ b/iotbx/regression/tst_hierarchy_altlocs.py @@ -0,0 +1,58 @@ +from __future__ import absolute_import, division, print_function +import iotbx.pdb + +pdb_str1 = """ +ATOM 1 N AVAL A 1 -4.898 0.072 13.387 0.49 7.34 N +ATOM 2 CA AVAL A 1 -4.626 0.703 12.080 0.49 7.71 C +ATOM 3 C AVAL A 1 -3.475 1.680 12.227 0.49 7.52 C +ATOM 4 O AVAL A 1 -3.125 2.100 13.335 0.49 7.59 O +ATOM 5 CB AVAL A 1 -5.882 1.390 11.495 0.49 7.79 C +ATOM 6 CG1AVAL A 1 -6.979 0.367 11.258 0.49 7.20 C +ATOM 7 CG2AVAL A 1 -6.359 2.496 12.408 0.49 7.81 C +ATOM 8 H1 AVAL A 1 -4.794 -0.809 13.318 0.49 8.81 H +ATOM 9 H2 AVAL A 1 -4.331 0.391 13.995 0.49 8.81 H +ATOM 10 H3 AVAL A 1 -5.733 0.254 13.636 0.49 8.81 H +ATOM 11 HA AVAL A 1 -4.371 0.017 11.444 0.49 9.26 H +ATOM 12 HB AVAL A 1 -5.655 1.790 10.641 0.49 9.35 H +HETATM 2211 O HOH S 216 9.105 -6.647 -4.343 0.25 56.37 O +HETATM 2219 O BHOH S 224 6.977 3.045 9.044 0.31 55.60 O +""" + +pdb_str2 = """ +HETATM 2174 O HOH S 179 -5.781 7.569 9.276 0.24 14.70 O +HETATM 2174 O AHOH S 179 -5.781 7.569 9.276 0.24 14.70 O +HETATM 2174 O HOH S 179 -4.781 7.569 9.276 0.24 14.70 H +HETATM 2174 O CHOH S 179 -6.781 7.569 9.276 0.24 14.70 H +END +""" + +pdb_str3 = """ +HETATM 2174 O HOH S 179 -5.781 7.569 9.276 0.24 14.70 O +HETATM 2174 O HOH S 179 -5.781 7.569 9.276 0.24 14.70 O +HETATM 2174 O HOH S 179 -4.781 7.569 9.276 0.24 14.70 H +HETATM 2174 O HOH S 179 -6.781 7.569 9.276 0.24 14.70 H +END +""" + +def get_h(s): + return iotbx.pdb.input(source_info=None, lines=s).construct_hierarchy() + +def run(): + # + # This is current state of affairs. This was also the case in + # Phenix 1.20 and 1.18. + # + altlocs = [ag.altloc for ag in get_h(pdb_str1).only_model().atom_groups()] + assert altlocs == ['A', '', 'B'], altlocs + # + print("------------") + altlocs = [ag.altloc for ag in get_h(pdb_str2).only_model().atom_groups()] + assert altlocs == [' ', 'A', 'C'], altlocs + + print("------------") + altlocs = [ag.altloc for ag in get_h(pdb_str3).only_model().atom_groups()] + assert altlocs == [''], altlocs + +if (__name__ == "__main__"): + run() + print("OK") From 1d5885da49f6e808493e792e47f71e171d3b5aac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Tcho=C5=84?= Date: Mon, 20 May 2024 09:54:22 -0700 Subject: [PATCH 481/748] Mpi helper counter (#991) * Document mpi_helper, simplify use of flex methods, add .count() * Revert implicit use of mpi flex types in case of `None`s * Remove clutter --- xfel/merging/application/mpi_helper.py | 73 ++++++++++++++------------ 1 file changed, 40 insertions(+), 33 deletions(-) diff --git a/xfel/merging/application/mpi_helper.py b/xfel/merging/application/mpi_helper.py index c6ce22f61d..c8302dd982 100644 --- a/xfel/merging/application/mpi_helper.py +++ b/xfel/merging/application/mpi_helper.py @@ -1,5 +1,5 @@ from __future__ import absolute_import, division, print_function -from six.moves import range +from collections import Counter from libtbx.mpi4py import MPI import numpy as np from dials.array_family import flex @@ -22,6 +22,7 @@ def system_exception_handler(exception_type, value, traceback): raise e sys.excepthook = system_exception_handler + class mpi_helper(object): def __init__(self): self.MPI = MPI @@ -36,43 +37,49 @@ def time(self): def finalize(self): self.MPI.Finalize() - def cumulative_flex(self, flex_array, flex_type): - '''Build a cumulative sum flex array out of multiple same-size flex arrays.''' - # Example: (a1,a2,a3) + (b1, b2, b3) = (a1+b1, a2+b2, a3+b3) - if self.rank == 0: - cumulative = flex_type(flex_array.size(), 0) - else: - cumulative = None - - list_of_all_flex_arrays = self.comm.gather(flex_array, 0) - - if self.rank == 0: - for i in range(len(list_of_all_flex_arrays)): - flex_array = list_of_all_flex_arrays[i] - if flex_array is not None: - cumulative += flex_array - + def cumulative_flex(self, flex_array, flex_type=None, root=0): + """ + Build a cumulative sum flex array out of multiple same-size flex arrays. + Example: (a1,a2,a3) + (b1, b2, b3) = (a1+b1, a2+b2, a3+b3) + """ + flex_type = flex_type if flex_type is not None else type(flex_array) + list_of_all_flex_arrays = self.comm.gather(flex_array, root=root) + if self.rank != root: + return None + cumulative = flex_type(flex_array.size(), 0) + for flex_array in list_of_all_flex_arrays: + if flex_array is not None: + cumulative += flex_array return cumulative - def aggregate_flex(self, flex_array, flex_type): - '''Build an aggregate flex array out of multiple flex arrays''' - # Example: (a1,a2,a3) + (b1, b2, b3) = (a1, a2, a3, b1, b2, b3) - if self.rank == 0: - aggregate = flex_type() - else: - aggregate = None - - list_of_all_flex_arrays = self.comm.gather(flex_array, 0) - - if self.rank == 0: - for i in range(len(list_of_all_flex_arrays)): - flex_array = list_of_all_flex_arrays[i] - if flex_array is not None: - aggregate.extend(flex_array) - + def aggregate_flex(self, flex_array, flex_type=None, root=0): + """ + Build an aggregate flex array out of multiple flex arrays + Example: (a1,a2,a3) + (b1, b2, b3) = (a1, a2, a3, b1, b2, b3) + """ + flex_type = flex_type if flex_type is not None else type(flex_array) + list_of_all_flex_arrays = self.comm.gather(flex_array, root=root) + if self.rank != root: + return None + aggregate = flex_type() + for flex_array in list_of_all_flex_arrays: + if flex_array is not None: + aggregate.extend(flex_array) return aggregate + def count(self, data, root=0): + """ + Return total `Counter` of occurrences of each element in data across ranks. + Example: (a1, a1, a2) + (a1, a2, a3) = {a1: 3, a2: 2, a1: 1} + """ + counters = self.comm.gather(Counter(data), rank=root) + return sum(counters, Counter()) if self.rank == root else None + def sum(self, data, root=0): + """ + Sum values of data across all ranks. + Example: a1 + a2 + a3 = a1+a2+a3 + """ return self.comm.reduce(data, self.MPI.SUM, root=root) def set_error(self, description): From 6fbb4b7a94cc8e7d5b295ef29ac9906ed24e5d28 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 20 May 2024 17:32:43 -0700 Subject: [PATCH 482/748] run test --- iotbx/run_tests.py | 1 + 1 file changed, 1 insertion(+) diff --git a/iotbx/run_tests.py b/iotbx/run_tests.py index b5baaf9e4e..f4840facae 100644 --- a/iotbx/run_tests.py +++ b/iotbx/run_tests.py @@ -160,6 +160,7 @@ "$D/regression/tst_hierarchy_long_resname_4.py", "$D/regression/tst_hierarchy_copy_select.py", "$D/regression/tst_hierarchy_id_str.py", + "$D/regression/tst_hierarchy_altlocs.py", "$D/regression/tst_fetch.py", ] From d564aa3f60fe0b5472a5eff477c0c480266844f4 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Mon, 20 May 2024 18:45:23 -0700 Subject: [PATCH 483/748] Bugfix UR-6982: wrong CC1/2 values. The values are not wrong, but Xtriage displays the Ranom column instead of CC1/2. Fixed with this commit. Will break three wizard tests. --- iotbx/merging_statistics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iotbx/merging_statistics.py b/iotbx/merging_statistics.py index 355e34e444..a5abb8e6be 100644 --- a/iotbx/merging_statistics.py +++ b/iotbx/merging_statistics.py @@ -692,7 +692,7 @@ def quality_table(self): force_exact_x_labels=True) for bin in self.bins : data = bin.table_data() - table.add_row([ data[0] ] + data[7:11] + [ data[-1] ]) + table.add_row([ data[0] ] + data[7:10] + [ data[11] ] + [ data[-1] ]) return table @property From cef7d3ce8f6aea225a1ed248d4b38fb86efac3d8 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 21 May 2024 13:46:00 -0700 Subject: [PATCH 484/748] Reduce2: process restraint objects to pipe them into mon_lib_srv. --- mmtbx/programs/hydrogenate.py | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/mmtbx/programs/hydrogenate.py b/mmtbx/programs/hydrogenate.py index dc190c0192..ceb5f317e1 100644 --- a/mmtbx/programs/hydrogenate.py +++ b/mmtbx/programs/hydrogenate.py @@ -27,7 +27,6 @@ print_time = False .type = bool - ''' # ------------------------------------------------------------------------------ @@ -45,7 +44,7 @@ class Program(ProgramTemplate): data_manager_options = ['model_skip_expand_with_mtrix', 'model_skip_ss_annotations'] -# ------------------------------------------------------------------------------ + # ---------------------------------------------------------------------------- def validate(self): self.data_manager.has_models( @@ -53,11 +52,12 @@ def validate(self): expected_n = 1, exact_count = True) -# ------------------------------------------------------------------------------ + # ---------------------------------------------------------------------------- def run(self): self.model = self.data_manager.get_model() - # + self.model.process(make_restraints=False) + make_sub_header('Add H atoms', out=self.logger) hydrogenate_obj = reduce_hydrogen.place_hydrogens( model = self.model, @@ -79,12 +79,10 @@ def run(self): elif self.params.add_d_to_water: self.model.add_hydrogens(1., element="D", occupancy=1.) - if self.params.output.prefix is None: self.params.output.prefix = os.path.split(os.path.splitext( self.data_manager.get_default_model_name())[0])[1] - if self.data_manager.get_model().input_model_format_cif(): self.output_file_name = self.params.output.prefix+"_hydrogenate.cif" self.data_manager.write_model_file( @@ -98,19 +96,8 @@ def run(self): print("Wrote file: %s" % self.output_file_name, file=self.logger) + # ---------------------------------------------------------------------------- + def get_results(self): return group_args( output_file_name=self.output_file_name) - - -# ------------------------------------------------------------------------------ - -# def get_results(self): -# return group_args(model = self.model) -# def get_results(self): -# # results object not returned because it contains maps -# return group_args( -# message = self.message, -# output_file = self.output_file_name, -# model = self.data_manager.get_default_model_name()) - From 824e38e178600c3c6c248389879fea09393eb6d9 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 21 May 2024 14:27:12 -0700 Subject: [PATCH 485/748] Keep list of expected failures even when using sorted version --- libtbx/command_line/run_tests_parallel.py | 85 ++++++++++++----------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/libtbx/command_line/run_tests_parallel.py b/libtbx/command_line/run_tests_parallel.py index 03276961b3..27b5f4ef44 100755 --- a/libtbx/command_line/run_tests_parallel.py +++ b/libtbx/command_line/run_tests_parallel.py @@ -86,50 +86,46 @@ def run(args, #fails with return_list_of_tests) all_tests.extend(libtbx.test_utils.parallel.make_commands(params.script, python_keyword_text=python_keyword_text)) - if (supplied_list_of_tests is not None): - all_tests = libtbx.test_utils.parallel.make_commands(supplied_list_of_tests, - python_keyword_text=python_keyword_text) - else: # usual - for dir_name in params.directory : - if os.path.split(dir_name)[-1].find("cctbx_project")>-1: - print('DANGER '*10) - print('Using the directory option in cctbx_project can be very time consuming') - print('DANGER '*10) - dir_tests = libtbx.test_utils.parallel.find_tests(dir_name) - all_tests.extend(libtbx.test_utils.parallel.make_commands(dir_tests, - python_keyword_text=python_keyword_text)) - for module_name in params.module : - module_tests = libtbx.test_utils.parallel.get_module_tests(module_name, - slow_tests = params.slow_tests, - python_keyword_text=python_keyword_text, - skip_missing = params.skip_missing) - fail_tests = libtbx.test_utils.parallel.\ - get_module_expected_test_failures(module_name, - skip_missing = params.skip_missing) - unstable_tests = libtbx.test_utils.\ - parallel.get_module_expected_unstable_tests(module_name, - skip_missing = params.skip_missing) - parallel_tests = libtbx.test_utils.parallel.\ - get_module_parallel_tests(module_name, - skip_missing = params.skip_missing) - all_tests.extend(module_tests) - all_tests.extend(fail_tests) - all_tests.extend(unstable_tests) - expected_failure_list.extend(fail_tests) - expected_unstable_list.extend(unstable_tests) - parallel_list.extend(parallel_tests) + for dir_name in params.directory : + if os.path.split(dir_name)[-1].find("cctbx_project")>-1: + print('DANGER '*10) + print('Using the directory option in cctbx_project can be very time consuming') + print('DANGER '*10) + dir_tests = libtbx.test_utils.parallel.find_tests(dir_name) + all_tests.extend(libtbx.test_utils.parallel.make_commands(dir_tests, + python_keyword_text=python_keyword_text)) + for module_name in params.module : + module_tests = libtbx.test_utils.parallel.get_module_tests(module_name, + slow_tests = params.slow_tests, + python_keyword_text=python_keyword_text, + skip_missing = params.skip_missing) + fail_tests = libtbx.test_utils.parallel.\ + get_module_expected_test_failures(module_name, + skip_missing = params.skip_missing) + unstable_tests = libtbx.test_utils.\ + parallel.get_module_expected_unstable_tests(module_name, + skip_missing = params.skip_missing) + parallel_tests = libtbx.test_utils.parallel.\ + get_module_parallel_tests(module_name, + skip_missing = params.skip_missing) + all_tests.extend(module_tests) + all_tests.extend(fail_tests) + all_tests.extend(unstable_tests) + expected_failure_list.extend(fail_tests) + expected_unstable_list.extend(unstable_tests) + parallel_list.extend(parallel_tests) - # add expected failures from phenix regression - for ef in expected_failures_from_phenix_regression: - for t in all_tests: - if t.find(ef) > -1: - expected_failure_list.append(t) + # add expected failures from phenix regression + for ef in expected_failures_from_phenix_regression: + for t in all_tests: + if t.find(ef) > -1: + expected_failure_list.append(t) - # add unstables from phenix regression - for u in unstables_from_phenix_regression: - for t in all_tests: - if t.find(u) > -1: - expected_unstable_list.append(t) + # add unstables from phenix regression + for u in unstables_from_phenix_regression: + for t in all_tests: + if t.find(u) > -1: + expected_unstable_list.append(t) # remove any specified tests: if tests_to_skip: @@ -144,6 +140,11 @@ def run(args, else: print ("Skipping the test %s" %(t)) all_tests=new_tests + + if (supplied_list_of_tests is not None): + all_tests = supplied_list_of_tests # just use supplied tests + # Run all above to get expected failures etc + # check that test lists are unique seen = set() duplicates = set() From e112bb9f6a482aaa9502faf0a256a85b96af6979 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Wed, 22 May 2024 10:23:32 -0700 Subject: [PATCH 486/748] Remove chain if it becomes empty in merge_atoms_at_end_to_residues. Add test. --- iotbx/pdb/hierarchy.py | 2 + ...ierarchy_merge_atoms_at_end_to_residues.py | 65 +++++++++++++++++++ iotbx/run_tests.py | 1 + 3 files changed, 68 insertions(+) create mode 100644 iotbx/regression/tst_hierarchy_merge_atoms_at_end_to_residues.py diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index e6f912c1e3..9fc1882895 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -2225,6 +2225,8 @@ def merge_atoms_at_end_to_residues(self): rg.remove_atom_group(ag) chain = rg.parent() chain.remove_residue_group(rg) + if chain.atoms_size() == 0: + model.remove_chain(chain) else: residues[key] = ag diff --git a/iotbx/regression/tst_hierarchy_merge_atoms_at_end_to_residues.py b/iotbx/regression/tst_hierarchy_merge_atoms_at_end_to_residues.py new file mode 100644 index 0000000000..d17b5ede55 --- /dev/null +++ b/iotbx/regression/tst_hierarchy_merge_atoms_at_end_to_residues.py @@ -0,0 +1,65 @@ +from __future__ import absolute_import, division, print_function +import iotbx.pdb + +def exercise_1(): + pdb_str_1 = """\ +ATOM 1492 N TYR 1 7 -13.645 6.683 6.147 1.00 14.70 N +ATOM 1493 CA TYR 1 7 -12.778 7.010 7.299 1.00 15.18 C +ATOM 1494 C TYR 1 7 -11.334 7.197 6.885 1.00 15.91 C +ATOM 1495 O TYR 1 7 -10.896 6.677 5.855 1.00 15.76 O +ATOM 1496 CB TYR 1 7 -12.876 5.931 8.369 1.00 15.35 C +ATOM 1497 CG TYR 1 7 -14.272 5.795 8.902 1.00 14.45 C +ATOM 1498 CD1 TYR 1 7 -14.727 6.622 9.920 1.00 14.80 C +ATOM 1499 CD2 TYR 1 7 -15.166 4.887 8.327 1.00 15.68 C +ATOM 1500 CE1 TYR 1 7 -16.033 6.515 10.416 1.00 14.33 C +ATOM 1501 CE2 TYR 1 7 -16.457 4.772 8.796 1.00 13.46 C +ATOM 1502 CZ TYR 1 7 -16.890 5.595 9.831 1.00 15.09 C +ATOM 1503 OH TYR 1 7 -18.171 5.455 10.291 1.00 14.39 O +ATOM 1504 OXT TYR 1 7 -10.579 7.865 7.612 1.00 17.49 O +ATOM 1505 H TYR 1 7 -13.863 5.691 6.055 0.00 14.70 H +ATOM 1506 HA TYR 1 7 -13.122 7.951 7.728 0.00 15.18 H +ATOM 1507 HB2 TYR 1 7 -12.217 6.188 9.199 0.00 15.35 H +ATOM 1508 HB3 TYR 1 7 -12.579 4.974 7.941 0.00 15.35 H +ATOM 1509 HD1 TYR 1 7 -14.061 7.362 10.338 0.00 14.80 H +ATOM 1510 HD2 TYR 1 7 -14.841 4.267 7.504 0.00 15.68 H +ATOM 1511 HE1 TYR 1 7 -16.365 7.135 11.236 0.00 14.33 H +ATOM 1512 HE2 TYR 1 7 -17.129 4.047 8.362 0.00 13.46 H +ATOM 1513 HH TYR 1 7 -18.330 6.073 11.035 0.00 14.39 H +TER +ATOM 1560 N GLN 3 4 -20.932 4.661 -3.598 1.00 10.29 N +ATOM 1561 CA GLN 3 4 -22.321 4.321 -3.199 1.00 10.53 C +ATOM 1562 C GLN 3 4 -23.372 5.039 -4.088 1.00 10.24 C +ATOM 1563 O GLN 3 4 -23.484 6.276 -4.115 1.00 8.86 O +ATOM 1564 CB GLN 3 4 -22.593 4.581 -1.711 1.00 9.80 C +ATOM 1565 CG GLN 3 4 -23.881 3.891 -1.213 1.00 10.25 C +ATOM 1566 CD GLN 3 4 -24.441 4.477 0.089 1.00 12.43 C +ATOM 1567 OE1 GLN 3 4 -24.681 5.701 0.190 1.00 14.62 O +ATOM 1568 NE2 GLN 3 4 -24.687 3.594 1.091 1.00 9.05 N +ATOM 1569 H GLN 3 4 -20.775 5.669 -3.622 0.00 10.29 H +ATOM 1570 HA GLN 3 4 -22.442 3.248 -3.346 0.00 10.53 H +ATOM 1571 HB2 GLN 3 4 -22.701 5.654 -1.552 0.00 9.80 H +ATOM 1572 HB3 GLN 3 4 -21.757 4.199 -1.125 0.00 9.80 H +ATOM 1573 HG2 GLN 3 4 -24.650 3.992 -1.979 0.00 10.25 H +ATOM 1574 HG3 GLN 3 4 -23.667 2.837 -1.036 0.00 10.25 H +ATOM 1575 HE21 GLN 3 4 -25.060 3.924 1.981 0.00 9.05 H +ATOM 1576 HE22 GLN 3 4 -24.499 2.601 0.953 0.00 9.05 H +TER +ATOM H2 GLN 1 4 -23.584 6.695 2.944 1.00 10.29 H +TER +ATOM HC GLN 3 4 -23.988 4.503 -4.665 1.00 10.24 H +TER +""" + h = iotbx.pdb.input(lines=pdb_str_1, source_info=None).construct_hierarchy() + atoms_in_chains = [(c.id, c.atoms_size()) for c in h.only_model().chains()] + print (atoms_in_chains) + assert atoms_in_chains == [('1', 22), ('3', 17), ('1', 1), ('3', 1)], atoms_in_chains + + h.merge_atoms_at_end_to_residues() + atoms_in_chains2 = [(c.id, c.atoms_size()) for c in h.only_model().chains()] + # Note that the second chain '3' is removed and there's no chain with zero atoms. + print (atoms_in_chains2) + assert atoms_in_chains2 == [('1', 22), ('3', 18), ('1', 1)], atoms_in_chains + +if (__name__ == "__main__"): + exercise_1() + print("OK") diff --git a/iotbx/run_tests.py b/iotbx/run_tests.py index f4840facae..95747bf302 100644 --- a/iotbx/run_tests.py +++ b/iotbx/run_tests.py @@ -153,6 +153,7 @@ "$D/regression/tst_mtz_as_cif.py", "$D/regression/tst_group_rounding.py", "$D/regression/tst_hierarchy_occupancies_rounding.py", + "$D/regression/tst_hierarchy_merge_atoms_at_end_to_residues.py", "$D/regression/tst_hierarchy_long_chain_ids_1.py", "$D/regression/tst_hierarchy_long_resname_1.py", "$D/regression/tst_hierarchy_long_resname_2.py", From 2e52877346fcc72641ae2e356a4973af7b364807 Mon Sep 17 00:00:00 2001 From: cschlick Date: Wed, 22 May 2024 10:44:22 -0700 Subject: [PATCH 487/748] Change dispatcher name for qscore to mmtbx.development.qscore --- cctbx/command_line/qscore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cctbx/command_line/qscore.py b/cctbx/command_line/qscore.py index be5f21697e..033253d813 100644 --- a/cctbx/command_line/qscore.py +++ b/cctbx/command_line/qscore.py @@ -1,4 +1,4 @@ -# LIBTBX_SET_DISPATCHER_NAME cctbx.qscore +# LIBTBX_SET_DISPATCHER_NAME mmtbx.development.qscore from __future__ import absolute_import, division, print_function from iotbx.cli_parser import run_program From 9adc9aac3b3d65a972f1d26a6bb333d72ba3365f Mon Sep 17 00:00:00 2001 From: "Aaron S. Brewster" Date: Thu, 23 May 2024 09:32:04 -0700 Subject: [PATCH 488/748] XFEL GUI updates (#992) Series of updates from most recent beamtime: * Switch extant usage of mpi4py to libtbx.mpi4py * Refresh cached database connection after 5 minutes * add pydrive2 to psana_environment * XFEL GUI: only move on to next task if the previous one is in the DONE state * XFEL GUI: more tweaks for energy tab: add max events box, fix for parameter loading at GUI start, hide energy tab if not LCLS, fix for ListCtrl if clicked and empty, remove resizing code, fix invisible boxes in ListCtrl * Prevent duplicate gdrive uploads * Improve mpi safety * only disable mpi if the gui actually runs * XFEL GUI: energy tab, label eBeam using average * XFEL GUI: open image viewer when clicking on a dot (LCLS only for now) * XFEL GUI: better checks for closed image viewer Co-authored-by: Daniel Paley --- libtbx/__init__.py | 3 + libtbx/mpi4py.py | 10 ++ prime/command_line/mpi_run.py | 2 +- prime/command_line/mpi_scale.py | 2 +- simtbx/command_line/errors.py | 2 +- simtbx/command_line/estimate_Ncells_Eta.py | 2 +- simtbx/command_line/integrate.py | 2 +- xfel/amo/pnccd_ana/mpi_fxs_bg.py | 4 +- xfel/amo/pnccd_ana/mpi_fxs_c2.py | 4 +- xfel/amo/pnccd_ana/mpi_fxs_calib.py | 4 +- xfel/amo/pnccd_ana/mpi_fxs_index.py | 4 +- xfel/amo/pnccd_ana/mpi_fxs_launch.py | 2 +- xfel/amo/pnccd_ana/mpi_fxs_mask.py | 4 +- xfel/amo/pnccd_ana/pnccd_hit.py | 2 +- xfel/command_line/FEE_average_plot.py | 2 +- xfel/command_line/cxi_xtc_process.py | 2 +- xfel/command_line/mpi_average.py | 2 +- xfel/command_line/upload_mtz.py | 53 +++++-- xfel/command_line/xfel_process.py | 7 + xfel/command_line/xtc_dump.py | 2 +- xfel/command_line/xtc_process.py | 2 +- xfel/conda_envs/psana_environment.yml | 1 + xfel/cxi/cspad_ana/mod_event_code.py | 2 +- xfel/merging/application/phil/phil.py | 2 +- .../command_line/small_cell_index.py | 2 +- xfel/ui/command_line/xfel_gui_launch.py | 15 +- xfel/ui/components/ebeam_plotter.py | 21 ++- xfel/ui/components/run_stats_plotter.py | 13 +- xfel/ui/components/xfel_gui_dialogs.py | 5 + xfel/ui/components/xfel_gui_init.py | 146 +++++++++++++----- xfel/ui/db/job.py | 7 +- xfel/ui/db/xfel_db.py | 9 +- 32 files changed, 237 insertions(+), 103 deletions(-) diff --git a/libtbx/__init__.py b/libtbx/__init__.py index cb029d73e0..68b7ef65b8 100644 --- a/libtbx/__init__.py +++ b/libtbx/__init__.py @@ -68,6 +68,9 @@ def __new__(cls): Auto = AutoType() +class mpi_import_guard: + disable_mpi = False + class slots_getstate_setstate(object): """ Implements getstate and setstate for classes with __slots__ defined. Allows an diff --git a/libtbx/mpi4py.py b/libtbx/mpi4py.py index 1e13c57a84..edb047ff73 100644 --- a/libtbx/mpi4py.py +++ b/libtbx/mpi4py.py @@ -67,13 +67,23 @@ def size(self): mpiEmulator.COMM_WORLD = mpiCommEmulator() +class MpiDisabledError(Exception): + pass + try: + import libtbx + if libtbx.mpi_import_guard.disable_mpi: + raise MpiDisabledError from mpi4py import MPI using_mpi = True except ImportError: print ("\nWarning: could not import mpi4py. Running as a single process.\n") MPI = mpiEmulator() using_mpi = False +except MpiDisabledError: + MPI = mpiEmulator() + using_mpi = False + def mpi_abort_on_exception(func): """ diff --git a/prime/command_line/mpi_run.py b/prime/command_line/mpi_run.py index 82aa650e4e..8f1639dbe8 100644 --- a/prime/command_line/mpi_run.py +++ b/prime/command_line/mpi_run.py @@ -3,7 +3,7 @@ Find initial scaling factors for all integration results """ from __future__ import absolute_import, division, print_function -from mpi4py import MPI +from libtbx.mpi4py import MPI import sys, os from prime.postrefine.mod_input import process_input, read_pickles from prime.postrefine.mod_util import intensities_scaler diff --git a/prime/command_line/mpi_scale.py b/prime/command_line/mpi_scale.py index a2c032df9e..8b8534ee24 100644 --- a/prime/command_line/mpi_scale.py +++ b/prime/command_line/mpi_scale.py @@ -3,7 +3,7 @@ Find initial scaling factors for all integration results """ from __future__ import absolute_import, division, print_function -from mpi4py import MPI +from libtbx.mpi4py import MPI import sys, os from prime.postrefine.mod_input import process_input, read_pickles from prime.postrefine.mod_util import intensities_scaler diff --git a/simtbx/command_line/errors.py b/simtbx/command_line/errors.py index 4d0ff05c17..e9df001588 100644 --- a/simtbx/command_line/errors.py +++ b/simtbx/command_line/errors.py @@ -10,7 +10,7 @@ parser.add_argument("--ndev", type=int, default=1, help="number of gpu devices") args = parser.parse_args() -from mpi4py import MPI +from libtbx.mpi4py import MPI COMM = MPI.COMM_WORLD import os diff --git a/simtbx/command_line/estimate_Ncells_Eta.py b/simtbx/command_line/estimate_Ncells_Eta.py index 1b6b95349d..d41d33ac97 100644 --- a/simtbx/command_line/estimate_Ncells_Eta.py +++ b/simtbx/command_line/estimate_Ncells_Eta.py @@ -17,7 +17,7 @@ #parser.add_argument("--njobs", type=int, default=5, help="number of jobs (only runs on single node, no MPI)") parser.add_argument("--plot", action="store_true", help="show a histogram at the end") args = parser.parse_args() -from mpi4py import MPI +from libtbx.mpi4py import MPI COMM = MPI.COMM_WORLD #from joblib import Parallel, delayed import json diff --git a/simtbx/command_line/integrate.py b/simtbx/command_line/integrate.py index e1d0cdd3c1..a1f39b9259 100644 --- a/simtbx/command_line/integrate.py +++ b/simtbx/command_line/integrate.py @@ -21,7 +21,7 @@ args = parser.parse_args() -from mpi4py import MPI +from libtbx.mpi4py import MPI COMM = MPI.COMM_WORLD import logging diff --git a/xfel/amo/pnccd_ana/mpi_fxs_bg.py b/xfel/amo/pnccd_ana/mpi_fxs_bg.py index ccb919b84c..7ad7e5d759 100644 --- a/xfel/amo/pnccd_ana/mpi_fxs_bg.py +++ b/xfel/amo/pnccd_ana/mpi_fxs_bg.py @@ -17,7 +17,7 @@ #times. Here ignoring those errors. np.seterr(divide='ignore', invalid='ignore') -from mpi4py import MPI +from libtbx.mpi4py import MPI comm = MPI.COMM_WORLD rank = comm.Get_rank() size = comm.Get_size() @@ -141,7 +141,7 @@ def compute_bg(argv=None) : argv = sys.argv[1:] try: - from mpi4py import MPI + from libtbx.mpi4py import MPI except ImportError: raise Sorry("MPI not found") diff --git a/xfel/amo/pnccd_ana/mpi_fxs_c2.py b/xfel/amo/pnccd_ana/mpi_fxs_c2.py index 09a1c65bdc..4da8aebd52 100644 --- a/xfel/amo/pnccd_ana/mpi_fxs_c2.py +++ b/xfel/amo/pnccd_ana/mpi_fxs_c2.py @@ -18,7 +18,7 @@ #times. Here ignoring those errors. np.seterr(divide='ignore', invalid='ignore') -from mpi4py import MPI +from libtbx.mpi4py import MPI comm = MPI.COMM_WORLD rank = comm.Get_rank() size = comm.Get_size() @@ -148,7 +148,7 @@ def compute_c2(argv=None) : argv = sys.argv[1:] try: - from mpi4py import MPI + from libtbx.mpi4py import MPI except ImportError: raise Sorry("MPI not found") diff --git a/xfel/amo/pnccd_ana/mpi_fxs_calib.py b/xfel/amo/pnccd_ana/mpi_fxs_calib.py index 635c622688..2bb2c5200f 100644 --- a/xfel/amo/pnccd_ana/mpi_fxs_calib.py +++ b/xfel/amo/pnccd_ana/mpi_fxs_calib.py @@ -16,7 +16,7 @@ #times. Here ignoring those errors. np.seterr(divide='ignore', invalid='ignore') -from mpi4py import MPI +from libtbx.mpi4py import MPI comm = MPI.COMM_WORLD rank = comm.Get_rank() size = comm.Get_size() @@ -135,7 +135,7 @@ def compute_calib(argv=None) : argv = sys.argv[1:] try: - from mpi4py import MPI + from libtbx.mpi4py import MPI except ImportError: raise Sorry("MPI not found") diff --git a/xfel/amo/pnccd_ana/mpi_fxs_index.py b/xfel/amo/pnccd_ana/mpi_fxs_index.py index b8d409b53f..f8fe8cb1c5 100644 --- a/xfel/amo/pnccd_ana/mpi_fxs_index.py +++ b/xfel/amo/pnccd_ana/mpi_fxs_index.py @@ -17,7 +17,7 @@ #times. Here ignoring those errors. np.seterr(divide='ignore', invalid='ignore') -from mpi4py import MPI +from libtbx.mpi4py import MPI comm = MPI.COMM_WORLD rank = comm.Get_rank() size = comm.Get_size() @@ -136,7 +136,7 @@ def compute_index(argv=None) : argv = sys.argv[1:] try: - from mpi4py import MPI + from libtbx.mpi4py import MPI except ImportError: raise Sorry("MPI not found") diff --git a/xfel/amo/pnccd_ana/mpi_fxs_launch.py b/xfel/amo/pnccd_ana/mpi_fxs_launch.py index d55b68e3b7..fae8328351 100644 --- a/xfel/amo/pnccd_ana/mpi_fxs_launch.py +++ b/xfel/amo/pnccd_ana/mpi_fxs_launch.py @@ -77,7 +77,7 @@ def launch(argv=None) : argv = sys.argv[1:] try: - from mpi4py import MPI + from libtbx.mpi4py import MPI except ImportError: raise Sorry("MPI not found") diff --git a/xfel/amo/pnccd_ana/mpi_fxs_mask.py b/xfel/amo/pnccd_ana/mpi_fxs_mask.py index 791492ece9..0ef5477f18 100644 --- a/xfel/amo/pnccd_ana/mpi_fxs_mask.py +++ b/xfel/amo/pnccd_ana/mpi_fxs_mask.py @@ -18,7 +18,7 @@ #times. Here ignoring those errors. np.seterr(divide='ignore', invalid='ignore') -from mpi4py import MPI +from libtbx.mpi4py import MPI comm = MPI.COMM_WORLD rank = comm.Get_rank() size = comm.Get_size() @@ -140,7 +140,7 @@ def compute_mask(argv=None) : argv = sys.argv[1:] try: - from mpi4py import MPI + from libtbx.mpi4py import MPI except ImportError: raise Sorry("MPI not found") diff --git a/xfel/amo/pnccd_ana/pnccd_hit.py b/xfel/amo/pnccd_ana/pnccd_hit.py index 0972369a7d..f9fb8fff89 100644 --- a/xfel/amo/pnccd_ana/pnccd_hit.py +++ b/xfel/amo/pnccd_ana/pnccd_hit.py @@ -1,6 +1,6 @@ from __future__ import absolute_import, division, print_function import numpy as np -from mpi4py import MPI +from libtbx.mpi4py import MPI comm = MPI.COMM_WORLD rank = comm.Get_rank() size = comm.Get_size() diff --git a/xfel/command_line/FEE_average_plot.py b/xfel/command_line/FEE_average_plot.py index 343c86c12a..c3cbc0d493 100644 --- a/xfel/command_line/FEE_average_plot.py +++ b/xfel/command_line/FEE_average_plot.py @@ -92,7 +92,7 @@ def run(args): ds = DataSource(dataset_name) src = Source('DetInfo(%s)'%params.input.address) # set up multiprocessing with MPI - from mpi4py import MPI + from libtbx.mpi4py import MPI comm = MPI.COMM_WORLD rank = comm.Get_rank() # each process in MPI has a unique id, 0-indexed size = comm.Get_size() # size: number of processes running in this job diff --git a/xfel/command_line/cxi_xtc_process.py b/xfel/command_line/cxi_xtc_process.py index 76259b4bdf..cdaa3a678c 100644 --- a/xfel/command_line/cxi_xtc_process.py +++ b/xfel/command_line/cxi_xtc_process.py @@ -137,7 +137,7 @@ def run(self): print("Processing run %d of experiment %s using config file %s"%(params.input.run_num, params.input.experiment, params.input.cfg)) if params.mp.method == "mpi": - from mpi4py import MPI + from libtbx.mpi4py import MPI comm = MPI.COMM_WORLD rank = comm.Get_rank() # each process in MPI has a unique id, 0-indexed size = comm.Get_size() # size: number of processes running in this job diff --git a/xfel/command_line/mpi_average.py b/xfel/command_line/mpi_average.py index 1724ace7a9..827fbfa6ad 100644 --- a/xfel/command_line/mpi_average.py +++ b/xfel/command_line/mpi_average.py @@ -22,7 +22,7 @@ def average(argv=None): argv = sys.argv[1:] try: - from mpi4py import MPI + from libtbx.mpi4py import MPI except ImportError: raise Sorry("MPI not found") diff --git a/xfel/command_line/upload_mtz.py b/xfel/command_line/upload_mtz.py index 481f19e127..52a54e9cc9 100644 --- a/xfel/command_line/upload_mtz.py +++ b/xfel/command_line/upload_mtz.py @@ -5,6 +5,7 @@ from dials.util import Sorry import os, sys import re +import fcntl help_message = """ @@ -71,6 +72,21 @@ def _get_log_fname(mtz_fname): assert len(hit.groups()) == 1 return hit.groups()[0] + '_main.log' +class Locker: + """ See https://stackoverflow.com/a/60214222 + """ + def __enter__(self): + try: + self.fp = open(os.path.expanduser('~/.upload_mtz.lock'), 'wb') + except FileNotFoundError: + self.fp = None + if self.fp is not None: + fcntl.flock(self.fp.fileno(), fcntl.LOCK_EX) + def __exit__(self, *args, **kwargs): + if self.fp is not None: + fcntl.flock(self.fp.fileno(), fcntl.LOCK_UN) + self.fp.close() + class pydrive2_interface: """ Wrapper for uploading versioned mtzs and logs using Pydrive2. Constructed from @@ -92,26 +108,29 @@ def __init__(self, cred_file, folder_id): self.drive = GoogleDrive(gauth) self.top_folder_id = folder_id + + def _fetch_or_create_folder(self, fname, parent_id): - query = { - "q": "'{}' in parents and title='{}'".format(parent_id, fname), - "supportsTeamDrives": "true", - "includeItemsFromAllDrives": "true", - "corpora": "allDrives" - } - hits = self.drive.ListFile(query).GetList() - if hits: - assert len(hits)==1 - return hits[0]['id'] - else: + with Locker(): query = { - "title": fname, - "mimeType": "application/vnd.google-apps.folder", - "parents": [{"kind": "drive#fileLink", "id": parent_id}] + "q": "'{}' in parents and title='{}'".format(parent_id, fname), + "supportsTeamDrives": "true", + "includeItemsFromAllDrives": "true", + "corpora": "allDrives" } - f = self.drive.CreateFile(query) - f.Upload() - return f['id'] + hits = self.drive.ListFile(query).GetList() + if hits: + assert len(hits)==1 + return hits[0]['id'] + else: + query = { + "title": fname, + "mimeType": "application/vnd.google-apps.folder", + "parents": [{"kind": "drive#fileLink", "id": parent_id}] + } + f = self.drive.CreateFile(query) + f.Upload() + return f['id'] def _upload_detail(self, file_path, parent_id): title = os.path.split(file_path)[1] diff --git a/xfel/command_line/xfel_process.py b/xfel/command_line/xfel_process.py index 5012086d6c..77ca6e7d27 100644 --- a/xfel/command_line/xfel_process.py +++ b/xfel/command_line/xfel_process.py @@ -3,6 +3,7 @@ # LIBTBX_SET_DISPATCHER_NAME cctbx.xfel.process from __future__ import absolute_import, division, print_function +from libtbx.mpi4py import mpi_abort_on_exception help_message = ''' @@ -85,6 +86,12 @@ def __init__(self): epilog=help_message ) + @mpi_abort_on_exception + def run(self): + super().run() + + + if __name__ == '__main__': import dials.command_line.stills_process dials.command_line.stills_process.Processor = DialsProcessorWithLogging diff --git a/xfel/command_line/xtc_dump.py b/xfel/command_line/xtc_dump.py index aeffd60f68..6157e577de 100644 --- a/xfel/command_line/xtc_dump.py +++ b/xfel/command_line/xtc_dump.py @@ -156,7 +156,7 @@ def run(self): self.params = params self.options = options - from mpi4py import MPI + from libtbx.mpi4py import MPI comm = MPI.COMM_WORLD rank = comm.Get_rank() # each process in MPI has a unique id, 0-indexed size = comm.Get_size() # size: number of processes running in this job diff --git a/xfel/command_line/xtc_process.py b/xfel/command_line/xtc_process.py index fe935ba802..82ec787c23 100644 --- a/xfel/command_line/xtc_process.py +++ b/xfel/command_line/xtc_process.py @@ -615,7 +615,7 @@ def run(self): self.options = options if params.mp.method == "mpi": - from mpi4py import MPI + from libtbx.mpi4py import MPI comm = MPI.COMM_WORLD rank = comm.Get_rank() # each process in MPI has a unique id, 0-indexed size = comm.Get_size() # size: number of processes running in this job diff --git a/xfel/conda_envs/psana_environment.yml b/xfel/conda_envs/psana_environment.yml index d942df5bc3..f508c81d98 100644 --- a/xfel/conda_envs/psana_environment.yml +++ b/xfel/conda_envs/psana_environment.yml @@ -76,6 +76,7 @@ dependencies: # xfel gui - mysql - mysqlclient + - pydrive2 # Avoid numpy 1.21.[01234] # See https://github.com/cctbx/cctbx_project/issues/627 diff --git a/xfel/cxi/cspad_ana/mod_event_code.py b/xfel/cxi/cspad_ana/mod_event_code.py index 8450a36690..76ec18dc86 100644 --- a/xfel/cxi/cspad_ana/mod_event_code.py +++ b/xfel/cxi/cspad_ana/mod_event_code.py @@ -50,7 +50,7 @@ def __init__( self.size = int(os.environ['SGE_TASK_LAST']) - int(os.environ['SGE_TASK_FIRST']) + 1 else: try: - from mpi4py import MPI + from libtbx.mpi4py import MPI except ImportError: self.rank = 0 self.size = 1 diff --git a/xfel/merging/application/phil/phil.py b/xfel/merging/application/phil/phil.py index 7076b11431..f8eba14180 100644 --- a/xfel/merging/application/phil/phil.py +++ b/xfel/merging/application/phil/phil.py @@ -687,7 +687,7 @@ diffbragg_phil = """ diffBragg { - include scope simtbx.command_line.hopper.phil_scope + include scope simtbx.diffBragg.phil.phil_scope } """ diff --git a/xfel/small_cell/command_line/small_cell_index.py b/xfel/small_cell/command_line/small_cell_index.py index 41f5a071c4..e5bff9a776 100644 --- a/xfel/small_cell/command_line/small_cell_index.py +++ b/xfel/small_cell/command_line/small_cell_index.py @@ -118,7 +118,7 @@ def run(argv=None): files = os.listdir(path) try: - from mpi4py import MPI + from libtbx.mpi4py import MPI comm = MPI.COMM_WORLD rank = comm.Get_rank() size = comm.Get_size() diff --git a/xfel/ui/command_line/xfel_gui_launch.py b/xfel/ui/command_line/xfel_gui_launch.py index 592cf09863..36135ec498 100644 --- a/xfel/ui/command_line/xfel_gui_launch.py +++ b/xfel/ui/command_line/xfel_gui_launch.py @@ -14,16 +14,17 @@ import matplotlib as mp mp.use('PS') + from xfel.ui.components.xfel_gui_init import MainWindow from xfel.ui.components.xfel_gui_dialogs import SettingsDialog -from xfel.ui import save_cached_settings +from xfel.ui import load_cached_settings, save_cached_settings class MainApp(wx.App): ''' App for the main GUI window ''' def OnInit(self): - - self.frame = MainWindow(None, -1, title='CCTBX.XFEL') + params = load_cached_settings() + self.frame = MainWindow(None, -1, title='CCTBX.XFEL', params=params) # select primary display and center on that self.frame.SetSize((800, -1)) @@ -33,11 +34,11 @@ def OnInit(self): self.frame.Center() # Start with login dialog before opening main window - self.login = SettingsDialog(self.frame, self.frame.params) + self.login = SettingsDialog(self.frame, params=params) self.login.SetTitle('CCTBX.XFEL Login') self.login.Center() if (self.login.ShowModal() == wx.ID_OK): - save_cached_settings(self.frame.params) + save_cached_settings(params) if self.frame.connect_to_db(drop_tables=self.login.drop_tables): self.exp_tag = '| {}'.format(self.login.db_cred.ctr.GetValue()) self.exp = '| {}'.format(self.login.experiment.ctr.GetValue()) @@ -48,6 +49,7 @@ def OnInit(self): #self.frame.start_run_sentinel() #self.frame.start_job_monitor() #self.frame.start_prg_sentinel() + self.frame.run_window.show_hide_tabs() return True else: return False @@ -55,6 +57,9 @@ def OnInit(self): return False def run(args): + import libtbx + libtbx.mpi_import_guard.disable_mpi = True + if '-h' in args or '--help' in args or '-c' in args: from xfel.ui import master_phil_str from libtbx.phil import parse diff --git a/xfel/ui/components/ebeam_plotter.py b/xfel/ui/components/ebeam_plotter.py index d52b942e56..ed865790fd 100644 --- a/xfel/ui/components/ebeam_plotter.py +++ b/xfel/ui/components/ebeam_plotter.py @@ -42,15 +42,26 @@ def compare_ebeams_with_fees(locfiles, runs=None, plot=True, use_figure=None, ma ebeams_eV.append(eeV:=ENERGY_CONV/ewav) print(f'{i}: {int(feV)} eV FEE / {int(eeV)} eV Ebeam') - if plot: - ax.hist(ebeams_eV, alpha=0.5, bins=40, label=f'run {runs[i]} ebeams ({int(eeV)} eV)') - ax.hist(fee_coms_eV, alpha=0.5, bins=40, label=f'run {runs[i]} FEE COMs ({int(feV)} eV)') + if len(ebeams_eV) == 0: + print("No events found with both FEE and eBeam") + return None, None + fee_coms_eV = np.array(fee_coms_eV) + ebeam_eV = np.array(ebeams_eV) + fee_coms_wav = np.array(fee_coms_wav) + ebeams_wav = np.array(ebeams_wav) - diffs_eV = np.array(fee_coms_eV) - np.array(ebeams_eV) + diffs_eV = fee_coms_eV - ebeam_eV ebeam_eV_offsets.append(sum(diffs_eV)/len(diffs_eV)) - diffs_wav = np.array(fee_coms_wav) - np.array(ebeams_wav) + diffs_wav = fee_coms_wav - ebeams_wav ebeam_wav_offsets.append(sum(diffs_wav)/len(diffs_wav)) + mean_fee_eV = np.mean(fee_coms_eV) + mean_ebeam_eV = np.mean(ebeam_eV) + + if plot: + ax.hist(ebeams_eV, alpha=0.5, bins=40, label=f'run {runs[i]} ebeams ({int(mean_ebeam_eV)} eV)') + ax.hist(fee_coms_eV, alpha=0.5, bins=40, label=f'run {runs[i]} FEE COMs ({int(mean_fee_eV)} eV)') + if plot: ax.legend() ax.set_xlabel('Energy (eV)') diff --git a/xfel/ui/components/run_stats_plotter.py b/xfel/ui/components/run_stats_plotter.py index 6b6a0ef51e..492531e3fa 100644 --- a/xfel/ui/components/run_stats_plotter.py +++ b/xfel/ui/components/run_stats_plotter.py @@ -305,17 +305,6 @@ def resolution(x,pos): if title is not None: plt.title(title) if interactive: - def onclick(event): - ts = event.xdata - if ts is None: return - diffs = flex.abs(t - ts) - ts = t[flex.first_index(diffs, flex.min(diffs))] - print(get_paths_from_timestamps([ts], tag="shot", ext=ext)[0]) - - if hasattr(f, '_cid'): - f.canvas.mpl_disconnect(f._cid) - f._cid = f.canvas.mpl_connect('button_press_event', onclick) - if not figure: plt.show() else: @@ -361,7 +350,7 @@ def plot_multirun_stats(runs, if len(r[0]) > 0: if compress_runs: tslice = r[0] - r[0][0] + offset - offset += (r[0][-1] - r[0][0] + 1/120.) + offset += (r[0][-1] - r[0][0] + 1) else: tslice = r[0] last_end = r[0][-1] diff --git a/xfel/ui/components/xfel_gui_dialogs.py b/xfel/ui/components/xfel_gui_dialogs.py index 25842c6a31..8d6621faeb 100644 --- a/xfel/ui/components/xfel_gui_dialogs.py +++ b/xfel/ui/components/xfel_gui_dialogs.py @@ -52,6 +52,11 @@ def __init__(self, parent, ID=wx.ID_ANY, pos=wx.DefaultPosition, TextEditMixin.__init__(self) self.curRow = -1 + def OnLeftDown(self, evt=None): + try: + return super(EdListCtrl, self).OnLeftDown(evt) + except wx._core.wxAssertionError: + pass class BaseDialog(wx.Dialog): def __init__(self, parent, diff --git a/xfel/ui/components/xfel_gui_init.py b/xfel/ui/components/xfel_gui_init.py index bdcf0fa8c1..ee490f6aa3 100644 --- a/xfel/ui/components/xfel_gui_init.py +++ b/xfel/ui/components/xfel_gui_init.py @@ -177,7 +177,6 @@ def run(self): from xfel.command_line.fee_calibration import fee_phil_string from libtbx.phil import parse self.fee_params = parse(notch_phil_string + fee_phil_string).extract() - self.fee_params.max_events=100 self.energy_tab.refresh_runs() while self.active: @@ -189,8 +188,6 @@ def run(self): if self.energy_tab.ebeam_calib_stale: self.run_ebeam_calib() self.post_refresh_energy() - if self.energy_tab.size_stale: - self.resize() self.parent.run_window.calib_light.change_status('on') # green-- actually means idle time.sleep(1) except Exception as e: @@ -198,20 +195,13 @@ def run(self): self.parent.run_window.calib_light.change_status('alert') # red -- means crashed break - def resize(self): - #for fig in (self.energy_tab.trendline_figure, self.energy_tab.spectra_figure, self.energy_tab.ebeam_figure): - # fig.set_figwidth(self.energy_tab.plotx) - # fig.set_figheight(self.energy_tab.ploty) - self.energy_tab.Layout() - #self.energy_tab.Fit() - def run_fee_calib(self): from serialtbx.util.energy_scan_notch_finder import find_notch, plot_notches, calibrate_energy from xfel.command_line.fee_calibration import tally_fee_data runs = self.energy_tab.fee_runs energies = self.energy_tab.fee_energies - rundata = tally_fee_data(self.energy_tab.experiment, runs, plot=False, verbose=True, max_events=self.fee_params.max_events) + rundata = tally_fee_data(self.energy_tab.experiment, runs, plot=False, verbose=True, max_events=self.energy_tab.max_events) notches = [find_notch(range(len(data)), data, self.fee_params.kernel_size, @@ -299,18 +289,19 @@ def run_ebeam_calib(self, source='loc'): self.energy_tab.ebeam_figure.clear() ebeam_eV_offset, ebeam_wavelength_offset = compare_ebeams_with_fees( - locfiles, - runs=reordered_run_strings, - plot=True, - use_figure=self.energy_tab.ebeam_figure, - max_events=100) + locfiles, + runs=reordered_run_strings, + plot=True, + use_figure=self.energy_tab.ebeam_figure, + max_events=self.energy_tab.max_events) self.energy_tab.ebeam_figure.canvas.draw_idle() - self.energy_tab.ebeam_eV_offset = ebeam_eV_offset - self.energy_tab.ebeam_wavelength_offset = ebeam_wavelength_offset - ang = u'\u212b' # Angstrom - self.energy_tab.ebeam_offset_text.SetLabel(f'{ebeam_eV_offset:.2f} eV ({ebeam_wavelength_offset:.6f} {ang})') - self.energy_tab.ebeam_calib_stale = False + if ebeam_eV_offset is not None: + self.energy_tab.ebeam_eV_offset = ebeam_eV_offset + self.energy_tab.ebeam_wavelength_offset = ebeam_wavelength_offset + ang = u'\u212b' # Angstrom + self.energy_tab.ebeam_offset_text.SetLabel(f'{ebeam_eV_offset:.2f} eV ({ebeam_wavelength_offset:.6f} {ang})') + self.energy_tab.ebeam_calib_stale = False #try: # locfile = os.path.join(db.params.output_folder, f'r{run.run:04d}', f'{trial.trial:03d}_rg{rg.rungroup_id:03d', 'data.loc') @@ -1267,7 +1258,7 @@ def plot_stats_static(self): class MainWindow(wx.Frame): - def __init__(self, parent, id, title): + def __init__(self, parent, id, title, params=None): wx.Frame.__init__(self, parent, id, title, size=(200, 200)) self.run_sentinel = None @@ -1279,7 +1270,9 @@ def __init__(self, parent, id, title): self.unitcell_sentinel = None self.mergingstats_sentinel = None - self.params = load_cached_settings() + if not params: + params = load_cached_settings() + self.params = params self.db = None self.high_vis = False @@ -1640,6 +1633,9 @@ def onLeavingTab(self, e): def onQuit(self, e): self.stop_sentinels() save_cached_settings(self.params) + # wx windows resolve to False if closed + if self.run_window.runstats_tab.sf_frame: + self.run_window.runstats_tab.sf_frame.Close() self.Destroy() @@ -1701,17 +1697,30 @@ def __init__(self, parent): main_sizer.Add(self.main_panel, 1, flag=wx.EXPAND | wx.ALL, border=3) self.SetSizer(main_sizer) + self.show_hide_tabs() + + def show_hide_tabs(self): if self.parent.params.monitoring_mode: self.runs_tab.Hide() - self.energy_tab.Hide() self.trials_tab.Hide() self.jobs_tab.Hide() self.datasets_tab.Hide() self.run_light.Hide() self.job_light.Hide() self.jmn_light.Hide() - - + else: + self.runs_tab.Show() + self.trials_tab.Show() + self.jobs_tab.Show() + self.datasets_tab.Show() + self.run_light.Show() + self.job_light.Show() + self.jmn_light.Show() + + if self.parent.params.facility.name == "lcls" and not self.parent.params.monitoring_mode: + self.energy_tab.Show() + else: + self.energy_tab.Hide() # --------------------------------- UI Tabs ---------------------------------- # @@ -1879,7 +1888,7 @@ def __init__(self, parent, main): NavigationToolbar2WxAgg as NavigationToolbar) # FEE scan section - self.scan_runs_panel = ScrolledPanel(self.calib_panel, size=(220, 300)) + self.scan_runs_panel = ScrolledPanel(self.calib_panel, size=(220, 325)) self.scan_runs_sizer = wx.BoxSizer(wx.VERTICAL) self.scan_runs_panel.SetSizer(self.scan_runs_sizer) @@ -1896,6 +1905,16 @@ def __init__(self, parent, main): self.expt_id_panel.SetSizer(self.expt_id_sizer) self.scan_runs_sizer.Add(self.expt_id_panel) + self.max_evts_panel = wx.Panel(self.scan_runs_panel) + self.max_evts_sizer = wx.BoxSizer(wx.HORIZONTAL) + self.max_evts_label = wx.StaticText(self.max_evts_panel, label='Max events:', size=(80, -1)) + self.max_evts = wx.TextCtrl(self.max_evts_panel, size=(118, -1)) + self.max_evts_sizer.Add(self.max_evts_label) + self.max_evts_sizer.Add(self.max_evts) + self.max_evts.SetValue("200") + self.max_evts_panel.SetSizer(self.max_evts_sizer) + self.scan_runs_sizer.Add(self.max_evts_panel) + self.scan_runs_list = dlg.EdListCtrl(self.scan_runs_panel, style=wx.LC_EDIT_LABELS | wx.LC_REPORT, size=(200,165)) @@ -1903,6 +1922,8 @@ def __init__(self, parent, main): self.scan_runs_list.InsertColumn(0, 'Run', width=60) self.scan_runs_list.InsertColumn(1, 'Notch Energy (eV)', width=140) self.scan_runs_list.integer_columns = {0} + self.scan_runs_list.InsertItem(0, 0) + self.scan_runs_list.Select(0) self.scan_runs_sizer.Add(self.scan_runs_list, 1) @@ -2060,25 +2081,20 @@ def __init__(self, parent, main): self.Bind(wx.EVT_BUTTON, self.onRunsClear, self.ebeam_runs_clear_button) self.Bind(wx.EVT_BUTTON, self.onRunEbeamCalib, self.ebeam_runs_launch_button) self.Bind(wx.EVT_BUTTON, self.onSaveCalib, self.export_button) - self.Bind(wx.EVT_SIZE, self.onSize) self.Layout() self.Fit() - self.onSize() - - def onSize(self, e=None): - self.size_stale = True - # Caution: attempting to resize causes frequent core dumps!! - if e is not None: - e.Skip() def onAddScanRuns(self, e): n_rows = self.scan_runs_list.GetItemCount() self.scan_runs_list.InsertItem(n_rows, 0) + self.scan_runs_list.Select(n_rows) def onClearScanRuns(self, e): n_rows = self.scan_runs_list.GetItemCount() self.scan_runs_list.DeleteAllItems() + self.scan_runs_list.InsertItem(0, 0) + self.scan_runs_list.Select(0) e.Skip() def onRunFEECalib(self, e): @@ -2093,6 +2109,7 @@ def onRunFEECalib(self, e): self.experiment = self.main.params.facility.lcls.experiment else: self.experiment = None + self.max_events = int(self.max_evts.GetValue()) #TODO: validation during input instead? self.fee_runs = [] @@ -2124,6 +2141,7 @@ def onRunFEECalib(self, e): def onRunEbeamCalib(self, e): #self.ebeam_offset_text.SetLabel('') self.selected_runs = self.ebeam_runs_selection.ctr.GetCheckedStrings() + self.max_events = int(self.max_evts.GetValue()) self.ebeam_calib_stale = True e.Skip() @@ -2737,6 +2755,8 @@ def __init__(self, parent, main): self.strong_indexed_image_paths = None self.strong_indexed_image_timestamps = None self.auto_update = True + self.sf_frame = None + self.cached_run = None self.runstats_panel = wx.Panel(self, size=(100, 100)) self.runstats_box = wx.StaticBox(self.runstats_panel, label='Run Statistics') @@ -2946,6 +2966,10 @@ def __init__(self, parent, main): self.Bind(EVT_RUNSTATS_REFRESH, self.onRefresh) self.Bind(wx.EVT_SIZE, self.OnSize) + if hasattr(self.figure, '_cid'): + self.figure.canvas.mpl_disconnect(self.figure._cid) + self.figure._cid = self.figure.canvas.mpl_connect('button_press_event', self.onCanvasClick) + self.Layout() self.Fit() self.runstats_panelsize = self.runstats_box.GetSize() @@ -3004,6 +3028,58 @@ def onToggleOptions(self, e): self.Layout() self.Fit() + @staticmethod + def onCanvasClick(event): + if event.canvas.toolbar.mode: return + if event.xdata is None: return + tab = event.canvas.GetParent().GetParent().GetParent() + params = tab.main.params + if params.facility.name != 'lcls': return + all_stats = tab.main.runstats_sentinel.stats + if not all_stats: + return + x = round(event.xdata) + run_numbers = tab.main.runstats_sentinel.run_numbers + found_it = False + for run_number, stats in zip(run_numbers, all_stats): + timestamps, two_theta_low, two_theta_high, n_strong, resolutions, n_lattices = stats + if x < len(timestamps): + found_it = True + break + else: + x -= len(timestamps) + assert found_it, x + + trial = tab.trial + found_it = False + for rg in trial.rungroups: + for run in rg.runs: + if run.run == run_number: + found_it = True + break + if found_it: + break + assert found_it, run_number + + locator_path = os.path.join(params.output_folder, "r%04d"%int(run_number), \ + "%03d_rg%03d"%(trial.trial, rg.id), 'data.loc') + + from dials.command_line.image_viewer import phil_scope + from dials.util.image_viewer.spotfinder_frame import SpotFrame, chooser_wrapper + from dxtbx.model.experiment_list import ExperimentListFactory + if not tab.sf_frame: # if closed, wx windows resolve to False + expts = ExperimentListFactory.from_filenames([locator_path], load_models=False) + tab.sf_frame = SpotFrame(tab.main, params=phil_scope.extract(), experiments=[expts], reflections=[]) + tab.sf_frame.SetSize((1024, 780)) + elif tab.cached_run.run != run.run: + expts = ExperimentListFactory.from_filenames([locator_path], load_models=False) + tab.sf_frame.imagesets = expts.imagesets() + tab.sf_frame.add_file_name_or_data(chooser_wrapper(tab.sf_frame.imagesets[x], 0)) + print("Loading run %s, image %d"%(run.run, x+1)) + tab.sf_frame.load_image(chooser_wrapper(tab.sf_frame.imagesets[x], 0)) + tab.sf_frame.Show() + tab.cached_run = run + def onChkAutoUpdate(self, e): self.auto_update = self.chk_auto_update.GetValue() diff --git a/xfel/ui/db/job.py b/xfel/ui/db/job.py index 1647436e02..9717c6d4b7 100644 --- a/xfel/ui/db/job.py +++ b/xfel/ui/db/job.py @@ -1060,9 +1060,10 @@ def submit_all_jobs(app): print ("Task %s waiting on job %d (%s) for trial %d, rungroup %d, run %s, task %d" % \ (next_task.type, submitted_job.id, submitted_job.status, trial.trial, rungroup.id, run.run, next_task.id)) break - if submitted_job.status not in ["DONE", "EXIT"]: - print ("Task %s cannot start due to unexpected status for job %d (%s) for trial %d, rungroup %d, run %s, task %d" % \ - (next_task.type, submitted_job.id, submitted_job.status, trial.trial, rungroup.id, run.run, next_task.id)) + if submitted_job.status not in ["DONE"]: + if submitted_job.status != "EXIT": + print ("Task %s cannot start due to unexpected status for job %d (%s) for trial %d, rungroup %d, run %s, task %d" % \ + (next_task.type, submitted_job.id, submitted_job.status, trial.trial, rungroup.id, run.run, next_task.id)) break if submitted_job.status in ("SUBMIT_FAIL", "DELETED") and job.task and job.task.type == "ensemble_refinement": break # XXX need a better way to indicate that a job has failed and shouldn't go through the pipeline due to no data diff --git a/xfel/ui/db/xfel_db.py b/xfel/ui/db/xfel_db.py index 2913ec790d..315f984ab0 100644 --- a/xfel/ui/db/xfel_db.py +++ b/xfel/ui/db/xfel_db.py @@ -21,6 +21,8 @@ from xfel.command_line.experiment_manager import initialize as initialize_base +CACHED_CONNECT_TIMEOUT = 300 + class initialize(initialize_base): expected_tables = ["run", "job", "rungroup", "trial", "tag", "run_tag", "event", "trial_rungroup", "imageset", "imageset_event", "beam", "detector", "experiment", @@ -293,6 +295,7 @@ class db_application(object): def __init__(self, params, cache_connection = True, mode = 'execute'): self.params = params self.dbobj = None + self.dbobj_refreshed_time = None self.cache_connection = cache_connection self.query_count = 0 self.mode = mode @@ -326,8 +329,12 @@ def execute_query(self, query, commit=True): # https://stackoverflow.com/questions/1617637/pythons-mysqldb-not-getting-updated-row if not commit: # connection caching is not attempted if commit=False dbobj = get_db_connection(self.params, autocommit=False) - elif self.dbobj is None: + elif ( + self.dbobj is None + or time.time() - self.dbobj_refreshed_time > CACHED_CONNECT_TIMEOUT + ): dbobj = get_db_connection(self.params, autocommit=True) + self.dbobj_refreshed_time = time.time() if self.cache_connection: self.dbobj = dbobj else: From 03769f5727f4251a4ff5bea47205813af3e54c0a Mon Sep 17 00:00:00 2001 From: Vincent Chen Date: Fri, 3 May 2024 17:34:14 -0400 Subject: [PATCH 489/748] updates to mp test code to test vs mmcif files --- mmtbx/validation/cablam.py | 23 +- mmtbx/validation/regression/tst_cablam.py | 216 ++++++++++-------- mmtbx/validation/regression/tst_cbetadev.py | 21 +- .../regression/tst_chiral_validation.py | 27 ++- .../regression/tst_mp_validate_bonds.py | 13 +- mmtbx/validation/regression/tst_omegalyze.py | 22 +- mmtbx/validation/regression/tst_ramalyze.py | 20 +- .../validation/regression/tst_rna_validate.py | 38 ++- mmtbx/validation/regression/tst_rotalyze.py | 20 +- mmtbx/validation/regression/tst_suitename.py | 48 +++- mmtbx/validation/regression/tst_undowser.py | 10 +- 11 files changed, 314 insertions(+), 144 deletions(-) diff --git a/mmtbx/validation/cablam.py b/mmtbx/validation/cablam.py index 2281f27978..87df90aff8 100644 --- a/mmtbx/validation/cablam.py +++ b/mmtbx/validation/cablam.py @@ -231,6 +231,9 @@ def __init__(self): self.conf_names = [] self.confs = {} + def __repr__(self): + return str(self.conf_names)+str(self.confs) + class cablam_conf(): #conformer-level organization for cablam results def __init__(self): @@ -238,6 +241,9 @@ def __init__(self): self.results = {} self.sec_struc_records = [] + def __repr__(self): + return str(self.conf_name)+str(self.results)+str(self.sec_struc_records) + class secondary_structure_segment(): #holds a secondary structure element identified by cablam def __init__(self, start, end, segment_type, segment_length): @@ -331,6 +337,9 @@ def as_string(self): #----------------------------------------------------------------------------- #}}} + def __repr__(self): + return self.as_string() + #{{{ mp_id #----------------------------------------------------------------------------- def mp_id(self): @@ -372,9 +381,11 @@ def sorting_id(self): #----------------------------------------------------------------------------- #returns the desired atom from a hierarchy residue object def get_atom(self, atom_name): - for atom in self.residue.atoms(): - if atom.name == atom_name: return atom - else: return None + #for atom in self.residue.atoms(): + # if atom.name == atom_name: return atom + atom = self.residue.find_atom_by(atom_name) + return atom + #else: return None #----------------------------------------------------------------------------- #}}} @@ -919,9 +930,11 @@ def __init__(self, if conf.is_protein(): break #at least one conformer must be protein else: continue if use_segids: - chain_id = utils.get_segid_as_chainid(chain=chain).rjust(2) + chain_id = utils.get_segid_as_chainid(chain=chain) else: - chain_id = chain.id.rjust(2) + chain_id = chain.id + if len(chain_id) < 2: + chain_id = chain_id.rjust(2) #The above .rjust(2)'s are to force 2-char chain ids current_chain = cablam_chain() self.all_results[model.id][chain_id] = current_chain diff --git a/mmtbx/validation/regression/tst_cablam.py b/mmtbx/validation/regression/tst_cablam.py index d87cf8f2f8..759b4c0ffd 100644 --- a/mmtbx/validation/regression/tst_cablam.py +++ b/mmtbx/validation/regression/tst_cablam.py @@ -2,6 +2,7 @@ from mmtbx.validation import cablam from libtbx.test_utils import show_diff from iotbx.data_manager import DataManager +from libtbx.test_utils import convert_string_to_cif_long, convert_pdb_to_cif_for_pdb_str from iotbx import pdb import libtbx.load_env @@ -212,101 +213,105 @@ def exercise_cablam(): assert not show_diff(output_holder.output , ref_cablam_text) cablam_json_multimodel_pdb = """MODEL 1 -ATOM 120 N LEU 15 47.483 17.606 20.296 1.00 24.69 103L 218 -ATOM 121 CA LEU 15 47.208 17.724 21.716 1.00 28.08 103L 219 -ATOM 122 C LEU 15 46.866 19.132 22.189 1.00 47.52 103L 220 -ATOM 123 O LEU 15 46.551 19.411 23.375 1.00 42.41 103L 221 -ATOM 124 CB LEU 15 48.364 17.085 22.505 1.00 31.96 103L 222 -ATOM 125 CG LEU 15 48.460 15.567 22.290 1.00 33.79 103L 223 -ATOM 126 CD1 LEU 15 49.627 14.978 23.088 1.00 56.11 103L 224 -ATOM 127 CD2 LEU 15 47.145 14.911 22.717 1.00 70.78 103L 225 -ATOM 128 N LYS 16 46.925 20.028 21.225 1.00 27.45 103L 226 -ATOM 129 CA LYS 16 46.714 21.414 21.506 1.00 50.37 103L 227 -ATOM 130 C LYS 16 45.623 21.941 20.637 1.00 31.00 103L 228 -ATOM 131 O LYS 16 45.582 21.634 19.451 1.00 60.11 103L 229 -ATOM 132 CB LYS 16 48.019 22.163 21.214 1.00 55.51 103L 230 -ATOM 133 CG LYS 16 48.021 23.610 21.660 1.00 83.77 103L 231 -ATOM 134 CD LYS 16 48.087 23.790 23.175 1.00100.00 103L 232 -ATOM 135 CE LYS 16 46.895 24.555 23.771 1.00100.00 103L 233 -ATOM 136 NZ LYS 16 46.850 26.013 23.485 1.00100.00 103L 234 -ATOM 137 N ILE 17 44.688 22.708 21.196 1.00 56.16 103L 235 -ATOM 138 CA ILE 17 43.629 23.210 20.321 1.00 19.13 103L 236 -ATOM 139 C ILE 17 44.193 23.624 18.967 1.00 40.60 103L 237 -ATOM 140 O ILE 17 45.370 23.978 18.830 1.00 68.25 103L 238 -ATOM 141 CB ILE 17 42.830 24.404 20.896 1.00 47.36 103L 239 -ATOM 142 CG1 ILE 17 42.267 24.102 22.265 1.00 43.38 103L 240 -ATOM 143 CG2 ILE 17 41.684 24.855 19.952 1.00 16.95 103L 241 -ATOM 144 CD1 ILE 17 40.965 24.845 22.441 1.00 27.07 103L 242 -ATOM 145 N TYR 18 43.324 23.628 17.965 1.00 20.84 103L 243 -ATOM 146 CA TYR 18 43.767 24.010 16.657 1.00 17.35 103L 244 -ATOM 147 C TYR 18 42.604 24.316 15.754 1.00 20.49 103L 245 -ATOM 148 O TYR 18 41.441 24.001 16.010 1.00 36.50 103L 246 -ATOM 149 CB TYR 18 44.788 23.023 16.018 1.00 42.02 103L 247 -ATOM 150 CG TYR 18 44.181 21.700 15.576 1.00 53.94 103L 248 -ATOM 151 CD1 TYR 18 44.040 20.596 16.425 1.00 30.37 103L 249 -ATOM 152 CD2 TYR 18 43.736 21.576 14.262 1.00 27.24 103L 250 -ATOM 153 CE1 TYR 18 43.447 19.409 15.988 1.00 71.37 103L 251 -ATOM 154 CE2 TYR 18 43.188 20.385 13.783 1.00 25.76 103L 252 -ATOM 155 CZ TYR 18 43.014 19.319 14.661 1.00 38.01 103L 253 -ATOM 156 OH TYR 18 42.461 18.164 14.150 1.00 42.56 103L 254 -ATOM 157 N LYS 19 42.908 24.929 14.651 1.00 27.49 103L 255 -ATOM 158 CA LYS 19 41.887 25.242 13.695 1.00 22.06 103L 256 -ATOM 159 C LYS 19 41.905 24.288 12.552 1.00 73.84 103L 257 -ATOM 160 O LYS 19 42.947 23.965 11.971 1.00 50.03 103L 258 -ATOM 161 CB LYS 19 41.983 26.625 13.131 1.00 32.98 103L 259 -ATOM 162 CG LYS 19 41.434 27.679 14.049 1.00 94.12 103L 260 -ATOM 163 CD LYS 19 41.484 29.058 13.414 1.00100.00 103L 261 -ATOM 164 CE LYS 19 42.332 30.073 14.190 1.00 71.32 103L 262 -ATOM 165 NZ LYS 19 42.244 31.445 13.655 1.00100.00 103L 263 +ATOM 120 N LEU A 15 47.483 17.606 20.296 1.00 24.69 N +ATOM 121 CA LEU A 15 47.208 17.724 21.716 1.00 28.08 C +ATOM 122 C LEU A 15 46.866 19.132 22.189 1.00 47.52 C +ATOM 123 O LEU A 15 46.551 19.411 23.375 1.00 42.41 O +ATOM 124 CB LEU A 15 48.364 17.085 22.505 1.00 31.96 C +ATOM 125 CG LEU A 15 48.460 15.567 22.290 1.00 33.79 C +ATOM 126 CD1 LEU A 15 49.627 14.978 23.088 1.00 56.11 C +ATOM 127 CD2 LEU A 15 47.145 14.911 22.717 1.00 70.78 C +ATOM 128 N LYS A 16 46.925 20.028 21.225 1.00 27.45 N +ATOM 129 CA LYS A 16 46.714 21.414 21.506 1.00 50.37 C +ATOM 130 C LYS A 16 45.623 21.941 20.637 1.00 31.00 C +ATOM 131 O LYS A 16 45.582 21.634 19.451 1.00 60.11 O +ATOM 132 CB LYS A 16 48.019 22.163 21.214 1.00 55.51 C +ATOM 133 CG LYS A 16 48.021 23.610 21.660 1.00 83.77 C +ATOM 134 CD LYS A 16 48.087 23.790 23.175 1.00100.00 C +ATOM 135 CE LYS A 16 46.895 24.555 23.771 1.00100.00 C +ATOM 136 NZ LYS A 16 46.850 26.013 23.485 1.00100.00 N +ATOM 137 N ILE A 17 44.688 22.708 21.196 1.00 56.16 N +ATOM 138 CA ILE A 17 43.629 23.210 20.321 1.00 19.13 C +ATOM 139 C ILE A 17 44.193 23.624 18.967 1.00 40.60 C +ATOM 140 O ILE A 17 45.370 23.978 18.830 1.00 68.25 O +ATOM 141 CB ILE A 17 42.830 24.404 20.896 1.00 47.36 C +ATOM 142 CG1 ILE A 17 42.267 24.102 22.265 1.00 43.38 C +ATOM 143 CG2 ILE A 17 41.684 24.855 19.952 1.00 16.95 C +ATOM 144 CD1 ILE A 17 40.965 24.845 22.441 1.00 27.07 C +ATOM 145 N TYR A 18 43.324 23.628 17.965 1.00 20.84 N +ATOM 146 CA TYR A 18 43.767 24.010 16.657 1.00 17.35 C +ATOM 147 C TYR A 18 42.604 24.316 15.754 1.00 20.49 C +ATOM 148 O TYR A 18 41.441 24.001 16.010 1.00 36.50 O +ATOM 149 CB TYR A 18 44.788 23.023 16.018 1.00 42.02 C +ATOM 150 CG TYR A 18 44.181 21.700 15.576 1.00 53.94 C +ATOM 151 CD1 TYR A 18 44.040 20.596 16.425 1.00 30.37 C +ATOM 152 CD2 TYR A 18 43.736 21.576 14.262 1.00 27.24 C +ATOM 153 CE1 TYR A 18 43.447 19.409 15.988 1.00 71.37 C +ATOM 154 CE2 TYR A 18 43.188 20.385 13.783 1.00 25.76 C +ATOM 155 CZ TYR A 18 43.014 19.319 14.661 1.00 38.01 C +ATOM 156 OH TYR A 18 42.461 18.164 14.150 1.00 42.56 O +ATOM 157 N LYS A 19 42.908 24.929 14.651 1.00 27.49 N +ATOM 158 CA LYS A 19 41.887 25.242 13.695 1.00 22.06 C +ATOM 159 C LYS A 19 41.905 24.288 12.552 1.00 73.84 C +ATOM 160 O LYS A 19 42.947 23.965 11.971 1.00 50.03 O +ATOM 161 CB LYS A 19 41.983 26.625 13.131 1.00 32.98 C +ATOM 162 CG LYS A 19 41.434 27.679 14.049 1.00 94.12 C +ATOM 163 CD LYS A 19 41.484 29.058 13.414 1.00100.00 C +ATOM 164 CE LYS A 19 42.332 30.073 14.190 1.00 71.32 C +ATOM 165 NZ LYS A 19 42.244 31.445 13.655 1.00100.00 N ENDMDL MODEL 2 -ATOM 1014 N LEU 133 30.536 10.928 -6.190 1.00 16.93 103L1112 -ATOM 1015 CA LEU 133 31.011 11.480 -4.927 1.00 19.63 103L1113 -ATOM 1016 C LEU 133 31.992 12.625 -5.134 1.00 26.72 103L1114 -ATOM 1017 O LEU 133 32.125 13.484 -4.270 1.00 23.28 103L1115 -ATOM 1018 CB LEU 133 31.707 10.402 -4.052 1.00 14.35 103L1116 -ATOM 1019 CG LEU 133 30.760 9.425 -3.342 1.00 31.49 103L1117 -ATOM 1020 CD1 LEU 133 31.551 8.266 -2.745 1.00 37.78 103L1118 -ATOM 1021 CD2 LEU 133 30.076 10.146 -2.198 1.00 14.00 103L1119 -ATOM 1022 N ALA 134 32.750 12.572 -6.245 1.00 21.52 103L1120 -ATOM 1023 CA ALA 134 33.801 13.544 -6.549 1.00 21.07 103L1121 -ATOM 1024 C ALA 134 33.292 14.934 -6.866 1.00 21.47 103L1122 -ATOM 1025 O ALA 134 34.032 15.932 -6.804 1.00 19.33 103L1123 -ATOM 1026 CB ALA 134 34.720 13.025 -7.662 1.00 17.54 103L1124 -ATOM 1027 N LYS 135 32.011 14.996 -7.224 1.00 21.06 103L1125 -ATOM 1028 CA LYS 135 31.347 16.250 -7.554 1.00 25.54 103L1126 -ATOM 1029 C LYS 135 30.774 16.866 -6.309 1.00 19.56 103L1127 -ATOM 1030 O LYS 135 29.550 16.919 -6.156 1.00 24.91 103L1128 -ATOM 1031 CB LYS 135 30.214 16.106 -8.570 1.00 12.97 103L1129 -ATOM 1032 CG LYS 135 30.558 15.217 -9.733 1.00 22.54 103L1130 -ATOM 1033 CD LYS 135 29.544 15.351 -10.840 1.00 46.13 103L1131 -ATOM 1034 CE LYS 135 30.178 15.191 -12.206 1.00 71.90 103L1132 -ATOM 1035 NZ LYS 135 29.730 13.985 -12.903 1.00 97.93 103L1133 -ATOM 1036 N SER 136 31.642 17.287 -5.410 1.00 13.65 103L1134 -ATOM 1037 CA SER 136 31.181 17.859 -4.158 1.00 14.56 103L1135 -ATOM 1038 C SER 136 32.180 18.868 -3.601 1.00 27.10 103L1136 -ATOM 1039 O SER 136 33.388 18.832 -3.911 1.00 22.82 103L1137 -ATOM 1040 CB SER 136 31.008 16.717 -3.136 1.00 17.51 103L1138 -ATOM 1041 OG SER 136 32.237 15.971 -3.070 1.00 15.66 103L1139 -ATOM 1042 N ARG 137 31.700 19.738 -2.728 1.00 19.66 103L1140 -ATOM 1043 CA ARG 137 32.576 20.679 -2.052 1.00 18.34 103L1141 -ATOM 1044 C ARG 137 33.630 19.903 -1.265 1.00 15.29 103L1142 -ATOM 1045 O ARG 137 34.808 20.230 -1.267 1.00 20.30 103L1143 -ATOM 1046 CB ARG 137 31.754 21.450 -1.038 1.00 22.08 103L1144 -ATOM 1047 CG ARG 137 32.616 22.258 -0.087 1.00 29.17 103L1145 -ATOM 1048 CD ARG 137 31.813 23.256 0.761 1.00 24.81 103L1146 -ATOM 1049 NE ARG 137 32.564 24.474 1.087 1.00100.00 103L1147 -ATOM 1050 CZ ARG 137 33.415 24.547 2.121 1.00100.00 103L1148 -ATOM 1051 NH1 ARG 137 33.629 23.496 2.928 1.00100.00 103L1149 -ATOM 1052 NH2 ARG 137 34.073 25.698 2.345 1.00100.00 103L1150 +ATOM 1014 N LEU A 133 30.536 10.928 -6.190 1.00 16.93 N +ATOM 1015 CA LEU A 133 31.011 11.480 -4.927 1.00 19.63 C +ATOM 1016 C LEU A 133 31.992 12.625 -5.134 1.00 26.72 C +ATOM 1017 O LEU A 133 32.125 13.484 -4.270 1.00 23.28 O +ATOM 1018 CB LEU A 133 31.707 10.402 -4.052 1.00 14.35 C +ATOM 1019 CG LEU A 133 30.760 9.425 -3.342 1.00 31.49 C +ATOM 1020 CD1 LEU A 133 31.551 8.266 -2.745 1.00 37.78 C +ATOM 1021 CD2 LEU A 133 30.076 10.146 -2.198 1.00 14.00 C +ATOM 1022 N ALA A 134 32.750 12.572 -6.245 1.00 21.52 N +ATOM 1023 CA ALA A 134 33.801 13.544 -6.549 1.00 21.07 C +ATOM 1024 C ALA A 134 33.292 14.934 -6.866 1.00 21.47 C +ATOM 1025 O ALA A 134 34.032 15.932 -6.804 1.00 19.33 O +ATOM 1026 CB ALA A 134 34.720 13.025 -7.662 1.00 17.54 C +ATOM 1027 N LYS A 135 32.011 14.996 -7.224 1.00 21.06 N +ATOM 1028 CA LYS A 135 31.347 16.250 -7.554 1.00 25.54 C +ATOM 1029 C LYS A 135 30.774 16.866 -6.309 1.00 19.56 C +ATOM 1030 O LYS A 135 29.550 16.919 -6.156 1.00 24.91 O +ATOM 1031 CB LYS A 135 30.214 16.106 -8.570 1.00 12.97 C +ATOM 1032 CG LYS A 135 30.558 15.217 -9.733 1.00 22.54 C +ATOM 1033 CD LYS A 135 29.544 15.351 -10.840 1.00 46.13 C +ATOM 1034 CE LYS A 135 30.178 15.191 -12.206 1.00 71.90 C +ATOM 1035 NZ LYS A 135 29.730 13.985 -12.903 1.00 97.93 N +ATOM 1036 N SER A 136 31.642 17.287 -5.410 1.00 13.65 N +ATOM 1037 CA SER A 136 31.181 17.859 -4.158 1.00 14.56 C +ATOM 1038 C SER A 136 32.180 18.868 -3.601 1.00 27.10 C +ATOM 1039 O SER A 136 33.388 18.832 -3.911 1.00 22.82 O +ATOM 1040 CB SER A 136 31.008 16.717 -3.136 1.00 17.51 C +ATOM 1041 OG SER A 136 32.237 15.971 -3.070 1.00 15.66 O +ATOM 1042 N ARG A 137 31.700 19.738 -2.728 1.00 19.66 N +ATOM 1043 CA ARG A 137 32.576 20.679 -2.052 1.00 18.34 C +ATOM 1044 C ARG A 137 33.630 19.903 -1.265 1.00 15.29 C +ATOM 1045 O ARG A 137 34.808 20.230 -1.267 1.00 20.30 O +ATOM 1046 CB ARG A 137 31.754 21.450 -1.038 1.00 22.08 C +ATOM 1047 CG ARG A 137 32.616 22.258 -0.087 1.00 29.17 C +ATOM 1048 CD ARG A 137 31.813 23.256 0.761 1.00 24.81 C +ATOM 1049 NE ARG A 137 32.564 24.474 1.087 1.00100.00 N +ATOM 1050 CZ ARG A 137 33.415 24.547 2.121 1.00100.00 C +ATOM 1051 NH1 ARG A 137 33.629 23.496 2.928 1.00100.00 N +ATOM 1052 NH2 ARG A 137 34.073 25.698 2.345 1.00100.00 N ENDMDL END """ -def exercise_cablam_json2(): +def exercise_cablam_json2(test_mmcif=False): dm = DataManager() #print(help(dm)) - dm.process_model_str("1",cablam_json_multimodel_pdb) + if test_mmcif: + pdb_test_string = convert_string_to_cif_long(cablam_json_multimodel_pdb, hetatm_name_addition = "", chain_addition="LONGCHAIN") + else: + pdb_test_string = cablam_json_multimodel_pdb + dm.process_model_str("1",pdb_test_string) m = dm.get_model("1") output_holder = cablam_test_string() @@ -318,10 +323,20 @@ def exercise_cablam_json2(): cablam_json = cablamalyze.as_JSON() cablam_dict = json.loads(cablam_json) - assert cablam_dict['summary_results'][" 2"]["num_cablam_disfavored"]==1, "tst_cablam summary json model 2 num_disfavored value changed, now: "+str(cablam_dict['summary_results'][" 2"]["num_cablam_disfavored"]) - assert cablam_dict['summary_results'][" 1"]["num_cablam_outliers"]==1, "tst_cablam summary json model 1 num_outliers value changed, now: "+str(cablam_dict['summary_results'][" 1"]["num_cablam_outliers"]) + #import pprint + #pprint.pprint(cablam_dict) + summary_results_dict = cablam_dict['summary_results'] + if " 1" in summary_results_dict: + summary_results_1_dict = summary_results_dict[" 1"] + summary_results_2_dict = summary_results_dict[" 2"] + else: + summary_results_1_dict = summary_results_dict["1"] + summary_results_2_dict = summary_results_dict["2"] + assert summary_results_2_dict["num_cablam_disfavored"]==1, "tst_cablam summary json model 2 num_disfavored value changed, now: "+str(cablam_dict['summary_results'][" 2"]["num_cablam_disfavored"]) + assert summary_results_1_dict["num_cablam_outliers"]==1, "tst_cablam summary json model 1 num_outliers value changed, now: "+str(cablam_dict['summary_results'][" 1"]["num_cablam_outliers"]) + return cablam_dict -def exercise_cablam_json(): +def exercise_cablam_json(test_mmcif=False): regression_pdb = libtbx.env.find_in_repositories( relative_path="phenix_regression/pdb/pdb103l.ent", test=os.path.isfile) #This is the same file used for tst_kinemage.py @@ -330,9 +345,18 @@ def exercise_cablam_json(): return #----- dm = DataManager() - m = dm.get_model(regression_pdb) + if test_mmcif: + with open(regression_pdb) as f: + pdb_103l_str = f.read() + pdb_103l_str = convert_string_to_cif_long(pdb_103l_str, hetatm_name_addition = "", chain_addition="LONGCHAIN") + dm.process_model_str("1", pdb_103l_str) + m = dm.get_model("1") + else: + m = dm.get_model(regression_pdb) output_holder = cablam_test_string() + pdb_hierarchy_tst = m.get_hierarchy() + cablamalyze = cablam.cablamalyze( pdb_hierarchy = m.get_hierarchy(), outliers_only=False, @@ -354,9 +378,15 @@ def exercise_cablam_json(): def run(): t0 = time.time() exercise_cablam() + print("Cablam Text test OK") exercise_cablam_json() - exercise_cablam_json2() - print("OK") + exercise_cablam_json(test_mmcif=True) + print("Cablam JSON 1 OK") + cablam_dict2 = exercise_cablam_json2() + cablam_dict2cif = exercise_cablam_json2(test_mmcif=True) + assert cablam_dict2['summary_results'][' 1'] == cablam_dict2cif['summary_results']['1'] + assert cablam_dict2['summary_results'][' 2'] == cablam_dict2cif['summary_results']['2'] + print("Cablam JSON 2 OK") print("OK. Time: %8.3f"%(time.time()-t0)) if (__name__ == "__main__"): diff --git a/mmtbx/validation/regression/tst_cbetadev.py b/mmtbx/validation/regression/tst_cbetadev.py index bb1904481d..94c2f61902 100644 --- a/mmtbx/validation/regression/tst_cbetadev.py +++ b/mmtbx/validation/regression/tst_cbetadev.py @@ -6,6 +6,7 @@ from six.moves import cStringIO as StringIO import iotbx.pdb from iotbx.data_manager import DataManager +from libtbx.test_utils import convert_string_to_cif_long import os.path import json import time @@ -311,7 +312,7 @@ def exercise_cbetadev_unknown_peptide(): assert cb.deviation<1. print('OK') -def exercise_cbetadev_json(): +def exercise_cbetadev_json(test_mmcif=False): regression_pdb = libtbx.env.find_in_repositories( relative_path="phenix_regression/pdb/pdb1jxt.ent", test=os.path.isfile) @@ -320,15 +321,25 @@ def exercise_cbetadev_json(): return from mmtbx.validation import cbetadev dm = DataManager() - m = dm.get_model(regression_pdb) + if test_mmcif: + with open(regression_pdb) as f: + pdb_1jxt_str = f.read() + pdb_1jxt_str = convert_string_to_cif_long(pdb_1jxt_str, hetatm_name_addition = "", chain_addition="LONGCHAIN") + dm.process_model_str("1", pdb_1jxt_str) + m = dm.get_model("1") + chainA = "ALONGCHAIN" + else: + m = dm.get_model(regression_pdb) + chainA = "A" cbeta_json = cbetadev.cbetadev(pdb_hierarchy=m.get_hierarchy(), outliers_only=True).as_JSON() cbeta_dict = json.loads(cbeta_json) assert len(cbeta_dict['flat_results'])==6, "tst_cbetadev json output not returning correct number of outliers, now: "+str(len(cbeta_dict['flat_results'])) assert approx_equal(cbeta_dict['flat_results'][0]['deviation'], 0.25977096732623106), "tst_cbetadev json output first deviation not approx_equal, now: "+str(cbeta_dict['flat_results'][0]['deviation']) assert approx_equal(cbeta_dict['flat_results'][-1]['deviation'], 0.5001892640352836), "tst_cbetadev json output last deviation not approx_equal, now: "+str(cbeta_dict['flat_results'][-1]['deviation']) - assert approx_equal(cbeta_dict['hierarchical_results']['']["A"][" 8 "]['B']["dihedral_NABB"], 80.92016704402938), "tst_cbetadev json output hierarchical result changed dihedral_NABB result, now: "+str(cbeta_dict['hierarchical_results']['']["A"][" 8 "]['B']["dihedral_NABB"]) + assert approx_equal(cbeta_dict['hierarchical_results'][''][chainA][" 8 "]['B']["dihedral_NABB"], 80.92016704402938), "tst_cbetadev json output hierarchical result changed dihedral_NABB result, now: "+str(cbeta_dict['hierarchical_results'][''][chainA][" 8 "]['B']["dihedral_NABB"]) assert cbeta_dict['summary_results'][""]['num_outliers']==6, "tst_cbetadev json output summary results num_outliers changed, now: "+str(cbeta_dict['summary_results'][""]['num_outliers']) assert cbeta_dict['summary_results'][""]['num_cbeta_residues']==51, "tst_cbetadev json output summary results num_cbeta_residues changed, now: "+str(cbeta_dict['summary_results'][""]['num_cbeta_residues']) + return cbeta_dict if (__name__ == "__main__"): t0 = time.time() @@ -337,5 +348,7 @@ def exercise_cbetadev_json(): exercise_cbetadev_misnamed_peptides() exercise_cbetadev_nonstandard_peptide() exercise_cbetadev_unknown_peptide() - exercise_cbetadev_json() + cb_dict = exercise_cbetadev_json() + cb_dict_cif = exercise_cbetadev_json(test_mmcif=True) + assert cb_dict['summary_results'] == cb_dict_cif['summary_results'], "tst_cbetadev summary results changed between pdb and cif version" print("OK. Time: %8.3f"%(time.time()-t0)) diff --git a/mmtbx/validation/regression/tst_chiral_validation.py b/mmtbx/validation/regression/tst_chiral_validation.py index 82854f5e11..117b6fbd3f 100644 --- a/mmtbx/validation/regression/tst_chiral_validation.py +++ b/mmtbx/validation/regression/tst_chiral_validation.py @@ -141,23 +141,34 @@ def exercise_chiral_validation(chiral_list): def exercise_chiral_json(chiral_list): ch_dict = json.loads(chiral_list.as_JSON()) #import pprint - #pprint.pprint(csjson_dict) + #pprint.pprint(ch_dict) assert len(ch_dict['flat_results']) == 6, "tst_chiral_validation json output not returning correct number of water clashes, now: "+str(len(ch_dict['flat_results'])) assert ch_dict['flat_results'][0]["outlier_type"] == "Tetrahedral geometry outlier", "tst_chiral_validation json output first outlier_type value changed, now: "+ch_dict['flat_results'][0]["outlier_type"] from mmtbx.validation import test_utils assert test_utils.count_dict_values(ch_dict['hierarchical_results'], "Tetrahedral geometry outlier")==2, "tst_chiral_validation json hierarchical output total number of Tetrahedral geometry outlier changed, now: "+str(test_utils.count_dict_values(ch_dict['hierarchical_results'], "Tetrahedral geometry outlier")) assert test_utils.count_dict_values(ch_dict['hierarchical_results'], "Pseudochiral naming error")==2, "tst_chiral_validation json hierarchical output total number of Pseudochiral naming error changed, now: "+str(test_utils.count_dict_values(ch_dict['hierarchical_results'], "Pseudochiral naming error")) assert test_utils.count_dict_values(ch_dict['hierarchical_results'], "Chiral handedness swap")==2, "tst_chiral_validation json hierarchical output total number of Chiral handedness swap changed, now: "+str(test_utils.count_dict_values(ch_dict['hierarchical_results'], "Chiral handedness swap")) - assert ch_dict['summary_results'][" 1"]["num_outliers"] == 3, "tst_chiral_validation json summary output total number of outliers changed, now: "+str(ch_dict['summary_results'][" 1"]["num_outliers"]) - assert ch_dict['summary_results'][" 1"]["num_chiral_centers"] == 1, "tst_chiral_validation json summary output total number of true chiral centers changed, now: "+str(ch_dict['summary_results'][" 1"]["num_chiral_centers"]) - assert ch_dict['summary_results'][" 1"]["num_total"] == 3, "tst_chiral_validation json summary output total number of tetrahedral changed, now: "+str(ch_dict['summary_results'][" 1"]["num_total"]) - assert ch_dict['summary_results'][" 2"]["num_outliers"] == 3, "tst_chiral_validation json summary output model 2 total number of outliers changed, now: "+str(ch_dict['summary_results'][" 1"]["num_outliers"]) + summary_results_dict = ch_dict['summary_results'] + if " 1" in summary_results_dict: + summary_results_1_dict = summary_results_dict[" 1"] + summary_results_2_dict = summary_results_dict[" 2"] + else: + summary_results_1_dict = summary_results_dict["1"] + summary_results_2_dict = summary_results_dict["2"] + assert summary_results_1_dict["num_outliers"] == 3, "tst_chiral_validation json summary output total number of outliers changed, now: "+str(ch_dict['summary_results'][" 1"]["num_outliers"]) + assert summary_results_1_dict["num_chiral_centers"] == 1, "tst_chiral_validation json summary output total number of true chiral centers changed, now: "+str(ch_dict['summary_results'][" 1"]["num_chiral_centers"]) + assert summary_results_1_dict["num_total"] == 3, "tst_chiral_validation json summary output total number of tetrahedral changed, now: "+str(ch_dict['summary_results'][" 1"]["num_total"]) + assert summary_results_2_dict["num_outliers"] == 3, "tst_chiral_validation json summary output model 2 total number of outliers changed, now: "+str(ch_dict['summary_results'][" 1"]["num_outliers"]) + return ch_dict if (__name__ == "__main__"): t0 = time.time() chiral_list = calculate_results() exercise_chiral_validation(chiral_list) - exercise_chiral_json(chiral_list) - convert_pdb_to_cif_for_pdb_str(locals(), chain_addition="ALONGCHAIN", key_str="pdb_") - exercise_chiral_json(chiral_list) + ch_dict = exercise_chiral_json(chiral_list) + convert_pdb_to_cif_for_pdb_str(locals(), chain_addition="LONGCHAIN", hetatm_name_addition = "", key_str="pdb_", print_new_string = False) + chiral_list = calculate_results() + ch_dict_cif = exercise_chiral_json(chiral_list) + assert ch_dict['summary_results'][' 1'] == ch_dict_cif['summary_results']['1'], "tst_chiral_validation summary results changed between pdb and cif version" + assert ch_dict['summary_results'][' 2'] == ch_dict_cif['summary_results']['2'], "tst_chiral_validation summary results changed between pdb and cif version" print("OK. Time: %8.3f"%(time.time()-t0)) diff --git a/mmtbx/validation/regression/tst_mp_validate_bonds.py b/mmtbx/validation/regression/tst_mp_validate_bonds.py index 5175dc2a48..de99557bfd 100644 --- a/mmtbx/validation/regression/tst_mp_validate_bonds.py +++ b/mmtbx/validation/regression/tst_mp_validate_bonds.py @@ -5,7 +5,7 @@ from mmtbx.model import manager from libtbx.utils import null_out from libtbx.test_utils import approx_equal - +from libtbx.test_utils import convert_pdb_to_cif_for_pdb_str import time import json @@ -173,8 +173,9 @@ def exercise_mp_validate_bonds(): pdb_atoms=atoms, geometry_restraints_manager=geometry, outliers_only=False) - + #import pprint bonds_json = json.loads(bonds.as_JSON()) + #pprint.pprint(bonds_json) assert len(bonds_json['flat_results'])==19, "tst_mp_validate_bonds total number of bonds changed, now: "+str(len(bonds_json['flat_results'])) assert approx_equal(bonds_json['flat_results'][18]["sigma"], 0.019), "tst_mp_validate_bonds json output last sigma value changed, now: "+str(bonds_json['flat_results'][18]["sigma"]) assert bonds_json['summary_results'][""]["num_outliers"] == 1, "tst_mp_validate_bonds json summary output total number of outliers changed, now: "+str(bonds_json['summary_results'][""]["num_outliers"]) @@ -182,14 +183,20 @@ def exercise_mp_validate_bonds(): assert bonds_json['summary_results'][""]["num_outliers_too_small"] == 0, "tst_mp_validate_bonds json summary output total number of bonds too small changed, now: "+str(bonds_json['summary_results'][""]["num_outliers_too_small"]) assert bonds_json['summary_results'][""]["num_outliers_too_large"] == 1, "tst_mp_validate_bonds json summary output total number of bonds too large changed, now: "+str(bonds_json['summary_results'][""]["num_outliers_too_large"]) angles_json = json.loads(angles.as_JSON()) + #pprint.pprint(angles_json) assert len(angles_json['flat_results'])==24, "tst_mp_validate_bonds total number of angles changed, now: "+str(len(angles_json['flat_results'])) assert approx_equal(angles_json['flat_results'][23]["sigma"], 2.3), "tst_mp_validate_bonds json output last sigma value changed, now: "+str(angles_json['flat_results'][23]["sigma"]) assert angles_json['summary_results'][""]["num_outliers"] == 1, "tst_mp_validate_bonds json summary output total number of outliers changed, now: "+str(angles_json['summary_results'][""]["num_outliers"]) assert angles_json['summary_results'][""]["num_total"]==24, "tst_mp_validate_bonds json summary output total number of angles changed, now: "+str(angles_json['summary_results'][""]["num_total"]) assert angles_json['summary_results'][""]["num_outliers_too_small"]==1, "tst_mp_validate_bonds json summary output total number of angles too small changed, now: "+str(angles_json['summary_results'][""]["num_outliers_too_small"]) assert angles_json['summary_results'][""]["num_outliers_too_large"]==0, "tst_mp_validate_bonds json summary output total number of angles too large changed, now: "+str(angles_json['summary_results'][""]["num_outliers_too_large"]) + return bonds_json, angles_json if (__name__ == "__main__"): t0 = time.time() - exercise_mp_validate_bonds() + bonds_dict, angles_dict = exercise_mp_validate_bonds() + convert_pdb_to_cif_for_pdb_str(locals(), chain_addition="LONGCHAIN", hetatm_name_addition = "", key_str="pdb_", print_new_string = False) + bonds_dict_cif, angles_dict_cif = exercise_mp_validate_bonds() + assert bonds_dict['summary_results'] == bonds_dict_cif['summary_results'], "tst_mp_validate_bonds summary results changed between pdb and cif version" + assert angles_dict['summary_results'] == angles_dict_cif['summary_results'], "tst_mp_validate_bonds summary results changed between pdb and cif version" print("OK. Time: %8.3f"%(time.time()-t0)) diff --git a/mmtbx/validation/regression/tst_omegalyze.py b/mmtbx/validation/regression/tst_omegalyze.py index b46c77a3a2..c1c53d4bc4 100644 --- a/mmtbx/validation/regression/tst_omegalyze.py +++ b/mmtbx/validation/regression/tst_omegalyze.py @@ -3,6 +3,7 @@ from libtbx.test_utils import show_diff, approx_equal from iotbx import pdb from iotbx.data_manager import DataManager +from libtbx.test_utils import convert_string_to_cif_long import libtbx.load_env import os import json @@ -55,7 +56,7 @@ def exercise_omegalyze(): assert not show_diff(text_test.output , ref_omegalyze_give_text) -def exercise_omegalyze_json(): +def exercise_omegalyze_json(test_mmcif=False): regression_pdb = libtbx.env.find_in_repositories( relative_path="phenix_regression/pdb/2hr0.pdb", test=os.path.isfile) @@ -64,14 +65,24 @@ def exercise_omegalyze_json(): return #----- dm = DataManager() - m = dm.get_model(regression_pdb) + if test_mmcif: + with open(regression_pdb) as f: + pdb_2hr0_str = f.read() + pdb_2hr0_str = convert_string_to_cif_long(pdb_2hr0_str, chain_addition="LONGCHAIN") + dm.process_model_str("1", pdb_2hr0_str) + m = dm.get_model("1") + #print(pdb_2hr0_str) + else: + m = dm.get_model(regression_pdb) + omegalyze_json = omegalyze.omegalyze(pdb_hierarchy=m.get_hierarchy(), nontrans_only=True).as_JSON() omjson_dict = json.loads(omegalyze_json) - import pprint + #import pprint #pprint.pprint(omjson_dict) assert len(omjson_dict['flat_results'])==9, "tst_omegalyze json output not returning correct number of nontrans residues, now: "+str(len(omjson_dict['flat_results'])) assert approx_equal(omjson_dict['flat_results'][0]['omega'], -14.27418253081719), "tst_omegalyze json output first calculated omega dihedral angle not matching previous value, now: "+str(omjson_dict['flat_results'][0]['omega']) assert omjson_dict['flat_results'][0]['omega_type']=='Cis', "tst_omegalyze json output first omega_type not matching previous value, now: "+str(omjson_dict['flat_results'][0]['omega_type']) + assert approx_equal(omjson_dict['flat_results'][0]['highest_mc_b'], 28.76), "tst_omegalyze json output first calculated highest_mc_b not matching previous value, now: "+str(omjson_dict['flat_results'][0]['highest_mc_b']) assert approx_equal(omjson_dict['flat_results'][8]['omega'], 8.043663329121266), "tst_omegalyze json output last calculated omega dihedral angle not matching previous value, now: "+str(omjson_dict['flat_results'][8]['omega']) assert omjson_dict['flat_results'][8]['omega_type']=='Cis', "tst_omegalyze json output last omega_type not matching previous value, now: "+str(omjson_dict['flat_results'][8]['omega_type']) @@ -80,11 +91,14 @@ def exercise_omegalyze_json(): assert test_utils.count_dict_values(omjson_dict['hierarchical_results'], "Cis")==5, "tst_omegalyze json hierarchical output total number of omega Cis outliers changed to: "+str(test_utils.count_dict_values(omjson_dict['hierarchical_results'], "Cis")) assert test_utils.count_dict_values(omjson_dict['hierarchical_results'], "Twisted")==4, "tst_omegalyze json hierarchical output total number of omega Twisted outliers changed to: "+str(test_utils.count_dict_values(omjson_dict['hierarchical_results'], "Twisted")) assert omjson_dict['summary_results'][""]['num_cis_proline']==3, "tst_omegalyze json summary results num cis prolines changed to: " + str(omjson_dict['summary_results'][""]['num_cis_proline']) + return omjson_dict def run(): t0 = time.time() exercise_omegalyze() - exercise_omegalyze_json() + om_dict = exercise_omegalyze_json() + om_dict_cif = exercise_omegalyze_json(test_mmcif=True) + assert om_dict['summary_results'] == om_dict_cif['summary_results'], "tst_omegalyze summary results changed between pdb and cif version" print("OK. Time: %8.3f"%(time.time()-t0)) if (__name__ == "__main__"): diff --git a/mmtbx/validation/regression/tst_ramalyze.py b/mmtbx/validation/regression/tst_ramalyze.py index 3fbcfd51d7..aa97bf0c89 100644 --- a/mmtbx/validation/regression/tst_ramalyze.py +++ b/mmtbx/validation/regression/tst_ramalyze.py @@ -8,6 +8,8 @@ from mmtbx.validation import ramalyze from mmtbx.rotamer.rotamer_eval import find_rotarama_data_dir from iotbx.data_manager import DataManager +from libtbx.test_utils import convert_string_to_cif_long + import time import json @@ -231,7 +233,7 @@ def exercise_constants(): assert ramalyze.RAMALYZE_ANY == 3 assert ramalyze.RAMALYZE_NOT_FAVORED == 4 -def exercise_ramalyze_json(): +def exercise_ramalyze_json(test_mmcif=False): regression_pdb = libtbx.env.find_in_repositories( relative_path="phenix_regression/pdb/jcm.pdb", test=os.path.isfile) @@ -242,10 +244,17 @@ def exercise_ramalyze_json(): print("Skipping exercise_ramalyze(): rotarama_data directory not available") return dm = DataManager() - m = dm.get_model(regression_pdb) + if test_mmcif: + with open(regression_pdb) as f: + pdb_jcm_str = f.read() + pdb_jcm_str = convert_string_to_cif_long(pdb_jcm_str, chain_addition="LONGCHAIN") + dm.process_model_str("1", pdb_jcm_str) + m = dm.get_model("1") + else: + m = dm.get_model(regression_pdb) ramalyze_json = ramalyze.ramalyze(pdb_hierarchy=m.get_hierarchy(), outliers_only=True).as_JSON() rmjson_dict = json.loads(ramalyze_json) - import pprint + #import pprint #pprint.pprint(rmjson_dict) assert len(rmjson_dict['flat_results'])==100, "tst_ramalyze json output not returning correct number of values" assert approx_equal(rmjson_dict['flat_results'][0]['phi'], 50.51521639791719), "tst_ramalyze json output first calculated phi dihedral angle not matching previous value" @@ -260,12 +269,15 @@ def exercise_ramalyze_json(): assert rmjson_dict['summary_results'][""]['num_favored'] == 463, "tst_ramalyze json output summary total num_favored not matching previous value" assert rmjson_dict['summary_results'][""]['num_outliers'] == 100, "tst_ramalyze json output summary total num_outliers not matching previous value" assert rmjson_dict['summary_results'][""]['num_residues'] == 725, "tst_ramalyze json output summary total num_residues not matching previous value" + return rmjson_dict if (__name__ == "__main__"): t0=time.time() exercise_ramalyze() exercise_favored_regions() exercise_constants() - exercise_ramalyze_json() + rm_dict = exercise_ramalyze_json() + rm_dict_cif = exercise_ramalyze_json(test_mmcif=True) + assert rm_dict['summary_results'] == rm_dict_cif['summary_results'], "tst_ramalyze summary results changed between pdb and cif version" print("Time: %6.4f"%(time.time()-t0)) print("OK") diff --git a/mmtbx/validation/regression/tst_rna_validate.py b/mmtbx/validation/regression/tst_rna_validate.py index a2b2da71a5..cec5c8158f 100644 --- a/mmtbx/validation/regression/tst_rna_validate.py +++ b/mmtbx/validation/regression/tst_rna_validate.py @@ -8,6 +8,7 @@ import libtbx.load_env from six.moves import cStringIO as StringIO from iotbx.data_manager import DataManager +from libtbx.test_utils import convert_string_to_cif_long import sys, os import json import time @@ -16,7 +17,7 @@ # This actually tests expected output - the remaining tests guard against # fixed bugs. -def exercise_1(): +def exercise_1(test_mmcif=False): # derived from 2goz regression_pdb = libtbx.env.find_in_repositories( relative_path="phenix_regression/pdb/pdb2goz_refmac_tls.ent", @@ -25,7 +26,14 @@ def exercise_1(): print("Skipping exercise: input pdb (pdb2goz_refmac_tls.ent) not available") return dm = DataManager() - m = dm.get_model(regression_pdb) + if test_mmcif: + with open(regression_pdb) as f: + pdb_2goz_str = f.read() + pdb_2goz_str = convert_string_to_cif_long(pdb_2goz_str, chain_addition="LONGCHAIN", hetatm_name_addition = "") + dm.process_model_str("1", pdb_2goz_str) + m = dm.get_model("1") + else: + m = dm.get_model(regression_pdb) rv = rna_validation(m.get_hierarchy()) assert len(rv.puckers.results) == 2, len(rv.puckers.results) assert len(rv.bonds.results) == 4, len(rv.bonds.results) @@ -43,7 +51,8 @@ def exercise_1(): angles_json = json.loads(rv.angles.as_JSON()) puckers_json = json.loads(rv.puckers.as_JSON()) suites_json = json.loads(rv.suites.as_JSON()) - #print(bonds_json) + #import pprint + #pprint.pprint(puckers_json) assert len(bonds_json["flat_results"]) == 4, "tst_rna_validate json output not returning correct number of bond outliers, changed to: "+str(len(bonds_json["flat_results"])) assert approx_equal(bonds_json['flat_results'][0]["score"], 4.40664), "tst_rna_validate json output first bond outlier score changed to: "+str(bonds_json['flat_results'][0]["score"]) assert approx_equal(bonds_json['flat_results'][0]["xyz"][0], -17.61949), "tst_rna_validate json output first bond x changed to: "+str(bonds_json['flat_results'][0]["xyz"][0]) @@ -56,16 +65,31 @@ def exercise_1(): assert approx_equal(angles_json['flat_results'][0]["xyz"][0], -16.161), "tst_rna_validate json output first angle x score changed to: " + str(angles_json['flat_results'][0]["xyz"][0]) assert approx_equal(angles_json['flat_results'][0]["xyz"][1], -6.863), "tst_rna_validate json output first angle y score changed to: " + str(angles_json['flat_results'][0]["xyz"][1]) assert approx_equal(angles_json['flat_results'][0]["xyz"][2], -20.773), "tst_rna_validate json output first angle z score changed to: " + str(angles_json['flat_results'][0]["xyz"][2]) - assert test_utils.count_dict_values(angles_json['hierarchical_results'], ["A", "A", "A"])==11, "tst_rna_validate json hierarchical output number of angle outliers in chain A changed to: "+str(test_utils.count_dict_values(angles_json['hierarchical_results'], ["A", "A", "A"])) + assert test_utils.count_dict_values(angles_json['hierarchical_results'], [1.0, 1.0, 1.0])==14, "tst_rna_validate json hierarchical output number of angle outliers changed to: "+str(test_utils.count_dict_values(angles_json['hierarchical_results'], [1.0, 1.0, 1.0])) assert angles_json['summary_results']['']["num_outliers_too_large"]==6, "tst_rna_validate json output summary result number of angle outliers too large changed to: "+str(angles_json['summary_results']['']["num_outliers_too_large"]) assert len(puckers_json["flat_results"]) == 2, "tst_rna_validate json output not returning correct number of pucker outliers, changed to: " + str(len(puckers_json["flat_results"])) assert approx_equal(puckers_json['flat_results'][0]["delta_angle"], 106.454213), "tst_rna_validate json output first pucker outlier delta changed to: " + str(puckers_json['flat_results'][0]["delta_angle"]) - assert test_utils.count_dict_values(puckers_json['hierarchical_results'], "A")==2, "tst_rna_validate json hierarchical output number of pucker outliers changed to: "+str(test_utils.count_dict_values(puckers_json['hierarchical_results'], "A", "A", "A")) + assert test_utils.count_dict_values(puckers_json['hierarchical_results'], " ")==2, "tst_rna_validate json hierarchical output number of pucker outliers changed to: "+str(test_utils.count_dict_values(puckers_json['hierarchical_results'], " ")) assert puckers_json['summary_results']['']["num_outliers"]==2, "tst_rna_validate json output summary result number of pucker outliers changed to: "+str(puckers_json['summary_results']['']["num_outliers"]) assert len(suites_json["flat_results"]) == 5, "tst_rna_validate json output not returning correct number of suite outliers, changed to: " + str(len(suites_json["flat_results"])) assert suites_json['flat_results'][0]["suiteness"]==0, "tst_rna_validate json output first suite outlier suiteness changed to: " + str(suites_json['flat_results'][0]["suiteness"]) assert test_utils.count_dict_values(suites_json['hierarchical_results'], "!!")==5, "tst_rna_validate json hierarchical output number of suite outliers changed to: "+str(test_utils.count_dict_values(suites_json['hierarchical_results'], "!!")) #assert suites_json['summary_results']['']["num_outliers"]==2, "tst_rna_validate json output summary result number of pucker outliers changed to: "+str(puckers_json['summary_results']['']["num_outliers"]) + return rv + +def exercise_pdbvcif(rv, rv_cif): + bonds_json = json.loads(rv.bonds.as_JSON()) + angles_json = json.loads(rv.angles.as_JSON()) + puckers_json = json.loads(rv.puckers.as_JSON()) + suites_json = json.loads(rv.suites.as_JSON()) + bonds_json_cif = json.loads(rv_cif.bonds.as_JSON()) + angles_json_cif = json.loads(rv_cif.angles.as_JSON()) + puckers_json_cif = json.loads(rv_cif.puckers.as_JSON()) + suites_json_cif = json.loads(rv_cif.suites.as_JSON()) + assert bonds_json['summary_results'] == bonds_json_cif['summary_results'], "tst_rna_validate summary results changed between pdb and cif version" + assert angles_json['summary_results'] == angles_json_cif['summary_results'], "tst_rna_validate summary results changed between pdb and cif version" + assert puckers_json['summary_results'] == puckers_json_cif['summary_results'], "tst_rna_validate summary results changed between pdb and cif version" + assert suites_json['summary_results'] == suites_json_cif['summary_results'], "tst_rna_validate summary results changed between pdb and cif version" def exercise_2(): # fragment from 3g8t @@ -199,7 +223,9 @@ def pickle_unpickle(result): def run(): t0 = time.time() verbose = "--verbose" in sys.argv[1:] - exercise_1() + rv = exercise_1() + rv_cif = exercise_1(test_mmcif=True) + exercise_pdbvcif(rv, rv_cif) exercise_2() exercise_3() print("OK. Time: %8.3f"%(time.time()-t0)) diff --git a/mmtbx/validation/regression/tst_rotalyze.py b/mmtbx/validation/regression/tst_rotalyze.py index ddaac041f6..3f0991eb17 100644 --- a/mmtbx/validation/regression/tst_rotalyze.py +++ b/mmtbx/validation/regression/tst_rotalyze.py @@ -9,6 +9,7 @@ from libtbx.easy_pickle import loads, dumps from six.moves import cStringIO as StringIO from iotbx.data_manager import DataManager +from libtbx.test_utils import convert_string_to_cif_long import os.path import json from six.moves import zip @@ -290,7 +291,7 @@ def exercise_2(): results.append(cur_rot) assert results == ['Cg_exo', 'OUTLIER', 'OUTLIER'] -def exercise_rotalyze_json(): +def exercise_rotalyze_json(test_mmcif=False): regression_pdb = libtbx.env.find_in_repositories( relative_path="phenix_regression/pdb/jcm.pdb", test=os.path.isfile) @@ -301,10 +302,17 @@ def exercise_rotalyze_json(): print("Skipping exercise_rotalyze(): rotarama_data directory not available") return dm = DataManager() - m = dm.get_model(regression_pdb) + if test_mmcif: + with open(regression_pdb) as f: + pdb_jcm_str = f.read() + pdb_jcm_str = convert_string_to_cif_long(pdb_jcm_str, chain_addition="LONGCHAIN") + dm.process_model_str("1", pdb_jcm_str) + m = dm.get_model("1") + else: + m = dm.get_model(regression_pdb) rotalyze_json = rotalyze.rotalyze(pdb_hierarchy=m.get_hierarchy(), outliers_only=True).as_JSON() rtjson_dict = json.loads(rotalyze_json) - import pprint + #import pprint #pprint.pprint(rtjson_dict) assert len(rtjson_dict['flat_results'])==123, "tst_rotalyze json output not returning correct number of values" assert approx_equal(rtjson_dict['flat_results'][0]['chi_angles'][0], 229.02299329063914), "tst_rotalyze json output first calculated chi dihedral angle not matching previous value" @@ -318,9 +326,13 @@ def exercise_rotalyze_json(): assert rtjson_dict['summary_results'][""]['num_favored'] == 404, "tst_rotalyze json output summary total num_favored not matching previous value" assert rtjson_dict['summary_results'][""]['num_outliers'] == 123, "tst_rotalyze json output summary total num_outliers not matching previous value" assert rtjson_dict['summary_results'][""]['num_residues'] == 643, "tst_rotalyze json output summary total num_residues not matching previous value" + return rtjson_dict if (__name__ == "__main__"): exercise_rotalyze() exercise_2() - exercise_rotalyze_json() + rt_dict = exercise_rotalyze_json() + rt_dict_cif = exercise_rotalyze_json(test_mmcif=True) + assert rt_dict['summary_results'] == rt_dict_cif['summary_results'], "tst_rotalyze summary results changed between pdb and cif version" + print("OK") diff --git a/mmtbx/validation/regression/tst_suitename.py b/mmtbx/validation/regression/tst_suitename.py index 9508a48a4d..d7603bb592 100644 --- a/mmtbx/validation/regression/tst_suitename.py +++ b/mmtbx/validation/regression/tst_suitename.py @@ -1,12 +1,14 @@ from __future__ import absolute_import, division, print_function from mmtbx.suitename import suitealyze from iotbx.data_manager import DataManager +from libtbx.test_utils import convert_string_to_cif_long, convert_pdb_to_cif_for_pdb_str + import libtbx.load_env import time import json import os -def exercise_suitename_json(): +def exercise_suitename_json(test_mmcif=False): # derived from 2goz # note: chain B, residue 20 of 2goz is a DNA residue (DC). As of 2023, DNA conformations are not handled by suitename, # and this residue is skipped. @@ -17,11 +19,22 @@ def exercise_suitename_json(): print("Skipping exercise: input pdb (pdb2goz_refmac_tls.ent) not available") return dm = DataManager() - m = dm.get_model(regression_pdb) + if test_mmcif: + with open(regression_pdb) as f: + pdb_2goz_str = f.read() + pdb_2goz_str = convert_string_to_cif_long(pdb_2goz_str, hetatm_name_addition = "", chain_addition="LONGCHAIN") + dm.process_model_str("1", pdb_2goz_str) + m = dm.get_model("1") + chainA = "ALONGCHAIN" + chainB = "BLONGCHAIN" + else: + m = dm.get_model(regression_pdb) + chainA = "A" + chainB = "B" sz = suitealyze.suitealyze(pdb_hierarchy=m.get_hierarchy()) sz_dict = json.loads(sz.as_JSON()) #import pprint - #pprint.pprint(csjson_dict) + #pprint.pprint(sz_dict) assert len(sz_dict['flat_results']) == 62, "tst_suitename json output not returning correct number of suites, now: "+str(len(sz_dict['flat_results'])) assert sz_dict['flat_results'][0]["cluster"] == "__", "tst_suitename json output first cluster value changed, now: "+sz_dict['flat_results'][0]["cluster"] from mmtbx.validation import test_utils @@ -32,8 +45,8 @@ def exercise_suitename_json(): assert test_utils.count_dict_values(sz_dict['hierarchical_results'], "__")==2, "tst_suitename json hierarchical output total number of __ changed, now: "+str(test_utils.count_dict_values(sz_dict['hierarchical_results'], "__")) assert sz_dict['summary_results'][""]["num_outliers"] == 5, "tst_suitename json summary output total number of outliers changed" assert sz_dict['summary_results'][""]["num_suites"] == 62, "tst_suitename json summary output total number of suites changed" - assert sz_dict['suitestrings'][""]["A"] == "__G1aG1aA1aU1aG1aU1aA7rC0aU1aA1aC1aC1aA1cG1bC4aU1gG1aA1[U6gG9aA1aG1aU1aC1aC1aC1aA!!A!!A2aU1bA!!G1aG1aA1aC1aG&aA1aA1aA1aC1aG1aC1cC", "model 1 chain A suitestring changed" - assert sz_dict['suitestrings'][""]["B"] == "__G1aG1aC1aG1aU1bC!!C1aU1aG1cG1a?1aA1bU4aC1bC!!A1aA1a?1aC", "model 1 chain B suitestring changed" + assert sz_dict['suitestrings'][""][chainA] == "__G1aG1aA1aU1aG1aU1aA7rC0aU1aA1aC1aC1aA1cG1bC4aU1gG1aA1[U6gG9aA1aG1aU1aC1aC1aC1aA!!A!!A2aU1bA!!G1aG1aA1aC1aG&aA1aA1aA1aC1aG1aC1cC", "model 1 chain A suitestring changed" + assert sz_dict['suitestrings'][""][chainB] == "__G1aG1aC1aG1aU1bC!!C1aU1aG1cG1a?1aA1bU4aC1bC!!A1aA1a?1aC", "model 1 chain B suitestring changed" multimod_2goz_pdb_str = """MODEL 1 ATOM 539 P C A 26 -19.024 25.068 -5.945 1.00 46.81 P @@ -254,13 +267,19 @@ def exercise_suitename_json(): END """ -def exercise_multimodel_suitename_json(): +def exercise_multimodel_suitename_json(test_mmcif=False): # derived from 2goz dm = DataManager() dm.process_model_str("1",multimod_2goz_pdb_str) m = dm.get_model("1") sz = suitealyze.suitealyze(pdb_hierarchy=m.get_hierarchy()) sz_dict = json.loads(sz.as_JSON()) + if test_mmcif: + model_1 = "1" + model_2 = "2" + else: + model_1 = " 1" + model_2 = " 2" #import pprint #pprint.pprint(sz_dict) assert len(sz_dict['flat_results']) == 10, "tst_suitename json output not returning correct number of suites, now: "+str(len(sz_dict['flat_results'])) @@ -270,13 +289,20 @@ def exercise_multimodel_suitename_json(): assert test_utils.count_dict_values(sz_dict['hierarchical_results'], "2a")==2, "tst_suitename json hierarchical output total number of 1b changed, now: "+str(test_utils.count_dict_values(sz_dict['hierarchical_results'], "2a")) assert test_utils.count_dict_values(sz_dict['hierarchical_results'], "!!")==4, "tst_suitename json hierarchical output total number of !! changed, now: "+str(test_utils.count_dict_values(sz_dict['hierarchical_results'], "!!")) assert test_utils.count_dict_values(sz_dict['hierarchical_results'], "__")==2, "tst_suitename json hierarchical output total number of __ changed, now: "+str(test_utils.count_dict_values(sz_dict['hierarchical_results'], "__")) - assert sz_dict['summary_results'][" 1"]["num_outliers"] == 2, "tst_suitename json summary output total number of outliers changed" - assert sz_dict['summary_results'][" 1"]["num_suites"] == 5, "tst_suitename json summary output total number of suites changed" - assert sz_dict['summary_results'][" 2"]["num_outliers"] == 2, "tst_suitename json summary output total number of outliers changed" - assert sz_dict['summary_results'][" 2"]["num_suites"] == 5, "tst_suitename json summary output total number of suites changed" + assert sz_dict['summary_results'][model_1]["num_outliers"] == 2, "tst_suitename json summary output total number of outliers changed" + assert sz_dict['summary_results'][model_1]["num_suites"] == 5, "tst_suitename json summary output total number of suites changed" + assert sz_dict['summary_results'][model_2]["num_outliers"] == 2, "tst_suitename json summary output total number of outliers changed" + assert sz_dict['summary_results'][model_2]["num_suites"] == 5, "tst_suitename json summary output total number of suites changed" + return sz_dict if (__name__ == "__main__"): t0 = time.time() exercise_suitename_json() - exercise_multimodel_suitename_json() + suite_json = exercise_multimodel_suitename_json() + exercise_suitename_json(test_mmcif=True) + convert_pdb_to_cif_for_pdb_str(locals(), chain_addition="LONGCHAIN", hetatm_name_addition = "", key_str="multimod_", print_new_string = False) + suite_json_cif = exercise_multimodel_suitename_json(test_mmcif=True) + assert suite_json['summary_results'][' 1'] == suite_json_cif['summary_results']['1'], "tst_suitename summary results changed between pdb and cif version" + assert suite_json['summary_results'][' 2'] == suite_json_cif['summary_results']['2'], "tst_suitename summary results changed between pdb and cif version" + print("OK. Time: %8.3f"%(time.time()-t0)) diff --git a/mmtbx/validation/regression/tst_undowser.py b/mmtbx/validation/regression/tst_undowser.py index c46e3f86f8..8da777870c 100644 --- a/mmtbx/validation/regression/tst_undowser.py +++ b/mmtbx/validation/regression/tst_undowser.py @@ -2,6 +2,7 @@ from mmtbx.validation import undowser from libtbx.easy_pickle import loads from iotbx.data_manager import DataManager +from libtbx.test_utils import convert_pdb_to_cif_for_pdb_str import libtbx.load_env import time import json @@ -251,8 +252,8 @@ def exercise_undowser_json(): m = dm.get_model("1") uz = undowser.undowserlyze(pdb_hierarchy=m.get_hierarchy()) uz_dict = json.loads(uz.as_JSON()) - #import pprint - #pprint.pprint(csjson_dict) + import pprint + pprint.pprint(uz_dict) assert len(uz_dict['flat_results']) == 11, "tst_undowser json output not returning correct number of water clashes, now: "+str(len(uz_dict['flat_results'])) assert uz_dict['flat_results'][0]["src_atom_id"] == " A 503 HOH O ", "tst_undowser json output first src_atom_id value changed, now: "+uz_dict['flat_results'][0]["src_atom_id"] from mmtbx.validation import test_utils @@ -270,4 +271,9 @@ def exercise_undowser_json(): t0 = time.time() exercise_undowser() exercise_undowser_json() + print("Undowser using PDB OK.") + convert_pdb_to_cif_for_pdb_str(locals(), chain_addition="LONGCHAIN", hetatm_name_addition = "", key_str="pdb_", print_new_string = False) + #this won't work until undowser is swapped to use probe2 + #exercise_undowser_json() + #print("Undowser using mmCIF OK.") print("OK. Time: %8.3f"%(time.time()-t0)) From 0abde9694564e81c6271d8847155daea86605539 Mon Sep 17 00:00:00 2001 From: Vincent Chen Date: Thu, 23 May 2024 15:55:29 -0400 Subject: [PATCH 490/748] cleanup test changes --- mmtbx/validation/regression/tst_cablam.py | 170 ++++++++++---------- mmtbx/validation/regression/tst_undowser.py | 4 +- 2 files changed, 87 insertions(+), 87 deletions(-) diff --git a/mmtbx/validation/regression/tst_cablam.py b/mmtbx/validation/regression/tst_cablam.py index 759b4c0ffd..70ced78113 100644 --- a/mmtbx/validation/regression/tst_cablam.py +++ b/mmtbx/validation/regression/tst_cablam.py @@ -213,93 +213,93 @@ def exercise_cablam(): assert not show_diff(output_holder.output , ref_cablam_text) cablam_json_multimodel_pdb = """MODEL 1 -ATOM 120 N LEU A 15 47.483 17.606 20.296 1.00 24.69 N -ATOM 121 CA LEU A 15 47.208 17.724 21.716 1.00 28.08 C -ATOM 122 C LEU A 15 46.866 19.132 22.189 1.00 47.52 C -ATOM 123 O LEU A 15 46.551 19.411 23.375 1.00 42.41 O -ATOM 124 CB LEU A 15 48.364 17.085 22.505 1.00 31.96 C -ATOM 125 CG LEU A 15 48.460 15.567 22.290 1.00 33.79 C -ATOM 126 CD1 LEU A 15 49.627 14.978 23.088 1.00 56.11 C -ATOM 127 CD2 LEU A 15 47.145 14.911 22.717 1.00 70.78 C -ATOM 128 N LYS A 16 46.925 20.028 21.225 1.00 27.45 N -ATOM 129 CA LYS A 16 46.714 21.414 21.506 1.00 50.37 C -ATOM 130 C LYS A 16 45.623 21.941 20.637 1.00 31.00 C -ATOM 131 O LYS A 16 45.582 21.634 19.451 1.00 60.11 O -ATOM 132 CB LYS A 16 48.019 22.163 21.214 1.00 55.51 C -ATOM 133 CG LYS A 16 48.021 23.610 21.660 1.00 83.77 C -ATOM 134 CD LYS A 16 48.087 23.790 23.175 1.00100.00 C -ATOM 135 CE LYS A 16 46.895 24.555 23.771 1.00100.00 C -ATOM 136 NZ LYS A 16 46.850 26.013 23.485 1.00100.00 N -ATOM 137 N ILE A 17 44.688 22.708 21.196 1.00 56.16 N -ATOM 138 CA ILE A 17 43.629 23.210 20.321 1.00 19.13 C -ATOM 139 C ILE A 17 44.193 23.624 18.967 1.00 40.60 C -ATOM 140 O ILE A 17 45.370 23.978 18.830 1.00 68.25 O -ATOM 141 CB ILE A 17 42.830 24.404 20.896 1.00 47.36 C -ATOM 142 CG1 ILE A 17 42.267 24.102 22.265 1.00 43.38 C -ATOM 143 CG2 ILE A 17 41.684 24.855 19.952 1.00 16.95 C -ATOM 144 CD1 ILE A 17 40.965 24.845 22.441 1.00 27.07 C -ATOM 145 N TYR A 18 43.324 23.628 17.965 1.00 20.84 N -ATOM 146 CA TYR A 18 43.767 24.010 16.657 1.00 17.35 C -ATOM 147 C TYR A 18 42.604 24.316 15.754 1.00 20.49 C -ATOM 148 O TYR A 18 41.441 24.001 16.010 1.00 36.50 O -ATOM 149 CB TYR A 18 44.788 23.023 16.018 1.00 42.02 C -ATOM 150 CG TYR A 18 44.181 21.700 15.576 1.00 53.94 C -ATOM 151 CD1 TYR A 18 44.040 20.596 16.425 1.00 30.37 C -ATOM 152 CD2 TYR A 18 43.736 21.576 14.262 1.00 27.24 C -ATOM 153 CE1 TYR A 18 43.447 19.409 15.988 1.00 71.37 C -ATOM 154 CE2 TYR A 18 43.188 20.385 13.783 1.00 25.76 C -ATOM 155 CZ TYR A 18 43.014 19.319 14.661 1.00 38.01 C -ATOM 156 OH TYR A 18 42.461 18.164 14.150 1.00 42.56 O -ATOM 157 N LYS A 19 42.908 24.929 14.651 1.00 27.49 N -ATOM 158 CA LYS A 19 41.887 25.242 13.695 1.00 22.06 C -ATOM 159 C LYS A 19 41.905 24.288 12.552 1.00 73.84 C -ATOM 160 O LYS A 19 42.947 23.965 11.971 1.00 50.03 O -ATOM 161 CB LYS A 19 41.983 26.625 13.131 1.00 32.98 C -ATOM 162 CG LYS A 19 41.434 27.679 14.049 1.00 94.12 C -ATOM 163 CD LYS A 19 41.484 29.058 13.414 1.00100.00 C -ATOM 164 CE LYS A 19 42.332 30.073 14.190 1.00 71.32 C -ATOM 165 NZ LYS A 19 42.244 31.445 13.655 1.00100.00 N +ATOM 120 N LEU A 15 47.483 17.606 20.296 1.00 24.69 N +ATOM 121 CA LEU A 15 47.208 17.724 21.716 1.00 28.08 C +ATOM 122 C LEU A 15 46.866 19.132 22.189 1.00 47.52 C +ATOM 123 O LEU A 15 46.551 19.411 23.375 1.00 42.41 O +ATOM 124 CB LEU A 15 48.364 17.085 22.505 1.00 31.96 C +ATOM 125 CG LEU A 15 48.460 15.567 22.290 1.00 33.79 C +ATOM 126 CD1 LEU A 15 49.627 14.978 23.088 1.00 56.11 C +ATOM 127 CD2 LEU A 15 47.145 14.911 22.717 1.00 70.78 C +ATOM 128 N LYS A 16 46.925 20.028 21.225 1.00 27.45 N +ATOM 129 CA LYS A 16 46.714 21.414 21.506 1.00 50.37 C +ATOM 130 C LYS A 16 45.623 21.941 20.637 1.00 31.00 C +ATOM 131 O LYS A 16 45.582 21.634 19.451 1.00 60.11 O +ATOM 132 CB LYS A 16 48.019 22.163 21.214 1.00 55.51 C +ATOM 133 CG LYS A 16 48.021 23.610 21.660 1.00 83.77 C +ATOM 134 CD LYS A 16 48.087 23.790 23.175 1.00100.00 C +ATOM 135 CE LYS A 16 46.895 24.555 23.771 1.00100.00 C +ATOM 136 NZ LYS A 16 46.850 26.013 23.485 1.00100.00 N +ATOM 137 N ILE A 17 44.688 22.708 21.196 1.00 56.16 N +ATOM 138 CA ILE A 17 43.629 23.210 20.321 1.00 19.13 C +ATOM 139 C ILE A 17 44.193 23.624 18.967 1.00 40.60 C +ATOM 140 O ILE A 17 45.370 23.978 18.830 1.00 68.25 O +ATOM 141 CB ILE A 17 42.830 24.404 20.896 1.00 47.36 C +ATOM 142 CG1 ILE A 17 42.267 24.102 22.265 1.00 43.38 C +ATOM 143 CG2 ILE A 17 41.684 24.855 19.952 1.00 16.95 C +ATOM 144 CD1 ILE A 17 40.965 24.845 22.441 1.00 27.07 C +ATOM 145 N TYR A 18 43.324 23.628 17.965 1.00 20.84 N +ATOM 146 CA TYR A 18 43.767 24.010 16.657 1.00 17.35 C +ATOM 147 C TYR A 18 42.604 24.316 15.754 1.00 20.49 C +ATOM 148 O TYR A 18 41.441 24.001 16.010 1.00 36.50 O +ATOM 149 CB TYR A 18 44.788 23.023 16.018 1.00 42.02 C +ATOM 150 CG TYR A 18 44.181 21.700 15.576 1.00 53.94 C +ATOM 151 CD1 TYR A 18 44.040 20.596 16.425 1.00 30.37 C +ATOM 152 CD2 TYR A 18 43.736 21.576 14.262 1.00 27.24 C +ATOM 153 CE1 TYR A 18 43.447 19.409 15.988 1.00 71.37 C +ATOM 154 CE2 TYR A 18 43.188 20.385 13.783 1.00 25.76 C +ATOM 155 CZ TYR A 18 43.014 19.319 14.661 1.00 38.01 C +ATOM 156 OH TYR A 18 42.461 18.164 14.150 1.00 42.56 O +ATOM 157 N LYS A 19 42.908 24.929 14.651 1.00 27.49 N +ATOM 158 CA LYS A 19 41.887 25.242 13.695 1.00 22.06 C +ATOM 159 C LYS A 19 41.905 24.288 12.552 1.00 73.84 C +ATOM 160 O LYS A 19 42.947 23.965 11.971 1.00 50.03 O +ATOM 161 CB LYS A 19 41.983 26.625 13.131 1.00 32.98 C +ATOM 162 CG LYS A 19 41.434 27.679 14.049 1.00 94.12 C +ATOM 163 CD LYS A 19 41.484 29.058 13.414 1.00100.00 C +ATOM 164 CE LYS A 19 42.332 30.073 14.190 1.00 71.32 C +ATOM 165 NZ LYS A 19 42.244 31.445 13.655 1.00100.00 N ENDMDL MODEL 2 -ATOM 1014 N LEU A 133 30.536 10.928 -6.190 1.00 16.93 N -ATOM 1015 CA LEU A 133 31.011 11.480 -4.927 1.00 19.63 C -ATOM 1016 C LEU A 133 31.992 12.625 -5.134 1.00 26.72 C -ATOM 1017 O LEU A 133 32.125 13.484 -4.270 1.00 23.28 O -ATOM 1018 CB LEU A 133 31.707 10.402 -4.052 1.00 14.35 C -ATOM 1019 CG LEU A 133 30.760 9.425 -3.342 1.00 31.49 C -ATOM 1020 CD1 LEU A 133 31.551 8.266 -2.745 1.00 37.78 C -ATOM 1021 CD2 LEU A 133 30.076 10.146 -2.198 1.00 14.00 C -ATOM 1022 N ALA A 134 32.750 12.572 -6.245 1.00 21.52 N -ATOM 1023 CA ALA A 134 33.801 13.544 -6.549 1.00 21.07 C -ATOM 1024 C ALA A 134 33.292 14.934 -6.866 1.00 21.47 C -ATOM 1025 O ALA A 134 34.032 15.932 -6.804 1.00 19.33 O -ATOM 1026 CB ALA A 134 34.720 13.025 -7.662 1.00 17.54 C -ATOM 1027 N LYS A 135 32.011 14.996 -7.224 1.00 21.06 N -ATOM 1028 CA LYS A 135 31.347 16.250 -7.554 1.00 25.54 C -ATOM 1029 C LYS A 135 30.774 16.866 -6.309 1.00 19.56 C -ATOM 1030 O LYS A 135 29.550 16.919 -6.156 1.00 24.91 O -ATOM 1031 CB LYS A 135 30.214 16.106 -8.570 1.00 12.97 C -ATOM 1032 CG LYS A 135 30.558 15.217 -9.733 1.00 22.54 C -ATOM 1033 CD LYS A 135 29.544 15.351 -10.840 1.00 46.13 C -ATOM 1034 CE LYS A 135 30.178 15.191 -12.206 1.00 71.90 C -ATOM 1035 NZ LYS A 135 29.730 13.985 -12.903 1.00 97.93 N -ATOM 1036 N SER A 136 31.642 17.287 -5.410 1.00 13.65 N -ATOM 1037 CA SER A 136 31.181 17.859 -4.158 1.00 14.56 C -ATOM 1038 C SER A 136 32.180 18.868 -3.601 1.00 27.10 C -ATOM 1039 O SER A 136 33.388 18.832 -3.911 1.00 22.82 O -ATOM 1040 CB SER A 136 31.008 16.717 -3.136 1.00 17.51 C -ATOM 1041 OG SER A 136 32.237 15.971 -3.070 1.00 15.66 O -ATOM 1042 N ARG A 137 31.700 19.738 -2.728 1.00 19.66 N -ATOM 1043 CA ARG A 137 32.576 20.679 -2.052 1.00 18.34 C -ATOM 1044 C ARG A 137 33.630 19.903 -1.265 1.00 15.29 C -ATOM 1045 O ARG A 137 34.808 20.230 -1.267 1.00 20.30 O -ATOM 1046 CB ARG A 137 31.754 21.450 -1.038 1.00 22.08 C -ATOM 1047 CG ARG A 137 32.616 22.258 -0.087 1.00 29.17 C -ATOM 1048 CD ARG A 137 31.813 23.256 0.761 1.00 24.81 C -ATOM 1049 NE ARG A 137 32.564 24.474 1.087 1.00100.00 N -ATOM 1050 CZ ARG A 137 33.415 24.547 2.121 1.00100.00 C -ATOM 1051 NH1 ARG A 137 33.629 23.496 2.928 1.00100.00 N -ATOM 1052 NH2 ARG A 137 34.073 25.698 2.345 1.00100.00 N +ATOM 1014 N LEU A 133 30.536 10.928 -6.190 1.00 16.93 N +ATOM 1015 CA LEU A 133 31.011 11.480 -4.927 1.00 19.63 C +ATOM 1016 C LEU A 133 31.992 12.625 -5.134 1.00 26.72 C +ATOM 1017 O LEU A 133 32.125 13.484 -4.270 1.00 23.28 O +ATOM 1018 CB LEU A 133 31.707 10.402 -4.052 1.00 14.35 C +ATOM 1019 CG LEU A 133 30.760 9.425 -3.342 1.00 31.49 C +ATOM 1020 CD1 LEU A 133 31.551 8.266 -2.745 1.00 37.78 C +ATOM 1021 CD2 LEU A 133 30.076 10.146 -2.198 1.00 14.00 C +ATOM 1022 N ALA A 134 32.750 12.572 -6.245 1.00 21.52 N +ATOM 1023 CA ALA A 134 33.801 13.544 -6.549 1.00 21.07 C +ATOM 1024 C ALA A 134 33.292 14.934 -6.866 1.00 21.47 C +ATOM 1025 O ALA A 134 34.032 15.932 -6.804 1.00 19.33 O +ATOM 1026 CB ALA A 134 34.720 13.025 -7.662 1.00 17.54 C +ATOM 1027 N LYS A 135 32.011 14.996 -7.224 1.00 21.06 N +ATOM 1028 CA LYS A 135 31.347 16.250 -7.554 1.00 25.54 C +ATOM 1029 C LYS A 135 30.774 16.866 -6.309 1.00 19.56 C +ATOM 1030 O LYS A 135 29.550 16.919 -6.156 1.00 24.91 O +ATOM 1031 CB LYS A 135 30.214 16.106 -8.570 1.00 12.97 C +ATOM 1032 CG LYS A 135 30.558 15.217 -9.733 1.00 22.54 C +ATOM 1033 CD LYS A 135 29.544 15.351 -10.840 1.00 46.13 C +ATOM 1034 CE LYS A 135 30.178 15.191 -12.206 1.00 71.90 C +ATOM 1035 NZ LYS A 135 29.730 13.985 -12.903 1.00 97.93 N +ATOM 1036 N SER A 136 31.642 17.287 -5.410 1.00 13.65 N +ATOM 1037 CA SER A 136 31.181 17.859 -4.158 1.00 14.56 C +ATOM 1038 C SER A 136 32.180 18.868 -3.601 1.00 27.10 C +ATOM 1039 O SER A 136 33.388 18.832 -3.911 1.00 22.82 O +ATOM 1040 CB SER A 136 31.008 16.717 -3.136 1.00 17.51 C +ATOM 1041 OG SER A 136 32.237 15.971 -3.070 1.00 15.66 O +ATOM 1042 N ARG A 137 31.700 19.738 -2.728 1.00 19.66 N +ATOM 1043 CA ARG A 137 32.576 20.679 -2.052 1.00 18.34 C +ATOM 1044 C ARG A 137 33.630 19.903 -1.265 1.00 15.29 C +ATOM 1045 O ARG A 137 34.808 20.230 -1.267 1.00 20.30 O +ATOM 1046 CB ARG A 137 31.754 21.450 -1.038 1.00 22.08 C +ATOM 1047 CG ARG A 137 32.616 22.258 -0.087 1.00 29.17 C +ATOM 1048 CD ARG A 137 31.813 23.256 0.761 1.00 24.81 C +ATOM 1049 NE ARG A 137 32.564 24.474 1.087 1.00100.00 N +ATOM 1050 CZ ARG A 137 33.415 24.547 2.121 1.00100.00 C +ATOM 1051 NH1 ARG A 137 33.629 23.496 2.928 1.00100.00 N +ATOM 1052 NH2 ARG A 137 34.073 25.698 2.345 1.00100.00 N ENDMDL END """ diff --git a/mmtbx/validation/regression/tst_undowser.py b/mmtbx/validation/regression/tst_undowser.py index 8da777870c..ac8f0a4bc7 100644 --- a/mmtbx/validation/regression/tst_undowser.py +++ b/mmtbx/validation/regression/tst_undowser.py @@ -252,8 +252,8 @@ def exercise_undowser_json(): m = dm.get_model("1") uz = undowser.undowserlyze(pdb_hierarchy=m.get_hierarchy()) uz_dict = json.loads(uz.as_JSON()) - import pprint - pprint.pprint(uz_dict) + #import pprint + #pprint.pprint(uz_dict) assert len(uz_dict['flat_results']) == 11, "tst_undowser json output not returning correct number of water clashes, now: "+str(len(uz_dict['flat_results'])) assert uz_dict['flat_results'][0]["src_atom_id"] == " A 503 HOH O ", "tst_undowser json output first src_atom_id value changed, now: "+uz_dict['flat_results'][0]["src_atom_id"] from mmtbx.validation import test_utils From b3404476ee642902c51e4fc9aaed66b7e3d5b207 Mon Sep 17 00:00:00 2001 From: terwill Date: Fri, 24 May 2024 12:38:10 -0700 Subject: [PATCH 491/748] Allow running tests with specific words --- libtbx/command_line/run_tests_parallel.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/libtbx/command_line/run_tests_parallel.py b/libtbx/command_line/run_tests_parallel.py index 27b5f4ef44..b9ce8a910b 100755 --- a/libtbx/command_line/run_tests_parallel.py +++ b/libtbx/command_line/run_tests_parallel.py @@ -45,6 +45,7 @@ def run(args, max_tests=None, start_test=None, tests_to_skip=None, + tests_to_run=None, expected_failures_from_phenix_regression=[], unstables_from_phenix_regression = [], supplied_list_of_tests = None): @@ -127,6 +128,21 @@ def run(args, if t.find(u) > -1: expected_unstable_list.append(t) + # run only specified tests: + if tests_to_run: + new_tests=[] + for t in all_tests: + keep=False + for tts in tests_to_run: + if t.find(tts)>-1: + keep=True + if keep: + print ("Keeping the test %s" %(t)) + new_tests.append(t) + else: + pass + all_tests=new_tests + # remove any specified tests: if tests_to_skip: new_tests=[] From 8a814870e0fe9e7a0c7befbde7bb1f23478b7d81 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 24 May 2024 13:10:30 -0700 Subject: [PATCH 492/748] Tidy-up Phenix: remove phenix.chains_as_models.py. Adapt test. --- mmtbx/command_line/chains_as_models.py | 42 ------------------- mmtbx/regression/tst_models_to_from_chains.py | 11 ----- 2 files changed, 53 deletions(-) delete mode 100644 mmtbx/command_line/chains_as_models.py diff --git a/mmtbx/command_line/chains_as_models.py b/mmtbx/command_line/chains_as_models.py deleted file mode 100644 index e7bc5b78aa..0000000000 --- a/mmtbx/command_line/chains_as_models.py +++ /dev/null @@ -1,42 +0,0 @@ -from __future__ import absolute_import, division, print_function -# LIBTBX_SET_DISPATCHER_NAME phenix.chains_as_models - -import sys -import iotbx.pdb -from libtbx.utils import Sorry - -legend = """phenix.models_as_chains: - Convert multi-chain PDB file into multi-model (MODEL-ENDMDL) PDB file. - -How to run: - phenix.chains_as_models model.pdb - -Feedback: - PAfonine@lbl.gov - phenixbb@phenix-online.org""" - -def run(args): - if(len(args)!=1): raise Sorry("PDB file is expected.") - try: - pdb_inp = iotbx.pdb.input(file_name=args[0]) - except Exception: - raise Sorry("PDB file is expected.") - # - root = iotbx.pdb.hierarchy.root() - h = pdb_inp.construct_hierarchy() - n_models = len(h.models()) - if(not n_models==1): - raise Sorry("PDB file must contain one MODEL, found %d models."%n_models) - for i, chain in enumerate(h.chains()): - m = iotbx.pdb.hierarchy.model(id=str(i)) - chain_ = chain.detached_copy() - chain_.id="A" - m.append_chain(chain_) - root.append_model(m) - root.write_pdb_file( - file_name = "models_"+args[0], - crystal_symmetry = pdb_inp.crystal_symmetry()) - - -if (__name__ == "__main__"): - run(args=sys.argv[1:]) diff --git a/mmtbx/regression/tst_models_to_from_chains.py b/mmtbx/regression/tst_models_to_from_chains.py index 5ed90afcdb..9b40b94108 100644 --- a/mmtbx/regression/tst_models_to_from_chains.py +++ b/mmtbx/regression/tst_models_to_from_chains.py @@ -95,18 +95,7 @@ def exercise(prefix="tst_models_to_from_chains"): fc_c = complete_set.structure_factors_from_scatterers( xray_structure=xrs_c).f_calc() # - assert not easy_run.call("phenix.chains_as_models chains_%s"%input_file_name) - pdb_inp = iotbx.pdb.input(file_name="models_chains_"+input_file_name) - h = pdb_inp.construct_hierarchy() - assert len(list(h.chains()))==expected_n - assert len(list(h.models()))==expected_n - xrs_m = pdb_inp.xray_structure_simple() - fc_m = complete_set.structure_factors_from_scatterers( - xray_structure=xrs_m).f_calc() - # assert approx_equal(0, r(fc, fc_c) ) - assert approx_equal(0, r(fc, fc_m) ) - assert approx_equal(0, r(fc_c, fc_m)) if (__name__ == "__main__"): exercise() From 1f16ea1a9b94e537c7e889993f566d12795ab74b Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 24 May 2024 13:16:28 -0700 Subject: [PATCH 493/748] Clean clutter --- mmtbx/validation/regression/tst_cablam.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/validation/regression/tst_cablam.py b/mmtbx/validation/regression/tst_cablam.py index 70ced78113..4faace2af5 100644 --- a/mmtbx/validation/regression/tst_cablam.py +++ b/mmtbx/validation/regression/tst_cablam.py @@ -2,7 +2,7 @@ from mmtbx.validation import cablam from libtbx.test_utils import show_diff from iotbx.data_manager import DataManager -from libtbx.test_utils import convert_string_to_cif_long, convert_pdb_to_cif_for_pdb_str +from libtbx.test_utils import convert_string_to_cif_long from iotbx import pdb import libtbx.load_env From 87d856f706749159e52d114593db4015d0e1a7eb Mon Sep 17 00:00:00 2001 From: terwill Date: Fri, 24 May 2024 15:40:24 -0600 Subject: [PATCH 494/748] Allow sort, git with tests_to_run and tests_to_skip --- libtbx/command_line/run_tests_parallel.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libtbx/command_line/run_tests_parallel.py b/libtbx/command_line/run_tests_parallel.py index b9ce8a910b..038c56e8f9 100755 --- a/libtbx/command_line/run_tests_parallel.py +++ b/libtbx/command_line/run_tests_parallel.py @@ -127,6 +127,10 @@ def run(args, for t in all_tests: if t.find(u) > -1: expected_unstable_list.append(t) + # Run all above to get expected failures etc + + if (supplied_list_of_tests is not None): + all_tests = supplied_list_of_tests # just use supplied tests # run only specified tests: if tests_to_run: @@ -157,9 +161,6 @@ def run(args, print ("Skipping the test %s" %(t)) all_tests=new_tests - if (supplied_list_of_tests is not None): - all_tests = supplied_list_of_tests # just use supplied tests - # Run all above to get expected failures etc # check that test lists are unique seen = set() From 4d9dba267c69511d06e2ba184970adf82efcd0ca Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Fri, 24 May 2024 15:05:02 -0700 Subject: [PATCH 495/748] Remove unused counter. --- cctbx/geometry_restraints/__init__.py | 21 +-------------------- mmtbx/monomer_library/pdb_interpretation.py | 2 -- 2 files changed, 1 insertion(+), 22 deletions(-) diff --git a/cctbx/geometry_restraints/__init__.py b/cctbx/geometry_restraints/__init__.py index 742246b86a..cc38f9bf1b 100644 --- a/cctbx/geometry_restraints/__init__.py +++ b/cctbx/geometry_restraints/__init__.py @@ -65,7 +65,6 @@ def __init__(self, proxies, strict_conflict_handling): self.proxies = proxies self.strict_conflict_handling = strict_conflict_handling self.n_resolved_conflicts = 0 - self.counts = flex.size_t() self.discard_table() def initialize_table(self): @@ -81,11 +80,9 @@ def discard_table(self): def append_custom_proxy(self, proxy): assert self.table is None self.proxies.append(proxy) - self.counts.append(1) def _append_proxy(self, source_info, proxy, process_result): self.proxies.append(proxy) - self.counts.append(1) self.source_labels.append(source_info.labels()) self.source_n_expected_atoms.append(source_info.n_expected_atoms()) process_result.tabulated_proxy = proxy @@ -96,6 +93,7 @@ def _handle_conflict(self, proxy, i_list, process_result): + # Almost never called. source_n_expected_atoms = source_info.n_expected_atoms() if (self.strict_conflict_handling or self.source_n_expected_atoms[i_list] @@ -156,8 +154,6 @@ def process(self, source_info, proxy, tolerance=1.e-6): proxy=proxy, i_list=i_list, process_result=result) - if (not result.is_conflicting): - self.counts[i_list] += 1 return result class angle_proxy_registry(proxy_registry_base): @@ -175,7 +171,6 @@ def add_if_not_duplicated(self, proxy, tolerance=1.e-6): if (i_seqs_0_2 not in tab_i_seq_1): tab_i_seq_1[i_seqs_0_2] = self.proxies.size() self.proxies.append(proxy) - self.counts.append(1) return True return False @@ -202,8 +197,6 @@ def process(self, source_info, proxy, tolerance=1.e-6): proxy=proxy, i_list=i_list, process_result=result) - if (not result.is_conflicting): - self.counts[i_list] += 1 return result def lookup_i_proxy(self, i_seqs): @@ -231,7 +224,6 @@ def add_if_not_duplicated(self, proxy, tolerance=1.e-6): if (i_seqs_1_2_3 not in tab_i_seq_0): tab_i_seq_0[i_seqs_1_2_3] = self.proxies.size() self.proxies.append(proxy) - self.counts.append(1) return True return False @@ -260,8 +252,6 @@ def process(self, source_info, proxy, tolerance=1.e-6): proxy=proxy, i_list=i_list, process_result=result) - if (not result.is_conflicting): - self.counts[i_list] += 1 return result def lookup_i_proxy(self, i_seqs): @@ -293,7 +283,6 @@ def add_if_not_duplicated(self, proxy, tolerance=1.e-6): if (i_seqs_1_2_3 not in tab_i_seq_0): tab_i_seq_0[i_seqs_1_2_3] = self.proxies.size() self.proxies.append(proxy) - self.counts.append(1) return True return False @@ -321,8 +310,6 @@ def process(self, source_info, proxy, tolerance=1.e-6): proxy=proxy, i_list=i_list, process_result=result) - if (not result.is_conflicting): - self.counts[i_list] += 1 return result class planarity_proxy_registry(proxy_registry_base): @@ -341,7 +328,6 @@ def add_if_not_duplicated(self, proxy, tolerance=1.e-6): tab_i_seq_0[i_seqs_1_up] = self.proxies.size() # saving proxy number in list self.proxies.append(proxy) - self.counts.append(1) return True return False @@ -367,8 +353,6 @@ def process(self, source_info, proxy, tolerance=1.e-6): proxy=proxy, i_list=i_list, process_result=result) - if (not result.is_conflicting): - self.counts[i_list] += 1 return result class parallelity_proxy_registry(proxy_registry_base): @@ -388,7 +372,6 @@ def add_if_not_duplicated(self, proxy, tolerance=1.e-6): # saving proxy number in list self.table[(tab_i_seqs, tab_j_seqs)]= self.proxies.size() self.proxies.append(proxy) - self.counts.append(1) return True return False @@ -422,8 +405,6 @@ def process(self, source_info, proxy, tolerance=1.e-6): proxy=proxy, i_list=i_list, process_result=result) - if (not result.is_conflicting): - self.counts[i_list] += 1 # mark somewhere that this is duplicated return result @bp.inject_into(prolsq_repulsion_function) diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index 084bfb248b..64992970cf 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -3055,8 +3055,6 @@ def __init__(self, n_seq, strict_conflict_handling): self.parallelity = geometry_restraints.parallelity_proxy_registry( strict_conflict_handling=strict_conflict_handling) - # XXX TODO use counts to modify weights - def initialize_tables(self): self.bond_simple.initialize_table() self.angle.initialize_table() From 8a5111d25e8d79105ffcefe5c62585a265b3265b Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Fri, 24 May 2024 18:48:20 -0700 Subject: [PATCH 496/748] 3x faster adopt_xray_structure(). 7% off of pdb_interpretation runtime. --- iotbx/pdb/hierarchy.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index 9fc1882895..6659e01f59 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -1145,11 +1145,10 @@ def adopt_xray_structure(self, xray_structure): """ if(self.atoms_size() != xray_structure.scatterers().size()): raise RuntimeError("Incompatible size of hierarchy and scatterers array.") - awl = self.atoms_with_labels() scatterers = xray_structure.scatterers() uc = xray_structure.unit_cell() orth = uc.orthogonalize - for sc, a in zip(scatterers, awl): + for sc, a in zip(scatterers, self.atoms()): a.set_xyz(new_xyz=orth(sc.site)) a.set_occ(new_occ=sc.occupancy) a.set_b(new_b=adptbx.u_as_b(sc.u_iso_or_equiv(uc))) From 496847aaa1c00218d19112bb1ea91806a369b623 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sat, 25 May 2024 14:39:19 -0700 Subject: [PATCH 497/748] Fo-Fc OMIT map based per atom-group fitting of H with rotational d.o.f. --- mmtbx/hydrogens/__init__.py | 108 ++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/mmtbx/hydrogens/__init__.py b/mmtbx/hydrogens/__init__.py index 9fc01eb283..a7a110acf6 100644 --- a/mmtbx/hydrogens/__init__.py +++ b/mmtbx/hydrogens/__init__.py @@ -330,6 +330,114 @@ def count_rotatable(selections): result += len(s[1]) return result +class map_manager(object): + + def __init__(self, fmodel, map_type): + self.fmodel = fmodel + self.map_type = map_type + cs = fmodel.f_obs().crystal_symmetry() + self.unit_cell = cs.unit_cell() + self.crystal_gridding = maptbx.crystal_gridding( + unit_cell = self.unit_cell, + space_group_info = cs.space_group_info(), + symmetry_flags = maptbx.use_space_group_symmetry, + step = 0.25) + self.omit_map = None + self.size = self.fmodel.xray_structure.scatterers().size() + + def update_omit_map(self, omit_selection): + sel_keep = ~flex.bool(self.size, omit_selection) + fmodel = self.fmodel.deep_copy() + fmodel.update_xray_structure( + xray_structure = fmodel.xray_structure.select(sel_keep), + update_f_calc = True, + update_f_mask = False) + mc = fmodel.electron_density_map().map_coefficients( + map_type = "mFobs-DFmodel", + isotropize = False, + exclude_free_r_reflections = True) + fft_map = mc.fft_map(crystal_gridding = self.crystal_gridding) + fft_map.apply_sigma_scaling() + self.omit_map = fft_map.real_map_unpadded() + + def score(self, sites_cart): + return maptbx.real_space_target_simple( + unit_cell = self.unit_cell, + density_map = self.omit_map, + sites_cart = sites_cart) + +def fit_rotatable2(model, fmodel, use_electron_xh=True): + """ + Slow, OMIT map based fitting of rotatable H. + """ + # Reset mask params if needed + mask_params = fmodel.mask_params + mpih = mask_params.ignore_hydrogens + if(mpih): + mask_params.ignore_hydrogens=False + fmodel.update(mask_params=mask_params) + fmodel.update_all_scales() + # Set X-H bonds to shorter (electron) distances + model.set_hydrogen_bond_length(use_neutron_distances = False) + # + fmodel.update_all_scales() + # FIT + mm = map_manager(fmodel = fmodel, map_type = "mFobs-DFmodel") + get_class = iotbx.pdb.common_residue_names_get_class + sites_cart = model.get_sites_cart() + for m in model.get_hierarchy().models(): + for c in m.chains(): + first=True + for r in c.residues(): + if not get_class(r.resname)=="common_amino_acid": continue + s = mmtbx.hydrogens.shortcut(residue=r, first=first, log=model.log) + first=False + if s is None: continue + # print(r.resname, s) + omit_selection = flex.size_t() + for cl in s: + omit_selection.extend(flex.size_t(cl[1])) + mm.update_omit_map(omit_selection = omit_selection) + for cl in s: + axis = cl[0] + a1, a2 = sites_cart[axis[0]], sites_cart[axis[1]] + sel_to_rotate = flex.size_t(cl[1]) + sites_cart_to_rotate = sites_cart.select(sel_to_rotate) + score_start = mm.score(sites_cart = sites_cart_to_rotate) + score_best = score_start + sites_cart_moved = flex.vec3_double(sites_cart_to_rotate.size()) + sites_cart_best = None + assert len(sel_to_rotate) in [1,3] + if len(sel_to_rotate)==1: stop=360 + else: stop=60 + for angle in range(0, stop, 1): + sites_cart_moved = flex.vec3_double(sites_cart_to_rotate.size()) + for isite, site_cart in enumerate(sites_cart_to_rotate): + site_cart_rotated = rotate_point_around_axis( + axis_point_1 = a1, + axis_point_2 = a2, + point = site_cart, + angle = angle, + deg = True) + sites_cart_moved[isite] = site_cart_rotated + score = mm.score(sites_cart = sites_cart_moved) + if score > score_best: + score_best = score + sites_cart_best = sites_cart_moved.deep_copy() + if sites_cart_best is not None: + sites_cart = sites_cart.set_selected(sel_to_rotate, sites_cart_best) + model.set_sites_cart(sites_cart) + # Reset X-H bonds + if not use_electron_xh: + model.set_hydrogen_bond_length(use_neutron_distances = True) + # Update fmodel with new sites_cart + fmodel.xray_structure.set_sites_cart(model.get_sites_cart()) + if(mpih): + mask_params.ignore_hydrogens=False + fmodel.update(mask_params=mask_params) + fmodel.update_xray_structure(update_f_calc=True, update_f_mask=True) + fmodel.update_all_scales() + def fit_rotatable( pdb_hierarchy, xray_structure, From 7bc72e7116bb97cca91777ee2572d96028e81095 Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Sat, 25 May 2024 14:44:32 -0700 Subject: [PATCH 498/748] adjust transparency, propagate keep_occupancy parameter --- mmtbx/nci/skew_kurt_plot.py | 2 +- mmtbx/pdbtools.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mmtbx/nci/skew_kurt_plot.py b/mmtbx/nci/skew_kurt_plot.py index c3532bba2e..665e6ddd51 100644 --- a/mmtbx/nci/skew_kurt_plot.py +++ b/mmtbx/nci/skew_kurt_plot.py @@ -171,7 +171,7 @@ def make_figure( aspect=aspect, # interpolation='bicubic', # norm=norm, - alpha=0.5 + alpha=0.7 ) plt.contour( blue_filling, contours[type], origin="lower", diff --git a/mmtbx/pdbtools.py b/mmtbx/pdbtools.py index 85f75b0389..563cbd117c 100644 --- a/mmtbx/pdbtools.py +++ b/mmtbx/pdbtools.py @@ -400,7 +400,8 @@ def _remove_alt_confs(self): print("Remove altlocs", file=self.log) self.pdb_hierarchy.remove_alt_confs( always_keep_one_conformer = self.params.always_keep_one_conformer, - altloc_to_keep = self.params.altloc_to_keep) + altloc_to_keep = self.params.altloc_to_keep, + keep_occupancy = self.params.keep_occupancy) def _truncate_to_poly_gly(self): if(self.params.truncate_to_polygly): From fd728736ce788d9235080811a9f24264a684db79 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sat, 25 May 2024 15:24:51 -0700 Subject: [PATCH 499/748] Bug fix: once model is processed there is no model_input any more --- mmtbx/model/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index f7aca3dbd7..e23006c0e8 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -2946,7 +2946,7 @@ def set_hydrogen_bond_length(self, pi_scope = self.get_current_pdb_interpretation_params() # check if current pi_params is consistent with requested X-H length mode if (pi_scope.pdb_interpretation.use_neutron_distances - is not use_neutron_distances): + is not use_neutron_distances and self._model_input is not None): pi_scope.pdb_interpretation.use_neutron_distances = use_neutron_distances # this will take care of resetting everything (grm, processed pdb) self.process(make_restraints=True, From 970dde93f69aaec5013fa97df709a05f8afac7fd Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Tue, 28 May 2024 13:57:45 -0700 Subject: [PATCH 500/748] self._model_input can actually be absent... --- mmtbx/model/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index e23006c0e8..f7aca3dbd7 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -2946,7 +2946,7 @@ def set_hydrogen_bond_length(self, pi_scope = self.get_current_pdb_interpretation_params() # check if current pi_params is consistent with requested X-H length mode if (pi_scope.pdb_interpretation.use_neutron_distances - is not use_neutron_distances and self._model_input is not None): + is not use_neutron_distances): pi_scope.pdb_interpretation.use_neutron_distances = use_neutron_distances # this will take care of resetting everything (grm, processed pdb) self.process(make_restraints=True, From a8b79cc26ffe3cebccf9b4ff9a083fa7b5e0ef4d Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Wed, 29 May 2024 12:05:08 -0700 Subject: [PATCH 501/748] New convenience function with tests --- mmtbx/alignment/__init__.py | 16 ++++++++++++++++ mmtbx/regression/tst_alignment.py | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/mmtbx/alignment/__init__.py b/mmtbx/alignment/__init__.py index c9cd9f87e3..84081f7ebd 100644 --- a/mmtbx/alignment/__init__.py +++ b/mmtbx/alignment/__init__.py @@ -379,6 +379,22 @@ def exact_match_selections(self): j_seqs.append(j) return i_seqs, j_seqs + def exact_mismatch_selection(self): + """Returns i_seqs and j_seqs of residues that do not match, excluding + insertions and deletions. + + Returns: + (flex.size_t, flex.size_t): i_seqs that mismatch + """ + i_seqs = flex.size_t() + j_seqs = flex.size_t() + for a, b, i, j in zip(self.a, self.b, self.i_seqs_a, self.i_seqs_b): + if(a != b and a not in ["-", None] and b not in ["-", None]): + if(i is not None and j is not None): + i_seqs.append(i) + j_seqs.append(j) + return i_seqs, j_seqs + # amino acid similarity scores from Dayhoff's 1978 paper; like PAM250? dayhoff_mdm78_similarity_scores = [ [ 18,-20, 3, 3,-35, 13,-14, -5,-12,-19,-11, 2, 11, -4,-15, 11, 12, 2,-58,-35], diff --git a/mmtbx/regression/tst_alignment.py b/mmtbx/regression/tst_alignment.py index 34005de26f..05ed280a94 100644 --- a/mmtbx/regression/tst_alignment.py +++ b/mmtbx/regression/tst_alignment.py @@ -74,6 +74,26 @@ def exercise_align(): assert i_seqs == flex.size_t([0, 1, 2, 7, 8, 9]) and \ j_seqs == flex.size_t([0, 1, 2, 8, 9, 10]) +def exercise_exact_mismatch_selection(): + """ examples from exercise_aligh function + """ + def get_mismatch_sel(s1, s2): + i, j = align(s1, s2).extract_alignment().exact_mismatch_selection() + return list(i), list(j) + i_seqs, j_seqs = get_mismatch_sel("EASYA", + "AETSYT") + assert i_seqs == [1,4] and j_seqs == [2,5] + + i_seqs, j_seqs = get_mismatch_sel("EASY", + "KMST") + assert i_seqs == [0,1,3] and j_seqs == [0,1,3] + + i_seqs, j_seqs = get_mismatch_sel("EASY", + "KMT") + assert i_seqs == [1,2,3] and j_seqs == [0,1,2] + i_seqs, j_seqs = get_mismatch_sel("EASY", + "EASY") + assert i_seqs == [] and j_seqs == [] def exercise_2(): A = "AAAGGTT" @@ -232,6 +252,7 @@ def testUnknown(self): def exercise(): exercise_align_mask() exercise_align() + exercise_exact_mismatch_selection() exercise_2() exercise_similarity_scores() exercise_ext From 7d10c26626bb367be9f82525194b73ff9d476f7c Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Wed, 29 May 2024 14:55:19 -0700 Subject: [PATCH 502/748] detector_residuals: update for matplotlib api --- xfel/command_line/detector_residuals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xfel/command_line/detector_residuals.py b/xfel/command_line/detector_residuals.py index 6ed6152aee..a4922fe708 100644 --- a/xfel/command_line/detector_residuals.py +++ b/xfel/command_line/detector_residuals.py @@ -1541,7 +1541,7 @@ def detector_plot_refls(self, detector, reflections, title, show=True, plot_call if sm is not None and color_vals is not None: if colorbar_units is None: colorbar_units = "mm" - cb = ax.figure.colorbar(sm, ticks=color_vals) + cb = ax.figure.colorbar(sm, ticks=color_vals, ax=ax) cb.ax.set_yticklabels(["%3.2f %s"%(i,colorbar_units) for i in color_vals]) plt.title(title) From c462423cefebab8c82f4b17ab8e55a8f7884c8a2 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 30 May 2024 12:26:54 -0700 Subject: [PATCH 503/748] Xtriage: use the word multiplicity instead of redundancy --- iotbx/merging_statistics.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/iotbx/merging_statistics.py b/iotbx/merging_statistics.py index a5abb8e6be..1e10f24105 100644 --- a/iotbx/merging_statistics.py +++ b/iotbx/merging_statistics.py @@ -471,7 +471,7 @@ def show_summary(self, out=sys.stdout, prefix=""): print(prefix+"Resolution: %.2f - %.2f" % (self.d_max, self.d_min), file=out) print(prefix+"Observations: %d" % self.n_obs, file=out) print(prefix+"Unique reflections: %d" % self.n_uniq, file=out) - print(prefix+"Redundancy: %.1f" % self.mean_redundancy, file=out) + print(prefix+"Multiplicity: %.1f" % self.mean_redundancy, file=out) print(prefix+"Completeness: %.2f%%" % (self.completeness*100), file=out) print(prefix+"Mean intensity: %.1f" % self.i_mean, file=out) print(prefix+"Mean I/sigma(I): %.1f" % self.i_over_sigma_mean, file=out) @@ -611,10 +611,10 @@ def __init__(self, ) self.bins = [] title = "Intensity merging statistics" - column_labels = ["1/d**2","N(obs)","N(unique)","Redundancy","Completeness", + column_labels = ["1/d**2","N(obs)","N(unique)","Multiplicity","Completeness", "Mean(I)", "Mean(I/sigma)", "R-merge", "R-meas", "R-pim", "R-anom", "CC1/2", "CC(anom)"] - graph_names = ["Reflection counts", "Redundancy", "Completeness", + graph_names = ["Reflection counts", "Multiplicity", "Completeness", "Mean(I)", "Mean(I/sigma)", "R-factors", "CC1/2", "CC(anom)"] graph_columns = [[0,1,2],[0,3],[0,4],[0,5],[0,6],[0,7,8,9],[0,11],[0,13]] if cc_one_half_significance_level is not None: @@ -658,13 +658,13 @@ def __init__(self, @property def signal_table(self): - column_labels = ["1/d**2","N(obs)","N(unique)","Redundancy","Completeness", + column_labels = ["1/d**2","N(obs)","N(unique)","Multiplicity","Completeness", "Mean(I)", "Mean(I/sigma)", ] - graph_names = ["Reflection counts", "Redundancy", "Completeness", + graph_names = ["Reflection counts", "Multiplicity", "Completeness", "Mean(I)", "Mean(I/sigma)",] graph_columns = [[0,1,2],[0,3],[0,4],[0,5],[0,6],] table = data_plots.table_data( - title="Statistics for redundancy, completeness, and signal", + title="Statistics for multiplicity, completeness, and signal", column_labels=column_labels, graph_names=graph_names, graph_columns=graph_columns, @@ -728,7 +728,7 @@ def show(self, out=None, header=True): if self.overall.anom_probability_plot_all_data is not None: self.overall.show_anomalous_probability_plot(out) print("", file=out) - print("Redundancies%s:" % self.anom_extra, file=out) + print("Multiplicities%s:" % self.anom_extra, file=out) n_obs = sorted(self.overall.redundancies.keys()) for x in n_obs : print(" %d : %d" % (x, self.overall.redundancies[x]), file=out) @@ -915,7 +915,7 @@ def show_model_vs_data(self, out=None, prefix=""): outer_shell.d_min), file=out) print(prefix + " Mean(I/sigmaI) : %6.3f (%.3f)" % ( self.overall.i_over_sigma_mean, outer_shell.i_over_sigma_mean), file=out) - print(prefix + " Redundancy : %4.2f (%.2f)" % ( + print(prefix + " Multiplicity : %4.2f (%.2f)" % ( self.overall.mean_redundancy, outer_shell.mean_redundancy), file=out) print(prefix + " R-merge : %5.3f (%.3f)" % ( self.overall.r_merge, outer_shell.r_merge), file=out) From 127375ad37edfdb05a7551c9eac666ad5f5e7c62 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 31 May 2024 09:55:14 -0700 Subject: [PATCH 504/748] Reduce2: bugfix with test --- mmtbx/hydrogens/reduce_hydrogen.py | 11 ++--- mmtbx/hydrogens/tst_add_hydrogen_3.py | 61 +++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index 9d9ea68a59..95d8a770ab 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -402,20 +402,18 @@ def add_missing_H_atoms_at_bogus_position(self): pdb_hierarchy = self.model.get_hierarchy() mon_lib_srv = self.model.get_mon_lib_srv() #XXX This breaks for 1jxt, residue 2, TYR - #no_H_placed_resnames = list() for m in pdb_hierarchy.models(): for chain in m.chains(): for rg in chain.residue_groups(): n_atom_groups = len(rg.atom_groups()) for ag in rg.atom_groups(): - if n_atom_groups == 3 and ag.altloc == '': + if n_atom_groups > 2 and ag.altloc == '': continue #print list(ag.atoms().extract_name()) if(get_class(name=ag.resname) == "common_water"): continue actual = [a.name.strip().upper() for a in ag.atoms()] # mlq = mon_lib_query(residue=ag, mon_lib_srv=mon_lib_srv) - #if (get_class(name=ag.resname) in ['modified_rna_dna', 'other']): if mlq is None: self.no_H_placed_mlq.append(ag.resname) continue @@ -428,8 +426,10 @@ def add_missing_H_atoms_at_bogus_position(self): expected_h.append(k) #else: # expected_ha.append(k) - # TODO start: temporary fix until v3 names are in mon lib #print('expected H', expected_h) + # + # TODO start + # temporary fix until v3 names are in mon lib if (get_class(name=ag.resname) in ['common_amino_acid', 'modified_amino_acid', 'd_amino_acid']): for altname in alternative_names: @@ -451,9 +451,6 @@ def add_missing_H_atoms_at_bogus_position(self): segid = ag.atoms()[0].segid for mh in missing_h: - #if ag.resname == 'PTR' and mh == 'HN2': continue - # TODO: this should be probably in a central place - # NWM: I have something like this in ready_set_utils if len(mh) < 4: mh = (' ' + mh).ljust(4) a = (iotbx.pdb.hierarchy.atom() .set_name(new_name=mh) diff --git a/mmtbx/hydrogens/tst_add_hydrogen_3.py b/mmtbx/hydrogens/tst_add_hydrogen_3.py index 7bcdec874b..24ebfc19fe 100644 --- a/mmtbx/hydrogens/tst_add_hydrogen_3.py +++ b/mmtbx/hydrogens/tst_add_hydrogen_3.py @@ -16,6 +16,7 @@ def run(): test_004() test_005() test_006() + test_007() # ------------------------------------------------------------------------------ @@ -140,6 +141,15 @@ def test_006(): # ------------------------------------------------------------------------------ +def test_007(): + ''' + MET in triple conformation, with split at CAlpha (i.e. N-C-O have altloc + blank). Make sure that H atoms are added at each alt conf. + ''' + compare_models(pdb_str = pdb_str_007) + +# ------------------------------------------------------------------------------ + pdb_str_000 = """ REMARK Make sure reduce does not crash for single_atom_residue models CRYST1 22.029 33.502 24.035 90.00 90.00 90.00 P 1 @@ -739,6 +749,57 @@ def test_006(): HETATM 122 H132BCNZ A 301 23.663 35.651 78.292 0.58 36.08 H END''' +pdb_str_007 = ''' +REMARK scenario for 3 alt confs with split at Calpha (1ssx) +CRYST1 14.055 14.336 16.437 90.00 90.00 90.00 P 1 +ATOM 1 N MET A 190 8.147 8.228 5.841 1.00 5.11 N +ATOM 2 C MET A 190 6.079 7.001 6.145 1.00 4.90 C +ATOM 3 O MET A 190 5.489 8.085 6.030 1.00 5.59 O +ATOM 4 CA AMET A 190 7.607 6.937 6.231 0.64 5.00 C +ATOM 5 CB AMET A 190 8.086 6.534 7.644 0.64 5.98 C +ATOM 6 CG AMET A 190 7.600 7.386 8.781 0.64 8.55 C +ATOM 7 SD AMET A 190 5.950 7.100 9.364 0.64 9.70 S +ATOM 8 CE AMET A 190 6.057 5.778 10.487 0.64 19.81 C +ATOM 9 H AMET A 190 8.372 8.277 5.013 1.00 5.11 H +ATOM 10 HA AMET A 190 7.935 6.240 5.642 0.64 5.00 H +ATOM 11 HB2AMET A 190 7.785 5.628 7.818 0.64 5.98 H +ATOM 12 HB3AMET A 190 9.055 6.569 7.655 0.64 5.98 H +ATOM 13 HG2AMET A 190 8.193 7.243 9.535 0.64 8.55 H +ATOM 14 HG3AMET A 190 7.641 8.313 8.498 0.64 8.55 H +ATOM 15 HE1AMET A 190 6.408 5.000 10.026 0.64 19.81 H +ATOM 16 HE2AMET A 190 5.172 5.586 10.834 0.64 19.81 H +ATOM 17 HE3AMET A 190 6.649 6.028 11.213 0.64 19.81 H +ATOM 18 CA BMET A 190 7.599 6.926 6.172 0.21 4.35 C +ATOM 19 CB BMET A 190 8.059 6.429 7.549 0.21 3.88 C +ATOM 20 CG BMET A 190 7.945 7.470 8.646 0.21 3.81 C +ATOM 21 SD BMET A 190 6.333 8.029 9.240 0.21 5.37 S +ATOM 22 CE BMET A 190 5.873 6.543 10.201 0.21 7.00 C +ATOM 23 H BMET A 190 8.283 8.347 5.000 1.00 5.11 H +ATOM 24 HA BMET A 190 7.929 6.282 5.526 0.21 4.35 H +ATOM 25 HB2BMET A 190 7.513 5.669 7.804 0.21 3.88 H +ATOM 26 HB3BMET A 190 8.990 6.163 7.489 0.21 3.88 H +ATOM 27 HG2BMET A 190 8.403 7.114 9.423 0.21 3.81 H +ATOM 28 HG3BMET A 190 8.400 8.266 8.329 0.21 3.81 H +ATOM 29 HE1BMET A 190 5.845 5.778 9.605 0.21 7.00 H +ATOM 30 HE2BMET A 190 5.000 6.683 10.601 0.21 7.00 H +ATOM 31 HE3BMET A 190 6.535 6.398 10.895 0.21 7.00 H +ATOM 32 CA CMET A 190 7.592 6.970 6.290 0.15 4.69 C +ATOM 33 CB CMET A 190 7.939 6.723 7.773 0.15 5.99 C +ATOM 34 CG CMET A 190 7.637 7.940 8.598 0.15 7.61 C +ATOM 35 SD CMET A 190 7.421 7.776 10.371 0.15 6.55 S +ATOM 36 CE CMET A 190 5.808 8.422 10.506 0.15 6.32 C +ATOM 37 H CMET A 190 8.470 8.203 5.044 1.00 5.11 H +ATOM 38 HA CMET A 190 7.972 6.249 5.764 0.15 4.69 H +ATOM 39 HB2CMET A 190 8.884 6.521 7.855 0.15 5.99 H +ATOM 40 HB3CMET A 190 7.411 5.982 8.110 0.15 5.99 H +ATOM 41 HG2CMET A 190 8.368 8.564 8.471 0.15 7.61 H +ATOM 42 HG3CMET A 190 6.812 8.322 8.259 0.15 7.61 H +ATOM 43 HE1CMET A 190 5.536 8.401 11.437 0.15 6.32 H +ATOM 44 HE2CMET A 190 5.205 7.880 9.973 0.15 6.32 H +ATOM 45 HE3CMET A 190 5.806 9.336 10.181 0.15 6.32 H +END +''' + # ------------------------------------------------------------------------------ if (__name__ == "__main__"): From 05bcfc6a3444e9646e0b144b5edd4c617731ef8f Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Sun, 2 Jun 2024 18:57:08 -0700 Subject: [PATCH 505/748] Update CHANGELOG.rst for 2024.5 release [skip ci] --- CHANGELOG.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1ecf553ead..04cf587c5f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,10 @@ +2024.5 +====== + +* Added water picking with alternate conformations +* Removed more unused or not maintained tools in iotbx and mmtbx +* Added check for NaN in ccp4/mrc maps + 2024.4 ====== From d5a87e0c349cb1ef2868b55042d863aa6c4028e3 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Mon, 3 Jun 2024 14:25:54 -0700 Subject: [PATCH 506/748] Reduce2: Add test illustrating behavior of grm add_new_bond_restraints_in_place function --- cctbx/regression/tst_grm_modifications.py | 49 +++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/cctbx/regression/tst_grm_modifications.py b/cctbx/regression/tst_grm_modifications.py index 753dddef97..402afd4102 100644 --- a/cctbx/regression/tst_grm_modifications.py +++ b/cctbx/regression/tst_grm_modifications.py @@ -61,6 +61,19 @@ END """.splitlines() +raw_records4b = """\ +CRYST1 15.775 12.565 13.187 90.00 90.00 90.00 P 1 +ATOM 1 N MET A 1 9.821 6.568 5.000 1.00 66.07 N +ATOM 2 CA MET A 1 9.946 7.171 6.357 1.00 66.55 C +ATOM 3 C MET A 1 10.571 6.157 7.305 1.00 64.57 C +ATOM 4 O MET A 1 10.775 5.000 6.933 1.00 66.25 O +ATOM 5 CB MET A 1 8.570 7.565 6.897 1.00 69.08 C +ATOM 6 CG MET A 1 7.723 6.373 7.299 1.00 71.37 C +ATOM 7 SD MET A 1 6.247 6.862 8.187 1.00 76.22 S +ATOM 8 CE MET A 1 -1.000 6.694 6.892 1.00 74.93 C +END +""".splitlines() + raw_records5 = """\ CRYST1 258.687 258.687 47.103 90.00 90.00 120.00 P 63 6 ATOM 213 N ILE A 78 87.236 -55.209 0.578 1.00179.51 N @@ -305,6 +318,41 @@ def exercise_add_new_bond_restraint_in_place(mon_lib_srv, ener_lib): assert geometry.pair_proxies().nonbonded_proxies.simple.size() == 8 assert geometry.pair_proxies().nonbonded_proxies.asu.size() == 0 +def exercise_add_new_bond_when_long_bond_across_ASU(mon_lib_srv, ener_lib): + ''' + raw_records4b is same as raw_records4, except that CE is in another ASU + --> 6A long bond to SD --> this will choke the call of + all_bonds_asu_table.add_pair_sym_table(self.shell_sym_tables[0]) + in add_new_bond_restraints_in_place + root of the issue is that there is >5 A long bond (i.e. longer than the + default of max_distance_between_connecting_atoms, which is 5) between + atoms where one atom is in another ASU + see also test + ''' + geometry, xrs = make_initial_grm(mon_lib_srv, ener_lib, raw_records4b) + + proxy = geometry_restraints.bond_simple_proxy( + i_seqs=(0,3), + distance_ideal=2.0, + weight=3000) + assert not geometry.is_bonded_atoms(0,3) + assert not geometry.is_bonded_atoms(3,0) + # DL: this will fail + #geometry.add_new_bond_restraints_in_place([proxy], xrs.sites_cart()) + # DL: this works + geometry.add_new_bond_restraints_in_place([proxy], xrs.sites_cart(), + max_distance_between_connecting_atoms=10) + + assert geometry.is_bonded_atoms(0,3) + assert geometry.is_bonded_atoms(3,0) + assert geometry.pair_proxies().bond_proxies.simple.size() == 8 + assert geometry.pair_proxies().bond_proxies.asu.size() == 0 + simple, asu = geometry.get_covalent_bond_proxies() + assert simple.size() + asu.size() == 8 + # DL: these numbers will need to be adapted + #assert geometry.pair_proxies().nonbonded_proxies.simple.size() == 8 + #assert geometry.pair_proxies().nonbonded_proxies.asu.size() == 0 + def exercise_add_super_long_bond(mon_lib_srv, ener_lib): # distance between the two is 26A, they are not added because of # max_distance_between_connecting_atoms=5 is default. @@ -682,6 +730,7 @@ def exercise(): exercise_bond_near_symmetry3(mon_lib_srv, ener_lib) exercise_bond_over_symmetry(mon_lib_srv, ener_lib) exercise_bond_over_symmetry_2(mon_lib_srv, ener_lib) + exercise_add_new_bond_when_long_bond_across_ASU(mon_lib_srv, ener_lib) if (__name__ == "__main__"): exercise() From c3fc892d781ade8750ce485d7be713599bda9998 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 4 Jun 2024 14:19:18 -0700 Subject: [PATCH 507/748] Remove unused keyword/parameter. Slightly better warning. --- mmtbx/secondary_structure/nucleic_acids.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/mmtbx/secondary_structure/nucleic_acids.py b/mmtbx/secondary_structure/nucleic_acids.py index 77dcf3457b..68311d26bc 100644 --- a/mmtbx/secondary_structure/nucleic_acids.py +++ b/mmtbx/secondary_structure/nucleic_acids.py @@ -20,13 +20,6 @@ .short_caption = Distance cutoff for hydrogen bonds .help = Hydrogen bonds with length exceeding this limit will not be \ established -angle_between_bond_and_nucleobase_cutoff = 35.0 - .type = float - .short_caption = Angle between bond and nucleobase cutoff for \ - hydrogen bonds - .help = If angle between supposed hydrogen bond and \ - basepair plane (defined by C4, C5, C6 atoms) is less than this \ - value (in degrees), the bond will not be established. scale_bonds_sigma = 1. .type = float .short_caption = Scale h-bond sigma @@ -420,7 +413,7 @@ def print_warning_msg(rn): # print resname # print r.resname # print new_res.resname.strip() - print("Warning, Cannot make NA restraints for %s residue" % resname) + print("Warning, Cannot make NA restraints for %s residue (no planarity definition)" % rn) i_seqs = [] result = [] r1_i_seqs = {} From 5f6c169e8bd82759a6acb68c73202c507e14cd3a Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 5 Jun 2024 11:08:15 -0700 Subject: [PATCH 508/748] libtbx: add debug info for Windows compilers --- libtbx/SConscript | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libtbx/SConscript b/libtbx/SConscript index db4a5c42ba..3fd8ce6319 100644 --- a/libtbx/SConscript +++ b/libtbx/SConscript @@ -375,7 +375,9 @@ Unknown or unsupported cl.exe version. Minimum version is 7.1 (Visual Studio 2003). For newer versions, please adjust this SConscript. -""") + +%s +""" % cl_info) print("MSVC_VERSION:", env_base["MSVC_VERSION"]) env_base.Replace( SHCC="cl", From f73e102ec3dbfdf7ab62a50ea07ffd527fc17073 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 5 Jun 2024 11:39:13 -0700 Subject: [PATCH 509/748] libtbx: add support for VS 2022 v17.10 --- libtbx/SConscript | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libtbx/SConscript b/libtbx/SConscript index 3fd8ce6319..b64decdf1a 100644 --- a/libtbx/SConscript +++ b/libtbx/SConscript @@ -369,6 +369,11 @@ if (sys.platform == "win32" or ENV=os.environ, MSVC_VERSION="14.3", TARGET_ARCH=target_arch, tools=['msvc','mslink', 'mslib']) env_etc.have_manifest_tool = True env_etc.msvc_version = 17 + elif visual_studio_version.startswith("19.4"): + env_base = Environment( + ENV=os.environ, MSVC_VERSION="14.4", TARGET_ARCH=target_arch, tools=['msvc','mslink', 'mslib']) + env_etc.have_manifest_tool = True + env_etc.msvc_version = 17 else: raise RuntimeError("""\ Unknown or unsupported cl.exe version. From b88f7d7b96d9ca780207fb2b721d65222f695144 Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 6 Jun 2024 12:20:34 -0700 Subject: [PATCH 510/748] Supply hierarchy to model manager in as_model_manager unless crystal_symmetry is missing --- iotbx/pdb/hierarchy.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index 6659e01f59..c98c2d8098 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -993,11 +993,18 @@ def as_model_manager(self, crystal_symmetry, unit_cell_crystal_symmetry = None, shift_cart = None): ''' Returns simple version of model object based on this hierarchy - Requires crystal_symmetry. Optional unit_cell_crystal_symmetry and - shift_cart + Expects but does not require crystal_symmetry. + Optional unit_cell_crystal_symmetry and shift_cart. ''' import mmtbx.model - mm = mmtbx.model.manager( + if crystal_symmetry: # usual + mm = mmtbx.model.manager( + model_input = None, # REQUIRED + pdb_hierarchy = self, + crystal_symmetry = crystal_symmetry, + ) + else: # usual, make a deep_copy and supply as_pdb_input: + mm = mmtbx.model.manager( model_input = self.deep_copy().as_pdb_input(), crystal_symmetry = crystal_symmetry, ) From 51c23a20248f993a5a964334fe86c19915c19cc8 Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 6 Jun 2024 12:23:57 -0700 Subject: [PATCH 511/748] Remove as_pdb_input --- mmtbx/building/merge_models.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/mmtbx/building/merge_models.py b/mmtbx/building/merge_models.py index 2f7a2b04e4..a83bd47e3d 100644 --- a/mmtbx/building/merge_models.py +++ b/mmtbx/building/merge_models.py @@ -498,10 +498,9 @@ def get_cc_dict(hierarchy=None,crystal_symmetry=None, asc=hierarchy.atom_selection_cache() sel=asc.selection(string = atom_selection) sel_hierarchy=hierarchy.select(sel) - pdb_inp=sel_hierarchy.as_pdb_input(crystal_symmetry=crystal_symmetry) - ph=pdb_inp.construct_hierarchy() - - xrs = pdb_inp.xray_structure_simple(crystal_symmetry=crystal_symmetry) + sel_hierarchy.atoms().reset_i_seq() + xrs = sel_hierarchy.extract_xray_structure( + crystal_symmetry=crystal_symmetry) xrs.scattering_type_registry(table = table) cc_calculator=mmtbx.maps.correlation.from_map_and_xray_structure_or_fmodel( @@ -509,7 +508,7 @@ def get_cc_dict(hierarchy=None,crystal_symmetry=None, map_data = map_data, d_min = d_min) - for m in ph.models(): + for m in sel_hierarchy.models(): for chain in m.chains(): cc_list=flex.double() cc_dict[model.id]=cc_list @@ -651,7 +650,6 @@ def run( if n_models==1: # nothing to do return hierarchy - #xrs = pdb_inp.xray_structure_simple(crystal_symmetry=crystal_symmetry) xrs = hierarchy.extract_xray_structure(crystal_symmetry=crystal_symmetry) xrs.scattering_type_registry(table=scattering_table) if not resolution: @@ -696,8 +694,8 @@ def run( asc=hierarchy.atom_selection_cache() sel=asc.selection(string = atom_selection) sel_hierarchy=hierarchy.select(sel) - pdb_inp=sel_hierarchy.as_pdb_input(crystal_symmetry=crystal_symmetry) - ph=pdb_inp.construct_hierarchy() + sel_hierarchy.atoms().reset_i_seq() + ph=sel_hierarchy print("\nWorking on chain_id='%s' resseq %d:%d\n" %( chain_id_and_resseq[0],chain_id_and_resseq[1][0],chain_id_and_resseq[1][1]), file=out) @@ -823,7 +821,6 @@ def run( from iotbx.pdb.utils import add_hierarchies pdb_hierarchy = remove_ter_or_break(add_hierarchies(sel_ph_list, create_new_chain_ids_if_necessary = False)) - print(pdb_hierarchy.as_pdb_string()) if pdb_out: pdb_out = pdb_hierarchy.write_pdb_or_mmcif_file(target_filename = pdb_out, From df59536ad9b9b3f5a6323bfb0e2dcf5b6ae606b3 Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 6 Jun 2024 13:37:55 -0600 Subject: [PATCH 512/748] Remove as_pdb_input --- mmtbx/command_line/map_box.py | 5 +---- mmtbx/command_line/validation_summary.py | 8 +++----- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/mmtbx/command_line/map_box.py b/mmtbx/command_line/map_box.py index f71b11a405..7d295c5a0d 100644 --- a/mmtbx/command_line/map_box.py +++ b/mmtbx/command_line/map_box.py @@ -406,10 +406,7 @@ def get_model_from_inputs( print_statistics.make_sub_header("pdb model", out = log) if pdb_hierarchy: # convert to model object . XXX should come in this way - model = mmtbx.model.manager( - model_input = pdb_hierarchy.as_pdb_input(), - crystal_symmetry = crystal_symmetry, - log = log) + model = pdb_hierarchy.as_model_manager(crystal_symmetry = crystal_symmetry) if len(file_names)>0: file_name = file_names[0] diff --git a/mmtbx/command_line/validation_summary.py b/mmtbx/command_line/validation_summary.py index cae1eddc4c..e000be1e54 100644 --- a/mmtbx/command_line/validation_summary.py +++ b/mmtbx/command_line/validation_summary.py @@ -30,15 +30,13 @@ def summary(pdb_file=None, else : assert (pdb_file is None) # + assert crystal_symmetry is not None + cache = pdb_hierarchy.atom_selection_cache() sel = cache.selection('protein') pdb_hierarchy = pdb_hierarchy.select(sel) # - model = mmtbx.model.manager(model_input = pdb_hierarchy.as_pdb_input()) - if crystal_symmetry and model.crystal_symmetry() is None: - model.set_crystal_symmetry(crystal_symmetry) # Somehow pdb_hiearchy lacks cs - if not model.crystal_symmetry(): - aaa=bbb + model = pdb_hierarchy.as_model_manager(crystal_symmetry = crystal_symmetry) return molprobity.molprobity( model=model, keep_hydrogens=False, From 34d8c91df39d70be174c768384951ed29d1177e0 Mon Sep 17 00:00:00 2001 From: terwill Date: Fri, 7 Jun 2024 07:20:52 -0700 Subject: [PATCH 513/748] Remove as_pdb_input --- iotbx/map_model_manager.py | 10 ++++------ mmtbx/building/minimize_chain.py | 5 +++-- mmtbx/regression/tst_minimize_chain.py | 7 +++---- mmtbx/regression/tst_minimize_chain_cif.py | 9 +++++---- mmtbx/regression/tst_process_predicted_model.py | 7 ++++--- mmtbx/secondary_structure/find_ss_from_ca.py | 4 +++- 6 files changed, 22 insertions(+), 20 deletions(-) diff --git a/iotbx/map_model_manager.py b/iotbx/map_model_manager.py index 0d191e0ddc..4f3310ff57 100644 --- a/iotbx/map_model_manager.py +++ b/iotbx/map_model_manager.py @@ -8169,17 +8169,15 @@ def model_from_text(self, def model_from_hierarchy(self, hierarchy, return_as_model = False, - model_id = 'model_from_hierarchy'): + model_id = 'model_from_hierarchy', + use_pdb_input = False): ''' Convenience method to convert a hierarchy into a model, where the model has symmetry and shift cart matching this manager ''' + model = hierarchy.as_model_manager( + crystal_symmetry = self.crystal_symmetry()) - from mmtbx.model import manager as model_manager - model = model_manager( - model_input = hierarchy.as_pdb_input(), - crystal_symmetry = self.crystal_symmetry(), - log = null_out()) self.set_model_symmetries_and_shift_cart_to_match_map(model) if return_as_model: return model diff --git a/mmtbx/building/minimize_chain.py b/mmtbx/building/minimize_chain.py index b75e85bf12..5587bd83eb 100644 --- a/mmtbx/building/minimize_chain.py +++ b/mmtbx/building/minimize_chain.py @@ -164,8 +164,9 @@ def get_map_coeffs( reflection_file=reflection_file_reader.any_reflection_file(map_coeffs_file) miller_arrays=reflection_file.as_miller_arrays() for ma in miller_arrays: - if not ma.is_complex_array: continue - if not map_coeffs_labels or map_coeffs_labels==ma.info().labels[0]: + if not ma.is_complex_array(): continue + if (not map_coeffs_labels) or map_coeffs_labels==ma.info().labels[0] or \ + map_coeffs_labels == ",".join(ma.info().labels): return ma raise Sorry("Unable to find map coeffs in the file %s with labels %s" %( map_coeffs_file,str(map_coeffs_labels))) diff --git a/mmtbx/regression/tst_minimize_chain.py b/mmtbx/regression/tst_minimize_chain.py index b94ac53b70..d7d54ba270 100644 --- a/mmtbx/regression/tst_minimize_chain.py +++ b/mmtbx/regression/tst_minimize_chain.py @@ -574,8 +574,7 @@ def tst_01(): dist_max=100, verbose=True) - pdb_inp=hierarchy.as_pdb_input(crystal_symmetry=fc.crystal_symmetry()) - xrs=pdb_inp.xray_structure_simple() + xrs=hierarchy.extract_xray_structure(crystal_symmetry=fc.crystal_symmetry()) hierarchy.write_pdb_file(file_name="%s_refined.pdb"%prefix) rmsd=xrs.sites_cart().rms_difference(xrs_answer_full.sites_cart()) print("RMSD from TARGET allowing any CROSSOVERS: %8.2f " %(rmsd)) @@ -620,8 +619,8 @@ def tst_02(args,prefix=None): crystal_symmetry=fc.crystal_symmetry(), pdb_string=pdb_str_poor_full) - pdb_inp=hierarchy.as_pdb_input(crystal_symmetry=fc.crystal_symmetry()) - xrs_refined=pdb_inp.xray_structure_simple() + xrs_refined=hierarchy.extract_xray_structure( + crystal_symmetry=fc.crystal_symmetry()) hierarchy.write_pdb_file(file_name="%s_refined.pdb"%prefix) multiple_model_hierarchy.write_pdb_file( file_name="%s_refined_all_states.pdb"%prefix) diff --git a/mmtbx/regression/tst_minimize_chain_cif.py b/mmtbx/regression/tst_minimize_chain_cif.py index b91e18e074..26fa9a776c 100644 --- a/mmtbx/regression/tst_minimize_chain_cif.py +++ b/mmtbx/regression/tst_minimize_chain_cif.py @@ -582,8 +582,9 @@ def tst_01(): dist_max=100, verbose=True) - pdb_inp=hierarchy.as_pdb_input(crystal_symmetry=fc.crystal_symmetry()) - xrs=pdb_inp.xray_structure_simple() + xrs=hierarchy.extract_xray_structure( + crystal_symmetry=fc.crystal_symmetry()) + refined_ph=pdb_inp.construct_hierarchy() fn = refined_ph.write_pdb_or_mmcif_file( target_filename = "%s_refined.cif"%prefix, @@ -635,8 +636,8 @@ def tst_02(args,prefix=None): crystal_symmetry=fc.crystal_symmetry(), pdb_string=pdb_str_poor_full) - pdb_inp=hierarchy.as_pdb_input(crystal_symmetry=fc.crystal_symmetry()) - xrs_refined=pdb_inp.xray_structure_simple() + xrs_refined=hierarchy.extract_xray_structure( + crystal_symmetry=fc.crystal_symmetry()) fn = hierarchy.write_pdb_or_mmcif_file( target_filename = "%s_refined.cif"%prefix, crystal_symmetry = pdb_inp.crystal_symmetry()) diff --git a/mmtbx/regression/tst_process_predicted_model.py b/mmtbx/regression/tst_process_predicted_model.py index 4f4f554c9b..9f8198a28b 100644 --- a/mmtbx/regression/tst_process_predicted_model.py +++ b/mmtbx/regression/tst_process_predicted_model.py @@ -175,7 +175,7 @@ def tst_01(log = sys.stdout): chainid_list = model_info.chainid_list print("Segments found: %s" %(" ".join(chainid_list)), file = log) - assert len(chainid_list) == 2 + assert len(chainid_list) == 1 # Check processing and splitting model into domains, adjusting domain size automatically print("\nProcessing and splitting model into domains", file = log) @@ -225,13 +225,13 @@ def tst_01(log = sys.stdout): chainid_list = model_info.chainid_list print("Segments found: %s" %(" ".join(chainid_list)), file = log) - assert len(chainid_list) == 2 + assert len(chainid_list) == 1 mmm = model_info.model.as_map_model_manager() mmm.write_model('model_with_groupings.pdb') residue_count = [] - expected_residue_count = [84, 88] + expected_residue_count = [172] for chainid in chainid_list: selection_string = "chain %s" %(chainid) ph = model_info.model.get_hierarchy() @@ -243,6 +243,7 @@ def tst_01(log = sys.stdout): selection_string, n), file = log) residue_count.append(n) + print(expected_residue_count,residue_count) assert expected_residue_count == residue_count # Now process and use pae model and pae model file diff --git a/mmtbx/secondary_structure/find_ss_from_ca.py b/mmtbx/secondary_structure/find_ss_from_ca.py index 32c7c0a153..99f2b1795f 100644 --- a/mmtbx/secondary_structure/find_ss_from_ca.py +++ b/mmtbx/secondary_structure/find_ss_from_ca.py @@ -1754,7 +1754,9 @@ def apply_lsq_fit(self,lsq_fit_obj=None,hierarchy=None, xyz = new_ph.atoms().extract_xyz() new_xyz = lsq_fit_obj.r.elems * xyz + lsq_fit_obj.t.elems new_ph.atoms().set_xyz(new_xyz) - return new_ph.as_pdb_input().construct_hierarchy() # XXX seems to reformat + new_ph.sort_atoms_in_place() + new_ph.atoms().reset_i_seq() + return new_ph def get_site(self,resno=None): first_residue=self.get_start_resno() From a2dd8f3e7019cd58fc2cd99d65b9d042fb68c582 Mon Sep 17 00:00:00 2001 From: terwill Date: Fri, 7 Jun 2024 10:13:56 -0700 Subject: [PATCH 514/748] Add notes that using as_pdb_input changes model very slightly due to rounding --- iotbx/pdb/hierarchy.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index c98c2d8098..458ce44463 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -962,6 +962,8 @@ def as_pdb_input(self, crystal_symmetry=None, segid_as_auth_segid = True): """ Generate corresponding pdb.input object. + Note that this uses a text representation of the hierarchy so that + values for xyz, occ, b, and crystal_symmetry are all rounded. """ import iotbx.pdb if self.fits_in_pdb_format(): @@ -995,6 +997,10 @@ def as_model_manager(self, crystal_symmetry, ''' Returns simple version of model object based on this hierarchy Expects but does not require crystal_symmetry. Optional unit_cell_crystal_symmetry and shift_cart. + + Note that if crystal_symmetry is not supplied, + this uses a text representation of the hierarchy so that + values for xyz, occ, b, and crystal_symmetry are all rounded. ''' import mmtbx.model if crystal_symmetry: # usual From 117d8d2f82107300f9935cd2ef42122710ffb2f3 Mon Sep 17 00:00:00 2001 From: terwill Date: Fri, 7 Jun 2024 13:27:34 -0700 Subject: [PATCH 515/748] Remove as_pdb_input() --- cctbx/maptbx/refine_sharpening.py | 6 +- cctbx/maptbx/segment_and_split_map.py | 92 +++++++++++++-------------- 2 files changed, 47 insertions(+), 51 deletions(-) diff --git a/cctbx/maptbx/refine_sharpening.py b/cctbx/maptbx/refine_sharpening.py index 78ce4eb1b5..6bdbbdc131 100644 --- a/cctbx/maptbx/refine_sharpening.py +++ b/cctbx/maptbx/refine_sharpening.py @@ -184,7 +184,7 @@ def adjust_amplitudes_linear(f_array,b1,b2,b3,resolution=None, data_array=data_array*scale_array return f_array.customized_copy(data=data_array) -def get_model_map_coeffs_normalized(pdb_inp=None, +def get_model_map_coeffs_normalized(pdb_hierarchy=None, si=None, f_array=None, overall_b=None, @@ -193,7 +193,7 @@ def get_model_map_coeffs_normalized(pdb_inp=None, target_b_iso_model_scale=0, target_b_iso_ratio = 5.9, # empirical, see params for segment_and_split_map out=sys.stdout): - if not pdb_inp: return None + if not pdb_hierarchy: return None if not si: from cctbx.maptbx.segment_and_split_map import sharpening_info si=sharpening_info(resolution=resolution, @@ -212,7 +212,7 @@ def get_model_map_coeffs_normalized(pdb_inp=None, from cctbx.maptbx.segment_and_split_map import get_f_phases_from_model try: model_map_coeffs=get_f_phases_from_model( - pdb_inp=pdb_inp, + pdb_hierarchy=pdb_hierarchy, f_array=f_array, overall_b=overall_b, k_sol=si.k_sol, diff --git a/cctbx/maptbx/segment_and_split_map.py b/cctbx/maptbx/segment_and_split_map.py index 6efe57d0d3..8b85745b50 100644 --- a/cctbx/maptbx/segment_and_split_map.py +++ b/cctbx/maptbx/segment_and_split_map.py @@ -1956,7 +1956,7 @@ def __init__(self, d_min_list = None, verbose = None, resolve_size = None, - pdb_inp = None, # XXX probably do not need this + pdb_inp = None, # XXX probably do not need this, just used to set params local_solvent_fraction = None, wang_radius = None, buffer_radius = None, @@ -1969,7 +1969,6 @@ def __init__(self, adopt_init_args(self, locals()) del self.tracking_data # don't need it as part of the object del self.box_sharpening_info_obj# don't need it as part of the object - del self.pdb_inp # don't need it as part of the object if tracking_data: # use tracking data information self.update_with_tracking_data(tracking_data = tracking_data) @@ -2688,9 +2687,10 @@ def map_coeffs_to_fp(map_coeffs): assert amplitudes.is_real_array() return amplitudes -def get_f_phases_from_model(f_array = None, pdb_inp = None, overall_b = None, +def get_f_phases_from_model(f_array = None, pdb_hierarchy= None, + overall_b = None, k_sol = None, b_sol = None, out = sys.stdout): - xray_structure = pdb_inp.construct_hierarchy().extract_xray_structure( + xray_structure = pdb_hierarchy.extract_xray_structure( crystal_symmetry = f_array.crystal_symmetry()) print("Getting map coeffs from model with %s atoms.." %( xray_structure.sites_frac().size()), file = out) @@ -8439,7 +8439,6 @@ def apply_origin_shift(origin_shift = None, shifted_pdb_file = None, shifted_ncs_file = None, tracking_data = None, - sharpening_target_pdb_inp = None, out = sys.stdout): if shifted_map_file: @@ -8462,13 +8461,6 @@ def apply_origin_shift(origin_shift = None, pdb_hierarchy = pdb_hierarchy, out = out) - if sharpening_target_pdb_inp: - sharpening_target_pdb_inp = apply_shift_to_pdb_hierarchy( - origin_shift = origin_shift, - crystal_symmetry = tracking_data.crystal_symmetry, - pdb_hierarchy = sharpening_target_pdb_inp.construct_hierarchy(), - out = out).as_pdb_input() - if target_hierarchy: target_hierarchy = apply_shift_to_pdb_hierarchy( origin_shift = origin_shift, @@ -8508,7 +8500,7 @@ def apply_origin_shift(origin_shift = None, tracking_data.shifted_ncs_info.show_summary(out = out) return shifted_pdb_file, shifted_ncs_object, pdb_hierarchy, \ - target_hierarchy, tracking_data, sharpening_target_pdb_inp + target_hierarchy, tracking_data def restore_pdb(params, tracking_data = None, out = sys.stdout): if not params.output_files.restored_pdb: @@ -9265,7 +9257,8 @@ def get_solvent_fraction_from_molecular_mass( def set_up_si(var_dict = None, crystal_symmetry = None, is_crystal = None, ncs_copies = None, n_residues = None, - solvent_fraction = None, molecular_mass = None, pdb_inp = None, map = None, + solvent_fraction = None, molecular_mass = None, + pdb_inp = None, map = None, auto_sharpen = True, half_map_data_list = None, verbose = None, out = sys.stdout): si = sharpening_info(n_real = map.all()) @@ -9473,7 +9466,7 @@ def select_box_map_data(si = None, map_data = None, first_half_map_data = None, second_half_map_data = None, - pdb_inp = None, + pdb_hierarchy = None, get_solvent_fraction = True, # XXX test not doing this... n_min = 30, # at least 30 atoms to run model sharpening restrict_map_size = None, @@ -9489,7 +9482,7 @@ def select_box_map_data(si = None, original_box_map_data = None # n_buffer = None - if (not pdb_inp and not si.box_in_auto_sharpen) and ( + if (not pdb_hierarchy and not si.box_in_auto_sharpen) and ( first_half_map_data and second_half_map_data): print("Creating density-based soft mask and applying to half-map data", file = out) @@ -9513,27 +9506,24 @@ def select_box_map_data(si = None, box_first_half_map, box_second_half_map = half_map_data_list box_crystal_symmetry = crystal_symmetry - box_pdb_inp = pdb_inp + box_pdb_hierarchy = None - elif pdb_inp or ( + elif pdb_hierarchy or ( si.density_select_in_auto_sharpen and not si.box_in_auto_sharpen): - # use map_box for pdb_inp (mask with model) + # use map_box for pdb_hierarchy (mask with model) # also use map_box for density_select_in_auto_sharpen sharpening because # need to use the same density select for all 3 maps. - # XXX Perhaps we canuse above method for pdb_inp assert not si.local_sharpening - if pdb_inp: + if pdb_hierarchy: print("Using map_box based on input model", file = out) - hierarchy = pdb_inp.construct_hierarchy() max_box_fraction = si.max_box_fraction si.density_select_in_auto_sharpen = False else: #print >>out, "Using density_select in map_box" - hierarchy = None assert si.density_select_in_auto_sharpen max_box_fraction = si.density_select_max_box_fraction @@ -9603,8 +9593,9 @@ def select_box_map_data(si = None, args.append('restrict_map_size = True') print("Getting map as box now", file = out) local_hierarchy = None - if hierarchy: - local_hierarchy = hierarchy.deep_copy() # run_map_box modifies its argument + if pdb_hierarchy: + local_hierarchy = pdb_hierarchy.deep_copy() + # run_map_box modifies its argument assert isinstance(si.wrapping, bool) # wrapping must be defined box = run_map_box(args, map_data = map_data, pdb_hierarchy = local_hierarchy, @@ -9619,13 +9610,13 @@ def select_box_map_data(si = None, box_map = scale_map(box_map, out = out) box_crystal_symmetry = box.box_crystal_symmetry if box.hierarchy: - box_pdb_inp = box.hierarchy.as_pdb_input() + box_pdb_hierarchy = box.hierarchy else: - box_pdb_inp = None + box_pdb_hierarchy = None if first_half_map_data: print("Getting first map as box", file = out) - if hierarchy: - local_hierarchy = hierarchy.deep_copy() # required + if pdb_hierarchy: + local_hierarchy = pdb_hierarchy.deep_copy() # required box_first = run_map_box(args, map_data = first_half_map_data, pdb_hierarchy = local_hierarchy, write_output_files = False, @@ -9640,8 +9631,8 @@ def select_box_map_data(si = None, if second_half_map_data: print("Getting second map as box", file = out) - if hierarchy: - local_hierarchy = hierarchy.deep_copy() # required + if pdb_hierarchy: + local_hierarchy = pdb_hierarchy.deep_copy() # required box_second = run_map_box(args, map_data = second_half_map_data, pdb_hierarchy = local_hierarchy, write_output_files = False, @@ -9694,7 +9685,7 @@ def select_box_map_data(si = None, resolution = si.resolution, shift_origin = True, min_point = lower_bounds, max_point = upper_bounds, out = out) - box_pdb_inp = None + box_pdb_hierarchy = None if first_half_map_data: box_first_half_map, box_first_crystal_symmetry, \ @@ -9723,7 +9714,7 @@ def select_box_map_data(si = None, box_second_half_map = None if not box_map or ( - (not pdb_inp and not second_half_map_data) and \ + (not pdb_hierarchy and not second_half_map_data) and \ box_map.size() > si.max_box_fraction* map_data.size()): return None, map_data, first_half_map_data, \ @@ -9755,7 +9746,7 @@ def select_box_map_data(si = None, wrapping = False, crystal_symmetry = box_crystal_symmetry, solvent_fraction = box_solvent_fraction) - return box_pdb_inp, box_map, box_first_half_map, box_second_half_map, \ + return box_pdb_hierarchy, box_map, box_first_half_map, box_second_half_map, \ box_crystal_symmetry, box_sharpening_info_obj, \ smoothed_box_mask_data, original_box_map_data, n_buffer @@ -10792,11 +10783,16 @@ def run_auto_sharpen( smoothed_box_mask_data = None original_box_map_data = None + if pdb_inp: + pdb_hierarchy = pdb_inp.construct_hierarchy() + else: + pdb_hierarchy = None if si.auto_sharpen and ( - si.box_in_auto_sharpen or si.density_select_in_auto_sharpen or pdb_inp): + si.box_in_auto_sharpen or + si.density_select_in_auto_sharpen or pdb_hierarchy): original_box_sharpening_info_obj = deepcopy(si) # should really not be box - box_pdb_inp, box_map_data, box_first_half_map_data, \ + box_pdb_hierarchy, box_map_data, box_first_half_map_data, \ box_second_half_map_data, \ box_crystal_symmetry, box_sharpening_info_obj, \ smoothed_box_mask_data, original_box_map_data, n_buffer = \ @@ -10804,7 +10800,7 @@ def run_auto_sharpen( map_data = map_data, first_half_map_data = first_half_map_data, second_half_map_data = second_half_map_data, - pdb_inp = pdb_inp, + pdb_hierarchy = pdb_hierarchy, restrict_map_size = si.restrict_map_size, out = out, local_out = local_out) @@ -10823,11 +10819,11 @@ def run_auto_sharpen( original_crystal_symmetry = si.crystal_symmetry map_data = box_map_data - pdb_inp = box_pdb_inp - if si.density_select_in_auto_sharpen and ( # catch empty pdb_inp - not pdb_inp or not \ - pdb_inp.construct_hierarchy().overall_counts().n_residues): - pdb_inp = None + pdb_hierarchy = box_pdb_hierarchy + if si.density_select_in_auto_sharpen and ( # catch empty pdb_hierarchy + (not pdb_hierarchy) or (not + pdb_hierarchy.overall_counts().n_residues)): + pdb_hierarchy = None crystal_symmetry = box_crystal_symmetry if box_first_half_map_data: @@ -10887,16 +10883,17 @@ def run_auto_sharpen( else: second_half_map_coeffs = None - if pdb_inp: - # Getting model information if pdb_inp present --------------------------- + if pdb_hierarchy: + # Getting model information if pdb_hierarchy present ------------------- from cctbx.maptbx.refine_sharpening import get_model_map_coeffs_normalized - model_map_coeffs = get_model_map_coeffs_normalized(pdb_inp = pdb_inp, + model_map_coeffs = get_model_map_coeffs_normalized( + pdb_hierarchy = pdb_hierarchy, si = si, f_array = f_array, resolution = si.resolution, out = out) if not model_map_coeffs: # give up - pdb_inp = None + pdb_hierarchy = None if si.is_model_sharpening(): raise Sorry("Cannot carry out model sharpening without a model."+ " It could be that the model was outside the map") @@ -11841,7 +11838,7 @@ def run(args, else: shifted_pdb_file = None shifted_pdb_file, ncs_obj, pdb_hierarchy, target_hierarchy, \ - tracking_data, sharpening_target_pdb_inp = apply_origin_shift( + tracking_data= apply_origin_shift( shifted_map_file = shifted_map_file, shifted_pdb_file = shifted_pdb_file, shifted_ncs_file = shifted_ncs_file, @@ -11851,7 +11848,6 @@ def run(args, target_hierarchy = target_hierarchy, map_data = map_data, tracking_data = tracking_data, - sharpening_target_pdb_inp = sharpening_target_pdb_inp, out = out) if shifted_pdb_file: params.output_files.shifted_pdb_file = os.path.split(shifted_pdb_file)[-1] From 6b87fc000263f7479a6508a0e884d7a50b09209a Mon Sep 17 00:00:00 2001 From: Daniel Tchon Date: Fri, 7 Jun 2024 14:06:19 -0700 Subject: [PATCH 516/748] Fix `count_each`'s log all expt/img/refl counts when `verbose` --- xfel/merging/application/utils/data_counter.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/xfel/merging/application/utils/data_counter.py b/xfel/merging/application/utils/data_counter.py index 56016609d9..791efe9073 100644 --- a/xfel/merging/application/utils/data_counter.py +++ b/xfel/merging/application/utils/data_counter.py @@ -1,4 +1,6 @@ from __future__ import absolute_import, division, print_function +from math import log10 + class data_counter(object): def __init__(self, params, mpi_helper=None, mpi_logger=None): @@ -18,7 +20,6 @@ def count_each(self, experiments, reflections, verbose=False): # MPI-gather individual counts comm = self.mpi_helper.comm - MPI = self.mpi_helper.MPI # count experiments and reflections experiment_count = len(experiments) if experiments != None else 0 @@ -36,9 +37,11 @@ def count_each(self, experiments, reflections, verbose=False): # rank 0: log data statistics if self.mpi_helper.rank == 0 and verbose: - self.logger.main_log('Experiments by rank: ' + ', '.join(experiment_count_list)) - self.logger.main_log('Images by rank: ' + ', '.join(image_count_list)) - self.logger.main_log('Reflections by rank: ' + ', '.join(reflection_count_list)) + max_count = int(log10(max(*image_count_list, *reflection_count_list))) + count_fmt = '%' + str(max_count + 1) + 'd' + self.logger.main_log('Experiments by rank: ' + ', '.join([count_fmt % i for i in experiment_count_list])) + self.logger.main_log('Images by rank: ' + ', '.join([count_fmt % i for i in image_count_list])) + self.logger.main_log('Reflections by rank: ' + ', '.join([count_fmt % i for i in reflection_count_list])) self.logger.log_step_time("CALC_LOAD_STATISTICS", True) From 851206e6a524deed554e4b12d4270b73da9c6db8 Mon Sep 17 00:00:00 2001 From: terwill Date: Fri, 7 Jun 2024 14:55:27 -0700 Subject: [PATCH 517/748] Remove as_pdb_input --- cctbx/maptbx/auto_sharpen.py | 39 ++++++++++---------- cctbx/maptbx/segment_and_split_map.py | 53 +++++++++++++-------------- 2 files changed, 45 insertions(+), 47 deletions(-) diff --git a/cctbx/maptbx/auto_sharpen.py b/cctbx/maptbx/auto_sharpen.py index 54fc7b19f1..b98a0ed397 100644 --- a/cctbx/maptbx/auto_sharpen.py +++ b/cctbx/maptbx/auto_sharpen.py @@ -790,21 +790,20 @@ def get_map_coeffs_from_file( if not map_coeffs_labels or labels==map_coeffs_labels: # take it return ma -def map_inside_cell(pdb_inp,crystal_symmetry=None): - ph=pdb_inp.construct_hierarchy() - pa=ph.atoms() +def map_inside_cell(pdb_hierarchy,crystal_symmetry=None): + pa=pdb_hierarchy.atoms() sites_cart=pa.extract_xyz() from cctbx.maptbx.segment_and_split_map import move_xyz_inside_cell new_sites_cart=move_xyz_inside_cell(xyz_cart=sites_cart, crystal_symmetry=crystal_symmetry) pa.set_xyz(new_sites_cart) - return ph.as_pdb_input() + return pdb_hierarchy def get_map_and_model(params=None, map_data=None, crystal_symmetry=None, - pdb_inp=None, + pdb_hierarchy=None, ncs_obj=None, half_map_data_list=None, map_coords_inside_cell=True, @@ -924,27 +923,27 @@ def get_map_and_model(params=None, "poor at %7.0f A" %(params.crystal_info.resolution), file=out) - if params.input_files.pdb_file and not pdb_inp: # get model + if params.input_files.pdb_file and not pdb_hierarchy: # get model model_file=params.input_files.pdb_file if not os.path.isfile(model_file): raise Sorry("Missing the model file: %s" %(model_file)) - from iotbx.pdb.utils import get_pdb_input - pdb_inp = get_pdb_input(file_name = model_file) - if pdb_inp: # XXX added 2019-05-05 + from iotbx.pdb.utils import get_pdb_hierarchy + pdb_hierarchy= get_pdb_hierarchy(file_name = model_file) + if pdb_hierarchy: # XXX added 2019-05-05 if origin_frac != (0,0,0): print("Shifting model by %s" %(str(origin_frac)), file=out) from cctbx.maptbx.segment_and_split_map import \ apply_shift_to_pdb_hierarchy origin_shift=crystal_symmetry.unit_cell().orthogonalize( (-origin_frac[0],-origin_frac[1],-origin_frac[2])) - pdb_inp=apply_shift_to_pdb_hierarchy( + pdb_hierarchy=apply_shift_to_pdb_hierarchy( origin_shift=origin_shift, crystal_symmetry=crystal_symmetry, - pdb_hierarchy=pdb_inp.construct_hierarchy(), - out=out).as_pdb_input() + pdb_hierarchy=pdb_hierarchy, + out=out) if map_coords_inside_cell: # put inside (0,1) - pdb_inp=map_inside_cell(pdb_inp,crystal_symmetry=crystal_symmetry) + pdb_hierarchy=map_inside_cell(pdb_hierarchy,crystal_symmetry=crystal_symmetry) if params.input_files.ncs_file and not ncs_obj: # NCS from cctbx.maptbx.segment_and_split_map import get_ncs @@ -958,10 +957,12 @@ def get_map_and_model(params=None, coordinate_offset=matrix.col(origin_shift)) if get_map_labels: - return pdb_inp,map_data,half_map_data_list,ncs_obj,crystal_symmetry,acc,\ + return pdb_hierarchy,\ + map_data,half_map_data_list,ncs_obj,crystal_symmetry,acc,\ original_crystal_symmetry,original_unit_cell_grid,map_labels else: - return pdb_inp,map_data,half_map_data_list,ncs_obj,crystal_symmetry,acc,\ + return pdb_hierarchy,\ + map_data,half_map_data_list,ncs_obj,crystal_symmetry,acc,\ original_crystal_symmetry,original_unit_cell_grid @@ -969,7 +970,7 @@ def run(args=None,params=None, map_data=None,crystal_symmetry=None, wrapping = None, write_output_files=True, - pdb_inp=None, + pdb_hierarchy=None, ncs_obj=None, return_map_data_only=False, return_unshifted_map=False, @@ -986,12 +987,12 @@ def run(args=None,params=None, # get map_data and crystal_symmetry - pdb_inp,map_data,half_map_data_list,ncs_obj,crystal_symmetry,acc,\ + pdb_hierarchy,map_data,half_map_data_list,ncs_obj,crystal_symmetry,acc,\ original_crystal_symmetry,original_unit_cell_grid,map_labels=\ get_map_and_model( map_data=map_data, half_map_data_list=half_map_data_list, - pdb_inp=pdb_inp, + pdb_hierarchy=pdb_hierarchy, ncs_obj=ncs_obj, map_coords_inside_cell=False, crystal_symmetry=crystal_symmetry, @@ -1090,7 +1091,7 @@ def run(args=None,params=None, params.map_modification.resolution_dependent_b, normalize_amplitudes_in_resdep=\ params.map_modification.normalize_amplitudes_in_resdep, - pdb_inp=pdb_inp, + pdb_hierarchy=pdb_hierarchy, ncs_obj=ncs_obj, rmsd=params.map_modification.rmsd, rmsd_resolution_factor=params.map_modification.rmsd_resolution_factor, diff --git a/cctbx/maptbx/segment_and_split_map.py b/cctbx/maptbx/segment_and_split_map.py index 8b85745b50..7aa7621f3a 100644 --- a/cctbx/maptbx/segment_and_split_map.py +++ b/cctbx/maptbx/segment_and_split_map.py @@ -1956,7 +1956,7 @@ def __init__(self, d_min_list = None, verbose = None, resolve_size = None, - pdb_inp = None, # XXX probably do not need this, just used to set params + pdb_hierarchy = None, # XXX just used to set params local_solvent_fraction = None, wang_radius = None, buffer_radius = None, @@ -1989,7 +1989,7 @@ def __init__(self, if self.sharpening_method == 'b_iso' and self.k_sharpen is not None: self.k_sharpen = None - if pdb_inp: + if pdb_hierarchy: self.sharpening_method = 'model_sharpening' self.box_in_auto_sharpen = True self.density_select_in_auto_sharpen = False @@ -2057,7 +2057,7 @@ def update_with_params(self, params = None, solvent_fraction = None, auto_sharpen = None, sharpening_method = None, - pdb_inp = None, + pdb_hierarchy = None, half_map_data_list = None, n_residues = None, ncs_copies = None): self.crystal_symmetry = crystal_symmetry @@ -2177,7 +2177,7 @@ def update_with_params(self, params = None, self.sharpening_method = 'half_map_sharpening' self.sharpening_target = 'half_map' - elif pdb_inp or self.sharpening_method == 'model_sharpening': + elif pdb_hierarchy or self.sharpening_method == 'model_sharpening': self.sharpening_method = 'model_sharpening' self.box_in_auto_sharpen = True self.density_select_in_auto_sharpen = False @@ -4877,7 +4877,7 @@ def check_memory(map_data, ratio_needed, maximum_fraction_to_use = 0.90, def get_params(args, map_data = None, crystal_symmetry = None, half_map_data_list = None, - sharpening_target_pdb_inp = None, + sharpening_target_pdb_hierarchy = None, ncs_object = None, write_files = None, auto_sharpen = None, @@ -5156,7 +5156,7 @@ def get_params(args, map_data = None, crystal_symmetry = None, wrapping = wrapping, crystal_symmetry = crystal_symmetry, write_output_files = False, - pdb_inp = sharpening_target_pdb_inp, + pdb_hierarchy = sharpening_target_pdb_hierarchy, ncs_obj = ncs_obj, return_map_data_only = False, return_unshifted_map = True, @@ -9258,7 +9258,7 @@ def set_up_si(var_dict = None, crystal_symmetry = None, is_crystal = None, ncs_copies = None, n_residues = None, solvent_fraction = None, molecular_mass = None, - pdb_inp = None, map = None, + pdb_hierarchy = None, map = None, auto_sharpen = True, half_map_data_list = None, verbose = None, out = sys.stdout): si = sharpening_info(n_real = map.all()) @@ -9388,7 +9388,7 @@ def set_up_si(var_dict = None, crystal_symmetry = None, n_residues = n_residues, auto_sharpen = auto_sharpen, sharpening_method = sharpening_method, - pdb_inp = pdb_inp, + pdb_hierarchy = pdb_hierarchy, half_map_data_list = half_map_data_list, ) return si @@ -10003,7 +10003,7 @@ def split_boxes(lower = None, upper = None, target_size = None, target_n_overlap return new_lower_upper_list def get_target_boxes(si = None, ncs_obj = None, map = None, - pdb_inp = None, out = sys.stdout): + pdb_hierarchy = None, out = sys.stdout): print(80*"-", file = out) print("Getting segmented map to ID locations for sharpening", file = out) @@ -10048,8 +10048,8 @@ def get_target_boxes(si = None, ncs_obj = None, map = None, centers_frac = flex.vec3_double() upper_bounds_list = [] lower_bounds_list = [] - if pdb_inp and pdb_inp.atoms().extract_xyz().size()>1: - xyz_list = pdb_inp.atoms().extract_xyz() + if pdb_hierarchy and pdb_hierarchy.atoms().extract_xyz().size()>1: + xyz_list = pdb_hierarchy.atoms().extract_xyz() i_end = xyz_list.size() n_centers = min(i_end, max(1, len(tracking_data.output_region_map_info_list))) n_steps = min(n_centers, xyz_list.size()) @@ -10152,7 +10152,7 @@ def run_local_sharpening(si = None, map = None, ncs_obj = None, half_map_data_list = None, - pdb_inp = None, + pdb_hierarchy = None, out = sys.stdout): print(80*"-", file = out) print("Running local sharpening", file = out) @@ -10172,7 +10172,7 @@ def run_local_sharpening(si = None, auto_sharpen_methods = auto_sharpen_methods, map = map, half_map_data_list = half_map_data_list, - pdb_inp = pdb_inp, + pdb_hierarchy = pdb_hierarchy, out = out) sharpened_map = overall_si.map_data print("\nDone sharpening map overall before carrying out local sharpening\n", file = out) @@ -10199,7 +10199,7 @@ def run_local_sharpening(si = None, upper_bounds_list, lower_bounds_list, \ centers_cart_ncs_list, centers_cart, all_cart = \ get_target_boxes(si = si, map = sharpened_map, ncs_obj = ncs_obj, - pdb_inp = pdb_inp, out = out) + pdb_hierarchy = pdb_hierarchy, out = out) dist = mean_dist_to_nearest_neighbor(all_cart) if not dist: @@ -10244,7 +10244,7 @@ def run_local_sharpening(si = None, auto_sharpen_methods = auto_sharpen_methods, map = sharpened_map, half_map_data_list = half_map_data_list, - pdb_inp = pdb_inp, + pdb_hierarchy = pdb_hierarchy, return_bsi = True, # just return the bsi of sharpened data out = out) @@ -10325,7 +10325,7 @@ def auto_sharpen_map_or_map_coeffs( half_map_data_list = None, # two half-maps matching map is_crystal = None, map_coeffs = None, - pdb_inp = None, + pdb_hierarchy = None, ncs_obj = None, seq_file = None, sequence = None, @@ -10456,7 +10456,7 @@ def auto_sharpen_map_or_map_coeffs( if half_map_data_list and len(half_map_data_list) == 2: if auto_sharpen_methods != ['external_map_sharpening']: auto_sharpen_methods = ['half_map_sharpening'] - elif pdb_inp: + elif pdb_hierarchy: auto_sharpen_methods = ['model_sharpening'] if not si: # Copy parameters to si (sharpening_info_object) @@ -10469,7 +10469,7 @@ def auto_sharpen_map_or_map_coeffs( map = map, verbose = verbose, half_map_data_list = half_map_data_list, - pdb_inp = pdb_inp, + pdb_hierarchy = pdb_hierarchy, ncs_copies = ncs_copies, n_residues = n_residues, out = out) if wrapping is not None: @@ -10506,7 +10506,7 @@ def auto_sharpen_map_or_map_coeffs( map = map, ncs_obj = ncs_obj, half_map_data_list = half_map_data_list, - pdb_inp = pdb_inp, + pdb_hierarchy = pdb_hierarchy, out = out) # Get preliminary values of sharpening @@ -10523,7 +10523,7 @@ def auto_sharpen_map_or_map_coeffs( auto_sharpen_methods = auto_sharpen_methods, map = map, half_map_data_list = half_map_data_list, - pdb_inp = pdb_inp, + pdb_hierarchy = pdb_hierarchy, out = out) working_map = overall_si.map_data # Get solvent content again @@ -10555,7 +10555,7 @@ def auto_sharpen_map_or_map_coeffs( map_data = working_map, first_half_map_data = first_half_map_data, second_half_map_data = second_half_map_data, - pdb_inp = pdb_inp, + pdb_hierarchy = pdb_hierarchy, auto_sharpen_methods = auto_sharpen_methods, print_result = False, return_bsi = return_bsi, @@ -10763,7 +10763,7 @@ def run_auto_sharpen( map_data = None, first_half_map_data = None, second_half_map_data = None, - pdb_inp = None, + pdb_hierarchy = None, auto_sharpen_methods = None, print_result = True, return_bsi = False, @@ -10783,10 +10783,6 @@ def run_auto_sharpen( smoothed_box_mask_data = None original_box_map_data = None - if pdb_inp: - pdb_hierarchy = pdb_inp.construct_hierarchy() - else: - pdb_hierarchy = None if si.auto_sharpen and ( si.box_in_auto_sharpen or si.density_select_in_auto_sharpen or pdb_hierarchy): @@ -11749,7 +11745,7 @@ def run(args, target_xyz = None, target_hierarchy = None, target_model = None, - sharpening_target_pdb_inp = None, + sharpening_target_pdb_hierarchy = None, wrapping = None, target_ncs_au_file = None, regions_to_keep = None, @@ -11791,7 +11787,8 @@ def run(args, box_buffer = box_buffer, soft_mask_extract_unique = soft_mask_extract_unique, mask_expand_ratio = mask_expand_ratio, - sharpening_target_pdb_inp = sharpening_target_pdb_inp, out = out) + sharpening_target_pdb_hierarchy = sharpening_target_pdb_hierarchy, + out = out) if params.control.shift_only: return map_data, ncs_obj, tracking_data elif params.control.check_ncs or \ From ac333a41f34d210d106d70340608f4ee11ae69d4 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Fri, 7 Jun 2024 14:54:25 -0700 Subject: [PATCH 518/748] More comprehensive test/illustration of corner-case altloc handling --- iotbx/regression/tst_hierarchy_altlocs.py | 107 +++++++++++++++++++--- 1 file changed, 94 insertions(+), 13 deletions(-) diff --git a/iotbx/regression/tst_hierarchy_altlocs.py b/iotbx/regression/tst_hierarchy_altlocs.py index b3b3073e8e..8f5e0ff323 100644 --- a/iotbx/regression/tst_hierarchy_altlocs.py +++ b/iotbx/regression/tst_hierarchy_altlocs.py @@ -1,5 +1,7 @@ from __future__ import absolute_import, division, print_function import iotbx.pdb +from six.moves import cStringIO as StringIO +from libtbx.test_utils import show_diff pdb_str1 = """ ATOM 1 N AVAL A 1 -4.898 0.072 13.387 0.49 7.34 N @@ -34,25 +36,104 @@ END """ -def get_h(s): - return iotbx.pdb.input(source_info=None, lines=s).construct_hierarchy() +pdb_str4 = """ +ATOM 1 N ALA A 1 -4.898 0.072 13.387 0.49 7.34 N +ATOM 2 CA ALA A 1 -4.626 0.703 12.080 0.49 7.71 C +ATOM 3 C ALA A 1 -3.475 1.680 12.227 0.49 7.52 C +ATOM 4 O ALA A 1 -3.125 2.100 13.335 0.49 7.59 O +ATOM 5 CB ALA A 1 -5.882 1.390 11.495 0.49 7.79 C +ATOM 5 CB AALA A 1 -5.882 1.390 11.495 0.49 7.79 C +""" -def run(): - # - # This is current state of affairs. This was also the case in - # Phenix 1.20 and 1.18. - # - altlocs = [ag.altloc for ag in get_h(pdb_str1).only_model().atom_groups()] +def get_h_oc(s): + h = iotbx.pdb.input(source_info=None, lines=s).construct_hierarchy() + oc = h.overall_counts() + return h, oc + +# +# This is current state of affairs. This was also the case in +# Phenix 1.20 and 1.18. +# + +def tst1(): + """Everything is good here, empty altloc as expected. + """ + h, oc = get_h_oc(pdb_str1) + altlocs = [ag.altloc for ag in h.only_model().atom_groups()] assert altlocs == ['A', '', 'B'], altlocs + assert oc.n_alt_conf_improper == 0, oc.n_alt_conf_improper + assert oc.duplicate_atom_labels == [], list(oc.duplicate_atom_labels) # - print("------------") - altlocs = [ag.altloc for ag in get_h(pdb_str2).only_model().atom_groups()] + +def tst2(): + """There's duplicated atom - HOH without altloc. It gets whitespace: ' ', + but overall_counts has several warnings. + """ + h, oc = get_h_oc(pdb_str2) + altlocs = [ag.altloc for ag in h.only_model().atom_groups()] assert altlocs == [' ', 'A', 'C'], altlocs + # for a in h.atoms(): + # print("%s '%s'" % (a.id_str(), a.parent().altloc)) - print("------------") - altlocs = [ag.altloc for ag in get_h(pdb_str3).only_model().atom_groups()] + # Things that let one know about improper alt conf: + assert oc.n_alt_conf_improper == 1, oc.n_alt_conf_improper + assert len(oc.duplicate_atom_labels) == 1, list(oc.duplicate_atom_labels) + + duplicate_output = StringIO() + oc.show_duplicate_atom_labels(out=duplicate_output) + do_value = duplicate_output.getvalue() + assert not show_diff(do_value, """\ +number of groups of duplicate atom labels: 1 + total number of affected atoms: 2 + group "HETA .*. O HOH S 179 .*. O " + "HETA .*. O HOH S 179 .*. H " +""") + +def tst3(): + """ This is a simple case of duplicated atom labels: + no n_alt_conf_improper + """ + h, oc = get_h_oc(pdb_str3) + altlocs = [ag.altloc for ag in h.only_model().atom_groups()] assert altlocs == [''], altlocs + assert oc.n_alt_conf_improper == 0, oc.n_alt_conf_improper + assert len(oc.duplicate_atom_labels) == 1, list(oc.duplicate_atom_labels) + + duplicate_output = StringIO() + oc.show_duplicate_atom_labels(out=duplicate_output) + do_value = duplicate_output.getvalue() + assert not show_diff(do_value, """\ +number of groups of duplicate atom labels: 1 + total number of affected atoms: 4 + group "HETA .*. O HOH S 179 .*. O " + "HETA .*. O HOH S 179 .*. O " + "HETA .*. O HOH S 179 .*. H " + "HETA .*. O HOH S 179 .*. H " +""") + +def tst4(): + """This is pure case where only n_alt_conf_improper shows problem, + but no duplicated atom labels. + """ + # Here we have a residue with one atom duplicated out of several. + # CB atoms get ' ' and 'A' altlocs, while the rest get ''. + h, oc = get_h_oc(pdb_str4) + altlocs = [ag.altloc for ag in h.only_model().atom_groups()] + # for a in h.atoms(): + # print("%s '%s'" % (a.id_str(), a.parent().altloc)) + assert altlocs == ['', ' ', 'A'], altlocs + assert oc.n_alt_conf_improper == 1, oc.n_alt_conf_improper + assert len(oc.duplicate_atom_labels) == 0, list(oc.duplicate_atom_labels) + + duplicate_output = StringIO() + oc.show_duplicate_atom_labels(out=duplicate_output) + do_value = duplicate_output.getvalue() + assert not show_diff(do_value, "") + if (__name__ == "__main__"): - run() + tst1() + tst2() + tst3() + tst4() print("OK") From 8160f6b4fb1e4808837b751a3a6ff2248636cd45 Mon Sep 17 00:00:00 2001 From: Daniel Tchon Date: Fri, 7 Jun 2024 15:20:56 -0700 Subject: [PATCH 519/748] Fix `count_each`'s log all expt/img/refl counts when `verbose` 2, python2 syntax fix --- xfel/merging/application/utils/data_counter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xfel/merging/application/utils/data_counter.py b/xfel/merging/application/utils/data_counter.py index 791efe9073..dadf8983a3 100644 --- a/xfel/merging/application/utils/data_counter.py +++ b/xfel/merging/application/utils/data_counter.py @@ -37,7 +37,7 @@ def count_each(self, experiments, reflections, verbose=False): # rank 0: log data statistics if self.mpi_helper.rank == 0 and verbose: - max_count = int(log10(max(*image_count_list, *reflection_count_list))) + max_count = int(log10(max(max(image_count_list), max(reflection_count_list)))) count_fmt = '%' + str(max_count + 1) + 'd' self.logger.main_log('Experiments by rank: ' + ', '.join([count_fmt % i for i in experiment_count_list])) self.logger.main_log('Images by rank: ' + ', '.join([count_fmt % i for i in image_count_list])) From fb324479769280a8d055cad81d5d24e9851572a0 Mon Sep 17 00:00:00 2001 From: Daniel Tchon Date: Fri, 7 Jun 2024 15:25:26 -0700 Subject: [PATCH 520/748] Fix `count_each`'s log all expt/img/refl counts when `verbose` 2, nicer fix --- xfel/merging/application/utils/data_counter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xfel/merging/application/utils/data_counter.py b/xfel/merging/application/utils/data_counter.py index dadf8983a3..e5912f89b1 100644 --- a/xfel/merging/application/utils/data_counter.py +++ b/xfel/merging/application/utils/data_counter.py @@ -37,7 +37,7 @@ def count_each(self, experiments, reflections, verbose=False): # rank 0: log data statistics if self.mpi_helper.rank == 0 and verbose: - max_count = int(log10(max(max(image_count_list), max(reflection_count_list)))) + max_count = int(log10(max(image_count_list + reflection_count_list))) count_fmt = '%' + str(max_count + 1) + 'd' self.logger.main_log('Experiments by rank: ' + ', '.join([count_fmt % i for i in experiment_count_list])) self.logger.main_log('Images by rank: ' + ', '.join([count_fmt % i for i in image_count_list])) From bb644c1640f0d929f59f83747bda97d8a32a9e5b Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Fri, 7 Jun 2024 15:31:41 -0700 Subject: [PATCH 521/748] One more test/example case --- iotbx/regression/tst_hierarchy_altlocs.py | 31 +++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/iotbx/regression/tst_hierarchy_altlocs.py b/iotbx/regression/tst_hierarchy_altlocs.py index 8f5e0ff323..033ba9a232 100644 --- a/iotbx/regression/tst_hierarchy_altlocs.py +++ b/iotbx/regression/tst_hierarchy_altlocs.py @@ -45,6 +45,15 @@ ATOM 5 CB AALA A 1 -5.882 1.390 11.495 0.49 7.79 C """ +pdb_str5 = """ +ATOM 1 N ALA A 1 -4.898 0.072 13.387 0.49 7.34 N +ATOM 2 CA ALA A 1 -4.626 0.703 12.080 0.49 7.71 C +ATOM 3 C ALA A 1 -3.475 1.680 12.227 0.49 7.52 C +ATOM 4 O ALA A 1 -3.125 2.100 13.335 0.49 7.59 O +ATOM 5 CB AALA A 1 -5.882 1.390 11.495 0.49 7.79 C +ATOM 5 CB BALA A 1 -5.882 1.390 11.495 0.49 7.79 C +""" + def get_h_oc(s): h = iotbx.pdb.input(source_info=None, lines=s).construct_hierarchy() oc = h.overall_counts() @@ -130,10 +139,32 @@ def tst4(): do_value = duplicate_output.getvalue() assert not show_diff(do_value, "") +def tst5(): + """putting whitespace into already created hierarchy results + in exactly same behavior as having incorrect one: + here we transform good hierarchy into one from tst4 by changing + altloc A to ' ' and get the same n_alt_conf_improper == 1.""" + h, oc = get_h_oc(pdb_str5) + altlocs = [ag.altloc for ag in h.only_model().atom_groups()] + assert altlocs == ['', 'A', 'B'], altlocs + assert oc.n_alt_conf_improper == 0, oc.n_alt_conf_improper + assert len(oc.duplicate_atom_labels) == 0, list(oc.duplicate_atom_labels) + + # Now we change altloc A to ' ' + h.atoms()[-2].parent().altloc = ' ' + # h.atoms()[-1].parent().altloc = ' ' + + altlocs = [ag.altloc for ag in h.only_model().atom_groups()] + assert altlocs == ['', ' ', 'B'], altlocs + # print(h.as_pdb_string()) + oc2 = h.overall_counts() + assert oc2.n_alt_conf_improper == 1, oc2.n_alt_conf_improper + assert len(oc2.duplicate_atom_labels) == 0, list(oc2.duplicate_atom_labels) if (__name__ == "__main__"): tst1() tst2() tst3() tst4() + tst5() print("OK") From d8bc62d0e43b904afd5755e780de52f1336d90e8 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Fri, 7 Jun 2024 16:34:21 -0700 Subject: [PATCH 522/748] One more test/example on altloc --- iotbx/regression/tst_hierarchy_altlocs.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/iotbx/regression/tst_hierarchy_altlocs.py b/iotbx/regression/tst_hierarchy_altlocs.py index 033ba9a232..600cc8fe34 100644 --- a/iotbx/regression/tst_hierarchy_altlocs.py +++ b/iotbx/regression/tst_hierarchy_altlocs.py @@ -54,6 +54,9 @@ ATOM 5 CB BALA A 1 -5.882 1.390 11.495 0.49 7.79 C """ +pdb_str6 = """ +HETATM 2174 O HOH S 179 -5.781 7.569 9.276 0.24 14.70 O +""" def get_h_oc(s): h = iotbx.pdb.input(source_info=None, lines=s).construct_hierarchy() oc = h.overall_counts() @@ -161,10 +164,30 @@ def tst5(): assert oc2.n_alt_conf_improper == 1, oc2.n_alt_conf_improper assert len(oc2.duplicate_atom_labels) == 0, list(oc2.duplicate_atom_labels) +def tst6(): + """Putting whitespace into altloc seem to always result + in n_alt_conf_improper. + """ + h, oc = get_h_oc(pdb_str6) + altlocs = [ag.altloc for ag in h.only_model().atom_groups()] + assert altlocs == [''], altlocs + assert oc.n_alt_conf_improper == 0, oc.n_alt_conf_improper + assert len(oc.duplicate_atom_labels) == 0, list(oc.duplicate_atom_labels) + + # Now we change altloc A to ' ' + h.atoms()[0].parent().altloc = ' ' + altlocs = [ag.altloc for ag in h.only_model().atom_groups()] + assert altlocs == [' '], altlocs + oc2 = h.overall_counts() + assert oc2.n_alt_conf_improper == 1, oc2.n_alt_conf_improper + assert len(oc2.duplicate_atom_labels) == 0, list(oc2.duplicate_atom_labels) + + if (__name__ == "__main__"): tst1() tst2() tst3() tst4() tst5() + tst6() print("OK") From 7f4d4e4e4b77f0c9737691a83292ca7b805bc1e4 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sat, 8 Jun 2024 21:10:36 -0700 Subject: [PATCH 523/748] Parse hierarchy differently to allow altlocs --- mmtbx/hydrogens/__init__.py | 86 +++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/mmtbx/hydrogens/__init__.py b/mmtbx/hydrogens/__init__.py index a7a110acf6..ebc3433bdc 100644 --- a/mmtbx/hydrogens/__init__.py +++ b/mmtbx/hydrogens/__init__.py @@ -385,47 +385,57 @@ def fit_rotatable2(model, fmodel, use_electron_xh=True): mm = map_manager(fmodel = fmodel, map_type = "mFobs-DFmodel") get_class = iotbx.pdb.common_residue_names_get_class sites_cart = model.get_sites_cart() + + #for m in model.get_hierarchy().models(): + # for c in m.chains(): + # first=True + # for r in c.residues(): + for m in model.get_hierarchy().models(): for c in m.chains(): first=True - for r in c.residues(): - if not get_class(r.resname)=="common_amino_acid": continue - s = mmtbx.hydrogens.shortcut(residue=r, first=first, log=model.log) - first=False - if s is None: continue - # print(r.resname, s) - omit_selection = flex.size_t() - for cl in s: - omit_selection.extend(flex.size_t(cl[1])) - mm.update_omit_map(omit_selection = omit_selection) - for cl in s: - axis = cl[0] - a1, a2 = sites_cart[axis[0]], sites_cart[axis[1]] - sel_to_rotate = flex.size_t(cl[1]) - sites_cart_to_rotate = sites_cart.select(sel_to_rotate) - score_start = mm.score(sites_cart = sites_cart_to_rotate) - score_best = score_start - sites_cart_moved = flex.vec3_double(sites_cart_to_rotate.size()) - sites_cart_best = None - assert len(sel_to_rotate) in [1,3] - if len(sel_to_rotate)==1: stop=360 - else: stop=60 - for angle in range(0, stop, 1): - sites_cart_moved = flex.vec3_double(sites_cart_to_rotate.size()) - for isite, site_cart in enumerate(sites_cart_to_rotate): - site_cart_rotated = rotate_point_around_axis( - axis_point_1 = a1, - axis_point_2 = a2, - point = site_cart, - angle = angle, - deg = True) - sites_cart_moved[isite] = site_cart_rotated - score = mm.score(sites_cart = sites_cart_moved) - if score > score_best: - score_best = score - sites_cart_best = sites_cart_moved.deep_copy() - if sites_cart_best is not None: - sites_cart = sites_cart.set_selected(sel_to_rotate, sites_cart_best) + for residue_group in c.residue_groups(): + conformers = residue_group.conformers() + for conformer in conformers: + r = conformer.only_residue() + + if not get_class(r.resname)=="common_amino_acid": continue + s = mmtbx.hydrogens.shortcut(residue=r, first=first, log=model.log) + first=False + if s is None: continue + # print(r.resname, s) + omit_selection = flex.size_t() + for cl in s: + omit_selection.extend(flex.size_t(cl[1])) + mm.update_omit_map(omit_selection = omit_selection) + for cl in s: + axis = cl[0] + a1, a2 = sites_cart[axis[0]], sites_cart[axis[1]] + sel_to_rotate = flex.size_t(cl[1]) + sites_cart_to_rotate = sites_cart.select(sel_to_rotate) + score_start = mm.score(sites_cart = sites_cart_to_rotate) + score_best = score_start + sites_cart_moved = flex.vec3_double(sites_cart_to_rotate.size()) + sites_cart_best = None + assert len(sel_to_rotate) in [1,3] + if len(sel_to_rotate)==1: stop=360 + else: stop=60 + for angle in range(0, stop, 1): + sites_cart_moved = flex.vec3_double(sites_cart_to_rotate.size()) + for isite, site_cart in enumerate(sites_cart_to_rotate): + site_cart_rotated = rotate_point_around_axis( + axis_point_1 = a1, + axis_point_2 = a2, + point = site_cart, + angle = angle, + deg = True) + sites_cart_moved[isite] = site_cart_rotated + score = mm.score(sites_cart = sites_cart_moved) + if score > score_best: + score_best = score + sites_cart_best = sites_cart_moved.deep_copy() + if sites_cart_best is not None: + sites_cart = sites_cart.set_selected(sel_to_rotate, sites_cart_best) model.set_sites_cart(sites_cart) # Reset X-H bonds if not use_electron_xh: From 75a51840a507788ee473b44349a4eb62261d7990 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sat, 8 Jun 2024 21:12:16 -0700 Subject: [PATCH 524/748] Add symetric distance method. Simple. Inefficient. But useful if you want to calculate distance between two sets of atoms and you don't care about labels! --- mmtbx/model/model.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index f7aca3dbd7..be2af08d1d 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -472,6 +472,24 @@ def get_source_filename(self, full_path=True): filename = None return filename + def distances_symmetric(self, other): + """ + Min distances between matching atoms accounting for pseudo-symmetric + residues. Slow. + """ + assert self.size() == other.size() + atoms_1 = self.get_hierarchy().atoms() + atoms_2 = other.get_hierarchy().atoms() + result = flex.double() + for i, ai in enumerate(atoms_1): + dbest = 1.e9 + for j, aj in enumerate(atoms_2): + d = ai.distance(aj) + if d Date: Sat, 8 Jun 2024 21:27:47 -0700 Subject: [PATCH 525/748] Two methods to fit residues with altlocs: masking and sampling --- mmtbx/refinement/real_space/fit_residue.py | 191 ++++++++- mmtbx/refinement/real_space/fit_residues.py | 405 ++++++++++++++++---- 2 files changed, 520 insertions(+), 76 deletions(-) diff --git a/mmtbx/refinement/real_space/fit_residue.py b/mmtbx/refinement/real_space/fit_residue.py index a94f8a90c0..0cbd67be0e 100644 --- a/mmtbx/refinement/real_space/fit_residue.py +++ b/mmtbx/refinement/real_space/fit_residue.py @@ -9,6 +9,8 @@ import mmtbx.idealized_aa_residues.rotamer_manager import collections from libtbx import group_args +from collections import OrderedDict +from scitbx.matrix import rotate_point_around_axis import boost_adaptbx.boost.python as bp from six.moves import range @@ -92,6 +94,184 @@ def show(self): for k_,v_ in zip(v.vals.keys(), v.vals.values())]) print(" %7s: score: %7.3f %s %s"%(k, v.target, vals, v.rot), file=self.log) +def find_peak(angles, values, threshold): + peaks = [] + s = len(values) + #print("looking at peaks", s) + for i, a in enumerate(angles): + v = values[i] + if v < threshold: continue + ip1 = i+1 if i+1 < s else abs(s-(i+1)) + ip2 = i+2 if i+2 < s else abs(s-(i+2)) + ip3 = i+3 if i+3 < s else abs(s-(i+3)) + vip1 = values[ip1] + vip2 = values[ip2] + vip3 = values[ip3] + im1 = i-1 + im2 = i-2 + im3 = i-3 + vim1 = values[im1] + vim2 = values[im2] + vim3 = values[im3] + #print(" ", a, v, "|", vim1,vim2,vim3, vip1,vip2,vip3) + stop = False + for vv in [vip1,vip2,vip3, vim1,vim2,vim3]: + if vv < threshold: stop=True + if stop: continue + fl=vim1", vim10: continue + #if t<=self.target_start: continue + #print(rotamer_status, " ".join(["%6.2f"%v for v in vals]), "<<<<<<<<", t) + self.rotamers.setdefault(rotamer_status, []).append([t,sites_cart]) + tmp.append(sites_cart) + self.sites_cart_conformers_all = tmp + # + #print("rotamers") + #for k,v in self.rotamers.items(): + # print(" ", k,[vv[0] for vv in v]) + + self.unique = {} + for k,v in self.rotamers.items(): + vbest = -1.e9 + ssbest = None + for it in v: + vv, ss = it + if vv > vbest: + vbest = vv + ssbest = ss + self.unique[k] = [vbest, ssbest] + #print("unique") + #for k, v in self.unique.items(): + # print(" ", k, v) + # + self.unique_sorted = None + + def _get_target(self, sites_cart): + vals = flex.double() + for sc in sites_cart.select(self.side_chain_selection): + vals.append(self.map_data.tricubic_interpolation( + self.unit_cell.fractionalize(sc))) + return flex.mean(vals), vals + + def sorted_by_map_value(self, n=None): + tbest=-9999 + scbest = None + if self.unique=={}: return None + for k, v in self.unique.items(): + t = v[0] + if t > tbest: + tbest = t + scbest = v[1].deep_copy() + return [scbest] + + #if self.unique_sorted is not None: return self.unique_sorted + #self.unique_sorted = OrderedDict() + #for k,v in self.unique.items(): + # self.unique_sorted[v[0]] = v[1] + #self.unique_sorted = OrderedDict(reversed(list(self.unique_sorted.items()))) + ##for k,v in self.unique_sorted.items(): + ## print("LOOK", k,v) + #if n is None: return self.unique_sorted + #else: + # rv = list(self.unique_sorted.values())[:n] + # return rv + + def func(self, cl, sites_cart, last): + if not last: points = [sites_cart[cl.atoms_to_rotate[0]]] + else: + points = [] + for i in cl.atoms_to_rotate: + if not i in self.rsr_eval_selection: continue + points.append(sites_cart[i]) + angles = flex.double() + values = flex.double() + + #print("using axis", list(cl.axis)) + + if last and len(points)>1: end=180 + else: end=360 + for angle in range(0, end, 1): + vals = flex.double() + for point in points: + new_point = rotate_point_around_axis( + axis_point_1 = sites_cart[cl.axis[0]], + axis_point_2 = sites_cart[cl.axis[1]], + point = point, + angle = angle, deg=True) + value = self.map_data.eight_point_interpolation( + self.unit_cell.fractionalize(new_point)) + vals.append(value) + #print(angle, flex.mean(vals)) + angles.append(angle) + values.append(flex.mean(vals)) + peaks = find_peak(angles=angles, values=values, threshold=self.threshold) + #print(peaks) + for peak in peaks: + sites_cart_ = sites_cart.deep_copy() + for atom in cl.atoms_to_rotate: + new_xyz = rotate_point_around_axis( + axis_point_1 = sites_cart_[cl.axis[0]], + axis_point_2 = sites_cart_[cl.axis[1]], + point = sites_cart_[atom], + angle = peak, deg=True) + sites_cart_[atom] = new_xyz + self.sites_cart_conformers_all.append(sites_cart_) + class run(object): def __init__(self, residue, @@ -107,6 +287,7 @@ def __init__(self, target_map_for_cb=None, backbone_sample=False, accept_only_if_max_shift_is_smaller_than=None, + trust_map_values_real=True, log=None): adopt_init_args(self, locals()) if(self.log is None): self.log = sys.stdout @@ -259,14 +440,20 @@ def fit_side_chain(self, clusters): # Ad hoc: S or SE have larger peaks! if(self.residue.resname in ["MET","MSE"]): scale=100 else: scale=3 + if self.trust_map_values_real: + scaleup=1 + scaledown=1 + else: + scaleup=10000 + scaledown=0 moving = ext.moving( sites_cart = self.residue.atoms().extract_xyz(), sites_cart_start = sites_cart_start, radii = radii, weights = self.weights, bonded_pairs = self.pairs, - ref_map_max = ref_map_vals * scale, - ref_map_min = ref_map_vals / 10) + ref_map_max = ref_map_vals * scale*scaleup, + ref_map_min = ref_map_vals / 10 *scaledown) # ro = ext.fit( fixed = self.xyzrad_bumpers, diff --git a/mmtbx/refinement/real_space/fit_residues.py b/mmtbx/refinement/real_space/fit_residues.py index 36a7736cf7..918efdc992 100644 --- a/mmtbx/refinement/real_space/fit_residues.py +++ b/mmtbx/refinement/real_space/fit_residues.py @@ -11,15 +11,19 @@ cctbx_maptbx_ext = bp.import_ext("cctbx_maptbx_ext") fit_ext = bp.import_ext("mmtbx_rotamer_fit_ext") +import scitbx.math +from mmtbx.rotamer.rotamer_eval import RotamerEval +rotamer_manager = RotamerEval() + # XXX Keep for debugging -#def write_map_file(crystal_symmetry, map_data, file_name): -# from iotbx import mrcfile -# mrcfile.write_ccp4_map( -# file_name = file_name, -# unit_cell = crystal_symmetry.unit_cell(), -# space_group = crystal_symmetry.space_group(), -# map_data = map_data, -# labels = flex.std_string([""])) +def write_map_file(crystal_symmetry, map_data, file_name): + from iotbx import mrcfile + mrcfile.write_ccp4_map( + file_name = file_name, + unit_cell = crystal_symmetry.unit_cell(), + space_group = crystal_symmetry.space_group(), + map_data = map_data, + labels = flex.std_string([""])) negate_map_table = { #"ala": False, @@ -46,6 +50,178 @@ "pro": 3 } +def get_map(fmodel, crystal_gridding, map_type): + coeffs = fmodel.electron_density_map().map_coefficients( + map_type = map_type, + fill_missing = False, + isotropize = False) + fft_map = coeffs.fft_map(crystal_gridding = crystal_gridding) + fft_map.apply_sigma_scaling() + result = fft_map.real_map_unpadded() + return result + +def fit_altlocs_with_masking(model, fmodel, sin_cos_table=None, + rotamer_manager=None): + log = model.log + if rotamer_manager is None: + rotamer_manager = mmtbx.idealized_aa_residues.rotamer_manager.load( + residues = None, rotamers = "favored_allowed") + if sin_cos_table is None: + sin_cos_table = scitbx.math.sin_cos_table(n=10000) + # + crystal_symmetry = fmodel.xray_structure.crystal_symmetry() + cg = maptbx.crystal_gridding( + unit_cell = crystal_symmetry.unit_cell(), + space_group_info = crystal_symmetry.space_group_info(), + symmetry_flags = maptbx.use_space_group_symmetry, + step = 0.3) + # + map_data = get_map(fmodel=fmodel, crystal_gridding=cg, map_type='2mFo-DFc') + # + sites_cart = model.get_sites_cart() + sites_cart_start = sites_cart.deep_copy() + cis = model.get_hierarchy().get_conformer_indices() + indices = cis.conformer_indices + vals = list(set(cis.index_altloc_mapping.values())) + for k,v in zip(cis.index_altloc_mapping.keys(), vals): + if v == 0: continue + sel = indices == 0 + sel |= indices == v + model_conf = model.select(sel) + # Compute mask for other conformers + model_other = model.select(~sel) + ss = "not (name CA or name O or name N or name C)" + sssel = model_other.selection(string=ss) + model_other = model_other.select(sssel) + model_other = model_other.remove_hydrogens() + mask_p1 = mmtbx.masks.mask_from_xray_structure( + xray_structure = model_other.get_xray_structure(), + p1 = True, + for_structure_factors = True, + solvent_radius = 0, + shrink_truncation_radius = 0, + atom_radius = 0.5, + n_real = map_data.accessor().all(), + in_asu = False).mask_data + maptbx.unpad_in_place(map=mask_p1) + # + map_data_masked = map_data * mask_p1 + # + # FOR DEBUGGING + # + #with open("%s%d.pdb"%(k,v),"w") as fo: + # fo.write(model_conf.model_as_pdb()) + #write_map_file(crystal_symmetry = model.crystal_symmetry(), + # map_data = map_data_masked, + # file_name = "%s%d.map"%(k,v)) + # + result = mmtbx.refinement.real_space.fit_residues.run( + pdb_hierarchy = model_conf.get_hierarchy(), + vdw_radii = model_conf.get_vdw_radii(), + crystal_symmetry = model_conf.crystal_symmetry(), + map_data = map_data_masked, + backbone_sample = False, + rotatable_hd = model_conf.rotatable_hd_selection(iselection=False), + rotamer_manager = rotamer_manager, + sin_cos_table = sin_cos_table, + mon_lib_srv = model_conf.get_mon_lib_srv(), + fit_altlocs_method= "masking", + log = log) + # + sites_cart = sites_cart.set_selected( + sel, result.pdb_hierarchy.atoms().extract_xyz()) + model_conf.set_sites_cart(result.pdb_hierarchy.atoms().extract_xyz()) + # + # FOR DEBUGGING + # + #with open("%s%d_fitted.pdb"%(k,v),"w") as fo: + # fo.write(model_conf.model_as_pdb()) + # + model.set_sites_cart(sites_cart) + fmodel.xray_structure.set_sites_cart(model.get_sites_cart()) + fmodel.update_xray_structure(update_f_calc=True) + # + map_data = get_map(fmodel=fmodel, crystal_gridding=cg, map_type='2mFo-DFc') + # + # FOR DEBUGGING + # + #with open("fitted1.pdb","w") as fo: + # fo.write(model.model_as_pdb()) + #print("pre-FINAL:", fmodel.r_work()) + # + sites_cart = model.get_sites_cart() + uc = model.crystal_symmetry().unit_cell() + for m in model.get_hierarchy().models(): + for chain in m.chains(): + for residue_group in chain.residue_groups(): + conformers = residue_group.conformers() + rs = [] + for conformer in residue_group.conformers(): + residue = conformer.only_residue() + sel = residue.atoms().extract_i_seq() + + if len(residue_group.conformers()) > 1: + t1 = maptbx.real_space_target_simple( + unit_cell = uc, + density_map = map_data, + sites_cart = residue.atoms().extract_xyz()) + mmtbx.refinement.real_space.fit_residue.tune_up( + target_map = map_data, + residue = residue, + mon_lib_srv = model.get_mon_lib_srv(), + rotamer_manager = rotamer_manager.rotamer_evaluator, + unit_cell = uc, + monitor = None, + torsion_search_start = -20, + torsion_search_stop = 20, + torsion_search_step = 1) + t2 = maptbx.real_space_target_simple( + unit_cell = uc, + density_map = map_data, + sites_cart = residue.atoms().extract_xyz()) + if t2>t1: + sites_cart = sites_cart.set_selected(sel, residue.atoms().extract_xyz()) + #print(" tuneup:", t1, t2) + + ts = maptbx.real_space_target_simple( + unit_cell = uc, + density_map = map_data, + sites_cart = sites_cart_start.select(sel)) + te = maptbx.real_space_target_simple( + unit_cell = uc, + density_map = map_data, + sites_cart = sites_cart.select(sel)) + f = "" + if te > ts: f = "<<< better" + r = (ts-te)/(ts+te)*100*2 + label = "%2s %5s %s%4s"%( + chain.id, residue.resseq, conformer.altloc, residue.resname) + #print(label, "%6.2f %6.2f %6.2f"%(ts, te, r), f) + rs.append(r) + # + if len(rs)>0: + got_better = 0 + got_worse = 0 + for r in rs: + if r<-1 or r<-1 : got_better+=1 + if r> 1 or r> 1 : got_worse +=1 + if got_better>0 and got_worse==0: + #print(" "*30, "<<< fit accepted") + for conformer in residue_group.conformers(): + sel = conformer.atoms().extract_i_seq() + sel = flex.bool(model.size(), sel) + sites_cart_start = sites_cart_start.set_selected(sel, sites_cart) + # + model.set_sites_cart(sites_cart_start) + fmodel.xray_structure.set_sites_cart(model.get_sites_cart()) + fmodel.update_xray_structure(update_f_calc=True) + #print("FINAL:", fmodel.r_work()) + # + # FOR DEBUGGING + # + #with open("fitted2.pdb","w") as fo: + # fo.write(model.model_as_pdb()) + class run(object): def __init__(self, pdb_hierarchy, @@ -64,8 +240,10 @@ def __init__(self, vdw_radii=None, backbone_sample=False, # XXX diff_map_data=None, + fit_altlocs_method=None, log = None): adopt_init_args(self, locals()) + assert fit_altlocs_method in [None, 'sampling', 'masking'] # Final filtering by CC_mask requires the map and resolution if self.filter_by_cc: assert self.d_min is not None @@ -255,6 +433,10 @@ def one_residue_iteration(self, residue): xyzrad_bumpers = self.get_nonbonded_bumpers( residue=residue, radius=negate_rad) self.processed +=1 + if self.fit_altlocs_method=="masking": + trust_map_values_real=False + else: + trust_map_values_real=True mmtbx.refinement.real_space.fit_residue.run( residue = residue, vdw_radii = self.vdw_radii, @@ -268,34 +450,106 @@ def one_residue_iteration(self, residue): rotatable_hd = self.rotatable_hd, sin_cos_table = self.sin_cos_table, cmv = self.cmv, + trust_map_values_real = trust_map_values_real, log = self.log) self.total_time_residue_loop += (time.time()-t0) def loop(self, function): + get_class = iotbx.pdb.common_residue_names_get_class for model in self.pdb_hierarchy.models(): for chain in model.chains(): for residue_group in chain.residue_groups(): conformers = residue_group.conformers() - if(len(conformers)>1): continue - for conformer in residue_group.conformers(): - residue = conformer.only_residue() - if(not self.bselection[residue.atoms()[0].i_seq]): continue - xyz_start = residue.atoms().extract_xyz() - function(residue = residue) - # Check for symmetry clash - sels = self._selection_around_minus_self(residue=residue, radius=1.5) - if(sels is not None and sels.size()>0): - print(" revert: symmetry clash", file=self.log) - residue.atoms().set_xyz(xyz_start) - # XXX - # XXX For debugging - # XXX - #atoms=self.pdb_hierarchy.atoms() - #for s in sels: - # atom = atoms[s] - # key = "%s_%s_%s"%( - # atom.parent().parent().parent().id, atom.parent().resname, atom.name) - # print(key, residue.resname, "LOOK-"*10) + # DEAL WITH ALTLOCS + if(len(conformers)>1 and self.fit_altlocs_method=='sampling'): + n = len(conformers) + overall = {} + for conformer in conformers: + residue = conformer.only_residue() + + #if int(residue.resseq) != 30: continue + + # + rn = residue.resname.strip().lower() + if rn in ["ala", "pro", "gly"]: continue + negate_rad = negate_map_table[residue.resname.strip().lower()] + xrs = self.pdb_hierarchy.extract_xray_structure( + crystal_symmetry = self.crystal_symmetry) + negate_selection = mmtbx.refinement.real_space.selection_around_to_negate( + xray_structure = xrs, + selection_within_radius = negate_rad, + iselection = residue_group.atoms().extract_i_seq()) + + target_map_work = mmtbx.refinement.real_space.\ + negate_map_around_selected_atoms_except_selected_atoms( + xray_structure = xrs, + map_data = self.target_map.deep_copy(), + negate_selection = negate_selection, + atom_radius = 1.5) + + if(get_class(residue.resname) != "common_amino_acid"): continue + sel = residue.atoms().extract_i_seq() + residue_dc = residue.standalone_copy() + residue_dc.atoms().reset_i_seq() + o = mmtbx.refinement.real_space.fit_residue.find_all_conformers( + residue = residue_dc, + map_data = target_map_work, #self.target_map, + mon_lib_srv = self.mon_lib_srv, + unit_cell = self.crystal_symmetry.unit_cell(), + threshold = 1.0, + rotamer_evaluator = rotamer_manager) + for k,v in o.unique.items(): + overall.setdefault(k, []).append(v) + #sites_cart_conformers = o.sorted_by_map_value(n=n) + #if sites_cart_conformers is not None: + ## for sites_cart, conformer in zip(sites_cart_conformers, conformers): + ## residue = conformer.only_residue() + ## residue.atoms().set_xyz( sites_cart ) + # residue.atoms().set_xyz( sites_cart_conformers[0] ) + unique = {} + for k,v in overall.items(): + vbest = -1.e9 + ssbest = None + for it in v: + vv, ss = it + if vv > vbest: + vbest = vv + ssbest = ss + unique[k] = [vbest, ssbest] + if unique != {}: + print("OVERALL unique") + code=flex.std_string() + vals=flex.double() + for k, v in unique.items(): + print(" ", k, v) + code.append(k) + vals.append(v[0]) + sel = flex.sort_permutation(vals, reverse=True) + print(list(vals.select(sel))) + + + + # SINGLE CONFORMATION + else: + for conformer in residue_group.conformers(): + residue = conformer.only_residue() + if(not self.bselection[residue.atoms()[0].i_seq]): continue + xyz_start = residue.atoms().extract_xyz() + function(residue = residue) + # Check for symmetry clash + sels = self._selection_around_minus_self(residue=residue, radius=1.5) + if(sels is not None and sels.size()>0): + print(" revert: symmetry clash", file=self.log) + residue.atoms().set_xyz(xyz_start) + # XXX + # XXX For debugging + # XXX + #atoms=self.pdb_hierarchy.atoms() + #for s in sels: + # atom = atoms[s] + # key = "%s_%s_%s"%( + # atom.parent().parent().parent().id, atom.parent().resname, atom.name) + # print(key, residue.resname, "LOOK-"*10) def count_outliers(self): o = mmtbx.refinement.real_space.side_chain_fit_evaluator( @@ -304,50 +558,53 @@ def count_outliers(self): rotamer_evaluator = self.rotamer_manager.rotamer_evaluator) return o.cntr_outliers +# XXX +# XXX Looks obsolete. Not used anywhere. +# XXX # XXX Where is this used? Looks like severe duplication! -class fix_outliers(object): - def __init__(self, - pdb_hierarchy, - rotamer_manager, - sin_cos_table, - mon_lib_srv, - f_map=None, - fdiff_map=None, - unit_cell=None, - accept_only_if_max_shift_is_smaller_than=None, - log = None): - adopt_init_args(self, locals()) - assert [f_map, fdiff_map, unit_cell].count(None) in [0,3] - ac = accept_only_if_max_shift_is_smaller_than - if(self.log is None): self.log = sys.stdout - get_class = iotbx.pdb.common_residue_names_get_class - for model in self.pdb_hierarchy.models(): - for chain in model.chains(): - for residue_group in chain.residue_groups(): - conformers = residue_group.conformers() - if(len(conformers)>1): continue - for conformer in residue_group.conformers(): - residue = conformer.only_residue() - id_str="%s%s%s"%(chain.id,residue.resname,residue.resseq.strip()) - if(get_class(residue.resname) == "common_amino_acid"): - # Idealize rotamer: move to nearest rotameric state - re = self.rotamer_manager.rotamer_evaluator - if(re.evaluate_residue(residue)=="OUTLIER"): - go=True - if([f_map, fdiff_map, unit_cell].count(None)==0): - go = mmtbx.refinement.real_space.need_sidechain_fit( - residue = residue, - rotamer_evaluator = self.rotamer_manager.rotamer_evaluator, - mon_lib_srv = self.mon_lib_srv, - unit_cell = self.unit_cell, - f_map = f_map, - fdiff_map = fdiff_map) - if(go): - mmtbx.refinement.real_space.fit_residue.run( - residue = residue, - backbone_sample = False, - mon_lib_srv = self.mon_lib_srv, - rotamer_manager = self.rotamer_manager, - sin_cos_table = self.sin_cos_table, - accept_only_if_max_shift_is_smaller_than = ac, - log = self.log) +#class fix_outliers(object): +# def __init__(self, +# pdb_hierarchy, +# rotamer_manager, +# sin_cos_table, +# mon_lib_srv, +# f_map=None, +# fdiff_map=None, +# unit_cell=None, +# accept_only_if_max_shift_is_smaller_than=None, +# log = None): +# adopt_init_args(self, locals()) +# assert [f_map, fdiff_map, unit_cell].count(None) in [0,3] +# ac = accept_only_if_max_shift_is_smaller_than +# if(self.log is None): self.log = sys.stdout +# get_class = iotbx.pdb.common_residue_names_get_class +# for model in self.pdb_hierarchy.models(): +# for chain in model.chains(): +# for residue_group in chain.residue_groups(): +# conformers = residue_group.conformers() +# if(len(conformers)>1): continue +# for conformer in residue_group.conformers(): +# residue = conformer.only_residue() +# id_str="%s%s%s"%(chain.id,residue.resname,residue.resseq.strip()) +# if(get_class(residue.resname) == "common_amino_acid"): +# # Idealize rotamer: move to nearest rotameric state +# re = self.rotamer_manager.rotamer_evaluator +# if(re.evaluate_residue(residue)=="OUTLIER"): +# go=True +# if([f_map, fdiff_map, unit_cell].count(None)==0): +# go = mmtbx.refinement.real_space.need_sidechain_fit( +# residue = residue, +# rotamer_evaluator = self.rotamer_manager.rotamer_evaluator, +# mon_lib_srv = self.mon_lib_srv, +# unit_cell = self.unit_cell, +# f_map = f_map, +# fdiff_map = fdiff_map) +# if(go): +# mmtbx.refinement.real_space.fit_residue.run( +# residue = residue, +# backbone_sample = False, +# mon_lib_srv = self.mon_lib_srv, +# rotamer_manager = self.rotamer_manager, +# sin_cos_table = self.sin_cos_table, +# accept_only_if_max_shift_is_smaller_than = ac, +# log = self.log) From 309ccea913ae43ba1781ac2b508aa02d89986a12 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sun, 9 Jun 2024 08:09:10 -0700 Subject: [PATCH 526/748] Fix missing / wrong arg with a test --- mmtbx/command_line/find_peaks_holes.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/mmtbx/command_line/find_peaks_holes.py b/mmtbx/command_line/find_peaks_holes.py index 3665d372c5..66561d2fdc 100644 --- a/mmtbx/command_line/find_peaks_holes.py +++ b/mmtbx/command_line/find_peaks_holes.py @@ -321,9 +321,13 @@ def find_peaks_holes( f_map_.apply_sigma_scaling() f_map = f_map_.real_map() make_header("Positive difference map peaks", out=out) + coeffs = fmodel.electron_density_map().map_coefficients( + map_type = "mFo-DFc", + fill_missing = False, + isotropize = False) peaks_result = find_peaks.manager( - fmodel=fmodel, - map_type="mFo-DFc", + map_coeffs = coeffs, + xray_structure = fmodel.xray_structure, map_cutoff=map_cutoff, params=params, log=out) @@ -342,9 +346,13 @@ def find_peaks_holes( print("", file=out) out.flush() make_header("Negative difference map holes", out=out) + coeffs = fmodel.electron_density_map().map_coefficients( + map_type = "mFo-DFc", + fill_missing = False, + isotropize = False) holes_result = find_peaks.manager( - fmodel=fmodel, - map_type="mFo-DFc", + map_coeffs = coeffs, + xray_structure = fmodel.xray_structure, map_cutoff=-map_cutoff, params=params, log=out) From 4c99c27e0f36222066b34216fea824f387d856c1 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Thu, 13 Jun 2024 09:28:31 -0700 Subject: [PATCH 527/748] pdbtools: use data_manager to output model so it can figure out correct output format. With test. Propagate output_cs parameter. --- iotbx/data_manager/model.py | 10 +++++++--- mmtbx/programs/pdbtools.py | 3 +-- mmtbx/regression/tst_pdbtools.py | 10 ++++++++++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/iotbx/data_manager/model.py b/iotbx/data_manager/model.py index e3268f9c2d..c37d01eaea 100644 --- a/iotbx/data_manager/model.py +++ b/iotbx/data_manager/model.py @@ -278,7 +278,8 @@ def get_default_output_model_filename(self, extension=Auto): return filename def write_model_file(self, model_str, filename=Auto, - format=Auto, overwrite=Auto): + format=Auto, overwrite=Auto, + output_cs=True): ''' Function for writing a model to file @@ -300,6 +301,9 @@ def write_model_file(self, model_str, filename=Auto, overwrite: bool or Auto Overwrite filename if it exists. If set to Auto, the overwrite state of the DataManager is used. + output_cs: bool + Defines if crystal symmetry needs to be outputted. Passed directly + into model_as_mmcif() and model_as_pdb() Returns ------- @@ -331,11 +335,11 @@ def write_model_file(self, model_str, filename=Auto, not model_str.get_hierarchy().fits_in_pdb_format()): extension = '.cif' format = 'cif' - model_str = model_str.model_as_mmcif() + model_str = model_str.model_as_mmcif(output_cs=output_cs) else: extension = '.pdb' format = 'pdb' - model_str = model_str.model_as_pdb() + model_str = model_str.model_as_pdb(output_cs=output_cs) else: # writing a string. Output format must be specified on input diff --git a/mmtbx/programs/pdbtools.py b/mmtbx/programs/pdbtools.py index 05934ae68d..f654546347 100644 --- a/mmtbx/programs/pdbtools.py +++ b/mmtbx/programs/pdbtools.py @@ -90,8 +90,7 @@ def run(self): output_cs=True if(cs is None): output_cs = False - self.data_manager.write_model_file(self.model.model_as_str( - output_cs=output_cs), ofn) + self.data_manager.write_model_file(self.model, ofn, output_cs=output_cs) self.result = ofn def get_results(self): diff --git a/mmtbx/regression/tst_pdbtools.py b/mmtbx/regression/tst_pdbtools.py index 63b5a49192..3a1590faf1 100644 --- a/mmtbx/regression/tst_pdbtools.py +++ b/mmtbx/regression/tst_pdbtools.py @@ -865,6 +865,16 @@ def exercise_mmcif_support(): hierarchy = pdb_inp.construct_hierarchy() assert [chain.id for chain in hierarchy.chains()] == ['C', 'B'] + # check target_output_format=pdb + cmd = " ".join(["phenix.pdbtools", "\"%s\"" % f.name, + "rename_chain_id.old_id=A", + "rename_chain_id.new_id=C", + "target_output_format=pdb",]) + print(cmd) + run_command(command=cmd, verbose=False) + ofn = f.name[:].replace(".cif","_modified.pdb") + assert os.path.isfile(ofn) + def exercise_mmcif_support_2(prefix="tst_pdbtools_mmcif2"): f = open("%s.pdb" % prefix, 'w') f.write("""\ From 870ef04f8f74ae01e959510ee37548aa333ad41b Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Thu, 13 Jun 2024 10:46:45 -0700 Subject: [PATCH 528/748] Remove not used, not tested undeveloped function. --- mmtbx/model/model.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index be2af08d1d..8c772b1055 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -1942,13 +1942,6 @@ def input_model_format_cif(self): def input_model_format_pdb(self): return self._original_model_format == "pdb" - def model_as_str(self, output_cs=True): - if( self.input_model_format_cif()): - return self.model_as_mmcif(output_cs=output_cs) - elif(self.input_model_format_pdb()): - return self.model_as_pdb(output_cs=output_cs) - else: raise RuntimeError("Model source is unknown.") - def get_current_pdb_interpretation_params(self): if(self._pdb_interpretation_params is not None): return self._pdb_interpretation_params From 1c39c600e90944080edbbaeb5e33c18cecbac471 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Tcho=C5=84?= Date: Thu, 13 Jun 2024 12:27:20 -0700 Subject: [PATCH 529/748] Monitor resource usage (#994) * Framework for compile-time polymorphism. In the exascale_api, allow pixel values to be calculation either on large array (all pixels), or with low-memory on just the whitelist consisting of shoebox pixels. This commit only gives the polymorphism framework; both implementations are currently identical giving the large-array behavior. * Debug case for non-working test. The script tests/tst_memory_policy.py fails with a cuda illegal access. The intention is to get help from NESAP to get a functional test. * Minimal changes for working tst_memory_policy.py Memory savings achieved through code specialization, for the case where pixel values are simulated on a small whitelist. Specializations are not yet optimal, as there is still a lot of code duplication. Changes give ~4.5x reduction in memory footprint, but no success yet in resizing the array m_accumulate_floatimage. Attempts so far lead to cuda memory allocation error. * Remove debugging output to conserve stdout size. * Add first verion of `UsageMonitor` to monitor C/GPU memory/use * Suppress logging information from loggers other than `usage` * Explicitely point to `target` when starting threads * Add logging details, period, null loggers * Correctly calculate total `UsageStats` across cpu, gpu * Don't pass `self` as arg to `Thread` (oddly, this is correct) * Add `UsageStatsHistory`, try to fix empty log * Add test prints for logging * All ranks need to call `log_current_usage` * Why does logging usage stop at some point? * Correctly measure GPU memory use, only sample rank if `single` * Add some basic usage stats plotting every 10th iteration * Allow plotting empty, plot only in main thread * Correctly calculate max memory * Add timestamp to print statements to correlate with usage log * Make `rank/node_usage_stats` a method, avoid unnecessary calls * Only rank 0 should attempt plotting `usage_stats_histories` * `gpu_usage_and_memory`: return -1 if no GPU * `log_current_usage`: No longer print that you're logging * Don't try to sleep backwards :) * Move logging to `UsageLogManager`, allow plotting from logs * Implement inheritance structure that allows for easy extension * Reorganize, heavily document the code * Reorganize, heavily document the code 2 * Rename `UnitIntervalFloat` to PerCentFloat`, fix gpu mem. range * Rename `UsageStats` to `ResourceStats` (and associated) * Improve type annotations * Add option to monitor node 0 only * Add `MonitorWorker` for `cctbx.xfel.merge` * Improve `ResourceStatsArtist` axes description * Add `DummyResourceProbe` for CPU & GPU in case no `Probe` works * Fix typo * Fix typo 2 * Fix typo 3 * Fix typo 4 * Fix missing microseconds in log * In `ResourceStatsArtist`, change `tight_layout` to `constrained_layout` * Use only single `.png` path extension * Fix `ResourceStatsHistory.get_deltas_array` if empty * Correctly print milliseconds * Correctly check for empty array * Revert `ResourceLogManager` as it's used outside * Correctly pass phil parameters to `MonitorWorker` * Correctly pass phil parameters to `MonitorWorker` * In `get_node_resource_stats` communicate within node only * Comm in `get_node_resource_stats` fails. Try adding barrier. * Don't attempt to collect data across ranks, mpi fails * Allow two loggers to work independently by customizing `logger_name` * Add options and phil pars to disable writing and disable plotting * Add options and phil pars to disable writing and disable plotting 2 * Update phil * Update phil 2 * Add `libtbx/resource_monitor.py` to py2 syntax exceptions * Remove Nick's changes specific to `memory_policy` branch * Remove outdated line in `py2_syntax_exceptions.txt` * Remove python3.5+ syntax from `xfel/merging/application/monitor` * Add clutter because libtbx requires it * Update `ResourceLogManager.line_regex` * Assert all `ResourceStats` contain only `PerCentFloat`s, not `str` * support for python versions < 3.9 * Increase plot font size from 10 to 16 * Add support for PathLike ResourceMonitor.prefix as suggested by @dermen * Add grid to make trends more visible as suggested by @dermen * Set libtbx dispatcher name `libtbx.resource_monitor_plot` for plot_logs * Set font.size 12 (16 is big), and locally to not affect any other plot * Move resource monitor's `plot_log` thin wrapper to libtbx/command_line * Make `lilbtbx.resource_monitor_plot`'s prefix optional --------- Co-authored-by: Nicholas K Sauter Co-authored-by: dermen --- .azure-pipelines/py2_syntax_exceptions.txt | 1 + libtbx/command_line/resource_monitor_plot.py | 17 + libtbx/resource_monitor.py | 469 +++++++++++++++++++ xfel/merging/application/monitor/__init__.py | 0 xfel/merging/application/monitor/factory.py | 11 + xfel/merging/application/monitor/monitor.py | 36 ++ xfel/merging/application/phil/phil.py | 26 +- 7 files changed, 559 insertions(+), 1 deletion(-) create mode 100644 libtbx/command_line/resource_monitor_plot.py create mode 100644 libtbx/resource_monitor.py create mode 100644 xfel/merging/application/monitor/__init__.py create mode 100644 xfel/merging/application/monitor/factory.py create mode 100644 xfel/merging/application/monitor/monitor.py diff --git a/.azure-pipelines/py2_syntax_exceptions.txt b/.azure-pipelines/py2_syntax_exceptions.txt index 4a70a6bf1c..7be5254be5 100644 --- a/.azure-pipelines/py2_syntax_exceptions.txt +++ b/.azure-pipelines/py2_syntax_exceptions.txt @@ -2,6 +2,7 @@ crys3d/hklviewer/webbrowser_messenger_py3.py crys3d/hklviewer/xtriage_runner.py crys3d/regression/tst_websocket.py libtbx/auto_build/conda_build/create_custom_bin.py +libtbx/resource_monitor.py serialtbx/util/energy_scan_notch_finder.py xfel/ui/components/xfel_gui_init.py xfel/ui/components/ebeam_plotter.py diff --git a/libtbx/command_line/resource_monitor_plot.py b/libtbx/command_line/resource_monitor_plot.py new file mode 100644 index 0000000000..cc9071e429 --- /dev/null +++ b/libtbx/command_line/resource_monitor_plot.py @@ -0,0 +1,17 @@ +# LIBTBX_SET_DISPATCHER_NAME libtbx.resource_monitor_plot +from __future__ import division + +import argparse +import inspect + +from libtbx.resource_monitor import plot_logs + + +if __name__ == '__main__': # make the plot in case the original monitor failed + parser = argparse.ArgumentParser(description=str(inspect.getdoc(plot_logs))) + parser.add_argument('prefix', nargs='?', type=str, default='monitor*.log', + help='Glob matching all log files to be plotted') + parser.add_argument('-o', '--output', type=str, default='monitor.png', + help='Filepath to save the final plot under') + args = parser.parse_args() + plot_logs(log_glob=args.prefix, save_path=args.output) diff --git a/libtbx/resource_monitor.py b/libtbx/resource_monitor.py new file mode 100644 index 0000000000..0c33962378 --- /dev/null +++ b/libtbx/resource_monitor.py @@ -0,0 +1,469 @@ +from __future__ import division + +from collections import UserDict +from contextlib import ContextDecorator +from dataclasses import astuple, dataclass +from datetime import datetime, timedelta +from enum import Enum +from functools import cached_property +from glob import glob +import itertools +import logging +from pathlib import Path +import platform +import re +import os +from statistics import mean +import subprocess +import threading +import time +from typing import Iterable, Type, Union + +import matplotlib.pyplot as plt +from matplotlib.gridspec import GridSpec +import numpy as np + +from libtbx.mpi4py import MPI + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~ TYPING AND UTILITY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # + + +comm = MPI.COMM_WORLD +PathLike = Union[str, bytes, os.PathLike] + + +def _mkdir_if_missing(path: PathLike) -> None: + path: Path = Path(path) + if comm.rank == 0: + if dir_name := Path(path).parent: + dir_name.mkdir(parents=True, exist_ok=True) + comm.barrier() + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LOGGING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # + + +class ResourceLogManager: + """Create appropriate resource logger for each rank and control its format""" + date_fmt = '%Y-%m-%d %H:%M:%S,%f' # exposed logging default, do not change + fmt = '%(asctime)s - %(message)s' + formatter = logging.Formatter(fmt=fmt) + line_regex = re.compile( + r'(\d{2,4}-\d\d-\d\d \d\d:\d\d:\d\d,\d+) - ' + r'ResourceStats\(cpu_usage=(-?\d+\.?\d*), ?cpu_memory=(-?\d+\.?\d*), ?' + r'gpu_usage=(-?\d+\.?\d*), ?gpu_memory=(-?\d+\.?\d*)') + + def __init__(self, logger_name: str) -> None: + self.log = logging.getLogger(logger_name) + + def get_file_logger(self, file_path: PathLike) -> logging.Logger: + self.log.setLevel(logging.DEBUG) + file_handler = logging.FileHandler(filename=file_path) + file_handler.setLevel(logging.DEBUG) + file_handler.setFormatter(self.formatter) + self.log.addHandler(file_handler) + return self.log + + def get_null_logger(self) -> logging.Logger: + self.log.setLevel(logging.CRITICAL + 1) + self.log.addHandler(logging.NullHandler()) + return self.log + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ STORING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # + + +class PerCentFloat(float): + """Convenience wrapper that clamps float between 0 and 100""" + def __new__(cls, value) -> 'PerCentFloat': + return float.__new__(float, max(min(float(value), 100.0), 0.0)) + + +@dataclass +class ResourceStats: + """Convenient dataclass used to pass info about CPU/GPU usage/memory""" + cpu_usage: PerCentFloat = 0.0 + cpu_memory: PerCentFloat = 0.0 + gpu_usage: PerCentFloat = 0.0 + gpu_memory: PerCentFloat = 0.0 + + def __post_init__(self): + for attr in ['cpu_usage', 'cpu_memory', 'gpu_usage', 'gpu_memory']: + setattr(self, attr, PerCentFloat(getattr(self, attr))) + + @property + def vector(self) -> np.ndarray: + return np.array(list(astuple(self)), dtype=float) + + def __add__(self, other: 'ResourceStats') -> 'ResourceStats': + return self.__class__(*(self.vector + other.vector)) # noqa + + def __mul__(self, other: float) -> 'ResourceStats': + return self.__class__(*(self.vector * other)) # noqa + + def __truediv__(self, other: float) -> 'ResourceStats': + return self.__class__(*(self.vector / other)) # noqa + + +try: + _UD = UserDict[datetime, ResourceStats] +except TypeError: + _UD = UserDict # Needed for PyVer < 3.9 +class ResourceStatsHistory(_UD): + """Store and easily handle a dictionary of datetime-ResourceStats pairs""" + + @classmethod + def from_file(cls, path: PathLike) -> 'ResourceStatsHistory': + new = cls() + with open(path, 'r') as file: + for line in file.readlines(): + if match := ResourceLogManager.line_regex.match(line): + t = datetime.strptime(match.group(1), ResourceLogManager.date_fmt) + new[t] = ResourceStats(*match.group(2, 3, 4, 5)) + return new + + def get_deltas_array(self) -> np.ndarray: # result in minutes + times = np.array(list(self.keys()), dtype=np.datetime64) + return (times - times[0]) / np.timedelta64(1, 'm') \ + if times.size else np.empty((0,), dtype=np.float64) + + def get_stats_array(self, key: str) -> np.ndarray: + return np.array([getattr(u, key) for u in self.values()]) + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PROBING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # + + +class ResourceProbeException(OSError): + """Raised if a `ResourceProbe` fails during `get_resource_stats()`""" + + +class NoSuitableResourceProbeException(OSError): + """Raised if all of available `ResourceProbe`s fail `get_resource_stats()`""" + + +class BaseResourceProbeType(type): + """Metaclass that implements automatic probe `REGISTRY` and `discover`y""" + REGISTRY: dict + + def __new__(mcs, *args, **kwargs) -> Union[Type['BaseCPUResourceProbe'], + Type['BaseGPUResourceProbe']]: + new_cls = type.__new__(mcs, *args, **kwargs) + if kind := getattr(new_cls, 'kind', ''): + mcs.REGISTRY[kind] = new_cls + return new_cls + + @classmethod + def discover(mcs) -> Union[Type['BaseCPUResourceProbe'], + Type['BaseGPUResourceProbe']]: + for _, probe_class in mcs.REGISTRY.items(): + try: + probe_instance = probe_class() + _ = probe_instance.get_resource_stats() + except ResourceProbeException: + continue + else: + return probe_class + raise NoSuitableResourceProbeException + + +class DummyResourceProbe: + kind = 'dummy' + + def get_name(self) -> str: # noqa + return 'unknown' + + def get_resource_stats(self) -> ResourceStats: # noqa + return ResourceStats(-1., -1., -1., -1.) + + +class CPUResourceProbeType(BaseResourceProbeType): + """Metaclass for CPU resource probes""" + REGISTRY = {} + + +class BaseCPUResourceProbe(metaclass=CPUResourceProbeType): + """ + Base class for CPU resource probes to be inherited by all CPU probes. + Every subclass should define `kind`, `get_name()`, `get_resource_stats()`. + """ + kind = None + + def get_name(self) -> str: # noqa + return platform.node() + + +class PsutilCPUResourceProbe(BaseCPUResourceProbe): + """CPU resource probe that attempts collecting CPU usage via psutil""" + kind = 'psutil' + + def __init__(self) -> None: + try: + import psutil + except ImportError as e: + raise ResourceProbeException from e + self.process = psutil.Process() + + def get_resource_stats(self) -> ResourceStats: + cpu_usage = PerCentFloat(self.process.cpu_percent(interval=None)) + cpu_memory = PerCentFloat(self.process.memory_percent()) + return ResourceStats(cpu_usage=cpu_usage, cpu_memory=cpu_memory) + + +class DummyCPUResourceProbe(BaseCPUResourceProbe, DummyResourceProbe): + """CPU resource probe that reports dummy data when no good probe is found""" + kind = 'dummy' + + +class GPUResourceProbeType(BaseResourceProbeType): + """Metaclass for GPU resource probes""" + REGISTRY = {} + + +class BaseGPUResourceProbe(metaclass=GPUResourceProbeType): + """ + Base class for GPU resource probes to be inherited by all GPU probes + Every subclass should define `kind`, `get_name()`, `get_resource_stats()`. + """ + kind = None + + +class NvidiaGPUResourceProbe(BaseGPUResourceProbe): + """GPU resource probe that attempts collecting GPU resource via nvidia-smi""" + kind = 'Nvidia' + + def get_name(self) -> str: # noqa + args = ['nvidia-smi', '--list-gpus'] + out = subprocess.run(args, stdout=subprocess.PIPE).stdout.decode('utf-8') + return out.strip() + + def get_resource_stats(self) -> ResourceStats: # noqa + args = ['nvidia-smi', + '--query-gpu=utilization.gpu,memory.used,memory.total', + '--format=csv,noheader,nounits'] + try: + out = subprocess.run(args, stdout=subprocess.PIPE).stdout.decode('utf-8') + values = [float(v) for v in out.replace(',', ' ').strip().split()] + gpu_usage = PerCentFloat(mean(values[::3])) + gpu_memory = PerCentFloat(100. * mean(values[1::3]) / mean(values[2::3])) + return ResourceStats(gpu_usage=gpu_usage, gpu_memory=gpu_memory) + except (FileNotFoundError, ValueError) as e: + raise ResourceProbeException from e + + +class DummyGPUResourceProbe(BaseGPUResourceProbe, DummyResourceProbe): + """CPU resource probe that reports dummy data when no good probe is found""" + kind = 'dummy' + + +class RankInfo: + """Manage info about this and neighbor ranks using auto-discovered probes""" + def __init__(self) -> None: + self.rank = comm.rank + self.cpu_probe = CPUResourceProbeType.discover()() + self.gpu_probe = GPUResourceProbeType.discover()() + self.node = self.cpu_probe.get_name() + self.gpu = self.gpu_probe.get_name() + neighborhood = comm.allgather((self.rank, self.node, self.gpu)) + self.same_node_ranks = [r for r, n, g in neighborhood if n == self.node] + self.same_gpu_ranks = [r for r, n, g in neighborhood if g == self.gpu] + self.is_gpu_ambassador = self.rank == min(self.same_gpu_ranks) + self.is_node_ambassador = self.rank == min(self.same_node_ranks) + + def get_rank_resource_stats(self) -> ResourceStats: + cpu_resource_stats = self.cpu_probe.get_resource_stats() + gpu_stats = self.gpu_probe.get_resource_stats() + return cpu_resource_stats + gpu_stats + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MONITORING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # + + +class ResourceMonitor(ContextDecorator): + """ + Collect and log information about CPU & GPU resources in decorated processes. + In each case the information is limited to single rank to avoid mpi comm. + This class can be used in several ways listed below: + + - As a decorator – to monitor every call of a given function, decorate the + function definition itself. The monitor will start every time the function + is called and stop every time the function is terminated: + ``` + @ResourceMonitor(*args) + def function_to_be_monitored() + stuff_to_be_timed() + ``` + + - As a context manager – to monitor a part of the code, place it withing + a context manager using a `with` statement. The monitor will start at the + start of the `with` block and terminate at the end of the `with` block: + ``` + with ResourceMonitor(*args): + stuff_to_be_timed() + ``` + + - As a standalone instance – for more advanced or customizable application, + the context manager can be manually instantiated, started, stopped, etc. + The following would be roughly equivalent to context manager approach: + ``` + rm = ResourceMonitor(*args): + try: + um.start() + stuff_to_be_timed() + finally: + self.stop() + ``` + """ + + class Detail(Enum): + node = 'node' + rank = 'rank' + rank0 = 'rank0' + none = 'none' + + def __init__(self, + detail: str = 'rank', + period: float = 5.0, + plot: bool = True, + prefix: str = 'monitor', + write: bool = True, + ) -> None: + self.active: bool = False + self.daemon: threading.Thread = None + self.detail: 'ResourceMonitor.Detail' = self.Detail(detail) + self.period: float = period # <5 sec. de-prioritizes sub-procs & they stop + self.plot: bool = plot + self.prefix: PathLike = prefix if prefix else 'monitor' + self.write: bool = write + self.rank_info: RankInfo = RankInfo() + _mkdir_if_missing(prefix) + logger_name = 'libtbx.resource_monitor.' + Path(self.prefix).name + self.log_manager = ResourceLogManager(logger_name) + self.log: logging.Logger = self.get_logger() + self.log.info(f'Collecting CPU stats with {self.rank_info.cpu_probe.kind=}') + self.log.info(f'Collecting GPU stats with {self.rank_info.gpu_probe.kind=}') + self.resource_stats_history = ResourceStatsHistory() + + def __enter__(self) -> None: + self.start() + + def __exit__(self, exc_type, exc_val, exc_tb) -> None: + self.stop() + + @property + def resource_stats(self) -> ResourceStats: + return { + self.Detail.node: self.rank_info.get_rank_resource_stats, + self.Detail.rank: self.rank_info.get_rank_resource_stats, + self.Detail.rank0: self.rank_info.get_rank_resource_stats, + self.Detail.none: (lambda _: None) + }[self.detail]() + + @cached_property + def is_logging(self) -> bool: + return { + self.Detail.node: self.rank_info.is_node_ambassador, + self.Detail.rank: True, + self.Detail.rank0: self.rank_info.rank == 0, + self.Detail.none: False + }[self.detail] + + @cached_property + def log_path(self) -> str: + return { + self.Detail.node: f'{self.prefix}_{self.rank_info.node}.log', + self.Detail.rank: f'{self.prefix}_{self.rank_info.rank}.log', + self.Detail.rank0: f'{self.prefix}.log', + self.Detail.none: None + }[self.detail] + + def get_logger(self) -> logging.Logger: + return self.log_manager.get_file_logger(self.log_path) \ + if self.is_logging and self.write else self.log_manager.get_null_logger() + + def log_current_resource_stats(self) -> None: + """Get current usage stats and log + save them""" + resource_stats = self.resource_stats + if self.is_logging: + self.resource_stats_history[datetime.now()] = resource_stats + self.log.info(msg=f'{resource_stats}') + + def log_resource_stats_every_period(self) -> None: + """Call in thread only, can be stopped only upon `self.active` = False""" + start = datetime.now() + log_iter_counter = itertools.count(start=0, step=1) + for log_iter in log_iter_counter: + self.snapshot() + next_iter_time = start + timedelta(seconds=self.period) * (log_iter + 1) + time.sleep(max((next_iter_time - datetime.now()).total_seconds(), 0)) + if not self.active: + break + + def start(self) -> None: + """Call to start probing resources""" + self.active = True + self.daemon = threading.Thread(target=self.log_resource_stats_every_period, + args=(), daemon=True) + self.daemon.start() + + def snapshot(self) -> None: + """Call to probe resources in current single moment only""" + threading.Thread(target=self.log_current_resource_stats, args=()).start() + + def stop(self) -> None: + """Call to stop probing resources""" + self.active = False + if self.plot: + self.plot_resource_stats_history() + + def plot_resource_stats_history(self) -> None: + resource_stats_histories = comm.gather(self.resource_stats_history, root=0) + if self.rank_info.rank == 0: + resource_stats_histories = [h for h in resource_stats_histories if h] + rsa = ResourceStatsArtist() + rsa.plot(resource_stats_histories, f'{self.prefix}.png') + + +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PLOTTING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # + + +class ResourceStatsArtist: + def __init__(self) -> None: + self.colormap = plt.get_cmap('tab10') + self.colormap_period = 10 + self.fig = plt.figure(tight_layout=True, figsize=(12, 10)) + gs = GridSpec(4, 1, figure=self.fig, hspace=0, wspace=0) + self.ax_cu = self.fig.add_subplot(gs[0, 0]) # cu = (c)pu (u)sage + self.ax_cm = self.fig.add_subplot(gs[1, 0], sharex=self.ax_cu) + self.ax_gu = self.fig.add_subplot(gs[2, 0], sharex=self.ax_cu) + self.ax_gm = self.fig.add_subplot(gs[3, 0], sharex=self.ax_cu) + + def plot(self, + resource_stats_histories: Iterable[ResourceStatsHistory], + save_path: PathLike = None, + ) -> None: + axes = self.ax_cu, self.ax_cm, self.ax_gu, self.ax_gm + stats = ['cpu_usage', 'cpu_memory', 'gpu_usage', 'gpu_memory'] + labels = ['CPU usage', 'CPU memory', 'GPU usage', 'GPU memory'] + for i, rsh in enumerate(resource_stats_histories): + minutes = rsh.get_deltas_array() + color = self.colormap(i % self.colormap_period) + for ax, stat in zip(axes, stats): + ax.plot(minutes, rsh.get_stats_array(stat), color=color) + self.ax_gm.set_xlabel('Time since first probe [min]', fontsize=12) + for ax, label in zip(axes, labels): + ax.grid(True) + ax.tick_params(axis='both', which='major', labelsize=12) + ax.set_ylabel(label + ' [%]', fontsize=12) + if save_path: + self.fig.savefig(f'{save_path}') + else: + plt.show() + + +def plot_logs(log_glob: PathLike, save_path: PathLike) -> None: + """Manually plot if ResourceMonitor terminates unexpectedly i.e.due to OOM""" + histories = [ResourceStatsHistory.from_file(Path(p)) for p in glob(log_glob)] + rsa = ResourceStatsArtist() + rsa.plot(resource_stats_histories=histories, save_path=save_path) diff --git a/xfel/merging/application/monitor/__init__.py b/xfel/merging/application/monitor/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xfel/merging/application/monitor/factory.py b/xfel/merging/application/monitor/factory.py new file mode 100644 index 0000000000..973531a17a --- /dev/null +++ b/xfel/merging/application/monitor/factory.py @@ -0,0 +1,11 @@ +from __future__ import absolute_import, division, print_function + +from xfel.merging.application.monitor.monitor import MonitorWorker +from xfel.merging.application.worker import factory as factory_base + + +class factory(factory_base): + """Factory class for monitoring CPU and GPU resources in the background""" + @staticmethod + def from_parameters(params, additional_info=None, mpi_helper=None, mpi_logger=None): + return [MonitorWorker(params, mpi_helper, mpi_logger)] diff --git a/xfel/merging/application/monitor/monitor.py b/xfel/merging/application/monitor/monitor.py new file mode 100644 index 0000000000..feebf422f5 --- /dev/null +++ b/xfel/merging/application/monitor/monitor.py @@ -0,0 +1,36 @@ +from __future__ import absolute_import, division, print_function + +from libtbx.resource_monitor import ResourceMonitor +from xfel.merging.application.worker import worker + + +resource_monitor = None + + +class MonitorWorker(worker): + """Monitor and plot CPU and GPU resources during `cctbx.xfel.merge`""" + + def __init__(self, params, mpi_helper=None, mpi_logger=None): + kwargs = dict(params=params, mpi_helper=mpi_helper, mpi_logger=mpi_logger) + super(MonitorWorker, self).__init__(**kwargs) + + def __repr__(self): + return 'Monitor CPU and GPU resources' + + def run(self, experiments, reflections): + global resource_monitor + if resource_monitor is None: + resource_monitor = ResourceMonitor( + detail=self.params.monitor.detail, + period=self.params.monitor.period, + plot=self.params.monitor.plot, + prefix=self.params.monitor.prefix, + write=self.params.monitor.write, + ) + if resource_monitor.active: + self.logger.log('Stopping resource monitor') + resource_monitor.stop() + else: # if resource_monitor.active == False + self.logger.log('Starting resource monitor') + resource_monitor.start() + return experiments, reflections diff --git a/xfel/merging/application/phil/phil.py b/xfel/merging/application/phil/phil.py index f8eba14180..26aa16b010 100644 --- a/xfel/merging/application/phil/phil.py +++ b/xfel/merging/application/phil/phil.py @@ -691,6 +691,29 @@ } """ +monitor_phil = """ +monitor { + detail = *rank node rank0 none + .type = choice + .help = Detail of data to be collected: from every rank, from rank 0 only, + .help = from first rank on every node, or none. + period = 5.0 + .type = float + .help = Interval between subsequent resource statistics checks in seconds. + .help = Short periods might lead to inconsistent logging. + plot = True + .type = bool + .help = Plot the resource usage history after the monitor is stopped. + prefix = monitor + .type = str + .help = Filename prefix for log files and summary plot. + write = True + .type = bool + .help = Write collected resource information to log files. +} +""" + + # A place to override any defaults included from elsewhere program_defaults_phil_str = """ modify.cosym.use_curvatures=False @@ -698,7 +721,8 @@ master_phil = dispatch_phil + input_phil + tdata_phil + filter_phil + modify_phil + \ select_phil + scaling_phil + postrefinement_phil + merging_phil + \ - output_phil + statistics_phil + group_phil + lunus_phil + publish_phil + diffbragg_phil + output_phil + statistics_phil + group_phil + lunus_phil + \ + publish_phil + diffbragg_phil + monitor_phil import os, importlib custom_phil_pathstr = os.environ.get('XFEL_CUSTOM_WORKER_PATH') From 3f84e12b8ae2cc9ec354122b231f0c69c01155f9 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Thu, 13 Jun 2024 13:52:07 -0700 Subject: [PATCH 530/748] Bugfix: work correctly when there is longer bond in the model than max_distance_between_connecting_atoms. Enabling tests. --- cctbx/geometry_restraints/manager.py | 6 ++---- cctbx/regression/tst_grm_modifications.py | 9 +++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/cctbx/geometry_restraints/manager.py b/cctbx/geometry_restraints/manager.py index c43778d9d6..e3c705d1d4 100644 --- a/cctbx/geometry_restraints/manager.py +++ b/cctbx/geometry_restraints/manager.py @@ -1060,12 +1060,10 @@ def add_new_bond_restraints_in_place(self, proxies, sites_cart, max_p_distance = distance_model bonded_distance_cutoff = max(bonded_distance_cutoff, max_p_distance) - bonded_distance_cutoff = max( - [existing_max_bonded_distance, - max_p_distance, - max_distance_between_connecting_atoms]) bonded_distance_cutoff = min(bonded_distance_cutoff, max_distance_between_connecting_atoms)+0.1 + bonded_distance_cutoff = max(bonded_distance_cutoff, + existing_max_bonded_distance) t2 = time.time() # print("bonded_distance_cutoff", bonded_distance_cutoff) # make asu mappings diff --git a/cctbx/regression/tst_grm_modifications.py b/cctbx/regression/tst_grm_modifications.py index 402afd4102..707e8d4db2 100644 --- a/cctbx/regression/tst_grm_modifications.py +++ b/cctbx/regression/tst_grm_modifications.py @@ -338,7 +338,7 @@ def exercise_add_new_bond_when_long_bond_across_ASU(mon_lib_srv, ener_lib): assert not geometry.is_bonded_atoms(0,3) assert not geometry.is_bonded_atoms(3,0) # DL: this will fail - #geometry.add_new_bond_restraints_in_place([proxy], xrs.sites_cart()) + geometry.add_new_bond_restraints_in_place([proxy], xrs.sites_cart()) # DL: this works geometry.add_new_bond_restraints_in_place([proxy], xrs.sites_cart(), max_distance_between_connecting_atoms=10) @@ -370,9 +370,10 @@ def exercise_add_super_long_bond(mon_lib_srv, ener_lib): max_distance_between_connecting_atoms=5) assert not geometry.is_bonded_atoms(0,1) assert not geometry.is_bonded_atoms(1,0) - # !!! This will fail, but should not. Left for future investigation. - # geometry.add_new_bond_restraints_in_place([proxy], xrs.sites_cart(), - # max_distance_between_connecting_atoms=30) + geometry.add_new_bond_restraints_in_place([proxy], xrs.sites_cart(), + max_distance_between_connecting_atoms=30) + assert geometry.is_bonded_atoms(0,1) + assert geometry.is_bonded_atoms(1,0) def exercise_bond_near_symmetry(mon_lib_srv, ener_lib): """ Making bond near symmetry mate: From 01b0860c0294c87854f6da5343b902e23fb27290 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 13 Jun 2024 22:38:41 -0700 Subject: [PATCH 531/748] Cleanup --- cctbx/regression/tst_grm_modifications.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/cctbx/regression/tst_grm_modifications.py b/cctbx/regression/tst_grm_modifications.py index 707e8d4db2..f7ef72e3fe 100644 --- a/cctbx/regression/tst_grm_modifications.py +++ b/cctbx/regression/tst_grm_modifications.py @@ -321,13 +321,15 @@ def exercise_add_new_bond_restraint_in_place(mon_lib_srv, ener_lib): def exercise_add_new_bond_when_long_bond_across_ASU(mon_lib_srv, ener_lib): ''' raw_records4b is same as raw_records4, except that CE is in another ASU - --> 6A long bond to SD --> this will choke the call of + --> 6A long bond to SD --> this broke the call of all_bonds_asu_table.add_pair_sym_table(self.shell_sym_tables[0]) - in add_new_bond_restraints_in_place - root of the issue is that there is >5 A long bond (i.e. longer than the + in add_new_bond_restraints_in_place() method. + Reason for the fail: there is >5 A long bond (i.e. longer than the default of max_distance_between_connecting_atoms, which is 5) between atoms where one atom is in another ASU - see also test + see also test phenix_regression/mmtbx/tst_pdb_interpretation_3.py + Fixed with + https://github.com/cctbx/cctbx_project/commit/3f84e12b8ae2cc9ec354122b231f0c69c01155f9 ''' geometry, xrs = make_initial_grm(mon_lib_srv, ener_lib, raw_records4b) @@ -337,9 +339,7 @@ def exercise_add_new_bond_when_long_bond_across_ASU(mon_lib_srv, ener_lib): weight=3000) assert not geometry.is_bonded_atoms(0,3) assert not geometry.is_bonded_atoms(3,0) - # DL: this will fail geometry.add_new_bond_restraints_in_place([proxy], xrs.sites_cart()) - # DL: this works geometry.add_new_bond_restraints_in_place([proxy], xrs.sites_cart(), max_distance_between_connecting_atoms=10) @@ -735,3 +735,4 @@ def exercise(): if (__name__ == "__main__"): exercise() + print("OK") From 038c5a36cb572bd5f730b2ccb36c0bdf99835c14 Mon Sep 17 00:00:00 2001 From: Nicholas K Sauter Date: Fri, 14 Jun 2024 17:31:34 -0700 Subject: [PATCH 532/748] Refactor to reuse class API in other code. Makes the tdata globally available for use in the new ucinline worker of psii_spread. --- xfel/merging/application/tdata/cell_listing.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xfel/merging/application/tdata/cell_listing.py b/xfel/merging/application/tdata/cell_listing.py index 1164b6b940..51e69669ad 100644 --- a/xfel/merging/application/tdata/cell_listing.py +++ b/xfel/merging/application/tdata/cell_listing.py @@ -28,14 +28,14 @@ def run(self, all_experiments, all_reflections): comm = self.mpi_helper.comm MPI = self.mpi_helper.MPI - global_results = comm.reduce(all_results, MPI.SUM, 0) + self.global_results = comm.reduce(all_results, MPI.SUM, 0) if self.mpi_helper.rank == 0: file_cells = open("%s.tdata"%(self.params.tdata.output_path), "w") - for result in global_results: + for result in self.global_results: line = str(result) + "\n" file_cells.write(line) file_cells.close() - self.logger.main_log("output a list of %d unit cells"%len(global_results)) + self.logger.main_log("output a list of %d unit cells"%len(self.global_results)) # END OUTPUT ALL UNIT CELLS return all_experiments, all_reflections From c0527f9938cb6cc8295b17cd2b3c8d9029c753f9 Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 20 Jun 2024 07:31:33 -0700 Subject: [PATCH 533/748] Reset model after shifting coordinates --- iotbx/map_model_manager.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iotbx/map_model_manager.py b/iotbx/map_model_manager.py index 4f3310ff57..b3c42120f0 100644 --- a/iotbx/map_model_manager.py +++ b/iotbx/map_model_manager.py @@ -3603,6 +3603,8 @@ def shift_any_model_to_match(self, model, map_manager = None, shift_cart = coordinate_shift, crystal_symmetry=map_manager.crystal_symmetry()) + model.reset_after_changing_hierarchy() + if set_unit_cell_crystal_symmetry and self.map_manager(): self.set_model_symmetries_and_shift_cart_to_match_map(model) From 41bef9ac1cda9115402fdfc0fef326b74461f9ed Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 20 Jun 2024 07:56:09 -0700 Subject: [PATCH 534/748] Undo reset --- iotbx/map_model_manager.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/iotbx/map_model_manager.py b/iotbx/map_model_manager.py index b3c42120f0..4f3310ff57 100644 --- a/iotbx/map_model_manager.py +++ b/iotbx/map_model_manager.py @@ -3603,8 +3603,6 @@ def shift_any_model_to_match(self, model, map_manager = None, shift_cart = coordinate_shift, crystal_symmetry=map_manager.crystal_symmetry()) - model.reset_after_changing_hierarchy() - if set_unit_cell_crystal_symmetry and self.map_manager(): self.set_model_symmetries_and_shift_cart_to_match_map(model) From 66dd4ca857c409d8525ab86345757fb9ed6fcb8e Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Thu, 20 Jun 2024 15:01:19 -0700 Subject: [PATCH 535/748] Sync with DIALS API changes See dials/dials#2679 https://github.com/dials/dials/pull/2679 --- xfel/merging/application/balance/load_balancer.py | 2 +- xfel/merging/application/integrate/integrate.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xfel/merging/application/balance/load_balancer.py b/xfel/merging/application/balance/load_balancer.py index 9b7c61e7ca..c335c2640d 100644 --- a/xfel/merging/application/balance/load_balancer.py +++ b/xfel/merging/application/balance/load_balancer.py @@ -281,7 +281,7 @@ def first(lst, test): recv_ids = set([e.identifier for e in received_expt_i]) assert current_ids.isdisjoint(recv_ids) experiments.extend(received_expt_i) - flex.reflection_table.concat([reflections, received_refl_i]) + reflections = flex.reflection_table.concat([reflections, received_refl_i]) self.logger.log_step_time("LB_EXPTS_AND_REFLS_ALLTOALL", True) diff --git a/xfel/merging/application/integrate/integrate.py b/xfel/merging/application/integrate/integrate.py index c1de75414a..8231ae807f 100644 --- a/xfel/merging/application/integrate/integrate.py +++ b/xfel/merging/application/integrate/integrate.py @@ -56,7 +56,7 @@ def run(self, experiments, reflections): all_integrated_expts.append(expt) if all_integrated_refls: - flex.reflection_table.concat([all_integrated_refls, integrated]) + all_integrated_refls = flex.reflection_table.concat([all_integrated_refls, integrated]) else: all_integrated_refls = integrated From e6a8401fc1343d52d6a3fedc70b71a1882da3521 Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Thu, 20 Jun 2024 17:42:57 -0700 Subject: [PATCH 536/748] Alow some slack --- mmtbx/solvent/ordered_solvent.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mmtbx/solvent/ordered_solvent.py b/mmtbx/solvent/ordered_solvent.py index 2e18dce525..0f558599d1 100644 --- a/mmtbx/solvent/ordered_solvent.py +++ b/mmtbx/solvent/ordered_solvent.py @@ -380,8 +380,8 @@ def filter_by_distance(model, fix_altlocs_and_filter_was_run, dist_min=1.8, altloc_j = aj.parent().altloc d = ai.distance(aj) if fix_altlocs_and_filter_was_run: - if(d0 and len(altloc_j)>0 + if(abs(d-dist_min)>1.e-3): # assumes fix_altlocs_and_filter was run, or else remove ai + assert len(altloc_i)>0 and len(altloc_j)>0, [d, dist_min] # Check water inside shell dist_min < dist < dist_max found = False for j in selection_shell: From 96441f855c32e82d02c3ba66d3b090e9a038d1f1 Mon Sep 17 00:00:00 2001 From: Robert Oeffner Date: Fri, 21 Jun 2024 15:13:30 +0100 Subject: [PATCH 537/748] hopefully a fix to crash on mac when opening documentation for HKLviewer --- crys3d/hklviewer/HKLviewer.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crys3d/hklviewer/HKLviewer.py b/crys3d/hklviewer/HKLviewer.py index 54346ebc9b..5658d19c17 100644 --- a/crys3d/hklviewer/HKLviewer.py +++ b/crys3d/hklviewer/HKLviewer.py @@ -577,19 +577,19 @@ def __init__(self, thisapp, isembedded=False): #, cctbxpython=None): def onOpenHelpFile(self): - QDesktopServices.openUrl("http://cci.lbl.gov/docs/cctbx/doc_hklviewer/") + QDesktopServices.openUrl(QUrl("https://cci.lbl.gov/docs/cctbx/doc_hklviewer/")) def onOpenTutorialHelpFile(self): - QDesktopServices.openUrl("http://cci.lbl.gov/docs/cctbx/tuto_hklviewer/") + QDesktopServices.openUrl(QUrl("https://cci.lbl.gov/docs/cctbx/tuto_hklviewer/")) def onOpenCCTBXwebsite(self): - QDesktopServices.openUrl("http://cci.lbl.gov/docs/cctbx/") + QDesktopServices.openUrl(QUrl("https://cci.lbl.gov/docs/cctbx/")) def onNGLmouseControlswebsite(self): - QDesktopServices.openUrl("http://nglviewer.org/ngl/api/manual/interaction-controls.html#controls") + QDesktopServices.openUrl(QUrl("https://nglviewer.org/ngl/api/manual/interaction-controls.html#controls")) def onPresetbtn_click(self): From 20d1113d122ef7823c2882b5dfc0048eb85c3269 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Fri, 21 Jun 2024 14:58:02 -0700 Subject: [PATCH 538/748] typo --- mmtbx/monomer_library/pdb_interpretation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index 64992970cf..beb42dcb76 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -3885,7 +3885,7 @@ def raise_if_corrupt(link_resolution): def _check_for_capitalised_element(self): for atom in self.pdb_hierarchy.atoms(): - if atom.element==atom.element.upper(): + if atom.element!=atom.element.upper(): atom.element=atom.element.upper() def __getstate__(self): From caf0e17c63742b918e5c826a945da78a677e72e0 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Fri, 21 Jun 2024 16:03:07 -0700 Subject: [PATCH 539/748] changes for upper --- mmtbx/ligands/electrons.py | 22 +++++++++---------- .../monomer_library/tst_pdb_interpretation.py | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/mmtbx/ligands/electrons.py b/mmtbx/ligands/electrons.py index e04a1966fe..efc417c008 100644 --- a/mmtbx/ligands/electrons.py +++ b/mmtbx/ligands/electrons.py @@ -54,21 +54,21 @@ def get_atom_database(): from mmtbx.ligands.chemistry import non_metal_indices atom_database = atoms() for i, element in enumerate(elements): - atom_database[element]={'number':i} + atom_database[element.upper()]={'number':i} for element, valence in zip(elements, valences): if valence>-1: - atom_database[element]['valence'] = valence + atom_database[element.upper()]['valence'] = valence for element, lone_pair in zip(elements, lone_pairs): if lone_pair>0: - atom_database[element]['lone pairs'] = lone_pair + atom_database[element.upper()]['lone pairs'] = lone_pair for i, element in enumerate(elements): if i not in non_metal_indices: - atom_database[element]['metal']=True + atom_database[element.upper()]['metal']=True if element in default_metal_charges: # atom_database['valence'] = default_metal_charges[element]*-1 - atom_database[element]['charge'] = default_metal_charges[element] + atom_database[element.upper()]['charge'] = default_metal_charges[element] else: - atom_database[element]['charge'] = None + atom_database[element.upper()]['charge'] = None atom_database['D']=atom_database['H'] return atom_database @@ -95,7 +95,7 @@ def get_atomic_number(self, element): return self.get(element.strip(), {}).get('number', 0) def is_metal(self, element): - return self.get(element.strip().capitalize(), {}).get('metal', False) + return self.get(element.strip(), {}).get('metal', False) def get_charge(self): return self.get(element.strip(), {}).get('charge', None) @@ -136,8 +136,8 @@ def __init__(self, assert e is not None, ' element %s not found' % atom.element metal = self.properties.is_metal(atom.element) if metal: - if atom.element in default_metal_charges: - self[atom.i_seq]=default_metal_charges[atom.element]*-1 + if atom.element.capitalize() in default_metal_charges: + self[atom.i_seq]=default_metal_charges[atom.element.capitalize()]*-1 # self[atom.i_seq]=None else: print(atom.quote()) @@ -264,8 +264,8 @@ def set_charges(self): atoms = self.hierarchy.atoms() for key, electrons in self.items(): element = atoms[key].element.strip() - if element in default_metal_charges: - self[key]=default_metal_charges[element]*-1 + if element.capitalize() in default_metal_charges: + self[key]=default_metal_charges[element.capitalize()]*-1 for atom in atoms: element = atom.element.strip() diff --git a/mmtbx/monomer_library/tst_pdb_interpretation.py b/mmtbx/monomer_library/tst_pdb_interpretation.py index d0999eb8f8..3c46ba98d7 100644 --- a/mmtbx/monomer_library/tst_pdb_interpretation.py +++ b/mmtbx/monomer_library/tst_pdb_interpretation.py @@ -2426,7 +2426,7 @@ def exercise_bad_custom_bonds(mon_lib_srv, ener_lib): expected = """ Custom bonds: bond: - atom 1: "HETATM 64 FE HEM A 154 .*. Fe " + atom 1: "HETATM 64 FE HEM A 154 .*. FE " atom 2: "ATOM 16 NE2 HIS A 93 .*. N " symmetry operation: x,y,z distance_model: 2.146 @@ -2436,7 +2436,7 @@ def exercise_bad_custom_bonds(mon_lib_srv, ener_lib): delta_slack: -0.046 sigma: 0.0100 bond: - atom 1: "HETATM 64 FE HEM A 154 .*. Fe " + atom 1: "HETATM 64 FE HEM A 154 .*. FE " atom 2: "HETATM 65 O MTO A 155 .*. O " symmetry operation: x,y,z distance_model: 2.164 From 3901ee2b27db9ef949bceac685fdb8a973d0c26c Mon Sep 17 00:00:00 2001 From: terwill Date: Sun, 23 Jun 2024 09:30:32 -0700 Subject: [PATCH 540/748] Catch tuple vs list --- iotbx/map_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iotbx/map_manager.py b/iotbx/map_manager.py index 8f980dea23..2727c3ec7c 100644 --- a/iotbx/map_manager.py +++ b/iotbx/map_manager.py @@ -2273,7 +2273,7 @@ def resample_on_different_grid(self, n_real = None, assert n_real or target_grid_spacing - if self.origin_shift_grid_units != (0,0,0): + if tuple(self.origin_shift_grid_units) != (0,0,0): return self._resample_on_different_grid_and_rebox(n_real = n_real, target_grid_spacing = target_grid_spacing) From 5d74467fa1765c335bd588e7811a881c0008b91d Mon Sep 17 00:00:00 2001 From: Pavel Date: Sun, 23 Jun 2024 19:51:49 -0700 Subject: [PATCH 541/748] Bug fix and make sure no lone water is added (no matching altloc) --- mmtbx/solvent/ordered_solvent.py | 50 +++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/mmtbx/solvent/ordered_solvent.py b/mmtbx/solvent/ordered_solvent.py index 0f558599d1..ff727c4e9a 100644 --- a/mmtbx/solvent/ordered_solvent.py +++ b/mmtbx/solvent/ordered_solvent.py @@ -23,6 +23,14 @@ def get_unique_altloc(exclude): if not l in exclude: return l +def get_unique_altloc2(available, exclude): + l = None + for l in available: + if l in [' ', '']: continue + if not l in exclude: + return l + return l + output_params_str = """ output_residue_name = HOH .type=str @@ -250,7 +258,9 @@ def score_atom(self, atom, min_cc, min_value): x=self.model_map.select(sel), y=self.data_map.select(sel)).coefficient() value_2 = self.data_map.eight_point_interpolation(site_frac) - result = cc > min_cc and value_2 > min_value*atom.occ + diff_map_val = self.difference_map.eight_point_interpolation(site_frac) + result = (cc > min_cc and value_2 > min_value*atom.occ) and \ + not (diff_map_val < -3) return group_args(result = result, cc=cc, value_2=value_2) def _estimate_diff_map_cutoff(self): @@ -286,6 +296,8 @@ def _estimate_diff_map_cutoff(self): if mean/2 > 3: cutoff = 3 def fix_altlocs_and_filter(model, dist_min=1.8, fix_only=False): + present_altlocs = list( + model.get_hierarchy().get_conformer_indices().index_altloc_mapping.keys()) sps = model.crystal_symmetry().special_position_settings() get_class = iotbx.pdb.common_residue_names_get_class only_model = model.get_hierarchy().only_model() @@ -318,8 +330,13 @@ def fix_altlocs_and_filter(model, dist_min=1.8, fix_only=False): remove_sel.extend(agi.atoms().extract_i_seq()) skip=True else: - new_altloc = get_unique_altloc(exclude=altlocs_inside+[agi.altloc]) - agj.altloc = new_altloc + new_altloc = get_unique_altloc2( + available = present_altlocs, + exclude = altlocs_inside+[agi.altloc]) + if new_altloc is not None: agj.altloc = new_altloc + else: + remove_sel.extend(agi.atoms().extract_i_seq()) + skip = True if skip: continue # altlocs_inside = [] @@ -328,8 +345,14 @@ def fix_altlocs_and_filter(model, dist_min=1.8, fix_only=False): # if agi.altloc in altlocs_inside or agi.altloc in [' ', '']: #print(ai.i_seq, selection_around_ai, altlocs_inside, [agi.altloc]) - new_altloc = get_unique_altloc(exclude=altlocs_inside+[agi.altloc]) - agi.altloc = new_altloc + #new_altloc = get_unique_altloc(exclude=altlocs_inside+[agi.altloc]) + new_altloc = get_unique_altloc2( + available = present_altlocs, + exclude = altlocs_inside+[agi.altloc]) + if new_altloc is not None: + agi.altloc = new_altloc + else: + remove_sel.extend(agi.atoms().extract_i_seq()) # if remove_sel.size() > 0 and not fix_only: remove_sel = ~flex.bool(model.size(), remove_sel) @@ -378,10 +401,15 @@ def filter_by_distance(model, fix_altlocs_and_filter_was_run, dist_min=1.8, for j in selection_around_ai_min: aj = atoms[j] altloc_j = aj.parent().altloc - d = ai.distance(aj) if fix_altlocs_and_filter_was_run: +<<<<<<< HEAD if(abs(d-dist_min)>1.e-3): # assumes fix_altlocs_and_filter was run, or else remove ai assert len(altloc_i)>0 and len(altloc_j)>0, [d, dist_min] +======= + if altloc_i =="" or altloc_i==" " or altloc_j =="" or altloc_j==" " or altloc_i==altloc_j: + remove_sel.extend(agi.atoms().extract_i_seq()) + +>>>>>>> 9e7c5df37e (Bug fix and make sure no lone water is added (no matching altloc)) # Check water inside shell dist_min < dist < dist_max found = False for j in selection_shell: @@ -436,7 +464,8 @@ def __init__(self, fmodel, self._call(msg="Find peaks", func=self._find_peaks) self._call(msg="Add new water", func=self._add_new_solvent) self._call(msg="Refine new water", func=self._refine) - self._call(msg="Filter (q & B)", func=self._filter_q_b) + self._call(msg="Filter (q & B)", func=self._filter_q_b) + self._call(msg="Filter (dist only)", func=self._filter_dist) #self._call(msg="Correct drifted", func=self._correct_drifted_waters) def _call(self, msg, func = None): @@ -493,6 +522,13 @@ def _filter_dist_fix_altlocs(self): dist_min = self.params.dist_min, dist_max = self.params.dist_max) + def _filter_dist(self): + self.model = filter_by_distance( + model = self.model, + fix_altlocs_and_filter_was_run = self.params.include_altlocs, + dist_min = self.params.dist_min, + dist_max = self.params.dist_max) + def _filter_q_b(self): self._filter(filter_occ=True, filter_adp=True) From 10f9eeb27233891273fff3a6df79dc94beb168b9 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sun, 23 Jun 2024 19:54:05 -0700 Subject: [PATCH 542/748] Bug fix and make sure no lone water is added (no matching altloc) --- mmtbx/solvent/ordered_solvent.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/mmtbx/solvent/ordered_solvent.py b/mmtbx/solvent/ordered_solvent.py index ff727c4e9a..56645bc406 100644 --- a/mmtbx/solvent/ordered_solvent.py +++ b/mmtbx/solvent/ordered_solvent.py @@ -402,14 +402,9 @@ def filter_by_distance(model, fix_altlocs_and_filter_was_run, dist_min=1.8, aj = atoms[j] altloc_j = aj.parent().altloc if fix_altlocs_and_filter_was_run: -<<<<<<< HEAD - if(abs(d-dist_min)>1.e-3): # assumes fix_altlocs_and_filter was run, or else remove ai - assert len(altloc_i)>0 and len(altloc_j)>0, [d, dist_min] -======= if altloc_i =="" or altloc_i==" " or altloc_j =="" or altloc_j==" " or altloc_i==altloc_j: remove_sel.extend(agi.atoms().extract_i_seq()) ->>>>>>> 9e7c5df37e (Bug fix and make sure no lone water is added (no matching altloc)) # Check water inside shell dist_min < dist < dist_max found = False for j in selection_shell: From 98bc43ca9182d3a79b1fb8f510832296128737e1 Mon Sep 17 00:00:00 2001 From: terwill Date: Mon, 24 Jun 2024 12:26:04 -0700 Subject: [PATCH 543/748] fix overwrite --- mmtbx/validation/holton_geometry_validation.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 85f3b31ca3..ff509e40cd 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -973,6 +973,7 @@ def get_model(info): if not info.dm: from iotbx.data_manager import DataManager info.dm = DataManager() + info.dm.set_overwrite(True) if not info.model: info.model = info.dm.get_model(info.filename) info.model.set_log(null_out()) @@ -982,7 +983,9 @@ def get_model(info): info.model.add_crystal_symmetry_if_necessary() if info.model.has_hd(): info.model.get_hierarchy().remove_hd(reset_i_seq=True) - if not os.path.isfile(info.filename): # write to it + if (not os.path.isfile(info.filename)) or \ + (not open(info.filename).read().strip()): + # write to it info.dm.write_model_file(info.model, info.filename) info.model.set_stop_for_unknowns(False) info.model.process(make_restraints=True) From 665b30bf196c9da379979a3c48f4b2e16bb4d681 Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Mon, 24 Jun 2024 13:46:42 -0700 Subject: [PATCH 544/748] XFEL GUI updates - Add filter for datasets in the datasets tab - Use medians in the energy tab - Bugfix for d_min in the runstats plot - Handle UNKWN for ensemble_refinement, which is the state if some jobs haven't finished in a job with multiple submitted job ids - More precision for the merging stats plot --- xfel/ui/components/ebeam_plotter.py | 12 ++++++------ xfel/ui/components/xfel_gui_init.py | 27 +++++++++++++++++++++++---- xfel/ui/db/job.py | 2 +- xfel/ui/db/merging_log_scraper.py | 2 +- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/xfel/ui/components/ebeam_plotter.py b/xfel/ui/components/ebeam_plotter.py index ed865790fd..2b79267f27 100644 --- a/xfel/ui/components/ebeam_plotter.py +++ b/xfel/ui/components/ebeam_plotter.py @@ -51,16 +51,16 @@ def compare_ebeams_with_fees(locfiles, runs=None, plot=True, use_figure=None, ma ebeams_wav = np.array(ebeams_wav) diffs_eV = fee_coms_eV - ebeam_eV - ebeam_eV_offsets.append(sum(diffs_eV)/len(diffs_eV)) + ebeam_eV_offsets.append(np.median(diffs_eV)) diffs_wav = fee_coms_wav - ebeams_wav - ebeam_wav_offsets.append(sum(diffs_wav)/len(diffs_wav)) + ebeam_wav_offsets.append(np.median(diffs_wav)) - mean_fee_eV = np.mean(fee_coms_eV) - mean_ebeam_eV = np.mean(ebeam_eV) + median_fee_eV = np.median(fee_coms_eV) + median_ebeam_eV = np.median(ebeam_eV) if plot: - ax.hist(ebeams_eV, alpha=0.5, bins=40, label=f'run {runs[i]} ebeams ({int(mean_ebeam_eV)} eV)') - ax.hist(fee_coms_eV, alpha=0.5, bins=40, label=f'run {runs[i]} FEE COMs ({int(mean_fee_eV)} eV)') + ax.hist(ebeams_eV, alpha=0.5, bins=40, label=f'run {runs[i]} ebeams ({round(median_ebeam_eV)} eV)') + ax.hist(fee_coms_eV, alpha=0.5, bins=40, label=f'run {runs[i]} FEE COMs ({round(median_fee_eV)} eV)') if plot: ax.legend() diff --git a/xfel/ui/components/xfel_gui_init.py b/xfel/ui/components/xfel_gui_init.py index ee490f6aa3..00877637a6 100644 --- a/xfel/ui/components/xfel_gui_init.py +++ b/xfel/ui/components/xfel_gui_init.py @@ -2744,7 +2744,7 @@ def __init__(self, parent, main): self.tag_runs_changed = True self.tag_last_five = False self.entire_expt = False - self.d_min = 2.5 + self.d_min = 2 self.n_multiples = 2 self.ratio = 1 self.n_strong = 16 @@ -2797,7 +2797,7 @@ def __init__(self, parent, main): sub_labels=[''], label_size=(160, -1), ctrl_size=(30, -1), - items=[('d_min', 2.5)]) + items=[('d_min', 2.0)]) self.n_multiples_selector = gctr.OptionCtrl(self.options_box, name='rs_multiples', label='# multiples threshold:', @@ -2913,6 +2913,7 @@ def __init__(self, parent, main): self.manage_panel = wx.Panel(self) self.manage_sizer = wx.BoxSizer(wx.HORIZONTAL) + self.btn_toggle_options = wx.ToggleButton(self.manage_panel, label='Hide options') self.chk_auto_update = wx.CheckBox(self.manage_panel, label='Auto update') @@ -3063,6 +3064,7 @@ def onCanvasClick(event): locator_path = os.path.join(params.output_folder, "r%04d"%int(run_number), \ "%03d_rg%03d"%(trial.trial, rg.id), 'data.loc') + print("Loading run %s, image %d"%(run.run, x+1)) from dials.command_line.image_viewer import phil_scope from dials.util.image_viewer.spotfinder_frame import SpotFrame, chooser_wrapper @@ -3075,7 +3077,6 @@ def onCanvasClick(event): expts = ExperimentListFactory.from_filenames([locator_path], load_models=False) tab.sf_frame.imagesets = expts.imagesets() tab.sf_frame.add_file_name_or_data(chooser_wrapper(tab.sf_frame.imagesets[x], 0)) - print("Loading run %s, image %d"%(run.run, x+1)) tab.sf_frame.load_image(chooser_wrapper(tab.sf_frame.imagesets[x], 0)) tab.sf_frame.Show() tab.cached_run = run @@ -3488,8 +3489,17 @@ def __init__(self, parent, main): self.dataset_sizer = wx.BoxSizer(wx.HORIZONTAL) self.dataset_panel.SetSizer(self.dataset_sizer) - self.btn_sizer = wx.FlexGridSizer(1, 2, 0, 10) + self.btn_sizer = wx.FlexGridSizer(1, 3, 0, 10) self.btn_sizer.AddGrowableCol(0) + + self.filter = gctr.TextButtonCtrl(self, + name='filter', + label='Filter', + label_style='bold', + label_size=(100, -1), + value="") + self.btn_sizer.Add(self.filter, flag=wx.ALIGN_RIGHT) + self.btn_add_dataset = wx.Button(self, label='New Dataset', size=(120, -1)) self.btn_active_only = wx.ToggleButton(self, label='Show Only Active Datasets', @@ -3501,6 +3511,7 @@ def __init__(self, parent, main): self.main_sizer.Add(self.btn_sizer, flag=wx.EXPAND | wx.ALL, border=10) # Bindings + self.Bind(wx.EVT_TEXT, self.onFilter, self.filter.ctr) self.Bind(wx.EVT_BUTTON, self.onAddDataset, self.btn_add_dataset) self.Bind(wx.EVT_TOGGLEBUTTON, self.onActiveOnly, self.btn_active_only) @@ -3509,7 +3520,12 @@ def __init__(self, parent, main): def refresh_datasets(self): self.dataset_sizer.Clear(delete_windows=True) self.all_datasets = self.main.db.get_all_datasets() + + filter_str = self.filter.ctr.GetValue() + for dataset in self.all_datasets: + if filter_str and filter_str not in dataset.name: + continue if self.show_active_only: if dataset.active: self.add_dataset(dataset=dataset) @@ -3535,6 +3551,9 @@ def onAddDataset(self, e): if new_dataset_dlg.ShowModal() == wx.ID_OK: self.refresh_datasets() + def onFilter(self, e): + self.refresh_datasets() + def onActiveOnly(self, e): self.show_active_only = self.btn_active_only.GetValue() self.refresh_datasets() diff --git a/xfel/ui/db/job.py b/xfel/ui/db/job.py index 9717c6d4b7..1b91691b26 100644 --- a/xfel/ui/db/job.py +++ b/xfel/ui/db/job.py @@ -1065,7 +1065,7 @@ def submit_all_jobs(app): print ("Task %s cannot start due to unexpected status for job %d (%s) for trial %d, rungroup %d, run %s, task %d" % \ (next_task.type, submitted_job.id, submitted_job.status, trial.trial, rungroup.id, run.run, next_task.id)) break - if submitted_job.status in ("SUBMIT_FAIL", "DELETED") and job.task and job.task.type == "ensemble_refinement": + if submitted_job.status in ("SUBMIT_FAIL", "DELETED", "UNKWN") and job.task and job.task.type == "ensemble_refinement": break # XXX need a better way to indicate that a job has failed and shouldn't go through the pipeline due to no data submit_next_task = True previous_job = submitted_job diff --git a/xfel/ui/db/merging_log_scraper.py b/xfel/ui/db/merging_log_scraper.py index bdd3d47ea7..0ee39f8c26 100644 --- a/xfel/ui/db/merging_log_scraper.py +++ b/xfel/ui/db/merging_log_scraper.py @@ -192,7 +192,7 @@ def plot_many_results(self, all_results, title, xsize=30, ysize=10, interactive def resolution(y, pos): if y <= 0: return '-' - return "%.1f"%(1/math.sqrt(y)) + return "%.2f"%(1/math.sqrt(y)) formatter = FuncFormatter(resolution) ax2.yaxis.set_major_formatter(formatter) From 842d097c6a3681978f91d8b6f77be0bff3dcfb0e Mon Sep 17 00:00:00 2001 From: terwill Date: Mon, 24 Jun 2024 13:59:23 -0700 Subject: [PATCH 545/748] Spell out deep_copy of map_manager instead of using deepcopy (deepcopy(map_data) is very slow relative to map_data.deep_copy()) --- iotbx/map_manager.py | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/iotbx/map_manager.py b/iotbx/map_manager.py index 2727c3ec7c..bbb9377421 100644 --- a/iotbx/map_manager.py +++ b/iotbx/map_manager.py @@ -1430,18 +1430,38 @@ def customized_copy(self, map_data = None, origin_shift_grid_units = None, # Deepcopy this object and then set map_data and origin_shift_grid_units - mm = deepcopy(self) + mm = map_manager( + file_name = None, + map_data = map_data, + unit_cell_grid = self.unit_cell_grid, + unit_cell_crystal_symmetry = self._unit_cell_crystal_symmetry, + origin_shift_grid_units = origin_shift_grid_units, + ncs_object = self._ncs_object.deep_copy() if self._ncs_object else None, + wrapping = False, + experiment_type = self._experiment_type, + scattering_table = self._scattering_table, + resolution = self._resolution, + log = self.log,) + + mm._is_mask = self._is_mask + mm._is_dummy_map_manager = self._is_dummy_map_manager # Set things that are not necessarily the same as in self: - mm.log=self.log - mm.origin_shift_grid_units = origin_shift_grid_units # specified above - mm.data = map_data # using self.data or a deepcopy (specified above) mm._created_mask = created_mask # using self._created_mask or a - #deepcopy (specified above) + mm.file_name = self.file_name + mm.program_name = self.program_name + mm.limitations = self.limitations + mm.labels = self.labels + + if wrapping is not None: - mm.set_wrapping(wrapping) + desired_wrapping = wrapping + else: + desired_wrapping = self._wrapping - if not mm.is_full_size(): + if mm.is_full_size(): + mm.set_wrapping(desired_wrapping) + else: # mm.set_wrapping(False) # Set up _crystal_symmetry for the new object From 1de64c1d770ec8f2c92ecf85665dc2ea994c8fb8 Mon Sep 17 00:00:00 2001 From: terwill Date: Mon, 24 Jun 2024 15:24:39 -0600 Subject: [PATCH 546/748] clean clutter --- iotbx/map_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iotbx/map_manager.py b/iotbx/map_manager.py index bbb9377421..f7e2ae0252 100644 --- a/iotbx/map_manager.py +++ b/iotbx/map_manager.py @@ -1452,7 +1452,7 @@ def customized_copy(self, map_data = None, origin_shift_grid_units = None, mm.program_name = self.program_name mm.limitations = self.limitations mm.labels = self.labels - + if wrapping is not None: desired_wrapping = wrapping From 8381e635ad68970cea92d8674e4ec90d2c9dc931 Mon Sep 17 00:00:00 2001 From: Daniel Tchon Date: Mon, 24 Jun 2024 17:41:32 -0700 Subject: [PATCH 547/748] Submit `cctbx.xfel` jobs using "/bin/bash" instead of "/bin/sh" Co-authored-by: Aaron Brewster --- xfel/util/mp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xfel/util/mp.py b/xfel/util/mp.py index 4e2a10e23f..5ef550e962 100644 --- a/xfel/util/mp.py +++ b/xfel/util/mp.py @@ -174,7 +174,7 @@ def __init__(self, command, submit_path, stdoutdir, params, @param err_name Filename for stderr (if None, combined with the stdout). @param job_name For applicable queueing systems, identifier for the job (optional). """ - self.shell_path = "/bin/sh" + self.shell_path = "/bin/bash" self.source_env_scripts = [] self.options_inside_submit_script = [] self.submit_head = "qsub" From c779886e73a4f5d036a9c3abfa19e5fe74e2b521 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 25 Jun 2024 08:47:32 -0700 Subject: [PATCH 548/748] mid-june update --- iotbx/pdb/modified_aa_names.h | 10 +++++++++- iotbx/pdb/modified_aa_names.py | 9 ++++++++- iotbx/pdb/modified_rna_dna_names.h | 4 +++- iotbx/pdb/modified_rna_dna_names.py | 4 +++- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/iotbx/pdb/modified_aa_names.h b/iotbx/pdb/modified_aa_names.h index 2966a40e5d..458e1a93c7 100644 --- a/iotbx/pdb/modified_aa_names.h +++ b/iotbx/pdb/modified_aa_names.h @@ -5,7 +5,7 @@ This file is generated by the following procedure: phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Wed May 8 17:01:20 2024 +The date of file generation: Mon Jun 24 07:02:52 2024 */ #include @@ -474,6 +474,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "A1ADW", "A1ADY", "A1ADZ", + "A1AQ4", "A5R", "A66", "A67", @@ -900,6 +901,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "QAC", "QQB", "QRG", + "QUK", "QWE", "QXV", "R00", @@ -1068,8 +1070,10 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "ZU5", "ZUK", "ZXX", + "ZY9", "ZYA", "ZZU", + "YWF", // parent is ABU "OGU", // parent is ACY "02K", // parent is ALA "02O", @@ -1098,6 +1102,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "7OZ", "7VN", "9WV", + "A1H5W", "AA3", "AA4", "ABA", @@ -1539,6 +1544,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "2LU", "2ML", "8WY", + "A1ADO", "AN6", "BL2", "BLE", @@ -2051,6 +2057,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "4LZ", "51T", "73O", + "A1D5P", "A30", "AGQ", "AZY", @@ -2142,6 +2149,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "VAI", "WVL", "X60", + "ZQN", 0 }; diff --git a/iotbx/pdb/modified_aa_names.py b/iotbx/pdb/modified_aa_names.py index 23ecf4c880..3e26067704 100644 --- a/iotbx/pdb/modified_aa_names.py +++ b/iotbx/pdb/modified_aa_names.py @@ -7,7 +7,7 @@ phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Wed May 8 17:01:20 2024 +The date of file generation: Mon Jun 24 07:02:52 2024 """ from __future__ import absolute_import, division, print_function @@ -472,6 +472,7 @@ "A1ADW" : "?", "A1ADY" : "?", "A1ADZ" : "?", + "A1AQ4" : "?", "A5R" : "?", "A66" : "?", "A67" : "?", @@ -898,6 +899,7 @@ "QAC" : "?", "QQB" : "?", "QRG" : "?", + "QUK" : "?", "QWE" : "?", "QXV" : "?", "R00" : "?", @@ -1066,6 +1068,7 @@ "ZU5" : "?", "ZUK" : "?", "ZXX" : "?", + "ZY9" : "?", "ZYA" : "?", "ZZU" : "?", "02K" : "A", @@ -1095,6 +1098,7 @@ "7OZ" : "A", "7VN" : "A", "9WV" : "A", + "A1H5W" : "A", "AA3" : "A", "AA4" : "A", "ABA" : "A", @@ -1533,6 +1537,7 @@ "2LU" : "L", "2ML" : "L", "8WY" : "L", + "A1ADO" : "L", "AN6" : "L", "BL2" : "L", "BLE" : "L", @@ -2044,6 +2049,7 @@ "4LZ" : "Y", "51T" : "Y", "73O" : "Y", + "A1D5P" : "Y", "A30" : "Y", "AGQ" : "Y", "AZY" : "Y", @@ -2134,6 +2140,7 @@ "VAI" : "V", "WVL" : "V", "X60" : "V", + "ZQN" : "V", } if __name__ == '__main__': print(len(lookup.keys())) diff --git a/iotbx/pdb/modified_rna_dna_names.h b/iotbx/pdb/modified_rna_dna_names.h index 8e502c1e90..52f833ffea 100644 --- a/iotbx/pdb/modified_rna_dna_names.h +++ b/iotbx/pdb/modified_rna_dna_names.h @@ -5,7 +5,7 @@ This file is generated by the following procedure: phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Wed May 8 17:01:21 2024 +The date of file generation: Mon Jun 24 07:02:53 2024 */ #include @@ -281,6 +281,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "6MZ", "6NW", "7AT", + "7RZ", "8AH", "8AN", "9SI", @@ -606,6 +607,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "F3H", "F4H", "JDT", + "L5R", "LSH", "LST", "MMT", diff --git a/iotbx/pdb/modified_rna_dna_names.py b/iotbx/pdb/modified_rna_dna_names.py index d16d4a472d..00d84be684 100644 --- a/iotbx/pdb/modified_rna_dna_names.py +++ b/iotbx/pdb/modified_rna_dna_names.py @@ -7,7 +7,7 @@ phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Wed May 8 17:01:21 2024 +The date of file generation: Mon Jun 24 07:02:53 2024 """ from __future__ import absolute_import, division, print_function @@ -279,6 +279,7 @@ "6MZ" : "A", "6NW" : "A", "7AT" : "A", + "7RZ" : "A", "8AH" : "A", "8AN" : "A", "9SI" : "A", @@ -604,6 +605,7 @@ "F3H" : "DT", "F4H" : "DT", "JDT" : "DT", + "L5R" : "DT", "LSH" : "DT", "LST" : "DT", "MMT" : "DT", From 3132585bc38a39d08d24a1ce94df9d746f71558f Mon Sep 17 00:00:00 2001 From: Daniel Paley Date: Thu, 27 Jun 2024 14:16:13 -0400 Subject: [PATCH 549/748] Update small_cell indexing documentation --- xfel/small_cell/README.md | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/xfel/small_cell/README.md b/xfel/small_cell/README.md index 2ce3494339..097ff86f12 100644 --- a/xfel/small_cell/README.md +++ b/xfel/small_cell/README.md @@ -161,7 +161,6 @@ dispatch.hit_finder { maximum_number_of_reflections = 40 } dispatch.index=False -output.composite_output=True spotfinder.filter.min_spot_size=3 ``` @@ -257,12 +256,6 @@ dispatch { dispatch { refine = True } -output { - composite_output=True - experiments_filename = None - strong_filename = None -} - spotfinder { filter { min_spot_size = 3 @@ -283,11 +276,6 @@ refinement { small_cell { powdercell = "1,2,3,90,90,90" spacegroup = "P2" - high_res_limit = 1.2 - min_spots_to_integrate = 3 - faked_mosaicity = 0.1 - spot_connection_epsilon = 0.01 - d_ring_overlap_limit = None } ``` @@ -378,12 +366,6 @@ dispatch { dispatch { refine = True } -output { - composite_output=True - experiments_filename = None - strong_filename = None -} - spotfinder { filter { min_spot_size = 3 @@ -404,11 +386,6 @@ refinement { small_cell { powdercell = "5.93762, 7.32461, 29.202, 90, 95.4404, 90" spacegroup = "C2" - high_res_limit = 0.8 - min_spots_to_integrate = 3 - faked_mosaicity = 0.1 - spot_connection_epsilon = 0.004 - d_ring_overlap_limit = None } ``` From 946087200f905e283cceba7e0d31fb5c99c3941f Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Thu, 27 Jun 2024 15:58:54 -0600 Subject: [PATCH 550/748] Not used and not tested code. There are functions like add_crystal_symmetry_if_necessary in the class which should be used instead. --- mmtbx/model/model.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index 8c772b1055..1c7d4bbd63 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -201,8 +201,7 @@ def __init__(self, log = None, expand_with_mtrix = True, process_biomt = True, - skip_ss_annotations = False, - reset_crystal_symmetry_to_box_with_buffer = None): + skip_ss_annotations = False): # Assert basic assumptions if(model_input is not None): assert pdb_hierarchy is None if(pdb_hierarchy is not None): @@ -307,15 +306,6 @@ def __init__(self, self.get_hierarchy().atoms().reset_i_seq() ########### Allow access to methods from pdb_hierarchy directly ###### self.set_up_methods_from_hierarchy() # Allow methods from hierarchy - # !!! This must be the last call !!! - # This forces to use P1 box as crystal symmetry with specified buffer - # This needs to use BIOMT expanded model for the box to be meaningful - if(reset_crystal_symmetry_to_box_with_buffer is not None): - box = uctbx.non_crystallographic_unit_cell_with_the_sites_in_its_center( - sites_cart = self.get_hierarchy().atoms().extract_xyz(), - buffer_layer = reset_crystal_symmetry_to_box_with_buffer) - self._crystal_symmetry = box.crystal_symmetry() - self.get_hierarchy().atoms().set_xyz(box.sites_cart) @classmethod def from_sites_cart(cls, From 42d905a2d01425b186717ce550dbd4c0801db4dc Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Thu, 27 Jun 2024 17:09:37 -0600 Subject: [PATCH 551/748] Unused import --- mmtbx/model/model.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index 1c7d4bbd63..1da853d3eb 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -27,7 +27,6 @@ from cctbx import adp_restraints from cctbx import crystal -from cctbx import uctbx import mmtbx.restraints import mmtbx.hydrogens From c67a526d3e5fef94e2588db9bc0f68e3d063d5d2 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Fri, 28 Jun 2024 02:23:13 -0700 Subject: [PATCH 552/748] CCTBXParser: write modified DataManager scope with --diff-params - add test --- iotbx/cli_parser.py | 4 +- iotbx/regression/tst_cli_parser.py | 62 ++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/iotbx/cli_parser.py b/iotbx/cli_parser.py index 275dc39acf..34c405e32c 100644 --- a/iotbx/cli_parser.py +++ b/iotbx/cli_parser.py @@ -780,10 +780,10 @@ def show_phil_summary(self): # write differences if self.namespace.write_modified or self.namespace.diff_params: - if phil_is_different: + if is_different: ow = overwrite or self.namespace.diff_params self.data_manager.write_phil_file( - phil_diff.as_str(), filename=self.modified_filename, + data_diff.as_str() + phil_diff.as_str(), filename=self.modified_filename, overwrite=ow) print(' Modified PHIL parameters written to %s.' % self.modified_filename, file=self.logger) diff --git a/iotbx/regression/tst_cli_parser.py b/iotbx/regression/tst_cli_parser.py index 8932056c95..34d4ebea33 100644 --- a/iotbx/regression/tst_cli_parser.py +++ b/iotbx/regression/tst_cli_parser.py @@ -3,6 +3,7 @@ import os import json +from multiprocessing import Process from six.moves import cStringIO as StringIO from iotbx.cli_parser import run_program @@ -422,6 +423,66 @@ def get_results_as_JSON(self): assert result == expected_result os.remove(expected_filename) +# ----------------------------------------------------------------------------- +# since --diff-params calls sys.exit, run in a separate process +class testProgram(ProgramTemplate): + program_name = 'test_diff_params' + master_phil_str = ''' +diff_test_parameter = None +.type = str +''' + def run(): + pass + def validate(self): + pass + +def run_diff_program(args): + return run_program(program_class=testProgram, args=args) + +def run_function_in_process(args): + p = Process(target=run_diff_program, args=[args]) + p.start() + p.join() + +def test_diff_params(): + + expected_filename = 'test_diff_params_modified.eff' + if os.path.exists(expected_filename): + os.remove(expected_filename) + + # no diff + args = ['--quiet', '--diff-params'] + run_function_in_process(args) + assert not os.path.exists(expected_filename) + + # program diff + args = ['--quiet', '--diff-params', 'diff_test=abc'] + run_function_in_process(args) + with open(expected_filename, 'r') as f: + text = f.read() + assert 'diff_test_parameter = abc' in text.strip(), text + + # DataManager diff + data_dir = os.path.dirname(os.path.abspath(__file__)) + model_1yjp = os.path.join(data_dir, 'data', '1yjp.pdb') + args = [model_1yjp, '--quiet', '--diff-params'] + run_function_in_process(args) + with open(expected_filename, 'r') as f: + text = f.read() + assert text.count(model_1yjp) == 2, text + assert 'diff_test_parameter' not in text.strip(), text + + # both diff + args = ['--quiet', '--diff-params', model_1yjp, 'diff_test=abc'] + run_function_in_process(args) + with open(expected_filename, 'r') as f: + text = f.read() + assert text.count(model_1yjp) == 2, text + assert 'diff_test_parameter' in text.strip(), text + + if os.path.exists(expected_filename): + os.remove(expected_filename) + # ============================================================================= if __name__ == '__main__': test_dry_run() @@ -429,5 +490,6 @@ def get_results_as_JSON(self): test_model_type_parsing() test_user_selected_labels() test_json() + test_diff_params() print("OK") From a6b867c792ff16fd05e169e332f57fa7703d5f3c Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Fri, 28 Jun 2024 13:38:15 -0700 Subject: [PATCH 553/748] CCTBXParser: adjust check to avoid file separator --- iotbx/regression/tst_cli_parser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iotbx/regression/tst_cli_parser.py b/iotbx/regression/tst_cli_parser.py index 34d4ebea33..29f8fd68fb 100644 --- a/iotbx/regression/tst_cli_parser.py +++ b/iotbx/regression/tst_cli_parser.py @@ -469,7 +469,7 @@ def test_diff_params(): run_function_in_process(args) with open(expected_filename, 'r') as f: text = f.read() - assert text.count(model_1yjp) == 2, text + assert text.count('1yjp.pdb') == 2, text assert 'diff_test_parameter' not in text.strip(), text # both diff @@ -477,7 +477,7 @@ def test_diff_params(): run_function_in_process(args) with open(expected_filename, 'r') as f: text = f.read() - assert text.count(model_1yjp) == 2, text + assert text.count('1yjp.pdb') == 2, text assert 'diff_test_parameter' in text.strip(), text if os.path.exists(expected_filename): From 56c25ea36947240746f8eb69f52406cfd2f82c0a Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Sun, 30 Jun 2024 10:28:20 -0700 Subject: [PATCH 554/748] CI: bump macOS for XFEL CI --- .azure-pipelines/xfel/xfel-ci-build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.azure-pipelines/xfel/xfel-ci-build.yml b/.azure-pipelines/xfel/xfel-ci-build.yml index 7cedd3baf3..5f37f88f3b 100644 --- a/.azure-pipelines/xfel/xfel-ci-build.yml +++ b/.azure-pipelines/xfel/xfel-ci-build.yml @@ -15,8 +15,8 @@ jobs: prefix: xfel_psana_ - template: ./conda-osx.yml parameters: - vmImage: [11] - xcode_version: [12, 5, 1] + vmImage: [12] + xcode_version: [14, 2] modules: xfel_modules template: ./unix-conda-build.yml prefix: xfel_ From 67acd807d45aa6abe40ba5451184a2fbce1fd48f Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Mon, 1 Jul 2024 14:03:35 -0700 Subject: [PATCH 555/748] Update CHANGELOG.rst for 2024.6 release [skip ci] --- CHANGELOG.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 04cf587c5f..4075be50c3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,10 @@ +2024.6 +====== + +* Update pdbtools to use target_output_format +* Update known residue codes +* Update CCTBXParser to show diff of DataManager scope with --diff-params + 2024.5 ====== From 1edbdfc5dc3cc2339b4b978fea267b188e72d90c Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Tue, 2 Jul 2024 09:45:49 -0700 Subject: [PATCH 556/748] CI: stop CentOS 7 builds and move to Rocky Linux 8 - Set locale and clean up XFEL CI - Add make to XFEL CI - Fix macOS cache for XFEL CI --- .azure-pipelines/ci-build.yml | 6 +++--- .azure-pipelines/full-build.yml | 12 ++++++------ .azure-pipelines/xfel/conda-linux.yml | 18 ++---------------- .azure-pipelines/xfel/conda-osx.yml | 9 +++++---- .azure-pipelines/xfel/unix-conda-build.yml | 2 +- .azure-pipelines/xfel/xfel-ci-build.yml | 8 ++++---- 6 files changed, 21 insertions(+), 34 deletions(-) diff --git a/.azure-pipelines/ci-build.yml b/.azure-pipelines/ci-build.yml index a74970f345..0533ac54e3 100644 --- a/.azure-pipelines/ci-build.yml +++ b/.azure-pipelines/ci-build.yml @@ -9,9 +9,9 @@ jobs: modules: modules - template: ./conda-linux.yml parameters: - distribution: centos - version: [7] - modules: modules + distribution: rockylinux + version: [8] + modules: ${{ parameters.modules }} template: ./unix-conda-build.yml - template: ./conda-osx.yml parameters: diff --git a/.azure-pipelines/full-build.yml b/.azure-pipelines/full-build.yml index 7378480452..554e0f13f1 100644 --- a/.azure-pipelines/full-build.yml +++ b/.azure-pipelines/full-build.yml @@ -18,12 +18,12 @@ jobs: version: [9] modules: ${{ parameters.modules }} template: ./unix-conda-build.yml - - template: ./conda-linux.yml - parameters: - distribution: centos - version: [7] - modules: ${{ parameters.modules }} - template: ./unix-conda-build.yml + # - template: ./conda-linux.yml + # parameters: + # distribution: centos + # version: [7] + # modules: ${{ parameters.modules }} + # template: ./unix-conda-build.yml - template: ./conda-linux.yml parameters: distribution: rockylinux diff --git a/.azure-pipelines/xfel/conda-linux.yml b/.azure-pipelines/xfel/conda-linux.yml index 8cd28885bd..84325457df 100644 --- a/.azure-pipelines/xfel/conda-linux.yml +++ b/.azure-pipelines/xfel/conda-linux.yml @@ -49,16 +49,6 @@ jobs: # https://github.com/ApexAI/performance_test/blob/master/azure-pipelines.yml#L9-L17 # centos setup - - script: | - set -xe - /tmp/docker exec -t -u 0 ci-container \ - sh -c "sed -i 's/mirrorlist=http/#mirrorlist=http/g' /etc/yum.repos.d/CentOS-Base.repo" - /tmp/docker exec -t -u 0 ci-container \ - sh -c "sed -i 's/#baseurl=http:\/\/mirror/baseurl=http:\/\/vault/g' /etc/yum.repos.d/CentOS-Base.repo" - cat /etc/yum.repos.d/CentOS-Base.repo - displayName: Modify yum repositories for CentOS 6 - condition: eq('${{ parameters.version[0] }}', 6) - - script: | /tmp/docker exec -t -u 0 ci-container \ sh -c "yum install -y sudo" @@ -71,15 +61,11 @@ jobs: displayName: Install dependencies for CentOS condition: eq('${{ parameters.distribution }}', 'centos') - - script: | - sudo yum install -y python-argparse - displayName: Install argparse for CentOS 6 - condition: eq('${{ parameters.version[0] }}', 6) - - bash: | echo "##vso[task.setvariable variable=LC_ALL]C.utf8" displayName: Setup locale for CentOS 8 - condition: eq('${{ parameters.version[0] }}', 8) + condition: or(eq('${{ parameters.version[0] }}', 8), + eq('${{ parameters.version[0] }}', 9)) # https://lists.openhpc.community/g/users/topic/openmpi_and_shared_memory/16489081?p=,,,20,0,0,0::recentpostdate%2Fsticky,,,20,2,0,16489081 - script: | diff --git a/.azure-pipelines/xfel/conda-osx.yml b/.azure-pipelines/xfel/conda-osx.yml index d558686cea..76f72700c3 100644 --- a/.azure-pipelines/xfel/conda-osx.yml +++ b/.azure-pipelines/xfel/conda-osx.yml @@ -92,10 +92,11 @@ jobs: failOnStderr: false - script: | - rm -f $(Pipeline.Workspace)/build/lib/scitbx_array_family_flex_ext.so - displayName: Fix broken cache on macOS 10.15 and 11 - condition: or(and(eq('${{ parameters.vmImage[0] }}', 10), eq('${{ parameters.vmImage[1] }}', 15)), - eq('${{ parameters.vmImage[0] }}', 11)) + set -xe + for f in cctbx_geometry_restraints_ext.so scitbx_array_family_flex_ext.so ; do + rm -f $(Pipeline.Workspace)/build/lib/${f} + done + displayName: Fix broken cache on macOS continueOnError: true failOnStderr: false diff --git a/.azure-pipelines/xfel/unix-conda-build.yml b/.azure-pipelines/xfel/unix-conda-build.yml index 9e40551341..9eaeff62bd 100644 --- a/.azure-pipelines/xfel/unix-conda-build.yml +++ b/.azure-pipelines/xfel/unix-conda-build.yml @@ -56,7 +56,7 @@ steps: source $(Pipeline.Workspace)/miniforge/etc/profile.d/conda.sh conda create -y -n $(PYTHON_VERSION) --file $(Pipeline.Workspace)/modules/dials/.conda-envs/$(OS).txt python=$(PYTHON_FULL_VERSION) conda install -y -c conda-forge --no-deps -n $(PYTHON_VERSION) junit-xml - conda install -y -c conda-forge cmake pandas distro -n $(PYTHON_VERSION) + conda install -y -c conda-forge cmake make pandas distro -n $(PYTHON_VERSION) displayName: Create conda environment retryCountOnTaskFailure: 3 diff --git a/.azure-pipelines/xfel/xfel-ci-build.yml b/.azure-pipelines/xfel/xfel-ci-build.yml index 5f37f88f3b..d032bef6d0 100644 --- a/.azure-pipelines/xfel/xfel-ci-build.yml +++ b/.azure-pipelines/xfel/xfel-ci-build.yml @@ -1,15 +1,15 @@ jobs: - template: ./conda-linux.yml parameters: - distribution: centos - version: [7] + distribution: rockylinux + version: [8] modules: xfel_modules template: ./unix-conda-build.yml prefix: xfel_ - template: ./conda-linux.yml parameters: - distribution: centos - version: [7] + distribution: rockylinux + version: [8] modules: xfel_modules template: ./unix-psana-build.yml prefix: xfel_psana_ From 3d42afce58b204283b5e644d4f30726b3e9a1f60 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 2 Jul 2024 15:49:19 -0700 Subject: [PATCH 557/748] Don't create present_anames until really need them. Surprising time savings for models without alt locs. --- mmtbx/ncs/ncs_search.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mmtbx/ncs/ncs_search.py b/mmtbx/ncs/ncs_search.py index 0bf2858ef4..419e87cf22 100644 --- a/mmtbx/ncs/ncs_search.py +++ b/mmtbx/ncs/ncs_search.py @@ -940,11 +940,10 @@ def get_chains_info(ph, selection_list=None): chains_info[ch.id].resid.append(rg.resid()) chains_info[ch.id].res_names.append(rg.atom_groups()[0].resname) # atoms = res.atoms() - ag0 = rg.atom_groups()[0] - atoms = ag0.atoms() - present_anames = [a.name for a in atoms] + atoms = rg.atom_groups()[0].atoms() # print "rg.atom_groups_size()", rg.atom_groups_size() if rg.atom_groups_size() > 1: + present_anames = [a.name for a in atoms] for add_rgs in rg.atom_groups()[1:]: for a in add_rgs.atoms(): # print " getting atom '%s'" % a.name, a.name not in present_anames From e3f1760a466196329660d001d7928fece1cdd028 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 2 Jul 2024 19:35:32 -0700 Subject: [PATCH 558/748] bug fix: skip rotamer fitting if rotamer iterator is None (or else it crashes!) --- mmtbx/refinement/real_space/fit_residue.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mmtbx/refinement/real_space/fit_residue.py b/mmtbx/refinement/real_space/fit_residue.py index 0cbd67be0e..734b1b524c 100644 --- a/mmtbx/refinement/real_space/fit_residue.py +++ b/mmtbx/refinement/real_space/fit_residue.py @@ -389,6 +389,12 @@ def fit_proline(self): """ if(self.target_map is None): return rotamer_iterator = self.get_rotamer_iterator() + if rotamer_iterator is None: + id_str="chain: %s"%(self.residue.parent().parent().id) + id_str+=" residue: %s %s"%( + self.residue.resname, self.residue.resseq.strip()) + print("Corrupt residue: %s >>> skipping"%id_str, file=self.log) + return None scorer = mmtbx.refinement.real_space.score3( unit_cell = self.unit_cell, target_map = self.target_map, From 3f2b36fbc673dd23f7a518020700f60a40b61dad Mon Sep 17 00:00:00 2001 From: Pavel Date: Fri, 5 Jul 2024 18:11:05 -0700 Subject: [PATCH 559/748] Fix unsupported map type --- mmtbx/solvent/ordered_solvent.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mmtbx/solvent/ordered_solvent.py b/mmtbx/solvent/ordered_solvent.py index 56645bc406..b0821c3695 100644 --- a/mmtbx/solvent/ordered_solvent.py +++ b/mmtbx/solvent/ordered_solvent.py @@ -133,7 +133,7 @@ def get_unique_altloc2(available, exclude): cc_map_1_type = "Fmodel" .type = str .short_caption = Model map type for CC calculation - cc_map_2_type = 2mFo-DFmodel + cc_map_2_type = 2mFobs-DFmodel .type = str .short_caption = Experimental map type for CC calculation poor_cc_threshold = 0.70 @@ -276,7 +276,7 @@ def _estimate_diff_map_cutoff(self): self.fmodel.update_xray_structure(update_f_calc=True) coeffs = self.fmodel.electron_density_map().map_coefficients( - map_type = "mFo-DFmodel", + map_type = "mFobs-DFmodel", fill_missing = False, isotropize = True) fft_map = coeffs.fft_map(crystal_gridding = self.crystal_gridding) From 370c29726d9221376aaa52a27a755933afd0efe1 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 8 Jul 2024 14:05:20 -0700 Subject: [PATCH 560/748] speedup ncs_search, 40% --- mmtbx/ncs/ncs_search.py | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/mmtbx/ncs/ncs_search.py b/mmtbx/ncs/ncs_search.py index 419e87cf22..4071a9b06a 100644 --- a/mmtbx/ncs/ncs_search.py +++ b/mmtbx/ncs/ncs_search.py @@ -547,13 +547,9 @@ def my_selection(ph, ch_id, sel_list_extended): def get_match_rmsd(ph, match): assert len(ph.models()) == 1 - [ch_a_id,ch_b_id,list_a,list_b,res_list_a,res_list_b,similarity] = match - sel_list_extended_a = [x for y in list_a for x in y] - sel_list_extended_b = [x for y in list_b for x in y] - sel_list_extended_a.sort() - sel_list_extended_b.sort() + [ch_a_id,ch_b_id,list_a,list_b] = match - if len(sel_list_extended_a) == 0 or len(sel_list_extended_b) == 0: + if len(list_a) == 0 or len(list_b) == 0: # e.g. 3liy (whole chain in AC) return None, None, None, None, None # @@ -568,8 +564,8 @@ def get_match_rmsd(ph, match): # even larger molecules (1.2Gb is currently the max). # At this point no hierarchy selections left in this module. # - other_h = my_selection(ph, ch_a_id, sel_list_extended_a) - ref_h = my_selection(ph, ch_b_id, sel_list_extended_b) + other_h = my_selection(ph, ch_a_id, list_a) + ref_h = my_selection(ph, ch_b_id, list_b) # other_atoms = other_h.atoms() ref_atoms = ref_h.atoms() @@ -721,13 +717,14 @@ def search_ncs_relations(ph=None, res_sel_m, res_sel_c, similarity = mmtbx_res_alignment( seq_a=seq_m,seq_b=seq_c, min_percent=chain_similarity_threshold) - sel_m, sel_c,res_sel_m,res_sel_c,new_msg = get_matching_atoms( + sel_m, sel_c, sel_m_flat, sel_c_flat, res_sel_m,res_sel_c,new_msg = get_matching_atoms( chains_info,m_ch_id,c_ch_id,res_sel_m,res_sel_c) if len(res_sel_m) > 0 and len(res_sel_c) > 0: msg += new_msg - rec = [m_ch_id,c_ch_id,sel_m,sel_c,res_sel_m,res_sel_c,similarity] if similarity > chain_similarity_threshold: - rmsd, ref_sites, other_sites_best, r,t = get_match_rmsd(ph, rec) + rmsd, ref_sites, other_sites_best, r,t = get_match_rmsd( + ph, + [m_ch_id,c_ch_id,sel_m_flat,sel_c_flat]) if rmsd is not None and rmsd <= chain_max_rmsd: # get the chains atoms and convert selection to flex bool sel_aa,sel_bb,res_list_a,res_list_b,ref_sites,other_sites_best = \ @@ -821,11 +818,16 @@ def get_matching_atoms(chains_info,a_id,b_id,res_num_a,res_num_b): Returns: sel_a/b (list of lists): matching atoms selection + sel_a/b_flat (list): matching atoms (sel_a/b) flattened selection - + faster to create on the go then convert sel_a/b later. Literally: + sel_a_flat = [x for y in sel_a for x in y].sort() res_num_a/b (list of int): updated res_num_a/b msg (str): message regarding matching residues with different atom number """ sel_a = [] sel_b = [] + sel_a_flat = flex.size_t([]) + sel_b_flat = flex.size_t([]) # check if any of the residues has alternate locations a_altloc = bool(chains_info[a_id].no_altloc) if a_altloc: @@ -882,6 +884,8 @@ def get_matching_atoms(chains_info,a_id,b_id,res_num_a,res_num_b): res_num_b_updated.append(j) sel_a.append(sa) sel_b.append(sb) + sel_a_flat.extend(sa) + sel_b_flat.extend(sb) if residues_with_different_n_atoms: problem_res_nums = [x.strip() for x in residues_with_different_n_atoms] msg = "NCS related residues with different number of atoms, selection " @@ -889,7 +893,18 @@ def get_matching_atoms(chains_info,a_id,b_id,res_num_a,res_num_b): msg += ','.join(problem_res_nums) + ']\n' else: msg = '' - return sel_a,sel_b,res_num_a_updated,res_num_b_updated,msg + + # Not faster downstream when working with resulting arrays. + # a_perm = flex.sort_permutation(sel_a_flat) + # sel_a_flat = sel_a_flat.select(a_perm) + # b_perm = flex.sort_permutation(sel_b_flat) + # sel_b_flat = sel_b_flat.select(b_perm) + + sel_a_flat = list(sel_a_flat) + sel_b_flat = list(sel_b_flat) + sel_a_flat.sort() + sel_b_flat.sort() + return sel_a,sel_b,sel_a_flat,sel_b_flat,res_num_a_updated,res_num_b_updated,msg def get_chains_info(ph, selection_list=None): """ From a43aa7b25afecbe5145ec95872ded041bec76d88 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 8 Jul 2024 15:56:01 -0700 Subject: [PATCH 561/748] Same result way faster without selection --- mmtbx/ncs/ncs_restraints_group_list.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mmtbx/ncs/ncs_restraints_group_list.py b/mmtbx/ncs/ncs_restraints_group_list.py index 28b6c53f76..247d7e8c28 100644 --- a/mmtbx/ncs/ncs_restraints_group_list.py +++ b/mmtbx/ncs/ncs_restraints_group_list.py @@ -301,8 +301,7 @@ def filter_ncs_restraints_group_list(self, whole_h, ncs_obj): This leads to undesired artefacts in refinement. """ def whole_chain_in_ncs(whole_h, master_iselection): - m_c = whole_h.select(master_iselection) - m_c_id = m_c.only_model().chains()[0].id + m_c_id = whole_h.atoms()[master_iselection[0]].parent().parent().parent().id for chain in ncs_obj.truncated_hierarchy.only_model().chains(): if chain.id == m_c_id: if chain.atoms_size() <= master_iselection.size(): From 5d1527053e58064881e907a843254ab6211a1053 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 9 Jul 2024 14:23:09 -0700 Subject: [PATCH 562/748] ncs_search speedup 2.5x --- mmtbx/ncs/ncs_search.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mmtbx/ncs/ncs_search.py b/mmtbx/ncs/ncs_search.py index 4071a9b06a..db2741b0fd 100644 --- a/mmtbx/ncs/ncs_search.py +++ b/mmtbx/ncs/ncs_search.py @@ -477,6 +477,7 @@ def make_flips_if_necessary_torsion(const_h, flip_h): flipped_other_selection = flex.size_t([]) ch_const = const_h.only_model().chains() ch_flip = flip_h.only_model().chains() + # looks like moving residue groups when there are 2 chains with the same id for another_ch in ch_const[1:]: if another_ch.id == ch_const[0].id: for rg in another_ch.residue_groups(): @@ -494,7 +495,7 @@ def make_flips_if_necessary_torsion(const_h, flip_h): if (residue.resname in flippable_sidechains and should_be_flipped(residue, res_flip)): fl_atom_list = flippable_sidechains[residue.resname] - iseqs = [0]*residue.atoms_size() + iseqs = flex.size_t([0]*residue.atoms_size()) for i, a in enumerate(residue.atoms()): try: ind = fl_atom_list.index(a.name) @@ -510,11 +511,9 @@ def make_flips_if_necessary_torsion(const_h, flip_h): if i == len(iseqs)-1: # this is for case where the last atom is not present iseqs[i] = a.i_seq - for i in iseqs: - flipped_other_selection.append(i) + flipped_other_selection.extend(iseqs) else: - for a in residue.atoms(): - flipped_other_selection.append(a.i_seq) + flipped_other_selection.extend(residue.atoms().extract_i_seq()) assert flipped_other_selection.size() == original_atoms_size, "%d %d" % ( flipped_other_selection.size(), original_atoms_size) # assert flipped_other_selection.size() == const_h.atoms_size() @@ -751,7 +750,8 @@ def mmtbx_res_alignment(seq_a, seq_b, a = len(seq_a) b = len(seq_b) if (a == 0) or (b == 0): return [], [], 0 - if seq_a == seq_b: return list(range(a)), list(range(a)), 1.0 + if ",".join(seq_a) == ",".join(seq_b): + return list(range(a)), list(range(a)), 1.0 norm_seq_a = seq_a norm_seq_b = seq_b if not atomnames: @@ -965,8 +965,8 @@ def get_chains_info(ph, selection_list=None): if a.name not in present_anames: atoms.append(a) present_anames.append(a.name) - chains_info[ch.id].atom_names.append(list(atoms.extract_name())) - chains_info[ch.id].atom_selection.append(list(atoms.extract_i_seq())) + chains_info[ch.id].atom_names.append(atoms.extract_name()) + chains_info[ch.id].atom_selection.append(atoms.extract_i_seq()) chains_info[ch.id].no_altloc.append(not rg.have_conformers() or len_conf==1) chains_info[ch.id].gap_residue.append(gr) # print " ", rg.id_str(), rg.have_conformers(), not res.is_pure_main_conf, "|noaltloc:", (not rg.have_conformers() or len_conf==1), "size:", atoms.size(), "gr:", gr From e33bbba7faa62e7be915836271c2242e6d1a4e67 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 9 Jul 2024 15:00:12 -0700 Subject: [PATCH 563/748] Correct comment --- iotbx/pdb/atom_selection.py | 9 ++++----- mmtbx/ncs/ncs_search.py | 22 +++++++--------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/iotbx/pdb/atom_selection.py b/iotbx/pdb/atom_selection.py index 767319fb70..8a705e0c87 100644 --- a/iotbx/pdb/atom_selection.py +++ b/iotbx/pdb/atom_selection.py @@ -888,13 +888,12 @@ def selection_string_from_selection(pdb_h, Args: pdb_h : iotbx.pdb.hierarchy selection (flex.bool or flex.size_t) - chains_info : object containing - chains (str): chain IDs OR selections string + chains_info (dict): values are object containing res_name (list of str): list of residues names resid (list of str): list of residues sequence number, resid - atom_names (list of list of str): list of atoms in residues - atom_selection (list of list of list of int): the location of atoms in ph - chains_atom_number (list of int): list of number of atoms in each chain + atom_names (list of flex.str): per residue atom names + atom_selection (list of flex.size_t()): per residue atom selections + chains_atom_number (int): list of number of atoms in each chain Returns: sel_str (str): atom selection string diff --git a/mmtbx/ncs/ncs_search.py b/mmtbx/ncs/ncs_search.py index db2741b0fd..cd5bec5b7c 100644 --- a/mmtbx/ncs/ncs_search.py +++ b/mmtbx/ncs/ncs_search.py @@ -662,12 +662,11 @@ def search_ncs_relations(ph=None, Args: ph (object): hierarchy chains_info (dict): values are object containing - chains (str): chain IDs OR selections string res_name (list of str): list of residues names resid (list of str): list of residues sequence number, resid - atom_names (list of list of str): list of atoms in residues - atom_selection (list of list of list of int): the location of atoms in ph - chains_atom_number (list of int): list of number of atoms in each chain + atom_names (list of flex.str): per residue atom names + atom_selection (list of flex.size_t()): per residue atom selections + chains_atom_number (int): list of number of atoms in each chain Returns: msg (str): message regarding matching residues with different atom number @@ -806,13 +805,7 @@ def get_matching_atoms(chains_info,a_id,b_id,res_num_a,res_num_b): Residues with alternative locations and of different size are excluded Args: - chains_info (object): object containing - chains (str): chain IDs or selections string - res_name (list of str): list of residues names - resid (list of str): list of residues sequence number, resid - atom_names (list of list of str): list of atoms in residues - atom_selection (list of list of list of int): the location of atoms in ph - chains_atom_number (list of int): list of number of atoms in each chain + chains_info a_id,b_id (str): Chain IDs res_num_a/b (list of int): indices of matching residues position @@ -918,12 +911,11 @@ def get_chains_info(ph, selection_list=None): Returns: chains_info (dict): values are object containing - chains (str): chain IDs OR selections string res_name (list of str): list of residues names resid (list of str): list of residues sequence number, resid - atom_names (list of list of str): list of atoms in residues - atom_selection (list of list of list of int): the location of atoms in ph - chains_atom_number (list of int): list of number of atoms in each chain + atom_names (list of flex.str): per residue atom names + atom_selection (list of flex.size_t()): per residue atom selections + chains_atom_number (int): list of number of atoms in each chain exclude_water (bool): exclude water """ From 810451e6a6a55dcc94a47a139f02b49583e6dfb0 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Wed, 10 Jul 2024 08:08:00 -0700 Subject: [PATCH 564/748] ncs_search speedup 20%: sacrifice memory for performance: having flat atom selection is faster than constructing it from list of lists --- iotbx/pdb/atom_selection.py | 2 +- mmtbx/ncs/ncs_search.py | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/iotbx/pdb/atom_selection.py b/iotbx/pdb/atom_selection.py index 8a705e0c87..adb4ea0156 100644 --- a/iotbx/pdb/atom_selection.py +++ b/iotbx/pdb/atom_selection.py @@ -917,7 +917,7 @@ def selection_string_from_selection(pdb_h, # this "unfolds" the atom_selection array which is [[],[],[],[]...] into # a set if not chain_is_needed(selection, chains_info[ch_id].atom_selection): continue - a_sel = {x for xi in chains_info[ch_id].atom_selection for x in xi} + a_sel = set(chains_info[ch_id].flat_atom_selection) test_set = a_sel.intersection(selection_set) if not test_set: continue ch_sel = "chain '%s'" % convert_wildcards_in_chain_id(ch_id) diff --git a/mmtbx/ncs/ncs_search.py b/mmtbx/ncs/ncs_search.py index cd5bec5b7c..7353cfe3a2 100644 --- a/mmtbx/ncs/ncs_search.py +++ b/mmtbx/ncs/ncs_search.py @@ -10,6 +10,7 @@ NCS_restraint_group, NCS_copy from mmtbx.refinement.flip_peptide_side_chain import should_be_flipped, \ flippable_sidechains +from copy import deepcopy import six from six.moves import zip @@ -25,6 +26,7 @@ def __init__(self): self.resid = [] self.atom_names = [] self.atom_selection = [] + self.flat_atom_selection = flex.size_t([]) self.chains_atom_number = 0 self.no_altloc = [] self.gap_residue = [] @@ -37,6 +39,7 @@ def __str__(self): print("self.resid", self.resid, file=res) print("self.atom_names", self.atom_names, file=res) print("self.atom_selection", self.atom_selection, file=res) + print("self.flat_atom_selection", list(self.flat_atom_selection), file=res) print("self.chains_atom_number", self.chains_atom_number, file=res) print("self.no_altloc", self.no_altloc, file=res) print("self.center_of_coordinates", self.center_of_coordinates, file=res) @@ -59,8 +62,6 @@ def shortcut_1( molecule with BIOMT or MTRIX matrices (or both). In this case we are expecting to find identical chains with 0 rmsd between them. """ - def flatten_list_of_list(lofl): - return [x for y in lofl for x in y] assert chains_info is not None assert len(chains_info) > 1 empty_result = class_ncs_restraints_group_list() @@ -84,10 +85,8 @@ def flatten_list_of_list(lofl): for n_atoms, chains_list in six.iteritems(n_atom_chain_id_dict): # this should make one ncs group master_chain_id = chains_list[0] - master_iselection = flatten_list_of_list( - chains_info[master_chain_id].atom_selection) ncs_gr = NCS_restraint_group( - master_iselection=flex.size_t(master_iselection), + master_iselection=chains_info[master_chain_id].flat_atom_selection.deep_copy(), str_selection="chain '%s'" % master_chain_id) master_xyz = get_chain_xyz(hierarchy, master_chain_id) for copy_chain_id in chains_list[1:]: @@ -95,8 +94,6 @@ def flatten_list_of_list(lofl): if chains_info[master_chain_id].atom_names != chains_info[copy_chain_id].atom_names: print("No shortcut, atom names are not identical", file=log) return empty_result - copy_iselection = flatten_list_of_list( - chains_info[copy_chain_id].atom_selection) copy_xyz = get_chain_xyz(hierarchy, copy_chain_id) lsq_fit_obj = superpose.least_squares_fit( reference_sites = copy_xyz, @@ -114,7 +111,7 @@ def flatten_list_of_list(lofl): return empty_result # seems like a good enough copy c = NCS_copy( - copy_iselection=flex.size_t(copy_iselection), + copy_iselection=chains_info[copy_chain_id].flat_atom_selection.deep_copy(), rot=r, tran=t, str_selection="chain '%s'" % copy_chain_id, @@ -519,7 +516,9 @@ def make_flips_if_necessary_torsion(const_h, flip_h): # assert flipped_other_selection.size() == const_h.atoms_size() return flipped_other_selection -def my_selection(ph, ch_id, sel_list_extended): +def my_selection(ph, ch_id, sel_list_extended_original): + # Make sure we are not changing incoming array + sel_list_extended = deepcopy(sel_list_extended_original) min_iseq = sel_list_extended[0] new_h = None prev_minus = 0 @@ -937,6 +936,7 @@ def get_chains_info(ph, selection_list=None): # coc = flex.vec3_double([ph_sel.atoms().extract_xyz().mean()]) # chains_info[ch.id].center_of_coordinates = coc chains_info[ch.id].center_of_coordinates = None + chains_info[ch.id].flat_atom_selection.extend(ch.atoms().extract_i_seq()) chains_info[ch.id].chains_atom_number += ch.atoms_size() conf = ch.conformers()[0] len_conf = len(ch.conformers()) From 2d12ea10c88bf95c17f39253fd420c2583886223 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Wed, 10 Jul 2024 09:04:10 -0700 Subject: [PATCH 565/748] ncs_search: consistent use of flex.size_t, 10% speedup, comments. --- mmtbx/ncs/ncs_search.py | 58 ++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/mmtbx/ncs/ncs_search.py b/mmtbx/ncs/ncs_search.py index 7353cfe3a2..79e91dbfff 100644 --- a/mmtbx/ncs/ncs_search.py +++ b/mmtbx/ncs/ncs_search.py @@ -10,7 +10,6 @@ NCS_restraint_group, NCS_copy from mmtbx.refinement.flip_peptide_side_chain import should_be_flipped, \ flippable_sidechains -from copy import deepcopy import six from six.moves import zip @@ -517,8 +516,19 @@ def make_flips_if_necessary_torsion(const_h, flip_h): return flipped_other_selection def my_selection(ph, ch_id, sel_list_extended_original): + """custom-made selection function for selecting one + chain - whole or parts. Speed reasons. + + Args: + ph (_type_): hierarchy + ch_id (str): chain id which will be selected + sel_list_extended_original (flex.size_t): selection + + Returns: + root: new hierarchy + """ # Make sure we are not changing incoming array - sel_list_extended = deepcopy(sel_list_extended_original) + sel_list_extended = sel_list_extended_original.deep_copy() min_iseq = sel_list_extended[0] new_h = None prev_minus = 0 @@ -528,8 +538,7 @@ def my_selection(ph, ch_id, sel_list_extended_original): # append first chain and tweak selections new_h = new_hierarchy_from_chain(chain) min_iseq = chain.atoms()[0].i_seq - for i in range(len(sel_list_extended)): - sel_list_extended[i] -= min_iseq + sel_list_extended -= min_iseq else: # append extra chain and tweak selection new_start_iseq = new_h.atoms_size() @@ -541,11 +550,23 @@ def my_selection(ph, ch_id, sel_list_extended_original): # new = old - old + new sel_list_extended[i] -= dif prev_minus += dif - return new_h.select(flex.size_t(sel_list_extended)) + return new_h.select(sel_list_extended) -def get_match_rmsd(ph, match): +def get_match_rmsd(ph, ch_a_id,ch_b_id,list_a,list_b): + """get RMSD of the match + + Args: + ph (_type_): hierarchy + ch_a_id (str): one chain id + ch_b_id (str): another chain id + list_a (flex.size_t): one selection + list_b (flex.size_t): another selection + + Returns: + rmsd, ref_sites, other_sites_best, r,t + """ assert len(ph.models()) == 1 - [ch_a_id,ch_b_id,list_a,list_b] = match + # [ch_a_id,ch_b_id,list_a,list_b] = match if len(list_a) == 0 or len(list_b) == 0: # e.g. 3liy (whole chain in AC) @@ -720,8 +741,7 @@ def search_ncs_relations(ph=None, msg += new_msg if similarity > chain_similarity_threshold: rmsd, ref_sites, other_sites_best, r,t = get_match_rmsd( - ph, - [m_ch_id,c_ch_id,sel_m_flat,sel_c_flat]) + ph,m_ch_id,c_ch_id,sel_m_flat,sel_c_flat) if rmsd is not None and rmsd <= chain_max_rmsd: # get the chains atoms and convert selection to flex bool sel_aa,sel_bb,res_list_a,res_list_b,ref_sites,other_sites_best = \ @@ -886,16 +906,12 @@ def get_matching_atoms(chains_info,a_id,b_id,res_num_a,res_num_b): else: msg = '' - # Not faster downstream when working with resulting arrays. - # a_perm = flex.sort_permutation(sel_a_flat) - # sel_a_flat = sel_a_flat.select(a_perm) - # b_perm = flex.sort_permutation(sel_b_flat) - # sel_b_flat = sel_b_flat.select(b_perm) - - sel_a_flat = list(sel_a_flat) - sel_b_flat = list(sel_b_flat) - sel_a_flat.sort() - sel_b_flat.sort() + # Not faster downstream when working with resulting arrays but keep + # as flex.size_t + a_perm = flex.sort_permutation(sel_a_flat) + sel_a_flat = sel_a_flat.select(a_perm) + b_perm = flex.sort_permutation(sel_b_flat) + sel_b_flat = sel_b_flat.select(b_perm) return sel_a,sel_b,sel_a_flat,sel_b_flat,res_num_a_updated,res_num_b_updated,msg def get_chains_info(ph, selection_list=None): @@ -989,8 +1005,8 @@ def my_get_rot_trans( master/copy_selection: master and copy iselections """ - other_h = my_selection(ph,master_chain_id, list(master_selection)) - ref_h = my_selection(ph,copy_chain_id, list(copy_selection)) + other_h = my_selection(ph,master_chain_id, master_selection) + ref_h = my_selection(ph,copy_chain_id, copy_selection) other_sites = other_h.atoms().extract_xyz() ref_sites = ref_h.atoms().extract_xyz() From c99d03d7d07510419d3c791a06a351f168ec0f7a Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 24 Jun 2024 13:00:46 -0700 Subject: [PATCH 566/748] First draft on using NCS in pdb_interpretation. --- cctbx/geometry_restraints/__init__.py | 23 ++++ cctbx/geometry_restraints/manager.py | 6 +- iotbx/ncs/__init__.py | 7 +- iotbx/pdb/hierarchy.py | 3 +- mmtbx/monomer_library/pdb_interpretation.py | 126 ++++++++++++++++++-- mmtbx/ncs/ncs_restraints_group_list.py | 38 ++++++ 6 files changed, 187 insertions(+), 16 deletions(-) diff --git a/cctbx/geometry_restraints/__init__.py b/cctbx/geometry_restraints/__init__.py index cc38f9bf1b..13bc60b2d2 100644 --- a/cctbx/geometry_restraints/__init__.py +++ b/cctbx/geometry_restraints/__init__.py @@ -12,6 +12,7 @@ from six.moves import zip ext = bp.import_ext("cctbx_geometry_restraints_ext") from cctbx_geometry_restraints_ext import * +from cctbx import geometry_restraints import scitbx.stl.map import math @@ -117,6 +118,28 @@ def __init__(self, n_seq, strict_conflict_handling): strict_conflict_handling=strict_conflict_handling) self.n_seq = n_seq + def expand_with_ncs(self, nrgl): + # print("original proxies:", [p.i_seqs for p in self.proxies]) + n_proxies = len(self.proxies) + for i, p in enumerate(self.proxies): + if i == n_proxies: + break + all_new_iseqs = nrgl.get_copy_iseqs(p.i_seqs) + # print(' all_new_iseqs', all_new_iseqs) + for new_iseqs in all_new_iseqs: + new_proxy = bond_simple_proxy( + i_seqs=new_iseqs, + distance_ideal=p.distance_ideal, + weight=p.weight, + origin_id=p.origin_id) + # marking table + self.table[new_iseqs[0]][new_iseqs[1]] = self.proxies.size() + # ~ self._append_proxy + self.proxies.append(new_proxy) + self.source_labels.append(self.source_labels[i]) + self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) + + def initialize_table(self): proxy_registry_base.initialize_table(self) self.table = [{} for i in range(self.n_seq)] diff --git a/cctbx/geometry_restraints/manager.py b/cctbx/geometry_restraints/manager.py index e3c705d1d4..85daeb29e0 100644 --- a/cctbx/geometry_restraints/manager.py +++ b/cctbx/geometry_restraints/manager.py @@ -64,9 +64,11 @@ def __init__(self, assert len(shell_sym_tables) > 0 assert shell_sym_tables[0].size() == site_symmetry_table.indices().size() if (nonbonded_types is not None and site_symmetry_table is not None): - assert nonbonded_types.size() == site_symmetry_table.indices().size() + assert nonbonded_types.size() == site_symmetry_table.indices().size(), "%d != %d" % ( + nonbonded_types.size(), site_symmetry_table.indices().size()) if (nonbonded_types is not None) and (nonbonded_charges is not None): - assert (nonbonded_charges.size() == nonbonded_types.size()) + assert nonbonded_charges.size() == nonbonded_types.size(), "%d != %d" % ( + nonbonded_charges.size(), nonbonded_types.size()) adopt_init_args(self, locals(), exclude=["log"]) self.reset_internals() diff --git a/iotbx/ncs/__init__.py b/iotbx/ncs/__init__.py index e2dbd0cf01..2414e6bdc8 100644 --- a/iotbx/ncs/__init__.py +++ b/iotbx/ncs/__init__.py @@ -506,6 +506,8 @@ def build_ncs_obj_from_pdb_asu(self,pdb_h, asc): chain_ids = {x.id for x in pdb_h.models()[0].chains()} if len(chain_ids) > 1: t0 = time() + print("self.params.try_shortcuts", self.params.try_shortcuts) + import sys if self.params.try_shortcuts: # probably the most parameters are not necessary, since # we are going after cases where molecule was multiplied using @@ -515,9 +517,10 @@ def build_ncs_obj_from_pdb_asu(self,pdb_h, asc): chains_info=self.chains_info, chain_similarity_threshold=self.params.chain_similarity_threshold, chain_max_rmsd=self.params.chain_max_rmsd, - log=null_out(), + log=sys.stdout, + # log=null_out(), residue_match_radius=self.params.residue_match_radius) - # print >> self.log, "Time spend for trying shortcut: %.2f" % (time()-t0) + print ("Time spend for trying shortcut: %.2f" % (time()-t0), file=self.log) if self.ncs_restraints_group_list.get_n_groups() == 0: # shortcuts failed self.ncs_restraints_group_list = ncs_search.find_ncs_in_hierarchy( diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index 458ce44463..3032ff071d 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -1157,7 +1157,8 @@ def adopt_xray_structure(self, xray_structure): object to the atoms in the PDB hierarchy. """ if(self.atoms_size() != xray_structure.scatterers().size()): - raise RuntimeError("Incompatible size of hierarchy and scatterers array.") + raise RuntimeError("Incompatible size of hierarchy and scatterers array: %d and %d" % ( + self.atoms_size(), xray_structure.scatterers().size())) scatterers = xray_structure.scatterers() uc = xray_structure.unit_cell() orth = uc.orthogonalize diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index beb42dcb76..c8c27d56c4 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -19,7 +19,7 @@ from cctbx.array_family import flex from scitbx.python_utils import dicts from libtbx.str_utils import show_string -from libtbx.utils import flat_list, Sorry, user_plus_sys_time, plural_s +from libtbx.utils import flat_list, Sorry, user_plus_sys_time, plural_s, null_out from libtbx.utils import format_exception, greek_time from libtbx import Auto, group_args, slots_getstate_setstate from six.moves import cStringIO as StringIO @@ -897,6 +897,36 @@ def __init__(self, type_label, symbols, strict_conflict_handling): self.source_n_expected_atoms = flex.int(symbols.size(), -1) self.charges = flex.int(symbols.size(), 0) + def _show(self): + print ('self.type_label', self.type_label) + print ('size: ', self.symbols.size()) + print (list(self.symbols)) + print (self.strict_conflict_handling) + print (self.n_resolved_conflicts) + print (list(self.source_labels)) + print (list(self.source_n_expected_atoms)) + print (list(self.charges)) + + def expand_with_ncs(self, nrgl, n_atoms): + new_symbols = flex.std_string(n_atoms) + new_source_labels = flex.std_string(n_atoms) + new_source_n_expected_atoms = flex.int(new_symbols.size(), -1) + new_charges = flex.int(new_symbols.size(), 0) + for ncs_group in nrgl: + new_symbols.set_selected(ncs_group.master_iselection, self.symbols) + new_source_labels.set_selected(ncs_group.master_iselection, self.source_labels) + new_source_n_expected_atoms.set_selected(ncs_group.master_iselection, self.source_n_expected_atoms) + new_charges.set_selected(ncs_group.master_iselection, self.charges) + for c in ncs_group.copies: + new_symbols.set_selected(c.iselection, self.symbols) + new_source_labels.set_selected(c.iselection, self.source_labels) + new_source_n_expected_atoms.set_selected(c.iselection, self.source_n_expected_atoms) + new_charges.set_selected(c.iselection, self.charges) + self.symbols = new_symbols + self.source_labels = new_source_labels + self.source_n_expected_atoms = new_source_n_expected_atoms + self.charges = new_charges + def discard_tables(self): self.source_labels = None self.source_n_expected_atoms = None @@ -3055,6 +3085,15 @@ def __init__(self, n_seq, strict_conflict_handling): self.parallelity = geometry_restraints.parallelity_proxy_registry( strict_conflict_handling=strict_conflict_handling) + def expand_with_ncs(self, nrgl): + self.bond_simple.expand_with_ncs(nrgl) + # self.angle.expand_with_ncs() + # self.dihedral.expand_with_ncs() + # self.chirality.expand_with_ncs() + # self.planarity.expand_with_ncs() + # self.parallelity.expand_with_ncs() + + def initialize_tables(self): self.bond_simple.initialize_table() self.angle.initialize_table() @@ -3531,6 +3570,58 @@ def set_donor_acceptor_excl_groups(): self.conformation_dependent_restraints_list = [] model_type_indices = [-1] * len(models) self.all_monomer_mappings = [] + # self.scattering_type_registry = scattering_type_registry( + # # XXX should be same as in pdb_inp.xray_structure_simple + # scattering_types=self.pdb_atoms.extract_element(strip=True), + # strict_conflict_handling=strict_conflict_handling) + # self.nonbonded_energy_type_registry = nonbonded_energy_type_registry( + # n_seq=self.pdb_atoms.size(), + # strict_conflict_handling=strict_conflict_handling) + self.geometry_proxy_registries = geometry_restraints_proxy_registries( + n_seq=self.pdb_atoms.size(), + strict_conflict_handling=strict_conflict_handling) + self.cystein_sulphur_i_seqs = flex.size_t() + self.cystein_monomer_mappings = [] + n_unique_models = 0 + + ncs_will_be_used = False + # trying NCS shortcut here + if len(models) == 1: + # search for NCS + ncs_params = iotbx.ncs.input.get_default_params() + ncs_params.ncs_search.try_shortcuts = True + ncs_obj = iotbx.ncs.input( + ncs_phil_groups = None, + hierarchy = self.pdb_hierarchy.deep_copy(), + params = ncs_params.ncs_search, + log = None) + nrgl = ncs_obj.get_ncs_restraints_group_list() + f_nrgl = nrgl.filter_ncs_restraints_group_list(self.pdb_hierarchy, ncs_obj) + print("Found NCS") + ncs_obj.show(format='phil') + # max_rmsd = nrgl.check_for_max_rmsd(self.sites_cart, 0.01, null_out()) + nrgl_ok = nrgl.check_for_max_rmsd(self.sites_cart, 0.01, sys.stdout) + ncs_will_be_used = (nrgl.get_n_groups()>0) and (nrgl == f_nrgl) and nrgl_ok + if ncs_will_be_used: + print(" will use NCS in pdb_interpretation") + self._full_pdb_hierarchy = self.pdb_hierarchy + self._old_models = models + # self._full_pdb_atoms=self.pdb_atoms, + # self._full_sites_cart=self.sites_cart, + # print("nrgl[0].master_iselection", list(nrgl[0].master_iselection)) + + # nrgl._show(self.pdb_hierarchy, brief=False) + self.pdb_hierarchy = self.pdb_hierarchy.select(nrgl[0].master_iselection) + # print(self.pdb_hierarchy.as_pdb_string()) + self.pdb_atoms = self.pdb_hierarchy.atoms() + self.sites_cart = self.pdb_atoms.extract_xyz() + models = self.pdb_hierarchy.models() + # !!! + + # self.scattering_type_registry + # self.nonbonded_energy_type_registry + # STOP() + self.scattering_type_registry = scattering_type_registry( # XXX should be same as in pdb_inp.xray_structure_simple scattering_types=self.pdb_atoms.extract_element(strip=True), @@ -3538,12 +3629,7 @@ def set_donor_acceptor_excl_groups(): self.nonbonded_energy_type_registry = nonbonded_energy_type_registry( n_seq=self.pdb_atoms.size(), strict_conflict_handling=strict_conflict_handling) - self.geometry_proxy_registries = geometry_restraints_proxy_registries( - n_seq=self.pdb_atoms.size(), - strict_conflict_handling=strict_conflict_handling) - self.cystein_sulphur_i_seqs = flex.size_t() - self.cystein_monomer_mappings = [] - n_unique_models = 0 + for i_model,model in enumerate(models): if (log is not None): print(' Model: "%s"' % model.id, file=log) @@ -3832,6 +3918,22 @@ def raise_if_corrupt(link_resolution): print(" Unresolved apply_cif_link planarities:", \ n_unresolved_apply_cif_link_planarities, file=log) flush_log(log) + # multiply by NCS and restore all others + # self.scattering_type_registry._show() + if ncs_will_be_used: + # multiply first? + print(" NCS: Multiplying, restoring") + self.pdb_hierarchy = self._full_pdb_hierarchy + self.pdb_atoms = self.pdb_hierarchy.atoms() + self.sites_cart = self.pdb_atoms.extract_xyz() + # We have to expand the tables using ncs information... + nrgl.setup_sets() + self.scattering_type_registry.expand_with_ncs(nrgl, self.pdb_hierarchy.atoms_size()) + self.nonbonded_energy_type_registry.expand_with_ncs(nrgl, self.pdb_hierarchy.atoms_size()) + self.geometry_proxy_registries.expand_with_ncs(nrgl) + # self.scattering_type_registry._show() + # STOP() + for apply in self.apply_cif_links: if (not apply.was_used): raise RuntimeError( @@ -3873,8 +3975,8 @@ def raise_if_corrupt(link_resolution): self.type_h_bonds = self.type_h_bonds.convert() self.time_building_chain_proxies = timer.elapsed() # Make sure pdb_hierarchy and xray_structure are consistent - if(self.special_position_settings is not None): - self.pdb_hierarchy.adopt_xray_structure(self.extract_xray_structure()) + # if(self.special_position_settings is not None): + # self.pdb_hierarchy.adopt_xray_structure(self.extract_xray_structure()) # Create selection_manager self.selman = selection_manager( all_monomer_mappings = self.all_monomer_mappings, @@ -5674,9 +5776,11 @@ def extract_xray_structure(self, unknown_scattering_type_substitute = "?"): if (site_symmetry_table is not None): assert site_symmetry_table.indices().size() == sites_frac.size() scattering_types = self.scattering_type_registry.symbols - if (scattering_types is None): - scattering_types = self.get_element_symbols(strip_symbols=True) + # if (scattering_types is None): + # assert 0 # Never used, the function is not defined: + # scattering_types = self.get_element_symbols(strip_symbols=True) site_symmetry_ops = None + print("in extract xrs: ", len(self.pdb_atoms), len(sites_frac), len(scattering_types)) for i_seq,atom,site_frac,scattering_type in zip( count(), self.pdb_atoms, diff --git a/mmtbx/ncs/ncs_restraints_group_list.py b/mmtbx/ncs/ncs_restraints_group_list.py index 247d7e8c28..7655340d2b 100644 --- a/mmtbx/ncs/ncs_restraints_group_list.py +++ b/mmtbx/ncs/ncs_restraints_group_list.py @@ -70,6 +70,10 @@ def __eq__(self, other): result &= sc == oc return result + def setup_selection_set(self): + self.set_master_iselection = set(self.master_iselection) + self.list_master_iselection = list(self.master_iselection) + def get_iselections_list(self): """ Returns all iselections in the group in one list @@ -233,6 +237,40 @@ def __eq__(self, other): result &= (sg == og) return result + def setup_sets(self): + for g in self: + g.setup_selection_set() + + def get_copy_iseqs(self, iseqs): + """get iseqs from copies for proxy. E.g. for bond: + iseqs = [1,2] + + Args: + iseqs (iterable): iseqs of original proxy + + Returns: + [[3,4], [5,6], [7,8]] + """ + result = [] + # self.setup_sets() + # print("iseqs in get_copy_iseqs:", iseqs) + for gr in self: + if iseqs[0] in gr.set_master_iselection: + # check the rest are in: + for iseq in iseqs[1:]: + assert iseq in gr.set_master_iselection + # now iterate over input iseqs and populate the result + for i in range(gr.get_number_of_copies()): + result.append([]) + for in_iseq in iseqs: + # find the index: + iseq_idex = gr.list_master_iselection.index(in_iseq) + for i, c in enumerate(gr.copies): + result[i].append(c.iselection[iseq_idex]) + return result + + + def get_n_groups(self): return len(self) From a1886d17fb834e095ecaaaa90ed9e8f230455396 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Thu, 27 Jun 2024 13:59:33 -0600 Subject: [PATCH 567/748] Introduce parameter --- mmtbx/monomer_library/pdb_interpretation.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index c8c27d56c4..19b1f36562 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -214,6 +214,9 @@ def __init__(self, residue_name, atom_name, atom_element): sort_atoms = True .type = bool .short_caption = Sort atoms in input pdb so they would be in the same order + use_ncs_to_build_restraints = True + .type = bool + .short_caption = Look for NCS and use it to speed up building restraints flip_symmetric_amino_acids = True .type = bool .short_caption = Flip symmetric amino acids to conform to IUPAC convention @@ -3586,7 +3589,7 @@ def set_donor_acceptor_excl_groups(): ncs_will_be_used = False # trying NCS shortcut here - if len(models) == 1: + if len(models) == 1 and self.params.use_ncs_to_build_restraints: # search for NCS ncs_params = iotbx.ncs.input.get_default_params() ncs_params.ncs_search.try_shortcuts = True From 8a5fe4ceeba15bf9ea00ed13648b3f217c5a65c4 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 2 Jul 2024 12:18:30 -0700 Subject: [PATCH 568/748] Expanding restraints with NCS. Not changing existing array. --- cctbx/geometry_restraints/__init__.py | 152 +++++++++++++++++++- mmtbx/monomer_library/pdb_interpretation.py | 10 +- 2 files changed, 151 insertions(+), 11 deletions(-) diff --git a/cctbx/geometry_restraints/__init__.py b/cctbx/geometry_restraints/__init__.py index 13bc60b2d2..548d93ea9f 100644 --- a/cctbx/geometry_restraints/__init__.py +++ b/cctbx/geometry_restraints/__init__.py @@ -111,6 +111,10 @@ def _handle_conflict(self, process_result.tabulated_proxy = proxy class bond_simple_proxy_registry(proxy_registry_base): + """ + self.table: + [ {iseq1: Nproxy} ] , index in this array is iseq0 + """ def __init__(self, n_seq, strict_conflict_handling): proxy_registry_base.__init__(self, @@ -120,10 +124,9 @@ def __init__(self, n_seq, strict_conflict_handling): def expand_with_ncs(self, nrgl): # print("original proxies:", [p.i_seqs for p in self.proxies]) - n_proxies = len(self.proxies) + # n_proxies = len(self.proxies) + additional_proxies = [] for i, p in enumerate(self.proxies): - if i == n_proxies: - break all_new_iseqs = nrgl.get_copy_iseqs(p.i_seqs) # print(' all_new_iseqs', all_new_iseqs) for new_iseqs in all_new_iseqs: @@ -131,13 +134,17 @@ def expand_with_ncs(self, nrgl): i_seqs=new_iseqs, distance_ideal=p.distance_ideal, weight=p.weight, - origin_id=p.origin_id) + slack=p.slack, + limit=p.limit, + top_out=p.top_out, + origin_id=p.origin_id).sort_i_seqs() # marking table self.table[new_iseqs[0]][new_iseqs[1]] = self.proxies.size() # ~ self._append_proxy - self.proxies.append(new_proxy) + additional_proxies.append(new_proxy) self.source_labels.append(self.source_labels[i]) self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) + self.proxies.extend(additional_proxies) def initialize_table(self): @@ -180,12 +187,40 @@ def process(self, source_info, proxy, tolerance=1.e-6): return result class angle_proxy_registry(proxy_registry_base): + # + """ + self.table: nested dicts + { iseq1: + { + (iseq0, iseq2) : Nproxy + } + } + """ def __init__(self, strict_conflict_handling): proxy_registry_base.__init__(self, proxies=shared_angle_proxy(), strict_conflict_handling=strict_conflict_handling) + def expand_with_ncs(self, nrgl): + additional_proxies = [] + # n_proxies = len(self.proxies) + for i, p in enumerate(self.proxies): + all_new_iseqs = nrgl.get_copy_iseqs(p.i_seqs) + for new_iseqs in all_new_iseqs: + new_proxy = angle_proxy( + i_seqs=new_iseqs, + proxy=p).sort_i_seqs() + # marking table + tab_i_seq_1 = self.table.setdefault(new_proxy.i_seqs[1], {}) + tab_i_seq_1[(new_proxy.i_seqs[0], new_proxy.i_seqs[2])] = self.proxies.size() + # ~ self._append_proxy + additional_proxies.append(new_proxy) + # self.proxies.append(new_proxy) + self.source_labels.append(self.source_labels[i]) + self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) + self.proxies.extend(additional_proxies) + def add_if_not_duplicated(self, proxy, tolerance=1.e-6): assert len(proxy.i_seqs) == 3 proxy = proxy.sort_i_seqs() @@ -233,12 +268,38 @@ def lookup_i_proxy(self, i_seqs): return tab_i_seq_1.get((i0, i2)) class dihedral_proxy_registry(proxy_registry_base): + """ + self.table - similar to angle: + { iseq0: + { + (iseq1, iseq2, iseq3) : Nproxy + } + } + """ def __init__(self, strict_conflict_handling): proxy_registry_base.__init__(self, proxies=shared_dihedral_proxy(), strict_conflict_handling=strict_conflict_handling) + def expand_with_ncs(self, nrgl): + additional_proxies = [] + for i, p in enumerate(self.proxies): + all_new_iseqs = nrgl.get_copy_iseqs(p.i_seqs) + for new_iseqs in all_new_iseqs: + new_proxy = dihedral_proxy( + i_seqs=new_iseqs, + proxy=p).sort_i_seqs() + # marking table + tab_i_seq_0 = self.table.setdefault(new_proxy.i_seqs[0], {}) + tab_i_seq_0[(new_proxy.i_seqs[1], new_proxy.i_seqs[2], new_proxy.i_seqs[3])] = self.proxies.size() + # ~ self._append_proxy + additional_proxies.append(new_proxy) + # self.proxies.append(new_proxy) + self.source_labels.append(self.source_labels[i]) + self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) + self.proxies.extend(additional_proxies) + def add_if_not_duplicated(self, proxy, tolerance=1.e-6): assert len(proxy.i_seqs) == 4 proxy = proxy.sort_i_seqs() @@ -293,12 +354,38 @@ def lookup_i_proxy(self, i_seqs): return (tab_i_seq_0.get((i1, i2, i3)), angle_sign) class chirality_proxy_registry(proxy_registry_base): + """ + self.table - same as dihedral: + { iseq0: + { + (iseq1, iseq2, iseq3) : Nproxy + } + } + """ def __init__(self, strict_conflict_handling): proxy_registry_base.__init__(self, proxies=shared_chirality_proxy(), strict_conflict_handling=strict_conflict_handling) + def expand_with_ncs(self, nrgl): + additional_proxies = [] + for i, p in enumerate(self.proxies): + all_new_iseqs = nrgl.get_copy_iseqs(p.i_seqs) + for new_iseqs in all_new_iseqs: + new_proxy = chirality_proxy( + i_seqs=new_iseqs, + proxy=p).sort_i_seqs() + # marking table + tab_i_seq_0 = self.table.setdefault(new_proxy.i_seqs[0], {}) + tab_i_seq_0[(new_proxy.i_seqs[1], new_proxy.i_seqs[2], new_proxy.i_seqs[3])] = self.proxies.size() + # ~ self._append_proxy + additional_proxies.append(new_proxy) + # self.proxies.append(new_proxy) + self.source_labels.append(self.source_labels[i]) + self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) + self.proxies.extend(additional_proxies) + def add_if_not_duplicated(self, proxy, tolerance=1.e-6): proxy = proxy.sort_i_seqs() tab_i_seq_0 = self.table.setdefault(proxy.i_seqs[0], {}) @@ -336,12 +423,42 @@ def process(self, source_info, proxy, tolerance=1.e-6): return result class planarity_proxy_registry(proxy_registry_base): + """ + self.table: + + self.table - similar to dihedral, chiralities, but undefined + number of iseqs in the nested dictionary keys: + { iseq0: + { + (iseq1, iseq2, iseq3, ... ) : Nproxy + } + } + + """ def __init__(self, strict_conflict_handling): proxy_registry_base.__init__(self, proxies=shared_planarity_proxy(), strict_conflict_handling=strict_conflict_handling) + def expand_with_ncs(self, nrgl): + additional_proxies = [] + for i, p in enumerate(self.proxies): + all_new_iseqs = nrgl.get_copy_iseqs(p.i_seqs) + for new_iseqs in all_new_iseqs: + new_proxy = planarity_proxy( + i_seqs=new_iseqs, + proxy=p).sort_i_seqs() + # marking table + tab_i_seq_0 = self.table.setdefault(new_proxy.i_seqs[0], {}) + tab_i_seq_0[(new_proxy.i_seqs[1:])] = self.proxies.size() + # ~ self._append_proxy + additional_proxies.append(new_proxy) + # self.proxies.append(new_proxy) + self.source_labels.append(self.source_labels[i]) + self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) + self.proxies.extend(additional_proxies) + def add_if_not_duplicated(self, proxy, tolerance=1.e-6): assert proxy.i_seqs.size() > 2 proxy = proxy.sort_i_seqs() @@ -379,11 +496,35 @@ def process(self, source_info, proxy, tolerance=1.e-6): return result class parallelity_proxy_registry(proxy_registry_base): + """ + self.table: + { ( (iseqs), (jseqs) ) : Nproxy } + """ + def __init__(self, strict_conflict_handling): proxy_registry_base.__init__(self, proxies=shared_parallelity_proxy(), strict_conflict_handling=strict_conflict_handling) + def expand_with_ncs(self, nrgl): + additional_proxies = [] + for i, p in enumerate(self.proxies): + all_new_iseqs = nrgl.get_copy_iseqs(p.i_seqs) + all_new_jseqs = nrgl.get_copy_iseqs(p.i_seqs) + for new_iseqs, new_jseqs in zip(all_new_iseqs, all_new_jseqs): + new_proxy = parallelity_proxy( + i_seqs=new_iseqs, + j_seqs=new_jseqs, + proxy=p).sort_i_seqs() + # marking table + self.table[(tuple(new_proxy.i_seqs), tuple(new_proxy.j_seqs))] = self.proxies.size() + # ~ self._append_proxy + additional_proxies.append(new_proxy) + # self.proxies.append(new_proxy) + self.source_labels.append(self.source_labels[i]) + self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) + self.proxies.extend(additional_proxies) + def add_if_not_duplicated(self, proxy, tolerance=1.e-6): assert proxy.i_seqs.size() > 2 assert proxy.j_seqs.size() > 2 @@ -398,7 +539,6 @@ def add_if_not_duplicated(self, proxy, tolerance=1.e-6): return True return False - def process(self, source_info, proxy, tolerance=1.e-6): assert proxy.i_seqs.size() > 2 assert proxy.j_seqs.size() > 2 diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index 19b1f36562..1053f62d30 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -3090,11 +3090,11 @@ def __init__(self, n_seq, strict_conflict_handling): def expand_with_ncs(self, nrgl): self.bond_simple.expand_with_ncs(nrgl) - # self.angle.expand_with_ncs() - # self.dihedral.expand_with_ncs() - # self.chirality.expand_with_ncs() - # self.planarity.expand_with_ncs() - # self.parallelity.expand_with_ncs() + self.angle.expand_with_ncs(nrgl) + self.dihedral.expand_with_ncs(nrgl) + self.chirality.expand_with_ncs(nrgl) + self.planarity.expand_with_ncs(nrgl) + self.parallelity.expand_with_ncs(nrgl) def initialize_tables(self): From 953f0da33bb00be72a9b2f6d6659e0476c536f86 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Wed, 3 Jul 2024 15:52:25 -0700 Subject: [PATCH 569/748] Now handle multiple NCS groups --- iotbx/ncs/__init__.py | 5 +-- iotbx/pdb/hierarchy.py | 5 ++- mmtbx/monomer_library/pdb_interpretation.py | 45 +++++++++++---------- 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/iotbx/ncs/__init__.py b/iotbx/ncs/__init__.py index 2414e6bdc8..0af90892db 100644 --- a/iotbx/ncs/__init__.py +++ b/iotbx/ncs/__init__.py @@ -506,8 +506,6 @@ def build_ncs_obj_from_pdb_asu(self,pdb_h, asc): chain_ids = {x.id for x in pdb_h.models()[0].chains()} if len(chain_ids) > 1: t0 = time() - print("self.params.try_shortcuts", self.params.try_shortcuts) - import sys if self.params.try_shortcuts: # probably the most parameters are not necessary, since # we are going after cases where molecule was multiplied using @@ -517,8 +515,7 @@ def build_ncs_obj_from_pdb_asu(self,pdb_h, asc): chains_info=self.chains_info, chain_similarity_threshold=self.params.chain_similarity_threshold, chain_max_rmsd=self.params.chain_max_rmsd, - log=sys.stdout, - # log=null_out(), + log=null_out(), residue_match_radius=self.params.residue_match_radius) print ("Time spend for trying shortcut: %.2f" % (time()-t0), file=self.log) if self.ncs_restraints_group_list.get_n_groups() == 0: diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index 3032ff071d..fc68b79938 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -1157,8 +1157,9 @@ def adopt_xray_structure(self, xray_structure): object to the atoms in the PDB hierarchy. """ if(self.atoms_size() != xray_structure.scatterers().size()): - raise RuntimeError("Incompatible size of hierarchy and scatterers array: %d and %d" % ( - self.atoms_size(), xray_structure.scatterers().size())) + raise RuntimeError("Incompatible size of hierarchy and scatterers array.") + # raise RuntimeError("Incompatible size of hierarchy and scatterers array: %d and %d" % ( + # self.atoms_size(), xray_structure.scatterers().size())) scatterers = xray_structure.scatterers() uc = xray_structure.unit_cell() orth = uc.orthogonalize diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index 1053f62d30..b8d119a4d4 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -214,7 +214,7 @@ def __init__(self, residue_name, atom_name, atom_element): sort_atoms = True .type = bool .short_caption = Sort atoms in input pdb so they would be in the same order - use_ncs_to_build_restraints = True + use_ncs_to_build_restraints = False .type = bool .short_caption = Look for NCS and use it to speed up building restraints flip_symmetric_amino_acids = True @@ -916,15 +916,16 @@ def expand_with_ncs(self, nrgl, n_atoms): new_source_n_expected_atoms = flex.int(new_symbols.size(), -1) new_charges = flex.int(new_symbols.size(), 0) for ncs_group in nrgl: - new_symbols.set_selected(ncs_group.master_iselection, self.symbols) - new_source_labels.set_selected(ncs_group.master_iselection, self.source_labels) - new_source_n_expected_atoms.set_selected(ncs_group.master_iselection, self.source_n_expected_atoms) - new_charges.set_selected(ncs_group.master_iselection, self.charges) + # print("len(ncs_group.master_iselection), len(self.symbols), n_atoms", len(ncs_group.master_iselection), len(self.symbols), n_atoms) + new_symbols.set_selected(ncs_group.master_iselection, self.symbols.select(ncs_group.master_iselection)) + new_source_labels.set_selected(ncs_group.master_iselection, self.source_labels.select(ncs_group.master_iselection)) + new_source_n_expected_atoms.set_selected(ncs_group.master_iselection, self.source_n_expected_atoms.select(ncs_group.master_iselection)) + new_charges.set_selected(ncs_group.master_iselection, self.charges.select(ncs_group.master_iselection)) for c in ncs_group.copies: - new_symbols.set_selected(c.iselection, self.symbols) - new_source_labels.set_selected(c.iselection, self.source_labels) - new_source_n_expected_atoms.set_selected(c.iselection, self.source_n_expected_atoms) - new_charges.set_selected(c.iselection, self.charges) + new_symbols.set_selected(c.iselection, self.symbols.select(ncs_group.master_iselection)) + new_source_labels.set_selected(c.iselection, self.source_labels.select(ncs_group.master_iselection)) + new_source_n_expected_atoms.set_selected(c.iselection, self.source_n_expected_atoms.select(ncs_group.master_iselection)) + new_charges.set_selected(c.iselection, self.charges.select(ncs_group.master_iselection)) self.symbols = new_symbols self.source_labels = new_source_labels self.source_n_expected_atoms = new_source_n_expected_atoms @@ -3587,7 +3588,7 @@ def set_donor_acceptor_excl_groups(): self.cystein_monomer_mappings = [] n_unique_models = 0 - ncs_will_be_used = False + use_ncs_for_interpretation = False # trying NCS shortcut here if len(models) == 1 and self.params.use_ncs_to_build_restraints: # search for NCS @@ -3600,12 +3601,12 @@ def set_donor_acceptor_excl_groups(): log = None) nrgl = ncs_obj.get_ncs_restraints_group_list() f_nrgl = nrgl.filter_ncs_restraints_group_list(self.pdb_hierarchy, ncs_obj) - print("Found NCS") - ncs_obj.show(format='phil') + # print("Found NCS") + # ncs_obj.show(format='phil') # max_rmsd = nrgl.check_for_max_rmsd(self.sites_cart, 0.01, null_out()) - nrgl_ok = nrgl.check_for_max_rmsd(self.sites_cart, 0.01, sys.stdout) - ncs_will_be_used = (nrgl.get_n_groups()>0) and (nrgl == f_nrgl) and nrgl_ok - if ncs_will_be_used: + nrgl_ok = nrgl.check_for_max_rmsd(self.sites_cart, 0.01, null_out()) + use_ncs_for_interpretation = (nrgl.get_n_groups()>0) and (nrgl == f_nrgl) and nrgl_ok + if use_ncs_for_interpretation: print(" will use NCS in pdb_interpretation") self._full_pdb_hierarchy = self.pdb_hierarchy self._old_models = models @@ -3614,7 +3615,9 @@ def set_donor_acceptor_excl_groups(): # print("nrgl[0].master_iselection", list(nrgl[0].master_iselection)) # nrgl._show(self.pdb_hierarchy, brief=False) - self.pdb_hierarchy = self.pdb_hierarchy.select(nrgl[0].master_iselection) + master_and_rest_bool_selection = ~flex.bool(self._full_pdb_hierarchy.atoms_size(), nrgl.get_all_copies_selection()) + self.pdb_hierarchy = self.pdb_hierarchy.select(master_and_rest_bool_selection) + # print(self.pdb_hierarchy.as_pdb_string()) self.pdb_atoms = self.pdb_hierarchy.atoms() self.sites_cart = self.pdb_atoms.extract_xyz() @@ -3923,9 +3926,9 @@ def raise_if_corrupt(link_resolution): flush_log(log) # multiply by NCS and restore all others # self.scattering_type_registry._show() - if ncs_will_be_used: + if use_ncs_for_interpretation: # multiply first? - print(" NCS: Multiplying, restoring") + # print(" NCS: Multiplying, restoring") self.pdb_hierarchy = self._full_pdb_hierarchy self.pdb_atoms = self.pdb_hierarchy.atoms() self.sites_cart = self.pdb_atoms.extract_xyz() @@ -3978,8 +3981,8 @@ def raise_if_corrupt(link_resolution): self.type_h_bonds = self.type_h_bonds.convert() self.time_building_chain_proxies = timer.elapsed() # Make sure pdb_hierarchy and xray_structure are consistent - # if(self.special_position_settings is not None): - # self.pdb_hierarchy.adopt_xray_structure(self.extract_xray_structure()) + if(self.special_position_settings is not None): + self.pdb_hierarchy.adopt_xray_structure(self.extract_xray_structure()) # Create selection_manager self.selman = selection_manager( all_monomer_mappings = self.all_monomer_mappings, @@ -5783,7 +5786,6 @@ def extract_xray_structure(self, unknown_scattering_type_substitute = "?"): # assert 0 # Never used, the function is not defined: # scattering_types = self.get_element_symbols(strip_symbols=True) site_symmetry_ops = None - print("in extract xrs: ", len(self.pdb_atoms), len(sites_frac), len(scattering_types)) for i_seq,atom,site_frac,scattering_type in zip( count(), self.pdb_atoms, @@ -6097,6 +6099,7 @@ def geometry_restraints_manager(self, print(" Total time for adding SS restraints: %.2f" % (t3-t1), file=self.log) print(file=self.log) if (self.log is not None): + # if False: print(" Time building geometry restraints manager: %.2f seconds" % ( self.all_chain_proxies.time_building_geometry_restraints_manager), file=self.log) print(file=self.log) From 1e5cd29632502557fc530e505ea0ac6c0d32b44f Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Thu, 11 Jul 2024 11:42:45 -0700 Subject: [PATCH 570/748] Removing unnecessary import --- cctbx/geometry_restraints/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cctbx/geometry_restraints/__init__.py b/cctbx/geometry_restraints/__init__.py index 548d93ea9f..180e205f87 100644 --- a/cctbx/geometry_restraints/__init__.py +++ b/cctbx/geometry_restraints/__init__.py @@ -12,7 +12,6 @@ from six.moves import zip ext = bp.import_ext("cctbx_geometry_restraints_ext") from cctbx_geometry_restraints_ext import * -from cctbx import geometry_restraints import scitbx.stl.map import math From 614642a2cca95dc9f96483caf7ea660cd6775a0b Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Thu, 11 Jul 2024 13:38:52 -0700 Subject: [PATCH 571/748] Cleanup --- mmtbx/refinement/real_space/tst_individual_sites_3.py | 2 +- mmtbx/regression/ncs/tst_minimization_ncs_constraints2.py | 2 +- .../ncs/tst_minimization_ncs_constraints_real_space.py | 2 +- mmtbx/utils/__init__.py | 2 -- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/mmtbx/refinement/real_space/tst_individual_sites_3.py b/mmtbx/refinement/real_space/tst_individual_sites_3.py index af529c668a..781a4f9e10 100644 --- a/mmtbx/refinement/real_space/tst_individual_sites_3.py +++ b/mmtbx/refinement/real_space/tst_individual_sites_3.py @@ -500,7 +500,7 @@ """ def get_pdb_inputs(pdb_str, restraints): - ppf = mmtbx.utils.process_pdb_file_srv(log=False).process_pdb_files( + ppf = mmtbx.utils.process_pdb_file_srv().process_pdb_files( raw_records=pdb_str.splitlines())[0] xrs = ppf.xray_structure(show_summary = False) restraints_manager=None diff --git a/mmtbx/regression/ncs/tst_minimization_ncs_constraints2.py b/mmtbx/regression/ncs/tst_minimization_ncs_constraints2.py index 6534167511..4d27d81ef4 100644 --- a/mmtbx/regression/ncs/tst_minimization_ncs_constraints2.py +++ b/mmtbx/regression/ncs/tst_minimization_ncs_constraints2.py @@ -230,7 +230,7 @@ def get_inputs(prefix, pdb_answer, pdb_poor, ncs_params_str, real_space, d_min): ph_poor.atoms().reset_i_seq() xrs_poor = pdb_inp_poor.xray_structure_simple() # - ppf = mmtbx.utils.process_pdb_file_srv(log=False).process_pdb_files( + ppf = mmtbx.utils.process_pdb_file_srv().process_pdb_files( raw_records=pdb_poor.splitlines())[0] mmtbx.utils.assert_xray_structures_equal( x1=ppf.xray_structure(show_summary = False), diff --git a/mmtbx/regression/ncs/tst_minimization_ncs_constraints_real_space.py b/mmtbx/regression/ncs/tst_minimization_ncs_constraints_real_space.py index 416ec9847d..eb83ff8f5b 100644 --- a/mmtbx/regression/ncs/tst_minimization_ncs_constraints_real_space.py +++ b/mmtbx/regression/ncs/tst_minimization_ncs_constraints_real_space.py @@ -108,7 +108,7 @@ def run(prefix="tst", d_min=1.0): ph_poor.atoms().reset_i_seq() xrs_poor = pdb_inp_poor.xray_structure_simple() # - ppf = mmtbx.utils.process_pdb_file_srv(log=False).process_pdb_files( + ppf = mmtbx.utils.process_pdb_file_srv().process_pdb_files( raw_records=pdb_str_poor.splitlines())[0] mmtbx.utils.assert_xray_structures_equal( x1=ppf.xray_structure(show_summary = False), diff --git a/mmtbx/utils/__init__.py b/mmtbx/utils/__init__.py index da080996e9..6c7d51f3d2 100644 --- a/mmtbx/utils/__init__.py +++ b/mmtbx/utils/__init__.py @@ -266,8 +266,6 @@ def __init__(self, crystal_symmetry = None, use_neutron_distances=use_neutron_distances, ) else: self.ener_lib = ener_lib - if(self.log is None): self.log = sys.stdout - if(self.log == False): self.log = None def process_pdb_files(self, pdb_file_names = None, raw_records = None, pdb_inp=None, From 5d40b2969a96add3c68464e2149c3674748c0671 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 16 Jul 2024 08:07:06 -0700 Subject: [PATCH 572/748] Allow p.pdb_interpretation.allow_polymer_cross_special_position in holton_geometry_validation --- mmtbx/validation/holton_geometry_validation.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index ff509e40cd..978957f65a 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -988,7 +988,11 @@ def get_model(info): # write to it info.dm.write_model_file(info.model, info.filename) info.model.set_stop_for_unknowns(False) - info.model.process(make_restraints=True) + # Allow polymer to cross special positions if necessary + p = info.model.get_current_pdb_interpretation_params() + p.pdb_interpretation.allow_polymer_cross_special_position=True + info.model.process(make_restraints=True, + pdb_interpretation_params = p) info.model.setup_riding_h_manager(idealize=True) info.chain_dict = {} for chain_id in info.model.chain_ids(unique_only = True): From 05cd2c48c5ee5e0e885d232db97ead2cf4dbd250 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 16 Jul 2024 08:32:14 -0700 Subject: [PATCH 573/748] clean clutter --- mmtbx/validation/holton_geometry_validation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index 978957f65a..e1953e8ab9 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -990,7 +990,7 @@ def get_model(info): info.model.set_stop_for_unknowns(False) # Allow polymer to cross special positions if necessary p = info.model.get_current_pdb_interpretation_params() - p.pdb_interpretation.allow_polymer_cross_special_position=True + p.pdb_interpretation.allow_polymer_cross_special_position=True info.model.process(make_restraints=True, pdb_interpretation_params = p) info.model.setup_riding_h_manager(idealize=True) From 40b388366e7076d045297ed8dfd84d1b4ad6e2f5 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 17 Jul 2024 09:56:52 -0700 Subject: [PATCH 574/748] XFEL CI: switch back to CentOS 7 --- .azure-pipelines/xfel/conda-linux.yml | 12 ++++++++++++ .azure-pipelines/xfel/xfel-ci-build.yml | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.azure-pipelines/xfel/conda-linux.yml b/.azure-pipelines/xfel/conda-linux.yml index 84325457df..2bbfea1e1f 100644 --- a/.azure-pipelines/xfel/conda-linux.yml +++ b/.azure-pipelines/xfel/conda-linux.yml @@ -49,6 +49,18 @@ jobs: # https://github.com/ApexAI/performance_test/blob/master/azure-pipelines.yml#L9-L17 # centos setup + # https://serverfault.com/questions/1161816/mirrorlist-centos-org-no-longer-resolve + - script: | + set -xe + /tmp/docker exec -t -u 0 ci-container \ + sh -c "sed -i s/mirror.centos.org/vault.centos.org/g /etc/yum.repos.d/*.repo" + /tmp/docker exec -t -u 0 ci-container \ + sh -c "sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/*.repo" + /tmp/docker exec -t -u 0 ci-container \ + sh -c "sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo" + displayName: Modify yum repositories for CentOS 7 + condition: eq('${{ parameters.distribution }}', 'centos') + - script: | /tmp/docker exec -t -u 0 ci-container \ sh -c "yum install -y sudo" diff --git a/.azure-pipelines/xfel/xfel-ci-build.yml b/.azure-pipelines/xfel/xfel-ci-build.yml index d032bef6d0..e8a921acb6 100644 --- a/.azure-pipelines/xfel/xfel-ci-build.yml +++ b/.azure-pipelines/xfel/xfel-ci-build.yml @@ -1,8 +1,8 @@ jobs: - template: ./conda-linux.yml parameters: - distribution: rockylinux - version: [8] + distribution: centos + version: [7] modules: xfel_modules template: ./unix-conda-build.yml prefix: xfel_ From 9e4c2b4db54a5a0fa0f4cfc1034a16ff19f1bc2a Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Wed, 17 Jul 2024 14:56:45 -0700 Subject: [PATCH 575/748] temp. disable of pH restraints --- mmtbx/monomer_library/pdb_interpretation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index b8d119a4d4..94f00dcffa 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -5934,7 +5934,7 @@ def __init__(self, if atoms[i].element in ['H', 'D']: missing_h_atoms=True break - if missing_h_atoms: + if missing_h_atoms and 0: # turning off until debugged NWM rc = pH_dependent_restraints.adjust_geometry_proxies_registeries( self.all_chain_proxies.pdb_hierarchy, self.all_chain_proxies.geometry_proxy_registries, From 945df1a9d254df75621a4a4aac9428440cd746fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Tcho=C5=84?= Date: Mon, 22 Jul 2024 14:52:38 -0600 Subject: [PATCH 576/748] Don't `self.params.input.path = None` after `list_input_pairs` on rank0 (#999) --- xfel/merging/application/input/file_loader.py | 1 - 1 file changed, 1 deletion(-) diff --git a/xfel/merging/application/input/file_loader.py b/xfel/merging/application/input/file_loader.py index 4983064986..c4507d2b4f 100644 --- a/xfel/merging/application/input/file_loader.py +++ b/xfel/merging/application/input/file_loader.py @@ -115,7 +115,6 @@ def run(self, all_experiments, all_reflections): if self.mpi_helper.rank == 0: file_list = list_input_pairs(self.params) self.logger.log("Built an input list of %d json/pickle file pairs"%(len(file_list))) - self.params.input.path = None # Rank 0 has already parsed the input parameters # optionally write a file list mapping to disk, useful in post processing if save_experiments_and_reflections=True file_id_from_names = None From f46b6f9c19c7003c359291270b319671a5d05e55 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Mon, 22 Jul 2024 14:12:10 -0700 Subject: [PATCH 577/748] debug code for pH --- .../pH_dependent_restraints.py | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/mmtbx/conformation_dependent_library/pH_dependent_restraints.py b/mmtbx/conformation_dependent_library/pH_dependent_restraints.py index 49ecbe3e4e..d38e9fadfe 100644 --- a/mmtbx/conformation_dependent_library/pH_dependent_restraints.py +++ b/mmtbx/conformation_dependent_library/pH_dependent_restraints.py @@ -8,7 +8,7 @@ from mmtbx.monomer_library import server from cctbx import geometry_restraints -def process_bonds(gpr, bond, atom_dict, atom1, atom2, name1, name2, neutron1, neutron2): +def process_bonds(gpr, bond, atom_dict, atom1, atom2, name1, name2, neutron1, neutron2, atoms=None): atoms_added = {} bond_counters = [0,0] i_seqs = [atom1.i_seq, atom2.i_seq] @@ -20,7 +20,22 @@ def process_bonds(gpr, bond, atom_dict, atom1, atom2, name1, name2, neutron1, ne k=1 l=0 bond_table_entry = gpr.bond_simple.table[i_seqs[k]] + print(atom1.quote(), atom2.quote()) + print(bond_table_entry) + # print(atom_dict) + # for atom, item in atom_dict.items(): + # print('-'*80) + # print(atom, item.show()) + print('='*80) + print(gpr.bond_simple.proxies) + # print(dir(gpr.bond_simple.proxies)) + for i, proxy in enumerate(gpr.bond_simple.proxies): + # print(dir(proxy)) + print(i, proxy.i_seqs) if i_seqs[l] in bond_table_entry: + print(i_seqs[l], i_seqs[k]) + print(atoms[i_seqs[l]].quote()) + print(atoms[i_seqs[k]].quote()) bond_simple = gpr.bond_simple.proxies[i_seqs[k]] bond_simple.distance_ideal = bond.value_dist bond_simple.weight=1/bond.value_dist_esd**2 @@ -144,7 +159,9 @@ def adjust_geometry_proxies_registeries(hierarchy, name1, name2, neutron1, - neutron2) + neutron2, + atoms=pdb_atoms, + ) for i in range(2): bond_counters[i]+=bc[i] if ad: From 76e88fdaceb2b1ba3f4759d1f45d61618ed13bc2 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Mon, 22 Jul 2024 14:12:45 -0700 Subject: [PATCH 578/748] more options for DDR --- .../density_dependent_restraints.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mmtbx/conformation_dependent_library/density_dependent_restraints.py b/mmtbx/conformation_dependent_library/density_dependent_restraints.py index cf8ee3f459..4384210972 100644 --- a/mmtbx/conformation_dependent_library/density_dependent_restraints.py +++ b/mmtbx/conformation_dependent_library/density_dependent_restraints.py @@ -8,6 +8,12 @@ { enable = False .type = bool + weighting_factor = 0.5 + .type = float + cc_minimum = 0. + .type = float + map_value_minimum = 0.5 + .type = float bond_weighting = True .type = bool angle_weighting = True @@ -56,7 +62,7 @@ def expand_i_seqs_to_neighbouring_residue(hierarchy, ddr_i_seqs): rg_set = [] for atom in rg.atoms(): rg_set.append(atom.i_seq) intersection = ddr_set.intersection(set(rg_set)) - if intersection: + if intersection and previous: total_i_seqs += rg_set rc = get_selected_i_seqs(previous, [' CA ', ' C ', ' O ']) total_i_seqs += rc From 243c4616766d5b0567cb03eb9ebdc16d4b13a73f Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Mon, 22 Jul 2024 14:14:57 -0700 Subject: [PATCH 579/748] placeholder for QMF --- libtbx/citations.params | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libtbx/citations.params b/libtbx/citations.params index 0a4a3b2d0a..6547437c7a 100644 --- a/libtbx/citations.params +++ b/libtbx/citations.params @@ -1641,3 +1641,11 @@ citation { pmid = 36762856 doi_id = 10.1107/S2059798323000025 } + +citation { + article_id = qmr_nqh + authors = Moriarty NW, Moussa J, Adams PD + title = Protonation of histidine rings using quantum mechanical methods + journal = Acta Cryst. D + year = 2024 +} From c8aef62350c443264130c7e45bc3243ffa446ffc Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Mon, 22 Jul 2024 14:15:56 -0700 Subject: [PATCH 580/748] read files with ? --- mmtbx/ligands/rdkit_utils.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/mmtbx/ligands/rdkit_utils.py b/mmtbx/ligands/rdkit_utils.py index 32b3519be3..b8e2d586f7 100644 --- a/mmtbx/ligands/rdkit_utils.py +++ b/mmtbx/ligands/rdkit_utils.py @@ -18,7 +18,7 @@ match_mol_indices: Match atom indices of different mols """ -def get_cc_cartesian_coordinates(cc_cif, label='pdbx_model_Cartn_x_ideal'): +def get_cc_cartesian_coordinates(cc_cif, label='pdbx_model_Cartn_x_ideal', ignore_question_mark=False): rc = [] for i, (code, monomer) in enumerate(cc_cif.items()): atom = monomer.get_loop_or_row('_chem_comp_atom') @@ -35,7 +35,8 @@ def get_cc_cartesian_coordinates(cc_cif, label='pdbx_model_Cartn_x_ideal'): tmp.get('_chem_comp_atom.model_Cartn_z'), ) rc.append(xyz) - if '?' in xyz[-1]: return None + if not ignore_question_mark and '?' in xyz[-1]: return None + print(rc) return rc def read_chemical_component_filename(filename): @@ -49,10 +50,14 @@ def read_chemical_component_filename(filename): bond_order_rdkitkey = {value:key for key,value in bond_order_ccd.items()} ccd = cif.reader(filename).model() lookup={} - xyzs = get_cc_cartesian_coordinates(ccd) - if xyzs is None: - xyzs = get_cc_cartesian_coordinates(ccd, label='model_Cartn_x') - if xyzs is None: + def is_coordinates(x): + return x!=('?', '?', '?') + xyzs = get_cc_cartesian_coordinates(ccd, ignore_question_mark=True) + xyzs = list(filter(is_coordinates, xyzs)) + if xyzs is None or len(xyzs)==0: + xyzs = get_cc_cartesian_coordinates(ccd, label='model_Cartn_x', ignore_question_mark=True) + xyzs = list(filter(is_coordinates, xyzs)) + if xyzs is None or len(xyzs)==0: for code, monomer in ccd.items(): break raise Sorry(''' @@ -73,8 +78,12 @@ def read_chemical_component_filename(filename): for prop in ['atom_id', 'type_symbol']: new.SetProp(prop, tmp.get('_chem_comp_atom.%s' % prop, '?')) rdatom = rwmol.AddAtom(new) - xyz = (float(xyzs[j][0]), float(xyzs[j][1]), float(xyzs[j][2])) - conformer.SetAtomPosition(rdatom, xyz) + print(xyzs[j]) + if xyzs[j][0] in ['?']: + pass + else: + xyz = (float(xyzs[j][0]), float(xyzs[j][1]), float(xyzs[j][2])) + conformer.SetAtomPosition(rdatom, xyz) lookup[tmp.get('_chem_comp_atom.atom_id')]=j bond = monomer.get_loop_or_row('_chem_comp_bond') if bond: @@ -88,7 +97,7 @@ def read_chemical_component_filename(filename): #print('---') rwmol.AddBond(atom1, atom2, order) rwmol.AddConformer(conformer) - Chem.SanitizeMol(rwmol) + # Chem.SanitizeMol(rwmol) # from rdkit.Chem.PropertyMol import PropertyMol molecule = rwmol.GetMol() # molecule = PropertyMol(molecule) From 5806fd86907547669566bed170606d8a6a3dee11 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Mon, 22 Jul 2024 14:17:55 -0700 Subject: [PATCH 581/748] new energy unit --- mmtbx/refinement/energy_monitor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mmtbx/refinement/energy_monitor.py b/mmtbx/refinement/energy_monitor.py index 21967c0365..262abe05d6 100644 --- a/mmtbx/refinement/energy_monitor.py +++ b/mmtbx/refinement/energy_monitor.py @@ -1,7 +1,8 @@ from __future__ import absolute_import, division, print_function from libtbx import group_args -to_kcal_mol = {'ev':23.0609, +to_kcal_mol = { 'ev' : 23.0609, + 'hartree' : 627.503, } def _print_energy_in_kcal(e, units): From 4eabd71fe6ef40736950f44006bd9b1a12f49407 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Mon, 22 Jul 2024 14:18:20 -0700 Subject: [PATCH 582/748] read_charge... --- mmtbx/geometry_restraints/orca_manager.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/mmtbx/geometry_restraints/orca_manager.py b/mmtbx/geometry_restraints/orca_manager.py index b6e84f7177..ec2fc20f22 100644 --- a/mmtbx/geometry_restraints/orca_manager.py +++ b/mmtbx/geometry_restraints/orca_manager.py @@ -78,6 +78,20 @@ def read_engrad_output(self): self.gradients = gradients return self.energy, self.gradients + def read_charge(self): + filename = self.get_log_filename() + f=open(filename, 'r') + lines=f.readlines() + del f + #Sum of atomic charges: -1.0000000 + for line in lines: + if line.find('Sum of atomic charges:')>-1: + if len(line.split())==5: + self.charge = float(line.split()[-1]) + else: + self.charge = 99 + return self.charge + def read_energy(self): filename = self.get_log_filename() f=open(filename, 'r') From 3a77803d1365acfaa612618e180de27a4ea9f8cd Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 23 Jul 2024 12:01:21 -0700 Subject: [PATCH 583/748] default solvent model for isolated molecules --- mmtbx/geometry_restraints/quantum_restraints_manager.py | 7 +++++-- mmtbx/programs/quantum_interface.py | 1 - 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mmtbx/geometry_restraints/quantum_restraints_manager.py b/mmtbx/geometry_restraints/quantum_restraints_manager.py index baaec97399..0f378bc627 100644 --- a/mmtbx/geometry_restraints/quantum_restraints_manager.py +++ b/mmtbx/geometry_restraints/quantum_restraints_manager.py @@ -469,22 +469,25 @@ def get_specific_atom_charges(qmr): def get_qm_manager(ligand_model, buffer_model, qmr, program_goal, log=StringIO()): program = qmr.package.program + default_solvent_model='' if program=='test': qmm = qm_manager.base_qm_manager.base_qm_manager elif program=='orca': qmm = orca_manager.orca_manager + default_solvent_model='CPCM' elif program=='mopac': qmm = mopac_manager.mopac_manager + default_solvent_model='EPS=78.4' else: assert 0 qmr = quantum_interface.populate_qmr_defaults(qmr) + if qmr.package.solvent_model: default_solvent_model=qmr.package.solvent_model electron_model = None solvent_model = qmr.package.solvent_model if program_goal in ['energy', 'strain']: electron_model = ligand_model - solvent_model = 'EPS=78.4 PRECISE NSPA=92' # maybe not the best place as it's - # not in the input file??? + solvent_model = default_solvent_model elif program_goal in ['opt', 'bound']: electron_model = buffer_model else: diff --git a/mmtbx/programs/quantum_interface.py b/mmtbx/programs/quantum_interface.py index 6cb16d8f87..2af392db65 100644 --- a/mmtbx/programs/quantum_interface.py +++ b/mmtbx/programs/quantum_interface.py @@ -1277,7 +1277,6 @@ def write_qmr_phil(self, 'protein_optimisation_freeze = *all None main_chain main_chain_to_beta main_chain_to_delta torsions', 'protein_optimisation_freeze = all None main_chain main_chain_to_beta *main_chain_to_delta *torsions') qi_phil_string = qi_phil_string.replace( - # 'solvent_model = None', 'solvent_model = EPS=78.4 PRECISE LET DDMIN=0.0 NSPA=92', 'solvent_model = None', 'solvent_model = EPS=78.4', ) # qi_phil_string = qi_phil_string.replace('buffer = 3.5', 'buffer = 4.') From e75a3e1f8cc41fa21a3b4cb1aa71cc7cbc6aa8f6 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 23 Jul 2024 12:03:49 -0700 Subject: [PATCH 584/748] alert about solvent model --- mmtbx/geometry_restraints/quantum_restraints_manager.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mmtbx/geometry_restraints/quantum_restraints_manager.py b/mmtbx/geometry_restraints/quantum_restraints_manager.py index 0f378bc627..9b365571a3 100644 --- a/mmtbx/geometry_restraints/quantum_restraints_manager.py +++ b/mmtbx/geometry_restraints/quantum_restraints_manager.py @@ -481,8 +481,12 @@ def get_qm_manager(ligand_model, buffer_model, qmr, program_goal, log=StringIO() else: assert 0 qmr = quantum_interface.populate_qmr_defaults(qmr) - if qmr.package.solvent_model: default_solvent_model=qmr.package.solvent_model - + if qmr.package.solvent_model: + default_solvent_model=qmr.package.solvent_model + else: + print(u' Update solvent model for "%s" ligand to %s' % (qmr.selection, + default_solvent_model, + ) electron_model = None solvent_model = qmr.package.solvent_model if program_goal in ['energy', 'strain']: From dd7ca67cc4c88b1c02ab4a4107a6b4d631d78637 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 23 Jul 2024 12:06:42 -0700 Subject: [PATCH 585/748] update --- mmtbx/geometry_restraints/orca_manager.py | 2 +- mmtbx/geometry_restraints/quantum_restraints_manager.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mmtbx/geometry_restraints/orca_manager.py b/mmtbx/geometry_restraints/orca_manager.py index ec2fc20f22..c73191108d 100644 --- a/mmtbx/geometry_restraints/orca_manager.py +++ b/mmtbx/geometry_restraints/orca_manager.py @@ -227,7 +227,7 @@ def cleanup(self, level=None, verbose=False): tf = 'orca_%s.trj' % self.preamble if os.path.exists(tf): uf = 'orca_%s_trj.xyz' % self.preamble - print('rename',tf,uf) + # print('rename',tf,uf) os.rename(tf, uf) most_keepers = ['.xyz', '.log', '.in', '.engrad', '.trj'] for filename in os.listdir('.'): diff --git a/mmtbx/geometry_restraints/quantum_restraints_manager.py b/mmtbx/geometry_restraints/quantum_restraints_manager.py index 9b365571a3..7d73e794d8 100644 --- a/mmtbx/geometry_restraints/quantum_restraints_manager.py +++ b/mmtbx/geometry_restraints/quantum_restraints_manager.py @@ -487,6 +487,7 @@ def get_qm_manager(ligand_model, buffer_model, qmr, program_goal, log=StringIO() print(u' Update solvent model for "%s" ligand to %s' % (qmr.selection, default_solvent_model, ) + ) electron_model = None solvent_model = qmr.package.solvent_model if program_goal in ['energy', 'strain']: From 4129e3428388fe46ba193babf70b3c6c0804b8c0 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 23 Jul 2024 12:30:00 -0700 Subject: [PATCH 586/748] small changes --- mmtbx/geometry_restraints/base_qm_manager.py | 3 ++- .../geometry_restraints/quantum_restraints_manager.py | 10 ++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/mmtbx/geometry_restraints/base_qm_manager.py b/mmtbx/geometry_restraints/base_qm_manager.py index 7dfce73670..4ea95fe7ea 100644 --- a/mmtbx/geometry_restraints/base_qm_manager.py +++ b/mmtbx/geometry_restraints/base_qm_manager.py @@ -48,6 +48,7 @@ def process_qm_log_file(log_filename=None, generator=None, error_lines=None, log=None, + verbose=False, ): if log_filename is not None: generator=loop_over_file(log_filename) error_line = None @@ -55,7 +56,7 @@ def process_qm_log_file(log_filename=None, for i, line in enumerate(generator): if line.find('GEOMETRY OPTIMIZATION CYCLE')>-1: cycle = int(line.split()[4]) - if cycle==1: print(' QM minimisation started', file=log) + if verbose and cycle==1: print(' QM minimisation started', file=log) # if line.find('Max(Improp)')>-1: # conv = process_orca_convergence(last_ten) # if cycle%10==0: diff --git a/mmtbx/geometry_restraints/quantum_restraints_manager.py b/mmtbx/geometry_restraints/quantum_restraints_manager.py index 7d73e794d8..8aadedf19e 100644 --- a/mmtbx/geometry_restraints/quantum_restraints_manager.py +++ b/mmtbx/geometry_restraints/quantum_restraints_manager.py @@ -484,10 +484,12 @@ def get_qm_manager(ligand_model, buffer_model, qmr, program_goal, log=StringIO() if qmr.package.solvent_model: default_solvent_model=qmr.package.solvent_model else: - print(u' Update solvent model for "%s" ligand to %s' % (qmr.selection, - default_solvent_model, - ) - ) + if program_goal in ['energy', 'strain']: + print(u' Update solvent model for "%s" ligand %s to "%s"' % (qmr.selection, + program_goal, + default_solvent_model, + ) + ) electron_model = None solvent_model = qmr.package.solvent_model if program_goal in ['energy', 'strain']: From 38c7950f9cf995664c1dfcbeae37405eb4df77c6 Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Tue, 23 Jul 2024 12:44:14 -0700 Subject: [PATCH 587/748] change const_shrink_donor_acceptor from 0.6 to 0, and fix test failures --- .../tst_nonbonded_overlaps.py | 8 ++++---- .../tst_process_nonbonded_proxies.py | 17 ++++++++--------- mmtbx/dynamics/tst_sa.py | 4 ++-- mmtbx/ligands/tst_ready_set_utils.py | 4 ++-- mmtbx/monomer_library/pdb_interpretation.py | 2 +- mmtbx/regression/model/tst_model.py | 2 +- .../ncs/tst_minimization_ncs_constraints2.py | 16 +++++++--------- 7 files changed, 25 insertions(+), 28 deletions(-) diff --git a/cctbx/geometry_restraints/tst_nonbonded_overlaps.py b/cctbx/geometry_restraints/tst_nonbonded_overlaps.py index 23595adf30..956479c39b 100644 --- a/cctbx/geometry_restraints/tst_nonbonded_overlaps.py +++ b/cctbx/geometry_restraints/tst_nonbonded_overlaps.py @@ -773,7 +773,7 @@ def test_print(self): results = results_str.split('\n') # check number of lines in output - self.assertEqual(len(results),19) + self.assertEqual(len(results),21) # check general table structure self.assertTrue(results[4].startswith('========')) self.assertTrue(results[6].startswith('--------')) @@ -871,13 +871,13 @@ def test_overlaps(self): results = overlaps_count_info.result self.assertEqual(len(results.nb_overlaps_proxies_due_to_sym_op),2) self.assertEqual(len(results.nb_overlaps_proxies_macro_molecule),3) - self.assertEqual(len(results.nb_overlaps_proxies_all),12) + self.assertEqual(len(results.nb_overlaps_proxies_all),14) # results r_overlaps_all = round(results.nb_overlaps_all,2) r_overlaps_sym = round(results.nb_overlaps_due_to_sym_op,2) r_overlaps_macro_mol = round(results.nb_overlaps_macro_molecule,2) # test - self.assertEqual(r_overlaps_all,12) + self.assertEqual(r_overlaps_all,14) self.assertEqual(r_overlaps_sym,2) self.assertEqual(r_overlaps_macro_mol,3) # results @@ -885,7 +885,7 @@ def test_overlaps(self): r_overlaps_sym = round(results.normalized_nbo_sym,2) r_overlaps_macro_mol = round(results.normalized_nbo_macro_molecule,2) # - overlaps_all = round(1000*12/n_atoms,2) + overlaps_all = round(1000*14/n_atoms,2) overlaps_sym = round(1000*2/n_atoms,2) overlaps_macro_mol = round(1000*3/n_atoms_macro_mol,2) # test diff --git a/cctbx/geometry_restraints/tst_process_nonbonded_proxies.py b/cctbx/geometry_restraints/tst_process_nonbonded_proxies.py index c50954cc92..fd0c5e1b78 100644 --- a/cctbx/geometry_restraints/tst_process_nonbonded_proxies.py +++ b/cctbx/geometry_restraints/tst_process_nonbonded_proxies.py @@ -98,10 +98,12 @@ def test_manager_and_clashes_functions(): clashes = pnps.get_clashes() # sorted by overlap (default) clashes.sort_clashes(by_value='overlap') - assert(list(clashes._clashes_dict.items())[11][0] == ((38, 39))) + val = list(clashes._clashes_dict.items())[11][0] + assert(val == ((19, 36))), val # sorted by symmetry clashes.sort_clashes(by_value='symmetry') - assert(list(clashes._clashes_dict.items())[11][0] == (27, 27)) + val=list(clashes._clashes_dict.items())[11][0] + assert(val == (38, 39)), val assert(clashes.iseq_is_clashing(iseq=27)) assert(clashes.iseq_is_clashing(iseq=44)) @@ -198,18 +200,15 @@ def test_show(): ''' clashes = get_clashes_result(raw_records=raw_records_7) results = clashes.get_results() - assert(results.n_clashes == 12) + assert(results.n_clashes == 14), results.n_clashes assert(results.n_clashes_sym == 2) assert(results.n_clashes_macro_mol == 3) - assert approx_equal(results.clashscore, 260.87, eps=1) + assert approx_equal(results.clashscore, 304.347, eps=1) assert approx_equal(results.clashscore_sym, 43.48, eps=1) assert approx_equal(results.clashscore_macro_mol, 78.95, eps=1) string_io = StringIO() clashes.show(log=string_io) lines = string_io.getvalue().split('\n') - assert(lines[8].startswith('--------')) - assert(lines[21].startswith('--------')) - def test_unknown_pair_type(): ''' @@ -337,8 +336,8 @@ def test_no_unit_cell(): ''' clashes = get_clashes_result(raw_records=raw_records_9) results = clashes.get_results() - assert(results.n_clashes == 15) - assert approx_equal(results.clashscore, 468, eps=2.0) + assert(results.n_clashes == 19), results.n_clashes + assert approx_equal(results.clashscore, 593, eps=2.0), results.clashscore raw_records_0 = """ diff --git a/mmtbx/dynamics/tst_sa.py b/mmtbx/dynamics/tst_sa.py index 1ea2db5872..f966100f78 100644 --- a/mmtbx/dynamics/tst_sa.py +++ b/mmtbx/dynamics/tst_sa.py @@ -221,14 +221,14 @@ def exercise_2(d_min = 1.5): if(shake): assert r < 0.07, r else: - assert r < 0.07, r + assert r < 0.13, r dist = flex.mean(flex.sqrt((pi.xrs.sites_cart() - fmodel.xray_structure.sites_cart()).dot())) print("Distance(refined, answer): %6.4f"%dist) if(shake): assert dist < 0.35, r else: - assert dist < 0.06, r + assert dist < 0.14, dist if(0): pi.ph.adopt_xray_structure(fmodel.xray_structure) pi.ph.write_pdb_file(file_name="refined.pdb", diff --git a/mmtbx/ligands/tst_ready_set_utils.py b/mmtbx/ligands/tst_ready_set_utils.py index 943deffbd2..d34a2c912b 100644 --- a/mmtbx/ligands/tst_ready_set_utils.py +++ b/mmtbx/ligands/tst_ready_set_utils.py @@ -180,7 +180,7 @@ def tst_adding_side_chain_acid_hydrogen_atoms(switch): hierarchy = pdb_inp.construct_hierarchy() add_side_chain_acid_hydrogens(hierarchy, configuration_index=i, element=element) hierarchy.write_pdb_file(fn.replace('.pdb', '_updated.pdb')) - cmd='phenix.pdb_interpretation %s flip_sym=0 write_geo=True' % fn.replace('.pdb', '_updated.pdb') + cmd='phenix.pdb_interpretation const_shrink_donor_acceptor=0.6 %s flip_sym=0 write_geo=True' % fn.replace('.pdb', '_updated.pdb') print(cmd) easy_run.go(cmd) assert_lines_in_file(file_name='%s.geo' % fn.replace('.pdb', '_updated.pdb'), @@ -203,7 +203,7 @@ def tst_adding_disulfur_hydrogen_atoms(switch): lines = f.read() assert lines.find('HG')==-1 else: - cmd='phenix.pdb_interpretation %s write_geo=True' % fn.replace('.pdb', '_updated.pdb') + cmd='phenix.pdb_interpretation const_shrink_donor_acceptor=0.6 %s write_geo=True' % fn.replace('.pdb', '_updated.pdb') print(cmd) easy_run.go(cmd) assert_lines_in_file(file_name='%s.geo' % fn.replace('.pdb', '_updated.pdb'), diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index 94f00dcffa..c67ee74260 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -478,7 +478,7 @@ def __init__(self, residue_name, atom_name, atom_element): .help = Weighting of nonbonded restraints term. By default, this will be \ set to 16 if explicit hydrogens are used (this was the default in \ earlier versions of Phenix), or 100 if hydrogens are missing. - const_shrink_donor_acceptor = 0.6 + const_shrink_donor_acceptor = 0 .type=float .optional=False .expert_level=3 diff --git a/mmtbx/regression/model/tst_model.py b/mmtbx/regression/model/tst_model.py index 1b3d5510e1..fe2c051682 100644 --- a/mmtbx/regression/model/tst_model.py +++ b/mmtbx/regression/model/tst_model.py @@ -1083,7 +1083,7 @@ def exercise_convert_atom(): # not push the for atom in mol.get_hierarchy().atoms(): xyz_max = max([ abs(n) for n in atom.xyz]) - assert (xyz_max < 2.6), 'max %s is larger than 2.6' % xyz_max + assert (xyz_max < 3.5), 'max %s is larger than 2.6' % xyz_max mol = mol.select(flex.size_t([1,2,3,4,5,6])) assert mol.have_anomalous_scatterer_groups() # assert mol.update_anomalous_groups(out=null_out()) # not needed because select() processed groups correctly diff --git a/mmtbx/regression/ncs/tst_minimization_ncs_constraints2.py b/mmtbx/regression/ncs/tst_minimization_ncs_constraints2.py index 4d27d81ef4..1131159346 100644 --- a/mmtbx/regression/ncs/tst_minimization_ncs_constraints2.py +++ b/mmtbx/regression/ncs/tst_minimization_ncs_constraints2.py @@ -3,12 +3,12 @@ from scitbx.array_family import flex from libtbx import group_args import iotbx.ncs as ncs -import mmtbx.utils import iotbx.pdb import time from iotbx.ncs import ncs_group_master_phil import iotbx.phil from six.moves import range +import mmtbx.model pdb_answer_0 = """\ CRYST1 18.415 14.419 12.493 90.00 90.00 90.00 P 1 @@ -230,14 +230,12 @@ def get_inputs(prefix, pdb_answer, pdb_poor, ncs_params_str, real_space, d_min): ph_poor.atoms().reset_i_seq() xrs_poor = pdb_inp_poor.xray_structure_simple() # - ppf = mmtbx.utils.process_pdb_file_srv().process_pdb_files( - raw_records=pdb_poor.splitlines())[0] - mmtbx.utils.assert_xray_structures_equal( - x1=ppf.xray_structure(show_summary = False), - x2=xrs_poor) - restraints_manager = mmtbx.restraints.manager( - geometry = ppf.geometry_restraints_manager(show_energies = False), - normalization = True) + pdb_inp = iotbx.pdb.input(source_info=None, lines=pdb_poor) + model = mmtbx.model.manager(model_input=pdb_inp) + p = model.get_default_pdb_interpretation_params() + p.pdb_interpretation.const_shrink_donor_acceptor=0.6 + model.process(pdb_interpretation_params=p, make_restraints=True) + restraints_manager = model.get_restraints_manager() restraints_manager.geometry.remove_c_beta_torsion_restraints_in_place() # phil_groups = ncs_group_master_phil.fetch( From 5d2bf340f4d88c55f432c2073059140fbc02141a Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 23 Jul 2024 17:11:17 -0700 Subject: [PATCH 588/748] Bugfix in ncs_search shortcut with a test --- .../ncs/tst_ncs_search_shortcut_1.py | 243 ++++++++++++++++++ iotbx/run_tests.py | 1 + mmtbx/ncs/ncs_search.py | 7 +- 3 files changed, 248 insertions(+), 3 deletions(-) create mode 100644 iotbx/regression/ncs/tst_ncs_search_shortcut_1.py diff --git a/iotbx/regression/ncs/tst_ncs_search_shortcut_1.py b/iotbx/regression/ncs/tst_ncs_search_shortcut_1.py new file mode 100644 index 0000000000..8f99458083 --- /dev/null +++ b/iotbx/regression/ncs/tst_ncs_search_shortcut_1.py @@ -0,0 +1,243 @@ +from __future__ import absolute_import, division, print_function +import iotbx.ncs +import iotbx.ncs as ncs +from iotbx import pdb + +pdb_str_1="""\ +CRYST1 34.917 22.246 44.017 90.00 90.00 90.00 P 1 +SCALE1 0.028639 0.000000 0.000000 0.00000 +SCALE2 0.000000 0.044952 0.000000 0.00000 +SCALE3 0.000000 0.000000 0.022718 0.00000 +ATOM 1 N ALA A 1 27.344 16.348 30.784 1.00 10.00 N +ATOM 2 CA ALA A 1 26.429 15.281 31.335 1.00 10.00 C +ATOM 3 C ALA A 1 26.610 14.025 30.603 1.00 10.00 C +ATOM 4 O ALA A 1 26.479 13.979 29.356 1.00 10.00 O +ATOM 5 CB ALA A 1 24.874 15.800 31.300 1.00 10.00 C +ATOM 1 N ALA A 2 26.812 12.925 31.345 1.00 10.00 N +ATOM 2 CA ALA A 2 27.084 11.577 30.797 1.00 10.00 C +ATOM 3 C ALA A 2 25.856 10.737 30.707 1.00 10.00 C +ATOM 4 O ALA A 2 25.741 9.860 29.891 1.00 10.00 O +ATOM 5 CB ALA A 2 28.151 10.950 31.721 1.00 10.00 C +ATOM 1 N ALA A 3 25.009 10.973 31.714 1.00 10.00 N +ATOM 2 CA ALA A 3 23.621 10.543 31.560 1.00 10.00 C +ATOM 3 C ALA A 3 23.023 11.008 30.214 1.00 10.00 C +ATOM 4 O ALA A 3 22.786 10.233 29.249 1.00 10.00 O +ATOM 5 CB ALA A 3 22.760 11.040 32.654 1.00 10.00 C +ATOM 1 N ALA A 4 22.798 12.304 30.175 1.00 10.00 N +ATOM 2 CA ALA A 4 22.329 13.084 28.981 1.00 10.00 C +ATOM 4 O ALA A 4 22.533 12.805 26.670 1.00 10.00 O +ATOM 5 CB ALA A 4 22.372 14.607 29.318 1.00 10.00 C +ATOM 1 N ALA A 5 24.448 12.622 27.823 1.00 10.00 N +ATOM 2 CA ALA A 5 25.228 12.407 26.573 1.00 10.00 C +ATOM 3 C ALA A 5 25.222 10.947 26.143 1.00 10.00 C +ATOM 4 O ALA A 5 25.386 10.664 24.983 1.00 10.00 O +ATOM 5 CB ALA A 5 26.634 12.906 26.746 1.00 10.00 C +ATOM 1 N ALA A 6 24.976 10.048 27.071 1.00 10.00 N +ATOM 2 CA ALA A 6 24.857 8.614 26.805 1.00 10.00 C +ATOM 3 C ALA A 6 23.537 8.349 26.054 1.00 10.00 C +ATOM 4 O ALA A 6 23.439 7.570 25.057 1.00 10.00 O +ATOM 5 CB ALA A 6 24.874 7.845 28.114 1.00 10.00 C +ATOM 1 N ALA A 7 22.542 9.039 26.580 1.00 10.00 N +ATOM 2 CA ALA A 7 21.228 8.903 25.942 1.00 10.00 C +ATOM 3 C ALA A 7 21.329 9.698 24.628 1.00 10.00 C +ATOM 4 O ALA A 7 20.707 9.383 23.632 1.00 10.00 O +ATOM 5 CB ALA A 7 20.146 9.465 26.862 1.00 10.00 C +ATOM 1 N ALA A 8 22.181 10.696 24.613 1.00 10.00 N +ATOM 2 CA ALA A 8 22.526 11.372 23.378 1.00 10.00 C +ATOM 3 C ALA A 8 23.351 10.555 22.448 1.00 10.00 C +ATOM 4 O ALA A 8 23.618 10.883 21.252 1.00 10.00 O +ATOM 5 CB ALA A 8 23.168 12.697 23.693 1.00 10.00 C +ATOM 1 N ALA A 9 23.864 9.423 22.961 1.00 10.00 N +ATOM 2 CA ALA A 9 24.785 8.541 22.264 1.00 10.00 C +ATOM 3 C ALA A 9 24.057 7.451 21.484 1.00 10.00 C +ATOM 4 O ALA A 9 24.127 7.381 20.257 1.00 10.00 O +ATOM 5 CB ALA A 9 25.815 7.975 23.249 1.00 10.00 C +ATOM 1 N ALA A 10 23.518 6.548 22.264 1.00 10.00 N +ATOM 2 CA ALA A 10 22.629 5.525 21.690 1.00 10.00 C +ATOM 3 C ALA A 10 21.549 6.308 21.009 1.00 10.00 C +ATOM 4 O ALA A 10 21.114 5.933 19.930 1.00 10.00 O +ATOM 5 CB ALA A 10 22.057 4.714 22.784 1.00 10.00 C +ATOM 1 N ALA A 11 21.120 7.452 21.541 1.00 10.00 N +ATOM 2 CA ALA A 11 20.186 8.260 20.874 1.00 10.00 C +ATOM 3 C ALA A 11 20.978 9.215 19.937 1.00 10.00 C +ATOM 4 O ALA A 11 20.386 10.177 19.507 1.00 10.00 O +ATOM 5 CB ALA A 11 19.295 9.031 21.867 1.00 10.00 C +ATOM 1 N ALA A 12 22.222 8.932 19.598 1.00 10.00 N +ATOM 2 CA ALA A 12 22.896 9.709 18.563 1.00 10.00 C +ATOM 3 C ALA A 12 22.924 8.925 17.308 1.00 10.00 C +ATOM 4 O ALA A 12 22.982 9.445 16.193 1.00 10.00 O +ATOM 5 CB ALA A 12 24.294 10.138 18.994 1.00 10.00 C +ATOM 1 N ALA A 13 22.951 7.633 17.508 1.00 10.00 N +ATOM 2 CA ALA A 13 22.709 6.629 16.554 1.00 10.00 C +ATOM 3 C ALA A 13 21.275 6.673 16.206 1.00 10.00 C +ATOM 4 O ALA A 13 20.870 6.521 15.092 1.00 10.00 O +ATOM 5 CB ALA A 13 23.077 5.254 17.025 1.00 10.00 C +ATOM 1 N ALA A 14 20.471 6.929 17.226 1.00 10.00 N +ATOM 2 CA ALA A 14 19.039 6.992 17.025 1.00 10.00 C +ATOM 3 C ALA A 14 18.676 8.380 16.528 1.00 10.00 C +ATOM 4 O ALA A 14 17.748 8.556 15.761 1.00 10.00 O +ATOM 5 CB ALA A 14 18.240 6.715 18.272 1.00 10.00 C +ATOM 1 N ALA A 15 19.381 9.390 17.055 1.00 10.00 N +ATOM 2 CA ALA A 15 19.204 10.743 16.669 1.00 10.00 C +ATOM 3 C ALA A 15 19.407 10.807 15.174 1.00 10.00 C +ATOM 4 O ALA A 15 18.402 10.987 14.424 1.00 10.00 O +ATOM 5 CB ALA A 15 20.190 11.665 17.493 1.00 10.00 C +ATOM 1 N ALA A 16 20.702 10.653 14.831 1.00 10.00 N +ATOM 2 CA ALA A 16 21.206 10.546 13.480 1.00 10.00 C +ATOM 3 C ALA A 16 20.484 9.612 12.585 1.00 10.00 C +ATOM 4 O ALA A 16 20.380 9.918 11.386 1.00 10.00 O +ATOM 5 CB ALA A 16 22.631 10.174 13.475 1.00 10.00 C +ATOM 1 N ALA A 17 20.064 8.475 13.175 1.00 10.00 N +ATOM 2 CA ALA A 17 19.355 7.473 12.426 1.00 10.00 C +ATOM 3 C ALA A 17 17.924 7.807 12.064 1.00 10.00 C +ATOM 4 O ALA A 17 17.535 7.721 10.871 1.00 10.00 O +ATOM 5 CB ALA A 17 19.359 6.123 13.216 1.00 10.00 C +ATOM 1 N ALA A 18 17.152 8.115 13.031 1.00 10.00 N +ATOM 2 CA ALA A 18 15.835 8.594 12.861 1.00 10.00 C +ATOM 3 C ALA A 18 15.811 9.835 11.861 1.00 10.00 C +ATOM 4 O ALA A 18 15.020 9.889 10.868 1.00 10.00 O +ATOM 5 CB ALA A 18 15.272 8.918 14.234 1.00 10.00 C +ATOM 1 N ALA A 19 16.661 10.845 12.100 1.00 10.00 N +ATOM 2 CA ALA A 19 16.435 12.061 11.275 1.00 10.00 C +ATOM 3 C ALA A 19 17.004 11.815 9.833 1.00 10.00 C +ATOM 4 O ALA A 19 16.334 12.117 8.857 1.00 10.00 O +ATOM 5 CB ALA A 19 17.059 13.242 11.866 1.00 10.00 C +ATOM 1 N ALA A 20 18.191 11.200 9.841 1.00 10.00 N +ATOM 2 CA ALA A 20 19.091 11.247 8.697 1.00 10.00 C +ATOM 3 C ALA A 20 19.549 9.835 8.231 1.00 10.00 C +ATOM 4 O ALA A 20 20.670 9.692 7.663 1.00 10.00 O +ATOM 5 CB ALA A 20 20.326 12.105 9.035 1.00 10.00 C +ATOM 1 N ALA A 21 18.654 8.850 8.523 1.00 10.00 N +ATOM 2 CA ALA A 21 18.827 7.437 8.168 1.00 10.00 C +ATOM 3 C ALA A 21 17.565 6.607 8.282 1.00 10.00 C +ATOM 4 O ALA A 21 16.485 6.992 7.820 1.00 10.00 O +ATOM 5 CB ALA A 21 19.888 6.838 8.983 1.00 10.00 C +TER +ATOM 1 N ALA B 1 16.348 17.420 35.897 1.00 50.00 N +ATOM 2 CA ALA B 1 16.783 16.083 36.351 1.00 50.00 C +ATOM 3 C ALA B 1 16.794 15.172 35.139 1.00 50.00 C +ATOM 4 O ALA B 1 16.167 15.477 34.133 1.00 50.00 O +ATOM 5 CB ALA B 1 15.785 15.534 37.468 1.00 50.00 C +ATOM 1 N ALA B 2 17.491 14.058 35.255 1.00 50.00 N +ATOM 2 CA ALA B 2 17.790 13.267 34.127 1.00 50.00 C +ATOM 3 C ALA B 2 16.716 12.232 33.688 1.00 50.00 C +ATOM 4 O ALA B 2 16.676 11.869 32.543 1.00 50.00 O +ATOM 5 CB ALA B 2 19.125 12.656 34.415 1.00 50.00 C +ATOM 1 N ALA B 3 15.904 11.687 34.605 1.00 50.00 N +ATOM 2 CA ALA B 3 14.798 10.901 34.173 1.00 50.00 C +ATOM 3 C ALA B 3 13.740 11.723 33.536 1.00 50.00 C +ATOM 4 O ALA B 3 13.398 11.501 32.356 1.00 50.00 O +ATOM 5 CB ALA B 3 14.148 10.176 35.403 1.00 50.00 C +ATOM 1 N ALA B 4 13.239 12.708 34.247 1.00 50.00 N +ATOM 2 CA ALA B 4 12.158 13.487 33.709 1.00 50.00 C +ATOM 3 C ALA B 4 12.674 14.248 32.495 1.00 50.00 C +ATOM 4 O ALA B 4 11.935 14.376 31.526 1.00 50.00 O +ATOM 5 CB ALA B 4 11.553 14.432 34.712 1.00 50.00 C +ATOM 1 N ALA B 5 13.947 14.627 32.479 1.00 50.00 N +ATOM 2 CA ALA B 5 14.416 15.490 31.405 1.00 50.00 C +ATOM 3 C ALA B 5 14.960 14.730 30.186 1.00 50.00 C +ATOM 4 O ALA B 5 14.575 14.940 29.054 1.00 50.00 O +ATOM 5 CB ALA B 5 15.464 16.431 31.928 1.00 50.00 C +ATOM 1 N ALA B 6 15.867 13.827 30.546 1.00 50.00 N +ATOM 2 CA ALA B 6 16.575 12.918 29.615 1.00 50.00 C +ATOM 3 C ALA B 6 15.465 12.002 28.975 1.00 50.00 C +ATOM 4 O ALA B 6 15.450 11.709 27.742 1.00 50.00 O +ATOM 5 CB ALA B 6 17.632 12.157 30.362 1.00 50.00 C +ATOM 1 N ALA B 7 14.542 11.597 29.783 1.00 50.00 N +ATOM 2 CA ALA B 7 13.529 10.701 29.277 1.00 50.00 C +ATOM 3 C ALA B 7 12.175 11.364 28.835 1.00 50.00 C +ATOM 4 O ALA B 7 11.466 10.770 27.969 1.00 50.00 O +ATOM 5 CB ALA B 7 13.161 9.644 30.376 1.00 50.00 C +ATOM 1 N ALA B 8 11.753 12.455 29.452 1.00 50.00 N +ATOM 2 CA ALA B 8 10.536 13.193 28.972 1.00 50.00 C +ATOM 3 C ALA B 8 10.919 13.923 27.670 1.00 50.00 C +ATOM 4 O ALA B 8 10.171 14.036 26.729 1.00 50.00 O +ATOM 5 CB ALA B 8 10.032 14.139 30.014 1.00 50.00 C +ATOM 1 N ALA B 9 12.185 14.247 27.579 1.00 50.00 N +ATOM 2 CA ALA B 9 12.754 14.849 26.385 1.00 50.00 C +ATOM 3 C ALA B 9 12.892 13.859 25.320 1.00 50.00 C +ATOM 4 O ALA B 9 12.234 13.980 24.290 1.00 50.00 O +ATOM 5 CB ALA B 9 14.108 15.448 26.695 1.00 50.00 C +ATOM 1 N ALA B 10 13.655 12.794 25.566 1.00 50.00 N +ATOM 2 CA ALA B 10 13.831 11.803 24.529 1.00 50.00 C +ATOM 3 C ALA B 10 12.551 10.987 24.319 1.00 50.00 C +ATOM 4 O ALA B 10 12.514 10.237 23.390 1.00 50.00 O +ATOM 5 CB ALA B 10 15.024 10.750 24.992 1.00 50.00 C +ATOM 1 N ALA B 11 11.558 11.184 25.126 1.00 50.00 N +ATOM 2 CA ALA B 11 10.334 10.457 24.931 1.00 50.00 C +ATOM 3 C ALA B 11 9.326 11.284 24.168 1.00 50.00 C +ATOM 4 O ALA B 11 8.566 10.707 23.476 1.00 50.00 O +ATOM 5 CB ALA B 11 9.644 10.042 26.251 1.00 50.00 C +ATOM 1 N ALA B 12 9.277 12.611 24.334 1.00 50.00 N +ATOM 2 CA ALA B 12 8.354 13.375 23.644 1.00 50.00 C +ATOM 3 C ALA B 12 9.019 13.546 22.264 1.00 50.00 C +ATOM 4 O ALA B 12 8.400 13.891 21.317 1.00 50.00 O +ATOM 5 CB ALA B 12 8.056 14.678 24.287 1.00 50.00 C +ATOM 1 N ALA B 13 10.333 13.339 22.264 1.00 50.00 N +ATOM 2 CA ALA B 13 11.239 13.471 21.127 1.00 50.00 C +ATOM 3 C ALA B 13 11.096 12.161 20.325 1.00 50.00 C +ATOM 4 O ALA B 13 11.145 12.175 19.123 1.00 50.00 O +ATOM 5 CB ALA B 13 12.584 13.665 21.596 1.00 50.00 C +ATOM 1 N ALA B 14 11.051 11.078 21.086 1.00 50.00 N +ATOM 2 CA ALA B 14 10.953 9.771 20.454 1.00 50.00 C +ATOM 3 C ALA B 14 9.550 9.463 20.117 1.00 50.00 C +ATOM 4 O ALA B 14 9.233 8.571 19.367 1.00 50.00 O +ATOM 1 N ALA B 15 8.669 10.215 20.743 1.00 50.00 N +ATOM 2 CA ALA B 15 7.282 10.010 20.486 1.00 50.00 C +ATOM 3 C ALA B 15 6.825 10.982 19.376 1.00 50.00 C +ATOM 4 O ALA B 15 5.855 10.783 18.619 1.00 50.00 O +ATOM 5 CB ALA B 15 6.367 10.306 21.797 1.00 50.00 C +ATOM 1 N ALA B 16 7.511 12.143 19.430 1.00 50.00 N +ATOM 2 CA ALA B 16 7.233 13.302 18.551 1.00 50.00 C +ATOM 3 C ALA B 16 7.912 13.082 17.205 1.00 50.00 C +ATOM 4 O ALA B 16 7.492 13.573 16.111 1.00 50.00 O +ATOM 5 CB ALA B 16 7.762 14.594 19.165 1.00 50.00 C +ATOM 1 N ALA B 17 9.071 12.427 17.269 1.00 50.00 N +ATOM 2 CA ALA B 17 9.595 11.771 16.091 1.00 50.00 C +ATOM 3 C ALA B 17 8.883 10.519 15.763 1.00 50.00 C +ATOM 4 O ALA B 17 8.890 10.193 14.597 1.00 50.00 O +ATOM 5 CB ALA B 17 11.046 11.518 16.265 1.00 50.00 C +ATOM 1 N ALA B 18 8.315 9.809 16.722 1.00 50.00 N +ATOM 2 CA ALA B 18 7.515 8.647 16.448 1.00 50.00 C +ATOM 3 C ALA B 18 6.253 9.063 15.707 1.00 50.00 C +ATOM 4 O ALA B 18 5.559 8.173 15.198 1.00 50.00 O +ATOM 5 CB ALA B 18 7.129 7.915 17.695 1.00 50.00 C +ATOM 1 N ALA B 19 5.866 10.332 15.772 1.00 50.00 N +ATOM 2 CA ALA B 19 4.686 10.808 15.089 1.00 50.00 C +ATOM 3 C ALA B 19 5.011 11.578 13.803 1.00 50.00 C +ATOM 4 O ALA B 19 4.291 11.514 12.837 1.00 50.00 O +ATOM 5 CB ALA B 19 3.854 11.710 15.960 1.00 50.00 C +ATOM 1 N ALA B 20 6.176 12.195 13.822 1.00 50.00 N +ATOM 2 CA ALA B 20 6.614 13.121 12.789 1.00 50.00 C +ATOM 3 C ALA B 20 7.933 12.759 12.098 1.00 50.00 C +ATOM 4 O ALA B 20 8.620 13.613 11.585 1.00 50.00 O +ATOM 5 CB ALA B 20 6.823 14.498 13.449 1.00 50.00 C +ATOM 1 N ALA B 21 8.284 11.511 12.050 1.00 50.00 N +ATOM 2 CA ALA B 21 9.513 11.117 11.323 1.00 50.00 C +ATOM 3 C ALA B 21 9.313 9.628 11.029 1.00 50.00 C +ATOM 4 O ALA B 21 9.731 8.751 11.795 1.00 50.00 O +ATOM 5 CB ALA B 21 10.799 11.332 12.178 1.00 50.00 C +TER +""" + +def exercise_00(): + """ Verify that shortcut1 is not failing""" + pdb_inp = iotbx.pdb.input(lines=pdb_str_1,source_info=None) + hierarchy = pdb_inp.construct_hierarchy() + ncs_params = iotbx.ncs.input.get_default_params() + ncs_params.ncs_search.try_shortcuts = True + ncs_params.ncs_search.exclude_selection="water" + + ncs_inp = iotbx.ncs.input( + hierarchy = hierarchy, + params = ncs_params.ncs_search) + ncs_groups = ncs_inp.get_ncs_restraints_group_list() + ncs_inp.show(format='phil') + assert len(ncs_groups) == 1 + assert len(ncs_groups[0].copies) == 1, len(ncs_groups[0].copies) + assert ncs_groups[0].master_iselection.size() == 103, ncs_groups[0].master_iselection.size() # all chain + assert ncs_groups[0].copies[0].iselection.size() == 103, ncs_groups[0].copies[0].iselection.size() # all chain + print("OK") + +if(__name__=='__main__'): + exercise_00() diff --git a/iotbx/run_tests.py b/iotbx/run_tests.py index 95747bf302..e477512a51 100644 --- a/iotbx/run_tests.py +++ b/iotbx/run_tests.py @@ -130,6 +130,7 @@ "$D/regression/ncs/tst_mmcif_biomt_reduction_output.py", "$D/regression/ncs/tst_ncs_search_ligs.py", "$D/regression/ncs/tst_ncs_search_broken_chain.py", + "$D/regression/ncs/tst_ncs_search_shortcut_1.py", "$D/regression/ncs/tst_ncs_groups_preprocessing.py", "$D/regression/ncs/tst_ncs_input.py", "$D/regression/ncs/tst_ncs_user_selections.py", diff --git a/mmtbx/ncs/ncs_search.py b/mmtbx/ncs/ncs_search.py index 79e91dbfff..bfd23167d7 100644 --- a/mmtbx/ncs/ncs_search.py +++ b/mmtbx/ncs/ncs_search.py @@ -90,9 +90,10 @@ def shortcut_1( master_xyz = get_chain_xyz(hierarchy, master_chain_id) for copy_chain_id in chains_list[1:]: # these are copies - if chains_info[master_chain_id].atom_names != chains_info[copy_chain_id].atom_names: - print("No shortcut, atom names are not identical", file=log) - return empty_result + for a, b in zip(chains_info[master_chain_id].atom_names, chains_info[copy_chain_id].atom_names): + if list(a)!=list(b): + print("No shortcut, atom names are not identical", file=log) + return empty_result copy_xyz = get_chain_xyz(hierarchy, copy_chain_id) lsq_fit_obj = superpose.least_squares_fit( reference_sites = copy_xyz, From 813aa5612555a2ef510abb3ad6d4632b9971989c Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 23 Jul 2024 17:12:57 -0700 Subject: [PATCH 589/748] pdb interpretation with NCS should now work if ON by default for all tests. Not enabling just yet. --- cctbx/geometry_restraints/__init__.py | 232 +++++---- mmtbx/monomer_library/pdb_interpretation.py | 78 +-- .../pdb_interpretation/tst_using_ncs_1.py | 184 +++++++ .../pdb_interpretation/tst_using_ncs_2.py | 478 ++++++++++++++++++ mmtbx/run_tests.py | 2 + 5 files changed, 853 insertions(+), 121 deletions(-) create mode 100644 mmtbx/regression/pdb_interpretation/tst_using_ncs_1.py create mode 100644 mmtbx/regression/pdb_interpretation/tst_using_ncs_2.py diff --git a/cctbx/geometry_restraints/__init__.py b/cctbx/geometry_restraints/__init__.py index 180e205f87..b58f72a25f 100644 --- a/cctbx/geometry_restraints/__init__.py +++ b/cctbx/geometry_restraints/__init__.py @@ -121,28 +121,42 @@ def __init__(self, n_seq, strict_conflict_handling): strict_conflict_handling=strict_conflict_handling) self.n_seq = n_seq - def expand_with_ncs(self, nrgl): + def expand_with_ncs(self, nrgl, masters_and_rest_iselection): # print("original proxies:", [p.i_seqs for p in self.proxies]) - # n_proxies = len(self.proxies) + # nrgl._show(brief=False) additional_proxies = [] - for i, p in enumerate(self.proxies): - all_new_iseqs = nrgl.get_copy_iseqs(p.i_seqs) + for i in range(len(self.proxies)): + p = self.proxies[i] + new_current_proxy_iseqs = (masters_and_rest_iselection[p.i_seqs[0]], + masters_and_rest_iselection[p.i_seqs[1]]) + new_master_p = bond_simple_proxy( + i_seqs = new_current_proxy_iseqs, + distance_ideal=p.distance_ideal, + weight=p.weight, + slack=p.slack, + limit=p.limit, + top_out=p.top_out, + origin_id=p.origin_id).sort_i_seqs() + self.proxies[i] = new_master_p + all_new_iseqs = nrgl.get_copy_iseqs(new_current_proxy_iseqs) + # print(' i, p.i_seqs', i, p.i_seqs) # print(' all_new_iseqs', all_new_iseqs) - for new_iseqs in all_new_iseqs: - new_proxy = bond_simple_proxy( - i_seqs=new_iseqs, - distance_ideal=p.distance_ideal, - weight=p.weight, - slack=p.slack, - limit=p.limit, - top_out=p.top_out, - origin_id=p.origin_id).sort_i_seqs() - # marking table - self.table[new_iseqs[0]][new_iseqs[1]] = self.proxies.size() - # ~ self._append_proxy - additional_proxies.append(new_proxy) - self.source_labels.append(self.source_labels[i]) - self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) + if all_new_iseqs is not None: + for new_iseqs in all_new_iseqs: + new_proxy = bond_simple_proxy( + i_seqs=new_iseqs, + distance_ideal=p.distance_ideal, + weight=p.weight, + slack=p.slack, + limit=p.limit, + top_out=p.top_out, + origin_id=p.origin_id).sort_i_seqs() + # marking table + self.table[new_iseqs[0]][new_iseqs[1]] = self.proxies.size() + # ~ self._append_proxy + additional_proxies.append(new_proxy) + self.source_labels.append(self.source_labels[i]) + self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) self.proxies.extend(additional_proxies) @@ -201,23 +215,30 @@ def __init__(self, strict_conflict_handling): proxies=shared_angle_proxy(), strict_conflict_handling=strict_conflict_handling) - def expand_with_ncs(self, nrgl): + def expand_with_ncs(self, nrgl, masters_and_rest_iselection): additional_proxies = [] # n_proxies = len(self.proxies) - for i, p in enumerate(self.proxies): - all_new_iseqs = nrgl.get_copy_iseqs(p.i_seqs) - for new_iseqs in all_new_iseqs: - new_proxy = angle_proxy( - i_seqs=new_iseqs, + for i in range(len(self.proxies)): + p = self.proxies[i] + new_current_proxy_iseqs = [ masters_and_rest_iselection[iseq] for iseq in p.i_seqs] + new_master_p = angle_proxy( + i_seqs=new_current_proxy_iseqs, proxy=p).sort_i_seqs() - # marking table - tab_i_seq_1 = self.table.setdefault(new_proxy.i_seqs[1], {}) - tab_i_seq_1[(new_proxy.i_seqs[0], new_proxy.i_seqs[2])] = self.proxies.size() - # ~ self._append_proxy - additional_proxies.append(new_proxy) - # self.proxies.append(new_proxy) - self.source_labels.append(self.source_labels[i]) - self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) + self.proxies[i] = new_master_p + all_new_iseqs = nrgl.get_copy_iseqs(new_current_proxy_iseqs) + if all_new_iseqs is not None: + for new_iseqs in all_new_iseqs: + new_proxy = angle_proxy( + i_seqs=new_iseqs, + proxy=p).sort_i_seqs() + # marking table + tab_i_seq_1 = self.table.setdefault(new_proxy.i_seqs[1], {}) + tab_i_seq_1[(new_proxy.i_seqs[0], new_proxy.i_seqs[2])] = self.proxies.size() + # ~ self._append_proxy + additional_proxies.append(new_proxy) + # self.proxies.append(new_proxy) + self.source_labels.append(self.source_labels[i]) + self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) self.proxies.extend(additional_proxies) def add_if_not_duplicated(self, proxy, tolerance=1.e-6): @@ -281,22 +302,29 @@ def __init__(self, strict_conflict_handling): proxies=shared_dihedral_proxy(), strict_conflict_handling=strict_conflict_handling) - def expand_with_ncs(self, nrgl): + def expand_with_ncs(self, nrgl, masters_and_rest_iselection): additional_proxies = [] - for i, p in enumerate(self.proxies): - all_new_iseqs = nrgl.get_copy_iseqs(p.i_seqs) - for new_iseqs in all_new_iseqs: - new_proxy = dihedral_proxy( - i_seqs=new_iseqs, + for i in range(len(self.proxies)): + p = self.proxies[i] + new_current_proxy_iseqs = [ masters_and_rest_iselection[iseq] for iseq in p.i_seqs] + new_master_p = dihedral_proxy( + i_seqs=new_current_proxy_iseqs, proxy=p).sort_i_seqs() - # marking table - tab_i_seq_0 = self.table.setdefault(new_proxy.i_seqs[0], {}) - tab_i_seq_0[(new_proxy.i_seqs[1], new_proxy.i_seqs[2], new_proxy.i_seqs[3])] = self.proxies.size() - # ~ self._append_proxy - additional_proxies.append(new_proxy) - # self.proxies.append(new_proxy) - self.source_labels.append(self.source_labels[i]) - self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) + self.proxies[i] = new_master_p + all_new_iseqs = nrgl.get_copy_iseqs(new_current_proxy_iseqs) + if all_new_iseqs is not None: + for new_iseqs in all_new_iseqs: + new_proxy = dihedral_proxy( + i_seqs=new_iseqs, + proxy=p).sort_i_seqs() + # marking table + tab_i_seq_0 = self.table.setdefault(new_proxy.i_seqs[0], {}) + tab_i_seq_0[(new_proxy.i_seqs[1], new_proxy.i_seqs[2], new_proxy.i_seqs[3])] = self.proxies.size() + # ~ self._append_proxy + additional_proxies.append(new_proxy) + # self.proxies.append(new_proxy) + self.source_labels.append(self.source_labels[i]) + self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) self.proxies.extend(additional_proxies) def add_if_not_duplicated(self, proxy, tolerance=1.e-6): @@ -367,22 +395,29 @@ def __init__(self, strict_conflict_handling): proxies=shared_chirality_proxy(), strict_conflict_handling=strict_conflict_handling) - def expand_with_ncs(self, nrgl): + def expand_with_ncs(self, nrgl, masters_and_rest_iselection): additional_proxies = [] - for i, p in enumerate(self.proxies): - all_new_iseqs = nrgl.get_copy_iseqs(p.i_seqs) - for new_iseqs in all_new_iseqs: - new_proxy = chirality_proxy( - i_seqs=new_iseqs, + for i in range(len(self.proxies)): + p = self.proxies[i] + new_current_proxy_iseqs = [ masters_and_rest_iselection[iseq] for iseq in p.i_seqs] + new_master_p = chirality_proxy( + i_seqs=new_current_proxy_iseqs, proxy=p).sort_i_seqs() - # marking table - tab_i_seq_0 = self.table.setdefault(new_proxy.i_seqs[0], {}) - tab_i_seq_0[(new_proxy.i_seqs[1], new_proxy.i_seqs[2], new_proxy.i_seqs[3])] = self.proxies.size() - # ~ self._append_proxy - additional_proxies.append(new_proxy) - # self.proxies.append(new_proxy) - self.source_labels.append(self.source_labels[i]) - self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) + self.proxies[i] = new_master_p + all_new_iseqs = nrgl.get_copy_iseqs(new_current_proxy_iseqs) + if all_new_iseqs is not None: + for new_iseqs in all_new_iseqs: + new_proxy = chirality_proxy( + i_seqs=new_iseqs, + proxy=p).sort_i_seqs() + # marking table + tab_i_seq_0 = self.table.setdefault(new_proxy.i_seqs[0], {}) + tab_i_seq_0[(new_proxy.i_seqs[1], new_proxy.i_seqs[2], new_proxy.i_seqs[3])] = self.proxies.size() + # ~ self._append_proxy + additional_proxies.append(new_proxy) + # self.proxies.append(new_proxy) + self.source_labels.append(self.source_labels[i]) + self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) self.proxies.extend(additional_proxies) def add_if_not_duplicated(self, proxy, tolerance=1.e-6): @@ -440,22 +475,29 @@ def __init__(self, strict_conflict_handling): proxies=shared_planarity_proxy(), strict_conflict_handling=strict_conflict_handling) - def expand_with_ncs(self, nrgl): + def expand_with_ncs(self, nrgl, masters_and_rest_iselection): additional_proxies = [] - for i, p in enumerate(self.proxies): - all_new_iseqs = nrgl.get_copy_iseqs(p.i_seqs) - for new_iseqs in all_new_iseqs: - new_proxy = planarity_proxy( - i_seqs=new_iseqs, + for i in range(len(self.proxies)): + p = self.proxies[i] + new_current_proxy_iseqs = [ masters_and_rest_iselection[iseq] for iseq in p.i_seqs] + new_master_p = planarity_proxy( + i_seqs=new_current_proxy_iseqs, proxy=p).sort_i_seqs() - # marking table - tab_i_seq_0 = self.table.setdefault(new_proxy.i_seqs[0], {}) - tab_i_seq_0[(new_proxy.i_seqs[1:])] = self.proxies.size() - # ~ self._append_proxy - additional_proxies.append(new_proxy) - # self.proxies.append(new_proxy) - self.source_labels.append(self.source_labels[i]) - self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) + self.proxies[i] = new_master_p + all_new_iseqs = nrgl.get_copy_iseqs(new_current_proxy_iseqs) + if all_new_iseqs is not None: + for new_iseqs in all_new_iseqs: + new_proxy = planarity_proxy( + i_seqs=new_iseqs, + proxy=p).sort_i_seqs() + # marking table + tab_i_seq_0 = self.table.setdefault(new_proxy.i_seqs[0], {}) + tab_i_seq_0[(new_proxy.i_seqs[1:])] = self.proxies.size() + # ~ self._append_proxy + additional_proxies.append(new_proxy) + # self.proxies.append(new_proxy) + self.source_labels.append(self.source_labels[i]) + self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) self.proxies.extend(additional_proxies) def add_if_not_duplicated(self, proxy, tolerance=1.e-6): @@ -505,23 +547,33 @@ def __init__(self, strict_conflict_handling): proxies=shared_parallelity_proxy(), strict_conflict_handling=strict_conflict_handling) - def expand_with_ncs(self, nrgl): + def expand_with_ncs(self, nrgl, masters_and_rest_iselection): additional_proxies = [] - for i, p in enumerate(self.proxies): - all_new_iseqs = nrgl.get_copy_iseqs(p.i_seqs) - all_new_jseqs = nrgl.get_copy_iseqs(p.i_seqs) - for new_iseqs, new_jseqs in zip(all_new_iseqs, all_new_jseqs): - new_proxy = parallelity_proxy( - i_seqs=new_iseqs, - j_seqs=new_jseqs, + for i in range(len(self.proxies)): + p = self.proxies[i] + new_current_proxy_iseqs = [ masters_and_rest_iselection[iseq] for iseq in p.i_seqs] + new_current_proxy_jseqs = [ masters_and_rest_iselection[jseq] for jseq in p.j_seqs] + new_master_p = parallelity_proxy( + i_seqs=new_current_proxy_iseqs, + j_seqs=new_current_proxy_jseqs, proxy=p).sort_i_seqs() - # marking table - self.table[(tuple(new_proxy.i_seqs), tuple(new_proxy.j_seqs))] = self.proxies.size() - # ~ self._append_proxy - additional_proxies.append(new_proxy) - # self.proxies.append(new_proxy) - self.source_labels.append(self.source_labels[i]) - self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) + self.proxies[i] = new_master_p + # all_new_iseqs = nrgl.get_copy_iseqs(new_current_proxy_iseqs) + all_new_iseqs = nrgl.get_copy_iseqs(new_current_proxy_iseqs) + all_new_jseqs = nrgl.get_copy_iseqs(new_current_proxy_jseqs) + if all_new_iseqs is not None and all_new_jseqs is not None: + for new_iseqs, new_jseqs in zip(all_new_iseqs, all_new_jseqs): + new_proxy = parallelity_proxy( + i_seqs=new_iseqs, + j_seqs=new_jseqs, + proxy=p).sort_i_seqs() + # marking table + self.table[(tuple(new_proxy.i_seqs), tuple(new_proxy.j_seqs))] = self.proxies.size() + # ~ self._append_proxy + additional_proxies.append(new_proxy) + # self.proxies.append(new_proxy) + self.source_labels.append(self.source_labels[i]) + self.source_n_expected_atoms.append(self.source_n_expected_atoms[i]) self.proxies.extend(additional_proxies) def add_if_not_duplicated(self, proxy, tolerance=1.e-6): diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index c67ee74260..bc078ad186 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -18,6 +18,7 @@ from cctbx import sgtbx from cctbx.array_family import flex from scitbx.python_utils import dicts +from scitbx_array_family_flex_ext import reindexing_array from libtbx.str_utils import show_string from libtbx.utils import flat_list, Sorry, user_plus_sys_time, plural_s, null_out from libtbx.utils import format_exception, greek_time @@ -901,31 +902,42 @@ def __init__(self, type_label, symbols, strict_conflict_handling): self.charges = flex.int(symbols.size(), 0) def _show(self): + print ('==== show symbol registry base:') print ('self.type_label', self.type_label) print ('size: ', self.symbols.size()) - print (list(self.symbols)) - print (self.strict_conflict_handling) - print (self.n_resolved_conflicts) - print (list(self.source_labels)) - print (list(self.source_n_expected_atoms)) - print (list(self.charges)) - - def expand_with_ncs(self, nrgl, n_atoms): - new_symbols = flex.std_string(n_atoms) - new_source_labels = flex.std_string(n_atoms) + print ('symbols: ', list(self.symbols)) + print ('strict_conflict_handling:', self.strict_conflict_handling) + print ('n_resolved_conflicts:', self.n_resolved_conflicts) + print ('source_labels:', list(self.source_labels)) + print ('source_n_expected_atoms:', list(self.source_n_expected_atoms)) + print ('charges', list(self.charges)) + print ('==== end of symbol registry base:') + + def expand_with_ncs(self, nrgl, n_atoms_full): + new_symbols = flex.std_string(n_atoms_full) + new_source_labels = flex.std_string(new_symbols.size()) new_source_n_expected_atoms = flex.int(new_symbols.size(), -1) new_charges = flex.int(new_symbols.size(), 0) + masters_and_rest_bool_selection = ~flex.bool(n_atoms_full, nrgl.get_all_copies_selection()) + masters_and_rest_iselection = masters_and_rest_bool_selection.iselection() + assert len(masters_and_rest_iselection) == len(self.symbols) + ra = reindexing_array(n_atoms_full, masters_and_rest_iselection.as_int()) + new_symbols.set_selected(masters_and_rest_iselection, self.symbols) + new_source_labels.set_selected(masters_and_rest_iselection, self.source_labels) + new_source_n_expected_atoms.set_selected(masters_and_rest_iselection, self.source_n_expected_atoms) + new_charges.set_selected(masters_and_rest_iselection, self.charges) for ncs_group in nrgl: - # print("len(ncs_group.master_iselection), len(self.symbols), n_atoms", len(ncs_group.master_iselection), len(self.symbols), n_atoms) - new_symbols.set_selected(ncs_group.master_iselection, self.symbols.select(ncs_group.master_iselection)) - new_source_labels.set_selected(ncs_group.master_iselection, self.source_labels.select(ncs_group.master_iselection)) - new_source_n_expected_atoms.set_selected(ncs_group.master_iselection, self.source_n_expected_atoms.select(ncs_group.master_iselection)) - new_charges.set_selected(ncs_group.master_iselection, self.charges.select(ncs_group.master_iselection)) + # print("list(ncs_group.master_iselection)", list(ncs_group.master_iselection)) + # here we need to translate master_iselection iseqs from applicable to whole molecule to this new + # masters_and_rest arrays.... + translated_master_iselection = flex.size_t([ra[i] for i in ncs_group.master_iselection]) for c in ncs_group.copies: - new_symbols.set_selected(c.iselection, self.symbols.select(ncs_group.master_iselection)) - new_source_labels.set_selected(c.iselection, self.source_labels.select(ncs_group.master_iselection)) - new_source_n_expected_atoms.set_selected(c.iselection, self.source_n_expected_atoms.select(ncs_group.master_iselection)) - new_charges.set_selected(c.iselection, self.charges.select(ncs_group.master_iselection)) + # print ("len c.iselection: ", len(c.iselection), len(ncs_group.master_iselection)) + # print ("c.iselection: ", list(c.iselection), list(ncs_group.master_iselection), list(translated_master_iselection)) + new_symbols.set_selected(c.iselection, self.symbols.select(translated_master_iselection)) + new_source_labels.set_selected(c.iselection, self.source_labels.select(translated_master_iselection)) + new_source_n_expected_atoms.set_selected(c.iselection, self.source_n_expected_atoms.select(translated_master_iselection)) + new_charges.set_selected(c.iselection, self.charges.select(translated_master_iselection)) self.symbols = new_symbols self.source_labels = new_source_labels self.source_n_expected_atoms = new_source_n_expected_atoms @@ -3089,13 +3101,15 @@ def __init__(self, n_seq, strict_conflict_handling): self.parallelity = geometry_restraints.parallelity_proxy_registry( strict_conflict_handling=strict_conflict_handling) - def expand_with_ncs(self, nrgl): - self.bond_simple.expand_with_ncs(nrgl) - self.angle.expand_with_ncs(nrgl) - self.dihedral.expand_with_ncs(nrgl) - self.chirality.expand_with_ncs(nrgl) - self.planarity.expand_with_ncs(nrgl) - self.parallelity.expand_with_ncs(nrgl) + def expand_with_ncs(self, nrgl, n_atoms_full): + masters_and_rest_bool_selection = ~flex.bool(n_atoms_full, nrgl.get_all_copies_selection()) + masters_and_rest_iselection = masters_and_rest_bool_selection.iselection() + self.bond_simple.expand_with_ncs(nrgl, masters_and_rest_iselection) + self.angle.expand_with_ncs(nrgl, masters_and_rest_iselection) + self.dihedral.expand_with_ncs(nrgl, masters_and_rest_iselection) + self.chirality.expand_with_ncs(nrgl, masters_and_rest_iselection) + self.planarity.expand_with_ncs(nrgl, masters_and_rest_iselection) + self.parallelity.expand_with_ncs(nrgl, masters_and_rest_iselection) def initialize_tables(self): @@ -3594,11 +3608,12 @@ def set_donor_acceptor_excl_groups(): # search for NCS ncs_params = iotbx.ncs.input.get_default_params() ncs_params.ncs_search.try_shortcuts = True + ncs_params.ncs_search.exclude_selection="water" ncs_obj = iotbx.ncs.input( ncs_phil_groups = None, hierarchy = self.pdb_hierarchy.deep_copy(), params = ncs_params.ncs_search, - log = None) + log = null_out()) nrgl = ncs_obj.get_ncs_restraints_group_list() f_nrgl = nrgl.filter_ncs_restraints_group_list(self.pdb_hierarchy, ncs_obj) # print("Found NCS") @@ -3607,7 +3622,7 @@ def set_donor_acceptor_excl_groups(): nrgl_ok = nrgl.check_for_max_rmsd(self.sites_cart, 0.01, null_out()) use_ncs_for_interpretation = (nrgl.get_n_groups()>0) and (nrgl == f_nrgl) and nrgl_ok if use_ncs_for_interpretation: - print(" will use NCS in pdb_interpretation") + # print(" will use NCS in pdb_interpretation") self._full_pdb_hierarchy = self.pdb_hierarchy self._old_models = models # self._full_pdb_atoms=self.pdb_atoms, @@ -3616,7 +3631,8 @@ def set_donor_acceptor_excl_groups(): # nrgl._show(self.pdb_hierarchy, brief=False) master_and_rest_bool_selection = ~flex.bool(self._full_pdb_hierarchy.atoms_size(), nrgl.get_all_copies_selection()) - self.pdb_hierarchy = self.pdb_hierarchy.select(master_and_rest_bool_selection) + self.pdb_hierarchy = self.pdb_hierarchy.select(master_and_rest_bool_selection,copy_atoms=True) + self.pdb_hierarchy.reset_atom_i_seqs() # print(self.pdb_hierarchy.as_pdb_string()) self.pdb_atoms = self.pdb_hierarchy.atoms() @@ -3936,7 +3952,7 @@ def raise_if_corrupt(link_resolution): nrgl.setup_sets() self.scattering_type_registry.expand_with_ncs(nrgl, self.pdb_hierarchy.atoms_size()) self.nonbonded_energy_type_registry.expand_with_ncs(nrgl, self.pdb_hierarchy.atoms_size()) - self.geometry_proxy_registries.expand_with_ncs(nrgl) + self.geometry_proxy_registries.expand_with_ncs(nrgl, self.pdb_hierarchy.atoms_size()) # self.scattering_type_registry._show() # STOP() @@ -5791,7 +5807,7 @@ def extract_xray_structure(self, unknown_scattering_type_substitute = "?"): self.pdb_atoms, sites_frac, scattering_types): - assert atom.i_seq == i_seq + assert atom.i_seq == i_seq, "%d != %d" % (atom.i_seq, i_seq) from cctbx.eltbx.xray_scattering import get_standard_label scattering_type = get_standard_label( label=scattering_type, exact=True, optional=True) diff --git a/mmtbx/regression/pdb_interpretation/tst_using_ncs_1.py b/mmtbx/regression/pdb_interpretation/tst_using_ncs_1.py new file mode 100644 index 0000000000..bfbfbbb55b --- /dev/null +++ b/mmtbx/regression/pdb_interpretation/tst_using_ncs_1.py @@ -0,0 +1,184 @@ +from __future__ import absolute_import, division, print_function + +import iotbx.pdb +import mmtbx.model +import libtbx.load_env +from libtbx.utils import null_out + + +pdb_str = """\ +ATOM 1 N GLY A 1 12.928 4.612 6.102 1.00 16.77 N +ATOM 2 CA GLY A 1 12.885 4.207 4.651 1.00 16.57 C +ATOM 3 C GLY A 1 13.922 3.140 4.419 1.00 16.16 C +ATOM 4 O GLY A 1 14.414 2.521 5.381 1.00 16.78 O +ATOM 5 H1 GLY A 1 11.977 4.525 6.514 0.00 16.77 H +ATOM 6 H2 GLY A 1 13.586 3.992 6.616 0.00 16.77 H +ATOM 7 H3 GLY A 1 13.250 5.598 6.177 0.00 16.77 H +ATOM 8 HA2 GLY A 1 11.900 3.815 4.398 0.00 16.57 H +ATOM 9 HA3 GLY A 1 13.100 5.065 4.014 0.00 16.57 H +ATOM 10 N ASN A 2 14.281 2.923 3.155 1.00 15.02 N +ATOM 11 CA ASN A 2 15.415 2.038 2.831 1.00 14.10 C +ATOM 12 C ASN A 2 16.696 2.537 3.427 1.00 13.13 C +ATOM 13 O ASN A 2 16.959 3.742 3.426 1.00 11.91 O +ATOM 14 CB ASN A 2 15.591 1.881 1.341 1.00 15.38 C +ATOM 15 CG ASN A 2 14.353 1.342 0.692 1.00 14.08 C +ATOM 16 OD1 ASN A 2 13.912 0.227 1.016 1.00 17.46 O +ATOM 17 ND2 ASN A 2 13.733 2.155 -0.169 1.00 11.72 N +ATOM 18 H ASN A 2 13.820 3.334 2.343 0.00 15.02 H +ATOM 19 HA ASN A 2 15.193 1.057 3.252 0.00 14.10 H +ATOM 20 HB2 ASN A 2 15.813 2.853 0.900 0.00 15.38 H +ATOM 21 HB3 ASN A 2 16.409 1.188 1.146 0.00 15.38 H +ATOM 22 HD21 ASN A 2 12.885 1.845 -0.643 0.00 11.72 H +ATOM 23 HD22 ASN A 2 14.108 3.086 -0.352 0.00 11.72 H +ATOM 24 N ASN A 3 17.499 1.590 3.905 1.00 12.26 N +ATOM 25 CA ASN A 3 18.744 1.904 4.589 1.00 11.74 C +ATOM 26 C ASN A 3 19.982 1.332 3.895 1.00 11.10 C +ATOM 27 O ASN A 3 20.065 0.119 3.648 1.00 10.42 O +ATOM 28 CB ASN A 3 18.678 1.378 6.042 1.00 12.15 C +ATOM 29 CG ASN A 3 19.931 1.739 6.861 1.00 12.82 C +ATOM 30 OD1 ASN A 3 20.235 2.925 7.072 1.00 15.05 O +ATOM 31 ND2 ASN A 3 20.666 0.715 7.306 1.00 13.48 N +ATOM 32 OXT ASN A 3 20.908 2.077 3.576 1.00 11.10 O +ATOM 33 H ASN A 3 17.311 0.590 3.832 0.00 12.26 H +ATOM 34 HA ASN A 3 18.863 2.987 4.586 0.00 11.74 H +ATOM 35 HB2 ASN A 3 17.812 1.815 6.539 0.00 12.15 H +ATOM 36 HB3 ASN A 3 18.588 0.292 6.023 0.00 12.15 H +ATOM 37 HD21 ASN A 3 21.508 0.892 7.854 0.00 13.48 H +ATOM 38 HD22 ASN A 3 20.385 -0.243 7.097 0.00 13.48 H +TER +ATOM 39 N GLY B 1 12.928 -0.254 6.102 1.00 16.77 N +ATOM 40 CA GLY B 1 12.885 -0.659 4.651 1.00 16.57 C +ATOM 41 C GLY B 1 13.922 -1.726 4.419 1.00 16.16 C +ATOM 42 O GLY B 1 14.414 -2.345 5.381 1.00 16.78 O +ATOM 43 H1 GLY B 1 11.977 -0.341 6.514 0.00 16.77 H +ATOM 44 H2 GLY B 1 13.586 -0.874 6.616 0.00 16.77 H +ATOM 45 H3 GLY B 1 13.250 0.732 6.177 0.00 16.77 H +ATOM 46 HA2 GLY B 1 11.900 -1.051 4.398 0.00 16.57 H +ATOM 47 HA3 GLY B 1 13.100 0.199 4.014 0.00 16.57 H +ATOM 48 N ASN B 2 14.281 -1.943 3.155 1.00 15.02 N +ATOM 49 CA ASN B 2 15.415 -2.828 2.831 1.00 14.10 C +ATOM 50 C ASN B 2 16.696 -2.329 3.427 1.00 13.13 C +ATOM 51 O ASN B 2 16.959 -1.124 3.426 1.00 11.91 O +ATOM 52 CB ASN B 2 15.591 -2.985 1.341 1.00 15.38 C +ATOM 53 CG ASN B 2 14.353 -3.524 0.692 1.00 14.08 C +ATOM 54 OD1 ASN B 2 13.912 -4.639 1.016 1.00 17.46 O +ATOM 55 ND2 ASN B 2 13.733 -2.711 -0.169 1.00 11.72 N +ATOM 56 H ASN B 2 13.820 -1.532 2.343 0.00 15.02 H +ATOM 57 HA ASN B 2 15.193 -3.809 3.252 0.00 14.10 H +ATOM 58 HB2 ASN B 2 15.813 -2.013 0.900 0.00 15.38 H +ATOM 59 HB3 ASN B 2 16.409 -3.678 1.146 0.00 15.38 H +ATOM 60 HD21 ASN B 2 12.885 -3.021 -0.643 0.00 11.72 H +ATOM 61 HD22 ASN B 2 14.108 -1.780 -0.352 0.00 11.72 H +ATOM 62 N ASN B 3 17.499 -3.276 3.905 1.00 12.26 N +ATOM 63 CA ASN B 3 18.744 -2.962 4.589 1.00 11.74 C +ATOM 64 C ASN B 3 19.982 -3.534 3.895 1.00 11.10 C +ATOM 65 O ASN B 3 20.065 -4.747 3.648 1.00 10.42 O +ATOM 66 CB ASN B 3 18.678 -3.488 6.042 1.00 12.15 C +ATOM 67 CG ASN B 3 19.931 -3.127 6.861 1.00 12.82 C +ATOM 68 OD1 ASN B 3 20.235 -1.941 7.072 1.00 15.05 O +ATOM 69 ND2 ASN B 3 20.666 -4.151 7.306 1.00 13.48 N +ATOM 70 OXT ASN B 3 20.908 -2.789 3.576 1.00 11.10 O +ATOM 71 H ASN B 3 17.311 -4.276 3.832 0.00 12.26 H +ATOM 72 HA ASN B 3 18.863 -1.879 4.586 0.00 11.74 H +ATOM 73 HB2 ASN B 3 17.812 -3.051 6.539 0.00 12.15 H +ATOM 74 HB3 ASN B 3 18.588 -4.574 6.023 0.00 12.15 H +ATOM 75 HD21 ASN B 3 21.508 -3.974 7.854 0.00 13.48 H +ATOM 76 HD22 ASN B 3 20.385 -5.109 7.097 0.00 13.48 H +TER +ATOM 77 N GLY C 1 12.928 9.478 6.102 1.00 16.77 N +ATOM 78 CA GLY C 1 12.885 9.073 4.651 1.00 16.57 C +ATOM 79 C GLY C 1 13.922 8.006 4.419 1.00 16.16 C +ATOM 80 O GLY C 1 14.414 7.387 5.381 1.00 16.78 O +ATOM 81 H1 GLY C 1 11.977 9.391 6.514 0.00 16.77 H +ATOM 82 H2 GLY C 1 13.586 8.858 6.616 0.00 16.77 H +ATOM 83 H3 GLY C 1 13.250 10.464 6.177 0.00 16.77 H +ATOM 84 HA2 GLY C 1 11.900 8.681 4.398 0.00 16.57 H +ATOM 85 HA3 GLY C 1 13.100 9.931 4.014 0.00 16.57 H +ATOM 86 N ASN C 2 14.281 7.789 3.155 1.00 15.02 N +ATOM 87 CA ASN C 2 15.415 6.904 2.831 1.00 14.10 C +ATOM 88 C ASN C 2 16.696 7.403 3.427 1.00 13.13 C +ATOM 89 O ASN C 2 16.959 8.608 3.426 1.00 11.91 O +ATOM 90 CB ASN C 2 15.591 6.747 1.341 1.00 15.38 C +ATOM 91 CG ASN C 2 14.353 6.208 0.692 1.00 14.08 C +ATOM 92 OD1 ASN C 2 13.912 5.093 1.016 1.00 17.46 O +ATOM 93 ND2 ASN C 2 13.733 7.021 -0.169 1.00 11.72 N +ATOM 94 H ASN C 2 13.820 8.200 2.343 0.00 15.02 H +ATOM 95 HA ASN C 2 15.193 5.923 3.252 0.00 14.10 H +ATOM 96 HB2 ASN C 2 15.813 7.719 0.900 0.00 15.38 H +ATOM 97 HB3 ASN C 2 16.409 6.054 1.146 0.00 15.38 H +ATOM 98 HD21 ASN C 2 12.885 6.711 -0.643 0.00 11.72 H +ATOM 99 HD22 ASN C 2 14.108 7.952 -0.352 0.00 11.72 H +ATOM 100 N ASN C 3 17.499 6.456 3.905 1.00 12.26 N +ATOM 101 CA ASN C 3 18.744 6.770 4.589 1.00 11.74 C +ATOM 102 C ASN C 3 19.982 6.198 3.895 1.00 11.10 C +ATOM 103 O ASN C 3 20.065 4.985 3.648 1.00 10.42 O +ATOM 104 CB ASN C 3 18.678 6.244 6.042 1.00 12.15 C +ATOM 105 CG ASN C 3 19.931 6.605 6.861 1.00 12.82 C +ATOM 106 OD1 ASN C 3 20.235 7.791 7.072 1.00 15.05 O +ATOM 107 ND2 ASN C 3 20.666 5.581 7.306 1.00 13.48 N +ATOM 108 OXT ASN C 3 20.908 6.943 3.576 1.00 11.10 O +ATOM 109 H ASN C 3 17.311 5.456 3.832 0.00 12.26 H +ATOM 110 HA ASN C 3 18.863 7.853 4.586 0.00 11.74 H +ATOM 111 HB2 ASN C 3 17.812 6.681 6.539 0.00 12.15 H +ATOM 112 HB3 ASN C 3 18.588 5.158 6.023 0.00 12.15 H +ATOM 113 HD21 ASN C 3 21.508 5.758 7.854 0.00 13.48 H +ATOM 114 HD22 ASN C 3 20.385 4.623 7.097 0.00 13.48 H +TER +ATOM 115 N GLY D 1 9.009 2.179 -6.102 1.00 16.77 N +ATOM 116 CA GLY D 1 9.052 1.774 -4.651 1.00 16.57 C +ATOM 117 C GLY D 1 8.015 0.707 -4.419 1.00 16.16 C +ATOM 118 O GLY D 1 7.523 0.088 -5.381 1.00 16.78 O +ATOM 119 H1 GLY D 1 9.960 2.092 -6.514 0.00 16.77 H +ATOM 120 H2 GLY D 1 8.351 1.559 -6.616 0.00 16.77 H +ATOM 121 H3 GLY D 1 8.687 3.165 -6.177 0.00 16.77 H +ATOM 122 HA2 GLY D 1 10.037 1.382 -4.398 0.00 16.57 H +ATOM 123 HA3 GLY D 1 8.837 2.632 -4.014 0.00 16.57 H +ATOM 124 N ASN D 2 7.656 0.490 -3.155 1.00 15.02 N +ATOM 125 CA ASN D 2 6.522 -0.395 -2.831 1.00 14.10 C +ATOM 126 C ASN D 2 5.241 0.104 -3.427 1.00 13.13 C +ATOM 127 O ASN D 2 4.978 1.309 -3.426 1.00 11.91 O +ATOM 128 CB ASN D 2 6.346 -0.552 -1.341 1.00 15.38 C +ATOM 129 CG ASN D 2 7.584 -1.091 -0.692 1.00 14.08 C +ATOM 130 OD1 ASN D 2 8.025 -2.206 -1.016 1.00 17.46 O +ATOM 131 ND2 ASN D 2 8.204 -0.278 0.169 1.00 11.72 N +ATOM 132 H ASN D 2 8.117 0.901 -2.343 0.00 15.02 H +ATOM 133 HA ASN D 2 6.744 -1.376 -3.252 0.00 14.10 H +ATOM 134 HB2 ASN D 2 6.124 0.420 -0.900 0.00 15.38 H +ATOM 135 HB3 ASN D 2 5.528 -1.245 -1.146 0.00 15.38 H +ATOM 136 HD21 ASN D 2 9.052 -0.588 0.643 0.00 11.72 H +ATOM 137 HD22 ASN D 2 7.829 0.653 0.352 0.00 11.72 H +TER +ATOM 138 N ASN E 2 7.656 5.356 -3.155 1.00 15.02 N +ATOM 139 CA ASN E 2 6.522 4.471 -2.831 1.00 14.10 C +ATOM 140 C ASN E 2 5.241 4.970 -3.427 1.00 13.13 C +ATOM 141 O ASN E 2 4.978 6.175 -3.426 1.00 11.91 O +ATOM 142 CB ASN E 2 6.346 4.314 -1.341 1.00 15.38 C +ATOM 143 CG ASN E 2 7.584 3.775 -0.692 1.00 14.08 C +ATOM 144 OD1 ASN E 2 8.025 2.660 -1.016 1.00 17.46 O +ATOM 145 ND2 ASN E 2 8.204 4.588 0.169 1.00 11.72 N +ATOM 146 H ASN E 2 8.117 5.767 -2.343 0.00 15.02 H +ATOM 147 HA ASN E 2 6.744 3.490 -3.252 0.00 14.10 H +ATOM 148 HB2 ASN E 2 6.124 5.286 -0.900 0.00 15.38 H +ATOM 149 HB3 ASN E 2 5.528 3.621 -1.146 0.00 15.38 H +ATOM 150 HD21 ASN E 2 9.052 4.278 0.643 0.00 11.72 H +ATOM 151 HD22 ASN E 2 7.829 5.519 0.352 0.00 11.72 H +TER +""" + +def exercise_01(): + + + pdb_inp = iotbx.pdb.input(source_info=None, lines=pdb_str) + m = mmtbx.model.manager(model_input = pdb_inp, log = null_out()) + p = m.get_default_pdb_interpretation_params() + p.pdb_interpretation.use_ncs_to_build_restraints = True + # p.pdb_interpretation.use_ncs_to_build_restraints = False + m.process(make_restraints=True, pdb_interpretation_params=p) + + +if(__name__ == "__main__"): + if libtbx.env.find_in_repositories(relative_path="chem_data") is None: + print("Skipping exercise_02(): chem_data directory not available") + else: + exercise_01() + print('OK') diff --git a/mmtbx/regression/pdb_interpretation/tst_using_ncs_2.py b/mmtbx/regression/pdb_interpretation/tst_using_ncs_2.py new file mode 100644 index 0000000000..25b05c5820 --- /dev/null +++ b/mmtbx/regression/pdb_interpretation/tst_using_ncs_2.py @@ -0,0 +1,478 @@ +from __future__ import absolute_import, division, print_function + +import iotbx.pdb +import mmtbx.model +import libtbx.load_env +from libtbx.utils import null_out + + +pdb_str = """\ +ATOM 1 N GLY A 1 -9.009 4.612 6.102 1.00 16.77 N +ATOM 2 CA GLY A 1 -9.052 4.207 4.651 1.00 16.57 C +ATOM 3 C GLY A 1 -8.015 3.140 4.419 1.00 16.16 C +ATOM 4 O GLY A 1 -7.523 2.521 5.381 1.00 16.78 O +ATOM 5 N ASN A 2 -7.656 2.923 3.155 1.00 15.02 N +ATOM 6 CA ASN A 2 -6.522 2.038 2.831 1.00 14.10 C +ATOM 7 C ASN A 2 -5.241 2.537 3.427 1.00 13.13 C +ATOM 8 O ASN A 2 -4.978 3.742 3.426 1.00 11.91 O +ATOM 9 CB ASN A 2 -6.346 1.881 1.341 1.00 15.38 C +ATOM 10 CG ASN A 2 -7.584 1.342 0.692 1.00 14.08 C +ATOM 11 OD1 ASN A 2 -8.025 0.227 1.016 1.00 17.46 O +ATOM 12 ND2 ASN A 2 -8.204 2.155 -0.169 1.00 11.72 N +ATOM 13 N ASN A 3 -4.438 1.590 3.905 1.00 12.26 N +ATOM 14 CA ASN A 3 -3.193 1.904 4.589 1.00 11.74 C +ATOM 15 C ASN A 3 -1.955 1.332 3.895 1.00 11.10 C +ATOM 16 O ASN A 3 -1.872 0.119 3.648 1.00 10.42 O +ATOM 17 CB ASN A 3 -3.259 1.378 6.042 1.00 12.15 C +ATOM 18 CG ASN A 3 -2.006 1.739 6.861 1.00 12.82 C +ATOM 19 OD1 ASN A 3 -1.702 2.925 7.072 1.00 15.05 O +ATOM 20 ND2 ASN A 3 -1.271 0.715 7.306 1.00 13.48 N +ATOM 21 N GLN A 4 -1.005 2.228 3.598 1.00 10.29 N +ATOM 22 CA GLN A 4 0.384 1.888 3.199 1.00 10.53 C +ATOM 23 C GLN A 4 1.435 2.606 4.088 1.00 10.24 C +ATOM 24 O GLN A 4 1.547 3.843 4.115 1.00 8.86 O +ATOM 25 CB GLN A 4 0.656 2.148 1.711 1.00 9.80 C +ATOM 26 CG GLN A 4 1.944 1.458 1.213 1.00 10.25 C +ATOM 27 CD GLN A 4 2.504 2.044 -0.089 1.00 12.43 C +ATOM 28 OE1 GLN A 4 2.744 3.268 -0.190 1.00 14.62 O +ATOM 29 NE2 GLN A 4 2.750 1.161 -1.091 1.00 9.05 N +ATOM 30 N GLN A 5 2.154 1.821 4.871 1.00 10.38 N +ATOM 31 CA GLN A 5 3.270 2.361 5.640 1.00 11.39 C +ATOM 32 C GLN A 5 4.594 1.768 5.172 1.00 11.52 C +ATOM 33 O GLN A 5 4.768 0.546 5.054 1.00 12.05 O +ATOM 34 CB GLN A 5 3.056 2.183 7.147 1.00 11.96 C +ATOM 35 CG GLN A 5 1.829 2.950 7.647 1.00 10.81 C +ATOM 36 CD GLN A 5 1.344 2.414 8.954 1.00 13.10 C +ATOM 37 OE1 GLN A 5 0.774 1.325 9.002 1.00 10.65 O +ATOM 38 NE2 GLN A 5 1.549 3.187 10.039 1.00 12.30 N +ATOM 39 N ASN A 6 5.514 2.664 4.856 1.00 11.99 N +ATOM 40 CA ASN A 6 6.831 2.310 4.318 1.00 12.30 C +ATOM 41 C ASN A 6 7.854 2.761 5.324 1.00 13.40 C +ATOM 42 O ASN A 6 8.219 3.943 5.374 1.00 13.92 O +ATOM 43 CB ASN A 6 7.065 3.016 2.993 1.00 12.13 C +ATOM 44 CG ASN A 6 5.961 2.735 2.003 1.00 12.77 C +ATOM 45 OD1 ASN A 6 5.798 1.604 1.551 1.00 14.27 O +ATOM 46 ND2 ASN A 6 5.195 3.747 1.679 1.00 10.07 N +ATOM 47 N TYR A 7 8.292 1.817 6.147 1.00 14.70 N +ATOM 48 CA TYR A 7 9.159 2.144 7.299 1.00 15.18 C +ATOM 49 C TYR A 7 10.603 2.331 6.885 1.00 15.91 C +ATOM 50 O TYR A 7 11.041 1.811 5.855 1.00 15.76 O +ATOM 51 CB TYR A 7 9.061 1.065 8.369 1.00 15.35 C +ATOM 52 CG TYR A 7 7.665 0.929 8.902 1.00 14.45 C +ATOM 53 CD1 TYR A 7 7.210 1.756 9.920 1.00 14.80 C +ATOM 54 CD2 TYR A 7 6.771 0.021 8.327 1.00 15.68 C +ATOM 55 CE1 TYR A 7 5.904 1.649 10.416 1.00 14.33 C +ATOM 56 CE2 TYR A 7 5.480 -0.094 8.796 1.00 13.46 C +ATOM 57 CZ TYR A 7 5.047 0.729 9.831 1.00 15.09 C +ATOM 58 OH TYR A 7 3.766 0.589 10.291 1.00 14.39 O +ATOM 59 OXT TYR A 7 11.358 2.999 7.612 1.00 17.49 O +TER +HETATM 60 O HOH A 8 -6.471 5.227 7.124 1.00 22.62 O +HETATM 61 O HOH A 9 10.431 1.858 3.216 1.00 19.71 O +HETATM 62 O HOH A 10 -11.286 1.756 -1.468 1.00 17.08 O +HETATM 63 O HOH A 11 11.808 4.179 9.970 1.00 23.99 O +HETATM 64 O HOH A 12 13.605 1.327 9.198 1.00 26.17 O +HETATM 65 O HOH A 13 -2.749 3.429 10.024 1.00 39.15 O +HETATM 66 O HOH A 14 -1.500 0.682 10.967 1.00 43.49 O +ATOM 67 N GLY B 1 -9.009 -0.254 6.102 1.00 16.77 N +ATOM 68 CA GLY B 1 -9.052 -0.659 4.651 1.00 16.57 C +ATOM 69 C GLY B 1 -8.015 -1.726 4.419 1.00 16.16 C +ATOM 70 O GLY B 1 -7.523 -2.345 5.381 1.00 16.78 O +ATOM 71 N ASN B 2 -7.656 -1.943 3.155 1.00 15.02 N +ATOM 72 CA ASN B 2 -6.522 -2.828 2.831 1.00 14.10 C +ATOM 73 C ASN B 2 -5.241 -2.329 3.427 1.00 13.13 C +ATOM 74 O ASN B 2 -4.978 -1.124 3.426 1.00 11.91 O +ATOM 75 CB ASN B 2 -6.346 -2.985 1.341 1.00 15.38 C +ATOM 76 CG ASN B 2 -7.584 -3.524 0.692 1.00 14.08 C +ATOM 77 OD1 ASN B 2 -8.025 -4.639 1.016 1.00 17.46 O +ATOM 78 ND2 ASN B 2 -8.204 -2.711 -0.169 1.00 11.72 N +ATOM 79 N ASN B 3 -4.438 -3.276 3.905 1.00 12.26 N +ATOM 80 CA ASN B 3 -3.193 -2.962 4.589 1.00 11.74 C +ATOM 81 C ASN B 3 -1.955 -3.534 3.895 1.00 11.10 C +ATOM 82 O ASN B 3 -1.872 -4.747 3.648 1.00 10.42 O +ATOM 83 CB ASN B 3 -3.259 -3.488 6.042 1.00 12.15 C +ATOM 84 CG ASN B 3 -2.006 -3.127 6.861 1.00 12.82 C +ATOM 85 OD1 ASN B 3 -1.702 -1.941 7.072 1.00 15.05 O +ATOM 86 ND2 ASN B 3 -1.271 -4.151 7.306 1.00 13.48 N +ATOM 87 N GLN B 4 -1.005 -2.638 3.598 1.00 10.29 N +ATOM 88 CA GLN B 4 0.384 -2.978 3.199 1.00 10.53 C +ATOM 89 C GLN B 4 1.435 -2.260 4.088 1.00 10.24 C +ATOM 90 O GLN B 4 1.547 -1.023 4.115 1.00 8.86 O +ATOM 91 CB GLN B 4 0.656 -2.718 1.711 1.00 9.80 C +ATOM 92 CG GLN B 4 1.944 -3.408 1.213 1.00 10.25 C +ATOM 93 CD GLN B 4 2.504 -2.822 -0.089 1.00 12.43 C +ATOM 94 OE1 GLN B 4 2.744 -1.598 -0.190 1.00 14.62 O +ATOM 95 NE2 GLN B 4 2.750 -3.705 -1.091 1.00 9.05 N +ATOM 96 N GLN B 5 2.154 -3.045 4.871 1.00 10.38 N +ATOM 97 CA GLN B 5 3.270 -2.505 5.640 1.00 11.39 C +ATOM 98 C GLN B 5 4.594 -3.098 5.172 1.00 11.52 C +ATOM 99 O GLN B 5 4.768 -4.320 5.054 1.00 12.05 O +ATOM 100 CB GLN B 5 3.056 -2.683 7.147 1.00 11.96 C +ATOM 101 CG GLN B 5 1.829 -1.916 7.647 1.00 10.81 C +ATOM 102 CD GLN B 5 1.344 -2.452 8.954 1.00 13.10 C +ATOM 103 OE1 GLN B 5 0.774 -3.541 9.002 1.00 10.65 O +ATOM 104 NE2 GLN B 5 1.549 -1.679 10.039 1.00 12.30 N +ATOM 105 N ASN B 6 5.514 -2.202 4.856 1.00 11.99 N +ATOM 106 CA ASN B 6 6.831 -2.556 4.318 1.00 12.30 C +ATOM 107 C ASN B 6 7.854 -2.105 5.324 1.00 13.40 C +ATOM 108 O ASN B 6 8.219 -0.923 5.374 1.00 13.92 O +ATOM 109 CB ASN B 6 7.065 -1.850 2.993 1.00 12.13 C +ATOM 110 CG ASN B 6 5.961 -2.131 2.003 1.00 12.77 C +ATOM 111 OD1 ASN B 6 5.798 -3.262 1.551 1.00 14.27 O +ATOM 112 ND2 ASN B 6 5.195 -1.119 1.679 1.00 10.07 N +ATOM 113 N TYR B 7 8.292 -3.049 6.147 1.00 14.70 N +ATOM 114 CA TYR B 7 9.159 -2.722 7.299 1.00 15.18 C +ATOM 115 C TYR B 7 10.603 -2.535 6.885 1.00 15.91 C +ATOM 116 O TYR B 7 11.041 -3.055 5.855 1.00 15.76 O +ATOM 117 CB TYR B 7 9.061 -3.801 8.369 1.00 15.35 C +ATOM 118 CG TYR B 7 7.665 -3.937 8.902 1.00 14.45 C +ATOM 119 CD1 TYR B 7 7.210 -3.110 9.920 1.00 14.80 C +ATOM 120 CD2 TYR B 7 6.771 -4.845 8.327 1.00 15.68 C +ATOM 121 CE1 TYR B 7 5.904 -3.217 10.416 1.00 14.33 C +ATOM 122 CE2 TYR B 7 5.480 -4.960 8.796 1.00 13.46 C +ATOM 123 CZ TYR B 7 5.047 -4.137 9.831 1.00 15.09 C +ATOM 124 OH TYR B 7 3.766 -4.277 10.291 1.00 14.39 O +ATOM 125 OXT TYR B 7 11.358 -1.867 7.612 1.00 17.49 O +TER +HETATM 126 O HOH C 8 -6.471 0.361 7.124 1.00 22.62 O +HETATM 127 O HOH C 9 10.431 -3.008 3.216 1.00 19.71 O +HETATM 128 O HOH C 10 -11.286 -3.110 -1.468 1.00 17.08 O +HETATM 129 O HOH C 11 11.808 -0.687 9.970 1.00 23.99 O +HETATM 130 O HOH C 12 13.605 -3.539 9.198 1.00 26.17 O +HETATM 131 O HOH C 13 -2.749 -1.437 10.024 1.00 39.15 O +HETATM 132 O HOH C 14 -1.500 -4.184 10.967 1.00 43.49 O +HETATM 133 O HOH E 13 -4.146 0.996 12.418 1.00 39.15 O +HETATM 134 O HOH E 14 -5.395 -1.751 11.475 1.00 43.49 O +HETATM 135 O HOH G 13 -4.146 5.862 12.418 1.00 39.15 O +HETATM 136 O HOH G 14 -5.395 3.115 11.475 1.00 43.49 O +ATOM 137 N GLY H 1 -9.009 9.478 6.102 1.00 16.77 N +ATOM 138 CA GLY H 1 -9.052 9.073 4.651 1.00 16.57 C +ATOM 139 C GLY H 1 -8.015 8.006 4.419 1.00 16.16 C +ATOM 140 O GLY H 1 -7.523 7.387 5.381 1.00 16.78 O +ATOM 141 N ASN H 2 -7.656 7.789 3.155 1.00 15.02 N +ATOM 142 CA ASN H 2 -6.522 6.904 2.831 1.00 14.10 C +ATOM 143 C ASN H 2 -5.241 7.403 3.427 1.00 13.13 C +ATOM 144 O ASN H 2 -4.978 8.608 3.426 1.00 11.91 O +ATOM 145 CB ASN H 2 -6.346 6.747 1.341 1.00 15.38 C +ATOM 146 CG ASN H 2 -7.584 6.208 0.692 1.00 14.08 C +ATOM 147 OD1 ASN H 2 -8.025 5.093 1.016 1.00 17.46 O +ATOM 148 ND2 ASN H 2 -8.204 7.021 -0.169 1.00 11.72 N +ATOM 149 N ASN H 3 -4.438 6.456 3.905 1.00 12.26 N +ATOM 150 CA ASN H 3 -3.193 6.770 4.589 1.00 11.74 C +ATOM 151 C ASN H 3 -1.955 6.198 3.895 1.00 11.10 C +ATOM 152 O ASN H 3 -1.872 4.985 3.648 1.00 10.42 O +ATOM 153 CB ASN H 3 -3.259 6.244 6.042 1.00 12.15 C +ATOM 154 CG ASN H 3 -2.006 6.605 6.861 1.00 12.82 C +ATOM 155 OD1 ASN H 3 -1.702 7.791 7.072 1.00 15.05 O +ATOM 156 ND2 ASN H 3 -1.271 5.581 7.306 1.00 13.48 N +ATOM 157 N GLN H 4 -1.005 7.094 3.598 1.00 10.29 N +ATOM 158 CA GLN H 4 0.384 6.754 3.199 1.00 10.53 C +ATOM 159 C GLN H 4 1.435 7.472 4.088 1.00 10.24 C +ATOM 160 O GLN H 4 1.547 8.709 4.115 1.00 8.86 O +ATOM 161 CB GLN H 4 0.656 7.014 1.711 1.00 9.80 C +ATOM 162 CG GLN H 4 1.944 6.324 1.213 1.00 10.25 C +ATOM 163 CD GLN H 4 2.504 6.910 -0.089 1.00 12.43 C +ATOM 164 OE1 GLN H 4 2.744 8.134 -0.190 1.00 14.62 O +ATOM 165 NE2 GLN H 4 2.750 6.027 -1.091 1.00 9.05 N +ATOM 166 N GLN H 5 2.154 6.687 4.871 1.00 10.38 N +ATOM 167 CA GLN H 5 3.270 7.227 5.640 1.00 11.39 C +ATOM 168 C GLN H 5 4.594 6.634 5.172 1.00 11.52 C +ATOM 169 O GLN H 5 4.768 5.412 5.054 1.00 12.05 O +ATOM 170 CB GLN H 5 3.056 7.049 7.147 1.00 11.96 C +ATOM 171 CG GLN H 5 1.829 7.816 7.647 1.00 10.81 C +ATOM 172 CD GLN H 5 1.344 7.280 8.954 1.00 13.10 C +ATOM 173 OE1 GLN H 5 0.774 6.191 9.002 1.00 10.65 O +ATOM 174 NE2 GLN H 5 1.549 8.053 10.039 1.00 12.30 N +ATOM 175 N ASN H 6 5.514 7.530 4.856 1.00 11.99 N +ATOM 176 CA ASN H 6 6.831 7.176 4.318 1.00 12.30 C +ATOM 177 C ASN H 6 7.854 7.627 5.324 1.00 13.40 C +ATOM 178 O ASN H 6 8.219 8.809 5.374 1.00 13.92 O +ATOM 179 CB ASN H 6 7.065 7.882 2.993 1.00 12.13 C +ATOM 180 CG ASN H 6 5.961 7.601 2.003 1.00 12.77 C +ATOM 181 OD1 ASN H 6 5.798 6.470 1.551 1.00 14.27 O +ATOM 182 ND2 ASN H 6 5.195 8.613 1.679 1.00 10.07 N +ATOM 183 N TYR H 7 8.292 6.683 6.147 1.00 14.70 N +ATOM 184 CA TYR H 7 9.159 7.010 7.299 1.00 15.18 C +ATOM 185 C TYR H 7 10.603 7.197 6.885 1.00 15.91 C +ATOM 186 O TYR H 7 11.041 6.677 5.855 1.00 15.76 O +ATOM 187 CB TYR H 7 9.061 5.931 8.369 1.00 15.35 C +ATOM 188 CG TYR H 7 7.665 5.795 8.902 1.00 14.45 C +ATOM 189 CD1 TYR H 7 7.210 6.622 9.920 1.00 14.80 C +ATOM 190 CD2 TYR H 7 6.771 4.887 8.327 1.00 15.68 C +ATOM 191 CE1 TYR H 7 5.904 6.515 10.416 1.00 14.33 C +ATOM 192 CE2 TYR H 7 5.480 4.772 8.796 1.00 13.46 C +ATOM 193 CZ TYR H 7 5.047 5.595 9.831 1.00 15.09 C +ATOM 194 OH TYR H 7 3.766 5.455 10.291 1.00 14.39 O +ATOM 195 OXT TYR H 7 11.358 7.865 7.612 1.00 17.49 O +TER +HETATM 196 O HOH I 9 10.431 6.724 3.216 1.00 19.71 O +HETATM 197 O HOH I 10 -11.286 6.622 -1.468 1.00 17.08 O +HETATM 198 O HOH I 12 13.605 6.193 9.198 1.00 26.17 O +HETATM 199 O HOH I 14 -1.500 5.548 10.967 1.00 43.49 O +ATOM 200 N GLN L 5 12.888 4.254 17.571 1.00 10.38 N +ATOM 201 CA GLN L 5 11.772 4.794 16.802 1.00 11.39 C +ATOM 202 C GLN L 5 10.448 4.201 17.270 1.00 11.52 C +ATOM 203 O GLN L 5 10.274 2.979 17.388 1.00 12.05 O +ATOM 204 CB GLN L 5 11.986 4.616 15.295 1.00 11.96 C +ATOM 205 CG GLN L 5 13.213 5.383 14.795 1.00 10.81 C +ATOM 206 CD GLN L 5 13.698 4.847 13.488 1.00 13.10 C +ATOM 207 OE1 GLN L 5 14.268 3.758 13.440 1.00 10.65 O +ATOM 208 NE2 GLN L 5 13.493 5.620 12.403 1.00 12.30 N +ATOM 209 N TYR L 7 6.750 4.250 16.295 1.00 14.70 N +ATOM 210 CA TYR L 7 5.883 4.577 15.143 1.00 15.18 C +ATOM 211 C TYR L 7 4.439 4.764 15.557 1.00 15.91 C +ATOM 212 O TYR L 7 4.001 4.244 16.587 1.00 15.76 O +ATOM 213 CB TYR L 7 5.981 3.498 14.073 1.00 15.35 C +ATOM 214 CG TYR L 7 7.377 3.362 13.540 1.00 14.45 C +ATOM 215 CD1 TYR L 7 7.832 4.189 12.522 1.00 14.80 C +ATOM 216 CD2 TYR L 7 8.271 2.454 14.115 1.00 15.68 C +ATOM 217 CE1 TYR L 7 9.138 4.082 12.026 1.00 14.33 C +ATOM 218 CE2 TYR L 7 9.562 2.339 13.646 1.00 13.46 C +ATOM 219 CZ TYR L 7 9.995 3.162 12.611 1.00 15.09 C +ATOM 220 OH TYR L 7 11.276 3.022 12.151 1.00 14.39 O +ATOM 221 OXT TYR L 7 3.684 5.432 14.830 1.00 17.49 O +TER +HETATM 222 O HOH M 11 3.234 6.612 12.472 1.00 23.99 O +HETATM 223 O HOH M 12 1.437 3.760 13.244 1.00 26.17 O +HETATM 224 O HOH M 14 16.542 3.115 11.475 1.00 43.49 O +ATOM 225 N ASN N 2 7.656 0.490 -3.155 1.00 15.02 N +ATOM 226 CA ASN N 2 6.522 -0.395 -2.831 1.00 14.10 C +ATOM 227 C ASN N 2 5.241 0.104 -3.427 1.00 13.13 C +ATOM 228 O ASN N 2 4.978 1.309 -3.426 1.00 11.91 O +ATOM 229 CB ASN N 2 6.346 -0.552 -1.341 1.00 15.38 C +ATOM 230 CG ASN N 2 7.584 -1.091 -0.692 1.00 14.08 C +ATOM 231 OD1 ASN N 2 8.025 -2.206 -1.016 1.00 17.46 O +ATOM 232 ND2 ASN N 2 8.204 -0.278 0.169 1.00 11.72 N +ATOM 233 N ASN N 3 4.438 -0.843 -3.905 1.00 12.26 N +ATOM 234 CA ASN N 3 3.193 -0.529 -4.589 1.00 11.74 C +ATOM 235 C ASN N 3 1.955 -1.101 -3.895 1.00 11.10 C +ATOM 236 O ASN N 3 1.872 -2.314 -3.648 1.00 10.42 O +ATOM 237 CB ASN N 3 3.259 -1.055 -6.042 1.00 12.15 C +ATOM 238 CG ASN N 3 2.006 -0.694 -6.861 1.00 12.82 C +ATOM 239 OD1 ASN N 3 1.702 0.492 -7.072 1.00 15.05 O +ATOM 240 ND2 ASN N 3 1.271 -1.718 -7.306 1.00 13.48 N +ATOM 241 N GLN N 4 1.005 -0.205 -3.598 1.00 10.29 N +ATOM 242 CA GLN N 4 -0.384 -0.545 -3.199 1.00 10.53 C +ATOM 243 C GLN N 4 -1.435 0.173 -4.088 1.00 10.24 C +ATOM 244 O GLN N 4 -1.547 1.410 -4.115 1.00 8.86 O +ATOM 245 CB GLN N 4 -0.656 -0.285 -1.711 1.00 9.80 C +ATOM 246 CG GLN N 4 -1.944 -0.975 -1.213 1.00 10.25 C +ATOM 247 CD GLN N 4 -2.504 -0.389 0.089 1.00 12.43 C +ATOM 248 OE1 GLN N 4 -2.744 0.835 0.190 1.00 14.62 O +ATOM 249 NE2 GLN N 4 -2.750 -1.272 1.091 1.00 9.05 N +ATOM 250 N ASN N 6 -5.514 0.231 -4.856 1.00 11.99 N +ATOM 251 CA ASN N 6 -6.831 -0.123 -4.318 1.00 12.30 C +ATOM 252 C ASN N 6 -7.854 0.328 -5.324 1.00 13.40 C +ATOM 253 O ASN N 6 -8.219 1.510 -5.374 1.00 13.92 O +ATOM 254 CB ASN N 6 -7.065 0.583 -2.993 1.00 12.13 C +ATOM 255 CG ASN N 6 -5.961 0.302 -2.003 1.00 12.77 C +ATOM 256 OD1 ASN N 6 -5.798 -0.829 -1.551 1.00 14.27 O +ATOM 257 ND2 ASN N 6 -5.195 1.314 -1.679 1.00 10.07 N +TER +HETATM 258 O HOH O 9 -10.431 -0.575 -3.216 1.00 19.71 O +HETATM 259 O HOH O 10 11.286 -0.677 1.468 1.00 17.08 O +ATOM 260 N ASN P 2 7.656 5.356 -3.155 1.00 15.02 N +ATOM 261 CA ASN P 2 6.522 4.471 -2.831 1.00 14.10 C +ATOM 262 C ASN P 2 5.241 4.970 -3.427 1.00 13.13 C +ATOM 263 O ASN P 2 4.978 6.175 -3.426 1.00 11.91 O +ATOM 264 CB ASN P 2 6.346 4.314 -1.341 1.00 15.38 C +ATOM 265 CG ASN P 2 7.584 3.775 -0.692 1.00 14.08 C +ATOM 266 OD1 ASN P 2 8.025 2.660 -1.016 1.00 17.46 O +ATOM 267 ND2 ASN P 2 8.204 4.588 0.169 1.00 11.72 N +ATOM 268 N ASN P 3 4.438 4.023 -3.905 1.00 12.26 N +ATOM 269 CA ASN P 3 3.193 4.337 -4.589 1.00 11.74 C +ATOM 270 C ASN P 3 1.955 3.765 -3.895 1.00 11.10 C +ATOM 271 O ASN P 3 1.872 2.552 -3.648 1.00 10.42 O +ATOM 272 CB ASN P 3 3.259 3.811 -6.042 1.00 12.15 C +ATOM 273 CG ASN P 3 2.006 4.172 -6.861 1.00 12.82 C +ATOM 274 OD1 ASN P 3 1.702 5.358 -7.072 1.00 15.05 O +ATOM 275 ND2 ASN P 3 1.271 3.148 -7.306 1.00 13.48 N +ATOM 276 N GLN P 4 1.005 4.661 -3.598 1.00 10.29 N +ATOM 277 CA GLN P 4 -0.384 4.321 -3.199 1.00 10.53 C +ATOM 278 C GLN P 4 -1.435 5.039 -4.088 1.00 10.24 C +ATOM 279 O GLN P 4 -1.547 6.276 -4.115 1.00 8.86 O +ATOM 280 CB GLN P 4 -0.656 4.581 -1.711 1.00 9.80 C +ATOM 281 CG GLN P 4 -1.944 3.891 -1.213 1.00 10.25 C +ATOM 282 CD GLN P 4 -2.504 4.477 0.089 1.00 12.43 C +ATOM 283 OE1 GLN P 4 -2.744 5.701 0.190 1.00 14.62 O +ATOM 284 NE2 GLN P 4 -2.750 3.594 1.091 1.00 9.05 N +ATOM 285 N ASN P 6 -5.514 5.097 -4.856 1.00 11.99 N +ATOM 286 CA ASN P 6 -6.831 4.743 -4.318 1.00 12.30 C +ATOM 287 C ASN P 6 -7.854 5.194 -5.324 1.00 13.40 C +ATOM 288 O ASN P 6 -8.219 6.376 -5.374 1.00 13.92 O +ATOM 289 CB ASN P 6 -7.065 5.449 -2.993 1.00 12.13 C +ATOM 290 CG ASN P 6 -5.961 5.168 -2.003 1.00 12.77 C +ATOM 291 OD1 ASN P 6 -5.798 4.037 -1.551 1.00 14.27 O +ATOM 292 ND2 ASN P 6 -5.195 6.180 -1.679 1.00 10.07 N +ATOM 293 N TYR P 7 -8.292 4.250 -6.147 1.00 14.70 N +ATOM 294 CA TYR P 7 -9.159 4.577 -7.299 1.00 15.18 C +ATOM 295 C TYR P 7 -10.603 4.764 -6.885 1.00 15.91 C +ATOM 296 O TYR P 7 -11.041 4.244 -5.855 1.00 15.76 O +ATOM 297 CB TYR P 7 -9.061 3.498 -8.369 1.00 15.35 C +ATOM 298 CG TYR P 7 -7.665 3.362 -8.902 1.00 14.45 C +ATOM 299 CD1 TYR P 7 -7.210 4.189 -9.920 1.00 14.80 C +ATOM 300 CD2 TYR P 7 -6.771 2.454 -8.327 1.00 15.68 C +ATOM 301 CE1 TYR P 7 -5.904 4.082 -10.416 1.00 14.33 C +ATOM 302 CE2 TYR P 7 -5.480 2.339 -8.796 1.00 13.46 C +ATOM 303 CZ TYR P 7 -5.047 3.162 -9.831 1.00 15.09 C +ATOM 304 OH TYR P 7 -3.766 3.022 -10.291 1.00 14.39 O +ATOM 305 OXT TYR P 7 -11.358 5.432 -7.612 1.00 17.49 O +TER +HETATM 306 O HOH Q 9 -10.431 4.291 -3.216 1.00 19.71 O +HETATM 307 O HOH Q 10 11.286 4.189 1.468 1.00 17.08 O +ATOM 308 N GLN R 5 12.888 -0.612 17.571 1.00 10.38 N +ATOM 309 CA GLN R 5 11.772 -0.072 16.802 1.00 11.39 C +ATOM 310 C GLN R 5 10.448 -0.665 17.270 1.00 11.52 C +ATOM 311 O GLN R 5 10.274 -1.887 17.388 1.00 12.05 O +ATOM 312 CB GLN R 5 11.986 -0.250 15.295 1.00 11.96 C +ATOM 313 CG GLN R 5 13.213 0.517 14.795 1.00 10.81 C +ATOM 314 CD GLN R 5 13.698 -0.019 13.488 1.00 13.10 C +ATOM 315 OE1 GLN R 5 14.268 -1.108 13.440 1.00 10.65 O +ATOM 316 NE2 GLN R 5 13.493 0.754 12.403 1.00 12.30 N +ATOM 317 N TYR R 7 6.750 -0.616 16.295 1.00 14.70 N +ATOM 318 CA TYR R 7 5.883 -0.289 15.143 1.00 15.18 C +ATOM 319 C TYR R 7 4.439 -0.102 15.557 1.00 15.91 C +ATOM 320 O TYR R 7 4.001 -0.622 16.587 1.00 15.76 O +ATOM 321 CB TYR R 7 5.981 -1.368 14.073 1.00 15.35 C +ATOM 322 CG TYR R 7 7.377 -1.504 13.540 1.00 14.45 C +ATOM 323 CD1 TYR R 7 7.832 -0.677 12.522 1.00 14.80 C +ATOM 324 CD2 TYR R 7 8.271 -2.412 14.115 1.00 15.68 C +ATOM 325 CE1 TYR R 7 9.138 -0.784 12.026 1.00 14.33 C +ATOM 326 CE2 TYR R 7 9.562 -2.527 13.646 1.00 13.46 C +ATOM 327 CZ TYR R 7 9.995 -1.704 12.611 1.00 15.09 C +ATOM 328 OH TYR R 7 11.276 -1.844 12.151 1.00 14.39 O +ATOM 329 OXT TYR R 7 3.684 0.566 14.830 1.00 17.49 O +TER +HETATM 330 O HOH S 11 3.234 1.746 12.472 1.00 23.99 O +HETATM 331 O HOH S 12 1.437 -1.106 13.244 1.00 26.17 O +ATOM 332 N ASN V 6 -16.423 2.664 4.856 1.00 11.99 N +ATOM 333 CA ASN V 6 -15.106 2.310 4.318 1.00 12.30 C +ATOM 334 C ASN V 6 -14.083 2.761 5.324 1.00 13.40 C +ATOM 335 O ASN V 6 -13.718 3.943 5.374 1.00 13.92 O +ATOM 336 CB ASN V 6 -14.872 3.016 2.993 1.00 12.13 C +ATOM 337 CG ASN V 6 -15.976 2.735 2.003 1.00 12.77 C +ATOM 338 OD1 ASN V 6 -16.139 1.604 1.551 1.00 14.27 O +ATOM 339 ND2 ASN V 6 -16.742 3.747 1.679 1.00 10.07 N +ATOM 340 N TYR V 7 -13.645 1.817 6.147 1.00 14.70 N +ATOM 341 CA TYR V 7 -12.778 2.144 7.299 1.00 15.18 C +ATOM 342 C TYR V 7 -11.334 2.331 6.885 1.00 15.91 C +ATOM 343 O TYR V 7 -10.896 1.811 5.855 1.00 15.76 O +ATOM 344 CB TYR V 7 -12.876 1.065 8.369 1.00 15.35 C +ATOM 345 CG TYR V 7 -14.272 0.929 8.902 1.00 14.45 C +ATOM 346 CD1 TYR V 7 -14.727 1.756 9.920 1.00 14.80 C +ATOM 347 CD2 TYR V 7 -15.166 0.021 8.327 1.00 15.68 C +ATOM 348 CE1 TYR V 7 -16.033 1.649 10.416 1.00 14.33 C +ATOM 349 CE2 TYR V 7 -16.457 -0.094 8.796 1.00 13.46 C +ATOM 350 CZ TYR V 7 -16.890 0.729 9.831 1.00 15.09 C +ATOM 351 OH TYR V 7 -18.171 0.589 10.291 1.00 14.39 O +ATOM 352 OXT TYR V 7 -10.579 2.999 7.612 1.00 17.49 O +TER +HETATM 353 O HOH W 9 -11.506 1.858 3.216 1.00 19.71 O +HETATM 354 O HOH W 11 -10.129 4.179 9.970 1.00 23.99 O +HETATM 355 O HOH W 12 -8.332 1.327 9.198 1.00 26.17 O +ATOM 356 N GLY X 1 -12.928 2.179 -6.102 1.00 16.77 N +ATOM 357 CA GLY X 1 -12.885 1.774 -4.651 1.00 16.57 C +ATOM 358 C GLY X 1 -13.922 0.707 -4.419 1.00 16.16 C +ATOM 359 O GLY X 1 -14.414 0.088 -5.381 1.00 16.78 O +ATOM 360 N ASN X 2 -14.281 0.490 -3.155 1.00 15.02 N +ATOM 361 CA ASN X 2 -15.415 -0.395 -2.831 1.00 14.10 C +ATOM 362 C ASN X 2 -16.696 0.104 -3.427 1.00 13.13 C +ATOM 363 O ASN X 2 -16.959 1.309 -3.426 1.00 11.91 O +ATOM 364 CB ASN X 2 -15.591 -0.552 -1.341 1.00 15.38 C +ATOM 365 CG ASN X 2 -14.353 -1.091 -0.692 1.00 14.08 C +ATOM 366 OD1 ASN X 2 -13.912 -2.206 -1.016 1.00 17.46 O +ATOM 367 ND2 ASN X 2 -13.733 -0.278 0.169 1.00 11.72 N +TER +HETATM 368 O HOH Y 10 -10.651 -0.677 1.468 1.00 17.08 O +ATOM 369 N ASN Z 2 -14.281 5.356 -3.155 1.00 15.02 N +ATOM 370 CA ASN Z 2 -15.415 4.471 -2.831 1.00 14.10 C +ATOM 371 C ASN Z 2 -16.696 4.970 -3.427 1.00 13.13 C +ATOM 372 O ASN Z 2 -16.959 6.175 -3.426 1.00 11.91 O +ATOM 373 CB ASN Z 2 -15.591 4.314 -1.341 1.00 15.38 C +ATOM 374 CG ASN Z 2 -14.353 3.775 -0.692 1.00 14.08 C +ATOM 375 OD1 ASN Z 2 -13.912 2.660 -1.016 1.00 17.46 O +ATOM 376 ND2 ASN Z 2 -13.733 4.588 0.169 1.00 11.72 N +TER +HETATM 377 O HOH 0 10 -10.651 4.189 1.468 1.00 17.08 O +ATOM 378 N GLY 1 1 12.928 -0.254 6.102 1.00 16.77 N +ATOM 379 CA GLY 1 1 12.885 -0.659 4.651 1.00 16.57 C +ATOM 380 C GLY 1 1 13.922 -1.726 4.419 1.00 16.16 C +ATOM 381 O GLY 1 1 14.414 -2.345 5.381 1.00 16.78 O +TER +HETATM 382 O HOH 2 8 15.466 0.361 7.124 1.00 22.62 O +ATOM 383 N GLY 3 1 12.928 4.612 6.102 1.00 16.77 N +ATOM 384 CA GLY 3 1 12.885 4.207 4.651 1.00 16.57 C +ATOM 385 C GLY 3 1 13.922 3.140 4.419 1.00 16.16 C +ATOM 386 O GLY 3 1 14.414 2.521 5.381 1.00 16.78 O +ATOM 387 N ASN 3 2 14.281 2.923 3.155 1.00 15.02 N +ATOM 388 CA ASN 3 2 15.415 2.038 2.831 1.00 14.10 C +ATOM 389 C ASN 3 2 16.696 2.537 3.427 1.00 13.13 C +ATOM 390 O ASN 3 2 16.959 3.742 3.426 1.00 11.91 O +ATOM 391 CB ASN 3 2 15.591 1.881 1.341 1.00 15.38 C +ATOM 392 CG ASN 3 2 14.353 1.342 0.692 1.00 14.08 C +ATOM 393 OD1 ASN 3 2 13.912 0.227 1.016 1.00 17.46 O +ATOM 394 ND2 ASN 3 2 13.733 2.155 -0.169 1.00 11.72 N +TER +HETATM 395 O HOH 4 8 15.466 5.227 7.124 1.00 22.62 O +HETATM 396 O HOH 4 10 10.651 1.756 -1.468 1.00 17.08 O +HETATM 397 O HOH 8 11 3.234 -3.120 12.472 1.00 23.99 O +ATOM 398 N TYR 9 7 -13.645 6.683 6.147 1.00 14.70 N +ATOM 399 CA TYR 9 7 -12.778 7.010 7.299 1.00 15.18 C +ATOM 400 C TYR 9 7 -11.334 7.197 6.885 1.00 15.91 C +ATOM 401 O TYR 9 7 -10.896 6.677 5.855 1.00 15.76 O +ATOM 402 CB TYR 9 7 -12.876 5.931 8.369 1.00 15.35 C +ATOM 403 CG TYR 9 7 -14.272 5.795 8.902 1.00 14.45 C +ATOM 404 CD1 TYR 9 7 -14.727 6.622 9.920 1.00 14.80 C +ATOM 405 CD2 TYR 9 7 -15.166 4.887 8.327 1.00 15.68 C +ATOM 406 CE1 TYR 9 7 -16.033 6.515 10.416 1.00 14.33 C +ATOM 407 CE2 TYR 9 7 -16.457 4.772 8.796 1.00 13.46 C +ATOM 408 CZ TYR 9 7 -16.890 5.595 9.831 1.00 15.09 C +ATOM 409 OH TYR 9 7 -18.171 5.455 10.291 1.00 14.39 O +ATOM 410 OXT TYR 9 7 -10.579 7.865 7.612 1.00 17.49 O +TER +HETATM 411 O HOH a 9 -11.506 6.724 3.216 1.00 19.71 O +HETATM 412 O HOH a 12 -8.332 6.193 9.198 1.00 26.17 O +ATOM 413 N ASN f 2 14.281 7.789 3.155 1.00 15.02 N +ATOM 414 CA ASN f 2 15.415 6.904 2.831 1.00 14.10 C +ATOM 415 C ASN f 2 16.696 7.403 3.427 1.00 13.13 C +ATOM 416 O ASN f 2 16.959 8.608 3.426 1.00 11.91 O +ATOM 417 CB ASN f 2 15.591 6.747 1.341 1.00 15.38 C +ATOM 418 CG ASN f 2 14.353 6.208 0.692 1.00 14.08 C +ATOM 419 OD1 ASN f 2 13.912 5.093 1.016 1.00 17.46 O +ATOM 420 ND2 ASN f 2 13.733 7.021 -0.169 1.00 11.72 N +TER +ATOM 421 N TYR h 7 6.750 9.116 16.295 1.00 14.70 N +ATOM 422 CA TYR h 7 5.883 9.443 15.143 1.00 15.18 C +ATOM 423 C TYR h 7 4.439 9.630 15.557 1.00 15.91 C +ATOM 424 O TYR h 7 4.001 9.110 16.587 1.00 15.76 O +ATOM 425 CB TYR h 7 5.981 8.364 14.073 1.00 15.35 C +ATOM 426 CG TYR h 7 7.377 8.228 13.540 1.00 14.45 C +ATOM 427 CD1 TYR h 7 7.832 9.055 12.522 1.00 14.80 C +ATOM 428 CD2 TYR h 7 8.271 7.320 14.115 1.00 15.68 C +ATOM 429 CE1 TYR h 7 9.138 8.948 12.026 1.00 14.33 C +ATOM 430 CE2 TYR h 7 9.562 7.205 13.646 1.00 13.46 C +ATOM 431 CZ TYR h 7 9.995 8.028 12.611 1.00 15.09 C +ATOM 432 OH TYR h 7 11.276 7.888 12.151 1.00 14.39 O +ATOM 433 OXT TYR h 7 3.684 10.298 14.830 1.00 17.49 O +TER + +""" + +def exercise_01(): + + + pdb_inp = iotbx.pdb.input(source_info=None, lines=pdb_str) + m = mmtbx.model.manager(model_input = pdb_inp, log = null_out()) + p = m.get_default_pdb_interpretation_params() + p.pdb_interpretation.use_ncs_to_build_restraints = True + # p.pdb_interpretation.use_ncs_to_build_restraints = False + m.process(make_restraints=True, pdb_interpretation_params=p) + + +if(__name__ == "__main__"): + if libtbx.env.find_in_repositories(relative_path="chem_data") is None: + print("Skipping exercise_02(): chem_data directory not available") + else: + exercise_01() + print('OK') + diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index f34a0e4b90..1e72561d43 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -428,6 +428,8 @@ "$D/validation/regression/tst_rama_z_02.py", "$D/regression/pdb_interpretation/tst_edits.py", "$D/regression/pdb_interpretation/tst_edits_actions.py", + "$D/regression/pdb_interpretation/tst_using_ncs_1.py", + "$D/regression/pdb_interpretation/tst_using_ncs_2.py", "$D/regression/tst_add_arrows_on_plot.py", "$D/regression/model/tst_model.py", "$D/regression/tst_reduce_timeout.py", From 78b918af8c954ba32ef349aa545a00526f38a55d Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Tue, 23 Jul 2024 16:32:15 -0700 Subject: [PATCH 590/748] CI: use libcxx=17 for XFEL CI --- .azure-pipelines/xfel/unix-conda-build.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.azure-pipelines/xfel/unix-conda-build.yml b/.azure-pipelines/xfel/unix-conda-build.yml index 9eaeff62bd..313761f1fc 100644 --- a/.azure-pipelines/xfel/unix-conda-build.yml +++ b/.azure-pipelines/xfel/unix-conda-build.yml @@ -67,6 +67,13 @@ steps: displayName: Create conda environment condition: eq('${{ parameters.distribution }}', 'centos') +- script: | + set -xe + source $(Pipeline.Workspace)/miniforge/etc/profile.d/conda.sh + conda install -y -c conda-forge -n $(PYTHON_VERSION) libcxx=17 + displayName: Select libcxx on macOS + condition: eq(variables.OS, 'macos') + # build - script: | set -xe From b7650a87912914a48b190648f11451c4fdec8ec8 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Thu, 25 Jul 2024 16:45:54 -0700 Subject: [PATCH 591/748] If no rgs found, keep looking, chain might be split into 2 with TER card --- mmtbx/secondary_structure/proteins.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mmtbx/secondary_structure/proteins.py b/mmtbx/secondary_structure/proteins.py index 76ebeb2611..47388024bf 100644 --- a/mmtbx/secondary_structure/proteins.py +++ b/mmtbx/secondary_structure/proteins.py @@ -577,7 +577,8 @@ def _get_residue_groups_from_selection(pdb_hierarchy, bool_selection): for rg in chain.residue_groups(): if bool_selection[rg.atoms()[0].i_seq]: rgs.append(rg) - return rgs + if len(rgs)>0: + return rgs return rgs ######################################################################## From 555aee4fc405a59aea0406d0ff02d87fa849b6dd Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Mon, 29 Jul 2024 13:43:01 -0700 Subject: [PATCH 592/748] iotbx: fix typo --- iotbx/data_manager/ncs_spec.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iotbx/data_manager/ncs_spec.py b/iotbx/data_manager/ncs_spec.py index 15a9a0afcb..5ee31dd0cf 100644 --- a/iotbx/data_manager/ncs_spec.py +++ b/iotbx/data_manager/ncs_spec.py @@ -30,7 +30,7 @@ def get_default_ncs_spec_name(self): def remove_ncs_spec(self, filename): return self._remove(NcsSpecDataManager.datatype, filename) - def has_ncs_specs(self, expected_n=1, exact_count=False, raise_sorry=False): + def has_ncs_spec(self, expected_n=1, exact_count=False, raise_sorry=False): return self._has_data(NcsSpecDataManager.datatype, expected_n=expected_n, exact_count=exact_count, raise_sorry=raise_sorry) From 7143c7d26d1cd883f7285d8a486664aa97c5f917 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Mon, 29 Jul 2024 13:53:34 -0700 Subject: [PATCH 593/748] Revert "iotbx: fix typo" This reverts commit 555aee4fc405a59aea0406d0ff02d87fa849b6dd. --- iotbx/data_manager/ncs_spec.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iotbx/data_manager/ncs_spec.py b/iotbx/data_manager/ncs_spec.py index 5ee31dd0cf..15a9a0afcb 100644 --- a/iotbx/data_manager/ncs_spec.py +++ b/iotbx/data_manager/ncs_spec.py @@ -30,7 +30,7 @@ def get_default_ncs_spec_name(self): def remove_ncs_spec(self, filename): return self._remove(NcsSpecDataManager.datatype, filename) - def has_ncs_spec(self, expected_n=1, exact_count=False, raise_sorry=False): + def has_ncs_specs(self, expected_n=1, exact_count=False, raise_sorry=False): return self._has_data(NcsSpecDataManager.datatype, expected_n=expected_n, exact_count=exact_count, raise_sorry=raise_sorry) From 75df09c14c76f674d196e29ef39605872677ec35 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Mon, 29 Jul 2024 17:28:55 -0700 Subject: [PATCH 594/748] for bulk QMF of a model --- mmtbx/programs/quantum_interface.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mmtbx/programs/quantum_interface.py b/mmtbx/programs/quantum_interface.py index 2af392db65..af0eee8743 100644 --- a/mmtbx/programs/quantum_interface.py +++ b/mmtbx/programs/quantum_interface.py @@ -250,7 +250,7 @@ def qm_restraints_has_selection(params): return False return bc==len(bools) -def get_selection_from_user(hierarchy, include_amino_acids=None, log=None): +def get_selection_from_user(hierarchy, include_amino_acids=None, return_list=False, log=None): j=0 opts = [] if include_amino_acids is not None: @@ -285,6 +285,7 @@ def get_selection_from_user(hierarchy, include_amino_acids=None, log=None): opts.append(' or '.join(ts)) j+=1 print('\n\n', file=log) + if return_list: return opts for i, sel in enumerate(opts): print(' %2d : "%s"' % (i+1,sel), file=log) if len(opts)==1: @@ -777,8 +778,8 @@ def generate_metals(s): def iterate_NQH(self, nq_or_h, classify_nqh, add_nqh_H_atoms, generate_flipping, log=None): from mmtbx.geometry_restraints.quantum_interface import get_preamble if len(self.params.qi.qm_restraints)<1: - self.write_qmr_phil(iterate_NQH=True) - print('Restart command with PHIL file', file=self.logger) + pf = self.write_qmr_phil(iterate_NQH=True) + print('Restart command with PHIL file : %s' % pf, file=self.logger) return qm_work_dir = get_working_directory(self.data_manager.get_model(), self.params) nproc = self.params.qi.nproc From c6dfcd49f653e966a9fbf436bda69307e3842348 Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 30 Jul 2024 16:05:30 -0700 Subject: [PATCH 595/748] Factor out getting crystal_symmetry in model.py and allow call with just pdb_hierarchy; use hierarchy not pdb_input in validation --- iotbx/pdb/hierarchy.py | 48 ++++++++++++------------- mmtbx/model/model.py | 4 +-- mmtbx/validation/cablam.py | 3 +- mmtbx/validation/molprobity/__init__.py | 2 +- mmtbx/validation/mp_validate_bonds.py | 2 +- mmtbx/validation/rna_validate.py | 2 +- 6 files changed, 29 insertions(+), 32 deletions(-) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index fc68b79938..62386e8b9a 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -1003,17 +1003,15 @@ def as_model_manager(self, crystal_symmetry, values for xyz, occ, b, and crystal_symmetry are all rounded. ''' import mmtbx.model - if crystal_symmetry: # usual - mm = mmtbx.model.manager( + + # make up crystal_symmetry if not present + crystal_symmetry = self.generate_crystal_symmetry(crystal_symmetry) + + mm = mmtbx.model.manager( model_input = None, # REQUIRED pdb_hierarchy = self, crystal_symmetry = crystal_symmetry, ) - else: # usual, make a deep_copy and supply as_pdb_input: - mm = mmtbx.model.manager( - model_input = self.deep_copy().as_pdb_input(), - crystal_symmetry = crystal_symmetry, - ) mm.set_unit_cell_crystal_symmetry_and_shift_cart( unit_cell_crystal_symmetry = unit_cell_crystal_symmetry, shift_cart = shift_cart) @@ -1084,7 +1082,21 @@ def format_fasta(self, else: # usual return seq_fasta_lines + def generate_crystal_symmetry(self, crystal_symmetry): + cryst1_substitution_buffer_layer = None + if (crystal_symmetry is None): + crystal_symmetry = crystal.symmetry() + if (crystal_symmetry.unit_cell() is None): + crystal_symmetry = crystal_symmetry.customized_copy( + unit_cell=uctbx.non_crystallographic_unit_cell( + sites_cart=self.atoms().extract_xyz(), + buffer_layer=cryst1_substitution_buffer_layer)) + if (crystal_symmetry.space_group_info() is None): + crystal_symmetry = crystal_symmetry.cell_equivalent_p1() + return crystal_symmetry + def extract_xray_structure(self, crystal_symmetry=None, + enable_scattering_type_unknown = False, min_distance_sym_equiv=None): """ Generate the equivalent cctbx.xray.structure object. If the crystal @@ -1092,30 +1104,16 @@ def extract_xray_structure(self, crystal_symmetry=None, is usually best to keep the original xray structure object around, but this method is helpful in corner cases. """ - # if min_distance_sym_equiv is not None: # use it - # return self.as_pdb_input(crystal_symmetry).xray_structure_simple( - # min_distance_sym_equiv=min_distance_sym_equiv) - # else: # usual just use whatever is default in xray_structure_simple - # return self.as_pdb_input(crystal_symmetry).xray_structure_simple() - # # Abbreviated copy-paste from iotbx/pdb/__init__.py: def xray_structures_simple() # Better than getting iotbx.pdb.input from hierarchy.as_pdb_string() from cctbx import xray import scitbx.stl.set - cryst1_substitution_buffer_layer = None non_unit_occupancy_implies_min_distance_sym_equiv_zero = True if min_distance_sym_equiv is None: min_distance_sym_equiv = 0.5 - # - if (crystal_symmetry is None): - crystal_symmetry = crystal.symmetry() - if (crystal_symmetry.unit_cell() is None): - crystal_symmetry = crystal_symmetry.customized_copy( - unit_cell=uctbx.non_crystallographic_unit_cell( - sites_cart=self.atoms().extract_xyz(), - buffer_layer=cryst1_substitution_buffer_layer)) - if (crystal_symmetry.space_group_info() is None): - crystal_symmetry = crystal_symmetry.cell_equivalent_p1() + + # Make up crystal symmetry if not present + crystal_symmetry = self.generate_crystal_symmetry(crystal_symmetry) unit_cell = crystal_symmetry.unit_cell() scale_r = (0,0,0,0,0,0,0,0,0) scale_t = (0,0,0) @@ -1131,7 +1129,7 @@ def extract_xray_structure(self, crystal_symmetry=None, False, # unit_cube_pseudo_crystal, False, # fractional_coordinates, False, # scattering_type_exact, - False, # enable_scattering_type_unknown, + enable_scattering_type_unknown, self.atoms_with_labels(), mi, scitbx.stl.set.stl_string(atom_names_scattering_type_const), diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index 1da853d3eb..a6674a5c03 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -191,7 +191,7 @@ class manager(object): """ def __init__(self, - model_input, + model_input = None, pdb_hierarchy = None, crystal_symmetry = None, restraint_objects = None, @@ -205,7 +205,7 @@ def __init__(self, if(model_input is not None): assert pdb_hierarchy is None if(pdb_hierarchy is not None): assert model_input is None - assert crystal_symmetry is not None + # assert crystal_symmetry is not None # Internals self._processed = False self._xray_structure = None diff --git a/mmtbx/validation/cablam.py b/mmtbx/validation/cablam.py index 87df90aff8..29dc2c3264 100644 --- a/mmtbx/validation/cablam.py +++ b/mmtbx/validation/cablam.py @@ -1462,11 +1462,10 @@ def as_full_kinemage(self,pdbid=''): sites_cart=self.pdb_hierarchy.atoms().extract_xyz() mon_lib_srv = monomer_library.server.server() ener_lib = monomer_library.server.ener_lib() - pdb_io=self.pdb_hierarchy.as_pdb_input() processed_pdb_file = pdb_interpretation.process( mon_lib_srv=mon_lib_srv, ener_lib=ener_lib, - pdb_inp=pdb_io, + pdb_hierarchy=self.pdb_hierarchy, #params=work_params.kinemage.pdb_interpretation, substitute_non_crystallographic_unit_cell_if_necessary=True) geometry = processed_pdb_file.geometry_restraints_manager() diff --git a/mmtbx/validation/molprobity/__init__.py b/mmtbx/validation/molprobity/__init__.py index 78e8b3d02e..97782df26c 100644 --- a/mmtbx/validation/molprobity/__init__.py +++ b/mmtbx/validation/molprobity/__init__.py @@ -182,7 +182,7 @@ def __init__(self, if(self.model is None and pdb_hierarchy is not None): import mmtbx.model self.model = mmtbx.model.manager( - model_input = pdb_hierarchy.as_pdb_input()) + pdb_hierarchy = pdb_hierarchy) self.model.process(make_restraints=True) pdb_hierarchy = self.model.get_hierarchy() diff --git a/mmtbx/validation/mp_validate_bonds.py b/mmtbx/validation/mp_validate_bonds.py index aefcb491f1..0400066f51 100644 --- a/mmtbx/validation/mp_validate_bonds.py +++ b/mmtbx/validation/mp_validate_bonds.py @@ -346,7 +346,7 @@ def __init__(self, processed_pdb_file = pdb_interpretation.process( mon_lib_srv=mon_lib_srv, ener_lib=ener_lib, - pdb_inp=pdb_hierarchy.as_pdb_input(), + pdb_hierarchy=pdb_hierarchy, substitute_non_crystallographic_unit_cell_if_necessary=True) geometry_restraints_manager = \ processed_pdb_file.geometry_restraints_manager() diff --git a/mmtbx/validation/rna_validate.py b/mmtbx/validation/rna_validate.py index 7c47c74915..619e29bc1a 100644 --- a/mmtbx/validation/rna_validate.py +++ b/mmtbx/validation/rna_validate.py @@ -487,7 +487,7 @@ def __init__(self, processed_pdb_file = pdb_interpretation.process( mon_lib_srv=mon_lib_srv, ener_lib=ener_lib, - pdb_inp=pdb_hierarchy.as_pdb_input(), + pdb_hierarchy=pdb_hierarchy, substitute_non_crystallographic_unit_cell_if_necessary=True) geometry_restraints_manager = \ processed_pdb_file.geometry_restraints_manager() From 0adfafca75cfb4457fd75ecc3e341e5ea95e630d Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 30 Jul 2024 16:40:58 -0700 Subject: [PATCH 596/748] update --- iotbx/pdb/modified_aa_names.h | 9 ++++++++- iotbx/pdb/modified_aa_names.py | 8 +++++++- iotbx/pdb/modified_rna_dna_names.h | 2 +- iotbx/pdb/modified_rna_dna_names.py | 2 +- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/iotbx/pdb/modified_aa_names.h b/iotbx/pdb/modified_aa_names.h index 458e1a93c7..18580be38c 100644 --- a/iotbx/pdb/modified_aa_names.h +++ b/iotbx/pdb/modified_aa_names.h @@ -5,7 +5,7 @@ This file is generated by the following procedure: phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Mon Jun 24 07:02:52 2024 +The date of file generation: Tue Jul 30 14:45:49 2024 */ #include @@ -1048,6 +1048,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "Y28", "YCP", "YEN", + "YFZ", "YNM", "YYA", "Z50", @@ -1102,6 +1103,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "7OZ", "7VN", "9WV", + "A1ALE", "A1H5W", "AA3", "AA4", @@ -1168,6 +1170,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "X5P", "XW1", "XYC", + "YFQ", "Z01", "ZTK", "ZZJ", @@ -1180,6 +1183,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "4J5", "73N", "9NR", + "A1LTQ", "AAR", "ACL", "AGM", @@ -1606,6 +1610,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "9TU", "9TX", "9U0", + "A1D5B", "A1LWV", "ALY", "API", @@ -1824,6 +1829,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "4N9", "6Y9", "8LJ", + "A1D5E", "DPL", "DYJ", "E0Y", @@ -2150,6 +2156,7 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "WVL", "X60", "ZQN", + "YF5", // parent is YFZ 0 }; diff --git a/iotbx/pdb/modified_aa_names.py b/iotbx/pdb/modified_aa_names.py index 3e26067704..d5175e39a2 100644 --- a/iotbx/pdb/modified_aa_names.py +++ b/iotbx/pdb/modified_aa_names.py @@ -7,7 +7,7 @@ phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Mon Jun 24 07:02:52 2024 +The date of file generation: Tue Jul 30 14:45:49 2024 """ from __future__ import absolute_import, division, print_function @@ -1046,6 +1046,7 @@ "Y28" : "?", "YCP" : "?", "YEN" : "?", + "YFZ" : "?", "YNM" : "?", "YYA" : "?", "Z50" : "?", @@ -1098,6 +1099,7 @@ "7OZ" : "A", "7VN" : "A", "9WV" : "A", + "A1ALE" : "A", "A1H5W" : "A", "AA3" : "A", "AA4" : "A", @@ -1164,6 +1166,7 @@ "X5P" : "A", "XW1" : "A", "XYC" : "A", + "YFQ" : "A", "Z01" : "A", "ZTK" : "A", "ZZJ" : "A", @@ -1176,6 +1179,7 @@ "4J5" : "R", "73N" : "R", "9NR" : "R", + "A1LTQ" : "R", "AAR" : "R", "ACL" : "R", "AGM" : "R", @@ -1599,6 +1603,7 @@ "9TU" : "K", "9TX" : "K", "9U0" : "K", + "A1D5B" : "K", "A1LWV" : "K", "ALY" : "K", "API" : "K", @@ -1817,6 +1822,7 @@ "4N9" : "P", "6Y9" : "P", "8LJ" : "P", + "A1D5E" : "P", "DPL" : "P", "DYJ" : "P", "E0Y" : "P", diff --git a/iotbx/pdb/modified_rna_dna_names.h b/iotbx/pdb/modified_rna_dna_names.h index 52f833ffea..5de48746c1 100644 --- a/iotbx/pdb/modified_rna_dna_names.h +++ b/iotbx/pdb/modified_rna_dna_names.h @@ -5,7 +5,7 @@ This file is generated by the following procedure: phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Mon Jun 24 07:02:53 2024 +The date of file generation: Tue Jul 30 14:45:49 2024 */ #include diff --git a/iotbx/pdb/modified_rna_dna_names.py b/iotbx/pdb/modified_rna_dna_names.py index 00d84be684..fab3acac13 100644 --- a/iotbx/pdb/modified_rna_dna_names.py +++ b/iotbx/pdb/modified_rna_dna_names.py @@ -7,7 +7,7 @@ phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Mon Jun 24 07:02:53 2024 +The date of file generation: Tue Jul 30 14:45:49 2024 """ from __future__ import absolute_import, division, print_function From 86b14eb314b17c73ddc74622d85ae562d1cfc78f Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 30 Jul 2024 17:40:52 -0700 Subject: [PATCH 597/748] parameter to avoid histogram calcualtion and show. --- mmtbx/monomer_library/pdb_interpretation.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index bc078ad186..6978eed650 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -218,6 +218,9 @@ def __init__(self, residue_name, atom_name, atom_element): use_ncs_to_build_restraints = False .type = bool .short_caption = Look for NCS and use it to speed up building restraints + show_restraints_histograms = True + .type = bool + .short_caption = Show histograms. Disable for speed. flip_symmetric_amino_acids = True .type = bool .short_caption = Flip symmetric amino acids to conform to IUPAC convention @@ -6114,7 +6117,7 @@ def geometry_restraints_manager(self, t3=time.time() print(" Total time for adding SS restraints: %.2f" % (t3-t1), file=self.log) print(file=self.log) - if (self.log is not None): + if self.log is not None and self.all_chain_proxies.params.show_restraints_histograms: # if False: print(" Time building geometry restraints manager: %.2f seconds" % ( self.all_chain_proxies.time_building_geometry_restraints_manager), file=self.log) From a59dab9e529e6113d6526c626b67616ab7f7cc7a Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Wed, 31 Jul 2024 15:37:15 -0700 Subject: [PATCH 598/748] pdb_int speedup: 40% faster process nonbonded for links in linkin_mixins. --- cctbx/geometry_restraints/__init__.py | 23 +++++++++++++++++++++++ mmtbx/monomer_library/linking_mixins.py | 18 ++++++++++-------- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/cctbx/geometry_restraints/__init__.py b/cctbx/geometry_restraints/__init__.py index b58f72a25f..0bb05e9215 100644 --- a/cctbx/geometry_restraints/__init__.py +++ b/cctbx/geometry_restraints/__init__.py @@ -1192,6 +1192,29 @@ def get_sorted_i_proxies(self, i_proxies_sorted = i_proxies_sorted[:max_items] return i_proxies_sorted + def sorted_value_proxies_generator(self, + by_value, + sites_cart): + assert by_value in ["delta"] + deltas = nonbonded_deltas(sites_cart=sites_cart, sorted_asu_proxies=self) + if (deltas.size() == 0): return + i_proxies_sorted = flex.sort_permutation(data=deltas) + n_simple = self.simple.size() + asu_mappings = self.asu_mappings() + for i_proxy in i_proxies_sorted: + if (i_proxy < n_simple): + yield ( + deltas[i_proxy], + self.simple[i_proxy], + None, + "") + else: + yield ( + deltas[i_proxy], + self.asu[i_proxy-n_simple], + asu_mappings.get_rt_mx_ji(pair=self.asu[i_proxy-n_simple]), + " sym.op.") + def get_sorted_proxies(self, by_value, sites_cart, diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index 77f059ccc0..89c60bbc01 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -391,14 +391,16 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., def _nonbonded_pair_generator_geometry_restraints_sort( nonbonded_proxies, max_bonded_cutoff=3.): - rc = nonbonded_proxies.get_sorted(by_value="delta", - sites_cart=sites_cart, - include_proxy=True, - ) - if rc is None: return - rc, junk = rc + rc = nonbonded_proxies.sorted_value_proxies_generator(by_value="delta", + sites_cart=sites_cart) for item in rc: - yield item + distance, proxy, rt_mx_ji, sym_op = item + try: + i_seq, j_seq = proxy.i_seqs + except AttributeError: + i_seq, j_seq = proxy.i_seq, proxy.j_seq + yield i_seq, j_seq, distance, sym_op, rt_mx_ji, proxy + # if(log is not None): print(""" @@ -448,7 +450,7 @@ def _nonbonded_pair_generator_geometry_restraints_sort( max_bonded_cutoff=max_bonded_cutoff, ) ): - labels, i_seq, j_seq, distance, vdw_distance, sym_op, rt_mx_ji, proxy = item + i_seq, j_seq, distance, sym_op, rt_mx_ji, proxy = item # # include & exclude selection # From 8d1a1a752b1718a47c209a7bdb3ab11267ae9aad Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Wed, 31 Jul 2024 17:31:44 -0700 Subject: [PATCH 599/748] Add cutoff to generator, switch the rest linking to use it --- cctbx/geometry_restraints/__init__.py | 24 ++++++++++++++----- mmtbx/conformation_dependent_library/mcl.py | 4 ---- .../mcl_sf4_coordination.py | 20 ++++------------ .../metal_coordination_library.py | 18 ++++---------- mmtbx/monomer_library/linking_mixins.py | 22 ++++------------- 5 files changed, 32 insertions(+), 56 deletions(-) diff --git a/cctbx/geometry_restraints/__init__.py b/cctbx/geometry_restraints/__init__.py index 0bb05e9215..d335da3c51 100644 --- a/cctbx/geometry_restraints/__init__.py +++ b/cctbx/geometry_restraints/__init__.py @@ -1194,26 +1194,38 @@ def get_sorted_i_proxies(self, def sorted_value_proxies_generator(self, by_value, - sites_cart): + sites_cart, + cutoff = 100): assert by_value in ["delta"] deltas = nonbonded_deltas(sites_cart=sites_cart, sorted_asu_proxies=self) if (deltas.size() == 0): return i_proxies_sorted = flex.sort_permutation(data=deltas) + n_proxies = deltas.size() n_simple = self.simple.size() asu_mappings = self.asu_mappings() - for i_proxy in i_proxies_sorted: + i = 0 + while i < n_proxies and deltas[i_proxies_sorted[i]] < cutoff: + i_proxy = i_proxies_sorted[i] if (i_proxy < n_simple): + i_seq, j_seq = self.simple[i_proxy].i_seqs yield ( + i_seq, + j_seq, deltas[i_proxy], - self.simple[i_proxy], None, - "") + "", + self.simple[i_proxy], + ) else: + i_seq, j_seq = self.asu[i_proxy-n_simple].i_seq, self.asu[i_proxy-n_simple].j_seq yield ( + i_seq, + j_seq, deltas[i_proxy], - self.asu[i_proxy-n_simple], asu_mappings.get_rt_mx_ji(pair=self.asu[i_proxy-n_simple]), - " sym.op.") + " sym.op.", + self.asu[i_proxy-n_simple]) + i += 1 def get_sorted_proxies(self, by_value, diff --git a/mmtbx/conformation_dependent_library/mcl.py b/mmtbx/conformation_dependent_library/mcl.py index 028f063c80..816559d171 100644 --- a/mmtbx/conformation_dependent_library/mcl.py +++ b/mmtbx/conformation_dependent_library/mcl.py @@ -77,15 +77,11 @@ def _atom_id(a, show_i_seq=False): sites_c = pdb_hierarchy.atoms().extract_xyz() nb_proxies = grm.pair_proxies( sites_cart=sites_c).nonbonded_proxies - sorted_nb_pr_result = nb_proxies.get_sorted( - by_value="delta", - sites_cart=sites_c) for label, get_coordination, get_all_proxies in hooks: rc = get_coordination( pdb_hierarchy=pdb_hierarchy, nonbonded_proxies=nb_proxies, - sorted_nb_proxies_res=sorted_nb_pr_result, verbose=verbose, ) bproxies, aproxies = get_all_proxies(rc) diff --git a/mmtbx/conformation_dependent_library/mcl_sf4_coordination.py b/mmtbx/conformation_dependent_library/mcl_sf4_coordination.py index 6a10211484..36932f674d 100644 --- a/mmtbx/conformation_dependent_library/mcl_sf4_coordination.py +++ b/mmtbx/conformation_dependent_library/mcl_sf4_coordination.py @@ -122,21 +122,11 @@ def get_sulfur_iron_cluster_coordination(pdb_hierarchy, done_aa = [] atoms = pdb_hierarchy.atoms() sites_cart = atoms.extract_xyz() - get_sorted_result = sorted_nb_proxies_res - if sorted_nb_proxies_res is None: - get_sorted_result = nonbonded_proxies.get_sorted( - by_value="delta", - sites_cart=sites_cart) - if get_sorted_result is None: - return None - sorted_nonb, n_not_shown = get_sorted_result - - # Get potential hbonds - n_nonb = len(sorted_nonb) - i = 0 - while i < n_nonb and sorted_nonb[i][3] < coordination_distance_cutoff: - (labels, i_seq, j_seq, dist, vdw_distance, sym_op_j, rt_mx) = sorted_nonb[i] - i += 1 + for item in nonbonded_proxies.sorted_value_proxies_generator( + by_value="delta", + sites_cart=sites_cart, + cutoff=coordination_distance_cutoff): + i_seq, j_seq, dist, sym_op_j, rt_mx, proxy = item a1 = atoms[i_seq] ag1 = a1.parent() a2 = atoms[j_seq] diff --git a/mmtbx/conformation_dependent_library/metal_coordination_library.py b/mmtbx/conformation_dependent_library/metal_coordination_library.py index 399870f1fc..cb7c80eaf5 100644 --- a/mmtbx/conformation_dependent_library/metal_coordination_library.py +++ b/mmtbx/conformation_dependent_library/metal_coordination_library.py @@ -97,18 +97,11 @@ def is_residue_already_linked_to_metal(linked, atom): mbonds = {} atoms = pdb_hierarchy.atoms() sites_cart = atoms.extract_xyz() - get_sorted_result = sorted_nb_proxies_res - if get_sorted_result is None: - get_sorted_result = nonbonded_proxies.get_sorted( - by_value="delta", - sites_cart=sites_cart) - # its never None, it is always a tuple ([], int) - if get_sorted_result is None: return mbonds - sorted_nonb, n_not_shown = get_sorted_result - n_nonb = len(sorted_nonb) - i = 0 - while i < n_nonb and sorted_nonb[i][3] < hbond_distance_cutoff: - (labels, i_seq, j_seq, dist, vdw_distance, sym_op_j, rt_mx) = sorted_nonb[i] + for item in nonbonded_proxies.sorted_value_proxies_generator( + by_value="delta", + sites_cart=sites_cart, + cutoff=hbond_distance_cutoff): + i_seq, j_seq, dist, sym_op_j, rt_mx, proxy = item a1 = atoms[i_seq] ag1 = a1.parent() a2 = atoms[j_seq] @@ -134,7 +127,6 @@ def is_residue_already_linked_to_metal(linked, atom): sub = mbonds[metal.i_seq]['others'] if other not in sub: sub.append(other) - i += 1 pairs = [] if verbose: diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index 89c60bbc01..6578aa448a 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -388,18 +388,6 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., shell_asu_tables=[pair_asu_table]) return nonbonded_proxies, sites_cart, pair_asu_table, asu_mappings, i_seqs # - def _nonbonded_pair_generator_geometry_restraints_sort( - nonbonded_proxies, - max_bonded_cutoff=3.): - rc = nonbonded_proxies.sorted_value_proxies_generator(by_value="delta", - sites_cart=sites_cart) - for item in rc: - distance, proxy, rt_mx_ji, sym_op = item - try: - i_seq, j_seq = proxy.i_seqs - except AttributeError: - i_seq, j_seq = proxy.i_seq, proxy.j_seq - yield i_seq, j_seq, distance, sym_op, rt_mx_ji, proxy # if(log is not None): @@ -444,12 +432,10 @@ def _nonbonded_pair_generator_geometry_restraints_sort( _nonbonded_pair_objects(max_bonded_cutoff=max_bonded_cutoff, ) initial_pair_asu_table_table = bond_asu_table.table().deep_copy() - for ii, item in enumerate( - _nonbonded_pair_generator_geometry_restraints_sort( - nonbonded_proxies=nonbonded_proxies, - max_bonded_cutoff=max_bonded_cutoff, - ) - ): + for ii, item in enumerate(nonbonded_proxies.sorted_value_proxies_generator( + by_value="delta", + sites_cart=sites_cart, + cutoff=max_bonded_cutoff)): i_seq, j_seq, distance, sym_op, rt_mx_ji, proxy = item # # include & exclude selection From 175e8ecf3d00d23f03233174631af48258562a9c Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 31 Jul 2024 14:21:18 -0700 Subject: [PATCH 600/748] iotbx: use scoring to remove possible conflicts in creating fmodel in DataManager --- iotbx/data_manager/miller_array.py | 48 ++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/iotbx/data_manager/miller_array.py b/iotbx/data_manager/miller_array.py index 31c9e6064a..781424b5a9 100644 --- a/iotbx/data_manager/miller_array.py +++ b/iotbx/data_manager/miller_array.py @@ -11,7 +11,8 @@ from cctbx import crystal from iotbx.data_manager import DataManagerBase -from iotbx.reflection_file_utils import label_table, reflection_file_server +from iotbx.reflection_file_utils import label_table, get_experimental_phases_scores, \ + get_phase_scores, get_r_free_flags_scores, reflection_file_server from libtbx import Auto from libtbx.utils import Sorry @@ -329,6 +330,7 @@ def get_reflection_file_server(self, filenames=None, labels=None, if len(filenames) > len(labels): labels += [None]*(len(filenames) - len(labels)) assert len(filenames) == len(labels) + # determine types of selected arrays across all files and decide # whether to ignore intensity arrays that are not explicitly selected selected_types = set() @@ -340,10 +342,11 @@ def get_reflection_file_server(self, filenames=None, labels=None, selected_types.add(self.get_miller_array_array_types(filename)[label]) if 'amplitude' in selected_types and ignore_intensities_if_amplitudes_present: selected_types.add('intensity') + # check for user selected labels selected_labels = deepcopy(labels) for i, filename in enumerate(filenames): - current_selected_labels = self.get_miller_array_user_selected_labels(filename) + current_selected_labels = deepcopy(self.get_miller_array_user_selected_labels(filename)) current_all_labels = labels[i] if labels[i] is None: current_all_labels = self.get_miller_array_all_labels(filename) @@ -359,6 +362,7 @@ def get_reflection_file_server(self, filenames=None, labels=None, current_selected_labels.append(label) selected_labels[i] = current_selected_labels labels = selected_labels + # force crystal symmetry if a crystal symmetry is provided if crystal_symmetry is not None and force_symmetry is None: force_symmetry = True @@ -382,6 +386,12 @@ def get_reflection_file_server(self, filenames=None, labels=None, # crystal_symmetry and force_symmetry should be set by now miller_arrays = [] + miller_array_labels = [] # filename:array_label + def get_array_label(filename, array): + ''' + Convenience function for creating filename:array_label label + ''' + return filename + ':' + array.info().label_string() merge_equivalents = 'miller_array_skip_merge' not in self.custom_options for filename, file_labels in zip(filenames, labels): file_arrays = self.get_miller_array(filename).\ @@ -398,6 +408,40 @@ def get_reflection_file_server(self, filenames=None, labels=None, if (array_type is None or array_type in self.get_miller_array_type(filename, label_name)): miller_arrays.append(miller_array) + miller_array_labels.append(get_array_label(filename, miller_array)) + + # final check of selected labels with scores + problem_arrays = set() # arrays with the same score as selected arrays + # ------------------------------------------------------------------------- + def filter_arrays_by_scores(filename, arrays, test_scores): + ''' + Convenience function for using scores to select arrays for removal + ''' + remove_set = set() + for selected_array in arrays: + selected_array_label = get_array_label(filename, selected_array) + score = score_dict[selected_array_label] + if score > 0 and test_scores.count(score) > 1: + for array, array_label in zip(miller_arrays, miller_array_labels): + if score_dict[array_label] == score and array_label != selected_array_label: + remove_set.add(array) + return remove_set + # ------------------------------------------------------------------------- + for scores in [ + get_experimental_phases_scores(miller_arrays, False), + get_phase_scores(miller_arrays), + get_r_free_flags_scores(miller_arrays, None).scores, + ]: + score_dict = {miller_array_labels[i]:scores[i] for i in range(len(miller_arrays))} + for filename in filenames: + selected_arrays = self.get_miller_arrays( + labels=self.get_miller_array_user_selected_labels(filename=filename), + filename=filename) + problem_arrays.update(filter_arrays_by_scores(filename, selected_arrays, scores)) + new_arrays = [ma for ma in miller_arrays if ma not in problem_arrays] + + miller_arrays = new_arrays + file_server = reflection_file_server( crystal_symmetry=crystal_symmetry, force_symmetry=force_symmetry, From 47cb6c2551ab91061a14309d46cf63b844181d32 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Thu, 1 Aug 2024 06:42:29 -0700 Subject: [PATCH 601/748] iotbx: only use scoring if score is available --- iotbx/data_manager/miller_array.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/iotbx/data_manager/miller_array.py b/iotbx/data_manager/miller_array.py index 781424b5a9..d99e5122dc 100644 --- a/iotbx/data_manager/miller_array.py +++ b/iotbx/data_manager/miller_array.py @@ -420,11 +420,12 @@ def filter_arrays_by_scores(filename, arrays, test_scores): remove_set = set() for selected_array in arrays: selected_array_label = get_array_label(filename, selected_array) - score = score_dict[selected_array_label] - if score > 0 and test_scores.count(score) > 1: - for array, array_label in zip(miller_arrays, miller_array_labels): - if score_dict[array_label] == score and array_label != selected_array_label: - remove_set.add(array) + if selected_array_label in score_dict: + score = score_dict[selected_array_label] + if score > 0 and test_scores.count(score) > 1: + for array, array_label in zip(miller_arrays, miller_array_labels): + if score_dict[array_label] == score and array_label != selected_array_label: + remove_set.add(array) return remove_set # ------------------------------------------------------------------------- for scores in [ From 9eed7fa290a73b3771d3b65a05d952cc79366b1c Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 1 Aug 2024 09:23:38 -0700 Subject: [PATCH 602/748] Catch None --- iotbx/map_model_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iotbx/map_model_manager.py b/iotbx/map_model_manager.py index 4f3310ff57..dd25b71059 100644 --- a/iotbx/map_model_manager.py +++ b/iotbx/map_model_manager.py @@ -6278,7 +6278,7 @@ def _average_scale_factor_info_over_xyz(self, scale_factor_info): getattr(scaling_group_info.overall_si,key)) - if scaling_group_info_list: + if scaling_group_info_list and average_scaling_group_info.scaling_info_list: for key in ('target_scale_factors','cc_list','rms_fo_list'): for si in average_scaling_group_info.scaling_info_list: setattr(si,key, getattr(si,key)/max(1,n_used)) From 56823537cced0004a26e262013c15af0b769772e Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 1 Aug 2024 12:12:05 -0700 Subject: [PATCH 603/748] Remove as_pdb_input() completely --- iotbx/pdb/hierarchy.py | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index 62386e8b9a..cfe16223b7 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -950,38 +950,6 @@ def as_pdb_string(self, return cstringio return cstringio.getvalue() -# MARKED_FOR_DELETION_OLEG -# REASON: This is not equivalent conversion. Hierarchy does not have a lot -# of information pdb_input and cif_input should have. Therefore this -# function should not be used at all to avoid confusion and having crippled -# input objects. Moreover, the use of mmtbx.model should eliminate the -# need in this tranformation. -# Currently used exclusively in Tom's code. - - def as_pdb_input(self, crystal_symmetry=None, - segid_as_auth_segid = True): - """ - Generate corresponding pdb.input object. - Note that this uses a text representation of the hierarchy so that - values for xyz, occ, b, and crystal_symmetry are all rounded. - """ - import iotbx.pdb - if self.fits_in_pdb_format(): - h_str = self.as_pdb_string(crystal_symmetry=crystal_symmetry) - inp = iotbx.pdb.input( - source_info="pdb_hierarchy", - lines=flex.split_lines(h_str)) - else: - h_str = self.deep_copy().as_mmcif_string( - segid_as_auth_segid=segid_as_auth_segid, - crystal_symmetry=crystal_symmetry) # deep_copy needed to preserve parents - inp = iotbx.pdb.mmcif.cif_input( - source_info="pdb_hierarchy", - lines=flex.split_lines(h_str)) - return inp - -# END_MARKED_FOR_DELETION_OLEG - def as_list_of_residue_names(self): sequence=[] for model in self.models(): From 532c1f4b7afdbb55d606f6fe9e89d7153dbcef49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Tcho=C5=84?= Date: Thu, 1 Aug 2024 19:06:50 -0600 Subject: [PATCH 604/748] Replace `dict` with `Counter` in the postrefine worker (#1002) * Add `postrefinement.intensity_extrema_iqr_distance_threshold` phil par * experiments_rejected_by_reason: dict -> Counter saves 15 lines of code * correction: dict -> Counter saves 18 lines of code, not 15 * Add preliminary version of `IntensityExtrema` handler: will work @ end * Sanitize expts and refls AFTER initial exception catching * Fix typo in `mpi_helper.count` * Change import of `intensity_sanitizer` from relative to absolute * Fix mistake in phil helpstring * Default `postrefinement.intensity_extrema_iqr_dist_threshold`:100->1000 * Add clutter to `intensity_sanitizer.py` * Implement `libtbx.mpi4py.mpiEmulator.allgather` method * Remove all functional changes to the postrefinement worker --- libtbx/mpi4py.py | 2 ++ xfel/merging/application/mpi_helper.py | 2 +- .../postrefine/postrefinement_rs.py | 27 ++++--------------- .../postrefine/postrefinement_rs2.py | 27 ++++--------------- 4 files changed, 13 insertions(+), 45 deletions(-) diff --git a/libtbx/mpi4py.py b/libtbx/mpi4py.py index edb047ff73..da39bd9834 100644 --- a/libtbx/mpi4py.py +++ b/libtbx/mpi4py.py @@ -54,6 +54,8 @@ def Gatherv(self, sendbuf, recvbuf, root=0): for item, count in zip(sendbuf, counts): rbuff[counter:counter+count] = item counter += count + def allgather(self, sendobj): + return [sendobj] def Abort(self,errorcode=0): import sys sys.exit() diff --git a/xfel/merging/application/mpi_helper.py b/xfel/merging/application/mpi_helper.py index c8302dd982..215a8d0260 100644 --- a/xfel/merging/application/mpi_helper.py +++ b/xfel/merging/application/mpi_helper.py @@ -72,7 +72,7 @@ def count(self, data, root=0): Return total `Counter` of occurrences of each element in data across ranks. Example: (a1, a1, a2) + (a1, a2, a3) = {a1: 3, a2: 2, a1: 1} """ - counters = self.comm.gather(Counter(data), rank=root) + counters = self.comm.gather(Counter(data), root=root) return sum(counters, Counter()) if self.rank == root else None def sum(self, data, root=0): diff --git a/xfel/merging/application/postrefine/postrefinement_rs.py b/xfel/merging/application/postrefine/postrefinement_rs.py index 59aec9bca7..d7dc97f8ba 100644 --- a/xfel/merging/application/postrefine/postrefinement_rs.py +++ b/xfel/merging/application/postrefine/postrefinement_rs.py @@ -2,6 +2,7 @@ import six from six.moves import range from six.moves import cStringIO as StringIO +from collections import Counter import math from xfel.merging.application.worker import worker from libtbx import adopt_init_args, group_args @@ -46,7 +47,7 @@ def run(self, experiments, reflections): new_experiments = ExperimentList() new_reflections = flex.reflection_table() - experiments_rejected_by_reason = {} # reason:how_many_rejected + experiments_rejected_by_reason = Counter() # reason:how_many_rejected for expt_id, experiment in enumerate(experiments): @@ -191,10 +192,7 @@ def run(self, experiments, reflections): reason = repr(e) if not reason: reason = "Unknown error" - if not reason in experiments_rejected_by_reason: - experiments_rejected_by_reason[reason] = 1 - else: - experiments_rejected_by_reason[reason] += 1 + experiments_rejected_by_reason[reason] += 1 if not error_detected: new_experiments.append(experiment) @@ -228,27 +226,12 @@ def run(self, experiments, reflections): self.logger.log("Experiments rejected by post-refinement: %d"%experiments_rejected_by_postrefinement) self.logger.log("Reflections rejected by post-refinement: %d"%reflections_rejected_by_postrefinement) - all_reasons = [] for reason, count in six.iteritems(experiments_rejected_by_reason): self.logger.log("Experiments rejected due to %s: %d"%(reason,count)) - all_reasons.append(reason) - - comm = self.mpi_helper.comm - MPI = self.mpi_helper.MPI - - # Collect all rejection reasons from all ranks. Use allreduce to let each rank have all reasons. - all_reasons = comm.allreduce(all_reasons, MPI.SUM) - all_reasons = set(all_reasons) # Now that each rank has all reasons from all ranks, we can treat the reasons in a uniform way. - total_experiments_rejected_by_reason = {} - for reason in all_reasons: - rejected_experiment_count = 0 - if reason in experiments_rejected_by_reason: - rejected_experiment_count = experiments_rejected_by_reason[reason] - total_experiments_rejected_by_reason[reason] = comm.reduce(rejected_experiment_count, MPI.SUM, 0) - - total_accepted_experiment_count = comm.reduce(len(new_experiments), MPI.SUM, 0) + total_experiments_rejected_by_reason = self.mpi_helper.count(experiments_rejected_by_reason) + total_accepted_experiment_count = self.mpi_helper.sum(len(new_experiments)) # how many reflections have we rejected due to post-refinement? rejected_reflections = len(reflections) - len(new_reflections); diff --git a/xfel/merging/application/postrefine/postrefinement_rs2.py b/xfel/merging/application/postrefine/postrefinement_rs2.py index e431d413b8..d9531d7c43 100644 --- a/xfel/merging/application/postrefine/postrefinement_rs2.py +++ b/xfel/merging/application/postrefine/postrefinement_rs2.py @@ -2,6 +2,7 @@ import six from six.moves import range from six.moves import cStringIO as StringIO +from collections import Counter import math from libtbx import adopt_init_args from dials.array_family import flex @@ -56,7 +57,7 @@ def run(self, experiments, reflections): new_experiments = ExperimentList() new_reflections = flex.reflection_table() - experiments_rejected_by_reason = {} # reason:how_many_rejected + experiments_rejected_by_reason = Counter() # reason:how_many_rejected for expt_id, experiment in enumerate(experiments): @@ -192,10 +193,7 @@ def run(self, experiments, reflections): reason = repr(e) if not reason: reason = "Unknown error" - if not reason in experiments_rejected_by_reason: - experiments_rejected_by_reason[reason] = 1 - else: - experiments_rejected_by_reason[reason] += 1 + experiments_rejected_by_reason[reason] += 1 if not error_detected: new_experiments.append(experiment) @@ -229,27 +227,12 @@ def run(self, experiments, reflections): self.logger.log("Experiments rejected by post-refinement: %d"%experiments_rejected_by_postrefinement) self.logger.log("Reflections rejected by post-refinement: %d"%reflections_rejected_by_postrefinement) - all_reasons = [] for reason, count in six.iteritems(experiments_rejected_by_reason): self.logger.log("Experiments rejected due to %s: %d"%(reason,count)) - all_reasons.append(reason) - - comm = self.mpi_helper.comm - MPI = self.mpi_helper.MPI - - # Collect all rejection reasons from all ranks. Use allreduce to let each rank have all reasons. - all_reasons = comm.allreduce(all_reasons, MPI.SUM) - all_reasons = set(all_reasons) # Now that each rank has all reasons from all ranks, we can treat the reasons in a uniform way. - total_experiments_rejected_by_reason = {} - for reason in all_reasons: - rejected_experiment_count = 0 - if reason in experiments_rejected_by_reason: - rejected_experiment_count = experiments_rejected_by_reason[reason] - total_experiments_rejected_by_reason[reason] = comm.reduce(rejected_experiment_count, MPI.SUM, 0) - - total_accepted_experiment_count = comm.reduce(len(new_experiments), MPI.SUM, 0) + total_experiments_rejected_by_reason = self.mpi_helper.count(experiments_rejected_by_reason) + total_accepted_experiment_count = self.mpi_helper.sum(len(new_experiments)) # how many reflections have we rejected due to post-refinement? rejected_reflections = len(reflections) - len(new_reflections); From 8c701e5e82a58163067ff52e1cab6a5cfde5fc84 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Fri, 2 Aug 2024 09:55:43 -0700 Subject: [PATCH 605/748] Update CHANGELOG.rst for 2024.7 release [skip ci] --- CHANGELOG.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 4075be50c3..c95ab6a175 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,9 @@ +2024.7 +====== + +* Speed improvements in NCS search and process non-bonded links +* DataManager: add scoring layer to filter arrays for fmodel + 2024.6 ====== From 860527ce34e1771f0f331161e491bb856d033dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Tcho=C5=84?= Date: Fri, 2 Aug 2024 14:50:35 -0600 Subject: [PATCH 606/748] "Truncate" XFEL expts/refls based on aggregated statistics (#1003) * Make postsanitize/postrefinement sanitization standalone CCTBX worker * Removed unused `Experiment` import * Add comments to aid future development * Add `truncate_phil` to the `cctbx.xfel.merge` `master_phil` * Convert arguments of `uniques` into lists before summing * `TruncationReasons.max_reason_len` should be `int`, not `str` * Mention `TruncationReasons.intensity_extremum_iqr_dist` when truncating * Change formatting so that it is clear that expt/refls are removed * When writing output, write `TruncationReasons` value * Make expts, refls plural in `TruncationReasons.report_line` * Rename `truncate` worker into `filter_global`, use `global_` phil scope * Improve main log message style * Rename `filter_global` worker's phil scope to `filter_global` --- xfel/merging/application/filter/factory.py | 14 ++- .../application/filter/global_filter.py | 112 ++++++++++++++++++ xfel/merging/application/phil/phil.py | 13 +- 3 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 xfel/merging/application/filter/global_filter.py diff --git a/xfel/merging/application/filter/factory.py b/xfel/merging/application/filter/factory.py index fb06e357e4..ad6a70dabc 100644 --- a/xfel/merging/application/filter/factory.py +++ b/xfel/merging/application/filter/factory.py @@ -1,6 +1,7 @@ from __future__ import absolute_import, division, print_function from xfel.merging.application.filter.experiment_filter import experiment_filter from xfel.merging.application.filter.reflection_filter import reflection_filter +from xfel.merging.application.filter.global_filter import GlobalFilter from xfel.merging.application.worker import factory as factory_base class factory(factory_base): @@ -9,8 +10,13 @@ class factory(factory_base): def from_parameters(params, additional_info=None, mpi_helper=None, mpi_logger=None): """ """ workers = [] - if params.filter.algorithm != None: - workers.append(experiment_filter(params, mpi_helper, mpi_logger)) - if params.select.algorithm != None: - workers.append(reflection_filter(params, mpi_helper, mpi_logger)) + if additional_info and additional_info[0] == 'global': + workers.append(GlobalFilter(params, mpi_helper, mpi_logger)) + elif additional_info: + raise KeyError('Unknown worker: filter_' + '_'.join(additional_info)) + else: # if not additional_info + if params.filter.algorithm is not None: + workers.append(experiment_filter(params, mpi_helper, mpi_logger)) + if params.select.algorithm is not None: + workers.append(reflection_filter(params, mpi_helper, mpi_logger)) return workers diff --git a/xfel/merging/application/filter/global_filter.py b/xfel/merging/application/filter/global_filter.py new file mode 100644 index 0000000000..4d7ed56cf4 --- /dev/null +++ b/xfel/merging/application/filter/global_filter.py @@ -0,0 +1,112 @@ +from __future__ import division + +from collections import Counter +from enum import Enum +from itertools import chain + +import numpy as np + +from dials.array_family import flex +from dxtbx.model import ExperimentList +from xfel.merging.application.utils.data_counter import data_counter +from xfel.merging.application.worker import worker + + +def flat_array(iterable): + """Return the contents of all input iterables flattened into a 1d np.array""" + return np.array(list(chain.from_iterable(iterable))) + + +def uniques(*iterables): + """Return a set of unique elements across all input iterables""" + return set(sum([list(i) for i in iterables], [])) + + +class FilterReasons(Enum): + """Enumerator documenting all possible reasons for filtering expts/refls""" + intensity_extremum_iqr_dist = "Intensity extremum outside IQR dist threshold" + # add subsequent global filtering reasons here (step 1/3) + + @classmethod + def max_reason_len(cls): + return max(len(r.value) for r in cls) + + @classmethod + def report_line(cls, reason, filtered_expts, filtered_refls): + """Return a line for the report listing all input in nice format""" + fmt = '- {:' + str(cls.max_reason_len() + 1) + '} {:6d} expts, {:9d} refls' + return fmt.format(str(reason) + ':', filtered_expts, filtered_refls) + + +class GlobalFilter(worker): + """Filter experiments & reflections based on their aggregated statistics""" + + def __init__(self, params, mpi_helper=None, mpi_logger=None): + self.expt_filter_reasons = Counter() + self.refl_filter_reasons = Counter() + super(GlobalFilter, self).__init__(params=params, mpi_helper=mpi_helper, + mpi_logger=mpi_logger) + + def __repr__(self): + return """Filter expts & refls based on their aggregated statistics""" + + def filter_intensity_extrema(self, expts, refls): + """Filter expts whose refls' intensity extrema don't fit the population""" + iqr_lim = self.params.filter_global.intensity_extrema_iqr_dist_threshold + maxima = [] + minima = [] + refl_list = [] + for iid, expt in enumerate(expts): + refl = refls.select(refls["id"] == iid) + maxima.append(max(refl['intensity.sum.value'])) + minima.append(min(refl['intensity.sum.value'])) + refl_list.append(refl) + all_maxima = flat_array(self.mpi_helper.comm.allgather(maxima)) + all_minima = flat_array(self.mpi_helper.comm.allgather(minima)) + maxima_quartiles = np.nanpercentile(all_maxima, [25, 50, 75]) + minima_quartiles = np.nanpercentile(all_minima, [25, 50, 75]) + maxima_iqr = maxima_quartiles[2] - maxima_quartiles[0] + minima_iqr = minima_quartiles[2] - minima_quartiles[0] + maxima_upper_lim = maxima_quartiles[1] + iqr_lim * maxima_iqr + minima_lower_lim = minima_quartiles[1] - iqr_lim * minima_iqr + filtered_expts = ExperimentList() + filtered_refls = flex.reflection_table() + for expt, refl, minimum, maximum in zip(expts, refl_list, minima, maxima): + if minimum < minima_lower_lim or maximum > maxima_upper_lim: + filter_reason = FilterReasons.intensity_extremum_iqr_dist + self.expt_filter_reasons[filter_reason] += 1 + self.refl_filter_reasons[filter_reason] += refl.size() + else: + filtered_expts.append(expt) + filtered_refls.extend(refl) + return filtered_expts, filtered_refls + + # implement subsequent global filtering algorithms here (step 2/3) + + def report_filter_reasons(self): + self.logger.log('Experiments/reflections filtered on this rank due to:') + for r in uniques(self.expt_filter_reasons, self.refl_filter_reasons): + te = self.expt_filter_reasons[r] + tr = self.refl_filter_reasons[r] + self.logger.log(FilterReasons.report_line(r.value, te, tr)) + te = sum(self.expt_filter_reasons.values()) + tr = sum(self.refl_filter_reasons.values()) + self.logger.log(FilterReasons.report_line('TOTAL', te, tr)) + if self.mpi_helper.rank == 0: + self.logger.main_log('Experiments/reflections filtered due to:') + expt_filter_reasons = self.mpi_helper.count(self.expt_filter_reasons) + refl_filter_reasons = self.mpi_helper.count(self.refl_filter_reasons) + for r in uniques(expt_filter_reasons, refl_filter_reasons): + te = expt_filter_reasons[r] + tr = refl_filter_reasons[r] + self.logger.main_log(FilterReasons.report_line(r.value, te, tr)) + te = sum(expt_filter_reasons.values()) + tr = sum(refl_filter_reasons.values()) + self.logger.main_log(FilterReasons.report_line('TOTAL', te, tr)) + + def run(self, experiments, reflections): + expts, refls = self.filter_intensity_extrema(experiments, reflections) + # call subsequent global filtering algorithms here (step 3/3) + self.report_filter_reasons() + data_counter(self.params).count(expts, refls) + return expts, refls diff --git a/xfel/merging/application/phil/phil.py b/xfel/merging/application/phil/phil.py index 26aa16b010..c580bbac79 100644 --- a/xfel/merging/application/phil/phil.py +++ b/xfel/merging/application/phil/phil.py @@ -714,6 +714,17 @@ """ +filter_global_phil = """ +filter_global { + intensity_extrema_iqr_dist_threshold = 1000.0 + .type = float(value_min=0, value_max=None) + .help = Maximum tolerated deviation of max(intensity.sum.value) + .help = and min(intensity.sum.value) from expts' population's respective + .help = medians, expressed in population's interquartile range units. +} +""" + + # A place to override any defaults included from elsewhere program_defaults_phil_str = """ modify.cosym.use_curvatures=False @@ -722,7 +733,7 @@ master_phil = dispatch_phil + input_phil + tdata_phil + filter_phil + modify_phil + \ select_phil + scaling_phil + postrefinement_phil + merging_phil + \ output_phil + statistics_phil + group_phil + lunus_phil + \ - publish_phil + diffbragg_phil + monitor_phil + publish_phil + diffbragg_phil + monitor_phil + filter_global_phil import os, importlib custom_phil_pathstr = os.environ.get('XFEL_CUSTOM_WORKER_PATH') From 062c59188379f7b2f0f1bcb3b81304353a9ac530 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Fri, 2 Aug 2024 17:25:23 -0700 Subject: [PATCH 607/748] Revert "CI: use libcxx=17 for XFEL CI" This reverts commit 78b918af8c954ba32ef349aa545a00526f38a55d. [skip ci] --- .azure-pipelines/xfel/unix-conda-build.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.azure-pipelines/xfel/unix-conda-build.yml b/.azure-pipelines/xfel/unix-conda-build.yml index 313761f1fc..9eaeff62bd 100644 --- a/.azure-pipelines/xfel/unix-conda-build.yml +++ b/.azure-pipelines/xfel/unix-conda-build.yml @@ -67,13 +67,6 @@ steps: displayName: Create conda environment condition: eq('${{ parameters.distribution }}', 'centos') -- script: | - set -xe - source $(Pipeline.Workspace)/miniforge/etc/profile.d/conda.sh - conda install -y -c conda-forge -n $(PYTHON_VERSION) libcxx=17 - displayName: Select libcxx on macOS - condition: eq(variables.OS, 'macos') - # build - script: | set -xe From f4c4338b0ade24a38df19a3e9aab738a6392965a Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 6 Aug 2024 13:42:21 -0700 Subject: [PATCH 608/748] Declutter Phenix: remove geo_file_parsing from master --- mmtbx/geometry_restraints/geo_file_parsing.py | 351 -------- .../tst_geo_file_parsing.py | 810 ------------------ mmtbx/run_tests.py | 1 - 3 files changed, 1162 deletions(-) delete mode 100644 mmtbx/geometry_restraints/geo_file_parsing.py delete mode 100644 mmtbx/geometry_restraints/tst_geo_file_parsing.py diff --git a/mmtbx/geometry_restraints/geo_file_parsing.py b/mmtbx/geometry_restraints/geo_file_parsing.py deleted file mode 100644 index eb451a5065..0000000000 --- a/mmtbx/geometry_restraints/geo_file_parsing.py +++ /dev/null @@ -1,351 +0,0 @@ -from __future__ import division, print_function -import re -import json -import pandas as pd -import numpy as np - -def tryfloat(value): - # Try to make float - try: - return float(value) - except Exception: - return value - -# Pattern to plit on either space or id_str -pattern = re.compile(r'pdb="[^"]*"|\S+') - - -# Define classes for restraints with fixed number of atoms -class BondRestraint: - restraint_label = 'bond' - @classmethod - def from_geo_lines(cls, lines, settings): - # start make restraint - n_atoms = settings["n_atoms"] - restraint_key = cls.restraint_label - key_index = n_atoms - value_index = n_atoms + 1 - - # Extract atom sequences or pdb strings - atoms_i_seqs = [] - for i in range(n_atoms): - match = pattern.findall(lines[i].replace(cls.restraint_label,"")) - parts = [part.strip() for part in match if part.strip() != ""] - if len(parts)>0: - # Assuming the first match is the desired one; adjust as necessary - atoms_i_seqs.append(parts[0]) - else: - atoms_i_seqs.append(lines[i].replace(cls.restraint_label,"").strip()) - - keys = pattern.findall(lines[key_index]) - values = [tryfloat(value) for value in pattern.findall(lines[value_index])] - d = {"restraint_type": restraint_key} - for i, i_seq in enumerate(atoms_i_seqs): - if "pdb" in i_seq: - k = f"id_str_{i}" - else: - k = f"i_seq_{i}" - d[k] = i_seq - - d.update({key: value for key, value in zip(keys, values)}) - return cls(d) - - def __init__(self, data_dict): - self.data_dict = data_dict -class AngleRestraint(BondRestraint): - restraint_label = 'angle' -class DihedralRestraint(BondRestraint): - restraint_label = 'dihedral' -class NonBondedRestraint(BondRestraint): - restraint_label = 'nonbonded' -class ChiralityRestraint(BondRestraint): - restraint_label = 'chirality' -class CBetaRestraint(BondRestraint): - restraint_label = 'c-beta' - -# Planes have variable n_atoms -class PlanarityRestraint: - restraint_label = 'plane' - - @classmethod - def from_geo_lines(cls, lines, settings): - planes_data = [] - headers = None - current_plane_data = {} - - for i,line in enumerate(lines): - if 'delta' in line: # Header line detected - headers = line.split() - continue # Skip to the next iteration after setting headers - - - # Handling a new "plane" line or a continuation of plane data - if line.startswith(cls.restraint_label): - # New "plane" entry; save the previous one if it exists - if current_plane_data: - planes_data.append(current_plane_data) - # Reset current_plane_data for a new "plane" entry - current_plane_data = {header: [] for header in headers} - current_plane_data['plane_indices'] = [] # Ensure 'plane_indices' is initialized - - # Split the line using the precompiled pattern, then strip and filter - matches = [match.group() for match in pattern.finditer(line)] - parts = [part.strip() for part in matches if part.strip()!=""] - #print(line) - #print(parts) - - start_idx = 1 if line.startswith(cls.restraint_label) else 0 - #print("Start idx:",start_idx) - # Adjust parsing according to the specific needs, for simplicity assuming plane_index is first - plane_index = parts[start_idx] - # Append the plane_index after conversion to integer if necessary - current_plane_data['plane_indices'].append(int(plane_index) if plane_index.isdigit() else plane_index) - - # Assign values to their corresponding headers - value_idx = start_idx + 1 - #print("Value idx:",value_idx) - for header, value in zip(headers, parts[value_idx:]): - current_plane_data[header].append(tryfloat(value)) - - - - # Add the last plane's data if it exists - #print(current_plane_data) - if current_plane_data: - planes_data.append(current_plane_data) - - - # another pass to ensure equal length data - assert len(planes_data)==1 - plane_data = planes_data[0] - lens = [len(value) for value in plane_data.values()] - max_len = max(lens) - - for key,value in list(plane_data.items()): - if len(value)==1: - plane_data[key] = value*max_len - if key == "plane_indices": - if any([isinstance(v,str) and ("pdb" in v) for v in value]): - plane_data["id_str"] = value - else: - plane_data["i_seq"] = value - del plane_data["plane_indices"] - - return cls({"plane": plane_data}) - - - def __init__(self, data_dict): - self.data_dict = data_dict - - @staticmethod - def form_dataframe(planes): - planes = [d["plane"] for d in planes] - - # Find max length - max_len = 0 - for plane in planes: - lens = [len(value) for value in plane.values()] - assert len(set(lens))==1, "Error: mismatched data lens" - if max(lens)>max_len: - max_len = max(lens) - - # expand each dict - expanded_planes= [] - for plane in planes: - plane_len = len(list(plane.values())[0]) - expanded_plane = {} - for key,value in plane.items(): - cols = [] - values = [] - for i in range(1,max_len+1): - col_name = f"{key}_{i}" - if i<=plane_len: - col_value = value[i-1] - else: - col_value = pd.NA - cols.append(col_name) - values.append(col_value) - expanded_plane.update(dict(zip(cols,values))) - expanded_planes.append(expanded_plane) - # make df - df = pd.DataFrame.from_records(expanded_planes) - return df - -restraint_settings = { - "nonbonded":{ # name of restraint - "header_label":"Nonbonded interactions", # search string - "n_atoms":2, # n_atoms to look for - "cif_key":"_phenix_restraint_nonbonded", # key for restraint in result - "restraint_class":NonBondedRestraint, - }, - "angle":{ - "header_label":"Bond angle restraints", - "n_atoms":3, - "cif_key":"_phenix_restraint_angle", - "restraint_class":AngleRestraint, - }, - "bond":{ - "header_label":"Bond restraints", - "n_atoms":2, - "cif_key":"_phenix_restraint_bond", - "restraint_class":BondRestraint, - }, - "dihedral":{ - "header_label":"Dihedral angle restraints", - "n_atoms":4, - "cif_key":"_phenix_restraint_dihedral", - "restraint_class":DihedralRestraint, - }, - "chirality":{ - "header_label":"Chirality restraints", - "n_atoms":4, - "cif_key":"_phenix_restraint_chirality", - "restraint_class":ChiralityRestraint, - }, - "c-beta":{ - "header_label":"C-Beta improper torsion angle restraints", - "n_atoms":4, - "cif_key":"_phenix_restraint_c-beta", - "restraint_class":CBetaRestraint, - }, - "plane":{ - "header_label":"Planarity restraints", - "n_atoms":None, - "cif_key":"_phenix_restraint_planarity", - "restraint_class":PlanarityRestraint, - }, -} -def split_into_sections(lines): - """ - Split a .geo file lines into sub-sections of lines for each restraint type - """ - sections = {} - current_section = None - for idx,line in enumerate(lines): - line = line.strip() - if not line: - continue - # Check if the line is a section header - if ':' in line and any(keyword in line for keyword in ['restraints', 'interactions']): - current_section = line - sections[current_section] = [] - elif current_section is not None: - # if 'plane' in line: - # sections[current_section].append(lines[idx-1]) - sections[current_section].append(line) - # Rename labels - output = {} - for section_label,section_value in sections.items(): - for setting_label, setting_value in restraint_settings.items(): - search_term = setting_value["header_label"] - if search_term in section_label: - output[setting_label] = section_value - return output - -def extract_restraint_objs_from_group(group, - settings, - restraint_key=None): - """ - Given a 'group' of lines for a given restraint, extract the data to a restraint instance - """ - n_atoms = settings["n_atoms"] - restraints = [] - restraint_lines = [] - if restraint_key == "c-beta": - new_entry_indicator = 'dihedral' - else: - new_entry_indicator = restraint_key - - restraint_label = restraint_key - for idx,line in enumerate(group): - # Check if the line is the start of a new entry within the restraint - if new_entry_indicator in line: - if restraint_lines: - # If there are already lines collected for a previous entry, save them - if restraint_key == "plane": - restraint_lines = restraint_lines[:-1] - restraints.append(restraint_lines) - restraint_lines = [] - if restraint_key == "plane": - if idx>1: - restraint_lines.append(group[idx-1]) - restraint_lines.append(line) - else: - # This is the first entry in the restraint - if restraint_key == "plane": - if idx>1: - restraint_lines.append(group[idx-1]) - restraint_lines.append(line) - elif restraint_lines: - # Continue adding lines to the current entry - restraint_lines.append(line) - # Add the last set of lines if not empty - if restraint_lines: - if restraint_key == "plane": - restraint_lines = restraint_lines[:-1] - restraints.append(restraint_lines) - s = set([len(r) for r in restraints]) - if restraint_key != "plane": - assert len(s)==1, "Failed .geo parsing\n"+"\n".join(restraint_lines) - assert next(iter(s))==n_atoms+2, "Failed .geo parsing"+"\n".join(restraints) - restraint_objs = [] - for restraint_lines in restraints: - settings = restraint_settings[restraint_label] - if "restraint_class" in settings: - restraint_class = restraint_settings[restraint_label]["restraint_class"] - restraint_instance = restraint_class.from_geo_lines(restraint_lines,settings) - restraint_objs.append(restraint_instance) - return restraint_objs - -def parse_geo_file(filename,return_format='dict'): - """ - Args: - filename (str): the .geo filename - return_format (str): One of 'dict', 'df' (pd.DataFrame), or 'json' - Returns: - restraint_dicts (dict): nested dictionary with final data in column format - """ - with open(filename,"r") as fh: - lines = fh.readlines() - restraint_dicts_all = {} - restraint_sections = split_into_sections(lines) - for restraint_label,setting_dict in restraint_settings.items(): - if restraint_label in restraint_sections: - group = restraint_sections[restraint_label] - restraint_objs = extract_restraint_objs_from_group(group, - setting_dict, - restraint_key=restraint_label) - restraint_dicts_all[restraint_label] = [obj.data_dict for obj in restraint_objs] - # convert dicts to dataframes and fill nan with None - dfs = {key:pd.DataFrame(value).replace({np.nan: None}) for key,value in restraint_dicts_all.items() if key != "plane"} - - # add planes - if "plane" in restraint_dicts_all: - df = PlanarityRestraint.form_dataframe(restraint_dicts_all["plane"]) - dfs["plane"] = df - if return_format == "df": - return dfs - elif return_format == "dict": - # convert to 'records' format dict - return {key:df.to_dict(orient='records') for key,df in dfs.items()} - elif return_format == "json": - # same format as dict, but as json string - d = {key:df.to_json(orient='records') for key,df in dfs.items()} - d = {key:json.loads(v) for key,v in d.items()} - return json.dumps(d,indent=2) - - - -def add_i_seq_columns_from_id_str(restraint_dfs,model): - """ - Given a dict of pandas DataFrames, each containing one type of restraint data, - add i_seq columns from a model by translating the existing id_str columns - """ - restraint_dfs = d - mapping_dict = {atom.id_str():atom.i_seq for atom in model.get_atoms()} - for restraint_name,df in restraint_dfs.items(): - id_str_cols = [col for col in df.columns if "id_str" in col] - i_seq_cols = [col.replace("id_str","i_seq") for col in id_str_cols] - for i_seq_col,id_str_col in zip(i_seq_cols,id_str_cols): - df[i_seq_col] = df[id_str_col].map(mapping_dict) - return restraint_dfs diff --git a/mmtbx/geometry_restraints/tst_geo_file_parsing.py b/mmtbx/geometry_restraints/tst_geo_file_parsing.py deleted file mode 100644 index 7a7e53712d..0000000000 --- a/mmtbx/geometry_restraints/tst_geo_file_parsing.py +++ /dev/null @@ -1,810 +0,0 @@ -from __future__ import division, print_function -import json -import pandas as pd -from mmtbx.geometry_restraints.geo_file_parsing import parse_geo_file - - -""" -Test that parsing a geo file yields previous results -""" -sample_geo_text = """ -# Geometry restraints - -Bond restraints: 2 -bond 38 - 39 - ideal model delta sigma weight residual - 1.522 1.553 -0.030 1.18e-02 7.18e+03 6.53e+00 -bond 37 - 38 - ideal model delta sigma weight residual - 1.460 1.485 -0.025 1.17e-02 7.31e+03 4.40e+00 - -Bond angle restraints: 2 -Sorted by residual: -angle 23 - 24 - 25 - ideal model delta sigma weight residual - 108.90 113.48 -4.58 1.63e+00 3.76e-01 7.90e+00 -angle 37 - 38 - 39 - ideal model delta sigma weight residual - 108.02 111.93 -3.91 1.78e+00 3.16e-01 4.84e+00 - - -Dihedral angle restraints: 2 - sinusoidal: 1 - harmonic: 1 -Sorted by residual: -dihedral 24 - 25 - 37 - 38 - ideal model delta harmonic sigma weight residual - 180.00 166.21 13.79 0 5.00e+00 4.00e-02 7.60e+00 -dihedral 58 - 59 - 60 - 61 - ideal model delta sinusoidal sigma weight residual - 0.00 -72.39 72.39 2 3.00e+01 1.11e-03 4.85e+00 - - -C-Beta improper torsion angle restraints: 2 -Sorted by residual: -dihedral 37 - 39 - 38 - 41 - ideal model delta harmonic sigma weight residual - 122.80 126.95 -4.15 0 2.50e+00 1.60e-01 2.75e+00 -dihedral 56 - 54 - 55 - 58 - ideal model delta harmonic sigma weight residual - -122.60 -126.01 3.41 0 2.50e+00 1.60e-01 1.86e+00 - - -Chirality restraints: 2 -Sorted by residual: -chirality 55 - 54 - 56 - 58 - both_signs ideal model delta sigma weight residual - False 2.51 2.39 0.12 2.00e-01 2.50e+01 3.48e-01 -chirality 72 - 71 - 73 - 75 - both_signs ideal model delta sigma weight residual - False 2.51 2.62 -0.11 2.00e-01 2.50e+01 2.86e-01 - -Planarity restraints: 2 -Sorted by residual: - delta sigma weight rms_deltas residual -plane 89 0.007 2.00e-02 2.50e+03 1.43e-02 6.15e+00 - 90 0.029 2.00e-02 2.50e+03 - 91 -0.003 2.00e-02 2.50e+03 - 92 0.001 2.00e-02 2.50e+03 - 93 0.003 2.00e-02 2.50e+03 - 94 -0.001 2.00e-02 2.50e+03 - 95 -0.013 2.00e-02 2.50e+03 - 96 -0.001 2.00e-02 2.50e+03 - 102 -0.029 2.00e-02 2.50e+03 - 103 -0.016 2.00e-02 2.50e+03 - 104 0.017 2.00e-02 2.50e+03 - 105 0.005 2.00e-02 2.50e+03 - delta sigma weight rms_deltas residual -plane 13 -0.003 2.00e-02 2.50e+03 1.55e-02 3.62e+00 - 14 -0.022 2.00e-02 2.50e+03 - 15 0.019 2.00e-02 2.50e+03 - 16 -0.002 2.00e-02 2.50e+03 - 19 -0.012 2.00e-02 2.50e+03 - 20 0.020 2.00e-02 2.50e+03 - - -Nonbonded interactions: 3 -Sorted by model distance: -nonbonded 106 - 110 - model vdw sym.op. - 1.719 1.850 -x+1,y-1/2,-z+1 -nonbonded 29 - 34 - model vdw sym.op. - 1.859 1.850 x,y+1,z - -nonbonded 33 - 61 - model vdw - 1.876 1.850 - -""" - -test_data_json = """ -{ - "nonbonded": [ - { - "restraint_type": "nonbonded", - "i_seq_0": "106", - "i_seq_1": "110", - "model": 1.719, - "vdw": 1.85, - "sym.op.": "-x+1,y-1/2,-z+1" - }, - { - "restraint_type": "nonbonded", - "i_seq_0": "29", - "i_seq_1": "34", - "model": 1.859, - "vdw": 1.85, - "sym.op.": "x,y+1,z" - }, - { - "restraint_type": "nonbonded", - "i_seq_0": "33", - "i_seq_1": "61", - "model": 1.876, - "vdw": 1.85, - "sym.op.": null - } - ], - "angle": [ - { - "restraint_type": "angle", - "i_seq_0": "23", - "i_seq_1": "24", - "i_seq_2": "25", - "ideal": 108.9, - "model": 113.48, - "delta": -4.58, - "sigma": 1.63, - "weight": 0.376, - "residual": 7.9 - }, - { - "restraint_type": "angle", - "i_seq_0": "37", - "i_seq_1": "38", - "i_seq_2": "39", - "ideal": 108.02, - "model": 111.93, - "delta": -3.91, - "sigma": 1.78, - "weight": 0.316, - "residual": 4.84 - } - ], - "bond": [ - { - "restraint_type": "bond", - "i_seq_0": "38", - "i_seq_1": "39", - "ideal": 1.522, - "model": 1.553, - "delta": -0.03, - "sigma": 0.0118, - "weight": 7180.0, - "residual": 6.53 - }, - { - "restraint_type": "bond", - "i_seq_0": "37", - "i_seq_1": "38", - "ideal": 1.46, - "model": 1.485, - "delta": -0.025, - "sigma": 0.0117, - "weight": 7310.0, - "residual": 4.4 - } - ], - "dihedral": [ - { - "restraint_type": "dihedral", - "i_seq_0": "24", - "i_seq_1": "25", - "i_seq_2": "37", - "i_seq_3": "38", - "ideal": 180.0, - "model": 166.21, - "delta": 13.79, - "harmonic": 0.0, - "sigma": 5.0, - "weight": 0.04, - "residual": 7.6, - "sinusoidal": null - }, - { - "restraint_type": "dihedral", - "i_seq_0": "58", - "i_seq_1": "59", - "i_seq_2": "60", - "i_seq_3": "61", - "ideal": 0.0, - "model": -72.39, - "delta": 72.39, - "harmonic": null, - "sigma": 30.0, - "weight": 0.00111, - "residual": 4.85, - "sinusoidal": 2.0 - } - ], - "chirality": [ - { - "restraint_type": "chirality", - "i_seq_0": "55", - "i_seq_1": "54", - "i_seq_2": "56", - "i_seq_3": "58", - "both_signs": "False", - "ideal": 2.51, - "model": 2.39, - "delta": 0.12, - "sigma": 0.2, - "weight": 25.0, - "residual": 0.348 - }, - { - "restraint_type": "chirality", - "i_seq_0": "72", - "i_seq_1": "71", - "i_seq_2": "73", - "i_seq_3": "75", - "both_signs": "False", - "ideal": 2.51, - "model": 2.62, - "delta": -0.11, - "sigma": 0.2, - "weight": 25.0, - "residual": 0.286 - } - ], - "c-beta": [ - { - "restraint_type": "c-beta", - "i_seq_0": "dihedral", - "i_seq_1": "39", - "i_seq_2": "38", - "i_seq_3": "41", - "ideal": 122.8, - "model": 126.95, - "delta": -4.15, - "harmonic": 0.0, - "sigma": 2.5, - "weight": 0.16, - "residual": 2.75 - }, - { - "restraint_type": "c-beta", - "i_seq_0": "dihedral", - "i_seq_1": "54", - "i_seq_2": "55", - "i_seq_3": "58", - "ideal": -122.6, - "model": -126.01, - "delta": 3.41, - "harmonic": 0.0, - "sigma": 2.5, - "weight": 0.16, - "residual": 1.86 - } - ], - "plane": [ - { - "delta_1": 0.007, - "delta_2": 0.029, - "delta_3": -0.003, - "delta_4": 0.001, - "delta_5": 0.003, - "delta_6": -0.001, - "delta_7": -0.013, - "delta_8": -0.001, - "delta_9": -0.029, - "delta_10": -0.016, - "delta_11": 0.017, - "delta_12": 0.005, - "sigma_1": 0.02, - "sigma_2": 0.02, - "sigma_3": 0.02, - "sigma_4": 0.02, - "sigma_5": 0.02, - "sigma_6": 0.02, - "sigma_7": 0.02, - "sigma_8": 0.02, - "sigma_9": 0.02, - "sigma_10": 0.02, - "sigma_11": 0.02, - "sigma_12": 0.02, - "weight_1": 2500.0, - "weight_2": 2500.0, - "weight_3": 2500.0, - "weight_4": 2500.0, - "weight_5": 2500.0, - "weight_6": 2500.0, - "weight_7": 2500.0, - "weight_8": 2500.0, - "weight_9": 2500.0, - "weight_10": 2500.0, - "weight_11": 2500.0, - "weight_12": 2500.0, - "rms_deltas_1": 0.0143, - "rms_deltas_2": 0.0143, - "rms_deltas_3": 0.0143, - "rms_deltas_4": 0.0143, - "rms_deltas_5": 0.0143, - "rms_deltas_6": 0.0143, - "rms_deltas_7": 0.0143, - "rms_deltas_8": 0.0143, - "rms_deltas_9": 0.0143, - "rms_deltas_10": 0.0143, - "rms_deltas_11": 0.0143, - "rms_deltas_12": 0.0143, - "residual_1": 6.15, - "residual_2": 6.15, - "residual_3": 6.15, - "residual_4": 6.15, - "residual_5": 6.15, - "residual_6": 6.15, - "residual_7": 6.15, - "residual_8": 6.15, - "residual_9": 6.15, - "residual_10": 6.15, - "residual_11": 6.15, - "residual_12": 6.15, - "i_seq_1": 89, - "i_seq_2": 90, - "i_seq_3": 91, - "i_seq_4": 92, - "i_seq_5": 93, - "i_seq_6": 94, - "i_seq_7": 95, - "i_seq_8": 96, - "i_seq_9": 102, - "i_seq_10": 103, - "i_seq_11": 104, - "i_seq_12": 105 - }, - { - "delta_1": -0.003, - "delta_2": -0.022, - "delta_3": 0.019, - "delta_4": -0.002, - "delta_5": -0.012, - "delta_6": null, - "delta_7": null, - "delta_8": null, - "delta_9": null, - "delta_10": null, - "delta_11": null, - "delta_12": null, - "sigma_1": 0.02, - "sigma_2": 0.02, - "sigma_3": 0.02, - "sigma_4": 0.02, - "sigma_5": 0.02, - "sigma_6": null, - "sigma_7": null, - "sigma_8": null, - "sigma_9": null, - "sigma_10": null, - "sigma_11": null, - "sigma_12": null, - "weight_1": 2500.0, - "weight_2": 2500.0, - "weight_3": 2500.0, - "weight_4": 2500.0, - "weight_5": 2500.0, - "weight_6": null, - "weight_7": null, - "weight_8": null, - "weight_9": null, - "weight_10": null, - "weight_11": null, - "weight_12": null, - "rms_deltas_1": 0.0155, - "rms_deltas_2": 0.0155, - "rms_deltas_3": 0.0155, - "rms_deltas_4": 0.0155, - "rms_deltas_5": 0.0155, - "rms_deltas_6": null, - "rms_deltas_7": null, - "rms_deltas_8": null, - "rms_deltas_9": null, - "rms_deltas_10": null, - "rms_deltas_11": null, - "rms_deltas_12": null, - "residual_1": 3.62, - "residual_2": 3.62, - "residual_3": 3.62, - "residual_4": 3.62, - "residual_5": 3.62, - "residual_6": null, - "residual_7": null, - "residual_8": null, - "residual_9": null, - "residual_10": null, - "residual_11": null, - "residual_12": null, - "i_seq_1": 13, - "i_seq_2": 14, - "i_seq_3": 15, - "i_seq_4": 16, - "i_seq_5": 19, - "i_seq_6": null, - "i_seq_7": null, - "i_seq_8": null, - "i_seq_9": null, - "i_seq_10": null, - "i_seq_11": null, - "i_seq_12": null - } - ] -} -""" -# Now with labels rather than i_seqs -sample_geo_text_2 = """ -Bond restraints: 3 -Sorted by residual: -bond pdb=" N GLY A 1 " - pdb=" CA GLY A 1 " - ideal model delta sigma weight residual - 1.451 1.507 -0.056 1.60e-02 3.91e+03 1.23e+01 -bond pdb=" CA GLN A 4 " - pdb=" C GLN A 4 " - ideal model delta sigma weight residual - 1.522 1.553 -0.030 1.18e-02 7.18e+03 6.53e+00 -bond pdb=" N GLN A 4 " - pdb=" CA GLN A 4 " - ideal model delta sigma weight residual - 1.460 1.485 -0.025 1.17e-02 7.31e+03 4.40e+00 - -Bond angle restraints: 2 -Sorted by residual: -angle pdb=" N ASN A 3 " - pdb=" CA ASN A 3 " - pdb=" C ASN A 3 " - ideal model delta sigma weight residual - 108.90 113.48 -4.58 1.63e+00 3.76e-01 7.90e+00 -angle pdb=" N GLN A 4 " - pdb=" CA GLN A 4 " - pdb=" C GLN A 4 " - ideal model delta sigma weight residual - 108.02 111.93 -3.91 1.78e+00 3.16e-01 4.84e+00 - -Dihedral angle restraints: 3 - sinusoidal: 15 - harmonic: 7 -Sorted by residual: -dihedral pdb=" CA ASN A 3 " - pdb=" C ASN A 3 " - pdb=" N GLN A 4 " - pdb=" CA GLN A 4 " - ideal model delta harmonic sigma weight residual - 180.00 166.21 13.79 0 5.00e+00 4.00e-02 7.60e+00 -dihedral pdb=" CB GLN A 5 " - pdb=" CG GLN A 5 " - pdb=" CD GLN A 5 " - pdb=" OE1 GLN A 5 " - ideal model delta sinusoidal sigma weight residual - 0.00 -72.39 72.39 2 3.00e+01 1.11e-03 4.85e+00 -dihedral pdb=" CB GLN A 4 " - pdb=" CG GLN A 4 " - pdb=" CD GLN A 4 " - pdb=" OE1 GLN A 4 " - ideal model delta sinusoidal sigma weight residual - 0.00 54.08 -54.08 2 3.00e+01 1.11e-03 3.50e+00 -Planarity restraints: 2 -Sorted by residual: - delta sigma weight rms_deltas residual -plane pdb=" CB TYR A 7 " -0.006 2.00e-02 2.50e+03 9.66e-03 1.87e+00 - pdb=" CG TYR A 7 " 0.022 2.00e-02 2.50e+03 - pdb=" CD1 TYR A 7 " -0.008 2.00e-02 2.50e+03 - pdb=" CD2 TYR A 7 " -0.004 2.00e-02 2.50e+03 - pdb=" CE1 TYR A 7 " 0.002 2.00e-02 2.50e+03 - pdb=" CE2 TYR A 7 " -0.001 2.00e-02 2.50e+03 - pdb=" CZ TYR A 7 " -0.011 2.00e-02 2.50e+03 - pdb=" OH TYR A 7 " 0.006 2.00e-02 2.50e+03 - delta sigma weight rms_deltas residual -plane pdb=" CB ASN A 2 " 0.006 2.00e-02 2.50e+03 1.19e-02 1.42e+00 - pdb=" CG ASN A 2 " -0.021 2.00e-02 2.50e+03 - pdb=" OD1 ASN A 2 " 0.008 2.00e-02 2.50e+03 - pdb=" ND2 ASN A 2 " 0.007 2.00e-02 2.50e+03 -""" -test_data_json_2 = """ -{ - "angle": [ - { - "restraint_type": "angle", - "id_str_0": "pdb=\\\" N ASN A 3 \\\"", - "id_str_1": "pdb=\\\" CA ASN A 3 \\\"", - "id_str_2": "pdb=\\\" C ASN A 3 \\\"", - "ideal": 108.9, - "model": 113.48, - "delta": -4.58, - "sigma": 1.63, - "weight": 0.376, - "residual": 7.9 - }, - { - "restraint_type": "angle", - "id_str_0": "pdb=\\\" N GLN A 4 \\\"", - "id_str_1": "pdb=\\\" CA GLN A 4 \\\"", - "id_str_2": "pdb=\\\" C GLN A 4 \\\"", - "ideal": 108.02, - "model": 111.93, - "delta": -3.91, - "sigma": 1.78, - "weight": 0.316, - "residual": 4.84 - } - ], - "bond": [ - { - "restraint_type": "bond", - "id_str_0": "pdb=\\\" N GLY A 1 \\\"", - "id_str_1": "pdb=\\\" CA GLY A 1 \\\"", - "ideal": 1.451, - "model": 1.507, - "delta": -0.056, - "sigma": 0.016, - "weight": 3910.0, - "residual": 12.3 - }, - { - "restraint_type": "bond", - "id_str_0": "pdb=\\\" CA GLN A 4 \\\"", - "id_str_1": "pdb=\\\" C GLN A 4 \\\"", - "ideal": 1.522, - "model": 1.553, - "delta": -0.03, - "sigma": 0.0118, - "weight": 7180.0, - "residual": 6.53 - }, - { - "restraint_type": "bond", - "id_str_0": "pdb=\\\" N GLN A 4 \\\"", - "id_str_1": "pdb=\\\" CA GLN A 4 \\\"", - "ideal": 1.46, - "model": 1.485, - "delta": -0.025, - "sigma": 0.0117, - "weight": 7310.0, - "residual": 4.4 - } - ], - "dihedral": [ - { - "restraint_type": "dihedral", - "id_str_0": "pdb=\\\" CA ASN A 3 \\\"", - "id_str_1": "pdb=\\\" C ASN A 3 \\\"", - "id_str_2": "pdb=\\\" N GLN A 4 \\\"", - "id_str_3": "pdb=\\\" CA GLN A 4 \\\"", - "ideal": 180.0, - "model": 166.21, - "delta": 13.79, - "harmonic": 0.0, - "sigma": 5.0, - "weight": 0.04, - "residual": 7.6, - "sinusoidal": null - }, - { - "restraint_type": "dihedral", - "id_str_0": "pdb=\\\" CB GLN A 5 \\\"", - "id_str_1": "pdb=\\\" CG GLN A 5 \\\"", - "id_str_2": "pdb=\\\" CD GLN A 5 \\\"", - "id_str_3": "pdb=\\\" OE1 GLN A 5 \\\"", - "ideal": 0.0, - "model": -72.39, - "delta": 72.39, - "harmonic": null, - "sigma": 30.0, - "weight": 0.00111, - "residual": 4.85, - "sinusoidal": 2.0 - }, - { - "restraint_type": "dihedral", - "id_str_0": "pdb=\\\" CB GLN A 4 \\\"", - "id_str_1": "pdb=\\\" CG GLN A 4 \\\"", - "id_str_2": "pdb=\\\" CD GLN A 4 \\\"", - "id_str_3": "pdb=\\\" OE1 GLN A 4 \\\"", - "ideal": 0.0, - "model": 54.08, - "delta": -54.08, - "harmonic": null, - "sigma": 30.0, - "weight": 0.00111, - "residual": 3.5, - "sinusoidal": 2.0 - } - ], - "plane": [ - { - "delta_1": -0.006, - "delta_2": 0.022, - "delta_3": -0.008, - "delta_4": -0.004, - "delta_5": 0.002, - "delta_6": -0.001, - "delta_7": -0.011, - "delta_8": 0.006, - "sigma_1": 0.02, - "sigma_2": 0.02, - "sigma_3": 0.02, - "sigma_4": 0.02, - "sigma_5": 0.02, - "sigma_6": 0.02, - "sigma_7": 0.02, - "sigma_8": 0.02, - "weight_1": 2500.0, - "weight_2": 2500.0, - "weight_3": 2500.0, - "weight_4": 2500.0, - "weight_5": 2500.0, - "weight_6": 2500.0, - "weight_7": 2500.0, - "weight_8": 2500.0, - "rms_deltas_1": 0.00966, - "rms_deltas_2": 0.00966, - "rms_deltas_3": 0.00966, - "rms_deltas_4": 0.00966, - "rms_deltas_5": 0.00966, - "rms_deltas_6": 0.00966, - "rms_deltas_7": 0.00966, - "rms_deltas_8": 0.00966, - "residual_1": 1.87, - "residual_2": 1.87, - "residual_3": 1.87, - "residual_4": 1.87, - "residual_5": 1.87, - "residual_6": 1.87, - "residual_7": 1.87, - "residual_8": 1.87, - "id_str_1": "pdb=\\\" CB TYR A 7 \\\"", - "id_str_2": "pdb=\\\" CG TYR A 7 \\\"", - "id_str_3": "pdb=\\\" CD1 TYR A 7 \\\"", - "id_str_4": "pdb=\\\" CD2 TYR A 7 \\\"", - "id_str_5": "pdb=\\\" CE1 TYR A 7 \\\"", - "id_str_6": "pdb=\\\" CE2 TYR A 7 \\\"", - "id_str_7": "pdb=\\\" CZ TYR A 7 \\\"", - "id_str_8": "pdb=\\\" OH TYR A 7 \\\"" - }, - { - "delta_1": 0.006, - "delta_2": -0.021, - "delta_3": 0.008, - "delta_4": null, - "delta_5": null, - "delta_6": null, - "delta_7": null, - "delta_8": null, - "sigma_1": 0.02, - "sigma_2": 0.02, - "sigma_3": 0.02, - "sigma_4": null, - "sigma_5": null, - "sigma_6": null, - "sigma_7": null, - "sigma_8": null, - "weight_1": 2500.0, - "weight_2": 2500.0, - "weight_3": 2500.0, - "weight_4": null, - "weight_5": null, - "weight_6": null, - "weight_7": null, - "weight_8": null, - "rms_deltas_1": 0.0119, - "rms_deltas_2": 0.0119, - "rms_deltas_3": 0.0119, - "rms_deltas_4": null, - "rms_deltas_5": null, - "rms_deltas_6": null, - "rms_deltas_7": null, - "rms_deltas_8": null, - "residual_1": 1.42, - "residual_2": 1.42, - "residual_3": 1.42, - "residual_4": null, - "residual_5": null, - "residual_6": null, - "residual_7": null, - "residual_8": null, - "id_str_1": "pdb=\\\" CB ASN A 2 \\\"", - "id_str_2": "pdb=\\\" CG ASN A 2 \\\"", - "id_str_3": "pdb=\\\" OD1 ASN A 2 \\\"", - "id_str_4": null, - "id_str_5": null, - "id_str_6": null, - "id_str_7": null, - "id_str_8": null - } - ] -} -""" - - -test_data = json.loads(test_data_json) -test_data_2 = json.loads(test_data_json_2) - -# load file -with open("tst_geo_parsing.geo","w") as fh: - fh.write(sample_geo_text) - -# load file -with open("tst_geo_parsing_2.geo","w") as fh: - fh.write(sample_geo_text_2) - -# read back in -geo_dict = parse_geo_file("tst_geo_parsing.geo",return_format='dict') -geo_dict_2 = parse_geo_file("tst_geo_parsing_2.geo",return_format='dict') - - -# define comparison functions - -def get_type(value): - if pd.isna(value): - return None - try: - f = float(value) - if f.is_integer(): - return int - else: - return float - except Exception: - return str - -def compare_custom(d1,d2): - """ - Compare two dictionaries by types, and 'ideal' floats - with a large tolerance to enable future changes to restraints. - """ - #print(d1) - #print(d2) - for key1,value1 in d1.items(): - assert key1 in d2 - value2 = d2[key1] - #print(value1,value2) - t1,t2 = get_type(value1), get_type(value2) - assert t1==t2, '%s!=%s' % (t1, t2) - - # get all none-like values to be None - if t1 is None: - value1 = None - if t2 is None: - value2 = None - assert str(value1)==str(value2), "Invalid comparisons: "+str(value1)+" and "+str(value2) - return True - - - -# test -def test1(): - print("Test1") - for key,d_list in geo_dict.items(): - for j,d in enumerate(d_list): - d_ref = test_data[key][j] - same = compare_custom(d,d_ref) - print(same) - -def test2(): - print("Test2") - for key,d_list in geo_dict_2.items(): - for j,d in enumerate(d_list): - d_ref = test_data_2[key][j] - same = compare_custom(d,d_ref) - print(same) - -if __name__ == '__main__': - test1() - test2() - print("Finished") - diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index 1e72561d43..8adab233ea 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -56,7 +56,6 @@ "$D/regression/tst_ml_estimate.py", "$D/density_modification/tst_density_modification.py", "$D/geometry_restraints/tst_ramachandran.py", - "$D/geometry_restraints/tst_geo_file_parsing.py", "$D/geometry_restraints/tst_manager.py", "$D/geometry_restraints/external.py", "$D/regression/tst_map_type_parser.py", From 77b5ab763863eb9377c3a53476ea0422657bed41 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Tue, 6 Aug 2024 14:00:36 -0700 Subject: [PATCH 609/748] CI: remove deleted entries [skip ci] --- .azure-pipelines/py2_syntax_exceptions.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/.azure-pipelines/py2_syntax_exceptions.txt b/.azure-pipelines/py2_syntax_exceptions.txt index 7be5254be5..fc86cc0ff7 100644 --- a/.azure-pipelines/py2_syntax_exceptions.txt +++ b/.azure-pipelines/py2_syntax_exceptions.txt @@ -20,5 +20,3 @@ xfel/merging/application/errors/error_modifier_mm24.py xfel/util/preference.py cctbx/maptbx/qscore.py cctbx/maptbx/tst_qscore.py -mmtbx/geometry_restraints/geo_file_parsing.py -mmtbx/geometry_restraints/tst_geo_file_parsing.py From 09bf1c96da5bdb7d2d787816f6230b98122a731f Mon Sep 17 00:00:00 2001 From: randyjread Date: Fri, 21 Jun 2024 17:22:52 +0100 Subject: [PATCH 610/748] Changes towards allowing docking to account for fixed models. --- cctbx/maptbx/prepare_map_for_docking.py | 127 +++++++----------------- 1 file changed, 36 insertions(+), 91 deletions(-) diff --git a/cctbx/maptbx/prepare_map_for_docking.py b/cctbx/maptbx/prepare_map_for_docking.py index f4846df1b8..5faad12934 100644 --- a/cctbx/maptbx/prepare_map_for_docking.py +++ b/cctbx/maptbx/prepare_map_for_docking.py @@ -818,56 +818,25 @@ def sphere_enclosing_model(model): model_radius = math.sqrt(dsqrmax) return model_centre, model_radius -def sphere_sampling_model(model): - sites_cart = model.get_sites_cart() - cart_min = flex.double(sites_cart.min()) - cart_max = flex.double(sites_cart.max()) - model_midpoint = (cart_max + cart_min) / 2 - meansqr = flex.mean((sites_cart - tuple(model_midpoint)).norms() ** 2) - rms_model_radius = math.sqrt(meansqr) - return model_midpoint, rms_model_radius - -def flatten_model_region(mmm, d_min): - # Flatten the region covered by the model - # For map_manager, replace it by the mask-weighted mean within this region - # For half-maps, replace by the mean and put back the original half-map - # map difference to preserve the error signal. - mm = mmm.map_manager() - mm1 = mmm.map_manager_1() - mm2 = mmm.map_manager_2() - delta_mm = mm1.customized_copy(map_data = mm1.map_data() - mm2.map_data()) - model = mmm.model() - mmm.create_mask_around_atoms(model=model, soft_mask=True, soft_mask_radius=d_min/2) - working_mmm = mmm.deep_copy() # Save a copy before masking to work on later - - working_mmm.add_map_manager_by_id(delta_mm, map_id = 'delta_map') - - # Invert original mask and apply to original maps to flatten density under model - mask_mm_inverse = mmm.get_map_manager_by_id('mask') - mask_mm_inverse.set_map_data(map_data = 1. - mask_mm_inverse.map_data()) - mmm.apply_mask_to_maps(set_outside_to_mean_inside = False) - - # Apply original mask to working_mmm to get density and difference density under model - mask_mm = working_mmm.get_map_manager_by_id('mask') - working_mmm.apply_mask_to_maps(set_outside_to_mean_inside = False) - - # Get mean density for part of each map under model, to add back to - # flattened region of each map - mask_info = working_mmm.mask_info() - weighted_points = mask_info.size*mask_info.mean - wmm = working_mmm.map_manager() - mean_map = flex.sum(wmm.map_data()) / weighted_points - mask_data = mask_mm.map_data() - mm.set_map_data(map_data = mm.map_data() + mean_map * mask_data) - wmm1 = working_mmm.map_manager_1() - mean_map1 = flex.sum(wmm1.map_data()) / weighted_points - mm1.set_map_data(map_data = mm1.map_data() + - mean_map1 * mask_data + delta_mm.map_data()/2) - wmm2 = working_mmm.map_manager_2() - mean_map2 = flex.sum(wmm2.map_data()) / weighted_points - mm2.set_map_data(map_data = mm2.map_data() + - mean_map2 * mask_data - delta_mm.map_data()/2) - mmm.remove_map_manager_by_id('mask') +def mask_fixed_model_region(mmm, d_min, + fixed_model=None, + ordered_mask_id='ordered_volume_mask', + fixed_mask_id='mask_around_atoms'): + # Flatten the region of the mask covered by the fixed model + # and keep the mask for the fixed model. + + # Do nothing if no fixed model + if fixed_model is None: + return + + radius = max(3., d_min) + mmm.create_mask_around_atoms(model=fixed_model, mask_atoms_atom_radius=radius, mask_id=fixed_mask_id) + fixed_model_mask = mmm.get_map_manager_by_id(map_id=fixed_mask_id) + # Invert fixed_model_mask before flattening + fixed_model_mask.set_map_data(map_data = 1. - fixed_model_mask.map_data()) + mmm.apply_mask_to_map(map_id=ordered_mask_id, mask_id=fixed_mask_id) + # Invert back so we can use to assess fraction of fixed model in masked sphere + fixed_model_mask.set_map_data(map_data = 1. - fixed_model_mask.map_data()) def add_local_squared_deviation_map( mmm, coeffs_in, radius, d_min, map_id_out): @@ -1922,29 +1891,21 @@ def run(): Optional command-line arguments (keyworded): --protein_mw*: molecular weight expected for protein component of ordered density --nucleic_mw*: same for nucleic acid component - --model: PDB file for model that can either be used to flatten the map around - the model, to search for the next component, or to cut out a sphere - of density to refine and score the fit of the model - --flatten_model: Use model to define region where map should be flattened - --cutout_model: Use model to define sphere to process for refining and - scoring the docking of this model --sphere_cent: Centre of sphere defining target map region (3 floats) defaults to centre of map --radius: radius of sphere (1 float) must be given if sphere_cent defined, otherwise - defaults to narrowest extent of input map divided by 4 + defaults to either radius enclosing 98% of ordered volume (if determined) + or narrowest extent of input map divided by 4 --no_shift_map_origin: don't shift output mtz file to match input map on its origin default False - --no_determine_ordered_volume: don't define ordered volume for comparison with cutout volume + --no_determine_ordered_volume: don't determine ordered volume default False --file_root: root name for output files --mute (or -m): mute output --verbose (or -v): verbose output --testing: extra verbose output for debugging * NB: At least one of protein_mw or nucleic_mw must be given - Either a model or a sphere can be used to specify a cutout region, but - not both - The flatten_model option cannot be combined with cutting out a sphere. """ import argparse dm = DataManager() @@ -1952,7 +1913,7 @@ def run(): parser = argparse.ArgumentParser( description='Prepare cryo-EM map for docking') - parser.add_argument('map1',help='Map file for half-map 1') + parser.add_argument('map1', help='Map file for half-map 1') parser.add_argument('map2', help='Map file for half-map 2') parser.add_argument('d_min', help='d_min for maps', type=float) parser.add_argument('--protein_mw', @@ -1963,11 +1924,7 @@ def run(): type=float) parser.add_argument('--sphere_points',help='Target nrefs in averaging sphere', type=float, default=500.) - parser.add_argument('--model',help='Placed model') - parser.add_argument('--flatten_model',help='Flatten map around model', - action='store_true') - parser.add_argument('--cutout_model',help='Cut out sphere around model', - action='store_true') + parser.add_argument('--fixed_model', help='Fixed model') parser.add_argument('--sphere_cent',help='Centre of sphere for docking', nargs=3, type=float) parser.add_argument('--radius',help='Radius of sphere for docking', type=float) @@ -1991,7 +1948,10 @@ def run(): cutout_specified = False sphere_cent = None radius = None - model = None + fixed_model = None + if args.fixed_model is not None: + model_file = args.fixed_model + fixed_model = dm.get_model(model_file) protein_mw = None nucleic_mw = None @@ -2005,26 +1965,12 @@ def run(): sphere_points = args.sphere_points - if args.model is not None: - if not (args.cutout_model or args.flatten_model): - raise Sorry("Use for model must be specified (flatten or cut out map)") - model_file = args.model - model = dm.get_model(model_file) - - if (args.sphere_cent is not None) and args.cutout_model: - raise Sorry("Only one method to define region to cut out (sphere or model) can be given") if args.sphere_cent is not None: if args.radius is None: raise Sorry("Radius must be provided if sphere_cent is defined") sphere_cent = tuple(args.sphere_cent) radius = args.radius cutout_specified = True - if args.cutout_model: - if args.model is None: - raise Sorry("Model must be provided if cutout_model is defined") - sphere_cent, radius = sphere_enclosing_model(model) - radius = radius + d_min # Expand to allow width for density - cutout_specified = True if (not determine_ordered_volume and not cutout_specified): raise Sorry("Must determine ordered volume if cutout not specified") @@ -2033,19 +1979,15 @@ def run(): mm1 = dm.get_real_map(map1_filename) map2_filename = args.map2 mm2 = dm.get_real_map(map2_filename) - mmm = map_model_manager(model=model, map_manager_1=mm1, map_manager_2=mm2) - - # Prepare maps by flattening model volume if desired - if args.flatten_model: - if args.model is None: - raise Sorry("Model must be provided if flatten_model is defined") - flatten_model_region(mmm, d_min) + mmm = map_model_manager(model=fixed_model, map_manager_1=mm1, map_manager_2=mm2) if determine_ordered_volume: mask_id = 'ordered_volume_mask' add_ordered_volume_mask(mmm, d_min, protein_mw=protein_mw, nucleic_mw=nucleic_mw, map_id_out=mask_id) + if fixed_model: + mask_fixed_model_region(mmm, d_min, fixed_model=fixed_model) if verbosity>1: ordered_mm = mmm.get_map_manager_by_id(map_id=mask_id) if args.file_root is not None: @@ -2056,10 +1998,13 @@ def run(): # Default to sphere containing most of ordered volume if not cutout_specified: - target_completeness = 0.98 - radius = get_mask_radius(mmm.get_map_manager_by_id(mask_id),target_completeness) ucpars = mm1.unit_cell().parameters() sphere_cent = (ucpars[0]/2,ucpars[1]/2,ucpars[2]/2) + if determine_ordered_volume: + target_completeness = 0.98 + radius = get_mask_radius(mmm.get_map_manager_by_id(mask_id),target_completeness) + else: + radius = min(ucpars[0],ucpars[1],ucpars[2])/4. # Refine to get scale and error parameters for docking region results = assess_cryoem_errors(mmm, d_min, sphere_points=sphere_points, From 20d723aab96c23eab0f559b62f0d66891c63a222 Mon Sep 17 00:00:00 2001 From: randyjread Date: Fri, 26 Jul 2024 14:32:08 +0100 Subject: [PATCH 611/748] Changes to account for contribution from fixed model. This is a temporary version, in which the fixed model contribution is subtracted from the input map. This will be changed when phasertng can account itself for the contribution of the fixed model. --- cctbx/maptbx/prepare_map_for_docking.py | 155 +++++++++++++++++++++++- 1 file changed, 151 insertions(+), 4 deletions(-) diff --git a/cctbx/maptbx/prepare_map_for_docking.py b/cctbx/maptbx/prepare_map_for_docking.py index 5faad12934..dcbc465342 100644 --- a/cctbx/maptbx/prepare_map_for_docking.py +++ b/cctbx/maptbx/prepare_map_for_docking.py @@ -822,7 +822,7 @@ def mask_fixed_model_region(mmm, d_min, fixed_model=None, ordered_mask_id='ordered_volume_mask', fixed_mask_id='mask_around_atoms'): - # Flatten the region of the mask covered by the fixed model + # Flatten the region of the ordered volume mask covered by the fixed model # and keep the mask for the fixed model. # Do nothing if no fixed model @@ -1436,6 +1436,13 @@ def assess_cryoem_errors( raise Sorry("Provided maps must be full-size") spacings = get_grid_spacings(unit_cell,unit_cell_grid) ucpars = unit_cell.parameters() + # Determine voxel count for fixed model mask + mm_model_mask = mmm.get_map_manager_by_id('mask_around_atoms') + voxels_in_model = 0 + if mm_model_mask is not None: + model_mask_data = mm_model_mask.map_data() + mask_sel = model_mask_data > 0 + voxels_in_model = mask_sel.count(True) # Keep track of shifted origin origin_shift = mmm.map_manager().origin_shift_grid_units @@ -1534,10 +1541,18 @@ def assess_cryoem_errors( working_mmm.apply_mask_to_maps() mask_info = working_mmm.mask_info() + working_map_size = working_mmm.map_data().size() box_volume = uc.volume() * ( - working_mmm.map_data().size()/mmm.map_data().size()) + working_map_size/mmm.map_data().size()) weighted_masked_volume = box_volume * mask_info.mean + voxels_in_masked_model = 0 + if voxels_in_model > 0: + mask_info = working_mmm.mask_info(mask_id='mask_around_atoms') + mm_model_mask = working_mmm.get_map_manager_by_id('mask_around_atoms') + model_mask_data = mm_model_mask.map_data() + voxels_in_masked_model = working_map_size * mask_info.mean + # Calculate an oversampling ratio defined as the ratio between the size of # the cut-out cube and the size of a cube that could contain a sphere # big enough to hold the volume of ordered density. Because the ratio of @@ -1846,6 +1861,22 @@ def assess_cryoem_errors( working_mmm.remove_map_manager_by_id('map_manager_1') working_mmm.remove_map_manager_by_id('map_manager_2') + # If there is a fixed model and it occupies a significant part of the sphere, + # compute the structure factors corresponding to the cutout density for the fixed + # model. + + masked_model_contributes = False + masked_model_E = None + masked_model_sigmaA = None + fraction_masked = voxels_in_masked_model/working_map_size + if fraction_masked > 0.01: + print("Masked voxels from fixed model, total in box, fraction: ", + voxels_in_masked_model, working_map_size, fraction_masked, file=log) + masked_model_contributes = True + mm_masked_model = working_mmm.get_map_manager_by_id(map_id='fixed_atom_map') + mm_masked_model.write_map('masked_model.map') + masked_model_E = mm_masked_model.map_as_fourier_coefficients(d_min=d_min,d_max=d_max) + shift_cart = working_mmm.shift_cart() if shift_map_origin: ucwork = expectE.crystal_symmetry().unit_cell() @@ -1855,6 +1886,116 @@ def assess_cryoem_errors( shift_frac = ucwork.fractionalize(shift_cart) shift_frac = tuple(-flex.double(shift_frac)) expectE = expectE.translational_shift(shift_frac) + if masked_model_contributes: + masked_model_E = masked_model_E.translational_shift(shift_frac) + # write_mtz(expectE,"expectE.mtz","eE") + # write_mtz(masked_model_E,"masked_model.mtz","masked_model") + + expectE_mod = expectE.deep_copy() # For temporary kludge where expectE is modified instead of adding fixed contribution in phasertng + if masked_model_contributes: + masked_model_sigmaA = expectE.customized_copy(data=flex.double(expectE.size(),0)) + xdat = [] + ydat = [] + wdat = [] + expectE.use_binner_of(mc1) + for i_bin in mc1.binner().range_used(): + sel = expectE.binner().selection(i_bin) + eEsel = expectE.select(sel) + abseE = eEsel.amplitudes().data() + p1 = eEsel.phases().data() + masked_coeffs_sel = masked_model_E.select(sel) + absEc = masked_coeffs_sel.amplitudes().data() + sigmaP = flex.mean_default(flex.pow2(absEc),0.) + absEc /= math.sqrt(sigmaP) + masked_model_E.data().set_selected(sel, + masked_model_E.data().select(sel) / math.sqrt(sigmaP)) + masked_coeffs_sel /= math.sqrt(sigmaP) + p2 = masked_coeffs_sel.phases().data() + cosdphi = flex.cos(p2 - p1) + dobssel = dobs.data().select(sel) + + # Solve for sigmaA yielding 1st derivative of LLG approximately equal to zero (assuming only numerator matters) + sum0 = flex.sum(2.*dobssel*abseE*absEc*cosdphi) + sum1 = flex.sum(2*flex.pow2(dobssel) * (1. - flex.pow2(abseE) - flex.pow2(absEc))) + sum2 = flex.sum(2*flex.pow(dobssel,3)*abseE*absEc*cosdphi) + sum3 = flex.sum(- 2*flex.pow(dobssel,4)) + u1 = -2*sum2**3 + 9*sum1*sum2*sum3 - 27*sum0*sum3**2 + sqrt_arg = u1**2 - 4*(sum2**2 - 3*sum1*sum3)**3 + if sqrt_arg < 0: # Paranoia: haven't run into this in a wide variety of calculations + raise Sorry("Argument of square root in sigmaA calculation is negative") + third = 1./3 + x1 = (u1 + math.sqrt(sqrt_arg))**third + sigmaA = ( (2 * 2.**third * sum2**2 - 6 * 2.**third*sum1*sum3 + - 2*sum2*x1 + 2.**(2*third) * x1**2) / + (6 * sum3 * x1) ) + sigmaA = max(min(sigmaA,0.999),1.E-6) + # Now work out approximate e.s.d. of sigmaA estimate from 2nd derivative of LLG at optimal sigmaA + denom = flex.pow((1-flex.pow2(dobssel)*sigmaA**2),3) + sum0 = flex.sum((2*flex.pow2(dobssel) * (1. - flex.pow2(abseE) - flex.pow2(absEc)))/denom) + sum1 = flex.sum((12*flex.pow(dobssel,3)*abseE*absEc*cosdphi)/denom) + sum2 = flex.sum((-6*flex.pow(dobssel,4)*(flex.pow2(abseE) + flex.pow2(absEc)))/denom) + sum3 = flex.sum((4*flex.pow(dobssel,5)*abseE*absEc*cosdphi)/denom) + sum4 = flex.sum((-2*flex.pow(dobssel,6))/denom) + d2LLGbydsigmaA = sum0 + sum1*sigmaA + sum2*sigmaA**2 + sum3*sigmaA**3 + sum4*sigmaA**4 + d2LLGbydsigmaA /= over_sampling_factor + sigma_sigmaA = 1./math.sqrt(abs(d2LLGbydsigmaA)) + ssqr = flex.mean_default(eEsel.d_star_sq().data(),0) + ndat = dobssel.size() + print(ndat,ssqr,sigmaA,sigma_sigmaA) + xdat.append(ssqr) + ydat.append(math.log(sigmaA)) + wdat.append(abs(d2LLGbydsigmaA)) # Inverse variance estimate + + xdat = flex.double(xdat) + ydat = flex.double(ydat) + wdat = flex.double(wdat) + W = flex.sum(wdat) + Wx = flex.sum(wdat * xdat) + Wy = flex.sum(wdat * ydat) + Wxx = flex.sum(wdat * xdat * xdat) + Wxy = flex.sum(wdat * xdat * ydat) + slope = (W * Wxy - Wx * Wy) / (W * Wxx - Wx * Wx) + intercept = (Wy * Wxx - Wx * Wxy) / (W * Wxx - Wx * Wx) + frac_complete = math.exp(2.*intercept) + print("Slope and intercept of sigmaA plot: ",slope,intercept,file=log) + print("Approximate fraction of scattering: ",frac_complete,file=log) + linlogsiga = flex.double() + logsiga_combined = flex.double() + sigma_linlog = math.log(1.5) # Allow 50% error in linear fit + i_bin_used = 0 + for i_bin in mc1.binner().range_used(): + sigmaA = math.exp(ydat[i_bin_used]) + # For complete model, slope should be negative, but can be positive if the + # modelled part is much better ordered than the larger unmodelled part + linlog = min(math.log(0.999),(intercept + slope*xdat[i_bin_used])) + linlogsiga.append(linlog) + sigma_sigmaA = 1./math.sqrt(wdat[i_bin_used]) + sigma_lnsigmaA = math.exp(-ydat[i_bin_used])*sigma_sigmaA + combined_logsiga = ((ydat[i_bin_used]/sigma_lnsigmaA**2 + linlog/sigma_linlog**2) / + (1./sigma_lnsigmaA**2 + 1./sigma_linlog**2) ) + logsiga_combined.append(combined_logsiga) + combined_siga = math.exp(combined_logsiga) + + sel = expectE.binner().selection(i_bin) + expectE_mod.data().set_selected(sel, expectE_mod.data().select(sel) + - math.exp(combined_logsiga)*dobs.data().select(sel) + * masked_model_E.data().select(sel) ) + masked_model_sigmaA.data().set_selected(sel, combined_siga) + i_bin_used += 1 + + if False: + import matplotlib.pyplot as plt + fig, ax = plt.subplots(2,1) + ax[0].plot(xdat,ydat,label="ln(sigmaA)") + ax[0].plot(xdat,linlogsiga,label="line fit") + ax[0].plot(xdat,logsiga_combined,label="combined") + ax[0].legend(loc="upper right") + ax[1].plot(xdat,flex.exp(ydat),label="sigmaA") + ax[1].plot(xdat,flex.exp(linlogsiga),label="line fit") + ax[1].plot(xdat,flex.exp(logsiga_combined),label="combined") + ax[1].legend(loc="lower left") + plt.show() + # write_mtz(expectE_mod,"expectE_mod.mtz","expectEmod") ssqmin = flex.min(mc1.d_star_sq().data()) ssqmax = flex.max(mc1.d_star_sq().data()) @@ -1872,7 +2013,9 @@ def assess_cryoem_errors( new_mmm = working_mmm, shift_cart = shift_cart, sphere_center = list(sphere_cent_map), - expectE = expectE, dobs = dobs, + expectE = expectE_mod, dobs = dobs, # Temporary kludge + # expectE = expectE, dobs = dobs, + masked_model_E = masked_model_E, masked_model_sigmaA = masked_model_sigmaA, over_sampling_factor = over_sampling_factor, fraction_scattering = fraction_scattering, weighted_map_noise = weighted_map_noise, @@ -1979,7 +2122,11 @@ def run(): mm1 = dm.get_real_map(map1_filename) map2_filename = args.map2 mm2 = dm.get_real_map(map2_filename) - mmm = map_model_manager(model=fixed_model, map_manager_1=mm1, map_manager_2=mm2) + mmm = map_model_manager(map_manager_1=mm1, map_manager_2=mm2) + + if (fixed_model): + mmm.add_model_by_id(model=fixed_model, model_id='fixed_model') + mmm.generate_map(model=fixed_model, d_min=d_min, map_id='fixed_atom_map') if determine_ordered_volume: mask_id = 'ordered_volume_mask' From 7319c633369b6536b57906f75075de2d77c88a53 Mon Sep 17 00:00:00 2001 From: randyjread Date: Tue, 6 Aug 2024 13:21:20 +0100 Subject: [PATCH 612/748] Don't write out masked_model.map. --- cctbx/maptbx/prepare_map_for_docking.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cctbx/maptbx/prepare_map_for_docking.py b/cctbx/maptbx/prepare_map_for_docking.py index dcbc465342..552062effd 100644 --- a/cctbx/maptbx/prepare_map_for_docking.py +++ b/cctbx/maptbx/prepare_map_for_docking.py @@ -1874,7 +1874,7 @@ def assess_cryoem_errors( voxels_in_masked_model, working_map_size, fraction_masked, file=log) masked_model_contributes = True mm_masked_model = working_mmm.get_map_manager_by_id(map_id='fixed_atom_map') - mm_masked_model.write_map('masked_model.map') + # mm_masked_model.write_map('masked_model.map') masked_model_E = mm_masked_model.map_as_fourier_coefficients(d_min=d_min,d_max=d_max) shift_cart = working_mmm.shift_cart() From 6d23008b511221fb7ca9e766da6a35a2fc38e073 Mon Sep 17 00:00:00 2001 From: randyjread Date: Tue, 6 Aug 2024 13:55:46 +0100 Subject: [PATCH 613/748] Fix bug for when d_min is not specified. --- cctbx/maptbx/prepare_map_for_docking.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cctbx/maptbx/prepare_map_for_docking.py b/cctbx/maptbx/prepare_map_for_docking.py index 552062effd..490e9359b3 100644 --- a/cctbx/maptbx/prepare_map_for_docking.py +++ b/cctbx/maptbx/prepare_map_for_docking.py @@ -829,7 +829,9 @@ def mask_fixed_model_region(mmm, d_min, if fixed_model is None: return - radius = max(3., d_min) + radius = 3. + if d_min is not None: + radius = max(radius, d_min) mmm.create_mask_around_atoms(model=fixed_model, mask_atoms_atom_radius=radius, mask_id=fixed_mask_id) fixed_model_mask = mmm.get_map_manager_by_id(map_id=fixed_mask_id) # Invert fixed_model_mask before flattening From c9f86987acd158917e5f5b3ef3a1637ec0154b66 Mon Sep 17 00:00:00 2001 From: randyjread Date: Wed, 7 Aug 2024 17:00:07 +0100 Subject: [PATCH 614/748] Set verbosity level for print statements about fixed model contribution. --- cctbx/maptbx/prepare_map_for_docking.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/cctbx/maptbx/prepare_map_for_docking.py b/cctbx/maptbx/prepare_map_for_docking.py index 490e9359b3..8b2884b974 100644 --- a/cctbx/maptbx/prepare_map_for_docking.py +++ b/cctbx/maptbx/prepare_map_for_docking.py @@ -1872,8 +1872,9 @@ def assess_cryoem_errors( masked_model_sigmaA = None fraction_masked = voxels_in_masked_model/working_map_size if fraction_masked > 0.01: - print("Masked voxels from fixed model, total in box, fraction: ", - voxels_in_masked_model, working_map_size, fraction_masked, file=log) + if verbosity > 1: + print("Masked voxels from fixed model, total in box, fraction: ", + voxels_in_masked_model, working_map_size, fraction_masked, file=log) masked_model_contributes = True mm_masked_model = working_mmm.get_map_manager_by_id(map_id='fixed_atom_map') # mm_masked_model.write_map('masked_model.map') @@ -1900,6 +1901,9 @@ def assess_cryoem_errors( ydat = [] wdat = [] expectE.use_binner_of(mc1) + if verbosity > 1: + print("SigmaA curve for fixed model contribution",file=log) + print(" # of terms mean(ssqr) sigmaA sigma(sigmaA)") for i_bin in mc1.binner().range_used(): sel = expectE.binner().selection(i_bin) eEsel = expectE.select(sel) @@ -1943,7 +1947,8 @@ def assess_cryoem_errors( sigma_sigmaA = 1./math.sqrt(abs(d2LLGbydsigmaA)) ssqr = flex.mean_default(eEsel.d_star_sq().data(),0) ndat = dobssel.size() - print(ndat,ssqr,sigmaA,sigma_sigmaA) + if verbosity > 1: + print(ndat,ssqr,sigmaA,sigma_sigmaA,file=log) xdat.append(ssqr) ydat.append(math.log(sigmaA)) wdat.append(abs(d2LLGbydsigmaA)) # Inverse variance estimate @@ -1959,8 +1964,9 @@ def assess_cryoem_errors( slope = (W * Wxy - Wx * Wy) / (W * Wxx - Wx * Wx) intercept = (Wy * Wxx - Wx * Wxy) / (W * Wxx - Wx * Wx) frac_complete = math.exp(2.*intercept) - print("Slope and intercept of sigmaA plot: ",slope,intercept,file=log) - print("Approximate fraction of scattering: ",frac_complete,file=log) + if verbosity > 0: + print("Slope and intercept of sigmaA plot for fixed model contribution: ",slope,intercept,file=log) + print("Approximate fraction of scattering: ",frac_complete,file=log) linlogsiga = flex.double() logsiga_combined = flex.double() sigma_linlog = math.log(1.5) # Allow 50% error in linear fit From 9158e1d1fc83a81625e1543856cbaf413f7137a8 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Wed, 7 Aug 2024 21:25:22 -0700 Subject: [PATCH 615/748] Comment out excessive check. Mark and safeguard non-used function. --- mmtbx/monomer_library/linking_mixins.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index 6578aa448a..d7554f4dfc 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -283,6 +283,10 @@ def check_for_peptide_links(atom1, return False def check_all_classes(pdb_hierarchy, class_type): + """ This one is not used anywhere. + If start using it, beware of getting classes for all atoms + """ + assert 0 found = False for residue_group in pdb_hierarchy.residue_groups(): for atom in residue_group.atoms(): @@ -513,9 +517,11 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., print("Distance: %0.2f" % distance, rt_mx_ji, sym_op) # don't link atoms not in the same conformer (works for models also)... - if not atom1.is_in_same_conformer_as(atom2): - assert 0 - continue + # They will never be in different conformers, we are looping over + # nonbonded interactions here! This check takes 14% of this whole function. + # if not atom1.is_in_same_conformer_as(atom2): + # assert 0 + # continue # don't link atoms in same residue group if atom1.parent().parent()==atom2.parent().parent(): continue atom_group1 = atom1.parent() From 1b127403daf3019ab2b98014ce581fe131fb8463 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Wed, 7 Aug 2024 21:56:21 -0700 Subject: [PATCH 616/748] pdb_int speedup 5%: Call atom_classes once per atom and then use the results. --- mmtbx/monomer_library/linking_mixins.py | 33 ++++++++++++++----------- mmtbx/monomer_library/linking_utils.py | 23 +++++++++-------- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index d7554f4dfc..a5a4ff157f 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -254,9 +254,9 @@ def possible_cyclic_peptide(atom1, def check_for_peptide_links(atom1, atom2, + classes1, + classes2, ): - classes1 = linking_utils.get_classes(atom1) - classes2 = linking_utils.get_classes(atom2) atom_group1 = atom1.parent() atom_group2 = atom2.parent() if classes1.common_amino_acid or classes2.common_amino_acid: @@ -432,6 +432,7 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., exclude_out_lines = {} # main loop + atom_classes = [linking_utils.get_classes(a) for a in atoms] nonbonded_proxies, sites_cart, pair_asu_table, asu_mappings, nonbonded_i_seqs = \ _nonbonded_pair_objects(max_bonded_cutoff=max_bonded_cutoff, ) @@ -532,8 +533,8 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., elif atom_group2.altloc.strip()=="": pass else: continue # don't link some classes - classes1 = linking_utils.get_classes(atom1) - classes2 = linking_utils.get_classes(atom2) + classes1 = atom_classes[i_seq] + classes2 = atom_classes[j_seq] use_only_bond_cutoff = False if verbose: print(""" @@ -588,6 +589,8 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., aa_rc = linking_utils.is_atom_pair_linked( atom1, atom2, + classes1.important_only, + classes2.important_only, distance=distance, max_bonded_cutoff=max_bonded_cutoff, amino_acid_bond_cutoff=amino_acid_bond_cutoff, @@ -602,6 +605,8 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., if not linking_utils.is_atom_pair_linked( atom1, atom2, + classes1.important_only, + classes2.important_only, distance=distance, max_bonded_cutoff=max_bonded_cutoff, amino_acid_bond_cutoff=amino_acid_bond_cutoff, @@ -634,12 +639,8 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., continue # got a link.... - class1 = linking_utils.get_classes(atom1, #_group1.resname, - important_only=True, - ) - class2 = linking_utils.get_classes(atom2, #_group2.resname, - important_only=True, - ) + class1 = classes1.important_only + class2 = classes2.important_only class_key = [class1, class2] class_key.sort() class_key = tuple(class_key) @@ -747,6 +748,8 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., if link is None: link, swap, key = linking_utils.is_atom_pair_linked_tuple(atom1, atom2, + classes1.important_only, + classes2.important_only, ) if link=='TRANS': key=link @@ -870,7 +873,7 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., continue else: # possible peptide or rna/dna link - rc = check_for_peptide_links(atom1, atom2) + rc = check_for_peptide_links(atom1, atom2, classes1, classes2) # no peptide links across symmetry if len(done_key)==3: rc = None @@ -933,8 +936,8 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., (classes2.common_rna_dna or classes2.ccp4_mon_lib_rna_dna)): bond_name = "h-dna" assert 0 - elif (linking_utils.get_classes(atom1, important_only=True)=="metal" or - linking_utils.get_classes(atom2, important_only=True)=="metal"): + elif (class1=="metal" or + class2=="metal"): origin_id = origin_ids['metal coordination'] if sym_op: sym_bonds += 1 @@ -987,8 +990,8 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., atom1 = atoms[i_seq] atom2 = atoms[j_seq] # check for NA linkage - classes1 = linking_utils.get_classes(atom1) - classes2 = linking_utils.get_classes(atom2) + classes1 = atom_classes[i_seq] + classes2 = atom_classes[j_seq] ans = bondlength_defaults.run(atom1, atom2) equil = 2.3 weight = 0.02 diff --git a/mmtbx/monomer_library/linking_utils.py b/mmtbx/monomer_library/linking_utils.py index ff542c7c65..ee23fd2d44 100644 --- a/mmtbx/monomer_library/linking_utils.py +++ b/mmtbx/monomer_library/linking_utils.py @@ -217,7 +217,7 @@ def get_hand(c_atom, o_atom, angles, verbose=False): else: return "ALPHA" -def get_classes(atom, important_only=False, verbose=False): +def get_classes(atom, verbose=False): def _num_atoms_residue(atom): return len(atom.parent().parent().atoms()) def _filter_for_metal(atom, class_name): @@ -230,6 +230,7 @@ def _filter_for_metal(atom, class_name): return "metal" return class_name # + important_only_value = None attrs = [ "common_saccharide", "common_water", @@ -291,7 +292,9 @@ def _filter_for_metal(atom, class_name): rc = attr # if rc==attr: - if important_only: return _filter_for_metal(atom, rc) + if not important_only_value: + important_only_value = _filter_for_metal(atom, rc) + setattr(classes, "important_only", important_only_value) setattr(classes, attr, True) return classes @@ -335,10 +338,10 @@ def _get_cis_trans(): return 'TRANS' def is_atom_pair_linked_tuple(atom1, - atom2): - class1 = get_classes(atom1, important_only=True) - class2 = get_classes(atom2, important_only=True) - if class1=='common_amino_acid' and class2==class1: + atom2, + class_important_1, + class_important_2): + if class_important_1=='common_amino_acid' and class_important_2==class_important_1: if atom1.name==' N ' and atom2.name==' C ': return _get_cis_trans(), False, '?' elif atom1.name==' C ' and atom2.name==' N ': @@ -349,6 +352,8 @@ def is_atom_pair_linked_tuple(atom1, def is_atom_pair_linked(atom1, atom2, + class_important_1, + class_important_2, distance=None, max_bonded_cutoff=3., amino_acid_bond_cutoff=1.9, @@ -381,10 +386,8 @@ def is_atom_pair_linked(atom1, sulfur_bond_cutoff, other_bond_cutoff, ) - class1 = get_classes(atom1, important_only=True) - class2 = get_classes(atom2, important_only=True) - class1 = linking_setup.adjust_class(atom1, class1) - class2 = linking_setup.adjust_class(atom2, class2) + class1 = linking_setup.adjust_class(atom1, class_important_1) + class2 = linking_setup.adjust_class(atom2, class_important_2) # python3 # assert type(class1)==type(''), 'class1 of %s not singular : %s' % (atom1.quote(), class1) # assert type(class2)==type(''), 'class2 of %s not singular : %s' % (atom2.quote(), class2) From e8a2cec94987cb953df823a2a8ae5af3e26578ae Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 7 Aug 2024 14:38:53 -0700 Subject: [PATCH 617/748] iotbx: do not remove array if it is explicitly selected --- iotbx/data_manager/miller_array.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iotbx/data_manager/miller_array.py b/iotbx/data_manager/miller_array.py index d99e5122dc..6f7cd42671 100644 --- a/iotbx/data_manager/miller_array.py +++ b/iotbx/data_manager/miller_array.py @@ -418,13 +418,13 @@ def filter_arrays_by_scores(filename, arrays, test_scores): Convenience function for using scores to select arrays for removal ''' remove_set = set() - for selected_array in arrays: - selected_array_label = get_array_label(filename, selected_array) + selected_array_labels = [get_array_label(filename, selected_array) for selected_array in arrays] + for selected_array_label in selected_array_labels: if selected_array_label in score_dict: score = score_dict[selected_array_label] if score > 0 and test_scores.count(score) > 1: for array, array_label in zip(miller_arrays, miller_array_labels): - if score_dict[array_label] == score and array_label != selected_array_label: + if score_dict[array_label] == score and array_label not in selected_array_labels: remove_set.add(array) return remove_set # ------------------------------------------------------------------------- From 66671308664defbb271c77db67ba2cfb71dcd960 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 8 Aug 2024 10:15:12 -0700 Subject: [PATCH 618/748] update --- mmtbx/programs/quantum_interface.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mmtbx/programs/quantum_interface.py b/mmtbx/programs/quantum_interface.py index af0eee8743..6eced47b6b 100644 --- a/mmtbx/programs/quantum_interface.py +++ b/mmtbx/programs/quantum_interface.py @@ -1168,9 +1168,10 @@ def run_qmr(self, format, log=None): if len(rc.final_pdbs)>1: cannot_run_final_energies=True checks = 'final_strain final_energy final_bound' - fn = os.path.join('qm_work_dir', rc.final_pdbs[0][0]) - self.data_manager.process_model_file(fn) - model = self.data_manager.get_model(fn) + if rc.final_pdbs[0]: + fn = os.path.join('qm_work_dir', rc.final_pdbs[0][0]) + self.data_manager.process_model_file(fn) + model = self.data_manager.get_model(fn) if any(item in checks for item in qmr.calculate): if cannot_run_final_energies: print('Cannot run final energies. Restart with only one ligand selection.', From 318c5e062984a7ec0b136d5a001aad4a1986006c Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 8 Aug 2024 14:55:08 -0700 Subject: [PATCH 619/748] small changes to output and big change to linking sym op --- mmtbx/model/statistics.py | 6 ++++-- mmtbx/monomer_library/linking_mixins.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mmtbx/model/statistics.py b/mmtbx/model/statistics.py index 1a3631e72d..3d0772b8fa 100644 --- a/mmtbx/model/statistics.py +++ b/mmtbx/model/statistics.py @@ -328,7 +328,7 @@ def fmt2(f1): a,b,c,d,p,n = res.angle, res.bond, res.chirality, res.dihedral, \ res.planarity, res.nonbonded az, bz = res.angle_z, res.bond_z - result = """ + result = """%s %sGeometry Restraints Library: %s %sDeviations from Ideal Values - rmsd, rmsZ for bonds and angles. %s Bond : %s @@ -338,6 +338,7 @@ def fmt2(f1): %s Dihedral : %s %s Min Nonbonded Distance : %s %s"""%(#prefix.strip(), + prefix, prefix, self.restraints_source, prefix, @@ -349,7 +350,7 @@ def fmt2(f1): prefix, fmt2(n.min).strip(), prefix) if not exclude_protein_only_stats: - result += """ + result += """%s %sMolprobity Statistics. %s All-atom Clashscore : %s %s Ramachandran Plot: @@ -366,6 +367,7 @@ def fmt2(f1): %s Cis-general : %s %% %s Twisted Proline : %s %% %s Twisted General : %s %%"""%( + prefix, prefix, prefix, format_value("%5.2f", res.clash.score).strip(), prefix, diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index a5a4ff157f..47d5bd0757 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -577,7 +577,7 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., ] key.sort() if sym_op: - key.append(str(rt_mx_ji)) + key.append(str(sym_op)) key = tuple(key) # hydrogens if not exclude_hydrogens_from_bonding_decisions: From 982cf8b2d4ab270b8c7b5341936252712a465b9f Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 8 Aug 2024 16:00:22 -0600 Subject: [PATCH 620/748] Reinstate value of const_shrink_donor_acceptor=0.6 for holton_geometry_validation --- mmtbx/validation/holton_geometry_validation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index e1953e8ab9..ab5a349c29 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -991,6 +991,7 @@ def get_model(info): # Allow polymer to cross special positions if necessary p = info.model.get_current_pdb_interpretation_params() p.pdb_interpretation.allow_polymer_cross_special_position=True + p.pdb_interpretation.const_shrink_donor_acceptor=0.6 # REINSTATES ORIGINAL info.model.process(make_restraints=True, pdb_interpretation_params = p) info.model.setup_riding_h_manager(idealize=True) From f6003449e4ddcad1e824403dc2939cc095044819 Mon Sep 17 00:00:00 2001 From: terwill Date: Thu, 8 Aug 2024 16:42:07 -0600 Subject: [PATCH 621/748] Use default for const_shrink_donor_acceptor --- mmtbx/validation/holton_geometry_validation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/validation/holton_geometry_validation.py b/mmtbx/validation/holton_geometry_validation.py index ab5a349c29..0cd2c400fc 100644 --- a/mmtbx/validation/holton_geometry_validation.py +++ b/mmtbx/validation/holton_geometry_validation.py @@ -991,7 +991,7 @@ def get_model(info): # Allow polymer to cross special positions if necessary p = info.model.get_current_pdb_interpretation_params() p.pdb_interpretation.allow_polymer_cross_special_position=True - p.pdb_interpretation.const_shrink_donor_acceptor=0.6 # REINSTATES ORIGINAL + # p.pdb_interpretation.const_shrink_donor_acceptor=0.6 # REINSTATES ORIGINAL info.model.process(make_restraints=True, pdb_interpretation_params = p) info.model.setup_riding_h_manager(idealize=True) From 3d6e0149e5fdcf420a197bf5d9e9ef6303fa022e Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Fri, 9 Aug 2024 13:18:08 -0700 Subject: [PATCH 622/748] stab in the dark about SIA --- mmtbx/monomer_library/glyco_chiral_values.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mmtbx/monomer_library/glyco_chiral_values.py b/mmtbx/monomer_library/glyco_chiral_values.py index b4189ef72d..447c80b8cd 100644 --- a/mmtbx/monomer_library/glyco_chiral_values.py +++ b/mmtbx/monomer_library/glyco_chiral_values.py @@ -313,6 +313,8 @@ 'Z6J' : 2.5, 'Z9M' : 2.4, 'Z9N' : 2.7, + # edited + 'SIA' : 2.5, } alpha_beta = { '0AT' : 'alpha', @@ -627,6 +629,8 @@ 'Z6J' : 'alpha', 'Z9M' : 'beta', 'Z9N' : 'alpha', + # edited + 'SIA' : 'alpha', } if __name__=="__main__": @@ -635,5 +639,6 @@ "NAG", "FUL", "FUC", + 'SIA', ]: print(code, alpha_beta.get(code, None),volumes.get(code, None)) From a3f5f3b5ad204b29425eeb4aa66565ea17702eae Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Fri, 9 Aug 2024 13:18:49 -0700 Subject: [PATCH 623/748] QM timing info --- mmtbx/geometry_restraints/base_qm_manager.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/mmtbx/geometry_restraints/base_qm_manager.py b/mmtbx/geometry_restraints/base_qm_manager.py index 4ea95fe7ea..2ec00671bb 100644 --- a/mmtbx/geometry_restraints/base_qm_manager.py +++ b/mmtbx/geometry_restraints/base_qm_manager.py @@ -426,7 +426,23 @@ def get_gradients(self): assert 0 def get_timings(self, energy=None): - if not self.times: return '-' + if not self.times: + filename = self.get_log_filename() + if os.path.exists(filename): + f=open(filename, 'r') + lines=f.read() + del f + for line in lines.splitlines(): + #TOTAL JOB TIME: 1622.77 SECONDS + if line.find('TOTAL JOB TIME:')>-1: + print(line) + # print(energy) + # if energy is None: + # rc=self.read_energy() + # print(rc) + return ' Timings : %0.2fs' % float(line.split()[3]) + # assert 0 + return '-' f=' Timings : %0.2fs (%ss)' % ( self.times[-1], self.times.format_mean(format='%.2f')) From 54e44a756e0e29cac618f75c8d114e8d0f440c28 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Fri, 9 Aug 2024 14:27:47 -0700 Subject: [PATCH 624/748] documentation --- mmtbx/monomer_library/pdb_interpretation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index 6978eed650..b6835511e1 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -1868,6 +1868,7 @@ def get_lib_link(mon_lib_srv, group_1 = comp_1.chem_comp.group group_2 = comp_2.chem_comp.group matches = [] + # this list seems to be only from GeoStd - NWM for link_link_id in mon_lib_srv.link_link_id_list: chem_link = link_link_id.chem_link if (chem_link.name in cif_types.non_chain_links): continue From db69383ca7d1bd533012ab5cb7f64340a4488afd Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Sun, 11 Aug 2024 04:28:47 -0700 Subject: [PATCH 625/748] DataManager: Add check to ensure low_resolution > high_resolution --- iotbx/data_manager/common.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iotbx/data_manager/common.py b/iotbx/data_manager/common.py index e10d232357..1ebdf39f64 100644 --- a/iotbx/data_manager/common.py +++ b/iotbx/data_manager/common.py @@ -227,6 +227,10 @@ def get_fmodel(self, dpg = None if(model.crystal_symmetry() is not None): dpg = model.crystal_symmetry().space_group().build_derived_point_group() + # if both low_resolution and high_resolution are set, check that low_resolution > high_resolution + if parameters.low_resolution is not None and parameters.high_resolution is not None \ + and parameters.low_resolution < parameters.high_resolution: + raise Sorry('The low_resolution parameter is less than the high_resolution parameter. Please swap those values.') data = extract_xtal_data.run( keep_going = not tmp_p.r_free_flags.required, extract_r_free_flags = not tmp_p.r_free_flags.ignore_r_free_flags, From 04736bbeb359546e69ea5fc7903900a7e2001ea8 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Mon, 12 Aug 2024 07:33:28 -0700 Subject: [PATCH 626/748] dumb error --- mmtbx/geometry_restraints/base_qm_manager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmtbx/geometry_restraints/base_qm_manager.py b/mmtbx/geometry_restraints/base_qm_manager.py index 2ec00671bb..1c064586c9 100644 --- a/mmtbx/geometry_restraints/base_qm_manager.py +++ b/mmtbx/geometry_restraints/base_qm_manager.py @@ -426,6 +426,7 @@ def get_gradients(self): assert 0 def get_timings(self, energy=None): + return '-' if not self.times: filename = self.get_log_filename() if os.path.exists(filename): From d723c64ab7dd9f8af0220ef3e112f9e4525d91ad Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 12 Aug 2024 18:06:00 -0700 Subject: [PATCH 627/748] pdb_int speedup 10%. Create atom quotes only when need them to raise Sorry. Faster way to check if atoms are there. --- .../multi_residue_cdl_class.py | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/mmtbx/conformation_dependent_library/multi_residue_cdl_class.py b/mmtbx/conformation_dependent_library/multi_residue_cdl_class.py index bee56c1905..98ff3c86d1 100644 --- a/mmtbx/conformation_dependent_library/multi_residue_cdl_class.py +++ b/mmtbx/conformation_dependent_library/multi_residue_cdl_class.py @@ -293,21 +293,22 @@ def _get_i_seqs(names): else: assert 0, 'names %s not found' % names # adjust X-N-H angles to obtain planar - nh_atoms = {} - error_atoms = [] - for atom in self[0].atoms(): - error_atoms.append('%s\n' %atom.quote()) - if atom.name.strip() in ['C']: - nh_atoms[atom.name.strip()] = atom - for atom in self[1].atoms(): - error_atoms.append('%s\n' %atom.quote()) - if atom.name.strip() in ['N', 'H', 'CA']: - nh_atoms[atom.name.strip()] = atom - if len(nh_atoms)==4: + nh_atoms = 0 + if self[0].find_atom_by(name=" C "): + nh_atoms += 1 + for name in [" N ", " CA ", ' H ']: + if self[1].find_atom_by(name=name): + nh_atoms += 1 + if nh_atoms == 4: CNCA = _get_angle_proxy(_get_i_seqs(["C_minus_1", "N_i", "CA_i"])) CNH = _get_angle_proxy(_get_i_seqs(["C_minus_1", "N_i", "H_i"])) CANH = _get_angle_proxy(_get_i_seqs(["CA_i", "N_i", "H_i"])) if not (CNH and CANH): + error_atoms = [] + for atom in self[0].atoms(): + error_atoms.append('%s\n' %atom.quote()) + for atom in self[1].atoms(): + error_atoms.append('%s\n' %atom.quote()) raise Sorry(''' Certain angles in the protein chain (C-N-H or CA-N-H) have not been found in the restraints by the Conformational Dependent Library. This usually From 50c7b7210bdb59ef1fe751b9146390e599449e3a Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 13 Aug 2024 11:35:05 -0700 Subject: [PATCH 628/748] Decluttering Phenix: archive phenix.evalurama --- mmtbx/command_line/evalurama.py | 7 -- mmtbx/programs/evalurama.py | 59 --------- mmtbx/validation/evalurama.py | 210 -------------------------------- 3 files changed, 276 deletions(-) delete mode 100644 mmtbx/command_line/evalurama.py delete mode 100644 mmtbx/programs/evalurama.py delete mode 100644 mmtbx/validation/evalurama.py diff --git a/mmtbx/command_line/evalurama.py b/mmtbx/command_line/evalurama.py deleted file mode 100644 index cf9bbbcba9..0000000000 --- a/mmtbx/command_line/evalurama.py +++ /dev/null @@ -1,7 +0,0 @@ -from __future__ import absolute_import, division, print_function -# LIBTBX_SET_DISPATCHER_NAME phenix.evalurama - -from mmtbx.programs import evalurama -from iotbx.cli_parser import run_program - -run_program(evalurama.Program) diff --git a/mmtbx/programs/evalurama.py b/mmtbx/programs/evalurama.py deleted file mode 100644 index f3d4af7ece..0000000000 --- a/mmtbx/programs/evalurama.py +++ /dev/null @@ -1,59 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, division, print_function - -from libtbx.program_template import ProgramTemplate - -from mmtbx.validation import evalurama -from mmtbx.validation import ramalyze -from collections import OrderedDict -import six - -# ============================================================================= - -class Program(ProgramTemplate): - - description = ''' -phenix.evalurama: tool for checking distribution of points inside favored - ramachandran region - -Usage examples: - phenix.evalurama model1.pdb - ''' - - datatypes = ['model', 'phil'] - - master_phil_str = """\ - include scope mmtbx.validation.evalurama.master_phil_str -""" - - # --------------------------------------------------------------------------- - def validate(self): - print('Validating inputs', file=self.logger) - self.data_manager.has_models(expected_n=1, exact_count=False, raise_sorry=True) - m = self.data_manager.get_model() - assert m.get_hierarchy().models_size() == 1 - - # --------------------------------------------------------------------------- - def run(self): - models = [] - for name in self.data_manager.get_model_names(): - models.append(self.data_manager.get_model(name)) - - self.evalurama = evalurama.eval( - models = models, - params = self.params.evalurama, - log = self.logger) - - results = self.evalurama.get_results() - res_sorted = OrderedDict(sorted(results.items())) - print("", file=self.logger) - print("Grand total results:", file=self.logger) - print("Rama type Peak coordinates CC Number of residues", file=self.logger) - for k, v in six.iteritems(res_sorted): - if v is not None: - print("%10s %-30s %.3f %5d" % (ramalyze.res_type_labels[k[0]],k[1], v[0], v[1]), file=self.logger) - - # --------------------------------------------------------------------------- - def get_results(self): - return self.evalurama.get_results() - diff --git a/mmtbx/validation/evalurama.py b/mmtbx/validation/evalurama.py deleted file mode 100644 index af78fb9f5b..0000000000 --- a/mmtbx/validation/evalurama.py +++ /dev/null @@ -1,210 +0,0 @@ -from __future__ import absolute_import, division, print_function - -from mmtbx.validation.ramalyze import ramalyze, find_region_max_value, get_favored_peaks, \ - RAMALYZE_FAVORED, res_types -from libtbx.utils import null_out -from mmtbx.rotamer import ramachandran_eval -import numpy as np -from libtbx import easy_mp -from six.moves import range - - -master_phil_str = """\ -evalurama { - use_allowed = False - .type = bool - .help = include residues that are allowed but still falls into grid squares - corners_inside = 1 - .type = int - .help = for grid, how many corners of the square need to be inside favored - grid_size = 10 - .type = float - .help = for grid, what size of the squares - grid_center_on_peak = False - .type = bool - .help = center grid on peak. Otherwise, center will be (0,0) - nproc = 1 - .type = int -} -""" - -class square(object): - def __init__(self, low_left, high_right, probability=0): - self.low_left = low_left - self.high_right = high_right - self.probability = probability - self.n_points = 0 - self.prob_points = 0 - - def add_point_if_inside(self, point): - inside = False - for i in [0,1]: - for j in [0,1]: - if (self.low_left[0] <= point[0] + 360*i <= self.high_right[0] and - self.low_left[1] <= point[1] + 360*j <= self.high_right[1]): - inside = True - if inside: - self.n_points += 1 - return inside - - def _show(self): - print(self.low_left, self.high_right, self.probability, self.n_points, self.prob_points) - - -class grid(list): - def __init__(self, *args): - super(grid, self).__init__(*args) - - def scale_to_1(self): - prob_sum = 0 - for x in self: - prob_sum += x.probability - for x in self: - x.probability /= prob_sum - prob_sum = 0 - for x in self: - prob_sum += x.probability - - def add_points(self, points, stop_on_outsiders=True): - """ points: [(xy),(xy)...] """ - self.total_points = len(points) - print(" Using", self.total_points, "points") - - self.not_placed_points = 0 - for p in points: - placed = False - for x in self: - placed = x.add_point_if_inside(p) - if placed: - break - if not placed: - # basically all points in the vicinity of this peak, including outliers - # print " Rejected point:", p - self.not_placed_points += 1 - if not placed and not stop_on_outsiders: - assert 0, "point was not placed in any square (%f, %f)" % (p[0], p[1]) - self.total_points -= self.not_placed_points - print(" Total residues placed:", self.total_points) - if self.total_points > 0: - for x in self: - x.prob_points = x.n_points/self.total_points - - def get_corr(self): - a = [] - b = [] - for x in self: - a.append(x.probability) - b.append(x.prob_points) - if len(a) == 0 or len(b) == 0: - return None - if self.total_points < 30: - return None - corr = np.corrcoef(a,b) - print(" Correlation", corr[0,1]) - return corr - - def get_total_points(self): - t = 0 - for x in self: - t += x.n_points - return t - - def _show(self): - for x in self: - x._show() - -class grid_over_favored(object): - def __init__(self, rama_type, rama_region, start_point, grid_size, corners_inside, use_allowed=False): - self.rama_type = rama_type - self.rama_region = rama_region - self.start_point = start_point - self.grid_size = grid_size - self.corners_inside = corners_inside - self.r = ramachandran_eval.RamachandranEval() - self.grid = grid() # list of square objects - points_x = grid_over_favored._get_grid_points(start_point[0], grid_size) - points_y = grid_over_favored._get_grid_points(start_point[1], grid_size) - for x in points_x: - for y in points_y: - n_inside = 0 - for dx in [0,1]: - for dy in [0,1]: - reg = find_region_max_value(rama_type, x+grid_size*dx, y+grid_size*dy) - if reg is not None and reg[0] == rama_region: - n_inside += 1 - if n_inside >= corners_inside: - v = self.r.evaluate(rama_type, [x+0.5*grid_size, y+0.5*grid_size]) - self.grid.append(square((x,y), (x+grid_size, y+grid_size), v)) - print(" Number of grid cells", len(self.grid)) - - self.grid.scale_to_1() - - def add_points(self, points, stop_on_outsiders=True): - self.grid.add_points(points, stop_on_outsiders=stop_on_outsiders) - - def get_corr(self): - c = self.grid.get_corr() - if c is not None: - return c[0,1] - return None - - @staticmethod - def _get_grid_points(start_point, size): - """ returns values in [-180, 180] one of them is start point and """ - x = start_point - result = [x] - x -= size - while x >= -180: - result.append(x) - x -= size - x = start_point - x += size - while x <= 180: - result.append(x) - x += size - return sorted(result) - -def ramalyze_parallel(hierarchy): - return ramalyze(hierarchy, out=null_out()) - -class eval(object): - def __init__(self, models, params, log): - self.models = models - self.log = log - self.params = params - self.total_rama = [] - rama_res = easy_mp.pool_map( - processes=self.params.nproc, - fixed_func=ramalyze_parallel, - args=[m.get_hierarchy() for m in self.models]) - for r in rama_res: - for res in r.results: - self.total_rama.append(res) - - self.results = {} - for rama_type in range(5): - print("Working with", res_types[rama_type], "plot") - for peak in get_favored_peaks(rama_type): - print(" Working with peak:", peak) - start_point = peak[0] if self.params.grid_center_on_peak else (0,0) - gof = grid_over_favored( - rama_type=rama_type, - rama_region=peak[0], - start_point=start_point, - grid_size=self.params.grid_size, - corners_inside=self.params.corners_inside) - points = [] - for r in self.total_rama: - if (r.res_type == rama_type - and (r.rama_type == RAMALYZE_FAVORED or self.params.use_allowed) - and find_region_max_value(rama_type, r.phi, r.psi, - allow_outside=self.params.use_allowed) == peak): - points.append((r.phi, r.psi)) - gof.add_points(points, stop_on_outsiders=self.params.use_allowed) - c = gof.get_corr(), gof.grid.get_total_points() - if c.count(None) > 0: - c = None - self.results[(rama_type, peak)] = c - - def get_results(self): - return self.results From 38960db2449101d57087f695b943b77785ed7576 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Tue, 13 Aug 2024 12:52:37 -0700 Subject: [PATCH 629/748] Decluttering Phenix: remove phenix.fest --- mmtbx/command_line/fest.py | 8 - mmtbx/scaling/fest.py | 87 ---------- mmtbx/scaling/rip_scale.py | 271 ------------------------------- mmtbx/scaling/sad_scale.py | 235 --------------------------- mmtbx/scaling/sir_scale.py | 270 ------------------------------- mmtbx/scaling/siras_scale.py | 301 ----------------------------------- 6 files changed, 1172 deletions(-) delete mode 100644 mmtbx/command_line/fest.py delete mode 100644 mmtbx/scaling/fest.py delete mode 100644 mmtbx/scaling/rip_scale.py delete mode 100644 mmtbx/scaling/sad_scale.py delete mode 100644 mmtbx/scaling/sir_scale.py delete mode 100644 mmtbx/scaling/siras_scale.py diff --git a/mmtbx/command_line/fest.py b/mmtbx/command_line/fest.py deleted file mode 100644 index f2eb905efe..0000000000 --- a/mmtbx/command_line/fest.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import absolute_import, division, print_function -# LIBTBX_SET_DISPATCHER_NAME phenix.fest - -from mmtbx.scaling import fest -import sys - -if (__name__ == "__main__"): - fest.run(args=sys.argv[1:]) diff --git a/mmtbx/scaling/fest.py b/mmtbx/scaling/fest.py deleted file mode 100644 index 500a8fed6c..0000000000 --- a/mmtbx/scaling/fest.py +++ /dev/null @@ -1,87 +0,0 @@ -from __future__ import absolute_import, division, print_function -from libtbx.utils import Sorry -from mmtbx.scaling import sad_scale, sir_scale, rip_scale, siras_scale -from mmtbx.scaling import twmad_scale -import sys - - -def print_banner(command_name): - hashes = "#########################################" - subtitle = "#### Delta F and FA estimation ####" - n = len(hashes) - 10 - len(command_name) - left = " " * (n//2) - right = left + " " * (n%2) - print(hashes) - print("#### %s%s%s ####" % (left, command_name, right)) - print(subtitle) - print(hashes) - -def run(args, command_name="phenix.fest"): - print_banner(command_name=command_name) - - scenarios = [ "SAD",#0 - - "SIR",#1 - "RIP",#2 - - "SIRAS",#3 - "RIPAS",#4 - - "MIR",#5 - "MIRAS",#6 - - "2WMAD",#7 - "3WMAD",#8 - "4WMAD",#9 - - "2WMAD+NAT",#10 - "3WMAD+NAT",#11 - "4WMAD+NAT",#12 - - "2WSAD",#13 - "3WSAD",#14 - "4WSAD" ]#15 - if len(args)==0: - print() - print("usage: %s " \ - % command_name) - print() - raise Sorry("No instructions received") - - if args[0] in scenarios: - print("experiment: " , args[0]) - else: - print("Unknown experiment type") - print(" Choose from the following list:") - for method in scenarios: - print(method) - - raise Sorry("Unmknown experimenttype") - - ## this is a rather ugly enumeration of all cases - if args[0]==scenarios[0]: - sad_scale.run( args[1:] ) - - elif args[0]==scenarios[1]: - sir_scale.run( args[1:] ) - - elif args[0]==scenarios[2]: - rip_scale.run( args[1:] ) - - elif args[0]==scenarios[3]: - siras_scale.run( args[1:] ) - - elif args[0]==scenarios[4]: - siras_scale.run( args[1:] ) - - elif args[0]==scenarios[7]: - twmad_scale.run( args[1:] ) - - else: - print() - print("Sorry, no time. This method has not yet been implemented.") - print("Currently, only SAD,SIR,RIP and 2WMAD are supported.") - print() - -if (__name__ == "__main__"): - run(sys.argv[1:]) diff --git a/mmtbx/scaling/rip_scale.py b/mmtbx/scaling/rip_scale.py deleted file mode 100644 index 373ee03bdd..0000000000 --- a/mmtbx/scaling/rip_scale.py +++ /dev/null @@ -1,271 +0,0 @@ -from __future__ import absolute_import, division, print_function -from cctbx import crystal -from libtbx.utils import Sorry, date_and_time, multi_out -import iotbx.phil -from iotbx import reflection_file_reader -from iotbx import reflection_file_utils -from iotbx import crystal_symmetry_from_any -import mmtbx.scaling -from mmtbx.scaling import pair_analyses -from libtbx.str_utils import StringIO -from mmtbx.scaling import pre_scale, make_param -import sys, os - - -from mmtbx.scaling import fa_estimation - -params_generator = make_param.phil_lego() -master_params = iotbx.phil.parse( params_generator.default_rip() ) - - -def run(args): - - if len(args)==0: - master_params.show(expert_level=0) - elif ( "--help" in args ): - print("no help available") - elif ( "--h" in args ): - print("no help available") - elif ( "--show_defaults" in args ): - master_params.show(expert_level=0) - elif ( "--show_defaults_all" in args ): - master_params.show(expert_level=10) - - - - else: - log = multi_out() - if (not "--quiet" in args): - log.register(label="stdout", file_object=sys.stdout) - string_buffer = StringIO() - string_buffer_plots = StringIO() - log.register(label="log_buffer", file_object=string_buffer) - - log_plots = StringIO() - print("#phil __OFF__", file=log) - print(file=log) - print(date_and_time(), file=log) - print(file=log) - print(file=log) - - phil_objects = [] - argument_interpreter = master_params.command_line_argument_interpreter( - home_scope="scaling") - - reflection_file = None - - for arg in args: - command_line_params = None - arg_is_processed = False - if arg == '--quiet': - arg_is_processed = True - ## The associated action with this keyword is implemented above - if (os.path.isfile(arg)): ## is this a file name? - ## Check if this is a phil file - try: - command_line_params = iotbx.phil.parse(file_name=arg) - except KeyboardInterrupt: raise - except Exception : pass - if command_line_params is not None: - phil_objects.append(command_line_params) - arg_is_processed = True - ## Check if this file is a reflection file - if command_line_params is None: - reflection_file = reflection_file_reader.any_reflection_file( - file_name=arg, ensure_read_access=False) - if (reflection_file is not None): - reflection_file = arg - arg_is_processed = True - ## If it is not a file, it must be a phil command - else: - try: - command_line_params = argument_interpreter.process(arg=arg) - if command_line_params is not None: - phil_objects.append(command_line_params) - arg_is_processed = True - except KeyboardInterrupt: raise - except Exception : pass - - if not arg_is_processed: - print("##----------------------------------------------##", file=log) - print("## Unknown phil-file or phil-command:", arg, file=log) - print("##----------------------------------------------##", file=log) - print(file=log) - raise Sorry("Unknown file format or phil command: %s" % arg) - - - effective_params = master_params.fetch(sources=phil_objects) - params = effective_params.extract() - - ## Now please read in the reflections files - - ## get symmetry and cell data first please - ## By default, the native cell and symmetry are used - ## as reference - crystal_symmetry_nat = None - crystal_symmetry_nat = crystal_symmetry_from_any.extract_from( - file_name=params.scaling.input.xray_data.after_burn.file_name) - - if params.scaling.input.xray_data.space_group is None: - params.scaling.input.xray_data.space_group =\ - crystal_symmetry_nat.space_group_info() - print("Using symmetry of after_burn data", file=log) - - if params.scaling.input.xray_data.unit_cell is None: - params.scaling.input.xray_data.unit_cell =\ - crystal_symmetry_nat.unit_cell() - print("Using cell of after_burn data", file=log) - - ## Check if a unit cell is defined - if params.scaling.input.xray_data.space_group is None: - raise Sorry("No space group defined") - if params.scaling.input.xray_data.unit_cell is None: - raise Sorry("No unit cell defined") - - - crystal_symmetry = crystal_symmetry = crystal.symmetry( - unit_cell = params.scaling.input.xray_data.unit_cell, - space_group_symbol = str( - params.scaling.input.xray_data.space_group) ) - - - effective_params = master_params.fetch(sources=phil_objects) - new_params = master_params.format(python_object=params) - print("Effective parameters", file=log) - print("#phil __ON__", file=log) - new_params.show(out=log, - expert_level=params.scaling.input.expert_level ) - print("#phil __END__", file=log) - print(file=log) - - ## define a xray data server - xray_data_server = reflection_file_utils.reflection_file_server( - crystal_symmetry = crystal_symmetry, - force_symmetry = True, - reflection_files=[]) - - ## Read in native data and make appropriatre selections - miller_array_native = None - miller_array_native = xray_data_server.get_xray_data( - file_name = params.scaling.input.xray_data.after_burn.file_name, - labels = params.scaling.input.xray_data.after_burn.labels, - ignore_all_zeros = True, - parameter_scope = 'scaling.input.SIR_scale.xray_data.after_burn' - ) - info_native = miller_array_native.info() - miller_array_native=miller_array_native.map_to_asu().select( - miller_array_native.indices()!=(0,0,0) ) - miller_array_native = miller_array_native.select( - miller_array_native.data() > 0 ) - ## Convert to amplitudes - if (miller_array_native.is_xray_intensity_array()): - miller_array_native = miller_array_native.f_sq_as_f() - elif (miller_array_native.is_complex_array()): - miller_array_native = abs(miller_array_native) - if not miller_array_native.is_real_array(): - raise Sorry("miller_array_native is not a real array") - miller_array_native.set_info(info = info_native) - - - - ## Read in derivative data and make appropriate selections - miller_array_derivative = None - miller_array_derivative = xray_data_server.get_xray_data( - file_name = params.scaling.input.xray_data.before_burn.file_name, - labels = params.scaling.input.xray_data.before_burn.labels, - ignore_all_zeros = True, - parameter_scope = 'scaling.input.SIR_scale.xray_data.before_burn' - ) - info_derivative = miller_array_derivative.info() - miller_array_derivative=miller_array_derivative.map_to_asu().select( - miller_array_derivative.indices()!=(0,0,0) ) - miller_array_derivative = miller_array_derivative.select( - miller_array_derivative.data() > 0 ) - ## Convert to amplitudes - if (miller_array_derivative.is_xray_intensity_array()): - miller_array_derivative = miller_array_derivative.f_sq_as_f() - elif (miller_array_derivative.is_complex_array()): - miller_array_derivative = abs(miller_array_derivative) - if not miller_array_derivative.is_real_array(): - raise Sorry("miller_array_derivative is not a real array") - miller_array_derivative.set_info(info = info_derivative) - - - - - ## As this is a SIR case, we will remove any anomalous pairs - if miller_array_derivative.anomalous_flag(): - miller_array_derivative = miller_array_derivative.average_bijvoet_mates()\ - .set_observation_type( miller_array_derivative ) - if miller_array_native.anomalous_flag(): - miller_array_native = miller_array_native.average_bijvoet_mates()\ - .set_observation_type( miller_array_native ) - - - ## Print info - print(file=log) - print("Native data", file=log) - print("===========", file=log) - miller_array_native.show_comprehensive_summary(f=log) - print(file=log) - native_pre_scale = pre_scale.pre_scaler( - miller_array_native, - params.scaling.input.scaling_strategy.pre_scaler_protocol, - params.scaling.input.basic) - miller_array_native = native_pre_scale.x1.deep_copy() - del native_pre_scale - - print(file=log) - print("Derivative data", file=log) - print("===============", file=log) - miller_array_derivative.show_comprehensive_summary(f=log) - print(file=log) - derivative_pre_scale = pre_scale.pre_scaler( - miller_array_derivative, - params.scaling.input.scaling_strategy.pre_scaler_protocol, - params.scaling.input.basic) - miller_array_derivative = derivative_pre_scale.x1.deep_copy() - del derivative_pre_scale - - scaler = fa_estimation.combined_scaling( - miller_array_native, - miller_array_derivative, - params.scaling.input.scaling_strategy.iso_protocol) - - miller_array_native = scaler.x1.deep_copy() - miller_array_derivative = scaler.x2.deep_copy() - del scaler - - print(file=log) - print("Making delta f's", file=log) - print("----------------", file=log) - print(file=log) - - delta_gen = pair_analyses.delta_generator( miller_array_native, - miller_array_derivative, - params.scaling.input.scaling_strategy.iso_protocol.nsr_bias ) - print(file=log) - print("writing mtz file", file=log) - print("----------------", file=log) - print(file=log) - - ## some assertions to make sure nothing went weerd - assert miller_array_native.observation_type() is not None - assert miller_array_derivative.observation_type() is not None - assert delta_gen.abs_delta_f.observation_type() is not None - - ## Please write out the abs_delta_f array - - mtz_dataset = delta_gen.abs_delta_f.as_mtz_dataset( - column_root_label='F'+params.scaling.input.output.outlabel) - mtz_dataset.mtz_object().write( - file_name=params.scaling.input.output.hklout) - - - - - - - -if (__name__ == "__main__"): - run(sys.argv[1:]) diff --git a/mmtbx/scaling/sad_scale.py b/mmtbx/scaling/sad_scale.py deleted file mode 100644 index af7fdbe4fc..0000000000 --- a/mmtbx/scaling/sad_scale.py +++ /dev/null @@ -1,235 +0,0 @@ -from __future__ import absolute_import, division, print_function -from cctbx import crystal -from libtbx.utils import Sorry, date_and_time, multi_out -import iotbx.phil -from iotbx import reflection_file_reader -from iotbx import reflection_file_utils -from iotbx import crystal_symmetry_from_any -import mmtbx.scaling -from mmtbx.scaling import pair_analyses -from libtbx.str_utils import StringIO -from mmtbx.scaling import pre_scale -from mmtbx.scaling import make_param -import sys, os - -from mmtbx.scaling import fa_estimation -from mmtbx.scaling import random_omit - - - -params_generator = make_param.phil_lego() -master_params = iotbx.phil.parse( params_generator.default_sad() ) - - -def run(args): - - if len(args)==0: - master_params.show(expert_level=0) - elif ( "--help" in args ): - print("no help available as yet") - elif ( "--h" in args ): - print("no help availableas yet") - elif ( "--show_defaults" in args ): - master_params.show(expert_level=0) - elif ( "--show_defaults_all" in args ): - master_params.show(expert_level=10) - else: - log = multi_out() - if (not "--quiet" in args): - log.register(label="stdout", file_object=sys.stdout) - string_buffer = StringIO() - string_buffer_plots = StringIO() - log.register(label="log_buffer", file_object=string_buffer) - - log_plots = StringIO() - print("#phil __OFF__", file=log) - print(file=log) - print(date_and_time(), file=log) - print(file=log) - print(file=log) - - phil_objects = [] - argument_interpreter = master_params.command_line_argument_interpreter( - home_scope="scaling") - - reflection_file = None - - for arg in args: - command_line_params = None - arg_is_processed = False - if arg == '--quiet': - arg_is_processed = True - ## The associated action with this keyword is implemented above - if (os.path.isfile(arg)): ## is this a file name? - ## Check if this is a phil file - try: - command_line_params = iotbx.phil.parse(file_name=arg) - except KeyboardInterrupt: raise - except Exception : pass - if command_line_params is not None: - phil_objects.append(command_line_params) - arg_is_processed = True - ## Check if this file is a reflection file - if command_line_params is None: - reflection_file = reflection_file_reader.any_reflection_file( - file_name=arg, ensure_read_access=False) - if (reflection_file is not None): - reflection_file = arg - arg_is_processed = True - ## If it is not a file, it must be a phil command - else: - try: - command_line_params = argument_interpreter.process(arg=arg) - if command_line_params is not None: - phil_objects.append(command_line_params) - arg_is_processed = True - except KeyboardInterrupt: raise - except Exception : pass - - if not arg_is_processed: - print("##----------------------------------------------##", file=log) - print("## Unknown phil-file or phil-command:", arg, file=log) - print("##----------------------------------------------##", file=log) - print(file=log) - raise Sorry("Unknown file format or phil command: %s" % arg) - - - effective_params = master_params.fetch(sources=phil_objects) - params = effective_params.extract() - - effective_params = master_params.fetch(sources=phil_objects) - new_params = master_params.format(python_object=params) - - ## Now please read in the reflections files - - ## get symmetry and cell data first please - ## By default, the native cell and symmetry are used - ## as reference - crystal_symmetry_nat = None - crystal_symmetry_nat = crystal_symmetry_from_any.extract_from( - file_name=params.scaling.input.xray_data.reference.file_name) - - if params.scaling.input.xray_data.space_group is None: - params.scaling.input.xray_data.space_group =\ - crystal_symmetry_nat.space_group_info() - print("Using symmetry of native data", file=log) - - if params.scaling.input.xray_data.unit_cell is None: - params.scaling.input.xray_data.unit_cell =\ - crystal_symmetry_nat.unit_cell() - print("Using cell of native data", file=log) - - ## Check if a unit cell is defined - if params.scaling.input.xray_data.space_group is None: - raise Sorry("No space group defined") - if params.scaling.input.xray_data.unit_cell is None: - raise Sorry("No unit cell defined") - - - crystal_symmetry = crystal_symmetry = crystal.symmetry( - unit_cell = params.scaling.input.xray_data.unit_cell, - space_group_symbol = str( - params.scaling.input.xray_data.space_group) ) - - - effective_params = master_params.fetch(sources=phil_objects) - new_params = master_params.format(python_object=params) - print("Effective parameters", file=log) - print("#phil __ON__", file=log) - new_params.show(out=log, - expert_level=params.scaling.input.expert_level) - print("#phil __END__", file=log) - print(file=log) - - ## define a xray data server - xray_data_server = reflection_file_utils.reflection_file_server( - crystal_symmetry = crystal_symmetry, - force_symmetry = True, - reflection_files=[]) - - ## Read in native data and make appropriatre selections - miller_array_native = None - miller_array_native = xray_data_server.get_xray_data( - file_name = params.scaling.input.xray_data.reference.file_name, - labels = params.scaling.input.xray_data.reference.labels, - ignore_all_zeros = True, - parameter_scope = 'scaling.input.SIR_scale.xray_data.native' - ) - info_native = miller_array_native.info() - miller_array_native=miller_array_native.map_to_asu().select( - miller_array_native.indices()!=(0,0,0) ) - miller_array_native = miller_array_native.select( - miller_array_native.data() > 0 ) - ## Convert to amplitudes - if (miller_array_native.is_xray_intensity_array()): - miller_array_native = miller_array_native.f_sq_as_f() - elif (miller_array_native.is_complex_array()): - miller_array_native = abs(miller_array_native) - if not miller_array_native.is_real_array(): - raise Sorry("miller_array_native is not a real array") - miller_array_native.set_info(info = info_native) - - - ## Print info - print(file=log) - print("Reference data", file=log) - print("==============", file=log) - miller_array_native.show_comprehensive_summary(f=log) - print(file=log) - native_pre_scale = pre_scale.pre_scaler( - miller_array_native, - params.scaling.input.scaling_strategy.pre_scaler_protocol, - params.scaling.input.basic) - miller_array_native = native_pre_scale.x1.deep_copy() - del native_pre_scale - - scaler = fa_estimation.ano_scaling( - miller_array_native, - params.scaling.input.scaling_strategy.ano_protocol) - - positive_miller = scaler.x1p.deep_copy() - negative_miller = scaler.x1n.deep_copy() - - - print(file=log) - print("Making delta f's", file=log) - print("----------------", file=log) - print(file=log) - - delta_gen = pair_analyses.delta_generator( positive_miller, - negative_miller ) - print(file=log) - print("writing mtz file", file=log) - print("----------------", file=log) - print(file=log) - - ## some assertions to make sure nothing went weerd - assert positive_miller.observation_type() is not None - assert negative_miller.observation_type() is not None - assert delta_gen.abs_delta_f.observation_type() is not None - - ## Please write out the abs_delta_f array - - mtz_dataset = delta_gen.abs_delta_f.as_mtz_dataset( - column_root_label='F'+params.scaling.input.output.outlabel) - mtz_dataset.mtz_object().write( - file_name=params.scaling.input.output.hklout) - - if params.scaling.input.omit.perform_omit: - print(file=log) - print("writing omit files", file=log) - print("------------------", file=log) - print(file=log) - omit_object = random_omit.random_omit_data( - delta_gen.abs_delta_f, - params.scaling.input.omit ) - omit_object.write_datasets() - - - - - - - -if (__name__ == "__main__"): - run(sys.argv[1:]) diff --git a/mmtbx/scaling/sir_scale.py b/mmtbx/scaling/sir_scale.py deleted file mode 100644 index 57efad664d..0000000000 --- a/mmtbx/scaling/sir_scale.py +++ /dev/null @@ -1,270 +0,0 @@ -from __future__ import absolute_import, division, print_function -from cctbx import crystal -from libtbx.utils import Sorry, date_and_time, multi_out -import iotbx.phil -from iotbx import reflection_file_reader -from iotbx import reflection_file_utils -from iotbx import crystal_symmetry_from_any -import mmtbx.scaling -from mmtbx.scaling import pair_analyses -from libtbx.str_utils import StringIO -from mmtbx.scaling import pre_scale, make_param -import sys, os - - -from mmtbx.scaling import fa_estimation - -params_generator = make_param.phil_lego() -master_params = iotbx.phil.parse( params_generator.default_sir() ) - - -def run(args): - - if len(args)==0: - master_params.show(expert_level=0) - elif ( "--help" in args ): - print("no help available") - elif ( "--h" in args ): - print("no help available") - elif ( "--show_defaults" in args ): - master_params.show(expert_level=0) - elif ( "--show_defaults_all" in args ): - master_params.show(expert_level=10) - - - - else: - log = multi_out() - if (not "--quiet" in args): - log.register(label="stdout", file_object=sys.stdout) - string_buffer = StringIO() - string_buffer_plots = StringIO() - log.register(label="log_buffer", file_object=string_buffer) - - log_plots = StringIO() - print("#phil __OFF__", file=log) - print(file=log) - print(date_and_time(), file=log) - print(file=log) - print(file=log) - - phil_objects = [] - argument_interpreter = master_params.command_line_argument_interpreter( - home_scope="scaling") - - reflection_file = None - - for arg in args: - command_line_params = None - arg_is_processed = False - if arg == '--quiet': - arg_is_processed = True - ## The associated action with this keyword is implemented above - if (os.path.isfile(arg)): ## is this a file name? - ## Check if this is a phil file - try: - command_line_params = iotbx.phil.parse(file_name=arg) - except KeyboardInterrupt: raise - except Exception : pass - if command_line_params is not None: - phil_objects.append(command_line_params) - arg_is_processed = True - ## Check if this file is a reflection file - if command_line_params is None: - reflection_file = reflection_file_reader.any_reflection_file( - file_name=arg, ensure_read_access=False) - if (reflection_file is not None): - reflection_file = arg - arg_is_processed = True - ## If it is not a file, it must be a phil command - else: - try: - command_line_params = argument_interpreter.process(arg=arg) - if command_line_params is not None: - phil_objects.append(command_line_params) - arg_is_processed = True - except KeyboardInterrupt: raise - except Exception : pass - - if not arg_is_processed: - print("##----------------------------------------------##", file=log) - print("## Unknown phil-file or phil-command:", arg, file=log) - print("##----------------------------------------------##", file=log) - print(file=log) - raise Sorry("Unknown file format or phil command: %s" % arg) - - - effective_params = master_params.fetch(sources=phil_objects) - params = effective_params.extract() - - ## Now please read in the reflections files - - ## get symmetry and cell data first please - ## By default, the native cell and symmetry are used - ## as reference - crystal_symmetry_nat = None - crystal_symmetry_nat = crystal_symmetry_from_any.extract_from( - file_name=params.scaling.input.xray_data.native.file_name) - - if params.scaling.input.xray_data.space_group is None: - params.scaling.input.xray_data.space_group =\ - crystal_symmetry_nat.space_group_info() - print("Using symmetry of native data", file=log) - - if params.scaling.input.xray_data.unit_cell is None: - params.scaling.input.xray_data.unit_cell =\ - crystal_symmetry_nat.unit_cell() - print("Using cell of native data", file=log) - - ## Check if a unit cell is defined - if params.scaling.input.xray_data.space_group is None: - raise Sorry("No space group defined") - if params.scaling.input.xray_data.unit_cell is None: - raise Sorry("No unit cell defined") - - - crystal_symmetry = crystal_symmetry = crystal.symmetry( - unit_cell = params.scaling.input.xray_data.unit_cell, - space_group_symbol = str( - params.scaling.input.xray_data.space_group) ) - - - effective_params = master_params.fetch(sources=phil_objects) - new_params = master_params.format(python_object=params) - print("Effective parameters", file=log) - print("#phil __ON__", file=log) - new_params.show(out=log, - expert_level=params.scaling.input.expert_level ) - print("#phil __END__", file=log) - print(file=log) - - ## define a xray data server - xray_data_server = reflection_file_utils.reflection_file_server( - crystal_symmetry = crystal_symmetry, - force_symmetry = True, - reflection_files=[]) - - ## Read in native data and make appropriatre selections - miller_array_native = None - miller_array_native = xray_data_server.get_xray_data( - file_name = params.scaling.input.xray_data.native.file_name, - labels = params.scaling.input.xray_data.native.labels, - ignore_all_zeros = True, - parameter_scope = 'scaling.input.SIR_scale.xray_data.native' - ) - info_native = miller_array_native.info() - miller_array_native=miller_array_native.map_to_asu().select( - miller_array_native.indices()!=(0,0,0) ) - miller_array_native = miller_array_native.select( - miller_array_native.data() > 0 ) - ## Convert to amplitudes - if (miller_array_native.is_xray_intensity_array()): - miller_array_native = miller_array_native.f_sq_as_f() - elif (miller_array_native.is_complex_array()): - miller_array_native = abs(miller_array_native) - if not miller_array_native.is_real_array(): - raise Sorry("miller_array_native is not a real array") - miller_array_native.set_info(info = info_native) - - - - ## Read in derivative data and make appropriate selections - miller_array_derivative = None - miller_array_derivative = xray_data_server.get_xray_data( - file_name = params.scaling.input.xray_data.derivative.file_name, - labels = params.scaling.input.xray_data.derivative.labels, - ignore_all_zeros = True, - parameter_scope = 'scaling.input.SIR_scale.xray_data.derivative' - ) - info_derivative = miller_array_derivative.info() - miller_array_derivative=miller_array_derivative.map_to_asu().select( - miller_array_derivative.indices()!=(0,0,0) ) - miller_array_derivative = miller_array_derivative.select( - miller_array_derivative.data() > 0 ) - ## Convert to amplitudes - if (miller_array_derivative.is_xray_intensity_array()): - miller_array_derivative = miller_array_derivative.f_sq_as_f() - elif (miller_array_derivative.is_complex_array()): - miller_array_derivative = abs(miller_array_derivative) - if not miller_array_derivative.is_real_array(): - raise Sorry("miller_array_derivative is not a real array") - miller_array_derivative.set_info(info = info_derivative) - - - - - ## As this is a SIR case, we will remove any anomalous pairs - if miller_array_derivative.anomalous_flag(): - miller_array_derivative = miller_array_derivative.average_bijvoet_mates()\ - .set_observation_type( miller_array_derivative ) - if miller_array_native.anomalous_flag(): - miller_array_native = miller_array_native.average_bijvoet_mates()\ - .set_observation_type( miller_array_native ) - - - ## Print info - print(file=log) - print("Native data", file=log) - print("===========", file=log) - miller_array_native.show_comprehensive_summary(f=log) - print(file=log) - native_pre_scale = pre_scale.pre_scaler( - miller_array_native, - params.scaling.input.scaling_strategy.pre_scaler_protocol, - params.scaling.input.basic) - miller_array_native = native_pre_scale.x1.deep_copy() - del native_pre_scale - - print(file=log) - print("Derivative data", file=log) - print("===============", file=log) - miller_array_derivative.show_comprehensive_summary(f=log) - print(file=log) - derivative_pre_scale = pre_scale.pre_scaler( - miller_array_derivative, - params.scaling.input.scaling_strategy.pre_scaler_protocol, - params.scaling.input.basic) - miller_array_derivative = derivative_pre_scale.x1.deep_copy() - del derivative_pre_scale - - scaler = fa_estimation.combined_scaling( - miller_array_native, - miller_array_derivative, - params.scaling.input.scaling_strategy.iso_protocol) - - miller_array_native = scaler.x1.deep_copy() - miller_array_derivative = scaler.x2.deep_copy() - del scaler - - print(file=log) - print("Making delta f's", file=log) - print("----------------", file=log) - print(file=log) - - delta_gen = pair_analyses.delta_generator( miller_array_native, - miller_array_derivative ) - print(file=log) - print("writing mtz file", file=log) - print("----------------", file=log) - print(file=log) - - ## some assertions to make sure nothing went weerd - assert miller_array_native.observation_type() is not None - assert miller_array_derivative.observation_type() is not None - assert delta_gen.abs_delta_f.observation_type() is not None - - ## Please write out the abs_delta_f array - - mtz_dataset = delta_gen.abs_delta_f.as_mtz_dataset( - column_root_label='F'+params.scaling.input.output.outlabel) - mtz_dataset.mtz_object().write( - file_name=params.scaling.input.output.hklout) - - - - - - - -if (__name__ == "__main__"): - run(sys.argv[1:]) diff --git a/mmtbx/scaling/siras_scale.py b/mmtbx/scaling/siras_scale.py deleted file mode 100644 index cac4397f69..0000000000 --- a/mmtbx/scaling/siras_scale.py +++ /dev/null @@ -1,301 +0,0 @@ -from __future__ import absolute_import, division, print_function -from cctbx import crystal -from libtbx.utils import Sorry, date_and_time, multi_out -import iotbx.phil -from iotbx import reflection_file_reader -from iotbx import reflection_file_utils -from iotbx import crystal_symmetry_from_any -import mmtbx.scaling -from mmtbx.scaling import pair_analyses -from libtbx.str_utils import StringIO -from mmtbx.scaling import pre_scale, make_param -import sys, os - - -from mmtbx.scaling import fa_estimation - - -params_generator = make_param.phil_lego() -master_params = iotbx.phil.parse( params_generator.default_siras() ) - -def run(args): - - if len(args)==0: - master_params.show(expert_level=0) - elif ( "--help" in args ): - print("no help available as yet") - elif ( "--h" in args ): - print("no help availableas yet") - elif ( "--show_defaults" in args ): - master_params.show(expert_level=0) - elif ( "--show_defaults_all" in args ): - master_params.show(expert_level=10) - else: - log = multi_out() - if (not "--quiet" in args): - log.register(label="stdout", file_object=sys.stdout) - string_buffer = StringIO() - string_buffer_plots = StringIO() - log.register(label="log_buffer", file_object=string_buffer) - - log_plots = StringIO() - print("#phil __OFF__", file=log) - print(file=log) - print(date_and_time(), file=log) - print(file=log) - print(file=log) - - phil_objects = [] - argument_interpreter = master_params.command_line_argument_interpreter( - home_scope="scaling") - - reflection_file = None - - for arg in args: - command_line_params = None - arg_is_processed = False - if arg == '--quiet': - arg_is_processed = True - ## The associated action with this keyword is implemented above - if (os.path.isfile(arg)): ## is this a file name? - ## Check if this is a phil file - try: - command_line_params = iotbx.phil.parse(file_name=arg) - except KeyboardInterrupt: raise - except Exception : pass - if command_line_params is not None: - phil_objects.append(command_line_params) - arg_is_processed = True - ## Check if this file is a reflection file - if command_line_params is None: - reflection_file = reflection_file_reader.any_reflection_file( - file_name=arg, ensure_read_access=False) - if (reflection_file is not None): - reflection_file = arg - arg_is_processed = True - ## If it is not a file, it must be a phil command - else: - try: - command_line_params = argument_interpreter.process(arg=arg) - if command_line_params is not None: - phil_objects.append(command_line_params) - arg_is_processed = True - except KeyboardInterrupt: raise - except Exception : pass - - if not arg_is_processed: - print("##----------------------------------------------##", file=log) - print("## Unknown phil-file or phil-command:", arg, file=log) - print("##----------------------------------------------##", file=log) - print(file=log) - raise Sorry("Unknown file format or phil command: %s" % arg) - - - effective_params = master_params.fetch(sources=phil_objects) - params = effective_params.extract() - - - ## Now please read in the reflections files - - ## get symmetry and cell data first please - ## By default, the native cell and symmetry are used - ## as reference - crystal_symmetry_nat = None - print(params.scaling.input.xray_data.native.file_name) - crystal_symmetry_nat = crystal_symmetry_from_any.extract_from( - file_name=params.scaling.input.xray_data.native.file_name) - - if params.scaling.input.xray_data.space_group is None: - params.scaling.input.xray_data.space_group =\ - crystal_symmetry_nat.space_group_info() - print("Using symmetry of native data", file=log) - - if params.scaling.input.xray_data.unit_cell is None: - params.scaling.input.xray_data.unit_cell =\ - crystal_symmetry_nat.unit_cell() - print("Using cell of native data", file=log) - - ## Check if a unit cell is defined - if params.scaling.input.xray_data.space_group is None: - raise Sorry("No space group defined") - if params.scaling.input.xray_data.unit_cell is None: - raise Sorry("No unit cell defined") - - - crystal_symmetry = crystal_symmetry = crystal.symmetry( - unit_cell = params.scaling.input.xray_data.unit_cell, - space_group_symbol = str( - params.scaling.input.xray_data.space_group) ) - - - effective_params = master_params.fetch(sources=phil_objects) - new_params = master_params.format(python_object=params) - print("Effective parameters", file=log) - print("#phil __ON__", file=log) - new_params.show(out=log,expert_level=effective_params.expert_level) - print("#phil __END__", file=log) - print(file=log) - - ## define a xray data server - xray_data_server = reflection_file_utils.reflection_file_server( - crystal_symmetry = crystal_symmetry, - force_symmetry = True, - reflection_files=[]) - - ## Read in native data and make appropriatre selections - miller_array_native = None - miller_array_native = xray_data_server.get_xray_data( - file_name = params.scaling.input.xray_data.native.file_name, - labels = params.scaling.input.xray_data.native.labels, - ignore_all_zeros = True, - parameter_scope = 'scaling.input.SIR_scale.xray_data.native' - ) - info_native = miller_array_native.info() - miller_array_native=miller_array_native.map_to_asu().select( - miller_array_native.indices()!=(0,0,0) ) - miller_array_native = miller_array_native.select( - miller_array_native.data() > 0 ) - ## Convert to amplitudes - if (miller_array_native.is_xray_intensity_array()): - miller_array_native = miller_array_native.f_sq_as_f() - elif (miller_array_native.is_complex_array()): - miller_array_native = abs(miller_array_native) - if not miller_array_native.is_real_array(): - raise Sorry("miller_array_native is not a real array") - miller_array_native.set_info(info = info_native) - - - - ## Read in derivative data and make appropriate selections - miller_array_derivative = None - miller_array_derivative = xray_data_server.get_xray_data( - file_name = params.scaling.input.xray_data.derivative.file_name, - labels = params.scaling.input.xray_data.derivative.labels, - ignore_all_zeros = True, - parameter_scope = 'scaling.input.SIR_scale.xray_data.derivative' - ) - info_derivative = miller_array_derivative.info() - miller_array_derivative=miller_array_derivative.map_to_asu().select( - miller_array_derivative.indices()!=(0,0,0) ) - miller_array_derivative = miller_array_derivative.select( - miller_array_derivative.data() > 0 ) - ## Convert to amplitudes - if (miller_array_derivative.is_xray_intensity_array()): - miller_array_derivative = miller_array_derivative.f_sq_as_f() - elif (miller_array_derivative.is_complex_array()): - miller_array_derivative = abs(miller_array_derivative) - if not miller_array_derivative.is_real_array(): - raise Sorry("miller_array_derivative is not a real array") - miller_array_derivative.set_info(info = info_derivative) - - ## Make sure we have anomalous diffs - assert miller_array_derivative.anomalous_flag() - - ## As this is a SIR case, we will remove any anomalous pairs from the native - if miller_array_native.anomalous_flag(): - miller_array_native = miller_array_native.average_bijvoet_mates()\ - .set_observation_type( miller_array_native ) - - ## Use this copy for anomalous diff's later - miller_array_derivative_anom = miller_array_derivative.deep_copy() - - if miller_array_derivative.anomalous_flag(): - miller_array_derivative = miller_array_derivative.average_bijvoet_mates()\ - .set_observation_type( miller_array_derivative ) - - ## Print info - print(file=log) - print("Native data", file=log) - print("===========", file=log) - miller_array_native.show_comprehensive_summary(f=log) - print(file=log) - native_pre_scale = pre_scale.pre_scaler( - miller_array_native, - params.scaling.input.scaling_strategy.pre_scaler_protocol, - params.scaling.input.basic) - miller_array_native = native_pre_scale.x1.deep_copy() - del native_pre_scale - - print(file=log) - print("Derivative data (merged friedels)", file=log) - print("=================================", file=log) - miller_array_derivative.show_comprehensive_summary(f=log) - print(file=log) - derivative_pre_scale = pre_scale.pre_scaler( - miller_array_derivative, - params.scaling.input.scaling_strategy.pre_scaler_protocol, - params.scaling.input.basic) - miller_array_derivative = derivative_pre_scale.x1.deep_copy() - del derivative_pre_scale - - - print(file=log) - print("Anomalous data (non merged Friedels of derivative)", file=log) - print("==================================================", file=log) - miller_array_derivative_anom.show_comprehensive_summary(f=log) - print(file=log) - derivative_anom_pre_scale = pre_scale.pre_scaler( - miller_array_derivative_anom, - params.scaling.input.scaling_strategy.pre_scaler_protocol, - params.scaling.input.basic) - miller_array_derivative_anom = derivative_anom_pre_scale.x1.deep_copy() - - - print(file=log) - print("Working on isomorphous differences", file=log) - print("==================================", file=log) - print(file=log) - iso_scaler = fa_estimation.combined_scaling( - miller_array_native, - miller_array_derivative, - params.scaling.input.scaling_strategy.iso_protocol) - - miller_array_native = iso_scaler.x1.deep_copy() - miller_array_derivative = iso_scaler.x2.deep_copy() - del iso_scaler - - delta_gen_iso = pair_analyses.delta_generator( - miller_array_native, - miller_array_derivative ) - - print(file=log) - print("Working on anomalous differences", file=log) - print("================================", file=log) - print(file=log) - - ano_scaler = fa_estimation.ano_scaling( - miller_array_derivative_anom, - params.scaling.input.scaling_strategy.ano_protocol) - - positive_miller = ano_scaler.x1p.deep_copy() - negative_miller = ano_scaler.x1n.deep_copy() - del ano_scaler - delta_gen_ano = pair_analyses.delta_generator( - positive_miller, - negative_miller) - - print(file=log) - print("Combining iso and ano data", file=log) - print("==========================", file=log) - print(file=log) - - fa = fa_estimation.naive_fa_estimation( - delta_gen_ano.abs_delta_f, - delta_gen_iso.abs_delta_f, - params.scaling.input.fa_estimation - ) - - print(file=log) - print("writing mtz file", file=log) - print("----------------", file=log) - print(file=log) - - ## Please write out the abs_delta_f array - mtz_dataset = fa.fa.as_mtz_dataset( - column_root_label='F'+params.scaling.input.output.outlabel) - mtz_dataset.mtz_object().write( - file_name=params.scaling.input.output.hklout) - - -if (__name__ == "__main__"): - run(sys.argv[1:]) From 7e9652ea7f6e02b1c82cc7a87c48f9b207bfebad Mon Sep 17 00:00:00 2001 From: "Aaron S. Brewster" Date: Tue, 13 Aug 2024 16:52:17 -0700 Subject: [PATCH 630/748] XFEL GUI: MPI safe ensemble refinement (#840) * Add optional argument lists to xfel programs Specifically recompute_mosaicity and merge * New command cctbx.xfel.enesemble_refine_pipeline This is an MPI safe script that runs four programs in sequence - dials.combine_experiments - dials.refine - cctbx.xfel.recompute_mosaicity - cctbx.xfel.mpi_integrate For the first 3, only mpi rank 0 is used. Then the full MPI job can run for integration. This ensures the first 3 programs are only ran single process. * Rewrite striping to use cctbx.xfel.ensemble_refinement_pipeline Also, it's time to disable frame_extractor * Fix typos and splitting strings with whitespace * Add GUI widget to modify number of nodes for TDER (#843) * Add `params.mp.nnodes_tder` and `nnodes_tder` widget * Fix typo in nnodes_tder SpinCtrl in settings * Decrease width of all nnodes widgets * Add tooltip for TDER abbreviation itself * Try to `run()` `dials.command_line.combine_experiments` (new interface) * Try to `run()` `dials.command_line.combine_experiments` (new interface) * Try to `run()` `dials.command_line.combine_experiments`, unify syntax --------- Co-authored-by: Daniel Tchon --- xfel/command_line/ensemble_refine_pipeline.py | 92 +++++++++++++++++++ xfel/command_line/recompute_mosaicity.py | 11 ++- xfel/command_line/striping.py | 35 +++---- xfel/merging/command_line/merge.py | 8 +- xfel/ui/components/tooltips.py | 1 + xfel/ui/components/xfel_gui_dialogs.py | 30 ++++-- xfel/ui/db/job.py | 8 +- xfel/util/mp.py | 4 + 8 files changed, 155 insertions(+), 34 deletions(-) create mode 100644 xfel/command_line/ensemble_refine_pipeline.py diff --git a/xfel/command_line/ensemble_refine_pipeline.py b/xfel/command_line/ensemble_refine_pipeline.py new file mode 100644 index 0000000000..46ec21e3a0 --- /dev/null +++ b/xfel/command_line/ensemble_refine_pipeline.py @@ -0,0 +1,92 @@ +from __future__ import absolute_import, division, print_function +# +# LIBTBX_SET_DISPATCHER_NAME cctbx.xfel.ensemble_refinement_pipeline +# + +help_message = """ +This is an MPI enabled pipeline to run several dials and cctbx.xfel commands in row. +Specifically dials.combine_experiments, dials.refine, cctbx.xfel.recompute_mosaicity, +and optionally cctbx.xfel.mpi_integrate +""" + +from libtbx.phil import parse +from dials.util import show_mail_on_error + +ensemble_refinement_pipline_str = """ +combine_experiments_phil = None + .type = path + .help = Path to the phil file for dials.combine_experiments +refine_phil = None + .type = path + .help = Path to the phil file for dials.refine +recompute_mosaicity_phil = None + .type = path + .help = Path to the phil file for cctbx.xfel.recompute_mosaicity +integration_phil = None + .type = path + .help = Path to the phil file for cctbx.xfel.mpi_integrate +""" + +phil_scope = parse(ensemble_refinement_pipline_str) + +class Script(object): + ''' Class to parse the command line options. ''' + + def __init__(self): + ''' Set the expected options. ''' + from dials.util.options import ArgumentParser + import libtbx.load_env + + # Create the option parser + usage = "usage: %s combine_experiments_phil=combine.phil refine_phil=refine.phil recompute_mosaicity_phil=recompute_mosaicity.phil integration_phil=integration.phil" % libtbx.env.dispatcher_name + self.parser = ArgumentParser( + usage=usage, + phil=phil_scope, + epilog=help_message) + + def run(self): + ''' Parse the options. ''' + from libtbx.mpi4py import MPI + comm = MPI.COMM_WORLD + rank = comm.Get_rank() # each process in MPI has a unique id, 0-indexed + size = comm.Get_size() # size: number of processes running in this job + + # Parse the command line arguments + params, options = self.parser.parse_args(show_diff_phil=True if rank == 0 else False) + + if rank == 0: + try: + if params.combine_experiments_phil: + from dials.command_line.combine_experiments import run + run(args=[params.combine_experiments_phil]) + if params.refine_phil: + from dials.command_line.refine import run + run(args=[params.refine_phil]) + if params.recompute_mosaicity_phil: + from xfel.command_line.recompute_mosaicity import Script as RecomputeScript + script = RecomputeScript() + script.run_with_preparsed(*script.parser.parse_args([params.recompute_mosaicity_phil], show_diff_phil=True)) + except Exception as e: + if hasattr(e, 'message'): + print(e.message) + else: + print(str(e)) + status = False + else: + status = True + else: + status = None + status = comm.bcast(status, root=0) + if not status: + print("Rank %d shutting down due to job failure"%rank) + return + + if params.integration_phil: + import xfel.merging.command_line.mpi_integrate # reconfigure phils for integration + from xfel.merging.command_line.merge import Script as IntegrateScript + IntegrateScript().run(args=[params.integration_phil]) + +if __name__ == '__main__': + with show_mail_on_error(): + script = Script() + script.run() diff --git a/xfel/command_line/recompute_mosaicity.py b/xfel/command_line/recompute_mosaicity.py index 9c96e996fb..062b25fabf 100644 --- a/xfel/command_line/recompute_mosaicity.py +++ b/xfel/command_line/recompute_mosaicity.py @@ -64,11 +64,14 @@ def __init__(self): check_format=False, epilog=help_message) - def run(self): - ''' Parse the options. ''' + def run(self, args=None): + """Execute the script.""" + params, options = self.parser.parse_args(args, show_diff_phil=True) + self.run_with_preparsed(params, options) + + def run_with_preparsed(self, params, options): + """Run recompute_mosaicity, but allow passing in of parameters""" from dials.util.options import flatten_experiments, flatten_reflections - # Parse the command line arguments - params, options = self.parser.parse_args(show_diff_phil=True) experiments = flatten_experiments(params.input.experiments) reflections = flatten_reflections(params.input.reflections) assert len(reflections) == 1 diff --git a/xfel/command_line/striping.py b/xfel/command_line/striping.py index ea63a8d220..cc18e5df31 100644 --- a/xfel/command_line/striping.py +++ b/xfel/command_line/striping.py @@ -205,7 +205,7 @@ # split results and coerce to integration pickle for merging postprocessing_str = ''' postprocessing { - enable = True + enable = False include scope xfel.command_line.frame_extractor.phil_scope } ''' @@ -451,8 +451,8 @@ def set_up_section(self, section_tag, dispatcher_name, self.intermediates) command = ". %s" % os.path.join(self.params.striping.output_folder, self.intermediates, script) else: - command = "%s %s" % (dispatcher_name, phil_filename) - self.command_sequence.append(command) + command = "%s_phil=%s" % (dispatcher_name, phil_filename) + self.argument_sequence.append(command) def run(self): '''Execute the script.''' @@ -485,7 +485,7 @@ def run(self): # reset for this chunk/stripe self.filename = "t%03d_%s_%s%03d" % (self.params.striping.trial, batch, tag, idx) - self.command_sequence = [] + self.argument_sequence = [] # set up the file containing input expts and refls (logging) chunk_path = os.path.join(self.params.striping.output_folder, self.intermediates, self.filename) @@ -502,35 +502,36 @@ def run(self): for refl_path in chunk[1]: custom_parts.append(" reflections = %s" % refl_path) custom_parts.append(" }") - self.set_up_section("combine_experiments", "dials.combine_experiments", + self.set_up_section("combine_experiments", "combine_experiments", clustering=False, custom_parts=custom_parts) # refinement of the grouped experiments - self.set_up_section("refinement", "dials.refine", + self.set_up_section("refinement", "refine", clustering=self.clustering) # refinement of the grouped experiments - self.set_up_section("recompute_mosaicity", "cctbx.xfel.recompute_mosaicity", + self.set_up_section("recompute_mosaicity", "recompute_mosaicity", clustering=self.clustering) # reintegration if self.params.reintegration.enable: - if self.params.mp.method == 'shifter' or not self.params.mp.mpi_command: - self.set_up_section("reintegration", "cctbx.xfel.mpi_integrate", clustering=self.clustering) - else: - self.set_up_section("reintegration", "%s cctbx.xfel.mpi_integrate"%self.params.mp.mpi_command, - clustering=self.clustering) + self.set_up_section("reintegration", "integration", clustering=self.clustering) # extract results to integration pickles for merging if self.params.postprocessing.enable: - lambda_diff_str = lambda diff_str: (diff_str % \ - (os.path.join("..", "final_extracted"))).replace("ITER", "%04d") - self.set_up_section("postprocessing", "cctbx.xfel.frame_extractor", - lambda_diff_str=lambda_diff_str, clustering=self.clustering) + pass # disabled + #lambda_diff_str = lambda diff_str: (diff_str % \ + # (os.path.join("..", "final_extracted"))).replace("ITER", "%04d") + #self.set_up_section("postprocessing", "cctbx.xfel.frame_extractor", + # lambda_diff_str=lambda_diff_str, clustering=self.clustering) # submit queued job from appropriate directory os.chdir(self.intermediates) - command = " && ".join(self.command_sequence) + command = "cctbx.xfel.ensemble_refinement_pipeline " + " ".join(self.argument_sequence) + + if self.params.mp.method != 'shifter' and self.params.mp.mpi_command: + command = "%s %s"%(self.params.mp.mpi_command, command) + if self.params.combine_experiments.clustering.dendrogram: easy_run.fully_buffered(command).raise_if_errors().show_stdout() else: diff --git a/xfel/merging/command_line/merge.py b/xfel/merging/command_line/merge.py index 5aea100ddb..e4e506fdf6 100644 --- a/xfel/merging/command_line/merge.py +++ b/xfel/merging/command_line/merge.py @@ -49,7 +49,7 @@ def __init__(self): def __del__(self): self.mpi_helper.finalize() - def parse_input(self): + def parse_input(self, args=None): '''Parse input at rank 0 and broadcast the input parameters and options to all ranks''' if self.mpi_helper.rank == 0: @@ -70,7 +70,7 @@ def parse_input(self): epilog=help_message) # Parse the command line. quick_parse is required for MPI compatibility - params, options = self.parser.parse_args(show_diff_phil=True,quick_parse=True) + params, options = self.parser.parse_args(args, show_diff_phil=True,quick_parse=True) # Log the modified phil parameters diff_phil_str = self.parser.diff_phil.as_str() @@ -104,7 +104,7 @@ def parse_input(self): self.mpi_logger.log_step_time("BROADCAST_INPUT_PARAMS", True) @mpi_abort_on_exception - def run(self): + def run(self, args=None): import datetime time_now = datetime.datetime.now() @@ -115,7 +115,7 @@ def run(self): self.mpi_logger.log_step_time("TOTAL") self.mpi_logger.log_step_time("PARSE_INPUT_PARAMS") - self.parse_input() + self.parse_input(args) self.mpi_logger.log_step_time("PARSE_INPUT_PARAMS", True) if self.params.mp.debug.cProfile: diff --git a/xfel/ui/components/tooltips.py b/xfel/ui/components/tooltips.py index f8040e13f2..dee0291e9f 100644 --- a/xfel/ui/components/tooltips.py +++ b/xfel/ui/components/tooltips.py @@ -32,6 +32,7 @@ def get_help(path, scope = master_phil_scope): 'htcondor_executable_path_ctr': get_help('mp.htcondor.executable_path'), 'htcondor_filesystemdomain_ctr': get_help('mp.htcondor.filesystemdomain'), 'nnodes_index_ctr': get_help('mp.nnodes_index'), + 'nnodes_tder_ctr': get_help('mp.nnodes_tder'), 'nnodes_scale_ctr': get_help('mp.nnodes_scale'), 'nnodes_merge_ctr': get_help('mp.nnodes_merge'), 'extra_options': get_help('mp.extra_options'), diff --git a/xfel/ui/components/xfel_gui_dialogs.py b/xfel/ui/components/xfel_gui_dialogs.py index 8d6621faeb..e49aff26b7 100644 --- a/xfel/ui/components/xfel_gui_dialogs.py +++ b/xfel/ui/components/xfel_gui_dialogs.py @@ -899,20 +899,32 @@ def __init__(self, parent, params, self.nnodes_index = gctr.SpinCtrl(self, name='nnodes_index', label='Indexing:', - label_size=(80, -1), + label_size=(60, -1), label_style='normal', - ctrl_size=(100, -1), + ctrl_size=(60, -1), ctrl_value='%d'%(params.mp.nnodes_index or 1), ctrl_min=1, ctrl_max=1000) self.jobtype_nnodes_sizer.Add(self.nnodes_index, flag=wx.EXPAND | wx.ALL, border=10) + self.nnodes_tder = gctr.SpinCtrl(self, + name='nnodes_tder', + label='TDER:', + label_size=(60, -1), + label_style='normal', + ctrl_size=(60, -1), + ctrl_value='%d'%(params.mp.nnodes_tder or 1), + ctrl_min=1, + ctrl_max=1000) + self.nnodes_tder.SetToolTip('Time Dependent Ensemble Refinement') + self.jobtype_nnodes_sizer.Add(self.nnodes_tder, flag=wx.EXPAND | wx.ALL, border=10) + self.nnodes_scale = gctr.SpinCtrl(self, name='nnodes_scale', label='Scaling:', - label_size=(80, -1), + label_size=(60, -1), label_style='normal', - ctrl_size=(100, -1), + ctrl_size=(60, -1), ctrl_value='%d'%(params.mp.nnodes_scale or 1), ctrl_min=1, ctrl_max=1000) @@ -921,9 +933,9 @@ def __init__(self, parent, params, self.nnodes_merge = gctr.SpinCtrl(self, name='nnodes_merge', label='Merging:', - label_size=(80, -1), + label_size=(60, -1), label_style='normal', - ctrl_size=(100, -1), + ctrl_size=(60, -1), ctrl_value='%d'%(params.mp.nnodes_merge or 1), ctrl_min=1, ctrl_max=1000) @@ -1116,6 +1128,7 @@ def updateMultiprocessing(self): self.htcondor_filesystemdomain.Hide() self.jobtype_nnodes_box.Hide() self.nnodes_index.Hide() + self.nnodes_tder.Hide() self.nnodes_scale.Hide() self.nnodes_merge.Hide() self.extra_box.Hide() @@ -1141,6 +1154,7 @@ def updateMultiprocessing(self): self.htcondor_executable_path.Hide() self.htcondor_filesystemdomain.Hide() self.nnodes_index.Show() + self.nnodes_tder.Show() self.nnodes_scale.Show() self.nnodes_merge.Show() self.extra_box.Show() @@ -1167,6 +1181,7 @@ def updateMultiprocessing(self): self.htcondor_executable_path.Show() self.htcondor_filesystemdomain.Show() self.nnodes_index.Hide() + self.nnodes_tder.Hide() self.nnodes_scale.Hide() self.nnodes_merge.Hide() self.extra_box.Hide() @@ -1193,6 +1208,7 @@ def updateMultiprocessing(self): self.htcondor_executable_path.Hide() self.htcondor_filesystemdomain.Hide() self.nnodes_index.Show() + self.nnodes_tder.Show() self.nnodes_scale.Show() self.nnodes_merge.Show() self.extra_box.Show() @@ -1223,6 +1239,7 @@ def updateMultiprocessing(self): self.htcondor_executable_path.Hide() self.htcondor_filesystemdomain.Hide() self.nnodes_index.Hide() + self.nnodes_tder.Hide() self.nnodes_scale.Hide() self.nnodes_merge.Hide() self.extra_box.Show() @@ -1288,6 +1305,7 @@ def onOK(self, e): self.params.mp.queue = self.queue_text.ctr.GetValue() if self.mp_option.ctr.GetStringSelection() in ['shifter', 'slurm', 'pbs']: self.params.mp.nnodes_index = int(self.nnodes_index.ctr.GetValue()) + self.params.mp.nnodes_tder = int(self.nnodes_tder.ctr.GetValue()) self.params.mp.nnodes_scale = int(self.nnodes_scale.ctr.GetValue()) self.params.mp.nnodes_merge = int(self.nnodes_merge.ctr.GetValue()) if self.mp_option.ctr.GetStringSelection() == 'shifter': diff --git a/xfel/ui/db/job.py b/xfel/ui/db/job.py index 1b91691b26..fa2735ca69 100644 --- a/xfel/ui/db/job.py +++ b/xfel/ui/db/job.py @@ -637,6 +637,7 @@ def submit(self, previous_job = None): mp.wall_time={} mp.use_mpi=False mp.mpi_command={} + {} mp.shifter.submit_command={} mp.shifter.shifter_image={} mp.shifter.sbatch_script_template={} @@ -659,13 +660,14 @@ def submit(self, previous_job = None): reintegration.integration.lookup.mask={} mp.local.include_mp_in_command=False """.format(self.app.params.mp.queue if len(self.app.params.mp.queue) > 0 else None, - 1,#self.app.params.mp.nproc, + self.app.params.mp.nnodes_tder or self.app.params.mp.nnodes, self.app.params.mp.nproc_per_node, self.app.params.mp.method, '\n'.join(['mp.env_script={}'.format(p) for p in self.app.params.mp.env_script if p]), '\n'.join(['mp.phenix_script={}'.format(p) for p in self.app.params.mp.phenix_script if p]), self.app.params.mp.wall_time, self.app.params.mp.mpi_command, + "\n".join(["mp.extra_options={}".format(opt) for opt in self.app.params.mp.extra_options]), self.app.params.mp.shifter.submit_command, self.app.params.mp.shifter.shifter_image, self.app.params.mp.shifter.sbatch_script_template, @@ -683,8 +685,8 @@ def submit(self, previous_job = None): target_phil_path, path, self.rungroup.untrusted_pixel_mask_path, - ).split() - arguments.extend(["mp.extra_options={}".format(opt) for opt in self.app.params.mp.extra_options]) + ).split('\n') + arguments = [arg.strip() for arg in arguments] try: commands = Script(arguments).run() diff --git a/xfel/util/mp.py b/xfel/util/mp.py index 5ef550e962..635c9fb509 100644 --- a/xfel/util/mp.py +++ b/xfel/util/mp.py @@ -37,6 +37,10 @@ .type = int .help = If defined, use this many nodes for indexing and integration. \ Currently only works for mp.method=shifter or slurm. + nnodes_tder = None + .type = int + .help = If defined, use this many nodes for ensemble refinement. \ + Currently only works for mp.method=shifter or slurm. nnodes_scale = None .type = int .help = If defined, use this many nodes for scaling. \ From e3b69747be8d89140b1e5b0edc3c01149137b97d Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 13 Aug 2024 13:35:08 -0700 Subject: [PATCH 631/748] Negligible tidying up - moving operation out of cycle. --- mmtbx/geometry_restraints/c_beta.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mmtbx/geometry_restraints/c_beta.py b/mmtbx/geometry_restraints/c_beta.py index 8068818fc1..1087b2e724 100644 --- a/mmtbx/geometry_restraints/c_beta.py +++ b/mmtbx/geometry_restraints/c_beta.py @@ -9,6 +9,7 @@ def get_c_beta_torsion_proxies(pdb_hierarchy, selection=None, sigma=2.5): origin_ids = cctbx.geometry_restraints.linking_class.linking_class() + c_beta_origin_id = origin_ids.get_origin_id('C-beta') if (selection is not None): if (isinstance(selection, flex.bool)): actual_bselection = selection @@ -66,7 +67,7 @@ def get_c_beta_torsion_proxies(pdb_hierarchy, i_seqs=i_seqs, angle_ideal=dihedralNCAB, weight=1/sigma**2, - origin_id=origin_ids.get_origin_id('C-beta')) + origin_id=c_beta_origin_id) c_beta_dihedral_proxies.append(dp_add) #CNAB i_seqs = [C_atom.i_seq,N_atom.i_seq,CA_atom.i_seq,CB_atom.i_seq] @@ -74,7 +75,7 @@ def get_c_beta_torsion_proxies(pdb_hierarchy, i_seqs=i_seqs, angle_ideal=dihedralCNAB, weight=1/sigma**2, - origin_id=origin_ids.get_origin_id('C-beta')) + origin_id=c_beta_origin_id) c_beta_dihedral_proxies.append(dp_add) return c_beta_dihedral_proxies, c_beta_residues_skipped # BAD From 38f230e43f5df40f0817e6567ff1d43ac107dd1b Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 13 Aug 2024 17:37:51 -0700 Subject: [PATCH 632/748] pdb_int speedup 4%: Don't use get_sorted, too slow for the task. --- cctbx/geometry_restraints/__init__.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/cctbx/geometry_restraints/__init__.py b/cctbx/geometry_restraints/__init__.py index d335da3c51..791e8e6716 100644 --- a/cctbx/geometry_restraints/__init__.py +++ b/cctbx/geometry_restraints/__init__.py @@ -923,12 +923,18 @@ def show_histogram_of_model_distances(self, sites_cart=sites_cart, sorted_asu_proxies=self) else: - sorted_table, n_not_shown = self.get_sorted( - by_value="delta", - sites_cart=sites_cart, - origin_id=origin_id) - hd = [x[4] for x in sorted_table] - hdata = flex.double(hd) + selected_simple = self.simple.proxy_select(origin_id = origin_id) + selected_asu = self.asu.proxy_select(origin_id = origin_id) + hdata_simple = bond_distances_model( + sites_cart=sites_cart, + proxies=selected_simple) + sap = bond_sorted_asu_proxies(asu_mappings=self.asu_mappings()) + sap.process(selected_asu) + hdata_asu = bond_distances_model( + sites_cart=sites_cart, + sorted_asu_proxies=sap) + hdata_simple.extend(hdata_asu) + hdata = hdata_simple histogram = flex.histogram( data=flex.double(hdata), n_slots=n_slots) From 46a172818d6072859f1f2f29027ad24684a41ca3 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 13 Aug 2024 17:38:42 -0700 Subject: [PATCH 633/748] pdb_int speedup 4%: Don't use get_sorted for angles too, too slow for the task. Also now will display actual absolute deviations, not angle values. --- cctbx/geometry_restraints/__init__.py | 17 ++++++----------- cctbx/regression/tst_geometry_restraints_2.py | 10 +++++----- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/cctbx/geometry_restraints/__init__.py b/cctbx/geometry_restraints/__init__.py index 791e8e6716..56f9b86509 100644 --- a/cctbx/geometry_restraints/__init__.py +++ b/cctbx/geometry_restraints/__init__.py @@ -2105,19 +2105,14 @@ def _show_histogram_of_deltas_impl(O, if (f is None): f = sys.stdout print("%sHistogram of %s deviations from ideal:" % ( prefix, proxy_label), file=f) + selected_proxies = O if origin_id is not None: - sorted_table, n_not_shown = O.get_sorted( - by_value="delta", - sites_cart=sites_cart, - origin_id=origin_id) - hd = [x[2] for x in sorted_table] - data = flex.double(hd) + selected_proxies = O.proxy_select(origin_id=origin_id) + if unit_cell is None: + data = flex.abs(selected_proxies.deltas(sites_cart=sites_cart)) else: - if unit_cell is None: - data = flex.abs(O.deltas(sites_cart=sites_cart)) - else: - data = flex.abs( - O.deltas(unit_cell=unit_cell, sites_cart=sites_cart)) + data = flex.abs( + selected_proxies.deltas(unit_cell=unit_cell, sites_cart=sites_cart)) histogram = flex.histogram( data=data, n_slots=n_slots) diff --git a/cctbx/regression/tst_geometry_restraints_2.py b/cctbx/regression/tst_geometry_restraints_2.py index f7cef1fb11..ca45c1e429 100644 --- a/cctbx/regression/tst_geometry_restraints_2.py +++ b/cctbx/regression/tst_geometry_restraints_2.py @@ -550,11 +550,11 @@ def exercise_na_restraints_output_to_geo(verbose=False): Bond restraints: 87""", '''\ Histogram of bond angle deviations from ideal: - 99.49 - 105.87: 23 - 105.87 - 112.26: 36 - 112.26 - 118.65: 28 - 118.65 - 125.04: 30 - 125.04 - 131.42: 13 + 0.00 - 1.10: 75 + 1.10 - 2.19: 30 + 2.19 - 3.29: 13 + 3.29 - 4.38: 8 + 4.38 - 5.48: 4 Bond angle restraints: 130''', ] with open("tst_cctbx_geometry_restraints_2_na.pdb", "w") as f: From 57cd1f9e0009b4338bad8785498597afb26ede86 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 13 Aug 2024 19:36:36 -0700 Subject: [PATCH 634/748] Check for undefined pdb input --- mmtbx/model/model.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index a6674a5c03..02e1346df7 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -1954,9 +1954,11 @@ def process( # if(not self._pdb_interpretation_params.pdb_interpretation.sort_atoms and self._pdb_hierarchy is not None): - self._xray_structure = None - self._pdb_hierarchy = None - assert not self._mtrix_expanded + if self._model_input is not None: + # otherwise it fails here: = processed_pdb_files_srv.process_pdb_files( + self._xray_structure = None + self._pdb_hierarchy = None + assert not self._mtrix_expanded # if(self._pdb_interpretation_params.pdb_interpretation.sort_atoms and self._pdb_hierarchy is not None): From 1a7d7943215a3d17921b9540b0975b6dde0c8e09 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Mon, 12 Aug 2024 13:49:50 -0700 Subject: [PATCH 635/748] bootstrap: switch more repositories to git - opt_resources - Plex - PyQuante - elbow - ksdssp - pulchra - reel - muscle - buildbot - xfel_regression [skip ci] --- libtbx/auto_build/bootstrap.py | 37 +++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/libtbx/auto_build/bootstrap.py b/libtbx/auto_build/bootstrap.py index aceb8bac3b..cacfcaab78 100644 --- a/libtbx/auto_build/bootstrap.py +++ b/libtbx/auto_build/bootstrap.py @@ -483,7 +483,19 @@ def git(module, parameters, destination=None, use_ssh=False, verbose=False, refe destpath, destdir = os.path.split(destination) # default to using ssh for private phenix repositories - if module in ['phenix', 'solve_resolve', 'phenix_pathwalker', 'labelit']: + if module in ['elbow', + 'ksdssp', + 'labelit', + 'muscle', + 'opt_resources', + 'phenix', + 'phenix_pathwalker', + 'Plex', + 'PyQuante', + 'pulchra', + 'reel', + 'solve_resolve', + ]: use_ssh = True if os.path.exists(destination): @@ -827,7 +839,7 @@ class gui_resources_module(SourceModule): class opt_resources_module(SourceModule): module = 'opt_resources' - authenticated = ['svn', 'svn+ssh://%(cciuser)s@boa.lbl.gov/opt_resources/trunk'] + authenticated = ['git', 'git@github.com:phenix-project/opt_resources.git'] class eigen_module(SourceModule): module = 'eigen' @@ -871,11 +883,11 @@ class phenix_colabs(SourceModule): class plex_module(SourceModule): module = 'Plex' - authenticated = ['svn', 'svn+ssh://%(cciuser)s@boa.lbl.gov/Plex/trunk'] + authenticated = ['git', 'git@github.com:phenix-project/Plex.git'] class pyquante_module(SourceModule): module = 'PyQuante' - authenticated = ['svn', 'svn+ssh://%(cciuser)s@boa.lbl.gov/PyQuante/trunk'] + authenticated = ['git', 'git@github.com:phenix-project/PyQuante.git'] class chem_data_module(SourceModule): module = 'chem_data' @@ -883,15 +895,15 @@ class chem_data_module(SourceModule): class elbow_module(SourceModule): module = 'elbow' - authenticated = ['svn', 'svn+ssh://%(cciuser)s@boa.lbl.gov/elbow/trunk'] + authenticated = ['git', 'git@github.com:phenix-project/elbow.git'] class ksdssp_module(SourceModule): module = 'ksdssp' - authenticated = ['svn', 'svn+ssh://%(cciuser)s@boa.lbl.gov/ksdssp/trunk'] + authenticated = ['git', 'git@github.com:phenix-project/ksdssp.git'] class pulchra_module(SourceModule): module = 'pulchra' - authenticated = ['svn', 'svn+ssh://%(cciuser)s@boa.lbl.gov/pulchra/trunk'] + authenticated = ['git', 'git@github.com:phenix-project/pulchra.git'] class solve_resolve_module(SourceModule): module = 'solve_resolve' @@ -899,11 +911,11 @@ class solve_resolve_module(SourceModule): class reel_module(SourceModule): module = 'reel' - authenticated = ['svn', 'svn+ssh://%(cciuser)s@boa.lbl.gov/reel/trunk'] + authenticated = ['git', 'git@github.com:phenix-project/reel.git'] class muscle_module(SourceModule): module = 'muscle' - authenticated = ['svn', 'svn+ssh://%(cciuser)s@boa.lbl.gov/muscle/trunk'] + authenticated = ['git', 'git@github.com:phenix-project/muscle.git'] class cxi_xdr_xes_module(SourceModule): module = 'cxi_xdr_xes' @@ -911,7 +923,7 @@ class cxi_xdr_xes_module(SourceModule): class buildbot_module(SourceModule): module = 'buildbot' - authenticated = ['svn', 'svn+ssh://%(cciuser)s@boa.lbl.gov/buildbot/trunk'] + authenticated = ['git', 'git@github.com:cci-lbl/buildbot.git'] class phenix_pathwalker_module(SourceModule): module = 'phenix_pathwalker' @@ -994,8 +1006,9 @@ class msgpack_module(SourceModule): class xfel_regression_module(SourceModule): module = 'xfel_regression' - authenticated = ['svn', - 'svn+ssh://%(cciuser)s@boa.lbl.gov/xfel_regression/trunk'] + authenticated = ['git', + 'git@gitlab.com:cctbx/xfel_regression.git', + 'https://gitlab.com/cctbx/xfel_regression.git'] class xia2_module(SourceModule): module = 'xia2' From 23b871db3014d0185a632aac7eab3d4f655fbd33 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Wed, 14 Aug 2024 15:45:13 -0700 Subject: [PATCH 636/748] reducing AA flip output --- iotbx/pdb/hierarchy.py | 20 +++++++++----------- mmtbx/monomer_library/pdb_interpretation.py | 3 +-- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index cfe16223b7..1aa0415cf5 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -2307,6 +2307,7 @@ def chirality_delta(sites, volume_ideal, both_signs): sites_cart = self.atoms().extract_xyz() t0=time.time() info = "" + flips=0 for rg in self.residue_groups(): flip_it=False for ag in rg.atom_groups(): @@ -2338,11 +2339,6 @@ def chirality_delta(sites, volume_ideal, both_signs): if abs(delta)>2.: flip_it=True if flip_it: - info += ' Residue "%s %s %s":' % ( - rg.parent().id, - ag.resname, - rg.resseq, - ) flips_stored = [] atoms = ag.atoms() for pair in flip_data["pairs"]: @@ -2351,7 +2347,11 @@ def chirality_delta(sites, volume_ideal, both_signs): if atom1 is None and atom2 is None: continue if len(list(filter(None, [atom1, atom2]))) == 1: flips_stored=[] - info += ' not complete - not flipped' + info += ' Residue "%s %s %s": not complete - not flipped' % ( + rg.parent().id, + ag.resname, + rg.resseq, + ) break flips_stored.append([atom1,atom2]) for atom1, atom2 in flips_stored: @@ -2359,11 +2359,9 @@ def chirality_delta(sites, volume_ideal, both_signs): tmp = getattr(atom1, attr) setattr(atom1, attr, getattr(atom2, attr)) setattr(atom2, attr, tmp) - info += ' "%s" <-> "%s"' % (atom1.name.strip(), - atom2.name.strip()) - info += '\n' - if not info: info = ' None\n' - info += ' Time to flip residues: %0.2fs\n' % (time.time()-t0) + flips+=1 + if flips or info: + info += ' Time to flip %d residue(s): %0.2fs\n' % (flips, time.time()-t0) return info def distance_based_simple_two_way_bond_sets(self, diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index b6835511e1..c66d574b53 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -3427,8 +3427,7 @@ def __init__(self, if self.params.flip_symmetric_amino_acids: info = self.pdb_hierarchy.flip_symmetric_amino_acids() if info and log is not None: - print("\n Symmetric amino acids flipped", file=log) - print(info, file=log) + print("\n Symmetric amino acids flipped. %s\n" % info.strip(), file=log) if atom_selection_string is not None: sel = self.pdb_hierarchy.atom_selection_cache().selection(atom_selection_string) temp_string = self.pdb_hierarchy.select(sel).as_pdb_string() From 0e5b50d0c964003591ae234f866d44f55dd74f53 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Wed, 14 Aug 2024 15:45:41 -0700 Subject: [PATCH 637/748] user control over H/D checking --- .../geometry_restraints/quantum_interface.py | 4 ++++ .../quantum_restraints_manager.py | 21 +++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/mmtbx/geometry_restraints/quantum_interface.py b/mmtbx/geometry_restraints/quantum_interface.py index 8a831fffb9..33f94026fe 100644 --- a/mmtbx/geometry_restraints/quantum_interface.py +++ b/mmtbx/geometry_restraints/quantum_interface.py @@ -124,6 +124,10 @@ def get_qm_restraints_scope(validate=True, verbose=False): .type = choice ignore_x_h_distance_protein = False .type = bool + .help = skip check on transfer of proton during QM optimisation + ignore_lack_of_h_on_ligand = False + .type = bool + .help = skip check on protonation of ligand for entities such as MgF3 capping_groups = True .type = bool diff --git a/mmtbx/geometry_restraints/quantum_restraints_manager.py b/mmtbx/geometry_restraints/quantum_restraints_manager.py index 8aadedf19e..b7f7689a4b 100644 --- a/mmtbx/geometry_restraints/quantum_restraints_manager.py +++ b/mmtbx/geometry_restraints/quantum_restraints_manager.py @@ -334,8 +334,14 @@ def validate_ligand_buffer_models(ligand_model, buffer_model, qmr, log=None): # if not ligand_model.has_hd(): for atom_group in ligand_model.get_hierarchy().atom_groups(): - if get_class(atom_group.resname) in [ 'common_small_molecule', - 'common_element', + if qmr.ignore_lack_of_h_on_ligand: + print(' Selection %s has no H/D but is skipped via PHIL - continue' % ( + qmr.selection, + ), + file=log) + break + elif get_class(atom_group.resname) in [ 'common_small_molecule', + 'common_element', ]: print(' Selection %s has no H/D but is %s - continue' % ( qmr.selection, @@ -357,6 +363,17 @@ def validate_ligand_buffer_models(ligand_model, buffer_model, qmr, log=None): "modified_rna_dna", "ccp4_mon_lib_rna_dna"]: raise Sorry('QI cannot protonate RNA/DNA : "%s"' % atom_group.id_str()) + for atom_group in buffer_model.get_hierarchy().atom_groups(): + if atom_group.resname in ['HOH', 'DOD']: continue + if get_class(atom_group.resname) in [ 'common_small_molecule', + 'common_element', + ]: continue + hs=0 + for atom in atom_group.atoms(): + if atom.element_is_hydrogen(): hs+=1 + if not hs: + print(' Warning: Atom group %s has no H/D atoms' % (atom_group.id_str()), + file=log) def get_ligand_buffer_models(model, qmr, verbose=False, write_steps=False, log=None, debug=False): if WRITE_STEPS_GLOBAL: write_steps=True From ddbc1f9847eaa8851a4f13916bd3f9b8f40e766d Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 15 Aug 2024 15:16:50 -0700 Subject: [PATCH 638/748] moved neutron options from eLBOW --- mmtbx/hydrogens/neutron_utils.py | 198 ++++++++++++++++++++++++++++ mmtbx/hydrogens/reduce_hydrogen.py | 2 +- mmtbx/programs/quantum_interface.py | 1 + 3 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 mmtbx/hydrogens/neutron_utils.py diff --git a/mmtbx/hydrogens/neutron_utils.py b/mmtbx/hydrogens/neutron_utils.py new file mode 100644 index 0000000000..c0627a4ecf --- /dev/null +++ b/mmtbx/hydrogens/neutron_utils.py @@ -0,0 +1,198 @@ +from string import ascii_uppercase + +import iotbx +from mmtbx.chemical_components import get_bond_pairs + +def add_side_chain_hydrogen(atom_group): + def _get_side_chain_hydrogen_xyz(atom_names): + from elbow.chemistry.xyzClass import xyzClass + vec_oo = xyzClass(atom_names[0].xyz) - xyzClass(atom_names[2].xyz) + mid = xyzClass(atom_names[0].xyz) - vec_oo/2 + vec_cm = mid - xyzClass(atom_names[1].xyz) + h_xyz = xyzClass(atom_names[2].xyz) + vec_cm*1/abs(vec_cm) + return h_xyz + # + heavy_name = None + if atom_group.resname == "ASP": + atom_names = ["OD1", "CG", "OD2", "HD2"] + elif atom_group.resname == "GLU": + atom_names = ["OE1", "CD", "OE2", "HE2"] + else: + raise Sorry("residue %s has no side chain acid group" % atom_group.resname) + count=0 + for i, name in enumerate(atom_names): + for atom in atom_group.atoms(): + if atom.name.strip()==name: + atom_names[i]=atom + count+=1 + break + if count!=3: return None + h_xyz = _get_side_chain_hydrogen_xyz(atom_names) + new_atom = iotbx.pdb.hierarchy.atom() + new_atom.element = "H" + new_atom.name = atom_names[3] + new_atom.xyz = h_xyz + atom_group.insert_atom(-1, new_atom) + return new_atom + +def neutron_exchange_hydrogens(hierarchy, + cifs=None, + exchange_sites_only=True, + perdeuterate=False, + only_chain_id=None, + only_resseq=None, + side_chain_acids=False, + verbose=False, + ): + if verbose: + print("""neutron_exchange_hydrogens + hierarchy : %s + cifs : %s + exchange_sites_only : %s + perdeuterate : %s + """ % (hierarchy, + cifs, + exchange_sites_only, + perdeuterate, + )) + def _get_exchange_sites(atom_group, side_chain_acids=False, verbose=False): + exchanges = [] + for atom in atom_group.atoms(): + # if atom.hetero: continue + if atom.element.strip() == "": + raise Sorry("Need element columns in input PDB") + if atom.element.strip() in ["H"]: + for a1, a2 in bonds1: + other = None + if atom.name.strip()==a1: + other = a2 + break + elif atom.name.strip()==a2: + other = a1 + break + else: + for a1, a2 in bonds2: + if atom.name.strip()==a1: + other = a2 + break + elif atom.name.strip()==a2: + other = a1 + break + if other: + for heavy in atom_group.atoms(): + if heavy.element.strip() in ["H"]: continue + if heavy.name.strip() == other.strip(): + break + else: + continue + if verbose: print('heavy :%s: :%s:' % (heavy.quote(), + heavy.element.strip())) + if heavy.element.strip() in ["C"]: continue + exchanges.append(atom) + if side_chain_acids: + rc = add_side_chain_hydrogen(atom_group) + if rc: + exchanges.append(rc) + return exchanges + ############################################## + def _get_hydrogens(atom_group, verbose=False): + exchanges = [] + for atom in atom_group.atoms(): + # if atom.hetero: continue + if atom.element.strip() == "": + raise Sorry("Need element columns in input PDB") + if not atom.element.strip() in ["H", "D"]: continue + exchanges.append(atom) + return exchanges + ############################ + if verbose: hierarchy.show() + exchange_count = 0 + for model in hierarchy.models(): + if verbose: print('model: "%s"' % model.id) + for chain in model.chains(): + if only_chain_id is not None and chain.id!=only_chain_id: continue + if verbose: print('chain: "%s"' % chain.id) + for residue_group in chain.residue_groups(): + if ( only_resseq is not None and + residue_group.resseq.strip()!=only_resseq + ): + continue + if verbose: print(' residue_group: resseq="%s" icode="%s"' % ( + residue_group.resseq, residue_group.icode)) + altlocs = [] + for atom_group in residue_group.atom_groups(): + altlocs.append(atom_group.altloc) + for atom_group in residue_group.atom_groups(): + if verbose: print(' atom_group: resname="%s" altloc="%s"' % ( + atom_group.resname, atom_group.altloc)) + bonds1 = get_bond_pairs(atom_group.resname) + bonds2 = get_bond_pairs(atom_group.resname, + alternate=True) + if cifs: + bonds3 = get_bond_pairs_from_cif(cifs.get(atom_group.resname, None)) + if bonds3: + bonds1 = bonds3 + bonds2 = bonds3 + else: + if bonds1 is None: continue + if bonds2 is None: continue + else: + if bonds1 is None: continue + if bonds2 is None: continue + if verbose: print(' atom_group: altloc="%s" resname="%s"' % ( + atom_group.altloc, atom_group.resname)) + + # for deuteriums + deuteriums=True + for atom in atom_group.atoms(): + if atom.hetero: continue + if atom.element.strip() in ["D"]: + break + else: + deuteriums=False + if deuteriums: break + + if exchange_sites_only: + exchanges = _get_exchange_sites(atom_group, + side_chain_acids=side_chain_acids, + verbose=verbose, + ) + else: + exchanges = _get_hydrogens(atom_group, verbose=verbose) + + for u, l in enumerate(ascii_uppercase): + if l not in altlocs: + break + else: + assert 0 + + if perdeuterate: + for atom in atom_group.atoms(): + if atom.element.strip() not in ["H", "D"]: continue + if atom in exchanges: continue + atom.element = " D" + atom.name = atom.name.replace("H","D", 1) + + if exchanges and not atom_group.altloc.strip(): + for i_exchange, exchange in enumerate(exchanges): + if verbose: + print('Exchanging',exchange.quote()) + exchange.occ=0.5 + atom_group.remove_atom(exchange) + if i_exchange==0: + new_atom_group = iotbx.pdb.hierarchy.atom_group() + new_atom_group.altloc = l + new_atom_group.resname = atom_group.resname + new_atom_group.append_atom(exchange) + exchange_count += 1 + residue_group.append_atom_group(new_atom_group) + other = new_atom_group.detached_copy() + other.altloc = ascii_uppercase[u+1] + for exchange in other.atoms(): + exchange.element = " D" + exchange.name = exchange.name.replace("H","D", 1) + residue_group.append_atom_group(other) + hierarchy.atoms().reset_serial() + # hierarchy.overall_counts().show() + if verbose: print(" Deuterium exchange count : %d" % exchange_count) + return hierarchy diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index 95d8a770ab..e93dea6e88 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -125,7 +125,7 @@ def get_reduce_pdb_interpretation_params(use_neutron_distances): Do this in a function so other programs (reduce2) can use the same parameters ''' p = mmtbx.model.manager.get_default_pdb_interpretation_params() - #p.pdb_interpretation.restraints_library.cdl=False # XXX this triggers a bug !=360 + p.pdb_interpretation.restraints_library.cdl=False # XXX this triggers a bug !=360 p.pdb_interpretation.clash_guard.nonbonded_distance_threshold=None p.pdb_interpretation.disable_uc_volume_vs_n_atoms_check=True p.pdb_interpretation.use_neutron_distances = use_neutron_distances diff --git a/mmtbx/programs/quantum_interface.py b/mmtbx/programs/quantum_interface.py index 6eced47b6b..735f28c39d 100644 --- a/mmtbx/programs/quantum_interface.py +++ b/mmtbx/programs/quantum_interface.py @@ -137,6 +137,7 @@ def assert_histidine_double_protonated(ag): for atom in ag.atoms(): if atom.name.strip() in ['HD1', 'HE2', 'DD1', 'DE2']: count+=1 + print(atom.name) if count not in [2]: raise Sorry('incorrect protonation of %s' % ag.id_str()) From d2045cec0d6c2f920ad4af465c859477cb6db068 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 15 Aug 2024 15:36:40 -0700 Subject: [PATCH 639/748] clean clutter and more --- mmtbx/hydrogens/neutron_utils.py | 1 + mmtbx/programs/quantum_interface.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/hydrogens/neutron_utils.py b/mmtbx/hydrogens/neutron_utils.py index c0627a4ecf..2e6bd2cc01 100644 --- a/mmtbx/hydrogens/neutron_utils.py +++ b/mmtbx/hydrogens/neutron_utils.py @@ -1,3 +1,4 @@ +from __future__ import division from string import ascii_uppercase import iotbx diff --git a/mmtbx/programs/quantum_interface.py b/mmtbx/programs/quantum_interface.py index 735f28c39d..6eced47b6b 100644 --- a/mmtbx/programs/quantum_interface.py +++ b/mmtbx/programs/quantum_interface.py @@ -137,7 +137,6 @@ def assert_histidine_double_protonated(ag): for atom in ag.atoms(): if atom.name.strip() in ['HD1', 'HE2', 'DD1', 'DE2']: count+=1 - print(atom.name) if count not in [2]: raise Sorry('incorrect protonation of %s' % ag.id_str()) From 2fe26fcbf8b014c13ec360f1247d134f241a94b9 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Thu, 15 Aug 2024 16:22:04 -0700 Subject: [PATCH 640/748] pdb_int speedup, this function 50x. Preparing data outside the loop, then use it. Fixing typo. --- mmtbx/monomer_library/linking_mixins.py | 29 +++++++++++++------------ 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index 47d5bd0757..0399d51034 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -230,27 +230,21 @@ def _check_i_seqs(atom_group1, atom_group2, i_seqs): def possible_cyclic_peptide(atom1, atom2, + atoms_in_first_last_rgs, verbose=False, ): if verbose: print(atom1.quote(),atom2.quote()) if atom1.element_is_hydrogen() or atom2.element_is_hydrogen(): return False chain1 = atom1.parent().parent().parent() - chain2 = atom1.parent().parent().parent() + chain2 = atom2.parent().parent().parent() if not chain1.id == chain2.id: if verbose: print('chain id differs', chain1.id, chain2.id) return False - fl = {} - rgs = chain1.residue_groups() - for i in range(0,-2,-1): - for atom in rgs[i].atoms(): - if atom.quote()==atom1.quote(): - fl[i]=atom1 - break - elif atom.quote()==atom2.quote(): - fl[i]=atom2 - break - return len(fl)==2 + len_fl = 0 + len_fl += atoms_in_first_last_rgs.get(atom1.quote(), -1) + len_fl += atoms_in_first_last_rgs.get(atom2.quote(), -1) + return len_fl == 1 def check_for_peptide_links(atom1, atom2, @@ -431,8 +425,15 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., custom_links = {} exclude_out_lines = {} - # main loop atom_classes = [linking_utils.get_classes(a) for a in atoms] + atoms_in_first_last_rgs = {} + for c in self.pdb_hierarchy.chains(): + for i in [0,-1]: + rg = c.residue_groups()[i] + abs_i = abs(i) + for a in rg.atoms(): + atoms_in_first_last_rgs[a.quote()] = abs_i + # main loop nonbonded_proxies, sites_cart, pair_asu_table, asu_mappings, nonbonded_i_seqs = \ _nonbonded_pair_objects(max_bonded_cutoff=max_bonded_cutoff, ) @@ -553,7 +554,7 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., # special amino acid linking # - cyclic # - beta, delta ??? - if possible_cyclic_peptide(atom1, atom2): # first & last peptide + if possible_cyclic_peptide(atom1, atom2, atoms_in_first_last_rgs): # first & last peptide use_only_bond_cutoff = True if sym_op: if classes1.common_amino_acid and classes2.common_saccharide: continue From 312c37c67a6defa6e2648c90b1d331768118ed34 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Thu, 15 Aug 2024 16:35:37 -0700 Subject: [PATCH 641/748] Clean unused --- mmtbx/monomer_library/linking_mixins.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index 0399d51034..b908ed167b 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -9,7 +9,6 @@ from mmtbx.monomer_library import bondlength_defaults from libtbx.utils import Sorry from functools import cmp_to_key -from six.moves import range origin_ids = geometry_restraints.linking_class.linking_class() From f8fc99900d296b37409fb36bcb2400b7554568bd Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Thu, 15 Aug 2024 17:08:14 -0700 Subject: [PATCH 642/748] No need in quote, i_seq should do just fine. Faster this way. --- mmtbx/monomer_library/linking_mixins.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index b908ed167b..a7d7679208 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -241,8 +241,8 @@ def possible_cyclic_peptide(atom1, if verbose: print('chain id differs', chain1.id, chain2.id) return False len_fl = 0 - len_fl += atoms_in_first_last_rgs.get(atom1.quote(), -1) - len_fl += atoms_in_first_last_rgs.get(atom2.quote(), -1) + len_fl += atoms_in_first_last_rgs.get(atom1.i_seq, -1) + len_fl += atoms_in_first_last_rgs.get(atom2.i_seq, -1) return len_fl == 1 def check_for_peptide_links(atom1, @@ -431,7 +431,7 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., rg = c.residue_groups()[i] abs_i = abs(i) for a in rg.atoms(): - atoms_in_first_last_rgs[a.quote()] = abs_i + atoms_in_first_last_rgs[a.i_seq] = abs_i # main loop nonbonded_proxies, sites_cart, pair_asu_table, asu_mappings, nonbonded_i_seqs = \ _nonbonded_pair_objects(max_bonded_cutoff=max_bonded_cutoff, From 1fdc8a59587bd62ad84a6674d3b40eaddad52687 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Fri, 16 Aug 2024 10:26:25 -0700 Subject: [PATCH 643/748] possible bugfix --- mmtbx/secondary_structure/nucleic_acids.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/secondary_structure/nucleic_acids.py b/mmtbx/secondary_structure/nucleic_acids.py index 68311d26bc..bfdaca9b6e 100644 --- a/mmtbx/secondary_structure/nucleic_acids.py +++ b/mmtbx/secondary_structure/nucleic_acids.py @@ -600,7 +600,7 @@ def get_angle_proxies_for_bond(atoms): angle_ideal=vals[i][0], weight=1./vals[i][1]**2, origin_id=origin_ids.get_origin_id('hydrogen bonds')) - proxies.append(p) + proxies.append(p) return proxies def get_h_bonds_for_particular_basepair(atoms, saenger_class=0): From 18ee996be98a5b917824972fc054c723d1b280af Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Fri, 16 Aug 2024 10:18:03 -0700 Subject: [PATCH 644/748] bootstrap: move chem_data to git [skip ci] --- .../templates/download-data-cache.yml | 16 +++++++++++----- .../templates/update-data-cache.yml | 18 ++++++++---------- libtbx/auto_build/bootstrap.py | 10 +++++++++- 3 files changed, 28 insertions(+), 16 deletions(-) diff --git a/.azure-pipelines/templates/download-data-cache.yml b/.azure-pipelines/templates/download-data-cache.yml index 9159583249..689670843b 100644 --- a/.azure-pipelines/templates/download-data-cache.yml +++ b/.azure-pipelines/templates/download-data-cache.yml @@ -22,12 +22,18 @@ steps: displayName: Download chem_data - script: | - export SVN_SSH="ssh -F $(ssh_config.secureFilePath)" - if [ ! -d "$(Pipeline.Workspace)/modules/chem_data" ]; then - svn co svn+ssh://builder@boa.lbl.gov/chem_data/trunk chem_data + if [ ! -d "$(System.DefaultWorkingDirectory)/chem_data/.git" ]; then + rm -fr $(System.DefaultWorkingDirectory)/chem_data + cd $(System.DefaultWorkingDirectory) + git clone https://gitlab.com/phenix_project/chem_data.git + git lfs install --local + git lfs pull fi - cd $(Pipeline.Workspace)/modules/chem_data - svn update + cd $(System.DefaultWorkingDirectory)/chem_data + git reset --hard origin/main + git lfs install --local + git pull --rebase + git lfs pull displayName: Update chem_data continueOnError: true diff --git a/.azure-pipelines/templates/update-data-cache.yml b/.azure-pipelines/templates/update-data-cache.yml index fa340b776a..50e7af6e18 100644 --- a/.azure-pipelines/templates/update-data-cache.yml +++ b/.azure-pipelines/templates/update-data-cache.yml @@ -26,11 +26,6 @@ jobs: sshKeySecureFile: id_rsa displayName: Download SSH key - - task: DownloadSecureFile@1 - name: ssh_config - inputs: - secureFile: ssh.config - # miniforge - script: | mkdir -p $(System.DefaultWorkingDirectory)/miniforge @@ -66,15 +61,18 @@ jobs: continueOnError: true - script: | - export SVN_SSH="ssh -F $(ssh_config.secureFilePath)" - if [ ! -d "$(System.DefaultWorkingDirectory)/chem_data/.svn" ]; then + if [ ! -d "$(System.DefaultWorkingDirectory)/chem_data/.git" ]; then rm -fr $(System.DefaultWorkingDirectory)/chem_data cd $(System.DefaultWorkingDirectory) - svn co svn+ssh://builder@boa.lbl.gov/chem_data/trunk chem_data + git clone https://gitlab.com/phenix_project/chem_data.git + git lfs install --local + git lfs pull fi cd $(System.DefaultWorkingDirectory)/chem_data - svn relocate svn+ssh://builder@boa.lbl.gov/chem_data/trunk - svn update + git reset --hard origin/main + git lfs install --local + git pull --rebase + git lfs pull displayName: Update chem_data continueOnError: true diff --git a/libtbx/auto_build/bootstrap.py b/libtbx/auto_build/bootstrap.py index cacfcaab78..0070151b7b 100644 --- a/libtbx/auto_build/bootstrap.py +++ b/libtbx/auto_build/bootstrap.py @@ -891,7 +891,9 @@ class pyquante_module(SourceModule): class chem_data_module(SourceModule): module = 'chem_data' - authenticated = ['svn', 'svn+ssh://%(cciuser)s@boa.lbl.gov/chem_data/trunk'] + anonymous = ['git', + 'git@gitlab.com:phenix_project/chem_data.git', + 'https://gitlab.com/phenix_project/chem_data.git'] class elbow_module(SourceModule): module = 'elbow' @@ -1571,6 +1573,12 @@ def run(self): workdir = ['modules', module] self.add_step(self.shell(command=[sys.executable, os.path.join('libtbx', 'version.py')], workdir=workdir)) + # add geostd to chem_data + if module == 'chem_data': + action = MODULES.get_module('geostd')().get_url(auth=self.get_auth()) + method, parameters = action[0], action[1:] + self._add_git('geostd', parameters, destination=self.opjoin('modules', 'chem_data', 'geostd')) + # Use dials-2.2 branches for Python 2 if (module == 'dials' or module == 'dxtbx' or module == 'xia2') and not self.python3: workdir = ['modules', module] From d4f9ef652409e35c4a72951974bc50c8074830ff Mon Sep 17 00:00:00 2001 From: "Aaron S. Brewster" Date: Fri, 16 Aug 2024 15:27:13 -0700 Subject: [PATCH 645/748] =?UTF-8?q?New=20cctbx.xfel.merge=20worker=20for?= =?UTF-8?q?=20computing=20and=20filtering=20on=20=CE=94CC=C2=BD=20(#1005)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a means of filtering out lattices that degrade the overall CC½. Uses the σ-τ method from Assmann 2016 to avoid splitting the data into odd/even datasets. Enable by adding the deltaccint worker after the group worker. Includes parameter iqr_ratio = 10. If the ΔCC½ filter is enabled, first compute CC½ when removing every image one at a time, then compute the IQR of these CC½s. Remove all lattices whose contribution degrades CC½ by more than IQR * iqr_ratio above the median. You can discover a good IQR by running the program once, examining the log file where possible values are listed, and running it again with the best value. Co-authored-by: Daniel Tchon --- xfel/merging/application/phil/phil.py | 12 ++ .../application/statistics/deltaccint.py | 179 ++++++++++++++++++ .../merging/application/statistics/factory.py | 3 + 3 files changed, 194 insertions(+) create mode 100644 xfel/merging/application/statistics/deltaccint.py diff --git a/xfel/merging/application/phil/phil.py b/xfel/merging/application/phil/phil.py index c580bbac79..efb179480c 100644 --- a/xfel/merging/application/phil/phil.py +++ b/xfel/merging/application/phil/phil.py @@ -639,6 +639,18 @@ .help = As an example, could be intensity from *sf.cif .help = Specifically this is a tag searched for in the array name, could be 'tensity' from 'intensity' } + deltaccint + .help = Parameters used when computing ΔCC½ (aka ΔCC internal), a means of filtering out lattices that + .help = degrade the overall CC½. Uses the σ-τ method from Assmann 2016 to avoid splitting the data into + .help = odd/even datasets. Enable by adding the deltaccint worker after the group worker. + { + iqr_ratio = 10 + .type = float + .help = If the ΔCC½ filter is enabled, first compute CC½ when removing every image one at a time, then + .help = compute the IQR of these CC½s. Remove all lattices whose contribution degrades CC½ by more than + .help = IQR * iqr_ratio above the median. You can discover a good IQR by running the program once, + .help = examining the log file where possible values are listed, and running it again with the best value. + } predictions_to_edge { apply = False .type = bool diff --git a/xfel/merging/application/statistics/deltaccint.py b/xfel/merging/application/statistics/deltaccint.py new file mode 100644 index 0000000000..5ff294c16d --- /dev/null +++ b/xfel/merging/application/statistics/deltaccint.py @@ -0,0 +1,179 @@ +from __future__ import absolute_import, division, print_function +from six.moves import range +from dxtbx import flumpy +from dials.array_family import flex +import itertools +import numpy as np +from scitbx.math import five_number_summary +from xfel.merging.application.reflection_table_utils import reflection_table_utils +from xfel.merging.application.worker import worker + + +class deltaccint(worker): + '''Calculates ΔCC½ using the σ-τ method from Assmann 2016''' + + def __repr__(self): + return 'ΔCC½ statistics (σ-τ method)' + + def run(self, experiments, reflections): + self.logger.log_step_time("STATISTICS_DELTA_CCINT") + + comm = self.mpi_helper.comm + MPI = self.mpi_helper.MPI + + assert experiments == None, "Must be run after the group worker" + # need at least 3 reflections to keep multiplicty > 2 when removing an image + filtered = flex.reflection_table() + min_mult = max(3, self.params.merging.minimum_multiplicity) + for refls in reflection_table_utils.get_next_hkl_reflection_table(reflections=reflections): + if len(set(refls['id'])) >= min_mult: + filtered.extend(refls) + + all_expt_ids = sorted(set(itertools.chain.from_iterable(comm.allgather(filtered.experiment_identifiers().values())))) + all_expts_map = {v: k for k, v in enumerate(all_expt_ids)} + + if self.mpi_helper.rank == 0: + self.logger.main_log("Beginning ΔCC½ analysis (σ-τ method from Assmann 2016)") + self.logger.main_log("Removing reflections with less than %d measurements"%min_mult) + self.logger.main_log("N experiments after filtering: %d"%len(all_expt_ids)) + self.logger.main_log("") + + # We need to compute + # 1) variance of the average intensities -> compute averages of all intensities and then compute variance per bin + # 2) average variance of the intensities -> compute variances of all intensities and then compute average per bin + + resolution_binner = self.params.statistics.resolution_binner + hkl_resolution_bins = self.params.statistics.hkl_resolution_bins + + hkl_set = [hkl for hkl in set(filtered['miller_index_asymmetric']) if hkl in hkl_resolution_bins] + n_hkl = len(hkl_set) + hkl_map = {v: k for k, v in enumerate(hkl_set)} + + expt_map = filtered.experiment_identifiers() + + # N expts (all ranks) x N hkl (this rank) + sums = np.zeros((len(all_expt_ids), n_hkl), float) + n = np.zeros((len(all_expt_ids), n_hkl), int) + merged = np.zeros((len(all_expt_ids), n_hkl), float) + variance = np.zeros((len(all_expt_ids), n_hkl), float) + + for refls in reflection_table_utils.get_next_hkl_reflection_table(reflections=filtered): + hkl = refls['miller_index_asymmetric'][0] + if hkl not in hkl_map: continue + hkl_idx = hkl_map[hkl] + intensity = flumpy.to_numpy(refls['intensity.sum.value']) + + # set the sum and n for all expts for this hkl + sums[:,hkl_idx] = np.sum(intensity) + n [:,hkl_idx] = len(refls) + + # For each reflection, subtract it off the experiment it came from, leaving it for the rest of the experiments + for i in range(len(refls)): + expt_idx = all_expts_map[expt_map[refls['id'][i]]] + sums[expt_idx,hkl_idx] -= intensity[i] + n [expt_idx,hkl_idx] -= 1 + merged[:,hkl_idx] = sums[:,hkl_idx]/n[:,hkl_idx] + + # compute variance for each hkl (less the intensity from each experiment) + diff_sq_ = np.zeros(len(all_expt_ids)) + for expt_idx in range(len(all_expt_ids)): + mean_intensity = merged[expt_idx,hkl_idx] + diff_sq_[expt_idx] = np.sum((intensity-mean_intensity)**2) + + for i in range(len(refls)): + expt_idx = all_expts_map[expt_map[refls['id'][i]]] + mean_intensity = merged[expt_idx,hkl_idx] + diff_sq_[expt_idx] -= (intensity[i] - mean_intensity)**2 + + variance[:,hkl_idx] = diff_sq_ / (n[:,hkl_idx]-1) + + # N expts (all ranks) x N bins + n_bins = resolution_binner.n_bins_used() + all_i_sums = np.zeros((len(all_expt_ids), n_bins), float) # sum of the averaged intensities + all_i_n = np.zeros((len(all_expt_ids), n_bins), int) # count of the averaged intensities + all_var_sums = np.zeros((len(all_expt_ids), n_bins), float) # sums of the variances of the intensities + + # Sum up and reduce the bins + for hkl in hkl_set: + bin_idx = hkl_resolution_bins[hkl] - 1 + all_i_sums [:,bin_idx] += merged[:,hkl_map[hkl]] + all_i_n [:,bin_idx] += 1 + all_var_sums[:,bin_idx] += variance[:,hkl_map[hkl]] + + total_var_sums = comm.reduce(all_var_sums, MPI.SUM, 0) + + # Broadcast the average intensities + total_i_sums = comm.allreduce(all_i_sums, op=MPI.SUM) + total_i_n = comm.allreduce(all_i_n, op=MPI.SUM) + total_var_sums = comm.reduce(all_var_sums, op=MPI.SUM) + total_i_average = total_i_sums / total_i_n + + # Compute the variance of the average intensities + # First, the numerator, the difference between each hkl and the average for that hkl's bin (ommiting each experiment once) + diff_sq = np.zeros(merged.shape, float) + for hkl in hkl_set: + diff_sq[:,hkl_map[hkl]] = (merged[:,hkl_map[hkl]] - total_i_average[:,hkl_resolution_bins[hkl]-1]) ** 2 + + # N expts (all ranks) x N bins + diff_sq_sum = np.zeros(all_i_sums.shape, float) + + # Complete the numerator for this rank + for hkl in hkl_set: + diff_sq_sum[:,hkl_resolution_bins[hkl]-1] += diff_sq[:,hkl_map[hkl]] + + total_diff_sq_sum = comm.reduce(diff_sq_sum, MPI.SUM, 0) + + # Report + if self.mpi_helper.rank == 0: + sigma_sq_y = total_diff_sq_sum / (all_i_n-1) + sigma_sq_e = total_var_sums / total_i_n + deltaccint_st = (sigma_sq_y - (0.5 * sigma_sq_e)) / (sigma_sq_y + sigma_sq_e) + + data = flex.double(np.mean(deltaccint_st, axis=1)) * 100 + sorted_data = data.select(flex.sort_permutation(data)) + + mini, q1, med, q3, maxi = five_number_summary(data) + self.logger.main_log("Five number summary") + self.logger.main_log("% 8.4f%% min"%mini) + self.logger.main_log("% 8.4f%% q1"%q1) + self.logger.main_log("% 8.4f%% median"%med) + self.logger.main_log("% 8.4f%% q3"%q3) + self.logger.main_log("% 8.4f%% max"%maxi) + self.logger.main_log("") + + n_worst = min(len(data), 30) + worst = sorted_data[-n_worst:] + iqr = q3-q1 + + self.logger.main_log("Showing ΔCC½ of the worst %d lattices and IQR ratio needed to remove them"%n_worst) + self.logger.main_log(" ΔCC½ (%) IQR ratio Lattices removed") + for i in range(len(worst)): + self.logger.main_log("% 8.4f % 10.1f %d"%(worst[i], (worst[i]-med)/iqr, n_worst-i)) + self.logger.main_log("") + + if self.params.statistics.deltaccint.iqr_ratio: + cut = q3 + iqr * self.params.statistics.deltaccint.iqr_ratio + sel = data > cut + worst_expts_ = flex.std_string(all_expt_ids).select(sel) + + self.logger.main_log("Removing %d experiments out of %d using IQR ratio %.1f"%(len(worst_expts_), len(all_expt_ids), self.params.statistics.deltaccint.iqr_ratio)) + + # Broadcast the worst experiments to cut + else: + worst_expts_ = None + + if self.params.statistics.deltaccint.iqr_ratio: + worst_expts = comm.bcast(worst_expts_, 0) + self.logger.log("Starting number of reflections: %d"%len(reflections)) + self.logger.log("Reflections after filtering by minimum multiplicity of %d: %d"%(min_mult, len(filtered))) + reflections.remove_on_experiment_identifiers(worst_expts) + reflections.reset_ids() + self.logger.log("Reflections after filtering by ΔCC½: %d"%len(reflections)) + + self.logger.log_step_time("STATISTICS_DELTA_CCINT", True) + + return experiments, reflections + +if __name__ == '__main__': + from xfel.merging.application.worker import exercise_worker + exercise_worker(deltaccint) diff --git a/xfel/merging/application/statistics/factory.py b/xfel/merging/application/statistics/factory.py index fc906133ed..1def5e7169 100644 --- a/xfel/merging/application/statistics/factory.py +++ b/xfel/merging/application/statistics/factory.py @@ -3,6 +3,7 @@ from xfel.merging.application.statistics.beam_statistics import beam_statistics from xfel.merging.application.statistics.intensity_resolution_statistics import intensity_resolution_statistics from xfel.merging.application.statistics.intensity_resolution_statistics_cxi import intensity_resolution_statistics_cxi +from xfel.merging.application.statistics.deltaccint import deltaccint from xfel.merging.application.statistics.experiment_resolution_statistics import experiment_resolution_statistics from xfel.merging.application.statistics.intensity_histogram import intensity_histogram from xfel.merging.application.worker import factory as factory_base @@ -27,4 +28,6 @@ def from_parameters(params, additional_info=[], mpi_helper=None, mpi_logger=None return [intensity_resolution_statistics_cxi(params, mpi_helper, mpi_logger)] elif info_count > 1 and additional_info[1] == 'histogram': return [intensity_histogram(params, mpi_helper, mpi_logger)] + elif additional_info[0] == 'deltaccint': + return [deltaccint(params, mpi_helper, mpi_logger)] From a32311d79a78ca228bb336c373684683a8c4c041 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Fri, 16 Aug 2024 17:04:08 -0700 Subject: [PATCH 646/748] Testing binding ligand binding energy --- mmtbx/geometry_restraints/base_qm_manager.py | 37 +++++++++++++++---- .../geometry_restraints/quantum_interface.py | 2 + .../quantum_restraints_manager.py | 35 +++++++++++++++--- mmtbx/programs/quantum_interface.py | 2 +- mmtbx/refinement/energy_monitor.py | 23 ++++++++++++ 5 files changed, 85 insertions(+), 14 deletions(-) diff --git a/mmtbx/geometry_restraints/base_qm_manager.py b/mmtbx/geometry_restraints/base_qm_manager.py index 1c064586c9..3ca7d55595 100644 --- a/mmtbx/geometry_restraints/base_qm_manager.py +++ b/mmtbx/geometry_restraints/base_qm_manager.py @@ -390,12 +390,22 @@ def get_strain(self, redirect_output=False, log=StringIO(), **kwds): + # + # Get the strain energy of a ligand. Only works? when this is applied to + # the ligand. + # old_preamble = self.preamble + # + # get energy with just the H opt + # start_energy, junk = self.get_energy(optimise_h=True, redirect_output=redirect_output, cleanup=cleanup, log=log) self.preamble = old_preamble+'_strain' + # + # optimise all atoms positions and get energy + # final_energy, units = self.get_opt(redirect_output=redirect_output, cleanup=cleanup, log=log) @@ -406,15 +416,20 @@ def get_strain(self, self.preamble = old_preamble return self.strain, self.units - def get_bound(self, - cleanup=False, - file_read=True, - redirect_output=False, - log=StringIO(), - **kwds - ): + def get_something_energy( self, + preamble, + cleanup=False, + file_read=True, + redirect_output=False, + log=StringIO(), + verbose=False, + **kwds + ): + if verbose: + print('get %s' % preamble) + print(self) old_preamble = self.preamble - self.preamble += '_bound' + self.preamble += '_%s' % preamble energy, units = self.get_energy(optimise_h=True, redirect_output=redirect_output, cleanup=cleanup, @@ -422,6 +437,12 @@ def get_bound(self, self.preamble = old_preamble return energy, units + def get_bound(self, **kwds): + return self.get_something_energy('bound', **kwds) + + def get_pocket(self, **kwds): + return self.get_something_energy('pocket', **kwds) + def get_gradients(self): assert 0 diff --git a/mmtbx/geometry_restraints/quantum_interface.py b/mmtbx/geometry_restraints/quantum_interface.py index 33f94026fe..008d4aef8d 100644 --- a/mmtbx/geometry_restraints/quantum_interface.py +++ b/mmtbx/geometry_restraints/quantum_interface.py @@ -89,6 +89,7 @@ def get_qm_restraints_scope(validate=True, verbose=False): calculate = *in_situ_opt starting_energy final_energy \ starting_strain final_strain starting_bound final_bound \ +starting_binding final_binding \ starting_higher_single_point final_higher_single_point .type = choice(multi=True) .help = Choose QM calculations to run @@ -97,6 +98,7 @@ def get_qm_restraints_scope(validate=True, verbose=False): strain_energy_of_starting_ligand_geometry \ strain_energy_of_final_ligand_geometry \ starting_energy_of_bound_ligand_cluster \ + starting_binding_energy_of)ligand final_binding_energy_of_ligand \ final_energy_of_bound_ligand_cluster not_implemented not_implemented write_files = *restraints pdb_core pdb_buffer pdb_final_core pdb_final_buffer diff --git a/mmtbx/geometry_restraints/quantum_restraints_manager.py b/mmtbx/geometry_restraints/quantum_restraints_manager.py index b7f7689a4b..2464474791 100644 --- a/mmtbx/geometry_restraints/quantum_restraints_manager.py +++ b/mmtbx/geometry_restraints/quantum_restraints_manager.py @@ -514,9 +514,16 @@ def get_qm_manager(ligand_model, buffer_model, qmr, program_goal, log=StringIO() solvent_model = default_solvent_model elif program_goal in ['opt', 'bound']: electron_model = buffer_model + elif program_goal in ['pocket']: + tmps=[] + for atom in ligand_model.get_atoms(): tmps.append(atom.tmp) + list_of_i_seqs=[] + for atom in buffer_model.get_atoms(): + if atom.tmp not in tmps: list_of_i_seqs.append(atom.i_seq) + pocket_model=buffer_model.select(flex.size_t(list_of_i_seqs)) + electron_model=pocket_model else: assert 0, 'program_goal %s not in list' % program_goal - # specific_atom_charges = get_specific_atom_charges(qmr) specific_atom_charges = qmr.specific_atom_charges total_charge = quantum_interface.electrons( electron_model, @@ -598,6 +605,12 @@ def running_this_macro_cycle(qmr, pre_refinement=True, verbose=False, ): + if verbose: + print(qmr) + print('macro_cycle',macro_cycle) + print('number_of_macro_cycles',number_of_macro_cycles) + print('energy_only',energy_only) + print('pre_refinement',pre_refinement) from mmtbx.geometry_restraints.quantum_interface import get_qi_macro_cycle_array if not energy_only: if 'in_situ_opt' not in qmr.calculate: return False @@ -612,13 +625,13 @@ def running_this_macro_cycle(qmr, return 'restraints' else: if pre_refinement: - checks = 'starting_strain starting_energy starting_bound' + checks = 'starting_strain starting_energy starting_bound starting_binding' tmp = set(checks.split()) inter = tmp.intersection(set(qmr.calculate)) if macro_cycle==1: return list(inter) else: - checks = 'final_strain final_energy final_bound' + checks = 'final_strain final_energy final_bound final_binding' tmp = set(checks.split()) inter = tmp.intersection(set(qmr.calculate)) if macro_cycle==number_of_macro_cycles or macro_cycle==-1: @@ -892,7 +905,7 @@ def update_dihedral_restraints_simple(model): angle_proxy.angle_ideal=angle def get_program_goal(qmr, macro_cycle=None, energy_only=False): - program_goal=[] # can be 'opt', 'energy', 'strain' + program_goal=[] if not energy_only: program_goal=['opt'] return program_goal @@ -903,6 +916,11 @@ def get_program_goal(qmr, macro_cycle=None, energy_only=False): program_goal.append('strain') if qmr.calculate.count('starting_bound'): program_goal.append('bound') + if qmr.calculate.count('starting_binding'): + program_goal.append('energy') + program_goal.append('strain') + program_goal.append('bound') + program_goal.append('pocket') else: # only called with final energy on final macro cycle if qmr.calculate.count('final_energy'): program_goal.append('energy') @@ -910,6 +928,11 @@ def get_program_goal(qmr, macro_cycle=None, energy_only=False): program_goal.append('strain') if qmr.calculate.count('final_bound'): program_goal.append('bound') + if qmr.calculate.count('final_binding'): + program_goal.append('energy') + program_goal.append('strain') + program_goal.append('bound') + program_goal.append('pocket') return program_goal def setup_qm_jobs(model, @@ -1010,13 +1033,15 @@ def run_jobs(objects, macro_cycle, nproc=1, log=StringIO()): buffer_model.get_number_of_atoms()) time_query = qmm.get_timings() curve_fit_3d.load_and_display(qmm.program_goal, key, time_query, show=True) - elif qmm.program_goal in ['energy', 'strain', 'bound']: + elif qmm.program_goal in ['energy', 'strain', 'bound', 'pocket']: energy=xyz units=xyz_buffer xyz=None xyz_buffer=None qmm.preamble += '_%s' % qmm.program_goal if qmm.program_goal in ['bound']: qmm.preamble += '_energy' + elif qmm.program_goal in ['pocket']: qmm.preamble += '_energy' + # qmm.preamble=qmm.preamble.replace(qmm.program_goal, 'pocket_energy') charge = qmm.read_charge() # except: charge=-99 else: diff --git a/mmtbx/programs/quantum_interface.py b/mmtbx/programs/quantum_interface.py index 6eced47b6b..8580e86f0d 100644 --- a/mmtbx/programs/quantum_interface.py +++ b/mmtbx/programs/quantum_interface.py @@ -1133,7 +1133,7 @@ def run_qmr(self, format, log=None): from mmtbx.refinement.energy_monitor import digest_return_energy_object model = self.data_manager.get_model() qmr = self.params.qi.qm_restraints[0] - checks = 'starting_strain starting_energy starting_bound' + checks = 'starting_strain starting_energy starting_bound starting_binding' energies = None rcs=[] if any(item in checks for item in qmr.calculate): diff --git a/mmtbx/refinement/energy_monitor.py b/mmtbx/refinement/energy_monitor.py index 262abe05d6..fc4bf95950 100644 --- a/mmtbx/refinement/energy_monitor.py +++ b/mmtbx/refinement/energy_monitor.py @@ -5,6 +5,11 @@ 'hartree' : 627.503, } +rename = {'pocket+energy-bound': 'Binding Energy', + 'energy-strain' : 'Unbound Energy', + # 'energy' : 'Bound Energy' + } + def _print_energy_in_kcal(e, units): if units.lower() in to_kcal_mol: return '%15.1f %s' % (e*to_kcal_mol[units.lower()], 'kcal/mol') @@ -18,6 +23,9 @@ def print_energy_in_kcal(ga): units=ga.units.lower() if d in ['opt', 'bound']: atoms=b elif d in ['energy', 'strain']: atoms=l + elif d in ['pocket']: atoms=b-l + else: assert 0 + d=rename.get(d,d) s.append('%-22s %s (atoms %4d, charge %2d) ' % (d, _print_energy_in_kcal(e, units), atoms, c)) return s @@ -29,8 +37,14 @@ def __init__(self): def as_string(self, verbose=False): # from libtbx import easy_pickle # easy_pickle.dump('ga.pickle', self) + plusses = [ ['pocket', 'energy'], + # ['pocket', 'strain'], + ] pairs = [['bound', 'opt'], ['bound-opt', 'strain'], + ['pocket+energy', 'bound'], + # ['pocket+energy-strain', 'bound'], + ['energy', 'strain'], ] s='' tmp = {} @@ -51,6 +65,14 @@ def as_string(self, verbose=False): for line in rc: t += '%s%s\n' % (' '*6, line) if verbose: print('macro_cycle %d %s' % (i+1,t)) + + for k1, k2 in plusses: + if not (t_atoms[i].get(k1, False) and t_atoms[i].get(k2, False)): + continue + if t_atoms[i][k1]!=t_atoms[i][k2]: continue + t_atoms[i]['%s+%s' % (k1,k2)]=b + tmp[i]['%s+%s' % (k1,k2)]=tmp[i][k1]+tmp[i][k2] + for k1, k2 in pairs: if not (t_atoms[i].get(k1, False) and t_atoms[i].get(k2, False)): continue @@ -58,6 +80,7 @@ def as_string(self, verbose=False): if k1 in tmp[i] and k2 in tmp[i]: e = tmp[i][k1]-tmp[i][k2] k3='%s-%s' % (k1,k2) + k3=rename.get(k3, k3) t+='%s%-22s %s (atoms %4d)\n' % (' '*6, k3, _print_energy_in_kcal(e, units), From d317725f78bd496140fa4d9819af60cf0593b8e4 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 16 Aug 2024 21:42:15 -0700 Subject: [PATCH 647/748] Reduce2: remove an unnecessary model.select() call. This improves runtime, especially for large models. --- mmtbx/hydrogens/reduce_hydrogen.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index e93dea6e88..944c27a5dc 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -288,9 +288,12 @@ def run(self): # (when heavy atom is missing, H needs not to be placed) t0 = time.time() sel_isolated = self.model.isolated_atoms_selection() - self.sel_lone_H = sel_h & sel_isolated - if not self.sel_lone_H.all_eq(False): - self.model = self.model.select(~self.sel_lone_H) + sel_lone_H = sel_h & sel_isolated + # As h_parameterization will not include these, they can be removed in the + # next step; for book-keeping it is useful to keep track of lone H as a + # selection + #if not sel_lone_H.all_eq(False): + # self.model = self.model.select(~sel_lone_H) self.time_remove_isolated = round(time.time()-t0, 2) sel_h = self.model.get_hd_selection() @@ -310,9 +313,12 @@ def run(self): sel_h_in_para = flex.bool( [bool(x) for x in riding_h_manager.h_parameterization]) sel_h_not_in_para = sel_h_in_para.exclusive_or(sel_h) + # no need to display lone H atoms in the log, so remove from labels + sel_h_not_in_para_but_not_lone = sel_h_not_in_para.exclusive_or(sel_lone_H) self.site_labels_no_para = [atom.id_str().replace('pdb=','').replace('"','') - for atom in self.model.get_hierarchy().atoms().select(sel_h_not_in_para)] - self.model = self.model.select(~sel_h_not_in_para) + for atom in self.model.get_hierarchy().atoms().select(sel_h_not_in_para_but_not_lone)] + if not sel_h_not_in_para.all_eq(False): + self.model = self.model.select(~sel_h_not_in_para) self.time_remove_H_nopara = round(time.time()-t0, 2) # f = open("intermediate4.pdb","w") From a5ae3c45f245dfc195c2edc7a18b46905b8cf52e Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Sat, 17 Aug 2024 11:41:41 -0700 Subject: [PATCH 648/748] CI: fix chem_data location --- .azure-pipelines/templates/download-data-cache.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.azure-pipelines/templates/download-data-cache.yml b/.azure-pipelines/templates/download-data-cache.yml index 689670843b..39be342785 100644 --- a/.azure-pipelines/templates/download-data-cache.yml +++ b/.azure-pipelines/templates/download-data-cache.yml @@ -22,14 +22,13 @@ steps: displayName: Download chem_data - script: | - if [ ! -d "$(System.DefaultWorkingDirectory)/chem_data/.git" ]; then - rm -fr $(System.DefaultWorkingDirectory)/chem_data - cd $(System.DefaultWorkingDirectory) + if [ ! -d "$(Pipeline.Workspace)/modules/chem_data" ]; then + cd $(Pipeline.Workspace)/modules git clone https://gitlab.com/phenix_project/chem_data.git git lfs install --local git lfs pull fi - cd $(System.DefaultWorkingDirectory)/chem_data + cd $(Pipeline.Workspace)/modules/chem_data git reset --hard origin/main git lfs install --local git pull --rebase From a8de1d4fe27e7e2ef99d3f607b3395d5f4e6e232 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Sat, 17 Aug 2024 13:38:14 -0700 Subject: [PATCH 649/748] bootstrap: use git-lfs for chem_data [skip ci] --- libtbx/auto_build/bootstrap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libtbx/auto_build/bootstrap.py b/libtbx/auto_build/bootstrap.py index 0070151b7b..960f26b589 100644 --- a/libtbx/auto_build/bootstrap.py +++ b/libtbx/auto_build/bootstrap.py @@ -2439,7 +2439,7 @@ def add_module(self, module, workdir=None, module_directory=None): super(PhenixBuilder, self).add_module(module, workdir, module_directory) # update phenix_regression and phenix_examples with git-lfs - if module == 'phenix_examples' or module == 'phenix_regression': + if module == 'phenix_examples' or module == 'phenix_regression' or module == 'chem_data': # prepend path for check dev_env = os.path.join('.', 'dev_env', 'bin') if sys.platform == 'win32': From 4602610fdc843dc5a664b7373bd0fd75b8c48fc2 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Sat, 17 Aug 2024 13:50:07 -0700 Subject: [PATCH 650/748] bootstrap: avoid overwriting parameters when downloading geostd [skip ci] --- libtbx/auto_build/bootstrap.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libtbx/auto_build/bootstrap.py b/libtbx/auto_build/bootstrap.py index 960f26b589..f49e1c2d01 100644 --- a/libtbx/auto_build/bootstrap.py +++ b/libtbx/auto_build/bootstrap.py @@ -1576,8 +1576,8 @@ def run(self): # add geostd to chem_data if module == 'chem_data': action = MODULES.get_module('geostd')().get_url(auth=self.get_auth()) - method, parameters = action[0], action[1:] - self._add_git('geostd', parameters, destination=self.opjoin('modules', 'chem_data', 'geostd')) + method, geostd_parameters = action[0], action[1:] + self._add_git('geostd', geostd_parameters, destination=self.opjoin('modules', 'chem_data', 'geostd')) # Use dials-2.2 branches for Python 2 if (module == 'dials' or module == 'dxtbx' or module == 'xia2') and not self.python3: From daea0c43ffa559fa4b4f5e87e4d354643cab1b97 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Mon, 19 Aug 2024 09:39:38 -0700 Subject: [PATCH 651/748] safety check for empty chains --- mmtbx/monomer_library/linking_mixins.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index a7d7679208..81876419d2 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -428,6 +428,7 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., atoms_in_first_last_rgs = {} for c in self.pdb_hierarchy.chains(): for i in [0,-1]: + if not c.residue_groups(): continue rg = c.residue_groups()[i] abs_i = abs(i) for a in rg.atoms(): From 9a201d10599d49a638d19dfc8f701a2dcfc04399 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Mon, 19 Aug 2024 12:51:30 -0700 Subject: [PATCH 652/748] more specific cBeta restraints because MTX --- mmtbx/geometry_restraints/c_beta.py | 5 +++++ mmtbx/monomer_library/linking_mixins.py | 6 +----- mmtbx/monomer_library/pdb_interpretation.py | 2 ++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/mmtbx/geometry_restraints/c_beta.py b/mmtbx/geometry_restraints/c_beta.py index 1087b2e724..49070a64c5 100644 --- a/mmtbx/geometry_restraints/c_beta.py +++ b/mmtbx/geometry_restraints/c_beta.py @@ -49,6 +49,11 @@ def get_c_beta_torsion_proxies(pdb_hierarchy, continue # check for correct chiral volume sites_cart = [N_atom.xyz, C_atom.xyz, CA_atom.xyz, CB_atom.xyz] + CAC_dist = C_atom.distance(CA_atom) + if CAC_dist>2.: + c_beta_residues_skipped.setdefault('CA---C', []) + c_beta_residues_skipped['CA---C'].append(CB_atom) + continue chiral = cctbx.geometry_restraints.chirality( sites_cart, volume_ideal=0., diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index 81876419d2..213e743198 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -351,9 +351,7 @@ def process_nonbonded_for_links(self, from cctbx import crystal from cctbx.array_family import flex # - def _nonbonded_pair_objects(max_bonded_cutoff=3., - i_seqs=None, - ): + def _nonbonded_pair_objects(max_bonded_cutoff=3., i_seqs=None): if i_seqs is None: atoms = self.pdb_hierarchy.atoms() i_seqs = flex.size_t() @@ -385,8 +383,6 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., shell_asu_tables=[pair_asu_table]) return nonbonded_proxies, sites_cart, pair_asu_table, asu_mappings, i_seqs # - - # if(log is not None): print(""" Automatic linking diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index c66d574b53..bb0d778a31 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -6058,6 +6058,8 @@ def geometry_restraints_manager(self, outl += " Input volumes are d-peptide like\n" elif key=="d-peptide": outl += " Input residue name is d-peptide\n" + elif key=='CA---C': + outl += " Input residue is complicated and confusing\n" for cb_atom in item: outl += " %s\n"% cb_atom.id_str() if outl: From dc079483aa4049e5588cd8d8327289a62941fc6f Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Mon, 19 Aug 2024 12:51:51 -0700 Subject: [PATCH 653/748] pass file_read option correctly --- mmtbx/geometry_restraints/base_qm_manager.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mmtbx/geometry_restraints/base_qm_manager.py b/mmtbx/geometry_restraints/base_qm_manager.py index 3ca7d55595..a2e208cb40 100644 --- a/mmtbx/geometry_restraints/base_qm_manager.py +++ b/mmtbx/geometry_restraints/base_qm_manager.py @@ -316,7 +316,7 @@ def get_opt(self, coordinates = None rc=True - if check_file_read_safe: + if file_read and check_file_read_safe: if verbose: print('check_file_read_safe',check_file_read_safe) rc = self.check_file_read_safe(optimise_ligand=optimise_ligand, optimise_h=optimise_h, @@ -401,6 +401,7 @@ def get_strain(self, start_energy, junk = self.get_energy(optimise_h=True, redirect_output=redirect_output, cleanup=cleanup, + file_read=file_read, log=log) self.preamble = old_preamble+'_strain' # @@ -408,6 +409,7 @@ def get_strain(self, # final_energy, units = self.get_opt(redirect_output=redirect_output, cleanup=cleanup, + file_read=file_read, log=log) final_energy, units = self.read_energy() self.strain = start_energy-final_energy @@ -433,6 +435,7 @@ def get_something_energy( self, energy, units = self.get_energy(optimise_h=True, redirect_output=redirect_output, cleanup=cleanup, + file_read=file_read, log=log) self.preamble = old_preamble return energy, units From 17f1a72121be3c440728a139693e22ee4d201cbe Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 20 Aug 2024 16:28:22 -0700 Subject: [PATCH 654/748] pdb_int speedup. Early exits across linking routines. --- mmtbx/conformation_dependent_library/mcl.py | 9 ++++----- .../mcl_sf4_coordination.py | 4 ++++ .../metal_coordination_library.py | 4 ++++ mmtbx/monomer_library/linking_mixins.py | 2 ++ 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/mmtbx/conformation_dependent_library/mcl.py b/mmtbx/conformation_dependent_library/mcl.py index 816559d171..9a22d61421 100644 --- a/mmtbx/conformation_dependent_library/mcl.py +++ b/mmtbx/conformation_dependent_library/mcl.py @@ -66,10 +66,10 @@ def _atom_id(a, show_i_seq=False): metal_coordination_library.get_metal_coordination_proxies, metal_coordination_library.get_proxies_zn, ], - ['Mg2+ Nucleotide coordination', - metal_coordination_library.get_metal_coordination_proxies, - metal_coordination_library.get_proxies_mg_nuc, - ], + # ['Mg2+ Nucleotide coordination', + # metal_coordination_library.get_metal_coordination_proxies, + # metal_coordination_library.get_proxies_mg_nuc, + # ], ] outl = '' outl_debug = '' @@ -77,7 +77,6 @@ def _atom_id(a, show_i_seq=False): sites_c = pdb_hierarchy.atoms().extract_xyz() nb_proxies = grm.pair_proxies( sites_cart=sites_c).nonbonded_proxies - for label, get_coordination, get_all_proxies in hooks: rc = get_coordination( pdb_hierarchy=pdb_hierarchy, diff --git a/mmtbx/conformation_dependent_library/mcl_sf4_coordination.py b/mmtbx/conformation_dependent_library/mcl_sf4_coordination.py index 36932f674d..80e33679b9 100644 --- a/mmtbx/conformation_dependent_library/mcl_sf4_coordination.py +++ b/mmtbx/conformation_dependent_library/mcl_sf4_coordination.py @@ -122,6 +122,10 @@ def get_sulfur_iron_cluster_coordination(pdb_hierarchy, done_aa = [] atoms = pdb_hierarchy.atoms() sites_cart = atoms.extract_xyz() + selection_string = " or ".join(['resname %s' %x for x in sf_clusters]) + s = pdb_hierarchy.atom_selection_cache().selection(selection_string) + if s.all_eq(False): + return coordination for item in nonbonded_proxies.sorted_value_proxies_generator( by_value="delta", sites_cart=sites_cart, diff --git a/mmtbx/conformation_dependent_library/metal_coordination_library.py b/mmtbx/conformation_dependent_library/metal_coordination_library.py index cb7c80eaf5..6c437211ef 100644 --- a/mmtbx/conformation_dependent_library/metal_coordination_library.py +++ b/mmtbx/conformation_dependent_library/metal_coordination_library.py @@ -95,6 +95,10 @@ def is_residue_already_linked_to_metal(linked, atom): if params is not None: hbond_distance_cutoff = params.hbond_distance_cutoff mbonds = {} + selection_string = " or ".join(["element ZN"]) + s = pdb_hierarchy.atom_selection_cache().selection(selection_string) + if s.all_eq(False): + return mbonds atoms = pdb_hierarchy.atoms() sites_cart = atoms.extract_xyz() for item in nonbonded_proxies.sorted_value_proxies_generator( diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index 213e743198..7f5bff5937 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -478,6 +478,8 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., i_seqs=None): if bond_asu_table.contains(i_seq, j_seq, 1): continue atom1 = atoms[i_seq] atom2 = atoms[j_seq] + if atom1.element_is_hydrogen() or atom2.element_is_hydrogen(): + continue if exclude_this_nonbonded: key = (selection_1,selection_2) if key not in exclude_out_lines: From f5996c1d86e50c8f7915f9cb67125637837d718b Mon Sep 17 00:00:00 2001 From: randyjread Date: Wed, 21 Aug 2024 17:30:55 +0100 Subject: [PATCH 655/748] Refactor code so that sigmaA calculation of model vs cryo-EM map can be called externally. --- cctbx/maptbx/prepare_map_for_docking.py | 255 +++++++++++++----------- 1 file changed, 138 insertions(+), 117 deletions(-) diff --git a/cctbx/maptbx/prepare_map_for_docking.py b/cctbx/maptbx/prepare_map_for_docking.py index 8b2884b974..f23018316c 100644 --- a/cctbx/maptbx/prepare_map_for_docking.py +++ b/cctbx/maptbx/prepare_map_for_docking.py @@ -1386,6 +1386,129 @@ def local_mean_density(mm, radius): return local_mean_mm +def sigmaA_from_model_in_map(expectE, dobs, Ecalc, over_sampling_factor, + verbosity=0, log=sys.stdout): + """ + Compute sigmaA values needed to explain agreement of model with map given map errors + + Compulsory arguments: + expectE: Emean giving expected E for map + dobs: weighting factor for map coefficient accuracy + Ecalc: calculated E-values for placed model + over_sampling_factor: account for oversampling in LLG calculation + relevant here for precision of sigmaA estimate + Optional arguments: + verbosity: levels greater than default of 0 progressively more verbose + log: destination for printing if any + """ + model_sigmaA = expectE.customized_copy(data=flex.double(expectE.size(),0)) + xdat = [] + ydat = [] + wdat = [] + if expectE.binner() is None: + expectE.setup_binner_d_star_sq_bin_size() + if verbosity > 1: + print("SigmaA curve for placed model contribution",file=log) + print(" # of terms mean(ssqr) sigmaA sigma(sigmaA)") + for i_bin in expectE.binner().range_used(): + sel = expectE.binner().selection(i_bin) + eEsel = expectE.select(sel) + abseE = eEsel.amplitudes().data() + p1 = eEsel.phases().data() + Ecalc_sel = Ecalc.select(sel) + absEc = Ecalc_sel.amplitudes().data() + sigmaP = flex.mean_default(flex.pow2(absEc),0.) + absEc /= math.sqrt(sigmaP) + Ecalc.data().set_selected(sel, + Ecalc.data().select(sel) / math.sqrt(sigmaP)) + Ecalc_sel /= math.sqrt(sigmaP) + p2 = Ecalc_sel.phases().data() + cosdphi = flex.cos(p2 - p1) + dobssel = dobs.data().select(sel) + + # Solve for sigmaA yielding 1st derivative of LLG approximately equal to zero (assuming only numerator matters) + sum0 = flex.sum(2.*dobssel*abseE*absEc*cosdphi) + sum1 = flex.sum(2*flex.pow2(dobssel) * (1. - flex.pow2(abseE) - flex.pow2(absEc))) + sum2 = flex.sum(2*flex.pow(dobssel,3)*abseE*absEc*cosdphi) + sum3 = flex.sum(- 2*flex.pow(dobssel,4)) + u1 = -2*sum2**3 + 9*sum1*sum2*sum3 - 27*sum0*sum3**2 + sqrt_arg = u1**2 - 4*(sum2**2 - 3*sum1*sum3)**3 + if sqrt_arg < 0: # Paranoia: haven't run into this in a wide variety of calculations + raise Sorry("Argument of square root in sigmaA calculation is negative") + third = 1./3 + x1 = (u1 + math.sqrt(sqrt_arg))**third + sigmaA = ( (2 * 2.**third * sum2**2 - 6 * 2.**third*sum1*sum3 + - 2*sum2*x1 + 2.**(2*third) * x1**2) / + (6 * sum3 * x1) ) + sigmaA = max(min(sigmaA,0.999),1.E-6) + # Now work out approximate e.s.d. of sigmaA estimate from 2nd derivative of LLG at optimal sigmaA + denom = flex.pow((1-flex.pow2(dobssel)*sigmaA**2),3) + sum0 = flex.sum((2*flex.pow2(dobssel) * (1. - flex.pow2(abseE) - flex.pow2(absEc)))/denom) + sum1 = flex.sum((12*flex.pow(dobssel,3)*abseE*absEc*cosdphi)/denom) + sum2 = flex.sum((-6*flex.pow(dobssel,4)*(flex.pow2(abseE) + flex.pow2(absEc)))/denom) + sum3 = flex.sum((4*flex.pow(dobssel,5)*abseE*absEc*cosdphi)/denom) + sum4 = flex.sum((-2*flex.pow(dobssel,6))/denom) + d2LLGbydsigmaA = sum0 + sum1*sigmaA + sum2*sigmaA**2 + sum3*sigmaA**3 + sum4*sigmaA**4 + d2LLGbydsigmaA /= over_sampling_factor + sigma_sigmaA = 1./math.sqrt(abs(d2LLGbydsigmaA)) + ssqr = flex.mean_default(eEsel.d_star_sq().data(),0) + ndat = dobssel.size() + if verbosity > 1: + print(ndat,ssqr,sigmaA,sigma_sigmaA,file=log) + xdat.append(ssqr) + ydat.append(math.log(sigmaA)) + wdat.append(abs(d2LLGbydsigmaA)) # Inverse variance estimate + + xdat = flex.double(xdat) + ydat = flex.double(ydat) + wdat = flex.double(wdat) + W = flex.sum(wdat) + Wx = flex.sum(wdat * xdat) + Wy = flex.sum(wdat * ydat) + Wxx = flex.sum(wdat * xdat * xdat) + Wxy = flex.sum(wdat * xdat * ydat) + slope = (W * Wxy - Wx * Wy) / (W * Wxx - Wx * Wx) + intercept = (Wy * Wxx - Wx * Wxy) / (W * Wxx - Wx * Wx) + frac_complete = math.exp(2.*intercept) + if verbosity > 0: + print("Slope and intercept of sigmaA plot for placed model contribution: ",slope,intercept,file=log) + print("Approximate fraction of scattering: ",frac_complete,file=log) + linlogsiga = flex.double() + logsiga_combined = flex.double() + sigma_linlog = math.log(1.5) # Allow 50% error in linear fit + i_bin_used = 0 + for i_bin in expectE.binner().range_used(): + sigmaA = math.exp(ydat[i_bin_used]) + # For complete model, slope should be negative, but can be positive if the + # modelled part is much better ordered than the larger unmodelled part + linlog = min(math.log(0.999),(intercept + slope*xdat[i_bin_used])) + linlogsiga.append(linlog) + sigma_sigmaA = 1./math.sqrt(wdat[i_bin_used]) + sigma_lnsigmaA = math.exp(-ydat[i_bin_used])*sigma_sigmaA + combined_logsiga = ((ydat[i_bin_used]/sigma_lnsigmaA**2 + linlog/sigma_linlog**2) / + (1./sigma_lnsigmaA**2 + 1./sigma_linlog**2) ) + logsiga_combined.append(combined_logsiga) + combined_siga = math.exp(combined_logsiga) + + sel = expectE.binner().selection(i_bin) + model_sigmaA.data().set_selected(sel, combined_siga) + i_bin_used += 1 + + if verbosity > 1: + import matplotlib.pyplot as plt + fig, ax = plt.subplots(2,1) + ax[0].plot(xdat,ydat,label="ln(sigmaA)") + ax[0].plot(xdat,linlogsiga,label="line fit") + ax[0].plot(xdat,logsiga_combined,label="combined") + ax[0].legend(loc="upper right") + ax[1].plot(xdat,flex.exp(ydat),label="sigmaA") + ax[1].plot(xdat,flex.exp(linlogsiga),label="line fit") + ax[1].plot(xdat,flex.exp(logsiga_combined),label="combined") + ax[1].legend(loc="lower left") + plt.show() + + return(model_sigmaA) + def assess_cryoem_errors( mmm, d_min, determine_ordered_volume=True, @@ -1894,129 +2017,27 @@ def assess_cryoem_errors( # write_mtz(expectE,"expectE.mtz","eE") # write_mtz(masked_model_E,"masked_model.mtz","masked_model") - expectE_mod = expectE.deep_copy() # For temporary kludge where expectE is modified instead of adding fixed contribution in phasertng if masked_model_contributes: - masked_model_sigmaA = expectE.customized_copy(data=flex.double(expectE.size(),0)) - xdat = [] - ydat = [] - wdat = [] - expectE.use_binner_of(mc1) - if verbosity > 1: - print("SigmaA curve for fixed model contribution",file=log) - print(" # of terms mean(ssqr) sigmaA sigma(sigmaA)") - for i_bin in mc1.binner().range_used(): - sel = expectE.binner().selection(i_bin) - eEsel = expectE.select(sel) - abseE = eEsel.amplitudes().data() - p1 = eEsel.phases().data() - masked_coeffs_sel = masked_model_E.select(sel) - absEc = masked_coeffs_sel.amplitudes().data() - sigmaP = flex.mean_default(flex.pow2(absEc),0.) - absEc /= math.sqrt(sigmaP) - masked_model_E.data().set_selected(sel, - masked_model_E.data().select(sel) / math.sqrt(sigmaP)) - masked_coeffs_sel /= math.sqrt(sigmaP) - p2 = masked_coeffs_sel.phases().data() - cosdphi = flex.cos(p2 - p1) - dobssel = dobs.data().select(sel) - - # Solve for sigmaA yielding 1st derivative of LLG approximately equal to zero (assuming only numerator matters) - sum0 = flex.sum(2.*dobssel*abseE*absEc*cosdphi) - sum1 = flex.sum(2*flex.pow2(dobssel) * (1. - flex.pow2(abseE) - flex.pow2(absEc))) - sum2 = flex.sum(2*flex.pow(dobssel,3)*abseE*absEc*cosdphi) - sum3 = flex.sum(- 2*flex.pow(dobssel,4)) - u1 = -2*sum2**3 + 9*sum1*sum2*sum3 - 27*sum0*sum3**2 - sqrt_arg = u1**2 - 4*(sum2**2 - 3*sum1*sum3)**3 - if sqrt_arg < 0: # Paranoia: haven't run into this in a wide variety of calculations - raise Sorry("Argument of square root in sigmaA calculation is negative") - third = 1./3 - x1 = (u1 + math.sqrt(sqrt_arg))**third - sigmaA = ( (2 * 2.**third * sum2**2 - 6 * 2.**third*sum1*sum3 - - 2*sum2*x1 + 2.**(2*third) * x1**2) / - (6 * sum3 * x1) ) - sigmaA = max(min(sigmaA,0.999),1.E-6) - # Now work out approximate e.s.d. of sigmaA estimate from 2nd derivative of LLG at optimal sigmaA - denom = flex.pow((1-flex.pow2(dobssel)*sigmaA**2),3) - sum0 = flex.sum((2*flex.pow2(dobssel) * (1. - flex.pow2(abseE) - flex.pow2(absEc)))/denom) - sum1 = flex.sum((12*flex.pow(dobssel,3)*abseE*absEc*cosdphi)/denom) - sum2 = flex.sum((-6*flex.pow(dobssel,4)*(flex.pow2(abseE) + flex.pow2(absEc)))/denom) - sum3 = flex.sum((4*flex.pow(dobssel,5)*abseE*absEc*cosdphi)/denom) - sum4 = flex.sum((-2*flex.pow(dobssel,6))/denom) - d2LLGbydsigmaA = sum0 + sum1*sigmaA + sum2*sigmaA**2 + sum3*sigmaA**3 + sum4*sigmaA**4 - d2LLGbydsigmaA /= over_sampling_factor - sigma_sigmaA = 1./math.sqrt(abs(d2LLGbydsigmaA)) - ssqr = flex.mean_default(eEsel.d_star_sq().data(),0) - ndat = dobssel.size() - if verbosity > 1: - print(ndat,ssqr,sigmaA,sigma_sigmaA,file=log) - xdat.append(ssqr) - ydat.append(math.log(sigmaA)) - wdat.append(abs(d2LLGbydsigmaA)) # Inverse variance estimate - - xdat = flex.double(xdat) - ydat = flex.double(ydat) - wdat = flex.double(wdat) - W = flex.sum(wdat) - Wx = flex.sum(wdat * xdat) - Wy = flex.sum(wdat * ydat) - Wxx = flex.sum(wdat * xdat * xdat) - Wxy = flex.sum(wdat * xdat * ydat) - slope = (W * Wxy - Wx * Wy) / (W * Wxx - Wx * Wx) - intercept = (Wy * Wxx - Wx * Wxy) / (W * Wxx - Wx * Wx) - frac_complete = math.exp(2.*intercept) - if verbosity > 0: - print("Slope and intercept of sigmaA plot for fixed model contribution: ",slope,intercept,file=log) - print("Approximate fraction of scattering: ",frac_complete,file=log) - linlogsiga = flex.double() - logsiga_combined = flex.double() - sigma_linlog = math.log(1.5) # Allow 50% error in linear fit - i_bin_used = 0 - for i_bin in mc1.binner().range_used(): - sigmaA = math.exp(ydat[i_bin_used]) - # For complete model, slope should be negative, but can be positive if the - # modelled part is much better ordered than the larger unmodelled part - linlog = min(math.log(0.999),(intercept + slope*xdat[i_bin_used])) - linlogsiga.append(linlog) - sigma_sigmaA = 1./math.sqrt(wdat[i_bin_used]) - sigma_lnsigmaA = math.exp(-ydat[i_bin_used])*sigma_sigmaA - combined_logsiga = ((ydat[i_bin_used]/sigma_lnsigmaA**2 + linlog/sigma_linlog**2) / - (1./sigma_lnsigmaA**2 + 1./sigma_linlog**2) ) - logsiga_combined.append(combined_logsiga) - combined_siga = math.exp(combined_logsiga) - - sel = expectE.binner().selection(i_bin) - expectE_mod.data().set_selected(sel, expectE_mod.data().select(sel) - - math.exp(combined_logsiga)*dobs.data().select(sel) - * masked_model_E.data().select(sel) ) - masked_model_sigmaA.data().set_selected(sel, combined_siga) - i_bin_used += 1 - - if False: - import matplotlib.pyplot as plt - fig, ax = plt.subplots(2,1) - ax[0].plot(xdat,ydat,label="ln(sigmaA)") - ax[0].plot(xdat,linlogsiga,label="line fit") - ax[0].plot(xdat,logsiga_combined,label="combined") - ax[0].legend(loc="upper right") - ax[1].plot(xdat,flex.exp(ydat),label="sigmaA") - ax[1].plot(xdat,flex.exp(linlogsiga),label="line fit") - ax[1].plot(xdat,flex.exp(logsiga_combined),label="combined") - ax[1].legend(loc="lower left") - plt.show() + masked_model_sigmaA = sigmaA_from_model_in_map(expectE, dobs, masked_model_E, over_sampling_factor, verbosity) + # Temporary kludge where expectE is modified instead of adding fixed contribution in phasertng + expectE_mod = expectE.customized_copy(data=expectE.data() + - masked_model_sigmaA.data()*dobs.data()*masked_model_E.data()) # write_mtz(expectE_mod,"expectE_mod.mtz","expectEmod") + else: + expectE_mod = expectE.deep_copy() ssqmin = flex.min(mc1.d_star_sq().data()) ssqmax = flex.max(mc1.d_star_sq().data()) resultsdict = dict( - n_bins = n_bins, - ssqr_bins = ssqr_bins, - ssqmin = ssqmin, - ssqmax = ssqmax, - asqr_scale = asqr_scale, - sigmaT_bins = sigmaT_bins, - asqr_beta = asqr_beta, - a_baniso = a_baniso, - mapCC_bins = mapCC_bins) + n_bins = n_bins, + ssqr_bins = ssqr_bins, + ssqmin = ssqmin, + ssqmax = ssqmax, + asqr_scale = asqr_scale, + sigmaT_bins = sigmaT_bins, + asqr_beta = asqr_beta, + a_baniso = a_baniso, + mapCC_bins = mapCC_bins) return group_args( new_mmm = working_mmm, shift_cart = shift_cart, From 9c450e26a1fa9a60da44bd4575c1087e3734d3d3 Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Wed, 21 Aug 2024 10:33:16 -0700 Subject: [PATCH 656/748] New cctbx.xfel.merge parameter, select.significance_filter.d_min Removes the entire lattice if the resolution is not at least this d_min. Similar to the cxi.merge parameter lattice_rejection.d_min. --- xfel/merging/application/filter/reflection_filter.py | 3 +++ xfel/merging/application/phil/phil.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/xfel/merging/application/filter/reflection_filter.py b/xfel/merging/application/filter/reflection_filter.py index 5c28a16df3..68dbdd73ec 100644 --- a/xfel/merging/application/filter/reflection_filter.py +++ b/xfel/merging/application/filter/reflection_filter.py @@ -112,6 +112,9 @@ def apply_significance_filter(self, experiments, reflections): %(expt_id, imposed_res_filter) ) + if self.params.select.significance_filter.d_min and imposed_res_filter > self.params.select.significance_filter.d_min: + self.logger.log("Resolution below %f, rejecting"%self.params.select.significance_filter.d_min) + continue imposed_res_sel = exp_observations.resolution_filter_selection(d_min=imposed_res_filter) assert imposed_res_sel.size() == refls.size() diff --git a/xfel/merging/application/phil/phil.py b/xfel/merging/application/phil/phil.py index efb179480c..04a935c20c 100644 --- a/xfel/merging/application/phil/phil.py +++ b/xfel/merging/application/phil/phil.py @@ -354,6 +354,9 @@ sigma = 0.5 .type = float .help = Remove highest resolution bins such that all accepted bins have >= sigma + d_min = None + .type = float + .help = Remove the entire lattice if the resolution is not at least this d_min } } """ From 7d409c6984a8481962d27aac192413e2bbc445f8 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Wed, 21 Aug 2024 11:28:04 -0700 Subject: [PATCH 657/748] Remove unused call. --- mmtbx/monomer_library/linking_mixins.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index 7f5bff5937..40ca68550b 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -585,22 +585,6 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., i_seqs=None): if atom2.element.strip() in hydrogens: done[atom1.id_str()] = atom2.id_str() # bond length cutoff & some logic - aa_rc = linking_utils.is_atom_pair_linked( - atom1, - atom2, - classes1.important_only, - classes2.important_only, - distance=distance, - max_bonded_cutoff=max_bonded_cutoff, - amino_acid_bond_cutoff=amino_acid_bond_cutoff, - inter_residue_bond_cutoff=inter_residue_bond_cutoff, - second_row_buffer=second_row_buffer, - saccharide_bond_cutoff=carbohydrate_bond_cutoff, - metal_coordination_cutoff=metal_coordination_cutoff, - use_only_bond_cutoff=use_only_bond_cutoff, - link_metals=link_metals, - verbose=verbose, - ) if not linking_utils.is_atom_pair_linked( atom1, atom2, From e20fc78e1f57433205dbd53eb11581453a392af0 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Wed, 21 Aug 2024 11:58:05 -0700 Subject: [PATCH 658/748] Minor reordering for speed --- mmtbx/monomer_library/linking_mixins.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index 40ca68550b..0af7805abc 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -234,16 +234,16 @@ def possible_cyclic_peptide(atom1, ): if verbose: print(atom1.quote(),atom2.quote()) - if atom1.element_is_hydrogen() or atom2.element_is_hydrogen(): return False - chain1 = atom1.parent().parent().parent() - chain2 = atom2.parent().parent().parent() - if not chain1.id == chain2.id: - if verbose: print('chain id differs', chain1.id, chain2.id) - return False len_fl = 0 len_fl += atoms_in_first_last_rgs.get(atom1.i_seq, -1) len_fl += atoms_in_first_last_rgs.get(atom2.i_seq, -1) - return len_fl == 1 + if len_fl == 1: + chain1 = atom1.parent().parent().parent() + chain2 = atom2.parent().parent().parent() + if chain1.id == chain2.id: + return True + elif verbose: print('chain id differs', chain1.id, chain2.id) + return False def check_for_peptide_links(atom1, atom2, From 558c79f0e2b90f88e82f64f2bb2c30f2a341aaf3 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Wed, 21 Aug 2024 15:21:11 -0700 Subject: [PATCH 659/748] Move function out of cycle. --- mmtbx/monomer_library/linking_mixins.py | 23 ++++++++++++++++++++--- mmtbx/monomer_library/linking_utils.py | 20 +++++--------------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index 0af7805abc..624a13569e 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -429,6 +429,15 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., i_seqs=None): abs_i = abs(i) for a in rg.atoms(): atoms_in_first_last_rgs[a.i_seq] = abs_i + skip_if_longer = linking_setup.update_skip_if_longer(amino_acid_bond_cutoff, + rna_dna_bond_cutoff=3.4, + intra_residue_bond_cutoff=inter_residue_bond_cutoff, + saccharide_bond_cutoff=carbohydrate_bond_cutoff, + metal_coordination_cutoff=metal_coordination_cutoff, + sulfur_bond_cutoff=2.5, + other_bond_cutoff=2, + ) + # main loop nonbonded_proxies, sites_cart, pair_asu_table, asu_mappings, nonbonded_i_seqs = \ _nonbonded_pair_objects(max_bonded_cutoff=max_bonded_cutoff, @@ -443,6 +452,7 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., i_seqs=None): # include & exclude selection # origin_id = None + updated_skip_if_longer = None if ( include_selections and distance>=max_bonded_cutoff_standard ): @@ -458,6 +468,15 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., i_seqs=None): inter_residue_bond_cutoff=bond_cutoff saccharide_bond_cutoff=bond_cutoff link_residues=True + updated_skip_if_longer = linking_setup.update_skip_if_longer( + amino_acid_bond_cutoff, + rna_dna_bond_cutoff=3.4, + intra_residue_bond_cutoff=inter_residue_bond_cutoff, + saccharide_bond_cutoff=saccharide_bond_cutoff, + metal_coordination_cutoff=metal_coordination_cutoff, + sulfur_bond_cutoff=2.5, + other_bond_cutoff=2, + ) break else: continue # exclude this nonbond from consideration @@ -591,9 +610,7 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., i_seqs=None): classes1.important_only, classes2.important_only, distance=distance, - max_bonded_cutoff=max_bonded_cutoff, - amino_acid_bond_cutoff=amino_acid_bond_cutoff, - inter_residue_bond_cutoff=inter_residue_bond_cutoff, + skip_if_longer=updated_skip_if_longer if updated_skip_if_longer is not None else skip_if_longer, second_row_buffer=second_row_buffer, saccharide_bond_cutoff=carbohydrate_bond_cutoff, metal_coordination_cutoff=metal_coordination_cutoff, diff --git a/mmtbx/monomer_library/linking_utils.py b/mmtbx/monomer_library/linking_utils.py index ee23fd2d44..2478f7d220 100644 --- a/mmtbx/monomer_library/linking_utils.py +++ b/mmtbx/monomer_library/linking_utils.py @@ -355,20 +355,18 @@ def is_atom_pair_linked(atom1, class_important_1, class_important_2, distance=None, - max_bonded_cutoff=3., - amino_acid_bond_cutoff=1.9, - rna_dna_bond_cutoff=3.4, - rna_dna_angle_cutoff=35, - inter_residue_bond_cutoff=1.99, + skip_if_longer=None, second_row_buffer=.5, metal_coordination_cutoff=3., saccharide_bond_cutoff=3., - sulfur_bond_cutoff=2.5, - other_bond_cutoff=2., # this is the ligand distance use_only_bond_cutoff=False, link_metals=True, verbose=False, ): + # + # TODO: wrap metal_coordination_cutoff and saccharide_bond_cutoff + # into skip_if_longer too. + # if atom1.element.strip().upper() in ad_hoc_non_linking_elements: return False if atom2.element.strip().upper() in ad_hoc_non_linking_elements: @@ -378,14 +376,6 @@ def is_atom_pair_linked(atom1, if atom_pair in ad_hoc_non_linking_pairs: return False skip_if_both = linking_setup.skip_if_both - skip_if_longer = linking_setup.update_skip_if_longer(amino_acid_bond_cutoff, - rna_dna_bond_cutoff, - inter_residue_bond_cutoff, - saccharide_bond_cutoff, - metal_coordination_cutoff, - sulfur_bond_cutoff, - other_bond_cutoff, - ) class1 = linking_setup.adjust_class(atom1, class_important_1) class2 = linking_setup.adjust_class(atom2, class_important_2) # python3 From 98938c9ebb59077a2cfa5a23c543ffc3e639fb5b Mon Sep 17 00:00:00 2001 From: randyjread Date: Thu, 22 Aug 2024 14:52:09 +0100 Subject: [PATCH 660/748] Put back option to define sphere center with placed model. Tidy up argparse input and logic of options. --- cctbx/maptbx/prepare_map_for_docking.py | 60 +++++++++++++++++-------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/cctbx/maptbx/prepare_map_for_docking.py b/cctbx/maptbx/prepare_map_for_docking.py index f23018316c..cb57498fe8 100644 --- a/cctbx/maptbx/prepare_map_for_docking.py +++ b/cctbx/maptbx/prepare_map_for_docking.py @@ -2062,7 +2062,11 @@ def run(): Optional command-line arguments (keyworded): --protein_mw*: molecular weight expected for protein component of ordered density + in full map --nucleic_mw*: same for nucleic acid component + --sphere_points: number of reflections to be used for averaging in Fourier space + --model: PDB file for placed model used to define the centre and radius of + the cut-out sphere, used as an alternative to sphere_cent and radius --sphere_cent: Centre of sphere defining target map region (3 floats) defaults to centre of map --radius: radius of sphere (1 float) @@ -2077,7 +2081,8 @@ def run(): --mute (or -m): mute output --verbose (or -v): verbose output --testing: extra verbose output for debugging - * NB: At least one of protein_mw or nucleic_mw must be given + * NB: At least one of protein_mw or nucleic_mw must be given if sphere + parameters are not defined either explicitly or through model """ import argparse dm = DataManager() @@ -2089,17 +2094,23 @@ def run(): parser.add_argument('map2', help='Map file for half-map 2') parser.add_argument('d_min', help='d_min for maps', type=float) parser.add_argument('--protein_mw', - help='Molecular weight of protein component of map', + help='Molecular weight of protein component of full map', type=float) parser.add_argument('--nucleic_mw', - help='Molecular weight of nucleic acid component of map', + help='Molecular weight of nucleic acid component of full map', type=float) parser.add_argument('--sphere_points',help='Target nrefs in averaging sphere', type=float, default=500.) - parser.add_argument('--fixed_model', help='Fixed model') - parser.add_argument('--sphere_cent',help='Centre of sphere for docking', + parser.add_argument('--model', + help='Optional placed model defining size and position of cut-out sphere') + parser.add_argument('--fixed_model', + help='Optional fixed model accounting for explained map features') + parser.add_argument('--sphere_cent', + help='Centre of sphere for docking, if no model provided', nargs=3, type=float) - parser.add_argument('--radius',help='Radius of sphere for docking', type=float) + parser.add_argument('--radius', + help='Radius of sphere for docking, if no model provided', + type=float) parser.add_argument('--file_root', help='Root of filenames for output') parser.add_argument('--no_shift_map_origin', action='store_true') @@ -2117,26 +2128,27 @@ def run(): shift_map_origin = not(args.no_shift_map_origin) determine_ordered_volume = not(args.no_determine_ordered_volume) + sphere_points = args.sphere_points + cutout_specified = False sphere_cent = None radius = None + + model = None + if args.model is not None: + model_file = args.model + model = dm.get_model(model_file) + if args.sphere_cent is not None: + raise Sorry('Either model or sphere specification may be given but not both') + sphere_cent, radius = sphere_enclosing_model(model) + radius = radius + d_min # Expand to allow width for density + cutout_specified = True + fixed_model = None if args.fixed_model is not None: model_file = args.fixed_model fixed_model = dm.get_model(model_file) - protein_mw = None - nucleic_mw = None - if (args.protein_mw is None) and (args.nucleic_mw is None): - if determine_ordered_volume: - raise Sorry("At least one of protein_mw or nucleic_mw must be given") - if args.protein_mw is not None: - protein_mw = args.protein_mw - if args.nucleic_mw is not None: - nucleic_mw = args.nucleic_mw - - sphere_points = args.sphere_points - if args.sphere_cent is not None: if args.radius is None: raise Sorry("Radius must be provided if sphere_cent is defined") @@ -2146,6 +2158,18 @@ def run(): if (not determine_ordered_volume and not cutout_specified): raise Sorry("Must determine ordered volume if cutout not specified") + protein_mw = None + nucleic_mw = None + if (args.protein_mw is None) and (args.nucleic_mw is None): + if cutout_specified: + determine_ordered_volume = False + if determine_ordered_volume and not cutout_specified: + raise Sorry("At least one of protein_mw or nucleic_mw must be given") + if args.protein_mw is not None: + protein_mw = args.protein_mw + if args.nucleic_mw is not None: + nucleic_mw = args.nucleic_mw + # Create map_model_manager containing half-maps map1_filename = args.map1 mm1 = dm.get_real_map(map1_filename) From b308ac4283cf57e067a755a7f522a807c2af8e2c Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Thu, 22 Aug 2024 09:35:10 -0700 Subject: [PATCH 661/748] bootstrap: add aimnet2calc repo for qrefine [skip ci] --- libtbx/auto_build/bootstrap.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libtbx/auto_build/bootstrap.py b/libtbx/auto_build/bootstrap.py index f49e1c2d01..459e8019b2 100644 --- a/libtbx/auto_build/bootstrap.py +++ b/libtbx/auto_build/bootstrap.py @@ -768,6 +768,13 @@ class amber_library_module(SourceModule): 'https://github.com/phenix-project/amber_library.git', ] +class aimnet2calc_module(SourceModule): + module = 'aimnet2calc' + anonymous = ['git', + 'git@github.com:zubatyuk/aimnet2calc.git', + 'https://github.com/zubatyuk/aimnet2calc.git', + ] + class qrefine_module(SourceModule): module = 'qrefine' anonymous = ['git', From 996478aa5b44f7e49fc1445345c93210444af171 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 22 Aug 2024 10:47:39 -0700 Subject: [PATCH 662/748] Reduce2: prevent Sorry. --- mmtbx/programs/hydrogenate.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mmtbx/programs/hydrogenate.py b/mmtbx/programs/hydrogenate.py index ceb5f317e1..5a5651afb1 100644 --- a/mmtbx/programs/hydrogenate.py +++ b/mmtbx/programs/hydrogenate.py @@ -56,6 +56,7 @@ def validate(self): def run(self): self.model = self.data_manager.get_model() + self.model.set_stop_for_unknowns(False) self.model.process(make_restraints=False) make_sub_header('Add H atoms', out=self.logger) From bfaa7c17712cf32e10b162ff8216fd26ae46a1b0 Mon Sep 17 00:00:00 2001 From: Daniel Tchon Date: Thu, 22 Aug 2024 15:17:34 -0700 Subject: [PATCH 663/748] Add handling of `MPI.LAND`, `MPI.LOR`, `MPI.LXOR` to `mpiEmulator` --- libtbx/mpi4py.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libtbx/mpi4py.py b/libtbx/mpi4py.py index da39bd9834..a2f13a3336 100644 --- a/libtbx/mpi4py.py +++ b/libtbx/mpi4py.py @@ -9,6 +9,9 @@ class mpiEmulator(object): SUM = "SUM" MAX = "MAX" MIN = "MIN" + LAND = "LAND" + LOR = "LOR" + LXOR = "LXOR" # TODO: implement more operations as needed def Wtime(self): @@ -30,7 +33,8 @@ def bcast(self, obj, root=0): def Bcast(self, buf, root=0): pass def reduce(self, sendobj, op=mpiEmulator.SUM, root=0): - if op == mpiEmulator.SUM or op == mpiEmulator.MAX or op == mpiEmulator.MIN: + if op in {mpiEmulator.SUM, mpiEmulator.MAX, mpiEmulator.MIN, + mpiEmulator.LAND, mpiEmulator.LOR, mpiEmulator.LXOR}: return sendobj else: assert False, "Unsupported MPI reduce operation %s"%(op) From e8e709ae9a3f1229b61a0c799f21a7769b0306d0 Mon Sep 17 00:00:00 2001 From: Daniel Paley Date: Fri, 23 Aug 2024 10:29:38 -0700 Subject: [PATCH 664/748] Performance improvements in deltacc Co-authored-by: Aaron Brewster --- .../application/statistics/deltaccint.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/xfel/merging/application/statistics/deltaccint.py b/xfel/merging/application/statistics/deltaccint.py index 5ff294c16d..a24e5550be 100644 --- a/xfel/merging/application/statistics/deltaccint.py +++ b/xfel/merging/application/statistics/deltaccint.py @@ -75,16 +75,21 @@ def run(self, experiments, reflections): merged[:,hkl_idx] = sums[:,hkl_idx]/n[:,hkl_idx] # compute variance for each hkl (less the intensity from each experiment) - diff_sq_ = np.zeros(len(all_expt_ids)) - for expt_idx in range(len(all_expt_ids)): - mean_intensity = merged[expt_idx,hkl_idx] - diff_sq_[expt_idx] = np.sum((intensity-mean_intensity)**2) + diff_sq_ = np.full(len(all_expt_ids), -1, dtype=float) for i in range(len(refls)): expt_idx = all_expts_map[expt_map[refls['id'][i]]] - mean_intensity = merged[expt_idx,hkl_idx] - diff_sq_[expt_idx] -= (intensity[i] - mean_intensity)**2 - + mean_intensity_modified = merged[expt_idx,hkl_idx] + # Handle the case where a single image contains same hkl twice. + if diff_sq_[expt_idx] <0: + diff_sq_modified = np.sum((intensity-mean_intensity_modified)**2) + diff_sq_[expt_idx] = diff_sq_modified - (intensity[i] - mean_intensity_modified)**2 + else: + diff_sq_[expt_idx] -= (intensity[i] - mean_intensity_modified)**2 + + mean_intensity_unmodified = np.mean(intensity) + diff_sq_unmodified = np.sum((intensity-mean_intensity_unmodified)**2) + diff_sq_[diff_sq_<0] = diff_sq_unmodified variance[:,hkl_idx] = diff_sq_ / (n[:,hkl_idx]-1) # N expts (all ranks) x N bins From b196093a21f61815d4d7cd6da5029bb6c11a236b Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Mon, 26 Aug 2024 11:12:04 -0700 Subject: [PATCH 665/748] Bugfix for deltaccint --- xfel/merging/application/statistics/deltaccint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xfel/merging/application/statistics/deltaccint.py b/xfel/merging/application/statistics/deltaccint.py index a24e5550be..cb7be4a828 100644 --- a/xfel/merging/application/statistics/deltaccint.py +++ b/xfel/merging/application/statistics/deltaccint.py @@ -130,7 +130,7 @@ def run(self, experiments, reflections): # Report if self.mpi_helper.rank == 0: - sigma_sq_y = total_diff_sq_sum / (all_i_n-1) + sigma_sq_y = total_diff_sq_sum / (total_i_n-1) sigma_sq_e = total_var_sums / total_i_n deltaccint_st = (sigma_sq_y - (0.5 * sigma_sq_e)) / (sigma_sq_y + sigma_sq_e) From c3422c87755e951092bd7e34fafb862c090e75c2 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Mon, 26 Aug 2024 16:22:03 -0700 Subject: [PATCH 666/748] New cutoff for pdb_interpretation speedup. Leaving the old cutoff in the test. --- mmtbx/monomer_library/pdb_interpretation.py | 2 +- mmtbx/regression/tst_metal_link_1.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index bb0d778a31..aa7719687b 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -305,7 +305,7 @@ def __init__(self, residue_name, atom_name, atom_element): link_small_molecules = False .type = bool .short_caption = Link small molecules such as SO4, PO4 to protein - metal_coordination_cutoff = 3.5 + metal_coordination_cutoff = 3.0 .type = float .short_caption = Maximum distance for automatic linking of metals amino_acid_bond_cutoff = 1.9 diff --git a/mmtbx/regression/tst_metal_link_1.py b/mmtbx/regression/tst_metal_link_1.py index 11c3ef6b49..883b612bd7 100644 --- a/mmtbx/regression/tst_metal_link_1.py +++ b/mmtbx/regression/tst_metal_link_1.py @@ -99,6 +99,7 @@ def run(): pdb_inp = iotbx.pdb.input(lines=pdb_str, source_info=None) params = mmtbx.model.manager.get_default_pdb_interpretation_params() params.pdb_interpretation.automatic_linking.link_metals=True + params.pdb_interpretation.automatic_linking.metal_coordination_cutoff=3.5 m = mmtbx.model.manager( model_input = pdb_inp, log = null_out()) From 85468c4432bbe47185144098a8575bd08ed31c09 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 27 Aug 2024 10:36:24 -0700 Subject: [PATCH 667/748] Better test fix, with Nigel. --- mmtbx/regression/tst_metal_link_1.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mmtbx/regression/tst_metal_link_1.py b/mmtbx/regression/tst_metal_link_1.py index 883b612bd7..44fce3b785 100644 --- a/mmtbx/regression/tst_metal_link_1.py +++ b/mmtbx/regression/tst_metal_link_1.py @@ -99,7 +99,6 @@ def run(): pdb_inp = iotbx.pdb.input(lines=pdb_str, source_info=None) params = mmtbx.model.manager.get_default_pdb_interpretation_params() params.pdb_interpretation.automatic_linking.link_metals=True - params.pdb_interpretation.automatic_linking.metal_coordination_cutoff=3.5 m = mmtbx.model.manager( model_input = pdb_inp, log = null_out()) @@ -110,7 +109,7 @@ def run(): assert atoms[73].element.strip().upper() == "FE" bond_proxies_simple, asu = grm.geometry.get_all_bond_proxies( sites_cart = ph.atoms().extract_xyz()) - expected_link_atoms = ['NE2', "NE2", "OE1", "OE2", "O", "O", "O"] + expected_link_atoms = ['NE2', "OE2", "O", "O", "O"] expected_link_atoms.sort() linked_atoms_found = [] for p in bond_proxies_simple: From 107a9336d58eabe6938e633d99b86bc1d0086804 Mon Sep 17 00:00:00 2001 From: Russell Taylor Date: Tue, 27 Aug 2024 14:59:19 -0400 Subject: [PATCH 668/748] Ribbons (#1007) * Fixing the nucleic-acid residue code in Reduce to work with DNA as well as RNA, and to handle the broader range of potential names. Speeding up the protein and NA determination code by making the lists outside of the functions. * Adding scaffolding and initial functions for ribbon-generation code. * Documentation update * Adding function to produce the guidepoints for protein ribbons. * Continuing to implement ribbon generation, porting from the Java code. * Cleaning up command-line argument style and adding a choice for coloring for ribbons * Continuing to add ribbon support * Continuing to implement ribbon printing code. * Removing spurious Phil argument. Clarifying name of variable * Adding ability to set coil width * Updating the code dealing with secondary structure types to include more information that is needed in the ribbon-printing code. * Continuing to implement fancy-ribbon printing * Simplifying and correcting modulo calculation on chain colors. * Re-using existing method to determine chain colors based on index * Fixing indentation and initialization errors * Continuing to implement and debug ribbon code * Fixing rainbow color map to do once per chain. Fixing line thickness on ribbon edges. * Fixing element creation to get helix construction working better. * Integer division * Adding the triangle tip for the ribbon to the output * Removigtnn spurious parentheses * Adjusting the spline code to start and end at the correct control points * Added coil sections of ribbons and starting on sheets, including calculating next/previous/duplicate information required for this processing. * First version of ribbon code that generates helices, sheets, and coils. * Replacing SciPy NURBS with implementation of NRUBS ported from original Java code. * Replacing duplicate residue names with a single quote to reduce ribbon file sizes * Removing extra spaces at end of line. * Comment fix * Fixing multi-model behavior for ribbons. Casting parameter into an int so that a function can handle strings that hold integers as well. * Adding the ability to select atoms. Fixing the label on the models when multiple models are in a file. * Selecting only alternate a by default. Adding animation for multiple-model files we make ribbons for * Fixing print statement to be compatible with python 2 * Cleaning up clutter --- mmtbx/command_line/ribbons.py | 6 + mmtbx/kinemage/nrubs.py | 161 ++++++++ mmtbx/kinemage/ribbons.py | 383 +++++++++++++++++++ mmtbx/kinemage/validation.py | 8 +- mmtbx/programs/reduce2.py | 19 +- mmtbx/programs/ribbons.py | 702 ++++++++++++++++++++++++++++++++++ 6 files changed, 1263 insertions(+), 16 deletions(-) create mode 100644 mmtbx/command_line/ribbons.py create mode 100644 mmtbx/kinemage/nrubs.py create mode 100644 mmtbx/kinemage/ribbons.py create mode 100644 mmtbx/programs/ribbons.py diff --git a/mmtbx/command_line/ribbons.py b/mmtbx/command_line/ribbons.py new file mode 100644 index 0000000000..3454b3ab36 --- /dev/null +++ b/mmtbx/command_line/ribbons.py @@ -0,0 +1,6 @@ +from __future__ import absolute_import, division, print_function + +from iotbx.cli_parser import run_program +from mmtbx.programs import ribbons + +run_program(ribbons.Program) diff --git a/mmtbx/kinemage/nrubs.py b/mmtbx/kinemage/nrubs.py new file mode 100644 index 0000000000..ba27f6549e --- /dev/null +++ b/mmtbx/kinemage/nrubs.py @@ -0,0 +1,161 @@ +# Converted from the NRUBS.java file in the following repository: https://github.com/rlabduke/javadev +# Comments from the original NRUBS.java file. + +from __future__ import absolute_import, division, print_function +import numpy as np + +''' +NRUBS implements non-rational, uniform B-splines, a much simpler +thing than NURBS (non-uniform rational B-splines). + +

My reference was Computer Graphics: Principles and Practice, 2nd ed. +in the Systems Programming Series by Foley, van Dam, Feiner, and Hughes (1993). +With some work, I could probably use it to implement NURBS (which are a +generalization of NRUBS, on two counts), but since Prekin uses the plain +B-splines for ribbons, I don't see the point. + +

Here's my simplified layout of the math of splines. +B-splines require 4 control points per segment, and adjacent segments +share 3 of the 4 control points. +For simplicity, I deal with only one segment at a time here, +with control points P0, P1, P2, P3. +Segments are C2 continuous at join points, meaning their second derivatives +are equal. Doubling or tripling guide points may break this. +The points along the actual spline are given as Q(t), where t is on [0,1]. +Although the Q(t) don't actually pass through any of the control points, +they do lie within the convex hull of those points. +You can make the spline go closer by doubling up a control point, but if +three of them are the same, then that spline segment will be a straight line. + +

+t                               the parameter for spline coordinates
+
+Q(t) = [x(t) y(t) z(t)]         the functions of t that give spline coordinates
+
+    [P0]   [P0_x P0_y P0_z]
+G = [P1] = [P1_x P1_y P1_z]     the control points (guide points)
+    [P2]   [P2_x P2_y P2_z]
+    [P3]   [P3_x P3_y P3_z]
+
+            [-1  3 -3  1]
+M = (1/6) * [ 3 -6  3  0]       the basis matrix, which determines blending functions
+            [-3  0  3  0]
+            [ 1  4  1  0]
+
+T = [t^3  t^2  t  1]            powers of t -- makes this a CUBIC spline function
+
+Q(t) = T * M * G                the spline function itself
+     = T * C                        alternate representation: C = M * G
+     = B * G                        alternate representation: B = T * M
+
+ +

Notice that if you're going to do a bunch of segments with the same +subdivisions of t (e.g. t = [0.00 0.25 0.50 0.75 1.00]), it makes sense +to precalculate all the B(t) you need. This gives: +

+Q(t) = (1/6) * {  [(1-t)^3]*P0 + [3t^3 - 6t^2 + 4]*P1 + [-3t^3 + 3t^2 + 3t + 1]*P2 + [t^3]*P3  }
+
+ + +

Copyright (C) 2006 by Ian W. Davis. All rights reserved. +
Begun on Thu Jan 19 16:56:14 EST 2006 +''' + +class Triple: + def __init__(self, x=0, y=0, z=0): + self.x = x + self.y = y + self.z = z + + def setXYZ(self, x, y, z): + self.x = x + self.y = y + self.z = z + + def addMult(self, scalar, other): + self.x += scalar * other.x + self.y += scalar * other.y + self.z += scalar * other.z + + def getX(self): + return self.x + + def getY(self): + return self.y + + def getZ(self): + return self.z + +class NRUBS: + def __init__(self): + self.Bcache = {} + self.work = Triple() + + def spline(self, guidePts, nIntervals): + '''Generates interpolated points between two guide points (guideStart and guideStart+1), + and stores them in splineOut at splineStart through splineStart+nIntervals. + (Yes, that's right: it calculates nIntervals+1 points.) + ''' + B = self.getB(nIntervals) + out = [Triple() for _ in range(nIntervals * (len(guidePts) - 3) + 1)] + + for i in range(len(guidePts) - 3): + self._spline(guidePts, i, out, i * nIntervals, B) + + return out + + def _spline(self, guidePts, guideStart, splineOut, splineStart, B): + '''Calculates the N+1 points along the spline for a particular segment. + Using this repeatedly along a series of guidepoints will result in small + amount of duplicate calculation (each join calc'd twice). + ''' + P0 = guidePts[guideStart + 0] + P1 = guidePts[guideStart + 1] + P2 = guidePts[guideStart + 2] + P3 = guidePts[guideStart + 3] + + for i in range(len(B)): + self.work.setXYZ(0, 0, 0) + self.work.addMult(B[i][0], P0) + self.work.addMult(B[i][1], P1) + self.work.addMult(B[i][2], P2) + self.work.addMult(B[i][3], P3) + splineOut[splineStart + i].setXYZ(self.work.getX(), self.work.getY(), self.work.getZ()) + + def getB(self, nIntervals): + '''Returns the "B" coefficients for a particular number N of intervals + along a spline segment. Because N+1 points are generated (fencepost problem) + this function returns a double[N+1][4]. + + If possible, the value will be retrieved from cache instead of recalculated. + ''' + if nIntervals not in self.Bcache: + self.Bcache[nIntervals] = self.calculateB(nIntervals) + return self.Bcache[nIntervals] + + @staticmethod + def calculateB(nIntervals): + '''Returns the "B" coefficients for a particular number N of intervals + along a spline segment. Because N+1 points are generated (fencepost problem) + this function returns a double[N+1][4]. + ''' + B = np.zeros((nIntervals + 1, 4)) + for i in range(nIntervals + 1): + t = i / nIntervals + t2 = t * t + t3 = t2 * t + _1_t = 1 - t + B[i][0] = (_1_t * _1_t * _1_t) / 6 + B[i][1] = (3 * t3 - 6 * t2 + 4) / 6 + B[i][2] = (-3 * t3 + 3 * t2 + 3 * t + 1) / 6 + B[i][3] = t3 / 6 + return B + +# Example usage +if __name__ == "__main__": + guidePts = [Triple(0, 0, 0), Triple(1, 2, 0), Triple(2, 3, 0), Triple(4, 0, 0)] + nrubs = NRUBS() + result = nrubs.spline(guidePts, 10) + for point in result: + print("({}, {}, {})".format(point.getX(), point.getY(), point.getZ())) + diff --git a/mmtbx/kinemage/ribbons.py b/mmtbx/kinemage/ribbons.py new file mode 100644 index 0000000000..947ec893b0 --- /dev/null +++ b/mmtbx/kinemage/ribbons.py @@ -0,0 +1,383 @@ +from __future__ import absolute_import, division, print_function +from iotbx.pdb import amino_acid_codes, nucleic_acid_codes +from scitbx.matrix import col + +_amino_acid_resnames = sorted(amino_acid_codes.one_letter_given_three_letter.keys()) +def _IsStandardResidue(resname): + return resname.strip().upper() in _amino_acid_resnames + +_nucleic_acid_resnames = set(nucleic_acid_codes.rna_one_letter_code_dict.keys()).union( + set(nucleic_acid_codes.dna_one_letter_code_dict.keys())) +def _IsNucleicAcidResidue(resname): + return resname.strip().upper() in _nucleic_acid_resnames + +def _FindNamedAtomInResidue(residue_group, atom_names): + '''Return the first atom in the residue with a name in the atom_names list. + :param residue_group: iotbx.pdb.hierarchy.residue_group, the residue to search. + :param atom_names: list of strings, the names of the atoms to search for. + :return: iotbx.pdb.hierarchy.atom, the first atom found with a name in the atom_names list, + or None if none are found. + ''' + for name in atom_names: + name = name.strip().upper() + for atom in residue_group.atoms(): + if atom.name.strip().upper() == name.upper(): + return atom + return None + +def _FindContiguousResiduesByAtomDistances(chain, type_function, desired_atoms, distance_threshold): + '''Return a list of contiguous nucleic acid residues in the chain based on the distance between P atoms, + or O5* or O5' if the P atom is not found. + :param chain: PDB chain to be searched for contiguous residues. + :param type_function: function, a function that takes a residue name and returns True if the residue is of the desired type. + :param desired_atoms: list of strings, the names of the atoms to use for distance calculations. The first + one found in the residue will be used. + :param distance_threshold: float, the maximum distance between desired atoms to consider them contiguous. + ''' + contiguous_residues = [] + + current_contig_residues = [] + prev_atom = None + + for residue_group in chain.residue_groups(): + # Check if the residue is of the desired type, based on its name + if not type_function(residue_group.unique_resnames()[0]): + continue + + # Attempt to find the desired atom in the current residue. Search all atoms for the + # first one in the desired_atoms list, then later ones if it is not found. + # If no atom is found, skip to the next residue + atom = _FindNamedAtomInResidue(residue_group, desired_atoms) + if atom is None: + continue + + # If this is the first residue being examined, initialize the list + if prev_atom is None: + current_contig_residues.append(residue_group) + else: + # Calculate the distance between the current and previous atoms + current_pos = col(atom.xyz) + prev_pos = col(prev_atom.xyz) + distance = (current_pos - prev_pos).length() + + if distance < distance_threshold: + # If the distance is within the threshold, add to the current list + current_contig_residues.append(residue_group) + else: + # If not, start a new list for the current residue if we have at least one residue + if len(current_contig_residues) > 0: + contiguous_residues.append(current_contig_residues) + current_contig_residues = [residue_group] + + # Update the previous atom to the current one + prev_atom = atom + + # After iterating through the chain, add any remaining contiguous residues to the main list + # if there are at least two. + if len(current_contig_residues) > 1: + contiguous_residues.append(current_contig_residues) + + return contiguous_residues + +# ------------------------------------------------------------------------------ + +def find_contiguous_protein_residues(chain, distance_threshold=5.0): + '''Return a list of contiguous protein residues in the chain based on the distance between CA atoms. + :param chain: PDB chain to be searched for contiguous residues. + :param distance_threshold: float, the maximum distance between CA atoms to consider them contiguous. + The empirical 5.0 default value comes from the Richardson lab's Prekin code; the ideal length is 3.80. + ''' + return _FindContiguousResiduesByAtomDistances(chain, _IsStandardResidue, ["CA"], distance_threshold) + +def find_contiguous_nucleic_acid_residues(chain, distance_threshold=10.0): + '''Return a list of contiguous nucleic acid residues in the chain based on the distance between P atoms, + or O5* or O5' if the P atom is not found. + :param chain: PDB chain to be searched for contiguous residues. + :param distance_threshold: float, the maximum distance between CA atoms to consider them contiguous. + The empirical 10.0 default value comes from the Richardson lab's Prekin code; the ideal length is ~7. + ''' + return _FindContiguousResiduesByAtomDistances(chain, _IsNucleicAcidResidue, ["P", "O5*", "O5'"], distance_threshold) + +# ------------------------------------------------------------------------------ + +class GuidePoint: + '''Class to hold a guide point for the ribbons representation.''' + def __init__(self, pos = None, cvec = None, dvec = None, offsetFactor = 0.0, widthFactor = 0.0, prevRes = None, nextRes = None): + '''Constructor for the class. + :param pos: vec3_double, the final position of the guide point. + :param cvec: vec3_double, the unit vector normal to the local plane of the ribbon. + :param dvec: vec3_double, the unit vector in the plane of the ribbon, perpendicular to its overall direction. + :param offsetFactor: float, the factor needed to pull spline through guidepoints. + It is already applied and does not depend on neighbors (unlike widthFactor). + :param widthFactor: float, Suggested ribbon width modifier, from 0 (skinniest) to 1 (fattest). + This is based on low/high curvatire of 3+ residues in a row. + :param prevRes: iotbx.pdb.hierarchy.residue_group, the residue in the chain just before this guidepoint + (never None). Usually different residues for proteins and for nucleic acids, except at chain ends. + For nucleic acids, prevRes is the residue centered on the guide point and nextRes is the one after. + (Protein guides fall between residues; nucleic guides fall in middle of a residue.) + :param nextRes: iotbx.pdb.hierarchy.residue_group, the residue in the chain just after this guidepoint. + ''' + self.pos = pos + self.cvec = cvec + self.dvec = dvec + self.offsetFactor = offsetFactor + self.widthFactor = widthFactor + self.prevRes = prevRes + self.nextRes = nextRes + + def __str__(self): + return 'GuidePoint(pos={}, cvec={}, dvec={}, offsetFactor={}, widthFactor={}, prev={}, next={})'.format( + self.pos, self.cvec, self.dvec, self.offsetFactor, self.widthFactor, self.prevRes, self.nextRes) + +# ------------------------------------------------------------------------------ + +def make_protein_guidepoints(contiguous_residues): + '''Return a list of GuidePoint objects for the protein residues. + :param contiguous_residues: list of iotbx.pdb.hierarchy.residue_group entries, on of + the contiguous residue lists returned by find_contiguous_protein_residues(). + ''' + + # Initialize an empty list of guiepoints that lie between residues (one less than the number of residues) + # plus two at the beginning and two at the end. These will be filled in below. These mist be independent + # GuidePoint objects, not references to the same object, because they will be modified in place. + numResidues = len(contiguous_residues) + guidepoints = [] + for i in range(numResidues - 1 + 2 + 2): + guidepoints.append(GuidePoint()) + + # Initialize some values for the calculations + maxOffset = 1.5 # Maximum displacement of guidepoint based on curvature + anchorAtoms = ["CA"] # Atoms to use for anchor points + + # Make normal guidepoints between each pair of residues. + for i in range(numResidues - 1): + + # Find the guidepoint to work on. + g = guidepoints[i+2] + + # Set the residues before and after the guidepoint + g.prevRes = contiguous_residues[i] + g.nextRes = contiguous_residues[i+1] + + # Find the anchor atoms for the current and previous residues. + # We know they are there because we found the residues in the contiguous_residues list. + ca1 = _FindNamedAtomInResidue(g.prevRes, anchorAtoms) + ca2 = _FindNamedAtomInResidue(g.nextRes, anchorAtoms) + + # Calculate the position of the guide point, which is halfway between them. + g.pos = (col(ca1.xyz) + col(ca2.xyz)) / 2 + + # Based on Ca(i-1) to Ca(i+2) distance, we may adjust ribbon width + # and/or guidepoint position. Ribbon widens in areas of high OR low + # curvature (alpha/beta, respectively). This is only a preliminary + # estimate -- it's applied only for 3+ residues in a row. (checked below) + # + # For high curvature ONLY (alpha), we offset the guidepoint + # outwards to make the spline track the chain (esp. helix); + # this is done for each and does not require 3+ in a row. + # Offset vector goes from the midpoint of Ca(i-1) to Ca(i+2) + # thru the current guide point + # (which is the midpoint of Ca(i) and Ca(i+1)). + # + # CA-CA DIST WIDTH FACTOR OFFSET FACTOR NOTE + # ========== ============ ============= ==== + # 5.0 1 1 ~limit for curled-up protein + # 5.5 1 1 } linear interpolation + # 7.0 0 0 } from 1.0 to 0.0 + # 9.0 0 0 } linear interpolation + # 10.5 1 0 } from 1.0 to 0.0 + # 11.0 1 0 ~limit for extended protein + + if 1 <= i and i <= numResidues - 3: + ca0 = _FindNamedAtomInResidue(contiguous_residues[i-1], anchorAtoms) + ca3 = _FindNamedAtomInResidue(contiguous_residues[i+2], anchorAtoms) + cacaDist = (col(ca0.xyz) - col(ca3.xyz)).length() + if cacaDist < 7: + g.widthFactor = min(1.5, 7-cacaDist) / 1.5 + g.offsetFactor = g.widthFactor + midpt = (col(ca0.xyz) + col(ca3.xyz)) / 2 + offsetVec = (g.pos - midpt).normalize() + g.pos += maxOffset * g.offsetFactor * offsetVec + elif cacaDist > 9: + g.widthFactor = min(1.5, cacaDist-9) / 1.5 + g.offsetFactor = 0 + else: + g.widthFactor = 0 + g.offsetFactor = 0 + + # Do this last so that for CA-only structures, everything above has been calculated + # before we might have to bail on this guidepoint. + ox1 = _FindNamedAtomInResidue(g.prevRes, ["O"]) + if ox1 is not None: + avec = col(ca2.xyz) - col(ca1.xyz) + bvec = col(ox1.xyz) - col(ca1.xyz) + g.cvec = avec.cross(bvec).normalize() + g.dvec = g.cvec.cross(avec).normalize() + else: + g.cvec = col({0, 0, 0}) + g.dvec = col({0, 0, 0}) + + # Check on widthFactors -- only apply for 3+ in a row > 0 + i = 2 + while i < len(guidepoints) - 2: + # Scan to find the first widened guidepoint. + if guidepoints[i].widthFactor == 0: + i += 1 + continue + # Scan to find the last widened guidepoint. + firstWide = i + nextThin = i+1 + while nextThin < len(guidepoints) - 2 and guidepoints[nextThin].widthFactor != 0: + nextThin += 1 + # If the span is less than 3, set them all back to zero. + if nextThin - firstWide < 3: + for j in range(firstWide, nextThin): + guidepoints[j].widthFactor = 0 + i += 1 + + # Make two dummy guidepoints at the beginning and end of the chain. + firstGuides = GuidePoint(col(_FindNamedAtomInResidue(contiguous_residues[0], anchorAtoms).xyz), + guidepoints[2].cvec, guidepoints[2].dvec, + guidepoints[2].offsetFactor, guidepoints[2].widthFactor, + contiguous_residues[0], contiguous_residues[0]) + guidepoints[0] = firstGuides + guidepoints[1] = firstGuides + lastGuides = GuidePoint(col(_FindNamedAtomInResidue(contiguous_residues[-1], anchorAtoms).xyz), + guidepoints[-3].cvec, guidepoints[-3].dvec, + guidepoints[-3].offsetFactor, guidepoints[-3].widthFactor, + contiguous_residues[-1], contiguous_residues[-1]) + guidepoints[-1] = lastGuides + guidepoints[-2] = lastGuides + + return guidepoints + +def make_nucleic_acid_guidepoints(contiguous_residues): + '''Return a list of GuidePoint objects for the nucleic acid residues. + :param contiguous_residues: list of iotbx.pdb.hierarchy.residue_group entries, one of + the contiguous residue lists returned by find_contiguous_amino_acid_residues(). + ''' + + # Initialize an empty list of guiepoints that lie between residues (one less than the number of residues) + # plus two at the beginning and two at the end. These will be filled in below. These mist be independent + # GuidePoint objects, not references to the same object, because they will be modified in place. + numResidues = len(contiguous_residues) + guidepoints = [] + for i in range(numResidues - 1 + 2 + 2): + guidepoints.append(GuidePoint()) + + # Initialize some values for the calculations + maxOffset = 1.5 # Maximum displacement of guidepoint based on curvature + anchorAtoms = ["P", "O5*", "O5'"] # Atoms to use for anchor points + + # Make normal guidepoints between each pair of residues. + for i in range(numResidues - 1): + + # Find the guidepoint to work on. + g = guidepoints[i+2] + + # Set the residues before and after the guidepoint + g.prevRes = contiguous_residues[i] + g.nextRes = contiguous_residues[i+1] + + # Find the anchor atoms for the current and previous residues. + # We know they are there because we found the residues in the contiguous_residues list. + phos1 = _FindNamedAtomInResidue(g.prevRes, anchorAtoms) + phos2 = _FindNamedAtomInResidue(g.nextRes, anchorAtoms) + + # Calculate the position of the guide point, which is halfway between them. + g.pos = (col(phos1.xyz) + col(phos2.xyz)) / 2 + + # Based on P(i-1) to P(i+1) or P(i) to P(i+2) distance, we may offset guide points. + # For areas of high curvature, the guide point is offset towards the C4'Based + # on P(i-1) to P(i+2) distance, we may adjust ribbon width. + + if (1 <= i and i <= numResidues - 3): + p0 = _FindNamedAtomInResidue(contiguous_residues[i-1], anchorAtoms) + p3 = _FindNamedAtomInResidue(contiguous_residues[i+2], anchorAtoms) + ppDist1 = (g.pos - col(p0.xyz)).length() + ppDist2 = (g.pos - col(p3.xyz)).length() + + # Default values for regions of low curvature + isTightlyCurved = False + ppDistance = ppDist1 + maxOffset = 0.0 + g.offsetFactor = 0.0 + g.widthFactor = 0.0 # There is never width hinting for nucleic acids + if ppDist1 <= 9.0 or ppDist2 <= 9.0: + isTightlyCurved = True + ppDistance = min(ppDist1, ppDist2) + carbon4 = _FindNamedAtomInResidue(g.prevRes, ["C4*", "C4'"]) + if carbon4 is not None: + maxOffset = (g.pos - col(carbon4.xyz)).length() + 1.0 # Allows guidepoint to go past the C4' + g.offsetFactor = (9.0 - ppDistance) / (9.0 - 7.0) + g.offsetFactor = min(1.0, g.offsetFactor) # Reaches full offset at 7A curvature + offsetVec = (col(carbon4.xyz) - g.pos).normalize() + g.pos += maxOffset * g.offsetFactor * offsetVec + + # We do this last so that if there are missing atoms everying above has been calculated + # before we might have to bail on this guidepoint. + carbon3 = _FindNamedAtomInResidue(g.prevRes, ["C3*", "C3'"]) + carbon1 = _FindNamedAtomInResidue(g.nextRes, ["C1*", "C1'"]) + if carbon3 is not None and carbon1 is not None: + avec = col(phos2.xyz) - col(phos1.xyz) + bvec = col(carbon1.xyz) - col(carbon3.xyz) + g.cvec = avec.cross(bvec).normalize() + g.dvec = g.cvec.cross(avec).normalize() + else: + g.cvec = col({0, 0, 0}) + g.dvec = col({0, 0, 0}) + + # Make dummy guidepoints at the beginning and end of the chain. + firstGuides = GuidePoint(col(_FindNamedAtomInResidue(contiguous_residues[0], anchorAtoms).xyz), + guidepoints[2].cvec, guidepoints[2].dvec, + guidepoints[2].offsetFactor, guidepoints[2].widthFactor, + contiguous_residues[0], contiguous_residues[0]) + guidepoints[0] = firstGuides + guidepoints[1] = firstGuides + # Prekin: 3' guide point is 2/3 of the way to the O3' from the last guide point, + # but we just use the C3 atom. + carbon3 = _FindNamedAtomInResidue(contiguous_residues[-1], ["C3*", "C3'", "P", "O5'", "O5*"]) + if carbon3 is not None: + lastGuides = GuidePoint(col(carbon3.xyz), + guidepoints[-3].cvec, guidepoints[-3].dvec, + guidepoints[-3].offsetFactor, guidepoints[-3].widthFactor, + contiguous_residues[-1], contiguous_residues[-1]) + guidepoints[-1] = lastGuides + guidepoints[-2] = lastGuides + + return guidepoints + +# ------------------------------------------------------------------------------ + +def swap_edge_and_face(guidepoints): + '''Converts a RNA-style ribbon (the default) to a DNA-style one, + and vice versa, by swapping the "c" and "d" vectors. + This results in a 90 degree rotation of the ribbon around the ribbon axis. + :param guidepoints: list of GuidePoint objects to swap the edge and face vectors for. + ''' + for g in guidepoints: + g.cvec, g.dvec = g.dvec, g.cvec + +def untwist_ribbon(guidepoints): + '''Removes excess twist from a ribbon by reversing the sign of the GuidePoint + "d" vectors as necessary. A vector is flipped if it has a negative dot product + with the previous one (i.e. the angle between them is greater than 90 degrees). + :param guidepoints: list of GuidePoint objects to untwist. + ''' + for i in range(len(guidepoints)-1): + if guidepoints[i].dvec.dot(guidepoints[i+1].dvec) < 0: + guidepoints[i+1].dvec *= -1.0 + +# ------------------------------------------------------------------------------ + +def non_CA_atoms_present(structure): + '''Return True if any atom other than CA is present in the structure. + :param structure: iotbx.pdb.hierarchy.root object holding the structure to check. + ''' + for model in structure.models(): + for chain in model.chains(): + for residue_group in chain.residue_groups(): + for atom in residue_group.atoms(): + if atom.name.strip().upper() != "CA": + return True + return False diff --git a/mmtbx/kinemage/validation.py b/mmtbx/kinemage/validation.py index a44edbbbb6..024cfbdafe 100644 --- a/mmtbx/kinemage/validation.py +++ b/mmtbx/kinemage/validation.py @@ -565,13 +565,7 @@ def get_chain_color(index): 'lilactint', 'bluetint', 'greentint'] - match = False - while not match: - if index > 6: - index = index - 6 - else: - match = True - return chain_colors[index] + return chain_colors[int(index) % len(chain_colors)] def get_ions(ion_list): ion_txt = "@spherelist {het M} color= gray radius= 0.5 nobutton master= {hets}\n" diff --git a/mmtbx/programs/reduce2.py b/mmtbx/programs/reduce2.py index e1e223202d..6b4e4896ea 100644 --- a/mmtbx/programs/reduce2.py +++ b/mmtbx/programs/reduce2.py @@ -29,14 +29,14 @@ from mmtbx.hydrogens import reduce_hydrogen from mmtbx.reduce import Optimizers from scitbx.array_family import flex -from iotbx.pdb import common_residue_names_get_class, amino_acid_codes +from iotbx.pdb import common_residue_names_get_class, amino_acid_codes, nucleic_acid_codes from mmtbx.programs import probe2 import copy import tempfile from iotbx.data_manager import DataManager import csv -version = "2.5.0" +version = "2.6.0" master_phil_str = ''' approach = *add remove @@ -310,16 +310,17 @@ def _DescribeMainchainLink(a0s, a1s, group): ret += _AddPosition(a0, 'P', group) + ' ' + _AddPosition(a1, 'L', group, a0) + '\n' return ret + +_amino_acid_resnames = sorted(amino_acid_codes.one_letter_given_three_letter.keys()) def _IsStandardResidue(resname): - amino_acid_resnames = sorted(amino_acid_codes.one_letter_given_three_letter.keys()) - return resname.strip().upper() in amino_acid_resnames + return resname.strip().upper() in _amino_acid_resnames + +_nucleic_acid_resnames = set(nucleic_acid_codes.rna_one_letter_code_dict.keys()).union( + set(nucleic_acid_codes.dna_one_letter_code_dict.keys())) def _IsNucleicAcidResidue(resname): - nucleic_acids = [ - "A", "C", "G", "T", # DNA bases - "U", "I", # RNA bases (I for inosine, a modified RNA base) - ] - return resname.strip().upper() in nucleic_acids + return resname.strip().upper() in _nucleic_acid_resnames + def _MainChainAtomsWithHydrogen(resname): # Find the main chain atoms with hydrogen bonds diff --git a/mmtbx/programs/ribbons.py b/mmtbx/programs/ribbons.py new file mode 100644 index 0000000000..a7913ffb6d --- /dev/null +++ b/mmtbx/programs/ribbons.py @@ -0,0 +1,702 @@ +from __future__ import absolute_import, division, print_function +from libtbx.program_template import ProgramTemplate +import iotbx.pdb +import mmtbx.secondary_structure +from pathlib import Path +import numpy as np +from mmtbx.kinemage.validation import get_chain_color +from mmtbx.kinemage.ribbons import find_contiguous_protein_residues, find_contiguous_nucleic_acid_residues +from mmtbx.kinemage.ribbons import make_protein_guidepoints, make_nucleic_acid_guidepoints +from mmtbx.kinemage.ribbons import untwist_ribbon, swap_edge_and_face, _FindNamedAtomInResidue +from mmtbx.kinemage.nrubs import Triple, NRUBS + +version = "1.0.0" + +master_phil_str = ''' +do_protein = True + .type = bool + .short_caption = Construct protein ribbons + .help = Construct ribbons for the protein sections of the model +do_nucleic_acid = True + .type = bool + .short_caption = Construct nucleic acid ribbons + .help = Construct ribbons for the nucleic acid sections of the model +untwist_ribbons = True + .type = bool + .short_caption = Untwist ribbons + .help = Remove excess twist from ribbons by making the neighboring dot products positive +DNA_style = False + .type = bool + .short_caption = DNA style ribbons + .help = Use the DNA style ribbons instead of the default RNA style ribbons (rotates them by 90 degrees) +color_by = *rainbow secondary_structure + .type = choice(multi=False) + .short_caption = How to color the ribbons + .help = How to color the ribbons +do_plain_coils = False + .type = bool + .short_caption = Do plain coils + .help = Do plain coils (no halo) even for the helix and sheet parts of the protein +coil_width = 1.0 + .type = float + .short_caption = Coil width + .help = Width of the coil part of the ribbon +selection = (altloc ' ' or altloc '' or altloc a) + .type = atom_selection + .short_caption = Atom selection + .help = Atom selection description +''' + +# ------------------------------------------------------------------------------ + +class Program(ProgramTemplate): + description = ''' +mmtbx.ribbons version {}: Given PDB file produce Kinemage file with ribbons representation. + +This program produces a kinemage file with ribbons representation of the input file using the +same algorithm as the Richardson lab's MolProbity server. The code is based on the Java code +within the javadev repository. + +How to run: + mmtbx.ribbons model.pdb + +Output: + If neither output.file_name nor output.filename is specified, it will write + to a file with the same name as the input model file name but with the + extension replaced with with '.kin'. + +'''.format(version) + datatypes = ['model', 'phil'] + master_phil_str = master_phil_str + +# ------------------------------------------------------------------------------ + + def validate(self): + self.data_manager.has_models(raise_sorry=True) + + if self.params.output.filename is None: + # If the output file name is not specified, use the same root as the + # input file and replace the suffix with .kin. + suffix = '.kin' + inName = self.data_manager.get_default_model_name() + p = Path(inName) + self.params.output.filename = str(p.with_suffix(suffix)) + print('Setting output.filename Phil parameter to',self.params.output.filename) + +# ------------------------------------------------------------------------------ + + def splineInterplate(self, pts, nIntervals): + # Returns a list of interpolated points between the points using a spline interpolation. + # Based on https://docs.scipy.org/doc/scipy/tutorial/interpolate/1D.html#parametric-spline-curves + # @param pts: The guidepoints to interpolate between (a list of 3D points with at least 6 points in it). + # The first and last points are duplicates to form knots, so are not interpolated between. + # @param nIntervals: The number of intervals to interpolate between each pair of guidepoints, skipping the first and last. + # @return: The list of interpolated points + + nrubs = NRUBS() + points = [] + for pt in pts: + points.append( Triple(pt[0], pt[1], pt[2]) ) + res = nrubs.spline(points, nIntervals) + ret = [] + for r in res: + ret.append( np.array((r.x, r.y, r.z)) ) + return ret + + # Adjust the points to match what is expected by the Java code. + # The Java code expects the first and last points to be duplicates of the second and second-to-last points. + points = pts[1:-1] + +# ------------------------------------------------------------------------------ + + # The original code constructed a NONE crayon for the fancy print, which did not add color to + # the output, re-using the colors specified by model or chain. It sometimes also specified + # the RAINBOW crayon, which overwrites the colors with a rainbow color scheme across each chain. + # For the edges, it specified a constant crayon whose string value is deadblack + # and it adds "U " to make it un-pickable. + # We pull that logic into here by implementing the forRibbon() and shouldPrint() and + # getKinString() methods in our own class. + class Crayon: + def __init__(self, doRainBow, color=None): + self._doRainBow = doRainBow + self._color = color + self._rainbowColors = [ "blue", "sky", "cyan", "sea", "green", "lime", "yellow" ,"gold" ,"orange" ,"red" ] + + # Rainbow color map changes the color once across the rainbow for each chain (the chain goes from + # blue to red). + # The non-rainbow, constant-colored map does not change. + def forRibbon(self, startGuide): + if self._doRainBow: + res = startGuide.prevRes + chain = res.parent() + firstChainResID = chain.residue_groups()[0].resseq + lastChainResID = chain.residue_groups()[-1].resseq + normRes = (int(res.resseq) - int(firstChainResID)) / (int(lastChainResID) - int(firstChainResID)) + scaledIndex = int(normRes * len(self._rainbowColors)) + if scaledIndex == len(self._rainbowColors): + scaledIndex -= 1 + self._color = self._rainbowColors[scaledIndex] + + def getKinString(self): + if self._color is None: + return "" + return self._color + + # All of our elements should be visible in the output. + def shouldPrint(self): + return True + + # Commented out the fields and did not include methods that we don't need for our implementation + # Switched getType() to making type public. + # Its fields should be based on the PDB secondary structure records. + class Range: + def __init__(self, pType = 'COIL', pChainId = '', pInit = 0, pEnd = 0, pSense = 0, pStrand = 1, pSheet = ' ', pFlipped = False): + # self._rangeIndex = 0 + self.type = pType + self._chainId = pChainId + self.initSeqNum = pInit + self.endSeqNum = pEnd + #self._initICode = ' ' + #self._endICode = ' ' + self.sense = pSense # 0 if first strand, 1 if parallel, -1 if anti-parallel + self.strand = pStrand # Starts at 1 for each strand within a sheet and increases by 1 + self.sheetID = pSheet + self.flipped = pFlipped # Used by printing code to make the tops within a set of ribbons all point the same way + self.previous = None + self.next = None + self.duplicateOf = None + + def __str__(self): + return 'Range: type={}, init={}, end={}, sense={}, strand={}, sheet={}, flipped={}'.format( + self.type, self.initSeqNum, self.endSeqNum, self.sense, self.strand, self.sheetID, self.flipped) + + def ConsolidateSheets(self): + uniqueStrands = {} + + # For each ribbon, record its predecessor in sheet, and check for duplicates + for rng in self.secondaryStructure.values(): + if not rng.type == 'SHEET': + continue + + key = str(int(rng.initSeqNum)) + rng._chainId + if not key in uniqueStrands: + uniqueStrands[key] = rng + else: + rng.duplicateOf = uniqueStrands[key] + + # Now find this strand's previous and next strand. + for rng2 in self.secondaryStructure.values(): + if not rng2.type == 'SHEET': + continue + if rng2.sheetID == rng.sheetID and rng2.strand == rng.strand-1: + rng.previous = rng2 + rng2.next = rng + + # Now go through and reassign previous/next fields in duplicates + for rng in self.secondaryStructure.values(): + if not rng.type == 'SHEET': + continue + if rng.duplicateOf is None and rng.next is not None and rng.next.duplicateOf is not None: + rng.next.duplicateOf.previous = rng + if rng.duplicateOf is None and rng.previous is not None and rng.previous.duplicateOf is not None: + rng.previous = rng.previous.duplicateOf + + class RibbonElement: + def __init__(self, other=None, setRange=None): + self.start = 0 + self.end = 0 + self.type = 'COIL' + self.range = setRange + if other is not None: + self.like(other) + if self.range is not None: + if self.range.type is None or self.range.type == 'TURN': + self.type = 'COIL' + else: + self.type = self.range.type + + def sameSSE(self, that): + return self.type == that.type and self.range == that.range + + def like(self, that): + self.start = that.start + self.end = that.end + self.type = that.type + self.range = that.range + + def __lt__(self, that): + a = 0 + b = 0 + if self.range is not None: + a = self.range.strand + if that.range is not None: + b = that.range.strand + return a < b + + # If the current point ID is the same as the previous point ID, we return the shorthand double-quote (") to + # indicate this. To force a new point ID, set self._lastPointID to "" before calling this function. + def getPointID(self, point, start, end, interval, nIntervals): + if self._lastPointID is None: + self._lastPointID = "" + + res = start.nextRes + if self.params.DNA_style and interval <= nIntervals // 2: + res = start.prevRes # == first res, for RNA/DNA only + + buf = res.atom_groups()[0].resname.strip() + " " + res.parent().id.strip() + " " + res.resseq.strip() + res.icode + res = buf.lower().strip() + + if res == self._lastPointID: + res = '"' + else: + self._lastPointID = res + + return res + + def printFancy(self, guides, splines, i, lineBreak = False): + # Prints a fancy ribbon element with the given guidepoints and splines. + # @param guides: The guidepoints for the ribbon + # @param splines: The interpolated points for the ribbon + # @param i: The index of the guidepoint to print + + ret = "" + # Not self.nIntervals, we want a local variable here + nIntervals = (len(splines) - 1) // (len(guides) - 3) + interval = i % nIntervals + startGuide = (i // nIntervals) + 1 + ret += "{" + ret += self.getPointID(splines[i], guides[startGuide], guides[startGuide + 1], interval, nIntervals) + ret += "}" + if lineBreak: + ret += "P " + self.crayon.forRibbon(guides[startGuide]) + ret += self.crayon.getKinString() + ret += " " + ret += "{:.3f} {:.3f} {:.3f}\n".format(splines[i][0], splines[i][1], splines[i][2]) + + return ret + + def printFancyRibbon(self, guides, widthAlpha, widthBeta, listAlpha, listBeta, listCoil, listCoilOutline, doRainbow): + # Constructs a kinemage string for a ribbon representation of a protein or nucleic acid chain. + # Makes a triangulated ribbon with arrowheads, etc. + # @param guides: The guidepoints for the ribbon + # @param widthAlpha: The width of the alpha helix part of the ribbon + # @param widthBeta: The width of the beta sheet part of the ribbon + # @param listAlpha: The kinemage string describing the alpha helix part of the ribbon + # @param listBeta: The kinemage string describing the beta sheet part of the ribbon + # @param listCoil: The kinemage string describing the coil part of the ribbon + # @param listCoilOutline: The kinemage string describing the outline of the coil part of the ribbon + # @param doRainbow: Whether or not to color the ribbon by rainbow + # If false (the default), the protein style will be used instead. + # @return: The kinemage string for the ribbon representation + + ret = "" + + # Initialize local references + widthCoil = self.params.coil_width + secStruct = self.secondaryStructure + + # Seven strands of guidpoints: coil, +/-alpha, +/-beta, +/-beta arrowheads. + # Each strand is a list of 3D points and there is a strand for each offset from the center spline. + halfWidths = [0.0, -widthAlpha/2, widthAlpha/2, -widthBeta/2, widthBeta/2, -widthBeta, widthBeta] + # Make a different empty list for each strand + strands = [] + for _ in range(len(halfWidths)): + strands.append([]) + for g in guides: + for i in range(len(halfWidths)): + strands[i].append(g.pos + g.dvec * halfWidths[i]) + + # Seven strands of interpolated points + splinepts = [] + for i in range(len(strands)): + splinepts.append(self.splineInterplate(strands[i], self.nIntervals)) + + # Discovery of ribbon elements: ribbons, ropes, and arrows. + # We skip the regions associated with the first and last points, which are present to cause the + # curve to pass through those points (like knots) but are not interpolated between. + # We do that by looping through fewer entries and by adding 1 to the index. + ribbonElements = [] + ribElement = self.RibbonElement() + prevRibElt = self.RibbonElement() + ribbonElements.append(ribElement) + # Element that is reused and copied when creating a new list entry + ribElement.type = None + for i in range(len(guides) - 1 - 2): + g1 = guides[i + 1] + g2 = guides[i + 2] + + # The Java code reports that we're not really using ribbon elements, just reusing the + # class for convenience. So not all of the member variables may be filled in. + currSS = self.RibbonElement(setRange=secStruct[int(g1.nextRes.resseq)]) + nextSS = self.RibbonElement(setRange=secStruct[int(g2.nextRes.resseq)]) + + # Otherwise, we get one unit of coil before alpha or beta at start + if ribElement.type is None: + ribElement.like(currSS) + + if not ribElement.sameSSE(currSS): # Helix / sheet starting + if currSS.type == 'HELIX' or currSS.type == 'SHEET': + ribElement.end = self.nIntervals*i + 1 + ribElement = self.RibbonElement(currSS) + ribbonElements.append(ribElement) + # Every helix or sheet starts with a coil; see below + ribElement.start = self.nIntervals*i + 1 + if not ribElement.sameSSE(nextSS): # Helix / sheet ending + if currSS.type == 'HELIX' or currSS.type == 'SHEET': + end = self.nIntervals*i + 0 + if currSS.type == 'SHEET': + end += self.nIntervals - 1 + ribElement.end = end + ribElement = self.RibbonElement() + ribbonElements.append(ribElement) + # Every helix or sheet flows into coil + ribElement.type = 'COIL' + ribElement.start = end + ribElement.end = len(splinepts[0]) - 1 + + # "Crayons" to use for coloring the ribbon, juggling them around to keep the edges black. + normalCrayon = self.Crayon(doRainbow) + edgeCrayon = self.Crayon(False) # Default no color; the deadblack will be set on the vectorlist + + # Sort the ribbon elements by strand number + ribbonElements.sort() + + # Create a list of just sheets (Java STRANDs) for searching through + strands = [r for r in ribbonElements if r.type == 'SHEET'] + + for ribElement in ribbonElements: + stGuide = (ribElement.start // self.nIntervals) + 2 + endGuide = (ribElement.end // self.nIntervals) - 1 + + if ribElement.type == 'HELIX': + + k = (ribElement.start + ribElement.end) // 2 + pt = splinepts[2][k] + v1 = splinepts[1][k] - pt + v2 = splinepts[1][k+1] - pt + cross = np.cross(v1, v2) + dot = np.dot( np.linalg.norm(cross), np.linalg.norm(np.array(guides[k//self.nIntervals+1].cvec))) + + self.crayon = normalCrayon + ret += "@ribbonlist {fancy helix} " + listAlpha + "\n" + self._lastPointID = "" + + for i in range(ribElement.start, ribElement.end): + if dot > 0: + # Flip the normals (for sidedness) by switching the order of these two lines. + ret += self.printFancy(guides, splinepts[2], i) + ret += self.printFancy(guides, splinepts[1], i) + else: + ret += self.printFancy(guides, splinepts[1], i) + ret += self.printFancy(guides, splinepts[2], i) + ret += self.printFancy(guides, splinepts[0], ribElement.end) # Angled tip at end of helix + self.crayon = edgeCrayon + ret += "@vectorlist {fancy helix edges} width=1 " + listAlpha + " color= deadblack\n" + self._lastPointID = "" + # Black edge, left side + ret += self.printFancy(guides, splinepts[0], ribElement.start, True) + for i in range(ribElement.start, ribElement.end): + ret += self.printFancy(guides, splinepts[1], i) + ret += self.printFancy(guides, splinepts[0], ribElement.end) + # Black edge, right side + ret += self.printFancy(guides, splinepts[0], ribElement.start, True) + for i in range(ribElement.start, ribElement.end): + ret += self.printFancy(guides, splinepts[2], i) + ret += self.printFancy(guides, splinepts[0], ribElement.end) + + elif ribElement.type == 'SHEET': + + dot = 0.0 # Used to determine sidedness + + # Don't do for the first strand in the sheet + if ribElement.range.strand != 1: + # Look for previous strand + for i in range(len(strands)): + curElt = strands[i] + if curElt.range == ribElement.range.previous: + prevRibElt = curElt + break + + prevRange = prevRibElt.range + if prevRange is None: + prevRibElt = ribElement + + # Detrmine sidedness using splinepts and normals + prevStGuide = (prevRibElt.start // self.nIntervals) + 2 + prevEndGuide = (prevRibElt.end // self.nIntervals) + 1 + curClosest = stGuide # Find the pair of guidepoints closest to each other + prevClosest = prevStGuide # (one on each strand) to perform the test + closeDist = 1e10 + for i in range(stGuide, endGuide+2 + 1): + for j in range(prevStGuide, endGuide+2 + 1): + # Look for closest pair of H-bonding partners + try: + O = _FindNamedAtomInResidue(guides[i].prevRes, "O") + N = _FindNamedAtomInResidue(guides[i].prevRes, "N") + dist = np.linalg.norm(O.pos - N.pos) + if dist < closeDist: + closeDist = dist + curClosest = i + prevClosest = j + except Exception: + pass + kCur = min(self.nIntervals*(curClosest-1), len(splinepts[4])) + kPrev = min(self.nIntervals*(prevClosest-1), len(splinepts[4])) + ptCur = splinepts[4][kCur] + v1Cur = splinepts[3][kCur] - ptCur + # VBC Hack to get 1jj2 at least generating ribbons kins. Doesn't seem to + # correctly generate beta sides though. Error is kCur+1 generates an ArrayIndexOutOfBoundsException in splinepts[3] + if kCur+1 < len(splinepts[3]): + v2Cur = splinepts[3][kCur+1] - ptCur + crossCur = np.cross(v1Cur, v2Cur) + ptPrev = splinepts[4][kPrev] + v1Prev = splinepts[3][kPrev] - ptPrev + v2Prev = splinepts[3][kPrev+1] - ptPrev + crossPrev = np.cross(v1Prev, v2Prev) + dot = np.dot( crossCur, crossPrev) + + self.crayon = normalCrayon + ret += "@ribbonlist {fancy sheet} " + listBeta + "\n" + self._lastPointID = "" + for i in range(ribElement.start, ribElement.end - 1): + # If strands are not "facing" the same way, + # flip the normals (for sidedness) by switching the order of these two lines, (ARK Spring2010) + if (dot < 0 and not prevRibElt.range.flipped) or (dot > 0 and prevRibElt.range.flipped): + ret += self.printFancy(guides, splinepts[4], i) + ret += self.printFancy(guides, splinepts[3], i) + ribElement.range.flipped = True + else: + ret += self.printFancy(guides, splinepts[3], i) + ret += self.printFancy(guides, splinepts[4], i) + + # Ending *exactly* like this is critical to avoiding a break + # between the arrow body and arrow head! + if (dot < 0 and not prevRibElt.range.flipped) or (dot > 0 and prevRibElt.range.flipped): + ret += self.printFancy(guides, splinepts[6], ribElement.end - 2) + ret += self.printFancy(guides, splinepts[5], ribElement.end - 2) + ret += self.printFancy(guides, splinepts[0], ribElement.end) + else: + ret += self.printFancy(guides, splinepts[5], ribElement.end - 2) + ret += self.printFancy(guides, splinepts[6], ribElement.end - 2) + ret += self.printFancy(guides, splinepts[0], ribElement.end) + # Borders + self.crayon = edgeCrayon + ret += "@vectorlist {fancy sheet edges} width=1 " + listBeta + " color= deadblack\n" + self._lastPointID = "" + # Black edge, left side + ret += self.printFancy(guides, splinepts[0], ribElement.start, True) + for i in range(ribElement.start, ribElement.end - 1): + ret += self.printFancy(guides, splinepts[3], i) + ret += self.printFancy(guides, splinepts[5], ribElement.end - 2) + ret += self.printFancy(guides, splinepts[0], ribElement.end) + # Black edge, right side + ret += self.printFancy(guides, splinepts[0], ribElement.start, True) + for i in range(ribElement.start, ribElement.end - 1): + ret += self.printFancy(guides, splinepts[4], i) + ret += self.printFancy(guides, splinepts[6], ribElement.end - 2) + ret += self.printFancy(guides, splinepts[0], ribElement.end) + + else: # Coil + + # for black outlines on coils + if listCoilOutline is not None: + self.crayon = normalCrayon + ret += "@vectorlist {fancy coil edges} " + listCoilOutline + "\n" + self._lastPointID = "" + for i in range(ribElement.start, ribElement.end+1): + ret += self.printFancy(guides, splinepts[0], i) + + self.crayon = normalCrayon + ret += "@vectorlist {fancy coil} " + listCoil + "\n" + self._lastPointID = "" + for i in range(ribElement.start, ribElement.end+1): + ret += self.printFancy(guides, splinepts[0], i) + + # Reset the crayon for the next pass + self.crayon = normalCrayon + + return ret + +# ------------------------------------------------------------------------------ + + def run(self): + self.model = self.data_manager.get_model() + self.nIntervals = 4 + + # Apply a selection to the model if one is provided. The default is to select atoms in the + # first alternate location. + hierarchy = self.model.get_hierarchy() + selection_string = self.params.selection + if selection_string is None: + selection_string = "(altloc ' ' or altloc '' or altloc a)" + selection = hierarchy.atom_selection_cache().selection(selection_string) + hierarchy = hierarchy.select(selection) + + # Analyze the secondary structure and make a dictionary that maps from residue sequence number to secondary structure type + # by filling in 'COIL' as a default value for each and then parsing all of the secondary structure records in the + # model and filling in the relevant values for them. + print('Finding secondary structure:') + ss_manager = mmtbx.secondary_structure.manager(hierarchy) + self.secondaryStructure = {} + for model in hierarchy.models(): + for chain in model.chains(): + for residue_group in chain.residue_groups(): + self.secondaryStructure[int(residue_group.resseq)] = self.Range() + for line in ss_manager.records_for_pdb_file().splitlines(): + r = self.Range(line[0:5].strip()) + if r.type == 'HELIX': + r.sheetID = line[11:14].strip() + r._chainId = line[19:21].strip() + r.initSeqNum = int(line[22:26].strip()) + r.endSeqNum = int(line[33:38].strip()) + elif r.type == 'SHEET': # Java code marks this internally as STRAND but we leave it as SHEET + r.sheetID = line[11:14].strip() + r._chainId = line[21:22].strip() + r.initSeqNum = int(line[23:28].strip()) + r.endSeqNum = int(line[33:38].strip()) + r.sense = int(line[38:40].strip()) + r.strand = int(line[7:10].strip()) + elif r.type == 'TURN': + # In fact, we turn turns int coils, so we really don't care. + # r.sheetID = line[11:14].strip() + r._chainId = line[20:21].strip() + r.initSeqNum = int(line[22:26].strip()) + r.endSeqNum = int(line[33:37].strip()) + for i in range(r.initSeqNum,r.endSeqNum+1): + self.secondaryStructure[i] = r + + self.ConsolidateSheets() + + # The name of the structure, which is the root of the input file name (no path, no extension) + self.idCode = self.data_manager.get_default_model_name().split('.')[0] + if self.idCode is None or self.idCode == "": + self.idCode = "macromol" + + # Create the output string that will be written to the output file. It will be filled in during the run. + outString = "" + + # Fill in the header information + outString += "@kinemage 1\n" + outString += "@onewidth\n" + + # Handle multiple models + groupByModel = hierarchy.models_size() > 1 + for model in hierarchy.models(): + modelID = model.id + if modelID == "": + modelID = "_" + print('Processing model', modelID, 'with', len(model.chains()), 'chains') + if groupByModel: + outString += "@group {{{} {}}} animate dominant master= {{all models}}\n".format(self.idCode, str(modelID).strip()) + + # Make a list of all the chain names in the model with only one entry per name. + # Use this to make a dictionary to look up the color that is used for each chain name. + # This ensures that the chains are colored the same no matter their order or repeat in the file. + chainNames = set() + for chain in model.chains(): + chainNames.add(chain.id) + chainNames = sorted(list(chainNames)) + chainCount = 0 + chainColors = {} + for name in chainNames: + # Backbone color by model ID if we have multiple models, or by chain ID if we have multiple chains in a model. + if groupByModel: + c = get_chain_color(modelID) + else: + c = get_chain_color(chainCount) + chainColors[name] = c + chainCount += 1 + + # Cycle over all chains in the model and make a group or subgroup for each chain + # depending on whether we are grouping by model or not. + for chain in model.chains(): + print('Processing chain',chain.id) + + if self.params.do_protein: + # Find the contiguous protein residues by CA distance + contiguous_residue_lists = find_contiguous_protein_residues(chain) + print('Found {} contiguous protein residue lists'.format(len(contiguous_residue_lists))) + + if len(contiguous_residue_lists) > 0: + if groupByModel: + outString += "@subgroup {{chain{}}} dominant master= {{chain {}}}\n".format(chain.id, chain.id) + else: + outString += "@group {{{} {}}} dominant\n".format(self.idCode, chain.id) + outString += "@subgroup {ribbon}\n" + + bbColor = chainColors[chain.id] + if bbColor == "white": + # Distinguish between the different types of secondary structure for the first chain + outString += "@colorset {{alph{}}} red\n".format(chain.id) + outString += "@colorset {{beta{}}} lime\n".format(chain.id) + outString += "@colorset {{coil{}}} white\n".format(chain.id) + else: + # Do all secondary structure in the same color for all but the first chain to clean up the display + outString += "@colorset {{alph{}}} {}\n".format(chain.id, bbColor) + outString += "@colorset {{beta{}}} {}\n".format(chain.id, bbColor) + outString += "@colorset {{coil{}}} {}\n".format(chain.id, bbColor) + + for contig in contiguous_residue_lists: + guidepoints = make_protein_guidepoints(contig) + print(' Made {} protein guidepoints for {} residues'.format(len(guidepoints),len(contig))) + if self.params.untwist_ribbons: + print(' Untwisted ribbon') + untwist_ribbon(guidepoints) + # There is always secondary structure looked up for protein residues, so we skip the case from the Java code + # where it can be missing. + if self.params.do_plain_coils: + outString += self.printFancyRibbon(guidepoints, 2, 2.2, + "color= {alph"+chain.id+"} master= {protein} master= {ribbon} master= {alpha}", + "color= {beta"+chain.id+"} master= {protein} master= {ribbon} master= {beta}", + "width= 4 color= {coil"+chain.id+"} master= {protein} master= {ribbon} master= {coil}", + self.params.color_by == "rainbow"); + else: + outString += self.printFancyRibbon(guidepoints, 2, 2.2, + "color= {alph"+chain.id+"} master= {protein} master= {ribbon} master= {alpha}", + "color= {beta"+chain.id+"} master= {protein} master= {ribbon} master= {beta}", + "width= 4 fore color= {coil"+chain.id+"} master= {protein} master= {ribbon} master= {coil}", + "width= 6 rear color= deadblack master= {protein} master= {ribbon} master= {coil}", + self.params.color_by == "rainbow") + + if self.params.do_nucleic_acid: + # Find the contiguous nucleic acid residues by CA distance + contiguous_residue_lists = find_contiguous_nucleic_acid_residues(chain) + print('Found {} contiguous nucleic acid residue lists'.format(len(contiguous_residue_lists))) + + if len(contiguous_residue_lists) > 0: + if groupByModel: + outString += "@subgroup {{chain{}}} dominant master= {chain {}}}\n".format(chain.id, chain.id) + else: + outString += "@group {{{} {}}} dominant\n".format(self.idCode, chain.id) + outString += "@subgroup {ribbon}\n" + + bbColor = chainColors[chain.id] + if bbColor == "white": + outString += "@colorset {{nucl{}}} lime\n".format(chain.id) + outString += "@colorset {{ncoi{}}} white\n".format(chain.id) + else: + outString += "@colorset {{nucl{}}} {}\n".format(chain.id, bbColor) + outString += "@colorset {{ncoi{}}} {}\n".format(chain.id, bbColor) + + for contig in contiguous_residue_lists: + guidepoints = make_nucleic_acid_guidepoints(contig) + print(' Made {} NA guidepoints for {} residues'.format(len(guidepoints),len(contig))) + if self.params.untwist_ribbons: + print(' Untwisted ribbon') + untwist_ribbon(guidepoints) + if self.params.DNA_style: + print(' Swapped edge and face (DNA style)') + swap_edge_and_face(guidepoints) + else: + print(' Using RNA style ribbons') + + outString += self.printFancyRibbon(guidepoints, 3.0, 3.0, + "color= {nucl"+chain.id+"} master= {nucleic acid} master= {ribbon} master= {RNA helix?}", + "color= {nucl"+chain.id+"} master= {nucleic acid} master= {ribbon} master= {A-form}", + "width= 4 color= {ncoi"+chain.id+"} master= {nucleic acid} master= {ribbon} master= {coil}", + None, + self.params.color_by == "rainbow") + + # Write the output to the specified file. + self.data_manager._write_text("Text", outString, self.params.output.filename) From c4a8c656bb144fa1efec9df49e40aeb6ac2cbdee Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Tue, 27 Aug 2024 17:09:23 -0700 Subject: [PATCH 669/748] Use standard error of the mean to match computation from cctbx --- xfel/merging/application/statistics/deltaccint.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/xfel/merging/application/statistics/deltaccint.py b/xfel/merging/application/statistics/deltaccint.py index cb7be4a828..4e69cf2d7d 100644 --- a/xfel/merging/application/statistics/deltaccint.py +++ b/xfel/merging/application/statistics/deltaccint.py @@ -90,7 +90,7 @@ def run(self, experiments, reflections): mean_intensity_unmodified = np.mean(intensity) diff_sq_unmodified = np.sum((intensity-mean_intensity_unmodified)**2) diff_sq_[diff_sq_<0] = diff_sq_unmodified - variance[:,hkl_idx] = diff_sq_ / (n[:,hkl_idx]-1) + variance[:,hkl_idx] = diff_sq_ / (n[:,hkl_idx]-1) / n[:,hkl_idx] # N expts (all ranks) x N bins n_bins = resolution_binner.n_bins_used() @@ -105,9 +105,7 @@ def run(self, experiments, reflections): all_i_n [:,bin_idx] += 1 all_var_sums[:,bin_idx] += variance[:,hkl_map[hkl]] - total_var_sums = comm.reduce(all_var_sums, MPI.SUM, 0) - - # Broadcast the average intensities + # Broadcast the variances and average intensities total_i_sums = comm.allreduce(all_i_sums, op=MPI.SUM) total_i_n = comm.allreduce(all_i_n, op=MPI.SUM) total_var_sums = comm.reduce(all_var_sums, op=MPI.SUM) @@ -130,9 +128,9 @@ def run(self, experiments, reflections): # Report if self.mpi_helper.rank == 0: - sigma_sq_y = total_diff_sq_sum / (total_i_n-1) - sigma_sq_e = total_var_sums / total_i_n - deltaccint_st = (sigma_sq_y - (0.5 * sigma_sq_e)) / (sigma_sq_y + sigma_sq_e) + sigma_sq_y = total_diff_sq_sum / (total_i_n-1) # variance of the average intensities # CHECK + sigma_sq_e = 2 * total_var_sums / total_i_n # average variance of the intensities # CHECK + deltaccint_st = (sigma_sq_y - (0.5 * sigma_sq_e)) / (sigma_sq_y + (0.5 * sigma_sq_e)) data = flex.double(np.mean(deltaccint_st, axis=1)) * 100 sorted_data = data.select(flex.sort_permutation(data)) From f40439b4b0b5f405fedaa70e882dd36749d30c2b Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 27 Aug 2024 17:29:09 -0700 Subject: [PATCH 670/748] Enabling using ncs in pdb_interpretation, with log output and enabled tests. --- mmtbx/monomer_library/pdb_interpretation.py | 10 +++++- .../pdb_interpretation/tst_using_ncs_1.py | 31 +++++++++++++------ .../pdb_interpretation/tst_using_ncs_2.py | 26 +++++++--------- 3 files changed, 41 insertions(+), 26 deletions(-) diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index aa7719687b..139ff85d50 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -26,6 +26,7 @@ from six.moves import cStringIO as StringIO import string import sys, os +import textwrap import time import math import numpy as np @@ -215,7 +216,7 @@ def __init__(self, residue_name, atom_name, atom_element): sort_atoms = True .type = bool .short_caption = Sort atoms in input pdb so they would be in the same order - use_ncs_to_build_restraints = False + use_ncs_to_build_restraints = True .type = bool .short_caption = Look for NCS and use it to speed up building restraints show_restraints_histograms = True @@ -3953,6 +3954,13 @@ def raise_if_corrupt(link_resolution): self.sites_cart = self.pdb_atoms.extract_xyz() # We have to expand the tables using ncs information... nrgl.setup_sets() + # get copies chain ids and output them: + cids = [] + for g in nrgl: + for c in g.copies: + cids.append(self.pdb_atoms[c.iselection[0]].parent().parent().parent().id) + print(" Restraints were copied for chains:", file=log) + print("\n".join(textwrap.wrap(", ".join(cids), initial_indent=' ', subsequent_indent=' ')), file=log) self.scattering_type_registry.expand_with_ncs(nrgl, self.pdb_hierarchy.atoms_size()) self.nonbonded_energy_type_registry.expand_with_ncs(nrgl, self.pdb_hierarchy.atoms_size()) self.geometry_proxy_registries.expand_with_ncs(nrgl, self.pdb_hierarchy.atoms_size()) diff --git a/mmtbx/regression/pdb_interpretation/tst_using_ncs_1.py b/mmtbx/regression/pdb_interpretation/tst_using_ncs_1.py index bfbfbbb55b..2de9129ae3 100644 --- a/mmtbx/regression/pdb_interpretation/tst_using_ncs_1.py +++ b/mmtbx/regression/pdb_interpretation/tst_using_ncs_1.py @@ -3,8 +3,8 @@ import iotbx.pdb import mmtbx.model import libtbx.load_env -from libtbx.utils import null_out - +from libtbx.test_utils import show_diff, assert_lines_in_text +from six.moves import cStringIO as StringIO pdb_str = """\ ATOM 1 N GLY A 1 12.928 4.612 6.102 1.00 16.77 N @@ -165,20 +165,31 @@ TER """ -def exercise_01(): - - - pdb_inp = iotbx.pdb.input(source_info=None, lines=pdb_str) - m = mmtbx.model.manager(model_input = pdb_inp, log = null_out()) +def get_geometry_stats(lines, use_ncs=True): + log_str=StringIO() + pdb_inp = iotbx.pdb.input(source_info=None, lines=lines) + m = mmtbx.model.manager(model_input = pdb_inp, log = log_str) p = m.get_default_pdb_interpretation_params() - p.pdb_interpretation.use_ncs_to_build_restraints = True - # p.pdb_interpretation.use_ncs_to_build_restraints = False + p.pdb_interpretation.use_ncs_to_build_restraints = use_ncs m.process(make_restraints=True, pdb_interpretation_params=p) + geom=StringIO() + g = m.geometry_statistics() + g.show(log=geom, exclude_protein_only_stats=True) + return geom.getvalue(), log_str.getvalue() +def exercise_01(): + geom_ncs, log_ncs=get_geometry_stats(pdb_str, True) + geom_no_ncs, log_no_ncs=get_geometry_stats(pdb_str, False) + assert not show_diff(geom_ncs, geom_no_ncs) + # assert not show_diff(log_ncs, log_no_ncs) + assert_lines_in_text(log_ncs, """ Restraints were copied for chains: + B, C +""") + # print(log_ncs) if(__name__ == "__main__"): if libtbx.env.find_in_repositories(relative_path="chem_data") is None: - print("Skipping exercise_02(): chem_data directory not available") + print("Skipping exercise_01(): chem_data directory not available") else: exercise_01() print('OK') diff --git a/mmtbx/regression/pdb_interpretation/tst_using_ncs_2.py b/mmtbx/regression/pdb_interpretation/tst_using_ncs_2.py index 25b05c5820..d3a6e7d48c 100644 --- a/mmtbx/regression/pdb_interpretation/tst_using_ncs_2.py +++ b/mmtbx/regression/pdb_interpretation/tst_using_ncs_2.py @@ -1,10 +1,8 @@ from __future__ import absolute_import, division, print_function -import iotbx.pdb -import mmtbx.model import libtbx.load_env -from libtbx.utils import null_out - +from libtbx.test_utils import show_diff, assert_lines_in_text +from mmtbx.regression.pdb_interpretation.tst_using_ncs_1 import get_geometry_stats pdb_str = """\ ATOM 1 N GLY A 1 -9.009 4.612 6.102 1.00 16.77 N @@ -455,23 +453,21 @@ ATOM 432 OH TYR h 7 11.276 7.888 12.151 1.00 14.39 O ATOM 433 OXT TYR h 7 3.684 10.298 14.830 1.00 17.49 O TER - """ def exercise_01(): - - - pdb_inp = iotbx.pdb.input(source_info=None, lines=pdb_str) - m = mmtbx.model.manager(model_input = pdb_inp, log = null_out()) - p = m.get_default_pdb_interpretation_params() - p.pdb_interpretation.use_ncs_to_build_restraints = True - # p.pdb_interpretation.use_ncs_to_build_restraints = False - m.process(make_restraints=True, pdb_interpretation_params=p) - + geom_ncs, log_ncs=get_geometry_stats(pdb_str, True) + geom_no_ncs, log_no_ncs=get_geometry_stats(pdb_str, False) + assert not show_diff(geom_ncs, geom_no_ncs) + # assert not show_diff(log_ncs, log_no_ncs) + assert_lines_in_text(log_ncs, """ Restraints were copied for chains: + X, h, B, H, R, f +""") + # print(log_ncs) if(__name__ == "__main__"): if libtbx.env.find_in_repositories(relative_path="chem_data") is None: - print("Skipping exercise_02(): chem_data directory not available") + print("Skipping exercise_01(): chem_data directory not available") else: exercise_01() print('OK') From 9323335ebc334be0cc5b4111f2638d7354aa35a2 Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Wed, 28 Aug 2024 17:40:28 -0700 Subject: [PATCH 671/748] Switch deltaccint to using unbinned data (ie overall delta cc1/2 instead of average of the delta cc1/2 bins) --- .../application/statistics/deltaccint.py | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/xfel/merging/application/statistics/deltaccint.py b/xfel/merging/application/statistics/deltaccint.py index 4e69cf2d7d..94561cd114 100644 --- a/xfel/merging/application/statistics/deltaccint.py +++ b/xfel/merging/application/statistics/deltaccint.py @@ -92,18 +92,16 @@ def run(self, experiments, reflections): diff_sq_[diff_sq_<0] = diff_sq_unmodified variance[:,hkl_idx] = diff_sq_ / (n[:,hkl_idx]-1) / n[:,hkl_idx] - # N expts (all ranks) x N bins - n_bins = resolution_binner.n_bins_used() - all_i_sums = np.zeros((len(all_expt_ids), n_bins), float) # sum of the averaged intensities - all_i_n = np.zeros((len(all_expt_ids), n_bins), int) # count of the averaged intensities - all_var_sums = np.zeros((len(all_expt_ids), n_bins), float) # sums of the variances of the intensities + # N expts (all ranks) + all_i_sums = np.zeros(len(all_expt_ids), float) # sum of the averaged intensities + all_i_n = np.zeros(len(all_expt_ids), int) # count of the averaged intensities + all_var_sums = np.zeros(len(all_expt_ids), float) # sums of the variances of the intensities # Sum up and reduce the bins for hkl in hkl_set: - bin_idx = hkl_resolution_bins[hkl] - 1 - all_i_sums [:,bin_idx] += merged[:,hkl_map[hkl]] - all_i_n [:,bin_idx] += 1 - all_var_sums[:,bin_idx] += variance[:,hkl_map[hkl]] + all_i_sums += merged[:,hkl_map[hkl]] + all_i_n += 1 + all_var_sums += variance[:,hkl_map[hkl]] # Broadcast the variances and average intensities total_i_sums = comm.allreduce(all_i_sums, op=MPI.SUM) @@ -115,24 +113,24 @@ def run(self, experiments, reflections): # First, the numerator, the difference between each hkl and the average for that hkl's bin (ommiting each experiment once) diff_sq = np.zeros(merged.shape, float) for hkl in hkl_set: - diff_sq[:,hkl_map[hkl]] = (merged[:,hkl_map[hkl]] - total_i_average[:,hkl_resolution_bins[hkl]-1]) ** 2 + diff_sq[:,hkl_map[hkl]] = (merged[:,hkl_map[hkl]] - total_i_average) ** 2 # N expts (all ranks) x N bins diff_sq_sum = np.zeros(all_i_sums.shape, float) # Complete the numerator for this rank for hkl in hkl_set: - diff_sq_sum[:,hkl_resolution_bins[hkl]-1] += diff_sq[:,hkl_map[hkl]] + diff_sq_sum += diff_sq[:,hkl_map[hkl]] total_diff_sq_sum = comm.reduce(diff_sq_sum, MPI.SUM, 0) # Report if self.mpi_helper.rank == 0: - sigma_sq_y = total_diff_sq_sum / (total_i_n-1) # variance of the average intensities # CHECK - sigma_sq_e = 2 * total_var_sums / total_i_n # average variance of the intensities # CHECK + sigma_sq_y = total_diff_sq_sum / (total_i_n-1) # variance of the average intensities + sigma_sq_e = 2 * total_var_sums / total_i_n # average variance of the intensities deltaccint_st = (sigma_sq_y - (0.5 * sigma_sq_e)) / (sigma_sq_y + (0.5 * sigma_sq_e)) - data = flex.double(np.mean(deltaccint_st, axis=1)) * 100 + data = flex.double(deltaccint_st) * 100 sorted_data = data.select(flex.sort_permutation(data)) mini, q1, med, q3, maxi = five_number_summary(data) From fdb5a2e29de823cdeb23500ff2bbe7a4e4dfa4a0 Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Wed, 28 Aug 2024 17:52:18 -0700 Subject: [PATCH 672/748] Tidy --- .../application/statistics/deltaccint.py | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/xfel/merging/application/statistics/deltaccint.py b/xfel/merging/application/statistics/deltaccint.py index 94561cd114..2ed11048b5 100644 --- a/xfel/merging/application/statistics/deltaccint.py +++ b/xfel/merging/application/statistics/deltaccint.py @@ -41,10 +41,9 @@ def run(self, experiments, reflections): # We need to compute # 1) variance of the average intensities -> compute averages of all intensities and then compute variance per bin # 2) average variance of the intensities -> compute variances of all intensities and then compute average per bin + # In reality for 2), we compute the average of the standard error of the mean squared instead of the variance (semsq) - resolution_binner = self.params.statistics.resolution_binner hkl_resolution_bins = self.params.statistics.hkl_resolution_bins - hkl_set = [hkl for hkl in set(filtered['miller_index_asymmetric']) if hkl in hkl_resolution_bins] n_hkl = len(hkl_set) hkl_map = {v: k for k, v in enumerate(hkl_set)} @@ -52,10 +51,10 @@ def run(self, experiments, reflections): expt_map = filtered.experiment_identifiers() # N expts (all ranks) x N hkl (this rank) - sums = np.zeros((len(all_expt_ids), n_hkl), float) - n = np.zeros((len(all_expt_ids), n_hkl), int) - merged = np.zeros((len(all_expt_ids), n_hkl), float) - variance = np.zeros((len(all_expt_ids), n_hkl), float) + sums = np.zeros((len(all_expt_ids), n_hkl), float) + n = np.zeros((len(all_expt_ids), n_hkl), int) + merged = np.zeros((len(all_expt_ids), n_hkl), float) + semsq = np.zeros((len(all_expt_ids), n_hkl), float) for refls in reflection_table_utils.get_next_hkl_reflection_table(reflections=filtered): hkl = refls['miller_index_asymmetric'][0] @@ -74,7 +73,7 @@ def run(self, experiments, reflections): n [expt_idx,hkl_idx] -= 1 merged[:,hkl_idx] = sums[:,hkl_idx]/n[:,hkl_idx] - # compute variance for each hkl (less the intensity from each experiment) + # compute semsq for each hkl (less the intensity from each experiment) diff_sq_ = np.full(len(all_expt_ids), -1, dtype=float) for i in range(len(refls)): @@ -90,24 +89,24 @@ def run(self, experiments, reflections): mean_intensity_unmodified = np.mean(intensity) diff_sq_unmodified = np.sum((intensity-mean_intensity_unmodified)**2) diff_sq_[diff_sq_<0] = diff_sq_unmodified - variance[:,hkl_idx] = diff_sq_ / (n[:,hkl_idx]-1) / n[:,hkl_idx] + semsq[:,hkl_idx] = diff_sq_ / (n[:,hkl_idx]-1) / n[:,hkl_idx] # N expts (all ranks) - all_i_sums = np.zeros(len(all_expt_ids), float) # sum of the averaged intensities - all_i_n = np.zeros(len(all_expt_ids), int) # count of the averaged intensities - all_var_sums = np.zeros(len(all_expt_ids), float) # sums of the variances of the intensities + all_i_sums = np.zeros(len(all_expt_ids), float) # sum of the averaged intensities + all_i_n = np.zeros(len(all_expt_ids), int) # count of the averaged intensities + all_semsq_sums = np.zeros(len(all_expt_ids), float) # sums of the semsq of the intensities # Sum up and reduce the bins for hkl in hkl_set: - all_i_sums += merged[:,hkl_map[hkl]] - all_i_n += 1 - all_var_sums += variance[:,hkl_map[hkl]] + all_i_sums += merged[:,hkl_map[hkl]] + all_i_n += 1 + all_semsq_sums += semsq[:,hkl_map[hkl]] - # Broadcast the variances and average intensities - total_i_sums = comm.allreduce(all_i_sums, op=MPI.SUM) - total_i_n = comm.allreduce(all_i_n, op=MPI.SUM) - total_var_sums = comm.reduce(all_var_sums, op=MPI.SUM) - total_i_average = total_i_sums / total_i_n + # Broadcast the semsq and average intensities + total_i_sums = comm.allreduce(all_i_sums, op=MPI.SUM) + total_i_n = comm.allreduce(all_i_n, op=MPI.SUM) + total_semsq_sums = comm.reduce(all_semsq_sums, op=MPI.SUM) + total_i_average = total_i_sums / total_i_n # Compute the variance of the average intensities # First, the numerator, the difference between each hkl and the average for that hkl's bin (ommiting each experiment once) @@ -127,7 +126,7 @@ def run(self, experiments, reflections): # Report if self.mpi_helper.rank == 0: sigma_sq_y = total_diff_sq_sum / (total_i_n-1) # variance of the average intensities - sigma_sq_e = 2 * total_var_sums / total_i_n # average variance of the intensities + sigma_sq_e = 2 * total_semsq_sums / total_i_n # average semsq of the intensities deltaccint_st = (sigma_sq_y - (0.5 * sigma_sq_e)) / (sigma_sq_y + (0.5 * sigma_sq_e)) data = flex.double(deltaccint_st) * 100 From 6daf607a18b90ee17b820303dc7f5206a3c56982 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 28 Aug 2024 20:47:36 -0700 Subject: [PATCH 673/748] CI: continue if SSH key already added [skip ci] --- .azure-pipelines/templates/download-data-cache.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.azure-pipelines/templates/download-data-cache.yml b/.azure-pipelines/templates/download-data-cache.yml index 39be342785..020dc21951 100644 --- a/.azure-pipelines/templates/download-data-cache.yml +++ b/.azure-pipelines/templates/download-data-cache.yml @@ -11,6 +11,7 @@ steps: sshPublicKey: ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA7XgVgdU9GmZuo5yVyW/htrAuxe7ypuq7IowWwfUC0WZw9SPzQ8kOGj63plF3ytx/qpgvUlS1AiywO20rZ83gHmRdAiuvt9laH09KlWEUhIhAQTzesqBG5aUT0MKo01yxijoRl5HC8w/MdOanc0h01e6IxnZvgG0N30RB1i4xVPCtR/VBmXSp4R0T+Q/gJjfQssuBxHVMrrute4V3uUHek58FL2QgUB0+zq6ipETjuCJxTSyYVAFtCYDPYs+0lAYYkWrXALCr9kX9s22jYtkyv5kNw6mEW8nhtA7GbTdJLv4M6/WYtcvQV8TDcNCfltOfl81U3gcZ9zhQDKGVoNaJEw== buildbot@cci.lbl.gov sshKeySecureFile: id_rsa displayName: Download SSH key + continueOnError: true - task: DownloadPipelineArtifact@2 inputs: From 136b35b0ac74dacb4320c4cf88ce2ae7cbb1097a Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Thu, 29 Aug 2024 11:08:27 -0700 Subject: [PATCH 674/748] Make generating experiment identifiers more constant Instead of using the full path as part of the input to the hash function, use the base name. This means XFEL CI should pass when checking out xfel_regression on different computers in cases when the identifiers are missing and need to be generated. --- xfel/merging/application/input/file_loader.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xfel/merging/application/input/file_loader.py b/xfel/merging/application/input/file_loader.py index c4507d2b4f..9360fbad30 100644 --- a/xfel/merging/application/input/file_loader.py +++ b/xfel/merging/application/input/file_loader.py @@ -15,12 +15,12 @@ def create_experiment_identifier(experiment, experiment_file_path, experiment_id): 'Create a hashed experiment identifier based on the experiment file path, experiment index in the file, and experiment features' import hashlib - exp_identifier_str = experiment_file_path + \ + exp_identifier_str = os.path.basename(experiment_file_path + \ str(experiment_id) + \ str(experiment.beam) + \ str(experiment.crystal) + \ str(experiment.detector) + \ - ''.join(experiment.imageset.paths()) + ''.join([os.path.basename(p) for p in experiment.imageset.paths()])) hash_obj = hashlib.md5(exp_identifier_str.encode('utf-8')) return hash_obj.hexdigest() From 5f4a50162abd9c5fa346749132563efcb57fe2b7 Mon Sep 17 00:00:00 2001 From: Aaron Brewster Date: Thu, 29 Aug 2024 15:05:09 -0700 Subject: [PATCH 675/748] Add verbose option for deltaccint [skip ci] --- xfel/merging/application/phil/phil.py | 3 +++ xfel/merging/application/statistics/deltaccint.py | 11 ++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/xfel/merging/application/phil/phil.py b/xfel/merging/application/phil/phil.py index 04a935c20c..cc9895b3cb 100644 --- a/xfel/merging/application/phil/phil.py +++ b/xfel/merging/application/phil/phil.py @@ -653,6 +653,9 @@ .help = compute the IQR of these CC½s. Remove all lattices whose contribution degrades CC½ by more than .help = IQR * iqr_ratio above the median. You can discover a good IQR by running the program once, .help = examining the log file where possible values are listed, and running it again with the best value. + verbose = False + .type = bool + .help = If True, include the ΔCC½ for every lattice in the main log. } predictions_to_edge { apply = False diff --git a/xfel/merging/application/statistics/deltaccint.py b/xfel/merging/application/statistics/deltaccint.py index 2ed11048b5..11a6393ad3 100644 --- a/xfel/merging/application/statistics/deltaccint.py +++ b/xfel/merging/application/statistics/deltaccint.py @@ -29,7 +29,9 @@ def run(self, experiments, reflections): if len(set(refls['id'])) >= min_mult: filtered.extend(refls) - all_expt_ids = sorted(set(itertools.chain.from_iterable(comm.allgather(filtered.experiment_identifiers().values())))) + expt_map = filtered.experiment_identifiers() + + all_expt_ids = sorted(set(itertools.chain.from_iterable(comm.allgather(expt_map.values())))) all_expts_map = {v: k for k, v in enumerate(all_expt_ids)} if self.mpi_helper.rank == 0: @@ -48,8 +50,6 @@ def run(self, experiments, reflections): n_hkl = len(hkl_set) hkl_map = {v: k for k, v in enumerate(hkl_set)} - expt_map = filtered.experiment_identifiers() - # N expts (all ranks) x N hkl (this rank) sums = np.zeros((len(all_expt_ids), n_hkl), float) n = np.zeros((len(all_expt_ids), n_hkl), int) @@ -141,6 +141,11 @@ def run(self, experiments, reflections): self.logger.main_log("% 8.4f%% max"%maxi) self.logger.main_log("") + if self.params.statistics.deltaccint.verbose: + self.logger.main_log("Showing ΔCC½ for all lattices") + for e, identifier in enumerate(all_expt_ids): + self.logger.main_log("%s %f"%(identifier, data[e])) + n_worst = min(len(data), 30) worst = sorted_data[-n_worst:] iqr = q3-q1 From db0e4250fb22f94ead693717eb757ce0547e1d2c Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Mon, 26 Aug 2024 14:59:54 -0700 Subject: [PATCH 676/748] turn off RNA pucker restraints option --- mmtbx/monomer_library/pdb_interpretation.py | 5 +++++ mmtbx/monomer_library/rna_sugar_pucker_analysis.py | 3 +++ 2 files changed, 8 insertions(+) diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index 139ff85d50..7626bd7857 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -1299,6 +1299,7 @@ def _rna_sugar_pucker_analysis(self, params, next_pdb_residue): if (ra1.problems is not None): return self.is_rna_dna = True if (not ra1.is_rna): return + if not params.enable: return residue_2_p_atom = None if (next_pdb_residue is not None): residue_2_p_atom = next_pdb_residue.find_atom_by(name=" P ") @@ -2727,6 +2728,10 @@ def _get_next_residue(): self.type_h_bonds[atom.i_seq] = None raise Sorry('Not able to determine energy type for atom %s' % atom.quote()) # + if (mm.monomer is None): + # try to get restraints from e tu + pass + # if (mm.monomer is None): def use_scattering_type_if_available_to_define_nonbonded_type(): if ( residue.atoms_size() != 1 diff --git a/mmtbx/monomer_library/rna_sugar_pucker_analysis.py b/mmtbx/monomer_library/rna_sugar_pucker_analysis.py index 2070c318bc..fdbc344f46 100644 --- a/mmtbx/monomer_library/rna_sugar_pucker_analysis.py +++ b/mmtbx/monomer_library/rna_sugar_pucker_analysis.py @@ -28,6 +28,9 @@ .type = float bond_detection_distance_tolerance = 0.5 .type = float + enable = True + .type = bool + .style = hidden """) class evaluate(slots_getstate_setstate): From 9ca4b765c404853af70948f4e1bde1bdda01f26d Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 29 Aug 2024 15:17:00 -0700 Subject: [PATCH 677/748] adding mahalanobis distance --- .gitignore | 2 + libtbx/math_utils.py | 45 ++++++++++++++++ libtbx/tst_mahalanobis.py | 110 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 libtbx/tst_mahalanobis.py diff --git a/.gitignore b/.gitignore index 337074773b..3b17754062 100644 --- a/.gitignore +++ b/.gitignore @@ -69,3 +69,5 @@ mmtbx/suitename/test/ mmtbx/suitename/suitename.stderr.log mmtbx/suitename/assist/ mmtbx/suitename/*.show.txt + +*sublime* diff --git a/libtbx/math_utils.py b/libtbx/math_utils.py index af39a0d497..2ceb1fc15e 100644 --- a/libtbx/math_utils.py +++ b/libtbx/math_utils.py @@ -269,3 +269,48 @@ def percentile_based_spread_with_selection(values, pbs_fraction=0.608, else: high = working return last_value + +def mahalanobis_using_sklearn(x=None, data=None, cov=None, verbose=False): + if cov is None: + cov = covariance_using_sklearn(data, verbose=verbose) + mahal_cov = cov.mahalanobis(x) + if verbose: print(mahal_cov) + return mahal_cov + +def covariance_using_sklearn(data=None, values=None, verbose=False): + from sklearn.covariance import EmpiricalCovariance, MinCovDet + if values: + assert 0 + cov=EmpiricalCovariance() + cov.covariance_=values + return cov + # fit a MCD robust estimator to data + robust_cov = MinCovDet().fit(data) + # fit a MLE estimator to data + emp_cov = EmpiricalCovariance().fit(data) + if verbose: + print( + "Estimated covariance matrix:\nMCD (Robust):\n{}\nMLE:\n{}".format( + robust_cov.covariance_, emp_cov.covariance_ + ) + ) + # choose one + cov = emp_cov + return cov + +def mahalanobis_p_values_outlier_indices(x=None, data=None, cov=None): + rc = mahalanobis_p_values(x=x, data=data, cov=cov) + return list(filter(lambda x: rc[x] <0.01, range(len(rc)))) + +def mahalanobis_p_values(x=None, data=None, cov=None, verbose=False): + from scipy.stats import chi2 + df=len(x[0])-1 + if verbose: + print(chi2.ppf((1-0.01), df=df)) + #> 9.21 + mahal_cov = mahalanobis_using_sklearn(x=x, data=data, cov=cov) + if verbose: print(mahal_cov) + return(1 - chi2.cdf(mahal_cov, df)) + +def mahalanobis(x=None, data=None, mu=None, cov=None): + return mahalanobis_using_sklearn(x=x, data=data, cov=cov) diff --git a/libtbx/tst_mahalanobis.py b/libtbx/tst_mahalanobis.py new file mode 100644 index 0000000000..d547ac5b65 --- /dev/null +++ b/libtbx/tst_mahalanobis.py @@ -0,0 +1,110 @@ +from __future__ import division +from io import StringIO + +diamonds_short = '''"carat","cut","color","clarity","depth","table","price","x","y","z" +0.23,"Ideal","E","SI2",61.5,55,326,3.95,3.98,2.43 +0.21,"Premium","E","SI1",59.8,61,326,3.89,3.84,2.31 +0.23,"Good","E","VS1",56.9,65,327,4.05,4.07,2.31 +0.29,"Premium","I","VS2",62.4,58,334,4.2,4.23,2.63 +0.31,"Good","J","SI2",63.3,58,335,4.34,4.35,2.75 +0.24,"Very Good","J","VVS2",62.8,57,336,3.94,3.96,2.48 +0.24,"Very Good","I","VVS1",62.3,57,336,3.95,3.98,2.47 +0.26,"Very Good","H","SI1",61.9,55,337,4.07,4.11,2.53 +0.22,"Fair","E","VS2",65.1,61,337,3.87,3.78,2.49 +0.23,"Very Good","H","VS1",59.4,61,338,4,4.05,2.39 +0.3,"Good","J","SI1",64,55,339,4.25,4.28,2.73 +0.23,"Ideal","J","VS1",62.8,56,340,3.93,3.9,2.46 +0.22,"Premium","F","SI1",60.4,61,342,3.88,3.84,2.33 +0.31,"Ideal","J","SI2",62.2,54,344,4.35,4.37,2.71 +0.2,"Premium","E","SI2",60.2,62,345,3.79,3.75,2.27 +0.32,"Premium","E","I1",60.9,58,345,4.38,4.42,2.68 +0.3,"Ideal","I","SI2",62,54,348,4.31,4.34,2.68 +0.3,"Good","J","SI1",63.4,54,351,4.23,4.29,2.7 +0.3,"Good","J","SI1",63.8,56,351,4.23,4.26,2.71 +''' + +def mahalanobis_using_numpy_and_scipy(x=None, data=None, mu=None, cov=None): + """ + Compute the Mahalanobis Distance between each row of x and the data + x : vector or matrix of data with, say, p columns. + data : ndarray of the distribution from which Mahalanobis distance of each + observation of x is to be computed. + cov : covariance matrix (p x p) of the distribution. If None, will be + computed from data. + """ + # error prone + assert 0 + import numpy as np + import scipy as sp + if mu: + x_minus_mu = x - mu + else: + print(x) + print(np.mean(data)) + x_minus_mu = x - np.mean(data) + print('x_minus_mu',x_minus_mu) + if not cov: cov = np.cov(data) + print(cov) + inv_covmat = sp.linalg.inv(cov) + print(inv_covmat) + left_term = np.dot(x_minus_mu, inv_covmat) + mahal = np.dot(left_term, x_minus_mu.T) + return mahal.diagonal() + +def main(): + from libtbx import math_utils + import csv + data=[] + f=StringIO(diamonds_short) + spamreader = csv.reader(f, delimiter=',', quotechar='|') + for i, row in enumerate(spamreader): + if not i: continue + # print(', '.join(row)) + data.append([float(row[0]), float(row[4]), float(row[6])]) + + zz=[(0.23, 61.5, 326), + (0.23, 56.9, 329), + (0.23, 56.9, 349), + ] + + rc=math_utils.mahalanobis(zz, data) + print(rc) + rc=math_utils.mahalanobis_p_values(zz, data, verbose=True) + print(rc) + rc=math_utils.mahalanobis_p_values_outlier_indices(zz, data) + assert rc==[2] + for i, p in enumerate(math_utils.mahalanobis_p_values(zz, data)): + outlier='' + if i in rc: + outlier='OUTLIER' + print(' %s %0.4f %s' % (i,p,outlier)) + cov = math_utils.covariance_using_sklearn(data, verbose=True) + rc=math_utils.mahalanobis(zz, cov=cov) + print(rc) + rc=math_utils.mahalanobis_p_values(zz, cov=cov, verbose=True) + print(rc) + rc=math_utils.mahalanobis_p_values_outlier_indices(zz, cov=cov) + assert rc==[2] + rc=math_utils.mahalanobis_p_values_outlier_indices(zz[:1], cov=cov) + print(rc) + + # values = cov.covariance_.tolist() + # cov = math_utils.covariance_using_sklearn(values=values, verbose=True) + # assert 0 + from libtbx import easy_pickle + easy_pickle.dump('tst_mahal.pickle', cov) + cov=easy_pickle.load('tst_mahal.pickle') + # import pickle + # pf='tst_mahal.pickle' + # f=open(pf, 'w') + # pickle.dump(cov, f) + # del f + # f=open(pf, 'r') + # cov=pickle.load(f) + # del f + rc=math_utils.mahalanobis_p_values_outlier_indices(zz, cov=cov) + print(rc) + assert rc==[2] + +if __name__ == '__main__': + main() From 256502b90b7163b370840bd49cc5373162c2ffac Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 30 Aug 2024 10:25:20 -0700 Subject: [PATCH 678/748] Declutter Phenix: archive cl dispatcher mp_validate_bonds --- mmtbx/command_line/mp_validate_bonds.py | 43 ------------- mmtbx/programs/mp_validate_bonds.py | 82 ------------------------- 2 files changed, 125 deletions(-) delete mode 100644 mmtbx/command_line/mp_validate_bonds.py delete mode 100644 mmtbx/programs/mp_validate_bonds.py diff --git a/mmtbx/command_line/mp_validate_bonds.py b/mmtbx/command_line/mp_validate_bonds.py deleted file mode 100644 index aad4a60a33..0000000000 --- a/mmtbx/command_line/mp_validate_bonds.py +++ /dev/null @@ -1,43 +0,0 @@ -# LIBTBX_SET_DISPATCHER_NAME phenix.mp_validate_bonds -# LIBTBX_SET_DISPATCHER_NAME molprobity.mp_validate_bonds - -from __future__ import absolute_import, division, print_function -import sys -from iotbx.cli_parser import CCTBXParser -from libtbx.utils import multi_out, show_total_time -from mmtbx.programs import mp_validate_bonds -from iotbx.cli_parser import run_program - -def old_run(args, out=sys.stdout, quiet=False): - # create parser - logger = multi_out() - logger.register('stderr', sys.stderr) - logger2 = multi_out() - logger2.register('stdout', sys.stdout) - - parser = CCTBXParser( - program_class=mp_validate_bonds.Program, - logger=logger) - namespace = parser.parse_args(sys.argv[1:]) - - # start program - print('Starting job', file=logger) - print('='*79, file=logger) - task = mp_validate_bonds.Program( - parser.data_manager, parser.working_phil.extract(), logger=logger2) - - # validate inputs - task.validate() - - # run program - task.run() - - # stop timer - print('', file=logger) - print('='*79, file=logger) - print('Job complete', file=logger) - show_total_time(out=logger) - -if (__name__ == "__main__"): - #run(sys.argv[1:]) - run_program(program_class=mp_validate_bonds.Program, hide_parsing_output=True) diff --git a/mmtbx/programs/mp_validate_bonds.py b/mmtbx/programs/mp_validate_bonds.py deleted file mode 100644 index ff409009d9..0000000000 --- a/mmtbx/programs/mp_validate_bonds.py +++ /dev/null @@ -1,82 +0,0 @@ -from __future__ import absolute_import, division, print_function - -import os -from mmtbx.model import manager -from libtbx.program_template import ProgramTemplate -from libtbx.utils import null_out -import json -from mmtbx.validation.mp_validate_bonds import mp_validate_bonds -from datetime import datetime - -class Program(ProgramTemplate): - prog = os.getenv('LIBTBX_DISPATCHER_NAME') - description="""\ -%(prog)s file.pdb [params.eff] [options ...] - -Options: - - model=input_file input PDB file - outliers_only=False only print outliers - json=False Outputs results as JSON compatible dictionary - use_cdl=True Use the Conformational Dependent Library (cdl) for reference values - verbose=False verbose text output - -Example: - - %(prog)s model=1ubq.pdb outliers_only=True -""" % locals() - - master_phil_str = """ - include scope mmtbx.validation.molprobity_cmdline_phil_str - show_errors = False - .type = bool - .help = '''Print out errors''' - json = False - .type = bool - .help = "Prints results as JSON format dictionary" - use_cdl = True - .type = bool - .help = "Use conformational dependent library for reference values" - use_parent = False - .type = bool - """ - datatypes = ['model','phil'] - data_manager_options = ['model_skip_expand_with_mtrix'] - known_article_ids = ['molprobity'] - - def validate(self): - self.data_manager.has_models(raise_sorry=True) - - def run(self): - model = self.data_manager.get_model() - model.set_stop_for_unknowns(False) - hierarchy = model.get_hierarchy() - self.info_json = {"model_name":self.data_manager.get_default_model_name(), - "time_analyzed": str(datetime.now()), - "params": {"use_cdl":self.params.use_cdl, - "outliers_only":self.params.outliers_only, - }} - p = manager.get_default_pdb_interpretation_params() - ##print(dir(p.pdb_interpretation)) - p.pdb_interpretation.allow_polymer_cross_special_position=True - p.pdb_interpretation.flip_symmetric_amino_acids=False - p.pdb_interpretation.clash_guard.nonbonded_distance_threshold = None - p.pdb_interpretation.restraints_library.cdl=self.params.use_cdl - model.set_log(log = null_out()) - model.process(make_restraints=True, pdb_interpretation_params=p) - geometry = model.get_restraints_manager().geometry - atoms = hierarchy.atoms() - self.results = mp_validate_bonds( - pdb_hierarchy=hierarchy, - geometry_restraints_manager=geometry, - outliers_only=self.params.outliers_only) - if self.params.json: - print(self.results.as_JSON(addon_json=self.info_json), file=self.logger) - elif self.params.verbose: - self.results.show(out=self.logger, verbose=True) - - def get_results(self): - return self.results - - def get_results_as_JSON(self): - return self.results.as_JSON(self.info_json) From c2df187782bbb252692c37b71fa6694eceb923fc Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Fri, 30 Aug 2024 10:53:39 -0700 Subject: [PATCH 679/748] CI: add geostd to data cache download [skip ci] --- .../templates/download-data-cache.yml | 32 ++++++++++++++----- .../templates/update-data-cache.yml | 1 + 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/.azure-pipelines/templates/download-data-cache.yml b/.azure-pipelines/templates/download-data-cache.yml index 020dc21951..2dd5fae2bc 100644 --- a/.azure-pipelines/templates/download-data-cache.yml +++ b/.azure-pipelines/templates/download-data-cache.yml @@ -1,8 +1,8 @@ -# Template for updating data cache artifacts +# Template for downloading data cache artifacts # - chem_data +# - geostd # - phenix_regression # - phenix_examples -# A ssh_config secure file is needed steps: - task: InstallSSHKey@0 @@ -13,6 +13,7 @@ steps: displayName: Download SSH key continueOnError: true +# chem_data - task: DownloadPipelineArtifact@2 inputs: source: 'specific' @@ -23,12 +24,6 @@ steps: displayName: Download chem_data - script: | - if [ ! -d "$(Pipeline.Workspace)/modules/chem_data" ]; then - cd $(Pipeline.Workspace)/modules - git clone https://gitlab.com/phenix_project/chem_data.git - git lfs install --local - git lfs pull - fi cd $(Pipeline.Workspace)/modules/chem_data git reset --hard origin/main git lfs install --local @@ -37,6 +32,26 @@ steps: displayName: Update chem_data continueOnError: true +# geostd (in chem_data) +- task: DownloadPipelineArtifact@2 + inputs: + source: 'specific' + project: '$(resources.pipeline.data_cache.projectID)' + pipeline: '$(resources.pipeline.data_cache.pipelineID)' + allowPartiallySucceededBuilds: true + artifact: 'geostd' + path: $(Pipeline.Workspace)/modules/chem_data/geostd + displayName: Download geostd + continueOnError: true + +- script: | + cd $(Pipeline.Workspace)/modules/chem_data/geostd + git reset --hard origin/master + git pull --rebase + displayName: Update geostd + continueOnError: true + +# phenix_regression - task: DownloadPipelineArtifact@2 inputs: source: 'specific' @@ -55,6 +70,7 @@ steps: displayName: Update phenix_regression continueOnError: true +# phenix_examples - task: DownloadPipelineArtifact@2 inputs: source: 'specific' diff --git a/.azure-pipelines/templates/update-data-cache.yml b/.azure-pipelines/templates/update-data-cache.yml index 50e7af6e18..4ced0b3134 100644 --- a/.azure-pipelines/templates/update-data-cache.yml +++ b/.azure-pipelines/templates/update-data-cache.yml @@ -3,6 +3,7 @@ # is required to prevent Azure Pipelines from deleting the .git directory. # when creating the artifact. # - miniforge +# - mambaforge # - chem_data # - geostd # - phenix_regression From 63e38989cb0e038a8d302bbbaa24a255aeb569c3 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 30 Aug 2024 11:45:41 -0700 Subject: [PATCH 680/748] Declutter Phenix: remove model_vs_sequence cl tool --- mmtbx/command_line/model_vs_sequence.py | 76 ----------------------- mmtbx/regression/tst_model_vs_sequence.py | 20 ------ mmtbx/run_tests.py | 1 - 3 files changed, 97 deletions(-) delete mode 100644 mmtbx/command_line/model_vs_sequence.py delete mode 100644 mmtbx/regression/tst_model_vs_sequence.py diff --git a/mmtbx/command_line/model_vs_sequence.py b/mmtbx/command_line/model_vs_sequence.py deleted file mode 100644 index f8ef4981b5..0000000000 --- a/mmtbx/command_line/model_vs_sequence.py +++ /dev/null @@ -1,76 +0,0 @@ -from __future__ import absolute_import, division, print_function -# LIBTBX_SET_DISPATCHER_NAME mmtbx.model_vs_sequence -# LIBTBX_SET_DISPATCHER_NAME phenix.model_vs_sequence - -import mmtbx.validation.sequence -from libtbx.utils import Sorry, Usage -import libtbx.phil -import os -import sys - -master_phil = libtbx.phil.parse(""" -input - .style = auto_align -{ - pdb_file = None - .type = path - .style = file_type:pdb input_file - seq_file = None - .type = path - .style = file_type:seq input_file -} -include scope mmtbx.validation.sequence.master_phil -""", process_includes=True) - -def run(args=(), params=None, out=None): - if (out is None): - out = sys.stdout - if (len(args) == 0) and (params is None): - raise Usage("""\ -phenix.model_vs_sequence model.pdb sequence.fa - -Verify the sequence of each chain in a PDB file to detect residue mismatches -and other inconsistencies (similar to validation upon PDB deposition).""") - import iotbx.phil - cmdline = iotbx.phil.process_command_line_with_files( - args=args, - master_phil=master_phil, - pdb_file_def="input.pdb_file", - seq_file_def="input.seq_file") - params = cmdline.work.extract() - try : - validate_params(params) - except Sorry as e : - print(e) - raise Usage("phenix.model_vs_sequence model.pdb sequence.fa") - import mmtbx.validation.sequence - from iotbx.file_reader import any_file - import iotbx.pdb - pdb_in = iotbx.pdb.input(params.input.pdb_file) - seq_in = any_file(params.input.seq_file, force_type="seq") - seq_in.check_file_type("seq") - pdb_hierarchy = pdb_in.construct_hierarchy() - sequences = seq_in.file_object - if (len(sequences) == 0): - raise Sorry("There don't appear to be any valid sequences in %s!" % - params.input.seq_file) - v = mmtbx.validation.sequence.validation( - pdb_hierarchy=pdb_hierarchy, - sequences=sequences, - params=params, - log=out) - v.show(out=out) - -def validate_params(params): - if (params.input.pdb_file is None): - raise Sorry("No PDB file specified.") - elif (not os.path.isfile(params.input.pdb_file)): - raise Sorry("'%s' is not a file." % params.input.pdb_file) - elif (params.input.seq_file is None): - raise Sorry("No sequence file specified.") - elif (not os.path.isfile(params.input.seq_file)): - raise Sorry("'%s' is not a file." % params.input.seq_file) - return True - -if (__name__ == "__main__"): - run(sys.argv[1:]) diff --git a/mmtbx/regression/tst_model_vs_sequence.py b/mmtbx/regression/tst_model_vs_sequence.py deleted file mode 100644 index 44e5b2c5df..0000000000 --- a/mmtbx/regression/tst_model_vs_sequence.py +++ /dev/null @@ -1,20 +0,0 @@ -from __future__ import absolute_import, division, print_function - -import libtbx.load_env -import os.path -from libtbx import easy_run - -def run(): - """ - Just make sure it runs. - """ - pdb_fname = libtbx.env.find_in_repositories( - relative_path="mmtbx/regression/pdbs/p9.pdb", test=os.path.isfile) - seq_filename = "tst_model_vs_sequence_seq.fa" - assert not easy_run.call("iotbx.pdb_as_fasta %s output_file=%s" % (pdb_fname, seq_filename)) - cmd = "mmtbx.model_vs_sequence %s %s" % (pdb_fname, seq_filename) - print(cmd) - assert not easy_run.call(cmd) - -if (__name__ == "__main__"): - run() diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index 8adab233ea..b5cb6130f4 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -440,7 +440,6 @@ "$D/regression/tst_statistics_output.py", "$D/regression/tst_geo_min_restraints_phil.py", "$D/regression/tst_model_vs_map.py", - "$D/regression/tst_model_vs_sequence.py", # validation/molprobity "$D/validation/regression/tst_molprobity_1.py", "$D/validation/regression/tst_molprobity_4.py", From 2ac3b127c2270fae18c365df855e5d4c1e458825 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Fri, 30 Aug 2024 12:02:21 -0700 Subject: [PATCH 681/748] update from CC --- iotbx/pdb/modified_aa_names.h | 8 +++++++- iotbx/pdb/modified_aa_names.py | 8 +++++++- iotbx/pdb/modified_rna_dna_names.h | 2 +- iotbx/pdb/modified_rna_dna_names.py | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/iotbx/pdb/modified_aa_names.h b/iotbx/pdb/modified_aa_names.h index 18580be38c..cebae451f8 100644 --- a/iotbx/pdb/modified_aa_names.h +++ b/iotbx/pdb/modified_aa_names.h @@ -5,7 +5,7 @@ This file is generated by the following procedure: phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Tue Jul 30 14:45:49 2024 +The date of file generation: Fri Aug 30 11:46:00 2024 */ #include @@ -475,6 +475,8 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "A1ADY", "A1ADZ", "A1AQ4", + "A1D9H", + "A1IJ4", "A5R", "A66", "A67", @@ -899,9 +901,13 @@ namespace iotbx { namespace pdb { namespace common_residue_names { "Q3S", "Q78", "QAC", + "QDD", "QQB", "QRG", + "QUJ", "QUK", + "QVE", + "QVS", "QWE", "QXV", "R00", diff --git a/iotbx/pdb/modified_aa_names.py b/iotbx/pdb/modified_aa_names.py index d5175e39a2..bdc746b391 100644 --- a/iotbx/pdb/modified_aa_names.py +++ b/iotbx/pdb/modified_aa_names.py @@ -7,7 +7,7 @@ phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Tue Jul 30 14:45:49 2024 +The date of file generation: Fri Aug 30 11:46:00 2024 """ from __future__ import absolute_import, division, print_function @@ -473,6 +473,8 @@ "A1ADY" : "?", "A1ADZ" : "?", "A1AQ4" : "?", + "A1D9H" : "?", + "A1IJ4" : "?", "A5R" : "?", "A66" : "?", "A67" : "?", @@ -897,9 +899,13 @@ "Q3S" : "?", "Q78" : "?", "QAC" : "?", + "QDD" : "?", "QQB" : "?", "QRG" : "?", + "QUJ" : "?", "QUK" : "?", + "QVE" : "?", + "QVS" : "?", "QWE" : "?", "QXV" : "?", "R00" : "?", diff --git a/iotbx/pdb/modified_rna_dna_names.h b/iotbx/pdb/modified_rna_dna_names.h index 5de48746c1..f5fbaa5ecc 100644 --- a/iotbx/pdb/modified_rna_dna_names.h +++ b/iotbx/pdb/modified_rna_dna_names.h @@ -5,7 +5,7 @@ This file is generated by the following procedure: phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Tue Jul 30 14:45:49 2024 +The date of file generation: Fri Aug 30 11:46:00 2024 */ #include diff --git a/iotbx/pdb/modified_rna_dna_names.py b/iotbx/pdb/modified_rna_dna_names.py index fab3acac13..014a24bdb6 100644 --- a/iotbx/pdb/modified_rna_dna_names.py +++ b/iotbx/pdb/modified_rna_dna_names.py @@ -7,7 +7,7 @@ phenix.python elbow/elbow/scripts/process_amino_acid_parentage_from_chemical_componts.py This file is intended to be generated monthly. -The date of file generation: Tue Jul 30 14:45:49 2024 +The date of file generation: Fri Aug 30 11:46:00 2024 """ from __future__ import absolute_import, division, print_function From 4fa059925d0a09a918113f3e32d5d6eceea3e63b Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Fri, 30 Aug 2024 12:02:40 -0700 Subject: [PATCH 682/748] mostly updates to test --- libtbx/math_utils.py | 5 +- libtbx/tst_mahalanobis.py | 192 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 187 insertions(+), 10 deletions(-) diff --git a/libtbx/math_utils.py b/libtbx/math_utils.py index 2ceb1fc15e..ab6d25d763 100644 --- a/libtbx/math_utils.py +++ b/libtbx/math_utils.py @@ -137,7 +137,7 @@ def next_permutation(seq): sequences. Permutes the current sequence into the next one of this set. Returns true if there are more sequences to generate. If the sequence is the largest of the set, the smallest is generated and false returned. -""" + """ if (len(seq) <= 1): return False i = len(seq) - 1 while True: @@ -237,8 +237,7 @@ def percentile_based_spread_with_sort(values, pbs_fraction=0.608): x_frac = x_low + (frac_delta * (x_high - x_low)) return x_frac -def percentile_based_spread_with_selection(values, pbs_fraction=0.608, - tolerance = 0.0001): +def percentile_based_spread_with_selection(values, pbs_fraction=0.608, tolerance = 0.0001): """ See Pozharski (2010) Acta. Cryst. D66, 970-978. The default value of the pbs_fraction parameter is for 3D geometries, and should be adjusted as diff --git a/libtbx/tst_mahalanobis.py b/libtbx/tst_mahalanobis.py index d547ac5b65..696a8b56d9 100644 --- a/libtbx/tst_mahalanobis.py +++ b/libtbx/tst_mahalanobis.py @@ -23,6 +23,154 @@ 0.3,"Good","J","SI1",63.8,56,351,4.23,4.26,2.71 ''' +zz=[(0.23, 61.5, 326), + (0.23, 56.9, 329), + (0.23, 56.9, 349), + ] + +def mahalanobis_using_pandas(): + import numpy as np + import pandas as pd + import scipy as stats + from scipy.stats import chi2 + + # calculateMahalanobis Function to calculate + # the Mahalanobis distance + def calculateMahalanobis(y=None, data=None, cov=None): + + y_mu = y - np.mean(data) + print(data) + print(y) + print(y_mu) + if not cov: + cov = np.cov(data.values.T) + print(cov) + inv_covmat = np.linalg.inv(cov) + left = np.dot(y_mu, inv_covmat) + mahal = np.dot(left, y_mu.T) + return mahal.diagonal() + + # data + data = { 'Price': [100000, 800000, 650000, 700000, + 860000, 730000, 400000, 870000, + 780000, 400000], + 'Distance': [16000, 60000, 300000, 10000, + 252000, 350000, 260000, 510000, + 2000, 5000], + 'Emission': [300, 400, 1230, 300, 400, 104, + 632, 221, 142, 267], + 'Performance': [60, 88, 90, 87, 83, 81, 72, + 91, 90, 93], + 'Mileage': [76, 89, 89, 57, 79, 84, 78, 99, + 97, 99] + } + + # Creating dataset + df = pd.DataFrame(data,columns=['Price', 'Distance', + 'Emission','Performance', + 'Mileage']) + + # Creating a new column in the dataframe that holds + # the Mahalanobis distance for each row + data = { 'Price': [100000], + 'Distance': [60000], + 'Emission': [104, + ], + 'Performance': [ 87], + 'Mileage': [99] + } + y=pd.DataFrame(data,columns=['Price', 'Distance', + 'Emission','Performance', + 'Mileage']) + rc = calculateMahalanobis(y=y, data=df[[ + 'Price', 'Distance', 'Emission','Performance', 'Mileage']]) + print(rc) + + # calculate p-value for each mahalanobis distance + rc = 1 - chi2.cdf(rc, 4) + print(rc) + + # display first five rows of dataframe + print(df) + assert 0 + +def another_pandas(): + import numpy as np + + def mahalanobis(x, y, cov=None): + x_mean = np.mean(x,0) + Covariance = np.cov(np.transpose(y)) + inv_covmat = np.linalg.inv(Covariance) + x_minus_mn = x - x_mean + D_square = np.dot(np.dot(x_minus_mn, inv_covmat), np.transpose(x_minus_mn)) + return D_square.diagonal() + + import pandas as pd + + # filepath = 'https://raw.githubusercontent.com/selva86/datasets/master/diamonds.csv' + filepath='diamonds_short.csv' + f=open(filepath, 'w') + f.write(diamonds_short) + del f + df = pd.read_csv(filepath).iloc[:, [0,4,6]] + df.head() + + #"carat","cut","color","clarity","depth","table","price","x","y","z" + data = { 'carat': [], + 'depth': [], + 'price': [] + } + for i in range(len(zz)): + print(i,zz[i]) + data['carat'].append(zz[i][0]) + data['depth'].append(zz[i][1]) + data['price'].append(zz[i][2]) + print(data) + + X=pd.DataFrame(data,columns=['carat', 'depth', 'price']) + print(X) + + X = np.asarray(X[['carat', 'depth', 'price']].values) + Y = np.asarray(df[['carat', 'depth', 'price']].values) + print(X) + print(Y) + + rc=mahalanobis(X, Y) + print('another_pandas',rc) + +def mahalanobis_using_numpy(x, data=None, cov=None, verbose=False): + import numpy as np + def mahalanobis(x, data, cov=None): + x_mean = np.mean(x, 0) + if verbose: print('x_mean',x_mean) + if cov: + Covariance=np.asarray(cov) + else: + Covariance = np.cov(np.transpose(data)) + if verbose: + print('Covariance') + print(Covariance) + inv_covmat = np.linalg.inv(Covariance) + if verbose: + print('inv_covmat') + print(inv_covmat) + x_minus_mn = x - x_mean + if verbose: + print('x_minus_mn') + print(x_minus_mn) + D_square = np.dot(np.dot(x_minus_mn, inv_covmat), np.transpose(x_minus_mn)) + if verbose: + print('D_square') + print(D_square) + print(D_square.diagonal()) + return D_square.diagonal() + + if verbose: + print(x) + print(data) + rc = mahalanobis(x, data=data, cov=cov) + return rc + def mahalanobis_using_numpy_and_scipy(x=None, data=None, mu=None, cov=None): """ Compute the Mahalanobis Distance between each row of x and the data @@ -32,16 +180,30 @@ def mahalanobis_using_numpy_and_scipy(x=None, data=None, mu=None, cov=None): cov : covariance matrix (p x p) of the distribution. If None, will be computed from data. """ - # error prone - assert 0 import numpy as np import scipy as sp + + x=np.array(x) + print(x) + data=np.array(data) + print(data) + x_mu = x - np.mean(data) + if not cov: + cov = np.cov(data.values.T) + inv_covmat = np.linalg.inv(cov) + left = np.dot(y_mu, inv_covmat) + mahal = np.dot(left, y_mu.T) + return mahal.diagonal() + if mu: x_minus_mu = x - mu else: print(x) print(np.mean(data)) x_minus_mu = x - np.mean(data) + print('x_minus_mu',x_minus_mu) + assert 0 + # x_minus_mu=np.array(x) print('x_minus_mu',x_minus_mu) if not cov: cov = np.cov(data) print(cov) @@ -59,13 +221,26 @@ def main(): spamreader = csv.reader(f, delimiter=',', quotechar='|') for i, row in enumerate(spamreader): if not i: continue - # print(', '.join(row)) + print(i,', '.join(row)) data.append([float(row[0]), float(row[4]), float(row[6])]) - zz=[(0.23, 61.5, 326), - (0.23, 56.9, 329), - (0.23, 56.9, 349), - ] + use_numpy=0 + use_pandas=0 + if use_pandas: + another_pandas() + + if use_numpy: + # another_pandas() + # mahalanobis_using_pandas() + #np.asarray + rc1 = mahalanobis_using_numpy(zz, data, verbose=1) + # rc = mahalanobis_using_numpy_and_scipy(zz, data) + print('rc1',rc1) + rc2 = mahalanobis_using_numpy(zz, cov=[ + [1.55789474e-03, 3.08947368e-02, 1.42105263e-01], + [3.08947368e-02, 3.50038781e+00, 5.25207756e+00], + [1.42105263e-01, 5.25207756e+00, 5.39556787e+01]], verbose=1) + print('rc2',rc2) rc=math_utils.mahalanobis(zz, data) print(rc) @@ -81,6 +256,9 @@ def main(): cov = math_utils.covariance_using_sklearn(data, verbose=True) rc=math_utils.mahalanobis(zz, cov=cov) print(rc) + if use_numpy: + print(rc1) + print(rc2) rc=math_utils.mahalanobis_p_values(zz, cov=cov, verbose=True) print(rc) rc=math_utils.mahalanobis_p_values_outlier_indices(zz, cov=cov) From 983b8ae7be93812e52cdafa1f2f96637c79c2780 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Fri, 30 Aug 2024 16:20:33 -0700 Subject: [PATCH 683/748] mmtbx: switch NaN to avoid numpy import --- mmtbx/atomic_environment_vectors/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mmtbx/atomic_environment_vectors/__init__.py b/mmtbx/atomic_environment_vectors/__init__.py index 8fcb026db3..36632898d6 100644 --- a/mmtbx/atomic_environment_vectors/__init__.py +++ b/mmtbx/atomic_environment_vectors/__init__.py @@ -2,12 +2,13 @@ import math import copy import mmtbx.model -from numpy import NaN from libtbx.utils import null_out from collections import OrderedDict from scitbx.array_family import flex from mmtbx.secondary_structure.build import ss_idealization as ssb +NaN = float('nan') + def format_HELIX_records_from_AEV(aev_values_dict): threshold1 = [2.48, 0.9, 4] threshold2 = [2.38, 0.9, 4] From 429625e9c956db46c857a8b3357e3481df40d4aa Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Sat, 31 Aug 2024 12:43:37 -0700 Subject: [PATCH 684/748] CI: clean up ssh options [skip ci] --- .azure-pipelines/download-source.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.azure-pipelines/download-source.yml b/.azure-pipelines/download-source.yml index a4a8079868..125cb3a396 100644 --- a/.azure-pipelines/download-source.yml +++ b/.azure-pipelines/download-source.yml @@ -13,11 +13,6 @@ jobs: steps: - - task: DownloadSecureFile@1 - name: ssh_config - inputs: - secureFile: ssh.config - # download sources - checkout: self path: ./modules/cctbx_project @@ -29,7 +24,6 @@ jobs: - script: | cd $(Pipeline.Workspace) - export SVN_SSH="ssh -F $(ssh_config.secureFilePath)" python bootstrap.py hot update --builder=cctbx --python=38 ${{ parameters.flags }} displayName: Download sources From 8149b8542865a4c5806a94f23d5d788527e2ab70 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Sun, 1 Sep 2024 13:37:20 -0700 Subject: [PATCH 685/748] Update CHANGELOG.rst for 2024.8 release [skip ci] --- CHANGELOG.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c95ab6a175..9c28e1f30b 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,9 @@ +2024.8 +====== + +* Speed improvements to pdb_interpretation +* DataManager: add sanity check for specified resolution limits + 2024.7 ====== From b6e57a5de608d5da137cb63bed639f811c28802d Mon Sep 17 00:00:00 2001 From: terwill Date: Tue, 3 Sep 2024 07:56:26 -0600 Subject: [PATCH 686/748] Fix missing chain ID --- mmtbx/process_predicted_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/process_predicted_model.py b/mmtbx/process_predicted_model.py index 046fda8447..a3a255b044 100644 --- a/mmtbx/process_predicted_model.py +++ b/mmtbx/process_predicted_model.py @@ -593,7 +593,7 @@ def get_selection_for_short_segments(ph, minimum_sequential_residues): for r in get_indices_as_ranges(residue_list): if (minimum_sequential_residues is None) or ( r.end - r.start + 1 < minimum_sequential_residues): - selections.append("(chain %s and resseq %s:%s)" %( + selections.append("(chain '%s' and resseq %s:%s)" %( chain_id, r.start, r.end)) selection_string = " or ".join(selections) return selection_string From df9ce430bd3cb93fc7241cbb57e3cd18aa2ad75d Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 3 Sep 2024 09:00:41 -0700 Subject: [PATCH 687/748] Malanobis reorg and corrctions --- libtbx/math_utils.py | 94 ++++++++++++++++++++---- libtbx/tst_mahalanobis.py | 145 ++++++++------------------------------ 2 files changed, 109 insertions(+), 130 deletions(-) diff --git a/libtbx/math_utils.py b/libtbx/math_utils.py index ab6d25d763..cdc54bc81e 100644 --- a/libtbx/math_utils.py +++ b/libtbx/math_utils.py @@ -276,13 +276,9 @@ def mahalanobis_using_sklearn(x=None, data=None, cov=None, verbose=False): if verbose: print(mahal_cov) return mahal_cov -def covariance_using_sklearn(data=None, values=None, verbose=False): +def covariance_using_sklearn(data=None, choice='Empirical', return_numpy=True, verbose=False): from sklearn.covariance import EmpiricalCovariance, MinCovDet - if values: - assert 0 - cov=EmpiricalCovariance() - cov.covariance_=values - return cov + import numpy as np # fit a MCD robust estimator to data robust_cov = MinCovDet().fit(data) # fit a MLE estimator to data @@ -294,22 +290,92 @@ def covariance_using_sklearn(data=None, values=None, verbose=False): ) ) # choose one - cov = emp_cov + if choice=='Empirical': + cov = emp_cov + elif choice=='Robust': + cov = robust_cov + if return_numpy: + return np.asarray(cov.covariance_) return cov -def mahalanobis_p_values_outlier_indices(x=None, data=None, cov=None): - rc = mahalanobis_p_values(x=x, data=data, cov=cov) +def covariance_using_numpy(data): + import numpy as np + return np.cov(np.transpose(data)) + +def numpy_mean(data, index=0): + import numpy as np + return np.mean(data, index) + +def mahalanobis_using_numpy(x, data=None, mu=None, cov=None, inv_cov=None, verbose=False): + """ + Compute the Mahalanobis Distance between each row of x and the data + x : vector or matrix of data with, say, p columns. + data : ndarray of the distribution from which Mahalanobis distance of each + observation of x is to be computed. + mu : mean of data. If None, computer from data. + cov : covariance matrix (p x p) of the distribution. If None, computed from data. + inv_cov : inverse of covariance matrix. If None, computed from cov + """ + import numpy as np + def _mahalanobis(x, data=None, mu=None, cov=None, inv_cov=None): + if verbose: + print('x',x) + print('data',data) + if mu is None: + mu = np.mean(data, 0) + else: + mu = np.asarray(mu) + if verbose: print('mu',mu) + if inv_cov is None: + if cov is None: + cov = covariance_using_numpy(data) + else: + cov=np.asarray(cov) + inv_cov = np.linalg.inv(cov) + if verbose: + print('Covariance') + print(cov) + if verbose: + print('Inverse Covariance') + print(inv_cov) + x_minus_mn = x - mu + if verbose: + print('x_minus_mn') + print(x_minus_mn) + D_square = np.dot(np.dot(x_minus_mn, inv_cov), np.transpose(x_minus_mn)) + if verbose: + print('D_square') + print(D_square) + print(D_square.diagonal()) + return D_square.diagonal() + + if verbose: + print(x) + print(data) + print(mu) + print(cov) + print(inv_cov) + if data is None: + assert mu and (cov is not None or inv_cov is not None) + rc = _mahalanobis(x, data=data, mu=mu, cov=cov, inv_cov=inv_cov) + return rc + +def mahalanobis_p_values_outlier_indices(x=None, data=None, mu=None, cov=None, inv_cov=None, verbose=False): + rc = mahalanobis_p_values(x=x, data=data, mu=mu, cov=cov, inv_cov=inv_cov, verbose=verbose) return list(filter(lambda x: rc[x] <0.01, range(len(rc)))) -def mahalanobis_p_values(x=None, data=None, cov=None, verbose=False): +def mahalanobis_p_values(x=None, data=None, mu=None, cov=None, inv_cov=None, verbose=False): from scipy.stats import chi2 df=len(x[0])-1 if verbose: print(chi2.ppf((1-0.01), df=df)) - #> 9.21 - mahal_cov = mahalanobis_using_sklearn(x=x, data=data, cov=cov) + #> 9.21 for df=2 + mahal_cov = mahalanobis(x=x, data=data, mu=mu, cov=cov, inv_cov=inv_cov, verbose=verbose) if verbose: print(mahal_cov) return(1 - chi2.cdf(mahal_cov, df)) -def mahalanobis(x=None, data=None, mu=None, cov=None): - return mahalanobis_using_sklearn(x=x, data=data, cov=cov) +def mahalanobis(x=None, data=None, mu=None, cov=None, inv_cov=None, verbose=False): + if 1: + return mahalanobis_using_numpy(x=x, data=data, mu=mu, cov=cov, inv_cov=inv_cov, verbose=verbose) + else: + return mahalanobis_using_sklearn(x=x, data=data, cov=cov, verbose=verbose) diff --git a/libtbx/tst_mahalanobis.py b/libtbx/tst_mahalanobis.py index 696a8b56d9..2f1e5702ae 100644 --- a/libtbx/tst_mahalanobis.py +++ b/libtbx/tst_mahalanobis.py @@ -31,7 +31,6 @@ def mahalanobis_using_pandas(): import numpy as np import pandas as pd - import scipy as stats from scipy.stats import chi2 # calculateMahalanobis Function to calculate @@ -138,81 +137,6 @@ def mahalanobis(x, y, cov=None): rc=mahalanobis(X, Y) print('another_pandas',rc) -def mahalanobis_using_numpy(x, data=None, cov=None, verbose=False): - import numpy as np - def mahalanobis(x, data, cov=None): - x_mean = np.mean(x, 0) - if verbose: print('x_mean',x_mean) - if cov: - Covariance=np.asarray(cov) - else: - Covariance = np.cov(np.transpose(data)) - if verbose: - print('Covariance') - print(Covariance) - inv_covmat = np.linalg.inv(Covariance) - if verbose: - print('inv_covmat') - print(inv_covmat) - x_minus_mn = x - x_mean - if verbose: - print('x_minus_mn') - print(x_minus_mn) - D_square = np.dot(np.dot(x_minus_mn, inv_covmat), np.transpose(x_minus_mn)) - if verbose: - print('D_square') - print(D_square) - print(D_square.diagonal()) - return D_square.diagonal() - - if verbose: - print(x) - print(data) - rc = mahalanobis(x, data=data, cov=cov) - return rc - -def mahalanobis_using_numpy_and_scipy(x=None, data=None, mu=None, cov=None): - """ - Compute the Mahalanobis Distance between each row of x and the data - x : vector or matrix of data with, say, p columns. - data : ndarray of the distribution from which Mahalanobis distance of each - observation of x is to be computed. - cov : covariance matrix (p x p) of the distribution. If None, will be - computed from data. - """ - import numpy as np - import scipy as sp - - x=np.array(x) - print(x) - data=np.array(data) - print(data) - x_mu = x - np.mean(data) - if not cov: - cov = np.cov(data.values.T) - inv_covmat = np.linalg.inv(cov) - left = np.dot(y_mu, inv_covmat) - mahal = np.dot(left, y_mu.T) - return mahal.diagonal() - - if mu: - x_minus_mu = x - mu - else: - print(x) - print(np.mean(data)) - x_minus_mu = x - np.mean(data) - print('x_minus_mu',x_minus_mu) - assert 0 - # x_minus_mu=np.array(x) - print('x_minus_mu',x_minus_mu) - if not cov: cov = np.cov(data) - print(cov) - inv_covmat = sp.linalg.inv(cov) - print(inv_covmat) - left_term = np.dot(x_minus_mu, inv_covmat) - mahal = np.dot(left_term, x_minus_mu.T) - return mahal.diagonal() - def main(): from libtbx import math_utils import csv @@ -224,27 +148,13 @@ def main(): print(i,', '.join(row)) data.append([float(row[0]), float(row[4]), float(row[6])]) - use_numpy=0 use_pandas=0 if use_pandas: another_pandas() - if use_numpy: - # another_pandas() - # mahalanobis_using_pandas() - #np.asarray - rc1 = mahalanobis_using_numpy(zz, data, verbose=1) - # rc = mahalanobis_using_numpy_and_scipy(zz, data) - print('rc1',rc1) - rc2 = mahalanobis_using_numpy(zz, cov=[ - [1.55789474e-03, 3.08947368e-02, 1.42105263e-01], - [3.08947368e-02, 3.50038781e+00, 5.25207756e+00], - [1.42105263e-01, 5.25207756e+00, 5.39556787e+01]], verbose=1) - print('rc2',rc2) - rc=math_utils.mahalanobis(zz, data) print(rc) - rc=math_utils.mahalanobis_p_values(zz, data, verbose=True) + rc=math_utils.mahalanobis_p_values(zz, data, verbose=False) print(rc) rc=math_utils.mahalanobis_p_values_outlier_indices(zz, data) assert rc==[2] @@ -253,36 +163,39 @@ def main(): if i in rc: outlier='OUTLIER' print(' %s %0.4f %s' % (i,p,outlier)) - cov = math_utils.covariance_using_sklearn(data, verbose=True) - rc=math_utils.mahalanobis(zz, cov=cov) + cov = math_utils.covariance_using_sklearn(data, verbose=False) + print('Empirical',cov) + mu=[2.60000000e-01, 6.18473684e+01, 3.38789474e+02] + cov=[ + [1.55789474e-03, 3.08947368e-02, 1.42105263e-01], + [3.08947368e-02, 3.50038781e+00, 5.25207756e+00], + [1.42105263e-01, 5.25207756e+00, 5.39556787e+01]] + inv_cov=[ + [ 9.20610847e+02, -5.25486917e+00, -1.91313813e+00], + [-5.25486917e+00, 3.64538468e-01, -2.16444268e-02], + [-1.91313813e+00, -2.16444268e-02, 2.56793212e-02]] + + rc1=math_utils.mahalanobis(zz, mu=mu, cov=cov) + print(rc1) + rc2=math_utils.mahalanobis_p_values(zz, mu=mu, inv_cov=inv_cov) + print(rc2) + rc=math_utils.mahalanobis_p_values_outlier_indices(zz, mu=mu, cov=cov) + assert rc==[2] + rc=math_utils.mahalanobis_p_values_outlier_indices(zz[:1], mu=mu, cov=cov) print(rc) - if use_numpy: - print(rc1) - print(rc2) - rc=math_utils.mahalanobis_p_values(zz, cov=cov, verbose=True) + + cov = math_utils.covariance_using_sklearn(data, choice='Robust', verbose=False) + print('Robust',cov) + rc=math_utils.mahalanobis(zz, mu=mu, cov=cov) print(rc) - rc=math_utils.mahalanobis_p_values_outlier_indices(zz, cov=cov) - assert rc==[2] - rc=math_utils.mahalanobis_p_values_outlier_indices(zz[:1], cov=cov) + rc=math_utils.mahalanobis_p_values_outlier_indices(zz, mu=mu, cov=cov) print(rc) + assert rc==[1,2] - # values = cov.covariance_.tolist() - # cov = math_utils.covariance_using_sklearn(values=values, verbose=True) - # assert 0 - from libtbx import easy_pickle - easy_pickle.dump('tst_mahal.pickle', cov) - cov=easy_pickle.load('tst_mahal.pickle') - # import pickle - # pf='tst_mahal.pickle' - # f=open(pf, 'w') - # pickle.dump(cov, f) - # del f - # f=open(pf, 'r') - # cov=pickle.load(f) - # del f - rc=math_utils.mahalanobis_p_values_outlier_indices(zz, cov=cov) + cov = math_utils.covariance_using_numpy(data) + print('???',cov) + rc=math_utils.mahalanobis(zz, mu=mu, cov=cov) print(rc) - assert rc==[2] if __name__ == '__main__': main() From 6bf0449b499ac9986f75489f90b5c340602f6644 Mon Sep 17 00:00:00 2001 From: Russell Taylor Date: Tue, 3 Sep 2024 17:08:43 -0400 Subject: [PATCH 688/748] Ribbons2 (#1009) * Adding a third, 'solid', color scheme for ribbons that makes all chains a solid color, even the first one. * By default, treats nucleic acids as helices rather than coils. * Bumped minor version number on ribbons --- mmtbx/programs/ribbons.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/mmtbx/programs/ribbons.py b/mmtbx/programs/ribbons.py index a7913ffb6d..bcbc15b38b 100644 --- a/mmtbx/programs/ribbons.py +++ b/mmtbx/programs/ribbons.py @@ -7,10 +7,10 @@ from mmtbx.kinemage.validation import get_chain_color from mmtbx.kinemage.ribbons import find_contiguous_protein_residues, find_contiguous_nucleic_acid_residues from mmtbx.kinemage.ribbons import make_protein_guidepoints, make_nucleic_acid_guidepoints -from mmtbx.kinemage.ribbons import untwist_ribbon, swap_edge_and_face, _FindNamedAtomInResidue +from mmtbx.kinemage.ribbons import untwist_ribbon, swap_edge_and_face, _FindNamedAtomInResidue, _IsNucleicAcidResidue from mmtbx.kinemage.nrubs import Triple, NRUBS -version = "1.0.0" +version = "1.1.0" master_phil_str = ''' do_protein = True @@ -29,10 +29,10 @@ .type = bool .short_caption = DNA style ribbons .help = Use the DNA style ribbons instead of the default RNA style ribbons (rotates them by 90 degrees) -color_by = *rainbow secondary_structure +color_by = *rainbow secondary_structure solid .type = choice(multi=False) .short_caption = How to color the ribbons - .help = How to color the ribbons + .help = How to color the ribbons. Rainbow adjusts the color smoothly along each chain. Solid make each chain a single color. Secondary structure colors every 7th chain by the secondary structure and makes the others solid colors. do_plain_coils = False .type = bool .short_caption = Do plain coils @@ -45,6 +45,10 @@ .type = atom_selection .short_caption = Atom selection .help = Atom selection description +nucleic_acid_as_helix = True + .type = bool + .short_caption = Draw nucleic acids as helix + .help = If true, draw nucleic acids as helix rather than treating as coil because there are not secondary structure records for them ''' # ------------------------------------------------------------------------------ @@ -335,7 +339,7 @@ def printFancyRibbon(self, guides, widthAlpha, widthBeta, listAlpha, listBeta, l if ribElement.type is None: ribElement.like(currSS) - if not ribElement.sameSSE(currSS): # Helix / sheet starting + if i == 0 or not ribElement.sameSSE(currSS): # Helix / sheet starting if currSS.type == 'HELIX' or currSS.type == 'SHEET': ribElement.end = self.nIntervals*i + 1 ribElement = self.RibbonElement(currSS) @@ -568,6 +572,13 @@ def run(self): self.ConsolidateSheets() + # If we are treating nucleic acids as helices, change the record of each nucleic acid residue to be a helix. + if self.params.nucleic_acid_as_helix: + r = self.Range('HELIX') + for res in hierarchy.residue_groups(): + if _IsNucleicAcidResidue(res.unique_resnames()[0]): + self.secondaryStructure[int(res.resseq)] = r + # The name of the structure, which is the root of the input file name (no path, no extension) self.idCode = self.data_manager.get_default_model_name().split('.')[0] if self.idCode is None or self.idCode == "": @@ -625,14 +636,17 @@ def run(self): outString += "@group {{{} {}}} dominant\n".format(self.idCode, chain.id) outString += "@subgroup {ribbon}\n" + # Set the basic colors for the parts of the ribbon, which may be overridden by rainbow coloring on a + # per-residue basis. bbColor = chainColors[chain.id] - if bbColor == "white": - # Distinguish between the different types of secondary structure for the first chain + if bbColor == "white" and not (self.params.color_by == "solid"): + # Distinguish between the different types of secondary structure for the first chain (out of every 7th) + # if we're not coloring by solid colors outString += "@colorset {{alph{}}} red\n".format(chain.id) outString += "@colorset {{beta{}}} lime\n".format(chain.id) outString += "@colorset {{coil{}}} white\n".format(chain.id) else: - # Do all secondary structure in the same color for all but the first chain to clean up the display + # Do all secondary structure in the same color for all but the first chain (out of every 7th) to clean up the display outString += "@colorset {{alph{}}} {}\n".format(chain.id, bbColor) outString += "@colorset {{beta{}}} {}\n".format(chain.id, bbColor) outString += "@colorset {{coil{}}} {}\n".format(chain.id, bbColor) From b4d65205891b5818627ea110b1be16387fe29ca4 Mon Sep 17 00:00:00 2001 From: cschlick Date: Wed, 4 Sep 2024 10:59:04 -0700 Subject: [PATCH 689/748] Add function to return origin_label given origin .geo header. --- cctbx/geometry_restraints/linking_class.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/cctbx/geometry_restraints/linking_class.py b/cctbx/geometry_restraints/linking_class.py index 4ea391364d..ae3e799e41 100644 --- a/cctbx/geometry_restraints/linking_class.py +++ b/cctbx/geometry_restraints/linking_class.py @@ -111,6 +111,26 @@ def get_geo_file_header(self, origin_id_label, internals=None): else: assert 0 else: return info[0] + def get_label_for_geo_header(self,query_header,internals=None): + """ + Given the string found in a geo file origin_id header, get the label + From label can use get_origin_id to get the integer origin id. + """ + if not internals: + internals = "bonds" + internals_all = ["bonds", "angles", "dihedrals", "chirals", "planes","parallelities"] + assert internals in internals_all + internal_idx = internals_all.index(internals) + + for origin_label, info in self.data.items(): + if len(info)>=4: + header_info = info[3] + if isinstance(header_info,list) and len(header_info)>internal_idx: + header = header_info[internal_idx] + if header: + if header.startswith(query_header) or query_header.startswith(header): + return origin_label + if __name__=='__main__': lc = linking_class() print(lc) From 2194c33a45b6190a6be6bfad2e16c92eacc4f956 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 4 Sep 2024 15:13:26 -0700 Subject: [PATCH 690/748] Reduce2: rename test for consistency --- mmtbx/hydrogens/{tst_add_hydrogen.py => tst_add_hydrogen_1.py} | 0 mmtbx/run_tests.py | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename mmtbx/hydrogens/{tst_add_hydrogen.py => tst_add_hydrogen_1.py} (100%) diff --git a/mmtbx/hydrogens/tst_add_hydrogen.py b/mmtbx/hydrogens/tst_add_hydrogen_1.py similarity index 100% rename from mmtbx/hydrogens/tst_add_hydrogen.py rename to mmtbx/hydrogens/tst_add_hydrogen_1.py diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index b5cb6130f4..bbca20bf3a 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -150,7 +150,7 @@ "$D/regression/tst_altloc_remediate.py", "$D/hydrogens/build_hydrogens.py", "$D/hydrogens/tst.py", - "$D/hydrogens/tst_add_hydrogen.py", + "$D/hydrogens/tst_add_hydrogen_1.py", "$D/hydrogens/tst_add_hydrogen_2.py", "$D/hydrogens/tst_add_hydrogen_3.py", #"$D/hydrogens/tst_add_hydrogen_time.py", From 27136c52067d8099f65eb5011aa99b4737b2d2c9 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 4 Sep 2024 15:33:04 -0700 Subject: [PATCH 691/748] Reduce2: propagate name change --- mmtbx/hydrogens/tst_add_hydrogen_2.py | 2 +- mmtbx/hydrogens/tst_add_hydrogen_3.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mmtbx/hydrogens/tst_add_hydrogen_2.py b/mmtbx/hydrogens/tst_add_hydrogen_2.py index 052cbec494..be14339a0a 100644 --- a/mmtbx/hydrogens/tst_add_hydrogen_2.py +++ b/mmtbx/hydrogens/tst_add_hydrogen_2.py @@ -1,7 +1,7 @@ from __future__ import absolute_import, division, print_function import time import mmtbx.model -from mmtbx.hydrogens.tst_add_hydrogen import compare_models +from mmtbx.hydrogens.tst_add_hydrogen_1 import compare_models def run(): diff --git a/mmtbx/hydrogens/tst_add_hydrogen_3.py b/mmtbx/hydrogens/tst_add_hydrogen_3.py index 24ebfc19fe..60dc6dbdad 100644 --- a/mmtbx/hydrogens/tst_add_hydrogen_3.py +++ b/mmtbx/hydrogens/tst_add_hydrogen_3.py @@ -3,7 +3,7 @@ import mmtbx.model import iotbx.pdb from mmtbx.hydrogens import reduce_hydrogen -from mmtbx.hydrogens.tst_add_hydrogen import compare_models +from mmtbx.hydrogens.tst_add_hydrogen_1 import compare_models from libtbx.utils import null_out # ------------------------------------------------------------------------------ From 68997a20670ae95b3343c1e033c8c148c0a11877 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 4 Sep 2024 15:36:15 -0700 Subject: [PATCH 692/748] Reduce2: Add test. Clean up. --- mmtbx/hydrogens/tst_add_hydrogen_0.py | 91 ----------------------- mmtbx/hydrogens/tst_add_hydrogen_4.py | 101 ++++++++++++++++++++++++++ mmtbx/run_tests.py | 1 + 3 files changed, 102 insertions(+), 91 deletions(-) create mode 100644 mmtbx/hydrogens/tst_add_hydrogen_4.py diff --git a/mmtbx/hydrogens/tst_add_hydrogen_0.py b/mmtbx/hydrogens/tst_add_hydrogen_0.py index a545cdbcc1..f94becf2e3 100644 --- a/mmtbx/hydrogens/tst_add_hydrogen_0.py +++ b/mmtbx/hydrogens/tst_add_hydrogen_0.py @@ -6,23 +6,7 @@ # ------------------------------------------------------------------------------ def run(): - test_000() test_001() - test_002() - # test_003() - # test_004() - # test_005() - # test_006() - # test_007() - # test_008() - -# ------------------------------------------------------------------------------ - -def test_000(): - ''' - Added a torsion to NH2_CTERM - ''' - compare_models(pdb_str = pdb_str_000) # ------------------------------------------------------------------------------ @@ -34,43 +18,6 @@ def test_001(): # ------------------------------------------------------------------------------ -def test_002(): - ''' - Carbohydrates need more dihedrals - ''' - compare_models(pdb_str = pdb_str_002) - -# ------------------------------------------------------------------------------ - -pdb_str_000 = """ -CRYST1 56.445 72.085 123.593 90.00 90.00 90.00 P 21 21 21 -SCALE1 0.017716 0.000000 0.000000 0.00000 -SCALE2 0.000000 0.013873 0.000000 0.00000 -SCALE3 0.000000 0.000000 0.008091 0.00000 -HETATM 1 N DLE E 12 -46.710 -11.701 15.468 1.00 34.07 N -HETATM 2 CA DLE E 12 -47.200 -11.850 14.105 1.00 39.64 C -HETATM 3 C DLE E 12 -48.679 -11.482 14.009 1.00 41.13 C -HETATM 4 O DLE E 12 -49.335 -11.798 13.021 1.00 42.80 O -HETATM 5 CB DLE E 12 -46.390 -10.976 13.144 1.00 43.98 C -HETATM 6 CG DLE E 12 -44.950 -11.415 12.889 1.00 46.65 C -HETATM 7 CD1 DLE E 12 -44.919 -12.765 12.197 1.00 46.88 C -HETATM 8 CD2 DLE E 12 -44.198 -10.363 12.085 1.00 48.25 C -HETATM 10 HA DLE E 12 -47.098 -12.777 13.837 1.00 39.64 H -HETATM 11 HB2 DLE E 12 -46.356 -10.078 13.509 1.00 43.98 H -HETATM 12 HB3 DLE E 12 -46.844 -10.969 12.287 1.00 43.98 H -HETATM 13 HG DLE E 12 -44.493 -11.511 13.739 1.00 46.65 H -HETATM 14 HD11 DLE E 12 -43.996 -13.021 12.046 1.00 46.88 H -HETATM 15 HD12 DLE E 12 -45.386 -12.696 11.349 1.00 46.88 H -HETATM 16 HD13 DLE E 12 -45.356 -13.420 12.763 1.00 46.88 H -HETATM 17 HD21 DLE E 12 -44.646 -10.236 11.234 1.00 48.25 H -HETATM 18 HD22 DLE E 12 -43.289 -10.668 11.938 1.00 48.25 H -HETATM 19 HD23 DLE E 12 -44.192 -9.530 12.582 1.00 48.25 H -HETATM 20 N NH2 E 202 -49.193 -10.809 15.033 1.00 40.90 N -HETATM 21 HN1 NH2 E 202 -48.680 -10.596 15.728 1.00 40.90 H -HETATM 22 HN2 NH2 E 202 -50.051 -10.572 15.024 1.00 40.90 H -END -""" - pdb_str_001 = ''' CRYST1 60.683 61.851 76.893 90.00 90.00 90.00 P 21 21 21 SCALE1 0.016479 0.000000 0.000000 0.00000 @@ -117,44 +64,6 @@ def test_002(): HETATM 39 HO3' ADP A1311 -6.507 15.409 14.043 0.60 15.01 H ''' -pdb_str_002 = ''' -CRYST1 16.163 16.054 17.729 90.00 90.00 90.00 P 1 -SCALE1 0.061870 0.000000 0.000000 0.00000 -SCALE2 0.000000 0.062290 0.000000 0.00000 -SCALE3 0.000000 0.000000 0.056405 0.00000 -HETATM 1 C1 NAG A 1 7.207 7.892 8.696 1.00 20.00 A C -HETATM 2 C2 NAG A 1 8.726 7.903 8.675 1.00 20.00 A C -HETATM 3 C3 NAG A 1 9.299 7.873 10.037 1.00 20.00 A C -HETATM 4 C4 NAG A 1 8.735 8.963 10.912 1.00 20.00 A C -HETATM 5 C5 NAG A 1 7.211 8.952 10.928 1.00 20.00 A C -HETATM 6 C6 NAG A 1 6.722 10.156 11.692 1.00 20.00 A C -HETATM 7 C7 NAG A 1 9.920 6.866 6.642 1.00 20.00 A C -HETATM 8 C8 NAG A 1 10.391 5.633 5.851 1.00 20.00 A C -HETATM 9 N2 NAG A 1 9.210 6.694 7.918 1.00 20.00 A N -HETATM 10 O1 NAG A 1 6.748 8.064 7.430 1.00 20.00 A O -HETATM 11 O3 NAG A 1 10.730 8.045 9.943 1.00 20.00 A O -HETATM 12 O4 NAG A 1 9.211 8.778 12.243 1.00 20.00 A O -HETATM 13 O5 NAG A 1 6.644 8.983 9.574 1.00 20.00 A O -HETATM 14 O6 NAG A 1 5.328 10.234 11.597 1.00 20.00 A O -HETATM 15 O7 NAG A 1 10.109 7.947 6.214 1.00 20.00 A O -HETATM 16 H1 NAG A 1 6.928 7.042 9.072 1.00 20.00 A H -HETATM 17 H2 NAG A 1 9.004 8.727 8.246 1.00 20.00 A H -HETATM 18 H3 NAG A 1 9.042 7.013 10.404 1.00 20.00 A H -HETATM 19 H4 NAG A 1 9.054 9.784 10.505 1.00 20.00 A H -HETATM 20 H5 NAG A 1 6.893 8.131 11.334 1.00 20.00 A H -HETATM 21 H61 NAG A 1 7.154 10.946 11.330 1.00 20.00 A H -HETATM 22 H62 NAG A 1 7.018 10.077 12.612 1.00 20.00 A H -HETATM 23 H81 NAG A 1 10.095 4.828 6.305 1.00 20.00 A H -HETATM 24 H82 NAG A 1 11.359 5.638 5.795 1.00 20.00 A H -HETATM 25 H83 NAG A 1 10.013 5.661 4.958 1.00 20.00 A H -HETATM 26 HN2 NAG A 1 9.068 5.908 8.238 1.00 20.00 A H -HETATM 27 HO1 NAG A 1 6.819 8.882 7.211 1.00 20.00 A H -HETATM 28 HO3 NAG A 1 10.919 8.822 10.230 1.00 20.00 A H -HETATM 29 HO4 NAG A 1 9.549 8.001 12.310 1.00 20.00 A H -HETATM 30 HO6 NAG A 1 5.126 10.415 10.791 1.00 20.00 A H -END -''' - if (__name__ == "__main__"): t0 = time.time() run() diff --git a/mmtbx/hydrogens/tst_add_hydrogen_4.py b/mmtbx/hydrogens/tst_add_hydrogen_4.py new file mode 100644 index 0000000000..c4aff24042 --- /dev/null +++ b/mmtbx/hydrogens/tst_add_hydrogen_4.py @@ -0,0 +1,101 @@ +from __future__ import absolute_import, division, print_function +import time + +from mmtbx.hydrogens.tst_add_hydrogen_1 import compare_models + +# ------------------------------------------------------------------------------ + +def run(): + test_000() + test_001() + +# ------------------------------------------------------------------------------ + +def test_000(): + ''' + D-Leucine with an NH2. + ''' + compare_models(pdb_str = pdb_str_000) + +# ------------------------------------------------------------------------------ + +def test_001(): + ''' + NAG carbohydrate + ''' + compare_models(pdb_str = pdb_str_001) + +# ------------------------------------------------------------------------------ + +pdb_str_000 = """ +CRYST1 56.445 72.085 123.593 90.00 90.00 90.00 P 21 21 21 +SCALE1 0.017716 0.000000 0.000000 0.00000 +SCALE2 0.000000 0.013873 0.000000 0.00000 +SCALE3 0.000000 0.000000 0.008091 0.00000 +HETATM 1 N DLE E 12 -46.710 -11.701 15.468 1.00 34.07 N +HETATM 2 CA DLE E 12 -47.200 -11.850 14.105 1.00 39.64 C +HETATM 3 C DLE E 12 -48.679 -11.482 14.009 1.00 41.13 C +HETATM 4 O DLE E 12 -49.335 -11.798 13.021 1.00 42.80 O +HETATM 5 CB DLE E 12 -46.390 -10.976 13.144 1.00 43.98 C +HETATM 6 CG DLE E 12 -44.950 -11.415 12.889 1.00 46.65 C +HETATM 7 CD1 DLE E 12 -44.919 -12.765 12.197 1.00 46.88 C +HETATM 8 CD2 DLE E 12 -44.198 -10.363 12.085 1.00 48.25 C +HETATM 9 H DLE E 12 -46.283 -12.387 15.763 1.00 34.07 H +HETATM 10 HA DLE E 12 -47.098 -12.777 13.837 1.00 39.64 H +HETATM 11 HB2 DLE E 12 -46.356 -10.078 13.509 1.00 43.98 H +HETATM 12 HB3 DLE E 12 -46.844 -10.969 12.287 1.00 43.98 H +HETATM 13 HG DLE E 12 -44.493 -11.511 13.739 1.00 46.65 H +HETATM 14 HD11 DLE E 12 -43.996 -13.021 12.046 1.00 46.88 H +HETATM 15 HD12 DLE E 12 -45.386 -12.696 11.349 1.00 46.88 H +HETATM 16 HD13 DLE E 12 -45.356 -13.420 12.763 1.00 46.88 H +HETATM 17 HD21 DLE E 12 -44.646 -10.236 11.234 1.00 48.25 H +HETATM 18 HD22 DLE E 12 -43.289 -10.668 11.938 1.00 48.25 H +HETATM 19 HD23 DLE E 12 -44.192 -9.530 12.582 1.00 48.25 H +HETATM 20 N NH2 E 202 -49.193 -10.809 15.033 1.00 40.90 N +HETATM 21 HN1 NH2 E 202 -48.680 -10.596 15.728 1.00 40.90 H +HETATM 22 HN2 NH2 E 202 -50.051 -10.572 15.024 1.00 40.90 H +END +""" + +pdb_str_001 = ''' +CRYST1 16.163 16.054 17.729 90.00 90.00 90.00 P 1 +SCALE1 0.061870 0.000000 0.000000 0.00000 +SCALE2 0.000000 0.062290 0.000000 0.00000 +SCALE3 0.000000 0.000000 0.056405 0.00000 +HETATM 1 C1 NAG A 1 7.207 7.892 8.696 1.00 20.00 A C +HETATM 2 C2 NAG A 1 8.726 7.903 8.675 1.00 20.00 A C +HETATM 3 C3 NAG A 1 9.299 7.873 10.037 1.00 20.00 A C +HETATM 4 C4 NAG A 1 8.735 8.963 10.912 1.00 20.00 A C +HETATM 5 C5 NAG A 1 7.211 8.952 10.928 1.00 20.00 A C +HETATM 6 C6 NAG A 1 6.722 10.156 11.692 1.00 20.00 A C +HETATM 7 C7 NAG A 1 9.920 6.866 6.642 1.00 20.00 A C +HETATM 8 C8 NAG A 1 10.391 5.633 5.851 1.00 20.00 A C +HETATM 9 N2 NAG A 1 9.210 6.694 7.918 1.00 20.00 A N +HETATM 10 O1 NAG A 1 6.748 8.064 7.430 1.00 20.00 A O +HETATM 11 O3 NAG A 1 10.730 8.045 9.943 1.00 20.00 A O +HETATM 12 O4 NAG A 1 9.211 8.778 12.243 1.00 20.00 A O +HETATM 13 O5 NAG A 1 6.644 8.983 9.574 1.00 20.00 A O +HETATM 14 O6 NAG A 1 5.328 10.234 11.597 1.00 20.00 A O +HETATM 15 O7 NAG A 1 10.109 7.947 6.214 1.00 20.00 A O +HETATM 16 H1 NAG A 1 6.928 7.042 9.072 1.00 20.00 A H +HETATM 17 H2 NAG A 1 9.004 8.727 8.246 1.00 20.00 A H +HETATM 18 H3 NAG A 1 9.042 7.013 10.404 1.00 20.00 A H +HETATM 19 H4 NAG A 1 9.054 9.784 10.505 1.00 20.00 A H +HETATM 20 H5 NAG A 1 6.893 8.131 11.334 1.00 20.00 A H +HETATM 21 H61 NAG A 1 7.154 10.946 11.330 1.00 20.00 A H +HETATM 22 H62 NAG A 1 7.018 10.077 12.612 1.00 20.00 A H +HETATM 23 H81 NAG A 1 10.095 4.828 6.305 1.00 20.00 A H +HETATM 24 H82 NAG A 1 11.359 5.638 5.795 1.00 20.00 A H +HETATM 25 H83 NAG A 1 10.013 5.661 4.958 1.00 20.00 A H +HETATM 26 HN2 NAG A 1 9.068 5.908 8.238 1.00 20.00 A H +HETATM 27 HO1 NAG A 1 6.806 8.885 7.217 1.00 20.00 A H +HETATM 28 HO3 NAG A 1 10.879 8.808 9.599 1.00 20.00 A H +HETATM 29 HO4 NAG A 1 9.998 8.457 12.213 1.00 20.00 A H +HETATM 30 HO6 NAG A 1 5.116 10.219 10.774 1.00 20.00 A H +END +''' + +if (__name__ == "__main__"): + t0 = time.time() + run() + print("OK. Time: %8.3f"%(time.time()-t0)) diff --git a/mmtbx/run_tests.py b/mmtbx/run_tests.py index bbca20bf3a..d681fa579f 100644 --- a/mmtbx/run_tests.py +++ b/mmtbx/run_tests.py @@ -153,6 +153,7 @@ "$D/hydrogens/tst_add_hydrogen_1.py", "$D/hydrogens/tst_add_hydrogen_2.py", "$D/hydrogens/tst_add_hydrogen_3.py", + "$D/hydrogens/tst_add_hydrogen_4.py", #"$D/hydrogens/tst_add_hydrogen_time.py", "$D/hydrogens/tst_validate_H.py", "$D/hydrogens/tst_connectivity.py", From e9bce95d2fe0e62e56f571bc6f273e03c16b3528 Mon Sep 17 00:00:00 2001 From: Daniel Tchon Date: Thu, 5 Sep 2024 15:40:56 -0700 Subject: [PATCH 693/748] Clean clutter --- cctbx/geometry_restraints/linking_class.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cctbx/geometry_restraints/linking_class.py b/cctbx/geometry_restraints/linking_class.py index ae3e799e41..8314ac3555 100644 --- a/cctbx/geometry_restraints/linking_class.py +++ b/cctbx/geometry_restraints/linking_class.py @@ -121,7 +121,7 @@ def get_label_for_geo_header(self,query_header,internals=None): internals_all = ["bonds", "angles", "dihedrals", "chirals", "planes","parallelities"] assert internals in internals_all internal_idx = internals_all.index(internals) - + for origin_label, info in self.data.items(): if len(info)>=4: header_info = info[3] @@ -130,7 +130,7 @@ def get_label_for_geo_header(self,query_header,internals=None): if header: if header.startswith(query_header) or query_header.startswith(header): return origin_label - + if __name__=='__main__': lc = linking_class() print(lc) From d8e5e8105d5d5dddeaeeb7417a9f6d2851330947 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Tcho=C5=84?= Date: Thu, 5 Sep 2024 22:02:03 -0700 Subject: [PATCH 694/748] Make `mpi_helper`'s method non-rooted if `root=None` (#1010) * Auto-select `mpi_helper`'s collectives using new context manager * Remove unused `from dials.array_family import flex` statement * Change misleading (?) name in `gather_variable_length_numpy_arrays` * Simplify code following changes in `beam_statistics.py` * Simplify code following changes in `error_modifier_mm24.py` * Simplify code following changes in `unit_cell_statistics.py` * Bugfix multiprocessing reporting in `global_filter.py` * Extend `adaptive_collective` `contextmanager`'s docstring * Revert "Simplify code following changes in `error_modifier_mm24.py`" This reverts commit b4edf435f9afae0c34281ec730545bc2388a32fc. * Bugfix: non-rooted collective should be never passed `root` kwarg * define `mpiCommEmulator.Allgatherv` * Remove walrus operator for python2.7 compliance --- libtbx/mpi4py.py | 2 + .../application/filter/global_filter.py | 14 ++--- xfel/merging/application/mpi_helper.py | 52 +++++++++++++------ .../application/statistics/beam_statistics.py | 11 +--- .../statistics/unit_cell_statistics.py | 22 ++++---- 5 files changed, 57 insertions(+), 44 deletions(-) diff --git a/libtbx/mpi4py.py b/libtbx/mpi4py.py index a2f13a3336..eb186e578e 100644 --- a/libtbx/mpi4py.py +++ b/libtbx/mpi4py.py @@ -60,6 +60,8 @@ def Gatherv(self, sendbuf, recvbuf, root=0): counter += count def allgather(self, sendobj): return [sendobj] + def Allgatherv(self, sendbuf, recvbuf): + return self.Gatherv(sendbuf, recvbuf) def Abort(self,errorcode=0): import sys sys.exit() diff --git a/xfel/merging/application/filter/global_filter.py b/xfel/merging/application/filter/global_filter.py index 4d7ed56cf4..11038f76e5 100644 --- a/xfel/merging/application/filter/global_filter.py +++ b/xfel/merging/application/filter/global_filter.py @@ -92,16 +92,16 @@ def report_filter_reasons(self): te = sum(self.expt_filter_reasons.values()) tr = sum(self.refl_filter_reasons.values()) self.logger.log(FilterReasons.report_line('TOTAL', te, tr)) + all_expt_filter_reasons = self.mpi_helper.count(self.expt_filter_reasons) + all_refl_filter_reasons = self.mpi_helper.count(self.refl_filter_reasons) if self.mpi_helper.rank == 0: self.logger.main_log('Experiments/reflections filtered due to:') - expt_filter_reasons = self.mpi_helper.count(self.expt_filter_reasons) - refl_filter_reasons = self.mpi_helper.count(self.refl_filter_reasons) - for r in uniques(expt_filter_reasons, refl_filter_reasons): - te = expt_filter_reasons[r] - tr = refl_filter_reasons[r] + for r in uniques(all_expt_filter_reasons, all_refl_filter_reasons): + te = all_expt_filter_reasons[r] + tr = all_refl_filter_reasons[r] self.logger.main_log(FilterReasons.report_line(r.value, te, tr)) - te = sum(expt_filter_reasons.values()) - tr = sum(refl_filter_reasons.values()) + te = sum(all_expt_filter_reasons.values()) + tr = sum(all_refl_filter_reasons.values()) self.logger.main_log(FilterReasons.report_line('TOTAL', te, tr)) def run(self, experiments, reflections): diff --git a/xfel/merging/application/mpi_helper.py b/xfel/merging/application/mpi_helper.py index 215a8d0260..171ae4a82a 100644 --- a/xfel/merging/application/mpi_helper.py +++ b/xfel/merging/application/mpi_helper.py @@ -1,8 +1,9 @@ from __future__ import absolute_import, division, print_function from collections import Counter +from contextlib import contextmanager from libtbx.mpi4py import MPI import numpy as np -from dials.array_family import flex + import sys def system_exception_handler(exception_type, value, traceback): @@ -23,6 +24,24 @@ def system_exception_handler(exception_type, value, traceback): sys.excepthook = system_exception_handler +@contextmanager +def adaptive_collective(rooted_variant, non_rooted_variant): + """ + Declare and switch from rooted to non-rooted collective if root is None. + Statement `with adaptive_collective(gather, allgather) as gather:` will yield + `allgather` if root is None, and gather (with an appropriate root) otherwise. + """ + def adaptive_collective_dispatcher(*args, **kwargs): + root = kwargs.pop('root', 0) + if root is None: + collective = non_rooted_variant + else: # if root is an integer + collective = rooted_variant + kwargs['root'] = root + return collective(*args, **kwargs) + yield adaptive_collective_dispatcher + + class mpi_helper(object): def __init__(self): self.MPI = MPI @@ -43,8 +62,9 @@ def cumulative_flex(self, flex_array, flex_type=None, root=0): Example: (a1,a2,a3) + (b1, b2, b3) = (a1+b1, a2+b2, a3+b3) """ flex_type = flex_type if flex_type is not None else type(flex_array) - list_of_all_flex_arrays = self.comm.gather(flex_array, root=root) - if self.rank != root: + with adaptive_collective(self.comm.gather, self.comm.allgather) as gather: + list_of_all_flex_arrays = gather(flex_array, root=root) + if list_of_all_flex_arrays is None: return None cumulative = flex_type(flex_array.size(), 0) for flex_array in list_of_all_flex_arrays: @@ -58,8 +78,9 @@ def aggregate_flex(self, flex_array, flex_type=None, root=0): Example: (a1,a2,a3) + (b1, b2, b3) = (a1, a2, a3, b1, b2, b3) """ flex_type = flex_type if flex_type is not None else type(flex_array) - list_of_all_flex_arrays = self.comm.gather(flex_array, root=root) - if self.rank != root: + with adaptive_collective(self.comm.gather, self.comm.allgather) as gather: + list_of_all_flex_arrays = gather(flex_array, root=root) + if list_of_all_flex_arrays is None: return None aggregate = flex_type() for flex_array in list_of_all_flex_arrays: @@ -72,15 +93,17 @@ def count(self, data, root=0): Return total `Counter` of occurrences of each element in data across ranks. Example: (a1, a1, a2) + (a1, a2, a3) = {a1: 3, a2: 2, a1: 1} """ - counters = self.comm.gather(Counter(data), root=root) - return sum(counters, Counter()) if self.rank == root else None + with adaptive_collective(self.comm.gather, self.comm.allgather) as gather: + counters = gather(Counter(data), root=root) + return sum(counters, Counter()) if counters is not None else None def sum(self, data, root=0): """ Sum values of data across all ranks. Example: a1 + a2 + a3 = a1+a2+a3 """ - return self.comm.reduce(data, self.MPI.SUM, root=root) + with adaptive_collective(self.comm.reduce, self.comm.allreduce) as reduce: + return reduce(data, self.MPI.SUM, root=root) def set_error(self, description): self.error = (self.rank, description) @@ -96,10 +119,9 @@ def check_errors(self): self.comm.Abort(1) def gather_variable_length_numpy_arrays(self, send_arrays, root=0, dtype=float): - lengths = self.comm.gather(send_arrays.size, root=root) - if self.rank == root: - gathered_arrays = np.empty(np.sum(lengths), dtype=dtype) - else: - gathered_arrays = None - self.comm.Gatherv(sendbuf=send_arrays, recvbuf=(gathered_arrays, lengths), root=root) - return gathered_arrays + with adaptive_collective(self.comm.gather, self.comm.allgather) as gather: + lengths = gather(send_arrays.size, root=root) + gathered_array = np.empty(np.sum(lengths), dtype=dtype) if lengths else None + with adaptive_collective(self.comm.Gatherv, self.comm.Allgatherv) as gather_v: + gather_v(sendbuf=send_arrays, recvbuf=(gathered_array, lengths), root=root) + return gathered_array diff --git a/xfel/merging/application/statistics/beam_statistics.py b/xfel/merging/application/statistics/beam_statistics.py index f16ea09d74..098c24ff6c 100644 --- a/xfel/merging/application/statistics/beam_statistics.py +++ b/xfel/merging/application/statistics/beam_statistics.py @@ -14,17 +14,10 @@ def run(self, experiments, reflections): self.logger.log_step_time("BEAM_STATISTICS") f_wavelengths = flex.double([b.get_wavelength() for b in experiments.beams()]) - flex_all_wavelengths = self.mpi_helper.aggregate_flex(f_wavelengths, flex.double) - + flex_all_wavelengths = self.mpi_helper.aggregate_flex(f_wavelengths, flex.double, root=None) + average_wavelength = flex.mean(flex_all_wavelengths) if self.mpi_helper.rank == 0: - average_wavelength = flex.mean(flex_all_wavelengths) self.logger.main_log("Wavelength: %f"%average_wavelength) - else: - average_wavelength = None - - self.logger.log_step_time("BROADCAST_WAVELENGTH") - average_wavelength = self.mpi_helper.comm.bcast(average_wavelength, root = 0) - self.logger.log_step_time("BROADCAST_WAVELENGTH", True) # save the average wavelength to the phil parameters if self.mpi_helper.rank == 0: diff --git a/xfel/merging/application/statistics/unit_cell_statistics.py b/xfel/merging/application/statistics/unit_cell_statistics.py index bc1d37f899..99394ff379 100644 --- a/xfel/merging/application/statistics/unit_cell_statistics.py +++ b/xfel/merging/application/statistics/unit_cell_statistics.py @@ -49,13 +49,13 @@ def add_cell(self, unit_cell): self.uc_gamma_values.append(gamma) def collect_from_all_ranks(self): - self.all_uc_a_values = self.mpi_helper.aggregate_flex(self.uc_a_values, flex.double) - self.all_uc_b_values = self.mpi_helper.aggregate_flex(self.uc_b_values, flex.double) - self.all_uc_c_values = self.mpi_helper.aggregate_flex(self.uc_c_values, flex.double) + self.all_uc_a_values = self.mpi_helper.aggregate_flex(self.uc_a_values, flex.double, root=None) + self.all_uc_b_values = self.mpi_helper.aggregate_flex(self.uc_b_values, flex.double, root=None) + self.all_uc_c_values = self.mpi_helper.aggregate_flex(self.uc_c_values, flex.double, root=None) - self.all_uc_alpha_values = self.mpi_helper.aggregate_flex(self.uc_alpha_values, flex.double) - self.all_uc_beta_values = self.mpi_helper.aggregate_flex(self.uc_beta_values, flex.double) - self.all_uc_gamma_values = self.mpi_helper.aggregate_flex(self.uc_gamma_values, flex.double) + self.all_uc_alpha_values = self.mpi_helper.aggregate_flex(self.uc_alpha_values, flex.double, root=None) + self.all_uc_beta_values = self.mpi_helper.aggregate_flex(self.uc_beta_values, flex.double, root=None) + self.all_uc_gamma_values = self.mpi_helper.aggregate_flex(self.uc_gamma_values, flex.double, root=None) def is_valid(self): return len(self.all_uc_a_values) > 0 and len(self.all_uc_b_values) > 0 and len(self.all_uc_c_values) > 0 and \ @@ -129,14 +129,10 @@ def run(self, experiments, reflections): ucd.collect_from_all_ranks() average_unit_cell = None - if self.mpi_helper.rank == 0: - if ucd.is_valid(): + if ucd.is_valid(): + if self.mpi_helper.rank == 0: ucd.show_histograms() - average_unit_cell = ucd.get_average_cell() - - self.logger.log_step_time("BROADCAST_UNIT_CELL") - average_unit_cell = self.mpi_helper.comm.bcast(average_unit_cell, root = 0) - self.logger.log_step_time("BROADCAST_UNIT_CELL", True) + average_unit_cell = ucd.get_average_cell() # save the average unit cell to the phil parameters if self.mpi_helper.rank == 0: From 3f9c8775be1e7b67917c7370e628c7bae18d10fc Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Fri, 6 Sep 2024 14:45:07 -0700 Subject: [PATCH 695/748] Reduce2: break down timing even more. Only process if cif restraints is provided in input. No need otherwise. --- mmtbx/hydrogens/reduce_hydrogen.py | 17 +++++++++++------ mmtbx/programs/hydrogenate.py | 13 ++++++++++--- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/mmtbx/hydrogens/reduce_hydrogen.py b/mmtbx/hydrogens/reduce_hydrogen.py index 944c27a5dc..441920b18b 100644 --- a/mmtbx/hydrogens/reduce_hydrogen.py +++ b/mmtbx/hydrogens/reduce_hydrogen.py @@ -196,7 +196,8 @@ def __init__(self, self.time_remove_isolated = None self.time_riding_manager = None self.time_remove_H_nopara = None - self.time_reset_idealize = None + self.time_reset = None + self.time_idealize = None self.time_remove_H_on_links = None # ------------------------------------------------------------------------------ @@ -336,8 +337,10 @@ def run(self): t0 = time.time() self.model.reset_adp_for_hydrogens(scale = self.adp_scale) self.model.reset_occupancy_for_hydrogens_simple() + self.time_reset = round(time.time()-t0, 2) + t0 = time.time() self.model.idealize_h_riding() - self.time_reset_idealize = round(time.time()-t0, 2) + self.time_idealize = round(time.time()-t0, 2) # Remove H atoms that are involved in links (bonds, metal coordination, etc) # -------------------------------------------------------------------------- @@ -658,7 +661,8 @@ def get_times(self): time_remove_isolated = self.time_remove_isolated, time_riding_manager = self.time_riding_manager, time_remove_H_nopara = self.time_remove_H_nopara, - time_reset_idealize = self.time_reset_idealize, + time_reset = self.time_reset, + time_idealize = self.time_idealize, time_remove_H_on_links = self.time_remove_H_on_links) # ------------------------------------------------------------------------------ @@ -667,13 +671,14 @@ def print_times(self): print('Detailed timings:') print("Rebox model:", self.time_rebox_model) print('Remove element X:', self.time_remove_element_X) - print("Add_missing_H_atoms_at_bogus_position:", self.time_add_missing_H) - print('Add N-terminal propeller', self.time_terminal_propeller) + print("Add missing H at bogus position:", self.time_add_missing_H) + print('Add N-terminal propeller:', self.time_terminal_propeller) print("Get new model obj and grm:", self.time_make_grm ) print("Remove isolated H:", self.time_remove_isolated) print("Setup Riding manager:", self.time_riding_manager) print("Remove H that were not parameterized:", self.time_remove_H_nopara) - print("Reset adp, occ; idealize H positions:", self.time_reset_idealize) + print("Reset adp, occ:", self.time_reset) + print("idealize H positions:", self.time_idealize) print("Remove H on links:", self.time_remove_H_on_links) print() diff --git a/mmtbx/programs/hydrogenate.py b/mmtbx/programs/hydrogenate.py index 5a5651afb1..fc8284205b 100644 --- a/mmtbx/programs/hydrogenate.py +++ b/mmtbx/programs/hydrogenate.py @@ -1,5 +1,5 @@ from __future__ import absolute_import, division, print_function -import os +import os, time from libtbx.program_template import ProgramTemplate #from libtbx.utils import null_out from libtbx import group_args @@ -55,9 +55,12 @@ def validate(self): # ---------------------------------------------------------------------------- def run(self): + t0 = time.time() self.model = self.data_manager.get_model() - self.model.set_stop_for_unknowns(False) - self.model.process(make_restraints=False) + if self.data_manager.has_restraints(): + self.model.set_stop_for_unknowns(False) + self.model.process(make_restraints=False) + time_get_model = round(time.time()-t0, 2) make_sub_header('Add H atoms', out=self.logger) hydrogenate_obj = reduce_hydrogen.place_hydrogens( @@ -74,6 +77,10 @@ def run(self): self.model = hydrogenate_obj.get_model() hydrogenate_obj.show(log = self.logger) + if self.params.print_time: + print("Get model obj in program template:", time_get_model) + hydrogenate_obj.print_times() + # Why is this done here and in the class? if self.params.add_h_to_water: self.model.add_hydrogens(1., occupancy=1.) From 4444ace020517ec26c9dd888c83ae268130bcee4 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sat, 7 Sep 2024 15:19:22 -0700 Subject: [PATCH 696/748] Do not allow ADP > 999 in rsr --- mmtbx/refinement/real_space/adp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/refinement/real_space/adp.py b/mmtbx/refinement/real_space/adp.py index 6257545f60..acd090953b 100644 --- a/mmtbx/refinement/real_space/adp.py +++ b/mmtbx/refinement/real_space/adp.py @@ -298,7 +298,7 @@ def run_one_one(self, args): for it in range(1,2): x = fmodel.xray_structure.extract_u_iso_or_u_equiv()*adptbx.u_as_b(1.) lower = flex.double(x.size(), 0) - upper = flex.double(x.size(), flex.max(x)*2) + upper = flex.double(x.size(), min(999,flex.max(x)*2) ) calculator = tg(fmodel = fmodel, x = x, restraints_weight = None) m = tncs.minimizer( potential = calculator, From 75b6f410f5638a1de5fadf47f388e24e12dde640 Mon Sep 17 00:00:00 2001 From: terwill Date: Sun, 8 Sep 2024 15:55:55 -0600 Subject: [PATCH 697/748] Allow external origin in ligandfit --- cctbx/maptbx/segment_and_split_map.py | 41 +++++++++++---------------- iotbx/map_manager.py | 1 - 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/cctbx/maptbx/segment_and_split_map.py b/cctbx/maptbx/segment_and_split_map.py index 7aa7621f3a..be85557334 100644 --- a/cctbx/maptbx/segment_and_split_map.py +++ b/cctbx/maptbx/segment_and_split_map.py @@ -2500,22 +2500,21 @@ def get_map_object(file_name = None, must_allow_sharpening = None, raise Sorry("The map file %s is missing..." %(file_name)) map_labels = None if file_name.endswith(".xplor"): - import iotbx.xplor.map - m = iotbx.xplor.map.reader(file_name = file_name) - m.unit_cell_grid = m.map_data().all() # just so we have something - m.space_group_number = 0 # so we have something - else: - from iotbx import mrcfile - m = mrcfile.map_reader(file_name = file_name) - print("MIN MAX MEAN RMS of map: %7.2f %7.2f %7.2f %7.2f " %( + raise Sorry("Unable to read xplor maps with segment_and_split_map") + from iotbx.data_manager import DataManager + dm = DataManager() + m = dm.get_real_map(file_name) + m.shift_origin() + + print("MIN MAX MEAN RMS of map: %7.2f %7.2f %7.2f %7.2f " %( m.header_min, m.header_max, m.header_mean, m.header_rms), file = out) - print("grid: ", m.unit_cell_grid, file = out) - print("cell: %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f " %tuple( + print("grid: ", m.unit_cell_grid, file = out) + print("cell: %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f " %tuple( m.unit_cell().parameters()), file = out) - print("SG: ", m.unit_cell_crystal_symmetry().space_group_number(), file = out) - if must_allow_sharpening and m.cannot_be_sharpened(): + print("SG: ", m.unit_cell_crystal_symmetry().space_group_number(), file = out) + if must_allow_sharpening and m.cannot_be_sharpened(): raise Sorry("Input map is already modified and should not be sharpened") - if get_map_labels: + if get_map_labels: map_labels = m.labels print("ORIGIN: ", m.map_data().origin(), file = out) print("EXTENT: ", m.map_data().all(), file = out) @@ -2523,18 +2522,10 @@ def get_map_object(file_name = None, must_allow_sharpening = None, map_data = m.data acc = map_data.accessor() - shift_needed = not \ - (map_data.focus_size_1d() > 0 and map_data.nd() == 3 and - map_data.is_0_based()) - if(shift_needed): - map_data = map_data.shift_origin() - origin_shift = ( - m.map_data().origin()[0]/m.map_data().all()[0], - m.map_data().origin()[1]/m.map_data().all()[1], - m.map_data().origin()[2]/m.map_data().all()[2]) - origin_frac = origin_shift # NOTE: fraction of NEW cell - else: - origin_frac = (0., 0., 0.) + origin_frac = ( + m.origin_shift_grid_units[0]/m.map_data().all()[0], + m.origin_shift_grid_units[1]/m.map_data().all()[1], + m.origin_shift_grid_units[2]/m.map_data().all()[2]) # determine if we need to trim off the outer part of the map duplicating inner offsets = [] need_offset = False diff --git a/iotbx/map_manager.py b/iotbx/map_manager.py index f7e2ae0252..6d1096cb46 100644 --- a/iotbx/map_manager.py +++ b/iotbx/map_manager.py @@ -700,7 +700,6 @@ def _get_shift_info(self, desired_origin = None, current_end = add_tuples_int(current_origin, self.map_data().all()) new_end = add_tuples_int(desired_origin, self.map_data().all()) - shift_to_apply_cart = self.grid_units_to_cart(shift_to_apply) shift_info = group_args( From 6927c852953fdb07c2d43bcc97a32743f88e0dda Mon Sep 17 00:00:00 2001 From: Russell Taylor Date: Tue, 10 Sep 2024 13:54:14 -0400 Subject: [PATCH 698/748] Don't shift the coordinates when doing box and shift for Reduce2 (#1012) --- mmtbx/programs/reduce2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/programs/reduce2.py b/mmtbx/programs/reduce2.py index 6b4e4896ea..2eee9f844f 100644 --- a/mmtbx/programs/reduce2.py +++ b/mmtbx/programs/reduce2.py @@ -1188,7 +1188,7 @@ def run(self): # @todo reduce_hydrogens.py:run() says: TODO temporary fix until the code is moved to model class cs = self.model.crystal_symmetry() if (cs is None) or (cs.unit_cell() is None): - self.model = shift_and_box_model(model = self.model) + self.model = shift_and_box_model(model = self.model, shift_model=False) # If we've been asked to only to a single model index from the file, strip the model down to # only that index. From 3360b226f28d8b2d71af5591d52e3a898d2fdb6e Mon Sep 17 00:00:00 2001 From: Russell Taylor Date: Wed, 11 Sep 2024 10:01:51 -0400 Subject: [PATCH 699/748] Pull chem_data for molprobity builder now that it is available publically (#1013) --- libtbx/auto_build/bootstrap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libtbx/auto_build/bootstrap.py b/libtbx/auto_build/bootstrap.py index 459e8019b2..37714c6ac6 100644 --- a/libtbx/auto_build/bootstrap.py +++ b/libtbx/auto_build/bootstrap.py @@ -2029,7 +2029,7 @@ class MOLPROBITYBuilder(Builder): ] CODEBASES_EXTRA = [ 'molprobity', - #'chem_data', #chem_data removed from molprobity builder until accessible outside cci, -CJW + 'chem_data', 'reduce', 'probe' ] From ba66eae0e0ea0247009ca0c14d41ab7e8ac59912 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 11 Sep 2024 12:30:32 -0400 Subject: [PATCH 700/748] Declutter Phenix: resurrect mp_validate_bonds --- mmtbx/command_line/mp_validate_bonds.py | 43 +++++++++++++ mmtbx/programs/mp_validate_bonds.py | 82 +++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 mmtbx/command_line/mp_validate_bonds.py create mode 100644 mmtbx/programs/mp_validate_bonds.py diff --git a/mmtbx/command_line/mp_validate_bonds.py b/mmtbx/command_line/mp_validate_bonds.py new file mode 100644 index 0000000000..aad4a60a33 --- /dev/null +++ b/mmtbx/command_line/mp_validate_bonds.py @@ -0,0 +1,43 @@ +# LIBTBX_SET_DISPATCHER_NAME phenix.mp_validate_bonds +# LIBTBX_SET_DISPATCHER_NAME molprobity.mp_validate_bonds + +from __future__ import absolute_import, division, print_function +import sys +from iotbx.cli_parser import CCTBXParser +from libtbx.utils import multi_out, show_total_time +from mmtbx.programs import mp_validate_bonds +from iotbx.cli_parser import run_program + +def old_run(args, out=sys.stdout, quiet=False): + # create parser + logger = multi_out() + logger.register('stderr', sys.stderr) + logger2 = multi_out() + logger2.register('stdout', sys.stdout) + + parser = CCTBXParser( + program_class=mp_validate_bonds.Program, + logger=logger) + namespace = parser.parse_args(sys.argv[1:]) + + # start program + print('Starting job', file=logger) + print('='*79, file=logger) + task = mp_validate_bonds.Program( + parser.data_manager, parser.working_phil.extract(), logger=logger2) + + # validate inputs + task.validate() + + # run program + task.run() + + # stop timer + print('', file=logger) + print('='*79, file=logger) + print('Job complete', file=logger) + show_total_time(out=logger) + +if (__name__ == "__main__"): + #run(sys.argv[1:]) + run_program(program_class=mp_validate_bonds.Program, hide_parsing_output=True) diff --git a/mmtbx/programs/mp_validate_bonds.py b/mmtbx/programs/mp_validate_bonds.py new file mode 100644 index 0000000000..ff409009d9 --- /dev/null +++ b/mmtbx/programs/mp_validate_bonds.py @@ -0,0 +1,82 @@ +from __future__ import absolute_import, division, print_function + +import os +from mmtbx.model import manager +from libtbx.program_template import ProgramTemplate +from libtbx.utils import null_out +import json +from mmtbx.validation.mp_validate_bonds import mp_validate_bonds +from datetime import datetime + +class Program(ProgramTemplate): + prog = os.getenv('LIBTBX_DISPATCHER_NAME') + description="""\ +%(prog)s file.pdb [params.eff] [options ...] + +Options: + + model=input_file input PDB file + outliers_only=False only print outliers + json=False Outputs results as JSON compatible dictionary + use_cdl=True Use the Conformational Dependent Library (cdl) for reference values + verbose=False verbose text output + +Example: + + %(prog)s model=1ubq.pdb outliers_only=True +""" % locals() + + master_phil_str = """ + include scope mmtbx.validation.molprobity_cmdline_phil_str + show_errors = False + .type = bool + .help = '''Print out errors''' + json = False + .type = bool + .help = "Prints results as JSON format dictionary" + use_cdl = True + .type = bool + .help = "Use conformational dependent library for reference values" + use_parent = False + .type = bool + """ + datatypes = ['model','phil'] + data_manager_options = ['model_skip_expand_with_mtrix'] + known_article_ids = ['molprobity'] + + def validate(self): + self.data_manager.has_models(raise_sorry=True) + + def run(self): + model = self.data_manager.get_model() + model.set_stop_for_unknowns(False) + hierarchy = model.get_hierarchy() + self.info_json = {"model_name":self.data_manager.get_default_model_name(), + "time_analyzed": str(datetime.now()), + "params": {"use_cdl":self.params.use_cdl, + "outliers_only":self.params.outliers_only, + }} + p = manager.get_default_pdb_interpretation_params() + ##print(dir(p.pdb_interpretation)) + p.pdb_interpretation.allow_polymer_cross_special_position=True + p.pdb_interpretation.flip_symmetric_amino_acids=False + p.pdb_interpretation.clash_guard.nonbonded_distance_threshold = None + p.pdb_interpretation.restraints_library.cdl=self.params.use_cdl + model.set_log(log = null_out()) + model.process(make_restraints=True, pdb_interpretation_params=p) + geometry = model.get_restraints_manager().geometry + atoms = hierarchy.atoms() + self.results = mp_validate_bonds( + pdb_hierarchy=hierarchy, + geometry_restraints_manager=geometry, + outliers_only=self.params.outliers_only) + if self.params.json: + print(self.results.as_JSON(addon_json=self.info_json), file=self.logger) + elif self.params.verbose: + self.results.show(out=self.logger, verbose=True) + + def get_results(self): + return self.results + + def get_results_as_JSON(self): + return self.results.as_JSON(self.info_json) From 412052b2c7cf09d095528f0f3ea610fe4d75629e Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 11 Sep 2024 15:55:48 -0400 Subject: [PATCH 701/748] CI: start Python 3.13 syntax check [skip ci] --- .azure-pipelines/syntax.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.azure-pipelines/syntax.yml b/.azure-pipelines/syntax.yml index a0596e20b2..9f1299611b 100644 --- a/.azure-pipelines/syntax.yml +++ b/.azure-pipelines/syntax.yml @@ -22,6 +22,8 @@ jobs: PYTHON_VERSION: 3.11 python3.12: PYTHON_VERSION: 3.12 + python3.13: + PYTHON_VERSION: 3.13 steps: @@ -34,6 +36,15 @@ jobs: - script: | conda create -y -c conda-forge -n py$(PYTHON_VERSION) python=$(PYTHON_VERSION) six future scons displayName: Create conda environment + condition: ne(variables['PYTHON_VERSION'], '3.13') + + - script: | + conda create -y -c conda-forge -c conda-forge/label/python_rc -n py$(PYTHON_VERSION) python=$(PYTHON_VERSION) six future setuptools + conda activate py$(PYTHON_VERSION) + cd $(Pipeline.Workspace)/modules + git clone -b 4.8.1 https://github.com/SCons/scons.git + displayName: Create conda environment + condition: eq(variables['PYTHON_VERSION'], '3.13') - script: | set -xe From 865e8e3e193df6a8e6ea5f1c36080a7ab8d26d81 Mon Sep 17 00:00:00 2001 From: David Moreau Date: Wed, 11 Sep 2024 18:38:45 -0700 Subject: [PATCH 702/748] Mm24 correlation bug fix (#1014) * Updates to the MM24 algorithm to prevent sadd optimizing to zero * Additional matplotlib import --- .../application/errors/error_modifier_mm24.py | 133 ++++++------------ xfel/merging/application/phil/phil.py | 3 - 2 files changed, 40 insertions(+), 96 deletions(-) diff --git a/xfel/merging/application/errors/error_modifier_mm24.py b/xfel/merging/application/errors/error_modifier_mm24.py index 259ca5b7da..f2ffa2b417 100644 --- a/xfel/merging/application/errors/error_modifier_mm24.py +++ b/xfel/merging/application/errors/error_modifier_mm24.py @@ -22,7 +22,6 @@ def __init__(self, params, mpi_helper=None, mpi_logger=None): else: self.limit_differences = False - self.n_coefs = self.params.merging.error.mm24.n_degrees + 1 self.tuning_param = self.params.merging.error.mm24.tuning_param self.number_of_intensity_bins = self.params.merging.error.mm24.number_of_intensity_bins if self.params.merging.error.mm24.cc_after_pr: @@ -53,6 +52,7 @@ def modify_errors(self, reflections): # Run LBFGSB minimizer # -- only rank0 does minimization but gradients/functionals are calculated using all rank self.run_minimizer() + if self.params.merging.error.mm24.do_diagnostics: self.plot_diagnostics(reflections) # Finally update the variances of each reflection as per Eq (10) in Brewster et. al (2019) @@ -252,7 +252,9 @@ def target_fun_scalar(sadd, bin_centers, mean_differences): bin_centers = bin_centers[positive_indices] mean_differences = mean_differences[positive_indices] - self.sadd = [0 for i in range(self.n_coefs)] + self.sadd = [0, 0.001, 0.001] + self.sadd[1] = 0.001 + self.sadd[2] = 0.001 if self.expected_sf is None: results = scipy.optimize.minimize( target_fun_bfgs, @@ -262,7 +264,7 @@ def target_fun_scalar(sadd, bin_centers, mean_differences): method='BFGS' ) self.sfac = abs(float(results.x[0])) - self.sadd[0] = abs(float(results.x[1])) + self.sadd[0] = math.sqrt(abs(float(results.x[1]))) fit_curve = fitting_equation(results.x, bin_centers, mean_differences[0], False) else: results = scipy.optimize.minimize_scalar( @@ -271,7 +273,7 @@ def target_fun_scalar(sadd, bin_centers, mean_differences): args=(bin_centers, mean_differences), ) self.sfac = self.expected_sf - self.sadd[0] = abs(float(results.x)) + self.sadd[0] = math.sqrt(abs(float(results.x))) if self.params.merging.error.mm24.do_diagnostics: import matplotlib.pyplot as plt @@ -292,7 +294,7 @@ def target_fun_scalar(sadd, bin_centers, mean_differences): else: self.sfac = 0 - self.sadd = [0 for i in range(self.n_coefs)] + self.sadd = [0, 0, 0] self.sfac = self.mpi_helper.comm.bcast(self.sfac, root=0) self.sadd = self.mpi_helper.comm.bcast(self.sadd, root=0) @@ -311,7 +313,7 @@ def run_minimizer(self): param_offset = 1 param_shift = 0 self.x = flex.double([self.sfac, *self.sadd]) - self.n = self.n_coefs + param_offset + self.n = 3 + param_offset if self.mpi_helper.rank == 0: self.logger.main_log( 'Initial Parameter Estimates = ' @@ -326,7 +328,7 @@ def run_minimizer(self): l[0] = 2 if self.x[0] < 2: self.x[0] = 2 - for degree_index in range(self.n_coefs): + for degree_index in range(3): l[degree_index + param_offset] = -1000 if self.mpi_helper.rank == 0: self.minimizer = lbfgsb.minimizer( @@ -346,7 +348,7 @@ def run_minimizer(self): self.sfac = self.x[0 + param_shift] self.sadd = self.x[1 + param_shift:] sfac = f'{self.sfac:0.3f}' - sadd = [f'{self.sadd[i]:0.3f}' for i in range(self.n_coefs)] + sadd = [f'{self.sadd[i]:0.3f}' for i in range(3)] log_out = 'intermediate minimization results = '\ + f'loss: {self.L:.2f} '\ + f'sfac: {sfac} '\ @@ -371,7 +373,7 @@ def run_minimizer(self): if self.mpi_helper.rank == 0: tuning_param = f'{self.tuning_param:0.3f}' sfac = f'{self.sfac:0.3f}' - sadd = [f'{self.sadd[i]:0.3f}' for i in range(self.n_coefs)] + sadd = [f'{self.sadd[i]:0.3f}' for i in range(3)] log_out = 'FINAL mm24 VALUES = '\ + f'loss: {self.L:.2f} '\ + f'sfac: {sfac} '\ @@ -392,9 +394,9 @@ def verify_derivatives(self): shift = 0.000001 import copy if self.params.merging.error.mm24.tuning_param_opt: - self.n = self.n_coefs + 3 + self.n = 6 else: - self.n = self.n_coefs + 2 + self.n = 5 self.calculate_functional() sfac = copy.copy(self.sfac) @@ -437,7 +439,7 @@ def verify_derivatives(self): print(f'der_wrt_sfac numerical: {check_der_wrt_sfac} analytical {der_wrt_sfac}') # sadd: - for degree_index in range(self.n_coefs): + for degree_index in range(3): if sadd[degree_index] == 0: self.sadd[degree_index] = shift else: @@ -526,21 +528,23 @@ def _loss_function_t_v_opt(self, differences, var_i, var_j): dL_dv = dL0_dv + dL2_dv + dL3_dv + dL5_dv return L, dL_dvar, dL_dv - def _get_sadd(self, correlation): - sadd = flex.double(len(correlation), 0) - dsadd_dsaddi = [flex.double(len(correlation), 0) for i in range(self.n_coefs)] - for degree_index in range(self.n_coefs): - sadd += self.sadd[degree_index] * correlation**degree_index - dsadd_dsaddi[degree_index] = correlation**degree_index - return sadd, dsadd_dsaddi + def _get_sadd2(self, correlation): + term1 = flex.exp(-self.sadd[1] * correlation) + sadd2 = self.sadd[0]**2 * term1 + self.sadd[2]**2 + dsadd2_dsaddi = [ + 2 * self.sadd[0] * term1, + -correlation * self.sadd[0]**2 * term1, + 2 * self.sadd[2] * flex.double(len(correlation), 1) + ] + return sadd2, dsadd2_dsaddi def _get_var_mm24(self, counting_err, biased_mean, correlation, return_der=False): - sadd, dsadd_dsaddi = self._get_sadd(correlation) - var = self.sfac**2 * (counting_err + sadd**2 * biased_mean**2) + sadd2, dsadd2_dsaddi = self._get_sadd2(correlation) + var = self.sfac**2 * (counting_err + sadd2 * biased_mean**2) if return_der: - dvar_dsfac = 2 * self.sfac * (counting_err + sadd**2 * biased_mean**2) - dvar_dsadd = 2 * self.sfac**2 * sadd * biased_mean**2 - return var, dvar_dsfac, dvar_dsadd, dsadd_dsaddi + dvar_dsfac = 2 * self.sfac * (counting_err + sadd2 * biased_mean**2) + dvar_dsadd2 = self.sfac**2 * biased_mean**2 + return var, dvar_dsfac, dvar_dsadd2, dsadd2_dsaddi else: return var @@ -549,19 +553,19 @@ def calculate_functional(self): MPI = self.mpi_helper.MPI L_bin_rank = flex.double(self.number_of_intensity_bins, 0) dL_dsfac_bin_rank = flex.double(self.number_of_intensity_bins, 0) - dL_dsadd_bin_rank = [flex.double(self.number_of_intensity_bins, 0) for i in range(self.n_coefs)] + dL_dsadd_bin_rank = [flex.double(self.number_of_intensity_bins, 0) for i in range(3)] if self.params.merging.error.mm24.tuning_param_opt: dL_dnu_bin_rank = flex.double(self.number_of_intensity_bins, 0) for bin_index, differences in enumerate(self.intensity_bins): if len(differences) > 0: - var_i, dvar_i_dsfac, dvar_i_dsadd, dsadd_i_dsaddi = self._get_var_mm24( + var_i, dvar_i_dsfac, dvar_i_dsadd2, dsadd2_i_dsaddi = self._get_var_mm24( differences['counting_stats_var_i'], differences['biased_mean'], differences['correlation_i'], return_der=True ) - var_j, dvar_j_dsfac, dvar_j_dsadd, dsadd_j_dsaddi = self._get_var_mm24( + var_j, dvar_j_dsfac, dvar_j_dsadd2, dsadd2_j_dsaddi = self._get_var_mm24( differences['counting_stats_var_j'], differences['biased_mean'], differences['correlation_j'], @@ -585,15 +589,15 @@ def calculate_functional(self): L_bin_rank[bin_index] = flex.sum(L_in_bin) dL_dsfac_bin_rank[bin_index] = flex.sum(dL_dvar_x * (dvar_i_dsfac + dvar_j_dsfac)) - for degree_index in range(self.n_coefs): + for degree_index in range(3): dL_dsadd_bin_rank[degree_index][bin_index] = flex.sum(dL_dvar_x * ( - dvar_i_dsadd * dsadd_i_dsaddi[degree_index] + dvar_j_dsadd * dsadd_j_dsaddi[degree_index] + dvar_i_dsadd2 * dsadd2_i_dsaddi[degree_index] + dvar_j_dsadd2 * dsadd2_j_dsaddi[degree_index] )) L_bin = comm.reduce(L_bin_rank, MPI.SUM, root=0) dL_dsfac_bin = comm.reduce(dL_dsfac_bin_rank, MPI.SUM, root=0) - dL_dsadd_bin = [None for i in range(self.n_coefs)] - for degree_index in range(self.n_coefs): + dL_dsadd_bin = [None for i in range(3)] + for degree_index in range(3): dL_dsadd_bin[degree_index] = comm.reduce(dL_dsadd_bin_rank[degree_index], MPI.SUM, root=0) if self.params.merging.error.mm24.tuning_param_opt: dL_dnu_bin = comm.reduce(dL_dnu_bin_rank, MPI.SUM, root=0) @@ -601,13 +605,14 @@ def calculate_functional(self): if self.mpi_helper.rank == 0: self.L = flex.sum(self.bin_weighting * L_bin) self.dL_dsfac = flex.sum(self.bin_weighting * dL_dsfac_bin) - self.dL_dsadd = [0 for i in range(self.n_coefs)] - for degree_index in range(self.n_coefs): + self.dL_dsadd = [0 for i in range(3)] + for degree_index in range(3): self.dL_dsadd[degree_index] = flex.sum(self.bin_weighting * dL_dsadd_bin[degree_index]) if self.params.merging.error.mm24.tuning_param_opt: self.dL_dnu = flex.sum(self.bin_weighting * dL_dnu_bin) def plot_diagnostics(self, reflections): + import matplotlib.pyplot as plt I_scale = 100000 def get_rankits(n, down_sample, distribution): prob_level = (np.arange(1, n+1) - 0.5) / n @@ -644,26 +649,6 @@ def min_fun_t(c, df): conversion_factor = None conversion_factor = self.mpi_helper.comm.bcast(conversion_factor) - # Setup for the ENCE calculation - variance = self._get_var_mm24( - reflections['intensity.sum.variance'], - reflections['biased_mean'], - reflections[self.cc_key] - ).as_numpy_array() - variance.sort() - lower = self.mpi_helper.comm.gather(variance[int(0.005 * variance.size)]) - upper = self.mpi_helper.comm.gather(variance[int(0.995 * variance.size)]) - n_ENCE_bins = 25 - if self.mpi_helper.rank == 0: - ENCE_bins = np.linspace(np.sqrt(10*np.median(lower)), np.sqrt(np.median(upper)), n_ENCE_bins + 1) - else: - ENCE_bins = np.empty(n_ENCE_bins + 1) - self.mpi_helper.comm.Bcast(ENCE_bins, root=0) - ENCE_centers = (ENCE_bins[1:] + ENCE_bins[:-1]) / 2 - ENCE_counts_rank = np.zeros(n_ENCE_bins, dtype=int) - ENCE_sum_V_rank = np.zeros(n_ENCE_bins) - ENCE_sum_D_rank = np.zeros(n_ENCE_bins) - median_differences = [[] for i in range(self.number_of_intensity_bins)] for refls in reflection_table_utils.get_next_hkl_reflection_table(reflections): number_of_reflections = refls.size() @@ -686,44 +671,6 @@ def min_fun_t(c, df): median_differences[bin_index].append( np.median(differences / np.sqrt(variances), axis=1) ) - # Calculations for ENCE - triu_indices = np.triu_indices(n=I.size, k=1) - differences = differences[triu_indices[0], triu_indices[1]] - variances = variances[triu_indices[0], triu_indices[1]] - bin_indices = np.searchsorted(ENCE_bins, np.sqrt(variances)) - in_range = np.logical_and(bin_indices >= 0, bin_indices < n_ENCE_bins) - ENCE_counts_rank[bin_indices[in_range]] += 1 - ENCE_sum_V_rank[bin_indices[in_range]] += variances[in_range] - ENCE_sum_D_rank[bin_indices[in_range]] += differences[in_range]**2 - ENCE_counts = np.empty(n_ENCE_bins, dtype=int) - ENCE_sum_V = np.empty(n_ENCE_bins) - ENCE_sum_D = np.empty(n_ENCE_bins) - self.mpi_helper.comm.Reduce(ENCE_counts_rank, ENCE_counts, op=self.mpi_helper.MPI.SUM, root=0) - self.mpi_helper.comm.Reduce(ENCE_sum_V_rank, ENCE_sum_V, op=self.mpi_helper.MPI.SUM, root=0) - self.mpi_helper.comm.Reduce(ENCE_sum_D_rank, ENCE_sum_D, op=self.mpi_helper.MPI.SUM, root=0) - - # Reliability plot and ENCE - if self.mpi_helper.rank == 0: - import matplotlib.pyplot as plt - ENCE_RMV = np.sqrt(ENCE_sum_V / ENCE_counts) / I_scale - ENCE_RMD = np.sqrt(ENCE_sum_D / ENCE_counts) / I_scale - ENCE = np.abs(ENCE_RMV - ENCE_RMD) / ENCE_RMV - good_bins = ENCE_counts > 0 - fig, axes = plt.subplots(2, 1, figsize=(3, 4), sharex=True) - lims = [ENCE_RMV[good_bins].min(), ENCE_RMV[good_bins].max()] - axes[0].plot(lims, lims, color=[0, 0, 0]) - axes[0].plot(ENCE_RMV[good_bins], ENCE_RMD[good_bins]) - axes[1].plot(ENCE_RMV[good_bins], ENCE[good_bins]) - axes[0].set_title(f'ENCE: {ENCE.mean():0.03f}') - axes[0].set_ylabel('Root mean difference\n(x 100,000)') - axes[1].set_ylabel('ENCE') - axes[1].set_xlabel('Root mean variance\n(x 100,000)') - fig.tight_layout() - fig.savefig(os.path.join( - self.params.output.output_dir, - self.params.output.prefix + '_ENCE.png' - )) - plt.close() binned_scale = np.zeros(self.number_of_intensity_bins) for bin_index in range(self.number_of_intensity_bins): @@ -850,11 +797,11 @@ def min_fun_t(c, df): hist_color = np.array([0, 49, 60]) / 256 line_color = np.array([213, 120, 0]) / 256 - sadd, _ = self._get_sadd(flex.double(centers)) + sadd2, _ = self._get_sadd2(flex.double(centers)) fig, axes_hist = plt.subplots(1, 1, figsize=(5, 3)) axes_sadd = axes_hist.twinx() axes_hist.bar(centers, hist_all / 1000, width=dbin, color=hist_color) - axes_sadd.plot(centers, (self.sfac * sadd)**2, color=line_color) + axes_sadd.plot(centers, self.sfac**2 * sadd2, color=line_color) axes_hist.set_xlabel('Correlation Coefficient') axes_hist.set_ylabel('Lattices (x1,000)') axes_sadd.set_ylabel('$s_{\mathrm{fac}}^2 \\times s_{\mathrm{add}}^2$') diff --git a/xfel/merging/application/phil/phil.py b/xfel/merging/application/phil/phil.py index cc9895b3cb..327550717d 100644 --- a/xfel/merging/application/phil/phil.py +++ b/xfel/merging/application/phil/phil.py @@ -529,9 +529,6 @@ number_of_intensity_bins = 100 .help = Number of intensity bins .type = int - n_degrees = 2 - .help = s_add as a n_degree polynomial of the correlation coefficient - .type = int tuning_param = 10 .help = Tuning param for t-dist in maximum log likelihood .type = float From bd69e48f4fcee87432574c0c1c2c041cc0596085 Mon Sep 17 00:00:00 2001 From: randyjread Date: Mon, 16 Sep 2024 12:03:32 +0100 Subject: [PATCH 703/748] Fix bug in relative weight of fixed model contribution. Allow fixed model to be used without specifying total composition. Tidy up code so it's not relying as much on automatic naming of different elements of mmm object. --- cctbx/maptbx/prepare_map_for_docking.py | 121 +++++++++++------- .../regression/tst_prepare_map_for_docking.py | 6 +- 2 files changed, 76 insertions(+), 51 deletions(-) diff --git a/cctbx/maptbx/prepare_map_for_docking.py b/cctbx/maptbx/prepare_map_for_docking.py index cb57498fe8..5d3a451710 100644 --- a/cctbx/maptbx/prepare_map_for_docking.py +++ b/cctbx/maptbx/prepare_map_for_docking.py @@ -820,7 +820,7 @@ def sphere_enclosing_model(model): def mask_fixed_model_region(mmm, d_min, fixed_model=None, - ordered_mask_id='ordered_volume_mask', + ordered_mask_id=None, fixed_mask_id='mask_around_atoms'): # Flatten the region of the ordered volume mask covered by the fixed model # and keep the mask for the fixed model. @@ -834,11 +834,13 @@ def mask_fixed_model_region(mmm, d_min, radius = max(radius, d_min) mmm.create_mask_around_atoms(model=fixed_model, mask_atoms_atom_radius=radius, mask_id=fixed_mask_id) fixed_model_mask = mmm.get_map_manager_by_id(map_id=fixed_mask_id) - # Invert fixed_model_mask before flattening - fixed_model_mask.set_map_data(map_data = 1. - fixed_model_mask.map_data()) - mmm.apply_mask_to_map(map_id=ordered_mask_id, mask_id=fixed_mask_id) - # Invert back so we can use to assess fraction of fixed model in masked sphere - fixed_model_mask.set_map_data(map_data = 1. - fixed_model_mask.map_data()) + + if ordered_mask_id is not None: + # Invert fixed_model_mask before flattening + fixed_model_mask.set_map_data(map_data = 1. - fixed_model_mask.map_data()) + mmm.apply_mask_to_map(map_id=ordered_mask_id, mask_id=fixed_mask_id) + # Invert back so we can use to assess fraction of fixed model in masked sphere + fixed_model_mask.set_map_data(map_data = 1. - fixed_model_mask.map_data()) def add_local_squared_deviation_map( mmm, coeffs_in, radius, d_min, map_id_out): @@ -943,7 +945,7 @@ def auto_sharpen_isotropic(mc1, mc2): def add_ordered_volume_mask( mmm, d_min, rad_factor=2, protein_mw=None, nucleic_mw=None, - map_id_out='ordered_volume_mask'): + ordered_mask_id='ordered_volume_mask'): """ Add map defining mask covering the volume of most ordered density required to contain the specified content of protein and nucleic acid, judged by @@ -958,7 +960,7 @@ def add_ordered_volume_mask( sphere, defaults to 2 protein_mw*: molecular weight of protein expected in map, if any nucleic_mw*: molecular weight of nucleic acid expected in map - map_id_out: identifier of output map, defaults to ordered_volume_mask + ordered_mask_id: identifier of output map, defaults to ordered_volume_mask * Note that at least one of protein_mw and nucleic_mw must be specified, and that the map must be complete @@ -1033,7 +1035,7 @@ def add_ordered_volume_mask( # Clean up temporary map, then add ordered volume mask mmm.remove_map_manager_by_id('map_variance') - mmm.add_map_manager_by_id(new_mm,map_id=map_id_out) + mmm.add_map_manager_by_id(new_mm,map_id=ordered_mask_id) def get_grid_spacings(unit_cell, unit_cell_grid): if unit_cell.parameters()[3:] != (90,90,90): @@ -1512,8 +1514,8 @@ def sigmaA_from_model_in_map(expectE, dobs, Ecalc, over_sampling_factor, def assess_cryoem_errors( mmm, d_min, determine_ordered_volume=True, - ordered_mask_id='ordered_volume_mask', sphere_points=500, - sphere_cent=None, radius=None, + ordered_mask_id=None, fixed_mask_id=None, + sphere_points=500, sphere_cent=None, radius=None, verbosity=1, shift_map_origin=True, keep_full_map=False, log=sys.stdout): """ Refine error parameters from half-maps, make weighted map coeffs for region. @@ -1562,12 +1564,12 @@ def assess_cryoem_errors( spacings = get_grid_spacings(unit_cell,unit_cell_grid) ucpars = unit_cell.parameters() # Determine voxel count for fixed model mask - mm_model_mask = mmm.get_map_manager_by_id('mask_around_atoms') - voxels_in_model = 0 + mm_model_mask = mmm.get_map_manager_by_id(fixed_mask_id) + voxels_in_fixed_model = 0 if mm_model_mask is not None: model_mask_data = mm_model_mask.map_data() mask_sel = model_mask_data > 0 - voxels_in_model = mask_sel.count(True) + voxels_in_fixed_model = mask_sel.count(True) # Keep track of shifted origin origin_shift = mmm.map_manager().origin_shift_grid_units @@ -1672,9 +1674,9 @@ def assess_cryoem_errors( weighted_masked_volume = box_volume * mask_info.mean voxels_in_masked_model = 0 - if voxels_in_model > 0: - mask_info = working_mmm.mask_info(mask_id='mask_around_atoms') - mm_model_mask = working_mmm.get_map_manager_by_id('mask_around_atoms') + if voxels_in_fixed_model > 0: + mask_info = working_mmm.mask_info(mask_id=fixed_mask_id) + mm_model_mask = working_mmm.get_map_manager_by_id(fixed_mask_id) model_mask_data = mm_model_mask.map_data() voxels_in_masked_model = working_map_size * mask_info.mean @@ -1974,18 +1976,6 @@ def assess_cryoem_errors( print("Weighted map noise: ",weighted_map_noise, file=log) sys.stdout.flush() - # Return a map_model_manager with the weighted map - wEmean = dobs*expectE - working_mmm.add_map_from_fourier_coefficients(map_coeffs=wEmean, map_id='map_manager_wtd') - sigmaA = 0.9 # Default for likelihood-weighted map - dosa = sigmaA*dobs.data() - lweight = dobs.customized_copy(data=(2*dosa)/(1.-flex.pow2(dosa))) - wEmean2 = lweight*expectE - working_mmm.add_map_from_fourier_coefficients(map_coeffs=wEmean2, map_id='map_manager_lwtd') - # working_mmm.write_map(map_id='map_manager_wtd',file_name='prepmap.map') - working_mmm.remove_map_manager_by_id('map_manager_1') - working_mmm.remove_map_manager_by_id('map_manager_2') - # If there is a fixed model and it occupies a significant part of the sphere, # compute the structure factors corresponding to the cutout density for the fixed # model. @@ -2003,6 +1993,25 @@ def assess_cryoem_errors( # mm_masked_model.write_map('masked_model.map') masked_model_E = mm_masked_model.map_as_fourier_coefficients(d_min=d_min,d_max=d_max) + if masked_model_contributes: + masked_model_sigmaA = sigmaA_from_model_in_map(expectE, dobs, masked_model_E, over_sampling_factor, verbosity) + # Possibly temporary choice: modify expectE instead of adding fixed contribution in phasertng + expectE_mod = expectE.customized_copy(data=expectE.data() + - masked_model_sigmaA.data()*masked_model_E.data()) + else: + expectE_mod = expectE.deep_copy() + + # Return map_model_managers with weighted maps + wEmean = dobs*expectE_mod + working_mmm.add_map_from_fourier_coefficients(map_coeffs=wEmean, map_id='map_manager_wtd') + sigmaA = 0.9 # Default for likelihood-weighted map + dosa = sigmaA*dobs.data() + lweight = dobs.customized_copy(data=(2*dosa)/(1.-flex.pow2(dosa))) + wEmean2 = lweight*expectE_mod + working_mmm.add_map_from_fourier_coefficients(map_coeffs=wEmean2, map_id='map_manager_lwtd') + working_mmm.remove_map_manager_by_id('map_manager_1') + working_mmm.remove_map_manager_by_id('map_manager_2') + shift_cart = working_mmm.shift_cart() if shift_map_origin: ucwork = expectE.crystal_symmetry().unit_cell() @@ -2012,20 +2021,13 @@ def assess_cryoem_errors( shift_frac = ucwork.fractionalize(shift_cart) shift_frac = tuple(-flex.double(shift_frac)) expectE = expectE.translational_shift(shift_frac) + expectE_mod = expectE_mod.translational_shift(shift_frac) if masked_model_contributes: masked_model_E = masked_model_E.translational_shift(shift_frac) # write_mtz(expectE,"expectE.mtz","eE") + # write_mtz(expectE_mod,"expectE_mod.mtz","expectEmod") # write_mtz(masked_model_E,"masked_model.mtz","masked_model") - if masked_model_contributes: - masked_model_sigmaA = sigmaA_from_model_in_map(expectE, dobs, masked_model_E, over_sampling_factor, verbosity) - # Temporary kludge where expectE is modified instead of adding fixed contribution in phasertng - expectE_mod = expectE.customized_copy(data=expectE.data() - - masked_model_sigmaA.data()*dobs.data()*masked_model_E.data()) - # write_mtz(expectE_mod,"expectE_mod.mtz","expectEmod") - else: - expectE_mod = expectE.deep_copy() - ssqmin = flex.min(mc1.d_star_sq().data()) ssqmax = flex.max(mc1.d_star_sq().data()) resultsdict = dict( @@ -2078,6 +2080,7 @@ def run(): --no_determine_ordered_volume: don't determine ordered volume default False --file_root: root name for output files + --write_maps: write sharpened and likelihood-weighted maps --mute (or -m): mute output --verbose (or -v): verbose output --testing: extra verbose output for debugging @@ -2102,7 +2105,9 @@ def run(): parser.add_argument('--sphere_points',help='Target nrefs in averaging sphere', type=float, default=500.) parser.add_argument('--model', - help='Optional placed model defining size and position of cut-out sphere') + help='''Optional roughly-placed model defining size and + position of cut-out sphere for docking. + Orientation of model is ignored.''') parser.add_argument('--fixed_model', help='Optional fixed model accounting for explained map features') parser.add_argument('--sphere_cent', @@ -2113,12 +2118,14 @@ def run(): type=float) parser.add_argument('--file_root', help='Root of filenames for output') + parser.add_argument('--write_maps', help = 'Write sharpened and likelihood-weighted maps', + action = 'store_true') parser.add_argument('--no_shift_map_origin', action='store_true') parser.add_argument('--no_determine_ordered_volume', action='store_true') parser.add_argument('-m', '--mute', help = 'Mute output', action = 'store_true') parser.add_argument('-v', '--verbose', help = 'Set output as verbose', action = 'store_true') - parser.add_argument('--testing', help='Set output as testing', action='store_true') + parser.add_argument('--testing', help='Set output as testing level', action='store_true') args = parser.parse_args() d_min = args.d_min verbosity = 1 @@ -2181,35 +2188,43 @@ def run(): mmm.add_model_by_id(model=fixed_model, model_id='fixed_model') mmm.generate_map(model=fixed_model, d_min=d_min, map_id='fixed_atom_map') + ordered_mask_id = None if determine_ordered_volume: - mask_id = 'ordered_volume_mask' + ordered_mask_id = 'ordered_volume_mask' add_ordered_volume_mask(mmm, d_min, protein_mw=protein_mw, nucleic_mw=nucleic_mw, - map_id_out=mask_id) - if fixed_model: - mask_fixed_model_region(mmm, d_min, fixed_model=fixed_model) + ordered_mask_id=ordered_mask_id) if verbosity>1: - ordered_mm = mmm.get_map_manager_by_id(map_id=mask_id) + ordered_mm = mmm.get_map_manager_by_id(map_id=ordered_mask_id) if args.file_root is not None: map_file_name = args.file_root + "_ordered_volume_mask.map" else: map_file_name = "ordered_volume_mask.map" ordered_mm.write_map(map_file_name) + fixed_mask_id = None + if fixed_model: + fixed_mask_id = 'mask_around_atoms' + mask_fixed_model_region(mmm, d_min, + fixed_model=fixed_model, + ordered_mask_id=ordered_mask_id, + fixed_mask_id=fixed_mask_id) + # Default to sphere containing most of ordered volume if not cutout_specified: ucpars = mm1.unit_cell().parameters() sphere_cent = (ucpars[0]/2,ucpars[1]/2,ucpars[2]/2) if determine_ordered_volume: target_completeness = 0.98 - radius = get_mask_radius(mmm.get_map_manager_by_id(mask_id),target_completeness) + radius = get_mask_radius(mmm.get_map_manager_by_id(ordered_mask_id),target_completeness) else: radius = min(ucpars[0],ucpars[1],ucpars[2])/4. # Refine to get scale and error parameters for docking region results = assess_cryoem_errors(mmm, d_min, sphere_points=sphere_points, determine_ordered_volume=determine_ordered_volume, verbosity=verbosity, - sphere_cent=sphere_cent, radius=radius, shift_map_origin=shift_map_origin) + sphere_cent=sphere_cent, radius=radius, shift_map_origin=shift_map_origin, + ordered_mask_id=ordered_mask_id, fixed_mask_id=fixed_mask_id) expectE = results.expectE mtz_dataset = expectE.as_mtz_dataset(column_root_label='Emean') @@ -2220,13 +2235,23 @@ def run(): if args.file_root is not None: mtzout_file_name = args.file_root + ".mtz" + mapout1_file_name = args.file_root + "_weighted.map" + mapout2_file_name = args.file_root + "_likelihood_weighted.map" else: mtzout_file_name = "weighted_map_data.mtz" - print ("Writing mtz for docking as",mtzout_file_name) + mapout1_file_name = "weighted.map" + mapout2_file_name = "likelihood_weighted.map" + print ("Writing mtz for docking as", mtzout_file_name) if not shift_map_origin: shift_cart = results.shift_cart print ("Origin of full map relative to mtz:", shift_cart) dm.write_miller_array_file(mtz_object, filename=mtzout_file_name) + if args.write_maps: + print ("Writing weighted map as", mapout1_file_name) + print ("Writing likelihood-weighted map as", mapout2_file_name) + new_mmm = results.new_mmm + new_mmm.write_map(map_id='map_manager_wtd', file_name = mapout1_file_name) + new_mmm.write_map(map_id='map_manager_lwtd', file_name = mapout2_file_name) over_sampling_factor = results.over_sampling_factor fraction_scattering = results.fraction_scattering print ("Over-sampling factor for Fourier terms:",over_sampling_factor) diff --git a/cctbx/regression/tst_prepare_map_for_docking.py b/cctbx/regression/tst_prepare_map_for_docking.py index ea862105f9..5724f37089 100644 --- a/cctbx/regression/tst_prepare_map_for_docking.py +++ b/cctbx/regression/tst_prepare_map_for_docking.py @@ -130,10 +130,10 @@ def exercise(): mmm.map_manager().set_map_data(map_data = mm_mean_data) # Add mask map for ordered component of map - mask_id = 'ordered_volume_mask' + ordered_mask_id = 'ordered_volume_mask' add_ordered_volume_mask(mmm, d_min, protein_mw=protein_mw, nucleic_mw=nucleic_mw, - map_id_out=mask_id) + ordered_mask_id=ordered_mask_id) box_centre = tuple(flex.double((ucpars[0],ucpars[1],ucpars[2]))/2) # Now refine to assess parameters describing map errors @@ -142,7 +142,7 @@ def exercise(): else: verbosity = 0 results = assess_cryoem_errors( - mmm, d_min, sphere_points=500, + mmm, d_min, ordered_mask_id=ordered_mask_id, sphere_points=500, sphere_cent=box_centre, radius=model_radius+d_min, verbosity=verbosity) if debug: From 5e4a68b62f8cf9ab80d1fe9814de1a87f18c6af3 Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Mon, 16 Sep 2024 18:29:02 -0700 Subject: [PATCH 704/748] bug fix. Use native method of hierarchy instead --- mmtbx/model/model.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index 02e1346df7..e3d342652d 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -1090,11 +1090,7 @@ def get_site_symmetry_table(self): return self._site_symmetry_table def altlocs_present(self): - conformer_indices = \ - self.get_hierarchy().get_conformer_indices().conformer_indices - if(len(list(set(list(conformer_indices))))>1): - result = True - return False + return self.get_hierarchy().altlocs_present() def aa_residues_with_bound_sidechains(self): """ From 083816b5beec9ba1c06079fd5ebb11ef10de5ab4 Mon Sep 17 00:00:00 2001 From: Pavel Afonine Date: Tue, 17 Sep 2024 13:19:22 -0700 Subject: [PATCH 705/748] Bug fixes with a test --- iotbx/pdb/hierarchy.py | 6 +- mmtbx/model/model.py | 8 ++ mmtbx/regression/model/tst_model_2.py | 137 ++++++++++++++++++++++++++ 3 files changed, 149 insertions(+), 2 deletions(-) diff --git a/iotbx/pdb/hierarchy.py b/iotbx/pdb/hierarchy.py index 1aa0415cf5..131a5789eb 100644 --- a/iotbx/pdb/hierarchy.py +++ b/iotbx/pdb/hierarchy.py @@ -2562,10 +2562,12 @@ def exchangeable_hd_selections(self): for chain in model.chains(): for residue_group in chain.residue_groups(): for i_gr1, atom_group_1 in enumerate(residue_group.atom_groups()): - elements_group1 = atom_group_1.atoms().extract_element() + elements_group1 = [ + e.strip() for e in atom_group_1.atoms().extract_element()] non_H_atoms_group1 = list(set(elements_group1) - set(['H','D'])) for i_gr2, atom_group_2 in enumerate(residue_group.atom_groups()): - elements_group2 = atom_group_2.atoms().extract_element() + elements_group2 = [ + e.strip() for e in atom_group_2.atoms().extract_element()] non_H_atoms_group2 = list(set(elements_group2) - set(['H','D'])) if non_H_atoms_group1 and non_H_atoms_group2: continue if(atom_group_1.altloc != atom_group_2.altloc and i_gr2 > i_gr1): diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index e3d342652d..2bc1568727 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -1092,6 +1092,14 @@ def get_site_symmetry_table(self): def altlocs_present(self): return self.get_hierarchy().altlocs_present() + def altlocs_present_only_hd(self): + noh_selection = self.selection("not (element H or element D)") + hierarchy_no_hd = self.get_hierarchy().select(noh_selection) + altlocs = hierarchy_no_hd.altlocs_present() + hd = self.get_hierarchy().exchangeable_hd_selections() + if not altlocs and len(hd)>0: return True + return False + def aa_residues_with_bound_sidechains(self): """ Return array of i_seqs of residue side chain atoms that are involved into diff --git a/mmtbx/regression/model/tst_model_2.py b/mmtbx/regression/model/tst_model_2.py index 54381854bf..2a25893fe1 100644 --- a/mmtbx/regression/model/tst_model_2.py +++ b/mmtbx/regression/model/tst_model_2.py @@ -491,8 +491,145 @@ def exercise_model_filename(): m = mmtbx.model.manager(model_input=inp) assert m.get_source_filename() is None +def exercise_altlocs_present(): + pdb_str1=""" +CRYST1 13.135 16.057 12.855 90.00 90.00 90.00 P 1 +ATOM 1 N HIS A 3 8.135 7.414 7.855 1.00 22.05 N +ATOM 2 CA HIS A 3 7.032 6.873 7.032 1.00 18.37 C +ATOM 3 C HIS A 3 7.233 5.393 6.739 1.00 13.79 C +ATOM 4 O HIS A 3 8.085 5.000 5.991 1.00 12.07 O +ATOM 5 CB HIS A 3 6.816 7.572 5.708 1.00 21.10 C +ATOM 6 CG HIS A 3 6.273 8.956 5.759 1.00 24.64 C +ATOM 7 ND1 HIS A 3 5.237 9.382 6.577 1.00 21.60 N +ATOM 8 CD2 HIS A 3 6.625 10.039 5.000 1.00 33.23 C +ATOM 9 CE1 HIS A 3 5.000 10.626 6.356 1.00 23.45 C +ATOM 10 NE2 HIS A 3 5.834 11.057 5.402 1.00 24.68 N +ATOM 11 OXT HIS A 3 6.509 4.555 7.276 1.00 13.79 O +ATOM 12 H HIS A 3 7.879 8.235 8.404 1.00 22.05 H +ATOM 13 H2 HIS A 3 8.446 6.714 8.498 1.00 22.05 H +ATOM 14 H3 HIS A 3 8.894 7.681 7.262 1.00 22.05 H +ATOM 15 HA HIS A 3 6.135 7.043 7.628 1.00 18.37 H +ATOM 16 HB2 HIS A 3 7.776 7.626 5.195 1.00 21.10 H +ATOM 17 HB3 HIS A 3 6.114 6.977 5.123 1.00 21.10 H +ATOM 18 HD2 HIS A 3 7.384 10.073 4.233 1.00 33.23 H +ATOM 19 HE1 HIS A 3 4.253 11.224 6.857 1.00 23.45 H + +ATOM 20 HD1AHIS A 3 4.740 8.798 7.250 0.50 21.60 H +ATOM 21 HE2AHIS A 3 5.867 12.008 5.035 0.50 24.68 H + +ATOM 22 DD1BHIS A 3 4.740 8.798 7.250 0.50 21.60 D +ATOM 23 DE2BHIS A 3 5.867 12.008 5.035 0.50 24.68 D +TER +END + """ + pdb_str2=""" +CRYST1 13.135 16.057 12.855 90.00 90.00 90.00 P 1 +ATOM 1 N HIS A 3 8.135 7.414 7.855 1.00 22.05 N +ATOM 2 CA AHIS A 3 7.032 6.873 7.032 1.00 18.37 C +ATOM 2 CA BHIS A 3 7.032 6.873 7.032 1.00 18.37 C +ATOM 3 C HIS A 3 7.233 5.393 6.739 1.00 13.79 C +ATOM 4 O HIS A 3 8.085 5.000 5.991 1.00 12.07 O +ATOM 5 CB HIS A 3 6.816 7.572 5.708 1.00 21.10 C +ATOM 6 CG HIS A 3 6.273 8.956 5.759 1.00 24.64 C +ATOM 7 ND1 HIS A 3 5.237 9.382 6.577 1.00 21.60 N +ATOM 8 CD2 HIS A 3 6.625 10.039 5.000 1.00 33.23 C +ATOM 9 CE1 HIS A 3 5.000 10.626 6.356 1.00 23.45 C +ATOM 10 NE2 HIS A 3 5.834 11.057 5.402 1.00 24.68 N +ATOM 11 OXT HIS A 3 6.509 4.555 7.276 1.00 13.79 O +ATOM 12 H HIS A 3 7.879 8.235 8.404 1.00 22.05 H +ATOM 13 H2 HIS A 3 8.446 6.714 8.498 1.00 22.05 H +ATOM 14 H3 HIS A 3 8.894 7.681 7.262 1.00 22.05 H +ATOM 15 HA HIS A 3 6.135 7.043 7.628 1.00 18.37 H +ATOM 16 HB2 HIS A 3 7.776 7.626 5.195 1.00 21.10 H +ATOM 17 HB3 HIS A 3 6.114 6.977 5.123 1.00 21.10 H +ATOM 18 HD2 HIS A 3 7.384 10.073 4.233 1.00 33.23 H +ATOM 19 HE1 HIS A 3 4.253 11.224 6.857 1.00 23.45 H + +ATOM 20 HD1AHIS A 3 4.740 8.798 7.250 0.50 21.60 H +ATOM 21 HE2AHIS A 3 5.867 12.008 5.035 0.50 24.68 H + +ATOM 22 DD1BHIS A 3 4.740 8.798 7.250 0.50 21.60 D +ATOM 23 DE2BHIS A 3 5.867 12.008 5.035 0.50 24.68 D +TER +END + """ + pdb_str3=""" +CRYST1 13.135 16.057 12.855 90.00 90.00 90.00 P 1 +ATOM 1 N HIS A 3 8.135 7.414 7.855 1.00 22.05 N +ATOM 2 CA AHIS A 3 7.032 6.873 7.032 1.00 18.37 C +ATOM 2 CA BHIS A 3 7.032 6.873 7.032 1.00 18.37 C +ATOM 3 C HIS A 3 7.233 5.393 6.739 1.00 13.79 C +ATOM 4 O HIS A 3 8.085 5.000 5.991 1.00 12.07 O +ATOM 5 CB HIS A 3 6.816 7.572 5.708 1.00 21.10 C +ATOM 6 CG HIS A 3 6.273 8.956 5.759 1.00 24.64 C +ATOM 7 ND1 HIS A 3 5.237 9.382 6.577 1.00 21.60 N +ATOM 8 CD2 HIS A 3 6.625 10.039 5.000 1.00 33.23 C +ATOM 9 CE1 HIS A 3 5.000 10.626 6.356 1.00 23.45 C +ATOM 10 NE2 HIS A 3 5.834 11.057 5.402 1.00 24.68 N +ATOM 11 OXT HIS A 3 6.509 4.555 7.276 1.00 13.79 O +ATOM 12 H HIS A 3 7.879 8.235 8.404 1.00 22.05 H +ATOM 13 H2 HIS A 3 8.446 6.714 8.498 1.00 22.05 H +ATOM 14 H3 HIS A 3 8.894 7.681 7.262 1.00 22.05 H +ATOM 15 HA HIS A 3 6.135 7.043 7.628 1.00 18.37 H +ATOM 16 HB2 HIS A 3 7.776 7.626 5.195 1.00 21.10 H +ATOM 17 HB3 HIS A 3 6.114 6.977 5.123 1.00 21.10 H +ATOM 18 HD2 HIS A 3 7.384 10.073 4.233 1.00 33.23 H +ATOM 19 HE1 HIS A 3 4.253 11.224 6.857 1.00 23.45 H +TER +END + """ + pdb_str4=""" +CRYST1 13.135 16.057 12.855 90.00 90.00 90.00 P 1 +ATOM 1 N HIS A 3 8.135 7.414 7.855 1.00 22.05 N +ATOM 2 CA HIS A 3 7.032 6.873 7.032 1.00 18.37 C +ATOM 3 C HIS A 3 7.233 5.393 6.739 1.00 13.79 C +ATOM 4 O HIS A 3 8.085 5.000 5.991 1.00 12.07 O +ATOM 5 CB HIS A 3 6.816 7.572 5.708 1.00 21.10 C +ATOM 6 CG HIS A 3 6.273 8.956 5.759 1.00 24.64 C +ATOM 7 ND1 HIS A 3 5.237 9.382 6.577 1.00 21.60 N +ATOM 8 CD2 HIS A 3 6.625 10.039 5.000 1.00 33.23 C +ATOM 9 CE1 HIS A 3 5.000 10.626 6.356 1.00 23.45 C +ATOM 10 NE2 HIS A 3 5.834 11.057 5.402 1.00 24.68 N +ATOM 11 OXT HIS A 3 6.509 4.555 7.276 1.00 13.79 O +ATOM 12 H HIS A 3 7.879 8.235 8.404 1.00 22.05 H +ATOM 13 H2 HIS A 3 8.446 6.714 8.498 1.00 22.05 H +ATOM 14 H3 HIS A 3 8.894 7.681 7.262 1.00 22.05 H +ATOM 15 HA HIS A 3 6.135 7.043 7.628 1.00 18.37 H +ATOM 16 HB2 HIS A 3 7.776 7.626 5.195 1.00 21.10 H +ATOM 17 HB3 HIS A 3 6.114 6.977 5.123 1.00 21.10 H +ATOM 18 HD2 HIS A 3 7.384 10.073 4.233 1.00 33.23 H +ATOM 19 HE1 HIS A 3 4.253 11.224 6.857 1.00 23.45 H +TER +END + """ + pdb_inp1 = iotbx.pdb.input(source_info=None, lines=pdb_str1) + m1 = mmtbx.model.manager(model_input = pdb_inp1) + # + pdb_inp2 = iotbx.pdb.input(source_info=None, lines=pdb_str2) + m2 = mmtbx.model.manager(model_input = pdb_inp2) + # + pdb_inp3 = iotbx.pdb.input(source_info=None, lines=pdb_str3) + m3 = mmtbx.model.manager(model_input = pdb_inp3) + # + pdb_inp4 = iotbx.pdb.input(source_info=None, lines=pdb_str4) + m4 = mmtbx.model.manager(model_input = pdb_inp4) + # + assert m1.altlocs_present() + assert m1.altlocs_present_only_hd() + # + assert m2.altlocs_present() + assert not m2.altlocs_present_only_hd() + # + assert m3.altlocs_present() + assert not m3.altlocs_present_only_hd() + # + assert not m4.altlocs_present() + assert not m4.altlocs_present_only_hd() + + if (__name__ == "__main__"): t0 = time.time() + exercise_altlocs_present() exercise_macromolecule_plus_hetatms_by_chain_selections() exercise_ss_creation_crash() exercise_set_b_iso() From 0c7cd4b09251ebb520e1f03b420e8ce368f5dc70 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 17 Sep 2024 14:01:54 -0700 Subject: [PATCH 706/748] suppress approx_equal output --- mmtbx/ncs/ncs_restraints_group_list.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mmtbx/ncs/ncs_restraints_group_list.py b/mmtbx/ncs/ncs_restraints_group_list.py index 7655340d2b..998c93f3ae 100644 --- a/mmtbx/ncs/ncs_restraints_group_list.py +++ b/mmtbx/ncs/ncs_restraints_group_list.py @@ -5,7 +5,7 @@ from scitbx import matrix import mmtbx.ncs.ncs_utils as nu import scitbx.rigid_body -from libtbx.utils import Sorry +from libtbx.utils import null_out, Sorry from libtbx.test_utils import approx_equal import iotbx.cif.model from six.moves import zip @@ -28,7 +28,7 @@ def __init__(self,copy_iselection, rot, tran, str_selection=None, rmsd=999): self.rmsd = rmsd def __eq__(self, other): - return approx_equal(self.r, other.r) and approx_equal(self.t, other.t) + return approx_equal(self.r, other.r, out=null_out()) and approx_equal(self.t, other.t, out=null_out()) def deep_copy(self): res = NCS_copy( From ac046ce88d2c82192f30e7c69c46690a7f316ea4 Mon Sep 17 00:00:00 2001 From: Oleg Sobolev Date: Tue, 17 Sep 2024 14:24:14 -0700 Subject: [PATCH 707/748] Doc for the new function. --- mmtbx/model/model.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mmtbx/model/model.py b/mmtbx/model/model.py index 2bc1568727..1db3a0007a 100644 --- a/mmtbx/model/model.py +++ b/mmtbx/model/model.py @@ -1093,6 +1093,9 @@ def altlocs_present(self): return self.get_hierarchy().altlocs_present() def altlocs_present_only_hd(self): + """ True when model has H/D exchangeable sites and does not have + other alternative conformations. False otherwise. + """ noh_selection = self.selection("not (element H or element D)") hierarchy_no_hd = self.get_hierarchy().select(noh_selection) altlocs = hierarchy_no_hd.altlocs_present() From 394fee6f9bfacda26ff813370edf603335061ab5 Mon Sep 17 00:00:00 2001 From: Pavel Date: Tue, 17 Sep 2024 22:12:51 -0700 Subject: [PATCH 708/748] Use correct version of ASE --- libtbx/auto_build/bootstrap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libtbx/auto_build/bootstrap.py b/libtbx/auto_build/bootstrap.py index 37714c6ac6..bf9943aa16 100644 --- a/libtbx/auto_build/bootstrap.py +++ b/libtbx/auto_build/bootstrap.py @@ -2754,7 +2754,7 @@ def add_make(self): # XXX Do not get JPype1 as it fails. This makes QR work only with # XXX fast_interaction=True (=False won't work) # - pip_installs = ['ase', 'pymongo'] + pip_installs = ['ase==3.22.1',] instructions = [] # versioning cmd = [os.path.join('..', self.python_base), From 45449dd50f63dce8b7f5cc2bdb5ab7ac4650a28a Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Wed, 18 Sep 2024 15:28:45 -0700 Subject: [PATCH 709/748] Towards a general lbfgs minimizer: adding a lbfgsb run() function --- scitbx/lbfgsb.py | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/scitbx/lbfgsb.py b/scitbx/lbfgsb.py index 4295eca7ae..4a81acb275 100644 --- a/scitbx/lbfgsb.py +++ b/scitbx/lbfgsb.py @@ -1,11 +1,10 @@ from __future__ import absolute_import, division, print_function -import scitbx.array_family.flex +from scitbx.array_family import flex import boost_adaptbx.boost.python as bp ext = bp.import_ext("scitbx_lbfgsb_ext") from scitbx_lbfgsb_ext import * -from scitbx.array_family import flex class minimizer(ext.minimizer): @@ -33,3 +32,36 @@ def __init__(self, n=None, if (iprint is None): iprint = -1 ext.minimizer.__init__(self, n, m, l, u, nbd, enable_stp_init, factr, pgtol, iprint) + + +def run(target_evaluator, + use_bounds, + lower_bound, + upper_bound, + n, + max_iterations = None): + nbd = flex.int(n, use_bounds) + lbfgsb_minimizer = minimizer( + n = n, + l = lower_bound, + u = upper_bound, + nbd = nbd) # flag to apply both bounds + lbfgsb_minimizer.error = None + try: + icall = 0 + while 1: + icall += 1 + x, f, g = target_evaluator.compute_functional_and_gradients() + have_request = lbfgsb_minimizer.process(x, f, g) + if(have_request): + requests_f_and_g = lbfgsb_minimizer.requests_f_and_g() + continue + assert not lbfgsb_minimizer.requests_f_and_g() + if(lbfgsb_minimizer.is_terminated()): break + if(max_iterations is not None and icall>max_iterations): break + except RuntimeError as e: + lbfgsb_minimizer.error = str(e) + lbfgsb_minimizer.n_calls = icall + if(lbfgsb_minimizer.error is not None): + print("lbfgs-b: an error occured: %s"%lbfgsb_minimizer.error) + return lbfgsb_minimizer From 19709d520c79aa0226e72a1b33e65e8a44f785a7 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 19 Sep 2024 11:55:09 -0700 Subject: [PATCH 710/748] Cleanup --- scitbx/lbfgsb.py | 58 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/scitbx/lbfgsb.py b/scitbx/lbfgsb.py index 4a81acb275..d6c83292f6 100644 --- a/scitbx/lbfgsb.py +++ b/scitbx/lbfgsb.py @@ -1,6 +1,5 @@ from __future__ import absolute_import, division, print_function from scitbx.array_family import flex - import boost_adaptbx.boost.python as bp ext = bp.import_ext("scitbx_lbfgsb_ext") from scitbx_lbfgsb_ext import * @@ -40,6 +39,63 @@ def run(target_evaluator, upper_bound, n, max_iterations = None): + """ + Run the L-BFGS-B minimization algorithm using the provided target + evaluator and bounds. + + This function minimizes a target function using the Limited-memory + Broyden–Fletcher–Goldfarb–Shanno with Box constraints (L-BFGS-B) + algorithm. It iteratively calls the target evaluator to compute the + function value and gradients, and processes them with the L-BFGS-B + minimizer. + + Parameters + ---------- + target_evaluator : callable + A callable object that provides the method + `compute_functional_and_gradients()`, which returns the current + values of the variables `x`, the function value `f`, and the + gradient `g`. + use_bounds : int + Number of bounds used in the optimization. Used to compute nbd which + is the flag that tells the optimizer which bounds to use. + lower_bound : flex.double + The lower bound for the optimization variables. + upper_bound : flex.double + The upper bound for the optimization variables. + n : int + The size of x (i.e. the number of variables to be optimized). + max_iterations : int, optional + Maximum number of iterations allowed during the optimization. If + None, there is no limit on the number of iterations. + + Returns + ------- + lbfgsb_minimizer : object + An instance of the minimizer object that contains the result of the + optimization process. Its attributes are: + - `x`: The optimized variables. + - `f`: The minimized function value. + - `g`: The gradient at the optimized point. + - `error`: A string containing any error message that occurred + during execution. + - `n_calls`: The number of iterations performed. + + Raises + ------ + RuntimeError + If the L-BFGS-B minimizer encounters an error during execution. The + error message is stored in `lbfgsb_minimizer.error`. + + Notes + ----- + - The process runs in a loop until either the minimizer converges, the + specified maximum number of iterations is reached, or an error + occurs. + - If bounds are specified, the optimization is constrained within the + provided lower and upper bounds. + """ + # nbd = flex.int(n, use_bounds) lbfgsb_minimizer = minimizer( n = n, From 2b5d162119db63dd91072e694b2a0bc68d301a69 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 19 Sep 2024 12:08:03 -0700 Subject: [PATCH 711/748] Fix typo --- scitbx/lbfgsb.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scitbx/lbfgsb.py b/scitbx/lbfgsb.py index d6c83292f6..8a577e8f8c 100644 --- a/scitbx/lbfgsb.py +++ b/scitbx/lbfgsb.py @@ -39,7 +39,7 @@ def run(target_evaluator, upper_bound, n, max_iterations = None): - """ + """ Run the L-BFGS-B minimization algorithm using the provided target evaluator and bounds. @@ -94,7 +94,7 @@ def run(target_evaluator, occurs. - If bounds are specified, the optimization is constrained within the provided lower and upper bounds. - """ + """ # nbd = flex.int(n, use_bounds) lbfgsb_minimizer = minimizer( From 8b6eb0cc04365da29830921e68f7dae048486890 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 17 Sep 2024 08:30:15 -0700 Subject: [PATCH 712/748] still a mess --- .../geometry_restraints/auto_linking_types.py | 16 +++++ cctbx/geometry_restraints/linking_class.py | 23 +++++++ cctbx/geometry_restraints/manager.py | 60 ++++++++++++------- 3 files changed, 78 insertions(+), 21 deletions(-) diff --git a/cctbx/geometry_restraints/auto_linking_types.py b/cctbx/geometry_restraints/auto_linking_types.py index 3c617921f5..1a1ab8c0bf 100644 --- a/cctbx/geometry_restraints/auto_linking_types.py +++ b/cctbx/geometry_restraints/auto_linking_types.py @@ -25,6 +25,22 @@ def __init__(self, item, internals=None): def __repr__(self): return list.__repr__(self) + ' is %s' % self.internals +covalent_headers = ['Bond', + "Bond angle", + "Dihedral angle", + "Chirality", + "Plane", + "Parallelity", + ] + +internal_labels = ['bonds', + 'angles', + 'dihedrals', + 'chirals', + 'planes', + 'parallelities', + ] + starting_id = 0 for link_info in [ ['covalent geometry', [0,1,2,3,4,5]], # 0 diff --git a/cctbx/geometry_restraints/linking_class.py b/cctbx/geometry_restraints/linking_class.py index 8314ac3555..0fbf6b8b06 100644 --- a/cctbx/geometry_restraints/linking_class.py +++ b/cctbx/geometry_restraints/linking_class.py @@ -97,6 +97,8 @@ def get_parallelity_origin_id_labels(self): return self._get_origin_id_labels(internals='parallelity') def get_geo_file_header(self, origin_id_label, internals=None): + print(origin_id_label,internals) + print(self.data.keys()) info = self.data.get(origin_id_label, None) assert info if len(info)>=4: @@ -123,6 +125,7 @@ def get_label_for_geo_header(self,query_header,internals=None): internal_idx = internals_all.index(internals) for origin_label, info in self.data.items(): + print('origin_label, info',origin_label,info) if len(info)>=4: header_info = info[3] if isinstance(header_info,list) and len(header_info)>internal_idx: @@ -131,6 +134,26 @@ def get_label_for_geo_header(self,query_header,internals=None): if header.startswith(query_header) or query_header.startswith(header): return origin_label + def get_origin_label_and_internal(self, query_header): + for origin_label, info in self.data.items(): + print('origin_label, info',origin_label,info) + tmp = query_header.split('|') + print(tmp) + if len(tmp)==1: + oi = 0 # default + rc = 'covalent' + else: + print(tmp) + header='%s %s' % (tmp[0].strip(), tmp[2].strip()) + rc = self.get_geo_file_header(header) + print(rc) + assert 0 + return oi, rc + if __name__=='__main__': lc = linking_class() print(lc) + for line in ['Bond restraints', + 'Bond | Misc. | restraints', + ]: + print('.........',line, lc.get_origin_label_and_internal(line)) diff --git a/cctbx/geometry_restraints/manager.py b/cctbx/geometry_restraints/manager.py index 85daeb29e0..f7bbd317e4 100644 --- a/cctbx/geometry_restraints/manager.py +++ b/cctbx/geometry_restraints/manager.py @@ -1631,6 +1631,8 @@ def show_sorted(self, sites_cart=None, site_labels=None, f=None): + from cctbx.geometry_restraints.auto_linking_types import covalent_headers + from cctbx.geometry_restraints.auto_linking_types import internal_labels default_origin_id = origin_ids.get_origin_id('covalent geometry') if (f is None): f = sys.stdout pair_proxies = self.pair_proxies(flags=flags, sites_cart=sites_cart) @@ -1638,18 +1640,26 @@ def show_sorted(self, sites_cart = self._sites_cart_used_for_pair_proxies if pair_proxies.bond_proxies is not None: + # # write covalent bonds + # + label=covalent_headers[0] + tempbuffer = StringIO() pair_proxies.bond_proxies.show_sorted( by_value="residual", sites_cart=sites_cart, site_labels=site_labels, - f=f, + f=tempbuffer, origin_id=default_origin_id) - print(file=f) + if tempbuffer.getvalue().find(': 0')==-1: + print(label, tempbuffer.getvalue()[5:], file=f) + # + # write bonds with other origin_id + # for key in origin_ids.get_bond_origin_id_labels(): origin_id=origin_ids.get_origin_id(key) if origin_id==default_origin_id: continue - label=origin_ids.get_geo_file_header(key) + t_label=origin_ids.get_geo_file_header(key) tempbuffer = StringIO() pair_proxies.bond_proxies.show_sorted( by_value="residual", @@ -1658,41 +1668,42 @@ def show_sorted(self, f=tempbuffer, prefix="", origin_id=origin_id) + print('='*80) + print(tempbuffer.getvalue()) if tempbuffer.getvalue().find(': 0')==-1: - print(label, tempbuffer.getvalue()[5:], file=f) - - for p_label, proxies, internals, i_label, keys, start in [ - ("Bond angle", + print('%s | %s |' % (label, t_label), tempbuffer.getvalue()[5:], file=f) + # + # write of the other internals for each origin_id + # + for i, (proxies, i_label, keys, start) in enumerate([ + ( self.angle_proxies, # self.get_all_angle_proxies(), - 'angles', '', origin_ids.get_angle_origin_id_labels(), - 5), - ("Dihedral angle", + 11), + ( self.dihedral_proxies, # self.get_dihedral_proxies(), - 'dihedrals', 'torsion', origin_ids.get_dihedral_origin_id_labels(), - 9), - ("Chirality", + 15), + ( self.chirality_proxies, - 'chirals', '', origin_ids.get_chiral_origin_id_labels(), - 0), - ("Planes", + 10), + ( self.planarity_proxies, - 'planes', '', origin_ids.get_plane_origin_id_labels(), 10), - ("Parallelity", + ( self.parallelity_proxies, - 'parallelities', '', origin_ids.get_parallelity_origin_id_labels(), 12), - ]: + ]): + p_label=covalent_headers[i+1] + internals=internal_labels[i+1] if (proxies is not None): if p_label not in ['Parallelity']: # not default origin for parallelity proxies.show_sorted( @@ -1707,6 +1718,8 @@ def show_sorted(self, if origin_id==default_origin_id: continue label=origin_ids.get_geo_file_header(key, internals=internals) if label is None: continue + print('p_label',p_label,'label',label,'i_label',i_label) + # label = '%s - %s' % (p_label, label) if i_label: label = '%s %s' % (label, i_label) tempbuffer = StringIO() proxies.show_sorted( @@ -1716,8 +1729,13 @@ def show_sorted(self, f=tempbuffer, prefix="", origin_id=origin_id) + print('-'*80) + print(tempbuffer.getvalue()) if len(tempbuffer.getvalue()) and tempbuffer.getvalue().find(': 0')==-1: - print(label, tempbuffer.getvalue()[start:], file=f) + print('-'*80) + print('~> ',p_label,label,origin_id) + print(tempbuffer.getvalue()) + print('%s | %s |' % (p_label, label), tempbuffer.getvalue()[start:], file=f) for p_label, proxies in [ ("Reference torsion angle", self.reference_dihedral_manager), From ae63ba05cfa751d526a6e5527b1e7fbab5490677 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 17 Sep 2024 08:54:50 -0700 Subject: [PATCH 713/748] test for ARG geom --- mmtbx/regression/tst_arginine_geometry.py | 97 +++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 mmtbx/regression/tst_arginine_geometry.py diff --git a/mmtbx/regression/tst_arginine_geometry.py b/mmtbx/regression/tst_arginine_geometry.py new file mode 100644 index 0000000000..3b6b39fa2c --- /dev/null +++ b/mmtbx/regression/tst_arginine_geometry.py @@ -0,0 +1,97 @@ +from __future__ import division +import sys +from iotbx.cli_parser import run_program +from mmtbx.programs.arginine_geometry import Program + +pdb_str = '''CRYST1 38.853 46.881 71.758 90.00 90.00 90.00 P 21 21 21 +SCALE1 0.025738 0.000000 0.000000 0.00000 +SCALE2 0.000000 0.021331 0.000000 0.00000 +SCALE3 0.000000 0.000000 0.013936 0.00000 +ATOM 10 N GLU A 248 -8.310 -2.226 10.254 1.00 17.05 N +ANISOU 10 N GLU A 248 2878 1993 1606 -179 -365 90 N +ATOM 11 CA GLU A 248 -8.170 -3.714 10.203 1.00 17.32 C +ANISOU 11 CA GLU A 248 2932 1996 1654 -158 -409 183 C +ATOM 12 C GLU A 248 -8.952 -4.335 11.364 1.00 18.33 C +ANISOU 12 C GLU A 248 3283 2097 1585 -225 -344 222 C +ATOM 13 O GLU A 248 -9.604 -5.377 11.174 1.00 18.66 O +ANISOU 13 O GLU A 248 3334 2113 1644 -227 -252 268 O +ATOM 14 CB GLU A 248 -6.710 -4.119 10.242 1.00 18.66 C +ANISOU 14 CB GLU A 248 3052 2128 1911 -119 -629 243 C +ATOM 15 CG GLU A 248 -5.970 -3.729 8.986 1.00 19.08 C +ANISOU 15 CG GLU A 248 2877 2194 2177 -62 -637 207 C +ATOM 16 CD GLU A 248 -6.210 -4.566 7.743 1.00 19.74 C +ANISOU 16 CD GLU A 248 2830 2276 2393 -17 -531 212 C +ATOM 17 OE1 GLU A 248 -5.446 -4.333 6.804 1.00 23.25 O +ANISOU 17 OE1 GLU A 248 3120 2722 2991 18 -536 187 O +ATOM 18 OE2 GLU A 248 -7.190 -5.424 7.676 1.00 17.49 O +ANISOU 18 OE2 GLU A 248 2602 1985 2059 -28 -428 231 O +ATOM 19 N AARG A 249 -8.924 -3.737 12.553 0.50 19.58 N +ANISOU 19 N AARG A 249 3635 2254 1550 -290 -374 199 N +ATOM 20 CA AARG A 249 -9.730 -4.282 13.672 0.50 21.22 C +ANISOU 20 CA AARG A 249 4090 2434 1537 -373 -266 232 C +ATOM 21 C AARG A 249 -11.212 -4.230 13.327 0.50 20.68 C +ANISOU 21 C AARG A 249 3967 2375 1515 -395 19 165 C +ATOM 22 O AARG A 249 -11.922 -5.224 13.583 0.50 20.67 O +ANISOU 22 O AARG A 249 4046 2337 1470 -433 135 221 O +ATOM 23 CB AARG A 249 -9.489 -3.467 14.930 0.50 23.49 C +ANISOU 23 CB AARG A 249 4611 2727 1587 -454 -321 185 C +ATOM 24 CG AARG A 249 -8.072 -3.629 15.421 0.50 25.09 C +ANISOU 24 CG AARG A 249 4885 2911 1738 -445 -644 262 C +ATOM 25 CD AARG A 249 -8.221 -3.512 16.898 0.50 27.81 C +ANISOU 25 CD AARG A 249 5575 3244 1749 -559 -667 266 C +ATOM 26 NE AARG A 249 -8.624 -2.206 17.353 0.50 29.01 N +ANISOU 26 NE AARG A 249 5810 3425 1787 -625 -540 106 N +ATOM 27 CZ AARG A 249 -7.786 -1.191 17.460 0.50 29.90 C +ANISOU 27 CZ AARG A 249 5889 3551 1921 -629 -708 25 C +ATOM 28 NH1AARG A 249 -6.544 -1.279 17.005 0.50 29.11 N +ANISOU 28 NH1AARG A 249 5624 3444 1992 -564 -987 84 N +ATOM 29 NH2AARG A 249 -8.211 -0.073 18.013 0.50 31.92 N +ANISOU 29 NH2AARG A 249 6262 3814 2053 -702 -578 -126 N +ATOM 30 N BARG A 249 -8.925 -3.732 12.561 0.50 19.84 N +ANISOU 30 N BARG A 249 3670 2287 1582 -291 -374 198 N +ATOM 31 CA BARG A 249 -9.709 -4.282 13.701 0.50 21.70 C +ANISOU 31 CA BARG A 249 4157 2495 1593 -374 -271 233 C +ATOM 32 C BARG A 249 -11.206 -4.202 13.383 0.50 20.99 C +ANISOU 32 C BARG A 249 4017 2415 1545 -399 19 163 C +ATOM 33 O BARG A 249 -11.925 -5.175 13.683 0.50 21.05 O +ANISOU 33 O BARG A 249 4113 2385 1500 -439 137 219 O +ATOM 34 CB BARG A 249 -9.372 -3.588 15.023 0.50 24.47 C +ANISOU 34 CB BARG A 249 4757 2847 1695 -456 -351 202 C +ATOM 35 CG BARG A 249 -8.322 -4.340 15.822 0.50 27.11 C +ANISOU 35 CG BARG A 249 5261 3141 1899 -471 -627 332 C +ATOM 36 CD BARG A 249 -8.449 -4.152 17.324 0.50 30.43 C +ANISOU 36 CD BARG A 249 6039 3552 1971 -590 -651 335 C +ATOM 37 NE BARG A 249 -7.980 -2.852 17.724 0.50 31.82 N +ANISOU 37 NE BARG A 249 6257 3760 2073 -627 -736 211 N +ATOM 38 CZ BARG A 249 -7.824 -2.442 18.979 0.50 34.06 C +ANISOU 38 CZ BARG A 249 6849 4043 2050 -736 -813 179 C +ATOM 39 NH1BARG A 249 -8.116 -3.243 19.991 0.50 36.40 N +ANISOU 39 NH1BARG A 249 7464 4312 2056 -822 -809 280 N +ATOM 40 NH2BARG A 249 -7.383 -1.217 19.209 0.50 34.74 N +ANISOU 40 NH2BARG A 249 6937 4149 2112 -768 -887 43 N +ATOM 41 N SER A 250 -11.652 -3.118 12.750 1.00 19.65 N +ANISOU 41 N SER A 250 3692 2278 1498 -373 120 55 N +ATOM 42 CA SER A 250 -13.080 -2.949 12.372 1.00 19.72 C +ANISOU 42 CA SER A 250 3604 2282 1605 -384 368 -13 C +ATOM 43 C SER A 250 -13.449 -4.047 11.363 1.00 18.82 C +ANISOU 43 C SER A 250 3339 2165 1648 -344 381 46 C +ATOM 44 O SER A 250 -14.476 -4.726 11.556 1.00 18.74 O +ANISOU 44 O SER A 250 3351 2123 1647 -389 546 49 O +ATOM 45 CB SER A 250 -13.334 -1.618 11.815 1.00 20.51 C +ANISOU 45 CB SER A 250 3555 2400 1836 -348 417 -113 C +ATOM 46 OG SER A 250 -14.727 -1.474 11.599 1.00 23.31 O +ANISOU 46 OG SER A 250 3816 2734 2306 -359 635 -175 O +END +''' + +def main(pdb_file=None): + if pdb_file is None: + pdb_file='tst_arginine_geometry.pdb' + f=open(pdb_file, 'w') + f.write(pdb_str) + del f + results = run_program(program_class=Program, args=[pdb_file]) + assert len(results)==1 + +if __name__ == '__main__': + main(*tuple(sys.argv[1:])) From b49c2dca8494fedf770a65ba53d72dfee4ab621a Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Wed, 18 Sep 2024 15:18:57 -0700 Subject: [PATCH 714/748] writing and parsing .geo file headers --- .../geometry_restraints/auto_linking_types.py | 8 +- cctbx/geometry_restraints/linking_class.py | 81 +++++++++++-------- cctbx/geometry_restraints/manager.py | 16 ++-- 3 files changed, 57 insertions(+), 48 deletions(-) diff --git a/cctbx/geometry_restraints/auto_linking_types.py b/cctbx/geometry_restraints/auto_linking_types.py index 1a1ab8c0bf..2328eadd70 100644 --- a/cctbx/geometry_restraints/auto_linking_types.py +++ b/cctbx/geometry_restraints/auto_linking_types.py @@ -111,18 +111,18 @@ def __repr__(self): # ['Trans Peptide']*3+[None], # [0,1,2,4] # ] - ['Misc. bond', + ['Misc. bond', # 9 'Bond created based on atom type and distance.', '', ['Misc.']*5, [0,1,2,3,4] - ], # 9 - ['User supplied cif_link', + ], + ['User supplied cif_link', # 10 'Internal coordinates supplied by the user in cif_link format', '', ['User cif_link']*5, [0,1,2,3,4] - ], # 10 + ], ]: for oi in origin_ids: assert starting_id not in oi diff --git a/cctbx/geometry_restraints/linking_class.py b/cctbx/geometry_restraints/linking_class.py index 0fbf6b8b06..f42a762c1e 100644 --- a/cctbx/geometry_restraints/linking_class.py +++ b/cctbx/geometry_restraints/linking_class.py @@ -1,5 +1,6 @@ from __future__ import absolute_import, division, print_function from cctbx.geometry_restraints.auto_linking_types import origin_ids +from cctbx.geometry_restraints.auto_linking_types import covalent_headers class linking_class(dict): def __init__(self): @@ -97,8 +98,6 @@ def get_parallelity_origin_id_labels(self): return self._get_origin_id_labels(internals='parallelity') def get_geo_file_header(self, origin_id_label, internals=None): - print(origin_id_label,internals) - print(self.data.keys()) info = self.data.get(origin_id_label, None) assert info if len(info)>=4: @@ -113,47 +112,61 @@ def get_geo_file_header(self, origin_id_label, internals=None): else: assert 0 else: return info[0] - def get_label_for_geo_header(self,query_header,internals=None): - """ - Given the string found in a geo file origin_id header, get the label - From label can use get_origin_id to get the integer origin id. - """ - if not internals: - internals = "bonds" - internals_all = ["bonds", "angles", "dihedrals", "chirals", "planes","parallelities"] - assert internals in internals_all - internal_idx = internals_all.index(internals) - - for origin_label, info in self.data.items(): - print('origin_label, info',origin_label,info) - if len(info)>=4: - header_info = info[3] - if isinstance(header_info,list) and len(header_info)>internal_idx: - header = header_info[internal_idx] - if header: - if header.startswith(query_header) or query_header.startswith(header): - return origin_label - - def get_origin_label_and_internal(self, query_header): - for origin_label, info in self.data.items(): - print('origin_label, info',origin_label,info) + def parse_geo_file_header(self, origin_id_label, subheader=None, internals=None): + if not origin_id_label in covalent_headers: + assert 0, 'origin_id_label "%s" not in %s' % (origin_id_label, covalent_headers) + info = self.data.get(origin_id_label, None) + if info: + assert 0 + else: + for i, (origin_label, info) in enumerate(self.data.items()): + if len(info)==2: + if subheader in info: + return i, '%s %s' % (origin_id_label, subheader) + elif len(info)>=4: + header_info = info[3] + if isinstance(header_info, list): + if subheader in header_info: + return i, '%s %s' % (origin_id_label, subheader) + + print(origin_id_label, subheader) + assert 0 + + def get_origin_label_and_internal(self, query_header, verbose=False): + if verbose: + for origin_label, info in self.data.items(): + print('origin_label, info',origin_label,info) tmp = query_header.split('|') - print(tmp) if len(tmp)==1: oi = 0 # default rc = 'covalent' else: - print(tmp) - header='%s %s' % (tmp[0].strip(), tmp[2].strip()) - rc = self.get_geo_file_header(header) - print(rc) - assert 0 + header=tmp[0].strip() + subheader=tmp[1].strip() + oi, rc = self.parse_geo_file_header(header, subheader=subheader) return oi, rc if __name__=='__main__': lc = linking_class() print(lc) - for line in ['Bond restraints', - 'Bond | Misc. | restraints', + for line in [ 'Bond restraints', + 'Bond | Misc. | restraints', + 'Bond | link_BETA1-4 | restraints', + 'Bond | link_TRANS | restraints', + 'Bond angle restraints', + 'Bond angle | link_BETA1-4 | restraints', + 'Bond angle | link_TRANS | restraints', + 'Dihedral angle restraints', + 'Dihedral angle | C-Beta improper | restraints', + 'Dihedral angle | link_TRANS | restraints', + 'Chirality restraints', + 'Chirality | link_BETA1-4 | restraints', + 'Planarity restraints', + 'Plane | link_TRANS | restraints', + + "Bond | Bond-like | restraints", + "Bond angle | Secondary Structure restraints around h-bond | restraints", + "Parallelity | Stacking parallelity | restraints", + "Parallelity | Basepair parallelity | restraints", ]: print('.........',line, lc.get_origin_label_and_internal(line)) diff --git a/cctbx/geometry_restraints/manager.py b/cctbx/geometry_restraints/manager.py index f7bbd317e4..87a402d82b 100644 --- a/cctbx/geometry_restraints/manager.py +++ b/cctbx/geometry_restraints/manager.py @@ -1668,8 +1668,6 @@ def show_sorted(self, f=tempbuffer, prefix="", origin_id=origin_id) - print('='*80) - print(tempbuffer.getvalue()) if tempbuffer.getvalue().find(': 0')==-1: print('%s | %s |' % (label, t_label), tempbuffer.getvalue()[5:], file=f) # @@ -1683,7 +1681,7 @@ def show_sorted(self, 11), ( self.dihedral_proxies, # self.get_dihedral_proxies(), - 'torsion', + '', #'torsion', origin_ids.get_dihedral_origin_id_labels(), 15), ( @@ -1718,7 +1716,6 @@ def show_sorted(self, if origin_id==default_origin_id: continue label=origin_ids.get_geo_file_header(key, internals=internals) if label is None: continue - print('p_label',p_label,'label',label,'i_label',i_label) # label = '%s - %s' % (p_label, label) if i_label: label = '%s %s' % (label, i_label) tempbuffer = StringIO() @@ -1729,14 +1726,13 @@ def show_sorted(self, f=tempbuffer, prefix="", origin_id=origin_id) - print('-'*80) - print(tempbuffer.getvalue()) if len(tempbuffer.getvalue()) and tempbuffer.getvalue().find(': 0')==-1: - print('-'*80) - print('~> ',p_label,label,origin_id) - print(tempbuffer.getvalue()) - print('%s | %s |' % (p_label, label), tempbuffer.getvalue()[start:], file=f) + print('%s | %s | %s' % (p_label, label, tempbuffer.getvalue()[start:]), + file=f) + # + # not parsed for geo viewer + # for p_label, proxies in [ ("Reference torsion angle", self.reference_dihedral_manager), ("NCS torsion angle", self.ncs_dihedral_manager), From f65da2675c006c732d8eb5b9c8b93e6f15468014 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Wed, 18 Sep 2024 15:51:12 -0700 Subject: [PATCH 715/748] update --- cctbx/geometry_restraints/manager.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cctbx/geometry_restraints/manager.py b/cctbx/geometry_restraints/manager.py index 87a402d82b..5d2a5f24f5 100644 --- a/cctbx/geometry_restraints/manager.py +++ b/cctbx/geometry_restraints/manager.py @@ -1729,7 +1729,6 @@ def show_sorted(self, if len(tempbuffer.getvalue()) and tempbuffer.getvalue().find(': 0')==-1: print('%s | %s | %s' % (p_label, label, tempbuffer.getvalue()[start:]), file=f) - # # not parsed for geo viewer # From 527f3e882f52fd2a4e8dfe9a8af51d34fcfedd7f Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Wed, 18 Sep 2024 17:18:06 -0700 Subject: [PATCH 716/748] fixing tests for geo header parsing --- mmtbx/monomer_library/tst_linking.py | 30 +++++++++++++++++----------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/mmtbx/monomer_library/tst_linking.py b/mmtbx/monomer_library/tst_linking.py index b978a87d15..eeff7fe841 100644 --- a/mmtbx/monomer_library/tst_linking.py +++ b/mmtbx/monomer_library/tst_linking.py @@ -2424,22 +2424,26 @@ def run_and_test(cmd, pdb, i, skip_links=False): f.close() if pdb=='linking_test_cyclic_main_chain.pdb': if i==1: - assert lines.find('link_TRANS restraints: 1')>-1 + assert lines.find('link_TRANS | restraints: 1')>-1 bonds = 0 for line in lines.splitlines(): for bond_like in ["Bond restraints:", 'Bond-like restraints:', - 'Metal coordination restraints:', - # - 'Disulphide bridge restraints:', - 'User supplied restraints:', - 'Standard Glycosidic restraints:', - 'Custom Glycosidic restraints:', - 'Misc. restraints:', - # - 'link_' + 'Bond | Metal coordination | restraints', + 'Bond | User supplied | restraints', + 'Bond | Custom Glycosidic | restraints', + 'Bond | link_BETA1-6 | restraints', + 'Bond | link_NAG-ASN | restraints', + 'Bond | link_BETA1-3 | restraints', + 'Bond | link_BETA1-4 | restraints', + 'Bond | link_ALPHA2-6 | restraints', + 'Bond | Misc. | restraints', + 'Bond | Disulphide bridge | restraints', + 'Bond | link_TRANS | restraints', ]: if line.find(bond_like)>-1: + print('line',line) + print('bond_like',bond_like) print('Adding %s for "%s"' % (int(line.split()[-1]), line)) bonds += int(line.split()[-1]) if line.find('Bond angle')>-1: break @@ -2537,9 +2541,11 @@ def run(only_i=None): cmd += " secondary_structure.enabled=1" if pdb.replace(".pdb", ".params") in pdbs: cmd += " %s" % pdb.replace(".pdb", ".params") - print("test number:",j) + print('='*80) + print("test number: %s (%s)" % (j,i)) + print('='*80) print(cmd) - run_and_test(cmd, pdb,i) + run_and_test(cmd, pdb, i) for pdb in sorted(pdbs): if pdb not in longer_tests: continue From 7e66c368322cd08c6d39b73ed95a1169d94e5eba Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Wed, 18 Sep 2024 17:27:20 -0700 Subject: [PATCH 717/748] update --- mmtbx/monomer_library/tst_metal_coordination.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmtbx/monomer_library/tst_metal_coordination.py b/mmtbx/monomer_library/tst_metal_coordination.py index b66b1892d2..83f3a25dc5 100644 --- a/mmtbx/monomer_library/tst_metal_coordination.py +++ b/mmtbx/monomer_library/tst_metal_coordination.py @@ -138,7 +138,7 @@ def run_and_test(cmd, pdb, i): lines = f.readlines() f.close() for line in lines: - if line.find("Metal coordination restraints:")>-1: + if line.find("Bond | Metal coordination | restraints")>-1: bonds = int(line.split()[-1]) break else: From 89ab9c9d093defe7feece2ec35b3006c8f3280d3 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Wed, 18 Sep 2024 17:47:22 -0700 Subject: [PATCH 718/748] update --- cctbx/regression/tst_geometry_restraints_2.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/cctbx/regression/tst_geometry_restraints_2.py b/cctbx/regression/tst_geometry_restraints_2.py index ca45c1e429..84a2fd9691 100644 --- a/cctbx/regression/tst_geometry_restraints_2.py +++ b/cctbx/regression/tst_geometry_restraints_2.py @@ -602,10 +602,15 @@ def exercise_na_restraints_output_to_geo(verbose=False): "Bond angle restraints: 130", "Dihedral angle restraints: 33", "Chirality restraints: 15", "Planarity restraints: 4"] - ss_geo_portions = ["Bond-like restraints: 6", - 'Secondary Structure restraints around h-bond angle restraints: 12', - "Stacking parallelity restraints: 2", - 'Basepair parallelity restraints: 2', + ss_geo_portions = [ + # "Bond-like restraints: 6", + "Bond | Bond-like | restraints: 6", + # 'Secondary Structure restraints around h-bond angle restraints: 12', + 'Bond angle | Secondary Structure restraints around h-bond | restraints: 12', + # "Stacking parallelity restraints: 2", + # 'Basepair parallelity restraints: 2', + 'Parallelity | Stacking parallelity | restraints: 2', + 'Parallelity | Basepair parallelity | restraints: 2', "Nonbonded interactions: 504"] non_ss_geo_portions = [ #"Bond-like restraints: 0", @@ -622,9 +627,10 @@ def exercise_na_restraints_output_to_geo(verbose=False): v_geo_out_noss = geo_out1.getvalue() v_geo_out_ss = geo_out2.getvalue() for portion in geo_identical_portions+ss_geo_portions: - assert v_geo_out_ss.find(portion) >= 0, 'did not find %s\n in \n%s' % ( + assert v_geo_out_ss.find(portion) >= 0, 'did not find %s\n in \n%s\n%s\n' % ( portion, - v_geo_out_ss) + v_geo_out_ss, + portion) for portion in geo_identical_portions+non_ss_geo_portions: assert v_geo_out_noss.find(portion) >= 0, 'did not find %s\n in \n%s' % ( portion, From f4795f932cd5c942fb94bf3f87b941dbd03db2ce Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Wed, 18 Sep 2024 18:10:39 -0700 Subject: [PATCH 719/748] update --- mmtbx/monomer_library/tst_paral_geo.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mmtbx/monomer_library/tst_paral_geo.py b/mmtbx/monomer_library/tst_paral_geo.py index f1855a6a65..6a147a07b9 100644 --- a/mmtbx/monomer_library/tst_paral_geo.py +++ b/mmtbx/monomer_library/tst_paral_geo.py @@ -704,7 +704,7 @@ def test_geo(result, opposite=False): def main(): write_and_run(large_pdb) - result = '''Basepair planarity restraints: 5 + result = '''Plane | Basepair planarity | restraints: 5 Sorted by residual: delta sigma weight rms_deltas residual plane pdb=" C1' DC C 7 " -0.366 1.76e-01 3.23e+01 1.84e-01 2.28e+01 @@ -729,7 +729,7 @@ def main(): pdb=" N3 DG D 10 " 0.167 1.76e-01 3.23e+01 pdb=" C4 DG D 10 " 0.015 1.76e-01 3.23e+01''' test_geo(result) - result = '''Stacking parallelity restraints: 8 + result = '''Parallelity | Stacking parallelity | restraints: 8 Sorted by residual: plane 1 plane 2 residual delta(deg) sigma pdb=" C1' DC C 7 " pdb=" C1' DG C 8 " 3.21e+01 12.4210 0.0270 @@ -745,7 +745,7 @@ def main(): pdb=" N3 DG C 8 " pdb=" C4 DG C 8 "''' test_geo(result) - result = '''Basepair parallelity restraints: 5 + result = '''Parallelity | Basepair parallelity | restraints: 5 Sorted by residual: plane 1 plane 2 residual delta(deg) sigma pdb=" C1' DG C 8 " pdb=" C1' DC D 9 " 2.80e+01 14.3936 0.0335 @@ -761,7 +761,7 @@ def main(): test_geo(result) write_and_run(small_pdb) - result = '''Stacking parallelity restraints: 2 + result = '''Parallelity | Stacking parallelity | restraints: 2 Sorted by residual: plane 1 plane 2 residual delta(deg) sigma pdb=" C1' DC D 11 " pdb=" C1' DC D 12 " 1.50e+01 8.4829 0.0270 @@ -786,8 +786,8 @@ def main(): pdb=" C2 DG D 10 " pdb=" C6 DC D 11 " pdb=" N2 DG D 10 "''' test_geo(result) - test_geo('Basepair planarity restraints:', opposite=True) - test_geo('Basepair parallelity restraints:', opposite=True) + test_geo('Basepair planarity | restraints:', opposite=True) + test_geo('Basepair parallelity | restraints:', opposite=True) if __name__ == '__main__': main() From f798e6b86d6fd55f6dbe35241c93b1ad1a1472d2 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 19 Sep 2024 07:43:29 -0700 Subject: [PATCH 720/748] update --- mmtbx/regression/tst_origin_ids.py | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/mmtbx/regression/tst_origin_ids.py b/mmtbx/regression/tst_origin_ids.py index 7c057f1315..7108d6e85e 100644 --- a/mmtbx/regression/tst_origin_ids.py +++ b/mmtbx/regression/tst_origin_ids.py @@ -10,7 +10,8 @@ ' sinusoidal': 15, 'Planarity restraints': 13, 'Chirality restraints': 6, - 'C-Beta improper torsion angle restraints': 12, + # 'C-Beta improper torsion angle restraints': 12, + 'Dihedral angle | C-Beta improper | restraints': 12, # 'Parallelity restraints': 0, #'User supplied restraints': 0, #'User supplied torsion angle restraints': 0, @@ -24,6 +25,8 @@ #'Disulphide bridge angle restraints': 0, #'Disulphide bridge restraints': 0, 'Nonbonded interactions': 990, + # + # 'Bond | User supplied | restraints': -1, } count_1yjp_with_waters = count_1yjp.copy() count_1yjp_with_waters['Nonbonded interactions'] = 1178 @@ -54,6 +57,8 @@ def check_geo(geo_lines): def check_diff(d1,d2): outl = 'diff\n%s\n%s\n' % (d1,d2) for key in d1: + print(d1) + print(d2) if d1[key]!=d2[key]: outl += '%s : %d %d\n' % (key, d1[key], d2[key]) return outl @@ -86,7 +91,8 @@ def main(): rc = model.restraints_as_geo(force=True) rc = check_geo(rc) current = count_1yjp_with_waters.copy() - current['User supplied restraints'] = 1 + # current['User supplied restraints'] = 1 + current['Bond | User supplied | restraints'] = 1 current['Nonbonded interactions'] = 1176 assert rc == current, check_diff(rc, current) @@ -101,8 +107,8 @@ def main(): rc = model.restraints_as_geo(force=True) rc = check_geo(rc) current = count_1yjp_with_waters.copy() - current['User supplied restraints'] = 1 - current['User supplied angle restraints'] = 1 + current['Bond | User supplied | restraints'] = 1 + current['Bond angle | User supplied | restraints'] = 1 current['Nonbonded interactions'] = 1176 assert rc == current, check_diff(rc, current) @@ -119,9 +125,9 @@ def main(): rc = model.restraints_as_geo(force=True) rc = check_geo(rc) current = count_1yjp_with_waters.copy() - current['User supplied restraints'] = 1 - current['User supplied angle restraints'] = 1 - current['User supplied torsion angle restraints'] = 1 + current['Bond | User supplied | restraints'] = 1 + current['Bond angle | User supplied | restraints'] = 1 + current['Dihedral angle | User supplied | restraints'] = 1 #current[' sinusoidal'] = 16 current['Nonbonded interactions'] = 1176 assert rc == current, check_diff(rc, current) From b003e5256e02682496a2b14e0c8a7b11b8caf374 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Thu, 19 Sep 2024 13:48:23 -0700 Subject: [PATCH 721/748] update --- mmtbx/regression/pdb_interpretation/tst_edits.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mmtbx/regression/pdb_interpretation/tst_edits.py b/mmtbx/regression/pdb_interpretation/tst_edits.py index d1d1916e52..bd2172bef4 100644 --- a/mmtbx/regression/pdb_interpretation/tst_edits.py +++ b/mmtbx/regression/pdb_interpretation/tst_edits.py @@ -115,7 +115,7 @@ def exercise_user_edits(mon_lib_srv, ener_lib): with open(geo_fname, 'r') as f: user_suppl_count = 0 for l in f.readlines(): - if l.startswith("User supplied"): + if l.find("| User supplied |")>-1: user_suppl_count += 1 # Right now user-supplied planarity is missing from the .geo file. assert user_suppl_count == 5, "Expected 5 user-supplied restraints, got %i in the .geo" % user_suppl_count @@ -240,7 +240,7 @@ def exercise_angle_edits_change(mon_lib_srv, ener_lib): geo_file = open(pdb_file.name+'.geo', "r") # geo_file = open(pdb_file.name.replace(".pdb", '_minimized.geo'), "r") geo_file_str = geo_file.read() - assert '''User supplied angle restraints: 1 + assert '''| User supplied | restraints: 1 Sorted by residual: angle pdb=" N ALA A 2 " segid="A " pdb=" CA ALA A 2 " segid="A " From 10caab4f3ed6ba86903d97a2d30822a17b435b26 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 19 Sep 2024 14:52:15 -0700 Subject: [PATCH 722/748] Towards a general lbfgs minimizer: add a general minimizer class --- scitbx/minimizers.py | 60 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/scitbx/minimizers.py b/scitbx/minimizers.py index 2b2cbc0895..9018d8fa1d 100644 --- a/scitbx/minimizers.py +++ b/scitbx/minimizers.py @@ -1,9 +1,10 @@ from __future__ import absolute_import, division, print_function +import sys import scitbx.math from scitbx.array_family import flex from scitbx import lbfgsb as lbfgsb_core import scitbx.lbfgs as lbfgs_core -import sys +from libtbx import adopt_init_args floating_point_epsilon_double = scitbx.math.floating_point_epsilon_double_get() @@ -241,6 +242,63 @@ def show_statistics(self): print(" line_search_info:", \ self.line_search_info) + +class minimizer_lbfgs_general(object): + + def __init__(self, + mode, + calculator, + max_iterations = None, + diag_mode = None): + + adopt_init_args(self, locals()) + assert mode in ['lbfgs', 'lbfgsb'] + # necessary? also done in run_c_plus_plus + if diag_mode is not None: assert diag_mode in ['once', 'always'] + if self.mode == 'lbfgs': + self.x = self.calculator.x + # TODO: How to best expose all the params of these classes? + lbfgs_core_params = lbfgs_core.core_parameters() + termination_params = lbfgs_core.termination_parameters( + max_iterations=max_iterations) + exception_handling_params = lbfgs_core.exception_handling_parameters() + self.minimizer = lbfgs_core.run_c_plus_plus( + target_evaluator = self, + termination_params = termination_params, + core_params = lbfgs_core_params, + exception_handling_params = exception_handling_params, + log = None, + gradient_only = False, + line_search = False + ) + if self.mode == 'lbfgsb': + self.x = self.calculator.initial_values + self.minimizer = lbfgsb_core.run( + target_evaluator = self, + max_iterations = max_iterations, + use_bounds = self.calculator.n_bounds, + lower_bound = self.calculator.lower_bound, + upper_bound = self.calculator.upper_bound, + n = self.x.size()) + + def compute_functional_and_gradients(self): + self.calculator.update(x = self.x) + t = self.calculator.target() + g = self.calculator.gradients() + if self.mode == 'lbfgs': + return t,g + if self.mode == 'lbfgsb': + return self.x,t,g + + def compute_functional_gradients_diag(self): + self.calculator.update(x = self.x) + t = self.calculator.target() + g = self.calculator.gradients() + d = self.calculator.curvatures() + return t,g,d + + + class lbfgsb(object): """ Wrapper for LBGFGS-B minimizer with simplified interface. See lbfgsb_core for From 85da7499972da5ea56d3e9d877df0020d0f8a749 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 19 Sep 2024 15:38:28 -0700 Subject: [PATCH 723/748] Docstrings --- scitbx/minimizers.py | 69 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/scitbx/minimizers.py b/scitbx/minimizers.py index 9018d8fa1d..911b7fd5bb 100644 --- a/scitbx/minimizers.py +++ b/scitbx/minimizers.py @@ -244,13 +244,67 @@ def show_statistics(self): class minimizer_lbfgs_general(object): + """ + A general L-BFGS and L-BFGS-B minimizer class. + + This class implements a minimizer for solving optimization problems using + either the Limited-memory Broyden–Fletcher–Goldfarb–Shanno (L-BFGS) or + L-BFGS with Box constraints (L-BFGS-B) algorithms. + The behavior is determined by the selected mode, and it interacts with + provided calculator object to compute function values, gradients, and + curvatures. + + Parameters + ---------- + mode : str + The minimization mode, either 'lbfgs' for L-BFGS or 'lbfgsb' for + L-BFGS-B. + calculator : object + An object that provides methods to compute the target function value, + gradients, and optionally curvatures. It must have `x`, + `initial_values`, `target()`, `gradients()`, and `curvatures()` + methods. + max_iterations : int, optional + Maximum number of iterations for the minimization. Defaults to None, + allowing unlimited iterations. + diag_mode : str, optional + If specified, controls the frequency of diagonal updates for curvature + approximation. Must be either 'once' or 'always'. Defaults to None. + + Attributes + ---------- + x : flex.double + The current values of the variables being optimized. + minimizer : object + The underlying L-BFGS or L-BFGS-B minimizer object, depending on the + selected mode. + + Notes + ----- + - The class selects between L-BFGS and L-BFGS-B based on + the value of `mode`. For L-BFGS-B, it also uses bounds specified by the + `calculator` object. + - The `diag_mode` controls if curvature are used during optimization. + + Methods + ------- + compute_functional_and_gradients() + Computes the target function value and gradients for the current + values of the variables. + compute_functional_gradients_diag() + Computes the target function value, gradients, and curvatures + (diagonal) for the current values of the variables (only applicable + in modes where curvature is needed). + """ def __init__(self, mode, calculator, max_iterations = None, diag_mode = None): - + """ + Initialize the minimizer with the selected mode and calculator object. + """ adopt_init_args(self, locals()) assert mode in ['lbfgs', 'lbfgsb'] # necessary? also done in run_c_plus_plus @@ -282,6 +336,12 @@ def __init__(self, n = self.x.size()) def compute_functional_and_gradients(self): + """ + Compute the target function value and gradients. + + Updates the calculator with the current values of the variables `x`, + then computes the target function value and gradients. + """ self.calculator.update(x = self.x) t = self.calculator.target() g = self.calculator.gradients() @@ -291,6 +351,13 @@ def compute_functional_and_gradients(self): return self.x,t,g def compute_functional_gradients_diag(self): + """ + Compute the target function value, gradients, and diagonal curvatures. + + Updates the calculator with the current values of the variables `x`, + then computes the target function value, gradients, and curvatures + (diagonal elements). + """ self.calculator.update(x = self.x) t = self.calculator.target() g = self.calculator.gradients() From 3fdbcf6e7f60de268849008a55a31c238206a092 Mon Sep 17 00:00:00 2001 From: dcliebschner Date: Thu, 19 Sep 2024 15:47:16 -0700 Subject: [PATCH 724/748] Towards a general lbfgs minimizer: add test --- scitbx/tests/tst_minimizer_lbfgs_general.py | 91 +++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 scitbx/tests/tst_minimizer_lbfgs_general.py diff --git a/scitbx/tests/tst_minimizer_lbfgs_general.py b/scitbx/tests/tst_minimizer_lbfgs_general.py new file mode 100644 index 0000000000..11767ed056 --- /dev/null +++ b/scitbx/tests/tst_minimizer_lbfgs_general.py @@ -0,0 +1,91 @@ +from __future__ import absolute_import, division, print_function +import time +from scitbx.array_family import flex +from libtbx import adopt_init_args +import scitbx.lbfgs +from scitbx import lbfgsb +from scitbx import minimizers +from libtbx.test_utils import approx_equal + +class rosenbrock(object): + def __init__(self, a, b, x, # lbfgs and lbfgsb minimizer + n_bounds = None, # only lbfgsb + lower_bound = None, # only lbfgsb + upper_bound = None, # only lbfgsb + initial_values = None # only lbfgsb + ): + adopt_init_args(self, locals()) + assert self.x.size() == 2 + + def update(self, x): + self.x = x + assert self.x.size() == 2 + + def target(self): + t = (self.a-self.x[0])**2+self.b*(self.x[1]-self.x[0]**2)**2 + return t + + def gradients(self): + g1 = 2*(self.x[0]-self.a) + 4*self.b*(self.x[0]**3-self.x[0]*self.x[1]) + g2 = 2*self.b*(self.x[1]-self.x[0]**2) + return flex.double([g1,g2]) + + def curvatures(self): + d1 = 2+4*self.b*(-self.x[1]+3*self.x[0]**2) + d2 = 2*self.b + d = flex.double([d1,d2]) + assert d.all_ne(0) + return 1 / d + + +def run(): + # Run L-BFGS (no boundaries) + calculator = rosenbrock(a = 20, b = 10, x = flex.double([0,0]), + n_bounds = 2, + lower_bound = flex.double([-10000,-10000]), + upper_bound = flex.double([10000,10000]), + initial_values = flex.double([0,0])) + m_unbound = scitbx.minimizers.minimizer_lbfgs_general( + mode='lbfgs', max_iterations=100, calculator=calculator) + #print('\tMinimum: ', list(m_unbound.x)) + res = (19.99999855596629, 399.99994289914525) + assert approx_equal(m_unbound.x[0]-res[0],0, 1.e-16) + assert approx_equal(m_unbound.x[1]-res[1],0, 1.e-16) + + # Run L-BFGS-B with boundaries + calculator = rosenbrock(a = 20, b = 10, x = flex.double([0,0]), + n_bounds = 2, + lower_bound = flex.double([-10000,-10000]), + upper_bound = flex.double([10000,10000]), + initial_values = flex.double([0,0])) + m_bound = scitbx.minimizers.minimizer_lbfgs_general( + mode='lbfgsb', calculator=calculator) + #print('\tMinimum: ', list(m_bound.x)) + res = (19.999999988074844, 399.99999950735986) + assert approx_equal(m_bound.x[0]-res[0],0, 1.e-16) + assert approx_equal(m_bound.x[1]-res[1],0, 1.e-16) + + # Run L-BFGS (no curvatures) + calculator = rosenbrock(a = 1, b = 100, x = flex.double([-3,-4])) + m_unbound = scitbx.minimizers.minimizer_lbfgs_general( + mode='lbfgs', calculator=calculator) + #print('\tMinimum: ', list(m_unbound.x)) + res = (0.9999998308201578, 0.9999996829964546) + assert approx_equal(m_unbound.x[0]-res[0],0, 1.e-16) + assert approx_equal(m_unbound.x[1]-res[1],0, 1.e-16) + + + # Run L-BFGS (with curvatures) + calculator = rosenbrock(a = 1, b = 100, x = flex.double([-3,-4])) + m_unbound2 = scitbx.minimizers.minimizer_lbfgs_general( + mode='lbfgs', calculator=calculator, diag_mode='always') + #print('\tMinimum: ', list(m_unbound2.x)) + res = (1.0000002135019004, 1.000000406037043) + assert approx_equal(m_unbound2.x[0]-res[0],0, 1.e-16) + assert approx_equal(m_unbound2.x[1]-res[1],0, 1.e-16) + + +if (__name__ == "__main__"): + t0 = time.time() + run() + print("OK. Time: %8.3f"%(time.time()-t0)) From ed70df65554ccf459260b4b6afdbd15839a15067 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Thu, 19 Sep 2024 21:59:12 -0700 Subject: [PATCH 725/748] Switch to normal dash in docstring --- scitbx/lbfgsb.py | 2 +- scitbx/minimizers.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scitbx/lbfgsb.py b/scitbx/lbfgsb.py index 8a577e8f8c..fe4bd6f5e8 100644 --- a/scitbx/lbfgsb.py +++ b/scitbx/lbfgsb.py @@ -44,7 +44,7 @@ def run(target_evaluator, evaluator and bounds. This function minimizes a target function using the Limited-memory - Broyden–Fletcher–Goldfarb–Shanno with Box constraints (L-BFGS-B) + Broyden-Fletcher-Goldfarb-Shanno with Box constraints (L-BFGS-B) algorithm. It iteratively calls the target evaluator to compute the function value and gradients, and processes them with the L-BFGS-B minimizer. diff --git a/scitbx/minimizers.py b/scitbx/minimizers.py index 911b7fd5bb..ef775121f7 100644 --- a/scitbx/minimizers.py +++ b/scitbx/minimizers.py @@ -248,7 +248,7 @@ class minimizer_lbfgs_general(object): A general L-BFGS and L-BFGS-B minimizer class. This class implements a minimizer for solving optimization problems using - either the Limited-memory Broyden–Fletcher–Goldfarb–Shanno (L-BFGS) or + either the Limited-memory Broyden-Fletcher-Goldfarb-Shanno (L-BFGS) or L-BFGS with Box constraints (L-BFGS-B) algorithms. The behavior is determined by the selected mode, and it interacts with provided calculator object to compute function values, gradients, and From 41294a66c648f33bb9200fcc7aa89da33826b4e3 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Fri, 20 Sep 2024 16:48:00 -0700 Subject: [PATCH 726/748] expanded cyclic amino acid classes and set default to True --- mmtbx/monomer_library/linking_mixins.py | 5 +- mmtbx/monomer_library/linking_utils.py | 12 ++++- mmtbx/monomer_library/pdb_interpretation.py | 5 +- mmtbx/monomer_library/tst_linking.py | 60 +++++++++++++++++++-- 4 files changed, 74 insertions(+), 8 deletions(-) diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index 624a13569e..cd2595d28d 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -565,7 +565,7 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., i_seqs=None): if (not link_small_molecules and (classes1.common_small_molecule or classes2.common_small_molecule)): continue # is_proxy_set between any of the atoms ???????? - if classes1.common_amino_acid and classes2.common_amino_acid: + if linking_utils.allow_cis_trans(classes1, classes2): if not link_residues: continue # special amino acid linking @@ -651,7 +651,8 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., i_seqs=None): if not link_residues: if class_key in [ ("common_amino_acid", "common_amino_acid"), - #("common_amino_acid", "other"), + ("common_amino_acid", "d_amino_acid"), + ("common_amino_acid", "uncommon_amino_acid"), ]: continue #else: diff --git a/mmtbx/monomer_library/linking_utils.py b/mmtbx/monomer_library/linking_utils.py index 2478f7d220..1c2312213a 100644 --- a/mmtbx/monomer_library/linking_utils.py +++ b/mmtbx/monomer_library/linking_utils.py @@ -337,11 +337,21 @@ def is_atom_metal_coordinated(lookup, def _get_cis_trans(): return 'TRANS' +def allow_cis_trans_important(class_important_1, class_important_2): + peptides = ['common_amino_acid', 'd_amino_acid', 'uncommon_amino_acid'] + if class_important_1 in peptides and class_important_2 in peptides: + return True + return False + +def allow_cis_trans(classes1, classes2): + return allow_cis_trans_important(classes1.important_only, classes2.important_only) + def is_atom_pair_linked_tuple(atom1, atom2, class_important_1, class_important_2): - if class_important_1=='common_amino_acid' and class_important_2==class_important_1: + # if class_important_1=='common_amino_acid' and class_important_2==class_important_1: + if allow_cis_trans_important(class_important_1, class_important_2): if atom1.name==' N ' and atom2.name==' C ': return _get_cis_trans(), False, '?' elif atom1.name==' C ' and atom2.name==' N ': diff --git a/mmtbx/monomer_library/pdb_interpretation.py b/mmtbx/monomer_library/pdb_interpretation.py index 7626bd7857..ce4aa22fde 100644 --- a/mmtbx/monomer_library/pdb_interpretation.py +++ b/mmtbx/monomer_library/pdb_interpretation.py @@ -290,7 +290,7 @@ def __init__(self, residue_name, atom_name, atom_element): .style = noauto link_metals = Auto .type = bool - link_residues = False + link_residues = True .type = bool .short_caption = Link amino acids in "special" ways such as cyclic and \ side-chain to side-chain links @@ -3827,7 +3827,8 @@ def raise_missing_cif(i_pair): apply.was_used = True def raise_if_corrupt(link_resolution): counters = link_resolution.counters - if (counters.corrupt_monomer_library_definitions != 0): + if (counters.corrupt_monomer_library_definitions != 0 or + getattr(link_resolution, 'broken_bond_i_seq_pairs', False)): raise Sorry( "Error processing %s:\n" % counters.label + " data_link: %s\n" % show_string(apply.data_link) diff --git a/mmtbx/monomer_library/tst_linking.py b/mmtbx/monomer_library/tst_linking.py index eeff7fe841..010e6f72e3 100644 --- a/mmtbx/monomer_library/tst_linking.py +++ b/mmtbx/monomer_library/tst_linking.py @@ -2358,6 +2358,59 @@ selection_2 = all } } + ''', + 'linking_test_cyclic_d_amino_acid.pdb' : ''' +CRYST1 62.592 88.672 79.544 90.00 90.00 90.00 P 1 0 +SCALE1 0.015976 0.000000 0.000000 0.00000 +SCALE2 0.000000 0.011278 0.000000 0.00000 +SCALE3 0.000000 0.000000 0.012572 0.00000 +ATOM 1 N ALA A 1 139.541 141.181 96.260 1.00 20.00 N +ATOM 2 CA ALA A 1 138.637 140.412 97.146 1.00 20.00 C +ATOM 3 C ALA A 1 139.314 139.161 97.689 1.00 20.00 C +ATOM 4 O ALA A 1 140.095 138.531 96.963 1.00 20.00 O +ATOM 5 CB ALA A 1 137.356 140.101 96.417 1.00 20.00 C +ATOM 6 O ALA A 2 137.325 136.971 99.601 1.00 30.00 O +ATOM 7 N ALA A 2 139.043 138.844 98.952 1.00 30.00 N +ATOM 8 CA ALA A 2 139.595 137.635 99.598 1.00 30.00 C +ATOM 9 C ALA A 2 138.408 136.872 100.186 1.00 30.00 C +ATOM 10 CB ALA A 2 140.622 138.035 100.627 1.00 30.00 C +ATOM 11 O GLY A 3 137.830 133.641 100.447 1.00 30.00 O +ATOM 12 N GLY A 3 138.559 136.152 101.290 1.00 30.00 N +ATOM 13 CA GLY A 3 137.375 135.482 101.846 1.00 30.00 C +ATOM 14 C GLY A 3 136.942 134.331 100.969 1.00 30.00 C +ATOM 15 O ALA A 4 136.226 132.849 97.746 1.00 30.00 O +ATOM 16 N ALA A 4 135.635 134.109 100.811 1.00 30.00 N +ATOM 17 CA ALA A 4 135.185 133.051 99.882 1.00 30.00 C +ATOM 18 C ALA A 4 135.449 133.514 98.449 1.00 30.00 C +ATOM 19 CB ALA A 4 133.736 132.690 100.110 1.00 30.00 C +ATOM 20 O ALA A 5 136.629 136.668 96.001 1.00 30.00 O +ATOM 21 N ALA A 5 134.856 134.630 98.036 1.00 30.00 N +ATOM 22 CA ALA A 5 134.990 135.102 96.644 1.00 30.00 C +ATOM 23 C ALA A 5 136.429 135.521 96.406 1.00 30.00 C +ATOM 24 CB ALA A 5 134.055 136.265 96.409 1.00 30.00 C +ATOM 25 O ALA A 6 139.834 134.403 94.458 1.00 30.00 O +ATOM 26 N ALA A 6 137.389 134.638 96.643 1.00 30.00 N +ATOM 27 CA ALA A 6 138.809 135.028 96.518 1.00 30.00 C +ATOM 28 C ALA A 6 139.123 135.234 95.043 1.00 30.00 C +ATOM 29 CB ALA A 6 139.676 133.969 97.130 1.00 30.00 C +ATOM 30 O ALA A 7 137.722 138.645 93.058 1.00 30.00 O +ATOM 31 N ALA A 7 138.555 136.270 94.446 1.00 30.00 N +ATOM 32 CA ALA A 7 138.715 136.491 92.997 1.00 30.00 C +ATOM 33 C ALA A 7 138.736 137.996 92.776 1.00 30.00 C +ATOM 34 CB ALA A 7 137.571 135.846 92.258 1.00 30.00 C +ATOM 35 N DPR A 8 139.914 138.630 92.485 1.00 20.00 N +ATOM 36 CA DPR A 8 139.816 140.123 92.327 1.00 20.00 C +ATOM 37 CB DPR A 8 140.573 140.423 91.018 1.00 20.00 C +ATOM 38 CG DPR A 8 141.601 139.328 90.913 1.00 20.00 C +ATOM 39 CD DPR A 8 141.393 138.483 92.150 1.00 20.00 C +ATOM 40 C DPR A 8 140.000 141.439 93.121 1.00 20.00 C +ATOM 41 O DPR A 8 139.549 142.442 92.591 1.00 20.00 O +ATOM 42 N DAL A 9 140.609 141.365 93.957 1.00 20.00 N +ATOM 43 CA DAL A 9 140.665 142.742 94.522 1.00 20.00 C +ATOM 44 CB DAL A 9 142.190 142.550 94.599 1.00 20.00 C +ATOM 45 C DAL A 9 140.049 142.247 95.882 1.00 20.00 C +ATOM 46 O DAL A 9 139.571 143.185 96.612 1.00 20.00 O +END ''', } @@ -2406,7 +2459,8 @@ "linking_test_MAN-before-ASN.pdb" : [15,15], "linking_test_partial_alt_loc_glyco.pdb" : [63,67], 'linking_test_CM-SO4.pdb' : [4,4], - 'linking_test_exclusion_SO4.pdb' :[24,22] + 'linking_test_exclusion_SO4.pdb' :[24,22], + 'linking_test_cyclic_d_amino_acid.pdb' : [46,47], } def run_and_test(cmd, pdb, i, skip_links=False): @@ -2516,7 +2570,7 @@ def run(only_i=None): f.close() if pdb.endswith(".cif"): cifs += " %s" % pdb j=0 - for pdb in sorted(pdbs): + for k, pdb in enumerate(sorted(pdbs)): #break if pdb.endswith(".cif"): continue if pdb.endswith(".params"): continue @@ -2526,7 +2580,7 @@ def run(only_i=None): if pdb.find("partial")>-1: continue #if pdb.find('SO4')==-1: continue if pdb in ['linking_test_exclusion_SO4.pdb']: continue - print('pdb '*10,pdb) + print('pdb '*10,k-10,pdb) j+=1 if only_i is not None and only_i!=j: continue for i in range(2): From 0bb7bfea0945da1d787bf2326848f8cc15963700 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Sun, 22 Sep 2024 21:06:42 -0700 Subject: [PATCH 727/748] update --- mmtbx/monomer_library/linking_mixins.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mmtbx/monomer_library/linking_mixins.py b/mmtbx/monomer_library/linking_mixins.py index cd2595d28d..dd5b01a5dc 100644 --- a/mmtbx/monomer_library/linking_mixins.py +++ b/mmtbx/monomer_library/linking_mixins.py @@ -655,6 +655,8 @@ def _nonbonded_pair_objects(max_bonded_cutoff=3., i_seqs=None): ("common_amino_acid", "uncommon_amino_acid"), ]: continue + else: + if len(key)>2: continue #else: # atoms_must_be.setdefault(("common_amino_acid", # "common_amino_acid"),["C", "N"]) From 12911b38920025d34dad305aad8f15244c1e27da Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Sun, 22 Sep 2024 22:15:41 -0700 Subject: [PATCH 728/748] update --- mmtbx/monomer_library/linking_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mmtbx/monomer_library/linking_utils.py b/mmtbx/monomer_library/linking_utils.py index 1c2312213a..764a33d436 100644 --- a/mmtbx/monomer_library/linking_utils.py +++ b/mmtbx/monomer_library/linking_utils.py @@ -356,8 +356,8 @@ def is_atom_pair_linked_tuple(atom1, return _get_cis_trans(), False, '?' elif atom1.name==' C ' and atom2.name==' N ': return _get_cis_trans(), True, '?' - else: - print('amino acid link not found',atom1.quote(),atom2.quote()) + # else: + # print('amino acid link not found',atom1.quote(),atom2.quote()) return None, None, None def is_atom_pair_linked(atom1, From d82c25109f9dc204bbf2fae247c479ab3ca313de Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Mon, 23 Sep 2024 09:01:35 -0700 Subject: [PATCH 729/748] make defaults the same as old --- cctbx/geometry_restraints/tst_nonbonded_overlaps.py | 8 +++++++- .../geometry_restraints/tst_process_nonbonded_proxies.py | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/cctbx/geometry_restraints/tst_nonbonded_overlaps.py b/cctbx/geometry_restraints/tst_nonbonded_overlaps.py index 956479c39b..7089cf30b4 100644 --- a/cctbx/geometry_restraints/tst_nonbonded_overlaps.py +++ b/cctbx/geometry_restraints/tst_nonbonded_overlaps.py @@ -639,6 +639,7 @@ def test_atom_selection(self): outstring = '{0} , expected {1:.2f}, actual {2:.2f}' params = mmtbx.model.manager.get_default_pdb_interpretation_params() params.pdb_interpretation.allow_polymer_cross_special_position=True + params.pdb_interpretation.automatic_linking.link_residues=False pdb_inp = iotbx.pdb.input(lines=raw_records3.split("\n"), source_info=None) model = mmtbx.model.manager( model_input = pdb_inp, @@ -677,11 +678,14 @@ def test_labels_and_addition_scatterers(self): Test overlaps when adding and moving scatterers Test water scatterers with and without labels ''' + params = mmtbx.model.manager.get_default_pdb_interpretation_params() + params.pdb_interpretation.allow_polymer_cross_special_position=True + params.pdb_interpretation.automatic_linking.link_residues=False pdb_inp = iotbx.pdb.input(lines=raw_records3.split('\n'), source_info=None) model = mmtbx.model.manager( model_input = pdb_inp, log = null_out()) - model.process(make_restraints=True) + model.process(pdb_interpretation_params=params, make_restraints=True) outstring = '{0} , expected {1:.2f}, actual {2:.2f}' geometry = model.get_restraints_manager().geometry xrs = model.get_xray_structure() @@ -711,6 +715,7 @@ def test_labels_and_addition_scatterers(self): pdb_str = model.model_as_pdb() params = mmtbx.model.manager.get_default_pdb_interpretation_params() params.pdb_interpretation.allow_polymer_cross_special_position=True + params.pdb_interpretation.automatic_linking.link_residues=False pdb_inp = iotbx.pdb.input(lines=pdb_str.split('\n'), source_info=None) model = mmtbx.model.manager( model_input = pdb_inp, @@ -1078,6 +1083,7 @@ def process_raw_records( params = mmtbx.model.manager.get_default_pdb_interpretation_params() params.pdb_interpretation.allow_polymer_cross_special_position=True params.pdb_interpretation.clash_guard.nonbonded_distance_threshold = None + params.pdb_interpretation.automatic_linking.link_residues=False pdb_inp = iotbx.pdb.input(lines=records, source_info=None) model = mmtbx.model.manager( model_input = pdb_inp, diff --git a/cctbx/geometry_restraints/tst_process_nonbonded_proxies.py b/cctbx/geometry_restraints/tst_process_nonbonded_proxies.py index fd0c5e1b78..2cd62fde28 100644 --- a/cctbx/geometry_restraints/tst_process_nonbonded_proxies.py +++ b/cctbx/geometry_restraints/tst_process_nonbonded_proxies.py @@ -44,6 +44,7 @@ def get_clashes_result(raw_records, sel=None): params = mmtbx.model.manager.get_default_pdb_interpretation_params() params.pdb_interpretation.allow_polymer_cross_special_position=True params.pdb_interpretation.clash_guard.nonbonded_distance_threshold = None + params.pdb_interpretation.automatic_linking.link_residues=False pdb_inp = iotbx.pdb.input(lines=raw_records.split("\n"), source_info=None) model = mmtbx.model.manager( model_input = pdb_inp, From 98fe1eb6568d6ae1f9caaf9b8e486bd097a59f79 Mon Sep 17 00:00:00 2001 From: "Nigel W. Moriarty" Date: Tue, 24 Sep 2024 09:01:57 -0700 Subject: [PATCH 730/748] fixed link_residues test --- mmtbx/monomer_library/tst_linking.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mmtbx/monomer_library/tst_linking.py b/mmtbx/monomer_library/tst_linking.py index 010e6f72e3..a27c25349c 100644 --- a/mmtbx/monomer_library/tst_linking.py +++ b/mmtbx/monomer_library/tst_linking.py @@ -2588,11 +2588,10 @@ def run(only_i=None): cmd = "phenix.geometry_minimization %s write_geo_file=True" % pdb cmd += " link_all=%d link_carbohydrate=%d %s" % (i, i, cifs) cmd += " link_ligand=%d" % i - if pdb in [ - "linking_test_ccp4_other.pdb", - ]: - if i: - cmd += " secondary_structure.enabled=1" + if pdb in ["linking_test_ccp4_other.pdb"]: + if i: cmd += " secondary_structure.enabled=1" + if pdb in ['linking_test_cyclic_d_amino_acid.pdb']: + if not i: cmd += ' link_residues=False' if pdb.replace(".pdb", ".params") in pdbs: cmd += " %s" % pdb.replace(".pdb", ".params") print('='*80) From 6a6e55e279c7738e10fe80b12ef4f69e8beb0f1c Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Tue, 24 Sep 2024 11:06:34 -0700 Subject: [PATCH 731/748] cootbx: make file finding more portable - Works for both development builds and installer builds [skip ci] --- cootbx/__init__.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cootbx/__init__.py b/cootbx/__init__.py index e4e839e8ab..ba46b4308f 100644 --- a/cootbx/__init__.py +++ b/cootbx/__init__.py @@ -34,13 +34,11 @@ def create_refinement_view_script( print("import coot", file=f) print("import os", file=f) write_disable_nomenclature_errors(f) - load_script = libtbx.env.find_in_repositories( - relative_path="cctbx_project/cootbx/view_refinement.py", + load_script = libtbx.env.under_dist("cootbx", "view_refinement.py", test=os.path.isfile) assert (load_script is not None) concatenate_python_script(out=f, file_name=load_script) - zoom_ligand_script = libtbx.env.find_in_repositories( - relative_path="cctbx_project/cootbx/simple_zoom_list.py", + zoom_ligand_script = libtbx.env.under_dist("cootbx", "simple_zoom_list.py", test=os.path.isfile) concatenate_python_script(out=f, file_name=zoom_ligand_script) if (work_dir is not None): From 6db802164efa69f8509dcf85eb40a2975b657919 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Tue, 24 Sep 2024 11:48:16 -0700 Subject: [PATCH 732/748] bootstrap: add AlphaFold repository [skip ci] --- libtbx/auto_build/bootstrap.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libtbx/auto_build/bootstrap.py b/libtbx/auto_build/bootstrap.py index bf9943aa16..0d04552c88 100644 --- a/libtbx/auto_build/bootstrap.py +++ b/libtbx/auto_build/bootstrap.py @@ -938,6 +938,12 @@ class phenix_pathwalker_module(SourceModule): module = 'phenix_pathwalker' anonymous = ['git', 'git@github.com:phenix-project/phenix_pathwalker.git'] +class alphafold_module(SourceModule): + module = 'alphafold' + anonymous = ['git', + 'git@github.com:google-deepmind/alphafold.git', + 'https://github.com/google-deepmind/alphafold.git'] + # Phaser repositories class phaser_module(SourceModule): module = 'phaser' From d7d0138fbc88fe1098622d2d38696800f245c46c Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Tue, 24 Sep 2024 13:50:18 -0700 Subject: [PATCH 733/748] conda: clean up devenv file fot cctbx dependencies [skip ci] --- libtbx/auto_build/conda_envs/cctbx.devenv.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libtbx/auto_build/conda_envs/cctbx.devenv.yml b/libtbx/auto_build/conda_envs/cctbx.devenv.yml index ef7f8e5f4c..0f9fbbccc7 100644 --- a/libtbx/auto_build/conda_envs/cctbx.devenv.yml +++ b/libtbx/auto_build/conda_envs/cctbx.devenv.yml @@ -15,8 +15,3 @@ dependencies: - libtiff - pint - pybind11 - - # dxtbx testing - - dials-data - - pytest-mock - - pytest-xdist From ee847b86eb8e1ef31cca26e52ac2b28ec940711f Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 25 Sep 2024 15:31:57 -0700 Subject: [PATCH 734/748] CI: switch mamba to conda --- .azure-pipelines/unix-conda-build.yml | 2 +- .azure-pipelines/xfel/unix-psana-build.yml | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.azure-pipelines/unix-conda-build.yml b/.azure-pipelines/unix-conda-build.yml index 1a291ae245..ee14248496 100644 --- a/.azure-pipelines/unix-conda-build.yml +++ b/.azure-pipelines/unix-conda-build.yml @@ -84,7 +84,7 @@ steps: - script: | set -xe source $(Pipeline.Workspace)/miniforge/etc/profile.d/conda.sh - mamba update --all -y -n base + conda update --all -y -n base displayName: Update miniforge # create conda environment diff --git a/.azure-pipelines/xfel/unix-psana-build.yml b/.azure-pipelines/xfel/unix-psana-build.yml index 25ab5d8361..8580b3aa02 100644 --- a/.azure-pipelines/xfel/unix-psana-build.yml +++ b/.azure-pipelines/xfel/unix-psana-build.yml @@ -48,10 +48,9 @@ steps: - script: | set -xe source $(Pipeline.Workspace)/miniforge/etc/profile.d/conda.sh - conda install -y -c conda-forge mamba - mamba env create -f $(Pipeline.Workspace)/modules/cctbx_project/xfel/conda_envs/psana_environment.yml - mamba install -y -c conda-forge --no-deps -n psana_env junit-xml - mamba install -y -c conda-forge cmake pandas distro -n psana_env + conda env create -f $(Pipeline.Workspace)/modules/cctbx_project/xfel/conda_envs/psana_environment.yml + conda install -y -c conda-forge --no-deps -n psana_env junit-xml + conda install -y -c conda-forge cmake pandas distro -n psana_env displayName: Create conda environment retryCountOnTaskFailure: 3 From 079f2da03736d72efb520cc2b3df8b472d50b218 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 25 Sep 2024 14:30:01 -0700 Subject: [PATCH 735/748] libtbx: remove entry point functions --- libtbx/env_config.py | 84 -------------------------------------------- 1 file changed, 84 deletions(-) diff --git a/libtbx/env_config.py b/libtbx/env_config.py index f620483ae1..8d868399d2 100644 --- a/libtbx/env_config.py +++ b/libtbx/env_config.py @@ -2066,89 +2066,6 @@ def run(self): command.run() return dist.install_scripts - def regenerate_entry_point_console_scripts(self, verbose=True): - ''' - Creates all console_scripts entry point scripts from scratch and overwrites existing ones. - This is intended to be used by installers to relocate the entry point script paths. - ''' - try: - import distutils.dist - import libtbx.fastentrypoints # monkeypatches setuptools - import pkg_resources - import setuptools.command.easy_install - except ImportError: - return - - # Prepare generic script generator - distribution = distutils.dist.Distribution({'name': 'setuptools'}) - command = setuptools.command.easy_install.easy_install(distribution) - command.args = ['wheel'] # dummy argument - command.finalize_options() - - # Force regeneration of all known console_scripts - for pkg_resources_dist in pkg_resources.working_set: - console_scripts = pkg_resources_dist.get_entry_map().get('console_scripts') - if console_scripts: - if verbose: - print("Regenerating commands for %s: %s" % ( - pkg_resources_dist, - list(console_scripts), - )) - command.install_wrapper_scripts(pkg_resources_dist) - - def generate_entry_point_dispatchers(self): - ''' - Write indirect dispatcher scripts for all console_scripts entry points - that have existing dispatcher scripts in the base/bin directory, but - add a 'libtbx.' prefix. - Generate dispatchers for any libtbx.dispatcher.script entry points. - These can be arbitrary non-python scripts defined by modules. - ''' - try: - import pkg_resources - except ImportError: - return - if self.build_options.use_conda and os.name != "nt": - paths = { - os.path.normpath(os.path.join(sys.prefix, "bin")), - os.path.normpath(os.path.join(get_conda_prefix(), "bin")), - } - else: - try: - paths = {self.get_setuptools_script_dir()} - except ImportError: - return - - for bin_directory in paths: - if not os.path.isdir(bin_directory): - continue # do not create console_scripts dispatchers, only point to them - - base_bin_dispatchers = os.listdir(bin_directory) - if os.name == "nt": - base_bin_dispatchers = [os.path.splitext(f)[0] if os.path.splitext( - f)[1] in ['.bat', '.exe'] else f for f in base_bin_dispatchers] - base_bin_dispatchers = set(base_bin_dispatchers) - existing_dispatchers = filter(lambda f: f.startswith( - 'libtbx.'), self.bin_path.listdir()) - existing_dispatchers = set([f[7:] for f in existing_dispatchers]) - entry_point_candidates = base_bin_dispatchers - existing_dispatchers - - entry_points = pkg_resources.iter_entry_points('console_scripts') - entry_points = filter(lambda ep: ep.name in entry_point_candidates, entry_points) - for ep in entry_points: - self.write_dispatcher( - source_file=os.path.join(bin_directory, ep.name), - target_file=os.path.join('bin', 'libtbx.' + ep.name), - ) - - entry_points = pkg_resources.iter_entry_points('libtbx.dispatcher.script') - entry_points = filter(lambda ep: ep.name in entry_point_candidates, entry_points) - for ep in entry_points: - self.write_dispatcher( - source_file=os.path.join(bin_directory, ep.module_name), - target_file=os.path.join('bin', ep.name), - ) - def write_command_version_duplicates(self): if (self.command_version_suffix is None): return suffix = "_" + self.command_version_suffix @@ -2283,7 +2200,6 @@ def refresh(self): os.environ.pop('SETUPTOOLS_ENABLE_FEATURES') self.write_python_and_show_path_duplicates() - self.generate_entry_point_dispatchers() self.process_exe() self.write_command_version_duplicates() if (os.name != "nt"): # LD_LIBRARY_PATH for dependencies From b0d9ec87d42d103f13c826125ea4a43b36913a2f Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Wed, 25 Sep 2024 14:39:00 -0700 Subject: [PATCH 736/748] libtbx: remove most distutils imports - Fixes #1018 for more general Python 3.12 support - Three remaining distutils imports remain, but in deprecated code --- libtbx/clear_paths.py | 4 ++-- libtbx/command_line/remove_tree.py | 4 ++-- libtbx/path.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libtbx/clear_paths.py b/libtbx/clear_paths.py index 0f6fef1851..ccf00d0211 100644 --- a/libtbx/clear_paths.py +++ b/libtbx/clear_paths.py @@ -1,9 +1,9 @@ from __future__ import absolute_import, division, print_function -from distutils.dir_util import remove_tree import random import stat import os import os.path as op +from shutil import rmtree from six.moves import range def make_paths_writable_if_possible(paths): @@ -34,7 +34,7 @@ def remove_directories_if_possible(paths): for path in paths: if (op.isdir(path)): try: - remove_tree(path) + rmtree(path, ignore_errors=True) except KeyboardInterrupt: raise except Exception: pass diff --git a/libtbx/command_line/remove_tree.py b/libtbx/command_line/remove_tree.py index 7697b64edb..cb14e021d1 100644 --- a/libtbx/command_line/remove_tree.py +++ b/libtbx/command_line/remove_tree.py @@ -1,5 +1,5 @@ from __future__ import absolute_import, division, print_function -import distutils.dir_util +from shutil import rmtree import sys, os def run(): @@ -7,7 +7,7 @@ def run(): if (os.path.isfile(arg)): os.remove(arg) elif (os.path.isdir(arg)): - distutils.dir_util.remove_tree(arg) + rmtree(arg) if (__name__ == "__main__"): run() diff --git a/libtbx/path.py b/libtbx/path.py index 513e28e452..daf6fdb965 100644 --- a/libtbx/path.py +++ b/libtbx/path.py @@ -283,9 +283,9 @@ def remove(self): assert not self.exists() def remove_tree(self): - from distutils.dir_util import remove_tree + from shutil import rmtree if self.isdir(): - remove_tree(abs(self)) + rmtree(abs(self)) else: self.remove() From 93560d19328613810a41ca26000e91a3b9226b78 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Thu, 26 Sep 2024 15:17:36 -0700 Subject: [PATCH 737/748] conda: add Boost packages and bump minimum Python version [skip ci] --- libtbx/auto_build/conda_envs/cctbxlite.devenv.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libtbx/auto_build/conda_envs/cctbxlite.devenv.yml b/libtbx/auto_build/conda_envs/cctbxlite.devenv.yml index 962dfe0d7a..952ce3f195 100644 --- a/libtbx/auto_build/conda_envs/cctbxlite.devenv.yml +++ b/libtbx/auto_build/conda_envs/cctbxlite.devenv.yml @@ -9,8 +9,10 @@ dependencies: # cctbx-base # host - future + - libboost-devel + - libboost-python-devel - numpy - - python ={{ get_env("PY_VER", default="3.8") }} + - python ={{ get_env("PY_VER", default="3.9") }} - python.app # [osx] - scons - setuptools From 1be152461bff3cefe9432d44f6dcb21a4a965046 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Fri, 27 Sep 2024 11:21:54 -0700 Subject: [PATCH 738/748] CI: update mirror in syntax check [skip ci] --- .azure-pipelines/syntax.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.azure-pipelines/syntax.yml b/.azure-pipelines/syntax.yml index 9f1299611b..49b6604463 100644 --- a/.azure-pipelines/syntax.yml +++ b/.azure-pipelines/syntax.yml @@ -27,9 +27,27 @@ jobs: steps: + - task: InstallSSHKey@0 + inputs: + knownHostsEntry: boa.lbl.gov ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAnPOtqyYASs6hc3fsmUQn92ovSozJsMsJyrMWjppUERX1tD4Fh0D7YaNhLvYpKi5mYVREo+tsKoOatCcqKGHCONWpzx7JHXUzfIBsy6nCeygRyyW4yuyoCuYFvOYLkaM4PrN/7XaZEnp1ux6/ZcbRxBDNK4f42svJUV39OX33tRuQWpP+O85paJr1ePHVz6U2n14a+3fRN3DBMti1dJuKOThU4djYEBQimx54pnW71eYORN2oUz+N/4RHAcomtxZpcUMl3Qadw8hD4s1XM6fzJ0Que7KefnnrPOgAEtZxKl9j09aaE70Oh+ie5Y6ckwddJ/4qZB5m2tBaEi3xuy0TSQ== + sshPublicKey: ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA7XgVgdU9GmZuo5yVyW/htrAuxe7ypuq7IowWwfUC0WZw9SPzQ8kOGj63plF3ytx/qpgvUlS1AiywO20rZ83gHmRdAiuvt9laH09KlWEUhIhAQTzesqBG5aUT0MKo01yxijoRl5HC8w/MdOanc0h01e6IxnZvgG0N30RB1i4xVPCtR/VBmXSp4R0T+Q/gJjfQssuBxHVMrrute4V3uUHek58FL2QgUB0+zq6ipETjuCJxTSyYVAFtCYDPYs+0lAYYkWrXALCr9kX9s22jYtkyv5kNw6mEW8nhtA7GbTdJLv4M6/WYtcvQV8TDcNCfltOfl81U3gcZ9zhQDKGVoNaJEw== buildbot@cci.lbl.gov + sshKeySecureFile: id_rsa + displayName: Download SSH key + - checkout: self path: ./modules/cctbx_project + - script: | + set -xe + ssh-keyscan -t rsa gitlab.com >> ~/.ssh/known_hosts + cd $(Pipeline.Workspace)/modules/cctbx_project + git remote add gitlab git@gitlab.com:cctbx/cctbx_project.git + git fetch gitlab + git push -u gitlab master + displayName: Update GitLab mirror + condition: eq(variables['PYTHON_VERSION'], '3.9') + continueOnError: true + - script: echo "##vso[task.prependpath]$CONDA/bin" displayName: Add conda to PATH From f269d4fe257a551ed7b72e241407752c01cb028a Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Fri, 27 Sep 2024 11:22:35 -0700 Subject: [PATCH 739/748] boost: add temporary flag for Boost Timer deprecation --- boost_adaptbx/SConscript | 1 + 1 file changed, 1 insertion(+) diff --git a/boost_adaptbx/SConscript b/boost_adaptbx/SConscript index 221d784444..bf788783f4 100644 --- a/boost_adaptbx/SConscript +++ b/boost_adaptbx/SConscript @@ -88,6 +88,7 @@ if (not env_etc.no_boost_python): # boost_adaptbx/meta_ext.cpp if (libtbx.env.build_options.use_conda): env_etc.cxxflags_bpl_defines_base.append("-DUSE_CONDA") + env_etc.cxxflags_bpl_defines_base.append("-DBOOST_TIMER_ENABLE_DEPRECATED") env_no_includes_boost_python_ext = env_base.Clone( SHLINKFLAGS=env_etc.shlinkflags_bpl, SHLIBPREFIX="") From f76dadef4794f22e51467ef3c04a8b98424c557a Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Fri, 27 Sep 2024 11:32:46 -0700 Subject: [PATCH 740/748] CI: add checkout step [skip ci] --- .azure-pipelines/syntax.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.azure-pipelines/syntax.yml b/.azure-pipelines/syntax.yml index 49b6604463..aa8ec7c287 100644 --- a/.azure-pipelines/syntax.yml +++ b/.azure-pipelines/syntax.yml @@ -41,6 +41,7 @@ jobs: set -xe ssh-keyscan -t rsa gitlab.com >> ~/.ssh/known_hosts cd $(Pipeline.Workspace)/modules/cctbx_project + git checkout master git remote add gitlab git@gitlab.com:cctbx/cctbx_project.git git fetch gitlab git push -u gitlab master From 890188d73d168e36a1e8509a45f256d441bda4f5 Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Fri, 27 Sep 2024 16:47:56 -0700 Subject: [PATCH 741/748] conda: add qt-webengine to devenv file [skip ci] --- libtbx/auto_build/conda_envs/cctbxlite.devenv.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/libtbx/auto_build/conda_envs/cctbxlite.devenv.yml b/libtbx/auto_build/conda_envs/cctbxlite.devenv.yml index 952ce3f195..7cb730a24f 100644 --- a/libtbx/auto_build/conda_envs/cctbxlite.devenv.yml +++ b/libtbx/auto_build/conda_envs/cctbxlite.devenv.yml @@ -33,6 +33,7 @@ dependencies: - ipython - pyside2 - pyzmq + - qt-webengine - websockets - wxpython From 5ca82bbe365eb2ef91ad4008de6457aa8fc9b818 Mon Sep 17 00:00:00 2001 From: Pavel Date: Sat, 28 Sep 2024 15:11:07 -0700 Subject: [PATCH 742/748] Catch None in arrays supplied to the minimizer --- cctbx/maptbx/bcr/bcr.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cctbx/maptbx/bcr/bcr.py b/cctbx/maptbx/bcr/bcr.py index 5c87c562ac..34669b4b75 100644 --- a/cctbx/maptbx/bcr/bcr.py +++ b/cctbx/maptbx/bcr/bcr.py @@ -626,8 +626,10 @@ def RefineBCR(dens,dist,bpeak,cpeak,rpeak,npeak,bmin,cmin,rmin,nfmes): lbound = [] ubound = [] for b in bcrbounds: - lbound.append(b[0]) - ubound.append(b[1]) + b0,b1=b[0],b[1] + assert b0 is not None and b1 is not None + lbound.append(b0) + ubound.append(b1) res = minimizer_bound( calculator = CALC, use_bounds = 2, From c0ef0d79214454511b669ce9772d6a6beb02b49d Mon Sep 17 00:00:00 2001 From: "Billy K. Poon" Date: Tue, 1 Oct 2024 09:34:44 -0700 Subject: [PATCH 743/748] Update CHANGELOG.rst for 2024.9 release [skip ci] --- CHANGELOG.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9c28e1f30b..10ed5d8421 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,10 @@ +2024.9 +====== + +* Added general minimizer class for LBFGS and LBFGS-B minimizers +* Enabled linking of modified amino acids for cyclic peptides +* Added functions for parsing .geo files + 2024.8 ====== From 51c8a608061c5ea1ff9254f0d7e3a043da78b49a Mon Sep 17 00:00:00 2001 From: Markus Gerstel Date: Wed, 19 Aug 2020 11:21:28 +0100 Subject: [PATCH 744/748] Disable broken test --- cctbx/run_tests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cctbx/run_tests.py b/cctbx/run_tests.py index f9d73dace3..461d49ee4e 100644 --- a/cctbx/run_tests.py +++ b/cctbx/run_tests.py @@ -152,7 +152,6 @@ "$D/regression/tst_connectivity.py", "$D/regression/tst_connectivity_allsym.py", "$D/regression/tst_diffuse.py", - "$D/regression/tst_grm_modifications.py", "$D/regression/tst_prepare_map_for_docking.py", "$D/regression/tst_wavelength_units.py", ] From e93cb83db04b9005cdabfefa6ecfad4029e9f1e4 Mon Sep 17 00:00:00 2001 From: Nicholas Devenish Date: Mon, 15 Mar 2021 17:43:11 +0000 Subject: [PATCH 745/748] Remove unstable test --- iotbx/run_tests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/iotbx/run_tests.py b/iotbx/run_tests.py index e477512a51..cf658da81f 100644 --- a/iotbx/run_tests.py +++ b/iotbx/run_tests.py @@ -144,7 +144,6 @@ "$D/bioinformatics/test/tst_alignment_as_hsearch.py", "$D/bioinformatics/test/tst_ebi_wu_blast_xml.py", "$D/bioinformatics/test/tst_ncbi_blast_xml.py", - "$D/bioinformatics/pdb_info.py", "$D/regression/tst_cif_as_pdb_1atom.py", "$D/regression/tst_cif_1.py", "$D/regression/tst_split_data_cif.py", From c21aa36d17154c5b59d16f737904c496bfe6ad42 Mon Sep 17 00:00:00 2001 From: Nicholas Devenish Date: Thu, 27 May 2021 18:47:43 +0100 Subject: [PATCH 746/748] Remove external data test --- iotbx/run_tests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/iotbx/run_tests.py b/iotbx/run_tests.py index cf658da81f..efe4b88e50 100644 --- a/iotbx/run_tests.py +++ b/iotbx/run_tests.py @@ -114,7 +114,6 @@ "$D/regression/tst_reflection_file_editor.py", "$D/regression/tst_split_models.py", "$D/regression/tst_pdb_as_fasta.py", - "$D/regression/tst_pdb_link_records.py", "$D/regression/tst_merging_statistics.py", "$D/regression/tst_simple_map_coefficients.py", "$D/regression/tst_sort_atoms.py", From 49f06304376de538f49685e6e668d704981bab42 Mon Sep 17 00:00:00 2001 From: Nicholas Devenish Date: Mon, 16 Jan 2023 11:48:58 +0000 Subject: [PATCH 747/748] Disable another failing test --- cctbx/run_tests.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cctbx/run_tests.py b/cctbx/run_tests.py index 461d49ee4e..9bfb8e8ac0 100644 --- a/cctbx/run_tests.py +++ b/cctbx/run_tests.py @@ -101,7 +101,6 @@ "$D/maptbx/tst_real_space_refinement_simple.py", "$D/maptbx/tst_interpolation.py", "$D/maptbx/tst_interpolation_2.py", - "$D/regression/tst_loc_res.py", "$D/maptbx/tst_target_and_gradients.py", ["$D/regression/tst_miller_merge_equivalents.py", "P31"], ["$D/regression/tst_grouped_data.py", "P31"], From dfa034d547e901cb9bec899d03616822a36ae0f4 Mon Sep 17 00:00:00 2001 From: Nicholas Devenish Date: Mon, 14 Aug 2023 14:31:17 +0100 Subject: [PATCH 748/748] Disable repeat-failing tests --- cctbx/run_tests.py | 1 - iotbx/run_tests.py | 1 - 2 files changed, 2 deletions(-) diff --git a/cctbx/run_tests.py b/cctbx/run_tests.py index 9bfb8e8ac0..e9902c3e24 100644 --- a/cctbx/run_tests.py +++ b/cctbx/run_tests.py @@ -56,7 +56,6 @@ "$D/geometry_restraints/tst_process_nonbonded_proxies.py", "$D/geometry_restraints/tst_angle_derivs.py", "$D/geometry_restraints/tst_motif.py", - "$D/adp_restraints/tst_ext.py", "$D/regression/tst_math_module.py", ["$D/regression/tst_krivy_gruber.py", "--Quick"], "$D/regression/tst_sgtbx.py", diff --git a/iotbx/run_tests.py b/iotbx/run_tests.py index efe4b88e50..b03ffac1d2 100644 --- a/iotbx/run_tests.py +++ b/iotbx/run_tests.py @@ -38,7 +38,6 @@ "$D/cif/tests/tst_geometry.py", "$D/cif/tests/tst_lex_parse_build.py", "$D/cif/tests/tst_model.py", - "$D/cif/tests/tst_restraints.py", "$D/cif/tests/tst_validation.py", "$D/cif/tests/tst_ucif_examples_compilation.py", "$D/cif/tests/tst_parser.py",