Skip to content

stochastic galerkin projection routines #300

Open
abhiyanpaudel wants to merge 44 commits intodevelopfrom
mc_projection
Open

stochastic galerkin projection routines #300
abhiyanpaudel wants to merge 44 commits intodevelopfrom
mc_projection

Conversation

@abhiyanpaudel
Copy link
Collaborator

This PR adds the stochastic Galerkin projection workflow. Currently, this works for 2D linear elements. A follow-up cleanup would be to remove the current file-based Sobol input path and add a function for Sobol sampling.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a stochastic (Monte Carlo / Sobol-sampled) workflow for assembling the Galerkin projection load vector on 2D linear triangular meshes, alongside renaming the existing mesh-intersection (exact) projection APIs for clarity.

Changes:

  • Add Monte Carlo sampling + point-localization utilities and a Monte Carlo load-vector integrator.
  • Split/rename mesh-intersection routines to *MI variants and add *MC solver/RHS variants.
  • Add unit tests covering sampling/mapping/localization/field-evaluation and end-to-end Monte Carlo projection.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
test/test_monte_carlo_projection_functions.cpp New tests for Sobol file read, barycentric sampling, mapping, localization, and field evaluation pipeline.
test/test_monte_carlo_field_transfer.cpp New end-to-end PETSc-enabled test for Monte Carlo projection (constant/linear fields).
test/test_mesh_intersection_field_transfer.cpp Update to renamed mesh-intersection projection entrypoint (solveGalerkinProjectionMI).
test/test_load_vector.cpp Update to renamed mesh-intersection load-vector builder (buildLoadVectorMI).
test/CMakeLists.txt Register new test sources (Omega_h + PETSc gates).
src/pcms/transfer/load_vector_integrator_mi.cpp Rename mesh-intersection integrator entrypoint to buildLoadVectorMI.
src/pcms/transfer/load_vector_integrator_mc.cpp New Monte Carlo sampling, mapping, localization, field-eval, and buildLoadVectorMC.
src/pcms/transfer/load_vector_integrator.hpp Add MC API declarations + SamplingMethod; rename MI entrypoint declaration.
src/pcms/transfer/conservative_projection_solver.hpp Add solveGalerkinProjectionMI/MC and computeRhsVectorMI/MC APIs + updated documentation.
src/pcms/transfer/conservative_projection_solver.cpp Implement MI/MC projection solves and RHS-vector helpers using PETSc.
src/pcms/transfer/calculate_load_vector.hpp Rename MI assembler to calculateLoadVectorMI; add MC assembler API.
src/pcms/transfer/calculate_load_vector.cpp Implement calculateLoadVectorMI and new calculateLoadVectorMC.
src/pcms/transfer/CMakeLists.txt Build both MI + MC integrator sources; keep PETSc pieces behind PCMS_ENABLE_PETSC.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +107 to +115
const std::string filename = "tmp_sobol_barycentric_samples.txt";
std::ofstream out(filename);
REQUIRE(out.is_open());
out << "l0 l1 l2\n";
out << "1.0 0.0 0.0\n";
out << "0.0 1.0 0.0\n";
out << "0.2 0.3 0.5\n";
out.close();

Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test uses a fixed temporary filename (tmp_sobol_barycentric_samples.txt). If tests are executed in parallel (or rerun after a crash), this can cause collisions or stale data. Consider using a unique temp path and/or an RAII cleanup guard so the file is removed even when assertions fail.

Copilot uses AI. Check for mistakes.

int nx = edge_length[0] * Kokkos::sqrt(mesh.nelems());
int ny = edge_length[1] * Kokkos::sqrt(mesh.nelems());

Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

localize_points_in_mesh computes nx/ny by casting a floating expression to int. For small bounding boxes (edge length < 1) this can truncate to 0, which later causes division-by-zero in UniformGrid (divisions used as a divisor). Clamp nx/ny to at least 1 (and consider using Omega_h::LO/std::max).

Suggested change
if (nx < 1) nx = 1;
if (ny < 1) ny = 1;

Copilot uses AI. Check for mistakes.
#include <Omega_h_mesh.hpp>
#include <fstream>
#include <iostream>
#include <sstream>
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

load_vector_integrator.hpp declares APIs using std::string, but it does not include <string>. Please add the missing include to make the header self-contained, and consider removing heavy/unused includes like <iostream> (include it in the .cpp that needs it instead).

Suggested change
#include <sstream>
#include <sstream>
#include <string>

Copilot uses AI. Check for mistakes.
Comment on lines +129 to +130
const auto npoints = points.extent(0);

Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const auto npoints = points.extent(0); is unused, which will trigger warnings in this TU. Please remove it or use it for validation (e.g., early return on zero points).

Suggested change
const auto npoints = points.extent(0);

Copilot uses AI. Check for mistakes.
const auto& npoints = results.extent(0);

const auto& faces2nodes = mesh.ask_down(Omega_h::FACE, Omega_h::VERT).ab2b;
const auto& coordinates = mesh.coords();
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const auto& coordinates = mesh.coords(); is unused in evaluate_field_from_point_localization. Please remove it to avoid warnings and keep the function focused.

Suggested change
const auto& coordinates = mesh.coords();

Copilot uses AI. Check for mistakes.
Comment on lines +181 to +195

Vec vec;
PetscErrorCode ierr;
ierr =
calculateLoadVectorMC(target_mesh, field_values_at_points,
npoints_each_tri, method, &vec, sobol_filename);
CHKERRABORT(PETSC_COMM_WORLD, ierr);

auto rhsvector = vecToOmegaHReals(vec);
ierr = VecDestroy(&vec);
CHKERRABORT(PETSC_COMM_WORLD, ierr);

return rhsvector;
}

Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

computeRhsVectorMC has inconsistent indentation and a trailing tab after the closing brace, which will fight auto-formatting and make diffs noisy. Please reformat this block to match the rest of the file.

Suggested change
Vec vec;
PetscErrorCode ierr;
ierr =
calculateLoadVectorMC(target_mesh, field_values_at_points,
npoints_each_tri, method, &vec, sobol_filename);
CHKERRABORT(PETSC_COMM_WORLD, ierr);
auto rhsvector = vecToOmegaHReals(vec);
ierr = VecDestroy(&vec);
CHKERRABORT(PETSC_COMM_WORLD, ierr);
return rhsvector;
}
Vec vec;
PetscErrorCode ierr;
ierr =
calculateLoadVectorMC(target_mesh, field_values_at_points,
npoints_each_tri, method, &vec, sobol_filename);
CHKERRABORT(PETSC_COMM_WORLD, ierr);
auto rhsvector = vecToOmegaHReals(vec);
ierr = VecDestroy(&vec);
CHKERRABORT(PETSC_COMM_WORLD, ierr);
return rhsvector;
}

Copilot uses AI. Check for mistakes.
#include <pcms/transfer/conservative_projection_solver.hpp>
#include <pcms/transfer/load_vector_integrator.hpp>

#include <fstream>
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test uses std::function (see evaluate_field_at_barycentric_samples) but does not include <functional>. Please add the missing include to avoid relying on transitive headers.

Suggested change
#include <fstream>
#include <fstream>
#include <functional>

Copilot uses AI. Check for mistakes.
Comment on lines +534 to +538
auto bary = make_sobol_barycentric_samples();
const int npoints_each_tri = bary.extent(0);
const std::string sobol_filename = "tmp_mc_barycentric_samples.txt";
write_barycentric_samples_file(sobol_filename, bary);

Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test writes tmp_mc_barycentric_samples.txt but never deletes it. This can pollute the working directory and can also cause collisions when tests run concurrently. Add cleanup (ideally via an RAII guard) and consider using a unique filename per test run.

Copilot uses AI. Check for mistakes.
Comment on lines 399 to 402
test_interpolation_class.cpp
test_mesh_geometry.cpp
test_monte_carlo_projection_functions.cpp
test_omega_h_field2_outofbounds.cpp)
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This added entry is indented with a tab, which is inconsistent with the surrounding CMake formatting and may fail format checks. Replace the tab with spaces to match the rest of the file.

Copilot uses AI. Check for mistakes.
Comment on lines 411 to 414
list(APPEND PCMS_UNIT_TEST_SOURCES
test_mesh_intersection_field_transfer.cpp)
test_mesh_intersection_field_transfer.cpp
test_monte_carlo_field_transfer.cpp)
endif()
Copy link

Copilot AI Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This list append adds an entry with tab indentation. Use spaces to match the existing CMake formatting so automated formatters don't keep rewriting this line.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@Sichao25 Sichao25 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall. Just commented a few minor issues.

namespace pcms
{
PetscErrorCode calculateLoadVector(Omega_h::Mesh& target_mesh,
PetscErrorCode calculateLoadVectorMI(Omega_h::Mesh& target_mesh,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I haven't missed anything, the calculateLoadVectorMI and calculateLoadVectorMC share roughly 90% of their code, there may be room to refactor and eliminate the duplication.

buildLoadVectorMI(target_mesh, source_mesh, intersection, source_values);

auto hostElmLoadVector = Kokkos::create_mirror_view(elmLoadVector);
Kokkos::deep_copy(hostElmLoadVector, elmLoadVector);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a create_mirror_view_and_copy function.

{
std::ifstream infile(file_path);
if (!infile) {
throw std::runtime_error("Could not open sobol sample file");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have pcms_error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants