Skip to content

1675 cosserat implementation - Base branch - #1753

Open
Rohit-Kakodkar wants to merge 102 commits into
develfrom
1675-cosserat-mesh
Open

1675 cosserat implementation - Base branch#1753
Rohit-Kakodkar wants to merge 102 commits into
develfrom
1675-cosserat-mesh

Conversation

@Rohit-Kakodkar

Copy link
Copy Markdown
Collaborator

Description

Creates a temporary branch for cosserat mesh. @maxlchien

Issue Number

If there is an issue created for these changes, link it here

Checklist

Please make sure to check developer documentation on specfem docs.

  • I ran the code through pre-commit to check style
  • THE DOCUMENTATION BUILDS WITHOUT WARNINGS/ERRORS
  • I have added labels to the PR (see right hand side of the PR page)
  • My code passes all the integration tests
  • I have added sufficient unittests to test my changes
  • I have added/updated documentation for the changes I am proposing
  • I have updated CMakeLists to ensure my code builds
  • My code builds across all platforms

maxlchien and others added 19 commits March 6, 2026 05:43
…cept for receivers.hpp, receivers.cpp, info.tpp, and boundary_medium_container.hpp (see next commit)
Copilot AI review requested due to automatic review settings March 25, 2026 13:13
Update Fortran 3D mesher to accommodate isotropic Cosserat

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a new 3D “EightNodeElasticCosserat” mesh test case and wires up dim3 material/tag plumbing so Cosserat (elastic spin + isotropic Cosserat) meshes can be exercised by the unit-test suite.

Changes:

  • Extend dim3 unit-test parameterization and expected-results maps to include EightNodeElasticCosserat.
  • Add dim3 Cosserat material container instantiations and a new material_id parsing branch in the Fortran mesh reader.
  • Add a new dim3 test dataset directory (provenance + generated database.bin) and a Snakemake workflow to regenerate it.

Reviewed changes

Copilot reviewed 18 out of 19 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
tests/unit-tests/mesh/dim3/test.cpp Adds EightNodeElasticCosserat to the parameterized dim3 mesh test suite.
tests/unit-tests/mesh/dim3/tags.cpp Adds expected tag entries for Cosserat elements.
tests/unit-tests/mesh/dim3/mesh.cpp Adds expected mesh-size entry for the Cosserat dataset.
tests/unit-tests/mesh/dim3/materials.cpp Adds expected Cosserat material entries.
tests/unit-tests/mesh/dim3/control_nodes.cpp Adds expected control-node entry for the Cosserat dataset.
tests/unit-tests/mesh/dim3/boundaries.cpp Adds expected boundary-face entry for the Cosserat dataset.
tests/unit-tests/mesh/dim3/adjacency_graph.cpp Adds expected adjacency entry for the Cosserat dataset.
tests/unit-tests/data/dim3/EightNodeElasticCosserat/provenance/interfaces.txt Adds provenance input describing interfaces for the Cosserat mesh.
tests/unit-tests/data/dim3/EightNodeElasticCosserat/provenance/interface1.txt Adds provenance interface elevation file.
tests/unit-tests/data/dim3/EightNodeElasticCosserat/provenance/Mesh_Par_file Adds provenance mesher parameter file for generating the Cosserat mesh.
tests/unit-tests/data/dim3/EightNodeElasticCosserat/database.bin Adds the generated mesh database used by unit tests.
tests/unit-tests/data/dim3/EightNodeElasticCosserat/Snakefile Adds a workflow to regenerate database.bin.
tests/unit-tests/data/dim3/EightNodeElasticCosserat/.gitignore Ignores Snakemake’s executable check artifact.
core/specfem/mesh/dim3/materials/materials.hpp Instantiates dim3 material containers/accessors for elastic_spin + isotropic_cosserat.
core/specfem/io/mesh/impl/fortran/dim3/read_materials.cpp Adds parsing for Cosserat material ID and fixes an acoustic/elastic Vs error message.

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

