<SYSTEM_TASK:>
Given the following text description, write Python code to implement the functionality described below step by step
<END_TASK>
<USER_TASK:>
Description:
 Structure Prediction
In this notebook, we aim to do a test of the structure substitution algorithm implemented in SMACT
Before we can do predictions, we need to create our cation mutator, database and a table, and a list of hypothetical compositions
Procedure
Create a list of hypothetical compositions
Create a database of structures
Create Cation Mutator
Predict structures
Part 1
Step1:  Part 2
Step2:  Part 3
Step3:  Part 4
Step4:  Part 5
<ASSISTANT_TASK:>
Python Code:
comps=pd.read_csv("Li-Garnet_Comps_sus.csv")
comps.head()
Explanation: Structure Prediction
In this notebook, we aim to do a test of the structure substitution algorithm implemented in SMACT
Before we can do predictions, we need to create our cation mutator, database and a table, and a list of hypothetical compositions
Procedure
Create a list of hypothetical compositions
Create a database of structures
Create Cation Mutator
Predict structures
Part 1: Compositions
These compositions have generated in a different notebook and the results have been loaded in
End of explanation
DB=StructureDB("Test.db")
SP=StructurePredictor(CM, DB, "Garnets")
Explanation: Part 2: Database
Let's follow this procedure
1. Create a SMACT database and add a table which contains the result of our query
End of explanation
#Create the CationMutator class
#Here we use the default lambda table
CM=CationMutator.from_json()
Explanation: Part 3: Cation Mutator
In order to set up the cation mutator, we must do the following:
1. Generate a dataframe of lambda values for all species we which to consider
2. Instantiate the CationMutator class with the lambda dataframe
End of explanation
#Corrections
cond_df=CM.complete_cond_probs()
species=list(cond_df.columns)
comps_copy=comps[['A','B','C','D']]
df_copy_bool=comps_copy.isin(species)
x=comps_copy[df_copy_bool].fillna(0)
x=x[x.A != 0]
x=x[x.B != 0]
x=x[x.C != 0]
x=x[x.D != 0]
x=x.reset_index(drop=True)
#x.to_csv("./Garnet_Comps_Corrected_Pym.csv", index=False)
x.head()
inner_merged=pd.merge(x, comps)
inner_merged.to_csv("./Li-Garnet_Comps_Corrected_Pym.csv", index=False)
inner_merged.head()
print(inner_merged.head())
print("")
print(f"We have reduced our search space from {comps.shape[0]} to {inner_merged.shape[0]}")
#x=x[:100]
#Create a list of test species
test_specs_list=[[parse_spec(inner_merged["A"][i]),parse_spec(inner_merged["B"][i]),parse_spec(inner_merged["C"][i]),parse_spec(inner_merged["D"][i]) ] for i in range(inner_merged.shape[0])]
#Set up a for loop to store
from datetime import datetime
start = datetime.now()
from operator import itemgetter
preds=[]
parents_list=[]
probs_list=[]
for test_specs in test_specs_list:
    predictions=list(SP.predict_structs(test_specs, thresh=10e-4, include_same=False ))
    predictions.sort(key=itemgetter(1), reverse=True)
    parents = [x[2].composition() for x in predictions]
    probs = [x[1] for x in predictions]
    preds.append(predictions)
    parents_list.append(parents)
    probs_list.append(probs)
print(f"Time taken to predict the crystal structures of our search space of {inner_merged.shape[0]} with a threshold of 0.0001 is {datetime.now()-start} ")
#print(parents_list)
print("")
#print(probs_list)
Explanation: Part 4: Structure Prediction
Prerequisites: Part 1, Part 2 & Part 3
Procedure:
1. Instantiate the StructurePredictor class with the cation mutator (part 1), database (part 2) and table (part 2)
2. Predict Structures
3. Compare predicted structures with Database
End of explanation
#Add predictions to dataframe
import pymatgen as mg
pred_structs=[]
probs=[]
parent_structs=[]
parent_pretty_formula=[]
for i in preds:
    if len(i)==0:
        pred_structs.append(None)
        probs.append(None)
        parent_structs.append(None)
        parent_pretty_formula.append(None)
    else:
        pred_structs.append(i[0][0].as_poscar())
        probs.append(i[0][1])
        parent_structs.append(i[0][2].as_poscar())
        parent_pretty_formula.append(mg.Structure.from_str(i[0][2].as_poscar(), fmt="poscar").composition.reduced_formula)
