Getting Started with fr5¶
This guide will walk you through your first steps with fr5, from basic usage to advanced features.
Quick Example¶
Let's start with a simple example - predicting ionic liquid viscosity:
import fr5
from fr5.property_prediction_il import predict_viscosity
# Predict viscosity for 1-ethyl-3-methylimidazolium tetrafluoroborate (EMIM-BF4)
result = predict_viscosity({
'cation': 'EMIM',
'anion': 'BF4',
'temperature': 298.15 # 25°C
})
print(f"Predicted viscosity: {result['viscosity']:.2f} mPa·s")
Core Concepts¶
1. Package Structure¶
fr5 is organized into specialized modules:
import fr5
# Molecular descriptors
from fr5.descriptors import generate_il_descriptors
# Property prediction
from fr5.property_prediction_il import predict_viscosity, predict_density
from fr5.property_prediction_mof import predict_co2_uptake
# Bayesian optimization
from fr5.bayes_opt import BOExperimentManager
# Reaction analysis
from fr5.reaction_analysis import predict_reaction_outcome
# Shared utilities
from fr5.shared import clean_chemical_data, plot_property_comparison
2. Data Formats¶
fr5 works with standard Python data structures:
# Single ionic liquid
il_single = {
'cation': 'EMIM',
'anion': 'BF4',
'temperature': 298.15
}
# Multiple ionic liquids
il_batch = [
{'cation': 'EMIM', 'anion': 'BF4', 'temperature': 298.15},
{'cation': 'BMIM', 'anion': 'PF6', 'temperature': 298.15},
{'cation': 'HMIM', 'anion': 'Tf2N', 'temperature': 298.15}
]
# Pandas DataFrame (preferred for larger datasets)
import pandas as pd
il_dataframe = pd.DataFrame(il_batch)
Step-by-Step Tutorial¶
Step 1: Basic Property Prediction¶
Start with simple property predictions:
from fr5.property_prediction_il import predict_viscosity, predict_density
# Single prediction
viscosity_result = predict_viscosity({
'cation': 'BMIM',
'anion': 'PF6',
'temperature': 323.15 # 50°C
})
density_result = predict_density({
'cation': 'BMIM',
'anion': 'PF6',
'temperature': 323.15
})
print(f"At 50°C, BMIM-PF6 has:")
print(f" Viscosity: {viscosity_result['viscosity']:.1f} mPa·s")
print(f" Density: {density_result['density']:.3f} g/cm³")
Step 2: Batch Predictions¶
Process multiple conditions efficiently:
import pandas as pd
from fr5.property_prediction_il import predict_viscosity_batch
# Create dataset with temperature variation
il_data = []
for temp in range(298, 374, 25): # 25°C to 100°C
il_data.append({
'cation': 'EMIM',
'anion': 'BF4',
'temperature': temp
})
# Batch prediction
results = predict_viscosity_batch(il_data)
# Convert to DataFrame for analysis
df = pd.DataFrame(results)
print(df[['temperature', 'viscosity']])
Step 3: Working with MOF Properties¶
Predict Metal-Organic Framework properties:
from fr5.property_prediction_mof import predict_co2_uptake
# Predict CO₂ uptake for HKUST-1
co2_result = predict_co2_uptake(
mof_name='HKUST-1',
pressure=1.0, # 1 bar
temperature=298.15 # 25°C
)
print(f"HKUST-1 CO₂ uptake: {co2_result['uptake']:.2f} mmol/g")
# From structure file
co2_result_file = predict_co2_uptake(
mof_structure='path/to/HKUST-1.cif',
pressure=1.0,
temperature=298.15
)
Step 4: Molecular Descriptors¶
Generate molecular descriptors for custom analysis:
from fr5.descriptors import generate_il_descriptors, generate_mof_descriptors
# IL descriptors
il_descriptors = generate_il_descriptors(
cation='EMIM',
anion='BF4',
descriptor_types=['fragment', 'property', 'topological']
)
print(f"Generated {len(il_descriptors)} IL descriptors")
print(f"Sample descriptors: {list(il_descriptors.keys())[:5]}")
# MOF descriptors (from structure file)
mof_descriptors = generate_mof_descriptors(
structure_file='MOF-5.cif',
descriptor_types=['geometric', 'chemical', 'topological']
)
print(f"Generated {len(mof_descriptors)} MOF descriptors")
Step 5: Visualization¶
Create publication-quality plots:
import matplotlib.pyplot as plt
from fr5.shared.visualization import plot_property_comparison
# Generate some predictions for plotting
experimental = [45.2, 78.9, 156.3, 298.7] # Experimental viscosities
predicted = [43.8, 82.1, 149.2, 305.4] # Predicted viscosities
# Create comparison plot
plot_property_comparison(
experimental=experimental,
predicted=predicted,
property_name='Viscosity',
units='mPa·s',
title='Viscosity Prediction Performance',
save_path='viscosity_comparison.png'
)
Advanced Features¶
Bayesian Optimization¶
Optimize experimental conditions automatically:
import pandas as pd
from fr5.bayes_opt import BOExperimentManager
# Define experimental variables
variables = [
{'name': 'temperature', 'type': 'continuous', 'bounds': (20, 100)},
{'name': 'pressure', 'type': 'continuous', 'bounds': (1, 10)},
{'name': 'catalyst', 'type': 'categorical', 'categories': ['Pd', 'Pt', 'Ni']}
]
# Initial experimental data
initial_data = pd.DataFrame({
'temperature': [25, 50, 75],
'pressure': [1, 5, 10],
'catalyst': ['Pd', 'Pt', 'Ni'],
'yield': [45.2, 72.8, 68.9],
'selectivity': [85.1, 91.2, 78.4]
})
# Create Bayesian optimization manager
bo_manager = BOExperimentManager(
input_details=variables,
initial_experiments=initial_data,
db_path="optimization.db",
objective_names=['yield', 'selectivity'],
strategy_type='mobo_pareto'
)
# Suggest next experiments
next_experiments = bo_manager.suggest_experiments(batch_size=3)
print("Next experiments to perform:")
print(next_experiments)
Reaction Analysis¶
Analyze and predict reaction outcomes:
from fr5.reaction_analysis import predict_reaction_outcome, analyze_kinetics
# Predict reaction conversion
reaction_result = predict_reaction_outcome(
reaction_type='hydrogenation',
conditions={
'catalyst': 'Pd/C',
'solvent': 'ethanol',
'temperature': 60, # °C
'pressure': 1.0, # atm
'time': 4.0 # hours
}
)
print(f"Predicted conversion: {reaction_result['conversion']:.1f}%")
print(f"Predicted selectivity: {reaction_result['selectivity']:.1f}%")
# Analyze reaction kinetics from time-course data
time_points = [0, 1, 2, 4, 8, 12] # hours
conversions = [0, 25, 42, 65, 78, 85] # %
kinetic_analysis = analyze_kinetics(
time=time_points,
conversion=conversions,
models=['first_order', 'second_order']
)
best_model = kinetic_analysis.best_model
print(f"Best kinetic model: {best_model['name']}")
print(f"Rate constant: {best_model['rate_constant']:.2e} h⁻¹")
Working with Real Data¶
Loading Experimental Data¶
import pandas as pd
from fr5.shared.io import load_experimental_data
# Load from various formats
csv_data = pd.read_csv('experiments.csv')
excel_data = pd.read_excel('experiments.xlsx', sheet_name='results')
# Load from database
from fr5.bayes_opt import load_dataframe_from_db
db_data = load_dataframe_from_db('experiments.db', 'optimization_results')
# Validate data quality
from fr5.shared.validation import validate_chemical_data
validation_report = validate_chemical_data(csv_data)
if validation_report['is_valid']:
print("✅ Data validation passed")
else:
print("❌ Data validation issues found:")
for error in validation_report['errors']:
print(f" - {error}")
Data Preprocessing¶
from fr5.shared import clean_chemical_data, handle_missing_values
# Clean experimental data
clean_data = clean_chemical_data(
data=raw_data,
remove_outliers=True,
outlier_method='iqr',
missing_value_strategy='interpolate'
)
# Handle specific missing value patterns
filled_data = handle_missing_values(
data=clean_data,
strategies={
'viscosity': 'knn_impute',
'density': 'interpolate',
'temperature': 'forward_fill'
}
)
Best Practices¶
1. Data Organization¶
Keep your data well-organized:
# Good: Consistent naming and units
good_data = {
'cation': 'EMIM', # Standard abbreviation
'anion': 'BF4', # Standard abbreviation
'temperature': 298.15, # Kelvin
'viscosity': 45.2 # mPa·s
}
# Avoid: Inconsistent naming and units
bad_data = {
'Cat': '1-ethyl-3-methylimidazolium', # Non-standard name
'An': 'tetrafluoroborate', # Non-standard name
'T': 25, # Celsius (ambiguous)
'visc': 0.0452 # Pa·s (wrong units)
}
2. Error Handling¶
Always handle potential errors:
from fr5.property_prediction_il import predict_viscosity
from fr5.shared.exceptions import ChemistryValidationError
try:
result = predict_viscosity({
'cation': 'UNKNOWN_CATION',
'anion': 'BF4',
'temperature': 298.15
})
except ChemistryValidationError as e:
print(f"Chemistry validation failed: {e}")
# Handle error gracefully
except Exception as e:
print(f"Unexpected error: {e}")
# Log error and continue
3. Performance Optimization¶
For large datasets, use batch processing:
# Efficient batch processing
from fr5.property_prediction_il import predict_viscosity_batch
# Instead of individual predictions
results = []
for il in large_il_list:
result = predict_viscosity(il) # Slow for large datasets
results.append(result)
# Use batch prediction
batch_results = predict_viscosity_batch(large_il_list) # Much faster
4. Reproducibility¶
Set random seeds for reproducible results:
import numpy as np
import torch
from fr5.shared import set_random_seed
# Set global random seed
set_random_seed(42)
# Or set individually
np.random.seed(42)
torch.manual_seed(42)
Common Workflows¶
Workflow 1: Property Screening¶
Screen ionic liquids for optimal properties:
import pandas as pd
from fr5.property_prediction_il import predict_viscosity_batch, predict_density_batch
# Define IL library
cations = ['EMIM', 'BMIM', 'HMIM']
anions = ['BF4', 'PF6', 'Tf2N']
temperatures = [298.15, 323.15, 348.15]
# Generate all combinations
il_library = []
for cation in cations:
for anion in anions:
for temp in temperatures:
il_library.append({
'cation': cation,
'anion': anion,
'temperature': temp
})
# Predict properties
viscosities = predict_viscosity_batch(il_library)
densities = predict_density_batch(il_library)
# Combine results
results_df = pd.DataFrame(il_library)
results_df['viscosity'] = [r['viscosity'] for r in viscosities]
results_df['density'] = [r['density'] for r in densities]
# Find optimal ILs (e.g., low viscosity, high density)
optimal_ils = results_df[
(results_df['viscosity'] < 50) &
(results_df['density'] > 1.2)
].sort_values('viscosity')
print("Optimal ionic liquids:")
print(optimal_ils[['cation', 'anion', 'temperature', 'viscosity', 'density']])
Workflow 2: Experimental Design¶
Use Bayesian optimization to design experiments:
import pandas as pd
from fr5.bayes_opt import BOExperimentManager
# Step 1: Define experimental space
experimental_space = [
{'name': 'temperature', 'type': 'continuous', 'bounds': (20, 100)},
{'name': 'catalyst_loading', 'type': 'continuous', 'bounds': (0.1, 5.0)},
{'name': 'reaction_time', 'type': 'continuous', 'bounds': (0.5, 24)},
{'name': 'solvent', 'type': 'categorical', 'categories': ['ethanol', 'water', 'dms0']}
]
# Step 2: Provide initial data
initial_experiments = pd.DataFrame({
'temperature': [25, 50, 75, 100],
'catalyst_loading': [0.5, 1.0, 2.0, 5.0],
'reaction_time': [2, 4, 8, 16],
'solvent': ['ethanol', 'water', 'dmso', 'ethanol'],
'yield': [12.3, 45.6, 78.9, 65.4],
'selectivity': [85.2, 91.7, 88.3, 82.1]
})
# Step 3: Set up optimization
optimizer = BOExperimentManager(
input_details=experimental_space,
initial_experiments=initial_experiments,
db_path="reaction_optimization.db",
objective_names=['yield', 'selectivity'],
strategy_type='mobo_pareto'
)
# Step 4: Iterative optimization
for iteration in range(10):
print(f"\n--- Iteration {iteration + 1} ---")
# Suggest next experiments
suggestions = optimizer.suggest_experiments(batch_size=2)
print(f"Suggested experiments:\n{suggestions}")
# Simulate experimental results (replace with real experiments)
new_results = simulate_experiments(suggestions) # Your experimental function
# Add results to database
optimizer.add_experiments(new_results)
# Check optimization progress
best_results = optimizer.get_best_results()
print(f"Best yield so far: {best_results['yield']:.1f}%")
print(f"Best selectivity so far: {best_results['selectivity']:.1f}%")
Workflow 3: Model Validation¶
Validate predictions against experimental data:
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score
from fr5.property_prediction_il import predict_viscosity_batch
from fr5.shared.validation import validate_model
# Load experimental dataset
experimental_data = pd.read_csv('experimental_viscosities.csv')
# Split into train and test
train_data, test_data = train_test_split(
experimental_data,
test_size=0.2,
random_state=42
)
# Make predictions on test set
test_inputs = test_data[['cation', 'anion', 'temperature']].to_dict('records')
predictions = predict_viscosity_batch(test_inputs)
predicted_values = [p['viscosity'] for p in predictions]
# Calculate validation metrics
experimental_values = test_data['viscosity_experimental'].values
rmse = np.sqrt(mean_squared_error(experimental_values, predicted_values))
r2 = r2_score(experimental_values, predicted_values)
mape = np.mean(np.abs((experimental_values - predicted_values) / experimental_values)) * 100
print(f"Model Validation Results:")
print(f" RMSE: {rmse:.2f} mPa·s")
print(f" R²: {r2:.3f}")
print(f" MAPE: {mape:.1f}%")
# Plot predictions vs experimental
from fr5.shared.visualization import plot_property_comparison
plot_property_comparison(
experimental=experimental_values,
predicted=predicted_values,
property_name='Viscosity',
units='mPa·s',
title='Model Validation Results'
)
Next Steps¶
Now that you're familiar with the basics of fr5:
- Explore specific modules in detail using the module documentation
- Try the examples in the
examples/directory - Read the API documentation for complete function references
- Join the community discussions on GitHub
- Contribute improvements or report issues
Getting Help¶
- 📖 Documentation: Browse the complete API reference
- 💬 Discussions: Join GitHub Discussions
- 🐛 Issues: Report bugs on GitHub Issues
- 📧 Contact: Reach out to the development team
Happy experimenting with fr5! 🧪✨