Comment on lines 181 to 197
@@ -190,8 +192,8 @@ template <> struct materials<specfem::element::dimension_tag::dim3> {
* - Integration with SPECFEM++ template metaprogramming patterns
*/
FOR_EACH_IN_PRODUCT(
(DIMENSION_TAG(DIM3), MEDIUM_TAG(ACOUSTIC, ELASTIC),
PROPERTY_TAG(ISOTROPIC, ANISOTROPIC),
(DIMENSION_TAG(DIM3), MEDIUM_TAG(ACOUSTIC, ELASTIC, ELASTIC_SPIN),
PROPERTY_TAG(ISOTROPIC, ANISOTROPIC, ISOTROPIC_COSSERAT),
ATTENUATION_TAG(NONE, CONSTANT_ISOTROPIC)),

Copilot AI Mar 25, 2026

Copy link

Choose a reason for hiding this comment

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

This doc block (and the @tparam descriptions in this struct) still describes only acoustic/elastic + isotropic/anisotropic combinations, but the implementation now supports elastic_spin and isotropic_cosserat. Please update the parameter/docs list so it matches the actual supported material systems in dim3.

Copilot uses AI. Check for mistakes.
Comment on lines +176 to 185
material(rho, kappa, mu, nu, j, lambda_c, mu_c, nu_c);
const int index = materials.add_material(material);
mapping.push_back({ specfem::element::medium_tag::elastic_spin,
specfem::element::property_tag::isotropic_cosserat,
specfem::element::attenuation_tag::none, index,
imat });
}
default:
throw std::runtime_error("Unknown material ID: " +
std::to_string(material_id));

Copilot AI Mar 25, 2026

Copy link

Choose a reason for hiding this comment

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

case 4 (Cosserat) falls through into default because it’s missing a break; at the end of the case block. As written, Cosserat materials will always be parsed and then immediately trigger the "Unknown material ID" exception.

Copilot uses AI. Check for mistakes.
Comment on lines +165 to +169
if (mu < 0.0 || mu_c < 0.0 || 3 * lambda + 2 * mu < 0.0 ||
3 * lambda_c + 2 * mu_c < 0.0) {
throw std::runtime_error(
"Invalid elastic parameters for Cosserat material. u, mu_c, "
"3*lambda + 2*mu, and 3*lambda_c + 2*mu_c must be non-negative.");

Copilot AI Mar 25, 2026

Copy link

Choose a reason for hiding this comment

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

The Cosserat validation error message has a typo and is a bit unclear: it says "u" but the variable is mu. Consider correcting the parameter name(s) in the message (and potentially include the offending values) to make debugging material files easier.

Suggested change
if (mu < 0.0 || mu_c < 0.0 || 3 * lambda + 2 * mu < 0.0 ||
3 * lambda_c + 2 * mu_c < 0.0) {
throw std::runtime_error(
"Invalid elastic parameters for Cosserat material. u, mu_c, "
"3*lambda + 2*mu, and 3*lambda_c + 2*mu_c must be non-negative.");
const type_real first_combination = static_cast<type_real>(3.0) * lambda +
static_cast<type_real>(2.0) * mu;
const type_real second_combination =
static_cast<type_real>(3.0) * lambda_c +
static_cast<type_real>(2.0) * mu_c;
if (mu < 0.0 || mu_c < 0.0 || first_combination < 0.0 ||
second_combination < 0.0) {
throw std::runtime_error(
"Invalid elastic parameters for Cosserat material. mu, mu_c, "
"3*lambda + 2*mu, and 3*lambda_c + 2*mu_c must be non-negative. " +
std::string("Values are mu=") + std::to_string(mu) +
", mu_c=" + std::to_string(mu_c) +
", 3*lambda + 2*mu=" + std::to_string(first_combination) +
", 3*lambda_c + 2*mu_c=" + std::to_string(second_combination) +
".");

Copilot uses AI. Check for mistakes.
Comment on lines +156 to +180
{
"EightNodeElasticCosserat",
ExpectedMaterials3D(
TotalMaterials(1, 8),
{ // Element 0
ElementMaterial(
specfem::element::medium_tag::elastic_spin,
specfem::element::property_tag::isotropic_cosserat, 0,
specfem::medium_container::material<
specfem::element::dimension_tag::dim3,
specfem::element::medium_tag::elastic_spin,
specfem::element::property_tag::isotropic_cosserat,
specfem::element::attenuation_tag::none>(
2300.0, 1500.0, 2800.0, 1e6, 1e4, 300.0, 25.0, 500.0)),
// Element 5
ElementMaterial(
specfem::element::medium_tag::elastic_spin,
specfem::element::property_tag::isotropic_cosserat, 5,
specfem::medium_container::material<
specfem::element::dimension_tag::dim3,
specfem::element::medium_tag::elastic_spin,
specfem::element::property_tag::isotropic_cosserat,
specfem::element::attenuation_tag::none>(
2300.0, 1500.0, 2800.0, 1e6, 1e4, 300.0, 25.0,
500.0)) }),

Copilot AI Mar 25, 2026

Copy link

Choose a reason for hiding this comment

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

This new Cosserat test case adds expected elastic_spin/isotropic_cosserat materials, but the current material-comparison logic in ExpectedMaterials3D::check() won’t validate them (the FOR_EACH_IN_PRODUCT call used for comparison doesn’t enumerate any combinations unless it includes an ATTENUATION_TAG(...) list, and it’s also limited to MEDIUM_TAG(ELASTIC)/PROPERTY_TAG(ISOTROPIC)). Please extend the comparison logic to iterate valid (medium, property, attenuation) combinations and validate Cosserat materials too, otherwise this test can pass without actually checking the computed materials.

Copilot uses AI. Check for mistakes.
Comment thread tests/unit-tests/mesh/dim3/tags.cpp Outdated
Comment on lines +179 to +188
specfem::element::property_tag::isotropic,
specfem::element::attenuation_tag::none,
specfem::element::boundary_tag::none) }) }
specfem::element::boundary_tag::none) }) },

