2017-12-14 2 views
1

저는 파이썬 3.6.2 및 numpy로 작업하고 있습니다.ID에서 인덱스로의 연결 변환을 향상시키는 더 나은 알고리즘 또는 데이터 구조 찾기

유한 요소 모델과 결과를 시각화하는 코드를 작성하고 있습니다.

시각화 코드는 유한 요소 메쉬 노드와 요소가 색인으로 식별되어야하지만 (0으로 시작하고 틈이 없음) 입력 모델은 ID를 기반으로하며 ID 공간에 매우 큰 간격을 가질 수 있습니다.

그래서 모든 노드와 요소를 처리하고 ID 대신 색인을 사용하도록 변경하고 있습니다.

노드는

첫 단계는 노드와 노드 좌표의 배열을 처리하는 것입니다. 이것은 저에게옵니다. 그래서 좌표를 가지고 특별히 아무것도 할 필요가 없습니다 - 저는 꼭지 좌표 배열의 인덱스를 사용합니다. 하지만 ID 기반 대신 인덱스 기반으로 요소의 연결을 재정의해야합니다.

이렇게하려면, I는

을 노드 ID의 배열을 반복하고이 값과 키 인덱스 다음의 코드에

같은 ID를 이용하여 사전에 각 노드를 추가하여 사전을 만들

  1. model.nodes 자신의 ID가

  2. nodeCoords 열쇠 노드의 모든 객체를 포함하는 사전 I 시각화에 나중에 사용하기 위해 노드 좌표를 미리 할당 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는
  2. N1, N2, N3 및 N4는 길게 사전 할당 NumPy와 배열되는 요소 ID를 이용하여 키가 입력 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는 사전에서 조회해야하므로 사전에 1,600,000 개 항목의 사전에서 2,600,000 개의 사전 조회가 이루어집니다.

그래서 질문은 6,500,000 개의 tet4 요소를 처리하는 데 약 16 초가 걸립니다. 내가 C로 이동합니다 ++하지만 지금 내가 파이썬에서 성능을 향상시키기 위해 찾고 있어요 어떤 점에서? 빨리이 작업을 수행하는 방법이다.

어떤 아이디어가 성능을 향상시키기 위해 내가 감사 할 것입니다.

감사합니다 ,

더그

+2

,''tet4Elements'' 등) 이것은 알고리즘이 무엇을 시도 하는지를 이해하기 어렵게 만듭니다. 게시물을 수정하고 [MCVE] (https://stackoverflow.com/help/mcve)를 제공하십시오. – jakevdp

+0

정의되지 않은 변수에 대한 정의가 일부 추가되었습니다. – max375

+0

총 ID 수는 얼마입니까? –

답변

2

인용하고있는 숫자와 합리적인 하드웨어 (8GB RAM)를 사용하면 1 초 내에 매핑을 완료 할 수 있습니다. 나쁜 소식은 객체의 원래 dicts에서 데이터를 가져 오는 것은 내가 만든 mock 객체로 적어도 60 x 길어진다는 것입니다.

# extract 29.2821946144104 map 0.4702422618865967 

하지만 노드와 tets를 일괄 적으로 쿼리하는 방법을 찾을 수 있습니까?

코드 : 당신은`id``,``n1`` 정의되지 않은 변수의 수 (``nodeIndex``,``tet4Index``를,`이

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

또한, 이전에 보여준 프래그먼트는 원래 노드와 요소 데이터를 사전에 가지고 있었고 여러분이 지적했듯이 데이터를 꺼내는 것은 느려질 수 있습니다. 하지만 하나의 모델 가져 오기 경로에 대해서만이 데이터 구조를 사용합니다. 대형 모델에 대한 선호하는 접근 방식은 hdf5를 통해 가져 오는 것입니다. 데이터를 신속하게 가져 와서 전체적으로 가져 오기가 빠릅니다. 이제 병목 현상은 vtk에서 발생합니다. vtk 데이터 구조를 디스크 (웜 스타트, 윈도우 파일 시스템 캐시의 hdf5 파일)에 채우는 데는 1 초도 채 걸리지 않지만 렌더하려면 vtk 25 초가 소요됩니다 ........ – max375

+0

'pandas.core. 알고리즘 .match' 또한 흥미로운 옵션입니다. 기본적으로 "벡터화 된"해시 테이블 접근 방식입니다. 이 데이터는 LUT보다 느리지 만 바이너리 검색보다 좋은 대안이라고 생각합니다. – user7138814

관련 문제