def create_prop_around_cutout(self): if self.prop_around_cutout is not None: from abaqus import mdb from abaqusConstants import CYLINDRICAL cc = self.impconf.conecyl mod = mdb.models[cc.model_name] p = mod.parts[cc.part_name_shell] if not isinstance(self.prop_around_cutout, dict): raise ValueError('prop_around_cutout must be a dictionary') mode = self.prop_around_cutout['mode'] stack = self.prop_around_cutout['stack'] plyts = self.prop_around_cutout['plyts'] mat_names = self.prop_around_cutout['mat_names'] if mode == 'radius': radius = self.prop_around_cutout['radius'] elem_set = p.Set(name='elems_around_cutout_%02d' % self.index, elements=p.elements.getByBoundingCylinder( center1=self.p0coord, center2=self.p2coord, radius=radius)) elif mode == 'partition': selection_radius = ( 1 + self.clearance_factor) * self.d * 1.05 * 2**0.5 elem_set = p.Set(name='elems_around_cutout_%02d' % self.index, faces=p.faces.getByBoundingCylinder( center1=self.p0coord, center2=self.p2coord, radius=selection_radius)) else: raise ValueError('%s is an invalid options for "mode"' % mode) #TODO could get the Csys that already exists... part_csys = p.DatumCsysByThreePoints(name='part_cyl_csys', coordSysType=CYLINDRICAL, origin=(0.0, 0.0, 0.0), point1=(1.0, 0.0, 0.0), point2=(0.0, 1.0, 0.0)) #FIXME create a circular boundary region around the cutout to # guarantee a better mesh for these cases with a new property # around the cutout part_csys = p.datums[part_csys.id] abaqus_functions.create_composite_layup( name='prop_around_cutout_%02d' % self.index, stack=stack, plyts=plyts, mat_names=mat_names, part=p, part_csys=part_csys, region=elem_set) else: raise RuntimeError('prop_around_cutout not defined!')
def create_prop_around_cutout(self): if self.prop_around_cutout is not None: from abaqus import mdb from abaqusConstants import CYLINDRICAL cc = self.impconf.conecyl mod = mdb.models[cc.model_name] p = mod.parts[cc.part_name_shell] if not isinstance(self.prop_around_cutout, dict): raise ValueError('prop_around_cutout must be a dictionary') mode = self.prop_around_cutout['mode'] stack = self.prop_around_cutout['stack'] plyts = self.prop_around_cutout['plyts'] mat_names = self.prop_around_cutout['mat_names'] if mode == 'radius': radius = self.prop_around_cutout['radius'] elem_set = p.Set(name='elems_around_cutout_%02d' % self.index, elements=p.elements.getByBoundingCylinder( center1=self.p0coord, center2=self.p2coord, radius=radius)) elif mode == 'partition': selection_radius = (1+self.clearance_factor)*self.d*1.05*2**0.5 elem_set = p.Set(name='elems_around_cutout_%02d' % self.index, faces=p.faces.getByBoundingCylinder( center1=self.p0coord, center2=self.p2coord, radius=selection_radius)) else: raise ValueError('%s is an invalid options for "mode"' % mode) #TODO could get the Csys that already exists... part_csys = p.DatumCsysByThreePoints(name='part_cyl_csys', coordSysType=CYLINDRICAL, origin=(0.0, 0.0, 0.0), point1=(1.0, 0.0, 0.0), point2=(0.0, 1.0, 0.0)) #FIXME create a circular boundary region around the cutout to # guarantee a better mesh for these cases with a new property # around the cutout part_csys = p.datums[part_csys.id] abaqus_functions.create_composite_layup( name='prop_around_cutout_%02d' % self.index, stack=stack, plyts=plyts, mat_names=mat_names, part=p, part_csys=part_csys, region=elem_set) else: raise RuntimeError('prop_around_cutout not defined!')
def create_prop_around_hole(self): if self.prop_around_hole is not None: if not isinstance(self.prop_around_hole, dict): raise ValueError("prop_around_hole must be a dictionary") radius = self.prop_around_hole["radius"] stack = self.prop_around_hole["stack"] plyts = self.prop_around_hole["plyts"] mat_names = self.prop_around_hole["mat_names"] p = self.part print self.p0coord print self.p2coord print radius elem_set = p.Set( name="elems_around_cutout_%02d" % self.index, elements=p.elements.getByBoundingCylinder(center1=self.p0coord, center2=self.p2coord, radius=radius), ) # TODO could get the Csys that already exists... part_csys = p.DatumCsysByThreePoints( name="part_cyl_csys", coordSysType=CYLINDRICAL, origin=(0.0, 0.0, 0.0), point1=(1.0, 0.0, 0.0), point2=(0.0, 1.0, 0.0), ) part_csys = p.datums[part_csys.id] # FIXME create a circular boundary region around the cutout to # guarantee a better mesh for these cases with a new property # around the cutout abaqus_functions.create_composite_layup( name="prop_around_cutout_%02d" % self.index, stack=stack, plyts=plyts, mat_names=mat_names, part=p, part_csys=part_csys, region=elem_set, ) else: raise RuntimeError("prop_around_hole not defined!")
def create(self): #TODO # for each stringer create a method that will create its part and # translate at the Assembly level already. The part name should be the # stringer name added by an identification number # probably it will be easier to handle the identification number by # creating a StringerConfiguration class, analogously to the # imperfection configuration class from desicos.abaqus import abaqus_functions from regionToolset import Region from abaqus import mdb, session from abaqusConstants import (STANDALONE, THREE_D, DEFORMABLE_BODY, FIXED, QUAD, STRUCTURED, ON, XZPLANE, CARTESIAN, LAMINA, COMPUTED, SURFACE_TO_SURFACE, OFF) cc = self.stringerconf.conecyl mod = mdb.models[cc.model_name] vp = session.viewports[session.currentViewportName] count = 1 for part_name in mod.parts.keys(): if 'Stringer' in part_name: count += 1 self.name = 'StringerBladeComposite_{0:02d}'.format(count) thetarad = np.deg2rad(self.thetadeg) L = cc.L sina = sin(cc.alpharad) cosa = cos(cc.alpharad) rbot = cc.rbot rtop = cc.rtop wbot = self.wbot wtop = self.wtop point1 = (0, 0) point2 = (-wbot, 0) point3 = (-L*sina - wtop, L*cosa) point4 = (-L*sina, L*cosa) # creating part s = mod.ConstrainedSketch(name='__profile__', sheetSize=L) g, v, d, c = s.geometry, s.vertices, s.dimensions, s.constraints s.setPrimaryObject(option=STANDALONE) s.Line(point1=point1, point2=point2) s.Line(point1=point2, point2=point3) s.Line(point1=point3, point2=point4) s.Line(point1=point4, point2=point1) part = mod.Part(name=self.name, dimensionality=THREE_D, type=DEFORMABLE_BODY) part.BaseShell(sketch=s) s.unsetPrimaryObject() vp.setValues(displayedObject=part) del mod.sketches['__profile__'] # partitioning along the meridian for pt in cc.pts: plane = part.DatumPlaneByPrincipalPlane( principalPlane=XZPLANE, offset=pt*cc.H) part.PartitionFaceByDatumPlane(datumPlane=part.datums[plane.id], faces=part.faces) # material properties same_laminaprop = True for laminaprop in self.laminaprops: if laminaprop != self.laminaprops[0]: same_lamiaprop = False break material_type = LAMINA if same_laminaprop: mat_name = 'MatStringer_{0:02d}'.format(count) mat_names = [mat_name for _ in self.laminaprops] myMat = mod.Material(name=mat_name) myMat.Elastic(table=(laminaprop,), type=material_type) else: mat_names = [] for i, laminaprop in enumerate(self.laminaprops): mat_name = 'MatStringer_{0:02d}_ply_{0:02d}'.format(count, i+1) mat_names.append(mat_name) myMat = mod.Material(name=mat_name) myMat.Elastic(table=(laminaprop,), type=material_type) csys_name = 'CsysStringer_{0:02d}'.format(count) csys = part.DatumCsysByThreePoints(point1=(-L*sina, L*cosa, 0), point2=(-wbot, 0, 0), name=csys_name, coordSysType=CARTESIAN, origin=(0.0, 0.0, 0.0)) csys_datum = part.datums[csys.id] abaqus_functions.create_composite_layup( name='LayupStringer_{0:02d}'.format(count), stack=self.stack, plyts=self.plyts, mat_names=mat_names, part=part, part_csys=csys_datum, region=Region(faces=part.faces), axis_normal=3) # meshing part # flange edge = part.edges.findAt((-wbot/2., 0., 0.)) part.seedEdgeByNumber(edges=(edge,), number=self.numel_flange, constraint=FIXED) # meridian coords = [] for f in np.linspace(0.01, 0.99, 100): Li = f*L coords.append(((-Li*sina, Li*cosa, 0.),)) edges = part.edges.findAt(*coords) part.seedEdgeBySize(edges=edges, size=cc.mesh_size, constraint=FIXED) part.setMeshControls(regions=part.faces, elemShape=QUAD, technique=STRUCTURED) part.generateMesh() # assemblying part ra = mod.rootAssembly ra.Instance(name=self.name, part=part, dependent=ON) ra.rotate(instanceList=(self.name,), axisPoint=(0.0, 0.0, 0.0), axisDirection=(1.0, 0.0, 0.0), angle=90.0) if self.thetadeg > 0: ra.rotate(instanceList=(self.name,), axisPoint=(0.0, 0.0, 0.0), axisDirection=(0.0, 0.0, 1.0), angle=self.thetadeg) ra.translate(instanceList=(self.name,), vector=(rbot*cos(thetarad), rbot*sin(thetarad), 0.)) vp.setValues(displayedObject=ra) # tieing stringer to the shell surface inst_shell = ra.instances['INST_SHELL'] side2Faces1 = inst_shell.faces region1 = Region(side2Faces=side2Faces1) inst_stringer_faces = ra.instances[self.name].faces region2 = Region(side2Faces=inst_stringer_faces) tie_name = 'TieStringer_{0:02d}'.format(count) mod.Tie(name=tie_name, master=region1, slave=region2, positionToleranceMethod=COMPUTED, adjust=OFF, tieRotations=ON, constraintEnforcement=SURFACE_TO_SURFACE, thickness=ON) # output request hist_name = 'HistoryOutStringer_{0:02d}'.format(count) mod.FieldOutputRequest(name=hist_name, createStepName=cc.step1Name, variables=('U',))
def change_thickness_ABAQUS(imperfection_file_name, model_name, part_name, stack, t_model, t_measured, H_model, H_measured, R_model, R_best_fit=None, number_of_sets=None, semi_angle=0., stretch_H=False, z_offset_bot=None, scaling_factor=1., num_closest_points=5, power_parameter=2, num_sec_z=100, elems_t=None, t_set=None, use_theta_z_format=False): r"""Applies a given thickness imperfection to the finite element model Assumes that a percentage variation of the laminate thickness can be represented by the same percentage veriation of each ply, i.e., each ply thickness is varied in order to reflect a given measured thickness imperfection field. Parameters ---------- imperfection_file_name : str Full path to the imperfection file. model_name : str Model name. part_name : str Part name. stack : list The stacking sequence of the current model with each angle given in degrees. t_model : float The nominal shell thickness of the current model. t_measured : float The nominal thickness of the measured specimen. H_model : float Total height of the model where the imperfections will be applied to, considering also eventual resin rings. H_measured : float The total height of the measured test specimen, including eventual resin rings at the edges. R_model : float Radius **at the bottom edge** of the model where the imperfections will be applied to. R_best_fit : float, optional Best fit radius obtained with functions :func:`.best_fit_cylinder` or :func:`.best_fit_cone`. number_of_sets : int, optional Defines in how many levels the thicknesses should be divided. If ``None`` it will be based on the input file, and if the threshold of ``100`` is exceeded, ``10`` sections are used. semi_angle : float, optional Cone semi-vertex angle in degrees, when applicable. stretch_H : bool, optional If the measured imperfection data should be stretched to the current model (which may happen when ``H_model!=H_measured``. z_offset_bot : float, optional It is common to have the measured data not covering the whole test specimen, and therefore it will be centralized, if a non-centralized position is desired this parameter can be used for the adjustment. scaling_factor : float, optional A scaling factor that can be used to study the imperfection sensitivity. num_closest_points : int, optional See :func:`the inverse-weighted interpolation algorithm <.inv_weighted>`. power_parameter : float, optional See :func:`the inverse-weighted interpolation algorithm <.inv_weighted>`. num_sec_z : int, optional Number of spatial sections used to classify the measured data in order to accelerate the searching algorithms elems_t : np.ndarray, optional Interpolated thickness for each element. Can be used to avoid the same interpolation to be performed twice. t_set : set, optional A ``set`` object containing the unique thicknesses that will be used to create the new properties. use_theta_z_format : bool, optional If the new format `\theta, Z, imp` should be used instead of the old `X, Y, Z`. """ from abaqus import mdb import desicos.abaqus.abaqus_functions as abaqus_functions mod = mdb.models[model_name] part = mod.parts[part_name] part_cyl_csys = part.features['part_cyl_csys'] part_cyl_csys = part.datums[part_cyl_csys.id] if use_theta_z_format: if elems_t is None or t_set is None: log('Reading coordinates for elements...') elements = vec_calc_elem_cg(part.elements) log('Coordinates for elements read!') d, d, data = read_theta_z_imp(path=imperfection_file_name, H_measured=H_measured, stretch_H=stretch_H, z_offset_bot=z_offset_bot) data3D = np.zeros((data.shape[0], 4), dtype=FLOAT) z = data[:, 1] z *= H_model alpharad = deg2rad(semi_angle) tana = tan(alpharad) def r_local(z): return R_model - z * tana data3D[:, 0] = r_local(z) * cos(data[:, 0]) data3D[:, 1] = r_local(z) * sin(data[:, 0]) data3D[:, 2] = z data3D[:, 3] = data[:, 2] ans = inv_weighted(data3D, elements[:, :3], num_sub=num_sec_z, col=2, ncp=num_closest_points, power_parameter=power_parameter) t_set = set(ans) t_set.discard(0.) #TODO why inv_weighted returns an array with 0. elems_t = np.zeros((elements.shape[0], 2), dtype=FLOAT) elems_t[:, 0] = elements[:, 3] elems_t[:, 1] = ans else: log('Thickness differences already calculated!') else: if elems_t is None or t_set is None: # reading elements data log('Reading coordinates for elements...') elements = vec_calc_elem_cg(part.elements) log('Coordinates for elements read!') # calling translate_nodes function elems_t, t_set = calc_elems_t( imperfection_file_name, nodes=elements, t_model=t_model, t_measured=t_measured, H_model=H_model, H_measured=H_measured, R_model=R_model, R_best_fit=R_best_fit, semi_angle=semi_angle, stretch_H=stretch_H, z_offset_bot=z_offset_bot, num_closest_points=num_closest_points, power_parameter=power_parameter, num_sec_z=num_sec_z) else: log('Thickness differences already calculated!') # creating sets t_list = [] max_len_t_set = 100 if len(t_set) >= max_len_t_set: number_of_sets = 10 log('More than {0:d} different thicknesses measured!'.format( max_len_t_set)) log('Forcing a number_of_sets = {0:d}'.format(number_of_sets)) if number_of_sets is None or number_of_sets == 0: number_of_sets = len(t_set) t_list = list(t_set) t_list.sort() else: t_min = min(t_set) t_max = max(t_set) t_list = list(np.linspace(t_min, t_max, number_of_sets + 1)) # grouping elements sets_ids = [[] for i in range(len(t_list))] for entry in elems_t: elem_id, t = entry index = index_within_linspace(t_list, t) sets_ids[index].append(int(elem_id)) # putting elements in sets original_layup = part.compositeLayups['CompositePlate'] plyts = [ply.thickness for ply in original_layup.plies.values()] mat_names = [ply.material for ply in original_layup.plies.values()] for i, set_ids in enumerate(sets_ids): if len(set_ids) == 0: # since t_set_norm * t_model <> t_set originally measured # there may be empty set_ids at the end continue elements = part.elements.sequenceFromLabels(labels=set_ids) sufix = 'measured_imp_t_{0:03d}'.format(i) set_name = 'Set_' + sufix log('Creating set ({0: 7d} elements): {1}'.format( len(set_ids), set_name)) part.Set(name=set_name, elements=elements) region = part.sets[set_name] layup_name = 'CLayup_' + sufix t_diff = (float(t_list[i]) - t_model) * scaling_factor t_scaling_factor = (t_model + t_diff) / t_model abaqus_functions.create_composite_layup( name=layup_name, stack=stack, plyts=plyts, mat_names=mat_names, region=region, part=part, part_csys=part_cyl_csys, scaling_factor=t_scaling_factor) # suppress needed to put the new properties to the input file original_layup.suppress() return elems_t, t_set