Surface reactoins without Interface.h (deprecated)

99 views
Skip to first unread message

ste....@gmail.com

unread,
Feb 19, 2021, 5:12:00 PM2/19/21
to Cantera Users' Group

Hey guys,

I am try to moving from Interface.h to Solution.h to describe catalytic (surface) reactions, but I cannot find an example that shows how to correctly initialize all the objects required.

Right now, I'm initializing the objects as follow:

std::shared_ptr<Cantera::Solution>          gas_sol_;
std::shared_ptr<Cantera::Solution>          surf_sol_;
std::shared_ptr<Cantera::ThermoPhase>       thermo_;
std::shared_ptr<Cantera::Transport>         transport_;
std::shared_ptr<Cantera::Kinetics>          kinetic_;
std::shared_ptr<Cantera::SurfPhase>         surface_;
std::shared_ptr<Cantera::InterfaceKinetics> surface_kinetic_;

gas_sol_          = Cantera::newSolution(filename,type[0]);
transport_        = gas_sol_->transport();
thermo_           = gas_sol_->thermo();
 kinetic_          = gas_sol_->kinetics(); 

 surf_sol_         = Cantera::newSolution(filename,type[1],"None",{gas_sol_}); 
 surface_          = surf_sol_->thermo();
 surface_kinetic_  = surf_sol_->kinetics();

The problem is related with the surface part, can anyone help me?

Thank you so much,

Bests

Stefano

Ray Speth

unread,
Feb 19, 2021, 11:08:37 PM2/19/21
to Cantera Users' Group

Hi Stefano,

The Solution class only works with bulk phases. For surface phases, you need to construct separate thermo and kinetics objects. The easiest way to do this is probably with the newPhase and newKinetics functions, using the versions that take an input file as one of the arguments. For example,

std::shared_ptr<Cantera::ThermoPhase> surface_(newPhase(filename, "surfPhaseName"));
std::vector<Cantera::ThermoPhase*> phases { surface_.get(), thermo_.get() };
std::shared_ptr<Cantera::Kinetics> surface_kinetic_(newKinetics(phases, filename, "surfPhaseName"));

Regards,
Ray

ste....@gmail.com

unread,
Feb 23, 2021, 3:10:01 PM2/23/21
to Cantera Users' Group
Hi Ray,

thank you so much for your help. Just a couple of questions:

- should I create a Cantera::ThermoPhase or a Cantera::SurfPhase object for the "surface" phase?
- should I create a Cantera::Kinetics or a Cantera::InterfaceKinetics object for the "surface" reactions?

Thank you so much,

Regards,
Stefano

Ray Speth

unread,
Feb 24, 2021, 8:10:27 PM2/24/21
to Cantera Users' Group

Hi Stefano,

The underlying objects will be of the SurfPhase and InterfaceKinetics types, because that is what is specified in the input file. However, the newPhase and newKinetics functions have to return pointers which only specify the base class, because the underlying type of the returned object could be any kind of ThermoPhase or Kinetics object. If you only need to access the functions that are available from the base class (which is hopefully the case), then you can just use the base class pointer. However, if you need access to the few functions that are only defined on these specific derived classes, e.g. SurfPhase::setSiteDensity, then you will need to cast the pointer to the derived type, e.g.

std::shared_ptr<Cantera::SurfPhase> surf2 = std::dynamic_pointer_cast<Cantera::SurfPhase>(surface_);

Hope this helps.

Regards,
Ray

ste....@gmail.com

unread,
Mar 4, 2021, 1:30:56 PM3/4/21
to Cantera Users' Group
Hey Ray,

can I hopefully ask you my last question about C++ and Phases and Kinetics generation?

// Generation of gas phase as ThermoPhase
Cantera::ThermoPhase *thermo;
thermo = Cantera::newPhase(filepath, gasPhase);

//Generation of transport from thermo
Cantera::Transport *transport;
transport = Cantera::newDefaultTransportMgr(thermo);

//Generation of gas phase kinetics from thermo
Cantera::Kinetics *kinetic;
std::vector<Cantera::ThermoPhase *> phases{thermo};
kinetic = Cantera::newKineticsMgr(thermo->xml(), phases);

//Generation of surface as SurfPhase
Cantera::SurfPhase *surface;
std::shared_ptr<Cantera::ThermoPhase> surface_as_thermo(Cantera::newPhase(filepath, surfPhase));
surface = surface_ptr.get();

//Generation of surface kinetics from thermo and surface_as_thermo
Cantera::InterfaceKinetics *surface_kinetic;
std::vector<Cantera::ThermoPhase *> phases{thermo, surface_as_thermo.get()};
std::shared_ptr<Cantera::Kinetics> surface_as_kinetic(Cantera::newKinetics(phases, filepath, surfPhase));
std::shared_ptr<Cantera::InterfaceKinetics> surface_kinetic_ptr = std::dynamic_pointer_cast<Cantera::InterfaceKinetics>(surface_as_kinetic);
surface_kinetic = surface_kinetic_ptr.get();

When I try to get surface species names with:

std::vector<std::string> coverage_names = surface->speciesNames();

I get a core dump error.

Could you help me understand what's wrong with my initialization?

Thank you so much for your help,

Bests,

Stefano

Ray Speth

unread,
Mar 4, 2021, 3:54:05 PM3/4/21
to Cantera Users' Group

Hi Stefano,

I don’t see a declaration or initialization for surface_ptr in your example. Is there something missing? If it’s not being initialized anywhere, then surface is going to be a null pointer and generate the behavior that you’re observing.

Regards,
Ray

