2017-12-14 8 views
1

私はPython 3.6.2とnumpyで作業しています。より良いアルゴリズムやデータ構造を探して、IDからインデックスへの接続の変換を改善する

私は有限要素モデルと結果を視覚化するコードを書いています。

可視化コードでは、有限要素メッシュのノードと要素をインデックスで識別する必要があります(ゼロから始まり、ギャップなし)。入力モデルはIDに基づいており、ID空間に非常に大きなギャップを持つことがあります。

私はすべてのノードと要素を処理し、IDの代わりにインデックスを使用するように変更しています。

ノードは

です。最初のステップは、ノードとノード座標の配列を処理することです。これはソートされているので、特に座標を使って何もする必要はありません - 節点座標配列のインデックスを使用するだけです。しかし、IDベースではなくインデックスベースになるように要素の接続性を再定義する必要があります。これを行うには

は、Iは

、ノードIDの配列を反復し、次のコードの値

としてキーとその指標として、それはIDだ使用辞書に各ノードを追加することにより、辞書を作成します

  1. model.nodesそのIDによって

  2. nodeCoordsをキーイング、Nodeオブジェクトのすべてを含む辞書である私は視覚化に後で使用するために節点座標を記憶する予め割り当てられnumpyのアレイです。それは私が

  3. nodeIdIndexMapは私がキーとしてノードIDと値

としてnodeCoordsのインデックスを使用して移入辞書である私の要素を再定義するために、後で使用する必要があり、この配列のインデックスですコード:

nodeindex=0 
node_id_index_map={} 
for nid, node in sorted(model.nodes.items()): 
    nodeCoords[nodeIndex] = node.xyz 
    nodeIdIndexMap[nid] = nodeIndex 
    nodeIndex+=1 

それから私は、インデックスを取得し、インデックスとIDを交換し、辞書内の各要素ノードのIDを見上げ、すべての要素を反復処理します。以下のコードの断片で

  1. tet4Elementsは、要素ID
  2. N1、N2、N3およびN4が保持事前に割り当てられnumpyのアレイである使用キーイング、型tet4のすべての要素を含む辞書であります要素ノード
  3. element.nodes [N] .nid要素ノードIDを取得
  4. N1 [tet4Index] = nodeIdIndexMap [element.nodes [0]以前に作成した辞書に要素ノードIDをルックアップ.nid fragmentを返し、対応するインデックスを返し、numpyに格納します配列

コード:

tet4Index = 0 
for eid, element in tet4Elements.items(): 
    id[tet4Index] = eid 
    n1[tet4Index] = nodeIdIndexMap[element.nodes[0].nid] 
    n2[tet4Index] = nodeIdIndexMap[element.nodes[1].nid] 
    n3[tet4Index] = nodeIdIndexMap[element.nodes[2].nid] 
    n4[tet4Index] = nodeIdIndexMap[element.nodes[3].nid] 
    tet4Index+=1 

上記の作品が、それは遅いです......各tet4要素には4つのノードがあり、各ノードIDは辞書で検索されなければならないため、1600,000エントリの辞書で2,600万の辞書検索が行われます。

いくつかの点で私はC++に移動しますが、今、私はPythonでパフォーマンスを向上させるために探しています。

のために、私はパフォーマンスを向上させるための任意のアイデアに感謝でしょう?速くこれを行う方法である。

感謝、

ダグ

+2

あなたは未定義の変数( '' nodeIndex''、 '' tet4Index''、 '' id''、 '' n1''、 '' tet4Elements''などの数を持っています)これにより、あなたのアルゴリズムが何をしようとしているのかを理解することが難しくなります。投稿を編集して[MCVE](https://stackoverflow.com/help/mcve)を提供してください。 – jakevdp

+0

定義されていない変数のいくつかの定義を追加しました – max375

+0

IDの総範囲は何ですか? –

答えて

2

あなたが引用している数字と合理的なハードウェア(8GB RAM)を使って、マッピングを1秒未満で実行できます。悪いニュースは、オブジェクトの元のdictsからデータを取得するには、少なくとも私が作成したモックオブジェクトで60倍長くなることです。

# extract 29.2821946144104 map 0.4702422618865967 

しかし、あなたのノードやテントを一括してクエリする方法がありますか?

コード:

import numpy as np 
from time import time 

def mock_data(nn, nt, idf): 
    nid = np.cumsum(np.random.randint(1, 2*idf, (nn,))) 
    nodes = np.random.random((nn, 3)) 
    import collections 
    node = collections.namedtuple('node', 'nid xyz') 
    tet4 = collections.namedtuple('tet4', 'nodes') 
    nodes = dict(zip(nid, map(node, nid, nodes))) 
    eid = np.cumsum(np.random.randint(1, 2*idf, (nt,))) 
    tet4s = nid[np.random.randint(0, nn, (nt, 4))] 
    tet4s = dict(zip(eid, map(tet4, map(lambda t: [nodes[ti] for ti in t], tet4s)))) 
    return nodes, tet4s 

def f_extract(nodes, tet4s, limit=15*10**7): 
    nid = np.array(list(nodes.keys())) 
    from operator import attrgetter 
    ncoords = np.array(list(map(attrgetter('xyz'), nodes.values()))) 
    tid = np.array(list(tet4s.keys())) 
    tnodes = np.array([[n.nid for n in v.nodes] for v in tet4s.values()]) 
    return nid, ncoords, tid, tnodes, limit 

def f_lookup(nid, ncoords, tid, tnodes, limit): 
    nmx = nid.max() 
    if nmx < limit: 
     nlookup = np.empty((nmx+1,), dtype=np.uint32) 
     nlookup[nid] = np.arange(len(nid), dtype=np.uint32) 
     tnodes = nlookup[tnodes] 
     del nlookup 
    else: 
     nidx = np.argsort(nid) 
     nid = nid[nidx] 
     ncoords = ncoords[nidx] 
     tnodes = nid.searchsorted(tnodes) 
    tmx = tid.max() 
    if tmx < limit: 
     tlookup = np.empty((tmx+1,), dtype=np.uint32) 
     tlookup[tid] = np.arange(len(tid), dtype=np.uint32) 
    else: 
     tidx = np.argsort(tid) 
     tid = tid[tidx] 
     tnodes = tnodes[tidx] 
    return nid, ncoords, tid, tnodes 

data = mock_data(1_600_000, 6_500_000, 16) 
t0 = time() 
data = f_extract(*data) 
t1 = time() 
f_lookup(*data) 
t2 = time() 
print('extract', t1-t0, 'map', t2-t1) 
+0

Paul - このソリューションをありがとう。私のベンチマークの壁時計の時間は18秒から0.4秒に短縮されました...... – max375

+0

また、私が元々示した断片は、元々はノードと要素のデータを辞書に持っていましたが、あなたが指摘したように、私はこれらのデータ構造を1つのモデルインポートパスに対してのみ使用します。より大きいモデルのための私の好ましいアプローチは、hdf5経由でインポートすることです、そして、私はデータをすぐにnumpy配列に取得します。そのため、全体的にインポートが高速です。今やボトルネックはvtkである。 vtkのデータ構造をディスクから(Windowsのファイルシステムのキャッシュ内のウォームスタート、hdf5ファイル)読み込むのに1秒もかかりませんが、レンダリングにはvtkの時間がかかります........ – max375

+0

'pandas.core。アルゴリズム.match'も面白いオプションです。基本的には、「ベクトル化された」ハッシュテーブルのアプローチです。私はこれらのデータはLUTよりも遅いが、バイナリ検索よりも良い方法だと思います。 – user7138814

関連する問題