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

NREL / SolTrace / 14628243107

23 Apr 2025 09:13PM UTC coverage: 44.154% (+0.5%) from 43.617%
14628243107

Pull #65

github

web-flow
Merge e65736e0a into 96166e291
Pull Request #65: Refactor the Trace function (and related functions)

363 of 670 new or added lines in 6 files covered. (54.18%)

135 existing lines in 4 files now uncovered.

1941 of 4396 relevant lines covered (44.15%)

10000057.29 hits per line

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

74.83
/coretrace/raytrace_refactored.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

51

52
#include <vector>
53
#include <string>
54
#include <cmath>
55
#include <algorithm>
56
#include <ctime>
57

58
#include "types.h"
59
#include "procs.h"
60
#include "treemesh.h"
61

62
inline void CopyVec3( double dest[3], const std::vector<double> &src )
63
{
64
        dest[0] = src[0];
65
        dest[1] = src[1];
66
        dest[2] = src[2];
67
}
68

69
inline void CopyVec3( std::vector<double> &dest, double src[3] )
70
{
71
        dest[0] = src[0];
72
        dest[1] = src[1];
73
        dest[2] = src[2];
74
}
75

NEW
76
inline void CopyVec3( double dest[3], double src[3] )
×
77
{
NEW
78
        dest[0] = src[0];
×
NEW
79
        dest[1] = src[1];
×
NEW
80
        dest[2] = src[2];
×
NEW
81
}
×
82

83
class GlobalRay_refactored
84
{
85
public:
86
        GlobalRay_refactored() {
110,001✔
87
                Num = 0;
110,001✔
88
                for (int i=0;i<3;i++) Pos[i]=Cos[i]=0.0;
440,004✔
89
        }
110,001✔
90

91
        double Pos[3];
92
        double Cos[3];
93
        st_uint_t Num;
94
};
95

96
void FindElementHit(
893,970✔
97
        // stage info
98
        const int i, const TStage* Stage, const bool PT_override, const bool AsPowerTower,
99
        
100
        // element info
101
        const int nintelements, const vector<void*>& sunint_elements, const vector<void*>& reflint_elements,
102
        
103
        // ray info
104
        const int RayNumber, const bool in_multi_hit_loop,
105
        double(&PosRayStage)[3], double(&CosRayStage)[3],
106

107
        // outputs
108
        double(&LastPosRaySurfElement)[3], double(&LastCosRaySurfElement)[3], double(&LastDFXYZ)[3],
109
        st_uint_t& LastElementNumber, st_uint_t& LastRayNumber, 
110
        double(&LastPosRaySurfStage)[3], double(&LastCosRaySurfStage)[3],
111

112
        int& ErrorFlag, int& LastHitBackSide,
113
        bool& StageHit)
114
{
115
        // Initialize Variables
116
        double LastPathLength = 1e99;
893,970✔
117
        int HitBackSide = 0;
893,970✔
118
        int InterceptFlag = 0;
893,970✔
119
        double DFXYZ[3] = { 0.0, 0.0, 0.0 };
893,970✔
120
        double PosRayElement[3] = { 0.0, 0.0, 0.0 };
893,970✔
121
        double CosRayElement[3] = { 0.0, 0.0, 0.0 };
893,970✔
122
        double PosRaySurfStage[3] = { 0.0, 0.0, 0.0 };
893,970✔
123
        double CosRaySurfStage[3] = { 0.0, 0.0, 0.0 };
893,970✔
124
        double PosRaySurfElement[3] = { 0.0, 0.0, 0.0 };
893,970✔
125
        double CosRaySurfElement[3] = { 0.0, 0.0, 0.0 };
893,970✔
126
        StageHit = false;
893,970✔
127

128

129
        for (st_uint_t j = 0; j < nintelements; j++)
281,540,765✔
130
        {
131
                TElement* Element; // = Stage->ElementList[j];
132
                if (i == 0 && !PT_override)
280,646,795✔
133
                {
134
                        if (in_multi_hit_loop)
280,291,078✔
135
                        {
136
                                if (AsPowerTower)
275,608,299✔
137
                                        Element = (TElement*)reflint_elements.at(j);
1,398,999✔
138
                                else
139
                                        Element = (TElement*)Stage->ElementList[j];
274,209,300✔
140
                        }
141
                        else
142
                                Element = (TElement*)sunint_elements.at(j);
4,682,779✔
143
                }
144
                else
145
                        Element = Stage->ElementList[j];
355,717✔
146

147
                if (!Element->Enabled)
280,646,795✔
NEW
148
                        continue;
×
149

150
                //  {Transform ray to element[j] coord system of Stage[i]}
151
                TransformToLocal(PosRayStage, CosRayStage,
280,646,795✔
152
                        Element->Origin, Element->RRefToLoc,
280,646,795✔
153
                        PosRayElement, CosRayElement);
154

155
                ErrorFlag = 0;
280,646,795✔
156
                HitBackSide = 0;
280,646,795✔
157
                InterceptFlag = 0;
280,646,795✔
158
                double PathLength = 0;
280,646,795✔
159

160
                // increment position by tiny amount to get off the element if tracing to the same element
161
                PosRayElement[0] = PosRayElement[0] + 1.0e-5 * CosRayElement[0];
280,646,795✔
162
                PosRayElement[1] = PosRayElement[1] + 1.0e-5 * CosRayElement[1];
280,646,795✔
163
                PosRayElement[2] = PosRayElement[2] + 1.0e-5 * CosRayElement[2];
280,646,795✔
164

165
                // {Determine if ray intersects element[j]; if so, Find intersection point with surface of element[j] }
166
                DetermineElementIntersectionNew(Element, PosRayElement, CosRayElement,
280,646,795✔
167
                        PosRaySurfElement, CosRaySurfElement, DFXYZ,
168
                        &PathLength, &ErrorFlag, &InterceptFlag, &HitBackSide);
169

170

171

172
                if (InterceptFlag)
280,646,795✔
173
                {
174
                        //{If hit multiple elements, this loop determines which one hit first.
175
                        //Also makes sure that correct part of closed surface is hit. Also, handles wavy, but close to flat zernikes and polynomials correctly.}
176
                        //if (PathLength < LastPathLength) and (PosRaySurfElement[2] <= Element->ZAperture) then
177
                        if (PathLength < LastPathLength)
203,184✔
178
                        {
179
                                if (PosRaySurfElement[2] <= Element->ZAperture
203,165✔
NEW
180
                                        || Element->SurfaceIndex == 'm'
×
NEW
181
                                        || Element->SurfaceIndex == 'M'
×
NEW
182
                                        || Element->SurfaceIndex == 'r'
×
NEW
183
                                        || Element->SurfaceIndex == 'R')
×
184
                                {
185
                                        StageHit = true;
203,165✔
186
                                        LastPathLength = PathLength;
203,165✔
187
                                        CopyVec3(LastPosRaySurfElement, PosRaySurfElement);
203,165✔
188
                                        CopyVec3(LastCosRaySurfElement, CosRaySurfElement);
203,165✔
189
                                        CopyVec3(LastDFXYZ, DFXYZ);
203,165✔
190
                                        LastElementNumber = (i == 0 && !PT_override) ? Element->element_number : j + 1;    //mjw change from j index to element id
203,165✔
191
                                        LastRayNumber = RayNumber;
203,165✔
192
                                        TransformToReference(PosRaySurfElement, CosRaySurfElement,
203,165✔
193
                                                Element->Origin, Element->RLocToRef,
203,165✔
194
                                                PosRaySurfStage, CosRaySurfStage);
195

196
                                        CopyVec3(LastPosRaySurfStage, PosRaySurfStage);
203,165✔
197
                                        CopyVec3(LastCosRaySurfStage, CosRaySurfStage);
203,165✔
198
                                        LastHitBackSide = HitBackSide;
203,165✔
199
                                }
200
                        }
201
                }
202
        }
203
}
893,970✔
204

