예제 #1
0
def test_miller_array_datatype():

    data_dir = os.path.dirname(os.path.abspath(__file__))
    data_mtz = os.path.join(data_dir, 'data',
                            'insulin_unmerged_cutted_from_ccp4.mtz')

    dm = DataManager(['miller_array', 'phil'])
    dm.process_miller_array_file(data_mtz)

    # test labels
    labels = [
        'M_ISYM', 'BATCH', 'I, SIGI', 'IPR, SIGIPR', 'FRACTIONCALC', 'XDET',
        'YDET', 'ROT', 'WIDTH', 'LP', 'MPART', 'FLAG', 'BGPKRATIOS'
    ]
    for label in dm.get_miller_array_labels():
        assert (label in labels)

    assert (len(dm.get_miller_arrays()) == len(dm.get_miller_array_labels()))

    # test access by label
    label = dm.get_miller_array_labels()[3]
    new_label = ', '.join(
        dm.get_miller_arrays(labels=[label])[0].info().labels)
    assert (label == new_label)

    # test custom PHIL
    dm.write_phil_file('test.phil',
                       dm.export_phil_scope().as_str(),
                       overwrite=True)
    loaded_phil = libtbx.phil.parse(file_name='test.phil')
    new_dm = DataManager(['miller_array', 'phil'])
    new_dm.load_phil_scope(loaded_phil)
    assert (data_mtz == new_dm.get_default_miller_array_name())
    for label in new_dm.get_miller_array_labels():
        assert (label in labels)

    os.remove('test.phil')
