Skip to content

Commit

Permalink
Mark/1178 supports loading swapped-axes image cubes (#1194)
Browse files Browse the repository at this point in the history
* Do not fix the render axes to direction axes

* Modify the changelog

* Add axes numbers for Ra, Dec, Spectral and Stokes in the file info

* Add axes numbers in the file info extended message

* A minor code change

* Fix the problem of showing PV image coordinates for swapped axes cubes

* Identify key words GLON or GLAT as direction axes

* Remove unused codes

* Modify the protobuf message AxesNumbers

* Change axis indices from 0-based to 1-based in the axes_numbers message

* Minor code changes and refactoring

* Fix an unit test error for the file info

* Revert coordinate settings in PV generator

* Refactor codes

* Update the protobuf submodule

* Minor code changes

* Fix the problem of loading image file if it has both linear and direction coordinates

* Fix the error of showing direction axes range names in the file info for swapped images

* Modify file info on the file browser for swapped image cubes

* Fix the problem of showing direction axis names for compressed images

* Update the protobuf with the new dev branch

* Change the name of linear axis for a PV image as OFFSET

* Fix the name of non-direction axis for axis number is 0 or 1

* Remove the function GetRenderAxes from the FileLoader

* Fix the problem of axis names displayed on the file info panel

* Fix the problem of an image without direction axes info for AST rendering

* Update the protobuf submodule with the new dev branch

* Update the protobuf and modify the changelog and the index

* Get axes names through the image loader or the header entries

* Correct the definition of number of channels is spectral axis size

* Skip the stokes axis when rendering an image

* Get axis names from header entries that shown on the file info panel

* Modify the file info tester

* Represent the longitudinal coordinate value in the rangge [0, 360] deg

* Correct the syntax to initialize values for axis names

* Fix the reversed PV generation when getting with fixed angular region profiles

* Rename variables for directional axes as spatial axes

* Update the protobuf messages for spatial axes

* Fix the reference Dec value shown on the file info panel

* Minor code changes

* bumped protobuf commit

---------

Co-authored-by: Adrianna Pińska <[email protected]>
  • Loading branch information
markccchiang and confluence authored Mar 22, 2023
1 parent 46b4c00 commit 08832e1
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 139 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Added support to keep previously generated moment images ([#1202](https://github.com/CARTAvis/carta-backend/issues/1202)).
* Added pugixml as a third-party library with the option PUGIXML_COMPACT enabled ([#1217](https://github.com/CARTAvis/carta-backend/issues/1217)).
* Added automatically generated documentation with Doxygen ([#1215](https://github.com/CARTAvis/carta-backend/issues/1215)).
* Added support for loading swapped-axes image cubes ([#1178](https://github.com/CARTAvis/carta-backend/issues/1178)).

### Changed
* Removed CASA CRTF parser for performance and annotation region support ([#1219](https://github.com/CARTAvis/carta-backend/issues/1219)).
Expand Down
2 changes: 1 addition & 1 deletion carta-protobuf
190 changes: 127 additions & 63 deletions src/FileList/FileExtInfoLoader.cc

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions src/FileList/FileExtInfoLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ class FileExtInfoLoader {

// Computed entries
void AddDataTypeEntry(CARTA::FileInfoExtended& extended_info, casacore::DataType data_type);
void AddShapeEntries(CARTA::FileInfoExtended& extended_info, const casacore::IPosition& shape, int chan_axis, int depth_axis,
int stokes_axis, const std::vector<int>& render_axes);
void AddShapeEntries(CARTA::FileInfoExtended& extended_info, const casacore::IPosition& shape, const std::vector<int>& spatial_axes,
int spectral_axis, int stokes_axis, const std::vector<int>& render_axes, int depth_axis,
casacore::Vector<casacore::String>& axes_names);
void AddInitialComputedEntries(const std::string& hdu, CARTA::FileInfoExtended& extended_info, const std::string& filename,
const std::vector<int>& render_axes, CompressedFits* compressed_fits = nullptr);
void AddComputedEntries(CARTA::FileInfoExtended& extended_info, casacore::ImageInterface<float>* image,
Expand All @@ -66,7 +67,7 @@ class FileExtInfoLoader {
std::string MakeAngleString(const std::string& type, double val, const std::string& unit);

// Convert Quantities and return formatted string
std::string ConvertCoordsToDeg(const casacore::Quantity& coord0, const casacore::Quantity& coord1);
std::string ConvertCoordsToDeg(const std::string& type, const casacore::Quantity& coord);
std::string ConvertIncrementToArcsec(const casacore::Quantity& inc0, const casacore::Quantity& inc1);

void GetCoordNames(std::string& ctype1, std::string& ctype2, std::string& radesys, std::string& coord_name1, std::string& coord_name2,
Expand Down
6 changes: 2 additions & 4 deletions src/Frame/Frame.cc
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,16 @@ Frame::Frame(uint32_t session_id, std::shared_ptr<FileLoader> loader, const std:

// Get shape and axis values from the loader
std::string log_message;
if (!_loader->FindCoordinateAxes(_image_shape, _spectral_axis, _z_axis, _stokes_axis, log_message)) {
std::vector<int> spatial_axes, render_axes;
if (!_loader->FindCoordinateAxes(_image_shape, spatial_axes, _spectral_axis, _stokes_axis, render_axes, _z_axis, log_message)) {
_open_image_error = fmt::format("Cannot determine file shape. {}", log_message);
spdlog::error("Session {}: {}", session_id, _open_image_error);
_valid = false;
return;
}

// Determine which axes are rendered, e.g. for pV images
std::vector<int> render_axes = _loader->GetRenderAxes();
_x_axis = render_axes[0];
_y_axis = render_axes[1];

_width = _image_shape(_x_axis);
_height = _image_shape(_y_axis);
_depth = (_z_axis >= 0 ? _image_shape(_z_axis) : 1);
Expand Down
3 changes: 2 additions & 1 deletion src/Frame/Frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@ class Frame {

// Shape and axis info: X, Y, Z, Stokes
casacore::IPosition _image_shape;
int _x_axis, _y_axis, _z_axis, _spectral_axis, _stokes_axis;
int _x_axis, _y_axis, _z_axis; // X and Y are render axes, Z is depth axis (non-render axis) that is not stokes (if any)
int _spectral_axis, _stokes_axis;
int _z_index, _stokes_index; // current index
size_t _width, _height, _depth, _num_stokes;

Expand Down
85 changes: 26 additions & 59 deletions src/ImageData/FileLoader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,11 @@ std::shared_ptr<casacore::CoordinateSystem> FileLoader::GetCoordinateSystem(cons
return std::make_shared<casacore::CoordinateSystem>();
}

bool FileLoader::FindCoordinateAxes(casacore::IPosition& shape, int& spectral_axis, int& z_axis, int& stokes_axis, std::string& message) {
bool FileLoader::FindCoordinateAxes(casacore::IPosition& shape, std::vector<int>& spatial_axes, int& spectral_axis, int& stokes_axis,
std::vector<int>& render_axes, int& z_axis, std::string& message) {
// Return image shape and axes for image. Spectral axis may or may not be z axis.
// All parameters are return values.
spatial_axes.assign(2, -1);
spectral_axis = -1;
z_axis = -1;
stokes_axis = -1;
Expand All @@ -201,15 +203,33 @@ bool FileLoader::FindCoordinateAxes(casacore::IPosition& shape, int& spectral_ax
return false;
}

// Determine which axes will be rendered
std::vector<int> render_axes = GetRenderAxes();
// Get spectral and stokes axis
spectral_axis = _coord_sys->spectralAxisNumber();
stokes_axis = _coord_sys->polarizationAxisNumber();

// Set render axes are the first two axes that are not stokes
render_axes.resize(0);
for (int i = 0; i < _num_dims && render_axes.size() < 2; ++i) {
if (i != stokes_axis) {
render_axes.push_back(i);
}
}

_width = shape(render_axes[0]);
_height = shape(render_axes[1]);
_image_plane_size = _width * _height;

// Spectral and stokes axis
spectral_axis = _coord_sys->spectralAxisNumber();
stokes_axis = _coord_sys->polarizationAxisNumber();
// Find spatial axes
if (_coord_sys->hasDirectionCoordinate()) {
auto tmp_axes = _coord_sys->directionAxesNumbers();
spatial_axes[0] = tmp_axes[0];
spatial_axes[1] = tmp_axes[1];
} else if (_coord_sys->hasLinearCoordinate()) {
auto tmp_axes = _coord_sys->linearAxesNumbers();
for (int i = 0; i < casacore::min(tmp_axes.size(), 2); ++i) { // Assume the first two linear axes are spatial axes, if any
spatial_axes[i] = tmp_axes[i];
}
}

// 2D image
if (_num_dims == 2) {
Expand Down Expand Up @@ -282,59 +302,6 @@ bool FileLoader::FindCoordinateAxes(casacore::IPosition& shape, int& spectral_ax
return true;
}

std::vector<int> FileLoader::GetRenderAxes() {
// Determine which axes will be rendered
std::vector<int> axes;

if (!_render_axes.empty()) {
axes = _render_axes;
return axes;
}

// Default unless PV image
axes.assign({0, 1});

if (_image_shape.size() > 2) {
// Normally, use direction axes
if (_coord_sys->hasDirectionCoordinate()) {
casacore::Vector<casacore::Int> dir_axes = _coord_sys->directionAxesNumbers();
axes[0] = dir_axes[0];
axes[1] = dir_axes[1];
} else if (_coord_sys->hasLinearCoordinate()) {
// Check for PV image: usually [Linear, Spectral] axes but could be reversed
// Returns -1 if no spectral axis
int spectral_axis = _coord_sys->spectralAxisNumber();

if (spectral_axis >= 0) {
// Find valid (not -1) linear axes
std::vector<int> valid_axes;
if (spectral_axis == 0) { // reversed
valid_axes.push_back(spectral_axis);
}

casacore::Vector<casacore::Int> lin_axes = _coord_sys->linearAxesNumbers();
for (auto axis : lin_axes) {
if (axis >= 0) {
valid_axes.push_back(axis);
}
}

if (spectral_axis > 0) { // not reversed
valid_axes.push_back(spectral_axis);
}

// One linear + spectral axis = pV image
if (valid_axes.size() == 2) {
axes = valid_axes;
}
}
}
}

_render_axes = axes;
return axes;
}

bool FileLoader::GetSlice(casacore::Array<float>& data, const StokesSlicer& stokes_slicer) {
StokesSource stokes_source = stokes_slicer.stokes_source;
casacore::Slicer slicer = stokes_slicer.slicer;
Expand Down
7 changes: 2 additions & 5 deletions src/ImageData/FileLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@

namespace carta {

class Frame;

struct StokesSlicer {
StokesSource stokes_source;
casacore::Slicer slicer;
Expand Down Expand Up @@ -78,8 +76,8 @@ class FileLoader {
// Image shape and coordinate system axes
casacore::IPosition GetShape();
std::shared_ptr<casacore::CoordinateSystem> GetCoordinateSystem(const StokesSource& stokes_source = StokesSource());
bool FindCoordinateAxes(casacore::IPosition& shape, int& spectral_axis, int& z_axis, int& stokes_axis, std::string& message);
std::vector<int> GetRenderAxes(); // Determine axes used for image raster data
bool FindCoordinateAxes(casacore::IPosition& shape, std::vector<int>& spatial_axes, int& spectral_axis, int& stokes_axis,
std::vector<int>& render_axes, int& z_axis, std::string& message);

// Slice image data (with mask applied)
bool GetSlice(casacore::Array<float>& data, const StokesSlicer& stokes_slicer);
Expand Down Expand Up @@ -152,7 +150,6 @@ class FileLoader {
size_t _num_dims, _image_plane_size;
size_t _width, _height, _depth, _num_stokes;
int _z_axis, _stokes_axis;
std::vector<int> _render_axes;
std::shared_ptr<casacore::CoordinateSystem> _coord_sys;
bool _has_pixel_mask;
casacore::DataType _data_type;
Expand Down
7 changes: 5 additions & 2 deletions src/ImageData/StokesFilesConnector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -300,20 +300,23 @@ bool StokesFilesConnector::StokesFilesValid(std::string& err, int& stokes_axis)
}

casacore::IPosition ref_shape(0);
std::vector<int> ref_spatial_axes, ref_render_axes;
int ref_spectral_axis = -1;
int ref_z_axis = -1;
int ref_stokes_axis = -1;
int ref_index = 0;

for (auto& loader : _loaders) {
casacore::IPosition shape;
std::vector<int> spatial_axes, render_axes;
int spectral_axis;
int z_axis;

if (ref_index == 0) {
loader.second->FindCoordinateAxes(ref_shape, ref_spectral_axis, ref_z_axis, ref_stokes_axis, err);
loader.second->FindCoordinateAxes(
ref_shape, ref_spatial_axes, ref_spectral_axis, ref_stokes_axis, ref_render_axes, ref_z_axis, err);
} else {
loader.second->FindCoordinateAxes(shape, spectral_axis, z_axis, stokes_axis, err);
loader.second->FindCoordinateAxes(shape, spatial_axes, spectral_axis, stokes_axis, render_axes, z_axis, err);
if ((ref_shape.nelements() != shape.nelements()) || (ref_shape != shape) || (ref_spectral_axis != spectral_axis) ||
(ref_stokes_axis != stokes_axis)) {
err = "Image shapes or axes are not consistent!";
Expand Down
2 changes: 1 addition & 1 deletion test/TestFileInfo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class FileExtInfoLoaderTest : public ::testing::Test {
} else if (computed_entries.name() == "HDU") {
CheckHeaderEntry(computed_entries, "0", CARTA::EntryType::STRING);
} else if (computed_entries.name() == "Shape") {
CheckHeaderEntry(computed_entries, "[6, 6, 5, 1]", CARTA::EntryType::STRING);
CheckHeaderEntry(computed_entries, "[6, 6, 5, 1] (RA, DEC, FREQ, STOKES)", CARTA::EntryType::STRING);
} else if (computed_entries.name() == "Number of channels") {
CheckHeaderEntry(computed_entries, "5", CARTA::EntryType::INT, 5);
} else if (computed_entries.name() == "Number of polarizations") {
Expand Down

0 comments on commit 08832e1

Please sign in to comment.