예제 #1
0
def main():  # pragma: no cover
    p = Problem()
    p.model = LaunchVehicleLinearTangentODE(num_nodes=1)
    p.setup()

    p.run_model()

    var_map = {
        'rho': r'$\rho$',
        'x': r'$x$',
        'y': r'$y$',
        'vx': r'$v_x$',
        'vy': r'$v_y$',
        'm': r'$m$',
        'mdot': r'$\dot{m}$',
        'Isp': r'$I_{sp}$',
        'thrust': r'$F_{T}$',
        'ydot': r'$\dot{y}$',
        'xdot': r'$\dot{x}$',
        'vxdot': r'$\dot{v}_x$',
        'vydot': r'$\dot{v}_y$',
        'theta': r'$\theta$',
        'a_ctrl': r'$a$',
        'b_ctrl': r'$b$',
        'time': r'$time$'
    }

    xdsm = XDSM()
    xdsm.from_openmdao_group(p.model, var_map=var_map)
    xdsm.write('ssto_linear_tangent_xdsm', build=True, cleanup=True)
예제 #2
0
def main():
    p = Problem()
    p.model = LaunchVehicleODE(num_nodes=1)
    p.setup()

    p.run_model()

    var_map = {
        'rho': r'$\rho$',
        'x': r'$x$',
        'y': r'$y$',
        'vx': r'$v_x$',
        'vy': r'$v_y$',
        'm': r'$m$',
        'mdot': r'$\dot{m}$',
        'Isp': r'$I_{sp}$',
        'thrust': r'$F_{T}$',
        'ydot': r'$\dot{y}$',
        'xdot': r'$\dot{x}$',
        'vxdot': r'$\dot{v}_x$',
        'vydot': r'$\dot{v}_y$',
        'theta': r'$\theta$'
    }

    xdsm = XDSM()
    xdsm.from_openmdao_group(p.model, var_map=var_map)
    xdsm.write('ssto_xdsm', build=True, cleanup=True)
예제 #3
0
    def test_connect(self):
        x = XDSM(use_sfmath=False)
        x.add_system("D1", FUNC, "D_1", label_width=2)
        x.add_system("D2", FUNC, "D_2", stack=False)

        try:
            x.connect("D1", "D2", r"\mathcal{R}(y_1)", "foobar")
        except ValueError as err:
            self.assertEquals(str(err), "label_width argument must be an integer")
        else:
            self.fail("Expected ValueError")
예제 #4
0
    def test_connect(self):
        x = XDSM(use_sfmath=False)
        x.add_system('D1', 'Function', 'D_1', label_width=2)
        x.add_system('D2', 'Function', 'D_2', stack=False)

        try:
            x.connect('D1', 'D2', r'\mathcal{R}(y_1)', 'foobar')
        except ValueError as err:
            self.assertEquals(str(err),
                              'label_width argument must be an integer')
        else:
            self.fail('Expected ValueError')
예제 #5
0
    def test_stacked_system(self):

        x = XDSM()

        x.add_system("test", OPT, r"\text{test}", stack=True)

        file_name = "stacked_test"
        x.write(file_name)

        tikz_file = file_name + ".tikz"
        with open(tikz_file, "r") as f:
            tikz = f.read()

        self.assertIn(r"\node [Optimization,stack]", tikz)
예제 #6
0
파일: test_xdsm.py 프로젝트: mdolab/pyXDSM
    def test_write_outdir(self):
        fname = "test"

        for abspath in [True, False]:
            subdir = tempfile.mkdtemp(dir=self.tempdir)
            outdir = subdir if abspath else os.path.basename(subdir)

            x = XDSM()
            x.add_system("x", FUNC, "x")
            x.write(fname, outdir=outdir)

            for ext in [".tex", ".tikz", ".pdf"]:
                self.assertTrue(
                    os.path.isfile(os.path.join(subdir, fname + ext)))

        # no files outside the subdirs
        self.assertFalse(
            any(os.path.isfile(fp) for fp in os.listdir(self.tempdir)))
