def get_moments(self, Cp): pInf = self.pInf qInf = self.qInf momentCenter = array([self.xref, 0., 0.]) sumMoments = array([0., 0., 0.]) sumForces = array([0., 0., 0.]) for (key, cp) in self.Cps.items(): # centroidal based Cp area = self.areas[key] centroid = self.centroids[key] normal = self.normals[key] p = cp * qInf + pInf F = area * normal * p # negative sign is b/c the normals are flipped... r = momentCenter - centroid sumForces += F sumMoments += cross(r, F) #break log.info("pInf=%s [psi]; qInf= %s [psi]" % (pInf, qInf)) log.info("sumForcesCFD [lb] = %s" % ListPrint(sumForces)) log.info("sumMomentsCFD [ft-lb] = %s" % ListPrint(sumMoments / 12.)) Cf = sumForces / (self.Sref * qInf) Cm = sumMoments / (self.Sref * qInf * self.Lref) * 12. log.info("Cf = %s" % ListPrint(Cf)) log.info("Cm = %s" % ListPrint(Cm)) return (sumForces, sumMoments / 12.)
def mapDeflection(self, A, d1, d2, d3, d4, i, aeroNode, dType='x'): """ see mapDeflections... based on the posiition matrix, finds the ith deflection component Then we ratios the new deflection diMax and compares it to the nearby points to 'test'. """ di = array([d1[i], d2[i], d3[i], d4[i]]) diMax = max(abs(di)) # L1 norm log.info("d%s = %s" % (dType, ListPrint(di))) abcd = solve(A, di) #ui = abcd*aeroNode # element-wise multiplication...faster, cant make it work; tried dot & transpose too... (a, b, c, d) = abcd ui = a + b * aeroNode[0] + c * aeroNode[1] + d * aeroNode[2] isRanged = is_list_ranged(0., abcd, 1.) log.info('isRanged=%s u%sRatio=%g - a=%g b=%g c=%g d=%g' % (isRanged, dType, abs(ui / diMax), a, b, c, d)) return ui
def poor_mans_mapping(self, aCentroid, aEID, pSource, normal): """ distributes load without piercing elements based on distance """ (sElements, sDists) = self.centroidTree.getCloseElementIDs(aCentroid) log.debug("aCentroid = %s" % aCentroid) log.debug("sElements = %s" % sElements) log.debug("sDists = %s" % ListPrint(sDists)) setNodes = set([]) sModel = self.structuralModel for sEID in sElements: sNodes = sModel.get_element_nodes(sEID) setNodes.union(set(sNodes)) nIDs = list(setNodes) sNodes = sModel.getNodeIDLocations(nIDs) weights = self.get_weights(closePoint, sNodes) distribution = self.create_distribution(nIDs, weights) return distribution
def mapLoads(self): """ Loops thru the unitLoad mappingMatrix and multiplies by the total force F on each panel to calculate the PLOAD that will be printed to the output file. Also, performs a sum of Forces & Moments to verify the aero loads. """ log.info("---starting mapLoads---") self.bdf = open(self.bdffile, 'wb') #self.buildMappingMatrix() log.info("self.loadCase = %s" % self.loadCase) self.loadCases = {self.loadCase:{}} #self.loadCases = {self.loadCase={}, } momentCenter = array([self.xref, 0., 0.]) sumMoments = array([0., 0., 0.]) sumForces = array([0., 0., 0.]) sys.stdout.flush() for aEID, distribution in iteritems(self.mappingMatrix): #print "aEID = ",aEID #print "***distribution = ", distribution sumLoad = 0. area = self.aeroModel.Area(aEID) normal = self.aeroModel.Normal(aEID) Cp = self.aeroModel.Cp(aEID) #print "Cp = ",Cp #print "area[%s]=%s" % (aEID, area) p = self.getPressure(Cp) centroid = self.aeroModel.Centroid(aEID) r = momentCenter - centroid F = area * p Fn = F * normal sumMoments += cross(r, Fn) sumForces += Fn for sNID, percentLoad in sorted(iteritems(distribution)): sumLoad += percentLoad Fxyz = Fn * percentLoad # negative sign is to be consistent with nastran self.addForce(sNID, Fxyz) #print("Fxyz = ",Fxyz) #print("type(structuralModel) = ", type(self.structuralModel)) #comment = 'percentLoad=%.2f' % percentLoad #self.structuralModel.writeLoad(self.bdf, self.loadCase, sNID, # Fxyz[0], Fxyz[1], Fxyz[2], comment) #msg = '$ End of aEID=%s sumLoad=%s p=%s area=%s F=%s normal=%s\n' % (aEID, sumLoad, p, area, F, normal) #self.bdf.write(msg) self.writeLoads() # short version of writing loads... self.bdf.close() log.info("pInf=%g [psi]; qInf= %g [psi]" % (self.pInf, self.qInf)) log.info("sumForcesFEM [lb] = %s" % ListPrint(sumForces)) log.info("sumMomentsFEM [lb-ft] = %s" % ListPrint(sumMoments/12.)) # divided by 12 to have moments in lb-ft Cf = sumForces /(self.Sref * self.qInf) log.info("Cf = %s" % ListPrint(Cf)) Cm = sumMoments / (self.Sref * self.qInf * self.Lref) log.info("Cm = %s" % ListPrint(Cm*12.)) # multiply by 12 to nondimensionalize ??? maybe 144... #self.bdf.write('$***********\n') log.info("wrote loads to %r" % self.bdffile) log.info("---finished mapLoads---")
def distribute_unit_load(self, aEID, piercedElements, nPiercings): """ distribute unit loads to nearby nodes piercedElements is a list of piercings piercing = [sEID,P,u,v] or [sEID] where sEID - the structural element ID P - point p was pierced u - u coordinate v - v coordinate if nPiercings==0, all the nearby nodes will recieve load """ aModel = self.aeroModel sModel = self.structuralModel #print("piercedElements = ", piercedElements) nIDs = [] if nPiercings == 0: #assert len(nPiercings)==1,'fix me...' #print("nPiercings=0 distributing load to closest nodes...u=%g v=%g" %(-1,-1)) log.debug("nPiercings=0 distributing load to closest nodes...") for sEID in piercedElements: nIDs += sModel.get_element_node_ids(sEID) #print "nIDs1 = ",nIDs nIDs = list(set(nIDs)) log.debug("nIDs2 = %s" % nIDs) aCentroid = aModel.Centroid(aEID) nodes = sModel.getNodeIDLocations(nIDs) #print "nodes = ", nodes weights = self.get_weights(aCentroid, nodes) distribution = self.create_distribution(nIDs, weights) log.debug("element aEID=%s sEID=%s weights=%s" % (aEID, sEID, ListPrint(weights))) #print("distribution = ", distribution) #print("nIDs = ", nIDs) #print("weights = ", weights) #print("nodes = ", nodes) #print("nPiercings = ", nPiercings) else: log.info("mapping load to actual element...") nClose = 3 # number of elements to map to closeElements = piercedElements[:nClose] setCloseNodes = set([]) for closeElement in reversed(closeElements): log.info("closeElement = %s" % closeElement) #sEID, pIntersect, u1, v1, sDist (sEID, P, u, v, sDist) = closeElement # TODO: bug here...??? #closePoint = closeElement[1] #closeElement = sEID closePoint = P # get list of nearby structural nodes setElementNodes = set(sModel.get_element_node_ids(sEID)) setCloseNodes = setCloseNodes.union(setElementNodes) # setup for weighted average nIDs = list(setCloseNodes) sNodes = sModel.getNodeIDLocations(nIDs) weights = self.get_weights(closePoint, sNodes) distribution = self.create_distribution(nIDs, weights) log.info("element aEID=%s sEID=%s weights=%s" %(aEID, sEID, ListPrint(weights))) log.info("-------------------------\n") sys.stdout.flush() return (distribution)
def pierce_elements(self, aCentroid, aEID, pSource, normal): """ Pierces *1* element with a ray casted from the centroid/pSource in the direction of the normal vector of an aerodynamic triangle A 1 \/ \ / * \ 2---\-3 \ B *P = A+(B-A)*t """ #direction = -1. # TODO: direction of normal...? (sElements, sDists) = self.centroidTree.getCloseElementIDs(aCentroid) log.info("aCentroid = %s" % aCentroid) log.info("sElements = %s" % sElements) log.info("sDists = %s" % ListPrint(sDists)) #(nearbySElements, nearbyDistances) = sElements piercedElements = [] for sEID, sDist in zip(sElements, sDists): #print "aEID=%s sEID=%s" % (aEID, sEID) (sArea, sNormal, sCentroid) = self.structuralModel.get_element_properties(sEID) sNodes = self.structuralModel.get_element_nodes(sEID) nNodes = len(sNodes) pEnd = pSource + normal * 10. #pEnd2 = pSource - normal * 10. if nNodes == 3: # TODO: is this enough of a breakdown? (sA, sB, sC) = sNodes #pEnd = pSource+normal*10. tuv = pierce_plane_vector(sA, sB, sC, pSource, pEnd, piercedElements) #tuv2= pierce_plane_vector(sA, sB, sC, pSource, pEnd2, piercedElements) elif nNodes == 4: (sA, sB, sC, sD) = sNodes tuv = pierce_plane_vector(sA, sB, sC, pSource, pEnd, piercedElements) #tuv2= pierce_plane_vector(sA, sB, sC, pSource, pEnd2, piercedElements) #self.pierceTriangle(sA, sB, sC, sCentroid, sNormal, piercedElements) #self.pierceTriangle(sA, sC, sD, sCentroid, sNormal, piercedElements) else: raise RuntimeError('invalid element; nNodes=%s' % nNodes) t1, u1, v1 = tuv #t2, u2, v2 = tuv2 isInside = False #if self.isInside(u1, v1) or self.isInside(u2, v2): if self.is_inside(u1, v1): isInside = True #pIntersect = pSource + (pEnd - pSource) * t1 pIntersect = pEnd * t1 +pSource * (1 - t1) #P = A + (B - A) * t tuv = pierce_plane_vector(sA, sB, sC, pSource, pIntersect, piercedElements) #print "t,u,v=", tuv piercedElements.append([sEID, pIntersect, u1, v1, sDist]) #t = min(t1, t2) #print "t1=%6.3g t2=%6.3g" % (t1, t2) #if isInside: #print "*t[%s]=%6.3g u1=%6.3g v1=%6.3g u2=%6.3g v2=%6.3g" %(sEID,t,u1,v1,u2,v2) #else: #print " t[%s]=%6.3g u1=%6.3g v1=%6.3g u2=%6.3g v2=%6.3g" %(sEID,t,u1,v1,u2,v2) #if isInside: #print "*t[%s]=%6.3g u1=%6.3g v1=%6.3g d=%g" %(sEID,t1,u1,v1,sDist) #else: #print " t[%s]=%6.3g u1=%6.3g v1=%6.3g d=%g" %(sEID,t1,u1,v1,sDist) log.info("avgDist = %g" % mean(sDists)) (piercedElements, nPiercings) = self.fix_piercings(sElements, piercedElements) distribution = self.distribute_unit_load(aEID, piercedElements, nPiercings) return (distribution)
def find_closest_tet(self, m, closestTet=None): """ Finds the closest tet. Has the potential to fail, but until then, skipping. Solution to failure: brute force method. m = aeroNode tets = """ if closestTet == None: closestTet = tets[1] tets = self.tets #startingTet = tets[1] #closestTet = self.findClosestTet_recursion(m,startingTet,tets) #print "found tet = ",closestTet.ID #v1 = array([1.,0.,0.]) #tet,tetID = self.bruteForce(m,tets) #return tet log.info("starting tet = %s" % (closestTet)) tetID = closestTet.ID excluded = [] log.info("working on point = %s" % (ListPrint(m))) counter = 0 counterMax = 100 broken = False isInternal, localVol = closestTet.is_internal_node(m) if isInternal: log.info("***already Internal") while isInternal == False: log.info("excluding ID=%s" % tetID) excluded.append(tetID) (newTet, minValue) = self.find_closer_tet(m, closestTet, tets, excluded) closestTet = copy.deepcopy(newTet) tetID = closestTet.ID #print("excluded = ", len(excluded)) counter += 1 if (counter == counterMax): break if tetID in excluded: log.info("ERROR***ID=%s was already excluded...excluded=%s" % (tetID, excluded)) broken = True break else: pass #print("ID=%s dist=%s" % (tetID, minValue)) (isInternal, localVol) = closestTet.is_internal_node(m) if broken: (closestTet, tetID) = self.brute_force(m, tets, excluded) else: log.info("*findClosestTet worked!!!") #print("*tet[%s]=%s" % (tetID, closestTet)) #print("nodes = ",closestTet.nodes) return closestTet, closestTet.ID
def map_deflections(self, properTets=None): """ Loops thru all the aero nodes, finds the tet it's in, interpolates on the deflections at the nodes and maps the deflection to the aero node """ if properTets is None: properTets = {} sys.stdout.flush() #reader = f06Reader(self.structuralOutfile) #d = reader.readDeflections() aeroNodes = self.aeroNodes #tets = self.tets d = self.deflectionReader tets = self.tets #tets = self.buildTetrahedralization() #aeroNodes = [array([0.0,0.,0.])] aeroNodes2 = [] tet = tets[1] log.info("-" * 80) #print("type(aeroNodes)=%s" % type(aeroNodes)) for i, aeroNode in iteritems(aeroNodes): if aeroNode[1] < 0: log.info('skipping aeroNode=%s bc y<0.' % i) continue log.info("aeroNode[%s] = %s" % (i, ListPrint(aeroNode))) #print("aeroNode = ",aeroNode) #continue if properTets.has_key(i): tet = tets[properTets[i]] else: (tet, ID2) = self.find_closest_tet(aeroNode, tet) #(isInternal, localVol) = closeTet.isInternalNode(aeroNode) #assert isInternal==True #print("isInternal? = %s" % isInternal) #print("***tet = %s" % (tet)) (n0, n1, n2, n3) = tet.nodes ID = tet.ID deflectionsTet = d.get_deflections(ID, n0, n1, n2, n3) aeroNode2 = tet.map_deflections(deflectionsTet, aeroNode) log.info("aeroNode2 = %s" % (ListPrint(aeroNode2))) properTets[i] = ID aeroNodes2.append(aeroNode2) #for tet in tets: # should select in certain order based on centroids # if tet.isInternalNode(aeroNode): # n0,n1,n2,n3 = tet.nodes # # deflectionsTet = [ d[n0],d[n1],d[n2],d[n3] ] # aeroNode2 = tet.mapDeflections(deflectionsTet,aeroNode) #break # uncomment to run one aeroNode log.info("-" * 80) sys.stdout.flush() #return aeroNode2 #for key,value in properTets.items(): # print("pointID=%s -> tetID=%s" % (key, value)) sys.stdout.flush() return (aeroNodes2, properTets)