def estimate_parameters(self, dist_factor_min, dist_factor_max, symmetry_measure_type='csm_wcs_ctwcc'):
        only_symbols = [self.initial_environment_symbol, self.expected_final_environment_symbol]
        # Set up the local geometry finder
        lgf = LocalGeometryFinder()
        lgf.setup_parameters(structure_refinement=lgf.STRUCTURE_REFINEMENT_NONE)
        # Get the StructureEnvironments
        fake_valences = [-1] * (self.coordination_geometry.coordination_number + 1)
        fake_valences[0] = 1
        # Get the StructureEnvironments for the structure with dist_factor_min
        struct = self.get_structure(morphing_factor=dist_factor_min)
        lgf.setup_structure(structure=struct)
        se = lgf.compute_structure_environments(only_indices=[0], valences=fake_valences,
                                                only_symbols=only_symbols)
        csm_info = se.get_csms(isite=0,
                               mp_symbol=self.initial_environment_symbol)
        if len(csm_info) == 0:
            raise ValueError('No csm found for {}'.format(self.initial_environment_symbol))
        csm_info.sort(key=lambda x: x['other_symmetry_measures'][symmetry_measure_type])
        csm_initial_min_dist = csm_info[0]['other_symmetry_measures'][symmetry_measure_type]

        csm_info = se.get_csms(isite=0,
                               mp_symbol=self.expected_final_environment_symbol)
        if len(csm_info) == 0:
            raise ValueError('No csm found for {}'.format(self.initial_environment_symbol))
        csm_info.sort(key=lambda x: x['other_symmetry_measures'][symmetry_measure_type])

        csm_final = csm_info[0]['other_symmetry_measures'][symmetry_measure_type]
        if not np.isclose(csm_final, 0.0, rtol=0.0, atol=1e-10):
            raise ValueError('Final coordination is not perfect !')
        # Get the StructureEnvironments for the structure with dist_factor_max
        struct = self.get_structure(morphing_factor=dist_factor_max)
        lgf.setup_structure(structure=struct)
        se = lgf.compute_structure_environments(only_indices=[0], valences=fake_valences,
                                                only_symbols=only_symbols)
        csm_info = se.get_csms(isite=0,
                               mp_symbol=self.initial_environment_symbol)
        if len(csm_info) == 0:
            raise ValueError('No csm found for {}'.format(self.initial_environment_symbol))
        csm_info.sort(key=lambda x: x['other_symmetry_measures'][symmetry_measure_type])
        csm_initial_max_dist = csm_info[0]['other_symmetry_measures'][symmetry_measure_type]

        csm_info = se.get_csms(isite=0,
                               mp_symbol=self.expected_final_environment_symbol)
        if len(csm_info) == 0:
            raise ValueError('No csm found for {}'.format(self.initial_environment_symbol))
        csm_info.sort(key=lambda x: x['other_symmetry_measures'][symmetry_measure_type])

        csm_final = csm_info[0]['other_symmetry_measures'][symmetry_measure_type]
        if not np.isclose(csm_final, 0.0, rtol=0.0, atol=1e-10):
            raise ValueError('Final coordination is not perfect !')

        return {'delta_csm_min': csm_initial_min_dist, 'self_weight_max_csm': csm_initial_max_dist}
Example #2
0
def analyse_local_coord_env(atoms=None, ):
    """
    """
    #| - analyse_local_coord_env
    out_dict = dict()

    Ir_indices = []
    for i, s in enumerate(atoms.get_chemical_symbols()):
        if s == "Ir":
            Ir_indices.append(i)

    struct = AseAtomsAdaptor.get_structure(atoms)

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

    se = lgf.compute_structure_environments(maximum_distance_factor=1.41,
                                            only_cations=False)

    strategy = MultiWeightsChemenvStrategy.stats_article_weights_parameters()

    lse = LightStructureEnvironments.from_structure_environments(
        strategy=strategy, structure_environments=se)

    isite = 0
    cor_env = []
    coor_env_dict = dict()
    for isite in Ir_indices:
        c_env = lse.coordination_environments[isite]
        coor_env_dict[isite] = c_env
        cor_env += [c_env[0]['ce_symbol']]

    out_dict["coor_env_dict"] = coor_env_dict

    return (out_dict)
    def estimate_parameters(self, dist_factor_min, dist_factor_max, symmetry_measure_type="csm_wcs_ctwcc"):
        only_symbols = [self.initial_environment_symbol, self.expected_final_environment_symbol]
        # Set up the local geometry finder
        lgf = LocalGeometryFinder()
        lgf.setup_parameters(structure_refinement=lgf.STRUCTURE_REFINEMENT_NONE)
        # Get the StructureEnvironments
        fake_valences = [-1] * (self.coordination_geometry.coordination_number + 1)
        fake_valences[0] = 1
        # Get the StructureEnvironments for the structure with dist_factor_min
        struct = self.get_structure(morphing_factor=dist_factor_min)
        lgf.setup_structure(structure=struct)
        se = lgf.compute_structure_environments(only_indices=[0], valences=fake_valences, only_symbols=only_symbols)
        csm_info = se.get_csms(isite=0, mp_symbol=self.initial_environment_symbol)
        if len(csm_info) == 0:
            raise ValueError(f"No csm found for {self.initial_environment_symbol}")
        csm_info.sort(key=lambda x: x["other_symmetry_measures"][symmetry_measure_type])
        csm_initial_min_dist = csm_info[0]["other_symmetry_measures"][symmetry_measure_type]

        csm_info = se.get_csms(isite=0, mp_symbol=self.expected_final_environment_symbol)
        if len(csm_info) == 0:
            raise ValueError(f"No csm found for {self.initial_environment_symbol}")
        csm_info.sort(key=lambda x: x["other_symmetry_measures"][symmetry_measure_type])

        csm_final = csm_info[0]["other_symmetry_measures"][symmetry_measure_type]
        if not np.isclose(csm_final, 0.0, rtol=0.0, atol=1e-10):
            raise ValueError("Final coordination is not perfect !")
        # Get the StructureEnvironments for the structure with dist_factor_max
        struct = self.get_structure(morphing_factor=dist_factor_max)
        lgf.setup_structure(structure=struct)
        se = lgf.compute_structure_environments(only_indices=[0], valences=fake_valences, only_symbols=only_symbols)
        csm_info = se.get_csms(isite=0, mp_symbol=self.initial_environment_symbol)
        if len(csm_info) == 0:
            raise ValueError(f"No csm found for {self.initial_environment_symbol}")
        csm_info.sort(key=lambda x: x["other_symmetry_measures"][symmetry_measure_type])
        csm_initial_max_dist = csm_info[0]["other_symmetry_measures"][symmetry_measure_type]

        csm_info = se.get_csms(isite=0, mp_symbol=self.expected_final_environment_symbol)
        if len(csm_info) == 0:
            raise ValueError(f"No csm found for {self.initial_environment_symbol}")
        csm_info.sort(key=lambda x: x["other_symmetry_measures"][symmetry_measure_type])

        csm_final = csm_info[0]["other_symmetry_measures"][symmetry_measure_type]
        if not np.isclose(csm_final, 0.0, rtol=0.0, atol=1e-10):
            raise ValueError("Final coordination is not perfect !")

        return {"delta_csm_min": csm_initial_min_dist, "self_weight_max_csm": csm_initial_max_dist}
    def figure_fractions(self, weights_options, morphing_factors=None):
        if morphing_factors is None:
            morphing_factors = np.linspace(1.0, 2.0, 21)
        # Set up the local geometry finder
        lgf = LocalGeometryFinder()
        lgf.setup_parameters(structure_refinement=lgf.STRUCTURE_REFINEMENT_NONE)
        # Set up the weights for the MultiWeights strategy
        weights = self.get_weights(weights_options)
        # Set up the strategy
        strat = MultiWeightsChemenvStrategy(dist_ang_area_weight=weights['DistAngArea'],
                                            self_csm_weight=weights['SelfCSM'],
                                            delta_csm_weight=weights['DeltaCSM'],
                                            cn_bias_weight=weights['CNBias'],
                                            angle_weight=weights['Angle'],
                                            normalized_angle_distance_weight=weights['NormalizedAngDist'])
        fake_valences = [-1] * (self.coordination_geometry.coordination_number + 1)
        fake_valences[0] = 1
        fractions_initial_environment = np.zeros_like(morphing_factors)
        fractions_final_environment = np.zeros_like(morphing_factors)
        for ii, morphing_factor in enumerate(morphing_factors):
            print(ii)
            struct = self.get_structure(morphing_factor=morphing_factor)
            print(struct)
            # Get the StructureEnvironments
            lgf.setup_structure(structure=struct)
            se = lgf.compute_structure_environments(only_indices=[0], valences=fake_valences)
            strat.set_structure_environments(structure_environments=se)
            result = strat.get_site_coordination_environments_fractions(site=se.structure[0], isite=0,
                                                                        return_strategy_dict_info=True,
                                                                        return_all=True)
            for res in result:
                if res['ce_symbol'] == self.initial_environment_symbol:
                    fractions_initial_environment[ii] = res['ce_fraction']
                elif res['ce_symbol'] == self.expected_final_environment_symbol:
                    fractions_final_environment[ii] = res['ce_fraction']

        fig_width_cm = 8.25
        fig_height_cm = 7.0
        fig_width = fig_width_cm / 2.54
        fig_height = fig_height_cm / 2.54

        fig = plt.figure(num=1, figsize=(fig_width, fig_height))
        subplot = fig.add_subplot(111)

        subplot.plot(morphing_factors, fractions_initial_environment, 'b-',
                     label='{}'.format(self.initial_environment_symbol),
                     linewidth=1.5)
        subplot.plot(morphing_factors, fractions_final_environment, 'g--',
                     label='{}'.format(self.expected_final_environment_symbol), linewidth=1.5)

        plt.legend(fontsize=8.0, loc=7)
        plt.show()
    def setUp(self):
        with open("mp-7000.json", "r") as f:
            dict_lse = json.load(f)
        lse = LightStructureEnvironments.from_dict(dict_lse)
        struct = lse.structure
        bva = BVAnalyzer()
        valences = bva.get_valences(structure=struct)
        lgf = LocalGeometryFinder()
        lgf.setup_structure(structure=struct)
        se = lgf.compute_structure_environments(maximum_distance_factor=1.41, only_cations=False, valences=valences)
        strategy = MultiWeightsChemenvStrategy.stats_article_weights_parameters()
        self.lse = LightStructureEnvironments.from_structure_environments(strategy=strategy, structure_environments=se)

        with open("mp-5634.json", "r") as f:
            dict_lse2 = json.load(f)
        self.lse2 = LightStructureEnvironments.from_dict(dict_lse2)
Example #6
0
def getSimplestChemenvStrategy(struct):
    # Setup the local geometry finder
    lgf = LocalGeometryFinder()
    lgf.setup_parameters(centering_type='centroid',
                         include_central_site_in_centroid=True)

    #you can also save the logging to a file, just remove the comment

    #     logging.basicConfig(#filename='chemenv_structure_environments.log',
    #                         format='%(levelname)s:%(module)s:%(funcName)s:%(message)s',
    #                         level=logging.DEBUG)
    lgf.setup_structure(structure=struct)
    se = lgf.compute_structure_environments(maximum_distance_factor=1.41,
                                            only_cations=False)
    strategy = SimplestChemenvStrategy(distance_cutoff=1.4, angle_cutoff=0.3)
    lse = LightStructureEnvironments.from_structure_environments(
        strategy=strategy, structure_environments=se)
    return lse.coordination_environments
