Metal-Organic Framework (MOF) Property Prediction¶
The fr5.property_prediction_mof module provides machine learning models for predicting key properties of Metal-Organic Frameworks (MOFs). These models enable rapid screening of MOF databases and prediction of properties for novel MOF structures.
Overview¶
Metal-Organic Frameworks are crystalline porous materials with applications in:
- Gas separation and storage (CO₂, H₂, CH₄)
- Catalysis as supports and active catalysts
- Sensors for gas detection
- Drug delivery and biomedical applications
- Water harvesting from air
Accurate property prediction is essential for: - High-throughput virtual screening of MOF databases - Rational design of MOFs for specific applications - Process optimization for gas separation - Cost reduction by minimizing experimental synthesis
Supported Properties¶
💨 CO₂ Uptake Prediction¶
Predict CO₂ adsorption capacity at various conditions:
from fr5.property_prediction_mof import predict_co2_uptake
# Predict CO₂ uptake for a MOF structure
result = predict_co2_uptake(
mof_structure='HKUST-1.cif', # CIF file path
pressure=1.0, # bar
temperature=298.15, # Kelvin
return_uncertainty=True
)
print(f"CO₂ uptake: {result['uptake']:.2f} mmol/g")
print(f"Uncertainty: ±{result['uncertainty']:.2f} mmol/g")
Alternative input methods:
# From MOF descriptors
result = predict_co2_uptake(
descriptors={
'pore_volume': 1.23, # cm³/g
'surface_area': 1847, # m²/g
'pore_diameter': 12.4, # Å
'density': 0.887 # g/cm³
},
pressure=1.0,
temperature=298.15
)
# From MOF database entry
result = predict_co2_uptake(
mof_name='HKUST-1',
database='CoRE_MOF',
pressure=1.0,
temperature=298.15
)
Model Details: - Algorithm: Random Forest with pressure-temperature features - Training data: 3,000+ experimental measurements from CoRE MOF database - Pressure range: 0.1-100 bar - Temperature range: 273-373 K - RMSE: 0.8 mmol/g on validation set
🏗️ Pore Properties Prediction¶
Predict structural properties from MOF composition:
from fr5.property_prediction_mof import predict_pore_properties
# Predict multiple pore properties
pore_props = predict_pore_properties(
mof_structure='UiO-66.cif',
properties=['pore_volume', 'surface_area', 'pore_diameter']
)
print(f"Pore volume: {pore_props['pore_volume']:.3f} cm³/g")
print(f"Surface area: {pore_props['surface_area']:.0f} m²/g")
print(f"Pore diameter: {pore_props['pore_diameter']:.1f} Å")
⚡ Gas Selectivity Prediction¶
Predict selectivity for gas separation applications:
from fr5.property_prediction_mof import predict_gas_selectivity
# Predict CO₂/N₂ selectivity
selectivity = predict_gas_selectivity(
mof_structure='ZIF-8.cif',
gas_pair=['CO2', 'N2'], # Gas mixture
composition=[0.15, 0.85], # Mole fractions
pressure=1.0,
temperature=298.15
)
print(f"CO₂/N₂ selectivity: {selectivity['selectivity']:.1f}")
print(f"CO₂ uptake: {selectivity['co2_uptake']:.2f} mmol/g")
print(f"N₂ uptake: {selectivity['n2_uptake']:.2f} mmol/g")
MOF Descriptor Types¶
Geometric Descriptors¶
Structural and pore-related properties:
from fr5.property_prediction_mof import calculate_geometric_descriptors
geom_desc = calculate_geometric_descriptors('MOF-5.cif')
print(f"Geometric descriptors:")
print(f" Pore volume: {geom_desc['pore_volume']:.3f} cm³/g")
print(f" Surface area: {geom_desc['surface_area']:.0f} m²/g")
print(f" Largest cavity diameter: {geom_desc['lcd']:.1f} Å")
print(f" Pore limiting diameter: {geom_desc['pld']:.1f} Å")
print(f" Framework density: {geom_desc['density']:.3f} g/cm³")
Topological Descriptors¶
Network topology and connectivity:
from fr5.property_prediction_mof import calculate_topological_descriptors
topo_desc = calculate_topological_descriptors('IRMOF-1.cif')
print(f"Topological descriptors:")
print(f" Net topology: {topo_desc['topology']}")
print(f" Coordination number: {topo_desc['coordination_number']}")
print(f" Vertex symbol: {topo_desc['vertex_symbol']}")
print(f" Space group: {topo_desc['space_group']}")
Chemical Descriptors¶
Elemental composition and bonding:
from fr5.property_prediction_mof import calculate_chemical_descriptors
chem_desc = calculate_chemical_descriptors('MIL-101.cif')
print(f"Chemical descriptors:")
print(f" Metal content: {chem_desc['metal_content']:.1f} wt%")
print(f" Organic content: {chem_desc['organic_content']:.1f} wt%")
print(f" Functional groups: {chem_desc['functional_groups']}")
print(f" Electronegativity: {chem_desc['electronegativity']:.2f}")
Advanced Features¶
Multi-Component Adsorption¶
Predict adsorption of gas mixtures:
from fr5.property_prediction_mof import predict_mixture_adsorption
# CO₂/CH₄/N₂ mixture adsorption
mixture_result = predict_mixture_adsorption(
mof_structure='ZIF-8.cif',
gas_mixture={
'CO2': 0.10, # 10% CO₂
'CH4': 0.20, # 20% CH₄
'N2': 0.70 # 70% N₂
},
pressure=10.0, # bar
temperature=298.15
)
for gas, uptake in mixture_result['individual_uptakes'].items():
print(f"{gas} uptake: {uptake:.2f} mmol/g")
print(f"Total uptake: {mixture_result['total_uptake']:.2f} mmol/g")
Temperature-Pressure Sweeps¶
Predict property variation across conditions:
from fr5.property_prediction_mof import temperature_pressure_sweep
# Create isotherms and isobars
sweep_results = temperature_pressure_sweep(
mof_structure='HKUST-1.cif',
temperatures=[273, 298, 323, 348], # K
pressures=[0.1, 1, 10, 100], # bar
gas='CO2'
)
# Plot isotherms
import matplotlib.pyplot as plt
for temp in sweep_results['temperatures']:
plt.plot(sweep_results['pressures'],
sweep_results['uptakes'][temp],
label=f'{temp} K')
plt.xlabel('Pressure (bar)')
plt.ylabel('CO₂ Uptake (mmol/g)')
plt.legend()
plt.show()
Uncertainty Quantification¶
Get prediction confidence intervals:
from fr5.property_prediction_mof import predict_with_uncertainty
# Prediction with confidence intervals
result = predict_with_uncertainty(
mof_structure='novel_mof.cif',
property='co2_uptake',
conditions={'pressure': 1.0, 'temperature': 298.15},
confidence_level=0.95
)
print(f"Predicted uptake: {result['prediction']:.2f} mmol/g")
print(f"95% CI: [{result['ci_lower']:.2f}, {result['ci_upper']:.2f}] mmol/g")
print(f"Prediction reliability: {result['reliability']}")
Batch Processing¶
High-Throughput Screening¶
Screen large MOF databases:
from fr5.property_prediction_mof import screen_mof_database
# Screen CoRE MOF database
screening_results = screen_mof_database(
database_path='CoRE_MOF_structures/',
properties=['co2_uptake', 'selectivity_co2_n2'],
conditions={'pressure': 1.0, 'temperature': 298.15},
filters={
'pore_volume': (0.5, 3.0), # cm³/g
'surface_area': (500, 3000), # m²/g
'stability': 'high'
},
n_jobs=8 # Parallel processing
)
# Get top performers
top_mofs = screening_results.get_top_performers(
criterion='co2_uptake',
n_top=10
)
print(f"Top 10 MOFs for CO₂ uptake:")
for i, mof in enumerate(top_mofs, 1):
print(f"{i:2d}. {mof['name']:15s} {mof['co2_uptake']:6.2f} mmol/g")
Comparative Analysis¶
Compare MOF families or modifications:
from fr5.property_prediction_mof import compare_mof_series
# Compare IRMOF series
comparison = compare_mof_series(
mof_series=['IRMOF-1', 'IRMOF-3', 'IRMOF-6', 'IRMOF-8'],
properties=['co2_uptake', 'surface_area', 'pore_volume'],
conditions={'pressure': 1.0, 'temperature': 298.15}
)
comparison.plot_comparison(
property='co2_uptake',
title='IRMOF Series CO₂ Uptake Comparison'
)
Data Management¶
MOF Database Integration¶
Access popular MOF databases:
from fr5.property_prediction_mof import load_mof_database
# Load CoRE MOF database
core_mofs = load_mof_database('CoRE_MOF_2019')
print(f"Loaded {len(core_mofs)} CoRE MOFs")
# Load QMOF database
qmofs = load_mof_database('QMOF')
print(f"Loaded {len(qmofs)} QMOFs")
# Filter by properties
high_surface_area = core_mofs.filter(
surface_area_min=2000 # m²/g
)
Custom MOF Libraries¶
Manage custom MOF collections:
from fr5.property_prediction_mof import MOFLibrary
# Create custom library
my_library = MOFLibrary('my_novel_mofs')
# Add MOFs
my_library.add_mof(
name='Novel-MOF-1',
structure_file='novel_mof_1.cif',
metadata={'synthesis_date': '2024-08-12', 'stability': 'high'}
)
# Batch predict properties
my_library.predict_properties(
properties=['co2_uptake', 'selectivity_co2_n2'],
conditions={'pressure': 1.0, 'temperature': 298.15}
)
# Export results
my_library.export_results('novel_mofs_properties.xlsx')
Model Performance¶
Validation Metrics¶
Current model performance on test sets:
| Property | Model | RMSE | MAE | AARE (%) | R² | Training Size |
|---|---|---|---|---|---|---|
| CO₂ Uptake | Random Forest | 0.82 mmol/g | 0.61 mmol/g | 15.3 | 0.89 | 3,045 |
| Surface Area | XGBoost | 145 m²/g | 98 m²/g | 8.7 | 0.94 | 2,891 |
| Pore Volume | Neural Net | 0.08 cm³/g | 0.06 cm³/g | 12.1 | 0.91 | 2,654 |
Cross-Validation Results¶
Robust performance across MOF families:
from fr5.property_prediction_mof import cross_validate_models
# 5-fold cross-validation stratified by topology
cv_results = cross_validate_models(
properties=['co2_uptake'],
cv_folds=5,
stratify_by='topology',
test_fraction=0.2
)
print(f"Cross-validation RMSE: {cv_results['rmse']['mean']:.2f} ± {cv_results['rmse']['std']:.2f}")
print(f"Cross-validation R²: {cv_results['r2']['mean']:.3f} ± {cv_results['r2']['std']:.3f}")
Error Evaluation Metrics¶
Root Mean Squared Error (RMSE)¶
For continuous properties:
Mean Absolute Error (MAE)¶
Average absolute prediction error:
Average Absolute Relative Error (AARE)¶
Percentage-based error metric:
Coefficient of Determination (R²)¶
Model fit quality:
Integration with Optimization¶
MOF Design Optimization¶
Optimize MOF properties using Bayesian optimization:
from fr5.property_prediction_mof import optimize_mof_design
from fr5.bayes_opt import BOExperimentManager
# Define design space for MOF optimization
design_space = [
{'name': 'metal_node', 'type': 'categorical', 'categories': ['Zn', 'Cu', 'Zr', 'Cr']},
{'name': 'linker_length', 'type': 'continuous', 'bounds': (5, 20)}, # Å
{'name': 'pore_size', 'type': 'continuous', 'bounds': (8, 25)}, # Å
{'name': 'topology', 'type': 'categorical', 'categories': ['pcu', 'fcu', 'reo', 'soc']}
]
# Multi-objective optimization: maximize uptake and selectivity
optimizer = optimize_mof_design(
design_space=design_space,
objectives=['co2_uptake', 'selectivity_co2_n2'],
constraints={'stability': 'high', 'synthesizability': 'feasible'},
n_iterations=50
)
# Get Pareto-optimal designs
pareto_designs = optimizer.get_pareto_front()
Best Practices¶
1. Structure Validation¶
Always validate MOF structures before prediction:
from fr5.property_prediction_mof import validate_mof_structure
is_valid, issues = validate_mof_structure('novel_mof.cif')
if not is_valid:
print("Structure validation failed:")
for issue in issues:
print(f"- {issue}")
2. Descriptor Quality¶
Check descriptor calculation quality:
from fr5.property_prediction_mof import check_descriptor_quality
quality_report = check_descriptor_quality(
mof_structure='test_mof.cif',
descriptor_types=['geometric', 'chemical']
)
if quality_report['warnings']:
print("Descriptor quality warnings:")
for warning in quality_report['warnings']:
print(f"- {warning}")
3. Model Applicability¶
Check if MOF is within model training domain:
from fr5.property_prediction_mof import check_model_applicability
applicability = check_model_applicability(
mof_descriptors=calculated_descriptors,
property='co2_uptake'
)
print(f"Model applicability: {applicability['status']}")
print(f"Similarity to training data: {applicability['similarity']:.2f}")
4. Uncertainty Interpretation¶
Use uncertainty estimates to guide decision-making:
- Low uncertainty (< 10%): High confidence predictions
- Medium uncertainty (10-25%): Moderate confidence, consider validation
- High uncertainty (> 25%): Experimental validation strongly recommended
Troubleshooting¶
Common Issues¶
Structure reading errors: Ensure CIF files are properly formatted and contain all required crystallographic information
Missing descriptors: Some descriptors require specific software (Zeo++, RASPA) to be installed
Poor predictions: Check if MOF is similar to training data using applicability domain analysis
Memory errors: Use batch processing for large-scale screening