205
void ProcessInteraction(
107,552✔
206
        // system info
207
        TSystem* System, MTRand &myrng, const bool IncludeSunShape, TOpticalProperties* optics,
208
        const bool IncludeErrors,
209

210
        // stage info
211
        const int i, const TStage* Stage, const int k,
212
        
213
        // ray info
214
        const st_uint_t MultipleHitCount,
215
        double(&LastDFXYZ)[3],
216
        
217
        // Outputs
218
        double(&LastCosRaySurfElement)[3], int& ErrorFlag,
219
        double(&CosRayOutElement)[3], double(&LastPosRaySurfElement)[3],
220
        double(&PosRayOutElement)[3], int& myrng_counter)
221
{
222
        // Initialize
223
        double CosIn[3] = { 0.0, 0.0, 0.0 };
107,552✔
224
        double CosOut[3] = { 0.0, 0.0, 0.0 };
107,552✔
225

226
        if (!Stage->Virtual)
107,552✔
227
        {
228
                if (IncludeSunShape && i == 0 && MultipleHitCount == 1)//change to account for first hit only in primary stage 8-11-31
104,857✔
229
                {
230
                        // Apply sunshape to UNPERTURBED ray at intersection point
231
                        //only apply sunshape error once for primary stage
NEW
232
                        CopyVec3(CosIn, LastCosRaySurfElement);
×
NEW
233
                        Errors(myrng, CosIn, 1, &System->Sun,
×
NEW
234
                                Stage->ElementList[k], optics, CosOut, LastDFXYZ);  //sun shape
×
NEW
235
                        CopyVec3(LastCosRaySurfElement, CosOut);
×
236
                }
237

238
                //{Determine interaction at surface and direction of perturbed ray}
239
                ErrorFlag = 0;
104,857✔
240

241
                // {Apply surface normal errors to surface normal before interaction ray at intersection point - Wendelin 11-23-09}
242
                if (IncludeErrors)
104,857✔
243
                {
NEW
244
                        CopyVec3(CosIn, CosRayOutElement);
×
NEW
245
                        SurfaceNormalErrors(myrng, LastDFXYZ, optics, CosOut);  //surface normal errors
×
NEW
246
                        myrng_counter++;
×
NEW
247
                        CopyVec3(LastDFXYZ, CosOut);
×
248
                }
249

250
                Interaction(myrng, LastPosRaySurfElement, LastCosRaySurfElement, LastDFXYZ,
104,857✔
251
                        Stage->ElementList[k]->InteractionType, optics, 630.0,
104,857✔
252
                        PosRayOutElement, CosRayOutElement, &ErrorFlag);
253
                myrng_counter++;
104,857✔
254

255
                // {Apply specularity optical error to PERTURBED (i.e. after interaction) ray at intersection point}
256
                if (IncludeErrors)
104,857✔
257
                {
NEW
258
                        if (optics->DistributionType == 'F' || optics->DistributionType == 'f')
×
NEW
259
                                CopyVec3(CosIn, LastDFXYZ);  // Apply diffuse errors relative to surface normal
×
260
                        else
NEW
261
                                CopyVec3(CosIn, CosRayOutElement); // Apply all other errors relative to the specularly-reflected direction
×
262

NEW
263
                        Errors(myrng, CosIn, 2, &System->Sun,
×
NEW
264
                                Stage->ElementList[k], optics, CosOut, LastDFXYZ);  //optical errors
×
NEW
265
                        myrng_counter++;
×
NEW
266
                        CopyVec3(CosRayOutElement, CosOut);
×
267
                }
268
        }
269
}
107,552✔
270

271
// PT Optimization Methods and Structs
272

273
struct eprojdat
274
{
275
        TElement* el_addr;
276
        double d_proj;
277
        double az;
278
        double zen;
279

280
        eprojdat() {};
NEW
281
        eprojdat(TElement* e, double d, double a, double z)
×
NEW
282
        {
×
NEW
283
                el_addr = e;
×
NEW
284
                d_proj = d;
×
NEW
285
                az = a;
×
NEW
286
                zen = z;
×
NEW
287
        };
×
288
};
289

290
//Comparison function for sorting vector of eprojdat
291
static bool eprojdat_compare_refactored(const eprojdat& A, const eprojdat& B)
95,376✔
292
{
293
        return A.d_proj > B.d_proj;
95,376✔
294
};
295

