示例#1
0
    def calc(self, item):

        struct_or_mol = MontyDecoder().process_decoded(
            item[self.projected_object_name])

        # TODO: will combine these two functions into something more intuitive

        graph = StructureMoleculeComponent._preprocess_input_to_graph(
            struct_or_mol,
            bonding_strategy=self.settings["bonding_strategy"],
            bonding_strategy_kwargs=self.settings["bonding_strategy_kwargs"],
        )

        scene, legend = StructureMoleculeComponent.get_scene_and_legend(
            graph,
            color_scheme=self.settings["color_scheme"],
            color_scale=self.settings["color_scale"],
            radius_strategy=self.settings["radius_strategy"],
            draw_image_atoms=self.settings["draw_image_atoms"],
            bonded_sites_outside_unit_cell=self.
            settings["bonded_sites_outside_unit_cell"],
            hide_incomplete_bonds=self.settings["hide_incomplete_bonds"],
        )

        return {
            "scene": scene.to_json(),
            "legend": legend,
            "settings": self.settings,
            "source": item[self.projected_object_name],
        }
示例#2
0
    def get_graph_data(
        graph: Union[StructureGraph, MoleculeGraph],
        color_scheme="Jmol",
        color_scale=None,
    ):

        nodes = []
        edges = []

        struct_or_mol = StructureMoleculeComponent._get_struct_or_mol(graph)
        site_prop_types = StructureMoleculeComponent._analyze_site_props(
            struct_or_mol)
        colors, _ = StructureMoleculeComponent._get_display_colors_and_legend_for_sites(
            struct_or_mol,
            site_prop_types,
            color_scheme=color_scheme,
            color_scale=color_scale,
        )

        for idx, node in enumerate(graph.graph.nodes()):

            nodes.append({
                "id":
                node,
                "title":
                f"{struct_or_mol[node].species_string} site "
                f"({graph.get_coordination_of_site(idx)} neighbors)",
                "color":
                colors[node][0],
            })

        for u, v, d in graph.graph.edges(data=True):

            edge = {"from": u, "to": v, "arrows": ""}

            to_jimage = d.get("to_jimage", (0, 0, 0))

            # TODO: check these edge weights
            if isinstance(struct_or_mol, Structure):
                dist = struct_or_mol.get_distance(u, v, jimage=to_jimage)
            else:
                dist = struct_or_mol.get_distance(u, v)
            edge["length"] = 50 * dist

            label = f"{dist:.2f} Å distance to site"

            if to_jimage != (0, 0, 0):
                edge["arrows"] = "to"
                label += f" at image vector {to_jimage}"

            if label:
                edge["title"] = label

            #if 'weight' in d:
            #   label += f" {d['weight']}"

            edges.append(edge)

        return {"nodes": nodes, "edges": edges}
def view(molecule_or_structure, **kwargs):
    """View a pymatgen Molecule or Structure object interactively in a
    Jupyter notebook.
    
    Args:
        molecule_or_structure: Molecule or structure to display
        draw_image_atoms (bool):  Show periodic copies of atoms
    """
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")

        # Since the jupyter viewer is meant for quick peaks at the structure the default behaviour should be different
        # ex. draw_image_atoms should be set to false:
        if "draw_image_atoms" not in kwargs:
            kwargs["draw_image_atoms"] = False
        if "bonded_sites_outside_unit_cell" not in kwargs:
            kwargs["bonded_sites_outside_unit_cell"] = False
        if "hide_incomplete_edges" not in kwargs:
            kwargs["hide_incomplete_edges"] = True
        obj_or_scene = molecule_or_structure
        if isinstance(obj_or_scene, CrystalToolkitScene):
            scene = obj_or_scene
        elif hasattr(obj_or_scene, "get_scene"):
            scene = obj_or_scene.get_scene(**kwargs)
        # TODO: next two elif statements are only here until Molecule and Structure have get_scene()
        elif isinstance(obj_or_scene, Structure):
            # TODO Temporary place holder for render structure until structure.get_scene() is implemented
            struct_or_mol = obj_or_scene.copy()
            smc = StructureMoleculeComponent(
                struct_or_mol,
                static=True,
                hide_incomplete_bonds=kwargs['hide_incomplete_edges'],
                draw_image_atoms=kwargs['draw_image_atoms'],
                bonded_sites_outside_unit_cell=kwargs[
                    'bonded_sites_outside_unit_cell'],
            )
            origin = np.sum(obj_or_scene.lattice.matrix, axis=0) / 2.
            scene = smc.initial_graph.get_scene(origin=origin, **kwargs)
        elif isinstance(obj_or_scene, Molecule):
            # TODO Temporary place holder for render molecules
            kwargs.pop('draw_image_atoms')
            kwargs.pop('hide_incomplete_edges')
            kwargs.pop('bonded_sites_outside_unit_cell')
            origin = obj_or_scene.center_of_mass
            struct_or_mol = obj_or_scene.copy()
            smc = StructureMoleculeComponent(struct_or_mol,
                                             static=True,
                                             **kwargs)
            scene = smc.initial_graph.get_scene(origin=origin, **kwargs)
        else:
            raise ValueError(
                "Only Scene objects or objects with get_scene() methods "
                "can be displayed.")
        display_scene(scene)
示例#4
0
def display_struct(structure):
    """
    :param structure: input structure
    """
    smc = StructureMoleculeComponent(structure,
                                     bonded_sites_outside_unit_cell=False,
                                     hide_incomplete_bonds=True)
    display_StructureMoleculeComponent(smc)
示例#5
0
def get_scene_from_structure(self,
                             bonding_strategy="CrystalNN",
                             bonding_strategy_kwargs=None,
                             **kwargs):
    sgraph = SMC._preprocess_input_to_graph(self,
                                            bonding_strategy=bonding_strategy,
                                            bonding_strategy_kwargs=bonding_strategy_kwargs,
                                            )
    return sgraph.get_scene(origin=None, **kwargs)
示例#6
0
    def get_graph_data(graph, display_options):

        color_scheme = display_options.get("color_scheme", "Jmol")

        nodes = []
        edges = []

        struct_or_mol = StructureMoleculeComponent._get_struct_or_mol(graph)
        legend = Legend(struct_or_mol, color_scheme=color_scheme)

        for idx, node in enumerate(graph.graph.nodes()):

            # TODO: fix for disordered
            node_color = legend.get_color(
                struct_or_mol[node].species.elements[0],
                site=struct_or_mol[node])

            nodes.append({
                "id":
                node,
                "title":
                f"{struct_or_mol[node].species_string} site "
                f"({graph.get_coordination_of_site(idx)} neighbors)",
                "color":
                node_color,
            })

        for u, v, d in graph.graph.edges(data=True):

            edge = {"from": u, "to": v, "arrows": ""}

            to_jimage = d.get("to_jimage", (0, 0, 0))

            # TODO: check these edge weights
            if isinstance(struct_or_mol, Structure):
                dist = struct_or_mol.get_distance(u, v, jimage=to_jimage)
            else:
                dist = struct_or_mol.get_distance(u, v)
            edge["length"] = 50 * dist

            if to_jimage != (0, 0, 0):
                edge["arrows"] = "to"
                label = f"{dist:.2f} Å to site at image vector {to_jimage}"
            else:
                label = f"{dist:.2f} Å between sites"

            if label:
                edge["title"] = label

            # if 'weight' in d:
            #   label += f" {d['weight']}"

            edges.append(edge)

        return {"nodes": nodes, "edges": edges}
示例#7
0
def view(struct_or_mol, **kwargs):
    """
    View a Structure or Molecule inside a Jupyter notebook.
    :param struct_or_mol: Structure or Molecule object
    :param kwargs: kwargs to pass to StructureMoleculeComponent
    :return:
    """

    if "crystal_toolkit_app" not in globals():
        _init_viewer()

    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        component = StructureMoleculeComponent(struct_or_mol, **kwargs)

    crystal_toolkit_app.title = struct_or_mol.composition.reduced_formula
    crystal_toolkit_app.layout = html.Div(
        [component.layout(), component.screenshot_layout()]
    )
    crystal_toolkit_viewer.show(crystal_toolkit_app)
示例#8
0
    def update_contents(self, new_store_contents):

        struct = self.from_data(new_store_contents)

        msa = CollinearMagneticStructureAnalyzer(struct, round_magmoms=1)
        if not msa.is_magnetic:
            # TODO: detect magnetic elements (?)
            return html.Div(
                "This structure is not magnetic or does not have "
                "magnetic information associated with it."
            )

        mag_species_and_magmoms = msa.magnetic_species_and_magmoms
        for k, v in mag_species_and_magmoms.items():
            if not isinstance(v, list):
                mag_species_and_magmoms[k] = [v]
        magnetic_atoms = "\n".join(
            [
                f"{sp} ({', '.join([f'{magmom} µB' for magmom in magmoms])})"
                for sp, magmoms in mag_species_and_magmoms.items()
            ]
        )

        magnetization_per_formula_unit = (
            msa.total_magmoms
            / msa.structure.composition.get_reduced_composition_and_factor()[1]
        )

        rows = []
        rows.append(
            (
                html.B("Total magnetization per formula unit"),
                html.Br(),
                f"{magnetization_per_formula_unit:.1f} µB",
            )
        )
        rows.append((html.B("Atoms with local magnetic moments"), html.Br(),
                     magnetic_atoms))

        data_block = html.Div([html.P([html.Span(cell) for cell in row]) for row in rows])

        viewer = StructureMoleculeComponent(
            struct,
            id=self.id("structure"), color_scheme="magmom",
            static=True
        )

        return Columns([
            Column(html.Div([viewer.struct_layout], style={"height": "60vmin"})),
            Column(data_block)
        ])
