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 ******************************************************************************/
58 ATOM_DEF AtomTable
[ MAX_ATNR
];
59 SPECIES_DEF SpeciesTable
[ MAX_SPECIES
];
60 CODE ReverseCode
[ MAX_SPECIES
];
61 CODE Code
[ MAX_SPECIES
];
67 int Reactive
[ MAX_SPECIES
];
69 INLINE_KEY InlineKeys
[] = { { F77_GLOBAL
, APPEND
, "F77_GLOBAL" },
70 { F77_INIT
, APPEND
, "F77_INIT" },
71 { F77_DATA
, APPEND
, "F77_DATA" },
72 { F77_UTIL
, APPEND
, "F77_UTIL" },
73 { F77_RATES
, APPEND
, "F77_RATES" },
74 { F77_RCONST
, APPEND
, "F77_RCONST" },
75 { F90_GLOBAL
, APPEND
, "F90_GLOBAL" },
76 { F90_INIT
, APPEND
, "F90_INIT" },
77 { F90_DATA
, APPEND
, "F90_DATA" },
78 { F90_UTIL
, APPEND
, "F90_UTIL" },
79 { F90_RATES
, APPEND
, "F90_RATES" },
80 { F90_RCONST
, APPEND
, "F90_RCONST" },
81 { C_GLOBAL
, APPEND
, "C_GLOBAL" },
82 { C_INIT
, APPEND
, "C_INIT" },
83 { C_DATA
, APPEND
, "C_DATA" },
84 { C_UTIL
, APPEND
, "C_UTIL" },
85 { C_RATES
, APPEND
, "C_RATES" },
86 { C_RCONST
, APPEND
, "C_RCONST" },
87 { MATLAB_GLOBAL
, APPEND
, "MATLAB_GLOBAL" },
88 { MATLAB_INIT
, APPEND
, "MATLAB_INIT" },
89 { MATLAB_DATA
, APPEND
, "MATLAB_DATA" },
90 { MATLAB_UTIL
, APPEND
, "MATLAB_UTIL" },
91 { MATLAB_RATES
, APPEND
, "MATLAB_RATES" },
92 { MATLAB_RCONST
, APPEND
, "MATLAB_RCONST" }
96 int useJacobian
= JAC_LU_ROW
;
103 int useDummyindex
= 0;
105 int useLang
= F77_LANG
;
106 int useStochastic
= 0;
107 int useWRFConform
= 0;
110 char integrator
[ MAX_PATH
] = "none";
111 char driver
[ MAX_PATH
] = "none";
112 char runArgs
[ MAX_PATH
] = "";
114 /* mz_rs_20050701+ */
115 /* char varDefault[ MAX_IVAL ] = "1.E-8"; */
116 /* char fixDefault[ MAX_IVAL ] = "1.E-8"; */
117 /* double cfactor = 1.09E+10; */
118 char varDefault
[ MAX_IVAL
] = "0.";
119 char fixDefault
[ MAX_IVAL
] = "0.";
121 /* mz_rs_20050701- */
123 ATOM crtAtoms
[ MAX_ATOMS
];
126 char *fileList
[ MAX_FILES
];
129 double Abs( double x
)
131 return x
> 0 ? x
: -x
;
134 void DefineInitializeNbr( char *cmd
)
138 n
= sscanf( cmd
, "%d", &initNr
);
140 ScanError("Bad number of species to initialize <%s>", cmd
);
143 void DefineXGrid( char *cmd
)
148 n
= sscanf( cmd
, "%d", &xNr
);
150 ScanError("Bad X grid number <%s>", cmd
);
153 void DefineYGrid( char *cmd
)
158 n
= sscanf( cmd
, "%d", &yNr
);
160 ScanError("Bad Y grid number <%s>", cmd
);
163 void DefineZGrid( char *cmd
)
168 n
= sscanf( cmd
, "%d", &zNr
);
170 ScanError("Bad Z grid number <%s>", cmd
);
173 void CmdFunction( char *cmd
)
175 if( EqNoCase( cmd
, "AGGREGATE" ) ) {
179 if( EqNoCase( cmd
, "SPLIT" ) ) {
183 ScanError("'%s': Unknown parameter for #FUNCTION [AGGREGATE|SPLIT]", cmd
);
186 void CmdJacobian( char *cmd
)
188 if( EqNoCase( cmd
, "OFF" ) ) {
189 useJacobian
= JAC_OFF
;
193 if( EqNoCase( cmd
, "FULL" ) ) {
194 useJacobian
= JAC_FULL
;
198 if( EqNoCase( cmd
, "SPARSE_LU_ROW" ) ) {
199 useJacobian
= JAC_LU_ROW
;
203 if( EqNoCase( cmd
, "SPARSE_ROW" ) ) {
204 useJacobian
= JAC_ROW
;
208 ScanError("'%s': Unknown parameter for #JACOBIAN [OFF|FULL|SPARSE_LU_ROW|SPARSE_ROW]", cmd
);
211 void SparseData( char *cmd
) {
212 ScanError("Deprecated use of #SPARSEDATA %s: see #JACOBIAN for equivalent functionality", cmd
);
215 void CmdHessian( char *cmd
)
217 if( EqNoCase( cmd
, "OFF" ) ) {
221 if( EqNoCase( cmd
, "ON" ) ) {
225 ScanError("'%s': Unknown parameter for #HESSIAN [ON|OFF]", cmd
);
228 void CmdStoicmat( char *cmd
)
230 if( EqNoCase( cmd
, "OFF" ) ) {
234 if( EqNoCase( cmd
, "ON" ) ) {
238 ScanError("'%s': Unknown parameter for #STOICMAT [ON|OFF]", cmd
);
241 void CmdDouble( char *cmd
)
243 if( EqNoCase( cmd
, "OFF" ) ) {
247 if( EqNoCase( cmd
, "ON" ) ) {
251 ScanError("'%s': Unknown parameter for #DOUBLE [ON|OFF]", cmd
);
254 void CmdReorder( char *cmd
)
256 if( EqNoCase( cmd
, "OFF" ) ) {
260 if( EqNoCase( cmd
, "ON" ) ) {
264 ScanError("'%s': Unknown parameter for #REORDER [ON|OFF]", cmd
);
267 void CmdMex( char *cmd
)
269 if( EqNoCase( cmd
, "OFF" ) ) {
273 if( EqNoCase( cmd
, "ON" ) ) {
277 ScanError("'%s': Unknown parameter for #MEX [ON|OFF]", cmd
);
280 void CmdDummyindex( char *cmd
)
282 if( EqNoCase( cmd
, "OFF" ) ) {
286 if( EqNoCase( cmd
, "ON" ) ) {
290 ScanError("'%s': Unknown parameter for #DUMMYINDEX [ON|OFF]", cmd
);
293 void CmdEqntags( char *cmd
)
295 if( EqNoCase( cmd
, "OFF" ) ) {
299 if( EqNoCase( cmd
, "ON" ) ) {
303 ScanError("'%s': Unknown parameter for #EQNTAGS [ON|OFF]", cmd
);
306 void CmdUse( char *cmd
)
308 ScanError("Deprecated command '#USE %s';\nReplace with '#LANGUAGE %s'.",cmd
,cmd
);
312 void CmdLanguage( char *cmd
)
314 if( EqNoCase( cmd
, "FORTRAN77" ) ) {
318 if( EqNoCase( cmd
, "FORTRAN" ) ) {
319 ScanWarning("Fortran version not specified in '#LANGUAGE %s'. Will use Fortran 77.", cmd
);
323 if( EqNoCase( cmd
, "FORTRAN90" ) ) {
327 if( EqNoCase( cmd
, "MATLAB" ) ) {
328 useLang
= MATLAB_LANG
;
331 if( EqNoCase( cmd
, "C" ) ) {
335 ScanError("'%s': Unknown parameter for #LANGUAGE [Fortran77|Fortran90|C|Matlab]", cmd
);
338 void CmdStochastic( char *cmd
)
340 if( EqNoCase( cmd
, "ON" ) ) {
344 if( EqNoCase( cmd
, "OFF" ) ) {
348 ScanError("'%s': Unknown parameter for #STOCHASTIC [OFF|ON]", cmd
);
351 void CmdIntegrator( char *cmd
)
353 strcpy( integrator
, cmd
);
356 void CmdDriver( char *cmd
)
358 strcpy( driver
, cmd
);
361 void CmdRun( char *cmd
)
363 strcpy( runArgs
, cmd
);
366 int FindAtom( char *atname
)
370 for( i
=0; i
<AtomNr
; i
++ )
371 if( EqNoCase( AtomTable
[ i
].name
, atname
) ) {
377 void DeclareAtom( char *atname
)
381 code
= FindAtom( atname
);
383 ScanError("Multiple declaration for atom %s.", atname
);
386 if( AtomNr
>= MAX_ATNR
) {
387 Error("Too many atoms");
391 strcpy( AtomTable
[ AtomNr
].name
, atname
);
392 AtomTable
[ AtomNr
].check
= NO_CHECK
;
393 AtomTable
[ AtomNr
].masscheck
= 0;
397 void SetAtomType( char *atname
, int type
)
401 code
= FindAtom( atname
);
403 ScanError("Undefined atom %s.", atname
);
406 AtomTable
[ code
].check
= type
;
413 for( i
=0; i
<AtomNr
; i
++ ) {
414 if( AtomTable
[ i
].check
!= CANCEL_CHECK
)
415 AtomTable
[ i
].check
= DO_CHECK
;
417 SetAtomType( "IGNORE", NO_CHECK
);
420 void AddAtom( char *atname
, char *nr
)
424 code
= FindAtom( atname
);
426 ScanError("Undefined atom %s.", atname
);
429 crtAtoms
[ crtAtomNr
].code
= (unsigned char)code
;
430 crtAtoms
[ crtAtomNr
].nr
= (unsigned char)atoi(nr
);
434 int FindSpecies( char *spname
)
438 for( i
=0; i
<SpeciesNr
; i
++ )
439 if( EqNoCase( SpeciesTable
[ i
].name
, spname
) ) {
443 if( EqNoCase( SpeciesTable
[ MAX_SPECIES
-1 - i
].name
, spname
) ) {
444 return MAX_SPECIES
-1 - i
;
449 void StoreSpecies( int index
, int type
, char *spname
)
453 strcpy( SpeciesTable
[ index
].name
, spname
);
454 SpeciesTable
[ index
].type
= type
;
455 *SpeciesTable
[ index
].ival
= '\0';
456 SpeciesTable
[ index
].lookat
= 0;
457 SpeciesTable
[ index
].moni
= 0;
458 SpeciesTable
[ index
].trans
= 0;
459 if( (SpeciesTable
[ index
].nratoms
== 0) || ( crtAtomNr
> 0 ) ) {
460 SpeciesTable
[ index
].nratoms
= crtAtomNr
;
461 for( i
= 0; i
< crtAtomNr
; i
++ )
462 SpeciesTable
[ index
].atoms
[i
] = crtAtoms
[i
];
467 void DeclareSpecies( int type
, char *spname
)
471 code
= FindSpecies( spname
);
473 ScanError("Multiple declaration for species %s.", spname
);
476 if( SpeciesNr
>= MAX_SPECIES
) {
477 Error("Too many species");
480 StoreSpecies( SpeciesNr
, type
, spname
);
484 void SetSpcType( int type
, char *spname
)
489 if( EqNoCase( spname
, "VAR_SPEC" ) ) {
490 for( i
= 0; i
< SpeciesNr
; i
++ )
491 if( SpeciesTable
[i
].type
== VAR_SPC
)
492 SpeciesTable
[i
].type
= type
;
495 if( EqNoCase( spname
, "FIX_SPEC" ) ) {
496 for( i
= 0; i
< SpeciesNr
; i
++ )
497 if( SpeciesTable
[i
].type
== FIX_SPC
)
498 SpeciesTable
[i
].type
= type
;
501 if( EqNoCase( spname
, "ALL_SPEC" ) ) {
502 for( i
= 0; i
< SpeciesNr
; i
++ )
503 SpeciesTable
[i
].type
= type
;
507 code
= FindSpecies( spname
);
509 ScanError("Undefined species %s.", spname
);
512 SpeciesTable
[ code
].type
= type
;
515 void AssignInitialValue( char *spname
, char *spval
)
520 if( EqNoCase( spname
, "CFACTOR" ) ) {
521 code
= sscanf( spval
, "%lg", &cf
);
523 ScanWarning("Invalid CFACTOR value: %s", spval
);
530 if( EqNoCase( spname
, "VAR_SPEC" ) ) {
531 strcpy( varDefault
, spval
);
536 if( EqNoCase( spname
, "FIX_SPEC" ) ) {
537 strcpy( fixDefault
, spval
);
541 if( EqNoCase( spname
, "ALL_SPEC" ) ) {
542 strcpy( varDefault
, spval
);
543 strcpy( fixDefault
, spval
);
547 code
= FindSpecies( spname
);
549 ScanError("Undefined species %s.", spname
);
552 strcpy( SpeciesTable
[ code
].ival
, spval
);
555 void StoreEquationRate( char *rate
, char *label
)
562 kreact
= &kr
[ EqnNr
];
563 strcpy( kreact
->label
, label
);
565 kreact
->type
= PHOTO
;
566 strcpy( kreact
->val
.st
, rate
);
570 n
= sscanf( rate
, "%lf%s", &f
, buf
);
572 kreact
->type
= NUMBER
;
576 kreact
->type
= EXPRESION
;
577 strcpy( kreact
->val
.st
, rate
);
586 float atcnt
[ MAX_ATNR
];
592 if( EqnNr
>= MAX_EQN
) {
593 Error("Too many equations");
597 for( i
= 0; i
< AtomNr
; i
++ )
600 for( spc
= 0; spc
< SpcNr
; spc
++ ) {
601 sp
= &SpeciesTable
[ Code
[spc
] ];
602 if( Stoich_Left
[spc
][EqnNr
] != 0 ) {
603 for( i
= 0; i
< sp
->nratoms
; i
++ )
604 atcnt
[ sp
->atoms
[i
].code
] += Stoich_Left
[spc
][EqnNr
] * sp
->atoms
[i
].nr
;
606 if( Stoich_Right
[spc
][EqnNr
] != 0 ) {
607 for( i
= 0; i
< sp
->nratoms
; i
++ )
608 atcnt
[ sp
->atoms
[i
].code
] -= Stoich_Right
[spc
][EqnNr
] * sp
->atoms
[i
].nr
;
615 for( i
= 0; i
< AtomNr
; i
++ ) {
616 if ( Abs( atcnt
[i
] ) > 1e-5 ) {
617 if ( AtomTable
[i
].check
== CANCEL_CHECK
) {
621 if ( AtomTable
[i
].check
== NO_CHECK
) {
624 if ( AtomTable
[i
].check
== DO_CHECK
) {
626 sprintf(errmsg
, "%s %s", errmsg
, AtomTable
[i
].name
);
633 ScanWarning( "(eqn %d) Atom balance mismatch for:%s.", EqnNr
+1, errmsg
);
635 for( j
= 0; j
< SpcNr
; j
++ )
636 if( Stoich_Left
[j
][EqnNr
] != 0 )
637 { index
= j
; break; }
638 for( i
= 0; i
< EqnNr
; i
++ ) {
640 r1
= Stoich_Left
[index
][EqnNr
];
641 r2
= Stoich_Left
[index
][i
];
642 for( j
= 0; j
< SpcNr
; j
++ ) {
643 if( r1
* Stoich_Left
[j
][i
] != r2
* Stoich_Left
[j
][EqnNr
] )
644 { equal
= 0; break; }
645 if( r1
* Stoich_Right
[j
][i
] != r2
* Stoich_Right
[j
][EqnNr
] )
646 { equal
= 0; break; }
650 ScanError( "Duplicate equation: "
651 " (eqn<%d> = eqn<%d> )", i
+1, EqnNr
+1 );
653 ScanError( "Linearly dependent equations: "
654 "( %.0f eqn<%d> = %.0f eqn<%d> )",
655 r1
, i
+1, r2
, EqnNr
+1 );
662 void ProcessTerm( int side
, char *sign
, char *coef
, char *spname
)
670 code
= FindSpecies( spname
);
672 ScanError("Undefined species %s.", spname
);
676 crtSpec
= ReverseCode
[ code
];
678 if(EqNoCase(spname
,"HV")) isPhoto
= 1;
680 if ( crtSpec
== NO_CODE
) {
681 if( MAX_SPECIES
- code
<= 2 ) falseSpcNr
++;
683 Code
[ crtSpec
] = code
;
684 ReverseCode
[ code
] = crtSpec
;
689 sscanf( buf
, "%lf", &val
);
692 case LHS
: Stoich_Left
[ crtSpec
][ EqnNr
] += val
;
693 Stoich
[ crtSpec
][ EqnNr
] -= val
;
694 Reactive
[ crtSpec
] = 1;
696 case RHS
: Stoich_Right
[ crtSpec
][ EqnNr
] += val
;
697 Stoich
[ crtSpec
][ EqnNr
] += val
;
702 void AddLumpSpecies( char *spname
)
706 code
= FindSpecies( spname
);
708 ScanError("Undefined species %s.", spname
);
716 void CheckLump( char *spname
)
720 code
= FindSpecies( spname
);
722 ScanError("Undefined species %s.", spname
);
730 void AddLookAt( char *spname
)
734 code
= FindSpecies( spname
);
736 ScanError("Undefined species %s.", spname
);
740 SpeciesTable
[ code
].lookat
= 1;
747 for( i
=0; i
<SpeciesNr
; i
++ )
748 SpeciesTable
[ i
].lookat
= 1;
751 void AddMonitor( char *spname
)
755 code
= FindSpecies( spname
);
757 SpeciesTable
[ code
].moni
= 1;
761 code
= FindAtom( spname
);
763 AtomTable
[ code
].masscheck
= 1;
767 ScanError("Undefined species or atom %s.", spname
);
770 void AddTransport( char *spname
)
774 code
= FindSpecies( spname
);
776 ScanError("Undefined species %s.", spname
);
780 SpeciesTable
[ code
].trans
= 1;
787 for( i
=0; i
<SpeciesNr
; i
++ )
788 SpeciesTable
[ i
].trans
= 1;
791 void AddUseFile( char *fname
)
793 fileList
[fileNr
] = (char*)malloc(strlen(fname
)+1);
794 strcpy(fileList
[fileNr
], fname
);
798 char * AppendString( char * s1
, char * s2
, int * maxlen
, int addlen
)
805 s1
= (char*)malloc( *maxlen
);
809 if( strlen( s1
) + strlen( s2
) >= *maxlen
) {
810 s1
= (char*)realloc( (void*)s1
, *maxlen
);
816 char * ReplaceString( char * s1
, char * s2
, int * maxlen
, int addlen
)
822 *maxlen
= strlen( s2
);
823 s1
= (char*)malloc( 1+*maxlen
);
829 void AddInlineCode( char * ctx
, char * s
)
833 int totallength
; /* mz_rs_20050607 */
837 for( i
= 0; i
< INLINE_OPT
; i
++ )
838 if( EqNoCase( ctx
, InlineKeys
[i
].kname
) ) {
839 key
= InlineKeys
[i
].key
;
840 c
= &InlineCode
[key
];
841 type
= InlineKeys
[i
].type
;
845 printf( "\n'%s': Unknown inline option (ignored)", ctx
);
849 /* mz_rs_20050607+ */
851 totallength
= strlen( c
->code
)+strlen( s
);
853 totallength
= strlen( s
);
854 if (totallength
>MAX_INLINE
)
855 ScanError("\nInline code for %s is too long (%d>%d).\nIncrease MAX_INLINE in scan.h and recompile kpp!",
856 ctx
, totallength
, MAX_INLINE
);
857 /* mz_rs_20050607- */
860 case APPEND
: c
->code
= AppendString( c
->code
, s
, &c
->maxlen
, MAX_INLINE
);
862 case REPLACE
: c
->code
= ReplaceString( c
->code
, s
, &c
->maxlen
, MAX_INLINE
);
867 int ParseEquationFile( char * filename
)
872 for( i
= 0; i
< MAX_SPECIES
; i
++ ) {
873 ReverseCode
[i
] = NO_CODE
;
876 for( i
= 0; i
< MAX_SPECIES
; i
++ ) {
877 for( j
= 0; j
< MAX_EQN
; j
++ ) {
878 Stoich_Left
[i
][j
] = 0;
880 Stoich_Right
[i
][j
] = 0;
883 for( i
= 0; i
< MAX_SPECIES
; i
++ ) {
884 SpeciesTable
[ i
].nratoms
= 0;
887 for( i
= 0; i
< INLINE_OPT
; i
++ ) {
888 InlineCode
[i
].code
= NULL
;
889 InlineCode
[i
].maxlen
= 0;
895 DeclareAtom( "CANCEL" );
896 SetAtomType( "CANCEL", CANCEL_CHECK
);
897 DeclareAtom( "IGNORE" );
898 SetAtomType( "IGNORE", NO_CHECK
);
899 DeclareSpecies( DUMMY_SPC
, "???" );
900 StoreSpecies( MAX_SPECIES
-1, DUMMY_SPC
, "HV" );
901 AddAtom( "CANCEL", "1" );
902 StoreSpecies( MAX_SPECIES
-2, DUMMY_SPC
, "PROD" );
904 code
= Parser( filename
);
912 printf("\nKPP was told to generate WRF conform code");