1 /******************************************************************************
3 KPP - The Kinetic PreProcessor
4 Builds simulation code for chemical kinetic systems
6 Copyright (C) 1995-1996 Valeriu Damian and Adrian Sandu
7 Copyright (C) 1997-2005 Adrian Sandu
9 KPP is free software; you can redistribute it and/or modify it under the
10 terms of the GNU General Public License as published by the Free Software
11 Foundation (http://www.gnu.org/copyleft/gpl.html); either version 2 of the
12 License, or (at your option) any later version.
14 KPP is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
19 You should have received a copy of the GNU General Public License along
20 with this program; if not, consult http://www.gnu.org/copyleft/gpl.html or
21 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.
25 Computer Science Department
26 Virginia Polytechnic Institute and State University
28 E-mail: sandu@cs.vt.edu
30 ******************************************************************************/
39 char *rootFileName
= "ff";
40 char Home
[ MAX_PATH
] = "";
42 short int linStru
[ MAX_SPECIES
];
43 short int colStru
[ MAX_SPECIES
];
44 short int bestStru
[ MAX_SPECIES
];
47 enum stru_criteria
{ UNSORT
, LINSORT
, COLSORT
, BESTSORT
};
49 void EqCopy( EQ_VECT e1
, EQ_VECT e2
)
53 for( i
= 0; i
< EqnNr
; i
++ ) e2
[i
] = e1
[i
];
56 int NoSort( const void *p1
, const void *p2
)
61 int CodeCmp( const void *p1
, const void *p2
)
68 if ( *c1
< *c2
) return -1;
69 if ( *c1
> *c2
) return 1;
73 int CodeRCmp( const void *p1
, const void *p2
)
81 rc1
= Reactive
[ ReverseCode
[ *c1
] ];
82 rc2
= Reactive
[ ReverseCode
[ *c2
] ];
83 if ( rc1
> rc2
) return -1;
84 if ( rc1
< rc2
) return 1;
85 if ( *c1
< *c2
) return -1;
86 if ( *c1
> *c2
) return 1;
90 int CodeSSCmp( const void *p1
, const void *p2
)
92 return -CodeRCmp(p1
,p2
);
95 int CodeSCmp( const void *p1
, const void *p2
)
103 sc1
= Stru
[ ReverseCode
[ *c1
] ];
104 sc2
= Stru
[ ReverseCode
[ *c2
] ];
106 if ( sc1
> sc2
) return 1;
107 if ( sc1
< sc2
) return -1;
108 if ( *c1
< *c2
) return 1;
109 if ( *c1
> *c2
) return -1;
117 for ( i
=0; i
<VarNr
; i
++ )
118 for ( j
=0; j
<VarNr
; j
++ )
119 structJ
[i
][j
]=(i
==j
)?1:0;
121 for (i
= 0; i
< VarNr
; i
++)
122 for (j
= 0; j
< VarNr
; j
++)
123 for (k
= 0; k
< EqnNr
; k
++)
124 if ( Stoich
[i
][k
]*((Stoich_Left
[j
][k
])?1:0) != 0.0 )
127 for ( i
=0; i
<VarNr
; i
++ )
128 for ( j
=0; j
<VarNr
; j
++ )
129 LUstructJ
[i
][j
]=structJ
[i
][j
];
133 int ComputeLUStructJ()
138 for (j
= 0; j
< VarNr
-1; j
++) {
139 for (i
= j
+1; i
< VarNr
; i
++) {
140 if( LUstructJ
[i
][j
] ) {
141 for (k
= j
; k
< VarNr
; k
++)
142 /* LUstructJ[i][k] += LUstructJ[j][k]; */
143 if ( LUstructJ
[j
][k
] != 0 )
151 for (i
= 0; i
< VarNr
; i
++)
152 for (j
= 0; j
< VarNr
; j
++)
153 if( LUstructJ
[i
][j
] ) {
169 if( Stru
!= bestStru
) {
170 for( i
=0; i
<VarNr
; i
++ )
172 qsort( (void*)var
, VarNr
, sizeof(CODE
), CodeSCmp
);
177 for (i
= 0; i
< VarNr
; i
++)
178 for (j
= 0; j
< VarNr
; j
++)
179 LUstructJ
[i
][j
] = structJ
[ ReverseCode
[var
[i
]] ][ ReverseCode
[var
[j
]] ];
181 return ComputeLUStructJ();
184 void LinColSparsity()
190 for ( i
=0; i
<VarNr
; i
++ )
191 for ( j
=0; j
<VarNr
; j
++ )
192 structJ
[i
][j
]=(i
==j
)?1:0;
194 for (i
= 0; i
< VarNr
; i
++)
195 for (j
= 0; j
< VarNr
; j
++)
196 for (k
= 0; k
< EqnNr
; k
++)
197 if ( Stoich
[i
][k
]*((Stoich_Left
[j
][k
])?1:0) != 0.0 )
200 for ( i
=0; i
<VarNr
; i
++ ) {
202 for (j
= 0; j
< VarNr
; j
++)
203 linStru
[i
] += structJ
[i
][j
];
206 for ( i
=0; i
<VarNr
; i
++ ) {
208 for (j
= 0; j
< VarNr
; j
++)
209 colStru
[i
] += structJ
[j
][i
];
210 colStru
[i
] *= linStru
[i
];
234 for ( i
=0; i
<VarNr
; i
++ )
235 bestStru
[i
] = Code
[i
];
237 for ( s
=0; s
<VarNr
-1; s
++ ) {
238 best
= MAX_SPECIES
*MAX_SPECIES
; best_i
= 0;
239 for ( i
=s
; i
<VarNr
; i
++ ) {
241 for (j
= s
; j
< VarNr
; j
++) {
242 cnz
+= (LUstructJ
[i
][j
]?1:0);
243 lnz
+= (LUstructJ
[j
][i
]?1:0);
245 crt
= (cnz
-1)*(lnz
-1);
251 for ( i
=0; i
<VarNr
; i
++ ) {
252 tmp
= LUstructJ
[s
][i
];
253 LUstructJ
[s
][i
] = LUstructJ
[best_i
][i
];
254 LUstructJ
[best_i
][i
] = tmp
;
256 for ( i
=0; i
<VarNr
; i
++ ) {
257 tmp
= LUstructJ
[i
][s
];
258 LUstructJ
[i
][s
] = LUstructJ
[i
][best_i
];
259 LUstructJ
[i
][best_i
] = tmp
;
262 bestStru
[s
] = bestStru
[best_i
];
263 bestStru
[best_i
] = tmp
;
265 for (i
= s
+1; i
< VarNr
; i
++) {
266 if( LUstructJ
[i
][s
] ) {
267 for (k
= s
; k
< VarNr
; k
++)
268 LUstructJ
[i
][k
] += LUstructJ
[s
][k
];
276 void ReorderSpecies( int criteria
)
281 EQ_VECT
*tmpStoich_Left
;
282 EQ_VECT
*tmpStoich_Right
;
288 int (*cmpVar
)(const void *, const void *);
289 int (*cmpFix
)(const void *, const void *);
296 case UNSORT
: cmpVar
= useJacobian
? CodeRCmp
: CodeCmp
;
298 case LINSORT
: cmpVar
= useJacobian
? CodeSCmp
: CodeCmp
;
301 case COLSORT
: cmpVar
= useJacobian
? CodeSCmp
: CodeCmp
;
304 case BESTSORT
: cmpVar
= useJacobian
? NoSort
: CodeCmp
;
313 var
= (CODE
*)malloc( SpcNr
* sizeof(CODE
) );
314 fix
= (CODE
*)malloc( SpcNr
* sizeof(CODE
) );
315 dummy
= (CODE
*)malloc( 5 * sizeof(CODE
) );
316 tmpStoich_Left
= (EQ_VECT
*)malloc( SpcNr
* sizeof(EQ_VECT
) );
317 tmpStoich_Right
= (EQ_VECT
*)malloc( SpcNr
* sizeof(EQ_VECT
) );
318 tmpStoich
= (EQ_VECT
*)malloc( SpcNr
* sizeof(EQ_VECT
) );
319 tmpCode
= (CODE
*)malloc( SpcNr
* sizeof(CODE
) );
320 tmpReact
= (CODE
*)malloc( SpcNr
* sizeof(CODE
) );
322 for( i
= 0; i
< SpcNr
; i
++ ) {
323 switch( SpeciesTable
[ Code
[i
] ].type
) {
324 case VAR_SPC
: var
[ VarNr
++ ] = Code
[ i
];
326 case FIX_SPC
: fix
[ FixNr
++ ] = Code
[ i
];
328 case DUMMY_SPC
:dummy
[ dummyNr
++ ] = Code
[ i
];
333 if( Stru
!= bestStru
) {
334 qsort( (void*)var
, VarNr
, sizeof(CODE
), cmpVar
);
336 for( i
= 0; i
< SpcNr
; i
++ )
337 var
[i
] = bestStru
[i
];
339 qsort( (void*)fix
, FixNr
, sizeof(CODE
), cmpFix
);
341 for( i
= 0; i
< SpcNr
; i
++ ) {
342 EqCopy( Stoich_Left
[i
], tmpStoich_Left
[i
] );
343 EqCopy( Stoich_Right
[i
], tmpStoich_Right
[i
] );
344 EqCopy( Stoich
[i
], tmpStoich
[i
] );
345 tmpCode
[i
] = Code
[i
];
346 tmpReact
[i
] = Reactive
[i
];
353 for( i
= 0; i
< VarNr
; i
++ ) {
354 new = ReverseCode
[ var
[i
] ];
355 EqCopy( tmpStoich_Left
[ new ], Stoich_Left
[ k
] );
356 EqCopy( tmpStoich_Right
[ new ], Stoich_Right
[ k
] );
357 EqCopy( tmpStoich
[ new ], Stoich
[ k
] );
358 Code
[ k
] = tmpCode
[ new ];
359 Reactive
[ k
] = tmpReact
[ new ];
360 if( Reactive
[ k
] ) VarActiveNr
++;
363 for( i
= 0; i
< FixNr
; i
++ ) {
364 new = ReverseCode
[ fix
[i
] ];
365 EqCopy( tmpStoich_Left
[ new ], Stoich_Left
[ k
] );
366 EqCopy( tmpStoich_Right
[ new ], Stoich_Right
[ k
] );
367 EqCopy( tmpStoich
[ new ], Stoich
[ k
] );
368 Code
[ k
] = tmpCode
[ new ];
369 Reactive
[ k
] = tmpReact
[ new ];
372 for( i
= 0; i
< dummyNr
; i
++ ) {
373 new = ReverseCode
[ dummy
[i
] ];
374 EqCopy( tmpStoich_Left
[ new ], Stoich_Left
[ k
] );
375 EqCopy( tmpStoich_Right
[ new ], Stoich_Right
[ k
] );
376 EqCopy( tmpStoich
[ new ], Stoich
[ k
] );
377 Code
[ k
] = tmpCode
[ new ];
378 Reactive
[ k
] = tmpReact
[ new ];
383 for( i
= 0; i
< SpcNr
+dummyNr
; i
++ )
384 ReverseCode
[ Code
[i
] ] = i
;
389 free( tmpStoich_Right
);
390 free( tmpStoich_Left
);
398 /* Allocate Internal Arrays */
399 void AllocInternalArrays( void )
403 if ( (Stoich_Left
=(float**)calloc(MAX_SPECIES
,sizeof(float*)))==NULL
)
404 FatalError(-30,"Cannot allocate Stoich_Left.\n");
406 for (i
=0; i
<MAX_SPECIES
; i
++)
407 if ( (Stoich_Left
[i
] = (float*)calloc(MAX_EQN
,sizeof(float)))==NULL
) {
408 FatalError(-30,"Cannot allocate Stoich_Left[%d]",i
);
411 if ( (Stoich_Right
= (float**)calloc(MAX_SPECIES
,sizeof(float*)))==NULL
)
412 FatalError(-30,"Cannot allocate Stoich_Right.\n");
414 for (i
=0; i
<MAX_SPECIES
; i
++)
415 if ( (Stoich_Right
[i
] = (float*)calloc(MAX_EQN
,sizeof(float)))==NULL
) {
416 FatalError(-30,"Cannot allocate Stoich_Right[%d].",i
);
419 if ( (Stoich
= (float**)calloc(MAX_SPECIES
,sizeof(float*)))==NULL
)
420 FatalError(-30,"Cannot allocate Stoich.\n");
422 for (i
=0; i
<MAX_SPECIES
; i
++)
423 if ( (Stoich
[i
] = (float*)calloc(MAX_EQN
,sizeof(float)))==NULL
) {
424 FatalError(-30,"Cannot allocate Stoich[%d].",i
);
430 /* Allocate Structure Arrays */
431 void AllocStructArrays( void )
436 if ( (structB
= (int**)calloc(EqnNr
,sizeof(int*)))==NULL
)
437 FatalError(-30, "Cannot allocate structB.");
439 for (i
=0; i
<EqnNr
; i
++)
440 if ( (structB
[i
] =(int*) calloc(SpcNr
,sizeof(int)))==NULL
)
441 FatalError(-30, "Cannot allocate structB[%d].\n",i
);
443 if ( (structJ
= (int**)calloc(SpcNr
,sizeof(int*)))==NULL
)
444 FatalError(-30, "Cannot allocate structJ.");
446 for (i
=0; i
<SpcNr
; i
++)
447 if ( (structJ
[i
] =(int*) calloc(SpcNr
,sizeof(int)))==NULL
)
448 FatalError(-30, "Cannot allocate structJ[%d].\n",i
);
450 if ( (LUstructJ
= (int**)calloc(SpcNr
,sizeof(int*)))==NULL
)
451 FatalError(-30, "Cannot allocate LUstructJ.");
453 for (i
=0; i
<SpcNr
; i
++)
454 if ( (LUstructJ
[i
] = (int*)calloc(SpcNr
,sizeof(int)))==NULL
)
455 FatalError(-30, "Cannot allocate LUstructJ[%d].\n",i
);
459 /*******************************************************************/
460 int Postprocess( char * root
)
465 static char tmpfile
[] = "kppfile.tmp";
468 if ( useLang
== MATLAB_LANG
) {
469 /* Add rate function definitions as internal functions to the Update_RCONST file*/
470 sprintf( buf
, "cat %s_Update_RCONST.m %s_Rates.m > tmp; mv tmp %s_Update_RCONST.m;",
475 /* Postprocessing to replace parameter names by values in the declarations
476 strcpy( cmd, "sed " );
477 sprintf( cmd, "%s -e 's/(NVAR)/(%d)/g'", cmd, VarNr );
478 sprintf( cmd, "%s -e 's/(NFIX)/(%d)/g'", cmd, FixNr );
479 sprintf( cmd, "%s -e 's/(NSPEC)/(%d)/g'", cmd,SpcNr );
480 sprintf( cmd, "%s -e 's/(NREACT)/(%d)/g'", cmd, EqnNr );
481 sprintf( cmd, "%s -e 's/(NONZERO)/(%d)/g'", cmd, Jac_NZ );
482 sprintf( cmd, "%s -e 's/(LU_NONZERO)/(%d)/g'", cmd, LU_Jac_NZ );
483 sprintf( cmd, "%s -e 's/(NHESS)/(%)/g'", cmd, Hess_NZ );
485 sprintf( buf, "%s_Function", rootFileName );
487 case F77_LANG: sprintf( buf, "%s.f", buf );
489 case F90_LANG: sprintf( buf, "%s.f90", buf );
491 case C_LANG: sprintf( buf, "%s.c", buf );
493 case MATLAB_LANG: sprintf( buf, "%s.m", buf );
495 default: printf("\n Language '%d' not implemented!\n",useLang);
498 sprintf( cmdexe, "%s %s > %s; mv %s %s;", cmd, buf, tmpfile, tmpfile, buf );
499 printf("\n\nCMDEXE='%s'\n",cmdexe);
504 /*******************************************************************/
505 int main( int argc
, char * argv
[] )
512 AllocInternalArrays();
514 p
= getenv("KPP_HOME");
515 if( p
) strcpy( Home
, p
);
518 case 3: eqFileName
= argv
[1];
519 rootFileName
= argv
[2];
521 case 2: eqFileName
= argv
[1];
522 strcpy( name
, eqFileName
);
523 p
= name
+ strlen(name
);
533 default: FatalError(1,"\nUsage :"
534 "\n kpp <equations file> [output file]\n");
537 printf("\nThis is KPP-%s.\n", KPP_VERSION
);
539 printf("\nKPP is parsing the equation file.");
540 status
= ParseEquationFile( argv
[1] );
542 if( status
) FatalError(2,"%d errors and %d warnings encountered.",
544 /* Allocate some internal data structures */
547 printf("\nKPP is computing Jacobian sparsity structure.");
548 ReorderSpecies( UNSORT
);
551 ReorderSpecies( BESTSORT
);
556 if( initNr
== -1 ) initNr
= VarNr
;
559 printf("\nKPP is starting the code generation.");
560 Generate( rootFileName
);
562 printf("\nKPP is starting the code post-processing.");
563 Postprocess( rootFileName
);
565 printf("\n\nKPP has succesfully created the model \"%s\".\n\n",rootFileName
);
567 if( nError
) exit(4);
568 if( nWarning
) exit(5);