示例#9
0
        def update_displayed_structure(clickData):

            if not clickData:
                raise PreventUpdate

            task_id = clickData["points"][0]["text"]

            with MPRester(endpoint="https://zola.lbl.gov/rest/v2") as mpr:
                struct = mpr.get_task_data(task_id,
                                           prop="structure")[0]["structure"]

            print(struct)

            viewer = StructureMoleculeComponent(
                struct,
                id=self.id("magnetic_structure"),
                color_scheme="magmom",
                static=True,
            )

            return viewer.struct_layout
示例#10
0
def get_scene(structure):
    """
    :param structure:
    """

    smc = StructureMoleculeComponent(structure,
                                     bonded_sites_outside_unit_cell=False,
                                     hide_incomplete_bonds=False)
    obs = traverse_scene_object(smc.initial_scene_data)

    scene = Scene(
        children=[obs, AmbientLight(color='#FFFFFF', intensity=0.75)])
    c = PerspectiveCamera(position=[10, 10, 10])
    renderer = Renderer(camera=c,
                        background='black',
                        background_opacity=1,
                        scene=scene,
                        controls=[OrbitControls(controlling=c)],
                        width=400,
                        height=400)
    display(renderer)
示例#11
0
        def get_chemenv_analysis(struct, distance_cutoff, angle_cutoff):

            if not struct:
                raise PreventUpdate

            struct = self.from_data(struct)
            kwargs = self.reconstruct_kwargs_from_state(
                callback_context.inputs)
            distance_cutoff = kwargs["distance_cutoff"]
            angle_cutoff = kwargs["angle_cutoff"]

            # TODO: remove these brittle guard statements, figure out more robust way to handle multiple input types
            if isinstance(struct, StructureGraph):
                struct = struct.structure

            def get_valences(struct):
                valences = [
                    getattr(site.specie, "oxi_state", None) for site in struct
                ]
                valences = [v for v in valences if v is not None]
                if len(valences) == len(struct):
                    return valences
                else:
                    return "undefined"

            # decide which indices to present to user
            sga = SpacegroupAnalyzer(struct)
            symm_struct = sga.get_symmetrized_structure()
            inequivalent_indices = [
                indices[0] for indices in symm_struct.equivalent_indices
            ]
            wyckoffs = symm_struct.wyckoff_symbols

            lgf = LocalGeometryFinder()
            lgf.setup_structure(structure=struct)

            se = lgf.compute_structure_environments(
                maximum_distance_factor=distance_cutoff + 0.01,
                only_indices=inequivalent_indices,
                valences=get_valences(struct),
            )
            strategy = SimplestChemenvStrategy(distance_cutoff=distance_cutoff,
                                               angle_cutoff=angle_cutoff)
            lse = LightStructureEnvironments.from_structure_environments(
                strategy=strategy, structure_environments=se)
            all_ce = AllCoordinationGeometries()

            envs = []
            unknown_sites = []

            for index, wyckoff in zip(inequivalent_indices, wyckoffs):

                datalist = {
                    "Site": unicodeify_species(struct[index].species_string),
                    "Wyckoff Label": wyckoff,
                }

                if not lse.neighbors_sets[index]:
                    unknown_sites.append(
                        f"{struct[index].species_string} ({wyckoff})")
                    continue

                # represent the local environment as a molecule
                mol = Molecule.from_sites(
                    [struct[index]] +
                    lse.neighbors_sets[index][0].neighb_sites)
                mol = mol.get_centered_molecule()
                mg = MoleculeGraph.with_empty_graph(molecule=mol)
                for i in range(1, len(mol)):
                    mg.add_edge(0, i)

                view = html.Div(
                    [
                        StructureMoleculeComponent(
                            struct_or_mol=mg,
                            disable_callbacks=True,
                            id=
                            f"{struct.composition.reduced_formula}_site_{index}",
                            scene_settings={
                                "enableZoom": False,
                                "defaultZoom": 0.6
                            },
                        )._sub_layouts["struct"]
                    ],
                    style={
                        "width": "300px",
                        "height": "300px"
                    },
                )

                env = lse.coordination_environments[index]
                co = all_ce.get_geometry_from_mp_symbol(env[0]["ce_symbol"])
                name = co.name
                if co.alternative_names:
                    name += f" (also known as {', '.join(co.alternative_names)})"

                datalist.update({
                    "Environment":
                    name,
                    "IUPAC Symbol":
                    co.IUPAC_symbol_str,
                    get_tooltip(
                        "CSM",
                        "The continuous symmetry measure (CSM) describes the similarity to an "
                        "ideal coordination environment. It can be understood as a 'distance' to "
                        "a shape and ranges from 0 to 100 in which 0 corresponds to a "
                        "coordination environment that is exactly identical to the ideal one. A "
                        "CSM larger than 5.0 already indicates a relatively strong distortion of "
                        "the investigated coordination environment.",
                    ):
                    f"{env[0]['csm']:.2f}",
                    "Interactive View":
                    view,
                })

                envs.append(get_data_list(datalist))

            # TODO: switch to tiles?
            envs_grouped = [envs[i:i + 2] for i in range(0, len(envs), 2)]
            analysis_contents = []
            for env_group in envs_grouped:
                analysis_contents.append(
                    Columns([Column(e, size=6) for e in env_group]))

            if unknown_sites:
                unknown_sites = html.Strong(
                    f"The following sites were not identified: {', '.join(unknown_sites)}. "
                    f"Please try changing the distance or angle cut-offs to identify these sites, "
                    f"or try an alternative algorithm such as LocalEnv.")
            else:
                unknown_sites = html.Span()

            return html.Div(
                [html.Div(analysis_contents),
                 html.Br(), unknown_sites])
