diff --git a/src/Frame/Frame.cc b/src/Frame/Frame.cc index 646a3699a..b85aa25f6 100644 --- a/src/Frame/Frame.cc +++ b/src/Frame/Frame.cc @@ -85,6 +85,10 @@ Frame::Frame(uint32_t session_id, std::shared_ptr loader, const std: _depth = (_z_axis >= 0 ? _image_shape(_z_axis) : 1); _num_stokes = (_stokes_axis >= 0 ? _image_shape(_stokes_axis) : 1); + _all_x = AxisRange(0, _width - 1); + _all_y = AxisRange(0, _height - 1); + _all_z = AxisRange(0, _depth - 1); + _use_tile_cache = _loader->UseTileCache(); // load full image cache for loaders that don't use the tile cache and mipmaps @@ -207,7 +211,7 @@ bool Frame::GetBeams(std::vector& beams) { } StokesSlicer Frame::GetImageSlicer(const AxisRange& z_range, int stokes) { - return GetImageSlicer(AxisRange(ALL_X), AxisRange(ALL_Y), z_range, stokes); + return GetImageSlicer(_all_x, _all_y, z_range, stokes); } StokesSlicer Frame::GetImageSlicer(const AxisRange& x_range, const AxisRange& y_range, const AxisRange& z_range, int stokes) { @@ -226,13 +230,6 @@ StokesSlicer Frame::GetImageSlicer(const AxisRange& x_range, const AxisRange& y_ int start_x(x_range.from), end_x(x_range.to); // Normalize x constants - if (start_x == ALL_X) { - start_x = 0; - } - if (end_x == ALL_X) { - end_x = _width - 1; - } - if (stokes_source.IsOriginalImage()) { start(_x_axis) = start_x; end(_x_axis) = end_x; @@ -247,13 +244,6 @@ StokesSlicer Frame::GetImageSlicer(const AxisRange& x_range, const AxisRange& y_ int start_y(y_range.from), end_y(y_range.to); // Normalize y constants - if (start_y == ALL_Y) { - start_y = 0; - } - if (end_y == ALL_Y) { - end_y = _height - 1; - } - if (stokes_source.IsOriginalImage()) { start(_y_axis) = start_y; end(_y_axis) = end_y; @@ -313,7 +303,7 @@ bool Frame::CheckZ(int z) { } bool Frame::CheckStokes(int stokes) { - return (((stokes >= 0) && (stokes < NumStokes())) || IsComputedStokes(stokes)); + return (((stokes >= 0) && (stokes < NumStokes())) || Stokes::IsComputed(stokes)); } bool Frame::ZStokesChanged(int z, int stokes) { @@ -349,7 +339,7 @@ bool Frame::SetImageChannels(int new_z, int new_stokes, std::string& message) { _z_index = new_z; _stokes_index = new_stokes; - if (!(_use_tile_cache && _loader->HasMip(2)) || IsComputedStokes(_stokes_index)) { + if (!(_use_tile_cache && _loader->HasMip(2)) || Stokes::IsComputed(_stokes_index)) { // Reload the full channel cache for loaders which use it FillImageCache(); } else { @@ -582,7 +572,7 @@ bool Frame::GetRasterTileData(std::shared_ptr>& tile_data_ptr tile_data_ptr = _tile_pool->Pull(); bool loaded_data(0); - if (mip > 1 && !IsComputedStokes(_stokes_index)) { + if (mip > 1 && !Stokes::IsComputed(_stokes_index)) { // Try to load downsampled data from the image file loaded_data = _loader->GetDownsampledRasterData(*tile_data_ptr, _z_index, _stokes_index, bounds, mip, _image_mutex); } else if (!_image_cache_valid && _use_tile_cache) { @@ -1159,7 +1149,7 @@ bool Frame::FillSpatialProfileData(PointXy point, std::vector= 2); - if (downsample && _loader->HasMip(2) && !IsComputedStokes(stokes)) { // Use a mipmap dataset to return downsampled data + if (downsample && _loader->HasMip(2) && !Stokes::IsComputed(stokes)) { // Use a mipmap dataset to return downsampled data while (!_loader->HasMip(mip)) { mip /= 2; } @@ -1447,8 +1437,8 @@ bool Frame::FillSpectralProfileData(std::function spectral_data; int xy_count(1); - if (!IsComputedStokes(stokes) && _loader->GetCursorSpectralData(spectral_data, stokes, (start_cursor.x + 0.5), xy_count, - (start_cursor.y + 0.5), xy_count, _image_mutex)) { + if (!Stokes::IsComputed(stokes) && _loader->GetCursorSpectralData(spectral_data, stokes, (start_cursor.x + 0.5), xy_count, + (start_cursor.y + 0.5), xy_count, _image_mutex)) { // Use loader data spectral_profile->set_raw_values_fp32(spectral_data.data(), spectral_data.size() * sizeof(float)); cb(profile_message); @@ -2329,60 +2319,61 @@ casacore::Slicer Frame::GetExportRegionSlicer(const CARTA::SaveFile& save_file_m bool Frame::GetStokesTypeIndex(const string& coordinate, int& stokes_index) { // Coordinate could be profile (x, y, z), stokes string (I, Q, U), or combination (Ix, Qy) - bool is_stokes_string = StokesStringTypes.find(coordinate) != StokesStringTypes.end(); - bool is_combination = (coordinate.size() > 1 && (coordinate.back() == 'x' || coordinate.back() == 'y' || coordinate.back() == 'z')); - if (is_combination || is_stokes_string) { - bool stokes_ok(false); + if (coordinate.empty() || coordinate == 'x' || coordinate == 'y' || coordinate == 'z') { + // Profile only or blank; use current Stokes + stokes_index = CurrentStokes(); + return true; + } + + std::string stokes_string; + if (coordinate.size() > 1 && (coordinate.back() == 'x' || coordinate.back() == 'y' || coordinate.back() == 'z')) { + // Combination Stokes and profile string + stokes_string = coordinate.substr(0, coordinate.size() - 1); + } else { + // Stokes string + stokes_string = coordinate; + } + + bool stokes_ok(false); - std::string stokes_string; - if (is_stokes_string) { - stokes_string = coordinate; + auto stokes_type = Stokes::Get(stokes_string); + if (stokes_type) { + if (_loader->GetStokesTypeIndex(stokes_type, stokes_index)) { + stokes_ok = true; + } else if (Stokes::IsComputed(stokes_type)) { + stokes_index = stokes_type; + stokes_ok = true; } else { - stokes_string = coordinate.substr(0, coordinate.size() - 1); - } - - if (StokesStringTypes.count(stokes_string)) { - CARTA::PolarizationType stokes_type = StokesStringTypes[stokes_string]; - if (_loader->GetStokesTypeIndex(stokes_type, stokes_index)) { - stokes_ok = true; - } else if (IsComputedStokes(stokes_string)) { - stokes_index = StokesStringTypes.at(stokes_string); + int assumed_stokes_index = (stokes_type - 1) % 4; + if (NumStokes() > assumed_stokes_index) { + stokes_index = assumed_stokes_index; stokes_ok = true; - } else { - int assumed_stokes_index = (StokesValues[stokes_type] - 1) % 4; - if (NumStokes() > assumed_stokes_index) { - stokes_index = assumed_stokes_index; - stokes_ok = true; - spdlog::warn("Can not get stokes index from the header. Assuming stokes {} index is {}.", stokes_string, stokes_index); - } + spdlog::warn("Can not get stokes index from the header. Assuming stokes {} index is {}.", stokes_string, stokes_index); } } - if (!stokes_ok) { - spdlog::error("Spectral or spatial requirement {} failed: invalid stokes axis for image.", coordinate); - return false; - } - } else { - stokes_index = CurrentStokes(); // current stokes } + + if (!stokes_ok) { + spdlog::error("Spectral or spatial requirement {} failed: invalid stokes axis for image.", coordinate); + return false; + } + return true; } std::string Frame::GetStokesType(int stokes_index) { - for (auto stokes_type : StokesStringTypes) { - int tmp_stokes_index; - if (_loader->GetStokesTypeIndex(stokes_type.second, tmp_stokes_index) && (tmp_stokes_index == stokes_index)) { - std::string stokes = (stokes_type.first.length() == 1) ? fmt::format("Stokes {}", stokes_type.first) : stokes_type.first; - return stokes; - } - } - if (IsComputedStokes(stokes_index)) { - CARTA::PolarizationType stokes_type = StokesTypes[stokes_index]; - if (ComputedStokesName.count(stokes_type)) { - return ComputedStokesName[stokes_type]; - } + auto stokes_type = CARTA::PolarizationType::POLARIZATION_TYPE_NONE; + + // Computed stokes: stokes index is equal to numeric value + if (Stokes::IsComputed(stokes_index)) { + stokes_type = Stokes::Get(stokes_index); } - return "Unknown"; + + // Otherwise try to map index to type with loader + _loader->GetStokesType(stokes_index, stokes_type); + + return Stokes::Description(stokes_type); } std::shared_mutex& Frame::GetActiveTaskMutex() { diff --git a/src/Frame/Frame.h b/src/Frame/Frame.h index 7927947d4..55c1ec403 100644 --- a/src/Frame/Frame.h +++ b/src/Frame/Frame.h @@ -75,12 +75,6 @@ static std::unordered_map FileTypeString{{CARTA::FileTy {CARTA::FileType::DS9_REG, "DS9"}, {CARTA::FileType::FITS, "FITS"}, {CARTA::FileType::HDF5, "HDF5"}, {CARTA::FileType::MIRIAD, "MIRIAD"}, {CARTA::FileType::UNKNOWN, "Unknown"}}; -static std::unordered_map ComputedStokesName{ - {CARTA::PolarizationType::Ptotal, "Total polarization intensity"}, {CARTA::PolarizationType::Plinear, "Linear polarization intensity"}, - {CARTA::PolarizationType::PFtotal, "Fractional total polarization intensity"}, - {CARTA::PolarizationType::PFlinear, "Fractional linear polarization intensity"}, - {CARTA::PolarizationType::Pangle, "Polarization angle"}}; - class Frame { public: // Load image cache for default_z, except for PV preview image which needs cube @@ -286,6 +280,7 @@ class Frame { int _spectral_axis, _stokes_axis; int _z_index, _stokes_index; // current index size_t _width, _height, _depth, _num_stokes; + AxisRange _all_x, _all_y, _all_z; // Image settings CARTA::AddRequiredTiles _required_animation_tiles; diff --git a/src/ImageData/FileInfo.h b/src/ImageData/FileInfo.h index e57c4a7b6..4969cb730 100644 --- a/src/ImageData/FileInfo.h +++ b/src/ImageData/FileInfo.h @@ -14,7 +14,6 @@ #include #include -//#include namespace carta { namespace FileInfo { @@ -122,19 +121,6 @@ inline casacore::uInt GetFitsHdu(const std::string& hdu) { return hdu_num; } -// convert between CARTA::PolarizationType values and FITS standard stokes values -static bool ConvertFitsStokesValue(const int& in_stokes_value, int& out_stokes_value) { - if (in_stokes_value >= 1 && in_stokes_value <= 4) { - out_stokes_value = in_stokes_value; - return true; - } else if ((in_stokes_value >= 4 && in_stokes_value <= 12) || (in_stokes_value <= -1 && in_stokes_value >= -8)) { - // convert between [5, 6, ..., 12] and [-1, -2, ..., -8] - out_stokes_value = -in_stokes_value + 4; - return true; - } - return false; -} - } // namespace FileInfo } // namespace carta diff --git a/src/ImageData/FileLoader.cc b/src/ImageData/FileLoader.cc index 9bb71c73f..5c85c2c59 100644 --- a/src/ImageData/FileLoader.cc +++ b/src/ImageData/FileLoader.cc @@ -310,8 +310,10 @@ bool FileLoader::FindCoordinateAxes(casacore::IPosition& shape, std::vector for (int i = 0; i < _num_stokes; ++i) { int stokes_fits_value = _stokes_crval + (i + 1 - _stokes_crpix) * _stokes_cdelt; int stokes_value; - if (FileInfo::ConvertFitsStokesValue(stokes_fits_value, stokes_value)) { - _stokes_indices[GetStokesType(stokes_value)] = i; + if (Stokes::ConvertFits(stokes_fits_value, stokes_value)) { + auto stokes_type = static_cast(stokes_value); + _stokes_indices[stokes_type] = i; + _stokes_types[i] = stokes_type; } } } @@ -846,7 +848,7 @@ void FileLoader::LoadImageStats(bool load_percentiles) { } FileInfo::ImageStats& FileLoader::GetImageStats(int current_stokes, int z) { - if (!IsComputedStokes(current_stokes)) { // Note: loader cache does not support the computed stokes + if (!Stokes::IsComputed(current_stokes)) { // Note: loader cache does not support the computed stokes return (z >= 0 ? _z_stats[current_stokes][z] : _cube_stats[current_stokes]); } return _empty_stats; @@ -912,11 +914,21 @@ double FileLoader::CalculateBeamArea() { } bool FileLoader::GetStokesTypeIndex(const CARTA::PolarizationType& stokes_type, int& stokes_index) { - if (_stokes_indices.count(stokes_type)) { - stokes_index = _stokes_indices[stokes_type]; + try { + stokes_index = _stokes_indices.at(stokes_type); return true; + } catch (const std::out_of_range& e) { + return false; + } +} + +bool FileLoader::GetStokesType(const int& stokes_index, CARTA::PolarizationType& stokes_type) { + try { + stokes_type = _stokes_types.at(stokes_index); + return true; + } catch (const std::out_of_range& e) { + return false; } - return false; } typename FileLoader::ImageRef FileLoader::GetStokesImage(const StokesSource& stokes_source) { @@ -929,15 +941,15 @@ typename FileLoader::ImageRef FileLoader::GetStokesImage(const StokesSource& sto carta::PolarizationCalculator polarization_calculator( GetImage(), AxisRange(stokes_source.z_range), AxisRange(stokes_source.x_range), AxisRange(stokes_source.y_range)); - if (stokes_source.stokes == COMPUTE_STOKES_PTOTAL) { + if (stokes_source.stokes == CARTA::PolarizationType::Ptotal) { _computed_stokes_image = polarization_calculator.ComputeTotalPolarizedIntensity(); - } else if (stokes_source.stokes == COMPUTE_STOKES_PFTOTAL) { + } else if (stokes_source.stokes == CARTA::PolarizationType::PFtotal) { _computed_stokes_image = polarization_calculator.ComputeTotalFractionalPolarizedIntensity(); - } else if (stokes_source.stokes == COMPUTE_STOKES_PLINEAR) { + } else if (stokes_source.stokes == CARTA::PolarizationType::Plinear) { _computed_stokes_image = polarization_calculator.ComputePolarizedIntensity(); - } else if (stokes_source.stokes == COMPUTE_STOKES_PFLINEAR) { + } else if (stokes_source.stokes == CARTA::PolarizationType::PFlinear) { _computed_stokes_image = polarization_calculator.ComputeFractionalPolarizedIntensity(); - } else if (stokes_source.stokes == COMPUTE_STOKES_PANGLE) { + } else if (stokes_source.stokes == CARTA::PolarizationType::Pangle) { _computed_stokes_image = polarization_calculator.ComputePolarizedAngle(); } else { spdlog::error("Unknown computed stokes index {}", stokes_source.stokes); diff --git a/src/ImageData/FileLoader.h b/src/ImageData/FileLoader.h index 5765a5314..6551b74f3 100644 --- a/src/ImageData/FileLoader.h +++ b/src/ImageData/FileLoader.h @@ -121,6 +121,7 @@ class FileLoader { virtual void SetStokesCrpix(float stokes_crpix); virtual void SetStokesCdelt(int stokes_cdelt); virtual bool GetStokesTypeIndex(const CARTA::PolarizationType& stokes_type, int& stokes_index); + virtual bool GetStokesType(const int& stokes_index, CARTA::PolarizationType& stokes_type); std::unordered_map GetStokesIndices() { return _stokes_indices; }; @@ -180,6 +181,7 @@ class FileLoader { // Storage for the stokes type vs. stokes index std::unordered_map _stokes_indices; + std::unordered_map _stokes_types; float _stokes_crval; float _stokes_crpix; int _stokes_cdelt; diff --git a/src/ImageData/StokesFilesConnector.cc b/src/ImageData/StokesFilesConnector.cc index 845275999..e9a6607cd 100644 --- a/src/ImageData/StokesFilesConnector.cc +++ b/src/ImageData/StokesFilesConnector.cc @@ -13,14 +13,6 @@ using namespace carta; -static std::unordered_map CasaStokesTypes{ - {CARTA::PolarizationType::I, casacore::Stokes::I}, {CARTA::PolarizationType::Q, casacore::Stokes::Q}, - {CARTA::PolarizationType::U, casacore::Stokes::U}, {CARTA::PolarizationType::V, casacore::Stokes::V}, - {CARTA::PolarizationType::RR, casacore::Stokes::RR}, {CARTA::PolarizationType::LL, casacore::Stokes::LL}, - {CARTA::PolarizationType::RL, casacore::Stokes::RL}, {CARTA::PolarizationType::LR, casacore::Stokes::LR}, - {CARTA::PolarizationType::XX, casacore::Stokes::XX}, {CARTA::PolarizationType::YY, casacore::Stokes::YY}, - {CARTA::PolarizationType::XY, casacore::Stokes::XY}, {CARTA::PolarizationType::YX, casacore::Stokes::YX}}; - StokesFilesConnector::StokesFilesConnector(const std::string& _top_level_folder) : _top_level_folder(_top_level_folder) {} StokesFilesConnector::~StokesFilesConnector() { @@ -46,7 +38,7 @@ bool StokesFilesConnector::DoConcat(const CARTA::ConcatStokesFiles& message, CAR bool success(true); if (stokes_axis < 0) { // create a stokes coordinate and add it to the coordinate system - std::unordered_map>> extended_images; + std::map>> extended_images; std::unordered_map> coord_sys; CARTA::PolarizationType carta_stokes_type; @@ -95,46 +87,40 @@ bool StokesFilesConnector::DoConcat(const CARTA::ConcatStokesFiles& message, CAR // concatenate images along the stokes axis concatenated_image = std::make_shared>(stokes_axis); - for (int i = 1; i <= StokesTypes.size(); ++i) { // concatenate stokes file in the order I, Q, U, V (i.e., 1, 2, 3 ,4) - auto stokes_type = static_cast(i); - if (extended_images.count(stokes_type)) { - try { - concatenated_image->setImage(*extended_images[stokes_type], casacore::False); - } catch (const casacore::AipsError& error) { - return fail_exit(fmt::format("Failed to concatenate images: {}", error.getMesg())); - } + for (const auto& image_entry : extended_images) { // concatenate stokes file in the order I, Q, U, V (i.e., 1, 2, 3 ,4) + try { + concatenated_image->setImage(*image_entry.second, casacore::False); + } catch (const casacore::AipsError& error) { + return fail_exit(fmt::format("Failed to concatenate images: {}", error.getMesg())); } } } else { // concatenate images along the stokes axis concatenated_image = std::make_shared>(stokes_axis); - for (int i = 1; i <= StokesTypes.size(); ++i) { // concatenate stokes file in the order I, Q, U, V (i.e., 1, 2, 3 ,4) - auto stokes_type = static_cast(i); - if (_loaders.count(stokes_type)) { - auto image = _loaders[stokes_type]->GetImage(); - const casacore::CoordinateSystem& coordinates = image->coordinates(); - if (!coordinates.hasPolarizationCoordinate()) { - return fail_exit("Failed to get the stokes coordinate system!"); - } - casacore::StokesCoordinate& stokes_coord = const_cast(coordinates.stokesCoordinate()); - if (stokes_coord.stokes().size() != 1) { - return fail_exit("Stokes coordinate has no or multiple stokes types!"); - } + for (const auto& [stokes_type, loader] : _loaders) { // concatenate stokes file in the order I, Q, U, V (i.e., 1, 2, 3 ,4) + auto image = loader->GetImage(); + const casacore::CoordinateSystem& coordinates = image->coordinates(); + if (!coordinates.hasPolarizationCoordinate()) { + return fail_exit("Failed to get the stokes coordinate system!"); + } + casacore::StokesCoordinate& stokes_coord = const_cast(coordinates.stokesCoordinate()); + if (stokes_coord.stokes().size() != 1) { + return fail_exit("Stokes coordinate has no or multiple stokes types!"); + } - // set stokes type in the stokes coordinate - casacore::Vector vec(1); - casacore::Stokes::StokesTypes casa_stokes_type; + // set stokes type in the stokes coordinate + casacore::Vector vec(1); + casacore::Stokes::StokesTypes casa_stokes_type; - if (GetCasaStokesType(stokes_type, casa_stokes_type)) { - vec(0) = casa_stokes_type; - } - stokes_coord.setStokes(vec); + if (GetCasaStokesType(stokes_type, casa_stokes_type)) { + vec(0) = casa_stokes_type; + } + stokes_coord.setStokes(vec); - try { - concatenated_image->setImage(*(image.get()), casacore::False); - } catch (const casacore::AipsError& error) { - return fail_exit(fmt::format("Failed to concatenate images: {}", error.getMesg())); - } + try { + concatenated_image->setImage(*(image.get()), casacore::False); + } catch (const casacore::AipsError& error) { + return fail_exit(fmt::format("Failed to concatenate images: {}", error.getMesg())); } } } @@ -146,24 +132,21 @@ bool StokesFilesConnector::DoConcat(const CARTA::ConcatStokesFiles& message, CAR int stokes_size = concatenated_image->shape()[stokes_axis]; image_info.setAllBeams(image_info.nChannels(), stokes_size, casacore::GaussianBeam()); unsigned int stokes(0); - for (int i = 1; i <= StokesTypes.size(); ++i) { // set beam information through stokes types I, Q, U, V (i.e., 1, 2, 3 ,4) - auto stokes_type = static_cast(i); - if (_loaders.count(stokes_type)) { - if (_loaders[stokes_type]->GetImage()->imageInfo().hasBeam() && stokes < stokes_size) { - casacore::ImageBeamSet beam_set = _loaders[stokes_type]->GetImage()->imageInfo().getBeamSet(); - casacore::GaussianBeam gaussian_beam; - for (unsigned int chan = 0; chan < beam_set.nchan(); ++chan) { - gaussian_beam = beam_set.getBeam(chan, stokes); - casacore::Quantity major_ax(gaussian_beam.getMajor("arcsec"), "arcsec"); - casacore::Quantity minor_ax(gaussian_beam.getMinor("arcsec"), "arcsec"); - casacore::Quantity pa(gaussian_beam.getPA("deg").getValue(), "deg"); - image_info.setBeam(chan, stokes, major_ax, minor_ax, pa); - } - } else { - spdlog::warn("Stokes type {} has no beam information!", CARTA::PolarizationType_Name(stokes_type)); + for (const auto& [stokes_type, loader] : _loaders) { // set beam information through stokes types I, Q, U, V (i.e., 1, 2, 3 ,4) + if (loader->GetImage()->imageInfo().hasBeam() && stokes < stokes_size) { + casacore::ImageBeamSet beam_set = loader->GetImage()->imageInfo().getBeamSet(); + casacore::GaussianBeam gaussian_beam; + for (unsigned int chan = 0; chan < beam_set.nchan(); ++chan) { + gaussian_beam = beam_set.getBeam(chan, stokes); + casacore::Quantity major_ax(gaussian_beam.getMajor("arcsec"), "arcsec"); + casacore::Quantity minor_ax(gaussian_beam.getMinor("arcsec"), "arcsec"); + casacore::Quantity pa(gaussian_beam.getPA("deg").getValue(), "deg"); + image_info.setBeam(chan, stokes, major_ax, minor_ax, pa); } - ++stokes; + } else { + spdlog::warn("Stokes type {} has no beam information!", CARTA::PolarizationType_Name(stokes_type)); } + ++stokes; } concatenated_image->setImageInfo(image_info); } catch (const casacore::AipsError& error) { @@ -256,13 +239,10 @@ bool StokesFilesConnector::OpenStokesFiles(const CARTA::ConcatStokesFiles& messa } } - _concatenated_name = ""; // reset the name of concatenated image - for (int i = 1; i <= StokesTypes.size(); ++i) { // get stokes type in the order I, Q, U, V (i.e., 1, 2, 3 ,4) - auto stokes_type = static_cast(i); - if (_loaders.count(stokes_type)) { - // update the concatenated image name and insert a new stokes type - _concatenated_name += CARTA::PolarizationType_Name(stokes_type); - } + _concatenated_name = ""; // reset the name of concatenated image + for (const auto& loader_entry : _loaders) { // get stokes type in the order I, Q, U, V (i.e., 1, 2, 3 ,4) + // update the concatenated image name and insert a new stokes type + _concatenated_name += CARTA::PolarizationType_Name(loader_entry.first); } // check if FITS stokes axis is contiguous @@ -270,9 +250,9 @@ bool StokesFilesConnector::OpenStokesFiles(const CARTA::ConcatStokesFiles& messa int delt = 0; int stokes_fits_value = 0; for (int i = 0; i < message.stokes_files_size(); ++i) { - int new_stokes_value = GetStokesValue(message.stokes_files(i).polarization_type()); + int new_stokes_value = message.stokes_files(i).polarization_type(); int new_stokes_fits_value; - if (FileInfo::ConvertFitsStokesValue(new_stokes_value, new_stokes_fits_value)) { + if (Stokes::ConvertFits(new_stokes_value, new_stokes_fits_value)) { if (stokes_fits_value != 0) { if (delt == 0) { delt = new_stokes_fits_value - stokes_fits_value; @@ -330,8 +310,8 @@ bool StokesFilesConnector::StokesFilesValid(std::string& err, int& stokes_axis) bool StokesFilesConnector::GetCasaStokesType( const CARTA::PolarizationType& in_stokes_type, casacore::Stokes::StokesTypes& out_stokes_type) { - if (CasaStokesTypes.count(in_stokes_type)) { - out_stokes_type = CasaStokesTypes[in_stokes_type]; + if (!Stokes::IsComputed(in_stokes_type)) { + out_stokes_type = Stokes::ToCasa(in_stokes_type); return true; } return false; diff --git a/src/ImageData/StokesFilesConnector.h b/src/ImageData/StokesFilesConnector.h index 197960662..a4c4a4ddb 100644 --- a/src/ImageData/StokesFilesConnector.h +++ b/src/ImageData/StokesFilesConnector.h @@ -31,7 +31,7 @@ class StokesFilesConnector { std::string _top_level_folder; std::string _concatenated_name; - std::unordered_map> _loaders; + std::map> _loaders; }; } // namespace carta diff --git a/src/ImageGenerators/PvGenerator.cc b/src/ImageGenerators/PvGenerator.cc index 63310932e..fd2cc78f0 100644 --- a/src/ImageGenerators/PvGenerator.cc +++ b/src/ImageGenerators/PvGenerator.cc @@ -151,7 +151,7 @@ casacore::CoordinateSystem PvGenerator::GetPvCoordinateSystem(const std::shared_ // Add stokes coordinate if input image has one if (input_csys->hasPolarizationCoordinate()) { - auto casacore_stokes_type = StokesTypesToCasacore[stokes]; + auto casacore_stokes_type = Stokes::ToCasa(Stokes::Get(stokes)); casacore::Vector types(1, casacore_stokes_type); casacore::StokesCoordinate stokes_coord(types); pv_csys.addCoordinate(stokes_coord); diff --git a/src/Region/RegionHandler.cc b/src/Region/RegionHandler.cc index c5f5569f2..119abba7d 100644 --- a/src/Region/RegionHandler.cc +++ b/src/Region/RegionHandler.cc @@ -1918,7 +1918,7 @@ bool RegionHandler::GetRegionSpectralData(int region_id, int file_id, const Axis get_stokes_profiles_data(tmp_results, tmp_stokes)); }; - if (IsComputedStokes(stokes_index)) { // For computed stokes + if (Stokes::IsComputed(stokes_index)) { // For computed stokes if (!GetComputedStokesProfiles(results, stokes_index, get_profiles_data)) { return false; } @@ -1970,7 +1970,7 @@ bool RegionHandler::GetRegionSpectralData(int region_id, int file_id, const Axis }; ProfilesMap partial_profiles; - if (IsComputedStokes(stokes_index)) { // For computed stokes + if (Stokes::IsComputed(stokes_index)) { // For computed stokes if (!GetComputedStokesProfiles(partial_profiles, stokes_index, get_profiles_data)) { return false; } @@ -2019,7 +2019,7 @@ bool RegionHandler::GetRegionSpectralData(int region_id, int file_id, const Axis int dt_target = TARGET_DELTA_TIME; // the target time elapse for each step, in the unit of milliseconds auto t_partial_profile_start = std::chrono::high_resolution_clock::now(); - if (IsComputedStokes(stokes_index)) { // Need to re-calculate the lattice coordinate region for computed stokes index + if (Stokes::IsComputed(stokes_index)) { // Need to re-calculate the lattice coordinate region for computed stokes index lc_region = nullptr; } @@ -2048,7 +2048,7 @@ bool RegionHandler::GetRegionSpectralData(int region_id, int file_id, const Axis }; ProfilesMap partial_profiles; - if (IsComputedStokes(stokes_index)) { // For computed stokes + if (Stokes::IsComputed(stokes_index)) { // For computed stokes if (!GetComputedStokesProfiles(partial_profiles, stokes_index, get_profiles_data)) { return false; } @@ -2732,28 +2732,28 @@ bool RegionHandler::IsValid(double a, double b) { bool RegionHandler::GetComputedStokesProfiles( ProfilesMap& profiles, int stokes, const std::function& get_profiles_data) { ProfilesMap profile_i, profile_q, profile_u, profile_v; - if (stokes == COMPUTE_STOKES_PTOTAL) { + if (stokes == CARTA::PolarizationType::Ptotal) { if (!get_profiles_data(profile_q, "Qz") || !get_profiles_data(profile_u, "Uz") || !get_profiles_data(profile_v, "Vz")) { return false; } GetStokesPtotal(profile_q, profile_u, profile_v, profiles); - } else if (stokes == COMPUTE_STOKES_PFTOTAL) { + } else if (stokes == CARTA::PolarizationType::PFtotal) { if (!get_profiles_data(profile_i, "Iz") || !get_profiles_data(profile_q, "Qz") || !get_profiles_data(profile_u, "Uz") || !get_profiles_data(profile_v, "Vz")) { return false; } GetStokesPftotal(profile_i, profile_q, profile_u, profile_v, profiles); - } else if (stokes == COMPUTE_STOKES_PLINEAR) { + } else if (stokes == CARTA::PolarizationType::Plinear) { if (!get_profiles_data(profile_q, "Qz") || !get_profiles_data(profile_u, "Uz")) { return false; } GetStokesPlinear(profile_q, profile_u, profiles); - } else if (stokes == COMPUTE_STOKES_PFLINEAR) { + } else if (stokes == CARTA::PolarizationType::PFlinear) { if (!get_profiles_data(profile_i, "Iz") || !get_profiles_data(profile_q, "Qz") || !get_profiles_data(profile_u, "Uz")) { return false; } GetStokesPflinear(profile_i, profile_q, profile_u, profiles); - } else if (stokes == COMPUTE_STOKES_PANGLE) { + } else if (stokes == CARTA::PolarizationType::Pangle) { if (!get_profiles_data(profile_q, "Qz") || !get_profiles_data(profile_u, "Uz")) { return false; } diff --git a/src/Util/Stokes.cc b/src/Util/Stokes.cc index 78820b801..daad0c5d1 100644 --- a/src/Util/Stokes.cc +++ b/src/Util/Stokes.cc @@ -6,26 +6,71 @@ #include "Stokes.h" -int GetStokesValue(const CARTA::PolarizationType& stokes_type) { - int stokes_value(-1); - if (StokesValues.count(stokes_type)) { - stokes_value = StokesValues[stokes_type]; +using namespace carta; + +std::unordered_map Stokes::_to_casa{ + {CARTA::PolarizationType::POLARIZATION_TYPE_NONE, casacore::Stokes::StokesTypes::Undefined}, + {CARTA::PolarizationType::I, casacore::Stokes::StokesTypes::I}, {CARTA::PolarizationType::Q, casacore::Stokes::StokesTypes::Q}, + {CARTA::PolarizationType::U, casacore::Stokes::StokesTypes::U}, {CARTA::PolarizationType::V, casacore::Stokes::StokesTypes::V}, + {CARTA::PolarizationType::RR, casacore::Stokes::StokesTypes::RR}, {CARTA::PolarizationType::LL, casacore::Stokes::StokesTypes::LL}, + {CARTA::PolarizationType::RL, casacore::Stokes::StokesTypes::RL}, {CARTA::PolarizationType::LR, casacore::Stokes::StokesTypes::LR}, + {CARTA::PolarizationType::XX, casacore::Stokes::StokesTypes::XX}, {CARTA::PolarizationType::YY, casacore::Stokes::StokesTypes::YY}, + {CARTA::PolarizationType::XY, casacore::Stokes::StokesTypes::XY}, {CARTA::PolarizationType::YX, casacore::Stokes::StokesTypes::YX}, + {CARTA::PolarizationType::Ptotal, casacore::Stokes::StokesTypes::Ptotal}, + {CARTA::PolarizationType::Plinear, casacore::Stokes::StokesTypes::Plinear}, + {CARTA::PolarizationType::PFtotal, casacore::Stokes::StokesTypes::PFtotal}, + {CARTA::PolarizationType::PFlinear, casacore::Stokes::StokesTypes::PFlinear}, + {CARTA::PolarizationType::Pangle, casacore::Stokes::StokesTypes::Pangle}}; + +std::unordered_map Stokes::_description{{CARTA::PolarizationType::POLARIZATION_TYPE_NONE, "Unknown"}, + {CARTA::PolarizationType::I, "Stokes I"}, {CARTA::PolarizationType::Q, "Stokes Q"}, {CARTA::PolarizationType::U, "Stokes U"}, + {CARTA::PolarizationType::V, "Stokes V"}, {CARTA::PolarizationType::Ptotal, "Total polarization intensity"}, + {CARTA::PolarizationType::Plinear, "Linear polarization intensity"}, + {CARTA::PolarizationType::PFtotal, "Fractional total polarization intensity"}, + {CARTA::PolarizationType::PFlinear, "Fractional linear polarization intensity"}, + {CARTA::PolarizationType::Pangle, "Polarization angle"}}; + +CARTA::PolarizationType Stokes::Get(int value) { + if (CARTA::PolarizationType_IsValid(value)) { + return static_cast(value); } - return stokes_value; + return CARTA::PolarizationType::POLARIZATION_TYPE_NONE; +} + +CARTA::PolarizationType Stokes::Get(std::string name) { + auto type = CARTA::PolarizationType::POLARIZATION_TYPE_NONE; + CARTA::PolarizationType_Parse(name, &type); + return type; } -CARTA::PolarizationType GetStokesType(int stokes_value) { - CARTA::PolarizationType stokes_type = CARTA::PolarizationType::POLARIZATION_TYPE_NONE; - if (StokesTypes.count(stokes_value)) { - stokes_type = StokesTypes[stokes_value]; +casacore::Stokes::StokesTypes Stokes::ToCasa(CARTA::PolarizationType type) { + return _to_casa.at(type); +} + +bool Stokes::ConvertFits(const int& in_stokes_value, int& out_stokes_value) { + if (in_stokes_value >= 1 && in_stokes_value <= 4) { + out_stokes_value = in_stokes_value; + return true; + } else if ((in_stokes_value >= 4 && in_stokes_value <= 12) || (in_stokes_value <= -1 && in_stokes_value >= -8)) { + // convert between [5, 6, ..., 12] and [-1, -2, ..., -8] + out_stokes_value = -in_stokes_value + 4; + return true; } - return stokes_type; + return false; } -bool IsComputedStokes(int stokes) { - return ((stokes >= COMPUTE_STOKES_PTOTAL) && (stokes <= COMPUTE_STOKES_PANGLE)); +std::string Stokes::Name(CARTA::PolarizationType type) { + return CARTA::PolarizationType_Name(type); +} + +std::string Stokes::Description(CARTA::PolarizationType type) { + try { + return _description.at(type); + } catch (const std::out_of_range& e) { + return CARTA::PolarizationType_Name(type); + } } -bool IsComputedStokes(const std::string& stokes) { - return IsComputedStokes(StokesValues[StokesStringTypes[stokes]]); +bool Stokes::IsComputed(int value) { + return (value >= CARTA::PolarizationType::Ptotal) && (value <= CARTA::PolarizationType::Pangle); } diff --git a/src/Util/Stokes.h b/src/Util/Stokes.h index 87000dc00..c50a9800b 100644 --- a/src/Util/Stokes.h +++ b/src/Util/Stokes.h @@ -15,49 +15,23 @@ #include "Image.h" -// stokes types and value conversion -static std::unordered_map StokesValues{{CARTA::PolarizationType::I, 1}, {CARTA::PolarizationType::Q, 2}, - {CARTA::PolarizationType::U, 3}, {CARTA::PolarizationType::V, 4}, {CARTA::PolarizationType::RR, 5}, {CARTA::PolarizationType::LL, 6}, - {CARTA::PolarizationType::RL, 7}, {CARTA::PolarizationType::LR, 8}, {CARTA::PolarizationType::XX, 9}, {CARTA::PolarizationType::YY, 10}, - {CARTA::PolarizationType::XY, 11}, {CARTA::PolarizationType::YX, 12}, {CARTA::PolarizationType::Ptotal, 13}, - {CARTA::PolarizationType::Plinear, 14}, {CARTA::PolarizationType::PFtotal, 15}, {CARTA::PolarizationType::PFlinear, 16}, - {CARTA::PolarizationType::Pangle, 17}}; - -// computed stokes using StokesValues -#define COMPUTE_STOKES_PTOTAL StokesValues[CARTA::PolarizationType::Ptotal] // Total polarization intensity: (Q^2+U^2+V^2)^(1/2) -#define COMPUTE_STOKES_PLINEAR StokesValues[CARTA::PolarizationType::Plinear] // Linear polarization intensity: (Q^2+U^2)^(1/2) -#define COMPUTE_STOKES_PFTOTAL StokesValues[CARTA::PolarizationType::PFtotal] // Fractional total polarization intensity: Ptotal/I -#define COMPUTE_STOKES_PFLINEAR StokesValues[CARTA::PolarizationType::PFlinear] // Fractional linear polarization intensity: Plinear/I -#define COMPUTE_STOKES_PANGLE StokesValues[CARTA::PolarizationType::Pangle] // Polarization angle: (tan^-1(U/Q))/2 - -static std::unordered_map StokesTypes{{1, CARTA::PolarizationType::I}, {2, CARTA::PolarizationType::Q}, - {3, CARTA::PolarizationType::U}, {4, CARTA::PolarizationType::V}, {5, CARTA::PolarizationType::RR}, {6, CARTA::PolarizationType::LL}, - {7, CARTA::PolarizationType::RL}, {8, CARTA::PolarizationType::LR}, {9, CARTA::PolarizationType::XX}, {10, CARTA::PolarizationType::YY}, - {11, CARTA::PolarizationType::XY}, {12, CARTA::PolarizationType::YX}, {13, CARTA::PolarizationType::Ptotal}, - {14, CARTA::PolarizationType::Plinear}, {15, CARTA::PolarizationType::PFtotal}, {16, CARTA::PolarizationType::PFlinear}, - {17, CARTA::PolarizationType::Pangle}}; - -static std::unordered_map StokesStringTypes{{"I", CARTA::PolarizationType::I}, - {"Q", CARTA::PolarizationType::Q}, {"U", CARTA::PolarizationType::U}, {"V", CARTA::PolarizationType::V}, - {"RR", CARTA::PolarizationType::RR}, {"LL", CARTA::PolarizationType::LL}, {"RL", CARTA::PolarizationType::RL}, - {"LR", CARTA::PolarizationType::LR}, {"XX", CARTA::PolarizationType::XX}, {"YY", CARTA::PolarizationType::YY}, - {"XY", CARTA::PolarizationType::XY}, {"YX", CARTA::PolarizationType::YX}, {"Ptotal", CARTA::PolarizationType::Ptotal}, - {"Plinear", CARTA::PolarizationType::Plinear}, {"PFtotal", CARTA::PolarizationType::PFtotal}, - {"PFlinear", CARTA::PolarizationType::PFlinear}, {"Pangle", CARTA::PolarizationType::Pangle}}; - -static std::unordered_map StokesTypesToCasacore{{1, casacore::Stokes::StokesTypes::I}, - {2, casacore::Stokes::StokesTypes::Q}, {3, casacore::Stokes::StokesTypes::U}, {4, casacore::Stokes::StokesTypes::V}, - {5, casacore::Stokes::StokesTypes::RR}, {6, casacore::Stokes::StokesTypes::LL}, {7, casacore::Stokes::StokesTypes::RL}, - {8, casacore::Stokes::StokesTypes::LR}, {9, casacore::Stokes::StokesTypes::XX}, {10, casacore::Stokes::StokesTypes::YY}, - {11, casacore::Stokes::StokesTypes::XY}, {12, casacore::Stokes::StokesTypes::YX}, {13, casacore::Stokes::StokesTypes::Ptotal}, - {14, casacore::Stokes::StokesTypes::Plinear}, {15, casacore::Stokes::StokesTypes::PFtotal}, - {16, casacore::Stokes::StokesTypes::PFlinear}, {17, casacore::Stokes::StokesTypes::Pangle}}; - -int GetStokesValue(const CARTA::PolarizationType& stokes_type); -CARTA::PolarizationType GetStokesType(int stokes_value); -casacore::Stokes::StokesTypes GetCasacoreStokesValue(const CARTA::PolarizationType& stokes_type); -bool IsComputedStokes(int stokes); -bool IsComputedStokes(const std::string& stokes); +namespace carta { + +class Stokes { +public: + static CARTA::PolarizationType Get(int value); + static CARTA::PolarizationType Get(std::string name); + static casacore::Stokes::StokesTypes ToCasa(CARTA::PolarizationType type); + static bool ConvertFits(const int& in_stokes_value, int& out_stokes_value); + static std::string Name(CARTA::PolarizationType type); + static std::string Description(CARTA::PolarizationType type); + static bool IsComputed(int value); + + // TODO move FITS mappings here too +protected: + static std::unordered_map _to_casa; + static std::unordered_map _description; +}; // The struct StokesSource is used to tell the file loader to get the original image interface, or get the computed stokes image interface. // The x, y, and z ranges from the StokesSource indicate the range of image data to be calculated (for the new stokes type image). @@ -78,7 +52,7 @@ struct StokesSource { : stokes(stokes_), z_range(z_range_), x_range(x_range_), y_range(y_range_) {} bool IsOriginalImage() const { - return !IsComputedStokes(stokes); + return !Stokes::IsComputed(stokes); } bool operator==(const StokesSource& rhs) const { if ((stokes != rhs.stokes) || (z_range != rhs.z_range) || (x_range != rhs.x_range) || (y_range != rhs.y_range)) { @@ -94,4 +68,6 @@ struct StokesSource { } }; +} // namespace carta + #endif // CARTA_SRC_UTIL_STOKES_H_ diff --git a/test/TestExprImage.cc b/test/TestExprImage.cc index dd85e8fbe..ade8a96f1 100644 --- a/test/TestExprImage.cc +++ b/test/TestExprImage.cc @@ -11,6 +11,8 @@ #include "ImageData/FileLoader.h" #include "Logger/Logger.h" +using namespace carta; + class ImageExprTest : public ::testing::Test { public: void GenerateImageExprTimesTwo(const std::string& file_name, const std::string& hdu, CARTA::FileType file_type, bool invalid = false) {