diff --git a/src/libs/rover/domain.cpp b/src/libs/rover/domain.cpp index e5e5390a7..0f8a2b38f 100644 --- a/src/libs/rover/domain.cpp +++ b/src/libs/rover/domain.cpp @@ -86,9 +86,15 @@ Domain::init() } const int -Domain::get_num_channels() +Domain::get_num_energy_groups() { - return m_engine->get_num_channels(); + return m_engine->get_num_energy_groups(); +} + +bool +Domain::get_field_mismatch_error() +{ + return m_engine->get_field_mismatch_error(); } void diff --git a/src/libs/rover/domain.hpp b/src/libs/rover/domain.hpp index d794e09ff..b7e44909f 100644 --- a/src/libs/rover/domain.hpp +++ b/src/libs/rover/domain.hpp @@ -39,7 +39,8 @@ class Domain vtkm::Bounds& get_domain_bounds(); vtkmRange get_primary_range(); void set_global_bounds(vtkm::Bounds bounds); - const int get_num_channels(); + const int get_num_energy_groups(); + bool get_field_mismatch_error(); protected: std::shared_ptr m_engine; vtkmDataSet m_dataset; diff --git a/src/libs/rover/engine.cpp b/src/libs/rover/engine.cpp index 73ab37826..b64e1e509 100644 --- a/src/libs/rover/engine.cpp +++ b/src/libs/rover/engine.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace rover { @@ -16,6 +17,7 @@ namespace rover Engine::Engine() { m_tracer = nullptr; + m_field_mismatch_error = false; } Engine::~Engine() @@ -36,7 +38,7 @@ Engine::validate_tracer() // this in 1 or 2 spots and won't need a helper. if (!m_tracer) { - ROVER_ERROR("Error - Engine::validate_tracer: data was not set before tracing"); + ASCENT_LOG_ERROR("Error - Engine::validate_tracer: data was not set before tracing"); } } @@ -57,13 +59,13 @@ Engine::set_dataset(vtkm::cont::DataSet &dataset) template void Engine::init_emission(vtkmRayTracing::Ray &rays, - const int num_bins) + const int num_energy_groups) { if (rover::settings.has_child("emission")) { const std::string emission = rover::settings["emission"].as_string(); m_tracer->SetEmissionField(emission); - rays.AddBuffer(num_bins, "emission"); + rays.AddBuffer(num_energy_groups, "emission"); rays.GetBuffer("emission").InitConst(0.0f); } } @@ -83,12 +85,12 @@ void Engine::init_rays(Ray32 &rays) { validate_tracer(); - const int num_bins = get_num_channels(); - rays.Buffers.at(0).SetNumChannels(num_bins); + const int num_energy_groups = get_num_energy_groups(); + rays.Buffers.at(0).SetNumChannels(num_energy_groups); // TODO: I think this should be init with background intensities rays.Buffers.at(0).InitConst(1.0f); - init_emission(rays, num_bins); - rays.AddBuffer(num_bins, "optical_depths"); + init_emission(rays, num_energy_groups); + rays.AddBuffer(num_energy_groups, "optical_depths"); rays.GetBuffer("optical_depths").InitConst(0.0f); } @@ -96,12 +98,12 @@ void Engine::init_rays(Ray64 &rays) { validate_tracer(); - const int num_bins = get_num_channels(); - rays.Buffers.at(0).SetNumChannels(num_bins); + const int num_energy_groups = get_num_energy_groups(); + rays.Buffers.at(0).SetNumChannels(num_energy_groups); // TODO: I think this should be init with background intensities rays.Buffers.at(0).InitConst(1.0f); - init_emission(rays, num_bins); - rays.AddBuffer(num_bins, "optical_depths"); + init_emission(rays, num_energy_groups); + rays.AddBuffer(num_energy_groups, "optical_depths"); rays.GetBuffer("optical_depths").InitConst(0.0f); } @@ -117,40 +119,33 @@ Engine::partial_trace(Ray64 &rays, PartialVector64 &partials) } int -Engine::get_num_channels() +Engine::get_num_energy_groups() { - vtkm::Id absorption_size = 0; - ArraySizeFunctor functor(&absorption_size); const std::string absorption = rover::settings["absorption"].as_string(); - m_dataset.GetField(absorption). - GetData(). - CastAndCallForTypes(functor); - vtkm::Id num_cells = m_dataset.GetCellSet().GetNumberOfCells(); - - // TODO: Seemingly redundant assert followed by a check that num_cells == 0 - assert(num_cells > 0); - assert(absorption_size > 0); - if (num_cells == 0) - { - ROVER_ERROR("Error - Engine::get_num_channels: num cells is 0" - << "\n num cells " << num_cells - << "\n field size " <(num_bins); + + return static_cast(num_absorption_bins); +} + +bool +Engine::get_field_mismatch_error() +{ + return m_field_mismatch_error; } vtkmRange diff --git a/src/libs/rover/engine.hpp b/src/libs/rover/engine.hpp index 5269470d4..f611cb83a 100644 --- a/src/libs/rover/engine.hpp +++ b/src/libs/rover/engine.hpp @@ -43,7 +43,8 @@ class Engine void init_rays(Ray64 &rays); void partial_trace(Ray32 &rays, PartialVector32 &partials); void partial_trace(Ray64 &rays, PartialVector64 &partials); - int get_num_channels(); + int get_num_energy_groups(); + bool get_field_mismatch_error(); vtkmRange get_primary_range(); void set_primary_range(const vtkmRange &range); void set_composite_background(bool on); @@ -51,6 +52,7 @@ class Engine protected: vtkmDataSet m_dataset; vtkh::rendering::ConnectivityProxy *m_tracer; + bool m_field_mismatch_error; template void init_emission(vtkmRayTracing::Ray &rays, diff --git a/src/libs/rover/image.cpp b/src/libs/rover/image.cpp index 639719e7d..42430ad55 100644 --- a/src/libs/rover/image.cpp +++ b/src/libs/rover/image.cpp @@ -139,8 +139,8 @@ void cast_array_handle(vtkm::cont::ArrayHandle &cast_to, // template void init_from_image(Image &left, Image &right) { - const size_t channels = right.m_intensity_values.size(); - for(size_t i = 0; i < channels; ++i) + const size_t num_energy_groups = right.m_intensity_values.size(); + for(size_t i = 0; i < num_energy_groups; ++i) { cast_array_handle(left.m_intensity_values[i], right.m_intensity_values[i]); cast_array_handle(left.m_optical_depth_values[i], right.m_optical_depth_values[i]); @@ -171,7 +171,7 @@ Image::operator=(Image &other) template int -Image::get_num_channels() const +Image::get_num_energy_groups() const { return static_cast(m_intensity_values.size()); } @@ -200,7 +200,7 @@ Image::init_from_partial(PartialImage &partial) const int64 width = rover::settings["width"].to_int64(); const int64 height = rover::settings["height"].to_int64(); const int64 channel_size = width * height; - const int num_channels = partial.m_transmission.GetNumChannels(); + const int num_energy_groups = partial.m_transmission.GetNumChannels(); // Helper lambda to expand a channel and push its buffer to the output vector auto expand_and_push = [&](int channel_index, @@ -213,7 +213,7 @@ Image::init_from_partial(PartialImage &partial) output_vector.push_back(expanded.Buffer); }; - for (int i = 0; i < num_channels; i++) + for (int i = 0; i < num_energy_groups; i++) { // Intensities expand_and_push(i, @@ -255,15 +255,15 @@ template vtkm::cont::ArrayHandle Image::flatten_intensity_values() { - const int num_channels = this->get_num_channels(); + const int num_energy_groups = get_num_energy_groups(); HandleType res; const int64 width = rover::settings["width"].to_int64(); const int64 height = rover::settings["height"].to_int64(); const int64 size = width * height; - res.Allocate(num_channels * size); + res.Allocate(num_energy_groups * size); auto output = res.WritePortal(); - for(int c = 0; c < num_channels; ++c) + for(int c = 0; c < num_energy_groups; ++c) { auto channel = m_intensity_values[c].ReadPortal(); @@ -272,7 +272,8 @@ Image::flatten_intensity_values() #endif for(int i = 0; i < size; ++i) { - output.Set( i * num_channels + c, channel.Get(i)); + // Deinterleave the output: all pixels for group 0, then all pixels for group 1, etc. + output.Set(c * size + i, channel.Get(i)); } } return res; @@ -282,15 +283,15 @@ template vtkm::cont::ArrayHandle Image::flatten_optical_depth_values() { - const int num_channels = this->get_num_channels(); + const int num_energy_groups = get_num_energy_groups(); HandleType res; const int64 width = rover::settings["width"].to_int64(); const int64 height = rover::settings["height"].to_int64(); const int64 size = width * height; - res.Allocate(num_channels * size); + res.Allocate(num_energy_groups * size); auto output = res.WritePortal(); - for(int c = 0; c < num_channels; ++c) + for(int c = 0; c < num_energy_groups; ++c) { auto channel = m_optical_depth_values[c].ReadPortal(); #ifdef ROVER_OPENMP_ENABLED @@ -298,7 +299,8 @@ Image::flatten_optical_depth_values() #endif for(int i = 0; i < size; ++i) { - output.Set( i * num_channels + c, channel.Get(i)); + // Deinterleave the output: all pixels for group 0, then all pixels for group 1, etc. + output.Set( c * size + i, channel.Get(i)); } } return res; diff --git a/src/libs/rover/image.hpp b/src/libs/rover/image.hpp index cf1a1bf03..aa1cf0353 100644 --- a/src/libs/rover/image.hpp +++ b/src/libs/rover/image.hpp @@ -27,7 +27,7 @@ class Image HandleType get_intensity(const int &channel_num); HandleType get_optical_depth(const int &channel_num); - int get_num_channels() const; + int get_num_energy_groups() const; bool has_intensity(const int &channel_num) const; bool has_optical_depth(const int &channel_num) const; void normalize_intensity(const int &channel_num); diff --git a/src/libs/rover/rover.cpp b/src/libs/rover/rover.cpp index 319283b60..829c50b74 100644 --- a/src/libs/rover/rover.cpp +++ b/src/libs/rover/rover.cpp @@ -4,7 +4,9 @@ // other details. No copyright assignment is required to contribute to Ascent. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// -#include +#include +#include + #include #include #include @@ -13,6 +15,7 @@ #include #include + #ifdef ROVER_PARALLEL #include #endif @@ -141,7 +144,7 @@ Rover::create_scheduler() // Check to see if we have been initialized if(-1 == m_rank) { - ROVER_ERROR("Error - Rover::create_scheduler: MPI was not initialized"); + ASCENT_LOG_ERROR("Error - Rover::create_scheduler: MPI was not initialized"); } m_scheduler->set_comm_handle(m_comm_handle); #endif @@ -285,7 +288,7 @@ Rover::execute() // but a developer would prefer to be made aware. if (!m_scheduler) { - ROVER_ERROR("Error - Rover::execute: Execute called before adding a dataset"); + ASCENT_LOG_ERROR("Error - Rover::execute: Execute called before adding a dataset"); } // Applies the user-supplied parameters and then begins the ray trace diff --git a/src/libs/rover/typed_scheduler.cpp b/src/libs/rover/typed_scheduler.cpp index 24ec4e29b..347f19435 100644 --- a/src/libs/rover/typed_scheduler.cpp +++ b/src/libs/rover/typed_scheduler.cpp @@ -11,6 +11,7 @@ #include "vtkm_typedefs.hpp" #include #include +#include using namespace conduit; @@ -59,21 +60,28 @@ TypedScheduler::set_ray_generator(RayGenerator *ray_generator) template void -TypedScheduler::create_background(const int num_channels) +TypedScheduler::create_background(const int num_energy_groups) { // Initialize background intensities to 0.0f (by default) const float64 background_intensity = rover::settings["background_intensity"].to_float64(); - m_background.resize(num_channels, background_intensity); + m_background.resize(num_energy_groups, background_intensity); } template int -TypedScheduler::get_global_channels() +TypedScheduler::get_global_num_energy_groups() { - int num_channels = 1; + int num_energy_groups = 1; + int has_field_mismatch = 0; + for (auto& domain : m_domains) { - num_channels = std::max(num_channels, domain.get_num_channels()); + num_energy_groups = std::max(num_energy_groups, domain.get_num_energy_groups()); + // Check if this domain had a field mismatch + if (domain.get_field_mismatch_error()) + { + has_field_mismatch = 1; + } } #ifdef ROVER_PARALLEL @@ -81,15 +89,39 @@ TypedScheduler::get_global_channels() timer.Start(); double time = 0; (void) time; - int mpi_num_channels; - MPI_Allreduce(&num_channels, &mpi_num_channels, 1, MPI_INT, MPI_MAX, m_comm_handle); - num_channels = mpi_num_channels; + int mpi_min_energy_groups; + int mpi_max_energy_groups; + MPI_Allreduce(&num_energy_groups, &mpi_min_energy_groups, 1, MPI_INT, MPI_MIN, m_comm_handle); + MPI_Allreduce(&num_energy_groups, &mpi_max_energy_groups, 1, MPI_INT, MPI_MAX, m_comm_handle); + + // Check that all ranks have the same num_energy_groups + if (mpi_min_energy_groups != mpi_max_energy_groups) + { + ASCENT_LOG_ERROR("Error - TypedScheduler::get_global_num_energy_groups: MPI ranks have inconsistent number of energy groups. " + "Local: " << num_energy_groups << ", Global min: " << mpi_min_energy_groups << ", Global max: " << mpi_max_energy_groups); + } + + // Check that all ranks agree on field mismatch state + int global_field_mismatch = 0; + MPI_Allreduce(&has_field_mismatch, &global_field_mismatch, 1, MPI_INT, MPI_MAX, m_comm_handle); + if (global_field_mismatch) + { + ASCENT_LOG_ERROR("Error - TypedScheduler::get_global_num_energy_groups: " + "mismatched nunmber of absorption and emission fields detected on one or more ranks"); + } + time = timer.GetElapsedTime(); - ROVER_DATA_ADD("get_global_channels_all_reduce", time); + ROVER_DATA_ADD("get_global_num_energy_groups_all_reduce", time); +#else + if (has_field_mismatch) + { + ASCENT_LOG_ERROR("Error - TypedScheduler::get_global_num_energy_groups: " + "mismatched number of absorption and emission fields"); + } #endif - ROVER_INFO("Global number of channels" << num_channels); - return num_channels; + ROVER_INFO("Global number of energy groups" << num_energy_groups); + return num_energy_groups; } template @@ -248,6 +280,9 @@ TypedScheduler::typed_composite() const int num_partials = m_partial_images.size(); std::vector> partials(num_partials); +#ifdef ROVER_OPENMP_ENABLED + #pragma omp parallel for +#endif for (int i = 0; i < num_partials; ++i) { m_partial_images[i].extract_partials(partials[i]); @@ -277,6 +312,10 @@ TypedScheduler::typed_composite() int height = m_partial_images[0].m_height; std::vector>> partials; partials.resize(num_partials); + +#ifdef ROVER_OPENMP_ENABLED + #pragma omp parallel for +#endif for (int i = 0; i < num_partials; ++i) { m_partial_images[i].extract_partials(partials[i]); @@ -348,7 +387,7 @@ TypedScheduler::trace_rays() // TODO: I'm curious about which conditions can cause rays to fail to be created if (!m_ray_generator->get_rays(rays)) { - ROVER_ERROR("Failed to create new rays"); + ASCENT_LOG_ERROR("Failed to create new rays"); } ROVER_INFO("Generated " << rays.NumRays << " rays"); @@ -394,7 +433,7 @@ TypedScheduler::trace_rays() timer.Start(); time = trace_timer.GetElapsedTime(); ROVER_DATA_ADD("total_trace", time); - int num_channels = get_global_channels(); + int num_energy_groups = get_global_num_energy_groups(); vtkmTimer t1; t1.Start(); @@ -403,12 +442,12 @@ TypedScheduler::trace_rays() if (m_num_local_domains == 0 || m_partial_images.empty()) { PartialImage partial_image; - partial_image.m_transmission = vtkmRayTracing::ChannelBuffer(num_channels, 0); + partial_image.m_transmission = vtkmRayTracing::ChannelBuffer(num_energy_groups, 0); // Add an intensity buffer if the emission field is set if (m_has_emission) { - partial_image.m_intensity = vtkmRayTracing::ChannelBuffer(num_channels, 0); + partial_image.m_intensity = vtkmRayTracing::ChannelBuffer(num_energy_groups, 0); } m_partial_images.push_back(partial_image); @@ -419,7 +458,7 @@ TypedScheduler::trace_rays() if (m_background.empty()) { - create_background(num_channels); + create_background(num_energy_groups); } ROVER_DATA_ADD("default_bg", t1.GetElapsedTime()); @@ -476,9 +515,9 @@ void TypedScheduler::save_png(std::string filename) // if (m_render_settings.m_render_mode == energy) // removing volume renderer // { - const int num_channels = m_result.get_num_channels(); - ROVER_INFO("Saving " << num_channels << " channels"); - for (int i = 0; i < num_channels; ++i) + const int num_energy_groups = m_result.get_num_energy_groups(); + ROVER_INFO("Saving " << num_energy_groups << " energy groups"); + for (int i = 0; i < num_energy_groups; ++i) { std::stringstream sstream; sstream << filename << "_" << i << ".png"; @@ -527,10 +566,10 @@ void TypedScheduler::save_bov(std::string file_name) // if (m_render_settings.m_render_mode == energy) // removing volume renderer // { - const int num_channels = m_result.get_num_channels(); - ROVER_INFO("Saving bov with " << num_channels << " channels"); + const int num_energy_groups = m_result.get_num_energy_groups(); + ROVER_INFO("Saving bov with " << num_energy_groups << " energy groups"); - for (int i = 0; i < num_channels; ++i) + for (int i = 0; i < num_energy_groups; i++) { std::stringstream sstream; sstream << file_name << "_" << i << ".bov"; @@ -752,6 +791,9 @@ TypedScheduler::write_blueprint_rays_mesh(Node &data_out, scaled_unit_left = dx * vtkm::Normal(left); scaled_unit_up = dy * vtkm::Normal(up); +#ifdef ROVER_OPENMP_ENABLED + #pragma omp parallel for collapse(2) +#endif for (int j = 0; j < image_width; j++) { for (int k = 0; k < image_height; k++) @@ -806,7 +848,7 @@ TypedScheduler::to_blueprint(Node &data) const int64 image_height = rover::settings["height"].to_int64(); const double aspect_ratio = static_cast(image_width) / static_cast(image_height); - const int num_channels = m_result.get_num_channels(); + const int num_energy_groups = m_result.get_num_energy_groups(); vtkmCamera camera = m_ray_generator->get_camera(); const vtkmVec3f position = camera.GetPosition(); @@ -920,7 +962,7 @@ TypedScheduler::to_blueprint(Node &data) image_coords["values/x"].set(DataType::float64(image_width + 1)); image_coords["values/y"].set(DataType::float64(image_height + 1)); - image_coords["values/z"].set(DataType::float64(num_channels + 1)); + image_coords["values/z"].set(DataType::float64(num_energy_groups + 1)); float64_array image_coords_x = image_coords["values/x"].value(); float64_array image_coords_y = image_coords["values/y"].value(); @@ -936,7 +978,7 @@ TypedScheduler::to_blueprint(Node &data) image_coords_y[i] = i; } - for (int i = 0; i <= num_channels; i++) + for (int i = 0; i <= num_energy_groups; i++) { image_coords_z[i] = i; } @@ -1016,7 +1058,7 @@ TypedScheduler::to_blueprint(Node &data) spatial_coords["type"] = "rectilinear"; spatial_coords["values/x"].set(DataType::float64(image_width + 1)); spatial_coords["values/y"].set(DataType::float64(image_height + 1)); - spatial_coords["values/z"].set(DataType::float64(num_channels + 1)); + spatial_coords["values/z"].set(DataType::float64(num_energy_groups + 1)); float64_array spatial_coords_x = spatial_coords["values/x"].value(); float64_array spatial_coords_y = spatial_coords["values/y"].value(); @@ -1032,7 +1074,7 @@ TypedScheduler::to_blueprint(Node &data) spatial_coords_y[i] = i * spatial_dy; } - for (int i = 0; i <= num_channels; i++) + for (int i = 0; i <= num_energy_groups; i++) { spatial_coords_z[i] = i; } @@ -1133,7 +1175,7 @@ TypedScheduler::to_blueprint(Node &data) Node verify; if (!blueprint::verify("mesh", data, verify)) { - ROVER_ERROR("Error: to_blueprint failed to produce a valid conduit mesh: " << verify.to_yaml()); + ASCENT_LOG_ERROR("Error: to_blueprint failed to produce a valid conduit mesh: " << verify.to_yaml()); } } diff --git a/src/libs/rover/typed_scheduler.hpp b/src/libs/rover/typed_scheduler.hpp index 77d68d27c..d8ad9c0f1 100644 --- a/src/libs/rover/typed_scheduler.hpp +++ b/src/libs/rover/typed_scheduler.hpp @@ -94,8 +94,8 @@ class TypedScheduler : public Scheduler MPI_Comm m_comm_handle; #endif - void create_background(const int num_channels); - int get_global_channels(); + void create_background(const int num_energy_groups); + int get_global_num_energy_groups(); void set_global_range_and_bounds(); void add_partial(const vtkhRayTracing::PartialComposite &partial); void composite(); diff --git a/src/libs/vtkh/rendering/ConnectivityTracer.cpp b/src/libs/vtkh/rendering/ConnectivityTracer.cpp index 930b99cc9..e53bdaf97 100644 --- a/src/libs/vtkh/rendering/ConnectivityTracer.cpp +++ b/src/libs/vtkh/rendering/ConnectivityTracer.cpp @@ -234,7 +234,7 @@ void ConnectivityTracer::SetVolumeData(const vtkm::cont::Field& scalarField, // Absorption-only case void ConnectivityTracer::SetEnergyData(const vtkm::cont::Field& absorption, - const vtkm::Int32 numBins, + const vtkm::Int32 numEnergyGroups, const vtkm::cont::UnknownCellSet& cellSet, const vtkm::cont::CoordinateSystem& coords) { @@ -250,21 +250,13 @@ void ConnectivityTracer::SetEnergyData(const vtkm::cont::Field& absorption, Coords = coords; MeshConnIsConstructed = false; HasEmission = false; + NumEnergyGroups = numEnergyGroups; // Do some basic range checking - if (numBins < 1) - throw vtkm::cont::ErrorBadValue("Number of energy bins is less than 1"); + if (NumEnergyGroups < 1) + throw vtkm::cont::ErrorBadValue("Number of energy groups is less than 1"); vtkm::Id binCount = ScalarField.GetNumberOfValues(); vtkm::Id cellCount = this->GetNumberOfMeshCells(); - if (cellCount != (binCount / vtkm::Id(numBins))) - { - std::stringstream message; - message << "Invalid number of absorption bins\n"; - message << "Number of cells: " << cellCount << "\n"; - message << "Number of field values: " << binCount << "\n"; - message << "Number of bins: " << numBins << "\n"; - throw vtkm::cont::ErrorBadValue(message.str()); - } //TODO: Need a way to tell if we have been updated this->Integrator = Energy; @@ -283,7 +275,7 @@ void ConnectivityTracer::SetEnergyData(const vtkm::cont::Field& absorption, // Absorption + Emission case void ConnectivityTracer::SetEnergyData(const vtkm::cont::Field& absorption, - const vtkm::Int32 numBins, + const vtkm::Int32 numEnergyGroups, const vtkm::cont::UnknownCellSet& cellSet, const vtkm::cont::CoordinateSystem& coords, const vtkm::cont::Field& emission) @@ -291,11 +283,12 @@ void ConnectivityTracer::SetEnergyData(const vtkm::cont::Field& absorption, bool isSupportedField = absorption.GetAssociation() == vtkm::cont::Field::Association::Cells; if (!isSupportedField) throw vtkm::cont::ErrorBadValue("Absorption Field '" + absorption.GetName() + - "' not accociated with cells"); + "' not associated with cells"); ScalarField = absorption; CellSet = cellSet; Coords = coords; MeshConnIsConstructed = false; + NumEnergyGroups = numEnergyGroups; // Check for emission HasEmission = false; @@ -308,31 +301,13 @@ void ConnectivityTracer::SetEnergyData(const vtkm::cont::Field& absorption, EmissionField = emission; } // Do some basic range checking - if (numBins < 1) - throw vtkm::cont::ErrorBadValue("Number of energy bins is less than 1"); + if (NumEnergyGroups < 1) + throw vtkm::cont::ErrorBadValue("Number of energy groups is less than 1"); vtkm::Id binCount = ScalarField.GetNumberOfValues(); vtkm::Id cellCount = this->GetNumberOfMeshCells(); - if (cellCount != (binCount / vtkm::Id(numBins))) - { - std::stringstream message; - message << "Invalid number of absorption bins\n"; - message << "Number of cells: " << cellCount << "\n"; - message << "Number of field values: " << binCount << "\n"; - message << "Number of bins: " << numBins << "\n"; - throw vtkm::cont::ErrorBadValue(message.str()); - } if (HasEmission) { binCount = EmissionField.GetNumberOfValues(); - if (cellCount != (binCount / vtkm::Id(numBins))) - { - std::stringstream message; - message << "Invalid number of emission bins\n"; - message << "Number of cells: " << cellCount << "\n"; - message << "Number of field values: " << binCount << "\n"; - message << "Number of bins: " << numBins << "\n"; - throw vtkm::cont::ErrorBadValue(message.str()); - } } //TODO: Need a way to tell if we have been updated this->Integrator = Energy; @@ -687,13 +662,13 @@ class AddPathLengths : public vtkm::worklet::WorkletMapField class Integrate : public vtkm::worklet::WorkletMapField { private: - const vtkm::Int32 NumBins; + const vtkm::Int32 NumEnergyGroups; const vtkm::Float32 UnitScalar; public: VTKM_CONT - Integrate(const vtkm::Int32 numBins, const vtkm::Float32 unitScalar) - : NumBins(numBins) + Integrate(const vtkm::Int32 numEnergyGroups, const vtkm::Float32 unitScalar) + : NumEnergyGroups(numEnergyGroups) , UnitScalar(unitScalar) { } @@ -724,21 +699,27 @@ class Integrate : public vtkm::worklet::WorkletMapField } FloatType segmentLength = exitDistance - enterDistance; - vtkm::Id rayOffset = NumBins * rayIndex; - vtkm::Id cellOffset = NumBins * currentCell; - - for (vtkm::Int32 i = 0; i < NumBins; i++) + vtkm::Id rayOffset = NumEnergyGroups * rayIndex; + + // Get the cell value and use VecTraits to handle both scalar and vector fields + using AbsValueType = typename CellDataPortalType::ValueType; + using AbsVecTraits = vtkm::VecTraits; + + BOUNDS_CHECK(absorbtionData, currentCell); + AbsValueType absorptionCell = absorbtionData.Get(currentCell); + + // Use VecTraits for uniform handling - dispatcher ensures we get the right array type + for (vtkm::Int32 i = 0; i < NumEnergyGroups; i++) { - const int cellOffsetI = cellOffset + i; - BOUNDS_CHECK(absorbtionData, cellOffsetI); - FloatType absorb = static_cast(absorbtionData.Get(cellOffsetI)); + FloatType absorb = static_cast(AbsVecTraits::GetComponent(absorptionCell, i)); absorb *= UnitScalar; const int rayOffsetI = rayOffset + i; BOUNDS_CHECK(opticalDepthBins, rayOffsetI); - FloatType opticalDepth = static_cast(opticalDepthBins.Get(rayOffsetI)); + FloatType opticalDepth = static_cast(opticalDepthBins.Get(rayOffsetI)); opticalDepthBins.Set(rayOffsetI, opticalDepth + absorb * segmentLength); } + currentDistance = exitDistance; } }; @@ -746,16 +727,16 @@ class Integrate : public vtkm::worklet::WorkletMapField class IntegrateEmission : public vtkm::worklet::WorkletMapField { private: - const vtkm::Int32 NumBins; + const vtkm::Int32 NumEnergyGroups; const vtkm::Float32 UnitScalar; bool DivideEmisByAbsorb; public: VTKM_CONT - IntegrateEmission(const vtkm::Int32 numBins, + IntegrateEmission(const vtkm::Int32 numEnergyGroups, const vtkm::Float32 unitScalar, const bool divideEmisByAbsorb) - : NumBins(numBins) + : NumEnergyGroups(numEnergyGroups) , UnitScalar(unitScalar) , DivideEmisByAbsorb(divideEmisByAbsorb) { @@ -796,9 +777,19 @@ class IntegrateEmission : public vtkm::worklet::WorkletMapField } FloatType segmentLength = exitDistance - enterDistance; - vtkm::Id rayOffset = NumBins * rayIndex; - vtkm::Id cellOffset = NumBins * currentCell; - + vtkm::Id rayOffset = NumEnergyGroups * rayIndex; + + // Get the cell values to determine if we have vector or scalar fields + using AbsValueType = typename CellAbsPortalType::ValueType; + using EmisValueType = typename CellEmisPortalType::ValueType; + using AbsVecTraits = vtkm::VecTraits; + using EmisVecTraits = vtkm::VecTraits; + + BOUNDS_CHECK(absorptionData, currentCell); + AbsValueType absorptionCell = absorptionData.Get(currentCell); + BOUNDS_CHECK(emissionData, currentCell); + EmisValueType emissionCell = emissionData.Get(currentCell); + // // Traditionally, we would only keep track of a single intensity value per ray // per bin and we would integrate from the beginning to end of the ray. In a @@ -812,23 +803,20 @@ class IntegrateEmission : public vtkm::worklet::WorkletMapField // energy that escapes. // - // NumBins can potentially be a very large number, so the loops are duplicated + // NumEnergyGroups can potentially be a very large number, so the loops are duplicated // like this to avoid checking if DivideEmisByAbsorb == true each iteration. if (DivideEmisByAbsorb) { - for (vtkm::Int32 i = 0; i < NumBins; i++) + for (vtkm::Int32 i = 0; i < NumEnergyGroups; i++) { - const int cellOffsetI = cellOffset + i; - BOUNDS_CHECK(absorptionData, cellOffsetI); - FloatType absorb = static_cast(absorptionData.Get(cellOffsetI)); - BOUNDS_CHECK(emissionData, cellOffsetI); - FloatType emission = static_cast(emissionData.Get(cellOffsetI)); - + FloatType absorb = static_cast(AbsVecTraits::GetComponent(absorptionCell, i)); + FloatType emission = static_cast(EmisVecTraits::GetComponent(emissionCell, i)); + absorb *= UnitScalar; emission *= UnitScalar; FloatType tmp = vtkm::Exp(-absorb * segmentLength); - + const int rayOffsetI = rayOffset + i; BOUNDS_CHECK(absorptionBins, rayOffsetI); FloatType absorbIntensity = static_cast(absorptionBins.Get(rayOffsetI)); @@ -836,7 +824,7 @@ class IntegrateEmission : public vtkm::worklet::WorkletMapField FloatType emissionIntensity = static_cast(emissionBins.Get(rayOffsetI)); BOUNDS_CHECK(opticalDepthBins, rayOffsetI); FloatType opticalDepth = static_cast(opticalDepthBins.Get(rayOffsetI)); - + absorptionBins.Set(rayOffsetI, absorbIntensity * tmp); // The only difference with this loop vs the other is that we do (emission / absorb) here. emissionBins.Set(rayOffsetI, emissionIntensity * tmp + (emission / absorb) * (1.0f - tmp)); @@ -845,18 +833,15 @@ class IntegrateEmission : public vtkm::worklet::WorkletMapField } else // (!DivideEmisByAbsorb) { - for (vtkm::Int32 i = 0; i < NumBins; i++) + for (vtkm::Int32 i = 0; i < NumEnergyGroups; i++) { - const int cellOffsetI = cellOffset + i; - BOUNDS_CHECK(absorptionData, cellOffsetI); - FloatType absorb = static_cast(absorptionData.Get(cellOffsetI)); - BOUNDS_CHECK(emissionData, cellOffsetI); - FloatType emission = static_cast(emissionData.Get(cellOffsetI)); - + FloatType absorb = static_cast(AbsVecTraits::GetComponent(absorptionCell, i)); + FloatType emission = static_cast(EmisVecTraits::GetComponent(emissionCell, i)); + absorb *= UnitScalar; emission *= UnitScalar; FloatType tmp = vtkm::Exp(-absorb * segmentLength); - + const int rayOffsetI = rayOffset + i; BOUNDS_CHECK(absorptionBins, rayOffsetI); FloatType absorbIntensity = static_cast(absorptionBins.Get(rayOffsetI)); @@ -864,7 +849,7 @@ class IntegrateEmission : public vtkm::worklet::WorkletMapField FloatType emissionIntensity = static_cast(emissionBins.Get(rayOffsetI)); BOUNDS_CHECK(opticalDepthBins, rayOffsetI); FloatType opticalDepth = static_cast(opticalDepthBins.Get(rayOffsetI)); - + absorptionBins.Set(rayOffsetI, absorbIntensity * tmp); // Here we just use emission directly emissionBins.Set(rayOffsetI, emissionIntensity * tmp + emission * (1.0f - tmp)); @@ -1345,15 +1330,15 @@ void ConnectivityTracer::IntegrateCells(vtkm::rendering::raytracing::Ray absorption = rays.Buffers.at(0).Buffer; vtkm::cont::ArrayHandle emission = rays.GetBuffer("emission").Buffer; - vtkm::worklet::DispatcherMapField dispatcher(IntegrateEmission(rays.Buffers.at(0).GetNumChannels(), - UnitScalar, - DivideEmisByAbsorb)); + vtkm::worklet::DispatcherMapField dispatcher(IntegrateEmission(NumEnergyGroups, + UnitScalar, + DivideEmisByAbsorb)); dispatcher.Invoke(rays.Status, *(tracker.EnterDist), *(tracker.ExitDist), rays.Distance, - vtkm::rendering::raytracing::GetScalarFieldArray(ScalarField), - vtkm::rendering::raytracing::GetScalarFieldArray(EmissionField), + ScalarField.GetData(), + EmissionField.GetData(), absorption, emission, optical_depth, @@ -1361,13 +1346,12 @@ void ConnectivityTracer::IntegrateCells(vtkm::rendering::raytracing::Ray dispatcher(Integrate(rays.Buffers.at(0).GetNumChannels(), - UnitScalar)); + vtkm::worklet::DispatcherMapField dispatcher(Integrate(NumEnergyGroups, UnitScalar)); dispatcher.Invoke(rays.Status, *(tracker.EnterDist), *(tracker.ExitDist), rays.Distance, - vtkm::rendering::raytracing::GetScalarFieldArray(ScalarField), + ScalarField.GetData(), optical_depth, rays.HitIdx); } diff --git a/src/libs/vtkh/rendering/ConnectivityTracer.hpp b/src/libs/vtkh/rendering/ConnectivityTracer.hpp index e120d2136..560777a8d 100644 --- a/src/libs/vtkh/rendering/ConnectivityTracer.hpp +++ b/src/libs/vtkh/rendering/ConnectivityTracer.hpp @@ -84,6 +84,7 @@ class VTKH_API ConnectivityTracer , BumpEpsilon(1e-3) , CountRayStatus(false) , UnitScalar(1.f) + , NumEnergyGroups(1) { } @@ -226,6 +227,7 @@ class VTKH_API ConnectivityTracer bool FieldAssocPoints; bool HasEmission; // Mode for integrating through energy bins bool DivideEmisByAbsorb; + vtkm::Int32 NumEnergyGroups; // timers vtkm::Float64 IntersectTime; diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_absorption_only_optical_depth_000100.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_absorption_only_optical_depth_000100.png index fa9eb408b..b36027e9e 100644 Binary files a/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_absorption_only_optical_depth_000100.png and b/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_absorption_only_optical_depth_000100.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_absorption_only_optical_depth_spatial_000100.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_absorption_only_optical_depth_spatial_000100.png index 4e3ade1f3..d536ecc3a 100644 Binary files a/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_absorption_only_optical_depth_spatial_000100.png and b/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_absorption_only_optical_depth_spatial_000100.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_optical_depth_000100.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_optical_depth_000100.png index 4e7268387..b36027e9e 100644 Binary files a/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_optical_depth_000100.png and b/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_optical_depth_000100.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_uniform_multi_domain_intensities_spatial_000000.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_uniform_multi_domain_intensities_spatial_000000.png index 8ec37c6cb..d8ebe3c8b 100644 Binary files a/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_uniform_multi_domain_intensities_spatial_000000.png and b/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_uniform_multi_domain_intensities_spatial_000000.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_uniform_multi_domain_rotated_intensities_spatial_000000.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_uniform_multi_domain_rotated_intensities_spatial_000000.png index 9495036e8..233e0ae37 100644 Binary files a/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_uniform_multi_domain_rotated_intensities_spatial_000000.png and b/src/tests/_baseline_images/tout_rover_xray_blueprint_braid_uniform_multi_domain_rotated_intensities_spatial_000000.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_curv3d_rotated_intensities_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_curv3d_rotated_intensities_000048.png index e7aff09bd..da47a615d 100644 Binary files a/src/tests/_baseline_images/tout_rover_xray_blueprint_curv3d_rotated_intensities_000048.png and b/src/tests/_baseline_images/tout_rover_xray_blueprint_curv3d_rotated_intensities_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multi_curv3d_optical_depth_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multi_curv3d_optical_depth_000048.png index 3b9c08165..ee1c11ec0 100644 Binary files a/src/tests/_baseline_images/tout_rover_xray_blueprint_multi_curv3d_optical_depth_000048.png and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multi_curv3d_optical_depth_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multi_curv3d_rotated_intensities_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multi_curv3d_rotated_intensities_000048.png index 8753ebb05..10aaef89c 100644 Binary files a/src/tests/_baseline_images/tout_rover_xray_blueprint_multi_curv3d_rotated_intensities_000048.png and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multi_curv3d_rotated_intensities_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_full_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_full_000048.png new file mode 100644 index 000000000..465904c25 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_full_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_spatial_full_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_spatial_full_000048.png new file mode 100644 index 000000000..a0d60e709 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_spatial_full_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_spatial_z0_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_spatial_z0_000048.png new file mode 100644 index 000000000..9af3061f4 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_spatial_z0_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_spatial_z1_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_spatial_z1_000048.png new file mode 100644 index 000000000..1c05e8192 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_spatial_z1_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_spatial_z2_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_spatial_z2_000048.png new file mode 100644 index 000000000..2f73495f8 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_spatial_z2_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_z0_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_z0_000048.png new file mode 100644 index 000000000..9a7803160 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_z0_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_z1_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_z1_000048.png new file mode 100644 index 000000000..dcbf4ef20 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_z1_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_z2_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_z2_000048.png new file mode 100644 index 000000000..2ec0c5d52 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_absorption_only_optical_depth_z2_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_full_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_full_000048.png new file mode 100644 index 000000000..159fd69ba Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_full_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_spatial_full_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_spatial_full_000048.png new file mode 100644 index 000000000..52b4b442f Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_spatial_full_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_spatial_z0_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_spatial_z0_000048.png new file mode 100644 index 000000000..cab0b4296 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_spatial_z0_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_spatial_z1_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_spatial_z1_000048.png new file mode 100644 index 000000000..a40f6e6a9 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_spatial_z1_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_spatial_z2_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_spatial_z2_000048.png new file mode 100644 index 000000000..27ee4b191 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_spatial_z2_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_z0_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_z0_000048.png new file mode 100644 index 000000000..3bb7f6b3a Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_z0_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_z1_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_z1_000048.png new file mode 100644 index 000000000..0321bafae Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_z1_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_z2_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_z2_000048.png new file mode 100644 index 000000000..7445e3474 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_intensities_z2_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_full_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_full_000048.png new file mode 100644 index 000000000..465904c25 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_full_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_spatial_full_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_spatial_full_000048.png new file mode 100644 index 000000000..1a2114fee Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_spatial_full_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_spatial_z0_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_spatial_z0_000048.png new file mode 100644 index 000000000..496027741 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_spatial_z0_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_spatial_z1_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_spatial_z1_000048.png new file mode 100644 index 000000000..094106d6e Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_spatial_z1_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_spatial_z2_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_spatial_z2_000048.png new file mode 100644 index 000000000..3f7c9cd4e Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_spatial_z2_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_z0_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_z0_000048.png new file mode 100644 index 000000000..c4857c944 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_z0_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_z1_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_z1_000048.png new file mode 100644 index 000000000..46e4d1d64 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_z1_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_z2_000048.png b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_z2_000048.png new file mode 100644 index 000000000..eda1657b8 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_blueprint_multiple_groups_optical_depth_z2_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_braid_uniform_multi_domain_optical_depth_000000.png b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_braid_uniform_multi_domain_optical_depth_000000.png index 78d2f55dc..8b220fd7a 100644 Binary files a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_braid_uniform_multi_domain_optical_depth_000000.png and b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_braid_uniform_multi_domain_optical_depth_000000.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_braid_uniform_multi_domain_rotated_intensities_spatial_000000.png b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_braid_uniform_multi_domain_rotated_intensities_spatial_000000.png index f194b131b..9495036e8 100644 Binary files a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_braid_uniform_multi_domain_rotated_intensities_spatial_000000.png and b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_braid_uniform_multi_domain_rotated_intensities_spatial_000000.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_full_000048.png b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_full_000048.png new file mode 100644 index 000000000..159fd69ba Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_full_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_spatial_full_000048.png b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_spatial_full_000048.png new file mode 100644 index 000000000..0a2d4b305 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_spatial_full_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_spatial_z0_000048.png b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_spatial_z0_000048.png new file mode 100644 index 000000000..ff5543112 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_spatial_z0_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_spatial_z1_000048.png b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_spatial_z1_000048.png new file mode 100644 index 000000000..3b05d4c98 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_spatial_z1_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_spatial_z2_000048.png b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_spatial_z2_000048.png new file mode 100644 index 000000000..344b59bdc Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_spatial_z2_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_z0_000048.png b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_z0_000048.png new file mode 100644 index 000000000..3bb7f6b3a Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_z0_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_z1_000048.png b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_z1_000048.png new file mode 100644 index 000000000..b47efe722 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_z1_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_z2_000048.png b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_z2_000048.png new file mode 100644 index 000000000..0f8902032 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_intensities_z2_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_full_000048.png b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_full_000048.png new file mode 100644 index 000000000..465904c25 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_full_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_spatial_full_000048.png b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_spatial_full_000048.png new file mode 100644 index 000000000..a0d60e709 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_spatial_full_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_spatial_z0_000048.png b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_spatial_z0_000048.png new file mode 100644 index 000000000..e1e9cd968 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_spatial_z0_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_spatial_z1_000048.png b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_spatial_z1_000048.png new file mode 100644 index 000000000..37d7a4b56 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_spatial_z1_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_spatial_z2_000048.png b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_spatial_z2_000048.png new file mode 100644 index 000000000..fc1c0c33c Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_spatial_z2_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_z0_000048.png b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_z0_000048.png new file mode 100644 index 000000000..c4857c944 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_z0_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_z1_000048.png b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_z1_000048.png new file mode 100644 index 000000000..f1c8e377e Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_z1_000048.png differ diff --git a/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_z2_000048.png b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_z2_000048.png new file mode 100644 index 000000000..24c574420 Binary files /dev/null and b/src/tests/_baseline_images/tout_rover_xray_mpi_blueprint_multiple_groups_optical_depth_z2_000048.png differ diff --git a/src/tests/ascent/rover_test_utils.hpp b/src/tests/ascent/rover_test_utils.hpp index d89d46c53..4583cffe1 100644 --- a/src/tests/ascent/rover_test_utils.hpp +++ b/src/tests/ascent/rover_test_utils.hpp @@ -45,6 +45,7 @@ execute_ascent(const Node &data, { Ascent ascent; Node ascent_opts; + ascent_opts["exceptions"] = "forward"; #ifdef ROVER_TEST_MPI_ENABLED ascent_opts["mpi_comm"] = MPI_Comm_c2f(COMM); #endif @@ -115,7 +116,7 @@ render_fields(const Node &data, add_plots["scenes"] = scenes; - // Execute all renders in a single Ascent call + // Execute all renders in a single Ascent call for better performance execute_ascent(data, actions); // Check all generated images @@ -129,6 +130,137 @@ render_fields(const Node &data, } } +//----------------------------------------------------------------------------- +inline void +render_multi_group_fields(const Node &data, + const std::string &output_path, + const int cycle = 0, + const bool render_intensities = true) +{ + int par_rank = 0; +#ifdef ROVER_TEST_MPI_ENABLED + MPI_Comm_rank(COMM, &par_rank); +#endif + const bool is_root = (0 == par_rank); + + // This is here to help identify which ascent execute is throwing an error + if (is_root) + { + ASCENT_INFO("Executing render_multi_group_fields\n"); + } + + std::vector fields { + "optical_depth", + "optical_depth_spatial" + }; + + // We won't have intensities in the absorption-only case + if (render_intensities) + { + fields.push_back("intensities"); + fields.push_back("intensities_spatial"); + } + + // Create slices at the midpoints between different z values + std::vector z_values = {0.5, 1.5, 2.5}; + + Node pipelines; + Node scenes; + Node actions; + + // Add pipelines action + Node &add_pipelines = actions.append(); + add_pipelines["action"] = "add_pipelines"; + + // Add scenes action + Node &add_scenes = actions.append(); + add_scenes["action"] = "add_scenes"; + + int counter = 1; + + // Create pipelines and scenes for all fields + for (const auto& field : fields) + { + const bool is_spatial_mesh = field.find("spatial") != std::string::npos; + + // Full topology render + std::string scene_name = "s" + std::to_string(counter); + std::string plot_name = "p" + std::to_string(counter); + std::string render_name = "r" + std::to_string(counter); + std::string full_output_path = output_path + "_" + field + "_full"; + + // Create scene with pseudocolor plot (no pipeline needed for full topology) + scenes[scene_name]["plots"][plot_name]["type"] = "pseudocolor"; + scenes[scene_name]["plots"][plot_name]["field"] = field; + scenes[scene_name]["renders"][render_name]["image_prefix"] = full_output_path; + + // Rotate and elevate 3D meshes + scenes[scene_name]["renders"][render_name]["camera/azimuth"] = 45.0; + scenes[scene_name]["renders"][render_name]["camera/elevation"] = 45.0; + + counter += 1; + + // Slice renders at different z values + for (int i = 0; i < z_values.size(); i++) + { + double z_val = z_values[i]; + std::string pipeline_name = "pl" + std::to_string(counter); + std::string scene_name = "s" + std::to_string(counter); + std::string plot_name = "p" + std::to_string(counter); + std::string render_name = "r" + std::to_string(counter); + std::string full_output_path = output_path + "_" + field + "_z" + std::to_string(i); + + // Create pipeline with slice filter + std::string topology = "image_topo"; + if (is_spatial_mesh) + { + topology = "spatial_topo"; + } + + pipelines[pipeline_name]["f1"]["type"] = "slice"; + pipelines[pipeline_name]["f1"]["params"]["topology"] = topology; + pipelines[pipeline_name]["f1"]["params"]["point"]["x"] = 0.0; + pipelines[pipeline_name]["f1"]["params"]["point"]["y"] = 0.0; + pipelines[pipeline_name]["f1"]["params"]["point"]["z"] = z_val; + pipelines[pipeline_name]["f1"]["params"]["normal"]["x"] = 0.0; + pipelines[pipeline_name]["f1"]["params"]["normal"]["y"] = 0.0; + pipelines[pipeline_name]["f1"]["params"]["normal"]["z"] = 1.0; + + // Create scene with pseudocolor plot + scenes[scene_name]["plots"][plot_name]["type"] = "pseudocolor"; + scenes[scene_name]["plots"][plot_name]["field"] = field; + scenes[scene_name]["plots"][plot_name]["pipeline"] = pipeline_name; + scenes[scene_name]["renders"][render_name]["image_prefix"] = full_output_path; + + counter += 1; + } + } + + add_pipelines["pipelines"] = pipelines; + add_scenes["scenes"] = scenes; + + // Execute all renders in a single Ascent call for better performance + execute_ascent(data, actions); + + // Check all generated images + if (is_root) + { + for (const auto& field : fields) + { + // Full topology + std::string full_output_path = output_path + "_" + field + "_full"; + EXPECT_TRUE(check_test_image(full_output_path, 0.01f, cycle)); + + // Slices + for (int i = 0; i < z_values.size(); i++) + { + std::string full_output_path = output_path + "_" + field + "_z" + std::to_string(i); + EXPECT_TRUE(check_test_image(full_output_path, 0.01f, cycle)); + } + } + } +} + //----------------------------------------------------------------------------- inline void load_and_verify_local_data(Node &data, @@ -367,6 +499,65 @@ get_mpi_braid_multi_domain_test_data(Node &data, } #endif +//----------------------------------------------------------------------------- +inline void +get_multi_group_curv3d_data(Node &data) +{ + // Load dataset and verify blueprint + const std::string &filename = "multi_curv3d_blueprint.cycle_000048.root"; + load_and_verify_ascent_data(data, filename); + + // Build multi-group fields per domain + for (const auto &child : data.child_names()) + { + int64 num_elements = data[child]["fields/d/values"].dtype().number_of_elements(); + + // Allocate new arrays + data[child]["fields/d_multi/values/d0"].set(DataType::float32(num_elements)); + data[child]["fields/d_multi/values/d1"].set(DataType::float32(num_elements)); + data[child]["fields/d_multi/values/d2"].set(DataType::float32(num_elements)); + data[child]["fields/p_multi/values/p0"].set(DataType::float32(num_elements)); + data[child]["fields/p_multi/values/p1"].set(DataType::float32(num_elements)); + data[child]["fields/p_multi/values/p2"].set(DataType::float32(num_elements)); + + // Get array accessors + float32_array d_vals = data[child]["fields/d/values"].value(); + float32_array p_vals = data[child]["fields/p/values"].value(); + float32_array d0_vals = data[child]["fields/d_multi/values/d0"].value(); + float32_array d1_vals = data[child]["fields/d_multi/values/d1"].value(); + float32_array d2_vals = data[child]["fields/d_multi/values/d2"].value(); + float32_array p0_vals = data[child]["fields/p_multi/values/p0"].value(); + float32_array p1_vals = data[child]["fields/p_multi/values/p1"].value(); + float32_array p2_vals = data[child]["fields/p_multi/values/p2"].value(); + + // Create additional fields by scaling existing ones + for (int i = 0; i < num_elements; i++) + { + d0_vals[i] = d_vals[i]; + d1_vals[i] = d_vals[i] * 6.0f; + d2_vals[i] = d_vals[i] * 3.0f; + + p0_vals[i] = p_vals[i]; + p1_vals[i] = p_vals[i] * 6.0f; + p2_vals[i] = p_vals[i] * 3.0f; + } + + // Set topology and association for new fields + data[child]["fields/d_multi/topology"] = "mesh1"; + data[child]["fields/p_multi/topology"] = "mesh1"; + data[child]["fields/d_multi/association"] = "element"; + data[child]["fields/p_multi/association"] = "element"; + } + + // Verify test data + Node verify_info; +#ifdef ROVER_TEST_MPI_ENABLED + EXPECT_TRUE(blueprint::mpi::mesh::verify(data, verify_info, COMM)); +#else + EXPECT_TRUE(blueprint::mesh::verify(data, verify_info)); +#endif +} + //----------------------------------------------------------------------------- inline void remove_rover_test_data(const std::string &path, diff --git a/src/tests/ascent/t_ascent_mpi_rover.cpp b/src/tests/ascent/t_ascent_mpi_rover.cpp index 78571dfe4..12f4f4024 100644 --- a/src/tests/ascent/t_ascent_mpi_rover.cpp +++ b/src/tests/ascent/t_ascent_mpi_rover.cpp @@ -34,6 +34,8 @@ int par_size = 1; // MPI Rover X-Ray tests // +// TODO: Create an imaging planes and rays mesh test for MPI + //----------------------------------------------------------------------------- TEST(ascent_rover, test_xray_mpi_blueprint_braid_uniform_multi_domain) { @@ -382,6 +384,90 @@ TEST(ascent_rover, test_xray_mpi_blueprint_braid_uniform_single_domain_multiple_ } } +//----------------------------------------------------------------------------- +TEST(ascent_rover, test_xray_mpi_blueprint_multiple_groups) +{ + // Set up MPI + MPI_Comm_rank(COMM, &par_rank); + MPI_Comm_size(COMM, &par_size); + const bool is_root = (0 == par_rank); + + if (is_root) + { + ASCENT_INFO("Testing xray extract using MPI on multi-group curv3d example mesh\n"); + } + + if (is_vtkm_disabled(is_root)) + { + return; // Returning early is equivalent to passing the test + } + + // Test names + const std::string query_name = "tout_rover_xray_mpi_blueprint_multiple_groups"; + const std::string query_suffix = "_000048.cycle_000048.root"; + + // Set up paths + const std::string output_path = prepare_output_dir(); + const std::string query_path = utils::join_file_path(output_path, query_name); + const std::string output_data_path = query_path + query_suffix; + + // Remove old test data + const int cycle = 48; + remove_rover_test_data(query_path, query_suffix, cycle); + + // Generate test data for MPI + Node test_data; + get_multi_group_curv3d_data(test_data); + + // Define Ascent actions + Node extracts; + get_common_extract_params(extracts, query_path, "d_multi", "p_multi"); + + Node actions; + get_default_action_params(actions, extracts); + + // Execute Ascent actions + execute_ascent(test_data, actions); + + // Load and verify output mesh + Node xray_blueprint_output; + load_and_verify_local_data(xray_blueprint_output, output_data_path); + + // Rover's output is only single-domain, so we only use rank 0 to verify the output + if (is_root) + { + // Load and verify baseline data + Node baseline_data; + get_default_baseline(baseline_data, extracts["e1/params"], cycle); + + // Manually override the remaining fields with expected values + baseline_data["time"] = 4.80000019073486; + baseline_data["xray_view/position"] = {0.0, 2.49999904632568, 47.0156211853027}; + baseline_data["xray_view/look_at"] = {0.0, 2.49999904632568, 15.0}; + baseline_data["xray_view/near_plane"] = 3.20156216621399; + baseline_data["xray_view/far_plane"] = 320.156219482422; + baseline_data["xray_data/detector_width"] = 3.69684552235394; + baseline_data["xray_data/detector_height"] = 3.69684552235394; + baseline_data["xray_data/intensity_max"] = 2.94868206977844; + baseline_data["xray_data/optical_depth_max"] = 752.98779296875; + + // Diff the baseline data with our new output + const Node &state_output = xray_blueprint_output["domain_000000/state"]; + check_blueprint_diff(baseline_data, state_output); + } + + // Render and verify each field for multi-group data + render_multi_group_fields(xray_blueprint_output, query_path, cycle); + + // We only want to dump info if we are rank 0 + if (is_root) + { + // Dump info + const std::string msg = "Rendered XRay diagnostic images using MPI on an example multi-group curv3d mesh"; + ASCENT_ACTIONS_DUMP(actions, query_path, msg); + } +} + //----------------------------------------------------------------------------- int main(int argc, char* argv[]) { diff --git a/src/tests/ascent/t_ascent_rover.cpp b/src/tests/ascent/t_ascent_rover.cpp old mode 100644 new mode 100755 index d2dd1bda3..8250b9e8f --- a/src/tests/ascent/t_ascent_rover.cpp +++ b/src/tests/ascent/t_ascent_rover.cpp @@ -28,6 +28,8 @@ using namespace ascent; // Rover X-Ray tests // +// TODO: Create an imaging planes and rays mesh test + //----------------------------------------------------------------------------- TEST(ascent_rover, test_xray_blueprint_braid) { @@ -762,7 +764,189 @@ TEST(ascent_rover, test_xray_blueprint_curv3d_camera_params) ASCENT_ACTIONS_DUMP(actions, query_path, msg); } -// TODO: Add a test for imaging planes and the rays mesh +//----------------------------------------------------------------------------- +TEST(ascent_rover, test_xray_blueprint_multiple_groups) +{ + ASCENT_INFO("Testing xray extract on multi-group curv3d example mesh\n"); + + if (is_vtkm_disabled()) + { + return; // Returning early is equivalent to passing the test + } + + // Test names + const std::string query_name = "tout_rover_xray_blueprint_multiple_groups"; + const std::string query_suffix = "_000048.cycle_000048.root"; + + // Set up paths + const std::string output_path = prepare_output_dir(); + const std::string query_path = utils::join_file_path(output_path, query_name); + const std::string output_data_path = query_path + query_suffix; + + // Remove old test data + const int cycle = 48; + remove_rover_test_data(query_path, query_suffix, cycle); + + // Generate and verify test data + Node test_data; + get_multi_group_curv3d_data(test_data); + + // Define Ascent actions + Node extracts; + get_common_extract_params(extracts, query_path, "d_multi", "p_multi"); + + Node actions; + get_default_action_params(actions, extracts); + + // Execute Ascent actions + execute_ascent(test_data, actions); + + // Load and verify output mesh + Node xray_blueprint_output, verify_info; + load_and_verify_local_data(xray_blueprint_output, output_data_path); + + // Load and verify baseline data + Node baseline_data; + get_default_baseline(baseline_data, extracts["e1/params"], cycle); + + // Manually override the remaining fields with expected values + baseline_data["time"] = 4.80000019073486; + baseline_data["xray_view/position"] = {0.0, 2.49999904632568, 47.0156211853027}; + baseline_data["xray_view/look_at"] = {0.0, 2.49999904632568, 15.0}; + baseline_data["xray_view/near_plane"] = 3.20156216621399; + baseline_data["xray_view/far_plane"] = 320.156219482422; + baseline_data["xray_data/detector_width"] = 3.69684552235394; + baseline_data["xray_data/detector_height"] = 3.69684552235394; + baseline_data["xray_data/intensity_max"] = 2.94868206977844; + baseline_data["xray_data/optical_depth_max"] = 752.98779296875; + + // Diff the baseline data with our new output + const Node &state_output = xray_blueprint_output["domain_000000/state"]; + check_blueprint_diff(baseline_data, state_output); + + // Render and verify each field + render_multi_group_fields(xray_blueprint_output, query_path, cycle); + + // Dump info + const std::string msg = "Rendered XRay diagnostic images of an example multi-group curv3d mesh"; + ASCENT_ACTIONS_DUMP(actions, query_path, msg); +} + +//----------------------------------------------------------------------------- +TEST(ascent_rover, test_xray_blueprint_multiple_groups_absorption_only) +{ + ASCENT_INFO("Testing xray extract on multi-group curv3d example mesh (absorption only)\n"); + + if (is_vtkm_disabled()) + { + return; // Returning early is equivalent to passing the test + } + + // Test names + const std::string query_name = "tout_rover_xray_blueprint_multiple_groups_absorption_only"; + const std::string query_suffix = "_000048.cycle_000048.root"; + + // Set up paths + const std::string output_path = prepare_output_dir(); + const std::string query_path = utils::join_file_path(output_path, query_name); + const std::string output_data_path = query_path + query_suffix; + + // Remove old test data + const int cycle = 48; + remove_rover_test_data(query_path, query_suffix, cycle); + + // Generate and verify test data + Node test_data; + get_multi_group_curv3d_data(test_data); + + // Define Ascent actions (absorption only, no emission) + Node extracts; + get_common_extract_params(extracts, query_path, "d_multi", ""); + + Node actions; + get_default_action_params(actions, extracts); + + // Execute Ascent actions + execute_ascent(test_data, actions); + + // Load and verify output mesh + Node xray_blueprint_output, verify_info; + load_and_verify_local_data(xray_blueprint_output, output_data_path); + + // Load and verify baseline data + Node baseline_data; + get_default_baseline(baseline_data, extracts["e1/params"], cycle); + + // Manually override the remaining fields with expected values + baseline_data["time"] = 4.80000019073486; + baseline_data["xray_view/position"] = {0.0, 2.49999904632568, 47.0156211853027}; + baseline_data["xray_view/look_at"] = {0.0, 2.49999904632568, 15.0}; + baseline_data["xray_view/near_plane"] = 3.20156216621399; + baseline_data["xray_view/far_plane"] = 320.156219482422; + baseline_data["xray_data/detector_width"] = 3.69684552235394; + baseline_data["xray_data/detector_height"] = 3.69684552235394; + baseline_data["xray_data/optical_depth_max"] = 752.98779296875; + + // Diff the baseline data with our new output + const Node &state_output = xray_blueprint_output["domain_000000/state"]; + check_blueprint_diff(baseline_data, state_output); + + // Render and verify each field + const bool render_intensities = false; + render_multi_group_fields(xray_blueprint_output, query_path, cycle, render_intensities); + + // Dump info + const std::string msg = "Rendered XRay diagnostic images of an example multi-group curv3d mesh (absorption only)"; + ASCENT_ACTIONS_DUMP(actions, query_path, msg); +} + +//----------------------------------------------------------------------------- +TEST(ascent_rover, test_xray_blueprint_multiple_groups_mismatched) +{ + ASCENT_INFO("Testing xray extract on multi-group curv3d example mesh (mismatched number of fields)\n"); + + if (is_vtkm_disabled()) + { + return; // Returning early is equivalent to passing the test + } + + // Test names + const std::string query_name = "tout_rover_xray_blueprint_multiple_groups_mismatched"; + const std::string query_suffix = "_000048.cycle_000048.root"; + + // Set up paths + const std::string output_path = prepare_output_dir(); + const std::string query_path = utils::join_file_path(output_path, query_name); + const std::string output_data_path = query_path + query_suffix; + + // Remove old test data + const int cycle = 48; + remove_rover_test_data(query_path, query_suffix, cycle); + + // Generate and verify test data + Node test_data; + get_multi_group_curv3d_data(test_data); + + // Create mismatched fields by removing one component from emission field + for (const auto &child : test_data.child_names()) + { + test_data[child]["fields/p_multi/values"].remove("p2"); + } + + // Define Ascent actions + Node extracts; + get_common_extract_params(extracts, query_path, "d_multi", "p_multi"); + + Node actions; + get_default_action_params(actions, extracts); + + // Execute Ascent actions + EXPECT_THROW(execute_ascent(test_data, actions), conduit::Error); + + // Dump info + const std::string msg = "Expected failure for XRay with mismatched number of field components"; + ASCENT_ACTIONS_DUMP(actions, query_path, msg); +} //----------------------------------------------------------------------------- TEST(ascent_rover, test_xray_blueprint_multi_curv3d)