예제 #7
0
    def test_options(self):

        filename = "xdsm_test_options"
        spec_dir = filename + "_specs"

        # Change `use_sfmath` to False to use computer modern
        x = XDSM(use_sfmath=False)

        x.add_system("opt", OPT, r"\text{Optimizer}")
        x.add_system("solver", SOLVER, r"\text{Newton}")
        x.add_system("D1", FUNC, "D_1", label_width=2)
        x.add_system("D2", FUNC, "D_2", stack=False)
        x.add_system("F", FUNC, "F", faded=True)
        x.add_system("G", FUNC, "G", spec_name="G_spec")

        x.connect("opt", "D1", "x, z")
        x.connect("opt", "D2", "z")
        x.connect("opt", "F", "x, z")
        x.connect("solver", "D1", "y_2")
        x.connect("solver", "D2", "y_1")
        x.connect("D1", "solver", r"\mathcal{R}(y_1)")
        x.connect("solver", "F", "y_1, y_2")
        x.connect("D2", "solver", r"\mathcal{R}(y_2)")
        x.connect("solver", "G", "y_1, y_2")

        x.connect("F", "opt", "f")
        x.connect("G", "opt", "g")

        x.add_output("opt", "x^*, z^*", side="right")
        x.add_output("D1", "y_1^*", side="left", stack=True)
        x.add_output("D2", "y_2^*", side="left")
        x.add_output("F", "f^*", side="left")
        x.add_output("G", "g^*")
        x.write(filename)
        x.write_sys_specs(spec_dir)

        # Test if files where created
        self.assertTrue(os.path.isfile(filename + ".tikz"))
        self.assertTrue(os.path.isfile(filename + ".tex"))
        self.assertTrue(os.path.isdir(spec_dir))
        self.assertTrue(os.path.isfile(os.path.join(spec_dir, "F.json")))
        self.assertTrue(os.path.isfile(os.path.join(spec_dir, "G_spec.json")))
예제 #8
0
    def test_options(self):

        filename = 'xdsm_test_options'
        spec_dir = filename + '_specs'

        # Change `use_sfmath` to False to use computer modern
        x = XDSM(use_sfmath=False)

        x.add_system('opt', 'Optimization', r'\text{Optimizer}')
        x.add_system('solver', 'MDA', r'\text{Newton}')
        x.add_system('D1', 'Function', 'D_1', text_width=2.0)
        x.add_system('D2', 'Function', 'D_2', stack=False)
        x.add_system('F', 'Function', 'F', faded=True)
        x.add_system('G', 'Function', 'G', spec_name="G_spec")

        x.connect('opt', 'D1', 'x, z')
        x.connect('opt', 'D2', 'z')
        x.connect('opt', 'F', 'x, z')
        x.connect('solver', 'D1', 'y_2')
        x.connect('solver', 'D2', 'y_1')
        x.connect('D1', 'solver', r'\mathcal{R}(y_1)')
        x.connect('solver', 'F', 'y_1, y_2')
        x.connect('D2', 'solver', r'\mathcal{R}(y_2)')
        x.connect('solver', 'G', 'y_1, y_2')

        x.connect('F', 'opt', 'f')
        x.connect('G', 'opt', 'g')

        x.add_output('opt', 'x^*, z^*', side='right')
        x.add_output('D1', 'y_1^*', side='left', stack=True)
        x.add_output('D2', 'y_2^*', side='left')
        x.add_output('F', 'f^*', side='left')
        x.add_output('G', 'g^*')
        x.write(filename)
        x.write_sys_specs(spec_dir)

        # Test if files where created
        self.assertTrue(os.path.isfile(filename + '.tikz'))
        self.assertTrue(os.path.isfile(filename + '.tex'))
        self.assertTrue(os.path.isdir(spec_dir))
        self.assertTrue(os.path.isfile(os.path.join(spec_dir, 'F.json')))
        self.assertTrue(os.path.isfile(os.path.join(spec_dir, 'G_spec.json')))