예제 #2
0
def test_miller_array_datatype():

    data_dir = os.path.dirname(os.path.abspath(__file__))
    data_mtz = os.path.join(data_dir, 'data',
                            'insulin_unmerged_cutted_from_ccp4.mtz')

    dm = DataManager(['miller_array', 'phil'])
    dm.process_miller_array_file(data_mtz)

    # test labels
    labels = [
        'M_ISYM', 'BATCH', 'I,SIGI,merged', 'IPR,SIGIPR,merged',
        'FRACTIONCALC', 'XDET', 'YDET', 'ROT', 'WIDTH', 'LP', 'MPART', 'FLAG',
        'BGPKRATIOS'
    ]
    for label in dm.get_miller_array_labels():
        assert label in labels

    assert len(dm.get_miller_arrays()) == len(dm.get_miller_array_labels())

    # test access by label
    label = dm.get_miller_array_labels()[3]
    new_label = dm.get_miller_arrays(labels=[label])[0].info().label_string()
    assert label == new_label

    # test custom PHIL
    dm.write_phil_file(dm.export_phil_scope().as_str(),
                       filename='test.phil',
                       overwrite=True)
    loaded_phil = iotbx.phil.parse(file_name='test.phil')
    new_dm = DataManager(['miller_array', 'phil'])
    new_dm.load_phil_scope(loaded_phil)
    assert data_mtz == new_dm.get_default_miller_array_name()
    for label in new_dm.get_miller_array_labels():
        assert label in labels

    os.remove('test.phil')

    # test type
    assert dm.get_miller_array_type() == 'x_ray'
    label = labels[3]
    dm.set_miller_array_type(data_mtz, label, 'electron')
    assert dm.get_miller_array_type(label=label) == 'electron'
    dm.write_phil_file(dm.export_phil_scope().as_str(),
                       filename='test_phil',
                       overwrite=True)
    loaded_phil = iotbx.phil.parse(file_name='test_phil')
    new_dm.load_phil_scope(loaded_phil)
    assert new_dm.get_miller_array_type(label=label) == 'electron'
    new_dm = DataManager(['miller_array'])
    try:
        new_dm.set_default_miller_array_type('q')
    except Sorry:
        pass
    new_dm.set_default_miller_array_type('neutron')
    new_dm.process_miller_array_file(data_mtz)
    assert new_dm.get_miller_array_type(label=label) == 'neutron'

    os.remove('test_phil')

    # test writing file
    arrays = dm.get_miller_arrays()
    dataset = arrays[2].as_mtz_dataset(column_root_label='label1')
    dataset.add_miller_array(miller_array=arrays[3],
                             column_root_label='label2')
    mtz_object = dataset.mtz_object()
    dm.write_miller_array_file(mtz_object, filename='test.mtz', overwrite=True)
    dm.process_miller_array_file('test.mtz')
    new_labels = dm.get_miller_array_labels('test.mtz')
    assert 'label1,SIGlabel1' in new_labels
    assert 'label2,SIGlabel2' in new_labels

    os.remove('test.mtz')

    # test file server
    fs1 = dm.get_reflection_file_server()
    fs2 = dm.get_reflection_file_server([data_mtz, data_mtz])
    assert 2 * len(fs1.miller_arrays) == len(fs2.miller_arrays)
    cs = crystal.symmetry(
        unit_cell=dm.get_miller_arrays()[0].crystal_symmetry().unit_cell(),
        space_group_symbol='P1')
    fs = dm.get_reflection_file_server(crystal_symmetry=cs)
    assert fs.crystal_symmetry.is_similar_symmetry(cs)
    assert not fs.crystal_symmetry.is_similar_symmetry(
        dm.get_miller_arrays()[0].crystal_symmetry())
    fs = dm.get_reflection_file_server(labels=['I,SIGI,merged'])
    assert len(fs.get_miller_arrays(None)) == 1
    miller_array = fs.get_amplitudes(None, None, True, None, None)
    assert miller_array.info().label_string() == 'I,as_amplitude_array,merged'

    for label in dm.get_miller_array_labels():
        dm.set_miller_array_type(label=label, array_type='electron')
    fs = dm.get_reflection_file_server(array_type='x_ray')
    assert len(fs.get_miller_arrays(None)) == 0
    fs = dm.get_reflection_file_server(array_type='electron')
    assert len(fs.get_miller_arrays(None)) == 13
    fs = dm.get_reflection_file_server(
        filenames=[data_mtz],
        labels=[['I,SIGI,merged', 'IPR,SIGIPR,merged']],
        array_type='neutron')
    assert len(fs.get_miller_arrays(None)) == 0
    for label in ['I,SIGI,merged', 'IPR,SIGIPR,merged']:
        dm.set_miller_array_type(label=label, array_type='x_ray')
    fs = dm.get_reflection_file_server(
        filenames=[data_mtz],
        labels=[['I,SIGI,merged', 'IPR,SIGIPR,merged']],
        array_type='x_ray')
    assert len(fs.get_miller_arrays(data_mtz)) == 2
    fs = dm.get_reflection_file_server(filenames=[data_mtz],
                                       array_type='x_ray')
    assert len(fs.get_miller_arrays(data_mtz)) == 2
    fs = dm.get_reflection_file_server(filenames=[data_mtz],
                                       array_type='electron')
    assert len(fs.get_miller_arrays(data_mtz)) == 11

    # test subset of labels
    label_subset = labels[3:8]
    dm = DataManager(['miller_array', 'phil'])
    dm.process_miller_array_file(data_mtz)
    dm._miller_array_labels[data_mtz] = label_subset
    dm.set_miller_array_type(label=label_subset[2], array_type='electron')
    assert dm.get_miller_array_type(label=label_subset[2]) == 'electron'
    dm.write_phil_file(dm.export_phil_scope().as_str(),
                       filename='test.phil',
                       overwrite=True)
    loaded_phil = iotbx.phil.parse(file_name='test.phil')
    new_dm = DataManager(['miller_array', 'phil'])
    new_dm.load_phil_scope(loaded_phil)
    assert new_dm.get_miller_array_type(label=label_subset[2]) == 'electron'
    fs = new_dm.get_reflection_file_server(array_type='x_ray')
    assert len(fs.get_miller_arrays(None)) == 4
    fs = new_dm.get_reflection_file_server(array_type='electron')
    assert len(fs.get_miller_arrays(None)) == 1
    os.remove('test.phil')

    label_subset = list()
    dm = DataManager(['miller_array', 'phil'])
    dm.process_miller_array_file(data_mtz)
    dm._miller_array_labels[data_mtz] = label_subset
    dm.write_phil_file(dm.export_phil_scope().as_str(),
                       filename='test.phil',
                       overwrite=True)
    loaded_phil = iotbx.phil.parse(file_name='test.phil')
    new_dm = DataManager(['miller_array', 'phil'])
    new_dm.load_phil_scope(loaded_phil)
    fs = new_dm.get_reflection_file_server(array_type='x_ray')
    assert len(fs.get_miller_arrays(None)) == 13
    fs = new_dm.get_reflection_file_server(array_type='electron')
    assert len(fs.get_miller_arrays(None)) == 0
    os.remove('test.phil')
