Ejemplo n.º 1
0
def parse_cif_pycodcif(fileobj):
    """Parse a CIF file using pycodcif CIF parser"""
    blocks = []
    if not isinstance(fileobj, basestring):
        fileobj = fileobj.name

    try:
        from pycodcif import parse
    except ImportError:
        raise ImportError(
            'parse_cif_pycodcif requires pycodcif ' +
            '(http://wiki.crystallography.net/cod-tools/pycodcif/)')

    data, _, _ = parse(fileobj)

    for datablock in data:
        tags = datablock['values']
        for tag in tags.keys():
            values = [convert_value(x) for x in tags[tag]]
            if len(values) == 1:
                tags[tag] = values[0]
            else:
                tags[tag] = values
        blocks.append((datablock['name'], tags))

    return blocks
Ejemplo n.º 2
0
def validate():
    if flask.request.method == 'POST':
        file = flask.request.files['cif']
        filename = ("testfile_" + str(random.randint(1, 1000000)) + ".cif")
        file.save(filename)
        try:
            conf = {}
            for option in flask.request.form.items():
                conf[option[0]] = 1
            data, err_count, err_msg = pycodcif.parse(filename, conf)
            data[0]['err_count'] = err_count
            data[0]['err_msg'] = err_msg
        except Exception as e:
            e = str(e).replace("\n", " ")
            error = 'Failed to parse the cif file: ' + e
            data = [{
                'err_msg': error,
            }]
        try:
            os.remove(filename)
        except Exception as e:
            e = str(e).replace("\n", " ")
            error = 'Error: ' + e
            data = [{
                'err_msg': error,
            }]
        return json.dumps(data)
Ejemplo n.º 3
0
def validate_example():
    """
    API Route for some example files for validation.

    Parameters: Accepts the name of structure.
    Function: Validates the file using PyCodCIF.
    Response: A JSON Object containing the key 'status' which may hold the values 'valid' or 'error', and the key 'message'.
    """

    filename = 'code/webservice/static/' + flask.request.form.get("name")
    response = {'status': '', 'message': []}
    try:
        conf = {}
        for option in flask.request.form.items():
            conf[option[0]] = 1
        data, err_count, err_msg = pycodcif.parse(filename, conf)
        response['status'] = 'valid'
        response['message'].append(err_msg)
    except Exception as e:
        # Pycodcif could not parse the file
        e = str(e).replace("\n", " ")
        error = 'Failed to parse the cif file: ' + e
        response['status'] = 'error'
        response['message'].append(error)
    return json.dumps(response)  # Return JSON
Ejemplo n.º 4
0
def validate():
    """
    API Route for validation

    Parameters: Accepts a file with key 'cif' via POST
    Function: Validates the file using PyCodCIF
    Response: A JSON Object containing the key 'status' which may hold the values 'valid' or 'error', and the key 'message'.
    """

    file = flask.request.files['cif']  # The file must have the key 'cif'
    filename = ("testfile_" + str(random.randint(1, 1000000)) + ".cif"
                )  # Generate Filename
    file.save(filename)  # Save the file, PyCodCIF reads only saved files
    response = {'status': '', 'message': []}
    try:
        conf = {}
        for option in flask.request.form.items():
            conf[option[0]] = 1
        data, err_count, err_msg = pycodcif.parse(filename, conf)
        response['status'] = 'valid'
        response['message'].append(err_msg)
    except Exception as e:
        # Pycodcif could not parse the file
        e = str(e).replace("\n", " ")
        error = 'Failed to parse the cif file: ' + e
        response['status'] = 'error'
        response['message'].append(error)
    try:
        # Remove saved file
        os.remove(filename)
    except Exception as e:
        e = str(e).replace("\n", " ")
        response['message'].append(error)
    return json.dumps(response)  # Return JSON
Ejemplo n.º 5
0
def parse_cif_pycodcif(fileobj) -> Iterator[CIFBlock]:
    """Parse a CIF file using pycodcif CIF parser."""
    if not isinstance(fileobj, str):
        fileobj = fileobj.name

    try:
        from pycodcif import parse
    except ImportError:
        raise ImportError(
            'parse_cif_pycodcif requires pycodcif ' +
            '(http://wiki.crystallography.net/cod-tools/pycodcif/)')

    data, _, _ = parse(fileobj)

    for datablock in data:
        tags = datablock['values']
        for tag in tags.keys():
            values = [convert_value(x) for x in tags[tag]]
            if len(values) == 1:
                tags[tag] = values[0]
            else:
                tags[tag] = values
        yield CIFBlock(datablock['name'], tags)