Example #7
0
allcg = AllCoordinationGeometries()

lgf = LocalGeometryFinder()
logging.basicConfig(format="%(levelname)s:%(module)s:%(funcName)s:%(message)s",
                    level="DEBUG")

mp_symbol = "DD:20"
coordination = 20
myindices = [
    8, 12, 11, 0, 14, 10, 13, 6, 18, 1, 9, 17, 3, 19, 5, 7, 15, 2, 16, 4
]
cg = allcg.get_geometry_from_mp_symbol(mp_symbol=mp_symbol)
lgf.allcg = AllCoordinationGeometries(only_symbols=[mp_symbol])
lgf.setup_test_perfect_environment(
    mp_symbol,
    randomness=False,
    indices=myindices,
    random_translation="NONE",
    random_rotation="NONE",
    random_scale="NONE",
)
se = lgf.compute_structure_environments(
    only_indices=[0],
    maximum_distance_factor=1.01 * cg.distfactor_max,
    min_cn=cg.coordination_number,
    max_cn=cg.coordination_number,
    only_symbols=[mp_symbol],
)

print(se.ce_list[0][20][0])
Example #8
0
class CoordinationGeometryFinderTest(PymatgenTest):
    def setUp(self):
        self.lgf = LocalGeometryFinder()
        self.lgf.setup_parameters(
            centering_type="standard",
            structure_refinement=self.lgf.STRUCTURE_REFINEMENT_NONE,
        )

    #     self.strategies = [SimplestChemenvStrategy(), SimpleAbundanceChemenvStrategy()]

    def test_abstract_geometry(self):
        cg_ts3 = self.lgf.allcg["TS:3"]
        cg_tet = self.lgf.allcg["T:4"]
        abstract_geom = AbstractGeometry.from_cg(cg=cg_ts3,
                                                 centering_type="central_site")
        self.assertArrayAlmostEqual(abstract_geom.centre, [0.0, 0.0, 0.0])
        abstract_geom = AbstractGeometry.from_cg(cg=cg_ts3,
                                                 centering_type="centroid")
        self.assertArrayAlmostEqual(abstract_geom.centre,
                                    [0.0, 0.0, 0.33333333333])
        with self.assertRaises(ValueError) as cm:
            AbstractGeometry.from_cg(
                cg=cg_ts3,
                centering_type="central_site",
                include_central_site_in_centroid=True,
            )
        self.assertEqual(
            str(cm.exception),
            "The center is the central site, no calculation of the centroid, "
            "variable include_central_site_in_centroid should be set to False",
        )
        abstract_geom = AbstractGeometry.from_cg(
            cg=cg_ts3,
            centering_type="centroid",
            include_central_site_in_centroid=True)
        self.assertArrayAlmostEqual(abstract_geom.centre, [0.0, 0.0, 0.25])

        # WHY ARE WE TESTING STRINGS????
        # self.assertEqual(abstract_geom.__str__(),
        #                  '\nAbstract Geometry with 3 points :\n'
        #                  '  [-1.    0.   -0.25]\n'
        #                  '  [ 1.    0.   -0.25]\n'
        #                  '  [ 0.   0.   0.75]\n'
        #                  'Points are referenced to the centroid (calculated with the central site) :\n'
        #                  '  [ 0.   0.   0.25]\n')

        symm_dict = symmetry_measure([[0.0, 0.0, 0.0]], [1.1, 2.2, 3.3])
        self.assertAlmostEqual(symm_dict["symmetry_measure"], 0.0)
        self.assertEqual(symm_dict["scaling_factor"], None)
        self.assertEqual(symm_dict["rotation_matrix"], None)

        tio2_struct = self.get_structure("TiO2")

        envs = self.lgf.compute_coordination_environments(
            structure=tio2_struct, indices=[0])
        self.assertAlmostEqual(envs[0][0]["csm"], 1.5309987846957258)
        self.assertAlmostEqual(envs[0][0]["ce_fraction"], 1.0)
        self.assertEqual(envs[0][0]["ce_symbol"], "O:6")
        self.assertEqual(sorted(envs[0][0]["permutation"]),
                         sorted([0, 4, 1, 5, 2, 3]))

        self.lgf.setup_random_structure(coordination=5)
        self.assertEqual(len(self.lgf.structure), 6)

        self.lgf.setup_random_indices_local_geometry(coordination=5)
        self.assertEqual(self.lgf.icentral_site, 0)
        self.assertEqual(len(self.lgf.indices), 5)

        self.lgf.setup_ordered_indices_local_geometry(coordination=5)
        self.assertEqual(self.lgf.icentral_site, 0)
        self.assertEqual(self.lgf.indices, list(range(1, 6)))

        self.lgf.setup_explicit_indices_local_geometry(
            explicit_indices=[3, 5, 2, 0, 1, 4])
        self.assertEqual(self.lgf.icentral_site, 0)
        self.assertEqual(self.lgf.indices, [4, 6, 3, 1, 2, 5])

        LiFePO4_struct = self.get_structure("LiFePO4")
        isite = 10
        envs_LiFePO4 = self.lgf.compute_coordination_environments(
            structure=LiFePO4_struct, indices=[isite])
        self.assertAlmostEqual(envs_LiFePO4[isite][0]["csm"], 0.140355832317)
        nbs_coords = [
            np.array([6.16700437, -4.55194317, -5.89031356]),
            np.array([4.71588167, -4.54248093, -3.75553856]),
            np.array([6.88012571, -5.79877503, -3.73177541]),
            np.array([6.90041188, -3.32797839, -3.71812416]),
        ]
        self.lgf.setup_structure(LiFePO4_struct)
        self.lgf.setup_local_geometry(isite, coords=nbs_coords)

        perfect_tet = AbstractGeometry.from_cg(
            cg=cg_tet,
            centering_type="centroid",
            include_central_site_in_centroid=False)
        points_perfect_tet = perfect_tet.points_wcs_ctwcc()
        res = self.lgf.coordination_geometry_symmetry_measures_fallback_random(
            coordination_geometry=cg_tet,
            NRANDOM=5,
            points_perfect=points_perfect_tet)
        (
            permutations_symmetry_measures,
            permutations,
            algos,
            local2perfect_maps,
            perfect2local_maps,
        ) = res
        for perm_csm_dict in permutations_symmetry_measures:
            self.assertAlmostEqual(perm_csm_dict["symmetry_measure"],
                                   0.140355832317)

    #
    # def _strategy_test(self, strategy):
    #     files = []
    #     for (dirpath, dirnames, filenames) in os.walk(json_files_dir):
    #         files.extend(filenames)
    #         break
    #
    #     for ifile, json_file in enumerate(files):
    #         with self.subTest(json_file=json_file):
    #             f = open("{}/{}".format(json_files_dir, json_file), 'r')
    #             dd = json.load(f)
    #             f.close()
    #
    #             atom_indices = dd['atom_indices']
    #             expected_geoms = dd['expected_geoms']
    #
    #             struct = Structure.from_dict(dd['structure'])
    #
    #             struct = self.lgf.setup_structure(struct)
    #             se = self.lgf.compute_structure_environments_detailed_voronoi(only_indices=atom_indices,
    #                                                                           maximum_distance_factor=1.5)
    #
    #             #All strategies should get the correct environment with their default parameters
    #             strategy.set_structure_environments(se)
    #             for ienv, isite in enumerate(atom_indices):
    #                 ce = strategy.get_site_coordination_environment(struct[isite])
    #                 try:
    #                     coord_env = ce[0]
    #                 except TypeError:
    #                     coord_env = ce
    #                 #Check that the environment found is the expected one
    #                 self.assertEqual(coord_env, expected_geoms[ienv])
    #
    # def test_simplest_chemenv_strategy(self):
    #     strategy = SimplestChemenvStrategy()
    #     self._strategy_test(strategy)
    #
    # def test_simple_abundance_chemenv_strategy(self):
    #     strategy = SimpleAbundanceChemenvStrategy()
    #     self._strategy_test(strategy)

    def test_perfect_environments(self):
        allcg = AllCoordinationGeometries()
        indices_CN = {
            1: [0],
            2: [1, 0],
            3: [1, 0, 2],
            4: [2, 0, 3, 1],
            5: [2, 3, 1, 0, 4],
            6: [0, 2, 3, 1, 5, 4],
            7: [2, 6, 0, 3, 4, 5, 1],
            8: [1, 2, 6, 3, 7, 0, 4, 5],
            9: [5, 2, 6, 0, 4, 7, 3, 8, 1],
            10: [8, 5, 6, 3, 0, 7, 2, 4, 9, 1],
            11: [7, 6, 4, 1, 2, 5, 0, 8, 9, 10, 3],
            12: [5, 8, 9, 0, 3, 1, 4, 2, 6, 11, 10, 7],
            13: [4, 11, 5, 12, 1, 2, 8, 3, 0, 6, 9, 7, 10],
            20: [
                8, 12, 11, 0, 14, 10, 13, 6, 18, 1, 9, 17, 3, 19, 5, 7, 15, 2,
                16, 4
            ],
        }

        for coordination in range(1, 21):
            for mp_symbol in allcg.get_implemented_geometries(
                    coordination=coordination, returned="mp_symbol"):
                cg = allcg.get_geometry_from_mp_symbol(mp_symbol=mp_symbol)
                self.lgf.allcg = AllCoordinationGeometries(
                    only_symbols=[mp_symbol])
                self.lgf.setup_test_perfect_environment(
                    mp_symbol,
                    randomness=False,
                    indices=indices_CN[coordination],
                    random_translation="NONE",
                    random_rotation="NONE",
                    random_scale="NONE",
                )
                se = self.lgf.compute_structure_environments(
                    only_indices=[0],
                    maximum_distance_factor=1.01 * cg.distfactor_max,
                    min_cn=cg.coordination_number,
                    max_cn=cg.coordination_number,
                    only_symbols=[mp_symbol],
                )
                self.assertAlmostEqual(
                    se.get_csm(0, mp_symbol)["symmetry_measure"],
                    0.0,
                    delta=1e-8,
                    msg=
                    f"Failed to get perfect environment with mp_symbol {mp_symbol}",
                )

    def test_disable_hints(self):
        allcg = AllCoordinationGeometries()
        mp_symbol = "SH:13"
        mp_symbols = ["SH:13", "HP:12"]
        cg = allcg.get_geometry_from_mp_symbol(mp_symbol=mp_symbol)
        mypoints = cg.points
        mypoints[-1] = [0.9 * cc for cc in mypoints[-1]]
        self.lgf.allcg = AllCoordinationGeometries(only_symbols=[mp_symbol])
        self.lgf.setup_test_perfect_environment(
            mp_symbol,
            randomness=False,
            indices=[4, 11, 5, 12, 1, 2, 8, 3, 0, 6, 9, 7, 10],
            random_translation="NONE",
            random_rotation="NONE",
            random_scale="NONE",
            points=mypoints,
        )
        se_nohints = self.lgf.compute_structure_environments(
            only_indices=[0],
            maximum_distance_factor=1.02 * cg.distfactor_max,
            min_cn=12,
            max_cn=13,
            only_symbols=mp_symbols,
            get_from_hints=False,
        )
        se_hints = self.lgf.compute_structure_environments(
            only_indices=[0],
            maximum_distance_factor=1.02 * cg.distfactor_max,
            min_cn=12,
            max_cn=13,
            only_symbols=mp_symbols,
            get_from_hints=True,
        )
        with self.assertRaises(KeyError):
            abc = se_nohints.ce_list[0][12]
            abc.minimum_geometries()
        self.assertAlmostEqual(se_hints.ce_list[0][13][0],
                               se_nohints.ce_list[0][13][0])
        self.assertTrue(
            set(se_nohints.ce_list[0].keys()).issubset(
                set(se_hints.ce_list[0].keys())))
