diff --git a/app/models/economic_model.py b/app/models/economic_model.py index 0a2686e..e536e7a 100644 --- a/app/models/economic_model.py +++ b/app/models/economic_model.py @@ -318,9 +318,6 @@ class EconomicSimulation: if not wealth_values: return [], [] - # Debug logging - print(f"DEBUG: Wealth values - count: {len(wealth_values)}, min: {min(wealth_values)}, max: {max(wealth_values)}") - # Calculate histogram bins min_wealth = min(wealth_values) max_wealth = max(wealth_values) @@ -328,7 +325,6 @@ class EconomicSimulation: if min_wealth == max_wealth: # All agents have same wealth result = [f"${min_wealth:.0f}"], [len(wealth_values)] - print(f"DEBUG: All agents have same wealth - labels: {result[0]}, counts: {result[1]}") return result # Create bins @@ -357,7 +353,6 @@ class EconomicSimulation: if bin_start <= wealth < bin_end: bin_counts[i] += 1 - print(f"DEBUG: Histogram result - labels: {bin_labels}, counts: {bin_counts}") return bin_labels, bin_counts def update_parameters(self, new_parameters: SimulationParameters): diff --git a/app/routes/api.py b/app/routes/api.py index 21f0e77..12d881b 100644 --- a/app/routes/api.py +++ b/app/routes/api.py @@ -139,19 +139,29 @@ def start_simulation(simulation_id: str): try: # Run simulation with progress updates total_iterations = simulation.parameters.iterations + last_update_time = time.time() + update_interval = max(0.1, min(1.0, 1000 / total_iterations)) # Dynamic update interval + for i in range(total_iterations): if not simulation.is_running: break snapshot = simulation.step() - # Emit progress update every 10 iterations or at milestones - if i % 10 == 0 or i == total_iterations - 1: - # Get distribution data for real-time chart updates - bin_labels, bin_counts = simulation.get_wealth_histogram(10) + # Emit progress update at dynamic intervals for better performance + current_time = time.time() + if (i % max(1, total_iterations // 100) == 0 or # Every 1% of iterations + i == total_iterations - 1 or # Last iteration + current_time - last_update_time >= update_interval): # Time-based update - # Debug logging - print(f"DEBUG: Sending distribution data - labels: {bin_labels}, counts: {bin_counts}") + # Get distribution data for real-time chart updates (but less frequently) + distribution_data = None + if i % max(1, total_iterations // 20) == 0 or i == total_iterations - 1: + bin_labels, bin_counts = simulation.get_wealth_histogram(8) # Reduced bins for performance + distribution_data = { + 'labels': bin_labels, + 'counts': bin_counts + } progress_data = { 'simulation_id': simulation_id, @@ -161,18 +171,19 @@ def start_simulation(simulation_id: str): 'total_wealth': snapshot.total_wealth, 'gini_coefficient': snapshot.gini_coefficient, 'capital_share': snapshot.capital_share, - 'wealth_concentration_top10': snapshot.wealth_concentration_top10, - 'distribution': { - 'labels': bin_labels, - 'counts': bin_counts - } + 'wealth_concentration_top10': snapshot.wealth_concentration_top10 } + # Only include distribution data when we have it + if distribution_data: + progress_data['distribution'] = distribution_data + socketio.emit('simulation_progress', progress_data, room=f'simulation_{simulation_id}') + last_update_time = current_time - # Small delay to allow real-time visualization - time.sleep(0.01) + # Adaptive delay based on performance + time.sleep(max(0.001, 0.01 * (total_iterations / 1000))) # Mark as completed simulation.is_running = False @@ -367,7 +378,7 @@ def get_wealth_distribution(simulation_id: str): bin_labels, bin_counts = simulation.get_wealth_histogram(num_bins) # Debug logging - print(f"DEBUG: Distribution endpoint - labels: {bin_labels}, counts: {bin_counts}, bins: {num_bins}") + # print(f"DEBUG: Distribution endpoint - labels: {bin_labels}, counts: {bin_counts}, bins: {num_bins}") response_data = { 'simulation_id': simulation_id, @@ -379,7 +390,7 @@ def get_wealth_distribution(simulation_id: str): } } - print(f"DEBUG: Distribution endpoint response: {response_data}") + # print(f"DEBUG: Distribution endpoint response: {response_data}") return jsonify(response_data) except Exception as e: diff --git a/app/routes/main.py b/app/routes/main.py index e96d445..e361895 100644 --- a/app/routes/main.py +++ b/app/routes/main.py @@ -191,10 +191,14 @@ def test_simulation(): def debug_info(): """ Debug endpoint to verify deployment and test functionality. - - Returns: - JSON response with debug information + Only available in development mode. """ + from flask import current_app + + # Only allow debug endpoint in development mode + if not current_app.config.get('DEVELOPMENT', False): + return jsonify({'error': 'Debug endpoint not available in production'}), 403 + import os from datetime import datetime from app.models.economic_model import EconomicSimulation, SimulationParameters diff --git a/app/static/js/app.js b/app/static/js/app.js index 6977dd5..87c91e0 100644 --- a/app/static/js/app.js +++ b/app/static/js/app.js @@ -26,13 +26,13 @@ function initializeSocket() { window.MarkovEconomics.socket = io(); window.MarkovEconomics.socket.on('connect', function() { - console.log('Connected to server'); + // console.log('Connected to server'); window.MarkovEconomics.isConnected = true; updateConnectionStatus(true); }); window.MarkovEconomics.socket.on('disconnect', function() { - console.log('Disconnected from server'); + // console.log('Disconnected from server'); window.MarkovEconomics.isConnected = false; updateConnectionStatus(false); }); @@ -50,9 +50,9 @@ function initializeSocket() { function updateConnectionStatus(connected) { // You can add a connection status indicator here if needed if (connected) { - console.log('✅ Real-time connection established'); + // console.log('✅ Real-time connection established'); } else { - console.log('❌ Real-time connection lost'); + // console.log('❌ Real-time connection lost'); } } @@ -251,7 +251,7 @@ document.addEventListener('DOMContentLoaded', function() { card.classList.add('fade-in'); }); - console.log('🚀 Markov Economics application initialized'); + // console.log('🚀 Markov Economics application initialized'); }); /** @@ -259,9 +259,9 @@ document.addEventListener('DOMContentLoaded', function() { */ document.addEventListener('visibilitychange', function() { if (document.hidden) { - console.log('Page hidden - pausing updates'); + // console.log('Page hidden - pausing updates'); } else { - console.log('Page visible - resuming updates'); + // console.log('Page visible - resuming updates'); } }); diff --git a/app/static/js/simulation.js b/app/static/js/simulation.js index c3ce244..5088a3f 100644 --- a/app/static/js/simulation.js +++ b/app/static/js/simulation.js @@ -256,7 +256,7 @@ window.testDistributionChart = function() { }; // Debug flag - can be enabled even in production for troubleshooting -const DEBUG_DISTRIBUTION = true; +const DEBUG_DISTRIBUTION = false; /** * Debug logger that works in production @@ -1002,43 +1002,39 @@ function updateSimulationProgress(data) { progressText.textContent = percentage.toFixed(1) + '%'; } - // Update charts and metrics + // Update charts and metrics only if we have new data if (data.iteration !== undefined) { - currentSimulation.data.iterations.push(data.iteration); - currentSimulation.data.totalWealth.push(data.total_wealth || 0); - currentSimulation.data.giniCoefficients.push(data.gini_coefficient || 0); - currentSimulation.data.capitalShare.push(data.capital_share || 0); - currentSimulation.data.top10Share.push(data.wealth_concentration_top10 || 0); + // Only update time series data occasionally to improve performance + const shouldUpdateSeries = currentSimulation.data.iterations.length === 0 || + data.iteration % Math.max(1, Math.floor(currentSimulation.parameters.iterations / 200)) === 0 || + data.iteration === (currentSimulation.parameters.iterations - 1); + + if (shouldUpdateSeries) { + currentSimulation.data.iterations.push(data.iteration); + currentSimulation.data.totalWealth.push(data.total_wealth || 0); + currentSimulation.data.giniCoefficients.push(data.gini_coefficient || 0); + currentSimulation.data.capitalShare.push(data.capital_share || 0); + currentSimulation.data.top10Share.push(data.wealth_concentration_top10 || 0); + } // Update distribution data if available - debugLog('Received simulation progress data', { - hasDistribution: !!data.distribution, - distribution: data.distribution, - socketConnected: window.MarkovEconomics ? window.MarkovEconomics.isConnected : 'unknown' - }); - - // More robust handling of distribution data if (data.distribution && Array.isArray(data.distribution.labels) && Array.isArray(data.distribution.counts) && data.distribution.labels.length > 0 && data.distribution.counts.length > 0) { - debugLog('Updating distribution data', { - labelsLength: data.distribution.labels.length, - countsLength: data.distribution.counts.length, - labels: data.distribution.labels, - counts: data.distribution.counts - }); - // Store the distribution data properly currentSimulation.data.distribution.labels = [...data.distribution.labels]; currentSimulation.data.distribution.counts = [...data.distribution.counts]; - } else { - debugLog('No valid distribution data in progress update'); } - updateCharts(); + // Throttle chart updates to improve performance + if (!window.lastChartUpdate || (Date.now() - window.lastChartUpdate) > 50) { + updateCharts(); + window.lastChartUpdate = Date.now(); + } + updateMetricsDisplay(data); } }