/[ascend]/trunk/models/johnpye/tron/asc_tron.c
ViewVC logotype

Contents of /trunk/models/johnpye/tron/asc_tron.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1500 - (show annotations) (download) (as text)
Thu Jun 21 14:38:59 2007 UTC (17 years, 5 months ago) by jpye
File MIME type: text/x-csrc
File size: 39608 byte(s)
Preliminary work for TRON tie-in.
1 /* ASCEND modelling environment
2 Copyright (C) 2007 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 @file
20 Connection of the TRON solver into ASCEND.
21
22 THIS IS STILL VERY MUCH UNDER DEVELOPMENT AND INCOMPLETE. I'VE ACTUALLY
23 ONLY JUST STARTED WRITING IT by starting with asc_conopt.c and modifying.
24 *//*
25 originally by John Pye, Jun 2007.
26 */
27
28 #include <math.h>
29 #include <ctype.h>
30
31 #include <solver/solver.h>
32 #include <system/slv_stdcalls.h>
33 #include <system/relman.h>
34
35 #include <utilities/ascPanic.h>
36 #include <utilities/ascMalloc.h>
37 #include <utilities/ascDynaLoad.h>
38 #include <utilities/mem.h>
39 #include <utilities/ascEnvVar.h>
40 #include <general/tm_time.h>
41 #include <general/env.h>
42
43 /*
44 'tron.h' declares what we expect to find in the DLL/SO that we will dlopen
45 when this solver is loaded.
46 */
47
48 #include "tron.h"
49
50 ASC_DLLSPEC SolverRegisterFn tron_register;
51
52 /*
53 Output in user defined TRON subroutines
54 */
55 #define TRON_DEBUG
56
57 #ifdef TRON_DEBUG
58 # define TRON_CONSOLE_DEBUG(...) CONSOLE_DEBUG(__VA_ARGS__)
59 #else
60 # define TRON_CONSOLE_DEBUG(...) (void)0
61 #endif
62
63 /*
64 makes lots of extra spew
65 */
66 #define DEBUG FALSE
67
68 #define TRONSYS(s) ((TronSystem *)(s))
69
70 /* for integrity checks */
71 #define TRON_CREATED ((int32)813029392)
72 #define TRON_DESTROYED ((int32)103289182)
73
74 /*------------------------------------------------------------------------------
75 DATA STRUCTURES
76 */
77
78 enum{
79 TRON_PARAM_ITERMAX
80 ,TRON_PARAM_MAXFEV
81 ,TRON_PARAM_FATOL
82 ,TRON_PARAM_FRTOL
83 ,TRON_PARAM_FMIN
84 ,TRON_PARAM_CGTOL
85 ,TRON_PARAM_GTOL
86 ,TRON_PARAM_TIMELIMIT
87 ,TRON_PARAM_SAFECALC
88 ,TRON_PARAMS
89 };
90
91 /**
92 TRON's matrix storage format, for a square n-by-n matrix
93 */
94 typedef struct{
95 double *ltp; /**< lower triangular part, compressed column storage, dimension nnz + n*p. */
96 double *diag; /**< diagonal elements, n elements */
97 int *col_ptr; /** pointers to the columns, dimension n+1. The nonzeros in column j of L are in the
98 col_ptr(j), ... , col_ptr(j+1) - 1 positions of l. */
99 int *row_ind; /** row indices for the strict lower
100 triangular part of L (ltp) in compressed column storage. */
101 } TronMatrix;
102
103 #define TRON_MATRIX_ARG(SYS,MAT) (SYS)->MAT.ltp,(SYS)->MAT.diag,(SYS)->MAT.col_ptr,(SYS)->MAT.row_ind
104
105 typedef struct{
106
107 char task[60];
108 slv_parameters_t params; /* Parameters */
109 slv_status_t status; /* Status (as of iteration end) */
110 slv_system_t slv; /* slv_system_t back-link */
111 struct slv_parameter pa[TRON_PARAMS]; /* dunno... */
112
113 /* Problem definition */
114 struct rel_relation *obj; /* Objective function: NULL = none */
115 struct rel_relation *old_obj;/* Objective function: NULL = none */
116 struct var_variable **vlist; /* Variable list (NULL terminated) */
117 struct rel_relation **rlist; /* Relation list (NULL terminated) */
118 long vtot; /* length of varlist */
119 long rtot; /* length of rellist */
120 int m, n; /* size of system matrix? */
121 double objective; /* value of objective function */
122 int vused; /* Free and incident variables */
123 int rused; /* Included relations */
124
125 /* Solver information */
126 int created; /* Whether the system been created */
127 int presolved; /* Whether the system been presolved */
128 int optimised;
129
130 double *x;
131 double *xupper; /* upper bounds on each variable */
132 double *xlower; /* lower bounds on each variable */
133 double *f;
134 double *g;
135 TronMatrix A, B, L;
136
137 double *xc, *s, *dsave, *wa;
138 int *indfree, *isave, *iwa;
139
140 double clock; /* CPU time */
141
142 } TronSystem;
143
144 /* this stuff was in the above as well */
145
146 #if 0
147 struct update_data update; /* Jacobian frequency counters */
148 int32 cap; /* Order of matrix/vectors */
149 int32 rank; /* Symbolic rank of problem */
150 #endif
151
152 #if 0
153 void *parm_array[TRON_PARAMS];
154 #endif
155
156 #if 0
157 /*
158 TRON DATA
159 */
160 struct tron_data con;
161 #endif
162
163 #if 0
164 /*
165 Calculated data (scaled)
166 */
167 struct jacobian_data J; /* linearized system */
168
169 struct vec_vector nominals; /* Variable nominals */
170 struct vec_vector weights; /* Relation weights */
171 struct vec_vector relnoms; /* Relation nominals */
172 struct vec_vector variables; /* Variable values */
173 struct vec_vector residuals; /* Relation residuals */
174
175 real64 objective; /* Objective function evaluation */
176 #endif
177
178 /*------------------*/
179
180 #if 0
181 /*
182 Auxiliary structures
183 */
184
185 struct update_data {
186 int jacobian; /* Countdown on jacobian updating */
187 int weights; /* Countdown on weights updating */
188 int nominals; /* Countdown on nominals updating */
189 int relnoms; /* Countdown on relnom updating */
190 int iterative; /* Countdown on iterative scale update */
191 };
192
193
194 /*
195 varpivots, relpivots used only in optimizing, if we rewrite calc_pivots
196 without them.
197 */
198 struct jacobian_data {
199 linsolqr_system_t sys; /* Linear system */
200 mtx_matrix_t mtx; /* Transpose gradient of residuals */
201 real64 *rhs; /* RHS from linear system */
202 unsigned *varpivots; /* Pivoted variables */
203 unsigned *relpivots; /* Pivoted relations */
204 unsigned *subregions; /* Set of subregion indeces */
205 dof_t *dofdata; /* dof data pointer from server */
206 mtx_region_t reg; /* Current block region */
207 int32 rank; /* Numerical rank of the jacobian */
208 enum factor_method fm; /* Linear factorization method */
209 boolean accurate; /* ? Recalculate matrix */
210 boolean singular; /* ? Can matrix be inverted */
211 boolean old_partition;/* old value of partition flag */
212 };
213 #endif
214
215 /* forward decls */
216
217 static void tron_initialize(TronSystem * sys);
218 static int check_system(TronSystem *sys);
219 static void iteration_begins(TronSystem *sys);
220 static void iteration_ends( TronSystem *sys);
221 static int32 tron_dof_changed(TronSystem *sys);
222 static void update_status( TronSystem *sys);
223 static boolean calc_objective( TronSystem *sys);
224 static boolean calc_residuals( TronSystem *sys);
225
226 /*------------------------------------------------------------------------------
227 SOLVER PARAMETERS
228 */
229
230 /*
231 these are the parameters that AMPL says it offers for the TRON solver:
232
233 itermax the limit on the number of conjugate gradient iterations.
234 maxfev the limit on the number of function evaluations
235 fatol the absolute error desired in the function
236 frtol the relative error desired in the function
237 fmin a lower bound for the function
238 cgtol convergence criteria for the conjugate gradient method
239 gtol relative 2-norm of projected grdients; convergence criteria for the trust region method
240 */
241
242 static
243 int32 tron_get_default_parameters(slv_system_t server, SlvClientToken asys
244 ,slv_parameters_t *parameters
245 ){
246 TronSystem *sys = NULL;
247 struct slv_parameter *new_parms = NULL;
248 int32 make_macros = 0;
249
250 if(server != NULL && asys != NULL) {
251 sys = TRONSYS(asys);
252 make_macros = 1;
253 }
254
255 if(parameters->parms == NULL) {
256 new_parms = ASC_NEW_ARRAY_OR_NULL(struct slv_parameter,TRON_PARAMS);
257 if(new_parms == NULL) {
258 return -1;
259 }
260 parameters->parms = new_parms;
261 parameters->dynamic_parms = 1;
262 }
263
264 parameters->num_parms = 0;
265 asc_assert(TRON_PARAMS==7);
266
267 slv_param_int(parameters,TRON_PARAM_ITERMAX
268 ,(SlvParameterInitInt){{"itermax"
269 ,"Max. CG iterations",1
270 ,"Maximum number of conjugate gradient iterations"
271 }, 30, 1, 20000}
272 );
273
274 slv_param_int(parameters,TRON_PARAM_MAXFEV
275 ,(SlvParameterInitInt){{"maxfev"
276 ,"Max. function evaluations",1
277 ,"Maximum number of function evaluations"
278 }, 30, 1, 20000}
279 );
280
281 slv_param_real(parameters,TRON_PARAM_FATOL
282 ,(SlvParameterInitReal){{"fatol"
283 ,"Error tolerance (absolute)",1
284 ,"The absolute error desired in the function"
285 }, 1e-8, 1e-13, 100000.5}
286 );
287
288 slv_param_real(parameters,TRON_PARAM_FRTOL
289 ,(SlvParameterInitReal){{"frtol"
290 ,"Error tolerance (relative)",1
291 ,"The relative error desired in the function"
292 }, 1e-8, 1e-13, 100000.5}
293 );
294
295 slv_param_real(parameters,TRON_PARAM_FMIN
296 ,(SlvParameterInitReal){{"fmin"
297 ,"Function lower bound",1
298 ,"A lower bound for the function"
299 }, -1e8, 1e8, -1e8}
300 );
301
302 slv_param_real(parameters,TRON_PARAM_CGTOL
303 ,(SlvParameterInitReal){{"cgtol"
304 ,"Tolerance for CG convergence criteria",1
305 ,"Convergence criteria for the conjugate gradient method"
306 }, 1e-8, 1e-13, 100000.5}
307 );
308
309 slv_param_real(parameters,TRON_PARAM_GTOL
310 ,(SlvParameterInitReal){{"gtol"
311 ,"Trust region tolerance",1
312 ,"relative 2-norm of projected gradients; convergence criteria for the trust region method"
313 }, 1e-8, 1e-13, 100000.5}
314 );
315
316 slv_param_int(parameters,TRON_PARAM_TIMELIMIT
317 ,(SlvParameterInitInt){{"timelimit"
318 ,"time limit",1
319 ,"time limit (seconds)"
320 }, 30, 1, 20000}
321 );
322
323 slv_param_bool(parameters,TRON_PARAM_SAFECALC
324 ,(SlvParameterInitBool){{"safecalc"
325 ,"safe calc",1
326 ,"safe floating-point operations"
327 }, 0}
328 );
329
330 asc_assert(parameters->num_parms==TRON_PARAMS);
331
332 return 1;
333 }
334
335 static void tron_get_parameters(slv_system_t server, SlvClientToken asys
336 , slv_parameters_t *parameters
337 ){
338 TronSystem *sys;
339 UNUSED_PARAMETER(server);
340
341 sys = TRONSYS(asys);
342 if (check_system(sys)) return;
343 mem_copy_cast(&(sys->params),parameters,sizeof(slv_parameters_t));
344 }
345
346 static void tron_set_parameters(slv_system_t server, SlvClientToken asys
347 ,slv_parameters_t *parameters
348 ){
349 TronSystem *sys;
350 UNUSED_PARAMETER(server);
351
352 sys = TRONSYS(asys);
353 if (check_system(sys)) return;
354 mem_copy_cast(parameters,&(sys->params),sizeof(slv_parameters_t));
355 }
356
357 /*-----------------------------------------------------------------------------
358 SET-UP AND DESTROY SOLVER DATA
359 */
360
361 static SlvClientToken tron_create(slv_system_t server, int32*statusindex){
362 TronSystem *sys;
363
364 sys = ASC_NEW_CLEAR(TronSystem);
365 if(sys==NULL){
366 *statusindex = 1;
367 return sys;
368 }
369
370 sys->slv = server;
371 sys->params.parms = sys->pa;
372 sys->params.dynamic_parms = 0;
373 tron_get_default_parameters(server,(SlvClientToken)sys,&(sys->params));
374
375 sys->created = TRON_CREATED;
376 sys->presolved = 0;
377
378 sys->params.whose = (*statusindex);
379
380 sys->status.ok = TRUE;
381 sys->status.calc_ok = TRUE;
382 sys->status.costsize = 0;
383 sys->status.cost = NULL; /*redundant, but sanity-preserving */
384 sys->vlist = slv_get_solvers_var_list(server);
385 sys->rlist = slv_get_solvers_rel_list(server);
386 sys->rtot = slv_get_num_solvers_rels(server);
387 sys->vtot = slv_get_num_solvers_vars(server);
388
389 sys->obj = slv_get_obj_relation(server);
390
391 if (sys->vlist == NULL) {
392 ascfree(sys);
393 ERROR_REPORTER_HERE(ASC_PROG_ERR,"TRON called with no variables.");
394 *statusindex = -2;
395 return NULL; /* prolly leak here */
396 }
397 if (sys->rlist == NULL && sys->obj == NULL) {
398 ascfree(sys);
399 ERROR_REPORTER_HERE(ASC_PROG_ERR,"TRON called with no relations or objective.");
400 *statusindex = -1;
401 return NULL; /* prolly leak here */
402 }
403
404 /*
405 apparently we don't give a damn about the objective list or the pars or
406 bounds or extrels or any of the other crap.
407 */
408
409 slv_check_var_initialization(server);
410
411 sys->xc = ASC_NEW_ARRAY(double,sys->n);
412 sys->s = ASC_NEW_ARRAY(double,sys->n);
413 sys->indfree = ASC_NEW_ARRAY(int,sys->n);
414 sys->isave = ASC_NEW_ARRAY(int,sys->n*3);
415 sys->dsave = ASC_NEW_ARRAY(double,sys->n*3);
416 sys->wa = ASC_NEW_ARRAY(double,sys->n*7);
417 sys->iwa = ASC_NEW_ARRAY(int,sys->n*3);
418
419 *statusindex = 0; /* <-- what is that? */
420
421 return((SlvClientToken)sys);
422 }
423
424
425 /**
426 @TODO document this
427 */
428 static int32 tron_destroy(slv_system_t server, SlvClientToken asys){
429 TronSystem *sys;
430 UNUSED_PARAMETER(server);
431
432 sys = TRONSYS(asys);
433 if (check_system(sys)) return 1;
434 /* destroy_vectors(sys); */
435 /* destroy_matrices(sys); */
436 slv_destroy_parms(&(sys->params));
437 sys->created = TRON_DESTROYED;
438 if(sys->status.cost){
439 ASC_FREE(sys->status.cost);
440 }
441
442 /* clear all the work arrays used by TRON */
443 #define F(AA) if(sys->AA)ASC_FREE(sys->AA)
444 F(xc); F(s); F(indfree); F(isave); F(dsave); F(wa); F(iwa);
445 #undef F
446
447 ascfree( (POINTER)asys );
448 return 0;
449 }
450
451 #if 0
452 static void create_matrices(slv_system_t server, TronSystem *sys){
453 sys->J.mtx = mtx_create();
454 mtx_set_order(sys->J.mtx,sys->cap);
455 structural_analysis(server,sys);
456 }
457
458
459 static void create_vectors(TronSystem *sys){
460 sys->nominals.vec = create_array(sys->cap,real64);
461 sys->nominals.rng = &(sys->J.reg.col);
462 sys->weights.vec = create_array(sys->cap,real64);
463 sys->weights.rng = &(sys->J.reg.row);
464 sys->relnoms.vec = create_array(sys->cap,real64);
465 sys->relnoms.rng = &(sys->J.reg.row);
466 sys->variables.vec = create_array(sys->cap,real64);
467 sys->variables.rng = &(sys->J.reg.col);
468 sys->residuals.vec = create_array(sys->cap,real64);
469 sys->residuals.rng = &(sys->J.reg.row);
470 }
471 #endif
472
473 #if 0
474 static void destroy_matrices( TronSystem *sys){
475 if( sys->J.mtx ) {
476 mtx_destroy(sys->J.mtx);
477 }
478 }
479
480 static void destroy_vectors( TronSystem *sys){
481 destroy_array(sys->nominals.vec);
482 destroy_array(sys->weights.vec);
483 destroy_array(sys->relnoms.vec);
484 destroy_array(sys->variables.vec);
485 destroy_array(sys->residuals.vec);
486 }
487 #endif
488
489 /*------------------------------------------------------------------------------
490 HIGH-LEVEL SOLVE ROUTINES
491 */
492
493 static int tron_presolve(slv_system_t server, SlvClientToken asys){
494 struct rel_relation **rp;
495 int32 ind;
496 int32 matrix_creation_needed = 1;
497 TronSystem *sys;
498
499 #if 0
500 int32 cap;
501 struct var_variable **vp;
502 int *cntvect, temp;
503 #endif
504
505 TRON_CONSOLE_DEBUG("PRESOLVE");
506
507 sys = TRONSYS(asys);
508 iteration_begins(sys);
509 check_system(sys);
510 if( sys->vlist == NULL ) {
511 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Variable list was not set.");
512 return -1;
513 }
514 if( sys->rlist == NULL && sys->obj == NULL ) {
515 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Relation list and objective were not set.");
516 return -2;
517 }
518
519 sys->obj = slv_get_obj_relation(server); /*may have changed objective*/
520
521 if(!sys->obj){
522 ERROR_REPORTER_HERE(ASC_PROG_ERR,"No objective function was specified");
523 return -3;
524 }
525
526 if(sys->presolved > 0) { /* system has been presolved before */
527 if(!tron_dof_changed(sys) /*no changes in fixed or included flags*/
528 /* && sys->params.partition == sys->J.old_partition
529 && sys->obj == sys->old_obj */
530 ){
531 matrix_creation_needed = 0;
532 TRON_CONSOLE_DEBUG("YOU JUST AVOIDED MATRIX DESTRUCTION/CREATION");
533 }
534 }
535
536 rp=sys->rlist;
537 for( ind = 0; ind < sys->rtot; ++ind ) {
538 rel_set_satisfied(rp[ind],FALSE);
539 }
540 if( matrix_creation_needed ) {
541
542 #if 0
543 cap = slv_get_num_solvers_rels(sys->slv);
544 sys->cap = slv_get_num_solvers_vars(sys->slv);
545 sys->cap = MAX(sys->cap,cap);
546 vp=sys->vlist;
547 for( ind = 0; ind < sys->vtot; ++ind ) {
548 var_set_in_block(vp[ind],FALSE);
549 }
550 rp=sys->rlist;
551 for( ind = 0; ind < sys->rtot; ++ind ) {
552 rel_set_in_block(rp[ind],FALSE);
553 rel_set_satisfied(rp[ind],FALSE);
554 }
555 #endif
556
557 sys->presolved = 1; /* full presolve recognized here */
558
559 #if 0
560 sys->J.old_partition = sys->params.partition;
561 #endif
562 sys->old_obj = sys->obj;
563
564 slv_sort_rels_and_vars(server,&(sys->m),&(sys->n));
565 TRON_CONSOLE_DEBUG("FOUND %d CONSTRAINTS AND %d VARS",sys->m,sys->n);
566 if (sys->obj != NULL) {
567 TRON_CONSOLE_DEBUG("ADDING OBJECT AS A ROW");
568 sys->m++; /* treat objective as a row */
569 }
570
571 /* destroy_vectors(sys); */
572 /* destroy_matrices(sys); */
573 /* create_matrices(server,sys); */
574 /* create_vectors(sys); */
575
576 sys->status.block.current_reordered_block = -2;
577 }
578
579 /* Reset status */
580 sys->optimised = 0;
581 sys->status.iteration = 0;
582 sys->status.cpu_elapsed = 0.0;
583 sys->status.converged = sys->status.diverged = sys->status.inconsistent = FALSE;
584 sys->status.block.previous_total_size = 0;
585 sys->status.costsize = 1+sys->status.block.number_of;
586
587 if( matrix_creation_needed ) {
588 #if 0
589 destroy_array(sys->status.cost);
590 sys->status.cost = create_zero_array(sys->status.costsize,struct slv_block_cost);
591 for( ind = 0; ind < sys->status.costsize; ++ind ) {
592 sys->status.cost[ind].reorder_method = -1;
593 }
594 } else {
595 reset_cost(sys->status.cost,sys->status.costsize);
596 #endif
597 }
598
599 /* set to go to first unconverged block */
600 sys->status.block.current_block = -1;
601 sys->status.block.current_size = 0;
602 sys->status.calc_ok = TRUE;
603 sys->status.block.iteration = 0;
604 sys->objective = MAXDOUBLE/2000.0;
605
606 update_status(sys);
607 iteration_ends(sys);
608 sys->status.cost[sys->status.block.number_of].time=sys->status.cpu_elapsed;
609
610 return 0;
611 }
612
613 const char TRON_START[] = "START";
614 const char TRON_GH[] = "GH";
615 const char TRON_CONV[] = "CONV";
616
617 /**
618 @TODO document this
619 */
620 static int tron_iterate(slv_system_t server, SlvClientToken asys){
621 TronSystem *sys;
622 sys = TRONSYS(asys);
623
624 if(server == NULL || sys==NULL) return -1;
625 if(check_system(sys)) return -2;
626 if(!sys->status.ready_to_solve){
627 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Not ready to solve.");
628 return 1;
629 }
630
631 if(sys->status.block.current_block==-1) {
632 tron_initialize(sys);
633 sys->status.converged = sys->optimised;
634 update_status(sys);
635 /* do something with scaling here? calc_relnoms(sys)? */
636 }
637
638 iteration_begins(sys);
639
640 /* may have changed objective (how does that happen, BTW?) */
641 sys->obj = slv_get_obj_relation(server);
642
643 if(sys->task[0]=='F' || strncmp(sys->task,TRON_START,5)==0){
644
645 // Evaluate the function at x and store in f.
646
647 }
648 if(strncmp(sys->task,TRON_GH,2)==0 || strncmp(sys->task,TRON_START,5)==0){
649
650 // Evaluate the gradient at x and store in g.
651
652 // Evaluate the Hessian at x and store in compressed
653 // column storage in (a,adiag,acol_ptr,arow_ind)
654 }
655
656 double frtol = SLV_PARAM_REAL(&(sys->params),TRON_PARAM_FRTOL);
657 double fatol = SLV_PARAM_REAL(&(sys->params),TRON_PARAM_FATOL);
658 double cgtol = SLV_PARAM_REAL(&(sys->params),TRON_PARAM_CGTOL);
659 int itermax = SLV_PARAM_INT(&(sys->params),TRON_PARAM_ITERMAX);
660 double fmin = SLV_PARAM_REAL(&(sys->params),TRON_PARAM_FMIN);
661 double delta = SLV_PARAM_REAL(&(sys->params),TRON_PARAM_GTOL);
662 /** @TODO fmin should be taken from the model declaration somehow, not a solar parameter. */
663
664 DTRON(&(sys->n),sys->x,sys->xlower,sys->xupper,sys->f,sys->g
665 ,TRON_MATRIX_ARG(sys,A)
666 ,&frtol,&fatol,&fmin,&cgtol,&itermax,&delta,sys->task
667 ,TRON_MATRIX_ARG(sys,B)
668 ,TRON_MATRIX_ARG(sys,L)
669 ,sys->xc,sys->s,sys->indfree
670 ,sys->isave,sys->dsave,sys->wa,sys->iwa
671 );
672
673 if(strncmp(sys->task,TRON_CONV,4)==0){
674 sys->status.converged = 1;
675 TRON_CONSOLE_DEBUG("System has converged");
676 }
677
678 TRON_CONSOLE_DEBUG("DTRON status is '%s'",sys->task);
679
680 calc_objective(sys);
681 #if 0
682 calc_objectives(sys);
683 sys->residuals.accurate = FALSE;
684 #endif
685 calc_residuals(sys);
686 #if 0
687 update_cost(sys);
688 #endif
689 iteration_ends(sys);
690 update_status(sys);
691
692 return 0;
693 }
694
695 /**
696 @TODO document this
697 */
698 static int tron_solve(slv_system_t server, SlvClientToken asys){
699 TronSystem *sys;
700 int err = 0;
701 sys = TRONSYS(asys);
702 if(server == NULL || sys==NULL) return -1;
703 if(check_system(sys)) return -2;
704 while(sys->status.ready_to_solve)err = err | tron_iterate(server,sys);
705 return err;
706 }
707
708 /*------------------------------------------------------------------------------
709 INTEGRITY CHECKS
710 */
711
712 /**
713 Checks sys for NULL and for integrity.
714 */
715 static int check_system(TronSystem *sys){
716
717 if( sys == NULL ) {
718 ERROR_REPORTER_HERE(ASC_PROG_ERR,"NULL system handle");
719 return 1;
720 }
721
722 switch( sys->created ) {
723 case TRON_CREATED:
724 return 0;
725 case TRON_DESTROYED:
726 ERROR_REPORTER_HERE(ASC_PROG_ERR,"System was recently destroyed.");
727 return 1;
728 default:
729 ERROR_REPORTER_HERE(ASC_PROG_ERR,"System reused or never allocated.");
730 return 1;
731 }
732 }
733
734 /*------------------------------------------------------------------------------
735 CALCULATION ROUTINES
736
737 ok = calc_objective(sys)
738 ok = calc_residuals(sys)
739 ok = calc_J(sys)
740 calc_nominals(sys)
741 calc_weights(sys)
742 scale_J(sys)
743 scale_variables(sys)
744 scale_residuals(sys)
745 */
746
747 #if 0
748 /**
749 Count jacobian elements and set max to the number of elements
750 in the densest row
751 */
752 static int32 num_jacobian_nonzeros(TronSystem *sys, int32 *max){
753 int32 row, len, licn,c,count,row_max;
754 struct rel_relation *rel;
755 rel_filter_t rf;
756 var_filter_t vf;
757 const struct var_variable **list;
758
759 rf.matchbits = (REL_INCLUDED | REL_EQUALITY | REL_ACTIVE);
760 rf.matchvalue = (REL_INCLUDED | REL_EQUALITY | REL_ACTIVE);
761 vf.matchbits = (VAR_ACTIVE | VAR_INCIDENT | VAR_SVAR | VAR_FIXED);
762 vf.matchvalue = (VAR_ACTIVE | VAR_INCIDENT | VAR_SVAR);
763
764 licn = 0;
765 *max = 0;
766 row_max = sys->m;
767 if (sys->obj != NULL) {
768 row_max--;
769 }
770 /* replace at leisure with
771 * relman_jacobian_count(sys->rlist,row_max,&vfilter,&rfilter,max);
772 */
773 for( row = 0; row < row_max; row++ ) {
774 rel = sys->rlist[row];
775 if (rel_apply_filter(rel,&rf)) { /* shouldn't be needed */
776 len = rel_n_incidences(rel);
777 list = rel_incidence_list(rel);
778 count = 0;
779 for (c=0; c < len; c++) {
780 if( var_apply_filter(list[c],&vf) ) {
781 licn++;
782 count++;
783 }
784 }
785 *max = MAX(*max,count);
786 }
787 }
788 if (sys->obj != NULL) {
789 rel = sys->obj;
790 len = rel_n_incidences(rel);
791 list = rel_incidence_list(rel);
792 count = 0;
793 for (c=0; c < len; c++) {
794 if( var_apply_filter(list[c],&vf) ) {
795 licn++;
796 count++;
797 }
798 }
799 *max = MAX(*max,count);
800 }
801 return licn;
802 }
803 #endif
804
805 /**
806 Evaluate the objective function.
807 */
808 static boolean calc_objective(TronSystem *sys){
809 boolean calc_ok = TRUE;
810 asc_assert(sys->obj!=NULL);
811 if(sys->obj){
812 sys->objective = relman_eval(sys->obj,&calc_ok,SLV_PARAM_BOOL(&(sys->params),TRON_PARAM_SAFECALC));
813 }else{
814 sys->objective = 0.0;
815 }
816 return calc_ok;
817 }
818
819 #if 0
820 /**
821 Evaluate all objectives.
822 */
823 static boolean calc_objectives( TronSystem *sys){
824 int32 len,i;
825 static rel_filter_t rfilter;
826 struct rel_relation **rlist=NULL;
827 rfilter.matchbits = (REL_INCLUDED);
828 rfilter.matchvalue =(REL_INCLUDED);
829 rlist = slv_get_solvers_obj_list(sys->slv);
830 len = slv_get_num_solvers_objs(sys->slv);
831 calc_ok = TRUE;
832 for (i = 0; i < len; i++) {
833 if (rel_apply_filter(rlist[i],&rfilter)) {
834 asc_assert(rlist[i]!=NULL);
835 relman_eval(rlist[i],&calc_ok,SAFE_CALC);
836 if DEBUG
837 if (calc_ok == FALSE) {
838 ERROR_REPORTER_HERE(ASC_PROG_ERR,"error in calc_objectives");
839 calc_ok = TRUE;
840 }
841 endif /* DEBUG */
842 }
843 }
844 return calc_ok;
845 }
846 #endif
847
848 #if 0
849 /**
850 Calculate all of the residuals in the current block and compute
851 the residual norm for block status.
852
853 @return true iff calculations preceded without error.
854 */
855 static boolean calc_residuals( TronSystem *sys){
856 int32 row;
857 struct rel_relation *rel;
858 double time0;
859
860 if( sys->residuals.accurate ) return TRUE;
861
862 calc_ok = TRUE;
863 row = sys->residuals.rng->low;
864 time0=tm_cpu_time();
865 for( ; row <= sys->residuals.rng->high; row++ ) {
866 rel = sys->rlist[mtx_row_to_org(sys->J.mtx,row)];
867 if DEBUG
868 if (!rel) {
869 int32r;
870 r=mtx_row_to_org(sys->J.mtx,row);
871 ERROR_REPORTER_HERE(ASC_PROG_ERR
872 ,"NULL relation found at row %d rel %d in calc_residuals!",(int)row,r
873 );
874 }
875 endif /* DEBUG */
876 asc_assert(rel!=NULL);
877 sys->residuals.vec[row] = relman_eval(rel,&calc_ok,SAFE_CALC);
878
879 relman_calc_satisfied(rel,sys->params.tolerance.feasible);
880 }
881 sys->status.block.functime += (tm_cpu_time() -time0);
882 sys->status.block.funcs++;
883 square_norm( &(sys->residuals) );
884 sys->status.block.residual = calc_sqrt_D0(sys->residuals.norm2);
885 if(!calc_ok){
886 TRON_CONSOLE_DEBUG("ERROR IN EVALUATION");
887 }
888 return(calc_ok);
889 }
890 #endif
891
892 #if 0
893 /**
894 Calculate the current block of the jacobian.
895 It is initially unscaled.
896 */
897 static boolean calc_J( TronSystem *sys){
898 int32 row;
899 var_filter_t vfilter;
900 double time0;
901 real64 resid;
902
903 calc_ok = TRUE;
904 vfilter.matchbits = (VAR_ACTIVE | VAR_INCIDENT | VAR_SVAR | VAR_FIXED);
905 vfilter.matchvalue = (VAR_ACTIVE | VAR_INCIDENT | VAR_SVAR);
906 time0=tm_cpu_time();
907 mtx_clear_region(sys->J.mtx,&(sys->J.reg));
908 for( row = sys->J.reg.row.low; row <= sys->J.reg.row.high; row++ ) {
909 struct rel_relation *rel;
910 rel = sys->rlist[row];
911 relman_diffs(rel,&vfilter,sys->J.mtx,&resid,SAFE_CALC);
912 }
913 sys->status.block.jactime += (tm_cpu_time() - time0);
914 sys->status.block.jacs++;
915
916 if( --(sys->update.nominals) <= 0 ) sys->nominals.accurate = FALSE;
917 if( --(sys->update.weights) <= 0 ) sys->weights.accurate = FALSE;
918
919 return(calc_ok);
920 }
921 #endif
922
923 #if 0
924 /**
925 Retrieve the nominal values of all of the block variables,
926 and ensure that they are all strictly positive.
927 */
928 static void calc_nominals( TronSystem *sys){
929 int32 col;
930 if( sys->nominals.accurate ) return;
931 col = sys->nominals.rng->low;
932 if(strcmp(SCALEOPT,"NONE") == 0 ||
933 strcmp(SCALEOPT,"ITERATIVE") == 0){
934 for( ; col <= sys->nominals.rng->high; col++ ) {
935 sys->nominals.vec[col] = 1;
936 }
937 } else {
938 for( ; col <= sys->nominals.rng->high; col++ ) {
939 struct var_variable *var;
940 real64 n;
941 var = sys->vlist[mtx_col_to_org(sys->J.mtx,col)];
942 n = var_nominal(var);
943 if( n <= 0.0 ) {
944 if( n == 0.0 ) {
945 n = TOO_SMALL;
946
947 ERROR_REPORTER_START_HERE(ASC_USER_ERROR);
948 FPRINTF(ASCERR,"Variable ");
949 print_var_name(ASCERR,sys,var);
950 FPRINTF(ASCERR," has nominal value of zero. Resetting to %g.\n",n);
951 error_reporter_end_flush();
952
953 var_set_nominal(var,n);
954 } else {
955 n = -n;
956
957 ERROR_REPORTER_START_HERE(ASC_USER_ERROR);
958 FPRINTF(ASCERR,"Variable ");
959 print_var_name(ASCERR,sys,var);
960 FPRINTF(ASCERR," has negative nominal value. Resetting to %g.\n",n);
961 error_reporter_end_flush();
962
963 var_set_nominal(var,n);
964 }
965 }
966 if DEBUG
967 ERROR_REPORTER_START_HERE(ASC_USER_ERROR);
968 FPRINTF(ASCERR,"Column %d is");
969 print_var_name(ASCERR,sys,var);
970 FPRINTF(ASCERR,"\nScaling of column %d is %g\n",col,n);
971 error_reporter_end_flush();
972 endif /* DEBUG */
973 sys->nominals.vec[col] = n;
974 }
975 }
976 square_norm( &(sys->nominals) );
977 sys->update.nominals = UPDATE_NOMINALS;
978 sys->nominals.accurate = TRUE;
979 }
980 #endif
981
982 #if 0
983 /**
984 Calculate the weights of all of the block relations
985 to scale the rows of the Jacobian.
986 */
987 static void calc_weights( TronSystem *sys)
988 {
989 mtx_coord_t nz;
990 real64 sum;
991
992 if( sys->weights.accurate )
993 return;
994
995 nz.row = sys->weights.rng->low;
996 if(strcmp(SCALEOPT,"NONE") == 0 ||
997 strcmp(SCALEOPT,"ITERATIVE") == 0) {
998 for( ; nz.row <= sys->weights.rng->high; (nz.row)++ ) {
999 sys->weights.vec[nz.row] = 1;
1000 }
1001 } else if (strcmp(SCALEOPT,"ROW_2NORM") == 0 ||
1002 strcmp(SCALEOPT,"2NORM+ITERATIVE") == 0) {
1003 for( ; nz.row <= sys->weights.rng->high; (nz.row)++ ) {
1004 sum=mtx_sum_sqrs_in_row(sys->J.mtx,nz.row,&(sys->J.reg.col));
1005 sys->weights.vec[nz.row] = (sum>0.0) ? 1.0/calc_sqrt_D0(sum) : 1.0;
1006 }
1007 } else if (strcmp(SCALEOPT,"RELNOM") == 0 ||
1008 strcmp(SCALEOPT,"RELNOM+ITERATIVE") == 0) {
1009 for( ; nz.row <= sys->weights.rng->high; (nz.row)++ ) {
1010 sys->weights.vec[nz.row] =
1011 1.0/rel_nominal(sys->rlist[mtx_row_to_org(sys->J.mtx,nz.row)]);
1012 }
1013 }
1014 square_norm( &(sys->weights) );
1015 sys->update.weights = UPDATE_WEIGHTS;
1016 sys->residuals.accurate = FALSE;
1017 sys->weights.accurate = TRUE;
1018 }
1019 #endif
1020
1021
1022 /**
1023 Reset all flags to setup a new solve.
1024 Should set sys->status.block.current_block = -1
1025 before calling.
1026
1027 @TODO This is currently a HACK! Not sure if should call when done.
1028 */
1029 void tron_initialize( TronSystem *sys){
1030
1031 sys->status.block.current_block++;
1032 /*
1033 * Next line was added to create the aray cost, whis is used by
1034 * the interface to display residuals and number of iterations
1035 */
1036 sys->status.costsize = 1+sys->status.block.number_of;
1037
1038 if( sys->status.block.current_block < sys->status.block.number_of ) {
1039 boolean ok;
1040
1041 sys->status.block.iteration = 0;
1042 sys->status.block.cpu_elapsed = 0.0;
1043 sys->status.block.functime = 0.0;
1044 sys->status.block.jactime = 0.0;
1045 sys->status.block.funcs = 0;
1046 sys->status.block.jacs = 0;
1047
1048 sys->status.calc_ok = TRUE;
1049
1050 if( !(ok = calc_objective(sys)) ) {
1051 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Objective calculation errors detected.");
1052 }
1053
1054 #if 0
1055 sys->status.calc_ok = sys->status.calc_ok && ok;
1056
1057 if(!(sys->params.ignore_bounds) ) {
1058 slv_ensure_bounds(
1059 sys->slv, sys->J.reg.col.low,
1060 sys->J.reg.col.high,MIF(sys)
1061 );
1062 }
1063
1064 sys->residuals.accurate = FALSE;
1065 if( !(ok = calc_residuals(sys)) ) {
1066 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Residual calculation errors detected.");
1067 }
1068
1069 sys->status.calc_ok = sys->status.calc_ok && ok;
1070
1071 /* Must be updated as soon as required */
1072 sys->J.accurate = FALSE;
1073 sys->update.weights = 0;
1074 sys->update.nominals = 0;
1075 sys->update.relnoms = 0;
1076 sys->update.iterative = 0;
1077 sys->variables.accurate = FALSE;
1078 #endif
1079 }
1080 }
1081
1082
1083 /*------------------------------------------------------------------------------
1084 ITERATION BEGIN/END ROUTINES
1085 */
1086
1087 /**
1088 Prepare sys for entering an iteration, increasing the iteration counts
1089 and starting the clock.
1090 */
1091 static void iteration_begins(TronSystem *sys){
1092 sys->clock = tm_cpu_time();
1093 ++(sys->status.block.iteration);
1094 ++(sys->status.iteration);
1095 }
1096
1097
1098 /*
1099 Prepare sys for exiting an iteration, stopping the clock and recording
1100 the cpu time.
1101 */
1102 static void iteration_ends( TronSystem *sys){
1103 double cpu_elapsed; /* elapsed this iteration */
1104
1105 cpu_elapsed = (double)(tm_cpu_time() - sys->clock);
1106 sys->status.block.cpu_elapsed += cpu_elapsed;
1107 sys->status.cpu_elapsed += cpu_elapsed;
1108 }
1109
1110
1111 /**
1112 Update the solver status.
1113 */
1114 static void update_status( TronSystem *sys){
1115 boolean unsuccessful;
1116
1117 #if 0
1118 if( !sys->status.converged ) {
1119 sys->status.time_limit_exceeded =
1120 (sys->status.block.cpu_elapsed >= TIME_LIMIT);
1121 sys->status.iteration_limit_exceeded =
1122 (sys->status.block.iteration >= ITER_LIMIT);
1123 }
1124 #endif
1125
1126 unsuccessful = sys->status.diverged || sys->status.inconsistent ||
1127 sys->status.iteration_limit_exceeded || sys->status.time_limit_exceeded;
1128
1129 sys->status.ready_to_solve = !unsuccessful && !sys->status.converged;
1130 sys->status.ok = !unsuccessful && sys->status.calc_ok && !sys->status.struct_singular;
1131 }
1132
1133 /*-----------------------------------------------------------------------------
1134 EXTERNAL ROUTINES (see slv_client.h)
1135 */
1136
1137 static int32 tron_eligible_solver(slv_system_t server){
1138 struct rel_relation **rp;
1139 for( rp=slv_get_solvers_rel_list(server); *rp != NULL ; ++rp ) {
1140 if( rel_less(*rp) || rel_greater(*rp) ){
1141 ERROR_REPORTER_NOLINE(ASC_USER_ERROR,"less-than and greater-than relations are not permitted with TRON");
1142 return(FALSE);
1143 }
1144 }
1145 return(TRUE);
1146 }
1147
1148
1149 static int tron_get_status(slv_system_t server, SlvClientToken asys
1150 ,slv_status_t *status
1151 ){
1152 TronSystem *sys;
1153 UNUSED_PARAMETER(server);
1154
1155 sys = TRONSYS(asys);
1156 if (check_system(sys)) return 1;
1157 mem_copy_cast(&(sys->status),status,sizeof(slv_status_t));
1158 return 0;
1159 }
1160
1161 #if 0
1162 /**
1163 Perform structural analysis on the system, setting the flags in
1164 status.
1165
1166 The problem must be set up, the relation/variable list
1167 must be non-NULL. The jacobian (linear) system must be created
1168 and have the correct order (stored in sys->cap). Everything else
1169 will be determined here.
1170
1171 On entry there isn't yet a correspondence between var_sindex and
1172 jacobian column. Here we establish that.
1173
1174 @NOTE this function has been striped of its guts for TRON and may go away
1175 */
1176 static void structural_analysis(slv_system_t server, TronSystem *sys){
1177
1178 var_filter_t vfilter;
1179 rel_filter_t rfilter;
1180
1181 /*
1182 * The server has marked incidence flags already.
1183 */
1184 /* count included equalities */
1185 rfilter.matchbits = (REL_INCLUDED | REL_EQUALITY | REL_ACTIVE);
1186 rfilter.matchvalue = (REL_INCLUDED | REL_EQUALITY | REL_ACTIVE);
1187 sys->rused = slv_count_solvers_rels(server,&rfilter);
1188
1189 /* count free and incident vars */
1190 vfilter.matchbits = (VAR_FIXED | VAR_INCIDENT | VAR_SVAR | VAR_ACTIVE);
1191 vfilter.matchvalue = (VAR_INCIDENT | VAR_SVAR | VAR_ACTIVE);
1192 sys->vused = slv_count_solvers_vars(server,&vfilter);
1193
1194 /* Symbolic analysis */
1195 sys->rtot = slv_get_num_solvers_rels(server);
1196 sys->vtot = slv_get_num_solvers_vars(server);
1197
1198 /*
1199 * The next few lines are used to calculate the rank of the nonlinear
1200 * system. We need it to evaluate if the system is structurally
1201 * singular or not. Calculating this number will keep TRON from
1202 * displaying a "structurally singular" error message
1203 */
1204 if (sys->rtot) {
1205 slv_block_partition(server);
1206 }
1207 sys->J.dofdata = slv_get_dofdata(server);
1208 sys->rank = sys->J.dofdata->structural_rank;
1209 /*
1210 * Unify the partitions since we feed TRON with a single block.
1211 */
1212 slv_block_unify(server);
1213
1214
1215 sys->J.reg.row.low = sys->J.reg.col.low = 0;
1216 sys->J.reg.row.high = sys->m - 1;
1217 if (sys->obj != NULL) sys->J.reg.row.high--;
1218 sys->J.reg.col.high = sys->n - 1;
1219
1220 if(slv_check_bounds(sys->slv,sys->vused,-1,"fixed ")){
1221 sys->status.inconsistent = 1;
1222 }
1223
1224 /* Initialize Status */
1225 sys->status.over_defined = (sys->rused > sys->vused);
1226 sys->status.under_defined = (sys->rused < sys->vused);
1227 sys->status.struct_singular = (sys->rank < sys->rused);
1228 sys->status.block.number_of = (slv_get_solvers_blocks(sys->slv))->nblocks;
1229
1230 }
1231 #endif
1232
1233 /**
1234 Check if any fixed or included flags have
1235 changed since the last presolve.
1236 */
1237 static int32 tron_dof_changed(TronSystem *sys){
1238 int32 ind, result = 0;
1239 /* Currently we have two copies of the fixed and included flags
1240 which must be kept in sync. The var_fixed and rel_included
1241 functions perform the syncronization and hence must be called
1242 over the whole var list and rel list respectively. When we move
1243 to using only one set of flags (bit flags) this function can
1244 be changed to return 1 at the first indication of a change
1245 in the dof. */
1246
1247 /* search for vars that were fixed and are now free */
1248 for( ind = sys->vused; ind < sys->vtot; ++ind ) {
1249 if( !var_fixed(sys->vlist[ind]) && var_active(sys->vlist[ind]) ) {
1250 ++result;
1251 }
1252 }
1253 /* search for rels that were unincluded and are now included */
1254 for( ind = sys->rused; ind < sys->rtot; ++ind ) {
1255 if( rel_included(sys->rlist[ind]) && rel_active(sys->rlist[ind])) {
1256 ++result;
1257 }
1258 }
1259 /* search for vars that were free and are now fixed */
1260 for( ind = sys->vused -1; ind >= 0; --ind ) {
1261 if( var_fixed(sys->vlist[ind]) || !var_active(sys->vlist[ind])) {
1262 ++result;
1263 }
1264 }
1265 /* search for rels that were included and are now unincluded */
1266 for( ind = sys->rused -1; ind >= 0; --ind ) {
1267 if( !rel_included(sys->rlist[ind]) || !rel_active(sys->rlist[ind]) ) {
1268 ++result;
1269 }
1270 }
1271 return result;
1272 }
1273
1274 #if 0
1275 static void reset_cost(struct slv_block_cost *cost,int32 costsize){
1276 int32 ind;
1277 for( ind = 0; ind < costsize; ++ind ) {
1278 cost[ind].size = 0;
1279 cost[ind].iterations = 0;
1280 cost[ind].funcs = 0;
1281 cost[ind].jacs = 0;
1282 cost[ind].functime = 0;
1283 cost[ind].jactime = 0;
1284 cost[ind].time = 0;
1285 cost[ind].resid = 0;
1286 }
1287 }
1288 #endif
1289
1290 #if 0
1291 /**
1292 Update the values of the array cost, which is used by the interface
1293 to display residual and number of iterations. For use after running CONOPT
1294 */
1295 static void update_cost(TronSystem *sys)
1296 {
1297 int32 ci;
1298 if (sys->status.cost == NULL) {
1299 sys->status.cost = create_zero_array(sys->status.costsize,struct slv_block_cost);
1300 } else {
1301 reset_cost(sys->status.cost,sys->status.costsize);
1302 }
1303 ci=sys->status.block.current_block;
1304 sys->status.cost[ci].size = sys->status.block.current_size;
1305 sys->status.cost[ci].iterations = sys->status.block.iteration;
1306 sys->status.cost[ci].resid = sys->status.block.residual;
1307 }
1308 #endif
1309
1310 /*------------------------------------------------------------------------------
1311 LOADING TRON FROM SHARED LIBRARY, IF AVAILABLE
1312 */
1313
1314 typedef struct{
1315 dtron_fn_t *dtron_ptr;
1316 } DTronFns;
1317
1318 DTronFns tron_fptrs;
1319
1320 int tron_dlopen(){
1321 static int loaded=0;
1322 char *libpath;
1323 int status;
1324 char fnsymbol[400], *c;
1325 const char *libname=ASC_TRON_LIB;
1326 const char *envvar;
1327
1328 if(loaded) {
1329 return 0; /* already loaded */
1330 }
1331
1332 CONSOLE_DEBUG("LOADING TRON...");
1333
1334 envvar = ASC_TRON_ENVVAR;
1335
1336 /* need to import this variable into the ascend 'environment' */
1337 if(-1!=env_import(ASC_TRON_ENVVAR,getenv,Asc_PutEnv)){
1338 CONSOLE_DEBUG("Searching in path '%s' (from env var '%s')",getenv(envvar),envvar);
1339 }
1340 libpath = SearchArchiveLibraryPath(libname, ASC_TRON_DLPATH, envvar);
1341
1342 if(libpath==NULL){
1343 ERROR_REPORTER_NOLINE(ASC_PROG_ERR
1344 , "Library '%s' could not be located (check value of env var '%s' and/or default path '%s')"
1345 , libname, envvar, ASC_TRON_DLPATH
1346 );
1347 return 1;
1348 }
1349
1350 status = Asc_DynamicLoad(libpath, NULL);
1351 if (status != 0) {
1352 ASC_FREE(libpath);
1353 return 1; /* failed to load */
1354 }
1355
1356
1357 # if defined(FNAME_UCASE_NODECOR) || defined(FNAME_UCASE_DECOR) || defined(FNAME_UCASE_PREDECOR)
1358 # define FNCASE(C) C=toupper(C)
1359 # elif defined(FNAME_LCASE_NODECOR) || defined(FNAME_LCASE_DECOR)
1360 # define FNCASE(C) C=tolower(C)
1361 # else
1362 # error "Need platform-specific information (asc_tron.c)"
1363 # endif
1364
1365 # if defined(FNAME_UCASE_DECOR) || defined(FNAME_LCASE_DECOR)
1366 # define FNDECOR(S,L) strcat(S,"_")
1367 # elif defined(FNAME_UCASE_PREDECOR) /* on windows, precede with _ and append @L (integer value of L) */
1368 # define FNDECOR(S,L) strcat(S,L);for(c=S+strlen(S)+1;c>S;--c){*c=*(c-1);} *S='_';
1369 # else
1370 # define FNDECOR(S,L) (void)0
1371 # endif
1372
1373 # define FN_PTR_GET(T,A,V,L) \
1374 sprintf(fnsymbol,"%s",#T); \
1375 for(c=fnsymbol;*c!='\0';++c){ \
1376 FNCASE(*c); \
1377 } \
1378 FNDECOR(fnsymbol,L); \
1379 tron_fptrs.T##_ptr = (T##_fn_t *)Asc_DynamicFunction(libpath,fnsymbol); \
1380 if(tron_fptrs.T##_ptr==NULL)status+=1;
1381
1382 FN_PTR_GET(dtron,TRON_DTRON_ARGS,TRON_DTRON_VALS,"");
1383
1384 # undef FN_PTR_GET
1385 # undef FNDECOR
1386 # undef FNCASE
1387
1388 ASC_FREE(libpath);
1389
1390 if(status!=0){
1391 return 1; /* failed to resolve all symbols */
1392 }
1393
1394 loaded = 1; /* save result for next time, as we will never unload it */
1395 return 0;
1396 }
1397
1398 /*------------------------------------------------------------------------------
1399 REGISTERING 'TRON' WITH ASCEND
1400 */
1401
1402 static const SlvFunctionsT tron_internals = {
1403 10
1404 ,"TRON"
1405 ,tron_create
1406 ,tron_destroy
1407 ,tron_eligible_solver
1408 ,tron_get_default_parameters
1409 ,tron_get_parameters
1410 ,tron_set_parameters
1411 ,tron_get_status
1412 ,tron_solve
1413 ,tron_presolve
1414 ,tron_iterate
1415 ,NULL
1416 ,NULL
1417 ,NULL
1418 ,NULL
1419 };
1420
1421 int tron_register(void){
1422 #ifndef ASC_LINKED_TRON
1423 if(tron_dlopen()){
1424 ERROR_REPORTER_HERE(ASC_PROG_ERR,"Failed to load TRON");
1425 return 1;
1426 }
1427 #endif
1428 return solver_register(&tron_internals);
1429 }

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