22#include <unordered_set>
24using namespace helios;
36 directRayCount_default = 100;
37 diffuseRayCount_default = 1000;
39 diffuseFlux_default = -1.f;
41 minScatterEnergy_default = 0.1;
42 scatteringDepth_default = 0;
51 temperature_default = 300;
55 spectral_library_files.push_back(
"plugins/radiation/spectral_data/camera_spectral_library.xml");
56 spectral_library_files.push_back(
"plugins/radiation/spectral_data/light_spectral_library.xml");
57 spectral_library_files.push_back(
"plugins/radiation/spectral_data/soil_surface_spectral_library.xml");
58 spectral_library_files.push_back(
"plugins/radiation/spectral_data/leaf_surface_spectral_library.xml");
59 spectral_library_files.push_back(
"plugins/radiation/spectral_data/bark_surface_spectral_library.xml");
60 spectral_library_files.push_back(
"plugins/radiation/spectral_data/fruit_surface_spectral_library.xml");
61 spectral_library_files.push_back(
"plugins/radiation/spectral_data/solar_spectrum_ASTMG173.xml");
62 spectral_library_files.push_back(
"plugins/radiation/spectral_data/color_board/Calibrite_ColorChecker_Classic_colorboard.xml");
63 spectral_library_files.push_back(
"plugins/radiation/spectral_data/color_board/DGK_DKK_colorboard.xml");
69 RT_CHECK_ERROR(rtContextDestroy(OptiX_Context));
82 if (strcmp(label,
"reflectivity") == 0 || strcmp(label,
"transmissivity") == 0) {
83 output_prim_data.emplace_back(label);
85 std::cout <<
"WARNING (RadiationModel::optionalOutputPrimitiveData): unknown output primitive data " << label << std::endl;
91 helios_runtime_error(
"ERROR (RadiationModel::setDirectRayCount): Cannot set ray count for band '" + label +
"' because it is not a valid band.");
93 radiation_bands.at(label).directRayCount = N;
98 helios_runtime_error(
"ERROR (RadiationModel::setDiffuseRayCount): Cannot set ray count for band '" + label +
"' because it is not a valid band.");
100 radiation_bands.at(label).diffuseRayCount = N;
105 helios_runtime_error(
"ERROR (RadiationModel::setDiffuseRadiationFlux): Cannot set flux value for band '" + label +
"' because it is not a valid band.");
107 radiation_bands.at(label).diffuseFlux = flux;
116 helios_runtime_error(
"ERROR (RadiationModel::setDiffuseRadiationExtinctionCoeff): Cannot set diffuse extinction value for band '" + label +
"' because it is not a valid band.");
124 for (
int j = 0; j < N; j++) {
125 for (
int i = 0; i < N; i++) {
126 float theta = 0.5f *
M_PI / float(N) * (0.5f + float(i));
127 float phi = 2.f *
M_PI / float(N) * (0.5f + float(j));
132 if (psi <
M_PI / 180.f) {
133 fd = powf(
M_PI / 180.f, -K);
138 norm += fd * cosf(theta) * sinf(theta) *
M_PI / float(N * N);
143 radiation_bands.at(label).diffuseExtinction = K;
144 radiation_bands.at(label).diffusePeakDir = dir;
145 radiation_bands.at(label).diffuseDistNorm = 1.f / norm;
150 for (
auto &band: radiation_bands) {
157 for (
auto &band: radiation_bands) {
164 if (spectrum_integral < 0) {
165 helios_runtime_error(
"ERROR (RadiationModel::setDiffuseSpectrumIntegral): Source integral must be non-negative.");
167 helios_runtime_error(
"ERROR (RadiationModel::setDiffuseSpectrumIntegral): Cannot set integral for band '" + band_label +
"' because it is not a valid band.");
168 }
else if (radiation_bands.at(band_label).diffuse_spectrum.empty()) {
169 std::cerr <<
"WARNING (RadiationModel::setDiffuseSpectrumIntegral): Diffuse spectral distribution has not been set for radiation band '" + band_label +
"'. Cannot set its integral." << std::endl;
173 float current_integral =
integrateSpectrum(radiation_bands.at(band_label).diffuse_spectrum);
175 for (
vec2 &wavelength: radiation_bands.at(band_label).diffuse_spectrum) {
176 wavelength.y *= spectrum_integral / current_integral;
179 radiativepropertiesneedupdate =
true;
184 if (spectrum_integral < 0) {
185 helios_runtime_error(
"ERROR (RadiationModel::setDiffuseSpectrumIntegral): Source integral must be non-negative.");
187 helios_runtime_error(
"ERROR (RadiationModel::setDiffuseSpectrumIntegral): Cannot set integral for band '" + band_label +
"' because it is not a valid band.");
190 float current_integral =
integrateSpectrum(radiation_bands.at(band_label).diffuse_spectrum, wavelength1, wavelength2);
192 for (
vec2 &wavelength: radiation_bands.at(band_label).diffuse_spectrum) {
193 wavelength.y *= spectrum_integral / current_integral;
196 radiativepropertiesneedupdate =
true;
201 if (radiation_bands.find(label) != radiation_bands.end()) {
202 std::cerr <<
"WARNING (RadiationModel::addRadiationBand): Radiation band " << label <<
" has already been added. Skipping this call to addRadiationBand()." << std::endl;
206 RadiationBand band(label, directRayCount_default, diffuseRayCount_default, diffuseFlux_default, scatteringDepth_default, minScatterEnergy_default);
208 radiation_bands.emplace(label, band);
211 for (
auto &source: radiation_sources) {
212 source.source_fluxes[label] = -1.f;
215 radiativepropertiesneedupdate =
true;
220 if (radiation_bands.find(label) != radiation_bands.end()) {
221 std::cerr <<
"WARNING (RadiationModel::addRadiationBand): Radiation band " << label <<
" has already been added. Skipping this call to addRadiationBand()." << std::endl;
223 }
else if (wavelength1 > wavelength2) {
224 helios_runtime_error(
"ERROR (RadiationModel::addRadiationBand): The upper wavelength bound for a band must be greater than the lower bound.");
225 }
else if (wavelength2 - wavelength1 < 1) {
226 helios_runtime_error(
"ERROR (RadiationModel::addRadiationBand): The waveband range of a radiation band must be at least 1 nm.");
229 RadiationBand band(label, directRayCount_default, diffuseRayCount_default, diffuseFlux_default, scatteringDepth_default, minScatterEnergy_default);
233 radiation_bands.emplace(label, band);
236 for (
auto &source: radiation_sources) {
237 source.source_fluxes[label] = -1.f;
240 radiativepropertiesneedupdate =
true;
246 helios_runtime_error(
"ERROR (RadiationModel::copyRadiationBand): Cannot copy band " + old_label +
" because it does not exist.");
249 vec2 waveBounds = radiation_bands.at(old_label).wavebandBounds;
257 helios_runtime_error(
"ERROR (RadiationModel::copyRadiationBand): Cannot copy band " + old_label +
" because it does not exist.");
261 band.
label = new_label;
264 radiation_bands.emplace(new_label, band);
267 for (
auto &source: radiation_sources) {
268 source.source_fluxes[new_label] = source.source_fluxes.at(old_label);
271 radiativepropertiesneedupdate =
true;
275 if (radiation_bands.find(label) == radiation_bands.end()) {
285 helios_runtime_error(
"ERROR (RadiationModel::disableEmission): Cannot disable emission for band '" + label +
"' because it is not a valid band.");
288 radiation_bands.at(label).emissionFlag =
false;
294 helios_runtime_error(
"ERROR (RadiationModel::enableEmission): Cannot disable emission for band '" + label +
"' because it is not a valid band.");
297 radiation_bands.at(label).emissionFlag =
true;
312 helios_runtime_error(
"ERROR (RadiationModel::addCollimatedRadiationSource): Invalid collimated source direction. Direction vector should not have length of zero.");
315 uint Nsources = radiation_sources.size() + 1;
316 if (Nsources > 256) {
317 helios_runtime_error(
"ERROR (RadiationModel::addCollimatedRadiationSource): A maximum of 256 radiation sources are allowed.");
320 bool warn_multiple_suns =
false;
321 for (
auto &source: radiation_sources) {
322 if (source.source_type == RADIATION_SOURCE_TYPE_COLLIMATED || source.source_type == RADIATION_SOURCE_TYPE_SUN_SPHERE) {
323 warn_multiple_suns =
true;
326 if (warn_multiple_suns) {
327 std::cerr <<
"WARNING (RadiationModel::addCollimatedRadiationSource): Multiple sun sources have been added to the radiation model. This may lead to unintended behavior." << std::endl;
333 for (
const auto &band: radiation_bands) {
337 radiation_sources.emplace_back(collimated_source);
339 radiativepropertiesneedupdate =
true;
347 helios_runtime_error(
"ERROR (RadiationModel::addSphereRadiationSource): Spherical radiation source radius must be positive.");
350 uint Nsources = radiation_sources.size() + 1;
351 if (Nsources > 256) {
352 helios_runtime_error(
"ERROR (RadiationModel::addSphereRadiationSource): A maximum of 256 radiation sources are allowed.");
358 for (
const auto &band: radiation_bands) {
362 radiation_sources.emplace_back(sphere_source);
364 uint sourceID = Nsources - 1;
366 if (islightvisualizationenabled) {
367 buildLightModelGeometry(sourceID);
370 radiativepropertiesneedupdate =
true;
385 uint Nsources = radiation_sources.size() + 1;
386 if (Nsources > 256) {
387 helios_runtime_error(
"ERROR (RadiationModel::addSunSphereRadiationSource): A maximum of 256 radiation sources are allowed.");
390 bool warn_multiple_suns =
false;
391 for (
auto &source: radiation_sources) {
392 if (source.source_type == RADIATION_SOURCE_TYPE_COLLIMATED || source.source_type == RADIATION_SOURCE_TYPE_SUN_SPHERE) {
393 warn_multiple_suns =
true;
396 if (warn_multiple_suns) {
397 std::cerr <<
"WARNING (RadiationModel::addSunSphereRadiationSource): Multiple sun sources have been added to the radiation model. This may lead to unintended behavior." << std::endl;
400 RadiationSource sphere_source(150e9 * sun_direction / sun_direction.
magnitude(), 150e9, 2.f * 695.5e6, sigma * powf(5700, 4) / 1288.437f);
403 for (
const auto &band: radiation_bands) {
407 radiation_sources.emplace_back(sphere_source);
409 radiativepropertiesneedupdate =
true;
416 if (size.
x <= 0 || size.
y <= 0) {
417 helios_runtime_error(
"ERROR (RadiationModel::addRectangleRadiationSource): Radiation source size must be positive.");
420 uint Nsources = radiation_sources.size() + 1;
421 if (Nsources > 256) {
422 helios_runtime_error(
"ERROR (RadiationModel::addRectangleRadiationSource): A maximum of 256 radiation sources are allowed.");
428 for (
const auto &band: radiation_bands) {
432 radiation_sources.emplace_back(rectangle_source);
434 uint sourceID = Nsources - 1;
436 if (islightvisualizationenabled) {
437 buildLightModelGeometry(sourceID);
440 radiativepropertiesneedupdate =
true;
448 helios_runtime_error(
"ERROR (RadiationModel::addDiskRadiationSource): Disk radiation source radius must be positive.");
451 uint Nsources = radiation_sources.size() + 1;
452 if (Nsources > 256) {
453 helios_runtime_error(
"ERROR (RadiationModel::addDiskRadiationSource): A maximum of 256 radiation sources are allowed.");
459 for (
const auto &band: radiation_bands) {
463 radiation_sources.emplace_back(disk_source);
465 uint sourceID = Nsources - 1;
467 if (islightvisualizationenabled) {
468 buildLightModelGeometry(sourceID);
471 radiativepropertiesneedupdate =
true;
478 if (sourceID >= radiation_sources.size()) {
479 helios_runtime_error(
"ERROR (RadiationModel::deleteRadiationSource): Source ID out of bounds. Only " + std::to_string(radiation_sources.size() - 1) +
" radiation sources have been created.");
482 radiation_sources.erase(radiation_sources.begin() + sourceID);
484 radiativepropertiesneedupdate =
true;
489 if (source_ID >= radiation_sources.size()) {
490 helios_runtime_error(
"ERROR (RadiationModel::setSourceSpectrumIntegral): Source ID out of bounds. Only " + std::to_string(radiation_sources.size() - 1) +
" radiation sources have been created.");
491 }
else if (source_integral < 0) {
492 helios_runtime_error(
"ERROR (RadiationModel::setSourceIntegral): Source integral must be non-negative.");
495 float current_integral =
integrateSpectrum(radiation_sources.at(source_ID).source_spectrum);
497 for (
vec2 &wavelength: radiation_sources.at(source_ID).source_spectrum) {
498 wavelength.y *= source_integral / current_integral;
504 if (source_ID >= radiation_sources.size()) {
505 helios_runtime_error(
"ERROR (RadiationModel::setSourceSpectrumIntegral): Source ID out of bounds. Only " + std::to_string(radiation_sources.size() - 1) +
" radiation sources have been created.");
506 }
else if (source_integral < 0) {
507 helios_runtime_error(
"ERROR (RadiationModel::setSourceSpectrumIntegral): Source integral must be non-negative.");
508 }
else if (radiation_sources.at(source_ID).source_spectrum.empty()) {
509 std::cout <<
"WARNING (RadiationModel::setSourceSpectrumIntegral): Spectral distribution has not been set for radiation source. Cannot set its integral." << std::endl;
518 wavelength.y *= source_integral / old_integral;
525 helios_runtime_error(
"ERROR (RadiationModel::setSourceFlux): Cannot add set source flux for band '" + label +
"' because it is not a valid band.");
526 }
else if (source_ID >= radiation_sources.size()) {
527 helios_runtime_error(
"ERROR (RadiationModel::setSourceFlux): Source ID out of bounds. Only " + std::to_string(radiation_sources.size() - 1) +
" radiation sources have been created.");
528 }
else if (flux < 0) {
529 helios_runtime_error(
"ERROR (RadiationModel::setSourceFlux): Source flux must be non-negative.");
535 radiation_sources.at(source_ID).source_fluxes[label] = flux * radiation_sources.at(source_ID).source_flux_scaling_factor;
539 for (
auto ID: source_ID) {
547 helios_runtime_error(
"ERROR (RadiationModel::getSourceFlux): Cannot get source flux for band '" + label +
"' because it is not a valid band.");
548 }
else if (source_ID >= radiation_sources.size()) {
549 helios_runtime_error(
"ERROR (RadiationModel::getSourceFlux): Source ID out of bounds. Only " + std::to_string(radiation_sources.size() - 1) +
" radiation sources have been created.");
550 }
else if (radiation_sources.at(source_ID).source_fluxes.find(label) == radiation_sources.at(source_ID).source_fluxes.end()) {
551 helios_runtime_error(
"ERROR (RadiationModel::getSourceFlux): Cannot get flux for source #" + std::to_string(source_ID) +
" because radiative band '" + label +
"' does not exist.");
557 vec2 wavebounds = radiation_bands.at(label).wavebandBounds;
571 if (source_ID >= radiation_sources.size()) {
572 helios_runtime_error(
"ERROR (RadiationModel::setSourceSpectrum): Cannot add radiation spectra for this source because it is not a valid radiation source ID.\n");
576 for (
auto s = 0; s < spectrum.size(); s++) {
578 if (s > 0 && spectrum.at(s).x <= spectrum.at(s - 1).x) {
579 helios_runtime_error(
"ERROR (RadiationModel::setSourceSpectrum): Source spectral data validation failed. Wavelengths must increase monotonically.");
582 if (spectrum.at(s).x < 0 || spectrum.at(s).x > 100000) {
583 helios_runtime_error(
"ERROR (RadiationModel::setSourceSpectrum): Source spectral data validation failed. Wavelength value of " + std::to_string(spectrum.at(s).x) +
" appears to be erroneous.");
586 if (spectrum.at(s).y < 0) {
587 helios_runtime_error(
"ERROR (RadiationModel::setSourceSpectrum): Source spectral data validation failed. Flux value at wavelength of " + std::to_string(spectrum.at(s).x) +
" appears is negative.");
591 radiation_sources.at(source_ID).source_spectrum = spectrum;
593 radiativepropertiesneedupdate =
true;
597 for (
auto ID: source_ID) {
604 if (source_ID >= radiation_sources.size()) {
605 helios_runtime_error(
"ERROR (RadiationModel::setSourceSpectrum): Cannot add radiation spectra for this source because it is not a valid radiation source ID.\n");
608 std::vector<vec2> spectrum = loadSpectralData(spectrum_label);
610 radiation_sources.at(source_ID).source_spectrum = spectrum;
611 radiation_sources.at(source_ID).source_spectrum_label = spectrum_label;
613 radiativepropertiesneedupdate =
true;
617 for (
auto ID: source_ID) {
624 std::vector<vec2> spectrum;
627 if (spectrum_label ==
"ASTMG173") {
628 spectrum = loadSpectralData(
"solar_spectrum_diffuse_ASTMG173");
630 spectrum = loadSpectralData(spectrum_label);
633 for (
const auto &band: band_labels) {
635 helios_runtime_error(
"ERROR (RadiationModel::setDiffuseSpectrum): Cannot set diffuse spectrum for band '" + band +
"' because it is not a valid band.");
638 radiation_bands.at(band).diffuse_spectrum = spectrum;
641 radiativepropertiesneedupdate =
true;
652 helios_runtime_error(
"ERROR (RadiationModel::getDiffuseFlux): Cannot get diffuse flux for band '" + band_label +
"' because it is not a valid band.");
655 const std::vector<vec2> &spectrum = radiation_bands.at(band_label).diffuse_spectrum;
657 if (!spectrum.empty() && radiation_bands.at(band_label).diffuseFlux < 0.f) {
658 vec2 wavebounds = radiation_bands.at(band_label).wavebandBounds;
660 wavebounds =
make_vec2(spectrum.front().x, spectrum.back().x);
664 if (radiation_bands.at(band_label).diffuseFlux < 0.f) {
668 return radiation_bands.at(band_label).diffuseFlux;
672 islightvisualizationenabled =
true;
675 for (
int s = 0; s < radiation_sources.size(); s++) {
676 buildLightModelGeometry(s);
681 islightvisualizationenabled =
false;
682 for (
auto &UUIDs: source_model_UUIDs) {
688 iscameravisualizationenabled =
true;
691 for (
auto &cam: cameras) {
692 buildCameraModelGeometry(cam.first);
697 iscameravisualizationenabled =
false;
698 for (
auto &UUIDs: camera_model_UUIDs) {
703void RadiationModel::buildLightModelGeometry(
uint sourceID) {
705 assert(sourceID < radiation_sources.size());
708 if (source.
source_type == RADIATION_SOURCE_TYPE_SPHERE) {
709 source_model_UUIDs[sourceID] = context->
loadOBJ(
"SphereLightSource.obj",
true);
710 }
else if (source.
source_type == RADIATION_SOURCE_TYPE_SUN_SPHERE) {
711 source_model_UUIDs[sourceID] = context->
loadOBJ(
"SphereLightSource.obj",
true);
712 }
else if (source.
source_type == RADIATION_SOURCE_TYPE_DISK) {
713 source_model_UUIDs[sourceID] = context->
loadOBJ(
"DiskLightSource.obj",
true);
715 std::vector<uint> UUIDs_arrow = context->
loadOBJ(
"Arrow.obj",
true);
716 source_model_UUIDs.at(sourceID).insert(source_model_UUIDs.at(sourceID).begin(), UUIDs_arrow.begin(), UUIDs_arrow.end());
718 }
else if (source.
source_type == RADIATION_SOURCE_TYPE_RECTANGLE) {
719 source_model_UUIDs[sourceID] = context->
loadOBJ(
"RectangularLightSource.obj",
true);
721 std::vector<uint> UUIDs_arrow = context->
loadOBJ(
"Arrow.obj",
true);
722 source_model_UUIDs.at(sourceID).insert(source_model_UUIDs.at(sourceID).begin(), UUIDs_arrow.begin(), UUIDs_arrow.end());
728 if (source.
source_type == RADIATION_SOURCE_TYPE_SPHERE) {
731 }
else if (source.
source_type == RADIATION_SOURCE_TYPE_SUN_SPHERE) {
738 context->
translatePrimitive(source_model_UUIDs.at(sourceID), center + sunvec * radius);
749void RadiationModel::buildCameraModelGeometry(
const std::string &cameralabel) {
751 assert(cameras.find(cameralabel) != cameras.end());
755 vec3 viewvec = camera.lookat - camera.position;
758 camera_model_UUIDs[cameralabel] = context->
loadOBJ(
"Camera.obj",
true);
768void RadiationModel::updateLightModelPosition(
uint sourceID,
const helios::vec3 &delta_position) {
770 assert(sourceID < radiation_sources.size());
774 if (source.
source_type != RADIATION_SOURCE_TYPE_SPHERE && source.
source_type != RADIATION_SOURCE_TYPE_DISK && source.
source_type != RADIATION_SOURCE_TYPE_RECTANGLE) {
781void RadiationModel::updateCameraModelPosition(
const std::string &cameralabel) {
783 assert(cameras.find(cameralabel) != cameras.end());
786 buildCameraModelGeometry(cameralabel);
791 if (source_ID >= radiation_sources.size()) {
792 helios_runtime_error(
"ERROR (RadiationModel::integrateSpectrum): Radiation spectrum was not set for source ID. Make sure to set its spectrum using setSourceSpectrum() function.");
793 }
else if (object_spectrum.size() < 2) {
794 helios_runtime_error(
"ERROR (RadiationModel::integrateSpectrum): Radiation spectrum must have at least 2 wavelengths.");
795 }
else if (wavelength1 > wavelength2 || wavelength1 == wavelength2) {
796 helios_runtime_error(
"ERROR (RadiationModel::integrateSpectrum): Lower wavelength bound must be less than the upper wavelength bound.");
799 std::vector<helios::vec2> source_spectrum = radiation_sources.at(source_ID).source_spectrum;
802 int iend = (int) object_spectrum.size() - 1;
803 for (
auto i = 0; i < object_spectrum.size() - 1; i++) {
805 if (object_spectrum.at(i).x <= wavelength1 && object_spectrum.at(i + 1).x > wavelength1) {
808 if (object_spectrum.at(i).x <= wavelength2 && object_spectrum.at(i + 1).x > wavelength2) {
816 for (
auto i = istart; i < iend; i++) {
818 float x0 = object_spectrum.at(i).x;
819 float Esource0 =
interp1(source_spectrum, object_spectrum.at(i).x);
820 float Eobject0 = object_spectrum.at(i).y;
822 float x1 = object_spectrum.at(i + 1).x;
823 float Eobject1 = object_spectrum.at(i + 1).y;
824 float Esource1 =
interp1(source_spectrum, object_spectrum.at(i + 1).x);
826 E += 0.5f * (Eobject0 * Esource0 + Eobject1 * Esource1) * (x1 - x0);
827 Etot += 0.5f * (Esource1 + Esource0) * (x1 - x0);
835 if (object_spectrum.size() < 2) {
836 helios_runtime_error(
"ERROR (RadiationModel::integrateSpectrum): Radiation spectrum must have at least 2 wavelengths.");
837 }
else if (wavelength1 > wavelength2 || wavelength1 == wavelength2) {
838 helios_runtime_error(
"ERROR (RadiationModel::integrateSpectrum): Lower wavelength bound must be less than the upper wavelength bound.");
842 int iend = (int) object_spectrum.size() - 1;
843 for (
auto i = 0; i < object_spectrum.size() - 1; i++) {
845 if (object_spectrum.at(i).x <= wavelength1 && object_spectrum.at(i + 1).x > wavelength1) {
848 if (object_spectrum.at(i).x <= wavelength2 && object_spectrum.at(i + 1).x > wavelength2) {
855 for (
auto i = istart; i < iend; i++) {
856 float E0 = object_spectrum.at(i).y;
857 float x0 = object_spectrum.at(i).x;
858 float E1 = object_spectrum.at(i + 1).y;
859 float x1 = object_spectrum.at(i + 1).x;
860 E += (E0 + E1) * (x1 - x0) * 0.5f;
867 float wavelength1 = object_spectrum.at(0).x;
868 float wavelength2 = object_spectrum.at(object_spectrum.size() - 1).x;
875 if (source_ID >= radiation_sources.size()) {
876 helios_runtime_error(
"ERROR (RadiationModel::integrateSpectrum): Radiation spectrum was not set for source ID. Make sure to set its spectrum using setSourceSpectrum() function.");
877 }
else if (object_spectrum.size() < 2) {
878 helios_runtime_error(
"ERROR (RadiationModel::integrateSpectrum): Radiation spectrum must have at least 2 wavelengths.");
881 std::vector<helios::vec2> source_spectrum = radiation_sources.at(source_ID).source_spectrum;
885 for (
auto i = 1; i < object_spectrum.size(); i++) {
887 if (object_spectrum.at(i).x <= source_spectrum.front().x || object_spectrum.at(i).x <= camera_spectrum.front().x) {
890 if (object_spectrum.at(i).x > source_spectrum.back().x || object_spectrum.at(i).x > camera_spectrum.back().x) {
893 float x1 = object_spectrum.at(i).x;
894 float Eobject1 = object_spectrum.at(i).y;
895 float Esource1 =
interp1(source_spectrum, x1);
896 float Ecamera1 =
interp1(camera_spectrum, x1);
899 float x0 = object_spectrum.at(i - 1).x;
900 float Eobject0 = object_spectrum.at(i - 1).y;
901 float Esource0 =
interp1(source_spectrum, x0);
902 float Ecamera0 =
interp1(camera_spectrum, x0);
904 E += 0.5f * ((Eobject1 * Esource1 * Ecamera1) + (Eobject0 * Ecamera0 * Esource0)) * (x1 - x0);
905 Etot += 0.5f * (Esource1 + Esource0) * (x1 - x0);
914 if (object_spectrum.size() < 2) {
915 helios_runtime_error(
"ERROR (RadiationModel::integrateSpectrum): Radiation spectrum must have at least 2 wavelengths.");
920 for (
auto i = 1; i < object_spectrum.size(); i++) {
922 if (object_spectrum.at(i).x <= camera_spectrum.front().x) {
925 if (object_spectrum.at(i).x > camera_spectrum.back().x) {
929 float x1 = object_spectrum.at(i).x;
930 float Eobject1 = object_spectrum.at(i).y;
931 float Ecamera1 =
interp1(camera_spectrum, x1);
934 float x0 = object_spectrum.at(i - 1).x;
935 float Eobject0 = object_spectrum.at(i - 1).y;
936 float Ecamera0 =
interp1(camera_spectrum, x0);
938 E += 0.5f * ((Eobject1 * Ecamera1) + (Eobject0 * Ecamera0)) * (x1 - x0);
939 Etot += 0.5f * (Ecamera1 + Ecamera0) * (x1 - x0);
947 if (source_ID >= radiation_sources.size()) {
948 helios_runtime_error(
"ERROR (RadiationModel::integrateSourceSpectrum): Radiation spectrum was not set for source ID. Make sure to set its spectrum using setSourceSpectrum() function.");
949 }
else if (wavelength1 > wavelength2 || wavelength1 == wavelength2) {
950 helios_runtime_error(
"ERROR (RadiationModel::integrateSourceSpectrum): Lower wavelength bound must be less than the upper wavelength bound.");
953 return integrateSpectrum(radiation_sources.at(source_ID).source_spectrum, wavelength1, wavelength2);
958 std::vector<helios::vec2> spectrum = loadSpectralData(existing_global_data_label);
964 context->
setGlobalData(new_global_data_label.c_str(), spectrum);
969 std::vector<vec2> spectrum = loadSpectralData(global_data_label);
971 for (
vec2 &s: spectrum) {
980 scaleSpectrum(existing_global_data_label, new_global_data_label, context->
randu(minimum_scale_factor, maximum_scale_factor));
984void RadiationModel::blendSpectra(
const std::string &new_spectrum_label,
const std::vector<std::string> &spectrum_labels,
const std::vector<float> &weights)
const {
986 if (spectrum_labels.size() != weights.size()) {
987 helios_runtime_error(
"ERROR (RadiationModel::blendSpectra): number of spectra and weights must be equal");
988 }
else if (
sum(weights) != 1.f) {
992 std::vector<vec2> new_spectrum;
993 uint spectrum_size = 0;
995 std::vector<std::vector<vec2>> spectrum(spectrum_labels.size());
997 uint lambda_start = 0;
999 for (
uint i = 0; i < spectrum_labels.size(); i++) {
1001 spectrum.at(i) = loadSpectralData(spectrum_labels.at(i));
1004 lambda_start = spectrum.at(i).front().x;
1005 lambda_end = spectrum.at(i).back().x;
1007 if (spectrum.at(i).front().x > lambda_start) {
1008 lambda_start = spectrum.at(i).front().x;
1010 if (spectrum.at(i).back().x < lambda_end) {
1011 lambda_end = spectrum.at(i).back().x;
1016 spectrum_size = lambda_end - lambda_start + 1;
1017 new_spectrum.resize(spectrum_size);
1018 for (
uint j = 0; j < spectrum_size; j++) {
1019 new_spectrum.at(j) =
make_vec2(lambda_start + j, 0);
1023 for (
uint i = 0; i < spectrum_labels.size(); i++) {
1024 for (
uint j = 0; j < spectrum.at(i).size(); j++) {
1026 if (spectrum.at(i).at(j).x >= lambda_start) {
1028 spectrum.at(i).erase(spectrum.at(i).begin(), spectrum.at(i).begin() + j);
1036 for (
uint i = 0; i < spectrum_labels.size(); i++) {
1037 for (
int j = spectrum.at(i).size() - 1; j <= 0; j--) {
1039 if (spectrum.at(i).at(j).x <= lambda_end) {
1040 if (j < spectrum.at(i).size() - 1) {
1041 spectrum.at(i).erase(spectrum.at(i).begin() + j + 1, spectrum.at(i).end());
1048 for (
uint i = 0; i < spectrum_labels.size(); i++) {
1049 for (
uint j = 0; j < spectrum_size; j++) {
1050 assert(new_spectrum.at(j).x == spectrum.at(i).at(j).x);
1051 new_spectrum.at(j).y += weights.at(i) * spectrum.at(i).at(j).y;
1055 context->
setGlobalData(new_spectrum_label.c_str(), new_spectrum);
1060 std::vector<float> weights;
1061 weights.resize(spectrum_labels.size());
1062 for (
uint i = 0; i < spectrum_labels.size(); i++) {
1063 weights.at(i) = context->
randu();
1065 float sum_weights =
sum(weights);
1066 for (
uint i = 0; i < spectrum_labels.size(); i++) {
1067 weights.at(i) /= sum_weights;
1070 blendSpectra(new_spectrum_label, spectrum_labels, weights);
1075 if (source_ID >= radiation_sources.size()) {
1076 helios_runtime_error(
"ERROR (RadiationModel::setSourcePosition): Source ID out of bounds. Only " + std::to_string(radiation_sources.size() - 1) +
" radiation sources.");
1079 vec3 old_position = radiation_sources.at(source_ID).source_position;
1081 if (radiation_sources.at(source_ID).source_type == RADIATION_SOURCE_TYPE_COLLIMATED) {
1082 radiation_sources.at(source_ID).source_position = position / position.
magnitude();
1084 radiation_sources.at(source_ID).source_position = position * radiation_sources.at(source_ID).source_position_scaling_factor;
1087 if (islightvisualizationenabled) {
1088 updateLightModelPosition(source_ID, radiation_sources.at(source_ID).source_position - old_position);
1097 if (source_ID >= radiation_sources.size()) {
1100 return radiation_sources.at(source_ID).source_position;
1106 helios_runtime_error(
"ERROR (RadiationModel::setScatteringDepth): Cannot set scattering depth for band '" + label +
"' because it is not a valid band.");
1108 radiation_bands.at(label).scatteringDepth = depth;
1114 helios_runtime_error(
"ERROR (setMinScatterEnergy): Cannot set minimum scattering energy for band '" + label +
"' because it is not a valid band.");
1116 radiation_bands.at(label).minScatterEnergy = energy;
1121 if (boundary ==
"x") {
1123 periodic_flag.
x = 1;
1125 }
else if (boundary ==
"y") {
1127 periodic_flag.
y = 1;
1129 }
else if (boundary ==
"xy") {
1131 periodic_flag.
x = 1;
1132 periodic_flag.
y = 1;
1136 std::cout <<
"WARNING (RadiationModel::enforcePeriodicBoundary()): unknown boundary of '" << boundary
1137 <<
"'. Possible choices are "
1148void RadiationModel::initializeOptiX() {
1151 RT_CHECK_ERROR(rtContextCreate(&OptiX_Context));
1152 RT_CHECK_ERROR(rtContextSetPrintEnabled(OptiX_Context, 1));
1154 RT_CHECK_ERROR(rtContextSetRayTypeCount(OptiX_Context, 4));
1161 RT_CHECK_ERROR(rtContextSetEntryPointCount(OptiX_Context, 4));
1169 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"direct_ray_type", &direct_ray_type_RTvariable));
1170 RT_CHECK_ERROR(rtVariableSet1ui(direct_ray_type_RTvariable, RAYTYPE_DIRECT));
1171 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"diffuse_ray_type", &diffuse_ray_type_RTvariable));
1172 RT_CHECK_ERROR(rtVariableSet1ui(diffuse_ray_type_RTvariable, RAYTYPE_DIFFUSE));
1173 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"camera_ray_type", &camera_ray_type_RTvariable));
1174 RT_CHECK_ERROR(rtVariableSet1ui(camera_ray_type_RTvariable, RAYTYPE_CAMERA));
1175 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"pixel_label_ray_type", &pixel_label_ray_type_RTvariable));
1176 RT_CHECK_ERROR(rtVariableSet1ui(pixel_label_ray_type_RTvariable, RAYTYPE_PIXEL_LABEL));
1180 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_rayGeneration.cu.ptx").
string().c_str(),
"direct_raygen", &direct_raygen));
1181 RT_CHECK_ERROR(rtContextSetRayGenerationProgram(OptiX_Context, RAYTYPE_DIRECT, direct_raygen));
1182 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_rayGeneration.cu.ptx").
string().c_str(),
"diffuse_raygen", &diffuse_raygen));
1183 RT_CHECK_ERROR(rtContextSetRayGenerationProgram(OptiX_Context, RAYTYPE_DIFFUSE, diffuse_raygen));
1184 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_rayGeneration.cu.ptx").
string().c_str(),
"camera_raygen", &camera_raygen));
1185 RT_CHECK_ERROR(rtContextSetRayGenerationProgram(OptiX_Context, RAYTYPE_CAMERA, camera_raygen));
1186 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_rayGeneration.cu.ptx").
string().c_str(),
"pixel_label_raygen", &pixel_label_raygen));
1187 RT_CHECK_ERROR(rtContextSetRayGenerationProgram(OptiX_Context, RAYTYPE_PIXEL_LABEL, pixel_label_raygen));
1192 addBuffer(
"rho", rho_RTbuffer, rho_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT, 1);
1194 addBuffer(
"tau", tau_RTbuffer, tau_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT, 1);
1197 addBuffer(
"rho_cam", rho_cam_RTbuffer, rho_cam_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT, 1);
1199 addBuffer(
"tau_cam", tau_cam_RTbuffer, tau_cam_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT, 1);
1202 addBuffer(
"specular_exponent", specular_exponent_RTbuffer, specular_exponent_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT, 1);
1205 addBuffer(
"specular_scale", specular_scale_RTbuffer, specular_scale_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT, 1);
1208 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"specular_reflection_enabled", &specular_reflection_enabled_RTvariable));
1209 RT_CHECK_ERROR(rtVariableSet1ui(specular_reflection_enabled_RTvariable, 0));
1212 addBuffer(
"transform_matrix", transform_matrix_RTbuffer, transform_matrix_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT, 2);
1215 addBuffer(
"primitive_type", primitive_type_RTbuffer, primitive_type_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_UNSIGNED_INT, 1);
1218 addBuffer(
"primitive_solid_fraction", primitive_solid_fraction_RTbuffer, primitive_solid_fraction_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT, 1);
1221 addBuffer(
"patch_UUID", patch_UUID_RTbuffer, patch_UUID_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_UNSIGNED_INT, 1);
1222 addBuffer(
"triangle_UUID", triangle_UUID_RTbuffer, triangle_UUID_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_UNSIGNED_INT, 1);
1223 addBuffer(
"disk_UUID", disk_UUID_RTbuffer, disk_UUID_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_UNSIGNED_INT, 1);
1224 addBuffer(
"tile_UUID", tile_UUID_RTbuffer, tile_UUID_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_UNSIGNED_INT, 1);
1225 addBuffer(
"voxel_UUID", voxel_UUID_RTbuffer, voxel_UUID_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_UNSIGNED_INT, 1);
1228 addBuffer(
"objectID", objectID_RTbuffer, objectID_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_UNSIGNED_INT, 1);
1231 addBuffer(
"primitiveID", primitiveID_RTbuffer, primitiveID_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_UNSIGNED_INT, 1);
1234 addBuffer(
"twosided_flag", twosided_flag_RTbuffer, twosided_flag_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_BYTE, 1);
1237 addBuffer(
"patch_vertices", patch_vertices_RTbuffer, patch_vertices_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, 2);
1240 addBuffer(
"triangle_vertices", triangle_vertices_RTbuffer, triangle_vertices_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, 2);
1243 addBuffer(
"disk_centers", disk_centers_RTbuffer, disk_centers_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, 1);
1244 addBuffer(
"disk_radii", disk_radii_RTbuffer, disk_radii_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT, 1);
1245 addBuffer(
"disk_normals", disk_normals_RTbuffer, disk_normals_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, 1);
1248 addBuffer(
"tile_vertices", tile_vertices_RTbuffer, tile_vertices_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, 2);
1251 addBuffer(
"voxel_vertices", voxel_vertices_RTbuffer, voxel_vertices_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, 2);
1254 addBuffer(
"object_subdivisions", object_subdivisions_RTbuffer, object_subdivisions_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_INT2, 1);
1258 addBuffer(
"radiation_in", radiation_in_RTbuffer, radiation_in_RTvariable, RT_BUFFER_INPUT_OUTPUT, RT_FORMAT_FLOAT, 1);
1260 addBuffer(
"radiation_out_top", radiation_out_top_RTbuffer, radiation_out_top_RTvariable, RT_BUFFER_INPUT_OUTPUT, RT_FORMAT_FLOAT, 1);
1262 addBuffer(
"radiation_out_bottom", radiation_out_bottom_RTbuffer, radiation_out_bottom_RTvariable, RT_BUFFER_INPUT_OUTPUT, RT_FORMAT_FLOAT, 1);
1264 addBuffer(
"radiation_in_camera", radiation_in_camera_RTbuffer, radiation_in_camera_RTvariable, RT_BUFFER_INPUT_OUTPUT, RT_FORMAT_FLOAT, 1);
1265 addBuffer(
"camera_pixel_label", camera_pixel_label_RTbuffer, camera_pixel_label_RTvariable, RT_BUFFER_INPUT_OUTPUT, RT_FORMAT_UNSIGNED_INT, 1);
1266 addBuffer(
"camera_pixel_depth", camera_pixel_depth_RTbuffer, camera_pixel_depth_RTvariable, RT_BUFFER_INPUT_OUTPUT, RT_FORMAT_FLOAT, 1);
1270 addBuffer(
"scatter_buff_top", scatter_buff_top_RTbuffer, scatter_buff_top_RTvariable, RT_BUFFER_INPUT_OUTPUT, RT_FORMAT_FLOAT, 1);
1272 addBuffer(
"scatter_buff_bottom", scatter_buff_bottom_RTbuffer, scatter_buff_bottom_RTvariable, RT_BUFFER_INPUT_OUTPUT, RT_FORMAT_FLOAT, 1);
1275 addBuffer(
"Rsky", Rsky_RTbuffer, Rsky_RTvariable, RT_BUFFER_INPUT_OUTPUT, RT_FORMAT_FLOAT, 1);
1278 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"Nsources", &Nsources_RTvariable));
1279 RT_CHECK_ERROR(rtVariableSet1ui(Nsources_RTvariable, 0));
1282 addBuffer(
"source_positions", source_positions_RTbuffer, source_positions_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, 1);
1285 addBuffer(
"source_widths", source_widths_RTbuffer, source_widths_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT2, 1);
1288 addBuffer(
"source_rotations", source_rotations_RTbuffer, source_rotations_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, 1);
1291 addBuffer(
"source_types", source_types_RTbuffer, source_types_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_UNSIGNED_INT, 1);
1294 addBuffer(
"source_fluxes", source_fluxes_RTbuffer, source_fluxes_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT, 1);
1297 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"Nbands_global", &Nbands_global_RTvariable));
1298 RT_CHECK_ERROR(rtVariableSet1ui(Nbands_global_RTvariable, 0));
1299 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"Nbands_launch", &Nbands_launch_RTvariable));
1300 RT_CHECK_ERROR(rtVariableSet1ui(Nbands_launch_RTvariable, 0));
1303 addBuffer(
"band_launch_flag", band_launch_flag_RTbuffer, band_launch_flag_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_BYTE, 1);
1306 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"Nprimitives", &Nprimitives_RTvariable));
1307 RT_CHECK_ERROR(rtVariableSet1ui(Nprimitives_RTvariable, 0));
1310 addBuffer(
"diffuse_flux", diffuse_flux_RTbuffer, diffuse_flux_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT, 1);
1313 addBuffer(
"diffuse_extinction", diffuse_extinction_RTbuffer, diffuse_extinction_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT, 1);
1316 addBuffer(
"diffuse_peak_dir", diffuse_peak_dir_RTbuffer, diffuse_peak_dir_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, 1);
1319 addBuffer(
"diffuse_dist_norm", diffuse_dist_norm_RTbuffer, diffuse_dist_norm_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT, 1);
1322 addBuffer(
"bbox_UUID", bbox_UUID_RTbuffer, bbox_UUID_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_UNSIGNED_INT, 1);
1323 addBuffer(
"bbox_vertices", bbox_vertices_RTbuffer, bbox_vertices_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT3, 2);
1325 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"periodic_flag", &periodic_flag_RTvariable));
1326 RT_CHECK_ERROR(rtVariableSet2f(periodic_flag_RTvariable, 0.f, 0.f));
1329 RT_CHECK_ERROR(rtBufferCreate(OptiX_Context, RT_BUFFER_INPUT, &maskdata_RTbuffer));
1330 RT_CHECK_ERROR(rtBufferSetFormat(maskdata_RTbuffer, RT_FORMAT_BYTE));
1331 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"maskdata", &maskdata_RTvariable));
1332 RT_CHECK_ERROR(rtVariableSetObject(maskdata_RTvariable, maskdata_RTbuffer));
1333 std::vector<std::vector<std::vector<bool>>> dummydata;
1334 initializeBuffer3D(maskdata_RTbuffer, dummydata);
1337 addBuffer(
"masksize", masksize_RTbuffer, masksize_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_INT2, 1);
1340 addBuffer(
"maskID", maskID_RTbuffer, maskID_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_INT, 1);
1343 addBuffer(
"uvdata", uvdata_RTbuffer, uvdata_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_FLOAT2, 2);
1346 addBuffer(
"uvID", uvID_RTbuffer, uvID_RTvariable, RT_BUFFER_INPUT, RT_FORMAT_INT, 1);
1349 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"camera_position", &camera_position_RTvariable));
1350 RT_CHECK_ERROR(rtVariableSet3f(camera_position_RTvariable, 0.f, 0.f, 0.f));
1351 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"camera_direction", &camera_direction_RTvariable));
1352 RT_CHECK_ERROR(rtVariableSet2f(camera_direction_RTvariable, 0.f, 0.f));
1353 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"camera_lens_diameter", &camera_lens_diameter_RTvariable));
1354 RT_CHECK_ERROR(rtVariableSet1f(camera_lens_diameter_RTvariable, 0.f));
1355 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"FOV_aspect_ratio", &FOV_aspect_RTvariable));
1356 RT_CHECK_ERROR(rtVariableSet1f(FOV_aspect_RTvariable, 1.f));
1357 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"camera_focal_length", &camera_focal_length_RTvariable));
1358 RT_CHECK_ERROR(rtVariableSet1f(camera_focal_length_RTvariable, 0.f));
1359 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"camera_viewplane_length", &camera_viewplane_length_RTvariable));
1360 RT_CHECK_ERROR(rtVariableSet1f(camera_viewplane_length_RTvariable, 0.f));
1361 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"Ncameras", &Ncameras_RTvariable));
1362 RT_CHECK_ERROR(rtVariableSet1ui(Ncameras_RTvariable, 0));
1363 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"camera_ID", &camera_ID_RTvariable));
1364 RT_CHECK_ERROR(rtVariableSet1ui(camera_ID_RTvariable, 0));
1367 addBuffer(
"scatter_buff_top_cam", scatter_buff_top_cam_RTbuffer, scatter_buff_top_cam_RTvariable, RT_BUFFER_INPUT_OUTPUT, RT_FORMAT_FLOAT, 1);
1368 addBuffer(
"scatter_buff_bottom_cam", scatter_buff_bottom_cam_RTbuffer, scatter_buff_bottom_cam_RTvariable, RT_BUFFER_INPUT_OUTPUT, RT_FORMAT_FLOAT, 1);
1371 RTprogram closest_hit_direct;
1372 RTprogram closest_hit_diffuse;
1373 RTprogram closest_hit_camera;
1374 RTprogram closest_hit_pixel_label;
1375 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_rayHit.cu.ptx").
string().c_str(),
"closest_hit_direct", &closest_hit_direct));
1376 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_rayHit.cu.ptx").
string().c_str(),
"closest_hit_diffuse", &closest_hit_diffuse));
1377 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_rayHit.cu.ptx").
string().c_str(),
"closest_hit_camera", &closest_hit_camera));
1378 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_rayHit.cu.ptx").
string().c_str(),
"closest_hit_pixel_label", &closest_hit_pixel_label));
1382 RTprogram patch_intersection_program;
1383 RTprogram patch_bounding_box_program;
1385 RT_CHECK_ERROR(rtGeometryCreate(OptiX_Context, &patch));
1387 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_primitiveIntersection.cu.ptx").
string().c_str(),
"rectangle_bounds", &patch_bounding_box_program));
1388 RT_CHECK_ERROR(rtGeometrySetBoundingBoxProgram(patch, patch_bounding_box_program));
1389 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_primitiveIntersection.cu.ptx").
string().c_str(),
"rectangle_intersect", &patch_intersection_program));
1390 RT_CHECK_ERROR(rtGeometrySetIntersectionProgram(patch, patch_intersection_program));
1394 RT_CHECK_ERROR(rtMaterialCreate(OptiX_Context, &patch_material));
1396 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(patch_material, RAYTYPE_DIRECT, closest_hit_direct));
1397 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(patch_material, RAYTYPE_DIFFUSE, closest_hit_diffuse));
1398 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(patch_material, RAYTYPE_CAMERA, closest_hit_camera));
1399 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(patch_material, RAYTYPE_PIXEL_LABEL, closest_hit_pixel_label));
1403 RTprogram triangle_intersection_program;
1404 RTprogram triangle_bounding_box_program;
1406 RT_CHECK_ERROR(rtGeometryCreate(OptiX_Context, &triangle));
1408 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_primitiveIntersection.cu.ptx").
string().c_str(),
"triangle_bounds", &triangle_bounding_box_program));
1409 RT_CHECK_ERROR(rtGeometrySetBoundingBoxProgram(triangle, triangle_bounding_box_program));
1410 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_primitiveIntersection.cu.ptx").
string().c_str(),
"triangle_intersect", &triangle_intersection_program));
1411 RT_CHECK_ERROR(rtGeometrySetIntersectionProgram(triangle, triangle_intersection_program));
1415 RT_CHECK_ERROR(rtMaterialCreate(OptiX_Context, &triangle_material));
1417 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(triangle_material, RAYTYPE_DIRECT, closest_hit_direct));
1418 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(triangle_material, RAYTYPE_DIFFUSE, closest_hit_diffuse));
1419 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(triangle_material, RAYTYPE_CAMERA, closest_hit_camera));
1420 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(triangle_material, RAYTYPE_PIXEL_LABEL, closest_hit_pixel_label));
1424 RTprogram disk_intersection_program;
1425 RTprogram disk_bounding_box_program;
1427 RT_CHECK_ERROR(rtGeometryCreate(OptiX_Context, &disk));
1429 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_primitiveIntersection.cu.ptx").
string().c_str(),
"disk_bounds", &disk_bounding_box_program));
1430 RT_CHECK_ERROR(rtGeometrySetBoundingBoxProgram(disk, disk_bounding_box_program));
1431 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_primitiveIntersection.cu.ptx").
string().c_str(),
"disk_intersect", &disk_intersection_program));
1432 RT_CHECK_ERROR(rtGeometrySetIntersectionProgram(disk, disk_intersection_program));
1436 RT_CHECK_ERROR(rtMaterialCreate(OptiX_Context, &disk_material));
1438 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(disk_material, RAYTYPE_DIRECT, closest_hit_direct));
1439 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(disk_material, RAYTYPE_DIFFUSE, closest_hit_diffuse));
1440 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(disk_material, RAYTYPE_CAMERA, closest_hit_camera));
1441 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(disk_material, RAYTYPE_PIXEL_LABEL, closest_hit_pixel_label));
1445 RTprogram tile_intersection_program;
1446 RTprogram tile_bounding_box_program;
1448 RT_CHECK_ERROR(rtGeometryCreate(OptiX_Context, &tile));
1450 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_primitiveIntersection.cu.ptx").
string().c_str(),
"tile_bounds", &tile_bounding_box_program));
1451 RT_CHECK_ERROR(rtGeometrySetBoundingBoxProgram(tile, tile_bounding_box_program));
1452 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_primitiveIntersection.cu.ptx").
string().c_str(),
"tile_intersect", &tile_intersection_program));
1453 RT_CHECK_ERROR(rtGeometrySetIntersectionProgram(tile, tile_intersection_program));
1457 RT_CHECK_ERROR(rtMaterialCreate(OptiX_Context, &tile_material));
1459 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(tile_material, RAYTYPE_DIRECT, closest_hit_direct));
1460 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(tile_material, RAYTYPE_DIFFUSE, closest_hit_diffuse));
1461 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(tile_material, RAYTYPE_CAMERA, closest_hit_camera));
1462 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(tile_material, RAYTYPE_PIXEL_LABEL, closest_hit_pixel_label));
1466 RTprogram voxel_intersection_program;
1467 RTprogram voxel_bounding_box_program;
1469 RT_CHECK_ERROR(rtGeometryCreate(OptiX_Context, &voxel));
1471 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_primitiveIntersection.cu.ptx").
string().c_str(),
"voxel_bounds", &voxel_bounding_box_program));
1472 RT_CHECK_ERROR(rtGeometrySetBoundingBoxProgram(voxel, voxel_bounding_box_program));
1473 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_primitiveIntersection.cu.ptx").
string().c_str(),
"voxel_intersect", &voxel_intersection_program));
1474 RT_CHECK_ERROR(rtGeometrySetIntersectionProgram(voxel, voxel_intersection_program));
1478 RT_CHECK_ERROR(rtMaterialCreate(OptiX_Context, &voxel_material));
1480 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(voxel_material, RAYTYPE_DIRECT, closest_hit_direct));
1481 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(voxel_material, RAYTYPE_DIFFUSE, closest_hit_diffuse));
1482 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(voxel_material, RAYTYPE_CAMERA, closest_hit_camera));
1483 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(voxel_material, RAYTYPE_PIXEL_LABEL, closest_hit_pixel_label));
1487 RTprogram bbox_intersection_program;
1488 RTprogram bbox_bounding_box_program;
1490 RT_CHECK_ERROR(rtGeometryCreate(OptiX_Context, &bbox));
1492 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_primitiveIntersection.cu.ptx").
string().c_str(),
"bbox_bounds", &bbox_bounding_box_program));
1493 RT_CHECK_ERROR(rtGeometrySetBoundingBoxProgram(bbox, bbox_bounding_box_program));
1494 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_primitiveIntersection.cu.ptx").
string().c_str(),
"bbox_intersect", &bbox_intersection_program));
1495 RT_CHECK_ERROR(rtGeometrySetIntersectionProgram(bbox, bbox_intersection_program));
1499 RT_CHECK_ERROR(rtMaterialCreate(OptiX_Context, &bbox_material));
1501 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(bbox_material, RAYTYPE_DIRECT, closest_hit_direct));
1502 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(bbox_material, RAYTYPE_DIFFUSE, closest_hit_diffuse));
1503 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(bbox_material, RAYTYPE_CAMERA, closest_hit_camera));
1504 RT_CHECK_ERROR(rtMaterialSetClosestHitProgram(bbox_material, RAYTYPE_PIXEL_LABEL, closest_hit_pixel_label));
1507 RTprogram miss_program_direct;
1508 RTprogram miss_program_diffuse;
1509 RTprogram miss_program_camera;
1510 RTprogram miss_program_pixel_label;
1511 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_rayHit.cu.ptx").
string().c_str(),
"miss_direct", &miss_program_direct));
1512 RT_CHECK_ERROR(rtContextSetMissProgram(OptiX_Context, RAYTYPE_DIRECT, miss_program_direct));
1513 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_rayHit.cu.ptx").
string().c_str(),
"miss_diffuse", &miss_program_diffuse));
1514 RT_CHECK_ERROR(rtContextSetMissProgram(OptiX_Context, RAYTYPE_DIFFUSE, miss_program_diffuse));
1515 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_rayHit.cu.ptx").
string().c_str(),
"miss_camera", &miss_program_camera));
1516 RT_CHECK_ERROR(rtContextSetMissProgram(OptiX_Context, RAYTYPE_CAMERA, miss_program_camera));
1517 RT_CHECK_ERROR(rtProgramCreateFromPTXFile(OptiX_Context,
helios::resolvePluginAsset(
"radiation",
"cuda_compile_ptx_generated_rayHit.cu.ptx").
string().c_str(),
"miss_pixel_label", &miss_program_pixel_label));
1518 RT_CHECK_ERROR(rtContextSetMissProgram(OptiX_Context, RAYTYPE_PIXEL_LABEL, miss_program_pixel_label));
1522 RTtransform transform;
1524 RTgeometryinstance patch_instance;
1525 RTgeometryinstance triangle_instance;
1526 RTgeometryinstance disk_instance;
1527 RTgeometryinstance tile_instance;
1528 RTgeometryinstance voxel_instance;
1529 RTgeometryinstance bbox_instance;
1532 RT_CHECK_ERROR(rtGroupCreate(OptiX_Context, &top_level_group));
1533 RT_CHECK_ERROR(rtGroupSetChildCount(top_level_group, 1));
1535 RT_CHECK_ERROR(rtAccelerationCreate(OptiX_Context, &top_level_acceleration));
1536 RT_CHECK_ERROR(rtAccelerationSetBuilder(top_level_acceleration,
"NoAccel"));
1537 RT_CHECK_ERROR(rtAccelerationSetTraverser(top_level_acceleration,
"NoAccel"));
1538 RT_CHECK_ERROR(rtGroupSetAcceleration(top_level_group, top_level_acceleration));
1541 RT_CHECK_ERROR(rtAccelerationMarkDirty(top_level_acceleration));
1544 RT_CHECK_ERROR(rtTransformCreate(OptiX_Context, &transform));
1562 RT_CHECK_ERROR(rtTransformSetMatrix(transform, 0, m,
nullptr));
1563 RT_CHECK_ERROR(rtGroupSetChild(top_level_group, 0, transform));
1566 RT_CHECK_ERROR(rtGeometryGroupCreate(OptiX_Context, &base_geometry_group));
1567 RT_CHECK_ERROR(rtGeometryGroupSetChildCount(base_geometry_group, 6));
1568 RT_CHECK_ERROR(rtTransformSetChild(transform, base_geometry_group));
1571 RT_CHECK_ERROR(rtAccelerationCreate(OptiX_Context, &geometry_acceleration));
1572 RT_CHECK_ERROR(rtAccelerationSetBuilder(geometry_acceleration,
"Trbvh"));
1573 RT_CHECK_ERROR(rtAccelerationSetTraverser(geometry_acceleration,
"Bvh"));
1574 RT_CHECK_ERROR(rtGeometryGroupSetAcceleration(base_geometry_group, geometry_acceleration));
1575 RT_CHECK_ERROR(rtAccelerationMarkDirty(geometry_acceleration));
1579 RT_CHECK_ERROR(rtGeometryInstanceCreate(OptiX_Context, &patch_instance));
1580 RT_CHECK_ERROR(rtGeometryInstanceSetGeometry(patch_instance, patch));
1581 RT_CHECK_ERROR(rtGeometryInstanceSetMaterialCount(patch_instance, 1));
1582 RT_CHECK_ERROR(rtGeometryInstanceSetMaterial(patch_instance, 0, patch_material));
1583 RT_CHECK_ERROR(rtGeometryGroupSetChild(base_geometry_group, 0, patch_instance));
1585 RT_CHECK_ERROR(rtGeometryInstanceCreate(OptiX_Context, &triangle_instance));
1586 RT_CHECK_ERROR(rtGeometryInstanceSetGeometry(triangle_instance, triangle));
1587 RT_CHECK_ERROR(rtGeometryInstanceSetMaterialCount(triangle_instance, 1));
1588 RT_CHECK_ERROR(rtGeometryInstanceSetMaterial(triangle_instance, 0, triangle_material));
1589 RT_CHECK_ERROR(rtGeometryGroupSetChild(base_geometry_group, 1, triangle_instance));
1591 RT_CHECK_ERROR(rtGeometryInstanceCreate(OptiX_Context, &disk_instance));
1592 RT_CHECK_ERROR(rtGeometryInstanceSetGeometry(disk_instance, disk));
1593 RT_CHECK_ERROR(rtGeometryInstanceSetMaterialCount(disk_instance, 1));
1594 RT_CHECK_ERROR(rtGeometryInstanceSetMaterial(disk_instance, 0, disk_material));
1595 RT_CHECK_ERROR(rtGeometryGroupSetChild(base_geometry_group, 2, disk_instance));
1597 RT_CHECK_ERROR(rtGeometryInstanceCreate(OptiX_Context, &tile_instance));
1598 RT_CHECK_ERROR(rtGeometryInstanceSetGeometry(tile_instance, tile));
1599 RT_CHECK_ERROR(rtGeometryInstanceSetMaterialCount(tile_instance, 1));
1600 RT_CHECK_ERROR(rtGeometryInstanceSetMaterial(tile_instance, 0, tile_material));
1601 RT_CHECK_ERROR(rtGeometryGroupSetChild(base_geometry_group, 3, tile_instance));
1603 RT_CHECK_ERROR(rtGeometryInstanceCreate(OptiX_Context, &voxel_instance));
1604 RT_CHECK_ERROR(rtGeometryInstanceSetGeometry(voxel_instance, voxel));
1605 RT_CHECK_ERROR(rtGeometryInstanceSetMaterialCount(voxel_instance, 1));
1606 RT_CHECK_ERROR(rtGeometryInstanceSetMaterial(voxel_instance, 0, voxel_material));
1607 RT_CHECK_ERROR(rtGeometryGroupSetChild(base_geometry_group, 4, voxel_instance));
1610 RT_CHECK_ERROR(rtGeometryInstanceCreate(OptiX_Context, &bbox_instance));
1611 RT_CHECK_ERROR(rtGeometryInstanceSetGeometry(bbox_instance, bbox));
1612 RT_CHECK_ERROR(rtGeometryInstanceSetMaterialCount(bbox_instance, 1));
1613 RT_CHECK_ERROR(rtGeometryInstanceSetMaterial(bbox_instance, 0, bbox_material));
1614 RT_CHECK_ERROR(rtGeometryGroupSetChild(base_geometry_group, 5, bbox_instance));
1618 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"top_object", &top_object));
1619 RT_CHECK_ERROR(rtVariableSetObject(top_object, top_level_group));
1622 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"random_seed", &random_seed_RTvariable));
1623 RT_CHECK_ERROR(rtVariableSet1ui(random_seed_RTvariable, std::chrono::system_clock::now().time_since_epoch().count()));
1626 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"launch_offset", &launch_offset_RTvariable));
1627 RT_CHECK_ERROR(rtVariableSet1ui(launch_offset_RTvariable, 0));
1630 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"launch_face", &launch_face_RTvariable));
1631 RT_CHECK_ERROR(rtVariableSet1ui(launch_face_RTvariable, 0));
1634 RT_CHECK_ERROR(rtBufferCreate(OptiX_Context, RT_BUFFER_INPUT, &max_scatters_RTbuffer));
1635 RT_CHECK_ERROR(rtBufferSetFormat(max_scatters_RTbuffer, RT_FORMAT_UNSIGNED_INT));
1636 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context,
"max_scatters", &max_scatters_RTvariable));
1637 RT_CHECK_ERROR(rtVariableSetObject(max_scatters_RTvariable, max_scatters_RTbuffer));
1638 zeroBuffer1D(max_scatters_RTbuffer, 1);
1658 std::cout <<
"Updating geometry in radiation transport model..." << std::flush;
1661 context_UUIDs = UUIDs;
1664 for (std::size_t u = context_UUIDs.size(); u-- > 0;) {
1666 context_UUIDs[u] = context_UUIDs.back();
1667 context_UUIDs.pop_back();
1672 context_UUIDs[u] = context_UUIDs.back();
1673 context_UUIDs.pop_back();
1679 size_t Nprimitives = context_UUIDs.size();
1681 if (Nprimitives == 0) {
1682 std::cerr <<
"WARNING (RadiationModel::updateGeometry): No primitives found in context. Cannot update geometry." << std::endl;
1690 std::vector<uint> primitive_UUIDs_ordered;
1691 primitive_UUIDs_ordered.reserve(Nprimitives);
1693 std::unordered_set<uint> context_UUIDs_set(context_UUIDs.begin(), context_UUIDs.end());
1695 for (
uint objID: objID_all) {
1698 for (
uint p: primitive_UUIDs) {
1700 if (context->
doesPrimitiveExist(p) && context_UUIDs_set.find(p) != context_UUIDs_set.end()) {
1701 primitive_UUIDs_ordered.push_back(p);
1706 context_UUIDs = primitive_UUIDs_ordered;
1709 std::vector<std::vector<float>> m_global;
1712 std::vector<uint> ptype_global;
1715 std::vector<float> solid_fraction_global;
1718 std::vector<uint> patch_UUID;
1719 patch_UUID.reserve(Nprimitives);
1720 std::vector<uint> triangle_UUID;
1721 triangle_UUID.reserve(Nprimitives);
1722 std::vector<uint> disk_UUID;
1723 disk_UUID.reserve(Nprimitives);
1724 std::vector<uint> tile_UUID;
1725 tile_UUID.reserve(Nprimitives);
1726 std::vector<uint> voxel_UUID;
1729 std::vector<char> twosided_flag_global;
1730 twosided_flag_global.reserve(Nprimitives);
1733 std::vector<std::vector<optix::float3>> patch_vertices;
1734 patch_vertices.reserve(Nprimitives);
1735 std::vector<std::vector<optix::float3>> triangle_vertices;
1736 triangle_vertices.reserve(Nprimitives);
1737 std::vector<std::vector<optix::float3>> tile_vertices;
1738 tile_vertices.reserve(Nprimitives);
1739 std::vector<std::vector<optix::float3>> voxel_vertices;
1742 std::vector<optix::int2> object_subdivisions;
1743 object_subdivisions.reserve(Nprimitives);
1746 std::vector<uint> objectID;
1747 objectID.resize(Nprimitives);
1749 std::size_t patch_count = 0;
1750 std::size_t triangle_count = 0;
1751 std::size_t disk_count = 0;
1752 std::size_t tile_count = 0;
1753 std::size_t voxel_count = 0;
1755 solid_fraction_global.resize(Nprimitives);
1757 primitiveID.resize(0);
1758 primitiveID.reserve(Nprimitives);
1763 for (std::size_t u = 0; u < Nprimitives; u++) {
1765 uint p = context_UUIDs.at(u);
1773 primitiveID.push_back(u);
1782 objectID.at(u) = objID - 1;
1786 size_t Nobjects = primitiveID.size();
1788 m_global.resize(Nobjects);
1789 ptype_global.resize(Nobjects);
1790 twosided_flag_global.resize(Nobjects);
1791 for (
size_t i = 0; i < Nobjects; i++) {
1792 twosided_flag_global.at(i) = 1;
1796 for (std::size_t u = 0; u < Nobjects; u++) {
1798 uint p = context_UUIDs.at(primitiveID.at(u));
1805 ptype_global.at(u) = type;
1807 assert(ptype_global.at(u) >= 0 && ptype_global.at(u) <= 4);
1813 twosided_flag_global.at(u) = char(flag);
1820 ptype_global.at(u) = 3;
1824 m_global.at(u).resize(16);
1825 for (
uint i = 0; i < 16; i++) {
1826 m_global.at(u).at(i) = m[i];
1830 std::vector<optix::float3> v{optix::make_float3(vertices.at(0).x, vertices.at(0).y, vertices.at(0).z), optix::make_float3(vertices.at(1).x, vertices.at(1).y, vertices.at(1).z),
1831 optix::make_float3(vertices.at(2).x, vertices.at(2).y, vertices.at(2).z), optix::make_float3(vertices.at(3).x, vertices.at(3).y, vertices.at(3).z)};
1832 tile_vertices.push_back(v);
1836 object_subdivisions.push_back(optix::make_int2(subdiv.
x, subdiv.
y));
1838 tile_UUID.push_back(primitiveID.at(u));
1845 m_global.at(u).resize(16);
1846 for (
uint i = 0; i < 16; i++) {
1847 m_global.at(u).at(i) = m[i];
1851 std::vector<optix::float3> v{
1852 optix::make_float3(vertices.at(0).x, vertices.at(0).y, vertices.at(0).z),
1853 optix::make_float3(vertices.at(1).x, vertices.at(1).y, vertices.at(1).z),
1854 optix::make_float3(vertices.at(2).x, vertices.at(2).y, vertices.at(2).z),
1855 optix::make_float3(vertices.at(3).x, vertices.at(3).y, vertices.at(3).z),
1857 patch_vertices.push_back(v);
1858 object_subdivisions.push_back(optix::make_int2(1, 1));
1859 patch_UUID.push_back(primitiveID.at(u));
1865 m_global.at(u).resize(16);
1866 for (
uint i = 0; i < 16; i++) {
1867 m_global.at(u).at(i) = m[i];
1871 std::vector<optix::float3> v{optix::make_float3(vertices.at(0).x, vertices.at(0).y, vertices.at(0).z), optix::make_float3(vertices.at(1).x, vertices.at(1).y, vertices.at(1).z),
1872 optix::make_float3(vertices.at(2).x, vertices.at(2).y, vertices.at(2).z)};
1873 triangle_vertices.push_back(v);
1874 object_subdivisions.push_back(optix::make_int2(1, 1));
1875 triangle_UUID.push_back(primitiveID.at(u));
1881 m_global.at(u).resize(16);
1882 for (
uint i = 0; i < 16; i++) {
1883 m_global.at(u).at(i) = m[i];
1888 std::vector<optix::float3> v{optix::make_float3(center.
x - 0.5f * size.
x, center.
y - 0.5f * size.
y, center.
z - 0.5f * size.
z), optix::make_float3(center.
x + 0.5f * size.
x, center.
y + 0.5f * size.
y, center.
z + 0.5f * size.
z)};
1889 voxel_vertices.push_back(v);
1890 object_subdivisions.push_back(optix::make_int2(1, 1));
1891 voxel_UUID.push_back(primitiveID.at(u));
1897 std::vector<std::vector<std::vector<bool>>> maskdata;
1898 std::map<std::string, uint> maskname;
1899 std::vector<optix::int2> masksize;
1900 std::vector<int> maskID;
1901 std::vector<std::vector<optix::float2>> uvdata;
1902 std::vector<int> uvID;
1903 maskID.resize(Nobjects);
1904 uvID.resize(Nobjects);
1906 for (
size_t u = 0; u < Nobjects; u++) {
1908 uint p = context_UUIDs.at(primitiveID.at(u));
1924 if (maskname.find(maskfile) != maskname.end()) {
1925 uint ID = maskname.at(maskfile);
1929 uint ID = maskdata.size();
1931 maskname[maskfile] = maskdata.size();
1933 auto sy = maskdata.back().size();
1934 auto sx = maskdata.back().front().size();
1935 masksize.push_back(optix::make_int2(sx, sy));
1939 std::vector<vec2> uv;
1946 std::vector<optix::float2> uvf2;
1950 for (
int i = 0; i < uv.size(); i++) {
1951 uvf2.at(i) = optix::make_float2(uv.at(i).x, uv.at(i).y);
1953 if (uv.size() == 3) {
1954 uvf2.at(3) = optix::make_float2(0, 0);
1956 uvdata.push_back(uvf2);
1957 uvID.at(u) = uvdata.size() - 1;
1964 int2 size_max(0, 0);
1965 for (
int t = 0; t < maskdata.size(); t++) {
1966 int2 sz(maskdata.at(t).front().size(), maskdata.at(t).size());
1967 if (sz.
x > size_max.
x) {
1970 if (sz.
y > size_max.
y) {
1975 for (
int t = 0; t < maskdata.size(); t++) {
1976 maskdata.at(t).resize(size_max.
y);
1977 for (
int j = 0; j < size_max.
y; j++) {
1978 maskdata.at(t).at(j).resize(size_max.
x);
1982 initializeBuffer3D(maskdata_RTbuffer, maskdata);
1983 initializeBuffer1Dint2(masksize_RTbuffer, masksize);
1984 initializeBuffer1Di(maskID_RTbuffer, maskID);
1986 initializeBuffer2Dfloat2(uvdata_RTbuffer, uvdata);
1987 initializeBuffer1Di(uvID_RTbuffer, uvID);
1993 if (periodic_flag.
x == 1 || periodic_flag.
y == 1) {
1994 if (!cameras.empty()) {
1995 for (
auto &camera: cameras) {
1996 vec3 camerapos = camera.second.position;
1997 if (camerapos.
x < xbounds.
x || camerapos.
x > xbounds.
y || camerapos.
y < ybounds.
x || camerapos.
y > ybounds.
y) {
1998 std::cout <<
"WARNING (RadiationModel::updateGeometry): camera position is outside of the domain bounding box. Disabling periodic boundary conditions." << std::endl;
1999 periodic_flag.
x = 0;
2000 periodic_flag.
y = 0;
2003 if (camerapos.
z < zbounds.
x) {
2004 zbounds.
x = camerapos.
z;
2006 if (camerapos.
z > zbounds.
y) {
2007 zbounds.
y = camerapos.
z;
2020 std::vector<uint> bbox_UUID;
2021 int bbox_face_count = 0;
2023 std::vector<std::vector<optix::float3>> bbox_vertices;
2027 std::vector<optix::float3> v;
2030 if (periodic_flag.
x == 1) {
2033 v.at(0) = optix::make_float3(xbounds.
x, ybounds.
x, zbounds.
x);
2034 v.at(1) = optix::make_float3(xbounds.
x, ybounds.
y, zbounds.
x);
2035 v.at(2) = optix::make_float3(xbounds.
x, ybounds.
y, zbounds.
y);
2036 v.at(3) = optix::make_float3(xbounds.
x, ybounds.
x, zbounds.
y);
2037 bbox_vertices.push_back(v);
2038 bbox_UUID.push_back(Nprimitives + bbox_face_count);
2039 objectID.push_back(Nobjects + bbox_face_count);
2040 ptype_global.push_back(5);
2044 v.at(0) = optix::make_float3(xbounds.
y, ybounds.
x, zbounds.
x);
2045 v.at(1) = optix::make_float3(xbounds.
y, ybounds.
y, zbounds.
x);
2046 v.at(2) = optix::make_float3(xbounds.
y, ybounds.
y, zbounds.
y);
2047 v.at(3) = optix::make_float3(xbounds.
y, ybounds.
x, zbounds.
y);
2048 bbox_vertices.push_back(v);
2049 bbox_UUID.push_back(Nprimitives + bbox_face_count);
2050 objectID.push_back(Nobjects + bbox_face_count);
2051 ptype_global.push_back(5);
2054 if (periodic_flag.
y == 1) {
2057 v.at(0) = optix::make_float3(xbounds.
x, ybounds.
x, zbounds.
x);
2058 v.at(1) = optix::make_float3(xbounds.
y, ybounds.
x, zbounds.
x);
2059 v.at(2) = optix::make_float3(xbounds.
y, ybounds.
x, zbounds.
y);
2060 v.at(3) = optix::make_float3(xbounds.
x, ybounds.
x, zbounds.
y);
2061 bbox_vertices.push_back(v);
2062 bbox_UUID.push_back(Nprimitives + bbox_face_count);
2063 objectID.push_back(Nobjects + bbox_face_count);
2064 ptype_global.push_back(5);
2068 v.at(0) = optix::make_float3(xbounds.
x, ybounds.
y, zbounds.
x);
2069 v.at(1) = optix::make_float3(xbounds.
y, ybounds.
y, zbounds.
x);
2070 v.at(2) = optix::make_float3(xbounds.
y, ybounds.
y, zbounds.
y);
2071 v.at(3) = optix::make_float3(xbounds.
x, ybounds.
y, zbounds.
y);
2072 bbox_vertices.push_back(v);
2073 bbox_UUID.push_back(Nprimitives + bbox_face_count);
2074 objectID.push_back(Nobjects + bbox_face_count);
2075 ptype_global.push_back(5);
2079 initializeBuffer2Df(transform_matrix_RTbuffer, m_global);
2080 initializeBuffer1Dui(primitive_type_RTbuffer, ptype_global);
2081 initializeBuffer1Df(primitive_solid_fraction_RTbuffer, solid_fraction_global);
2082 initializeBuffer1Dchar(twosided_flag_RTbuffer, twosided_flag_global);
2083 initializeBuffer2Dfloat3(patch_vertices_RTbuffer, patch_vertices);
2084 initializeBuffer2Dfloat3(triangle_vertices_RTbuffer, triangle_vertices);
2085 initializeBuffer2Dfloat3(tile_vertices_RTbuffer, tile_vertices);
2086 initializeBuffer2Dfloat3(voxel_vertices_RTbuffer, voxel_vertices);
2087 initializeBuffer2Dfloat3(bbox_vertices_RTbuffer, bbox_vertices);
2089 initializeBuffer1Dint2(object_subdivisions_RTbuffer, object_subdivisions);
2091 initializeBuffer1Dui(patch_UUID_RTbuffer, patch_UUID);
2092 initializeBuffer1Dui(triangle_UUID_RTbuffer, triangle_UUID);
2093 initializeBuffer1Dui(disk_UUID_RTbuffer, disk_UUID);
2094 initializeBuffer1Dui(tile_UUID_RTbuffer, tile_UUID);
2095 initializeBuffer1Dui(voxel_UUID_RTbuffer, voxel_UUID);
2096 initializeBuffer1Dui(bbox_UUID_RTbuffer, bbox_UUID);
2098 initializeBuffer1Dui(objectID_RTbuffer, objectID);
2099 initializeBuffer1Dui(primitiveID_RTbuffer, primitiveID);
2101 RT_CHECK_ERROR(rtGeometrySetPrimitiveCount(patch, patch_count));
2102 RT_CHECK_ERROR(rtGeometrySetPrimitiveCount(triangle, triangle_count));
2103 RT_CHECK_ERROR(rtGeometrySetPrimitiveCount(disk, disk_count));
2104 RT_CHECK_ERROR(rtGeometrySetPrimitiveCount(tile, tile_count));
2105 RT_CHECK_ERROR(rtGeometrySetPrimitiveCount(voxel, voxel_count));
2106 RT_CHECK_ERROR(rtGeometrySetPrimitiveCount(bbox, bbox_face_count));
2108 RT_CHECK_ERROR(rtAccelerationMarkDirty(geometry_acceleration));
2112 RT_CHECK_ERROR(rtVariableSetObject(top_object, top_level_group));
2114 RTsize device_memory;
2115 RT_CHECK_ERROR(rtContextGetAttribute(OptiX_Context, RT_CONTEXT_ATTRIBUTE_AVAILABLE_DEVICE_MEMORY,
sizeof(RTsize), &device_memory));
2117 device_memory *= 1e-6;
2119 if (device_memory < 500) {
2120 std::cout <<
"WARNING (RadiationModel): device memory is very low (" << device_memory <<
" MB)" << std::endl;
2124 RT_CHECK_ERROR(rtContextValidate(OptiX_Context));
2125 RT_CHECK_ERROR(rtContextCompile(OptiX_Context));
2137 isgeometryinitialized =
true;
2149 optix::int3 launch_dim_dummy = optix::make_int3(1, 1, 1);
2150 RT_CHECK_ERROR(rtContextLaunch3D(OptiX_Context, RAYTYPE_DIRECT, launch_dim_dummy.x, launch_dim_dummy.y, launch_dim_dummy.z));
2152 RT_CHECK_ERROR(rtContextGetAttribute(OptiX_Context, RT_CONTEXT_ATTRIBUTE_AVAILABLE_DEVICE_MEMORY,
sizeof(RTsize), &device_memory));
2164 radiativepropertiesneedupdate =
true;
2167 std::cout <<
"done." << std::endl;
2171void RadiationModel::updateRadiativeProperties() {
2180 std::cout <<
"Updating radiative properties..." << std::flush;
2183 uint Nbands = radiation_bands.size();
2184 uint Nsources = radiation_sources.size();
2185 uint Ncameras = cameras.size();
2186 size_t Nobjects = primitiveID.size();
2187 size_t Nprimitives = context_UUIDs.size();
2189 scattering_iterations_needed.clear();
2190 for (
auto &band: radiation_bands) {
2191 scattering_iterations_needed[band.first] =
false;
2194 std::vector<std::vector<std::vector<float>>> rho, tau;
2195 std::vector<std::vector<std::vector<std::vector<float>>>> rho_cam, tau_cam;
2199 std::vector<std::string> band_labels;
2200 for (
auto &band: radiation_bands) {
2201 band_labels.push_back(band.first);
2204 rho.resize(Nsources);
2205 tau.resize(Nsources);
2206 for (
size_t s = 0; s < Nsources; s++) {
2207 rho.at(s).resize(Nprimitives);
2208 tau.at(s).resize(Nprimitives);
2209 for (
size_t p = 0; p < Nprimitives; p++) {
2210 rho.at(s).at(p).resize(Nbands);
2211 tau.at(s).at(p).resize(Nbands);
2215 rho_cam.resize(Nsources);
2216 tau_cam.resize(Nsources);
2217 for (
size_t s = 0; s < Nsources; s++) {
2218 rho_cam.at(s).resize(Nprimitives);
2219 tau_cam.at(s).resize(Nprimitives);
2220 for (
size_t p = 0; p < Nprimitives; p++) {
2221 rho_cam.at(s).at(p).resize(Nbands);
2222 tau_cam.at(s).at(p).resize(Nbands);
2223 for (
size_t b = 0; b < Nbands; b++) {
2224 rho_cam.at(s).at(p).at(b).resize(Ncameras);
2225 tau_cam.at(s).at(p).at(b).resize(Ncameras);
2232 std::vector<std::vector<std::vector<helios::vec2>>> camera_response_unique;
2233 camera_response_unique.resize(Ncameras);
2236 for (
const auto &camera: cameras) {
2238 camera_response_unique.at(cam).resize(Nbands);
2240 for (
uint b = 0; b < Nbands; b++) {
2242 if (camera.second.band_spectral_response.find(band_labels.at(b)) == camera.second.band_spectral_response.end()) {
2246 std::string camera_response = camera.second.band_spectral_response.at(band_labels.at(b));
2248 if (!camera_response.empty()) {
2251 if (camera_response !=
"uniform") {
2252 std::cerr <<
"WARNING (RadiationModel::updateRadiativeProperties): Camera spectral response \"" << camera_response <<
"\" does not exist. Assuming a uniform spectral response..." << std::endl;
2254 }
else if (context->
getGlobalDataType(camera_response.c_str()) == helios::HELIOS_TYPE_VEC2) {
2256 std::vector<helios::vec2> data = loadSpectralData(camera_response.c_str());
2258 camera_response_unique.at(cam).at(b) = data;
2260 }
else if (context->
getGlobalDataType(camera_response.c_str()) != helios::HELIOS_TYPE_VEC2 && context->
getGlobalDataType(camera_response.c_str()) != helios::HELIOS_TYPE_STRING) {
2261 camera_response.clear();
2262 std::cout <<
"WARNING (RadiationModel::runBand): Camera spectral response \"" << camera_response <<
"\" is not of type HELIOS_TYPE_VEC2 or HELIOS_TYPE_STRING. Assuming a uniform spectral response..." << std::endl;
2271 std::unordered_map<std::string, float> spectral_integration_cache;
2275 std::unordered_map<std::string, float> temp_spectral_cache;
2279 auto createCacheKey = [](
const std::string &spectrum_label,
uint source_id,
uint band_id,
uint camera_id,
const std::string &type) -> std::string {
2280 return spectrum_label +
"_" + std::to_string(source_id) +
"_" + std::to_string(band_id) +
"_" + std::to_string(camera_id) +
"_" + type;
2284 auto getCachedValue = [&](
const std::string &cache_key,
bool &found) ->
float {
2285 float result = 0.0f;
2293 auto cache_it = spectral_integration_cache.find(cache_key);
2294 if (cache_it != spectral_integration_cache.end()) {
2296 result = cache_it->second;
2305 auto setCachedValue = [&](
const std::string &cache_key,
float value) {
2310 spectral_integration_cache[cache_key] = value;
2317 auto cachedInterp1 = [&](
const std::vector<helios::vec2> &spectrum,
float wavelength,
const std::string &spectrum_id) ->
float {
2319 std::string cache_key =
"interp_" + spectrum_id +
"_" + std::to_string(wavelength);
2322 float cached_result = getCachedValue(cache_key, found);
2324 return cached_result;
2328 float result =
interp1(spectrum, wavelength);
2329 setCachedValue(cache_key, result);
2334 auto cachedIntegrateSpectrumWithSource = [&](
uint source_ID,
const std::vector<helios::vec2> &object_spectrum,
float wavelength1,
float wavelength2,
const std::string &object_spectrum_id) ->
float {
2335 if (source_ID >= radiation_sources.size() || object_spectrum.size() < 2 || wavelength1 >= wavelength2) {
2339 std::vector<helios::vec2> source_spectrum = radiation_sources.at(source_ID).source_spectrum;
2340 std::string source_id =
"source_" + std::to_string(source_ID);
2343 int iend = (int) object_spectrum.size() - 1;
2344 for (
auto i = 0; i < object_spectrum.size() - 1; i++) {
2345 if (object_spectrum.at(i).x <= wavelength1 && object_spectrum.at(i + 1).x > wavelength1) {
2348 if (object_spectrum.at(i).x <= wavelength2 && object_spectrum.at(i + 1).x > wavelength2) {
2356 for (
auto i = istart; i < iend; i++) {
2357 float x0 = object_spectrum.at(i).x;
2358 float Esource0 = cachedInterp1(source_spectrum, x0, source_id);
2359 float Eobject0 = object_spectrum.at(i).y;
2361 float x1 = object_spectrum.at(i + 1).x;
2362 float Eobject1 = object_spectrum.at(i + 1).y;
2363 float Esource1 = cachedInterp1(source_spectrum, x1, source_id);
2365 E += 0.5f * (Eobject0 * Esource0 + Eobject1 * Esource1) * (x1 - x0);
2366 Etot += 0.5f * (Esource1 + Esource0) * (x1 - x0);
2369 return (Etot != 0.0f) ? E / Etot : 0.0f;
2373 auto cachedIntegrateSpectrumWithSourceAndCamera = [&](
uint source_ID,
const std::vector<helios::vec2> &object_spectrum,
const std::vector<helios::vec2> &camera_spectrum,
uint camera_index,
uint band_index,
2374 const std::string &object_spectrum_id) ->
float {
2375 if (source_ID >= radiation_sources.size() || object_spectrum.size() < 2) {
2379 std::vector<helios::vec2> source_spectrum = radiation_sources.at(source_ID).source_spectrum;
2380 std::string source_id =
"source_" + std::to_string(source_ID);
2381 std::string camera_id =
"camera_" + std::to_string(camera_index) +
"_band_" + std::to_string(band_index);
2385 for (
auto i = 1; i < object_spectrum.size(); i++) {
2386 if (object_spectrum.at(i).x <= source_spectrum.front().x || object_spectrum.at(i).x <= camera_spectrum.front().x) {
2389 if (object_spectrum.at(i).x > source_spectrum.back().x || object_spectrum.at(i).x > camera_spectrum.back().x) {
2393 float x1 = object_spectrum.at(i).x;
2394 float Eobject1 = object_spectrum.at(i).y;
2395 float Esource1 = cachedInterp1(source_spectrum, x1, source_id);
2396 float Ecamera1 = cachedInterp1(camera_spectrum, x1, camera_id);
2398 float x0 = object_spectrum.at(i - 1).x;
2399 float Eobject0 = object_spectrum.at(i - 1).y;
2400 float Esource0 = cachedInterp1(source_spectrum, x0, source_id);
2401 float Ecamera0 = cachedInterp1(camera_spectrum, x0, camera_id);
2403 E += 0.5f * ((Eobject1 * Esource1 * Ecamera1) + (Eobject0 * Ecamera0 * Esource0)) * (x1 - x0);
2404 Etot += 0.5f * (Esource1 + Esource0) * (x1 - x0);
2407 return (Etot != 0.0f) ? E / Etot : 0.0f;
2413 std::map<std::string, std::vector<helios::vec2>> surface_spectra_rho;
2414 std::map<std::string, std::vector<helios::vec2>> surface_spectra_tau;
2415 for (
size_t u = 0; u < Nprimitives; u++) {
2417 uint UUID = context_UUIDs.at(u);
2421 std::string spectrum_label;
2425 if (surface_spectra_rho.find(spectrum_label) == surface_spectra_rho.end()) {
2427 if (message_flag && !spectrum_label.empty()) {
2428 std::cerr <<
"WARNING (RadiationModel::runBand): Primitive spectral reflectivity \"" << spectrum_label <<
"\" does not exist. Using default reflectivity of 0..." << std::flush;
2430 std::vector<helios::vec2> data;
2431 surface_spectra_rho.emplace(spectrum_label, data);
2432 }
else if (context->
getGlobalDataType(spectrum_label.c_str()) == HELIOS_TYPE_VEC2) {
2434 std::vector<helios::vec2> data = loadSpectralData(spectrum_label.c_str());
2435 surface_spectra_rho.emplace(spectrum_label, data);
2437 }
else if (context->
getGlobalDataType(spectrum_label.c_str()) != helios::HELIOS_TYPE_VEC2 && context->
getGlobalDataType(spectrum_label.c_str()) != helios::HELIOS_TYPE_STRING) {
2438 spectrum_label.clear();
2439 std::cout <<
"WARNING (RadiationModel::runBand): Object spectral reflectivity \"" << spectrum_label <<
"\" is not of type HELIOS_TYPE_VEC2 or HELIOS_TYPE_STRING. Assuming a uniform spectral distribution..." << std::flush;
2447 std::string spectrum_label;
2448 context->
getPrimitiveData(UUID,
"transmissivity_spectrum", spectrum_label);
2451 if (surface_spectra_tau.find(spectrum_label) == surface_spectra_tau.end()) {
2453 if (message_flag && !spectrum_label.empty()) {
2454 std::cerr <<
"WARNING (RadiationModel::runBand): Primitive spectral transmissivity \"" << spectrum_label <<
"\" does not exist. Using default transmissivity of 0..." << std::flush;
2456 std::vector<helios::vec2> data;
2457 surface_spectra_tau.emplace(spectrum_label, data);
2458 }
else if (context->
getGlobalDataType(spectrum_label.c_str()) == HELIOS_TYPE_VEC2) {
2460 std::vector<helios::vec2> data = loadSpectralData(spectrum_label.c_str());
2461 surface_spectra_tau.emplace(spectrum_label, data);
2463 }
else if (context->
getGlobalDataType(spectrum_label.c_str()) != helios::HELIOS_TYPE_VEC2 && context->
getGlobalDataType(spectrum_label.c_str()) != helios::HELIOS_TYPE_STRING) {
2464 spectrum_label.clear();
2465 std::cout <<
"WARNING (RadiationModel::runBand): Object spectral transmissivity \"" << spectrum_label <<
"\" is not of type HELIOS_TYPE_VEC2 or HELIOS_TYPE_STRING. Assuming a uniform spectral distribution..." << std::flush;
2475 std::map<std::string, std::vector<std::vector<float>>> rho_unique;
2476 std::map<std::string, std::vector<std::vector<float>>> tau_unique;
2478 std::map<std::string, std::vector<std::vector<std::vector<float>>>> rho_cam_unique;
2479 std::map<std::string, std::vector<std::vector<std::vector<float>>>> tau_cam_unique;
2481 std::vector<std::vector<float>> empty;
2482 empty.resize(Nbands);
2483 for (
uint b = 0; b < Nbands; b++) {
2484 empty.at(b).resize(Nsources, 0);
2486 std::vector<std::vector<std::vector<float>>> empty_cam;
2488 empty_cam.resize(Nbands);
2489 for (
uint b = 0; b < Nbands; b++) {
2490 empty_cam.at(b).resize(Nsources);
2491 for (
uint s = 0; s < Nsources; s++) {
2492 empty_cam.at(b).at(s).resize(Ncameras, 0);
2498 std::vector<std::pair<std::string, std::vector<helios::vec2>>> spectra_rho_vector(surface_spectra_rho.begin(), surface_spectra_rho.end());
2501 for (
const auto &spectrum: spectra_rho_vector) {
2502 rho_unique[spectrum.first] = empty;
2504 rho_cam_unique[spectrum.first] = empty_cam;
2510#pragma omp parallel for schedule(dynamic)
2512 for (
int spectrum_idx = 0; spectrum_idx < (int) spectra_rho_vector.size(); spectrum_idx++) {
2513 const auto &spectrum = spectra_rho_vector[spectrum_idx];
2515 for (
uint b = 0; b < Nbands; b++) {
2516 std::string band = band_labels.at(b);
2518 for (
uint s = 0; s < Nsources; s++) {
2521 auto band_it = radiation_bands.find(band);
2522 if (band_it != radiation_bands.end() && band_it->second.wavebandBounds.x != 0 && band_it->second.wavebandBounds.y != 0 && !spectrum.second.empty()) {
2523 if (!radiation_sources.at(s).source_spectrum.empty()) {
2524 std::string cache_key = createCacheKey(spectrum.first, s, b, 0,
"rho_source");
2526 float cached_result = getCachedValue(cache_key, found);
2528 rho_unique[spectrum.first][b][s] = cached_result;
2530 float result = cachedIntegrateSpectrumWithSource(s, spectrum.second, band_it->second.wavebandBounds.x, band_it->second.wavebandBounds.y, spectrum.first);
2531 setCachedValue(cache_key, result);
2532 rho_unique[spectrum.first][b][s] = result;
2536 std::string cache_key = createCacheKey(spectrum.first, s, b, 0,
"rho_no_source");
2538 float cached_result = getCachedValue(cache_key, found);
2540 rho_unique[spectrum.first][b][s] = cached_result;
2542 float result =
integrateSpectrum(spectrum.second, band_it->second.wavebandBounds.x, band_it->second.wavebandBounds.y) / (band_it->second.wavebandBounds.y - band_it->second.wavebandBounds.x);
2543 setCachedValue(cache_key, result);
2544 rho_unique[spectrum.first][b][s] = result;
2548 rho_unique[spectrum.first][b][s] = rho_default;
2554 for (
const auto &camera: cameras) {
2556 if (camera_response_unique.at(cam).at(b).empty()) {
2557 rho_cam_unique[spectrum.first][b][s][cam] = rho_unique[spectrum.first][b][s];
2561 if (!spectrum.second.empty()) {
2562 if (!radiation_sources.at(s).source_spectrum.empty()) {
2563 std::string cache_key = createCacheKey(spectrum.first, s, b, cam,
"rho_cam_source");
2565 float cached_result = getCachedValue(cache_key, found);
2567 rho_cam_unique.at(spectrum.first).at(b).at(s).at(cam) = cached_result;
2569 float result = cachedIntegrateSpectrumWithSourceAndCamera(s, spectrum.second, camera_response_unique.at(cam).at(b), cam, b, spectrum.first);
2570 setCachedValue(cache_key, result);
2571 rho_cam_unique.at(spectrum.first).at(b).at(s).at(cam) = result;
2574 std::string cache_key = createCacheKey(spectrum.first, s, b, cam,
"rho_cam_no_source");
2576 float cached_result = getCachedValue(cache_key, found);
2578 rho_cam_unique.at(spectrum.first).at(b).at(s).at(cam) = cached_result;
2580 float result =
integrateSpectrum(spectrum.second, camera_response_unique.at(cam).at(b));
2581 setCachedValue(cache_key, result);
2582 rho_cam_unique.at(spectrum.first).at(b).at(s).at(cam) = result;
2586 rho_cam_unique.at(spectrum.first).at(b).at(s).at(cam) = rho_default;
2598 std::vector<std::pair<std::string, std::vector<helios::vec2>>> spectra_tau_vector(surface_spectra_tau.begin(), surface_spectra_tau.end());
2601 for (
const auto &spectrum: spectra_tau_vector) {
2602 tau_unique[spectrum.first] = empty;
2604 tau_cam_unique[spectrum.first] = empty_cam;
2610#pragma omp parallel for schedule(dynamic)
2612 for (
int spectrum_idx = 0; spectrum_idx < (int) spectra_tau_vector.size(); spectrum_idx++) {
2613 const auto &spectrum = spectra_tau_vector[spectrum_idx];
2615 for (
uint b = 0; b < Nbands; b++) {
2616 std::string band = band_labels.at(b);
2618 for (
uint s = 0; s < Nsources; s++) {
2621 auto band_it = radiation_bands.find(band);
2622 if (band_it != radiation_bands.end() && band_it->second.wavebandBounds.x != 0 && band_it->second.wavebandBounds.y != 0 && !spectrum.second.empty()) {
2623 if (!radiation_sources.at(s).source_spectrum.empty()) {
2624 std::string cache_key = createCacheKey(spectrum.first, s, b, 0,
"tau_source");
2626 float cached_result = getCachedValue(cache_key, found);
2628 tau_unique[spectrum.first][b][s] = cached_result;
2630 float result = cachedIntegrateSpectrumWithSource(s, spectrum.second, band_it->second.wavebandBounds.x, band_it->second.wavebandBounds.y, spectrum.first);
2631 setCachedValue(cache_key, result);
2632 tau_unique[spectrum.first][b][s] = result;
2635 std::string cache_key = createCacheKey(spectrum.first, s, b, 0,
"tau_no_source");
2637 float cached_result = getCachedValue(cache_key, found);
2639 tau_unique[spectrum.first][b][s] = cached_result;
2641 float result =
integrateSpectrum(spectrum.second, band_it->second.wavebandBounds.x, band_it->second.wavebandBounds.y) / (band_it->second.wavebandBounds.y - band_it->second.wavebandBounds.x);
2642 setCachedValue(cache_key, result);
2643 tau_unique[spectrum.first][b][s] = result;
2647 tau_unique[spectrum.first][b][s] = tau_default;
2653 for (
const auto &camera: cameras) {
2655 if (camera_response_unique.at(cam).at(b).empty()) {
2657 tau_cam_unique[spectrum.first][b][s][cam] = tau_unique[spectrum.first][b][s];
2662 if (!spectrum.second.empty()) {
2663 if (!radiation_sources.at(s).source_spectrum.empty()) {
2664 std::string cache_key = createCacheKey(spectrum.first, s, b, cam,
"tau_cam_source");
2666 float cached_result = getCachedValue(cache_key, found);
2668 tau_cam_unique.at(spectrum.first).at(b).at(s).at(cam) = cached_result;
2670 float result = cachedIntegrateSpectrumWithSourceAndCamera(s, spectrum.second, camera_response_unique.at(cam).at(b), cam, b, spectrum.first);
2671 setCachedValue(cache_key, result);
2672 tau_cam_unique.at(spectrum.first).at(b).at(s).at(cam) = result;
2675 std::string cache_key = createCacheKey(spectrum.first, s, b, cam,
"tau_cam_no_source");
2677 float cached_result = getCachedValue(cache_key, found);
2679 tau_cam_unique.at(spectrum.first).at(b).at(s).at(cam) = cached_result;
2681 float result =
integrateSpectrum(spectrum.second, camera_response_unique.at(cam).at(b));
2682 setCachedValue(cache_key, result);
2683 tau_cam_unique.at(spectrum.first).at(b).at(s).at(cam) = result;
2687 tau_cam_unique.at(spectrum.first).at(b).at(s).at(cam) = tau_default;
2698 for (
size_t u = 0; u < Nprimitives; u++) {
2700 uint UUID = context_UUIDs.at(u);
2704 if (type == helios::PRIMITIVE_TYPE_VOXEL) {
2768 std::string spectrum_label;
2776 for (
const auto &band: band_labels) {
2779 prop =
"reflectivity_" + band;
2781 float rho_s = rho_default;
2786 for (
uint s = 0; s < Nsources; s++) {
2788 if (rho_s != rho_default || spectrum_label.empty() || !context->
doesGlobalDataExist(spectrum_label.c_str()) || rho_unique.find(spectrum_label) == rho_unique.end()) {
2790 rho.at(s).at(u).at(b) = rho_s;
2793 for (
uint cam = 0; cam < Ncameras; cam++) {
2794 rho_cam.at(s).at(u).at(b).at(cam) = rho_s;
2800 rho.at(s).at(u).at(b) = rho_unique.at(spectrum_label).at(b).at(s);
2803 for (
uint cam = 0; cam < Ncameras; cam++) {
2804 rho_cam.at(s).at(u).at(b).at(cam) = rho_cam_unique.at(spectrum_label).at(b).at(s).at(cam);
2809 if (rho.at(s).at(u).at(b) < 0) {
2810 rho.at(s).at(u).at(b) = 0.f;
2812 std::cout <<
"WARNING (RadiationModel): reflectivity cannot be less than 0. Clamping to 0 for band " << band <<
"." << std::flush;
2814 }
else if (rho.at(s).at(u).at(b) > 1.f) {
2815 rho.at(s).at(u).at(b) = 1.f;
2817 std::cout <<
"WARNING (RadiationModel): reflectivity cannot be greater than 1. Clamping to 1 for band " << band <<
"." << std::flush;
2820 if (rho.at(s).at(u).at(b) != 0) {
2821 scattering_iterations_needed.at(band) =
true;
2823 for (
auto &odata: output_prim_data) {
2824 if (odata ==
"reflectivity") {
2825 context->
setPrimitiveData(UUID, (
"reflectivity_" + std::to_string(s) +
"_" + band).c_str(), rho.at(s).at(u).at(b));
2835 spectrum_label.resize(0);
2838 context->
getPrimitiveData(UUID,
"transmissivity_spectrum", spectrum_label);
2843 for (
const auto &band: band_labels) {
2846 prop =
"transmissivity_" + band;
2848 float tau_s = tau_default;
2853 for (
uint s = 0; s < Nsources; s++) {
2855 if (tau_s != tau_default || spectrum_label.empty() || !context->
doesGlobalDataExist(spectrum_label.c_str()) || tau_unique.find(spectrum_label) == tau_unique.end()) {
2857 tau.at(s).at(u).at(b) = tau_s;
2860 for (
uint cam = 0; cam < Ncameras; cam++) {
2861 tau_cam.at(s).at(u).at(b).at(cam) = tau_s;
2866 tau.at(s).at(u).at(b) = tau_unique.at(spectrum_label).at(b).at(s);
2869 for (
uint cam = 0; cam < Ncameras; cam++) {
2870 tau_cam.at(s).at(u).at(b).at(cam) = tau_cam_unique.at(spectrum_label).at(b).at(s).at(cam);
2875 if (tau.at(s).at(u).at(b) < 0) {
2876 tau.at(s).at(u).at(b) = 0.f;
2878 std::cout <<
"WARNING (RadiationModel): transmissivity cannot be less than 0. Clamping to 0 for band " << band <<
"." << std::endl;
2880 }
else if (tau.at(s).at(u).at(b) > 1.f) {
2881 tau.at(s).at(u).at(b) = 1.f;
2883 std::cout <<
"WARNING (RadiationModel): transmissivity cannot be greater than 1. Clamping to 1 for band " << band <<
"." << std::endl;
2886 if (tau.at(s).at(u).at(b) != 0) {
2887 scattering_iterations_needed.at(band) =
true;
2889 for (
auto &odata: output_prim_data) {
2890 if (odata ==
"transmissivity") {
2891 context->
setPrimitiveData(UUID, (
"transmissivity_" + std::to_string(s) +
"_" + band).c_str(), tau.at(s).at(u).at(b));
2901 for (
const auto &band: band_labels) {
2903 prop =
"emissivity_" + band;
2914 std::cout <<
"WARNING (RadiationModel): emissivity cannot be less than 0. Clamping to 0 for band " << band <<
"." << std::endl;
2916 }
else if (eps > 1.f) {
2919 std::cout <<
"WARNING (RadiationModel): emissivity cannot be greater than 1. Clamping to 1 for band " << band <<
"." << std::endl;
2923 scattering_iterations_needed.at(band) =
true;
2928 for (
uint s = 0; s < Nsources; s++) {
2929 if (radiation_bands.at(band).emissionFlag) {
2930 if (eps != 1.f && rho.at(s).at(u).at(b) == 0 && tau.at(s).at(u).at(b) == 0) {
2931 rho.at(s).at(u).at(b) = 1.f - eps;
2932 }
else if (eps + tau.at(s).at(u).at(b) + rho.at(s).at(u).at(b) != 1.f && eps > 0.f) {
2933 helios_runtime_error(
"ERROR (RadiationModel): emissivity, transmissivity, and reflectivity must sum to 1 to ensure energy conservation. Band " + band +
", Primitive #" + std::to_string(UUID) +
": eps=" +
2934 std::to_string(eps) +
", tau=" + std::to_string(tau.at(s).at(u).at(b)) +
", rho=" + std::to_string(rho.at(s).at(u).at(b)) +
". It is also possible that you forgot to disable emission for this band.");
2935 }
else if (radiation_bands.at(band).scatteringDepth == 0 && eps != 1.f) {
2937 rho.at(s).at(u).at(b) = 0.f;
2938 tau.at(s).at(u).at(b) = 0.f;
2940 }
else if (tau.at(s).at(u).at(b) + rho.at(s).at(u).at(b) > 1.f) {
2941 helios_runtime_error(
"ERROR (RadiationModel): transmissivity and reflectivity cannot sum to greater than 1 ensure energy conservation. Band " + band +
", Primitive #" + std::to_string(UUID) +
": eps=" + std::to_string(eps) +
2942 ", tau=" + std::to_string(tau.at(s).at(u).at(b)) +
", rho=" + std::to_string(rho.at(s).at(u).at(b)) +
". It is also possible that you forgot to disable emission for this band.");
2950 initializeBuffer1Df(rho_RTbuffer,
flatten(rho));
2951 initializeBuffer1Df(tau_RTbuffer,
flatten(tau));
2953 initializeBuffer1Df(rho_cam_RTbuffer,
flatten(rho_cam));
2954 initializeBuffer1Df(tau_cam_RTbuffer,
flatten(tau_cam));
2957 std::vector<float> specular_exponent;
2958 specular_exponent.resize(Nprimitives, 0.f);
2959 std::vector<float> specular_scale;
2960 specular_scale.resize(Nprimitives, 0.f);
2961 bool specular_exponent_specified =
false;
2962 bool specular_scale_specified =
false;
2963 for (
size_t u = 0; u < Nprimitives; u++) {
2965 uint UUID = context_UUIDs.at(u);
2968 context->
getPrimitiveData(UUID,
"specular_exponent", specular_exponent.at(u));
2969 specular_exponent_specified =
true;
2971 specular_exponent.at(u) = -1.f;
2976 specular_scale_specified =
true;
2978 specular_scale.at(u) = 0.f;
2982 uint specular_enabled = 0;
2983 if (specular_exponent_specified) {
2984 initializeBuffer1Df(specular_exponent_RTbuffer, specular_exponent);
2985 if (specular_scale_specified) {
2986 initializeBuffer1Df(specular_scale_RTbuffer, specular_scale);
2987 specular_enabled = 2;
2989 specular_enabled = 1;
2992 RT_CHECK_ERROR(rtVariableSet1ui(specular_reflection_enabled_RTvariable, specular_enabled));
2994 radiativepropertiesneedupdate =
false;
2997 std::cout <<
"done\n";
3001std::vector<helios::vec2> RadiationModel::loadSpectralData(
const std::string &global_data_label)
const {
3003 std::vector<helios::vec2> spectrum;
3008 bool data_found =
false;
3009 for (
const auto &file: spectral_library_files) {
3011 context->
loadXML(file.c_str(),
true);
3018 helios_runtime_error(
"ERROR (RadiationModel::loadSpectralData): Global data for spectrum '" + global_data_label +
"' could not be found.");
3022 if (context->
getGlobalDataType(global_data_label.c_str()) != HELIOS_TYPE_VEC2) {
3023 helios_runtime_error(
"ERROR (RadiationModel::loadSpectralData): Global data for spectrum '" + global_data_label +
"' is not of type HELIOS_TYPE_VEC2.");
3026 context->
getGlobalData(global_data_label.c_str(), spectrum);
3029 if (spectrum.empty()) {
3030 helios_runtime_error(
"ERROR (RadiationModel::loadSpectralData): Global data for spectrum '" + global_data_label +
"' is empty.");
3032 for (
auto s = 0; s < spectrum.size(); s++) {
3034 if (s > 0 && spectrum.at(s).x <= spectrum.at(s - 1).x) {
3035 helios_runtime_error(
"ERROR (RadiationModel::loadSpectralData): Source spectral data validation failed. Wavelengths must increase monotonically.");
3038 if (spectrum.at(s).x < 0 || spectrum.at(s).x > 100000) {
3039 helios_runtime_error(
"ERROR (RadiationModel::loadSpectralData): Source spectral data validation failed. Wavelength value of " + std::to_string(spectrum.at(s).x) +
" appears to be erroneous.");
3042 if (spectrum.at(s).y < 0) {
3043 helios_runtime_error(
"ERROR (RadiationModel::loadSpectralData): Source spectral data validation failed. Flux value at wavelength of " + std::to_string(spectrum.at(s).x) +
" appears is negative.");
3051 std::vector<std::string> labels{label};
3061 std::vector<std::string> band_labels;
3062 for (
auto &band: radiation_bands) {
3063 if (std::find(label.begin(), label.end(), band.first) != label.end()) {
3064 band_labels.push_back(band.first);
3070 std::cerr <<
"WARNING (RadiationModel::runBand): No geometry was added to the context. There is nothing to simulate...exiting." << std::endl;
3075 if (!isgeometryinitialized) {
3080 for (
const std::string &band: band_labels) {
3082 helios_runtime_error(
"ERROR (RadiationModel::runBand): Cannot run band " + band +
" because it is not a valid band. Use addRadiationBand() function to add the band.");
3087 if (radiation_sources.empty()) {
3091 if (radiativepropertiesneedupdate) {
3092 updateRadiativeProperties();
3096 size_t Nbands_launch = band_labels.size();
3097 RT_CHECK_ERROR(rtVariableSet1ui(Nbands_launch_RTvariable, Nbands_launch));
3100 size_t Nbands_global = radiation_bands.size();
3101 RT_CHECK_ERROR(rtVariableSet1ui(Nbands_global_RTvariable, Nbands_global));
3104 std::vector<char> band_launch_flag(Nbands_global);
3106 for (
auto &band: radiation_bands) {
3107 if (std::find(band_labels.begin(), band_labels.end(), band.first) != band_labels.end()) {
3108 band_launch_flag.at(bb) = 1;
3112 initializeBuffer1Dchar(band_launch_flag_RTbuffer, band_launch_flag);
3115 size_t Nobjects = primitiveID.size();
3116 size_t Nprimitives = context_UUIDs.size();
3117 RT_CHECK_ERROR(rtVariableSet1ui(Nprimitives_RTvariable, Nprimitives));
3120 RT_CHECK_ERROR(rtVariableSet1ui(random_seed_RTvariable, std::chrono::system_clock::now().time_since_epoch().count()));
3123 uint Nsources = radiation_sources.size();
3124 RT_CHECK_ERROR(rtVariableSet1ui(Nsources_RTvariable, Nsources));
3127 RT_CHECK_ERROR(rtVariableSet2f(periodic_flag_RTvariable, periodic_flag.
x, periodic_flag.
y));
3130 uint Ncameras = cameras.size();
3131 RT_CHECK_ERROR(rtVariableSet1ui(Ncameras_RTvariable, Ncameras));
3134 std::vector<uint> scattering_depth(Nbands_launch);
3135 bool scatteringenabled =
false;
3136 for (
auto b = 0; b < Nbands_launch; b++) {
3137 scattering_depth.at(b) = radiation_bands.at(band_labels.at(b)).scatteringDepth;
3138 if (scattering_depth.at(b) > 0) {
3139 scatteringenabled =
true;
3142 initializeBuffer1Dui(max_scatters_RTbuffer, scattering_depth);
3145 for (
int b = 0; b < Nbands_launch; b++) {
3146 if (scattering_depth.at(b) == 0 && scattering_iterations_needed.at(band_labels.at(b))) {
3147 std::cout <<
"WARNING (RadiationModel::runBand): Surface radiative properties for band " << band_labels.at(b)
3148 <<
" are set to non-default values, but scattering iterations are disabled. Surface radiative properties will be ignored unless scattering depth is non-zero." << std::endl;
3153 std::vector<float> diffuse_flux(Nbands_launch);
3154 bool diffuseenabled =
false;
3155 for (
auto b = 0; b < Nbands_launch; b++) {
3157 if (diffuse_flux.at(b) > 0.f) {
3158 diffuseenabled =
true;
3161 initializeBuffer1Df(diffuse_flux_RTbuffer, diffuse_flux);
3164 std::vector<float> diffuse_extinction(Nbands_launch, 0);
3165 if (diffuseenabled) {
3166 for (
auto b = 0; b < Nbands_launch; b++) {
3167 diffuse_extinction.at(b) = radiation_bands.at(band_labels.at(b)).diffuseExtinction;
3170 initializeBuffer1Df(diffuse_extinction_RTbuffer, diffuse_extinction);
3173 std::vector<float> diffuse_dist_norm(Nbands_launch, 0);
3174 if (diffuseenabled) {
3175 for (
auto b = 0; b < Nbands_launch; b++) {
3176 diffuse_dist_norm.at(b) = radiation_bands.at(band_labels.at(b)).diffuseDistNorm;
3178 initializeBuffer1Df(diffuse_dist_norm_RTbuffer, diffuse_dist_norm);
3182 std::vector<optix::float3> diffuse_peak_dir(Nbands_launch);
3183 if (diffuseenabled) {
3184 for (
auto b = 0; b < Nbands_launch; b++) {
3185 helios::vec3 peak_dir = radiation_bands.at(band_labels.at(b)).diffusePeakDir;
3186 diffuse_peak_dir.at(b) = optix::make_float3(peak_dir.
x, peak_dir.
y, peak_dir.
z);
3188 initializeBuffer1Dfloat3(diffuse_peak_dir_RTbuffer, diffuse_peak_dir);
3192 bool emissionenabled =
false;
3193 for (
auto b = 0; b < Nbands_launch; b++) {
3194 if (radiation_bands.at(band_labels.at(b)).emissionFlag) {
3195 emissionenabled =
true;
3200 size_t directRayCount = 0;
3201 for (
const auto &band: label) {
3202 if (radiation_bands.at(band).directRayCount > directRayCount) {
3203 directRayCount = radiation_bands.at(band).directRayCount;
3208 size_t diffuseRayCount = 0;
3209 for (
const auto &band: label) {
3210 if (radiation_bands.at(band).diffuseRayCount > diffuseRayCount) {
3211 diffuseRayCount = radiation_bands.at(band).diffuseRayCount;
3216 size_t scatteringDepth = 0;
3217 for (
const auto &band: label) {
3218 if (radiation_bands.at(band).scatteringDepth > scatteringDepth) {
3219 scatteringDepth = radiation_bands.at(band).scatteringDepth;
3224 zeroBuffer1D(radiation_in_RTbuffer, Nbands_launch * Nprimitives);
3225 zeroBuffer1D(scatter_buff_top_RTbuffer, Nbands_launch * Nprimitives);
3226 zeroBuffer1D(scatter_buff_bottom_RTbuffer, Nbands_launch * Nprimitives);
3227 zeroBuffer1D(Rsky_RTbuffer, Nbands_launch * Nprimitives);
3230 zeroBuffer1D(scatter_buff_top_cam_RTbuffer, Nbands_launch * Nprimitives);
3231 zeroBuffer1D(scatter_buff_bottom_cam_RTbuffer, Nbands_launch * Nprimitives);
3234 std::vector<float> TBS_top, TBS_bottom;
3235 TBS_top.resize(Nbands_launch * Nprimitives, 0);
3236 TBS_bottom = TBS_top;
3238 std::map<std::string, std::vector<std::vector<float>>> radiation_in_camera;
3240 size_t maxRays = 1024 * 1024 * 1024;
3244 optix::int3 launch_dim_dir;
3246 bool rundirect =
false;
3247 for (
uint s = 0; s < Nsources; s++) {
3248 for (
uint b = 0; b < Nbands_launch; b++) {
3256 if (Nsources > 0 && rundirect) {
3260 std::vector<std::vector<float>> fluxes;
3261 fluxes.resize(Nsources);
3262 std::vector<optix::float3> positions(Nsources);
3263 std::vector<optix::float2> widths(Nsources);
3264 std::vector<optix::float3> rotations(Nsources);
3265 std::vector<uint> types(Nsources);
3268 for (
const auto &source: radiation_sources) {
3270 fluxes.at(s).resize(Nbands_launch);
3272 for (
auto b = 0; b < label.size(); b++) {
3284 initializeBuffer1Df(source_fluxes_RTbuffer,
flatten(fluxes));
3285 initializeBuffer1Dfloat3(source_positions_RTbuffer, positions);
3286 initializeBuffer1Dfloat2(source_widths_RTbuffer, widths);
3287 initializeBuffer1Dfloat3(source_rotations_RTbuffer, rotations);
3288 initializeBuffer1Dui(source_types_RTbuffer, types);
3293 size_t n = ceil(sqrt(
double(directRayCount)));
3295 size_t maxPrims = floor(
float(maxRays) /
float(n * n));
3297 int Nlaunches = ceil(n * n * Nobjects /
float(maxRays));
3299 size_t prims_per_launch = fmin(Nobjects, maxPrims);
3301 for (
uint launch = 0; launch < Nlaunches; launch++) {
3303 size_t prims_this_launch;
3304 if ((launch + 1) * prims_per_launch > Nobjects) {
3305 prims_this_launch = Nobjects - launch * prims_per_launch;
3307 prims_this_launch = prims_per_launch;
3310 RT_CHECK_ERROR(rtVariableSet1ui(launch_offset_RTvariable, launch * prims_per_launch));
3312 launch_dim_dir = optix::make_int3(round(n), round(n), prims_this_launch);
3315 std::cout <<
"Performing primary direct radiation ray trace for bands ";
3316 for (
const auto &band: label) {
3317 std::cout << band <<
", ";
3319 std::cout <<
" (batch " << launch + 1 <<
" of " << Nlaunches <<
")..." << std::flush;
3321 RT_CHECK_ERROR(rtContextLaunch3D(OptiX_Context, RAYTYPE_DIRECT, launch_dim_dir.x, launch_dim_dir.y, launch_dim_dir.z));
3324 std::cout <<
"\r \r" << std::flush;
3329 std::cout <<
"Performing primary direct radiation ray trace for bands ";
3330 for (
const auto &band: label) {
3331 std::cout << band <<
", ";
3333 std::cout <<
"...done." << std::endl;
3340 if (emissionenabled || diffuseenabled) {
3342 std::vector<float> flux_top, flux_bottom;
3343 flux_top.resize(Nbands_launch * Nprimitives, 0);
3344 flux_bottom = flux_top;
3347 if (scatteringenabled && rundirect) {
3348 flux_top = getOptiXbufferData(scatter_buff_top_RTbuffer);
3349 flux_bottom = getOptiXbufferData(scatter_buff_bottom_RTbuffer);
3350 zeroBuffer1D(scatter_buff_top_RTbuffer, Nbands_launch * Nprimitives);
3351 zeroBuffer1D(scatter_buff_bottom_RTbuffer, Nbands_launch * Nprimitives);
3355 if (emissionenabled) {
3357 float eps, temperature;
3360 float *scatter_buff_top_cam_data, *scatter_buff_bottom_cam_data;
3363 RT_CHECK_ERROR(rtBufferMap(scatter_buff_top_cam_RTbuffer, &ptr));
3364 scatter_buff_top_cam_data = (
float *) ptr;
3365 RT_CHECK_ERROR(rtBufferMap(scatter_buff_bottom_cam_RTbuffer, &ptr));
3366 scatter_buff_bottom_cam_data = (
float *) ptr;
3369 for (
auto b = 0; b < Nbands_launch; b++) {
3371 if (radiation_bands.at(band_labels.at(b)).emissionFlag) {
3372 std::string prop =
"emissivity_" + band_labels.at(b);
3373 for (
size_t u = 0; u < Nprimitives; u++) {
3374 size_t ind = u * Nbands_launch + b;
3375 uint p = context_UUIDs.at(u);
3381 if (scattering_depth.at(b) == 0 && eps != 1.f) {
3386 if (temperature < 0) {
3387 temperature = temperature_default;
3390 temperature = temperature_default;
3392 float out_top = sigma * eps * pow(temperature, 4);
3393 flux_top.at(ind) += out_top;
3395 scatter_buff_top_cam_data[ind] += out_top;
3398 flux_bottom.at(ind) += flux_top.at(ind);
3400 scatter_buff_bottom_cam_data[ind] += out_top;
3406 flux_bottom.at(ind) += flux_top.at(ind);
3408 scatter_buff_bottom_cam_data[ind] += out_top;
3416 RT_CHECK_ERROR(rtBufferUnmap(scatter_buff_top_cam_RTbuffer));
3417 RT_CHECK_ERROR(rtBufferUnmap(scatter_buff_bottom_cam_RTbuffer));
3421 initializeBuffer1Df(radiation_out_top_RTbuffer, flux_top);
3422 initializeBuffer1Df(radiation_out_bottom_RTbuffer, flux_bottom);
3425 size_t n = ceil(sqrt(
double(diffuseRayCount)));
3427 size_t maxPrims = floor(
float(maxRays) /
float(n * n));
3429 int Nlaunches = ceil(n * n * Nobjects /
float(maxRays));
3431 size_t prims_per_launch = fmin(Nobjects, maxPrims);
3433 for (
uint launch = 0; launch < Nlaunches; launch++) {
3435 size_t prims_this_launch;
3436 if ((launch + 1) * prims_per_launch > Nobjects) {
3437 prims_this_launch = Nobjects - launch * prims_per_launch;
3439 prims_this_launch = prims_per_launch;
3442 RT_CHECK_ERROR(rtVariableSet1ui(launch_offset_RTvariable, launch * prims_per_launch));
3444 optix::int3 launch_dim_diff = optix::make_int3(round(n), round(n), prims_this_launch);
3445 assert(launch_dim_diff.x > 0 && launch_dim_diff.y > 0);
3448 std::cout <<
"Performing primary diffuse radiation ray trace for bands ";
3449 for (
const auto &band: label) {
3450 std::cout << band <<
" ";
3452 std::cout <<
" (batch " << launch + 1 <<
" of " << Nlaunches <<
")..." << std::flush;
3456 RT_CHECK_ERROR(rtVariableSet1ui(launch_face_RTvariable, 1));
3457 RT_CHECK_ERROR(rtContextLaunch3D(OptiX_Context, RAYTYPE_DIFFUSE, launch_dim_diff.x, launch_dim_diff.y, launch_dim_diff.z));
3460 RT_CHECK_ERROR(rtVariableSet1ui(launch_face_RTvariable, 0));
3461 RT_CHECK_ERROR(rtContextLaunch3D(OptiX_Context, RAYTYPE_DIFFUSE, launch_dim_diff.x, launch_dim_diff.y, launch_dim_diff.z));
3464 std::cout <<
"\r \r" << std::flush;
3469 std::cout <<
"Performing primary diffuse radiation ray trace for bands ";
3470 for (
const auto &band: label) {
3471 std::cout << band <<
", ";
3473 std::cout <<
"...done." << std::endl;
3477 if (scatteringenabled && (emissionenabled || diffuseenabled || rundirect)) {
3479 for (
auto b = 0; b < Nbands_launch; b++) {
3480 diffuse_flux.at(b) = 0.f;
3482 initializeBuffer1Df(diffuse_flux_RTbuffer, diffuse_flux);
3484 size_t n = ceil(sqrt(
double(diffuseRayCount)));
3486 size_t maxPrims = floor(
float(maxRays) /
float(n * n));
3488 int Nlaunches = ceil(n * n * Nobjects /
float(maxRays));
3490 size_t prims_per_launch = fmin(Nobjects, maxPrims);
3493 for (s = 0; s < scatteringDepth; s++) {
3495 std::cout <<
"Performing scattering ray trace (iteration " << s + 1 <<
" of " << scatteringDepth <<
")..." << std::flush;
3499 for (
uint b_global = 0; b_global < Nbands_global; b_global++) {
3501 if (band_launch_flag.at(b_global) == 0) {
3506 uint depth = radiation_bands.at(band_labels.at(b)).scatteringDepth;
3507 if (s + 1 > depth) {
3509 std::cout <<
"Skipping band " << band_labels.at(b) <<
" for scattering launch " << s + 1 << std::flush;
3511 band_launch_flag.at(b_global) = 0;
3514 initializeBuffer1Dchar(band_launch_flag_RTbuffer, band_launch_flag);
3525 copyBuffer1D(scatter_buff_top_RTbuffer, radiation_out_top_RTbuffer);
3526 zeroBuffer1D(scatter_buff_top_RTbuffer, Nbands_launch * Nprimitives);
3527 copyBuffer1D(scatter_buff_bottom_RTbuffer, radiation_out_bottom_RTbuffer);
3528 zeroBuffer1D(scatter_buff_bottom_RTbuffer, Nbands_launch * Nprimitives);
3530 for (
uint launch = 0; launch < Nlaunches; launch++) {
3532 size_t prims_this_launch;
3533 if ((launch + 1) * prims_per_launch > Nobjects) {
3534 prims_this_launch = Nobjects - launch * prims_per_launch;
3536 prims_this_launch = prims_per_launch;
3538 optix::int3 launch_dim_diff = optix::make_int3(round(n), round(n), prims_this_launch);
3540 RT_CHECK_ERROR(rtVariableSet1ui(launch_offset_RTvariable, launch * prims_per_launch));
3543 RT_CHECK_ERROR(rtVariableSet1ui(launch_face_RTvariable, 1));
3544 RT_CHECK_ERROR(rtContextLaunch3D(OptiX_Context, RAYTYPE_DIFFUSE, launch_dim_diff.x, launch_dim_diff.y, launch_dim_diff.z));
3547 RT_CHECK_ERROR(rtVariableSet1ui(launch_face_RTvariable, 0));
3548 RT_CHECK_ERROR(rtContextLaunch3D(OptiX_Context, RAYTYPE_DIFFUSE, launch_dim_diff.x, launch_dim_diff.y, launch_dim_diff.z));
3551 std::cout <<
"\r \r" << std::flush;
3556 std::cout <<
"Performing scattering ray trace...done." << std::endl;
3563 if (scatteringenabled && (emissionenabled || diffuseenabled || rundirect)) {
3565 copyBuffer1D(scatter_buff_top_cam_RTbuffer, radiation_out_top_RTbuffer);
3566 copyBuffer1D(scatter_buff_bottom_cam_RTbuffer, radiation_out_bottom_RTbuffer);
3569 if (diffuseenabled) {
3570 for (
auto b = 0; b < Nbands_launch; b++) {
3573 initializeBuffer1Df(diffuse_flux_RTbuffer, diffuse_flux);
3577 size_t n = ceil(sqrt(
double(diffuseRayCount)));
3580 for (
auto &camera: cameras) {
3583 RT_CHECK_ERROR(rtVariableSet3f(camera_position_RTvariable, camera.second.position.
x, camera.second.position.
y, camera.second.position.
z));
3585 RT_CHECK_ERROR(rtVariableSet2f(camera_direction_RTvariable, dir.
zenith, dir.
azimuth));
3586 RT_CHECK_ERROR(rtVariableSet1f(camera_lens_diameter_RTvariable, camera.second.lens_diameter));
3587 RT_CHECK_ERROR(rtVariableSet1f(FOV_aspect_RTvariable, camera.second.FOV_aspect_ratio));
3588 RT_CHECK_ERROR(rtVariableSet1f(camera_focal_length_RTvariable, camera.second.focal_length));
3589 RT_CHECK_ERROR(rtVariableSet1f(camera_viewplane_length_RTvariable, 0.5f / tanf(0.5f * camera.second.HFOV_degrees *
M_PI / 180.f)));
3590 RT_CHECK_ERROR(rtVariableSet1ui(camera_ID_RTvariable, cam));
3592 zeroBuffer1D(radiation_in_camera_RTbuffer, camera.second.resolution.
x * camera.second.resolution.
y * Nbands_launch);
3594 optix::int3 launch_dim_camera = optix::make_int3(camera.second.antialiasing_samples, camera.second.resolution.
x, camera.second.resolution.
y);
3597 std::cout <<
"Performing scattering radiation camera ray trace for camera " << camera.second.label <<
"..." << std::flush;
3599 RT_CHECK_ERROR(rtContextLaunch3D(OptiX_Context, RAYTYPE_CAMERA, launch_dim_camera.x, launch_dim_camera.y, launch_dim_camera.z));
3601 std::cout <<
"done." << std::endl;
3604 std::vector<float> radiation_camera = getOptiXbufferData(radiation_in_camera_RTbuffer);
3606 std::string camera_label = camera.second.label;
3608 for (
auto b = 0; b < Nbands_launch; b++) {
3610 camera.second.pixel_data[band_labels.at(b)].resize(camera.second.resolution.
x * camera.second.resolution.
y);
3612 std::string data_label =
"camera_" + camera_label +
"_" + band_labels.at(b);
3614 for (
auto p = 0; p < camera.second.resolution.
x * camera.second.resolution.
y; p++) {
3615 camera.second.pixel_data.at(band_labels.at(b)).at(p) = radiation_camera.at(p * Nbands_launch + b);
3618 context->
setGlobalData(data_label.c_str(), camera.second.pixel_data.at(band_labels.at(b)));
3623 zeroBuffer1D(camera_pixel_label_RTbuffer, camera.second.resolution.
x * camera.second.resolution.
y);
3624 zeroBuffer1D(camera_pixel_depth_RTbuffer, camera.second.resolution.
x * camera.second.resolution.
y);
3627 std::cout <<
"Performing camera pixel labeling ray trace for camera " << camera.second.label <<
"..." << std::flush;
3629 RT_CHECK_ERROR(rtContextLaunch3D(OptiX_Context, RAYTYPE_PIXEL_LABEL, 1, launch_dim_camera.y, launch_dim_camera.z));
3631 std::cout <<
"done." << std::endl;
3634 camera.second.pixel_label_UUID = getOptiXbufferData_ui(camera_pixel_label_RTbuffer);
3635 camera.second.pixel_depth = getOptiXbufferData(camera_pixel_depth_RTbuffer);
3638 for (
uint ID = 0; ID < camera.second.pixel_label_UUID.size(); ID++) {
3639 if (camera.second.pixel_label_UUID.at(ID) > 0) {
3640 camera.second.pixel_label_UUID.at(ID) = context_UUIDs.at(camera.second.pixel_label_UUID.at(ID) - 1) + 1;
3644 std::string data_label =
"camera_" + camera_label +
"_pixel_UUID";
3646 context->
setGlobalData(data_label.c_str(), camera.second.pixel_label_UUID);
3648 data_label =
"camera_" + camera_label +
"_pixel_depth";
3650 context->
setGlobalData(data_label.c_str(), camera.second.pixel_depth);
3656 for (
auto &camera: cameras) {
3657 for (
auto b = 0; b < Nbands_launch; b++) {
3658 camera.second.pixel_data[band_labels.at(b)].resize(camera.second.resolution.
x * camera.second.resolution.
y);
3660 std::string data_label =
"camera_" + camera.second.label +
"_" + band_labels.at(b);
3662 for (
auto p = 0; p < camera.second.resolution.
x * camera.second.resolution.
y; p++) {
3663 camera.second.pixel_data.at(band_labels.at(b)).at(p) = 0.f;
3665 context->
setGlobalData(data_label.c_str(), camera.second.pixel_data.at(band_labels.at(b)));
3672 TBS_top = getOptiXbufferData(scatter_buff_top_RTbuffer);
3673 TBS_bottom = getOptiXbufferData(scatter_buff_bottom_RTbuffer);
3683 std::vector<float> radiation_flux_data;
3684 radiation_flux_data = getOptiXbufferData(radiation_in_RTbuffer);
3686 std::vector<uint> UUIDs_context_all = context->
getAllUUIDs();
3688 for (
auto b = 0; b < Nbands_launch; b++) {
3690 std::string prop =
"radiation_flux_" + band_labels.at(b);
3691 std::vector<float>
R(Nprimitives);
3692 for (
size_t u = 0; u < Nprimitives; u++) {
3693 size_t ind = u * Nbands_launch + b;
3694 R.at(u) = radiation_flux_data.at(ind) + TBS_top.at(ind) + TBS_bottom.at(ind);
3695 if (radiation_flux_data.at(ind) != radiation_flux_data.at(ind)) {
3696 std::cout <<
"NaN here " << ind << std::endl;
3701 if (UUIDs_context_all.size() != Nprimitives) {
3702 for (
uint UUID: UUIDs_context_all) {
3713 std::vector<float> Rsky_SW;
3714 Rsky_SW = getOptiXbufferData(Rsky_RTbuffer);
3716 for (
size_t i = 0; i < Rsky_SW.size(); i++) {
3717 Rsky += Rsky_SW.at(i);
3724 std::vector<float> total_flux;
3727 for (
const auto &band: radiation_bands) {
3729 std::string label = band.first;
3731 for (
size_t u = 0; u < context_UUIDs.size(); u++) {
3733 uint p = context_UUIDs.at(u);
3735 std::string str =
"radiation_flux_" + label;
3739 total_flux.at(u) +=
R;
3746std::vector<float> RadiationModel::getOptiXbufferData(RTbuffer buffer) {
3749 RT_CHECK_ERROR(rtBufferMap(buffer, &_data_));
3750 float *data_ptr = (
float *) _data_;
3753 RT_CHECK_ERROR(rtBufferGetSize1D(buffer, &size));
3755 std::vector<float> data_vec;
3756 data_vec.resize(size);
3757 for (
int i = 0; i < size; i++) {
3758 data_vec.at(i) = data_ptr[i];
3761 RT_CHECK_ERROR(rtBufferUnmap(buffer));
3766std::vector<double> RadiationModel::getOptiXbufferData_d(RTbuffer buffer) {
3769 RT_CHECK_ERROR(rtBufferMap(buffer, &_data_));
3770 double *data_ptr = (
double *) _data_;
3773 RT_CHECK_ERROR(rtBufferGetSize1D(buffer, &size));
3775 std::vector<double> data_vec;
3776 data_vec.resize(size);
3777 for (
int i = 0; i < size; i++) {
3778 data_vec.at(i) = data_ptr[i];
3781 RT_CHECK_ERROR(rtBufferUnmap(buffer));
3786std::vector<uint> RadiationModel::getOptiXbufferData_ui(RTbuffer buffer) {
3789 RT_CHECK_ERROR(rtBufferMap(buffer, &_data_));
3793 RT_CHECK_ERROR(rtBufferGetSize1D(buffer, &size));
3795 std::vector<uint> data_vec;
3796 data_vec.resize(size);
3797 for (
int i = 0; i < size; i++) {
3798 data_vec.at(i) = data_ptr[i];
3801 RT_CHECK_ERROR(rtBufferUnmap(buffer));
3806void RadiationModel::addBuffer(
const char *name, RTbuffer &buffer, RTvariable &variable, RTbuffertype type, RTformat format,
size_t dimension) {
3808 RT_CHECK_ERROR(rtBufferCreate(OptiX_Context, type, &buffer));
3809 RT_CHECK_ERROR(rtBufferSetFormat(buffer, format));
3810 RT_CHECK_ERROR(rtContextDeclareVariable(OptiX_Context, name, &variable));
3811 RT_CHECK_ERROR(rtVariableSetObject(variable, buffer));
3812 if (dimension == 1) {
3813 zeroBuffer1D(buffer, 1);
3814 }
else if (dimension == 2) {
3815 zeroBuffer2D(buffer, optix::make_int2(1, 1));
3817 helios_runtime_error(
"ERROR (RadiationModel::addBuffer): invalid buffer dimension of " + std::to_string(dimension) +
", must be 1 or 2.");
3821void RadiationModel::zeroBuffer1D(RTbuffer &buffer,
size_t bsize) {
3825 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
3827 if (format == RT_FORMAT_USER) {
3829 std::vector<double> array;
3830 array.resize(bsize);
3831 for (
int i = 0; i < bsize; i++) {
3835 initializeBuffer1Dd(buffer, array);
3837 }
else if (format == RT_FORMAT_FLOAT) {
3839 std::vector<float> array;
3840 array.resize(bsize);
3841 for (
int i = 0; i < bsize; i++) {
3845 initializeBuffer1Df(buffer, array);
3847 }
else if (format == RT_FORMAT_FLOAT2) {
3849 std::vector<optix::float2> array;
3850 array.resize(bsize);
3851 for (
int i = 0; i < bsize; i++) {
3852 array.at(i) = optix::make_float2(0, 0);
3855 initializeBuffer1Dfloat2(buffer, array);
3857 }
else if (format == RT_FORMAT_FLOAT3) {
3859 std::vector<optix::float3> array;
3860 array.resize(bsize);
3861 for (
int i = 0; i < bsize; i++) {
3862 array.at(i) = optix::make_float3(0, 0, 0);
3865 initializeBuffer1Dfloat3(buffer, array);
3867 }
else if (format == RT_FORMAT_INT) {
3869 std::vector<int> array;
3870 array.resize(bsize);
3871 for (
int i = 0; i < bsize; i++) {
3875 initializeBuffer1Di(buffer, array);
3877 }
else if (format == RT_FORMAT_INT2) {
3879 std::vector<optix::int2> array;
3880 array.resize(bsize);
3881 for (
int i = 0; i < bsize; i++) {
3882 array.at(i) = optix::make_int2(0, 0);
3885 initializeBuffer1Dint2(buffer, array);
3887 }
else if (format == RT_FORMAT_INT3) {
3889 std::vector<optix::int3> array;
3890 array.resize(bsize);
3891 for (
int i = 0; i < bsize; i++) {
3892 array.at(i) = optix::make_int3(0, 0, 0);
3895 initializeBuffer1Dint3(buffer, array);
3897 }
else if (format == RT_FORMAT_UNSIGNED_INT) {
3899 std::vector<uint> array;
3900 array.resize(bsize);
3901 for (
int i = 0; i < bsize; i++) {
3905 initializeBuffer1Dui(buffer, array);
3907 }
else if (format == RT_FORMAT_BYTE) {
3909 std::vector<char> array;
3910 array.resize(bsize);
3911 for (
int i = 0; i < bsize; i++) {
3915 initializeBuffer1Dchar(buffer, array);
3921void RadiationModel::copyBuffer1D(RTbuffer &buffer, RTbuffer &buffer_copy) {
3927 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
3931 rtBufferGetSize1D(buffer, &bsize);
3933 rtBufferSetSize1D(buffer_copy, bsize);
3935 if (format == RT_FORMAT_FLOAT) {
3938 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
3939 float *data = (
float *) ptr;
3942 RT_CHECK_ERROR(rtBufferMap(buffer_copy, &ptr_copy));
3943 float *data_copy = (
float *) ptr_copy;
3945 for (
size_t i = 0; i < bsize; i++) {
3946 data_copy[i] = data[i];
3949 }
else if (format == RT_FORMAT_FLOAT3) {
3952 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
3953 optix::float3 *data = (optix::float3 *) ptr;
3956 RT_CHECK_ERROR(rtBufferMap(buffer_copy, &ptr_copy));
3957 optix::float3 *data_copy = (optix::float3 *) ptr_copy;
3959 for (
size_t i = 0; i < bsize; i++) {
3960 data_copy[i] = data[i];
3964 RT_CHECK_ERROR(rtBufferUnmap(buffer));
3965 RT_CHECK_ERROR(rtBufferUnmap(buffer_copy));
3968void RadiationModel::initializeBuffer1Dd(RTbuffer &buffer,
const std::vector<double> &array) {
3970 size_t bsize = array.size();
3973 RT_CHECK_ERROR(rtBufferSetSize1D(buffer, bsize));
3977 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
3979 if (format != RT_FORMAT_USER) {
3980 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer1Dd): Buffer must have type double.");
3984 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
3986 double *data = (
double *) ptr;
3988 for (
size_t i = 0; i < bsize; i++) {
3992 RT_CHECK_ERROR(rtBufferUnmap(buffer));
3995void RadiationModel::initializeBuffer1Df(RTbuffer &buffer,
const std::vector<float> &array) {
3997 size_t bsize = array.size();
4000 RT_CHECK_ERROR(rtBufferSetSize1D(buffer, bsize));
4004 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4006 if (format != RT_FORMAT_FLOAT) {
4007 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer1Df): Buffer must have type float.");
4011 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4013 float *data = (
float *) ptr;
4015 for (
size_t i = 0; i < bsize; i++) {
4019 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4022void RadiationModel::initializeBuffer1Dfloat2(RTbuffer &buffer,
const std::vector<optix::float2> &array) {
4024 size_t bsize = array.size();
4027 RT_CHECK_ERROR(rtBufferSetSize1D(buffer, bsize));
4031 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4033 if (format != RT_FORMAT_FLOAT2) {
4034 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer1Dfloat2): Buffer must have type float2.");
4038 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4040 optix::float2 *data = (optix::float2 *) ptr;
4042 for (
size_t i = 0; i < bsize; i++) {
4043 data[i].x = array[i].x;
4044 data[i].y = array[i].y;
4047 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4050void RadiationModel::initializeBuffer1Dfloat3(RTbuffer &buffer,
const std::vector<optix::float3> &array) {
4052 size_t bsize = array.size();
4055 RT_CHECK_ERROR(rtBufferSetSize1D(buffer, bsize));
4059 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4061 if (format != RT_FORMAT_FLOAT3) {
4062 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer1Dfloat3): Buffer must have type float3.");
4066 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4068 optix::float3 *data = (optix::float3 *) ptr;
4070 for (
size_t i = 0; i < bsize; i++) {
4071 data[i].x = array[i].x;
4072 data[i].y = array[i].y;
4073 data[i].z = array[i].z;
4076 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4079void RadiationModel::initializeBuffer1Dfloat4(RTbuffer &buffer,
const std::vector<optix::float4> &array) {
4081 size_t bsize = array.size();
4084 RT_CHECK_ERROR(rtBufferSetSize1D(buffer, bsize));
4088 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4090 if (format != RT_FORMAT_FLOAT4) {
4091 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer1Dfloat4): Buffer must have type float4.");
4095 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4097 optix::float4 *data = (optix::float4 *) ptr;
4099 for (
size_t i = 0; i < bsize; i++) {
4100 data[i].x = array[i].x;
4101 data[i].y = array[i].y;
4102 data[i].z = array[i].z;
4103 data[i].w = array[i].w;
4106 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4109void RadiationModel::initializeBuffer1Di(RTbuffer &buffer,
const std::vector<int> &array) {
4111 size_t bsize = array.size();
4114 RT_CHECK_ERROR(rtBufferSetSize1D(buffer, bsize));
4118 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4120 if (format != RT_FORMAT_INT) {
4121 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer1Di): Buffer must have type int.");
4125 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4127 int *data = (
int *) ptr;
4129 for (
size_t i = 0; i < bsize; i++) {
4133 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4136void RadiationModel::initializeBuffer1Dui(RTbuffer &buffer,
const std::vector<uint> &array) {
4138 size_t bsize = array.size();
4141 RT_CHECK_ERROR(rtBufferSetSize1D(buffer, bsize));
4145 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4147 if (format != RT_FORMAT_UNSIGNED_INT) {
4148 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer1Dui): Buffer must have type unsigned int.");
4152 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4156 for (
size_t i = 0; i < bsize; i++) {
4160 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4163void RadiationModel::initializeBuffer1Dint2(RTbuffer &buffer,
const std::vector<optix::int2> &array) {
4165 size_t bsize = array.size();
4168 RT_CHECK_ERROR(rtBufferSetSize1D(buffer, bsize));
4172 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4174 if (format != RT_FORMAT_INT2) {
4175 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer1Dint2): Buffer must have type int2.");
4179 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4181 optix::int2 *data = (optix::int2 *) ptr;
4183 for (
size_t i = 0; i < bsize; i++) {
4187 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4190void RadiationModel::initializeBuffer1Dint3(RTbuffer &buffer,
const std::vector<optix::int3> &array) {
4192 size_t bsize = array.size();
4195 RT_CHECK_ERROR(rtBufferSetSize1D(buffer, bsize));
4199 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4201 if (format != RT_FORMAT_INT3) {
4202 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer1Dint3): Buffer must have type int3.");
4206 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4208 optix::int3 *data = (optix::int3 *) ptr;
4210 for (
size_t i = 0; i < bsize; i++) {
4214 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4217void RadiationModel::initializeBuffer1Dchar(RTbuffer &buffer,
const std::vector<char> &array) {
4219 size_t bsize = array.size();
4222 RT_CHECK_ERROR(rtBufferSetSize1D(buffer, bsize));
4226 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4228 if (format != RT_FORMAT_BYTE) {
4229 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer1Dchar): Buffer must have type char.");
4233 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4235 char *data = (
char *) ptr;
4237 for (
size_t i = 0; i < bsize; i++) {
4241 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4244void RadiationModel::zeroBuffer2D(RTbuffer &buffer, optix::int2 bsize) {
4247 RT_CHECK_ERROR(rtBufferSetSize2D(buffer, bsize.x, bsize.y));
4251 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4253 if (format == RT_FORMAT_USER) {
4254 std::vector<std::vector<double>> array;
4255 array.resize(bsize.y);
4256 for (
int j = 0; j < bsize.y; j++) {
4257 array.at(j).resize(bsize.x);
4258 for (
int i = 0; i < bsize.x; i++) {
4259 array.at(j).at(i) = 0.f;
4262 initializeBuffer2Dd(buffer, array);
4263 }
else if (format == RT_FORMAT_FLOAT) {
4264 std::vector<std::vector<float>> array;
4265 array.resize(bsize.y);
4266 for (
int j = 0; j < bsize.y; j++) {
4267 array.at(j).resize(bsize.x);
4268 for (
int i = 0; i < bsize.x; i++) {
4269 array.at(j).at(i) = 0.f;
4272 initializeBuffer2Df(buffer, array);
4273 }
else if (format == RT_FORMAT_FLOAT2) {
4274 std::vector<std::vector<optix::float2>> array;
4275 array.resize(bsize.y);
4276 for (
int j = 0; j < bsize.y; j++) {
4277 array.at(j).resize(bsize.x);
4278 for (
int i = 0; i < bsize.x; i++) {
4279 array.at(j).at(i).x = 0.f;
4280 array.at(j).at(i).y = 0.f;
4283 initializeBuffer2Dfloat2(buffer, array);
4284 }
else if (format == RT_FORMAT_FLOAT3) {
4285 std::vector<std::vector<optix::float3>> array;
4286 array.resize(bsize.y);
4287 for (
int j = 0; j < bsize.y; j++) {
4288 array.at(j).resize(bsize.x);
4289 for (
int i = 0; i < bsize.x; i++) {
4290 array.at(j).at(i).x = 0.f;
4291 array.at(j).at(i).y = 0.f;
4292 array.at(j).at(i).z = 0.f;
4295 initializeBuffer2Dfloat3(buffer, array);
4296 }
else if (format == RT_FORMAT_FLOAT4) {
4297 std::vector<std::vector<optix::float4>> array;
4298 array.resize(bsize.y);
4299 for (
int j = 0; j < bsize.y; j++) {
4300 array.at(j).resize(bsize.x);
4301 for (
int i = 0; i < bsize.x; i++) {
4302 array.at(j).at(i).x = 0.f;
4303 array.at(j).at(i).y = 0.f;
4304 array.at(j).at(i).z = 0.f;
4305 array.at(j).at(i).w = 0.f;
4308 initializeBuffer2Dfloat4(buffer, array);
4309 }
else if (format == RT_FORMAT_INT) {
4310 std::vector<std::vector<int>> array;
4311 array.resize(bsize.y);
4312 for (
int j = 0; j < bsize.y; j++) {
4313 array.at(j).resize(bsize.x);
4314 for (
int i = 0; i < bsize.x; i++) {
4315 array.at(j).at(i) = 0;
4318 initializeBuffer2Di(buffer, array);
4319 }
else if (format == RT_FORMAT_UNSIGNED_INT) {
4320 std::vector<std::vector<uint>> array;
4321 array.resize(bsize.y);
4322 for (
int j = 0; j < bsize.y; j++) {
4323 array.at(j).resize(bsize.x);
4324 for (
int i = 0; i < bsize.x; i++) {
4325 array.at(j).at(i) = 0;
4328 initializeBuffer2Dui(buffer, array);
4329 }
else if (format == RT_FORMAT_INT2) {
4330 std::vector<std::vector<optix::int2>> array;
4331 array.resize(bsize.y);
4332 for (
int j = 0; j < bsize.y; j++) {
4333 array.at(j).resize(bsize.x);
4334 for (
int i = 0; i < bsize.x; i++) {
4335 array.at(j).at(i).x = 0;
4336 array.at(j).at(i).y = 0;
4339 initializeBuffer2Dint2(buffer, array);
4340 }
else if (format == RT_FORMAT_INT3) {
4341 std::vector<std::vector<optix::int3>> array;
4342 array.resize(bsize.y);
4343 for (
int j = 0; j < bsize.y; j++) {
4344 array.at(j).resize(bsize.x);
4345 for (
int i = 0; i < bsize.x; i++) {
4346 array.at(j).at(i).x = 0;
4347 array.at(j).at(i).y = 0;
4348 array.at(j).at(i).z = 0;
4351 initializeBuffer2Dint3(buffer, array);
4352 }
else if (format == RT_FORMAT_BYTE) {
4353 std::vector<std::vector<bool>> array;
4354 array.resize(bsize.y);
4355 for (
int j = 0; j < bsize.y; j++) {
4356 array.at(j).resize(bsize.x);
4357 for (
int i = 0; i < bsize.x; i++) {
4358 array.at(j).at(i) =
false;
4361 initializeBuffer2Dbool(buffer, array);
4367void RadiationModel::initializeBuffer2Dd(RTbuffer &buffer,
const std::vector<std::vector<double>> &array) {
4370 bsize.y = array.size();
4374 bsize.x = array.front().size();
4378 RT_CHECK_ERROR(rtBufferSetSize2D(buffer, bsize.x, bsize.y));
4382 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4385 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4387 if (format == RT_FORMAT_USER) {
4388 double *data = (
double *) ptr;
4389 for (
size_t j = 0; j < bsize.y; j++) {
4390 for (
size_t i = 0; i < bsize.x; i++) {
4391 data[i + j * bsize.x] = array[j][i];
4395 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer2Dd): Buffer does not have format 'RT_FORMAT_USER'.");
4398 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4401void RadiationModel::initializeBuffer2Df(RTbuffer &buffer,
const std::vector<std::vector<float>> &array) {
4404 bsize.y = array.size();
4408 bsize.x = array.front().size();
4412 RT_CHECK_ERROR(rtBufferSetSize2D(buffer, bsize.x, bsize.y));
4416 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4419 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4421 if (format == RT_FORMAT_FLOAT) {
4422 float *data = (
float *) ptr;
4423 for (
size_t j = 0; j < bsize.y; j++) {
4424 for (
size_t i = 0; i < bsize.x; i++) {
4425 data[i + j * bsize.x] = array[j][i];
4429 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer2Df): Buffer does not have format 'RT_FORMAT_FLOAT'.");
4432 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4435void RadiationModel::initializeBuffer2Dfloat2(RTbuffer &buffer,
const std::vector<std::vector<optix::float2>> &array) {
4438 bsize.y = array.size();
4442 bsize.x = array.front().size();
4446 RT_CHECK_ERROR(rtBufferSetSize2D(buffer, bsize.x, bsize.y));
4450 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4453 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4455 if (format == RT_FORMAT_FLOAT2) {
4456 optix::float2 *data = (optix::float2 *) ptr;
4457 for (
size_t j = 0; j < bsize.y; j++) {
4458 for (
size_t i = 0; i < bsize.x; i++) {
4459 data[i + j * bsize.x].x = array[j][i].x;
4460 data[i + j * bsize.x].y = array[j][i].y;
4464 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer2Dfloat2): Buffer does not have format 'RT_FORMAT_FLOAT2'.");
4467 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4470void RadiationModel::initializeBuffer2Dfloat3(RTbuffer &buffer,
const std::vector<std::vector<optix::float3>> &array) {
4473 bsize.y = array.size();
4477 bsize.x = array.front().size();
4481 RT_CHECK_ERROR(rtBufferSetSize2D(buffer, bsize.x, bsize.y));
4485 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4488 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4490 if (format == RT_FORMAT_FLOAT3) {
4491 optix::float3 *data = (optix::float3 *) ptr;
4492 for (
size_t j = 0; j < bsize.y; j++) {
4493 for (
size_t i = 0; i < bsize.x; i++) {
4494 data[i + j * bsize.x].x = array.at(j).at(i).x;
4495 data[i + j * bsize.x].y = array.at(j).at(i).y;
4496 data[i + j * bsize.x].z = array.at(j).at(i).z;
4500 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer2Dfloat3): Buffer does not have format 'RT_FORMAT_FLOAT3'.");
4503 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4506void RadiationModel::initializeBuffer2Dfloat4(RTbuffer &buffer,
const std::vector<std::vector<optix::float4>> &array) {
4509 bsize.y = array.size();
4513 bsize.x = array.front().size();
4517 RT_CHECK_ERROR(rtBufferSetSize2D(buffer, bsize.x, bsize.y));
4521 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4524 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4526 if (format == RT_FORMAT_FLOAT4) {
4527 optix::float4 *data = (optix::float4 *) ptr;
4528 for (
size_t j = 0; j < bsize.y; j++) {
4529 for (
size_t i = 0; i < bsize.x; i++) {
4530 data[i + j * bsize.x].x = array[j][i].x;
4531 data[i + j * bsize.x].y = array[j][i].y;
4532 data[i + j * bsize.x].z = array[j][i].z;
4533 data[i + j * bsize.x].w = array[j][i].w;
4537 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer2Dfloat4): Buffer does not have format 'RT_FORMAT_FLOAT4'.");
4540 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4543void RadiationModel::initializeBuffer2Di(RTbuffer &buffer,
const std::vector<std::vector<int>> &array) {
4546 bsize.y = array.size();
4550 bsize.x = array.front().size();
4554 RT_CHECK_ERROR(rtBufferSetSize2D(buffer, bsize.x, bsize.y));
4558 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4561 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4563 if (format == RT_FORMAT_INT) {
4564 int *data = (
int *) ptr;
4565 for (
size_t j = 0; j < bsize.y; j++) {
4566 for (
size_t i = 0; i < bsize.x; i++) {
4567 data[i + j * bsize.x] = array[j][i];
4571 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer2Di): Buffer does not have format 'RT_FORMAT_INT'.");
4574 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4577void RadiationModel::initializeBuffer2Dui(RTbuffer &buffer,
const std::vector<std::vector<uint>> &array) {
4580 bsize.y = array.size();
4584 bsize.x = array.front().size();
4588 RT_CHECK_ERROR(rtBufferSetSize2D(buffer, bsize.x, bsize.y));
4592 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4595 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4597 if (format == RT_FORMAT_UNSIGNED_INT) {
4599 for (
size_t j = 0; j < bsize.y; j++) {
4600 for (
size_t i = 0; i < bsize.x; i++) {
4601 data[i + j * bsize.x] = array[j][i];
4605 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer2Dui): Buffer does not have format 'RT_FORMAT_UNSIGNED_INT'.");
4608 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4611void RadiationModel::initializeBuffer2Dint2(RTbuffer &buffer,
const std::vector<std::vector<optix::int2>> &array) {
4614 bsize.y = array.size();
4618 bsize.x = array.front().size();
4622 RT_CHECK_ERROR(rtBufferSetSize2D(buffer, bsize.x, bsize.y));
4626 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4629 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4631 if (format == RT_FORMAT_INT2) {
4632 optix::int2 *data = (optix::int2 *) ptr;
4633 for (
size_t j = 0; j < bsize.y; j++) {
4634 for (
size_t i = 0; i < bsize.x; i++) {
4635 data[i + j * bsize.x].x = array[j][i].x;
4636 data[i + j * bsize.x].y = array[j][i].y;
4640 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer2Dint2): Buffer does not have format 'RT_FORMAT_INT2'.");
4643 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4646void RadiationModel::initializeBuffer2Dint3(RTbuffer &buffer,
const std::vector<std::vector<optix::int3>> &array) {
4649 bsize.y = array.size();
4653 bsize.x = array.front().size();
4657 RT_CHECK_ERROR(rtBufferSetSize2D(buffer, bsize.x, bsize.y));
4661 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4664 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4666 if (format == RT_FORMAT_INT3) {
4667 optix::int3 *data = (optix::int3 *) ptr;
4668 for (
size_t j = 0; j < bsize.y; j++) {
4669 for (
size_t i = 0; i < bsize.x; i++) {
4670 data[i + j * bsize.x].x = array[j][i].x;
4671 data[i + j * bsize.x].y = array[j][i].y;
4672 data[i + j * bsize.x].z = array[j][i].z;
4676 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer2Dint3): Buffer does not have format 'RT_FORMAT_INT3'.");
4679 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4682void RadiationModel::initializeBuffer2Dbool(RTbuffer &buffer,
const std::vector<std::vector<bool>> &array) {
4685 bsize.y = array.size();
4689 bsize.x = array.front().size();
4693 RT_CHECK_ERROR(rtBufferSetSize2D(buffer, bsize.x, bsize.y));
4697 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4700 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4702 if (format == RT_FORMAT_BYTE) {
4703 bool *data = (
bool *) ptr;
4704 for (
size_t j = 0; j < bsize.y; j++) {
4705 for (
size_t i = 0; i < bsize.x; i++) {
4706 data[i + j * bsize.x] = array[j][i];
4710 helios_runtime_error(
"ERROR (RadiationModel::initializeBuffer2Dbool): Buffer does not have format 'RT_FORMAT_BYTE'.");
4713 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4716template<
typename anytype>
4717void RadiationModel::initializeBuffer3D(RTbuffer &buffer,
const std::vector<std::vector<std::vector<anytype>>> &array) {
4720 bsize.z = array.size();
4725 bsize.y = array.front().size();
4729 bsize.x = array.front().front().size();
4734 RT_CHECK_ERROR(rtBufferSetSize3D(buffer, bsize.x, bsize.y, bsize.z));
4738 RT_CHECK_ERROR(rtBufferGetFormat(buffer, &format));
4742 RT_CHECK_ERROR(rtBufferMap(buffer, &ptr));
4744 if (format == RT_FORMAT_FLOAT) {
4745 float *data = (
float *) ptr;
4746 for (
size_t k = 0; k < bsize.z; k++) {
4747 for (
size_t j = 0; j < bsize.y; j++) {
4748 for (
size_t i = 0; i < bsize.x; i++) {
4749 data[i + j * bsize.x + k * bsize.y * bsize.x] = array[k][j][i];
4753 }
else if (format == RT_FORMAT_INT) {
4754 int *data = (
int *) ptr;
4755 for (
size_t k = 0; k < bsize.z; k++) {
4756 for (
size_t j = 0; j < bsize.y; j++) {
4757 for (
size_t i = 0; i < bsize.x; i++) {
4758 data[i + j * bsize.x + k * bsize.y * bsize.x] = array[k][j][i];
4762 }
else if (format == RT_FORMAT_UNSIGNED_INT) {
4764 for (
size_t k = 0; k < bsize.z; k++) {
4765 for (
size_t j = 0; j < bsize.y; j++) {
4766 for (
size_t i = 0; i < bsize.x; i++) {
4767 data[i + j * bsize.x + k * bsize.y * bsize.x] = array[k][j][i];
4771 }
else if (format == RT_FORMAT_BYTE) {
4772 bool *data = (
bool *) ptr;
4773 for (
size_t k = 0; k < bsize.z; k++) {
4774 for (
size_t j = 0; j < bsize.y; j++) {
4775 for (
size_t i = 0; i < bsize.x; i++) {
4776 data[i + j * bsize.x + k * bsize.y * bsize.x] = array[k][j][i];
4781 std::cerr <<
"ERROR (RadiationModel::initializeBuffer3D): unsupported buffer format." << std::endl;
4784 RT_CHECK_ERROR(rtBufferUnmap(buffer));
4789 vec3 dir = view_direction;
4793 float total_area = 0;
4794 for (std::size_t u = 0; u < primitiveID.size(); u++) {
4796 uint UUID = context_UUIDs.at(primitiveID.at(u));
4801 Gtheta += fabsf(normal * dir) * area;
4806 return Gtheta / total_area;
4810 float average_delta_e) {
4812 std::ofstream file(file_path);
4813 if (!file.is_open()) {
4814 helios_runtime_error(
"ERROR (RadiationModel::exportColorCorrectionMatrixXML): Failed to open file for writing: " + file_path);
4818 std::string matrix_type =
"3x3";
4819 if (matrix.size() == 4 || (matrix.size() >= 3 && matrix[0].size() == 4)) {
4820 matrix_type =
"4x3";
4824 file <<
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
4825 file <<
"<!-- Camera Color Correction Matrix -->" << std::endl;
4826 file <<
"<!-- Source Image: " << source_image_path <<
" -->" << std::endl;
4827 file <<
"<!-- Camera Label: " << camera_label <<
" -->" << std::endl;
4828 file <<
"<!-- Colorboard Type: " << colorboard_type <<
" -->" << std::endl;
4829 if (average_delta_e >= 0.0f) {
4830 file <<
"<!-- Average Delta E: " << std::fixed << std::setprecision(2) << average_delta_e <<
" -->" << std::endl;
4832 file <<
"<!-- Matrix Type: " << matrix_type <<
" -->" << std::endl;
4833 file <<
"<!-- Generated: " << getCurrentDateTime() <<
" -->" << std::endl;
4836 file <<
"<helios>" << std::endl;
4837 file <<
" <ColorCorrectionMatrix camera_label=\"" << camera_label <<
"\" matrix_type=\"" << matrix_type <<
"\">" << std::endl;
4839 for (
size_t i = 0; i < matrix.size(); i++) {
4841 for (
size_t j = 0; j < matrix[i].size(); j++) {
4842 file << std::fixed << std::setprecision(6) << matrix[i][j];
4843 if (j < matrix[i].size() - 1) {
4847 file <<
"</row>" << std::endl;
4850 file <<
" </ColorCorrectionMatrix>" << std::endl;
4851 file <<
"</helios>" << std::endl;
4856std::string RadiationModel::getCurrentDateTime() {
4857 auto now = std::time(
nullptr);
4858 auto tm = *std::localtime(&now);
4859 std::stringstream ss;
4860 ss << std::put_time(&tm,
"%Y-%m-%d %H:%M:%S");
4866 std::ifstream file(file_path);
4867 if (!file.is_open()) {
4868 helios_runtime_error(
"ERROR (RadiationModel::loadColorCorrectionMatrixXML): Failed to open file for reading: " + file_path);
4871 std::vector<std::vector<float>> matrix;
4873 bool in_matrix =
false;
4874 std::string matrix_type =
"";
4876 while (std::getline(file, line)) {
4878 line.erase(0, line.find_first_not_of(
" \t"));
4879 line.erase(line.find_last_not_of(
" \t") + 1);
4882 if (line.find(
"<ColorCorrectionMatrix") != std::string::npos) {
4886 size_t camera_start = line.find(
"camera_label=\"");
4887 if (camera_start != std::string::npos) {
4889 size_t camera_end = line.find(
"\"", camera_start);
4890 if (camera_end != std::string::npos) {
4891 camera_label_out = line.substr(camera_start, camera_end - camera_start);
4896 size_t type_start = line.find(
"matrix_type=\"");
4897 if (type_start != std::string::npos) {
4899 size_t type_end = line.find(
"\"", type_start);
4900 if (type_end != std::string::npos) {
4901 matrix_type = line.substr(type_start, type_end - type_start);
4908 if (line.find(
"</ColorCorrectionMatrix>") != std::string::npos) {
4914 if (in_matrix && line.find(
"<row>") != std::string::npos && line.find(
"</row>") != std::string::npos) {
4916 size_t start = line.find(
"<row>") + 5;
4917 size_t end = line.find(
"</row>");
4918 std::string row_data = line.substr(start, end - start);
4921 std::vector<float> row;
4922 std::istringstream iss(row_data);
4924 while (iss >> value) {
4925 row.push_back(value);
4929 matrix.push_back(row);
4937 if (matrix.empty()) {
4938 helios_runtime_error(
"ERROR (RadiationModel::loadColorCorrectionMatrixXML): No matrix data found in file: " + file_path);
4941 if (matrix.size() != 3) {
4942 helios_runtime_error(
"ERROR (RadiationModel::loadColorCorrectionMatrixXML): Invalid matrix size. Expected 3 rows, found " + std::to_string(matrix.size()) +
" rows in file: " + file_path);
4946 bool is_3x3 = (matrix[0].size() == 3 && matrix[1].size() == 3 && matrix[2].size() == 3);
4947 bool is_4x3 = (matrix[0].size() == 4 && matrix[1].size() == 4 && matrix[2].size() == 4);
4949 if (!is_3x3 && !is_4x3) {
4950 helios_runtime_error(
"ERROR (RadiationModel::loadColorCorrectionMatrixXML): Invalid matrix dimensions. All rows must have either 3 or 4 elements. File: " + file_path);
4954 if (!matrix_type.empty()) {
4955 if ((matrix_type ==
"3x3" && !is_3x3) || (matrix_type ==
"4x3" && !is_4x3)) {
4956 helios_runtime_error(
"ERROR (RadiationModel::loadColorCorrectionMatrixXML): Matrix type attribute ('" + matrix_type +
"') does not match actual matrix dimensions in file: " + file_path);
4963std::string
RadiationModel::autoCalibrateCameraImage(
const std::string &camera_label,
const std::string &red_band_label,
const std::string &green_band_label,
const std::string &blue_band_label,
const std::string &output_file_path,
4967 if (cameras.find(camera_label) == cameras.end()) {
4968 helios_runtime_error(
"ERROR (RadiationModel::autoCalibrateCameraImage): Camera '" + camera_label +
"' does not exist. Make sure the camera was added to the radiation model.");
4972 std::string pixel_UUID_label =
"camera_" + camera_label +
"_pixel_UUID";
4974 helios_runtime_error(
"ERROR (RadiationModel::autoCalibrateCameraImage): Camera pixel UUID data '" + pixel_UUID_label +
"' does not exist for camera '" + camera_label +
"'. Make sure the radiation model has been run.");
4979 std::string colorboard_type;
4982 }
catch (
const std::exception &e) {
4983 helios_runtime_error(
"ERROR (RadiationModel::autoCalibrateCameraImage): Failed to detect colorboard type. " + std::string(e.what()));
4987 std::vector<CameraCalibration::LabColor> reference_lab_values;
4988 if (colorboard_type ==
"DGK") {
4990 }
else if (colorboard_type ==
"Calibrite") {
4992 }
else if (colorboard_type ==
"SpyderCHECKR") {
4995 helios_runtime_error(
"ERROR (RadiationModel::autoCalibrateCameraImage): Unsupported colorboard type '" + colorboard_type +
"'.");
4999 std::vector<uint> pixel_UUIDs;
5000 context->
getGlobalData(pixel_UUID_label.c_str(), pixel_UUIDs);
5001 int2 camera_resolution = cameras.at(camera_label).resolution;
5004 std::map<int, std::vector<std::vector<bool>>> patch_masks;
5005 for (
int patch_idx = 0; patch_idx < (int) reference_lab_values.size(); patch_idx++) {
5006 std::vector<std::vector<bool>> mask(camera_resolution.
y, std::vector<bool>(camera_resolution.
x,
false));
5009 for (
int y = 0; y < camera_resolution.
y; y++) {
5010 for (
int x = 0; x < camera_resolution.
x; x++) {
5011 int pixel_index = y * camera_resolution.
x + x;
5012 uint pixel_UUID = pixel_UUIDs[pixel_index];
5014 if (pixel_UUID > 0) {
5018 std::string colorboard_data_label =
"colorboard_" + colorboard_type;
5021 context->
getPrimitiveData(pixel_UUID, colorboard_data_label.c_str(), patch_id);
5023 if ((
int) patch_id == patch_idx) {
5031 patch_masks[patch_idx] = mask;
5036 std::vector<float> red_data, green_data, blue_data;
5039 auto &camera_bands = cameras.at(camera_label).band_labels;
5040 if (std::find(camera_bands.begin(), camera_bands.end(), red_band_label) == camera_bands.end()) {
5041 helios_runtime_error(
"ERROR (RadiationModel::autoCalibrateCameraImage): Red band '" + red_band_label +
"' not found in camera '" + camera_label +
"'.");
5043 if (std::find(camera_bands.begin(), camera_bands.end(), green_band_label) == camera_bands.end()) {
5044 helios_runtime_error(
"ERROR (RadiationModel::autoCalibrateCameraImage): Green band '" + green_band_label +
"' not found in camera '" + camera_label +
"'.");
5046 if (std::find(camera_bands.begin(), camera_bands.end(), blue_band_label) == camera_bands.end()) {
5047 helios_runtime_error(
"ERROR (RadiationModel::autoCalibrateCameraImage): Blue band '" + blue_band_label +
"' not found in camera '" + camera_label +
"'.");
5051 red_data = cameras.at(camera_label).pixel_data.at(red_band_label);
5052 green_data = cameras.at(camera_label).pixel_data.at(green_band_label);
5053 blue_data = cameras.at(camera_label).pixel_data.at(blue_band_label);
5056 float max_r = *std::max_element(red_data.begin(), red_data.end());
5057 float max_g = *std::max_element(green_data.begin(), green_data.end());
5058 float max_b = *std::max_element(blue_data.begin(), blue_data.end());
5061 float scale_factor = 1.0f;
5062 if (max_r > 1.0f || max_g > 1.0f || max_b > 1.0f) {
5063 scale_factor = 1.0f / std::max({max_r, max_g, max_b});
5065 for (
size_t i = 0; i < red_data.size(); i++) {
5066 red_data[i] *= scale_factor;
5067 green_data[i] *= scale_factor;
5068 blue_data[i] *= scale_factor;
5072 std::vector<helios::vec3> measured_rgb_values;
5073 int visible_patches = 0;
5075 for (
const auto &[patch_idx, mask]: patch_masks) {
5076 float sum_r = 0.0f, sum_g = 0.0f, sum_b = 0.0f;
5077 int pixel_count = 0;
5080 for (
int y = 0; y < camera_resolution.
y; y++) {
5081 for (
int x = 0; x < camera_resolution.
x; x++) {
5083 int pixel_index = y * camera_resolution.
x + x;
5084 sum_r += red_data[pixel_index];
5085 sum_g += green_data[pixel_index];
5086 sum_b += blue_data[pixel_index];
5092 if (pixel_count > 10) {
5094 measured_rgb_values.push_back(avg_rgb);
5099 measured_rgb_values.push_back(
make_vec3(0, 0, 0));
5104 std::vector<CameraCalibration::LabColor> measured_lab_values;
5105 for (
const auto &rgb: measured_rgb_values) {
5106 if (rgb.magnitude() > 0) {
5107 measured_lab_values.push_back(calibration.
rgbToLab(rgb));
5112 std::vector<std::vector<float>> correction_matrix = {{1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}};
5115 std::string algorithm_name;
5116 switch (algorithm) {
5118 algorithm_name =
"Diagonal scaling (white balance only)";
5121 algorithm_name =
"3x3 matrix with auto-fallback to diagonal";
5124 algorithm_name =
"3x3 matrix (forced)";
5128 if (measured_lab_values.size() >= 6 && reference_lab_values.size() >= 6) {
5130 std::vector<helios::vec3> target_rgb;
5132 for (
size_t i = 0; i < reference_lab_values.size(); i++) {
5135 target_rgb.push_back(ref_rgb);
5143 std::vector<helios::vec3> valid_measured, valid_target;
5144 std::vector<float> patch_weights;
5146 for (
size_t i = 0; i < std::min(measured_rgb_values.size(), target_rgb.size()); i++) {
5147 if (measured_rgb_values[i].magnitude() > 0.01f) {
5148 valid_measured.push_back(measured_rgb_values[i]);
5149 valid_target.push_back(target_rgb[i]);
5152 float weight = 1.0f;
5155 if (i >= 18 && i <= 23) {
5165 else if (i == 14 || i == 13 || i == 12)
5169 else if (i == 3 || i == 10)
5174 float luminance = 0.299f * measured_rgb.
x + 0.587f * measured_rgb.
y + 0.114f * measured_rgb.
z;
5177 if (luminance > 0.6f)
5179 else if (luminance < 0.2f)
5188 patch_weights.push_back(weight);
5196 bool matrix_valid =
true;
5199 std::vector<float> lambda_values = {0.01f, 0.05f, 0.1f, 0.15f, 0.2f};
5200 int lambda_attempt = 0;
5202 while (lambda_attempt < lambda_values.size()) {
5203 float lambda = lambda_values[lambda_attempt];
5204 matrix_valid =
true;
5206 for (
int row = 0; row < 3; row++) {
5208 float ATA[3][3] = {{0}};
5211 for (
size_t i = 0; i < valid_measured.size(); i++) {
5212 float weight = patch_weights[i];
5214 float target_val = (row == 0) ? valid_target[i].x : (row == 1) ? valid_target[i].y : valid_target[i].z;
5217 ATA[0][0] += weight * m.
x * m.
x;
5218 ATA[0][1] += weight * m.
x * m.
y;
5219 ATA[0][2] += weight * m.
x * m.
z;
5220 ATA[1][0] += weight * m.
y * m.
x;
5221 ATA[1][1] += weight * m.
y * m.
y;
5222 ATA[1][2] += weight * m.
y * m.
z;
5223 ATA[2][0] += weight * m.
z * m.
x;
5224 ATA[2][1] += weight * m.
z * m.
y;
5225 ATA[2][2] += weight * m.
z * m.
z;
5227 ATb[0] += weight * m.
x * target_val;
5228 ATb[1] += weight * m.
y * target_val;
5229 ATb[2] += weight * m.
z * target_val;
5235 float diag_reg = lambda * 2.0f;
5236 float offdiag_reg = lambda * 0.5f;
5238 ATA[0][0] += diag_reg;
5239 ATA[1][1] += diag_reg;
5240 ATA[2][2] += diag_reg;
5243 ATA[0][1] += offdiag_reg;
5244 ATA[1][0] += offdiag_reg;
5245 ATA[0][2] += offdiag_reg;
5246 ATA[2][0] += offdiag_reg;
5247 ATA[1][2] += offdiag_reg;
5248 ATA[2][1] += offdiag_reg;
5251 float det = ATA[0][0] * (ATA[1][1] * ATA[2][2] - ATA[1][2] * ATA[2][1]) - ATA[0][1] * (ATA[1][0] * ATA[2][2] - ATA[1][2] * ATA[2][0]) + ATA[0][2] * (ATA[1][0] * ATA[2][1] - ATA[1][1] * ATA[2][0]);
5253 if (fabs(det) < 1e-3f) {
5255 matrix_valid =
false;
5260 float inv_det = 1.0f / det;
5261 correction_matrix[row][0] = inv_det * (ATb[0] * (ATA[1][1] * ATA[2][2] - ATA[1][2] * ATA[2][1]) - ATb[1] * (ATA[0][1] * ATA[2][2] - ATA[0][2] * ATA[2][1]) + ATb[2] * (ATA[0][1] * ATA[1][2] - ATA[0][2] * ATA[1][1]));
5263 correction_matrix[row][1] = inv_det * (ATb[1] * (ATA[0][0] * ATA[2][2] - ATA[0][2] * ATA[2][0]) - ATb[0] * (ATA[1][0] * ATA[2][2] - ATA[1][2] * ATA[2][0]) + ATb[2] * (ATA[1][0] * ATA[0][2] - ATA[1][2] * ATA[0][0]));
5265 correction_matrix[row][2] = inv_det * (ATb[2] * (ATA[0][0] * ATA[1][1] - ATA[0][1] * ATA[1][0]) - ATb[0] * (ATA[1][0] * ATA[2][1] - ATA[1][1] * ATA[2][0]) + ATb[1] * (ATA[0][0] * ATA[2][1] - ATA[0][1] * ATA[2][0]));
5270 bool elements_reasonable =
true;
5271 for (
int i = 0; i < 3; i++) {
5272 for (
int j = 0; j < 3; j++) {
5273 if (fabs(correction_matrix[i][j]) > 5.0f) {
5275 elements_reasonable =
false;
5280 if (!elements_reasonable)
5283 matrix_valid = elements_reasonable;
5293 if (!matrix_valid) {
5297 float total_weight = 0.0f;
5300 for (
size_t i = 0; i < valid_measured.size(); i++) {
5301 float weight = patch_weights[i];
5306 if (measured.
x > 0.01f && measured.
y > 0.01f && measured.
z > 0.01f) {
5309 weighted_correction.
x += weight * channel_correction.
x;
5310 weighted_correction.
y += weight * channel_correction.
y;
5311 weighted_correction.
z += weight * channel_correction.
z;
5312 total_weight += weight;
5316 if (total_weight > 0.1f) {
5318 correction_matrix[0][0] = weighted_correction.
x / total_weight;
5319 correction_matrix[1][1] = weighted_correction.
y / total_weight;
5320 correction_matrix[2][2] = weighted_correction.
z / total_weight;
5323 correction_matrix[0][0] = std::max(0.5f, std::min(2.0f, correction_matrix[0][0]));
5324 correction_matrix[1][1] = std::max(0.5f, std::min(2.0f, correction_matrix[1][1]));
5325 correction_matrix[2][2] = std::max(0.5f, std::min(2.0f, correction_matrix[2][2]));
5331 correction_matrix = {{1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}};
5335 if (valid_measured.size() > 0 && patch_weights.size() == valid_measured.size()) {
5336 float total_weight = 0.0f;
5341 for (
size_t i = 0; i < valid_measured.size(); i++) {
5342 float weight = patch_weights[i];
5343 weighted_measured_avg = weighted_measured_avg + weight * valid_measured[i];
5344 weighted_target_avg = weighted_target_avg + weight * valid_target[i];
5345 total_weight += weight;
5348 if (total_weight > 0) {
5349 weighted_measured_avg = weighted_measured_avg / total_weight;
5350 weighted_target_avg = weighted_target_avg / total_weight;
5352 if (weighted_measured_avg.
x > 0.05f && weighted_measured_avg.
y > 0.05f && weighted_measured_avg.
z > 0.05f) {
5353 correction_matrix[0][0] = weighted_target_avg.
x / weighted_measured_avg.
x;
5354 correction_matrix[1][1] = weighted_target_avg.
y / weighted_measured_avg.
y;
5355 correction_matrix[2][2] = weighted_target_avg.
z / weighted_measured_avg.
z;
5358 correction_matrix[0][0] = std::max(0.5f, std::min(2.0f, correction_matrix[0][0]));
5359 correction_matrix[1][1] = std::max(0.5f, std::min(2.0f, correction_matrix[1][1]));
5360 correction_matrix[2][2] = std::max(0.5f, std::min(2.0f, correction_matrix[2][2]));
5364 size_t white_idx = 18;
5365 if (white_idx < measured_rgb_values.size() && white_idx < target_rgb.size()) {
5366 helios::vec3 measured_white = measured_rgb_values[white_idx];
5368 if (measured_white.
x > 0.05f && measured_white.
y > 0.05f && measured_white.
z > 0.05f) {
5369 correction_matrix[0][0] = std::max(0.5f, std::min(2.0f, target_white.
x / measured_white.
x));
5370 correction_matrix[1][1] = std::max(0.5f, std::min(2.0f, target_white.
y / measured_white.
y));
5371 correction_matrix[2][2] = std::max(0.5f, std::min(2.0f, target_white.
z / measured_white.
z));
5378 size_t white_idx = 18;
5379 if (white_idx < measured_rgb_values.size() && white_idx < target_rgb.size()) {
5380 helios::vec3 measured_white = measured_rgb_values[white_idx];
5382 if (measured_white.
x > 0.05f && measured_white.
y > 0.05f && measured_white.
z > 0.05f) {
5383 correction_matrix[0][0] = std::max(0.5f, std::min(2.0f, target_white.
x / measured_white.
x));
5384 correction_matrix[1][1] = std::max(0.5f, std::min(2.0f, target_white.
y / measured_white.
y));
5385 correction_matrix[2][2] = std::max(0.5f, std::min(2.0f, target_white.
z / measured_white.
z));
5392 size_t white_idx = 18;
5393 if (white_idx < measured_rgb_values.size() && white_idx < target_rgb.size() && measured_rgb_values[white_idx].magnitude() > 0) {
5395 helios::vec3 measured_white = measured_rgb_values[white_idx];
5398 if (measured_white.
x > 0.05f && measured_white.
y > 0.05f && measured_white.
z > 0.05f) {
5399 correction_matrix[0][0] = target_white.
x / measured_white.
x;
5400 correction_matrix[1][1] = target_white.
y / measured_white.
y;
5401 correction_matrix[2][2] = target_white.
z / measured_white.
z;
5404 correction_matrix[0][0] = std::max(0.5f, std::min(2.0f, correction_matrix[0][0]));
5405 correction_matrix[1][1] = std::max(0.5f, std::min(2.0f, correction_matrix[1][1]));
5406 correction_matrix[2][2] = std::max(0.5f, std::min(2.0f, correction_matrix[2][2]));
5410 std::cout <<
"Insufficient valid patches (" << valid_measured.size() <<
" available), using identity matrix" << std::endl;
5414 size_t white_idx = 18;
5415 if (white_idx < measured_rgb_values.size() && white_idx < reference_lab_values.size() && measured_rgb_values[white_idx].magnitude() > 0) {
5419 helios::vec3 measured_white = measured_rgb_values[white_idx];
5421 if (measured_white.
x > 0.05f && measured_white.
y > 0.05f && measured_white.
z > 0.05f) {
5422 correction_matrix[0][0] = target_white.
x / measured_white.
x;
5423 correction_matrix[1][1] = target_white.
y / measured_white.
y;
5424 correction_matrix[2][2] = target_white.
z / measured_white.
z;
5427 correction_matrix[0][0] = std::max(0.5f, std::min(2.0f, correction_matrix[0][0]));
5428 correction_matrix[1][1] = std::max(0.5f, std::min(2.0f, correction_matrix[1][1]));
5429 correction_matrix[2][2] = std::max(0.5f, std::min(2.0f, correction_matrix[2][2]));
5433 std::cout <<
"Insufficient patches for correction (" << measured_lab_values.size() <<
" available), using identity matrix" << std::endl;
5437 if (print_quality_report) {
5438 std::cout <<
"\n========== COLOR CALIBRATION QUALITY REPORT ==========" << std::endl;
5439 std::cout <<
"Colorboard type: " << colorboard_type << std::endl;
5440 std::cout <<
"Number of patches analyzed: " << visible_patches << std::endl;
5441 std::cout <<
"Algorithm used: " << algorithm_name << std::endl;
5444 bool is_diagonal_only =
true;
5445 for (
int i = 0; i < 3; i++) {
5446 for (
int j = 0; j < 3; j++) {
5447 if (i != j && fabs(correction_matrix[i][j]) > 1e-6f) {
5448 is_diagonal_only =
false;
5452 if (!is_diagonal_only)
5456 if (is_diagonal_only) {
5457 std::cout <<
"Color correction factors applied: R=" << correction_matrix[0][0] <<
", G=" << correction_matrix[1][1] <<
", B=" << correction_matrix[2][2] << std::endl;
5458 std::cout <<
"Matrix type: Diagonal (white balance only)" << std::endl;
5460 std::cout <<
"Full 3x3 color correction matrix applied:" << std::endl;
5461 for (
int i = 0; i < 3; i++) {
5462 std::cout <<
"[" << std::fixed << std::setprecision(4);
5463 for (
int j = 0; j < 3; j++) {
5464 std::cout << std::setw(8) << correction_matrix[i][j];
5468 std::cout <<
"]" << std::endl;
5470 std::cout <<
"Matrix type: Full 3x3 (corrects color casts and chromatic errors)" << std::endl;
5473 float det = correction_matrix[0][0] * (correction_matrix[1][1] * correction_matrix[2][2] - correction_matrix[1][2] * correction_matrix[2][1]) -
5474 correction_matrix[0][1] * (correction_matrix[1][0] * correction_matrix[2][2] - correction_matrix[1][2] * correction_matrix[2][0]) +
5475 correction_matrix[0][2] * (correction_matrix[1][0] * correction_matrix[2][1] - correction_matrix[1][1] * correction_matrix[2][0]);
5477 std::cout <<
"Matrix determinant: " << std::scientific << std::setprecision(3) << det << std::endl;
5478 if (fabs(det) > 0.1f) {
5479 std::cout <<
"Matrix conditioning: Good (well-conditioned)" << std::endl;
5480 }
else if (fabs(det) > 0.01f) {
5481 std::cout <<
"Matrix conditioning: Fair (moderately conditioned)" << std::endl;
5483 std::cout <<
"Matrix conditioning: Poor (ill-conditioned)" << std::endl;
5485 std::cout << std::fixed;
5489 double total_delta_e = 0.0;
5490 int valid_patches = 0;
5492 std::cout <<
"\nPer-patch analysis (after correction):" << std::endl;
5493 std::cout <<
"Patch | Corrected RGB | Reference RGB | Delta E " << std::endl;
5494 std::cout <<
"------|--------------------|--------------------|---------" << std::endl;
5496 for (
size_t i = 0; i < std::min(measured_rgb_values.size(), reference_lab_values.size()); i++) {
5497 if (measured_rgb_values[i].magnitude() > 0) {
5500 float corrected_r = correction_matrix[0][0] * measured_rgb.
x + correction_matrix[0][1] * measured_rgb.
y + correction_matrix[0][2] * measured_rgb.
z;
5501 float corrected_g = correction_matrix[1][0] * measured_rgb.
x + correction_matrix[1][1] * measured_rgb.
y + correction_matrix[1][2] * measured_rgb.
z;
5502 float corrected_b = correction_matrix[2][0] * measured_rgb.
x + correction_matrix[2][1] * measured_rgb.
y + correction_matrix[2][2] * measured_rgb.
z;
5518 double delta_E = calibration.
deltaE2000(corrected_lab, reference_lab);
5520 std::cout << std::setw(5) << i <<
" | " << std::fixed << std::setprecision(3) <<
"(" << std::setw(5) << corrected_rgb.
x <<
"," << std::setw(5) << corrected_rgb.
y <<
"," << std::setw(5) << corrected_rgb.
z <<
") | ";
5523 std::cout <<
"(" << std::setw(5) << ref_rgb.
x <<
"," << std::setw(5) << ref_rgb.
y <<
"," << std::setw(5) << ref_rgb.
z <<
") | " << std::setw(7) << delta_E << std::endl;
5525 total_delta_e += delta_E;
5531 double mean_delta_e = total_delta_e / valid_patches;
5532 std::cout <<
"\n========== OVERALL CALIBRATION QUALITY ==========" << std::endl;
5533 std::cout <<
"Mean Delta E: " << std::fixed << std::setprecision(2) << mean_delta_e << std::endl;
5535 std::cout <<
"======================================================\n" << std::endl;
5539 std::vector<helios::RGBcolor> corrected_pixels;
5540 corrected_pixels.resize(red_data.size());
5543 for (
int j = 0; j < camera_resolution.
y; j++) {
5544 for (
int i = 0; i < camera_resolution.
x; i++) {
5546 int source_index = j * camera_resolution.
x + i;
5547 float r = red_data[source_index];
5548 float g = green_data[source_index];
5549 float b = blue_data[source_index];
5552 float corrected_r = correction_matrix[0][0] * r + correction_matrix[0][1] * g + correction_matrix[0][2] * b;
5553 float corrected_g = correction_matrix[1][0] * r + correction_matrix[1][1] * g + correction_matrix[1][2] * b;
5554 float corrected_b = correction_matrix[2][0] * r + correction_matrix[2][1] * g + correction_matrix[2][2] * b;
5563 uint ii = camera_resolution.
x - i - 1;
5564 uint jj = camera_resolution.
y - j - 1;
5565 uint dest_index = jj * camera_resolution.
x + ii;
5567 corrected_pixels[dest_index] =
make_RGBcolor(corrected_r, corrected_g, corrected_b);
5572 std::string output_path = output_file_path;
5573 if (output_path.empty()) {
5574 output_path =
"auto_calibrated_" + camera_label +
".jpg";
5578 helios::writeJPEG(output_path, camera_resolution.
x, camera_resolution.
y, corrected_pixels);
5579 std::cout <<
"Wrote corrected image to: " << output_path << std::endl;
5580 }
catch (
const std::exception &e) {
5581 helios_runtime_error(
"ERROR (RadiationModel::autoCalibrateCameraImage): Failed to write corrected image. " + std::string(e.what()));
5585 if (!ccm_export_file_path.empty()) {
5588 double total_delta_e = 0.0;
5589 int valid_patches = 0;
5591 for (
size_t i = 0; i < std::min(measured_rgb_values.size(), reference_lab_values.size()); i++) {
5592 if (measured_rgb_values[i].magnitude() > 0) {
5595 float corrected_r = correction_matrix[0][0] * measured_rgb.
x + correction_matrix[0][1] * measured_rgb.
y + correction_matrix[0][2] * measured_rgb.
z;
5596 float corrected_g = correction_matrix[1][0] * measured_rgb.
x + correction_matrix[1][1] * measured_rgb.
y + correction_matrix[1][2] * measured_rgb.
z;
5597 float corrected_b = correction_matrix[2][0] * measured_rgb.
x + correction_matrix[2][1] * measured_rgb.
y + correction_matrix[2][2] * measured_rgb.
z;
5606 double delta_E = calibration.
deltaE2000(corrected_lab, reference_lab);
5607 total_delta_e += delta_E;
5612 double mean_delta_e = (valid_patches > 0) ? (total_delta_e / valid_patches) : -1.0;
5617 std::cout <<
"Exported color correction matrix to: " << ccm_export_file_path << std::endl;
5618 }
catch (
const std::exception &e) {
5619 helios_runtime_error(
"ERROR (RadiationModel::autoCalibrateCameraImage): Failed to export CCM to XML. " + std::string(e.what()));
5629 if (cameras.find(camera_label) == cameras.end()) {
5630 helios_runtime_error(
"ERROR (RadiationModel::applyCameraColorCorrectionMatrix): Camera '" + camera_label +
"' does not exist. Make sure the camera was added to the radiation model.");
5634 auto &camera_bands = cameras.at(camera_label).band_labels;
5635 if (std::find(camera_bands.begin(), camera_bands.end(), red_band_label) == camera_bands.end()) {
5636 helios_runtime_error(
"ERROR (RadiationModel::applyCameraColorCorrectionMatrix): Red band '" + red_band_label +
"' not found in camera '" + camera_label +
"'.");
5638 if (std::find(camera_bands.begin(), camera_bands.end(), green_band_label) == camera_bands.end()) {
5639 helios_runtime_error(
"ERROR (RadiationModel::applyCameraColorCorrectionMatrix): Green band '" + green_band_label +
"' not found in camera '" + camera_label +
"'.");
5641 if (std::find(camera_bands.begin(), camera_bands.end(), blue_band_label) == camera_bands.end()) {
5642 helios_runtime_error(
"ERROR (RadiationModel::applyCameraColorCorrectionMatrix): Blue band '" + blue_band_label +
"' not found in camera '" + camera_label +
"'.");
5646 std::string loaded_camera_label;
5647 std::vector<std::vector<float>> correction_matrix;
5650 }
catch (
const std::exception &e) {
5651 helios_runtime_error(
"ERROR (RadiationModel::applyCameraColorCorrectionMatrix): Failed to load CCM from XML file. " + std::string(e.what()));
5655 if (correction_matrix.size() != 3) {
5656 helios_runtime_error(
"ERROR (RadiationModel::applyCameraColorCorrectionMatrix): Invalid matrix dimensions. Expected 3x3 or 4x3 matrix, got " + std::to_string(correction_matrix.size()) +
" rows.");
5659 bool is_3x3 = (correction_matrix[0].size() == 3);
5660 bool is_4x3 = (correction_matrix[0].size() == 4);
5662 if (!is_3x3 && !is_4x3) {
5663 helios_runtime_error(
"ERROR (RadiationModel::applyCameraColorCorrectionMatrix): Invalid matrix dimensions. Expected 3x3 or 4x3 matrix, got " + std::to_string(correction_matrix.size()) +
"x" + std::to_string(correction_matrix[0].size()) +
5668 std::vector<float> &red_data = cameras.at(camera_label).pixel_data.at(red_band_label);
5669 std::vector<float> &green_data = cameras.at(camera_label).pixel_data.at(green_band_label);
5670 std::vector<float> &blue_data = cameras.at(camera_label).pixel_data.at(blue_band_label);
5672 int2 camera_resolution = cameras.at(camera_label).resolution;
5673 size_t pixel_count = red_data.size();
5676 for (
size_t i = 0; i < pixel_count; i++) {
5677 float r = red_data[i];
5678 float g = green_data[i];
5679 float b = blue_data[i];
5684 red_data[i] = correction_matrix[0][0] * r + correction_matrix[0][1] * g + correction_matrix[0][2] * b;
5685 green_data[i] = correction_matrix[1][0] * r + correction_matrix[1][1] * g + correction_matrix[1][2] * b;
5686 blue_data[i] = correction_matrix[2][0] * r + correction_matrix[2][1] * g + correction_matrix[2][2] * b;
5689 red_data[i] = correction_matrix[0][0] * r + correction_matrix[0][1] * g + correction_matrix[0][2] * b + correction_matrix[0][3];
5690 green_data[i] = correction_matrix[1][0] * r + correction_matrix[1][1] * g + correction_matrix[1][2] * b + correction_matrix[1][3];
5691 blue_data[i] = correction_matrix[2][0] * r + correction_matrix[2][1] * g + correction_matrix[2][2] * b + correction_matrix[2][3];
5696 std::cout <<
"Applied color correction matrix from '" << ccm_file_path <<
"' to camera '" << camera_label <<
"'" << std::endl;
5697 std::cout <<
"Matrix type: " << (is_3x3 ?
"3x3" :
"4x3") <<
", processed " << pixel_count <<
" pixels" << std::endl;
5702 if (cameras.find(camera_label) == cameras.end()) {
5703 helios_runtime_error(
"ERROR (RadiationModel::getCameraPixelData): Camera '" + camera_label +
"' does not exist.");
5706 auto &camera_pixel_data = cameras.at(camera_label).pixel_data;
5707 if (camera_pixel_data.find(band_label) == camera_pixel_data.end()) {
5708 helios_runtime_error(
"ERROR (RadiationModel::getCameraPixelData): Band '" + band_label +
"' does not exist in camera '" + camera_label +
"'.");
5711 return camera_pixel_data.at(band_label);
5715 if (cameras.find(camera_label) == cameras.end()) {
5716 helios_runtime_error(
"ERROR (RadiationModel::setCameraPixelData): Camera '" + camera_label +
"' does not exist.");
5719 cameras.at(camera_label).pixel_data[band_label] = pixel_data;
5722void sutilHandleError(RTcontext context, RTresult code,
const char *file,
int line) {
5723 const char *message;
5725 rtContextGetErrorString(context, code, &message);
5726 sprintf(s,
"%s\n(%s:%d)", message, file, line);
5727 sutilReportError(s);
5731void sutilReportError(
const char *message) {
5732 fprintf(stderr,
"OptiX Error: %s\n", message);
5733#if defined(_WIN32) && defined(RELEASE_PUBLIC)
5736 sprintf(s,
"OptiX Error: %s", message);
5737 MessageBox(0, s,
"OptiX Error", MB_OK | MB_ICONWARNING | MB_SYSTEMMODAL);