<jupyter_start><jupyter_text>Creating a MOF Collection Loading from path names.We can build a **MofCollection** from a list of paths to MOF CIF files. We can also specify the **analysis_folder** where all the results of the analyses perfromed on this MOF collection will be stored. The default value is analysis_folder = 'analysis_folder'.<jupyter_code>path_list = ['cif_files_example/HKUST-1_ASR_FIQCEN_clean.cif', 
             'cif_files_example/MgMOF-74_ASR_RAVVUH_clean.cif', 
             'cif_files_example/MOF-5_ASR_MIBQAR_clean.cif']

a_mof_collection = MofCollection(path_list = path_list, 
                                 analysis_folder="analysis_folder_example")

print("There are {} MOFs in the collection.".format(len(a_mof_collection)))
print(a_mof_collection)<jupyter_output><empty_output><jupyter_text>Loading CIFs from folder.It is often conveniet to load all the CIF files located in a specific folder. We can do this by using the **from_folder()** method to create the MofCollection object.<jupyter_code>a_mof_collection = MofCollection.from_folder(collection_folder="cif_files_example", 
                                             analysis_folder="analysis_folder_example")

print("There are {} MOFs in the collection.".format(len(a_mof_collection)))<jupyter_output><empty_output><jupyter_text>Loading selected CIFs from folder.We might have a large number of CIFs in a folder but are only interested in examing a small subset of them. To accomplish this we can create a MofCollection from a folder as before but this time provide the additional argument __name_list__ which is a list of the names of MOFs we are interested in. For example:<jupyter_code>a_mof_collection_name_list = MofCollection.from_folder(collection_folder="cif_files_example", 
                                                       analysis_folder="analysis_folder_example",
                                                       name_list=['HKUST-1_ASR_FIQCEN_clean.cif', 
                                                                  'MgMOF-74_ASR_RAVVUH_clean.cif', 
                                                                  'MOF-5_ASR_MIBQAR_clean.cif'])

print("There are {} MOFs in the collection.".format(len(a_mof_collection_name_list)))<jupyter_output><empty_output><jupyter_text>Filtering a CollectionBefore analyzing the MOFs in the collection we created we might want to filter the collection and keep only MOFs with certain characteristics, for example MOFs that contain certain metal atoms.We can do this using the **filter_collection()** method on the collection object. The CIF files that match the filter will be included to this collection.  Keep CIF files in original locationBy default the cif files will be still pointing to the original location. This might be useful if we want to analyze a subset of MOFs without copying over the files.<jupyter_code>co_coll = a_mof_collection.filter_collection(using_filter={"metal_species":["Co"]})<jupyter_output><empty_output><jupyter_text>Define a new CIF folder when filteringIf the keyword **new_collection_folder** is set when filtering a collection the CIF files will be coppied to that folder and paths for the CIF files of the collection will be updated to point to the new location.<jupyter_code>co_coll = a_mof_collection.filter_collection(using_filter={"metal_species":["Co"]}, 
                                             new_collection_folder="Co_mofs")<jupyter_output><empty_output><jupyter_text>Copy filtered collection laterThe third option is to create a filtered collection and explicitly copy the files at a later stage.<jupyter_code>co_coll = a_mof_collection.filter_collection(using_filter={"metal_species":["Co"], "non_metal_species":["C"]})
print(co_coll)
co_coll.copy_cifs(target_folder="Co_mofs")
print(co_coll)<jupyter_output><empty_output><jupyter_text>The same operations can be performed for any results that might be present using the **new_analysis_folder** keyword  or the **copy_results()** function.  Analyze a MOF CollectionOnce we have a MOF collection we can run the **analyse_mofs()** method on it, which will detect all the open metal sites (OMS) in the collection.<jupyter_code>a_mof_collection.analyse_mofs()<jupyter_output><empty_output><jupyter_text>How to overwrite resultsIf we try to re-run the analysis code it will by default only analyze MOFs for which no results can be found. This makes it easy to resume a calculation that ended prematurely.<jupyter_code>a_mof_collection.analyse_mofs()<jupyter_output><empty_output><jupyter_text>To control this behavior and force all the MOFs for which results exist to be reanalyzed we can set the keyword **overwrite** to True.<jupyter_code>a_mof_collection.analyse_mofs(overwrite=True)<jupyter_output><empty_output><jupyter_text>Run analysis in parallelSince every MOF can be analyzed separately we can parallelize the analysis by splitting the structures in batches and running each batch as a separate process. The number of batches is specified using the **num_batches** keyword for which the default value is 1. The structures are first ordered based on the square of the number of atoms and then split into batches. This ensures that all the batches will run roughly in the same time, which results in a time efficient completion of the analysis.<jupyter_code>a_mof_collection.analyse_mofs(num_batches=3, overwrite=True)<jupyter_output><empty_output><jupyter_text>Summarizing Results Summary for each metal typeWe can get a table that summarizes the findings for each metal type using the __summarize_results()__ function.<jupyter_code>a_mof_collection.summarize_results()<jupyter_output><empty_output><jupyter_text>Summary for each MOFWe can obtain a DataFrame for the OMS for each MOF using the __mof_oms_df__ variable of the __MofCollection__ object.<jupyter_code>mofs_df = a_mof_collection.mof_oms_df
print(mofs_df)<jupyter_output><empty_output><jupyter_text>We can then use standard pandas operations to select MOFs, for example, with certain metals or all MOFs that have OMS.<jupyter_code>print("MOFs that contain Cu")
print(mofs_df[mofs_df["Metal Types"].str.contains("Cu")])
print("\nMOFs that have OMS")
print(mofs_df[mofs_df["Has OMS"] == "Yes"])<jupyter_output><empty_output><jupyter_text>Filter collection using resultsFinally, we can use the filter function to isolate, for example, MOFs that have Co metal sites and that contain open metal sites. We can also copy the cif files and result files for this subset to new locations by providing values for the **new_collection_folder** and **new_analysis_folder** keywords.<jupyter_code>co_oms = a_mof_collection.filter_collection(using_filter={"metal_species":["Co"], "has_oms":True},
                                            new_collection_folder='Co_oms',
                                            new_analysis_folder='Co_oms_analysis')

print(co_oms)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.0685565519236332, 'fraction_numerical': 0.0014463407578825572, 'mean_word_length': 4.572119258662369, 'pattern_counts': {'":': 6, '<': 57, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 17, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '14', 'dir': 'jupyter-structured-clean-dedup', 'id': '449685', 'license': 'MIT', 'n_tokens_mistral': 1988, 'n_tokens_neox': 1910, 'n_words': 662, 'path': 'examples/example.ipynb', 'repo_name': 'emmhald/open_metal_detector', 'size': '6914'}