• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

NREL / SolTrace / 20284524697

16 Dec 2025 10:18PM UTC coverage: 89.66% (+0.5%) from 89.184%
20284524697

Pull #91

github

web-flow
Merge 8dcc78458 into a73a760a4
Pull Request #91: Implement multi-threading in NativeRunner

424 of 468 new or added lines in 11 files covered. (90.6%)

3 existing lines in 2 files now uncovered.

6096 of 6799 relevant lines covered (89.66%)

7502415.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.34
/coretrace/simulation_runner/native_runner/trace.cpp
1

2
/*******************************************************************************************************
3
 *  Copyright 2018 Alliance for Sustainable Energy, LLC
4
 *
5
 *  NOTICE: This software was developed at least in part by Alliance for Sustainable Energy, LLC
6
 *  ("Alliance") under Contract No. DE-AC36-08GO28308 with the U.S. Department of Energy and the U.S.
7
 *  The Government retains for itself and others acting on its behalf a nonexclusive, paid-up,
8
 *  irrevocable worldwide license in the software to reproduce, prepare derivative works, distribute
9
 *  copies to the public, perform publicly and display publicly, and to permit others to do so.
10
 *
11
 *  Redistribution and use in source and binary forms, with or without modification, are permitted
12
 *  provided that the following conditions are met:
13
 *
14
 *  1. Redistributions of source code must retain the above copyright notice, the above government
15
 *  rights notice, this list of conditions and the following disclaimer.
16
 *
17
 *  2. Redistributions in binary form must reproduce the above copyright notice, the above government
18
 *  rights notice, this list of conditions and the following disclaimer in the documentation and/or
19
 *  other materials provided with the distribution.
20
 *
21
 *  3. The entire corresponding source code of any redistribution, with or without modification, by a
22
 *  research entity, including but not limited to any contracting manager/operator of a United States
23
 *  National Laboratory, any institution of higher learning, and any non-profit organization, must be
24
 *  made publicly available under this license for as long as the redistribution is made available by
25
 *  the research entity.
26
 *
27
 *  4. Redistribution of this software, without modification, must refer to the software by the same
28
 *  designation. Redistribution of a modified version of this software (i) may not refer to the modified
29
 *  version by the same designation, or by any confusingly similar designation, and (ii) must refer to
30
 *  the underlying software originally provided by Alliance as "SolTrace". Except to comply with the
31
 *  foregoing, the term "SolTrace", or any confusingly similar designation may not be used to refer to
32
 *  any modified version of this software or any modified version of the underlying software originally
33
 *  provided by Alliance without the prior written consent of Alliance.
34
 *
35
 *  5. The name of the copyright holder, contributors, the United States Government, the United States
36
 *  Department of Energy, or any of their employees may not be used to endorse or promote products
37
 *  derived from this software without specific prior written permission.
38
 *
39
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
40
 *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
41
 *  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER,
42
 *  CONTRIBUTORS, UNITED STATES GOVERNMENT OR UNITED STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR
43
 *  EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
44
 *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
45
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
46
 *  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
47
 *  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48
 *******************************************************************************************************/
49

50
#include "trace.hpp"
51

52
// Standard library headers
53
#include <algorithm>
54
#include <cmath>
55
#include <limits>
56
#include <sstream>
57
#include <vector>
58

59
// SimulationData headers
60
#include <constants.hpp>
61
#include <matvec.hpp>
62
#include <simulation_data_export.hpp>
63

64
// SimulationRunner header
65
#include <simulation_runner.hpp>
66

67
// NativeRunner headers
68
#include "find_element_hit.hpp"
69
#include "generate_ray.hpp"
70
#include "native_runner_types.hpp"
71
#include "process_interaction.hpp"
72
#include "pt_optimizations.hpp"
73
#include "sun_to_primary_stage.hpp"
74
#include "thread_manager.hpp"
75
#include "treemesh.hpp"
76

