Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
4bf033a
add mc conservative projection file
abhiyan123 Mar 17, 2026
d2eb0af
add mc helper functions declaration
abhiyan123 Mar 17, 2026
8f5148a
change function name from buildLoadVector to buildLoadVectorMI
abhiyan123 Mar 17, 2026
9094916
fix the load vector integrator name
abhiyan123 Mar 17, 2026
a95460b
add mc load vector build declaration
abhiyan123 Mar 17, 2026
e0b9fcd
add header
abhiyan123 Mar 17, 2026
26f1a4f
delete pcms_mc_proj_utils.hpp
abhiyan123 Mar 17, 2026
12c50c7
rename pcms_mc_proj_utils.cpp -> load_vector_integrator_mc.cpp
abhiyan123 Mar 17, 2026
21fdaba
rename load_vector_integrator.cpp -> load_vector_integrator_mi.cpp
abhiyan123 Mar 17, 2026
ab31a90
add mc load vector build
abhiyan123 Mar 17, 2026
54213bb
add build load vector with mc approach
abhiyan123 Mar 17, 2026
ecd8234
change the parameter sequence
abhiyan123 Mar 17, 2026
56c0160
add mc solver function
abhiyan123 Mar 17, 2026
e489bea
change parameter sequence
abhiyan123 Mar 17, 2026
17644e3
update variants of galerkin projection solve
abhiyan123 Mar 18, 2026
d542524
add namespace
abhiyan123 Mar 18, 2026
aea8cb6
update filenames in CMakeLists.txt
abhiyan123 Mar 18, 2026
15897c1
update solveGalerkinProjection to solveGalerkinProjectionMI
abhiyan123 Mar 18, 2026
5643ec2
update buildLoadVector to buildLoadVectorMI
abhiyan123 Mar 18, 2026
6356c81
add mc test functions
abhiyan123 Mar 18, 2026
bb20610
update mc test file in CMakeLists.txt
abhiyan123 Mar 18, 2026
6d6e7e1
add semicolon
abhiyan123 Mar 19, 2026
65a09c9
correct the class name
abhiyan123 Mar 19, 2026
4f664bc
update variable
abhiyan123 Mar 19, 2026
af6e728
correct class name
abhiyan123 Mar 19, 2026
a6207e7
change tri_id to element_id
abhiyan123 Mar 19, 2026
d51b3cd
change tri_id to element_id
abhiyan123 Mar 19, 2026
73d2143
minor changes
abhiyan123 Mar 19, 2026
4e626c9
fix the function name
abhiyan123 Mar 19, 2026
5dca135
update header
abhiyan123 Mar 19, 2026
e0915d1
update header
abhiyan123 Mar 19, 2026
0310306
update function
abhiyan123 Mar 19, 2026
4556bdc
minor changes
abhiyan123 Mar 19, 2026
24eccd5
add test case for monte carlo field transfer
abhiyan123 Mar 19, 2026
083144c
add filename in CMakeLists.txt
abhiyan123 Mar 19, 2026
30785f1
update header
abhiyan123 Mar 19, 2026
82f2fa8
update solveGalerkinProjectionMC parameters
abhiyan123 Mar 19, 2026
7a9785d
update args in a solveGalerkinProjectionMC function
abhiyan123 Mar 19, 2026
5a3d44a
create a host view instead of device
abhiyan123 Mar 19, 2026
80f8aba
update the API docs for MC projection
abhiyan123 Mar 19, 2026
e0c310d
add sobol samples
abhiyan123 Mar 19, 2026
86285ff
added more sobol barycentric points
abhiyan123 Mar 20, 2026
a92a3d1
change triangular element to just element
abhiyan123 Mar 20, 2026
228d58a
minor changes
abhiyan123 Mar 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/pcms/transfer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ set(PCMS_FIELD_TRANSFER_HEADERS

set(PCMS_FIELD_TRANSFER_SOURCES
adj_search.cpp
load_vector_integrator.cpp
load_vector_integrator_mi.cpp
load_vector_integrator_mc.cpp
mesh_intersection.cpp
mls_interpolation.cpp
interpolation_base.cpp)
Expand Down
49 changes: 47 additions & 2 deletions src/pcms/transfer/calculate_load_vector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

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.

Omega_h::Mesh& source_mesh,
const IntersectionResults& intersection,
const Omega_h::Reals& source_values,
Expand All @@ -21,7 +21,52 @@ PetscErrorCode calculateLoadVector(Omega_h::Mesh& target_mesh,

// Fill COO values
auto elmLoadVector =
buildLoadVector(target_mesh, source_mesh, intersection, source_values);
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.

PetscCheck(static_cast<PetscInt>(hostElmLoadVector.extent(0)) == nnz,
PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ,
"Element load vector size (%d) does not match COO nnz (%d)",
static_cast<PetscInt>(hostElmLoadVector.extent(0)), nnz);

for (PetscInt e = 0; e < nnz; ++e) {
coo_vals[e] = hostElmLoadVector(e);
}

// create vector with preallocated COO structure
Vec vec;
PetscCall(createSeqVec(PETSC_COMM_WORLD, target_mesh.nverts(), &vec));
PetscCall(VecSetPreallocationCOO(vec, nnz, coo_i));
PetscCall(VecSetValuesCOO(vec, coo_vals, ADD_VALUES));
PetscCall(PetscFree(coo_i));
PetscCall(PetscFree(coo_vals));

if (target_mesh.nelems() < 10) {
PetscCall(VecView(vec, PETSC_VIEWER_STDOUT_WORLD));
}

*loadVec_out = vec;
PetscFunctionReturn(PETSC_SUCCESS);
}

PetscErrorCode calculateLoadVectorMC(
Omega_h::Mesh& target_mesh, const Omega_h::Reals& field_values_at_points,
const int npoints_each_tri, SamplingMethod method, Vec* loadVec_out,
const std::string sobol_filename)
{

PetscFunctionBeginUser;
PetscInt nnz = 0;
PetscInt* coo_i = nullptr;
PetscCall(build_linear_triangle_coo_rows(target_mesh, &coo_i, &nnz));
PetscScalar* coo_vals = nullptr;
PetscCall(PetscMalloc1(nnz, &coo_vals));

// Fill COO values
auto elmLoadVector =
buildLoadVectorMC(target_mesh, field_values_at_points, npoints_each_tri,
method, sobol_filename);

auto hostElmLoadVector = Kokkos::create_mirror_view(elmLoadVector);
Kokkos::deep_copy(hostElmLoadVector, elmLoadVector);
Expand Down
76 changes: 63 additions & 13 deletions src/pcms/transfer/calculate_load_vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,18 @@
#define PCMS_TRANSFER_CALCULATE_LOAD_VECTOR_HPP
#include <Omega_h_mesh.hpp>
#include <pcms/transfer/mesh_intersection.hpp>
#include <pcms/transfer/load_vector_integrator.hpp>
#include <petscvec.h>

namespace pcms
{

/**
* @brief Assembles the global load vector.
* @brief Assembles the global load vector using mesh intersection method.
*
* This function computes the unassembled local load vector contributions for
* each triangular element in the target mesh using `buildLoadVector()` and then
* assembles them into a global PETSc vector in COO format.
* each triangular element in the target mesh using `buildLoadVectorMI()` and
* then assembles them into a global PETSc vector in COO format.
*
*
* @param target_mesh The target Omega_h mesh to which the scalar field is being
Expand All @@ -40,20 +44,66 @@
* @note
* - Works for 2D linear triangular elements.
* - Uses COO-style preallocation and insertion into the PETSc vector.
* - Internally calls `buildLoadVector()` to compute per-element contributions.
* - Internally calls `buildLoadVectorMI()` to compute per-element
* contributions.
* - The resulting vector is used as the right-hand side (RHS) in a projection
* solve.
*
* @see buildLoadVector,IntersectionResults
* @see buildLoadVectorMI,IntersectionResults
*/

namespace pcms
{
// FIXME use PCMS error handling rather than returning a PETSC error code
PetscErrorCode calculateLoadVector(Omega_h::Mesh& target_mesh,
Omega_h::Mesh& source_mesh,
const IntersectionResults& intersection,
const Omega_h::Reals& source_values,
Vec* loadVec_out);
PetscErrorCode calculateLoadVectorMI(Omega_h::Mesh& target_mesh,
Omega_h::Mesh& source_mesh,
const IntersectionResults& intersection,
const Omega_h::Reals& source_values,
Vec* loadVec_out);

/**
* @brief Assembles the global load vector using Monte Carlo integration.
*
* This function computes the unassembled local load vector contributions for
* each element in the target mesh using Monte Carlo integration and
* then assembles them into a global PETSc vector in COO format.
*
* The element-local contributions are computed from source-field values already
* evaluated at the sampled physical points in each target element. The sampling
* pattern is defined on the reference triangle and may be generated either by
* uniform random sampling or by precomputed Sobol barycentric samples.
*
* @param target_mesh The target Omega_h mesh to which the scalar field is being
* projected.
* @param field_values_at_points Source-field values evaluated at the sampled
* physical points in the target mesh. The data is expected to be stored
* element-by-element, with total size
* `target_mesh.nelems() * npoints_each_tri`.
* @param npoints_each_tri Number of sample points used in each target triangle
* for the Monte Carlo integration.
* @param method Sampling method used to define the reference barycentric sample
* coordinates. Supported options include uniform random sampling and Sobol
* sampling.
* @param sobol_filename Path to the file containing precomputed Sobol
* barycentric samples when `method` is `SamplingMethod::SOBOL`.
* @param[out] loadVec_out Pointer to a PETSc Vec where the assembled load
* vector will be stored.
*
* @return PetscErrorCode Returns PETSC_SUCCESS if successful, or an appropriate
* PETSc error code otherwise.
*
* @note
* - Works for 2D linear triangular elements.
* - Uses COO-style preallocation and insertion into the PETSc vector.
* - Internally computes per-element Monte Carlo load vector contributions
* before assembling the global vector.
* - For linear triangular elements, the barycentric coordinates are equal to
* the local shape-function values used in the Monte Carlo estimator.
* - The resulting vector is used as the right-hand side (RHS) in a projection
* solve.
*
* @see buildLoadVectorMC, SamplingMethod
*/
PetscErrorCode calculateLoadVectorMC(
Omega_h::Mesh& target_mesh, const Omega_h::Reals& field_values_at_points,
const int npoints_each_tri, SamplingMethod method, Vec* loadVec_out,
const std::string sobol_filename = "");
} // namespace pcms
#endif // PCMS_TRANSFER_CALCULATE_LOAD_VECTOR_HPP
76 changes: 64 additions & 12 deletions src/pcms/transfer/conservative_projection_solver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,9 @@ static Omega_h::Reals vecToOmegaHReals(Vec vec)
return Omega_h::Reals(values_host);
}

Omega_h::Reals solveGalerkinProjection(Omega_h::Mesh& target_mesh,
Omega_h::Mesh& source_mesh,
const IntersectionResults& intersection,
const Omega_h::Reals& source_values)
Omega_h::Reals solveGalerkinProjectionMI(
Omega_h::Mesh& target_mesh, Omega_h::Mesh& source_mesh,
const IntersectionResults& intersection, const Omega_h::Reals& source_values)
{
if ((PetscInt)source_values.size() !=
source_mesh.coords().size() / source_mesh.dim()) {
Expand All @@ -105,8 +104,8 @@ Omega_h::Reals solveGalerkinProjection(Omega_h::Mesh& target_mesh,
CHKERRABORT(PETSC_COMM_WORLD, ierr);

Vec vec;
ierr = calculateLoadVector(target_mesh, source_mesh, intersection,
source_values, &vec);
ierr = calculateLoadVectorMI(target_mesh, source_mesh, intersection,
source_values, &vec);
CHKERRABORT(PETSC_COMM_WORLD, ierr);

Vec x = solveLinearSystem(mass, vec);
Expand All @@ -123,15 +122,46 @@ Omega_h::Reals solveGalerkinProjection(Omega_h::Mesh& target_mesh,

return solution_vector;
}
Omega_h::Reals rhsVectorMI(Omega_h::Mesh& target_mesh,
Omega_h::Mesh& source_mesh,
const IntersectionResults& intersection,
const Omega_h::Reals& source_values)

Omega_h::Reals solveGalerkinProjectionMC(
Omega_h::Mesh& target_mesh, const Omega_h::Reals& field_values_at_points,
const int npoints_each_tri, SamplingMethod method,
const std::string sobol_filename)
{

Mat mass;
PetscErrorCode ierr = calculateMassMatrix(target_mesh, &mass);
CHKERRABORT(PETSC_COMM_WORLD, ierr);

Vec vec;
ierr = calculateLoadVectorMC(target_mesh, field_values_at_points,
npoints_each_tri, method, &vec, sobol_filename);
CHKERRABORT(PETSC_COMM_WORLD, ierr);
Comment on lines +126 to +139
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.

solveGalerkinProjectionMC never validates that field_values_at_points has the expected size (target_mesh.nelems() * npoints_each_tri). If the caller passes a mismatched array, buildLoadVectorMC will index out-of-bounds. Add an explicit size check here (and/or in calculateLoadVectorMC/buildLoadVectorMC) and fail with a clear error message.

Copilot uses AI. Check for mistakes.

Vec x = solveLinearSystem(mass, vec);
auto solution_vector = vecToOmegaHReals(x);

ierr = VecDestroy(&x);
CHKERRABORT(PETSC_COMM_WORLD, ierr);

ierr = MatDestroy(&mass);
CHKERRABORT(PETSC_COMM_WORLD, ierr);

ierr = VecDestroy(&vec);
CHKERRABORT(PETSC_COMM_WORLD, ierr);

return solution_vector;
}

Omega_h::Reals computeRhsVectorMI(Omega_h::Mesh& target_mesh,
Omega_h::Mesh& source_mesh,
const IntersectionResults& intersection,
const Omega_h::Reals& source_values)
{
Vec vec;
PetscErrorCode ierr;
ierr = calculateLoadVector(target_mesh, source_mesh, intersection,
source_values, &vec);
ierr = calculateLoadVectorMI(target_mesh, source_mesh, intersection,
source_values, &vec);
CHKERRABORT(PETSC_COMM_WORLD, ierr);

auto rhsvector = vecToOmegaHReals(vec);
Expand All @@ -141,4 +171,26 @@ Omega_h::Reals rhsVectorMI(Omega_h::Mesh& target_mesh,

return rhsvector;
}

Omega_h::Reals computeRhsVectorMC(Omega_h::Mesh& target_mesh,
const Omega_h::Reals& field_values_at_points,
const int npoints_each_tri,
SamplingMethod method,
const std::string& sobol_filename)
{

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;
}

Comment on lines +181 to +195
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.
} // namespace pcms
Loading
Loading