Skip to content

Commit 02b6bc8

Browse files
committed
surf_react mpex: write reflected v directly (cosine direction + sqrt(RE) speed)
1 parent 3be1cfa commit 02b6bc8

1 file changed

Lines changed: 61 additions & 9 deletions

File tree

src/OPENEDGE/surf_react_mpex.cpp

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ int SurfReactMpex::react(Particle::OnePart *&ip,
128128

129129
// no secondaries in this model
130130
jp = nullptr;
131-
// let SurfCollideDiffuse::diffuse() modify the direction if we reflect
131+
// velreset toggled below: 1 if we set ip->v ourselves (reflected branch),
132+
// 0 if surf_collide should handle the leftover (stick branch with ip=nullptr).
132133
velreset = 0;
133134

134135
// If no reaction templates exist for this species, do nothing
@@ -166,15 +167,66 @@ int SurfReactMpex::react(Particle::OnePart *&ip,
166167
double u = random->uniform();
167168

168169
if (u < RN) {
169-
// REFLECTION: keep ip alive; SurfCollideDiffuse::diffuse will
170-
// randomize direction, but we can enforce the energy loss via RE.
171-
if (RE > 0.0) {
172-
double scale = sqrt(RE); // v' = sqrt(RE) * v => E' = RE * E
173-
ip->v[0] *= scale;
174-
ip->v[1] *= scale;
175-
ip->v[2] *= scale;
170+
// REFLECTION. We write the outgoing velocity directly here and tell
171+
// SPARTA's surf_collide to leave it alone (velreset = 1). Direction is
172+
// sampled from a cosine (Lambert) distribution in the outgoing half-
173+
// space; speed is set by the angle-dependent energy reflection
174+
// coefficient RE(theta): |v_out| = sqrt(RE) * |v_in|.
175+
velreset = 1;
176+
177+
// ---- local frame (n_hat, tan1, tan2) at the surface ----
178+
double n_hat[3];
179+
if (nlen > 0.0) {
180+
n_hat[0] = norm[0] / nlen;
181+
n_hat[1] = norm[1] / nlen;
182+
n_hat[2] = norm[2] / nlen;
183+
} else {
184+
n_hat[0] = 0.0; n_hat[1] = 0.0; n_hat[2] = 1.0;
176185
}
177-
ip->ispecies = r->products[0];
186+
187+
// tangent1 = component of incoming v perpendicular to n_hat (then
188+
// normalised). Falls back to a random tangent for normal incidence.
189+
double dotvn = MathExtra::dot3(v, n_hat);
190+
double tan1[3] = {
191+
v[0] - dotvn * n_hat[0],
192+
v[1] - dotvn * n_hat[1],
193+
v[2] - dotvn * n_hat[2]
194+
};
195+
if (MathExtra::lensq3(tan1) < 1.0e-30) {
196+
tan1[0] = random->uniform();
197+
tan1[1] = random->uniform();
198+
tan1[2] = random->uniform();
199+
double dt = MathExtra::dot3(tan1, n_hat);
200+
tan1[0] -= dt * n_hat[0];
201+
tan1[1] -= dt * n_hat[1];
202+
tan1[2] -= dt * n_hat[2];
203+
}
204+
MathExtra::norm3(tan1);
205+
double tan2[3];
206+
MathExtra::cross3(n_hat, tan1, tan2);
207+
MathExtra::norm3(tan2);
208+
209+
// ---- cosine-weighted (Lambert) hemisphere sample ----
210+
double xi1 = random->uniform();
211+
double xi2 = random->uniform();
212+
double cosT = sqrt(xi1); // p(cos theta) = 2 cos theta
213+
double sinT = sqrt(std::max(0.0, 1.0 - cosT * cosT));
214+
double phi = 2.0 * MathConst::MY_PI * xi2;
215+
double cosP = cos(phi), sinP = sin(phi);
216+
217+
double dir[3] = {
218+
sinT * cosP * tan1[0] + sinT * sinP * tan2[0] + cosT * n_hat[0],
219+
sinT * cosP * tan1[1] + sinT * sinP * tan2[1] + cosT * n_hat[1],
220+
sinT * cosP * tan1[2] + sinT * sinP * tan2[2] + cosT * n_hat[2]
221+
};
222+
223+
// ---- speed from RE(theta) ----
224+
double speed = vlen * sqrt(std::max(0.0, RE));
225+
ip->v[0] = speed * dir[0];
226+
ip->v[1] = speed * dir[1];
227+
ip->v[2] = speed * dir[2];
228+
229+
ip->ispecies = r->products[0];
178230
nsingle++;
179231
tally_single[list[0]]++; // bookkeeping
180232

0 commit comments

Comments
 (0)