示例#12
0
        def retrieve_grain_boundaries(mpid):

            if not mpid or "mpid" not in mpid:
                raise PreventUpdate

            data = None

            with MPRester() as mpr:

                data = mpr.get_gb_data(mpid["mpid"])

            if not data:

                return (
                    "No grain boundary information computed for this crystal structure. "
                    "Grain boundary information has only been computed for elemental ground state "
                    "crystal structures at present.")

            table_data = [{
                "Sigma":
                d["sigma"],
                "Rotation Axis":
                f"{d['rotation_axis']}",
                "Rotation Angle / º":
                f"{d['rotation_angle']:.2f}",
                "Grain Boundary Plane":
                f"({' '.join(map(str, d['gb_plane']))})",
                "Grain Boundary Energy / Jm⁻²":
                f"{d['gb_energy']:.2f}",
            } for d in data]
            df = pd.DataFrame(table_data)

            table = dt.DataTable(
                id=self.id("table"),
                columns=[{
                    "name": i,
                    "id": i
                } for i in df.columns],
                data=df.to_dict("records"),
                style_cell={
                    "minWidth": "0px",
                    "maxWidth": "200px",
                    "whiteSpace": "normal",
                },
                css=[{
                    "selector":
                    ".dash-cell div.dash-cell-value",
                    "rule":
                    "display: inline; white-space: inherit; overflow: inherit; text-overflow: inherit;",
                }],
                sort_action="native",
                sort_mode="multi",
            )

            view = html.Div(
                [
                    StructureMoleculeComponent(
                        data[2]["initial_structure"],
                        id=self.id("struct"),
                        static=True,
                        color_scheme="grain_label",
                    ).struct_layout
                ],
                style={
                    "width": "400px",
                    "height": "400px"
                },
            )

            return Columns([Column(table), Column(view)])
示例#13
0
from pymatgen.core.structure import Structure
from pymatgen.core.lattice import Lattice
from crystal_toolkit.helpers.asymptote import write_asy_file
from crystal_toolkit.components.structure import StructureMoleculeComponent
import os

example_struct = Structure.from_spacegroup(
    "P6_3mc",
    Lattice.hexagonal(3.22, 5.24),
    ["Ga", "N"],
    [[1 / 3, 2 / 3, 0], [1 / 3, 2 / 3, 3 / 8]],
)

smc = StructureMoleculeComponent(example_struct, hide_incomplete_bonds=True)
file_name = "./asy_test/single/GaN.asy"
write_asy_file(smc, file_name)
write_asy_file(smc, "./asy_test/multi/GaN.asy")

