Source code for desicos.abaqus.imperfections.pload

from __future__ import absolute_import

import numpy as np
from numpy import sin, cos

from desicos.abaqus.constants import *
from desicos.logger import warn
from .imperfection import Imperfection

[docs]class PLoad(Imperfection): """Perturbation Load """ def __init__(self, thetadeg, pt, pltotal, step=1): super(PLoad, self).__init__() self.thetadeg = thetadeg self.pt = pt self.pltotal = pltotal # resultant pload self.step = step self.name = 'PL' self.index = None if abs(pltotal) < 0.1*TOL: pltotal = 0.1*TOL self.plradial = None # component radial direction self.plx = None # component x direction self.ply = None # component y direction self.plz = None # component z direction # plotting options self.xaxis = 'pltotal' self.xaxis_label = 'Perturbation Load, N' def rebuild(self): cc = self.impconf.conecyl alpharad = cc.alpharad self.plradial = self.pltotal*cos(alpharad) self.plz = -self.pltotal*sin(alpharad) self.plx = -self.plradial*cos(np.deg2rad(self.thetadeg)) self.ply = -self.plradial*sin(np.deg2rad(self.thetadeg)) self.x, self.y, self.z = self.get_xyz() self.r, z = cc.r_z_from_pt(self.pt) self.thetadeg = self.thetadeg % 360. self.thetadegs = [self.thetadeg] self.pts = [self.pt] self.name = 'PL_pt_{0:03d}_theta_{1:03d}'.format( int(self.pt*100), int(self.thetadeg)) if abs(self.pltotal) < 0.1*TOL: warn('Ignoring perturbation load: {0}'.format(self.name))
[docs] def calc_amplitude(self): """Calculate the imperfection amplitude. The odb must be available and it will be used to extract the last frame of the first analysis step, corresponding to the constant loads. """ from abaqus import mdb cc = self.impconf.conecyl mod = mdb.models[cc.model_name] nodes = mod.parts[cc.part_name_shell].nodes # calculate unit normal vector w.r.t. the surface ux = cos(cc.alpharad)*cos(np.deg2rad(self.thetadeg)) uy = cos(cc.alpharad)*sin(np.deg2rad(self.thetadeg)) uz = sin(cc.alpharad) # It would be nicer to calculate this based on e.g. MSI amplitude max_imp = 10 r_TOL = 0.1 # Radius of cylinder to search pt1 = (self.x + max_imp*ux, self.y + max_imp*uy, self.z + max_imp*uz) pt2 = (self.x - max_imp*ux, self.y - max_imp*uy, self.z - max_imp*uz) # Search for our node in a cylinder normal to the surface, because # 'our' node may be moved by a MSI nodes = nodes.getByBoundingCylinder(pt1, pt2, r_TOL) if len(nodes) != 1: warn("Unable to locate node where perturbation load" + "'{0}' is applied. ".format(self.name) + "Cannot calculate imperfection amplitude.") self.amplitude = 0. return 0. odb = cc.attach_results() fo = odb.steps[cc.step1Name].frames[-1].fieldOutputs if not 'U' in fo.keys(): raise RuntimeError( 'Field output 'U' not available to calculate amplitude') #TODO not sure if this is robust: node.label-1 u, v, w = fo['U'].values[nodes[0].label-1].data cc.detach_results(odb) alpha = cc.alpharad theta = np.deg2rad(self.thetadeg) amp = -((u*cos(theta) + v*sin(theta))*cos(alpha) + w*sin(alpha)) self.amplitude = amp return amp
[docs] def create(self): """Include the perturbation load. The load step in which the perturbation load is included depends on the ``step`` parameter, which can be 1 or 2. If applied in the first step it will be kept constant, whereas in the second step it will be incremented. The perturbation load is included after finding its corresponding vertice. The perturbation load is **not created** if its value is smaller then ``0.1*TOL`` (see :mod:`desicos.constants`). .. note:: Must be called from Abaqus. """ if abs(self.pltotal) < 0.1*TOL: return from abaqus import mdb import regionToolset cc = self.impconf.conecyl mod = mdb.models[cc.model_name] inst_shell = mod.rootAssembly.instances['INST_SHELL'] region = regionToolset.Region(vertices=inst_shell.vertices.findAt( ((self.x, self.y, self.z),))) step_name = cc.get_step_name(self.step) mod.ConcentratedForce(name=self.name, createStepName=step_name, region=region, cf1=self.plx, cf2=self.ply, cf3=self.plz, field='')