File size: 5,232 Bytes
a6f3fc0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import gradio as gr
from scipy.optimize import differential_evolution
import pandas as pd
import joblib

# Load trained model
best_model = joblib.load("xgb_model.pkl")

# Predictor names and bounds
predictors = [
    'loaded_drv_time_percycle',
    'empty_drv_time_percycle',
    'Eng_Speed_Ave',
    'empty_stop_time_percycle',
    'loadingstoptime_percycle',
    'loaded_stop_time_percycle'
]

bounds_dict = {
    'loaded_drv_time_percycle': (3, 60),
    'empty_drv_time_percycle': (2, 51),
    'Eng_Speed_Ave': (1051, 1596),
    'empty_stop_time_percycle': (0.2, 24.6),
    'loadingstoptime_percycle': (2, 18),
    'loaded_stop_time_percycle': (0.4, 9)
}

# Optimization function
def optimize_dynamic(
    loaded_drv, empty_drv, eng_speed, empty_stop, loading_stop, loaded_stop,
    fix_loaded_drv, fix_empty_drv, fix_eng_speed, fix_empty_stop, fix_loading_stop, fix_loaded_stop
):
    input_values = {
        'loaded_drv_time_percycle': loaded_drv,
        'empty_drv_time_percycle': empty_drv,
        'Eng_Speed_Ave': eng_speed,
        'empty_stop_time_percycle': empty_stop,
        'loadingstoptime_percycle': loading_stop,
        'loaded_stop_time_percycle': loaded_stop
    }

    fixed_flags = {
        'loaded_drv_time_percycle': fix_loaded_drv,
        'empty_drv_time_percycle': fix_empty_drv,
        'Eng_Speed_Ave': fix_eng_speed,
        'empty_stop_time_percycle': fix_empty_stop,
        'loadingstoptime_percycle': fix_loading_stop,
        'loaded_stop_time_percycle': fix_loaded_stop
    }

    bounds = []
    variable_names = []
    for name in predictors:
        if not fixed_flags[name]:
            bounds.append(bounds_dict[name])
            variable_names.append(name)

    if len(variable_names) == 0:
        pred = best_model.predict(pd.DataFrame([input_values]))[0]
        return f"✅ All inputs fixed.\nPredicted Fuel Rate: {pred:.2f} L/cycle"

    def objective(x):
        current_input = input_values.copy()
        for i, name in enumerate(variable_names):
            current_input[name] = x[i]
        return best_model.predict(pd.DataFrame([current_input]))[0]

    result = differential_evolution(objective, bounds=bounds, seed=42, maxiter=100)

    final_input = input_values.copy()
    for i, name in enumerate(variable_names):
        final_input[name] = result.x[i]

    changes = []
    for name in variable_names:
        original = input_values[name]
        optimized = final_input[name]
        if abs(original - optimized) > 0.01:
            changes.append(f"{name}: {original:.2f}{optimized:.2f}")
        else:
            changes.append(f"{name}: unchanged ({original:.2f})")

    result_text = "\n".join([f"{k}: {v:.2f}" for k, v in final_input.items()])
    result_text += "\n\n🔁 Optimized Inputs:\n" + "\n".join(changes)
    result_text += f"\n\n⚡️ Predicted Fuel Rate: {result.fun:.2f} L/cycle"

    # Sensitivity analysis for Engine Speed
    sensitivity_lines = ["\n📊 Suggested RPM vs. Fuel Rate:"]
    start_rpm = int(round(final_input['Eng_Speed_Ave'] / 50.0) * 50)
    end_rpm = min(start_rpm + 300, bounds_dict['Eng_Speed_Ave'][1])
    start_rpm = max(start_rpm, bounds_dict['Eng_Speed_Ave'][0])

    for rpm in range(start_rpm, end_rpm + 1, 50):
        temp_input = final_input.copy()
        temp_input['Eng_Speed_Ave'] = rpm

        temp_bounds = []
        temp_names = []

        for name in predictors:
            if name != 'Eng_Speed_Ave' and not fixed_flags.get(name, False):
                temp_bounds.append(bounds_dict[name])
                temp_names.append(name)

        def temp_objective(x):
            t_input = temp_input.copy()
            for i, name in enumerate(temp_names):
                t_input[name] = x[i]
            return best_model.predict(pd.DataFrame([t_input]))[0]

        if temp_bounds:
            temp_result = differential_evolution(temp_objective, bounds=temp_bounds, seed=42, maxiter=50)
            fuel_rate = temp_result.fun
        else:
            fuel_rate = best_model.predict(pd.DataFrame([temp_input]))[0]

        sensitivity_lines.append(f"RPM {rpm}: {fuel_rate:.2f} L/cycle")

    result_text += "\n" + "\n".join(sensitivity_lines)
    return result_text

# Gradio Interface (Interface-style)
interface = gr.Interface(
    fn=optimize_dynamic,
    inputs=[
        gr.Slider(3, 60, value=30, label="Loaded Drive Time"),
        gr.Slider(2, 51, value=23.8, label="Empty Drive Time"),
        gr.Slider(1051, 1596, value=1300, label="Engine Speed"),
        gr.Slider(0.2, 24.6, value=10.0, label="Empty Stop Time"),
        gr.Slider(2, 18, value=2.0, label="Loading Stop Time"),
        gr.Slider(0.4, 9, value=0.4, label="Loaded Stop Time"),
        gr.Checkbox(label="Fix Loaded Drive"),
        gr.Checkbox(label="Fix Empty Drive"),
        gr.Checkbox(label="Fix Engine Speed"),
        gr.Checkbox(label="Fix Empty Stop"),
        gr.Checkbox(label="Fix Loading Stop"),
        gr.Checkbox(label="Fix Loaded Stop"),
    ],
    outputs=gr.Textbox(label="Optimization Result", lines=16),
    title="⚙️ Fuel Rate What-If Optimizer",
    description="Perform global optimization of fuel rate with optional fixed inputs and sensitivity on engine RPM."
)

interface.launch()