Skip to content

Multiple delegates for eval in ExtensibleReactor #253

@BoyangMichael

Description

@BoyangMichael

Abstract

Currently, ExtensibleReactor accept only one delegate for eval. It would be very helpful if we can define multiple delegates for eval at the same time. For example define before_eval and after_eval at the same time.

Motivation

The ExtensibleReactor is very useful when we want to do some "customization" of the ODEs and equations. However, different needs of customization may require to be placed in different positions along the process. For example, the operation to change the rate constant of one reaction at every integration step is better placed before eval while the operation to impose a fixed T profile is better to be placed after eval. Below is an example of script.

class NewReactor(ct.ExtensibleReactor):
    def __init__(self, phase, ramp=0.25, irxn=None, **kwargs):
        super().__init__(phase, **kwargs)
        # Customization 1 - change rate constant
        self.irxn = irxn
        self.multiplier = some_computations
        # Customization 2 - Impose T profile
        self.ramp = ramp
        self.T_index = self.component_index('temperature')

    # Customization 1 - change rate constant
    def before_eval(self, t, LHS, RHS):
        self.multiplier = some_computations
        self.kinetics.set_multiplier(self.multiplier, self.irxn)

    # Customization 2 - Impose T profile
    def after_eval(self, t, LHS, RHS):
        # Temperature Ramp
        LHS[self.T_index] = 1.0
        RHS[self.T_index] = self.ramp

However, such script is not possible because only one delegate for eval is allowed. Here is the error message.

File build/python/cantera/reactor.pyx:671, in 
cantera.reactor.ExtensibleReactor.__init__() 

File build/python/cantera/delegator.pyx:301, in 
cantera.delegator.assign_delegates() 

CanteraError: Only one delegate supported for 'eval'

An alternative way would be using replace_eval containing both customization operations and the original eval method. However, it is also not possible because the original eval method seems not available to Python. Example script below:

class NewReactor(ct.ExtensibleReactor):
    def __init__(self, phase, ramp=0.25, irxn=None, **kwargs):
        super().__init__(phase, **kwargs)
        # Obtain orginal eval method
        self.original_eval = super().eval

        # Customization 1 - change rate constant
        self.irxn = irxn
        self.multiplier = some_computations
        # Customization 2 - Impose T profile
        self.ramp = ramp
        self.T_index = self.component_index('temperature')

    def replace_eval(self, t, LHS, RHS):
        # Customization 1 - change rate constant
        self.multiplier = some_computations
        self.kinetics.set_multiplier(self.multiplier, self.irxn)

        # Original eval
        self.original_eval(t, LHS, RHS)

        # Customization 2 - Impose T profile
        LHS[self.T_index] = 1.0
        RHS[self.T_index] = self.ramp

Which gives error:

Exception thrown by Python callback function: 
AttributeError: 'super' object has no attribute 'eval'

Therefore, it would be very helpful if it is possible to (i) define multiple delegates for eval, and/or (ii) call original eval method in replace_eval.

Thank you very much in advance for consideration.

Ps. please forgive me if a similar request has been discussed before. I tried to search within the issues but I don't find a similar topic.

Possible Solutions

As mentioned above, the possible solutions I think of within my limited knowledge on programming are as follows.

  • Make it possible to define multiple delegates for eval, e.g., before_eval and after_eval at the same time.
  • Make it possible to call the original eval method in the replace_eval delegate.

References

None.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions