KerMor  0.9
Model order reduction for nonlinear dynamical systems and nonlinear approximation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
BaseModel.m
Go to the documentation of this file.
1 namespace models{
2 
3 
4 /* (Autoinserted by mtoc++)
5  * This source code has been filtered by the mtoc++ executable,
6  * which generates code that can be processed by the doxygen documentation tool.
7  *
8  * On the other hand, it can neither be interpreted by MATLAB, nor can it be compiled with a C++ compiler.
9  * Except for the comments, the function bodies of your M-file functions are untouched.
10  * Consequently, the FILTER_SOURCE_FILES doxygen switch (default in our Doxyfile.template) will produce
11  * attached source files that are highly readable by humans.
12  *
13  * Additionally, links in the doxygen generated documentation to the source code of functions and class members refer to
14  * the correct locations in the source code browser.
15  * However, the line numbers most likely do not correspond to the line numbers in the original MATLAB source files.
16  */
17 
18 class BaseModel
19  :public KerMorObject {
100  public: /* ( setObservable ) */
101 
117  char Name = "";
174  logical isStatic = false;
204  public: /* ( Dependent ) */
205 
250  public: /* ( Dependent, setObservable ) */
251 
369  public:
370 
371  dtscaled = .1;
406  private:
407 
408  struct ftau = 1;
420  fdt = .1;
421 
422  fT = 1;
423 
424  frtp = false;
425 
426  fODEs;
427 
428  steplistener;
429 
430  ctime;
431 
432  fDefMu = "[]";
433 
434 
435  public:
436 
437 
439 
440  /* Call superclass constructor first
441  * (not necessary in this version as automatically called first, but one never knows..) */
442  this = this@KerMorObject;
443 
444  /* Init defaults */
445  this.ODESolver= solvers.MLWrapper(@ode23);
446 
447  /* Register default properties */
448  this.registerProps(" System "," T "," ODESolver "," dt "," G ",...
449  " tau "," RealTimePlottingMinPause "," RealTimePlotting ");
450  }
451 
452 
453  function delete() {
454  this.ODESolver= [];
455  this.System= [];
456  }
457 
458 
459  function initDefaultParameter() {
460  mu = zeros(this.System.ParamCount,1);
461  /* p = struct; */
462  for k = 1:this.System.ParamCount
463  mu(k) = this.System.Params(k).Default;
464  /* name = regexprep(this.System.Params(k).Name,'[^A-Za-z0-9_]', '_');
465  *p.(name) = k; */
466  end
467  this.fDefMu= mu;
468  /* this.ParamIdx = p; */
469  }
477  function [rowvec<double>t , matrix<double>y , doublesec , x ] = simulate(colvec<double> mu,integer inputidx) {
478  if nargin < 3
479  inputidx = this.DefaultInput;
480  if nargin < 2
481  mu = this.DefaultMu;
482  end
483  end
484  /* Transpose if necessary */
485  if size(mu,2) > 1 && size(mu,1) == 1
486  mu =mu^t;
487  end
488  this.WorkspaceVariableName= inputname(1);
489 
490  if this.RealTimePlotting
491  this.ctime= tic;
492  end
493  if this.isStatic
494  /* solve static equation */
495  [t, x, time] = this.solveStatic(mu, inputidx);
496  else
497 
498  /* Get scaled state trajectory */
499  [t, x, time] = this.computeTrajectory(mu, inputidx);
500  end
501  /* Measure rest of time */
502  starttime = tic;
503 
504  /* Convert to output */
505  y = this.System.computeOutput(x);
506 
507  /* Scale times back to real units */
508  t = t*this.tau;
509 
510  sec = toc(starttime) + time;
511 
512  this.WorkspaceVariableName= ;
513  }
539  function [handlef , handleax ] = plot(rowvec<double> t,matrix<double> y,varargin) {
540  if isempty(varargin)
541  f = figure;
542  ax = gca(f);
543  else
544  ax = varargin[1];
545  f = get(ax," Parent ");
546  end
547  y = Utils.preparePlainPlot(y);
548  plot(ax,t,y);
549  title(ax,sprintf(" Output plot for model '%s' ", this.Name));
550  xlabel(ax," Time "); ylabel(ax," Output values ");
551  }
567  function [handlef , handleax ] = plotState(rowvec t,matrix<double> x,varargin) {
568  if isempty(varargin)
569  f = figure;
570  ax = gca(f);
571  else
572  ax = varargin[1];
573  f = get(ax," Parent ");
574  end
575  x = Utils.preparePlainPlot(x);
576  plot(ax,t,x);
577  title(ax,sprintf(" State space plot for model '%s' ", this.Name));
578  xlabel(ax," Time "); ylabel(ax," State space values ");
579  }
595  function [f , ax ] = plotSingle(double t,colvec<double> y,varargin) {
596  [f,ax] = this.plot(t, y, varargin[:]);
597  }
615  function plotInputs(pm) {
616  if nargin < 2
617  pm = PlotManager;
618  pm.LeaveOpen= true;
619  end
620  h = pm.nextPlot(" inputs "," Model inputs "," t "," u(t) ");
621  hold(h," on ");
622  leg = [];
623  cg = LineSpecIterator;
624  for k=1:this.System.InputCount
625  plot(h,this.Times,this.System.Inputs[k](this.scaledTimes)," Color ",cg.nextColor);
626  leg[k] = sprintf(" u_%d(t) ",k);/* #ok */
627 
628  end
629  legend(h,leg[:]);
630  pm.done;
631  }
632 
633 
634  function [doublet , colvec<double>x , doublectime ] = solveStatic(colvec<double> mu,integer inputidx) {
635  if nargin < 3
636  inputidx = [];
637  if nargin < 2
638  mu = [];
639  end
640  end
641  sys = this.System;
642  /* Stop the time */
643  st = tic;
644 
645  /* Prepare the system by setting mu and inputindex. */
646  sys.prepareSimulation(mu, inputidx);
647  t = this.scaledTimes;
648 
649  /* Prepare the right-hand side */
650  rhs = zeros(size(sys.A.evaluate(1,0),1), length(t));
651  if ~isempty(sys.B)
652  if ~sys.B.TimeDependent
653  rhs = sys.B.evaluate(0, sys.mu)*sys.u(t);
654  else
655  for tdx = 1:length(t)
656  rhs(:,tdx) = sys.B.evaluate(t(tdx), sys.mu)*sys.u(t(tdx));
657  end
658  end
659  end
660  if ~isempty(sys.f)
661  rhs = rhs + sys.f.evaluateMulti(zeros(sys.f.xDim,0), t, repmat(sys.mu,1,length(t)));
662  end
663 
664  /* solve the system A*x + rhs = 0 for x */
665  if ~sys.A.TimeDependent
666  /* precompute lu decomposition */
667  [l,u] = lu(sys.A.evaluate(1,0,sys.mu));
668  x = -u\(l\rhs);
669  else
670  x = zeros(sys.A.xDim, length(t));
671  for tdx = 1:length(t)
672  x(:,tdx) = -sys.A.evaluate(1,t(tdx),sys.mu)\rhs(:,tdx);
673  end
674  end
675 
676  ctime = toc(st);
677  }
691  function [rowvec<double>t , matrix<double>x , doublectime ] = computeTrajectory(colvec<double> mu,integer inputidx) {
692  if nargin < 3
693  inputidx = this.DefaultInput;
694  if nargin < 2
695  mu = this.DefaultMu;
696  end
697  end
698  sys = this.System;
699 
700  /* Stop the time */
701  st = tic;
702 
703  /* Prepare the system by setting mu and inputindex. */
704  sys.prepareSimulation(mu, inputidx);
705 
706  /* Check explicit solvers */
707  if isempty(this.System.MaxTimestep) && this.fODEs.SolverType ~= solvers.SolverTypes.Implicit
708  warning(" Attention: Using an non-implicit solver without System.MaxTimestep set. Please check. ");
709  end
710 
711  /* % Solve ODE */
712  slv = this.ODESolver;
713  slv.MaxStep= []; slv.InitialStep= [];
714  if ~isempty(sys.MaxTimestep)
715  /* Remember: When scaling is used, these are the */
716  slv.MaxStep= sys.MaxTimestep/this.tau;
717  slv.InitialStep= .5*sys.MaxTimestep/this.tau;
718  end
719 
720  /* Assign jacobian information if available */
721  if isa(slv," solvers.AJacobianSolver ")
722  slv.JPattern= sys.SparsityPattern;
723  slv.JacFun= @sys.getJacobian;
724  end
725 
726  /* Assign mass matrix to solver if present */
727  slv.M= [];
728  if ~isempty(sys.M)
729  slv.M= sys.getMassMatrix;
730  end
731 
732  /* Call solver */
733  [t, x] = slv.solve(@sys.ODEFun, this.scaledTimes, sys.getX0(mu));
734 
735  if length(this.scaledTimes) == 2
736  t = [t(1), t(end)];
737  x = [x(:,1), x(:,end)];
738  end
739 
740  /* Get used time */
741  ctime = toc(st);
742  }
763  function matrix<double>mu = getRandomParam(integer num,integer seed) {
764  if nargin < 3
765  seed = round(cputime*100);
766  if nargin < 2
767  num = 1;
768  end
769  end
770  s = this.System;
771  r = RandStream(" mt19937ar "," Seed ",seed);
772  if s.ParamCount > 0
773  pmin = [s.Params(:).MinVal]^t;
774  pmax = [s.Params(:).MaxVal]^t;
775  mu = r.rand(s.ParamCount,num) .* repmat(pmax-pmin,1,num) + repmat(pmin,1,num);
776  else
777  mu = [];
778  end
779  }
797  protected:
798 
799 
800  function this = saveobj() {
802  }
812  protected: /* ( Static ) */
813 
814  static function this = loadobj(this,s) {
815  if ~isa(this," models.BaseModel ") && nargin < 2
816  error(" The model class has changed but the loadobj method does not implement backwards-compatible loading behaviour.\nPlease implement the loadobj-method in your subclass and pass the loaded object struct as second argument. ");
817  end
818  if nargin == 2
819  this.System= s.System;
820  this.Name= s.Name;
821  this.G= s.G;
822  this.RealTimePlottingMinPause= s.RealTimePlottingMinPause;
823  this.ftau= s.ftau;
824  this.fdt= s.fdt;
825  this.fT= s.fT;
826  this.frtp= s.frtp;
827  this.fODEs= s.fODEs;
828  this.steplistener= s.steplistener;
829  this.ctime= s.ctime;
830  this.dtscaled= s.dtscaled;
831  this.gitRefOnSave= s.gitRefOnSave;
832  if isfield(s," DefaultMu ")
833  this.DefaultMu= s.DefaultMu;
834  this.DefaultInput= s.DefaultInput;
835  end
836  end
837  this = loadobj@DPCMObject(this);
838  }
839 
840 
841  protected: /* ( Sealed ) */
842 
843  function plotstep(src,ed) {
844  y = this.System.computeOutput(ed.States);
845  this.plotSingle(ed.Times * this.tau,y);
846  drawnow;
847  /* Gets first set in "simulate" */
848  per = toc(this.ctime);
849  pause(max(0,this.RealTimePlottingMinPause-per));
850  this.ctime= tic;
851  }
865  /* % Getter & Setter */
866  public:
867 
868 
869 #if 0 //mtoc++: 'get.Times'
870 function value = Times() {
871  value = 0:this.dt:this.T;
872  }
873 
874 #endif
875 
876 
877 
878 #if 0 //mtoc++: 'get.scaledTimes'
879 function value = scaledTimes() {
880  value = 0:this.dtscaled:this.Tscaled;
881  }
882 
883 #endif
884 
885 
886 
887 #if 0 //mtoc++: 'get.Tscaled'
888 function value = Tscaled() {
889  if isempty(this.tau)
890  value = this.T;
891  else
892  value = this.T/this.tau;
893  end
894  }
895 
896 #endif
897 
898 
899 
900 #if 0 //mtoc++: 'get.dt'
901 function dt = dt() {
902  dt = this.fdt;
903  }
904 
905 #endif
906 
907 
908 
909 #if 0 //mtoc++: 'get.tau'
910 function tau = tau() {
911  tau = this.ftau;
912  }
913 
914 #endif
915 
916 
917 
918 #if 0 //mtoc++: 'set.T'
919 function T(value) {
920  if ~isscalar(value) || value < 0
921  error(" T must be a positive real scalar. ");
922  elseif value < this.fdt
923  warning(" Timestep dt must be smaller or equal to T. Using dt=%g ",value/2);
924  this.fdt= value/2;
925  end
926  if value ~= this.fT
927  this.fT= value;
928  end
929  }
930 
931 #endif
932 
933 
934 
935 #if 0 //mtoc++: 'set.dt'
936 function dt(value) {
937  if ~isscalar(value) || value <= 0
938  error(" dt must be a positive real scalar. ");
939  elseif value > this.fT
940  error(" Timestep dt must be smaller or equal to T. ");
941  end
942  if this.fdt ~= value
943  this.dtscaled= value/this.ftau;
944  this.fdt= value;
945  end
946  }
947 
948 #endif
949 
950 
951 
952 #if 0 //mtoc++: 'set.tau'
953 function tau(value) {
954  if ~isreal(value) ||~isscalar(value)
955  error(" tau must be a positive real scalar. ");
956  end
957  if this.ftau ~= value
958  this.dtscaled= this.fdt/value;
959  this.ftau= value;
960  end
961  }
962 
963 #endif
964 
965 
966 
967 #if 0 //mtoc++: 'set.System'
968 function System(value) {
969  if ~isempty(value) && ~isa(value," models.BaseFirstOrderSystem ")
970  error(" The System property must be a subclass of models.BaseFirstOrderSystem. ");
971  end
972  if (isequal(this,value))
973  warning(" KerMor:selfReference "," Careful with self-referencing classes. See BaseFullModel class documentation for details. ");
974  end
975  this.System= value;
976  }
977 
978 #endif
979 
987 #if 0 //mtoc++: 'set.G'
988 function G(value) {
989  if isempty(value)
990  error(" G must not be empty. Use G=1 for default euclidean scalar product and norms ");
991  elseif any(abs(value-value^t) > eps)
992  error(" G must be symmetric. ");
993  end
994  this.G= value;
995  }
996 
997 #endif
998 
1005 #if 0 //mtoc++: 'set.ODESolver'
1006 function ODESolver(value) {
1007  this.checkType(value," solvers.BaseSolver ");
1008  /* Add listener if new ODE solver is passed and real time
1009  * plotting is turned on. */
1010  if this.frtp && this.fODEs ~= value
1011  if ~isempty(this.steplistener)
1012  delete(this.steplistener);
1013  end
1014  this.steplistener= value.addlistener(" StepPerformed ",@this.plotstep);
1015  end
1016  this.fODEs= value;
1017  }
1018 
1019 #endif
1020 
1021 
1022 
1023 #if 0 //mtoc++: 'get.ODESolver'
1024 function value = ODESolver() {
1025  value = this.fODEs;
1026  }
1027 
1028 #endif
1029 
1030 
1031 
1032 #if 0 //mtoc++: 'set.Name'
1033 function Name(value) {
1034  if ~ischar(value)
1035  error(" name is acharacter field ");
1036  end
1037  this.Name= value;
1038  }
1039 
1040 #endif
1041 
1042 
1043 
1044 #if 0 //mtoc++: 'get.RealTimePlotting'
1045 function value = RealTimePlotting() {
1046  value = this.frtp;
1047  }
1048 
1049 #endif
1050 
1051 
1052 
1053 #if 0 //mtoc++: 'get.T'
1054 function value = T() {
1055  value = this.fT;
1056  }
1057 
1058 #endif
1059 
1060 
1061 
1062 #if 0 //mtoc++: 'set.RealTimePlotting'
1063 function RealTimePlotting(value) {
1064  if ~islogical(value)
1065  error(" Value must be boolean. ");
1066  end
1067  if value
1068  if isempty(this.steplistener)
1069  this.steplistener= this.ODESolver.addlistener(" StepPerformed ",@this.plotstep);
1070  end
1071  else
1072  if ~isempty(this.steplistener)
1073  delete(this.steplistener);
1074  this.steplistener= [];
1075  end
1076  end
1077  this.frtp= value;
1078  }
1079 
1080 #endif
1081 
1082 
1083 
1084 #if 0 //mtoc++: 'set.DefaultMu'
1085 function DefaultMu(colvec<double> mu) {
1086  if size(mu,2) > 1
1087  error(" Default param must be a column vector ");
1088  end
1089  this.fDefMu= mu;
1090  }
1091 
1092 #endif
1093 
1094 
1095 
1096 #if 0 //mtoc++: 'get.DefaultMu'
1097 function colvec<double>mu = DefaultMu() {
1098  if isempty(this.fDefMu)
1099  this.initDefaultParameter;
1100  end
1101  mu = this.fDefMu;
1102  }
1103 
1104 #endif
1105 
1158 };
1159 }
1160 
1161 
1162 
char Name
The name of the Model.
Definition: BaseModel.m:117
Collection of generally useful functions.
Definition: Utils.m:17
WorkspaceVariableName
The workspace variable name of this class. Optional.
Definition: DPCMObject.m:48
Params
The parameters usable for the dynamical system.
BaseModel: Base class for both full and reduced models.
Definition: BaseModel.m:18
logical isStatic
Determines if the model is time dependent or static.
Definition: BaseModel.m:174
double dt
The desired time-stepsize for simulations.
Definition: BaseModel.m:291
models.BaseFirstOrderSystem System
The actual dynamical system used in the model.
Definition: BaseModel.m:102
Times
Evaluation points of the model.
Definition: BaseModel.m:206
A double value.
Base class for any KerMor class.
Definition: KerMorObject.m:17
function this = saveobj()
Store the current GIT branch in the object.
Definition: BaseModel.m:800
function registerProps(varargin)
Call this method at any class that defines DPCM observed properties.
Definition: DPCMObject.m:125
matrix< double > G
The custom scalar product matrix .
Definition: BaseModel.m:132
logical RealTimePlotting
Determines if the simulation should plot intermediate steps during computation.
Definition: BaseModel.m:335
An integer value.
DPCMObject()
Creates a new DPCM object.
Definition: DPCMObject.m:101
PlotManager: Small class that allows the same plots generated by some script to be either organized a...
Definition: PlotManager.m:17
A boolean value.
logical LeaveOpen
Flag indicating if the plots should be left open once the PlotManager is deleted (as variable) ...
Definition: PlotManager.m:213
KerMorObject()
Constructs a new KerMor object.
Definition: KerMorObject.m:55
A variable number of input arguments.
double tau
Time scaling factor .
Definition: BaseModel.m:252
solvers.BaseSolver ODESolver
The solver to use for the ODE. Must be an instance of any solvers.BaseSolver subclass.
Definition: BaseModel.m:315
function [ f , ax ] = plotSingle(double t,colvec< double > y, varargin)
Plots a single solution. Override in subclasses for specific plot behaviour.
Definition: BaseModel.m:595
double MaxStep
Maximum time step for solver.
Definition: BaseSolver.m:48
integer DefaultInput
The default input to use if none is given.
Definition: BaseModel.m:189
InputCount
The number of inputs available.
Inputs
The system's possible input functions. A cell array of function handles, each taking a time argument ...
function delete()
Definition: BaseModel.m:453
static function b = getGitBranch(dir)
Returns the current git commit in a descriptive string.
Definition: KerMor.m:1039
double Tscaled
The scaled end time .
Definition: BaseModel.m:234
double RealTimePlottingMinPause
Minimum pause between successive steps when RealTimePlotting is enabled.
Definition: BaseModel.m:156
double T
The final timestep up to which to simulate.
Definition: BaseModel.m:271
function prepareSimulation(colvec< double > mu,integer inputidx)
dtscaled
The scaled timestep .
Definition: BaseModel.m:371
function checkType(obj, type)
Object typechecker.
Definition: KerMorObject.m:122
colvec< double > DefaultMu
The default parameter value if none is given.
Definition: BaseModel.m:355
function [ double t , colvec< double > x , double ctime ] = solveStatic(colvec< double > mu,integer inputidx)
Solves the linear system . Spatial dependence of f is neglected in the current implementation (since ...
Definition: BaseModel.m:634
static function this = loadobj(this, s)
Definition: BaseModel.m:814
ParamCount
The number of the system's parameters.
rowvec< double > scaledTimes
The time steps Times in scaled time units .
Definition: BaseModel.m:218
function y = computeOutput(matrix< double > x,colvec< double > mu)
Computes the output from a given state result vector , using the system's time and current mu (if gi...
function [ handle f , handle ax ] = plot(rowvec< double > t,matrix< double > y, varargin)
Plots the results of the simulation. Override in subclasses for a more specific plot if desired...
Definition: BaseModel.m:539
function plotInputs(pm)
Definition: BaseModel.m:615
Global configuration class for all KerMor run-time settings.
Definition: KerMor.m:17
Base class for all KerMor ODE solvers.
Definition: BaseSolver.m:18
function [ rowvec< double > t , matrix< double > x , double ctime ] = computeTrajectory(colvec< double > mu,integer inputidx)
Computes a solution/trajectory for the given mu and inputidx in the SCALED state space.
Definition: BaseModel.m:691
function initDefaultParameter()
Reads the default values of the System's ModelParam list and initializes the BaseModel.DefaultMu with it.
Definition: BaseModel.m:459
function [ handle f , handle ax ] = plotState(rowvec t,matrix< double > x, varargin)
Plots the results of the simulation. Override in subclasses for a more specific plot if desired...
Definition: BaseModel.m:567
A MatLab struct.
LinSpecIterator: Small helper class to automatically iterate through different line styles/markers/co...
addlistener
Creates a listener for the specified event and assigns a callback function to execute when the event ...
A MatLab character array.
double MaxTimestep
The maximum timestep allowed for any ODE solvers.
Base class for all KerMor first-order dynamical systems.
function matrix< double > mu = getRandomParam(integer num,integer seed)
Gets a random parameter sample from the system's parameter domain P.
Definition: BaseModel.m:763
char gitRefOnSave
Contains the GIT revision of this model when it was last saved.
Definition: BaseModel.m:390
function plotstep(src, ed)
Callback for the ODE solvers StepPerformed event that enables during-simulation-plotting.
Definition: BaseModel.m:843
function [ rowvec< double > t , matrix< double > y , double sec , x ] = simulate(colvec< double > mu,integer inputidx)
Simulates the system and produces the system's output.
Definition: BaseModel.m:477
static function y = preparePlainPlot(y)
Memory-saving plotting for plain result plots.
Definition: Utils.m:297