Fix coverage: add /api/coverage route, remove stray gather code from loadCoverage
This commit is contained in:
206
frontend_src/components/DataDocumentation.tsx
Normal file
206
frontend_src/components/DataDocumentation.tsx
Normal file
@@ -0,0 +1,206 @@
|
||||
import React, { useState } from 'react';
|
||||
|
||||
interface Props {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export default function DataDocumentation({ onClose }: Props) {
|
||||
const [activeTab, setActiveTab] = useState<'overview' | 'channels' | 'pipeline' | 'conversion' | 'format'>('overview');
|
||||
|
||||
const tabs = [
|
||||
{ id: 'overview' as const, label: 'Vue d\'ensemble', icon: '📋' },
|
||||
{ id: 'channels' as const, label: 'Canaux', icon: '📊' },
|
||||
{ id: 'pipeline' as const, label: 'Pipeline', icon: '🔄' },
|
||||
{ id: 'conversion' as const, label: 'Conversion', icon: '⚙️' },
|
||||
{ id: 'format' as const, label: 'Format H5', icon: '📦' }
|
||||
];
|
||||
|
||||
return (
|
||||
<div style={{ position: 'fixed', top: 0, left: 0, right: 0, bottom: 0, background: 'rgba(0,0,0,0.5)', zIndex: 10000, display: 'flex', justifyContent: 'center', alignItems: 'center', padding: '20px' }}>
|
||||
<div style={{ background: 'white', borderRadius: '12px', maxWidth: '900px', width: '100%', maxHeight: '90vh', overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
|
||||
{/* Header */}
|
||||
<div style={{ padding: '20px', borderBottom: '2px solid #e2e8f0', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<h2 style={{ fontSize: '1.5rem', fontWeight: 'bold', color: '#1e293b', margin: 0 }}>
|
||||
Documentation Technique
|
||||
</h2>
|
||||
<button onClick={onClose} style={{ background: '#ef4444', color: 'white', border: 'none', padding: '8px 16px', borderRadius: '6px', cursor: 'pointer', fontWeight: 'bold' }}>
|
||||
Fermer
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Tabs */}
|
||||
<div style={{ display: 'flex', borderBottom: '2px solid #e2e8f0', overflowX: 'auto' }}>
|
||||
{tabs.map(tab => (
|
||||
<button
|
||||
key={tab.id}
|
||||
onClick={() => setActiveTab(tab.id)}
|
||||
style={{
|
||||
padding: '12px 20px',
|
||||
background: activeTab === tab.id ? '#3b82f6' : 'transparent',
|
||||
color: activeTab === tab.id ? 'white' : '#64748b',
|
||||
border: 'none',
|
||||
borderBottom: activeTab === tab.id ? '3px solid #2563eb' : '3px solid transparent',
|
||||
cursor: 'pointer',
|
||||
fontWeight: activeTab === tab.id ? 'bold' : 'normal',
|
||||
fontSize: '0.9rem',
|
||||
whiteSpace: 'nowrap'
|
||||
}}
|
||||
>
|
||||
{tab.icon} {tab.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div style={{ flex: 1, overflowY: 'auto', padding: '30px' }}>
|
||||
{activeTab === 'overview' && (
|
||||
<div>
|
||||
<h3 style={{ fontSize: '1.3rem', fontWeight: 'bold', color: '#1e293b', marginBottom: '15px' }}>Campagne SeaKESP - Sète 2020</h3>
|
||||
<p style={{ fontSize: '1rem', color: '#475569', marginBottom: '20px' }}>
|
||||
Campagne d'acquisition sismique Ocean Bottom Node (OBN) réalisée en août-septembre 2020.
|
||||
</p>
|
||||
|
||||
<h4 style={{ fontSize: '1.1rem', fontWeight: 'bold', color: '#334155', marginTop: '20px', marginBottom: '10px' }}>Données acquises</h4>
|
||||
<ul style={{ color: '#475569', lineHeight: '1.8' }}>
|
||||
<li><strong>345 fichiers RAW</strong> propriétaires (2.7 TB)</li>
|
||||
<li><strong>Durée totale :</strong> ~800 heures d'enregistrements continus</li>
|
||||
<li><strong>Plus long fichier :</strong> 60 heures (217k secondes)</li>
|
||||
<li><strong>Fréquence d'échantillonnage :</strong> 500 Hz</li>
|
||||
</ul>
|
||||
|
||||
<h4 style={{ fontSize: '1.1rem', fontWeight: 'bold', color: '#334155', marginTop: '20px', marginBottom: '10px' }}>État de conversion</h4>
|
||||
<p style={{ color: '#475569' }}>
|
||||
Conversion RAW → H5 en cours sur VM .81 (4 workers parallèles).
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeTab === 'channels' && (
|
||||
<div>
|
||||
<h3 style={{ fontSize: '1.3rem', fontWeight: 'bold', color: '#1e293b', marginBottom: '15px' }}>Canaux d'acquisition</h3>
|
||||
|
||||
<div style={{ marginBottom: '25px' }}>
|
||||
<h4 style={{ fontSize: '1.1rem', fontWeight: 'bold', color: '#0369a1', marginBottom: '10px' }}>Géophones (Canaux 1-3)</h4>
|
||||
<p style={{ color: '#475569', marginBottom: '10px' }}>Capteurs de vitesse particulaire 3 composantes (X, Y, Z)</p>
|
||||
<ul style={{ color: '#475569', lineHeight: '1.8' }}>
|
||||
<li><strong>Type :</strong> Géophones 15.6 V/(m/s)</li>
|
||||
<li><strong>Unité finale :</strong> m/s (mètres par seconde)</li>
|
||||
<li><strong>Sensibilité ADC :</strong> 3.576e-7 V/bit</li>
|
||||
<li><strong>Calibration :</strong> m/s = (ADC × 3.576e-7) / 15.6</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 style={{ fontSize: '1.1rem', fontWeight: 'bold', color: '#7c2d12', marginBottom: '10px' }}>Hydrophone (Canal 4)</h4>
|
||||
<p style={{ color: '#475569', marginBottom: '10px' }}>Capteur de pression acoustique</p>
|
||||
<ul style={{ color: '#475569', lineHeight: '1.8' }}>
|
||||
<li><strong>Type :</strong> Hydrophone 8.9 V/bar</li>
|
||||
<li><strong>Unité finale :</strong> Pa (Pascals)</li>
|
||||
<li><strong>Sensibilité ADC :</strong> 2.841e-6 V/bit</li>
|
||||
<li><strong>Calibration :</strong> Pa = (ADC × 2.841e-6 / 8.9) × 100000</li>
|
||||
<li><strong>Note :</strong> 1 bar = 100000 Pa</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeTab === 'pipeline' && (
|
||||
<div>
|
||||
<h3 style={{ fontSize: '1.3rem', fontWeight: 'bold', color: '#1e293b', marginBottom: '15px' }}>Pipeline de traitement</h3>
|
||||
|
||||
<div style={{ background: '#f8fafc', padding: '20px', borderRadius: '8px', marginBottom: '20px' }}>
|
||||
<h4 style={{ fontSize: '1rem', fontWeight: 'bold', color: '#475569', marginBottom: '15px' }}>Étapes de conversion</h4>
|
||||
<ol style={{ color: '#475569', lineHeight: '2', paddingLeft: '20px' }}>
|
||||
<li><strong>Fichier source :</strong> RAW propriétaire (format binaire non documenté)</li>
|
||||
<li><strong>Conversion initiale :</strong> RAW → SEGY via MantaSegy</li>
|
||||
<li><strong>Parsing SEGY :</strong> Extraction headers + données ADC brutes</li>
|
||||
<li><strong>Calibration :</strong> Application formules ADC → unités physiques</li>
|
||||
<li><strong>Export H5 :</strong> Sauvegarde données brutes + calibrées</li>
|
||||
<li><strong>Validation :</strong> Vérification précision (erreur < 10⁻¹¹)</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<h4 style={{ fontSize: '1.1rem', fontWeight: 'bold', color: '#334155', marginTop: '20px', marginBottom: '10px' }}>Objectif du traitement</h4>
|
||||
<p style={{ color: '#475569' }}>Convertir les fichiers RAW propriétaires en format HDF5 standardisé avec :</p>
|
||||
<ul style={{ color: '#475569', lineHeight: '1.8' }}>
|
||||
<li>Données ADC brutes (int32) pour archivage</li>
|
||||
<li>Données calibrées en unités physiques (float32)</li>
|
||||
<li>Métadonnées complètes (sample rate, durée, calibration)</li>
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeTab === 'conversion' && (
|
||||
<div>
|
||||
<h3 style={{ fontSize: '1.3rem', fontWeight: 'bold', color: '#1e293b', marginBottom: '15px' }}>Détails de conversion</h3>
|
||||
|
||||
<h4 style={{ fontSize: '1.1rem', fontWeight: 'bold', color: '#334155', marginBottom: '10px' }}>Configuration actuelle</h4>
|
||||
<ul style={{ color: '#475569', lineHeight: '1.8' }}>
|
||||
<li><strong>Machine :</strong> VM .81 (osboxes@192.168.0.81)</li>
|
||||
<li><strong>Workers :</strong> 4 processus parallèles</li>
|
||||
<li><strong>Stockage source :</strong> NFS depuis Pi 52 (/mnt/seismic-data)</li>
|
||||
<li><strong>Stockage destination :</strong> Local VM puis rsync vers Pi 27</li>
|
||||
</ul>
|
||||
|
||||
<h4 style={{ fontSize: '1.1rem', fontWeight: 'bold', color: '#334155', marginTop: '20px', marginBottom: '10px' }}>Formules de calibration</h4>
|
||||
<div style={{ background: '#f1f5f9', padding: '15px', borderRadius: '8px', fontFamily: 'monospace', fontSize: '0.9rem' }}>
|
||||
<p style={{ color: '#0369a1', marginBottom: '10px' }}><strong>Géophones (canaux 1-3) :</strong></p>
|
||||
<p style={{ color: '#475569' }}>m/s = (ADC_value × 3.576e-7 V/bit) / (15.6 V/(m/s))</p>
|
||||
|
||||
<p style={{ color: '#7c2d12', marginTop: '15px', marginBottom: '10px' }}><strong>Hydrophone (canal 4) :</strong></p>
|
||||
<p style={{ color: '#475569' }}>Pa = (ADC_value × 2.841e-6 V/bit / 8.9 V/bar) × 100000 Pa/bar</p>
|
||||
</div>
|
||||
|
||||
<h4 style={{ fontSize: '1.1rem', fontWeight: 'bold', color: '#334155', marginTop: '20px', marginBottom: '10px' }}>Validation qualité</h4>
|
||||
<p style={{ color: '#475569' }}>
|
||||
Précision de conversion vérifiée : erreur < 10⁻¹¹ entre calcul Python et valeurs attendues.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activeTab === 'format' && (
|
||||
<div>
|
||||
<h3 style={{ fontSize: '1.3rem', fontWeight: 'bold', color: '#1e293b', marginBottom: '15px' }}>Structure fichier H5</h3>
|
||||
|
||||
<div style={{ background: '#0f172a', padding: '20px', borderRadius: '8px', color: '#e2e8f0', fontFamily: 'monospace', fontSize: '0.85rem', marginBottom: '20px' }}>
|
||||
<pre style={{ margin: 0 }}>{`/
|
||||
├── metadata (group)
|
||||
│ ├── @duration_sec: 20.0
|
||||
│ ├── @sample_rate_hz: 500
|
||||
│ ├── @n_channels: 4
|
||||
│ └── @n_samples: 10000
|
||||
│
|
||||
├── calibration (group)
|
||||
│ ├── @geophone_v_per_bit: 3.576e-7
|
||||
│ ├── @geophone_v_per_ms: 15.6
|
||||
│ ├── @hydrophone_v_per_bit: 2.841e-6
|
||||
│ └── @hydrophone_v_per_bar: 8.9
|
||||
│
|
||||
├── raw_data (group)
|
||||
│ ├── channel_1 (dataset int32)
|
||||
│ ├── channel_2 (dataset int32)
|
||||
│ ├── channel_3 (dataset int32)
|
||||
│ └── channel_4 (dataset int32)
|
||||
│
|
||||
└── calibrated_data (group)
|
||||
├── channel_1 (dataset float32, unit: m/s)
|
||||
├── channel_2 (dataset float32, unit: m/s)
|
||||
├── channel_3 (dataset float32, unit: m/s)
|
||||
└── channel_4 (dataset float32, unit: Pa)`}</pre>
|
||||
</div>
|
||||
|
||||
<h4 style={{ fontSize: '1.1rem', fontWeight: 'bold', color: '#334155', marginBottom: '10px' }}>Avantages du format H5</h4>
|
||||
<ul style={{ color: '#475569', lineHeight: '1.8' }}>
|
||||
<li><strong>Compression efficace :</strong> Réduction ~30% taille fichiers</li>
|
||||
<li><strong>Accès rapide :</strong> Lecture sélective par canal/plage temporelle</li>
|
||||
<li><strong>Métadonnées intégrées :</strong> Toutes les infos de calibration dans le fichier</li>
|
||||
<li><strong>Interopérabilité :</strong> Compatible Python, MATLAB, Julia, C++</li>
|
||||
<li><strong>Archivage :</strong> Données brutes + calibrées dans un seul fichier</li>
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user