xcos_simulate: check loading against a library
[scilab.git] / scilab / modules / xcos / macros / xcos_simulate.sci
1 //
2 // Scilab ( httzp://www.scilab.org/ ) - This file is part of Scilab
3 // Copyright (C) Scilab Enterprises - 2013 - Bruno JOFRET
4 // Copyright (C) 2009-2009 - DIGITEO - Bruno JOFRET
5 //
6 // Copyright (C) 2012 - 2016 - Scilab Enterprises
7 //
8 // This file is hereby licensed under the terms of the GNU GPL v2.0,
9 // pursuant to article 5.3.4 of the CeCILL v.2.1.
10 // This file was originally licensed under the terms of the CeCILL v2.1,
11 // and continues to be available under such terms.
12 // For more information, see the COPYING file which you should have received
13 // along with this program.
14 //
15 //
16
17 function [%cpr, ok] = xcos_simulate(scs_m, needcompile)
18
19     // Load the block libs if not defined
20     prot = funcprot();
21     funcprot(0);
22     if ~exists("Sourceslib") then
23         loadXcosLibs();
24     end
25     funcprot(prot);
26     [modelica_libs, scicos_pal_libs, %scicos_with_grid, %scs_wgrid] = initial_scicos_tables();
27
28     // Hook according to SEP066
29     function [ok]=invoke_pre_simulate(fun, scs_m, needcompile)
30         ok=%f;
31         ierr=execstr("[continueSimulation]="+fun+"(scs_m, needcompile);", "errcatch");
32         if ierr<>0 then
33             disp(_("Error occurred in pre_xcos_simulate: Cancelling simulation."));
34             [str,n,line,func]=lasterror();
35             mprintf(" at line %d of function %s\n", line, func);
36             return
37         end
38         if ~continueSimulation then
39             return
40         end
41         ok=%t;
42
43         // Force update on the parent in case of scoped modification
44         scs_m=resume(scs_m);
45     endfunction
46
47     if isdef("pre_xcos_simulate") then
48         if type(pre_xcos_simulate) == 15 then
49             // If has a multiple implementation (on a list)
50             for f=pre_xcos_simulate;
51                 ok=invoke_pre_simulate(f, scs_m, needcompile);
52                 if ~ok then
53                     %cpr=[];
54                     return;
55                 end
56             end
57         else
58             // If has a unique implementation
59             ok=invoke_pre_simulate("pre_xcos_simulate", scs_m, needcompile);
60             if ~ok then
61                 %cpr=[];
62                 return;
63             end
64         end
65     end
66
67     //**---- prepare from and to workspace stuff ( "From workspace" block )
68     scicos_workspace_init()
69
70
71     //** extract tolerances from scs_m.props.tol
72     tolerances = scs_m.props.tol ;
73     //** extract solver type from tolerances
74     solver = tolerances(6) ;
75     //** initialize a "scicos_debug_gr" variable
76     %scicos_debug_gr = %f;
77
78     ////////////////////////////////////////////////////////////////
79     // Add global environment variable so that scicos is not lost //
80     ////////////////////////////////////////////////////////////////
81     if needcompile == 4 then
82         %state0     = list();
83         needcompile = 4;
84         curwin      = 1000;
85         %cpr        = struct();
86         %tcur       = 0;
87         %cpr.state  = %state0;
88         alreadyran = %f;
89     else
90         %state0 = %cpr.state;
91         alreadyran = %f;
92     end
93
94     tf          = scs_m.props.tf;
95     %zoom       = 1.4;
96     Select      = [];
97
98     //** extract tolerances from scs_m.props.tol
99     tolerances = scs_m.props.tol ;
100     //** extract solver type from tolerances
101     solver = tolerances(6) ;
102
103     // Propagate context through all blocks
104     %scicos_context = struct();
105     context = scs_m.props.context;
106     //** context eval here
107     [%scicos_context, ierr] = script2var(context, %scicos_context);
108
109     // For backward compatibility for scifunc
110     if ierr==0 then
111         %mm = getfield(1,%scicos_context)
112         for %mi=%mm(3:$)
113             ierr = execstr(%mi+"=%scicos_context(%mi)","errcatch")
114             if ierr<>0 then
115                 break; //** in case of error exit
116             end
117         end
118     end
119     // End of for backward compatibility for scifuncpagate context values
120
121     [scs_m,%cpr,needcompile,ok] = do_eval(scs_m, %cpr, %scicos_context);
122     if ~ok then
123         msg = msprintf(gettext("%s: Error during block parameters evaluation.\n"), "Xcos");
124         if getscilabmode() <> "NWNI" then
125             messagebox(msg, "Xcos", "error");
126         end
127         error(msprintf(gettext("%s: Error during block parameters evaluation.\n"), "xcos_simulate"));
128     end
129
130     //** update parameters or compilation results
131     [%cpr,%state0_n,needcompile,alreadyran,ok] = do_update(%cpr,%state0,needcompile)
132     if ~ok then
133         error(msprintf(gettext("%s: Error during block parameters update.\n"), "xcos_simulate"));
134     end
135
136     //** if alreadyran then set the var choice
137     if alreadyran then
138         choix = ["Continue";"Restart";"End"]
139     else
140         choix = [] ;
141     end
142
143     issequal = %t;
144     //** initial state has been changed
145     if ~isequal(%state0_n,%state0) then
146         issequal = %f
147     else
148         //** test typeof outtb element
149         for i=1:lstsize(%state0_n.outtb)
150             if typeof(%state0_n.outtb(i))<>typeof(%state0.outtb(i))
151                 issequal = %f
152                 break
153             end
154         end
155         //** test typeof oz element
156         for i=1:lstsize(%state0_n.oz)
157             if typeof(%state0_n.oz(i))<>typeof(%state0.oz(i))
158                 issequal = %f
159                 break
160             end
161         end
162     end
163
164     //** if state have changed
165     //** finish the simulation via do_terminate()
166     if ~issequal then
167         %state0 = %state0_n
168         [alreadyran,%cpr] = do_terminate()
169         choix = []
170     end
171
172     //** switch to appropriate solver
173     if %cpr.sim.xptr($)-1<size(%cpr.state.x,"*") & solver<100 then
174         warning(["Diagram has been compiled for implicit solver"
175         "switching to implicit Solver"])
176         solver = 100 ; //** Magic number
177         tolerances(6) = solver ; //** save Magic number solver type
178     elseif (%cpr.sim.xptr($)-1==size(%cpr.state.x,"*")) & ((or (solver == [100 101 102])) & size(%cpr.state.x,"*")<>0) then
179         message(["Diagram has been compiled for explicit solver"
180         "switching to explicit Solver"])
181         solver = 0 ; //** Magic number
182         tolerances(6) = solver ; //** save Magic number solver type
183     end
184
185     //** ask user what to do
186     if choix<>[] then
187         //** open dialog box
188         to_do = choose(choix,"What do you want to do")
189
190         //** if cancel then exit
191         if to_do==0 then
192             ok = %f
193             return
194         end
195
196         select choix(to_do)
197
198         case "Continue" then
199             needstart = %f ;
200             state     = %cpr.state ;
201
202         case "Restart" then
203             needstart = %t ;
204             state     = %state0 ;
205
206         case "End" then
207             state     = %cpr.state ;
208             needstart = %t ;
209             tf        = scs_m.props.tf;
210
211             //Alan: Cannot call do_terminate() here ?
212             //Answer: No, because do_terminate() doesn't
213             //          return control to the user
214
215             //** run scicosim via 'finish' flag
216             ierr = execstr("[state,t]=scicosim(%cpr.state,%tcur,tf,%cpr.sim,"+..
217             "''finish'',tolerances)","errcatch")
218
219             %cpr.state = state
220             alreadyran = %f
221
222             //** error case
223             if ierr<>0 then
224                 str_err = split_lasterror(lasterror());
225                 kfun    = curblock()
226                 corinv  = %cpr.corinv
227
228                 if kfun<>0 & length(corinv) > kfun then //** block error
229                     path = corinv(kfun)
230                     //** get error cmd for the block
231                     get_errorcmd(path,"End problem.",str_err);
232
233                 else //** simulator error
234                     message(["End problem:";str_err])
235                     //scf(curwin);
236                 end
237                 ok = %f
238             end
239
240             return
241         end
242
243     else //** Normal first start simulation
244
245         needstart = %t
246         state     = %state0
247
248     end
249
250     //gh_win = gcf();
251
252     //** scicos initialization
253     if needstart then
254         //** if the simulation has already run
255         //** and is not finished then call do_terminate
256         if alreadyran then
257             [alreadyran,%cpr] = do_terminate()
258             alreadyran = %f ;
259         end
260         //** set initial values for a new simulation
261         %tcur      = 0
262         %cpr.state = %state0
263         tf         = scs_m.props.tf;
264         if tf*tolerances==[] then
265             message(["Simulation parameters not set";"use setup button"]);
266             return;
267         end
268
269         //** Run the normal first start simulation here
270
271         //** run scicosim via 'start' flag
272         ierr = execstr("[state,t]=scicosim(%cpr.state,%tcur,tf,%cpr.sim,"+..
273         "''start'',tolerances)","errcatch")
274
275         %cpr.state = state ; //** save the state
276         //** error case
277         if ierr<>0 then
278             str_err=split_lasterror(lasterror());
279             kfun=curblock()
280             corinv=%cpr.corinv
281
282             if kfun<>0 & length(corinv) > kfun then  //** block error
283                 path=corinv(kfun)
284                 //** get error cmd for the block
285                 disp(str_err);
286                 get_errorcmd(path,gettext("Initialisation problem"),str_err);
287
288
289             else //** simulator error
290                 message(["Initialisation problem:";str_err])
291                 //scf(curwin);
292             end
293
294             ok = %f;
295             //xset('window',curwin)
296             return
297         end
298         //scf(gh_win);
299         //xset('window',win);
300     end
301
302     //** scicos simulation
303     tf = scs_m.props.tf
304
305     // Inform Xcos the simulator is going to run
306     if getscilabmode() <> "NWNI"
307         xcosSimulationStarted();
308     end
309
310     //** run scicosim via 'start' flag
311     ierr = execstr("[state,t]=scicosim(%cpr.state,%tcur,tf,%cpr.sim,"+..
312     "''run'',tolerances)","errcatch")
313
314     %cpr.state = state
315
316     //** no error
317     if ierr==0 then
318         alreadyran = %t;
319         //** we are at the end of the simulation
320         //** finish the simulation via do_terminate()
321         if tf-t<tolerances(3) then
322             //disp('fin');
323             //Alan : removing do_terminate() here because it
324             //       doesn't return control
325             //[alreadyran,%cpr]=do_terminate()
326             needstart  = %t;
327             alreadyran = %f;
328             //** run scicosim via 'finish' flag
329             ierr = execstr("[state,t]=scicosim(%cpr.state,tf,tf,%cpr.sim,"+..
330             "''finish'',tolerances)","errcatch")
331
332             %cpr.state = state;
333
334             //** error case
335             if ierr<>0 then
336                 str_err = split_lasterror(lasterror());
337                 kfun   = curblock()
338                 corinv = %cpr.corinv
339
340                 if kfun<>0 & length(corinv) > kfun then //** block error
341                     path = corinv(kfun)
342                     //** get error cmd for the block
343                     get_errorcmd(path,gettext("End problem"),str_err);
344                 else //** simulator error
345                     message(["End problem:";str_err])
346                     //scf(curwin);
347                 end
348             end
349         else
350             %tcur = t;
351         end
352         //** error case
353     else
354         str_err = split_lasterror(lasterror());
355
356         alreadyran = %f;
357         kfun       = curblock();
358         corinv     = %cpr.corinv;
359         if kfun<>0 & length(corinv) > kfun then //** block error
360             path = corinv(kfun);
361             //** get error cmd for the block
362             execstr(get_errorcmd(path,gettext("Simulation problem"),str_err));
363         else //** simulator error
364             message(["Simulation problem:";str_err])
365             //scf(curwin);
366         end
367         ok = %f;
368     end
369
370     // Restore saved variables in Scilab environment ("To workspace" block)
371
372     // First step: Search the %cpr tree for TOWS_c blocks, and extract the variable names.
373     path = %cpr.sim;
374     Names = [];
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
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             ierr = execstr(Names(i)+" = struct(''values'', NamesIval, ''time'', NamesIvalt)", "errcatch");
409             if ierr <> 0 then
410                 str_err = split_lasterror(lasterror());
411                 message(["Simulation problem" ; "Unable to resume To Workspace Variable {"+Names(i)+"}:" ; str_err]);
412                 break;
413             end
414             if i == 1 then
415                 Resume_line_args = Names(1);
416             else
417                 Resume_line_args = Resume_line_args + ", " + Names(i);  // Concatenate the variable names up to the last one
418             end
419         end
420         Resume_line = "[" + Resume_line_args + "] = resume(" + Resume_line_args + ");";  // Build the message
421         // Will execute Resume_line at the end of the function, to run the following Hook instructions
422     end
423
424     // Hook according to SEP066
425     function ok=invoke_post_simulate(fun, %cpr, scs_m, needcompile)
426         ok=%f;
427         ierr=execstr(fun+"(%cpr, scs_m, needcompile);", "errcatch");
428         if ierr<>0 then
429             disp(_("Error in post_xcos_simulate: ending simulation."))
430             return
431         end
432         ok=%t
433         // Force update on the parent in case of scoped modification
434         scs_m=resume(scs_m);
435     endfunction
436
437     if isdef("post_xcos_simulate") then
438         if type(post_xcos_simulate) == 15 then
439             // If has a multiple implementation (on a list)
440             for f=post_xcos_simulate;
441                 ok=invoke_post_simulate(f, %cpr, scs_m, needcompile);
442                 if ~ok then
443                     %cpr=[];
444                     return;
445                 end
446             end
447         else
448             // If has a unique implementation
449             ok=invoke_post_simulate("post_xcos_simulate", %cpr, scs_m, needcompile);
450             if ~ok then
451                 %cpr=[];
452                 return;
453             end
454         end
455     end
456
457     // Executing the resume() function at the end, because it does not return control
458     if ~isempty(Names) then
459         execstr(Resume_line);
460     end
461
462 endfunction