c86d8d7831a7d25c316b9204c2464c2e53fb7c07
[scilab.git] / scilab / modules / scicos / macros / scicos_auto / scicos_simulate.sci
1 //  Scicos
2 //
3 //  Copyright (C) Scilab Enterprises - 2013 - Bruno JOFRET
4 //  Copyright (C) INRIA - METALAU Project <scicos@inria.fr>
5 //  Copyright (C) 2011 - INRIA - Serge Steer
6
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 //
22 // See the file ./license.txt
23 //
24
25 function Info = scicos_simulate(scs_m, Info, updated_vars, flag, Ignb)
26     // Function for running scicos simulation in batch mode
27     // Info = scicos_simulate(scs_m[,Info][,updated_vars][,flag][,Ignb])
28     //
29     // scs_m: scicos diagram (obtained by "load file.cos"). Note that
30     // the version of file.cos must be the current version. If not, load
31     // into scicos and save.
32     //
33     // updated_vars: a scilab struct containing values of
34     // symbolic variables used in the context and Scicos blocks. This
35     // is often used to change a parameter in the diagram context. In that
36     // case, make sure that in the diagram context the variable is defined such
37     // that it can be modified. Say a variable "a" is to be defined in the
38     // context having value 1, and later in batch mode, we want to change
39     // the value of "a". In that case, in the context of the diagram place:
40     //  if ~exists('a') then a=1,end
41     // If you want then to run the simulation in batch mode using the value
42     // a=2, set:
43     // updated_vars.a=2
44     //
45     // Info: a list. It must be list() at the first call, then use output
46     // Info as input Info for the next calls. Info contains compilation and
47     // simulation information and is used to avoid recompilation when not
48     // needed.
49     //
50     // flag: string. If it equals 'nw' (no window), then blocks using
51     // graphical windows are not executed. Note that the list of such
52     // blocks must be updated as new blocks are added.
53     //
54     // Ignb : matrix of string : The name of blocks to ignore.
55     // If flag is set and equal to 'nw' then Ignb contains
56     // name of blocks that are added to the list
57     // of blocks to ignore.
58     //
59
60
61     //** check/set rhs parameters
62     //---------------------------
63     if argn(2) == 1 then
64         //scicos_simulate(scs_m)
65         Info            = list()
66         updated_vars = struct()
67         flag            = ""
68         Ignb            = ""
69     elseif argn(2) == 2 then
70         //scicos_simulate(scs_m, Info)
71         //or scicos_simulate(scs_m,updated_vars)
72         //or scicos_simulate(scs_m,flag)
73         select typeof(Info)
74         case "st" then //scicos_simulate(scs_m,updated_vars)
75             updated_vars = Info
76             Info=list()
77             ku=2
78             flag = ""
79         case "string" then //scicos_simulate(scs_m,flag)
80             flag=Info
81             Info=list()
82             kf=2
83             updated_vars = struct()
84         else  //scicos_simulate(scs_m,Info)
85             flag = ""
86             updated_vars = struct()
87             ki=2
88         end
89         Ignb = ""
90     elseif argn(2) == 3 then
91         //scicos_simulate(scs_m, Info,updated_vars) or scicos_simulate(scs_m, Info,"nw")
92         if type(updated_vars) == 10 then
93             flag = updated_vars
94             updated_vars = struct()
95         else
96             ku=3
97             flag = ""
98         end
99         Ignb = ""
100     elseif argn(2) >= 4 then
101         //scicos_simulate(scs_m, Info,updated_vars,"nw") or
102         //scicos_simulate(scs_m, Info,"nw",updated_vars)
103         ku=3;kf=4
104         if type(updated_vars) == 10 then
105             [updated_vars,flag]=(flag,updated_vars)
106             kf=3;ku=4
107         end
108         if argn(2) == 4 then Ignb = "",end
109     else
110         error(msprintf(_("%s: Wrong number of input arguments. Must be between %d and %d.\n"),...
111         "scicos_simulate", 1, 5))
112     end
113
114     //Check variable types
115     if typeof(scs_m)<>"diagram" then
116         error(msprintf(_("%s: Wrong type for input argument #%d: %s data structure expected.\n"),...
117         "scicos_simulate",1,"scs_m"))
118     end
119     if type(Info)<>15 then
120         error(msprintf(_("%s: Wrong type for input argument #%d: A list expected.\n"),..
121         "scicos_simulate",2))
122     end
123     if typeof(updated_vars)<>"st" then
124         error(msprintf(_("%s: Wrong type for input argument #%d: A list expected.\n"),...
125         "scicos_simulate",ku))
126     end
127     if and(stripblanks(flag)<>["nw" ""]) then
128         error(msprintf(_("%s: Wrong value for input argument #%d: ''%s'' expected.\n"),...
129         "scicos_simulate",kf,"nw"))
130     end
131     if type(Ignb) <> 10 then
132         error(msprintf(_("%s: Wrong type for input argument #%d: String array expected.\n"),...
133         "scicos_simulate",5))
134     end
135
136     if or(sciargs() == "-nogui")|or(sciargs() == "-nwni")  then
137         flag = "nw"
138     end
139     //**blocks to ignore requested by user
140     Ignb = matrix(Ignb,1,-1)//make it row vector
141
142     //**blocks to ignore in any cases
143     Ignore=["affich",...
144     "affich2"]
145     //**blocks to ignore with flag=="nw"
146     Ignoreb = ["bouncexy", ...
147     "cscope", ...
148     "cmscope", ...
149     "canimxy", ...
150     "canimxy3d", ...
151     "cevscpe", ...
152     "cfscope", ...
153     "cscopxy", ...
154     "cscopxy3d", ...
155     "cmatview", ...
156     "cmat3d", ...
157     "bplatform2"]
158
159     //** load the scicos function libraries
160     //------------------------------------
161
162     if exists("scicos_scicoslib")==0 then
163         load("SCI/modules/scicos/macros/scicos_scicos/lib") ;
164     end
165
166     if exists("scicos_autolib")==0 then
167         load("SCI/modules/scicos/macros/scicos_auto/lib") ;
168     end
169
170     if exists("scicos_utilslib")==0 then
171         load("SCI/modules/scicos/macros/scicos_utils/lib") ;
172     end
173
174     // Define Scicos data tables ===========================================
175     [modelica_libs, scicos_pal_libs, %scicos_with_grid, %scs_wgrid] = initial_scicos_tables();
176     // =====================================================================
177
178     //** initialize a "scicos_debug_gr" variable
179     %scicos_debug_gr = %f;
180
181
182     //** redefine some functions
183     prot = funcprot();funcprot(0);
184     do_terminate = do_terminate1
185     funcprot(prot)
186
187
188     //check version
189     current_version = get_scicos_version()
190     scicos_ver = find_scicos_version(scs_m)
191
192     //do version
193     if scicos_ver <> current_version then
194         ierr = execstr("scs_m = do_version(scs_m, scicos_ver)","errcatch")
195         if ierr <> 0 then
196             messagebox(_("Can''t convert old diagram (problem in version)"),"modal")
197             return
198         end
199     end
200
201     //** prepare from and to workspace stuff
202     //-------------------------------------
203     scicos_workspace_init()
204
205     if flag == "nw" then
206         Ignore = [Ignore,Ignoreb]
207     end
208     //add user ignored blocks if any
209     Ignore = [Ignore, Ignb]
210
211     //** retrieve Info list
212     if Info <> list() then
213         [%tcur, %cpr, alreadyran, needstart, needcompile, %state0] = Info(:)
214     else
215         %tcur = 0;
216         %cpr = list();
217         alreadyran = %f;
218         needstart = %t;
219         needcompile = 4;
220         %state0 = list();
221     end
222
223     //** set solver
224     tolerances     = scs_m.props.tol
225     solver         = tolerances(6)
226     %scicos_solver = solver
227     //** set variables of context
228     [%scicos_context, ierr] = script2var(scs_m.props.context,struct())
229     //overload %scicos_context variables with those defined by updated_vars
230     contextvars=fieldnames(%scicos_context)
231     updatedvars=fieldnames(updated_vars)
232     for k=1:size(updatedvars,"*")
233         u=updatedvars(k)
234         if or(u==contextvars) then
235             %scicos_context(u)=updated_vars(u)
236         else
237             mprintf(_("Warning the variable %s does not match any context variable name\nignored"),u)
238         end
239     end
240     if ierr == 0 then //++ no error
241         [scs_m, %cpr, needcompile, ok] = do_eval(scs_m, %cpr,%scicos_context)
242         if ~ok then
243             error(msprintf(gettext("%s: Error during block parameters evaluation.\n"), "scicos_simulate"));
244         end
245         if needcompile <> 4 & size(%cpr) > 0 then
246             %state0 = %cpr.state
247         end
248         alreadyran = %f
249     else
250         error(["Incorrect context definition, " + lasterror()])
251     end
252
253     // perform block supression only on partial compilation and full compilation
254     if needcompile > 1 then
255         need_suppress  =%t
256     else
257         need_suppress = %f
258     end
259
260     [%cpr, %state0_n, needcompile, alreadyran, ok] = do_update(%cpr, ...
261     %state0, needcompile)
262
263     if ~ok then
264         error(msprintf(gettext("%s: Error during block parameters update.\n"), "scicos_simulate"));
265     end
266
267     if or(%state0_n <> %state0) then //initial state has been changed
268         %state0 = %state0_n
269         [alreadyran, %cpr, Resume_line, TOWS_vals, Names] = do_terminate1(scs_m, %cpr)
270         choix = []
271     end
272     if (%cpr.sim.xptr($) - 1) < size(%cpr.state.x,"*") & solver < 100 then
273         warning(msprintf(_("Diagram has been compiled for implicit solver\nswitching to implicit solver.\n")))
274         solver = 100
275         tolerances(6) = solver
276     elseif (%cpr.sim.xptr($) - 1) == size(%cpr.state.x,"*") & ...
277         (or (solver == [100 101 102])) & size(%cpr.state.x,"*") <> 0 then
278         warning(msprintf(_("Diagram has been compiled for explicit solver\nswitching to explicit solver.\n")))
279         solver = 0
280         tolerances(6) = solver
281     end
282
283     if need_suppress then //this is done only once
284         for i = 1:length(%cpr.sim.funs)
285             if type(%cpr.sim.funs(i)) <> 13 then
286                 if find(%cpr.sim.funs(i)(1) == Ignore) <> [] then
287                     if (%cpr.sim.funs(i)(1) == "bplatform2") then
288                         %cpr.sim.funtyp(i) = 4; // BPLATFORM block has function type 5, so need to set it to 4, like the trash block.
289                     end
290                     %cpr.sim.funs(i)(1) = "trash";
291                 end
292             end
293         end
294     end
295
296     if needstart then //scicos initialization
297         if alreadyran then
298             [alreadyran, %cpr, Resume_line, TOWS_vals, Names] = do_terminate1(scs_m, %cpr)
299             alreadyran = %f
300         end
301         %tcur = 0
302         %cpr.state = %state0
303         tf = scs_m.props.tf;
304         if tf*tolerances == [] then
305             error(_("Simulation parameters not set:"));
306         end
307         ierr = execstr("[state, t] = scicosim(%cpr.state, %tcur, tf, %cpr.sim," + ..
308         "''start'', tolerances)","errcatch")
309         if ierr <> 0 then
310             error(_("Initialization problem:"))
311         end
312         %cpr.state = state
313     end
314
315     ierr = execstr("[state, t] = scicosim(%cpr.state, %tcur, tf, %cpr.sim," + ..
316     "''run'', tolerances)","errcatch")
317     if ierr == 0 then
318         %cpr.state = state
319         alreadyran = %t
320         if (tf - t) < tolerances(3) then
321             needstart = %t
322             [alreadyran, %cpr, Resume_line, TOWS_vals, Names] = do_terminate1(scs_m, %cpr)
323             for i=1:size(Names, "c")
324                 ierr = execstr(Names(i)+" = TOWS_vals("+string(i)+");", "errcatch");
325                 if ierr <> 0 then
326                     str_err = split_lasterror(lasterror());
327                     message(["Simulation problem" ; "Unable to find To Workspace Variable {"+Names(i)+"}:" ; str_err]);
328                     break;
329                 end
330             end
331         else
332             %tcur = t
333         end
334     else
335         error([_("Simulation problem: ");lasterror()])
336     end
337
338     Info = list(%tcur, %cpr, alreadyran, needstart, needcompile, %state0)
339
340     // Executing the resume() function at the end, because it does not return control
341     if ~isempty(Names) then
342         execstr(Resume_line);
343     end
344 endfunction
345
346 function [alreadyran, %cpr, Resume_line, TOWS_vals, Names] = do_terminate1(scs_m, %cpr)
347     // Copyright INRIA
348
349     // Default return values
350     Resume_line = "";
351     TOWS_vals = struct("values",[],"time",[]);
352     Names = [];
353
354     if prod(size(%cpr)) < 2 then
355         alreadyran = %f
356         return
357     end
358
359     par = scs_m.props;
360
361     if alreadyran then
362         alreadyran = %f
363         // terminate current simulation
364         ierr = execstr("[state, t] = scicosim(%cpr.state, par.tf, par.tf, %cpr.sim, ''finish'', par.tol)", "errcatch")
365
366         %cpr.state = state
367         if ierr <> 0 then
368             error([_("End problem: ");lasterror()])
369         end
370
371         // Restore saved variables in Scilab environment ("To workspace" block)
372
373         // First step: Search the %cpr tree for TOWS_c blocks, and extract the variable names.
374         path = %cpr.sim;
375         buff_sizes = [];
376         increment = 1;
377         for i=1:size(path.funs)
378             increment2 = path.ipptr(i+1);
379             if (increment2 - increment <> 0) then   // ipar has at least a few elements
380                 space = increment2 - increment;      // The number of elements that the current block pushed into ipar
381                 if (path.funs(i) == "tows_c") then  // Found a Tow_workspace block
382                     varNameLen = space - 2;         // Space minus 'buffer_size' and 'var length' ipar elements
383                     varNameCode = path.ipar(increment+2:increment+2+varNameLen-1);  // varName is stored in Scilab code
384                     varName = ascii(varNameCode);
385                     Names = [Names varName];        // Append varName in Names
386                     buff_size  = path.ipar(increment);  // Retrieve buffer size
387                     buff_sizes = [buff_sizes buff_size];
388                 end
389                 increment = increment2;
390             end
391         end
392         // At the end, Names contains the string names of the variables and buff_sizes the respective buffer sizes
393
394         // Second step: Link the variable names to their values vectors,
395         //and call '[names(1), names(2), ...] = resume(names(1), names(2), ...)' to save the variable into Scilab
396         if ~isempty(Names) then
397             for i=1:size(Names, "c")
398                 execstr("NamesIval = "+Names(i)+"_val;");
399                 execstr("NamesIvalt = "+Names(i)+"_valt;");
400                 // If input is a matrix, use function matrix() to reshape the saved values
401                 // Check condition using time vector, if we have more values than time stamps, split it
402                 if (size(NamesIval, "r") > size(NamesIvalt, "r")) then  // In this case, size(Names(i), 'r') = buff_sizes(i) * nCols2
403                     nRows  = size(NamesIvalt, "r");
404                     nCols  = size(NamesIval, "c");
405                     nCols2 = size(NamesIval, "r") / nRows;
406                     NamesIval = matrix(NamesIval, nCols, nCols2, nRows);
407                 end
408                 if i == 1 then
409                     // Replace default struct with value vector of first element of 'Names'
410                     TOWS_vals.values = NamesIval;
411                     TOWS_vals.time   = NamesIvalt;
412                     Resume_line_args = Names(1);
413                 else
414                     ierr = execstr("TOWS_vals = [TOWS_vals struct(''values'', NamesIval, ''time'', NamesIvalt)];", "errcatch");
415                     if ierr <> 0 then
416                         str_err = split_lasterror(lasterror());
417                         message(["Simulation problem" ; "Unable to find To Workspace Variable {"+Names(i)+"}:" ; str_err]);
418                         break;
419                     end
420                     Resume_line_args   = Resume_line_args + ", " + Names(i);  // Concatenate the variable names up to the last one
421                 end
422             end
423             Resume_line = "[" + Resume_line_args + "] = resume(" + Resume_line_args + ");";  // Build the message
424             // Will execute Resume_line at the end of the main function, because it does not return control
425         end
426     end
427 endfunction