Example #9
0
def compute_environments(chemenv_configuration):
    string_sources = {
        'cif': {
            'string': 'a Cif file',
            'regexp': '.*\.cif$'
        },
        'mp': {
            'string': 'the Materials Project database',
            'regexp': 'mp-[0-9]+$'
        }
    }
    questions = {'c': 'cif'}
    if chemenv_configuration.has_materials_project_access:
        questions['m'] = 'mp'
    lgf = LocalGeometryFinder()
    lgf.setup_parameters()
    allcg = AllCoordinationGeometries()
    strategy_class = strategies_class_lookup[
        chemenv_configuration.package_options['default_strategy']['strategy']]
    #TODO: Add the possibility to change the parameters and save them in the chemenv_configuration
    default_strategy = strategy_class()
    default_strategy.setup_options(
        chemenv_configuration.package_options['default_strategy']
        ['strategy_options'])
    max_dist_factor = chemenv_configuration.package_options[
        'default_max_distance_factor']
    firsttime = True
    while True:
        if len(questions) > 1:
            found = False
            print(
                'Enter the source from which the structure is coming or <q> to quit :'
            )
            for key_character, qq in questions.items():
                print(' - <{}> for a structure from {}'.format(
                    key_character, string_sources[qq]['string']))
            test = input(' ... ')
            if test == 'q':
                break
            if test not in list(questions.keys()):
                for key_character, qq in questions.items():
                    if re.match(string_sources[qq]['regexp'],
                                str(test)) is not None:
                        found = True
                        source_type = qq
                if not found:
                    print('Wrong key, try again ...')
                    continue
            else:
                source_type = questions[test]
        else:
            found = False
            source_type = list(questions.values())[0]
        if found and len(questions) > 1:
            input_source = test
        if source_type == 'cif':
            if not found:
                input_source = input('Enter path to cif file : ')
            cp = CifParser(input_source)
            structure = cp.get_structures()[0]
        elif source_type == 'mp':
            if not found:
                input_source = input(
                    'Enter materials project id (e.g. "mp-1902") : ')
            a = MPRester(chemenv_configuration.materials_project_api_key)
            structure = a.get_structure_by_material_id(input_source)
        lgf.setup_structure(structure)
        print('Computing environments for {} ... '.format(
            structure.composition.reduced_formula))
        se = lgf.compute_structure_environments(
            maximum_distance_factor=max_dist_factor)
        print('Computing environments finished')
        while True:
            test = input(
                'See list of environments determined for each (unequivalent) site ? '
                '("y" or "n", "d" with details, "g" to see the grid) : ')
            strategy = default_strategy
            if test in ['y', 'd', 'g']:
                strategy.set_structure_environments(se)
                for eqslist in se.equivalent_sites:
                    site = eqslist[0]
                    isite = se.structure.index(site)
                    try:
                        if strategy.uniquely_determines_coordination_environments:
                            ces = strategy.get_site_coordination_environments(
                                site)
                        else:
                            ces = strategy.get_site_coordination_environments_fractions(
                                site)
                    except NeighborsNotComputedChemenvError:
                        continue
                    if ces is None:
                        continue
                    if len(ces) == 0:
                        continue
                    comp = site.species_and_occu
                    #ce = strategy.get_site_coordination_environment(site)
                    if strategy.uniquely_determines_coordination_environments:
                        ce = ces[0]
                        if ce is None:
                            continue
                        thecg = allcg.get_geometry_from_mp_symbol(ce[0])
                        mystring = 'Environment for site #{} {} ({}) : {} ({})\n'.format(
                            str(isite),
                            comp.get_reduced_formula_and_factor()[0],
                            str(comp), thecg.name, ce[0])
                    else:
                        mystring = 'Environments for site #{} {} ({}) : \n'.format(
                            str(isite),
                            comp.get_reduced_formula_and_factor()[0],
                            str(comp))
                        for ce in ces:
                            cg = allcg.get_geometry_from_mp_symbol(ce[0])
                            csm = ce[1]['other_symmetry_measures'][
                                'csm_wcs_ctwcc']
                            mystring += ' - {} ({}): {:.2f} % (csm : {:2f})\n'.format(
                                cg.name, cg.mp_symbol, 100.0 * ce[2], csm)
                    if test in [
                            'd', 'g'
                    ] and strategy.uniquely_determines_coordination_environments:
                        if thecg.mp_symbol != UNCLEAR_ENVIRONMENT_SYMBOL:
                            mystring += '  <Continuous symmetry measures>  '
                            mingeoms = se.ce_list[isite][
                                thecg.
                                coordination_number][0].minimum_geometries()
                            for mingeom in mingeoms:
                                csm = mingeom[1]['other_symmetry_measures'][
                                    'csm_wcs_ctwcc']
                                mystring += '{} : {:.2f}       '.format(
                                    mingeom[0], csm)
                    print(mystring)
            if test == 'g':
                test = input(
                    'Enter index of site(s) for which you want to see the grid of parameters : '
                )
                indices = list(map(int, test.split()))
                print(indices)
                for isite in indices:
                    se.plot_environments(isite,
                                         additional_condition=se.AC.ONLY_ACB)
            if no_vis:
                test = input('Go to next structure ? ("y" to do so)')
                if test == 'y':
                    break
                continue
            test = input(
                'View structure with environments ? ("y" for the unit cell or "m" for a supercell or "n") : '
            )
            if test in ['y', 'm']:
                if test == 'm':
                    mydeltas = []
                    test = input('Enter multiplicity (e.g. 3 2 2) : ')
                    nns = test.split()
                    for i0 in range(int(nns[0])):
                        for i1 in range(int(nns[1])):
                            for i2 in range(int(nns[2])):
                                mydeltas.append(
                                    np.array([1.0 * i0, 1.0 * i1, 1.0 * i2],
                                             np.float))
                else:
                    mydeltas = [np.zeros(3, np.float)]
                if firsttime:
                    vis = StructureVis(show_polyhedron=False,
                                       show_unit_cell=True)
                    vis.show_help = False
                    firsttime = False
                vis.set_structure(se.structure)
                strategy.set_structure_environments(se)
                for isite, site in enumerate(se.structure):
                    try:
                        ces = strategy.get_site_coordination_environments(site)
                    except NeighborsNotComputedChemenvError:
                        continue
                    if len(ces) == 0:
                        continue
                    ce = strategy.get_site_coordination_environment(site)
                    if ce is not None and ce[0] != UNCLEAR_ENVIRONMENT_SYMBOL:
                        for mydelta in mydeltas:
                            psite = PeriodicSite(site._species,
                                                 site._fcoords + mydelta,
                                                 site._lattice,
                                                 properties=site._properties)
                            vis.add_site(psite)
                            neighbors = strategy.get_site_neighbors(psite)
                            draw_cg(vis,
                                    psite,
                                    neighbors,
                                    cg=lgf.allcg.get_geometry_from_mp_symbol(
                                        ce[0]),
                                    perm=ce[1]['permutation'])
                vis.show()
            test = input('Go to next structure ? ("y" to do so) : ')
            if test == 'y':
                break
        print('')
