download
raw
20.7 kB
import { useState } from 'react';
import { poissonApi } from '../../api';
const DEFAULT_PARAMS = {
name: 'Simulation Poisson',
domain_x_min: 0,
domain_x_max: 2,
domain_y_min: 0,
domain_y_max: 1,
mesh_nx: 64,
mesh_ny: 32,
source_type: 'gaussian',
source_amplitude: 10,
source_center_x: 0.5,
source_center_y: 0.5,
source_width: 0.02,
source_frequency: 1,
dirichlet_enabled: true,
dirichlet_boundaries: 'left,right',
dirichlet_value: 0,
neumann_enabled: true,
neumann_boundaries: 'top,bottom',
neumann_type: 'sinusoidal',
neumann_amplitude: 1,
neumann_frequency: 5,
};
export default function PoissonForm({ onPreviewMesh, onSimulationCreated, loading, setLoading }) {
const [params, setParams] = useState(DEFAULT_PARAMS);
const [activeSection, setActiveSection] = useState('domain');
const handleChange = (field, value) => {
setParams(prev => ({ ...prev, [field]: value }));
};
const handlePreview = async () => {
setLoading(true);
try {
await onPreviewMesh(params);
} catch (err) {
console.error('Erreur preview:', err);
}
setLoading(false);
};
const handleSubmit = async (e) => {
e.preventDefault();
setLoading(true);
try {
const simulation = await poissonApi.createSimulation(params);
onSimulationCreated(simulation);
} catch (err) {
console.error('Erreur création:', err);
alert('Erreur: ' + err.message);
}
setLoading(false);
};
const toggleBoundary = (field, boundary) => {
const current = params[field].split(',').filter(b => b);
const index = current.indexOf(boundary);
if (index >= 0) {
current.splice(index, 1);
} else {
current.push(boundary);
}
handleChange(field, current.join(','));
};
const isBoundarySelected = (field, boundary) => {
return params[field].split(',').includes(boundary);
};
return (
<form className="poisson-form" onSubmit={handleSubmit}>
<h3>Paramètres de simulation</h3>
{/* Section Domaine */}
<div className={`form-section ${activeSection === 'domain' ? 'expanded' : ''}`}>
<button
type="button"
className="section-header"
onClick={() => setActiveSection(activeSection === 'domain' ? '' : 'domain')}
>
<span>Domaine & Maillage</span>
<span className="toggle">{activeSection === 'domain' ? '−' : '+'}</span>
</button>
{activeSection === 'domain' && (
<div className="section-content">
<div className="form-group">
<label>Nom de la simulation</label>
<input
type="text"
value={params.name}
onChange={(e) => handleChange('name', e.target.value)}
/>
</div>
<div className="form-row">
<div className="form-group">
<label>X min</label>
<input
type="number"
step="0.1"
value={params.domain_x_min}
onChange={(e) => handleChange('domain_x_min', parseFloat(e.target.value))}
/>
</div>
<div className="form-group">
<label>X max</label>
<input
type="number"
step="0.1"
value={params.domain_x_max}
onChange={(e) => handleChange('domain_x_max', parseFloat(e.target.value))}
/>
</div>
</div>
<div className="form-row">
<div className="form-group">
<label>Y min</label>
<input
type="number"
step="0.1"
value={params.domain_y_min}
onChange={(e) => handleChange('domain_y_min', parseFloat(e.target.value))}
/>
</div>
<div className="form-group">
<label>Y max</label>
<input
type="number"
step="0.1"
value={params.domain_y_max}
onChange={(e) => handleChange('domain_y_max', parseFloat(e.target.value))}
/>
</div>
</div>
<div className="form-row">
<div className="form-group">
<label>Éléments X: {params.mesh_nx}</label>
<input
type="range"
min="8"
max="128"
step="8"
value={params.mesh_nx}
onChange={(e) => handleChange('mesh_nx', parseInt(e.target.value))}
/>
</div>
<div className="form-group">
<label>Éléments Y: {params.mesh_ny}</label>
<input
type="range"
min="8"
max="128"
step="8"
value={params.mesh_ny}
onChange={(e) => handleChange('mesh_ny', parseInt(e.target.value))}
/>
</div>
</div>
</div>
)}
</div>
{/* Section Source */}
<div className={`form-section ${activeSection === 'source' ? 'expanded' : ''}`}>
<button
type="button"
className="section-header"
onClick={() => setActiveSection(activeSection === 'source' ? '' : 'source')}
>
<span>Terme Source (f)</span>
<span className="toggle">{activeSection === 'source' ? '−' : '+'}</span>
</button>
{activeSection === 'source' && (
<div className="section-content">
<div className="form-group">
<label>Type de source</label>
<select
value={params.source_type}
onChange={(e) => handleChange('source_type', e.target.value)}
>
<option value="gaussian">Gaussienne</option>
<option value="constant">Constante</option>
<option value="sinusoidal">Sinusoïdale</option>
</select>
</div>
<div className="form-group">
<label>Amplitude: {params.source_amplitude}</label>
<input
type="range"
min="-50"
max="50"
step="1"
value={params.source_amplitude}
onChange={(e) => handleChange('source_amplitude', parseFloat(e.target.value))}
/>
</div>
{params.source_type === 'gaussian' && (
<>
<div className="form-row">
<div className="form-group">
<label>Centre X: {params.source_center_x}</label>
<input
type="range"
min="0"
max="2"
step="0.1"
value={params.source_center_x}
onChange={(e) => handleChange('source_center_x', parseFloat(e.target.value))}
/>
</div>
<div className="form-group">
<label>Centre Y: {params.source_center_y}</label>
<input
type="range"
min="0"
max="1"
step="0.1"
value={params.source_center_y}
onChange={(e) => handleChange('source_center_y', parseFloat(e.target.value))}
/>
</div>
</div>
<div className="form-group">
<label>Largeur (σ²): {params.source_width}</label>
<input
type="range"
min="0.01"
max="0.5"
step="0.01"
value={params.source_width}
onChange={(e) => handleChange('source_width', parseFloat(e.target.value))}
/>
</div>
</>
)}
{params.source_type === 'sinusoidal' && (
<div className="form-group">
<label>Fréquence: {params.source_frequency}</label>
<input
type="range"
min="0.5"
max="5"
step="0.5"
value={params.source_frequency}
onChange={(e) => handleChange('source_frequency', parseFloat(e.target.value))}
/>
</div>
)}
</div>
)}
</div>
{/* Section Dirichlet */}
<div className={`form-section ${activeSection === 'dirichlet' ? 'expanded' : ''}`}>
<button
type="button"
className="section-header"
onClick={() => setActiveSection(activeSection === 'dirichlet' ? '' : 'dirichlet')}
>
<span>Condition Dirichlet</span>
<span className="toggle">{activeSection === 'dirichlet' ? '−' : '+'}</span>
</button>
{activeSection === 'dirichlet' && (
<div className="section-content">
<div className="form-group checkbox">
<label>
<input
type="checkbox"
checked={params.dirichlet_enabled}
onChange={(e) => handleChange('dirichlet_enabled', e.target.checked)}
/>
Activer Dirichlet (u = valeur)
</label>
</div>
{params.dirichlet_enabled && (
<>
<div className="form-group">
<label>Frontières</label>
<div className="boundary-selector">
{['left', 'right', 'top', 'bottom'].map(b => (
<button
key={b}
type="button"
className={`boundary-btn ${isBoundarySelected('dirichlet_boundaries', b) ? 'selected' : ''}`}
onClick={() => toggleBoundary('dirichlet_boundaries', b)}
>
{b === 'left' ? 'Gauche' :
b === 'right' ? 'Droite' :
b === 'top' ? 'Haut' : 'Bas'}
</button>
))}
</div>
</div>
<div className="form-group">
<label>Valeur: {params.dirichlet_value}</label>
<input
type="range"
min="-10"
max="10"
step="0.5"
value={params.dirichlet_value}
onChange={(e) => handleChange('dirichlet_value', parseFloat(e.target.value))}
/>
</div>
</>
)}
</div>
)}
</div>
{/* Section Neumann */}
<div className={`form-section ${activeSection === 'neumann' ? 'expanded' : ''}`}>
<button
type="button"
className="section-header"
onClick={() => setActiveSection(activeSection === 'neumann' ? '' : 'neumann')}
>
<span>Condition Neumann</span>
<span className="toggle">{activeSection === 'neumann' ? '−' : '+'}</span>
</button>
{activeSection === 'neumann' && (
<div className="section-content">
<div className="form-group checkbox">
<label>
<input
type="checkbox"
checked={params.neumann_enabled}
onChange={(e) => handleChange('neumann_enabled', e.target.checked)}
/>
Activer Neumann (∂u/∂n = g)
</label>
</div>
{params.neumann_enabled && (
<>
<div className="form-group">
<label>Frontières</label>
<div className="boundary-selector">
{['left', 'right', 'top', 'bottom'].map(b => (
<button
key={b}
type="button"
className={`boundary-btn ${isBoundarySelected('neumann_boundaries', b) ? 'selected' : ''}`}
onClick={() => toggleBoundary('neumann_boundaries', b)}
>
{b === 'left' ? 'Gauche' :
b === 'right' ? 'Droite' :
b === 'top' ? 'Haut' : 'Bas'}
</button>
))}
</div>
</div>
<div className="form-group">
<label>Type de flux</label>
<select
value={params.neumann_type}
onChange={(e) => handleChange('neumann_type', e.target.value)}
>
<option value="constant">Constant</option>
<option value="sinusoidal">Sinusoïdal</option>
<option value="linear">Linéaire</option>
</select>
</div>
<div className="form-group">
<label>Amplitude: {params.neumann_amplitude}</label>
<input
type="range"
min="-10"
max="10"
step="0.5"
value={params.neumann_amplitude}
onChange={(e) => handleChange('neumann_amplitude', parseFloat(e.target.value))}
/>
</div>
{params.neumann_type === 'sinusoidal' && (
<div className="form-group">
<label>Fréquence: {params.neumann_frequency}</label>
<input
type="range"
min="1"
max="20"
step="1"
value={params.neumann_frequency}
onChange={(e) => handleChange('neumann_frequency', parseFloat(e.target.value))}
/>
</div>
)}
</>
)}
</div>
)}
</div>
{/* Boutons d'action */}
<div className="form-actions">
<button
type="button"
className="btn-preview"
onClick={handlePreview}
disabled={loading}
>
Aperçu du maillage
</button>
<button
type="submit"
className="btn-submit"
disabled={loading}
>
{loading ? 'Calcul...' : 'Lancer la simulation'}
</button>
</div>
</form>
);
}

Xet Storage Details

Size:
20.7 kB
·
Xet hash:
65ae624d707a98e95ad90e11b03092bd823f846382b47e873df3a22e33858c13

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.