Problem: 2D Tracer Transport Numerical Simulation

The problem aims to build a complete 2D tracer transport numerical simulation framework. It requires implementing core functional components including velocity field calculation, advection-diffusion term computation, boundary condition processing and time integration, all with numerical error protection, to support reliable simulation of tracer or pollutant transport in 2D fluid fields.


Input/Output: The problem receives as input 1D double vectors of x and y coordinate arrays, 2D double vector of initial tracer concentration grid Q, scalar double parameters including velocity field coefficients (F, b, p, q, A, B), diffusion coefficient k, time step dt, grid spacing dx and dy, boundary condition control parameters, Gaussian source parameters (x0, y0, amplitude, sigma), and total simulation step count passed as function arguments.
The problem outputs 2D double vectors of computed velocity components u and v, 2D double vector of updated tracer concentration after each simulation step, per-grid-cell advection and diffusion term values, boundary-processed concentration grids, per-grid-point Gaussian source intensity values, and boolean validation flags confirming no NaN or inf values in all computed results. Input parameters are processed sequentially via velocity field calculation, term computation, boundary application, and time stepping to generate corresponding outputs.

Required dependencies:

Sub-steps:
step_number: 1
step_description_prompt: Please write C++ code to implement a function named problem_2_01.
The function defines a lambda to compute 2D velocity field u and v grids from x, y coordinate arrays and input parameters, handles exponential computation overflow to avoid NaN/inf values, and exposes the lambda via a pre-declared global function pointer.
function_header: void problem_2_01() 
test_cases: int main() {
    void (*calculate_velocity_field_ptr)(std::vector<std::vector<double>>&, std::vector<std::vector<double>>&, const std::vector<double>&, const std::vector<double>&, double, double, double, double, double, double) = nullptr;
    
    calculate_velocity_field_pptr = &calculate_velocity_field_ptr;
    
    problem_2_01();

    std::cout << "========================================\n";
    std::cout << "Problem 2-Subproblem 1: Velocity Field Calculation\n";
    std::cout << "========================================\n";
    
    bool test1_passed = false, test2_passed = false, test3_passed = false;
    
    
    {
        std::vector<double> x = {0, 1000, 2000};
        std::vector<double> y = {0, 2500, 5000};
        std::vector<std::vector<double>> u(3, std::vector<double>(3));
        std::vector<std::vector<double>> v(3, std::vector<double>(3));
        
        calculate_velocity_field_ptr(u, v, x, y, 1.0, 5000, 0.05, 0.95, 2e-4, 1.3e-3);
        
        
        double x_val = 1000.0, y_val = 2500.0;
        double cos_term = cos(PI * y_val / 5000.0);
        double sin_term = sin(PI * y_val / 5000.0);
        double exp_Ax = exp(2e-4 * x_val);
        double exp_Bx = exp(-1.3e-3 * x_val);
        double expected_u = 1.0 * (PI / 5000.0) * cos_term * (0.05 * exp_Ax + 0.95 * exp_Bx - 1.0);
        double expected_v = -1.0 * sin_term * (0.05 * 2e-4 * exp_Ax - 0.95 * 1.3e-3 * exp_Bx);
        
        
        double u_at_origin = u[0][1];
        double expected_u_origin = 1.0 * (PI / 5000.0) * cos(PI * 2500.0 / 5000.0) * (0.05 + 0.95 - 1.0);
        
        test1_passed = (u.size() == 3 && v.size() == 3 && 
                       std::abs(u[1][1] - expected_u) < 1e-10 &&
                       std::abs(v[1][1] - expected_v) < 1e-10 &&
                       std::abs(u_at_origin - expected_u_origin) < 1e-12);
        if (test1_passed) {
            std::cout << "correct\n";
        } else {
            std::cout << "wrong\n";
        }
    }
    
    
    {
        std::vector<double> x = {0, 1000, 2000};
        std::vector<double> y = {0, 2500, 5000};
        std::vector<std::vector<double>> u(3, std::vector<double>(3));
        std::vector<std::vector<double>> v(3, std::vector<double>(3));
        
        calculate_velocity_field_ptr(u, v, x, y, 2.0, 5000, 0.1, 0.9, 3e-4, 2e-3);
        
        
        double x_val = 1000.0, y_val = 2500.0;
        double cos_term = cos(PI * y_val / 5000.0);
        double sin_term = sin(PI * y_val / 5000.0);
        double exp_Ax = exp(3e-4 * x_val);
        double exp_Bx = exp(-2e-3 * x_val);
        double expected_u = 2.0 * (PI / 5000.0) * cos_term * (0.1 * exp_Ax + 0.9 * exp_Bx - 1.0);
        double expected_v = -2.0 * sin_term * (0.1 * 3e-4 * exp_Ax - 0.9 * 2e-3 * exp_Bx);
        
        
        std::vector<std::vector<double>> u_ref(3, std::vector<double>(3));
        std::vector<std::vector<double>> v_ref(3, std::vector<double>(3));
        calculate_velocity_field_ptr(u_ref, v_ref, x, y, 1.0, 5000, 0.1, 0.9, 3e-4, 2e-3);
        bool scaling_ok = (std::abs(u[1][1] - 2.0 * u_ref[1][1]) < 1e-10);
        
        test2_passed = (u.size() == 3 && v.size() == 3 && 
                       std::abs(u[1][1] - expected_u) < 1e-10 &&
                       std::abs(v[1][1] - expected_v) < 1e-10 &&
                       scaling_ok);
        if (test2_passed) {
            std::cout << "correct\n";
        } else {
            std::cout << "wrong\n";
        }
    }
    
    
    {
        std::vector<double> x = {0, 1000, 2000, 5000, 10000};  
        std::vector<double> y = {0, 2500, 5000};
        std::vector<std::vector<double>> u(5, std::vector<double>(3));
        std::vector<std::vector<double>> v(5, std::vector<double>(3));
        
        calculate_velocity_field_ptr(u, v, x, y, 0.5, 5000, 0.02, 0.98, 1e-4, 0.5e-3);
        
        
        double x_val = 1000.0, y_val = 2500.0;
        double cos_term = cos(PI * y_val / 5000.0);
        double sin_term = sin(PI * y_val / 5000.0);
        double exp_Ax = exp(1e-4 * x_val);
        double exp_Bx = exp(-0.5e-3 * x_val);
        double expected_u = 0.5 * (PI / 5000.0) * cos_term * (0.02 * exp_Ax + 0.98 * exp_Bx - 1.0);
        double expected_v = -0.5 * sin_term * (0.02 * 1e-4 * exp_Ax - 0.98 * 0.5e-3 * exp_Bx);
        
        
        double u_at_y0 = u[1][0];
        double v_at_y0 = v[1][0];
        double expected_u_y0 = 0.5 * (PI / 5000.0) * 1.0 * (0.02 * exp(1e-4 * 1000.0) + 0.98 * exp(-0.5e-3 * 1000.0) - 1.0);
        double expected_v_y0 = 0.0;
        
        test3_passed = (u.size() == 5 && v.size() == 5 && 
                       std::abs(u[1][1] - expected_u) < 1e-10 &&
                       std::abs(v[1][1] - expected_v) < 1e-10 &&
                       std::abs(u_at_y0 - expected_u_y0) < 1e-10 &&
                       std::abs(v_at_y0) < 1e-12 &&
                       std::isfinite(u[4][1]) && std::isfinite(v[4][1]));
        if (test3_passed) {
            std::cout << "correct\n";
        } else {
            std::cout << "wrong\n";
        }
    }
    
    std::cout << "\n========================================\n";
    if (test1_passed && test2_passed && test3_passed) {
        std::cout << "Completely correct!\n";
    }
    std::cout << "========================================\n";
    
    return 0;
}

step_number: 2
step_description_prompt: Please write C++ code to implement the function named problem_2_02. This function will assign the pre-declared upwind_advection_ptr and diffusion_term_ptr function pointers to two custom lambdas. The first lambda calculates the 2D upwind advection term with proper boundary handling, the second calculates the 2D diffusion term, both return 0 when encountering invalid or NaN/inf results.
function_header: void problem_2_02() 
test_cases: int main() {
    // Initialize by calling problem_2_02 to set function pointers
    problem_2_02();

    std::cout << "========================================\n";
    std::cout << "Problem 2-Subproblem 2: Upwind Scheme and Diffusion Term Implementation\n";
    std::cout << "========================================\n";
    
    bool test1_passed = false, test2_passed = false, test3_passed = false;
    
    
    {
        std::vector<std::vector<double>> Q(5, std::vector<double>(5, 1.0));
        Q[2][2] = 2.0;
        double u1 = 1.0, v1 = 1.0;
        double u2 = 1e-10, v2 = 1e-10;  
        double dx = 1.0, dy = 1.0;
        
        double result1 = upwind_advection_ptr(2, 2, Q, u1, v1, dx, dy);
        double result2 = upwind_advection_ptr(2, 2, Q, u2, v2, dx, dy);
        double result_boundary = upwind_advection_ptr(0, 0, Q, u1, v1, dx, dy);
        
        double expected_result1 = -1.0 * (2.0 - 1.0) / 1.0 - 1.0 * (2.0 - 1.0) / 1.0;  // -2.0
        
        double expected_result2 = -1e-10 * (2.0 - 1.0) / 1.0 - 1e-10 * (2.0 - 1.0) / 1.0;  // -2e-10
        
        test1_passed = (std::abs(result1 - expected_result1) < 1e-12 &&
                       std::abs(result2 - expected_result2) < 1e-12 &&
                       std::abs(result_boundary) < 1e-12);
        if (test1_passed) {
            std::cout << "correct\n";
        } else {
            std::cout << "wrong\n";
        }
    }
    
    
    {
        std::vector<std::vector<double>> Q(5, std::vector<double>(5, 1.0));
        Q[2][2] = 2.0;
        double u = 1.0, v = -1.0;
        double dx1 = 1.0, dy1 = 1.0;
        double dx2 = 0.5, dy2 = 2.0;  
        
        double result1 = upwind_advection_ptr(2, 2, Q, u, v, dx1, dy1);
        double result2 = upwind_advection_ptr(2, 2, Q, u, v, dx2, dy2);
        
        double expected_result1 = -1.0 * (2.0 - 1.0) / 1.0 - (-1.0) * (1.0 - 2.0) / 1.0;  
        
        expected_result1 = -1.0 * (2.0 - 1.0) / 1.0 - (-1.0) * (1.0 - 2.0) / 1.0;  // -1.0 - (-1.0)*(-1.0) = -1.0 - 1.0 = -2.0
        
        
        double expected_result2 = -1.0 * (2.0 - 1.0) / 0.5 - (-1.0) * (1.0 - 2.0) / 2.0;  // -2.0 - 0.5 = -2.5
        
        test2_passed = (std::abs(result1 - expected_result1) < 1e-12 &&
                       std::abs(result2 - expected_result2) < 1e-12);
        if (test2_passed) {
            std::cout << "correct\n";
        } else {
            std::cout << "wrong\n";
        }
    }
    
    
    {
        std::vector<std::vector<double>> Q(7, std::vector<double>(7, 1.0));
        Q[3][3] = 5.0;  
        double k1 = 0.01;
        double k2 = 0.02;
        double dx1 = 1.0, dy1 = 1.0;
        double dx2 = 2.0, dy2 = 0.5;  
        
        double diff1_iso = diffusion_term_ptr(3, 3, Q, k1, dx1, dy1);
        double diff2_iso = diffusion_term_ptr(3, 3, Q, k2, dx1, dy1);
        double diff1_aniso = diffusion_term_ptr(3, 3, Q, k1, dx2, dy2);
        
        
        double laplacian_iso = (1.0 - 2.0*5.0 + 1.0) / (1.0*1.0) + (1.0 - 2.0*5.0 + 1.0) / (1.0*1.0);
        double expected_diff1_iso = k1 * laplacian_iso;
        double expected_diff2_iso = k2 * laplacian_iso;
        
        double laplacian_aniso = (1.0 - 2.0*5.0 + 1.0) / (2.0*2.0) + (1.0 - 2.0*5.0 + 1.0) / (0.5*0.5);
        double expected_diff1_aniso = k1 * laplacian_aniso;
        
        test3_passed = (std::abs(diff1_iso - expected_diff1_iso) < 1e-12 &&
                       std::abs(diff2_iso - expected_diff2_iso) < 1e-12 &&
                       std::abs(diff1_aniso - expected_diff1_aniso) < 1e-12 &&
                       std::abs(diff2_iso - 2.0*diff1_iso) < 1e-12);
        if (test3_passed) {
            std::cout << "correct\n";
        } else {
            std::cout << "wrong\n";
        }
    }
    
    std::cout << "\n========================================\n";
    if (test1_passed && test2_passed && test3_passed) {
        std::cout << "Completely correct!\n";
    }
    std::cout << "========================================\n";
    
    return 0;
}