class CoordinationGeometryFinderTest(unittest.TestCase):

    def setUp(self):
        self.lgf = LocalGeometryFinder()
        self.lgf.setup_parameters(centering_type='standard',
                                  structure_refinement=self.lgf.STRUCTURE_REFINEMENT_NONE)
    #     self.strategies = [SimplestChemenvStrategy(), SimpleAbundanceChemenvStrategy()]
    #
    # def _strategy_test(self, strategy):
    #     files = []
    #     for (dirpath, dirnames, filenames) in os.walk(json_files_dir):
    #         files.extend(filenames)
    #         break
    #
    #     for ifile, json_file in enumerate(files):
    #         with self.subTest(json_file=json_file):
    #             f = open("{}/{}".format(json_files_dir, json_file), 'r')
    #             dd = json.load(f)
    #             f.close()
    #
    #             atom_indices = dd['atom_indices']
    #             expected_geoms = dd['expected_geoms']
    #
    #             struct = Structure.from_dict(dd['structure'])
    #
    #             struct = self.lgf.setup_structure(struct)
    #             se = self.lgf.compute_structure_environments_detailed_voronoi(only_indices=atom_indices,
    #                                                                           maximum_distance_factor=1.5)
    #
    #             #All strategies should get the correct environment with their default parameters
    #             strategy.set_structure_environments(se)
    #             for ienv, isite in enumerate(atom_indices):
    #                 ce = strategy.get_site_coordination_environment(struct[isite])
    #                 try:
    #                     coord_env = ce[0]
    #                 except TypeError:
    #                     coord_env = ce
    #                 #Check that the environment found is the expected one
    #                 self.assertEqual(coord_env, expected_geoms[ienv])
    #
    # def test_simplest_chemenv_strategy(self):
    #     strategy = SimplestChemenvStrategy()
    #     self._strategy_test(strategy)
    #
    # def test_simple_abundance_chemenv_strategy(self):
    #     strategy = SimpleAbundanceChemenvStrategy()
    #     self._strategy_test(strategy)

    def test_perfect_environments(self):
        allcg = AllCoordinationGeometries()
        indices_CN = {1: [0],
                      2: [1, 0],
                      3: [1, 0, 2],
                      4: [2, 0, 3, 1],
                      5: [2, 3, 1, 0, 4],
                      6: [0, 2, 3, 1, 5, 4],
                      7: [2, 6, 0, 3, 4, 5, 1],
                      8: [1, 2, 6, 3, 7, 0, 4, 5],
                      9: [5, 2, 6, 0, 4, 7, 3, 8, 1],
                      10: [8, 5, 6, 3, 0, 7, 2, 4, 9, 1],
                      11: [7, 6, 4, 1, 2, 5, 0, 8, 9, 10, 3],
                      12: [5, 8, 9, 0, 3, 1, 4, 2, 6, 11, 10, 7],
                      13: [4, 11, 5, 12, 1, 2, 8, 3, 0, 6, 9, 7, 10],
                      }

        for coordination in range(1, 14):
            for mp_symbol in allcg.get_implemented_geometries(coordination=coordination,
                                                              returned='mp_symbol'):
                cg = allcg.get_geometry_from_mp_symbol(mp_symbol=mp_symbol)
                self.lgf.allcg = AllCoordinationGeometries(only_symbols=[mp_symbol])
                self.lgf.setup_test_perfect_environment(mp_symbol, randomness=False,
                                                        indices=indices_CN[coordination],
                                                        random_translation='NONE', random_rotation='NONE',
                                                        random_scale='NONE')
                se = self.lgf.compute_structure_environments(only_indices=[0],
                                                             maximum_distance_factor=1.01*cg.distfactor_max,
                                                             min_cn=cg.coordination_number,
                                                             max_cn=cg.coordination_number,
                                                             only_symbols=[mp_symbol]
                                                             )
                self.assertAlmostEqual(se.get_csm(0, mp_symbol)['symmetry_measure'], 0.0, delta=1e-8,
                                       msg='Failed to get perfect environment with mp_symbol {}'.format(mp_symbol))
    def test_real_systems(self):
        # Initialize geometry and connectivity finders
        strat = SimplestChemenvStrategy()
        lgf = LocalGeometryFinder()
        cf = ConnectivityFinder()

        # Connectivity of LiFePO4
        struct = self.get_structure("LiFePO4")
        lgf.setup_structure(structure=struct)
        se = lgf.compute_structure_environments(only_atoms=["Li", "Fe", "P"],
                                                maximum_distance_factor=1.2)
        lse = LightStructureEnvironments.from_structure_environments(
            strategy=strat, structure_environments=se)
        # Make sure the initial structure and environments are correct
        for isite in range(0, 4):
            assert lse.structure[isite].specie.symbol == "Li"
            assert lse.coordination_environments[isite][0][
                "ce_symbol"] == "O:6"
        for isite in range(4, 8):
            assert lse.structure[isite].specie.symbol == "Fe"
            assert lse.coordination_environments[isite][0][
                "ce_symbol"] == "O:6"
        for isite in range(8, 12):
            assert lse.structure[isite].specie.symbol == "P"
            assert lse.coordination_environments[isite][0][
                "ce_symbol"] == "T:4"
        # Get the connectivity including all environments and check results
        sc = cf.get_structure_connectivity(lse)
        assert len(sc.environment_subgraphs
                   ) == 0  # Connected component not computed by default
        ccs = sc.get_connected_components(
        )  # by default, will use all the environments (O:6 and T:4 here)
        assert list(sc.environment_subgraphs.keys()) == [
            "O:6-T:4"
        ]  # Now the default components are there
        assert len(sc.environment_subgraphs) == 1
        assert len(ccs) == 1
        cc = ccs[0]
        assert len(cc) == 12
        assert cc.periodicity == "3D"
        assert (
            cc.description() == """Connected component with environment nodes :
Node #0 Li (O:6)
Node #1 Li (O:6)
Node #2 Li (O:6)
Node #3 Li (O:6)
Node #4 Fe (O:6)
Node #5 Fe (O:6)
Node #6 Fe (O:6)
Node #7 Fe (O:6)
Node #8 P (T:4)
Node #9 P (T:4)
Node #10 P (T:4)
Node #11 P (T:4)""")
        assert (cc.description(
            full=True) == """Connected component with environment nodes :
Node #0 Li (O:6), connected to :
  - Node #1 Li (O:6) with delta image cells
     (-1 0 1)
     (-1 1 1)
  - Node #4 Fe (O:6) with delta image cells
     (-1 1 1)
     (0 1 1)
  - Node #5 Fe (O:6) with delta image cells
     (0 0 1)
  - Node #6 Fe (O:6) with delta image cells
     (-1 1 0)
  - Node #7 Fe (O:6) with delta image cells
     (-1 0 0)
     (0 0 0)
  - Node #8 P (T:4) with delta image cells
     (-1 0 1)
     (0 0 1)
  - Node #11 P (T:4) with delta image cells
     (-1 1 0)
     (0 1 0)
Node #1 Li (O:6), connected to :
  - Node #0 Li (O:6) with delta image cells
     (1 -1 -1)
     (1 0 -1)
  - Node #4 Fe (O:6) with delta image cells
     (0 0 0)
     (1 0 0)
  - Node #5 Fe (O:6) with delta image cells
     (1 0 0)
  - Node #6 Fe (O:6) with delta image cells
     (0 0 -1)
  - Node #7 Fe (O:6) with delta image cells
     (0 0 -1)
     (1 0 -1)
  - Node #8 P (T:4) with delta image cells
     (0 0 0)
     (1 0 0)
  - Node #11 P (T:4) with delta image cells
     (0 0 -1)
     (1 0 -1)
Node #2 Li (O:6), connected to :
  - Node #3 Li (O:6) with delta image cells
     (0 0 0)
     (0 1 0)
  - Node #4 Fe (O:6) with delta image cells
     (0 1 0)
  - Node #5 Fe (O:6) with delta image cells
     (0 0 0)
     (1 0 0)
  - Node #6 Fe (O:6) with delta image cells
     (-1 1 0)
     (0 1 0)
  - Node #7 Fe (O:6) with delta image cells
     (0 0 0)
  - Node #9 P (T:4) with delta image cells
     (0 1 0)
     (1 1 0)
  - Node #10 P (T:4) with delta image cells
     (-1 0 0)
     (0 0 0)
Node #3 Li (O:6), connected to :
  - Node #2 Li (O:6) with delta image cells
     (0 -1 0)
     (0 0 0)
  - Node #4 Fe (O:6) with delta image cells
     (0 0 0)
  - Node #5 Fe (O:6) with delta image cells
     (0 0 0)
     (1 0 0)
  - Node #6 Fe (O:6) with delta image cells
     (-1 0 0)
     (0 0 0)
  - Node #7 Fe (O:6) with delta image cells
     (0 0 0)
  - Node #9 P (T:4) with delta image cells
     (0 0 0)
     (1 0 0)
  - Node #10 P (T:4) with delta image cells
     (-1 0 0)
     (0 0 0)
Node #4 Fe (O:6), connected to :
  - Node #0 Li (O:6) with delta image cells
     (0 -1 -1)
     (1 -1 -1)
  - Node #1 Li (O:6) with delta image cells
     (-1 0 0)
     (0 0 0)
  - Node #2 Li (O:6) with delta image cells
     (0 -1 0)
  - Node #3 Li (O:6) with delta image cells
     (0 0 0)
  - Node #5 Fe (O:6) with delta image cells
     (0 -1 0)
     (0 0 0)
     (1 -1 0)
     (1 0 0)
  - Node #8 P (T:4) with delta image cells
     (0 -1 0)
     (0 0 0)
  - Node #9 P (T:4) with delta image cells
     (0 0 0)
     (1 0 0)
  - Node #11 P (T:4) with delta image cells
     (0 0 -1)
Node #5 Fe (O:6), connected to :
  - Node #0 Li (O:6) with delta image cells
     (0 0 -1)
  - Node #1 Li (O:6) with delta image cells
     (-1 0 0)
  - Node #2 Li (O:6) with delta image cells
     (-1 0 0)
     (0 0 0)
  - Node #3 Li (O:6) with delta image cells
     (-1 0 0)
     (0 0 0)
  - Node #4 Fe (O:6) with delta image cells
     (-1 0 0)
     (-1 1 0)
     (0 0 0)
     (0 1 0)
  - Node #8 P (T:4) with delta image cells
     (-1 0 0)
     (0 0 0)
  - Node #9 P (T:4) with delta image cells
     (0 0 0)
     (0 1 0)
  - Node #10 P (T:4) with delta image cells
     (-1 0 0)
Node #6 Fe (O:6), connected to :
  - Node #0 Li (O:6) with delta image cells
     (1 -1 0)
  - Node #1 Li (O:6) with delta image cells
     (0 0 1)
  - Node #2 Li (O:6) with delta image cells
     (0 -1 0)
     (1 -1 0)
  - Node #3 Li (O:6) with delta image cells
     (0 0 0)
     (1 0 0)
  - Node #7 Fe (O:6) with delta image cells
     (0 -1 0)
     (0 0 0)
     (1 -1 0)
     (1 0 0)
  - Node #9 P (T:4) with delta image cells
     (1 0 0)
  - Node #10 P (T:4) with delta image cells
     (0 -1 0)
     (0 0 0)
  - Node #11 P (T:4) with delta image cells
     (0 0 0)
     (1 0 0)
Node #7 Fe (O:6), connected to :
  - Node #0 Li (O:6) with delta image cells
     (0 0 0)
     (1 0 0)
  - Node #1 Li (O:6) with delta image cells
     (-1 0 1)
     (0 0 1)
  - Node #2 Li (O:6) with delta image cells
     (0 0 0)
  - Node #3 Li (O:6) with delta image cells
     (0 0 0)
  - Node #6 Fe (O:6) with delta image cells
     (-1 0 0)
     (-1 1 0)
     (0 0 0)
     (0 1 0)
  - Node #8 P (T:4) with delta image cells
     (0 0 1)
  - Node #10 P (T:4) with delta image cells
     (-1 0 0)
     (0 0 0)
  - Node #11 P (T:4) with delta image cells
     (0 0 0)
     (0 1 0)
Node #8 P (T:4), connected to :
  - Node #0 Li (O:6) with delta image cells
     (0 0 -1)
     (1 0 -1)
  - Node #1 Li (O:6) with delta image cells
     (-1 0 0)
     (0 0 0)
  - Node #4 Fe (O:6) with delta image cells
     (0 0 0)
     (0 1 0)
  - Node #5 Fe (O:6) with delta image cells
     (0 0 0)
     (1 0 0)
  - Node #7 Fe (O:6) with delta image cells
     (0 0 -1)
Node #9 P (T:4), connected to :
  - Node #2 Li (O:6) with delta image cells
     (-1 -1 0)
     (0 -1 0)
  - Node #3 Li (O:6) with delta image cells
     (-1 0 0)
     (0 0 0)
  - Node #4 Fe (O:6) with delta image cells
     (-1 0 0)
     (0 0 0)
  - Node #5 Fe (O:6) with delta image cells
     (0 -1 0)
     (0 0 0)
  - Node #6 Fe (O:6) with delta image cells
     (-1 0 0)
Node #10 P (T:4), connected to :
  - Node #2 Li (O:6) with delta image cells
     (0 0 0)
     (1 0 0)
  - Node #3 Li (O:6) with delta image cells
     (0 0 0)
     (1 0 0)
  - Node #5 Fe (O:6) with delta image cells
     (1 0 0)
  - Node #6 Fe (O:6) with delta image cells
     (0 0 0)
     (0 1 0)
  - Node #7 Fe (O:6) with delta image cells
     (0 0 0)
     (1 0 0)
Node #11 P (T:4), connected to :
  - Node #0 Li (O:6) with delta image cells
     (0 -1 0)
     (1 -1 0)
  - Node #1 Li (O:6) with delta image cells
     (-1 0 1)
     (0 0 1)
  - Node #4 Fe (O:6) with delta image cells
     (0 0 1)
  - Node #6 Fe (O:6) with delta image cells
     (-1 0 0)
     (0 0 0)
  - Node #7 Fe (O:6) with delta image cells
     (0 -1 0)
     (0 0 0)""")
        # Get the connectivity for T:4 and O:6 separately and check results
        # Only tetrahedral
        sc.setup_environment_subgraph(environments_symbols=["T:4"])
        assert list(sc.environment_subgraphs.keys()) == ["O:6-T:4", "T:4"]
        ccs = sc.get_connected_components()
        assert len(ccs) == 4
        for cc in ccs:
            assert cc.periodicity == "0D"
        # Only octahedral
        sc.setup_environment_subgraph(environments_symbols=["O:6"])
        assert list(
            sc.environment_subgraphs.keys()) == ["O:6-T:4", "T:4", "O:6"]
        ccs = sc.get_connected_components()
        assert len(ccs) == 1
        cc = ccs[0]
        assert cc.periodicity == "3D"
        # Only Manganese octahedral
        sc.setup_environment_subgraph(environments_symbols=["O:6"],
                                      only_atoms=["Fe"])
        assert list(sc.environment_subgraphs.keys()) == [
            "O:6-T:4",
            "T:4",
            "O:6",
            "O:6#Fe",
        ]
        ccs = sc.get_connected_components()
        assert len(ccs) == 2
        for cc in ccs:
            assert cc.periodicity == "2D"

        # Connectivity of Li4Fe3Mn1(PO4)4
        struct = Structure.from_file(
            os.path.join(self.TEST_FILES_DIR, "Li4Fe3Mn1(PO4)4.cif"))
        lgf.setup_structure(structure=struct)
        se = lgf.compute_structure_environments(
            only_atoms=["Li", "Fe", "Mn", "P"], maximum_distance_factor=1.2)
        lse = LightStructureEnvironments.from_structure_environments(
            strategy=strat, structure_environments=se)
        # Make sure the initial structure and environments are correct
        for isite in range(0, 4):
            assert lse.structure[isite].specie.symbol == "Li"
            assert lse.coordination_environments[isite][0][
                "ce_symbol"] == "O:6"
        for isite in range(4, 5):
            assert lse.structure[isite].specie.symbol == "Mn"
            assert lse.coordination_environments[isite][0][
                "ce_symbol"] == "O:6"
        for isite in range(5, 8):
            assert lse.structure[isite].specie.symbol == "Fe"
            assert lse.coordination_environments[isite][0][
                "ce_symbol"] == "O:6"
        for isite in range(8, 12):
            assert lse.structure[isite].specie.symbol == "P"
            assert lse.coordination_environments[isite][0][
                "ce_symbol"] == "T:4"
        # Get the connectivity including all environments and check results
        sc = cf.get_structure_connectivity(lse)
        assert len(sc.environment_subgraphs
                   ) == 0  # Connected component not computed by default
        ccs = sc.get_connected_components(
        )  # by default, will use all the environments (O:6 and T:4 here)
        # Now connected components for the defaults are there :
        assert list(sc.environment_subgraphs.keys()) == ["O:6-T:4"]
        assert len(sc.environment_subgraphs) == 1
        assert len(ccs) == 1
        cc = ccs[0]
        assert cc.periodicity == "3D"
        # Get the connectivity for Li octahedral only
        ccs = sc.get_connected_components(environments_symbols=["O:6"],
                                          only_atoms=["Li"])
        assert list(sc.environment_subgraphs.keys()) == ["O:6-T:4", "O:6#Li"]
        assert len(ccs) == 2
        for cc in ccs:
            assert cc.periodicity == "1D"
            assert len(cc) == 2
        # Sort connected components as they might
        # come in a different order depending on
        # the algorithm used to get them.
        sorted_ccs = sorted(ccs, key=lambda x: sorted(x.graph.nodes())[0])
        assert (sorted_ccs[0].description(
            full=True) == """Connected component with environment nodes :
Node #0 Li (O:6), connected to :
  - Node #1 Li (O:6) with delta image cells
     (1 -1 1)
     (1 0 1)
Node #1 Li (O:6), connected to :
  - Node #0 Li (O:6) with delta image cells
     (-1 0 -1)
     (-1 1 -1)""")
        assert (sorted_ccs[1].description(
            full=True) == """Connected component with environment nodes :
Node #2 Li (O:6), connected to :
  - Node #3 Li (O:6) with delta image cells
     (0 -1 0)
     (0 0 0)
Node #3 Li (O:6), connected to :
  - Node #2 Li (O:6) with delta image cells
     (0 0 0)
     (0 1 0)""")
        # Get the connectivity for Mn octahedral only
        ccs = sc.get_connected_components(environments_symbols=["O:6"],
                                          only_atoms=["Mn"])
        assert list(sc.environment_subgraphs.keys()) == [
            "O:6-T:4", "O:6#Li", "O:6#Mn"
        ]
        assert len(ccs) == 1
        assert ccs[0].periodicity == "0D"
        # Get the connectivity for Fe octahedral only
        ccs = sc.get_connected_components(environments_symbols=["O:6"],
                                          only_atoms=["Fe"])
        assert list(sc.environment_subgraphs.keys()) == [
            "O:6-T:4",
            "O:6#Li",
            "O:6#Mn",
            "O:6#Fe",
        ]
        assert len(ccs) == 2
        ccs_periodicities = set(cc.periodicity for cc in ccs)
        assert ccs_periodicities == {"0D", "2D"}
