Example #1
0
    def test_cap_atom(self):
        with self.subTest(msg="test hydrogen capping"):
            iz = Zeolite(
                Atoms('OSiOSi',
                      positions=[[0, 0, 0], [0, 0, -1], [0, 0, 1], [1, 1, 1]]))
            iz = iz.delete_atoms(2)  # delete Si
            iz = iz.cap_atoms()
            x = 0
            # self.assertEqual(len(iz), 3)
            for atom in iz:
                if atom.symbol == "H":
                    pass
                    # self.assertTrue(np.all(atom.position == np.array([0, 0, 1])))
                if atom.symbol == "O":
                    pass
                    # self.assertTrue(np.all(atom.position == np.array([0, 0, -1])))

        with self.subTest('oxygen and hydrogen capping'):
            cha = Zeolite.make('CHA')
            cha = cha.delete_atoms([i for i in range(0, 10)])
            for atom in cha:
                if atom.symbol == 'O':
                    atom.symbol = 'Po'

            cha = cha.cap_atoms()
            view(cha)
Example #2
0
    def test_register_with_parent(self):
        with self.subTest(msg='test simple case, no additions'):
            parent = PerfectZeolite.make('BEA')
            child = Zeolite.make('BEA')
            child = child.retag_self()
            child.register_with_parent(parent)
            self.assertEqual(parent.index_mapper, child.index_mapper)
            self.assertEqual(parent, child.parent_zeotype)
            self.assertIn(child.name, child.index_mapper.names)

        with self.subTest(msg='test additions'):
            parent = PerfectZeolite.make('BEA')
            additions_dict = copy.deepcopy(parent.additions)
            child = Zeolite.make('BEA')
            child = child.add_atoms(
                Atoms("H2", positions=[[0, 0, 0], [1, 1, 1]]),
                'H2').delete_atoms([1, 2, 3, 4])
            ads_map = child.build_additions_map()
            child.additions = additions_dict
            child = child.retag_self()
            child.register_with_parent(parent, ads_map)
            self.assertEqual(parent.index_mapper, child.index_mapper)
            self.assertEqual(parent, child.parent_zeotype)
            self.assertIn(child.name, child.index_mapper.names)
            name_list = []
            for key in ads_map:
                name_list.extend(list(ads_map[key]))
            for name in name_list:
                self.assertIn(name, child.index_mapper.names)
Example #3
0
 def test_build_cap_atoms(self):
     with self.subTest(msg="testing simple case"):
         cap_atoms_dict = {
             'H': [np.array([0, 0, 0])],
             'O': [np.array([1, 2, 3])],
             'N': [np.array([1, 3, 5])]
         }
         cap_atoms = Zeolite.build_cap_atoms(cap_atoms_dict)
         for atom in cap_atoms:
             self.assertIn(atom.symbol, cap_atoms_dict)
             self.assertCountEqual(cap_atoms_dict[atom.symbol][0],
                                   atom.position)
     with self.subTest(msg="testing multi atoms of same type"):
         cap_atoms_dict = {
             'H': [np.array([0, 0, 0]),
                   np.array([1, 1, 1])],
             'O': [np.array([3, 3, 3]),
                   np.array([3, 4, 5])]
         }
         cap_atoms = Zeolite.build_cap_atoms(cap_atoms_dict)
         # this complicated for loop checks that the position is in the
         for atom in cap_atoms:
             array_in = False
             for pos in cap_atoms_dict[atom.symbol]:
                 all_equal = True
                 for dict_el, atom_el in zip(pos, atom.position):
                     if dict_el != atom_el:
                         all_equal = False
                         break
                 if all_equal:
                     array_in = True
                     break
             self.assertTrue(array_in)
