mantis-rtm 0.1.1.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mantis/__init__.py +5 -0
- mantis/_version.py +24 -0
- mantis/diff_lib.py +1937 -0
- mantis/generate_equation_system.py +1975 -0
- mantis/live_plot_lib.py +623 -0
- mantis/model.py +942 -0
- mantis/monitor_plots.py +171 -0
- mantis/monolithic_solver.py +904 -0
- mantis/parallel_video.py +523 -0
- mantis/plot_data_new.py +1363 -0
- mantis/solvers_numba.py +219 -0
- mantis_rtm-0.1.1.dev0.dist-info/METADATA +175 -0
- mantis_rtm-0.1.1.dev0.dist-info/RECORD +17 -0
- mantis_rtm-0.1.1.dev0.dist-info/WHEEL +5 -0
- mantis_rtm-0.1.1.dev0.dist-info/entry_points.txt +6 -0
- mantis_rtm-0.1.1.dev0.dist-info/licenses/LICENSE +661 -0
- mantis_rtm-0.1.1.dev0.dist-info/top_level.txt +1 -0
mantis/monitor_plots.py
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
import time
|
|
3
|
+
import argparse
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import pathlib as pl
|
|
6
|
+
from watchdog.observers import Observer
|
|
7
|
+
from watchdog.events import FileSystemEventHandler
|
|
8
|
+
|
|
9
|
+
# Import project-specific modules
|
|
10
|
+
import mantis.plot_data_new as plot_data_new
|
|
11
|
+
|
|
12
|
+
class PlotUpdateHandler(FileSystemEventHandler):
|
|
13
|
+
"""Handles file system events for the results CSV."""
|
|
14
|
+
|
|
15
|
+
def __init__(
|
|
16
|
+
self, csv_file, layout_file, display_length, measured_data, output_plot=None
|
|
17
|
+
):
|
|
18
|
+
super().__init__()
|
|
19
|
+
self.csv_file = csv_file
|
|
20
|
+
self.layout_file = layout_file
|
|
21
|
+
self.display_length = display_length
|
|
22
|
+
self.measured_data = measured_data
|
|
23
|
+
self.output_plot = output_plot
|
|
24
|
+
self.last_trigger_time = 0
|
|
25
|
+
self.debounce_seconds = 1.0
|
|
26
|
+
|
|
27
|
+
def on_modified(self, event):
|
|
28
|
+
self._handle_event(event)
|
|
29
|
+
|
|
30
|
+
def on_created(self, event):
|
|
31
|
+
self._handle_event(event)
|
|
32
|
+
|
|
33
|
+
def on_moved(self, event):
|
|
34
|
+
self._handle_event(event)
|
|
35
|
+
|
|
36
|
+
def _handle_event(self, event):
|
|
37
|
+
if event.is_directory:
|
|
38
|
+
return
|
|
39
|
+
|
|
40
|
+
# Target files
|
|
41
|
+
target_csv = pl.Path(self.csv_file).resolve()
|
|
42
|
+
target_layout = pl.Path(self.layout_file).resolve()
|
|
43
|
+
|
|
44
|
+
# Source path of the event
|
|
45
|
+
src_path = pl.Path(event.src_path).resolve()
|
|
46
|
+
# For MoveEvent, we also check dest_path
|
|
47
|
+
dest_path = pl.Path(event.dest_path).resolve() if hasattr(event, 'dest_path') else None
|
|
48
|
+
|
|
49
|
+
is_match = (src_path == target_csv or src_path == target_layout or
|
|
50
|
+
(dest_path and (dest_path == target_csv or dest_path == target_layout)))
|
|
51
|
+
|
|
52
|
+
if is_match:
|
|
53
|
+
current_time = time.time()
|
|
54
|
+
dt = current_time - self.last_trigger_time
|
|
55
|
+
if dt > self.debounce_seconds:
|
|
56
|
+
print(f"[Monitor] DEBUG: Triggered by {event.event_type} on {src_path} (dt={dt:.3f}s)")
|
|
57
|
+
self.last_trigger_time = current_time
|
|
58
|
+
self.trigger_plot()
|
|
59
|
+
else:
|
|
60
|
+
# print(f"[Monitor] DEBUG: Debounced {event.event_type} on {src_path} (dt={dt:.3f}s)")
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
def trigger_plot(self):
|
|
64
|
+
print(f"[Monitor] Change detected. Updating plots...")
|
|
65
|
+
try:
|
|
66
|
+
# Short sleep to ensure the file is fully written/closed by the simulation
|
|
67
|
+
time.sleep(0.5)
|
|
68
|
+
|
|
69
|
+
# Load the fresh data
|
|
70
|
+
df = pd.read_csv(self.csv_file)
|
|
71
|
+
|
|
72
|
+
# Use specified output name or derive from CSV
|
|
73
|
+
output_path = (
|
|
74
|
+
pl.Path(self.output_plot)
|
|
75
|
+
if self.output_plot
|
|
76
|
+
else pl.Path(self.csv_file).with_suffix(".pdf")
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Load layout (this allows updates to plot_layout.py to be picked up too)
|
|
80
|
+
plt_desc = plot_data_new.load_layout_from_file(df, self.layout_file, self.measured_data)
|
|
81
|
+
|
|
82
|
+
# Execute the plotting function as requested
|
|
83
|
+
plot_data_new.plot(
|
|
84
|
+
df,
|
|
85
|
+
self.display_length,
|
|
86
|
+
output_path,
|
|
87
|
+
show=False,
|
|
88
|
+
plot_description=plt_desc,
|
|
89
|
+
measured_data_path=self.measured_data,
|
|
90
|
+
)
|
|
91
|
+
print(f"[Monitor] Plots updated: {output_path.name}")
|
|
92
|
+
|
|
93
|
+
except Exception as e:
|
|
94
|
+
print(f"[Monitor] Error during plotting: {e}")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def main():
|
|
98
|
+
import sys
|
|
99
|
+
|
|
100
|
+
parser = argparse.ArgumentParser(
|
|
101
|
+
description="Monitor a CSV file and update plots automatically."
|
|
102
|
+
)
|
|
103
|
+
parser.add_argument(
|
|
104
|
+
"-f", "--file", default="pyrite_model_fipy.csv", help="CSV file to monitor"
|
|
105
|
+
)
|
|
106
|
+
parser.add_argument(
|
|
107
|
+
"-l", "--layout", default="plot_layout.py", help="Plot layout file"
|
|
108
|
+
)
|
|
109
|
+
parser.add_argument(
|
|
110
|
+
"-d",
|
|
111
|
+
"--display_length",
|
|
112
|
+
type=float,
|
|
113
|
+
default=2.0,
|
|
114
|
+
help="Display length in meters",
|
|
115
|
+
)
|
|
116
|
+
parser.add_argument("-m", "--measured", default=None, help="Measured data CSV file")
|
|
117
|
+
parser.add_argument(
|
|
118
|
+
"-o", "--output", help="Output plot filename (default: derived from --file)"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
if len(sys.argv) == 1:
|
|
122
|
+
parser.print_help()
|
|
123
|
+
sys.exit(0)
|
|
124
|
+
|
|
125
|
+
args = parser.parse_args()
|
|
126
|
+
|
|
127
|
+
# Determine output path for the initial check
|
|
128
|
+
output_path = (
|
|
129
|
+
pl.Path(args.output) if args.output else pl.Path(args.file).with_suffix(".pdf")
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Setup the observer to watch the current directory
|
|
133
|
+
path = "."
|
|
134
|
+
event_handler = PlotUpdateHandler(
|
|
135
|
+
csv_file=args.file,
|
|
136
|
+
layout_file=args.layout,
|
|
137
|
+
display_length=args.display_length,
|
|
138
|
+
measured_data=args.measured,
|
|
139
|
+
output_plot=args.output,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# --- Initial Check ---
|
|
143
|
+
if not output_path.exists():
|
|
144
|
+
print(
|
|
145
|
+
f"[Monitor] Output file {output_path.name} not found. Generating initial plot..."
|
|
146
|
+
)
|
|
147
|
+
event_handler.trigger_plot()
|
|
148
|
+
|
|
149
|
+
observer = Observer()
|
|
150
|
+
observer.schedule(event_handler, path, recursive=False)
|
|
151
|
+
|
|
152
|
+
print(f"Starting Plot Monitor...")
|
|
153
|
+
print(f"Watching: {args.file}")
|
|
154
|
+
if args.output:
|
|
155
|
+
print(f"Output: {args.output}")
|
|
156
|
+
print(f"Layout: {args.layout}")
|
|
157
|
+
print(f"Display Length: {args.display_length}m")
|
|
158
|
+
print(f"Press Ctrl+C to stop.")
|
|
159
|
+
|
|
160
|
+
observer.start()
|
|
161
|
+
try:
|
|
162
|
+
while True:
|
|
163
|
+
time.sleep(1)
|
|
164
|
+
except KeyboardInterrupt:
|
|
165
|
+
print("\nStopping monitor...")
|
|
166
|
+
observer.stop()
|
|
167
|
+
observer.join()
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
if __name__ == "__main__":
|
|
171
|
+
main()
|