Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plasticity #142

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
fb03874
Initial compact test example
pabloseleson Oct 22, 2024
1b13ed8
Add initial plasticity model
streeve Sep 23, 2024
9980d18
fixup: fracture inheritance
streeve Jan 27, 2025
465f2ca
Updated compact tension test example
pabloseleson Jan 27, 2025
a3145c8
Updated json file for compact tension test example
pabloseleson Jan 28, 2025
9ae4de2
Add plastic bond stretch array;
streeve Jan 23, 2025
31355b9
fixup: example
streeve Jan 28, 2025
8e5a5e9
fixup: missing model api change
streeve Jan 28, 2025
97025af
Minor changes to compact tension test example
pabloseleson Jan 28, 2025
cec79fd
fixup: plastic energy
streeve Jan 28, 2025
61d6ce6
fixup: missing particle creation function
streeve Jan 28, 2025
8d38783
Making factor floating-point
pabloseleson Jan 28, 2025
6256e28
fixup: mistake in permanent stretch type
streeve Jan 29, 2025
9303619
fixup: remove plastic+no-fracture for now
streeve Jan 29, 2025
e44d61b
fixup: revert unrelated change
streeve Jan 29, 2025
a900585
Small edit on comment
pabloseleson Jan 29, 2025
a7a8c61
fixup: tension test regions and BC
streeve Jan 29, 2025
5a8f395
Revised comments
pabloseleson Jan 29, 2025
bec7020
Changed notation for platic stretch: s_0 to s_p
pabloseleson Jan 29, 2025
6713247
fixup: add yield stress input
streeve Jan 29, 2025
1c52911
fixup: clarify plastic force update
streeve Jan 29, 2025
67820d2
fixup: rename mistake
streeve Jan 29, 2025
2f27e5b
fixup: modify critical stretch for plasticity
streeve Jan 29, 2025
8554840
Adding yield stress to compact tension test example
pabloseleson Jan 29, 2025
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
5 changes: 4 additions & 1 deletion examples/mechanics/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@ target_link_libraries(FragmentingCylinder LINK_PUBLIC CabanaPD)
add_executable(RandomCracks random_cracks.cpp)
target_link_libraries(RandomCracks LINK_PUBLIC CabanaPD)

install(TARGETS ElasticWave KalthoffWinkler CrackBranching FragmentingCylinder RandomCracks DESTINATION ${CMAKE_INSTALL_BINDIR})
add_executable(CompactTensionTest compact_tension_test.cpp)
target_link_libraries(CompactTensionTest LINK_PUBLIC CabanaPD)

install(TARGETS ElasticWave KalthoffWinkler CrackBranching FragmentingCylinder RandomCracks CompactTensionTest DESTINATION ${CMAKE_INSTALL_BINDIR})
203 changes: 203 additions & 0 deletions examples/mechanics/compact_tension_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
/****************************************************************************
* Copyright (c) 2022 by Oak Ridge National Laboratory *
* All rights reserved. *
* *
* This file is part of CabanaPD. CabanaPD is distributed under a *
* BSD 3-clause license. For the licensing terms see the LICENSE file in *
* the top-level directory. *
* *
* SPDX-License-Identifier: BSD-3-Clause *
****************************************************************************/

#include <fstream>
#include <iostream>

#include "mpi.h"

#include <Kokkos_Core.hpp>

#include <CabanaPD.hpp>

