def read_atoms(self, fileobject):
        """
        read the data from a quantum espresso input file
        """
        fileformat = "qeinp-qetools"
        (cell, rel_positions,
         numbers) = get_structure_tuple(fileobject, fileformat)

        self.pos = rel_positions  # reduced coords
        self.cell = np.array(cell)
        self.rec = rec_lat(self.cell) * 2 * np.pi

        self.natoms = len(rel_positions)  # number of atoms
        self.atom_numbers = numbers  # atom number for each atom (integer)

        atom_names = []
        for n in numbers:
            for atom_name, atom_number in atomic_numbers.items():
                if atom_number == n:
                    atom_names.append(atom_name)

        self.atom_types = atom_names  # atom type for each atom (string)

        self.chemical_symbols = [
            chemical_symbols[number] for number in numbers
        ]
        self.chemical_formula = self.get_chemical_formula()
Exemplo n.º 2
0
def process_structure():
    """Example view to process a crystal structure."""

    # check if the post request has the file part,
    # otherwise redirect to first page
    if "structurefile" not in flask.request.files:
        # This will redirect the user to the selection page,
        # that is called `input_data` in tools-barebone
        return flask.redirect(flask.url_for("input_data"))

    # Get structure, file format, file content, and form data
    # (needed for additional information, e.g. cell in the case
    # of a XYZ file)
    structurefile = flask.request.files["structurefile"]
    fileformat = flask.request.form.get("fileformat", "unknown")
    filecontent = structurefile.read().decode("utf-8")
    fileobject = io.StringIO(str(filecontent))
    form_data = dict(flask.request.form)

    # Use
    try:
        structure_tuple = get_structure_tuple(fileobject,
                                              fileformat,
                                              extra_data=form_data)
    except UnknownFormatError:
        # You can use the flask.flash functionality to send a message
        # back to the structure selection page; this
        # will be shown in a red box on the top
        flask.flash("Unknown format '{}'".format(fileformat))
        return flask.redirect(flask.url_for("input_data"))
    except Exception:
        # Let's deal properly with any exception, to avoid to get a 500 error.
        # Feel free to do better error management here,
        # or to pass additional information via flask.flash
        flask.flash("I tried my best, but I wasn't able to load your "
                    "file in format '{}'...".format(fileformat))
        return flask.redirect(flask.url_for("input_data"))
    # If we are here, the file was retrieved.
    # It will contain a tuple of length three, with:
    # - the 3x3 unit cell (in angstrom)
    # - a Nx3 list of atomic coordinates (in angstrom)
    # - a list of integer atomic numbers of length N

    # As an example, we just create a string representation of the JSON
    # and send it back to the user, to be rendered in a form
    data_for_template = {
        "structure_json":
        json.dumps(
            {
                "cell": structure_tuple[0],
                "atoms": structure_tuple[1],
                "numbers": structure_tuple[2],
            },
            indent=2,
            sort_keys=True,
        )
    }
    return flask.render_template("user_templates/tools_example.html",
                                 **data_for_template)
Exemplo n.º 3
0
def parse_structure(filecontent, fileformat, extra_data=None):
    """Parse a structure given the file content and the file format.

    Possibly pass also the extra data from the form if needed
    (e.g. for the cell of a XYZ file).
    """
    fileobject = io.StringIO(str(filecontent))
    try:
        structure_tuple = get_structure_tuple(fileobject,
                                              fileformat,
                                              extra_data=extra_data)
    except UnknownFormatError:
        raise FlaskRedirectException("Unknown format '{}'".format(fileformat))
    # Bubble up the exception, will be managed by the level above

    return structure_tuple
