Skip to content

Commit

Permalink
Merge branch 'main' into current_positions
Browse files Browse the repository at this point in the history
  • Loading branch information
streeve committed Aug 8, 2023
2 parents 41bf6cc + f044aaa commit f6243ff
Show file tree
Hide file tree
Showing 8 changed files with 304 additions and 49 deletions.
5 changes: 4 additions & 1 deletion examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ target_link_libraries(ElasticWave LINK_PUBLIC CabanaPD)
add_executable(KalthoffWinkler kalthoff_winkler.cpp)
target_link_libraries(KalthoffWinkler LINK_PUBLIC CabanaPD)

install(TARGETS ElasticWave KalthoffWinkler DESTINATION ${CMAKE_INSTALL_BINDIR})
add_executable(CrackBranching crack_branching.cpp)
target_link_libraries(CrackBranching LINK_PUBLIC CabanaPD)

install(TARGETS ElasticWave KalthoffWinkler CrackBranching DESTINATION ${CMAKE_INSTALL_BINDIR})
121 changes: 121 additions & 0 deletions examples/crack_branching.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#include <fstream>
#include <iostream>

#include "mpi.h"

#include <Kokkos_Core.hpp>

#include <CabanaPD.hpp>

int main( int argc, char* argv[] )
{

MPI_Init( &argc, &argv );

{
Kokkos::ScopeGuard scope_guard( argc, argv );

// FIXME: change backend at compile time for now.
using exec_space = Kokkos::DefaultExecutionSpace;
using memory_space = typename exec_space::memory_space;

// Plate dimensions (m)
double height = 0.1;
double width = 0.04;
double thickness = 0.002;

// Domain
std::array<int, 3> num_cell = { 400, 160, 8 }; // 400 x 160 x 8
double low_x = -0.5 * height;
double low_y = -0.5 * width;
double low_z = -0.5 * thickness;
double high_x = 0.5 * height;
double high_y = 0.5 * width;
double high_z = 0.5 * thickness;
std::array<double, 3> low_corner = { low_x, low_y, low_z };
std::array<double, 3> high_corner = { high_x, high_y, high_z };

// Time
double t_final = 43e-6;
double dt = 5e-8;
double output_frequency = 5;

// Material constants
double E = 72e+9; // [Pa]
double nu = 0.25; // unitless
double K = E / ( 3 * ( 1 - 2 * nu ) ); // [Pa]
double rho0 = 2440; // [kg/m^3]
double G0 = 3.8; // [J/m^2]

// PD horizon
double delta = 0.001 + 1e-10;

// FIXME: set halo width based on delta
int m = std::floor(
delta / ( ( high_corner[0] - low_corner[0] ) / num_cell[0] ) );
int halo_width = m + 1;

// Prenotch
double L_prenotch = height / 2.0;
double y_prenotch1 = 0.0;
Kokkos::Array<double, 3> p01 = { low_x, y_prenotch1, low_z };
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 );

// Choose force model type.
using model_type =
CabanaPD::ForceModel<CabanaPD::PMB, CabanaPD::Fracture>;
model_type force_model( delta, K, G0 );
CabanaPD::Inputs inputs( num_cell, low_corner, high_corner, t_final, dt,
output_frequency );
inputs.read_args( argc, argv );

// Create particles from mesh.
// Does not set displacements, velocities, etc.
using device_type = Kokkos::Device<exec_space, memory_space>;
auto particles = std::make_shared<
CabanaPD::Particles<device_type, typename model_type::base_model>>(
exec_space(), inputs.low_corner, inputs.high_corner,
inputs.num_cells, halo_width );

// Define particle initialization.
auto x = particles->slice_x();
auto v = particles->slice_v();
auto f = particles->slice_f();
auto rho = particles->slice_rho();
auto nofail = particles->slice_nofail();

// Relying on uniform grid here.
double dy = particles->dy;
double b0 = 2e6 / dy; // Pa

CabanaPD::RegionBoundary plane1( low_x, high_x, low_y - dy, low_y + dy,
low_z, high_z );
CabanaPD::RegionBoundary plane2( low_x, high_x, high_y - dy,
high_y + dy, low_z, high_z );
std::vector<CabanaPD::RegionBoundary> planes = { plane1, plane2 };
auto bc =
createBoundaryCondition( CabanaPD::ForceCrackBranchBCTag{},
exec_space{}, *particles, planes, b0 );

auto init_functor = KOKKOS_LAMBDA( const int pid )
{
rho( pid ) = rho0;
// Set the no-fail zone.
if ( x( pid, 1 ) <= plane1.low_y + delta + 1e-10 ||
x( pid, 1 ) >= plane2.high_y - delta - 1e-10 )
nofail( pid ) = 1;
};
particles->update_particles( exec_space{}, init_functor );

// FIXME: use createSolver to switch backend at runtime.
auto cabana_pd = CabanaPD::createSolverFracture<device_type>(
inputs, particles, force_model, bc, prenotch );
cabana_pd->init_force();
cabana_pd->run();
}