def test_miller_array_datatype():

  data_dir = os.path.dirname(os.path.abspath(__file__))
  data_mtz = os.path.join(data_dir, 'data',
                          'insulin_unmerged_cutted_from_ccp4.mtz')

  dm = DataManager(['miller_array', 'phil'])
  dm.process_miller_array_file(data_mtz)

  # test labels
  labels = ['M_ISYM', 'BATCH', 'I,SIGI,merged', 'IPR,SIGIPR,merged',
            'FRACTIONCALC', 'XDET', 'YDET', 'ROT', 'WIDTH', 'LP', 'MPART',
            'FLAG', 'BGPKRATIOS']
  for label in dm.get_miller_array_labels():
    assert(label in labels)

  assert(len(dm.get_miller_arrays()) == len(dm.get_miller_array_labels()))

  # test access by label
  label = dm.get_miller_array_labels()[3]
  new_label = dm.get_miller_arrays(labels=[label])[0].info().label_string()
  assert(label == new_label)

  # test custom PHIL
  dm.write_phil_file('test.phil', dm.export_phil_scope().as_str(), True)
  loaded_phil = iotbx.phil.parse(file_name='test.phil')
  new_dm = DataManager(['miller_array', 'phil'])
  new_dm.load_phil_scope(loaded_phil)
  assert(data_mtz == new_dm.get_default_miller_array_name())
  for label in new_dm.get_miller_array_labels():
    assert(label in labels)

  os.remove('test.phil')

  # test type
  assert(dm.get_miller_array_type() == 'x_ray')
  dm.set_miller_array_type(data_mtz, 'electron')
  assert(dm.get_miller_array_type() == 'electron')
  dm.write_phil_file('test_phil', dm.export_phil_scope().as_str(), True)
  loaded_phil = iotbx.phil.parse(file_name='test_phil')
  new_dm.load_phil_scope(loaded_phil)
  assert(new_dm.get_miller_array_type() == 'electron')
  new_dm = DataManager(['miller_array'])
  try:
    new_dm.set_default_miller_array_type('q')
  except Sorry:
    pass
  new_dm.set_default_miller_array_type('neutron')
  new_dm.process_miller_array_file(data_mtz)
  assert(new_dm.get_miller_array_type() == 'neutron')

  # test file server
  fs1 = dm.get_reflection_file_server()
  fs2 = dm.get_reflection_file_server([data_mtz, data_mtz])
  assert(2*len(fs1.miller_arrays) == len(fs2.miller_arrays))
  cs = crystal.symmetry(
    unit_cell=dm.get_miller_arrays()[0].crystal_symmetry().unit_cell(),
    space_group_symbol='P1')
  fs = dm.get_reflection_file_server(crystal_symmetry=cs)
  assert(fs.crystal_symmetry.is_similar_symmetry(cs))
  assert(not fs.crystal_symmetry.is_similar_symmetry(
    dm.get_miller_arrays()[0].crystal_symmetry()))
  fs = dm.get_reflection_file_server(labels=['I,SIGI,merged'])
  assert(len(fs.get_miller_arrays(None)) == 1)
  miller_array = fs.get_amplitudes(None,None,True,None,None)
  assert(miller_array.info().label_string() == 'I,as_amplitude_array,merged')

  fs = dm.get_reflection_file_server(array_type='x_ray')
  assert(len(fs.get_miller_arrays(None)) == 0)
  fs = dm.get_reflection_file_server(array_type='electron')
  assert(len(fs.get_miller_arrays(None)) == 13)
  fs = dm.get_reflection_file_server(filenames=[data_mtz],
    labels=[['I,SIGI,merged', 'IPR,SIGIPR,merged']], array_type='neutron')
  assert(len(fs.get_miller_arrays(None)) == 0)
  dm.set_miller_array_type(data_mtz, 'x_ray')
  fs = dm.get_reflection_file_server(filenames=[data_mtz],
    labels=[['I,SIGI,merged', 'IPR,SIGIPR,merged']], array_type='x_ray')
  assert(len(fs.get_miller_arrays(data_mtz)) == 2)
