Skip to content

Commit e593b57

Browse files
Merge pull request #512 from ehlertdo/ReflectiveShell
Implemented ReflectiveShell as optional boundary
2 parents 795ff09 + bd1c0c9 commit e593b57

File tree

5 files changed

+114
-5
lines changed

5 files changed

+114
-5
lines changed

CHANGELOG.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@
77
* Fixed wrong generation of interval ranges in ObserverTimeEvolution
88

99
### New features:
10-
* Added new backwards-compatible function particleMass that returns particle mass also for non-nuclei
11-
* Added the new Galactic magnetic field models from Unger&Farrar arXiv:2311.12120 and Korochkin et al. arXiv:2407.02148
12-
* Added EBL model from Finke et al. 2022
13-
* Added overridable getTime function to ObserverTimeEvolution which is called instead of detList.
10+
11+
* Added new backwards-compatible function particleMass that returns particle mass also for non-nuclei
12+
* Added the new Galactic magnetic field models from Unger&Farrar arXiv:2311.12120
13+
* Added EBL model from Finke et al. 2022
14+
* Added ReflectiveShell boundary condition
15+
* Added overridable getTime function to ObserverTimeEvolution which is called instead of detList.
1416
Old functionalities are preserved by adding old functions and setter/getter functions.
1517

18+
1619
### Interface changes:
1720

1821
### Features that are deprecated and will be removed after this release

doc/pages/Simulation-Modules.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ General interactions/processes
4141
Conditional modules implement certain conditions for stopping propagation.
4242
They provide interfaces to act onReject or onAccept of a cosmic ray.
4343
Boundary modules can be used to limit the simulation volume.
44-
Periodic- and ReflectiveBox implement boundary conditions for the particles. They are useful for a 3D setup where an initial volume is to be repeated (periodically or reflectively). When using them, a couple of things need to be considered. Observers will shadow the volume behind if they are set to inactivate particles. Also Observers should be placed at a distance to the boundaries that is larger than the maximum step size of the propagator, since step size limitation does not work beyond periodic/reflective boundaries.
44+
Periodic-/ReflectiveBox and ReflectiveShell implement boundary conditions for the particles. They are useful for a 3D setup where an initial volume is to be repeated (periodically or reflectively). When using them, a couple of things need to be considered. Observers will shadow the volume behind if they are set to inactivate particles. Also Observers should be placed at a distance to the boundaries that is larger than the maximum step size of the propagator, since step size limitation does not work beyond periodic/reflective boundaries.
4545

4646
* **MaximumTrajectoryLength** - Stop after reaching maximum trajectory length
4747
* **MinimumEnergy** - Stop after reaching a minimum energy
@@ -53,6 +53,7 @@ Periodic- and ReflectiveBox implement boundary conditions for the particles. The
5353
* **CylindricalBoundary** - Cylindric simulation volume
5454
* **PeriodicBox** - Periodic boundary conditions for the particle: If a particle leaves the box it will enter from the opposite side and the initial position will be changed as if it had come from that side.
5555
* **ReflectiveBox** - Reflective boundary conditions for the particle: If a particle leaves the box it will be reflected (mirrored) and the initial position will be changed as if it had come from that side.
56+
* **ReflectiveShell** - Reflective spherical boundary condition for the particle; If a particle crosses the shell during the current step it will be reflected back at the boundary according to the law of reflection. Particles coming from the outside are only reflected if the current step ends inside the shell.
5657
* **DetectionLength** - Detects the candidate at a given trajectory length.
5758

5859
### Observers

include/crpropa/module/Boundary.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,32 @@ class PeriodicBox: public Module {
3737
std::string getDescription() const;
3838
};
3939

