Basics of Creating N2 Model Visualizations

An OpenMDAO model can have a number of connections, and several different residuals being converged. Trying to keep track of all the connections in your head can be a bit challenging, but OpenMDAO offers some visualization tools to help see what’s going on. This page explains the basics of generating an N2 diagram either from the command line or from a script.

An N2 diagram, also known as an N-squared diagram, is a diagram in the shape of a matrix, representing functional or physical interfaces between system elements. It is used to systematically identify, define, tabulate, design, and analyze functional and physical interfaces. It applies to system interfaces and hardware and/or software interfaces. For more information, see N2_chart.

For this page, we will be using this code example. Notice that there is an error in this code because one of the connection lines has been commented out. This was done to show how the N2 diagram can help point out unconnected inputs quickly.

import openmdao.api as om
from openmdao.test_suite.scripts.circuit_analysis import Resistor, Diode, Node

class Circuit(om.Group):

    def setup(self):
        self.add_subsystem('n1', Node(n_in=1, n_out=2), promotes_inputs=[('I_in:0', 'I_in')])
        self.add_subsystem('n2', Node())  # leaving defaults

        self.add_subsystem('R1', Resistor(R=100.), promotes_inputs=[('V_out', 'Vg')])
        self.add_subsystem('R2', Resistor(R=10000.))
        self.add_subsystem('D1', Diode(), promotes_inputs=[('V_out', 'Vg')])

        self.connect('n1.V', ['R1.V_in', 'R2.V_in'])
        self.connect('R1.I', 'n1.I_out:0')
        self.connect('R2.I', 'n1.I_out:1')

        self.connect('n2.V', ['R2.V_out', 'D1.V_in'])
        self.connect('R2.I', 'n2.I_in:0')
        # self.connect('D1.I', 'n2.I_out:0') # commented out so there is an unconnected input
                                             # example for docs for the N2 diagram

        self.nonlinear_solver = om.NewtonSolver(solve_subsystems=False)
        self.nonlinear_solver.options['iprint'] = 2
        self.nonlinear_solver.options['maxiter'] = 20
        self.linear_solver = om.DirectSolver()

p = om.Problem()
model = p.model

model.set_input_defaults('ground.V', 0., units='V')
model.set_input_defaults('source.I', 0.1, units='A')
model.add_subsystem('circuit', Circuit(),
                    promotes_inputs=[('Vg', 'ground.V'), ('I_in', 'source.I')])

model.add_design_var('ground.V')
model.add_design_var('source.I')
model.add_objective('circuit.D1.I')

p.setup()
p.check_config(checks=['unconnected_inputs'], out_file=None)

# set some initial guesses
p['circuit.n1.V'] = 10.
p['circuit.n2.V'] = 1.

p.run_model()

From the Command Line

Generating an N2 diagram for a model from the command line is easy. First, you need either a Python script that runs the model or a case recording file that was created when running the model.

Note

If using a script and final_setup isn’t called in the script (either directly or as a result of run_model or run_driver) then nothing will happen. Also, when using the command line version, even if the script does call run_model or run_driver, the script will terminate after final_setup and will not actually run the model.

The openmdao n2 command will generate an N2 diagram of the model that is viewable in a browser, for example:

openmdao n2 openmdao/test_suite/scripts/circuit_with_unconnected_input.py

will generate an N2 diagram like the one below.

The openmdao n2 has several options:

openmdao n2 -h
usage: openmdao n2 [-h] [-o OUTFILE] [--no_browser] [--embed] [--title TITLE]
                   [--use_declare_partial_info]
                   file

positional arguments:
  file                  Python script or recording containing the model.

optional arguments:
  -h, --help            show this help message and exit
  -o OUTFILE            html output file.
  --no_browser          don't display in a browser.
  --embed               create embeddable version.
  --title TITLE         diagram title.
  --use_declare_partial_info
                        ignored, now always true.

From a Script

You can do the same thing programmatically by calling the n2 function.

openmdao.visualization.n2_viewer.n2_viewer.n2(data_source, outfile='n2.html', show_browser=True, embeddable=False, title=None, use_declare_partial_info=False)[source]

Generate an HTML file containing a tree viewer.

Optionally opens a web browser to view the file.

Parameters
data_source<Problem> or str

The Problem or case recorder database containing the model or model data.

outfilestr, optional

The name of the final output file

show_browserbool, optional

If True, pop up the system default web browser to view the generated html file. Defaults to True.

embeddablebool, optional

If True, gives a single HTML file that doesn’t have the <html>, <DOCTYPE>, <body> and <head> tags. If False, gives a single, standalone HTML file for viewing.

titlestr, optional

The title for the diagram. Used in the HTML title.

use_declare_partial_infoignored

This option is no longer used because it is now always true. Still present for backwards compatibility.

Notice that the data source can be either a Problem or case recorder database containing the model or model data. The latter is indicated by a string giving the file path to the case recorder file.

Here are some code snippets showing the two cases.

Problem as Data Source

p.setup()

om.n2(p)

Case Recorder as Data Source

r = om.SqliteRecorder('circuit.sqlite')
p.driver.add_recorder(r)

p.setup()
p.final_setup()
r.shutdown()

om.n2('circuit.sqlite', outfile='circuit.html')

In the latter case, you could view the N2 diagram at a later time using the command:

openmdao n2 circuit.sqlite

For more details on N2 diagrams, see the N2 Details section.