Skip to content

Commit

Permalink
Merge pull request #179 from UCBoulder/feat/add-subcycling-option
Browse files Browse the repository at this point in the history
Feat/add subcycling option
  • Loading branch information
NateAM authored Oct 10, 2024
2 parents c7a77bc + 94e902a commit f2dc1cb
Show file tree
Hide file tree
Showing 6 changed files with 539 additions and 66 deletions.
1 change: 1 addition & 0 deletions docs/sphinx/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ New Features
- Added a relaxed solver as the default (:pull:`172`). By `Nathan Miller`_.
- Added ability to turn on additional messages for failed solves (:pull:`177`). By `Nathan Miller`_.
- Added the ability to scale the incoming load information by a scale factor (:pull:`178`). By `Nathan Miller`_.
- Added the ability to sub-cycle the analysis to try and improve convergence (:pull:`179`). By `Nathan Miller`_.

Internal Changes
================
Expand Down
194 changes: 186 additions & 8 deletions src/cpp/tardigrade_hydra.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ namespace tardigradeHydra{
const unsigned int maxLSIterations, const floatType lsAlpha,
const bool use_preconditioner, const unsigned int preconditioner_type ) : _dimension( dimension ),
_configuration_unknown_count( configuration_unknown_count ),
_stress_size( configuration_unknown_count ),
_time( time ), _deltaTime( deltaTime ),
_temperature( temperature ), _previousTemperature( previousTemperature ),
_deformationGradient( deformationGradient ),
Expand Down Expand Up @@ -224,22 +225,19 @@ namespace tardigradeHydra{

}