Example #4
0
    def test_build_iz_from_z(self):
        tmp_goo = PerfectZeolite.make('GOO')
        z = PerfectZeolite.build_from_cif_with_labels('data/GOO.cif')
        iz = Zeolite(z)
        # tests inheritance
        self.assertIsInstance(iz, Zeolite)
        self.assertIsInstance(iz, PerfectZeolite)
        self.assertIsInstance(iz, Atoms)
        # tests empty list attributes
        # tests corretly defined parameters
        self.assertEqual(iz._site_to_atom_indices, None)
        self.assertEqual(iz._atom_indices_to_site, None)
        #self.assertEqual(iz.name)
        self.assertEqual(iz.parent_zeotype, z)
        #tests atoms are there and behave the same
        self.assertCountEqual(iz.get_tags(), z.get_tags())
        self.assertCountEqual(iz.get_chemical_symbols(),
                              z.get_chemical_symbols())
        self.assertEqual(id(iz.parent_zeotype), id(z.parent_zeotype))
        self.assertEqual(id(iz.index_mapper), id(z.index_mapper))
        self.assertEqual(id(iz.parent_zeotype), id(z.parent_zeotype))
        self.assertNotEqual(iz.index_mapper, None)

        self.assertEqual(iz.parent_zeotype, z)
        self.assertEqual(iz.index_mapper, z.index_mapper)
        self.assertEqual(iz.index_mapper, z.index_mapper)
Example #5
0
    def __init__(self,
                 iza_code=None,
                 optimized_zeolite_path=None,
                 user_input_path=None):
        """ This is an extra-framework class
        :param iza_code: 3 letter code for the zeolite structures (IZA database)
        """
        if iza_code is not None:
            self.EFzeolite = Zeolite.make(iza_code)
        if optimized_zeolite_path is not None:
            read_vasp(optimized_zeolite_path, Zeolite.make(iza_code))
        if user_input_path is not None:
            # self.EFzeolite = read(user_input_path, '0')
            self.EFzeolite = Zeolite(
                PerfectZeolite.build_from_cif_with_labels(
                    filepath=user_input_path))

        self.t_site_indices = {}
        self.t_site_indices_count = {}
        self.traj_1Al = []
        self.traj_2Al = []
        self.count_all_Al_pairs = 0
        self.TM_list = ['Pt', 'Cu', 'Co', 'Pd', 'Fe', 'Cr', 'Rh', 'Ru']
        self.dict_1Al_replaced = {}
        self.dict_2Al_replaced = {}
        self.T_site_pair = []
        self.T_index_pair = []
Example #6
0
def read_zeolite(binary_filepath: str,
                 parent_zeolite: PerfectZeolite,
                 json_filepath: Optional[str] = None) -> Zeolite:
    if json_filepath:
        with open(json_filepath, 'r') as f:
            attr_dict = json.load(f)
        additions_map = attr_dict['additions_maps']
    else:
        additions_map = None

    z = Zeolite(read(binary_filepath))
    z.register_with_parent(parent_zeolite, additions_map)
    return z
Example #7
0
 def test__check_unique_positions(self):
     overlapping = Atoms('H2')
     non_overlapping = Atoms('H2', positions=[[0, 0, 0], [1, 1, 1]])
     with self.subTest('check if non_overlapping pass'):
         try:
             Zeolite._check_unique_positions(
                 non_overlapping.get_positions())
             self.assertTrue(True)
         except ValueError:
             self.fail('error thrown in wrong case')
     with self.subTest('check if overlapping fail'):
         try:
             Zeolite._check_unique_positions(overlapping.get_positions())
             self.fail('error not thrown')
         except ValueError:
             self.assertTrue(True)
Example #8
0
    def test_get_cluster(self):
        iz = Zeolite.make('BEA')
        cluster, od = iz.get_cluster(174)

        with self.subTest(msg='testing length is valid'):
            self.assertEqual(len(cluster) + len(od), len(iz))

        with self.subTest(msg='assert ztype correct'):
            self.assertEqual(iz.ztype, 'Zeolite')
            self.assertEqual(cluster.ztype, 'Cluster')
            self.assertEqual(od.ztype, 'Open Defect')

        with self.subTest(msg='assert name is correct'):
            self.assertIn('Cluster', cluster.name)
            self.assertIn('Open Defect', od.name)

        with self.subTest(msg='test names registered with index mapper'):
            # check names are in
            self.assertIn(cluster.name, iz.index_mapper.names)
            self.assertIn(od.name, iz.index_mapper.names)
            self.assertIn(iz.name, iz.index_mapper.names)

        with self.subTest(msg='test indices are in index mapper'):
            self.assertTrue(iz.index_mapper.get_reverse_main_index(iz.name))
            self.assertTrue(
                cluster.index_mapper.get_reverse_main_index(iz.name))
            self.assertTrue(od.index_mapper.get_reverse_main_index(iz.name))
Example #9
0
def read_vasp(optimized_zeolite_path: str,
              unoptimized_zeolite: Zeolite,
              atoms_sorted: bool = False):
    opt_atoms = read(optimized_zeolite_path)
    new, old = _make_sort(unoptimized_zeolite)
    if sorted:
        old_to_new_map = dict(zip(old, new))
    else:
        old_to_new_map = dict(zip(old, old))

    opt_zeolite = Zeolite(unoptimized_zeolite)

    for atom in opt_zeolite:
        opt_zeolite[atom.index].symbol = opt_atoms[old_to_new_map[
            atom.index]].symbol
        opt_zeolite[atom.index].position = opt_atoms[old_to_new_map[
            atom.index]].position
        opt_zeolite[atom.index].tag = opt_atoms[old_to_new_map[atom.index]].tag
        opt_zeolite[atom.index].momentum = opt_atoms[old_to_new_map[
            atom.index]].momentum
        opt_zeolite[atom.index].mass = opt_atoms[old_to_new_map[
            atom.index]].mass
        opt_zeolite[atom.index].magmom = opt_atoms[old_to_new_map[
            atom.index]].magmom
        opt_zeolite[atom.index].charge = opt_atoms[old_to_new_map[
            atom.index]].charge

    return opt_zeolite
Example #10
0
    def test_add_atoms(self):
        iz = Zeolite.make('BEA')
        iz_name_index = int(str(iz.name.split('_')[-1]))
        n3 = Atoms('N3', [(0, 0, 0), (1, 0, 0), (0, 0, 1)])
        addition_type = 'fish'
        addition_name = addition_type + '_' + str(iz_name_index + 1)
        iz2 = iz.add_atoms(n3, addition_type)
        with self.subTest(msg='test that added atom is in the index map'):
            self.assertIn(
                addition_name,
                iz2.index_mapper.names)  # this should be the second addition
        with self.subTest(msg='test that added atoms is in additions'):
            self.assertIn(addition_name, iz2.additions[addition_type])
        with self.subTest(msg='test that the length is correct'):
            self.assertEqual(len(iz2), len(iz) + len(n3))
        with self.subTest(msg='test mapping between n3 and iz'):
            for atom in n3:
                iz_index = iz2.index_mapper.get_index(addition_name, iz2.name,
                                                      atom.index)
                self.assertIsNotNone(iz_index)
                for p1, p2 in zip(atom.position, iz2[iz_index].position):
                    self.assertEqual(p1, p2)
                self.assertEqual(atom.symbol, iz2[iz_index].symbol)
                self.assertEqual(atom.tag, iz2[iz_index].tag)

        with self.subTest(
                msg='test that all of the indices of the main z are there'):
            for key, value in iz2.index_mapper.main_index.items():
                self.assertIsNotNone(value[iz2.name])
