上流リザーバ境界から流入する粒子を 1 つ、counter-based 乱数で面注入としてサンプルする。 同じ (seed, counter) は常に同じ粒子を返すので、どの rank・thread が生成しても結果は同じ。 速度の法線成分は flux-weighted に draw 1、面内位置は draw 2, 3、熱速度は draw 100 以降を使う。
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=dp), | intent(in) | :: | box_min(3) | |||
| real(kind=dp), | intent(in) | :: | box_max(3) | |||
| character(len=*), | intent(in) | :: | inject_face | |||
| real(kind=dp), | intent(in) | :: | pos_low(3) | |||
| real(kind=dp), | intent(in) | :: | pos_high(3) | |||
| real(kind=dp), | intent(in) | :: | drift_velocity(3) | |||
| real(kind=dp), | intent(in) | :: | m_particle | |||
| real(kind=dp), | intent(in) | :: | temperature_k | |||
| real(kind=dp), | intent(in) | :: | barrier_normal_energy |
法線エネルギー障壁 |
||
| real(kind=dp), | intent(in) | :: | vmin_normal |
法線エネルギー障壁 |
||
| integer(kind=i32), | intent(in) | :: | rng_seed | |||
| integer(kind=i64), | intent(in) | :: | rng_counter(:) | |||
| real(kind=dp), | intent(out) | :: | x(3) | |||
| real(kind=dp), | intent(out) | :: | v(3) |
subroutine sample_reservoir_face_particle_counter( & box_min, box_max, inject_face, pos_low, pos_high, drift_velocity, m_particle, temperature_k, & barrier_normal_energy, vmin_normal, rng_seed, rng_counter, x, v & ) real(dp), intent(in) :: box_min(3), box_max(3) character(len=*), intent(in) :: inject_face real(dp), intent(in) :: pos_low(3), pos_high(3), drift_velocity(3) real(dp), intent(in) :: m_particle, temperature_k, barrier_normal_energy, vmin_normal integer(i32), intent(in) :: rng_seed integer(i64), intent(in) :: rng_counter(:) real(dp), intent(out) :: x(3), v(3) integer :: axis_n, axis_t1, axis_t2 real(dp) :: boundary_value, inward_normal(3), sigma, u_n, vn_floor, vn_inf, vn(1), z(3, 1), uniform(3) call resolve_face_geometry(box_min, box_max, inject_face, axis_n, boundary_value, inward_normal) call resolve_face_axes(inject_face, axis_t1, axis_t2) if (m_particle <= 0.0_dp) error stop "particle mass [kg] must be > 0" if (temperature_k < 0.0_dp) error stop "temperature [K] must be >= 0" sigma = sqrt(k_boltzmann*temperature_k/m_particle) u_n = dot_product(drift_velocity, inward_normal) vn_floor = 0.0_dp if (barrier_normal_energy > 0.0_dp) vn_floor = sqrt(barrier_normal_energy) vn_floor = max(vn_floor, max(0.0_dp, vmin_normal)) call sample_standard_normal(z, sigma_cutoff=default_velocity_sigma_cutoff, rng_seed=rng_seed, rng_counter=rng_counter) v = sigma*z(:, 1) + drift_velocity ! Draw 1 picks the normal speed and draws 2 and 3 the position on the face. call counter_uniforms(rng_seed, rng_counter, 1_i64, uniform) call sample_flux_weighted_normal_component( & u_n, sigma, vn, vmin_normal=vn_floor, sigma_cutoff=default_velocity_sigma_cutoff, uniform=uniform(1:1) & ) ! A negative barrier (accelerating sheath) raises the normal speed. vn_inf = sqrt(max(0.0_dp, vn(1)*vn(1) - barrier_normal_energy)) v(axis_n) = inward_normal(axis_n)*vn_inf x = 0.0_dp ! One representable step inward avoids a zero-time boundary event without an untracked flight segment. x(axis_n) = nearest(boundary_value, inward_normal(axis_n)) x(axis_t1) = pos_low(axis_t1) + (pos_high(axis_t1) - pos_low(axis_t1))*uniform(2) x(axis_t2) = pos_low(axis_t2) + (pos_high(axis_t2) - pos_low(axis_t2))*uniform(3) end subroutine sample_reservoir_face_particle_counter