sandbox/fpicella/src/driver-tHree-smooth.h
# 3-forces microswimmer model
Build up a forcing field...
face vector av[];
/*
What is the smallest cells size (CS) in the simulation?
This will be the characteristic size with which I model
the presence of my microswimmer.*/
#define CS (L0/(N))
// This is right if I have a fixed mesh, but should check when using
// variable refinement (adaptive...)
Blob on which I compute the force on the center of the microswimmer.
It is a spherical blob of diameter one mesh cell.
#define blob(xp,yp,zp) (sq (PS(x,xp)) + sq (PS(y,yp)) + sq(PS(z,zp)) - sq (2.*CS))
#define radius sqrt(sq(PS(x,p().x+Shift.x))+sq(PS(y,p().y+Shift.y)))
Smoothed Profile, SP .
#define SP(RADIUS) 0.5*(tanh((RADIUS-radius)/CS)+1.)
#define sinTheta sin(p().theta)
#define cosTheta cos(p().theta)
#define ALPHA alpha*p().r
#define BETA beta*p().r
#define ShiftxCenter -0.*BETA*cosTheta+0.*ALPHA*sinTheta
#define ShiftyCenter -0.*BETA*sinTheta-0.*ALPHA*cosTheta
#define ShiftxTrans -1.*BETA*cosTheta+1.*ALPHA*sinTheta
#define ShiftyTrans -1.*BETA*sinTheta-1.*ALPHA*cosTheta
#define ShiftxCis -1.*BETA*cosTheta-1.*ALPHA*sinTheta
#define ShiftyCis -1.*BETA*sinTheta+1.*ALPHA*cosTheta
vector bodyForce[];
void compute_microswimmer_forcing_smooth(Particles p)
{
foreach()
foreach_dimension()
bodyForce.x[] = 0.;
foreach_particle_in(p){
coord Shift = {0.,0.};
// Center
Shift.x = ShiftxCenter; Shift.y = ShiftyCenter;
foreach(){
bodyForce.x[] += SP(p().r)*(p().B.x+cos(p().theta)*p().Thrust)/(p().r*p().r*M_PI);
bodyForce.y[] += SP(p().r)*(p().B.y+sin(p().theta)*p().Thrust)/(p().r*p().r*M_PI);
}
// Trans
Shift.x = ShiftxTrans; Shift.y = ShiftyTrans;
foreach(){
bodyForce.x[] += SP(p().r)*(-cos(p().theta)*p().Thrust/2.)/(p().r*p().r*M_PI);
bodyForce.y[] += SP(p().r)*(-sin(p().theta)*p().Thrust/2.)/(p().r*p().r*M_PI);
}
// Cis
Shift.x = ShiftxCis; Shift.y = ShiftyCis;
foreach(){
bodyForce.x[] += SP(p().r)*(-cos(p().theta)*p().Thrust/2.)/(p().r*p().r*M_PI);
bodyForce.y[] += SP(p().r)*(-sin(p().theta)*p().Thrust/2.)/(p().r*p().r*M_PI);
}
}
foreach_face()
av.x[] = face_value(bodyForce.x,0);
}
scalar sp[];
void compute_sp(Particles p){
foreach()
sp[] = 0.;
foreach_particle_in(p){
coord Shift = {0.,0.};
foreach()
sp[] += SP(p().r);
}
}
Include steric interactions. To do so, use some potential to tune body force on the particle when close to boundaries or other particles.
For the moment, I’ve got a purely repulsive potential, identical to the 12-term in Lennard-Jones.
Forces are applied directly at the center of the body, as if they where some sort of body-force.
Single common definition of the (repulsion / attraction) potential
#define potential pow(sigma/distance,12) - pow(sigma/distance,6)
void compute_repulsion(Particles p, double repulsion_distance, bool top, bool bottom, bool right, bool left, double repulsion_strength)
{
foreach()
foreach_dimension()
bodyForce.x[] = 0.;
foreach_particle_in(p){
coord Shift = {0.,0.}; // legacy from previous functions...keep it to zero
// if you want the force to be applied around the
// microswimmer body.
coord Intensity = {0.,0.}; // intensity of the force to apply.
// Intensity will be built upon body-wall and body-body interactions.
What is the distance from which I want the repulsion force to kick in?
double sigma = repulsion_distance*p().r;
Set up a variable for the particle-surface distance, for convenience…
double distance = 0.;
Compute the intensity of repulsion, between the particle and the bottom wall.
if(bottom==true){
distance = L0/2.+y;
Intensity.y += potential;//pow(sigma/distance,repulsion_strength);//-pow(sigma/distance,6);
}
Compute the intensity of repulsion, between the particle and the top wall.
if(top==true){
distance = L0/2.-y;
Intensity.y -= potential;//pow(sigma/distance,repulsion_strength);//-pow(sigma/distance,6);
}
Compute the intensity of repulsion, between the particle and the right wall.
if(right==true){
distance = L0/2.-x;
Intensity.x -= potential;//pow(sigma/distance,repulsion_strength);//-pow(sigma/distance,6);
}
Compute the intensity of repulsion, between the particle and the bottom wall.
if(left==true){
distance = L0/2.+x;
Intensity.x += potential;//pow(sigma/distance,repulsion_strength);//-pow(sigma/distance,6);
}
Compute particle-particle repelling force.
This clearly is not the most efficient way to do it: I’m computing twice for the same k-j particles. Still, it is super simple and it works. For the moment I keep it like this. Honestly, I don’t think that for my purposes the computational overhead will be even noticeable.
for (int _k_particle = 0; _k_particle < pn[_l_particle]; _k_particle++) {
if(_k_particle != _j_particle){
coord DISTANCE;
foreach_dimension()
DISTANCE.x = pl[_l_particle][_k_particle].x - pl[_l_particle][_j_particle].x;
distance = sqrt(sq(DISTANCE.x)+sq(DISTANCE.y))-sigma;
double INTENSITY = pow(sigma/distance,repulsion_strength);//-pow(sigma/distance,6);
double angle = atan2(DISTANCE.y/distance,DISTANCE.x/distance);
Intensity.x -= INTENSITY*cos(angle);
Intensity.y -= INTENSITY*sin(angle);
}
}
// Center
foreach(){
bodyForce.x[] += Intensity.x*SP(p().r)/(p().r*p().r*M_PI);
bodyForce.y[] += Intensity.y*SP(p().r)/(p().r*p().r*M_PI);
}
foreach_face()
av.x[] += face_value(bodyForce.x,0);
}
}
For plotting purposes only.
scalar bodyPlot[];
void compute_bodyPlot(Particles p){
foreach()
bodyPlot[] = 0.;
foreach_particle_in(p){
coord Shift = {0.,0.}; // legacy from previous functions...keep it to zero
// if you want the force to be applied around the
// microswimmer body.
// Center
Shift.x = ShiftxCenter; Shift.y = ShiftyCenter;
foreach()
bodyPlot[] += SP(p().r);
// Trans
Shift.x = ShiftxTrans; Shift.y = ShiftyTrans;
foreach()
bodyPlot[] += SP(p().r);
// Cis
Shift.x = ShiftxCis; Shift.y = ShiftyCis;
foreach()
bodyPlot[] += SP(p().r);
}
}
Particle output
A simple(r) implementation.
I will just write a single file for each particle in time.
For the moment, I allocate space for 100 particles.
In cas I'll need to do more...I'll have to deal with
the next line of code.
static FILE *singleParticleFile[100] = {NULL}; // for the moment only one set of particles...?
Prepare the output files.
/* Particle output, super-compact (and working in serial!) way :)
FP, 20250212 11h37 */
event output_particle_initialize(i=0){ // first iteration, define name and open files...
foreach_particle(){
char filename[100];
sprintf(filename, "particle_%03d.dat", _j_particle);
singleParticleFile[_j_particle] = fopen(filename,"w");
}
}
#define FORMAT_SPEC_7 ("%+6.5e %+6.5e %+6.5e %+6.5e %+6.5e %+6.5e %+6.5e\n") // to avoid writing every time it...
event output_particle(i++){
foreach_particle(){
//fprintf(singleParticleFile[_j_particle],FORMAT_SPEC_7,t,p().x,p().y,p().theta.z,p().u.x,p().u.y,p().omega.z);
fprintf(singleParticleFile[_j_particle],FORMAT_SPEC_7,t,p().x,p().y,p().theta,p().u.x,p().u.y,p().omega);
fflush(singleParticleFile[_j_particle]);
}
}