def setMeshData(self, data): # 'vertices': array([[x, y],...]) verts = data['vertices'] # 'segments': array([[NodeID1, NodeID2], ...], dtype=int32) # 'vertex_markers': array([[0],...], dtype=int32) verts_marker = data['vertex_markers'] #'triangles': array([[NodeID1, NodeID2, NodeID3],...], dtype=int32) tris = data['triangles'] #'triangle_attribute': array([[RegionID],...]) tris_attr = data['triangle_attribute'] # 'regions': array([[x, y, RegionID, Area],...]) regions = data['regions'] # make FE Nodes data for i, vert in enumerate(verts): self.FE_Nodes_[i] = {'point': vert, 'marker': int(verts_marker[i])} # make FE Elements data for i, tri in enumerate(tris): dim = len(tri) self.FE_Elements_[i] = { 'dim': dim, 'nodes': tri, 'J': 0, 'mu_x': 1, 'mu_y': 1, 'Mx': 0, 'My': 0, 'regionID': int(tris_attr[i]), 'A': np.zeros((dim, dim)), 'b': np.zeros(dim), 's': np.zeros(dim) } # make FE Regions data for region in regions: headNodeID = int(region[2]) head = bzmag.getObject(headNodeID) material = head.Material if material == None: materialID = -1 else: materialID = material.getID() #print('make material', materialID) regionID = region[2] if regionID not in self.FE_Regions_: self.FE_Regions_[regionID] = { 'sourceID': 0, 'materialID': materialID } #print('FE Region:',self.FE_Regions_) [bh, b2v] = self.loadBHCurve('35PN210_BH.tab') self.FE_Materials_[2] = [bh, b2v]
def addItem(self, nodeID): #print("Add Item in the ViewCanvas") node = bzmag.getObject(nodeID) # make a map for GeomBaseNode to its refered CS ID if 'GeomBaseNode' in node.getGenerations(): cs = node.CoordinateSystem csID = -1 if cs != None: csID = cs.getID() self.GeomNodeToReferedCS_[nodeID] = csID # make a GraphicItem for the HeadNode and # make a map for GeomHeadNode ID to GraphicItem if 'GeomHeadNode' == node.getTypeName() and node.IsStandAlone: print('Object is Added') if node.isCovered(): item = SurfaceArtist(self) self.HeadNodeToItem_[nodeID] = item item.setNode(node) else: item = SurfaceArtist(self) self.HeadNodeToItem_[nodeID] = item item.setNode(node) # make a map for CSNode ID to GraphicItem if 'CSNode' == node.getTypeName(): print('CS is Added') item = CSArtist(self) self.CSNodeToItem_[nodeID] = item item.setNode(node) item.hide() self.draw()
def updateCSNodeItem(self, nodeID, showCS): node = bzmag.getObject(nodeID) item = self.CSNodeToItem_[nodeID] item.setNode(node) for geomID, csID in self.GeomNodeToReferedCS_.items(): if csID == nodeID: self.updateItem(geomID, showCS)
def nodesSelected(self, nodeIDs): self.prop_browser.clear() nodeID = nodeIDs.last() if nodeID == None: return node = bzmag.getObject(nodeID) if node == None: self.selectedNode_ = None self.line_path.setText('') return path = node.getAbsolutePath() #self.CS_.clear() self.EnumToCSID_.clear() self.CSIDtoEnum_.clear() self.CSNames_.clear() self.EnumToMatID_.clear() self.MatIDtoEnum_.clear() self.MatNames_.clear() cs_root = bzmag.get('/coordinate') self.build_ObjectItem(cs_root, self.CSIDtoEnum_, self.EnumToCSID_, self.CSNames_, 'Global') mat_root = bzmag.get('/material') self.build_ObjectItem(mat_root, self.MatIDtoEnum_, self.EnumToMatID_, self.MatNames_, 'Vaccum') if path == '' : path = '/' self.line_path.setText(path) self.line_path.setReadOnly(True) #print('Binding node path', path) #node = bzmag.get(path) self.selectedNodeID_ = nodeID for type_name in node.getGenerations(): group = self.groupManager.addProperty(type_name) prop_names = node.getPropertyNames(type_name) if not prop_names: continue for prop_name in prop_names: prop_name, prop_value, prop_type, readonly = \ node.getProperty(prop_name) #print(prop_name, prop_value, prop_type, readonly) self.add_property(group, prop_name, prop_value, prop_type, readonly) #print('Property Browse : Add Property...', group) self.prop_browser.addProperty(group)
def nodesSelected(self, nodeIDs): # Previous selected items are removed from the scene #print('View Widget, Selected Nodes:', nodeIDs, self.selectedNodeIDs_) for nodeID in self.selectedNodeIDs_: node = bzmag.getObject(nodeID) if 'CSNode' == node.getTypeName(): item = self.CSNodeToItem_[nodeID] item.hide() if 'GeomBaseNode' in node.getGenerations(): csID = self.GeomNodeToReferedCS_[nodeID] if csID != -1: item = self.CSNodeToItem_[csID] item.hide() if 'GeomHeadNode' == node.getTypeName() and node.IsStandAlone: item = self.HeadNodeToItem_[nodeID] item.setSelected(False) # Current selected items are added to the scene for nodeID in nodeIDs: node = bzmag.getObject(nodeID) if 'CSNode' == node.getTypeName(): item = self.CSNodeToItem_[nodeID] item.show() if 'GeomBaseNode' in node.getGenerations(): csID = self.GeomNodeToReferedCS_[nodeID] if csID != -1: item = self.CSNodeToItem_[csID] item.show() if 'GeomHeadNode' == node.getTypeName() and node.IsStandAlone: item = self.HeadNodeToItem_[nodeID] item.setSelected(True) self.selectedNodeIDs_ = nodeIDs self.draw()
def updateGeomBaseNodeItem(self, nodeID, showCS): # Hide CS Artist of the previous node from the canvas prev_csID = self.GeomNodeToReferedCS_[nodeID] if prev_csID != -1 and showCS: item = self.CSNodeToItem_[prev_csID] item.hide() node = bzmag.getObject(nodeID) # Update referred CoordinateSystem of the GeomNode csID = -1 cs = node.CoordinateSystem if cs != None: csID = cs.getID() self.GeomNodeToReferedCS_[nodeID] = csID if csID != -1 and showCS: item = self.CSNodeToItem_[csID] item.show() # Find HeadNode if 'GeomHeadNode' == node.getTypeName(): hn = node else: hn = node.getHeadNode() if hn == None: return # When the HeadNode is not standard alone node # ex) it is referred by boolean node if hn.IsStandAlone == False: parent = hn.getParent() self.updateItem(parent.getID(), False) # Update Top Level HeadNode else: item = self.HeadNodeToItem_[hn.getID()] if item != None: item.setNode(hn) if hn.IsHide == True: item.hide() else: item.show() # Update CloneFromNode while node != None: n = None for n in node.getChildren(): if n.getTypeName() == 'GeomCloneToNode': for o in n.getClonedNodes(): parent = o.getParent() self.updateItem(parent.getID(), False) node = n
def updateItem(self, nodeID, showCS=True): #print('View Widget, Update Node:', nodeID) if nodeID == -1: return # get bzmag Node Object by its ID node = bzmag.getObject(nodeID) # Update GeomNode and related GeomNodes if 'GeomBaseNode' in node.getGenerations(): self.updateGeomBaseNodeItem(nodeID, showCS) # Update CS node and related GeomNodes if 'CSNode' == node.getTypeName(): self.updateCSNodeItem(nodeID, showCS) self.draw()
def valueChanged(self, property, value): if self.selectedNodeID_ == -1: return nodeID = self.selectedNodeID_ node = bzmag.getObject(nodeID) prop_name = property.propertyName() prop_name, prop_value, prop_type, readonly = node.getProperty(prop_name) #print(prop_name, prop_value, prop_type, readonly) # when type of the value is 'QColor', make value as '[r, g, b, a]' #if type(value).__name__ == 'QColor': if prop_type == 'color': value = '{}, {}, {}, {}'.format(value.red(), value.green(), \ value.blue(), value.alpha()) if prop_type == 'node': #print('Node value changed : ', value) #if value in self.EnumToCSID_.keys(): #value = self.EnumToCSID_[value] if prop_name == 'CoordinateSystem': value = self.EnumToCSID_[value] elif prop_name == 'Material': value = self.EnumToMatID_[value] # when the node is not readonly , update the property value if not readonly: #print(node, prop_name, str(value)) node.setProperty(str(prop_name), str(value)) # when the property is 'name' update NOHTree and Node Path if prop_name == 'name': path = node.getAbsolutePath() self.nameUpdated.emit(nodeID) self.line_path.setText(path) self.itemUpdated.emit(nodeID)
def nodesSelected(self, nodeIDs): #print('NOH Tree, Selected Nodes1:', nodeIDs, self.selectedNodeIDs_) self.directSelection_ = False self.unselectItemAllItem() if nodeIDs in self.selectedNodeIDs_: return #print('NOH Tree, Selected Nodes2:', nodeIDs, self.selectedNodeIDs_) for nodeID in nodeIDs: if nodeID == None: pass node = bzmag.getObject(nodeID) item = self.GeomNodeIdToItem_[node.getID()] item.setSelected(True) while item.parent() != None: item.parent().setExpanded(True) item = item.parent() self.directSelection_ = True #self.selectedNodeIDs_ = nodeIDs self.changeSelectedNode()
def makeElementEquation(self): mu0 = 4 * np.pi * 1e-7 print('------------------------------------') print(' Generating of the Element Matrices ') print('------------------------------------') for e in self.FE_Elements_.values(): #print('------------------------------------') #print(' Gathering Element the Properties ') #print('------------------------------------') # 요소의 재질데이터 가져오기 regionID = e['regionID'] headNode = bzmag.getObject(regionID) region = self.FE_Regions_[regionID] sourceID = region['sourceID'] materialID = region['materialID'] # 초기값(materialID가 -1일때) mu_x = mu0 mu_y = mu0 Mx = 0 My = 0 bh = None b2v = None # 참조하는 재질이 있으면 셋팅함 if materialID != -1: # 재질 데이터 가져오기 matNode = bzmag.getObject(int(materialID)) # 투자율 설정 mur_x = float(matNode.Permeability) mur_y = float(matNode.Permeability) mu_x = mu0 * mur_x mu_y = mu0 * mur_y if mur_x > 1000: [bh, b2v] = self.FE_Materials_[2] # 자화설정 Magnetization = float(matNode.Magnetization) if Magnetization > 0: sMx, sMy = matNode.Mvector Mx = float(sMx) My = float(sMy) uMx = Mx / math.sqrt(Mx * Mx + My * My) uMy = My / math.sqrt(Mx * Mx + My * My) Mx = Magnetization * uMx My = Magnetization * uMy # 영역이 참조하는 좌표계를 적용한다 cs = headNode.CoordinateSystem m11, m12, m13, m21, m22, m23 = cs.getTransformation() mtx = np.array([[m11, m12, 0], [m21, m22, 0], [0, 0, 1]]) refcs = Affine2D(matrix=mtx) Mx, My = refcs.transform((Mx, My)) #print(mu_x, mu_y, Mx, My) # 소스 가져오기 --> 추후 구현 J = 0 # 요소를 이루는 절점 ID 가져오기 nodeIDs = e['nodes'] # 추후 어셈블리 시 노드 ID가 필요함 # 노드 ID를 어셈블리 시 행렬 인덱스와 일치시킬 예정임 # 참고) 추후 주기경계조건 처리를 해야하는 경우 주기경계 상의 노드 절점은 따로 처리되므로 # Master/Slave 상의 노드 중 Slave 노드가 Master 노드로 맵핑됨 # 결국 Assembly 시 Slave 노드는 존재하지 않는 노드가 되므로 # 이들은 행렬 인덱스상 가장 마지막에 위치해야 편리함 (아닐지도 모르고...;;) # 2019.08.19 # 요소 형태 알아내기(절점의 수로 알아냄) dim = len(nodeIDs) # 요소 속성 저장 e['dim'] = dim e['J'] = J e['mu'] = [mu_x, mu_y] e['M'] = [Mx, My] e['bh'] = bh e['b2v'] = b2v #print('-------------------------------') #print(' Calculating Element Maxtrix ') #print('-------------------------------') # 요소절점의 좌표 얻기 x = np.zeros(dim) y = np.zeros(dim) for j, nodeID in enumerate(nodeIDs): # 노드 ID를 얻고 node = self.FE_Nodes_[nodeID] # 요소 노드 좌표 x[j], y[j] = node['point'] # 겔러킨법의 적용 (요소방정식) # 미분방정식 : "div(v gradA) + J = 0" # 여기서 v는 상수 (v는 텐서일 수 있음 -> 이 경우 수식전개 동일한지 고려해 봐야함) # A는 미지수(자기벡터 포텐셜) # J는 소스 항 (전류밀도) # 상기 미분방정식에 겔러킨법 적용함 (가중함수를 이용한 적분이 필요함) # 1) 정식화 (예, 첫번째 항) # ∫_global{grad(Nt)·v grad(N)A} dxdy # = ∫_local{grad(Nt)·v grad(N)A det(J)} dudv # 2) 수치적분 (가우스 르장드르 적분 적용) # ∫(K(u)) du = ∑wi K(ui) #s = np.zeros(dim) # source #A = np.zeros((dim,dim)) # stiffiness matrix #b = np.zeros(dim) # unknown s = np.zeros(dim) # source A = np.zeros((dim, dim)) # stiffiness matrix b = np.zeros(dim) # unknown # get integration points and corresponding weights [ui, vi, wi] = self.get_integration_weight(dim) # do integration for i, w in enumerate(wi): u = ui[i] v = vi[i] [N, dNdu, dNdv, detJ, dNdx, dNdy] = self.derivatives_of_shape_functions(u, v, x, y, dim) ''' for j in range(dim): #source term b[j] = b[j] + N[j]*J*detJ*w # stiffiness matrix for k in range(dim): A[j,k] = A[j,k] + (1.0/mu_x*dNdx[j]*dNdx[k] + 1.0/mu_y*dNdy[j]*dNdy[k])*detJ*w ''' Nt = np.transpose(N) gradN = np.array([dNdx, dNdy]) gradNt = np.transpose(gradN) mu = np.array([[mu_y, 0], [0, mu_x]]) # 투자율 텐서 ; y, x 순서 주의! inv_mu = np.linalg.inv(mu) M = np.array([My / mu_y, -Mx / mu_x]) # 자화벡터 ; 좌측 y, x 순서 및 부호 주의! # stiffiness matrix A = A + np.matmul(gradNt, np.matmul(inv_mu, gradN)) * detJ * w # source term (Current Density and Magnetization) b = b + (Nt * J - np.dot(gradNt, M)) * detJ * w #AA = NR_Jacobian(A, b, # 계산결과 저장 e['A'] = A e['b'] = b ''' print(A) print(b) #print(c) #return # 하기는 1차 삼각형 요소기반 글로벌 좌표계에서 정식화한 수식으로 Stiffiness 행렬을 구해 본 것 # 상기 결과와 동일함 # 요소면적 delta = (x[0]*y[1] + x[1]*y[2] + x[2]*y[0] - (y[0]*x[1] + y[1]*x[2] + y[2]*x[0])) / 2.0 # 계수 행렬을 위한 계수들 계산 a = np.zeros(3) a[0] = x[1]*y[2] - x[2]*y[1] a[1] = x[2]*y[0] - x[0]*y[2] a[2] = x[0]*y[1] - x[1]*y[0] b = np.zeros(3) b[0] = y[1] - y[2] b[1] = y[2] - y[0] b[2] = y[0] - y[1] c = np.zeros(3) c[0] = x[2] - x[1] c[1] = x[0] - x[2] c[2] = x[1] - x[0] # 계수행렬 만들기 K = np.zeros((3,3)) K[0,0] = ( (1.0/mu_y * b[0] * b[0]) + (1.0/mu_x * c[0] * c[0]) ) / ( 4.0 * delta ) K[0,1] = ( (1.0/mu_y * b[0] * b[1]) + (1.0/mu_x * c[0] * c[1]) ) / ( 4.0 * delta ) K[0,2] = ( (1.0/mu_y * b[0] * b[2]) + (1.0/mu_x * c[0] * c[2]) ) / ( 4.0 * delta ) K[1,0] = ( (1.0/mu_y * b[1] * b[0]) + (1.0/mu_x * c[1] * c[0]) ) / ( 4.0 * delta ) K[1,1] = ( (1.0/mu_y * b[1] * b[1]) + (1.0/mu_x * c[1] * c[1]) ) / ( 4.0 * delta ) K[1,2] = ( (1.0/mu_y * b[1] * b[2]) + (1.0/mu_x * c[1] * c[2]) ) / ( 4.0 * delta ) K[2,0] = ( (1.0/mu_y * b[2] * b[0]) + (1.0/mu_x * c[2] * c[0]) ) / ( 4.0 * delta ) K[2,1] = ( (1.0/mu_y * b[2] * b[1]) + (1.0/mu_x * c[2] * c[1]) ) / ( 4.0 * delta ) K[2,2] = ( (1.0/mu_y * b[2] * b[2]) + (1.0/mu_x * c[2] * c[2]) ) / ( 4.0 * delta ) # 구동벡터 만들기 f = np.zeros(3) f[0] = (J * delta / 3.0) + (( (c[0] * Mx/mu_x) - (b[0] * My/mu_y) ) / (2.0)) f[1] = (J * delta / 3.0) + (( (c[1] * Mx/mu_x) - (b[1] * My/mu_y) ) / (2.0)) f[2] = (J * delta / 3.0) + (( (c[2] * Mx/mu_x) - (b[2] * My/mu_y) ) / (2.0)) print(K) print(f) return ''' return
def makeElementEquation(self): mu0 = 4 * np.pi * 1e-7 flagStop = False print('------------------------------------') print(' Generating the Element Matrices ') print('------------------------------------') #print('Number of Elements:', len(self.FE_Elements_)) for e in self.FE_Elements_.values(): # 요소의 재질데이터 가져오기 regionID = e['regionID'] headNode = bzmag.getObject(regionID) region = self.FE_Regions_[regionID] sourceID = region['sourceID'] materialID = region['materialID'] # ---------------------------------------------------------------- # 재질 설정 # 참조하는 재질이 있으면 셋팅함 mat = self.FE_Materials_[int(materialID)] # 투자율 설정 # 실제로 이방성 재질을 고려하게끔 수식을 유도했으나, # 프로그램에서 아직 이방성 재질을 설정할 수 있도록 만들어지지 않아 # 이방성 재질에 대한 수식을 사용하되 nur_x 와 nur_y 가 같게 설정한다 # --> 즉 등방성 재질을 사용한 경우의 해석이다 nu = 1 / (mat['mur'] * mu0) #nu_x = nu #nu_y = nu # BH데이터 설정 BH = mat['BH'] # x축 B, y축 H B2v = mat['B2v'] # x축 B^2, y축 v # 자화설정 Mx = 0 My = 0 Magnetization = mat['M'] if Magnetization > 0: vMx, vMy = mat['dirM'] vM = math.sqrt(vMx * vMx + vMy * vMy) uMx = vMx / vM uMy = vMy / vM Mx = Magnetization * uMx My = Magnetization * uMy # 영역이 참조하는 좌표계를 적용한다 cs = headNode.CoordinateSystem m11, m12, m13, m21, m22, m23 = cs.getTransformation() mtx = np.array([[m11, m12, 0], [m21, m22, 0], [0, 0, 1]]) refcs = Affine2D(matrix=mtx) Mx, My = refcs.transform((Mx, My)) # ---------------------------------------------------------------- # 소스 설정 # 소스 가져오기 --> 추후 구현 J = 0 # ---------------------------------------------------------------- # 요소방정식 생성 # 요소를 이루는 절점 ID 가져오기 nodeIDs = e['nodes'] # 추후 어셈블리 시 노드 ID가 필요함 # 노드 ID를 어셈블리 시 행렬 인덱스와 일치시킬 예정임 # 참고) 추후 주기경계조건 처리를 해야하는 경우 주기경계 상의 노드 절점은 따로 처리되므로 # Master/Slave 상의 노드 중 Slave 노드가 Master 노드로 맵핑됨 # 결국 Assembly 시 Slave 노드는 존재하지 않는 노드가 되므로 # 이들은 행렬 인덱스상 가장 마지막에 위치해야 편리함 (아닐지도 모르고...;;) # 2019.08.19 # 요소 형태 알아내기(절점의 수로 알아냄) dim = len(nodeIDs) # 반복법에 있어 이전 반복의 A(미지수, 벡터포텐셜) 값을 0으로 초기화 A_prev = np.zeros(dim) # 소스항 0으로 초기화 Q = np.zeros(dim) # 요소절점의 좌표 얻기 x = np.zeros(dim) y = np.zeros(dim) for j, nodeID in enumerate(nodeIDs): # 노드 ID를 얻고 node = self.FE_Nodes_[nodeID] # 요소 노드 좌표 (단위 변환을 위해 1e-3 곱해줌; mm->m) x[j], y[j] = node['point'] * 1e-3 # 반복법에 있어, 한번이라도 반복이 발생한 경우에는 # 이전 연산에서의 벡터포텐셜이 self.A_에 저장되어 있음(즉, 크기가 0보다 큼) if len(self.A_) > 0: A_prev[j] = self.A_[nodeID] else: A_prev[j] = 0 # 겔러킨법의 적용 (요소방정식) # 미분방정식 : "div(v gradA) + J = 0" # 여기서 v는 상수 (v는 텐서일 수 있음 -> 이 경우 수식전개 동일한지 고려해 봐야함) # A는 미지수(자기벡터 포텐셜) # J는 소스 항 (전류밀도) # 상기 미분방정식에 겔러킨법 적용함 (가중함수를 이용한 적분이 필요함) # 1) 정식화 (예, 첫번째 항) # ∫_global{grad(Nt)·v grad(N)A} dxdy # = ∫_local{grad(Nt)·v grad(N)A det(J)} dudv # 2) 수치적분 (가우스 르장드르 적분 적용) # ∫(K(u)) du = ∑wi K(ui) #s = np.zeros(dim) # source #A = np.zeros((dim,dim)) # stiffiness matrix #b = np.zeros(dim) # unknown #A = np.zeros(dim) # current unknown SS = np.zeros((dim, dim)) # stiffiness matrix SS1 = np.zeros((dim, dim)) # stiffiness matrix sub1 ; 본래 계수행렬 #SS11= np.zeros((dim,dim)) # stiffiness matrix sub1 ; 본래 계수행렬 SS2 = np.zeros( (dim, dim)) # stiffiness matrix sub2 ; NR 법을 위한 미분항 계수행렬 #SS22= np.zeros((dim,dim)) # stiffiness matrix sub2 ; NR 법을 위한 미분항 계수행렬 # get integration points and corresponding weights [ui, vi, wi] = self.get_integration_weight(dim) # do integration for i, w in enumerate(wi): u = ui[i] v = vi[i] [N, dNdu, dNdv, detJ, dNdx, dNdy] = self.derivatives_of_shape_functions(u, v, x, y, dim) Nt = np.transpose(N) gradN = np.array([dNdx, dNdy]) gradNt = np.transpose(gradN) # Flux density # [Bx, By] = Curl(NA) Bx = np.matmul(dNdy, A_prev) By = -np.matmul(dNdx, A_prev) B2 = Bx**2 + By**2 absB = np.sqrt(B2) # BH커브 존재시 투자율의 역수 (nu)을 구한다 if BH != None: # B가 0인 경우에는 H도 0이기 때문에 H/B로 nu를 구할수 없다 # 그래서 B가 아주 작은 값일때의 nu를 구한다 #absBx = np.abs(Bx) #if absBx == 0: nu_x = BH(0.00001) / 0.00001 #else : nu_x = BH(absBx) / absBx #absBy = np.abs(By) #if absBx == 0: nu_y = BH(0.00001) / 0.00001 #else : nu_y = BH(absBy) / absBy if absB == 0: nu = BH(0.00001) / 0.00001 else: nu = BH(absB) / absB # 비선형 해석을 위해서는 dv/dB2 이 필요함 # 선형 재질일때는 dv/dB2 = 0이다 #dvdB2x = 0 #dvdB2y = 0 dvdB2 = 0 if B2v != None: #dvdB2x = fp(B2v, Bx**2) #dvdB2y = fp(B2v, By**2) dvdB2 = fp(B2v, B2) # v-B2 그래프는 단조증가함수이어야 한다! 해의 수렴을 위하여~! if dvdB2 < 0: print('dvdB2 should be positive value!!, B:', Bx, By, B2) ''' # 이하 for문을 사용하지 않고 행렬 연산으로 한번에 계산할 수 있는지 고민해야 함! for n in range(dim): # stiffiness matrix Exn = -dNdx[n] * By Eyn = dNdy[n] * Bx for m in range(dim): Exm = -dNdx[m] * By Eym = dNdy[m] * Bx SS1[n][m] = SS1[n][m] + (((nu*dNdx[n]*dNdx[m]) + (nu*dNdy[n]*dNdy[m])) * detJ*w) # 아래 항은 좀 고민해 봐야 함 # x,y성분으로 나누긴 했는데... # 교과서에서는 성분을 나누지 않고 |B| 의 값으로 계산함 SS2[n][m] = SS2[n][m] + ((2*dvdB2*(Exn+Eyn)*(Exm+Eym))* detJ*w) # 이하 이방성을 고려한 수식인데...뭔가 좀 이상함 #SS1[n][m] = SS1[n][m] + ((nu_x*dNdx[n]*dNdx[m]) + \ # (nu_y*dNdy[n]*dNdy[m])) * detJ*w # 아래 항은 좀 고민해 봐야 함 # x,y성분으로 나누긴 했는데... # 교과서에서는 성분을 나누지 않고 |B| 의 값으로 계산함 #SS2[n][m] = SS2[n][m] + ((2*dvdB2y*Exn*Exm) + \ # (2*dvdB2x*Eyn*Eym)) * detJ*w ''' #SS11 = SS11 + np.matmul(gradNt, np.matmul(inv_mu, gradN)) * detJ*w SS1 = SS1 + np.matmul(gradNt, nu * gradN) * detJ * w Ex = -dNdx * By Ey = dNdy * Bx E = Ex + Ey ff = np.outer(E, E.T) SS2 = SS2 + ((2 * dvdB2 * ff) * detJ * w) # source term (Current Density and Magnetization) M = np.array([nu * My, -nu * Mx]) # 자화벡터 ; 좌측 y, x 순서 및 부호 주의! # 소스항 벡터 Q = Q + (Nt * J - np.dot(gradNt, M)) * detJ * w # the component of the right-hand side depending on the potentials Q = Q - np.matmul(SS1, A_prev) #if Magnetization > 0: if mat['mur'] > 1000: if not flagStop: print('B', Bx, By) print('A', A_prev) print('nu', nu) print('dvdB2', dvdB2) print('Q', Q) print('SS1', SS1) print('SS2', SS2) flagStop = True # 요소 속성 저장 e['dim'] = dim e['J'] = J e['nu'] = [nu, nu] e['M'] = [Mx, My] e['BH'] = BH e['B2v'] = B2v # 요소방정식 계수행렬 및 소스 벡터 저장 e['SS'] = SS1 + SS2 e['SS1'] = SS1 e['SS2'] = SS2 e['Q'] = Q ''' # 하기는 1차 삼각형 요소기반 글로벌 좌표계에서 정식화한 수식으로 Stiffiness 행렬을 구해 본 것 # 상기 결과와 동일함 # 요소면적 delta = (x[0]*y[1] + x[1]*y[2] + x[2]*y[0] - (y[0]*x[1] + y[1]*x[2] + y[2]*x[0])) / 2.0 # 계수 행렬을 위한 계수들 계산 a = np.zeros(3) a[0] = x[1]*y[2] - x[2]*y[1] a[1] = x[2]*y[0] - x[0]*y[2] a[2] = x[0]*y[1] - x[1]*y[0] b = np.zeros(3) b[0] = y[1] - y[2] b[1] = y[2] - y[0] b[2] = y[0] - y[1] c = np.zeros(3) c[0] = x[2] - x[1] c[1] = x[0] - x[2] c[2] = x[1] - x[0] # 자속밀도 구하기 By = -(A_prev[0]*b[0]+A_prev[1]*b[1]+A_prev[2]*b[2]) / (2*delta) Bx = (A_prev[0]*c[0]+A_prev[1]*c[1]+A_prev[2]*c[2]) / (2*delta) # BH커브 존재시 투자율의 역수 (nu)을 구한다 if BH != None: # B가 0인 경우에는 H도 0이기 때문에 H/B로 기울기를 구할수 없다 # 그래서 미분값을 사용한다 absBx = np.abs(Bx) if absBx == 0 : nu_x = BH.derivative(1)(0) else : nu_x = BH(absBx) / absBx absBy = np.abs(By) if absBy == 0 : nu_y = BH.derivative(1)(0) else : nu_y = BH(absBy) / absBy #flagStop = True if not flagStop: flagStop = True dvdB2x = 0 dvdB2y = 0 if B2v != None: df1 = B2v.derivative(1) dvdB2x = df1(Bx**2) dvdB2y = df1(By**2) # 계수행렬 만들기 Kx = np.zeros((3,3)) Kx[0,0] = ( (c[0] * c[0]) ) Kx[0,1] = ( (c[0] * c[1]) ) Kx[0,2] = ( (c[0] * c[2]) ) Kx[1,0] = ( (c[1] * c[0]) ) Kx[1,1] = ( (c[1] * c[1]) ) Kx[1,2] = ( (c[1] * c[2]) ) Kx[2,0] = ( (c[2] * c[0]) ) Kx[2,1] = ( (c[2] * c[1]) ) Kx[2,2] = ( (c[2] * c[2]) ) Ky = np.zeros((3,3)) Ky[0,0] = ( (b[0] * b[0]) ) Ky[0,1] = ( (b[0] * b[1]) ) Ky[0,2] = ( (b[0] * b[2]) ) Ky[1,0] = ( (b[1] * b[0]) ) Ky[1,1] = ( (b[1] * b[1]) ) Ky[1,2] = ( (b[1] * b[2]) ) Ky[2,0] = ( (b[2] * b[0]) ) Ky[2,1] = ( (b[2] * b[1]) ) Ky[2,2] = ( (b[2] * b[2]) ) # NR법을 위한 추가분 dBx2dA = np.zeros(3) dBx2dA[0] = (2*c[0]*Bx) / (4*delta) dBx2dA[1] = (2*c[1]*Bx) / (4*delta) dBx2dA[2] = (2*c[2]*Bx) / (4*delta) dBy2dA = np.zeros(3) dBy2dA[0] = -(2*b[0]*By) / (4*delta) dBy2dA[1] = -(2*b[1]*By) / (4*delta) dBy2dA[2] = -(2*b[2]*By) / (4*delta) KAx = np.zeros(3) KAx[0] = Kx[0,0]*A_prev[0]+Kx[0,1]*A_prev[1]+Kx[0,2]*A_prev[2] KAx[1] = Kx[1,0]*A_prev[0]+Kx[1,1]*A_prev[1]+Kx[1,2]*A_prev[2] KAx[2] = Kx[2,0]*A_prev[0]+Kx[2,1]*A_prev[1]+Kx[2,2]*A_prev[2] KAy = np.zeros(3) KAy[0] = Ky[0,0]*A_prev[0]+Ky[0,1]*A_prev[1]+Ky[0,2]*A_prev[2] KAy[1] = Ky[1,0]*A_prev[0]+Ky[1,1]*A_prev[1]+Ky[1,2]*A_prev[2] KAy[2] = Ky[2,0]*A_prev[0]+Ky[2,1]*A_prev[1]+Ky[2,2]*A_prev[2] dKx = np.zeros((3,3)) dKx[0,0] = KAx[0] * dBx2dA[0] dKx[0,1] = KAx[0] * dBx2dA[1] dKx[0,2] = KAx[0] * dBx2dA[2] dKx[1,0] = KAx[1] * dBx2dA[0] dKx[1,1] = KAx[1] * dBx2dA[1] dKx[1,2] = KAx[1] * dBx2dA[2] dKx[2,0] = KAx[2] * dBx2dA[0] dKx[2,1] = KAx[2] * dBx2dA[1] dKx[2,2] = KAx[2] * dBx2dA[2] dKy = np.zeros((3,3)) dKy[0,0] = KAy[0] * dBy2dA[0] dKy[0,1] = KAy[0] * dBy2dA[1] dKy[0,2] = KAy[0] * dBy2dA[2] dKy[1,0] = KAy[1] * dBy2dA[0] dKy[1,1] = KAy[1] * dBy2dA[1] dKy[1,2] = KAy[1] * dBy2dA[2] dKy[2,0] = KAy[2] * dBy2dA[0] dKy[2,1] = KAy[2] * dBy2dA[1] dKy[2,2] = KAy[2] * dBy2dA[2] KK = np.zeros((3,3)) KK[0,0] = ((nu_x*Kx[0,0] + nu_y*Ky[0,0]) + (dvdB2x*dKx[0,0] + dvdB2y*dKy[0,0])) / (4*delta) KK[0,1] = ((nu_x*Kx[0,1] + nu_y*Ky[0,1]) + (dvdB2x*dKx[0,1] + dvdB2y*dKy[0,1])) / (4*delta) KK[0,2] = ((nu_x*Kx[0,2] + nu_y*Ky[0,2]) + (dvdB2x*dKx[0,2] + dvdB2y*dKy[0,2])) / (4*delta) KK[1,0] = ((nu_x*Kx[1,0] + nu_y*Ky[1,0]) + (dvdB2x*dKx[1,0] + dvdB2y*dKy[1,0])) / (4*delta) KK[1,1] = ((nu_x*Kx[1,1] + nu_y*Ky[1,1]) + (dvdB2x*dKx[1,1] + dvdB2y*dKy[1,1])) / (4*delta) KK[1,2] = ((nu_x*Kx[1,2] + nu_y*Ky[1,2]) + (dvdB2x*dKx[1,2] + dvdB2y*dKy[1,2])) / (4*delta) KK[2,0] = ((nu_x*Kx[2,0] + nu_y*Ky[2,0]) + (dvdB2x*dKx[2,0] + dvdB2y*dKy[2,0])) / (4*delta) KK[2,1] = ((nu_x*Kx[2,1] + nu_y*Ky[2,1]) + (dvdB2x*dKx[2,1] + dvdB2y*dKy[2,1])) / (4*delta) KK[2,2] = ((nu_x*Kx[2,2] + nu_y*Ky[2,2]) + (dvdB2x*dKx[2,2] + dvdB2y*dKy[2,2])) / (4*delta) # 구동벡터 만들기 f = np.zeros(3) f[0] = (J * delta / 3.0) + (( (c[0] * Mx*nu_x) - (b[0] * My*nu_y) ) / (2.0)) f[1] = (J * delta / 3.0) + (( (c[1] * Mx*nu_x) - (b[1] * My*nu_y) ) / (2.0)) f[2] = (J * delta / 3.0) + (( (c[2] * Mx*nu_x) - (b[2] * My*nu_y) ) / (2.0)) #e['SS'] = KK ''' ''' if flagStop : print('가우스 적분 사용 결과') print(SS) #print(Q) print('B', Bx, By) print('A', A_prev) print('nu', nu_x, nu_y) print('dB2dA', dBx2dA, dBy2dA) print('수식전개 사용 결과') print(KK) #print(f) return ''' return
def makeElementEquation(self): mu0 = 4 * np.pi * 1e-7 print('------------------------------------') print(' Generating the Element Matrices ') print('------------------------------------') #print('Number of Elements:', len(self.FE_Elements_)) for e in self.FE_Elements_.values(): # 요소의 재질데이터 가져오기 regionID = e['regionID'] headNode = bzmag.getObject(regionID) region = self.FE_Regions_[regionID] sourceID = region['sourceID'] materialID = region['materialID'] # ---------------------------------------------------------------- # 재질 설정 # 참조하는 재질이 있으면 셋팅함 mat = self.FE_Materials_[int(materialID)] # 투자율 설정 # 실제로 이방성 재질을 고려하게끔 수식을 유도했으나, # 프로그램에서 아직 이방성 재질을 설정할 수 있도록 만들어지지 않아 # 이방성 재질에 대한 수식을 사용하되 nur_x 와 nur_y 가 같게 설정한다 # --> 즉 등방성 재질을 사용한 경우의 해석이다 nu = 1 / (mat['mur']*mu0) # BH데이터 설정 BH = mat['BH'] # x축 B, y축 H B2v = mat['B2v']# x축 B^2, y축 v # 자화설정 Mx = 0 My = 0 Magnetization = mat['M'] if Magnetization > 0: vMx, vMy = mat['dirM'] vM = math.sqrt(vMx*vMx + vMy*vMy) uMx = vMx/vM uMy = vMy/vM Mx = Magnetization * uMx My = Magnetization * uMy # 영역이 참조하는 좌표계를 적용한다 cs = headNode.CoordinateSystem m11, m12, m13, m21, m22, m23 = cs.getTransformation() mtx = np.array([[m11, m12, 0], [m21, m22, 0], [0, 0, 1]]) refcs = Affine2D(matrix=mtx) Mx, My = refcs.transform((Mx, My)) # ---------------------------------------------------------------- # 소스 설정 # 소스 가져오기 --> 추후 구현 J = 0 # ---------------------------------------------------------------- # 요소방정식 생성 # 요소를 이루는 절점 ID 가져오기 nodeIDs = e['nodes'] # 추후 어셈블리 시 노드 ID가 필요함 # 노드 ID를 어셈블리 시 행렬 인덱스와 일치시킬 예정임 # 참고) 추후 주기경계조건 처리를 해야하는 경우 주기경계 상의 노드 절점은 따로 처리되므로 # Master/Slave 상의 노드 중 Slave 노드가 Master 노드로 맵핑됨 # 결국 Assembly 시 Slave 노드는 존재하지 않는 노드가 되므로 # 이들은 행렬 인덱스상 가장 마지막에 위치해야 편리함 (아닐지도 모르고...;;) # 2019.08.19 # 요소 형태 알아내기(절점의 수로 알아냄) dim = len(nodeIDs) # 반복법에 있어 이전 반복의 A(미지수, 벡터포텐셜) 값을 0으로 초기화 A_prev = np.zeros(dim) # 소스항 0으로 초기화 Q = np.zeros(dim) # 요소절점의 좌표 얻기 x = np.zeros(dim) y = np.zeros(dim) for j, nodeID in enumerate(nodeIDs): # 노드 ID를 얻고 node = self.FE_Nodes_[nodeID] # 요소 노드 좌표 (단위 변환을 위해 1e-3 곱해줌; mm->m) x[j], y[j] = node['point']*1e-3 # 반복법에 있어, 한번이라도 반복이 발생한 경우에는 # 이전 연산에서의 벡터포텐셜이 self.A_에 저장되어 있음(즉, 크기가 0보다 큼) if len(self.A_) > 0 : A_prev[j] = self.A_[nodeID] else : A_prev[j] = 0 # 겔러킨법의 적용 (요소방정식) # 미분방정식 : "div(v gradA) + J = 0" # 여기서 v는 상수 (v는 텐서일 수 있음 -> 이 경우 수식전개 동일한지 고려해 봐야함) # A는 미지수(자기벡터 포텐셜) # J는 소스 항 (전류밀도) # 상기 미분방정식에 겔러킨법 적용함 (가중함수를 이용한 적분이 필요함) # 1) 정식화 (예, 첫번째 항) # ∫_global{grad(Nt)·v grad(N)A} dxdy # = ∫_local{grad(Nt)·v grad(N)A det(J)} dudv # 2) 수치적분 (가우스 르장드르 적분 적용) # ∫(K(u)) du = ∑wi K(ui) SS = np.zeros((dim,dim)) # stiffiness matrix SS1 = np.zeros((dim,dim)) # stiffiness matrix sub1 ; 본래 계수행렬 SS2 = np.zeros((dim,dim)) # stiffiness matrix sub2 ; NR 법을 위한 미분항 계수행렬 # get integration points and corresponding weights [ui, vi, wi] = self.get_integration_weight(dim) # do integration for i, w in enumerate(wi): u = ui[i] v = vi[i] [N, dNdu, dNdv, detJ, dNdx, dNdy] = self.derivatives_of_shape_functions(u, v, x, y, dim) Nt = np.transpose(N) gradN = np.array([dNdx, dNdy]) gradNt = np.transpose(gradN) # Flux density # [Bx, By] = Curl(NA) Bx = np.matmul(dNdy, A_prev) By = -np.matmul(dNdx, A_prev) B2 = Bx**2 + By**2 absB = np.sqrt(B2) # BH커브 존재시 투자율의 역수 (nu)을 구한다 if BH != None: # B가 0인 경우에는 H도 0이기 때문에 H/B로 nu를 구할수 없다 if absB == 0: nu = BH(0.00001) / 0.00001 else : nu = BH(absB) / absB # 비선형 해석을 위해서는 dv/dB2 이 필요함 # 선형 재질일때는 dv/dB2 = 0이다 dvdB2 = 0 if B2v != None: dvdB2 = fp(B2v, B2) # v-B2 그래프는 단조증가함수이어야 한다! 해의 수렴을 위하여~! if dvdB2 < 0: print('dvdB2 should be positive value!!, B:', Bx, By, B2) SS1 = SS1 + np.matmul(gradNt, nu*gradN) * detJ*w Ex = -dNdx*By Ey = dNdy*Bx E = Ex + Ey ff = np.outer(E, E.T) SS2 = SS2 + ((2*dvdB2*ff)* detJ*w) # source term (Current Density and Magnetization) M = np.array([nu*My, -nu*Mx]) # 자화벡터 ; 좌측 y, x 순서 및 부호 주의! # 소스항 벡터 Q = Q + (Nt*J - np.dot(gradNt, M)) * detJ*w # the component of the right-hand side depending on the potentials Q = Q - np.matmul(SS1, A_prev) # 디버깅용 #if Magnetization > 0: if mat['mur'] > 1000: if not flagStop : print('B', Bx, By) print('A', A_prev) print('nu', nu) print('dvdB2', dvdB2) print('Q', Q) print('SS1', SS1) print('SS2', SS2) flagStop = True # 요소 속성 저장 e['dim'] = dim e['J'] = J e['nu'] = [nu, nu] e['M'] = [Mx, My] e['BH'] = BH e['B2v'] = B2v # 요소방정식 계수행렬 및 소스 벡터 저장 e['SS'] = SS1 + SS2 e['SS1'] = SS1 e['SS2'] = SS2 e['Q'] = Q return
def updateName(self, nodeID): item = self.GeomNodeIdToItem_[nodeID] node = bzmag.getObject(nodeID) item.setText(0, node.getName())