Exemplo n.º 4
0
    def process_structure():
        """Template view, should be replaced when extending tools-barebone."""
        global exception_traceback

        if flask.request.method == "POST":
            # check if the post request has the file part
            if "structurefile" not in flask.request.files:
                return flask.redirect(flask.url_for("input_data"))
            structurefile = flask.request.files["structurefile"]
            fileformat = flask.request.form.get("fileformat", "unknown")
            filecontent = structurefile.read().decode("utf-8")
            fileobject = io.StringIO(str(filecontent))
            form_data = dict(flask.request.form)
            try:
                structure_tuple = get_structure_tuple(fileobject,
                                                      fileformat,
                                                      extra_data=form_data)
            except UnknownFormatError:
                flask.flash("Unknown format '{}'".format(fileformat))
                return flask.redirect(flask.url_for("input_data"))
            except Exception:
                flask.flash("I tried my best, but I wasn't able to load your "
                            "file in format '{}'...".format(fileformat))
                return flask.redirect(flask.url_for("input_data"))
            data_for_template = {
                "structure_json":
                json.dumps(
                    {
                        "cell": structure_tuple[0],
                        "atoms": structure_tuple[1],
                        "numbers": structure_tuple[2],
                    },
                    indent=2,
                    sort_keys=True,
                ),
                "exception_traceback":
                exception_traceback,
            }
            return flask.render_template("tools_barebone.html",
                                         **data_for_template)

        # GET request
        flask.flash(
            "This is tools-barebone. You need to define a blueprint in a compute submodule. Import error traceback:\n{}"
            .format(exception_traceback))
        return flask.redirect(flask.url_for("input_data"))