ste....@gmail.com

unread,
Mar 6, 2021, 3:35:23 PM3/6/21
to Cantera Users' Group
Hi Ray,

sorry that was a wrong copy and paste of my code :(

Here, the correct version that still shows the same issue. Attached also the kinetic scheme in xml format.

        // Create gas phase as ThermoPhase
        Cantera::ThermoPhase *thermo;
        thermo = Cantera::newPhase(filepath, gasPhase);
         
        // Create gas Transport from thermo
        Cantera::Transport *transport;
        {
            transport = Cantera::newDefaultTransportMgr(thermo);
        }
         
        // Create gas kinetic reactions as Kinetics from thermo
        Cantera::Kinetics *kinetic;
        {
            std::vector<Cantera::ThermoPhase *> gas_phases{thermo};
            kinetic = Cantera::newKineticsMgr(thermo->xml(), gas_phases);
        }
 
        // Create surface phase as SurfPhase and surface kinetic as InterfaceKinetics
        Cantera::SurfPhase *surface;
        Cantera::InterfaceKinetics *surface_kinetic;
        if (surfPhase != "none")
        {
            std::shared_ptr<Cantera::ThermoPhase> surface_as_thermo(Cantera::newPhase(filepath, surfPhase));
            std::vector<Cantera::ThermoPhase *> gas_and_surface_phases{thermo, surface_as_thermo.get()};
            std::shared_ptr<Cantera::Kinetics> surface_as_kinetic(Cantera::newKinetics(gas_and_surface_phases, filepath, surfPhase));
             
            std::shared_ptr<Cantera::SurfPhase>         surface_ptr         = std::dynamic_pointer_cast<Cantera::SurfPhase>(surface_as_thermo);
            std::shared_ptr<Cantera::InterfaceKinetics> surface_kinetic_ptr = std::dynamic_pointer_cast<Cantera::InterfaceKinetics>(surface_as_kinetic);
            surface = surface_ptr.get();
            surface_kinetic = surface_kinetic_ptr.get();
        }


Since I don't wonna bother you too much, if you have a link where I can find some example for the C++ version of Cantera, I will try to solve this issue on my own.

Thank you so much,

Bests

H2-O2-Rh.xml

Ray Speth

unread,
Mar 8, 2021, 9:50:49 AM3/8/21
to Cantera Users' Group

Hi Stefano,

I tried making minimal additions to your code to get a complete example, and wasn’t able to replicate the problem you described. The following code works just fine for me:

#include "cantera/thermo.h"
#include "cantera/transport.h"
#include "cantera/kinetics.h"
#include "cantera/thermo/SurfPhase.h"
#include "cantera/kinetics/InterfaceKinetics.h"

int main(int argc, char** argv) {
    std::string filepath = "H2-O2-Rh.xml";
    std::string gasPhase = "gas";
    std::string surfPhase = "Rh_surface";

    
// Create gas phase as ThermoPhase
    Cantera::ThermoPhase *thermo;
    thermo = Cantera::newPhase(filepath, gasPhase);

    // Create gas Transport from thermo
    Cantera::Transport *transport;
    {
        transport = Cantera::newDefaultTransportMgr(thermo);
    }

    // Create gas kinetic reactions as Kinetics from thermo
    Cantera::Kinetics *kinetic;
    {
        std::vector<Cantera::ThermoPhase *> gas_phases{thermo};
        kinetic = Cantera::newKineticsMgr(thermo->xml(), gas_phases);
    }

    // Create surface phase as SurfPhase and surface kinetic as InterfaceKinetics
    Cantera::SurfPhase *surface;
    Cantera::InterfaceKinetics *surface_kinetic;
    if (surfPhase != "none")
    {
        std::shared_ptr<Cantera::ThermoPhase> surface_as_thermo(Cantera::newPhase(filepath, surfPhase));
        std::vector<Cantera::ThermoPhase *> gas_and_surface_phases{thermo, surface_as_thermo.get()};
        std::shared_ptr<Cantera::Kinetics> surface_as_kinetic(Cantera::newKinetics(gas_and_surface_phases, filepath, surfPhase));

        std::shared_ptr<Cantera::SurfPhase>         surface_ptr         = std::dynamic_pointer_cast<Cantera::SurfPhase>(surface_as_thermo);
        std::shared_ptr
<Cantera::InterfaceKinetics> surface_kinetic_ptr = std::dynamic_pointer_cast<Cantera::InterfaceKinetics>(surface_as_kinetic);
        surface = surface_ptr.get();
        surface_kinetic = surface_kinetic_ptr.get();

        for (auto& name : surface->speciesNames()) {
            Cantera::writelog("{}\n", name);
        }
    }
  return 0;
}

Regards,
Ray

ste....@gmail.com

unread,
Mar 13, 2021, 12:14:21 PM3/13/21
to Cantera Users' Group
Hi Ray,

I tried your code and I get the same problem, maybe my problem is related to some wrong compiling options. Right now, I'm compiling using g++ 9.3.0 on Ubuntu 20.04 LTS.

The compiling options are:
g++ -o test.sh test.cpp -I/usr/local/include/ -L/usr/local/lib -lcantera -lcantera_fortran -lgfortran -lpthread -lm

Bests,

Stefano

ste....@gmail.com

unread,
Mar 16, 2021, 9:04:36 AM3/16/21
to Cantera Users' Group
Hi Ray,

I fix the problem by recompiling cantera, I don't know what I did wrong. I am so sorry that I waste your time.

Thank you so much for your help,

Cheers,

Stefano
Reply all
Reply to author
Forward
0 new messages