Example #11
0
    def replace_2Al_unique_pairs(self, cutoff_radius=9):
        """ This function makes the 2 Al replacement for all possible pairs (not limited to unique T-site pairs since
        even though the binding energies might be the same, the geometric properties, such as, Al-Al distance, are
        different). Replacement obeys the Lowenstein's rule, and Al pairs with distance greater than the"cutoff_radius"
        are ignored.
        :param cutoff_radius: replace the second Si site within some cutoff radius (9 Angstrom by default) around the
        first replacement site which is done using function "replace_1Al".
        :return:
        """
        done_indices = []
        for site_name_1Al, traj_1Al in self.dict_1Al_replaced.items():
            index_Al = [a.index for a in traj_1Al[0] if a.symbol == 'Al'][0]
            neighboring_Si = []
            neigh_o_indices, offsets = traj_1Al[0].neighbor_list.get_neighbors(
                index_Al)
            for each_neigh_o_index in neigh_o_indices:
                neigh_si_indices, offsets = traj_1Al[
                    0].neighbor_list.get_neighbors(each_neigh_o_index)
                [
                    neighboring_Si.append(each_neigh_si_index)
                    for each_neigh_si_index in neigh_si_indices
                    if each_neigh_si_index != index_Al
                ]

            for zeolite in traj_1Al:
                atoms = Zeolite(zeolite)
                ini_atoms = copy.copy(atoms)
                for index in [a.index for a in atoms if a.symbol == 'Si']:
                    sorted_pair = list(np.sort([index, index_Al]))
                    if index not in neighboring_Si and sorted_pair not in done_indices:
                        if 3.3 < atoms.get_distance(index_Al, index,
                                                    mic=True) < cutoff_radius:
                            site_name_2Al = ini_atoms.atom_indices_to_sites[
                                index]
                            if int(site_name_2Al[1:]) >= int(
                                    site_name_1Al[1:]):
                                self.T_site_pair.append(
                                    [site_name_1Al, site_name_2Al])
                                self.T_index_pair.append([index_Al, index])
                                new_z_type = atoms.ztype + 'AND' + site_name_2Al + '->Al'
                                atoms = Zeolite(ini_atoms, ztype=new_z_type)
                                atoms[index].symbol = 'Al'
                                self.traj_2Al.append(atoms)
                                self.count_all_Al_pairs += 1
                                done_indices.append(sorted_pair)
Example #12
0
 def test_retag_self(self):
     with self.subTest(msg="retag doesn't throw errrors"):
         cha = Zeolite.make('CHA')
         cha = cha.retag_self()
     with self.subTest(msg='test main index matches tags'):
         reverse_index_map = cha.index_mapper.get_reverse_main_index(
             cha.name)
         for atom in cha:
             self.assertEqual(atom.tag, reverse_index_map[atom.index])
Example #13
0
    def test_build_additions_map(self):
        z = Zeolite.make('CHA')
        water = Adsorbate(
            Atoms('H2O', positions=[[-1, -1, 0], [0, 0, 0], [1, 1, 0]]))
        z, ads = z.integrate_adsorbate(water)
        z, ads = z.integrate_adsorbate(water)
        z, ads = z.integrate_adsorbate(water)

        print(z.build_additions_map())
Example #14
0
 def test_wrap_self(self):
     bea = Zeolite.make("BEA")
     bea_wrapped = bea.wrap_self()
     for value in bea_wrapped.index_mapper.main_index.values():
         self.assertEqual(value[bea.name], value[bea_wrapped.name])
     for a1, a2 in zip(bea, bea_wrapped):
         for p1, p2 in zip(a1.position, a2.position):
             if p1 != p2:
                 pass
Example #15
0
    def test_workflow(self):
        def change_atoms(atoms):
            for atom in atoms:
                if atom.symbol == 'Si' and atom.tag != 154:
                    atoms[atom.index].symbol = 'Sn'

        bea = Zeolite.make('BEA')
        cluster = bea.get_cluster(154)[0].cap_atoms().apply(
            change_atoms).remove_caps()
        bea_sn = bea.integrate(cluster)