예제 #9
0
    def test_tikz_content(self):
        # Check if TiKZ file was created.
        # Compare the content of the sample below and the newly created TiKZ file.

        sample_txt = r"""

            %%% Preamble Requirements %%%
            % \usepackage{geometry}
            % \usepackage{amsfonts}
            % \usepackage{amsmath}
            % \usepackage{amssymb}
            % \usepackage{tikz}

            % Optional packages such as sfmath set through python interface
            % \usepackage{sfmath}

            % \usetikzlibrary{arrows,chains,positioning,scopes,shapes.geometric,shapes.misc,shadows}

            %%% End Preamble Requirements %%%

            \input{"path/to/diagram_styles"}
            \begin{tikzpicture}

            \matrix[MatrixSetup]{
            %Row 0
            \node [DataIO] (left_output_opt) {$x^*, z^*$};&
            \node [Optimization] (opt) {$\text{Optimizer}$};&
            &
            \node [DataInter] (opt-D1) {$x, z$};&
            \node [DataInter] (opt-D2) {$z$};&
            \node [DataInter] (opt-F) {$x, z$};&
            \\
            %Row 1
            &
            &
            \node [MDA] (solver) {$\text{Newton}$};&
            \node [DataInter] (solver-D1) {$y_2$};&
            \node [DataInter] (solver-D2) {$y_1$};&
            \node [DataInter] (solver-F) {$y_1, y_2$};&
            \node [DataInter] (solver-G) {$y_1, y_2$};\\
            %Row 2
            \node [DataIO] (left_output_D1) {$y_1^*$};&
            &
            \node [DataInter] (D1-solver) {$\mathcal{R}(y_1)$};&
            \node [Function] (D1) {$D_1$};&
            &
            &
            \\
            %Row 3
            \node [DataIO] (left_output_D2) {$y_2^*$};&
            &
            \node [DataInter] (D2-solver) {$\mathcal{R}(y_2)$};&
            &
            \node [Function] (D2) {$D_2$};&
            &
            \\
            %Row 4
            \node [DataIO] (left_output_F) {$f^*$};&
            \node [DataInter] (F-opt) {$f$};&
            &
            &
            &
            \node [Function] (F) {$F$};&
            \\
            %Row 5
            \node [DataIO] (left_output_G) {$g^*$};&
            \node [DataInter] (G-opt) {$g$};&
            &
            &
            &
            &
            \node [Function] (G) {$G$};\\
            %Row 6
            &
            &
            &
            &
            &
            &
            \\
            };

            % XDSM process chains


            \begin{pgfonlayer}{data}
            \path
            % Horizontal edges
            (opt) edge [DataLine] (opt-D1)
            (opt) edge [DataLine] (opt-D2)
            (opt) edge [DataLine] (opt-F)
            (solver) edge [DataLine] (solver-D1)
            (solver) edge [DataLine] (solver-D2)
            (D1) edge [DataLine] (D1-solver)
            (solver) edge [DataLine] (solver-F)
            (D2) edge [DataLine] (D2-solver)
            (solver) edge [DataLine] (solver-G)
            (F) edge [DataLine] (F-opt)
            (G) edge [DataLine] (G-opt)
            (opt) edge [DataLine] (left_output_opt)
            (D1) edge [DataLine] (left_output_D1)
            (D2) edge [DataLine] (left_output_D2)
            (F) edge [DataLine] (left_output_F)
            (G) edge [DataLine] (left_output_G)
            % Vertical edges
            (opt-D1) edge [DataLine] (D1)
            (opt-D2) edge [DataLine] (D2)
            (opt-F) edge [DataLine] (F)
            (solver-D1) edge [DataLine] (D1)
            (solver-D2) edge [DataLine] (D2)
            (D1-solver) edge [DataLine] (solver)
            (solver-F) edge [DataLine] (F)
            (D2-solver) edge [DataLine] (solver)
            (solver-G) edge [DataLine] (G)
            (F-opt) edge [DataLine] (opt)
            (G-opt) edge [DataLine] (opt);
            \end{pgfonlayer}

            \end{tikzpicture}"""

        filename = "xdsm_test_tikz"

        x = XDSM(use_sfmath=True)

        x.add_system("opt", OPT, r"\text{Optimizer}")
        x.add_system("solver", SOLVER, r"\text{Newton}")
        x.add_system("D1", FUNC, "D_1")
        x.add_system("D2", FUNC, "D_2")
        x.add_system("F", FUNC, "F")
        x.add_system("G", FUNC, "G")

        x.connect("opt", "D1", "x, z")
        x.connect("opt", "D2", "z")
        x.connect("opt", "F", "x, z")
        x.connect("solver", "D1", "y_2")
        x.connect("solver", "D2", "y_1")
        x.connect("D1", "solver", r"\mathcal{R}(y_1)")
        x.connect("solver", "F", "y_1, y_2")
        x.connect("D2", "solver", r"\mathcal{R}(y_2)")
        x.connect("solver", "G", "y_1, y_2")

        x.connect("F", "opt", "f")
        x.connect("G", "opt", "g")

        x.add_output("opt", "x^*, z^*", side="left")
        x.add_output("D1", "y_1^*", side="left")
        x.add_output("D2", "y_2^*", side="left")
        x.add_output("F", "f^*", side="left")
        x.add_output("G", "g^*", side="left")
        x.write(filename)

        # Check if file was created
        tikz_file = filename + ".tikz"

        self.assertTrue(os.path.isfile(tikz_file))

        sample_lines = sample_txt.split("\n")
        sample_lines = filter_lines(sample_lines)

        with open(tikz_file, "r") as f:
            new_lines = filter_lines(f.readlines())

        sample_no_match = []  # Sample text
        new_no_match = []  # New text

        for new_line, sample_line in zip(new_lines, sample_lines):
            if new_line.startswith(r"\input{"):
                continue
            if new_line != sample_line:  # else everything is okay
                # This can be because of the different ordering of lines or because of an error.
                sample_no_match.append(new_line)
                new_no_match.append(sample_line)

        # Sort both sets of suspicious lines
        sample_no_match.sort()
        new_no_match.sort()

        for sample_line, new_line in zip(sample_no_match, new_no_match):
            # Now the lines should match, if only the ordering was different
            self.assertEqual(new_line, sample_line)

        # To be sure, check the length, otherwise a missing last line could get unnoticed because of using zip
        self.assertEqual(len(new_lines), len(sample_lines))
