/[ascend]/trunk/ascxx/simulation.cpp
ViewVC logotype

Annotation of /trunk/ascxx/simulation.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2407 - (hide annotations) (download) (as text)
Tue Mar 1 07:43:18 2011 UTC (12 years ago) by jpye
File MIME type: text/x-c++src
File size: 29637 byte(s)
Fixes bug 490.
1 johnpye 669 /* ASCEND modelling environment
2     Copyright (C) 2006 Carnegie Mellon University
3    
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2, or (at your option)
7     any later version.
8    
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12     GNU General Public License for more details.
13    
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 59 Temple Place - Suite 330,
17     Boston, MA 02111-1307, USA.
18     */
19 johnpye 132 #include <iostream>
20     #include <iomanip>
21     #include <stdexcept>
22     #include <sstream>
23     using namespace std;
24    
25 johnpye 506 #include "config.h"
26    
27 johnpye 132 extern "C"{
28 jpye 2018 #include <ascend/utilities/error.h>
29     #include <ascend/utilities/ascSignal.h>
30 jpye 2322 #include <ascend/general/ascMalloc.h>
31 jpye 2323 #include <ascend/general/panic.h>
32 jpye 1341
33 jpye 2018 #include <ascend/general/tm_time.h>
34 johnpye 1210
35 jpye 2018 #include <ascend/compiler/symtab.h>
36     #include <ascend/compiler/instance_io.h>
37     #include <ascend/compiler/instantiate.h>
38     #include <ascend/compiler/bintoken.h>
39     #include <ascend/compiler/instance_enum.h>
40     #include <ascend/compiler/instquery.h>
41     #include <ascend/compiler/check.h>
42     #include <ascend/compiler/name.h>
43     #include <ascend/compiler/pending.h>
44     #include <ascend/compiler/importhandler.h>
45     #include <ascend/linear/mtx.h>
46     #include <ascend/system/calc.h>
47     #include <ascend/system/relman.h>
48     #include <ascend/system/system.h>
49     #include <ascend/solver/slvDOF.h>
50     #include <ascend/system/slv_stdcalls.h>
51     #include <ascend/system/slv_server.h>
52     #include <ascend/system/graph.h>
53     #include <ascend/solver/solver.h>
54 johnpye 132 }
55    
56     #include "simulation.h"
57     #include "solver.h"
58 johnpye 208 #include "solverparameters.h"
59 johnpye 132 #include "name.h"
60 johnpye 233 #include "incidencematrix.h"
61 johnpye 237 #include "variable.h"
62 johnpye 307 #include "solverstatus.h"
63 johnpye 310 #include "solverreporter.h"
64 johnpye 1126 #include "matrix.h"
65 jpye 2183 #include "solverhooks.h"
66 johnpye 132
67 jpye 1775 #define SIMULATION_DEBUG 0
68    
69 johnpye 132 /**
70     Create an instance of a type (call compiler etc)
71    
72     @TODO fix mutex on compile command filenames
73     */
74     Simulation::Simulation(Instance *i, const SymChar &name) : Instanc(i, name), simroot(GetSimulationRoot(i),SymChar("simroot")){
75 jpye 2183 #if SIMULATION_DEBUG
76     CONSOLE_DEBUG("Created simulation at %p",this);
77     #endif
78 johnpye 919 sys = NULL;
79 jpye 2183 solverhooks = NULL;
80 johnpye 919 //is_built = false;
81 johnpye 132 // Create an Instance object for the 'simulation root' (we'll call
82 johnpye 190 // it the 'simulation model') and it can be fetched using 'getModel()'
83 johnpye 132 // any time later.
84     //simroot = Instanc(GetSimulationRoot(i),name);
85     }
86    
87 johnpye 164 Simulation::Simulation(const Simulation &old) : Instanc(old), simroot(old.simroot){
88 johnpye 919 //is_built = old.is_built;
89 jpye 2183 #if SIMULATION_DEBUG
90     CONSOLE_DEBUG("Copying Simulation...");
91     #endif
92 johnpye 164 sys = old.sys;
93 johnpye 775 sing = NULL;
94 jpye 2183 solverhooks = old.solverhooks;
95 johnpye 164 }
96    
97 jpye 1387 Instanc Simulation::getRoot(){
98     return simroot;
99     }
100    
101 johnpye 164 Simulation::~Simulation(){
102 jpye 1749 //CONSOLE_DEBUG("Destroying Simulation...");
103 johnpye 972 /*
104     // FIXME removing this here, because Python overzealously seems to delete simulations
105 jpye 1380
106 johnpye 968 CONSOLE_DEBUG("Deleting simulation %s", getName().toString());
107     system_free_reused_mem();
108     if(sys){
109     CONSOLE_DEBUG("Destroying simulation system...");
110     system_destroy(sys);
111     }
112 johnpye 972 */
113 johnpye 1027 sys = NULL;
114 johnpye 164 }
115    
116 johnpye 132 Instanc &
117     Simulation::getModel(){
118     if(!simroot.getInternalType()){
119     throw runtime_error("Simulation::getModel: simroot.getInternalType()is NULL");
120     }
121 johnpye 919 if(InstanceKind(simroot.getInternalType())!=MODEL_INST){
122     throw runtime_error("Simulation::getModel: simroot is not a MODEL instance");
123     }
124 johnpye 132 return simroot;
125     }
126    
127 johnpye 775
128 johnpye 1247 slv_system_t
129 johnpye 775 Simulation::getSystem(){
130     if(!sys)throw runtime_error("Can't getSystem: simulation not yet built");
131     return sys;
132 johnpye 132 }
133    
134 johnpye 295
135 johnpye 775 const string
136     Simulation::getInstanceName(const Instanc &i) const{
137     char *n;
138     n = WriteInstanceNameString(i.getInternalType(),simroot.getInternalType());
139     string s(n);
140     ascfree(n);
141     return s;
142     }
143 johnpye 295
144 johnpye 775 const int
145     Simulation::getNumVars(){
146     return slv_get_num_solvers_vars(getSystem());
147 johnpye 295 }
148    
149 jpye 1347 /**
150     A general purpose routine for reporting from simulations.
151     */
152     void
153 jpye 1350 Simulation::write(FILE *fp, const char *type) const{
154 jpye 1347 int res;
155 johnpye 295
156 jpye 1347 const var_filter_t vfilter = {
157     VAR_SVAR | VAR_ACTIVE | VAR_INCIDENT | VAR_FIXED
158     , VAR_SVAR | VAR_ACTIVE | VAR_INCIDENT | 0
159     };
160    
161     const rel_filter_t rfilter = {
162 jpye 1380 REL_INCLUDED | REL_EQUALITY | REL_ACTIVE
163     , REL_INCLUDED | REL_EQUALITY | REL_ACTIVE
164 jpye 1347 };
165    
166 jpye 1350 if(type==NULL){
167 jpye 1349 CONSOLE_DEBUG("Writing simroot...");
168 jpye 1347 simroot.write(fp);
169 jpye 1349 return;
170 jpye 1350 }else if(string(type) == "dot"){
171 jpye 1347 if(!sys)throw runtime_error("Can't write DOT file: simulation not built");
172     CONSOLE_DEBUG("Writing graph...");
173 jpye 1380 if(!fp){
174 jpye 1679 throw runtime_error("Need a file to write to in Simulation::write");
175 jpye 1380 }
176 jpye 1679 res = system_write_graph(sys, fp, "png");
177 jpye 1347 if(res){
178     stringstream ss;
179     ss << "Error running system_write_graph (err " << res << ")";
180     throw runtime_error(ss.str());
181     }
182 jpye 1349 return;
183 jpye 1347 }
184 jpye 1349
185     stringstream ss;
186     ss << "Unrecognised type '" << type << "' in Simulation::write";
187     throw runtime_error(ss.str());
188 johnpye 295 }
189    
190 johnpye 775 //------------------------------------------------------------------------------
191     // RUNNING MODEL 'METHODS'
192 johnpye 772
193 johnpye 295 void
194 johnpye 132 Simulation::run(const Method &method){
195 jpye 2183
196     // we have to assign hooks every time, because the Python layer causes
197     // copying of Simulation objects, resulting in the 'this' address changing.
198     SolverHooksManager::Instance()->getHooks()->assign(this);
199    
200 johnpye 774 Instanc &model = getModel();
201     this->run(method,model);
202     }
203    
204     void
205 johnpye 900 Simulation::runDefaultMethod(){
206 johnpye 1021 const Type &type = getType();
207     Method m;
208     try{
209     m = type.getMethod(SymChar("on_load"));
210     }catch(runtime_error &e){
211     ERROR_REPORTER_NOLINE(ASC_USER_WARNING,"There is no 'on_load' method defined for type '%s'",type.getName().toString());
212     return;
213     }
214 jpye 1380 run(m);
215     }
216 johnpye 900
217     void
218 johnpye 774 Simulation::run(const Method &method, Instanc &model){
219    
220 johnpye 900 // set the 'sim' pointer to our local variable...
221 jpye 1749 //CONSOLE_DEBUG("Setting shared pointer 'sim' = %p",this);
222 johnpye 900 importhandler_setsharedpointer("sim",this);
223    
224 johnpye 919 /*if(not is_built){
225 johnpye 912 CONSOLE_DEBUG("WARNING, SIMULATION NOT YET BUILT");
226 johnpye 919 }*/
227 johnpye 912
228 jpye 2340 CONSOLE_DEBUG("Running method '%s' on simulation '%s'...", method.getName(), (const char *)(getName().getInternalType()));
229 johnpye 912
230 johnpye 132 Nam name = Nam(method.getSym());
231 johnpye 154 //cerr << "CREATED NAME '" << name.getName() << "'" << endl;
232 johnpye 900
233 johnpye 932 error_reporter_tree_start();
234 johnpye 900
235 jpye 1749 //CONSOLE_DEBUG("sys = %p",sys);
236     //CONSOLE_DEBUG("simroot = %p",simroot.getInternalType());
237 johnpye 1027
238 johnpye 132 Proc_enum pe;
239     pe = Initialize(
240 jpye 2275 &*(model.getInternalType()), name.getInternalType(), name.getName().c_str()
241 johnpye 132 ,ASCERR
242 jpye 2183 ,WP_STOPONERR, NULL, NULL
243 johnpye 132 );
244    
245 johnpye 932 int haserror=0;
246     if(error_reporter_tree_has_error()){
247     haserror=1;
248     }
249     error_reporter_tree_end();
250    
251 johnpye 900 // clear out the 'sim' pointer (soon it will be invalid)
252     importhandler_setsharedpointer("sim",NULL);
253 jpye 1749 //CONSOLE_DEBUG("Cleared shared pointer 'sim'");
254 johnpye 900
255 johnpye 132 if(pe == Proc_all_ok){
256 johnpye 932 if(haserror){
257     ERROR_REPORTER_NOLINE(ASC_PROG_ERR,"Method '%s' had error(s).",method.getName());
258     stringstream ss;
259     ss << "Method '"<<method.getName()<<"' returned 'all_ok' status but output error(s)";
260     throw runtime_error(ss.str());
261     }else{
262     ERROR_REPORTER_NOLINE(ASC_USER_SUCCESS,"Method '%s' returned 'all_ok' and output no errors.\n",method.getName());
263     }
264 johnpye 132 //cerr << "METHOD " << method.getName() << " COMPLETED OK" << endl;
265     }else{
266     stringstream ss;
267     ss << "Simulation::run: Method '" << method.getName() << "' returned error: ";
268     switch(pe){
269     case Proc_CallOK: ss << "Call OK"; break;
270     case Proc_CallError: ss << "Error occurred in call"; break;
271     case Proc_CallReturn: ss << "Request that caller return (OK)"; break;
272     case Proc_CallBreak: ss << "Break out of enclosing loop"; break;
273     case Proc_CallContinue: ss << "Skip to next iteration"; break;
274    
275     case Proc_break: ss << "Break"; break;
276     case Proc_continue: ss << "Continue"; break;
277     case Proc_fallthru: ss << "Fall-through"; break;
278     case Proc_return: ss << "Return"; break;
279     case Proc_stop: ss << "Stop"; break;
280     case Proc_stack_exceeded: ss << "Stack exceeded"; break;
281     case Proc_stack_exceeded_this_frame: ss << "Stack exceeded this frame"; break;
282     case Proc_case_matched: ss << "Case matched"; break;
283     case Proc_case_unmatched: ss << "Case unmatched"; break;
284    
285     case Proc_case_undefined_value: ss << "Undefined value in case"; break;
286     case Proc_case_boolean_mismatch: ss << "Boolean mismatch in case"; break;
287     case Proc_case_integer_mismatch: ss << "Integer mismatch in case"; break;
288     case Proc_case_symbol_mismatch: ss << "Symbol mismatch in case"; break;
289     case Proc_case_wrong_index: ss << "Wrong index in case"; break;
290     case Proc_case_wrong_value: ss << "Wrong value in case"; break;
291     case Proc_case_extra_values: ss << "Extra values in case"; break;
292     case Proc_bad_statement: ss << "Bad statement"; break;
293     case Proc_bad_name: ss << "Bad name"; break;
294     case Proc_for_duplicate_index: ss << "Duplicate index"; break;
295     case Proc_for_set_err: ss << "For set error"; break;
296     case Proc_for_not_set: ss << "For not set"; break;
297     case Proc_illegal_name_use: ss << "Illegal name use"; break;
298     case Proc_name_not_found: ss << "Name not found"; break;
299     case Proc_instance_not_found: ss << "Instance not found"; break;
300     case Proc_type_not_found: ss << "Type not found"; break;
301     case Proc_illegal_type_use: ss << "Illegal use"; break;
302     case Proc_proc_not_found: ss << "Method not found"; break;
303     case Proc_if_expr_error_typeconflict: ss << "Type conflict in 'if' expression"; break;
304     case Proc_if_expr_error_nameunfound: ss << "Name not found in 'if' expression"; break;
305     case Proc_if_expr_error_incorrectname: ss << "Incorrect name in 'if' expression"; break;
306     case Proc_if_expr_error_undefinedvalue: ss << "Undefined value in 'if' expression"; break;
307     case Proc_if_expr_error_dimensionconflict: ss << "Dimension conflict in 'if' expression"; break;
308     case Proc_if_expr_error_emptychoice: ss << "Empty choice in 'if' expression"; break;
309     case Proc_if_expr_error_emptyintersection: ss << "Empty intersection in 'if' expression"; break;
310     case Proc_if_expr_error_confused: ss << "Confused in 'if' expression"; break;
311     case Proc_if_real_expr: ss << "Real-valued result in 'if' expression"; break;
312     case Proc_if_integer_expr: ss << "Integeter-valued result in 'if' expression"; break;
313     case Proc_if_symbol_expr: ss << "Symbol-valued result in 'if' expression"; break;
314     case Proc_if_set_expr: ss << "Set-valued result in 'if' expression"; break;
315     case Proc_if_not_logical: ss << "If expression is not logical"; break;
316     case Proc_user_interrupt: ss << "User interrupt"; break;
317     case Proc_infinite_loop: ss << "Infinite loop"; break;
318     case Proc_declarative_constant_assignment: ss << "Declarative constant assignment"; break;
319     case Proc_nonsense_assignment: ss << "Nonsense assginment (bogus)"; break;
320     case Proc_nonconsistent_assignment: ss << "Inconsistent assignment"; break;
321     case Proc_nonatom_assignment: ss << "Non-atom assignment"; break;
322     case Proc_nonboolean_assignment: ss << "Non-boolean assignment"; break;
323     case Proc_noninteger_assignment: ss << "Non-integer assignment"; break;
324     case Proc_nonreal_assignment: ss << "Non-real assignment"; break;
325     case Proc_nonsymbol_assignment: ss << "Non-symbol assignment"; break;
326     case Proc_lhs_error: ss << "Left-hand-side error"; break;
327     case Proc_rhs_error: ss << "Right-hand-side error"; break;
328     case Proc_unknown_error: ss << "Unknown error"; break;
329     default:
330     ss << "Invalid error code";
331     }
332    
333     ss << " (" << int(pe) << ")";
334     throw runtime_error(ss.str());
335     }
336     }
337    
338 johnpye 775 //-----------------------------------------------------------------------------
339     // CHECKING METHODS
340    
341 johnpye 772 /**
342 johnpye 775 Check that all the analysis went OK: solver lists are all there, etc...?
343    
344     Can't return anything here because of limitations in the C API
345 johnpye 912
346     @TODO there's something wrong with this at the moment: even after 'FIX'
347     methods are run, check shows them as not fixed, up until the point that 'SOLVE'
348     successfully completes. Something's not being synchronised properly...
349 johnpye 772 */
350 johnpye 775 void
351     Simulation::checkInstance(){
352 johnpye 132 Instance *i1 = getModel().getInternalType();
353 johnpye 164 CheckInstance(stderr, &*i1);
354 johnpye 897 //cerr << "DONE CHECKING INSTANCE" << endl;
355 johnpye 775 }
356 johnpye 772
357 johnpye 775 /**
358     @return 1 = underspecified, 2 = square, 3 = structurally singular, 4 = overspecified
359     */
360     enum StructuralStatus
361     Simulation::checkDoF() const{
362     int dof, status;
363 johnpye 918
364 johnpye 919 if(!sys){
365     throw runtime_error("System is not built");
366     }
367    
368     /*if(!is_built){
369 johnpye 918 throw runtime_error("System not yet built");
370 johnpye 919 }*/
371 johnpye 918 CONSOLE_DEBUG("Calling slvDOF_status...");
372 johnpye 775 slvDOF_status(sys, &status, &dof);
373     switch(status){
374     case ASCXX_DOF_UNDERSPECIFIED:
375     case ASCXX_DOF_SQUARE:
376     case ASCXX_DOF_OVERSPECIFIED:
377     case ASCXX_DOF_STRUCT_SINGULAR:
378     return (enum StructuralStatus)status;
379     case 5:
380     throw runtime_error("Unable to resolve degrees of freedom"); break;
381     default:
382     throw runtime_error("Invalid return status from slvDOF_status");
383     }
384 johnpye 190 }
385 johnpye 132
386 johnpye 775 /**
387     Check consistency
388    
389     @TODO what is the difference between this and checkStructuralSingularity?
390 jpye 1380
391 johnpye 775 @return list of freeable variables. List will be empty if sys is consistent.
392     */
393     vector<Variable>
394     Simulation::getFreeableVariables(){
395     vector<Variable> v;
396    
397 johnpye 897 //cerr << "CHECKING CONSISTENCY..." << endl;
398 johnpye 841 int *fixedarrayptr=NULL;
399 johnpye 775
400 johnpye 841 if(!sys){
401     throw runtime_error("System not yet built");
402     }
403    
404 johnpye 775 int res = consistency_analysis(sys, &fixedarrayptr);
405    
406     if(res==1){
407     cerr << "STRUCTURALLY CONSISTENT" << endl;
408     }else{
409 johnpye 841 if(fixedarrayptr ==NULL){
410     ERROR_REPORTER_HERE(ASC_USER_ERROR,"STRUCTURALLY INCONSISTENT");
411 johnpye 918 throw runtime_error("Invalid consistency analysis result returned!");
412 johnpye 841 }
413    
414     struct var_variable **vp = slv_get_master_var_list(sys);
415 johnpye 775 for(int i=0; fixedarrayptr[i]!=-1; ++i){
416     v.push_back( Variable(this, vp[fixedarrayptr[i]]) );
417     }
418     }
419     return v;
420     }
421    
422     /** Returns TRUE if all is OK (not singular) */
423     bool
424     Simulation::checkStructuralSingularity(){
425     int *vil;
426     int *ril;
427     int *fil;
428    
429     if(this->sing){
430     cerr << "DELETING OLD SINGULATING INFO" << endl;
431     delete this->sing;
432     this->sing = NULL;
433     }
434    
435 johnpye 1106 cerr << "RETRIEVING slfDOF_structsing INFO" << endl;
436    
437     int res = slvDOF_structsing(sys, mtx_FIRST, &vil, &ril, &fil);
438    
439    
440 johnpye 775 if(res==1){
441 johnpye 1046 throw runtime_error("Unable to determine singularity lists");
442     }
443 johnpye 775
444 johnpye 1046 if(res!=0){
445     throw runtime_error("Invalid return from slvDOF_structsing.");
446     }
447 johnpye 775
448    
449 johnpye 1046 CONSOLE_DEBUG("processing singularity data...");
450     sing = new SingularityInfo();
451 johnpye 775
452 johnpye 1046 struct var_variable **varlist = slv_get_solvers_var_list(sys);
453     struct rel_relation **rellist = slv_get_solvers_rel_list(sys);
454 jpye 2041 int32 nv = slv_get_num_solvers_vars(sys);
455    
456 johnpye 1046 // pull in the lists of vars and rels, and the freeable vars:
457     for(int i=0; ril[i]!=-1; ++i){
458     sing->rels.push_back( Relation(this, rellist[ril[i]]) );
459 johnpye 775 }
460 johnpye 1046
461     for(int i=0; vil[i]!=-1; ++i){
462 jpye 2041 assert(vil[i] < nv);
463 johnpye 1046 sing->vars.push_back( Variable(this, varlist[vil[i]]) );
464     }
465    
466     for(int i=0; fil[i]!=-1; ++i){
467     sing->freeablevars.push_back( Variable(this, varlist[fil[i]]) );
468     }
469    
470     // we're done with those lists now
471     ASC_FREE(vil);
472     ASC_FREE(ril);
473     ASC_FREE(fil);
474    
475     if(sing->isSingular()){
476     CONSOLE_DEBUG("singularity found");
477     this->sing = sing;
478     return FALSE;
479     }
480     CONSOLE_DEBUG("no singularity");
481     delete sing;
482     return TRUE;
483 johnpye 775 }
484    
485     /**
486     If the checkStructuralSingularity analysis has been done,
487     this funciton will let you access the SingularityInfo data that was
488     stored.
489     */
490     const SingularityInfo &
491     Simulation::getSingularityInfo() const{
492     if(sing==NULL){
493     throw runtime_error("No singularity info present");
494     }
495     return *sing;
496     }
497    
498     //------------------------------------------
499     // ASSIGNING SOLVER TO SIMULATION
500    
501 johnpye 132 void
502 johnpye 775 Simulation::setSolver(Solver &solver){
503 johnpye 910 /* CONSOLE_DEBUG("Setting solver on sim %p, root inst %p",this,this->simroot.getInternalType()); */
504 johnpye 775
505 johnpye 919 try{
506 johnpye 1027 // build the system (if not built already)
507 johnpye 919 build();
508     }catch(runtime_error &e){
509     stringstream ss;
510     ss << "Couldn't prepare system for solving:";
511     ss << e.what();
512     throw runtime_error(ss.str());
513     }
514 johnpye 775
515 jpye 1775 #if SIMULATION_DEBUG
516 johnpye 972 CONSOLE_DEBUG("Selecting solver '%s'",solver.getName().c_str());
517 jpye 1775 #endif
518    
519 johnpye 775 int selected = slv_select_solver(sys, solver.getIndex());
520 jpye 1775 #if SIMULATION_DEBUB
521 jpye 1487 cerr << "Simulation::setSolver: slv_select_solver returned " << selected << endl;
522 jpye 1775 #endif
523 johnpye 775
524     if(selected<0){
525     ERROR_REPORTER_NOLINE(ASC_PROG_ERROR,"Failed to select solver");
526     throw runtime_error("Failed to select solver");
527     }
528    
529     if(selected!=solver.getIndex()){
530     solver = Solver(slv_solver_name(selected));
531     ERROR_REPORTER_NOLINE(ASC_PROG_NOTE,"Substitute solver '%s' (index %d) selected.\n", solver.getName().c_str(), selected);
532     }
533    
534     if( slv_eligible_solver(sys) <= 0){
535     ERROR_REPORTER_NOLINE(ASC_PROG_ERROR,"Inelegible solver '%s'", solver.getName().c_str() );
536     throw runtime_error("Inelegible solver");
537     }
538     }
539    
540     const Solver
541     Simulation::getSolver() const{
542     int index = slv_get_selected_solver(sys);
543     //cerr << "Simulation::getSolver: index = " << index << endl;
544     if(index<0)throw runtime_error("No solver selected");
545    
546     return Solver(slv_solver_name(index));
547     }
548    
549     //------------------------------------------------------------------------------
550 johnpye 919 // BUILD THE SYSTEM
551 johnpye 775
552     /**
553     Build the system (send it to the solver)
554     */
555     void
556 johnpye 132 Simulation::build(){
557 johnpye 919 if(sys){
558 jpye 1368 //CONSOLE_DEBUG("System is already built (%p)",sys);
559 johnpye 919 return;
560 jpye 1368 }else{
561     CONSOLE_DEBUG("Building system...");
562 johnpye 900 }
563    
564 johnpye 919 if(simroot.getKind() != MODEL_INST){
565     throw runtime_error("Simulation does not contain a MODEL_INST");
566     }
567    
568     if(NumberPendingInstances(simroot.getInternalType())){
569     throw runtime_error("System has pending instances; can't yet send to solver.");
570     }
571 jpye 1380
572 jpye 2183 #if SIMULATION_DEBUG
573 johnpye 1027 CONSOLE_DEBUG("============== REALLY building system...");
574 jpye 2183 #endif
575 johnpye 918 sys = system_build(simroot.getInternalType());
576 johnpye 164 if(!sys){
577 johnpye 1199 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to build system");
578 johnpye 132 throw runtime_error("Unable to build system");
579     }
580 jpye 1380
581 johnpye 919 CONSOLE_DEBUG("System built OK");
582 johnpye 132 }
583    
584 johnpye 775
585     //------------------------------------------------------------------------------
586     // SOLVER CONFIGURATION PARAMETERS
587    
588     /**
589     Get solver parameters struct wrapped up as a SolverParameters class.
590     */
591     SolverParameters
592 johnpye 1133 Simulation::getParameters() const{
593 johnpye 919 //if(!is_built)throw runtime_error("Can't getSolverParameters: Simulation system has not been built yet.");
594 johnpye 900 if(!sys)throw runtime_error("Can't getSolverParameters: Simulation system has no 'sys' assigned.");
595 johnpye 775
596     slv_parameters_t p;
597     slv_get_parameters(sys,&p);
598     return SolverParameters(p);
599     }
600    
601     /**
602     Update the solver parameters by passing a new set back
603     */
604     void
605 johnpye 1133 Simulation::setParameters(SolverParameters &P){
606 johnpye 775 if(!sys)throw runtime_error("Can't set solver parameters: simulation has not been built yet.");
607 jpye 2183 #if SIMULATION_DEBUG
608 johnpye 918 CONSOLE_DEBUG("Calling slv_set_parameters");
609 jpye 2183 #endif
610 johnpye 775 slv_set_parameters(sys, &(P.getInternalType()));
611     }
612    
613     //------------------------------------------------------------------------------
614     // PRE-SOLVE DIAGNOSTICS
615    
616 jpye 1380 /**
617 johnpye 775 Get a list of variables to fix to make an underspecified system
618     become square. Also seems to return stuff when you have a structurally
619     singuler system.
620     */
621 johnpye 132 vector<Variable>
622     Simulation::getFixableVariables(){
623 johnpye 897 //cerr << "GETTING FIXABLE VARIABLES..." << endl;
624 johnpye 132 vector<Variable> vars;
625    
626 johnpye 164 if(!sys){
627 johnpye 132 throw runtime_error("Simulation system not yet built");
628     }
629    
630 johnpye 316 int32 *vip; /** TODO ensure 32 bit integers are used */
631 johnpye 132
632     // Get IDs of elegible variables in array at vip...
633 johnpye 918 CONSOLE_DEBUG("Calling slvDOF_eligible");
634 johnpye 316 if(!slvDOF_eligible(sys,&vip)){
635 johnpye 190 ERROR_REPORTER_NOLINE(ASC_USER_NOTE,"No fixable variables found.");
636 johnpye 132 }else{
637     struct var_variable **vp = slv_get_solvers_var_list(sys);
638    
639     if(vp==NULL){
640     throw runtime_error("Simulation variable list is null");
641     }
642 johnpye 190
643 johnpye 132 // iterate through this list until we find a -1:
644     int i=0;
645 johnpye 316 int var_index = vip[i];
646 johnpye 132 while(var_index >= 0){
647     struct var_variable *var = vp[var_index];
648 johnpye 237 vars.push_back( Variable(this, var) );
649 johnpye 132 ++i;
650 johnpye 316 var_index = vip[i];
651 johnpye 132 }
652 johnpye 190 ERROR_REPORTER_NOLINE(ASC_USER_NOTE,"Found %d fixable variables.",i);
653 johnpye 316 ascfree(vip);
654 johnpye 132 }
655    
656     return vars;
657     }
658    
659 johnpye 1126 /**
660     Return a list of ALL the fixed variables in the solver's variable list
661     */
662 johnpye 1117 vector<Variable>
663     Simulation::getFixedVariables(){
664     if(!sys)throw runtime_error("Simulation system not build yet");
665     vector<Variable> vars;
666     var_variable **vlist = slv_get_solvers_var_list(sys);
667     unsigned long nvars = slv_get_num_solvers_vars(sys);
668 johnpye 1126 for(unsigned long i=0;i<nvars;++i){
669 johnpye 1117 if(!var_fixed(vlist[i]))continue;
670     vars.push_back(Variable(this,vlist[i]));
671     }
672     return vars;
673     }
674    
675 johnpye 775 /**
676 arijit 2074 Returns all variables in solver's variables list that will be saved in pickle
677     */
678     vector<Variable>
679     Simulation::getallVariables(){
680     if(!sys)throw runtime_error("Simulation system not build yet");
681     vector<Variable> vars;
682     var_variable **vlist = slv_get_solvers_var_list(sys);
683     unsigned long nvars = slv_get_num_solvers_vars(sys);
684     for(unsigned long i=0;i<nvars;++i)
685     vars.push_back(Variable(this,vlist[i]));
686     return vars;
687     }
688    
689     /**
690 johnpye 1126 For solvers that store a big matrix for the system, return a pointer to that
691     matrix (struct mtx_header*) as a C++-wrapped object of class Matrix.
692     */
693     Matrix
694     Simulation::getMatrix(){
695     if(!sys)throw runtime_error("Simulation system not built yet");
696     mtx_matrix_t M = slv_get_sys_mtx(sys);
697     if(M==NULL)throw runtime_error("Simulation system does not possess a matrix");
698     return Matrix(M);
699     }
700    
701     /**
702 johnpye 775 Get the list of variables near their bounds. Helps to indentify why
703     you might be having non-convergence problems.
704     */
705 johnpye 328 vector<Variable>
706     Simulation::getVariablesNearBounds(const double &epsilon){
707 johnpye 897 //cerr << "GETTING VARIABLES NEAR BOUNDS..." << endl;
708 johnpye 328 vector<Variable> vars;
709    
710     if(!sys){
711     throw runtime_error("Simulation system not yet built");
712     }
713    
714     int *vip;
715 johnpye 918 CONSOLE_DEBUG("Calling slv_near_bounds...");
716 johnpye 328 if(slv_near_bounds(sys,epsilon,&vip)){
717     struct var_variable **vp = slv_get_solvers_var_list(sys);
718     struct var_variable *var;
719     cerr << "VARS FOUND NEAR BOUNDS" << endl;
720     int nlow = vip[0];
721     int nhigh = vip[1];
722     int lim1 = 2 + nlow;
723     for(int i=2; i<lim1; ++i){
724     var = vp[vip[i]];
725     char *var_name = var_make_name(sys,var);
726     cerr << "AT LOWER BOUND: " << var_name << endl;
727     ascfree(var_name);
728     vars.push_back(Variable(this,var));
729     };
730     int lim2 = lim1 + nhigh;
731     for(int i=lim1; i<lim2; ++i){
732     var = vp[vip[i]];
733     char *var_name = var_make_name(sys,var);
734     cerr << "AT UPPER BOUND: " << var_name << endl;
735     ascfree(var_name);
736     vars.push_back(Variable(this,var));
737     }
738     }
739 johnpye 1145 ASC_FREE(vip);
740 johnpye 328 return vars;
741     }
742 johnpye 502
743 johnpye 1145 vector<Variable>
744     Simulation::getVariablesFarFromNominals(const double &bignum){
745     vector<Variable> vars;
746 johnpye 775
747 johnpye 1145 if(!sys){
748     throw runtime_error("Simulation system not yet built");
749     }
750    
751     int *vip;
752     int nv;
753     CONSOLE_DEBUG("Calling slv_far_from_nominals...");
754     if((nv=slv_far_from_nominals(sys, bignum, &vip))){
755     struct var_variable **vp = slv_get_solvers_var_list(sys);
756     struct var_variable *var;
757     cerr << "VARS FAR FROM NOMINAL" << endl;
758     for(int i=0; i<nv; ++i){
759     var = vp[vip[i]];
760     char *varname = var_make_name(sys,var);
761     cerr << "FAR FROM NOMINAL: " << varname << endl;
762     ASC_FREE(varname);
763     vars.push_back(Variable(this,var));
764     };
765     }
766     ASC_FREE(vip);
767     return vars;
768     }
769    
770 johnpye 775 bool
771     SingularityInfo::isSingular() const{
772     if(vars.size()||rels.size()){
773     return true;
774     }
775     return false;
776     }
777    
778     //------------------------------------------------------------------------------
779     // SOLVING
780    
781     /**
782 jpye 1380 Solve the system through to convergence. This function is hardwired with
783 johnpye 775 a maximum of 1000 iterations, but will interrupt itself when the 'stop'
784     condition comes back from the SolverReporter.
785     */
786 johnpye 132 void
787 johnpye 310 Simulation::solve(Solver solver, SolverReporter &reporter){
788 johnpye 1034 int res;
789 johnpye 919
790 jpye 1775 #if SIMULATION_DEBUG
791 johnpye 1035 cerr << "-----------------set solver----------------" << endl;
792 jpye 1775 #endif
793    
794 jpye 1749 //CONSOLE_DEBUG("Setting solver to '%s'",solver.getName().c_str());
795 johnpye 132 setSolver(solver);
796 johnpye 190
797 jpye 1775 #if SIMULATION_DEBUG
798 johnpye 1035 cerr << "-----------------presolve----------------" << endl;
799 jpye 1775 #endif
800 johnpye 1035
801 johnpye 890 //cerr << "PRESOLVING SYSTEM...";
802 jpye 1749 //CONSOLE_DEBUG("Calling slv_presolve...");
803 johnpye 1034
804     res = slv_presolve(sys);
805 jpye 1749 //CONSOLE_DEBUG("slv_presolve returns %d",res);
806 johnpye 1034 if(res!=0){
807     throw runtime_error("Error in slv_presolve");
808     }
809    
810 jpye 1775 #if SIMULATION_DEBUG
811 johnpye 1035 cerr << "-----------------solve----------------" << endl;
812 jpye 1775 #endif
813 johnpye 890 //cerr << "DONE" << endl;
814 johnpye 190
815 johnpye 890 //cerr << "SOLVING SYSTEM..." << endl;
816 johnpye 714 //double updateinterval = 0.02;
817 johnpye 132
818 johnpye 196 double starttime = tm_cpu_time();
819 johnpye 714 //double lastupdate = starttime;
820 johnpye 307 SolverStatus status;
821 johnpye 714 //int solved_vars=0;
822 johnpye 196 bool stop=false;
823    
824 johnpye 307 status.getSimulationStatus(*this);
825 johnpye 314 reporter.report(&status);
826 johnpye 307
827 jpye 2183 unsigned iter;
828     for(iter = 0; stop==false; ++iter){
829     #if SIMULATION_DEBUG
830     CONSOLE_DEBUG("Iter %d",iter);
831     #endif
832 johnpye 307 if(status.isReadyToSolve()){
833 johnpye 1034 res = slv_iterate(sys);
834 jpye 2183 if(res)CONSOLE_DEBUG("slv_iterate returns %d",res);
835     }else{
836     stop = true;
837     }
838 johnpye 307
839     status.getSimulationStatus(*this);
840 johnpye 502
841 johnpye 1034 if(res || reporter.report(&status)){
842 jpye 2183 CONSOLE_DEBUG("STOPPING!");
843 johnpye 317 stop = true;
844     }
845 johnpye 196 }
846 johnpye 317
847 johnpye 230 double elapsed = tm_cpu_time() - starttime;
848 jpye 1775
849     #if SIMULATION_DEBUG
850 jpye 2183 CONSOLE_DEBUG("Elapsed time %0.3f for %d iterations (solver completed)", elapsed,iter);
851 jpye 1775 #endif
852 jpye 1380
853 johnpye 307 activeblock = status.getCurrentBlockNum();
854 johnpye 285
855 jpye 1354 try{
856     // reporter can do output of num of iterations etc, if it wants to.
857     reporter.finalise(&status);
858     }catch(std::exception &e){
859     CONSOLE_DEBUG("Error finalising solver reporter (%s)",e.what());
860     }
861 johnpye 319
862 johnpye 915 // communicate solver variable status back to the instance tree
863     processVarStatus();
864 johnpye 1034
865 johnpye 1035 if(res){
866     stringstream ss;
867     ss << "Error in solving (res = " << res << ")";
868     throw runtime_error(ss.str());
869     }
870     if(!status.isOK()){
871     if(status.isDiverged())throw runtime_error("Solution diverged");
872     if(status.isInconsistent())throw runtime_error("System is inconsistent");
873     if(status.hasExceededIterationLimit())throw runtime_error("Solver exceeded iteration limit");
874     if(status.hasExceededTimeLimit())throw runtime_error("Solver exceeded time limit");
875 johnpye 1109 if(status.isOverDefined())throw runtime_error("Solver system is over-defined");
876     if(status.isUnderDefined())throw runtime_error("Solver system is under-defined");
877 johnpye 1049 throw runtime_error("Error in solver (status.isOK()==FALSE but can't see why)");
878 johnpye 1035 }
879 johnpye 132 }
880    
881 johnpye 775 //------------------------------------------------------------------------------
882     // POST-SOLVE DIAGNOSTICS
883 johnpye 132
884 johnpye 775 const int
885     Simulation::getActiveBlock() const{
886     return activeblock;
887 johnpye 132 }
888    
889 johnpye 208 /**
890 johnpye 775 Return an IncidenceMatrix built from the current state of the solver system.
891 johnpye 132
892 johnpye 775 This will actually return something meaningful even before solve.
893 johnpye 225 */
894 johnpye 233 IncidenceMatrix
895     Simulation::getIncidenceMatrix(){
896     return IncidenceMatrix(*this);
897     }
898 johnpye 252
899 johnpye 775 /**
900 jpye 1737 This function looks at all the variables in the solver list, and updates
901     the variable status for the corresponding instances so that feedback can
902     be given to the user via the GUI.
903 johnpye 317
904 johnpye 775 It does this by using the 'interface pointer' in the Instance, see
905     the C-API function GetInterfacePtr.
906 johnpye 317
907 johnpye 775 This is used to display visually which variables have been solved, which
908     ones have not yet been attempted, and which ones were active when the solver
909     failed (ASCXX_VAR_ACTIVE).
910     */
911 johnpye 255 void
912     Simulation::processVarStatus(){
913 mahesh 2130 int low;
914     int high;
915    
916 jpye 2407 if(!sys)return;
917 johnpye 255
918 jpye 1355 //CONSOLE_DEBUG("Getting var status");
919 johnpye 973
920 johnpye 255 // this is a cheap function call:
921     const mtx_block_t *bb = slv_get_solvers_blocks(getSystem());
922 johnpye 297
923 johnpye 255 var_variable **vlist = slv_get_solvers_var_list(getSystem());
924     int nvars = slv_get_num_solvers_vars(getSystem());
925    
926 jpye 1362 rel_relation **rlist = slv_get_solvers_rel_list(getSystem());
927     int nrels = slv_get_num_solvers_rels(getSystem());
928    
929 johnpye 255 slv_status_t status;
930 johnpye 1197 if(slv_get_status(sys, &status)){
931     ERROR_REPORTER_HERE(ASC_PROG_ERR,"Unable to update var status (get_status returns error)");
932     return;
933     }
934 jpye 1380
935 johnpye 297 if(status.block.number_of == 0){
936     cerr << "Variable statuses can't be set: block structure not yet determined." << endl;
937     return;
938 jpye 1737 }else{
939 jpye 1775 #if SIMULATION_DEBUG
940 jpye 1737 CONSOLE_DEBUG("There are %d blocks", status.block.number_of);
941 jpye 1775 #endif
942 johnpye 297 }
943 jpye 1341
944     if(!bb->block){
945 mahesh 2130 /**
946     @todo just manually set 'low' and 'high' to both be equal to
947     sys->n if the system is converged, or else set low to 1 and hight to
948     sys->n in the case where it did not converge.
949     */
950    
951     /** @todo find out the way code is taking */
952     if (status.converged == 1){
953     low = high = status.block.current_size;
954     }
955     else{
956     low = 1; // is this 1 or 0??
957     high = status.block.current_size;
958     }
959 jpye 1341 }
960 mahesh 2130 else{
961 johnpye 255 int activeblock = status.block.current_block;
962 jpye 1342 asc_assert(activeblock <= status.block.number_of);
963 jpye 1341
964 mahesh 2130 low = bb->block[activeblock].col.low;
965     high = bb->block[activeblock].col.high;
966     }
967 johnpye 258 bool allsolved = status.converged;
968 johnpye 255 for(int c=0; c < nvars; ++c){
969     var_variable *v = vlist[c];
970     Instanc i((Instance *)var_instance(v));
971 jpye 1362 InstanceStatus s = ASCXX_INST_STATUS_UNKNOWN;
972 johnpye 258 if(i.isFixed()){
973     s = ASCXX_VAR_FIXED;
974     }else if(var_incident(v) && var_active(v)){
975     if(allsolved || c < low){
976 johnpye 255 s = ASCXX_VAR_SOLVED;
977 jpye 2155 //CONSOLE_DEBUG("Solved Variable : %d",c);
978 johnpye 255 }else if(c <= high){
979     s = ASCXX_VAR_ACTIVE;
980 jpye 2155 //CONSOLE_DEBUG("Active Variable : %d",c);
981 johnpye 255 }else{
982     s = ASCXX_VAR_UNSOLVED;
983 jpye 2155 //CONSOLE_DEBUG("Unsolved Variable: %d",c);
984 johnpye 255 }
985     }
986 jpye 1362 i.setStatus(s);
987 johnpye 255 }
988 johnpye 973
989 jpye 1362 for(int j=0; j < nrels; ++j){
990     rel_relation *r = rlist[j];
991     Instanc i((Instance *)rel_instance(r));
992     InstanceStatus s = ASCXX_INST_STATUS_UNKNOWN;
993     if(rel_in_when(r)){
994     if(!rel_active(r)){
995     s = ASCXX_REL_INACTIVE;
996     }
997     }
998     i.setStatus(s);
999     }
1000    
1001 jpye 1355 //CONSOLE_DEBUG(" ...done var status");
1002 johnpye 255 }
1003 johnpye 285
1004 jpye 2183 void
1005     Simulation::setSolverHooks(SolverHooks *H){
1006     #if SIMULATION_DEBUG
1007     CONSOLE_DEBUG("Setting SolverHooks to %p for Simulation at %p",H,this);
1008     #endif
1009     this->solverhooks = H;
1010     }
1011 jpye 1362
1012 jpye 2183 SolverHooks *
1013     Simulation::getSolverHooks() const{
1014     #if SIMULATION_DEBUG
1015     CONSOLE_DEBUG("Got SolverHooks at %p for Simulation at %p",this->solverhooks,this);
1016     #endif
1017     return this->solverhooks;
1018     }
1019    

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22