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 ******************************************************************************/
40 char *F90_types
[] = { "", /* VOID */
42 "REAL(kind=sp)", /* FLOAT */
43 "REAL(kind=dp)", /* DOUBLE */
44 "CHARACTER(LEN=12)", /* STRING */
45 "CHARACTER(LEN=100)" /* DOUBLESTRING */
48 /*************************************************************************************************/
49 void F90_WriteElm( NODE
* n
)
57 name
= varTable
[ elm
->var
]->name
;
60 case CONST
: bprintf("%g", elm
->val
.cnst
);
62 case ELM
: bprintf("%s", name
);
64 case VELM
: if( elm
->val
.idx
.i
>= 0 ) sprintf( maxi
, "%d", elm
->val
.idx
.i
+1 );
65 else sprintf( maxi
, "%s", varTable
[ -elm
->val
.idx
.i
]->name
);
66 bprintf("%s(%s)", name
, maxi
);
68 case MELM
: if( elm
->val
.idx
.i
>= 0 ) sprintf( maxi
, "%d", elm
->val
.idx
.i
+1 );
69 else sprintf( maxi
, "%s", varTable
[ -elm
->val
.idx
.i
]->name
);
70 if( elm
->val
.idx
.j
>= 0 ) sprintf( maxj
, "%d", elm
->val
.idx
.j
+1 );
71 else sprintf( maxj
, "%s", varTable
[ -elm
->val
.idx
.j
]->name
);
72 bprintf("%s(%s,%s)", name
, maxi
, maxj
);
74 case EELM
: bprintf("(%s)", elm
->val
.expr
);
79 /*************************************************************************************************/
80 void F90_WriteSymbol( int op
)
83 case ADD
: bprintf("+");
86 case SUB
: bprintf("-");
89 case MUL
: bprintf("*");
92 case DIV
: bprintf("/");
95 case POW
: bprintf("power");
97 case O_PAREN
: bprintf("(");
100 case C_PAREN
: bprintf(")");
107 /*************************************************************************************************/
108 void F90_WriteAssign( char *ls
, char *rs
)
118 /* Max no of continuation lines in F90/F95 differs with compilers, but 39
119 should work for every compiler*/
120 int number_of_lines
= 1, MAX_NO_OF_LINES
= 36;
122 /* Operator Mapping: 0xaa = '*' | 0xab = '+' | 0xac = ','
123 0xad = '-' | 0xae ='.' | 0xaf = '/' */
124 char op_mult
=0xaa, op_plus
=0xab, op_minus
=0xad, op_dot
=0xae, op_div
=0xaf;
126 crtident
= 2 + ident
* 2;
127 bprintf("%*s%s = ", crtident
, "", ls
);
128 start
= strlen( ls
) + 2;
129 linelg
= 120 - crtident
- start
- 1; /* F90 max line length is 132 */
132 while( strlen(rs
) > linelg
) {
133 ifound
= 0; jfound
= 0;
134 if ( number_of_lines
>= MAX_NO_OF_LINES
) {
135 /* If a new line needs to be started.
136 Note: the approach below will create erroneous code if the +/- is within a subexpression, e.g. for
137 A*(B+C) one cannot start a new continuation line by splitting at the + sign */
138 for( j
=linelg
; j
>5; j
-- ) /* split row here if +, -, or comma */
139 if ( ( rs
[j
] == op_plus
)||( rs
[j
] == op_minus
)||( rs
[j
]==',' ) ) {
140 jfound
= 1; i
=j
; break;
143 if ( ( number_of_lines
< MAX_NO_OF_LINES
)||( !jfound
) ) {
144 for( i
=linelg
; i
>10; i
-- ) /* split row here if operator or comma */
145 if ( ( rs
[i
] & 0x80 )||( rs
[i
]==',' ) ) {
149 printf("\n Warning: double-check continuation lines for:\n %s = %s\n",ls
,rs
);
153 while ( rs
[i
-1] & 0x80 ) i
--; /* put all operators on the next row */
154 while ( rs
[i
] == ',' ) i
++; /* put commas on the current row */
159 if ( first
) { /* first line in a split row */
163 } else {/* continuation line in a split row - but not last line*/
164 bprintf("&\n %*s&%s", start
, "", rs
);
166 bprintf("\n%*s%s = %s", crtident
, "", ls
, ls
);
171 rs
+= i
; /* jump to the first not-yet-written character */
175 if ( number_of_lines
> MAX_NO_OF_LINES
) {
176 printf("\n Warning: %d continuation lines for %s = ...",number_of_lines
,ls
);
179 if ( first
) bprintf("%s\n", rs
); /* non-split row */
180 else bprintf("&\n %*s&%s\n", start
, "", rs
); /* last line in a split row */
187 /*************************************************************************************************/
188 void F90_WriteComment( char *fmt
, ... )
192 char buf
[ MAX_LINE
];
194 Va_start( args
, fmt
);
195 vsprintf( buf
, fmt
, args
);
197 /* remove trailing spaces */
198 /* taken from http://www.cs.bath.ac.uk/~pjw/NOTES/ansi_c/ch10-idioms.pdf */
199 for (n
= strlen(buf
) - 1; n
>= 0; n
--)
200 if (buf
[n
] != ' ') break;
202 bprintf( "! %s\n", buf
);
206 /*************************************************************************************************/
207 char * F90_Decl( int v
)
209 static char buf
[120];
216 baseType
= F90_types
[ var
->baseType
];
220 switch( var
->type
) {
222 sprintf( buf
, "%s :: %s", baseType
, var
->name
);
225 if( var
->maxi
> 0 ) sprintf( maxi
, "%d", var
->maxi
);
226 /* else sprintf( maxi, "%s", varTable[ -var->maxi ]->name); */
227 /*sprintf( buf, "%s, DIMENSION(%s) :: %s", baseType, maxi, var->name );*/
228 if( var
->maxi
== 0 ) sprintf( maxi
, "%d", 1 );
229 /* else sprintf( maxi, "%s", varTable[ -var->maxi ]->name); */
230 if ( var
->maxi
< 0 ) {
231 if (varTable
[ -var
->maxi
]->value
< 0)
232 sprintf( maxi
, "%s", varTable
[ -var
->maxi
]->name
);
234 sprintf( maxi
, "%d", (varTable
[-var
->maxi
]->value
)==0?
235 1:varTable
[-var
->maxi
]->value
);
237 sprintf( buf
, "%s :: %s(%s)", baseType
, var
->name
, maxi
);
240 if( var
->maxi
> 0 ) sprintf( maxi
, "%d", var
->maxi
);
242 if (varTable
[ -var
->maxi
]->value
< 0)
243 sprintf( maxi
, "%s", varTable
[ -var
->maxi
]->name
);
245 sprintf( maxi
, "%d", (varTable
[-var
->maxi
]->value
)==0?
246 1:varTable
[-var
->maxi
]->value
);
248 /* else sprintf( maxi, "%s", varTable[ -var->maxi ]->name); */
249 /* if( (var->maxi == 0) ||
250 ((var->maxi < 0) && (varTable[ -var->maxi ]->maxi == 0)) )
251 strcat( maxi, "+1"); */
252 if( var
->maxj
> 0 ) sprintf( maxj
, "%d", var
->maxj
);
254 if (varTable
[ -var
->maxj
]->value
< 0)
255 sprintf( maxj
, "%s", varTable
[ -var
->maxj
]->name
);
257 sprintf( maxj
, "%d", (varTable
[-var
->maxj
]->value
)==0?
258 1:varTable
[-var
->maxj
]->value
);
260 /* else sprintf( maxj, "%s", varTable[ -var->maxj ]->name); */
261 /*if( (var->maxj == 0) ||
262 ((var->maxj < 0 ) && (varTable[ -var->maxj ]->maxi == 0)) )
263 strcat( maxj, "+1");*/
264 /*sprintf( buf, "%s, DIMENSION(%s,%s) :: %s",
265 baseType, maxi, maxj,var->name ); */
266 sprintf( buf
, "%s :: %s(%s,%s)",
267 baseType
, var
->name
, maxi
, maxj
);
270 printf( "Can not declare type %d\n", var
->type
);
276 /*************************************************************************************************/
277 char * F90_DeclareData( int v
, void * values
, int n
)
282 static char buf
[120];
290 int maxCols
= MAX_COLS
;
302 ival
= (int*) values
;
303 dval
= (double *) values
;
304 cval
= (char **) values
;
308 var
-> maxi
= max( n
, 1 );
310 baseType
= F90_types
[ var
->baseType
];
314 switch( var
->type
) {
316 bprintf( " %s :: %s = ", baseType
, var
->name
);
317 switch ( var
->baseType
) {
318 case INT
: bprintf( "%d", *ival
); break;
319 case DOUBLE
: bprintf( "%f", *dval
); break;
320 case REAL
: bprintf( "%lg", *dval
); break;
321 case STRING
: bprintf( "'%3s'", *cval
); break;
325 /* define maxCols here already and choose suitable splitsize */
326 switch( var
-> baseType
) {
327 case INT
: maxCols
=12; break;
328 case DOUBLE
: maxCols
= 5; break;
329 case REAL
: maxCols
= 5; break;
330 case STRING
: maxCols
= 3; break;
331 case DOUBLESTRING
: maxCols
= 1; break;
333 splitsize
= 30 * maxCols
; /* elements = lines * columns */
334 maxi_mod
= var
->maxi
% splitsize
;
335 maxi_div
= var
->maxi
/ splitsize
;
336 /* correction if var->maxi is a multiple of splitsize */
337 if ( (maxi_div
>0) && (maxi_mod
==0) ) {
338 maxi_mod
= splitsize
;
341 for ( isplit
=0; isplit
<= maxi_div
; isplit
++ ) {
342 if( var
->maxi
> 0 ) sprintf( maxi
, "%d", var
->maxi
);
343 else sprintf( maxi
, "%s", varTable
[ -var
->maxi
]->name
);
344 if( (var
->maxi
== 0) ||
345 ((var
->maxi
< 0) && (varTable
[ -var
->maxi
]->maxi
== 0)) )
347 bprintf( " %s, " , baseType
);
348 if( n
>0 ) bprintf( "PARAMETER, " ); /* if values are assigned now */
349 if ( maxi_div
==0 ) { /* define array in one piece */
350 bprintf( "DIMENSION(%s) :: %s",
352 } else {/* define partial arrays */
353 if ( isplit
==maxi_div
) { /* last part has size maxi_mod */
354 bprintf( "DIMENSION(%d) :: %s_%d",
355 maxi_mod
, var
->name
, isplit
) ;
356 } else { /* all other parts have size splitsize */
357 bprintf( "DIMENSION(%d) :: %s_%d",
358 splitsize
, var
->name
, isplit
) ;
363 /* now list values */
364 bprintf( " = (/ &\n " );
365 /* if the array is defined in one piece, then the for loop will
366 go from 0 to n. Otherwise, there will be partial arrays from
367 i_from to i_to which are of size splitsize except for the
368 last one which is usually smaller and contains the rest */
369 i_from
= isplit
* splitsize
;
370 i_to
= min(i_from
+splitsize
,n
);
371 for ( i
=i_from
; i
< i_to
; i
++ ) {
372 switch( var
-> baseType
) {
374 bprintf( "%3d", ival
[i
] ); break;
376 /* bprintf( "%4f", dval[i] ); maxCols = 5; break; */
377 sprintf(mynumber
, "%12.6e_dp",dval
[i
]);
378 /* mynumber[ strlen(mynumber)-4 ] = 'd'; */
379 bprintf( " %s", mynumber
); break;
381 bprintf( "%12.6e", dval
[i
] ); break;
383 bprintf( "'%-12s'", cval
[i
] ); break;
385 /* strncpy( dsbuf, cval[i], 54 ); dsbuf[54]='\0'; */
386 /* bprintf( "'%48s'", dsbuf ); break; */
387 bprintf( "'%-100.100s'", cval
[i
] ); break;
391 if( (i
+1) % maxCols
== 0 ) {
400 /* combine the partial arrays */
401 if ( maxi_div
!= 0 ) {
402 bprintf( " %s, PARAMETER, DIMENSION(%s) :: %s = (/&\n ",
403 baseType
, maxi
, var
->name
) ;
404 for ( isplit
=0; isplit
<= maxi_div
; isplit
++ ) {
405 bprintf( "%s_%d", var
->name
, isplit
) ;
406 if( isplit
< maxi_div
) { /* more parts will follow */
408 /* line break after 5 variables */
409 if( (isplit
+1) % 5 == 0 ) bprintf( "&\n " );
410 } else { /* after last part */
418 case MELM
: if( var
->maxi
> 0 ) sprintf( maxi
, "%d", var
->maxi
);
419 else sprintf( maxi
, "%s", varTable
[ -var
->maxi
]->name
);
420 if( (var
->maxi
== 0) ||
421 ((var
->maxi
< 0) && (varTable
[ -var
->maxi
]->maxi
== 0)) )
423 if( var
->maxj
> 0 ) sprintf( maxj
, "%d", var
->maxj
);
424 else sprintf( maxj
, "%s", varTable
[ -var
->maxj
]->name
);
425 if( (var
->maxj
== 0) ||
426 ((var
->maxj
< 0 ) && (varTable
[ -var
->maxj
]->maxi
== 0)) )
428 sprintf( buf
, "%s, DIMENSION(%s,%s) :: %s\n", /* changed here */
429 baseType
, maxi
, maxj
,var
->name
);
432 printf( "Can not declare type %d", var
->type
);
438 /*************************************************************************************************/
439 void F90_Declare( int v
)
441 if( varTable
[ v
]->comment
) {
442 F90_WriteComment( "%s - %s",
443 varTable
[ v
]->name
, varTable
[ v
]->comment
);
445 bprintf(" %s\n", F90_Decl(v
) );
450 /*************************************************************************************************/
451 void F90_ExternDeclare( int v
)
454 // bprintf(" COMMON /%s/ %s\n", CommonName, varTable[ v ]->name );
457 /*************************************************************************************************/
458 void F90_GlobalDeclare( int v
)
462 /*************************************************************************************************/
463 void F90_DeclareConstant( int v
, char *val
)
467 char dummy_val
[100]; /* used just to avoid strange behaviour of
468 sscanf when compiled with gcc */
470 strcpy(dummy_val
,val
);val
= dummy_val
;
474 if( sscanf(val
, "%d", &ival
) == 1 )
475 if( ival
== 0 ) var
->maxi
= 0;
481 F90_WriteComment( "%s - %s", var
->name
, var
->comment
);
483 switch( var
->type
) {
484 case CONST
: bprintf(" %s, PARAMETER :: %s = %s \n",
485 F90_types
[ var
->baseType
], var
->name
, val
);
488 printf( "Invalid constant %d", var
->type
);
496 /*************************************************************************************************/
497 void F90_WriteVecData( VARIABLE
* var
, int min
, int max
, int split
)
503 sprintf( buf
, "%6sdata( %s(i), i = %d, %d ) / &\n%5s",
504 " ", var
->name
, min
, max
, " " );
506 sprintf( buf
, "%6sdata %s / &\n%5s",
507 " ", var
->name
, " " );
510 bprintf( " / \n\n" );
514 /*************************************************************************************************/
515 void F90_DeclareDataOld( int v
, int * values
, int n
)
518 int nlines
, min
, max
;
524 int maxCols
= MAX_COLS
;
528 ival
= (int*) values
;
529 dval
= (double*) values
;
530 cval
= (char**) values
;
536 switch( var
->type
) {
537 case VELM
: if( n
<= 0 ) break;
538 for( i
= 0; i
< n
; i
++ ) {
539 switch( var
->baseType
) {
540 case INT
: bprintf( "%3d", ival
[i
] ); maxCols
=12; break;
542 case REAL
:bprintf( "%5lg", dval
[i
] ); maxCols
=8; break;
543 case STRING
:bprintf( "'%s'", cval
[i
] ); maxCols
=5; break;
545 strncpy( dsbuf
, cval
[i
], 54 ); dsbuf
[54]='\0';
546 bprintf( "'%48s'", dsbuf
); maxCols
=1; break;
548 if( ( (i
+1) % 12 == 0 ) && ( nlines
> MAX_LINES
) ) {
549 split
= 1; nlines
= 1;
550 F90_WriteVecData( var
, min
, max
, split
);
554 if( i
< n
-1 ) bprintf( "," );
555 if( (i
+1) % maxCols
== 0 ) {
556 bprintf( "\n%5s", " " );
562 F90_WriteVecData( var
, min
, max
-1, split
);
565 case ELM
: bprintf( "%6sdata %s / ", " ", var
->name
);
566 switch( var
->baseType
) {
567 case INT
: bprintf( "%d", *ival
); break;
569 case REAL
:bprintf( "%lg", *dval
); break;
570 case STRING
:bprintf( "'%s'", *cval
); break;
572 strncpy( dsbuf
, *cval
, 54 ); dsbuf
[54]='\0';
573 bprintf( "'%s'", dsbuf
); maxCols
=1; break;
574 /* bprintf( "'%50s'", *cval ); break; */
580 printf( "\n Function not defined !\n" );
585 /*************************************************************************************************/
586 void F90_InitDeclare( int v
, int n
, void * values
)
592 var
->maxi
= max( n
, 1 );
595 F90_DeclareData( v
, values
, n
);
598 /*************************************************************************************************/
599 void F90_FunctionStart( int f
, int *vars
)
606 name
= varTable
[ f
]->name
;
607 narg
= varTable
[ f
]->maxi
;
609 bprintf("SUBROUTINE %s ( ", name
);
610 for( i
= 0; i
< narg
-1; i
++ ) {
612 bprintf("%s, ", varTable
[ v
]->name
);
616 bprintf("%s ", varTable
[ v
]->name
);
623 /*************************************************************************************************/
624 void F90_FunctionPrototipe( int f
, ... )
629 name
= varTable
[ f
]->name
;
630 narg
= varTable
[ f
]->maxi
;
632 bprintf(" EXTERNAL %s\n", name
);
637 /*************************************************************************************************/
638 void F90_FunctionBegin( int f
, ... )
648 name
= varTable
[ f
]->name
;
649 narg
= varTable
[ f
]->maxi
;
652 for( i
= 0; i
< narg
; i
++ )
653 vars
[ i
] = va_arg( args
, int );
656 CommentFncBegin( f
, vars
);
657 F90_FunctionStart( f
, vars
);
659 /* bprintf(" USE %s_Precision\n", rootFileName );
660 bprintf(" USE %s_Parameters\n\n", rootFileName ); */
661 /* bprintf(" IMPLICIT NONE\n" ); */
665 for( i
= 0; i
< narg
; i
++ )
666 F90_Declare( vars
[ i
] );
671 MapFunctionComment( f
, vars
);
674 /*************************************************************************************************/
675 void F90_FunctionEnd( int f
)
677 bprintf(" \nEND SUBROUTINE %s\n\n", varTable
[ f
]->name
);
681 CommentFunctionEnd( f
);
684 /*************************************************************************************************/
685 void F90_Inline( char *fmt
, ... )
690 if( useLang
!= F90_LANG
) return;
692 va_start( args
, fmt
);
693 vsprintf( buf
, fmt
, args
);
695 bprintf( "%s\n", buf
);
701 /*************************************************************************************************/
704 WriteElm
= F90_WriteElm
;
705 WriteSymbol
= F90_WriteSymbol
;
706 WriteAssign
= F90_WriteAssign
;
707 WriteComment
= F90_WriteComment
;
708 DeclareConstant
= F90_DeclareConstant
;
709 Declare
= F90_Declare
;
710 ExternDeclare
= F90_ExternDeclare
;
711 GlobalDeclare
= F90_GlobalDeclare
;
712 InitDeclare
= F90_InitDeclare
;
714 FunctionStart
= F90_FunctionStart
;
715 FunctionPrototipe
= F90_FunctionPrototipe
;
716 FunctionBegin
= F90_FunctionBegin
;
717 FunctionEnd
= F90_FunctionEnd
;
719 OpenFile( ¶m_headerFile
, rootFileName
, "_Parameters.f90", "Parameter Module File" );
720 /* mz_rs_20050117+ */
721 OpenFile( &initFile
, rootFileName
, "_Initialize.f90", "Initialization File" );
722 /* mz_rs_20050117- */
723 /* mz_rs_20050518+ no driver file if driver = none */
724 if( strcmp( driver
, "none" ) != 0 )
725 OpenFile( &driverFile
, rootFileName
, "_Main.f90", "Main Program File" );
726 /* mz_rs_20050518- */
727 OpenFile( &integratorFile
, rootFileName
, "_Integrator.f90",
728 "Numerical Integrator (Time-Stepping) File" );
729 OpenFile( &linalgFile
, rootFileName
, "_LinearAlgebra.f90",
730 "Linear Algebra Data and Routines File" );
731 OpenFile( &functionFile
, rootFileName
, "_Function.f90",
732 "The ODE Function of Chemical Model File" );
733 OpenFile( &jacobianFile
, rootFileName
, "_Jacobian.f90",
734 "The ODE Jacobian of Chemical Model File" );
735 OpenFile( &rateFile
, rootFileName
, "_Rates.f90",
736 "The Reaction Rates File" );
738 OpenFile( &stochasticFile
, rootFileName
, "_Stochastic.f90",
739 "The Stochastic Chemical Model File" );
741 OpenFile( &stoichiomFile
, rootFileName
, "_Stoichiom.f90",
742 "The Stoichiometric Chemical Model File" );
743 OpenFile( &sparse_stoicmFile
, rootFileName
, "_StoichiomSP.f90",
744 "Sparse Stoichiometric Data Structures File" );
746 OpenFile( &utilFile
, rootFileName
, "_Util.f90",
747 "Auxiliary Routines File" );
748 /* OpenFile( &sparse_dataFile, rootFileName, "_Sparse.f90",
749 "Sparse Data Module File" );*/
750 OpenFile( &global_dataFile
, rootFileName
, "_Global.f90", "Global Data Module File" );
751 if ( useJacSparse
) {
752 OpenFile( &sparse_jacFile
, rootFileName
, "_JacobianSP.f90",
753 "Sparse Jacobian Data Structures File" );
756 OpenFile( &hessianFile
, rootFileName
, "_Hessian.f90", "Hessian File" );
757 OpenFile( &sparse_hessFile
, rootFileName
, "_HessianSP.f90",
758 "Sparse Hessian Data Structures File" );
760 OpenFile( &mapFile
, rootFileName
, ".map",
761 "Map File with Human-Readable Information" );
762 OpenFile( &monitorFile
, rootFileName
, "_Monitor.f90",
763 "Utility Data Module File" );