view scripts/ode/odeset.m @ 20595:c1a6c31ac29a

eliminate more simple uses of error_state * ov-classdef.cc: Eliminate simple uses of error_state.
author John W. Eaton <jwe@octave.org>
date Tue, 06 Oct 2015 00:20:02 -0400
parents 45151de7423f
children e5f36a7854a5
line wrap: on
line source

## Copyright (C) 2013, Roberto Porcu' <roberto.porcu@polimi.it>
## Copyright (C) 2006-2012, Thomas Treichl <treichl@users.sourceforge.net>
##
## This file is part of Octave.
##
## Octave 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 3 of the License, or (at
## your option) any later version.
##
## Octave 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 Octave; see the file COPYING.  If not, see
## <http://www.gnu.org/licenses/>.

## -*- texinfo -*-
## @deftypefn  {Function File} {} odeset ()
## @deftypefnx {Function File} {@var{odestruct} =} odeset (@var{"field1"}, @var{value1}, @var{"field2"}, @var{value2}, @dots{})
## @deftypefnx {Function File} {@var{odestruct} =} odeset (@var{oldstruct}, @var{"field1"}, @var{value1}, @var{"field2"}, @var{value2}, @dots{})
## @deftypefnx {Function File} {@var{odestruct} =} odeset (@var{oldstruct}, @var{newstruct})
##
## Create or modify an ODE options structure.
##
## If this function is called without an input argument then return a new ODE
## options structure array that contains all the necessary fields and sets
## the values of all fields to default values.
##
## If this function is called with string input arguments @var{"field1"},
## @var{"field2"}, @dots{} identifying valid ODE options then return a new
## ODE options structure with all necessary fields and set the values of the
## fields @var{"field1"}, @var{"field2"}, @dots{} to the values @var{value1},
## @var{value2}, @dots{}
##
## If this function is called with a first input argument @var{oldstruct} of
## type structure array then overwrite all values of the options
## @var{"field1"}, @var{"field2"}, @dots{} of the structure @var{oldstruct}
## with new values @var{value1}, @var{value2}, @dots{} and return the
## modified structure array.
##
## If this function is called with two input arguments @var{oldstruct} and
## @var{newstruct} of type structure array then overwrite all values in the
## fields from the structure @var{oldstruct} with new values of the fields
## from the structure @var{newstruct}.  Empty values of @var{newstruct} will
## not overwrite values in @var{oldstruct}.
## @seealso{odeget}
## @end deftypefn

