KineticPreProcessor / KPP

The KPP kinetic preprocessor is a software tool that assists the computer simulation of chemical kinetic systems
GNU General Public License v3.0
21 stars 11 forks source link

Updates for C-language output #53

Closed yantosca closed 2 years ago

yantosca commented 2 years ago

This PR fixes several issues that were preventing KPP from generating C-language output code. Namely:

NOTE: At present, the C-language code fails when trying to use a mechanism other than small_strato. I think this is due to a Makefile issue that happens when e.g. Hessian is turned off but the Makefile looks for the Hessian files. I can implement a similar fix as was done for Fortran90.

RolfSander commented 2 years ago

Looks good.

Thanks for given the CI tests a nice structure!

yantosca commented 2 years ago

Still debugging a seg fault when I try to build a larger mechanism than small_strato. It seems to be in C_InitDeclare when we pass it the EQN_NAMES. Will dig into this a bit.

yantosca commented 2 years ago

gdb output says:

Program received signal SIGSEGV, Segmentation fault.
0x00002aaaaaf60f76 in __mempcpy_sse2 () from /lib64/libc.so.6
(gdb) where
#0  0x00002aaaaaf60f76 in __mempcpy_sse2 () from /lib64/libc.so.6
#1  0x00002aaaaaf4e06c in _IO_default_xsputn () from /lib64/libc.so.6
#2  0x00002aaaaaf1e033 in vfprintf () from /lib64/libc.so.6
#3  0x00002aaaaaf424cb in vsprintf () from /lib64/libc.so.6
#4  0x0000000000401b55 in bprintf (fmt=0x425ce4 "\"%s\"") at code.c:202
#5  0x0000000000404878 in C_InitDeclare (v=90, n=235, values=0x7ffffffda350)
    at code_c.c:333
#6  0x000000000040dd4d in GenerateMonitorData () at gen.c:525
#7  0x000000000041998c in Generate () at gen.c:3629
#8  0x000000000041c66e in main (argc=2, argv=0x7fffffffb938) at kpp.c:640
yantosca commented 2 years ago

@RolfSander, I think I see what is going on. In routine C_InitDeclare I put in a debug statement that only executes when the variable EQN_NAMES is passed:

  // debug
  if ( v==90 ) {
    printf("\n");
    for (i=0; i<n; i++) printf( "\n%d, %s\n", i, cval[i] );
    exit(1);
  }

which gives this output:

0,               NO2 --> O3P + NO                                                                                                                                                                                                                                                                                 O3P + AIR + O2 --> O3                                                                                                                                                                                                                                                                                             O3P + O3 --> 2 O2                                                                                                                                                                                                                                                                                     O3P + NO + AIR --> NO2                                                                                                                                                                                                                                                                                           O3P + NO2 --> NO                                                                                                                                                                                                                                                                                            O3P + NO2 --> NO3                                                                                                                                                                                                                                                                                             O3 + NO --> NO2

so for each index i, the cval[i] contains the list of equations from i to the end of the file. This is causing the seg fault as we eventually run out of memory.

This is called from GenerateMonitorData in gen.c here:

  p = bufeqn;
  for (i = 0; i < EqnNr; i++) {
    EqnString(i, p);
    seqn[i] = p;
    p += MAX_EQNLEN;
  }
  InitDeclare( EQN_NAMES, EqnNr, (void*)seqn );

If you have any ideas then let me know. Thanks!

RolfSander commented 2 years ago

I'm sorry but I don't know how to solve this problem.

Maybe the easiest quick&dirty fix is to deactive EQN_NAMES for the C language? I think that would be okay because I don't even know a single KPP user who creates output in C.

yantosca commented 2 years ago

Found a solution!

  switch( var->type ) {
    case VELM: bprintf( "  %s  %s[] = {\n%5s", C_types[var->baseType], var->name, " " );
               for( i = 0; i < n; i++ ) {
                 switch( var->baseType ) {
                   case INT:
             bprintf( "%3d",  ival[i] );
             maxCols=12;
             break;
                   case DOUBLE:
                   case REAL:
             bprintf( "%5lg", dval[i] );
             maxCols=8;
             break;
                   case STRING:
             bprintf( "\"%s\"", cval[i] );
             maxCols=8;
             break;
           case DOUBLESTRING:
             // Bug fix: To avoid a segmentation fault, copy the
             // string from cval[i] to string variable thisEqn
             // before passing it to bprintf.
             //  -- Bob Yantosca (28 Jun 2022)
             strncpy( thisEqn, cval[i], MAX_EQNLEN+1 );
             bprintf( "\"%s\"", thisEqn );
             maxCols=1;
             break;
                 }
yantosca commented 2 years ago

I've since fixed the issue above. For now I only use the small_strato mechanism for all the C-language integration tests. KPP will now generate code with the other mechanisms (e.g. saprcnov.eqn) though. Good enough for the sake of continuity and for the KPP 3.0.0 version.