Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file not shown.
64 changes: 64 additions & 0 deletions src/main/Simulator/Generated/data.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
within Simulator.Generated;

package data

record GeneralProperties "Record to declare the variables for thermophysical properties of the compounds in the database"
extends Modelica.Icons.Record;
parameter Integer SN "Serial Number";
parameter String name "Compound Name";
parameter String CAS "CAS Number";
parameter Real Tc (unit="K") "Critical Temperature";
parameter Real Pc (unit="Pa") "Critical Pressure";
parameter Real Vc (unit="m3/kmol") "Critical Volume";
parameter Real Cc (unit="-") "Critical Compressibility Factor";
parameter Real Tb (unit="K") "Boiling Point Temperature";
parameter Real Tm (unit="K") "Melting Point Temperature";
parameter Real TT (unit="K") "Triple Point Temperature";
parameter Real TP (unit="Pa") "Triple Point Pressure";
parameter Real MW (unit="-") "Molecular Weight";
parameter Real LVB (unit="m3/kmol") "Liquid Molar Volume at Normal Boiling Point";
parameter Real AF (unit="-") "Acentric Factor";
parameter Real SP (unit="J0.5/m1.5") "Solubility Parameter";
parameter Real DM (unit="Coulomb.m") "Dipole Moment";
parameter Real SH (unit="J/kmol") "Absolute Enthalpy";
parameter Real IGHF (unit="J/kmol") "Standard Heat of Formation";
parameter Real GEF (unit="J/kmol") "Gibbs Energy of Formation";
parameter Real AS (unit="J/kmol/K") "Absolute Entropy";
parameter Real HFMP (unit="J/kmol") "Heat of Fusion at Melting Point";
parameter Real HOC (unit="J/kmol") "Heat of Combustion";
parameter Real UniquacR (unit="-") "UNIQUAC r";
parameter Real UniquacQ (unit="-") "UNIQUAC q";
parameter Real LiqDen[6] (each unit="kmol/m3") "Liquid Density Coefficients";
parameter Real VP[6] (each unit="Pa") "Vapor Pressure Coefficients";
parameter Real LiqCp[6] (each unit="J/kmol/K") "Liquid Heat Capacity Coefficients";
parameter Real HOV[6] (each unit="J/kmol") "Heat of Vaporization Coefficients";
parameter Real VapCp[6] (each unit="J/kmol/K") "Ideal Gas Heat Capacity Coefficients";
parameter Real LiqVis[6] (each unit="Pa s") "Liquid Viscosity Coefficients";
parameter Real VapVis[6] (each unit="Pa s") "Vapor Viscosity Coefficients";
parameter Real LiqK[6] (each unit="W/m/K") "Liquid Thermal Conductivity Coefficients";
parameter Real VapK[6] (each unit="W/m/K") "Vapor Thermal Conductivity Coefficients";
parameter Real Racketparam (unit="-") "Racket Parameter";
parameter Real ChaoSeadAF (unit="-") "Chao-Seader Accentric Factor";
parameter Real ChaoSeadSP (unit="J0.5/m1.5") "Shao-Seader Solubility Parameter";
parameter Real ChaoSeadLV (unit="m3/kmol") "Chao-Seader Liquid Volume";
end GeneralProperties;


record Air
extends Modelica.Icons.Record;
extends GeneralProperties(SN = 1, name = "Air", CAS = "132259-10-0", Tc = 132.45, Pc = 3774000, Vc = 0.09147, Cc = 0.313, Tb = 78.67, Tm = 59.15, TT = 59.15, TP = 5642.15, MW = 28.96, LVB = 0.0329147, AF = 0, SP = 12750, DM = 0, SH = 0.0, IGHF = 0, GEF = 0, AS = 199000, HFMP = 0, HOC = 0, LiqDen = {105, 2.6731, 0.25637, 132.51, 0.26788, 0}, VP = {101, 14.794, -599.85, 1.0009, -3.9938E-07, 2}, LiqCp = {16, 53628, 4511.1, -143.29, 1.582, -0.0051332}, HOV = {106, 7385651, 0.276676, 0.211253, -0.836764, 0.722737}, VapCp = {100, 29562.29, -7.164949, 0.0216294, -0.0000139748, 2.89195E-09}, LiqVis = {101, -72.336, 813.48, 12.687, -0.00033062, 2}, VapVis = {102, 0.000001592, 0.48975, 123.45, -829.58, 0}, LiqK = {16, -0.21199, -16.311, -0.23057, -0.0076197, 0.0000025018}, VapK = {102, 0.0003511, 0.76492, 16.071, 1084.4, 0}, Racketparam = 0.29056, UniquacR = 0, UniquacQ = 0, ChaoSeadAF = -0.00787976, ChaoSeadSP = 12749.8, ChaoSeadLV = 0.0329147);
end Air;