// Simulate crack propagation in a compact tension test.
void crackBranchingExample( const std::string filename )
streeve marked this conversation as resolved.
Show resolved Hide resolved
{
// ====================================================
// Use default Kokkos spaces
pabloseleson marked this conversation as resolved.
Show resolved Hide resolved
// ====================================================
using exec_space = Kokkos::DefaultExecutionSpace;
using memory_space = typename exec_space::memory_space;

// ====================================================
// Read inputs
// ====================================================
CabanaPD::Inputs inputs( filename );

// ====================================================
// Material parameters
// ====================================================
double rho0 = inputs["density"];
double E = inputs["elastic_modulus"];
double nu = 0.25; // Use bond-based model
double K = E / ( 3 * ( 1 - 2 * nu ) );
double G0 = inputs["fracture_energy"];
double delta = inputs["horizon"];
delta += 1e-10;

// ====================================================
// Discretization
// ====================================================
// FIXME: set halo width based on delta
pabloseleson marked this conversation as resolved.
Show resolved Hide resolved
std::array<double, 3> low_corner = inputs["low_corner"];
std::array<double, 3> high_corner = inputs["high_corner"];

// ====================================================
// Pre-notch
// ====================================================
double height = inputs["system_size"][0];
double thickness = inputs["system_size"][2];
double L_prenotch = height / 2.0;
double y_prenotch1 = 0.0;
Kokkos::Array<double, 3> p01 = { low_corner[0], y_prenotch1,
low_corner[2] };
Kokkos::Array<double, 3> v1 = { L_prenotch, 0, 0 };
Kokkos::Array<double, 3> v2 = { 0, 0, thickness };
Kokkos::Array<Kokkos::Array<double, 3>, 1> notch_positions = { p01 };
CabanaPD::Prenotch<1> prenotch( v1, v2, notch_positions );

// ====================================================
// Force model
// ====================================================
using model_type =
CabanaPD::ForceModel<CabanaPD::PMB, CabanaPD::ElasticPerfectlyPlastic>;
model_type force_model( delta, K, G0 );

// ====================================================
// Particle generation
// ====================================================
// Note that individual inputs can be passed instead (see other examples).
auto particles = CabanaPD::createParticles<memory_space, model_type>(
exec_space{}, inputs );

// ====================================================
// Custom particle generation and initialization
// ====================================================

// Rectangular prism containing the full specimen: original geometry
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should never do this - if we need every particle considered, it should use a body term

CabanaPD::RegionBoundary<CabanaPD::RectangularPrism> plane(
low_corner[0], high_corner[0], low_corner[1], high_corner[1],
low_corner[2], high_corner[2] );
std::vector<CabanaPD::RegionBoundary<CabanaPD::RectangularPrism>> planes = {
pabloseleson marked this conversation as resolved.
Show resolved Hide resolved
plane };

// Geometric parameters of specimen
double L = inputs["system_size"][1];
double W = L / 1.25;
double a = 0.45 * W;

// Grid spacing in y-direction
double dy = particles->dx[1];

// Remove particles from original geometry
Copy link
Collaborator

Choose a reason for hiding this comment

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

Not technically true, the other particles are never created

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

How about "// Do not create particles outside compact tension test specimen region"?

This would be consistent with the fragmenting cylinder example? We say there "// Do not create particles outside given cylindrical region"

auto init_op = KOKKOS_LAMBDA( const int, const double x[3] )
{
// Thin rectangle
if ( x[0] < low_corner[1] + 0.25 * W + a &&
Kokkos::abs( x[1] ) < 0.5 * dy )
{
return false;
}
// Thick rectangle
else if ( x[0] < low_corner[1] + 0.25 * W &&
Kokkos::abs( x[1] ) < 25e-4 )
{
return false;
}
else
{
return true;
}
};

particles->createParticles( exec_space(), init_op );
streeve marked this conversation as resolved.
Show resolved Hide resolved

auto rho = particles->sliceDensity();
auto x = particles->sliceReferencePosition();
auto v = particles->sliceVelocity();
auto f = particles->sliceForce();
streeve marked this conversation as resolved.
Show resolved Hide resolved
auto nofail = particles->sliceNoFail();

// Pin radius
double R = 4e-3;
// Pin center coordinates (top)
double x_pin = low_corner[0] + 0.25 * W;
double y_pin = 0.37 * W;
// Pin velocity magnitude
double v0 = inputs["pin_velocity"];

auto init_functor = KOKKOS_LAMBDA( const int pid )
{
// Density
rho( pid ) = rho0;

auto xpos = x( pid, 0 );
auto ypos = x( pid, 1 );
auto distsq =
( xpos - x_pin ) * ( xpos - x_pin ) +
( Kokkos::abs( ypos ) - y_pin ) * ( Kokkos::abs( ypos ) - y_pin );
auto sign = Kokkos::abs( ypos ) / ypos;

// pins' y-velocity
if ( distsq < R * R )
v( pid, 1 ) = sign * v0;

// No-fail zone
if ( distsq < ( 2 * R ) * ( 2 * R ) )
pabloseleson marked this conversation as resolved.
Show resolved Hide resolved
nofail( pid ) = 1;
};
particles->updateParticles( exec_space{}, init_functor );

// ====================================================
// Create solver
// ====================================================
auto cabana_pd =
CabanaPD::createSolver<memory_space>( inputs, particles, force_model );

// ====================================================
// Boundary conditions
// ====================================================

// Create BC last to ensure ghost particles are included.
f = particles->sliceForce();
x = particles->sliceReferencePosition();
// Create a symmetric force BC in the y-direction.
auto bc_op = KOKKOS_LAMBDA( const int pid, const double )
{
auto xpos = x( pid, 0 );
auto ypos = x( pid, 1 );
if ( ( xpos - x_pin ) * ( xpos - x_pin ) +
( Kokkos::abs( ypos ) - y_pin ) *
( Kokkos::abs( ypos ) - y_pin ) <
R * R )
f( pid, 1 ) = 0;
};
auto bc = createBoundaryCondition( bc_op, exec_space{}, *particles, planes,
true );

// ====================================================
// Simulation run
// ====================================================
cabana_pd->init( prenotch );
cabana_pd->run( bc );
}