예제 #10
0
from pyxdsm.XDSM import XDSM

#
opt = 'Optimization'
solver = 'MDA'
ecomp = 'Analysis'
icomp = 'ImplicitAnalysis'
group = 'Metamodel'
func = 'Function'

x = XDSM()

#x.add_system('const', comp, r'\text{Constants}')
x.add_system('DYMOS', opt, [r'\text{DYMOS}'])
x.add_system('ambient', ecomp, [r'\text{Ambient}'])
# x.add_system('USATM', comp, [r'\text{US Atm 1976}'])
# x.add_system('mach_comp', comp, [r'\text{MACH}'])
x.add_system('prop_comp', icomp, [r'\text{Propeller}', r'\text{(OpenBEMT)}'])
x.add_system('e_comp', icomp, [r'\text{Electrical}', r'\text{(Zappy)}'])
x.add_system('engine_comp', icomp, [r'\text{Turboshaft}', r'\text{(pyCycle)}'])
# x.add_system('cool_comp', comp, [r'\text{Thermal}'])
x.add_system('solver', solver, [r'\text{Solver}'])
x.add_system('aero_comp', icomp,
             [r'\text{Wing Aerodynamics}', r'\text{(OpenAeroStruct)}'])
x.add_system('flight_dynamics', ecomp,
             [r'\text{Flight Dynamics}'])  # AKA prebalance
