microlens-submit 0.12.1__py3-none-any.whl → 0.16.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.
- microlens_submit/__init__.py +7 -157
- microlens_submit/cli/__init__.py +5 -0
- microlens_submit/cli/__main__.py +6 -0
- microlens_submit/cli/commands/__init__.py +1 -0
- microlens_submit/cli/commands/dossier.py +139 -0
- microlens_submit/cli/commands/export.py +177 -0
- microlens_submit/cli/commands/init.py +172 -0
- microlens_submit/cli/commands/solutions.py +722 -0
- microlens_submit/cli/commands/validation.py +241 -0
- microlens_submit/cli/main.py +120 -0
- microlens_submit/dossier/__init__.py +51 -0
- microlens_submit/dossier/dashboard.py +499 -0
- microlens_submit/dossier/event_page.py +369 -0
- microlens_submit/dossier/full_report.py +330 -0
- microlens_submit/dossier/solution_page.py +533 -0
- microlens_submit/dossier/utils.py +111 -0
- microlens_submit/error_messages.py +283 -0
- microlens_submit/models/__init__.py +28 -0
- microlens_submit/models/event.py +406 -0
- microlens_submit/models/solution.py +569 -0
- microlens_submit/models/submission.py +569 -0
- microlens_submit/tier_validation.py +208 -0
- microlens_submit/utils.py +373 -0
- microlens_submit/validate_parameters.py +478 -180
- {microlens_submit-0.12.1.dist-info → microlens_submit-0.16.0.dist-info}/METADATA +54 -37
- microlens_submit-0.16.0.dist-info/RECORD +32 -0
- {microlens_submit-0.12.1.dist-info → microlens_submit-0.16.0.dist-info}/WHEEL +1 -1
- microlens_submit/api.py +0 -1274
- microlens_submit/cli.py +0 -1803
- microlens_submit/dossier.py +0 -1443
- microlens_submit-0.12.1.dist-info/RECORD +0 -13
- {microlens_submit-0.12.1.dist-info/licenses → microlens_submit-0.16.0.dist-info}/LICENSE +0 -0
- {microlens_submit-0.12.1.dist-info → microlens_submit-0.16.0.dist-info}/entry_points.txt +0 -0
- {microlens_submit-0.12.1.dist-info → microlens_submit-0.16.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Dashboard generation module for microlens-submit.
|
|
3
|
+
|
|
4
|
+
This module provides functionality to generate the main dashboard HTML page
|
|
5
|
+
for submission review and documentation. The dashboard provides an overview
|
|
6
|
+
of the submission including event summaries, solution statistics, and metadata.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import shutil
|
|
10
|
+
import webbrowser
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
import importlib_resources
|
|
15
|
+
|
|
16
|
+
from ..models.submission import Submission
|
|
17
|
+
from .utils import extract_github_repo_name, format_hardware_info
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def generate_dashboard_html(submission: Submission, output_dir: Path, open: bool = False) -> None:
|
|
21
|
+
"""Generate a complete HTML dossier for the submission.
|
|
22
|
+
|
|
23
|
+
Creates a comprehensive HTML dashboard that provides an overview of the submission,
|
|
24
|
+
including event summaries, solution statistics, and metadata. The dossier includes:
|
|
25
|
+
- Main dashboard (index.html) with submission overview
|
|
26
|
+
- Individual event pages for each event
|
|
27
|
+
- Individual solution pages for each solution
|
|
28
|
+
- Full comprehensive dossier (full_dossier_report.html) for printing
|
|
29
|
+
|
|
30
|
+
The function creates the output directory structure and copies necessary assets
|
|
31
|
+
like logos and GitHub icons.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
submission: The submission object containing events and solutions.
|
|
35
|
+
output_dir: Directory where the HTML files will be saved. Will be created
|
|
36
|
+
if it doesn't exist.
|
|
37
|
+
open: If True, open the generated index.html in the default web browser after generation.
|
|
38
|
+
|
|
39
|
+
Raises:
|
|
40
|
+
OSError: If unable to create output directory or write files.
|
|
41
|
+
ValueError: If submission data is invalid or missing required fields.
|
|
42
|
+
|
|
43
|
+
Example:
|
|
44
|
+
>>> from microlens_submit import load
|
|
45
|
+
>>> from microlens_submit.dossier import generate_dashboard_html
|
|
46
|
+
>>> from pathlib import Path
|
|
47
|
+
>>>
|
|
48
|
+
>>> # Load a submission project
|
|
49
|
+
>>> submission = load("./my_project")
|
|
50
|
+
>>>
|
|
51
|
+
>>> # Generate the complete dossier and open in browser
|
|
52
|
+
>>> generate_dashboard_html(submission, Path("./dossier_output"), open=True)
|
|
53
|
+
>>>
|
|
54
|
+
>>> # Files created:
|
|
55
|
+
>>> # - ./dossier_output/index.html (main dashboard)
|
|
56
|
+
>>> # - ./dossier_output/EVENT001.html (event page)
|
|
57
|
+
>>> # - ./dossier_output/solution_id.html (solution pages)
|
|
58
|
+
>>> # - ./dossier_output/full_dossier_report.html (printable version)
|
|
59
|
+
>>> # - ./dossier_output/assets/ (logos and icons)
|
|
60
|
+
|
|
61
|
+
Note:
|
|
62
|
+
This function generates all dossier components. For partial generation
|
|
63
|
+
(e.g., only specific events), use the CLI command with --event-id or
|
|
64
|
+
--solution-id flags instead.
|
|
65
|
+
"""
|
|
66
|
+
# Create output directory structure
|
|
67
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
68
|
+
(output_dir / "assets").mkdir(exist_ok=True)
|
|
69
|
+
# (No events or solutions subfolders)
|
|
70
|
+
|
|
71
|
+
# Check if full dossier report exists
|
|
72
|
+
full_dossier_exists = (output_dir / "full_dossier_report.html").exists()
|
|
73
|
+
# Generate the main dashboard HTML
|
|
74
|
+
html_content = _generate_dashboard_content(submission, full_dossier_exists=full_dossier_exists)
|
|
75
|
+
|
|
76
|
+
# Write the HTML file
|
|
77
|
+
index_path = output_dir / "index.html"
|
|
78
|
+
with index_path.open("w", encoding="utf-8") as f:
|
|
79
|
+
f.write(html_content)
|
|
80
|
+
|
|
81
|
+
# Copy logos using importlib_resources for robust package data access
|
|
82
|
+
def _get_asset_path(package, filename):
|
|
83
|
+
try:
|
|
84
|
+
# Python 3.9+ or importlib_resources >= 3.1
|
|
85
|
+
return importlib_resources.files(package).joinpath(filename)
|
|
86
|
+
except AttributeError:
|
|
87
|
+
# Python 3.8 fallback
|
|
88
|
+
with importlib_resources.path(package, filename) as p:
|
|
89
|
+
return p
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
logo_path = _get_asset_path("microlens_submit.assets", "rges-pit_logo.png")
|
|
93
|
+
shutil.copy2(logo_path, output_dir / "assets" / "rges-pit_logo.png")
|
|
94
|
+
except (FileNotFoundError, ModuleNotFoundError, AttributeError):
|
|
95
|
+
pass
|
|
96
|
+
try:
|
|
97
|
+
github_logo_path = _get_asset_path("microlens_submit.assets", "github-desktop_logo.png")
|
|
98
|
+
shutil.copy2(github_logo_path, output_dir / "assets" / "github-desktop_logo.png")
|
|
99
|
+
except (FileNotFoundError, ModuleNotFoundError, AttributeError):
|
|
100
|
+
pass
|
|
101
|
+
|
|
102
|
+
# After generating index.html, generate event pages
|
|
103
|
+
# Import here to avoid circular imports
|
|
104
|
+
from .event_page import generate_event_page
|
|
105
|
+
|
|
106
|
+
for event in submission.events.values():
|
|
107
|
+
generate_event_page(event, submission, output_dir)
|
|
108
|
+
|
|
109
|
+
# Optionally open the dashboard in the browser
|
|
110
|
+
if open:
|
|
111
|
+
webbrowser.open(index_path.resolve().as_uri())
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _generate_dashboard_content(submission: Submission, full_dossier_exists: bool = False) -> str:
|
|
115
|
+
"""Generate the HTML content for the submission dashboard.
|
|
116
|
+
|
|
117
|
+
Creates the main dashboard HTML following the Dashboard_Design.md specification.
|
|
118
|
+
The dashboard includes submission statistics, progress tracking, event tables,
|
|
119
|
+
and aggregate parameter distributions.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
submission: The submission object containing events and solutions.
|
|
123
|
+
full_dossier_exists: Whether the full dossier report exists. Currently
|
|
124
|
+
ignored but kept for future use.
|
|
125
|
+
|
|
126
|
+
Returns:
|
|
127
|
+
str: Complete HTML content as a string, ready to be written to index.html.
|
|
128
|
+
|
|
129
|
+
Example:
|
|
130
|
+
>>> from microlens_submit import load
|
|
131
|
+
>>> from microlens_submit.dossier import _generate_dashboard_content
|
|
132
|
+
>>>
|
|
133
|
+
>>> submission = load("./my_project")
|
|
134
|
+
>>> html_content = _generate_dashboard_content(submission)
|
|
135
|
+
>>>
|
|
136
|
+
>>> # Write to file
|
|
137
|
+
>>> with open("dashboard.html", "w", encoding="utf-8") as f:
|
|
138
|
+
... f.write(html_content)
|
|
139
|
+
|
|
140
|
+
Note:
|
|
141
|
+
This is an internal function. Use generate_dashboard_html() for the
|
|
142
|
+
complete dossier generation workflow.
|
|
143
|
+
"""
|
|
144
|
+
# Calculate statistics
|
|
145
|
+
total_events = len(submission.events)
|
|
146
|
+
total_active_solutions = sum(len(event.get_active_solutions()) for event in submission.events.values())
|
|
147
|
+
total_cpu_hours = 0
|
|
148
|
+
total_wall_time_hours = 0
|
|
149
|
+
|
|
150
|
+
# Calculate compute time
|
|
151
|
+
for event in submission.events.values():
|
|
152
|
+
for solution in event.solutions.values():
|
|
153
|
+
if solution.compute_info:
|
|
154
|
+
total_cpu_hours += solution.compute_info.get("cpu_hours", 0)
|
|
155
|
+
total_wall_time_hours += solution.compute_info.get("wall_time_hours", 0)
|
|
156
|
+
|
|
157
|
+
# Format hardware info
|
|
158
|
+
hardware_info_str = format_hardware_info(submission.hardware_info)
|
|
159
|
+
|
|
160
|
+
# Calculate progress (hardcoded total from design spec)
|
|
161
|
+
TOTAL_CHALLENGE_EVENTS = 293
|
|
162
|
+
progress_percentage = (total_events / TOTAL_CHALLENGE_EVENTS) * 100 if TOTAL_CHALLENGE_EVENTS > 0 else 0
|
|
163
|
+
|
|
164
|
+
# Generate event table
|
|
165
|
+
event_rows = []
|
|
166
|
+
for event in sorted(submission.events.values(), key=lambda e: e.event_id):
|
|
167
|
+
active_solutions = event.get_active_solutions()
|
|
168
|
+
model_types = set(sol.model_type for sol in active_solutions)
|
|
169
|
+
model_types_str = ", ".join(sorted(model_types)) if model_types else "None"
|
|
170
|
+
|
|
171
|
+
event_rows.append(
|
|
172
|
+
f"""
|
|
173
|
+
<tr class="border-b border-gray-200 hover:bg-gray-50">
|
|
174
|
+
<td class="py-3 px-4">
|
|
175
|
+
<a href="{event.event_id}.html"
|
|
176
|
+
class="font-medium text-rtd-accent hover:underline">
|
|
177
|
+
{event.event_id}
|
|
178
|
+
</a>
|
|
179
|
+
</td>
|
|
180
|
+
<td class="py-3 px-4">{len(active_solutions)}</td>
|
|
181
|
+
<td class="py-3 px-4">{model_types_str}</td>
|
|
182
|
+
</tr>
|
|
183
|
+
"""
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
event_table = (
|
|
187
|
+
"\n".join(event_rows)
|
|
188
|
+
if event_rows
|
|
189
|
+
else """
|
|
190
|
+
<tr class="border-b border-gray-200">
|
|
191
|
+
<td colspan="3" class="py-3 px-4 text-center text-gray-500">
|
|
192
|
+
No events found
|
|
193
|
+
</td>
|
|
194
|
+
</tr>
|
|
195
|
+
"""
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
# Insert Print Full Dossier placeholder before the footer
|
|
199
|
+
print_link_html = "<!--FULL_DOSSIER_LINK_PLACEHOLDER-->"
|
|
200
|
+
|
|
201
|
+
# GitHub repo link (if present)
|
|
202
|
+
github_html = ""
|
|
203
|
+
repo_url = getattr(submission, "repo_url", None) or (
|
|
204
|
+
submission.repo_url if hasattr(submission, "repo_url") else None
|
|
205
|
+
)
|
|
206
|
+
if repo_url:
|
|
207
|
+
repo_name = extract_github_repo_name(repo_url)
|
|
208
|
+
github_html = f"""
|
|
209
|
+
<div class="flex items-center justify-center mb-4">
|
|
210
|
+
<a href="{repo_url}" target="_blank" rel="noopener"
|
|
211
|
+
class="flex items-center space-x-2 group">
|
|
212
|
+
<img src="assets/github-desktop_logo.png" alt="GitHub"
|
|
213
|
+
class="w-6 h-6 inline-block align-middle mr-2 group-hover:opacity-80"
|
|
214
|
+
style="display:inline;vertical-align:middle;">
|
|
215
|
+
<span class="text-base text-rtd-accent font-semibold group-hover:underline">
|
|
216
|
+
{repo_name}
|
|
217
|
+
</span>
|
|
218
|
+
</a>
|
|
219
|
+
</div>
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
# Generate the complete HTML following the design spec
|
|
223
|
+
html = f"""<!DOCTYPE html>
|
|
224
|
+
<html lang="en">
|
|
225
|
+
<head>
|
|
226
|
+
<meta charset="UTF-8">
|
|
227
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
228
|
+
<title>Microlensing Data Challenge Submission Dossier - \
|
|
229
|
+
{submission.team_name}</title>
|
|
230
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
231
|
+
<script>
|
|
232
|
+
tailwind.config = {{
|
|
233
|
+
theme: {{
|
|
234
|
+
extend: {{
|
|
235
|
+
colors: {{
|
|
236
|
+
'rtd-primary': '#dfc5fa',
|
|
237
|
+
'rtd-secondary': '#361d49',
|
|
238
|
+
'rtd-accent': '#a859e4',
|
|
239
|
+
'rtd-background': '#faf7fd',
|
|
240
|
+
'rtd-text': '#000',
|
|
241
|
+
}},
|
|
242
|
+
fontFamily: {{
|
|
243
|
+
inter: ['Inter', 'sans-serif'],
|
|
244
|
+
}},
|
|
245
|
+
}},
|
|
246
|
+
}},
|
|
247
|
+
}};
|
|
248
|
+
</script>
|
|
249
|
+
<link
|
|
250
|
+
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap"
|
|
251
|
+
rel="stylesheet"
|
|
252
|
+
>
|
|
253
|
+
<!-- Highlight.js for code syntax highlighting -->
|
|
254
|
+
<link
|
|
255
|
+
rel="stylesheet"
|
|
256
|
+
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css"
|
|
257
|
+
>
|
|
258
|
+
<script
|
|
259
|
+
src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"
|
|
260
|
+
>
|
|
261
|
+
</script>
|
|
262
|
+
<script>hljs.highlightAll();</script>
|
|
263
|
+
<style>
|
|
264
|
+
.prose {{
|
|
265
|
+
color: #000;
|
|
266
|
+
line-height: 1.6;
|
|
267
|
+
}}
|
|
268
|
+
.prose h1 {{
|
|
269
|
+
font-size: 1.5rem;
|
|
270
|
+
font-weight: 700;
|
|
271
|
+
color: #361d49;
|
|
272
|
+
margin-top: 1.5rem;
|
|
273
|
+
margin-bottom: 0.75rem;
|
|
274
|
+
}}
|
|
275
|
+
.prose h2 {{
|
|
276
|
+
font-size: 1.25rem;
|
|
277
|
+
font-weight: 600;
|
|
278
|
+
color: #361d49;
|
|
279
|
+
margin-top: 1.25rem;
|
|
280
|
+
margin-bottom: 0.5rem;
|
|
281
|
+
}}
|
|
282
|
+
.prose h3 {{
|
|
283
|
+
font-size: 1.125rem;
|
|
284
|
+
font-weight: 600;
|
|
285
|
+
color: #a859e4;
|
|
286
|
+
margin-top: 1rem;
|
|
287
|
+
margin-bottom: 0.5rem;
|
|
288
|
+
}}
|
|
289
|
+
.prose p {{
|
|
290
|
+
margin-bottom: 0.75rem;
|
|
291
|
+
}}
|
|
292
|
+
.prose ul, .prose ol {{
|
|
293
|
+
margin-left: 1.5rem;
|
|
294
|
+
margin-bottom: 0.75rem;
|
|
295
|
+
}}
|
|
296
|
+
.prose ul {{ list-style-type: disc; }}
|
|
297
|
+
.prose ol {{ list-style-type: decimal; }}
|
|
298
|
+
.prose li {{
|
|
299
|
+
margin-bottom: 0.25rem;
|
|
300
|
+
}}
|
|
301
|
+
.prose code {{
|
|
302
|
+
background: #f3f3f3;
|
|
303
|
+
padding: 2px 4px;
|
|
304
|
+
border-radius: 4px;
|
|
305
|
+
font-family: 'Courier New', monospace;
|
|
306
|
+
font-size: 0.875rem;
|
|
307
|
+
}}
|
|
308
|
+
.prose pre {{
|
|
309
|
+
background: #f8f8f8;
|
|
310
|
+
padding: 1rem;
|
|
311
|
+
border-radius: 8px;
|
|
312
|
+
overflow-x: auto;
|
|
313
|
+
margin: 1rem 0;
|
|
314
|
+
border: 1px solid #e5e5e5;
|
|
315
|
+
}}
|
|
316
|
+
.prose pre code {{
|
|
317
|
+
background: none;
|
|
318
|
+
padding: 0;
|
|
319
|
+
}}
|
|
320
|
+
.prose blockquote {{
|
|
321
|
+
border-left: 4px solid #a859e4;
|
|
322
|
+
padding-left: 1rem;
|
|
323
|
+
margin: 1rem 0;
|
|
324
|
+
font-style: italic;
|
|
325
|
+
color: #666;
|
|
326
|
+
}}
|
|
327
|
+
</style>
|
|
328
|
+
</head>
|
|
329
|
+
<body class="font-inter bg-rtd-background">
|
|
330
|
+
<div class="max-w-7xl mx-auto p-6 lg:p-8">
|
|
331
|
+
<div class="bg-white shadow-xl rounded-lg">
|
|
332
|
+
<!-- Header Section -->
|
|
333
|
+
<div class="text-center py-8">
|
|
334
|
+
<img src="./assets/rges-pit_logo.png" alt="RGES-PIT Logo" \
|
|
335
|
+
class="w-48 mx-auto mb-6">
|
|
336
|
+
<h1 class="text-4xl font-bold text-rtd-secondary text-center mb-2">
|
|
337
|
+
Microlensing Data Challenge Submission Dossier
|
|
338
|
+
</h1>
|
|
339
|
+
<p class="text-xl text-rtd-accent text-center mb-8">
|
|
340
|
+
Team: {submission.team_name or 'Not specified'} |
|
|
341
|
+
Tier: {submission.tier or 'Not specified'}
|
|
342
|
+
</p>
|
|
343
|
+
{github_html}
|
|
344
|
+
</div>
|
|
345
|
+
|
|
346
|
+
<hr class="border-t-4 border-rtd-accent my-8 mx-8">
|
|
347
|
+
|
|
348
|
+
<!-- Regex Start -->
|
|
349
|
+
|
|
350
|
+
<!-- Submission Summary Section -->
|
|
351
|
+
<section class="mb-10 px-8">
|
|
352
|
+
<h2 class="text-2xl font-semibold text-rtd-secondary mb-4">
|
|
353
|
+
Submission Overview
|
|
354
|
+
</h2>
|
|
355
|
+
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
356
|
+
<div class="bg-rtd-primary p-6 rounded-lg shadow-md text-center">
|
|
357
|
+
<p class="text-sm font-medium text-rtd-secondary">
|
|
358
|
+
Total Events Submitted
|
|
359
|
+
</p>
|
|
360
|
+
<p class="text-4xl font-bold text-rtd-accent mt-2">
|
|
361
|
+
{total_events}
|
|
362
|
+
</p>
|
|
363
|
+
</div>
|
|
364
|
+
<div class="bg-rtd-primary p-6 rounded-lg shadow-md text-center">
|
|
365
|
+
<p class="text-sm font-medium text-rtd-secondary">
|
|
366
|
+
Total Active Solutions
|
|
367
|
+
</p>
|
|
368
|
+
<p class="text-4xl font-bold text-rtd-accent mt-2">
|
|
369
|
+
{total_active_solutions}
|
|
370
|
+
</p>
|
|
371
|
+
</div>
|
|
372
|
+
<div class="bg-rtd-primary p-6 rounded-lg shadow-md text-center">
|
|
373
|
+
<p class="text-sm font-medium text-rtd-secondary">
|
|
374
|
+
Hardware Information
|
|
375
|
+
</p>
|
|
376
|
+
<p class="text-lg text-rtd-text mt-2">
|
|
377
|
+
{hardware_info_str}
|
|
378
|
+
</p>
|
|
379
|
+
</div>
|
|
380
|
+
</div>
|
|
381
|
+
</section>
|
|
382
|
+
|
|
383
|
+
<!-- Overall Progress & Compute Time -->
|
|
384
|
+
<section class="mb-10 px-8">
|
|
385
|
+
<h2 class="text-2xl font-semibold text-rtd-secondary mb-4">
|
|
386
|
+
Challenge Progress & Compute Summary
|
|
387
|
+
</h2>
|
|
388
|
+
|
|
389
|
+
<!-- Progress Bar -->
|
|
390
|
+
<div class="w-full bg-gray-200 rounded-full h-4 mb-4">
|
|
391
|
+
<div class="bg-rtd-accent h-4 rounded-full" \
|
|
392
|
+
style="width: {progress_percentage}%"></div>
|
|
393
|
+
</div>
|
|
394
|
+
<p class="text-sm text-rtd-text text-center mb-6">
|
|
395
|
+
{total_events} / {TOTAL_CHALLENGE_EVENTS} Events Processed
|
|
396
|
+
({progress_percentage:.1f}%)
|
|
397
|
+
</p>
|
|
398
|
+
|
|
399
|
+
<!-- Compute Time Summary -->
|
|
400
|
+
<div class="text-lg text-rtd-text mb-2">
|
|
401
|
+
<p><strong>Total CPU Hours:</strong> {total_cpu_hours:.2f}</p>
|
|
402
|
+
<p><strong>Total Wall Time Hours:</strong> \
|
|
403
|
+
{total_wall_time_hours:.2f}</p>
|
|
404
|
+
</div>
|
|
405
|
+
<p class="text-sm text-gray-500 italic">
|
|
406
|
+
Note: Comparison to other teams' compute times is available in the
|
|
407
|
+
Evaluator Dossier.
|
|
408
|
+
</p>
|
|
409
|
+
</section>
|
|
410
|
+
|
|
411
|
+
<!-- Event List -->
|
|
412
|
+
<section class="mb-10 px-8">
|
|
413
|
+
<h2 class="text-2xl font-semibold text-rtd-secondary mb-4">
|
|
414
|
+
Submitted Events
|
|
415
|
+
</h2>
|
|
416
|
+
<table class="w-full text-left table-auto border-collapse">
|
|
417
|
+
<thead class="bg-rtd-primary text-rtd-secondary uppercase text-sm">
|
|
418
|
+
<tr>
|
|
419
|
+
<th class="py-3 px-4">Event ID</th>
|
|
420
|
+
<th class="py-3 px-4">Active Solutions</th>
|
|
421
|
+
<th class="py-3 px-4">Model Types Submitted</th>
|
|
422
|
+
</tr>
|
|
423
|
+
</thead>
|
|
424
|
+
<tbody class="text-rtd-text">
|
|
425
|
+
{event_table}
|
|
426
|
+
</tbody>
|
|
427
|
+
</table>
|
|
428
|
+
</section>
|
|
429
|
+
|
|
430
|
+
<!-- Aggregate Parameter Distributions (Placeholders) -->
|
|
431
|
+
<section class="mb-10 px-8">
|
|
432
|
+
<h2 class="text-2xl font-semibold text-rtd-secondary mb-4">
|
|
433
|
+
Aggregate Parameter Distributions
|
|
434
|
+
</h2>
|
|
435
|
+
<p class="text-sm text-gray-500 italic mb-4">
|
|
436
|
+
Note: These plots show distributions from <em>your</em> submitted
|
|
437
|
+
solutions. Comparisons to simulation truths and other teams' results
|
|
438
|
+
are available in the Evaluator Dossier.
|
|
439
|
+
</p>
|
|
440
|
+
|
|
441
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
442
|
+
<div class="text-center">
|
|
443
|
+
<img src="https://placehold.co/600x300/dfc5fa/361d49?text=tE+Distribution"
|
|
444
|
+
alt="tE Distribution"
|
|
445
|
+
class="w-full rounded-lg shadow-md"
|
|
446
|
+
>
|
|
447
|
+
<p class="text-sm text-gray-600 mt-2">
|
|
448
|
+
Histogram of Einstein Crossing Times (tE) from your
|
|
449
|
+
active solutions.
|
|
450
|
+
</p>
|
|
451
|
+
</div>
|
|
452
|
+
<div class="text-center">
|
|
453
|
+
<img src="https://placehold.co/600x300/dfc5fa/361d49?text=u0+Distribution"
|
|
454
|
+
alt="u0 Distribution"
|
|
455
|
+
class="w-full rounded-lg shadow-md"
|
|
456
|
+
>
|
|
457
|
+
<p class="text-sm text-gray-600 mt-2">
|
|
458
|
+
Histogram of Impact Parameters (u0) from your active
|
|
459
|
+
solutions.
|
|
460
|
+
</p>
|
|
461
|
+
</div>
|
|
462
|
+
<div class="text-center">
|
|
463
|
+
<img src="https://placehold.co/600x300/dfc5fa/361d49?text=Lens+Mass+Distribution"
|
|
464
|
+
alt="M_L Distribution"
|
|
465
|
+
class="w-full rounded-lg shadow-md"
|
|
466
|
+
>
|
|
467
|
+
<p class="text-sm text-gray-600 mt-2">
|
|
468
|
+
Histogram of derived Lens Masses (M_L) from your
|
|
469
|
+
active solutions.
|
|
470
|
+
</p>
|
|
471
|
+
</div>
|
|
472
|
+
<div class="text-center">
|
|
473
|
+
<img src="https://placehold.co/600x300/dfc5fa/361d49?text=Lens+Distance+Distribution"
|
|
474
|
+
alt="D_L Distribution"
|
|
475
|
+
class="w-full rounded-lg shadow-md"
|
|
476
|
+
>
|
|
477
|
+
<p class="text-sm text-gray-600 mt-2">
|
|
478
|
+
Histogram of derived Lens Distances (D_L) from your
|
|
479
|
+
active solutions.
|
|
480
|
+
</p>
|
|
481
|
+
</div>
|
|
482
|
+
</div>
|
|
483
|
+
</section>
|
|
484
|
+
{print_link_html}
|
|
485
|
+
|
|
486
|
+
<!-- Footer -->
|
|
487
|
+
<div class="text-sm text-gray-500 text-center pt-8 pb-6">
|
|
488
|
+
Generated by microlens-submit v0.16.0 on
|
|
489
|
+
{datetime.now().strftime('%Y-%m-%d %H:%M:%S UTC')}
|
|
490
|
+
</div>
|
|
491
|
+
|
|
492
|
+
<!-- Regex Finish -->
|
|
493
|
+
|
|
494
|
+
</div>
|
|
495
|
+
</div>
|
|
496
|
+
</body>
|
|
497
|
+
</html>"""
|
|
498
|
+
|
|
499
|
+
return html
|