step_number: 3
step_description_prompt: Please write C++ code to generate a function named problem_2_03.
This function initializes four pre-declared global function pointers: three for different boundary condition processing on 2D double vectors, one for Gaussian source value calculation. It defines matching type lambdas for each pointer, then assigns the lambdas to the corresponding global function pointers.
function_header: void problem_2_03() 
test_cases: int main() {
    // Initialize by calling problem_2_03 to set function pointers
    problem_2_03();

    std::cout << "========================================\n";
    std::cout << "Problem 2-Subproblem 3: Source Term Handling and Boundary Conditions\n";
    std::cout << "========================================\n";
    
    bool test1_passed = false, test2_passed = false, test3_passed = false;
    
    
    {
        
        {
            std::vector<std::vector<double>> Q1(5, std::vector<double>(5, 1.0));
            apply_boundary_conditions_ptr(Q1);
        }
        
        
        {
            std::vector<std::vector<double>> Q2(15, std::vector<double>(15));
            for (int i = 0; i < 15; ++i) {
                for (int j = 0; j < 15; ++j) {
                    Q2[i][j] = 2.0 + 1.5 * sin(i * 0.3) * cos(j * 0.4);
                }
            }
            apply_boundary_conditions_ptr(Q2);
        }
        
        
        {
            std::vector<std::vector<double>> Q3(25, std::vector<double>(25));
            for (int i = 0; i < 25; ++i) {
                for (int j = 0; j < 25; ++j) {
                    Q3[i][j] = 3.0 + 2.0 * exp(-((i-12)*(i-12) + (j-12)*(j-12)) / 20.0);
                }
            }
            apply_boundary_conditions_ptr(Q3);
        }
        
        
        std::vector<std::vector<double>> Q(15, std::vector<double>(15));
        for (int i = 0; i < 15; ++i) {
            for (int j = 0; j < 15; ++j) {
                Q[i][j] = 2.0 + 1.5 * sin(i * 0.3) * cos(j * 0.4);
            }
        }
        double internal_sum_before = 0.0;
        for (int i = 1; i < 14; ++i) {
            for (int j = 1; j < 14; ++j) {
                internal_sum_before += Q[i][j];
            }
        }
        apply_boundary_conditions_ptr(Q);
        double internal_sum_after = 0.0;
        for (int i = 1; i < 14; ++i) {
            for (int j = 1; j < 14; ++j) {
                internal_sum_after += Q[i][j];
            }
        }
        
        
        bool all_boundaries_zero = true;
        for (int i = 0; i < 15; ++i) {
            if (Q[i][0] != 0.0 || Q[i][14] != 0.0) all_boundaries_zero = false;
        }
        for (int j = 0; j < 15; ++j) {
            if (Q[0][j] != 0.0 || Q[14][j] != 0.0) all_boundaries_zero = false;
        }
        
        test1_passed = (all_boundaries_zero && std::abs(internal_sum_before - internal_sum_after) < 1e-10 && Q[7][7] > 0.0);
        if (test1_passed) {
            std::cout << "correct\n";
        } else {
            std::cout << "wrong\n";
        }
    }
    
    
    {
        
        {
            std::vector<std::vector<double>> Q1(5, std::vector<double>(5, 0.0));
            Q1[2][2] = 1.0;
            apply_boundary_conditions_ptr(Q1);
        }
        
        
        {
            std::vector<std::vector<double>> Q2(10, std::vector<double>(10, 0.0));
            Q2[3][3] = 2.5;
            Q2[6][6] = 1.8;
            Q2[7][2] = 1.2;
            apply_boundary_conditions_ptr(Q2);
        }
        
        
        {
            std::vector<std::vector<double>> Q3(12, std::vector<double>(12, 0.0));
            for (int i = 2; i < 10; ++i) {
                for (int j = 2; j < 10; ++j) {
                    Q3[i][j] = 1.0 + 0.5 * sin(i * 0.5) * cos(j * 0.5);
                }
            }
            apply_boundary_conditions_ptr(Q3);
        }
        
        
        std::vector<std::vector<double>> Q(10, std::vector<double>(10, 0.0));
        Q[3][3] = 2.5;
        Q[6][6] = 1.8;
        Q[7][2] = 1.2;
        double source_sum_before = Q[3][3] + Q[6][6] + Q[7][2];
        apply_boundary_conditions_ptr(Q);
        double source_sum_after = Q[3][3] + Q[6][6] + Q[7][2];
        
        test2_passed = (std::abs(Q[3][3] - 2.5) < 1e-10 && 
                       std::abs(Q[6][6] - 1.8) < 1e-10 &&
                       std::abs(Q[7][2] - 1.2) < 1e-10 &&
                       std::abs(source_sum_before - source_sum_after) < 1e-10 &&
                       Q[0][0] == 0.0);
        if (test2_passed) {
            std::cout << "correct\n";
        } else {
            std::cout << "wrong\n";
        }
    }
    
    
    {
        
        {
            std::vector<std::vector<double>> Q1(10, std::vector<double>(10, 1.0));
            apply_gradient_boundary_conditions_ptr(Q1, 0.5, -0.5, 0.3, -0.3, 1.0, 1.0);
        }
        
        
        {
            std::vector<std::vector<double>> Q2(20, std::vector<double>(20));
            for (int i = 0; i < 20; ++i) {
                for (int j = 0; j < 20; ++j) {
                    Q2[i][j] = 2.0 + 1.5 * sin(i * 0.2) * cos(j * 0.3);
                }
            }
            apply_gradient_boundary_conditions_ptr(Q2, 0.8, -0.6, 0.5, -0.4, 1.2, 0.9);
        }
        
        
        {
            std::vector<std::vector<double>> Q3(15, std::vector<double>(15, 1.5));
            
            double source1 = calculate_gaussian_source_ptr(5.0, 5.0, 5.0, 5.0, 3.0, 1.5);
            double source2 = calculate_gaussian_source_ptr(10.0, 10.0, 10.0, 10.0, 2.5, 1.2);
            double source3 = calculate_gaussian_source_ptr(2.0, 12.0, 2.0, 12.0, 1.8, 1.0);
        }
        
        
        std::vector<std::vector<double>> Q(10, std::vector<double>(10, 1.0));
        double dx = 1.0, dy = 1.0;
        double gradient_x_left = 0.5;
        double gradient_x_right = -0.5;
        double gradient_y_bottom = 0.3;
        double gradient_y_top = -0.3;
        
        // Calculate expected values before applying boundary conditions
        double expected_left = Q[1][5] - gradient_x_left * dx;
        double expected_right = Q[8][5] + gradient_x_right * dx;
        double expected_bottom = Q[5][1] - gradient_y_bottom * dy;
        double expected_top = Q[5][8] + gradient_y_top * dy;
        
        apply_gradient_boundary_conditions_ptr(Q, gradient_x_left, gradient_x_right, 
                                          gradient_y_bottom, gradient_y_top, dx, dy);
        
        double source_center = calculate_gaussian_source_ptr(5.0, 5.0, 5.0, 5.0, 2.0, 1.0);
        double source_edge = calculate_gaussian_source_ptr(0.0, 0.0, 5.0, 5.0, 2.0, 1.0);
        double source_mid = calculate_gaussian_source_ptr(7.0, 7.0, 5.0, 5.0, 2.0, 1.0);
        
        // Check boundary conditions - y boundary setting uses Q[i][1] which for i=0,9 may be modified by x boundary
        // But for Q[5][0], Q[5][1] should be unchanged, so expected_bottom is correct
        // For Q[0][5] and Q[9][5], these are on x boundaries and should be correct
        bool boundary_ok = (std::abs(Q[0][5] - expected_left) < 1e-3 && 
                           std::abs(Q[9][5] - expected_right) < 1e-3 &&
                           std::abs(Q[5][0] - expected_bottom) < 1e-3 &&
                           std::abs(Q[5][9] - expected_top) < 1e-3);
        // Check source terms
        bool source_ok = (std::abs(source_center - 2.0) < 1e-5 &&
                         source_edge < 0.1 &&
                         source_mid > 0.01 && source_mid < 2.0);
        test3_passed = (boundary_ok && source_ok);
        if (test3_passed) {
            std::cout << "correct\n";
        } else {
            std::cout << "wrong\n";
        }
    }
    
    std::cout << "\n========================================\n";
    if (test1_passed && test2_passed && test3_passed) {
        std::cout << "Completely correct!\n";
    }
    std::cout << "========================================\n";
    
    return 0;
}

