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

NREL / SolTrace / 20378883693

19 Dec 2025 06:23PM UTC coverage: 89.332% (+0.1%) from 89.184%
20378883693

Pull #94

github

web-flow
Merge 5886fcdf4 into a73a760a4
Pull Request #94: Round robin validation tests

6029 of 6749 relevant lines covered (89.33%)

34032352.27 hits per line

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

95.05
/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 <mutex>
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 "treemesh.hpp"
75

76
namespace SolTrace::NativeRunner
77
{
78

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

82
        // Trace method
83
        RunnerStatus trace_native(
60✔
84
                TSystem *System,
85
                unsigned int seed,
86
                uint_fast64_t NumberOfRays,
87
                uint_fast64_t MaxNumberOfRays,
88
                bool IncludeSunShape,
89
                bool IncludeErrors,
90
                bool AsPowerTower)
91
        {
92
                // Create isolated scope for lock guard
93
                {
94
                        std::lock_guard<std::mutex> lk(System->state_mutex);
60✔
95
                        System->progress = 0.0;
60✔
96
                        System->cancel = false;
60✔
97
                        System->current_state = RunnerStatus::RUNNING;
60✔
98
                }
60✔
99

100
                // Determine if PT optimizations should be applied
101
                bool PT_override = false;
60✔
102
                if (System->StageList.size() > 0 &&
158✔
103
                        (System->StageList[0]->ElementList.size() < 10 || System->StageList.size() == 1))
98✔
104
                {
105
                        PT_override = true;
24✔
106
                }
107

108
                // Initialize variables
109
                // std::cout << "Seed: " << seed << std::endl;
110
                MTRand myrng(seed);
60✔
111
                int myrng_counter = 0;
60✔
112

113
                uint_fast64_t update_rate = std::min(
60✔
114
                        std::max(static_cast<uint_fast64_t>(1), NumberOfRays / 10),
120✔
115
                        static_cast<uint_fast64_t>(1000));
60✔
116
                uint_fast64_t update_count = 0;
60✔
117
                double total_work = System->StageList.size() * NumberOfRays;
60✔
118

119
                // Initialize Internal State Variables
120
                uint_fast64_t RayNumber = 1; // Ray Number of current ray
60✔
121
                bool PreviousStageHasRays = false;
60✔
122
                uint_fast64_t LastRayNumberInPreviousStage = NumberOfRays;
60✔
123

124
                // Define IncomingRays
125
                std::vector<GlobalRay_refactored> IncomingRays; // Vector of rays from previous stage, going into next stage
60✔
126
                IncomingRays.resize(NumberOfRays);
60✔
127

128
                // Initialize Sun
129
                double PosSunStage[3] = {0.0, 0.0, 0.0};
60✔
130
                if (!SunToPrimaryStage(System,
60✔
131
                                                           System->StageList[0].get(),
60✔
132
                                                           &System->Sun,
133
                                                           PosSunStage))
134
                        return RunnerStatus::ERROR;
×
135

136
                // Calculate hash tree for reflection to receiver plane(polar coordinates).
137
                st_hash_tree sun_hash;
60✔
138
                st_hash_tree rec_hash;
60✔
139
                double reccm_helio[3]; // receiver centroid in heliostat field coordinates
140
                if (!PT_override)
60✔
141
                {
142
                        SetupPTOptimizations(System, AsPowerTower, sun_hash,
36✔
143
                                                                 rec_hash, reccm_helio);
144
                }
145

146
                System->SunRayCount = 0;
60✔
147
                // Start the clock
148
                clock_t startTime = clock();
60✔
149
                // int rays_per_callback_estimate = 50;
150
                uint_fast64_t RaysTracedTotal = 0;
60✔
151

152
                // Initialize stage variables
153
                uint_fast64_t StageDataArrayIndex = 0;
60✔
154
                uint_fast64_t PreviousStageDataArrayIndex = 0;
60✔
155
                uint_fast64_t n_rays_active = NumberOfRays;
60✔
156

157
                // Loop through stages
158
                for (uint_fast64_t i = 0; i < System->StageList.size(); i++)
170✔
159
                {
160
                        // std::cout << "Processing stage " << i << "..." << std::endl;
161
                        // Check if previous stage has rays
162
                        bool StageHasRays = true;
111✔
163
                        if (i > 0 && PreviousStageHasRays == false)
111✔
164
                        {
165
                                StageHasRays = false;
×
166
                        }
167

168
                        // Get Current Stage
169
                        tstage_ptr Stage = System->StageList[i];
111✔
170

171
                        // Initialize stage variables
172
                        StageDataArrayIndex = 0;
111✔
173
                        PreviousStageDataArrayIndex = 0;
111✔
174

175
                        // Loop through rays
176
                        while (StageHasRays)
98,769,283✔
177
                        {
178
                                // Initialize Global Coordinates
179
                                double PosRayGlob[3] = {0.0, 0.0, 0.0};
98,769,283✔
180
                                double CosRayGlob[3] = {0.0, 0.0, 0.0};
98,769,283✔
181

182
                                // Initialize Stage Coordinates
183
                                double PosRayStage[3] = {0.0, 0.0, 0.0};
98,769,283✔
184
                                double CosRayStage[3] = {0.0, 0.0, 0.0};
98,769,283✔
185

186
                                // Initialize PT Optimization variables
187
                                bool has_elements = true;
98,769,283✔
188
                                std::vector<void *> sunint_elements;
98,769,283✔
189

190
                                // Get Ray
191
                                if (i == 0)
98,769,283✔
192
                                {
193
                                        // TODO: This function seems to ignore the MaxNumberOfRays
194
                                        // argument. Should fix that.
195

196
                                        // Make ray (if first stage)
197
                                        double PosRaySun[3];
198
                                        GenerateRay(myrng, PosSunStage, Stage->Origin,
86,499,280✔
199
                                                                Stage->RLocToRef, &System->Sun,
86,499,280✔
200
                                                                PosRayGlob, CosRayGlob, PosRaySun);
201
                                        myrng_counter++;
86,499,280✔
202
                                        System->SunRayCount++;
86,499,280✔
203

204
                                        // If using PT optimizations, check if stage has elements
205
                                        // that could interact with ray
206
                                        if (!PT_override)
86,499,280✔
207
                                        {
208
                                                has_elements =
74,985,489✔
209
                                                        sun_hash.get_all_data_at_loc(sunint_elements,
74,985,489✔
210
                                                                                                                 PosRaySun[0],
211
                                                                                                                 PosRaySun[1]);
212
                                        }
213
                                }
214
                                else
215
                                {
216
                                        // Get ray from previous stage
217
                                        RayNumber = IncomingRays[StageDataArrayIndex].Num;
12,270,003✔
218
                                        CopyVec3(PosRayGlob, IncomingRays[StageDataArrayIndex].Pos);
12,270,003✔
219
                                        CopyVec3(CosRayGlob, IncomingRays[StageDataArrayIndex].Cos);
12,270,003✔
220
                                        StageDataArrayIndex++;
12,270,003✔
221
                                }
222

223
                                // transform the global incoming ray to local stage coordinates
224
                                TransformToLocal(PosRayGlob, CosRayGlob,
98,769,283✔
225
                                                                 Stage->Origin, Stage->RRefToLoc,
98,769,283✔
226
                                                                 PosRayStage, CosRayStage);
227

228
                                // Initialize internal variables for ray intersection tracing
229
                                bool RayInStage = true;
98,769,283✔
230
                                bool in_multi_hit_loop = false;
98,769,283✔
231
                                double LastPosRaySurfElement[3] = {0.0, 0.0, 0.0};
98,769,283✔
232
                                double LastCosRaySurfElement[3] = {0.0, 0.0, 0.0};
98,769,283✔
233
                                double LastPosRaySurfStage[3] = {0.0, 0.0, 0.0};
98,769,283✔
234
                                double LastCosRaySurfStage[3] = {0.0, 0.0, 0.0};
98,769,283✔
235
                                double LastDFXYZ[3] = {0.0, 0.0, 0.0};
98,769,283✔
236
                                uint_fast64_t LastElementNumber = 0;
98,769,283✔
237
                                uint_fast64_t LastRayNumber = 0;
98,769,283✔
238
                                int ErrorFlag;
239
                                int LastHitBackSide;
240
                                bool StageHit;
241
                                int MultipleHitCount = 0;
98,769,283✔
242
                                double PosRayOutElement[3] = {0.0, 0.0, 0.0};
98,769,283✔
243
                                double CosRayOutElement[3] = {0.0, 0.0, 0.0};
98,769,283✔
244

245
                                // Start Loop to trace ray until it leaves stage
246
                                bool RayIsAbsorbed = false;
98,769,283✔
247
                                while (RayInStage)
112,164,411✔
248
                                {
249
                                        // Set number of elements to search through
250
                                        uint_fast64_t nintelements = 0;
112,164,411✔
251
                                        std::vector<void *> reflint_elements;
112,164,411✔
252
                                        if (!PT_override) // if using opt AND first stage
112,164,411✔
253
                                        {
254
                                                nintelements = GetPTElements(AsPowerTower, Stage, i,
98,308,866✔
255
                                                                                                         in_multi_hit_loop, PosRayStage,
256
                                                                                                         reccm_helio, rec_hash,
257
                                                                                                         sunint_elements,
258
                                                                                                         reflint_elements, has_elements);
259
                                        }
260
                                        else
261
                                        {
262
                                                nintelements = Stage->ElementList.size();
13,855,545✔
263
                                        }
264

265
                                        // Find the element the ray hits
266
                                        FindElementHit(i, Stage, PT_override, AsPowerTower,
112,164,411✔
267
                                                                   nintelements, sunint_elements,
268
                                                                   reflint_elements,
269
                                                                   RayNumber, in_multi_hit_loop,
270
                                                                   PosRayStage, CosRayStage,
271
                                                                   LastPosRaySurfElement,
272
                                                                   LastCosRaySurfElement,
273
                                                                   LastDFXYZ,
274
                                                                   LastElementNumber, LastRayNumber,
275
                                                                   LastPosRaySurfStage, LastCosRaySurfStage,
276
                                                                   ErrorFlag, LastHitBackSide, StageHit);
277

278
                                        // Breakout if ray left stage
279
                                        if (!StageHit)
112,164,411✔
280
                                        {
281
                                                RayInStage = false;
85,665,088✔
282
                                                break;
85,665,088✔
283
                                        }
284

285
                                        // Increment MultipleHitCount
286
                                        MultipleHitCount++;
26,499,323✔
287

288
                                        if (i == 0 && MultipleHitCount == 1)
26,499,323✔
289
                                        {
290
                                                System->RayData.Append(PosRayGlob,
13,990,436✔
291
                                                                                           CosRayGlob,
292
                                                                                           ELEMENT_NULL,
293
                                                                                           i + 1,
13,990,436✔
294
                                                                                           LastRayNumber,
295
                                                                                           RayEvent::CREATE);
296
                                        }
297

298
                                        // Get optics and check for absorption
299
                                        const OpticalProperties *optics = 0;
26,499,323✔
300
                                        RayEvent rev = RayEvent::VIRTUAL;
26,499,323✔
301
                                        if (Stage->Virtual)
26,499,323✔
302
                                        {
303
                                                // If stage is virtual, there is no interaction
304
                                                CopyVec3(PosRayOutElement, LastPosRaySurfElement);
×
305
                                                CopyVec3(CosRayOutElement, LastCosRaySurfElement);
×
306
                                        }
307
                                        else
308
                                        {
309
                                                // trace through the interaction
310
                                                telement_ptr optelm = Stage->ElementList[LastElementNumber - 1];
26,499,323✔
311

312
                                                if (LastHitBackSide)
26,499,323✔
313
                                                        optics = &optelm->Optics.Back;
1,098,538✔
314
                                                else
315
                                                        optics = &optelm->Optics.Front;
25,400,785✔
316

317
                                                double TestValue;
318
                                                double UnitLastDFXYZ[3] = {0.0, 0.0, 0.0};
26,499,323✔
319
                                                double IncidentAngle = 0;
26,499,323✔
320
                                                // switch (optelm->InteractionType)
321
                                                switch (optics->my_type)
26,499,323✔
322
                                                {
323
                                                case InteractionType::REFRACTION: // refraction
194,853✔
324
                                                        // TODO: Implement transmissivity table?
325
                                                        // if (optics->UseTransmissivityTable)
326
                                                        // {
327
                                                        //         int npoints = optics->TransmissivityTable.size();
328
                                                        //         int m = 0;
329

330
                                                        //         UnitLastDFXYZ[0] = -LastDFXYZ[0] / sqrt(DOT(LastDFXYZ, LastDFXYZ));
331
                                                        //         UnitLastDFXYZ[1] = -LastDFXYZ[1] / sqrt(DOT(LastDFXYZ, LastDFXYZ));
332
                                                        //         UnitLastDFXYZ[2] = -LastDFXYZ[2] / sqrt(DOT(LastDFXYZ, LastDFXYZ));
333
                                                        //         IncidentAngle = acos(DOT(LastCosRaySurfElement, UnitLastDFXYZ)) * 1000.; //[mrad]
334
                                                        //         if (IncidentAngle >= optics->TransmissivityTable[npoints - 1].angle)
335
                                                        //         {
336
                                                        //                 TestValue = optics->TransmissivityTable[npoints - 1].trans;
337
                                                        //         }
338
                                                        //         else
339
                                                        //         {
340
                                                        //                 while (optics->TransmissivityTable[m].angle < IncidentAngle)
341
                                                        //                         m++;
342

343
                                                        //                 if (m == 0)
344
                                                        //                         TestValue = optics->TransmissivityTable[m].trans;
345
                                                        //                 else
346
                                                        //                         TestValue = (optics->TransmissivityTable[m].trans + optics->TransmissivityTable[m - 1].trans) / 2.0;
347
                                                        //         }
348
                                                        // }
349
                                                        // else
350
                                                        //         TestValue = optics->Transmissivity;
351
                                                        TestValue = optics->transmitivity;
194,853✔
352
                                                        rev = RayEvent::TRANSMIT;
194,853✔
353
                                                        break;
194,853✔
354
                                                case InteractionType::REFLECTION: // reflection
26,304,470✔
355
                                                        // TODO: Implement reflectivity table?
356
                                                        // if (optics->UseReflectivityTable)
357
                                                        // {
358
                                                        //         int npoints = optics->ReflectivityTable.size();
359
                                                        //         int m = 0;
360
                                                        //         UnitLastDFXYZ[0] = -LastDFXYZ[0] / sqrt(DOT(LastDFXYZ, LastDFXYZ));
361
                                                        //         UnitLastDFXYZ[1] = -LastDFXYZ[1] / sqrt(DOT(LastDFXYZ, LastDFXYZ));
362
                                                        //         UnitLastDFXYZ[2] = -LastDFXYZ[2] / sqrt(DOT(LastDFXYZ, LastDFXYZ));
363
                                                        //         IncidentAngle = acos(DOT(LastCosRaySurfElement, UnitLastDFXYZ)) * 1000.; //[mrad]
364
                                                        //         if (IncidentAngle >= optics->ReflectivityTable[npoints - 1].angle)
365
                                                        //         {
366
                                                        //                 TestValue = optics->ReflectivityTable[npoints - 1].refl;
367
                                                        //         }
368
                                                        //         else
369
                                                        //         {
370
                                                        //                 while (optics->ReflectivityTable[m].angle < IncidentAngle)
371
                                                        //                         m++;
372

373
                                                        //                 if (m == 0)
374
                                                        //                         TestValue = optics->ReflectivityTable[m].refl;
375
                                                        //                 else
376
                                                        //                         TestValue = (optics->ReflectivityTable[m].refl + optics->ReflectivityTable[m - 1].refl) / 2.0;
377
                                                        //         }
378
                                                        // }
379
                                                        // else
380
                                                        //         TestValue = optics->Reflectivity;
381
                                                        TestValue = optics->reflectivity;
26,304,470✔
382
                                                        rev = RayEvent::REFLECT;
26,304,470✔
383
                                                        break;
26,304,470✔
384
                                                default:
×
385
                                                        System->errlog(
×
386
                                                                "Bad optical interaction type = %d (stage %d)",
387
                                                                i, optics->my_type);
388
                                                        return RunnerStatus::ERROR;
×
389
                                                }
390

391
                                                // Apply MonteCarlo probability of absorption. Limited
392
                                                // for now, but can make more complex later on if desired
393
                                                // if (TestValue <= myrng())
394
                                                double flip = myrng();
26,499,323✔
395
                                                if (TestValue <= flip)
26,499,323✔
396
                                                {
397
                                                        myrng_counter++;
13,091,987✔
398
                                                        // ray was fully absorbed
399
                                                        RayIsAbsorbed = true;
13,091,987✔
400
                                                        break;
13,091,987✔
401
                                                }
402
                                        }
26,499,323✔
403

404
                                        // Process Interaction
405
                                        int_fast64_t k = LastElementNumber - 1;
13,407,336✔
406
                                        ProcessInteraction(System, myrng, IncludeSunShape,
13,407,336✔
407
                                                                           optics,
408
                                                                           IncludeErrors,
409
                                                                           i, Stage, // k,
410
                                                                           MultipleHitCount, LastDFXYZ,
411
                                                                           LastCosRaySurfElement, ErrorFlag,
412
                                                                           CosRayOutElement, LastPosRaySurfElement,
413
                                                                           PosRayOutElement, myrng_counter);
414

415
                                        // Transform ray back to stage coordinate system
416
                                        TransformToReference(PosRayOutElement, CosRayOutElement,
13,407,336✔
417
                                                                                 Stage->ElementList[k]->Origin,
13,407,336✔
418
                                                                                 Stage->ElementList[k]->RLocToRef,
13,407,336✔
419
                                                                                 PosRayStage, CosRayStage);
420
                                        TransformToReference(PosRayStage, CosRayStage,
13,407,336✔
421
                                                                                 Stage->Origin, Stage->RLocToRef,
13,407,336✔
422
                                                                                 PosRayGlob, CosRayGlob);
423

424
                                        System->RayData.Append(PosRayGlob,
13,407,336✔
425
                                                                                   CosRayGlob,
426
                                                                                   LastElementNumber,
427
                                                                                   i + 1,
13,407,336✔
428
                                                                                   LastRayNumber,
429
                                                                                   rev);
430

431
                                        // Break out if multiple hits are not allowed
432
                                        if (!Stage->MultiHitsPerRay)
13,407,336✔
433
                                        {
434
                                                StageHit = false;
12,208✔
435
                                                break;
12,208✔
436
                                        }
437
                                        else
438
                                        {
439
                                                in_multi_hit_loop = true;
13,395,128✔
440
                                        }
441
                                }
112,164,411✔
442

443
                                ++update_count;
98,769,283✔
444
                                if (update_count % update_rate == 0)
98,769,283✔
445
                                {
446
                                        double progress = update_count / total_work;
98,772✔
447
                                        std::lock_guard<std::mutex> lk(System->state_mutex);
98,772✔
448
                                        if (System->cancel)
98,772✔
449
                                        {
450
                                                return RunnerStatus::CANCEL;
1✔
451
                                        }
452
                                        else
453
                                        {
454
                                                System->progress = progress;
98,771✔
455
                                        }
456
                                }
98,772✔
457

458
                                // Handle if Ray was absorbed
459
                                if (RayIsAbsorbed)
98,769,282✔
460
                                {
461
                                        TransformToReference(LastPosRaySurfStage,
13,091,987✔
462
                                                                                 LastCosRaySurfStage,
463
                                                                                 Stage->Origin,
13,091,987✔
464
                                                                                 Stage->RLocToRef,
13,091,987✔
465
                                                                                 PosRayGlob,
466
                                                                                 CosRayGlob);
467

468
                                        System->RayData.Append(PosRayGlob,
13,091,987✔
469
                                                                                   CosRayGlob,
470
                                                                                   LastElementNumber,
471
                                                                                   i + 1,
13,091,987✔
472
                                                                                   LastRayNumber,
473
                                                                                   RayEvent::ABSORB);
474

475
                                        n_rays_active--;
13,091,987✔
476

477
                                        // ray was fully absorbed
478
                                        if (RayNumber == LastRayNumberInPreviousStage)
13,091,987✔
479
                                        {
480
                                                PreviousStageHasRays = false;
56✔
481
                                                if (PreviousStageDataArrayIndex > 0)
56✔
482
                                                {
483
                                                        PreviousStageDataArrayIndex--;
52✔
484
                                                        PreviousStageHasRays = true;
52✔
485
                                                }
486
                                                break;
56✔
487
                                        }
488
                                        else
489
                                        {
490
                                                if (i == 0)
13,091,931✔
491
                                                {
492
                                                        if (RayNumber == NumberOfRays)
1,696,466✔
493
                                                                break;
×
494
                                                        else
495
                                                                RayNumber++;
1,696,466✔
496
                                                }
497

498
                                                // Next ray in loop
499
                                                continue;
13,091,931✔
500
                                        }
501
                                }
502

503
                                // Ray has left the stage
504
                                bool FlagMiss = false;
85,677,295✔
505
                                if (i == 0)
85,677,295✔
506
                                {
507
                                        if (MultipleHitCount == 0)
84,802,802✔
508
                                        {
509
                                                // Ray in first stage missed stage entirely
510
                                                // Generate new ray
511
                                                continue;
72,508,843✔
512
                                        }
513
                                        else
514
                                        {
515
                                                // Ray hit an element, so save it for next stage
516
                                                CopyVec3(IncomingRays[PreviousStageDataArrayIndex].Pos,
12,293,959✔
517
                                                                 PosRayGlob);
518
                                                CopyVec3(IncomingRays[PreviousStageDataArrayIndex].Cos,
12,293,959✔
519
                                                                 CosRayGlob);
520
                                                IncomingRays[PreviousStageDataArrayIndex].Num = RayNumber;
12,293,959✔
521

522
                                                // Is Ray the last in the stage?
523
                                                if (RayNumber == NumberOfRays)
12,293,959✔
524
                                                {
525
                                                        StageHasRays = false;
48✔
526
                                                        break;
48✔
527
                                                }
528

529
                                                PreviousStageDataArrayIndex++;
12,293,911✔
530
                                                PreviousStageHasRays = true;
12,293,911✔
531

532
                                                // Move on to next ray
533
                                                RayNumber++;
12,293,911✔
534
                                                continue;
12,293,911✔
535
                                        }
536
                                }
537
                                else
538
                                {
539
                                        // After the first stage
540
                                        // Ray hit element OR is traced through stage
541
                                        if (Stage->TraceThrough || MultipleHitCount > 0)
874,493✔
542
                                        {
543
                                                // Ray is saved for the next stage
544
                                                CopyVec3(IncomingRays[PreviousStageDataArrayIndex].Pos,
868,137✔
545
                                                                 PosRayGlob);
546
                                                CopyVec3(IncomingRays[PreviousStageDataArrayIndex].Cos,
868,137✔
547
                                                                 CosRayGlob);
548
                                                IncomingRays[PreviousStageDataArrayIndex].Num = RayNumber;
868,137✔
549

550
                                                // Check if ray is last in stage
551
                                                if (RayNumber == LastRayNumberInPreviousStage)
868,137✔
552
                                                {
553
                                                        StageHasRays = false;
5✔
554
                                                        break;
5✔
555
                                                }
556

557
                                                PreviousStageDataArrayIndex++;
868,132✔
558
                                                PreviousStageHasRays = true;
868,132✔
559

560
                                                if (MultipleHitCount == 0)
868,132✔
561
                                                {
562
                                                        FlagMiss = true;
815,494✔
563
                                                }
564

565
                                                // Go to next ray
566
                                                continue;
868,132✔
567
                                        }
568
                                        // Ray missed stage entirely and is not traced
569
                                        else
570
                                        {
571
                                                FlagMiss = true;
6,356✔
572
                                        }
573

574
                                        // Handle FlagMiss condition (
575
                                        if (FlagMiss == true)
6,356✔
576
                                        {
577
                                                LastRayNumber = RayNumber;
6,356✔
578

579
                                                System->RayData.Append(PosRayGlob,
6,356✔
580
                                                                                           CosRayGlob,
581
                                                                                           ELEMENT_NULL,
582
                                                                                           i + 1,
6,356✔
583
                                                                                           LastRayNumber,
584
                                                                                           RayEvent::EXIT);
585

586
                                                n_rays_active--;
6,356✔
587

588
                                                if (RayNumber == LastRayNumberInPreviousStage)
6,356✔
589
                                                {
590
                                                        if (!Stage->TraceThrough)
1✔
591
                                                        {
592
                                                                PreviousStageHasRays = false;
1✔
593
                                                                if (PreviousStageDataArrayIndex > 0)
1✔
594
                                                                {
595
                                                                        PreviousStageHasRays = true;
1✔
596
                                                                        PreviousStageDataArrayIndex--; // last ray was previous one
1✔
597
                                                                }
598
                                                        }
599

600
                                                        // Exit stage
601
                                                        StageHasRays = false;
1✔
602
                                                        break;
1✔
603
                                                }
604
                                                else
605
                                                {
606
                                                        if (i == 0)
6,355✔
607
                                                                RayNumber++; // generate new sun ray
×
608

609
                                                        // Start new ray
610
                                                        continue;
6,355✔
611
                                                }
612
                                        }
613
                                }
614
                        }
98,769,283✔
615

616
                        // EndStage section...
617

618
                        // skipping save_st_data logic
619

620
                        if (!PreviousStageHasRays)
110✔
621
                        {
622
                                LastRayNumberInPreviousStage = 0;
5✔
623
                                continue; // No rays to carry forward
5✔
624
                        }
625

626
                        if (PreviousStageDataArrayIndex < IncomingRays.size())
105✔
627
                        {
628
                                LastRayNumberInPreviousStage = IncomingRays[PreviousStageDataArrayIndex].Num;
105✔
629
                                if (LastRayNumberInPreviousStage == 0)
105✔
630
                                {
631
                                        return RunnerStatus::ERROR;
×
632
                                }
633
                        }
634
                        else
635
                        {
636
                                return RunnerStatus::ERROR;
×
637
                        }
638
                }
111✔
639

640
                // Close out any remaining rays as misses
641
                unsigned idx = System->StageList.size() - 1;
59✔
642
                tstage_ptr Stage = System->StageList[idx];
59✔
643
                for (uint_fast64_t k = 0; k < n_rays_active; ++k)
891,793✔
644
                {
645
                        GlobalRay_refactored ray = IncomingRays[k];
891,734✔
646
                        System->RayData.Append(ray.Pos,
891,734✔
647
                                                                   ray.Cos,
648
                                                                   ELEMENT_NULL,
649
                                                                   idx + 1,
891,734✔
650
                                                                   ray.Num,
891,734✔
651
                                                                   RayEvent::EXIT);
652
                }
653

654
                return RunnerStatus::SUCCESS;
59✔
655
        }
60✔
656

657
} // 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