Ejemplo n.º 1
0
def run(args: List[str] = None, phil: libtbx.phil.scope = phil_scope) -> None:
    """
    Run dials.anvil_correction as from the command line.

    Take integrated experiment lists and reflection tables and correct the all the
    integrated intensities for the estimated attenuation by the diamond anvils.

    Args:
        args: The arguments supplied by the user (default: sys.argv[1:]).
        phil: The PHIL scope definition (default: phil_scope, the master PHIL scope
              for this program).
    """
    usage = "dials.anvil_correction [options] integrated.expt integrated.refl"

    parser = OptionParser(
        usage=usage,
        phil=phil,
        read_reflections=True,
        read_experiments=True,
        check_format=False,
        epilog=__doc__,
    )

    params, options = parser.parse_args(args=args, show_diff_phil=False)

    # Log the difference between the PHIL scope definition and the active PHIL scope,
    # which will include the parsed user inputs.
    diff_phil = parser.diff_phil.as_str()
    if diff_phil:
        logger.info("The following parameters have been modified:\n%s",
                    diff_phil)

    # Check that at least one reflection table and experiment list have been provided.
    input_errors = []
    if not params.input.experiments:
        input_errors.append(
            "Please provide at least one valid experiment list (.expt) file.")
    if not params.input.reflections:
        input_errors.append(
            "Please provide at least one valid reflection table (.refl) file.")
    if input_errors:
        sys.exit("\n".join([parser.format_help()] + input_errors))

    if not np.linalg.norm(params.anvil.normal):
        sys.exit(
            "It seems you have provided a surface normal vector with zero length."
        )

    # Check that the anvil surface normal really is normalised.
    dac_norm = params.anvil.normal / np.linalg.norm(params.anvil.normal)

    # Configure the logging.
    dials.util.log.config(options.verbose, logfile=params.output.log)

    # These functions are commonly used to collate the input.
    experiments = flatten_experiments(params.input.experiments)
    reflections_list = flatten_reflections(params.input.reflections)
    # Work around parse_multiple_datasets dropping unindexed reflections.
    unindexed = flex.reflection_table()
    for r_table in reflections_list:
        unindexed.extend(r_table.select(r_table["id"] == -1))
    # Get a single reflection table per experiment object.
    reflections_list = parse_multiple_datasets(reflections_list)
    reflections_list = sort_tables_to_experiments_order(
        reflections_list, experiments)

    # Record the density of diamond in g·cm⁻³ (for consistency with NIST tables,
    # https://doi.org/10.18434/T4D01F).
    density = params.anvil.density / 1000  # g·cm⁻³

    # Correct for the attenuation of the incident and diffracted beams by the diamond
    # anvil cell.
    logger.info(
        "Correcting integrated reflection intensities for attenuation by the diamond "
        "anvil cell.")
    for experiment, reflections in zip(experiments, reflections_list):
        correct_intensities_for_dac_attenuation(experiment, reflections,
                                                dac_norm,
                                                params.anvil.thickness,
                                                density)
    logger.info("Done.")

    # Do optional experiment list file output here.
    if params.output.experiments:
        logger.info("Writing the experiment list to %s",
                    params.output.experiments)
        experiments.as_file(params.output.experiments)
    logger.info("Writing the reflection table to %s",
                params.output.reflections)
    # Collate reflections into a single reflection table and save it to file.
    reflections = unindexed
    for r_table in reflections_list:
        reflections.extend(r_table)
    del reflections_list
    reflections.as_file(params.output.reflections)