/* octcdf, a netcdf toolbox for octave Copyright (C) 2005 Alexander Barth 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 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 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 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 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; idimvec(i) << " x "; // } // os << ncv->dimvec(ndims()-1) << std::endl; // std::list dimnames = get_dimnames(); std::list::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 octave_ncvar::get_slice(octave_value_list key_idx) { //std::string key = key_idx(0).string_value (); std::list 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