x.add_system('balance', icomp, [r'\text{Balance}'])
# x.add_system('drag_comp', comp, [r'\text{Aero Drag}'])
x.add_system('EOM_comp', ecomp, [r'\text{State Rates}'])
# x.add_system('', comp, r'\text{}')
예제 #11
0
    def test_tikz_content(self):
        # Check if TiKZ file was created.
        # Compare the content of the sample below and the newly created TiKZ file.

        tikz_txt = r"""
            
            %%% Preamble Requirements %%%
            % \usepackage{geometry}
            % \usepackage{amsfonts}
            % \usepackage{amsmath}
            % \usepackage{amssymb}
            % \usepackage{tikz}
            
            % Optional packages such as sfmath set through python interface
            % \usepackage{sfmath}
            
            % \usetikzlibrary{arrows,chains,positioning,scopes,shapes.geometric,shapes.misc,shadows}
            
            %%% End Preamble Requirements %%%
            
            \input{"D:/Documents/GitHub/mypyXDSM/pyXDSM/pyxdsm/diagram_styles"}
            \begin{tikzpicture}
            
            \matrix[MatrixSetup]{
            %Row 0
            \node [DataIO] (left_output_opt) {$x^*, z^*$};&
            \node [Optimization] (opt) {$\text{Optimizer}$};&
            &
            \node [DataInter] (opt-D1) {$x, z$};&
            \node [DataInter] (opt-D2) {$z$};&
            \node [DataInter] (opt-F) {$x, z$};&
            \\
            %Row 1
            &
            &
            \node [MDA] (solver) {$\text{Newton}$};&
            \node [DataInter] (solver-D1) {$y_2$};&
            \node [DataInter] (solver-D2) {$y_1$};&
            \node [DataInter] (solver-F) {$y_1, y_2$};&
            \node [DataInter] (solver-G) {$y_1, y_2$};\\
            %Row 2
            \node [DataIO] (left_output_D1) {$y_1^*$};&
            &
            \node [DataInter] (D1-solver) {$\mathcal{R}(y_1)$};&
            \node [Function] (D1) {$D_1$};&
            &
            &
            \\
            %Row 3
            \node [DataIO] (left_output_D2) {$y_2^*$};&
            &
            \node [DataInter] (D2-solver) {$\mathcal{R}(y_2)$};&
            &
            \node [Function] (D2) {$D_2$};&
            &
            \\
            %Row 4
            \node [DataIO] (left_output_F) {$f^*$};&
            \node [DataInter] (F-opt) {$f$};&
            &
            &
            &
            \node [Function] (F) {$F$};&
            \\
            %Row 5
            \node [DataIO] (left_output_G) {$g^*$};&
            \node [DataInter] (G-opt) {$g$};&
            &
            &
            &
            &
            \node [Function] (G) {$G$};\\
            %Row 6
            &
            &
            &
            &
            &
            &
            \\
            };
            
            % XDSM process chains
            
            
            \begin{pgfonlayer}{data}
            \path
            % Horizontal edges
            (opt) edge [DataLine] (opt-D1)
            (opt) edge [DataLine] (opt-D2)
            (opt) edge [DataLine] (opt-F)
            (solver) edge [DataLine] (solver-D1)
            (solver) edge [DataLine] (solver-D2)
            (D1) edge [DataLine] (D1-solver)
            (solver) edge [DataLine] (solver-F)
            (D2) edge [DataLine] (D2-solver)
            (solver) edge [DataLine] (solver-G)
            (F) edge [DataLine] (F-opt)
            (G) edge [DataLine] (G-opt)
            (opt) edge [DataLine] (left_output_opt)
            (D1) edge [DataLine] (left_output_D1)
            (D2) edge [DataLine] (left_output_D2)
            (F) edge [DataLine] (left_output_F)
            (G) edge [DataLine] (left_output_G)
            % Vertical edges
            (opt-D1) edge [DataLine] (D1)
            (opt-D2) edge [DataLine] (D2)
            (opt-F) edge [DataLine] (F)
            (solver-D1) edge [DataLine] (D1)
            (solver-D2) edge [DataLine] (D2)
            (D1-solver) edge [DataLine] (solver)
            (solver-F) edge [DataLine] (F)
            (D2-solver) edge [DataLine] (solver)
            (solver-G) edge [DataLine] (G)
            (F-opt) edge [DataLine] (opt)
            (G-opt) edge [DataLine] (opt);
            \end{pgfonlayer}
            
            \end{tikzpicture}"""

        def filter_lines(lns):
            # Empty lines are excluded.
            # Leading and trailing whitespaces are removed
            # Comments are removed.
            return [
                ln.strip() for ln in lns
                if ln.strip() and not ln.strip().startswith('%')
            ]

        filename = 'xdsm_test_tikz'

        x = XDSM(use_sfmath=True)

        x.add_system('opt', 'Optimization', r'\text{Optimizer}')
        x.add_system('solver', 'MDA', r'\text{Newton}')
        x.add_system('D1', 'Function', 'D_1')
        x.add_system('D2', 'Function', 'D_2')
        x.add_system('F', 'Function', 'F')
        x.add_system('G', 'Function', 'G')

        x.connect('opt', 'D1', 'x, z')
        x.connect('opt', 'D2', 'z')
        x.connect('opt', 'F', 'x, z')
        x.connect('solver', 'D1', 'y_2')
        x.connect('solver', 'D2', 'y_1')
        x.connect('D1', 'solver', r'\mathcal{R}(y_1)')
        x.connect('solver', 'F', 'y_1, y_2')
        x.connect('D2', 'solver', r'\mathcal{R}(y_2)')
        x.connect('solver', 'G', 'y_1, y_2')

        x.connect('F', 'opt', 'f')
        x.connect('G', 'opt', 'g')

        x.add_output('opt', 'x^*, z^*', side='left')
        x.add_output('D1', 'y_1^*', side='left')
        x.add_output('D2', 'y_2^*', side='left')
        x.add_output('F', 'f^*', side='left')
        x.add_output('G', 'g^*', side='left')
        x.write(filename)

        # Check if file was created
        tikz_file = filename + '.tikz'

        self.assertTrue(os.path.isfile(tikz_file))

        tikz_lines = tikz_txt.split('\n')
        tikz_lines = filter_lines(tikz_lines)

        with open(tikz_file, "r") as f:
            lines = filter_lines(f.readlines())

        sample_no_match = []  # Sample text
        new_no_match = []  # New text

        for line1, line2 in zip(lines, tikz_lines):
            if line1 != line2:  # else everything is okay
                # This can be because of the different ordering of lines or because of an error.
                sample_no_match.append(line1)
                new_no_match.append(line2)

        # Sort both sets of suspicious lines
        sample_no_match.sort()
        new_no_match.sort()

        for line1, line2 in zip(sample_no_match, new_no_match):
            # Now the lines should match, if only the ordering was different
            self.assertEqual(line1, line2)

        # To be sure, check the length, otherwise a missing last line could get unnoticed because of using zip
        self.assertEqual(len(lines), len(tikz_lines))