step_number: 4
step_description_prompt: Please write C++ code to implement a function named problem_2_04.
The function defines two lambdas: one applies zero Dirichlet boundary conditions to 2D grid data, the other performs 2D diffusion time stepping calculation, then assigns both lambdas to corresponding pre-declared global function pointers. Add necessary parameter checks and invalid value protection for the calculation process.
function_header: void problem_2_04() 
test_cases: int main() {
    // Initialize by calling problem_2_04 to set function pointers
    problem_2_04();

    // Wrapper functions in main (using global function pointers)
    auto apply_boundary_conditions = [](std::vector<std::vector<double>>& Q) -> void {
        apply_boundary_conditions_ptr(Q);
    };

    auto time_step = [](
        std::vector<std::vector<double>>& Q,
        const std::vector<std::vector<double>>& u,
        const std::vector<std::vector<double>>& v,
        const std::vector<std::vector<double>>& source,
        double k, double dt, double dx, double dy
    ) -> void {
        time_step_ptr(Q, u, v, source, k, dt, dx, dy);
    };

    std::cout << "========================================\n";
    std::cout << "Problem 2-Subproblem 4: Time Integration and Numerical Stability\n";
    std::cout << "========================================\n";
    
    bool test1_passed = false, test2_passed = false, test3_passed = false;
    
    
    {
        std::vector<std::vector<double>> Q(10, std::vector<double>(10, 0.0));
        Q[5][5] = 1.0;
        std::vector<std::vector<double>> u(10, std::vector<double>(10, 0.0));
        std::vector<std::vector<double>> v(10, std::vector<double>(10, 0.0));
        std::vector<std::vector<double>> source(10, std::vector<double>(10, 0.0));
        
        
        double mass_before = 0.0;
        for (const auto& row : Q) {
            for (double val : row) {
                mass_before += val;
            }
        }
        
        double k = 0.01, dt = 3600.0, dx = 100.0, dy = 100.0;
        time_step(Q, u, v, source, k, dt, dx, dy);
        
        
        double cfl_diff = 2.0 * k * dt * (1.0/(dx*dx) + 1.0/(dy*dy));
        
        
        double mass_after = 0.0;
        for (const auto& row : Q) {
            for (double val : row) {
                mass_after += val;
            }
        }
        double mass_change = std::abs(mass_after - mass_before) / (mass_before + 1e-10);
        
        
        double expected_q = 1.0 - 4.0 * k * dt / (dx*dx);  
        
        test1_passed = (Q.size() == 10 && 
                       std::isfinite(Q[5][5]) && Q[5][5] > 0.0 && Q[5][5] < 1.0 &&
                       cfl_diff < 0.5 &&
                       mass_change < 0.01);
        if (test1_passed) {
            std::cout << "correct\n";
        } else {
            std::cout << "wrong\n";
        }
    }
    
    
    {
        std::vector<std::vector<double>> Q(15, std::vector<double>(15, 0.0));
        Q[7][7] = 1.0;
        std::vector<std::vector<double>> u(15, std::vector<double>(15, 0.0));
        std::vector<std::vector<double>> v(15, std::vector<double>(15, 0.0));
        std::vector<std::vector<double>> source(15, std::vector<double>(15, 0.0));
        
        
        double energy_before = 0.0;
        for (const auto& row : Q) {
            for (double val : row) {
                energy_before += val * val;
            }
        }
        
        double k = 0.01, dt = 3600.0, dx = 100.0, dy = 100.0;
        for (int i = 0; i < 10; ++i) {
            time_step(Q, u, v, source, k, dt, dx, dy);
        }
        
        
        double energy_after = 0.0;
        for (const auto& row : Q) {
            for (double val : row) {
                energy_after += val * val;
            }
        }
        double energy_decay = (energy_before > 0.0) ? (energy_before - energy_after) / energy_before : 0.0;
        
        
        test2_passed = (Q.size() == 15 && 
                       std::isfinite(Q[7][7]) && Q[7][7] > 0.0 && Q[7][7] < 1.0 &&
                       energy_after < energy_before &&
                       energy_decay > 0.0 && energy_decay < 1.0);
        if (test2_passed) {
            std::cout << "correct\n";
        } else {
            std::cout << "wrong\n";
        }
    }
    
    
    {
        std::vector<std::vector<double>> Q(20, std::vector<double>(20, 0.0));
        Q[10][10] = 1.0;
        std::vector<std::vector<double>> u(20, std::vector<double>(20, 0.0));
        std::vector<std::vector<double>> v(20, std::vector<double>(20, 0.0));
        std::vector<std::vector<double>> source(20, std::vector<double>(20, 0.0));
        
        double k = 0.01, dt = 3600.0, dx = 100.0, dy = 100.0;
        
        
        std::vector<double> q_history;
        q_history.push_back(Q[10][10]);
        
        for (int i = 0; i < 24; ++i) {
            time_step(Q, u, v, source, k, dt, dx, dy);
            q_history.push_back(Q[10][10]);
        }
        
        
        bool monotonic = true;
        for (size_t i = 1; i < q_history.size(); ++i) {
            if (q_history[i] > q_history[i-1] + 1e-10) {  
                monotonic = false;
                break;
            }
        }
        
        
        double diffusion_time = dx * dx / (4.0 * k);  
        double total_time = 24.0 * 3600.0;
        double time_ratio = total_time / diffusion_time;
        
        test3_passed = (Q.size() == 20 && 
                       std::isfinite(Q[10][10]) && Q[10][10] > 0.0 && Q[10][10] < 1.0 &&
                       monotonic &&
                       time_ratio > 0.1);
        if (test3_passed) {
            std::cout << "correct\n";
        } else {
            std::cout << "wrong\n";
        }
    }
    
    std::cout << "\n========================================\n";
    if (test1_passed && test2_passed && test3_passed) {
        std::cout << "Completely correct!\n";
    }
    std::cout << "========================================\n";
    
    return 0;
}