void hydraBase::decomposeUnknownVector( ){
void hydraBase::updateConfigurationsFromUnknownVector( ){
/*!
* Decompose the unknown vector into the cauchy stress, configurations, and state variables used for the non-linear solve
* Update the configurations from the unknown vector
*/

const floatVector *unknownVector = getUnknownVector( );

// Set the stress
extractStress( );

// Set the configurations
auto configurations = get_setDataStorage_configurations( );

auto inverseConfigurations = get_setDataStorage_inverseConfigurations( );

computeConfigurations( unknownVector, getStress( )->size( ), *getDeformationGradient( ), *configurations.value, *inverseConfigurations.value );
computeConfigurations( unknownVector, *getStressSize( ), *getDeformationGradient( ), *configurations.value, *inverseConfigurations.value );

// Extract the remaining state variables required for the non-linear solve
auto nonLinearSolveStateVariables = get_setDataStorage_nonLinearSolveStateVariables( );
Expand All @@ -254,6 +252,18 @@ namespace tardigradeHydra{

}

void hydraBase::decomposeUnknownVector( ){
/*!
* Decompose the unknown vector into the cauchy stress, configurations, and state variables used for the non-linear solve
*/

// Set the stress
extractStress( );

updateConfigurationsFromUnknownVector( );

}

void hydraBase::decomposeStateVariableVector( ){
/*!
* Decompose the incoming state variable vector setting the different configurations along the way
Expand Down Expand Up @@ -2034,9 +2044,177 @@ namespace tardigradeHydra{

}

void hydraBase::evaluate( ){
void hydraBase::setScaledQuantities( ){
/*!
* Set the scaled quantities
*/

_scaled_time = ( _scale_factor - 1 ) * _deltaTime + _time;

_scaled_deltaTime = _scale_factor * _deltaTime;

_scaled_temperature = _scale_factor * ( _temperature - _previousTemperature ) + _previousTemperature;

_scaled_deformationGradient = _scale_factor * ( _deformationGradient - _previousDeformationGradient ) + _previousDeformationGradient;

_scaled_additionalDOF = _scale_factor * ( _additionalDOF - _previousAdditionalDOF ) + _previousAdditionalDOF;

}

void hydraBase::setScaleFactor( const floatType &value ){
/*!
* Set the value of the scale factor. Will automatically re-calculate the deformation and trial stresses
*
* \param &value: The value of the scale factor
*/

// Update the scale factor
_scale_factor = value;

// Update the scaled quantities
setScaledQuantities( );

// Copy the current unknown vector
floatVector unknownVector = *getUnknownVector( );

// Reset the iteration data
resetIterationData( );

// Set the unknown vector
setX( unknownVector );

// Update the deformation quantities
updateConfigurationsFromUnknownVector( );

// Compute the new trial stress
std::copy( getStress( )->begin( ), getStress( )->end( ), unknownVector.begin( ) );

// Re-set the unknown vector
setX( unknownVector );

// Extract the stress
extractStress( );

}

const bool hydraBase::allowStepGrowth( const unsigned int &num_good ){
/*!
* Function to determine if we can increase the step-size for the sub-cycler
*
* \param &num_good: The number of good increments since the last failure
*/

if ( num_good >= ( *getNumGoodControl( ) ) ){

return true;

}

return false;

}

void hydraBase::evaluate( const bool &use_subcycler ){
/*!
* Solver the non-linear problem and update the variables
*
* \param &use_subcycler: Flag for if the subcycler should be used for difficult analyses (defaults to false)
*/

try{

evaluateInternal( );

return;

}
catch( std::exception &e ){

if ( !use_subcycler ){

throw;

}

if ( ( *getFailureVerbosityLevel( ) ) > 0 ){
addToFailureOutput( "\n\n" );
addToFailureOutput( "#########################################\n" );
addToFailureOutput( "### ENTERING SUB-CYCLER ###\n" );
addToFailureOutput( "#########################################\n" );
addToFailureOutput( "\n\n" );
}

floatType sp = 0.0;

floatType ds = ( *getCutbackFactor( ) );

unsigned int num_good = 0;

// Set the unknown vector to the initial unknown. We're using setX because we call setScaleFactor right away which will update the unknown vector
setX( _initialX );

while ( sp < 1.0 ){

try{

if ( ( *getFailureVerbosityLevel( ) ) > 0 ){
addToFailureOutput( "\n\n" );
addToFailureOutput( "######### PSEUDO-TIME INCREMENT #########\n" );
addToFailureOutput( "\n\n sp, ds: " + std::to_string( sp ) + ", " + std::to_string( ds ) );
addToFailureOutput( "\n" );
}

setScaleFactor( sp + ds ); // Update the scaling factor

resetIterations( ); // Reset the non-linear iteration count

evaluateInternal( ); // Try to solve the non-linear problem

sp += ds; // Update the pseudo-time

num_good++; // Update the number of good iterations

// Grow the step if possible
if ( allowStepGrowth( num_good ) ){

ds *= ( *getGrowthFactor( ) );

}

// Make sure s will be less than or equal to 1
if ( sp + ds > 1.0 ){

ds = 1.0 - sp;

}

}
catch( std::exception &e ){

// Reduce the time-step and try again
num_good = 0;

ds *= ( *getCutbackFactor( ) );

setX( _initialX ); // Reset X to the last good point

if ( ds < *getMinDS( ) ){

throw;

}

}

}

}

}

void hydraBase::evaluateInternal( ){
/*!
* Solve the non-linear problem and update the variables
* Solve the non-linear problem with the current scaling and update the variables
*/

// Reset the counters for the number of steps being performed
Expand Down
55 changes: 39 additions & 16 deletions src/cpp/tardigrade_hydra.h
Original file line number Diff line number Diff line change
Expand Up @@ -1080,6 +1080,9 @@ namespace tardigradeHydra{
//! Get a reference to the number of unknowns in each configuration
const unsigned int* getConfigurationUnknownCount( ){ return &_configuration_unknown_count; }

//! Get a reference to the number of components of the stress
const unsigned int* getStressSize( ){ return &_stress_size; }

//! Get a reference to the current time
const floatType* getTime( ){ return getScaledTime( ); }

Expand Down Expand Up @@ -1413,7 +1416,7 @@ namespace tardigradeHydra{

const floatVector* getPreviousStress( );

virtual void evaluate( );
virtual void evaluate( const bool &use_subcycler = false );

virtual void computeTangents( );

Expand Down Expand Up @@ -1494,8 +1497,8 @@ namespace tardigradeHydra{
//! Get a scale factor for the deformation
const floatType *getScaleFactor( ){ return &_scale_factor; }

//! Set the value of the scale factor. Will automatically re-calculate the deformation
const void setScaleFactor( const floatType &value ){ _scale_factor = value; setScaledQuantities( ); updateUnknownVector( *getUnknownVector( ) ); }
//! Set the value of the scale factor. Will automatically re-calculate the deformation and trial stresses
void setScaleFactor( const floatType &value );

const floatType *getScaledTime( ){ return &_scaled_time; }

Expand All @@ -1507,6 +1510,24 @@ namespace tardigradeHydra{

const floatVector *getScaledAdditionalDOF( ){ return &_scaled_additionalDOF; }

const floatType *getCutbackFactor( ){ return &_cutback_factor; }

const unsigned int *getNumGoodControl( ){ return &_num_good_control; }

const floatType *getGrowthFactor( ){ return &_growth_factor; }

const floatType *getMinDS( ){ return &_minDS; }

void setCutbackFactor( const floatType &value ){ _cutback_factor = value; }

void setNumGoodControl( const unsigned int &value ){ _num_good_control = value; }

void setGrowthFactor( const floatType &value ){ _growth_factor = value; }

void setMinDS( const floatType &value ){ _minDS = value; }

const bool allowStepGrowth( const unsigned int &num_good );

protected:

// Setters that the user may need to access but not override
Expand All @@ -1521,6 +1542,8 @@ namespace tardigradeHydra{

virtual void extractStress( );

virtual void updateConfigurationsFromUnknownVector( );

virtual void decomposeUnknownVector( );

virtual void decomposeStateVariableVector( );
Expand All @@ -1541,6 +1564,8 @@ namespace tardigradeHydra{

virtual void initializePreconditioner( );

virtual void evaluateInternal( );

//! Update the line-search lambda parameter
virtual void updateLambda( ){ _lambda *= 0.5; }

Expand All @@ -1553,19 +1578,7 @@ namespace tardigradeHydra{
virtual void performGradientStep( const floatVector &X0 );

//! Update the scaled quantities
virtual void setScaledQuantities( ){

_scaled_time = ( _scale_factor - 1 ) * _deltaTime + _time;

_scaled_deltaTime = _scale_factor * _deltaTime;

_scaled_temperature = _scale_factor * ( _temperature - _previousTemperature ) + _previousTemperature;

_scaled_deformationGradient = _scale_factor * ( _deformationGradient - _previousDeformationGradient ) + _previousDeformationGradient;

_scaled_additionalDOF = _scale_factor * ( _additionalDOF - _previousAdditionalDOF ) + _previousAdditionalDOF;

}
virtual void setScaledQuantities( );

const floatType *get_baseResidualNorm( );

Expand Down Expand Up @@ -1776,6 +1789,8 @@ namespace tardigradeHydra{

unsigned int _configuration_unknown_count; //!< The number of unknowns required for a configuration. Used to ensure that the unknown and state variable vectors are the right size. Must be set by all inheriting classes. For 3D classical continuum this will be 9, for higher order theories this will change.

unsigned int _stress_size; //!< The number of terms in the stress measures. For 3D classical continuum this will be 9, for higher order theories this will change.

floatType _time; //!< The current time

floatType _deltaTime; //!< The change in time
Expand Down Expand Up @@ -1948,6 +1963,14 @@ namespace tardigradeHydra{

floatType _scale_factor = 1.0; //!< A scale factor applied to the incoming loading (deformation, temperature, etc.)

floatType _cutback_factor = 0.5; //!< The factor by which the pseudo-time will be scaled if a solve fails

floatType _growth_factor = 1.2; //!< The factor by which the pseudo-time will be scaled if we can grow the pseudo-timestep

unsigned int _num_good_control = 2; //!< The number of good iterations we need to have before we try and increase the timestep

floatType _minDS = 1e-2; //!< The minimum allowable pseudo-timestep

TARDIGRADE_HYDRA_DECLARE_ITERATION_STORAGE( private, configurations, floatVector, passThrough )

TARDIGRADE_HYDRA_DECLARE_PREVIOUS_STORAGE( private, previousConfigurations, floatVector, passThrough )
Expand Down
Loading

0 comments on commit f2dc1cb

Please sign in to comment.