예제 #12
0
from pyxdsm.XDSM import XDSM, OPT, SOLVER, FUNC

# Change `use_sfmath` to False to use computer modern
x = XDSM(use_sfmath=True)

x.add_system("opt", OPT, r"\text{Optimizer}")
x.add_system("solver", SOLVER, r"\text{Newton}")
x.add_system("D1", FUNC, "D_1")
x.add_system("D2", FUNC, "D_2")
x.add_system("F", FUNC, "F")
x.add_system("G", FUNC, "G")

x.connect("opt", "D1", "x, z")
x.connect("opt", "D2", "z")
x.connect("opt", "F", "x, z")
x.connect("solver", "D1", "y_2")
x.connect("solver", "D2", "y_1")
x.connect("D1", "solver", r"\mathcal{R}(y_1)")
x.connect("solver", "F", "y_1, y_2")
x.connect("D2", "solver", r"\mathcal{R}(y_2)")
x.connect("solver", "G", "y_1, y_2")

x.connect("F", "opt", "f")
x.connect("G", "opt", "g")

x.add_output("opt", "x^*, z^*", side="left")
x.add_output("D1", "y_1^*", side="left")
x.add_output("D2", "y_2^*", side="left")
x.add_output("F", "f^*", side="left")
x.add_output("G", "g^*", side="left")
x.write("mdf")
예제 #13
0
from pyxdsm.XDSM import XDSM, OPT, SUBOPT, SOLVER, DOE, IFUNC, FUNC, GROUP, IGROUP, METAMODEL


x = XDSM(use_sfmath=False)

x.add_system('OPT', OPT, r"\text{Optimizer}")
x.add_system('ODE', GROUP, r"\text{ODE or DAE}")

x.connect('ODE', 'OPT', ["J", r"\bar{g}_0", r"\bar{g}_f", r"\bar{p}"],  label_width=4)
x.connect('OPT', 'ODE', ["t", r"\bar{x}", r"\bar{u}", r"\bar{d}"],  label_width=4)

x.write('opt_control')


x = XDSM(use_sfmath=False)

x.add_system('OPT_static', OPT, r"\text{Static Optimizer}")
x.add_system('static', GROUP, r"\text{Static System Model}")

x.add_system('OPT_dynamic', OPT, r"\text{Dynamic Optimizer}")
x.add_system('dynamic', GROUP, r"\text{ODE or DAE}")

x.connect('dynamic', 'OPT_dynamic', [r"J_\text{dynamic}", r"\bar{g}_0", r"\bar{g}_f", r"\bar{p}"],  label_width=4)
x.connect('OPT_dynamic', 'dynamic', ["t", r"\bar{x}", r"\bar{u}"],  label_width=3)

x.connect('static', 'OPT_static', [r"J_\text{static}", r"g_\text{static}"],  label_width=3)
x.connect('OPT_static', 'static', [r"\bar{d}"],  label_width=3)

x.connect('OPT_static', 'OPT_dynamic', [r'\text{static optimization}', r'\text{outputs}'])
x.connect('OPT_dynamic', 'OPT_static', [r'\text{dynamic optimization}', r'\text{outputs}'])