Files
Jungfraujoch/CPU_DATA_ANALYSIS.html
T
2026-07-19 09:00:52 +00:00

1 line
146 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html> <html lang=en data-content_root="./"> <meta charset=utf-8 /> <meta name=viewport content="width=device-width, initial-scale=1.0" /><meta name=viewport content="width=device-width, initial-scale=1" /> <meta name=viewport content="width=device-width,initial-scale=1"> <meta http-equiv=x-ua-compatible content="ie=edge"> <meta name="lang:clipboard.copy" content="Copy to clipboard"> <meta name="lang:clipboard.copied" content="Copied to clipboard"> <meta name="lang:search.language" content=en > <meta name="lang:search.pipeline.stopwords" content=True > <meta name="lang:search.pipeline.trimmer" content=True > <meta name="lang:search.result.none" content="No matching documents"> <meta name="lang:search.result.one" content="1 matching document"> <meta name="lang:search.result.other" content="# matching documents"> <meta name="lang:search.tokenizer" content="[\s\-]+"> <link href="https://fonts.gstatic.com/" rel=preconnect crossorigin> <link href="https://fonts.googleapis.com/css?family=Roboto+Mono:400,500,700|Roboto:300,400,400i,700&display=fallback" rel=stylesheet > <style> body, input { font-family: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif } code, kbd, pre { font-family: "Roboto Mono", "Courier New", Courier, monospace } </style> <link rel=stylesheet href="_static/stylesheets/application.css"/> <link rel=stylesheet href="_static/stylesheets/application-palette.css"/> <link rel=stylesheet href="_static/stylesheets/application-fixes.css"/> <link rel=stylesheet href="_static/fonts/material-icons.css"/> <meta name=theme-color content="#3f51b5"> <script src="_static/javascripts/modernizr.js"></script> <title>CPU-side crystallographic data analysis (Jungfraujoch) &#8212; Jungfraujoch 1.0.0-rc.160 documentation</title> <link rel=stylesheet type="text/css" href="_static/pygments.css?v=83e35b93" /> <link rel=stylesheet type="text/css" href="_static/material.css?v=79c92029" /> <script src="_static/documentation_options.js?v=a57231c3"></script> <script src="_static/doctools.js?v=9bcbadda"></script> <script src="_static/sphinx_highlight.js?v=dc90522c"></script> <script>window.MathJax = {"tex": {"tags": "ams", "inlineMath": [["\\(", "\\)"], ["$", "$"]], "displayMath": [["\\[", "\\]"], ["$$", "$$"]], "processEscapes": true}, "options": {"processHtmlClass": "tex2jax_process|mathjax_process|math|output_area"}}</script> <script defer=defer src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script> <link rel=icon href="_static/jfjoch.png"/> <link rel=index title=Index href=genindex.html /> <link rel=search title=Search href=search.html /> <link rel=next title=OpenAPI href=OPENAPI.html /> <link rel=prev title="Detector geometry" href=DETECTOR_GEOMETRY.html /> <body dir=ltr data-md-color-primary=indigo data-md-color-accent=lime> <svg class=md-svg > <defs data-children-count=0 > <svg xmlns="http://www.w3.org/2000/svg" width=500 height=500 viewBox="0 0 500 500" id=__gitlab ><path fill=currentColor d="M93.667 473.347l90.684-279.097H2.983l90.684 279.097z" transform="translate(156.198 1.16)"/><path fill=currentColor d="M221.333 473.345L130.649 194.25H3.557l217.776 279.095z" transform="translate(28.531 1.16)" opacity=.7 /><path fill=currentColor d="M32 195.155L4.441 279.97a18.773 18.773 0 0 0 6.821 20.99l238.514 173.29L32 195.155z" transform="translate(.089 .256)" opacity=.5 /><path fill=currentColor d="M2.667-84.844h127.092L75.14-252.942c-2.811-8.649-15.047-8.649-17.856 0L2.667-84.844z" transform="translate(29.422 280.256)"/><path fill=currentColor d="M2.667 473.345L93.351 194.25h127.092L2.667 473.345z" transform="translate(247.198 1.16)" opacity=.7 /><path fill=currentColor d="M221.334 195.155l27.559 84.815a18.772 18.772 0 0 1-6.821 20.99L3.557 474.25l217.777-279.095z" transform="translate(246.307 .256)" opacity=.5 /><path fill=currentColor d="M130.667-84.844H3.575l54.618-168.098c2.811-8.649 15.047-8.649 17.856 0l54.618 168.098z" transform="translate(336.974 280.256)"/></svg> </defs> </svg> <input class=md-toggle data-md-toggle=drawer type=checkbox id=__drawer > <input class=md-toggle data-md-toggle=search type=checkbox id=__search > <label class=md-overlay data-md-component=overlay for=__drawer ></label> <a href="#CPU_DATA_ANALYSIS" tabindex=1 class=md-skip > Skip to content </a> <header class=md-header data-md-component=header > <nav class="md-header-nav md-grid"> <div class="md-flex navheader"> <div class="md-flex__cell md-flex__cell--shrink"> <a href=index.html title="Jungfraujoch 1.0.0-rc.160 documentation" class="md-header-nav__button md-logo"> <i class=md-icon >&#xe30d</i> </a> </div> <div class="md-flex__cell md-flex__cell--shrink"> <label class="md-icon md-icon--menu md-header-nav__button" for=__drawer ></label> </div> <div class="md-flex__cell md-flex__cell--stretch"> <div class="md-flex__ellipsis md-header-nav__title" data-md-component=title > <span class=md-header-nav__topic >PSI Jungfraujoch</span> <span class=md-header-nav__topic > CPU-side crystallographic data analysis (Jungfraujoch) </span> </div> </div> <div class="md-flex__cell md-flex__cell--shrink"> <label class="md-icon md-icon--search md-header-nav__button" for=__search ></label> <div class=md-search data-md-component=search role=dialog > <label class=md-search__overlay for=__search ></label> <div class=md-search__inner role=search > <form class=md-search__form action=search.html method=get name=search > <input type=text class=md-search__input name=q placeholder=""Search"" autocapitalize=off autocomplete=off spellcheck=false data-md-component=query data-md-state=active > <label class="md-icon md-search__icon" for=__search ></label> <button type=reset class="md-icon md-search__icon" data-md-component=reset tabindex=-1 > &#xE5CD; </button> </form> <div class=md-search__output > <div class=md-search__scrollwrap data-md-scrollfix> <div class=md-search-result data-md-component=result > <div class=md-search-result__meta > Type to start searching </div> <ol class=md-search-result__list ></ol> </div> </div> </div> </div> </div> </div> <div class="md-flex__cell md-flex__cell--shrink"> <div class=md-header-nav__source > <a href="https://gitea.psi.ch/mx/jungfraujoch" title="Go to repository" class=md-source data-md-source=github > <div class=md-source__icon > <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" width=28 height=28 > <use xlink:href="#__gitlab" width=24 height=24 ></use> </svg> </div> <div class=md-source__repository > Jungfraujoch </div> </a> </div> </div> <script src="_static/javascripts/version_dropdown.js"></script> <script> var json_loc = ""versions.json"", target_loc = "../", text = "Versions"; $( document ).ready( add_version_dropdown(json_loc, target_loc, text)); </script> </div> </nav> </header> <div class=md-container > <nav class=md-tabs data-md-component=tabs > <div class="md-tabs__inner md-grid"> <ul class=md-tabs__list > <li class=md-tabs__item ><a href=index.html class=md-tabs__link >Jungfraujoch 1.0.0-rc.160 documentation</a> </ul> </div> </nav> <main class=md-main > <div class="md-main__inner md-grid" data-md-component=container > <div class="md-sidebar md-sidebar--primary" data-md-component=navigation > <div class=md-sidebar__scrollwrap > <div class=md-sidebar__inner > <nav class="md-nav md-nav--primary" data-md-level=0 > <label class="md-nav__title md-nav__title--site" for=__drawer > <a href=index.html title="Jungfraujoch 1.0.0-rc.160 documentation" class="md-nav__button md-logo"> <i class=md-icon >&#xe30d</i> </a> <a href=index.html title="Jungfraujoch 1.0.0-rc.160 documentation">PSI Jungfraujoch</a> </label> <div class=md-nav__source > <a href="https://gitea.psi.ch/mx/jungfraujoch" title="Go to repository" class=md-source data-md-source=github > <div class=md-source__icon > <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" width=28 height=28 > <use xlink:href="#__gitlab" width=24 height=24 ></use> </svg> </div> <div class=md-source__repository > Jungfraujoch </div> </a> </div> <ul class=md-nav__list > <li class=md-nav__item > <span class="md-nav__link caption"><span class=caption-text >General</span></span> <li class=md-nav__item > <a href=ACKNOWLEDGEMENT.html class=md-nav__link >Acknowledgements</a> <li class=md-nav__item > <a href=LICENSE.html class=md-nav__link >License</a> <li class=md-nav__item > <a href=THIRD_PARTY_NOTICES.html class=md-nav__link >Third-party software notices</a> <li class=md-nav__item > <a href=DETECTORS.html class=md-nav__link >Supported detectors</a> <li class=md-nav__item > <a href="DETECTORS.html#dectris-detectors" class=md-nav__link >DECTRIS detectors</a> <li class=md-nav__item > <a href=HARDWARE.html class=md-nav__link >Hardware requirements</a> <li class=md-nav__item > <a href=SOFTWARE.html class=md-nav__link >Software requirements</a> <li class=md-nav__item > <a href=VERSIONING.html class=md-nav__link >Semantic versioning</a> <li class=md-nav__item > <a href=DEPLOYMENT.html class=md-nav__link >Deployment</a> <li class=md-nav__item > <a href=REPOSITORIES.html class=md-nav__link >Linux package repositories</a> <li class=md-nav__item > <a href=NAMING.html class=md-nav__link >Naming</a> <li class=md-nav__item > <a href=CHANGELOG.html class=md-nav__link >Changelog</a> <li class=md-nav__item > <span class="md-nav__link caption"><span class=caption-text >Software</span></span> <li class=md-nav__item > <a href=JFJOCH_BROKER.html class=md-nav__link >jfjoch_broker</a> <li class=md-nav__item > <a href=JFJOCH_WRITER.html class=md-nav__link >jfjoch_writer</a> <li class=md-nav__item > <a href=RUGNUX.html class=md-nav__link >rugnux</a> <li class=md-nav__item > <a href=JFJOCH_VIEWER.html class=md-nav__link >jfjoch_viewer</a> <li class=md-nav__item > <a href=SOFTWARE_INTEGRATION.html class=md-nav__link >Integration with MX data processing software</a> <li class=md-nav__item > <a href=TOOLS.html class=md-nav__link >Tools</a> <li class=md-nav__item > <span class="md-nav__link caption"><span class=caption-text >FPGA</span></span> <li class=md-nav__item > <a href=FPGA.html class=md-nav__link >FPGA smartNIC</a> <li class=md-nav__item > <a href=FPGA_LICENSE.html class=md-nav__link >FPGA license</a> <li class=md-nav__item > <a href=FPGA_DESIGN.html class=md-nav__link >FPGA data flow</a> <li class=md-nav__item > <a href=FPGA_NETWORK.html class=md-nav__link >FPGA network</a> <li class=md-nav__item > <a href=FPGA_PCIE_DRIVER.html class=md-nav__link >FPGA PCIe driver</a> <li class=md-nav__item > <a href=FPGA_SETTINGS.html class=md-nav__link >FPGA advanced reference</a> <li class=md-nav__item > <a href=FPGA_DATA_ANALYSIS.html class=md-nav__link >FPGA data analysis</a> <li class=md-nav__item > <span class="md-nav__link caption"><span class=caption-text >Reference</span></span> <li class=md-nav__item > <a href=DETECTOR_GEOMETRY.html class=md-nav__link >Detector geometry</a> <li class=md-nav__item > <input class="md-toggle md-nav__toggle" data-md-toggle=toc type=checkbox id=__toc > <label class="md-nav__link md-nav__link--active" for=__toc > CPU-side crystallographic data analysis (Jungfraujoch) </label> <a href="#" class="md-nav__link md-nav__link--active">CPU-side crystallographic data analysis (Jungfraujoch)</a> <nav class="md-nav md-nav--secondary"> <ul class=md-nav__list data-md-scrollfix=""> </ul> </nav> <ul class=md-nav__list > <li class=md-nav__item > <a href="#references" class=md-nav__link >References</a> <li class=md-nav__item > <a href="#geometry-reciprocal-space-mapping-and-basic-quantities" class=md-nav__link >1. Geometry, reciprocal-space mapping, and basic quantities</a> <li class=md-nav__item > <a href="#azimuthal-integration-radial-profiles" class=md-nav__link >2. Azimuthal integration (radial profiles)</a> <li class=md-nav__item > <a href="#spot-finding-strong-pixels-bragg-spots" class=md-nav__link >3. Spot finding (strong pixels → Bragg spots)</a> <li class=md-nav__item > <a href="#indexing-overview" class=md-nav__link >4. Indexing overview</a> <li class=md-nav__item > <a href="#fft-indexing-unknown-unit-cell" class=md-nav__link >5. FFT indexing (unknown unit cell)</a> <li class=md-nav__item > <a href="#bravais-lattice-centering-inference-lattice-search" class=md-nav__link >6. Bravais lattice / centering inference (“lattice search”)</a> <li class=md-nav__item > <a href="#geometry-and-lattice-refinement" class=md-nav__link >7. Geometry and lattice refinement</a> <li class=md-nav__item > <a href="#reflection-prediction" class=md-nav__link >8. Reflection prediction</a> <li class=md-nav__item > <a href="#d-bragg-integration-profile-fitting-over-a-three-ring-roi" class=md-nav__link >9. 2D Bragg integration (profile fitting over a three-ring ROI)</a> <li class=md-nav__item > <a href="#scaling-and-merging" class=md-nav__link >10. Scaling and merging</a> <li class=md-nav__item > <a href="#mosaicity-and-profile-radius-monitoring" class=md-nav__link >11. Mosaicity and “profile radius” monitoring</a> <li class=md-nav__item > <a href="#auxiliary-statistics-i-i-and-wilson-plot" class=md-nav__link >12. Auxiliary statistics: ⟨I/σ(I)⟩ and Wilson plot</a> <li class=md-nav__item > <a href="#practical-notes-and-limitations" class=md-nav__link >13. Practical notes and limitations</a> <li class=md-nav__item > <a href="#model-based-validation-r-free-against-a-model-and-electron-density-maps" class=md-nav__link >14. Model-based validation: R-free against a model and electron-density maps</a> </ul> <li class=md-nav__item > <a href=OPENAPI.html class=md-nav__link >OpenAPI</a> <li class=md-nav__item > <a href=OPENAPI_SPECS.html class=md-nav__link >OpenAPI specification</a> <li class=md-nav__item > <a href=CBOR.html class=md-nav__link >CBOR messages</a> <li class=md-nav__item > <a href=HDF5.html class=md-nav__link >HDF5 / NeXus data format</a> <li class=md-nav__item > <a href=IMAGE_STREAM.html class=md-nav__link >Data streams</a> <li class=md-nav__item > <a href=PIXEL_MASK.html class=md-nav__link >Pixel mask</a> <li class=md-nav__item > <a href=WEB_FRONTEND.html class=md-nav__link >Web frontend</a> <li class=md-nav__item > <a href=TESTS.html class=md-nav__link >Tests</a> <li class=md-nav__item > <span class="md-nav__link caption"><span class=caption-text >OpenAPI Python client</span></span> <li class=md-nav__item > <a href="python_client/README.html" class=md-nav__link >jfjoch-client</a> <li class=md-nav__item > <a href="python_client/README.html#license-clarification" class=md-nav__link >License Clarification</a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html" class=md-nav__link >jfjoch_client.DefaultApi</a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#cancel-post" class=md-nav__link ><strong>cancel_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-azim-int-get" class=md-nav__link ><strong>config_azim_int_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-azim-int-put" class=md-nav__link ><strong>config_azim_int_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-bragg-integration-get" class=md-nav__link ><strong>config_bragg_integration_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-bragg-integration-put" class=md-nav__link ><strong>config_bragg_integration_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-dark-mask-get" class=md-nav__link ><strong>config_dark_mask_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-dark-mask-put" class=md-nav__link ><strong>config_dark_mask_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-detector-get" class=md-nav__link ><strong>config_detector_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-detector-put" class=md-nav__link ><strong>config_detector_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-file-writer-get" class=md-nav__link ><strong>config_file_writer_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-file-writer-put" class=md-nav__link ><strong>config_file_writer_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-image-format-conversion-post" class=md-nav__link ><strong>config_image_format_conversion_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-image-format-get" class=md-nav__link ><strong>config_image_format_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-image-format-put" class=md-nav__link ><strong>config_image_format_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-image-format-raw-post" class=md-nav__link ><strong>config_image_format_raw_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-indexing-get" class=md-nav__link ><strong>config_indexing_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-indexing-put" class=md-nav__link ><strong>config_indexing_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-instrument-get" class=md-nav__link ><strong>config_instrument_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-instrument-put" class=md-nav__link ><strong>config_instrument_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-internal-generator-image-put" class=md-nav__link ><strong>config_internal_generator_image_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-internal-generator-image-tiff-put" class=md-nav__link ><strong>config_internal_generator_image_tiff_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-mask-get" class=md-nav__link ><strong>config_mask_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-mask-tiff-get" class=md-nav__link ><strong>config_mask_tiff_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-roi-get" class=md-nav__link ><strong>config_roi_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-roi-put" class=md-nav__link ><strong>config_roi_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-select-detector-get" class=md-nav__link ><strong>config_select_detector_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-select-detector-put" class=md-nav__link ><strong>config_select_detector_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-spot-finding-get" class=md-nav__link ><strong>config_spot_finding_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-spot-finding-put" class=md-nav__link ><strong>config_spot_finding_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-user-mask-get" class=md-nav__link ><strong>config_user_mask_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-user-mask-put" class=md-nav__link ><strong>config_user_mask_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-user-mask-tiff-get" class=md-nav__link ><strong>config_user_mask_tiff_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-user-mask-tiff-put" class=md-nav__link ><strong>config_user_mask_tiff_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-zeromq-metadata-get" class=md-nav__link ><strong>config_zeromq_metadata_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-zeromq-metadata-put" class=md-nav__link ><strong>config_zeromq_metadata_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-zeromq-preview-get" class=md-nav__link ><strong>config_zeromq_preview_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-zeromq-preview-put" class=md-nav__link ><strong>config_zeromq_preview_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#deactivate-post" class=md-nav__link ><strong>deactivate_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#detector-status-get" class=md-nav__link ><strong>detector_status_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#fpga-status-get" class=md-nav__link ><strong>fpga_status_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#image-buffer-clear-post" class=md-nav__link ><strong>image_buffer_clear_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#image-buffer-image-cbor-get" class=md-nav__link ><strong>image_buffer_image_cbor_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#image-buffer-image-jpeg-get" class=md-nav__link ><strong>image_buffer_image_jpeg_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#image-buffer-image-tiff-get" class=md-nav__link ><strong>image_buffer_image_tiff_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#image-buffer-start-cbor-get" class=md-nav__link ><strong>image_buffer_start_cbor_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#image-buffer-status-get" class=md-nav__link ><strong>image_buffer_status_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#image-pusher-status-get" class=md-nav__link ><strong>image_pusher_status_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#initialize-post" class=md-nav__link ><strong>initialize_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#pedestal-post" class=md-nav__link ><strong>pedestal_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#preview-pedestal-tiff-get" class=md-nav__link ><strong>preview_pedestal_tiff_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#preview-plot-bin-get" class=md-nav__link ><strong>preview_plot_bin_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#preview-plot-get" class=md-nav__link ><strong>preview_plot_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#result-scan-get" class=md-nav__link ><strong>result_scan_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#start-post" class=md-nav__link ><strong>start_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#statistics-calibration-get" class=md-nav__link ><strong>statistics_calibration_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#statistics-data-collection-get" class=md-nav__link ><strong>statistics_data_collection_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#statistics-get" class=md-nav__link ><strong>statistics_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#status-get" class=md-nav__link ><strong>status_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#trigger-post" class=md-nav__link ><strong>trigger_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#version-get" class=md-nav__link ><strong>version_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#wait-till-done-post" class=md-nav__link ><strong>wait_till_done_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#wait-until-running-post" class=md-nav__link ><strong>wait_until_running_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#xfel-event-code-get" class=md-nav__link ><strong>xfel_event_code_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#xfel-pulse-id-get" class=md-nav__link ><strong>xfel_pulse_id_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/AzimIntSettings.html" class=md-nav__link >AzimIntSettings</a> <li class=md-nav__item > <a href="python_client/docs/BrokerStatus.html" class=md-nav__link >BrokerStatus</a> <li class=md-nav__item > <a href="python_client/docs/CalibrationStatisticsInner.html" class=md-nav__link >CalibrationStatisticsInner</a> <li class=md-nav__item > <a href="python_client/docs/ColorScale.html" class=md-nav__link >ColorScale</a> <li class=md-nav__item > <a href="python_client/docs/DarkMaskSettings.html" class=md-nav__link >DarkMaskSettings</a> <li class=md-nav__item > <a href="python_client/docs/DatasetSettings.html" class=md-nav__link >DatasetSettings</a> <li class=md-nav__item > <a href="python_client/docs/DatasetSettingsSmargon.html" class=md-nav__link >DatasetSettingsSmargon</a> <li class=md-nav__item > <a href="python_client/docs/DatasetSettingsUnitCell.html" class=md-nav__link >DatasetSettingsUnitCell</a> <li class=md-nav__item > <a href="python_client/docs/DatasetSettingsXrayFluorescenceSpectrum.html" class=md-nav__link >DatasetSettingsXrayFluorescenceSpectrum</a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html" class=md-nav__link >jfjoch_client.DefaultApi</a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#cancel-post" class=md-nav__link ><strong>cancel_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-azim-int-get" class=md-nav__link ><strong>config_azim_int_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-azim-int-put" class=md-nav__link ><strong>config_azim_int_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-bragg-integration-get" class=md-nav__link ><strong>config_bragg_integration_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-bragg-integration-put" class=md-nav__link ><strong>config_bragg_integration_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-dark-mask-get" class=md-nav__link ><strong>config_dark_mask_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-dark-mask-put" class=md-nav__link ><strong>config_dark_mask_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-detector-get" class=md-nav__link ><strong>config_detector_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-detector-put" class=md-nav__link ><strong>config_detector_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-file-writer-get" class=md-nav__link ><strong>config_file_writer_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-file-writer-put" class=md-nav__link ><strong>config_file_writer_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-image-format-conversion-post" class=md-nav__link ><strong>config_image_format_conversion_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-image-format-get" class=md-nav__link ><strong>config_image_format_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-image-format-put" class=md-nav__link ><strong>config_image_format_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-image-format-raw-post" class=md-nav__link ><strong>config_image_format_raw_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-indexing-get" class=md-nav__link ><strong>config_indexing_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-indexing-put" class=md-nav__link ><strong>config_indexing_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-instrument-get" class=md-nav__link ><strong>config_instrument_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-instrument-put" class=md-nav__link ><strong>config_instrument_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-internal-generator-image-put" class=md-nav__link ><strong>config_internal_generator_image_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-internal-generator-image-tiff-put" class=md-nav__link ><strong>config_internal_generator_image_tiff_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-mask-get" class=md-nav__link ><strong>config_mask_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-mask-tiff-get" class=md-nav__link ><strong>config_mask_tiff_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-roi-get" class=md-nav__link ><strong>config_roi_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-roi-put" class=md-nav__link ><strong>config_roi_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-select-detector-get" class=md-nav__link ><strong>config_select_detector_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-select-detector-put" class=md-nav__link ><strong>config_select_detector_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-spot-finding-get" class=md-nav__link ><strong>config_spot_finding_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-spot-finding-put" class=md-nav__link ><strong>config_spot_finding_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-user-mask-get" class=md-nav__link ><strong>config_user_mask_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-user-mask-put" class=md-nav__link ><strong>config_user_mask_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-user-mask-tiff-get" class=md-nav__link ><strong>config_user_mask_tiff_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-user-mask-tiff-put" class=md-nav__link ><strong>config_user_mask_tiff_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-zeromq-metadata-get" class=md-nav__link ><strong>config_zeromq_metadata_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-zeromq-metadata-put" class=md-nav__link ><strong>config_zeromq_metadata_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-zeromq-preview-get" class=md-nav__link ><strong>config_zeromq_preview_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#config-zeromq-preview-put" class=md-nav__link ><strong>config_zeromq_preview_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#deactivate-post" class=md-nav__link ><strong>deactivate_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#detector-status-get" class=md-nav__link ><strong>detector_status_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#fpga-status-get" class=md-nav__link ><strong>fpga_status_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#image-buffer-clear-post" class=md-nav__link ><strong>image_buffer_clear_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#image-buffer-image-cbor-get" class=md-nav__link ><strong>image_buffer_image_cbor_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#image-buffer-image-jpeg-get" class=md-nav__link ><strong>image_buffer_image_jpeg_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#image-buffer-image-tiff-get" class=md-nav__link ><strong>image_buffer_image_tiff_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#image-buffer-start-cbor-get" class=md-nav__link ><strong>image_buffer_start_cbor_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#image-buffer-status-get" class=md-nav__link ><strong>image_buffer_status_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#image-pusher-status-get" class=md-nav__link ><strong>image_pusher_status_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#initialize-post" class=md-nav__link ><strong>initialize_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#pedestal-post" class=md-nav__link ><strong>pedestal_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#preview-pedestal-tiff-get" class=md-nav__link ><strong>preview_pedestal_tiff_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#preview-plot-bin-get" class=md-nav__link ><strong>preview_plot_bin_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#preview-plot-get" class=md-nav__link ><strong>preview_plot_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#result-scan-get" class=md-nav__link ><strong>result_scan_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#start-post" class=md-nav__link ><strong>start_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#statistics-calibration-get" class=md-nav__link ><strong>statistics_calibration_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#statistics-data-collection-get" class=md-nav__link ><strong>statistics_data_collection_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#statistics-get" class=md-nav__link ><strong>statistics_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#status-get" class=md-nav__link ><strong>status_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#trigger-post" class=md-nav__link ><strong>trigger_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#version-get" class=md-nav__link ><strong>version_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#wait-till-done-post" class=md-nav__link ><strong>wait_till_done_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#wait-until-running-post" class=md-nav__link ><strong>wait_until_running_post</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#xfel-event-code-get" class=md-nav__link ><strong>xfel_event_code_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/DefaultApi.html#xfel-pulse-id-get" class=md-nav__link ><strong>xfel_pulse_id_get</strong></a> <li class=md-nav__item > <a href="python_client/docs/Detector.html" class=md-nav__link >Detector</a> <li class=md-nav__item > <a href="python_client/docs/DetectorList.html" class=md-nav__link >DetectorList</a> <li class=md-nav__item > <a href="python_client/docs/DetectorListDetectorsInner.html" class=md-nav__link >DetectorListDetectorsInner</a> <li class=md-nav__item > <a href="python_client/docs/DetectorListElement.html" class=md-nav__link >DetectorListElement</a> <li class=md-nav__item > <a href="python_client/docs/DetectorModule.html" class=md-nav__link >DetectorModule</a> <li class=md-nav__item > <a href="python_client/docs/DetectorModuleDirection.html" class=md-nav__link >DetectorModuleDirection</a> <li class=md-nav__item > <a href="python_client/docs/DetectorPowerState.html" class=md-nav__link >DetectorPowerState</a> <li class=md-nav__item > <a href="python_client/docs/DetectorSelection.html" class=md-nav__link >DetectorSelection</a> <li class=md-nav__item > <a href="python_client/docs/DetectorSettings.html" class=md-nav__link >DetectorSettings</a> <li class=md-nav__item > <a href="python_client/docs/DetectorState.html" class=md-nav__link >DetectorState</a> <li class=md-nav__item > <a href="python_client/docs/DetectorStatus.html" class=md-nav__link >DetectorStatus</a> <li class=md-nav__item > <a href="python_client/docs/DetectorTiming.html" class=md-nav__link >DetectorTiming</a> <li class=md-nav__item > <a href="python_client/docs/DetectorType.html" class=md-nav__link >DetectorType</a> <li class=md-nav__item > <a href="python_client/docs/ErrorMessage.html" class=md-nav__link >ErrorMessage</a> <li class=md-nav__item > <a href="python_client/docs/FileWriterFormat.html" class=md-nav__link >FileWriterFormat</a> <li class=md-nav__item > <a href="python_client/docs/FileWriterSettings.html" class=md-nav__link >FileWriterSettings</a> <li class=md-nav__item > <a href="python_client/docs/FpgaStatusInner.html" class=md-nav__link >FpgaStatusInner</a> <li class=md-nav__item > <a href="python_client/docs/GeomRefinementAlgorithm.html" class=md-nav__link >GeomRefinementAlgorithm</a> <li class=md-nav__item > <a href="python_client/docs/GridPlot.html" class=md-nav__link >GridPlot</a> <li class=md-nav__item > <a href="python_client/docs/GridPlots.html" class=md-nav__link >GridPlots</a> <li class=md-nav__item > <a href="python_client/docs/GridScan.html" class=md-nav__link >GridScan</a> <li class=md-nav__item > <a href="python_client/docs/GridScanResult.html" class=md-nav__link >GridScanResult</a> <li class=md-nav__item > <a href="python_client/docs/GridScanResultImagesInner.html" class=md-nav__link >GridScanResultImagesInner</a> <li class=md-nav__item > <a href="python_client/docs/ImageBufferStatus.html" class=md-nav__link >ImageBufferStatus</a> <li class=md-nav__item > <a href="python_client/docs/ImageFormatSettings.html" class=md-nav__link >ImageFormatSettings</a> <li class=md-nav__item > <a href="python_client/docs/ImagePusherStatus.html" class=md-nav__link >ImagePusherStatus</a> <li class=md-nav__item > <a href="python_client/docs/ImagePusherType.html" class=md-nav__link >ImagePusherType</a> <li class=md-nav__item > <a href="python_client/docs/IndexingAlgorithm.html" class=md-nav__link >IndexingAlgorithm</a> <li class=md-nav__item > <a href="python_client/docs/IndexingSettings.html" class=md-nav__link >IndexingSettings</a> <li class=md-nav__item > <a href="python_client/docs/InstrumentMetadata.html" class=md-nav__link >InstrumentMetadata</a> <li class=md-nav__item > <a href="python_client/docs/JfjochBrokerApi.html" class=md-nav__link >jfjoch_client.JfjochBrokerApi</a> <li class=md-nav__item > <a href="python_client/docs/JfjochBrokerApi.html#config-zeromq-metadata-put" class=md-nav__link ><strong>config_zeromq_metadata_put</strong></a> <li class=md-nav__item > <a href="python_client/docs/JfjochSettings.html" class=md-nav__link >JfjochSettings</a> <li class=md-nav__item > <a href="python_client/docs/JfjochSettingsSsl.html" class=md-nav__link >JfjochSettingsSsl</a> <li class=md-nav__item > <a href="python_client/docs/JfjochStatistics.html" class=md-nav__link >JfjochStatistics</a> <li class=md-nav__item > <a href="python_client/docs/MeasurementStatistics.html" class=md-nav__link >MeasurementStatistics</a> <li class=md-nav__item > <a href="python_client/docs/PcieDevicesInner.html" class=md-nav__link >PcieDevicesInner</a> <li class=md-nav__item > <a href="python_client/docs/PixelMaskStatistics.html" class=md-nav__link >PixelMaskStatistics</a> <li class=md-nav__item > <a href="python_client/docs/Plot.html" class=md-nav__link >Plot</a> <li class=md-nav__item > <a href="python_client/docs/PlotTypeEnum.html" class=md-nav__link >PlotTypeEnum</a> <li class=md-nav__item > <a href="python_client/docs/PlotUnitX.html" class=md-nav__link >PlotUnitX</a> <li class=md-nav__item > <a href="python_client/docs/Plots.html" class=md-nav__link >Plots</a> <li class=md-nav__item > <a href="python_client/docs/PreviewSettings.html" class=md-nav__link >PreviewSettings</a> <li class=md-nav__item > <a href="python_client/docs/RoiAzimList.html" class=md-nav__link >RoiAzimList</a> <li class=md-nav__item > <a href="python_client/docs/RoiAzimuthal.html" class=md-nav__link >RoiAzimuthal</a> <li class=md-nav__item > <a href="python_client/docs/RoiBox.html" class=md-nav__link >RoiBox</a> <li class=md-nav__item > <a href="python_client/docs/RoiBoxList.html" class=md-nav__link >RoiBoxList</a> <li class=md-nav__item > <a href="python_client/docs/RoiCircle.html" class=md-nav__link >RoiCircle</a> <li class=md-nav__item > <a href="python_client/docs/RoiCircleList.html" class=md-nav__link >RoiCircleList</a> <li class=md-nav__item > <a href="python_client/docs/RoiDefinitions.html" class=md-nav__link >RoiDefinitions</a> <li class=md-nav__item > <a href="python_client/docs/RotationAxis.html" class=md-nav__link >RotationAxis</a> <li class=md-nav__item > <a href="python_client/docs/ScanResult.html" class=md-nav__link >ScanResult</a> <li class=md-nav__item > <a href="python_client/docs/ScanResultImagesInner.html" class=md-nav__link >ScanResultImagesInner</a> <li class=md-nav__item > <a href="python_client/docs/SpotFindingSettings.html" class=md-nav__link >SpotFindingSettings</a> <li class=md-nav__item > <a href="python_client/docs/StandardDetectorGeometry.html" class=md-nav__link >StandardDetectorGeometry</a> <li class=md-nav__item > <a href="python_client/docs/TcpSettings.html" class=md-nav__link >TcpSettings</a> <li class=md-nav__item > <a href="python_client/docs/UnitCell.html" class=md-nav__link >UnitCell</a> <li class=md-nav__item > <a href="python_client/docs/ZeromqMetadataSettings.html" class=md-nav__link >ZeromqMetadataSettings</a> <li class=md-nav__item > <a href="python_client/docs/ZeromqPreviewSettings.html" class=md-nav__link >ZeromqPreviewSettings</a> <li class=md-nav__item > <a href="python_client/docs/ZeromqSettings.html" class=md-nav__link >ZeromqSettings</a> </ul> </nav> </div> </div> </div> <div class="md-sidebar md-sidebar--secondary" data-md-component=toc > <div class=md-sidebar__scrollwrap > <div class=md-sidebar__inner > <nav class="md-nav md-nav--secondary"> <ul class=md-nav__list data-md-scrollfix=""> </ul> </nav> </div> </div> </div> <div class=md-content > <article class="md-content__inner md-typeset" role=main > <section class="tex2jax_ignore mathjax_ignore" id=cpu-side-crystallographic-data-analysis-jungfraujoch > <h1 id=cpu-data-analysis--page-root >CPU-side crystallographic data analysis (Jungfraujoch)<a class=headerlink href="#cpu-data-analysis--page-root" title="Link to this heading"></a></h1> <p>This document describes the crystallographic algorithms implemented in Jungfraujoch for <strong>CPU</strong>- and <strong>GPU</strong>-side realtime and nearrealtime data analysis.</p> <p><strong>Scope.</strong> The pipeline covered here comprises:</p> <ol class="arabic simple"> <li><p>geometry mapping and corrections,</p> <li><p>azimuthal integration (powder/radial profiles),</p> <li><p>Bragg spot finding (strong pixels → connected components → spot descriptors),</p> <li><p>indexing (still and rotation modes),</p> <li><p>Bravais lattice / centering inference,</p> <li><p>geometry and lattice refinement,</p> <li><p>reflection prediction (still and rotation),</p> <li><p>Bragg integration by either 2D box summation or profile fitting (Kabsch, reference-free),</p> <li><p>scaling and merging,</p> <li><p>merge-level error modelling and outlier rejection,</p> <li><p>auxiliary statistics (Wilson plot, ⟨I/σ(I)⟩, CC1/2, CCref),</p> <li><p>amplitude estimation (FrenchWilson) and R-free test-set flagging,</p> <li><p>optional model-based validation: R-free against a supplied model and 2FoFc / FoFc electron-density maps.</p> </ol> <section id=references > <h2 id=references >References<a class=headerlink href="#references" title="Link to this heading"></a></h2> <p>The methods are inspired and reuising solutions implemented in:</p> <ul class=simple > <li><p>W. Kabsch, “XDS”, <em>Acta Cryst.</em> <strong>D66</strong> (2010), 125132 and related XDS papers (rotation geometry, partiality, scaling concepts).</p> <li><p>W. Kabsch, “Integration, scaling, space-group assignment and post-refinement”, <em>Acta Cryst.</em> <strong>D66</strong> (2010), 133144 (mosaicity/partiality likelihood treatment; notation such as ζ and rotation factors).</p> <li><p>T. A. White et al., CrystFEL method papers (spot finding, threering integration, serial/still diffraction processing concepts).</p> <li><p>J. Kieffer &amp; J. P. Wright, “PyFAI: a Python library for high performance azimuthal integration on GPU”, <em>Powder Diffraction</em> <strong>28</strong> (2013), S339-S350 (detector geometry definition, azimuthal integration)</p> <li><p>H. Powell, “The Rossmann Fourier autoindexing algorithm in MOSFLM”, <em>Acta Cryst.</em> <strong>D55</strong> (1999), 1690-1695 (FFT indexing)</p> <li><p>S. French &amp; K. Wilson, “On the treatment of negative intensity observations”, <em>Acta Cryst.</em> <strong>A34</strong> (1978), 517-525 (Bayesian amplitude estimation from intensities).</p> <li><p>A. T. Brünger, “Free R value: a novel statistical quantity for assessing the accuracy of crystal structures”, <em>Nature</em> <strong>355</strong> (1992), 472-475 (R-free cross-validation).</p> <li><p>M. Wojdyr, “GEMMI: A library for structural biology”, <em>J. Open Source Softw.</em> <strong>7</strong> (2022), 4200 (model / structure-factor / map machinery used in §14). (list is not exhaustive)</p> </ul> </section> <section id=geometry-reciprocal-space-mapping-and-basic-quantities > <h2 id=geometry-reciprocal-space-mapping-and-basic-quantities >1. Geometry, reciprocal-space mapping, and basic quantities<a class=headerlink href="#geometry-reciprocal-space-mapping-and-basic-quantities" title="Link to this heading"></a></h2> <section id=coordinate-conventions > <h3 id=coordinate-conventions >1.1 Coordinate conventions<a class=headerlink href="#coordinate-conventions" title="Link to this heading"></a></h3> <p>For a pixel coordinate <span class="math notranslate nohighlight">\((x,y)\)</span> (in pixels), Jungfraujoch converts to a laboratory direction vector via:</p> <ol class="arabic simple"> <li><p>shift by direct-beam position <span class="math notranslate nohighlight">\((x_\mathrm{beam}, y_\mathrm{beam})\)</span>,</p> <li><p>scale by pixel size <span class="math notranslate nohighlight">\(p\)</span> (mm),</p> <li><p>set detector distance <span class="math notranslate nohighlight">\(D\)</span> (mm),</p> <li><p>apply detector orientation rotation <span class="math notranslate nohighlight">\(R_\mathrm{det}\)</span> (PyFAI-like parameterization).</p> </ol> <p>The unnormalized detector coordinate (mm) is: <span class="math notranslate nohighlight">\( \mathbf{r}_\mathrm{det}(x,y) = \begin{pmatrix} (x-x_\mathrm{beam})p\\ (y-y_\mathrm{beam})p\\ D \end{pmatrix}. \)</span></p> <p>The lab-frame vector is: <span class="math notranslate nohighlight">\( \mathbf{r}_\mathrm{lab} = R_\mathrm{det}\,\mathbf{r}_\mathrm{det}. \)</span></p> <p>Let the incident wavevector magnitude be <span class="math notranslate nohighlight">\(k = 1/\lambda\)</span> in Å<span class="math notranslate nohighlight">\(^{-1}\)</span>, and define: <span class="math notranslate nohighlight">\( \mathbf{S}_0 = (0,0,k). \)</span></p> <p>The <strong>reciprocal-space scattering vector</strong> associated with pixel <span class="math notranslate nohighlight">\((x,y)\)</span> is: <span class="math notranslate nohighlight">\( \mathbf{s}(x,y) = k\,\frac{\mathbf{r}_\mathrm{lab}}{\lVert \mathbf{r}_\mathrm{lab}\rVert} - \mathbf{S}_0. \)</span></p> <p>This <span class="math notranslate nohighlight">\(\mathbf{s}\)</span> is the fundamental quantity used for spot finding (resolution filters), indexing, and refinement.</p> </section> <section id=two-theta-azimuth-resolution-and-q > <h3 id=two-theta-azimuth-resolution-and-q >1.2 Two-theta, azimuth, resolution and <span class="math notranslate nohighlight">\(q\)</span><a class=headerlink href="#two-theta-azimuth-resolution-and-q" title="Link to this heading"></a></h3> <p>The scattering angle <span class="math notranslate nohighlight">\(2\theta\)</span> is computed from <span class="math notranslate nohighlight">\(\mathbf{r}_\mathrm{lab}\)</span> via: <span class="math notranslate nohighlight">\( 2\theta = \arctan\!\left(\frac{\sqrt{x_\mathrm{lab}^2 + y_\mathrm{lab}^2}}{z_\mathrm{lab}}\right). \)</span></p> <p>Resolution (Å) at a pixel is: <span class="math notranslate nohighlight">\( d = \frac{\lambda}{2\sin(\theta)} = \frac{\lambda}{2\sin(2\theta/2)}. \)</span></p> <p>The magnitude <span class="math notranslate nohighlight">\(q = 2\pi/d\)</span> is used for radial binning and ice-ring handling.</p> </section> <section id=distance-from-the-ewald-sphere > <h3 id=distance-from-the-ewald-sphere >1.3 Distance from the Ewald sphere<a class=headerlink href="#distance-from-the-ewald-sphere" title="Link to this heading"></a></h3> <p>For a reciprocal lattice point <span class="math notranslate nohighlight">\(\mathbf{p}\)</span><span class="math notranslate nohighlight">\(^{-1}\)</span>), define: <span class="math notranslate nohighlight">\( \Delta_\mathrm{Ewald}(\mathbf{p}) = \lVert \mathbf{p} + \mathbf{S}_0\rVert - k. \)</span> Jungfraujoch uses <span class="math notranslate nohighlight">\(|\Delta_\mathrm{Ewald}|\)</span> as an operational proxy for excitation error. This appears in:</p> <ul class=simple > <li><p>still prediction (accept if <span class="math notranslate nohighlight">\(|\Delta_\mathrm{Ewald}|\le \Delta_\mathrm{cut}\)</span>),</p> <li><p>profile radius estimation (see §11.1),</p> <li><p>still partiality option in scaling/merging (§10.2).</p> </ul> </section> </section> <hr class=docutils /> <section id=azimuthal-integration-radial-profiles > <h2 id=azimuthal-integration-radial-profiles >2. Azimuthal integration (radial profiles)<a class=headerlink href="#azimuthal-integration-radial-profiles" title="Link to this heading"></a></h2> <p>Azimuthal integration produces a radial profile <span class="math notranslate nohighlight">\(I(q)\)</span> or <span class="math notranslate nohighlight">\(I(d)\)</span> by histogramming pixels into radial bins. Pixels are <strong>not split</strong> across bins; each pixel contributes wholly to a single bin. By default the profile is purely radial (a single azimuthal bin), but the azimuth can optionally be split into up to 512 <span class="math notranslate nohighlight">\(\phi\)</span> sectors (<code class="docutils literal notranslate"><span class=pre >azim_bins</span></code>, <code class="docutils literal notranslate"><span class=pre >--azim-phi-bins</span></code>), giving a <strong>2D <span class="math notranslate nohighlight">\(q\times\phi\)</span> profile</strong> that exposes azimuthal anisotropy such as detector shadowing or sample texture.</p> <section id=histogram-estimator > <h3 id=histogram-estimator >2.1 Histogram estimator<a class=headerlink href="#histogram-estimator" title="Link to this heading"></a></h3> <p>Let bin index <span class="math notranslate nohighlight">\(b(x,y)\)</span> be precomputed from <span class="math notranslate nohighlight">\(q(x,y)\)</span> (or equivalently from <span class="math notranslate nohighlight">\(d(x,y)\)</span>) and, when <span class="math notranslate nohighlight">\(\phi\)</span> sectors are enabled, the azimuth <span class="math notranslate nohighlight">\(\phi(x,y)\)</span> — so <span class="math notranslate nohighlight">\(b = b_q + b_\phi B_q\)</span>. For each bin <span class="math notranslate nohighlight">\(b\)</span>:</p> <ul class=simple > <li><p>accumulate corrected intensity and its square: <span class="math notranslate nohighlight">\( S_b = \sum_{(x,y):\,b(x,y)=b} I(x,y)\,C(x,y),\qquad S^{(2)}_b = \sum I(x,y)^2\,C(x,y)^2, \)</span></p> <li><p>and count: <span class="math notranslate nohighlight">\( N_b = \#\{(x,y):\,b(x,y)=b \text{ and pixel is valid}\}. \)</span></p> </ul> <p>The profile reports both the mean <span class="math notranslate nohighlight">\(\bar{I}_b = S_b / N_b\)</span> (when <span class="math notranslate nohighlight">\(N_b&gt;0\)</span>) and a per-bin sample standard deviation <span class="math notranslate nohighlight">\(\sigma_b = \sqrt{(S^{(2)}_b - S_b^2/N_b)/(N_b-1)}\)</span> (a spread/error estimate for each radial point). Invalid pixels (masked, saturated, detector error codes) are excluded.</p> </section> <section id=corrections-applied > <h3 id=corrections-applied >2.2 Corrections applied<a class=headerlink href="#corrections-applied" title="Link to this heading"></a></h3> <p>Two standard corrections are available:</p> <p><strong>(i) Solid angle / geometric correction.</strong> A flat pixels solid angle falls off with the <strong>incidence angle <span class="math notranslate nohighlight">\(\alpha\)</span> between the scattered ray and the detector normal</strong>. With the in-plane detector offsets <span class="math notranslate nohighlight">\(u=(x-x_\mathrm{beam})p\)</span> and <span class="math notranslate nohighlight">\(v=(y-y_\mathrm{beam})p\)</span> (§1.1) and detector distance <span class="math notranslate nohighlight">\(D\)</span>, <span class="math notranslate nohighlight">\( \cos\alpha = \frac{D}{\sqrt{u^2+v^2+D^2}},\qquad C_\Omega = \cos^3\alpha, \)</span> applied — like the polarization term below — as a <strong>divisor</strong> (intensities are scaled by <span class="math notranslate nohighlight">\(1/\cos^3\alpha\)</span>), so pixels at oblique incidence, which subtend a smaller solid angle, are boosted. Because <span class="math notranslate nohighlight">\(\alpha\)</span> is evaluated in the detectors own frame it is <strong>invariant under detector tilt</strong> (<span class="math notranslate nohighlight">\(\mathrm{rot1}/\mathrm{rot2}/\mathrm{rot3}\)</span>), matching PyFAIs <code class="docutils literal notranslate"><span class=pre >solidAngleArray</span></code> and MAX IV azint. It reduces to the commonly quoted <span class="math notranslate nohighlight">\(\cos^3(2\theta)\)</span> form only for an untilted detector, where the incidence angle coincides with the scattering angle.</p> <p><strong>(ii) Polarization correction.</strong> With polarization coefficient <span class="math notranslate nohighlight">\(P\)</span> (beamline dependent) and azimuth <span class="math notranslate nohighlight">\(\phi\)</span>: <span class="math notranslate nohighlight">\( C_\mathrm{pol}(2\theta,\phi) = \frac{1}{2}\left(1+\cos^2(2\theta) - P\cos(2\phi)\left(1-\cos^2(2\theta)\right)\right), \)</span> applied as a divisor to intensities (i.e. scale by <span class="math notranslate nohighlight">\(1/C_\mathrm{pol}\)</span>) when enabled.</p> </section> <section id=background-estimate-for-profiles > <h3 id=background-estimate-for-profiles >2.3 Background estimate for profiles<a class=headerlink href="#background-estimate-for-profiles" title="Link to this heading"></a></h3> <p>A background estimate is derived from the profile as its mean intensity over a fixed low-to-mid <span class="math notranslate nohighlight">\(Q\)</span> window (default <span class="math notranslate nohighlight">\(2\pi/5\)</span> to <span class="math notranslate nohighlight">\(2\pi/3\)</span> Å<span class="math notranslate nohighlight">\(^{-1}\)</span>). This background is used for monitoring and diagnostics; it is <strong>not</strong> the same as the local Bragg-spot background used in summation integration (§9.2).</p> </section> </section> <hr class=docutils /> <section id=spot-finding-strong-pixels-bragg-spots > <h2 id=spot-finding-strong-pixels-bragg-spots >3. Spot finding (strong pixels → Bragg spots)<a class=headerlink href="#spot-finding-strong-pixels-bragg-spots" title="Link to this heading"></a></h2> <p>Spot finding is a two-stage process:</p> <ol class="arabic simple"> <li><p><strong>Strong-pixel selection</strong> using intensity and/or local signal-to-noise criteria.</p> <li><p><strong>Connected-component labeling (CCL)</strong> to group strong pixels into candidate spots, followed by spot-level filtering and feature extraction.</p> </ol> <section id=strong-pixel-detection-by-local-statistics > <h3 id=strong-pixel-detection-by-local-statistics >3.1 Strong-pixel detection by local statistics<a class=headerlink href="#strong-pixel-detection-by-local-statistics" title="Link to this heading"></a></h3> <p>For each pixel <span class="math notranslate nohighlight">\(i\)</span> with value <span class="math notranslate nohighlight">\(v_i\)</span>, consider a square window (nominally <span class="math notranslate nohighlight">\(31\times 31\)</span> pixels) around it. Let the window contain <span class="math notranslate nohighlight">\(n\)</span> valid pixels (excluding masked/bad/saturated), and define: <span class="math notranslate nohighlight">\( \Sigma = \sum v,\qquad \Sigma_2 = \sum v^2. \)</span></p> <p>To avoid biasing the local statistics by the test pixel itself, Jungfraujoch evaluates the pixel against the window with the pixel removed: <span class="math notranslate nohighlight">\( \Sigma' = \Sigma - v_i,\quad \Sigma_2' = \Sigma_2 - v_i^2,\quad n' = n-1. \)</span></p> <p>A variance-like quantity proportional to <span class="math notranslate nohighlight">\(n'^2\)</span> is formed: <span class="math notranslate nohighlight">\( V = n'\Sigma_2' - (\Sigma')^2, \)</span> and the deviation-from-mean quantity: <span class="math notranslate nohighlight">\( \Delta = v_i n' - \Sigma'. \)</span></p> <p>A pixel is considered strong if:</p> <ul class=simple > <li><p>it is above a photon/count threshold, and</p> <li><p>its window contains enough valid neighbours (more than 100), so the local statistics are meaningful, and</p> <li><p><span class="math notranslate nohighlight">\(\Delta&gt;0\)</span>, and</p> <li><p>the squared deviation exceeds a scaled variance: <span class="math notranslate nohighlight">\( \Delta^2 &gt; V\cdot T^2, \)</span> where <span class="math notranslate nohighlight">\(T\)</span> is the configured signal-to-noise threshold.</p> </ul> <p>This is equivalent to a local z-score criterion but implemented in integer arithmetic to be robust and fast.</p> <p>Special cases:</p> <ul class=simple > <li><p>saturated pixels can be forced to “strong” (useful for detecting overloaded Bragg spots),</p> <li><p>invalid pixels are never strong.</p> </ul> </section> <section id=resolution-and-ice-ring-handling > <h3 id=resolution-and-ice-ring-handling >3.2 Resolution and ice-ring handling<a class=headerlink href="#resolution-and-ice-ring-handling" title="Link to this heading"></a></h3> <p>Spot finding can be restricted to a resolution range <span class="math notranslate nohighlight">\([d_\mathrm{high}, d_\mathrm{low}]\)</span> by masking pixels outside the range. Optionally, spots in identified ice-ring regions can be tagged so that subsequent indexing/refinement may include or exclude them (see §4 and §6).</p> <p>A single per-image <strong>ice-ring score</strong> is derived from the azimuthally-integrated radial profile: for each hexagonal-ice powder ring (positions <span class="math notranslate nohighlight">\(d\)</span> from Moreau <em>et al.</em>, Acta Cryst D77, 2021), the profile intensity at the ring is divided by a smooth background estimated from the <em>whole</em> profile — a running median of the non-ice bins, interpolated under each ring — and the strongest rings ratio is reported (1 = no ice, <span class="math notranslate nohighlight">\(&gt;1\)</span> = ice above background). A whole-profile background is used rather than a couple of adjacent shoulder bins so the estimate is robust to the radial binning: at a coarse Q-spacing a local shoulder can be only ~1 bin and would double-count the rings own edge (offline processing defaults to a fine 0.01 1/Å spacing, <code class="docutils literal notranslate"><span class=pre >--azim-q-spacing</span></code>, so the rings are well resolved). (A significance/z-score was considered but is uninformative here: with many photons any real ice ring is highly significant, so the discriminating quantity is the ice <em>magnitude</em>, i.e. this ratio.) It is stored per image (<code class="docutils literal notranslate"><span class=pre >ice_ring_score</span></code>, HDF5 <code class="docutils literal notranslate"><span class=pre >/entry/MX/iceRingScore</span></code>) as a monitoring quantity, distinct from the merge-time ice masking, which is data-driven from the per-ring merged CC1/2.</p> <p>A further optional safeguard removes isolated high-resolution “spur” spots by detecting large gaps in <span class="math notranslate nohighlight">\(1/d\)</span> (or <span class="math notranslate nohighlight">\(q\)</span>) space and discarding spots beyond the gap. This is intended for macromolecular diffraction where edge-of-detector backgrounds can be extremely low.</p> </section> <section id=connected-component-labeling-ccl > <h3 id=connected-component-labeling-ccl >3.3 Connected-component labeling (CCL)<a class=headerlink href="#connected-component-labeling-ccl" title="Link to this heading"></a></h3> <p>Strong pixels are grouped into connected components (adjacent strong pixels) using a CCL algorithm. Each component yields a candidate spot with:</p> <ul class=simple > <li><p>centroid <span class="math notranslate nohighlight">\((x,y)\)</span> (often intensity-weighted),</p> <li><p>pixel count (spot size),</p> <li><p>integrated spot intensity proxy (sum of pixel values),</p> <li><p>resolution <span class="math notranslate nohighlight">\(d\)</span> at the centroid (or mean over pixels),</p> <li><p>and quality flags (e.g. ice-ring classification).</p> </ul> <p>Spot-level filters include minimum/maximum pixel count and resolution limits.</p> </section> </section> <hr class=docutils /> <section id=indexing-overview > <h2 id=indexing-overview >4. Indexing overview<a class=headerlink href="#indexing-overview" title="Link to this heading"></a></h2> <p>Indexing maps observed reciprocal-space vectors <span class="math notranslate nohighlight">\(\mathbf{s}_i\)</span> to a lattice such that: <span class="math notranslate nohighlight">\( \mathbf{s}_i \approx h_i\mathbf{a}^* + k_i\mathbf{b}^* + l_i\mathbf{c}^*, \)</span> with integer <span class="math notranslate nohighlight">\((h_i,k_i,l_i)\)</span>.</p> <p>Jungfraujoch supports two complementary indexing strategies:</p> <ol class="arabic simple"> <li><p><strong>FFT-based indexing</strong> (Rossmann-type): does not require an a priori unit cell; suitable for unknown samples.</p> <li><p><strong>Fast-feedback indexing</strong> (TORO-like): requires an approximate unit cell; optimized for speed and feedback.</p> </ol> <p>Both feed into a common robust refinement/selection stage which maximizes the number of inliers under an indexing tolerance, and which can return <strong>more than one lattice</strong> per image (multi-lattice indexing; see §5.4).</p> <section id=indexed-spot-decision-inlier-test > <h3 id=indexed-spot-decision-inlier-test >4.1 Indexed-spot decision (inlier test)<a class=headerlink href="#indexed-spot-decision-inlier-test" title="Link to this heading"></a></h3> <p>Given a trial lattice with direct basis vectors <span class="math notranslate nohighlight">\(\mathbf{a},\mathbf{b},\mathbf{c}\)</span> (used here as reciprocal-space dot-test vectors), fractional indices are estimated by: <span class="math notranslate nohighlight">\( h_f = \mathbf{s}\cdot\mathbf{a},\quad k_f = \mathbf{s}\cdot\mathbf{b},\quad l_f = \mathbf{s}\cdot\mathbf{c}. \)</span> Let <span class="math notranslate nohighlight">\((h,k,l)=(\mathrm{round}(h_f),\mathrm{round}(k_f),\mathrm{round}(l_f))\)</span> and define the fractional residual: <span class="math notranslate nohighlight">\( \delta^2 = (h_f-h)^2 + (k_f-k)^2 + (l_f-l)^2. \)</span> A spot is indexed if <span class="math notranslate nohighlight">\(\delta^2 &lt; \tau^2\)</span>, where <span class="math notranslate nohighlight">\(\tau\)</span> is the configured tolerance.</p> <p>For indexed spots, the reciprocal lattice point <span class="math notranslate nohighlight">\(\mathbf{p} = h\mathbf{a}^*+k\mathbf{b}^*+l\mathbf{c}^*\)</span> is used to compute <span class="math notranslate nohighlight">\(\Delta_\mathrm{Ewald}(\mathbf{p})\)</span> (stored as a diagnostic and later used in profile-radius estimation).</p> </section> </section> <hr class=docutils /> <section id=fft-indexing-unknown-unit-cell > <h2 id=fft-indexing-unknown-unit-cell >5. FFT indexing (unknown unit cell)<a class=headerlink href="#fft-indexing-unknown-unit-cell" title="Link to this heading"></a></h2> <p>FFT indexing follows a classical approach: detect dominant periodicities by projecting reciprocal-space points onto many directions and Fourier transforming the resulting 1D histograms.</p> <section id=directional-projections-and-histograms > <h3 id=directional-projections-and-histograms >5.1 Directional projections and histograms<a class=headerlink href="#directional-projections-and-histograms" title="Link to this heading"></a></h3> <p>Choose a set of unit vectors <span class="math notranslate nohighlight">\(\{\mathbf{u}_d\}\)</span> on a half-sphere (a near-uniform distribution generated via a golden-angle construction). For each direction <span class="math notranslate nohighlight">\(d\)</span>, form a histogram in the scalar projection: <span class="math notranslate nohighlight">\( t_{id} = \left|\mathbf{u}_d\cdot \mathbf{s}_i\right|. \)</span></p> <p>Bin width is chosen approximately as: <span class="math notranslate nohighlight">\( \Delta t \approx \frac{1}{2 L_\mathrm{max}}, \)</span> where <span class="math notranslate nohighlight">\(L_\mathrm{max}\)</span> is the maximum expected real-space unit-cell edge (Å). The histogram extent is tied to the maximum <span class="math notranslate nohighlight">\(q\)</span> used (set by a high-resolution cutoff for indexing).</p> </section> <section id=fft-peak-picking-and-candidate-vectors > <h3 id=fft-peak-picking-and-candidate-vectors >5.2 FFT peak picking and candidate vectors<a class=headerlink href="#fft-peak-picking-and-candidate-vectors" title="Link to this heading"></a></h3> <p>For each direction, the FFT magnitude spectrum is computed; peaks correspond to periodicities along <span class="math notranslate nohighlight">\(\mathbf{u}_d\)</span>. Each direction yields a candidate real-space length <span class="math notranslate nohighlight">\(L\)</span> chosen <strong>not</strong> by raw magnitude but by <strong>maximum prominence above a running-mean local background</strong> (subtracting the broad low-frequency envelope that otherwise dominates on weak or pink-beam frames), subject to <span class="math notranslate nohighlight">\(L\ge L_\mathrm{min}\)</span>.</p> <p>Candidate vectors are <span class="math notranslate nohighlight">\(\mathbf{v}_d = L_d\,\mathbf{u}_d\)</span>.</p> <p>A collinearity filter removes nearly parallel vectors (e.g. within 5°) and attempts to resolve harmonic ambiguity: shorter “fundamental” vectors may be preferred over longer harmonics if their peak magnitude is sufficiently strong relative to the dominant peak.</p> </section> <section id=lattice-reduction-and-cell-candidates > <h3 id=lattice-reduction-and-cell-candidates >5.3 Lattice reduction and cell candidates<a class=headerlink href="#lattice-reduction-and-cell-candidates" title="Link to this heading"></a></h3> <p>Triples of candidate vectors are combined to form candidate bases <span class="math notranslate nohighlight">\((\mathbf{A},\mathbf{B},\mathbf{C})\)</span>, each reduced to its <strong>Niggli-reduced cell</strong> (Gruber-vector reduction) before comparison, and filtered by allowed length and angle ranges. Two passes are run: a standard pass forms shortest-vector triples from the ~30 strongest filtered directions; if the best cell then indexes fewer than half the spots, a <strong>widened fallback</strong> anchors the two shortest axes and lets the third range over up to ~60 candidate vectors (deduplicated by Niggli cell), catching large, elongated or superstructure cells the first pass misses.</p> </section> <section id=robust-refinement-and-best-cell-selection > <h3 id=robust-refinement-and-best-cell-selection >5.4 Robust refinement and best-cell selection<a class=headerlink href="#robust-refinement-and-best-cell-selection" title="Link to this heading"></a></h3> <p>Candidate bases are refined against observed spots using an iterative inlierfocused leastsquares procedure (trimmed/contracting threshold). Candidates are then ranked:</p> <ol class="arabic simple"> <li><p>more indexed spots wins — <strong>unless</strong> two candidates index within ~10 % of each other, in which case</p> <li><p>the <strong>smaller-volume</strong> cell is preferred (when the volumes differ by more than ~5 %), avoiding a doubled supercell, then</p> <li><p>the smaller refinement score, then the spot count again.</p> </ol> <p>Selection is <strong>not limited to a single lattice</strong>: after the best cell is accepted, further lattices are added as separate crystals provided fewer than ~40 % of their indexed spots overlap an already-accepted lattice (up to two extra by default), so split or multi-lattice crystals are indexed rather than discarded.</p> <p>An optional reference unit cell (if supplied) restricts acceptance to cells within a relative distance tolerance in edge lengths (permutation-invariant).</p> </section> </section> <hr class=docutils /> <section id=bravais-lattice-centering-inference-lattice-search > <h2 id=bravais-lattice-centering-inference-lattice-search >6. Bravais lattice / centering inference (“lattice search”)<a class=headerlink href="#bravais-lattice-centering-inference-lattice-search" title="Link to this heading"></a></h2> <p>If the space group is supplied by the user, its lattice constraints are assumed for refinement and subsequent processing.</p> <p>If not, Jungfraujoch attempts to infer the most plausible Bravais lattice type from the metric tensor after Niggli reduction:</p> <ol class="arabic simple"> <li><p><strong>Niggli reduction</strong> is performed to obtain a reduced cell in <span class="math notranslate nohighlight">\(G^6\)</span> representation (Gruber vector).</p> <li><p>The reduced cell is compared against a list of Niggli classes corresponding to Bravais lattices and centerings.</p> <li><p>The highest-symmetry class that matches within tolerances is selected (relative metric tolerance and angular tolerance).</p> </ol> <p>The output includes:</p> <ul class=simple > <li><p>a conventional cell,</p> <li><p>crystal system (triclinic, monoclinic, …),</p> <li><p>centering symbol (one of <span class="math notranslate nohighlight">\(P, C, I, F, R\)</span>; the <span class="math notranslate nohighlight">\(A/B\)</span> variants are not emitted here — they are handled only later as prediction absences, §8.4).</p> </ul> <p>This stage provides centering information used for systematic absences in prediction (§8.4) and for reporting.</p> <p><strong>Note.</strong> In ambiguous or special cases, forcing space group to <span class="math notranslate nohighlight">\(P1\)</span> (no symmetry assumptions) is recommended.</p> </section> <hr class=docutils /> <section id=geometry-and-lattice-refinement > <h2 id=geometry-and-lattice-refinement >7. Geometry and lattice refinement<a class=headerlink href="#geometry-and-lattice-refinement" title="Link to this heading"></a></h2> <p>Refinement adjusts experimental geometry and crystal parameters to minimize discrepancies between observed spot reciprocal vectors and those predicted by a lattice model with integer indices.</p> <section id=parameterization > <h3 id=parameterization >7.1 Parameterization<a class=headerlink href="#parameterization" title="Link to this heading"></a></h3> <p>The refinement jointly optimizes, depending on mode and constraints:</p> <ul class=simple > <li><p>beam center <span class="math notranslate nohighlight">\((x_\mathrm{beam}, y_\mathrm{beam})\)</span>,</p> <li><p>detector distance <span class="math notranslate nohighlight">\(D\)</span>,</p> <li><p>detector tilt angles (two-angle model; third rotation often held at 0),</p> <li><p>rotation axis direction (for rotation datasets),</p> <li><p>crystal orientation (a global rotation),</p> <li><p>unit-cell parameters, with constraints determined by inferred crystal system.</p> </ul> <p>By default only the beam center, unit cell and crystal orientation are refined; the detector distance, tilt angles and rotation-axis direction are held fixed unless explicitly enabled. A lighter <strong>orientation-only</strong> mode refines just the crystal orientation (with a weak small-rotation prior on the poorly-determined out-of-plane component), for stills whose geometry is already trusted.</p> <p>For higher symmetries, constraints are enforced, e.g.</p> <ul class=simple > <li><p>cubic: <span class="math notranslate nohighlight">\(a=b=c,\ \alpha=\beta=\gamma=90^\circ\)</span>,</p> <li><p>tetragonal: <span class="math notranslate nohighlight">\(a=b\)</span>,</p> <li><p>hexagonal: <span class="math notranslate nohighlight">\(a=b,\ \gamma=120^\circ\)</span>,</p> <li><p>monoclinic (unique axis <span class="math notranslate nohighlight">\(b\)</span>): <span class="math notranslate nohighlight">\(\alpha=\gamma=90^\circ\)</span>, <span class="math notranslate nohighlight">\(\beta\)</span> refined.</p> </ul> </section> <section id=residuals-and-objective > <h3 id=residuals-and-objective >7.2 Residuals and objective<a class=headerlink href="#residuals-and-objective" title="Link to this heading"></a></h3> <p>For each indexed spot assigned integer <span class="math notranslate nohighlight">\((h,k,l)\)</span>, compute:</p> <ul class=simple > <li><p>observed reciprocal vector <span class="math notranslate nohighlight">\(\mathbf{s}_\mathrm{obs}\)</span> from its detector position and current geometry,</p> <li><p>predicted reciprocal vector <span class="math notranslate nohighlight">\(\mathbf{s}_\mathrm{pred}(h,k,l;\ \text{lattice params})\)</span>.</p> </ul> <p>Residual is: <span class="math notranslate nohighlight">\( \mathbf{r} = \mathbf{s}_\mathrm{obs} - \mathbf{s}_\mathrm{pred}. \)</span></p> <p>A non-linear least squares solver minimizes <span class="math notranslate nohighlight">\(\sum \|\mathbf{r}\|^2\)</span> over all selected inlier spots.</p> </section> <section id=rotation-datasets-bringing-observations-to-a-common-reference-frame > <h3 id=rotation-datasets-bringing-observations-to-a-common-reference-frame >7.3 Rotation datasets: bringing observations to a common reference frame<a class=headerlink href="#rotation-datasets-bringing-observations-to-a-common-reference-frame" title="Link to this heading"></a></h3> <p>For oscillation/rotation data, each image corresponds to a rotation angle <span class="math notranslate nohighlight">\(\phi\)</span> about an axis <span class="math notranslate nohighlight">\(\mathbf{m}_2\)</span>. Observed reciprocal vectors are rotated “back to start” so that all images are refined in a single reference crystal frame: <span class="math notranslate nohighlight">\( \mathbf{s}_\mathrm{obs,ref} = R(\phi)\,\mathbf{s}_\mathrm{obs}, \)</span> with <span class="math notranslate nohighlight">\(R(\phi)\)</span> constructed from the axis-angle representation of the goniometer model. The angle <span class="math notranslate nohighlight">\(\phi\)</span> is taken at the centre of each frames oscillation (the frame angle plus half the oscillation width).</p> </section> <section id=multi-stage-tightening-of-inlier-tolerance > <h3 id=multi-stage-tightening-of-inlier-tolerance >7.4 Multi-stage tightening of inlier tolerance<a class=headerlink href="#multi-stage-tightening-of-inlier-tolerance" title="Link to this heading"></a></h3> <p>Refinement is performed in stages with decreasing acceptance tolerance for including reflections (three stages, indexing tolerance <span class="math notranslate nohighlight">\(0.3\to0.2\to0.1\)</span>), which stabilizes convergence when starting from imperfect indexing and approximate geometry.</p> </section> <section id=rotation-geometry-post-refinement-two-pass > <h3 id=rotation-geometry-post-refinement-two-pass >7.5 Rotation geometry post-refinement (two-pass)<a class=headerlink href="#rotation-geometry-post-refinement-two-pass" title="Link to this heading"></a></h3> <p>The refinement above (§7.2) runs per image against that images spots. For rotation data an additional <strong>post-refinement</strong> (on by default; <code class="docutils literal notranslate"><span class=pre >--rotation-no-postrefine</span></code> disables it) improves the detector distance, beam centre and crystal cell/axis using <strong>all</strong> frames at once, then re-integrates:</p> <ol class="arabic simple"> <li><p><strong>Pass 1</strong> integrates, scales and merges at the header geometry.</p> <li><p>Against the merged fulls, the shared detector distance and beam centre and the crystal cell / goniometer-axis are refined jointly over all frames (Ceres, robust loss). The fit is <strong>cross-validated</strong> on a deterministic frame split — refined on one half, gated on the held-out half — and the geometry is <strong>committed only for a small move</strong> (a distance/beam shift under ~1 %); a larger move is treated as a fit instability and rejected. The beam centre is gauge-weak in a rotation series (it trades off against the crystal orientation), so it is restrained toward the header value.</p> <li><p><strong>Pass 2</strong> re-indexes de novo and re-integrates at the committed geometry, reusing pass-1s space group for the merge only.</p> </ol> <p>The refined pass is written as the canonical <code class="docutils literal notranslate"><span class=pre >&lt;prefix&gt;_*</span></code> output; the pass-1 (header-geometry) result is kept alongside as <code class="docutils literal notranslate"><span class=pre >&lt;prefix&gt;_01_*</span></code> for comparison.</p> </section> </section> <hr class=docutils /> <section id=reflection-prediction > <h2 id=reflection-prediction >8. Reflection prediction<a class=headerlink href="#reflection-prediction" title="Link to this heading"></a></h2> <p>Jungfraujoch predicts reflection positions for integration by enumerating Miller indices within a resolution cutoff and accepting those that satisfy a diffraction condition model.</p> <section id=enumerating-reciprocal-lattice-points > <h3 id=enumerating-reciprocal-lattice-points >8.1 Enumerating reciprocal lattice points<a class=headerlink href="#enumerating-reciprocal-lattice-points" title="Link to this heading"></a></h3> <p>For a maximum resolution <span class="math notranslate nohighlight">\(d_\mathrm{min}\)</span>, accept <span class="math notranslate nohighlight">\((h,k,l)\)</span> such that: <span class="math notranslate nohighlight">\( \lVert \mathbf{p}(h,k,l)\rVert^2 = \lVert h\mathbf{a}^* + k\mathbf{b}^* + l\mathbf{c}^*\rVert^2 \le \left(\frac{1}{d_\mathrm{min}}\right)^2. \)</span></p> </section> <section id=still-prediction-excitation-error-cutoff > <h3 id=still-prediction-excitation-error-cutoff >8.2 Still prediction (excitation-error cutoff)<a class=headerlink href="#still-prediction-excitation-error-cutoff" title="Link to this heading"></a></h3> <p>For still images, the diffracting condition is approximated by an excitation-error cutoff: <span class="math notranslate nohighlight">\( \left|\Delta_\mathrm{Ewald}(\mathbf{p})\right| \le \Delta_\mathrm{cut}. \)</span> Accepted reflections are projected to the detector by intersecting the diffracted direction <span class="math notranslate nohighlight">\(\mathbf{S}=\mathbf{S}_0+\mathbf{p}\)</span> with the detector plane, using the current geometry.</p> <p>When the beam has a finite energy bandwidth, this window is <strong>broadened radially per reflection</strong>: the cutoff is combined in quadrature with a bandwidth smear, <span class="math notranslate nohighlight">\(\sqrt{\Delta_\mathrm{cut}^2 + (3\,\sigma_\mathrm{bw})^2}\)</span>, where <span class="math notranslate nohighlight">\(\sigma_\mathrm{bw}\propto|p_z|\)</span> (the reciprocal-space depth along the beam, growing as <span class="math notranslate nohighlight">\(\sim 1/d^2\)</span>). This keeps high-resolution reflections — smeared by the bandwidth into radial streaks — from being clipped. The same <span class="math notranslate nohighlight">\(\sigma_\mathrm{bw}\)</span> is deconvolved from the measured profile radius (§11.1), so it is not double-counted.</p> </section> <section id=rotation-prediction-laue-equation-partiality-model > <h3 id=rotation-prediction-laue-equation-partiality-model >8.3 Rotation prediction (Laue equation + partiality model)<a class=headerlink href="#rotation-prediction-laue-equation-partiality-model" title="Link to this heading"></a></h3> <p>For rotation/oscillation datasets, Jungfraujoch solves for rotation angles <span class="math notranslate nohighlight">\(\phi\)</span> where the rotated reciprocal lattice point satisfies the Ewald-sphere condition. In an XDS-like notation, define:</p> <ul class=simple > <li><p>rotation axis unit vector <span class="math notranslate nohighlight">\(\mathbf{m}_2\)</span>,</p> <li><p><span class="math notranslate nohighlight">\(\mathbf{S}_0\)</span> incident vector,</p> <li><p><span class="math notranslate nohighlight">\(\mathbf{S}(\phi)=\mathbf{S}_0+\mathbf{p}(\phi)\)</span>.</p> </ul> <p>A key quantity is: <span class="math notranslate nohighlight">\( \zeta = \left|\mathbf{m}_2\cdot \mathbf{e}_1\right|,\quad \mathbf{e}_1 = \frac{\mathbf{S}\times \mathbf{S}_0}{\lVert \mathbf{S}\times \mathbf{S}_0\rVert}, \)</span> which also appears in XDS as the Lorentz component linked to the rotation axis.</p> <p>A Gaussian mosaicity model yields a partiality fraction over an oscillation width <span class="math notranslate nohighlight">\(\Delta\phi\)</span>:</p> <p><span class="math notranslate nohighlight">\( P(\phi;\sigma_M,\zeta,\Delta\phi) = \frac{1}{2}\left[\mathrm{erf}\!\left(\frac{\phi+\Delta\phi/2}{\sqrt{2}\,\sigma_M/\zeta}\right) - \mathrm{erf}\!\left(\frac{\phi-\Delta\phi/2}{\sqrt{2}\,\sigma_M/\zeta}\right)\right], \)</span></p> <p>with mosaicity <span class="math notranslate nohighlight">\(\sigma_M\)</span> in radians.</p> <p>Reflections are predicted if they meet minimum <span class="math notranslate nohighlight">\(\zeta\)</span> and mosaicity-window criteria, and their predicted detector coordinates fall on the active detector area.</p> </section> <section id=systematic-absences-centering > <h3 id=systematic-absences-centering >8.4 Systematic absences (centering)<a class=headerlink href="#systematic-absences-centering" title="Link to this heading"></a></h3> <p>Systematic absences are applied at least at the centering level (prior to full space-group symmetry). For centering symbol <span class="math notranslate nohighlight">\(C\)</span>:</p> <ul class=simple > <li><p><span class="math notranslate nohighlight">\(I\)</span>: absent if <span class="math notranslate nohighlight">\(h+k+l\)</span> odd,</p> <li><p><span class="math notranslate nohighlight">\(A\)</span>: absent if <span class="math notranslate nohighlight">\(k+l\)</span> odd,</p> <li><p><span class="math notranslate nohighlight">\(B\)</span>: absent if <span class="math notranslate nohighlight">\(h+l\)</span> odd,</p> <li><p><span class="math notranslate nohighlight">\(C\)</span>: absent if <span class="math notranslate nohighlight">\(h+k\)</span> odd,</p> <li><p><span class="math notranslate nohighlight">\(F\)</span>: absent if any of <span class="math notranslate nohighlight">\(h+k, h+l, k+l\)</span> is odd,</p> <li><p><span class="math notranslate nohighlight">\(R\)</span>: absent if <span class="math notranslate nohighlight">\((-h+k+l)\bmod 3 \ne 0\)</span>,</p> <li><p><span class="math notranslate nohighlight">\(P\)</span>: no centering absences.</p> </ul> </section> </section> <hr class=docutils /> <section id=d-bragg-integration-profile-fitting-over-a-three-ring-roi > <h2 id=d-bragg-integration-profile-fitting-over-a-three-ring-roi >9. 2D Bragg integration (profile fitting over a three-ring ROI)<a class=headerlink href="#d-bragg-integration-profile-fitting-over-a-three-ring-roi" title="Link to this heading"></a></h2> <p>Jungfraujoch integrates each predicted reflection in the detector plane over a CrystFEL-inspired “three-ring” region of interest (§9.1). The <strong>default</strong> extraction is <strong>profile fitting</strong> (Kabsch; §9.3), which weights each pixel by a fitted spot profile and so recovers weak reflections far better than plain summation; plain box summation (§9.2) is retained as the seed for the profile and as a fallback. Both methods share the same ROI and background model, and emit the same per-reflection <span class="math notranslate nohighlight">\((I,\sigma,\text{partiality},d)\)</span>, so scaling, the rotation combine (§10.6) and merging consume either unchanged.</p> <section id=regions-of-interest > <h3 id=regions-of-interest >9.1 Regions of interest<a class=headerlink href="#regions-of-interest" title="Link to this heading"></a></h3> <p>For each predicted reflection at <span class="math notranslate nohighlight">\((x_p,y_p)\)</span>, define three radii:</p> <ul class=simple > <li><p><span class="math notranslate nohighlight">\(r_1\)</span>: inner signal radius,</p> <li><p><span class="math notranslate nohighlight">\(r_2\)</span>: inner background radius,</p> <li><p><span class="math notranslate nohighlight">\(r_3\)</span>: outer background radius.</p> </ul> <p>Pixels are classified by their squared distance <span class="math notranslate nohighlight">\(r^2=(x-x_p)^2+(y-y_p)^2\)</span>:</p> <ul class=simple > <li><p><strong>signal region:</strong> <span class="math notranslate nohighlight">\(r^2 &lt; r_1^2\)</span>,</p> <li><p><strong>background annulus:</strong> <span class="math notranslate nohighlight">\(r_2^2 \le r^2 &lt; r_3^2\)</span>.</p> </ul> <p>Invalid pixels (masked/bad/saturated) are excluded from both sums. In addition, pixels lying inside the signal disk (<span class="math notranslate nohighlight">\(r&lt;r_2\)</span>) of any <em>other</em> predicted reflection are removed from this reflections background annulus, so a neighbouring spot cannot leak into the background estimate.</p> </section> <section id=box-summation-seed-and-fallback > <h3 id=box-summation-seed-and-fallback >9.2 Box summation (seed and fallback)<a class=headerlink href="#box-summation-seed-and-fallback" title="Link to this heading"></a></h3> <p>Let:</p> <ul class=simple > <li><p><span class="math notranslate nohighlight">\(S = \sum I(x,y)\)</span> over signal pixels,</p> <li><p><span class="math notranslate nohighlight">\(n_S\)</span> = number of valid signal pixels,</p> <li><p><span class="math notranslate nohighlight">\(B = \sum I(x,y)\)</span> over background pixels,</p> <li><p><span class="math notranslate nohighlight">\(n_B\)</span> = number of valid background pixels.</p> </ul> <p>Background per pixel and integrated intensity: <span class="math notranslate nohighlight">\( \hat{b} = \frac{B}{n_B},\qquad \hat{I} = S - n_S \hat{b}, \)</span> with a Poisson-like uncertainty <span class="math notranslate nohighlight">\(\sigma(\hat{I})=\max\!\big(1,\ r_\sigma\hat{I},\ \sqrt{S}\big)\)</span>, i.e. <span class="math notranslate nohighlight">\(\sqrt{S}\)</span> floored both at 1 and at a small fraction <span class="math notranslate nohighlight">\(r_\sigma\)</span> of the intensity. A reflection is accepted as “observed” only if all signal pixels were valid and <span class="math notranslate nohighlight">\(n_B\)</span> exceeds a minimum. This box sum is the classical estimator; it is used directly with <code class="docutils literal notranslate"><span class=pre >--integrator</span> <span class=pre >boxsum</span></code>, and otherwise seeds the profile fit below.</p> <p><strong>Trimmed-mean background (monochromatic, default on).</strong> On monochromatic data — rotation <em>and</em> still (the discriminator is the beam, not the acquisition mode) — the ring mean <span class="math notranslate nohighlight">\(\hat{b}\)</span> is by default replaced with a <strong>symmetric trimmed mean</strong>: the ring pixels are sorted, the lowest and highest fraction <span class="math notranslate nohighlight">\(f\)</span> are dropped, and the central <span class="math notranslate nohighlight">\((1-2f)\)</span> are averaged (<span class="math notranslate nohighlight">\(f=0.10\)</span> by default, <code class="docutils literal notranslate"><span class=pre >--background-trim</span></code>; <span class="math notranslate nohighlight">\(f=0\)</span> restores the plain mean). Because <span class="math notranslate nohighlight">\(\hat{I}=S-n_S\hat{b}\)</span> is a small difference of large numbers for weak reflections, a per-pixel background bias <span class="math notranslate nohighlight">\(\delta\hat{b}\)</span> becomes a <em>fractional</em> intensity bias <span class="math notranslate nohighlight">\(\approx n_S\,\delta\hat{b}/\hat{I}\)</span> that grows as <span class="math notranslate nohighlight">\(\hat{I}\)</span> shrinks — worst at the resolution edge. The plain mean reads high there because neighbour-spot wings that survive the signal-disk mask, tails and zingers are one-sided (positive) contaminants; dropping the extreme ring pixels removes that bias while a clean Poisson ring is essentially unchanged. In practice this lowers the resolution-edge <span class="math notranslate nohighlight">\(R_\text{meas}\)</span> several-fold, raises <span class="math notranslate nohighlight">\(\langle I/\sigma\rangle\)</span>, and rescues the high-resolution CC<span class="math notranslate nohighlight">\(_{1/2}\)</span> on data where the plain mean had collapsed it (at a small CC<span class="math notranslate nohighlight">\(_{1/2}\)</span> cost in already-clean shells, from the slightly higher variance of the trimmed estimate). It is applied to the shared background used by both the box sum and the profile fit.</p> <p>For the <strong>profile-fit path on broadband (non-zero bandwidth: pink-beam / DMM) data</strong>, the trimmed mean is <em>not</em> used; instead the background mean is computed with a single high-outlier reject (drop ring pixels above <span class="math notranslate nohighlight">\(\hat{b}+3\sqrt{\hat{b}}\)</span>, then recompute): a bandwidth-streaked high-resolution spot or a close neighbour can leak into the ring and bias the mean high, over-subtracting and driving weak high-resolution intensities negative. A clean Poisson background is essentially unchanged by the cut. Neither robustification is applied to plain box summation (<code class="docutils literal notranslate"><span class=pre >--integrator</span> <span class=pre >boxsum</span></code>).</p> </section> <section id=profile-fitted-extraction-default > <h3 id=profile-fitted-extraction-default >9.3 Profile-fitted extraction (default)<a class=headerlink href="#profile-fitted-extraction-default" title="Link to this heading"></a></h3> <p>A fixed signal disk captures a <em>width-dependent</em> fraction of each spot, which puts a multiplicative floor on the per-observation precision of strong reflections and weights weak reflections poorly. Profile fitting removes this by extracting each intensity against a fitted spot shape, without needing reference intensities. Per frame:</p> <ol class=arabic > <li><p><strong>Seed.</strong> Box-sum every reflection (§9.2) to get a rough intensity and observed centroid, and select strong spots (significance <span class="math notranslate nohighlight">\(\ge 5\)</span>).</p> <li><p><strong>Build the profile.</strong> For <code class="docutils literal notranslate"><span class=pre >gaussian</span></code> (the default) the width is taken <strong>per resolution shell</strong> from the measured second moment of the strong spots (shell-dependent because spot size grows with resolution); the intrinsic spot is essentially round in the detector plane (per-detector-region and crystal-anisotropy profiles were evaluated and add nothing — the real crystal anisotropy lives in the discarded rocking direction). For <code class="docutils literal notranslate"><span class=pre >empirical</span></code> the profile is instead the averaged, centroid-aligned, background-subtracted pixel grid of the shells strong spots. Either way the profile is then <strong>rebuilt for each reflection</strong>, centred on its <strong>sub-pixel predicted position</strong> (the noise-free geometric centre, not the observed centroid) and, where needed, <strong>elongated only along the radial direction</strong> (away from the beam centre) — because two effects stretch a spot radially but not tangentially:</p> <ul class=simple > <li><p>a finite energy <strong>bandwidth</strong> smears each spot by <span class="math notranslate nohighlight">\(\sigma_\mathrm{bw}=\text{bandwidth}\cdot R_\mathrm{px}\)</span> (<span class="math notranslate nohighlight">\(R_\mathrm{px}\)</span> = distance from the beam centre, large at high resolution), and</p> <li><p>sensor <strong>parallax</strong> — the depth over which a photon converts in a thick Si/CdTe sensor — adds a term <span class="math notranslate nohighlight">\(\propto\tan^2(2\theta)\)</span> (material- and energy-dependent), plus, on the monochromatic path, a small fixed weak-spot capture term.</p> </ul> <p>These combine as <span class="math notranslate nohighlight">\(\sigma^2_\mathrm{radial}=\sigma^2_\mathrm{intrinsic}+\sigma_\mathrm{bw}^2+c_\mathrm{par}\tan^2(2\theta)\)</span> (tangential unchanged), on a grid grown to hold the streak — capturing it without the tangential background an isotropic widening would add.</p> <li><p><strong>Fit (Kabsch).</strong> With profile <span class="math notranslate nohighlight">\(P\)</span>, background <span class="math notranslate nohighlight">\(B\)</span> and the shell variance model, the intensity and its uncertainty are <span class="math notranslate nohighlight">\( I = \frac{\sum P\,(c-B)/v}{\sum P^2/v},\qquad \sigma = \sqrt{\frac{1}{\sum P^2/v}},\qquad v = B + \max(I,0)\,P, \)</span> where <span class="math notranslate nohighlight">\(c\)</span> is the pixel value and the de-biased variance <span class="math notranslate nohighlight">\(v\)</span> (background plus model signal, rather than the down-fluctuating observed count) is iterated (a few passes). As a guard, if the profile intensity runs away from the box-sum seed (by more than ~10 box-sum <span class="math notranslate nohighlight">\(\sigma\)</span>) it falls back to the seed, and the variance floors the background at <span class="math notranslate nohighlight">\(1/12\)</span> (the integer-binning pixel-variance floor). The rotation/excitation partiality is carried exactly as in the box-sum path.</p> </ol> <p>The integrator is selected by <code class="docutils literal notranslate"><span class=pre >--integrator</span> <span class=pre >boxsum|gaussian|empirical</span></code> (default <code class="docutils literal notranslate"><span class=pre >gaussian</span></code>).</p> </section> <section id=lorentzpolarization-factor-handling > <h3 id=lorentzpolarization-factor-handling >9.4 Lorentzpolarization factor handling<a class=headerlink href="#lorentzpolarization-factor-handling" title="Link to this heading"></a></h3> <p>For integrated reflections, polarization correction can be applied as a multiplicative correction to the reflection scale via the geometry-based polarization term (§2.2). A Lorentz-like factor is carried as <code class="docutils literal notranslate"><span class=pre >rlp</span></code> in predictions, and used during scaling/merging (§10).</p> </section> </section> <hr class=docutils /> <section id=scaling-and-merging > <h2 id=scaling-and-merging >10. Scaling and merging<a class=headerlink href="#scaling-and-merging" title="Link to this heading"></a></h2> <p>After per-image integration, Jungfraujoch scales observations and merges them into unique reflections. The design is intentionally compatible with XDS/XSCALE concepts, and handles both still and rotation data.</p> <section id=observation-model > <h3 id=observation-model >10.1 Observation model<a class=headerlink href="#observation-model" title="Link to this heading"></a></h3> <p>For an observation <span class="math notranslate nohighlight">\(j\)</span> of a unique reflection <span class="math notranslate nohighlight">\(h\)</span> on image (or image group) <span class="math notranslate nohighlight">\(i\)</span>, the predicted measured intensity is modeled as: <span class="math notranslate nohighlight">\( I_{ij} \approx G_i \, L_{ij}\, P_{ij}\, I_h, \)</span> where:</p> <ul class=simple > <li><p><span class="math notranslate nohighlight">\(G_i\)</span> is the image scale factor,</p> <li><p><span class="math notranslate nohighlight">\(L_{ij}\)</span> is a Lorentz-like / geometry factor (stored as <code class="docutils literal notranslate"><span class=pre >rlp</span></code> or derived),</p> <li><p><span class="math notranslate nohighlight">\(P_{ij}\)</span> is a partiality term (model-dependent),</p> <li><p><span class="math notranslate nohighlight">\(I_h\)</span> is the merged (true) intensity parameter for that unique reflection.</p> </ul> <p>A least-squares objective is minimized: <span class="math notranslate nohighlight">\( \sum_{ij} \left(\frac{I_{ij}^{\mathrm{pred}} - I_{ij}^{\mathrm{obs}}}{\sigma_{ij}}\right)^2 \)</span> solved by robust (Cauchy) weighted least squares, with optional post-fit smoothing of the per-frame scales for rotation series (§10.3).</p> </section> <section id=partiality-models > <h3 id=partiality-models >10.2 Partiality models<a class=headerlink href="#partiality-models" title="Link to this heading"></a></h3> <p>The partiality applied is fixed by the data type and scaling stage, not chosen from a user menu:</p> <ol class="arabic simple"> <li><p><strong>Rotation partiality</strong> (XDS-like; see §8.3), used for the per-frame scaling of rotation partials: <span class="math notranslate nohighlight">\( P_{ij} = \frac{1}{2}\left[ \mathrm{erf}\!\left(\frac{\Delta\phi_{ij}+\Delta\phi/2}{\sqrt{2}\,\sigma_{M,i}/\zeta_{ij}}\right) - \mathrm{erf}\!\left(\frac{\Delta\phi_{ij}-\Delta\phi/2}{\sqrt{2}\,\sigma_{M,i}/\zeta_{ij}}\right) \right]. \)</span> The mosaicity <span class="math notranslate nohighlight">\(\sigma_{M,i}\)</span> is <strong>measured once per image at indexing</strong> (MLE, §11.2) and held fixed during scaling — only smoothed in frame order (§10.3), never re-refined (it is degenerate with the scale <span class="math notranslate nohighlight">\(G\)</span>; §11.2).</p> <li><p><strong>Unity</strong> (<span class="math notranslate nohighlight">\(P_{ij}=1\)</span>): used for the scale-on-fulls refit (§10.6), where each observation is already a complete reflection.</p> <li><p><strong>Fixed</strong>: use the per-reflection partiality carried from prediction. Still/serial images are predicted with <span class="math notranslate nohighlight">\(P=1\)</span> by default, so their scaling is effectively unity/fixed. An optional excitation-error still-partiality model (<code class="docutils literal notranslate"><span class=pre >--still-partiality</span></code>) instead weights each stills reflection by a Gaussian <span class="math notranslate nohighlight">\(\exp(-\Delta_\mathrm{Ewald}^2/2\sigma^2)\)</span> in its distance from the Ewald sphere, with a companion merge term (<code class="docutils literal notranslate"><span class=pre >--partiality-uncertainty</span></code>) that adds an intensity- and <span class="math notranslate nohighlight">\((1-P)\)</span>-proportional sigma to down-weight the least-complete reflections.</p> </ol> <p>Reflections below a minimum partiality can be rejected from merging to avoid unstable corrections.</p> </section> <section id=smoothing-of-per-frame-scales > <h3 id=smoothing-of-per-frame-scales >10.3 Smoothing of per-frame scales<a class=headerlink href="#smoothing-of-per-frame-scales" title="Link to this heading"></a></h3> <p>The per-frame scales <span class="math notranslate nohighlight">\(G_i\)</span> are fit by robust (Cauchy) inverse-variance-weighted ratios; there is no explicit <span class="math notranslate nohighlight">\(G\approx1\)</span> prior. For rotation datasets, optional smoothing enforces the expectation that scale and mosaicity vary slowly across a sweep: <strong>after</strong> the per-frame fit, <span class="math notranslate nohighlight">\(\log G_i\)</span> (and the mosaicity) are replaced by a centred <strong>moving average</strong> over a window spanning a configurable rotation range (XDS DELPHI-like; <code class="docutils literal notranslate"><span class=pre >--smooth-g</span></code>, default 5° for rot3d, off otherwise). It is a post-fit smoothing pass, not a curvature penalty inside the least-squares objective.</p> </section> <section id=merging-estimator > <h3 id=merging-estimator >10.4 Merging estimator<a class=headerlink href="#merging-estimator" title="Link to this heading"></a></h3> <p>After refinement, corrected observations are formed: <span class="math notranslate nohighlight">\( I^{\mathrm{corr}}_{ij} = \frac{I^{\mathrm{obs}}_{ij}}{G_i L_{ij} P_{ij}},\qquad \sigma^{\mathrm{corr}}_{ij} = \frac{\sigma^{\mathrm{obs}}_{ij}}{G_i L_{ij} P_{ij}}. \)</span></p> <p>Unique intensities are merged by inverse-variance weighted mean: <span class="math notranslate nohighlight">\( I_h = \frac{\sum_j w_j I^{\mathrm{corr}}_{ij}}{\sum_j w_j},\qquad w_j = \frac{1}{(\sigma^{\mathrm{corr}}_{ij})^2}. \)</span></p> <p>An internal-consistency term can inflate uncertainties when multiple observations are present, in the spirit of XSCALE.</p> </section> <section id=merging-statistics > <h3 id=merging-statistics >10.5 Merging statistics<a class=headerlink href="#merging-statistics" title="Link to this heading"></a></h3> <p>Per-shell and overall merging statistics are computed on corrected intensities, including:</p> <ul class=simple > <li><p>number of observations and of unique reflections, and multiplicity,</p> <li><p>mean <span class="math notranslate nohighlight">\(I/\sigma(I)\)</span>,</p> <li><p><span class="math notranslate nohighlight">\(R_\mathrm{meas}\)</span> (the redundancy-independent DiederichsKarplus form) from withinHKL deviations,</p> <li><p><span class="math notranslate nohighlight">\(\mathrm{CC}_{1/2}\)</span> (half-set correlation) and, when a reference dataset is supplied, <span class="math notranslate nohighlight">\(\mathrm{CC}_\mathrm{ref}\)</span>,</p> <li><p>completeness against the enumerated reflections for the cell and symmetry,</p> <li><p>the anomalous signal-to-noise <span class="math notranslate nohighlight">\(\mathrm{SigAno}\)</span> (below).</p> </ul> <p>The error model is refined as <span class="math notranslate nohighlight">\(\sigma_\mathrm{corr}^2 = a\,\sigma^2 + (b\,\langle I\rangle)^2\)</span>, with <span class="math notranslate nohighlight">\(a\)</span> set by the scatter of weak (counting-limited) reflections and <span class="math notranslate nohighlight">\(b\)</span> the intensity-proportional systematic scatter of the strong ones. <strong>ISa</strong> is the asymptotic (<span class="math notranslate nohighlight">\(I\to\infty\)</span>) signal-to-noise — by definition the reproducibility limit of the strongest reflections (Diederichs, <em>Acta Cryst.</em> <strong>D66</strong> (2010) 733) — and is read directly from the strong symmetry equivalents as the counting-subtracted fractional scatter of well-measured reflection groups (a robust median over strong groups; the <span class="math notranslate nohighlight">\(I/\sigma\)</span> threshold is relaxed on weak or radiation-damaged data that has few strong reflections), rather than as <span class="math notranslate nohighlight">\(1/b\)</span> of the whole-range fit, whose <span class="math notranslate nohighlight">\(b\)</span> is raised slightly by an intermediate-intensity excess and so understates the limit. The reported ISa and the merged-intensity systematic floor <span class="math notranslate nohighlight">\(\sigma \ge b_\mathrm{ISa}\,|I|\)</span> both use this asymptotic value, so a high-multiplicity merged <span class="math notranslate nohighlight">\(I/\sigma\)</span> approaches ISa; the per-observation <span class="math notranslate nohighlight">\(\sigma_\mathrm{corr}\)</span> (the merge weights) uses the whole-range <span class="math notranslate nohighlight">\(a,b\)</span> and is unchanged.</p> <p><strong>Anomalous signal-to-noise (SigAno).</strong> The strength of the anomalous signal is reported per shell and overall as <span class="math notranslate nohighlight">\(\mathrm{SigAno}=\langle|\Delta I|\rangle / \langle\sigma(\Delta I)\rangle\)</span>, where <span class="math notranslate nohighlight">\(\Delta I = I(+)-I(-)\)</span> over acentric reflections measured in both Bijvoet hands and <span class="math notranslate nohighlight">\(\sigma(\Delta I)=\sqrt{\sigma_+^2+\sigma_-^2}\)</span>. It is computed from the <strong>full-multiplicity</strong> inverse-variance <span class="math notranslate nohighlight">\(I(+)/I(-)\)</span> split (the same one written to the output), i.e. from all observations rather than a half-set. For pure noise <span class="math notranslate nohighlight">\(\mathrm{SigAno}\)</span> approaches the half-normal value <span class="math notranslate nohighlight">\(\sqrt{2/\pi}\approx0.8\)</span>, and it rises above <span class="math notranslate nohighlight">\(1\)</span> once a real anomalous difference is present. A half-set anomalous correlation (“<span class="math notranslate nohighlight">\(\mathrm{CC}_\mathrm{anom}\)</span>”) is deliberately <strong>not</strong> used: its two half estimates <span class="math notranslate nohighlight">\(\Delta I_0,\Delta I_1\)</span> are complementary partitions of one observation pool (<span class="math notranslate nohighlight">\(\Delta I_0+\Delta I_1=2\,\Delta I_\mathrm{full}\)</span>), so subtracting the two Bijvoet hands cancels the large common intensity that keeps <span class="math notranslate nohighlight">\(\mathrm{CC}_{1/2}\)</span> non-negative and leaves only the small anomalous signal against the per-half split noise; once the anomalous signal-to-noise per half drops below <span class="math notranslate nohighlight">\(1\)</span> that correlation is driven towards <span class="math notranslate nohighlight">\(-1\)</span> rather than <span class="math notranslate nohighlight">\(0\)</span>, misrepresenting a weak-but-real signal, whereas <span class="math notranslate nohighlight">\(\mathrm{SigAno}\)</span> has no such floor. It is emitted only when an anomalous split was made, using the standard PDBx items <code class="docutils literal notranslate"><span class=pre >_reflns.pdbx_absDiff_over_sigma_anomalous</span></code> (overall) and <code class="docutils literal notranslate"><span class=pre >_reflns_shell.pdbx_absDiff_over_sigma_anomalous</span></code> (per shell), and appears as the <code class="docutils literal notranslate"><span class=pre >SigAno</span></code> column of the printed merge-statistics table.</p> </section> <section id=rotation-datasets-combining-partials-into-fulls-3d-integration > <h3 id=rotation-datasets-combining-partials-into-fulls-3d-integration >10.6 Rotation datasets: combining partials into fulls (3D integration)<a class=headerlink href="#rotation-datasets-combining-partials-into-fulls-3d-integration" title="Link to this heading"></a></h3> <p>In a rotation scan a reflection is recorded as a series of <em>partials</em> spread across the frames its rocking curve crosses. Merging those partials directly would force the merge error model to absorb the rocking-curve slicing as if it were measurement noise, capping the achievable <span class="math notranslate nohighlight">\(I/\sigma\)</span>. For rotation data Jungfraujoch instead <strong>combines</strong> each reflections partials into a single <em>full</em> intensity first, then scales and merges the fulls — a 3D integration over the rocking curve.</p> <p>The combine groups each reflections partials into rocking events (contiguous runs of frames) and reduces each event to one full:</p> <ul class=simple > <li><p><strong>De-biased weighted sum.</strong> Partials are combined by inverse-variance weighting, where each partials variance is its background-noise component plus the <em>model</em> signal shared across the event (Kabsch profile-fit form). Using the shared model signal rather than the individual down-fluctuating intensity stops weak partials from being over-weighted, which would otherwise inflate the merged error model. The weights depend on the full, so the estimate is iterated.</p> <li><p><strong>Captured fraction.</strong> The partiality summed over the event, <span class="math notranslate nohighlight">\(f=\min(1,\sum_j p_j)\)</span>, measures how completely the rocking curve was sampled. A full whose curve was captured below a threshold (<code class="docutils literal notranslate"><span class=pre >--min-captured-fraction</span></code>, default 0.7 for rotation) is dropped — an event seen over only a small fraction of its curve is unreliable however many frames it spans. (The per-partial minimum-partiality cut of §10.2 still applies upstream, in the per-frame scaling.)</p> <li><p><strong>Capture-aware uncertainty.</strong> A full captured incompletely (<span class="math notranslate nohighlight">\(f&lt;1\)</span>) is extrapolated and biased high. The unobserved fraction is charged as an extra systematic uncertainty, <span class="math notranslate nohighlight">\(\sigma^2 \leftarrow \sigma^2 + \big(c\,(1-f)\,I\big)^2\)</span>, so the merge down-weights these extrapolated fulls and the error model treats their scatter as expected. It is enabled by default for the rotation path.</p> </ul> <p>The fulls are then re-scaled in the XDS sense — a per-image scale refit directly on the complete reflections under the unity partiality model — and merged (§10.4). Because every merged observation is now a counting-statistics-limited full rather than a partiality-divided slice, the error model reaches a far higher asymptotic <span class="math notranslate nohighlight">\(I/\sigma\)</span>.</p> <p>After scale-fulls, three <strong>correction surfaces</strong> are fitted on the combined fulls (rotation path, <strong>on by default</strong>; disable all with <code class="docutils literal notranslate"><span class=pre >--no-scaling-corrections</span></code>), each an alternating multiplicative refinement of the per-full scale against the merged reference:</p> <ul class=simple > <li><p><strong>Decay.</strong> Radiation damage weakens later frames more at higher resolution — a resolution×time (DebyeWaller) systematic the resolution-flat per-image scale cannot capture. A single global relative-<span class="math notranslate nohighlight">\(B\)</span> rate is fitted, <span class="math notranslate nohighlight">\(\ln(I_\mathrm{ref}/I_\mathrm{obs}) = 2\,(\mathrm{d}B/\mathrm{d}n)\,(n-\bar n)\,s^2\)</span> (frame <span class="math notranslate nohighlight">\(n\)</span>, <span class="math notranslate nohighlight">\(s^2 = 1/4d^2\)</span>), and folded into the scale. It engages only when the total relative-<span class="math notranslate nohighlight">\(B\)</span> over the run exceeds a physical floor (2 Ų); below that the decay is negligible and “correcting” it only spreads symmetry equivalents (same <span class="math notranslate nohighlight">\(s^2\)</span>, different frames). An optional <strong>per-batch relative-<span class="math notranslate nohighlight">\(B\)</span></strong> (<code class="docutils literal notranslate"><span class=pre >--relative-b[=deg]</span></code>, off unless requested; 10°-of-rotation batches by default) extends the single global rate to a smooth <span class="math notranslate nohighlight">\(B(n)\)</span> curve — the same <span class="math notranslate nohighlight">\(s^2\)</span>-weighted decay fit solved independently over short frame batches, curvature-penalized so it cannot over-fit and cross-validated like the surfaces below — for crystals whose decay is non-linear in dose.</p> <li><p><strong>Absorption.</strong> A smooth multiplicative factor over the diffracted-beam direction expressed in the goniometer (crystal) frame: each fulls predicted detector position gives the lab diffracted direction, de-rotated by the spindle so a fixed crystal-frame direction is sampled at many rotation angles and its grid cell is well-determined. Negligible at hard X-rays / thin crystals; it matters at low photon energy.</p> <li><p><strong>Modulation</strong> (detector-plane flat-field). A smooth multiplicative factor over where each reflection lands on the detector (predicted <span class="math notranslate nohighlight">\(x,y\)</span>): symmetry-equivalents land at different positions as the crystal rotates, over-determining the surface. It absorbs detector-response and geometric systematics that inflate <span class="math notranslate nohighlight">\(R_\mathrm{meas}\)</span>. The same 16×16 detector-frame surface is available for the stills path (<code class="docutils literal notranslate"><span class=pre >--stills-modulation</span></code>, off by default), where serial data repeatedly hammers the same detector regions.</p> </ul> <p>Each surface is <strong>cross-validated</strong>: fitted on even-numbered frames and kept only if it improves the held-out odd-frame agreement by a clear margin (and vice versa), scored by a <strong>σ-independent, <span class="math notranslate nohighlight">\(R_\mathrm{meas}\)</span>-like</strong> fractional agreement <span class="math notranslate nohighlight">\(\sum|I_s-I_\mathrm{ref}|/\sum|I_\mathrm{ref}|\)</span> rather than a studentized <span class="math notranslate nohighlight">\(\chi^2\)</span> — so a surface cannot “pass” by reshaping the sigmas instead of tightening the intensities. A surface fitted to noise where its systematic is absent does not generalize and is discarded — a correction never adds scatter.</p> <p><strong>Radiation-damage report (rotation, report-only).</strong> Independently of whether any decay correction is applied, rugnux measures and reports the relative DebyeWaller <span class="math notranslate nohighlight">\(B\)</span> across the sweep: the per-image scales correlation to the merge and the per-image mosaicity versus frame (dose), together with a per-batch relative-<span class="math notranslate nohighlight">\(B\)</span> curve whose first→last change is a single headline number (measured before any decay correction, against the least-damaged early wedge). It is written to the log and to the merged mmCIF as a data-quality-vs-dose diagnostic and <strong>never</strong> alters the merged intensities — distinct from the decay correction above, which does fold into the scale.</p> </section> <section id=r-free-test-set-flags > <h3 id=r-free-test-set-flags >10.7 R-free test-set flags<a class=headerlink href="#r-free-test-set-flags" title="Link to this heading"></a></h3> <p>A fraction of the unique reflections (<code class="docutils literal notranslate"><span class=pre >rfree_fraction</span></code>, default 0.05) is flagged as a <strong>free (test) set</strong>, written to the output (MTZ <code class="docutils literal notranslate"><span class=pre >FreeR_flag</span></code>, mmCIF <code class="docutils literal notranslate"><span class=pre >_refln.status_free</span></code>, a text-HKL column) for model validation (§14) and for downstream refinement. The flag is a pure function of the reflections <strong>Friedel-merged (Laue) ASU index</strong>, which gives three properties:</p> <ul class=simple > <li><p>all symmetry- and Friedel-equivalent reflections share one flag — in particular a Bijvoet pair <span class="math notranslate nohighlight">\(I(+)/I(-)\)</span>, kept as two separate merged rows in anomalous mode, is <strong>never split</strong> across the work and free sets (which would bias R-free);</p> <li><p>the free/work decision is a deterministic hash of that key, so the same reflection always lands in the same set — reproducible run-to-run and independent of the order in which observations were merged;</p> <li><p>the hash depends only on the reflection index, <strong>not</strong> on this datasets resolution range or which reflections it happens to contain, so a uniform draw takes ~<code class="docutils literal notranslate"><span class=pre >rfree_fraction</span></code> of the distinct reflections free and — crucially — <strong>every dataset of one crystal form gets the same free set</strong>. That cross-dataset consistency is what a multi-dataset campaign (ensemble refinement, PanDDA) requires; a per-shell stratification tied to each datasets own <span class="math notranslate nohighlight">\(d_\mathrm{min}\)</span> would break it.</p> </ul> <p>On small data, where <code class="docutils literal notranslate"><span class=pre >rfree_fraction</span></code> (default 0.05) would give too few test reflections for a statistically stable R-free (Brüngers ~5002000 rule), the fraction is <strong>floored</strong> so at least ~500 distinct reflections are free — capped at 10 % so a large test set never steals working data. For ordinary data this floor is inactive and the fraction stays flat at <code class="docutils literal notranslate"><span class=pre >rfree_fraction</span></code>, preserving the cross-dataset-identical property above; it only lifts the fraction on genuinely small datasets, where per-dataset R-free stability outweighs cross-dataset identity (and a shared reference set is the way to keep exact identity there).</p> <p>When a reference MTZ (<code class="docutils literal notranslate"><span class=pre >--reference-mtz</span></code>) carries a <code class="docutils literal notranslate"><span class=pre >FreeR_flag</span></code> column, its test set is <strong>imported</strong> instead: every merged reflection whose Laue-ASU index matches the reference takes the references flag (reflections absent from the reference keep the hash flag). This lets a whole fragment-screening campaign inherit one shared free set from the apo/reference dataset. The CCP4/refmac convention (test set = flag 0, including the historical 019 form) is assumed, with the complement taken automatically if flag 0 would be the majority (a phenix-style file where 1 marks free).</p> </section> <section id=frenchwilson-amplitudes > <h3 id=frenchwilson-amplitudes >10.8 FrenchWilson amplitudes<a class=headerlink href="#frenchwilson-amplitudes" title="Link to this heading"></a></h3> <p>The last step of the merge estimates a Bayesian structure-factor amplitude <span class="math notranslate nohighlight">\(|F|\)</span> for each unique reflection from its intensity <span class="math notranslate nohighlight">\(I\)</span> and error <span class="math notranslate nohighlight">\(\sigma\)</span>, so the output carries amplitudes alongside intensities (a naïve <span class="math notranslate nohighlight">\(\sqrt{\max(I,0)}\)</span> turns every weak or negative measurement into a biased — or zero — amplitude). With the Wilson prior for the true intensity <span class="math notranslate nohighlight">\(J\ge 0\)</span> at that resolution,</p> <p><span class="math notranslate nohighlight">\( P_\mathrm{acentric}(J) \propto e^{-J/\Sigma},\qquad P_\mathrm{centric}(J) \propto J^{-1/2}\,e^{-J/2\Sigma}, \)</span></p> <p>and a Gaussian likelihood <span class="math notranslate nohighlight">\(\mathcal{N}(I;J,\sigma^2)\)</span>, the posterior mean amplitude and its uncertainty are</p> <p><span class="math notranslate nohighlight">\( \langle |F|\rangle = \frac{\int_0^\infty \sqrt{J}\,\mathcal{N}(I;J,\sigma^2)\,P(J)\,\mathrm{d}J}{\int_0^\infty \mathcal{N}(I;J,\sigma^2)\,P(J)\,\mathrm{d}J},\qquad \sigma_F = \sqrt{\langle J\rangle - \langle|F|\rangle^2}. \)</span></p> <p>The prior mean is <span class="math notranslate nohighlight">\(\Sigma = \varepsilon\,\langle I/\varepsilon\rangle_\mathrm{shell}\)</span>, where <span class="math notranslate nohighlight">\(\varepsilon\)</span> is the reflections epsilon (symmetry-enhancement) multiplicity and <span class="math notranslate nohighlight">\(\langle I/\varepsilon\rangle\)</span> is the Wilson mean in its resolution shell (so reflections on symmetry elements, and each shell, are treated correctly). Strong reflections (<span class="math notranslate nohighlight">\(I&gt;4\sigma\)</span>) short-circuit to <span class="math notranslate nohighlight">\(|F|=\sqrt{I}\)</span>, where the FrenchWilson bias is negligible; a reflection with an unusable <span class="math notranslate nohighlight">\(I/\sigma\)</span> falls back to <span class="math notranslate nohighlight">\(\sqrt{\max(I,0)}\)</span>. The integral is evaluated numerically with a log-shift for stability.</p> <p>Amplitudes are written as MTZ <code class="docutils literal notranslate"><span class=pre >F</span></code>/<code class="docutils literal notranslate"><span class=pre >SIGF</span></code>, mmCIF <code class="docutils literal notranslate"><span class=pre >_refln.F_meas_au</span></code>/<code class="docutils literal notranslate"><span class=pre >F_meas_sigma_au</span></code>, and appended to the text HKL, alongside the intensity columns. The <strong>same</strong> <span class="math notranslate nohighlight">\(|F|\)</span> feed the model-validation step (§14), so the reflection file and the maps use one consistent set of amplitudes.</p> </section> <section id=reference-data-fixing-the-space-group-and-resolving-the-indexing-ambiguity > <h3 id=reference-data-fixing-the-space-group-and-resolving-the-indexing-ambiguity >10.9 Reference data: fixing the space group and resolving the indexing ambiguity<a class=headerlink href="#reference-data-fixing-the-space-group-and-resolving-the-indexing-ambiguity" title="Link to this heading"></a></h3> <p>A reference dataset (<code class="docutils literal notranslate"><span class=pre >--reference-mtz</span></code>) supplies known intensities for the same crystal form, and is used in two ways.</p> <p><strong>Fix the space group and cell.</strong> Unless overridden on the command line (<code class="docutils literal notranslate"><span class=pre >-S</span></code> for the space group, <code class="docutils literal notranslate"><span class=pre >-C</span></code> for the cell), the references space group is adopted and its cell is used as the soft reference cell — indexing may still drift the cell within tolerance, so a small mismatch between reference and data is absorbed rather than rejected. This applies to both stills and rotation data.</p> <p><strong>Resolve the indexing (merohedral) ambiguity.</strong> When the lattice symmetry is higher than the crystals Laue symmetry (e.g. <span class="math notranslate nohighlight">\(P3\)</span>, <span class="math notranslate nohighlight">\(P4\)</span>, <span class="math notranslate nohighlight">\(P6\)</span>, <span class="math notranslate nohighlight">\(C2\)</span>), more than one indexing of the same lattice is geometrically valid, and the two solutions produce <em>different</em> merged intensities that a self-consistent scale cannot tell apart — only an external reference can. The candidate reindexings are the identity together with the twin-law cosets of the metric symmetry (from the unit-cell metric and the Laue group); each is scored by the intensity correlation <span class="math notranslate nohighlight">\(\mathrm{CC}_\mathrm{ref}\)</span> of the reindexed merge against the reference, and the data are re-merged in the best-correlating indexing. The reindex is <strong>metric-preserving</strong> — only the <span class="math notranslate nohighlight">\(hkl\)</span> labels change, the cell is unchanged — and it is a no-op for a holohedral crystal, which has no twin laws (the lattice and Laue symmetry coincide). For rotation data this is done once, after the space group is determined; the reference is <em>not</em> used to scale the rotation merge, which stays self-consistent (its <span class="math notranslate nohighlight">\(\mathrm{ISa}\)</span> comes from the data alone). For stills the reference is the per-image scale target of the on-the-fly scaling (§10.2).</p> </section> </section> <hr class=docutils /> <section id=mosaicity-and-profile-radius-monitoring > <h2 id=mosaicity-and-profile-radius-monitoring >11. Mosaicity and “profile radius” monitoring<a class=headerlink href="#mosaicity-and-profile-radius-monitoring" title="Link to this heading"></a></h2> <section id=profile-radius-intrinsic-excitation-error-width > <h3 id=profile-radius-intrinsic-excitation-error-width >11.1 Profile radius (intrinsic excitation-error width)<a class=headerlink href="#profile-radius-intrinsic-excitation-error-width" title="Link to this heading"></a></h3> <p>The “profile radius” is the intrinsic angular width of a reflection — crystal mosaicity plus beam divergence — estimated from the spread of <span class="math notranslate nohighlight">\(\Delta_\mathrm{Ewald}\)</span> over indexed spots, <span class="math notranslate nohighlight">\( R \approx \sqrt{\tfrac{1}{N}\sum_i \Delta_{\mathrm{Ewald},i}^2}. \)</span> When the beam has a finite energy bandwidth, that bandwidth smears each reflection radially by <span class="math notranslate nohighlight">\(\sigma_\mathrm{bw}\approx \mathrm{bandwidth}\cdot\lambda/2d^2\)</span> (largest at high resolution), which also broadens the measured <span class="math notranslate nohighlight">\(\Delta_\mathrm{Ewald}\)</span> spread. Since prediction re-applies the bandwidth term per reflection (§8.2), this contribution is deconvolved from the estimate — <span class="math notranslate nohighlight">\(R^2 = \langle\Delta_\mathrm{Ewald}^2\rangle - \langle\sigma_\mathrm{bw}^2\rangle\)</span> — so that <span class="math notranslate nohighlight">\(R\)</span> is the intrinsic width and bandwidth is not double-counted. Still predictions use an excitation-error cutoff proportional to <span class="math notranslate nohighlight">\(R\)</span>.</p> </section> <section id=mosaicity-from-rotation-data > <h3 id=mosaicity-from-rotation-data >11.2 Mosaicity from rotation data<a class=headerlink href="#mosaicity-from-rotation-data" title="Link to this heading"></a></h3> <p>For rotation data the mosaicity <span class="math notranslate nohighlight">\(\sigma_M\)</span> is estimated by maximum likelihood from the rocking offsets <span class="math notranslate nohighlight">\(\tau\)</span> of indexed spots, using the XDS reflection-fraction model <span class="math notranslate nohighlight">\(R(\tau;\sigma_M/\zeta)\)</span> (Kabsch 2010): each spots exact Bragg angle is located near its frame, <span class="math notranslate nohighlight">\(\zeta\)</span> (the rotation-axis Lorentz component) is computed, and <span class="math notranslate nohighlight">\(\sigma_M\)</span> is chosen to maximize <span class="math notranslate nohighlight">\(\sum_i \log R(\tau_i;\sigma_M/\zeta_i)\)</span>.</p> <p>The <span class="math notranslate nohighlight">\(\phi\)</span> search window for the Bragg angle is set <strong>wider than the oscillation</strong>, so that reflections recorded at large rocking offset are included. These tail reflections carry most of the information about the mosaic width; a window limited to the oscillation range would truncate the <span class="math notranslate nohighlight">\(\tau\)</span> distribution and bias <span class="math notranslate nohighlight">\(\sigma_M\)</span> low.</p> <p>The estimated mosaicity feeds the rotation prediction (how many frames each reflection spans, §8.3) and the rotation partiality (§10.2). It is <strong>held fixed during scaling</strong>: in the per-image scale fit the mosaicity is degenerate with the scale <span class="math notranslate nohighlight">\(G\)</span> (both rescale the predicted intensity), so refining it there is unstable. A correct mosaicity matters because it controls both how much of each rocking curve is captured and the partiality used to form fulls (§10.6); too small a value truncates the captured curve and over-peaks the partiality, degrading the combined fulls.</p> </section> </section> <hr class=docutils /> <section id=auxiliary-statistics-i-i-and-wilson-plot > <h2 id=auxiliary-statistics-i-i-and-wilson-plot >12. Auxiliary statistics: ⟨I/σ(I)⟩ and Wilson plot<a class=headerlink href="#auxiliary-statistics-i-i-and-wilson-plot" title="Link to this heading"></a></h2> <section id=per-shell-i-i > <h3 id=per-shell-i-i >12.1 Per-shell ⟨I/σ(I)⟩<a class=headerlink href="#per-shell-i-i" title="Link to this heading"></a></h3> <p>For monitoring integration quality, Jungfraujoch reports mean <span class="math notranslate nohighlight">\(\langle I/\sigma(I)\rangle\)</span> in a fixed number of resolution shells. Shelling is performed in <span class="math notranslate nohighlight">\(1/d^2\)</span> space (typical of crystallographic practice).</p> </section> <section id=wilson-plot-b-factor-proxy > <h3 id=wilson-plot-b-factor-proxy >12.2 Wilson plot (B-factor proxy)<a class=headerlink href="#wilson-plot-b-factor-proxy" title="Link to this heading"></a></h3> <p>A Wilson-type analysis is computed by binning intensities by resolution and fitting: <span class="math notranslate nohighlight">\( \langle I\rangle \propto \exp\!\left(-\frac{B}{2}\frac{1}{d^2}\right), \)</span> i.e. <span class="math notranslate nohighlight">\( \log \langle I\rangle = \mathrm{const} - \frac{B}{2}\left(\frac{1}{d^2}\right). \)</span> A linear regression of <span class="math notranslate nohighlight">\(\log\langle I\rangle\)</span> vs <span class="math notranslate nohighlight">\(1/d^2\)</span> provides an estimate of <span class="math notranslate nohighlight">\(B\)</span>, subject to basic quality checks (e.g. <span class="math notranslate nohighlight">\(R^2\)</span> threshold).</p> <p>A <strong>dataset-wide</strong> Wilson <span class="math notranslate nohighlight">\(B\)</span> is also estimated over the merged reflections — restricted to the meaningful resolution range (skipping the low-resolution non-linear region below ~4 Å and shells past the signal limit <span class="math notranslate nohighlight">\(\langle I/\sigma\rangle &lt; 1\)</span>, so it is insensitive to how far the merged data extend) — and written to the merged mmCIF as <code class="docutils literal notranslate"><span class=pre >_reflns.B_iso_Wilson_estimate</span></code>, the analogue of XDSs Wilson-line <span class="math notranslate nohighlight">\(B\)</span>. It is diagnostic only and is not fed back into scaling. The <strong>per-image</strong> estimate (used for the live radiation-damage plot) is accepted only when the fit is well-correlated and physically plausible (<span class="math notranslate nohighlight">\(0 &lt; B &lt; 200\)</span> Ų); on a bad frame (an indexing glitch, too few reflections) the Wilson line runs wildly steep, so an implausible <span class="math notranslate nohighlight">\(B\)</span> is reported as NaN rather than a spurious hundreds-of-Ų value.</p> </section> </section> <hr class=docutils /> <section id=practical-notes-and-limitations > <h2 id=practical-notes-and-limitations >13. Practical notes and limitations<a class=headerlink href="#practical-notes-and-limitations" title="Link to this heading"></a></h2> <ul class=simple > <li><p><strong>Bragg integration is profile-fitted by default</strong> (per-shell Gaussian profile, Kabsch extraction; §9.3), with plain box summation available as a fallback (<code class="docutils literal notranslate"><span class=pre >--integrator</span> <span class=pre >boxsum</span></code>). The profiles are built per frame from that frames strong spots, which suits fast-feedback and serial/streaming use; a profile shared across many frames (as in full offline workflows) is not currently formed.</p> <li><p><strong>Space-group symmetry</strong> beyond centering absences is not necessarily enforced during prediction/integration unless the space group is supplied and used downstream.</p> <li><p><strong>Resolution masking and ice rings</strong> are controllable; including ice-ring spots in indexing can improve robustness for some samples but may bias refinement in others.</p> <li><p><strong>Rotation vs still modes</strong> differ substantially in prediction and scaling: partiality is angle-driven in rotation data, while stills are predicted (within an excitation-error window) and scaled with unit partiality.</p> <li><p><strong>Space-group determination.</strong> When no space group is supplied, a POINTLESS-like search scores Laue-group symmetry (CC of <span class="math notranslate nohighlight">\(I(h)\)</span> vs <span class="math notranslate nohighlight">\(I(Rh)\)</span> plus merge self-consistency) and detects screw/centering absences from the <span class="math notranslate nohighlight">\(P1\)</span>-merged intensities. The self-consistency test is calibrated so a merohedral twin — whose twin law forces non-equivalent reflections together and inflates the merged <span class="math notranslate nohighlight">\(\chi^2\)</span> — stays in its true lower symmetry rather than being over-promoted to the holohedral group. Because a partial twins within-orbit <span class="math notranslate nohighlight">\(\chi^2\)</span> can nonetheless look self-consistent, a chi²-passing promotion is additionally <strong>vetoed</strong> when merging its extra operator balloons the error-model <span class="math notranslate nohighlight">\(b\)</span> (the intensity-proportional systematic) relative to the confirmed subgroup: a genuine symmetry step gains multiplicity without inflating <span class="math notranslate nohighlight">\(b\)</span>, whereas a twin forces non-equivalent reflections together and <span class="math notranslate nohighlight">\(b\)</span> balloons. <strong>Centering</strong> is accepted when the systematically-absent class is weak relative to the present one by <em>either</em> of two floor-independent tests — its mean signed <span class="math notranslate nohighlight">\(I/\sigma\)</span> well below the present mean, <em>or</em> its rate of individually-significant reflections well below the present classs own significant rate. The second test matters on weak / low-energy data, where a positive intensity floor (background/profile leakage) lifts the absent classs mean <span class="math notranslate nohighlight">\(I/\sigma\)</span> to <span class="math notranslate nohighlight">\(\sim1.5\)</span><span class="math notranslate nohighlight">\(2.3\)</span> instead of <span class="math notranslate nohighlight">\(\sim0\)</span> and, when the present class is itself weak, inflates the plain mean ratio past its bound and hides a real centering (an <span class="math notranslate nohighlight">\(I\)</span>-centred cubic recorded at 5 keV was otherwise kept primitive); a false centering fails both tests because its absent class is as strong as the present one. When several centerings pass, they are ranked by their <strong>net</strong> systematic absences (absent minus violating), not the gross absent count, so a super-centering (e.g. <span class="math notranslate nohighlight">\(F\)</span> over a true <span class="math notranslate nohighlight">\(C\)</span>) whose extra, only-half-populated absent class merely dilutes the strength ratio does not out-rank the correct lower centering.</p> <li><p><strong>Twinning check.</strong> A PadillaYeates <span class="math notranslate nohighlight">\(L\)</span>-test (<span class="math notranslate nohighlight">\(\langle|L|\rangle\)</span>, <span class="math notranslate nohighlight">\(\langle L^2\rangle\)</span>) and the second moment <span class="math notranslate nohighlight">\(\langle I^2\rangle/\langle I\rangle^2\)</span> (taken per resolution shell with noise-only shells skipped and Wilson outliers rejected, so a single strong reflection in a collapsed-mean shell cannot skew it) are written to the merged mmCIF as a twinning diagnostic. Twinning is only flagged in Laue classes where a merohedral twin law can exist; the holohedral high-symmetry classes (<span class="math notranslate nohighlight">\(4/mmm\)</span>, <span class="math notranslate nohighlight">\(6/mmm\)</span>, <span class="math notranslate nohighlight">\(m\bar{3}m\)</span>, and <span class="math notranslate nohighlight">\(\bar{3}m\)</span> on a rhombohedral lattice) are exempt, so a low <span class="math notranslate nohighlight">\(\langle|L|\rangle\)</span> there is reported as a statistical artefact rather than twinning.</p> <li><p><strong>Outlier rejection.</strong> Merging applies an optional per-observation median-based <span class="math notranslate nohighlight">\(N\sigma\)</span> cut (default 6σ for <code class="docutils literal notranslate"><span class=pre >rot3d</span></code>) and an optional per-crystal <span class="math notranslate nohighlight">\(\Delta\mathrm{CC}_{1/2}\)</span> image rejection (<code class="docutils literal notranslate"><span class=pre >--reject-delta-cchalf</span></code>, CrystFEL-style, off by default). The same <span class="math notranslate nohighlight">\(N\sigma\)</span> cut is fed back into the error model: after an initial <span class="math notranslate nohighlight">\(a,b\)</span> fit the parameters are re-fit once on the reflections that survive rejection (dropping any whose squared deviation exceeds <span class="math notranslate nohighlight">\(N\sigma^2\,[a\,\sigma^2 + (b\,\langle I\rangle)^2]\)</span>), so the calibrated errors describe the reflections that actually enter the merge rather than the pre-rejection pool.</p> <li><p><strong>Automatic resolution cutoff.</strong> By default the reported/written high-resolution limit is trimmed where <span class="math notranslate nohighlight">\(\mathrm{CC}_{1/2}\)</span> falls off (logistic, target 0.30); <code class="docutils literal notranslate"><span class=pre >--scaling-high-resolution</span></code> overrides it and <code class="docutils literal notranslate"><span class=pre >--resolution-cutoff</span> <span class=pre >off</span></code> disables it.</p> <li><p><strong>Amplitudes and intensities.</strong> The merged output carries both intensities (mmCIF <code class="docutils literal notranslate"><span class=pre >intensity_meas</span></code>, MTZ <code class="docutils literal notranslate"><span class=pre >IMEAN</span></code>/<code class="docutils literal notranslate"><span class=pre >SIGIMEAN</span></code>) and FrenchWilson amplitudes (mmCIF <code class="docutils literal notranslate"><span class=pre >F_meas_au</span></code>, MTZ <code class="docutils literal notranslate"><span class=pre >F</span></code>/<code class="docutils literal notranslate"><span class=pre >SIGF</span></code>; §10.8), so a downstream program can refine against either.</p> </ul> </section> <hr class=docutils /> <section id=model-based-validation-r-free-against-a-model-and-electron-density-maps > <h2 id=model-based-validation-r-free-against-a-model-and-electron-density-maps >14. Model-based validation: R-free against a model and electron-density maps<a class=headerlink href="#model-based-validation-r-free-against-a-model-and-electron-density-maps" title="Link to this heading"></a></h2> <p>Offline (<code class="docutils literal notranslate"><span class=pre >rugnux</span> <span class=pre >--model</span> <span class=pre >model.pdb</span></code>) the merged data can be scored against a supplied atomic model and <strong>initial</strong> electron-density maps computed — enough to confirm that a model fits the data and to inspect the density, not a substitute for refinement. <strong>The structure itself is not refined</strong>; the model is only re-fractionalized into the data unit cell (a rigid cell adjustment, so a deposited model with a slightly different cell still lines up), and the observed amplitudes are the FrenchWilson <span class="math notranslate nohighlight">\(|F|\)</span> from §10.8, so the R-free and the maps use exactly the same amplitudes as the written reflection file. The model, structure-factor, bulk-solvent and FFT machinery is provided by GEMMI.</p> <section id=model-structure-factors > <h3 id=model-structure-factors >14.1 Model structure factors<a class=headerlink href="#model-structure-factors" title="Link to this heading"></a></h3> <p>The model electron density is sampled on a grid (IT92 X-ray form factors, with a Refmac-compatible Gaussian blur chosen for the grid spacing) and Fourier-transformed to structure factors <span class="math notranslate nohighlight">\(F_\mathrm{calc}(hkl)\)</span> up to the data resolution.</p> </section> <section id=bulk-solvent-and-scaling > <h3 id=bulk-solvent-and-scaling >14.2 Bulk solvent and scaling<a class=headerlink href="#bulk-solvent-and-scaling" title="Link to this heading"></a></h3> <p>A flat bulk-solvent mask around the model is transformed to <span class="math notranslate nohighlight">\(F_\mathrm{mask}\)</span>, and the model is scaled to the observed amplitudes by an overall least-squares fit of a scale <span class="math notranslate nohighlight">\(k\)</span>, an anisotropic <span class="math notranslate nohighlight">\(B\)</span>, and the flat-solvent parameters <span class="math notranslate nohighlight">\(k_\mathrm{sol}, B_\mathrm{sol}\)</span>:</p> <p><span class="math notranslate nohighlight">\( F_\mathrm{model} = k\,e^{-\mathbf{h}^\top \mathbf{B}\,\mathbf{h}/4}\left(F_\mathrm{calc} + k_\mathrm{sol}\,e^{-B_\mathrm{sol}\,s^2}\,F_\mathrm{mask}\right),\quad s^2 = 1/4d^2. \)</span></p> <p>This is the standard, few-parameter scaling model used by refinement programs. A dataset-specific free-form per-resolution-shell rescale would lower this datasets R a little, but it reshapes each maps radial amplitude profile differently, so a batch of maps would no longer be directly comparable — for a fragment-screening / PanDDA campaign, comparable maps across datasets matter more than the last bit of per-dataset R, so it is deliberately not applied.</p> </section> <section id=r-work-and-r-free > <h3 id=r-work-and-r-free >14.3 R-work and R-free<a class=headerlink href="#r-work-and-r-free" title="Link to this heading"></a></h3> <p>Crystallographic R-factors are reported over the work and free sets (the §10.7 flags):</p> <p><span class="math notranslate nohighlight">\( R = \frac{\sum \big|\,|F_o| - |F_\mathrm{model}|\,\big|}{\sum |F_o|}, \)</span></p> <p>with R-free the same sum restricted to the free set — an unbiased measure of how well the model explains data it was not scaled against.</p> </section> <section id=electron-density-maps > <h3 id=electron-density-maps >14.4 Electron-density maps<a class=headerlink href="#electron-density-maps" title="Link to this heading"></a></h3> <p>Two maps are formed with the model phases <span class="math notranslate nohighlight">\(\varphi_\mathrm{model}\)</span>: a <span class="math notranslate nohighlight">\(2F_o-F_c\)</span> map, coefficients <span class="math notranslate nohighlight">\((2|F_o|-|F_\mathrm{model}|)\,e^{i\varphi_\mathrm{model}}\)</span>, and an <span class="math notranslate nohighlight">\(F_o-F_c\)</span> difference map, <span class="math notranslate nohighlight">\((|F_o|-|F_\mathrm{model}|)\,e^{i\varphi_\mathrm{model}}\)</span>, each inverse-Fourier-transformed to a real-space CCP4 map (<code class="docutils literal notranslate"><span class=pre >&lt;prefix&gt;_2fofc.ccp4</span></code>, <code class="docutils literal notranslate"><span class=pre >&lt;prefix&gt;_fofc.ccp4</span></code>). A map-coefficient MTZ (<code class="docutils literal notranslate"><span class=pre >&lt;prefix&gt;_maps.mtz</span></code>: <code class="docutils literal notranslate"><span class=pre >FP</span></code>, <code class="docutils literal notranslate"><span class=pre >FC</span></code>, <code class="docutils literal notranslate"><span class=pre >PHIC</span></code>, <code class="docutils literal notranslate"><span class=pre >FWT</span></code>/<code class="docutils literal notranslate"><span class=pre >PHWT</span></code>, <code class="docutils literal notranslate"><span class=pre >DELFWT</span></code>/<code class="docutils literal notranslate"><span class=pre >PHDELWT</span></code>, <code class="docutils literal notranslate"><span class=pre >FREE</span></code>) is written alongside so the maps can be reopened or rebuilt in Coot / PyMOL. These are unweighted difference coefficients (no <span class="math notranslate nohighlight">\(\sigma_A\)</span> / figure-of-merit weighting), which is why they are described as <em>initial</em> maps.</p> </section> <section id=aligning-the-data-to-the-model-enantiomorph-and-indexing-ambiguity > <h3 id=aligning-the-data-to-the-model-enantiomorph-and-indexing-ambiguity >14.5 Aligning the data to the model: enantiomorph and indexing ambiguity<a class=headerlink href="#aligning-the-data-to-the-model-enantiomorph-and-indexing-ambiguity" title="Link to this heading"></a></h3> <p>The model fixes a definite hand and indexing, but the merged data need not share them, so before comparison the observed reflections are brought into the models frame.</p> <ul class=simple > <li><p><strong>Enantiomorph / screw.</strong> When the data space group is the enantiomorph of the models (e.g. data <span class="math notranslate nohighlight">\(P4_12_12\)</span>, model <span class="math notranslate nohighlight">\(P4_32_12\)</span>; or <span class="math notranslate nohighlight">\(P3_1/P3_2\)</span>), the two are <strong>indistinguishable from merged intensities</strong><span class="math notranslate nohighlight">\(|F_\mathrm{calc}|\)</span> is invariant under the change of hand, so R-free cannot choose between them and probing would be meaningless. The hand is therefore taken from the model: the observed reflections are reindexed by the change-of-hand operator into the models enantiomorph. Only the map phases (the densitys hand) depend on this choice.</p> <li><p><strong>Indexing (merohedral) ambiguity.</strong> When the crystal has a merohedral ambiguity (§10.9), the observed intensities <em>do</em> differ between indexings, and the right one is chosen against the best available reference. <strong>If a reference MTZ was supplied, the data were already reindexed to agree with it</strong> (§10.9 — by the reference-intensity correlation, at the merge stage for rotation data or per image in stills scaling), and model validation keeps that authoritative choice. <strong>Only with a model and no reference</strong> does validation resolve the ambiguity itself, as a fallback: the scaled model is fit to each reindexing of the data (identity plus the twin-law cosets) and the one giving the <strong>lowest R-free</strong> is kept. This matters for a multi-dataset campaign — a single shared reference fixes one indexing convention for every dataset, whereas an independent per-dataset lowest-R-free choice could send borderline datasets to different conventions. A no-op either way for a holohedral crystal (no twin laws).</p> </ul> </section> </section> </section> </article> </div> </div> </main> </div> <footer class=md-footer > <div class=md-footer-nav > <nav class="md-footer-nav__inner md-grid"> <a href=DETECTOR_GEOMETRY.html title="Detector geometry" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel=prev > <div class="md-flex__cell md-flex__cell--shrink"> <i class="md-icon md-icon--arrow-back md-footer-nav__button"></i> </div> <div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title"> <span class=md-flex__ellipsis > <span class=md-footer-nav__direction > "Previous" </span> Detector geometry </span> </div> </a> <a href=OPENAPI.html title=OpenAPI class="md-flex md-footer-nav__link md-footer-nav__link--next" rel=next > <div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title"><span class=md-flex__ellipsis > <span class=md-footer-nav__direction > "Next" </span> OpenAPI </span> </div> <div class="md-flex__cell md-flex__cell--shrink"><i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i> </div> </a> </nav> </div> <div class="md-footer-meta md-typeset"> <div class="md-footer-meta__inner md-grid"> <div class=md-footer-copyright > <div class=md-footer-copyright__highlight > &#169; Copyright 2024, Paul Scherrer Institute. </div> Created using <a href="http://www.sphinx-doc.org/">Sphinx</a> 8.1.3. and <a href="https://github.com/bashtage/sphinx-material/">Material for Sphinx</a> </div> </div> </div> </footer> <script src="_static/javascripts/application.js"></script> <script>app.initialize({version: "1.0.4", url: {base: ".."}})</script>