Example #12
0
    def run_task(self, fw_spec):
        logging.basicConfig(
            filename='chemenv_structure_environments.log',
            format='%(levelname)s:%(module)s:%(funcName)s:%(message)s',
            level=logging.DEBUG)
        lgf = LocalGeometryFinder()
        lgf.setup_parameters(
            centering_type='centroid',
            include_central_site_in_centroid=True,
            structure_refinement=lgf.STRUCTURE_REFINEMENT_NONE)
        if 'chemenv_parameters' in fw_spec:
            for param, value in fw_spec['chemenv_parameters'].items():
                lgf.setup_parameter(param, value)
        identifier = fw_spec['identifier']
        if 'structure' in fw_spec:
            structure = fw_spec['structure']
        else:
            if identifier[
                    'source'] == 'MaterialsProject' and 'material_id' in identifier:
                if not 'mapi_key' in fw_spec:
                    raise ValueError(
                        'The mapi_key should be provided to get the structure from the Materials Project'
                    )
                a = MPRester(fw_spec['mapi_key'])
                structure = a.get_structure_by_material_id(
                    identifier['material_id'])
            else:
                raise ValueError(
                    'Either structure or identifier with source = MaterialsProject and material_id '
                    'should be provided')

        info = {}
        # Compute the structure environments
        lgf.setup_structure(structure)
        if 'valences' in fw_spec:
            valences = fw_spec['valences']
        else:
            try:
                bva = BVAnalyzer()
                valences = bva.get_valences(structure=structure)
                info['valences'] = {'origin': 'BVAnalyzer'}
            except:
                valences = 'undefined'
                info['valences'] = {'origin': 'None'}
        excluded_atoms = None
        if 'excluded_atoms' in fw_spec:
            excluded_atoms = fw_spec['excluded_atoms']

        se = lgf.compute_structure_environments(only_cations=False,
                                                valences=valences,
                                                excluded_atoms=excluded_atoms)

        # Write to json file
        if 'json_file' in fw_spec:
            json_file = fw_spec['json_file']
        else:
            json_file = 'structure_environments.json'
        f = open(json_file, 'w')
        json.dump(se.as_dict(), f)
        f.close()

        # Save to database
        if 'mongo_database' in fw_spec:
            database = fw_spec['mongo_database']
            entry = {
                'identifier':
                identifier,
                'elements':
                [elmt.symbol for elmt in structure.composition.elements],
                'nelements':
                len(structure.composition.elements),
                'pretty_formula':
                structure.composition.reduced_formula,
                'nsites':
                len(structure)
            }

            saving_option = fw_spec['saving_option']
            if saving_option == 'gridfs':
                gridfs_msonables = {
                    'structure': structure,
                    'structure_environments': se
                }
            elif saving_option == 'storefile':
                gridfs_msonables = None
                if 'se_prefix' in fw_spec:
                    se_prefix = fw_spec['se_prefix']
                    if not se_prefix.isalpha():
                        raise ValueError(
                            'Prefix for structure_environments file is "{}" '
                            'while it should be alphabetic'.format(se_prefix))
                else:
                    se_prefix = ''
                if se_prefix:
                    se_rfilename = '{}_{}.json'.format(
                        se_prefix, fw_spec['storefile_basename'])
                else:
                    se_rfilename = '{}.json'.format(
                        fw_spec['storefile_basename'])
                se_rfilepath = '{}/{}'.format(fw_spec['storefile_dirpath'],
                                              se_rfilename)
                storage_server = fw_spec['storage_server']
                storage_server.put(localpath=json_file,
                                   remotepath=se_rfilepath,
                                   overwrite=True,
                                   makedirs=False)
                entry['structure_environments_file'] = se_rfilepath
            else:
                raise ValueError(
                    'Saving option is "{}" while it should be '
                    '"gridfs" or "storefile"'.format(saving_option))
            criteria = {'identifier': identifier}
            if database.collection.find(criteria).count() == 1:
                database.update_entry(query=criteria,
                                      entry_update=entry,
                                      gridfs_msonables=gridfs_msonables)
            else:
                database.insert_entry(entry=entry,
                                      gridfs_msonables=gridfs_msonables)
Example #13
0
    def run_task(self, fw_spec):
        logging.basicConfig(filename='chemenv_structure_environments.log',
                            format='%(levelname)s:%(module)s:%(funcName)s:%(message)s',
                            level=logging.DEBUG)
        lgf = LocalGeometryFinder()
        lgf.setup_parameters(centering_type='centroid', include_central_site_in_centroid=True,
                             structure_refinement=lgf.STRUCTURE_REFINEMENT_NONE)
        if 'chemenv_parameters' in fw_spec:
            for param, value in fw_spec['chemenv_parameters'].items():
                lgf.setup_parameter(param, value)
        identifier = fw_spec['identifier']
        if 'structure' in fw_spec:
            structure = fw_spec['structure']
        else:
            if identifier['source'] == 'MaterialsProject' and 'material_id' in identifier:
                if not 'mapi_key' in fw_spec:
                    raise ValueError('The mapi_key should be provided to get the structure from the Materials Project')
                # FIXME: Use MPRester from pymatgen
                from pymatgen.matproj.rest import MPRester
                a = MPRester(fw_spec['mapi_key'])
                structure = a.get_structure_by_material_id(identifier['material_id'])
            else:
                raise ValueError('Either structure or identifier with source = MaterialsProject and material_id '
                                 'should be provided')

        info = {}
        # Compute the structure environments
        lgf.setup_structure(structure)
        if 'valences' in fw_spec:
            valences = fw_spec['valences']
        else:
            try:
                bva = BVAnalyzer()
                valences = bva.get_valences(structure=structure)
                info['valences'] = {'origin': 'BVAnalyzer'}
            except:
                valences = 'undefined'
                info['valences'] = {'origin': 'None'}
        excluded_atoms = None
        if 'excluded_atoms' in fw_spec:
            excluded_atoms = fw_spec['excluded_atoms']

        se = lgf.compute_structure_environments(only_cations=False, valences=valences, excluded_atoms=excluded_atoms)

        # Write to json file
        if 'json_file' in fw_spec:
            json_file = fw_spec['json_file']
        else:
            json_file = 'structure_environments.json'
        f = open(json_file, 'w')
        json.dump(se.as_dict(), f)
        f.close()

        # Save to database
        if 'mongo_database' in fw_spec:
            database = fw_spec['mongo_database']
            entry = {'identifier': identifier,
                     'elements': [elmt.symbol for elmt in structure.composition.elements],
                     'nelements': len(structure.composition.elements),
                     'pretty_formula': structure.composition.reduced_formula,
                     'nsites': len(structure)
                     }

            saving_option = fw_spec['saving_option']
            if saving_option == 'gridfs':
                gridfs_msonables = {'structure': structure,
                                    'structure_environments': se}
            elif saving_option == 'storefile':
                gridfs_msonables = None
                if 'se_prefix' in fw_spec:
                    se_prefix = fw_spec['se_prefix']
                    if not se_prefix.isalpha():
                        raise ValueError('Prefix for structure_environments file is "{}" '
                                         'while it should be alphabetic'.format(se_prefix))
                else:
                    se_prefix = ''
                if se_prefix:
                    se_rfilename = '{}_{}.json'.format(se_prefix, fw_spec['storefile_basename'])
                else:
                    se_rfilename = '{}.json'.format(fw_spec['storefile_basename'])
                se_rfilepath = '{}/{}'.format(fw_spec['storefile_dirpath'], se_rfilename)
                storage_server = fw_spec['storage_server']
                storage_server.put(localpath=json_file, remotepath=se_rfilepath, overwrite=True, makedirs=False)
                entry['structure_environments_file'] = se_rfilepath
            else:
                raise ValueError('Saving option is "{}" while it should be '
                                 '"gridfs" or "storefile"'.format(saving_option))
            criteria = {'identifier': identifier}
            if database.collection.find(criteria).count() == 1:
                database.update_entry(query=criteria, entry_update=entry,
                                      gridfs_msonables=gridfs_msonables)
            else:
                database.insert_entry(entry=entry, gridfs_msonables=gridfs_msonables)