record Argon
extends Modelica.Icons.Record;
extends GeneralProperties(SN = 2, name = "Argon", CAS = "7440-37-1", Tc = 150.86, Pc = 4898000, Vc = 0.07457, Cc = 0.291, Tb = 87.27, Tm = 83.8039, TT = 83.8, TP = 68906.1, MW = 39.948, LVB = 0.0291, AF = -0.002, SP = 14138.3, DM = 0, SH = 0.0, IGHF = 0, GEF = 0, AS = 154732, HFMP = 1184900, HOC = 0, LiqDen = {105, 3.803, 0.286, 150.86, 0.2984, 0}, VP = {101, 44.369, -1126.1, -4.5688, 0.000062339, 2}, LiqCp = {16, 46085, -1304.5, 21.195, -0.015382, 0.000033063}, HOV = {106, 7981000, 0.099752, 0.32009, -0.11898, 0.031141}, VapCp = {16, 20786, 0, 0, 0, 0}, LiqVis = {101, -99.903, 1347.5, 17.615, -0.00032893, 2}, VapVis = {102, 0.0000010023, 0.5922, 85.563, 238.26, 0}, LiqK = {16, -0.30397, -0.82999, -0.71462, -0.00039294, -0.000012209}, VapK = {102, 0.00013095, 0.81923, -122.33, 13993, 0}, Racketparam = 0, UniquacR = 1.1074, UniquacQ = 1.068, ChaoSeadAF = -0.002, ChaoSeadSP = 14138.3, ChaoSeadLV = 0.0285865);
end Argon;


record Bromine
extends Modelica.Icons.Record;
extends GeneralProperties(SN = 3, name = "Bromine", CAS = "7726-95-6", Tc = 584.15, Pc = 1.03E+07, Vc = 0.135, Cc = 0.286, Tb = 331.9, Tm = 265.9, TT = 265.85, TP = 5853.37, MW = 159.808, LVB = 0.0514795, AF = 0.128997, SP = 23590, DM = 0, SH = 0.0, IGHF = 3.091E+07, GEF = 3140000, AS = 245350, HFMP = 1.057E+07, HOC = 0, LiqDen = {105, 2.0603, 0.28982, 584.15, 0.28948, 0}, VP = {101, 63.657, -5321.6, -6.3199, 0.0000054412, 2}, LiqCp = {16, 75351, -4.87E+07, 54033, 102.73, 0.43775}, HOV = {106, 3.8419E+07, -0.26282, 2.1808, -2.7529, 1.1823}, VapCp = {16, 35000, -410, 8.5, -0.00016, -0.00000001}, LiqVis = {101, -5.9813, 410.55, -0.30036, -0.000006936, 2}, VapVis = {102, 1.1438E-07, 0.88111, 59.595, -6723.3, 0}, LiqK = {16, -0.69183, 27.775, -0.38966, 0.00057103, -8.8462E-07}, VapK = {102, 0.0000065648, 1.4785, 4505.6, -870500, 0}, Racketparam = 0.279241, UniquacR = 1.8985, UniquacQ = 1.672, ChaoSeadAF = 0.108, ChaoSeadSP = 23591.8, ChaoSeadLV = 0.0514795);
end Bromine;

end data;
5 changes: 5 additions & 0 deletions src/main/Simulator/Generated/package.mo
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
within Simulator;

