def calc_kG0(self, size=None, row0=0, col0=0, silent=False, finalize=True, c=None, NLgeom=False): """Calculate the linear geometric stiffness matrix """ self._rebuild() msg('Calculating kG0... ', level=2, silent=silent) kG0 = 0. if self.base is not None: #TODO include kG0 for pad-up and Nxx load that arrives there pass if self.flange is not None: kG0 += self.flange.calc_kG0(size=size, row0=row0, col0=col0, silent=True, finalize=False, NLgeom=NLgeom) if finalize: kG0 = finalize_symmetric_matrix(kG0) self.kG0 = kG0 #NOTE forcing Python garbage collector to clean the memory # it DOES make a difference! There is a memory leak not # identified, probably in the csr_matrix process gc.collect() msg('finished!', level=2, silent=silent)
def calc_kM(self, size=None, row0=0, col0=0, silent=False, finalize=True): """Calculate the mass matrix """ self._rebuild() msg('Calculating kM... ', level=2, silent=silent) rowf = row0 + self.base.get_size() colf = col0 + self.base.get_size() kM = 0. kM += self.base.calc_kM(size=size, row0=row0, col0=col0, silent=True, finalize=False) kM += self.flange.calc_kM(size=size, row0=rowf, col0=colf, silent=True, finalize=False) if finalize: kM = finalize_symmetric_matrix(kM) self.kM = kM #NOTE forcing Python garbage collector to clean the memory # it DOES make a difference! There is a memory leak not # identified, probably in the csr_matrix process gc.collect() msg('finished!', level=2, silent=silent)
def calc_kG0(self, size=None, row0=0, col0=0, silent=False, finalize=True, c=None): """Calculate the linear geometric stiffness matrix """ #TODO if c is not None: raise NotImplementedError('numerical kG0 not implemented') self._rebuild() msg('Calculating kG0... ', level=2, silent=silent) kG0 = 0. if self.base is not None: # TODO include kG0 for padup # now it is assumed that all the load goes to the flange pass if self.flam is not None: Fx = self.Fx if self.Fx is not None else 0. mod = modelDB.db[self.model]['matrices'] bay = self.bay kG0 += mod.fkG0f(self.ys, Fx, bay.a, bay.b, self.bf, bay.m, bay.n, bay.w1tx, bay.w1rx, bay.w2tx, bay.w2rx, bay.w1ty, bay.w1ry, bay.w2ty, bay.w2ry, size, row0, col0) if finalize: kG0 = finalize_symmetric_matrix(kG0) self.kG0 = kG0 #NOTE forcing Python garbage collector to clean the memory # it DOES make a difference! There is a memory leak not # identified, probably in the csr_matrix process gc.collect() msg('finished!', level=2, silent=silent)
def calc_k0(self, size=None, row0=0, col0=0, silent=False, finalize=True): """Calculate the linear constitutive stiffness matrix """ self._rebuild() msg('Calculating k0... ', level=2, silent=silent) k0 = 0. if self.base is not None: k0 += self.base.calc_k0(size=size, row0=row0, col0=col0, silent=True, finalize=False) if self.flam is not None: mod = modelDB.db[self.model]['matrices'] bay = self.bay k0 += mod.fk0f(self.ys, bay.a, bay.b, self.bf, self.dbf, self.E1, self.F1, self.S1, self.Jxx, bay.m, bay.n, bay.u1tx, bay.u1rx, bay.u2tx, bay.u2rx, bay.w1tx, bay.w1rx, bay.w2tx, bay.w2rx, bay.u1ty, bay.u1ry, bay.u2ty, bay.u2ry, bay.w1ty, bay.w1ry, bay.w2ty, bay.w2ry, size=size, row0=row0, col0=col0) if finalize: k0 = finalize_symmetric_matrix(k0) self.k0 = k0 #NOTE forcing Python garbage collector to clean the memory # it DOES make a difference! There is a memory leak not # identified, probably in the csr_matrix process gc.collect() msg('finished!', level=2, silent=silent)
def calc_kT(self, c=None, silent=False, finalize=True, inc=None): msg('Calculating kT for assembly...', level=2, silent=silent) size = self.get_size() kT = 0 #TODO use multiprocessing.Pool here for p in self.panels: if p.row_start is None or p.col_start is None: raise ValueError( 'Panel attributes "row_start" and "col_start" must be defined!' ) kT += p.calc_k0(c=c, size=size, row0=p.row_start, col0=p.col_start, silent=True, finalize=False, inc=inc, NLgeom=True) kT += p.calc_kG0(c=c, size=size, row0=p.row_start, col0=p.col_start, silent=True, finalize=False, NLgeom=True) if finalize: kT = finalize_symmetric_matrix(kT) k0_conn = self.get_k0_conn() kT += k0_conn self.kT = kT msg('finished!', level=2, silent=silent) return kT
def static(K, fext, silent=False): """Static Analyses Parameters ---------- K : sparse_matrix Stiffness matrix. Should include initial stress stiffness matrix, aerodynamic matrix and so forth when applicable. fext : array-like Vector of external loads. silent : bool, optional A boolean to tell whether the log messages should be printed. """ increments = [] cs = [] NLgeom=False if NLgeom: raise NotImplementedError('Independent static function not ready for NLgeom') else: msg('Started Linear Static Analysis', silent=silent) c = solve(K, fext, silent=silent) increments.append(1.) cs.append(c) msg('Finished Linear Static Analysis', silent=silent) return increments, cs
def calc_kM(self, size=None, row0=0, col0=0, silent=False, finalize=True): """Calculate the mass matrix """ self._rebuild() msg('Calculating kM... ', level=2, silent=silent) mod = modelDB.db[self.model]['matrices'] kM = 0. if self.base is not None: kM += self.base.calc_kM(size=size, row0=row0, col0=col0, silent=silent, finalize=False) if self.flam is not None: bay = self.bay h = 0.5*sum(self.panel1.plyts) + 0.5*sum(self.panel2.plyts) kM += mod.fkMf(self.ys, self.mu, h, self.hb, self.hf, bay.a, bay.b, self.bf, self.dbf, bay.m, bay.n, bay.u1tx, bay.u1rx, bay.u2tx, bay.u2rx, bay.v1tx, bay.v1rx, bay.v2tx, bay.v2rx, bay.w1tx, bay.w1rx, bay.w2tx, bay.w2rx, bay.u1ty, bay.u1ry, bay.u2ty, bay.u2ry, bay.v1ty, bay.v1ry, bay.v2ty, bay.v2ry, bay.w1ty, bay.w1ry, bay.w2ty, bay.w2ry, size=size, row0=row0, col0=col0) if finalize: kM = finalize_symmetric_matrix(kM) self.kM = kM #NOTE forcing Python garbage collector to clean the memory # it DOES make a difference! There is a memory leak not # identified, probably in the csr_matrix process gc.collect() msg('finished!', level=2, silent=silent)
def static(K, fext, silent=False): """Static Analyses Parameters ---------- K : sparse_matrix Stiffness matrix. Should include initial stress stiffness matrix, aerodynamic matrix and so forth when applicable. fext : array-like Vector of external loads. silent : bool, optional A boolean to tell whether the log messages should be printed. """ increments = [] cs = [] NLgeom = False if NLgeom: raise NotImplementedError( 'Independent static function not ready for NLgeom') else: msg('Started Linear Static Analysis', silent=silent) c = solve(K, fext, silent=silent) increments.append(1.) cs.append(c) msg('Finished Linear Static Analysis', silent=silent) return increments, cs
def calc_kM(self, size=None, row0=0, col0=0, silent=False, finalize=True): """Calculate the mass matrix """ self._rebuild() msg('Calculating kM... ', level=2, silent=silent) panmod = panmodelDB.db[self.panel1.model]['matrices'] mod = modelDB.db[self.model]['matrices'] bay = self.bay a = bay.a b = bay.b m = bay.m n = bay.n m1 = self.m1 n1 = self.n1 bf = self.bf kM = 0. if self.blam is not None: # stiffener pad-up y1 = self.ys - self.bb/2. y2 = self.ys + self.bb/2. kM += panmod.fkMy1y2(y1, y2, self.mu, self.db, self.hb, a, b, m, n, bay.u1tx, bay.u1rx, bay.u2tx, bay.u2rx, bay.v1tx, bay.v1rx, bay.v2tx, bay.v2rx, bay.w1tx, bay.w1rx, bay.w2tx, bay.w2rx, bay.u1ty, bay.u1ry, bay.u2ty, bay.u2ry, bay.v1ty, bay.v1ry, bay.v2ty, bay.v2ry, bay.w1ty, bay.w1ry, bay.w2ty, bay.w2ry, size, 0, 0) if self.flam is not None: kM += mod.fkMf(self.mu, self.hf, a, bf, 0., m1, n1, self.u1txf, self.u1rxf, self.u2txf, self.u2rxf, self.v1txf, self.v1rxf, self.v2txf, self.v2rxf, self.w1txf, self.w1rxf, self.w2txf, self.w2rxf, self.u1tyf, self.u1ryf, self.u2tyf, self.u2ryf, self.v1tyf, self.v1ryf, self.v2tyf, self.v2ryf, self.w1tyf, self.w1ryf, self.w2tyf, self.w2ryf, size, row0, col0) if finalize: assert np.any(np.isnan(kM.data)) == False assert np.any(np.isinf(kM.data)) == False kM = csr_matrix(make_symmetric(kM)) self.kM = kM #NOTE forcing Python garbage collector to clean the memory # it DOES make a difference! There is a memory leak not # identified, probably in the csr_matrix process gc.collect() msg('finished!', level=2, silent=silent)
def calc_k0(self, size=None, row0=0, col0=0, silent=False, finalize=True): """Calculate the linear constitutive stiffness matrix """ self._rebuild() msg('Calculating k0... ', level=2, silent=silent) panmod = panmodelDB.db[self.panel1.model]['matrices'] mod = modelDB.db[self.model]['matrices'] bay = self.bay ys = self.ys a = bay.a b = bay.b m = self.panel1.m n = self.panel1.n r = self.panel1.r alphadeg = self.panel1.alphadeg alphadeg = alphadeg if alphadeg is not None else 0. alpharad = deg2rad(alphadeg) k0 = 0. if self.blam is not None: Fsb = self.blam.ABD y1 = ys - self.bb/2. y2 = ys + self.bb/2. k0 += panmod.fk0y1y2(y1, y2, a, b, r, alpharad, Fsb, m, n, bay.u1tx, bay.u1rx, bay.u2tx, bay.u2rx, bay.v1tx, bay.v1rx, bay.v2tx, bay.v2rx, bay.w1tx, bay.w1rx, bay.w2tx, bay.w2rx, bay.u1ty, bay.u1ry, bay.u2ty, bay.u2ry, bay.v1ty, bay.v1ry, bay.v2ty, bay.v2ry, bay.w1ty, bay.w1ry, bay.w2ty, bay.w2ry, size=size, row0=row0, col0=col0) if self.flam is not None: k0 += mod.fk0f(ys, a, b, self.bf, self.df, self.E1, self.F1, self.S1, self.Jxx, m, n, bay.u1tx, bay.u1rx, bay.u2tx, bay.u2rx, bay.w1tx, bay.w1rx, bay.w2tx, bay.w2rx, bay.u1ty, bay.u1ry, bay.u2ty, bay.u2ry, bay.w1ty, bay.w1ry, bay.w2ty, bay.w2ry, size=size, row0=row0, col0=col0) if finalize: assert np.any(np.isnan(k0.data)) == False assert np.any(np.isinf(k0.data)) == False k0 = csr_matrix(make_symmetric(k0)) self.k0 = k0 #NOTE forcing Python garbage collector to clean the memory # it DOES make a difference! There is a memory leak not # identified, probably in the csr_matrix process gc.collect() msg('finished!', level=2, silent=silent)
def calc_k0(self, silent=False): self._rebuild() msg('Calculating k0... ', level=2, silent=silent) model = self.model a = self.a b = self.b r = self.r m = self.m n = self.n num = panmDB.db[self.model]['num'] size = self.get_size() k0 = 0. # contributions from panels for p in self.panels: p.calc_k0(size=size, row0=0, col0=0, silent=True, finalize=False) #TODO summing up coo_matrix objects may be slow! k0 += p.k0 # contributions from bladestiff1ds for s in self.bladestiff1ds: s.calc_k0(size=size, row0=0, col0=0, silent=True, finalize=False) #TODO summing up coo_matrix objects may be slow! k0 += s.k0 # contributions from bladestiff2ds row0 = num*m*n col0 = num*m*n for i, s in enumerate(self.bladestiff2ds): num1 = stiffmDB.db[s.model]['num1'] if i > 0: s_1 = bay.bladestiff2ds[i-1] row0 += num1*s_1.m1*s_1.n1 col0 += num1*s_1.m1*s_1.n1 s.calc_k0(size=size, row0=row0, col0=col0, silent=True, finalize=False) #TODO summing up coo_matrix objects may be slow! k0 += s.k0 # performing checks for the stiffness matrices assert np.any(np.isnan(k0.data)) == False assert np.any(np.isinf(k0.data)) == False k0 = csr_matrix(make_symmetric(k0)) self.k0 = k0 #NOTE forcing Python garbage collector to clean the memory # it DOES make a difference! There is a memory leak not # identified, probably in the csr_matrix process gc.collect() msg('finished!', level=2, silent=silent)
def calc_fext(self, inc=1., silent=False): msg('Calculating external forces for assembly...', level=2, silent=silent) size = self.get_size() fext = 0 for p in self.panels: if p.col_start is None: raise ValueError('Panel attributes "col_start" must be defined!') fext += p.calc_fext(inc=inc, size=size, col0=p.col_start, silent=True) self.fext = fext msg('finished!', level=2, silent=silent) return fext
def calc_fint(self, c, silent=False, inc=1.): msg('Calculating internal forces for assembly...', level=2, silent=silent) size = self.get_size() fint = 0 for p in self.panels: if p.col_start is None: raise ValueError('Panel attributes "col_start" must be defined!') fint += p.calc_fint(c=c, size=size, col0=p.col_start, silent=True) k0_conn = self.get_k0_conn() fint += k0_conn*c self.fint = fint msg('finished!', level=2, silent=silent) return fint
def calc_kM(self, silent=False, finalize=True): msg('Calculating kM for assembly...', level=2, silent=silent) size = self.get_size() kM = 0 for p in self.panels: if p.row_start is None or p.col_start is None: raise ValueError('Panel attributes "row_start" and "col_start" must be defined!') kM += p.calc_kM(row0=p.row_start, col0=p.col_start, size=size, silent=True, finalize=False) if finalize: kM = finalize_symmetric_matrix(kM) self.kM = kM msg('finished!', level=2, silent=silent) return kM
def calc_fext(self, silent=False): """Calculates the external force vector `\{F_{ext}\}` Parameters ---------- silent : bool, optional A boolean to tell whether the msg messages should be printed. Returns ------- fext : np.ndarray The external force vector """ msg('Calculating external forces...', level=2, silent=silent) num = panmDB.db[self.model]['num'] fg = panmDB.db[self.model]['field'].fg # punctual forces on skin size = num*self.m*self.n g = np.zeros((3, size), dtype=DOUBLE) fext_skin = np.zeros(size, dtype=DOUBLE) for i, force in enumerate(self.forces_skin): x, y, fx, fy, fz = force fg(g, self.m, self.n, x, y, self.a, self.b) fpt = np.array([[fx, fy, fz]]) fext_skin += fpt.dot(g).ravel() fext = fext_skin # punctual forces on stiffener for s in self.bladestiff2ds: num1 = stiffmDB.db[s.model]['num1'] m1 = s.m1 n1 = s.n1 bf = s.bf size = num1*m1*n1 g_stiffener = np.zeros((3, size), dtype=DOUBLE) fext_stiffener = np.zeros(size, dtype=DOUBLE) for i, force in enumerate(s.forces): xf, yf, fx, fy, fz = force fg(g_stiffener, m1, n1, xf, yf, self.a, bf) fpt = np.array([[fx, fy, fz]]) fext_stiffener += fpt.dot(g_stiffener).ravel() fext = np.concatenate((fext, fext_stiffener)) msg('finished!', level=2, silent=silent) return fext
def calc_kA(self, silent=False): self._rebuild() msg('Calculating kA... ', level=2, silent=silent) model = self.model a = self.a b = self.b r = self.r m = self.m n = self.n num = panmDB.db[self.model]['num'] size = self.get_size() if self.beta is None: if self.Mach < 1: raise ValueError('Mach number must be >= 1') elif self.Mach == 1: self.Mach = 1.0001 M = self.Mach beta = self.rho_air * self.V**2 / (M**2 - 1)**0.5 gamma = beta*1./(2.*self.r*(M**2 - 1)**0.5) ainf = self.speed_sound aeromu = beta/(M*ainf)*(M**2 - 2)/(M**2 - 1) else: beta = self.beta gamma = self.gamma if self.gamma is not None else 0. aeromu = self.aeromu if self.aeromu is not None else 0. # contributions from panels #TODO summing up coo_matrix objects may be slow! p = self.panels[0] #TODO if the initialization of panel is correct, the line below is # unnecessary p.flow = self.flow p.calc_kA(silent=silent, finalize=False) kA = p.kA assert np.any(np.isnan(kA.data)) == False assert np.any(np.isinf(kA.data)) == False kA = csr_matrix(make_skew_symmetric(kA)) self.kA = kA #NOTE forcing Python garbage collector to clean the memory # it DOES make a difference! There is a memory leak not # identified, probably in the csr_matrix process gc.collect() msg('finished!', level=2, silent=silent)
def calc_fint(self, c, silent=False, inc=1.): msg('Calculating internal forces for assembly...', level=2, silent=silent) size = self.get_size() fint = 0 for p in self.panels: if p.col_start is None: raise ValueError( 'Panel attributes "col_start" must be defined!') fint += p.calc_fint(c=c, size=size, col0=p.col_start, silent=True) k0_conn = self.get_k0_conn() fint += k0_conn * c self.fint = fint msg('finished!', level=2, silent=silent) return fint
def save(self): """Save the ``AeroPistonPlate`` object using ``cPickle`` Notes ----- The pickled file will have the name stored in ``AeroPistonPlate.name`` followed by a ``'.AeroPistonPlate'`` extension. """ name = self.name + '.AeroPistonPlate' msg('Saving AeroPistonPlate to {}'.format(name)) self._clear_matrices() with open(name, 'wb') as f: cPickle.dump(self, f, protocol=cPickle.HIGHEST_PROTOCOL)
def save(self): """Save the :class:`StiffPanelBay` object using ``cPickle`` Notes ----- The pickled file will have the name stored in :property:`.StiffPanelBay.name` followed by a ``'.StiffPanelBay'`` extension. """ name = self.name + '.StiffPanelBay' msg('Saving StiffPanelBay to {0}'.format(name)) self._clear_matrices() with open(name, 'wb') as f: cPickle.dump(self, f, protocol=cPickle.HIGHEST_PROTOCOL)
def calc_fext(self, inc=1., silent=False): msg('Calculating external forces for assembly...', level=2, silent=silent) size = self.get_size() fext = 0 for p in self.panels: if p.col_start is None: raise ValueError( 'Panel attributes "col_start" must be defined!') fext += p.calc_fext(inc=inc, size=size, col0=p.col_start, silent=True) self.fext = fext msg('finished!', level=2, silent=silent) return fext
def calc_cA(self, silent=False): self._rebuild() msg('Calculating cA... ', level=2, silent=silent) model = self.model a = self.a b = self.b r = self.r m = self.m n = self.n num = panmDB.db[self.model]['num'] size = self.get_size() if self.beta is None: if self.Mach < 1: raise ValueError('Mach number must be >= 1') elif self.Mach == 1: self.Mach = 1.0001 M = self.Mach beta = self.rho_air * self.V**2 / (M**2 - 1)**0.5 gamma = beta*1./(2.*self.r*(M**2 - 1)**0.5) ainf = self.speed_sound aeromu = beta/(M*ainf)*(M**2 - 2)/(M**2 - 1) else: beta = self.beta gamma = self.gamma if self.gamma is not None else 0. aeromu = self.aeromu if self.aeromu is not None else 0. # contributions from panels p = self.panels[0] p.calc_cA(size=size, row0=0, col0=0, silent=silent) cA = p.cA assert np.any(np.isnan(cA.data)) == False assert np.any(np.isinf(cA.data)) == False cA = csr_matrix(make_symmetric(cA)) self.cA = cA #NOTE forcing Python garbage collector to clean the memory # it DOES make a difference! There is a memory leak not # identified, probably in the csr_matrix process gc.collect() msg('finished!', level=2, silent=silent)
def calc_kG0(self, size=None, row0=0, col0=0, silent=False, finalize=True): """Calculate the linear geometric stiffness matrix """ self._rebuild() msg('Calculating kG0... ', level=2, silent=silent) panmod = panmodelDB.db[self.panel1.model]['matrices'] mod = modelDB.db[self.model]['matrices'] bay = self.bay ys = self.ys m = bay.m n = bay.n mu = self.mu kG0 = 0. if self.blam is not None: Fsb = self.blam.ABD y1 = ys - self.bb/2. y2 = ys + self.bb/2. # TODO include kG0 for padup # now it is assumed that all the load goes to the flange if self.flam is not None: Fx = self.Fx if self.Fx is not None else 0. kG0 += mod.fkG0f(ys, Fx, bay.a, bay.b, self.bf, m, n, bay.w1tx, bay.w1rx, bay.w2tx, bay.w2rx, bay.w1ty, bay.w1ry, bay.w2ty, bay.w2ry, size, row0, col0) if finalize: assert np.any((np.isnan(kG0.data) | np.isinf(kG0.data))) == False kG0 = csr_matrix(make_symmetric(kG0)) self.kG0 = kG0 #NOTE forcing Python garbage collector to clean the memory # it DOES make a difference! There is a memory leak not # identified, probably in the csr_matrix process gc.collect() msg('finished!', level=2, silent=silent)
def calc_kT(self, c=None, silent=False, finalize=True, inc=None): msg('Calculating kT for assembly...', level=2, silent=silent) size = self.get_size() kT = 0 #TODO use multiprocessing.Pool here for p in self.panels: if p.row_start is None or p.col_start is None: raise ValueError('Panel attributes "row_start" and "col_start" must be defined!') kT += p.calc_k0(c=c, size=size, row0=p.row_start, col0=p.col_start, silent=True, finalize=False, inc=inc, NLgeom=True) kT += p.calc_kG0(c=c, size=size, row0=p.row_start, col0=p.col_start, silent=True, finalize=False, NLgeom=True) if finalize: kT = finalize_symmetric_matrix(kT) k0_conn = self.get_k0_conn() kT += k0_conn self.kT = kT msg('finished!', level=2, silent=silent) return kT
def calc_kM(self, silent=False, finalize=True): msg('Calculating kM for assembly...', level=2, silent=silent) size = self.get_size() kM = 0 for p in self.panels: if p.row_start is None or p.col_start is None: raise ValueError( 'Panel attributes "row_start" and "col_start" must be defined!' ) kM += p.calc_kM(row0=p.row_start, col0=p.col_start, size=size, silent=True, finalize=False) if finalize: kM = finalize_symmetric_matrix(kM) self.kM = kM msg('finished!', level=2, silent=silent) return kM
def calc_kG0(self, size=None, row0=0, col0=0, silent=False, finalize=True): """Calculate the linear geometric stiffness matrix """ self._rebuild() msg('Calculating kG0... ', level=2, silent=silent) mod = modelDB.db[self.model]['matrices'] bay = self.bay a = bay.a kG0 = 0. if self.blam is not None: # stiffener pad-up #TODO include kG0 for pad-up (Nxx load that arrives there) pass if self.flam is not None: F = self.flam.ABD # stiffener flange Nxx = self.Nxx if self.Nxx is not None else 0. Nxy = self.Nxy if self.Nxy is not None else 0. kG0 += mod.fkG0f(Nxx, 0., Nxy, a, self.bf, self.m1, self.n1, self.w1txf, self.w1rxf, self.w2txf, self.w2rxf, self.w1tyf, self.w1ryf, self.w2tyf, self.w2ryf, size, row0, col0) if finalize: assert np.any((np.isnan(kG0.data) | np.isinf(kG0.data))) == False kG0 = csr_matrix(make_symmetric(kG0)) self.kG0 = kG0 #NOTE forcing Python garbage collector to clean the memory # it DOES make a difference! There is a memory leak not # identified, probably in the csr_matrix process gc.collect() msg('finished!', level=2, silent=silent)
def calc_kG0(self, c=None, silent=False, finalize=True): """Calculate the geometric stiffness matrix of the assembly Parameters ---------- c : array-like or None, optional This must be the result of a static analysis, used to compute non-linear terms based on the actual displacement field. silent : bool, optional A boolean to tell whether the log messages should be printed. finalize : bool, optional Asserts validity of output data and makes the output matrix symmetric, should be ``False`` when assemblying. """ size = self.get_size() if c is None: msg('Calculating kG0 for assembly...', level=2, silent=silent) else: check_c(c, size) msg('Calculating kG for assembly...', level=2, silent=silent) kG0 = 0. for p in self.panels: if p.row_start is None or p.col_start is None: raise ValueError('Panel attributes "row_start" and "col_start" must be defined!') kG0 += p.calc_kG0(c=c, row0=p.row_start, col0=p.col_start, size=size, silent=True, finalize=False) if finalize: kG0 = finalize_symmetric_matrix(kG0) self.kG0 = kG0 msg('finished!', level=2, silent=silent) return kG0
def calc_kG0(self, size=None, row0=0, col0=0, silent=False, finalize=True, c=None, NLgeom=False): """Calculate the linear geometric stiffness matrix See :meth:`.Panel.calc_k0` for details on each parameter. """ self._rebuild() if c is None: msg('Calculating kG0... ', level=2, silent=silent) else: msg('Calculating kG... ', level=2, silent=silent) # NOTE: # - row0 and col0 define where the stiffener's base matrix starts # - rowf and colf define where the stiffener's flange matrix starts rowf = row0 + self.base.get_size() colf = col0 + self.base.get_size() kG0 = 0. kG0 += self.base.calc_kG0(c=c, size=size, row0=row0, col0=col0, silent=True, finalize=False, NLgeom=NLgeom) kG0 += self.flange.calc_kG0(c=c, size=size, row0=rowf, col0=colf, silent=True, finalize=False, NLgeom=NLgeom) if finalize: kG0 = finalize_symmetric_matrix(kG0) self.kG0 = kG0 #NOTE forcing Python garbage collector to clean the memory # it DOES make a difference! There is a memory leak not # identified, probably in the csr_matrix process gc.collect() msg('finished!', level=2, silent=silent)
def static(self, NLgeom=False, silent=False): """General solver for static analyses Selects the specific solver based on the ``NL_method`` parameter. """ self.increments = [] self.cs = [] if NLgeom: self.maxInc = max(self.initialInc, self.maxInc) msg('Started Non-Linear Static Analysis', silent=silent) if self.NL_method is 'NR': _solver_NR(self) elif self.NL_method is 'arc_length': _solver_arc_length(self) else: raise ValueError('{0} is an invalid NL_method') else: msg('Started Linear Static Analysis', silent=silent) fext = self.calc_fext() k0 = self.calc_k0() if self.calc_k0_bc is not None: k0_bc = self.calc_k0_bc() k0max = k0.max() k0 /= k0max fextmax = fext.max() fext /= fextmax k0 = k0 + k0_bc c = solve(k0, fext) if self.calc_k0_bc is not None: k0 *= k0max fext *= fextmax c /= k0max c *= fextmax self.cs.append(c) self.increments.append(1.) msg('Finished Linear Static Analysis', silent=silent) self.last_analysis = 'static' return self.increments, self.cs
def calc_k0(self, conn=None, c=None, silent=False, finalize=True, inc=1.): """Calculate the constitutive stiffness matrix of the assembly Parameters ---------- conn : dict, optional A connectivity dictionary. Optional if already defined for the assembly. c : array-like or None, optional This must be the result of a static analysis, used to compute non-linear terms based on the actual displacement field. silent : bool, optional A boolean to tell whether the log messages should be printed. finalize : bool, optional Asserts validity of output data and makes the output matrix symmetric, should be ``False`` when assemblying. inc : float, optional Dummy argument needed for non-linear analyses. """ size = self.get_size() if c is None: msg('Calculating k0 for assembly...', level=2, silent=silent) else: check_c(c, size) msg('Calculating kL for assembly...', level=2, silent=silent) k0 = 0. for p in self.panels: if p.row_start is None or p.col_start is None: raise ValueError( 'Panel attributes "row_start" and "col_start" must be defined!' ) k0 += p.calc_k0(c=c, row0=p.row_start, col0=p.col_start, size=size, silent=True, finalize=False) if finalize: k0 = finalize_symmetric_matrix(k0) k0_conn = self.get_k0_conn(conn=conn) k0 += self.k0_conn self.k0 = k0 msg('finished!', level=2, silent=silent) return k0
def calc_k0(self, conn=None, c=None, silent=False, finalize=True, inc=1.): """Calculate the constitutive stiffness matrix of the assembly Parameters ---------- conn : dict, optional A connectivity dictionary. Optional if already defined for the assembly. c : array-like or None, optional This must be the result of a static analysis, used to compute non-linear terms based on the actual displacement field. silent : bool, optional A boolean to tell whether the log messages should be printed. finalize : bool, optional Asserts validity of output data and makes the output matrix symmetric, should be ``False`` when assemblying. inc : float, optional Dummy argument needed for non-linear analyses. """ size = self.get_size() if c is None: msg('Calculating k0 for assembly...', level=2, silent=silent) else: check_c(c, size) msg('Calculating kL for assembly...', level=2, silent=silent) k0 = 0. for p in self.panels: if p.row_start is None or p.col_start is None: raise ValueError('Panel attributes "row_start" and "col_start" must be defined!') k0 += p.calc_k0(c=c, row0=p.row_start, col0=p.col_start, size=size, silent=True, finalize=False) if finalize: k0 = finalize_symmetric_matrix(k0) k0_conn = self.get_k0_conn(conn=conn) k0 += self.k0_conn self.k0 = k0 msg('finished!', level=2, silent=silent) return k0
def static(self, NLgeom=False, silent=False): """General solver for static analyses Selects the specific solver based on the ``NL_method`` parameter. Parameters ---------- NLgeom : bool Flag to indicate whether a linear or a non-linear analysis is to be performed. silent : bool, optional A boolean to tell whether the log messages should be printed. """ self.increments = [] self.cs = [] if NLgeom: self.maxInc = max(self.initialInc, self.maxInc) msg('Started Non-Linear Static Analysis', silent=silent) if self.NL_method is 'NR': _solver_NR(self, silent=silent) elif self.NL_method is 'arc_length': _solver_arc_length(self) else: raise ValueError('{0} is an invalid NL_method') else: msg('Started Linear Static Analysis', silent=silent) fext = self.calc_fext(silent=silent) k0 = self.calc_k0(silent=silent) c = solve(k0, fext, silent=silent) self.cs.append(c) self.increments.append(1.) msg('Finished Linear Static Analysis', silent=silent) self.last_analysis = 'static' return self.increments, self.cs
def calc_kG0(self, c=None, silent=False, finalize=True): """Calculate the geometric stiffness matrix of the assembly Parameters ---------- c : array-like or None, optional This must be the result of a static analysis, used to compute non-linear terms based on the actual displacement field. silent : bool, optional A boolean to tell whether the log messages should be printed. finalize : bool, optional Asserts validity of output data and makes the output matrix symmetric, should be ``False`` when assemblying. """ size = self.get_size() if c is None: msg('Calculating kG0 for assembly...', level=2, silent=silent) else: check_c(c, size) msg('Calculating kG for assembly...', level=2, silent=silent) kG0 = 0. for p in self.panels: if p.row_start is None or p.col_start is None: raise ValueError( 'Panel attributes "row_start" and "col_start" must be defined!' ) kG0 += p.calc_kG0(c=c, row0=p.row_start, col0=p.col_start, size=size, silent=True, finalize=False) if finalize: kG0 = finalize_symmetric_matrix(kG0) self.kG0 = kG0 msg('finished!', level=2, silent=silent) return kG0
def calc_k0(self, size=None, row0=0, col0=0, silent=False, finalize=True): """Calculate the linear constitutive stiffness matrix """ self._rebuild() msg('Calculating k0... ', level=2, silent=silent) flangemod = panmodelDB.db[self.flange.model]['matrices'] bay = self.bay a = bay.a b = bay.b m = bay.m n = bay.n k0 = 0. if self.base is not None: k0 += self.base.calc_k0(size=size, row0=0, col0=0, silent=True, finalize=False) if self.flange is not None: k0 += self.flange.calc_k0(size=size, row0=row0, col0=col0, silent=True, finalize=False) # connectivity between stiffener'base and stiffener's flange if self.base is None: ktbf, krbf = calc_kt_kr(self.panel1, self.flange, 'ycte') else: ktbf, krbf = calc_kt_kr(self.base, self.flange, 'ycte') mod = db['bladestiff2d_clt_donnell_bardell']['connections'] k0 += mod.fkCss(ktbf, krbf, self.ys, a, b, m, n, bay.u1tx, bay.u1rx, bay.u2tx, bay.u2rx, bay.v1tx, bay.v1rx, bay.v2tx, bay.v2rx, bay.w1tx, bay.w1rx, bay.w2tx, bay.w2rx, bay.u1ty, bay.u1ry, bay.u2ty, bay.u2ry, bay.v1ty, bay.v1ry, bay.v2ty, bay.v2ry, bay.w1ty, bay.w1ry, bay.w2ty, bay.w2ry, size, 0, 0) bf = self.flange.b k0 += mod.fkCsf(ktbf, krbf, self.ys, a, b, bf, m, n, self.flange.m, self.flange.n, bay.u1tx, bay.u1rx, bay.u2tx, bay.u2rx, bay.v1tx, bay.v1rx, bay.v2tx, bay.v2rx, bay.w1tx, bay.w1rx, bay.w2tx, bay.w2rx, bay.u1ty, bay.u1ry, bay.u2ty, bay.u2ry, bay.v1ty, bay.v1ry, bay.v2ty, bay.v2ry, bay.w1ty, bay.w1ry, bay.w2ty, bay.w2ry, self.flange.u1tx, self.flange.u1rx, self.flange.u2tx, self.flange.u2rx, self.flange.v1tx, self.flange.v1rx, self.flange.v2tx, self.flange.v2rx, self.flange.w1tx, self.flange.w1rx, self.flange.w2tx, self.flange.w2rx, self.flange.u1ty, self.flange.u1ry, self.flange.u2ty, self.flange.u2ry, self.flange.v1ty, self.flange.v1ry, self.flange.v2ty, self.flange.v2ry, self.flange.w1ty, self.flange.w1ry, self.flange.w2ty, self.flange.w2ry, size, 0, col0) k0 += mod.fkCff(ktbf, krbf, a, bf, self.flange.m, self.flange.n, self.flange.u1tx, self.flange.u1rx, self.flange.u2tx, self.flange.u2rx, self.flange.v1tx, self.flange.v1rx, self.flange.v2tx, self.flange.v2rx, self.flange.w1tx, self.flange.w1rx, self.flange.w2tx, self.flange.w2rx, self.flange.u1ty, self.flange.u1ry, self.flange.u2ty, self.flange.u2ry, self.flange.v1ty, self.flange.v1ry, self.flange.v2ty, self.flange.v2ry, self.flange.w1ty, self.flange.w1ry, self.flange.w2ty, self.flange.w2ry, size, row0, col0) if finalize: k0 = finalize_symmetric_matrix(k0) self.k0 = k0 #NOTE forcing Python garbage collector to clean the memory # it DOES make a difference! There is a memory leak not # identified, probably in the csr_matrix process gc.collect() msg('finished!', level=2, silent=silent)
def plot(self, c, group, invert_y=False, vec='w', filename='', ax=None, figsize=(3.5, 2.), save=True, title='', identify=False, show_boundaries=False, boundary_line='--k', boundary_linewidth=1., colorbar=False, cbar_nticks=2, cbar_format=None, cbar_title='', cbar_fontsize=10, colormap='jet', aspect='equal', clean=True, dpi=400, texts=[], xs=None, ys=None, gridx=50, gridy=50, num_levels=400, vecmin=None, vecmax=None, calc_data_only=False): r"""Contour plot for a Ritz constants vector. Parameters ---------- c : np.ndarray The Ritz constants that will be used to compute the field contour. group : str A group to plot. Each panel in ``panels`` should contain an attribute ``group``, which is used to identify which entities should be plotted together. vec : str, optional Can be one of the components: - Displacement: ``'u'``, ``'v'``, ``'w'``, ``'phix'``, ``'phiy'`` - Strain: ``'exx'``, ``'eyy'``, ``'gxy'``, ``'kxx'``, ``'kyy'``, ``'kxy'``, ``'gyz'``, ``'gxz'`` - Stress: ``'Nxx'``, ``'Nyy'``, ``'Nxy'``, ``'Mxx'``, ``'Myy'``, ``'Mxy'``, ``'Qy'``, ``'Qx'`` invert_y : bool, optional Inverts the `y` axis of the plot. save : bool, optional Flag telling whether the contour should be saved to an image file. dpi : int, optional Resolution of the saved file in dots per inch. filename : str, optional The file name for the generated image file. If no value is given, the `name` parameter of the ``Panel`` object will be used. ax : AxesSubplot, optional When ``ax`` is given, the contour plot will be created inside it. figsize : tuple, optional The figure size given by ``(width, height)``. title : str, optional If any string is given a title is added to the contour plot. indentify : bool, optional If domains should be identified. If yes, the name of each panel is used. show_boundaries : bool, optional If boundaries between domains should be drawn. boundary_line : str, optional Matplotlib string to define line type and color. boundary_linewidth : float, optional Matplotlib float to define line width. colorbar : bool, optional If a colorbar should be added to the contour plot. cbar_nticks : int, optional Number of ticks added to the colorbar. cbar_format : [ None | format string | Formatter object ], optional See the ``matplotlib.pyplot.colorbar`` documentation. cbar_title : str, optional Colorbar title. If ``cbar_title == ''`` no title is added. cbar_fontsize : int, optional Fontsize of the colorbar labels. colormap : string, optional Name of a matplotlib available colormap. aspect : str, optional String that will be passed to the ``AxesSubplot.set_aspect()`` method. clean : bool, optional Clean axes ticks, grids, spines etc. xs : np.ndarray, optional The `x` positions where to calculate the displacement field. Default is ``None`` and the method ``_default_field`` is used. ys : np.ndarray, optional The ``y`` positions where to calculate the displacement field. Default is ``None`` and the method ``_default_field`` is used. gridx : int, optional Number of points along the `x` axis where to calculate the displacement field. gridy : int, optional Number of points along the `y` where to calculate the displacement field. num_levels : int, optional Number of contour levels (higher values make the contour smoother). vecmin : float, optional Minimum value for the contour scale (useful to compare with other results). If not specified it will be taken from the calculated field. vecmax : float, optional Maximum value for the contour scale. calc_data_only : bool, optional If only calculated data should be returned. Returns ------- ax : matplotlib.axes.Axes The Matplotlib object that can be used to modify the current plot if needed. data : dict Data calculated during the plotting procedure. """ msg('Plotting contour...') import matplotlib if platform.system().lower() == 'linux': matplotlib.use('Agg') import matplotlib.pyplot as plt msg('Computing field variables...', level=1) displs = ['u', 'v', 'w', 'phix', 'phiy'] strains = ['exx', 'eyy', 'gxy', 'kxx', 'kyy', 'kxy', 'gyz', 'gxz'] stresses = ['Nxx', 'Nyy', 'Nxy', 'Mxx', 'Myy', 'Mxy', 'Qy', 'Qx'] if vec in displs: res = self.uvw(c, group, gridx=gridx, gridy=gridy) elif vec in strains: res = self.strain(c, group, gridx=gridx, gridy=gridy) elif vec in stresses: res = self.stress(c, group, gridx=gridx, gridy=gridy) else: raise ValueError( '{0} is not a valid vec parameter value!'.format(vec)) field = np.array(res[vec]) msg('Finished!', level=1) if vecmin is None: vecmin = field.min() if vecmax is None: vecmax = field.max() data = dict(vecmin=vecmin, vecmax=vecmax) if calc_data_only: return None, data levels = linspace(vecmin, vecmax, num_levels) if ax is None: fig = plt.figure(figsize=figsize) ax = fig.add_subplot(111) else: if isinstance(ax, matplotlib.axes.Axes): ax = ax fig = ax.figure save = False else: raise ValueError('ax must be an Axes object') if invert_y == True: ax.invert_yaxis() ax.invert_xaxis() colormap_obj = getattr(cm, colormap, None) if colormap_obj is None: warn('Invalid colormap, using "jet"', level=1) colormap_obj = cm.jet count = -1 for i, panel in enumerate(self.panels): if panel.group != group: continue count += 1 xplot = res['y'][count] + panel.y0 yplot = res['x'][count] + panel.x0 field = res[vec][count] contour = ax.contourf(xplot, yplot, field, levels=levels, cmap=colormap_obj) if identify: ax.text(xplot.mean(), yplot.mean(), 'P {0:02d}'.format(i+1), transform=ax.transData, ha='center') if show_boundaries: x1, x2 = xplot.min(), xplot.max() y1, y2 = yplot.min(), yplot.max() ax.plot((x1, x2), (y1, y1), boundary_line, lw=boundary_linewidth) ax.plot((x1, x2), (y2, y2), boundary_line, lw=boundary_linewidth) ax.plot((x1, x1), (y1, y2), boundary_line, lw=boundary_linewidth) ax.plot((x2, x2), (y1, y2), boundary_line, lw=boundary_linewidth) if colorbar: from mpl_toolkits.axes_grid1 import make_axes_locatable fsize = cbar_fontsize divider = make_axes_locatable(ax) cax = divider.append_axes('right', size='5%', pad=0.05) cbarticks = linspace(vecmin, vecmax, cbar_nticks) cbar = plt.colorbar(contour, ticks=cbarticks, format=cbar_format, cax=cax) if cbar_title: cax.text(0.5, 1.05, cbar_title, horizontalalignment='center', verticalalignment='bottom', fontsize=fsize) cbar.outline.remove() cbar.ax.tick_params(labelsize=fsize, pad=0., tick2On=False) if title != '': ax.set_title(str(title)) fig.tight_layout() ax.set_aspect(aspect) ax.grid(False) ax.set_frame_on(False) if clean: ax.xaxis.set_ticks_position('none') ax.yaxis.set_ticks_position('none') ax.xaxis.set_ticklabels([]) ax.yaxis.set_ticklabels([]) else: ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') for kwargs in texts: ax.text(transform=ax.transAxes, **kwargs) if save: if not filename: filename = group + '.png' fig.savefig(filename, transparent=True, bbox_inches='tight', pad_inches=0.05, dpi=dpi) plt.close() msg('finished!') return ax, data
def plot(self, c, group, invert_y=False, vec='w', filename='', ax=None, figsize=(3.5, 2.), save=True, title='', identify=False, show_boundaries=False, boundary_line='--k', boundary_linewidth=1., colorbar=False, cbar_nticks=2, cbar_format=None, cbar_title='', cbar_fontsize=10, colormap='jet', aspect='equal', clean=True, dpi=400, texts=[], xs=None, ys=None, gridx=50, gridy=50, num_levels=400, vecmin=None, vecmax=None, calc_data_only=False): r"""Contour plot for a Ritz constants vector. Parameters ---------- c : np.ndarray The Ritz constants that will be used to compute the field contour. group : str A group to plot. Each panel in ``panels`` should contain an attribute ``group``, which is used to identify which entities should be plotted together. vec : str, optional Can be one of the components: - Displacement: ``'u'``, ``'v'``, ``'w'``, ``'phix'``, ``'phiy'`` - Strain: ``'exx'``, ``'eyy'``, ``'gxy'``, ``'kxx'``, ``'kyy'``, ``'kxy'``, ``'gyz'``, ``'gxz'`` - Stress: ``'Nxx'``, ``'Nyy'``, ``'Nxy'``, ``'Mxx'``, ``'Myy'``, ``'Mxy'``, ``'Qy'``, ``'Qx'`` invert_y : bool, optional Inverts the `y` axis of the plot. save : bool, optional Flag telling whether the contour should be saved to an image file. dpi : int, optional Resolution of the saved file in dots per inch. filename : str, optional The file name for the generated image file. If no value is given, the `name` parameter of the ``Panel`` object will be used. ax : AxesSubplot, optional When ``ax`` is given, the contour plot will be created inside it. figsize : tuple, optional The figure size given by ``(width, height)``. title : str, optional If any string is given a title is added to the contour plot. indentify : bool, optional If domains should be identified. If yes, the name of each panel is used. show_boundaries : bool, optional If boundaries between domains should be drawn. boundary_line : str, optional Matplotlib string to define line type and color. boundary_linewidth : float, optional Matplotlib float to define line width. colorbar : bool, optional If a colorbar should be added to the contour plot. cbar_nticks : int, optional Number of ticks added to the colorbar. cbar_format : [ None | format string | Formatter object ], optional See the ``matplotlib.pyplot.colorbar`` documentation. cbar_title : str, optional Colorbar title. If ``cbar_title == ''`` no title is added. cbar_fontsize : int, optional Fontsize of the colorbar labels. colormap : string, optional Name of a matplotlib available colormap. aspect : str, optional String that will be passed to the ``AxesSubplot.set_aspect()`` method. clean : bool, optional Clean axes ticks, grids, spines etc. xs : np.ndarray, optional The `x` positions where to calculate the displacement field. Default is ``None`` and the method ``_default_field`` is used. ys : np.ndarray, optional The ``y`` positions where to calculate the displacement field. Default is ``None`` and the method ``_default_field`` is used. gridx : int, optional Number of points along the `x` axis where to calculate the displacement field. gridy : int, optional Number of points along the `y` where to calculate the displacement field. num_levels : int, optional Number of contour levels (higher values make the contour smoother). vecmin : float, optional Minimum value for the contour scale (useful to compare with other results). If not specified it will be taken from the calculated field. vecmax : float, optional Maximum value for the contour scale. calc_data_only : bool, optional If only calculated data should be returned. Returns ------- ax : matplotlib.axes.Axes The Matplotlib object that can be used to modify the current plot if needed. data : dict Data calculated during the plotting procedure. """ msg('Plotting contour...') import matplotlib if platform.system().lower() == 'linux': matplotlib.use('Agg') import matplotlib.pyplot as plt msg('Computing field variables...', level=1) displs = ['u', 'v', 'w', 'phix', 'phiy'] strains = ['exx', 'eyy', 'gxy', 'kxx', 'kyy', 'kxy', 'gyz', 'gxz'] stresses = ['Nxx', 'Nyy', 'Nxy', 'Mxx', 'Myy', 'Mxy', 'Qy', 'Qx'] if vec in displs: res = self.uvw(c, group, gridx=gridx, gridy=gridy) elif vec in strains: res = self.strain(c, group, gridx=gridx, gridy=gridy) elif vec in stresses: res = self.stress(c, group, gridx=gridx, gridy=gridy) else: raise ValueError( '{0} is not a valid vec parameter value!'.format(vec)) field = np.array(res[vec]) msg('Finished!', level=1) if vecmin is None: vecmin = field.min() if vecmax is None: vecmax = field.max() data = dict(vecmin=vecmin, vecmax=vecmax) if calc_data_only: return None, data levels = linspace(vecmin, vecmax, num_levels) if ax is None: fig = plt.figure(figsize=figsize) ax = fig.add_subplot(111) else: if isinstance(ax, matplotlib.axes.Axes): ax = ax fig = ax.figure save = False else: raise ValueError('ax must be an Axes object') if invert_y == True: ax.invert_yaxis() ax.invert_xaxis() colormap_obj = getattr(cm, colormap, None) if colormap_obj is None: warn('Invalid colormap, using "jet"', level=1) colormap_obj = cm.jet count = -1 for i, panel in enumerate(self.panels): if panel.group != group: continue count += 1 xplot = res['y'][count] + panel.y0 yplot = res['x'][count] + panel.x0 field = res[vec][count] contour = ax.contourf(xplot, yplot, field, levels=levels, cmap=colormap_obj) if identify: ax.text(xplot.mean(), yplot.mean(), 'P {0:02d}'.format(i + 1), transform=ax.transData, ha='center') if show_boundaries: x1, x2 = xplot.min(), xplot.max() y1, y2 = yplot.min(), yplot.max() ax.plot((x1, x2), (y1, y1), boundary_line, lw=boundary_linewidth) ax.plot((x1, x2), (y2, y2), boundary_line, lw=boundary_linewidth) ax.plot((x1, x1), (y1, y2), boundary_line, lw=boundary_linewidth) ax.plot((x2, x2), (y1, y2), boundary_line, lw=boundary_linewidth) if colorbar: from mpl_toolkits.axes_grid1 import make_axes_locatable fsize = cbar_fontsize divider = make_axes_locatable(ax) cax = divider.append_axes('right', size='5%', pad=0.05) cbarticks = linspace(vecmin, vecmax, cbar_nticks) cbar = plt.colorbar(contour, ticks=cbarticks, format=cbar_format, cax=cax) if cbar_title: cax.text(0.5, 1.05, cbar_title, horizontalalignment='center', verticalalignment='bottom', fontsize=fsize) cbar.outline.remove() cbar.ax.tick_params(labelsize=fsize, pad=0., tick2On=False) if title != '': ax.set_title(str(title)) fig.tight_layout() ax.set_aspect(aspect) ax.grid(False) ax.set_frame_on(False) if clean: ax.xaxis.set_ticks_position('none') ax.yaxis.set_ticks_position('none') ax.xaxis.set_ticklabels([]) ax.yaxis.set_ticklabels([]) else: ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') for kwargs in texts: ax.text(transform=ax.transAxes, **kwargs) if save: if not filename: filename = group + '.png' fig.savefig(filename, transparent=True, bbox_inches='tight', pad_inches=0.05, dpi=dpi) plt.close() msg('finished!') return ax, data
def calc_k0(self, size=None, row0=0, col0=0, silent=False, finalize=True): """Calculate the linear constitutive stiffness matrix """ self._rebuild() msg('Calculating k0... ', level=2, silent=silent) # NOTE # row0 and col0 define where the stiffener's base matrix starts # rowf and colf define where the stiffener's flange matrix starts rowf = row0 + self.base.get_size() colf = col0 + self.base.get_size() k0 = 0. k0 += self.base.calc_k0(size=size, row0=row0, col0=col0, silent=True, finalize=False) k0 += self.flange.calc_k0(size=size, row0=rowf, col0=colf, silent=True, finalize=False) # connectivity panel-base conn = stiffmDB.db[self.model]['connections'] ktpb, krpb = calc_kt_kr(self.panel1, self.base, 'bot-top') ktpb = min(1.e7, ktpb) #TODO remove from Cython the capability to run with debonding defect y1 = self.ys - self.base.b / 2. y2 = self.ys + self.base.b / 2. bay = self.bay k0 += conn.fkCppy1y2(y1, y2, ktpb, bay.a, bay.b, self.dpb, bay.m, bay.n, bay.u1tx, bay.u1rx, bay.u2tx, bay.u2rx, bay.v1tx, bay.v1rx, bay.v2tx, bay.v2rx, bay.w1tx, bay.w1rx, bay.w2tx, bay.w2rx, bay.u1ty, bay.u1ry, bay.u2ty, bay.u2ry, bay.v1ty, bay.v1ry, bay.v2ty, bay.v2ry, bay.w1ty, bay.w1ry, bay.w2ty, bay.w2ry, size, 0, 0) k0 += conn.fkCpby1y2( y1, y2, ktpb, bay.a, bay.b, self.dpb, bay.m, bay.n, self.base.m, self.base.n, bay.u1tx, bay.u1rx, bay.u2tx, bay.u2rx, bay.v1tx, bay.v1rx, bay.v2tx, bay.v2rx, bay.w1tx, bay.w1rx, bay.w2tx, bay.w2rx, bay.u1ty, bay.u1ry, bay.u2ty, bay.u2ry, bay.v1ty, bay.v1ry, bay.v2ty, bay.v2ry, bay.w1ty, bay.w1ry, bay.w2ty, bay.w2ry, self.base.u1tx, self.base.u1rx, self.base.u2tx, self.base.u2rx, self.base.v1tx, self.base.v1rx, self.base.v2tx, self.base.v2rx, self.base.w1tx, self.base.w1rx, self.base.w2tx, self.base.w2rx, self.base.u1ty, self.base.u1ry, self.base.u2ty, self.base.u2ry, self.base.v1ty, self.base.v1ry, self.base.v2ty, self.base.v2ry, self.base.w1ty, self.base.w1ry, self.base.w2ty, self.base.w2ry, size, 0, col0) k0 += conn.fkCbbpby1y2(y1, y2, ktpb, bay.a, bay.b, self.base.m, self.base.n, self.base.u1tx, self.base.u1rx, self.base.u2tx, self.base.u2rx, self.base.v1tx, self.base.v1rx, self.base.v2tx, self.base.v2rx, self.base.w1tx, self.base.w1rx, self.base.w2tx, self.base.w2rx, self.base.u1ty, self.base.u1ry, self.base.u2ty, self.base.u2ry, self.base.v1ty, self.base.v1ry, self.base.v2ty, self.base.v2ry, self.base.w1ty, self.base.w1ry, self.base.w2ty, self.base.w2ry, size, row0, col0) # connectivity base-flange ktbf, krbf = calc_kt_kr(self.base, self.flange, 'ycte') ycte1 = (self.eta_conn_base + 1) / 2. * self.base.b ycte2 = (self.eta_conn_flange + 1) / 2. * self.flange.b k0 += fkCBFycte11(ktbf, krbf, self.base, ycte1, size, row0, col0) k0 += fkCBFycte12(ktbf, krbf, self.base, self.flange, ycte1, ycte2, size, row0, colf) k0 += fkCBFycte22(ktbf, krbf, self.base, self.flange, ycte2, size, rowf, colf) if finalize: k0 = finalize_symmetric_matrix(k0) self.k0 = k0 #NOTE forcing Python garbage collector to clean the memory # it DOES make a difference! There is a memory leak not # identified, probably in the csr_matrix process gc.collect() msg('finished!', level=2, silent=silent)
def calc_k0(self, size=None, row0=0, col0=0, silent=False, finalize=True): """Calculate the linear constitutive stiffness matrix """ self._rebuild() msg('Calculating k0... ', level=2, silent=silent) flangemod = panmodelDB.db[self.flange.model]['matrices'] bay = self.bay a = bay.a b = bay.b m = bay.m n = bay.n k0 = 0. if self.base is not None: k0 += self.base.calc_k0(size=size, row0=0, col0=0, silent=True, finalize=False) if self.flange is not None: k0 += self.flange.calc_k0(size=size, row0=row0, col0=col0, silent=True, finalize=False) # connectivity between stiffener'base and stiffener's flange if self.base is None: ktbf, krbf = calc_kt_kr(self.panel1, self.flange, 'ycte') else: ktbf, krbf = calc_kt_kr(self.base, self.flange, 'ycte') mod = db['bladestiff2d_clt_donnell_bardell']['connections'] k0 += mod.fkCss(ktbf, krbf, self.ys, a, b, m, n, bay.u1tx, bay.u1rx, bay.u2tx, bay.u2rx, bay.v1tx, bay.v1rx, bay.v2tx, bay.v2rx, bay.w1tx, bay.w1rx, bay.w2tx, bay.w2rx, bay.u1ty, bay.u1ry, bay.u2ty, bay.u2ry, bay.v1ty, bay.v1ry, bay.v2ty, bay.v2ry, bay.w1ty, bay.w1ry, bay.w2ty, bay.w2ry, size, 0, 0) bf = self.flange.b k0 += mod.fkCsf( ktbf, krbf, self.ys, a, b, bf, m, n, self.flange.m, self.flange.n, bay.u1tx, bay.u1rx, bay.u2tx, bay.u2rx, bay.v1tx, bay.v1rx, bay.v2tx, bay.v2rx, bay.w1tx, bay.w1rx, bay.w2tx, bay.w2rx, bay.u1ty, bay.u1ry, bay.u2ty, bay.u2ry, bay.v1ty, bay.v1ry, bay.v2ty, bay.v2ry, bay.w1ty, bay.w1ry, bay.w2ty, bay.w2ry, self.flange.u1tx, self.flange.u1rx, self.flange.u2tx, self.flange.u2rx, self.flange.v1tx, self.flange.v1rx, self.flange.v2tx, self.flange.v2rx, self.flange.w1tx, self.flange.w1rx, self.flange.w2tx, self.flange.w2rx, self.flange.u1ty, self.flange.u1ry, self.flange.u2ty, self.flange.u2ry, self.flange.v1ty, self.flange.v1ry, self.flange.v2ty, self.flange.v2ry, self.flange.w1ty, self.flange.w1ry, self.flange.w2ty, self.flange.w2ry, size, 0, col0) k0 += mod.fkCff( ktbf, krbf, a, bf, self.flange.m, self.flange.n, self.flange.u1tx, self.flange.u1rx, self.flange.u2tx, self.flange.u2rx, self.flange.v1tx, self.flange.v1rx, self.flange.v2tx, self.flange.v2rx, self.flange.w1tx, self.flange.w1rx, self.flange.w2tx, self.flange.w2rx, self.flange.u1ty, self.flange.u1ry, self.flange.u2ty, self.flange.u2ry, self.flange.v1ty, self.flange.v1ry, self.flange.v2ty, self.flange.v2ry, self.flange.w1ty, self.flange.w1ry, self.flange.w2ty, self.flange.w2ry, size, row0, col0) if finalize: k0 = finalize_symmetric_matrix(k0) self.k0 = k0 #NOTE forcing Python garbage collector to clean the memory # it DOES make a difference! There is a memory leak not # identified, probably in the csr_matrix process gc.collect() msg('finished!', level=2, silent=silent)
def calc_Vf(self, rho=None, M=None, modes=(0, 1, 2, 3, 4, 5), num=10, silent=False): r"""Calculate the flutter speed If ``rho`` and ``M`` are not supplied, ``beta`` will be returned. Parameters ---------- rho : float, optional Air density. M : float, optional Mach number. modes : tuple, optional The modes that should be monitored. num : int, optional Number of points to search for each iteration. Returns ------- lambdacr : float The critical ``beta``. """ #TODO # - use a linear or parabolic interpolation to estimate new_lim1 msg('Flutter calculation...', level=1, silent=silent) lim1 = 0.1 lim2 = 100. new_lim1 = 1e6 new_lim2 = -1e6 eigvals_imag = np.zeros((num, len(modes))) if max(modes) > self.num_eigvalues-1: self.num_eigvalues = max(modes)+1 count = 0 while True: count += 1 betas = np.linspace(lim1, lim2, num) msg('iteration %d:' % count, level=2, silent=silent) msg('lambda_min: %1.3f' % lim1, level=3, silent=silent) msg('lambda_max: %1.3f' % lim2, level=3, silent=silent) for i, beta in enumerate(betas): self.beta = beta self.freq(atype=1, sparse_solver=False, silent=True) for j, mode in enumerate(modes): eigvals_imag[i, j] = self.eigvals[mode].imag check = np.where(eigvals_imag != 0.) if not np.any(check): continue if np.abs(eigvals_imag[check]).min() < 0.01: break if 0 in check[0]: new_lim1 = min(new_lim1, 0.5*betas[check[0][0]]) new_lim2 = max(new_lim2, 1.5*betas[check[0][-1]]) elif check[0].min() > 0: new_lim1 = betas[check[0][0]-1] new_lim2 = betas[check[0][0]] else: new_lim1 = min(new_lim1, lim1/2.) new_lim2 = max(new_lim2, 2*lim2) lim1 = new_lim1 lim2 = new_lim2 msg('finished!', level=1) msg('Number of analyses = %d' % (count*num), level=1) return lim1
def freq(K, M, tol=0, sparse_solver=True, silent=False, sort=True, reduced_dof=False, num_eigvalues=25, num_eigvalues_print=5): """Frequency Analysis Parameters ---------- K : sparse_matrix Stiffness matrix. Should include initial stress stiffness matrix, aerodynamic matrix and so forth when applicable. M : sparse_matrix Mass matrix. tol : float, optional A tolerance value passed to ``scipy.sparse.linalg.eigs``. sparse_solver : bool, optional Tells if solver :func:`scipy.linalg.eig` or :func:`scipy.sparse.linalg.eigs` should be used. .. note:: It is recommended ``sparse_solver=False``, because it was verified that the sparse solver becomes unstable for some cases, though the sparse solver is faster. silent : bool, optional A boolean to tell whether the log messages should be printed. sort : bool, optional Sort the output eigenvalues and eigenmodes. reduced_dof : bool, optional Considers only the contributions of `v` and `w` to the stiffness matrix and accelerates the run. Only effective when ``sparse_solver=False``. num_eigvalues : int, optional Number of calculated eigenvalues. num_eigvalues_print : int, optional Number of eigenvalues to print. Returns ------- The extracted eigenvalues are stored in the ``eigvals`` parameter and the `i^{th}` eigenvector in the ``eigvecs[:, i-1]`` parameter. """ msg('Running frequency analysis...', silent=silent) msg('Eigenvalue solver... ', level=2, silent=silent) k = min(num_eigvalues, M.shape[0]-2) if sparse_solver: msg('eigs() solver...', level=3, silent=silent) sizebkp = M.shape[0] K, M, used_cols = remove_null_cols(K, M, silent=silent, level=3) #NOTE Looking for better performance with symmetric matrices, I tried # using compmech.sparse.is_symmetric and eigsh, but it seems not # to improve speed (I did not try passing only half of the sparse # matrices to the solver) eigvals, peigvecs = eigs(A=K, k=k, which='LM', M=M, tol=tol, sigma=-1.) eigvecs = np.zeros((sizebkp, num_eigvalues), dtype=peigvecs.dtype) eigvecs[used_cols, :] = peigvecs eigvals = np.sqrt(eigvals) # omega^2 to omega, in rad/s else: msg('eig() solver...', level=3, silent=silent) M = M.toarray() K = K.toarray() sizebkp = M.shape[0] col_sum = M.sum(axis=0) check = col_sum != 0 used_cols = np.arange(M.shape[0])[check] M = M[:, check][check, :] K = K[:, check][check, :] if reduced_dof: i = np.arange(M.shape[0]) take = np.column_stack((i[1::3], i[2::3])).flatten() M = M[:, take][take, :] K = K[:, take][take, :] #TODO did not try using eigh when input is symmetric to see if there # will be speed improvements eigvals, peigvecs = eig(a=-M, b=K) eigvecs = np.zeros((sizebkp, K.shape[0]), dtype=peigvecs.dtype) eigvecs[check, :] = peigvecs eigvals = np.sqrt(-1./eigvals) # -1/omega^2 to omega, in rad/s eigvals = eigvals msg('finished!', level=3, silent=silent) if sort: sort_ind = np.lexsort((np.round(eigvals.imag, 1), np.round(eigvals.real, 1))) eigvals = eigvals[sort_ind] eigvecs = eigvecs[:, sort_ind] higher_zero = eigvals.real > 1e-6 eigvals = eigvals[higher_zero] eigvecs = eigvecs[:, higher_zero] if not sparse_solver and reduced_dof: new_eigvecs = np.zeros((3*eigvecs.shape[0]//2, eigvecs.shape[1]), dtype=eigvecs.dtype) new_eigvecs[take, :] = eigvecs eigvecs = new_eigvecs msg('finished!', level=2, silent=silent) msg('first {0} eigenvalues:'.format(num_eigvalues_print), level=1, silent=silent) for eigval in eigvals[:num_eigvalues_print]: msg('{0} rad/s'.format(eigval), level=2, silent=silent) return eigvals, eigvecs
def _solver_NR(run, silent=False): """Newton-Raphson solver """ msg('Initialization...', level=1, silent=silent) modified_NR = run.modified_NR inc = run.initialInc total = inc once_at_total = False max_total = 0. fext = run.calc_fext(inc=inc, silent=silent) k0 = run.calc_k0(silent=silent) c = solve(k0, fext, silent=silent) kT_last = k0 if modified_NR: compute_kT = False else: compute_kT = True step_num = 1 while True: msg('Started Load Step {} - '.format(step_num) + 'Attempting time = {0}'.format(total), level=1, silent=silent) # TODO maybe for pdC=True, pdT the fext must be calculated with # the last kT available... absERR = 1.e6 relERR = 1.e6 min_Rmax = 1.e6 prev_Rmax = 1.e6 last_min_Rmax = 1.e6 iteration = 0 converged = False kT = kT_last fext = run.calc_fext(inc=total, silent=silent) iter_NR = 0 while True: iteration += 1 msg('Iteration: {}'.format(iteration), level=2, silent=silent) if iteration > run.maxNumIter: warn('Maximum number of iterations achieved!', level=2, silent=silent) break if compute_kT or (run.kT_initial_state and step_num == 1 and iteration == 1) or iter_NR == (run.compute_every_n - 1): iter_NR = 0 kT = run.calc_kT(c=c, inc=total, silent=silent) else: iter_NR += 1 if not modified_NR: compute_kT = True fint = run.calc_fint(c=c, inc=total, silent=silent) R = fext - fint # convergence criteria: # - maximum residual force Rmax Rmax = np.abs(R).max() msg('Rmax = {0}'.format(Rmax), level=3, silent=silent) if iteration >= 2 and Rmax < run.absTOL: converged = True break if (Rmax > prev_Rmax and Rmax > min_Rmax and iteration > 2): warn('Diverged!', level=2, silent=silent) break else: min_Rmax = min(min_Rmax, Rmax) change_rate_Rmax = abs(prev_Rmax - Rmax) / abs(prev_Rmax) if (iteration > 2 and change_rate_Rmax < run.too_slow_TOL): warn('Diverged! (convergence too slow)', level=2, silent=silent) break prev_Rmax = Rmax msg('Solving... ', level=2, silent=silent) delta_c = solve(kT, R, silent=silent) msg('finished!', level=2, silent=silent) eta1 = 0. eta2 = 1. if run.line_search: msg('Performing line-search... ', level=2, silent=silent) iter_line_search = 0 while True: c1 = c + eta1 * delta_c c2 = c + eta2 * delta_c fint1 = run.calc_fint(c=c1, inc=total, silent=silent) fint2 = run.calc_fint(c=c2, inc=total, silent=silent) R1 = fext - fint1 R2 = fext - fint2 s1 = delta_c.dot(R1) s2 = delta_c.dot(R2) eta_new = (eta2 - eta1) * (-s1 / (s2 - s1)) + eta1 eta1 = eta2 eta2 = eta_new eta2 = min(max(eta2, 0.2), 10.) if abs(eta2 - eta1) < 0.01: break iter_line_search += 1 if iter_line_search == run.max_iter_line_search: eta2 = 1. warn('maxinum number of iterations', level=3, silent=silent) break msg('finished!', level=2, silent=silent) c = c + eta2 * delta_c if converged: msg('Finished Load Step {} at'.format(step_num) + ' time = {0}'.format(total), level=1, silent=silent) run.increments.append(total) run.cs.append(c.copy()) #NOTE copy required finished = False if abs(total - 1) < 1e-3: finished = True else: factor = 1.1 if once_at_total: inc_new = min(factor * inc, run.maxInc, (1. - total) / 2) else: inc_new = min(factor * inc, run.maxInc, 1. - total) msg('Changing time increment from {0:1.9f} to {1:1.9f}'.format( inc, inc_new), level=1, silent=silent) inc = inc_new total += inc total = min(1, total) step_num += 1 if finished: break if modified_NR: msg('Updating kT...', level=1, silent=silent) kT = run.calc_kT(c=c, inc=total, silent=silent) msg('kT updated!', level=1, silent=silent) compute_kT = False kT_last = kT else: max_total = max(max_total, total) while True: factor = 0.3 msg('Bisecting time increment from {0} to {1}'.format( inc, inc * factor), level=1, silent=silent) if abs(total - 1) < 1e-3: once_at_total = True total -= inc inc *= factor if inc < run.minInc: msg('Minimum step size achieved!', level=1, silent=silent) break total += inc if total >= max_total: continue else: break if inc < run.minInc: msg('Stopping solver: minimum step size achieved!', level=1, silent=silent) break if len(run.cs) > 0: c = run.cs[-1].copy() #NOTE copy required else: # means that run bisection must be done in initialInc fext = run.calc_fext(inc=inc, silent=silent) c = solve(k0, fext, silent=silent) msg('Finished Non-Linear Static Analysis', silent=silent) msg('at time {0}'.format(total), level=1, silent=silent)
def plot_skin(self, c, invert_y=False, plot_type=1, vec='w', deform_u=False, deform_u_sf=100., filename='', ax=None, figsize=(3.5, 2.), save=True, add_title=False, title='', colorbar=False, cbar_nticks=2, cbar_format=None, cbar_title='', cbar_fontsize=10, aspect='equal', clean=True, dpi=400, texts=[], xs=None, ys=None, gridx=300, gridy=300, num_levels=400, vecmin=None, vecmax=None): r"""Contour plot for a Ritz constants vector. Parameters ---------- c : np.ndarray The Ritz constants that will be used to compute the field contour. vec : str, optional Can be one of the components: - Displacement: ``'u'``, ``'v'``, ``'w'``, ``'phix'``, ``'phiy'`` - Strain: ``'exx'``, ``'eyy'``, ``'gxy'``, ``'kxx'``, ``'kyy'``, ``'kxy'``, ``'gyz'``, ``'gxz'`` - Stress: ``'Nxx'``, ``'Nyy'``, ``'Nxy'``, ``'Mxx'``, ``'Myy'``, ``'Mxy'``, ``'Qy'``, ``'Qx'`` deform_u : bool, optional If ``True`` the contour plot will look deformed. deform_u_sf : float, optional The scaling factor used to deform the contour. invert_y : bool, optional Inverts the `y` axis of the plot. It may be used to match the coordinate system of the finite element models created using the ``desicos.abaqus`` module. plot_type : int, optional For cylinders only ``4`` and ``5`` are valid. For cones all the following types can be used: - ``1``: concave up (with ``invert_y=False``) (default) - ``2``: concave down (with ``invert_y=False``) - ``3``: stretched closed - ``4``: stretched opened (`r \times y` vs. `a`) - ``5``: stretched opened (`y` vs. `a`) save : bool, optional Flag telling whether the contour should be saved to an image file. dpi : int, optional Resolution of the saved file in dots per inch. filename : str, optional The file name for the generated image file. If no value is given, the `name` parameter of the :class:`StiffPanelBay` object will be used. ax : AxesSubplot, optional When ``ax`` is given, the contour plot will be created inside it. figsize : tuple, optional The figure size given by ``(width, height)``. add_title : bool, optional If a title should be added to the figure. title : str, optional If any string is given ``add_title`` will be ignored and the given title added to the contour plot. colorbar : bool, optional If a colorbar should be added to the contour plot. cbar_nticks : int, optional Number of ticks added to the colorbar. cbar_format : [ None | format string | Formatter object ], optional See the ``matplotlib.pyplot.colorbar`` documentation. cbar_fontsize : int, optional Fontsize of the colorbar labels. cbar_title : str, optional Colorbar title. If ``cbar_title == ''`` no title is added. aspect : str, optional String that will be passed to the ``AxesSubplot.set_aspect()`` method. clean : bool, optional Clean axes ticks, grids, spines etc. xs : np.ndarray, optional The `x` positions where to calculate the displacement field. Default is ``None`` and the method ``_default_field`` is used. ys : np.ndarray, optional The ``y`` positions where to calculate the displacement field. Default is ``None`` and the method ``_default_field`` is used. gridx : int, optional Number of points along the `x` axis where to calculate the displacement field. gridy : int, optional Number of points along the `y` where to calculate the displacement field. num_levels : int, optional Number of contour levels (higher values make the contour smoother). vecmin : float, optional Minimum value for the contour scale (useful to compare with other results). If not specified it will be taken from the calculated field. vecmax : float, optional Maximum value for the contour scale. Returns ------- ax : matplotlib.axes.Axes The Matplotlib object that can be used to modify the current plot if needed. """ msg('Plotting contour...') ubkp, vbkp, wbkp, phixbkp, phiybkp = (self.u, self.v, self.w, self.phix, self.phiy) import matplotlib.pyplot as plt import matplotlib msg('Computing field variables...', level=1) displs = ['u', 'v', 'w', 'phix', 'phiy'] if vec in displs: self.uvw_skin(c, xs=xs, ys=ys, gridx=gridx, gridy=gridy) field = getattr(self, vec) else: raise ValueError( '{0} is not a valid vec parameter value!'.format(vec)) msg('Finished!', level=1) Xs = self.Xs Ys = self.Ys if vecmin is None: vecmin = field.min() if vecmax is None: vecmax = field.max() levels = linspace(vecmin, vecmax, num_levels) if ax is None: fig = plt.figure(figsize=figsize) ax = fig.add_subplot(111) else: if isinstance(ax, matplotlib.axes.Axes): ax = ax fig = ax.figure save = False else: raise ValueError('ax must be an Axes object') x = Ys y = Xs if deform_u: if vec in displs: pass else: self.uvw_skin(c, xs=xs, ys=ys, gridx=gridx, gridy=gridy) field_u = self.u field_v = self.v y -= deform_u_sf*field_u x += deform_u_sf*field_v contour = ax.contourf(x, y, field, levels=levels) if colorbar: from mpl_toolkits.axes_grid1 import make_axes_locatable fsize = cbar_fontsize divider = make_axes_locatable(ax) cax = divider.append_axes('right', size='5%', pad=0.05) cbarticks = linspace(vecmin, vecmax, cbar_nticks) cbar = plt.colorbar(contour, ticks=cbarticks, format=cbar_format, cax=cax) if cbar_title: cax.text(0.5, 1.05, cbar_title, horizontalalignment='center', verticalalignment='bottom', fontsize=fsize) cbar.outline.remove() cbar.ax.tick_params(labelsize=fsize, pad=0., tick2On=False) if invert_y == True: ax.invert_yaxis() ax.invert_xaxis() if title != '': ax.set_title(str(title)) elif add_title: if self.analysis.last_analysis == 'static': ax.set_title('$m, n={0}, {1}$'.format(self.m, self.n)) elif self.analysis.last_analysis == 'lb': ax.set_title( r'$m, n={0}, {1}$, $\lambda_{{CR}}={4:1.3e}$'.format( self.m, self.n, self.eigvals[0])) fig.tight_layout() ax.set_aspect(aspect) ax.grid(False) ax.set_frame_on(False) if clean: ax.xaxis.set_ticks_position('none') ax.yaxis.set_ticks_position('none') ax.xaxis.set_ticklabels([]) ax.yaxis.set_ticklabels([]) else: ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') for kwargs in texts: ax.text(transform=ax.transAxes, **kwargs) if save: if not filename: filename = 'test.png' fig.savefig(filename, transparent=True, bbox_inches='tight', pad_inches=0.05, dpi=dpi) plt.close() if ubkp is not None: self.u = ubkp if vbkp is not None: self.v = vbkp if wbkp is not None: self.w = wbkp if phixbkp is not None: self.phix = phixbkp if phiybkp is not None: self.phiy = phiybkp msg('finished!') return ax
def inv_weighted(data, mesh, num_sub, col, ncp=5, power_parameter=2): r"""Interpolates the values taken at one group of points into another using an inverse-weighted algorithm In the inverse-weighted algorithm a number of `n_{CP}` measured points of the input parameter ``data`` that are closest to a given node in the input parameter ``mesh`` are found and the imperfection value of this node (represented by the normal displacement `{w_0}_{node}`) is calculated as follows: .. math:: {w_0}_{node} = \frac{\sum_{i}^{n_{CP}}{{w_0}_i\frac{1}{w_i}}} {\sum_{i}^{n_{CP}}{\frac{1}{w_i}}} where `w_i` is the imperfection at each measured point, calculated as: .. math:: w_i = \left[(x_{node}-x_i)^2+(y_{node}-y_i)^2+(z_{node}-y_i)^2 \right]^p with `p` being a power parameter that when increased will increase the relative influence of a closest point. Parameters ---------- data : numpy.ndarray, shape (N, ndim+1) The data or an array containing the imperfection file. The values to be interpolated must be in the last column. mesh : numpy.ndarray, shape (M, ndim) The new coordinates where the values will be interpolated to. num_sub : int The number of sub-sets used during the interpolation. The points are divided in sub-sets to increase the algorithm's efficiency. col : int The index of the column to be used in order to divide the data in sub-sets. Note that the first column index is ``0``. ncp : int, optional Number of closest points used in the inverse-weighted interpolation. power_parameter : float, optional Power of inverse weighted interpolation function. Returns ------- ans : numpy.ndarray A 1-D array with the interpolated values. The size of this array is ``mesh.shape[0]``. """ if mesh.shape[1] != data.shape[1] - 1: raise ValueError('Invalid input: mesh.shape[1] != data.shape[1]') msg('Interpolating... ') num_sub = int(num_sub) mesh_size = mesh.shape[0] # memory control mem_limit = 1024 * 1024 * 1024 * 8 * 2 # 2 GB mem_entries = int(mem_limit / 64) # if float64 is used sec_size = int(mesh_size / num_sub) while sec_size**2 * 10 > mem_entries: num_sub += 1 sec_size = int(mesh_size / num_sub) if sec_size**2 * 10 <= mem_entries: warn('New num_sub: {0}'.format(int(mesh_size / float(sec_size)))) break mesh_seq = np.arange(mesh.shape[0]) mesh_argsort = np.argsort(mesh[:, col]) mesh_seq = mesh_seq[mesh_argsort] back_argsort = np.argsort(mesh_seq) mesh = np.asarray(mesh[mesh_argsort], order='F') length = mesh[:, col].max() - mesh[:, col].min() data = np.asarray(data[np.argsort(data[:, col])], order='F') ans = np.zeros(mesh.shape[0], dtype=mesh.dtype) # max_num_limits defines how many times the log will print # "processed ... out of ... entries" max_num_limits = 10 for den in range(max_num_limits, 0, -1): if num_sub % den == 0: limit = int(num_sub / den) break for i in range(num_sub + 1): i_inf = sec_size * i i_sup = sec_size * (i + 1) if i % limit == 0: msg('\t processed {0:7d} out of {1:7d} entries'.format( min(i_sup, mesh_size), mesh_size)) sub_mesh = mesh[i_inf:i_sup] if not np.any(sub_mesh): continue inf = sub_mesh[:, col].min() sup = sub_mesh[:, col].max() tol = 0.03 if i == 0 or i == num_sub: tol = 0.06 while True: cond1 = data[:, col] >= inf - tol * length cond2 = data[:, col] <= sup + tol * length cond = np.all(np.array((cond1, cond2)), axis=0) sub_data = data[cond] if not np.any(sub_data): tol += 0.01 else: break dist = np.subtract.outer(sub_mesh[:, 0], sub_data[:, 0])**2 for j in range(1, sub_mesh.shape[1]): dist += np.subtract.outer(sub_mesh[:, j], sub_data[:, j])**2 asort = np.argsort(dist, axis=1) lenn = sub_mesh.shape[0] lenp = sub_data.shape[0] asort_mesh = asort + np.meshgrid( np.arange(lenn) * lenp, np.arange(lenp))[0].transpose() # getting the distance of the closest points dist_cp = np.take(dist, asort_mesh[:, :ncp]) # avoiding division by zero dist_cp[(dist_cp == 0)] == 1.e-12 # fetching the imperfection of the sub-data imp = sub_data[:, -1] # taking only the imperfection of the closest points imp_cp = np.take(imp, asort[:, :ncp]) # weight calculation total_weight = np.sum(1. / (dist_cp**power_parameter), axis=1) weight = 1. / (dist_cp**power_parameter) # computing the new imp imp_new = np.sum(imp_cp * weight, axis=1) / total_weight # updating the answer array ans[i_inf:i_sup] = imp_new ans = ans[back_argsort] msg('Interpolation completed!') return ans
def lb(K, KG, tol=0, sparse_solver=True, silent=False, num_eigvalues=25, num_eigvalues_print=5): """Linear Buckling Analysis It can also be used for more general eigenvalue analyzes if `K` is the tangent stiffness matrix of a given load state. Parameters ---------- K : sparse_matrix Stiffness matrix. Should include all constant terms of the initial stress stiffness matrix, aerodynamic matrix and so forth when applicable. KG : sparse_matrix Initial stress stiffness matrix that multiplies the load multiplcator `\lambda` of the eigenvalue problem. tol : float, optional A float tolerance passsed to the eigenvalue solver. sparse_solver : bool, optional Tells if solver :func:`scipy.linalg.eigh` or :func:`scipy.sparse.linalg.eigsh` should be used. silent : bool, optional A boolean to tell whether the log messages should be printed. num_eigvalues : int, optional Number of calculated eigenvalues. num_eigvalues_print : int, optional Number of eigenvalues to print. Notes ----- The extracted eigenvalues are stored in the ``eigvals`` parameter of the ``Panel`` object and the `i^{th}` eigenvector in the ``eigvecs[:, i-1]`` parameter. """ msg('Running linear buckling analysis...', silent=silent) msg('Eigenvalue solver... ', level=2, silent=silent) k = min(num_eigvalues, KG.shape[0]-2) if sparse_solver: mode = 'cayley' try: msg('eigsh() solver...', level=3, silent=silent) eigvals, eigvecs = eigsh(A=KG, k=k, which='SM', M=K, tol=tol, sigma=1., mode=mode) msg('finished!', level=3, silent=silent) except Exception as e: warn(str(e), level=4, silent=silent) msg('aborted!', level=3, silent=silent) sizebkp = KG.shape[0] K, KG, used_cols = remove_null_cols(K, KG, silent=silent) msg('eigsh() solver...', level=3, silent=silent) eigvals, peigvecs = eigsh(A=KG, k=k, which='SM', M=K, tol=tol, sigma=1., mode=mode) msg('finished!', level=3, silent=silent) eigvecs = np.zeros((sizebkp, num_eigvalues), dtype=peigvecs.dtype) eigvecs[used_cols, :] = peigvecs else: size = KG.shape[0] K, KG, used_cols = remove_null_cols(K, KG, silent=silent) K = K.toarray() KG = KG.toarray() msg('eigh() solver...', level=3, silent=silent) eigvals, peigvecs = eigh(a=KG, b=K) msg('finished!', level=3, silent=silent) eigvecs = np.zeros((size, num_eigvalues), dtype=peigvecs.dtype) eigvecs[used_cols, :] = peigvecs[:, :num_eigvalues] eigvals = -1./eigvals eigvals = eigvals eigvecs = eigvecs msg('finished!', level=2, silent=silent) msg('first {0} eigenvalues:'.format(num_eigvalues_print), level=1, silent=silent) for eig in eigvals[:num_eigvalues_print]: msg('{0}'.format(eig), level=2, silent=silent) return eigvals, eigvecs