example_struct = Structure.from_spacegroup(
    "P6_3mc",
    Lattice.hexagonal(3.22, 5.24),
    ["In", "N"],
    [[1 / 3, 2 / 3, 0], [1 / 3, 2 / 3, 3 / 8]],
)
smc = StructureMoleculeComponent(example_struct, hide_incomplete_bonds=True)
write_asy_file(smc, "./asy_test/multi/InN.asy")
example_struct = Structure.from_spacegroup(
    "P6_3mc",
    Lattice.hexagonal(3.22, 5.24),
    ["Al", "N"],
    [[1 / 3, 2 / 3, 0], [1 / 3, 2 / 3, 3 / 8]],
示例#14
0
def get_combined_scene(bs, extra_scene):
    smc = StructureMoleculeComponent(bs, scene_additions=extra_scene)
    return smc
示例#15
0
        def get_chemenv_analysis(struct, distance_cutoff, angle_cutoff):

            if not struct:
                raise PreventUpdate

            struct = self.from_data(struct)
            distance_cutoff = float(distance_cutoff)
            angle_cutoff = float(angle_cutoff)

            # decide which indices to present to user
            sga = SpacegroupAnalyzer(struct)
            symm_struct = sga.get_symmetrized_structure()
            inequivalent_indices = [
                indices[0] for indices in symm_struct.equivalent_indices
            ]
            wyckoffs = symm_struct.wyckoff_symbols

            lgf = LocalGeometryFinder()
            lgf.setup_structure(structure=struct)

            se = lgf.compute_structure_environments(
                maximum_distance_factor=distance_cutoff + 0.01,
                only_indices=inequivalent_indices,
            )
            strategy = SimplestChemenvStrategy(distance_cutoff=distance_cutoff,
                                               angle_cutoff=angle_cutoff)
            lse = LightStructureEnvironments.from_structure_environments(
                strategy=strategy, structure_environments=se)
            all_ce = AllCoordinationGeometries()

            envs = []
            unknown_sites = []

            for index, wyckoff in zip(inequivalent_indices, wyckoffs):

                datalist = {
                    "Site": struct[index].species_string,
                    "Wyckoff Label": wyckoff,
                }

                if not lse.neighbors_sets[index]:
                    unknown_sites.append(
                        f"{struct[index].species_string} ({wyckoff})")
                    continue

                # represent the local environment as a molecule
                mol = Molecule.from_sites(
                    [struct[index]] +
                    lse.neighbors_sets[index][0].neighb_sites)
                mol = mol.get_centered_molecule()
                mg = MoleculeGraph.with_empty_graph(molecule=mol)
                for i in range(1, len(mol)):
                    mg.add_edge(0, i)

                view = html.Div(
                    [
                        StructureMoleculeComponent(
                            struct_or_mol=mg,
                            static=True,
                            id=
                            f"{struct.composition.reduced_formula}_site_{index}",
                            scene_settings={
                                "enableZoom": False,
                                "defaultZoom": 0.6
                            },
                        ).all_layouts["struct"]
                    ],
                    style={
                        "width": "300px",
                        "height": "300px"
                    },
                )

                env = lse.coordination_environments[index]
                co = all_ce.get_geometry_from_mp_symbol(env[0]["ce_symbol"])
                name = co.name
                if co.alternative_names:
                    name += f" (also known as {', '.join(co.alternative_names)})"

                datalist.update({
                    "Environment":
                    name,
                    "IUPAC Symbol":
                    co.IUPAC_symbol_str,
                    get_tooltip(
                        "CSM",
                        '"Continuous Symmetry Measure," a measure of how symmetrical a '
                        "local environment is from most symmetrical at 0% to least "
                        "symmetrical at 100%",
                    ):
                    f"{env[0]['csm']:.2f}%",
                    "Interactive View":
                    view,
                })

                envs.append(get_data_list(datalist))

            # TODO: switch to tiles?
            envs_grouped = [envs[i:i + 2] for i in range(0, len(envs), 2)]
            analysis_contents = []
            for env_group in envs_grouped:
                analysis_contents.append(
                    Columns([Column(e, size=6) for e in env_group]))

            if unknown_sites:
                unknown_sites = html.Strong(
                    f"The following sites were not identified: {', '.join(unknown_sites)}. "
                    f"Please try changing the distance or angle cut-offs to identify these sites."
                )
            else:
                unknown_sites = html.Span()

            return html.Div(
                [html.Div(analysis_contents),
                 html.Br(), unknown_sites])