package Generated
extends Modelica.Icons.Package;
end Generated;
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
83 changes: 52 additions & 31 deletions src/main/python/Landing_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..')))
from src.main.ui.utils.LandingPageUI import IconPanel, GlassButton

# Import the module-level globals that Graphics.py uses so we can
# purge them before stashing the old MainApp window.
try:
from python.utils.Graphics import dock_widget_lst as _dock_widget_lst, lst as _node_lst
except Exception:
_dock_widget_lst = None
_node_lst = None

# Keep old MainApp instances alive (hidden) so their C++ objects are never
# destroyed while something might still reference them. This prevents the
# "wrapped C/C++ object has been deleted" crashes and the "Not responding"
# freezes caused by asynchronous deleteLater() destruction.
_stashed_windows = []

class LandingPage(QWidget):
def __init__(self):
super().__init__()
Expand All @@ -41,7 +55,7 @@ def __init__(self):
self.main_window = None
self.init_ui()

# 🔥 Start background preload once the window is ready
# Start background preload once the window is ready
QTimer.singleShot(500, self.preload_main_window)

def paintEvent(self, event):
Expand Down Expand Up @@ -157,13 +171,33 @@ def start_simulation(self):


def _cleanup_main_window(self):
"""Safely schedule the old main window for deletion."""
"""Hide the old main window and stash it so it stays alive.

We intentionally do NOT call deleteLater(). Destroying a QMainWindow
with dozens of child widgets, dock widgets, QThreads, and scene items
triggers asynchronous C++ object destruction that races with the Qt
event loop and causes 'Not responding' freezes or outright segfaults.
Keeping the old window alive but hidden is safe and costs very little
memory (users won't create hundreds of sessions).
"""
if self.main_window is not None:
# Clear the module-level global Graphics lists so the new
# MainApp starts with clean state.
try:
if _dock_widget_lst is not None:
_dock_widget_lst.clear()
if _node_lst is not None:
_node_lst.clear()
except Exception:
pass

try:
self.main_window.hide()
self.main_window.deleteLater()
except Exception:
pass

# Stash — prevent Python GC from collecting (and destroying) it
_stashed_windows.append(self.main_window)
self.main_window = None

def open_existing_project(self):
Expand All @@ -184,18 +218,8 @@ def open_existing_project(self):
self._cleanup_main_window()
self.main_window = MainApp()

# Preserve original closeEvent
orig_close = getattr(self.main_window, "closeEvent", None)
def _wrapped_close(event):
try:
if orig_close is not None:
orig_close(event)
except Exception:
pass
if event.isAccepted():
# Defer restoration so closeEvent finishes before we touch self.main_window
QTimer.singleShot(0, self.restore_landing_page)
self.main_window.closeEvent = _wrapped_close
# Connect to closed signal to restore landing page
self.main_window.closed.connect(lambda: QTimer.singleShot(0, self.restore_landing_page))

# Open project file
self.main_window.open(file_path)
Expand Down Expand Up @@ -241,18 +265,8 @@ def launch_main_window(self):
self.main_window = MainApp()
self.main_window.new_project() # reset all components for new project

# Wrap closeEvent to restore landing page
orig_close = getattr(self.main_window, "closeEvent", None)
def _wrapped_close(event):
if orig_close:
try:
orig_close(event)
except Exception:
pass
if event.isAccepted():
# Defer restoration so closeEvent finishes before we touch self.main_window
QTimer.singleShot(0, self.restore_landing_page)
self.main_window.closeEvent = _wrapped_close
# Connect to closed signal to restore landing page
self.main_window.closed.connect(lambda: QTimer.singleShot(0, self.restore_landing_page))

# Show main window maximized
self.main_window.showMaximized()
Expand Down Expand Up @@ -324,20 +338,26 @@ def fit_canvas(self):
gv.centerOn(self.main_window.scene.itemsBoundingRect().center())
self.reset_cursor()

def closeEvent(self, event):
# Explicitly quit the entire application when the landing page is closed
QApplication.quit()
event.accept()

