-
Notifications
You must be signed in to change notification settings - Fork 631
Expand file tree
/
Copy pathray.cpp
More file actions
213 lines (182 loc) · 7.23 KB
/
ray.cpp
File metadata and controls
213 lines (182 loc) · 7.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#include "openmc/ray.h"
#include "openmc/error.h"
#include "openmc/geometry.h"
#include "openmc/material.h"
#include "openmc/mgxs_interface.h"
#include "openmc/settings.h"
namespace openmc {
void Ray::compute_distance()
{
boundary() = distance_to_boundary(*this);
}
void Ray::trace()
{
// To trace the ray from its origin all the way through the model, we have
// to proceed in two phases. In the first, the ray may or may not be found
// inside the model. If the ray is already in the model, phase one can be
// skipped. Otherwise, the ray has to be advanced to the boundary of the
// model where all the cells are defined. Importantly, this is assuming that
// the model is convex, which is a very reasonable assumption for any
// radiation transport model.
//
// After phase one is done, we can starting tracing from cell to cell within
// the model. This step can use neighbor lists to accelerate the ray tracing.
bool inside_cell;
// Check for location if the particle is already known
if (lowest_coord().cell() == C_NONE) {
// The geometry position of the particle is either unknown or outside of the
// edge of the model.
if (lowest_coord().universe() == C_NONE) {
// Attempt to initialize the particle. We may have to
// enter a loop to move it up to the edge of the model.
inside_cell = exhaustive_find_cell(*this, settings::verbosity >= 10);
} else {
// It has been already calculated that the current position is outside of
// the edge of the model.
inside_cell = false;
}
} else {
// Availability of the cell means that the particle is located inside the
// edge.
inside_cell = true;
}
// Advance to the boundary of the model
while (!inside_cell) {
advance_to_boundary_from_void();
inside_cell = exhaustive_find_cell(*this, settings::verbosity >= 10);
// If true this means no surface was intersected. See cell.cpp and search
// for numeric_limits to see where we return it.
if (surface() == std::numeric_limits<int>::max()) {
warning(fmt::format("Lost a ray, r = {}, u = {}", r(), u()));
return;
}
// Exit this loop and enter into cell-to-cell ray tracing (which uses
// neighbor lists)
if (inside_cell)
break;
// if there is no intersection with the model, we're done
if (boundary().surface() == SURFACE_NONE)
return;
event_counter_++;
if (event_counter_ > MAX_INTERSECTIONS) {
warning("Likely infinite loop in ray traced plot");
return;
}
}
// Call the specialized logic for this type of ray. This is for the
// intersection for the first intersection if we had one.
if (boundary().surface() != SURFACE_NONE) {
// set the geometry state's surface attribute to be used for
// surface normal computation
surface() = boundary().surface();
on_intersection();
if (stop_)
return;
}
// reset surface attribute to zero after the first intersection so that it
// doesn't perturb surface crossing logic from here on out
surface() = 0;
// This is the ray tracing loop within the model. It exits after exiting
// the model, which is equivalent to assuming that the model is convex.
// It would be nice to factor out the on_intersection at the end of this
// loop and then do "while (inside_cell)", but we can't guarantee it's
// on a surface in that case. There might be some other way to set it
// up that is perhaps a little more elegant, but this is what works just
// fine.
while (true) {
compute_distance();
// There are no more intersections to process
// if we hit the edge of the model, so stop
// the particle in that case. Also, just exit
// if a negative distance was somehow computed.
if (boundary().distance() == INFTY || boundary().distance() == INFINITY ||
boundary().distance() < 0) {
return;
}
// See below comment where call_on_intersection is checked in an
// if statement for an explanation of this.
bool call_on_intersection {true};
if (boundary().distance() < 10 * TINY_BIT) {
call_on_intersection = false;
}
// DAGMC surfaces expect us to go a little bit further than the advance
// distance to properly check cell inclusion.
boundary().distance() += TINY_BIT;
// Advance particle, prepare for next intersection
for (int lev = 0; lev < n_coord(); ++lev) {
coord(lev).r() += boundary().distance() * coord(lev).u();
}
surface() = boundary().surface();
// Initialize last cells from the current cell, because the cell() variable
// does not contain the data for the case of a single-segment ray
for (int j = 0; j < n_coord(); ++j) {
cell_last(j) = coord(j).cell();
}
n_coord_last() = n_coord();
n_coord() = boundary().coord_level();
if (boundary().lattice_translation()[0] != 0 ||
boundary().lattice_translation()[1] != 0 ||
boundary().lattice_translation()[2] != 0) {
cross_lattice(*this, boundary(), settings::verbosity >= 10);
}
update_distance();
inside_cell = neighbor_list_find_cell(*this, settings::verbosity >= 10);
// Call the specialized logic for this type of ray. Note that we do not
// call this if the advance distance is very small. Unfortunately, it seems
// darn near impossible to get the particle advanced to the model boundary
// and through it without sometimes accidentally calling on_intersection
// twice. This incorrectly shades the region as occluded when it might not
// actually be. By screening out intersection distances smaller than a
// threshold 10x larger than the scoot distance used to advance up to the
// model boundary, we can avoid that situation.
if (call_on_intersection) {
on_intersection();
if (stop_)
return;
}
if (!inside_cell)
return;
event_counter_++;
if (event_counter_ > MAX_INTERSECTIONS) {
warning("Likely infinite loop in ray traced plot");
return;
}
}
}
void Ray::update_distance()
{
// Record how far the ray has traveled
traversal_distance_ += boundary().distance();
}
void ParticleRay::on_intersection() {}
void ParticleRay::update_distance()
{
Ray::update_distance();
time() += boundary().distance() / speed();
// Calculate microscopic and macroscopic cross sections
if (material() != MATERIAL_VOID) {
if (settings::run_CE) {
if (material() != material_last() || sqrtkT() != sqrtkT_last() ||
density_mult() != density_mult_last()) {
// If the material is the same as the last material and the
// temperature hasn't changed, we don't need to lookup cross
// sections again.
model::materials[material()]->calculate_xs(*this);
}
} else {
// Get the MG data; unlike the CE case above, we have to re-calculate
// cross sections for every collision since the cross sections may
// be angle-dependent
data::mg.macro_xs_[material()].calculate_xs(*this);
// Update the particle's group while we know we are multi-group
g_last() = g();
}
} else {
macro_xs().total = 0.0;
macro_xs().absorption = 0.0;
macro_xs().fission = 0.0;
macro_xs().nu_fission = 0.0;
}
traversal_mfp_ += macro_xs().total * boundary().distance();
}
} // namespace openmc