MPI_Finalize();
}
7 changes: 4 additions & 3 deletions examples/kalthoff_winkler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,10 @@ int main( int argc, char* argv[] )
CabanaPD::RegionBoundary plane(
x_bc - dx, x_bc + dx * 1.25, y_prenotch1 - dx * 0.25,
y_prenotch2 + dx * 0.25, -thickness, thickness );

auto bc = createBoundaryCondition( exec_space{}, *particles, plane,
CabanaPD::ForceBCTag{} );
std::vector<CabanaPD::RegionBoundary> planes = { plane };
auto bc =
createBoundaryCondition( CabanaPD::ForceValueBCTag{}, exec_space{},
*particles, planes, 0.0 );

auto init_functor = KOKKOS_LAMBDA( const int pid )
{
Expand Down
178 changes: 142 additions & 36 deletions src/CabanaPD_Boundary.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
namespace CabanaPD
{

// Empty boundary.
struct ZeroBoundary
{
};

// Define a plane or other rectilinear subset of the system as the boundary.
struct RegionBoundary
{
double low_x;
Expand All @@ -47,26 +49,45 @@ struct RegionBoundary
template <class MemorySpace, class BoundaryType>
struct BoundaryIndexSpace;

// FIXME: fails for some cases if initial guess is not sufficient.
template <class MemorySpace>
struct BoundaryIndexSpace<MemorySpace, RegionBoundary>
{
using index_view_type = Kokkos::View<std::size_t*, MemorySpace>;
index_view_type _index_space;
index_view_type _view;
index_view_type _count;

template <class ExecSpace, class Particles>
BoundaryIndexSpace( ExecSpace exec_space, Particles particles,
RegionBoundary plane )
std::vector<RegionBoundary> planes,
const double initial_guess )
{
create( exec_space, particles, plane );
_view = index_view_type( "boundary_indices",
particles.n_local * initial_guess );
_count = index_view_type( "count", 1 );

for ( RegionBoundary plane : planes )
{
update( exec_space, particles, plane );
}
// Resize after all planes searched.
auto count_host =
Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace{}, _count );
if ( count_host( 0 ) < _view.size() )
{
Kokkos::resize( _view, count_host( 0 ) );
}
}

template <class ExecSpace, class Particles>
void create( ExecSpace, Particles particles, RegionBoundary plane )
void update( ExecSpace, Particles particles, RegionBoundary plane )
{
// Guess 10% boundary particles.
auto index_space =
index_view_type( "boundary_indices", particles.n_local * 0.1 );
auto count = index_view_type( "count", 1 );
auto count_host =
Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace{}, _count );
auto init_count = count_host( 0 );

auto index_space = _view;
auto count = _count;
auto x = particles.slice_x();
Kokkos::RangePolicy<ExecSpace> policy( 0, particles.n_local );
auto index_functor = KOKKOS_LAMBDA( const std::size_t pid )
Expand All @@ -84,74 +105,159 @@ struct BoundaryIndexSpace<MemorySpace, RegionBoundary>
}
};

Kokkos::parallel_for( "CabanaPD::BC::create", policy, index_functor );
auto count_host =
Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace{}, count );
if ( count_host( 0 ) != index_space.size() )
{
Kokkos::resize( index_space, count_host( 0 ) );
}
Kokkos::parallel_for( "CabanaPD::BC::update", policy, index_functor );
Kokkos::deep_copy( count_host, _count );
if ( count_host( 0 ) > index_space.size() )
{
Kokkos::deep_copy( count, 0 );
Kokkos::parallel_for( "CabanaPD::BC::create", policy,
Kokkos::resize( index_space, count_host( 0 ) );
Kokkos::deep_copy( count, init_count );
Kokkos::parallel_for( "CabanaPD::BC::update", policy,
index_functor );
}
_index_space = index_space;
}
};

template <class ExecSpace, class Particles, class BoundaryType>
template <class BoundaryType, class ExecSpace, class Particles>
auto createBoundaryIndexSpace( ExecSpace exec_space, Particles particles,
BoundaryType plane )
std::vector<RegionBoundary> planes,
const double initial_guess )
{
using memory_space = typename Particles::memory_space;
return BoundaryIndexSpace<memory_space, BoundaryType>( exec_space,
particles, plane );
return BoundaryIndexSpace<memory_space, BoundaryType>(
exec_space, particles, planes, initial_guess );
}

class ForceBCTag
struct ForceValueBCTag
{
};
struct ForceUpdateBCTag
{
};