Example #14
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])
Example #15
0
class CoordinationGeometryFinderTest(unittest.TestCase):
    def setUp(self):
        self.lgf = LocalGeometryFinder()
        self.lgf.setup_parameters(
            centering_type='standard',
            structure_refinement=self.lgf.STRUCTURE_REFINEMENT_NONE)

    #     self.strategies = [SimplestChemenvStrategy(), SimpleAbundanceChemenvStrategy()]
    #
    # def _strategy_test(self, strategy):
    #     files = []
    #     for (dirpath, dirnames, filenames) in os.walk(json_files_dir):
    #         files.extend(filenames)
    #         break
    #
    #     for ifile, json_file in enumerate(files):
    #         with self.subTest(json_file=json_file):
    #             f = open("{}/{}".format(json_files_dir, json_file), 'r')
    #             dd = json.load(f)
    #             f.close()
    #
    #             atom_indices = dd['atom_indices']
    #             expected_geoms = dd['expected_geoms']
    #
    #             struct = Structure.from_dict(dd['structure'])
    #
    #             struct = self.lgf.setup_structure(struct)
    #             se = self.lgf.compute_structure_environments_detailed_voronoi(only_indices=atom_indices,
    #                                                                           maximum_distance_factor=1.5)
    #
    #             #All strategies should get the correct environment with their default parameters
    #             strategy.set_structure_environments(se)
    #             for ienv, isite in enumerate(atom_indices):
    #                 ce = strategy.get_site_coordination_environment(struct[isite])
    #                 try:
    #                     coord_env = ce[0]
    #                 except TypeError:
    #                     coord_env = ce
    #                 #Check that the environment found is the expected one
    #                 self.assertEqual(coord_env, expected_geoms[ienv])
    #
    # def test_simplest_chemenv_strategy(self):
    #     strategy = SimplestChemenvStrategy()
    #     self._strategy_test(strategy)
    #
    # def test_simple_abundance_chemenv_strategy(self):
    #     strategy = SimpleAbundanceChemenvStrategy()
    #     self._strategy_test(strategy)

    def test_perfect_environments(self):
        allcg = AllCoordinationGeometries()
        indices_CN = {
            1: [0],
            2: [1, 0],
            3: [1, 0, 2],
            4: [2, 0, 3, 1],
            5: [2, 3, 1, 0, 4],
            6: [0, 2, 3, 1, 5, 4],
            7: [2, 6, 0, 3, 4, 5, 1],
            8: [1, 2, 6, 3, 7, 0, 4, 5],
            9: [5, 2, 6, 0, 4, 7, 3, 8, 1],
            10: [8, 5, 6, 3, 0, 7, 2, 4, 9, 1],
            11: [7, 6, 4, 1, 2, 5, 0, 8, 9, 10, 3],
            12: [5, 8, 9, 0, 3, 1, 4, 2, 6, 11, 10, 7],
            13: [4, 11, 5, 12, 1, 2, 8, 3, 0, 6, 9, 7, 10],
        }

        for coordination in range(1, 14):
            for mp_symbol in allcg.get_implemented_geometries(
                    coordination=coordination, returned='mp_symbol'):
                cg = allcg.get_geometry_from_mp_symbol(mp_symbol=mp_symbol)
                self.lgf.allcg = AllCoordinationGeometries(
                    only_symbols=[mp_symbol])
                self.lgf.setup_test_perfect_environment(
                    mp_symbol,
                    randomness=False,
                    indices=indices_CN[coordination],
                    random_translation='NONE',
                    random_rotation='NONE',
                    random_scale='NONE')
                se = self.lgf.compute_structure_environments(
                    only_indices=[0],
                    maximum_distance_factor=1.01 * cg.distfactor_max,
                    min_cn=cg.coordination_number,
                    max_cn=cg.coordination_number,
                    only_symbols=[mp_symbol])
                self.assertAlmostEqual(
                    se.get_csm(0, mp_symbol)['symmetry_measure'],
                    0.0,
                    delta=1e-8,
                    msg='Failed to get perfect environment with mp_symbol {}'.
                    format(mp_symbol))
    structure_id = key_value_pairs["structure_id"]

    if structure_id in ids_to_run:
        print("RUNNING!")

        atoms = row.toatoms()
        Ir_indices = [
            i for i, s in enumerate(atoms.get_chemical_symbols()) if s == 'Ir'
        ]

        struct = AseAtomsAdaptor.get_structure(atoms)

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

        se = lgf.compute_structure_environments(maximum_distance_factor=1.41,
                                                only_cations=False)

        strategy = MultiWeightsChemenvStrategy.stats_article_weights_parameters(
        )

        lse = LightStructureEnvironments.from_structure_environments(
            strategy=strategy, structure_environments=se)

        isite = 0

        cor_env = []
        for isite in Ir_indices:
            c_env = lse.coordination_environments[isite]
            if len(c_env) == 0:
                continue
            cor_env += [c_env[0]['ce_symbol']]
Example #17
0
def compute_environments(chemenv_configuration):
    string_sources = {
        "cif": {
            "string": "a Cif file",
            "regexp": r".*\.cif$"
        },
        "mp": {
            "string": "the Materials Project database",
            "regexp": r"mp-[0-9]+$"
        },
    }
    questions = {"c": "cif"}
    questions["m"] = "mp"
    lgf = LocalGeometryFinder()
    lgf.setup_parameters()
    allcg = AllCoordinationGeometries()
    strategy_class = strategies_class_lookup[
        chemenv_configuration.package_options["default_strategy"]["strategy"]]
    # TODO: Add the possibility to change the parameters and save them in the chemenv_configuration
    default_strategy = strategy_class()
    default_strategy.setup_options(
        chemenv_configuration.package_options["default_strategy"]
        ["strategy_options"])
    max_dist_factor = chemenv_configuration.package_options[
        "default_max_distance_factor"]
    firsttime = True
    while True:
        if len(questions) > 1:
            found = False
            print(
                "Enter the source from which the structure is coming or <q> to quit :"
            )
            for key_character, qq in questions.items():
                print(" - <{}> for a structure from {}".format(
                    key_character, string_sources[qq]["string"]))
            test = input(" ... ")
            if test == "q":
                break
            if test not in list(questions.keys()):
                for key_character, qq in questions.items():
                    if re.match(string_sources[qq]["regexp"],
                                str(test)) is not None:
                        found = True
                        source_type = qq
                if not found:
                    print("Wrong key, try again ...")
                    continue
            else:
                source_type = questions[test]
        else:
            found = False
            source_type = list(questions.values())[0]
        if found and len(questions) > 1:
            input_source = test
        if source_type == "cif":
            if not found:
                input_source = input("Enter path to cif file : ")
            cp = CifParser(input_source)
            structure = cp.get_structures()[0]
        elif source_type == "mp":
            if not found:
                input_source = input(
                    'Enter materials project id (e.g. "mp-1902") : ')
            a = MPRester()
            structure = a.get_structure_by_material_id(input_source)
        lgf.setup_structure(structure)
        print("Computing environments for {} ... ".format(
            structure.composition.reduced_formula))
        se = lgf.compute_structure_environments(
            maximum_distance_factor=max_dist_factor)
        print("Computing environments finished")
        while True:
            test = input(
                "See list of environments determined for each (unequivalent) site ? "
                '("y" or "n", "d" with details, "g" to see the grid) : ')
            strategy = default_strategy
            if test in ["y", "d", "g"]:
                strategy.set_structure_environments(se)
                for eqslist in se.equivalent_sites:
                    site = eqslist[0]
                    isite = se.structure.index(site)
                    try:
                        if strategy.uniquely_determines_coordination_environments:
                            ces = strategy.get_site_coordination_environments(
                                site)
                        else:
                            ces = strategy.get_site_coordination_environments_fractions(
                                site)
                    except NeighborsNotComputedChemenvError:
                        continue
                    if ces is None:
                        continue
                    if len(ces) == 0:
                        continue
                    comp = site.species
                    # ce = strategy.get_site_coordination_environment(site)
                    if strategy.uniquely_determines_coordination_environments:
                        ce = ces[0]
                        if ce is None:
                            continue
                        thecg = allcg.get_geometry_from_mp_symbol(ce[0])
                        mystring = "Environment for site #{} {} ({}) : {} ({})\n".format(
                            str(isite),
                            comp.get_reduced_formula_and_factor()[0],
                            str(comp),
                            thecg.name,
                            ce[0],
                        )
                    else:
                        mystring = "Environments for site #{} {} ({}) : \n".format(
                            str(isite),
                            comp.get_reduced_formula_and_factor()[0],
                            str(comp),
                        )
                        for ce in ces:
                            cg = allcg.get_geometry_from_mp_symbol(ce[0])
                            csm = ce[1]["other_symmetry_measures"][
                                "csm_wcs_ctwcc"]
                            mystring += " - {} ({}): {:.2f} % (csm : {:2f})\n".format(
                                cg.name, cg.mp_symbol, 100.0 * ce[2], csm)
                    if (test in ["d", "g"] and strategy.
                            uniquely_determines_coordination_environments):
                        if thecg.mp_symbol != UNCLEAR_ENVIRONMENT_SYMBOL:
                            mystring += "  <Continuous symmetry measures>  "
                            mingeoms = se.ce_list[isite][
                                thecg.
                                coordination_number][0].minimum_geometries()
                            for mingeom in mingeoms:
                                csm = mingeom[1]["other_symmetry_measures"][
                                    "csm_wcs_ctwcc"]
                                mystring += "{} : {:.2f}       ".format(
                                    mingeom[0], csm)
                    print(mystring)
            if test == "g":
                while True:
                    test = input(
                        "Enter index of site(s) (e.g. 0 1 2, separated by spaces) for which you want to see the grid "
                        "of parameters : ")
                    try:
                        indices = [int(x) for x in test.split()]
                        print(str(indices))
                        for isite in indices:
                            if isite < 0:
                                raise IndexError
                            se.plot_environments(
                                isite, additional_condition=se.AC.ONLY_ACB)
                        break
                    except ValueError:
                        print("This is not a valid site")
                    except IndexError:
                        print("This site is out of the site range")

            if no_vis:
                test = input('Go to next structure ? ("y" to do so)')
                if test == "y":
                    break
                continue
            test = input(
                'View structure with environments ? ("y" for the unit cell or "m" for a supercell or "n") : '
            )
            if test in ["y", "m"]:
                if test == "m":
                    mydeltas = []
                    while True:
                        try:
                            test = input("Enter multiplicity (e.g. 3 2 2) : ")
                            nns = test.split()
                            for i0 in range(int(nns[0])):
                                for i1 in range(int(nns[1])):
                                    for i2 in range(int(nns[2])):
                                        mydeltas.append(
                                            np.array(
                                                [1.0 * i0, 1.0 * i1, 1.0 * i2],
                                                np.float))
                            break

                        except (ValueError, IndexError):
                            print("Not a valid multiplicity")
                else:
                    mydeltas = [np.zeros(3, np.float)]
                if firsttime:
                    vis = StructureVis(show_polyhedron=False,
                                       show_unit_cell=True)
                    vis.show_help = False
                    firsttime = False
                vis.set_structure(se.structure)
                strategy.set_structure_environments(se)
                for isite, site in enumerate(se.structure):
                    try:
                        ces = strategy.get_site_coordination_environments(site)
                    except NeighborsNotComputedChemenvError:
                        continue
                    if len(ces) == 0:
                        continue
                    ce = strategy.get_site_coordination_environment(site)
                    if ce is not None and ce[0] != UNCLEAR_ENVIRONMENT_SYMBOL:
                        for mydelta in mydeltas:
                            psite = PeriodicSite(
                                site.species,
                                site.frac_coords + mydelta,
                                site.lattice,
                                properties=site.properties,
                            )
                            vis.add_site(psite)
                            neighbors = strategy.get_site_neighbors(psite)
                            draw_cg(
                                vis,
                                psite,
                                neighbors,
                                cg=lgf.allcg.get_geometry_from_mp_symbol(
                                    ce[0]),
                                perm=ce[1]["permutation"],
                            )
                vis.show()
            test = input('Go to next structure ? ("y" to do so) : ')
            if test == "y":
                break
        print("")
Example #18
0
def compute_environments(chemenv_configuration):
    string_sources = {'cif': {'string': 'a Cif file', 'regexp': r'.*\.cif$'},
                      'mp': {'string': 'the Materials Project database',
                             'regexp': r'mp-[0-9]+$'}}
    questions = {'c': 'cif'}
    questions['m'] = 'mp'
    lgf = LocalGeometryFinder()
    lgf.setup_parameters()
    allcg = AllCoordinationGeometries()
    strategy_class = strategies_class_lookup[chemenv_configuration.package_options['default_strategy']['strategy']]
    #TODO: Add the possibility to change the parameters and save them in the chemenv_configuration
    default_strategy = strategy_class()
    default_strategy.setup_options(chemenv_configuration.package_options['default_strategy']['strategy_options'])
    max_dist_factor = chemenv_configuration.package_options['default_max_distance_factor']
    firsttime = True
    while True:
        if len(questions) > 1:
            found = False
            print('Enter the source from which the structure is coming or <q> to quit :')
            for key_character, qq in questions.items():
                print(' - <{}> for a structure from {}'.format(key_character, string_sources[qq]['string']))
            test = input(' ... ')
            if test == 'q':
                break
            if test not in list(questions.keys()):
                for key_character, qq in questions.items():
                    if re.match(string_sources[qq]['regexp'], str(test)) is not None:
                        found = True
                        source_type = qq
                if not found:
                    print('Wrong key, try again ...')
                    continue
            else:
                source_type = questions[test]
        else:
            found = False
            source_type = list(questions.values())[0]
        if found and len(questions) > 1:
            input_source = test
        if source_type == 'cif':
            if not found:
                input_source = input('Enter path to cif file : ')
            cp = CifParser(input_source)
            structure = cp.get_structures()[0]
        elif source_type == 'mp':
            if not found:
                input_source = input('Enter materials project id (e.g. "mp-1902") : ')
            a = MPRester()
            structure = a.get_structure_by_material_id(input_source)
        lgf.setup_structure(structure)
        print('Computing environments for {} ... '.format(structure.composition.reduced_formula))
        se = lgf.compute_structure_environments(maximum_distance_factor=max_dist_factor)
        print('Computing environments finished')
        while True:
            test = input('See list of environments determined for each (unequivalent) site ? '
                         '("y" or "n", "d" with details, "g" to see the grid) : ')
            strategy = default_strategy
            if test in ['y', 'd', 'g']:
                strategy.set_structure_environments(se)
                for eqslist in se.equivalent_sites:
                    site = eqslist[0]
                    isite = se.structure.index(site)
                    try:
                        if strategy.uniquely_determines_coordination_environments:
                            ces = strategy.get_site_coordination_environments(site)
                        else:
                            ces = strategy.get_site_coordination_environments_fractions(site)
                    except NeighborsNotComputedChemenvError:
                        continue
                    if ces is None:
                        continue
                    if len(ces) == 0:
                        continue
                    comp = site.species_and_occu
                    #ce = strategy.get_site_coordination_environment(site)
                    if strategy.uniquely_determines_coordination_environments:
                        ce = ces[0]
                        if ce is None:
                            continue
                        thecg = allcg.get_geometry_from_mp_symbol(ce[0])
                        mystring = 'Environment for site #{} {} ({}) : {} ({})\n'.format(str(isite),
                                                                                         comp.get_reduced_formula_and_factor()[0],
                                                                                         str(comp),
                                                                                         thecg.name,
                                                                                         ce[0])
                    else:
                        mystring = 'Environments for site #{} {} ({}) : \n'.format(str(isite),
                                                                                   comp.get_reduced_formula_and_factor()[0],
                                                                                   str(comp))
                        for ce in ces:
                            cg = allcg.get_geometry_from_mp_symbol(ce[0])
                            csm = ce[1]['other_symmetry_measures']['csm_wcs_ctwcc']
                            mystring += ' - {} ({}): {:.2f} % (csm : {:2f})\n'.format(cg.name, cg.mp_symbol,
                                                                                      100.0*ce[2],
                                                                                      csm)
                    if test in ['d', 'g'] and strategy.uniquely_determines_coordination_environments:
                        if thecg.mp_symbol != UNCLEAR_ENVIRONMENT_SYMBOL:
                            mystring += '  <Continuous symmetry measures>  '
                            mingeoms = se.ce_list[isite][thecg.coordination_number][0].minimum_geometries()
                            for mingeom in mingeoms:
                                csm = mingeom[1]['other_symmetry_measures']['csm_wcs_ctwcc']
                                mystring += '{} : {:.2f}       '.format(mingeom[0], csm)
                    print(mystring)
            if test == 'g':
                while True:
                    test = input('Enter index of site(s) (e.g. 0 1 2, separated by spaces) for which you want to see the grid of parameters : ')
                    try:
                         indices=[int(x) for x in test.split()]
                         print(str(indices))
                         for isite in indices:
                             if isite <0:
                                 raise IndexError
                             se.plot_environments(isite, additional_condition=se.AC.ONLY_ACB)
                         break
                    except ValueError:
                         print('This is not a valid site')
                    except IndexError:
                         print('This site is out of the site range')


            if no_vis:
                test = input('Go to next structure ? ("y" to do so)')
                if test == 'y':
                    break
                continue
            test = input('View structure with environments ? ("y" for the unit cell or "m" for a supercell or "n") : ')
            if test in ['y', 'm']:
                if test == 'm':
                    mydeltas = []
                    while True:
                        try:
                            test = input('Enter multiplicity (e.g. 3 2 2) : ')
                            nns = test.split()
                            for i0 in range(int(nns[0])):
                                for i1 in range(int(nns[1])):
                                    for i2 in range(int(nns[2])):
                                        mydeltas.append(np.array([1.0*i0, 1.0*i1, 1.0*i2], np.float))
                            break

                        except (ValueError,IndexError):
                            print('Not a valid multiplicity')
                else:
                    mydeltas = [np.zeros(3, np.float)]
                if firsttime:
                    vis = StructureVis(show_polyhedron=False, show_unit_cell=True)
                    vis.show_help = False
                    firsttime = False
                vis.set_structure(se.structure)
                strategy.set_structure_environments(se)
                for isite, site in enumerate(se.structure):
                    try:
                        ces = strategy.get_site_coordination_environments(site)
                    except NeighborsNotComputedChemenvError:
                        continue
                    if len(ces) == 0:
                        continue
                    ce = strategy.get_site_coordination_environment(site)
                    if ce is not None and ce[0] != UNCLEAR_ENVIRONMENT_SYMBOL:
                        for mydelta in mydeltas:
                            psite = PeriodicSite(site._species, site._fcoords + mydelta, site._lattice,
                                                 properties=site._properties)
                            vis.add_site(psite)
                            neighbors = strategy.get_site_neighbors(psite)
                            draw_cg(vis, psite, neighbors, cg=lgf.allcg.get_geometry_from_mp_symbol(ce[0]),
                                    perm=ce[1]['permutation'])
                vis.show()
            test = input('Go to next structure ? ("y" to do so) : ')
            if test == 'y':
                break
        print('')
    def figure_fractions(self, weights_options, morphing_factors=None):
        if morphing_factors is None:
            morphing_factors = np.linspace(1.0, 2.0, 21)
        # Set up the local geometry finder
        lgf = LocalGeometryFinder()
        lgf.setup_parameters(
            structure_refinement=lgf.STRUCTURE_REFINEMENT_NONE)
        # Set up the weights for the MultiWeights strategy
        weights = self.get_weights(weights_options)
        # Set up the strategy
        strat = MultiWeightsChemenvStrategy(
            dist_ang_area_weight=weights['DistAngArea'],
            self_csm_weight=weights['SelfCSM'],
            delta_csm_weight=weights['DeltaCSM'],
            cn_bias_weight=weights['CNBias'],
            angle_weight=weights['Angle'],
            normalized_angle_distance_weight=weights['NormalizedAngDist'])
        fake_valences = [-1] * (
            self.coordination_geometry.coordination_number + 1)
        fake_valences[0] = 1
        fractions_initial_environment = np.zeros_like(morphing_factors)
        fractions_final_environment = np.zeros_like(morphing_factors)
        for ii, morphing_factor in enumerate(morphing_factors):
            print(ii)
            struct = self.get_structure(morphing_factor=morphing_factor)
            print(struct)
            # Get the StructureEnvironments
            lgf.setup_structure(structure=struct)
            se = lgf.compute_structure_environments(only_indices=[0],
                                                    valences=fake_valences)
            strat.set_structure_environments(structure_environments=se)
            result = strat.get_site_coordination_environments_fractions(
                site=se.structure[0],
                isite=0,
                return_strategy_dict_info=True,
                return_all=True)
            for res in result:
                if res['ce_symbol'] == self.initial_environment_symbol:
                    fractions_initial_environment[ii] = res['ce_fraction']
                elif res[
                        'ce_symbol'] == self.expected_final_environment_symbol:
                    fractions_final_environment[ii] = res['ce_fraction']

        fig_width_cm = 8.25
        fig_height_cm = 7.0
        fig_width = fig_width_cm / 2.54
        fig_height = fig_height_cm / 2.54

        fig = plt.figure(num=1, figsize=(fig_width, fig_height))
        subplot = fig.add_subplot(111)

        subplot.plot(morphing_factors,
                     fractions_initial_environment,
                     'b-',
                     label='{}'.format(self.initial_environment_symbol),
                     linewidth=1.5)
        subplot.plot(morphing_factors,
                     fractions_final_environment,
                     'g--',
                     label='{}'.format(self.expected_final_environment_symbol),
                     linewidth=1.5)

        plt.legend(fontsize=8.0, loc=7)
        plt.show()