step_number: 5
step_description_prompt: Please use C++ to generate a function named problem_2_05. A global function pointer double (*check_mass_conservation_ptr)(const std::vector<std::vector<double>>&, double, double) is pre-defined. Implement a lambda inside the function to compute total mass of 2D grid Q with dx, dy via high-precision summation, return 0 if result is nan or inf, assign the lambda to the global pointer.
function_header: void problem_2_05() 
test_cases: int main() {
    // Initialize by calling problem_2_05 to set function pointers
    problem_2_05();

    


    std::cout << "========================================\n";
    std::cout << "Problem 2-Subproblem 5: Result Output and Validation\n";
    std::cout << "========================================\n";
    
    bool test1_passed = false, test2_passed = false, test3_passed = false;
    
    
    {
        std::vector<std::vector<double>> Q1(5, std::vector<double>(5, 1.0));
        std::vector<std::vector<double>> Q2(50, std::vector<double>(50, 0.1));  
        std::vector<std::vector<double>> Q3(10, std::vector<double>(10));
        for (int i = 0; i < 10; ++i) {
            for (int j = 0; j < 10; ++j) {
                Q3[i][j] = 1e-10 + (i + j) * 1e-12;  
            }
        }
        
        double mass1 = check_mass_conservation_ptr(Q1, 100.0, 100.0);
        double mass2 = check_mass_conservation_ptr(Q2, 10.0, 10.0);
        double mass3 = check_mass_conservation_ptr(Q3, 100.0, 100.0);
        
        double expected_mass1 = 25.0 * 100.0 * 100.0;
        double expected_mass2 = 2500.0 * 0.1 * 10.0 * 10.0;
        
        double sum3 = 0.0;
        for (int i = 0; i < 10; ++i) {
            for (int j = 0; j < 10; ++j) {
                sum3 += Q3[i][j];
            }
        }
        double expected_mass3_calc = sum3 * 100.0 * 100.0;
        
        test1_passed = (std::abs(mass1 - expected_mass1) < 1e-10 &&
                       std::abs(mass2 - expected_mass2) < 1e-8 &&
                       std::abs(mass3 - expected_mass3_calc) < 1e-15);
        if (test1_passed) {
            std::cout << "correct\n";
        } else {
            std::cout << "wrong\n";
        }
    }
    
    
    {
        std::vector<std::vector<double>> Q(20, std::vector<double>(20, 1.0));
        
        for (int i = 0; i < 20; ++i) {
            Q[i][0] = 0.0;
            Q[i][19] = 0.0;
            Q[0][i] = 0.0;
            Q[19][i] = 0.0;
        }
        
        double mass_before = check_mass_conservation_ptr(Q, 100.0, 100.0);
        
        
        double mass_after_boundary = check_mass_conservation_ptr(Q, 100.0, 100.0);
        
        
        int internal_points = 18 * 18;
        double expected_mass = internal_points * 1.0 * 100.0 * 100.0;
        
        
        double relative_error = std::abs(mass_after_boundary - expected_mass) / expected_mass;
        
        test2_passed = (std::abs(mass_after_boundary - expected_mass) < 1e-10 &&
                       relative_error < 1e-12);
        if (test2_passed) {
            std::cout << "correct\n";
        } else {
            std::cout << "wrong\n";
        }
    }
    
    
    {
        std::vector<std::vector<double>> Q(15, std::vector<double>(15, 0.02));
        Q[7][7] = 1.0;
        Q[3][3] = 0.5;
        Q[11][11] = 0.3;
        
        double max_val = Q[0][0], min_val = Q[0][0];
        double sum = 0.0, sum_sq = 0.0;
        size_t count = 0;
        size_t nan_count = 0, inf_count = 0, negative_count = 0;
        
        for (const auto& row : Q) {
            for (double val : row) {
                if (std::isnan(val)) {
                    nan_count++;
                    continue;
                }
                if (std::isinf(val)) {
                    inf_count++;
                    continue;
                }
                if (val < 0.0) {
                    negative_count++;
                }
                max_val = std::max(max_val, val);
                min_val = std::min(min_val, val);
                sum += val;
                sum_sq += val * val;
                count++;
            }
        }
        
        double mean = sum / count;
        double variance = (sum_sq / count) - (mean * mean);
        double std_dev = sqrt(std::max(0.0, variance));
        
        double expected_mean = (1.0 + 0.5 + 0.3 + (15.0 * 15.0 - 3) * 0.02) / (15.0 * 15.0);
        double expected_max = 1.0;
        double expected_min = 0.02;
        
        test3_passed = (std::abs(max_val - expected_max) < 1e-12 &&
                       std::abs(min_val - expected_min) < 1e-12 &&
                       std::abs(mean - expected_mean) < 1e-12 &&
                       std_dev > 0.0 &&
                       nan_count == 0 && inf_count == 0 && negative_count == 0);
        if (test3_passed) {
            std::cout << "correct\n";
        } else {
            std::cout << "wrong\n";
        }
    }
    
    std::cout << "\n========================================\n";
    if (test1_passed && test2_passed && test3_passed) {
        std::cout << "Completely correct!\n";
    }
    std::cout << "========================================\n";
    
    return 0;
}

General solution:

General tests: