/*
octcdf, a netcdf toolbox for octave
Copyright (C) 2005 Alexander Barth <abarth@marine.usf.edu>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "ov-netcdf.h"
#include "ov-ncfile.h"
#include "ov-ncvar.h"
#include "ov-ncatt.h"
//
// Constructors of octave_ncvar
//
octave_ncvar::octave_ncvar(octave_ncfile* ncfilep, std::string varnamep) :octave_base_value() {
int status, varid;
ncv = new ncvar_t;
set_ncfile(ncfilep);
set_varname(varnamep);
set_ncid(ncfilep->get_ncid());
status = nc_inq_varid(get_ncid(),get_varname().c_str(), &varid);
if (status != NC_NOERR) {
error("Error while querying variable %s: %s",
get_varname().c_str(), nc_strerror(status));
}
set_varid(varid);
# ifdef OV_NETCDF_VERBOSE
octave_stdout << "new variable " << __LINE__ << ":" << __FUNCTION__ << std::endl;
# endif
read_info();
autoscale() = false;
}
octave_ncvar::octave_ncvar(octave_ncfile* ncfilep, int varidp):octave_base_value() {
ncv = new ncvar_t;
set_varid(varidp);
set_ncfile(ncfilep);
set_ncid(ncfilep->get_ncid());
# ifdef OV_NETCDF_VERBOSE
octave_stdout << "new variable " << __LINE__ << ":" << __FUNCTION__ << std::endl;
# endif
read_info();
autoscale() = false;
}
// load charecteristics of netcdf variable from file
void octave_ncvar::read_info() {
int status;
int dimids[NC_MAX_VAR_DIMS];
int ndims, natts;
char name[NC_MAX_NAME];
size_t length;
nc_type nctype;
dim_vector dimvec, ncdimvec;
std::list<std::string> dimnames;
if (get_varid() == -1) return;
# ifdef OV_NETCDF_VERBOSE
octave_stdout << __FILE__ << __LINE__ << ":" << __FUNCTION__ << std::endl;
# endif
status = nc_inq_var(get_ncid(),get_varid(),name,&nctype,&ndims,dimids,&natts);
if (status != NC_NOERR)
error("Error while quering variable: %s",nc_strerror(status));
set_nctype(nctype);
set_natts(natts);
set_varname(string(name));
ncdimvec.resize(ndims);
// reverse dimids if FORTRAN_ORDER
if (STORAGE_ORDER == FORTRAN_ORDER)
for (int i=0; i<ndims/2; i++) {
status = dimids[i];
dimids[i] = dimids[ndims-i-1];
dimids[ndims-i-1] = status;
}
for (int i=0; i<ndims; i++) {
status = nc_inq_dim(get_ncid(),dimids[i],name,&length);
if (status != NC_NOERR)
error("Error while quering dimenstion: %s",nc_strerror(status));
set_dimid(i,dimids[i]);
dimnames.push_back(name);
ncdimvec(i) = length;
}
// octave dimvec
// Number of dimensions is at least 2
dimvec.resize(max(ndims,2));
if (ndims > 1)
dimvec = ncdimvec;
else {
dimvec(1) = 1;
if (ndims == 1)
dimvec(0) = ncdimvec(0);
else
dimvec(0) = 1;
}
ncv->dimvec = dimvec;
ncv->ncdimvec = ncdimvec;
set_dimnames(dimnames);
}
// Assigmnent of the type:
// x.v = y x(idx).v = y x{idx}.v = y
octave_value octave_ncvar::subsasgn(const std::string & type,
const LIST < octave_value_list > &idx,
const octave_value & rhs) {
octave_value scale_factor, add_offset, scaledrhs;
octave_value retval;
switch (type[0])
{
case '.':
{
std::string name = idx.front()(0).string_value();
get_ncfile()->set_mode(DefineMode);
# ifdef OV_NETCDF_VERBOSE
octave_stdout << "create attribute " << name << std::endl;
# endif
if (!rhs.is_cell()) {
nc_type nctype = ovtype2nctype(rhs);
ov_nc_put_att(get_ncid(),get_varid(),name,nctype,rhs);
}
else {
# ifdef OV_NETCDF_VERBOSE
octave_stdout << "define attribute from cell " << get_ncid() << std::endl;
# endif
Cell c = rhs.cell_value();
nc_type nctype = ncname2nctype(c.elem(0).string_value());
ov_nc_put_att(get_ncid(),get_varid(),name,nctype,c.elem(1));
}
break;
}
case '(':
{
# ifdef OV_NETCDF_VERBOSE
octave_stdout << "putting var " << std::endl;
# endif
scaledrhs = rhs;
// autoscale the retrieved variable if necessary
// the variables attributes "scale_factor" and "add_offset" are
// used for the linear scale if present.
if (autoscale()) {
add_offset = ov_nc_get_att(get_ncid(),get_varid(),"add_offset");
if (!add_offset.is_empty()) {
scaledrhs = scaledrhs - add_offset;
}
scale_factor = ov_nc_get_att(get_ncid(),get_varid(),"scale_factor");
if (!scale_factor.is_empty()) {
scaledrhs = scaledrhs / scale_factor;
}
}
get_ncfile()->set_mode(DataMode);
octave_value_list key_idx = *idx.begin();
std::list<Range> ranges = get_slice(key_idx);
ov_nc_put_vars(get_ncid(),get_varid(),ranges,get_nctype(),scaledrhs);
retval = rhs;
break;
}
case '{':
{
error("octave_ncvar cannout be referenced with {}");
break;
}
break;
}
// update characteristics
read_info();
retval = octave_value(this, count + 1);
return retval;
};
// References of the type:
// x.v x(idx).v x{idx}.v
octave_value octave_ncvar::subsref(const std::string SUBSREF_STRREF type,
const LIST < octave_value_list > &idx)
{
octave_value scale_factor, add_offset;
octave_value retval;
switch (type[0])
{
case '.':
{
std::string attrname = idx.front()(0).string_value();
# ifdef OV_NETCDF_VERBOSE
octave_stdout << "getting attribute " << attrname << std::endl;
# endif
retval = ov_nc_get_att(get_ncid(),get_varid(),attrname);
break;
}
case '(':
{
# ifdef OV_NETCDF_VERBOSE
octave_stdout << "getting var " << std::endl;
# endif
get_ncfile()->set_mode(DataMode);
octave_value_list key_idx = idx.front();
std::list<Range> ranges = get_slice(key_idx);
retval = ov_nc_get_vars(get_ncid(),get_varid(),ranges,get_nctype());
// autoscale the retrieved variable if necessary
// the variables attributes "scale_factor" and "add_offset" are
// used for the linear scale if present.
if (autoscale()) {
scale_factor = ov_nc_get_att(get_ncid(),get_varid(),"scale_factor");
if (!scale_factor.is_empty()) {
retval = retval * scale_factor;
}
add_offset = ov_nc_get_att(get_ncid(),get_varid(),"add_offset");
if (!add_offset.is_empty()) {
retval = retval + add_offset;
}
}
break;
}
case '{':
{
error("octave_ncvar cannot not be indexed with {}");
break;
}
break;
}
// apply remaining subreference operator
return retval.next_subsref(type, idx);
}
void octave_ncvar::print(std::ostream & os, bool pr_as_read_syntax = false) const
{
int i;
os << "varname = \"" << get_varname() << "\"" << std::endl;
os << "type = " << nctype2ncname(get_nctype()) << endl;;
# ifdef OV_NETCDF_VERBOSE
os << "ncid = " << get_ncid() << std::endl;
os << "varid = " << get_varid() << std::endl;
# endif
os << "natts = " << get_natts() << std::endl;
os << "size = " << dims().str() << std::endl;
os << "ncsize = " << ncv->ncdimvec.str() << std::endl;
// os << "size = ";
// for (i=0; i<ndims()-1; i++) {
// os << ncv->dimvec(i) << " x ";
// }
// os << ncv->dimvec(ndims()-1) << std::endl;
// std::list<std::string> dimnames = get_dimnames();
std::list<std::string>::const_iterator it;
i=1;
for(it=ncv->dimnames.begin(); it!=ncv->dimnames.end(); ++it) {
os << "dimension " << i << " = " << *it << std::endl;
os << "dimension id " << i << " = " << ncv->dimids[i-1] << std::endl;
i=i+1;
}
}
// determine the slice of the variable to read or to store depending
// on the ranges given in key_idx
std::list<Range> octave_ncvar::get_slice(octave_value_list key_idx)
{
//std::string key = key_idx(0).string_value ();
std::list<Range> ranges;
dim_vector dv;
dv.resize(ncndims());
int ip;
// special case: if only one colone, then retrieve all data
if (key_idx.length() == 1 && key_idx(0).is_magic_colon())
{
for (int i = 0; i < ncndims(); i++)
{
ranges.push_back(Range(1. , (double)dims()(i), 1.));
}
}
else
{
for (int i = 0; i < ncndims(); i++)
{
if (key_idx(i).is_range()) {
ranges.push_back(key_idx(i).range_value());
}
else if (key_idx(i).is_magic_colon()) {
ranges.push_back(Range(1. , (double)dims()(i)));
}
else if (key_idx(i).is_real_scalar()) {
ranges.push_back(Range(key_idx(i).scalar_value(),key_idx(i).scalar_value()));
}
else {
error("octcdf: unknown index specification: type %s",key_idx(i).type_name().c_str());
}
}
}
if (STORAGE_ORDER == FORTRAN_ORDER)
ranges.reverse();
return ranges;
}
void octave_ncvar::rename(string new_name) {
int status;
status = nc_rename_var(get_ncid(),get_varid(), new_name.c_str());
if (status != NC_NOERR) {
error("Error while renaming variable %s: %s", get_varname().c_str(),
nc_strerror(status));
return;
}
set_varname(new_name);
}
DEFINE_OCTAVE_ALLOCATOR(octave_ncvar);
DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_ncvar, "ncvar", "ncvar");
// end octave_ncvar
syntax highlighted by Code2HTML, v. 0.9.1