// Initialize MPI+Kokkos.
int main( int argc, char* argv[] )
{
MPI_Init( &argc, &argv );
Kokkos::initialize( argc, argv );

crackBranchingExample( argv[1] );

Kokkos::finalize();
MPI_Finalize();
}
15 changes: 15 additions & 0 deletions examples/mechanics/inputs/compact_tension_test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"num_cells" : {"value": [187, 181, 15]},
"system_size" : {"value": [0.12625, 0.1212, 0.01], "unit": "m"},
"density" : {"value": 2440, "unit": "kg/m^3"},
"elastic_modulus" : {"value": 72.6e+9, "unit": "Pa"},
"fracture_energy" : {"value": 16160, "unit": "J/m^2"},
"horizon" : {"value": 0.00203, "unit": "m"},
"yield_stretch" : {"value": 304e6, "unit": "Pa"},
"pin_velocity" : {"value": 7.15e6, "unit": "m/s"},
"final_time" : {"value": 43e-6, "unit": "s"},
"timestep" : {"value": 4.5e-8, "unit": "s"},
"timestep_safety_factor" : {"value": 0.85},
"output_frequency" : {"value": 5},
"output_reference" : {"value": true}
}
3 changes: 3 additions & 0 deletions src/CabanaPD_Types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ struct is_fracture<Fracture> : public std::true_type
struct Elastic
{
};
struct ElasticPerfectlyPlastic
{
};

// Contact and DEM (contact without PD) tags.
struct NoContact
Expand Down
101 changes: 101 additions & 0 deletions src/force/CabanaPD_ForceModels_PMB.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,60 @@ struct ForceModel<PMB, Elastic, NoFracture, TemperatureIndependent>
}
};

template <>
struct ForceModel<PMB, ElasticPerfectlyPlastic, NoFracture,
streeve marked this conversation as resolved.
Show resolved Hide resolved
TemperatureIndependent>
: public ForceModel<PMB, Elastic, NoFracture, TemperatureIndependent>
{
using base_type = ForceModel<PMB, Elastic, NoFracture>;
using base_model = PMB;
using fracture_type = NoFracture;
using plasticity_type = ElasticPerfectlyPlastic;
using thermal_type = TemperatureIndependent;

using base_type::c;
using base_type::delta;
using base_type::K;
// FIXME: hardcoded
const double s_Y = 0.0014;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We need this to computer based on the yield stress.


ForceModel( const double delta, const double K )
: base_type( delta, K )
{
}

KOKKOS_INLINE_FUNCTION
auto forceCoeff( const double s, const double vol ) const
{
if ( s < s_Y )
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We will need to write 93-96 just as as:

        return c * ( s - s_0) * vol;

Copy link
Collaborator

Choose a reason for hiding this comment

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

As we discussed this will not work in the current setup and isn't worth updating right now - I've removed for now

return c * s * vol;
else
return c * s_Y * vol;
}

KOKKOS_INLINE_FUNCTION
auto energy( const double s, const double xi, const double vol ) const
{
double stretch_term = 0.0;
streeve marked this conversation as resolved.
Show resolved Hide resolved
if ( s < s_Y )
streeve marked this conversation as resolved.
Show resolved Hide resolved
stretch_term = s * s;
else
stretch_term = s_Y * ( 2 * s - s_Y );

// 0.25 factor is due to 1/2 from outside the integral and 1/2 from
// the integrand (pairwise potential).
return 0.25 * c * stretch_term * xi * vol;
}
};