Example #20
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])
class CoordinationGeometryFinderTest(PymatgenTest):

    def setUp(self):
        self.lgf = LocalGeometryFinder()
        self.lgf.setup_parameters(centering_type='standard',
                                  structure_refinement=self.lgf.STRUCTURE_REFINEMENT_NONE)
    #     self.strategies = [SimplestChemenvStrategy(), SimpleAbundanceChemenvStrategy()]

    def test_abstract_geometry(self):
        cg_ts3 = self.lgf.allcg['TS:3']
        cg_tet = self.lgf.allcg['T:4']
        abstract_geom = AbstractGeometry.from_cg(cg=cg_ts3, centering_type='central_site')
        self.assertArrayAlmostEqual(abstract_geom.centre, [0.0, 0.0, 0.0])
        abstract_geom = AbstractGeometry.from_cg(cg=cg_ts3, centering_type='centroid')
        self.assertArrayAlmostEqual(abstract_geom.centre, [0.0, 0.0, 0.33333333333])
        with self.assertRaises(ValueError) as cm:
            AbstractGeometry.from_cg(cg=cg_ts3, centering_type='central_site',
                                     include_central_site_in_centroid=True)
        self.assertEqual(str(cm.exception), 'The center is the central site, no calculation of the centroid, '
                                            'variable include_central_site_in_centroid should be set to False')
        abstract_geom = AbstractGeometry.from_cg(cg=cg_ts3, centering_type='centroid',
                                                 include_central_site_in_centroid=True)
        self.assertArrayAlmostEqual(abstract_geom.centre, [0.0, 0.0, 0.25])

        self.assertEqual(abstract_geom.__str__(),
                         '\nAbstract Geometry with 3 points :\n'
                         '  [-1.    0.   -0.25]\n'
                         '  [ 1.    0.   -0.25]\n'
                         '  [0.   0.   0.75]\n'
                         'Points are referenced to the centroid (calculated with the central site) :\n'
                         '  [0.   0.   0.25]\n')

        symm_dict = symmetry_measure([[0.0, 0.0, 0.0]], [1.1, 2.2, 3.3])
        self.assertAlmostEqual(symm_dict['symmetry_measure'], 0.0)
        self.assertEqual(symm_dict['scaling_factor'], None)
        self.assertEqual(symm_dict['rotation_matrix'], None)

        tio2_struct = self.get_structure('TiO2')

        envs = self.lgf.compute_coordination_environments(structure=tio2_struct, indices=[0])
        self.assertAlmostEqual(envs[0][0]['csm'], 1.5309987846957258)
        self.assertAlmostEqual(envs[0][0]['ce_fraction'], 1.0)
        self.assertEqual(envs[0][0]['ce_symbol'], 'O:6')
        self.assertEqual(sorted(envs[0][0]['permutation']), sorted([0, 4, 1, 5, 2, 3]))

        self.lgf.setup_random_structure(coordination=5)
        self.assertEqual(len(self.lgf.structure), 6)

        self.lgf.setup_random_indices_local_geometry(coordination=5)
        self.assertEqual(self.lgf.icentral_site, 0)
        self.assertEqual(len(self.lgf.indices), 5)

        self.lgf.setup_ordered_indices_local_geometry(coordination=5)
        self.assertEqual(self.lgf.icentral_site, 0)
        self.assertEqual(self.lgf.indices, list(range(1, 6)))

        self.lgf.setup_explicit_indices_local_geometry(explicit_indices=[3, 5, 2, 0, 1, 4])
        self.assertEqual(self.lgf.icentral_site, 0)
        self.assertEqual(self.lgf.indices, [4, 6, 3, 1, 2, 5])

        LiFePO4_struct = self.get_structure('LiFePO4')
        isite = 10
        envs_LiFePO4 = self.lgf.compute_coordination_environments(structure=LiFePO4_struct, indices=[isite])
        self.assertAlmostEqual(envs_LiFePO4[isite][0]['csm'], 0.140355832317)
        nbs_coords = [np.array([6.16700437, -4.55194317, -5.89031356]),
                      np.array([4.71588167, -4.54248093, -3.75553856]),
                      np.array([6.88012571, -5.79877503, -3.73177541]),
                      np.array([6.90041188, -3.32797839, -3.71812416])]
        self.lgf.setup_structure(LiFePO4_struct)
        self.lgf.setup_local_geometry(isite, coords=nbs_coords)

        perfect_tet = AbstractGeometry.from_cg(cg=cg_tet,
                                               centering_type='centroid',
                                               include_central_site_in_centroid=False)
        points_perfect_tet = perfect_tet.points_wcs_ctwcc()
        res = self.lgf.coordination_geometry_symmetry_measures_fallback_random(coordination_geometry=cg_tet,
                                                                               NRANDOM=5,
                                                                               points_perfect=points_perfect_tet)
        permutations_symmetry_measures, permutations, algos, local2perfect_maps, perfect2local_maps = res
        for perm_csm_dict in permutations_symmetry_measures:
            self.assertAlmostEqual(perm_csm_dict['symmetry_measure'], 0.140355832317)

    #
    # def _strategy_test(self, strategy):
    #     files = []
    #     for (dirpath, dirnames, filenames) in os.walk(json_files_dir):
    #         files.extend(filenames)
    #         break
    #
    #     for ifile, json_file in enumerate(files):
    #         with self.subTest(json_file=json_file):
    #             f = open("{}/{}".format(json_files_dir, json_file), 'r')
    #             dd = json.load(f)
    #             f.close()
    #
    #             atom_indices = dd['atom_indices']
    #             expected_geoms = dd['expected_geoms']
    #
    #             struct = Structure.from_dict(dd['structure'])
    #
    #             struct = self.lgf.setup_structure(struct)
    #             se = self.lgf.compute_structure_environments_detailed_voronoi(only_indices=atom_indices,
    #                                                                           maximum_distance_factor=1.5)
    #
    #             #All strategies should get the correct environment with their default parameters
    #             strategy.set_structure_environments(se)
    #             for ienv, isite in enumerate(atom_indices):
    #                 ce = strategy.get_site_coordination_environment(struct[isite])
    #                 try:
    #                     coord_env = ce[0]
    #                 except TypeError:
    #                     coord_env = ce
    #                 #Check that the environment found is the expected one
    #                 self.assertEqual(coord_env, expected_geoms[ienv])
    #
    # def test_simplest_chemenv_strategy(self):
    #     strategy = SimplestChemenvStrategy()
    #     self._strategy_test(strategy)
    #
    # def test_simple_abundance_chemenv_strategy(self):
    #     strategy = SimpleAbundanceChemenvStrategy()
    #     self._strategy_test(strategy)

    def test_perfect_environments(self):
        allcg = AllCoordinationGeometries()
        indices_CN = {1: [0],
                      2: [1, 0],
                      3: [1, 0, 2],
                      4: [2, 0, 3, 1],
                      5: [2, 3, 1, 0, 4],
                      6: [0, 2, 3, 1, 5, 4],
                      7: [2, 6, 0, 3, 4, 5, 1],
                      8: [1, 2, 6, 3, 7, 0, 4, 5],
                      9: [5, 2, 6, 0, 4, 7, 3, 8, 1],
                      10: [8, 5, 6, 3, 0, 7, 2, 4, 9, 1],
                      11: [7, 6, 4, 1, 2, 5, 0, 8, 9, 10, 3],
                      12: [5, 8, 9, 0, 3, 1, 4, 2, 6, 11, 10, 7],
                      13: [4, 11, 5, 12, 1, 2, 8, 3, 0, 6, 9, 7, 10],
                      }

        for coordination in range(1, 14):
            for mp_symbol in allcg.get_implemented_geometries(coordination=coordination,
                                                              returned='mp_symbol'):
                cg = allcg.get_geometry_from_mp_symbol(mp_symbol=mp_symbol)
                self.lgf.allcg = AllCoordinationGeometries(only_symbols=[mp_symbol])
                self.lgf.setup_test_perfect_environment(mp_symbol, randomness=False,
                                                        indices=indices_CN[coordination],
                                                        random_translation='NONE', random_rotation='NONE',
                                                        random_scale='NONE')
                se = self.lgf.compute_structure_environments(only_indices=[0],
                                                             maximum_distance_factor=1.01*cg.distfactor_max,
                                                             min_cn=cg.coordination_number,
                                                             max_cn=cg.coordination_number,
                                                             only_symbols=[mp_symbol]
                                                             )
                self.assertAlmostEqual(se.get_csm(0, mp_symbol)['symmetry_measure'], 0.0, delta=1e-8,
                                       msg='Failed to get perfect environment with mp_symbol {}'.format(mp_symbol))

    def test_disable_hints(self):
        allcg = AllCoordinationGeometries()
        mp_symbol = 'SH:13'
        mp_symbols = ['SH:13', 'HP:12']
        cg = allcg.get_geometry_from_mp_symbol(mp_symbol=mp_symbol)
        mypoints = cg.points
        mypoints[-1] = [0.9*cc for cc in mypoints[-1]]
        self.lgf.allcg = AllCoordinationGeometries(only_symbols=[mp_symbol])
        self.lgf.setup_test_perfect_environment(mp_symbol, randomness=False,
                                                indices=[4, 11, 5, 12, 1, 2, 8, 3, 0, 6, 9, 7, 10],
                                                random_translation='NONE', random_rotation='NONE',
                                                random_scale='NONE', points=mypoints)
        se_nohints = self.lgf.compute_structure_environments(only_indices=[0],
                                                             maximum_distance_factor=1.02 * cg.distfactor_max,
                                                             min_cn=12,
                                                             max_cn=13,
                                                             only_symbols=mp_symbols,
                                                             get_from_hints=False
                                                             )
        se_hints = self.lgf.compute_structure_environments(only_indices=[0],
                                                           maximum_distance_factor=1.02 * cg.distfactor_max,
                                                           min_cn=12,
                                                           max_cn=13,
                                                           only_symbols=mp_symbols,
                                                           get_from_hints=True
                                                           )
        with self.assertRaises(KeyError):
            abc = se_nohints.ce_list[0][12]
            abc.minimum_geometries()
        self.assertAlmostEqual(se_hints.ce_list[0][13][0], se_nohints.ce_list[0][13][0])
        self.assertTrue(set(se_nohints.ce_list[0].keys()).issubset(set(se_hints.ce_list[0].keys())))