1

接続コマンドを分割する最良の方法を知りたいです。モジュール化したい 2 つのグループがあります。内側のグループと外側のグループです。内側のグループを、外側のグループのすべての接続を変更することなく、内側のグループを切り替えたり変更したりできる一種のブラック ボックスにしたいと考えています。外側のグループが内側のグループの入力と出力を知る必要があるだけです。例:

import numpy as np
from openmdao.api import Group, Problem, Component, IndepVarComp, ExecComp

class C(Component):
    def __init__(self, n):
        super(C, self).__init__()
        self.add_param('array_element', shape=1)
        self.add_output('new_element', shape=1)

    def solve_nonlinear(self, params, unknowns, resids):
        unknowns['new_element'] = params['array_element']*2.0

class MUX(Component):
    def __init__(self, n):
        super(MUX, self).__init__()
        for i in range(n):
            self.add_param('new_element' + str(i), shape=1)
        self.add_output('new_array', shape=n)
        self.n = n

    def solve_nonlinear(self, params, unknowns, resids):
        new_array = np.zeros(n)
        for i in range(n):
            new_array[i] = params['new_element' + str(i)]
        unknowns['new_array'] = new_array

class GroupInner(Group):
    def __init__(self, n):
        super(GroupInner, self).__init__()
        for i in range(n):
            self.add('c'+str(i), C(n))
            self.connect('array', 'c'+str(i) + '.array_element', src_indices=[i])                
            self.connect('c'+str(i)+'.new_element', 'new_element'+str(i))

        self.add('mux', MUX(n), promotes=['*'])

class GroupOuter(Group):
    def __init__(self, n):
        super(GroupOuter, self).__init__()
        self.add('array', IndepVarComp('array', np.zeros(n)), promotes=['*'])
        self.add('inner', GroupInner(n), promotes=['new_array'])
        for i in range(n):
            # self.connect('array', 'inner.c'+str(i) + '.array_element', src_indices=[i])
            self.connect('array', 'inner.array', src_indices=[i])
n = 3
p = Problem()
p.root = GroupOuter(n)
p.setup(check=False)
p['array'] = np.ones(n)
p.run()

print p['new_array']

コードを実行すると、次のエラーが表示されます。

NameError: Source 'array' cannot be connected to target 'c0.array_element': 'array' does not exist.

これを解決するために、'array' を GroupInner グループの IndepVarComp にしました。ただし、これを行うと、エラーが発生します。

NameError: Source 'array' cannot be connected to target 'inner.array': Target must be a parameter but 'inner.array' is an unknown.

私は完全な接続を確立するだけでよいことを知っています: しかし、私が言ったように、GroupInner は、その中にどのグループやコンポーネントがあるかわからないブラック ボックスのようなものにしたいと考えています。array_elements が異なるため、すべてを昇格させることもできません。これを行うことは可能ですか、それとも接続全体を 1 つのコマンドで行う必要がありますか?

4

1 に答える 1

2

あなたの質問には2つの答えがあります。まず、あなたが指定したように問題を解決します。次に、このモデル構造の一部のアプリケーションでより効率的であると思われる変更を提案します。

まず、あなたが指定した問題の主な問題は次の行でした

            self.connect('array', 'c'+str(i) + '.array_element', src_indices=[i])                

arrayグループ内のどこにも名前が付けられた出力または状態Innerがないため、その接続は機能しません。グループに「配列」という変数を作成しましたが、そのスコープでは使用できないためOuter、定義内から変数への接続を発行できません。Inner指定したとおりに動作させるには、次のようにするのが最も簡単な方法です。

class GroupInner(Group):
def __init__(self, n):
    super(GroupInner, self).__init__()
    for i in range(n):
        self.add('c'+str(i), C(n))
        self.connect('c%d.new_element'%i, 'new_element'+str(i))

    self.add('mux', MUX(n), promotes=['*'])


class GroupOuter(Group):
    def __init__(self, n):
        super(GroupOuter, self).__init__()
        self.add('array', IndepVarComp('array', np.zeros(n)), promotes=['*'])
        self.add('inner', GroupInner(n), promotes=['new_array'])
        for i in range(n):
            self.connect('array', 'inner.c%d.array_element'%i, src_indices=[i])

モデル内の変数とコンポーネントの数を減らす別の方法を次に示しますn。実際の分散コンポーネントを使用し、MPI 通信を使用して配列を分割すると、モデルが大きくなる場合にセットアップ時間を短縮できます。これには、セットアップ コストの節約に加えて、いくつかの優れた特性があります。これにより、計算をより柔軟にスケーリングし、シリアルで実行する際の効率が向上するためです。このソリューションは、モデルに実際に複数のcインスタンスがあり、それらがすべて同じことを行っていて、そのプロセスが numpy を介して単純にベクトル化できる場合にうまく機能します。

import numpy as np
from openmdao.api import Group, Problem, Component, IndepVarComp
from openmdao.util.array_util import evenly_distrib_idxs

from openmdao.core.mpi_wrap import MPI

if MPI:
    # if you called this script with 'mpirun', then use the petsc data passing
    from openmdao.core.petsc_impl import PetscImpl as impl
else:
    # if you didn't use `mpirun`, then use the numpy data passing
    from openmdao.api import BasicImpl as impl


class C(Component):
    def __init__(self, n):
        super(C, self).__init__()
        self.add_param('in_array', shape=n)
        self.add_output('new_array', shape=n)
        self.n = n

    def get_req_procs(self):
        """
        min/max number of procs that this component can use
        """
        return (1,self.n)

    #NOTE: This needs to be setup_distrib_idx for <= version 1.5.0
    def setup_distrib(self):

        comm = self.comm
        rank = comm.rank

        # NOTE: evenly_distrib_idxs is a helper function to split the array
        #       up as evenly as possible
        sizes, offsets = evenly_distrib_idxs(comm.size, self.n)
        local_size, local_offset = sizes[rank], offsets[rank]
        self.local_size = int(local_size)

        start = local_offset
        end = local_offset + local_size

        self.set_var_indices('in_array', val=np.zeros(local_size, float),
            src_indices=np.arange(start, end, dtype=int))
        self.set_var_indices('new_array', val=np.zeros(local_size, float),
            src_indices=np.arange(start, end, dtype=int))

    def solve_nonlinear(self, params, unknowns, resids):
        unknowns['new_array'] = params['in_array']*2.0
        print "computing new_array: ", unknowns['new_array']


class GroupInner(Group):
    def __init__(self, n):
        super(GroupInner, self).__init__()
        self.add('c', C(n), promotes=['new_array', 'in_array'])


class GroupOuter(Group):
    def __init__(self, n):
        super(GroupOuter, self).__init__()
        self.add('array', IndepVarComp('array', np.zeros(n)), promotes=['*'])
        self.add('inner', GroupInner(n), promotes=['new_array',])
        self.connect('array', 'inner.in_array')
n = 3
p = Problem(impl=impl)
p.root = GroupOuter(n)
p.setup(check=False)
p['array'] = np.ones(n)
p.run()

print p['new_array']
于 2016-02-02T23:17:31.103 に答える