296
void SetupPTOptimizations(
2✔
297
        // system info
298
        TSystem* System, const bool AsPowerTower,
299

300
        // outputs
301
        st_hash_tree &sun_hash, st_hash_tree &rec_hash, double(&reccm_helio)[3]
302
        )
303
{
304
        //Calculate the center of mass of the receiver stage (StageList[1]) in heliostat stage coordinates.
305
        double reccm[] = { 0., 0., 0. };
2✔
306
        int nelrec = 0;
2✔
307
        if (AsPowerTower)
2✔
308
        {
309
                for (st_uint_t j = 0; j < System->StageList[1]->ElementList.size(); j++)
2✔
310
                {
311
                        TElement* el = System->StageList[1]->ElementList.at(j);
1✔
312

313
                        if (!el->Enabled)
1✔
NEW
314
                                continue;
×
315

316
                        nelrec++;
1✔
317

318
                        for (int jj = 0; jj < 3; jj++)
4✔
319
                                reccm[jj] += el->Origin[jj];
3✔
320
                }
321
                for (int jj = 0; jj < 3; jj++)
4✔
322
                        reccm[jj] /= (double)nelrec;    //average
3✔
323

324

325
                //Transform to reference 
326
                double dum1[] = { 0., 0., 1. };
1✔
327
                double dum2[3];
328
                double reccm_global[3];
329
                TransformToReference(reccm, dum1, System->StageList[1]->Origin, System->StageList[1]->RLocToRef, reccm_global, dum2);
1✔
330

331
                //Transform to local (heliostat). reccm_helio is the x,y,z position of the receiver centroid in heliostat stage coordinates.
332
                TransformToLocal(reccm_global, dum1, System->StageList[0]->Origin, System->StageList[0]->RRefToLoc, reccm_helio, dum2);
1✔
333
        }
334
        //Create an array that stores the element address and the projected size in polar coordinates
335
        vector<eprojdat> el_proj_dat;
2✔
336
        el_proj_dat.reserve(System->StageList[0]->ElementList.size());
2✔
337

338
        //calculate the smallest zone size. This should be on the order of the largest element in the stage. 
339
        //load stage 0 elements into the mesh
340
        double d_elm_max = -9.e9;
2✔
341

342
        for (st_uint_t i = 0; i < System->StageList[0]->ElementList.size(); i++)
12,566✔
343
        {
344
                TElement* el = System->StageList[0]->ElementList.at(i);
12,564✔
345

346
                el->element_number = i + 1;   //use index for element number
12,564✔
347

348
                double d_elm;
349

350
                switch (el->ShapeIndex)
12,564✔
351
                {
352
                        //circular aperture
NEW
353
                        case 'c':
×
354
                        case 'C':
355
                                //hexagonal aperture
356
                        case 'h':
357
                        case 'H':
358
                                //triangular aperture
359
                        case 't':
360
                        case 'T':
NEW
361
                                d_elm = el->ParameterA;
×
NEW
362
                                break;
×
363
                                //rectangular aperture
364
                        case 'r':
12,564✔
365
                        case 'R':
366
                                d_elm = sqrt(el->ParameterA * el->ParameterA + el->ParameterB * el->ParameterB);
12,564✔
367
                                break;
12,564✔
368
                                //annular aperture
NEW
369
                        case 'a':
×
370
                        case 'A':
NEW
371
                                d_elm = el->ParameterB;
×
NEW
372
                                break;
×
NEW
373
                        case 'l':
×
374
                        case 'L':
375
                                //off axis aperture section of line focus trough  or cylinder
NEW
376
                                d_elm = sqrt(el->ParameterB * el->ParameterB * 4. + el->ParameterC * el->ParameterC);
×
NEW
377
                                break;
×
378
                                //Irregular triangle
NEW
379
                        case 'i':
×
380
                        case 'I':
381
                                //irregular quadrilateral
382
                        case 'q':
383
                        case 'Q':
384
                        {
NEW
385
                                double xmax = fmax(el->ParameterA, fmax(el->ParameterC, el->ParameterE));
×
NEW
386
                                double xmin = fmin(el->ParameterA, fmin(el->ParameterC, el->ParameterE));
×
NEW
387
                                double ymax = fmax(el->ParameterB, fmax(el->ParameterD, el->ParameterF));
×
NEW
388
                                double ymin = fmin(el->ParameterB, fmin(el->ParameterD, el->ParameterF));
×
389

NEW
390
                                if (el->ShapeIndex == 'q' || el->ShapeIndex == 'Q')
×
391
                                {
NEW
392
                                        xmax = fmax(xmax, el->ParameterG);
×
NEW
393
                                        xmin = fmin(xmin, el->ParameterG);
×
NEW
394
                                        ymax = fmax(ymax, el->ParameterH);
×
NEW
395
                                        ymin = fmin(ymin, el->ParameterH);
×
396
                                }
397

NEW
398
                                double dx = xmax - xmin;
×
NEW
399
                                double dy = ymax - ymin;
×
400

NEW
401
                                d_elm = sqrt(dx * dx + dy * dy);
×
402

NEW
403
                                break;
×
404
                        }
NEW
405
                        default:
×
NEW
406
                                break;
×
407
                }
408

409
                d_elm_max = fmax(d_elm_max, d_elm);
12,564✔
410

411
                if (AsPowerTower)
12,564✔
412
                {
413
                        //Calculate the distance from the receiver to the element and the max projected size
414
                        double dX[3];
415
                        for (int jj = 0; jj < 3; jj++)
25,128✔
416
                                dX[jj] = el->Origin[jj] - reccm_helio[jj];  //vector from receiver to heliostat (not unitized)
18,846✔
417
                        double r_elm = 0.;
6,282✔
418
                        for (int jj = 0; jj < 3; jj++)
25,128✔
419
                                r_elm += dX[jj] * dX[jj];
18,846✔
420
                        r_elm = sqrt(r_elm);            //vector length
6,282✔
421
                        double d_elm_proj = d_elm / r_elm;  //Projected size of the element from the view of the receiver (radians)
6,282✔
422

423
                        //calculate az,zen coordinate
424
                        double az, zen;
425
                        az = atan2(dX[0] / r_elm, dX[1] / r_elm);       //Az coordinate of the heliostat from the receiver's perspective
6,282✔
426
                        zen = asin(dX[2] / r_elm);                    //Zen coordinate """"
6,282✔
427

428
                        el_proj_dat.push_back(eprojdat(el, d_elm_proj, az, zen));
6,282✔
429
                }
430
        }
431

432
        if (AsPowerTower)
2✔
433
        {
434
                //Sort the polar projections by size, largest to smallest
435
                std::sort(el_proj_dat.begin(), el_proj_dat.end(), eprojdat_compare_refactored);
1✔
436
        }
437

438
        //set up the layout data object that provides configuration details for the hash tree
439
        KDLayoutData sun_ld;
440
        sun_ld.xlim[0] = System->Sun.MinXSun;
2✔
441
        sun_ld.xlim[1] = System->Sun.MaxXSun;
2✔
442
        sun_ld.ylim[0] = System->Sun.MinYSun;
2✔
443
        sun_ld.ylim[1] = System->Sun.MaxYSun;
2✔
444
        sun_ld.min_unit_dx = d_elm_max;
2✔
445
        sun_ld.min_unit_dy = d_elm_max;
2✔
446

447
        sun_hash.create_mesh(sun_ld);
2✔
448

449
        //load stage 0 elements into the mesh
450
        for (st_uint_t i = 0; i < System->StageList[0]->ElementList.size(); i++)
12,566✔
451
        {
452
                TElement* el = System->StageList[0]->ElementList.at(i);
12,564✔
453
                sun_hash.add_object((void*)el, el->PosSunCoords[0], el->PosSunCoords[1]);
12,564✔
454
        }
455

456
        //calculate and associate neighbors with each zone
457
        sun_hash.add_neighborhood_data();
2✔
458

459
        if (AsPowerTower)
2✔
460
        {
461
                //Set things up for the polar coordinate tree
462
                KDLayoutData rec_ld;
463
                rec_ld.xlim[0] = -M_PI;
1✔
464
                rec_ld.xlim[1] = M_PI;
1✔
465
                rec_ld.ylim[0] = -M_PI / 2.;
1✔
466
                rec_ld.ylim[1] = M_PI / 2.;
1✔
467
                //use smallest element to set the minimum size
468
                rec_ld.min_unit_dx = rec_ld.min_unit_dy = el_proj_dat.back().d_proj; //radians at equator
1✔
469

470
                rec_hash.create_mesh(rec_ld);
1✔
471

472
                //load stage 0 elements into the receiver mesh in the order of largest projection to smallest
473
                for (int i = 0; i < el_proj_dat.size(); i++)
6,283✔
474
                {
475
                        eprojdat* D = &el_proj_dat.at(i);
6,282✔
476

477
                        //Calculate the angular span of the element
478
                        double angspan[2];
479
                        double adjmult = 1.5;
6,282✔
480
                        angspan[0] = D->d_proj / cos(fabs(D->zen)) * adjmult;   //azimuthal span
6,282✔
481
                        angspan[0] = fmin(angspan[0], 2. * M_PI);     //limit to circumference 
6,282✔
482
                        angspan[1] = D->d_proj / M_PI * adjmult;    //zenithal span
6,282✔
483
                        rec_hash.add_object((void*)D->el_addr, D->az, D->zen, angspan);
6,282✔
484
                }
485

486
                //associate neighbors with each zone
487
                rec_hash.add_neighborhood_data();
1✔
488
        }
489
}
2✔
490