Copilot AI Mar 25, 2026

Copy link

Choose a reason for hiding this comment

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

The surrounding documentation says the EightNodeElastic case “Spot-checks elements 0, 1, and 5”, but the expected tag list now only checks elements 0 and 5. Either re-add the element-1 check (to keep coverage consistent) or update the comment block so it matches what the test actually verifies.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,45 @@
# Snakemake workflow to generate database for 4-node elastic problem in 3D

Copilot AI Mar 25, 2026

Copy link

Choose a reason for hiding this comment

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

The header comment doesn’t match this workflow/test case: it says “4-node elastic problem in 3D”, but this directory is EightNodeElasticCosserat and NGNOD = 8 in the provenance. Please update the comment to avoid confusion when regenerating the database.

Suggested change
# Snakemake workflow to generate database for 4-node elastic problem in 3D
# Snakemake workflow to generate database for 8-node elastic Cosserat problem in 3D

Copilot uses AI. Check for mistakes.
shell:
"echo 'All tasks completed successfully.'"

rule check_executible:

Copilot AI Mar 25, 2026

Copy link

Choose a reason for hiding this comment

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

Typo in the rule name: check_executible should be check_executable (and update any references to it).

Suggested change
rule check_executible:
rule check_executable:

Copilot uses AI. Check for mistakes.
Comment on lines +96 to +101
# define the different materials in the model as:
# #material_id #rho #vp #vs #Q_Kappa #Q_mu #anisotropy_flag #domain_id
# Q_Kappa : Q_Kappa attenuation quality factor
# Q_mu : Q_mu attenuation quality factor
# anisotropy_flag : 0 = no anisotropy / 1,2,... check the implementation in file aniso_model.f90
# domain_id : 1 = acoustic / 2 = elastic

Copilot AI Mar 25, 2026

Copy link

Choose a reason for hiding this comment

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

The material-format comments are now misleading for this Cosserat case. The line defining the material has more fields than the documented “#rho #vp #vs #Q_Kappa #Q_mu #anisotropy_flag #domain_id”, and domain_id is shown as 4 even though the comment says it’s 1=acoustic / 2=elastic. Please update the inline documentation to reflect the Cosserat material parameter layout used here.

Suggested change
# define the different materials in the model as:
# #material_id #rho #vp #vs #Q_Kappa #Q_mu #anisotropy_flag #domain_id
# Q_Kappa : Q_Kappa attenuation quality factor
# Q_mu : Q_mu attenuation quality factor
# anisotropy_flag : 0 = no anisotropy / 1,2,... check the implementation in file aniso_model.f90
# domain_id : 1 = acoustic / 2 = elastic
# define the different materials in the model as (Cosserat elastic case):
# #material_id #rho #vp #vs #Q_Kappa #Q_mu #cosserat_param_1 #cosserat_param_2 #cosserat_param_3 #domain_id
# Q_Kappa : Q_Kappa attenuation quality factor
# Q_mu : Q_mu attenuation quality factor
# cosserat_param_* : additional Cosserat material parameters (see Cosserat model implementation)
# domain_id : 1 = acoustic / 2 = elastic / 4 = elastic Cosserat

Copilot uses AI. Check for mistakes.
@maxlchien maxlchien mentioned this pull request Mar 25, 2026
8 tasks
Co-authored-by: Rohit-Kakodkar <40695390+Rohit-Kakodkar@users.noreply.github.com>
@icui
icui requested review from icui and lsawade March 27, 2026 13:04
@lsawade lsawade linked an issue May 22, 2026 that may be closed by this pull request
Rohit-Kakodkar and others added 17 commits May 26, 2026 09:02
Move stress integrand conversion logic to jacobian inverse
`point::jacobian_matrix` stored a `tensor_type _data` plus public reference
members (`value_type &xix`, ...) aliasing it. Reference members are pointers
into the object's own storage, so the type was not relocatable: after a
byte-wise copy the references still pointed at the source object.

Kokkos bit-copies this type as a `View` element and as the reduction scalar of
`Kokkos::Sum<>` in `algorithms::interpolate_function`. Under a threaded backend
OpenMP accumulates into per-thread reduction scratch and copies out; once that
scratch was freed, reading `.xix` dereferenced freed memory and segfaulted.
Serial accumulates in place, which is why every Serial build passed and only
the OpenMP cells failed.

Option B from the issue: the tensor stays the sole storage and the components
become accessor methods.

  - Drop the reference members; add paired `xix()` / `xix() const` accessors
    (and the rest) that index into the tensor. The hand-written copy
    constructor and copy assignment, which existed only to rebind the
    references, are gone.
  - Make the `jacobian` determinant a private `jacobian_` with a `jacobian()`
    accessor, so the whole component API is uniform.
  - Remove the implicit `operator tensor_type&()` conversions; `tensor()` is
    now the single tensor accessor. Its three users all went through an
    explicit `static_cast` already.
  - Default `RegisterArray`'s copy constructor. The hand-written loop was plain
    memberwise copy of its `T m_value[size]`, and being user-provided was the
    only thing keeping `RegisterArray` (and so the point views) from being
    trivially copyable. Its default constructor is left alone: it
    zero-initializes, which `reduction_identity<T>::sum()` relies on.
  - Add `static_assert(std::is_trivially_copyable_v<...>)` on the point views
    and on all four `jacobian_matrix` specializations, for both SIMD settings.
    This turns the bug class into a compile error on every backend rather than
    a segfault on threaded ones only.

Call sites (~820) are mechanical `.xix` -> `.xix()`. The similarly named
members of the `assembly::jacobian_matrix` container views are untouched.

Add a `release-openmp` preset and a matching CI job, since GitHub CI was
Serial-only. `Kokkos_ENABLE_ATOMICS_BYPASS` is OFF there: it is a
single-thread-only optimization that is ON in every other preset. The job runs
the whole `tests` tree, because the Newmark moment-tensor cases that crashed
are integration tests.

Verified: 1334/1334 tests pass under both `release` (Serial, SIMD) and
`release-openmp` (OMP_NUM_THREADS=4), including the
`ASSEMBLY_NO_LOAD.compute_source_array_from_tensor` repro from the issue.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Follow-up cleanup on fa48cf2. No behavior change.

  - Move the relocatability assert to the choke point. The guard now sits
    next to both `Kokkos::Sum<T>` reductions in `algorithms/interpolate.hpp`
    -- the actual crash site -- so any scalar reduced through that path is
    checked, not just the one type that happened to break.

  - Replace the `#define`/invoke-twice/`#undef` macro in
    `point/jacobian_matrix.hpp` with a `jacobian_matrix_is_relocatable_v`
    variable template, and drop two of the four conjuncts: the
    `store_jacobian = true` specializations derive from the `false` ones,
    and a derived class cannot be trivially copyable unless its bases are.

  - Drop the third copy of the guard in `datatype/register_array.hpp`. It
    hardcoded `RegisterArray<double|float, extents<3,3>, layout_left>`,
    which no production code instantiates directly -- every real
    instantiation reaches it through `TensorPointViewType`, already covered
    by the assert in `point_view.hpp`.

  - `jacobian_matrix::init()` re-listed all 4 / all 9 components; the tensor
    is the sole storage now and `RegisterArray()` zero-fills, so both bodies
    become `_data = tensor_type()`.

  - `operator==` cast to `base_type` by value, slicing two base temporaries
    per comparison. Now casts to `const base_type &`.

  - `release-openmp` restated 11 cache variables that `release-nosimd`
    already provides; it now `inherits` it plus its four genuine deltas
    (Serial off, OpenMP on, ATOMICS_BYPASS off, benchmarks dir). Verified
    against the reconfigured cache that all inherited values are unchanged.

  - Collapse the 6-branch face dispatch in `locate_point/dim3` to 3.
    bottom/top returned byte-identical 8-tuples, as did left/right and
    front/back; only the constrained coordinate's sign differed. Now a
    ternary on the sign, matching the shape `project_onto_surface.cpp`
    already uses.

