Skip to content

Commit

Permalink
add rename_variables
Browse files Browse the repository at this point in the history
* adds teca_rename_variables an algorithm that could be used to rename
  arrays as they pass through.
* incldues a test and Python bindings.
  • Loading branch information
burlen committed Apr 19, 2021
1 parent 4cd087d commit d54095a
Show file tree
Hide file tree
Showing 7 changed files with 425 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ env:
- BUILD_TYPE=Debug
- TECA_DIR=/travis_teca_dir
- TECA_PYTHON_VERSION=3
- TECA_DATA_REVISION=116
- TECA_DATA_REVISION=117
jobs:
- DOCKER_IMAGE=ubuntu IMAGE_VERSION=20.04 IMAGE_NAME=ubuntu_20_04 REQUIRE_NETCDF_MPI=TRUE
- DOCKER_IMAGE=ubuntu IMAGE_VERSION=20.04 IMAGE_NAME=ubuntu_20_04 REQUIRE_NETCDF_MPI=FALSE
Expand Down
1 change: 1 addition & 0 deletions alg/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ set(teca_alg_cxx_srcs
teca_mask.cxx
teca_normalize_coordinates.cxx
teca_parser.cxx
teca_rename_variables.cxx
teca_table_calendar.cxx
teca_table_reduce.cxx
teca_table_region_mask.cxx
Expand Down
225 changes: 225 additions & 0 deletions alg/teca_rename_variables.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
#include "teca_rename_variables.h"

#include "teca_mesh.h"
#include "teca_array_collection.h"
#include "teca_variant_array.h"
#include "teca_metadata.h"
#include "teca_array_attributes.h"

#include <algorithm>
#include <iostream>
#include <string>
#include <set>
#include <cmath>

#if defined(TECA_HAS_BOOST)
#include <boost/program_options.hpp>
#endif

using std::string;
using std::vector;
using std::set;
using std::cerr;
using std::endl;

//#define TECA_DEBUG

// --------------------------------------------------------------------------
teca_rename_variables::teca_rename_variables() :
original_variable_names(), new_variable_names()
{
this->set_number_of_input_connections(1);
this->set_number_of_output_ports(1);
}

// --------------------------------------------------------------------------
teca_rename_variables::~teca_rename_variables()
{}

#if defined(TECA_HAS_BOOST)
// --------------------------------------------------------------------------
void teca_rename_variables::get_properties_description(
const string &prefix, options_description &global_opts)
{
options_description opts("Options for "
+ (prefix.empty()?"teca_rename_variables":prefix));

opts.add_options()
TECA_POPTS_MULTI_GET(std::vector<std::string>, prefix, original_variable_names,
"Sets the list of original_variable_names to rename.")
TECA_POPTS_MULTI_GET(std::vector<std::string>, prefix, new_variable_names,
"Sets the list of new names, one for each variable to rename.")
;

this->teca_algorithm::get_properties_description(prefix, opts);

global_opts.add(opts);
}

// --------------------------------------------------------------------------
void teca_rename_variables::set_properties(
const string &prefix, variables_map &opts)
{
this->teca_algorithm::set_properties(prefix, opts);

TECA_POPTS_SET(opts, std::vector<std::string>, prefix, original_variable_names)
TECA_POPTS_SET(opts, std::vector<std::string>, prefix, new_variable_names)

}
#endif

// --------------------------------------------------------------------------
teca_metadata teca_rename_variables::get_output_metadata(
unsigned int port,
const std::vector<teca_metadata> &input_md)
{
#ifdef TECA_DEBUG
cerr << teca_parallel_id()
<< "teca_rename_variables::get_output_metadata" << endl;
#endif
(void)port;

// validate the user provided values.
if (this->original_variable_names.size() != this->new_variable_names.size())
{
TECA_ERROR("Each variable to rename must have a "
" corresponding output_variable_name.")
return teca_metadata();
}

teca_metadata out_md(input_md[0]);

// update the list of original_variable_names to reflect the new names
std::set<std::string> out_vars;
if (out_md.get("variables", out_vars))
{
TECA_ERROR("Failed to get the list of variables")
return teca_metadata();
}

unsigned long n_vars = this->original_variable_names.size();
for (unsigned long i = 0; i < n_vars; ++i)
{
std::set<std::string>::iterator it = out_vars.find(this->original_variable_names[i]);
if (it == out_vars.end())
{
TECA_ERROR("No such variable \"" << this->original_variable_names[i]
<< "\" to rename")
return teca_metadata();
}

out_vars.erase(it);
out_vars.insert(this->new_variable_names[i]);
}

// update the list of attributes to reflect the new names
teca_metadata attributes;
if (out_md.get("attributes", attributes))
{
TECA_ERROR("Failed to get attributes")
return teca_metadata();
}

for (unsigned long i = 0; i < n_vars; ++i)
{
const std::string &var_name = this->original_variable_names[i];

teca_metadata atts;
if (attributes.get(var_name, atts))
{
TECA_ERROR("Failed to get attributes for \"" << var_name << "\"")
return teca_metadata();
}

attributes.remove(var_name);

attributes.set(this->new_variable_names[i], atts);
}

out_md.set("attributes", attributes);

return out_md;
}

// --------------------------------------------------------------------------
std::vector<teca_metadata> teca_rename_variables::get_upstream_request(
unsigned int port,
const std::vector<teca_metadata> &input_md,
const teca_metadata &request)
{
(void)port;
(void)input_md;

vector<teca_metadata> up_reqs;

// copy the incoming request to preserve the downstream requirements.
// replace renamed original_variable_names with their original name
teca_metadata req(request);

std::set<std::string> arrays;
if (req.has("arrays"))
req.get("arrays", arrays);

unsigned long n_vars = this->new_variable_names.size();
for (unsigned long i = 0; i < n_vars; ++i)
{
std::set<std::string>::iterator it = arrays.find(this->new_variable_names[i]);
if (it != arrays.end())
{
arrays.erase(it);
arrays.insert(this->original_variable_names[i]);
}

}

req.set("arrays", arrays);
up_reqs.push_back(req);

return up_reqs;
}

// --------------------------------------------------------------------------
const_p_teca_dataset teca_rename_variables::execute(
unsigned int port,
const std::vector<const_p_teca_dataset> &input_data,
const teca_metadata &request)
{
#ifdef TECA_DEBUG
cerr << teca_parallel_id() << "teca_rename_variables::execute" << endl;
#endif
(void)port;
(void)request;

// get the input mesh
const_p_teca_mesh in_mesh
= std::dynamic_pointer_cast<const teca_mesh>(input_data[0]);

if (!in_mesh)
{
TECA_ERROR("The input dataset is not a teca_mesh")
return nullptr;
}

// create the output mesh, pass everything through.
p_teca_mesh out_mesh = std::static_pointer_cast<teca_mesh>
(std::const_pointer_cast<teca_mesh>(in_mesh)->new_shallow_copy());


// rename the arrays if they are found
p_teca_array_collection arrays = out_mesh->get_point_arrays();

unsigned long n_vars = this->original_variable_names.size();
for (unsigned long i = 0; i < n_vars; ++i)
{
const std::string var_name = this->original_variable_names[i];

p_teca_variant_array array = arrays->get(var_name);
if (array)
{
arrays->remove(var_name);
arrays->set(this->new_variable_names[i], array);
}
}

return out_mesh;
}
70 changes: 70 additions & 0 deletions alg/teca_rename_variables.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#ifndef teca_rename_variables_h
#define teca_rename_variables_h

#include "teca_shared_object.h"
#include "teca_algorithm.h"
#include "teca_metadata.h"

#include <string>
#include <vector>

TECA_SHARED_OBJECT_FORWARD_DECL(teca_rename_variables)

/// An algorithm that renames original_variable_names.
class teca_rename_variables : public teca_algorithm
{
public:
TECA_ALGORITHM_STATIC_NEW(teca_rename_variables)
TECA_ALGORITHM_DELETE_COPY_ASSIGN(teca_rename_variables)
TECA_ALGORITHM_CLASS_NAME(teca_rename_variables)
~teca_rename_variables();

// report/initialize to/from Boost program options
// objects.
TECA_GET_ALGORITHM_PROPERTIES_DESCRIPTION()
TECA_SET_ALGORITHM_PROPERTIES()

/** @anchor original_variable_names
* @name original_variable_names
* Set the list of variables to rename. For each variable to rename a new
* name must be specified at the same index in the @ref new_variable_names
* list. The two lists must be the same length.
*/
///@{
TECA_ALGORITHM_VECTOR_PROPERTY(std::string, original_variable_name)
///@}

/** @anchor new_variable_names
* @name new_variable_names
* Set the names of the renamed variables. The new names are applied to the
* list of variables to rename in the same order and the two lists must be
* the same length.
*/
///@{
TECA_ALGORITHM_VECTOR_PROPERTY(std::string, new_variable_name)
///@}

protected:
teca_rename_variables();

private:
teca_metadata get_output_metadata(
unsigned int port,
const std::vector<teca_metadata> &input_md) override;

std::vector<teca_metadata> get_upstream_request(
unsigned int port,
const std::vector<teca_metadata> &input_md,
const teca_metadata &request) override;

const_p_teca_dataset execute(
unsigned int port,
const std::vector<const_p_teca_dataset> &input_data,
const teca_metadata &request) override;

private:
std::vector<std::string> original_variable_names;
std::vector<std::string> new_variable_names;
};

#endif
9 changes: 9 additions & 0 deletions python/teca_py_alg.i
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "teca_latitude_damper.h"
#include "teca_mask.h"
#include "teca_normalize_coordinates.h"
#include "teca_rename_variables.h"
#include "teca_saffir_simpson.h"
#include "teca_table_calendar.h"
#include "teca_table_sort.h"
Expand Down Expand Up @@ -429,3 +430,11 @@ struct teca_tc_saffir_simpson
%shared_ptr(teca_elevation_mask)
%ignore teca_elevation_mask::operator=;
%include "teca_elevation_mask.h"

/***************************************************************************
rename_variables
***************************************************************************/
%ignore teca_rename_variables::shared_from_this;
%shared_ptr(teca_rename_variables)
%ignore teca_rename_variables::operator=;
%include "teca_rename_variables.h"
7 changes: 7 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -748,3 +748,10 @@ teca_add_test(test_interval_iterator_yearly
1
FEATURES ${TECA_HAS_NETCDF}
REQ_TECA_DATA)

teca_add_test(test_rename_variables
SOURCES test_rename_variables.cpp
LIBS teca_core teca_data teca_io teca_alg ${teca_test_link}
COMMAND test_rename_variables "${TECA_DATA_ROOT}/test_rename_variables.nc"
FEATURES ${TECA_HAS_NETCDF}
REQ_TECA_DATA)
Loading

0 comments on commit d54095a

Please sign in to comment.