vates 0.1.0__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.
- vates/__init__.py +30 -0
- vates/_core/__init__.py +16 -0
- vates/_core/_html_generator.py +529 -0
- vates/_core/cli.py +28 -0
- vates/_core/keyed_array.py +340 -0
- vates/_core/proj_model_engine.py +518 -0
- vates/_core/proj_variables.py +283 -0
- vates/_core/stoch_executor.py +309 -0
- vates/_core/utils.py +233 -0
- vates/alm/__init__.py +27 -0
- vates/alm/assets/__init__.py +25 -0
- vates/alm/assets/_bond_fixed_component.py +376 -0
- vates/alm/assets/_derivative_pricer.py +255 -0
- vates/alm/assets/asset_base.py +226 -0
- vates/alm/assets/bond_fixed.py +375 -0
- vates/alm/assets/builders/__init__.py +11 -0
- vates/alm/assets/builders/asset_creation.py +48 -0
- vates/alm/assets/builders/bond_fixed_builder.py +251 -0
- vates/alm/assets/builders/equity_option_builder.py +125 -0
- vates/alm/assets/cash.py +147 -0
- vates/alm/assets/equity.py +184 -0
- vates/alm/assets/equity_option.py +248 -0
- vates/alm/econs/__init__.py +14 -0
- vates/alm/econs/credit_band.py +95 -0
- vates/alm/econs/currency.py +57 -0
- vates/alm/econs/equity_index.py +120 -0
- vates/alm/econs/market_info.py +49 -0
- vates/alm/econs/yield_curve.py +135 -0
- vates/alm/enums.py +34 -0
- vates/alm/funds/__init__.py +10 -0
- vates/alm/funds/_asset_allocator.py +425 -0
- vates/alm/funds/_fund_calculator.py +332 -0
- vates/alm/funds/fund.py +322 -0
- vates/alm/liabs/__init__.py +7 -0
- vates/alm/liabs/ext_proj_liab.py +130 -0
- vates/alm/liabs/liab_base.py +208 -0
- vates/solvency/__init__.py +6 -0
- vates/solvency/cn_cross2/__init__.py +27 -0
- vates/solvency/cn_cross2/params.py +186 -0
- vates/solvency/cn_cross2/quant_risk_min_cap.py +366 -0
- vates/utils/__init__.py +96 -0
- vates/utils/curve_conversion.py +297 -0
- vates/utils/curve_extrapolation.py +334 -0
- vates/utils/curve_interpolation.py +168 -0
- vates/utils/data_classes.py +26 -0
- vates/utils/qfi.py +83 -0
- vates/utils/risk_module.py +55 -0
- vates/utils/uncategorized.py +28 -0
- vates-0.1.0.dist-info/METADATA +106 -0
- vates-0.1.0.dist-info/RECORD +53 -0
- vates-0.1.0.dist-info/WHEEL +5 -0
- vates-0.1.0.dist-info/licenses/LICENSE +21 -0
- vates-0.1.0.dist-info/top_level.txt +1 -0
vates/__init__.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from vates._core import (
|
|
2
|
+
cli_main,
|
|
3
|
+
cli_run,
|
|
4
|
+
ProjModelEngine,
|
|
5
|
+
StochExecutor,
|
|
6
|
+
ConstVariable,
|
|
7
|
+
TDepVariable,
|
|
8
|
+
KeyedArray,
|
|
9
|
+
)
|
|
10
|
+
from vates import utils
|
|
11
|
+
|
|
12
|
+
from vates import alm
|
|
13
|
+
from vates import solvency
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
# core
|
|
17
|
+
'cli_main',
|
|
18
|
+
'cli_run',
|
|
19
|
+
'ProjModelEngine',
|
|
20
|
+
'StochExecutor',
|
|
21
|
+
'ConstVariable',
|
|
22
|
+
'TDepVariable',
|
|
23
|
+
'KeyedArray',
|
|
24
|
+
# utils
|
|
25
|
+
'utils',
|
|
26
|
+
# libs
|
|
27
|
+
'alm',
|
|
28
|
+
'solvency',
|
|
29
|
+
|
|
30
|
+
]
|
vates/_core/__init__.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from vates._core.proj_model_engine import ProjModelEngine
|
|
2
|
+
from vates._core.stoch_executor import StochExecutor
|
|
3
|
+
from vates._core.proj_variables import ConstVariable, TDepVariable
|
|
4
|
+
from vates._core.cli import cli_main, cli_run
|
|
5
|
+
from vates._core.keyed_array import KeyedArray
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
'cli_main',
|
|
10
|
+
'cli_run',
|
|
11
|
+
'ProjModelEngine',
|
|
12
|
+
'StochExecutor',
|
|
13
|
+
'ConstVariable',
|
|
14
|
+
'TDepVariable',
|
|
15
|
+
'KeyedArray',
|
|
16
|
+
]
|
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
import os
|
|
3
|
+
from typing import Dict, Any
|
|
4
|
+
|
|
5
|
+
def generate_runlog_html(runlog: Dict[str, Any]) -> str:
|
|
6
|
+
"""
|
|
7
|
+
Convert a runlog dictionary to a beautiful HTML visualization.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
runlog: Dictionary containing model run information
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
HTML content as string
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def calculate_duration(start_str: str, end_str: str) -> str:
|
|
17
|
+
"""Calculate duration between start and end times"""
|
|
18
|
+
start = datetime.strptime(start_str, "%Y-%m-%d %H:%M:%S")
|
|
19
|
+
end = datetime.strptime(end_str, "%Y-%m-%d %H:%M:%S")
|
|
20
|
+
sec = (end - start).total_seconds()
|
|
21
|
+
|
|
22
|
+
if sec < 60:
|
|
23
|
+
return f"~{int(sec)} second{'s' if sec != 1 else ''}"
|
|
24
|
+
elif sec < 3600:
|
|
25
|
+
minutes = round(sec / 60, 1)
|
|
26
|
+
return f"~{minutes} minute{'s' if int(minutes) != 1 else ''}"
|
|
27
|
+
else:
|
|
28
|
+
hours = round(sec / 3600, 2)
|
|
29
|
+
return f"~{hours} hour{'s' if int(hours) != 1 else ''}"
|
|
30
|
+
|
|
31
|
+
def get_file_info(file_path: str) -> tuple:
|
|
32
|
+
"""Get file modification time and size"""
|
|
33
|
+
try:
|
|
34
|
+
if os.path.exists(file_path):
|
|
35
|
+
stat_info = os.stat(file_path)
|
|
36
|
+
file_mtime = datetime.fromtimestamp(stat_info.st_mtime).strftime("%Y-%m-%d %H:%M:%S")
|
|
37
|
+
size_bytes = stat_info.st_size
|
|
38
|
+
|
|
39
|
+
# Format file size
|
|
40
|
+
if size_bytes < 1024 * 1024:
|
|
41
|
+
size_str = f"{size_bytes / 1024:.1f} KB"
|
|
42
|
+
elif size_bytes < 1024 * 1024 * 1024:
|
|
43
|
+
size_str = f"{size_bytes / (1024 * 1024):.1f} MB"
|
|
44
|
+
else:
|
|
45
|
+
size_str = f"{size_bytes / (1024 * 1024 * 1024):.1f} GB"
|
|
46
|
+
|
|
47
|
+
return file_mtime, size_str
|
|
48
|
+
else:
|
|
49
|
+
return "File not found", "N/A"
|
|
50
|
+
except Exception as e:
|
|
51
|
+
return "Unknown", "Unknown"
|
|
52
|
+
|
|
53
|
+
# Extract data from runlog
|
|
54
|
+
model_name = runlog['model_name']
|
|
55
|
+
model_desc = runlog['model_desc']
|
|
56
|
+
exe_start_time = runlog['exe_start_time']
|
|
57
|
+
exe_end_time = runlog['exe_end_time']
|
|
58
|
+
failed_simulations = runlog.get('failed_simulations',[])
|
|
59
|
+
settings = runlog['setting']
|
|
60
|
+
input_files = runlog['input_files']
|
|
61
|
+
proj_result_files = runlog['proj_result_files']
|
|
62
|
+
stoch_result_files = runlog['stoch_result_files']
|
|
63
|
+
other_result_files = runlog['other_result_files']
|
|
64
|
+
|
|
65
|
+
# Calculate execution duration
|
|
66
|
+
exe_duration = calculate_duration(exe_start_time, exe_end_time)
|
|
67
|
+
|
|
68
|
+
# Generate HTML
|
|
69
|
+
html_content = f"""<!DOCTYPE html>
|
|
70
|
+
<html lang="en">
|
|
71
|
+
<head>
|
|
72
|
+
<meta charset="UTF-8">
|
|
73
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
74
|
+
<title>Model Run Log - {model_name}</title>
|
|
75
|
+
<style>
|
|
76
|
+
body {{
|
|
77
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
78
|
+
line-height: 1.6;
|
|
79
|
+
margin: 0;
|
|
80
|
+
padding: 20px;
|
|
81
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
82
|
+
min-height: 100vh;
|
|
83
|
+
}}
|
|
84
|
+
|
|
85
|
+
.container {{
|
|
86
|
+
max-width: 1200px;
|
|
87
|
+
margin: 0 auto;
|
|
88
|
+
background: white;
|
|
89
|
+
border-radius: 12px;
|
|
90
|
+
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
|
|
91
|
+
overflow: hidden;
|
|
92
|
+
}}
|
|
93
|
+
|
|
94
|
+
.header {{
|
|
95
|
+
background: linear-gradient(135deg, #2c3e50 0%, #3498db 100%);
|
|
96
|
+
color: white;
|
|
97
|
+
padding: 30px;
|
|
98
|
+
text-align: center;
|
|
99
|
+
}}
|
|
100
|
+
|
|
101
|
+
.header h1 {{
|
|
102
|
+
margin: 0;
|
|
103
|
+
font-size: 2.5em;
|
|
104
|
+
font-weight: 300;
|
|
105
|
+
}}
|
|
106
|
+
|
|
107
|
+
.header .subtitle {{
|
|
108
|
+
opacity: 0.9;
|
|
109
|
+
font-size: 1.1em;
|
|
110
|
+
margin-top: 10px;
|
|
111
|
+
}}
|
|
112
|
+
|
|
113
|
+
.content {{
|
|
114
|
+
padding: 30px;
|
|
115
|
+
}}
|
|
116
|
+
|
|
117
|
+
.section {{
|
|
118
|
+
margin-bottom: 30px;
|
|
119
|
+
border-radius: 8px;
|
|
120
|
+
overflow: hidden;
|
|
121
|
+
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
122
|
+
}}
|
|
123
|
+
|
|
124
|
+
.section-header {{
|
|
125
|
+
background: linear-gradient(135deg, #34495e 0%, #2c3e50 100%);
|
|
126
|
+
color: white;
|
|
127
|
+
padding: 15px 20px;
|
|
128
|
+
font-size: 1.3em;
|
|
129
|
+
font-weight: 500;
|
|
130
|
+
cursor: pointer;
|
|
131
|
+
transition: background 0.3s ease;
|
|
132
|
+
}}
|
|
133
|
+
|
|
134
|
+
.section-header:hover {{
|
|
135
|
+
background: linear-gradient(135deg, #2c3e50 0%, #34495e 100%);
|
|
136
|
+
}}
|
|
137
|
+
|
|
138
|
+
.section-content {{
|
|
139
|
+
background: #f8f9fa;
|
|
140
|
+
padding: 20px;
|
|
141
|
+
}}
|
|
142
|
+
|
|
143
|
+
.info-grid {{
|
|
144
|
+
display: grid;
|
|
145
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
146
|
+
gap: 15px;
|
|
147
|
+
}}
|
|
148
|
+
|
|
149
|
+
.info-item {{
|
|
150
|
+
background: white;
|
|
151
|
+
padding: 15px;
|
|
152
|
+
border-radius: 6px;
|
|
153
|
+
border-left: 4px solid #3498db;
|
|
154
|
+
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
|
|
155
|
+
}}
|
|
156
|
+
|
|
157
|
+
.info-label {{
|
|
158
|
+
font-weight: 600;
|
|
159
|
+
color: #2c3e50;
|
|
160
|
+
margin-bottom: 5px;
|
|
161
|
+
font-size: 0.9em;
|
|
162
|
+
text-transform: uppercase;
|
|
163
|
+
letter-spacing: 0.5px;
|
|
164
|
+
}}
|
|
165
|
+
|
|
166
|
+
.info-value {{
|
|
167
|
+
color: #34495e;
|
|
168
|
+
font-family: 'Consolas', 'Monaco', monospace;
|
|
169
|
+
background: #ecf0f1;
|
|
170
|
+
padding: 8px;
|
|
171
|
+
border-radius: 4px;
|
|
172
|
+
word-break: break-all;
|
|
173
|
+
}}
|
|
174
|
+
|
|
175
|
+
.file-list {{
|
|
176
|
+
display: flex;
|
|
177
|
+
flex-direction: column;
|
|
178
|
+
gap: 8px;
|
|
179
|
+
}}
|
|
180
|
+
|
|
181
|
+
.file-item {{
|
|
182
|
+
background: white;
|
|
183
|
+
padding: 15px;
|
|
184
|
+
border-radius: 6px;
|
|
185
|
+
border-left: 4px solid #e74c3c;
|
|
186
|
+
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
|
|
187
|
+
display: grid;
|
|
188
|
+
grid-template-columns: 40px 1fr auto auto;
|
|
189
|
+
gap: 15px;
|
|
190
|
+
align-items: center;
|
|
191
|
+
}}
|
|
192
|
+
|
|
193
|
+
.file-item.result {{
|
|
194
|
+
border-left-color: #27ae60;
|
|
195
|
+
}}
|
|
196
|
+
|
|
197
|
+
.file-number {{
|
|
198
|
+
font-weight: bold;
|
|
199
|
+
color: #3498db;
|
|
200
|
+
font-size: 1.1em;
|
|
201
|
+
}}
|
|
202
|
+
|
|
203
|
+
.file-details {{
|
|
204
|
+
display: flex;
|
|
205
|
+
flex-direction: column;
|
|
206
|
+
}}
|
|
207
|
+
|
|
208
|
+
.file-name {{
|
|
209
|
+
font-weight: 600;
|
|
210
|
+
color: #2c3e50;
|
|
211
|
+
margin-bottom: 2px;
|
|
212
|
+
}}
|
|
213
|
+
|
|
214
|
+
.file-path {{
|
|
215
|
+
font-family: 'Consolas', 'Monaco', monospace;
|
|
216
|
+
color: #7f8c8d;
|
|
217
|
+
font-size: 0.85em;
|
|
218
|
+
}}
|
|
219
|
+
|
|
220
|
+
.file-mod-time {{
|
|
221
|
+
font-size: 0.8em;
|
|
222
|
+
color: #95a5a6;
|
|
223
|
+
text-align: center;
|
|
224
|
+
}}
|
|
225
|
+
|
|
226
|
+
.file-size {{
|
|
227
|
+
font-size: 0.8em;
|
|
228
|
+
color: #95a5a6;
|
|
229
|
+
font-weight: 500;
|
|
230
|
+
text-align: right;
|
|
231
|
+
}}
|
|
232
|
+
|
|
233
|
+
.collapsible {{
|
|
234
|
+
max-height: 0;
|
|
235
|
+
overflow: hidden;
|
|
236
|
+
transition: max-height 0.3s ease;
|
|
237
|
+
}}
|
|
238
|
+
|
|
239
|
+
.collapsible.active {{
|
|
240
|
+
max-height: 2000px;
|
|
241
|
+
}}
|
|
242
|
+
|
|
243
|
+
.toggle-btn {{
|
|
244
|
+
float: right;
|
|
245
|
+
font-size: 1.2em;
|
|
246
|
+
transition: transform 0.3s ease;
|
|
247
|
+
}}
|
|
248
|
+
|
|
249
|
+
.toggle-btn.rotated {{
|
|
250
|
+
transform: rotate(180deg);
|
|
251
|
+
}}
|
|
252
|
+
|
|
253
|
+
.duration {{
|
|
254
|
+
background: linear-gradient(135deg, #27ae60 0%, #2ecc71 100%);
|
|
255
|
+
color: white;
|
|
256
|
+
padding: 10px 20px;
|
|
257
|
+
border-radius: 20px;
|
|
258
|
+
display: inline-block;
|
|
259
|
+
font-weight: 600;
|
|
260
|
+
margin-top: 10px;
|
|
261
|
+
}}
|
|
262
|
+
|
|
263
|
+
.list-value {{
|
|
264
|
+
color: #34495e;
|
|
265
|
+
}}
|
|
266
|
+
|
|
267
|
+
@media (max-width: 768px) {{
|
|
268
|
+
.container {{
|
|
269
|
+
margin: 10px;
|
|
270
|
+
border-radius: 8px;
|
|
271
|
+
}}
|
|
272
|
+
|
|
273
|
+
.content {{
|
|
274
|
+
padding: 20px;
|
|
275
|
+
}}
|
|
276
|
+
|
|
277
|
+
.info-grid {{
|
|
278
|
+
grid-template-columns: 1fr;
|
|
279
|
+
}}
|
|
280
|
+
|
|
281
|
+
.file-list {{
|
|
282
|
+
flex-direction: column;
|
|
283
|
+
}}
|
|
284
|
+
|
|
285
|
+
.file-item {{
|
|
286
|
+
grid-template-columns: 30px 1fr;
|
|
287
|
+
gap: 10px;
|
|
288
|
+
}}
|
|
289
|
+
|
|
290
|
+
.file-mod-time,
|
|
291
|
+
.file-size {{
|
|
292
|
+
display: none;
|
|
293
|
+
}}
|
|
294
|
+
}}
|
|
295
|
+
</style>
|
|
296
|
+
</head>
|
|
297
|
+
<body>
|
|
298
|
+
<div class="container">
|
|
299
|
+
<div class="header">
|
|
300
|
+
<h1>Model Run Log</h1>
|
|
301
|
+
<div class="subtitle">{model_name.replace('_', ' ').title()} Execution Flash Report</div>
|
|
302
|
+
</div>
|
|
303
|
+
|
|
304
|
+
<div class="content">
|
|
305
|
+
<!-- Basic Info Section -->
|
|
306
|
+
<div class="section">
|
|
307
|
+
<div class="section-header" onclick="toggleSection('basic-info')">
|
|
308
|
+
📊 Basic Information
|
|
309
|
+
<span class="toggle-btn" id="basic-info-btn">▼</span>
|
|
310
|
+
</div>
|
|
311
|
+
<div class="section-content collapsible active" id="basic-info-content">
|
|
312
|
+
<div class="info-grid">
|
|
313
|
+
<div class="info-item" style="grid-column: 1 / 1;">
|
|
314
|
+
<div class="info-label">Model Name</div>
|
|
315
|
+
<div class="info-value">{model_name}</div>
|
|
316
|
+
</div>
|
|
317
|
+
<div class="info-item" style="grid-column: 2 / -1;">
|
|
318
|
+
<div class="info-label">Model Description</div>
|
|
319
|
+
<div class="info-value">{model_desc}</div>
|
|
320
|
+
</div>
|
|
321
|
+
<div class="info-item">
|
|
322
|
+
<div class="info-label">Execution Start Time</div>
|
|
323
|
+
<div class="info-value">{exe_start_time}</div>
|
|
324
|
+
</div>
|
|
325
|
+
<div class="info-item">
|
|
326
|
+
<div class="info-label">Execution End Time</div>
|
|
327
|
+
<div class="info-value">{exe_end_time}</div>
|
|
328
|
+
</div>
|
|
329
|
+
<div class="info-item">
|
|
330
|
+
<div class="info-label">Execution Duration</div>
|
|
331
|
+
<div class="duration">{exe_duration}</div>
|
|
332
|
+
</div>
|
|
333
|
+
</div>
|
|
334
|
+
</div>
|
|
335
|
+
</div>"""
|
|
336
|
+
|
|
337
|
+
# Settings Section
|
|
338
|
+
if settings:
|
|
339
|
+
html_content += """
|
|
340
|
+
<!-- Settings Section -->
|
|
341
|
+
<div class="section">
|
|
342
|
+
<div class="section-header" onclick="toggleSection('settings')">
|
|
343
|
+
⚙️ Run Setting
|
|
344
|
+
<span class="toggle-btn" id="settings-btn">▼</span>
|
|
345
|
+
</div>
|
|
346
|
+
<div class="section-content collapsible active" id="settings-content">
|
|
347
|
+
<div class="info-grid">"""
|
|
348
|
+
|
|
349
|
+
for key, value in settings.items():
|
|
350
|
+
if isinstance(value, list):
|
|
351
|
+
value_str = ', '.join(str(v) for v in value)
|
|
352
|
+
else:
|
|
353
|
+
value_str = str(value)
|
|
354
|
+
|
|
355
|
+
# Special formatting for specific keys
|
|
356
|
+
label = key.replace('_', ' ').title()
|
|
357
|
+
html_content += f"""
|
|
358
|
+
<div class="info-item">
|
|
359
|
+
<div class="info-label">{label}</div>
|
|
360
|
+
<div class="info-value">{value_str}</div>
|
|
361
|
+
</div>"""
|
|
362
|
+
|
|
363
|
+
html_content += """
|
|
364
|
+
</div>
|
|
365
|
+
</div>
|
|
366
|
+
</div>"""
|
|
367
|
+
|
|
368
|
+
# Input Section
|
|
369
|
+
if input_files:
|
|
370
|
+
html_content += """
|
|
371
|
+
<!-- Input Section -->
|
|
372
|
+
<div class="section">
|
|
373
|
+
<div class="section-header" onclick="toggleSection('input')">
|
|
374
|
+
📁 Input Files
|
|
375
|
+
<span class="toggle-btn" id="input-btn">▼</span>
|
|
376
|
+
</div>
|
|
377
|
+
<div class="section-content collapsible active" id="input-content">
|
|
378
|
+
<div class="file-list">"""
|
|
379
|
+
|
|
380
|
+
for i, (key, path) in enumerate(input_files.items(), 1):
|
|
381
|
+
mod_time, file_size = get_file_info(path)
|
|
382
|
+
html_content += f"""
|
|
383
|
+
<div class="file-item">
|
|
384
|
+
<div class="file-number">{i}</div>
|
|
385
|
+
<div class="file-details">
|
|
386
|
+
<div class="file-name">{key}</div>
|
|
387
|
+
<div class="file-path">{path}</div>
|
|
388
|
+
</div>
|
|
389
|
+
<div class="file-mod-time">{mod_time}</div>
|
|
390
|
+
<div class="file-size">{file_size}</div>
|
|
391
|
+
</div>"""
|
|
392
|
+
|
|
393
|
+
html_content += """
|
|
394
|
+
</div>
|
|
395
|
+
</div>
|
|
396
|
+
</div>"""
|
|
397
|
+
|
|
398
|
+
# Projection Results Section
|
|
399
|
+
if proj_result_files:
|
|
400
|
+
html_content += """
|
|
401
|
+
<!-- Projection Results Section -->
|
|
402
|
+
<div class="section">
|
|
403
|
+
<div class="section-header" onclick="toggleSection('projres')">
|
|
404
|
+
📈 Output - Projection Results
|
|
405
|
+
<span class="toggle-btn" id="projres-btn">▼</span>
|
|
406
|
+
</div>
|
|
407
|
+
<div class="section-content collapsible active" id="projres-content">
|
|
408
|
+
<div class="file-list">"""
|
|
409
|
+
|
|
410
|
+
for i, (key, path) in enumerate(proj_result_files.items(), 1):
|
|
411
|
+
mod_time, file_size = get_file_info(path)
|
|
412
|
+
html_content += f"""
|
|
413
|
+
<div class="file-item result">
|
|
414
|
+
<div class="file-number">{i}</div>
|
|
415
|
+
<div class="file-details">
|
|
416
|
+
<div class="file-name">{key}</div>
|
|
417
|
+
<div class="file-path">{path}</div>
|
|
418
|
+
</div>
|
|
419
|
+
<div class="file-mod-time">{mod_time}</div>
|
|
420
|
+
<div class="file-size">{file_size}</div>
|
|
421
|
+
</div>"""
|
|
422
|
+
|
|
423
|
+
html_content += """
|
|
424
|
+
</div>
|
|
425
|
+
</div>
|
|
426
|
+
</div>"""
|
|
427
|
+
|
|
428
|
+
# Stochastic Results Section
|
|
429
|
+
if stoch_result_files:
|
|
430
|
+
html_content += """
|
|
431
|
+
<!-- Stochastic Results Section -->
|
|
432
|
+
<div class="section">
|
|
433
|
+
<div class="section-header" onclick="toggleSection('stochres')">
|
|
434
|
+
📈 Output - Stochastic Results
|
|
435
|
+
<span class="toggle-btn" id="stochres-btn">▼</span>
|
|
436
|
+
</div>
|
|
437
|
+
<div class="section-content collapsible active" id="stochres-content">
|
|
438
|
+
<div class="file-list">"""
|
|
439
|
+
|
|
440
|
+
for i, (key, path) in enumerate(stoch_result_files.items(), 1):
|
|
441
|
+
mod_time, file_size = get_file_info(path)
|
|
442
|
+
html_content += f"""
|
|
443
|
+
<div class="file-item result">
|
|
444
|
+
<div class="file-number">{i}</div>
|
|
445
|
+
<div class="file-details">
|
|
446
|
+
<div class="file-name">{key}</div>
|
|
447
|
+
<div class="file-path">{path}</div>
|
|
448
|
+
</div>
|
|
449
|
+
<div class="file-mod-time">{mod_time}</div>
|
|
450
|
+
<div class="file-size">{file_size}</div>
|
|
451
|
+
</div>"""
|
|
452
|
+
|
|
453
|
+
html_content += """
|
|
454
|
+
</div>
|
|
455
|
+
</div>
|
|
456
|
+
</div>"""
|
|
457
|
+
|
|
458
|
+
# Failed Simulations Section
|
|
459
|
+
if failed_simulations:
|
|
460
|
+
html_content += """
|
|
461
|
+
<!-- Failed Simulations Section -->
|
|
462
|
+
<div class="section">
|
|
463
|
+
<div class="section-header" onclick="toggleSection('failsim')">
|
|
464
|
+
⚠️ Failed Simulation
|
|
465
|
+
<span class="toggle-btn" id="failsim-btn">▼</span>
|
|
466
|
+
</div>
|
|
467
|
+
<div class="section-content collapsible active" id="failsim-content">
|
|
468
|
+
<div class="file-list">"""
|
|
469
|
+
|
|
470
|
+
for sim, err in failed_simulations:
|
|
471
|
+
html_content += f"""
|
|
472
|
+
<div class="simulation result">
|
|
473
|
+
<div class="file-number">{sim}</div>
|
|
474
|
+
<div class="file-path">{err}</div>
|
|
475
|
+
</div>"""
|
|
476
|
+
|
|
477
|
+
html_content += """
|
|
478
|
+
</div>
|
|
479
|
+
</div>
|
|
480
|
+
</div>"""
|
|
481
|
+
|
|
482
|
+
# Other Results Section
|
|
483
|
+
if other_result_files:
|
|
484
|
+
html_content += """
|
|
485
|
+
<!-- Other Results Section -->
|
|
486
|
+
<div class="section">
|
|
487
|
+
<div class="section-header" onclick="toggleSection('otherres')">
|
|
488
|
+
📈 Output - Other
|
|
489
|
+
<span class="toggle-btn" id="otherres-btn">▼</span>
|
|
490
|
+
</div>
|
|
491
|
+
<div class="section-content collapsible active" id="otherres-content">
|
|
492
|
+
<div class="file-list">"""
|
|
493
|
+
|
|
494
|
+
for i, (key, path) in enumerate(other_result_files.items(), 1):
|
|
495
|
+
mod_time, file_size = get_file_info(path)
|
|
496
|
+
html_content += f"""
|
|
497
|
+
<div class="file-item result">
|
|
498
|
+
<div class="file-number">{i}</div>
|
|
499
|
+
<div class="file-details">
|
|
500
|
+
<div class="file-name">{key}</div>
|
|
501
|
+
<div class="file-path">{path}</div>
|
|
502
|
+
</div>
|
|
503
|
+
<div class="file-mod-time">{mod_time}</div>
|
|
504
|
+
<div class="file-size">{file_size}</div>
|
|
505
|
+
</div>"""
|
|
506
|
+
|
|
507
|
+
html_content += """
|
|
508
|
+
</div>
|
|
509
|
+
</div>
|
|
510
|
+
</div>"""
|
|
511
|
+
|
|
512
|
+
# Close HTML
|
|
513
|
+
html_content += """
|
|
514
|
+
</div>
|
|
515
|
+
</div>
|
|
516
|
+
|
|
517
|
+
<script>
|
|
518
|
+
function toggleSection(sectionId) {
|
|
519
|
+
const content = document.getElementById(sectionId + '-content');
|
|
520
|
+
const btn = document.getElementById(sectionId + '-btn');
|
|
521
|
+
|
|
522
|
+
content.classList.toggle('active');
|
|
523
|
+
btn.classList.toggle('rotated');
|
|
524
|
+
}
|
|
525
|
+
</script>
|
|
526
|
+
</body>
|
|
527
|
+
</html>"""
|
|
528
|
+
|
|
529
|
+
return html_content
|
vates/_core/cli.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
def cli_run(model_cls, stoch_cls = None):
|
|
2
|
+
import argparse
|
|
3
|
+
import json
|
|
4
|
+
parser = argparse.ArgumentParser()
|
|
5
|
+
parser.add_argument("args_json_file", type=str, help='args json file for model instance')
|
|
6
|
+
args = parser.parse_args()
|
|
7
|
+
|
|
8
|
+
with open(args.args_json_file, 'r', encoding='utf-8') as file:
|
|
9
|
+
model_args = json.load(file)
|
|
10
|
+
|
|
11
|
+
if stoch_cls:
|
|
12
|
+
model_instance = stoch_cls(model_cls, **model_args)
|
|
13
|
+
else:
|
|
14
|
+
model_instance = model_cls(**model_args)
|
|
15
|
+
|
|
16
|
+
model_instance.run()
|
|
17
|
+
|
|
18
|
+
def cli_main(main_func):
|
|
19
|
+
import argparse
|
|
20
|
+
import json
|
|
21
|
+
parser = argparse.ArgumentParser()
|
|
22
|
+
parser.add_argument("args_json_file", type=str, help='args json file for model instance')
|
|
23
|
+
args = parser.parse_args()
|
|
24
|
+
|
|
25
|
+
with open(args.args_json_file, 'r', encoding='utf-8') as file:
|
|
26
|
+
model_args = json.load(file)
|
|
27
|
+
|
|
28
|
+
main_func(**model_args)
|