491
st_uint_t GetPTElements(
858,360✔
492
        // system info
493
        const bool AsPowerTower,
494
        
495
        // Stage info
496
        const TStage* Stage, const int i,
497

498
        // Ray info
499
        const bool in_multi_hit_loop, const double(&PosRayStage)[3],
500
        const double(&reccm_helio)[3], st_hash_tree& rec_hash,
501

502
        const vector<void*> &sunint_elements,
503

504
        // Outputs
505
        vector<void*> &reflint_elements,
506
        bool& has_elements
507
        )
508
{
509
        st_uint_t nintelements = 0;
858,360✔
510

511
        if (i == 0)
858,360✔
512
        {
513
                if (in_multi_hit_loop)
766,577✔
514
                {
515
                        if (AsPowerTower)
87,302✔
516
                        {
517
                                //>=Second time through - checking for first stage multiple element interactions
518

519
                                //get ray position in receiver polar coordinates
520
                                double raypvec[3];
521
                                for (int jj = 0; jj < 3; jj++)
174,608✔
522
                                        raypvec[jj] = PosRayStage[jj] - reccm_helio[jj];
130,956✔
523
                                double raypvecmag = sqrt(raypvec[0] * raypvec[0] + raypvec[1] * raypvec[1] + raypvec[2] * raypvec[2]);
43,652✔
524
                                double raypol[2];
525
                                raypol[0] = atan2(raypvec[0], raypvec[1]);
43,652✔
526
                                raypol[1] = asin(raypvec[2] / raypvecmag);
43,652✔
527
                                //get elements in the vicinity of the ray's polar coordinates
528
                                reflint_elements.clear();
43,652✔
529
                                rec_hash.get_all_data_at_loc(reflint_elements, raypol[0], raypol[1]);
43,652✔
530
                                nintelements = reflint_elements.size();
43,652✔
531
                                has_elements = nintelements > 0;
43,652✔
532

533
                        }
534
                        else
535
                        {
536
                                nintelements = Stage->ElementList.size();
43,650✔
537
                        }
538
                }
539
                else
540
                {
541
                        //First time through - checking for sun ray intersections
542
                        if (has_elements)
679,275✔
543
                                nintelements = sunint_elements.size();
545,585✔
544
                        else
545
                                nintelements = 0;
133,690✔
546
                }
547
        }
548
        else
549
                nintelements = Stage->ElementList.size();
91,783✔
550

551
        return nintelements;
858,360✔
552
}
553

554
// Trace method
555

556
bool Trace_refactored(TSystem* System, unsigned int seed,
4✔
557
        st_uint_t NumberOfRays,
558
        st_uint_t MaxNumberOfRays,
559
        bool IncludeSunShape,
560
        bool IncludeErrors,
561
        bool AsPowerTower,
562
        int (*callback)(st_uint_t ntracedtotal, st_uint_t ntraced, st_uint_t ntotrace, st_uint_t curstage, st_uint_t nstages, void* data),
563
        void* cbdata)
564
{
565
        // Determine if PT optimizations should be applied
566
        bool PT_override = false;
4✔
567
        if (System->StageList.size() > 0
4✔
568
                && (System->StageList[0]->ElementList.size() < 10    //the first stage contains only a few elements
6✔
569
                        || System->StageList.size() == 1)                //there's only one stage
2✔
570
                )
571
        {
572
                PT_override = true;
2✔
573
        }
574

575
        // Initialize variables
576
        MTRand myrng(seed);
4✔
577
        int myrng_counter = 0;
4✔
578

579
        // Initialize Internal State Variables
580
        st_uint_t RayNumber = 1;                                                // Ray Number of current ray
4✔
581
        bool PreviousStageHasRays = false;
4✔
582
        st_uint_t LastRayNumberInPreviousStage = NumberOfRays;
4✔
583

584
        // Check Inputs
585
        if (NumberOfRays < 1)
4✔
586
        {
NEW
587
                System->errlog("invalid number of rays: %d", NumberOfRays);
×
NEW
588
                return false;
×
589
        }
590
        if (System->StageList.size() < 1)
4✔
591
        {
NEW
592
                System->errlog("no stages defined.");
×
NEW
593
                return false;
×
594
        }
595

596
        // Define IncomingRays
597
        std::vector<GlobalRay_refactored> IncomingRays;        // Vector of rays from previous stage, going into next stage
4✔
598
        try
599
        {
600
                IncomingRays.resize(NumberOfRays);
4✔
601
        }
NEW
602
        catch (std::exception& e) {
×
NEW
603
                System->errlog("Incoming rays resize exception: %d, '%s'", NumberOfRays, e.what());
×
NEW
604
                return false;
×
NEW
605
        }
×
606

607
        // Initialize Sun
608
        double PosSunStage[3] = { 0.0, 0.0, 0.0 };
4✔
609
        if (!SunToPrimaryStage(System, System->StageList[0], &System->Sun, PosSunStage))
4✔
NEW
610
                return false;
×
611

612
        // Calculate hash tree for reflection to receiver plane(polar coordinates).
613
        st_hash_tree sun_hash;
4✔
614
        st_hash_tree rec_hash;
4✔
615
        double reccm_helio[3];  //receiver centroid in heliostat field coordinates
616
        if (!PT_override)
4✔
617
        {
618
                SetupPTOptimizations(System, AsPowerTower, sun_hash, rec_hash, reccm_helio);
2✔
619
        }
620

621
        // Start the clock
622
        clock_t startTime = clock();
4✔
623
        int rays_per_callback_estimate = 50;
4✔
624
        st_uint_t RaysTracedTotal = 0;
4✔
625

626
        // Loop through stages
627
        for (st_uint_t i = 0; i < System->StageList.size(); i++)
12✔
628
        {
629
                // Check if previous stage has rays
630
                bool StageHasRays = true;
8✔
631
                if (i > 0 && PreviousStageHasRays == false)
8✔
632
                {
NEW
633
                        StageHasRays = false;
×
634
                }
635

636
                // Get Current Stage
637
                TStage* Stage = System->StageList[i];
8✔
638

639
                // Initialize stage variables
640
                st_uint_t StageDataArrayIndex = 0;
8✔
641
                st_uint_t PreviousStageDataArrayIndex = 0;
8✔
642

643
                // Loop through rays
644
                while (StageHasRays)
801,321✔
645
                {
646
                        // Initialize Global Coordinates
647
                        double PosRayGlob[3] = { 0.0, 0.0, 0.0 };
801,321✔
648
                        double CosRayGlob[3] = { 0.0, 0.0, 0.0 };
801,321✔
649

650
                        // Initialize Stage Coordinates
651
                        double PosRayStage[3] = { 0.0, 0.0, 0.0 };
801,321✔
652
                        double CosRayStage[3] = { 0.0, 0.0, 0.0 };
801,321✔
653

654
                        // Initialize PT Optimization variables
655
                        bool has_elements = true;
801,321✔
656
                        vector<void*> sunint_elements;
801,321✔
657

658
                        // Get Ray
659
                        if (i == 0)
801,321✔
660
                        {
661
                                // Make ray (if first stage)
662
                                double PosRaySun[3];
663
                                GenerateRay(myrng, PosSunStage, Stage->Origin,
702,676✔
664
                                        Stage->RLocToRef, &System->Sun,
702,676✔
665
                                        PosRayGlob, CosRayGlob, PosRaySun);
666
                                myrng_counter++;
702,676✔
667
                                System->SunRayCount++;
702,676✔
668

669
                                // If using PT optimizations, check if stage has elements that could interact with ray
670
                                if (!PT_override)
702,676✔
671
                                {
672
                                        has_elements = sun_hash.get_all_data_at_loc(sunint_elements, PosRaySun[0], PosRaySun[1]);
679,275✔
673
                                }
674
                        }
675
                        else
676
                        {
677
                                // Get ray from previous stage
678
                                RayNumber = IncomingRays[StageDataArrayIndex].Num;
98,645✔
679
                                CopyVec3(PosRayGlob, IncomingRays[StageDataArrayIndex].Pos);
98,645✔
680
                                CopyVec3(CosRayGlob, IncomingRays[StageDataArrayIndex].Cos);
98,645✔
681
                                StageDataArrayIndex++;
98,645✔
682
                        }
683

684
                        // transform the global incoming ray to local stage coordinates
685
                        TransformToLocal(PosRayGlob, CosRayGlob,
801,321✔
686
                                Stage->Origin, Stage->RRefToLoc,
801,321✔
687
                                PosRayStage, CosRayStage);
688

689
                        // Update callback
690
                        if (callback != 0
801,321✔
691
                                && RaysTracedTotal++ % rays_per_callback_estimate == 0)
801,321✔
692
                        {
693
                                if (RaysTracedTotal > 1)
452✔
694
                                {
695
                                        //update how often to call this
696
                                        double msec_per_ray = 1000. * (clock() - startTime) / CLOCKS_PER_SEC / (double)(RaysTracedTotal > 0 ? RaysTracedTotal : 1);
448✔
697
                                        //set the new callback estimate to be about 50 ms
698
                                        rays_per_callback_estimate = (int)(200. / msec_per_ray);
448✔
699
                                        //limit to something reasonable
700
                                        rays_per_callback_estimate = rays_per_callback_estimate < 5 ? 5 : rays_per_callback_estimate;
448✔
701
                                }
702

703
                                //do the callback
704
                                if (!(*callback)(RaysTracedTotal, RayNumber,
452✔
705
                                        LastRayNumberInPreviousStage, i + 1,
706
                                        System->StageList.size(), cbdata))
NEW
707
                                        return true;
×
708
                        }
709

710

711
                        // Initialize internal variables for ray intersection tracing
712
                        bool RayInStage = true;
801,321✔
713
                        bool in_multi_hit_loop = false;
801,321✔
714
                        double LastPosRaySurfElement[3] = { 0.0, 0.0, 0.0 };
801,321✔
715
                        double LastCosRaySurfElement[3] = { 0.0, 0.0, 0.0 };
801,321✔
716
                        double LastPosRaySurfStage[3] = { 0.0, 0.0, 0.0 };
801,321✔
717
                        double LastCosRaySurfStage[3] = { 0.0, 0.0, 0.0 };
801,321✔
718
                        double LastDFXYZ[3] = { 0.0, 0.0, 0.0 };
801,321✔
719
                        st_uint_t LastElementNumber = 0;
801,321✔
720
                        st_uint_t LastRayNumber = 0;
801,321✔
721
                        int ErrorFlag;
722
                        int LastHitBackSide;
723
                        bool StageHit;
724
                        int MultipleHitCount = 0;
801,321✔
725
                        double PosRayOutElement[3] = { 0.0, 0.0, 0.0 };
801,321✔
726
                        double CosRayOutElement[3] = { 0.0, 0.0, 0.0 };
801,321✔
727

728
                        // Start Loop to trace ray until it leaves stage
729
                        bool RayIsAbsorbed = false;
801,321✔
730
                        while (RayInStage)
893,970✔
731
                        {
732
                                // Set number of elements to search through
733
                                st_uint_t nintelements = 0;
893,970✔
734
                                vector<void*> reflint_elements;
893,970✔
735
                                if (!PT_override)        // if using opt AND first stage
893,970✔
736
                                {
737
                                        nintelements = GetPTElements(AsPowerTower, Stage, i, in_multi_hit_loop, PosRayStage,
858,360✔
738
                                                reccm_helio, rec_hash, sunint_elements,
739
                                                reflint_elements, has_elements);
740
                                }
741
                                else
742
                                {
743
                                        nintelements = Stage->ElementList.size();
35,610✔
744
                                }
745

746
                                // Find the element the ray hits
747
                                FindElementHit(i, Stage, PT_override, AsPowerTower,
893,970✔
748
                                        nintelements, sunint_elements, reflint_elements,
749
                                        RayNumber, in_multi_hit_loop,
750
                                        PosRayStage, CosRayStage,
751

752
                                        LastPosRaySurfElement, LastCosRaySurfElement, LastDFXYZ,
753
                                        LastElementNumber, LastRayNumber,
754
                                        LastPosRaySurfStage, LastCosRaySurfStage,
755
                                        ErrorFlag, LastHitBackSide, StageHit);
756

757
                                // Breakout if ray left stage
758
                                if (!StageHit)
893,970✔
759
                                {
760
                                        RayInStage = false;
690,815✔
761
                                        break;
690,815✔
762
                                }
763

764
                                // Add ray to Stage RayData
765
                                TRayData::ray_t* p_ray = Stage->RayData.Append(LastPosRaySurfStage,
406,310✔
766
                                        LastCosRaySurfStage,
767
                                        LastElementNumber,
768
                                        i + 1,
203,155✔
769
                                        LastRayNumber);
770

771
                                // Check p_ray saved correctly
772
                                if (!p_ray)
203,155✔
773
                                {
NEW
774
                                        System->errlog("Failed to save ray data at index %d", Stage->RayData.Count() - 1);
×
NEW
775
                                        return false;
×
776
                                }
777

778
                                // Skipping LastElementNumber == 0 check
779

780
                                // Increment MultipleHitCount
781
                                MultipleHitCount++;
203,155✔
782

783
                                // Get optics and check for absorption
784
                                TOpticalProperties* optics = 0;
203,155✔
785
                                if (Stage->Virtual)
203,155✔
786
                                {
787
                                        // If stage is virtual, there is no interaction
788
                                        CopyVec3(PosRayOutElement, LastPosRaySurfElement);
2,695✔
789
                                        CopyVec3(CosRayOutElement, LastCosRaySurfElement);
2,695✔
790
                                }
791
                                else
792
                                {
793
                                        // trace through the interaction
794
                                        TElement* optelm = Stage->ElementList[p_ray->element - 1];
200,460✔
795

796
                                        if (LastHitBackSide)
200,460✔
797
                                                optics = &optelm->Optics->Back;
87,303✔
798
                                        else
799
                                                optics = &optelm->Optics->Front;
113,157✔
800

801
                                        double TestValue;
802
                                        double UnitLastDFXYZ[3] = { 0.0, 0.0, 0.0 };
200,460✔
803
                                        double IncidentAngle = 0;
200,460✔
804
                                        switch (optelm->InteractionType)
200,460✔
805
                                        {
NEW
806
                                                case 1: // refraction
×
NEW
807
                                                        if (optics->UseTransmissivityTable)
×
808
                                                        {
NEW
809
                                                                int npoints = optics->TransmissivityTable.size();
×
NEW
810
                                                                int m = 0;
×
811

NEW
812
                                                                UnitLastDFXYZ[0] = -LastDFXYZ[0] / sqrt(DOT(LastDFXYZ, LastDFXYZ));
×
NEW
813
                                                                UnitLastDFXYZ[1] = -LastDFXYZ[1] / sqrt(DOT(LastDFXYZ, LastDFXYZ));
×
NEW
814
                                                                UnitLastDFXYZ[2] = -LastDFXYZ[2] / sqrt(DOT(LastDFXYZ, LastDFXYZ));
×
NEW
815
                                                                IncidentAngle = acos(DOT(LastCosRaySurfElement, UnitLastDFXYZ)) * 1000.;  //[mrad]
×
NEW
816
                                                                if (IncidentAngle >= optics->TransmissivityTable[npoints - 1].angle)
×
817
                                                                {
NEW
818
                                                                        TestValue = optics->TransmissivityTable[npoints - 1].trans;
×
819
                                                                }
820
                                                                else
821
                                                                {
NEW
822
                                                                        while (optics->TransmissivityTable[m].angle < IncidentAngle)
×
NEW
823
                                                                                m++;
×
824

NEW
825
                                                                        if (m == 0)
×
NEW
826
                                                                                TestValue = optics->TransmissivityTable[m].trans;
×
827
                                                                        else
NEW
828
                                                                                TestValue = (optics->TransmissivityTable[m].trans + optics->TransmissivityTable[m - 1].trans) / 2.0;
×
829
                                                                }
830
                                                        }
831
                                                        else
NEW
832
                                                                TestValue = optics->Transmissivity;
×
NEW
833
                                                        break;
×
834
                                                case 2: // reflection
200,460✔
835

836
                                                        if (optics->UseReflectivityTable)
200,460✔
837
                                                        {
NEW
838
                                                                int npoints = optics->ReflectivityTable.size();
×
NEW
839
                                                                int m = 0;
×
NEW
840
                                                                UnitLastDFXYZ[0] = -LastDFXYZ[0] / sqrt(DOT(LastDFXYZ, LastDFXYZ));
×
NEW
841
                                                                UnitLastDFXYZ[1] = -LastDFXYZ[1] / sqrt(DOT(LastDFXYZ, LastDFXYZ));
×
NEW
842
                                                                UnitLastDFXYZ[2] = -LastDFXYZ[2] / sqrt(DOT(LastDFXYZ, LastDFXYZ));
×
NEW
843
                                                                IncidentAngle = acos(DOT(LastCosRaySurfElement, UnitLastDFXYZ)) * 1000.;  //[mrad]
×
NEW
844
                                                                if (IncidentAngle >= optics->ReflectivityTable[npoints - 1].angle)
×
845
                                                                {
NEW
846
                                                                        TestValue = optics->ReflectivityTable[npoints - 1].refl;
×
847
                                                                }
848
                                                                else
849
                                                                {
NEW
850
                                                                        while (optics->ReflectivityTable[m].angle < IncidentAngle)
×
NEW
851
                                                                                m++;
×
852

NEW
853
                                                                        if (m == 0)
×
NEW
854
                                                                                TestValue = optics->ReflectivityTable[m].refl;
×
855
                                                                        else
NEW
856
                                                                                TestValue = (optics->ReflectivityTable[m].refl + optics->ReflectivityTable[m - 1].refl) / 2.0;
×
857
                                                                }
858
                                                        }
859
                                                        else
860
                                                                TestValue = optics->Reflectivity;
200,460✔
861
                                                        break;
200,460✔
NEW
862
                                                default:
×
NEW
863
                                                        System->errlog("Bad optical interaction type = %d (stage %d)", i, optelm->InteractionType);
×
NEW
864
                                                        return false;
×
865
                                        }
866

867
                                        //  {Apply MonteCarlo probability of absorption. Limited for now, but can make more complex later on if desired}
868
                                        if (TestValue <= myrng())
200,460✔
869
                                        {
870
                                                myrng_counter++;
95,603✔
871
                                                // ray was fully absorbed, so indicate by negating the element number
872
                                                p_ray->element = 0 - p_ray->element;
95,603✔
873
                                                RayIsAbsorbed = true;
95,603✔
874
                                                break;
95,603✔
875
                                        }
876

877
                                }
878

879
                                // Process Interaction
880
                                int k = abs(p_ray->element) - 1;
107,552✔
881
                                ProcessInteraction(System, myrng, IncludeSunShape, optics, IncludeErrors,
107,552✔
882
                                        i, Stage, k,
883
                                        MultipleHitCount, LastDFXYZ,
884
                                        LastCosRaySurfElement, ErrorFlag,
885
                                        CosRayOutElement, LastPosRaySurfElement,
886
                                        PosRayOutElement, myrng_counter);
887

888
                                // Transform ray back to stage coordinate system
889
                                TransformToReference(PosRayOutElement, CosRayOutElement,
107,552✔
890
                                        Stage->ElementList[k]->Origin, Stage->ElementList[k]->RLocToRef,
107,552✔
891
                                        PosRayStage, CosRayStage);
892
                                TransformToReference(PosRayStage, CosRayStage,
107,552✔
893
                                        Stage->Origin, Stage->RLocToRef,
107,552✔
894
                                        PosRayGlob, CosRayGlob);
895

896
                                // Break out if multiple hits are not allowed
897
                                if (!Stage->MultiHitsPerRay)
107,552✔
898
                                {
899
                                        StageHit = false;
14,903✔
900
                                        break;
14,903✔
901
                                }
902
                                else
903
                                {
904
                                        in_multi_hit_loop = true;
92,649✔
905
                                }
906

907
                        }
893,970✔
908

909
                        // Handle if Ray was absorbed
910
                        if (RayIsAbsorbed)
801,321✔
911
                        {
912
                                // ray was fully absorbed
913
                                if (RayNumber == LastRayNumberInPreviousStage)
95,603✔
914
                                {
915
                                        PreviousStageHasRays = false;
4✔
916
                                        if (PreviousStageDataArrayIndex > 0)
4✔
917
                                        {
918
                                                PreviousStageDataArrayIndex--;
4✔
919
                                                PreviousStageHasRays = true;
4✔
920
                                        }
921
                                        //goto Label_EndStageLoop;
922
                                        break;
4✔
923
                                }
924
                                else
925
                                {
926
                                        if (i == 0)
95,599✔
927
                                        {
928
                                                if (RayNumber == NumberOfRays)
14,048✔
929
                                                        //goto Label_EndStageLoop;
NEW
930
                                                        break;
×
931
                                                else
932
                                                        RayNumber++;
14,048✔
933
                                        }
934

935
                                        // Next ray in loop
936
                                        continue;
95,599✔
937
                                }
938
                        }
939

940
                        // !StageHit logic goes here
941
                        if (StageHit == true)
705,718✔
942
                        {
943
                                // This shouldn't happen...
944
                        }
945

946
                        // Ray has left the stage
947
                        bool FlagMiss = false;
705,718✔
948
                        if (i == 0)
705,718✔
949
                        {
950
                                if (MultipleHitCount == 0)
688,626✔
951
                                {
952
                                        // Ray in first stage missed stage entirely
953
                                        // Generate new ray
954
                                        continue;
592,675✔
955
                                }
956
                                else
957
                                {
958
                                        // Ray hit an element, so save it for next stage
959
                                        CopyVec3(IncomingRays[PreviousStageDataArrayIndex].Pos, PosRayGlob);
95,951✔
960
                                        CopyVec3(IncomingRays[PreviousStageDataArrayIndex].Cos, CosRayGlob);
95,951✔
961
                                        IncomingRays[PreviousStageDataArrayIndex].Num = RayNumber;
95,951✔
962

963
                                        // Is Ray the last in the stage?
964
                                        if (RayNumber == NumberOfRays)
95,951✔
965
                                        {
966
                                                StageHasRays = false;
2✔
967
                                                break;
2✔
968
                                        }
969

970
                                        PreviousStageDataArrayIndex++;
95,949✔
971
                                        PreviousStageHasRays = true;
95,949✔
972

973
                                        // Move on to next ray
974
                                        RayNumber++;
95,949✔
975
                                        continue;
95,949✔
976
                                }
977
                        }
978
                        else
979
                        {
980
                                // After the first stage
981
                                // Ray hit element OR is traced through stage
982
                                if (Stage->TraceThrough || MultipleHitCount > 0)
17,092✔
983
                                {
984
                                        // Ray is saved for the next stage
985
                                        CopyVec3(IncomingRays[PreviousStageDataArrayIndex].Pos, PosRayGlob);
10,736✔
986
                                        CopyVec3(IncomingRays[PreviousStageDataArrayIndex].Cos, CosRayGlob);
10,736✔
987
                                        IncomingRays[PreviousStageDataArrayIndex].Num = RayNumber;
10,736✔
988

989
                                        // Check if ray is last in stage
990
                                        if (RayNumber == LastRayNumberInPreviousStage)
10,736✔
991
                                        {
992
                                                StageHasRays = false;
1✔
993
                                                break;
1✔
994
                                        }
995

996
                                        PreviousStageDataArrayIndex++;
10,735✔
997
                                        PreviousStageHasRays = true;
10,735✔
998

999
                                        if (MultipleHitCount == 0)
10,735✔
1000
                                        {
NEW
1001
                                                FlagMiss = true;
×
1002
                                        }
1003

1004
                                        // Go to next ray
1005
                                        continue;
10,735✔
1006

1007
                                }
1008
                                // Ray missed stage entirely and is not traced
1009
                                else
1010
                                {
1011
                                        FlagMiss = true;
6,356✔
1012
                                }
1013

1014
                                // Handle FlagMiss condition (
1015
                                if (FlagMiss == true)
6,356✔
1016
                                {
1017
                                        LastElementNumber = 0;
6,356✔
1018
                                        LastRayNumber = RayNumber;
6,356✔
1019
                                        CopyVec3(LastPosRaySurfStage, PosRayStage);
6,356✔
1020
                                        CopyVec3(LastCosRaySurfStage, CosRayStage);
6,356✔
1021

1022
                                        // Copying this here to handle FlagMiss condition
1023
                                        TRayData::ray_t* p_ray = Stage->RayData.Append(LastPosRaySurfStage,
12,712✔
1024
                                                LastCosRaySurfStage,
1025
                                                LastElementNumber,
1026
                                                i + 1,
6,356✔
1027
                                                LastRayNumber);
1028

1029
                                        if (RayNumber == LastRayNumberInPreviousStage)
6,356✔
1030
                                        {
1031
                                                if (!Stage->TraceThrough)
1✔
1032
                                                {
1033
                                                        PreviousStageHasRays = false;
1✔
1034
                                                        if (PreviousStageDataArrayIndex > 0)
1✔
1035
                                                        {
1036
                                                                PreviousStageHasRays = true;
1✔
1037
                                                                PreviousStageDataArrayIndex--; // last ray was previous one
1✔
1038
                                                        }
1039
                                                }
1040
                                                
1041
                                                // Exit stage
1042
                                                StageHasRays = false;
1✔
1043
                                                break;
1✔
1044
                                        }
1045
                                        else
1046
                                        {
1047
                                                if (i == 0) RayNumber++; // generate new sun ray
6,355✔
1048
                                                
1049
                                                // Start new ray
1050
                                                continue;
6,355✔
1051
                                        }
1052
                                }
1053
                        }
1054
                }
801,321✔
1055

1056
                // EndStage section...
1057

1058
                // skipping save_st_data logic
1059

1060
                if (!PreviousStageHasRays)
8✔
1061
                {
1062
                        LastRayNumberInPreviousStage = 0;
1✔
1063
                        continue;        // No rays to carry forward
1✔
1064
                }
1065

1066
                if (PreviousStageDataArrayIndex < IncomingRays.size())
7✔
1067
                {
1068
                        LastRayNumberInPreviousStage = IncomingRays[PreviousStageDataArrayIndex].Num;
7✔
1069
                        if (LastRayNumberInPreviousStage == 0)
7✔
1070
                        {
NEW
1071
                                size_t pp = IncomingRays[PreviousStageDataArrayIndex - 1].Num;
×
NEW
1072
                                System->errlog("LastRayNumberInPreviousStage=0, stage %d, PrevIdx=%d, CurIdx=%d, pp=%d", i + 1,
×
1073
                                        PreviousStageDataArrayIndex, StageDataArrayIndex, pp);
NEW
1074
                                return false;
×
1075
                        }
1076
                }
1077
                else
1078
                {
NEW
1079
                        System->errlog("Invalid PreviousStageDataArrayIndex: %u, @ stage %d",
×
1080
                                PreviousStageDataArrayIndex, i + 1);
NEW
1081
                        return false;
×
1082
                }
1083

1084
        }
1085

1086
        return true;
4✔
1087
}
4✔
1088

1089

1090

1091

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