Skip to content
60 changes: 60 additions & 0 deletions src/coreComponents/constitutive/solid/ElasticIsotropic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ ElasticIsotropic::ElasticIsotropic( string const & name, Group * const parent ):
registerField< fields::solid::bulkModulus >( &m_bulkModulus );

registerField< fields::solid::shearModulus >( &m_shearModulus );

registerField< fields::solid::youngModulus >( &m_youngModulus );

registerField< fields::solid::poissonRatio >( &m_poissonRatio );
Comment thread
dkachuma marked this conversation as resolved.
}

void ElasticIsotropic::postInputInitialization()
Expand Down Expand Up @@ -147,6 +151,62 @@ void ElasticIsotropic::postInputInitialization()
setApplyDefaultValue( m_defaultShearModulus );
}

void ElasticIsotropic::initializePostInitialConditionsPreSubGroups()
{
SolidBase::initializePostInitialConditionsPreSubGroups();

// If per-cell Young's modulus and Poisson's ratio were imported from an external mesh
// (indicated by youngModulus[k] > 0 and poissonRatio[k] in (-0.5, 0.5)),
// convert them to bulk and shear modulus on a cell-by-cell basis.
Comment on lines +155 to +160

Copilot AI Apr 14, 2026

Copy link

Choose a reason for hiding this comment

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

New per-cell E/ν import/conversion logic isn’t covered by existing ElasticIsotropic unit tests (they currently validate allocation and constant-K/G stress updates). Adding a unit test that sets per-cell youngModulus/poissonRatio (including invalid/missing values) and verifies the resulting bulk/shear (and back-computed E/ν) would help prevent regressions.

Copilot uses AI. Check for mistakes.
arrayView1d< real64 const > const youngMod = m_youngModulus;
arrayView1d< real64 const > const nu = m_poissonRatio;
arrayView1d< real64 > const bulkMod = m_bulkModulus;
arrayView1d< real64 > const shearMod = m_shearModulus;

localIndex numConverted = 0;
localIndex numInvalidE = 0;

for( localIndex k = 0; k < m_youngModulus.size(); ++k )
{
// youngModulus default is 0: negative values are invalid, zero means not imported
if( youngMod[k] < 0.0 )
{
GEOS_WARNING( GEOS_FMT( "ElasticIsotropic '{}': element {} has negative Young's modulus ({:.6e}). "
Comment thread
dkachuma marked this conversation as resolved.
Outdated
"Skipping per-cell conversion; default bulk/shear modulus will be used.",
getName(), k, youngMod[k] ) );
++numInvalidE;
continue;
}

// youngModulus default is 0: not imported — skip silently
if( !( youngMod[k] > 0.0 ) )
continue;

// E was imported and is positive: nu must also be valid
GEOS_ERROR_IF( nu[k] <= -0.5 || nu[k] >= 0.5,

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.

For most common materials, Poisson’s ratio falls within the range of 0 to 0.5.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I agree with you, but there was some checks already done around line 80-84 that were with this range :

  if( nu > -0.5 && nu < 0.5 )
  {
    ++numConstantsSpecified;
    errorCheck += "nu, ";
  }

So I kept them as it is.

GEOS_FMT( "ElasticIsotropic '{}': element {} has Young's modulus imported ({:.6e}) "
"but Poisson's ratio ({:.6f}) is outside the valid range (-0.5, 0.5). "
"Both youngModulus and poissonRatio must be provided together.",
getName(), k, youngMod[k], nu[k] ) );

bulkMod[k] = conversions::youngModAndPoissonRatio::toBulkMod( youngMod[k], nu[k] );
shearMod[k] = conversions::youngModAndPoissonRatio::toShearMod( youngMod[k], nu[k] );
++numConverted;
}

GEOS_WARNING_IF( numInvalidE > 0,
Comment thread
dkachuma marked this conversation as resolved.
Outdated
GEOS_FMT( "ElasticIsotropic '{}': {} element(s) had non-positive Young's modulus and were skipped.",
getName(), numInvalidE ) );

// Back-compute E and nu for all cells from the final K/G so that output fields are meaningful
// for both imported and default cells.
for( localIndex k = 0; k < m_bulkModulus.size(); ++k )
{
m_youngModulus[k] = conversions::bulkModAndShearMod::toYoungMod( bulkMod[k], shearMod[k] );
m_poissonRatio[k] = conversions::bulkModAndShearMod::toPoissonRatio( bulkMod[k], shearMod[k] );
}
}

REGISTER_CATALOG_ENTRY( ConstitutiveBase, ElasticIsotropic, string const &, Group * const )
}
} /* namespace geos */
9 changes: 9 additions & 0 deletions src/coreComponents/constitutive/solid/ElasticIsotropic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,9 @@ class ElasticIsotropic : public SolidBase
/// Post-process XML data
virtual void postInputInitialization() override;

/// Convert per-cell Young's modulus / Poisson's ratio to bulk / shear modulus if imported from mesh
virtual void initializePostInitialConditionsPreSubGroups() override;

/// The default value of the bulk modulus for any new allocations.
real64 m_defaultBulkModulus;

Expand All @@ -585,6 +588,12 @@ class ElasticIsotropic : public SolidBase
/// The shear modulus for each upper level dimension (i.e. cell) of *this
array1d< real64 > m_shearModulus;

/// Young's modulus per cell (optional; used only when imported from an external mesh)
array1d< real64 > m_youngModulus;

/// Poisson's ratio per cell (optional; used only when imported from an external mesh)
array1d< real64 > m_poissonRatio;

};

} /* namespace constitutive */
Expand Down
16 changes: 16 additions & 0 deletions src/coreComponents/constitutive/solid/SolidFields.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,22 @@ DECLARE_FIELD( shearModulus,
WRITE_AND_READ,
"Shear modulus" );

DECLARE_FIELD( youngModulus,
"youngModulus",
array1d< real64 >,
0,
NOPLOT,
WRITE_AND_READ,
"Young's modulus (per-cell, used when imported from external mesh; converted to bulk/shear modulus at initialization)" );

DECLARE_FIELD( poissonRatio,
"poissonRatio",
array1d< real64 >,
0,
NOPLOT,
WRITE_AND_READ,
"Poisson's ratio (per-cell, used when imported from external mesh; converted to bulk/shear modulus at initialization)" );

DECLARE_FIELD( biotCoefficient,
"biotCoefficient",
array1d< real64 >,
Expand Down
Loading