예제 #4
0
def test_miller_array_datatype():

    data_dir = os.path.dirname(os.path.abspath(__file__))
    data_mtz = os.path.join(data_dir, 'data',
                            'insulin_unmerged_cutted_from_ccp4.mtz')

    dm = DataManager(['miller_array', 'phil'])
    dm.process_miller_array_file(data_mtz)

    # test labels
    labels = [
        'M_ISYM', 'BATCH', 'I,SIGI,merged', 'IPR,SIGIPR,merged',
        'FRACTIONCALC', 'XDET', 'YDET', 'ROT', 'WIDTH', 'LP', 'MPART', 'FLAG',
        'BGPKRATIOS'
    ]
    for label in dm.get_miller_array_labels():
        assert (label in labels)

    assert (len(dm.get_miller_arrays()) == len(dm.get_miller_array_labels()))

    # test access by label
    label = dm.get_miller_array_labels()[3]
    new_label = dm.get_miller_arrays(labels=[label])[0].info().label_string()
    assert (label == new_label)

    # test custom PHIL
    dm.write_phil_file('test.phil',
                       dm.export_phil_scope().as_str(),
                       overwrite=True)
    loaded_phil = libtbx.phil.parse(file_name='test.phil')
    new_dm = DataManager(['miller_array', 'phil'])
    new_dm.load_phil_scope(loaded_phil)
    assert (data_mtz == new_dm.get_default_miller_array_name())
    for label in new_dm.get_miller_array_labels():
        assert (label in labels)

    os.remove('test.phil')

    # test file server
    fs1 = dm.get_reflection_file_server()
    fs2 = dm.get_reflection_file_server([data_mtz, data_mtz])
    assert (2 * len(fs1.miller_arrays) == len(fs2.miller_arrays))
    cs = crystal.symmetry(
        unit_cell=dm.get_miller_arrays()[0].crystal_symmetry().unit_cell(),
        space_group_symbol='P1')
    fs = dm.get_reflection_file_server(crystal_symmetry=cs)
    assert (fs.crystal_symmetry.is_similar_symmetry(cs))
    assert (not fs.crystal_symmetry.is_similar_symmetry(
        dm.get_miller_arrays()[0].crystal_symmetry()))
    fs = dm.get_reflection_file_server(labels=['I,SIGI,merged'])
    assert (len(fs.get_miller_arrays(None)) == 1)
    miller_array = fs.get_amplitudes(None, None, True, None, None)
    assert (
        miller_array.info().label_string() == 'I,as_amplitude_array,merged')

    master_phil_str = '''
include scope iotbx.data_manager.miller_array.miller_array_phil_str
  '''
    master_phil = libtbx.phil.parse(master_phil_str, process_includes=True)
    master_extract = master_phil.extract()
    master_extract.data[0].file_name = data_mtz
    master_extract.data[0].labels = 'IPR,SIGIPR,merged'
    fs = get_reflection_file_server(dm, master_extract)
    assert (len(fs.get_miller_arrays(None)) == 1)
    master_extract.data[0].type = 'neutron'
    fs = get_reflection_file_server(dm, master_extract)
    assert (fs is None)
    fs = get_reflection_file_server(dm, master_extract, datatype='neutron')
    assert (len(fs.get_miller_arrays(None)) == 1)
