| 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 |
| |
| |
| 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_val = sum(cf / (1 + marr)**i for i, cf in enumerate(cashflows)) |
| |
| |
| 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) |
| |
| |
| 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 = 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> |
| """ |
| |
| |
| 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") |
|
|
| |
| 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() |
| |
| |
| 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*") |
|
|
| |
| demo.launch() |