Demo 2: Boundary Integral Operator
The code (tutorial/demo2-bio.cpp) demonstrates the basic usage of the BoundaryIntegralOp class.
The BoundaryIntegralOp class (in SCTL) is designed to construct and evaluate boundary integral operators, such as the Stokes single-layer and double-layer potential operators.
For more advanced usage and additional features, please refer to the class API in boundary_integral.hpp.
Building a Boundary Integral Operator
To build a boundary integral operator, follow these steps:
1. Initialize the Boundary Integral Operator
Initialize the boundary integral operator with the desired kernel and communication context.
In this example, we use the Stokes double-layer kernel (Stokes3D_DxU).
const Stokes3D_DxU ker;
BoundaryIntegralOp<double,Stokes3D_DxU> BIOp(ker, false, comm);
2. Set Quadrature Accuracy
Set the quadrature accuracy for numerical integration.
BIOp.SetAccuracy(1e-10);
3. Add Geometry to the Operator
Add the geometry of the surface to the boundary integral operator. This includes specifying the discretization of the surface. In this example the boundary is given by an instance of SlenderElemList class with geometry data loaded from a file.
SlenderElemList<double> elem_lst;
elem_lst.Read<double>("data/loop.geom", comm);
BIOp.AddElemList(elem_lst);
4. Set Evaluation Points
The target points can be specified as follows.
If not set or Xt is empty, then the default target points are the surface discretization nodes.
BIOp.SetTargetCoord(Xt);
Evaluating Potentials
Once the boundary integral operator is constructed, you can evaluate potentials at on- and off-surface target points.
1. Compute the Potential
Compute the potential using the boundary integral operator and a density function defined on the surface.
Vector<double> sigma(Ninput);
sigma = 1; // Set the density function sigma at each surface discretization node
Vector<double> U;
BIOp.ComputePotential(U, sigma); // Compute the potential U
2. Visualize the Results
Visualize the geometry and the computed potential.
elem_lst.WriteVTK("vis/U", U, comm); // Write visualization data to VTK file
Compiling and Running the Code
Without MPI: Navigate to the project root directory and run:
make bin/demo2-bio && ./bin/demo2-bio
With MPI: In the project root directory, edit
Makefileto setCXX=mpicxxand uncommentCXXFLAGS += -DSCTL_HAVE_MPI. Then, run:make bin/demo2-bio && mpirun -n 2 --map-by slot:pe=1 ./bin/demo2-bio
This will evaluate the Stokes double-layer potential on a loop geometry and write the VTK visualization to the file vis/U.pvtu which can be opened in ParaView.
Complete Example Code
/**
* This demo code shows how to use the class sctl::BoundaryIntegralOp. The
* class is declared in SCTL/include/sctl/boundary_integral.hpp. In particular,
* we show how to:
*
* 1) build a boundary integral operator.
*
* 2) evaluate potentials at on- and off-surface target points.
*
* To compile and run the code, start in the project root directory and run:
* make bin/demo2-bio && ./bin/demo2-bio
*/
#include <csbq.hpp>
using namespace sctl;
int main(int argc, char** argv) {
Comm::MPI_Init(&argc, &argv);
{
const Comm comm = Comm::World(); // comm must have local scope since it needs to be destroyed before Comm::MPI_Finalize()
Stokes3D_DxU ker; // Stokes double-layer kernel (@see SCTL/include/sctl/kernel_function.hpp)
BoundaryIntegralOp<double,Stokes3D_DxU> BIOp(ker, false, comm); // construct the boundary integral operator
BIOp.SetAccuracy(1e-10); // set quadrature accuracy
SlenderElemList<double> elem_lst;
elem_lst.Read<double>("data/ring.geom", comm); // read geometry data from file
BIOp.AddElemList(elem_lst); // add geometry to the boundary integral operator
// The target points can be specified as follows. If not set or Xt is empty,
// then the default target points are the surface discretization nodes.
//BIOp.SetTargetCoord(Xt);
const Long Ninput = BIOp.Dim(0); // (local) input dimension of the operator
const Long Noutput = BIOp.Dim(1); // (local) output dimension of the operator
// Set the density function sigma at each surface discretization node.
// The nodes can be queried using elem_lst.GetNodeCoord() (@see ex1_geometry.cpp).
Vector<double> sigma(Ninput);
sigma = 1;
Vector<double> U;
BIOp.ComputePotential(U, sigma); // compute the potential U
SCTL_ASSERT(U.Dim() == Noutput); // U will be of size Noutput
// visualizing the geometry and the potential
elem_lst.WriteVTK("vis/U", U, comm);
}
Comm::MPI_Finalize();
return 0;
}