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
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)
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
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
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)
def get_content(file): datablocks, error_count, error_messages = parse(file) return datablocks
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'