Source code for desicos.abaqus.imperfections.uneven_edges

from __future__ import absolute_import

import numpy as np
from numpy import deg2rad, rad2deg, pi

from desicos.conecylDB.interpolate import interp


[docs]class Shim(object): """Represents a shim added to one of the edges ============== ========================================================= Attributes Description ============== ========================================================= edge An object of the class :class:`.UnevenTopEdge` thetadeg The circumferential position where the shim starts thick The shim thickness width The shim perimetrical width (along the shell perimeter) ============== ========================================================= """ def __init__(self,thetadeg, thick, width, edge=None): self.thetadeg = thetadeg self.thick = thick self.width = width self.edge = edge if edge is not None: self.edge.shims.append(self)
[docs]class UnevenBottomEdge(object): """Uneven Bottom Edge The following attributes are taken into account: - misalignment of the bottom edge - presence of shims - measured uneven edge points ============== ========================================================= Attributes Description ============== ========================================================= uneven_plate ``bool``: If the unevenness should be applied to the testing plate or to the test specimen betadeg Misalignment of the bottom edge in degrees omegadeg Azimuth angle of the bottom edge misalignment in degrees. shims ``list`` of shims included to this edge measured_u3s Measured points describing the edge imperfection ============== ========================================================= """ def __init__(self, betadeg=None, omegadeg=None): self.name = 'uneven_bottom_edge' self.index = None self.impconf = None self.thetadegs = [] self.pts = [] self.shims = [] self.measured_u3s = None self.scaling_factor = 1. self.uneven_plate = True # plotting options self.xaxis = 'scaling_factor' self.xaxis_label = 'Scaling factor' def __nonzero__(self): # in Python 3 this method was renamed to __bool__ return self.__bool__() def __bool__(self): cc = self.impconf.conecyl return (bool(self.shims) or bool(self.measured_u3s is not None) or bool(cc.bc_gaps_bottom_edge)) def rebuild(self): cc = self.impconf.conecyl self.thetadegs = [s.thetadeg for s in self.shims] self.thetadegs += [s.thetadeg + 360*s.width/(2*pi*cc.rbot) for s in self.shims] self.pts = []
[docs] def add_measured_u3s(self, thetadegs, u3s): """Adds measured data to the uneven bottom edge The edge imperfection that actually goes for each node is a linear interpolation of the measured values. Parameters ---------- thetadegs : list The circumferential positions where the imperfect bottom edge was measured, in degrees. u3s : list The measured imperfections representing displacements along the `X_3` axis :ref:`of the adopted model <figure_conecyl>`. """ if len(thetadegs) != len(u3s): raise ValueError('thetadegs must have the same length of u3s!') self.measured_u3s = np.array([thetadegs, u3s])
[docs] def add_shim(self, thetadeg, thick, width): """Adds a shim to the uneven bottom edge Parameters ---------- thetadeg : float Circumferential position where the shim starts. thick : float Thickness of the shim. width : float Perimetrical width of the shim (along the shell perimeter). Returns ------- shim : :class:`.Shim` object. """ shim = Shim(thetadeg, thick, width, edge=self) return shim
def calc_amplitude(self): return self.scaling_factor
[docs] def create(self): r"""Creates the uneven bottom edge imperfections The uneven bottom edge will be represented by many GAP elements created in such a way to consider all the imperfections contained in the current :class:`.UnevenBottomEdge` object. The output file ``cc.model_name + '_bottom_edge.gaps'`` will be created, where ``cc`` is the :class:`.ConeCyl` object that contains this :class:`.UnevenBottomEdge` object. The following steps are executed: - get the `\theta` coordinate of the bottom nodes from the shell and bottom resin rings - get imperfection from the ``shims`` attribute - get any additional imperfection of the bottom edge represented by ``measured_u3s`` Assumptions: - for a given `\theta` coordinate the uneven displacement is the same for all the shell and resin ring nodes .. note:: Must be called from Abaqus """ from abaqus import mdb from abaqusConstants import (PIN_MPC, DOF_MODE_MPC) from regionToolset import Region from desicos.abaqus.abaqus_functions import edit_keywords cc = self.impconf.conecyl mod = mdb.models[cc.model_name] ra = mod.rootAssembly def calc_gaps(nodes, yx=True): # calculating gaps # theta according to the assembly coordinate system coords = np.array([n.coordinates for n in nodes]) if yx: theta_nodes = np.arctan2(coords[:,1], coords[:,0]) else: theta_nodes = np.arctan2(-coords[:,2], coords[:,0]) # contributions from measured edge imperfection if self.measured_u3s is not None: measured_u3s = np.asarray(self.measured_u3s) else: measured_u3s = np.zeros((2, 100)) measured_u3s[0, :] = np.linspace(0, 360, 100) # calculating u3 for each node u3_nodes = interp(rad2deg(theta_nodes), measured_u3s[0, :], measured_u3s[1, :], period=360) # contributions from shims hs = np.zeros_like(theta_nodes) for s in self.shims: trad1 = deg2rad(s.thetadeg) trad2 = deg2rad(s.thetadeg + 360*s.width/(2*pi*cc.rbot)) thetarads = [trad1-0.001, trad1, trad2, trad2+0.001] u3s = [0, s.thick, s.thick, 0] tmp = interp(theta_nodes, thetarads, u3s, period=2*pi) hs += tmp u3_nodes += hs # applying scaling_factor u3_nodes *= self.scaling_factor # calculating gap values gaps = u3_nodes.max() - u3_nodes return gaps if not self.uneven_plate: # shell part = mod.parts[cc.part_name_shell] wdw = 2*cc.rbot zmin = -0.001 zmax = cc.resin_bot_h*1.001 nodes = part.nodes.getByBoundingBox(-wdw, -wdw, zmin, +wdw, +wdw, zmax) coords = np.array([n.coordinates for n in nodes]) coords[:, 2] += calc_gaps(nodes) labels = [n.label for n in nodes] meshNodeArray = nodes.sequenceFromLabels(labels) part.editNode(nodes=meshNodeArray, coordinates=coords) # bottom inner ring if cc.resin_add_TIR: mesh_arrays = [] coords_list = [] part = mod.parts['Bottom_IR'] coords = np.array([n.coordinates for n in part.nodes]) gaps = calc_gaps(part.nodes, yx=False) coords[:, 1] += gaps part.editNode(nodes=part.nodes, coordinates=coords) # bottom outer ring if cc.resin_add_TOR: mesh_arrays = [] coords_list = [] part = mod.parts['Bottom_OR'] coords = np.array([n.coordinates for n in part.nodes]) gaps = calc_gaps(part.nodes, yx=False) coords[:, 1] += gaps part.editNode(nodes=part.nodes, coordinates=coords) nodes_shell = np.array(ra.sets['shell_bottom_edges'].nodes) nodes_all = nodes_shell tshell = sum(cc.plyts) cosa = np.cos(cc.alpharad) if cc.resin_add_BIR: tmp = np.array(ra.sets['Bottom_IR_faces'].nodes) coords = np.array([n.coordinates for n in tmp]) r_nodes = np.sqrt(coords[:,0]**2 + coords[:,1]**2) # taking nodes that are not pinned to the shell check = (r_nodes < (cc.rbot - cosa*0.51*tshell)) nodes_all = np.hstack((nodes_all, tmp[check])) if cc.resin_add_BOR: tmp = np.array(ra.sets['Bottom_OR_faces'].nodes) coords = np.array([n.coordinates for n in tmp]) r_nodes = np.sqrt(coords[:,0]**2 + coords[:,1]**2) # taking nodes that are not pinned to the shell check = (r_nodes > (cc.rbot + cosa*0.51*tshell)) nodes_all = np.hstack((nodes_all, tmp[check])) # creating GAP elements rps_gap = [] text = '' gaps = calc_gaps(nodes_all) for node, gap in zip(nodes_all, gaps): coord = list(node.coordinates) coord[2] -= gap rp = ra.ReferencePoint(point=coord) inst_name = node.instanceName #TODO really bad approach, but couldn' find any other way to # get the actual node id that is printed in the .inp # file rp_id = int(rp.name.split('-')[1]) + 2 # rps_gap.append(rp) gap_name = 'gap_{0}_{1:d}'.format(inst_name, 1000000+node.label) inst_node = '{0}.{1:d}'.format(inst_name, node.label) text += ('\n*Element, type=GAPUNI, elset={0}'.format(gap_name)) text += ('\n{0:d},{1},{2:d}'.format(1000000+node.label, inst_node, rp_id)) text += '\n*GAP, elset={0}'.format(gap_name) text += '\n{0:f},0,0,-1\n'.format(gap) bottom_name_gaps = '{0}_bottom_edge.gaps'.format(cc.model_name) with open(bottom_name_gaps, 'w') as f: f.write(text) if not self.impconf.uneven_top_edge: pattern = '*Instance' text = '*INCLUDE, INPUT={0}'.format(bottom_name_gaps) edit_keywords(mod=mod, text=text, before_pattern=pattern) set_RP_bot=ra.sets['RP_bot'] rps = ra.referencePoints rps_gap_datums = [rps[rp.id] for rp in rps_gap] region = Region(referencePoints=rps_gap_datums) ra_cyl_csys = ra.features['ra_cyl_csys'] ra_cyl_csys = ra.datums[ra_cyl_csys.id] mod.MultipointConstraint(name='MPC_RP_GAPs_bot_edge', controlPoint=set_RP_bot, surface=region, mpcType=PIN_MPC, userMode=DOF_MODE_MPC, userType=0, csys=ra_cyl_csys)
[docs]class UnevenTopEdge(object): """Uneven Top Edge The following attributes are taken into account: - misalignment of the top edge - presence of shims - measured uneven edge points ============== ========================================================== Attributes Description ============== ========================================================== uneven_plate ``bool``: If the unevenness should be applied to the testing plate or to the test specimen betadeg ``float``: Misalignment of the top edge in degrees omegadeg ``float``: Azimuth angle of the top edge misalignment in degrees shims ``list`` of shims included to this edge measured_u3s Measured points describing the edge imperfection ============== ========================================================== """ def __init__(self, betadeg=None, omegadeg=None): self.name = 'uneven_top_edge' self.index = None self.impconf = None self.betadeg = betadeg self.omegadeg = omegadeg self.thetadegs = [] self.pts = [] self.shims = [] self.measured_u3s = None self.scaling_factor = 1. self.uneven_plate = True # plotting options self.xaxis = 'scaling_factor' self.xaxis_label = 'Scaling factor' def __nonzero__(self): # in Python 3 this method was renamed to __bool__ return self.__bool__() def __bool__(self): cc = self.impconf.conecyl return (bool(self.betadeg) or bool(self.shims) or bool(self.measured_u3s is not None) or bool(cc.bc_gaps_top_edge)) def rebuild(self): cc = self.impconf.conecyl self.thetadegs = [s.thetadeg for s in self.shims] self.thetadegs += [s.thetadeg + 360*s.width/(2*pi*cc.rtop) for s in self.shims] self.pts = []
[docs] def add_measured_u3s(self, thetadegs, u3s): """Adds measured data to the uneven top edge The edge imperfection that actually goes for each node is a linear interpolation of the measured values. Parameters ---------- thetadegs : list The circumferential positions where the imperfect top edge was measured, in degrees. u3s : list The measured imperfections representing displacements along the `X_3` axis :ref:`of the adopted model <figure_conecyl>`. """ if len(thetadegs) != len(u3s): raise ValueError('thetadegs must have the same length of u3s!') self.measured_u3s = np.array([thetadegs, u3s])
[docs] def add_shim(self, thetadeg, thick, width): """Adds a shim to the uneven top edge Parameters ---------- thetadeg : float Circumferential position where the shim starts. thick : float Thickness of the shim. width : float Perimetrical width of the shim (along the shell perimeter). Returns ------- shim : :class:`.Shim` object. """ shim = Shim(thetadeg, thick, width, edge=self) return shim
def calc_amplitude(self): return self.scaling_factor
[docs] def create(self): r"""Creates the uneven top edge imperfections The uneven top edge will be represented by many GAP elements created in such a way to consider all the imperfections contained in the current :class:`.UnevenTopEdge` object. The output file ``cc.model_name + '_top_edge.gaps'`` will be created, where ``cc`` is the :class:`.ConeCyl` object that contains this :class:`.UnevenTopEdge` object. The following steps are executed: - get the `\theta` coordinate of the top nodes from the shell and top resin rings - get imperfection from the ``shims`` attribute - get any additional imperfection of the top edge represented by ``measured_u3s`` - include effect of the misalignment angle ``betadeg`` Assumptions: - for a given `\theta` coordinate the uneven displacement is the same for all the shell and resin ring nodes, but the load asymmetry angle ``self.betadeg`` may change this equality. The contribution due to `\beta` is given by: .. math:: \Delta u_3 = R_{top} tan(\beta) cos(\theta-\omega) .. note:: Must be called from Abaqus """ from abaqus import mdb from abaqusConstants import (PIN_MPC, DOF_MODE_MPC) from regionToolset import Region from desicos.abaqus.abaqus_functions import edit_keywords cc = self.impconf.conecyl mod = mdb.models[cc.model_name] ra = mod.rootAssembly def calc_gaps(nodes, yx=True): # calculating gaps # theta according to the assembly coordinate system coords = np.array([n.coordinates for n in nodes]) if yx: theta_nodes = np.arctan2(coords[:,1], coords[:,0]) else: theta_nodes = np.arctan2(-coords[:,2], coords[:,0]) # contributions from measured edge imperfection if self.measured_u3s is not None: measured_u3s = np.asarray(self.measured_u3s) else: measured_u3s = np.zeros((2, 100)) measured_u3s[0, :] = np.linspace(0, 360, 100) # calculating u3 for each node u3_nodes = interp(rad2deg(theta_nodes), measured_u3s[0, :], measured_u3s[1, :], period=360) # applying load asymmetry according to cc.betarad and omega betadeg = self.betadeg if self.betadeg is not None else 0. betarad = deg2rad(betadeg) omegadeg = self.omegadeg if self.omegadeg is not None else 0. omegarad = deg2rad(omegadeg) u3_nodes -= cc.rtop*np.tan(betarad)*np.cos(theta_nodes-omegarad) # contributions from shims hs = np.zeros_like(theta_nodes) for s in self.shims: trad1 = deg2rad(s.thetadeg) trad2 = deg2rad(s.thetadeg + 360*s.width/(2*pi*cc.rtop)) thetarads = [trad1-0.001, trad1, trad2, trad2+0.001] u3s = [0, s.thick, s.thick, 0] tmp = interp(theta_nodes, thetarads, u3s, period=2*pi) hs += tmp u3_nodes -= hs # applying scaling_factor u3_nodes *= self.scaling_factor # calculating gap values gaps = u3_nodes - u3_nodes.min() return gaps if not self.uneven_plate: # shell part = mod.parts[cc.part_name_shell] wdw = 2*cc.rtop zmin = cc.H - cc.resin_top_h*1.001 zmax = 1.001*cc.H nodes = part.nodes.getByBoundingBox(-wdw, -wdw, zmin, +wdw, +wdw, zmax) coords = np.array([n.coordinates for n in nodes]) coords[:, 2] -= calc_gaps(nodes) labels = [n.label for n in nodes] meshNodeArray = nodes.sequenceFromLabels(labels) part.editNode(nodes=meshNodeArray, coordinates=coords) # top inner ring if cc.resin_add_TIR: mesh_arrays = [] coords_list = [] part = mod.parts['Top_IR'] coords = np.array([n.coordinates for n in part.nodes]) gaps = calc_gaps(part.nodes, yx=False) coords[:, 1] -= gaps part.editNode(nodes=part.nodes, coordinates=coords) # top outer ring if cc.resin_add_TOR: mesh_arrays = [] coords_list = [] part = mod.parts['Top_OR'] coords = np.array([n.coordinates for n in part.nodes]) gaps = calc_gaps(part.nodes, yx=False) coords[:, 1] -= gaps part.editNode(nodes=part.nodes, coordinates=coords) nodes_shell = np.array(ra.sets['shell_top_edges'].nodes) nodes_all = nodes_shell tshell = sum(cc.plyts) cosa = np.cos(cc.alpharad) if cc.resin_add_TIR: nodes_TIR_assembly = np.array(ra.sets['Top_IR_faces'].nodes) coords = np.array([n.coordinates for n in nodes_TIR_assembly]) r_nodes = np.sqrt(coords[:,0]**2 + coords[:,1]**2) # taking nodes that are not pinned to the shell check = (r_nodes < (cc.rtop - cosa*0.51*tshell)) nodes_all = np.hstack((nodes_all, nodes_TIR_assembly[check])) if cc.bc_fix_top_side_u3: tmp = np.array(ra.sets['Top_IR_faces_side'].nodes) coords = np.array([n.coordinates for n in tmp]) # taking nodes that are not on the top edge check = (coords[:,2] < (cc.H-0.1)) nodes_all = np.hstack((nodes_all, tmp[check])) if cc.resin_add_TOR: nodes_TOR_assembly = np.array(ra.sets['Top_OR_faces'].nodes) coords = np.array([n.coordinates for n in nodes_TOR_assembly]) r_nodes = np.sqrt(coords[:,0]**2 + coords[:,1]**2) # taking nodes that are not pinned to the shell check = (r_nodes > (cc.rtop + cosa*0.51*tshell)) nodes_all = np.hstack((nodes_all, nodes_TOR_assembly[check])) if cc.bc_fix_top_side_u3: tmp = np.array(ra.sets['Top_OR_faces_side'].nodes) coords = np.array([n.coordinates for n in tmp]) # taking nodes that are not on the top edge check = (coords[:,2] < (cc.H-0.1)) nodes_all = np.hstack((nodes_all, tmp[check])) # creating GAP elements rps_gap = [] text = '' gaps = calc_gaps(nodes_all) for node, gap in zip(nodes_all, gaps): coord = list(node.coordinates) coord[2] += gap rp = ra.ReferencePoint(point=coord) inst_name = node.instanceName #TODO really bad approach, but couldn' find any other way to # get the actual node id that is printed in the .inp # file rp_id = int(rp.name.split('-')[1]) + 2 # rps_gap.append(rp) gap_name = 'gap_{0}_{1:d}'.format(inst_name, 2000000+node.label) inst_node = '{0}.{1:d}'.format(inst_name, node.label) text += ('\n*Element, type=GAPUNI, elset={0}'.format(gap_name)) text += ('\n{0:d},{1:d},{2}'.format(2000000+node.label, rp_id, inst_node)) text += '\n*GAP, elset={0}'.format(gap_name) text += '\n{0:f},0,0,-1\n'.format(gap) top_name_gaps = '{0}_top_edge.gaps'.format(cc.model_name) with open(top_name_gaps, 'w') as f: f.write(text) pattern = '*Instance' if self.impconf.uneven_bottom_edge: bottom_name_gaps = '{0}_bottom_edge.gaps'.format(cc.model_name) text = '*INCLUDE, INPUT={0}'.format(bottom_name_gaps) text += '\n**\n*INCLUDE, INPUT={0}'.format(top_name_gaps) else: text = '*INCLUDE, INPUT={0}'.format(top_name_gaps) edit_keywords(mod=mod, text=text, before_pattern=pattern, insert=True) set_RP_top = ra.sets['RP_top'] rps = ra.referencePoints rps_gap_datums = [rps[rp.id] for rp in rps_gap] region = Region(referencePoints=rps_gap_datums) ra_cyl_csys = ra.features['ra_cyl_csys'] ra_cyl_csys = ra.datums[ra_cyl_csys.id] mod.MultipointConstraint(name='MPC_RP_GAPs_top_edge', controlPoint=set_RP_top, surface=region, mpcType=PIN_MPC, userMode=DOF_MODE_MPC, userType=0, csys=ra_cyl_csys)