comparison scripts/ode/odeset.m @ 20585:45151de7423f

maint: Clean up implementations of ode45.m, odeget.m, odeset.m. * ode45.m: Match variable names in function to docstring. Don't use '...' line continuation unless strictly necessary. Remove incorrect isa check for inline function. Use '( )' around switch statement test variable. Use printf, rather than fprintf, where possible. * odeget.m: Match variable names in function to docstring. Rephrase error messages to begin with 'odeget:'. Use try/catch blocks to speed up "fast" and "fast_not_empty" code. Use rows() rather than "size (xxx, 1)". Use isempty rather than "size (xxx, 1) == 0". Use printf, rather than fprintf, where possible. Use unwind_protect block in BIST tests to restore warning state. * odeset.m: Match variable names in function to docstring. Use rows() rather than "size (xxx, 1)". Use isempty rather than "size (xxx, 1) == 0". Use printf, rather than fprintf, where possible. Eliminate for loop with cell2struct for odestruct initialization. Introduce temporary vars oldstruct, newstruct to clarify code. Restate some error messages to begin with 'odeset:'. Use cellfun to quickl check that all field inputs are strings. Use unwind_protect block in BIST tests to restore warning state.
author Rik <rik@octave.org>
date Mon, 05 Oct 2015 11:59:18 -0700
parents e368ce72a844
children e5f36a7854a5
comparison
equal deleted inserted replaced
20584:eb9e2d187ed2 20585:45151de7423f
47 ## from the structure @var{newstruct}. Empty values of @var{newstruct} will 47 ## from the structure @var{newstruct}. Empty values of @var{newstruct} will
48 ## not overwrite values in @var{oldstruct}. 48 ## not overwrite values in @var{oldstruct}.
49 ## @seealso{odeget} 49 ## @seealso{odeget}
50 ## @end deftypefn 50 ## @end deftypefn
51 51
52 function opt = odeset (varargin) 52 function odestruct = odeset (varargin)
53 53
54 ## Check number and types of all input arguments 54 ## Special calling syntax to display defaults
55 if (nargin == 0 && nargout == 0) 55 if (nargin == 0 && nargout == 0)
56 print_options; 56 print_options ();
57 return; 57 return;
58 endif 58 endif
59 59
60 ## Creating a vector of OdePkg possible fields 60 ## Column vector of all possible OdePkg fields
61 fields = ["AbsTol"; "Algorithm"; "BDF"; "Choice"; "Eta"; "Events"; 61 fields = ["AbsTol"; "Algorithm"; "BDF"; "Choice"; "Eta"; "Events";
62 "Explicit"; "InexactSolver"; "InitialSlope"; "InitialStep"; 62 "Explicit"; "InexactSolver"; "InitialSlope"; "InitialStep";
63 "Jacobian";"JConstant";"JPattern";"Mass"; "MassConstant"; 63 "Jacobian";"JConstant";"JPattern";"Mass"; "MassConstant";
64 "MassSingular"; "MaxNewtonIterations"; "MaxOrder"; "MaxStep"; 64 "MassSingular"; "MaxNewtonIterations"; "MaxOrder"; "MaxStep";
65 "MStateDependence"; "MvPattern"; "NewtonTol"; "NonNegative"; 65 "MStateDependence"; "MvPattern"; "NewtonTol"; "NonNegative";
66 "NormControl"; "OutputFcn"; "OutputSave"; "OutputSel"; 66 "NormControl"; "OutputFcn"; "OutputSave"; "OutputSel";
67 "PolynomialDegree"; "QuadratureOrder"; "Refine"; "RelTol"; 67 "PolynomialDegree"; "QuadratureOrder"; "Refine"; "RelTol";
68 "Restart"; "Stats"; "TimeStepNumber"; "TimeStepSize"; 68 "Restart"; "Stats"; "TimeStepNumber"; "TimeStepSize";
69 "UseJacobian"; "Vectorized"]; 69 "UseJacobian"; "Vectorized"];
70 70
71 fields_nb = size (fields, 1); 71 fields_nb = rows (fields);
72 72
73 ## initialize output 73 ## initialize output
74 opt = []; 74 odestruct = cell2struct (cell (rows (fields), 1), cellstr (fields));
75 for i = 1:1:fields_nb 75
76 opt.(deblank (fields(i,:))) = []; 76 odestruct.Refine = 0;
77 endfor 77 odestruct.OutputSave = 1;
78
79 opt.Refine = 0;
80 opt.OutputSave = 1;
81 78
82 if (nargin == 0 && nargout == 1) 79 if (nargin == 0 && nargout == 1)
83 return; 80 return;
84 endif 81 endif
85 82
86 ode_fields = fieldnames (opt); 83 ode_fields = fieldnames (odestruct);
87 84
88 if (isstruct (varargin{1})) 85 if (isstruct (varargin{1}))
89 ode_struct_value_check (varargin{1}); 86 oldstruct = varargin{1};
90 87 ode_struct_value_check (oldstruct);
91 optA_fields = fieldnames (varargin{1}); 88
89 optA_fields = fieldnames (oldstruct);
92 optA_f_nb = length (optA_fields); 90 optA_f_nb = length (optA_fields);
93 91
94 ## loop on first struct options for updating 92 ## loop on first struct options for updating
95 for i = 1:optA_f_nb 93 for i = 1:optA_f_nb
96 name = lower (deblank (optA_fields{i})); 94 name = lower (deblank (optA_fields{i}));
97 95
98 while (1) 96 while (1)
99 pos = fuzzy_compare (name, fields); 97 pos = fuzzy_compare (name, fields);
100 if (size (pos, 1) == 0) 98 if (isempty (pos))
101 warning ("OdePkg:InvalidArgument", 99 warning ("OdePkg:InvalidArgument",
102 "no property found with name '%s'", name); 100 "no property found with name '%s'", name);
103 endif 101 endif
104 102
105 if (size (pos, 1) == 1) 103 if (rows (pos) == 1)
106 if (! strcmp (lower (deblank (name)), 104 if (! strcmp (lower (deblank (name)),
107 lower (deblank (fields(pos,:))))) 105 lower (deblank (fields(pos,:)))))
108 warning ("OdePkg:InvalidArgument", "no exact matching for ", 106 warning ("OdePkg:InvalidArgument", "no exact matching for ",
109 "'%s'. Assuming you were intending '%s'", 107 "'%s'. Assuming you were intending '%s'",
110 name, deblank (fields(pos,:))); 108 name, deblank (fields(pos,:)));
111 endif 109 endif
112 110
113 opt.(deblank (fields(pos,:))) = varargin{1}.(optA_fields{i}); 111 odestruct.(deblank (fields(pos,:))) = oldstruct.(optA_fields{i});
114 break 112 break;
115 endif 113 endif
116 114
115 ## FIXME: Do we really need interactive selection?
117 ## if there are more matching, ask the user to be more precise 116 ## if there are more matching, ask the user to be more precise
118 warning ("OdePkg:InvalidArgument", 117 warning ("OdePkg:InvalidArgument",
119 "no exact matching for '%s'. %d possible fields were found", 118 "no exact matching for '%s'. %d possible fields were found",
120 name, size(pos, 1)); 119 name, size(pos, 1));
121 for j = 1:(size (pos, 1)) 120 for j = 1:(rows (pos))
122 fprintf ("%s\n", deblank (fields(pos(j),:))); 121 printf ("%s\n", deblank (fields(pos(j),:)));
123 endfor 122 endfor
124 do 123 do
125 fprintf ("Please insert field name again\n"); 124 disp ("Please insert field name again");
126 name = input ("New field name: "); 125 name = input ("New field name: ");
127 until (ischar (name)) 126 until (ischar (name))
128 endwhile 127 endwhile
129 endfor 128 endfor
130 129
131 if (nargin == 2 && isstruct (varargin{2})) 130 if (nargin == 2 && isstruct (varargin{2}))
132 ode_struct_value_check (varargin{2}); 131 newstruct = varargin{2};
133 132 ode_struct_value_check (newstruct);
134 optB_fields = fieldnames (varargin{2}); 133
134 optB_fields = fieldnames (newstruct);
135 optB_f_nb = length (optB_fields); 135 optB_f_nb = length (optB_fields);
136 136
137 ## update the first struct with the values in the second one 137 ## update the first struct with the values in the second one
138 for i = 1:optB_f_nb 138 for i = 1:optB_f_nb
139 name = lower (deblank (optB_fields{i})); 139 name = lower (deblank (optB_fields{i}));
140 while (1) 140 while (1)
141 pos = fuzzy_compare (name, fields); 141 pos = fuzzy_compare (name, fields);
142 142
143 if (size (pos, 1) == 0) 143 if (isempty (pos))
144 warning ("OdePkg:InvalidArgument", ... 144 warning ("OdePkg:InvalidArgument",
145 "no property found with name '%s'", name); 145 "no property found with name '%s'", name);
146 endif 146 endif
147 147
148 if (size(pos, 1) == 1) 148 if (rows (pos) == 1)
149 if (! strcmp (lower (deblank (name)), ... 149 if (! strcmp (lower (deblank (name)),
150 lower (deblank (fields(pos,:))))) 150 lower (deblank (fields(pos,:)))))
151 warning ("OdePkg:InvalidArgument", "no exact matching for ", 151 warning ("OdePkg:InvalidArgument", "no exact matching for ",
152 "'%s'. Assuming you were intending '%s'", 152 "'%s'. Assuming you were intending '%s'",
153 name, deblank (fields(pos,:))); 153 name, deblank (fields(pos,:)));
154 endif 154 endif
155 opt.(deblank (fields(pos,:))) = varargin{2}.(optB_fields{i}); 155 odestruct.(deblank (fields(pos,:))) = newstruct.(optB_fields{i});
156 break 156 break;
157 endif 157 endif
158 158
159 ## FIXME: Do we really need interactive selection?
159 ## if there are more matching, ask the user to be more precise 160 ## if there are more matching, ask the user to be more precise
160 warning ("OdePkg:InvalidArgument", "no exact matching for '%s'. ", 161 warning ("OdePkg:InvalidArgument", "no exact matching for '%s'. ",
161 "%d possible fields were found", 162 "%d possible fields were found",
162 name, size (pos, 1)); 163 name, rows (pos));
163 for j = 1:(size (pos, 1)) 164 for j = 1:(rows (pos))
164 fprintf ("%s\n", deblank (fields(pos(j),:))); 165 printf ("%s\n", deblank (fields(pos(j),:)));
165 endfor 166 endfor
166 do 167 do
167 fprintf ("Please insert field name again\n"); 168 disp ("Please insert field name again");
168 name = input ("New field name: "); 169 name = input ("New field name: ");
169 until (ischar (name)) 170 until (ischar (name))
170 endwhile 171 endwhile
171 endfor 172 endfor
172 return; 173 return;
173 endif 174 endif
174 175
175 ## if the second argument is not a struct, 176 ## if the second argument is not a struct,
176 ## pass new values of the OdePkg options to the first struct 177 ## pass new values of the OdePkg options to the first struct
177 if (mod (nargin, 2) != 1) 178 if (mod (nargin, 2) != 1)
178 error ("OdePkg:InvalidArgument", 179 error ("odeset: FIELD/VALUE arguments must occur in pairs");
179 "odeset expects an odd number of input arguments", 180 endif
180 " when the first is a ODE_STRUCT"); 181
182 if (! all (cellfun ("isclass", varargin(2:2:end), "char")))
183 error ("odeset: All FIELD names must be strings");
181 endif 184 endif
182 185
183 ## loop on the input arguments 186 ## loop on the input arguments
184 for i = 2:2:(nargin - 1) 187 for i = 2:2:(nargin - 1)
185
186 if (! ischar(varargin{i}))
187 error ("OdePkg:InvalidArgument",
188 "not all odd input arguments are strings");
189 endif
190
191 name = varargin{i}; 188 name = varargin{i};
192 189
193 while (1) 190 while (1)
194 pos = fuzzy_compare (name, fields); 191 pos = fuzzy_compare (name, fields);
195 192
196 if (size (pos, 1) == 0) 193 if (isempty (pos))
197 error ("OdePkg:InvalidArgument", 194 error ("OdePkg:InvalidArgument",
198 "no property found with name '%s'", name); 195 "no property found with name '%s'", name);
199 endif 196 endif
200 197
201 if (size (pos, 1) == 1) 198 if (rows (pos) == 1)
202 if (! strcmp (lower (deblank (name)), lower (deblank (fields(pos,:))))) 199 if (! strcmp (lower (deblank (name)),
200 lower (deblank (fields(pos,:)))))
203 warning ("OdePkg:InvalidArgument", "no exact matching for '%s'. ", 201 warning ("OdePkg:InvalidArgument", "no exact matching for '%s'. ",
204 "%d possible fields were found", 202 "%d possible fields were found",
205 name, size (pos, 1)); 203 name, rows (pos));
206 endif 204 endif
207 opt.(deblank (fields(pos,:))) = varargin{i+1}; 205 odestruct.(deblank (fields(pos,:))) = varargin{i+1};
208 break 206 break;
209 endif 207 endif
210 208
209 ## FIXME: Do we really need interactive selection?
211 ## if there are more matching, ask the user to be more precise 210 ## if there are more matching, ask the user to be more precise
212 warning ("OdePkg:InvalidArgument", "no exact matching for '%s'. ", 211 warning ("OdePkg:InvalidArgument", "no exact matching for '%s'. ",
213 "%d possible fields were found", 212 "%d possible fields were found",
214 name, size (pos, 1)); 213 name, rows (pos));
215 for j = 1:(size (pos, 1)) 214 for j = 1:(rows (pos))
216 fprintf ("%s\n", deblank (fields(pos(j),:))); 215 printf ("%s\n", deblank (fields(pos(j),:)));
217 endfor 216 endfor
218 do 217 do
219 fprintf ("Please insert field name again\n"); 218 disp ("Please insert field name again");
220 name = input ("New field name: "); 219 name = input ("New field name: ");
221 until (ischar (name)) 220 until (ischar (name))
222 endwhile 221 endwhile
223 endfor 222 endfor
224 223
225 ## check if all has been done gives a valid OdePkg struct 224 ## check if all has been done gives a valid OdePkg struct
226 ode_struct_value_check (opt); 225 ode_struct_value_check (odestruct);
227 return; 226 return;
228 endif 227 endif
229 228
230 ## first input argument was not a struct 229 ## first input argument was not a struct
231 if (mod (nargin, 2) != 0) 230 if (mod (nargin, 2) != 0)
232 error ("OdePkg:InvalidArgument", "odeset expects an even number ", 231 error ("odeset: FIELD/VALUE arguments must occur in pairs");
233 "of input arguments when the first is a string"); 232 endif
233
234 if (! all (cellfun ("isclass", varargin(1:2:end), "char")))
235 error ("odeset: All FIELD names must be strings");
234 endif 236 endif
235 237
236 for i = 1:2:(nargin-1) 238 for i = 1:2:(nargin-1)
237 if (! ischar (varargin{i}))
238 error ("OdePkg:InvalidArgument",
239 "not all even input arguments are strings");
240 endif
241
242 name = varargin{i}; 239 name = varargin{i};
243 240
244 while (1) 241 while (1)
245 pos = fuzzy_compare (name, fields); 242 pos = fuzzy_compare (name, fields);
246 243
247 if (size (pos, 1) == 0) 244 if (isempty (pos))
248 error ("OdePkg:InvalidArgument", 245 error ("OdePkg:InvalidArgument",
249 "invalid property. No property found with name '%s'", name); 246 "invalid property. No property found with name '%s'", name);
250 endif 247 endif
251 248
252 if (size (pos, 1) == 1) 249 if (rows (pos) == 1)
253 if (! strcmp (lower (deblank (name)), 250 if (! strcmp (lower (deblank (name)),
254 lower (deblank (fields(pos,:))))) 251 lower (deblank (fields(pos,:)))))
255 warning ("OdePkg:InvalidArgument", "no exact matching for ", 252 warning ("OdePkg:InvalidArgument", "no exact matching for ",
256 "'%s'. Assuming you were intending '%s'", 253 "'%s'. Assuming you were intending '%s'",
257 name, deblank (fields(pos,:))); 254 name, deblank (fields(pos,:)));
258 endif 255 endif
259 opt.(deblank (fields(pos,:))) = varargin{i+1}; 256 odestruct.(deblank (fields(pos,:))) = varargin{i+1};
260 break 257 break;
261 endif 258 endif
262 259
260 ## FIXME: Do we really need interactive selection?
263 ## if there are more matching, ask the user to be more precise 261 ## if there are more matching, ask the user to be more precise
264 warning ("OdePkg:InvalidArgument", "no exact matching for '%s'. ", 262 warning ("OdePkg:InvalidArgument", "no exact matching for '%s'. ",
265 "%d possible fields were found", 263 "%d possible fields were found",
266 name, size (pos, 1)); 264 name, rows (pos));
267 for j = 1:(size (pos, 1)) 265 for j = 1:rows (pos)
268 fprintf ("%s\n", deblank (fields(pos(j),:))); 266 printf ("%s\n", deblank (fields(pos(j),:)));
269 endfor 267 endfor
270 do 268 do
271 fprintf ("Please insert field name again\n"); 269 disp ("Please insert field name again");
272 name = input ("New field name: "); 270 name = input ("New field name: ");
273 until (ischar (name)) 271 until (ischar (name))
274 endwhile 272 endwhile
275 endfor 273 endfor
276 274
277 ## check if all has been done gives a valid OdePkg struct 275 ## check if all has been done gives a valid OdePkg struct
278 ode_struct_value_check (opt); 276 ode_struct_value_check (odestruct);
279 277
280 endfunction 278 endfunction
281 279
282 ## function useful to print all the possible options 280 ## function useful to print all the possible options
283 function print_options () 281 function print_options ()
284 282
285 printf ("These following are all possible options.\n", 283 disp ("These following are all possible options.");
286 "Default values are put in square brackets.\n\n"); 284 disp ("Default values are put in square brackets.");
287 285 disp ("");
288 disp (" AbsTol: scalar or vector, >0, [1.e-6]"); 286 disp (" AbsTol: scalar or vector, >0, [1e-6]");
289 disp (" Algorithm: string, {['gmres'], 'pcg', 'bicgstab'}"); 287 disp (" Algorithm: string, {['gmres'], 'pcg', 'bicgstab'}");
290 disp (" BDF: binary, {'on', ['off']}"); 288 disp (" BDF: binary, {'on', ['off']}");
291 disp (" Choice: switch, {[1], 2}"); 289 disp (" Choice: switch, {[1], 2}");
292 disp (" Eta: scalar, >=0, <1, [0.5]"); 290 disp (" Eta: scalar, >=0, <1, [0.5]");
293 disp (" Events: function_handle, []"); 291 disp (" Events: function_handle, []");
299 disp (" JConstant: binary, {'on', ['off']}"); 297 disp (" JConstant: binary, {'on', ['off']}");
300 disp (" JPattern: sparse matrix, []"); 298 disp (" JPattern: sparse matrix, []");
301 disp (" Mass: matrix or function_handle, []"); 299 disp (" Mass: matrix or function_handle, []");
302 disp (" MassConstant: binary, {'on', ['off']}"); 300 disp (" MassConstant: binary, {'on', ['off']}");
303 disp (" MassSingular: switch, {'yes', ['maybe'], 'no'}"); 301 disp (" MassSingular: switch, {'yes', ['maybe'], 'no'}");
304 disp ("MaxNewtonIterations: scalar, integer, >0, [1.e3]"); 302 disp ("MaxNewtonIterations: scalar, integer, >0, [1e3]");
305 disp (" MaxOrder: switch, {1, 2, 3, 4, [5]}"); 303 disp (" MaxOrder: switch, {1, 2, 3, 4, [5]}");
306 disp (" MaxStep: scalar, >0, []"); 304 disp (" MaxStep: scalar, >0, []");
307 disp (" MStateDependence: switch, {'none', ['weak'], 'strong'}"); 305 disp (" MStateDependence: switch, {'none', ['weak'], 'strong'}");
308 disp (" MvPattern: sparse matrix, []"); 306 disp (" MvPattern: sparse matrix, []");
309 disp (" NewtonTol: scalar or vector, >0, []"); 307 disp (" NewtonTol: scalar or vector, >0, []");
313 disp (" OutputSave: scalar, integer, >0, []"); 311 disp (" OutputSave: scalar, integer, >0, []");
314 disp (" OutputSel: scalar or vector, []"); 312 disp (" OutputSel: scalar or vector, []");
315 disp (" PolynomialDegree: scalar, integer, >0, []"); 313 disp (" PolynomialDegree: scalar, integer, >0, []");
316 disp (" QuadratureOrder: scalar, integer, >0, []"); 314 disp (" QuadratureOrder: scalar, integer, >0, []");
317 disp (" Refine: scalar, integer, >0, []"); 315 disp (" Refine: scalar, integer, >0, []");
318 disp (" RelTol: scalar, >0, [1.e-3]"); 316 disp (" RelTol: scalar, >0, [1e-3]");
319 disp (" Restart: scalar, integer, >0, [20]"); 317 disp (" Restart: scalar, integer, >0, [20]");
320 disp (" Stats: binary, {'on', ['off']}"); 318 disp (" Stats: binary, {'on', ['off']}");
321 disp (" TimeStepNumber: scalar, integer, >0, []"); 319 disp (" TimeStepNumber: scalar, integer, >0, []");
322 disp (" TimeStepSize: scalar, >0, []"); 320 disp (" TimeStepSize: scalar, >0, []");
323 disp (" UseJacobian: binary, {'yes', ['no']}"); 321 disp (" UseJacobian: binary, {'yes', ['no']}");
328 326
329 %!demo 327 %!demo
330 %! # A new OdePkg options structure with default values is created. 328 %! # A new OdePkg options structure with default values is created.
331 %! 329 %!
332 %! odeoptA = odeset (); 330 %! odeoptA = odeset ();
333 %! 331
334 %!demo 332 %!demo
335 %! # A new OdePkg options structure with manually set options 333 %! # A new OdePkg options structure with manually set options
336 %! # "AbsTol" and "RelTol" is created. 334 %! # for "AbsTol" and "RelTol" is created.
337 %! 335 %!
338 %! odeoptB = odeset ("AbsTol", 1e-2, "RelTol", 1e-1); 336 %! odeoptB = odeset ("AbsTol", 1e-2, "RelTol", 1e-1);
339 %! 337
340 %!demo 338 %!demo
341 %! # A new OdePkg options structure from odeoptB is created with 339 %! # A new OdePkg options structure is created from odeoptB with
342 %! # a modified value for option "NormControl". 340 %! # a modified value for option "NormControl".
343 %! 341
344 %! odeoptB = odeset ("AbsTol", 1e-2, "RelTol", 1e-1); 342 %! odeoptB = odeset ("AbsTol", 1e-2, "RelTol", 1e-1);
345 %! odeoptC = odeset (odeoptB, "NormControl", "on"); 343 %! odeoptC = odeset (odeoptB, "NormControl", "on");
346 344
347 ## All tests that are needed to check if a correct resp. valid option 345 ## All tests that are needed to check if a correct resp. valid option
348 ## has been set are implemented in ode_struct_value_check.m. 346 ## has been set are implemented in ode_struct_value_check.m.
349 %! ## Turn off output of warning messages for all tests, turn them on 347 %!test
350 %! ## again if the last test is called 348 %! wstate = warning ("off", "OdePkg:InvalidArgument");
351 %! warning ("off", "OdePkg:InvalidArgument"); 349 %! unwind_protect
352 %!test odeoptA = odeset (); 350 %! odeoptA = odeset ();
353 %!test odeoptB = odeset ("AbsTol", 1e-2, "RelTol", 1e-1); 351 %! ## FIXME: no assert check on odeoptA
354 %! if (odeoptB.AbsTol != 1e-2), error; endif 352 %! odeoptB = odeset ("AbsTol", 1e-2, "RelTol", 1e-1);
355 %! if (odeoptB.RelTol != 1e-1), error; endif 353 %! assert (odeoptB.AbsTol, 1e-2);
356 %!test odeoptB = odeset ("AbsTol", 1e-2, "RelTol", 1e-1); 354 %! assert (odeoptB.RelTol, 1e-1);
357 %! odeoptC = odeset (odeoptB, "NormControl", "on"); 355 %! odeoptC = odeset (odeoptB, "NormControl", "on");
358 %!test odeoptB = odeset ("AbsTol", 1e-2, "RelTol", 1e-1); 356 %! ## FIXME: no assert check on odeoptC
359 %! odeoptC = odeset (odeoptB, "NormControl", "on"); 357 %! odeoptD = odeset (odeoptC, odeoptB);
360 %! odeoptD = odeset (odeoptC, odeoptB); 358 %! ## FIXME: no assert check on odeoptD
361 %! 359 %! unwind_protect_cleanup
362 %! warning ("on", "OdePkg:InvalidArgument"); 360 %! warning (wstate);
363 361 %! end_unwind_protect
362