Skip to content

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:

\[\mathrm{RMSE} = \sqrt{\frac{1}{N}\sum^{N}_{i=1}\left(\hat{y}_{i} - y_{i} \right)^{2}}\]

Mean Absolute Error (MAE)

Average absolute prediction error:

\[\mathrm{MAE} = \frac{1}{N}\sum^{N}_{i=1}\left|\hat{y}_{i} - y_{i} \right|\]

Average Absolute Relative Error (AARE)

Percentage-based error metric:

\[\mathrm{AARE} = \frac{1}{N}\sum^{N}_{i=1} \left|\frac{\hat{y}_{i} - y_{i}}{y_{i}}\right| \times 100\%\]

Coefficient of Determination (R²)

Model fit quality:

\[\mathrm{R^{2}} = 1 - \frac{\sum^{N}_{i=1}(\hat{y}_{i} - y_{i})^{2}}{\sum^{N}_{i=1}(y_{i} - \overline{y})^{2}}\]

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

Debugging Tools

from fr5.property_prediction_mof import debug_prediction

# Debug problematic prediction
debug_info = debug_prediction(
    mof_structure='problematic_mof.cif',
    property='co2_uptake',
    expected_range=(1.0, 5.0)  # Expected uptake range
)

print(f"Debug information: {debug_info}")