#Add prediction results to dataframe
inner_merged["predicted_structure"]=pred_structs
inner_merged["probability"]=probs
inner_merged["Parent formula"]=parent_pretty_formula
inner_merged["parent_structure"]=parent_structs
inner_merged[35:40]
#output the intermediary results into a dataframe
outdir="./Li-SP_results"
if not os.path.exists(outdir):
    os.mkdir(outdir)
fullpath=os.path.join(outdir,"pred_results.csv")
inner_merged.to_csv(fullpath)
#Filter dataframe to remove blank entries from dataframe
results=inner_merged.dropna()
results=results.reset_index(drop=True)
results.head()
#Check if composition exists in our local database
in_db=[]
for i in results["predicted_structure"]:
    comp=SmactStructure.from_poscar(i).composition()
    if len(DB.get_structs(comp, "Garnets"))!=0:
        in_db.append("Yes")
    else:
        in_db.append("No")
results["In DB?"]=in_db
print(results["In DB?"].value_counts())
#Check the ratio of In DB?:Not in DB
in_db_count=results["In DB?"].value_counts()
from matplotlib import pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_axes([0,0,1,1])
ax.axis('equal')
ax.pie(in_db_count,labels=["No","Yes"], autopct='%1.2f%%')
plt.savefig(f"{outdir}/Li-Garnets_Li-In_DB_SP.png")
plt.show()
import seaborn as sns
import matplotlib.pyplot as plt
plt.figure(figsize=(8,6))
ax1=sns.histplot(data=results, x="probability", hue="In DB?",multiple="stack")
#ax2=sns.histplot(new_series, label="New Garnets")
#plt.savefig("Prediction_Probability_Distribution_pym.png")
g=sns.FacetGrid(results, col="In DB?", height=6, aspect=1)
g.map(sns.histplot,"probability")
g.savefig("./Li-SP_results/Prob_dist.png")
results.head()
#new_structures=
#pym_Li_DB=StructureDB("pym_Li.DB")
#pym_Li_DB.add_table("New")
#pym_Li_DB.add_table("not_new")
#pym_Li_DB.add_structs(new_structures,"New")
#pym_Li_DB.add_structs(exist_structures,"not_new")
#pym_Li_DB.add_table("not_new")
#pym_Li_DB.add_structs(new_structures,"New")
#pym_Li_DB.add_structs(exist_structures,"not_new")
#Periodic table BS
#Get element names
from pymatgen.util.plotting import periodic_table_heatmap
A_els=pd.Series([parse_spec(i)[0] for i in results["A"]])
B_els=pd.Series([parse_spec(i)[0] for i in results["B"]])
C_els=pd.Series([parse_spec(i)[0] for i in results["C"]])
#get dict of counts
A_els_counts=A_els.value_counts().to_dict()
B_els_counts=B_els.value_counts().to_dict()
C_els_counts=C_els.value_counts().to_dict()
ax1=periodic_table_heatmap(elemental_data=A_els_counts, cbar_label="Counts")
ax1.savefig(f"{outdir}/periodic_table_A.png")
ax2=periodic_table_heatmap(elemental_data=B_els_counts, cbar_label="Counts")
ax2.savefig(f"{outdir}/periodic_table_B.png")
ax3=periodic_table_heatmap(elemental_data=C_els_counts, cbar_label="Counts")
ax3.savefig(f"{outdir}/periodic_table_C.png")
Explanation: Part 5: Storing the results
End of explanation
<END_TASK>