function odestruct = odeset (varargin)

  ## Special calling syntax to display defaults
  if (nargin == 0 && nargout == 0)
    print_options ();
    return;
  endif

  ## Column vector of all possible OdePkg fields
  fields = ["AbsTol"; "Algorithm"; "BDF"; "Choice"; "Eta"; "Events";
            "Explicit"; "InexactSolver"; "InitialSlope"; "InitialStep";
            "Jacobian";"JConstant";"JPattern";"Mass"; "MassConstant";
            "MassSingular"; "MaxNewtonIterations"; "MaxOrder"; "MaxStep";
            "MStateDependence"; "MvPattern"; "NewtonTol"; "NonNegative";
            "NormControl"; "OutputFcn"; "OutputSave"; "OutputSel";
            "PolynomialDegree"; "QuadratureOrder"; "Refine"; "RelTol";
            "Restart"; "Stats"; "TimeStepNumber"; "TimeStepSize";
            "UseJacobian"; "Vectorized"];

  fields_nb = rows (fields);

  ## initialize output
  odestruct = cell2struct (cell (rows (fields), 1), cellstr (fields));

  odestruct.Refine = 0;
  odestruct.OutputSave = 1;

  if (nargin == 0 && nargout == 1)
    return;
  endif

  ode_fields = fieldnames (odestruct);
  
  if (isstruct (varargin{1}))
    oldstruct = varargin{1};
    ode_struct_value_check (oldstruct);

    optA_fields = fieldnames (oldstruct);
    optA_f_nb = length (optA_fields);

    ## loop on first struct options for updating
    for i = 1:optA_f_nb
      name = lower (deblank (optA_fields{i}));

      while (1)
        pos = fuzzy_compare (name, fields);
        if (isempty (pos))
          warning ("OdePkg:InvalidArgument",
                   "no property found with name '%s'", name);
        endif

        if (rows (pos) == 1)
          if (! strcmp (lower (deblank (name)),
                        lower (deblank (fields(pos,:)))))
            warning ("OdePkg:InvalidArgument", "no exact matching for ",
                     "'%s'. Assuming you were intending '%s'",
                     name, deblank (fields(pos,:)));
          endif

          odestruct.(deblank (fields(pos,:))) = oldstruct.(optA_fields{i});
          break;
        endif

        ## FIXME: Do we really need interactive selection?
        ## if there are more matching, ask the user to be more precise
        warning ("OdePkg:InvalidArgument",
                 "no exact matching for '%s'. %d possible fields were found",
                 name, size(pos, 1));
        for j = 1:(rows (pos))
          printf ("%s\n", deblank (fields(pos(j),:)));
        endfor
        do
          disp ("Please insert field name again");
          name = input ("New field name: ");
        until (ischar (name))
      endwhile
    endfor

    if (nargin == 2 && isstruct (varargin{2}))
      newstruct = varargin{2};
      ode_struct_value_check (newstruct);

      optB_fields = fieldnames (newstruct);
      optB_f_nb = length (optB_fields);

      ## update the first struct with the values in the second one
      for i = 1:optB_f_nb
        name = lower (deblank (optB_fields{i}));
        while (1)
          pos = fuzzy_compare (name, fields);

          if (isempty (pos))
            warning ("OdePkg:InvalidArgument",
                     "no property found with name '%s'", name);
          endif

          if (rows (pos) == 1)
            if (! strcmp (lower (deblank (name)),
                          lower (deblank (fields(pos,:)))))
              warning ("OdePkg:InvalidArgument", "no exact matching for ",
                       "'%s'. Assuming you were intending '%s'",
                        name, deblank (fields(pos,:)));
            endif
            odestruct.(deblank (fields(pos,:))) = newstruct.(optB_fields{i});
            break;
          endif

          ## FIXME: Do we really need interactive selection?
          ## if there are more matching, ask the user to be more precise
          warning ("OdePkg:InvalidArgument", "no exact matching for '%s'. ",
                   "%d possible fields were found",
                   name, rows (pos));
          for j = 1:(rows (pos))
            printf ("%s\n", deblank (fields(pos(j),:)));
          endfor
          do
            disp ("Please insert field name again");
            name = input ("New field name: ");
          until (ischar (name))
        endwhile
      endfor
      return;
    endif

    ## if the second argument is not a struct,
    ## pass new values of the OdePkg options to the first struct
    if (mod (nargin, 2) != 1)
      error ("odeset: FIELD/VALUE arguments must occur in pairs");
    endif

    if (! all (cellfun ("isclass", varargin(2:2:end), "char")))
      error ("odeset: All FIELD names must be strings");
    endif

    ## loop on the input arguments
    for i = 2:2:(nargin - 1)
      name = varargin{i};

      while (1)
        pos = fuzzy_compare (name, fields);

        if (isempty (pos))
          error ("OdePkg:InvalidArgument",
                 "no property found with name '%s'", name);
        endif

        if (rows (pos) == 1)
          if (! strcmp (lower (deblank (name)),
                        lower (deblank (fields(pos,:)))))
            warning ("OdePkg:InvalidArgument", "no exact matching for '%s'. ",
                     "%d possible fields were found",
                     name, rows (pos));
          endif
          odestruct.(deblank (fields(pos,:))) = varargin{i+1};
          break;
        endif

        ## FIXME: Do we really need interactive selection?
        ## if there are more matching, ask the user to be more precise
        warning ("OdePkg:InvalidArgument", "no exact matching for '%s'. ",
                 "%d possible fields were found",
                 name, rows (pos));
        for j = 1:(rows (pos))
          printf ("%s\n", deblank (fields(pos(j),:)));
        endfor
        do
          disp ("Please insert field name again");
          name = input ("New field name: ");
        until (ischar (name))
      endwhile
    endfor

    ## check if all has been done gives a valid OdePkg struct
    ode_struct_value_check (odestruct);
    return;
  endif

  ## first input argument was not a struct
  if (mod (nargin, 2) != 0)
    error ("odeset: FIELD/VALUE arguments must occur in pairs");
  endif

  if (! all (cellfun ("isclass", varargin(1:2:end), "char")))
    error ("odeset: All FIELD names must be strings");
  endif

  for i = 1:2:(nargin-1)
    name = varargin{i};

    while (1)
      pos = fuzzy_compare (name, fields);

      if (isempty (pos))
        error ("OdePkg:InvalidArgument",
               "invalid property. No property found with name '%s'", name);
      endif

      if (rows (pos) == 1)
        if (! strcmp (lower (deblank (name)),
                      lower (deblank (fields(pos,:)))))
          warning ("OdePkg:InvalidArgument", "no exact matching for ",
                   "'%s'. Assuming you were intending '%s'",
                   name, deblank (fields(pos,:)));
        endif
        odestruct.(deblank (fields(pos,:))) = varargin{i+1};
        break;
      endif

      ## FIXME: Do we really need interactive selection?
      ## if there are more matching, ask the user to be more precise
      warning ("OdePkg:InvalidArgument", "no exact matching for '%s'. ",
               "%d possible fields were found",
               name, rows (pos));
      for j = 1:rows (pos)
        printf ("%s\n", deblank (fields(pos(j),:)));
      endfor
      do
        disp ("Please insert field name again");
        name = input ("New field name: ");
      until (ischar (name))
    endwhile
  endfor

  ## check if all has been done gives a valid OdePkg struct
  ode_struct_value_check (odestruct);