Example #16
0
    def test_remove_caps(self):
        bea = Zeolite.make('BEA')
        cluster, od = bea.get_cluster(154)
        with self.subTest('testing removing caps without arguments'):
            capped_cluster = cluster.cap_atoms()
            uncapped_cluster = capped_cluster.remove_caps()
            for cap_type in uncapped_cluster.additions.keys():
                if 'cap' not in cap_type:
                    continue
                self.assertFalse(
                    uncapped_cluster.additions[cap_type])  # assert empty
            self.assertEqual(
                len(uncapped_cluster),
                len(cluster),
                msg='num atoms in uncapped = num atoms in original')
            for atom in uncapped_cluster:
                self.assertFalse(atom.symbol == 'H',
                                 msg='no hydrogen in uncapped cluster'
                                 )  # check for no hydrogens

        with self.subTest('testing oxygen and hydrogen caps'):
            cluster_wo_o = cluster.delete_atoms([1])
            capped_cluster = cluster_wo_o.cap_atoms()
            uncapped_cluster = capped_cluster.remove_caps()
            for cap_type in uncapped_cluster.additions.keys():
                if 'cap' not in cap_type:
                    continue
                self.assertFalse(
                    uncapped_cluster.additions[cap_type])  # assert empty
            self.assertEqual(len(uncapped_cluster), len(cluster_wo_o),
                             'num atoms in uncapped = num atoms in original')
            for atom in uncapped_cluster:
                self.assertFalse(atom.symbol == 'H',
                                 msg='no hydrogen in uncapped cluster'
                                 )  # check for no hydrogens

        with self.subTest('remove only H caps'):
            cluster_wo_o = cluster.delete_atoms([1])
            capped_cluster = cluster_wo_o.cap_atoms()
            uncapped_cluster = capped_cluster.remove_caps(cap_type='h_cap')
            for cap_type in uncapped_cluster.additions.keys():
                if 'h_cap' not in cap_type:
                    continue
                self.assertFalse(
                    uncapped_cluster.additions[cap_type])  # assert empty
            self.assertEqual(
                len(uncapped_cluster),
                len(cluster),
                msg='num atoms in uncapped = num atoms in original')
            for atom in uncapped_cluster:
                self.assertFalse(atom.symbol == 'H',
                                 msg='no hydrogen in uncapped cluster'
                                 )  # check for no hydrogens

        view(uncapped_cluster)
Example #17
0
 def test_integrate_adsorbate(self):
     iz = Zeolite.make('BEA')
     n3 = Atoms('N3', [(0, 0, 0), (1, 0, 0), (0, 0, 1)])
     n3_ads = Adsorbate(n3, name='n3')
     iz2, n3_ads2 = iz.integrate_adsorbate(n3_ads)
     with self.subTest(msg='test index map integration'):
         self.assertIn(n3_ads2.name, iz2.index_mapper.names)
     with self.subTest(msg='test lengths make sense'):
         self.assertEqual(len(iz2), len(iz) + len(n3_ads))
     with self.subTest(
             msg='Test that adsorbate name is in additions adsorbate list'):
         self.assertIn(n3_ads2.name, list(iz2.additions['adsorbate']))
Example #18
0
    def test_translate_self(self):
        bea = Zeolite.make("BEA")
        bea_translated = bea.translate_self([5, 5, 5])
        with self.subTest('test mapping preserved'):
            for value in bea_translated.index_mapper.main_index.values():
                self.assertEqual(value[bea.name], value[bea_translated.name])

        with self.subTest('test for no overlap'):
            for a1, a2 in zip(bea, bea_translated):
                for p1, p2 in zip(a1.position, a2.position):
                    if p1 != p2:
                        break
                else:
                    self.fail("Overlapping atoms found")
Example #19
0
 def test_get_self_to_main_index_map(self):
     # TODO: This function isn't needed and can be removed
     import pandas as pd
     z = Zeolite.make('BEA')
     z = z.add_atoms(Atoms("H2", positions=[[0, 0, 0], [1, 1, 1]]),
                     'H2').delete_atoms([1, 2, 3, 4]).cap_atoms()
     for atom in z:
         if atom.index == 194:
             atom.symbol = 'He'
     view(z)
     print(z.additions['o_caps'])
     # z = z.add_atoms(Atoms("H2", positions=[[0,0,0], [1,1,1]]), 'H2') #.cap_atoms()
     df = pd.DataFrame(z.index_mapper.main_index)
     print(df.T.to_string())
