File size: 4,562 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
"""

Binary Blending Tool CLI



Collects additive SMILES, base fuel selection, and sweep parameters

from the user interactively.

"""

from typing import Optional, List, Tuple


def _get_additive_smiles() -> str:
    from rdkit import Chem
    from rdkit.Chem import Descriptors

    print("\nAdditive Configuration")
    print("-" * 40)

    while True:
        smiles = input("Enter additive SMILES: ").strip()
        if not smiles:
            print("❌ SMILES cannot be empty.")
            continue

        mol = Chem.MolFromSmiles(smiles)
        if mol is None:
            print(f"❌ Invalid SMILES: '{smiles}'. Please try again.")
            continue

        formula = Chem.rdMolDescriptors.CalcMolFormula(mol)
        mw = Descriptors.MolWt(mol)
        print(f"  βœ“ Valid molecule: {formula} (MW: {mw:.2f} g/mol)")
        return smiles


def _get_base_fuel() -> Tuple[str, Optional[List[str]], Optional[List[float]]]:
    from applications.mixture_aware_generator.cli import get_custom_base_fuel

    print("\nBase Fuel Selection:")
    print("1. Fossil diesel (typical petroleum diesel)")
    print("2. Biodiesel (FAME)")
    print("3. Custom (enter your own composition)")

    while True:
        choice = input("\nSelect base fuel (1-3): ").strip()

        if choice == "1":
            print("βœ“ Using fossil diesel")
            return "fossil_diesel", None, None

        elif choice == "2":
            print("βœ“ Using biodiesel")
            return "biodiesel", None, None

        elif choice == "3":
            smiles, fracs = get_custom_base_fuel()
            if smiles is None:
                print("  β†’ Defaulting to fossil diesel.")
                return "fossil_diesel", None, None
            return "custom", smiles, fracs

        else:
            print("❌ Invalid choice. Enter 1, 2, or 3.")


def _get_sweep_config() -> Tuple[float, float, int]:
    print("\nSweep Configuration")
    print("-" * 40)
    print("Define the range of additive mole fractions to evaluate.")

    while True:
        try:
            raw = input("Min additive mole fraction [default 0.00]: ").strip()
            min_frac = float(raw) if raw else 0.0
            if not 0.0 <= min_frac < 1.0:
                print("❌ Min fraction must be in [0, 1).")
                continue
            break
        except ValueError:
            print("❌ Please enter a number.")

    while True:
        try:
            raw = input("Max additive mole fraction [default 0.30]: ").strip()
            max_frac = float(raw) if raw else 0.30
            if not min_frac < max_frac <= 1.0:
                print(f"❌ Max fraction must be greater than {min_frac:.3f} and ≀ 1.")
                continue
            break
        except ValueError:
            print("❌ Please enter a number.")

    while True:
        try:
            raw = input("Number of sweep steps [default 20]: ").strip()
            n_steps = int(raw) if raw else 20
            if n_steps < 2:
                print("❌ Need at least 2 steps.")
                continue
            break
        except ValueError:
            print("❌ Please enter a whole number.")

    return min_frac, max_frac, n_steps


def get_user_config() -> dict:
    """Interactive CLI β€” returns a config dict that maps directly to run_blend_sweep kwargs."""
    print("=" * 70)
    print("BINARY BLENDING TOOL")
    print("=" * 70)
    print("\nPredict how DCN and YSI change as a single additive is blended")
    print("into a base fuel across a range of mole fractions.")

    additive_smiles = _get_additive_smiles()
    base_fuel_type, base_fuel_smiles, base_fuel_mole_fractions = _get_base_fuel()
    min_frac, max_frac, n_steps = _get_sweep_config()

    print("\n" + "=" * 70)
    print("CONFIGURATION SUMMARY")
    print("=" * 70)
    print(f"  Additive SMILES : {additive_smiles}")
    print(f"  Base fuel       : {base_fuel_type}")
    if base_fuel_smiles:
        print(f"  Base components : {len(base_fuel_smiles)}")
    print(f"  Sweep           : {min_frac:.3f} β†’ {max_frac:.3f}  ({n_steps} steps)")
    print("=" * 70)

    return {
        "additive_smiles": additive_smiles,
        "base_fuel_type": base_fuel_type,
        "base_fuel_smiles": base_fuel_smiles,
        "base_fuel_mole_fractions": base_fuel_mole_fractions,
        "min_fraction": min_frac,
        "max_fraction": max_frac,
        "n_steps": n_steps,
    }