40+
/**
41+
@class ReflectiveShell
42+
@brief Shell with reflective boundary
43+
44+
If a particle crosses the boundary it is reflected back inside or outside (position and velocity) depending where it came from.
45+
Particles can overshoot (be outside of the box during the step) since the step size is not limited by this module.
46+
*/
47+
class ReflectiveShell: public Module {
48+
private:
49+
Vector3d center;
50+
double radius;
51+
52+
public:
53+
/** Constructor
54+
@param center vector corresponding to the center of the sphere
55+
@param r value corresponding to the radius of the shell
56+
*/
57+
ReflectiveShell(Vector3d center, double r);
58+
double distance(const Vector3d &point) const;
59+
Vector3d normal(const Vector3d &point) const;
60+
void process(Candidate *candidate) const;
61+
void setCenter(Vector3d center);
62+
void setRadius(double r);
63+
std::string getDescription() const;
64+
};
65+
4066
/**
4167
@class ReflectiveBox
4268
@brief Rectangular box with reflective boundaries.

src/module/Boundary.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,57 @@ std::string PeriodicBox::getDescription() const {
4040
return s.str();
4141
}
4242

43+
44+
ReflectiveShell::ReflectiveShell(Vector3d center, double r) :
45+
center(center), radius(r) {
46+
}
47+
48+
double ReflectiveShell::distance(const Vector3d &point) const {
49+
Vector3d dR = point - center;
50+
return dR.getR() - radius;
51+
}
52+
53+
Vector3d ReflectiveShell::normal(const Vector3d& point) const {
54+
Vector3d d = point - center;
55+
return d.getUnitVector();
56+
}
57+
58+
void ReflectiveShell::process(Candidate *c) const {
59+
double currentDistance = distance(c->current.getPosition());
60+
double previousDistance = distance(c->previous.getPosition());
61+
// check if cosmic ray crossed boundary in last step
62+
if (currentDistance * previousDistance < 0){
63+
Vector3d currentDirection = c->current.getDirection();
64+
Vector3d previousPosition = c->previous.getPosition();
65+
// get point where trajectory intersects the shell boundary
66+
double p_half = previousPosition.dot(currentDirection) / currentDirection.getR2();
67+
double q = (previousPosition.getR2() - radius * radius) / currentDirection.getR2();
68+
double k1 = - p_half + sqrt(p_half * p_half - q);
69+
Vector3d intersectPoint = previousPosition + k1 * currentDirection;
70+
// flip component of velocity normal to surface
71+
Vector3d surfaceNormal = normal(intersectPoint);
72+
Vector3d newDirection = currentDirection - 2 * currentDirection.dot(surfaceNormal) * surfaceNormal;
73+
c->current.setDirection(newDirection.getUnitVector());
74+
// also update position
75+
c->current.setPosition(intersectPoint + newDirection * (c->getCurrentStep() - (k1 * currentDirection).getR()) / newDirection.getR());
76+
}
77+
}
78+
79+
void ReflectiveShell::setCenter(Vector3d c) {
80+
center = c;
81+
}
82+
void ReflectiveShell::setRadius(double r) {
83+
radius = r;
84+
}
85+
86+
std::string ReflectiveShell::getDescription() const {
87+
std::stringstream s;
88+
s << "Reflective sphere: center: " << center / Mpc << " Mpc, ";
89+
s << "radius: " << radius / Mpc << " Mpc";
90+
return s.str();
91+
};
92+
93+
4394
ReflectiveBox::ReflectiveBox() :
4495
origin(Vector3d(0, 0, 0)), size(Vector3d(0, 0, 0)) {
4596
}

test/testBreakCondition.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,34 @@ TEST(PeriodicBox, low) {
413413
EXPECT_DOUBLE_EQ(3, c.created.getPosition().z);
414414
}
415415

416+
TEST(ReflectiveShell, inside) {
417+
// Tests if the reflective boundaries place the particle back inside the shell
418+
Vector3d center(0, 0, 0);
419+
double radius = 100;
420+
ReflectiveShell shell(center, radius);
421+
422+
Candidate c;
423+
c.setCurrentStep(20);
424+
c.previous.setPosition(Vector3d(80, 20, 30));
425+
c.previous.setDirection(Vector3d(10, -1, -1));
426+
// un-reflected new position (outside shell) after full step
427+
Vector3d currentPosition = c.previous.getPosition() + c.previous.getDirection() * c.getCurrentStep() / c.previous.getDirection().getR();
428+
c.current.setPosition(currentPosition);
429+
c.current.setDirection(Vector3d(10, -1, -1));
430+
// process reflection
431+
shell.process(&c);
432+
433+
// expected position & direction after reflection
434+
// calculated by hand with the same algorithm as implemented in Boundary.cpp
435+
EXPECT_NEAR(90.06356247, c.current.getPosition().x, 1e-7);
436+
EXPECT_NEAR(16.09256317, c.current.getPosition().y, 1e-7);
437+
EXPECT_NEAR(25.05646296, c.current.getPosition().z, 1e-7);
438+
439+
EXPECT_NEAR(-0.67179589, c.current.getDirection().x, 1e-7);
440+
EXPECT_NEAR(-0.42786503, c.current.getDirection().y, 1e-7);
441+
EXPECT_NEAR(-0.60466668, c.current.getDirection().z, 1e-7);
442+
}
443+
416444
TEST(ReflectiveBox, high) {
417445
// Tests if the reflective boundaries place the particle back inside the box and translate the initial position accordingly.
418446
// Also the initial and final directions are to be reflected

0 commit comments

Comments
 (0)