Example #20
0
 def test_remove_adsorbate(self):
     iz = Zeolite.make('BEA')
     n3 = Atoms('N3', [(0, 0, 0), (1, 0, 0), (0, 0, 1)])
     n3_ads = Adsorbate(n3, name='n3')
     iz2, n3_ads2 = iz.integrate_adsorbate(n3_ads)
     iz3 = iz2.remove_adsorbate(n3_ads2)
     with self.subTest(msg='test that adsorbate is still in index map'):
         self.assertIn(n3_ads2.name, iz3.index_mapper.names)
     with self.subTest(msg='test length back to original length'):
         self.assertEqual(len(iz3), len(iz))
     with self.subTest(
             msg=
             'Test that adsorbate name is not in additions adsorbate list'):
         self.assertNotIn(n3_ads2.name, list(iz3.additions['adsorbate']))
Example #21
0
    def test_get_oxygen_cap_pos(self):
        cha = Zeolite.make('CHA')
        cha = cha.delete_atoms([i for i in range(0, 10)])
        atoms_to_cap = []
        for atom in cha:
            if atom.symbol == 'O':
                if cha.needs_cap(atom.index, 2):
                    atoms_to_cap.append(atom.index)
            if atom.symbol == 'Si':
                if cha.needs_cap(atom.index, 4):
                    atoms_to_cap.append(atom.index)

        for index in atoms_to_cap:
            oxygen_cap_pos = cha.get_oxygen_cap_pos(index)
Example #22
0
    def test_read_zeotypes(self):
        output_filepath = 'zeolite_output/test_zeo'
        cha = Zeolite.make('CHA')
        cha2 = cha.delete_atoms(cha.site_to_atom_indices['T1'])
        water = Atoms("HHeO", positions=[[1,1,1], [0,0,0], [-1, -1, -1]])
        #water = Atoms("HO", positions=[[0,0,0], [-1, -1, -1]])

        cha3 = cha2.add_atoms(water, 'water')
        zeolite_list = [cha, cha2, cha3, cha3.parent_zeotype]
        save_zeolites(output_filepath, zeolite_list, zip=False)
        folder_file_list = glob.glob(output_filepath + '/**')

        with self.subTest('test that folders have been made'):
            for z in zeolite_list:
                self.assertIn(os.path.join(output_filepath, z.name), folder_file_list)
Example #23
0
    def test_apply(self):
        with self.subTest('test simple substitution'):
            bea = Zeolite.make("BEA")
            sites_to_change = bea.site_to_atom_indices['T1']

            def fun(atoms):
                for a in atoms:
                    if a.index in sites_to_change:
                        atoms[a.index].symbol = 'Sn'

            bea2 = bea.apply(fun)
            self.assertEqual(bea2.parent_zeotype, bea.parent_zeotype)
            self.assertIn(bea2.name, bea.index_mapper.names)
            for t1 in bea2.site_to_atom_indices['T1']:
                self.assertEqual(bea2[t1].symbol, 'Sn')
Example #24
0
 def replace_1Al(self):
     """ This function takes in a perfect zeolite and replace one Si atom with an Al for every T site. The atomic
     index of the T-site before and after Al replacement are kept fixed, while only the atom type is changing.
     :return: a dictionary of trajectories for each T site tags
     """
     self.get_t_sites()
     for site_name, t_site in self.t_site_indices.items():
         traj_t_sites = []
         for count, index in enumerate(t_site):
             new_zeo = copy.copy(self.EFzeolite)
             new_zeo[index].symbol = 'Al'
             new_ztype = new_zeo.ztype + site_name + '->Al'
             new_zeo = Zeolite(new_zeo, ztype=new_ztype)
             self.traj_1Al.append(new_zeo)
             traj_t_sites.append(new_zeo)
         self.dict_1Al_replaced[site_name] = traj_t_sites