Verified: `release-openmp` builds clean and 1334/1334 tests pass under
OMP_NUM_THREADS=4, including the `compute_source_array_from_tensor` repro.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
actions/checkout@v1 is deprecated. Bump the remaining usages in the
build and unittest workflows so all workflows are consistently on v4.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
jacobian_matrix.hpp and point_view.hpp use std::is_trivially_copyable_v
in their static_asserts but only got <type_traits> transitively. Include
it explicitly so the guards don't break if those transitive includes change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…-matrix-relocatable

Make point::jacobian_matrix relocatable (fixes #2008)
@codecov-commenter

codecov-commenter commented Aug 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 68.90034% with 181 lines in your changes missing coverage. Please review.
✅ Project coverage is 63.08%. Comparing base (1853fa7) to head (6fbece6).
⚠️ Report is 2 commits behind head on devel.

Files with missing lines Patch % Lines
core/specfem/point/jacobian_matrix.hpp 58.70% 53 Missing and 11 partials ⚠️
...ource/dim3/vector_source/cosserat_force_source.cpp 40.00% 24 Missing and 12 partials ⚠️
...e/specfem/io/seismogram/impl/channel_generator.cpp 0.00% 21 Missing and 6 partials ⚠️
...orithms/locate_point/dim3/project_onto_surface.cpp 33.33% 12 Missing ⚠️
...ource/dim3/vector_source/cosserat_force_source.hpp 61.29% 12 Missing ⚠️
...specfem/source/dim3/vector_source/force_source.cpp 38.46% 8 Missing ⚠️
...ecfem/io/mesh/impl/fortran/dim3/read_materials.cpp 79.31% 4 Missing and 2 partials ⚠️
...algorithms/locate_point/dim3/locate_point_impl.cpp 90.24% 4 Missing ⚠️
...embly/dim2/compute_wavefield/compute_wavefield.cpp 0.00% 3 Missing ⚠️
...algorithms/locate_point/dim2/locate_point_impl.cpp 75.00% 2 Missing ⚠️
... and 5 more
Additional details and impacted files
@@            Coverage Diff             @@
##            devel    #1753      +/-   ##
==========================================
+ Coverage   62.85%   63.08%   +0.22%     
==========================================
  Files         489      498       +9     
  Lines       20127    20534     +407     
  Branches     2615     2643      +28     
==========================================
+ Hits        12651    12953     +302     
- Misses       6621     6709      +88     
- Partials      855      872      +17     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

… in 3D.

I'm not sure whether this will fix the errors max is seeing. But one thing at a time.
- Creates the same mesh and plots seismograms.
- There are no reference seismograms at the moment. @maxlchien could maybe add them
Issue 2061 - Update field selection and allocation for the cosserat related fields
@lsawade

lsawade commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

I accidentally merged #2067 that was not on purpose! CI tests will run and I'll fix them when they come in.

Copilot AI and others added 6 commits August 24, 2026 19:36
Co-authored-by: lsawade <23224303+lsawade@users.noreply.github.com>
Add Cosserat integration test, and update stress reconstruction for 3D gather kernel
Add reference seismograms and update plotter for Cosserat benchmark
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new physics This labels the introduction of new physics to the code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement 3D Cosserat Media

7 participants