Exemplo n.º 5
0
def process_structure_core(  # pylint: disable=too-many-locals,too-many-statements,too-many-arguments
    filecontent,
    fileformat,
    seekpath_module,
    call_source="",
    logger=None,
    flask_request=None,
):
    """
    The main function that generates the data to be sent back to the view.

    :param filecontent: The file content (string)
    :param fileformat: The file format (string), among the accepted formats
    :param seekpath_module: the seekpath module. The reason for passing it
         is that, when running in debug mode, you want to get the local
         seekpath rather than the installed one.
    :param call_source: a string identifying the source (i.e., who called
       this function). This is a string, mainly for logging reasons.
    :param logger: if not None, should be a valid logger, that is used
       to output useful log messages.
    :param flask_request: if logger is not None, pass also the flask.request
       object to help in logging.

    :return: this function calls directly flask methods and returns flask
        objects

    :raise: FlaskRedirectException if there is an error that requires
        to redirect the the main selection page. The Exception message
        is the message to be flashed via Flask (or in general shown to
        the user).
    """
    start_time = time.time()
    fileobject = io.StringIO(str(filecontent))
    form_data = dict(flask_request.form)
    try:
        structure_tuple = get_structure_tuple(fileobject,
                                              fileformat,
                                              extra_data=form_data)
    except UnknownFormatError:
        logme(
            logger,
            filecontent,
            fileformat,
            flask_request,
            call_source,
            reason="unknownformat",
            extra={
                "form_data": form_data,
            },
        )
        raise FlaskRedirectException("Unknown format '{}'".format(fileformat))
    except Exception:
        # There was an exception...
        logme(
            logger,
            filecontent,
            fileformat,
            flask_request,
            call_source,
            reason="exception",
            extra={
                "traceback": traceback.format_exc(),
                "form_data": form_data,
            },
        )
        raise FlaskRedirectException(
            "I tried my best, but I wasn't able to load your "
            "file in format '{}'...".format(fileformat))

    if len(structure_tuple[1]) > MAX_NUMBER_OF_ATOMS:
        ## Structure too big
        logme(
            logger,
            filecontent,
            fileformat,
            flask_request,
            call_source,
            reason="toolarge",
            extra={
                "number_of_atoms": len(structure_tuple[1]),
                "form_data": form_data,
            },
        )
        raise FlaskRedirectException(
            "Sorry, this online visualizer is limited to {} atoms "
            "in the input cell, while your structure has {} atoms."
            "".format(MAX_NUMBER_OF_ATOMS, len(structure_tuple[1])))

    # Log the content in case of valid structure
    logme(
        logger,
        filecontent,
        fileformat,
        flask_request,
        call_source,
        reason="OK",
        extra={
            "number_of_atoms": len(structure_tuple[1]),
            "form_data": form_data,
        },
    )

    try:
        in_json_data = {
            "cell": structure_tuple[0],
            "scaled_coords": structure_tuple[1],
            "atomic_numbers": structure_tuple[2],
        }

        out_json_data, path_results = get_json_for_visualizer(
            in_json_data["cell"],
            in_json_data["scaled_coords"],
            in_json_data["atomic_numbers"],
            seekpath_module=seekpath_module,
        )

        raw_code_dict = copy.copy(out_json_data)
        for k in list(raw_code_dict.keys()):
            if k.startswith("explicit_"):
                raw_code_dict.pop(k)
            if k == "segments":
                raw_code_dict.pop(k)
        raw_code_dict.pop("faces_data")
        raw_code_dict["primitive_lattice"] = path_results[
            "primitive_lattice"].tolist()
        raw_code_dict["primitive_positions"] = path_results[
            "primitive_positions"].tolist()
        inputstructure_positions_cartesian = np.dot(
            np.array(in_json_data["scaled_coords"]),
            np.array(in_json_data["cell"]),
        ).tolist()
        primitive_positions_cartesian = np.dot(
            np.array(path_results["primitive_positions"]),
            np.array(path_results["primitive_lattice"]),
        ).tolist()
        primitive_positions_cartesian_refolded = np.dot(
            np.array(path_results["primitive_positions"]) % 1.0,
            np.array(path_results["primitive_lattice"]),
        ).tolist()
        raw_code_dict[
            "primitive_positions_cartesian"] = primitive_positions_cartesian

        # raw_code['primitive_types'] = path_results['primitive_types']
        primitive_symbols = [
            chemical_symbols[num] for num in path_results["primitive_types"]
        ]
        raw_code_dict["primitive_symbols"] = primitive_symbols

        raw_code = json.dumps(raw_code_dict, indent=2)
        ## I manually escape it to then add <br> and pass it to a filter with
        ## |safe. I have to 'unicode' it otherwise it keeps escaping also the
        ## next replaces
        raw_code = (str(jinja2.escape(raw_code)).replace("\n", "<br>").replace(
            " ", "&nbsp;"))

        kpoints = [[
            k,
            out_json_data["kpoints"][k][0],
            out_json_data["kpoints"][k][1],
            out_json_data["kpoints"][k][2],
        ] for k in sorted(out_json_data["kpoints"])]
        kpoints_rel = [[
            k,
            out_json_data["kpoints_rel"][k][0],
            out_json_data["kpoints_rel"][k][1],
            out_json_data["kpoints_rel"][k][2],
        ] for k in sorted(out_json_data["kpoints_rel"])]

        inputstructure_cell_vectors = [[
            idx, coords[0], coords[1], coords[2]
        ] for idx, coords in enumerate(in_json_data["cell"], start=1)]
        inputstructure_symbols = [
            chemical_symbols[num] for num in in_json_data["atomic_numbers"]
        ]
        inputstructure_atoms_scaled = [[
            label, coords[0], coords[1], coords[2]
        ] for label, coords in zip(inputstructure_symbols,
                                   in_json_data["scaled_coords"])]
        inputstructure_atoms_cartesian = [[
            label, coords[0], coords[1], coords[2]
        ] for label, coords in zip(inputstructure_symbols,
                                   inputstructure_positions_cartesian)]

        direct_vectors = [[idx, coords[0], coords[1], coords[2]]
                          for idx, coords in enumerate(
                              path_results["primitive_lattice"], start=1)]

        reciprocal_primitive_vectors = [[
            idx, coords[0], coords[1], coords[2]
        ] for idx, coords in enumerate(
            path_results["reciprocal_primitive_lattice"], start=1)]

        atoms_scaled = [
            [label, coords[0], coords[1], coords[2]] for label, coords in zip(
                primitive_symbols, path_results["primitive_positions"])
        ]

        atoms_cartesian = [
            [label, coords[0], coords[1], coords[2]] for label, coords in zip(
                primitive_symbols, primitive_positions_cartesian)
        ]

        # Create extetically-nice looking path, with dashes and pipes
        suggested_path = []
        if path_results["path"]:
            suggested_path.append(path_results["path"][0][0])
            suggested_path.append("-")
            suggested_path.append(path_results["path"][0][1])
            last = path_results["path"][0][1]
        for p1, p2 in path_results["path"][1:]:
            if p1 != last:
                suggested_path.append("|")
                suggested_path.append(p1)
            suggested_path.append("-")
            suggested_path.append(p2)
            last = p2

        primitive_lattice = path_results["primitive_lattice"]
        xsfstructure = []
        xsfstructure.append("CRYSTAL")
        xsfstructure.append("PRIMVEC")
        for vector in primitive_lattice:
            xsfstructure.append("{} {} {}".format(vector[0], vector[1],
                                                  vector[2]))
        xsfstructure.append("PRIMCOORD")
        xsfstructure.append("{} 1".format(
            len(primitive_positions_cartesian_refolded)))
        for atom_num, pos in zip(path_results["primitive_types"],
                                 primitive_positions_cartesian_refolded):
            xsfstructure.append("{} {} {} {}".format(atom_num, pos[0], pos[1],
                                                     pos[2]))
        xsfstructure = "\n".join(xsfstructure)

        compute_time = time.time() - start_time
    except Exception:
        logme(
            logger,
            filecontent,
            fileformat,
            flask_request,
            call_source,
            reason="codeexception",
            extra={
                "traceback": traceback.extract_stack(),
                "form_data": form_data,
            },
        )
        raise

    qe_pw = (str(jinja2.escape(get_qe_pw(raw_code_dict,
                                         out_json_data))).replace(
                                             "\n",
                                             "<br>").replace(" ", "&nbsp;"))
    qe_matdyn = (str(jinja2.escape(get_qe_matdyn(
        raw_code_dict, out_json_data))).replace("\n",
                                                "<br>").replace(" ", "&nbsp;"))
    cp2k = (str(jinja2.escape(get_cp2k(raw_code_dict))).replace(
        "\n", "<br>").replace(" ", "&nbsp;"))
    crystal = (str(jinja2.escape(get_crystal(raw_code_dict))).replace(
        "\n", "<br>").replace(" ", "&nbsp;"))
    vasp_gga = (str(jinja2.escape(get_vasp_gga(raw_code_dict))).replace(
        "\n", "<br>").replace(" ", "&nbsp;"))
    vasp_gen = (str(jinja2.escape(get_vasp_gen(out_json_data))).replace(
        "\n", "<br>").replace(" ", "&nbsp;"))

    return dict(
        jsondata=json.dumps(out_json_data),
        volume_ratio_prim=int(round(path_results["volume_original_wrt_prim"])),
        raw_code=raw_code,
        kpoints=kpoints,
        kpoints_rel=kpoints_rel,
        bravais_lattice=path_results["bravais_lattice"],
        bravais_lattice_extended=path_results["bravais_lattice_extended"],
        spacegroup_number=path_results["spacegroup_number"],
        spacegroup_international=path_results["spacegroup_international"],
        direct_vectors=direct_vectors,
        inputstructure_cell_vectors=inputstructure_cell_vectors,
        inputstructure_atoms_scaled=inputstructure_atoms_scaled,
        inputstructure_atoms_cartesian=inputstructure_atoms_cartesian,
        atoms_scaled=atoms_scaled,
        with_without_time_reversal=(
            "with" if path_results["has_inversion_symmetry"] else "without"),
        atoms_cartesian=atoms_cartesian,
        reciprocal_primitive_vectors=reciprocal_primitive_vectors,
        suggested_path=suggested_path,
        qe_pw=qe_pw,
        qe_matdyn=qe_matdyn,
        cp2k=cp2k,
        crystal=crystal,
        vasp_gga=vasp_gga,
        vasp_gen=vasp_gen,
        compute_time=compute_time,
        seekpath_version=seekpath_module.__version__,
        spglib_version=spglib.__version__,
        tools_barebone_version=get_tools_barebone_version(),
        tools_seekpath_version=__version__,
        time_reversal_note=(time_reversal_note
                            if path_results["augmented_path"] else ""),
        xsfstructure=xsfstructure,
    )