Example #25
0
 def test_delete_atoms(self):
     iz = Zeolite.make('BEA')
     sites_to_delete = iz.site_to_atom_indices['T1']
     iz2 = iz.delete_atoms(sites_to_delete)
     with self.subTest(msg='Test that the lengths are correct'):
         self.assertEqual(len(iz2) + len(sites_to_delete), len(iz))
     with self.subTest(msg='Test that the T sites are removed'):
         self.assertFalse(iz2.site_to_atom_indices['T1'])
     with self.subTest(
             msg='test that all sites in iz2 are mappable to iz1'):
         for atom in iz2:
             iz_index = iz2.index_mapper.get_index(iz2.name, iz.name,
                                                   atom.index)
             self.assertIsNotNone(iz_index)
             for p1, p2 in zip(atom.position, iz[iz_index].position):
                 self.assertEqual(p1, p2)
             self.assertEqual(atom.symbol, iz[iz_index].symbol)
             self.assertEqual(atom.tag, iz[iz_index].tag)
     with self.subTest(msg='test that T sites map to None'):
         for T1_site in iz.site_to_atom_indices['T1']:
             self.assertIsNone(
                 iz.index_mapper.get_index(iz.name, iz2.name, T1_site))
Example #26
0
def main():
    cha = Zeolite.make('CHA')
    cluster, od = cha.get_cluster(10)
Example #27
0
 def test_integrate(self):
     iz = Zeolite.make('BEA')
     cluster, od = iz.get_cluster(174)
     with self.subTest(msg='integrate other zeolite'):
         new_iz = cluster.integrate(od)
         self.assertEqual(len(new_iz), len(iz))
Example #28
0
def read_zeolites(file_path: str,
                  str_ext: str = '.traj',
                  zipped: bool = True,
                  glob_cmd: Optional[str] = None) -> Dict[str, PerfectZeolite]:
    """
    Read the zeolites from a .zeo file or folder or folder
    :param file_path: path to .zeo file with or without .zeo extension or path to unzipped zeo folder
    :type file_path: str
    :param str_ext: type of files in .zeo zip file
    :type str_ext: str
    :param glob_cmd: regular expression to select from folder structure
    :type glob_cmd: str
    :return: Dictionary of Zeotypes loaded from the files
    :rtype: Dict[str, PerfectZeolite]
    """
    if zipped:
        if '.' not in file_path:
            file_path = file_path + '.zeo'
        folder_path = unpack_zeo_file(file_path)
    else:
        folder_path = file_path

    zeotype_dict = {}
    folder_list = glob.glob(os.path.join(folder_path, '*/'))

    # read parent zeolite
    try:
        parent_folder = [
            folder for folder in folder_list if Path(folder).stem == 'parent'
        ][0]
    except IndexError as e:
        raise FileExistsError(
            'parent folder not found in specified directory') from e

    # get parent zeolite binary file
    # use regex binary command
    if glob_cmd:
        binary_glob_cmd = glob_cmd
    else:
        binary_glob_cmd = '*' + str_ext

    binary_filepath = glob.glob(os.path.join(parent_folder,
                                             binary_glob_cmd))[0]
    json_filepath = glob.glob(os.path.join(parent_folder, '*.json'))[0]
    index_mapper_filepath = glob.glob(
        os.path.join(folder_path, 'index_mapper.json'))[0]
    parent_zeolite = read_parent_zeolite(binary_filepath, json_filepath,
                                         index_mapper_filepath)
    zeotype_dict['parent'] = parent_zeolite

    for folder in folder_list:
        if folder == parent_folder:
            continue

        name = Path(folder).stem
        json_path = os.path.join(folder, name + '.json')
        binary_path = os.path.join(folder, name + str_ext)
        with open(json_path, 'r') as f:
            my_zeotype = Zeolite(read(binary_path))
            attr_dict = json.load(f)
            my_zeotype.name = name
            additions_map = attr_dict['additions_map']

        my_zeotype.register_with_parent(parent_zeolite, additions_map)
        zeotype_dict[name] = my_zeotype

    if zipped:
        delete_folder(folder_path)

    return zeotype_dict