Plotting - Nouman090/ThermoSim GitHub Wiki
All visualisation is handled by the CyclePlotter class, completely
separated from computation.
Setup
from ThermoSim.plotting import CyclePlotter
# Create plotter from a solved model
plotter = CyclePlotter(Model)
1. T-s Diagram
plotter.plot_Ts_diagram(
loop_points=['1', '2', '3', '4', '1'], # cycle path
fluid='water', # for saturation dome (auto-detected)
show_dome=True, # show saturation dome
show_labels=True, # label state points
title='My Rankine Cycle',
figsize=(10, 7),
save_csv=False, # NEW: export data to CSV
csv_path=None, # NEW: custom CSV filename (optional)
)
Scatter Mode (No Loop)
# Plot all points without connecting lines
plotter.plot_Ts_diagram()
Export Data to CSV
# Auto-generated filename with timestamp
plotter.plot_Ts_diagram(
loop_points=['1', '2', '3', '4', '1'],
save_csv=True
)
# Saves to: Ts_diagram_20240115_143022.csv
# Custom filename
plotter.plot_Ts_diagram(
loop_points=['1', '2', '3', '4', '1'],
save_csv=True,
csv_path='results/rankine_Ts.csv'
)
CSV Format:
Point,Entropy_kJ_per_kg_K,Temperature_C,Entropy_J_per_kg_K,Temperature_K
1,6.234,450.5,6234.0,723.65
2,6.234,120.3,6234.0,393.45
3,0.592,29.0,592.0,302.15
4,0.592,30.5,592.0,303.65
2. P-h Diagram
plotter.plot_Ph_diagram(
loop_points=['1', '2', '3', '4', '1'],
show_dome=True,
title='P-h Diagram',
save_csv=False, # NEW: export data to CSV
csv_path=None, # NEW: custom CSV filename (optional)
)
CSV Format:
Point,Enthalpy_kJ_per_kg,Pressure_bar,Enthalpy_J_per_kg,Pressure_Pa
1,3398.3,80.0,3398300,8000000
2,2346.2,0.08,2346200,8000
3. h-s Diagram (Mollier)
plotter.plot_hs_diagram(
loop_points=['1', '2', '3', '4', '1'],
show_dome=True,
title='Mollier Diagram',
save_csv=False, # NEW: export data to CSV
csv_path=None, # NEW: custom CSV filename (optional)
)
CSV Format:
Point,Entropy_kJ_per_kg_K,Enthalpy_kJ_per_kg,Entropy_J_per_kg_K,Enthalpy_J_per_kg
1,6.234,3398.3,6234.0,3398300
2,6.234,2346.2,6234.0,2346200
4. Heat Exchanger Temperature Profile
Shows how temperature varies along a heat exchanger and identifies the pinch point.
min_dT = plotter.plot_hex_profile(
hex_id='Recuperator', # component ID
div_N=200, # number of segments
save_csv=False, # NEW: export profile data to CSV
csv_path=None, # NEW: custom CSV filename (optional)
)
print(f"Minimum ΔT (pinch): {min_dT:.2f} K")
⚠️ Only works for
double_pipe,Condenser,Evaporatortypes (notSimpleHEX).
Export Profile Data
min_dT = plotter.plot_hex_profile(
hex_id='Recuperator',
div_N=200,
save_csv=True,
csv_path='recuperator_profile.csv'
)
CSV Format:
Heat_Transferred_kW,Hot_Temperature_C,Cold_Temperature_C,Delta_T_K,Hot_Enthalpy_J_per_kg,Cold_Enthalpy_J_per_kg,Hot_Pressure_Pa,Cold_Pressure_Pa
0.0,450.5,25.0,425.5,2800000,105000,8000000,100000
5.0,445.2,30.1,415.1,2750000,126000,7998000,99800
10.0,440.1,35.3,404.8,2700000,148000,7996000,99600
...
5. Exergy Destruction Bar Chart
# Absolute values (kW)
plotter.plot_exergy_bar()
# As percentage of total
plotter.plot_exergy_bar(as_percentage=True)
# NEW: Export to CSV
plotter.plot_exergy_bar(
as_percentage=True,
save_csv=True,
csv_path='exergy_analysis.csv'
)
CSV Format:
Component,Exergy_Destruction_W,Exergy_Destruction_kW,Percentage
Turbine,45000,45.0,35.5
Boiler,30000,30.0,23.7
Condenser,28000,28.0,22.1
Pump,24000,24.0,18.7
6. Exergy Destruction Pie Chart
plotter.plot_exergy_pie(
save_csv=False, # NEW: export data to CSV
csv_path=None, # NEW: custom CSV filename (optional)
)
CSV Format: Same as exergy bar chart.
7. Energy Flow Summary
plotter.plot_energy_summary(
save_csv=False, # NEW: export summary to CSV
csv_path=None, # NEW: custom CSV filename (optional)
)
Shows bar chart of: Turbine Work, Pump Work, Heat Added, Heat Rejected.
CSV Format (Summary):
Category,Value_W,Value_kW
Turbine Work,500000,500.0
Pump Work,50000,50.0
Heat Added,800000,800.0
Heat Rejected,250000,250.0
*CSV Format (Detailed - auto-saved as _detailed.csv):
Component,Type,Value_W,Value_kW
Turbine1,Turbine,500000,500.0
Pump1,Pump,50000,50.0
Boiler,Heat_Added,800000,800.0
Condenser,Heat_Rejected,250000,250.0
8. Export All State Points (NEW)
Export all thermodynamic properties of every state point to CSV.
csv_file = plotter.export_all_points(
csv_path='all_state_points.csv' # optional
)
print(f"Saved to: {csv_file}")
CSV Format:
Point,T,P,H,S,D,Q,fluid,T_C,P_bar,H_kJ_per_kg,S_kJ_per_kg_K
1,723.65,8000000,3398300,6234.0,38.45,None,water,450.5,80.0,3398.3,6.234
2,393.45,8000,2346200,6234.0,0.0039,0.95,water,120.3,0.08,2346.2,6.234
3,302.15,8000,105000,592.0,997.04,0.0,water,29.0,0.08,105.0,0.592
4,303.65,8000000,113000,592.0,999.8,0.0,water,30.5,80.0,113.0,0.592
9. Export All Components (NEW)
Export performance data for all components.
csv_file = plotter.export_all_components(
csv_path='all_components.csv' # optional
)
print(f"Saved to: {csv_file}")
CSV Format:
Component,Type,work,Q,Ex_D,eta,Solution_Status,work_kW,Q_kW,Ex_D_kW
Turbine,Turbine,500000,None,45000,0.85,True,500.0,None,45.0
Pump,Pump,50000,None,24000,0.85,True,50.0,None,24.0
Boiler,HeatExchanger,None,800000,30000,None,True,None,800.0,30.0
Condenser,HeatExchanger,None,250000,28000,None,True,None,250.0,28.0
Complete Plotting Example
from ThermoSim import (
ThermodynamicModel, Turbine, Pump, HeatExchanger,
)
from ThermoSim.plotting import CyclePlotter
# Build cycle
Model = ThermodynamicModel()
Model.set_dead_state()
Model.add_point('water', '1', P=8e6, T=753.15, Mass_flowrate=1)
Model.add_point('water', '2', P=0.008e6)
Model.add_point('water', '3', P=0.008e6, Q=0)
Model.add_point('water', '4', P=8e6)
Turbine(Model, 'Turbine', '1', '2', n_isen=0.85, Calculate=True)
HeatExchanger(Model, 'Condenser', PPT=5, HEX_type='SimpleHEX',
HeatAdded=False, Hot_In_state='2', Hot_Out_state='3',
Cold_In_state=None, Cold_Out_state=None, Calculate=True)
Pump(Model, 'Pump', '3', '4', n_isen=0.85, Calculate=True)
HeatExchanger(Model, 'Boiler', PPT=5, HEX_type='SimpleHEX',
HeatAdded=True, Hot_In_state=None, Hot_Out_state=None,
Cold_In_state='4', Cold_Out_state='1', Calculate=True)
Model.ModelSummary()
# Create plotter
plotter = CyclePlotter(Model)
# Generate all plots
plotter.plot_Ts_diagram(['1', '2', '3', '4', '1'])
plotter.plot_Ph_diagram(['1', '2', '3', '4', '1'])
plotter.plot_hs_diagram(['1', '2', '3', '4', '1'])
plotter.plot_exergy_bar(as_percentage=True)
plotter.plot_exergy_pie()
plotter.plot_energy_summary()
Complete Example with CSV Export
from ThermoSim import (
ThermodynamicModel, Turbine, Pump, HeatExchanger,
)
from ThermoSim.plotting import CyclePlotter
import os
# Build and solve cycle (same as above)
Model = ThermodynamicModel()
Model.set_dead_state()
Model.add_point('water', '1', P=8e6, T=753.15, Mass_flowrate=1)
Model.add_point('water', '2', P=0.008e6)
Model.add_point('water', '3', P=0.008e6, Q=0)
Model.add_point('water', '4', P=8e6)
Turbine(Model, 'Turbine', '1', '2', n_isen=0.85, Calculate=True)
HeatExchanger(Model, 'Condenser', PPT=5, HEX_type='SimpleHEX',
HeatAdded=False, Hot_In_state='2', Hot_Out_state='3',
Cold_In_state=None, Cold_Out_state=None, Calculate=True)
Pump(Model, 'Pump', '3', '4', n_isen=0.85, Calculate=True)
HeatExchanger(Model, 'Boiler', PPT=5, HEX_type='SimpleHEX',
HeatAdded=True, Hot_In_state=None, Hot_Out_state=None,
Cold_In_state='4', Cold_Out_state='1', Calculate=True)
Model.ModelSummary()
# Create output directory
os.makedirs('output/plots', exist_ok=True)
# Create plotter
plotter = CyclePlotter(Model)
# Generate plots with CSV export
plotter.plot_Ts_diagram(
['1', '2', '3', '4', '1'],
save_csv=True,
csv_path='output/plots/Ts_diagram.csv'
)
plotter.plot_Ph_diagram(
['1', '2', '3', '4', '1'],
save_csv=True,
csv_path='output/plots/Ph_diagram.csv'
)
plotter.plot_hs_diagram(
['1', '2', '3', '4', '1'],
save_csv=True,
csv_path='output/plots/hs_diagram.csv'
)
plotter.plot_exergy_bar(
as_percentage=True,
save_csv=True,
csv_path='output/plots/exergy_bar.csv'
)
plotter.plot_exergy_pie(
save_csv=True,
csv_path='output/plots/exergy_pie.csv'
)
plotter.plot_energy_summary(
save_csv=True,
csv_path='output/plots/energy_summary.csv'
)
# Export complete data
plotter.export_all_points('output/plots/all_state_points.csv')
plotter.export_all_components('output/plots/all_components.csv')
print("✓ All plots and data exported to output/plots/")
Directory Structure After Export:
output/plots/
├── Ts_diagram.csv
├── Ph_diagram.csv
├── hs_diagram.csv
├── exergy_bar.csv
├── exergy_pie.csv
├── energy_summary.csv
├── energy_summary_detailed.csv
├── all_state_points.csv
└── all_components.csv
Batch Processing Example
Process multiple cycles and export data:
from ThermoSim.plotting import CyclePlotter
import pandas as pd
# Assume you have multiple models
models = {
'Case_1_Low_Pressure': Model_1,
'Case_2_Med_Pressure': Model_2,
'Case_3_High_Pressure': Model_3,
}
# Process each case
all_results = []
for case_name, model in models.items():
plotter = CyclePlotter(model)
# Export data
plotter.export_all_points(f'results/{case_name}_points.csv')
plotter.export_all_components(f'results/{case_name}_components.csv')
# Plot with auto-generated filenames
plotter.plot_Ts_diagram(
['1', '2', '3', '4', '1'],
save_csv=True,
title=f'{case_name} - T-s Diagram'
)
plotter.plot_exergy_bar(
as_percentage=True,
save_csv=True
)
print(f"✓ Processed {case_name}")
print("✓ All cases processed")
CSV Data Analysis Example
Use exported CSV data for further analysis:
import pandas as pd
import matplotlib.pyplot as plt
# Load exported data
df_points = pd.read_csv('all_state_points.csv')
df_components = pd.read_csv('all_components.csv')
df_exergy = pd.read_csv('exergy_bar.csv')
# Analyze state points
print("State Point Summary:")
print(df_points['Point', 'T_C', 'P_bar', 'H_kJ_per_kg'](/Nouman090/ThermoSim/wiki/'Point',-'T_C',-'P_bar',-'H_kJ_per_kg').to_string())
# Calculate cycle efficiency
turbine_work = df_components[df_components['Type'] == 'Turbine']['work_kW'].sum()
pump_work = df_components[df_components['Type'] == 'Pump']['work_kW'].sum()
heat_added = df_components[df_components['Type'] == 'HeatExchanger']['Q_kW'].max()
net_work = turbine_work - pump_work
thermal_efficiency = net_work / heat_added * 100
print(f"\nCycle Performance:")
print(f"Net Work Output: {net_work:.2f} kW")
print(f"Thermal Efficiency: {thermal_efficiency:.2f}%")
# Exergy analysis
total_exergy = df_exergy['Exergy_Destruction_kW'].sum()
print(f"Total Exergy Destruction: {total_exergy:.2f} kW")
# Find worst component
worst = df_exergy.loc[df_exergy['Exergy_Destruction_kW'].idxmax()]
print(f"Largest Exergy Loss: {worst['Component']} ({worst['Percentage']:.1f}%)")
Tips and Best Practices
1. Organize Output Files
from datetime import datetime
import os
# Create timestamped directory
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
output_dir = f'results/run_{timestamp}'
os.makedirs(output_dir, exist_ok=True)
# Save all plots there
plotter.plot_Ts_diagram(
['1', '2', '3', '4', '1'],
save_csv=True,
csv_path=f'{output_dir}/Ts_diagram.csv'
)
2. Validate Before Plotting
# Check if model is solved
if not all(comp.Solution_Status for comp in Model.Component.values()):
print("⚠️ Warning: Some components not solved")
# Check for missing data
for name, point in Model.Point.items():
if point.T is None or point.P is None:
print(f"⚠️ Warning: Point {name} has missing properties")
3. Handle Errors Gracefully
try:
plotter.plot_hex_profile('Recuperator', save_csv=True)
except ValueError as e:
print(f"Could not plot heat exchanger: {e}")
4. Combine CSV Files for Comparison
import pandas as pd
import glob
# Load all Ts diagram CSVs
csv_files = glob.glob('results/*/Ts_diagram.csv')
combined = pd.concat([pd.read_csv(f) for f in csv_files],
keys=csv_files, names=['File', 'Row'])
combined.to_csv('combined_Ts_data.csv')
Troubleshooting
Issue: "No valid points to plot"
Cause: State points have None values for required properties.
Solution: Ensure all components are solved before plotting.
Model.ModelSummary() # Check solution status
Issue: CSV file not created
Cause: Permission denied or invalid path.
Solution: Check directory exists and permissions.
import os
os.makedirs('output', exist_ok=True)
plotter.plot_Ts_diagram(['1','2','3','4','1'],
save_csv=True,
csv_path='output/Ts.csv')
Issue: "Could not draw saturation dome"
Cause: Fluid not supported by CoolProp or is incompressible.
Solution: Check fluid name or disable dome.
plotter.plot_Ts_diagram(['1','2','3','4','1'], show_dome=False)
Issue: Heat exchanger profile fails
Cause: HEX type is SimpleHEX or not solved.
Solution: Use detailed HEX models (double_pipe, Condenser, Evaporator).
API Reference Summary
| Method | Purpose | CSV Export | Returns |
|---|---|---|---|
plot_Ts_diagram() |
Temperature-Entropy plot | ✅ | fig, ax |
plot_Ph_diagram() |
Pressure-Enthalpy plot | ✅ | fig, ax |
plot_hs_diagram() |
Enthalpy-Entropy plot | ✅ | fig, ax |
plot_hex_profile() |
Heat exchanger profile | ✅ | min_dT |
plot_exergy_bar() |
Exergy destruction bars | ✅ | fig, ax |
plot_exergy_pie() |
Exergy destruction pie | ✅ | fig, ax |
plot_energy_summary() |
Energy flow summary | ✅ | fig, ax |
export_all_points() |
Export all state points | ✅ (only) | csv_path |
export_all_components() |
Export all components | ✅ (only) | csv_path |
Version Information
- Version: 2.0.0
- New Features: CSV export for all plots, data export methods, improved error handling
- Breaking Changes: None (backward compatible)
- Dependencies:
pandas,matplotlib,numpy,CoolProp