iT邦幫忙

2022 iThome 鐵人賽

DAY 11
0
Software Development

或躍在淵的CAE: 讓咱們用Python會一會ANSA + LS-DYNA系列 第 11

[Day11] - Box Drop Project精進計畫(3) - 建立各Entity的id系統

  • 分享至 

  • xImage
  •  

今天的內容,可能是這個project最精實的部份呀(汗)!

在利用script進行自動化的時候,一個最困難的地方,是如何在新建一個甚至一群Entity的時候,給出適當的id,讓我們後續的script工作能夠更順利進行。

今天我們總共要建立下面幾個function

  • get_ent_ids
  • _grab_id_ranges
  • _filter_id_ranges
  • _grab_filtered_id_range
  • _grab_id_range
  • get_fit_id_range
  • get_id
  • _grab_mix_id_range
  • get_fit_mix_id_range
  • get_mix_id
  • get_mat_prop_id

get_ent_ids

get_ent_ids透過base.CollectEntities來搜集整個ANSA database裡,某一個search_type的全部Entity,然候取出各Entityid,回傳一個經過排序的list

# id_grabbers.py
def get_ent_ids(search_type, deck=None):
    deck = deck or constants.LSDYNA
    ents = base.CollectEntities(deck, None, search_type)
    return sorted(ent._id for ent in ents)

_grab_id_ranges

_grab_id_ranges 接收一個id的集合體叫ids,可以看作是get_ent_ids回傳的list

  • 如果ids是空的,我們就yield (1, 99999999, 99999999),代表當前可用的最小id1,最大id99999999,數量為99999999。如果不是空的話。我們就將ids丟進一個set,預防有重覆id出現的可能。
  • 加入0100000000,方便我們做後續的計算。
  • ids丟回一個list並進行排序。
  • 透過numpydiff去得到ids裡面,每兩個數字的差距,命名為id_diff
  • id_diff打一個迴圈,如果裡面有任何大於1的情況,則代表其最少能夠插入一個id,我們就yield (最小可用id,最大可用id,數量)這個tuple

簡單來說,_grab_id_ranges會lazy的回傳每一個可用的id區間。

# id_grabbers.py
import numpy as np


def _grab_id_ranges(ids):
    max_n = 1_0000_0000
    min_n = 0
    if not ids:
        yield (min_n+1, max_n-1,  max_n - min_n-1)
    else:
        ids = set(ids)
        ids.add(min_n)
        ids.add(max_n)
        ids = sorted(ids)
        id_diff = np.diff(ids)

        for id_, diff_ in zip(ids, id_diff):
            if diff_ > 1:
                yield (id_+1, id_+diff_-1, diff_-1)

_filter_id_ranges

_filter_id_ranges幫助我們去找出可用的id段裡,lazy地回傳可用數量大於req_n的。

# id_grabbers.py
def _filter_id_ranges(req_n, id_ranges):
    for start, end_, n in id_ranges:
        if n >= req_n:
            yield (start, end_)

_grab_filtered_id_range

_grab_filtered_id_range透過_grab_id_ranges得到可用的id ranges,並透過_filter_id_ranges回傳一個大於req_nid range

# id_grabbers.py
def _grab_filtered_id_range(req_n, ids):
    id_ranges = _grab_id_ranges(ids)
    filtered_id_range_iter = _filter_id_ranges(req_n, id_ranges)
    return next(filtered_id_range_iter)

_grab_id_range

_grab_id_range回傳某search_type下,一個大於或等於req_nid_range

# id_grabbers.py
def _grab_id_range(req_n, search_type, deck=None):
    ids = get_ent_ids(search_type, deck)
    return _grab_filtered_id_range(req_n, ids)

get_fit_id_range

get_fit_id_range回傳某search_type下,一個當下可用的fit id_range

# id_grabbers.py
def get_fit_id_range(req_n, search_type, deck=None):
    start, _ = _grab_id_range(req_n, search_type, deck)
    return start, start+req_n

get_id

get_id回傳某search_type下,當下可用的最小id

# id_grabbers.py
def get_id(search_type, deck=None):
    start, _ = get_fit_id_range(1, search_type, deck)
    return start

_grab_mix_id_range

有時候,我們會想對齊兩種不同Entityid,例如一連串相同idmaterialproperty,此時_grab_mix_id_range可以幫助我們。

_grab_mix_id_range回傳同時考慮search_types情況下,一個可用的id range

  • 透過raise_for_not_put_in_a_container檢查search_types是否為iterable
  • 透過get_ent_idsset.union去找出search_types內各種type用過的id
  • 透過_grab_filtered_id_range,回傳適合的id range
# id_grabbers.py
def _grab_mix_id_range(req_n, search_types, deck=None):
    err_msg = f'{search_types=} might not be a suitable iterable.\n\
        Try to put {search_types} in a list first.'
    raise_for_not_put_in_a_container(
        search_types, NotInContainerError, err_msg)

    container = [set(get_ent_ids(type_, deck))
                 for type_ in search_types]
    # Tricky
    ids = sorted(reduce(set.union, container))

    return _grab_filtered_id_range(req_n, ids)

get_fit_mix_id_range

get_fit_id_range回傳某些search_types下,一個當下可用的id_range

# id_grabbers.py
def get_fit_mix_id_range(req_n, search_types, deck=None):
    start, *_ = _grab_mix_id_range(req_n, search_types, deck)
    return start, start+req_n

get_mix_id

get_id回傳某些search_types下,當下可用的最小id

# id_grabbers.py
def get_mix_id(search_types, deck=None):
    start, _ = get_fit_mix_id_range(1, search_types, deck)
    return start

get_mat_prop_id

get_mat_prop_id回傳一個在同時考慮materialproperty情況下的最小可用id。這可以幫助我們在建立Entity時,有同樣的materialproperty id

# id_grabbers.py
def get_mat_prop_id(deck=None):
    search_types = [LSDYNAType.MATERIAL.value, LSDYNAType.PROPERTY.value]
    return get_mix_id(search_types, deck)

Code

本日程式碼傳送門


上一篇
[Day10] - Box Drop Project精進計畫(2) - 建立容易辨識的Entity名
下一篇
[Day12] - Box Drop Project精進計畫(4) - 建立creators
系列文
或躍在淵的CAE: 讓咱們用Python會一會ANSA + LS-DYNA30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言