File size: 6,258 Bytes
0dabc69
5455d26
 
0dabc69
adc5545
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5455d26
adc5545
 
 
 
5455d26
adc5545
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5455d26
adc5545
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import gradio as gr
import numpy as np
import plotly.graph_objects as go

def calculate_chemeng_tvm(capex, revenue, opex_fixed, opex_var, plant_life, marr_pct, salvage_pct, inflation_pct):
    capex = float(capex)
    revenue = float(revenue)
    opex_fixed = float(opex_fixed)
    opex_var = float(opex_var)
    plant_life = int(plant_life)
    marr = float(marr_pct) / 100
    salvage = float(salvage_pct) / 100
    inflation = float(inflation_pct) / 100
    
    # Generate cash flows
    cashflows = [-capex]
    for year in range(1, plant_life + 1):
        opex_total = (opex_fixed + opex_var) * (1 + inflation) ** year
        rev = revenue * (1 + inflation) ** year
        net_cf = rev - opex_total
        cashflows.append(net_cf)
    cashflows[-1] += capex * salvage
    
    # NPV Calculation
    npv_val = sum(cf / (1 + marr)**i for i, cf in enumerate(cashflows))
    
    # IRR Approximation (Newton-Raphson)
    irr_guess = 0.1
    for _ in range(50):
        npv_est = sum(cf / (1 + irr_guess)**i for i, cf in enumerate(cashflows))
        deriv = sum(-i * cf / (1 + irr_guess)**(i+1) for i, cf in enumerate(cashflows))
        if abs(deriv) < 1e-10: break
        irr_guess -= npv_est / deriv
    irr_val = max(0, irr_guess * 100)
    
    # Payback Period
    cum_cf = [0]
    for cf in cashflows[1:]:
        cum_cf.append(cum_cf[-1] + cf)
    payback = next((i for i, total in enumerate(cum_cf) if total >= 0), plant_life)
    
    # Results HTML
    results_html = f"""
    <div style='font-family: Arial; padding: 20px;'>
        <h2 style='color: #1f77b4;'>πŸ§ͺ Chemical Engineering Economics</h2>
        <table style='width: 100%; border-collapse: collapse; margin: 20px 0;'>
            <tr style='background: #f0f8ff;'>
                <th style='border: 1px solid #ddd; padding: 12px;'>Metric</th>
                <th style='border: 1px solid #ddd; padding: 12px; text-align: right;'>Value</th>
            </tr>
            <tr>
                <td style='border: 1px solid #ddd; padding: 12px;'><b>πŸ’Ž NPV</b></td>
                <td style='border: 1px solid #ddd; padding: 12px; text-align: right; font-size: 18px; color: {'green' if npv_val > 0 else 'red'};'>${npv_val:,.0f}</td>
            </tr>
            <tr style='background: #f9f9f9;'>
                <td style='border: 1px solid #ddd; padding: 12px;'><b>⚑ IRR</b></td>
                <td style='border: 1px solid #ddd; padding: 12px; text-align: right; font-size: 18px;'>{irr_val:.1f}%</td>
            </tr>
            <tr>
                <td style='border: 1px solid #ddd; padding: 12px;'><b>⏱️ Payback</b></td>
                <td style='border: 1px solid #ddd; padding: 12px; text-align: right;'>{payback:.1f} years</td>
            </tr>
            <tr style='background: #f9f9f9;'>
                <td style='border: 1px solid #ddd; padding: 12px;'><b>πŸ“Š Profitability Index</b></td>
                <td style='border: 1px solid #ddd; padding: 12px; text-align: right;'>{abs(npv_val/capex)*100:.1f}%</td>
            </tr>
        </table>
        <div style='background: {'#d4edda' if npv_val > 0 else '#f8d7da'}; padding: 15px; border-radius: 8px; border-left: 5px solid {'#28a745' if npv_val > 0 else '#dc3545'};'>
            <b>Status: {'βœ… PROJECT VIABLE (NPV > 0)' if npv_val > 0 else '⚠️ REVIEW REQUIRED'}</b>
        </div>
    </div>
    """
    
    # Cash Flow Chart
    years = list(range(len(cashflows)))
    fig = go.Figure()
    fig.add_trace(go.Bar(x=years[1:], y=cashflows[1:], 
                        name="Annual Cash Flow", marker_color='#1f77b4'))
    fig.add_trace(go.Scatter(x=years, y=cum_cf, 
                            mode='lines+markers', name="Cumulative CF",
                            line=dict(color='#ff4444', width=4)))
    fig.add_hline(y=0, line_dash="dash", line_color="gray", annotation_text="Breakeven")
    fig.update_layout(
        title="πŸ’Έ Chemical Plant Cash Flow Analysis",
        xaxis_title="Year", yaxis_title="Cash Flow ($)",
        height=400, showlegend=True,
        font=dict(size=12)
    )
    
    return results_html, fig.to_html(full_html=False, div_id="cashflow-chart")

# Gradio Interface
with gr.Blocks(title="ChemEng TVM Calculator") as demo:
    gr.Markdown("# πŸ§ͺ Chemical Engineering TVM Calculator")
    gr.Markdown("**CAPEX β€’ OPEX β€’ NPV β€’ IRR β€’ Plant Investment Analysis**")
    
    with gr.Row():
        with gr.Column(scale=1):
            gr.Markdown("### πŸ“Š Chemical Plant Inputs")
            
            gr.Markdown("**πŸ’° Investment & Revenue**")
            with gr.Row():
                capex_input = gr.Number(value=10000000, label="CAPEX ($)", precision=0)
                revenue_input = gr.Number(value=5000000, label="Revenue/Year ($)", precision=0)
            
            gr.Markdown("**🏭 Operating Costs**")
            with gr.Row():
                opex_fixed_input = gr.Number(value=1500000, label="Fixed OPEX ($)", precision=0)
                opex_var_input = gr.Number(value=2000000, label="Variable OPEX ($)", precision=0)
            
            gr.Markdown("**πŸ“… Economic Parameters**")
            with gr.Row():
                plant_life_input = gr.Slider(5, 30, value=15, step=1, label="Plant Life (years)")
                marr_input = gr.Slider(8, 20, value=12, step=1, label="MARR (%)")
            
            with gr.Row():
                salvage_input = gr.Slider(0, 20, value=10, step=1, label="Salvage Value (%)")
                inflation_input = gr.Slider(1, 8, value=3, step=0.5, label="Inflation (%)")
            
            calculate_btn = gr.Button("πŸ”¬ RUN ECONOMIC ANALYSIS", variant="primary", size="lg")
        
        with gr.Column(scale=2):
            results_output = gr.HTML()
            chart_output = gr.HTML()
    
    # Connect button to function
    calculate_btn.click(
        calculate_chemeng_tvm,
        inputs=[capex_input, revenue_input, opex_fixed_input, opex_var_input, 
                plant_life_input, marr_input, salvage_input, inflation_input],
        outputs=[results_output, chart_output]
    )
    
    gr.Markdown("---")
    gr.Markdown("*Professional tool for Chemical Engineers | Powered by Gradio*")

# Launch (Hugging Face auto-runs this)
demo.launch()