endfunction

## function useful to print all the possible options
function print_options ()
  
  disp ("These following are all possible options.");
  disp ("Default values are put in square brackets.");
  disp ("");
  disp ("             AbsTol:  scalar or vector, >0, [1e-6]");
  disp ("          Algorithm:  string, {['gmres'], 'pcg', 'bicgstab'}");
  disp ("                BDF:  binary, {'on', ['off']}");
  disp ("             Choice:  switch, {[1], 2}");
  disp ("                Eta:  scalar, >=0, <1, [0.5]");
  disp ("             Events:  function_handle, []");
  disp ("           Explicit:  binary, {'yes', ['no']}");
  disp ("      InexactSolver:  string, {'inexact_newton', 'fsolve', []}");
  disp ("       InitialSlope:  vector, []");
  disp ("        InitialStep:  scalar, >0, []");
  disp ("           Jacobian:  matrix or function_handle, []");
  disp ("          JConstant:  binary, {'on', ['off']}");
  disp ("           JPattern:  sparse matrix, []");
  disp ("               Mass:  matrix or function_handle, []");
  disp ("       MassConstant:  binary, {'on', ['off']}");
  disp ("       MassSingular:  switch, {'yes', ['maybe'], 'no'}");
  disp ("MaxNewtonIterations:  scalar, integer, >0, [1e3]");
  disp ("           MaxOrder:  switch, {1, 2, 3, 4, [5]}");
  disp ("            MaxStep:  scalar, >0, []");
  disp ("   MStateDependence:  switch, {'none', ['weak'], 'strong'}");
  disp ("          MvPattern:  sparse matrix, []");
  disp ("          NewtonTol:  scalar or vector, >0, []");
  disp ("        NonNegative:  vector of integers, []");
  disp ("        NormControl:  binary, {'on', ['off']}");
  disp ("          OutputFcn:  function_handle, []");
  disp ("         OutputSave:  scalar, integer, >0, []");
  disp ("          OutputSel:  scalar or vector, []");
  disp ("   PolynomialDegree:  scalar, integer, >0, []");
  disp ("    QuadratureOrder:  scalar, integer, >0, []");
  disp ("             Refine:  scalar, integer, >0, []");
  disp ("             RelTol:  scalar, >0, [1e-3]");
  disp ("            Restart:  scalar, integer, >0, [20]");
  disp ("              Stats:  binary, {'on', ['off']}");
  disp ("     TimeStepNumber:  scalar, integer, >0, []");
  disp ("       TimeStepSize:  scalar, >0, []");
  disp ("        UseJacobian:  binary, {'yes', ['no']}");
  disp ("         Vectorized:  binary, {'on', ['off']}");

endfunction


%!demo
%! # A new OdePkg options structure with default values is created.
%!
%! odeoptA = odeset ();

%!demo
%! # A new OdePkg options structure with manually set options 
%! # for "AbsTol" and "RelTol" is created.
%!
%! odeoptB = odeset ("AbsTol", 1e-2, "RelTol", 1e-1);

%!demo
%! # A new OdePkg options structure is created from odeoptB with
%! # a modified value for option "NormControl".

%! odeoptB = odeset ("AbsTol", 1e-2, "RelTol", 1e-1);
%! odeoptC = odeset (odeoptB, "NormControl", "on");

## All tests that are needed to check if a correct resp. valid option
## has been set are implemented in ode_struct_value_check.m.
%!test
%! wstate = warning ("off", "OdePkg:InvalidArgument");
%! unwind_protect
%!   odeoptA = odeset ();
%!   ## FIXME: no assert check on odeoptA
%!   odeoptB = odeset ("AbsTol", 1e-2, "RelTol", 1e-1);
%!   assert (odeoptB.AbsTol, 1e-2);
%!   assert (odeoptB.RelTol, 1e-1);
%!   odeoptC = odeset (odeoptB, "NormControl", "on");
%!   ## FIXME: no assert check on odeoptC
%!   odeoptD = odeset (odeoptC, odeoptB);
%!   ## FIXME: no assert check on odeoptD
%! unwind_protect_cleanup
%!   warning (wstate);
%! end_unwind_protect