How to know if a System is under FD or CS

All Systems (Components and Groups) have two flags that indicate whether the System is running under finite difference or complex step. The under_finite_difference flag is True if the System is being finite differenced and the under_complex_step flag is True if the System is being complex stepped.

Usage

First we’ll show how to detect when a component is being finite differenced:

import numpy as np

import openmdao.api as om


class MyFDPartialComp(om.ExplicitComponent):
    def setup(self):
        self.num_fd_computes = 0

        self.add_input('x')
        self.add_output('y')

    def setup_partials(self):
        self.declare_partials('y', 'x', method='fd')

    def compute(self, inputs, outputs):
        outputs['y'] = 1.5 * inputs['x']
        if self.under_finite_difference:
            self.num_fd_computes += 1
            print(f"{self.pathname} is being finite differenced!")

        
p = om.Problem()
p.model.add_subsystem('comp', MyFDPartialComp())

p.setup()
p.run_model()

# there shouldn't be any finite difference computes yet
print("Num fd calls = ", p.model.comp.num_fd_computes)

totals = p.compute_totals(['comp.y'], ['comp.x'])

# since we're doing forward difference, there should be 1 call to compute under fd
print("Num fd calls =", p.model.comp.num_fd_computes)
Num fd calls =  0
comp is being finite differenced!
Num fd calls = 1

Now we’ll do the same thing for a complex stepped component:

import numpy as np

import openmdao.api as om

class MyCSPartialComp(om.ExplicitComponent):
    def setup(self):
        self.num_cs_computes = 0

        self.add_input('x')
        self.add_output('y')

    def setup_partials(self):
        self.declare_partials('y', 'x', method='cs')

    def compute(self, inputs, outputs):
        outputs['y'] = 1.5 * inputs['x']
        if self.under_complex_step:
            self.num_cs_computes += 1
            print(f"{self.pathname} is being complex stepped!")

        
p = om.Problem()
p.model.add_subsystem('comp', MyCSPartialComp())

p.setup()
p.run_model()

# there shouldn't be any complex step computes yet
print("Num cs calls =", p.model.comp.num_cs_computes)


totals = p.compute_totals(['comp.y'], ['comp.x'])

# there should be 1 call to compute under cs
print("Num cs calls =", p.model.comp.num_cs_computes)
Num cs calls = 0
comp is being complex stepped!
Num cs calls = 1