Skip to content

Commit

Permalink
Merge branch 'dev' into pam/1186_channel_map
Browse files Browse the repository at this point in the history
  • Loading branch information
pford committed Nov 8, 2024
2 parents 22efce8 + 8d13764 commit 6c69d95
Show file tree
Hide file tree
Showing 16 changed files with 265 additions and 269 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Fix hdf5 image distortion after animation stops ([#1368](https://github.com/CARTAvis/carta-backend/issues/1368)).
* Fix matched polygon region approximation crash ([#1383](https://github.com/CARTAvis/carta-backend/issues/1383)).
* Fix save image/export regions bug which could cause directory overwrite or deletion ([#1377](https://github.com/CARTAvis/carta-backend/issues/1377)).
* Fix bug in cache slicer transformation which affects some images with rotated axes ([#1389](https://github.com/CARTAvis/carta-backend/pull/1389)).

### Changed
* Move the loader cache to separate files ([#1021](https://github.com/CARTAvis/carta-backend/issues/1021)).
Expand Down
137 changes: 70 additions & 67 deletions src/Frame/Frame.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ Frame::Frame(uint32_t session_id, std::shared_ptr<FileLoader> 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
Expand Down Expand Up @@ -189,6 +193,18 @@ int Frame::StokesAxis() {
return _stokes_axis;
}

int Frame::XAxis() {
return _x_axis;
}

int Frame::YAxis() {
return _y_axis;
}

int Frame::ZAxis() {
return _z_axis;
}

bool Frame::IsCurrentZStokes(const StokesSource& stokes_source) {
return (stokes_source.z_range.from == stokes_source.z_range.to) && (stokes_source.z_range.from == CurrentZ()) &&
(stokes_source.stokes == CurrentStokes());
Expand All @@ -207,7 +223,7 @@ bool Frame::GetBeams(std::vector<CARTA::Beam>& 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) {
Expand All @@ -226,13 +242,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;
Expand All @@ -247,13 +256,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;
Expand Down Expand Up @@ -313,7 +315,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) {
Expand Down Expand Up @@ -349,7 +351,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 {
Expand Down Expand Up @@ -603,7 +605,7 @@ bool Frame::GetRasterTileData(int z, std::shared_ptr<std::vector<float>>& tile_d
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 (z == _z_index && !_image_cache_valid && _use_tile_cache) {
Expand Down Expand Up @@ -1199,7 +1201,7 @@ bool Frame::FillSpatialProfileData(PointXy point, std::vector<CARTA::SetSpatialR
bool have_profile(false);
bool downsample(mip >= 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;
}
Expand Down Expand Up @@ -1487,8 +1489,8 @@ bool Frame::FillSpectralProfileData(std::function<void(CARTA::SpectralProfileDat

std::vector<float> 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);
Expand Down Expand Up @@ -1744,10 +1746,10 @@ bool Frame::GetSlicerData(const StokesSlicer& stokes_slicer, float* data) {
auto slicer_end = stokes_slicer.slicer.end();

// Adjust cache shape and slicer for single channel and stokes
if (_spectral_axis >= 0) {
cache_shape(_spectral_axis) = 1;
slicer_start(_spectral_axis) = 0;
slicer_end(_spectral_axis) = 0;
if (_z_axis >= 0) {
cache_shape(_z_axis) = 1;
slicer_start(_z_axis) = 0;
slicer_end(_z_axis) = 0;
}
if (_stokes_axis >= 0) {
cache_shape(_stokes_axis) = 1;
Expand Down Expand Up @@ -2369,60 +2371,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 (is_stokes_string) {
stokes_string = coordinate;
} else {
stokes_string = coordinate.substr(0, coordinate.size() - 1);
}
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;
}

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);
bool stokes_ok(false);

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 {
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() {
Expand Down
10 changes: 4 additions & 6 deletions src/Frame/Frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,6 @@ static std::unordered_map<CARTA::FileType, string> 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<CARTA::PolarizationType, std::string> 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
Expand Down Expand Up @@ -108,6 +102,9 @@ class Frame {
bool IsCurrentZStokes(const StokesSource& stokes_source);
int SpectralAxis();
int StokesAxis();
int XAxis();
int YAxis();
int ZAxis();
bool GetBeams(std::vector<CARTA::Beam>& beams);

// Slicer to set z and stokes ranges with full xy plane
Expand Down Expand Up @@ -286,6 +283,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;
Expand Down
14 changes: 0 additions & 14 deletions src/ImageData/FileInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#include <casacore/images/Images/SubImage.h>

#include <carta-protobuf/defs.pb.h>
//#include <carta-protobuf/enums.pb.h>

namespace carta {
namespace FileInfo {
Expand Down Expand Up @@ -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

Expand Down
40 changes: 27 additions & 13 deletions src/ImageData/FileLoader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ bool FileLoader::FindCoordinateAxes(casacore::IPosition& shape, std::vector<int>
}
}

_x_axis = render_axes[0];
_y_axis = render_axes[1];
_width = shape(render_axes[0]);
_height = shape(render_axes[1]);
_image_plane_size = _width * _height;
Expand Down Expand Up @@ -310,8 +312,10 @@ bool FileLoader::FindCoordinateAxes(casacore::IPosition& shape, std::vector<int>
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<CARTA::PolarizationType>(stokes_value);
_stokes_indices[stokes_type] = i;
_stokes_types[i] = stokes_type;
}
}
}
Expand Down Expand Up @@ -846,7 +850,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;
Expand Down Expand Up @@ -912,11 +916,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) {
Expand All @@ -926,18 +940,18 @@ typename FileLoader::ImageRef FileLoader::GetStokesImage(const StokesSource& sto

if (_stokes_source != stokes_source) {
// compute new stokes image with respect to the channel range
carta::PolarizationCalculator polarization_calculator(
GetImage(), AxisRange(stokes_source.z_range), AxisRange(stokes_source.x_range), AxisRange(stokes_source.y_range));
carta::PolarizationCalculator polarization_calculator(GetImage(), {_x_axis, _y_axis, _z_axis, _stokes_axis},
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);
Expand Down
Loading

0 comments on commit 6c69d95

Please sign in to comment.