Example #1
0
def main():
    """
    Main logic to find lowest energy conformation of the functional groups
    through an evolutionary.

    """

    info("Welcome to confswitch; finding your lowest energy conformers")
    info("Using fapswitch version {}".format(fapswitch.__version__))

    # Name for a the single structure
    job_name = options.get('job_name')

    # Load it
    input_structure = load_structure(job_name)
    # Structure is ready!

    # Begin processing
    info("Structure attachment sites: "
         "{}".format(list(input_structure.attachments)))
    info("Structure attachment multiplicities: "
         "{}".format(
             dict((key, len(val))
                  for key, val in input_structure.attachments.items())))

    # Functional group library is self initialising
    info("Groups in library: {}".format(functional_groups.group_list))

    # Only use the cif backend here
    backends = [CifFileBackend()]

    # Optimise each custom string passed to fapswitch
    custom_strings = options.get('custom_strings')
    site_strings = re.findall(r'\[(.*?)\]', custom_strings)
    debug("Site replacement options strings: {}".format(site_strings))
    for site_string in site_strings:
        # These should be [email protected]_group2@site2
        # with optional %angle
        site_list = []
        manual_angles = []
        for site in [x for x in site_string.split('.') if x]:
            site_id, functionalisation = site.split('@')
            if '%' in functionalisation:
                functionalisation, manual = functionalisation.split('%')
            else:
                manual = None
            site_list.append([site_id, functionalisation])
            manual_angles.append(manual)

        debug(str(site_list))
        debug(str(manual_angles))

        optimise_conformation(input_structure, site_list, backends=backends)
Example #2
0
def main():
    """
    Initialise everything needed to get the daemon running and start it up.

    """

    info("Welcome to fapswitchd; the daemon interface to fapswitch")
    info("Using fapswitch version {}".format(fapswitch.__version__))

    # Name for a the single structure
    job_name = options.get('job_name')

    # Load it
    input_structure = load_structure(job_name)
    # Structure is ready!

    # Begin processing
    info("Structure attachment sites: "
         "{}".format(list(input_structure.attachments)))
    info("Structure attachment multiplicities :"
         "{}".format(
             dict((key, len(val))
                  for key, val in input_structure.attachments.items())))

    # Functional group library is self initialising
    info("Groups in library: {}".format(functional_groups.group_list))

    #Define some backends for where to send the structures
    backends = []
    backend_options = options.gettuple('backends')

    rotations = options.getint('rotations')
    info("Will rotate each group a maximum of {} times.".format(rotations))

    if 'sqlite' in backend_options:
        # Initialise and add the database writer
        debug("Initialising the sqlite backend")
        try:
            from fapswitch.backend.sql import AlchemyBackend
            backend = AlchemyBackend(job_name)
            backend.populate_groups(functional_groups)
            backends.append(backend)
        except ImportError:
            error("SQLAlchemy not installed; sql backend unavailable")
        # done

    if 'file' in backend_options:
        # Just dumps to a named file
        debug("Initialising cif file writer backend")
        from fapswitch.backend.cif_file import CifFileBackend
        backends.append(CifFileBackend())

    # Make the program die if the daemon is called unsuccessfully
    if fapswitch_deamon(input_structure,
                        backends=backends,
                        rotations=rotations):
        info("Daemon completed successfully")
    else:
        error("Daemon did not complete successfully; check output")
Example #3
0
        distance = distance + pow(p - q, 2);
    };

}
else
{
    distance = 0;

    for(i=0; i<3; i++)
    {
        p = c_cob(i);
        q = c_coa(i);
        distance = distance + pow(p - q, 2);
    };
};