struct ForceCrackBranchBCTag
{
};

template <class BCIndexSpace, class BCTag>
struct BoundaryCondition;

template <class BCIndexSpace>
struct BoundaryCondition<BCIndexSpace, ForceBCTag>
struct BoundaryCondition<BCIndexSpace, ForceValueBCTag>
{
using view_type = typename BCIndexSpace::index_view_type;
view_type _index_space;
double _value;
BCIndexSpace _index_space;

BoundaryCondition( BCIndexSpace bc_index_space )
: _index_space( bc_index_space._index_space )
BoundaryCondition( const double value, BCIndexSpace bc_index_space )
: _value( value )
, _index_space( bc_index_space )
{
}

template <class ExecSpace, class Particles>
void update( ExecSpace exec_space, Particles particles,
RegionBoundary plane )
{
_index_space.update( exec_space, particles, plane );
}

template <class ExecSpace, class ParticleType>
void apply( ExecSpace, ParticleType& particles )
{
auto f = particles.slice_f();
auto index_space = _index_space;
auto x = particles.slice_x();
auto index_space = _index_space._view;
Kokkos::RangePolicy<ExecSpace> policy( 0, index_space.size() );
Kokkos::parallel_for(
"CabanaPD::BC::apply", policy, KOKKOS_LAMBDA( const int b ) {
auto pid = index_space( b );
for ( int d = 0; d < 3; d++ )
f( pid, d ) = 0.0;
f( pid, d ) = _value;
} );
}
};

template <class BCIndexSpace>
struct BoundaryCondition<BCIndexSpace, ForceUpdateBCTag>
{
double _value;
BCIndexSpace _index_space;

BoundaryCondition( const double value, BCIndexSpace bc_index_space )
: _value( value )
, _index_space( bc_index_space )
{
}

template <class ExecSpace, class Particles>
void update( ExecSpace exec_space, Particles particles,
RegionBoundary plane )
{
_index_space.update( exec_space, particles, plane );
}

template <class ExecSpace, class ParticleType>
void apply( ExecSpace, ParticleType& particles )
{
auto f = particles.slice_f();
auto index_space = _index_space._view;
Kokkos::RangePolicy<ExecSpace> policy( 0, index_space.size() );
Kokkos::parallel_for(
"CabanaPD::BC::apply", policy, KOKKOS_LAMBDA( const int b ) {
auto pid = index_space( b );
for ( int d = 0; d < 3; d++ )
f( pid, d ) += _value;
} );
}
};

template <class BCIndexSpace>
struct BoundaryCondition<BCIndexSpace, ForceCrackBranchBCTag>
{
double _value;
BCIndexSpace _index_space;

BoundaryCondition( const double value, BCIndexSpace bc_index_space )
: _value( value )
, _index_space( bc_index_space )
{
}

template <class ExecSpace, class Particles>
void update( ExecSpace exec_space, Particles particles,
RegionBoundary plane )
{
_index_space.update( exec_space, particles, plane );
}

template <class ExecSpace, class ParticleType>
void apply( ExecSpace, ParticleType& particles )
{
auto f = particles.slice_f();
auto x = particles.slice_x();
auto index_space = _index_space._view;
Kokkos::RangePolicy<ExecSpace> policy( 0, index_space.size() );
Kokkos::parallel_for(
"CabanaPD::BC::apply", policy, KOKKOS_LAMBDA( const int b ) {
auto pid = index_space( b );
// This is specifically for the crack branching.
auto sign = std::abs( x( pid, 1 ) ) / x( pid, 1 );
f( pid, 1 ) += _value * sign;
} );
}
};

template <class ExecSpace, class Particles, class BoundaryType, class BCTag>
auto createBoundaryCondition( ExecSpace exec_space, Particles particles,
BoundaryType plane, BCTag )
// FIXME: relatively large initial guess for allocation.
template <class BoundaryType, class BCTag, class ExecSpace, class Particles>
auto createBoundaryCondition( BCTag, ExecSpace exec_space, Particles particles,
std::vector<BoundaryType> planes,
const double value,
const double initial_guess = 0.5 )
{
using memory_space = typename Particles::memory_space;
using bc_index_type = BoundaryIndexSpace<memory_space, BoundaryType>;
bc_index_type bc_indices =
createBoundaryIndexSpace( exec_space, particles, plane );
return BoundaryCondition<bc_index_type, BCTag>( bc_indices );
bc_index_type bc_indices = createBoundaryIndexSpace<BoundaryType>(
exec_space, particles, planes, initial_guess );
return BoundaryCondition<bc_index_type, BCTag>( value, bc_indices );
}

} // namespace CabanaPD
Expand Down
Loading

0 comments on commit f6243ff

Please sign in to comment.