Spaces:
Running
Running
File size: 4,780 Bytes
a48faac | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | """
CLI for Mixture DCN Predictor
Interactive command-line interface for predicting Derived Cetane Number (DCN)
of fuel mixtures using SMILES input.
"""
from rdkit import Chem
from rdkit.Chem import Descriptors
import sys
from pathlib import Path
# Add parent directory to path for imports
sys.path.append(str(Path(__file__).parent.parent))
from core.predictors.mixture.mixture_dcn_predictor import MixtureDCNPredictor
def validate_smiles(smiles: str) -> bool:
"""Validate that a SMILES string is parseable by RDKit."""
mol = Chem.MolFromSmiles(smiles)
return mol is not None
def get_molecule_info(smiles: str) -> dict:
"""Get basic information about a molecule from SMILES."""
mol = Chem.MolFromSmiles(smiles)
if mol is None:
return None
return {
'formula': Chem.rdMolDescriptors.CalcMolFormula(mol),
'mol_weight': Descriptors.MolWt(mol),
'num_atoms': mol.GetNumAtoms()
}
def get_user_config():
"""
Collect user inputs for mixture DCN prediction.
Returns mixture composition (SMILES + mole fractions).
"""
print("\n" + "="*70)
print("MIXTURE DCN PREDICTOR - Configuration")
print("="*70)
# Get number of components
while True:
number_of_components = input("\nEnter number of components in the mixture (e.g., 2-10): ").strip()
if not number_of_components.isdigit():
print("β Invalid input. Please enter a positive integer.")
continue
num_comp = int(number_of_components)
if num_comp < 2:
print("β Mixture must have at least 2 components.")
print(" For single-component prediction, use the pure component predictor.")
continue
if num_comp > 11:
print("β Warning: Model trained on max 11 components. Limiting to 11.")
num_comp = 11
break
print(f"\nβ Configuring mixture with {num_comp} components")
print("-" * 70)
# Collect SMILES and mole fractions
components = []
total_fraction = 0.0
for i in range(num_comp):
print(f"\nπ Component {i+1}/{num_comp}:")
print("-" * 40)
# Get SMILES
while True:
smiles = input(f" Enter SMILES: ").strip()
if not smiles:
print(" β SMILES cannot be empty.")
continue
if not validate_smiles(smiles):
print(f" β Invalid SMILES: '{smiles}'")
print(" Please enter a valid SMILES string.")
continue
# Show molecule info
mol_info = get_molecule_info(smiles)
print(f" β Valid molecule: {mol_info['formula']} (MW: {mol_info['mol_weight']:.2f})")
break
# Get mole fraction
while True:
# For last component, auto-calculate remaining fraction
if i == num_comp - 1:
remaining = 1.0 - total_fraction
print(f" Mole fraction: {remaining:.4f} (auto-calculated)")
mole_frac = remaining
break
frac_input = input(f" Enter mole fraction (0-1, remaining: {1.0 - total_fraction:.4f}): ").strip()
try:
mole_frac = float(frac_input)
except ValueError:
print(" β Invalid input. Please enter a number between 0 and 1.")
continue
if mole_frac < 0 or mole_frac > 1:
print(" β Mole fraction must be between 0 and 1.")
continue
if total_fraction + mole_frac > 1.0:
print(f" β Total would exceed 1.0 (current total: {total_fraction:.4f})")
continue
if mole_frac == 0:
print(" β Warning: Zero mole fraction. Component will have no effect.")
break
components.append({
'smiles': smiles,
'mole_fraction': mole_frac,
'formula': mol_info['formula']
})
total_fraction += mole_frac
print(f" β Component added (Total fraction so far: {total_fraction:.4f})")
# Validate total
if abs(total_fraction - 1.0) > 1e-6:
print(f"\nβ Warning: Mole fractions sum to {total_fraction:.6f}, normalizing to 1.0")
for comp in components:
comp['mole_fraction'] /= total_fraction
return components
|