return_val = sqrt(distance);
    """
    return weave.inline(code, ['c_coa', 'f_coa', 'c_cob', 'f_cob', 'box'],
                        type_converters=converters.blitz,
                        support_code='#include <math.h>')


# Make an importable tester that picks up values from the global
# options set

_test_method = options.get('collision_method')
_test_scale = options.getfloat('collision_scale')

test_collision = make_collision_tester(_test_method, _test_scale)
Example #4
0
    def handle_request(self):
        """Generate a random structure and return the rendered page."""

        debug("Arguments: {}".format(self.request.arguments))

        max_trials = 20
        top_50_groups = [
            "Me", "Ph", "Cl", "OMe", "OH", "Et", "OEt", "F", "Br", "NO2",
            "NH2", "CN", "COOEt", "COMe", "COOH", "Bnz", "COOMe", "iPr",
            "pTol", "4ClPh", "tBu", "4OMePh", "CF3", "COPh", "Pr", "NMe2",
            "Bu", "OBnz", "4NO2Ph", "OAc", "4FPh", "I", "4BrPh", "2ClPh",
            "All", "COH", "SMe", "CONH2", "NPh", "24DClPh", "CHex", "Morph",
            "HCO", "3ClPh", "oTol", "2Fur", "iBu", "NCOMe"
        ]
        small_groups = ["F", "Cl", "Me", "NH2", "OH", "CN"]
        # Possible options:
        # replace_only: tuple of sites to replace
        # groups_only: only use specific groups
        # max_different: restrict simultaneous types of groups

        # This is new every time and keeps all the information
        # we need specific to the web version
        backends = [WebStoreBackend()]
        failed = ""

        if 'mof-choice' in self.request.arguments:
            # Selected a specific MOF
            chosen_structure = self.get_argument('mof-choice')
            base_structure = get_structure(chosen_structure)
            replace_list = []
            for site in available_structures[chosen_structure]:
                group = self.get_argument(site, None)
                if group is None or 'None' in group:
                    continue
                elif 'Random' in group:
                    replace_list.append([random.choice(top_50_groups), site])
                else:
                    replace_list.append([group, site])

            # Now make the MOF
            status = site_replace(base_structure,
                                  replace_list=replace_list,
                                  backends=backends)
            if not status:
                # couldn't make it so just use clean structure
                failed = ".".join("{}@{}".format(x[0], x[1])
                                  for x in replace_list)
                site_replace(base_structure,
                             replace_list=[],
                             backends=backends)
        else:
            # Completely random
            chosen_structure = random.choice(list(available_structures))
            # Make sure we have functionalisation sites
            while len(available_structures[chosen_structure]) == 0:
                chosen_structure = random.choice(list(available_structures))
            # Here's the actual structure
            base_structure = get_structure(chosen_structure)

            # Use several combinations to try to get something functionalised
            trial_number = 0
            while trial_number < max_trials:
                if trial_number < max_trials / 4.0:
                    debug("Trial all groups: {}".format(trial_number))
                    status = random_combination_replace(
                        structure=base_structure,
                        backends=backends,
                        max_different=2)
                elif trial_number < 2.0 * max_trials / 4.0:
                    debug("Trial max one group: {}".format(trial_number))
                    status = random_combination_replace(
                        structure=base_structure,
                        backends=backends,
                        max_different=1)
                elif trial_number < 3.0 * max_trials / 4.0:
                    debug("Trial top 50: {}".format(trial_number))
                    status = random_combination_replace(
                        structure=base_structure,
                        backends=backends,
                        groups_only=top_50_groups,
                        max_different=2)
                else:
                    debug("Trial small groups: {}".format(trial_number))
                    status = random_combination_replace(
                        structure=base_structure,
                        backends=backends,
                        groups_only=small_groups,
                        max_different=1)

                # If functionalisation attempted
                if status:
                    if backends[0].cifs[-1]['functions']:
                        # it was successful; done here
                        break
                else:
                    # only increment if we actually tried to add groups
                    trial_number += 1
            else:
                site_replace(base_structure,
                             replace_list=[],
                             backends=backends)
                failed = "{} random combinations".format(max_trials)

        # Should always have a structure, even if it is clean; but failed will
        # be True for that
        cif_info = backends[0].cifs[-1]
        # MEPO compatibility if all groups are okay
        if all(functional_groups[function[0]].mepo_compatible
               for function in cif_info['functions']):
            mepo_compatible = "Yes"
        else:
            mepo_compatible = "No"

        collision_tester = options.get('collision_method')
        collision_cutoff = options.getfloat('collision_scale')

        if cif_info['ligands'] is None:
            ligands = []
        else:
            ligands = cif_info['ligands']

        if ligands:
            sa_score = max(ligand.sa_score for ligand in ligands)
        else:
            sa_score = 0.0

        processed_ligands = make_ligands(ligands)

        extra_info = """<h4>Hypothetical functionalised MOF</h4>
        <p>Functional groups have been added using the crystal
        symmetry. A collision detection routine with a {} radius
        at {:.2f} was used to carry out the functionalisation.
        Note that although atoms may appear close, the bonding
        connectivity defined in the cif file will be correct.</p>
        """.format(collision_tester, collision_cutoff)

        # These references are always required
        local_references = [
            references['Kadantsev2013'], references['Ertl2009'],
            references['Chung2014']
        ]

        # Find all the references and add them too
        for reference in re.findall(r'\[(.*?)\]', extra_info):
            local_references.append(references[reference])

        # Raw HTML anchors. Ugly.
        extra_info = re.sub(
            r'\[(.*?)\]',  # non-greedy(?) find in square brackets
            r'[<a href="#\1">\1</a>]',  # replace raw html
            extra_info)

        page = templates.load('random.html').generate(
            mepo_compatible=mepo_compatible,
            references=local_references,
            functional_groups=functional_groups,
            extra_info=extra_info,
            sa_score=sa_score,
            processed_ligands=processed_ligands,
            available_structures=available_structures,
            failed=failed,
            **cif_info)
        self.write(page)
Example #5
0
def main():
    """
    Simple application that will read options and run the substitution
    for an input structure.

    """

    info("Welcome to cliswitch; the command line interface to fapswitch")
    info("Using fapswitch version {}".format(fapswitch.__version__))

    # Name for a the single structure
    job_name = options.get('job_name')

    # Load it
    input_structure = load_structure(job_name)
    # Structure is ready!

    # Begin processing
    info("Structure attachment sites: "
         "{}".format(list(input_structure.attachments)))
    info("Structure attachment multiplicities: "
         "{}".format(dict((key, len(val)) for key, val in
                          input_structure.attachments.items())))

    # Will use selected sites if specified, otherwise use all
    replace_only = options.gettuple('replace_only')
    if replace_only == ():
        replace_only = None

    # Functional group library is self initialising
    info("Groups in library: {}".format(functional_groups.group_list))

    #Define some backends for where to send the structures
    backends = []
    backend_options = options.gettuple('backends')

    if 'sqlite' in backend_options:
        # Initialise and add the database writer
        debug("Initialising the sqlite backend")
        try:
            from fapswitch.backend.sql import AlchemyBackend
            backend = AlchemyBackend(job_name)
            backend.populate_groups(functional_groups)
            backends.append(backend)
        except ImportError:
            error("SQLAlchemy not installed; sql backend unavailable")
        # done

    if 'file' in backend_options:
        # Just dumps to a named file
        debug("Initialising cif file writer backend")
        from fapswitch.backend.cif_file import CifFileBackend
        backends.append(CifFileBackend())

    ##
    # User defined, single-shot functionalisations
    ##

    rotations = options.getint('rotations')
    info("Will rotate each group a maximum of {} times.".format(rotations))

    custom_strings = options.get('custom_strings')
    # Pattern matching same as in the daemon
    # freeform strings are in braces {}, no spaces
    freeform_strings = re.findall('{(.*?)}', custom_strings)
    debug("Freeform option strings: {}".format(freeform_strings))
    for freeform_string in freeform_strings:
        freeform_replace(input_structure, custom=freeform_string,
                         backends=backends, rotations=rotations)

    # site replacements in square brackets [], no spaces
    site_strings = re.findall(r'\[(.*?)\]', custom_strings)
    debug("Site replacement options strings: {}".format(site_strings))
    for site_string in site_strings:
        # These should be [email protected]_group2@site2
        # with optional %angle
        site_list = []
        manual_angles = []
        for site in [x for x in site_string.split('.') if x]:
            site_id, functionalisation = site.split('@')
            if '%' in functionalisation:
                functionalisation, manual = functionalisation.split('%')
            else:
                manual = None
            site_list.append([site_id, functionalisation])
            manual_angles.append(manual)

        debug(str(site_list))
        debug(str(manual_angles))

        site_replace(input_structure, site_list, backends=backends,
                     rotations=rotations, manual_angles=manual_angles)

    ##
    # Full systematic replacement of everything start here
    ##

    # Only use these functional groups for replacements
    replace_groups = options.gettuple('replace_groups')
    if replace_groups == ():
        replace_groups = None

    max_different = options.getint('max_different')

    prob_unfunc = options.getfloat('unfunctionalised_probability')

    # Do absolutely every combination (might take a while)
    if options.getbool('replace_all_sites'):
        all_combinations_replace(input_structure,
                                 replace_only=replace_only,
                                 groups_only=replace_groups,
                                 max_different=max_different,
                                 backends=backends,
                                 rotations=rotations)

    # group@site randomisations
    random_count = options.getint('site_random_count')
    successful_randoms = 0
    while successful_randoms < random_count:
        #function returns true if structure is generated
        if random_combination_replace(input_structure,
                                      replace_only=replace_only,
                                      groups_only=replace_groups,
                                      max_different=max_different,
                                      prob_unfunc=prob_unfunc,
                                      backends=backends,
                                      rotations=rotations):
            successful_randoms += 1
            info("Generated %i of %i site random structures" %
                 (successful_randoms, random_count))

    # fully freeform randomisations
    random_count = options.getint('full_random_count')
    successful_randoms = 0
    while successful_randoms < random_count:
        #function returns true if structure is generated
        if freeform_replace(input_structure,
                            replace_only=replace_only,
                            groups_only=replace_groups,
                            max_different=max_different,
                            prob_unfunc=prob_unfunc,
                            backends=backends,
                            rotations=rotations):
            successful_randoms += 1
            info("Generated %i of %i fully random structures" %
                 (successful_randoms, random_count))
Example #6
0
def load_structure(name):
    """
    Load a structure from a pickle or generate a new one as required.
    Returns an initialised structure. Caches loaded structure on disk.

    """

    info("Structure version {}.{}".format(*DOT_FAPSWITCH_VERSION))
    pickle_file = "__{}.fapswitch".format(name)
    loaded = False
    if path.exists(pickle_file):
        info("Existing structure found: {}; loading...".format(pickle_file))
        #TODO(tdaff): deal with errors
        try:
            with open(pickle_file, 'rb') as p_structure:
                structure = pickle.load(p_structure)
            # Negative versions ensure that very old caches will be removed
            if not hasattr(structure, 'fapswitch_version'):
                structure.fapswitch_version = (-1, -1)
            # Need to make sure it is still valid
            if structure.fapswitch_version[0] < DOT_FAPSWITCH_VERSION[0]:
                error("Old dot-fapswitch detected, re-initialising")
                loaded = False
            elif structure.fapswitch_version[1] < DOT_FAPSWITCH_VERSION[1]:
                warning(
                    "Cached file {} may be out of date".format(pickle_file))
                loaded = True
            else:
                debug("Finished loading")
                loaded = True
        except EOFError:
            warning("Corrupt pickle; re-initialising")
            loaded = False

    if not loaded:
        info("Initialising a new structure. This may take some time.")
        structure = Structure(name)
        structure.from_cif('{}.cif'.format(name))

        # Ensure that atoms in the structure are properly typed
        structure.gen_factional_positions()
        bonding_src = options.get('connectivity')
        if bonding_src == 'file':
            # Rudimentary checks for poor structures
            if not hasattr(structure, 'bonds'):
                error("No bonding in input structure, will probably fail")
            elif len(structure.bonds) == 0:
                error("Zero bonds found, will fail")
            elif not hasattr(structure.atoms[0], 'uff_type'):
                warning("Atoms not properly typed, expect errors")
            else:
                info("Bonding from input file used")
        elif bonding_src == 'bondsonly':
            info("Generating atom types from cif bonding")
            structure.gen_types_from_bonds()
        elif bonding_src == 'openbabel':
            info("Generating topology with Open Babel")
            structure.gen_babel_uff_properties()

        # A couple of structure checks
        structure.check_close_contacts()
        structure.bond_length_check()

        # Initialise the sites after bonds are perceived
        structure.gen_attachment_sites()
        structure.gen_normals()

        # Cache the results
        info("Dumping cache of structure to {}".format(pickle_file))
        structure.fapswitch_version = DOT_FAPSWITCH_VERSION
        with open(pickle_file, 'wb') as p_structure:
            pickle.dump(structure, p_structure, protocol=-1)

    return structure
Example #7
0
 def __init__(self):
     self.hash_filenames = options.get('hash_filenames').lower()