view main/octcdf/src/ov-ncfile.cc @ 2608:59724598d7c5 octave-forge

Add isrecord function
author abarth93
date Fri, 06 Oct 2006 14:33:54 +0000
parents 7ee762e11903
children 643624495ca0
line wrap: on
line source

/*
  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"
#include "ov-ncdim.h"




octave_ncfile::octave_ncfile(string filenamep, string open_mode):octave_base_value()
{
  int status;
  int omode = NC_NOWRITE;
  bool do_open;

#     ifdef OV_NETCDF_VERBOSE
      octave_stdout << "allocate ncfile_t " << std::endl;
#    endif

  nf = new ncfile_t;

  nf->filename = filenamep;

  if (open_mode == "r" || open_mode == "nowrite") {
    do_open = true;
    omode = NC_NOWRITE;
  }
  else if (open_mode == "w" || open_mode == "write") {
    do_open = true;
    omode = NC_WRITE;
  }
  else if (open_mode == "c" || open_mode == "clobber") {
    do_open = false;
    omode = NC_CLOBBER;
  }
  else if (open_mode == "nc" || open_mode == "noclobber") {
    do_open = false;
    omode = NC_NOCLOBBER;
  }
  else {
    error("Unknown mode for opening netcdf file: %s",open_mode.c_str());
    return;
  }


  if (do_open)  {
      status = nc_open(nf->filename.c_str(), omode, &(nf->ncid));

      if (status != NC_NOERR)
	{
	  error("Error while opening %s: %s", nf->filename.c_str(),
		nc_strerror(status));
	  return;
	}


      nf->mode = DataMode;

    }
  else {
#     ifdef OCTCDF_64BIT_OFFSET 
      omode = omode | NC_64BIT_OFFSET;
#     endif

      status = nc_create(nf->filename.c_str(), omode, &(nf->ncid));

      if (status != NC_NOERR)
	{
	  error("Error while creating %s: %s", nf->filename.c_str(),
		nc_strerror(status));
	  return;
	}


      nf->mode = DefineMode;

    }

#     ifdef OV_NETCDF_VERBOSE
      octave_stdout << "Open file " << nf->filename.c_str() 
        << " omode " << omode << " mode " << (int) nf->mode << std::endl;
#    endif

    read_info();

}


void octave_ncfile::read_info() {

  int status;

  if (get_ncid() == -1) return;

# ifdef OV_NETCDF_VERBOSE
  octave_stdout << __FILE__ <<  __LINE__ << ":" << __FUNCTION__ << std::endl;
# endif

  status = nc_inq(get_ncid(),&(nf->ndims),&(nf->nvars),&(nf->natts),&(nf->unlimdimid));

  if (status != NC_NOERR)
    error("Error while quering file: %s",nc_strerror(status));

}


// x.v = y     x(idx).v = y     x{idx}.v = y

octave_value octave_ncfile::subsasgn(const std::string & type,
				const std::list < octave_value_list > &idx,
				const octave_value & rhs)
{
  int status;
  octave_value retval;


  //  check_args_string("octave_ncfile::subsasgn",idx.front());

  if (error_state)
    return octave_value();

  std::string name = idx.front()(0).string_value();


  switch (type[0]) {
    case '.': {
#       ifdef OV_NETCDF_VERBOSE
	octave_stdout << "create attribute " << name << std::endl;
#       endif

	set_mode(DefineMode);

	if (!rhs.is_cell()) {

#           ifdef OV_NETCDF_VERBOSE
	    octave_stdout << "type_id" << rhs.type_id() << endl;
#           endif

            nc_type nctype = ovtype2nctype(rhs);

#          ifdef OV_NETCDF_VERBOSE
	    octave_stdout << "type " << nctype << endl;
#          endif

          ov_nc_put_att(get_ncid(),NC_GLOBAL,name,nctype,rhs);
	}
        else {
#       ifdef OV_NETCDF_VERBOSE
	  octave_stdout << "define attribute from cell " << get_ncid() << std::endl;
#       endif

            Cell c =  rhs.cell_value();

#           ifdef OV_NETCDF_VERBOSE
	    octave_stdout << "type " << c.elem(0).string_value()<< endl;
#           endif
            nc_type nctype = ncname2nctype(c.elem(0).string_value());
#           ifdef OV_NETCDF_VERBOSE
	    octave_stdout << "type " << nctype << endl;
#           endif
     	    ov_nc_put_att(get_ncid(),NC_GLOBAL,name,nctype,c.elem(1));
	}

	break;
      }
    case '(': {
	int dimid;
#       ifdef OV_NETCDF_VERBOSE
	octave_stdout << "create dimension " << name << std::endl;
#       endif

	set_mode(DefineMode);

	status =
	  nc_def_dim(get_ncid(),name.c_str(), (size_t) rhs.scalar_value(),
		     &dimid);

	if (status == NC_ENAMEINUSE) {
	  octave_stdout << "dimension " << name.c_str() << " already exist" << std::endl;
	}
        else if (status != NC_NOERR) {
	    error("Error while creating dimension %s: %s",
		  name.c_str(), nc_strerror(status));
	  }
	break;
      }
    case '{': {
	set_mode(DefineMode);

	if (type.length() == 1) {
	  if (rhs.class_name() == "ncvar") {
	    // define a variables

            // downcast from octave_value to octave_ncvar

            const octave_ncvar& ncvar = (const octave_ncvar&)rhs.get_rep();
#           ifdef OV_NETCDF_VERBOSE
  	    octave_stdout << "define variable " << name <<  " nctype " << ncvar.get_nctype() << std::endl;
#           endif

            ov_nc_def_var(get_ncid(),name,ncvar.get_nctype(),ncvar.get_dimnames());

	  } 
	  else if (rhs.is_cell()) {
#           ifdef OV_NETCDF_VERBOSE
  	    octave_stdout << "define variable from cell " << std::endl;
#           endif
            Cell c =  rhs.cell_value();

#           ifdef OV_NETCDF_VERBOSE
	    octave_stdout << "type " << c.elem(0).string_value()<< endl;
#           endif
            nc_type nctype = ncname2nctype(c.elem(0).string_value());
#           ifdef OV_NETCDF_VERBOSE
	    octave_stdout << "type " << nctype << endl;
#           endif

            std::list<std::string> dimnames;

            for (int i = 1; i < c.nelem(); i++) {
              dimnames.push_back(c.elem(i).string_value());
#             ifdef OV_NETCDF_VERBOSE
	      octave_stdout << "dimention " << c.elem(i).string_value()<< endl;
#             endif
            }

            ov_nc_def_var(get_ncid(),name,nctype,dimnames);

	  }
          else
	    error("Error rhs of assignment should be an ncvar");
	}
	else {
	  octave_ncvar *var = new octave_ncvar(this,name);

          if (idx.front().length() == 2) 
	    if (idx.front()(1).is_scalar_type()) 
              var->autoscale() = idx.front()(1).scalar_value() == 1;


            
	  if (! error_state && idx.size () > 1)
	    {
	      // make necessary assignment with netcdf variable

	      std::list<octave_value_list> new_idx (idx);
	      new_idx.erase (new_idx.begin ());
	      retval = var->subsasgn (type.substr(1), new_idx,rhs);
	    }

	}


	break;
      }
      break;

    }


  // update characteristics

  read_info();

  // result of this assignement is the same 
  // octave_ncfile object

# ifdef OCTAVE_VALUE_COUNT_CONSTRUCTOR
  retval = octave_value(this, count + 1);
# else
  retval = octave_value(clone());
# endif

  return retval;


};

// x.v     x(idx).v     x{idx}.v

octave_value octave_ncfile::subsref(const std::string &type,
			       const std::list < octave_value_list > &idx)
{
  int dimid, status;
  octave_value retval;

  //  check_args_string("octave_ncfile::subsref",idx.front());

  if (error_state)
    return octave_value();

  std::string name = idx.front()(0).string_value();

  switch (type[0]) {
    case '.': {
#       ifdef OV_NETCDF_VERBOSE
	octave_stdout << "getting attribute " << name << std::endl;
#       endif

	retval = ov_nc_get_att(get_ncid(),NC_GLOBAL,name);

	break;
      }
    case '(':
      {
#       ifdef OV_NETCDF_VERBOSE
        octave_stdout << "getting dimension " << name << std::endl;
#       endif

	status = nc_inq_dimid(get_ncid(),name.c_str(), &dimid);

	if (status != NC_NOERR) {
	  error("Error while querying dimension %s: %s",name.c_str(), nc_strerror(status));
   	  return  octave_value();
	}

	retval = octave_value(new octave_ncdim(this,dimid));

	break;
      }
    case '{': {
#         ifdef OV_NETCDF_VERBOSE
	octave_stdout << "getting variable " << name << std::endl;
#         endif

	octave_ncvar *var = new octave_ncvar(this, name);

	// determine if the variable need to be scaled

        if (idx.front().length() == 2) {
            var->autoscale() = idx.front()(1).scalar_value() == 1;
	}

	retval = var;
	break;
      }
      break;

    }

  return retval.next_subsref(type, idx);
}


octave_ncfile::~octave_ncfile(void)
{
  // not a good idea to close file, since copies of ncfile are created 
  // which are destroyed when the original ncfile object is still used
  //  close();
}

void octave_ncfile::close(void) {
  int status;
#   ifdef OV_NETCDF_VERBOSE
  octave_stdout << "close file " << get_ncid() << std::endl;
#   endif

  if (get_ncid() == -1) return;

  status = nc_close(get_ncid());

   if (status != NC_NOERR)  {
       error("Error closing file: %s", nc_strerror(status));
     }

  nf->ncid = -1;
}

void octave_ncfile::sync(void) {
  int status;
#   ifdef OV_NETCDF_VERBOSE
  octave_stdout << "sync file " << std::endl;
#   endif

  set_mode(DataMode);
  status = nc_sync(get_ncid());

  if (status != NC_NOERR)
    {
      error("Error syncronizing file: %s", nc_strerror(status));
    }
}


void octave_ncfile::set_mode(Modes new_mode)
{
  int status;

  if (new_mode != get_mode())
    {
      if (new_mode == DataMode)
	  status = nc_enddef(get_ncid());
      else
	  status = nc_redef(get_ncid());

      if (status != NC_NOERR)
	  error("Error chaning mode: %s", nc_strerror(status));
      else
	  nf->mode = new_mode;
    }


}

void octave_ncfile::print(std::ostream & os, bool pr_as_read_syntax = false) const
{

  os << "filename = " << get_filename() << std::endl;
# ifdef OV_NETCDF_VERBOSE
  os << "ncid = " << get_ncid() << std::endl;
# endif
  os << "nvars = " << get_nvars() << std::endl;
  os << "natts = " << get_natts() << std::endl;
  os << "ndims = " << get_ndims() << std::endl;
  if (get_mode() == DataMode)
    os << "mode = DataMode " << std::endl;
  else
    os << "mode = DefineMode " << std::endl;
}




DEFINE_OCTAVE_ALLOCATOR(octave_ncfile);
DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_ncfile, "ncfile", "ncfile");


// end octave_ncfile