Ejemplo n.º 6
0
 def get_content(file):
     datablocks, error_count, error_messages = parse(file)
     return datablocks
Ejemplo n.º 7
0
def cif_to_ase(cif_string):
    """
    Naive pycodcif usage
    FIXME:
    as soon as pycodcif supports CIFs as strings,
    the tempfile below should be removed

    Args:
        cif_string: (str) WYSIWYG

    Returns:
        ASE atoms (object) *or* None
        None *or* error (str)
    """
    with tempfile.NamedTemporaryFile(suffix='.cif') as tmp:
        tmp.write(cif_string)
        tmp.flush()

        try:
            parsed_cif = parse(tmp.name)[0][0]['values']
        except:
            return None, 'Invalid or non-standard CIF'

        if '_symmetry_int_tables_number' in parsed_cif:
            try:
                spacegroup = int(parsed_cif['_symmetry_int_tables_number'][0])
            except ValueError:
                return None, 'Invalid space group info in CIF'

        elif '_symmetry_space_group_name_h-m' in parsed_cif:
            spacegroup = parsed_cif['_symmetry_space_group_name_h-m'][0].strip(
            )  # NB ase is very strict to whitespaces in HM symbols, so this is the most frequent error source
            if not spacegroup:
                return None, 'Empty space group info in CIF'

        else:
            return None, 'Absent space group info in CIF'

        try:
            cellpar = (float(parsed_cif['_cell_length_a'][0].split('(')[0]),
                       float(parsed_cif['_cell_length_b'][0].split('(')[0]),
                       float(parsed_cif['_cell_length_c'][0].split('(')[0]),
                       float(parsed_cif['_cell_angle_alpha'][0].split('(')[0]),
                       float(parsed_cif['_cell_angle_beta'][0].split('(')[0]),
                       float(parsed_cif['_cell_angle_gamma'][0].split('(')[0]))
            basis = np.transpose(
                np.array([[
                    char.split('(')[0]
                    for char in parsed_cif['_atom_site_fract_x']
                ],
                          [
                              char.split('(')[0]
                              for char in parsed_cif['_atom_site_fract_y']
                          ],
                          [
                              char.split('(')[0]
                              for char in parsed_cif['_atom_site_fract_z']
                          ]]).astype(np.float))
            occupancies = [
                float(occ.split('(')[0])
                for occ in parsed_cif.get('_atom_site_occupancy', [])
            ]
        except:
            return None, 'Unexpected non-numerical values occured in CIF'

    symbols = parsed_cif.get('_atom_site_type_symbol')
    if not symbols:
        symbols = parsed_cif.get('_atom_site_label')
        if not symbols:
            return None, 'Cannot find atomic positions in CIF'
        symbols = [
            char.encode('ascii').translate(None, ".0123456789")
            for char in symbols
        ]

    occ_data = None
    if occupancies and any([occ != 1 for occ in occupancies]):
        basis = basis.tolist()
        partial_pos, occ_data = {}, {}
        for n in range(len(occupancies) - 1, -1, -1):
            if occupancies[n] != 1:
                disordered_pos = basis.pop(n)
                disordered_el = symbols.pop(n)
                partial_pos.setdefault(tuple(disordered_pos),
                                       {})[disordered_el] = occupancies[n]

        for xyz, occs in partial_pos.items():
            index = len(symbols)
            symbols.append(sorted(occs.keys())[0])
            basis.append(xyz)
            occ_data[index] = occs

    atom_data = []
    for n, xyz in enumerate(basis):
        atom_data.append(Atom(symbols[n], tuple(xyz), tag=n))

    try:
        return crystal(
            atom_data,
            spacegroup=spacegroup,
            cellpar=cellpar,
            primitive_cell=True,
            onduplicates='error',
            info=dict(disordered=occ_data) if occ_data else {}), None
    except:
        return None, 'Unrecognized sites or invalid site symmetry in CIF'