77
namespace SolTrace::NativeRunner
78
{
79

80
        using SolTrace::Result::RayEvent;
81
        using SolTrace::Runner::RunnerStatus;
82

83
        // Trace method
84
        RunnerStatus trace_native(
25✔
85
                thread_manager_ptr manager,
86
                TSystem *System,
87
                const std::vector<unsigned int> &seeds,
88
                uint_fast64_t nthreads,
89
                uint_fast64_t NumberOfRays,
90
                uint_fast64_t MaxNumberOfRays,
91
                bool IncludeSunShape,
92
                bool IncludeErrors,
93
                bool AsPowerTower)
94
        {
95
                // Initialize Sun
96
                Vector3d PosSunStage;
25✔
97
                if (!SunToPrimaryStage(manager,
25✔
98
                                                           System,
99
                                                           System->StageList[0].get(),
25✔
100
                                                           &System->Sun,
101
                                                           PosSunStage.data))
NEW
102
                        return RunnerStatus::ERROR;
×
103

104
                // Determine if PT optimizations should be applied
105
                bool PT_override = false;
25✔
106
                if (System->StageList.size() > 0 &&
57✔
107
                        (System->StageList[0]->ElementList.size() < 10 || System->StageList.size() == 1))
32✔
108
                {
109
                        PT_override = true;
20✔
110
                }
111

112
                // Calculate hash tree for reflection to receiver plane(polar coordinates).
113
                st_hash_tree sun_hash;
25✔
114
                st_hash_tree rec_hash;
25✔
115
                // double reccm_helio[3]; // receiver centroid in heliostat field coordinates
116
                Vector3d reccm_helio;
25✔
117
                if (!PT_override)
25✔
118
                {
119
                        SetupPTOptimizations(System, AsPowerTower, sun_hash,
5✔
120
                                                                 rec_hash, reccm_helio.data);
121
                }
122

123
                // Bundle many args into a struct because the compiler was
124
                // having trouble with all the arguments...
125
                ThreadInfo my_info;
25✔
126
                my_info.manager = manager;
25✔
127
                my_info.System = System;
25✔
128
                my_info.NumberOfRays = NumberOfRays / nthreads;
25✔
129

130
                if (my_info.NumberOfRays * nthreads < NumberOfRays)
25✔
NEW
131
                        my_info.NumberOfRays += 1;
×
132

133
                my_info.MaxNumberOfRays = MaxNumberOfRays;
25✔
134
                my_info.IncludeSunShape = IncludeSunShape;
25✔
135
                my_info.IncludeErrors = IncludeErrors;
25✔
136
                my_info.AsPowerTower = AsPowerTower;
25✔
137
                my_info.PosSunStage = PosSunStage;
25✔
138
                my_info.sun_hash = &sun_hash;
25✔
139
                my_info.rec_hash = &rec_hash;
25✔
140
                my_info.reccm_helio = reccm_helio;
25✔
141

142
                System->RayData.SetUp(nthreads, my_info.NumberOfRays);
25✔
143
                System->SunRayCount = 0;
25✔
144

145
                for (unsigned int k = 0; k < nthreads; ++k)
50✔
146
                {
147
                        ThreadManager::future my_future = std::async(
148
                                std::launch::async,
149
                                trace_single_compact,
150
                                k,
151
                                seeds[k],
25✔
152
                                my_info);
25✔
153

154
                        manager->manage(k, std::move(my_future));
25✔
155
                }
25✔
156

157
                return manager->monitor_until_completion();
25✔
158
        }
25✔
159

160
        RunnerStatus trace_single_thread(
25✔
161
                unsigned thread_id,
162
                thread_manager_ptr manager,
163
                TSystem *System,
164
                unsigned int seed,
165
                uint_fast64_t NumberOfRays,
166
                uint_fast64_t MaxNumberOfRays, // TODO: How to handle MaxRays?
167
                bool IncludeSunShape,
168
                bool IncludeErrors,
169
                bool AsPowerTower,
170
                const Vector3d &PosSunStage,
171
                st_hash_tree *sun_hash,
172
                st_hash_tree *rec_hash,
173
                const Vector3d &reccm_helio)
174
        {
175
                // Initialize variables
176
                // std::cout << "Seed: " << seed << std::endl;
177
                MTRand myrng(seed);
25✔
178

179
                // Determine if PT optimizations should be applied
180
                bool PT_override = false;
25✔
181
                if (System->StageList.size() > 0 &&
57✔
182
                        (System->StageList[0]->ElementList.size() < 10 ||
32✔
183
                         System->StageList.size() == 1))
7✔
184
                {
185
                        PT_override = true;
20✔
186
                }
187

188
                uint_fast64_t update_rate = std::min(
25✔
189
                        std::max(static_cast<uint_fast64_t>(1), NumberOfRays / 10),
50✔
190
                        static_cast<uint_fast64_t>(1000));
25✔
191
                uint_fast64_t update_count = 0;
25✔
192
                double total_work = System->StageList.size() * NumberOfRays;
25✔
193

194
                // Initialize Internal State Variables
195
                uint_fast64_t RayNumber = 1; // Ray Number of current ray
25✔
196
                bool PreviousStageHasRays = false;
25✔
197
                uint_fast64_t LastRayNumberInPreviousStage = NumberOfRays;
25✔
198

199
                // Define IncomingRays
200
                std::vector<GlobalRay_refactored> IncomingRays; // Vector of rays from previous stage, going into next stage
25✔
201
                IncomingRays.resize(NumberOfRays);
25✔
202

203
                // Start the clock
204
                // clock_t startTime = clock();
205
                // int rays_per_callback_estimate = 50;
206
                // uint_fast64_t RaysTracedTotal = 0;
207

208
                // Initialize stage variables
209
                uint_fast64_t StageDataArrayIndex = 0;
25✔
210
                uint_fast64_t PreviousStageDataArrayIndex = 0;
25✔
211
                uint_fast64_t n_rays_active = NumberOfRays;
25✔
212
                uint_fast64_t sun_ray_count_local = 0;
25✔
213

214
                // Loop through stages
215
                for (uint_fast64_t i = 0; i < System->StageList.size(); i++)
65✔
216
                {
217
                        // std::cout << "Processing stage " << i << "..." << std::endl;
218
                        // Check if previous stage has rays
219
                        bool StageHasRays = true;
41✔
220
                        if (i > 0 && PreviousStageHasRays == false)
41✔
221
                        {
222
                                StageHasRays = false;
×
223
                        }
224

225
                        // Get Current Stage
226
                        tstage_ptr Stage = System->StageList[i];
41✔
227

228
                        // Initialize stage variables
229
                        StageDataArrayIndex = 0;
41✔
230
                        PreviousStageDataArrayIndex = 0;
41✔
231

232
                        // Loop through rays
233
                        while (StageHasRays)
11,738,818✔
234
                        {
235
                                // Initialize Global Coordinates
236
                                double PosRayGlob[3] = {0.0, 0.0, 0.0};
11,738,818✔
237
                                double CosRayGlob[3] = {0.0, 0.0, 0.0};
11,738,818✔
238

239
                                // Initialize Stage Coordinates
240
                                double PosRayStage[3] = {0.0, 0.0, 0.0};
11,738,818✔
241
                                double CosRayStage[3] = {0.0, 0.0, 0.0};
11,738,818✔
242

243
                                // Initialize PT Optimization variables
244
                                bool has_elements = true;
11,738,818✔
245
                                std::vector<void *> sunint_elements;
11,738,818✔
246

247
                                // Get Ray
248
                                if (i == 0)
11,738,818✔
249
                                {
250
                                        // TODO: This function seems to ignore the MaxNumberOfRays
251
                                        // argument. Should fix that.
252

253
                                        // Make ray (if first stage)
254
                                        double PosRaySun[3];
255
                                        GenerateRay(myrng, PosSunStage.data, Stage->Origin,
11,017,808✔
256
                                                                Stage->RLocToRef, &System->Sun,
11,017,808✔
257
                                                                PosRayGlob, CosRayGlob, PosRaySun);
258
                                        sun_ray_count_local++;
11,017,808✔
259

260
                                        // If using PT optimizations, check if stage has elements
261
                                        // that could interact with ray
262
                                        if (!PT_override)
11,017,808✔
263
                                        {
264
                                                has_elements =
470,016✔
265
                                                        sun_hash->get_all_data_at_loc(sunint_elements,
470,016✔
266
                                                                                                                  PosRaySun[0],
267
                                                                                                                  PosRaySun[1]);
268
                                        }
269
                                }
270
                                else
271
                                {
272
                                        // Get ray from previous stage
273
                                        RayNumber = IncomingRays[StageDataArrayIndex].Num;
721,010✔
274
                                        CopyVec3(PosRayGlob, IncomingRays[StageDataArrayIndex].Pos);
721,010✔
275
                                        CopyVec3(CosRayGlob, IncomingRays[StageDataArrayIndex].Cos);
721,010✔
276
                                        StageDataArrayIndex++;
721,010✔
277
                                }
278

279
                                // transform the global incoming ray to local stage coordinates
280
                                TransformToLocal(PosRayGlob, CosRayGlob,
11,738,818✔
281
                                                                 Stage->Origin, Stage->RRefToLoc,
11,738,818✔
282
                                                                 PosRayStage, CosRayStage);
283

284
                                // Initialize internal variables for ray intersection tracing
285
                                bool RayInStage = true;
11,738,818✔
286
                                bool in_multi_hit_loop = false;
11,738,818✔
287
                                double LastPosRaySurfElement[3] = {0.0, 0.0, 0.0};
11,738,818✔
288
                                double LastCosRaySurfElement[3] = {0.0, 0.0, 0.0};
11,738,818✔
289
                                double LastPosRaySurfStage[3] = {0.0, 0.0, 0.0};
11,738,818✔
290
                                double LastCosRaySurfStage[3] = {0.0, 0.0, 0.0};
11,738,818✔
291
                                double LastDFXYZ[3] = {0.0, 0.0, 0.0};
11,738,818✔
292
                                uint_fast64_t LastElementNumber = 0;
11,738,818✔
293
                                uint_fast64_t LastRayNumber = 0;
11,738,818✔
294
                                int ErrorFlag;
295
                                int LastHitBackSide;
296
                                bool StageHit;
297
                                int MultipleHitCount = 0;
11,738,818✔
298
                                double PosRayOutElement[3] = {0.0, 0.0, 0.0};
11,738,818✔
299
                                double CosRayOutElement[3] = {0.0, 0.0, 0.0};
11,738,818✔
300

301
                                // Start Loop to trace ray until it leaves stage
302
                                bool RayIsAbsorbed = false;
11,738,818✔
303
                                while (RayInStage)
12,786,743✔
304
                                {
305
                                        // Set number of elements to search through
306
                                        uint_fast64_t nintelements = 0;
12,786,743✔
307
                                        std::vector<void *> reflint_elements;
12,786,743✔
308
                                        if (!PT_override) // if using opt AND first stage
12,786,743✔
309
                                        {
310
                                                nintelements = GetPTElements(AsPowerTower, Stage, i,
617,966✔
311
                                                                                                         in_multi_hit_loop, PosRayStage,
312
                                                                                                         reccm_helio.data, rec_hash,
617,966✔
313
                                                                                                         sunint_elements,
314
                                                                                                         reflint_elements, has_elements);
315
                                        }
316
                                        else
317
                                        {
318
                                                nintelements = Stage->ElementList.size();
12,168,777✔
319
                                        }
320

321
                                        // Find the element the ray hits
322
                                        FindElementHit(i, Stage, PT_override, AsPowerTower,
12,786,743✔
323
                                                                   nintelements, sunint_elements,
324
                                                                   reflint_elements,
325
                                                                   RayNumber, in_multi_hit_loop,
326
                                                                   PosRayStage, CosRayStage,
327
                                                                   LastPosRaySurfElement,
328
                                                                   LastCosRaySurfElement,
329
                                                                   LastDFXYZ,
330
                                                                   LastElementNumber, LastRayNumber,
331
                                                                   LastPosRaySurfStage, LastCosRaySurfStage,
332
                                                                   ErrorFlag, LastHitBackSide, StageHit);
333

334
                                        // Breakout if ray left stage
335
                                        if (!StageHit)
12,786,743✔
336
                                        {
337
                                                RayInStage = false;
10,924,304✔
338
                                                break;
10,924,304✔
339
                                        }
340

341
                                        // Increment MultipleHitCount
342
                                        MultipleHitCount++;
1,862,439✔
343

344
                                        if (i == 0 && MultipleHitCount == 1)
1,862,439✔
345
                                        {
346
                                                auto r = System->RayData.Append(thread_id,
347
                                                                                                                PosRayGlob,
348
                                                                                                                CosRayGlob,
349
                                                                                                                ELEMENT_NULL,
350
                                                                                                                i + 1,
890,718✔
351
                                                                                                                LastRayNumber,
352
                                                                                                                RayEvent::CREATE);
890,718✔
353
                                                if (r == nullptr)
890,718✔
354
                                                {
NEW
355
                                                        std::stringstream ss;
×
NEW
356
                                                        ss << "Thread " << thread_id
×
NEW
357
                                                           << " failed to record ray data.\n";
×
NEW
358
                                                        manager->error_log(ss.str());
×
NEW
359
                                                }
×
360
                                        }
890,718✔
361

362
                                        // Get optics and check for absorption
363
                                        const OpticalProperties *optics = 0;
1,862,439✔
364
                                        RayEvent rev = RayEvent::VIRTUAL;
1,862,439✔
365
                                        if (Stage->Virtual)
1,862,439✔
366
                                        {
367
                                                // If stage is virtual, there is no interaction
368
                                                CopyVec3(PosRayOutElement, LastPosRaySurfElement);
×
369
                                                CopyVec3(CosRayOutElement, LastCosRaySurfElement);
×
370
                                        }
371
                                        else
372
                                        {
373
                                                // trace through the interaction
374
                                                telement_ptr optelm = Stage->ElementList[LastElementNumber - 1];
1,862,439✔
375

376
                                                if (LastHitBackSide)
1,862,439✔
377
                                                        optics = &optelm->Optics.Back;
208,881✔
378
                                                else
379
                                                        optics = &optelm->Optics.Front;
1,653,558✔
380

381
                                                double TestValue;
382
                                                double UnitLastDFXYZ[3] = {0.0, 0.0, 0.0};
1,862,439✔
383
                                                double IncidentAngle = 0;
1,862,439✔
384
                                                // switch (optelm->InteractionType)
385
                                                switch (optics->my_type)
1,862,439✔
386
                                                {
387
                                                case InteractionType::REFRACTION: // refraction
194,853✔
388
                                                        // TODO: Implement transmissivity table?
389
                                                        // if (optics->UseTransmissivityTable)
390
                                                        // {
391
                                                        //         int npoints = optics->TransmissivityTable.size();
392
                                                        //         int m = 0;
393

394
                                                        //         UnitLastDFXYZ[0] = -LastDFXYZ[0] / sqrt(DOT(LastDFXYZ, LastDFXYZ));
395
                                                        //         UnitLastDFXYZ[1] = -LastDFXYZ[1] / sqrt(DOT(LastDFXYZ, LastDFXYZ));
396
                                                        //         UnitLastDFXYZ[2] = -LastDFXYZ[2] / sqrt(DOT(LastDFXYZ, LastDFXYZ));
397
                                                        //         IncidentAngle = acos(DOT(LastCosRaySurfElement, UnitLastDFXYZ)) * 1000.; //[mrad]
398
                                                        //         if (IncidentAngle >= optics->TransmissivityTable[npoints - 1].angle)
399
                                                        //         {
400
                                                        //                 TestValue = optics->TransmissivityTable[npoints - 1].trans;
401
                                                        //         }
402
                                                        //         else
403
                                                        //         {
404
                                                        //                 while (optics->TransmissivityTable[m].angle < IncidentAngle)
405
                                                        //                         m++;
406

407
                                                        //                 if (m == 0)
408
                                                        //                         TestValue = optics->TransmissivityTable[m].trans;
409
                                                        //                 else
410
                                                        //                         TestValue = (optics->TransmissivityTable[m].trans + optics->TransmissivityTable[m - 1].trans) / 2.0;
411
                                                        //         }
412
                                                        // }
413
                                                        // else
414
                                                        //         TestValue = optics->Transmissivity;
415
                                                        TestValue = optics->transmitivity;
194,853✔
416
                                                        rev = RayEvent::TRANSMIT;
194,853✔
417
                                                        break;
194,853✔
418
                                                case InteractionType::REFLECTION: // reflection
1,667,586✔
419
                                                        // TODO: Implement reflectivity table?
420
                                                        // if (optics->UseReflectivityTable)
421
                                                        // {
422
                                                        //         int npoints = optics->ReflectivityTable.size();
423
                                                        //         int m = 0;
424
                                                        //         UnitLastDFXYZ[0] = -LastDFXYZ[0] / sqrt(DOT(LastDFXYZ, LastDFXYZ));
425
                                                        //         UnitLastDFXYZ[1] = -LastDFXYZ[1] / sqrt(DOT(LastDFXYZ, LastDFXYZ));
426
                                                        //         UnitLastDFXYZ[2] = -LastDFXYZ[2] / sqrt(DOT(LastDFXYZ, LastDFXYZ));
427
                                                        //         IncidentAngle = acos(DOT(LastCosRaySurfElement, UnitLastDFXYZ)) * 1000.; //[mrad]
428
                                                        //         if (IncidentAngle >= optics->ReflectivityTable[npoints - 1].angle)
429
                                                        //         {
430
                                                        //                 TestValue = optics->ReflectivityTable[npoints - 1].refl;
431
                                                        //         }
432
                                                        //         else
433
                                                        //         {
434
                                                        //                 while (optics->ReflectivityTable[m].angle < IncidentAngle)
435
                                                        //                         m++;
436

437
                                                        //                 if (m == 0)
438
                                                        //                         TestValue = optics->ReflectivityTable[m].refl;
439
                                                        //                 else
440
                                                        //                         TestValue = (optics->ReflectivityTable[m].refl + optics->ReflectivityTable[m - 1].refl) / 2.0;
441
                                                        //         }
442
                                                        // }
443
                                                        // else
444
                                                        //         TestValue = optics->Reflectivity;
445
                                                        TestValue = optics->reflectivity;
1,667,586✔
446
                                                        rev = RayEvent::REFLECT;
1,667,586✔
447
                                                        break;
1,667,586✔
448
                                                default:
×
NEW
449
                                                        std::stringstream ss;
×
450
                                                        ss << "Bad optical interaction."
NEW
451
                                                           << " Type: " << static_cast<int>(optics->my_type)
×
NEW
452
                                                           << " Stage: " << i
×
NEW
453
                                                           << " Thread: " << thread_id
×
NEW
454
                                                           << "\n";
×
NEW
455
                                                        manager->error_log(ss.str());
×
UNCOV
456
                                                        return RunnerStatus::ERROR;
×
457
                                                }
458

459
                                                // Apply MonteCarlo probability of absorption. Limited
460
                                                // for now, but can make more complex later on if desired
461
                                                // if (TestValue <= myrng())
462
                                                double flip = myrng();
1,862,439✔
463
                                                if (TestValue <= flip)
1,862,439✔
464
                                                {
465
                                                        // ray was fully absorbed
466
                                                        RayIsAbsorbed = true;
802,306✔
467
                                                        break;
802,306✔
468
                                                }
469
                                        }
1,862,439✔
470

471
                                        // Process Interaction
472
                                        int_fast64_t k = LastElementNumber - 1;
1,060,133✔
473
                                        ProcessInteraction(System,
1,060,133✔
474
                                                                           myrng,
475
                                                                           IncludeSunShape,
476
                                                                           optics,
477
                                                                           IncludeErrors,
478
                                                                           i, Stage, // k,
479
                                                                           MultipleHitCount,
480
                                                                           LastDFXYZ,
481
                                                                           LastCosRaySurfElement,
482
                                                                           ErrorFlag,
483
                                                                           CosRayOutElement,
484
                                                                           LastPosRaySurfElement,
485
                                                                           PosRayOutElement);
486

487
                                        // Transform ray back to stage coordinate system
488
                                        TransformToReference(PosRayOutElement,
1,060,133✔
489
                                                                                 CosRayOutElement,
490
                                                                                 Stage->ElementList[k]->Origin,
1,060,133✔
491
                                                                                 Stage->ElementList[k]->RLocToRef,
1,060,133✔
492
                                                                                 PosRayStage,
493
                                                                                 CosRayStage);
494
                                        TransformToReference(PosRayStage,
1,060,133✔
495
                                                                                 CosRayStage,
496
                                                                                 Stage->Origin,
1,060,133✔
497
                                                                                 Stage->RLocToRef,
1,060,133✔
498
                                                                                 PosRayGlob,
499
                                                                                 CosRayGlob);
500

501
                                        System->RayData.Append(thread_id,
1,060,133✔
502
                                                                                   PosRayGlob,
503
                                                                                   CosRayGlob,
504
                                                                                   LastElementNumber,
505
                                                                                   i + 1,
1,060,133✔
506
                                                                                   LastRayNumber,
507
                                                                                   rev);
508

509
                                        // Break out if multiple hits are not allowed
510
                                        if (!Stage->MultiHitsPerRay)
1,060,133✔
511
                                        {
512
                                                StageHit = false;
12,208✔
513
                                                break;
12,208✔
514
                                        }
515
                                        else
516
                                        {
517
                                                in_multi_hit_loop = true;
1,047,925✔
518
                                        }
519
                                }
12,786,743✔
520

521
                                ++update_count;
11,738,818✔
522
                                if (update_count % update_rate == 0)
11,738,818✔
523
                                {
524
                                        double progress = update_count / total_work;
11,759✔
525
                                        manager->progress_update(thread_id, progress);
11,759✔
526
                                        if (manager->terminate(thread_id))
11,759✔
527
                                                return RunnerStatus::CANCEL;
1✔
528
                                }
529

530
                                // Handle if Ray was absorbed
531
                                if (RayIsAbsorbed)
11,738,817✔
532
                                {
533
                                        TransformToReference(LastPosRaySurfStage,
802,306✔
534
                                                                                 LastCosRaySurfStage,
535
                                                                                 Stage->Origin,
802,306✔
536
                                                                                 Stage->RLocToRef,
802,306✔
537
                                                                                 PosRayGlob,
538
                                                                                 CosRayGlob);
539

540
                                        System->RayData.Append(thread_id,
802,306✔
541
                                                                                   PosRayGlob,
542
                                                                                   CosRayGlob,
543
                                                                                   LastElementNumber,
544
                                                                                   i + 1,
802,306✔
545
                                                                                   LastRayNumber,
546
                                                                                   RayEvent::ABSORB);
547

548
                                        n_rays_active--;
802,306✔
549

550
                                        // ray was fully absorbed
551
                                        if (RayNumber == LastRayNumberInPreviousStage)
802,306✔
552
                                        {
553
                                                PreviousStageHasRays = false;
17✔
554
                                                if (PreviousStageDataArrayIndex > 0)
17✔
555
                                                {
556
                                                        PreviousStageDataArrayIndex--;
16✔
557
                                                        PreviousStageHasRays = true;
16✔
558
                                                }
559
                                                break;
17✔
560
                                        }
561
                                        else
562
                                        {
563
                                                if (i == 0)
802,289✔
564
                                                {
565
                                                        if (RayNumber == NumberOfRays)
145,482✔
566
                                                                break;
×
567
                                                        else
568
                                                                RayNumber++;
145,482✔
569
                                                }
570

571
                                                // Next ray in loop
572
                                                continue;
802,289✔
573
                                        }
574
                                }
575

576
                                // Ray has left the stage
577
                                bool FlagMiss = false;
10,936,511✔
578
                                if (i == 0)
10,936,511✔
579
                                {
580
                                        if (MultipleHitCount == 0)
10,872,319✔
581
                                        {
582
                                                // Ray in first stage missed stage entirely
583
                                                // Generate new ray
584
                                                continue;
10,127,089✔
585
                                        }
586
                                        else
587
                                        {
588
                                                // Ray hit an element, so save it for next stage
589
                                                CopyVec3(IncomingRays[PreviousStageDataArrayIndex].Pos,
745,230✔
590
                                                                 PosRayGlob);
591
                                                CopyVec3(IncomingRays[PreviousStageDataArrayIndex].Cos,
745,230✔
592
                                                                 CosRayGlob);
593
                                                IncomingRays[PreviousStageDataArrayIndex].Num = RayNumber;
745,230✔
594

595
                                                // Is Ray the last in the stage?
596
                                                if (RayNumber == NumberOfRays)
745,230✔
597
                                                {
598
                                                        StageHasRays = false;
18✔
599
                                                        break;
18✔
600
                                                }
601

602
                                                PreviousStageDataArrayIndex++;
745,212✔
603
                                                PreviousStageHasRays = true;
745,212✔
604

605
                                                // Move on to next ray
606
                                                RayNumber++;
745,212✔
607
                                                continue;
745,212✔
608
                                        }
609
                                }
610
                                else
611
                                {
612
                                        // After the first stage
613
                                        // Ray hit element OR is traced through stage
614
                                        if (Stage->TraceThrough || MultipleHitCount > 0)
64,192✔
615
                                        {
616
                                                // Ray is saved for the next stage
617
                                                CopyVec3(IncomingRays[PreviousStageDataArrayIndex].Pos,
57,836✔
618
                                                                 PosRayGlob);
619
                                                CopyVec3(IncomingRays[PreviousStageDataArrayIndex].Cos,
57,836✔
620
                                                                 CosRayGlob);
621
                                                IncomingRays[PreviousStageDataArrayIndex].Num = RayNumber;
57,836✔
622

623
                                                // Check if ray is last in stage
624
                                                if (RayNumber == LastRayNumberInPreviousStage)
57,836✔
625
                                                {
626
                                                        StageHasRays = false;
4✔
627
                                                        break;
4✔
628
                                                }
629

630
                                                PreviousStageDataArrayIndex++;
57,832✔
631
                                                PreviousStageHasRays = true;
57,832✔
632

633
                                                if (MultipleHitCount == 0)
57,832✔
634
                                                {
635
                                                        FlagMiss = true;
46,529✔
636
                                                }
637

638
                                                // Go to next ray
639
                                                continue;
57,832✔
640
                                        }
641
                                        // Ray missed stage entirely and is not traced
642
                                        else
643
                                        {
644
                                                FlagMiss = true;
6,356✔
645
                                        }
646

647
                                        // Handle FlagMiss condition (
648
                                        if (FlagMiss == true)
6,356✔
649
                                        {
650
                                                LastRayNumber = RayNumber;
6,356✔
651

652
                                                System->RayData.Append(thread_id,
6,356✔
653
                                                                                           PosRayGlob,
654
                                                                                           CosRayGlob,
655
                                                                                           ELEMENT_NULL,
656
                                                                                           i + 1,
6,356✔
657
                                                                                           LastRayNumber,
658
                                                                                           RayEvent::EXIT);
659

660
                                                n_rays_active--;
6,356✔
661

662
                                                if (RayNumber == LastRayNumberInPreviousStage)
6,356✔
663
                                                {
664
                                                        if (!Stage->TraceThrough)
1✔
665
                                                        {
666
                                                                PreviousStageHasRays = false;
1✔
667
                                                                if (PreviousStageDataArrayIndex > 0)
1✔
668
                                                                {
669
                                                                        PreviousStageHasRays = true;
1✔
670
                                                                        PreviousStageDataArrayIndex--; // last ray was previous one
1✔
671
                                                                }
672
                                                        }
673

674
                                                        // Exit stage
675
                                                        StageHasRays = false;
1✔
676
                                                        break;
1✔
677
                                                }
678
                                                else
679
                                                {
680
                                                        if (i == 0)
6,355✔
681
                                                                RayNumber++; // generate new sun ray
×
682

683
                                                        // Start new ray
684
                                                        continue;
6,355✔
685
                                                }
686
                                        }
687
                                }
688
                        }
11,738,818✔
689

690
                        // EndStage section...
691

692
                        // skipping save_st_data logic
693

694
                        if (!PreviousStageHasRays)
40✔
695
                        {
696
                                LastRayNumberInPreviousStage = 0;
2✔
697
                                continue; // No rays to carry forward
2✔
698
                        }
699

700
                        if (PreviousStageDataArrayIndex < IncomingRays.size())
38✔
701
                        {
702
                                LastRayNumberInPreviousStage = IncomingRays[PreviousStageDataArrayIndex].Num;
38✔
703
                                if (LastRayNumberInPreviousStage == 0)
38✔
704
                                {
705
                                        return RunnerStatus::ERROR;
×
706
                                }
707
                        }
708
                        else
709
                        {
710
                                return RunnerStatus::ERROR;
×
711
                        }
712
                }
41✔
713

714
                // Close out any remaining rays as misses
715
                unsigned idx = System->StageList.size() - 1;
24✔
716
                tstage_ptr Stage = System->StageList[idx];
24✔
717
                for (uint_fast64_t k = 0; k < n_rays_active; ++k)
81,479✔
718
                {
719
                        GlobalRay_refactored ray = IncomingRays[k];
81,455✔
720
                        System->RayData.Append(thread_id,
81,455✔
721
                                                                   ray.Pos,
722
                                                                   ray.Cos,
723
                                                                   ELEMENT_NULL,
724
                                                                   idx + 1,
81,455✔
725
                                                                   ray.Num,
726
                                                                   RayEvent::EXIT);
727
                }
728

729
                // System->SunRayCount is atomic so this is thread safe
730
                System->SunRayCount += sun_ray_count_local;
24✔
731

732
                return RunnerStatus::SUCCESS;
24✔
733
        }
25✔
734

735
} // namespace SolTrace::NativeRunner
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc