Example #1
0
    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]
Example #2
0
    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()
Example #3
0
    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)
Example #4
0
 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)
Example #5
0
    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()
Example #6
0
    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
Example #7
0
    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()
Example #8
0
    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)
Example #9
0
    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()
Example #10
0
    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
Example #11
0
    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
Example #13
0
    def updateName(self, nodeID):
        item = self.GeomNodeIdToItem_[nodeID]

        node = bzmag.getObject(nodeID)
        item.setText(0, node.getName())