def restore_landing_page(self):
# Drain the entire override cursor stack left by MainApp/Graphics/Container
# before showing the landing page, to prevent corrupted mouse events.
while QApplication.overrideCursor() is not None:
QApplication.restoreOverrideCursor()

# Safely clean up old main window using Qt event loop
self._cleanup_main_window()

# Show landing page in full screen
# self.showFullScreen()

# Show landing page (windowed)
self.show()

# Make sure it is active
self.activateWindow()
self.raise_()
# QApplication.processEvents()

def resizeEvent(self, event):
# """Make sure gradient background fills screen on resize."""
Expand Down Expand Up @@ -391,6 +411,7 @@ def reset_cursor(self):

def run():
app = QApplication(sys.argv)
app.setQuitOnLastWindowClosed(False)
window = LandingPage()
window.show()
sys.exit(app.exec_())
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
52 changes: 39 additions & 13 deletions src/main/python/mainApp.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ def eventFilter(self, obj, event):
MainApp class is responsible for all the main App Ui operations
'''
class MainApp(QMainWindow,ui):
closed = pyqtSignal()
global compound_selected
'''
Initializing the application
Expand Down Expand Up @@ -446,20 +447,27 @@ def simulate(self, mode):
Terminate the current running simulation
'''
def terminate(self):
os.chdir(self.container.flowsheet.root_dir)
if self.thrd:
try:
os.chdir(self.container.flowsheet.root_dir)
except Exception:
pass

if self.thrd and self.thrd.is_alive():
thread_id = self.thrd.ident
# print('____________________Going to terminate simulation thread with Thread ID:',thread_id,'____________________')
# print('____________________Going to terminate the new process created for omc____________________')
self.container.flowsheet.process.terminate()
print('____________________New process created for omc is terminated.____________________')
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, ctypes.py_object(SystemExit))
if hasattr(self.container, 'flowsheet') and hasattr(self.container.flowsheet, 'process') and self.container.flowsheet.process:
try:
self.container.flowsheet.process.terminate()
print('____________________New process created for omc is terminated.____________________')
except Exception:
pass

res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(thread_id), ctypes.py_object(SystemExit))
self.textBrowser.append("<span style=\"color:red\">["+str(self.current_time())+"]<b>Simulation Terminated.</b></span>")
self.container.disableInterfaceforSimulation(False)
# print('____________________Simulation thread terminated____________________')
if res > 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0)
# print('Exception raise (Thread termination) failure')
ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(thread_id), 0)

self.thrd = None

'''
Resets the zoom level to default scaling
Expand Down Expand Up @@ -626,10 +634,13 @@ def new(self):
if hasattr(cls, "counter"):
cls.counter = 1

# Clear old dock widgets
# Clear old dock widgets — guard against already-deleted C++ objects
for dw in dock_widget_lst:
dw.hide()
dw.setParent(None)
try:
dw.hide()
dw.setParent(None)
except RuntimeError:
pass # C++ object already deleted — safe to skip
dock_widget_lst.clear()

# Reset compound selection
Expand Down Expand Up @@ -893,6 +904,21 @@ def _clear_selected_compounds_panel(self):
self.selectedElementsList.clear()
self._sel_status_label.setText("No compounds selected")

def closeEvent(self, event):
# Stop simulation thread if still running
try:
if self.thrd and self.thrd.is_alive():
self.terminate()
except Exception:
pass

# Drain any override cursors this window left on the stack
while QApplication.overrideCursor() is not None:
QApplication.restoreOverrideCursor()

event.accept()
self.closed.emit()

from python.utils.ComponentSelectorWindow import ComponentSelectorWindow

def select_compounds(self):
Expand Down
2 changes: 1 addition & 1 deletion src/main/python/utils/Container.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def __init__(self, msgbrowser, graphicsView):
self.result = []
self.graphics = Graphics(self, self.graphicsView)
self.scene = self.graphics.get_scene()
print(f"[DEBUG] Scene check container.scene id={id(self.scene)}, graphics.scene id={id(self.graphics.scene)}")
print(f"[DEBUG] Scene check -> container.scene id={id(self.scene)}, graphics.scene id={id(self.graphics.scene)}")


# ----------------- Utility -----------------
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading