Defining a new kinetic model for the electrochemical hydrogen oxidation (MultiReactionMcfc class)

here you are the passages i’ve done

as you said now i’ve to do the implementation of the parameters " In file
starting at line 60 where there is a series of if … else if … else if …
then i create a new paragraph with the parameter values and
equation .

as you said i’ve added at line 60 a new paragraph with parameters, what i’ave to do now?

As pointed out in the prerequisites section of the LIBPF™ SDK Developer manual, to develop models with LIBPF™ a basic knowledge of the C++11 programming language is required.

If you have no time to read the best book around for C++ (Bjarne Stroustrup’s “The C++ Programming Language” 4th ed. Addison-Wesley 2013):

then at least have a look at the C++ for dummies cheatsheet and the C++ All-In-One For Dummies cheatsheet. Despite the funny titles, these are good books !

For the first screenshot specifically (, first of all you have fallen prey of mistake #10 from the list of “The 10 Most Common C++ Mistakes”: you forgot a semicolon. Actually you forgot semicolons at the end of lines 103, 104 and 105. This is a classic mistake, we’ve all gone through !

Please note that Qt Creator, thanks to its excellent real-time Code Syntax Checking functionality, is trying to tell you about these errors: if you notice, these lines are highlighted with a red wavy line; and if you hover on that, it will very likely tell you “You forgot a semicolon”.

Also for the 1st screenshot, there are other errors so fix them one by one with the help of the Code Syntax Checking functionality !

Apart from the errors, I also have a style comment: although perfectly legit, declaring variables with non-ASCII characters such as θ is something we advise against; for example in the LIBPF™ Coding Standard we advise against using UNICODE characters at all in source files. So I would name that variable “theta” or “t”.

For the 2nd screenshot (multireactions.h), AFAICT there’s a stray colon after the semicolon at the end of the line. Again, the red wavy line is there to point you to your error.

As to the 3rd screenshot (, that looks fine to me.

In the last screenshot ( it looks like some variables (p1, p2, p3…) are defined multiple times. The wavy line this time is green (because Qt Creator is not 100% sure it’s an error) but I think that’s an error: if you try to build the project, the compiler will tell you !

Just declare the only new variable you’ve added (θ), or better yet rename that to theta or t and declare it.

Back to the original problem of defining a new kinetic expression for the electrochemical hydrogen oxydation (MultiReactionMcfc class), it looks to me you have done the following:

  • in the header file for the electrochemical reaction multireactions.h:

    • documented, in the MultiReactionMcfc class, the new available value for the kinetic option (finalmodel)
  • in the implementation file of the electrochemical reaction

    • declared the new variable you need for the new kinetic expression (theta)
    • added the values of the existing (p1, p2, p3…) and of the new parameter (theta) in the series of if ... else if ... else if ... that begins on line 62
    • leave the default kinetic = CONTEX at line 24 (DEFINE), so that all existing models still use that
  • in implementation file for your flowsheet

    • at line 87, override the default value for kinetic so that the new expression is used in you own model only

So it looks to me just this final step is missing:

  • in the file
    • in the series of if ... else if ... else if ... that begins around line 114, add the new functional expression (for where would the new parameter be used ?)


then i haven’t understand how i have to do at line 87 of file .
And in the file multi in what way i have to insert the new kinetic??

At line 87 of

FlowSheet::addUnit(typeW.value(), defaults.relay( "STACKS",  "MCFC
stack")("kinetic", "finalmodel"));

you have overridden the default value for the kinetic option (set at line 24 or to CONTEX) with your new value finalmodel so that’s OK.

What is now missing in the file around line 114, is that the if branch of the if ... else statement covers the cases when the string option kinetic has the values literature or Robystad3 or BocciardoGarbarino, in those cases it uses for the areic electrical resistance the functional expression:

RA * exp(RB / Teq) / pow(pO2cat, RE) + RC + RD*exp(RF / Teq)

whereas the else branch covers all other cases (including the case finalmodel we care about) with the expression:

Rohm = p1 * exp(p2/(Teq - 273.15))
Rcat = p3 * T * exp(p4/Teq) / pCO2cat
Ran  = p7 * T * exp(p8/Teq) / sqrt(pH2an)
Rohm + Rcat + Ran 

which is correct for CONTEX.

As you can see the parameter p2, p5 and the new one t are never used !

So you have to add the new functional expression which uses the parameters p2, p5 and t in a new else if branch like in:

if ( (kinetic.value() == "literature") || (kinetic.value() == "Robystad3") || (kinetic.value() == "BocciardoGarbarino") ) {
  // ...
} else if (kinetic.value() == "finalmodel") {
  // new expression goes here
} else {
  // ..

It’s ok in this way?

That looks like a step in the right direction. Of course you need to uncomment this new line 122 (remove the double forward slashes at the beginning). The compiler will then yell at you because not all required variables are entered in proper C++ syntax.

The function MultiReactionMcfc::calcE0 implements the pure virtual function MultiReactionElectrochemical::calcE0, from whose documentation here you can read the meaning of the x0 and x1 parameters.

Use those to access the molar fractions at the anode and the cathode side. They are vectors indexed by integers. To know which integer correspond to which component, check lines 161-168 of

components.addcomp(new purecomps::water);
components.addcomp(new purecomps::N2);
components.addcomp(new purecomps::O2);
components.addcomp(new purecomps::methane);
components.addcomp(new purecomps::ethane);
components.addcomp(new purecomps::CO);
components.addcomp(new purecomps::CO2);
components.addcomp(new purecomps::H2);

that means water will have index 0, N2 index 1 etc.

Alternatively you can use the syntax x0[components.lookup("H2")] as in the CONTEX expression, that uses the convenient helper function ListComponents::lookup which returns the index of component with name “n”.

This latter approach is better because if someone shuffles the component list, altering the order or adding new components, indexes may change. By using the ListComponents::lookup you’re always sure the index is correct !

i’m tryng to write the expression in the right way, it’s quite long so i divided in 3 pieces the image


Mmmmh difficult to say. Normally you should look at the first errors first, as sometimes the first one may cause unrelated effects in the new few lines.

If you don’t get the handle of it, just do a git commit -a -m 'errors' then git push and I’ll take a look tomorrow.

These are the errors you get:

src/ error: no matching function for call to 'pow'
src/ error: too many arguments to function call, expected single argument 'i',
      have 2 arguments
  ...outp[1]->frac(components.lookup("O2"),-0.75)*(pow(outp[1]->frac(components.lookup("CO2"),0.5) + ((...
     ~~~~~~~~~~~~~                         ^~~~~
src/ error: too many arguments to function call, expected single argument 'i',
      have 2 arguments
  ...outp[1]->frac(components.lookup("CO2"),0.5) + ((p7*Teq*exp(p8/Teq)))/(P1*log(1+outp[0]->frac(compo...
     ~~~~~~~~~~~~~                          ^~~
src/ error: use of undeclared identifier 'resistivity'
  DEFINE(resistivity, "Resistivity electrolyte correlation", "Fabbri2008"),

You have to address them one by one, starting from the first three. The errors from line 173 onward are fakes, and caused by the first ones.

BTW for the sake of readability I advise you to break up the very long line; I usually insert line breaks after the operators (+ * / …).

I don’t follow the thread of speech, in which way i have to breaks the line? in what points? then, in what way may I correct the errors?

I mean line 122 which is quite long as you wrote above when you had to capture three screenshots:

if you have a long line in C++ like this one:

a = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20;

you can break it up like this:

a = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 +
    12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20;

for example this is the 1st one:

src/ error: no matching function for call to 'pow'

you notice immediately that you are calling pow with just one argument, whereas pow takes two arguments: std::pow, std::powf, std::powl -

so it’s trivial to see that you meant:


rather than:


etc etc

I divided the kinetic expression, as you see in the first 2 lines there aren’t problems, instead in the other three yes!

the case

is different from partial pressure structure, for example [quote=“paolog, post:20, topic:58”]

how could modify it? i don’t find a solution

it looks like this time the error at line 125 is caused by incorrect parameters being passed to the frac function

so your code:


should really be:


beware the parentheses !

now the errors are 19 like is shown in the figure! but the problems of the other lines, excepted line 127 are solved!! Now i’m trying to modify parentheses but i don’t find a solution!

i’m quite sure that otp[0] is correct in the line 127

why it doesn’t work?

to troubleshoot such problems, here are the options:

  1. you can make good use of Qt Creator’s feature that highlights the matching parentheses; for example in this screenshot:

    I placed the cursor after the function pow - notice that Creator highlights the opening and closing parentheses

  2. you can break up the line according to the the parentheses, using indentation to make it clear which term belongs to which parenthesis, as in:

    Rarea = RA * exp(
    RB / Teq
    ) / pow(
    P1 * outp[1]->frac(
    ), RE
    ) + RC + RD*exp(
    RF / Teq

in this way, it should be easier to spot the error !
3) you can introduce auxiliary variables to break up the large expression in tinier bits; this is precisely what has been done for the CONTEX kinetic:

Value pCO2 = P1 * x1[components.lookup("CO2")]; // 0: anode, 1: cathode
Value pH2 = P1 * x0[components.lookup("H2")];
Value Rohm = p1 * exp(p2/(Teq - Value(273.15, "K")));
Value Rcat = p3 * T * exp(p4/Teq) / pCO2; // + p5 * Teq * exp(p6/Teq) / sqrt(pO2) * pCO2;
Value Ran  = p7 * T * exp(p8/Teq) / sqrt(pH2);
Rarea = Rohm + Rcat + Ran;

Now it told me this!

  Value Rohm = p1 * exp(p2/Teq);
  Value Rcat = (p3*T*exp(p4/Teq)/(P1*log(pow(1-(1.5/1+t)*(outp[1]->frac(components.lookup("CO2"))+t*(outp[0]->frac(components.lookup("H2O"))),-1)+
               p5*Teq*exp(p6/Teq)*(pow (P1,-0.25)*
  Value Ran = (p7*Teq*exp(p8/Teq))/(P1*log(1+outp[0]->frac(components.lookup("H2"))));
  Rarea = Rohm + Rcat + Ran