예제 #5
0
class CCTBXParser(ParserBase):
    def __init__(self,
                 program_class,
                 custom_process_arguments=None,
                 logger=None,
                 *args,
                 **kwargs):
        '''
    '''
        # program name
        self.prog = os.getenv('LIBTBX_DISPATCHER_NAME')
        if (self.prog is None):
            self.prog = sys.argv[0]
        self.prefix = self.prog.split('.')[-1]

        # PHIL filenames
        self.data_filename = self.prefix + '_data.eff'
        self.modified_filename = self.prefix + '_modified.eff'
        self.all_filename = self.prefix + '_all.eff'

        # terminal width
        self.text_width = 79

        # print header
        border = '-' * self.text_width
        description = border + program_class.description + border
        epilog = border + program_class.epilog
        super(CCTBXParser, self).__init__(
            prog=self.prog,
            description=description,
            epilog=epilog,
            formatter_class=argparse.RawDescriptionHelpFormatter,
            *args,
            **kwargs)

        # default values
        self.program_class = program_class
        self.custom_process_arguments = custom_process_arguments
        self.logger = logger
        if (self.logger is None):
            self.logger = logging.getLogger('main')
        self.data_manager = DataManager(datatypes=program_class.datatypes,
                                        logger=self.logger)

        # add PHIL converters if available
        if (len(program_class.phil_converters) > 0):
            iotbx.phil.default_converter_registry = \
              libtbx.phil.extended_converter_registry(
                additional_converters=program_class.phil_converters,
                base_registry=iotbx.phil.default_converter_registry)

        # set up master and working PHIL scopes
        self.master_phil = iotbx.phil.parse(program_class.master_phil_str,
                                            process_includes=True)
        required_output_phil = iotbx.phil.parse(
            ProgramTemplate.output_phil_str)
        self.master_phil.adopt_scope(required_output_phil)
        self.working_phil = None

        self.add_default_options()

    # ---------------------------------------------------------------------------
    def add_default_options(self):
        '''
    '''
        # --show-defaults by itself is set to 0
        # --show-defaults=n sets it to n and it can only be {0, 1, 2, 3}
        self.add_argument(
            '--show-defaults',
            '--show_defaults',
            nargs='?',
            const=0,
            type=int,
            choices=range(0, 4),
            help='show default parameters with expert level (default=0)')

        # --attributes-level by itself is set to 1
        # --attributes-level=n sets it to n and it can only be {1, 2, 3}
        self.add_argument('--attributes-level',
                          '--attributes_level',
                          nargs='?',
                          const=1,
                          type=int,
                          choices=range(0, 4),
                          help='show parameters with attributes (default=0)')

        # --write-data
        # switch for writing only DataManager PHIL parameters
        self.add_argument(
          '--write-data', '--write_data', action='store_true',
          help='write DataManager PHIL parameters to file (%s)' % \
          self.data_filename
        )

        # --write-modified
        # switch for writing only modified PHIL parameters
        self.add_argument(
          '--write-modified', '--write_modified', action='store_true',
          help='write modifed PHIL parameters to file (%s)' % \
          self.modified_filename
        )

        # --write-all
        # switch for writing all PHIL parameters
        self.add_argument(
            '--write-all',
            '--write_all',
            action='store_true',
            help=
            'write all (modified + default + data) PHIL parameters to file (%s)'
            % self.all_filename)

        # --overwrite
        # switch for overwriting files, takes precedence over PHIL definition
        self.add_argument(
            '--overwrite',
            action='store_true',
            default=False,
            help=
            'overwrite files, this overrides the output.overwrite PHIL parameter'
        )

        # --citations will use the default format
        # --citations=<format> will use the specified format
        self.add_argument(
            '--citations',
            nargs='?',
            const='default',
            type=str,
            choices=['default', 'cell', 'iucr'],
            help='show citation(s) for program in different formats')

    # ---------------------------------------------------------------------------
    def parse_args(self, args):
        '''
    '''
        # default behavior with no arguments
        if (len(args) == 0):
            self.print_help()
            self.exit()

        # parse arguments
        self.namespace = super(CCTBXParser, self).parse_args(args)

        # process command-line options
        if (self.namespace.attributes_level is not None):
            if (self.namespace.show_defaults is None):
                self.error(
                    '--attributes-level requires --show-defaults to be set')
        if (self.namespace.show_defaults is not None):
            self.master_phil.show(
                expert_level=self.namespace.show_defaults,
                attributes_level=self.namespace.attributes_level,
                out=self.logger)
            self.exit()
        if (self.namespace.citations is not None):
            self.show_citations()
            self.exit()

        # start program header
        print('Starting %s' % self.prog, file=self.logger)
        print('on %s by %s' % (time.asctime(), getpass.getuser()),
              file=self.logger)
        print('=' * self.text_width, file=self.logger)
        print('', file=self.logger)

        # process files
        if (self.parse_files):
            self.process_files(self.namespace.files)

        # process phil and phil files
        if (self.parse_phil):
            self.process_phil(self.namespace.phil)

        # process directories
        if (self.parse_dir):
            self.process_dir(self.namespace.dir)

        # custom processing of arguments (if available)
        # the function for custom processing of arguments should take a CCTBXParser
        # object as its argument. The function should modify the
        # CCTBXParser.namespace.unknown, CCTBXParser.data_manager,
        # CCTBXParser.working_phil, or other CCTBXParser members.
        # At the end of the function, CCTBXParser.working_phil should have the final
        # libtbx.phil.scope object (not libtbx.phil.scope_extract) for the program
        # A libtbx.phil.scope_extract object can be converted into a
        # libtbx.phil.scope object by
        #    CCTBXParser.master_phil.format(python_object=<scope_extract>)
        if (self.custom_process_arguments is not None):
            self.custom_process_arguments(self)
            assert (isinstance(self.working_phil, libtbx.phil.scope))

        # post processing after all arguments are parsed
        self.post_process()

        # show final PHIL parameters
        self.show_phil_summary()

        return self.namespace

    # ---------------------------------------------------------------------------
    def process_files(self, file_list, message='Processing files:'):
        '''
    Second pass to process files. The first pass already checked that these
    files exist. There may be conditions where the file is deleted in the time
    between the first pass and calling this function.

    Use iotbx.file_reader.any_file to process files.
    Will need updating to work with mmtbx.model.manager class more efficiently
    '''
        print(message, file=self.logger)
        print('-' * self.text_width, file=self.logger)
        print('', file=self.logger)
        printed_something = False

        unused_files = list()

        for filename in file_list:
            a = any_file(filename)
            process_function = 'process_%s_file' % data_manager_type.get(
                a.file_type)
            if (hasattr(self.data_manager, process_function)):
                getattr(self.data_manager, process_function)(filename)
                print('  Found %s, %s' %
                      (data_manager_type[a.file_type], filename),
                      file=self.logger)
                printed_something = True
            else:
                unused_files.append(filename)

        # show unrecognized files
        if (len(unused_files) > 0):
            if (printed_something):
                print('', file=self.logger)
            print('  Files not used by program:', file=self.logger)
            print('  --------------------------', file=self.logger)
            for filename in unused_files:
                print('  %s' % filename, file=self.logger)
            printed_something = True

        # process PHIL files for DataManager scope in order from command-line
        # files are appended and the default is not overridden
        # files from the command-line take precedence
        phil_names = self.data_manager.get_phil_names()
        for name in phil_names:
            phil = self.data_manager.get_phil(name)
            if (hasattr(phil.extract(), 'data_manager')):
                self.data_manager.load_phil_scope(phil)

        if (not printed_something):
            print('  No files found', file=self.logger)

        print('', file=self.logger)

    # ---------------------------------------------------------------------------
    def process_phil(self, phil_list):
        ''''
    Process PHIL arguments
    Also checks PHIL arguments (command line and files) for parameters that
    specify files (.type = path)
    '''
        print('Processing PHIL parameters:', file=self.logger)
        print('-' * self.text_width, file=self.logger)
        print('', file=self.logger)

        printed_something = False

        data_sources = list()
        sources = list()
        unused_phil = list()

        # PHIL files are processed in order from command-line
        if (self.data_manager.has_phils()):
            phil_names = self.data_manager.get_phil_names()
            phil = list()
            print('  Adding PHIL files:', file=self.logger)
            print('  ------------------', file=self.logger)
            for name in phil_names:
                # remove DataManager scope since input files are already loaded
                phil_scope = self.data_manager.get_phil(name)
                for phil_object in phil_scope.objects:
                    if (phil_object.name == 'data_manager'):
                        phil_scope.objects.remove(phil_object)
                phil.append(phil_scope)
                print('    %s' % name, file=self.logger)
            data_sources.extend(phil)
            print('', file=self.logger)
            printed_something = True

        # command-line PHIL arguments override any previous settings and are
        # processed in given order
        def custom_processor(arg):
            unused_phil.append(arg)
            return True

        if (len(phil_list) > 0):
            interpreter = self.master_phil.command_line_argument_interpreter(
                home_scope='')
            print('  Adding command-line PHIL:', file=self.logger)
            print('  -------------------------', file=self.logger)
            for phil in phil_list:
                print('    %s' % phil, file=self.logger)
            print('', file=self.logger)
            printed_something = True
            working = interpreter.process_args(
                phil_list, custom_processor=custom_processor)
            if (len(working) > 0):
                sources.extend(working)
        if (self.namespace.overwrite):  # override overwrite if True
            sources.append(iotbx.phil.parse('output.overwrite=True'))
        if ((len(data_sources) + len(sources)) > 0):
            self.working_phil, more_unused_phil = self.master_phil.fetch(
                sources=data_sources + sources, track_unused_definitions=True)
            unused_phil.extend(more_unused_phil)
        else:
            self.working_phil = self.master_phil

        # show unrecognized parameters and abort
        if (len(unused_phil) > 0):
            print('  Unrecognized PHIL parameters:', file=self.logger)
            print('  -----------------------------', file=self.logger)
            for phil in unused_phil:
                print('    %s' % phil, file=self.logger)
            print('', file=self.logger)
            error_message = 'Some PHIL parameters are not recognized by %s.\n' % \
                            self.prog
            error_message += wordwrap(
                'Please run this program with the --show-defaults option to see what parameters are available.',
                max_chars=self.text_width) + '\n'
            error_message += wordwrap(
                'PHIL parameters in files should be fully specified (e.g. "output.overwrite" instead of just "overwrite")',
                max_chars=self.text_width) + '\n'
            raise Sorry(error_message)

        # process input phil for file/directory defintions and add to DataManager
        # Note: if a PHIL file is input as a PHIL parameter, the contents of the
        # file will NOT be parsed and validated. The PHIL file should be provided
        # as a command-line argument. This is mostly for finding data files
        # defined by PHIL parameters that should be added to the DataManager
        diff_phil = self.master_phil.fetch_diff(self.working_phil)
        paths = self.check_phil_for_paths(diff_phil)
        if (len(paths) > 0):
            files = list()
            dirs = list()
            for path in paths:
                if (path is not None):
                    if (os.path.isfile(path)):
                        files.append(path)
                    elif (os.path.isdir(path)):
                        dirs.append(path)
            if (self.parse_files):
                self.process_files(files,
                                   message='Processing files from PHIL:')
            if (self.parse_dir):
                self.process_dir(dirs,
                                 message='Processing directories from PHIL:')

        if (not printed_something):
            print('  No PHIL parameters found', file=self.logger)
            print('', file=self.logger)

    # ---------------------------------------------------------------------------
    def process_dir(self, dir_list, message='Processing directories:'):
        '''
    '''
        print(message, file=self.logger)
        print('-' * self.text_width, file=self.logger)
        print('', file=self.logger)

    # ---------------------------------------------------------------------------
    def check_phil_for_paths(self, phil_scope):
        '''
    Recursively check PHIL scope if there is a 'path' type.
    Returns the paths (empty list means no paths were found)
    '''
        paths = list()
        if (phil_scope.is_definition):
            if (phil_scope.has_attribute_with_name('type')):
                if (phil_scope.type.phil_type == 'path'):
                    paths.append(phil_scope.extract())
        elif (phil_scope.is_scope):
            for phil_object in phil_scope.objects:
                paths.extend(self.check_phil_for_paths(phil_object))
        return paths

    # ---------------------------------------------------------------------------
    def post_process(self):
        '''
    Post processing of inputs after all arguments are parsed
    '''

        working_phil_extract = self.working_phil.extract()

        # update default model with program pdb interpretation scope
        if (self.data_manager.supports('model')
                and (self.data_manager.get_default_model_name() is not None)):
            self.data_manager.update_pdb_interpretation_for_model(
                self.data_manager.get_default_model_name(),
                working_phil_extract)

        # update default model and data scopes, if necessary
        # see iotbx.data_manager.model.model_phil_str and
        # iotbx.data_manager.miller_array.miller_array_phil_str for PHIL definitions
        if (hasattr(working_phil_extract, 'model')
                and hasattr(working_phil_extract, 'data')):
            update_phil = False
            if (self.data_manager.supports('model')):
                if (isinstance(working_phil_extract.model, list)
                        and (len(working_phil_extract.model) == 1)):
                    if (working_phil_extract.model[0].file_name is None):
                        working_phil_extract.model[0].file_name = self.data_manager.\
                                                                  get_default_model_name()
                        update_phil = True
            if (self.data_manager.supports('miller_array')):
                if (isinstance(working_phil_extract.data, list)
                        and (len(working_phil_extract.data) == 1)):
                    if (working_phil_extract.data[0].file_name is None):
                        working_phil_extract.data[0].file_name = \
                          self.data_manager.get_default_miller_array_name()
                        update_phil = True
            if (update_phil):
                self.working_phil = self.master_phil.format(
                    python_object=working_phil_extract)

    # ---------------------------------------------------------------------------
    def show_phil_summary(self):
        '''
    Show final, modified PHIL parameters after all processing is complete
    Also, write phil scopes based on command-line flags
    '''

        overwrite = (self.namespace.overwrite or \
                     self.working_phil.extract().output.overwrite)

        # check for any remaining unknown arguments
        if (len(self.namespace.unknown) > 0):
            error_message = 'The following arguments are not recognized:\n'
            for value in self.namespace.unknown:
                error_message += '  %s\n' % value
            raise Sorry(error_message)

        # get differences
        try:
            data_diff = self.data_manager.master_phil.fetch_diff(
                self.data_manager.export_phil_scope())
        except RuntimeError as err:
            raise Sorry(err)
        try:
            phil_diff = self.master_phil.fetch_diff(self.working_phil)
        except RuntimeError as err:
            raise Sorry(err)
        data_is_different = (len(data_diff.as_str()) > 0)
        phil_is_different = (len(phil_diff.as_str()) > 0)
        is_different = data_is_different or phil_is_different

        # show final processed phil scope
        print('Final processed PHIL parameters:', file=self.logger)
        print('-' * self.text_width, file=self.logger)
        if (is_different):
            data_diff.show(prefix='  ', out=self.logger)
            phil_diff.show(prefix='  ', out=self.logger)
        else:
            print('  All parameters are set to their defaults',
                  file=self.logger)
        print('', file=self.logger)

        # write scopes if requested
        if (self.namespace.write_data or self.namespace.write_modified
                or self.namespace.write_all):
            print('Writing program PHIL file(s):', file=self.logger)

        # write DataManager scope
        if (self.namespace.write_data):
            if (data_is_different):
                self.data_manager.write_phil_file(
                    self.data_filename,
                    self.data_manager.export_phil_scope().as_str(),
                    overwrite=overwrite)
                print('  Input file PHIL written to %s.' % self.data_filename,
                      file=self.logger)
            else:
                print('  No input file PHIL to write', file=self.logger)

        # write differences
        if (self.namespace.write_modified):
            if (phil_is_different):
                self.data_manager.write_phil_file(self.modified_filename,
                                                  phil_diff.as_str(),
                                                  overwrite=overwrite)
                print('  Modified PHIL parameters written to %s.' %
                      self.modified_filename,
                      file=self.logger)
            else:
                print('  No PHIL modifications to write', file=self.logger)

        # write all parameters (DataManager + Program)
        if (self.namespace.write_all):
            all_phil = self.data_manager.export_phil_scope().as_str()
            all_phil += self.working_phil.as_str(expert_level=3)
            self.data_manager.write_phil_file(self.all_filename,
                                              all_phil,
                                              overwrite=overwrite)
            print('  All PHIL parameters written to %s.' % self.all_filename,
                  file=self.logger)

        print('', file=self.logger)

    # ---------------------------------------------------------------------------
    def show_citations(self):
        # build list of program-specific citations
        program_citations = list()
        if (self.program_class.citations is not None):
            class_citations = citations.master_citation_phil.fetch(
                source=self.program_class.citations).extract()
            for citation in class_citations.citation:
                program_citations.append(citation)
        for article_id in self.program_class.known_article_ids:
            citation = citations.citations_db.get(article_id)
            if (citation is not None):
                program_citations.append(citation)
            else:
                raise Sorry('"%s" not found citations database' % article_id)

        # show program-specific citations and general citation for CCTBX
        if (len(program_citations) > 0):
            print('Citation(s) for %s:' % self.prog, file=self.logger)
            print('-' * self.text_width, file=self.logger)
            print('', file=self.logger)
            for citation in program_citations:
                citations.show_citation(citation,
                                        out=self.logger,
                                        format=self.namespace.citations)
        self.program_class.show_template_citation(
            text_width=self.text_width,
            logger=self.logger,
            citation_format=self.namespace.citations)