template <>
struct ForceModel<PMB, Elastic, Fracture, TemperatureIndependent>
: public ForceModel<PMB, Elastic, NoFracture, TemperatureIndependent>
{
using base_type = ForceModel<PMB, Elastic, NoFracture>;
using base_model = typename base_type::base_model;
using fracture_type = Fracture;
using mechanics_type = Elastic;
using thermal_type = base_type::thermal_type;

using base_type::c;
Expand All @@ -88,13 +135,65 @@ struct ForceModel<PMB, Elastic, Fracture, TemperatureIndependent>
}
};

template <>
struct ForceModel<PMB, ElasticPerfectlyPlastic, Fracture,
TemperatureIndependent>
: public ForceModel<PMB, Elastic, Fracture, TemperatureIndependent>
{
using base_type = ForceModel<PMB, Elastic>;
using base_model = typename base_type::base_model;
using fracture_type = Fracture;
using mechanics_type = ElasticPerfectlyPlastic;
using thermal_type = base_type::thermal_type;

// Purposely not using the (static) base class bond_break_coeff
using base_type::c;
using base_type::delta;
using base_type::G0;
using base_type::K;
using base_type::s0;

// FIXME: hardcoded
Copy link
Collaborator Author

@pabloseleson pabloseleson Jan 29, 2025

Choose a reason for hiding this comment

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

s_Y needs to be computed from the yield stress \sigma_Y. The relation is:

Untitled

where K is the bulk modulus.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Done

const double s_Y = 0.0014;

ForceModel( const double delta, const double K, const double G0 )
: base_type( delta, K, G0 )
{
}

// FIXME: avoiding multiple inheritance..
KOKKOS_INLINE_FUNCTION
auto forceCoeff( const double s, const double vol ) const
{
if ( s < s_Y )
return c * s * vol;
else
return c * s_Y * vol;
}

KOKKOS_INLINE_FUNCTION
auto energy( const double s, const double xi, const double vol ) const
{
double stretch_term = 0.0;
if ( s < s_Y )
stretch_term = s * s;
else
stretch_term = s_Y * ( 2 * s - s_Y );

// 0.25 factor is due to 1/2 from outside the integral and 1/2 from
// the integrand (pairwise potential).
return 0.25 * c * stretch_term * xi * vol;
}
};

template <>
struct ForceModel<LinearPMB, Elastic, NoFracture, TemperatureIndependent>
: public ForceModel<PMB, Elastic, NoFracture, TemperatureIndependent>
{
using base_type = ForceModel<PMB, Elastic, NoFracture>;
using base_model = typename base_type::base_model;
using fracture_type = typename base_type::fracture_type;
using mechanics_type = Elastic;
using thermal_type = base_type::thermal_type;

using base_type::base_type;
Expand All @@ -111,6 +210,7 @@ struct ForceModel<LinearPMB, Elastic, Fracture, TemperatureIndependent>
using base_type = ForceModel<PMB>;
using base_model = typename base_type::base_model;
using fracture_type = typename base_type::fracture_type;
using mechanics_type = Elastic;
using thermal_type = base_type::thermal_type;

using base_type::base_type;
Expand Down Expand Up @@ -187,6 +287,7 @@ struct ForceModel<PMB, Elastic, Fracture, TemperatureDependent, TemperatureType>
using base_temperature_type = BaseTemperatureModel<TemperatureType>;
using base_model = typename base_type::base_model;
using fracture_type = typename base_type::fracture_type;
using mechanics_type = Elastic;
using thermal_type = TemperatureDependent;

using base_type::c;
Expand Down
Loading
Loading