enabled multicore simulation for multiple sims
This commit is contained in:
@@ -10,9 +10,13 @@ from utils import euler2dcm, fmag2, initialize_magnetic_characteristics, reset_m
|
|||||||
from simulate import simulate_maglev_control
|
from simulate import simulate_maglev_control
|
||||||
from visualize import visualize_quad
|
from visualize import visualize_quad
|
||||||
import os
|
import os
|
||||||
|
from concurrent.futures import ProcessPoolExecutor
|
||||||
|
import multiprocessing
|
||||||
|
|
||||||
# ===== SIMULATION CONFIGURATION =====
|
# ===== SIMULATION CONFIGURATION =====
|
||||||
NUM_TRIALS = 5 # Number of trials to run
|
NUM_TRIALS = 5 # Number of trials to run
|
||||||
|
NUM_CORES_LIMIT = 8 # Max number of CPU cores to use for simulations
|
||||||
|
# (min of this and num of cores on ur computer will be chosen.)
|
||||||
NOISE_LEVEL = 0.1 # Standard deviation of noise (5%)
|
NOISE_LEVEL = 0.1 # Standard deviation of noise (5%)
|
||||||
# =====================================
|
# =====================================
|
||||||
|
|
||||||
@@ -86,7 +90,7 @@ def generate_parameter_report(trial_num, quad_params, output_dir):
|
|||||||
|
|
||||||
|
|
||||||
def run_single_trial(trial_num, Tsim, delt, ref_gap, z0, output_dir):
|
def run_single_trial(trial_num, Tsim, delt, ref_gap, z0, output_dir):
|
||||||
"""Run a single simulation trial with randomized parameters"""
|
"""Run a single simulation trial with randomized parameters, including all visualizations"""
|
||||||
|
|
||||||
# Reset and reinitialize noise for this trial
|
# Reset and reinitialize noise for this trial
|
||||||
reset_parameter_variations()
|
reset_parameter_variations()
|
||||||
@@ -113,7 +117,7 @@ def run_single_trial(trial_num, Tsim, delt, ref_gap, z0, output_dir):
|
|||||||
oversampFact = 10
|
oversampFact = 10
|
||||||
|
|
||||||
# Check nominal gap
|
# Check nominal gap
|
||||||
print(f"Force check: {4*fmag2(0, 10.830e-3) - m*g}")
|
print(f"Trial {trial_num}: Force check: {4*fmag2(0, 10.830e-3) - m*g}")
|
||||||
|
|
||||||
# SET REFERENCE HERE
|
# SET REFERENCE HERE
|
||||||
ref_gap = 10.830e-3 # from python code
|
ref_gap = 10.830e-3 # from python code
|
||||||
@@ -166,9 +170,9 @@ def run_single_trial(trial_num, Tsim, delt, ref_gap, z0, output_dir):
|
|||||||
generate_parameter_report(trial_num, quad_params, output_dir)
|
generate_parameter_report(trial_num, quad_params, output_dir)
|
||||||
|
|
||||||
# Run simulation
|
# Run simulation
|
||||||
print(f" Running simulation for trial {trial_num}...")
|
print(f"Trial {trial_num}: Running simulation...")
|
||||||
P0 = simulate_maglev_control(R, S, P)
|
P0 = simulate_maglev_control(R, S, P)
|
||||||
print(f" Trial {trial_num} simulation complete!")
|
print(f"Trial {trial_num}: Simulation complete!")
|
||||||
|
|
||||||
# Extract results
|
# Extract results
|
||||||
tVec_out = P0['tVec']
|
tVec_out = P0['tVec']
|
||||||
@@ -179,7 +183,7 @@ def run_single_trial(trial_num, Tsim, delt, ref_gap, z0, output_dir):
|
|||||||
currents = state['currents']
|
currents = state['currents']
|
||||||
|
|
||||||
# Generate 3D visualization (GIF) without displaying
|
# Generate 3D visualization (GIF) without displaying
|
||||||
print(f" Generating 3D visualization for trial {trial_num}...")
|
print(f"Trial {trial_num}: Generating 3D visualization...")
|
||||||
S2 = {
|
S2 = {
|
||||||
'tVec': tVec_out,
|
'tVec': tVec_out,
|
||||||
'rMat': rMat,
|
'rMat': rMat,
|
||||||
@@ -195,55 +199,12 @@ def run_single_trial(trial_num, Tsim, delt, ref_gap, z0, output_dir):
|
|||||||
# Calculate forces
|
# Calculate forces
|
||||||
Fm = fmag2(currents[:, 0], gaps[:, 0])
|
Fm = fmag2(currents[:, 0], gaps[:, 0])
|
||||||
|
|
||||||
return {
|
# Generate plots immediately after simulation
|
||||||
'tVec': tVec_out,
|
print(f"Trial {trial_num}: Generating plots...")
|
||||||
'gaps': gaps,
|
|
||||||
'currents': currents,
|
|
||||||
'Fm': Fm,
|
|
||||||
'quad_params': quad_params
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""Main simulation script - runs multiple trials"""
|
|
||||||
|
|
||||||
# Create output directory if it doesn't exist
|
|
||||||
output_dir = 'sim_results_multi'
|
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
|
||||||
|
|
||||||
# Total simulation time, in seconds
|
|
||||||
Tsim = 2
|
|
||||||
|
|
||||||
# Update interval, in seconds
|
|
||||||
delt = 0.005 # sampling interval
|
|
||||||
|
|
||||||
# Reference gap and initial condition
|
|
||||||
ref_gap = 10.830e-3
|
|
||||||
z0 = ref_gap - 2e-3
|
|
||||||
|
|
||||||
print(f"\n{'='*60}")
|
|
||||||
print(f"Running {NUM_TRIALS} trials with noise level {NOISE_LEVEL*100:.1f}%")
|
|
||||||
print(f"{'='*60}\n")
|
|
||||||
|
|
||||||
# Run all trials
|
|
||||||
trial_results = []
|
|
||||||
for trial in range(1, NUM_TRIALS + 1):
|
|
||||||
print(f"Trial {trial}/{NUM_TRIALS}")
|
|
||||||
result = run_single_trial(trial, Tsim, delt, ref_gap, z0, output_dir)
|
|
||||||
trial_results.append(result)
|
|
||||||
print()
|
|
||||||
|
|
||||||
# Create individual plots for each trial
|
|
||||||
print("Generating plots...")
|
|
||||||
for i, result in enumerate(trial_results, 1):
|
|
||||||
tVec_out = result['tVec']
|
|
||||||
gaps = result['gaps']
|
|
||||||
currents = result['currents']
|
|
||||||
Fm = result['Fm']
|
|
||||||
|
|
||||||
# Create plots for this trial
|
# Create plots for this trial
|
||||||
fig = plt.figure(figsize=(12, 8))
|
fig = plt.figure(figsize=(12, 8))
|
||||||
fig.suptitle(f'Trial {i} - Noise Level {NOISE_LEVEL*100:.1f}%', fontsize=14, fontweight='bold')
|
fig.suptitle(f'Trial {trial_num} - Noise Level {NOISE_LEVEL*100:.1f}%', fontsize=14, fontweight='bold')
|
||||||
|
|
||||||
# Plot 1: Gaps
|
# Plot 1: Gaps
|
||||||
ax1 = plt.subplot(3, 1, 1)
|
ax1 = plt.subplot(3, 1, 1)
|
||||||
@@ -275,12 +236,10 @@ def main():
|
|||||||
plt.grid(True)
|
plt.grid(True)
|
||||||
|
|
||||||
plt.tight_layout()
|
plt.tight_layout()
|
||||||
plt.savefig(f'{output_dir}/trial_{i:02d}_results.png', dpi=150)
|
plt.savefig(f'{output_dir}/trial_{trial_num:02d}_results.png', dpi=150)
|
||||||
print(f" Saved trial {i} plot")
|
|
||||||
plt.close()
|
plt.close()
|
||||||
|
|
||||||
# FFT for this trial
|
# FFT for this trial
|
||||||
oversampFact = 10
|
|
||||||
Fs = 1/delt * oversampFact
|
Fs = 1/delt * oversampFact
|
||||||
L = len(tVec_out)
|
L = len(tVec_out)
|
||||||
|
|
||||||
@@ -289,15 +248,62 @@ def main():
|
|||||||
|
|
||||||
fig2 = plt.figure(figsize=(10, 6))
|
fig2 = plt.figure(figsize=(10, 6))
|
||||||
plt.semilogx(frequencies, np.abs(Y), linewidth=2)
|
plt.semilogx(frequencies, np.abs(Y), linewidth=2)
|
||||||
plt.title(f"FFT Spectrum - Trial {i}")
|
plt.title(f"FFT Spectrum - Trial {trial_num}")
|
||||||
plt.xlabel("Frequency (Hz)")
|
plt.xlabel("Frequency (Hz)")
|
||||||
plt.ylabel("Magnitude")
|
plt.ylabel("Magnitude")
|
||||||
plt.ylim([0, np.max(np.abs(Y[1:])) * 1.05])
|
plt.ylim([0, np.max(np.abs(Y[1:])) * 1.05])
|
||||||
plt.grid(True)
|
plt.grid(True)
|
||||||
plt.savefig(f'{output_dir}/trial_{i:02d}_fft.png', dpi=150)
|
plt.savefig(f'{output_dir}/trial_{trial_num:02d}_fft.png', dpi=150)
|
||||||
print(f" Saved trial {i} FFT")
|
|
||||||
plt.close()
|
plt.close()
|
||||||
|
|
||||||
|
print(f"Trial {trial_num}: COMPLETE (all outputs generated)")
|
||||||
|
|
||||||
|
return {
|
||||||
|
'tVec': tVec_out,
|
||||||
|
'gaps': gaps,
|
||||||
|
'currents': currents,
|
||||||
|
'Fm': Fm,
|
||||||
|
'quad_params': quad_params
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main simulation script - runs multiple trials"""
|
||||||
|
|
||||||
|
# Create output directory if it doesn't exist
|
||||||
|
output_dir = 'sim_results_multi'
|
||||||
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# Total simulation time, in seconds
|
||||||
|
Tsim = 2
|
||||||
|
|
||||||
|
# Update interval, in seconds
|
||||||
|
delt = 0.005 # sampling interval
|
||||||
|
|
||||||
|
# Reference gap and initial condition
|
||||||
|
ref_gap = 10.830e-3
|
||||||
|
z0 = ref_gap - 2e-3
|
||||||
|
|
||||||
|
print(f"\n{'='*60}")
|
||||||
|
print(f"Running {NUM_TRIALS} trials with noise level {NOISE_LEVEL*100:.1f}%")
|
||||||
|
num_cores = min(multiprocessing.cpu_count(), NUM_CORES_LIMIT)
|
||||||
|
print(f"Using {num_cores} CPU cores for parallel processing")
|
||||||
|
print(f"{'='*60}\n")
|
||||||
|
|
||||||
|
# Run all trials in parallel (each trial does simulation + visualization + plots)
|
||||||
|
trial_results = []
|
||||||
|
with ProcessPoolExecutor(max_workers=num_cores) as executor:
|
||||||
|
# Submit all trials
|
||||||
|
futures = [
|
||||||
|
executor.submit(run_single_trial, trial, Tsim, delt, ref_gap, z0, output_dir)
|
||||||
|
for trial in range(1, NUM_TRIALS + 1)
|
||||||
|
]
|
||||||
|
|
||||||
|
# Collect results as they complete
|
||||||
|
for future in futures:
|
||||||
|
result = future.result()
|
||||||
|
trial_results.append(result)
|
||||||
|
|
||||||
# Create overlay comparison plots
|
# Create overlay comparison plots
|
||||||
print("\nGenerating comparison plots...")
|
print("\nGenerating comparison plots...")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user